diff --git a/doc/pub/NeuralNet/html/._NeuralNet-bs000.html b/doc/pub/NeuralNet/html/._NeuralNet-bs000.html index ee113eab4..e3971cad4 100644 --- a/doc/pub/NeuralNet/html/._NeuralNet-bs000.html +++ b/doc/pub/NeuralNet/html/._NeuralNet-bs000.html @@ -122,7 +122,22 @@ Automatically generated HTML file from DocOnce source ('Collect and pre-process data', 2, None, '___sec53'), ('Using TensorFlow backend', 2, None, '___sec54'), ('Optimizing and using gradient descent', 2, None, '___sec55'), - ('Using Keras', 2, None, '___sec56')]} + ('Using Keras', 2, None, '___sec56'), + ('Which activation function should I use?', 2, None, '___sec57'), + ('Is the Logistic activation function (Sigmoid) our choice?', + 2, + None, + '___sec58'), + ('The derivative of the Logistic funtion', 2, None, '___sec59'), + ('The RELU function family', 2, None, '___sec60'), + ('A top-down perspective on Neural networks', + 2, + None, + '___sec61'), + ('Limitations of supervised learning with deep networks', + 2, + None, + '___sec62')]} end of tocinfo -->
@@ -217,6 +232,12 @@ MathJax.Hub.Config({-
@@ -275,7 +296,7 @@ MathJax.Hub.Config({
+ + + + +
+ + +
epochs = 100
+batch_size = 100
+n_neurons_layer1 = 100
+n_neurons_layer2 = 50
+n_categories = 10
+eta_vals = np.logspace(-5, 1, 7)
+lmbd_vals = np.logspace(-5, 1, 7)
++ + +
DNN_tf = np.zeros((len(eta_vals), len(lmbd_vals)), dtype=object)
+
+for i, eta in enumerate(eta_vals):
+ for j, lmbd in enumerate(lmbd_vals):
+ DNN = NeuralNetworkTensorflow(X_train, Y_train, X_test, Y_test,
+ n_neurons_layer1, n_neurons_layer2, n_categories,
+ epochs=epochs, batch_size=batch_size, eta=eta, lmbd=lmbd)
+ DNN.fit()
+
+ DNN_tf[i][j] = DNN
+
+ print("Learning rate = ", eta)
+ print("Lambda = ", lmbd)
+ print("Test accuracy: %.3f" % DNN.test_accuracy)
+ print()
++ + +
# optional
+# visual representation of grid search
+# uses seaborn heatmap, could probably do this in matplotlib
+import seaborn as sns
+
+sns.set()
+
+train_accuracy = np.zeros((len(eta_vals), len(lmbd_vals)))
+test_accuracy = np.zeros((len(eta_vals), len(lmbd_vals)))
+
+for i in range(len(eta_vals)):
+ for j in range(len(lmbd_vals)):
+ DNN = DNN_tf[i][j]
+
+ train_accuracy[i][j] = DNN.train_accuracy
+ test_accuracy[i][j] = DNN.test_accuracy
+
+
+fig, ax = plt.subplots(figsize = (10, 10))
+sns.heatmap(train_accuracy, annot=True, ax=ax, cmap="viridis")
+ax.set_title("Training Accuracy")
+ax.set_ylabel("$\eta$")
+ax.set_xlabel("$\lambda$")
+plt.show()
+
+fig, ax = plt.subplots(figsize = (10, 10))
+sns.heatmap(test_accuracy, annot=True, ax=ax, cmap="viridis")
+ax.set_title("Test Accuracy")
+ax.set_ylabel("$\eta$")
+ax.set_xlabel("$\lambda$")
+plt.show()
++ + +
# optional
+# we can use log files to visualize our graph in Tensorboard
+writer = tf.summary.FileWriter('logs/')
+writer.add_graph(tf.get_default_graph())
++
+ +
+ + +
+ + + + +
+Keras is a high level neural network +that supports Tensorflow, CTNK and Theano as backends. +If you have Tensorflow installed Keras is available through the tf.keras module. +If you have Anaconda installed you may run the following command +
+ + +
conda install keras
++Alternatively, if you have Tensorflow or one of the other supported backends install you may use the pip package manager: + +
+ + +
pip3 install keras
++or look up the instructions here. + +
+ + +
from keras.models import Sequential
+from keras.layers import Dense
+from keras.regularizers import l2
+from keras.optimizers import SGD
+
+def create_neural_network_keras(n_neurons_layer1, n_neurons_layer2, n_categories, eta, lmbd):
+ model = Sequential()
+ model.add(Dense(n_neurons_layer1, activation='sigmoid', kernel_regularizer=l2(lmbd)))
+ model.add(Dense(n_neurons_layer2, activation='sigmoid', kernel_regularizer=l2(lmbd)))
+ model.add(Dense(n_categories, activation='softmax'))
+
+ sgd = SGD(lr=eta)
+ model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy'])
+
+ return model
++ + +
DNN_keras = np.zeros((len(eta_vals), len(lmbd_vals)), dtype=object)
+
+for i, eta in enumerate(eta_vals):
+ for j, lmbd in enumerate(lmbd_vals):
+ DNN = create_neural_network_keras(n_neurons_layer1, n_neurons_layer2, n_categories,
+ eta=eta, lmbd=lmbd)
+ DNN.fit(X_train, Y_train, epochs=epochs, batch_size=batch_size, verbose=0)
+ scores = DNN.evaluate(X_test, Y_test)
+
+ DNN_keras[i][j] = DNN
+
+ print("Learning rate = ", eta)
+ print("Lambda = ", lmbd)
+ print("Test accuracy: %.3f" % scores[1])
+ print()
++ + +
# optional
+# visual representation of grid search
+# uses seaborn heatmap, could probably do this in matplotlib
+import seaborn as sns
+
+sns.set()
+
+train_accuracy = np.zeros((len(eta_vals), len(lmbd_vals)))
+test_accuracy = np.zeros((len(eta_vals), len(lmbd_vals)))
+
+for i in range(len(eta_vals)):
+ for j in range(len(lmbd_vals)):
+ DNN = DNN_keras[i][j]
+
+ train_accuracy[i][j] = DNN.evaluate(X_train, Y_train)[1]
+ test_accuracy[i][j] = DNN.evaluate(X_test, Y_test)[1]
+
+
+fig, ax = plt.subplots(figsize = (10, 10))
+sns.heatmap(train_accuracy, annot=True, ax=ax, cmap="viridis")
+ax.set_title("Training Accuracy")
+ax.set_ylabel("$\eta$")
+ax.set_xlabel("$\lambda$")
+plt.show()
+
+fig, ax = plt.subplots(figsize = (10, 10))
+sns.heatmap(test_accuracy, annot=True, ax=ax, cmap="viridis")
+ax.set_title("Test Accuracy")
+ax.set_ylabel("$\eta$")
+ax.set_xlabel("$\lambda$")
+plt.show()
++
+ +
+ + +
+ + + + +
+Backpropagation algorithm works by going from the output layer to the +input layer, propagating the error gradient on the way. Once the algorithm has computed the gradient of the +cost function with regards to each parameter in the network, it uses these gradients to update each +parameter with a Gradient Descent step. + +
+Unfortunately, gradients often get smaller and smaller as the algorithm progresses down to the lower +layers. As a result, the Gradient Descent update leaves the lower layer connection weights virtually +unchanged, and training never converges to a good solution. This is called the vanishing gradients +problem. In some cases, the opposite can happen: the gradients can grow bigger and bigger, so many +layers get insanely large weight updates and the algorithm diverges. This is the exploding gradients +problem, which is mostly encountered in recurrent neural networks. More generally, +deep neural networks suffer from unstable gradients, different layers may learn at widely different speeds + +
+
+ +
+ + +
+ + + + +
+Although this unfortunate behavior has been empirically observed for quite a while (it was one of the +reasons why deep neural networks were mostly abandoned for a long time), it is only around 2010 that +significant progress was made in understanding it. + +
+A paper titled Understanding the Difficulty of Training Deep Feedforward Neural Networks by Xavier Glorot and Yoshua Bengio1 found a few suspects, +including the combination of the popular logistic sigmoid activation function and the weight initialization +technique that was most popular at the time, namely random initialization using a normal distribution with +a mean of 0 and a standard deviation of 1. In short, they showed that with this activation function and this +initialization scheme, the variance of the outputs of each layer is much greater than the variance of its +inputs. Going forward in the network, the variance keeps increasing after each layer until the activation +function saturates at the top layers. This is actually made worse by the fact that the logistic function has a +mean of 0.5, not 0 (the hyperbolic tangent function has a mean of 0 and behaves slightly better than the +logistic function in deep networks). + +
+
+ +
+ + +
+ + + + +
+Looking at the logistic activation function, when inputs become large +(negative or positive), the function saturates at 0 or 1, with a derivative extremely close to 0. Thus when +backpropagation kicks in, it has virtually no gradient to propagate back through the network, and what +little gradient exists keeps getting diluted as backpropagation progresses down through the top layers, so +there is really nothing left for the lower layers. + +
+In their paper, Glorot and Bengio propose a way to significantly alleviate this problem. We need the +signal to flow properly in both directions: in the forward direction when making predictions, and in the +reverse direction when backpropagating gradients. We don’t want the signal to die out, nor do we want it +to explode and saturate. For the signal to flow properly, the authors argue that we need the variance of the +outputs of each layer to be equal to the variance of its inputs, and we also need the gradients to have +equal variance before and after flowing through a layer in the reverse direction (please check out the +paper if you are interested in the mathematical details). + +
+One of the insights in the 2010 paper by Glorot and Bengio was that the vanishing/exploding gradients +problems were in part due to a poor choice of activation function. Until then most people had assumed +that if Nature had chosen to use roughly sigmoid activation functions in biological neurons, they +must be an excellent choice. But it turns out that other activation functions behave much better in deep +neural networks, in particular the ReLU activation function, mostly because it does not saturate for +positive values (and also because it is quite fast to compute). + +
+
+ +
+ + +
+ + + + +
+The ReLU activation function suffers from a problem known as the dying +ReLUs: during training, some neurons effectively die, meaning they stop outputting anything other than 0. + +
+In some cases, you may find that half of your network’s neurons are dead, especially if you used a large +learning rate. During training, if a neuron’s weights get updated such that the weighted sum of the neuron’s +inputs is negative, it will start outputting 0. When this happen, the neuron is unlikely to come back to life +since the gradient of the ReLU function is 0 when its input is negative. + +
+To solve this problem, you may want to use a variant of the ReLU function, such as the leaky ReLU discussed before or the so-called exponential linear unit (ELU) function +$$ +ELU(z) = \left\{\begin{array}{cc} \alpha\left( \exp{(z)}-1\right) & z > 0,\\ z & z \le 0.\end{array}\right. +$$ + +
+So which activation function should you use for the hidden layers of your deep neural networks? Although your mileage will vary, +in general ELU is better than leaky ReLU (and its variants), which is better than ReLU. ReLU performs better than \( \tanh \) which in turn performs better than the logistic function. If you care a lot about runtime performance, then you +may prefer leaky ReLUs over ELUs. If you don’t want to tweak yet another hyperparameter, you may just use the default \( \alpha \) of +\( 0.01 \) for the leaky ReLU, and \( 1 \) for ELU. If you have spare time and computing power, you can use +cross-validation or bootstrap to evaluate other activation functions. +huge training set. + +
+
+ +
+ + +
+ + + + +
+The first thing we would like to do is divide the data into two or three +parts. A training set, a validation or dev (development) set, and a +test set. The test set is the data on which we want to make +predictions. The dev set is a subset of the training data we use to +check how well we are doing out-of-sample, after training the model on +the training dataset. We use the validation error as a proxy for the +test error in order to make tweaks to our model. It is crucial that we +do not use any of the test data to train the algorithm. This is a +cardinal sin in ML. Then: + +
+
+ +
+ + +
+ + + + +
+Like all statistical methods, supervised learning using neural +networks has important limitations. This is especially important when +one seeks to apply these methods, especially to physics problems. Like +all tools, DNNs are not a universal solution. Often, the same or +better performance on a task can be achieved by using a few +hand-engineered features (or even a collection of random +features). + +
+Here we list some of the important limitations of supervised neural network based models. + +
+ +
+ + +-
@@ -275,7 +296,7 @@ MathJax.Hub.Config({
-
@@ -2786,6 +2786,175 @@ plt.show()
+
+Backpropagation algorithm works by going from the output layer to the
+input layer, propagating the error gradient on the way. Once the algorithm has computed the gradient of the
+cost function with regards to each parameter in the network, it uses these gradients to update each
+parameter with a Gradient Descent step.
+
+
+Unfortunately, gradients often get smaller and smaller as the algorithm progresses down to the lower
+layers. As a result, the Gradient Descent update leaves the lower layer connection weights virtually
+unchanged, and training never converges to a good solution. This is called the vanishing gradients
+problem. In some cases, the opposite can happen: the gradients can grow bigger and bigger, so many
+layers get insanely large weight updates and the algorithm diverges. This is the exploding gradients
+problem, which is mostly encountered in recurrent neural networks. More generally,
+deep neural networks suffer from unstable gradients, different layers may learn at widely different speeds
+
+Although this unfortunate behavior has been empirically observed for quite a while (it was one of the
+reasons why deep neural networks were mostly abandoned for a long time), it is only around 2010 that
+significant progress was made in understanding it.
+
+
+A paper titled Understanding the Difficulty of Training Deep Feedforward Neural Networks by Xavier Glorot and Yoshua Bengio1 found a few suspects,
+including the combination of the popular logistic sigmoid activation function and the weight initialization
+technique that was most popular at the time, namely random initialization using a normal distribution with
+a mean of 0 and a standard deviation of 1. In short, they showed that with this activation function and this
+initialization scheme, the variance of the outputs of each layer is much greater than the variance of its
+inputs. Going forward in the network, the variance keeps increasing after each layer until the activation
+function saturates at the top layers. This is actually made worse by the fact that the logistic function has a
+mean of 0.5, not 0 (the hyperbolic tangent function has a mean of 0 and behaves slightly better than the
+logistic function in deep networks).
+
+Looking at the logistic activation function, when inputs become large
+(negative or positive), the function saturates at 0 or 1, with a derivative extremely close to 0. Thus when
+backpropagation kicks in, it has virtually no gradient to propagate back through the network, and what
+little gradient exists keeps getting diluted as backpropagation progresses down through the top layers, so
+there is really nothing left for the lower layers.
+
+
+In their paper, Glorot and Bengio propose a way to significantly alleviate this problem. We need the
+signal to flow properly in both directions: in the forward direction when making predictions, and in the
+reverse direction when backpropagating gradients. We don’t want the signal to die out, nor do we want it
+to explode and saturate. For the signal to flow properly, the authors argue that we need the variance of the
+outputs of each layer to be equal to the variance of its inputs, and we also need the gradients to have
+equal variance before and after flowing through a layer in the reverse direction (please check out the
+paper if you are interested in the mathematical details).
+
+
+One of the insights in the 2010 paper by Glorot and Bengio was that the vanishing/exploding gradients
+problems were in part due to a poor choice of activation function. Until then most people had assumed
+that if Nature had chosen to use roughly sigmoid activation functions in biological neurons, they
+must be an excellent choice. But it turns out that other activation functions behave much better in deep
+neural networks, in particular the ReLU activation function, mostly because it does not saturate for
+positive values (and also because it is quite fast to compute).
+
+The ReLU activation function suffers from a problem known as the dying
+ReLUs: during training, some neurons effectively die, meaning they stop outputting anything other than 0.
+
+
+In some cases, you may find that half of your network’s neurons are dead, especially if you used a large
+learning rate. During training, if a neuron’s weights get updated such that the weighted sum of the neuron’s
+inputs is negative, it will start outputting 0. When this happen, the neuron is unlikely to come back to life
+since the gradient of the ReLU function is 0 when its input is negative.
+
+
+To solve this problem, you may want to use a variant of the ReLU function, such as the leaky ReLU discussed before or the so-called exponential linear unit (ELU) function
+
+So which activation function should you use for the hidden layers of your deep neural networks? Although your mileage will vary,
+in general ELU is better than leaky ReLU (and its variants), which is better than ReLU. ReLU performs better than \( \tanh \) which in turn performs better than the logistic function. If you care a lot about runtime performance, then you
+may prefer leaky ReLUs over ELUs. If you don’t want to tweak yet another hyperparameter, you may just use the default \( \alpha \) of
+\( 0.01 \) for the leaky ReLU, and \( 1 \) for ELU. If you have spare time and computing power, you can use
+cross-validation or bootstrap to evaluate other activation functions.
+huge training set.
+
+The first thing we would like to do is divide the data into two or three
+parts. A training set, a validation or dev (development) set, and a
+test set. The test set is the data on which we want to make
+predictions. The dev set is a subset of the training data we use to
+check how well we are doing out-of-sample, after training the model on
+the training dataset. We use the validation error as a proxy for the
+test error in order to make tweaks to our model. It is crucial that we
+do not use any of the test data to train the algorithm. This is a
+cardinal sin in ML. Then:
+
+
+
+If the validation and test sets are drawn from the same distributions,
+then good performance on the validation set should lead to similarly
+good performance on the test set.
+However, sometimes
+the training data and test data differ in subtle ways because, for
+example, they are collected using slightly different methods, or
+because it is cheaper to collect data in one way versus another. In
+this case, there can be a mismatch between the training and test
+data. This can lead to the neural network overfitting these small
+differences between the test and training sets, and a poor performance
+on the test set despite having a good performance on the validation
+set. To rectify this, Andrew Ng suggests making two validation or dev
+sets, one constructed from the training data and one constructed from
+the test data. The difference between the performance of the algorithm
+on these two validation sets quantifies the train-test mismatch. This
+can serve as another important diagnostic when using DNNs for
+supervised learning.
+
+Like all statistical methods, supervised learning using neural
+networks has important limitations. This is especially important when
+one seeks to apply these methods, especially to physics problems. Like
+all tools, DNNs are not a universal solution. Often, the same or
+better performance on a task can be achieved by using a few
+hand-engineered features (or even a collection of random
+features).
+
+
+Here we list some of the important limitations of supervised neural network based models.
+
+
+
+Some of these remarks are particular to DNNs, others are shared by all supervised learning methods. This motivates the use of unsupervised methods which in part circumnavigate these problems.
+Which activation function should I use?
+
+Is the Logistic activation function (Sigmoid) our choice?
+
+The derivative of the Logistic funtion
+
+The RELU function family
+
+
+$$
+ELU(z) = \left\{\begin{array}{cc} \alpha\left( \exp{(z)}-1\right) & z > 0,\\ z & z \le 0.\end{array}\right.
+$$
+
+
+A top-down perspective on Neural networks
+
+
+
+Limitations of supervised learning with deep networks
+
+
+
+
-
@@ -2629,6 +2644,169 @@ ax.set_xlabel("$\lambda$")
plt.show()
+ + +
+Backpropagation algorithm works by going from the output layer to the +input layer, propagating the error gradient on the way. Once the algorithm has computed the gradient of the +cost function with regards to each parameter in the network, it uses these gradients to update each +parameter with a Gradient Descent step. + +
+Unfortunately, gradients often get smaller and smaller as the algorithm progresses down to the lower +layers. As a result, the Gradient Descent update leaves the lower layer connection weights virtually +unchanged, and training never converges to a good solution. This is called the vanishing gradients +problem. In some cases, the opposite can happen: the gradients can grow bigger and bigger, so many +layers get insanely large weight updates and the algorithm diverges. This is the exploding gradients +problem, which is mostly encountered in recurrent neural networks. More generally, +deep neural networks suffer from unstable gradients, different layers may learn at widely different speeds + +
+ + +
+Although this unfortunate behavior has been empirically observed for quite a while (it was one of the +reasons why deep neural networks were mostly abandoned for a long time), it is only around 2010 that +significant progress was made in understanding it. + +
+A paper titled Understanding the Difficulty of Training Deep Feedforward Neural Networks by Xavier Glorot and Yoshua Bengio1 found a few suspects, +including the combination of the popular logistic sigmoid activation function and the weight initialization +technique that was most popular at the time, namely random initialization using a normal distribution with +a mean of 0 and a standard deviation of 1. In short, they showed that with this activation function and this +initialization scheme, the variance of the outputs of each layer is much greater than the variance of its +inputs. Going forward in the network, the variance keeps increasing after each layer until the activation +function saturates at the top layers. This is actually made worse by the fact that the logistic function has a +mean of 0.5, not 0 (the hyperbolic tangent function has a mean of 0 and behaves slightly better than the +logistic function in deep networks). + +
+
+
+
+Looking at the logistic activation function, when inputs become large +(negative or positive), the function saturates at 0 or 1, with a derivative extremely close to 0. Thus when +backpropagation kicks in, it has virtually no gradient to propagate back through the network, and what +little gradient exists keeps getting diluted as backpropagation progresses down through the top layers, so +there is really nothing left for the lower layers. + +
+In their paper, Glorot and Bengio propose a way to significantly alleviate this problem. We need the +signal to flow properly in both directions: in the forward direction when making predictions, and in the +reverse direction when backpropagating gradients. We don’t want the signal to die out, nor do we want it +to explode and saturate. For the signal to flow properly, the authors argue that we need the variance of the +outputs of each layer to be equal to the variance of its inputs, and we also need the gradients to have +equal variance before and after flowing through a layer in the reverse direction (please check out the +paper if you are interested in the mathematical details). + +
+One of the insights in the 2010 paper by Glorot and Bengio was that the vanishing/exploding gradients +problems were in part due to a poor choice of activation function. Until then most people had assumed +that if Nature had chosen to use roughly sigmoid activation functions in biological neurons, they +must be an excellent choice. But it turns out that other activation functions behave much better in deep +neural networks, in particular the ReLU activation function, mostly because it does not saturate for +positive values (and also because it is quite fast to compute). + +
+
+
+
+The ReLU activation function suffers from a problem known as the dying +ReLUs: during training, some neurons effectively die, meaning they stop outputting anything other than 0. + +
+In some cases, you may find that half of your network’s neurons are dead, especially if you used a large +learning rate. During training, if a neuron’s weights get updated such that the weighted sum of the neuron’s +inputs is negative, it will start outputting 0. When this happen, the neuron is unlikely to come back to life +since the gradient of the ReLU function is 0 when its input is negative. + +
+To solve this problem, you may want to use a variant of the ReLU function, such as the leaky ReLU discussed before or the so-called exponential linear unit (ELU) function +$$ +ELU(z) = \left\{\begin{array}{cc} \alpha\left( \exp{(z)}-1\right) & z > 0,\\ z & z \le 0.\end{array}\right. +$$ + +
+So which activation function should you use for the hidden layers of your deep neural networks? Although your mileage will vary, +in general ELU is better than leaky ReLU (and its variants), which is better than ReLU. ReLU performs better than \( \tanh \) which in turn performs better than the logistic function. If you care a lot about runtime performance, then you +may prefer leaky ReLUs over ELUs. If you don’t want to tweak yet another hyperparameter, you may just use the default \( \alpha \) of +\( 0.01 \) for the leaky ReLU, and \( 1 \) for ELU. If you have spare time and computing power, you can use +cross-validation or bootstrap to evaluate other activation functions. +huge training set. + +
+ + +
+The first thing we would like to do is divide the data into two or three +parts. A training set, a validation or dev (development) set, and a +test set. The test set is the data on which we want to make +predictions. The dev set is a subset of the training data we use to +check how well we are doing out-of-sample, after training the model on +the training dataset. We use the validation error as a proxy for the +test error in order to make tweaks to our model. It is crucial that we +do not use any of the test data to train the algorithm. This is a +cardinal sin in ML. Then: + +
+
+
+
+Like all statistical methods, supervised learning using neural +networks has important limitations. This is especially important when +one seeks to apply these methods, especially to physics problems. Like +all tools, DNNs are not a universal solution. Often, the same or +better performance on a task can be achieved by using a few +hand-engineered features (or even a collection of random +features). + +
+Here we list some of the important limitations of supervised neural network based models. + +
-
+
+
+
+Backpropagation algorithm works by going from the output layer to the
+input layer, propagating the error gradient on the way. Once the algorithm has computed the gradient of the
+cost function with regards to each parameter in the network, it uses these gradients to update each
+parameter with a Gradient Descent step.
+
+
+Unfortunately, gradients often get smaller and smaller as the algorithm progresses down to the lower
+layers. As a result, the Gradient Descent update leaves the lower layer connection weights virtually
+unchanged, and training never converges to a good solution. This is called the vanishing gradients
+problem. In some cases, the opposite can happen: the gradients can grow bigger and bigger, so many
+layers get insanely large weight updates and the algorithm diverges. This is the exploding gradients
+problem, which is mostly encountered in recurrent neural networks. More generally,
+deep neural networks suffer from unstable gradients, different layers may learn at widely different speeds
+
+
+
+
+
+Although this unfortunate behavior has been empirically observed for quite a while (it was one of the
+reasons why deep neural networks were mostly abandoned for a long time), it is only around 2010 that
+significant progress was made in understanding it.
+
+
+A paper titled Understanding the Difficulty of Training Deep Feedforward Neural Networks by Xavier Glorot and Yoshua Bengio1 found a few suspects,
+including the combination of the popular logistic sigmoid activation function and the weight initialization
+technique that was most popular at the time, namely random initialization using a normal distribution with
+a mean of 0 and a standard deviation of 1. In short, they showed that with this activation function and this
+initialization scheme, the variance of the outputs of each layer is much greater than the variance of its
+inputs. Going forward in the network, the variance keeps increasing after each layer until the activation
+function saturates at the top layers. This is actually made worse by the fact that the logistic function has a
+mean of 0.5, not 0 (the hyperbolic tangent function has a mean of 0 and behaves slightly better than the
+logistic function in deep networks).
+
+
+
+Looking at the logistic activation function, when inputs become large
+(negative or positive), the function saturates at 0 or 1, with a derivative extremely close to 0. Thus when
+backpropagation kicks in, it has virtually no gradient to propagate back through the network, and what
+little gradient exists keeps getting diluted as backpropagation progresses down through the top layers, so
+there is really nothing left for the lower layers.
+
+
+In their paper, Glorot and Bengio propose a way to significantly alleviate this problem. We need the
+signal to flow properly in both directions: in the forward direction when making predictions, and in the
+reverse direction when backpropagating gradients. We don’t want the signal to die out, nor do we want it
+to explode and saturate. For the signal to flow properly, the authors argue that we need the variance of the
+outputs of each layer to be equal to the variance of its inputs, and we also need the gradients to have
+equal variance before and after flowing through a layer in the reverse direction (please check out the
+paper if you are interested in the mathematical details).
+
+
+One of the insights in the 2010 paper by Glorot and Bengio was that the vanishing/exploding gradients
+problems were in part due to a poor choice of activation function. Until then most people had assumed
+that if Nature had chosen to use roughly sigmoid activation functions in biological neurons, they
+must be an excellent choice. But it turns out that other activation functions behave much better in deep
+neural networks, in particular the ReLU activation function, mostly because it does not saturate for
+positive values (and also because it is quite fast to compute).
+
+
+
+The ReLU activation function suffers from a problem known as the dying
+ReLUs: during training, some neurons effectively die, meaning they stop outputting anything other than 0.
+
+
+In some cases, you may find that half of your network’s neurons are dead, especially if you used a large
+learning rate. During training, if a neuron’s weights get updated such that the weighted sum of the neuron’s
+inputs is negative, it will start outputting 0. When this happen, the neuron is unlikely to come back to life
+since the gradient of the ReLU function is 0 when its input is negative.
+
+
+To solve this problem, you may want to use a variant of the ReLU function, such as the leaky ReLU discussed before or the so-called exponential linear unit (ELU) function
+$$
+ELU(z) = \left\{\begin{array}{cc} \alpha\left( \exp{(z)}-1\right) & z > 0,\\ z & z \le 0.\end{array}\right.
+$$
+
+
+So which activation function should you use for the hidden layers of your deep neural networks? Although your mileage will vary,
+in general ELU is better than leaky ReLU (and its variants), which is better than ReLU. ReLU performs better than \( \tanh \) which in turn performs better than the logistic function. If you care a lot about runtime performance, then you
+may prefer leaky ReLUs over ELUs. If you don’t want to tweak yet another hyperparameter, you may just use the default \( \alpha \) of
+\( 0.01 \) for the leaky ReLU, and \( 1 \) for ELU. If you have spare time and computing power, you can use
+cross-validation or bootstrap to evaluate other activation functions.
+huge training set.
+
+
+
+
+
+The first thing we would like to do is divide the data into two or three
+parts. A training set, a validation or dev (development) set, and a
+test set. The test set is the data on which we want to make
+predictions. The dev set is a subset of the training data we use to
+check how well we are doing out-of-sample, after training the model on
+the training dataset. We use the validation error as a proxy for the
+test error in order to make tweaks to our model. It is crucial that we
+do not use any of the test data to train the algorithm. This is a
+cardinal sin in ML. Then:
+
+
+
+Like all statistical methods, supervised learning using neural
+networks has important limitations. This is especially important when
+one seeks to apply these methods, especially to physics problems. Like
+all tools, DNNs are not a universal solution. Often, the same or
+better performance on a task can be achieved by using a few
+hand-engineered features (or even a collection of random
+features).
+
+
+Here we list some of the important limitations of supervised neural network based models.
+
+
@@ -2634,6 +2649,169 @@ ax.set_xlabel(&
plt.show()
Which activation function should I use?
+
+Is the Logistic activation function (Sigmoid) our choice?
+
+
+
+The derivative of the Logistic funtion
+
+
+
+The RELU function family
+
+A top-down perspective on Neural networks
+
+
+
+
+If the validation and test sets are drawn from the same distributions,
+then good performance on the validation set should lead to similarly
+good performance on the test set.
+However, sometimes
+the training data and test data differ in subtle ways because, for
+example, they are collected using slightly different methods, or
+because it is cheaper to collect data in one way versus another. In
+this case, there can be a mismatch between the training and test
+data. This can lead to the neural network overfitting these small
+differences between the test and training sets, and a poor performance
+on the test set despite having a good performance on the validation
+set. To rectify this, Andrew Ng suggests making two validation or dev
+sets, one constructed from the training data and one constructed from
+the test data. The difference between the performance of the algorithm
+on these two validation sets quantifies the train-test mismatch. This
+can serve as another important diagnostic when using DNNs for
+supervised learning.
+
+
+
+Limitations of supervised learning with deep networks
+
+
+
+
+Some of these remarks are particular to DNNs, others are shared by all supervised learning methods. This motivates the use of unsupervised methods which in part circumnavigate these problems.
diff --git a/doc/pub/NeuralNet/ipynb/NeuralNet.ipynb b/doc/pub/NeuralNet/ipynb/NeuralNet.ipynb
index d97039c78..d347caee3 100644
--- a/doc/pub/NeuralNet/ipynb/NeuralNet.ipynb
+++ b/doc/pub/NeuralNet/ipynb/NeuralNet.ipynb
@@ -10,7 +10,7 @@
" \n",
"**Morten Hjorth-Jensen**, Department of Physics, University of Oslo and Department of Physics and Astronomy and National Superconducting Cyclotron Laboratory, Michigan State University\n",
"\n",
- "Date: **Oct 11, 2018**\n",
+ "Date: **Oct 12, 2018**\n",
"\n",
"Copyright 1999-2018, Morten Hjorth-Jensen. Released under CC Attribution-NonCommercial 4.0 license\n",
"\n",
@@ -597,7 +597,9 @@
{
"cell_type": "code",
"execution_count": 1,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"%matplotlib inline\n",
@@ -1518,7 +1520,9 @@
{
"cell_type": "code",
"execution_count": 2,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"# import necessary packages\n",
@@ -1585,7 +1589,9 @@
{
"cell_type": "code",
"execution_count": 3,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"from sklearn.model_selection import train_test_split\n",
@@ -1707,7 +1713,9 @@
{
"cell_type": "code",
"execution_count": 4,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"# building our neural network\n",
@@ -1784,7 +1792,9 @@
{
"cell_type": "code",
"execution_count": 5,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"# setup the feed-forward pass, subscript h = hidden layer\n",
@@ -1947,7 +1957,9 @@
{
"cell_type": "code",
"execution_count": 6,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"# to categorical turns our integer vector into a onehot representation\n",
@@ -2049,7 +2061,9 @@
{
"cell_type": "code",
"execution_count": 7,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"class NeuralNetwork:\n",
@@ -2172,7 +2186,9 @@
{
"cell_type": "code",
"execution_count": 8,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"epochs = 100\n",
@@ -2206,7 +2222,9 @@
{
"cell_type": "code",
"execution_count": 9,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"eta_vals = np.logspace(-5, 1, 7)\n",
@@ -2241,7 +2259,9 @@
{
"cell_type": "code",
"execution_count": 10,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"# visual representation of grid search\n",
@@ -2301,7 +2321,9 @@
{
"cell_type": "code",
"execution_count": 11,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"from sklearn.neural_network import MLPClassifier\n",
@@ -2332,7 +2354,9 @@
{
"cell_type": "code",
"execution_count": 12,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"# optional\n",
@@ -2415,7 +2439,9 @@
{
"cell_type": "code",
"execution_count": 13,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"pip3 install tensorflow"
@@ -2431,7 +2457,9 @@
{
"cell_type": "code",
"execution_count": 14,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"conda install tensorflow"
@@ -2447,7 +2475,9 @@
{
"cell_type": "code",
"execution_count": 15,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"# import necessary packages\n",
@@ -2497,7 +2527,9 @@
{
"cell_type": "code",
"execution_count": 16,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"from keras.utils import to_categorical\n",
@@ -2527,7 +2559,9 @@
{
"cell_type": "code",
"execution_count": 17,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"import tensorflow as tf\n",
@@ -2673,7 +2707,9 @@
{
"cell_type": "code",
"execution_count": 18,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"epochs = 100\n",
@@ -2688,7 +2724,9 @@
{
"cell_type": "code",
"execution_count": 19,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"DNN_tf = np.zeros((len(eta_vals), len(lmbd_vals)), dtype=object)\n",
@@ -2711,7 +2749,9 @@
{
"cell_type": "code",
"execution_count": 20,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"# optional\n",
@@ -2750,7 +2790,9 @@
{
"cell_type": "code",
"execution_count": 21,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"# optional\n",
@@ -2774,7 +2816,9 @@
{
"cell_type": "code",
"execution_count": 22,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"conda install keras"
@@ -2790,7 +2834,9 @@
{
"cell_type": "code",
"execution_count": 23,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"pip3 install keras"
@@ -2806,7 +2852,9 @@
{
"cell_type": "code",
"execution_count": 24,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"from keras.models import Sequential\n",
@@ -2829,7 +2877,9 @@
{
"cell_type": "code",
"execution_count": 25,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"DNN_keras = np.zeros((len(eta_vals), len(lmbd_vals)), dtype=object)\n",
@@ -2852,7 +2902,9 @@
{
"cell_type": "code",
"execution_count": 26,
- "metadata": {},
+ "metadata": {
+ "collapsed": false
+ },
"outputs": [],
"source": [
"# optional\n",
@@ -2887,27 +2939,170 @@
"ax.set_xlabel(\"$\\lambda$\")\n",
"plt.show()"
]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "## Which activation function should I use?\n",
+ "\n",
+ "Backpropagation algorithm works by going from the output layer to the\n",
+ "input layer, propagating the error gradient on the way. Once the algorithm has computed the gradient of the\n",
+ "cost function with regards to each parameter in the network, it uses these gradients to update each\n",
+ "parameter with a Gradient Descent step.\n",
+ "\n",
+ "Unfortunately, gradients often get smaller and smaller as the algorithm progresses down to the lower\n",
+ "layers. As a result, the Gradient Descent update leaves the lower layer connection weights virtually\n",
+ "unchanged, and training never converges to a good solution. This is called the vanishing gradients\n",
+ "problem. In some cases, the opposite can happen: the gradients can grow bigger and bigger, so many\n",
+ "layers get insanely large weight updates and the algorithm diverges. This is the exploding gradients\n",
+ "problem, which is mostly encountered in recurrent neural networks. More generally,\n",
+ "deep neural networks suffer from unstable gradients, different layers may learn at widely different speeds\n",
+ "\n",
+ "\n",
+ "## Is the Logistic activation function (Sigmoid) our choice?\n",
+ "\n",
+ "Although this unfortunate behavior has been empirically observed for quite a while (it was one of the\n",
+ "reasons why deep neural networks were mostly abandoned for a long time), it is only around 2010 that\n",
+ "significant progress was made in understanding it. \n",
+ "\n",
+ "A paper titled **Understanding the Difficulty of Training Deep Feedforward Neural Networks** by Xavier Glorot and Yoshua Bengio1 found a few suspects,\n",
+ "including the combination of the popular logistic sigmoid activation function and the weight initialization\n",
+ "technique that was most popular at the time, namely random initialization using a normal distribution with\n",
+ "a mean of 0 and a standard deviation of 1. In short, they showed that with this activation function and this\n",
+ "initialization scheme, the variance of the outputs of each layer is much greater than the variance of its\n",
+ "inputs. Going forward in the network, the variance keeps increasing after each layer until the activation\n",
+ "function saturates at the top layers. This is actually made worse by the fact that the logistic function has a\n",
+ "mean of 0.5, not 0 (the hyperbolic tangent function has a mean of 0 and behaves slightly better than the\n",
+ "logistic function in deep networks).\n",
+ "\n",
+ "\n",
+ "## The derivative of the Logistic funtion\n",
+ "\n",
+ "Looking at the logistic activation function, when inputs become large\n",
+ "(negative or positive), the function saturates at 0 or 1, with a derivative extremely close to 0. Thus when\n",
+ "backpropagation kicks in, it has virtually no gradient to propagate back through the network, and what\n",
+ "little gradient exists keeps getting diluted as backpropagation progresses down through the top layers, so\n",
+ "there is really nothing left for the lower layers.\n",
+ "\n",
+ "In their paper, Glorot and Bengio propose a way to significantly alleviate this problem. We need the\n",
+ "signal to flow properly in both directions: in the forward direction when making predictions, and in the\n",
+ "reverse direction when backpropagating gradients. We don’t want the signal to die out, nor do we want it\n",
+ "to explode and saturate. For the signal to flow properly, the authors argue that we need the variance of the\n",
+ "outputs of each layer to be equal to the variance of its inputs, and we also need the gradients to have\n",
+ "equal variance before and after flowing through a layer in the reverse direction (please check out the\n",
+ "paper if you are interested in the mathematical details). \n",
+ "\n",
+ "\n",
+ "One of the insights in the 2010 paper by Glorot and Bengio was that the vanishing/exploding gradients\n",
+ "problems were in part due to a poor choice of activation function. Until then most people had assumed\n",
+ "that if Nature had chosen to use roughly sigmoid activation functions in biological neurons, they\n",
+ "must be an excellent choice. But it turns out that other activation functions behave much better in deep\n",
+ "neural networks, in particular the ReLU activation function, mostly because it does not saturate for\n",
+ "positive values (and also because it is quite fast to compute).\n",
+ "\n",
+ "\n",
+ "## The RELU function family\n",
+ "\n",
+ "The ReLU activation function suffers from a problem known as the dying\n",
+ "ReLUs: during training, some neurons effectively die, meaning they stop outputting anything other than 0.\n",
+ "\n",
+ "In some cases, you may find that half of your network’s neurons are dead, especially if you used a large\n",
+ "learning rate. During training, if a neuron’s weights get updated such that the weighted sum of the neuron’s\n",
+ "inputs is negative, it will start outputting 0. When this happen, the neuron is unlikely to come back to life\n",
+ "since the gradient of the ReLU function is 0 when its input is negative.\n",
+ "\n",
+ "To solve this problem, you may want to use a variant of the ReLU function, such as the leaky ReLU discussed before or the so-called exponential linear unit (ELU) function"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "$$\n",
+ "ELU(z) = \\left\\{\\begin{array}{cc} \\alpha\\left( \\exp{(z)}-1\\right) & z > 0,\\\\ z & z \\le 0.\\end{array}\\right.\n",
+ "$$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "So which activation function should you use for the hidden layers of your deep neural networks? Although your mileage will vary,\n",
+ "in general ELU is better than leaky ReLU (and its variants), which is better than ReLU. ReLU performs better than $\\tanh$ which in turn performs better than the logistic function. If you care a lot about runtime performance, then you\n",
+ "may prefer leaky ReLUs over ELUs. If you don’t want to tweak yet another hyperparameter, you may just use the default $\\alpha$ of\n",
+ "$0.01$ for the leaky ReLU, and $1$ for ELU. If you have spare time and computing power, you can use\n",
+ "cross-validation or bootstrap to evaluate other activation functions.\n",
+ "huge training set.\n",
+ "\n",
+ "\n",
+ "\n",
+ "## A top-down perspective on Neural networks\n",
+ "\n",
+ "\n",
+ "The first thing we would like to do is divide the data into two or three\n",
+ "parts. A training set, a validation or dev (development) set, and a\n",
+ "test set. The test set is the data on which we want to make\n",
+ "predictions. The dev set is a subset of the training data we use to\n",
+ "check how well we are doing out-of-sample, after training the model on\n",
+ "the training dataset. We use the validation error as a proxy for the\n",
+ "test error in order to make tweaks to our model. It is crucial that we\n",
+ "do not use any of the test data to train the algorithm. This is a\n",
+ "cardinal sin in ML. Then:\n",
+ "\n",
+ "\n",
+ "* Estimate optimal error rate\n",
+ "\n",
+ "* Minimize underfitting (bias) on training data set.\n",
+ "\n",
+ "* Make sure you are not overfitting.\n",
+ "\n",
+ "If the validation and test sets are drawn from the same distributions,\n",
+ "then good performance on the validation set should lead to similarly\n",
+ "good performance on the test set. \n",
+ "However, sometimes\n",
+ "the training data and test data differ in subtle ways because, for\n",
+ "example, they are collected using slightly different methods, or\n",
+ "because it is cheaper to collect data in one way versus another. In\n",
+ "this case, there can be a mismatch between the training and test\n",
+ "data. This can lead to the neural network overfitting these small\n",
+ "differences between the test and training sets, and a poor performance\n",
+ "on the test set despite having a good performance on the validation\n",
+ "set. To rectify this, Andrew Ng suggests making two validation or dev\n",
+ "sets, one constructed from the training data and one constructed from\n",
+ "the test data. The difference between the performance of the algorithm\n",
+ "on these two validation sets quantifies the train-test mismatch. This\n",
+ "can serve as another important diagnostic when using DNNs for\n",
+ "supervised learning.\n",
+ "\n",
+ "## Limitations of supervised learning with deep networks\n",
+ "\n",
+ "Like all statistical methods, supervised learning using neural\n",
+ "networks has important limitations. This is especially important when\n",
+ "one seeks to apply these methods, especially to physics problems. Like\n",
+ "all tools, DNNs are not a universal solution. Often, the same or\n",
+ "better performance on a task can be achieved by using a few\n",
+ "hand-engineered features (or even a collection of random\n",
+ "features). \n",
+ "\n",
+ "Here we list some of the important limitations of supervised neural network based models. \n",
+ "\n",
+ "\n",
+ "\n",
+ "* **Need labeled data**. All supervised learning methods, DNNs for supervised learning require labeled data. Often, labeled data is harder to acquire than unlabeled data (e.g. one must pay for human experts to label images).\n",
+ "\n",
+ "* **Supervised neural networks are extremely data intensive.** DNNs are data hungry. They perform best when data is plentiful. This is doubly so for supervised methods where the data must also be labeled. The utility of DNNs is extremely limited if data is hard to acquire or the datasets are small (hundreds to a few thousand samples). In this case, the performance of other methods that utilize hand-engineered features can exceed that of DNNs.\n",
+ "\n",
+ "* **Homogeneous data.** Almost all DNNs deal with homogeneous data of one type. It is very hard to design architectures that mix and match data types (i.e. some continuous variables, some discrete variables, some time series). In applications beyond images, video, and language, this is often what is required. In contrast, ensemble models like random forests or gradient-boosted trees have no difficulty handling mixed data types.\n",
+ "\n",
+ "* **Many problems are not about prediction.** In natural science we are often interested in learning something about the underlying distribution that generates the data. In this case, it is often difficult to cast these ideas in a supervised learning setting. While the problems are related, it is possible to make good predictions with a *wrong* model. The model might or might not be useful for understanding the underlying science.\n",
+ "\n",
+ "Some of these remarks are particular to DNNs, others are shared by all supervised learning methods. This motivates the use of unsupervised methods which in part circumnavigate these problems."
+ ]
}
],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.7.0"
- }
- },
+ "metadata": {},
"nbformat": 4,
"nbformat_minor": 2
}
diff --git a/doc/pub/NeuralNet/ipynb/ipynb-NeuralNet-src.tar.gz b/doc/pub/NeuralNet/ipynb/ipynb-NeuralNet-src.tar.gz
index 1c7c69186..b76609507 100644
Binary files a/doc/pub/NeuralNet/ipynb/ipynb-NeuralNet-src.tar.gz and b/doc/pub/NeuralNet/ipynb/ipynb-NeuralNet-src.tar.gz differ
diff --git a/doc/pub/NeuralNet/pdf/NeuralNet-minted.pdf b/doc/pub/NeuralNet/pdf/NeuralNet-minted.pdf
index b50fde78b..1630dbd4c 100644
Binary files a/doc/pub/NeuralNet/pdf/NeuralNet-minted.pdf and b/doc/pub/NeuralNet/pdf/NeuralNet-minted.pdf differ
diff --git a/doc/src/NeuralNet/NeuralNet.do.txt b/doc/src/NeuralNet/NeuralNet.do.txt
index e78845923..750133368 100644
--- a/doc/src/NeuralNet/NeuralNet.do.txt
+++ b/doc/src/NeuralNet/NeuralNet.do.txt
@@ -2187,3 +2187,151 @@ ax.set_ylabel("$\eta$")
ax.set_xlabel("$\lambda$")
plt.show()
!ec
+
+
+!split
+===== Which activation function should I use? =====
+
+Backpropagation algorithm works by going from the output layer to the
+input layer, propagating the error gradient on the way. Once the algorithm has computed the gradient of the
+cost function with regards to each parameter in the network, it uses these gradients to update each
+parameter with a Gradient Descent step.
+
+Unfortunately, gradients often get smaller and smaller as the algorithm progresses down to the lower
+layers. As a result, the Gradient Descent update leaves the lower layer connection weights virtually
+unchanged, and training never converges to a good solution. This is called the vanishing gradients
+problem. In some cases, the opposite can happen: the gradients can grow bigger and bigger, so many
+layers get insanely large weight updates and the algorithm diverges. This is the exploding gradients
+problem, which is mostly encountered in recurrent neural networks. More generally,
+deep neural networks suffer from unstable gradients, different layers may learn at widely different speeds
+
+!split
+===== Is the Logistic activation function (Sigmoid) our choice? =====
+
+Although this unfortunate behavior has been empirically observed for quite a while (it was one of the
+reasons why deep neural networks were mostly abandoned for a long time), it is only around 2010 that
+significant progress was made in understanding it.
+
+A paper titled _Understanding the Difficulty of Training Deep Feedforward Neural Networks_ by Xavier Glorot and Yoshua Bengio1 found a few suspects,
+including the combination of the popular logistic sigmoid activation function and the weight initialization
+technique that was most popular at the time, namely random initialization using a normal distribution with
+a mean of 0 and a standard deviation of 1. In short, they showed that with this activation function and this
+initialization scheme, the variance of the outputs of each layer is much greater than the variance of its
+inputs. Going forward in the network, the variance keeps increasing after each layer until the activation
+function saturates at the top layers. This is actually made worse by the fact that the logistic function has a
+mean of 0.5, not 0 (the hyperbolic tangent function has a mean of 0 and behaves slightly better than the
+logistic function in deep networks).
+
+
+!split
+===== The derivative of the Logistic funtion =====
+
+Looking at the logistic activation function, when inputs become large
+(negative or positive), the function saturates at 0 or 1, with a derivative extremely close to 0. Thus when
+backpropagation kicks in, it has virtually no gradient to propagate back through the network, and what
+little gradient exists keeps getting diluted as backpropagation progresses down through the top layers, so
+there is really nothing left for the lower layers.
+
+In their paper, Glorot and Bengio propose a way to significantly alleviate this problem. We need the
+signal to flow properly in both directions: in the forward direction when making predictions, and in the
+reverse direction when backpropagating gradients. We don’t want the signal to die out, nor do we want it
+to explode and saturate. For the signal to flow properly, the authors argue that we need the variance of the
+outputs of each layer to be equal to the variance of its inputs, and we also need the gradients to have
+equal variance before and after flowing through a layer in the reverse direction (please check out the
+paper if you are interested in the mathematical details).
+
+
+One of the insights in the 2010 paper by Glorot and Bengio was that the vanishing/exploding gradients
+problems were in part due to a poor choice of activation function. Until then most people had assumed
+that if Nature had chosen to use roughly sigmoid activation functions in biological neurons, they
+must be an excellent choice. But it turns out that other activation functions behave much better in deep
+neural networks, in particular the ReLU activation function, mostly because it does not saturate for
+positive values (and also because it is quite fast to compute).
+
+
+!split
+===== The RELU function family =====
+
+The ReLU activation function suffers from a problem known as the dying
+ReLUs: during training, some neurons effectively die, meaning they stop outputting anything other than 0.
+
+In some cases, you may find that half of your network’s neurons are dead, especially if you used a large
+learning rate. During training, if a neuron’s weights get updated such that the weighted sum of the neuron’s
+inputs is negative, it will start outputting 0. When this happen, the neuron is unlikely to come back to life
+since the gradient of the ReLU function is 0 when its input is negative.
+
+To solve this problem, you may want to use a variant of the ReLU function, such as the leaky ReLU discussed before or the so-called exponential linear unit (ELU) function
+!bt
+\[
+ELU(z) = \left\{\begin{array}{cc} \alpha\left( \exp{(z)}-1\right) & z > 0,\\ z & z \le 0.\end{array}\right.
+\]
+!et
+
+So which activation function should you use for the hidden layers of your deep neural networks? Although your mileage will vary,
+in general ELU is better than leaky ReLU (and its variants), which is better than ReLU. ReLU performs better than $\tanh$ which in turn performs better than the logistic function. If you care a lot about runtime performance, then you
+may prefer leaky ReLUs over ELUs. If you don’t want to tweak yet another hyperparameter, you may just use the default $\alpha$ of
+$0.01$ for the leaky ReLU, and $1$ for ELU. If you have spare time and computing power, you can use
+cross-validation or bootstrap to evaluate other activation functions.
+huge training set.
+
+
+!split
+===== A top-down perspective on Neural networks =====
+
+
+The first thing we would like to do is divide the data into two or three
+parts. A training set, a validation or dev (development) set, and a
+test set. The test set is the data on which we want to make
+predictions. The dev set is a subset of the training data we use to
+check how well we are doing out-of-sample, after training the model on
+the training dataset. We use the validation error as a proxy for the
+test error in order to make tweaks to our model. It is crucial that we
+do not use any of the test data to train the algorithm. This is a
+cardinal sin in ML. Then:
+
+
+* Estimate optimal error rate
+
+* Minimize underfitting (bias) on training data set.
+
+* Make sure you are not overfitting.
+
+If the validation and test sets are drawn from the same distributions,
+then good performance on the validation set should lead to similarly
+good performance on the test set.
+However, sometimes
+the training data and test data differ in subtle ways because, for
+example, they are collected using slightly different methods, or
+because it is cheaper to collect data in one way versus another. In
+this case, there can be a mismatch between the training and test
+data. This can lead to the neural network overfitting these small
+differences between the test and training sets, and a poor performance
+on the test set despite having a good performance on the validation
+set. To rectify this, Andrew Ng suggests making two validation or dev
+sets, one constructed from the training data and one constructed from
+the test data. The difference between the performance of the algorithm
+on these two validation sets quantifies the train-test mismatch. This
+can serve as another important diagnostic when using DNNs for
+supervised learning.
+
+!split
+===== Limitations of supervised learning with deep networks =====
+
+Like all statistical methods, supervised learning using neural
+networks has important limitations. This is especially important when
+one seeks to apply these methods, especially to physics problems. Like
+all tools, DNNs are not a universal solution. Often, the same or
+better performance on a task can be achieved by using a few
+hand-engineered features (or even a collection of random
+features).
+
+Here we list some of the important limitations of supervised neural network based models.
+
+
+
+* _Need labeled data_. All supervised learning methods, DNNs for supervised learning require labeled data. Often, labeled data is harder to acquire than unlabeled data (e.g. one must pay for human experts to label images).
+* _Supervised neural networks are extremely data intensive._ DNNs are data hungry. They perform best when data is plentiful. This is doubly so for supervised methods where the data must also be labeled. The utility of DNNs is extremely limited if data is hard to acquire or the datasets are small (hundreds to a few thousand samples). In this case, the performance of other methods that utilize hand-engineered features can exceed that of DNNs.
+* _Homogeneous data._ Almost all DNNs deal with homogeneous data of one type. It is very hard to design architectures that mix and match data types (i.e.~some continuous variables, some discrete variables, some time series). In applications beyond images, video, and language, this is often what is required. In contrast, ensemble models like random forests or gradient-boosted trees have no difficulty handling mixed data types.
+* _Many problems are not about prediction._ In natural science we are often interested in learning something about the underlying distribution that generates the data. In this case, it is often difficult to cast these ideas in a supervised learning setting. While the problems are related, it is possible to make good predictions with a *wrong* model. The model might or might not be useful for understanding the underlying science.
+
+Some of these remarks are particular to DNNs, others are shared by all supervised learning methods. This motivates the use of unsupervised methods which in part circumnavigate these problems.