神经网络:静态部分

白化

白化操作的输入是特征基准上的数据,然后对每个维度除以其特征值来对数值范围进行归一化。该变换的几何解释是:如果数据服从多变量的高斯分布,那么经过白化后,数据的分布将会是一个均值为零,且协方差相等的矩阵。该操作的代码如下:

1
2
3
# 对数据进行白化操作:
# 除以特征值
Xwhite = Xrot / np.sqrt(S + 1e-5)

警告:夸大的噪声。注意分母中添加了1e-5(或一个更小的常量)来防止分母为0。该变换的一个缺陷是在变换的过程中可能会夸大数据中的噪声,这是因为它将所有维度都拉伸到相同的数值范围,这些维度中也包含了那些只有极少差异性(方差小)而大多是噪声的维度。在实际操作中,这个问题可以用更强的平滑来解决(例如:采用比1e-5更大的值)。

注意

任何预处理策略(比如数据均值)都只能在训练集数据上进行计算,算法训练完毕后再应用到验证集或者测试集上。(避免过拟合等)

权重初始化

  • 错误:全零初始化。 权重全零,会导致每个神经元都计算出同样的输出,在BP时也会计算出同样的梯度,从而进行同样的参数更新。**
  • 小随机数初始化: W = 0.01 * np.random.randn(D,H)。并不是数值越小结果越好,要控制在一定的量级内才不会导致BP时梯度信号过小。
  • 使用$1/sqrt(n)$校准方差。随着输入数据量的增长,随机初始化的神经元的输出数据的分布中的方差也在增大。公式如下: w = np.random.randn(n) / sqrt(n). 此外,基于BP时梯度的分析,神经网络算法使用ReLU神经元时的当前最佳推荐形式为: w = np.random.randn(n) / sqrt(2.0/n)
  • 批量归一化。让激活数据在训练开始前通过一个网络,网络处理数据使其服从标准高斯分布。使用了批量归一化的网络对于不好的初始值有更强的鲁棒性。

正则化

L2正则化

L2正则化可以直观理解为它对于大数值的权重向量进行严厉惩罚,使网络更倾向于使用所有输入特征,而不是严重依赖输入特征中某些小部分特征。

L1正则化

L1正则化让权重向量在最优化的过程中变得稀疏(即非常接近0)。即使用L1正则化的神经元最后使用的是它们最重要的输入数据的稀疏子集,同时对于噪音输入则几乎是不变的了。

随机失活

在训练的时候,随机失活的实现方法是让神经元以超参数$p$的概率被激活或者被设置为0。随机失活可以被认为是对完整的神经网络抽样出一些子集,每次基于输入数据只更新子网络的参数。注意:predict函数中不进行随机失活,但是对于两个隐层的输出都要乘以p,调整其数值范围。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
""" 普通版随机失活: 不推荐实现 (看下面笔记) """

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 # 第一个随机失活遮罩
H1 *= U1 # drop!
H2 = np.maximum(0, np.dot(W2, H1) + b2)
U2 = np.random.rand(*H2.shape) < p # 第二个随机失活遮罩
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

反向随机失活。在训练时就进行数值范围调整,从而让前向传播在测试时保持不变。这样做还有一个好处,无论你决定是否使用随机失活,预测方法的代码可以保持不变。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
""" 
反向随机失活: 推荐实现方式.
在训练的时候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 # 第一个随机失活遮罩. 注意/p!
H1 *= U1 # drop!
H2 = np.maximum(0, np.dot(W2, H1) + b2)
U2 = (np.random.rand(*H2.shape) < p) / p # 第二个随机失活遮罩. 注意/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

随机失活的解释。

1、使用许多小的模型集成的一个大模型。假设某些神经元被随机失活了,那么在BP中,与这些神经元相连的上一层的权重也不会更新,那么就相当于只对整个大模型的子网络进行了训练。

2、假设我们使用神经网络对猫这个类别进行检测,在神经网络中我们用到的特征可能有:耳朵、尾巴、眼睛等等,在标准的神经网络中,我们需要考虑每一个特征因素才能对猫进行得分计算。但是在测试集中,猫的图片是多种多样的,可能有时看不到尾巴或则耳朵,这就会影响了模型的泛化能力。而利用了随机失活,即在训练时我们随机得不考虑一些特征(例如耳朵)来训练模型,这样模型在测试集上一般能得到更好的泛化能力。

分类问题

当面对一个回归任务,首先考虑是不是必须使用回归模型。一般而言,尽量把你的输出变成二分类,然后对它们进行分类,从而变成一个分类问题。

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×