pytorch学习笔记五:模型的创建

本文介绍了如何使用PyTorch构建深度学习模型,重点讲解了nn.Module类及其常用方法,包括nn.Sequential、nn.ModuleList和nn.ModuleDict。此外,还详细阐述了AlexNet网络的实现过程,探讨了其在缓解梯度消失问题上的创新策略。
摘要由CSDN通过智能技术生成

在上一节中整理了数据模块的知识点,在本节中主要围绕如何用pytorch构建一个模型来展开,最后用pytorch实现Alexnet网络结构的搭建。
在这里插入图片描述
下面基于上面的框架来探索每一个模块的实现细节。

一、模型的创建

在这里插入图片描述
上面是LetNet的网络图,由边和节点组成,节点表示输入的数据大小,而边就是数据之间的运算。从上面的LetNet的网络中可以看出,网络接受一个输入,然后经过运算得到一个输出,在网络结构的内部,又分为多个子网络层进行拼接组成,这些子网络层之间的拼接 配合,最终得到我们想要的输出。

所以通过上面的分析,可以得到构建模型的两大要素:
● 构建子模块(比如网络结构中的卷积层、池化层、激活层、全连接层);
● 拼接子模块(将子模块按照一定的顺序拼接起来,最终得到想到的网络结构)。

以人民币的二分类任务来构建LetNet网络结构:

class LeNet(nn.Module):
    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)

    def forward(self, x):
        # layer1: conv2d -> relu -> max_pool
        x = F.relu(self.conv1(x))
        x = F.max_pool2d(x, 2)

        # layer2: conv2d -> relu -> max_pool
        x = F.relu(self.conv2(x))
        x = F.max_pool2d(x, 2)

        # layer3: fc1 -> relu
        x = x.view(x.size(0), -1)
        x = F.relu(self.fc1(x))

        # layer4: fc2 -> relu
        x = F.relu(self.fc2(x))

        # layer5:fc3
        x = self.fc3(x)

        return x

    def initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.xavier_normal_(m.weight.data)
                if m.bias is not None:
                    m.bias.data.zero_()
            elif isinstance(m, nn.BatchNorm2d):
                m.weight.data.fill_(1)
                m.bias.data.zero_()
            elif isinstance(m, nn.Linear):
                nn.init.normal_(m.weight.data, 0, 0.1)
                m.bias.data.zero_()

从上面的代码里可看出,LeNet类继承了nn.Module,并且在__init__方法中实现了各个子模块的构建,所以构建模型的第一个要素—— 构建子模块在这里体现。
那子模块的拼接是怎么实现的呢?——LetNet类里面的forward方法,下面来调试代码,看如何调用forward方法来实现子模块的拼接操作。
在这里插入图片描述
主程序模型训练部分,在outputs = net(inputs)处打上断点,因为这里是模型开始训练的部分,此处也是模型开始正向传播的过程,debug如下:
在这里插入图片描述
程序进入module.py文件中的__call_impl函数,这是因为类LetNet继承了nn.Module。在这里会实现调用forward方法,把各个子模块拼接起来。

在构造模型中继承了 nn.Module 类,所有的网络层都是继承于这个类的。所以下面来详细了解一下nn.Module类。

二、nn.Module 类

1、nn.Module的简介

在这里插入图片描述
torch.nn: 这是 Pytorch 的神经网络模块,这里的 Module 就是它的子模块之一,另外还有几个与 Module 并列的子模块。其中nn.Module的自定义为:


class Module(object):
    def __init__(self):
        torch._C._log_api_usage_once("python.nn_module")

        self.training = True
        self._parameters = OrderedDict()
        self._buffers = OrderedDict()
        self._non_persistent_buffers_set = set()
        self._backward_hooks = OrderedDict()
        self._forward_hooks = OrderedDict()
        self._forward_pre_hooks = OrderedDict()
        self._state_dict_hooks = OrderedDict()
        self._load_state_dict_pre_hooks = OrderedDict()
        self._modules = OrderedDict()

    def register_parameter(self, name: str, param: Optional[Parameter]) -> None:
    def add_module(self, name: str, module: Optional['Module']) -> None:
    def get_parameter(self, target: str) -> "Parameter":
    def apply(self: T, fn: Callable[['Module'], None]) -> T:
    def cuda(self: T, device: Optional[Union[int, device]] = None) -> T:
    def cpu(self: T) -> T:
    def state_dict(self, destination=None, prefix='', keep_vars=False):
    def load_state_dict(self, state_dict: 'OrderedDict[str, Tensor]',
                        strict: bool = True):
    def named_parameters(self, prefix: str = '', 
                         recurse: bool = True) -> Iterator[Tuple[str, Parameter]]:
    def children(self) -> Iterator['Module']:
    def named_children(self) -> Iterator[Tuple[str, 'Module']]:
    def modules(self) -> Iterator['Module']:
    def named_modules(self, memo: Optional[Set['Module']] = None, 
                      prefix: str = '', remove_duplicate: bool = True):
    def train(self: T, mode: bool = True) -> T:
    def eval(self: T) -> T:
    ...
"""
还有一些其他的函数
"""

在nn.Module自定义中的属性:
● parameters:存储管理 nn.Parameter 类;
● modules:存储管理nn.Modules类;
● buffers:存储管理缓冲属性,如BN层中的running_mean;
● ***_hook:存储管理钩子函数
在这里插入图片描述

在构造网络结构是需要继承 nn.Module 类,并重新构造 __init__和forward两个方法,但需要注意的有:
● 一般将网络中具有可学习参数的层(如卷积层、全连接层)放在构造函数 __init__中,当然也可以把不具有参数的层也放在里面;
● 一般把不具有可学习参数的层(如ReLU、dropout、BatchNormanation层)可放在构造函数中,也可不放在构造函数中,如果不放在构造函数__init__里面,则在forward方法里面可以使用nn.functional来代替;
● forward方法是必须要重写的,它是实现模型的功能,实现各个层之间的连接关系的核心。

例如:
1、将所有的层都放在构造函数 __init__中,然后在forward中将这些层按顺序连接起来。

import torch.nn as nn

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

        self.conv1 = nn.Conv2d(3, 32, 3, 1, 1)
        self.relu1 = nn.ReLU()
        self.max_pooling1 = nn.MaxPool2d(2, 1)

        self.conv2 = nn.Conv2d(32, 32, 3, 1, 1)
        self.relu2 = nn.ReLU()
        self.max_pooling2 = nn.MaxPool2d(2, 1)
        
        self.dense1 = nn.Linear(32*3*3, 128)
        self.dense2 = nn.Linear(128, 10)

    def forward(self, x):
        x = self.conv1(x)
        x = self.relu1(x)
        x = self.max_pooling1(x)
        x = self.conv2(x)
        x = self.relu2(x)
        x = self.max_pooling2(x)
        x = self.dense1(x)
        x = self.dense2(x)
        return x

model = MyNet()
print(model)

输出结果:
在这里插入图片描述
2、将没有训练参数的层放到forward中,所以这些层没有出现在model中,但是在运行关系是在forward中通过torch.nn.function实现,如下:

import torch.nn.functional as F

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

        self.conv1 = nn.Conv2d(3, 32, 3, 1, 1)
        self.conv2 = nn.Conv2d(3, 32, 3, 1, 1)

        self.dense1 = nn.Linear(32 * 3 * 3, 128)
        self.dense2 = nn.Linear(128, 10)

    def forward(self, x):
        x = self.conv1(x)
        x = F.relu(x)
        x = F.max_pool2d(x)
        x = self.conv2(x)
        x = F
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值