参数管理
一、前言
1、访问参数,用于调试、诊断和可视化。
2、参数初始化
3、在不同模型组件间共享参数
具有单隐藏层的多层感知机
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import torch from torch import nn # 定义模型 net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(), nn.Linear(8, 1)) '' ' rand:均匀分布 randn:正态分布 '' ' X = torch.rand(size=(2, 4)) print(X) net(X) # 输出结果 tensor([[0.2432, 0.4543, 0.8625, 0.7993], [0.5532, 0.1438, 0.1615, 0.7403]]) tensor([[-0.2514], [-0.1798]], grad_fn=<AddmmBackward>) |
二、参数访问——从已有模型中访问参数
1、当通过Sequential类定义模型时,我们可以通过索引来访问模型的任意层。
2、模型就像是一个列表,每层的参数都在其属性中
3、通过输出,我们可以知道这个全连接层包括两个参数,权重和偏置
4、两者都存储为单精度浮点数(float32)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | print(net[0]) print(net[0].state_dict()) # 可以发现,第二层为激活函数,所以没有state_dict() print(net[1]) print(net[2]) print(net[2].state_dict()) #输出结果 Linear(in_features=4, out_features=8, bias=True) OrderedDict([( 'weight' , tensor([[ 7.7448e-02, 4.7971e-01, -1.5936e-01, -1.3894e-01], [ 2.7179e-01, 3.9095e-01, -3.1510e-01, -4.0719e-01], [-6.3319e-02, -2.7208e-01, 1.8300e-01, -4.9577e-01], [-4.2502e-01, 1.1207e-01, -4.5425e-01, 4.4386e-03], [-7.7748e-02, -4.4779e-01, 4.7048e-01, 3.5624e-01], [-4.8872e-01, 2.6752e-01, -3.0867e-01, 1.1333e-01], [ 3.5990e-01, -8.8453e-05, 2.3274e-01, 1.1129e-01], [ 3.8350e-02, 4.9810e-01, 2.1889e-01, 1.3846e-01]])), ( 'bias' , tensor([ 0.2809, -0.0994, -0.1554, -0.2670, 0.3500, 0.3831, -0.3080, 0.2146]))]) ReLU() Linear(in_features=8, out_features=1, bias=True) OrderedDict([( 'weight' , tensor([[ 0.2860, 0.2800, -0.1412, 0.1409, -0.0144, -0.2962, 0.3177, -0.2654]])), ( 'bias' , tensor([-0.0774]))]) |
三、目标参数
1、每个参数都表示为参数(parameter)类的一个实例。要对参数执行任何操作,首先我们需要访问底层的数值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # 访问参数(底层数值) print(net[2].state_dict()) print(type(net[2].bias)) print( '------------' ) print(net[2].bias) # .data就是参数数值部分,因为参数包含数值部分和梯度。梯度用.grad访问 print(net[2].bias.data) #输出结果 OrderedDict([( 'weight' , tensor([[ 0.2860, 0.2800, -0.1412, 0.1409, -0.0144, -0.2962, 0.3177, -0.2654]])), ( 'bias' , tensor([-0.0774]))]) < class 'torch.nn.parameter.Parameter' > ------------ Parameter containing: tensor([-0.0774], requires_grad=True) tensor([-0.0774]) |
2、参数是复合的对象,包含值、梯度和额外信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # 参数是复合的对象,包含值、梯度和额外信息 # 由于没有调用反向传播,参数都处于初始状态(None) print(net[2].weight.grad) print(net[2].bias.grad) print(list(net[2].named_parameters())) net[2].weight.grad == None #输出结果 None None [( 'weight' , Parameter containing: tensor([[ 0.2860, 0.2800, -0.1412, 0.1409, -0.0144, -0.2962, 0.3177, -0.2654]], requires_grad=True)), ( 'bias' , Parameter containing: tensor([-0.0774], requires_grad=True))] True |
四、一次性访问所有参数
1、通过递归整个树来提取每个子块的参数
1 2 3 4 5 6 7 8 9 10 11 12 | print(*[(name, param.shape) for name, param in net[0].named_parameters()]) print( "分割" ) # 直接调用net.named_parameters():会把所有层的参数打印出来 # 由输出可知,第二层(序号为1)是激活函数,没有参数 print(*[(name, param.shape) for name, param in net.named_parameters()]) #输出结果 ( 'weight' , torch.Size([8, 4])) ( 'bias' , torch.Size([8])) 分割 ( '0.weight' , torch.Size([8, 4])) ( '0.bias' , torch.Size([8])) ( '2.weight' , torch.Size([1, 8])) ( '2.bias' , torch.Size([1])) |
2、另一种访问网络参数的方式
1 2 3 4 5 6 7 8 | # 单独访问,另一种是net[2].bias.data print(net[2].bias.data) net.state_dict()[ '2.bias' ].data #输出结果 tensor([-0.0774]) tensor([-0.0774]) |
五、从嵌套块收集参数
我们首先定义一个生成块的函数(可以说是块工厂),然后将这些块组合到更大的块中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # 生成块函数 def block1(): return nn.Sequential(nn.Linear(4, 8), nn.ReLU(), nn.Linear(8, 4), nn.ReLU()) # 将块组合到更大的块中 # 以f开头表示在字符串内支持大括号内的python表达式 def block2(): net = nn.Sequential() for i in range(4): # 在这里嵌套 # 调用block1()函数生成块,将其放进net块中 net.add_module(f 'block {i}' , block1()) return net rgnet = nn.Sequential(block2(), nn.Linear(4, 1)) rgnet(X) # 输出结果 tensor([[-0.1549], [-0.1549]], grad_fn=<AddmmBackward>) |
2、现在我们已经设计了网络,让我们看看是如何组织的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | print(rgnet) #输出结果 Sequential( (0): Sequential( (block 0): Sequential( (0): Linear(in_features=4, out_features=8, bias=True) (1): ReLU() (2): Linear(in_features=8, out_features=4, bias=True) (3): ReLU() ) (block 1): Sequential( (0): Linear(in_features=4, out_features=8, bias=True) (1): ReLU() (2): Linear(in_features=8, out_features=4, bias=True) (3): ReLU() ) (block 2): Sequential( (0): Linear(in_features=4, out_features=8, bias=True) (1): ReLU() (2): Linear(in_features=8, out_features=4, bias=True) (3): ReLU() ) (block 3): Sequential( (0): Linear(in_features=4, out_features=8, bias=True) (1): ReLU() (2): Linear(in_features=8, out_features=4, bias=True) (3): ReLU() ) ) (1): Linear(in_features=4, out_features=1, bias=True) ) |
3、因为层是分层嵌套的,我们也可以像通过嵌套列表索引一样访问它
1 2 3 4 5 | rgnet[0][1][0].bias.data #输出结果 tensor([ 0.4981, -0.1192, 0.2003, 0.1594, -0.4493, -0.4022, 0.2514, -0.3822]) |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)