ShuffleNet V1代码和总结

针对1x1卷积数目增多后,导致有较大计算量的问题,采用1x1分组卷积,然而1x1卷积本身就只考虑了通道信息,若直接使用分组卷积会导致部分通道信息被忽视的问题,因此,需要在1x1分组卷积的基础上加入通道混洗再输入3x3卷积中获得相应特征信息。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码:

import torch
import torch.nn as nn

class Channel_Shuffle(nn.Module):
    def __init__(self,groups):
        super(Channel_Shuffle, self).__init__()
        self.groups = groups

    def forward(self,x):
        batch_size, channels, height, width = x.size()
        channels_per_group = channels // self.groups
        x = x.view(batch_size,self.groups,channels_per_group,height,width)
        x = x.transpose(1,2).contiguous()
        x = x.view(batch_size,-1,height,width)
        return x


class BLOCK(nn.Module):
    def __init__(self,inchannels,outchannels, stride,group):
        super(BLOCK, self).__init__()
        hidden_channels = outchannels//2
        self.shortcut = nn.Sequential()
        self.cat = True
        if stride == 1:
            self.conv = nn.Sequential(
                nn.Conv2d(inchannels,hidden_channels,1,1,groups = group),
                nn.BatchNorm2d(hidden_channels),
                nn.ReLU(inplace=True),
                Channel_Shuffle(group),
                nn.Conv2d(hidden_channels,hidden_channels,3,stride,1,groups=hidden_channels),
                nn.BatchNorm2d(hidden_channels),
                nn.Conv2d(hidden_channels,outchannels,1,1,groups=group),
                nn.BatchNorm2d(outchannels)
            )
            self.cat = False
        elif stride == 2:
            self.conv = nn.Sequential(
                nn.Conv2d(inchannels, hidden_channels, 1, 1, groups=group),
                nn.BatchNorm2d(hidden_channels),
                nn.ReLU(inplace=True),
                Channel_Shuffle(group),
                nn.Conv2d(hidden_channels, hidden_channels, 3, stride, 1, groups=hidden_channels),
                nn.BatchNorm2d(hidden_channels),
                nn.Conv2d(hidden_channels, outchannels-inchannels, 1, 1, groups=group),
                nn.BatchNorm2d(outchannels-inchannels)
            )
            self.shortcut = nn.Sequential(
                nn.AvgPool2d(kernel_size=3,stride=2,padding = 1)
            )
        self.relu = nn.ReLU(inplace=True)


    def forward(self,x):
        out = self.conv(x)
        x = self.shortcut(x)
        if self.cat:
            x = torch.cat([out,x],1)
        else:
            x = out+x
        return self.relu(x)


class Shuffle_v1(nn.Module):
    def __init__(self, classes,group = 1):
        super(Shuffle_v1, self).__init__()
        setting = {1:[3,24,144,288,576],
                   2:[3,24,200,400,800],
                   3:[3,24,240,480,960],
                   4:[3,24,272,544,1088],
                   8:[3,24,384,768,1536]}
        repeat = [3,7,3]
        channels = setting[group]

        self.conv1 = nn.Sequential(
            nn.Conv2d(channels[0],channels[1],3,2,1),
            nn.BatchNorm2d(channels[1]),
            nn.ReLU(inplace=True)
        )
        self.pool1 = nn.MaxPool2d(kernel_size=3,stride=2,padding=1)

        self.block = BLOCK
        self.stages = nn.ModuleList([])

        for i,j in enumerate(repeat):
            self.stages.append(self.block(channels[1+i],channels[2+i],stride=2, group = group))
            for _ in range(j):
                self.stages.append(self.block(channels[2 + i], channels[2 + i], stride=1, group=group))

        self.pool2 = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Sequential(
            nn.Dropout(0.2),
            nn.Linear(channels[-1],classes)
        )

        for m in self.modules():
            if isinstance(m,nn.Conv2d):
                nn.init.kaiming_normal_(m.weight,mode = 'fan_out')
                if m.bias is not None:
                    nn.init.zeros_(m.bias)
            elif isinstance(m,nn.BatchNorm2d):
                nn.init.ones_(m.weight)
                nn.init.zeros_(m.bias)
            elif isinstance(m,nn.Linear):
                nn.init.normal_(m.weight,0,0.01)
                nn.init.zeros_(m.bias)

    def forward(self,x):
        x = self.conv1(x)
        x = self.pool1(x)
        for stage in self.stages:
            x = stage(x)
        x = self.pool2(x)
        x = x.view(x.size(0),-1)
        x = self.fc(x)
        return x

