Improving the way neural networks learn--Regularization

说在前面的话:继续翻译neural networks and deep learning,看原文真的比看别人写的博客更有趣也更有收获。

Overfitting

之前解决了learning rate缓慢的问题,但它对神经网络正确率的提高并不算显著。神经网络——包括其他许多机器学习任务都面临着另外一个问题——过拟合。什么是过拟合?通俗来讲,就是神经网络的能力过于“强大”,以至于training data的所有特征——甚至包括其中的noise都被神经网络记忆得一清二楚,但到了与training data不同的test data上,神经网络的能力却大大降低。换句话说,就是我们的神经网络只会死记硬背,不会类比、变通,显然它并没有真正“学习”到。

但上述情况发生的前提是neural network有“记住”整个training set的能力,显然,当training set较小时更有可能过拟合,所以作者将训练集的大小由之前的50000改成了1000,另外,代码中添加了这样四个观测学习过程的指标:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if monitor_training_cost:
cost = self.total_cost(training_data, lmbda)
training_cost.append(cost)
print("Cost on training data: {}".format(cost))
if monitor_training_accuracy:
accuracy = self.accuracy(training_data, convert=True)
training_accuracy.append(accuracy)
print("Accuracy on training data: {} / {}".format(accuracy, n))
if monitor_evaluation_cost:
cost = self.total_cost(evaluation_data, lmbda, convert=True)
evaluation_cost.append(cost)
print("Cost on evaluation data: {}".format(cost))
if monitor_evaluation_accuracy:
accuracy = self.accuracy(evaluation_data)
evaluation_accuracy.append(accuracy)
print("Accuracy on evaluation data: {} / {}".format(self.accuracy(evaluation_data),

分别是训练cost、训练accuracy、测试cost、测试accuracy。需要说明的是,之前我一直认为只要设置accuracy和cost两种指标其一就可以,甚至愚蠢地以为cost+accuracy=1,思考后发现cost本质上是针对一个input,只不过我们说的cost是把training set所有的这些cost求了平均罢了;而accuracy是针对整个set,因为对于单一的input,只存在yes or no这种概念,并没有accuracy这种说法。所以,cost和accuracy其实是两种不同的指标。
训练400个epoch发现,在训练集上的cost一直在减少,accuracy更是在150个epoch后达到了100%,而测试集上的accuracy在280个epoch达到82%后就不再提高,测试集上的cost甚至在第15个epoch达到最小值后又开始回升,显然是出现了overfitting。

Early stopping & Validation data

出现了上面的问题,一个最容易想到的策略就是early stopping,即在训练过程中观测test data的accuracy,当它达到饱和时就提前终止训练,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
# Early stopping:
if early_stopping_n > 0:
if accuracy > best_accuracy:
best_accuracy = accuracy
no_accuracy_change = 0
#print("Early-stopping: Best so far {}".format(best_accuracy))
else:
no_accuracy_change += 1

if (no_accuracy_change == early_stopping_n):
#print("Early-stopping: No accuracy change in last epochs:{}".format(early_stopping_n))
return evaluation_cost, evaluation_accuracy, training_cost, training_accuracy

就是提前设置一个参数early_stopping_n参数,当test data上的accuracy不提高的epoch数达到early_stopping_n时,就提前停止训练。
这里我们是以test data作为”评估集”的,但实际上这并不是一种很好的做法。“评估集”除了early stopping外,还是我们调整超参数的重要依据,我们目的是让训练好的神经网络能适应所有的数据,即不同的test data,由于我们这里只设置了一个test data,倒也无可厚非,但如果面对不同的test data,上面的做法就有失妥当——以一个test data为“评估集”的训练并不是一定能满足所有test data的,所以我们就要设置“双重保险”——validation data。
validation data包含了10000张图片,以后无论是early stopping还是超参数调整都以它为“评估集”,以超参数调整为例,当我们用validation data调整好超参数后,再在test data上测试一下,这就使得test data是真正意义上用于test的data,而不是另一种形式的training data。简言之,validation data起到的作用就类似于“彩排”,它就是用于调整超参数的另一种training data。

Expanding the training data

在代码中提供了设置“评估集”的接口evaluation_data=None,作者使用50000张training data,以test data为“评估集”训练(为方便与之前对照),得到了如下结果

accuracy

可以发现overfitting仍然存在,但却比之前用1000张图片训练结果好得多,简单理解就是神经网络难以像之前一样“死记硬背”,它将会学习那些robust features,即所谓”见多识广“,关于这个策略,后面会简单介绍,但由于获得数据的代价是昂贵的,因此需要找到更好的策略。
除此之外,还可以考虑减小神经网络的size,但这种想法显然是与我们要获得更强性能网络的初衷相违背,一般不会采用。

Regularization

Definition

正则化策略既不需要扩大training set,也不需要更改neural network的size,仅仅是稍稍调整一下cost function,目前最常用的是L2 regularization,就是在原本的cost function后加一个regularization term(这里以互熵损失为例,其他的也是一样的做法):

regularization

λ为正则化系数,可以明显地看出,当λ较大时,网络倾向于学习更小的weights;反之网络倾向于使原本的cost更小。何谓学习更小的weights?我们从公式是可以明显看出的,但我们还是求导看一下:
$$
\frac{\partial C}{\partial w}=\frac{\partial C_0}{\partial w}+\frac{\lambda}{n}w
$$

$$
\frac{\partial C}{\partial b}=\frac{\partial C_0}{\partial b}
$$

再到weights和bias的更新公式:
$$
b→b-\eta\frac{\partial C_0}{\partial b}
$$

$$
w→(1-\frac{\eta\lambda}{n})w-\eta\frac{\partial C_0}{\partial w}
$$

对与SGD,更新则如下:
$$
b→b-\frac{\eta}{m}\sum_x\frac{\partial C_x}{\partial b}
$$

$$
w→(1-\frac{\lambda}{n})w-\frac{\eta}{m}\sum_x\frac{\partial C_x}{\partial w}
$$

1
2
3
4
self.weights = [(1-eta*(lmbda/n))*w-(eta/len(mini_batch))*nw
for w, nw in zip(self.weights, nabla_w)]
self.biases = [b-(eta/len(mini_batch))*nb
for b, nb in zip(self.biases, nabla_b)]

bias显然是没有受到影响,但weights每次都会通过系数 (1-λ/n) rescale一下,既让weights小一些,因此L2 regularization也叫做weight decay。但这并不意味着weights趋于0,因为后一项可能为负。作者通过测试发现无论是1000张training data还是50000张,用L2正则化之后overfitting现象明显减少了(这里我就没有自己run了)。除此以外,作者通过实验还发现,regularization还可以防止cost停留在局部最小点,因为未正则化的训练方法容易使weights很大,从而导致偏导项相对于weights很小,间接导致“相对步长”减小。

Why regularization works

事实上,对于标题的问题并没有严格的证明,目前的解释也都是基于经验的,即:小的weights可以以一个更精简有力的model解释数据。
这里作者首先给了我们一组数据:

data

欲对以上数据做拟合,现考虑两种函数,一是能准确描述上述数据的九次多项式:y=a0x9+a1x8+……a9(我没有画图,就是严格解出的方程),另一种就是常见的线性拟合:y=2x。两种拟合孰优孰劣并不好说,而且在training set上两种结果差异并不大(至少在树枝上如此),但当x→∞时,差异显然很大,对于这种差异(虽然从数学上说就是废话),不严格的解释就是前者学习到了training data上的许多noise(我之前提过,这里就不多说了)。
到神经网络上,对于小的权重,不同的训练数据只会对network造成很小的变化,这样可以减少训练数据中noise对网络的影响;而大权重对于输入数据的很小变化都会有很大的反应,也正因如此未正则化网络会学习出weights很大的复杂模型来”准确“描述training set,但同时很多noise也被学进去,可以说是有得必有失吧。目前基于我们神经网络的规模以及我们面对的问题,还是倾向于使用前者。
对于这种选择简单模型的想法,人们通常称之为”奥卡姆剃刀“原则,但这并不是一条科学的原则,许多例子都表明并不是越简单的模型越好,作者这里举的几个例子就不赘述了。这里由于小权重的优越性已经体现出来了,所以选择它。
回到L2 regularization,为什么只在cost function后面添加了关于weights的regularization term,而不添加关于bias的项呢?换言之,较大的bias对overfitting有影响吗?答案是否定的,bias项并不会影响不同输入最后输出的差距,即较大的bias并不会像大weights一样使神经元更加sensitive。

Other techniques for regularization

L1 regularization

不同于L2正则化的仅仅是它的regularization term:
$$
C=C_0+\frac{\lambda}{n}\sum_w|w|
$$
它同样是让network倾向于学习小weights:
$$
\frac{\partial C}{\partial w}=\frac{\partial C_0}{\partial w}+\frac{\lambda}{n}sgn(w)
$$

$$
w→w-\frac{\eta\lambda}{n}sgn(w)-\eta\frac{\partial C_0}{\partial w}
$$

与L2正则化不同,它每次减小weight的方法是减去一个constant,当|w|较小时,L1正则化减小weight显然更”快“;反之L2正则化使weight减小得更”快“。书中这一句话很好地指出了L1 regularization的特性:

L1 regularization tends to concentrate the weight of the network in a relatively small number of high-importance connections, while the other weights are driven toward zero.

Dropout

与L1、L2 regularization不同,Dropout是对神经网络结构的改动,我斗胆称网络中某层为Dropout层,对每个mini_batch,随机使Dropout层的神经元减半,更新完weight和bias后,对下一个mini_batch,再次使Dropout层的神经元随机减半,如此重复。

dropout

显然,对于同样的training set,同一个神经网络每次训练的结果也是不一样的,假设我们用同一个training set训练了三个neural network,用一张手写数字图片测试时,发现只有一个识别正确,另外两个都错误(由于某种形式的过拟合),我们当然会选择识别正确的网络作为最终结果,但也不能肯定它即最好的——可能存在着第四个、第五个更优的网络。Dropout就相当于每次使用一个不同的网络,最后把过拟合的影响”平均“,从而达到减小过拟合的目的。
另一种解释是,通过Dropout减少neurons之间复杂共适性的影响(我也不懂这个名词的具体含义),单一的神经元不能过于依赖其他神经元,即使得neuron有一定”自主思考“的能力,这样就迫使network学习更robust的特征,即这些特征对于Dropout层的不同子集都有效,某些input的”不适性“将会被忽略——与L1、L2正则化殊途同归,可以猜测,采用了Dropout的神经网络也会趋向于学习小的weights。

Artificially expanding the training data

之前已经提到过增大训练集可以有效降低overfitting的效果,在无法获得更多数据的情况下,可以手动扩大训练集。对于识别手写数字这个任务,可以使用小角度旋转图片、扭曲图片等方式,即人为添加噪音,要注意的是,这些变化要与实际生活的情况对应,即”伪造“出来的数据要尽量逼真(我说了什么)。
另外,作者还做了一项对比,随着training data的不断增加,SVM的性能竟逐渐向神经网络逼近,可见在某些时候,巨大的数据可以弥补算法的不足。

Others

随着计算机性能的提高,过拟合似乎成了一个普遍的问题,解决它的任务仍未完成。
书中举了个例子,人类看过几次大象,以后几乎都能正确分别出大象,即人脑只需要很少的training data就能训练出accuracy非常高的model,从这方面来说神经网络的发展仍是道阻且长。

0%