Pytorch中模型构建

一.模型构建

Pytorch中模型均问类Module的子类的实例,一个特定的网络层是一个Module子类的实例,而整个网络也是一个Module子类的实例,例子如下:

构建一个LeNet网络

net = LeNet(classes=2)

实际上这一步是使用Module类的子类LeNet构建了一个LeNet类net,LeNet类则由我们自己定义(这里Pytorch库已经帮我们定义好了,但我们自己搭建网络的时候需要自己定义,这个定义过程就是构建网络的过程)

LeNet类的定义

class LeNet(nn.Module):
    def __init__(self, classes):
        #使用super调用父类中的init函数对LeNet进行初始化,初始化后LeNet类的8个nn.Module属性都是空的
        super(LeNet, self).__init__()
        #构建网络子模块,存储到LeNet的module属性中
        #这种conv1的卷积层和fc1的全连接层也是一个Module的子类,其中已经预定好了相关的Module属性
        #这种子模块的module属性一般为空,即其中不再包含更小的子模块,而parameters中则存储了相关的权值等属性
        #nn.Conv2d(3,6,5)只是实现了一个卷积层的实例化,而赋值给self.conv1才实现了该卷积层到LeNet的module属性中的添加
        #这里进行赋值时其实会被setattr函数拦截,对赋值的数据类型进行判断,如果是module类或者其子类,则赋值给LeNet的module中
        #module这个属性其实是一个字典,赋值操作就是想该字典中添加键值对,键就是conv1,值就是nn.Conv2d(3,6,5)这个卷积层实例
        #赋值时候如果判断数据类型为Parameter类,则会存储到LeNet中的Parameter字典(即Parameter属性)中
        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
        
    #进行权值初始化
    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_()

使用父类Module中的init函数进行LeNet的初始化,super(LeNet, self).init(),初始化函数如下:

class Module:
 
...

    def __init__(self):
        """
        Initializes internal Module state, shared by both nn.Module and ScriptModule.
        """
        torch._C._log_api_usage_once("python.nn_module")

        #对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()

其中,对于self.conv1 = nn.Conv2d(3, 6, 5)这一句,其实也是在使用Module子类Conv2d实例化了一个2维卷积层conv1,Module类与Conv2d类的关系如下:
Module类->_ConvNd类->Conv2d类

二.模型容器

在这里插入图片描述
1.Sequential

# ============================ Sequential
#===============================网络层不带名称的Sequential容器===============
class LeNetSequential(nn.Module):
    def __init__(self, classes):
        super(LeNetSequential, self).__init__()

        #将卷积池化包装为特征提取器
        #此时多个网络层组成一个列表输入到Sequential函数中,会默认以序号0,1,2..索引
        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),)

    #包装后,forward就非常简单,只要在包装后的模块间传递就可以,不用每层的传递都要写
    def forward(self, x):
        x = self.features(x)
        x = x.view(x.size()[0], -1)
        x = self.classifier(x)
        return x

#===============================网络层带名称的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

2.ModuleList

# ============================ ModuleList
#采用ModuleList构建一个20层的全连接层神经网路
class ModuleList(nn.Module):
    def __init__(self):
        super(ModuleList, self).__init__()
        #通过迭代构建模型,这里构建了一个20层的全连接层
        self.linears = nn.ModuleList([nn.Linear(10, 10) for i in range(20)])

    def forward(self, x):
        #对于ModuleList,可以通过迭代进行前向传播
        for i, linear in enumerate(self.linears):
            x = linear(x)
        return x

3.ModuleDict

# ============================ ModuleDict
#通过ModuleDict构建可以选择的网络层
class ModuleDict(nn.Module):
    def __init__(self):
        super(ModuleDict, self).__init__()
        #构建一个choices的网络层字典,具备conv和pool两个可选择的网络层
        self.choices = nn.ModuleDict({
            'conv': nn.Conv2d(10, 10, 3),
            'pool': nn.MaxPool2d(3)
        })

        #构建一个activations的网络层字典,具备ReLU()和PReLU两个可选择的激活函数
        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))
#在对ModuleDIct网络进行前向传播时,需要传入对应字典键名来选择对相的网络
output = net(fake_img, 'conv', 'relu')

print(output)

三.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值