当前位置: 首页 > news >正文

深度学习参数初始化方法详解及代码实现

引言

在深度学习中,参数初始化是模型训练过程中至关重要的一环。良好的初始化方法能够帮助模型更快地收敛,避免梯度消失或梯度爆炸等问题。本文将详细介绍深度学习中常见的参数初始化方法,包括固定值初始化、随机初始化、Xavier初始化和He初始化,并通过PyTorch和TensorFlow的API示例展示如何在实际应用中使用这些方法。

1. 固定值初始化

固定值初始化是最简单的初始化方法,它将所有参数初始化为相同的固定值。

1.1 全零初始化

全零初始化将所有参数初始化为0。

PyTorch实现:

import torch
import torch.nn as nn# 定义一个线性层,使用全零初始化
linear_layer = nn.Linear(in_features=10, out_features=5)
# 手动将权重和偏置初始化为0
nn.init.zeros_(linear_layer.weight)  # 权重初始化为0
nn.init.zeros_(linear_layer.bias)    # 偏置初始化为0print("权重矩阵:\n", linear_layer.weight)
print("偏置向量:\n", linear_layer.bias)

TensorFlow实现: 

import tensorflow as tf# 定义一个全连接层,使用全零初始化
dense_layer = tf.keras.layers.Dense(units=5,input_shape=(10,),kernel_initializer=tf.keras.initializers.Zeros(),  # 权重初始化为0bias_initializer=tf.keras.initializers.Zeros()     # 偏置初始化为0
)# 创建一个输入张量查看初始化后的参数
input_tensor = tf.random.normal((1, 10))
output = dense_layer(input_tensor)print("权重矩阵:\n", dense_layer.weights[0].numpy())
print("偏置向量:\n", dense_layer.weights[1].numpy())

注意事项:

  • 全零初始化会导致所有神经元在第一次前向传播时输出相同的结果

  • 反向传播时梯度也会相同,导致所有参数更新相同

  • 实际上很少使用全零初始化,因为它会导致对称性问题

1.2 全1初始化

全1初始化将所有参数初始化为1。

PyTorch实现:

# 定义一个线性层,使用全1初始化
linear_layer = nn.Linear(in_features=10, out_features=5)
# 手动将权重和偏置初始化为1
nn.init.ones_(linear_layer.weight)  # 权重初始化为1
nn.init.ones_(linear_layer.bias)    # 偏置初始化为1print("权重矩阵:\n", linear_layer.weight)
print("偏置向量:\n", linear_layer.bias)

TensorFlow实现: 

# 定义一个全连接层,使用全1初始化
dense_layer = tf.keras.layers.Dense(units=5,input_shape=(10,),kernel_initializer=tf.keras.initializers.Ones(),  # 权重初始化为1bias_initializer=tf.keras.initializers.Ones()     # 偏置初始化为1
)# 创建一个输入张量查看初始化后的参数
input_tensor = tf.random.normal((1, 10))
output = dense_layer(input_tensor)print("权重矩阵:\n", dense_layer.weights[0].numpy())
print("偏置向量:\n", dense_layer.weights[1].numpy())

1.3 任意常数初始化

可以将参数初始化为任意指定的常数。

PyTorch实现:

# 定义一个线性层,使用常数初始化
linear_layer = nn.Linear(in_features=10, out_features=5)
# 手动将权重初始化为0.5,偏置初始化为-0.1
nn.init.constant_(linear_layer.weight, 0.5)  # 权重初始化为0.5
nn.init.constant_(linear_layer.bias, -0.1)   # 偏置初始化为-0.1print("权重矩阵:\n", linear_layer.weight)
print("偏置向量:\n", linear_layer.bias)

TensorFlow实现: 

