[CS231n]3·Neural Networks
CS231n Convolutional Neural Networks for Visual Recognition
https://www.bilibili.com/video/BV1nJ411z7fe
Modeling one neuron
即取输入的线性组合(加上偏置项),再对其取 activation function
Commonly used activation functions
Sigmoid:
Sigmoid 函数曾经很常用,但最近很少用了,这是因为它有两个大弊端:- Sigmoids 会 saturate,导致梯度消失。由于
在 较大时梯度非常小,而神经网络反向传播的本质是链式求导法则,要把梯度一级一级地乘起来,所以一旦遇到梯度很小的地方,梯度就无法继续反向传播了,这将导致前层的神经元的参数几乎不怎么更新。 - Sigmoid 的输出不是以
为中心的,这意味着后一层神经元接受的输入都是大于 的数,从而导致参数 的梯度全为正或者全为负。
- Sigmoids 会 saturate,导致梯度消失。由于
Tanh:
其实 仅仅是 放缩和移动后的结果: 所以依然存在梯度消失的问题,但是不同于 sigmoid 的是它的值域为 ,以 为中心。因此实践中, 往往比 sigmoid 更被大家喜爱。ReLU:Rectified Linear Unit.
- (+) 与 sigmoid 或 tanh 相比,ReLU 大大加速了
的收敛速度; - (+) ReLU 的计算非常简单(取
即可),而 sigmoid 和 tanh 涉及到指数等比较耗时的计算; - (-) 使用 ReLU 容易导致神经元 "die". 如果学习率设置的过大,容易使得参数变化过大,导致对数据集中的所有点
都小于 ,于是梯度不可逆地变成 .
- (+) 与 sigmoid 或 tanh 相比,ReLU 大大加速了
Leaky ReLU:
其中, 是一个较小的常数。这么做是为了解决 ReLU 中神经元 die 的问题。在 PReLU 中, 被视作神经元的一个参数。Maxout:
ReLU / Leaky ReLU 是 Maxout 的特殊情况。
Single neuron as a linear classifier
选取合适的损失函数后,一个神经元可以用来实现一个 linear classifier.
- Binary Softmax classifier:视神经元的输出
为分类为正类的概率,采取 cross-entropy loss 训练,则我们得到了 binary Softmax classifier,也即 logistic regression. - Binary SVM classifier:使用 max-margin hinge loss 训练,则我们得到 binary Support Vector Machine.
Neural Network architectures
一个 input layer,一个 output layer,若干 hidden layer. 对于最普通的神经网络而言,层与层之间全连接。
输出层的神经元经常没有 activation function,这样输出可以被视作分类的得分或者一些取实值的目标(比如回归值)。
一个单层的神经网络就可以任意近似任何函数,严格证明在 Approximation by superpositions of a sigmoidal function (1989) 这篇论文中,直观解释可以在博客 Neural Networks and Deep Learning 中找到。虽然如此,实践中多层的神经网络效果更好,也更容易学习。
神经网络中,隐藏层神经元数量越多,其表达能力越强大:
当然也意味着越容易过拟合,可以采取正则化的方式避免过拟合:
Data Preprocessing
Mean subtraction:将所有数据减去平均值,即中心化。
Normalization:将数据的各维度缩放到大致相同的规模。一般有两种方式:一是对中心化后的数据除以各维度的标准差,使得各维度的数据均值为
,方差为 ;二是将最大值和最小值缩放为 和 ,这样所有数据都在 之中。PCA:主成分分析 (PCA) 是一种常用的数据降维方法,具体内容可见机器学习笔记。
Whitening:假设数据是一个多元高斯分布,则 whitening 将数据变为均值为
,协方差矩阵为单位矩阵的多元高斯分布。就具体实现而言,在主成分分析中,如果没有使维度减小,则其效果为去相关性 (decorrelate);对去相关性后的数据除以各维度的特征值就得到了处理后的数据。
在实际应用中,PCA 和 Whitening 不会在卷积神经网络中用到,但是中心化以及 normalization 很重要。
在数据预处理时,非常重要的一点是预处理的统计量应该由 traning data 计算而来,然后应用到 validation / test data 上。不能够先在整个数据集上预处理,再划分 train / val / test.
Weight Initialization
陷阱:all zero initialization. 全部初始化为
是错误的做法,因为这样同一层的所有神经元都没有区别,它们将输出同样的值、具有同样的梯度、进行同样的更新(因为它们是对称的),这是没有意义的。Small random numbers:初始化为接近
的随机数是经常使用的方法。一般而言,可以取 倍的标准正态分布或者均匀分布等。Calibrating the variances with
:上一个方法存在一个问题,即神经网络输出的方差将随着输入量的增大而增大。在 Neural Networks and Deep Learning 中作者举了一个例子说明这一点:不妨假设 个输入中有 个 和 个 ,考察第一个隐藏层中的一个神经元, 将是 个标准正态分布之和,故服从 ,方差高达 !为了解决这个问题,我们计算:因此,若要
,需要 ,故我们只需要将初始化的值除以 即可。实践中这样做能加快收敛。在 Understanding the difficulty of training deep feedforward neural networks by Glorot et al. 这篇论文中,作者最终建议用
来初始化;在 Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification by He et al. 中,作者对 ReLU 神经网络进行分析,得到结论是方差应初始化为 .实践中,建议采用 ReLU 神经元并将权重方差设为
.Sparse initialization:另一种初始化方式是将权重矩阵初始化为
,但是为了打破对称性,每个神经元随机地连接下一层若干神经元(连接数目可由一个小的高斯分布生成)。Initializing the biases:常常将偏置初始化为
.Batch Normalization:在全连接层/卷积层与 activation function 之间插入一个 BatchNorm layer,因为 normalization 是可导的操作,这么做是可行的,具体查看论文:Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift.
Regularization
L2 regularization:最常见的正则化方法,向 loss function 加上
. 其特点是使得网络倾向于分散的权重。L1 regularization:相对常见的正则化方法,加上
. 其特点是使得网络的权重倾向于稀疏(即许多非常接近 的数字,与 L2 正好相反)。结合 L1 和 L2 我们得到 Elastic net regularization,即向 loss function 加上 . 一般而言,如果不是特别关注某些特征的选择,L2 比 L1 效果会更好。Max norm constraints:给神经元的权重向量
以约束: , 一般取 或 。Dropout:及其有效和简单的正则化方法,在 Dropout: A Simple Way to Prevent Neural Networks from Overfitting by Srivastava et al. 中提出,能作为其他正则化方法的补充。实现方法是在训练中让神经元以概率
(一个超参数)激活或设置为 .
我们无需对 bias 进行正则化,因为它们没有与数据直接相乘,并且正则化 bias 对结果的影响也微乎其微。
Loss functions
Classification
常用 SVM loss:
Attribute classification
不一定被分为某一类,而可以分到若干类,设
Regression
可采取 L2 或 L1 距离作为损失函数,即:
Gradient Checks
神经网络反向传播过程很容易写出 bug,为了检验我们计算的梯度是否正确,可以将 analytic gradient 和 numerical gradient 进行比较。这里有一些实现的 tips:
计算 numerical gradient 时,使用 centered formula,即:
而非 ,这是因为前者误差为 ,而后者有 . (泰勒展开即可证)使用相对误差作为比较基准。如果使用绝对误差,比如
,那么在梯度本来就小于 的地方,这个阈值没有什么作用。因此,我们使用相对误差: 分母用 或者加和或者取任意一个都是可以的,但是要小心除零。注意目标函数的不可导点。跨越了不可导点的 numerical gradient 可能和实际的 gradient 有较大差距,如果误差较大需要检查是不是这个原因。
只使用少量数据。解决上一条问题的一个方法是 gradient checks 时只用少量的数据,这样目标函数的不可导处将减少;同时只用检验
处的梯度就够了。 不宜设置得太小。理论上 越小越精确,但由于计算机浮点数的精度误差,太小了可能反而不精确。小心正则化项占了梯度的主要部分。如果正则化项在梯度中占比很大,它可能掩盖住了 back propagation 的错误。一个方式是在梯度检验时去掉正则化。
记住去掉 dropout/augmentations. 梯度检验时需要去除带有随机性质的量,比如 dropout 或者数据的随机 augmentation. 提前设置一个随机数种子也是可以的。
Sanity Checks
在实施学习之前,可以先进行 sanity checks,以保证我们的代码是正确的。
- 按概率推测损失函数初始值。例如一个十分类问题,随机初始化后我们应期望得到
的正确率,也即负对数概率的 loss function 大致为: . - 过拟合一个极小的数据集。用一个极小的数据集去训练,在去除正则化的情况下,我们应该期望得到
的正确率或 loss function 为 ,即在这个极小的数据集上过拟合。
Babysitting the learning process
学习过程中我们可以监测一些值随着迭代次数的增加的变化。
Loss function. 作 loss function - epoch 图能直观的告诉我们学习的状况,帮助我们调整学习率等参数。
Train/val accuracy. 作训练集和验证集上的准确率的图能直观的告诉我们是否过拟合/欠拟合,帮助我们调整正则化项。
Ratio of weights: updates. 检测参数更新的幅度,帮助我们判断学习率是否合适,合适的幅度应该在
左右。First-layer Visualizations. 在图像处理的网络中,我们可以把第一层的神经元的参数还原成图像可视化。
Parameter updates
SGD and bells and whistels
Vanilla update. 朴素的随机梯度下降
Momentum update. 朴素的 SGD 在每一处都向梯度下降的方向更新,就像一个人下山一样。而如果我们做另一个比喻,想象一个小球从山坡滚下,它在每一处将具有保持原方向的惯性,这就是 momentum SGD 的灵感来源。具体地,momentum SGD 更新如下:
其中, 为学习率, 可以看作是摩擦因子。Nesterov Momentum. 这是另一种 momentum update. 不同于上一条,Nesterov Momentum 计算随“惯性”移动一段距离之后的梯度再更新,见下图:
具体地,Nesterov Momentum 更新如下:
Annealing the learning rate
在学习过程中不断减小 learning rate 往往有帮助,一下三种方式是常用的 learning rate decay 实现方式:
- Step decay. 每迭代几次后将 learning rate 减小,例如每
次迭代后减小到原来的 ,或者每 次迭代减小一半等。这些参数依赖于具体问题和模型。一种启发式方法是当 validation error 停止减小时就减小 learning rate. - Exponential decay. 依
减小,其中 是超参数, 是迭代次数。 decay. 依 减小。
实践中,Step decay 稍稍更受喜爱一些,因为其解释性比其他的强。
Second order methods
梯度下降及其延伸算法只需要用到一阶导数,即梯度。还有些最优化算法需要用到二阶导数。
Newton's method.
其中, 表示 Hessian matrix, 表示 的梯度向量。注意到上述更新中不含有学习率这一超参数,这也是其优于一阶方法所在。
但是,Newton's method 有一个及其显著的缺点,即 Hessian matrix 过于庞大,
个参数的 Hessian matrix 是 的,计算耗时且难以存储。因此,出现了众多 quasi-Newton methods,例如 ,它们不需要将 Hessian matrix 完整计算出来.
Per-parameter adaptive learning rate methods
在之前的算法中,学习率是全局的且对所有参数都一样。调整学习率是一个耗时耗力的过程,因此人们发明了许多自动调整学习率的方法,且这些学习率甚至能对每一个参数进行调整。
虽然这些方法也有超参数,但它们与纯粹的学习率相比,能在更大的范围内表现较好,因而更好调参。
Adagrad:
注意,上式中对向量的运算符定义为与numpy
相同。对上式的理解是:
一路记录了每个参数的梯度平方和,如果某个参数有较大的梯度,那么它的学习率将减小;相反,梯度较小的参数将有较大的学习率。RMSprop:RMSprop 在 Adagrad 的基础上进行了简单的修改:
也即是增加了 这一超参数,一般取值为 .Adam:可以看作是 RMSprop 带 momentum 的版本,其(简化的)更新如下:
典型的参数是: .完整的 Adam 算法存在一个 bias correction 机制:
Hyperparameter optimization
超参数的优化是一个黑盒优化问题,其优化的目标函数是神经网络的性能,因而有一个显著的特点:得到每一组超参数的结果会花费巨额的时间。因此我们并不能直接套用一般的优化方法对超参数进行优化。一般的,超参数优化方法有以下几种:
Grid search:即每个超参数设置几个值,暴力遍历所有的可能。
Random search:在论文 Random Search for Hyper-Parameter Optimization by Bergstra and Bengio 中,作者论证了随机搜索比暴力遍历更为优秀,且更容易实现。
Bayesian Hyperparameter Optimation:利用贝叶斯方法进行超参数的寻找,核心是 exploration - exploitation trade-off.
Model Ensembles
实践中,一个提升神经网络性能的方法是训练多个独立的模型,使用它们的平均预测结果。这些独立的模型可以是不同的模型,同一种模型、不同初始化条件,甚至是同一个模型在训练的不同时间点处等。除了对模型结果进行平均,还可以对各模型的参数进行平均,有时也能提高神经网络性能。