卷积神经网络补充—GoogleNet
復雜神經網絡的問題
簡單神經網絡
我們注意這樣的一個問題,我們在之前的學習當中使用的都是簡單的一條龍走下來的方式進行學習,這種是比較基礎的,沒有分叉,沒有循環,就是一條路走完??梢钥吹街皩W的都是特別簡單的串行結構。
GoogleNet
是一種基礎架構,我們一般拿這個網絡做一個主干網絡,之后再在主干網絡上進行修改之后作為我們實際應用的場景。
減少代碼冗余:Inception Module
減少代碼冗余看起來比較陌生其實我們可能已經默默應用了很久了,例如:在面向過程的編程語言當中使用函數,在面向過程的編程語言當中使用類。都是對代碼進行減少冗余。
可以看到這種網絡結構是十分的復雜,那么我們如果全部一點一點的寫完,那么這個代碼的復雜度就太大了。所以我們必須選擇減少代碼的冗余:
可以看到其實代碼當中可復用的部分還是很多的,如上圖:
這個塊就被叫做:Inception(和電影盜夢空間重名)具體如下:
這里的設計靈感來自于,在模式識別的過程當中,主要是一些超參數的選擇不好處理,例如我們在進行卷積的時候,我們該選擇卷積核的維數為多少的問題。這樣我們設計為多個不同的路徑達到結果,這樣子在不斷的學習過程中,適合的卷積核所在的路徑就會被逐漸的凸顯出來。自動幫我們選擇一個超參數。
那么這里
1×1的卷積到底是為了什么?
也就是這個圖里的1×1卷積到底是在做什么?
如果我們這個channel數是一個1那么什么也別說了,這不就是一個矩陣數乘嗎?
但是我們大部分實際應用的過程中channel并不是1而是多個,例如三個:
通過這個圖我們可以看到,其實卷積是一個對不同通道數據的一個融合,融合這個說法比較空,不如舉一個例子來理解一下:我們上高中的時候經常有個???#xff0c;或者月考。如果有六個科目,那么就是一個六維空間,在一個六維空間很難比較兩個同學誰學習的情況更好,所以學校就有一個信息融合的算法,就是加總分。
當然這里是融合為一個通道,如果我們多幾組卷積核,我們可以融合出目標個通道數的數據形式。這個過程中一個顯著的特點就是改變了channel的個數。
可是改變一個channel的個數又有什么作用呢?我們可以詳細看下圖:
從圖里我們可以看到在經過1×1卷積channel下降之后再進行5×5卷積可以有效地節約運算次數,這就是在節約錢啊。
Concatenate是什么?
也就是這個東西是什么?
這個東西其實是將之前的內容拆分,再在這一層結束之后從新合并在一起,我們注意一下這里的合并是在什么情況下合并的,這里的合并是依據channel合并的,也就是channel之下的全部內容都必須全部相等,才能順利合并。
所以我們在中間過程的卷積過程當中要注意保證weight和height的穩定不變。
實現Googlenet
代碼實現
import torch import numpy from torchvision import functional as F#這里我們注意不論我們輸入的通道數是多少,我們輸出的通道數都是88. class Inception_Model(torch.nn.Module):def __init__(self,input_channel):super(Inception_Model,self).__init__()self.poolingbranch= torch.nn.Conv2d(input_channel,24,kernel_size=1)self.1m1branch =torch.nn.Conv2d(input_channel,16,kernel_size=1)self.5m5branch1 =torch.nn.Conv2d(input_channel,16,kernel_size=1)self.5m5branch2=torch.nn.Conv2d(16,24,kernel_size=5,padding=2)#注意這里設置一個2的padding是為了保證輸出的圖形的形狀一致self.3m3branch1=torch.nn.Conv2d(input_channel,16,kernel_size=1)self.3m3branch2=torch.nn.Conv2d(16,24,kernel_size=3,padding=1)#同樣這里的padding也是為了保證輸出的圖像一致self.3m3branch3 =torch.nn.Conv2d(24,24,kernel_size=3,padding=1)def forward(self,x):branchpool=F.avg_pool2d(x,kernel_size=3,stride=1,padding=1)#這里是使用一個函數,因為這個求平均沒有參數,所以直接可以當成函數使用branchpool=poolingbranch(branchpool)branch1m1=self.1m1branch(x)branch5m5=self.5m5branch1(x)branch5m5=self.5m5branch2(branch5m5)branch3m3=self.3m3branch1(x)branch3m3=self.3m3branch2(branch3m3)branch5m5=self.3m3branch3(branch3m3)outputs = [branchpool,branch1m1,branch5m5,branch3m3]#注意這里我們只是將其放在一個元組當中,并沒有拼起來return torch.cat(outputs,dim=1)#正著開始的第一號維度其實是第二個嘛,不就是channel嗎。只有當只有channel不一樣的時候,才可以順利合并起來。class Net(torch.nn.Module):def __init__(self):super(Net,self).__init__()self.conv1=torch.nn.Conv2d(1,10,kernel_size=5)self.conv2=torch.nn.Conv2d(88,20,kernel_size=5)self.incip1=Inception_Model(10)self.incip2=Inception_Model(20)self.mp=torch.nn.MaxPool2d(2)self.fullconnect=nn=(1408,10)#這里我們注意,我們的1408是可以算出來的。#但是實際上并沒有人去算,都是輸入一個數據測試一下到底是多少的情況。def forward(self,x):in_size=x.size(0)#注意這里我們其實是為了獲得我們是在使用的數據集的大小的問題x=F.relu(self.mp(self.conv1(x)))#從(1,28,28)到(10,24,24)再到(10,12,12)x=self.incip1(x)#從(10,12,12)到(88,12,12)x=f.relu(self.mp(self.conv2(x)))#從(88,12,12)到(10,8,8)再到(10,4,4)x=self.incip2(x)#從(10,4,4)到(88,4,4)所以一個輸出轉化為一個一維張量就成了1408了x=x.view(in_size,-1)#注意這里我們是將數據集中的,每一個數據,原來的矩陣換成一個行。x=self.fullconnect(x)return x在MNIST數據集上的表現
你看這里其實經過幾次訓練之后,這個測試集的準確度就開始下降了,這時候,可能就是出現了過擬合的現象。已經達到了這種網絡的極限。理論上我們需要畫圖來找到最大值。但是一般我們在實際的操作當中我們是每次達到新的高度就進行一次存盤。最后我們得到的就是一個最好的模型了。
總結
以上是生活随笔為你收集整理的卷积神经网络补充—GoogleNet的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pytorch的多分类问题
- 下一篇: 梯度消失的问题