Open bluejad opened 7 years ago
将原始的数据集的大小由[N x D]降到了[N x 100],留下了数据中包含最大方差的100个维度
通常使用PCA降维过的数据训练线性分类器和神经网络会达到非常好的性能效果,同时还能节省时间和存储器空间
白化操作的输入是特征基准上的数据,然后对每个维度除以其特征值来对数值范围进行归一化
该变换的几何解释是:如果数据服从多变量的高斯分布,那么经过白化后,数据的分布将会是一个均值为零,且协方差相等的矩阵。该操作的代码如下:
Xwhite = Xrot/np.sqrt(S + 1e - 5)
特征基准
Xrot
分母中添加了1e-5(或一个更小的常量)来防止分母为0
该变换的一个缺陷是在变换的过程中可能会夸大数据中的噪声,这是因为它将所有维度都拉伸到相同的数值范围,这些维度中也包含了那些只有极少差异性(方差小)而大多是噪声的维度
夸大的噪声可以用更强的平滑来解决(例如:采用比1e-5更大的值)
左边:是二维的原始数据
中间:经过PCA操作的数据。可以看出数据首先是零中心的,然后变换到了数据协方差矩阵的基准轴上。这样就对数据进行了解相关(协方差矩阵变成对角阵)
右边:每个维度都被特征值调整数值范围,将数据协方差矩阵变为单位矩阵
从几何上看,就是对数据在各个方向上拉伸压缩,使之变成服从高斯分布的一个数据点分布
应该先分成训练/验证/测试集,只是从训练集中求图片平均值,然后各个集(训练/验证/测试集)中的图像再减去这个平均值
译者注:此处确为初学者常见错误,请务必注意!
权重初始化
错误:全零初始化
小随机数初始化
使用1/sqrt(n)校准方差
稀疏初始化
偏置的初始化
批量归一化
权重初始值要非常接近0又不能等于0
解决方法就是将权重初始化为很小的数值,以此来打破对称性
小随机数权重初始化的实现方法是:
W = 0.01 * np.random.randn(D, H)
randn函数是基于零均值和标准差的一个高斯分布来生成随机数的
警告。并不是小数值一定会得到好的结果。例如,一个神经网络的层中的权重值很小,那么在反向传播的时候就会计算出非常小的梯度(因为梯度与权重值是成比例的)
使用1/sqrt(n)校准方差
建议将神经元的权重向量初始化为:w = np.random.randn(n) / sqrt(n)
其中n是输入数据的数量
这样就保证了网络中所有神经元起始时有近似同样的输出分布。实践经验证明,这样做可以提高收敛的速度
给出了一种针对ReLU神经元的特殊初始化,并给出结论:网络中神经元的方差应该是2.0/n
代码为w = np.random.randn(n) * sqrt(2.0/n)
这个形式是神经网络算法使用ReLU神经元时的当前最佳推荐
给出了一种针对ReLU神经元的特殊初始化,并给出结论:网络中神经元的方差应该是2.0/n
代码为w = np.random.randn(n) * sqrt(2.0/n)
这个形式是神经网络算法使用ReLU神经元时的当前最佳推荐
稀疏初始化(Sparse initialization)
另一个处理非标定方差的方法是将所有权重矩阵设为0,但是为了打破对称性,每个神经元都同下一层固定数目的神经元随机连接(其权重数值由一个小的高斯分布生成)
一个比较典型的连接数目是10个
偏置的初始化
通常将偏置初始化为0,这是因为随机小数值权重矩阵已经打破了对称性
当前的推荐是使用ReLU激活函数,并且使用w = np.random.randn(n) * sqrt(2.0/n)
来进行权重初始化
批量归一化
该方法减轻了如何合理初始化神经网络这个棘手问题带来的头痛:),其做法是让激活数据在训练开始前通过一个网络,网络处理数据使其服从标准高斯分布
在实现层面,应用这个技巧通常意味着全连接层(或者是卷积层,后续会讲)与激活函数之间添加一个BatchNorm层
在实践中,使用了批量归一化的网络对于不好的初始值有更强的鲁棒性
正则化
L2正则化
L1正则化
最大范式约束
随机失活
前向传播中的噪音
偏置正则化
每层正则化
有不少方法是通过控制神经网络的容量来防止其过拟合的
L2正则化可以直观理解为它对于大数值的权重向量进行严厉惩罚,倾向于更加分散的权重向量
使用L2正则化意味着所有的权重都以w += -lambda * W
向着0线性下降
L2正则化可能是最常用的正则化方法了。可以通过惩罚目标函数中所有参数的平方将其实现。即对于网络中的每个权重w,向目标函数中增加一个1/2λ w^2,其中λ是正则化强度
L1正则化是另一个相对常用的正则化方法。对于每个w我们都向目标函数增加一个λ|w|
L1和L2正则化也可以进行组合:λ|w| + λw^2
L1正则化有一个有趣的性质,它会让权重向量在最优化的过程中变得稀疏(即非常接近0)
也就是说,使用L1正则化的神经元最后使用的是它们最重要的输入数据的稀疏子集,同时对于噪音输入则几乎是不变的了
一般说来L2正则化都会比L1正则化效果好
最大范式约化
另一种形式的正则化是给每个神经元中权重向量的量级设定上限,并使用投影梯度下降来确保这一约束
在实践中,与之对应的是参数更新方式不变,然后要求神经元中的权重向量必须满足这一条件||w|| < c,一般值为3或者4。有研究者发文称在使用这种正则化方法时效果更好
这种正则化还有一个良好的性质,即使在学习率设置过高的时候,网络中也不会出现数值“爆炸”,这是因为它的参数更新始终是被限制着的
随机失活的实现方法是让神经元以超参数p的概率被激活或者被设置为0
在训练过程中,随机失活可以被认为是对完整的神经网络抽样出一些子集,每次基于输入数据只更新子网络的参数
一个3层神经网络的普通版随机失活可以用下面代码实现:
普通版随机失活: 不推荐实现
3层neural network的前向传播
p = 0.5
def train_step(X):
前向传播
H1 = np.maximum(0, np.dot(W1, X) + b1)
U1 = np.random.randn(*H1.shape) < p 第一个随机失活遮罩
H1 *= U1 drop!
H2 = maximum(0, np.dot(W2, H1) + b2)
U2 = np.random.randn(*H2.shape) < 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) * p
out = np.dot(W3, H2) + b3
上述操作不好的性质是必须在测试时对激活数据要按照进行数值范围调整
既然测试性能如此关键,实际更倾向使用反向随机失活(inverted dropout),它是在训练时就进行数值范围调整,从而让前向传播在测试时保持不变
这样做还有一个好处,无论你决定是否使用随机失活,预测方法的代码可以保持不变
反向随机失活: 推荐实现方式 在训练的时候drop和调整数值范围,测试时不做任何事
3层neural network的前向传播
p = 0.5
def train_step(X):
前向传播
H1 = np.maximum(0, np.dot(W1, X) + b1)
U1 = np.random.randn((*H1.shape) < p)/p 第一个随机失活遮罩
H1 *= U1 drop!
H2 = maximum(0, np.dot(W2, H1) + b2)
U2 = np.random.randn((*H2.shape) < 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) * p
out = np.dot(W3, H2) + b3
在随机失活发布后,很快有大量研究为什么它的实践效果如此之好
在使用费希尔信息矩阵(fisher information matrix)的对角逆矩阵的期望对特征进行数值范围调整后,再进行L2正则化这一操作,与随机失活正则化是一阶相等的
前向传播中的噪音
测试时,通过分析法或数值法将噪音边缘化
分析法:在使用随机失活的本例中就是乘以p
数值法:例如通过抽样出很多子网络,随机选择不同子网络进行前向传播,最后对它们取平均
偏置正则化
对于偏置参数的正则化并不常见,因为它们在矩阵乘法中和输入数据并不产生互动,所以并不需要控制其在数据维度上的效果
对偏置进行正则化也很少会导致算法性能变差
每层正则化:对于不同的层进行不同强度的正则化很少见(可能除了输出层以外)
实践:通过交叉验证获得一个全局使用的L2正则化强度是比较常见的。在使用L2正则化的同时在所有层后面使用随机失活也很常见。p值一般默认设为0.5,也可能在验证集上调参
正则化
完
损失函数:可以看做是对模型复杂程度的某种惩罚
损失函数的第二个部分是数据损失,它是一个有监督学习问题,用于衡量分类算法的预测结果(即分类评分)和真实标签结果之间的一致性
数据损失是对所有样本的数据损失求平均
斯坦福CS231n:面向视觉识别的卷积神经网络
CS231n课程翻译系列
课程教师Andrej Karpathy