# 定义一个全连接层,使用常数初始化
dense_layer = tf.keras.layers.Dense(units=5,input_shape=(10,),kernel_initializer=tf.keras.initializers.Constant(0.5),  # 权重初始化为0.5bias_initializer=tf.keras.initializers.Constant(-0.1)    # 偏置初始化为-0.1
)# 创建一个输入张量查看初始化后的参数
input_tensor = tf.random.normal((1, 10))
output = dense_layer(input_tensor)print("权重矩阵:\n", dense_layer.weights[0].numpy())
print("偏置向量:\n", dense_layer.weights[1].numpy())

2. 随机初始化

随机初始化是最常用的初始化方法之一,它可以打破对称性,使不同神经元学习到不同的特征。

2.1 均匀分布初始化

PyTorch实现:

# 定义一个线性层
linear_layer = nn.Linear(in_features=10, out_features=5)
# 使用均匀分布初始化权重,范围[-0.1, 0.1]
nn.init.uniform_(linear_layer.weight, a=-0.1, b=0.1)
# 偏置初始化为0
nn.init.zeros_(linear_layer.bias)print("权重矩阵:\n", linear_layer.weight)
print("权重范围:", linear_layer.weight.min().item(), "to", linear_layer.weight.max().item())
print("偏置向量:\n", linear_layer.bias)

TensorFlow实现: 

# 定义一个全连接层,使用均匀分布初始化
dense_layer = tf.keras.layers.Dense(units=5,input_shape=(10,),kernel_initializer=tf.keras.initializers.RandomUniform(minval=-0.1, maxval=0.1),  # 权重均匀分布bias_initializer=tf.keras.initializers.Zeros()  # 偏置初始化为0
)# 创建一个输入张量查看初始化后的参数
input_tensor = tf.random.normal((1, 10))
output = dense_layer(input_tensor)print("权重矩阵:\n", dense_layer.weights[0].numpy())
print("权重范围:", dense_layer.weights[0].numpy().min(), "to", dense_layer.weights[0].numpy().max())
print("偏置向量:\n", dense_layer.weights[1].numpy())

2.2 正态分布初始化

PyTorch实现:

# 定义一个线性层
linear_layer = nn.Linear(in_features=10, out_features=5)
# 使用正态分布初始化权重,均值0,标准差0.01
nn.init.normal_(linear_layer.weight, mean=0.0, std=0.01)
# 偏置初始化为0
nn.init.zeros_(linear_layer.bias)print("权重矩阵:\n", linear_layer.weight)
print("权重均值:", linear_layer.weight.mean().item())
print("权重标准差:", linear_layer.weight.std().item())
print("偏置向量:\n", linear_layer.bias)

TensorFlow实现: 

# 定义一个全连接层,使用正态分布初始化
dense_layer = tf.keras.layers.Dense(units=5,input_shape=(10,),kernel_initializer=tf.keras.initializers.RandomNormal(mean=0.0, stddev=0.01),  # 权重正态分布bias_initializer=tf.keras.initializers.Zeros()  # 偏置初始化为0
)# 创建一个输入张量查看初始化后的参数
input_tensor = tf.random.normal((1, 10))
output = dense_layer(input_tensor)print("权重矩阵:\n", dense_layer.weights[0].numpy())
print("权重均值:", dense_layer.weights[0].numpy().mean())
print("权重标准差:", dense_layer.weights[0].numpy().std())
print("偏置向量:\n", dense_layer.weights[1].numpy())

3. Xavier初始化

Xavier初始化(又称Glorot初始化)是由Xavier Glorot提出的,适用于Sigmoid和Tanh激活函数。它根据输入和输出的维度来缩放初始化范围,保持各层激活值的方差一致。

3.1 Xavier均匀分布初始化

PyTorch实现:

# 定义一个线性层
linear_layer = nn.Linear(in_features=10, out_features=5)
# 使用Xavier均匀分布初始化权重
nn.init.xavier_uniform_(linear_layer.weight, gain=1.0)
# gain 是一个缩放因子,用于调整初始化权重的范围,以适应不同的激活函数特性。它的作用是根据激活函数的非线性特性,调整初始化权重的分布范围,从而在训练初期保持各层激活值的方差稳定。
# 偏置初始化为0
nn.init.zeros_(linear_layer.bias)print("权重矩阵:\n", linear_layer.weight)
print("权重范围:", linear_layer.weight.min().item(), "to", linear_layer.weight.max().item())

