文章插圖

文章插圖
什么是ResNet,本項目給大家介紹殘差網絡ResNet 。
ResNet是一種殘差網絡,咱們可以先簡單看一下ResNet的結構,再對它的結構進行詳細介紹 。
為什么要引入ResNet?
我們知道,網絡越深,咱們能獲取的信息越多,而且特征也越豐富 。但是根據實驗表明,隨著網絡的加深,優化效果反而越差,測試數據和訓練數據的準確率反而降低了 。這是由于網絡的加深會造成梯度爆炸和梯度消失的問題 。
為了讓更深的網絡也能訓練出好的效果,何凱明大神提出了一個新的網絡結構——ResNet 。這個網絡結構的想法主要源于VLAD(殘差的想法來源)和Highway Network(跳躍連接的想法來源) 。
ResNet詳細解說
再放一遍ResNet結構圖 。要知道咱們要介紹的核心就是這個圖啦!(ResNet block有兩種,一種兩層結構,一種三層結構)兩種ResNet block(代碼給出了兩種殘差塊以供選擇)咱們要求解的映射為:H(x)現在咱們將這個問題轉換為求解網絡的殘差映射函數,也就是F(x),其中F(x) = H(x)-x 。
【resnet網絡結構圖 restnet網絡結構】那么咱們要求解的問題變成了H(x) = F(x)+x 。
有小伙伴可能會疑惑,咱們干嘛非要經過F(x)之后再求解H(x)啊?X的跳躍連接有什么好處嗎?因為如果是采用一般的卷積神經網絡的化,原先咱們要求解的是H(x) = F(x)這個值對不?ResNet相當于將學習目標改變了,不再是學習一個完整的輸出H(x),只是輸出和輸入的差別H(x)-x,即殘差 。學習一個微小的波動F(x)不比學習一個整個x更容易嗎?X的跳躍連接除了讓網絡的學習有了基礎,在梯度反向傳播時也能更直接的傳到前面的層去 。殘差塊殘差塊通過跳躍連接shortcut connection實現,通過shortcut將這個block的輸入和輸出進行一個逐點element-wise的加疊,這個簡單的加法并不會給網絡增加額外的參數和計算量,同時卻可以大大增加模型的訓練速度、提高訓練效果,并且當模型的層數加深時,這個簡單的結構能夠很好的解決退化問題 。注意:如果殘差映射(F(x))的結果的維度與跳躍連接(x)的維度不同,那咱們是沒有辦法對它們兩個進行相加操作的,必須對x進行升維操作,讓他倆的維度相同時才能計算 。升維的方法有兩種:1、用0填充;2、采用1*1的卷積 。一般都是采用1*1的卷積 。
#以下是代碼:#導入庫mport torchimport torch.nn as nnimport torch.nn.functional as Ffrom torch.autograd import Variable#定義殘差塊(BasicBlock是小殘差塊,Bottleneck是大殘差塊)class BasicBlock(nn.Module):#定義blockexpansion = 1def __init__(self, in_channels, channels, stride=1, downsample=None):#輸入通道,輸出通道,stride,下采樣super(BasicBlock, self).__init__()self.conv1 = conv3x3(in_channels, channels, stride)self.bn1 = nn.BatchNorm2d(channels)self.relu = F.relu(inplace=True)self.conv2 = conv3x3(channels, channels)self.bn2 = nn.BatchNorm2d(channels)self.downsample = downsampleself.stride = stridedef forward(self, x):residual = xout = 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 += residualout = self.relu(out)return out#block輸出class Bottleneck(nn.Module):expansion = 4def __init__(self, in_planes, planes, stride=1):super(Bottleneck, self).__init__()self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False)self.bn1 = nn.BatchNorm2d(planes)self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)self.bn2 = nn.BatchNorm2d(planes)self.conv3 = nn.Conv2d(planes, self.expansion*planes, kernel_size=1, bias=False)self.bn3 = nn.BatchNorm2d(self.expansion*planes)self.shortcut = nn.Sequential()if stride != 1 or in_planes != self.expansion*planes:self.shortcut = nn.Sequential(nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False),nn.BatchNorm2d(self.expansion*planes))def forward(self, x):out = F.relu(self.bn1(self.conv1(x)))out = F.relu(self.bn2(self.conv2(out)))out = self.bn3(self.conv3(out))out += self.shortcut(x)out = F.relu(out)return out#定義殘差網絡class ResNet(nn.Module):def __init__(self, block, num_blocks, num_classes=9,embedding_size=256):super(ResNet, self).__init__()self.in_planes = 64self.conv1 = nn.Conv2d(1, 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.avg_pool = nn.AdaptiveAvgPool2d([4, 1])self.fc=nn.Linear(512*4, embedding_size)self.linear = nn.Linear(embedding_size, 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 * block.expansionreturn nn.Sequential(*layers)def forward(self, x):x = torch.tensor(x, dtype=torch.float32)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 =self.avg_pool(out)out = out.view(out.size(0), -1)embedding=self.fc(out)out = self.linear(embedding)return out,embedding#從18層的到101層的,可以根據自己需要選擇網絡大小,大的網絡選用了大的殘差塊,#第一個參數指明用哪個殘差塊,第二個參數是一個列表,指明殘差塊的數量 。def ResNet18():return ResNet(BasicBlock, [2,2,2,2])def ResNet34():return ResNet(BasicBlock, [3,4,6,3])def ResNet50():return ResNet(Bottleneck, [3,4,6,3])def ResNet101():return ResNet(Bottleneck, [3,4,23,3])def ResNet152():return ResNet(Bottleneck, [3,8,36,3])總結:在使用了ResNet的結構后,可以發現層數不斷加深導致的訓練集上誤差增大的現象被消除了,ResNet網絡的訓練誤差會隨著層數增加而逐漸減少,并且在測試集上的表現也會變好 。原因在于,Resnet學習的是殘差函數F(x) = H(x) – x, 這里如果F(x) = 0, 那么就是上面提到的恒等映射 。事實上,resnet是“shortcut connections”的,在connections是在恒等映射下的特殊情況,學到的殘差為0時,它沒有引入額外的參數和計算復雜度,且不會降低精度 。在優化目標函數是逼近一個恒等映射 identity mapping, 而學習的殘差不為0時, 那么學習找到對恒等映射的擾動會比重新學習一個映射函數要更容易 。參考論文: Deep Residual Learning for Image Recognition殘差網絡有兩個版本,ResNet_v1和ResNet_v2,這兩者有何區別,為啥大多用的是ResNet_v2,它有什么優良的性質呢,下一篇殘差網絡深度解析為您解答 。
- 爬蟲軟件手機版下載 網絡爬蟲軟件免費
- 網絡撩妹技巧,網上聊天也要讓她離不開你
- 手機ping測試軟件 手機網絡ping測試工具
- 網站的推廣方法 網絡推廣宣傳方式
- 網絡受限怎么辦? 網絡受限是什么問題
- 網絡相親的套路 網上相親的男人都是套路
- 海康威視設備網絡搜索工具 海康威視設備搜索器
- 網絡組建與維護實訓總結 網絡組建與維護實訓報告
- 網絡在線會議平臺 電話會議系統軟件
- 樹結構屬于什么模型 樹結構圖屬于什么模型
