{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"<img src=\"https://i.ibb.co/gV6Td9Z/image-1.png\" alt=\"image-1\" border=\"0\">\n\n\n\n![tryborg](https://preview.redd.it/80rfxi6nyia71.jpg?width=960&crop=smart&auto=webp&s=683e5f8dc9adaa6af8f0cb9e72f055a461cd349b)\n<p style=\"font-size:120%;text-align:center\">Be Tryborg :/</p>","metadata":{}},{"cell_type":"markdown","source":"<h1 style=\"font-size:50px;color:#2874A6\"><strong>Notebook</strong> <strong style=\"color:black\">Setup</strong></h1>\n\nSource: [Github](https://github.com/ageron/handson-ml2)","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:120%\">First, let's import a few common modules, ensure MatplotLib plots figures inline and prepare a function to save the figures. We also check that Python 3.5 or later is installed (although Python 2.x may work, it is deprecated so we strongly recommend you use Python 3 instead), as well as Scikit-Learn ≥0.20 and TensorFlow ≥2.0.</p>","metadata":{}},{"cell_type":"code","source":"# Python ≥3.5 is required\nimport sys\nassert sys.version_info >= (3, 5)\n\n# Scikit-Learn ≥0.20 is required\nimport sklearn\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport gc\nfrom tensorflow.keras.utils import to_categorical\n\nassert sklearn.__version__ >= \"0.20\"\n\ntry:\n    # %tensorflow_version only exists in Colab.\n    %tensorflow_version 2.x\nexcept Exception:\n    pass\n\n# TensorFlow ≥2.0 is required\nimport tensorflow as tf\nfrom tensorflow import keras\nassert tf.__version__ >= \"2.0\"\n\n%load_ext tensorboard\n\n# Common imports\nimport numpy as np\nimport os\n\n# to make this notebook's output stable across runs\nnp.random.seed(42)\n\n# To plot pretty figures\n%matplotlib inline\nimport matplotlib as mpl\nimport matplotlib.pyplot as plt\nmpl.rc('axes', labelsize=14)\nmpl.rc('xtick', labelsize=12)\nmpl.rc('ytick', labelsize=12)\n\n# Where to save the figures\nPROJECT_ROOT_DIR = \".\"\nCHAPTER_ID = \"deep\"\nIMAGES_PATH = os.path.join(PROJECT_ROOT_DIR, \"images\", CHAPTER_ID)\nos.makedirs(IMAGES_PATH, exist_ok=True)\n\ndef save_fig(fig_id, tight_layout=True, fig_extension=\"png\", resolution=300):\n    path = os.path.join(IMAGES_PATH, fig_id + \".\" + fig_extension)\n    print(\"Saving figure\", fig_id)\n    if tight_layout:\n        plt.tight_layout()\n    plt.savefig(path, format=fig_extension, dpi=resolution)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-02T06:14:19.025514Z","iopub.execute_input":"2021-12-02T06:14:19.026316Z","iopub.status.idle":"2021-12-02T06:14:24.563143Z","shell.execute_reply.started":"2021-12-02T06:14:19.026228Z","shell.execute_reply":"2021-12-02T06:14:24.562375Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h1 style=\"font-size:50px;color:#2874A6\"><strong>Vanishing/Exploding</strong> <strong style=\"color:black\">Gradients Problem</strong></h1>","metadata":{}},{"cell_type":"code","source":"def logit(z): #sigmoid function\n    return 1 / (1 + np.exp(-z))","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:14:24.564769Z","iopub.execute_input":"2021-12-02T06:14:24.564996Z","iopub.status.idle":"2021-12-02T06:14:24.573048Z","shell.execute_reply.started":"2021-12-02T06:14:24.56496Z","shell.execute_reply":"2021-12-02T06:14:24.569644Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"z = np.linspace(-5, 5, 200)\n\nplt.plot([-5, 5], [0, 0], 'k-')\nplt.plot([-5, 5], [1, 1], 'k--')\nplt.plot([0, 0], [-0.2, 1.2], 'k-')\nplt.plot([-5, 5], [-3/4, 7/4], 'g--')\nplt.plot(z, logit(z), \"b-\", linewidth=2)\nprops = dict(facecolor='black', shrink=0.1)\nplt.annotate('Saturating', xytext=(3.5, 0.7), xy=(5, 1), arrowprops=props, fontsize=14, ha=\"center\")\nplt.annotate('Saturating', xytext=(-3.5, 0.3), xy=(-5, 0), arrowprops=props, fontsize=14, ha=\"center\")\nplt.annotate('Linear', xytext=(2, 0.2), xy=(0, 0.5), arrowprops=props, fontsize=14, ha=\"center\")\nplt.grid(True)\nplt.title(\"Sigmoid activation function\", fontsize=14)\nplt.axis([-5, 5, -0.2, 1.2])\n\nsave_fig(\"sigmoid_saturation_plot\")\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-02T06:14:24.574253Z","iopub.execute_input":"2021-12-02T06:14:24.574711Z","iopub.status.idle":"2021-12-02T06:14:25.346487Z","shell.execute_reply.started":"2021-12-02T06:14:24.574673Z","shell.execute_reply":"2021-12-02T06:14:25.341722Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h1 style=\"font-size:50px;color:#2874A6\"><strong> Xavier and He</strong> <strong style=\"color:black\">Initialization</strong></h1>","metadata":{}},{"cell_type":"code","source":"[name for name in dir(keras.initializers) if not name.startswith(\"_\")]","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:14:25.34849Z","iopub.execute_input":"2021-12-02T06:14:25.348758Z","iopub.status.idle":"2021-12-02T06:14:25.357018Z","shell.execute_reply.started":"2021-12-02T06:14:25.348721Z","shell.execute_reply":"2021-12-02T06:14:25.356317Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"keras.layers.Dense(10, activation=\"relu\", kernel_initializer=\"he_normal\") #kernel_initalizer is used for weight init","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:14:25.358511Z","iopub.execute_input":"2021-12-02T06:14:25.358982Z","iopub.status.idle":"2021-12-02T06:14:25.608813Z","shell.execute_reply.started":"2021-12-02T06:14:25.358945Z","shell.execute_reply":"2021-12-02T06:14:25.607998Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"init = keras.initializers.VarianceScaling(scale=2., mode='fan_avg',\n                                          distribution='uniform')\nkeras.layers.Dense(10, activation=\"relu\", kernel_initializer=init)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:14:25.61269Z","iopub.execute_input":"2021-12-02T06:14:25.614661Z","iopub.status.idle":"2021-12-02T06:14:25.627596Z","shell.execute_reply.started":"2021-12-02T06:14:25.614608Z","shell.execute_reply":"2021-12-02T06:14:25.626846Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h1 style=\"font-size:50px;color:#2874A6\"><strong>Nonsaturating </strong> <strong style=\"color:black\">Activation Functions</strong></h1>","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>Leaky ReLU</strong></p>","metadata":{}},{"cell_type":"code","source":"def leaky_relu(z, alpha=0.01):\n    return np.maximum(alpha*z, z)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:14:25.62901Z","iopub.execute_input":"2021-12-02T06:14:25.62949Z","iopub.status.idle":"2021-12-02T06:14:25.640903Z","shell.execute_reply.started":"2021-12-02T06:14:25.629434Z","shell.execute_reply":"2021-12-02T06:14:25.639761Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(z, leaky_relu(z, 0.05), \"b-\", linewidth=2)\nplt.plot([-5, 5], [0, 0], 'k-')\nplt.plot([0, 0], [-0.5, 4.2], 'k-')\nplt.grid(True)\nprops = dict(facecolor='black', shrink=0.1)\nplt.annotate('Leak', xytext=(-3.5, 0.5), xy=(-5, -0.2), arrowprops=props, fontsize=14, ha=\"center\")\nplt.title(\"Leaky ReLU activation function\", fontsize=14)\nplt.axis([-5, 5, -0.5, 4.2])\n\nsave_fig(\"leaky_relu_plot\")\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-02T06:14:25.642355Z","iopub.execute_input":"2021-12-02T06:14:25.643859Z","iopub.status.idle":"2021-12-02T06:14:26.507041Z","shell.execute_reply.started":"2021-12-02T06:14:25.643809Z","shell.execute_reply":"2021-12-02T06:14:26.504722Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"[m for m in dir(keras.activations) if not m.startswith(\"_\")]","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:14:26.508357Z","iopub.execute_input":"2021-12-02T06:14:26.50877Z","iopub.status.idle":"2021-12-02T06:14:26.52298Z","shell.execute_reply.started":"2021-12-02T06:14:26.508733Z","shell.execute_reply":"2021-12-02T06:14:26.522003Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"[m for m in dir(keras.layers) if \"relu\" in m.lower()]","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:14:26.529088Z","iopub.execute_input":"2021-12-02T06:14:26.529508Z","iopub.status.idle":"2021-12-02T06:14:26.541225Z","shell.execute_reply.started":"2021-12-02T06:14:26.529457Z","shell.execute_reply":"2021-12-02T06:14:26.540374Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:120%\">Let's train a neural network on tps november using the Leaky ReLU:</p>","metadata":{}},{"cell_type":"code","source":"train = pd.read_csv('../input/tabular-playground-series-dec-2021/train.csv')\nsubmission = pd.read_csv('../input/tabular-playground-series-dec-2021/sample_submission.csv')","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:20:11.45346Z","iopub.execute_input":"2021-12-02T06:20:11.453734Z","iopub.status.idle":"2021-12-02T06:20:27.924514Z","shell.execute_reply.started":"2021-12-02T06:20:11.453704Z","shell.execute_reply":"2021-12-02T06:20:27.923777Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#reduce memory\ndef reduce_mem_usage(df, verbose=True):\n    numerics = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']\n    start_mem = df.memory_usage().sum() / 1024**2    \n    for col in df.columns:\n        col_type = df[col].dtypes\n        if col_type in numerics:\n            c_min = df[col].min()\n            c_max = df[col].max()\n            if str(col_type)[:3] == 'int':\n                if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:\n                    df[col] = df[col].astype(np.int8)\n                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:\n                    df[col] = df[col].astype(np.int16)\n                elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:\n                    df[col] = df[col].astype(np.int32)\n                elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:\n                    df[col] = df[col].astype(np.int64)  \n            else:\n                if c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:\n                    df[col] = df[col].astype(np.float32)\n                else:\n                    df[col] = df[col].astype(np.float64)    \n    end_mem = df.memory_usage().sum() / 1024**2\n    if verbose: print('Mem. usage decreased to {:5.2f} Mb ({:.1f}% reduction)'.format(end_mem, 100 * (start_mem - end_mem) / start_mem))\n    return df","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:20:27.926351Z","iopub.execute_input":"2021-12-02T06:20:27.926612Z","iopub.status.idle":"2021-12-02T06:20:27.94067Z","shell.execute_reply.started":"2021-12-02T06:20:27.926578Z","shell.execute_reply":"2021-12-02T06:20:27.938194Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train = reduce_mem_usage(train)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:20:27.941909Z","iopub.execute_input":"2021-12-02T06:20:27.942173Z","iopub.status.idle":"2021-12-02T06:20:49.598285Z","shell.execute_reply.started":"2021-12-02T06:20:27.942137Z","shell.execute_reply":"2021-12-02T06:20:49.597502Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y = train['Cover_Type']\n\ntrain = train.drop(3403875) #droping single row of label 5\ny = y.drop(3403875)\n\ntrain = train.head(3000000) #just for fast computing remove these 2 lines to use full dataset\ny = y.head(3000000)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:20:49.600125Z","iopub.execute_input":"2021-12-02T06:20:49.600829Z","iopub.status.idle":"2021-12-02T06:20:50.458592Z","shell.execute_reply.started":"2021-12-02T06:20:49.600782Z","shell.execute_reply":"2021-12-02T06:20:50.457862Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import StandardScaler, OrdinalEncoder\n\n#no preprocessing done will do in next version...\nstd = StandardScaler()\nencoder = OrdinalEncoder()\n\ny = pd.DataFrame(to_categorical(encoder.fit_transform(y.values.reshape(-1,1))))\n\ntrain.drop(['Id','Cover_Type','Soil_Type7', 'Soil_Type15'], axis=1, inplace=True)\n\nX_train, X_test , y_train, y_test = train_test_split(train,y, stratify=y, test_size=0.2, random_state=42, shuffle=True)\nX_train = pd.DataFrame(std.fit_transform(X_train), columns = X_train.columns)\nX_test = pd.DataFrame(std.transform(X_test), columns = X_test.columns)\n\ndel train, y, std, encoder\n\ngc.collect()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train.shape, X_test.shape, y_train.shape, y_test.shape","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:23:46.928031Z","iopub.execute_input":"2021-12-02T06:23:46.928298Z","iopub.status.idle":"2021-12-02T06:23:46.935559Z","shell.execute_reply.started":"2021-12-02T06:23:46.928263Z","shell.execute_reply":"2021-12-02T06:23:46.934799Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from keras import Input, layers, Model\nfrom keras.layers import Dense\n\ndef get_model():\n    #this function is used to get the keras functional model\n    \n    #setting up reuseability\n    keras.backend.clear_session()\n    tf.keras.backend.clear_session()\n    tf.random.set_seed(42)\n    np.random.seed(42)\n    \n    input_ = Input(shape=(X_train.shape[1])) #input shape where (batch_size, column numbers) we only specify column number here\n    \n    x = Dense(300,activation= 'LeakyReLU', kernel_initializer=\"he_normal\")(input_) \n    x = Dense(100,activation= 'LeakyReLU', kernel_initializer=\"he_normal\")(x)\n    \n    output_ = Dense(y_train.shape[1], activation='softmax')(x)\n    \n    model = Model(inputs=[input_], outputs =[output_])\n    \n    return model\n","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:23:54.045493Z","iopub.execute_input":"2021-12-02T06:23:54.046046Z","iopub.status.idle":"2021-12-02T06:23:54.052693Z","shell.execute_reply.started":"2021-12-02T06:23:54.046004Z","shell.execute_reply":"2021-12-02T06:23:54.052005Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"try:\n    del model\nexcept:\n    model = get_model()\n\nmodel.compile(loss=\"categorical_crossentropy\",\n              optimizer=keras.optimizers.Adam(learning_rate=0.001),\n              metrics=[\"acc\",]);\n\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:24:00.904615Z","iopub.execute_input":"2021-12-02T06:24:00.905485Z","iopub.status.idle":"2021-12-02T06:24:01.151141Z","shell.execute_reply.started":"2021-12-02T06:24:00.905435Z","shell.execute_reply":"2021-12-02T06:24:01.150458Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(X_train, y_train, epochs=10,batch_size=2024,\n                    validation_data=(X_test, y_test))","metadata":{"scrolled":true,"_kg_hide-output":false,"execution":{"iopub.status.busy":"2021-12-02T06:24:08.22531Z","iopub.execute_input":"2021-12-02T06:24:08.225749Z","iopub.status.idle":"2021-12-02T06:25:34.039504Z","shell.execute_reply.started":"2021-12-02T06:24:08.225715Z","shell.execute_reply":"2021-12-02T06:25:34.038658Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:120%\">Now let's try PReLU:","metadata":{}},{"cell_type":"code","source":"def get_model():\n    #this function is used to get the keras functional model\n    \n    #setting up reuseability\n    keras.backend.clear_session()\n    tf.keras.backend.clear_session()\n    tf.random.set_seed(42)\n    np.random.seed(42)\n    \n    input_ = Input(shape=(X_train.shape[1])) #input shape where (batch_size, column numbers) we only specify column number here\n    \n    x = Dense(300,activation= 'PReLU', kernel_initializer=\"he_normal\")(input_) \n    x = Dense(100,activation= 'PReLU', kernel_initializer=\"he_normal\")(x)\n    \n    output_ = Dense(y_train.shape[1], activation='softmax')(x)\n    \n    model = Model(inputs=[input_], outputs =[output_])\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:26:23.681227Z","iopub.execute_input":"2021-12-02T06:26:23.681499Z","iopub.status.idle":"2021-12-02T06:26:23.687691Z","shell.execute_reply.started":"2021-12-02T06:26:23.681458Z","shell.execute_reply":"2021-12-02T06:26:23.687005Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = get_model()\n\nmodel.compile(loss=\"categorical_crossentropy\",\n              optimizer=keras.optimizers.Adam(learning_rate=0.001),\n              metrics=[\"acc\",]);","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:26:31.555179Z","iopub.execute_input":"2021-12-02T06:26:31.555679Z","iopub.status.idle":"2021-12-02T06:26:31.603749Z","shell.execute_reply.started":"2021-12-02T06:26:31.555615Z","shell.execute_reply":"2021-12-02T06:26:31.603051Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(X_train, y_train, epochs=10,batch_size=2024,\n                    validation_data=(X_test, y_test))\n\ndel history, model\n\ngc.collect()","metadata":{"_kg_hide-output":false,"execution":{"iopub.status.busy":"2021-12-02T06:26:32.498285Z","iopub.execute_input":"2021-12-02T06:26:32.498754Z","iopub.status.idle":"2021-12-02T06:27:58.155775Z","shell.execute_reply.started":"2021-12-02T06:26:32.498713Z","shell.execute_reply":"2021-12-02T06:27:58.15498Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>ELU</strong></p>","metadata":{}},{"cell_type":"code","source":"def elu(z, alpha=1):\n    return np.where(z < 0, alpha * (np.exp(z) - 1), z)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:28:01.357805Z","iopub.execute_input":"2021-12-02T06:28:01.358276Z","iopub.status.idle":"2021-12-02T06:28:01.362718Z","shell.execute_reply.started":"2021-12-02T06:28:01.358237Z","shell.execute_reply":"2021-12-02T06:28:01.361788Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(z, elu(z), \"b-\", linewidth=2)\nplt.plot([-5, 5], [0, 0], 'k-')\nplt.plot([-5, 5], [-1, -1], 'k--')\nplt.plot([0, 0], [-2.2, 3.2], 'k-')\nplt.grid(True)\nplt.title(r\"ELU activation function ($\\alpha=1$)\", fontsize=14)\nplt.axis([-5, 5, -2.2, 3.2])\n\nsave_fig(\"elu_plot\")\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-02T06:28:01.599309Z","iopub.execute_input":"2021-12-02T06:28:01.599744Z","iopub.status.idle":"2021-12-02T06:28:02.284291Z","shell.execute_reply.started":"2021-12-02T06:28:01.599706Z","shell.execute_reply":"2021-12-02T06:28:02.283503Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:120%\">Implementing ELU in TensorFlow is trivial, just specify the activation function when building each layer:","metadata":{}},{"cell_type":"code","source":"keras.layers.Dense(10, activation=\"elu\")","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:28:10.058876Z","iopub.execute_input":"2021-12-02T06:28:10.059666Z","iopub.status.idle":"2021-12-02T06:28:10.06627Z","shell.execute_reply.started":"2021-12-02T06:28:10.059603Z","shell.execute_reply":"2021-12-02T06:28:10.065593Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>SELU</strong></p>","metadata":{}},{"cell_type":"markdown","source":"\n<p style=\"font-size:120%\">\nThis activation function was proposed in this <a href=\"https://arxiv.org/pdf/1706.02515.pdf\">great paper</a> by Günter Klambauer, Thomas Unterthiner and Andreas Mayr, published in June 2017. During training, a neural network composed exclusively of a stack of dense layers using the SELU activation function and LeCun initialization will self-normalize: the output of each layer will tend to preserve the same mean and variance during training, which solves the vanishing/exploding gradients problem. As a result, this activation function outperforms the other activation functions very significantly for such neural nets, so you should really try it out. Unfortunately, the self-normalizing property of the SELU activation function is easily broken: you cannot use ℓ<sub>1</sub> or ℓ<sub>2</sub> regularization, regular dropout, max-norm, skip connections or other non-sequential topologies (so recurrent neural networks won't self-normalize). However, in practice it works quite well with sequential CNNs. If you break self-normalization, SELU will not necessarily outperform other activation functions.</p>","metadata":{}},{"cell_type":"code","source":"from scipy.special import erfc\n\n# alpha and scale to self normalize with mean 0 and standard deviation 1\n# (see equation 14 in the paper):\nalpha_0_1 = -np.sqrt(2 / np.pi) / (erfc(1/np.sqrt(2)) * np.exp(1/2) - 1)\nscale_0_1 = (1 - erfc(1 / np.sqrt(2)) * np.sqrt(np.e)) * np.sqrt(2 * np.pi) * (2 * erfc(np.sqrt(2))*np.e**2 + np.pi*erfc(1/np.sqrt(2))**2*np.e - 2*(2+np.pi)*erfc(1/np.sqrt(2))*np.sqrt(np.e)+np.pi+2)**(-1/2)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:28:17.028765Z","iopub.execute_input":"2021-12-02T06:28:17.029591Z","iopub.status.idle":"2021-12-02T06:28:17.039886Z","shell.execute_reply.started":"2021-12-02T06:28:17.02955Z","shell.execute_reply":"2021-12-02T06:28:17.038744Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def selu(z, scale=scale_0_1, alpha=alpha_0_1):\n    return scale * elu(z, alpha)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:28:17.261502Z","iopub.execute_input":"2021-12-02T06:28:17.262003Z","iopub.status.idle":"2021-12-02T06:28:17.266306Z","shell.execute_reply.started":"2021-12-02T06:28:17.261954Z","shell.execute_reply":"2021-12-02T06:28:17.265039Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(z, selu(z), \"b-\", linewidth=2)\nplt.plot([-5, 5], [0, 0], 'k-')\nplt.plot([-5, 5], [-1.758, -1.758], 'k--')\nplt.plot([0, 0], [-2.2, 3.2], 'k-')\nplt.grid(True)\nplt.title(\"SELU activation function\", fontsize=14)\nplt.axis([-5, 5, -2.2, 3.2])\n\nsave_fig(\"selu_plot\")\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-02T06:28:18.266956Z","iopub.execute_input":"2021-12-02T06:28:18.267686Z","iopub.status.idle":"2021-12-02T06:28:18.744Z","shell.execute_reply.started":"2021-12-02T06:28:18.267607Z","shell.execute_reply":"2021-12-02T06:28:18.743045Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:120%\">\nBy default, the SELU hyperparameters <mark>(scale and alpha)</mark> are tuned in such a way that the mean output of each neuron remains close to 0, and the standard deviation remains close to 1 (assuming the inputs are standardized with mean 0 and standard deviation 1 too). Using this activation function, even a 1,000 layer deep neural network preserves roughly mean 0 and standard deviation 1 across all layers, avoiding the exploding/vanishing gradients problem:\n</p>","metadata":{}},{"cell_type":"code","source":"np.random.seed(42)\nZ = np.random.normal(size=(500, 100)) # standardized inputs\nfor layer in range(1000):\n    W = np.random.normal(size=(100, 100), scale=np.sqrt(1 / 100)) # LeCun initialization\n    Z = selu(np.dot(Z, W))\n    means = np.mean(Z, axis=0).mean()\n    stds = np.std(Z, axis=0).mean()\n    if layer % 100 == 0:\n        print(\"Layer {}: mean {:.2f}, std deviation {:.2f}\".format(layer, means, stds))","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:28:28.151061Z","iopub.execute_input":"2021-12-02T06:28:28.151325Z","iopub.status.idle":"2021-12-02T06:28:30.716909Z","shell.execute_reply.started":"2021-12-02T06:28:28.151295Z","shell.execute_reply":"2021-12-02T06:28:30.715963Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:120%\">Using SELU is easy:","metadata":{}},{"cell_type":"code","source":"keras.layers.Dense(10, activation=\"selu\",\n                   kernel_initializer=\"lecun_normal\")","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:28:33.618209Z","iopub.execute_input":"2021-12-02T06:28:33.618696Z","iopub.status.idle":"2021-12-02T06:28:33.626308Z","shell.execute_reply.started":"2021-12-02T06:28:33.618657Z","shell.execute_reply":"2021-12-02T06:28:33.625474Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:120%\">Let's create a neural net for Fashion MNIST with 100 hidden layers, using the SELU activation function:","metadata":{}},{"cell_type":"code","source":"np.random.seed(42)\ntf.random.set_seed(42)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:28:37.082353Z","iopub.execute_input":"2021-12-02T06:28:37.082916Z","iopub.status.idle":"2021-12-02T06:28:37.08907Z","shell.execute_reply.started":"2021-12-02T06:28:37.082876Z","shell.execute_reply":"2021-12-02T06:28:37.088128Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = keras.models.Sequential()\nmodel.add(keras.layers.Flatten(input_shape=[X_train.shape[1],]))\nmodel.add(keras.layers.Dense(300, activation=\"selu\",\n                             kernel_initializer=\"lecun_normal\"))\nfor layer in range(99):\n    model.add(keras.layers.Dense(100, activation=\"selu\",\n                                 kernel_initializer=\"lecun_normal\"))\nmodel.add(keras.layers.Dense(y_train.shape[1], activation=\"softmax\"))","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:29:02.936325Z","iopub.execute_input":"2021-12-02T06:29:02.936987Z","iopub.status.idle":"2021-12-02T06:29:03.754226Z","shell.execute_reply.started":"2021-12-02T06:29:02.936946Z","shell.execute_reply":"2021-12-02T06:29:03.753477Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(loss=\"categorical_crossentropy\",\n              optimizer=keras.optimizers.Adam(learning_rate=0.001),\n              metrics=[\"acc\",]);","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:29:03.755835Z","iopub.execute_input":"2021-12-02T06:29:03.756059Z","iopub.status.idle":"2021-12-02T06:29:03.7665Z","shell.execute_reply.started":"2021-12-02T06:29:03.756027Z","shell.execute_reply":"2021-12-02T06:29:03.765657Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:120%\">Now let's train it. Do not forget to scale the inputs to mean 0 and standard deviation 1:","metadata":{}},{"cell_type":"code","source":"_means = X_train.values.mean(axis=0, keepdims=True)\n_stds = X_train.values.std(axis=0, keepdims=True)\nX_train_scaled = (X_train - _means) / _stds\nX_test_scaled = (X_test - _means) / _stds","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:29:09.631144Z","iopub.execute_input":"2021-12-02T06:29:09.631691Z","iopub.status.idle":"2021-12-02T06:29:11.352683Z","shell.execute_reply.started":"2021-12-02T06:29:09.631648Z","shell.execute_reply":"2021-12-02T06:29:11.351914Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(X_train_scaled, y_train, epochs=5,batch_size=1024,\n                    validation_data=(X_test_scaled, y_test))\n\ndel model, history\ngc.collect()","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-12-02T06:29:11.354133Z","iopub.execute_input":"2021-12-02T06:29:11.354383Z","iopub.status.idle":"2021-12-02T06:33:10.175131Z","shell.execute_reply.started":"2021-12-02T06:29:11.354348Z","shell.execute_reply":"2021-12-02T06:33:10.174387Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:120%\">Now look at what happens if we try to use the ReLU activation function instead:","metadata":{}},{"cell_type":"code","source":"np.random.seed(42)\ntf.random.set_seed(42)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:35:58.388127Z","iopub.execute_input":"2021-12-02T06:35:58.388446Z","iopub.status.idle":"2021-12-02T06:35:58.423036Z","shell.execute_reply.started":"2021-12-02T06:35:58.388412Z","shell.execute_reply":"2021-12-02T06:35:58.421822Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = keras.models.Sequential()\nmodel.add(keras.layers.Flatten(input_shape=[X_train.shape[1],]))\nmodel.add(keras.layers.Dense(300, activation=\"relu\", kernel_initializer=\"he_normal\"))\nfor layer in range(99):\n    model.add(keras.layers.Dense(100, activation=\"relu\", kernel_initializer=\"he_normal\"))\nmodel.add(keras.layers.Dense(y_train.shape[1], activation=\"softmax\"))","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:35:58.594013Z","iopub.execute_input":"2021-12-02T06:35:58.594548Z","iopub.status.idle":"2021-12-02T06:35:59.449079Z","shell.execute_reply.started":"2021-12-02T06:35:58.59451Z","shell.execute_reply":"2021-12-02T06:35:59.448328Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(loss=\"categorical_crossentropy\",\n              optimizer=keras.optimizers.Adam(learning_rate=0.001),\n              metrics=[\"acc\",]);","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:35:59.45055Z","iopub.execute_input":"2021-12-02T06:35:59.450809Z","iopub.status.idle":"2021-12-02T06:35:59.46146Z","shell.execute_reply.started":"2021-12-02T06:35:59.450776Z","shell.execute_reply":"2021-12-02T06:35:59.460807Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(X_train_scaled, y_train, epochs=5,batch_size=1024,\n                    validation_data=(X_test_scaled, y_test))\n\ndel model, history\ngc.collect()","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-12-02T06:35:59.4628Z","iopub.execute_input":"2021-12-02T06:35:59.463067Z","iopub.status.idle":"2021-12-02T06:40:28.115192Z","shell.execute_reply.started":"2021-12-02T06:35:59.463034Z","shell.execute_reply":"2021-12-02T06:40:28.114428Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:120%\">Not great at all, we suffered from the vanishing/exploding gradients problem.","metadata":{}},{"cell_type":"markdown","source":"<h1 style=\"font-size:50px;color:#2874A6\"><strong>Batch</strong> <strong style=\"color:black\">Normalization</strong></h1>","metadata":{}},{"cell_type":"code","source":"model = keras.models.Sequential([\n    keras.layers.Flatten(input_shape=[X_train.shape[1],]),\n    keras.layers.BatchNormalization(),\n    keras.layers.Dense(300, activation=\"relu\"),\n    keras.layers.BatchNormalization(),\n    keras.layers.Dense(100, activation=\"relu\"),\n    keras.layers.BatchNormalization(),\n    keras.layers.Dense(y_train.shape[1], activation=\"softmax\")\n])","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:40:28.117398Z","iopub.execute_input":"2021-12-02T06:40:28.11769Z","iopub.status.idle":"2021-12-02T06:40:28.185185Z","shell.execute_reply.started":"2021-12-02T06:40:28.117652Z","shell.execute_reply":"2021-12-02T06:40:28.184535Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:40:28.186359Z","iopub.execute_input":"2021-12-02T06:40:28.186597Z","iopub.status.idle":"2021-12-02T06:40:28.196741Z","shell.execute_reply.started":"2021-12-02T06:40:28.186565Z","shell.execute_reply":"2021-12-02T06:40:28.195868Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"bn1 = model.layers[1]\n[(var.name, var.trainable) for var in bn1.variables]","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:40:28.199236Z","iopub.execute_input":"2021-12-02T06:40:28.199422Z","iopub.status.idle":"2021-12-02T06:40:28.204747Z","shell.execute_reply.started":"2021-12-02T06:40:28.199399Z","shell.execute_reply":"2021-12-02T06:40:28.204064Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#bn1.updates #deprecated","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:40:28.205815Z","iopub.execute_input":"2021-12-02T06:40:28.206081Z","iopub.status.idle":"2021-12-02T06:40:28.213164Z","shell.execute_reply.started":"2021-12-02T06:40:28.206041Z","shell.execute_reply":"2021-12-02T06:40:28.212345Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(loss=\"categorical_crossentropy\",\n              optimizer=keras.optimizers.Adam(learning_rate=0.001),\n              metrics=[\"acc\",]);","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:40:28.21593Z","iopub.execute_input":"2021-12-02T06:40:28.216329Z","iopub.status.idle":"2021-12-02T06:40:28.226414Z","shell.execute_reply.started":"2021-12-02T06:40:28.216291Z","shell.execute_reply":"2021-12-02T06:40:28.225684Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(X_train, y_train, epochs=10,batch_size=1024,\n                    validation_data=(X_test, y_test))\n\ndel model, history\n\ngc.collect()","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-12-02T06:40:28.227866Z","iopub.execute_input":"2021-12-02T06:40:28.228145Z","iopub.status.idle":"2021-12-02T06:43:54.374141Z","shell.execute_reply.started":"2021-12-02T06:40:28.228101Z","shell.execute_reply":"2021-12-02T06:43:54.373401Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:120%\">Sometimes applying BN before the activation function works better (there's a debate on this topic). Moreover, the layer before a <mark>BatchNormalization</mark> layer does not need to have bias terms, since the <mark>BatchNormalization</mark> layer some as well, it would be a waste of parameters, so you can set <mark>use_bias=False</mark> when creating those layers:","metadata":{}},{"cell_type":"code","source":"model = keras.models.Sequential([\n    keras.layers.Flatten(input_shape=[X_train.shape[1],]),\n    keras.layers.BatchNormalization(),\n    keras.layers.Dense(300, use_bias=False),\n    keras.layers.BatchNormalization(),\n    keras.layers.Activation(\"relu\"),\n    keras.layers.Dense(100, use_bias=False),\n    keras.layers.BatchNormalization(),\n    keras.layers.Activation(\"relu\"),\n    keras.layers.Dense(y_train.shape[1], activation=\"softmax\")\n])","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:43:54.375258Z","iopub.execute_input":"2021-12-02T06:43:54.375691Z","iopub.status.idle":"2021-12-02T06:43:54.440137Z","shell.execute_reply.started":"2021-12-02T06:43:54.37565Z","shell.execute_reply":"2021-12-02T06:43:54.439483Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(loss=\"categorical_crossentropy\",\n              optimizer=keras.optimizers.Adam(learning_rate=0.001),\n              metrics=[\"acc\",]);","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:43:54.44134Z","iopub.execute_input":"2021-12-02T06:43:54.441576Z","iopub.status.idle":"2021-12-02T06:43:54.449547Z","shell.execute_reply.started":"2021-12-02T06:43:54.441551Z","shell.execute_reply":"2021-12-02T06:43:54.448886Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(X_train, y_train, epochs=10,batch_size=1024,\n                    validation_data=(X_test, y_test))\n\ndel model, history\ngc.collect()","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-12-02T06:43:54.450789Z","iopub.execute_input":"2021-12-02T06:43:54.451206Z","iopub.status.idle":"2021-12-02T06:46:23.978964Z","shell.execute_reply.started":"2021-12-02T06:43:54.451169Z","shell.execute_reply":"2021-12-02T06:46:23.978273Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h1 style=\"font-size:50px;color:#2874A6\"><strong>Gradient </strong> <strong style=\"color:black\">Clipping</strong></h1>","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:120%\">All Keras optimizers accept <mark>clipnorm</mark> or <mark>clipvalue</mark> arguments:\n    \n    Gradient clipping is a technique to prevent exploding gradients in very deep networks, usually in recurrent neural networks. ... With gradient clipping, pre-determined gradient threshold be introduced, and then gradients norms that exceed this threshold are scaled down to match the norm.","metadata":{}},{"cell_type":"code","source":"optimizer = keras.optimizers.SGD(clipvalue=1.0)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:46:23.980135Z","iopub.execute_input":"2021-12-02T06:46:23.98046Z","iopub.status.idle":"2021-12-02T06:46:23.985154Z","shell.execute_reply.started":"2021-12-02T06:46:23.980421Z","shell.execute_reply":"2021-12-02T06:46:23.984379Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"optimizer = keras.optimizers.SGD(clipnorm=1.0)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:46:23.986218Z","iopub.execute_input":"2021-12-02T06:46:23.987021Z","iopub.status.idle":"2021-12-02T06:46:23.997756Z","shell.execute_reply.started":"2021-12-02T06:46:23.98698Z","shell.execute_reply":"2021-12-02T06:46:23.996977Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h1 style=\"font-size:50px;color:#2874A6\"><strong>Reusing</strong> <strong style=\"color:black\">Pretrained Layers</strong></h1>","metadata":{}},{"cell_type":"markdown","source":"<h1 style=\"font-size:30px;color:#2874A6\"><strong>Reusing a</strong> <strong style=\"color:black\">Keras model</strong></h1>","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:120%\">\nLet's split the fashion MNIST training set in two:\n<ul>\n<li> <strong>X_train_A</strong>: all images of all items except for sandals and shirts (classes 5 and 6).</li>\n<li> <strong>X_train_B</strong>: a much smaller training set of just the first 200 images of sandals or shirts.</li>\n\nThe validation set and the test set are also split this way, but without restricting the number of images.\n\nWe will train a model on set A (classification task with 8 classes), and try to reuse it to tackle set B (binary classification). We hope to transfer a little bit of knowledge from task A to task B, since classes in set A (sneakers, ankle boots, coats, t-shirts, etc.) are somewhat similar to classes in set B (sandals and shirts). However, since we are using `Dense` layers, only patterns that occur at the same location can be reused (in contrast, convolutional layers will transfer much better, since learned patterns can be detected anywhere on the image, as we will see in the CNN chapter).</p>","metadata":{}},{"cell_type":"code","source":"(X_train_full, y_train_full), (_X_test, _y_test) = keras.datasets.fashion_mnist.load_data()\nX_train_full = X_train_full / 255.0\n_X_test = _X_test / 255.0\n_X_valid, _X_train = X_train_full[:5000], X_train_full[5000:]\n_y_valid, _y_train = y_train_full[:5000], y_train_full[5000:]","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:46:23.999087Z","iopub.execute_input":"2021-12-02T06:46:23.999341Z","iopub.status.idle":"2021-12-02T06:46:25.309677Z","shell.execute_reply.started":"2021-12-02T06:46:23.999304Z","shell.execute_reply":"2021-12-02T06:46:25.308961Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def split_dataset(X, y):\n    y_5_or_6 = (y == 5) | (y == 6) # sandals or shirts\n    y_A = y[~y_5_or_6]\n    y_A[y_A > 6] -= 2 # class indices 7, 8, 9 should be moved to 5, 6, 7\n    y_B = (y[y_5_or_6] == 6).astype(np.float32) # binary classification task: is it a shirt (class 6)?\n    return ((X[~y_5_or_6], y_A),\n            (X[y_5_or_6], y_B))\n\n(X_train_A, y_train_A), (X_train_B, y_train_B) = split_dataset(_X_train, _y_train)\n(X_valid_A, y_valid_A), (X_valid_B, y_valid_B) = split_dataset(_X_valid, _y_valid)\n(X_test_A, y_test_A), (X_test_B, y_test_B) = split_dataset(_X_test, _y_test)\nX_train_B = X_train_B[:200]\ny_train_B = y_train_B[:200]\n\n# del _X_train, _X_valid, _y_valid, _y_train, _X_test, _y_test\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:46:25.310935Z","iopub.execute_input":"2021-12-02T06:46:25.311182Z","iopub.status.idle":"2021-12-02T06:46:25.585084Z","shell.execute_reply.started":"2021-12-02T06:46:25.31115Z","shell.execute_reply":"2021-12-02T06:46:25.584262Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train_A.shape","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:46:25.586586Z","iopub.execute_input":"2021-12-02T06:46:25.586864Z","iopub.status.idle":"2021-12-02T06:46:25.592129Z","shell.execute_reply.started":"2021-12-02T06:46:25.586829Z","shell.execute_reply":"2021-12-02T06:46:25.591359Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train_B.shape","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:46:25.593574Z","iopub.execute_input":"2021-12-02T06:46:25.593861Z","iopub.status.idle":"2021-12-02T06:46:25.604788Z","shell.execute_reply.started":"2021-12-02T06:46:25.593821Z","shell.execute_reply":"2021-12-02T06:46:25.604092Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_train_A[:30]","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:46:25.606184Z","iopub.execute_input":"2021-12-02T06:46:25.606475Z","iopub.status.idle":"2021-12-02T06:46:25.614123Z","shell.execute_reply.started":"2021-12-02T06:46:25.606439Z","shell.execute_reply":"2021-12-02T06:46:25.612834Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_train_B[:30]","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:46:25.619671Z","iopub.execute_input":"2021-12-02T06:46:25.619864Z","iopub.status.idle":"2021-12-02T06:46:25.629348Z","shell.execute_reply.started":"2021-12-02T06:46:25.619842Z","shell.execute_reply":"2021-12-02T06:46:25.628487Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tf.random.set_seed(42)\nnp.random.seed(42)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:46:25.632198Z","iopub.execute_input":"2021-12-02T06:46:25.632401Z","iopub.status.idle":"2021-12-02T06:46:25.637598Z","shell.execute_reply.started":"2021-12-02T06:46:25.632376Z","shell.execute_reply":"2021-12-02T06:46:25.636881Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_A = keras.models.Sequential()\nmodel_A.add(keras.layers.Flatten(input_shape=[28, 28]))\nfor n_hidden in (300, 100, 50, 50, 50):\n    model_A.add(keras.layers.Dense(n_hidden, activation=\"selu\"))\nmodel_A.add(keras.layers.Dense(8, activation=\"softmax\"))","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:46:25.63909Z","iopub.execute_input":"2021-12-02T06:46:25.639499Z","iopub.status.idle":"2021-12-02T06:46:25.692961Z","shell.execute_reply.started":"2021-12-02T06:46:25.639464Z","shell.execute_reply":"2021-12-02T06:46:25.692322Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_A.compile(loss=\"sparse_categorical_crossentropy\",\n                optimizer=keras.optimizers.SGD(learning_rate=1e-3),\n                metrics=[\"accuracy\"])","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:46:25.69543Z","iopub.execute_input":"2021-12-02T06:46:25.696765Z","iopub.status.idle":"2021-12-02T06:46:25.706288Z","shell.execute_reply.started":"2021-12-02T06:46:25.696729Z","shell.execute_reply":"2021-12-02T06:46:25.705577Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model_A.fit(X_train_A, y_train_A, epochs=20,\n                    validation_data=(X_valid_A, y_valid_A))","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-12-02T06:46:25.707752Z","iopub.execute_input":"2021-12-02T06:46:25.708106Z","iopub.status.idle":"2021-12-02T06:47:48.215424Z","shell.execute_reply.started":"2021-12-02T06:46:25.70797Z","shell.execute_reply":"2021-12-02T06:47:48.214597Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_A.save(\"my_model_A.h5\")","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:47:48.217028Z","iopub.execute_input":"2021-12-02T06:47:48.217382Z","iopub.status.idle":"2021-12-02T06:47:48.255687Z","shell.execute_reply.started":"2021-12-02T06:47:48.217344Z","shell.execute_reply":"2021-12-02T06:47:48.255054Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_B = keras.models.Sequential()\nmodel_B.add(keras.layers.Flatten(input_shape=[28, 28]))\nfor n_hidden in (300, 100, 50, 50, 50):\n    model_B.add(keras.layers.Dense(n_hidden, activation=\"selu\"))\nmodel_B.add(keras.layers.Dense(1, activation=\"sigmoid\"))","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:47:48.258241Z","iopub.execute_input":"2021-12-02T06:47:48.258788Z","iopub.status.idle":"2021-12-02T06:47:48.308436Z","shell.execute_reply.started":"2021-12-02T06:47:48.258758Z","shell.execute_reply":"2021-12-02T06:47:48.307818Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_B.compile(loss=\"categorical_crossentropy\",\n                optimizer=keras.optimizers.SGD(learning_rate=1e-3),\n                metrics=[\"accuracy\"])","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:47:48.309455Z","iopub.execute_input":"2021-12-02T06:47:48.309738Z","iopub.status.idle":"2021-12-02T06:47:48.31892Z","shell.execute_reply.started":"2021-12-02T06:47:48.3097Z","shell.execute_reply":"2021-12-02T06:47:48.318123Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model_B.fit(X_train_B, y_train_B, epochs=20,\n                      validation_data=(X_valid_B, y_valid_B))","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-12-02T06:47:48.319983Z","iopub.execute_input":"2021-12-02T06:47:48.320344Z","iopub.status.idle":"2021-12-02T06:47:50.475006Z","shell.execute_reply.started":"2021-12-02T06:47:48.320305Z","shell.execute_reply":"2021-12-02T06:47:50.474315Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_B.summary()","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:47:50.476694Z","iopub.execute_input":"2021-12-02T06:47:50.476945Z","iopub.status.idle":"2021-12-02T06:47:50.486201Z","shell.execute_reply.started":"2021-12-02T06:47:50.476911Z","shell.execute_reply":"2021-12-02T06:47:50.485435Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_A = keras.models.load_model(\"my_model_A.h5\")\nmodel_B_on_A = keras.models.Sequential(model_A.layers[:-1])\nmodel_B_on_A.add(keras.layers.Dense(1, activation=\"sigmoid\"))","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:47:50.487484Z","iopub.execute_input":"2021-12-02T06:47:50.487837Z","iopub.status.idle":"2021-12-02T06:47:50.592961Z","shell.execute_reply.started":"2021-12-02T06:47:50.487799Z","shell.execute_reply":"2021-12-02T06:47:50.592287Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:120%\">Note that <mark>model_B_on_A</mark> and <mark>model_A</mark> actually share layers now, so when we train one, it will update both models. If we want to avoid that, we need to build <mark>model_B_on_A</mark> on top of a <strong>clone</strong> of <mark>model_A</mark>:","metadata":{}},{"cell_type":"code","source":"model_A_clone = keras.models.clone_model(model_A)\nmodel_A_clone.set_weights(model_A.get_weights())\nmodel_B_on_A = keras.models.Sequential(model_A_clone.layers[:-1])\nmodel_B_on_A.add(keras.layers.Dense(1, activation=\"sigmoid\"))","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:47:50.593938Z","iopub.execute_input":"2021-12-02T06:47:50.59417Z","iopub.status.idle":"2021-12-02T06:47:50.678593Z","shell.execute_reply.started":"2021-12-02T06:47:50.594137Z","shell.execute_reply":"2021-12-02T06:47:50.677967Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for layer in model_B_on_A.layers[:-1]:\n    layer.trainable = False\n\nmodel_B_on_A.compile(loss=\"categorical_crossentropy\",\n                     optimizer=keras.optimizers.SGD(learning_rate=1e-3),\n                     metrics=[\"accuracy\"])","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:47:50.679826Z","iopub.execute_input":"2021-12-02T06:47:50.680072Z","iopub.status.idle":"2021-12-02T06:47:50.689405Z","shell.execute_reply.started":"2021-12-02T06:47:50.680038Z","shell.execute_reply":"2021-12-02T06:47:50.688676Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model_B_on_A.fit(X_train_B, y_train_B, epochs=4,\n                           validation_data=(X_valid_B, y_valid_B))\n\nfor layer in model_B_on_A.layers[:-1]:\n    layer.trainable = True\n\nmodel_B_on_A.compile(loss=\"categorical_crossentropy\",\n                     optimizer=keras.optimizers.SGD(learning_rate=1e-3),\n                     metrics=[\"accuracy\"])\nhistory = model_B_on_A.fit(X_train_B, y_train_B, epochs=16,\n                           validation_data=(X_valid_B, y_valid_B))","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-12-02T06:47:50.69054Z","iopub.execute_input":"2021-12-02T06:47:50.691172Z","iopub.status.idle":"2021-12-02T06:47:55.1278Z","shell.execute_reply.started":"2021-12-02T06:47:50.691131Z","shell.execute_reply":"2021-12-02T06:47:55.126994Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:120%\">So, what's the final verdict?","metadata":{}},{"cell_type":"code","source":"model_B.evaluate(X_test_B, y_test_B)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:47:55.130875Z","iopub.execute_input":"2021-12-02T06:47:55.131385Z","iopub.status.idle":"2021-12-02T06:47:55.302306Z","shell.execute_reply.started":"2021-12-02T06:47:55.131352Z","shell.execute_reply":"2021-12-02T06:47:55.301668Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_B_on_A.evaluate(X_test_B, y_test_B)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:47:55.303535Z","iopub.execute_input":"2021-12-02T06:47:55.303875Z","iopub.status.idle":"2021-12-02T06:47:55.494141Z","shell.execute_reply.started":"2021-12-02T06:47:55.303838Z","shell.execute_reply":"2021-12-02T06:47:55.493451Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:120%\">Great! We got quite a bit of transfer: the error rate dropped by a factor of 4.9!","metadata":{}},{"cell_type":"code","source":"(100 - 97.05) / (100 - 99.40)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:47:55.495375Z","iopub.execute_input":"2021-12-02T06:47:55.495622Z","iopub.status.idle":"2021-12-02T06:47:55.50066Z","shell.execute_reply.started":"2021-12-02T06:47:55.495589Z","shell.execute_reply":"2021-12-02T06:47:55.499908Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h1 style=\"font-size:50px;color:#2874A6\"><strong>Faster </strong> <strong style=\"color:black\">Optimizers</strong></h1>","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>Momentum optimization</strong></p>","metadata":{}},{"cell_type":"code","source":"optimizer = keras.optimizers.SGD(learning_rate=0.001, momentum=0.9)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:47:55.502064Z","iopub.execute_input":"2021-12-02T06:47:55.502486Z","iopub.status.idle":"2021-12-02T06:47:55.510652Z","shell.execute_reply.started":"2021-12-02T06:47:55.502448Z","shell.execute_reply":"2021-12-02T06:47:55.509933Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>Nesterov Accelerated Gradient","metadata":{}},{"cell_type":"code","source":"optimizer = keras.optimizers.SGD(learning_rate=0.001, momentum=0.9, nesterov=True)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:47:55.512238Z","iopub.execute_input":"2021-12-02T06:47:55.512721Z","iopub.status.idle":"2021-12-02T06:47:55.522466Z","shell.execute_reply.started":"2021-12-02T06:47:55.512685Z","shell.execute_reply":"2021-12-02T06:47:55.521652Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>AdaGrad","metadata":{}},{"cell_type":"code","source":"optimizer = keras.optimizers.Adagrad(learning_rate=0.001)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:47:55.523721Z","iopub.execute_input":"2021-12-02T06:47:55.524038Z","iopub.status.idle":"2021-12-02T06:47:55.531196Z","shell.execute_reply.started":"2021-12-02T06:47:55.524004Z","shell.execute_reply":"2021-12-02T06:47:55.530439Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>RMSProp","metadata":{}},{"cell_type":"code","source":"optimizer = keras.optimizers.RMSprop(learning_rate=0.001, rho=0.9)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:47:55.532463Z","iopub.execute_input":"2021-12-02T06:47:55.532768Z","iopub.status.idle":"2021-12-02T06:47:55.540102Z","shell.execute_reply.started":"2021-12-02T06:47:55.532731Z","shell.execute_reply":"2021-12-02T06:47:55.539322Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>Adam Optimization","metadata":{}},{"cell_type":"code","source":"optimizer = keras.optimizers.Adam(learning_rate=0.001, beta_1=0.9, beta_2=0.999)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:47:55.543124Z","iopub.execute_input":"2021-12-02T06:47:55.543308Z","iopub.status.idle":"2021-12-02T06:47:55.549519Z","shell.execute_reply.started":"2021-12-02T06:47:55.543286Z","shell.execute_reply":"2021-12-02T06:47:55.548734Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>Adamax Optimization","metadata":{}},{"cell_type":"code","source":"optimizer = keras.optimizers.Adamax(learning_rate=0.001, beta_1=0.9, beta_2=0.999)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:47:55.550867Z","iopub.execute_input":"2021-12-02T06:47:55.551132Z","iopub.status.idle":"2021-12-02T06:47:55.558058Z","shell.execute_reply.started":"2021-12-02T06:47:55.551098Z","shell.execute_reply":"2021-12-02T06:47:55.557298Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>Nadam Optimization","metadata":{}},{"cell_type":"code","source":"optimizer = keras.optimizers.Nadam(learning_rate=0.001, beta_1=0.9, beta_2=0.999)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:47:55.55917Z","iopub.execute_input":"2021-12-02T06:47:55.559719Z","iopub.status.idle":"2021-12-02T06:47:55.566715Z","shell.execute_reply.started":"2021-12-02T06:47:55.559609Z","shell.execute_reply":"2021-12-02T06:47:55.565913Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>Learning Rate Scheduling","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>Power Scheduling","metadata":{}},{"cell_type":"markdown","source":"```lr = lr0 / (1 + steps / s)**c```\n* Keras uses `c=1` and `s = 1 / decay`","metadata":{}},{"cell_type":"code","source":"optimizer = keras.optimizers.SGD(learning_rate=0.01, decay=1e-4)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:48:48.242942Z","iopub.execute_input":"2021-12-02T06:48:48.243722Z","iopub.status.idle":"2021-12-02T06:48:48.248663Z","shell.execute_reply.started":"2021-12-02T06:48:48.243661Z","shell.execute_reply":"2021-12-02T06:48:48.247667Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = keras.models.Sequential([\n    keras.layers.Flatten(input_shape=[X_train.shape[1],]),\n    keras.layers.Dense(300, activation=\"selu\", kernel_initializer=\"lecun_normal\"),\n    keras.layers.Dense(100, activation=\"selu\", kernel_initializer=\"lecun_normal\"),\n    keras.layers.Dense(y_train.shape[1], activation=\"softmax\")\n])\nmodel.compile(loss=\"categorical_crossentropy\",\n              optimizer=optimizer,\n              metrics=[\"acc\",]);","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:48:48.483579Z","iopub.execute_input":"2021-12-02T06:48:48.48423Z","iopub.status.idle":"2021-12-02T06:48:48.520107Z","shell.execute_reply.started":"2021-12-02T06:48:48.484191Z","shell.execute_reply":"2021-12-02T06:48:48.519468Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_epochs = 20\nhistory = model.fit(X_train_scaled, y_train, epochs=n_epochs,batch_size=1024,\n                    validation_data=(X_test_scaled, y_test))\n\ndel model\ngc.collect()","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-12-02T06:48:51.952002Z","iopub.execute_input":"2021-12-02T06:48:51.95295Z","iopub.status.idle":"2021-12-02T06:52:00.106285Z","shell.execute_reply.started":"2021-12-02T06:48:51.952898Z","shell.execute_reply":"2021-12-02T06:52:00.105584Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import math\n\nlearning_rate = 0.01\ndecay = 1e-4\nbatch_size = 32\nn_steps_per_epoch = math.ceil(len(X_train) / batch_size)\nepochs = np.arange(n_epochs)\nlrs = learning_rate / (1 + decay * epochs * n_steps_per_epoch)\n\nplt.plot(epochs, lrs,  \"o-\")\nplt.axis([0, n_epochs - 1, 0, 0.01])\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Learning Rate\")\nplt.title(\"Power Scheduling\", fontsize=14)\nplt.grid(True)\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-02T06:52:00.107875Z","iopub.execute_input":"2021-12-02T06:52:00.10813Z","iopub.status.idle":"2021-12-02T06:52:00.305093Z","shell.execute_reply.started":"2021-12-02T06:52:00.108096Z","shell.execute_reply":"2021-12-02T06:52:00.304446Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>Exponential Scheduling","metadata":{}},{"cell_type":"markdown","source":"```lr = lr0 * 0.1**(epoch / s)```","metadata":{}},{"cell_type":"code","source":"def exponential_decay_fn(epoch):\n    return 0.01 * 0.1**(epoch / 20)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:52:00.306174Z","iopub.execute_input":"2021-12-02T06:52:00.306417Z","iopub.status.idle":"2021-12-02T06:52:00.310589Z","shell.execute_reply.started":"2021-12-02T06:52:00.306383Z","shell.execute_reply":"2021-12-02T06:52:00.30988Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def exponential_decay(lr0, s):\n    def exponential_decay_fn(epoch):\n        return lr0 * 0.1**(epoch / s)\n    return exponential_decay_fn\n\nexponential_decay_fn = exponential_decay(lr0=0.01, s=20)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:52:00.312467Z","iopub.execute_input":"2021-12-02T06:52:00.312911Z","iopub.status.idle":"2021-12-02T06:52:00.32071Z","shell.execute_reply.started":"2021-12-02T06:52:00.312873Z","shell.execute_reply":"2021-12-02T06:52:00.319914Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = keras.models.Sequential([\n    keras.layers.Flatten(input_shape=[X_train.shape[1],]),\n    keras.layers.Dense(300, activation=\"selu\", kernel_initializer=\"lecun_normal\"),\n    keras.layers.Dense(100, activation=\"selu\", kernel_initializer=\"lecun_normal\"),\n    keras.layers.Dense(y_train.shape[1], activation=\"softmax\")\n])\n\nmodel.compile(loss=\"categorical_crossentropy\",\n              optimizer=\"nadam\",\n              metrics=[\"acc\",]);\nn_epochs = 20","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:52:00.322419Z","iopub.execute_input":"2021-12-02T06:52:00.323026Z","iopub.status.idle":"2021-12-02T06:52:00.359139Z","shell.execute_reply.started":"2021-12-02T06:52:00.322983Z","shell.execute_reply":"2021-12-02T06:52:00.358502Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"lr_scheduler = keras.callbacks.LearningRateScheduler(exponential_decay_fn)\nhistory = model.fit(X_train_scaled, y_train, epochs=n_epochs,batch_size=1024,\n                    validation_data=(X_test_scaled, y_test),\n                    callbacks=[lr_scheduler])\n\ndel model\ngc.collect()","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-12-02T06:52:00.360207Z","iopub.execute_input":"2021-12-02T06:52:00.360538Z","iopub.status.idle":"2021-12-02T06:56:00.051524Z","shell.execute_reply.started":"2021-12-02T06:52:00.360467Z","shell.execute_reply":"2021-12-02T06:56:00.050804Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(history.epoch, history.history[\"lr\"], \"o-\")\nplt.axis([0, n_epochs - 1, 0, 0.011])\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Learning Rate\")\nplt.title(\"Exponential Scheduling\", fontsize=14)\nplt.grid(True)\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-02T06:56:00.052764Z","iopub.execute_input":"2021-12-02T06:56:00.053096Z","iopub.status.idle":"2021-12-02T06:56:00.252127Z","shell.execute_reply.started":"2021-12-02T06:56:00.053056Z","shell.execute_reply":"2021-12-02T06:56:00.251445Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:120%\">The schedule function can take the current learning rate as a second argument:","metadata":{}},{"cell_type":"code","source":"def exponential_decay_fn(epoch, lr):\n    return lr * 0.1**(1 / 20)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:56:00.253444Z","iopub.execute_input":"2021-12-02T06:56:00.253902Z","iopub.status.idle":"2021-12-02T06:56:00.257526Z","shell.execute_reply.started":"2021-12-02T06:56:00.253865Z","shell.execute_reply":"2021-12-02T06:56:00.256876Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:120%\">If you want to update the learning rate at each iteration rather than at each epoch, you must write your own callback class:","metadata":{}},{"cell_type":"code","source":"K = keras.backend\n\nclass ExponentialDecay(keras.callbacks.Callback):\n    def __init__(self, s=40000):\n        super().__init__()\n        self.s = s\n\n    def on_batch_begin(self, batch, logs=None):\n        # Note: the `batch` argument is reset at each epoch\n        lr = K.get_value(self.model.optimizer.learning_rate)\n        K.set_value(self.model.optimizer.learning_rate, lr * 0.1**(1 / s))\n\n    def on_epoch_end(self, epoch, logs=None):\n        logs = logs or {}\n        logs['lr'] = K.get_value(self.model.optimizer.learning_rate)\n\nmodel = keras.models.Sequential([\n    keras.layers.Flatten(input_shape=[X_train.shape[1],]),\n    keras.layers.Dense(300, activation=\"selu\", kernel_initializer=\"lecun_normal\"),\n    keras.layers.Dense(100, activation=\"selu\", kernel_initializer=\"lecun_normal\"),\n    keras.layers.Dense(y_train.shape[1], activation=\"softmax\")\n])\nlr0 = 0.01\noptimizer = keras.optimizers.Nadam(learning_rate=lr0)\nmodel.compile(loss=\"categorical_crossentropy\", optimizer=optimizer, metrics=[\"acc\",])\nn_epochs = 25\n\ns = 20 * len(X_train) // 32 # number of steps in 20 epochs (batch size = 32)\nexp_decay = ExponentialDecay(s)\nhistory = model.fit(X_train_scaled, y_train, epochs=n_epochs,batch_size=1024,\n                    validation_data=(X_test_scaled, y_test),\n                    callbacks=[exp_decay])\n\ndel model\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2021-12-02T06:56:00.258809Z","iopub.execute_input":"2021-12-02T06:56:00.259273Z","iopub.status.idle":"2021-12-02T07:02:26.20932Z","shell.execute_reply.started":"2021-12-02T06:56:00.259237Z","shell.execute_reply":"2021-12-02T07:02:26.208565Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_steps = n_epochs * len(X_train) // 32\nsteps = np.arange(n_steps)\nlrs = lr0 * 0.1**(steps / s)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T07:02:26.212498Z","iopub.execute_input":"2021-12-02T07:02:26.212716Z","iopub.status.idle":"2021-12-02T07:02:26.371018Z","shell.execute_reply.started":"2021-12-02T07:02:26.21269Z","shell.execute_reply":"2021-12-02T07:02:26.370168Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(steps, lrs, \"-\", linewidth=2)\nplt.axis([0, n_steps - 1, 0, lr0 * 1.1])\nplt.xlabel(\"Batch\")\nplt.ylabel(\"Learning Rate\")\nplt.title(\"Exponential Scheduling (per batch)\", fontsize=14)\nplt.grid(True)\nplt.show()","metadata":{"scrolled":true,"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-02T07:02:26.372392Z","iopub.execute_input":"2021-12-02T07:02:26.373181Z","iopub.status.idle":"2021-12-02T07:02:26.794267Z","shell.execute_reply.started":"2021-12-02T07:02:26.373131Z","shell.execute_reply":"2021-12-02T07:02:26.793622Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>Piecewise Constant Scheduling","metadata":{}},{"cell_type":"code","source":"def piecewise_constant_fn(epoch):\n    if epoch < 5:\n        return 0.01\n    elif epoch < 15:\n        return 0.005\n    else:\n        return 0.001","metadata":{"execution":{"iopub.status.busy":"2021-12-02T07:02:26.79543Z","iopub.execute_input":"2021-12-02T07:02:26.796799Z","iopub.status.idle":"2021-12-02T07:02:26.801508Z","shell.execute_reply.started":"2021-12-02T07:02:26.796756Z","shell.execute_reply":"2021-12-02T07:02:26.800816Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def piecewise_constant(boundaries, values):\n    boundaries = np.array([0] + boundaries)\n    values = np.array(values)\n    def piecewise_constant_fn(epoch):\n        return values[np.argmax(boundaries > epoch) - 1]\n    return piecewise_constant_fn\n\npiecewise_constant_fn = piecewise_constant([5, 15], [0.01, 0.005, 0.001])","metadata":{"execution":{"iopub.status.busy":"2021-12-02T07:02:26.802772Z","iopub.execute_input":"2021-12-02T07:02:26.803052Z","iopub.status.idle":"2021-12-02T07:02:26.811028Z","shell.execute_reply.started":"2021-12-02T07:02:26.80301Z","shell.execute_reply":"2021-12-02T07:02:26.810286Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"lr_scheduler = keras.callbacks.LearningRateScheduler(piecewise_constant_fn)\n\nmodel = keras.models.Sequential([\n    keras.layers.Flatten(input_shape=[X_train.shape[1],]),\n    keras.layers.Dense(300, activation=\"selu\", kernel_initializer=\"lecun_normal\"),\n    keras.layers.Dense(100, activation=\"selu\", kernel_initializer=\"lecun_normal\"),\n    keras.layers.Dense(y_train.shape[1], activation=\"softmax\")\n])\nmodel.compile(loss=\"categorical_crossentropy\", optimizer=\"nadam\", metrics=[\"acc\",])\nn_epochs = 25\nhistory = model.fit(X_train_scaled, y_train, epochs=n_epochs,batch_size=1024,\n                    validation_data=(X_test_scaled, y_test),\n                    callbacks=[lr_scheduler])\n\ndel model\ngc.collect()","metadata":{"_kg_hide-output":true,"_kg_hide-input":false,"execution":{"iopub.status.busy":"2021-12-02T07:02:26.812367Z","iopub.execute_input":"2021-12-02T07:02:26.81271Z","iopub.status.idle":"2021-12-02T07:07:52.876353Z","shell.execute_reply.started":"2021-12-02T07:02:26.812672Z","shell.execute_reply":"2021-12-02T07:07:52.875571Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(history.epoch, [piecewise_constant_fn(epoch) for epoch in history.epoch], \"o-\")\nplt.axis([0, n_epochs - 1, 0, 0.011])\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Learning Rate\")\nplt.title(\"Piecewise Constant Scheduling\", fontsize=14)\nplt.grid(True)\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-02T07:07:52.877871Z","iopub.execute_input":"2021-12-02T07:07:52.878136Z","iopub.status.idle":"2021-12-02T07:07:53.078236Z","shell.execute_reply.started":"2021-12-02T07:07:52.878101Z","shell.execute_reply":"2021-12-02T07:07:53.0775Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>Performance Scheduling","metadata":{}},{"cell_type":"code","source":"tf.random.set_seed(42)\nnp.random.seed(42)","metadata":{"execution":{"iopub.status.busy":"2021-12-02T07:07:53.079341Z","iopub.execute_input":"2021-12-02T07:07:53.079592Z","iopub.status.idle":"2021-12-02T07:07:53.098857Z","shell.execute_reply.started":"2021-12-02T07:07:53.079557Z","shell.execute_reply":"2021-12-02T07:07:53.098078Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"lr_scheduler = keras.callbacks.ReduceLROnPlateau(factor=0.5, patience=5)\n\nmodel = keras.models.Sequential([\n    keras.layers.Flatten(input_shape=[X_train.shape[1],]),\n    keras.layers.Dense(300, activation=\"selu\", kernel_initializer=\"lecun_normal\"),\n    keras.layers.Dense(100, activation=\"selu\", kernel_initializer=\"lecun_normal\"),\n    keras.layers.Dense(y_train.shape[1], activation=\"softmax\")\n])\noptimizer = keras.optimizers.SGD(learning_rate=0.02, momentum=0.9)\nmodel.compile(loss=\"categorical_crossentropy\", optimizer=optimizer, metrics=[\"acc\",])\nn_epochs = 25\nhistory = model.fit(X_train_scaled, y_train, epochs=n_epochs,\n                    validation_data=(X_test_scaled, y_test),\n                    callbacks=[lr_scheduler])\n\ndel model\ngc.collect()","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-12-02T07:07:53.100223Z","iopub.execute_input":"2021-12-02T07:07:53.101009Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(history.epoch, history.history[\"lr\"], \"bo-\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Learning Rate\", color='b')\nplt.tick_params('y', colors='b')\nplt.gca().set_xlim(0, n_epochs - 1)\nplt.grid(True)\n\nax2 = plt.gca().twinx()\nax2.plot(history.epoch, history.history[\"val_loss\"], \"r^-\")\nax2.set_ylabel('Validation Loss', color='r')\nax2.tick_params('y', colors='r')\n\nplt.title(\"Reduce LR on Plateau\", fontsize=14)\nplt.show()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>tf.keras schedulers","metadata":{}},{"cell_type":"code","source":"model = keras.models.Sequential([\n    keras.layers.Flatten(input_shape=[X_train.shape[1],]),\n    keras.layers.Dense(300, activation=\"selu\", kernel_initializer=\"lecun_normal\"),\n    keras.layers.Dense(100, activation=\"selu\", kernel_initializer=\"lecun_normal\"),\n    keras.layers.Dense(y_train.shape[1], activation=\"softmax\")\n])\ns = 20 * len(X_train) // 32 # number of steps in 20 epochs (batch size = 32)\nlearning_rate = keras.optimizers.schedules.ExponentialDecay(0.01, s, 0.1)\noptimizer = keras.optimizers.SGD(learning_rate)\nmodel.compile(loss=\"categorical_crossentropy\", optimizer=optimizer, metrics=[\"AUC\"])\nn_epochs = 25\nhistory = model.fit(X_train_scaled, y_train, epochs=n_epochs,batch_size=1024,\n                    validation_data=(X_test_scaled, y_test))\ndel model\ngc.collect()","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:120%\">For piecewise constant scheduling, try this:","metadata":{}},{"cell_type":"code","source":"learning_rate = keras.optimizers.schedules.PiecewiseConstantDecay(\n    boundaries=[5. * n_steps_per_epoch, 15. * n_steps_per_epoch],\n    values=[0.01, 0.005, 0.001])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>1Cycle scheduling","metadata":{}},{"cell_type":"code","source":"K = keras.backend\n\nclass ExponentialLearningRate(keras.callbacks.Callback):\n    def __init__(self, factor):\n        self.factor = factor\n        self.rates = []\n        self.losses = []\n    def on_batch_end(self, batch, logs):\n        self.rates.append(K.get_value(self.model.optimizer.learning_rate))\n        self.losses.append(logs[\"loss\"])\n        K.set_value(self.model.optimizer.learning_rate, self.model.optimizer.learning_rate * self.factor)\n\ndef find_learning_rate(model, X, y, epochs=1, batch_size=32, min_rate=10**-5, max_rate=10):\n    init_weights = model.get_weights()\n    iterations = math.ceil(len(X) / batch_size) * epochs\n    factor = np.exp(np.log(max_rate / min_rate) / iterations)\n    init_lr = K.get_value(model.optimizer.learning_rate)\n    K.set_value(model.optimizer.learning_rate, min_rate)\n    exp_lr = ExponentialLearningRate(factor)\n    history = model.fit(X, y, epochs=epochs, batch_size=batch_size,\n                        callbacks=[exp_lr])\n    K.set_value(model.optimizer.learning_rate, init_lr)\n    model.set_weights(init_weights)\n    return exp_lr.rates, exp_lr.losses\n\ndef plot_lr_vs_loss(rates, losses):\n    plt.plot(rates, losses)\n    plt.gca().set_xscale('log')\n    plt.hlines(min(losses), min(rates), max(rates))\n    plt.axis([min(rates), max(rates), min(losses), (losses[0] + min(losses)) / 2])\n    plt.xlabel(\"Learning rate\")\n    plt.ylabel(\"Loss\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Warning**: In the `on_batch_end()` method, `logs[\"loss\"]` used to contain the batch loss, but in TensorFlow 2.2.0 it was replaced with the mean loss (since the start of the epoch). This explains why the graph below is much smoother than in the book (if you are using TF 2.2 or above). It also means that there is a lag between the moment the batch loss starts exploding and the moment the explosion becomes clear in the graph. So you should choose a slightly smaller learning rate than you would have chosen with the \"noisy\" graph. Alternatively, you can tweak the `ExponentialLearningRate` callback above so it computes the batch loss (based on the current mean loss and the previous mean loss):\n\n```python\nclass ExponentialLearningRate(keras.callbacks.Callback):\n    def __init__(self, factor):\n        self.factor = factor\n        self.rates = []\n        self.losses = []\n    def on_epoch_begin(self, epoch, logs=None):\n        self.prev_loss = 0\n    def on_batch_end(self, batch, logs=None):\n        batch_loss = logs[\"loss\"] * (batch + 1) - self.prev_loss * batch\n        self.prev_loss = logs[\"loss\"]\n        self.rates.append(K.get_value(self.model.optimizer.learning_rate))\n        self.losses.append(batch_loss)\n        K.set_value(self.model.optimizer.learning_rate, self.model.optimizer.learning_rate * self.factor)\n```","metadata":{}},{"cell_type":"code","source":"tf.random.set_seed(42)\nnp.random.seed(42)\n\nmodel = keras.models.Sequential([\n    keras.layers.Flatten(input_shape=[X_train.shape[1],]),\n    keras.layers.Dense(300, activation=\"selu\", kernel_initializer=\"lecun_normal\"),\n    keras.layers.Dense(100, activation=\"selu\", kernel_initializer=\"lecun_normal\"),\n    keras.layers.Dense(y_train.shape[1], activation=\"softmax\")\n])\nmodel.compile(loss=\"categorical_crossentropy\",\n              optimizer=keras.optimizers.SGD(learning_rate=1e-3),\n              metrics=[\"acc\",])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch_size = 1024\nrates, losses = find_learning_rate(model, X_train_scaled, y_train, epochs=1, batch_size=batch_size)\nplot_lr_vs_loss(rates, losses)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class OneCycleScheduler(keras.callbacks.Callback):\n    def __init__(self, iterations, max_rate, start_rate=None,\n                 last_iterations=None, last_rate=None):\n        self.iterations = iterations\n        self.max_rate = max_rate\n        self.start_rate = start_rate or max_rate / 10\n        self.last_iterations = last_iterations or iterations // 10 + 1\n        self.half_iteration = (iterations - self.last_iterations) // 2\n        self.last_rate = last_rate or self.start_rate / 1000\n        self.iteration = 0\n    def _interpolate(self, iter1, iter2, rate1, rate2):\n        return ((rate2 - rate1) * (self.iteration - iter1)\n                / (iter2 - iter1) + rate1)\n    def on_batch_begin(self, batch, logs):\n        if self.iteration < self.half_iteration:\n            rate = self._interpolate(0, self.half_iteration, self.start_rate, self.max_rate)\n        elif self.iteration < 2 * self.half_iteration:\n            rate = self._interpolate(self.half_iteration, 2 * self.half_iteration,\n                                     self.max_rate, self.start_rate)\n        else:\n            rate = self._interpolate(2 * self.half_iteration, self.iterations,\n                                     self.start_rate, self.last_rate)\n        self.iteration += 1\n        K.set_value(self.model.optimizer.learning_rate, rate)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_epochs = 25\nonecycle = OneCycleScheduler(math.ceil(len(X_train) / batch_size) * n_epochs, max_rate=0.05)\nhistory = model.fit(X_train_scaled, y_train, epochs=n_epochs, batch_size=batch_size,\n                    validation_data=(X_test_scaled, y_test),\n                    callbacks=[onecycle])\n\ndel  model\ngc.collect()","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h1 style=\"font-size:50px;color:#2874A6\"><strong>Avoiding Overfitting Through </strong> <strong style=\"color:black\">Regularization</strong></h1>","metadata":{}},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>$\\ell_1$ and $\\ell_2$ regularization","metadata":{}},{"cell_type":"code","source":"layer = keras.layers.Dense(100, activation=\"elu\",\n                           kernel_initializer=\"he_normal\",\n                           kernel_regularizer=keras.regularizers.l2(0.01))\n# or l1(0.1) for ℓ1 regularization with a factor of 0.1\n# or l1_l2(0.1, 0.01) for both ℓ1 and ℓ2 regularization, with factors 0.1 and 0.01 respectively","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = keras.models.Sequential([\n    keras.layers.Flatten(input_shape=[X_train.shape[1],]),\n    keras.layers.Dense(300, activation=\"elu\",\n                       kernel_initializer=\"he_normal\",\n                       kernel_regularizer=keras.regularizers.l2(0.01)),\n    keras.layers.Dense(100, activation=\"elu\",\n                       kernel_initializer=\"he_normal\",\n                       kernel_regularizer=keras.regularizers.l2(0.01)),\n    keras.layers.Dense(y_train.shape[1], activation=\"softmax\",\n                       kernel_regularizer=keras.regularizers.l2(0.01))\n])\nmodel.compile(loss=\"categorical_crossentropy\", optimizer=\"nadam\", metrics=[\"acc\",])\nn_epochs = 2\nhistory = model.fit(X_train_scaled, y_train, epochs=n_epochs,batch_size=1024,\n                    validation_data=(X_test_scaled, y_test))\n\ndel model\ngc.collect()","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from functools import partial\n\nRegularizedDense = partial(keras.layers.Dense,\n                           activation=\"elu\",\n                           kernel_initializer=\"he_normal\",\n                           kernel_regularizer=keras.regularizers.l2(0.01))\n\nmodel = keras.models.Sequential([\n    keras.layers.Flatten(input_shape=[X_train.shape[1],]),\n    RegularizedDense(300),\n    RegularizedDense(100),\n    RegularizedDense(y_train.shape[1], activation=\"softmax\")\n])\nmodel.compile(loss=\"categorical_crossentropy\", optimizer=\"nadam\", metrics=[\"acc\",])\nn_epochs = 2\nhistory = model.fit(X_train_scaled, y_train, epochs=n_epochs,batch_size=1024,\n                    validation_data=(X_test_scaled, y_test))\n\ndel model\ngc.collect()","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>Dropout","metadata":{}},{"cell_type":"code","source":"model = keras.models.Sequential([\n    keras.layers.Flatten(input_shape=[X_train.shape[1],]),\n    keras.layers.Dropout(rate=0.2),\n    keras.layers.Dense(300, activation=\"elu\", kernel_initializer=\"he_normal\"),\n    keras.layers.Dropout(rate=0.2),\n    keras.layers.Dense(100, activation=\"elu\", kernel_initializer=\"he_normal\"),\n    keras.layers.Dropout(rate=0.2),\n    keras.layers.Dense(y_train.shape[1], activation=\"softmax\")\n])\nmodel.compile(loss=\"categorical_crossentropy\", optimizer=\"nadam\", metrics=[\"acc\",])\nn_epochs = 2\nhistory = model.fit(X_train_scaled, y_train, epochs=n_epochs,batch_size=1024,\n                    validation_data=(X_test_scaled, y_test))\n\ndel model\ngc.collect()","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>Alpha Dropout","metadata":{}},{"cell_type":"code","source":"tf.random.set_seed(42)\nnp.random.seed(42)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = keras.models.Sequential([\n    keras.layers.Flatten(input_shape=[X_train.shape[1],]),\n    keras.layers.AlphaDropout(rate=0.2),\n    keras.layers.Dense(300, activation=\"selu\", kernel_initializer=\"lecun_normal\"),\n    keras.layers.AlphaDropout(rate=0.2),\n    keras.layers.Dense(100, activation=\"selu\", kernel_initializer=\"lecun_normal\"),\n    keras.layers.AlphaDropout(rate=0.2),\n    keras.layers.Dense(y_train.shape[1], activation=\"softmax\")\n])\noptimizer = keras.optimizers.SGD(learning_rate=0.01, momentum=0.9, nesterov=True)\nmodel.compile(loss=\"categorical_crossentropy\", optimizer=optimizer, metrics=[\"acc\",])\nn_epochs = 20\nhistory = model.fit(X_train_scaled, y_train, epochs=n_epochs,batch_size=1024,\n                    validation_data=(X_test_scaled, y_test))\n\ngc.collect()","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.evaluate(X_test_scaled, y_test)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.evaluate(X_train_scaled, y_train)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(X_train_scaled, y_train)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>MC Dropout","metadata":{}},{"cell_type":"code","source":"tf.random.set_seed(42)\nnp.random.seed(42)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_probas = np.stack([model(X_test_scaled.values, training=True)\n                     for sample in range(100)])\ny_proba = y_probas.mean(axis=0)\ny_std = y_probas.std(axis=0)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"np.round(model.predict(X_test_scaled[:1]), 2)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"np.round(y_probas[:, :1], 2)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"np.round(y_proba[:1], 2)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_std = y_probas.std(axis=0)\nnp.round(y_std[:1], 2)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred = np.argmax(y_proba, axis=1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class MCDropout(keras.layers.Dropout):\n    def call(self, inputs):\n        return super().call(inputs, training=True)\n\nclass MCAlphaDropout(keras.layers.AlphaDropout):\n    def call(self, inputs):\n        return super().call(inputs, training=True)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tf.random.set_seed(42)\nnp.random.seed(42)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mc_model = keras.models.Sequential([\n    MCAlphaDropout(layer.rate) if isinstance(layer, keras.layers.AlphaDropout) else layer\n    for layer in model.layers\n])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mc_model.summary()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"optimizer = keras.optimizers.SGD(learning_rate=0.01, momentum=0.9, nesterov=True)\nmc_model.compile(loss=\"categorical_crossentropy\", optimizer=optimizer, metrics=[\"acc\",])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mc_model.set_weights(model.get_weights())","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now we can use the model with MC Dropout:","metadata":{}},{"cell_type":"code","source":"np.round(np.mean([mc_model.predict(X_test_scaled[:1]) for sample in range(100)], axis=0), 2)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<p style=\"font-size:180%\"><strong>Max norm","metadata":{}},{"cell_type":"code","source":"layer = keras.layers.Dense(100, activation=\"selu\", kernel_initializer=\"lecun_normal\",\n                           kernel_constraint=keras.constraints.max_norm(1.))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"MaxNormDense = partial(keras.layers.Dense,\n                       activation=\"selu\", kernel_initializer=\"lecun_normal\",\n                       kernel_constraint=keras.constraints.max_norm(1.))\n\nmodel = keras.models.Sequential([\n    keras.layers.Flatten(input_shape=[X_train.shape[1],]),\n    MaxNormDense(300),\n    MaxNormDense(100),\n    keras.layers.Dense(y_train.shape[1], activation=\"softmax\")\n])\nmodel.compile(loss=\"categorical_crossentropy\", optimizer=\"nadam\", metrics=[\"acc\",])\nn_epochs = 2\nhistory = model.fit(X_train_scaled, y_train, epochs=n_epochs,batch_size=1024,\n                    validation_data=(X_test_scaled, y_test))\n\ndel model\ngc.collect()","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"This notebook is forked from **Hands on machine learning with sklearn, tensorflow and keras book** github repo please check out the original author's work.([link](https://github.com/ageron/handson-ml2))\n\nThank you.\n\n\n![](data:image/jpeg;base64,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)","metadata":{}}]}