pytorch容器之nn.Sequential, nn.ModuleList, nn.ModuleDict介绍

这篇具有很好参考价值的文章主要介绍了pytorch容器之nn.Sequential, nn.ModuleList, nn.ModuleDict介绍。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

  在深度学习模型创建的时候,我们经常会碰到nn.Sequential, nn.ModuleList, nn.ModuleDict这三个东西,尤其是在迁移学习训练的时候经常碰到,他们到底是什么,怎么用的,使用的时候有哪些注意事项,通过这篇博文浅记一下。

一. nn.Module

  在介绍这三个容器之前,我们需要先知道什么是Module。我们在创建模型的时候几乎所有的模型都是继承于这个类。他是所有网络的基类,用来管理网络的属性。有两个与他相关联的模块:nn.Parameternn.functional。所有这些模块都来自于torch.nn。下面我们先简要介绍下这几个模块。

1.1. nn.Parameter

  首先是nn.Parameter, 在Pytorch中,nn.Parameter 是用于创建模型参数的特殊类。在一个模型中,往往有许多的参数,要手动管理这些参数并不是一件容易的事情。Pytorch一般将参数用nn.Parameter来表示,并且用nn.Module来管理其结构下的所有参数。

## nn.Parameter 具有 requires_grad = True 属性
w = nn.Parameter(torch.randn(2,2))
print(w)   # tensor([[ 0.3544, -1.1643],[ 1.2302,  1.3952]], requires_grad=True)
print(w.requires_grad)   # True

## nn.ParameterList 可以将多个nn.Parameter组成一个列表
params_list = nn.ParameterList([nn.Parameter(torch.rand(8,i)) for i in range(1,3)])
print(params_list)
print(params_list[0].requires_grad)

## nn.ParameterDict 可以将多个nn.Parameter组成一个字典
params_dict = nn.ParameterDict({"a":nn.Parameter(torch.rand(2,2)),
                               "b":nn.Parameter(torch.zeros(2))})
print(params_dict)
print(params_dict["a"].requires_grad)

可以通过Module把上面定义的参数管理起来:

# module.parameters()返回一个生成器,包括其结构下的所有parameters

module = nn.Module()
module.w = w
module.params_list = params_list
module.params_dict = params_dict

num_param = 0
for param in module.parameters():
    print(param,"\n")
    num_param = num_param + 1
print("number of Parameters =",num_param)

  实际使用的时候一般通过继承nn.Module来构建模块类,并将所有含有需要学习的参数的部分放在构造函数中。

#以下范例为Pytorch中nn.Linear的源码的简化版本
#可以看到它将需要学习的参数放在了__init__构造函数中,并在forward中调用F.linear函数来实现计算逻辑。

class Linear(nn.Module):
    __constants__ = ['in_features', 'out_features']

    def __init__(self, in_features, out_features, bias=True):
        super(Linear, self).__init__()
        self.in_features = in_features
        self.out_features = out_features
        self.weight = nn.Parameter(torch.Tensor(out_features, in_features))
        if bias:
            self.bias = nn.Parameter(torch.Tensor(out_features))
        else:
            self.register_parameter('bias', None)

    def forward(self, input):
        return F.linear(input, self.weight, self.bias)

1.2. nn.functional

nn.functional(一般引入后改名为F)有各种功能组件的函数实现。 比如:

  • 激活函数系列(F.relu, F.sigmoid, F.tanh, F.softmax)
  • 模型层系列(F.linear, F.conv2d, F.max_pool2d, F.dropout2d, F.embedding)
  • 损失函数系列(F.binary_cross_entropy, F.mse_loss, F.cross_entropy)

  为了便于对参数进行管理, 一般通过继承nn.Module转换为类的实现形式, 并直接封装在nn模块下:

  • 激活函数变成(nn.ReLu, nn.Sigmoid, nn.Tanh, nn.Softmax)
  • 模型层(nn.Linear, nn.Conv2d, nn.MaxPool2d, nn.Embedding)
  • 损失函数(nn.BCELoss, nn.MSELoss, nn.CrossEntorpyLoss)

  所以我们表面上用nn建立的这些激活函数, 层, 损失函数, 背后都在functional里面具体实现。继续往下看你就知道了, nn.Module这个模块确实非常强大, 除了可以管理其引用的各种参数,还可以管理其引用的子模块。

