0609-搭建ResNet網路
目錄- 一、ResNet 網路概述
- 二、利用 torch 實作 ResNet34 網路
- 三、torchvision 中的 resnet34網路呼叫
- 四、第六章總結
pytorch完整教程目錄:https://www.cnblogs.com/nickchen121/p/14662511.html
一、ResNet 網路概述
Kaiming He 的深度殘差網路(ResNet)相比較傳統的深度深度神經網路,解決了訓練極深網路的梯度消失問題,
這里選取 ResNet34 講解 ResNet 的網路結構,它的網路結構如下圖所示:

在上述的網路中,除了最開始的卷積池化和最后的池化全連接之外,網路中有很多結構相似的單元,這些重復單元的共同點就是有個跨層直連的 shortcut,ResNet 中將一個跨層直連的單元稱為 Residual block,它的結構如下圖所示:
對于 Residual block,左邊部分是普通的卷積網路結構,右邊是直連,如果輸入和輸出的通道數不一致,或者它的步長不為 1,就需要有一個專門的單元將二者裝換成一致的,讓它們可以相加,
并且從上圖可以發現 Residual block 的大小也是有規律的,在最開始的 pool 之后又連續的幾個一模一樣的 Residual block 單元,這些單元的通道數一樣,在這里我們把這幾個擁有多個 Residual block 單元的結構稱作 layer,注意這個 layer 和之前介紹的 layer 不同,這里的 layer 是幾個層的集合,
由于 Redisual block 和 layer 出現了很多次,我們可以把它們實作為一個子 Module 或函式,在這里我們把 Residual block 實作為一個子 Module,而讓 layer 實作為一個函式,
下面我們將盡量按照這三個規則去實作 ResNet 網路:
- 對模型中的重復部分,實作為子 module 或用函式生成相應的 module
nn.Module和nn.Funcitonal結合使用- 盡量使用
nn.Sequential
二、利用 torch 實作 ResNet34 網路
import torch as t
from torch import nn
from torch.nn import functional as F
class ResidualBlock(nn.Module):
"""
實作子 module:Residual Block
"""
def __init__(self, inchannel, outchannel, stride=1, shortcut=None):
super(ResidualBlock, self).__init__()
# 由于 Residual Block 分為左右兩部分,因此定義左右兩邊的 layer
# 定義左邊
self.left = nn.Sequential(
# Conv2d 引數:in_channel,out_channel,kernel_size,stride,padding
nn.Conv2d(inchannel, outchannel, 3, stride, 1, bias=False),
nn.BatchNorm2d(outchannel),
nn.ReLU(inplace=True),
nn.Conv2d(outchannel, outchannel, 3, 1, 1, bias=False),
nn.BatchNorm2d(outchannel))
# 定義右邊
self.right = shortcut
def forward(self, x):
out = self.left(x)
residual = x if self.right is None else self.right(x) # 檢測右邊直連的情況
out += residual
return F.relu(out)
class ResNet(nn.Module):
"""
實作主 module:ResNet34
ResNet34 包含多個 layer,每個 layer 又包含多個 residual block
用子 module 實作 residual block,用 _make_layer 函式實作 layer
"""
def __init__(self, num_classes=1000):
super(ResNet, self).__init__()
# 前幾層影像轉換
self.pre = nn.Sequential(
nn.Conv2d(3, 64, 7, 2, 3, bias=False),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.MaxPool2d(3, 2, 1),
)
# 重復的 layer 分別有 3,4,6,3 個 residual block
self.layer1 = self._make_layer(64, 128, 3)
self.layer2 = self._make_layer(128, 256, 4, stride=2)
self.layer3 = self._make_layer(256, 512, 6, stride=2)
self.layer4 = self._make_layer(512, 512, 3, stride=2)
# 分類用的全連接
self.fc = nn.Linear(512, num_classes)
def _make_layer(self, inchannel, outchannel, block_num, stride=1):
"""
構建 layer,包含多個 residual block
"""
shortcut = nn.Sequential(
nn.Conv2d(inchannel, outchannel, 1, stride, bias=False),
nn.BatchNorm2d(outchannel))
layers = []
layers.append(ResidualBlock(inchannel, outchannel, stride, shortcut))
for i in range(1, block_num):
layers.append(ResidualBlock(outchannel, outchannel))
return nn.Sequential(*layers)
def forward(self, x):
x = self.pre(x)
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
x = F.avg_pool2d(x, 7)
x = x.view(x.size(0), -1)
return self.fc(x)
res_net = ResNet()
inp = t.autograd.Variable(t.randn(1, 3, 224, 224))
output = res_net(inp)
output.size()
torch.Size([1, 1000])
不到 50 行代碼便實作了這樣一個網路,看起來是那么不可思議,如果對此感興趣的同學還可以取消嘗試實作 Google 的 Inception 網路,
三、torchvision 中的 resnet34網路呼叫
前面我們講過一個 hub 模塊,里面存盤了很多網路結構,不僅如此,和 torch 配套的影像工具包 torchvision 也實作了深度學習中的大多數經典的模型,其中就包括了 ResNet34,非常簡單,可以通過以下兩行代碼呼叫這個網路:
from torchvision import models
res_net = models.resnet34()
inp = t.autograd.Variable(t.randn(1, 3, 224, 224))
output = res_net(inp)
output.size()
torch.Size([1, 1000])
本例中的 ResNet34 的實作參考了 torchvision 中的實作并做了一定的調整,有興趣的同學可以去閱讀相對應的原始碼,
四、第六章總結
這一章詳細的介紹了 torch 中的 nn 工具箱,但是你說詳細嗎?又不是那么詳細,還有很多很多地方我們需要去補漏,如果想深入各個部分的同學們,可以去參考官方檔案,
當然,我更建議學一部分常用的基礎,然后在實踐中學習更加完善、更加系統的知識體系,因此,我們將在未來的實戰專案中不斷地鞏固 nn 這個工具箱的使用,
最后,隨著 nn 的落幕,torch 的地基也算是落幕了,剩下的都是一些邊邊角角的知識點,但是還是借用古人的一句話:路漫漫其修遠兮,任重而道遠,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/280509.html
標籤:其他
下一篇:撬動知識星球 - 02
