参数管理

一、前言

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])

  

posted @   小秦同学在上学  阅读(426)  评论(0编辑  收藏  举报
编辑推荐:
· 从 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)
点击右上角即可分享
微信分享提示