D3 Pytorch模型定义


1. 模型定义方式

  • Sequential
  • ModuleList
  • ModuleDict

1.1 nn.Sequential()

nn.Sequential()使用方法:

  • 直接排列
net1 = nn.Sequential(
                    nn.Linear(784, 256),
                    nn.ReLU(),
                    nn.Linear(256, 10),
                    )
  • 使用collections.OrderedDict
net2 = nn.Sequential(collections.OrderedDict([
    ('fc1',nn.Linear(784, 256)),
    ('relu1',nn.ReLU())
]))
net2.fc2 = nn.Linear(256, 10)  #  net2['fc2'] = nn.Linear(256, 10)        
Sequential(
  (fc1): Linear(in_features=784, out_features=256, bias=True)
  (relu1): ReLU()
  (fc2): Linear(in_features=256, out_features=10, bias=True)
)

[补充] 关于nn.Sequential()如何实现层之间级联的代码示意:

  1. __init__()中分别对 直接排列的层 和 OrderDict 中的层 利用 add_module方法添加进self._modules(一个OrderedDict)
  2. forward() : self._modules返回一个 OrderedDict, 在forward() 按照添加顺序遍历
from collections import OrderedDict
class MySequential(nn.Module):
    def __init__(self, *args):
        super(MySequential, self).__init__()
        if len(args) == 1 and isinstance(args[0], OrderedDict): # 如果传入的是一个OrderedDict
            for key, module in args[0].items():
                self.add_module(key, module)  
                # add_module方法会将module添加进self._modules(一个OrderedDict)
        else:  # 传入的是一些Module
            for idx, module in enumerate(args):
                self.add_module(str(idx), module)
                
    def forward(self, input):
        # self._modules返回一个 OrderedDict,保证会按照成员添加时的顺序遍历
        for module in self._modules.values():
            input = module(input)
        return input

nn.Sequential()官网介绍


1.2 nn.ModuleList() & nn.ModuleDict()

ModuleDict官网介绍 可通过遍历keys(): Return an iterable of the ModuleDict keys.实现forward()
ModuleList官网介绍

[注] 不同于nn.Sequential()nn.ModuleList()nn.ModuleDict()需定义forward()函数。

class Net3(nn.Module):
    def __init__(self):
        super().__init__()
        self.moduledict = nn.ModuleDict({
            'fc1': nn.Linear(784, 256),
            'relu1': nn.ReLU()}
        )
        self.moduledict['fc2'] = nn.Linear(256, 10)
        
    def forward(self, x):
#         x = self.moduledict['fc1'](x)
#         x = self.moduledict['relu1'](x)
#         x = self.moduledict['fc2'](x)
        for key in self.moduledict.keys():
            x = self.moduledict[key](x)
        return x
    
class Net4(nn.Module):
    def __init__(self):
        super().__init__()
        self.modulelist = nn.ModuleList([nn.Linear(784, 256), nn.ReLU()])
        self.modulelist.append(nn.Linear(256, 10))
        
    def forward(self, x):
        for layer in self.modulelist:
            x = layer(x)
        return x
    
net3 = Net3()
net4 = Net4()

out3 = net3(x)
out4 = net4(x)

net3, out3, net4, out4
(Net3(
   (moduledict): ModuleDict(
     (fc1): Linear(in_features=784, out_features=256, bias=True)
     (relu1): ReLU()
     (fc2): Linear(in_features=256, out_features=10, bias=True)
   )
 ),
 tensor([[-0.2505,  0.3850,  0.2285, -0.2629,  0.4223, -0.1359, -0.0014, -0.0182,
           0.2301, -0.2082],
         [-0.2505,  0.3850,  0.2285, -0.2629,  0.4223, -0.1359, -0.0014, -0.0182,
           0.2301, -0.2082],
         [-0.2505,  0.3850,  0.2285, -0.2629,  0.4223, -0.1359, -0.0014, -0.0182,
           0.2301, -0.2082],
         [-0.2505,  0.3850,  0.2285, -0.2629,  0.4223, -0.1359, -0.0014, -0.0182,
           0.2301, -0.2082]], grad_fn=<AddmmBackward0>),
 Net4(
   (modulelist): ModuleList(
     (0): Linear(in_features=784, out_features=256, bias=True)
     (1): ReLU()
     (2): Linear(in_features=256, out_features=10, bias=True)
   )
 ),
 tensor([[-0.0620,  0.1596, -0.1370,  0.3433, -0.1042, -0.1538, -0.0203, -0.2982,
          -0.0164, -0.3869],
         [-0.0620,  0.1596, -0.1370,  0.3433, -0.1042, -0.1538, -0.0203, -0.2982,
          -0.0164, -0.3869],
         [-0.0620,  0.1596, -0.1370,  0.3433, -0.1042, -0.1538, -0.0203, -0.2982,
          -0.0164, -0.3869],
         [-0.0620,  0.1596, -0.1370,  0.3433, -0.1042, -0.1538, -0.0203, -0.2982,
          -0.0164, -0.3869]], grad_fn=<AddmmBackward0>))

