再刷卷積神經網絡

時隔很久,我又回來了。。。。。。把以前不是非常懂的都記錄在這篇文章中。



1、單個卷積核

       看一下基本的卷積操作,如下圖。用一個kernel在原圖像上面滑動,通過相乘並累加的運算計算出featureMap上面對應點的像素值。

Alt




       可以看下面形象的動態圖。

       卷積神經網絡一個kernel在滑動的時候權值是共享的,看下面的圖也很好理解,不像全連接層參數巨多,CNN每層始終只保持了NxN(N爲卷積核的大小,卷積核的尺度一般都是奇數)的參數,加載權值的時候可以節省很多內存。

Alt




2、多Channel的卷積

       當然上面說的都是單個通道的情況,真正的RGB三通道的卷積操作是需要三個卷積核來負責的,相當於每個卷積覈對應輸入圖像的一個Channel,再將結果累加起來形成圖像上的像素點。

       非常簡單。圖片上的(x,y)座標上面都對應一種顏色,RGB三通道就會有一個三元組表示顏色。喂入卷積神經網絡的一般都是RGB三通道的圖片,所以每個通道進行卷積,最後將結果累加起來就是了。

Alt





3、損失函數及優化器

       神經網絡可以說每層對數據的操作都保存在權重裏面,每層都是權重來初始化的。每次訓練也就是先前向傳播進行相關計算,再反向傳播計算梯度並更新權重。

Alt


       具體參數怎麼更新梯度怎麼計算,人家框架都給你封裝好了,用一個叫做優化器的進行相關的計算。

Alt



       框架封裝的optimizer(優化器)中,可以設置學習率,動量及梯度下降算法等,優化器功能就是根據設置的參數執行某種梯度下降算法。

       這裏說一下動量,這也是以前的盲點。比較好理解,相當於是從下圖的最左邊開始梯度下降以及更新權值,快到局部最小值點的時候,因爲有動量的存在,水平方向還會有向右的一個類似慣性的分量,如下圖向上的箭頭,合理設置好這個動量參數可以衝破局部最小值

Alt





4、卷積神經網絡訓練的goal

       首先要搞明白最終目標是什麼,使用到卷積神經網絡個人感覺無非是圖像分類,那再往深層考慮,最後目的還是爲了將訓練好的模型用於測試的時候能獲得很高的準確率。

那好,再搞清楚一件事情,訓練時候用於優化模型的指標是什麼?之前機器學習裏面的線性迴歸什麼的是擬合,指標就是最小化均方誤差等;而CNN和邏輯迴歸有點像,只不過邏輯迴歸是二分類的,所以CNN指標是交叉熵





5、香農與熵

       以前一直以爲均方誤差這種損失函數也可以用於分類任務,到今天我才發現我徹底錯了額,以前的自己就是個菜雞。這時候有一位信息論的奠基人,香農大師。

Alt

       正好週一的時候,上科技論文寫作的時候,老師也提到了香農大師,他說:“那個年代審稿人沒怎麼看香農的論文就隨便寫幾個理由給拒絕了。”數學大師的科研之路尚且曲折,衝。香農大師首次給熵這個東西下了定義。

Alt

       熵的意義可以簡單的理解爲:熵越大不確定性越高



       交叉熵公式:

Alt
       交叉熵其實就是熵的變形,有兩個變量,可以想象成引入了預測值和真實值,用這個來評估分類任務的優化指標準確率是很高的,網上都說比迴歸時候的均方誤差什麼的準確率都要高。而且交叉熵的意義也和熵的意義是相同的,值越高也表示不確定性越高



       對於二分類的交叉熵,我看了一下之前自己寫的邏輯迴歸的博客,其實就是上面寫的經過極大似然法推導的(吳恩達機器學習的課程裏面抄的)。

Alt





6、維度問題

       手寫自己的CNN網絡的時候要弄清楚輸入圖片的格式,再來就是一次卷積核之後輸出圖片維度的計算。

       pytorch框架中每次卷積後輸出圖片維度計算公式(no padding,步長爲1) — b c w h:

       batch_size x kernel_num x (input_width - kernel_size +1) x (input_height - kernel_size +1)


       池化(下采樣)輸出維度比較簡單,反正下采樣不改變圖片的通道數,就是根據入參改變圖片的width和height。




7、pytorch實現最簡單的LeNet

	class LeNet5(nn.Module):
	    def __init__(self):
	        super(LeNet5, self).__init__()
	
	        self.conv_unit = nn.Sequential(
	            nn.Conv2d(in_channels=3, out_channels=6, kernel_size=5, stride=1),
	            nn.AvgPool2d(kernel_size=2, stride=2),
	            nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5, stride=1),
	            nn.AvgPool2d(kernel_size=2, stride=2)
	        )
	
	        self.fc_unit = nn.Sequential(
	        	# 這個維度可以自己初始化一個張量喂到卷積單元裏面測出來
	            nn.Linear(16 * 5 * 5, 120),
	            nn.ReLU(),
	            nn.Linear(120, 84),
	            nn.ReLU(),
	            nn.Linear(84, 10)
	        )
	
	        temp = torch.rand(2, 3, 32, 32)
	        print(self.conv_unit(temp).shape)
	
	    def forward(self, x):
	        x = self.conv_unit(x)
	        # 輸入到全連接層的時候需要將featureMap展平爲一維張量
	        x = x.view(x.size(0), -1)
	        x = self.fc_unit(x)
	
	        return x




8、pytorch的one-hot編碼

       主要就是理解out.scatter_(dim=1, index=idx, value=1)函數的作用,非常簡單。就是如果一個標籤直接是索引並不是一維張量的話,就可以調用這個函數,先用zero初始化好這個矩陣,然後在指定的維度上面根據索引填充1就好了,那必然未被填充到的肯定是默認值,就是爲0。

	def one_hot(label, class_num):
	    out = torch.zeros(label.size(0), class_num)
	    # 將標量轉化爲1x1的張量
	    idx = torch.LongTensor(label).view(-1, 1)
	    # 將1填充到out張量對應dim=1上指定index的位置
	    out.scatter_(dim=1, index=idx, value=1)
	    return out
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章