if __name__ == '__main__':
    input = torch.empty((1,3,224,224))
    m = Shuffle_v1(10,8)
    out = m(input)
    print(out)


  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是ShuffleNetV1PyTorch代码实现,包括ShuffleNetV1的网络结构和训练代码: ```python import torch.nn as nn import math __all__ = ['ShuffleNetV1', 'shufflenetv1'] def conv3x3(in_planes, out_planes, stride=1): """3x3 convolution with padding""" return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, padding=1, bias=False) class BasicBlock(nn.Module): def __init__(self, inplanes, planes, stride=1, downsample=None): super(BasicBlock, self).__init__() self.conv1 = conv3x3(inplanes, planes, stride) self.bn1 = nn.BatchNorm2d(planes) self.relu = nn.ReLU(inplace=True) self.conv2 = conv3x3(planes, planes) self.bn2 = nn.BatchNorm2d(planes) self.downsample = downsample self.stride = stride def forward(self, x): residual = x out = self.conv1(x) out = self.bn1(out) out = self.relu(out) out = self.conv2(out) out = self.bn2(out) if self.downsample is not None: residual = self.downsample(x) out += residual out = self.relu(out) return out class ShuffleNetV1(nn.Module): def __init__(self, num_classes=1000, groups=3, width_mult=1): super(ShuffleNetV1, self).__init__() self.groups = groups self.stage_repeats = [3, 7, 3] if groups == 1: self.stage_out_channels = [-1, 24, 144, 288, 576] elif groups == 2: self.stage_out_channels = [-1, 24, 200, 400, 800] elif groups == 3: self.stage_out_channels = [-1, 24, 240, 480, 960] elif groups == 4: self.stage_out_channels = [-1, 24, 272, 544, 1088] elif groups == 8: self.stage_out_channels = [-1, 24, 384, 768, 1536] else: raise ValueError("""{} groups is not supported for 1x1 Grouped Convolutions""".format(num_groups)) # building first layer input_channels = 3 output_channels = self.stage_out_channels[1] output_channels = int(output_channels * width_mult) self.conv1 = nn.Conv2d(input_channels, output_channels, kernel_size=3, stride=2, padding=1, bias=False) self.bn1 = nn.BatchNorm2d(output_channels) self.relu = nn.ReLU(inplace=True) self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) # building stages self.stage2 = self._make_stage(2, width_mult) self.stage3 = self._make_stage(3, width_mult) self.stage4 = self._make_stage(4, width_mult) # building last several layers self.conv_last = nn.Conv2d(self.stage_out_channels[-2], self.stage_out_channels[-1], kernel_size=1, stride=1, padding=0, bias=False) self.globalpool = nn.AvgPool2d(7) self.fc = nn.Linear(self.stage_out_channels[-1], num_classes) def _make_stage(self, stage, width_mult): modules = OrderedDict() stage_name = "ShuffleUnit_Stage{}".format(stage) # stage_repeats = self.stage_repeats[stage] unit1 = ShuffleUnit(self.stage_out_channels[stage-1], self.stage_out_channels[stage], 2, groups=self.groups, width_mult=width_mult) modules[stage_name+"_unit1"] = unit1 for i in range(self.stage_repeats[stage-2]): name = stage_name + "_unit" + str(i+2) module = ShuffleUnit(self.stage_out_channels[stage], self.stage_out_channels[stage], 1, groups=self.groups, width_mult=width_mult) modules[name] = module return nn.Sequential(modules) def forward(self, x): x = self.conv1(x) x = self.bn1(x) x = self.relu(x) x = self.maxpool(x) x = self.stage2(x) x = self.stage3(x) x = self.stage4(x) x = self.conv_last(x) x = self.globalpool(x) x = x.view(-1, self.stage_out_channels[-1]) x = self.fc(x) return x class ShuffleUnit(nn.Module): def __init__(self, in_channels, out_channels, stride, groups=3, width_mult=1): super(ShuffleUnit, self).__init__() if stride != 1 or in_channels != out_channels: self.use_res_connect = False self.shortcut = nn.Sequential( nn.Conv2d(in_channels, in_channels, kernel_size=3, stride=stride, padding=1, groups=in_channels, bias=False), nn.BatchNorm2d(in_channels), nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=False), nn.BatchNorm2d(out_channels), nn.ReLU(inplace=True), ) else: self.use_res_connect = True self.shortcut = nn.Sequential() self.groups = groups mid_channels = int(out_channels / 4 * width_mult) self.conv1 = nn.Conv2d(in_channels, mid_channels, kernel_size=1, stride=1, padding=0, bias=False) self.bn1 = nn.BatchNorm2d(mid_channels) self.conv2 = nn.Conv2d(mid_channels, mid_channels, kernel_size=3, stride=stride, padding=1, groups=groups, bias=False) self.bn2 = nn.BatchNorm2d(mid_channels) self.conv3 = nn.Conv2d(mid_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=False) self.bn3 = nn.BatchNorm2d(out_channels) self.relu = nn.ReLU(inplace=True) def _channel_shuffle(self, x, groups): batchsize, num_channels, height, width = x.data.size() channels_per_group = num_channels // groups x = x.view(batchsize, groups, channels_per_group, height, width) x = torch.transpose(x, 1, 2).contiguous() x = x.view(batchsize, -1, height, width) return x def forward(self, x): if self.use_res_connect: shortcut = x x = self.conv1(x) x = self.bn1(x) x = self.relu(x) x = self.conv2(x) x = self.bn2(x) x = self.relu(x) x = self._channel_shuffle(x, self.groups) x = self.conv3(x) x = self.bn3(x) if self.use_res_connect: shortcut = self.shortcut(shortcut) x += shortcut x = self.relu(x) return x def shufflenetv1(**kwargs): """ Constructs a ShuffleNetV1 model """ return ShuffleNetV1(**kwargs) ``` 在使用ShuffleNetV1时,可以通过以下方式进行实例化: ```python import torch from shufflenetv1 import shufflenetv1 model = shufflenetv1(groups=3, width_mult=1) input = torch.randn(1, 3, 224, 224) output = model(input) print(output.shape) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值