PyTorch 中的 ModuleList 和 Sequential: 区别和使用场景


2. 搭建复杂网络

组装U-Net!

U-Net搭建.ipynb

几点讨论:

  • 卷积中的padding值的设置问题
    设置padding=0(默认值),符合U-Net网络结构原图,窄卷积,尺寸减少,之后上采样拼接过程中需添加裁剪的代码。
    设置padding=1(教程示范代码),等宽卷积,尺寸不变,后续上采样过程中无需实现裁剪操作。

  • 在上采样过程中使用了两种方法

    1. nn.Upsamplenn.Upsample解析):采用线性插值(mode=‘bilinear’),宽高变成两倍(scale_factor=2),但使用nn.Upsample通道数不会发生变化,需在后续双层卷积操作中调整。
    2. nn.ConvTranspose2d : 转置卷积,设置宽高翻倍,通道减半。
  • 关于上采样中拼接部分分析:
    在Up类定义的forward中,完成上采样和拼接操作。
    由于不是等宽卷积,拼接前需要对两个特征图x1和x2进行宽高的匹配。
    对尺寸较小的x1进行扩充,采用F.pad() (形象理解参考F.pad() ),实现分别在宽和高两个维度的左右两侧均匀的补零操作。接着便可以用torch.cat()dim=1即在通道channel上拼接。


3. 修改模型

3.1 修改模型若干层

如修改ResNet50模型最后的fc层

  1. 定义替换 fc 层的分类器
from collections import OrderedDict
classifier = nn.Sequential(OrderedDict([('fc1', nn.Linear(2048, 128)),
                          ('relu1', nn.ReLU()), 
                          ('dropout1',nn.Dropout(0.5)),
                          ('fc2', nn.Linear(128, 10)),
                          ('output', nn.Softmax(dim=1))
                          ]))
  1. 替换ResNet50的fc层
net.fc = classifier

3.2 添加外部输入

如在模型中添加额外的输入变量,可以通过torch.cat((x,add_x),dim=1)通道上拼接
此时需注意:

  1. 修改forward()中传入的参数,添加add_x
  2. __init__()中,修改输入拼接后会影响的层的参数,例如后一层的卷积的输入通道数

修改模型层.ipynb

3.3 添加额外输出

需要输出forward()过程中的中间变量,可在return中返回。
需要注意,此时实例化模型,传入数据后会得到两个(或多个)输出值

修改模型层.ipynb


4. 模型保存和读取

4.1 保存模型

存储模型主要采用pkl,pt,pth三种格式

关于.pt、.pth与.pkl 的区别:
PyTorch模型 .pt,.pth,.pkl 的区别 – 编码无悔 / Intent & Focused (codelast.com)
不存在格式上的区别,只是后缀名不同而已。在用torch.save()函数保存模型文件的时候,有些人喜欢用.pt后缀,有些人喜欢用.pth.pkl,用相同的 torch.save()语句保存出来的模型文件没有什么不同。
为什么会有 .pkl这种后缀名呢?因为Python有一个序列化模块 - pickle,使用它保存模型时,通常会起一个以 .pkl为后缀名的文件。torch.save()正是使用pickle来保存模型的。

pytorch的模型和参数是分开的,可以分别保存或加载模型和参数。

pytorch有两种模型保存方式

  1. 保存整个神经网络的的结构信息和模型参数信息,save的对象是网络net

  2. 只保存神经网络的训练模型参数,save的对象是net.state_dict()

# 保存整个模型
torch.save(model, save_dir)
# 保存模型权重
torch.save(model.state_dict, save_dir)

4.2 加载模型

对应两种保存模型的方式,pytorch也有两种加载模型的方式

  • 第一种保存方式,加载模型时通过torch.load('.pth')直接初始化新的神经网络对象;

  • 第二种保存方式,需要首先导入对应的网络,再通过net.load_state_dict(torch.load('.pth'))完成模型参数的加载。

具体又可以分为以下几种:

  • 单卡保存 + 单卡加载
  • 单卡保存 + 多卡加载
  • 多卡保存 + 单卡加载
  • 多卡保存 + 多卡加载

细节可参考深入浅出Pyotch_加载模型


@夏日回

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值