L2 Regularization

在目标函数加入,这样在更新参数时,要在原本更新梯度的后面加入正则w += -lamda * W。L2正则项会将所有参数拉伸,使网络更倾向使用全部特征,而不是依赖小部分特征。

对于一组特征x=[1,1,1,1],他的label是1,不加正则项,训练之后可能会得到W=[1,0,0,0],但是加入正则后,训练之后的结果可能会偏向W=[0.25, 0.25, 0.25, 0.25],这就是拉伸所有参数,倾向使用全部特征的含义。

L1 Regularization

在目标函数加入,L1正则化倾向使参数变的稀疏,即W中很多为0.一般情况下,L2比L1好点。如果已知数据十分稀疏,那么L1效果自然更好。

还有一种正则化方式,将L1和L2想结合, ,也被称作Elastic net regularizaton.

Max norm constraints

一种形式的正则化是给每个神经元中权重向量的量级设定上限,并使用投影梯度下降来确保这一约束。在实践中,与之对应的是参数更新方式不变,然后要求神经元中的权重向量必须满足这一条件,一般值为3或者4。有研究者发文称在使用这种正则化方法时效果更好。这种正则化还有一个良好的性质,即使在学习率设置过高的时候,网络中也不会出现数值“爆炸”,这是因为它的参数更新始终是被限制着的。

Dropout

1 - dropout
图 1 - dropout

由Srivastava提出,论文见Dropout: A Simple Way to Prevent Neural Networks from Overfitting.思想是在前向传播的时候,随机使一些神经元失活,每次数据都是更新不同子网络的参数(子网络并不是独立的,而是共享参数);在测试的时候,使用完整的网络。可以理解为model ensemble,即训练了多个不同的网络,然后在测试的时候将预测结果平均,得到较好的performance。

一个3层神经网络的普通版随机失活可以用下面代码实现:

""" Vanilla Dropout: Not recommended implementation (see notes below) """

p = 0.5 # 激活神经元的概率. p值更高 = 随机失活更弱

def train_step(X):
  """ X中是输入数据 """

  # 3层neural network的前向传播
  H1 = np.maximum(0, np.dot(W1, X) + b1)
  U1 = np.random.rand(*H1.shape) < p # 第一个随机失活mask
  H1 *= U1 # drop!
  H2 = np.maximum(0, np.dot(W2, H1) + b2)
  U2 = np.random.rand(*H2.shape) < p # 第二个随机失活mask
  H2 *= U2 # drop!
  out = np.dot(W3, H2) + b3

  # 反向传播:计算梯度... (略)
  # 进行参数更新... (略)

def predict(X):
  # 前向传播时模型集成
  H1 = np.maximum(0, np.dot(W1, X) + b1) * p # 注意:激活数据要乘以p
  H2 = np.maximum(0, np.dot(W2, H1) + b2) * p # 注意:激活数据要乘以p
  out = np.dot(W3, H2) + b3

在上面的代码中,在训练阶段随机使神经元失活,然后在预测阶段将不用随机失火,但是要对结果做一个平均,乘以p就是做平均。通过超参数p来控制失火神经元数量。为什么乘以p就是做了一个平均呢? 2 - cs231n lecture6 58页ppt
如图2所示,predict阶段是用训练时期的所有子网络,然后平均他们的预测结果。注意,虽然这里设为p=0.5,并不是每次都是使一半神经元失活,可能第一次使所有神经元失活,但是第二次使所有神经元都激活,但是随着次数的增加,最后平均下来,就是每次失活一半神经元,这样按照图2的推导过程,就可以得出乘以p就是平均所有子网络的输出的结果。

官方文档给出的解释更加有理有据:假如,那么在训练的时候该神经元输出的期望就是,神经元有的概率被抑制,输出为0,那么在预测阶段所有的神经元都是激活的,为了保持和训练阶段相同的预期输出,所以需要调整.

那每次都在predict阶段做rescale,有的人看着不爽,可以将他移到训练阶段。在训练的时候,就把输出调为正常的输出。如下:

""" 
反向随机失活: 推荐实现方式.
在训练的时候drop和调整数值范围,测试时不做任何事.
"""

p = 0.5 # 激活神经元的概率. p值更高 = 随机失活更弱

def train_step(X):
  # 3层neural network的前向传播
  H1 = np.maximum(0, np.dot(W1, X) + b1)
  U1 = (np.random.rand(*H1.shape) < p) / p # 第一个随机失活mask. 注意/p!
  H1 *= U1 # drop!
  H2 = np.maximum(0, np.dot(W2, H1) + b2)
  U2 = (np.random.rand(*H2.shape) < p) / p # 第二个随机失活mask. 注意/p!
  H2 *= U2 # drop!
  out = np.dot(W3, H2) + b3

  # 反向传播:计算梯度... (略)
  # 进行参数更新... (略)

def predict(X):
  # 前向传播时模型集成
  H1 = np.maximum(0, np.dot(W1, X) + b1) # 不用数值范围调整了
  H2 = np.maximum(0, np.dot(W2, H1) + b2)
  out = np.dot(W3, H2) + b3

这就相当于我每次用一半神经元来训练,得到的结果也是全部神经元预测结果除以2的,那么我直接在用一半神经元的时候把结果扩大2倍。那么在predict的时候,embedding所有的子网络,就不用在除了,因为我们之前已经乘过了。

Dropout的效果很好,有效的避免过拟合,推荐使用。

results matching ""

    No results matching ""