1.3. nn.Module

我们的重点是介绍这个nn.Module模块。nn.Module中有很多重要的字典属性:

     	self.training = True
        self._parameters: Dict[str, Optional[Parameter]] = OrderedDict()
        self._buffers: Dict[str, Optional[Tensor]] = OrderedDict()
        self._non_persistent_buffers_set: Set[str] = set()
        self._backward_hooks: Dict[int, Callable] = OrderedDict()
        self._is_full_backward_hook = None
        self._forward_hooks: Dict[int, Callable] = OrderedDict()
        self._forward_pre_hooks: Dict[int, Callable] = OrderedDict()
        self._state_dict_hooks: Dict[int, Callable] = OrderedDict()
        self._load_state_dict_pre_hooks: Dict[int, Callable] = OrderedDict()
        self._modules: Dict[str, Optional['Module']] = OrderedDict()

我们只需要重点关注其中的两个即可:_parameters_modules

  • _parameters: 存储管理属于nn.Parameter类的属性,例如权值,偏置这些参数
  • _modules: 存储管理nn.Module类, 比如经典网络LeNet中,会构建子模块,卷积层,池化层,就会存储在_modules中

这里提个问题:nn.Parameternn.Module中的_parameters的区别是什么?

  • nn.Parameter:它是 torch.Tensor 的子类,用于标记张量为模型的可学习参数。在定义模型的过程中,我们通常会使用 nn.Parameter 来创建可学习参数,并将其作为模型的属性。这样做的好处是,nn.Parameter对象会自动被注册为模型的参数,参与梯度计算和参数更新。
  • _parameters:它是 nn.Module 类中的一个属性,是一个字典,用于存储模型的可学习参数。字典的键是参数的名称,值是对应的参数张量(nn.Parameter类型)。_parameters 属性的值会自动从模型的属性中提取可学习参数,并将其添加到字典中。

  可以将 _parameters 视为存储模型可学习参数的容器,而 nn.Parameter 则是用于创建和标记这些参数的特殊类。通过使用 nn.Parameter 创建参数,并将其作为模型属性,这些参数将被自动添加到 _parameters 字典中,方便对它们进行统一的管理和操作。即nn.Parameter 是用于创建模型参数的特殊类,而 _parameters 是存储模型参数的字典属性。使用 nn.Parameter 创建的参数会自动添加到 _parameters 字典中,以便于管理和访问模型的参数。

nn.Module构建构网络的过程是什么样的?以下面的网络为例:

import torch
from torch import nn


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 1, 1, 1)
        self.bn = nn.BatchNorm2d(1)
        self.relu = nn.ReLU()
        self.conv2 = nn.Conv2d(1, 1, 1, 1)

    def forward(self, x):
        x = self.conv1(x)
        x = self.bn(x)
        x = self.relu(x)
        x = self.conv2(x)
        return x


if __name__ == "__main__":
    dat = torch.rand(1, 1, 10, 10)
    net = Net().cuda()

构建过程如下:

  我们是先有一个大的Module(上面创建的Net)继承nn.Module这个基类,比如上面的Net,然后这个Net里面又可以有很多的子模块,这些子模块同样也是继承于nn.Module,在这些Module__init__方法中,会先通过调用父类的初始化方法进行父类属性的一个初始化。然后在构建每个子模块的时候,其实分为两步,第一步是初始化,然后被__setattr__这个方法通过判断value的类型将其保存到相应的属性字典里面去,然后再进行赋值给相应的成员。这样一个个的构建子模块,最终把整个Net构建完毕。具体过程可以自己调试看一下。