TensorFlow实现: 

# 定义一个全连接层,使用Glorot均匀分布初始化(Xavier均匀分布)
dense_layer = tf.keras.layers.Dense(units=5,input_shape=(10,),kernel_initializer=tf.keras.initializers.GlorotUniform(),  # Xavier均匀分布bias_initializer=tf.keras.initializers.Zeros()  # 偏置初始化为0
)# 创建一个输入张量查看初始化后的参数
input_tensor = tf.random.normal((1, 10))
output = dense_layer(input_tensor)print("权重矩阵:\n", dense_layer.weights[0].numpy())
print("权重范围:", dense_layer.weights[0].numpy().min(), "to", dense_layer.weights[0].numpy().max())

3.2 Xavier正态分布初始化

PyTorch实现:

# 定义一个线性层
linear_layer = nn.Linear(in_features=10, out_features=5)
# 使用Xavier正态分布初始化权重
nn.init.xavier_normal_(linear_layer.weight, gain=1.0)
# 偏置初始化为0
nn.init.zeros_(linear_layer.bias)print("权重矩阵:\n", linear_layer.weight)
print("权重均值:", linear_layer.weight.mean().item())
print("权重标准差:", linear_layer.weight.std().item())

TensorFlow实现: 

# 定义一个全连接层,使用Glorot正态分布初始化(Xavier正态分布)
dense_layer = tf.keras.layers.Dense(units=5,input_shape=(10,),kernel_initializer=tf.keras.initializers.GlorotNormal(),  # Xavier正态分布bias_initializer=tf.keras.initializers.Zeros()  # 偏置初始化为0
)# 创建一个输入张量查看初始化后的参数
input_tensor = tf.random.normal((1, 10))
output = dense_layer(input_tensor)print("权重矩阵:\n", dense_layer.weights[0].numpy())
print("权重均值:", dense_layer.weights[0].numpy().mean())
print("权重标准差:", dense_layer.weights[0].numpy().std())

gain 参数详解:

Xavier初始化的核心思想是让每一层输出的方差与输入的方差保持一致。其初始化公式为:

  • 均匀分布:权重从  中采样,其中

    • fan_in:输入维度

    • fan_out:输出维度

  • 正态分布:权重从中采样,其中

gain 的作用
  • 默认值 gain=1.0:适用于线性激活函数(Identity)、Sigmoid 和 Tanh。

  • 调整 gain:针对不同激活函数,通过实验确定的缩放因子:

    • Sigmoidgain=1(默认值)

    • Tanhgain=5/3 ≈ 1.67(因为 Tanh 的梯度范围更大)

    • ReLU:虽然 Xavier 不推荐用于 ReLU,但若强行使用,可设 gain=sqrt(2) ≈ 1.414(实际更推荐 He 初始化)

为什么需要 gain

不同激活函数的梯度范围不同:

  • Sigmoid:梯度最大值为 0.25(在输入为 0 时)。

  • Tanh:梯度最大值为 1(在输入为 0 时)。

  • ReLU:梯度为 0 或 1。

gain 的作用是补偿激活函数对梯度的缩放效应,确保信号在前向传播和反向传播时保持稳定的方差。

 

4. He初始化

He初始化是由Kaiming He提出的,专门针对ReLU及其变体激活函数(如Leaky ReLU)的初始化方法。它考虑了ReLU激活函数会"杀死"一半神经元的特点,调整了初始化范围。

4.1 He均匀分布初始化

PyTorch实现:

# 定义一个线性层
linear_layer = nn.Linear(in_features=10, out_features=5)
# 使用He均匀分布初始化权重
nn.init.kaiming_uniform_(linear_layer.weight, a=0, mode='fan_in', nonlinearity='relu')
# 偏置初始化为0
nn.init.zeros_(linear_layer.bias)print("权重矩阵:\n", linear_layer.weight)
print("权重范围:", linear_layer.weight.min().item(), "to", linear_layer.weight.max().item())

