当前位置:   article > 正文

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

动手学深度学习(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])
"""
表明第三个和第五个神经网络层的参数是绑定的。 它们不仅值相等,而且由相同的张量表示。
因此,如果我们改变其中一个参数,另一个参数也会改变。
这里有一个问题:当参数绑定时,梯度会发生什么情况?
答案是由于模型参数包含梯度,因此在反向传播期间第二个隐藏层 (即第三个神经网络层)
和第三个隐藏层(即第五个神经网络层)的梯度会加在一起。
"""
  • 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
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号