16 PyTorch 神经网络基础【李沐动手学深度学习v2】

要想直观地了解块是如何工作的,最简单的方法就是自己实现一个。 在实现我们自定义块之前,我们简要总结一下每个块必须提供的基本功能。

  1. 将输入数据作为其前向传播函数的参数。

  2. 通过前向传播函数来生成输出。请注意,输出的形状可能与输入的形状不同。例如,我们上面模型中的第一个全连接的层接收一个20维的输入,但是返回一个维度为256的输出。

  3. 计算其输出关于输入的梯度,可通过其反向传播函数进行访问。通常这是自动发生的。

  4. 存储和访问前向传播计算所需的参数。

  5. 根据需要初始化模型参数。


1. 模型构造

1.1 自定义块

层和块

构造单层神经网咯:线性层+RELU+线性层

生成2x20(2是批量大小,20是批量维度)的随机矩阵

自定义快

MLP是nn.Module的子类,所以nn.Module有两个函数

实例化多层感知机的层

动手打一遍吧,加深一下印象嘞

复制代码
class MLP(nn.Module):
    # 用模型参数声明层。这里,我们声明两个全连接的层
    def __init__(self):
        # 调用MLP的父类Module的构造函数来执行必要的初始化。
        # 这样,在类实例化时也可以指定其他函数参数,例如模型参数params(稍后将介绍)
        super().__init__()
        self.hidden = nn.Linear(20, 256)  # 隐藏层
        self.out = nn.Linear(256, 10)  # 输出层

    # 定义模型的前向传播,即如何根据输入X返回所需的模型输出
    def forward(self, X):
        # 注意,这里我们使用ReLU的函数版本,其在nn.functional模块中定义。
        return self.out(F.relu(self.hidden(X)))

net = MLP()
net(X)

上述代码的解析

复制代码
复制代码

测试上述代码 net = MLP() net(X) # 块的一个主要优点是它的多功能性。 # 我们可以子类化块以创建层(如全连接层的类)、 整个模型(如上面的MLP类)或具有中等复杂度的各种组件。 # 我们在接下来的章节中充分利用了这种多功能性, 比如在处理卷积神经网络时。


1.2 顺序块

现在我们可以更仔细地看看Sequential类是如何工作的, 回想一下Sequential的设计是为了把其他模块串起来。 为了构建我们自己的简化的MySequential, 我们只需要定义两个关键函数:

  1. 一种将块逐个追加到列表中的函数;

  2. 一种前向传播函数,用于将输入按追加块的顺序传递给块组成的"链条"。

下面的MySequential类提供了与默认Sequential类相同的功能。

顺序块

*args: lists of inputs of arguments

super( ).init( ) 调用父类的初始化函数

self._modeules[block] : ordered dictionary. 放进去key. 【也就是说把传进去的每一层layer都按照顺序放在这个容器里,感觉相当于是数组的作用,只不过她存的是神经网络层】

复制代码
复制代码

class MySequential(nn.Module): def init(self, *args): super().init() for idx, module in enumerate(args): # 这里,module是Module子类的一个实例。我们把它保存在'Module'类的成员 # 变量_modules中。_module的类型是OrderedDict self._modules[str(idx)] = module def forward(self, X): # OrderedDict保证了按照成员添加的顺序遍历它们 for block in self._modules.values(): X = block(X) return X net = MySequential(nn.Linear(20, 256), nn.ReLU(), nn.Linear(256, 10)) net(X)

1.3 在前向传播函数中执行代码

Sequential类使模型构造变得简单, 允许我们组合新的架构,而不必定义自己的类。 然而,并不是所有的架构都是简单的顺序架构。 当需要更强的灵活性时,我们需要定义自己的块。 例如,我们可能希望在前向传播函数中执行Python的控制流。 此外,我们可能希望执行任意的数学运算, 而不是简单地依赖预定义的神经网络层。

复制代码

class FixedHiddenMLP(nn.Module): def init(self): super().init() # 不计算梯度的随机权重参数。因此其在训练期间保持不变 self.rand_weight = torch.rand((20, 20), requires_grad=False) self.linear = nn.Linear(20, 20) def forward(self, X): X = self.linear(X) # 使用创建的常量参数以及relu和mm函数 X = F.relu(torch.mm(X, self.rand_weight) + 1) # 复用全连接层。这相当于两个全连接层共享参数 X = self.linear(X) # 控制流 while X.abs().sum() > 1: X /= 2 return X.sum() net = FixedHiddenMLP() net(X)

添加图片注释,不超过 140 字(可选)

我们可以混合搭配各种组合块的方法。 在下面的例子中,我们以一些想到的方法嵌套块。

复制代码
复制代码

class NestMLP(nn.Module): def init(self): super().init() self.net = nn.Sequential(nn.Linear(20, 64), nn.ReLU(), nn.Linear(64, 32), nn.ReLU()) self.linear = nn.Linear(32, 16) def forward(self, X): return self.linear(self.net(X)) chimera = nn.Sequential(NestMLP(), nn.Linear(16, 20), FixedHiddenMLP()) chimera(X)

不是很能完全理解....先这样,学到后面应该这里会好一些,迷茫抛在这里啦


2. 参数管理

我们首先看一下具有单隐藏层的多层感知机。

复制代码
复制代码

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)

参数访问

net[2] 拿到的是nn.Linear(8, 1)

state_dict() 就是权重

目标参数

一次性访问所有参数

添加图片注释,不超过 140 字(可选)

  1. 自定义层

  2. 读写文件

..... 没写完 明天的任务就是把这一节彻底吃透

相关推荐
爱喝可乐的老王3 分钟前
PyTorch简介与安装
人工智能·pytorch·python
看我干嘛!7 分钟前
第三次python作业
服务器·数据库·python
deephub7 分钟前
用 PyTorch 实现 LLM-JEPA:不预测 token,预测嵌入
人工智能·pytorch·python·深度学习·大语言模型
量子-Alex12 分钟前
【多模态大模型】Qwen2-VL项目代码初步解析
人工智能
飞鹰5120 分钟前
深度学习算子CUDA优化实战:从GEMM到Transformer—Week4学习总结
c++·人工智能·深度学习·学习·transformer
工程师老罗22 分钟前
Pytorch如何验证模型?
人工智能·pytorch·深度学习
Hi_kenyon23 分钟前
Skills精选
人工智能
我的xiaodoujiao31 分钟前
使用 Python 语言 从 0 到 1 搭建完整 Web UI自动化测试学习系列 44--将自动化测试结果自动推送至钉钉工作群聊
前端·python·测试工具·ui·pytest
沈浩(种子思维作者)31 分钟前
铁的居里点(770度就不被磁铁吸了)道理是什么?能不能精确计算出来?
人工智能·python·flask·量子计算
沛沛老爹33 分钟前
Web开发者转型AI:多模态Agent视频分析技能开发实战
前端·人工智能·音视频