TensorFlow实现: 

# 定义一个全连接层,使用He均匀分布初始化
dense_layer = tf.keras.layers.Dense(units=5,input_shape=(10,),kernel_initializer=tf.keras.initializers.HeUniform(),  # He均匀分布bias_initializer=tf.keras.initializers.Zeros()  # 偏置初始化为0
)# 创建一个输入张量查看初始化后的参数
input_tensor = tf.random.normal((1, 10))
output = dense_layer(input_tensor)print("权重矩阵:\n", dense_layer.weights[0].numpy())
print("权重范围:", dense_layer.weights[0].numpy().min(), "to", dense_layer.weights[0].numpy().max())

4.2 He正态分布初始化

PyTorch实现:

# 定义一个线性层
linear_layer = nn.Linear(in_features=10, out_features=5)
# 使用He正态分布初始化权重
nn.init.kaiming_normal_(linear_layer.weight, a=0, mode='fan_in', nonlinearity='relu')
# 偏置初始化为0
nn.init.zeros_(linear_layer.bias)print("权重矩阵:\n", linear_layer.weight)
print("权重均值:", linear_layer.weight.mean().item())
print("权重标准差:", linear_layer.weight.std().item())

TensorFlow实现: 

# 定义一个全连接层,使用He正态分布初始化
dense_layer = tf.keras.layers.Dense(units=5,input_shape=(10,),kernel_initializer=tf.keras.initializers.HeNormal(),  # He正态分布bias_initializer=tf.keras.initializers.Zeros()  # 偏置初始化为0
)# 创建一个输入张量查看初始化后的参数
input_tensor = tf.random.normal((1, 10))
output = dense_layer(input_tensor)print("权重矩阵:\n", dense_layer.weights[0].numpy())
print("权重均值:", dense_layer.weights[0].numpy().mean())
print("权重标准差:", dense_layer.weights[0].numpy().std())

参数解释:

  • a:Leaky ReLU的负斜率(当使用Leaky ReLU时设置)

  • mode

    • 'fan_in':保持前向传播时每层激活值的方差一致(默认)

    • 'fan_out':保持反向传播时梯度的方差一致

  • nonlinearity:指定激活函数类型,如'relu'或'leaky_relu'

5. 总结与选择指南

5.1 各种初始化方法对比

初始化方法适用场景优点缺点
全零初始化几乎不使用(有时被用来初始化偏置)简单导致对称性问题
随机初始化简单网络打破对称性可能梯度消失或爆炸
Xavier初始化Sigmoid/Tanh激活函数保持激活值方差一致不适用于ReLU系列激活函数
He初始化ReLU/Leaky ReLU等激活函数针对ReLU优化,避免梯度消失对Sigmoid/Tanh效果一般

5.2 选择指南

  1. 激活函数类型决定初始化方法

    • 使用Sigmoid或Tanh:优先选择Xavier初始化

    • 使用ReLU或其变体:优先选择He初始化

  2. 实践建议

    • 默认情况下,使用框架推荐的默认初始化方法(通常是Xavier或He的变体)

    • 对于特别深的网络,可能需要尝试不同的初始化方法

    • 可以结合批量归一化(BatchNorm)来减少对初始化的敏感度

  3. 其他注意事项

    • 偏置通常初始化为0

    • 对于RNN/LSTM等循环网络,可能需要特殊的正交初始化

    • 对于嵌入层,可以使用正态分布或均匀分布初始化

5.3 完整模型初始化示例(PyTorch)

