问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

神经网络中的层与块:概念与PyTorch实现

创作时间:
作者:
@小白创作中心

神经网络中的层与块:概念与PyTorch实现

引用
CSDN
1.
https://m.blog.csdn.net/qq_62827972/article/details/140369938

本文总结了神经网络中的层与块的概念及其在PyTorch中的实现方式,适合深度学习初学者阅读。

在介绍神经网络时,我们通常会从单一输出的线性模型开始,然后过渡到具有多个输出的网络。随着研究的深入,我们发现需要一个介于单个层和整个模型之间的组件,这就是神经网络块(block)的概念。

块可以描述单个层、由多个层组成的组件,甚至是整个模型本身。使用块进行抽象的一个重要优点是,可以将一些块组合成更大的组件,这一过程通常是递归的。通过定义代码来按需生成任意复杂度的块,我们可以用简洁的代码实现复杂的神经网络。

自定义块

为了更好地理解“块”的概念,我们可以自己实现一个简单的多层感知器(MLP):

import torch
import torch.nn as nn
import torch.nn.functional as F

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()
X = torch.randn(2, 20)  # 随机生成输入数据
output = net(X)  # 等效于net.forward(X)
print(output)

输出结果如下:

tensor([[ 0.2535, -0.1106, 0.1944, -0.1779, -0.1540, 0.0939, 0.2560, 0.1141,
 0.0368, -0.1281],
 [ 0.0286, 0.0554, 0.1914, 0.0065, -0.0017, 0.2003, 0.0707, 0.0512,
 -0.0016, -0.0085]], grad_fn=<AddmmBackward0>)

这个例子展示了如何定义一个简单的MLP模型。值得注意的是,当我们调用net(X)时,实际上是在调用net.forward(X)

顺序块

接下来,我们来看看如何实现一个顺序块。顺序块类似于PyTorch中的nn.Sequential,但提供了更多的灵活性:

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))
X = torch.randn(2, 20)  # 随机生成输入数据
output = net(X)
print(output)

输出结果如下:

tensor([[ 0.0011, 0.1545, -0.0147, -0.0517, -0.1129, 0.1292, 0.3381, 0.0989,
 -0.0893, -0.0295],
 [-0.0605, 0.1350, -0.0213, -0.1577, -0.0175, 0.0041, 0.2423, -0.0636,
 -0.0778, 0.0949]], grad_fn=<AddmmBackward0>)

这段代码定义了一个名为 MySequential 的类,它继承自 PyTorch 的 nn.Module 类。这个类实现了一个自定义的序列模型,类似于 PyTorch 的 nn.Sequential,但是提供了一种自定义的方式来添加模块。下面是代码的逐行解释:

  1. class MySequential(nn.Module):定义了一个名为 MySequential 的类,它继承自 nn.Module
  2. __init__(self, *args):构造函数接受任意数量的位置参数 *args。这些参数应该是 nn.Module 的子类实例。
  3. super().__init__():调用父类 nn.Module 的构造函数来执行必要的初始化。
  4. for idx, module in enumerate(args)::遍历所有传入的参数。enumerate 函数返回每个参数的索引(idx)和参数本身(module)。
  5. self._modules[str(idx)] = module:将每个模块实例添加到 _modules 字典中。索引被转换为字符串,因为 _modules 字典的键需要是字符串类型。这里使用字符串索引而不是数字索引是为了保持模块添加的顺序,类似于 OrderedDict
  6. def forward(self, X):定义了模型的前向传播方法。
  7. for block in self._modules.values()::遍历 _modules 字典中的所有值(即所有模块实例)。
  8. X = block(X):对输入 X 应用当前模块 block,并更新 X 为模块的输出。
  9. return X:返回经过所有模块处理后的最终输出。

这个自定义的 MySequential 类允许你以顺序的方式堆叠多个神经网络模块。每个模块将按照它们添加到 MySequential 实例中的顺序依次应用于输入数据 X。这与 PyTorch 的内置 nn.Sequential 类的功能类似,但提供了更多的灵活性,例如通过索引访问特定的模块或修改模块的顺序。

小结

  • 一个块可以由许多层组成;一个块可以由许多块组成。
  • 块可以包含代码。
  • 块负责大量的内部处理,包括参数初始化和反向传播。
  • 层和块的顺序连接由Sequential块处理。
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号