动手学深度学习(Pytorch版)代码实践 -卷积神经网络-15参数管理

15参数管理

import torch
from torch import nn

#具有单隐藏层的多层感知机
net = nn.Sequential(nn.Linear(4,8), nn.ReLU(), nn.Linear(8,1))
X = torch.rand(2,4)
print(net(X))
"""
tensor([[-0.4613],
        [-0.2691]], grad_fn=<AddmmBackward>)
"""

#当通过Sequential类定义模型时, 我们可以通过索引来访问模型的任意层。
print(net[2].state_dict())
"""
OrderedDict([('weight', tensor([[-0.0274, -0.1189,  0.2617, -0.1651, 
-0.2382, -0.2734, -0.0991,  0.1985]])), ('bias', tensor([-0.1222]))])

首先,这个全连接层包含两个参数,分别是该层的权重和偏置。 
两者都存储为单精度浮点数float32。 
注意: 参数名称允许唯一标识每个参数,即使在包含数百个层的网络中也是如此
"""

#目标参数
print(type(net[2].bias))
print(net[2].bias)
print(net[2].bias.data)
"""
<class 'torch.nn.parameter.Parameter'>
Parameter containing:
tensor([-0.1222], requires_grad=True)
tensor([-0.1222)
"""

#访问每个参数的梯度
#由于我们还没有调用反向传播,所以参数的梯度处于初始状态
print(net[2].weight.grad == None)
# True

#一次性访问所有参数
print(*[(name, param.shape) for name, param in net.named_parameters()])
print(*[(name, param.shape) for name, param in net[0].named_parameters()])
"""
('0.weight', torch.Size([8, 4])) ('0.bias', torch.Size([8])) ('2.weight', torch.Size([1, 8])) ('2.bias', torch.Size([1]))
('weight', torch.Size([8, 4])) ('bias', torch.Size([8]))
"""

#另一种访问网络参数的方式
print(net.state_dict()['2.bias'].data)
# tensor([-0.1222)

#从嵌套块收集参数
def block1():
    return nn.Sequential(nn.Linear(4, 8), nn.ReLU(),
                         nn.Linear(8, 4), nn.ReLU())

def block2():
    net = nn.Sequential()
    for i in range(2):
        # 在这里嵌套
        net.add_module(f'block {i}', block1())
    return net

rgnet = nn.Sequential(block2(), nn.Linear(4, 1))
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()
    )
  )
  (1): Linear(in_features=4, out_features=1, bias=True)
)
"""
#因为层是分层嵌套的,所以我们也可以像通过嵌套列表索引一样访问它们
print(rgnet[0][1][0].bias.data)

#参数初始化
#首先调用内置的初始化器
#将所有权重参数初始化为标准差为0.01的高斯随机变量, 且将偏置参数设置为0。
# net = nn.Sequential(nn.Linear(4,8), nn.ReLU(), nn.Linear(8,1))
def init_normal(m):
    if type(m) == nn.Linear:
        nn.init.normal_(m.weight, mean=0, std=0.01)
        nn.init.zeros_(m.bias)
    
net.apply(init_normal)
#前面定义的init_normal函数应用于模型net中的每一层。
#apply方法会递归地遍历模型的所有子模块,并对每一个子模块调用init_normal函数。

print(net[0].weight.data[0])
print(net[0].bias.data[0])
"""
tensor([-0.0055,  0.0028, -0.0095, -0.0059])
tensor(0.)
打印了模型net第一个全连接层的第一行权重和第一个偏置的值。
这里net[0]指的是net中的第一个子模块,也就是第一个全连接层nn.Linear(4, 8)。
通过.weight.data[0]访问权重的第一行,通过.bias.data[0]访问偏置的第一个元素。
"""

## net = nn.Sequential(nn.Linear(4,8), nn.ReLU(), nn.Linear(8,1))
def my_init(m):
    if type(m) == nn.Linear:
        #m.named_parameters() 返回该层的所有参数(名称和参数本身)
        print("Init", *[(name, param.shape) 
                        for name , param in m.named_parameters()][0])
        #nn.init.uniform_ 函数将权重 m.weight 初始化为均匀分布在 -10 到 10 之间的值。
        nn.init.uniform_(m.weight, -10, 10)
        m.weight.data = m.weight.data * ( m.weight.data.abs() >= 5)

net.apply(my_init)
print(net[0].weight[:2])
#从权重矩阵中提取前两行,即形状为 (2, 4) 的子矩阵
"""
tensor([[ 6.7495, -0.0000,  0.0000,  0.0000],
        [-0.0000, -7.6540, -0.0000,  0.0000]], grad_fn=<SliceBackward>) 
"""

#直接设置参数
net[0].weight.data[:] += 1
print(net[0].weight.data[:])
"""
tensor([[ 7.7495,  1.0000,  1.0000,  1.0000],
        [ 1.0000, -6.6540,  1.0000,  1.0000],
        [10.3503,  1.0000,  9.9864,  1.0000],
        [ 6.7700,  1.0000,  8.1017, -4.6532],
        [-4.0572,  1.0000,  1.0000,  1.0000],
        [ 1.0000,  1.0000,  1.0000, 10.8596],
        [ 1.0000, 10.9898,  7.0317, -4.4541],
        [-5.0554,  1.0000,  1.0000,  1.0000]])
"""
net[0].weight.data[0, 0] = 42
print(net[0].weight.data[0])
#tensor([42.,  1.,  1.,  1.])

# 参数绑定
# 有时我们希望在多个层间共享参数: 
# 我们可以定义一个稠密层,然后使用它的参数来设置另一个层的参数。

# 我们需要给共享层一个名称,以便可以引用它的参数
shared = nn.Linear(8, 8)
net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(),
                    shared, nn.ReLU(),
                    shared, nn.ReLU(),
                    nn.Linear(8, 1))
net(X)

# 检查参数是否相同
print(net[2].weight.data[0] == net[4].weight.data[0])
net[2].weight.data[0, 0] = 100
# 确保它们实际上是同一个对象,而不只是有相同的值
print(net[2].weight.data[0] == net[4].weight.data[0])

#tensor([True, True, True, True, True, True, True, True])
#tensor([True, True, True, True, True, True, True, True])
"""
表明第三个和第五个神经网络层的参数是绑定的。 它们不仅值相等,而且由相同的张量表示。
因此,如果我们改变其中一个参数,另一个参数也会改变。
这里有一个问题:当参数绑定时,梯度会发生什么情况?
答案是由于模型参数包含梯度,因此在反向传播期间第二个隐藏层 (即第三个神经网络层)
和第三个隐藏层(即第五个神经网络层)的梯度会加在一起。
"""
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@李思成

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值