【小白学PyTorch】12.SENet详解及PyTorch实现
<<小白學PyTorch>>
小白學PyTorch | 11 MobileNet詳解及PyTorch實現
小白學PyTorch | 10 pytorch常見運算詳解
小白學PyTorch | 9 tensor數據結構與存儲結構
小白學PyTorch | 8 實戰之MNIST小試牛刀
小白學PyTorch | 7 最新版本torchvision.transforms常用API翻譯與講解
小白學PyTorch | 6 模型的構建訪問遍歷存儲(附代碼)
小白學PyTorch | 5 torchvision預訓練模型與數據集全覽
小白學PyTorch | 4 構建模型三要素與權重初始化
小白學PyTorch | 3 淺談Dataset和Dataloader
小白學PyTorch | 2 淺談訓練集驗證集和測試集
小白學PyTorch | 1 搭建一個超簡單的網絡
小白學PyTorch | 動態圖與靜態圖的淺顯理解
參考目錄:
1 網絡結構
2 參數量分析
3 PyTorch實現與解析
上一節課講解了MobileNet的一個DSC深度可分離卷積的概念,希望大家可以在實際的任務中使用這種方法,現在再來介紹EfficientNet的另外一個基礎知識,Squeeze-and-Excitation Networks壓縮-激活網絡
1 網絡結構
可以看出來,左邊的圖是一個典型的Resnet的結構,Resnet這個殘差結構特征圖求和而不是通道拼接,這一點可以注意一下
這個SENet結構式融合在殘差網絡上的,我來分析一下上圖右邊的結構:
輸出特征圖假設shape是的;
一般的Resnet就是這個特征圖經過殘差網絡的基本組塊,得到了輸出特征圖,然后輸入特征圖和輸入特征圖通過殘差結構連在一起(通過加和的方式連在一起);
SE模塊就是輸出特征圖先經過一個全局池化層,shape從變成了,這個就變成了一個全連接層的輸入啦
壓縮Squeeze:先放到第一個全連接層里面,輸入個元素,輸出,r是一個事先設置的參數;
激活Excitation:在接上一個全連接層,輸入是個神經元,輸出是個元素,實現激活的過程;
現在我們有了一個個元素的經過了兩層全連接層的輸出,這個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?Fclass?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?layersself.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?xout?=?self.conv1(out)out?=?self.conv2(F.relu(self.bn2(out)))#?Squeezew?=?F.avg_pool2d(out,?out.size(2))w?=?F.relu(self.fc1(w))w?=?F.sigmoid(self.fc2(w))#?Excitationout?=?out?*?wout?+=?shortcutreturn?outclass?SENet(nn.Module):def?__init__(self,?block,?num_blocks,?num_classes=10):super(SENet,?self).__init__()self.in_planes?=?64self.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?=?planesreturn?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?outdef?SENet18():return?SENet(PreActBlock,?[2,2,2,2])net?=?SENet18() y?=?net(torch.randn(1,3,32,32)) print(y.size()) print(net)輸出和注解我都整理了一下:
- END -往期精彩回顧適合初學者入門人工智能的路線及資料下載機器學習及深度學習筆記等資料打印機器學習在線手冊深度學習筆記專輯《統計學習方法》的代碼復現專輯 AI基礎下載機器學習的數學基礎專輯獲取一折本站知識星球優惠券,復制鏈接直接打開:https://t.zsxq.com/662nyZF本站qq群704220115。加入微信群請掃碼進群(如果是博士或者準備讀博士請說明):總結
以上是生活随笔為你收集整理的【小白学PyTorch】12.SENet详解及PyTorch实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【论文解读】基于图卷积的价格感知推荐
- 下一篇: 【效率】这个神器可以摆脱变量命名纠结!