这是我参与11月更文挑战的第10天
之前权重的选择方式的根据独⽴⾼斯随机变量来选择权重和偏置,其被归⼀化为均值为0,标准差为1。这种方式存在明显的缺点,假设使用归一化高斯分布初始化了连接第一个隐含层的权重,忽略其他因素,重点讨论连接权重如下图所示:
为简化问题假设训练输入数据集的规模为,其中一半输入神经元值为0,另一半为1。对于神经元的带权输入,其中500项已经被消除了,剩下500个和一个。这501项的取值服从均值为0,标准差为1的高斯分布,因此的取值会是一个均值为0标准差为的高斯分布如下图所示:
可以看出的取值可能远大于或远小于1,进而影响到的取值令其接近于1或0,即隐藏神经元会接近饱和,而当隐藏神经元接近饱和时学习速率会下降,这也是导致学习速度缓慢的原因。
因此为了更好地初始化的值,假设有个输入神经元,使用均值为0标准差为的高斯分布初始化权重。在和上例相同的情况下,的分布变成了均值为0标准差为的高斯分布,如下图所示:
从而令神经元无法饱和,缓解学习速度下降问题。
练习: 假设有个输入神经元,使用均值为0标准差为的高斯分布初始化权重,均值为0,标准差为1的高斯分布初始化偏置。假设训练输入数据集的规模为,其中一半输入神经元值为0,另一半为1。验证的标准差为。
提示:(a)独⽴随机变量和的⽅差,是每个独⽴随机变量⽅差的和(b)⽅差是标准差的平⽅。
基于上面的条件可知,的方差为:
因此的标准差为。
代码实现和比较
原来的初始化:
# 之前使用过比较简单的初始化方法用来比较两种初始化方法的区别
def large_weight_initializer(self):
self.biases = [np.random.randn(y, 1) for y in self.sizes[1:]]
self.weights = [np.random.randn(y, x)
for x, y in list(zip(self.sizes[:-1], self.sizes[1:]))]
新的初始化方法:
# 使用均值为0标准差为1的高斯分布来初始化偏差
# 使用均值为0标准差为sqrt(n)的高斯分布来初始化权重,n为输入神经元的数量
def default_weight_initializer(self):
self.biases = [np.random.randn(y, 1) for y in self.sizes[1:]]
self.weights = [np.random.randn(y, x) / np.sqrt(x)
for x, y in list(zip(self.sizes[:-1], self.sizes[1:]))]
结果对比:
可以看出这种改进方法显著提升了学习速度,但并不会改变网络的最终性能。
如何选择神经⽹络的超参数
对于学习速率和规范化参数的选择方法,在实际中选择合适的值是很困难的。基本上这里的超参数的选择都基于启发式想法,不存在一种通用的正确选择方法:
宽泛策略
一开始不要将网络结构设置得过于复杂,可以只有用简单的三层网络架构测试参数变化对结果的影响来寻找参数优化网络的规律。
学习速率的调整
测试三个不同学习速率值对学习的影响:
可以看到当时,震荡非常明显,为了理解这个现象回到随机梯度下降的原理:
的值影响的是下降的步长,太大的话可能导致算法在接近最小值时越过谷底导致反复震荡,因此的值应该选择偏小的。(但是过小会影响学习的速度)
学习速率通常设置为常量,但是采⽤可变的学习速率可能更加有效。在学习的前期,使⽤⼀个较⼤的学习速率让权重变化得更快,往后就可以降低学习速率,这样可以作出更加精良的调整。基于这个思想如何设置学习速率?自然而然的可以想到:
- 一开始保持为一个常量直到验证准确率开始变差
- 按照某个比例降低,例如10或2,重复若干次直到低于初始值的后终止训练
epoch 使⽤提前停⽌来确定迭代期数量
这里前面过拟合部分已经提到过,在验证集上准确率不再提升时停止学习。
规范化参数的选择
的值一开始可以不确定(即),等确定之后再尝试变化的值。
mini_batch大小的选择
如何设置⼩批量数据的⼤小?为简化问题可以先假设学习大小为1的小批量数据,权重的变化为:
相比大小为100的小批量数据的权重变化率:,大小为1的小批量数据的权重变化快了100倍。但问题在于大小为1的小批量数据更新非常频繁(即需要用到循环的方式来计算梯度),而大小为100的小批量数据可以用矩阵技术来计算梯度,提升计算速度。
这也是选择小批量数据大小需要考虑的,太小了学习速度会降低,太大更新权重的次数太少。幸运的是,⼩批量数据⼤⼩的选择其实是相对独⽴的⼀个超参数(⽹络整体架构外的参数),所以不需要优化其他参数来寻找好的⼩批量数据⼤⼩。