总结:

  • 一个module可以包含多个子moduleNet包含卷积层,BN层,激活函数)
  • 一个module相当于一个运算, 必须实现forward()函数(有些模块的forward需要自己去重新写,往下看你就知道了)
  • 每个module都有很多个字典管理它的属性(最常用的就是_parameters_modules

  知道了网络的构建过程,我们就可以对别人创建好的模型进行解析,提取其中的若干部分,关于这部分的介绍可以参考这篇博文:Pytorch提取神经网络层结构、层参数及自定义初始化。

二. nn.Sequential

  上面介绍完了nn.Module模块,我们开始介绍容器。首先我们来看下nn.Sequentialnn.SequentialPyTorch 中的一个模块容器,用于按顺序组合多个模块。它可以将一系列的模块按照顺序连接起来,形成一个串联的模型结构。我们来看下他在pytorch中是怎么实现的,这里我们只看构造函数和前向传播部分,其他部分的代码省略:

class Sequential(Module):
	...
	
    def __init__(self, *args):
        super(Sequential, self).__init__()
        if len(args) == 1 and isinstance(args[0], OrderedDict):
            for key, module in args[0].items():
                self.add_module(key, module)
        else:
            for idx, module in enumerate(args):
                self.add_module(str(idx), module)

	...
	
    def forward(self, input):
        for module in self:
            input = module(input)
        return input

  通过上面的代码可以看到,nn.Sequential是继承于Module,说明Sequential本身也是一个Module,所以它也会有那几个字典参数。可以看到nn.Sequential自己实现了forward方法。nn.Sequential中经常使用的主要有如下几个方法:

  • forward(input):定义模型的前向传播过程。在 nn.Sequential 中,此方法会按照模块的顺序依次调用每个模块的 forward 方法,将前一个模块的输出作为输入传递给下一个模块,从而计算最终的输出。
  • add_module(name, module):向 nn.Sequential 中添加一个子模块。name 是子模块的名称,module 是要添加的子模块对象。模块将按照添加的顺序依次进行前向传播。
  • parameters():返回 nn.Sequential 中所有可学习参数的迭代器。可以通过迭代器访问和操作模型的可学习参数。
  • zero_grad():将 nn.Sequential 中所有模块的参数梯度置零。通常在每次进行梯度更新之前调用该方法

  就列举上面几个方法,其实还很对,平时用的最多的还是add_module(name, module)这个方法,用于添加模块。来看下 nn.Sequential 到底怎么使用的?

class Net(nn.Module):
    def __init__(self, classes):
        super(Net, self).__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 6, 5),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Conv2d(6, 16, 5),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),)

        self.classifier = nn.Sequential(
            nn.Linear(16*5*5, 120),
            nn.ReLU(),
            nn.Linear(120, 84),
            nn.ReLU(),
            nn.Linear(84, classes),)

    def forward(self, x):
        x = self.features(x)
        x = x.view(x.size()[0], -1)
        x = self.classifier(x)
        return x

也可以使用add_module的方法进行创建:

import torch
import torch.nn as nn

class Net(nn.Module):
    def __init__(self, classes):
        super(Net, self).__init__()

        self.features = nn.Sequential()
        self.features.add_module('conv1', nn.Conv2d(3, 6, 5))
        self.features.add_module('relu1', nn.ReLU())
        self.features.add_module('pool1', nn.MaxPool2d(kernel_size=2, stride=2))
        self.features.add_module('conv2', nn.Conv2d(6, 16, 5))
        self.features.add_module('relu2', nn.ReLU())
        self.features.add_module('pool2', nn.MaxPool2d(kernel_size=2, stride=2))

        self.classifier = nn.Sequential()
        self.classifier.add_module('fc1', nn.Linear(16*5*5, 120))
        self.classifier.add_module('relu3', nn.ReLU())
        self.classifier.add_module('fc2', nn.Linear(120, 84))
        self.classifier.add_module('relu4', nn.ReLU())
        self.classifier.add_module('fc3', nn.Linear(84, classes))

    def forward(self, x):
        x = self.features(x)
        x = x.view(x.size()[0], -1)
        x = self.classifier(x)
        return x

  通过上面的网络搭建,可以看到,forward函数中只用了一句self.features(x)即可完成六句话的执行。其之所以能完成这个操作地归功于nn.Sequential中的forward函数,程序在执行功的过程中会把参数传递给nn.Sequential中进行解析,具体实现过程可以调试代码观察。
