深度学习中权重初始化的重要性

深度学习模型中的权重初始化经常被人忽略,而事实上这是非常重要的一个步骤,模型的初始化权重的好坏关系到模型的训练成功与否,以及训练速度是否快速,效果是否更好等等,这次我们专门来看看深度学习中的权重初始化问题。本文参考斋藤康毅的书籍《深度学习入门》。

首先,一般的权重初始化是用高斯分布生成的值再乘以0.01后得到的,也就是均值为0,标准差为0.01的一组随机数。模型会使用初始化之后的权重再进行训练。

np.random.randn(10, 100)*0.01

为什么权重值不能设置为全零,或者完全一样的值呢?因为在误差反向传播中,所有的权重值都会进行相同的更新,假设一个两层的神将网络,如果第一层和第二层的权重为0,那么第二层的神经元中全部输入相同的值,这意味着反向传播时,第二层的权重全部都会进行相同的更新,这样的话,权重都会更新为相同的值,也就是所有分量的权重都一样,因此损失将不会下降,也就无法进行学习了。

下面我们来看看进行不同的权重初始化后,网络激活值的变化。

假设有一个五层的神经网络,激活函数使用sigmoid函数,用直方图画出每层的激活值的数据分布:

import matplotlib.pyplot as pltdef sigmoid(x):return 1/(1+np.exp(-x))x = np.random.randn(1000, 100) # 1000个数据,每个数据100维
node_num = 100 # 隐藏层的节点数
hidden_layer_size = 5 # 隐藏层的数量
activations = {} #激活值的结果for i in range(hidden_layer_size):# i=0的时候先计算激活值,往后每次的输入值x都是上一次激活值结果if i!=0:x = activations[i-1]w = np.random.randn(node_num, node_num)*1 # 权重初始化z = np.dot(x,w)a = sigmoid(z) # sigmoid函数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))
plt.show()

目前我们的初始化权重是高斯分布的随机数,也就是均值为0,标准差为1,得到的结果如下图所示:

可以看到随着层数加深,越来越的多激活值集中到0和1,从而导致它们的导数接近0,因此偏向0和1的数据分布会造成反向传播中梯度值不断减小,从而产生“梯度消失”问题,特别是当神经网络的层数不断加深时,这种问题会更明显。

下面我们把初始化权重变成均值为0,标准差为0.01的高斯分布,得到的结果如下:

w = np.random.randn(node_num, node_num)*0.01 # 权重初始化

这个分布的问题是,随着神经网络层数的加深,越来越多的激活值趋于相同,如果这样下去的话,所有神经元输出的值都一样,那就是说再多的神经元效果都和一个神经元一样,因此会出现“表现力受限”问题,效果一样不好。比较理想的情况是,各层的激活值的分布都要求有适当的广度。为什么呢?因为通过在各层间传递多样性的数据,神经网络可以进行高效的学习。反过来,如果传递的是有所偏向的数据,就会出现梯度消失或者“表现力受限”的问题,导致学习可能无法顺利进行。

对于sigmoid激活值,我们采用Xavier初始值是比较理想的权重初始化方式。Xavier初始值就是,假设前一层的节点数是n,则初始权重使用均值为0,标准差为1/开根号(n)的高斯分布。

w = np.random.randn(node_num, node_num)*1/np.sqrt(n) # xavier权重初始化

可以看到,此时输出的激活值分布具有比较高的广度,所以sigmoid的表现力不受限制,可以进行高效的学习。

不过这种Xavier权重初始化比较适合以sigmoid为激活函数的神经网络。实际应用中,我们更多的是使用ReLU作为神经网络的激活函数,当使用ReLU函数的初始化权重比较适合采用何凯明提出的kaiming权重初始化方法,kaiming初始化其实就是在xavier的基础上,根号内部乘以了2。因为ReLU函数在小于0的时候,值为0,为了增加它的广度,所以乘以了2倍系数。

