本文通过实例代码讲解如何在PyTorch中管理神经网络参数,包括参数访问、多种初始化方法、自定义初始化以及参数绑定技术。所有代码可直接运行,适合深度学习初学者进阶学习。
1. 定义网络与参数访问
1.1 定义单隐藏层多层感知机
python
import torch
from torch import nn
# 定义单隐藏层多层感知机
net1 = nn.Sequential(
nn.Linear(4, 8), # 输入层4维,隐藏层8维
nn.ReLU(),
nn.Linear(8, 1) # 输出层1维
)
x = torch.rand(2, 4) # 随机生成2个4维输入向量
net1(x) # 前向传播
1.2 访问网络参数
python
# 访问第二层(索引2)的参数(权重和偏置)
print(net1[2].state_dict())
# 查看参数类型、数据和梯度
print(type(net1[2].bias)) # 类型:Parameter
print(net1[2].bias) # 参数值(含梯度信息)
print(net1[2].bias.data) # 参数数据(张量)
print(net1[2].bias.grad) # 梯度(未反向传播时为None)
1.3 批量访问参数
python
# 访问第一层的参数名称和形状
print(*[(name, param.shape) for name, param in net1[0].named_parameters()])
# 访问整个网络的参数
print(*[(name, param.shape) for name, param in net1.named_parameters()])
# 通过state_dict直接访问参数数据
print(net1.state_dict()['2.bias'].data)
2. 参数初始化方法
2.1 内置初始化
python
# 正态分布初始化权重,偏置置零
def init_normal(model):
if isinstance(model, nn.Linear):
nn.init.normal_(model.weight, mean=0, std=0.01)
nn.init.zeros_(model.bias)
net1.apply(init_normal)
print(net1[0].weight.data[0], net1[0].bias.data[0])
# 常数初始化(权重为1,偏置为0)
def init_constant(model):
if isinstance(model, nn.Linear):
nn.init.constant_(model.weight, 1)
nn.init.zeros_(model.bias)
net1.apply(init_constant)
print(net1[0].weight.data[0], net1[0].bias.data[0])
2.2 分层初始化
python
# 对第一层使用Xavier初始化,第二层使用常数42初始化
def xavier(model):
if isinstance(model, nn.Linear):
nn.init.xavier_uniform_(model.weight)
def init_42(model):
if isinstance(model, nn.Linear):
nn.init.constant_(model.weight, 42)
net1[0].apply(xavier)
net1[2].apply(init_42)
print(net1[0].weight.data[0])
print(net1[2].weight.data)
2.3 自定义初始化
python
# 自定义初始化:权重在[-10,10]均匀分布,并过滤绝对值小于5的值
def my_init(model):
if isinstance(model, nn.Linear):
print(f'init weight {model.weight.shape}')
nn.init.uniform_(model.weight, -10, 10)
model.weight.data *= (model.weight.abs() >= 5)
net1.apply(my_init)
print(net1[0].weight.data[:2]) # 显示前两行权重
3. 参数绑定与共享
3.1 直接修改参数
python
# 直接操作参数数据
net1[0].weight.data[:] += 1 # 所有权重+1
net1[0].weight.data[0, 0] = 42 # 修改特定位置权重
print(net1[0].weight.data[0]) # 输出第一行权重
3.2 参数共享
python
# 共享线性层参数
shared_layer = nn.Linear(8, 8)
net3 = nn.Sequential(
nn.Linear(4, 8), nn.ReLU(),
shared_layer, nn.ReLU(), # 第2层
shared_layer, nn.ReLU(), # 第4层(共享参数)
nn.Linear(8, 1)
)
# 验证参数共享
print(net3[2].weight.data[0] == net3[4].weight.data[0]) # 输出全True
net3[2].weight.data[0, 0] = 100
print(net3[2].weight.data[0] == net3[4].weight.data[0]) # 修改后仍为True
4. 嵌套网络结构
python
# 构建嵌套网络
def model1():
return nn.Sequential(
nn.Linear(4, 8), nn.ReLU(),
nn.Linear(8, 4), nn.ReLU()
)
def model2():
net = nn.Sequential()
for i in range(4):
net.add_module(f'model{i}', model1())
return net
rgnet = nn.Sequential(model2(), nn.Linear(4, 1))
print(rgnet) # 打印网络结构
总结
本文演示了PyTorch中参数管理的核心操作,包括:
-
通过
state_dict
和named_parameters
访问参数 -
使用内置初始化方法(正态分布、常数、Xavier)
-
自定义初始化逻辑
-
参数的直接修改与共享
-
复杂嵌套网络的定义
掌握这些技能可以更灵活地设计和优化神经网络模型。建议读者在实践中结合具体任务调整初始化策略,并注意参数共享时的梯度传播特性。
提示:以上代码需要在PyTorch环境中运行,建议使用Jupyter Notebook逐步调试以观察中间结果。