• 动手学深度学习(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=)
    """
    
    #当通过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)
    """
    
    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=) 
    """
    
    #直接设置参数
    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])
    """
    表明第三个和第五个神经网络层的参数是绑定的。 它们不仅值相等,而且由相同的张量表示。
    因此,如果我们改变其中一个参数,另一个参数也会改变。
    这里有一个问题:当参数绑定时,梯度会发生什么情况?
    答案是由于模型参数包含梯度,因此在反向传播期间第二个隐藏层 (即第三个神经网络层)
    和第三个隐藏层(即第五个神经网络层)的梯度会加在一起。
    """
    
  • 相关阅读:
    解决Flutter应用程序的兼容性问题
    [游戏开发][Unity] UGUI上使用 ParticleSystem支持排序渲染
    Apifox能否替代Postman?
    adb手机调试常用命令
    React报错之组件不能作为JSX组件使用
    数据治理:误区梳理篇
    【论文阅读】Anchor-Free Person Search
    基于TextRank算法生成文本摘要有代码+数据+可直接运行
    【文档+源码+调试讲解】国风彩妆网站springboot
    【C++】面向对象编程(四)派生类
  • 原文地址:https://blog.csdn.net/weixin_46560570/article/details/139883961