“深度学习”学习日记。与学习有关的技巧--权重的初始值

2023.1.22

在深度学习的学习中,权重的初始值特别重要。这关系到神经网络的学习能否成功;

在以前误差反向传播法和神经网络学习的算法实现这两篇文章中,对权重的初始值的确定是这样的:

class TwoLayerNet:
    def __init__(self, input, hidden, output, weight__init__std=0.01):
        # 权重的初始化 假设一个权重
        # 通过本函数可以返回一个或一组服从标准正态分布的随机样本值。平均数为0,方差为1
        self.params = {}
        self.params['w1'] = weight__init__std * np.random.randn(input, hidden)
        self.params['b1'] = np.zeros(hidden)
        self.params['w2'] = weight__init__std * np.random.randn(hidden, output)
        self.params['b2'] = np.zeros(output)

 神经网络学习算法的实现:https://blog.csdn.net/m0_72675651/article/details/128671496

误差反向传播法的算法实现:https://blog.csdn.net/m0_72675651/article/details/128729159

 都是通过一个np.random.randn( )函数去返回一个或一组服从标准正态分布的随机样本值,平均数为0,方差为1。

先说结论:有一种抑制过拟合、提高泛化能力的技巧,称为“权值衰减”。顾名思义,就是一个让权重值减小的方法去抑制过拟合、提高泛化能力;

所以我们一开始就先设置一个较小的权重都是0.01*np.random.randn( )这样的。(标准差为0.01的高斯分布)

但是,我们不能将权重设置为0,否则神经网络将无法进行学习,因为在神经网络推理处理中,输入层正向传播的权重为0,而传递给下一层神经网络的值也是0,这也意味着在反向传播更新数值时权重更新的内容全是相同的值,就代表着神经网络模型无法学习;

接下来参照教材作一个实验:

观察权重初始值时如何影响隐藏层的激活函数输入值的分布的:假设神经网络有有5层,每层100个神经元,先研究 激活函数使用sigmoid()

import numpy as np
import matplotlib.pyplot as plt


# sigmoid函数的实现
def sigmoid(x):
    return 1 / (1 + np.exp(-x))


x = np.random.randn(1000, 100)
node_num = 100
hidden_layer_size = 5
activations = {}

for i in range(hidden_layer_size):
    if i != 0:
        x = activations[i - 1]

    w = np.random.randn(node_num, node_num) * 1

    z = np.dot(x, w)
    a = sigmoid(z)
    activations[i] = a

for i, a in activations.items():
    plt.subplot(1, len(activations), i + 1)
    plt.title(str(i + 1) + "-layer")
    plt.hist(a.flatten(), 30, range=(0, 1))  # 在matplotlib中,hist方法用于绘制直方图
# flatten是numpy.ndarray.flatten的一个函数,即返回一个折叠成一维的数组。但是该函数只能适用于numpy对象,即array或者mat,普通的list列表是不行的。
plt.show()


# subplot(nrows, ncols, index, **kwargs)
# subplot(pos, **kwargs)
# subplot(**kwargs)
# subplot(ax)

输出结果: 

 因为假设有1000个数据,其排列方式是1000×100的矩阵,权重是100×100的排列分布的矩阵,所以z是1000×100的矩阵,所以a.flatten()后是一个(1×100000)的一个向量;

 w = np.random.randn(node_num, node_num) * 1

”1“代表标准差为1的高斯分布,实验的目的就是通过改变这个尺度,观察权重初始值对激活函数的变化;

a经过sigmoid函数处理后成为i一个(0,1)的值;

如上图所示,他的输出不断地靠近0,1;所以他的导数逐渐接近0,在反向传播中他的梯度会不断的减小,最后消失,这样的现象,称他为“梯度消失”;层次加深的深度学习中梯度消失的问题会更加严重。

接着将标准差设置为0.01继续:

w = np.random.randn(node_num, node_num) * 1

更换成

w = np.random.randn(node_num, node_num) * 0.01

再观察结果

 

 这次a的输出值向0.5集中,并不会发生梯度消失的问题,但是,这样的激活值向一个方向偏向也是有问题的,因为如果全部神经元输出相同的值那么就没有价值了,就好比权重初始值设置为0,权重更新为相同的值,出现了权重结构对称的现象,也称为 表现力受损 的问题。

