【深度学习】1-权重参数全相同值初始化,导致无法训练-python

简介: 【深度学习】1-权重参数全相同值初始化,导致无法训练-python

1. 训练结果不稳定


虽然我大致知道模型中的每段代码大致在做什么,但现在我有些茫然了,感觉这些代码根本不在我的掌控之中。这种感觉有点糟糕,不过学习本来就是一个一边使用和一边了解的过程。

我后来猜测原因应该在权重参数那里。因为,权重参数是使用随机取样来初始化的。我这里使用的是正态分布(normal)中的随机取样。也就是说,每次开始训练时,初始模型参数都不一样。


参数初始化部分的代码:


num_inputs, num_outputs = 784, 10
num_hiddens, num_hiddens2 = 256, 30
W1 = nd.random.normal(scale=0.01, shape=(num_inputs, num_hiddens))
b1 = nd.zeros(num_hiddens)
W2 = nd.random.normal(scale=0.01, shape=(num_hiddens, num_hiddens2))
b2 = nd.zeros(num_hiddens2)
W3 = nd.random.normal(scale=0.01, shape=(num_hiddens2, num_outputs))
b3 = nd.zeros(num_outputs)
params = [W1, b1, W2, b2, W3, b3]
for param in params:
    param.attach_grad()

2. 全相同值初始化


考虑到很可能是权值参数导致的每次训练的结果有浮动,那不如就试试每次都从相同的权值参数开始训练,这样我后面调超参数的时候,应该就好观察一点。我一开始想的是简单起见,把所有的权值都设置为 1 试试。


改动后的参数初始化代码:

num_inputs, num_outputs = 784, 10
num_hiddens, num_hiddens2 = 256, 30
W1 = nd.ones((num_inputs, num_hiddens))
b1 = nd.zeros(num_hiddens)
W2 = nd.ones((num_hiddens, num_hiddens2))
b2 = nd.zeros(num_hiddens2)
W2 = nd.ones((num_hiddens2, num_outputs))
b3 = nd.zeros(num_outputs)
params = [W1, b1, W2, b2, W3, b3]
for param in params:
    param.attach_grad()

改动后的运行情况:


epoch 1, loss 9765948.7299, train acc 0.100, test acc 0.100
epoch 2, loss 2.3032, train acc 0.099, test acc 0.100
epoch 3, loss 2.3031, train acc 0.100, test acc 0.100
epoch 4, loss 2.3031, train acc 0.098, test acc 0.100
epoch 5, loss 2.3031, train acc 0.098, test acc 0.100

可以看到,在第一个训练周期中,损失值(loss)很大。后来损失值虽然变小了,但是在测试集上的准确率(test acc)却没有动静,始终为10%。而数据集中刚好一共就是10个类别。可以说,这分类,它完全就是蒙的。人工智障了属于是。


改动前正常的运行情况:


epoch 1, loss 1.4737, train acc 0.429, test acc 0.725
epoch 2, loss 0.6242, train acc 0.764, test acc 0.809
epoch 3, loss 0.4948, train acc 0.818, test acc 0.836
epoch 4, loss 0.4394, train acc 0.836, test acc 0.839
epoch 5, loss 0.4031, train acc 0.850, test acc 0.862

3. 为何丧失拟合能力


我刚刚是将初始权值参数全部设置为 1, 我也尝试了许多其它的数,无一例外,模型都无法成功训练。查了一些资料后,我发现了一个问题。

如果一层中,所有的参数都初始化为一样的,这一层就相当于只有一个神经元节点了。以一个简单的情况作为例子:


image.png


简单起见,这里我们也不考虑偏差参数(bias)。那么我们模型得到的函式就是:

f ( x 1 , x 2 ) = w 1 x 1 + w 2 x 2 f(x1, x2) = w1x1 + w2x2

f(x1,x2)=w1x1+w2x2


当权值参数都相同,即 w1 = w2 时,函数就可以写成:

f ( x 1 , x 2 ) = w ( x 1 + x 2 ) f(x1, x2) = w(x1+x2)

f(x1,x2)=w(x1+x2)


再用 x 代替(x1 + x2):

f ( x ) = w x f(x) = wx

f(x)=wx


而无论我们设置了多少节点,有多少权重参数,如果这些参数是相同的,那我们的模型仍然只拥有一元线性函式的拟合能力。


但是,我们只是初始权值参数是相同的,那么训练后的权值参数仍然一定是相同的吗?

在我的模型训练过程中,是使用通过梯度的反向传播,来更新模型参数的(lr为学习率):

w = w − l r Δ w w = w - lr \Delta w

w=w−lrΔw


如果不同节点得到的梯度反馈都是相同的,而初始值权值也相同,那么在训练过程中,权值自然会始终保持相同。而一维的线性模型,面对相对复杂的、非线性的分类任务,除了蒙,还能怎样呢?


关于梯度下降导致模型失去足够的拟合能力,下面提供我个人的一种稍稍形象一些的理解方式,仍然以我们之前的简单模型作为例子:


image.png


因为两个权值参数的初始值相等会导致:这两个参数的更新方向和幅度也是相等的。那么整个模型的训练过程中,权值参数向量的更新方向(Δw1, Δw2)就是恒定的。这样会造成什么问题呢?


l o s s = f ( w 1 , w 2 ) loss = f(w1, w2)

loss=f(w1,w2)


image.png


设图中的min就是我们要找的全局最优点(损失最小的点),而点(w1, w2) 就只能在图中的虚线上移动。它可以移动到一个比较靠近min的位置,而使得损失值loss变得较小。但显然模型的整个拟合效果常常是很差的。这样的分析也比较符合我们之前的运行结果:损失值变小一次后就不再改变,而模型的预测准确率则完全像是蒙的。


