动手学深度学习(pytorch)学习记录19-参数管理[学习记录]

news2024/12/28 3:34:19

文章目录

  • 参数访问
    • 目标参数
    • 一次性访问所有参数
    • 从嵌套块收集参数
  • 参数初始化
    • 内置初始化
    • 自定义初始化
  • 参数绑定
  • 延后初始化

本节内容:
访问参数,用于调试、诊断和可视化;
参数初始化;
在不同模型组件间共享参数;
延后初始化。

# 单隐藏层的多层感知机
import torch
from torch import nn

net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(), nn.Linear(8, 1))
X = torch.rand(size=(2, 4))
net(X)

在这里插入图片描述

参数访问

通过Sequential类定义的模型可以通过索引来访问模型的任意层。 模型就像一个列表一样,每层的参数都在其属性中。 如下所示,检查第二个全连接层的参数。

print(net[2].state_dict())
OrderedDict([('weight', tensor([[ 0.0143, -0.1299, -0.0290,  0.2700,  0.2086, -0.3533,  0.0657,  0.2856]])), ('bias', tensor([-0.1287]))])

通过输出可知:全连接层包含两个参数,分别是该层的权重和偏置。
每个参数都表示为参数类的一个实例。 要对参数执行任何操作,首先我们需要访问底层的数值。

目标参数

print(type(net[2].bias))
print(net[2].bias)
print(net[2].bias.data)
<class 'torch.nn.parameter.Parameter'>
Parameter containing:
tensor([-0.1287], requires_grad=True)
tensor([-0.1287])

参数是复合的对象,包含值、梯度和额外信息。
在上面这个网络中,由于我没有调用反向传播,所以参数的梯度处于初始状态。

net[2].weight.grad == None
True

一次性访问所有参数

当我们需要对所有参数执行操作时,逐个访问它们可能会很麻烦。 当我们处理更复杂的块(例如,嵌套块)时,情况可能会变得特别复杂, 因为我们需要递归整个树来提取每个子块的参数。 下面,演示来访问第一个全连接层的参数和访问所有层。

print(*[(name, param.shape) for name, param in net[0].named_parameters()]) # *应该是用于解包操作,对比有无*,发现删去*后,输出或多一个[]
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]))

另一种访问网络参数的方法

net.state_dict()['2.bias'].data
tensor([-0.1287])

从嵌套块收集参数

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(4):
        # 在这里嵌套
        net.add_module(f'block {i}', block1())
# 用 add_module 方法将 block1 函数返回的 nn.Sequential 对象添加到 net 容器中。每次迭代都会添加一个新的模块,并且每个模块都有一个唯一的名称(例如 'block 0', 'block 1', ...)
    return net

rgnet = nn.Sequential(block2(), nn.Linear(4, 1))
rgnet(X)
tensor([[0.1559],
        [0.1559]], grad_fn=<AddmmBackward0>)

查看一下网络结构

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

因为层是分层嵌套的,所以也可以像通过嵌套列表索引一样访问它们。 下面,访问第一个主要的块中、第二个子块的第一层的偏置项。

rgnet[0][1][0].bias.data
tensor([-0.4003,  0.3388,  0.2142,  0.3416, -0.0377,  0.3460, -0.1539,  0.0325])

参数初始化

PyTorch的nn.init模块提供了多种预置初始化方法。

内置初始化

首先调用内置的初始化器。 下面的代码将所有权重参数初始化为标准差为0.01的高斯随机变量, 且将偏置参数设置为0。

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)
net[0].weight.data[0], net[0].bias.data[0]
(tensor([0.0106, 0.0016, 0.0035, 0.0076]), tensor(0.))

还可以将所有参数初始化为给定的常数,比如初始化为6

def init_constant(m):
    if type(m) == nn.Linear:
        nn.init.constant_(m.weight, 6)
        nn.init.zeros_(m.bias)
net.apply(init_constant)
net[0].weight.data[0], net[0].bias.data[0]
(tensor([6., 6., 6., 6.]), tensor(0.))

还可以对某些块应用不同的初始化方法。
比如使用Xavier初始化方法初始化第一个神经网络层, 然后将第三个神经网络层初始化为常量值42。
(泰库辣)

def init_xavier(m):
    if type(m) == nn.Linear:
        nn.init.xavier_uniform_(m.weight)
def init_42(m):
    if type(m) == nn.Linear:
        nn.init.constant_(m.weight, 42)

net[0].apply(init_xavier)
net[2].apply(init_42)
print(net[0].weight.data[0])
print(net[2].weight.data)
tensor([-0.5471,  0.4637, -0.2951,  0.1913])
tensor([[42., 42., 42., 42., 42., 42., 42., 42.]])

自定义初始化

def my_init(m):
    if type(m) == nn.Linear:
        print("Init", *[(name, param.shape)
                        for name, param in m.named_parameters()][0])
        nn.init.uniform_(m.weight, -10, 10)
        m.weight.data *= m.weight.data.abs() >= 5
        # 将所有权重的绝对值小于5的权重设置为0,而保持权重的绝对值大于或等于5的权重不变

