首页 > 编程知识 正文

shuffle播放器,如何复现论文代码

时间:2023-05-06 09:25:22 阅读:38588 作者:256

ShuffleNet-V2论文理解及代码再现目录ShuffleNet-V2论文理解及代码再现文章速一览、论文理解一、关键点及实验二、体系结构设计二、代码再现一、通道spilt及shuffle操作二、2.bottion

本文总结了Shufflenet-V2对Shuffle-V1的改进,并用Pytorch1.8再现了其代码。 以下是论文地址和参考代码地址,以供学习和参考。

论文地址

参照代码地址

提示:以下为本文正文内容,以下案例可供参考

一、论文理解1 .关键和实验本文指出用间接指标FLOPs衡量模型结构速度是不完善的,提出了模型应该用目标平台上运行时间等指标来衡量,使用“平衡”卷积的四种网络结构设计原则; 减少元素操作,以降低了解组卷使用成本的碎片程度。

1 )为了节省内存访问的成本,保证了在深度为3*3的可分离卷积之前的定点加权卷积中输入/输出信道不会改变。 在这里,我们设计了通过将pointwise卷积输入输出的比例变为1、2、6、12来验证该原则的实验。 下图为实验结果。 实验结果表明,当c1:c2接近1:1时,MAC变小,网络评估速度加快。

2 )过度的组卷积会增加内存访问成本。 在此设定不同的组卷积数1、2、4、8来评价执行时间,在GPU中使用8组比使用1组慢2倍以上。 其实验结论如下:建议根据目标平台和任务谨慎选择分组号码。 加大组数是不明智的。 因为准确性的提高容易被快速增长的计算成本抵消,所以可能会使用更多的通道。

3 )网络碎片化降低了并行度。 虽然这种碎片结构已被证明有助于提高精度,但由于不利于GPU等具有强大并行处理能力的设备,因此可能会降低效率。 还引入了内核启动和同步等开销。 在此,设计了不同分片操作对执行时间的影响。 实验结果表明,切片在GPU上明显减慢速度,例如4个切片结构比1个切片结构慢3倍。

4 )元素操作需要时间。 GPU上的元素操作符包括ReLU、AddTensor、AddBias等。 这里,我们比较了GPU在ReLU和短cut操作上的运行时间,发现删除ReLU和快捷方式后,GPU和ARM都获得了约20%的加速。

2 .针对以上优化原则,本文设计了其基本模块。

1 )基本的bottleblock设计:

在不降维的block模块中,通过输入扩展通道的分割操作将输入轮廓分为两部分,满足(3)的原则减少网络碎片,一侧的轮廓通过三个输入和输出相等的卷积层。 其中,点wise卷积不再采用组卷积方法,(2)过多的组卷积会加重MAC,然后连接两个配置文件执行shuffle操作。 其他shufflenet-V2放弃添加和ReLU操作,原则上(4)满足元素操作占用时间。

在下采样的bottleblock模块中,去除了信道分割操作,继承了Densenet的紧密耦合思想,使下采样层成为33深度可分离卷积和11卷积的组合,输出信道增加了一倍。 在此作者比较了Densenet和shufflenet-V2之间特征重用的关系,发现特征重用的数量随两个块之间的距离呈指数衰减。

2 )整体网络结构

二、代码再现1 .通道spilt及shuffle操作代码如下:

defchannel_shuffle(self,x ) : batchsize,num_channels,height,width=x.data.size(assert ) num_channels heiize 2) x=x.reshape(2,-1,num_channels //2,height,width ) return x[0],x[1] 2.bottleblock的实现代码如下

classbottleblock(nn.module ) :def_init_(self,in_channel,out_channel,mid_channel, stride ) ) self(__init__ ) ) elf.mid channel=mid _ channel output=out _ channel-in _ channel self.stride

