Pytorch学习笔记(4):模型创建(Module)、模型容器(Containers)、AlexNet构建

简介: Pytorch学习笔记(4):模型创建(Module)、模型容器(Containers)、AlexNet构建


前期回顾:

Pytorch学习笔记(1):基本概念、安装、张量操作、逻辑回归

Pytorch学习笔记(2):数据读取机制(DataLoader与Dataset)

Pytorch学习笔记(3):图像的预处理(transforms)


一、网络模型的创建步骤

网络创建流程:


模型构建的两个要素:

  • 构建子模块:在自己建立的模型(继承nn.Module)的_init_()方法
  • 拼接子模块:是在模型的forward()方法中

以LeNet模型为例:

init函数中构建子模块,构建网络需要的卷积层、池化层、激活函数等

    def __init__(self, classes):
        super(LeNet, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16*5*5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, classes)

forward函数中拼接子模块 ,就是模型的实现

 def forward(self, x):
        out = F.relu(self.conv1(x))
        out = F.max_pool2d(out, 2)
        out = F.relu(self.conv2(out))
        out = F.max_pool2d(out, 2)
        out = out.view(out.size(0), -1)
        out = F.relu(self.fc1(out))
        out = F.relu(self.fc2(out))
        out = self.fc3(out)
        return out

二、nn.Mudule的属性

在模型的概念当中,有一个非常重要的概念叫做nn.Module, 我们所有的模型,所有的网络层都是继承于这个类的。

•  torch.nn: 这是Pytorch的神经网络模块, 这里的Module就是它的子模块之一,另外还有几个与Module并列的子模块, 这些子模块协同工作,各司其职。

nn.Module中,有8个重要的属性, 用于管理整个模型,他们都是以有序字典的形式存在着:

•  _parameters: 存储管理属于nn.Parameter类的属性,例如权值,偏置这些参数

•  _modules: 存储管理nn.Module类, 比如LeNet中,会构建子模块,卷积层,池化层,就会存储在_modules中

•  _buffers:存储管理缓冲属性, 如BN层中的running_mean, std等都会存在这里面

•  ***_hook:存储管理钩子函数(5个与hooks有关的字典,这个先不用管)

nn.Module属性构建:

在nn.Module类中进行属性赋值时,被setattr函数拦截,在该函数中,判断即将要赋值的这个数据类型是否是nn.Parameter类,是则存储到parameters这个字典中;如果是nn.Module类,则存储在module这个字典中进行管理

nn.module总结:

  • 一个module可以包含多个子module(LeNet包含卷积层,池化层,全连接层)
  • 一个module相当于一个运算, 必须实现forward函数(从计算图的角度去理解)
  • 每个module都有8个字典管理它的属性(最常用的就是_parameters_modules

具体代码段如下:

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 20, 5)
        self.conv2 = nn.Conv2d(20, 20, 5)
    def forward(self, x):
        x = F.relu(self.conv1(x))
        return F.relu(self.conv2(x))

三、模型容器Containers

3.1 nn.Sequential

nn.Sequential nn.module的容器,用于按顺序包装一组网络层

以LeNet为例,将卷积池化放到一个sequential中进行特征提取,将全连接层放到一个sequential中进行分类,然后将这两个sequential拼接起来,就是LeNet网络

(1)输入数据类型非字典

用sequential容器构建包装子模型:

'''------------Sequential---------------'''
class LeNetSequential(nn.Module):
    def __init__(self, classes):
        super(LeNetSequential, 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

可以看到,LeNet在这里分成了两大部分:

  • 第一部分是features模块,用于特征提取
  • 第二部分是classifier部分,用于分类

每一部分都是各种网络的堆叠,然后用sequential包装起来。 然后它的forward函数也比较简单, 只需要features处理输出,然后形状变换,然后classifier就完成了。

进入sequential类的init函数,调用init函数构建相应的属性,得到八个有序字典。

首先判断输入的参数的数据类型是否为有序字典,如果为有序字典,则可以对网络层进行命名操作,如果输入不为字典,则执行else操作

在for循环中将网络层添加到sequential中

 def __init__(self, *args: Any):
        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)

