本文目录:
前言:前一篇文章我们讲解了人工神经网络的激活函数,接下来讲解参数初始化和损失函数。
一、参数初始化
(一)概念
我们在构建网络之后,网络中的参数是需要初始化的。参数初始化是神经网络训练的第一步,直接影响模型的收敛性、训练速度和最终性能。我们需要初始化的参数主要有权重和偏置,偏置一般初始化为0即可,而对权重的初始化则会更加重要。
参数初始化的设置:
- 防止梯度消失或爆炸:初始权重值过大或过小会导致梯度在反向传播中指数级增大或缩小;
- 提高收敛速度:合理的初始化使得网络的激活值分布适中,有助于梯度高效更新;
- 保持对称性破除:权重的初始化需要打破对称性,否则网络的学习能力会受到限制。
(二)常见参数初始化函数
1.均匀分布初始化
权重参数初始化从区间均匀随机取值,默认区间为(0,1)。如下图: 其中d为神经元的输入数量。
2.正态分布初始化
随机初始化从均值为0,标准差是1的高斯分布中取样,使用一些很小的值对参数W进行初始化。
- 优点:能有效打破对称性。
- 缺点:随机选择范围不当可能导致梯度问题。
- 适用场景:浅层网络或低复杂度模型。隐藏层1-3层,总层数不超过5层。
-
3.全0初始化
将神经网络中的所有权重参数初始化为0。
- 优点:实现简单。
- 缺点:无法打破对称性,所有神经元更新方向相同,无法有效训练。
- 适用场景:几乎不使用,仅用于偏置项的初始化。
4.全1初始化
将神经网络中的所有权重参数初始化为1。
- 优点:实现简单。
- 缺点
- 无法打破对称性,所有神经元更新方向相同,无法有效训练;
- 会导致激活值在网络中呈指数增长,容易出现梯度爆炸。
- 适用场景
- 测试或调试:比如验证神经网络是否能正常前向传播和反向传播;
- 特殊模型结构:某些稀疏网络或特定的自定义网络中可能需要手动设置部分参数为1;
- 偏置初始化:偶尔可以将偏置初始化为小的正值(如 0.1),但很少用1作为偏置的初始值。
5.固定值初始化
将神经网络中的所有权重参数初始化为某个固定值。
- 优点:实现简单。
- 缺点
- 无法打破对称性,所有神经元更新方向相同,无法有效训练;
- 初始权重过大或过小可能导致梯度爆炸或梯度消失。
- 适用场景
- 测试或调试。
6.kaiming初始化
kaiming初始化其实也叫做HE初始化:专为ReLU和其变体设计,考虑到ReLU激活函数的特性,对输入维度进行缩放;
- HE初始化分为正态分布的HE初始化、均匀分布的HE初始化。
-
- 正态分布的he初始化
- w权重值从均值为0, 标准差为std中随机采样,std =
sqrt(2 / fan_in)
; - std值越大,w权重值离均值0分布相对较广,计算得到的内部状态值有较大的正值或负值。
- w权重值从均值为0, 标准差为std中随机采样,std =
- 均匀分布的he初始化
- 它从[-limit,limit] 中的均匀分布中抽取样本,
limit
是sqrt(6 / fan_in)
- 它从[-limit,limit] 中的均匀分布中抽取样本,
fan_in
输入神经元的个数,当前层接受的来自上一层的神经元的数量。简单来说,就是当前层接收多少个输入
- 正态分布的he初始化
- 优点:适合 ReLU,能保持梯度稳定
- 缺点:对非 ReLU 激活函数效果一般
- 适用场景:深度网络(10层及以上),使用 ReLU、Leaky ReLU 激活函数
7.xavier初始化
xavier初始化也叫做Glorot初始化:根据网络输入和输出的维度自动选择权重范围,使输入和输出的方差相同;
xavier初始化分为正态分布的xavier初始化、均匀分布的xavier初始化。
-
- 正态化的Xavier初始化
- w权重值从均值为0, 标准差为std中随机采样,std =
sqrt(2 / (fan_in + fan_out))
; - std值越小,w权重值离均值0分布相对集中,计算得到的内部状态值有较小的正值或负值。
- w权重值从均值为0, 标准差为std中随机采样,std =
- 均匀分布的Xavier初始化
- [-limit,limit] 中的均匀分布中抽取样本, limit 是
sqrt(6 / (fan_in + fan_out))
;
- [-limit,limit] 中的均匀分布中抽取样本, limit 是
- fan_in 是输入神经元个数,当前层接受的来自上一层的神经元的数量。简单来说,就是当前层接收多少个输入;
- fan_out 是输出神经元个数,当前层输出的神经元的数量,也就是当前层会传递给下一层的神经元的数量。简单来说,就是当前层会产生多少个输出。
- 正态化的Xavier初始化
优点:适用于Sigmoid、Tanh 等激活函数,解决梯度消失问题。
缺点:对 ReLU 等激活函数表现欠佳。
适用场景:深度网络(10层及以上),使用 Sigmoid 或 Tanh 激活函数。
import torch.nn as nn
# 1. 均匀分布随机初始化
def test01():
linear = nn.Linear(5, 3)
# 从0-1均匀分布产生参数
nn.init.uniform_(linear.weight)
nn.init.uniform_(linear.bias)
print(linear.weight.data)
# 2. 固定初始化
def test02():
linear = nn.Linear(5, 3)
nn.init.constant_(linear.weight, 5)
print(linear.weight.data)
# 3. 全0初始化
def test03():
linear = nn.Linear(5, 3)
nn.init.zeros_(linear.weight)
print(linear.weight.data)
# 4. 全1初始化
def test04():
linear = nn.Linear(5, 3)
nn.init.ones_(linear.weight)
print(linear.weight.data)
# 5. 正态分布随机初始化
def test05():
linear = nn.Linear(5, 3)
nn.init.normal_(linear.weight, mean=0, std=1)
print(linear.weight.data)
# 6. kaiming 初始化
def test06():
# kaiming 正态分布初始化
linear = nn.Linear(5, 3)
nn.init.kaiming_normal_(linear.weight, nonlinearity='relu')
print(linear.weight.data)
# kaiming 均匀分布初始化
linear = nn.Linear(5, 3)
nn.init.kaiming_uniform_(linear.weight, nonlinearity='relu')
print(linear.weight.data)
# 7. xavier 初始化
def test07():
# xavier 正态分布初始化
linear = nn.Linear(5, 3)
nn.init.xavier_normal_(linear.weight)
print(linear.weight.data)
# xavier 均匀分布初始化
linear = nn.Linear(5, 3)
nn.init.xavier_uniform_(linear.weight)
print(linear.weight.data)
(三)如何选择参数初始化
二、神经网络搭建及训练
(一)构建分析
在pytorch中定义深度神经网络其实就是层堆叠的过程,继承自nn.Module,实现两个方法:
__init__
方法中定义网络中的层结构,主要是全连接层,并进行初始化- forward方法,在调用神经网络模型对象的时候,底层会自动调用该函数。该函数中为初始化定义的layer传入数据,进行前向传播等。
接下来我们来构建如下图所示的神经网络模型:
编码设计如下:
- 第1个隐藏层:权重初始化采用标准化的xavier初始化, 激活函数使用sigmoid;
- 第2个隐藏层:权重初始化采用标准化的He初始化,激活函数采用relu;
- out输出层采用softmax做数据归一化。
(二)代码实现
1.构造神经网络模型代码
import torch
from torch.nn import Module,Linear
class Net(Module):
def __init__(self,*args, **kwargs):
super(Net, self).__init__()
self.fc1 = Linear(3, 5)
self.fc2 = Linear(5, 2)
self.out=Linear(2,2)
torch.nn.init.xavier_uniform_(self.fc1.weight)
torch.nn.init.kaiming_normal_(self.fc2.weight)
torch.nn.init.zeros_(self.fc1.bias)
torch.nn.init.zeros_(self.fc2.bias)
def forward(self, x):
x = torch.sigmoid(self.fc1(x))
x = torch.relu(self.fc2(x))
x = torch.softmax(self.out(x),dim=0) #dim=0,按列求和;dim=1,按行求和
return x
2.训练神经网络模型代码
model=Net()
torch.manual_seed(1)
data=torch.randn(4,3)
data1=torch.randint(0,10,(4,3)).float()
# data2=torch.randint(0,10,(4,3)) #不是浮点型,报错:神经网络的权重和计算默认使用浮点型(如 torch.float32)
print(data)
print(data1)
print(model(data))
print(model(data1))
# print(model(data2)) #报错,因为输入数据类型不一致
#summary:查看模型参数
今日分享到此结束。