当然,这也只是我自己一个用来帮助理解的想法,供大家参考一下。


4. 赋不同值初始化


不要忘了最初的目标,我只是想着用固定的初始权值参数,调超参数时,可能好观察和比较结果一点。那是不是只要我为这些参数都附上不同的值,模型就可以正常进行训练了呢?

理论上应该是可以的。我尝试用下面的代码来对一层权值参数的所有元素逐个来进行初始化:

k = 0.0000001
sum = 0.01
flag = 1
for i in range(num_inputs):
    for j in range(num_hiddens):
        W1[i][j] = sum * flag
        flag = -flag
        sum += k

但是,我发现这段代码运行起来实在是慢得可怜。python执行矩阵运算会比逐个元素的运算慢很多(是为什么我现在也还不知道)。希望到这里暂时就破灭了。哈哈。


5. 附录:初完整代码


注:代码来自《动手学深度学习》

%matplotlib inline
import d2lzh as d2l
from mxnet import nd
from mxnet.gluon import loss as gloss
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
num_inputs, num_outputs = 784, 10
num_hiddens, num_hiddens2 = 256, 30
W1 = nd.random.normal(scale=0.01, shape=(num_inputs, num_hiddens))
b1 = nd.zeros(num_hiddens)
W2 = nd.random.normal(scale=0.01, shape=(num_hiddens, num_hiddens2))
b2 = nd.zeros(num_hiddens2)
W3 = nd.random.normal(scale=0.01, shape=(num_hiddens2, num_outputs))
b3 = nd.zeros(num_outputs)
params = [W1, b1, W2, b2, W3, b3]
for param in params:
    param.attach_grad()
def relu(X):
    return nd.maximum(X, 0)
def net(X):
    X = X.reshape((-1, num_inputs))
    H = relu(nd.dot(X, W1) + b1)
    H2 = relu(nd.dot(H, W2) + b2)
    return nd.dot(H2, W3) + b3
loss = gloss.SoftmaxCrossEntropyLoss()
num_epochs, lr = 5, 0.5
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, params, lr)

总结


折腾了挺久,后面感觉我想使用固定的初始参数,来方便观察和比较实验结果的想法,本身可能也不是很好。每次都从相同的地方开始,即使通过调整超参数,取得了优秀的训练效果,取得这个效果可能是 依赖于初始参数的(当然,训练的结果本身仍然是优秀的)。

如果又换到随机的初始参数下训练,大概率会取得更差而不是更好的训练效果。


继续加油!!!学习本身就是一个不断试错的过程。


在学习的过程中,也参考了一些好文章。它们不是都与我本次的问题直接相关,但我觉得对我整体上的理解是有帮助的。


独家 | 初学者的问题:在神经网络中应使用多少隐藏层/神经元?(附实例)

深层神经网络的权值初始化问题

常用的激活函数汇总-Sigmoid, tanh, relu, elu


相关文章
|
6天前
|
机器学习/深度学习 数据采集 TensorFlow
使用Python实现智能食品加工优化的深度学习模型
使用Python实现智能食品加工优化的深度学习模型
99 59
|
2天前
|
机器学习/深度学习 人工智能 TensorFlow
人工智能浪潮下的自我修养:从Python编程入门到深度学习实践
【10月更文挑战第39天】本文旨在为初学者提供一条清晰的道路,从Python基础语法的掌握到深度学习领域的探索。我们将通过简明扼要的语言和实际代码示例,引导读者逐步构建起对人工智能技术的理解和应用能力。文章不仅涵盖Python编程的基础,还将深入探讨深度学习的核心概念、工具和实战技巧,帮助读者在AI的浪潮中找到自己的位置。
|
2天前
|
机器学习/深度学习 数据采集 TensorFlow
使用Python实现智能食品市场预测的深度学习模型
使用Python实现智能食品市场预测的深度学习模型
15 5
|
3天前
|
机器学习/深度学习 算法 数据可视化
使用Python实现深度学习模型:智能食品配送优化
使用Python实现深度学习模型:智能食品配送优化
13 2
|
2天前
|
机器学习/深度学习 人工智能 算法
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
手写数字识别系统,使用Python作为主要开发语言,基于深度学习TensorFlow框架,搭建卷积神经网络算法。并通过对数据集进行训练,最后得到一个识别精度较高的模型。并基于Flask框架,开发网页端操作平台,实现用户上传一张图片识别其名称。
11 0
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
|
2天前
|
机器学习/深度学习 人工智能 算法
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
蔬菜识别系统,本系统使用Python作为主要编程语言,通过收集了8种常见的蔬菜图像数据集('土豆', '大白菜', '大葱', '莲藕', '菠菜', '西红柿', '韭菜', '黄瓜'),然后基于TensorFlow搭建卷积神经网络算法模型,通过多轮迭代训练最后得到一个识别精度较高的模型文件。在使用Django开发web网页端操作界面,实现用户上传一张蔬菜图片识别其名称。
9 0
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
|
8天前
|
机器学习/深度学习 数据采集 数据库
使用Python实现智能食品营养分析的深度学习模型
使用Python实现智能食品营养分析的深度学习模型
33 6
|
5天前
|
机器学习/深度学习 数据采集 TensorFlow
使用Python实现智能食品储存管理的深度学习模型
使用Python实现智能食品储存管理的深度学习模型
18 2
|
10天前
|
机器学习/深度学习 供应链 安全
使用Python实现智能食品供应链管理的深度学习模型
使用Python实现智能食品供应链管理的深度学习模型
40 3
|
14天前
|
机器学习/深度学习 数据采集 存储
使用Python实现智能农业灌溉系统的深度学习模型
使用Python实现智能农业灌溉系统的深度学习模型
59 6

热门文章

最新文章