(激活函数值需要有一点的广度,神经网络2才能高效率的学习,如果是有所偏向的数值就会出现“表现力受损”、“梯度消失”的问题)

然后,现在学习Xavier值,先说结论:Xavier值是已经被作为标准使用。比如Caffe框架中,通过设定权重值时,赋予Xavier值参数,以此实现Xavier值得初始化;

简单得来说他得做法是:如果前一层得节点是n,那么初始值设置使用得标准差为 \frac{1}{\sqrt{h}}得分布;

该方法来自有Xavier得相关论文,它不仅考虑了前一层得输出节点得数量,也考虑了后一层得输出节点数量,但是,Caffe等框架得现实中进行了简化,只用前一层得输出节点数量即可。

# 因为这个实验代码每一层得节点数量都是100,所以可以简化实现过程

 

w = np.random.randn(node_num, node_num) / np.sqrt(node_num)

观察输出结果:

可以看出,越是后面得层,图像越是倾斜,也呈现了广度,sigmoid函数得表现力不受限制,能够高效得进型学习。

但是,会不会就觉得后面得图像有点抽象,所以学习了一个与sigmoid函数相同得tanh函数;

def tanh(x):
    return np.tanh(x)

使用tanh函数得输出结果:

sigmoid\left ( x \right )=\frac{1}{e^{-x}+1} ; tanh\left ( x \right ) =2sigmoid\left ( 2x \right )-1

tanh(x)得图像:关于原点对称;

 

tanh图像代码实现:

import numpy as np
import matplotlib.pyplot as plt


def tanh(x):
    return np.tanh(x)


x = np.arange(-10, 10)
y = tanh(x)

plt.plot(x, y)
plt.hlines(0, -10, 10, colors='red', linestyles='--')
plt.title('tanh')
plt.show()

 tanh函数和sigmoid函数一样都是S型曲线函数,而sigmoid函数是关于(0,0.5)对称得S型曲线。总所周知,用作激活函数得函数最好具有关于原点对称得性质。

( Xavier初始值是以激活函数是线性函数为前提而推出来的,因为sigmoid函数和tanh函数左右对称,且中央附近可以视为线性函数,所以适合Xavier初始值。)

当激活函数使用ReLU的权重初始值:

当即或函数用的ReLU函数时,一般推荐时用kaiming He 提出的“He初始值”。当前一个函数节点数为n时,He初始值使用的标准差为\sqrt{\frac{2}{n}}的高斯分布;分别通过标准差为0.01,Xavier值,He值观察参数分布;

拿代码运行看结果。

import numpy as np
import matplotlib.pyplot as plt


# sigmoid函数的实现
def sigmoid(x):
    return 1 / (1 + np.exp(-x))


def tanh(x):
    return np.tanh(x)


def ReLU(x):
    return np.maximum(0, x)


x = np.random.randn(1000, 100)
node_num = 100
hidden_layer_size = 5
activations = {}

for i in range(hidden_layer_size):
    if i != 0:
        x = activations[i - 1]

    w = np.random.randn(node_num, node_num) / np.sqrt(node_num)  # Xavier值
    # w = np.random.randn(node_num, node_num) * 0.01 # std=0.01
    # w = (np.random.randn(node_num, node_num) * np.sqrt(2)) / np.sqrt(node_num)# He值 

    z = np.dot(x, w)
    # a = tanh(z)
    # a=sigmoid(z)
    a = ReLU(z)
    activations[i] = a

for i, a in activations.items():
    plt.subplot(1, len(activations), i + 1)
    plt.title(str(i + 1) + "-layer")
    plt.hist(a.flatten(), 30, range=(0, 1))  # 在matplotlib中,hist方法用于绘制直方图
# flatten是numpy.ndarray.flatten的一个函数,即返回一个折叠成一维的数组。但是该函数只能适用于numpy对象,即array或者mat,普通的list列表是不行的。
plt.show()

# subplot(nrows, ncols, index, **kwargs)
# subplot(pos, **kwargs)
# subplot(**kwargs)
# subplot(ax)

当标准差为0.01时:

 各层的激活值非常小,神经网络传递的时非常小的值,反向传播的值也很小,说明权重该参数不会怎么更新,学习效果差;

当标准差为Xavier值:

 随着层的加深,偏向越来越大,会出现 梯度消失现象 ;

当标准差为He值时:

 随着层数的加深,各层中分布的广度相同,因此其逆向传播的效果也很好;

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值