w = np.random.randn(node_num, node_num)*np.sqrt(2/node_num) # kaiming权重初始化

下面我们来看看这两种权重初始化的不同效果。

def relu(x):return np.maximum(x,0)x = np.random.randn(1000, 100) # 1000个数据,每个数据100维
node_num = 100 # 隐藏层的节点数
hidden_layer_size = 5 # 隐藏层的数量
activations = {} # 激活值的结果for i in range(hidden_layer_size):# i=0的时候先计算激活值,往后每次的输入值x都是上一次激活值结果if i!=0:x = activations[i-1]#w = np.random.randn(node_num, node_num)*0.01 # 一般权重初始化w = np.random.randn(node_num, node_num)/np.sqrt(node_num) # xavier权重初始化#w = np.random.randn(node_num, node_num)*np.sqrt(2/node_num) # kaiming权重初始化z = np.dot(x,w)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))
plt.show()

随着层数的假设,xavier权重初始化,会使得激活值越来越靠近0,从而出现梯度消失的问题。

w = np.random.randn(node_num, node_num)*np.sqrt(2/node_num) # kaiming权重初始化

当我们采用kaiming初始化的时候,结果如下: 

可以看到,不论层数多深,激活值总是均匀分布在0~1之间,因此适合通过反向传播进行学习。

下面我们比较一下采用(0,0.01)的高斯分布做权重初始化和用xavier做权重初始化在多层感知机上的训练效果。假设我有一个线性不可分数据集:

import numpy as np
import matplotlib.pyplot as plt# 构建非线性可分数据集
def create_dataset():np.random.seed(1)m = 400 # 数据量N = int(m/2) # 每一类数据的个数dim = 2 # 数据维度X = np.zeros((m,dim))Y = np.zeros((m,1), dtype='uint8')a = 4# 生成数据for j in range(2):ix = range(N*j,N*(j+1))t = np.linspace(j*3.12,(j+1)*3.12,N)+np.random.randn(N)*0.2r = a*np.sin(4*t) + np.random.randn(N)*0.2X[ix] = np.c_[r*np.sin(t), r*np.cos(t)]Y[ix] = jX = X.TY = Y.Treturn X,YX,Y = create_dataset()
X = X.T
Y = Y.T
print(Y.shape)
print(X.shape)
plt.scatter(X[:, 0], X[:, 1], c=Y, cmap=plt.cm.Paired) # 画出数据

生成的图像如下,我们需要对该数据集进行分类,无法用单一的线性函数去分类,因此可以用神经网络(多层感知机)去尝试分类。

下面我们用numpy编写一个多层感知机:

def net(X,Y):# 定义网络结构,X数据,Y标签n = X.shape[0]num_hidden = 4 # 隐藏层的神经元个数m = Y.shape[0]return (n, num_hidden, m)def initialize_parameters(n, num_hidden, m):# 初始化参数w1 = np.random.randn(num_hidden, n)*0.01 # 从输入到隐藏层权重,随机初始化#w1 = np.zeros((num_hidden, n))#w1 = np.random.randn(num_hidden, n)/np.sqrt(n) # xavier权重初始化b1 = np.zeros((num_hidden, 1)) # 从输入到隐藏层偏置,初始化为零w2 = np.random.randn(m, num_hidden)*0.01 # 从隐藏层到输出层权重,随机初始化#w2 = np.zeros((m, num_hidden))#w2 = np.random.randn(m, num_hidden)/np.sqrt(num_hidden) # xavier权重初始化b2 = np.zeros((m, 1)) # 从隐藏层到输出层权重,初始化为零parameters = {'w1':w1,'w2':w2,'b1':b1,'b2':b2}return parametersdef sigmoid(x): # sigmoid激活函数s = 1 / (1 + np.exp(-x))return sdef forward(X,parameters): # 前向运算w1 = parameters['w1']b1 = parameters['b1']w2 = parameters['w2']b2 = parameters['b2']z1 = np.dot(w1,X)+b1#print("z1.shape:",z1.shape)a1 = np.tanh(z1)z2 = np.dot(w2,a1)+b2#print("z2.shape:",z2.shape)a2 = sigmoid(z2)cache = {'z1':z1,'a1':a1,'z2':z2,'a2':a2}return cachedef backward_propagation(parameters, cache, X, Y): # 反向传播m = X.shape[1] w1 = parameters['w1']w2 = parameters['w2']b1 = parameters['b1']b2 = parameters['b2']a1 = cache['a1']a2 = cache['a2']# 反向传播,根据吴恩达教程的公式推导dz2 = a2-Ydw2 = 1/m*np.dot(dz2,a1.T)db2 = 1/m*np.sum(dz2, axis=1, keepdims=True)dz1 = np.dot(w2.T,dz2)*(a1-np.power(a1,2))dw1 = 1/m*np.dot(dz1,X.T)db1 = 1/m*np.sum(dz1, axis=1, keepdims=True)grads = {'dw1':dw1,'db1':db1,'dw2':dw2,'db2':db2}return gradsdef loss(z2,Y): # 损失值计算m = Y.shape[1] # 列向量的数量loss = np.log(z2)*Y + np.log(1-z2)*(1-Y)loss = -1/m * np.sum(loss)loss = np.squeeze(loss)return lossdef update_weights(parameters, grads, lr): # 权重更新w1 = parameters['w1']w2 = parameters['w2']b1 = parameters['b1']b2 = parameters['b2']dw1 = grads['dw1']dw2 = grads['dw2']db1 = grads['db1']db2 = grads['db2']# 参数更新w1 -= lr*dw1b1 -= lr*db1w2 -= lr*dw2b2 -= lr*db2parameters = {'w1':w1,'w2':w2,'b1':b1,'b2':b2}return parametersdef train(X, Y):x,n_h,y = net(X,Y) # 构建网络并获取到输入和输出节点数print("x:{},n_h:{},y:{}".format(x,n_h,y))parameters = initialize_parameters(x,n_h,y)w1 = parameters['w1']b1 = parameters['b1']w2 = parameters['w2']b2 = parameters['b2']for i in range(100000):cache = forward(X, parameters)a2 = cache['a2']cost = loss(a2,Y)grads = backward_propagation(parameters, cache, X, Y)parameters = update_weights(parameters, grads, lr=0.001)if i%10000==0:print("================",cost)return parametersX,Y = create_dataset()
parameters = train(X, Y)
print("w1:{},b1:{},w2:{},b2:{}".format(parameters['w1'],parameters['b1'],parameters['w2'],parameters['b2']))

当我们使用(0,0.01)的高斯分布做权重初始化后,训练损失值如下:

================ 0.6931125167719424
================ 0.6929599436150587
================ 0.6928419798609118
================ 0.6927533221282552
================ 0.6926665006259728
================ 0.6925442899224475
================ 0.6923418054740101
================ 0.6919987185837877
================ 0.6914315483776486
================ 0.6905487939721282

可以看到损失值几乎不下降,无法训练,如果使用xavier权重初始化后,训练损失值如下:

================ 0.7088135432785352
================ 0.6196813019938332
================ 0.5770935283638372
================ 0.5129738885023197
================ 0.46283119618617713
================ 0.4218237851915789
================ 0.3914602876997484
================ 0.3705175596789437
================ 0.354306018670427
================ 0.3409172900251636

可以看到,使用(0,0.01)的高斯分布做权重初始化训练很难进行下去,而使用xavier做权重初始化后,训练会非常快速,损失值平稳的下降。最终分类结果也比较不错:

其实,我们平时工作中倒是不用特别担心这一点,因为我们现在一般采用pytorch之类的深度学习框架进行代码编写,很少从头开始构建深度学习模型,pytorch之类的框架中会对权重一个默认的初始化,而且效果都不错。不过权重初始化依然是一个非常重要的概念,对于一些特殊的模型,可能需要我们自己手动做权重初始化才能更好的训练。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/831721.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

my-room-in-3d中的电脑,电视,桌面光带发光原理

1. my-room-in-3d中的电脑,电视,桌面光带发光原理 最近在github中,看到了这样的一个项目; 项目地址 我看到的时候,蛮好奇他这个光带时怎么做的。 最后发现,他是通过,加载一个 lightMap.jpg这个…

让我们一起来领悟带环问题的核心思想

一、带环的链表: 本质还是快慢指针来解决 关于如下一个带环链表怎么去找到他们想碰到的节点呢????我们可以想到快慢指针,第一个快点走,若是有环就会进入环,此时快指针每次走2步&am…

2.1 上海雷卯电子PLC

PLC(可编程逻辑控制器)像是工厂自动化系统的“大脑”,负责监控和控制各种生产过程。PLC 能够精确地协调各类设备的操作,实现生产流程的自动化和优化。通过编程,它可以根据不同的生产需求灵活调整控制逻辑,提…

可视化大屏应用场景:智慧安防,保驾护航

hello,我是大千UI工场,本篇分享智慧安防的大屏设计,关注我们,学习N多UI干货,有设计需求,我们也可以接单。 实时监控与预警 可视化大屏可以将安防系统中的监控画面、报警信息、传感器数据等实时展示在大屏上…

快速幂笔记

快速幂即为快速求出一个数的幂&#xff0c;这样可以避免TLE&#xff08;超时&#xff09;的错误。 传送门&#xff1a;快速幂模板 前置知识&#xff1a; 1) 又 2) 代码&#xff1a; #include <bits/stdc.h> using namespace std; int quickPower(int a, int b) {int…

TiDB系列之:部署TiDB集群常见报错解决方法

TiDB系列之&#xff1a;部署TiDB集群常见报错解决方法 一、部署TiDB集群二、unsupported filesystem ext3三、soft limit of nofile四、THP is enabled五、numactl not usable六、net.ipv4.tcp_syncookies 1七、service irqbalance not found,八、登陆TiDB数据库 一、部署TiDB…

搜款网商品列表API接口:高效获取时尚潮流商品的新途径

API接口概述 搜款网商品列表API接口允许开发者根据设定的条件&#xff08;如分类、价格区间、关键词等&#xff09;查询搜款网上的商品信息&#xff0c;并返回符合条件的商品列表。通过调用该接口&#xff0c;您可以轻松获取到搜款网上最新、最热的时尚商品数据&#xff0c;为…

批量视频剪辑新选择:一键式按照指定秒数分割视频并轻松提取视频中的音频,让视频处理更高效!

是否经常为大量的视频剪辑工作感到头疼&#xff1f;还在一个个手动分割、提取音频吗&#xff1f;现在&#xff0c;我们为你带来了一款全新的视频批量剪辑神器&#xff0c;让你轻松应对各种视频处理需求&#xff01; 首先&#xff0c;进入媒体梦工厂的主页面&#xff0c;并在板…

TFT显示屏偶发无法点亮

一. 问题描述 最近接到一起客诉&#xff1a;设备偶发显示屏不亮。复现现象时&#xff0c;发现有如下规律&#xff1a; 上电后&#xff0c;如果显示屏正常启动&#xff0c;则在使用过程中会一直正常。反之&#xff0c;如果显示屏一上电就无法显示&#xff0c;则一直黑屏。 是…

安卓硬件访问服务

安卓硬件访问服务 硬件访问服务通过硬件抽象层模块来为应用程序提供硬件读写操作。 由于硬件抽象层模块是使用C语言开发的&#xff0c; 而应用程序框架层中的硬件访问服务是使用Java语言开发的&#xff0c; 因此&#xff0c; 硬件访问服务必须通过Java本地接口&#xff08;Jav…

