Pytorch基础——从nn.module转写成.py脚本(一)

Pytorch基础——从nn.module转写成.py脚本(一)

简介

起因还是在做AutoML,中间有小伙伴需要改写模型中channel的数量,希望能将模型channel变成一个变量,这需要改动torch定义的model类的脚本文件,所以想能不能根据传入的model,自动生成.py的脚本。

代码

为了测试代码,我们先写一个model.py文件生成一个简单地模型。

# model.py

import torch
import torch.nn as nn


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

        self.input = nn.Sequential(
            nn.Conv2d(1,16,3,1),
            nn.BatchNorm2d(16),
        )

        self.convs = nn.Sequential(
            nn.Conv2d(16,100,3),
            nn.ReLU(),
            nn.Conv2d(100,100,3),
            nn.BatchNorm2d(16),
            nn.Conv2d(100,100,3),
            nn.MaxPool2d(2),
            nn.Conv2d(100,100,3),            
        )
        self.out = nn.Linear(100,10)
        self.initialize()
    
    def initialize(self,):
        pass

    def forward(self, x):

        x = self.input(x)
        x2 = self.convs(x)
        x = x + x2
        x = self.out(x)

        return x

if __name__ == "__main__":
    model = Model()
    print(model.named_modules)

上面这部分就不多说了,下面是正文。新建一个文件,我们暂且命名为autoCode.py

from model import Model

model = Model()

先导入刚才构建的模型类,实例一个model出来。
为了简单起见,我们手工定义一下文件头部的内容

global tab
tab  = '    '
model_name = str(model.__class__.__name__)
file = './script/'+ model_name +'.py'
file_head = '# -*-coding:utf-8-*-\n\nimport torch\nimport torch.nn as nn\n\nclass '\
                + str(model.__class__.__name__)+'(nn.Module):\n'+tab+'def __init__(self,):\n'+tab+tab\
                + 'super(' + model_name + ', self).__init__()\n'

因为pytorch中是通过_module子模块对nn.module进行层层封装来得到最终的模型的,我们对它写一个递归调用,来获取每一个封装里的子操作。需要说明的是,._module是一个orderedDict类型变量,因此可以用.items()来得到它的key和value,其中key就是这个操作层的名字,value就是具体的操作,如value: Conv2d(…),我们要生成的代码就是value部分的内容。不过在torch定义中这些操作都在torch.nn这个类下,因此需要在value前面加上nn.

def nn_replace(model):
    global tab
    script = ''
    tmp_script = ''
    if len(model._modules) == 0:
        # name, m = model.named_modules()
        # print('module: nn.{},'.format(str(model)))
        script += 'nn.{},\n'.format(str(model))
        return script, tmp_script
        # model.pop(name)
    else:
        for n,m in model._modules.items():
            name = n
            s,_ = nn_replace(m)
            script += s
            try:
                int(n)
                continue
            except ValueError:
                pass
            # print('name: {}'.format(name))
            script = 'self.' + name + ' = nn.Sequential(' + script + ')\n'
            tmp_script += tab + tab + script
            script = ''
    return script, tmp_script

最后我们调用上述函数,返回script,并添加到head_script里,一起写到文件里看看

_, script = nn_replace(model)
print(script)

file_head += script
with open(file,'w') as f:
    f.write(file_head)

out: self.input = nn.Sequential(nn.Conv2d(1, 16, kernel_size=(3, 3), stride=(1, 1)),
nn.BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
)
self.convs = nn.Sequential(nn.Conv2d(16, 100, kernel_size=(3, 3), stride=(1, 1)),
nn.ReLU(),
nn.Conv2d(100, 100, kernel_size=(3, 3), stride=(1, 1)),
nn.BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
nn.Conv2d(100, 100, kernel_size=(3, 3), stride=(1, 1)),
nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False),
nn.Conv2d(100, 100, kernel_size=(3, 3), stride=(1, 1)),
)
self.out = nn.Sequential(nn.Linear(in_features=100, out_features=10, bias=True),
)

结果

生成的代码保存在./script/目录下,文件名与之前实例化的模型的l类名称相同,这里是Model.py

# -*-coding:utf-8-*-

import torch
import torch.nn as nn

class Model(nn.Module):
    def __init__(self,):
        super(Model, self).__init__()
        self.input = nn.Sequential(nn.Conv2d(1, 16, kernel_size=(3, 3), stride=(1, 1)),
nn.BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
)
        self.convs = nn.Sequential(nn.Conv2d(16, 100, kernel_size=(3, 3), stride=(1, 1)),
nn.ReLU(),
nn.Conv2d(100, 100, kernel_size=(3, 3), stride=(1, 1)),
nn.BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
nn.Conv2d(100, 100, kernel_size=(3, 3), stride=(1, 1)),
nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False),
nn.Conv2d(100, 100, kernel_size=(3, 3), stride=(1, 1)),
)
        self.out = nn.Sequential(nn.Linear(in_features=100, out_features=10, bias=True),
)

可以看到对的不齐,但并不关心。括号内部的空格都会被忽略。试验一下这个代码能不能生成模型,在下面添加以下内容:

if __name__ == "__main__":
    model = Model()
    print(model)

结果如下:

Model(
(input): Sequential(
(0): Conv2d(1, 16, kernel_size=(3, 3), stride=(1, 1))
(1): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
(convs): Sequential(
(0): Conv2d(16, 100, kernel_size=(3, 3), stride=(1, 1))
(1): ReLU()
(2): Conv2d(100, 100, kernel_size=(3, 3), stride=(1, 1))
(3): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(4): Conv2d(100, 100, kernel_size=(3, 3), stride=(1, 1))
(5): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(6): Conv2d(100, 100, kernel_size=(3, 3), stride=(1, 1))
)
(out): Sequential(
(0): Linear(in_features=100, out_features=10, bias=True)
)
)

it works.
这个小脚本只解决了部分简单地网络模型到代码生成的问题,对于其中的channel还没有自动改成变量,后续组里小伙伴如果想到了再更新吧。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值