深度学习之神经网络核心原理与算法-归一化与参数初始化

归一化

几乎所有机器学习算法在开始训练之前都必须克服的问题:

mark

假设我们要比较中国人和日本人的收入差距。从统计学角度。

都抽了一千人。 中国人平均年薪55000,日本人平均年薪2600000.如果这时候得出日本人年薪是中国人几十倍就很不符合现实了。以当地货币作为单位的。

因为人民币和日元的汇率。日本人是中国人的2.8倍。

计算机的系统中数字是没有量纲的,没有单位的,只有具体的浮点数或者定点数。

mark

左边同学的卷子是5分制的,而右边这两个是100分的卷子

在机器学习的过程中,由于数字单位的影响,导致分布范围较广的值和分布范围较窄的值会在训练的过程中有着不同的影响力,那么结果是会引起结果对于某些值过于敏感,或者是对于某些值不那么敏感。这是我们不愿意看到的。

这时我们就会使用归一化的操作,把数据大小分布在一个比例协调的范围之内。

常见的归一化方法:

  • 线性函数归一化(Min-Max Scaling)
  • 0均值标准化(Z-Score Standardization)

两种归一化的目的都是让各个维度的数据拉伸到一个相近的维度范围

线性函数归一化公式:

mark

假设x是一个向量,先用最大值与最小值的差作为分母。再用每个维度的数值与最小值作为分子,会得到一个比值。这个比值就是归一化之后的结果值。

每个数值经过这样的投射,会变成一个0-1之间的数值。这个数值表示自己在该维度样本中所处的位置比例。

mark

做了归一化之后,数据就会呈现出上图这种效果。左边图为x和y两个维度在原始的分布情况。

中间这幅图是对于数据进行(0中心化)之后,也就是x和y的值都减去各自的平均值。可以得到一堆有正有负的值,且0在中心的位置。

最右边是归一化以后的图。数据的分布不再是一个狭长的形状而是一个趋于正方形的形状。

深度学习中也会遇到归一化的问题,最常见的就是使用一种叫做批归一化(Batch Noramlization)的过程。

在整个网络的任何一层都可以加入批归一化的操作。这就等于把每层网络看成是一个独立的分类模型。

这样就可以避免网络因为数据分布不同所带来的尴尬。

参数初始化问题

在搭建完一个神经网络之后,再开始正式训练神经网络之前,有一件事我们不得不做。

要对整个网络中所有的待定系数进行初始化操作。我们究竟应该把这些权值w赋值为多少合适?

怎样初始化权重

结论: 一种在业界比较认可的说法是把整个网络中所有的w初始化为以0为均值,以某个很小的值为标准差的正态分布的方式,通常效果会比较好。

具体初始化: 以0为均值,以1为方差的分布来随机初始化。

mark

其实还有很多种其他的初始化方法,但是大多数都是高斯分布类似的,或者是变种的方式。

关于如何初始化这些w的值,在业界已经讨论了很久,最后的结果也属于仁者见仁智者见智

目前普遍得到认可的就是这种基于高斯分布的初始化方法。

我们可以这样理解这种初始化方法,就是在一个模型中对于输入的各个维度的权重的设置,就相当于一种重视的程度。有的维度对于模型的判断结果非常重要,属于正面因素。

有的维度对于模型的判断结果不那么重要,属于负面因素。

正面因素和负面因素都是比较少数的,而大部分的维度对于模型的判断结果是比较中庸的。这一部分中庸的维度就占了绝大多数。

有统计学基础或者是数据认知的朋友应该都会了解,自然界的大部分数据分布都呈现出高斯分布的特点。

我们看到任何一种事务都是中庸的比较多,极端的比较少。比如一个地区人群的收入,

收入低和高都比较少,收入中等的人群最多。一个地区成人的身高分布等。

同样一个城市人口寿命分布也是这样。

输入向量既然是没有经过什么特征提取的自然信息,这些特征中应该也会有其重要程度。

具有区分价值的维度是少数,大部分信息的特征不太明显。自然采纳度也不同。

mark

怎样初始化权重 二

怎样在代码里添加参数的初始化方法。

在我们原本的init方法中添加一个初始化我们每层的偏置和权重的方法large_weight_initializer,把之前的网络初始化方法放到新定义的里面去。

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 zip(self.sizes[:-1], self.sizes[1:])]

再新增一个方法default_weight_initializer来编写我们的新初始化方法。

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 zip(self.sizes[:-1], self.sizes[1:])]

mark

除以x的平方。

其他代码保持不变,同样经过30轮epoch,我们的准确率达到了96%

mark

发表评论

电子邮件地址不会被公开。 必填项已用*标注