, nn.ReLU(inplace=True)) self.depth_conv=nn.Sequential(nn.Conv2d(in_channels=mid_channel,out_channels=mid_channel,kernel_size=3,padding=1,stride=stride,groups=mid_channel,bias=False), nn.BatchNorm2d(mid_channel)) self.pointwise_conv2=nn.Sequential(nn.Conv2d(in_channels=mid_channel,out_channels=output,kernel_size=1,stride=1,bias=False), nn.BatchNorm2d(output), nn.ReLU(inplace=True)) if stride==2: self.shortcut=nn.Sequential(nn.Conv2d(in_channels=in_channel,out_channels=in_channel,kernel_size=3,padding=1,stride=stride,groups=in_channel,bias=False), nn.BatchNorm2d(in_channel), nn.Conv2d(in_channels=in_channel,out_channels=in_channel,kernel_size=1,stride=1,bias=False), nn.BatchNorm2d(in_channel), nn.ReLU(inplace=True)) else: self.shortcut=nn.Sequential() def channel_shuffle(self, x): batchsize, num_channels, height, width = x.data.size() assert (num_channels % 4 == 0) x = x.reshape(batchsize * num_channels // 2, 2, height * width) x = x.permute(1, 0, 2) x = x.reshape(2, -1, num_channels // 2, height, width) return x[0], x[1] def forward(self,x): if self.stride==2: residual=self.shortcut(x) x=self.pointwise_conv1(x) x=self.depth_conv(x) x=self.pointwise_conv2(x) return torch.cat((residual,x),dim=1) elif self.stride==1: x1,x2=self.channel_shuffle(x) residual=self.shortcut(x2) x1=self.pointwise_conv1(x1) x1=self.depth_conv(x1) x1=self.pointwise_conv2(x1) return torch.cat((residual,x1),dim=1) 3.网络实现

代码如下:

class shufflenet(nn.Module): def __init__(self,num_class,size): """size表示模型大小""" super(shufflenet, self).__init__() self.num_class=num_class self.inchannel=24 if size==0.5: stage_dict={'bolck_num':[4,8,4], 'outchannel':[48,96,192], 'last_conv':1024, 'size':size} elif size==1: stage_dict = {'bolck_num': [4, 8, 4], 'outchannel': [116, 232, 464], 'last_conv': 1024, 'size':size} elif size==1.5: stage_dict = {'bolck_num': [4, 8, 4], 'outchannel': [176, 352, 704], 'last_conv': 1024, 'size':size} elif size==2: stage_dict = {'bolck_num': [4, 8, 4], 'outchannel': [244, 488, 976], 'last_conv': 2048, 'size':size} block_num=stage_dict['bolck_num'] outchannel=stage_dict['outchannel'] last_conv=stage_dict['last_conv'] self.initial=nn.Sequential(nn.Conv2d(kernel_size=3,padding=1,in_channels=3,out_channels=24,stride=2), nn.BatchNorm2d(24), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=3,stride=2,padding=1)) self.layer1 = self.make_layer(block_num[0],outchannel[0]) self.layer2 = self.make_layer(block_num[1], outchannel[1]) self.layer3 = self.make_layer(block_num[2], outchannel[2]) self.last_conv=nn.Conv2d(in_channels=outchannel[2],out_channels=last_conv,stride=1,kernel_size=1,bias=False) self.pool=nn.AdaptiveAvgPool2d(1) self.fc=nn.Linear(last_conv,num_class) def make_layer(self,block_num,outchannel): layer_list=[] for i in range(block_num): if i==0: stride=2 layer_list.append(bottleblock(self.inchannel,outchannel,outchannel//2,stride=stride)) self.inchannel=outchannel else: stride=1 layer_list.append(bottleblock(self.inchannel//2,outchannel,outchannel//2,stride=stride)) return nn.Sequential(*layer_list) def forward(self,x): x=self.initial(x) x=self.layer1(x) x=self.layer2(x) x=self.layer3(x) x=self.last_conv(x) x=self.pool(x) x=x.view(x.size(0),-1) x=self.fc(x) return F.softmax(x,dim=1) 4.实现效果

结果如下:可以看出一张(224,224)的彩图经shufflenet-V2所需内存大小为56.44M,其轻量化程度属实不错!!!


总结

本文介绍了shuffleNetV2的核心思想及其代码实现,以供大家交流讨论!
往期回顾:
(1)CBAM论文解读+CBAM-ResNeXt的Pytorch实现
(2)SENet论文解读及代码实例
(3)ShuffleNet-V1论文理解及代码复现
下期预告:
GhostNet论文阅读及代码实现

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。