总结:
nn.Sequentialnn.module的容器, 用于按顺序包装一组网络层,主要有以下两个特点:

  • 顺序性: 各网络层之间严格按照顺序构建,这时候一定要注意前后层数据的关系
  • 自带forward(): 自带的forward里,通过for循环依次执行前向传播运算

三. nn.ModuleList

  nn.ModuleList也是nn.module的容器, 用于包装一组网络层, 以迭代方式调用网络层, 常用的方法有如下几个,跟list的使用很像:

  • append(): 在ModuleList后面添加网络层
  • extend(): 拼接两个ModuleList
  • insert(): 指定在ModuleList中位置插入网络层

直接看个例子,怎么使用nn.ModuleList搭建网络:

class ModuleListNet(nn.Module):
    def __init__(self):
        super(ModuleListNet, self).__init__()
        self.linears = nn.ModuleList([nn.Linear(10, 10) for i in range(10)])

    def forward(self, x):
        for i, linear in enumerate(self.linears):
            x = linear(x)
        return x

  上面的例子通过使用列表推导式创建了10个nn.Linear模块。整体上使用起来还是很简单的,具体实现过程感兴趣的小伙伴可以通过调试代码查看。

三. nn.ModuleDict

我们再来看下nn.ModuleDict这个模块。nn.ModuleDict也是nn.module的容器, 用于包装一组网络层, 以索引方式调用网络层, 常用的有如下方法,跟字典的操作比较像:

  • clear(): 清空ModuleDict
  • items(): 返回可迭代的键值对(key-value pairs)
  • keys(): 返回字典的键(key)
  • values(): 返回字典的值(value)
  • pop(): 返回一对键值对, 并从字典中删除

看个例子:

import torch
import torch.nn as nn

class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()

        self.module_dict = nn.ModuleDict({
            'conv1': nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1),
            'relu1': nn.ReLU(),
            'conv2': nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
            'relu2': nn.ReLU(),
            'flatten': nn.Flatten(),
            'linear': nn.Linear(128 * 32 * 32, 10)
        })

    def forward(self, x):
        for module in self.module_dict.values():
            x = module(x)
        return x

# 创建模型实例
model = MyModel()

# 随机生成输入
x = torch.randn(1, 3, 32, 32)

# 进行前向传播
output = model(x)
print(output.shape)

上面通过nn.ModuleDict创建了一个网络,整体来说还是很简单的,跟字典操作差不多。
  关于nn.Sequential, nn.ModuleList, nn.ModuleDict的基本使用基本上酒介绍完了,如有错误,敬请指正!文章来源地址https://www.toymoban.com/news/detail-477375.html