调试中可以看出,每个网络层都被加入到module中,但此时网络层的对应的索引都为序号。

打印网络层,我们可以看到:

从中我们可以看出,每个网络层都是用序号来索引的,如果网络层过多,则很难通过序号去索引网络层,故可以对网络层进行命名。


(2)输入数据类型为字典

对sequential输入一个有序的字典来对网络层进行命名:

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),
        }))
        self.classifier = nn.Sequential(OrderedDict({
            'fc1': nn.Linear(16*5*5, 120),
            'relu3': nn.ReLU(),
            'fc2': nn.Linear(120, 84),
            'relu4': nn.ReLU(inplace=True),
            '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

这里面Sequential包装的就是一个有序的字典, 字典中是网络名:网络层的形式。通过这个就可以对每一层网络进行命名

 def __init__(self, *args: Any):
        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)

调试结果中可以看出,网络层被写入sequential,注意,每个网络层前面都有单独的命名。不同于前面的序号索引:

打印网络层,我们可以看到,不同于之前,每个网络层都有自己的名字,可以更方便的通过网络名来索引网络:

总结——sequential

nn.sequential是nn.module的容器,用于按顺序包装一组网络层

  • 顺序性:各网络层之间严格按照顺序构建
  • 自带forward():自带的forward里,通过for循环依次执行前向传播运算

3.2 nn.ModuleList

nn.ModuleList是nn.module的容器,用于包装一组网络层,以迭代方式调用网络层

主要方法:

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

例:我们使用ModuleList来循环迭代的实现一个20个全连接层的网络的构建。

'''-------- ModuleList----------'''
class ModuleList(nn.Module):
    def __init__(self):
        super(ModuleList, self).__init__()
        self.linears = nn.ModuleList([nn.Linear(10, 10) for i in range(20)])
    def forward(self, x):
        for i, linear in enumerate(self.linears):
            x = linear(x)
        return x
net = ModuleList()
print(net)
fake_data = torch.ones((10, 10))
output = net(fake_data)
print(output)

进入container的modulelist类

将网络层加入到module中

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

打印网络层,我们可以看到:


3.3 nn.ModuleDict

nn.ModuleDict是nn.module的容器,用于包装一组网络层,以索引方式调用网络层。

主要方法:

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

具体代码如下:

'''-----------ModuleDict---------------'''
class ModuleDict(nn.Module):
    def __init__(self):
        super(ModuleDict, self).__init__()
        self.choices = nn.ModuleDict({
            'conv': nn.Conv2d(10, 10, 3),
            '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
net = ModuleDict()
fake_img = torch.randn((4, 10, 32, 32))
output = net(fake_img, 'conv', 'relu')    # 在这里可以选择我们的层进行组合
print(output)

上面通过self.choices这个ModuleDict可以选择卷积或者池化

下面通过self.activations这个ModuleDict可以选取是用哪个激活函数

这在选择网络层的时候挺实用,比如要做时间序列预测的时候,我们往往会用到GRU或者LSTM, 我们就可以通过这种方式来对比哪种网络的效果好。 而具体选择哪一层是前向传播那完成,会看到多了两个参数。

打印网络层,我们可以看到:


容器总结

nn.sequential:顺序性,各网络层之间严格按照顺序执行,常用于block构建

nn.ModuleList:迭代性,常用于大量重复网络构建,通过for循环实现重复构建

nn.ModuleDict:索引性,常用于可选择的网络层


四、 AlexNet构建

关于AlexNet的网络结构详解可参考我这篇文章:经典神经网络论文超详细解读(一)——AlexNet学习笔记(翻译+精读)

下面看看AlexNet的源代码:

class AlexNet(nn.Module):
    def __init__(self, num_classes=1000):
        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):
        x = self.features(x)
        x = self.avgpool(x)
        x = torch.flatten(x, 1)
        x = self.classifier(x)
        return x

本文参考:

[PyTorch 学习笔记] 3.1 模型创建步骤与 nn.Module - 知乎 (zhihu.com)

Pytorch基础学习(第三章-Pytorch模型搭建)_nn.maxpool2d(2)

相关文章
|
3月前
|
机器学习/深度学习 存储 PyTorch
Neural ODE原理与PyTorch实现:深度学习模型的自适应深度调节
Neural ODE将神经网络与微分方程结合,用连续思维建模数据演化,突破传统离散层的限制,实现自适应深度与高效连续学习。
213 3
Neural ODE原理与PyTorch实现:深度学习模型的自适应深度调节
|
2月前
|
边缘计算 人工智能 PyTorch
130_知识蒸馏技术:温度参数与损失函数设计 - 教师-学生模型的优化策略与PyTorch实现
随着大型语言模型(LLM)的规模不断增长,部署这些模型面临着巨大的计算和资源挑战。以DeepSeek-R1为例,其671B参数的规模即使经过INT4量化后,仍需要至少6张高端GPU才能运行,这对于大多数中小型企业和研究机构来说成本过高。知识蒸馏作为一种有效的模型压缩技术,通过将大型教师模型的知识迁移到小型学生模型中,在显著降低模型复杂度的同时保留核心性能,成为解决这一问题的关键技术之一。
|
4月前
|
PyTorch 算法框架/工具 异构计算
PyTorch 2.0性能优化实战:4种常见代码错误严重拖慢模型
我们将深入探讨图中断(graph breaks)和多图问题对性能的负面影响,并分析PyTorch模型开发中应当避免的常见错误模式。
314 9
|
6月前
|
机器学习/深度学习 存储 PyTorch
PyTorch + MLFlow 实战:从零构建可追踪的深度学习模型训练系统
本文通过使用 Kaggle 数据集训练情感分析模型的实例,详细演示了如何将 PyTorch 与 MLFlow 进行深度集成,实现完整的实验跟踪、模型记录和结果可复现性管理。文章将系统性地介绍训练代码的核心组件,展示指标和工件的记录方法,并提供 MLFlow UI 的详细界面截图。
306 2
PyTorch + MLFlow 实战:从零构建可追踪的深度学习模型训练系统
|
6月前
|
机器学习/深度学习 PyTorch 算法框架/工具
提升模型泛化能力:PyTorch的L1、L2、ElasticNet正则化技术深度解析与代码实现
本文将深入探讨L1、L2和ElasticNet正则化技术,重点关注其在PyTorch框架中的具体实现。关于这些技术的理论基础,建议读者参考相关理论文献以获得更深入的理解。
205 4
提升模型泛化能力:PyTorch的L1、L2、ElasticNet正则化技术深度解析与代码实现
|
5月前
|
机器学习/深度学习 数据可视化 PyTorch
Flow Matching生成模型:从理论基础到Pytorch代码实现
本文将系统阐述Flow Matching的完整实现过程,包括数学理论推导、模型架构设计、训练流程构建以及速度场学习等关键组件。通过本文的学习,读者将掌握Flow Matching的核心原理,获得一个完整的PyTorch实现,并对生成模型在噪声调度和分数函数之外的发展方向有更深入的理解。
2403 0
Flow Matching生成模型:从理论基础到Pytorch代码实现
|
7月前
|
机器学习/深度学习 搜索推荐 PyTorch
基于昇腾用PyTorch实现CTR模型DIN(Deep interest Netwok)网络
本文详细讲解了如何在昇腾平台上使用PyTorch训练推荐系统中的经典模型DIN(Deep Interest Network)。主要内容包括:DIN网络的创新点与架构剖析、Activation Unit和Attention模块的实现、Amazon-book数据集的介绍与预处理、模型训练过程定义及性能评估。通过实战演示,利用Amazon-book数据集训练DIN模型,最终评估其点击率预测性能。文中还提供了代码示例,帮助读者更好地理解每个步骤的实现细节。
|
4月前
|
Kubernetes Docker Python
Docker 与 Kubernetes 容器化部署核心技术及企业级应用实践全方案解析
本文详解Docker与Kubernetes容器化技术,涵盖概念原理、环境搭建、镜像构建、应用部署及监控扩展,助你掌握企业级容器化方案,提升应用开发与运维效率。
845 108

推荐镜像

更多