【小白学PyTorch】12 SENet详解及PyTorch实现
文章来自微信公众号【机器学习炼丹术】。我是炼丹兄,有什么问题都可以来找我交流,近期建立了微信交流群,也在朋友圈抽奖赠书十多本了。我的微信是cyx645016617,欢迎各位朋友。
参考目录:
@
上一节课讲解了MobileNet的一个DSC深度可分离卷积的概念,希望大家可以在实际的任务中使用这种方法,现在再来介绍EfficientNet的另外一个基础知识—,Squeeze-and-Excitation Networks压缩-激活网络
1 网络结构

可以看出来,左边的图是一个典型的Resnet的结构,Resnet这个残差结构特征图求和而不是通道拼接,这一点可以注意一下
这个SENet结构式融合在残差网络上的,我来分析一下上图右边的结构:
- 输出特征图假设shape是\(W \times H \times C\)的;
- 一般的Resnet就是这个特征图经过残差网络的基本组块,得到了输出特征图,然后输入特征图和输入特征图通过残差结构连在一起(通过加和的方式连在一起);
- SE模块就是输出特征图先经过一个全局池化层,shape从\(W \times H \times C\)变成了\(1 \times 1 \times C\),这个就变成了一个全连接层的输入啦
压缩Squeeze:先放到第一个全连接层里面,输入\(C\)个元素,输出\(\frac{C}{r}\),r是一个事先设置的参数;
激活Excitation:在接上一个全连接层,输入是\(\frac{C}{r}\)个神经元,输出是\(C\)个元素,实现激活的过程;
- 现在我们有了一个\(C\)个元素的经过了两层全连接层的输出,这个C个元素,刚好表示的是原来输出特征图\(W \times H \times C\)中C个通道的一个权重值,所以我们让C个通道上的像素值分别乘上全连接的C个输出,这个步骤在图中称为Scale。而这个调整过特征图每一个通道权重的特征图是SE-Resnet的输出特征图,之后再考虑残差接连的步骤。
在原文论文中还有另外一个结构图,供大家参考:

2 参数量分析
每一个卷积层都增加了额外的两个全连接层,不够好在全连接层的参数非常小,所以直观来看应该整体不会增加很多的计算量。 Resnet50的参数量为25M的大小,增加了SE模块,增加了2.5M的参数量,所以大概增加了10%左右,而且这2.5M的参数主要集中在final stage的se模块,因为在最后一个卷积模块中,特征图拥有最大的通道数,所以这个final stage的参数量占据了增加的2.5M参数的96%。
这里放一个几个网络结构的对比:

3 PyTorch实现与解析
先上完整版的代码,大家可以复制本地IDE跑一跑,如果代码有什么问题可以联系我:
import torch
import torch.nn as nn
import torch.nn.functional as F
class PreActBlock(nn.Module):
def __init__(self, in_planes, planes, stride=1):
super(PreActBlock, self).__init__()
self.bn1 = nn.BatchNorm2d(in_planes)
self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(planes)
self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False)
if stride != 1 or in_planes != planes:
self.shortcut = nn.Sequential(
nn.Conv2d(in_planes, planes, kernel_size=1, stride=stride, bias=False)
)
# SE layers
self.fc1 = nn.Conv2d(planes, planes//16, kernel_size=1)
self.fc2 = nn.Conv2d(planes//16, planes, kernel_size=1)
def forward(self, x):
out = F.relu(self.bn1(x))
shortcut = self.shortcut(out) if hasattr(self, 'shortcut') else x
out = self.conv1(out)
out = self.conv2(F.relu(self.bn2(out)))
# Squeeze
w = F.avg_pool2d(out, out.size(2))
w = F.relu(self.fc1(w))
w = F.sigmoid(self.fc2(w))
# Excitation
out = out * w
out += shortcut
return out
class SENet(nn.Module):
def __init__(self, block, num_blocks, num_classes=10):
super(SENet, self).__init__()
self.in_planes = 64
self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(64)
self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1)
self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2)
self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2)
self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2)
self.linear = nn.Linear(512, num_classes)
def _make_layer(self, block, planes, num_blocks, stride):
strides = [stride] + [1]*(num_blocks-1)
layers = []
for stride in strides:
layers.append(block(self.in_planes, planes, stride))
self.in_planes = planes
return nn.Sequential(*layers)
def forward(self, x):
out = F.relu(self.bn1(self.conv1(x)))
out = self.layer1(out)
out = self.layer2(out)
out = self.layer3(out)
out = self.layer4(out)
out = F.avg_pool2d(out, 4)
out = out.view(out.size(0), -1)
out = self.linear(out)
return out
def SENet18():
return SENet(PreActBlock, [2,2,2,2])
net = SENet18()
y = net(torch.randn(1,3,32,32))
print(y.size())
print(net)
输出和注解我都整理了一下:


【小白学PyTorch】12 SENet详解及PyTorch实现的更多相关文章
- 【小白学PyTorch】11 MobileNet详解及PyTorch实现
文章来自微信公众号[机器学习炼丹术].我是炼丹兄,欢迎加我微信好友交流学习:cyx645016617. @ 目录 1 背景 2 深度可分离卷积 2.2 一般卷积计算量 2.2 深度可分离卷积计算量 2 ...
- html5--1.12表格详解
html5--1.12表格详解 一.总结 一句话总结: 二.详解 1.表格构成三个基本要素 table:表格的范围,外框:用来定义表格,表格的其他元素包含在table标签里面: tr: 表格的行: t ...
- Pytorch autograd,backward详解
平常都是无脑使用backward,每次看到别人的代码里使用诸如autograd.grad这种方法的时候就有点抵触,今天花了点时间了解了一下原理,写下笔记以供以后参考.以下笔记基于Pytorch1.0 ...
- SENet详解及Keras复现代码
转: SENet详解及Keras复现代码 论文地址:https://arxiv.org/pdf/1709.01507.pdf 代码地址:https://github.com/hujie-frank/S ...
- 【小白学PyTorch】13 EfficientNet详解及PyTorch实现
参考目录: 目录 1 EfficientNet 1.1 概述 1.2 把扩展问题用数学来描述 1.3 实验内容 1.4 compound scaling method 1.5 EfficientNet ...
- 【小白学PyTorch】10 pytorch常见运算详解
参考目录: 目录 1 矩阵与标量 2 哈达玛积 3 矩阵乘法 4 幂与开方 5 对数运算 6 近似值运算 7 剪裁运算 这一课主要是讲解PyTorch中的一些运算,加减乘除这些,当然还有矩阵的乘法这些 ...
- Pytorch数据读取详解
原文:http://studyai.com/article/11efc2bf#%E9%87%87%E6%A0%B7%E5%99%A8%20Sampler%20&%20BatchSampler ...
- javaweb基础(12)_session详解
一.Session简单介绍 在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下).因此,在需要保存用户数据时,服务 ...
- 【Linux】一步一步学Linux——Linux系统目录详解(09)
目录 00. 目录 01. 文件系统介绍 02. 常用目录介绍 03. /etc目录文件 04. /dev目录文件 05. /usr目录文件 06. /var目录文件 07. /proc 08. 比较 ...
随机推荐
- 经典的 Fork 炸弹解析
原文出处: saymagic Jaromil 在 2002 年设计了最为精简的一个Linux Fork炸弹,整个代码只有13个字符,在 shell 中运行后几秒后系统就会宕机: ::(){:|:&am ...
- springmvc中get和post区别和应用
最近对post和get什么时候使用 和 应该怎么使用 他俩的区别 有了一些疑问 根据本人的了解 post是对数据进行了封装保护 get是安全性较差的 可以看到数据的信息 post是用来改 ...
- 全国大学生信息安全竞赛初赛writeup
本文首发于“合天智汇”公众号 作者:Fortheone WEB Babyunserialize 扫目录发现了 www.zip 下载下来发现似曾相识 之前wmctf2020的webweb出了f3的反序列 ...
- seo排名顾问不仅仅是关键词排名
http://www.wocaoseo.com/thread-246-1-1.html SEO顾问是什么,应该做什么工作呢,是不是主要做关键词的优化推广呢?做seo顾问入门的人,或者想聘请seo顾问的 ...
- Azure Storage 系列(一)入门简介
一,引言 今天作为新的Azure 资源介绍的开篇,我们来学习一个新的服务,Azure Storage.众所周知,我们实际在开发过程中,会需要存储一些比如说日志,图片,等等,各种类型的数据.比如说存储图 ...
- 《52讲轻松搞定网络爬虫》读书笔记 - Session和Cookie
为什么要用Session和Cookie? 简单一句话,因为Session和Cookie可以记录用户状态信息 嘶..这到底啥意思呢? 背景一:动态网页的出现 什么是静态网页 含义:一个网页的内容是HTM ...
- MonoBehaviour生命周期与对象数据池应用
预热游戏对象: tempObject = Instantiate(cubePrefab) as GameObject ; tempObject .SetActive( false ); 游戏对象tem ...
- react native 常用学习或查资料网址
react-native facebook官网:http://facebook.github.io/react-native/中文网:http://reactnative.cn/ react 官网地址 ...
- 初识ABP vNext(8):ABP特征管理
Tips:本篇已加入系列文章阅读目录,可点击查看更多相关文章. 目录 前言 开始 定义特征 应用特征 用户数量 社交登录 最后 前言 上一篇提到了ABP功能管理(特征管理),它来自ABP的Featur ...
- 使用Javax.mail 发送邮件
使用Javax.mail 发送邮件 详细说明都在代码中: 引入依赖 <!--sun定义的一套接收.发送电子邮件的API--> <dependency> < ...