到了这里,关于pytorch容器之nn.Sequential, nn.ModuleList, nn.ModuleDict介绍的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • pytorch中nn.ModuleList()使用方法

    我们可以将我们需要的层放入到一个集合中,然后将这个集合作为参数传入nn.ModuleList中,但是这个子类并不可以直接使用,因为这个子类并没有实现forward函数,所以要使用还需要放在继承了nn.Module的模型中进行使用。

    2024年02月07日
    浏览(35)
  • Pytorch学习:神经网络模块torch.nn.Module和torch.nn.Sequential

    官方文档:torch.nn.Module CLASS torch.nn.Module(*args, **kwargs) 所有神经网络模块的基类。 您的模型也应该对此类进行子类化。 模块还可以包含其他模块,允许将它们嵌套在树结构中。您可以将子模块分配为常规属性: training(bool) -布尔值表示此模块是处于训练模式还是评估模式。

    2024年02月10日
    浏览(41)
  • nn.Sequential、nn.Linear、nn.ReLU()函数

    nn.Sequential 是 PyTorch 中的一个容器模块,用于按照顺序组合多个神经网络层(如线性层、激活函数、池化层等)。这个容器允许你将各种层按照指定的顺序串联在一起,构建一个神经网络模型。nn.Sequential() 可以允许将整个容器视为单个模块(即相当于把多个模块封装成一个模

    2024年02月07日
    浏览(39)
  • 【PyTorch API】 nn.RNN 和 nn.LSTM 介绍和代码详解

    torch.nn.RNN 的 PyTorch 链接:torch.nn.RNN(*args, **kwargs) nn.RNN 的用法和输入输出参数的介绍直接看代码: 需要特别注意的是 nn.RNN 的第二个输出 hn 表示所有掩藏层的在最后一个 time step 隐状态,听起来很难理解,看下面的红色方框内的数据就懂了。即 output[:, -1, :] = hn[-1, : , :] 这里

    2024年02月12日
    浏览(37)
  • 深度学习之pytorch 中 torch.nn介绍

    pytorch 中必用的包就是 torch.nn,torch.nn 中按照功能分,主要如下有几类: 1. Layers(层):包括全连接层、卷积层、池化层等。 2. Activation Functions(激活函数):包括ReLU、Sigmoid、Tanh等。 3. Loss Functions(损失函数):包括交叉熵损失、均方误差等。 4. Optimizers(优化器):包括

    2024年02月22日
    浏览(41)
  • pytorch中nn.Conv1d功能介绍

            在使用Conv1d函数时,pytorch默认你的数据是一维的,比如一句话“深度学习”可以用一个一维数组 [\\\'深\\\', \\\'度\\\', \\\'学\\\', \\\'习\\\'] 表示,这个数据就是一维的。图片是二维数据,它有长宽两个维度。         因此在使用 Conv1d 函数时,输入是一个三位数组,三个维度分别表

    2024年02月10日
    浏览(42)
  • Pytorch学习笔记(5):torch.nn---网络层介绍(卷积层、池化层、线性层、激活函数层)

     一、卷积层—Convolution Layers  1.1 1d / 2d / 3d卷积 1.2 卷积—nn.Conv2d() nn.Conv2d 1.3 转置卷积—nn.ConvTranspose nn.ConvTranspose2d  二、池化层—Pooling Layer (1)nn.MaxPool2d (2)nn.AvgPool2d (3)nn.MaxUnpool2d  三、线性层—Linear Layer  nn.Linear  四、激活函数层—Activate Layer (1)nn.Sigmoid  (

    2024年01月20日
    浏览(41)
  • Pytorch 容器 - 1. Module类介绍

    目录 1. 基于Module构建自己的网络 2. Module的初始化变量 3. Modules中需要子类 forward() 4. Modules中其他内置函数 1. 基于Module构建自己的网络 torch.nn.Module是所有神经网络模块的基类,如何定义自已的网络: 由于 Module 是神经网络模块的基类,自己的模型应该要继承这个类 要实现 t

    2023年04月17日
    浏览(26)
  • 学习pytorch13 神经网络-搭建小实战&Sequential的使用

    B站小土堆pytorch视频学习 https://pytorch.org/docs/stable/generated/torch.nn.Sequential.html#torch.nn.Sequential sequential 将模型结构组合起来 以逗号分割,按顺序执行,和compose使用方式类似。 箭头指向部分还需要一层flatten层,展开输入shape为一维 tensorboard 展示图文件, 双击每层网络,可查看层

    2024年02月07日
    浏览(39)
  • PyTorch入门学习(十二):神经网络-搭建小实战和Sequential的使用

    目录 一、介绍 二、先决条件 三、代码解释 一、介绍 在深度学习领域,构建复杂的神经网络模型可能是一项艰巨的任务,尤其是当您有许多层和操作需要组织时。幸运的是,PyTorch提供了一个方便的工具,称为Sequential API,它简化了神经网络架构的构建过程。在本文中,将探

    2024年02月05日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包