vector的使用

1.构造函数 void test_vector1() {vector<int> v; //无参的构造函数vector<int> v2(10, 0);//n个value构造&#xff0c;初始化为10个0vector<int> v3(v2.begin(), v2.end());//迭代器区间初始化,可以用其他容器的区间初始化vector<int> v4(v3); //拷贝…

Java项目:基于SSM框架实现的学院党员管理系统高校党员管理系统(ssm+B/S架构+源码+数据库+毕业论文+开题)

一、项目简介 本项目是一套基于SSM框架实现的学院党员管理系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、功能齐…

ConstraintLayout 特殊用法详解

1.使用百分比设置间距 app:layout_constraintHorizontal_bias"0.4" 水平偏移&#xff08;0-1&#xff09; app:layout_constraintVertical_bias"0.4" 垂直偏移 &#xff08;0-1&#xff09; <?xml version"1.0" encoding"u…

第18章 基于经验的测试技术

一、错误猜想法 &#xff08;一&#xff09;概念 错误推算法基于测试人员对以往测试项目中一些经验测试程序中的错误测试程序时&#xff0c;人们可根据经验或直觉推测程序中可能存在的各种错误&#xff0c;然后有针对性地编写检查这些错误的测试用例的方法 &#xff08;二&a…

使用MATLAB/Simulink点亮STM32开发板LED灯

使用MATLAB/Simulink点亮STM32开发板LED灯-笔记 一、STM32CubeMX新建工程二、Simulink 新建工程三、MDK导入生成的代码 一、STM32CubeMX新建工程 1. 打开 STM32CubeMX 软件&#xff0c;点击“新建工程”&#xff0c;选择中对应的型号 2. RCC 设置&#xff0c;选择 HSE(外部高…

LeetCode 69—— x 的平方根

阅读目录 1. 题目2. 解题思路一3. 代码实现一4. 解题思路二5. 代码实现二 1. 题目 2. 解题思路一 二分查找法&#xff0c;对于整数 i ∈ [ 0 , x ] i \in [0,x] i∈[0,x]&#xff0c;我们判断 i 2 i^2 i2 和 x x x 的关系&#xff0c;然后找到最后一个平方小于等于 x x x …

【 书生·浦语大模型实战营】作业(六):Lagent AgentLego 智能体应用搭建

【 书生浦语大模型实战营】作业&#xff08;六&#xff09;&#xff1a;Lagent & AgentLego 智能体应用搭建 &#x1f389;AI学习星球推荐&#xff1a; GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI方…

35.Docker-数据卷,目录挂载

注意&#xff1a;在容器内修改文件是不推荐的。 1.修改不方便&#xff0c;比如vi命令都无法使用。 2.容器内修改&#xff0c;没有日志记录的。 问题&#xff1a;那应该如何修改容器中的文件呢&#xff1f; 数据卷 volume是一个虚拟目录&#xff0c;指向宿主机文件系统中的…

如何把学浪的视频保存到手机

你是不是还在为无法将学浪的视频保存到手机而烦恼&#xff1f;别担心&#xff0c;接下来我将为大家分享一个非常实用的方法&#xff0c;让你轻松实现这一目标&#xff01; 下载学浪的工具我已经打包好了&#xff0c;有需要的自己下载一下 学浪下载工具打包链接&#xff1a;百…

一加12/11/10/Ace2/Ace3手机上锁回锁BL无限重启黑屏9008模式救砖

一加12/11/10/Ace2/Ace3手机官方都支持解锁BL&#xff0c;搞机的用户也比较多&#xff0c;相对于其他品牌来说&#xff0c;并没有做出限制&#xff0c;这也可能是搞机党最后的救命稻草。而厌倦了root搞机的用户&#xff0c;就习惯性回锁BL&#xff0c;希望彻底变回官方原来的样…