栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

PyTorch Week 3——nn.Module的容器:Sequential、ModuleList、ModuleDice

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

PyTorch Week 3——nn.Module的容器:Sequential、ModuleList、ModuleDice

系列文章目录

PyTorch Week 3——模型创建

PyTorch Week 2——Dataloader与Dataset

PyTorch Week 1

PyTorch Week 3——nn.Module的容器:Sequential、ModuleList、ModuleDice
  • 系列文章目录
  • 前言
  • 一、Sequential
    • 1. 模型构建:默认的命名形式与字典命名方式
    • 2. 模型拼接
  • 二、ModuleList
    • 1. 构建
    • 2.拼接
  • 三、ModuleDict
  • 四、构建AlexNet
  • 总结


前言

本节介绍使用Pytorch的nn.Module模块的容器功能,包括Sequential、ModuleList、ModuleDice三种方法。

一、Sequential

打开lesson-11的module_containers.py,首先通过LeNetSequential类展示默认的Sequential定义方法

1. 模型构建:默认的命名形式与字典命名方式

Sequential类有两种命名方式,

#第一种默认的命名方式
class LeNetSequential(nn.Module):#继承nn.Module,LeNet包括特征提取器和分类器
    def __init__(self, classes):
        super(LeNetSequential, self).__init__()#调用nn.Module的__init__定义属性
        self.features = nn.Sequential(#调用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),)#在这一行完成了所有子层的实例化和Sequential的实例化,并将nn.Sequential赋值给self.features

#第二种,类似字典的命名方式
class LeNetSequentialOrderDict(nn.Module):
    def __init__(self, classes):
        super(LeNetSequentialOrderDict, self).__init__()

        self.features = nn.Sequential(OrderedDict({
            'conv1': nn.Conv2d(3, 6, 5),
            'relu1': nn.ReLU(inplace=True),
            'pool1': nn.MaxPool2d(kernel_size=2, stride=2),

            'conv2': nn.Conv2d(6, 16, 5),
            'relu2': nn.ReLU(inplace=True),
            'pool2': nn.MaxPool2d(kernel_size=2, stride=2),
        }))

步入Sequential赋值语句,进入container.py的Sequential类,__init__函数首先判断接收的变量是否是一个有序字典,若不是的话,反复调用add_module,将接收的模型变量赋值给‘0’,‘1’,‘2’······;

class Sequential(Module):#首先Sequential类也继承Module,同样有八个字典用于管理变量,变量型的子层和字典型的子层都通过add_Module方法存储在_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)#调用module的add_module方法,赋值给Sequential的_module
        else:
            for idx, module in enumerate(args):#
                self.add_module(str(idx), module)


若是的话,调用add_module,将接收的模型变量按照字典的键值赋值

2. 模型拼接

步入调用net

output = net(fake_img)

进入到了LeNetSequential的forward函数

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

进入了module的call函数,步入forward,可以看到self变量列表中已经定义好了两个子模块feature和classifier,其中包含每个子层。

步入classifier子模块,进入module的call函数,再步入,进入container的forward函数,在这里实现了前向传播,反复按照顺序调用Sequential的_module里的子层

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

小结:
nn.Sequential是nn.Module的容器,用于按照顺序包装一组网络层,具有两个性质:

  • 顺序性:网络层按照定义时的顺序排列
  • 自带forward:Sequential自带forward函数,使用for循环调用定义的子层,依次执行前向传播
二、ModuleList

ModuleList以迭代的方式调用网络层,与list类似,主要包含三种方法:

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

列表生成式的方式生成子层

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

ModuleList的实例化,与列表的方法类似,步入+=是extend方法

    def __init__(self, modules: Optional[Iterable[Module]] = None) -> None:
        super(ModuleList, self).__init__()
        if modules is not None:
            self += modules
    def __iadd__(self, modules: Iterable[Module]) -> 'ModuleList':
        return self.extend(modules)

步出至主函数,可以看到net的_module已经有了20个Linear层

2.拼接

继续运行步入

output = net(fake_data)

进入实例化的ModuleList的forward,前向传播过程与for循环列表类似

    def forward(self, x):
        for i, linear in enumerate(self.linears):#注意,这里需要手动写for循环实现前向传播,与Sequential不同
            x = linear(x)#步入
        return x

步入,进入的是linear.py文件,Linear类,forward函数,可以

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

查看container.py的ModuleList类后发现该类不具有forward函数,前向传播需要写for循环实现的

三、ModuleDict

ModuleDict函数是nn.Module的容器,用于包装一组网络层,以索引的方式调用网络层
主要方法:

  • clear():清空ModuleDict
  • iterms():返回可迭代的键值对(key-value pairs)
  • keys():返回字典的键(key)
  • values():返回字典的值(value)
  • pop():返回一对键值,并从字典中删除
 class ModuleDict(nn.Module):
    def __init__(self):
        super(ModuleDict, self).__init__()
        self.choices = nn.ModuleDict({
            'conv': nn.Conv2d(10, 10, 3),#ModuleDict的字典定义方式
            'pool': nn.MaxPool2d(3)
        })

        self.activations = nn.ModuleDict({
            'relu': nn.ReLU(),
            'prelu': nn.PReLU()
        })
    def forward(self, x, choice, act):
        x = self.choices[choice](x)#前向传播中调用:子模块名[键](输入)
        x = self.activations[act](x)
        return x

前向传播时,需要输入两个子模块的key,比如第二个子模块activate可以选择激活函数是使用relu还是prelu

output = net(fake_img, 'conv', 'relu')
四、构建AlexNet

AlexNet特点:

  • ReLU减轻梯度消失
  • LRN(Local Response Normalization)对数据归一化,减轻梯度消失
  • Dropout
  • Data Augmentation:TenCrop,色彩修改


分为特征提取器和分类器两部分。
查看Pytorch代码,AlexNet网络分成feature,avgpool,classifier,feature和classifier是Sequential

class AlexNet(nn.Module):

    def __init__(self, num_classes: int = 1000) -> None:
        super(AlexNet, self).__init__()
        self.features = nn.Sequential(#特征提取器
            nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
            nn.Conv2d(64, 192, kernel_size=5, padding=2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
            nn.Conv2d(192, 384, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(384, 256, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
        )
        self.avgpool = nn.AdaptiveAvgPool2d((6, 6))#池化层
        self.classifier = nn.Sequential(#分类器
            nn.Dropout(),
            nn.Linear(256 * 6 * 6, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(4096, 4096),
            nn.ReLU(inplace=True),
            nn.Linear(4096, num_classes),
        )

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        x = self.features(x)
        x = self.avgpool(x)
        x = torch.flatten(x, 1)
        x = self.classifier(x)
        return x

forward中只有四行,借助了Sequential函数自带的forward。

总结

本节学习了nn.Module的三种容器,分别是Sequential,ModuleList,ModuleDict

  • nn.Sequential:顺序性,严格按顺序执行,常用语block构建
  • nn.ModuleList:迭代性,通过for循环重复构建,常用语大量重复网络构建
  • nn.ModuleDict:所隐形,常用于可以选择的网络层

查看了pytorch代码中的AlexNet网络结构

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/339383.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号