import torch
import torch.nn as nnclass MyModel(nn.Module):def __init__(self, input_dim, hidden_dim, output_dim):super(MyModel, self).__init__()self.fc1 = nn.Linear(input_dim, hidden_dim)self.fc2 = nn.Linear(hidden_dim, hidden_dim)self.fc3 = nn.Linear(hidden_dim, output_dim)self.relu = nn.ReLU()# 初始化权重self._initialize_weights()def _initialize_weights(self):# 使用He初始化(针对ReLU)for m in self.modules():if isinstance(m, nn.Linear):nn.init.kaiming_normal_(m.weight, mode='fan_in', nonlinearity='relu')if m.bias is not None:nn.init.zeros_(m.bias)def forward(self, x):x = self.relu(self.fc1(x))x = self.relu(self.fc2(x))x = self.fc3(x)return x# 创建模型实例
model = MyModel(input_dim=100, hidden_dim=64, output_dim=10)# 打印第一层的权重统计信息
print("FC1权重均值:", model.fc1.weight.mean().item())
print("FC1权重标准差:", model.fc1.weight.std().item())

5.4 完整模型初始化示例(TensorFlow/Keras) 

import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Densedef create_model(input_dim, hidden_dim, output_dim):model = Sequential([Dense(hidden_dim, input_shape=(input_dim,), kernel_initializer='he_normal',  # He初始化bias_initializer='zeros',        # 偏置初始化为0activation='relu'),Dense(hidden_dim,kernel_initializer='he_normal',bias_initializer='zeros',activation='relu'),Dense(output_dim,kernel_initializer='he_normal',bias_initializer='zeros')])return model# 创建模型实例
model = create_model(input_dim=100, hidden_dim=64, output_dim=10)# 打印模型摘要
model.summary()# 获取第一层的权重
weights, biases = model.layers[0].get_weights()
print("\nFC1权重均值:", weights.mean())
print("FC1权重标准差:", weights.std())

结语

参数初始化在深度学习中扮演着至关重要的角色,良好的初始化可以加速模型收敛,提高训练稳定性。通过本文的介绍,希望读者能够理解不同初始化方法的原理和适用场景,并能够在实际项目中正确应用这些方法。记住,没有绝对最好的初始化方法,需要根据具体的网络结构和激活函数来选择最合适的初始化策略。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

http://www.dtcms.com/a/273380.html

相关文章:

  • 深度学习×第7卷:参数初始化与网络搭建——她第一次挑好初始的重量
  • ZW3D 二次开发-创建椭球体
  • 灰度发布策略制定方案时可以参考的几个维度
  • 递推+高精度加法 P1255 数楼梯
  • apt -y参数的含义
  • 计算机视觉 之 数字图像处理基础(一)
  • Kubernetes 1.23.6 kube-scheduler 默认打分和排序机制详解
  • 多商户商城系统源码选型指南:开源 vs 定制,哪种更适合?
  • 救回多年未用kubeadm搭建的kubernetes集群
  • 5. isaac sim4.2 教程-Core API-操作机械臂
  • 用黑盒测试与白盒测试,读懂专利审查的 “双重关卡”​​
  • K8S的CNI之calico插件升级至3.30.2
  • 深度学习中的 Seq2Seq 模型与注意力机制
  • 解释sync.WaitGroup的用途和工作原理。在什么情况下应该使用它?
  • 时间显示 蓝桥云课Java
  • Android ViewBinding 使用与封装教程​​
  • Netron的基本使用介绍
  • UNet改进(20):融合通道-空间稀疏注意力的医学图像分割模型
  • 客户频繁问询项目进度,如何提高响应效率
  • Java 中的多线程实现方式
  • Spring AI 系列之八 - MCP Server
  • NFS文件存储及部署论坛(小白的“升级打怪”成长之路)
  • (鱼书)深度学习入门2:手搓感知机
  • PostgreSQL创建新实例并指定目录
  • 下一代防火墙混合模式部署
  • Jupyter介绍
  • MySQL事务实现原理
  • SpringCloud系列 - 分布式锁(八)
  • html页面,当鼠标移开A字标就隐藏颜色框
  • Spring Boot项目中大文件上传的优化策略与实践