chainer-骨干网络backbone-MobileNet_V1代码重构【附源码】


前言

本文基于chainer实现MobileNet_V1网络结构,并基于torch的结构方式构建chainer版的,并计算MobileNet_V1的参数量。


代码实现

class Block(chainer.Chain):
    def __init__(self, layers_num,in_planes, out_planes, stride=1,initialW=None):
        super(Block, self).__init__()
        self.layers=[]
        # 深度卷积,通道数不变,用于缩小特征图大小  dw
        self.layers += [('block{0}_conv1'.format(layers_num),L.Convolution2D(in_channels = in_planes, out_channels = in_planes, ksize=3, stride=stride, pad=1, groups=in_planes, nobias=True,initialW=initialW))]
        self.layers += [('block{0}_bn1'.format(layers_num),L.BatchNormalization(in_planes))]
        self.layers += [('_block{0}_relu1'.format(layers_num),ReLU())]
        # 逐点卷积,用于增大通道数   pw
        self.layers += [('block{0}_conv2'.format(layers_num),L.Convolution2D(in_channels = in_planes, out_channels = out_planes, ksize=1, stride=1, pad=0, nobias=True,initialW=initialW))]
        self.layers += [('block{0}_bn2'.format(layers_num),L.BatchNormalization(out_planes))]
        self.layers += [('_block{0}_relu2'.format(layers_num),ReLU())]
        
        with self.init_scope():
            for n in self.layers:
                if not n[0].startswith('_'):
                    setattr(self, n[0], n[1])
                
    def forward(self, x):
        for n, f in self.layers:
            if not n.startswith('_'):
                x = getattr(self, n)(x)
            else:
                x = f.apply((x,))[0]
        return x
 
class MobileNet_V1(chainer.Chain):
    cfgs={
        'mobilenetv1_1.0':{'alpha':1.0},
        'mobilenetv1_0.75':{'alpha':0.75},
        'mobilenetv1_0.5':{'alpha':0.5},
        'mobilenetv1_0.25':{'alpha':0.25}
    }
    
    def _make_layers(self, model_name, in_planes,initialW=None,in_size=None):
        list_layers = [64, (128,2), 128, (256,2), 256, (512,2), 512, 512, 512, 512, 512, (1024,2), 1024]
        output_size = in_size
        layers = []
        layers_num=1
        for x in list_layers:
            out_planes = int((x if isinstance(x, int) else x[0])*self.cfgs[model_name]['alpha'])
            stride = 1 if isinstance(x, int) else x[1]
            layers += [("MVblock_{0}".format(layers_num),Block(layers_num,in_planes, out_planes, stride,initialW=initialW))]
            in_planes = out_planes
            layers_num += 1
            output_size = int((output_size-3+2*1)/stride +1)
            output_size = int((output_size-1+2*0)/1 +1)
        
        return layers,output_size
    
    def __init__(self, model_name='mobilenetv1_1.0',channels=3, num_classes=1000,image_size=224,initialW=chainer.initializers.HeNormal(), **kwargs):
        super(MobileNet_V1, self).__init__()
        self.image_size = image_size
        self.features = []
        # 首先是一个标准卷积:卷极+标准化+激活函数
        self.features += [('conv2d_1',L.Convolution2D(in_channels = channels, out_channels = int(32*self.cfgs[model_name]['alpha']), ksize=3, stride=2, pad=1, nobias=True,initialW=initialW))]
        output_size = int((self.image_size-3+2*1)/2 +1)
        self.features += [('bn1',L.BatchNormalization(int(32*self.cfgs[model_name]['alpha'])))]
        self.features += [('_relu1',ReLU())]
        
        # 然后堆叠深度可分离卷积
        layers,output_size = self._make_layers(model_name=model_name,in_planes=int(32*self.cfgs[model_name]['alpha']),initialW=initialW,in_size=output_size)
        self.features += layers

        # 全局平均池化层会将feature 展平
        self.features += [('_avgpool',AveragePooling2D(ksize=output_size,stride=2,pad=0))]
        self.features += [('fc',L.Linear(int(1024*self.cfgs[model_name]['alpha']), num_classes,initialW=initialW))]
        
        with self.init_scope():
            for n in self.features:
                if not n[0].startswith('_'):
                    setattr(self, n[0], n[1])
        
    def forward(self, x):
        for n, f in self.features:
            origin_size = x.shape
            if not n.startswith('_'):
                x = getattr(self, n)(x)
            else:
                x = f.apply((x,))[0]
            print(n,origin_size,x.shape)
        if chainer.config.train:
            return x
        return F.softmax(x)

注意此类就是MobileNet_V1的实现过程,注意网络的前向传播过程中,分了训练以及测试。
训练过程中直接返回x,测试过程中会进入softmax得出概率

调用方式


if __name__ == '__main__':
    batch_size = 4
    n_channels = 3
    image_size = 224
    num_classes = 123
    
    model_simple = MobileNet_V1(num_classes=num_classes, channels=n_channels,image_size=image_size)
    print(model_simple.count_params())
    
    x = np.random.rand(batch_size, n_channels, image_size, image_size).astype(np.float32)
    
    t = np.random.randint(0, num_classes, size=(batch_size,)).astype(np.int32)
    with chainer.using_config('train', True):
        y1 = model_simple(x)
    loss1 = F.softmax_cross_entropy(y1, t)
    print(loss1.data)

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱学习的广东仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值