net.apply(my_init)
net[0].weight[:2]
Init weight torch.Size([8, 4])
Init weight torch.Size([1, 8])

tensor([[ 5.1561, -0.0000,  5.4036,  5.2387],
        [-7.6918,  9.9444,  0.0000, -9.6561]], 
        grad_fn=<SliceBackward0>)

参数绑定

个层间共享参数: 可以定义一个稠密层,然后使用它的参数来设置另一个层的参数。

# 我们需要给共享层一个名称,以便可以引用它的参数
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])

这个例子表明第三个和第五个神经网络层的参数是绑定的。 它们不仅值相等,而且由相同的张量表示。 因此,如果我们改变其中一个参数,另一个参数也会改变。

延后初始化

我们定义了网络架构,但没有指定输入维度。
我们添加层时没有指定前一层的输出维度。
我们在初始化参数时,甚至没有足够的信息来确定模型应该包含多少参数。
这里的诀窍是框架的延后初始化(defers initialization), 即直到数据第一次通过模型传递时,框架才会动态地推断出每个层的大小。

import torch
from torch import nn
from d2l import torch as d2l
net = nn.Sequential(nn.LazyLinear(256), nn.ReLU(), nn.LazyLinear(10))
C:\anaconda3\envs\pytorch\lib\site-packages\torch\nn\modules\lazy.py:181: UserWarning: Lazy modules are a new feature under heavy development so changes to the API or functionality can happen at any moment.
  warnings.warn('Lazy modules are a new feature under heavy development '

网络络还不知道输入层权重的维度,因为输入维度仍然未知。

net[0].weight
<UninitializedParameter>

通过网络传递数据后,框架最终初始化参数。
一旦知道输入维度20,框架就可以通过插入20的值来识别第一层权重矩阵的形状。识别出第一层的形状后,框架继续到第二层,通过计算图依次进行,直到所有形状都已知。请注意,在这种情况下,只有第一层需要延迟初始化,但框架会顺序初始化。一旦已知所有参数形状,框架最终就可以初始化参数。

X = torch.rand(2, 20)
net(X)

net[0].weight.shape
torch.Size([256, 20])

以下方法通过网络传递伪输入进行试运行,以推断所有参数形状并随后初始化参数。稍后当不需要默认随机初始化时将使用它。

@d2l.add_to_class(d2l.Module)  #@save
def apply_init(self, inputs, init=None):
    self.forward(*inputs)
    if init is not None:
        self.net.apply(init)
AttributeError: module 'd2l.torch' has no attribute 'add_to_class'

封面图片来源

欢迎点击我的主页查看更多文章。
本人学习地址https://zh-v2.d2l.ai/
恳请大佬批评指正。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2083414.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++必修:unordered_set与unordered_map的实现

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C学习 贝蒂的主页&#xff1a;Betty’s blog 1. unordered_set与unordered_map的结构 我们知道STL中的unordered_set与unorder…

PowerDesigner生成数据库表结构

PowerDesigner生成数据库表结构 目录 1. 安装32位JDK 2. 更改当前DBMS 3. 下载MySQL驱动 4. 生成数据库表结构 安装32位JDK PowerDesigner只支持32位JDK 更改当前DBMS 下载MySQL驱动 下载地址&#xff1a; MySQL :: Begin Your Download 生成数据库表结构 选择Dire…

同城外卖系统开发方案解析

外卖系统开发是一个复杂而细致的过程&#xff0c;涉及多个方面的考虑和技术实现。以下是对外卖系统开发的详细解析&#xff1a; 一、需求分析 在开发外卖系统之前&#xff0c;首先需要进行详尽的需求分析。这包括用户需求、商家需求和后台管理需求三个方面&#xff1a; 用户需…

怎样把两个pdf合并成一个pdf?教你7种方法轻松完成合并!

新手小白如何将pdf合并成一个文件&#xff1f;pdf是目前较为主流的一种传输格式&#xff0c;内容包含了丰富的多媒体数据&#xff0c;包括文本、图像、表格等多种元素&#xff0c;很多企业和教育工作者都喜欢使用pdf格式。 pdf文件体积较小&#xff0c;兼容性高&#xff0c;平…

微深节能 卸料小车远程智能控制系统 格雷母线定位系统

微深节能的卸料小车远程智能控制系统与格雷母线定位系统的结合&#xff0c;为物料管理提供了智能化、精准化、高效化的解决方案。 一、系统概述 卸料小车远程智能控制系统&#xff1a;该系统利用现代科技手段&#xff0c;实现对卸料小车的远程监控与智能控制&#xff0c;旨在提…

使用vueuse在组件内复用模板

1. 安装vueusae pnpm i vueuse/core2. 组件内复用模板 createReusableTemplate 是vueuse中的一个实用工具&#xff0c;用于在 Vue 3 中创建可重复使用的模板片段&#xff0c;同时保持状态的独立性。这对于需要在多个组件中重复使用相同的结构和逻辑时非常有用。 因为这些可复…

基于ROM的VGA显示

前言 在早期计算机和嵌入式系统中&#xff0c;图形显示和用户界面的实现主要依赖于硬件技术。VGA&#xff08;视频图形阵列&#xff09;标准在1980年代中期成为主流图形显示技术&#xff0c;其高分辨率和良好的兼容性使其在计算机显示领域中占据了重要地位。VGA标准支持640x480…

基于清风数学建模视频课的思维导图

B站视频课地址 数学建模学习交流

【前端开发必备小技巧】前端代码规范html、css篇

文章目录 &#x1f7e2; 前端代码规范&#x1f7e2; 一、编码规约&#x1f449;1、命名规范&#x1f449;1.1、项目命名&#x1f449;1.2、目录命名&#x1f449;1.3、JS、CSS、SCSS、HTML、PNG 文件命名&#x1f449;1.4、命名严谨性 &#x1f449;2、HTML规范(Vue Template 同…

EasyCVR中的H.265技术:助力实现大规模高效流畅的视频监控应用

随着视频监控技术的不断发展和用户对视频质量要求的不断提高&#xff0c;高效能、低延迟的视频编码技术成为视频监控系统中的重要支撑。TSINGSEE青犀视频旗下的EasyCVR视频汇聚平台凭借其强大的视频处理能力和对H.265技术的支持&#xff0c;在视频监控系统中展现出显著的应用优…

【qt】锁

线程安全问题. 多线程程序太复杂了. 加锁 把多个线程要访问的公共资源&#xff0c;通过锁保护起来.>把并发执行变成串行执行. Linux mutex 互斥量. C11引入std::mutex Qt 同样也提供了对应的锁&#xff0c;来针对系统提供的锁进行封装.QMutex 多个线程进行加锁的对象&…

信息学奥赛初赛天天练-77-NOIP2015普及组-基础题2-二进制、连通图、最小生成树、链表、二叉树、完全二叉树

NOIP 2015 普及组 基础题2 4 在计算机内部用来传送、存贮、加工处理的数据或指令都是以( )形式进行的 A 二进制码 B 八进制码 C 十进制码 D 智能拼音码 5 下列说法正确的是( ) A CPU 的主要任务是执行数据运算和程序控制 B 存储器具有记忆能力&#xff0c;其中信息任何时候都…

【Linux】——Rocky Linux配置静态IP

Rocky Linux配置静态IP Rocky Linux Rocky Linux 进入官网进行下载&#xff0c;下载版本自定义 官网link 获取ip地址 ip addr 获取服务器ip地址 进入网络配置文件目录&#xff1a; cd /etc/NetworkManager/system-connections/vi打开ens33.nmconnection 在IPv4下输入配置信…

Day50 | 108.冗余连接 109.冗余连接II

108.冗余连接 108. 冗余连接 题目 题目描述 树可以看成是一个图&#xff08;拥有 n 个节点和 n - 1 条边的连通无环无向图&#xff09;。 现给定一个拥有 n 个节点&#xff08;节点标号是从 1 到 n&#xff09;和 n 条边的连通无向图&#xff0c;请找出一条可以删除的边&…

基于元神操作系统编程写USB扇区

1. 背景 本文介绍了“调用元神操作系统API向U盘扇区写数据”的程序实现及测试结果。 2. 方法 &#xff08;1&#xff09;调用元神操作系统API读U盘扇区 本部分内容已在前面的文章中进行介绍&#xff0c;详细内容请参考“编写程序调用元神操作系统的API”。 &#xff08;2&…

WordPress入门级防火墙推荐指南

随着互联网的发展&#xff0c;网站安全问题日益凸显。对于刚开始接触WordPress的用户来说&#xff0c;选择一款合适的防火墙插件非常关键。防火墙不仅能保护网站免受恶意攻击&#xff0c;还能实时监控流量&#xff0c;确保网站正常运行。今天我将为大家介绍两款适合新手使用的W…

Python计算机视觉 第4章-照相机模型与增强现实

Python计算机视觉 第4章-照相机模型与增强现实 4.1 针孔照相机模型 针孔照相机模型&#xff08;有时称为射影照相机模型&#xff09;是计算机视觉中广泛使用的照相机模型。对于大多数应用来说&#xff0c;针孔照相机模型简单&#xff0c;并且具有足够的精确度。这个名字来源…

我的电脑/资源管理器里无法显示新硬盘?

前情提要 我新&#xff01;买了一个京东京造的SATA3硬盘&#xff0c;一个绿联的SATA3转USB读取 现在我的电脑里只能显示我本地的C盘和D盘&#xff0c;不能显示这个接入的SATA盘。 系统环境&#xff1a;windows11 问题描述 在我的电脑里&#xff0c;只能看到我原本的C和D&…

mount : wrong fs type, bad option, bad superblock on

nfs-utils没有安装 rpm -qa|grep nfsyum install -y nfs-utils

【读书笔记-《30天自制操作系统》-9】Day10

本篇主要解决两个问题。一是扩充上一篇内存管理部分的功能&#xff0c;实现一种按4KB大小分配内存的函数&#xff1b;二是解决鼠标显示中鼠标覆盖任务栏的问题。 1. 以4KB大小为单位分配内存的函数 如果每次分配内存都需要按字节去分配&#xff0c;效率还是比较低的&#xf…