- 1. 一、文章來由
- 2. 二、cs231n 課程
- 3. 三、cs231n筆記
一、文章來由
原部落格來自:http://blog.csdn.net/scythe666/article/details/75265338
因為篇幅太長,不宜閱讀與編輯,分篇如下
二、cs231n 課程
第二講:資料驅動的影象分類方式:K最近鄰與線性分類器
(1)經典影象識別演算法不可擴充套件,data-driven的方式更科學
早期沒有使用的原因是早期沒有這麼多data,訓練的模型是一個類
(2)nearest neighbor classifier
記住所有training images和他們的label,找一個最相近的label
這種方法簡單,但是應用時效率低
CNN相對於這個方法反過來,不論訓練資料多少,分類時間都是固定的
KNN是nearest neighbor classifier的一種,找到最近K個images,have them vote on the label
5個最近點,分界線變得平滑
超引數:
1)最好的距離選取標準
2)k如何選
(3)5折理論
將所有data5折,其中一折用於超引數的設定
迴圈驗證,選取不同的折來設定超參
(4)線性分類器
類似於filter或者模板
f = Wx b
將x展平,相乘於W,再加上b
所有的分數都是所有畫素點值的加權和
W和b要訓練出來
(5)為了定量選擇的模型或者權值,定義了loss函式
為了讓loss函式最小化
第三講: 線性分類器損失函式與最優化
(1)計算loss,採用multiclass SVM loss
相當於單個相減,然後加安全係數1(可以是任意正數),hinge loss
full training loss就是在其上除以總數
程式碼實現
但這個裡面有一個bug
如果double每個值,其實結果沒有影響,但是會使資料間的差值越來越大
(2)正則化,給每個數字的權值儘量平均
分散權值
(3)softmax classifier
(4)不同的loss函式的比較
最大化log概率比直接最大化概率好
最大不同:
SVM比softmax穩定,就算slightly提高值也不會變化(前提條件是誤分類評分小於正確評分減一),softmax不然,將所有樣本點納入考量
(5)梯度下降法
計算複雜,且如果引數很多的時候,每個都要計算不太可能
用微積分求解
要檢查,寫起來簡單
並不是全部資料,而是抽樣
SGD是一種常用的更新W的方法
(6)經典方法是用 特徵 線性分類器 的方法
比如顏色直方圖 hog邊緣特徵,這樣線性分類器就有辦法處理,通常是將一幅圖人為拆分成多個特徵的組合
=== 某種程度上的統計特徵
傳統方法 vs 深度學習
第四講:反向傳播與神經網路初步
1、求偏導
反向傳播
在正向計算的時候,每個引數就能夠把其對最後的結果偏導公式計算出來
導數的意義是,因變數的增量與自變數增量的比值
正向和反向傳播的時間差不多相同。
2、反向傳播門的性質
加法門:梯度分配器,將梯度分配到前面的門
max門:梯度路由,將最大梯度放入路由,反向傳播的時候只分配給最大的那個(因為不是最大的,對結果產生不了影響)
乘法門:梯度開關
沒有迴路
3、正向傳播與反向傳播
1、總結前饋和反饋
對於每次更新,都要進行一次完整的前饋與反饋:
前饋計算loss,反饋計算梯度,update在負權值上權值微調
雅可比矩陣是一階偏導組成的矩陣
特殊情況下,不必計算雅可比行列式所有值
每一層之間都是通過矩陣連線
2、神經網路
隱含層可以有多個數,自己定義
隱含層引入多樣化
換算成公式太複雜,反向傳播簡化計算
每個單個的neuron都可以看作一個線性分類器
各種啟用函式
relu會讓神經網路快很多,預設啟用函式首選
算神經網路的層數是算有權值的層數
正則化係數越低,擬合程度越高,也越容易過擬合
幾條線就大概是幾條邊界,所以對於circle data來說,3條就好
三條邊的組合,第二層只是把這些組合拼在一起
網路中的neuron越多越好,但是要選擇合適的正則化項,而不是減少neuron,但可能有沒時間訓練等因素,所以選用更小的network
如果網路很小,有一種網路優化演算法L-BFGS,mini-batch好用,通常用不上
對於更深還是更寬也沒有一個確定的答案,對於圖片來說,層數更重要
對於其他問題,是data相關的
不同層用不同的啟用函式
通常不會這樣做,通常是選一個啟用函式,整個網路都用,不同層中換不同啟用函式一般並沒有什麼好處
第五講:神經網路訓練細節
https://github.com/BVLC/caffe/wiki/Model-Zoo
大量已經訓練好cnn權值資料的模型已經上傳到網上,超引數也設定好了
講述步驟
激勵函式
(1)sigmoid function
梯度消失問題
問題很多,飽和的神經元要麼非常接近0,要不非常接近1
—>反向的時候,梯度趨於0
問題1:local梯度很小
只在sigmoid的啟用區域才會有用
問題2:
不關於原點中心對稱,輸出值都在0,1之間
w的梯度要麼全正要麼全負,收斂速度很慢
問題3:
exp()耗時
但在rnn中用到,因為特殊原因
(2)tanh(x)
(3)ReLU
網路收斂速度快,之前的6倍
問題:不中心對稱
如果ReLU從未被啟用,那反向的時候就會梯度消失,不啟用就不能進行反向傳播(不更新權值,可以說什麼都不做)
如果啟用了,因為區域性梯度是1,所以都是將梯度傳遞給前面的
如果在x為0的時候,梯度未定義,隨便選一個對結果也不會有很大影響
dead relu問題:
永遠不啟用,也不更新
學習率過高也會出現這個問題
解決方法:可以給一個小的bias,重新啟用已死的神經元,但是講者認為這個方法沒什麼用
(3)Leaky ReLU
也不一定是0.01,可以是任意值,這個α可以被學習,反饋學到
計算圖中的每個神經元都有α,可以通過學習學到
還是relu最常用
(4)ELU
(5)maxout
資料處理
PPT中介紹了很多資料處理方法,但在影象處理中歸一化不常用,但0中心化應用很多,均值中心化
每個畫素減去均值image或者減去per channel 均值,後者更常用
權重初始化
過去人們常用全0初始化,但是效果不好,因為所有神經元的計算完全相同,反向的時候梯度也相同。最好採用隨機小值。
如果初始化不好,很可能飽和,反向不了
策略也已經有了,2010年提出的Glorot提出的Xavier初始化
但是這個用於tanh,不用於relu
但新發論文引入因數2
但這就是一個data-driven的活,不同批資料效果不同
還有方法是通過一個公式,能夠將資料高斯分佈化
BN有很多優點,如下:
代替了一部分正則化的工作
Note: at test time BatchNorm layer
functions differently:
The mean/std are not computed
based on the batch. Instead, a single
fixed empirical mean of activations
during training is used.
(e.g. can be estimated during training
with running averages)
會稍稍延長一點時間
Babysitting the Learning Process
正確性檢查,非常重要
為了確保神經網路工作正常:
step1:初始化2層神經網路,weights和bias用最簡單的初始值
step2:two_layer_net那句是train這個網路,最重要的是關注要返回的loss和梯度,講者取消了正則化,以確保損失值正確
step3:估算,softmax是-log(1/10)
step4:對於小資料,能夠達到過飽和說明具有合理性(反向傳播 update 學習率OK,演算法沒有大問題),然後才考慮增大訓練集。所以不應該擴大訓練集直到完全通過測試。
step5:擴大訓練集,在找到好的learning rate,從小的learning rate開始
learning rate太小的情況,這種假設是要建立在完成了正確性檢查之後,因為檢查無誤才能大膽判斷
但如果rate太大,cost就爆炸了
cost: NaN almost
always means high
learning rate…
超引數優化
粗糙—>精細的過程
超引數優化要隨機取樣超引數,網格取比隨機取差
一些可優化的超參
學會解讀不同的圖形
也要關注一些其他的引數,比如準確率
總結:
下節課繼續:
第六講:神經網路訓練細節 part2
如何訓練神經網路
為什麼要用啟用函式?
答:如果不用,不論多少層,如上圖,也只是一個三層的三明治,還是相當於一個線性分類器,使用線性分類器記憶data
如果初始權重太小,在網路中activate,權值更新就會趨於0;如果太大,就會梯度爆炸
—>那麼將會以超飽和的網路或者全0結束
–>選擇一個合理的初始化範圍很重要
batch normalization減輕初始化權重設定的麻煩
dx是梯度
原來只是用簡單的梯度與learning rate相乘,現在要更復雜一點
對於gsd,在豎直方向上比較快,在水平方向上比較慢,所以會震盪,有一種方法就是用momentum方法
mu在0與1之間,通常取0.5~0.9
v通常初始化為0
不同引數更新方法
(1)nesterov momentum
original的方法是建立了一個actual向量,但是現在要做的是想一步超前,計算下一步的梯度,會有一點點的不同
動量法的出現也不是因為有區域性最小值,當網路規模越來越大的時候,區域性最小值的問題不用特別關心
(2)AdaGrad update自適應梯度法
凸優化理論的成熟拿過來的
用一個cache(梯度的平方和構成,聯合向量,每個維度記錄相應梯度的平方和,有時叫做 second momentum),per parameter adaptive learning rate,儲存引數空間的每一維都有不同的learning rate,比如上面那張圖,垂直方向的learning rate會遞減,水平方向的會增大
反對有個問題:learning步長會減少,最終停止
(3)RMSProp update
Hinton做了一個小的改動,將上面的那個問題解決了,不會更新停止,而是不斷帶來更新
梯度大的地方減慢速度才是最好的
(4)Adam update
ada和momentum的結合
動量用於穩定梯度方向
beta1和2是超引數
beta1通常是0.9,beta2通常是0.995
Adam很好用,通常講者使用Adam
learning rate 怎麼設定更好
其實這裡很難說,開始的時候最好使用大一點的learning rate,但是到後期可以使用小一點的rate,因為系統能量太大不容易settle down
另一些凸優化方法,但是不細講
Hessian Matrix,又譯作海森矩陣、海瑟矩陣、海塞矩陣等,是一個多元函式的二階偏導數構成的方陣,描述了函式的區域性曲率。黑塞矩陣最早於19世紀由德國數學家Ludwig Otto Hesse提出,並以其名字命名。黑塞矩陣常用於牛頓法解決優化問題。
- Adam is a good default choice in most cases
- If you can afford to do full batch updates then try out
L-BFGS (and don’t forget to disable all sources of noise)
In practice
實際的大資料集不會採用 L-BFGS
adam 不會讓你學習率變為0,因為他說leaky gradient;如果用adagrad就不一樣了,learning rate可能降到0。
Evaluation: Model Ensembles
- Train multiple independent models
- At test time average their results
Enjoy 2% extra performance
這裡x_test是對於現在引數x的一個指數衰減,使用資料集和測試集,結果總比x要好,像引數進行加權的集合(不好解釋,想象碗狀函式優化問題,在最低點周圍不停跳動,最後做一個對這些值的,能夠更接近最低點)
Regularization (dropout)
涉及small samples,在前向的時候,要隨機將一些神經元置0
不僅在前向的時候,反向的時候也要用
都要乘以U1和U2,隨機失活過濾器
防止過擬合,如果只用一半網路,表達能力就變弱了,偏差-方差均衡
一旦dropout,沒有失活的神經元引數或者說神經元梯度才會被更新,因為一旦神經元被關閉,把輸出值固定為0,就不會有梯度經過他,他對應的上一層神經元的權值也不會更新,相當於是sub-sampling
因為他的值在計算損失函式中沒有用到,所以他的權值也就不更新了
在多次迴圈中我們會用相同的資料點訓練不同的共有引數的模型—>這就是隨機失活
每次前向的時候,我們sample,就會得到一個子網路
每一次迴圈中,我們先得到一個mini-batch,然後在神經網路中取樣,得到那些沒有失活的神經元,形成子網,然後前向 後向,然後得到梯度,一直重複這個過程
是否可以在不同層失活不同的比例,可以的,如果想更強的正則化,就失活多一點,比如一層有很多神經元,就可以多失活一點
也可以對每一個神經元進行一定概率的失活,叫做drop connect
這裡需要補足training的0.5那部分系數,需要在test時啟用函式也乘上這個係數,以減小輸出值
也有一種方法是在training中將啟用函式輸出變大
inverted dropout實際中應用很多
這裡的0.5不是絕對的,是期望
CNN
進入正題了,目前有一些很有名的網路,比如:
AlexNet,VGG-Net,LeNet,GoogleNet,ConvNet
AlexNet是2012年提出,但是跟1998年提出的LeNet差不多,差別就是一個用sigmoid一個用relu,而且更大更深,用gpu計算。
ConvNet對影象分類在行
第七講:卷積神經網路詳解
用一個5*5*3的卷積和做運算
—>得到一個28*28*3的卷積激勵map
—>用不同卷積filter做運算,可以得到一個多層的卷積組,比如6個,就得到28*28*6的卷積組
—>這些會被feed到下一個卷積層
當然這個過程中要經過激勵函式
通常filter都很小,一般3*3或者5*5等等
上圖中,第二層卷積層的大小變成5*5*6,有10個,所以得到一個24*24*10的卷積組
在每一層這會得到不同的特徵。
就是不同層的組合
步長不能是任意的,3的時候不允許
有時候會對影象做填補
作用就是,如果7*7的影象,用3*3的來filter,尺寸不會縮小
因為可能有很多層,如果縮小的太快,是不好的性質
引數還要加上bias
總結一下:
K總要是2的指數,為了方便計算,有些程式對於2指數有特殊優化
1*1的filter也是OK的,因為不僅是一個的,而是整個深度都參與卷積
filter總是偶數,奇數尺寸的濾波器有更好的表達,2*2也不是不行,但沒3*3好
為什麼填充的時候,只填充0,因為這樣filter只會考慮輸入的資料,點乘的時候,0不會對輸出有貢獻。即便是填充附近的資料。
每一層一般也不會用不同size的filter。
只有第一個卷積層能接觸到原始資料,後面的都是接觸前一個的資料
filter === kernel
在主流深度學習框架中也有體現:
站在神經元的角度來看這個問題:
每個神經元只管自己的一小塊區域(對應於一個kernel),一塊板上的所有neuron在一個啟用對映中都share一個weight
一塊版上的neuron有兩個重要特性:
共享引數 局域連線
對於多個kernel可以理解為:
所有神經元全部以一個局域模式,共享引數,並關注著同一個資料體
如上圖的5個neuron都看著同一塊資料
共享引數 局域連線的作用:
從視覺上控制模型的能力,神經元平面上希望計算相似的東西,例如小的邊緣,這樣的功能是有意義的,也是一種控制過擬合的方式
pooling就是一種下采樣
max pooling就是用幾個裡面的最大值代替,來進行下采樣
當然也是有average pooling
這就是兩種最常見的pooling技術
與Conv layer類似的是,pooling layer也有自己的定義,如下圖
這裡只有兩個引數,另外有輸入輸出的定義
fc層就是一個neuron來計算分類得分
98年提出的LeNet
AlexNet,圖顯示不全,而且有兩條路的原因是因為當時gpu發展沒有那麼好,就分了兩個
第一層應該是227,而不是224,Alex原作者說的有問題
pooling layer沒有引數,只有卷積層有引數
AlexNet完整的架構
依次為卷積-池化-norm,norm層是一個進行規範化的層,2012年前經常使用,現在不用了,因為對結果沒有幫助
也會對整個BP
BP的時候特別注意:
因為引數共享,當用filter做卷積的時候,所有neuron共享引數,所有濾波器梯度都彙總到一個weight blob
第一次使用relu
用了data 增強,拿到影象後不是直接用,而是先預處理
用了dropout 0.5,只在最後幾層用了
在監控準確率達到平臺期,學習率就除以10,基本減少一兩次,神經網路就收斂了
2013年冠軍是ZFNet,也是在Alexnet上改進的
fc7已經成為一個名詞:代表統計分數之前的最後一層
當然在每一個卷積層後有一個relu層
在fc層後也應該有一個relu層
2014年VGG提出,將top5 error率一下子刷到7%
全部的架構只使用 3*3 conv layer
2*2 max pooling layer
重複堆疊到16層,效果不錯
架構如下圖
我們注意到,過濾器在增加(更深),每個feature map在變小
224*224 —> 7*7
但是這一層深度不再是3通道,而是512個啟用通道(通過512個過濾器得到)
最後是每張圖片向前需要93m的記憶體,我們需要儲存這個值,因為要做BP,回來需要update,所以要double這個值,組後是最小200m左右
記憶體消耗主要在前期,見下圖,同時引數最多的時候在fc的時候
現在代替全連結層有—>average pooling技術
不直接全連結,而是改變他,成512個數,是通過average pooling對每個(feature map)取平均值得到512個數,效果幾乎一樣好,可以避免使用大量引數
GoogleNet使用這個方法
VGG有個很簡單的線性結構,GoogleNet就複雜化了
其最大創新點是加入了inception module
GoogleNet用inception layer取代了卷積層
將7*7*1024降到1*1*1024
但是還是更多的人使用VGG,因為更好更統一的結構,人類的錯誤率差不多是5%,如果訓練人可以降低到2%~3%
2015年的冠軍是3.6%,來自於MSRA的residual network。
當然層數是越多越好
不過不是簡單的堆疊
上圖說明了,如果要增加層數,不要用naive方法,要用resnet方法
微軟亞研院的resNet有152層,訓練時間比較久,但是跑起來比VGGNet快
resnet,採用跳躍的連線,會通過一個大的因子壓縮到一層 56*56的空間,剩下的150多層,都只作用在56*56的陣列裡,將很多資訊打包到如此小的空間
resnet的工作原理如上圖,需要加上輸入的殘差
原因就是,加法在BP的時候,梯度是直接分發給孩子,這樣跳躍的網路就可以幫助跳過很多中間層,因此可以訓練一個與原影象很像的影象,中間的層可以學習如何加入訊號使得更有效
如何訓練一個殘差網路:
Alexnet用了0.01的初始學習率,因為殘差網路有batch normalization,所以可以提高一點,沒有使用dropout
殘差網路也不用在加上的那個部分加權,最開始可以直接對結果產生影響
第八講:遷移學習之物體定位與檢測
localization可以看作迴歸問題。迴歸就是輸出一組數,而不是分類label了
選框可以用四個變數描述:左上角xy座標 長寬
類似分類問題:也有前向傳播 BP
loss可以選用標準的歐式距離loss
一個簡單的定位 分類recipe(固定種類)
pre-train就是先前有訓練的模型
簡單來說就是分別輸出框和分類結果
sliding window:overfeat
如果想識別圖中的物體,通常還有一種做法就是嘗試各種不同的框
重複上面的定位 分類操作,再將不同位置的結果進行聚合
將全連線層視為一個conv層
如上圖的5*5*1024 —> 被個4096個5*5的核conv
這樣就統一了計算,大大減少計算量
微軟2015年沒有靠的不只是更深層的特徵,而是發明了RPN—Region Proposal Network
L2 loss 有極端值的問題,L1沒有,所以可以用L1
有時有人會同時訓練迴歸與分類;有時分開
object detection
輸出的數量不定,也可以用不同的區域不停的試,試不同大小的視窗
加入兩個新東西:
(1)可以加入一個背景類,代表啥都沒有;
(2)多標籤分類,不用softmax loss,而是用獨立的迴歸loss,多個類可能在同一個點上
hog是用線性分類器,方向梯度直方圖,DPM類似CNN
當然不可能嘗試出所有的區域,所以用region proposal演算法
輸出可能含有物體的區域,不關心具體類別,只是告訴這個區域可能有物體,很快。在影象中找整塊的區域
最著名的Region proposal演算法有selective search — 將類似顏色 紋理進行融合成框,再用這些合成的框進行檢測
講者推薦edgebox
很快,1/3s一張圖
R-CNN Region based CNN
有了Region Proposal,有了CNN,就有了R-CNN
step1:執行selective search 到大噶2k個不同大小、不同位置的框
step2:每個框剪裁出來,調整到固定大小
step3:cnn分類 —> cnn網路分別連線回歸端 SVM分類端,迴歸端可以對目標框進行糾正
R-CNN Training 過程
step1:下載一個已有的對於imageNet資料集分類的模型比如Alexnet
step2:finetune用於檢測,因為原模型是用於1000類分類的,可以在後面加上幾層用於分類自己的資料
step3:提取特徵,存在磁碟上—對於每張圖片,執行selective search 演算法,送到CNN,把特徵存在磁碟
step4:訓練二分類SVM,回答是否包含特定物體
step5:box的迴歸,希望從特徵推回到box,有特徵 目標==訓練線性迴歸
測試標準
缺點:訓練有點麻煩,且費記憶體,慢,離線操作(不能update)
Fast R-CNN
swap提取出的區域再執行CNN,類似與overfeat滑動視窗
先高解析度影象輸入,卷積,得到高解析度卷積特徵
再用Region Proposal的方法, 即ROI分離區域特徵
投入全連線層
用分類端 迴歸端
解決了R-CNN在test和train時候的問題
Region of Interest Pooling
給出目標框,投影到conv feature空間,將conv feature分成小塊
再做max pooling,這樣也是可以BP
為什麼不用CNN做Region Proposal呢
Faster R-CNN
不用推薦區域的卷積,而是整張圖片卷積,使用RPN Region Proposal Network
做了和fast-RCNN相反的事情,用anchor框對特徵圖進行滑動,對映回原影象,特徵圖譜上的點和原影象有關聯,用這個就減少了計算量
原論文將RPN與Fast-RCNN訓練重合了,這樣就節省了很大的計算量
對於Faster的區域推薦只用通過一個3*3和一些1*1的卷積核,計算量很小,就基本不用花什麼時間了
速度對比:
授課時(2016.1)最好的組合還是 resNet101 faster RCNN
one-stage方法
YOLO:you only look once
將檢測問題直接當作迴歸來做
分離空間網格,他們7*7,對於網格中的每個元素,我們得到固定數目的bounding boxes,他們大部分實驗用B=2個
每個grid,預測2個B bounding boxes — 也就是4個數,還要預測一個score來表示可信度
現在還有SSD做實時的
問題:模型輸出數有限,速度快,但是不準,於是有fast YOLO
Object Detection 程式碼:
R-CNN
(Cafffe MATLAB): https://github.com/rbgirshick/rcnn
Probably don’t use this; too slow
Fast R-CNN
(Caffe MATLAB): https://github.com/rbgirshick/fast-rcnn
Faster R-CNN
(Caffe MATLAB): https://github.com/ShaoqingRen/faster_rcnn
(Caffe Python): https://github.com/rbgirshick/py-faster-rcnn
YOLO
http://pjreddie.com/darknet/yolo/
Maybe try this for projects?
第九講:卷積神經網路的視覺化與進一步理解
conv層weights(過濾器)如下
視覺化只能在第一層做,跟原圖有關
t-SNE對高維資料自動聚類,詳見:http://bindog.github.io/blog/2016/06/04/from-sne-to-tsne-to-largevis/
整個神經網路可微才能夠計算梯度
要想計算特定神經元的梯度,將這個神經元設定梯度為1.00,然後其餘的設定為0,做BP
用解析梯度法而不用數值梯度法的原因是,數值法更慢
對於一個任意的神經元,他的梯度並不是很容易看出是什麼,有個deconv的方法 guided BP
relu是阻斷為負數的BP
guided BP—只傳遞正數的梯度的部分,用relu;並且還阻斷梯度為負數的
只通過有正影響的,不通過有負影響的
普通的看起來不明顯的原因,是因為每個畫素點到目標神經元的影響有正有負,在GBP的只通過正值,就能看到清晰的圖片
Optimization to Image
另外通過優化的方法,對某一類物體儘可能高的提高得分,最大程度的啟用網路中某些單元的影象
無論梯度正負,只取最大值效果,不考慮符號
暗色的地方說明:這塊地方出現的東西,神經網路不care對結果的影響,但是如果改變白色部分,就會影響結果
開始的時候,kernel很小,比如3*3,但是後面層的畫素對結果的影響就可以組合了,變大很多,所以在底層就是一些片段的組合,但是到高層了會成團,到高層之後一個neuron就可能是整張圖片的函式了
DeepDream https://github.com/google/deepdream
增強跟目標相似的東西,做BP增強原圖
因為資料中狗很多,所以整個網路比較關注狗的特徵
損失要和這裡的啟用匹配,比如啟用和放進甘道夫的啟用類似
如何去fool一個分類器
其實可以將一張圖“變成”另外一張圖,對於分類器來說。
在高層中將梯度設定成另一個類別,然後反向傳播,得到原影象的改變
只是把畫素向置信度高的方向移動一點點,對於分類器來說就成了另一張圖,這是因為前向傳播中的函式線性的特點,因為在網路的頂端加了一個線性分類器,對於高維空間,只需要對每個維度順著結果遞增的梯度方向做微小改變,這個分類器就會被fool。
對抗樣本(adversarial example)—這是一種脆弱性,這和影象也沒關,任何data都可以做對抗樣本,目前沒有好的解決方法,是一個好的課題
如果人臉識別被做對抗樣本就可以變成任意一個人
第十講、RNN
RNN因為是不同做重複操作:
所以結果容易要麼爆炸,要麼消失
小技巧控制梯度爆炸:如果梯度大於5,就逐元素裁剪為5 — 梯度裁剪
- RNN有梯度彌散問題
- LSTM能很好的抑制梯度彌散,因為高速細胞只改變了加法運算,不會消失,每次都乘以相同的矩陣
第十一講、cnn實戰
data augmentation
- 翻轉是最常見的augment
random crops
test的時候,10-crops
上下左右中*2(水平翻轉),這十個位置得分取均值
顏色改變,如:對比度,但並不一定常見;還可以對每個畫素做PCA主成分分析,遍歷所有畫素後得到訓練集中的主要顏色有哪些,PCA給出顏色空間中3個主要顏色在哪個方向中變化最劇烈
防止過擬合,可以在forward的時候加一些隨機擾動,比如augment就是一種;還可以dropout dropconnect;還有Batch Normalization(任一張圖片,因為在不同的batch中,會不同,相當於引入了隨機噪聲)
transfer learning
1、如果自己訓練資料真的很少,可以把pre-trained的網路,當作一個特徵提取器,只train最後一層
2、對於從scratch開始學的層:一般學習率較高,但也不能太高(比如原來網路的1/10);對於finetune的層:就需要更小的learning rate(比如原來的1/100)
3、一般情況下,用同型別的訓練資料好,但是前幾層的feature很general,幾乎所有的影象資料都需要,所以不用太擔心
4、finetune步驟:
step1. 把網路固定,只train後面幾層
step2. 當最後幾層快收斂之後,再對中間層微調
一般來說都不應該從scratch開始訓練,多用finetuning,除非有很大很大dataset
5、(1)三層3*3的layer疊起來,一個neuron可以看到多大
5*5
(2)三個加起來呢?
7*7
(3)引數數量比較
(4)浮點運算量比較
更深的網路,更少的計算就有更強的非線性
6、bottleneck技巧—channel方向減半
這樣空間上尺寸一樣,但是深度方向上特徵數減半
代替全連線層
將3*3變成3*1 1*3
甚至可以將bottleneck與這種breakdown結構結合起來,Googlenet就有這麼做(rethink那篇)
7、將大的核分解成小的,會更有效率
- 引數更少
- 計算量更小
- 非線性更強
如何快速計算卷積
可以拉成矩陣操作,BP也可以用矩陣操作
在計算的時候可以用FFT(快速傅立葉變換)
第十二講、開源庫簡介
caffe
四種主要的類
blob
n維張量,儲存網路中所有的資料(比如畫素值、label)、權重、activations
內部有4個n維張量:raw data,diffs(儲存梯度),上面兩個各有cpu核gpu版本
layer
forward時:接受blob,bottom輸入,top輸出
BP時:layer實現BP,與上面相反
net
把許多層聯絡在一起,Net是layer的有向非迴圈圖
描述layer的連線,不用自己去修改程式碼
solver
進入net,更新網路的引數
不同的更新規則,比如Adam
caffe.proto
類json,用於序列化
定義了caffe中用到的所有 proto buffer種類
可以作為說明書來讀
caffe訓練步驟
讀入資料的方式
train_val的重要點
.caffemodel裡面其實是用鍵值對的形式儲存,但是是二進位制儲存(與layer名匹配),所以看不到
如果layer名匹配,就從pre-train初始化,否則從scratch
還可以在不同階段用不同的solver來調參
caffe的優缺點
tensorflow
與theano很像
tensorboard,可以實時看到圖形
講者給的建議
第十三講、attention
spacial transform network
空間轉換模組 — 放到其他網路中,可以attention
詳見:https://www.youtube.com/watch?v=Ywv0Xi2-14Y
第十四講、unsupervised learning
生成對抗樣本—生成圖片
- Autoencoders
- gan(Generative Adversarial Nets)
三、cs231n筆記
之所以將note部分單獨列出來,是希望不破壞之前聽課的筆記完整性,同時筆記部分有很多需要另記。
image classification notes
python介紹那章就直接skip了
Nearest Neighbor分類器
對於NN分類器有兩種計算距離的方法,L1和L2
(1)L1距離,即逐個畫素比較
例子如下:
(2)L2距離,從幾何學的角度,可以理解為它在計算兩個向量間的歐式距離。
L1和L2比較。比較這兩個度量方式是挺有意思的。在面對兩個向量之間的差異時,L2比L1更加不能容忍這些差異。也就是說,相對於1個巨大的差異,L2距離更傾向於接受多箇中等程度的差異。L1和L2都是在p-norm常用的特殊形式。
k-Nearest Neighbor分類器
上面兩種分類器不好的原因:
為什麼只用最相似的1張圖片的標籤來作為測試影象的標籤呢?這不是很奇怪嗎
KNN原理:
使用k-Nearest Neighbor分類器就能做得更好。它的思想很簡單:與其只找最相近的那1個圖片的標籤,我們找最相似的k個圖片的標籤,然後讓他們針對測試圖片進行投票,最後把票數最高的標籤作為對測試圖片的預測。所以當k=1的時候,k-Nearest Neighbor分類器就是Nearest Neighbor分類器。從直觀感受上就可以看到,更高的k值可以讓分類的效果更平滑,使得分類器對於異常值更有抵抗力。
KNN也有一個問題,因為很容易被背景主導,而不是圖片本身的語義。
CS231n課程筆記翻譯:線性分類筆記
將影象看做高維度的點:既然影象被伸展成為了一個高維度的列向量,那麼我們可以把影象看做這個高維度空間中的一個點(即每張影象是3072維空間中的一個點)。整個資料集就是一個點的集合,每個點都帶有1個分類標籤。
既然定義每個分類類別的分值是權重和影象的矩陣乘,那麼每個分類類別的分數就是這個空間中的一個線性函式的函式值。我們沒辦法視覺化3072維空間中的線性函式,但假設把這些維度擠壓到二維,那麼就可以看看這些分類器在做什麼了:
這裡關於3072維度要說一點,因為每張圖有3072個值,每個值都是一個數,對應到3072維度的一個點,當然都是在0~255
影象空間的示意圖。其中每個影象是一個點,有3個分類器。以紅色的汽車分類器為例,紅線表示空間中汽車分類分數為0的點的集合,紅色的箭頭表示分值上升的方向。所有紅線右邊的點的分數值均為正,且線性升高。紅線左邊的點分值為負,且線性降低。
W的每一行都是一個分類類別的分類器。對於這些數字的幾何解釋是:如果改變其中一行的數字,會看見分類器在空間中對應的直線開始向著不同方向旋轉。而偏差b,則允許分類器對應的直線平移。需要注意的是,如果沒有偏差,無論權重如何,在x_i=0時分類分值始終為0。這樣所有分類器的線都不得不穿過原點。這當然不對了
將線性分類器看做模板匹配:關於權重W的另一個解釋是它的每一行對應著一個分類的模板(有時候也叫作原型)。一張影象對應不同分類的得分,是通過使用內積(也叫點積)來比較影象和模板,然後找到和哪個模板最相似。從這個角度來看,線性分類器就是在利用學習到的模板,針對影象做模板匹配。從另一個角度來看,可以認為還是在高效地使用k-NN,不同的是我們沒有使用所有的訓練集的影象來比較,而是每個類別只用了一張圖片(這張圖片是我們學習到的,而不是訓練集中的某一張),而且我們會使用(負)內積來計算向量間的距離,而不是使用L1或者L2距離。
偏差和權重的合併技巧:在進一步學習前,要提一下這個經常使用的技巧。它能夠將我們常用的引數W和b合二為一。回憶一下,分類評分函式定義為:
f(x_i,W,b)=Wx_i b
分開處理這兩個引數(權重引數W和偏差引數b)有點笨拙,一般常用的方法是把兩個引數放到同一個矩陣中,同時x_i向量就要增加一個維度,這個維度的數值是常量1,這就是預設的偏差維度。這樣新的公式就簡化成下面這樣:
f(x_i,W)=Wx_i
還是以CIFAR-10為例,那麼x_i的大小就變成[3073×1],而不是[3072×1]了,多出了包含常量1的1個維度)。W大小就是[10×3073]了。W中多出來的這一列對應的就是偏差值b,具體見下圖:
————————————————————————————————————————
偏差技巧的示意圖。左邊是先做矩陣乘法然後做加法,右邊是將所有輸入向量的維度增加1個含常量1的維度,並且在權重矩陣中增加一個偏差列,最後做一個矩陣乘法即可。左右是等價的。通過右邊這樣做,我們就只需要學習一個權重矩陣,而不用去學習兩個分別裝著權重和偏差的矩陣了。
影象資料預處理:在上面的例子中,所有影象都是使用的原始畫素值(從0到255)。在機器學習中,對於輸入的特徵做歸一化(normalization)處理是常見的套路。而在影象分類的例子中,影象上的每個畫素可以看做一個特徵。在實踐中,對每個特徵減去平均值來中心化資料是非常重要的。在這些圖片的例子中,該步驟意味著根據訓練集中所有的影象計算出一個平均影象值,然後每個影象都減去這個平均值,這樣影象的畫素值就大約分佈在[-127, 127]之間了。下一個常見步驟是,讓所有數值分佈的區間變為[-1, 1]。零均值的中心化是很重要的,等我們理解了梯度下降後再來詳細解釋。
在上一節定義了從影象畫素值到所屬類別的評分函式(score function),該函式的引數是權重矩陣W。在函式中,資料(x_i,y_i)是給定的,不能修改。但是我們可以調整權重矩陣這個引數,使得評分函式的結果與訓練資料集中影象的真實類別一致,即評分函式在正確的分類的位置應當得到最高的評分(score)。
回到之前那張貓的影象分類例子,它有針對“貓”,“狗”,“船”三個類別的分數。我們看到例子中權重值非常差,因為貓分類的得分非常低(-96.8),而狗(437.9)和船(61.95)比較高。我們將使用損失函式(Loss Function)(有時也叫代價函式Cost Function或目標函式Objective)來衡量我們對結果的不滿意程度。直觀地講,當評分函式輸出結果與真實結果之間差異越大,損失函式輸出越大,反之越小。
多類支援向量機損失 Multiclass Support Vector Machine Loss
損失函式的具體形式多種多樣。首先,介紹常用的多類支援向量機(SVM)損失函式。SVM的損失函式想要SVM在正確分類上的得分始終比不正確分類上的得分高出一個邊界值\Delta。我們可以把損失函式想象成一個人,這位SVM先生(或者女士)對於結果有自己的品位,如果某個結果能使得損失值更低,那麼SVM就更加喜歡它。
讓我們更精確一些。回憶一下,第i個資料中包含影象x_i的畫素和代表正確類別的標籤y_i。評分函式輸入畫素資料,然後通過公式f(x_i,W)來計算不同分類類別的分值。這裡我們將分值簡寫為s。比如,針對第j個類別的得分就是第j個元素:s_j=f(x_i,W)_j。針對第i個資料的多類
SVM的損失函式定義如下:
L_i=\sum_{j\not=y_i}max(0,s_j-s_{y_i} \Delta)
舉例:用一個例子演示公式是如何計算的。假設有3個分類,並且得到了分值s=[13,-7,11]。其中第一個類別是正確類別,即y_i=0。同時假設\Delta是10(後面會詳細介紹該超引數)。上面的公式是將所有不正確分類(j\not=y_i)加起來,所以我們得到兩個部分:
Li=max(0,-7-13 10) max(0,11-13 10)
可以看到第一個部分結果是0,這是因為[-7-13 10]得到的是負數,經過max(0,-)函式處理後得到0。這一對類別分數和標籤的損失值是0,這是因為正確分類的得分13與錯誤分類的得分-7的差為20,高於邊界值10。而SVM只關心差距至少要大於10,更大的差值還是算作損失值為0。第二個部分計算[11-13 10]得到8。雖然正確分類的得分比不正確分類的得分要高(13>11),但是比10的邊界值還是小了,分差只有2,這就是為什麼損失值等於8。簡而言之,SVM的損失函式想要正確分類類別y_i的分數比不正確類別分數高,而且至少要高\Delta。如果不滿足這點,就開始計算損失值。
那麼在這次的模型中,我們面對的是線性評分函式(f(x_i,W)=Wx_i),所以我們可以將損失函式的公式稍微改寫一下:
L_i=\sum_{j\not=y_i}max(0,w^T_jx_i-w^T_{y_i}x_i \Delta)
其中w_j是權重W的第j行,被變形為列向量。然而,一旦開始考慮更復雜的評分函式f公式,這樣做就不是必須的了。
在結束這一小節前,還必須提一下的屬於是關於0的閥值:max(0,-)函式,它常被稱為折葉損失(hinge loss)。有時候會聽到人們使用平方折葉損失SVM(即L2-SVM),它使用的是max(0,-)^2,將更強烈(平方地而不是線性地)地懲罰過界的邊界值。不使用平方是更標準的版本,但是在某些資料集中,平方折葉損失會工作得更好。可以通過交叉驗證來決定到底使用哪個。
正則化(Regularization):
上面損失函式有一個問題。假設有一個資料集和一個權重集W能夠正確地分類每個資料(即所有的邊界都滿足,對於所有的i都有L_i=0)。問題在於這個W並不唯一:可能有很多相似的W都能正確地分類所有的資料。一個簡單的例子:如果W能夠正確分類所有資料,即對於每個資料,損失值都是0。那麼當\lambda>1時,任何數乘\lambda W都能使得損失值為0,因為這個變化將所有分值的大小都均等地擴大了,所以它們之間的絕對差值也擴大了。舉個例子,如果一個正確分類的分值和舉例它最近的錯誤分類的分值的差距是15,對W乘以2將使得差距變成30。
其中最好的性質就是對大數值權重進行懲罰,可以提升其泛化能力,因為這就意味著沒有哪個維度能夠獨自對於整體分值有過大的影響。舉個例子,假設輸入向量x=[1,1,1,1],兩個權重向量w_1=[1,0,0,0],w_2=[0.25,0.25,0.25,0.25]。那麼w^T_1x=w^T_2=1,兩個權重向量都得到同樣的內積,但是w_1的L2懲罰是1.0,而w_2的L2懲罰是0.25。因此,根據L2懲罰來看,w_2更好,因為它的正則化損失更小。從直觀上來看,這是因為w_2的權重值更小且更分散。既然L2懲罰傾向於更小更分散的權重向量,這就會鼓勵分類器最終將所有維度上的特徵都用起來,而不是強烈依賴其中少數幾個維度。在後面的課程中可以看到,這一效果將會提升分類器的泛化能力,並避免過擬合。
簡而言之,就是有衡量哪一種w更好的方法了
注:和權重不同,偏差沒有這樣的效果,因為它們並不控制輸入維度上的影響強度。因此通常只對權重W正則化,而不正則化偏差b。在實際操作中,可發現這一操作的影響可忽略不計。最後,因為正則化懲罰的存在,不可能在所有的例子中得到0的損失值,這是因為只有當W=0的特殊情況下,才能得到損失值為0。
Softmax分類器
其中函式f_j(z)=\frac{e^{z_j}}{\sum_ke^{z_k}}被稱作softmax 函式:其輸入值是一個向量,向量中元素為任意實數的評分值(z中的),函式對其進行壓縮,輸出一個向量,其中每個元素值在0到1之間,且所有元素之和為1。所以,包含softmax函式的完整交叉熵損失看起唬人,實際上還是比較容易理解的。
簡而言之,就是將分數進行壓縮,輸出相對概率 — 即歸一化
讓人迷惑的命名規則:
精確地說,SVM分類器使用的是折葉損失(hinge loss),有時候又被稱為最大邊界損失(max-margin loss)。Softmax分類器使用的是交叉熵損失(corss-entropy loss)。Softmax分類器的命名是從softmax函式那裡得來的,softmax函式將原始分類評分變成正的歸一化數值,所有數值和為1,這樣處理後交叉熵損失才能應用。注意從技術上說“softmax損失(softmax loss)”是沒有意義的,因為softmax只是一個壓縮數值的函式。但是在這個說法常常被用來做簡稱。
SVM和Softmax的比較
針對一個資料點,SVM和Softmax分類器的不同處理方式的例子。兩個分類器都計算了同樣的分值向量f(本節中是通過矩陣乘來實現)。不同之處在於對f中分值的解釋:SVM分類器將它們看做是分類評分,它的損失函式鼓勵正確的分類(本例中是藍色的類別2)的分值比其他分類的分值高出至少一個邊界值。Softmax分類器將這些數值看做是每個分類沒有歸一化的對數概率,鼓勵正確分類的歸一化的對數概率變高,其餘的變低。SVM的最終的損失值是1.58,Softmax的最終的損失值是0.452,但要注意這兩個數值沒有可比性。只在給定同樣資料,在同樣的分類器的損失值計算中,它們才有意義。
在實際使用中,SVM和Softmax經常是相似的:通常說來,兩種分類器的表現差別很小,不同的人對於哪個分類器更好有不同的看法。相對於Softmax分類器,SVM更加“區域性目標化(local objective)”,這既可以看做是一個特性,也可以看做是一個劣勢。考慮一個評分是[10, -2, 3]的資料,其中第一個分類是正確的。那麼一個SVM(\Delta =1)會看到正確分類相較於不正確分類,已經得到了比邊界值還要高的分數,它就會認為損失值是0。SVM對於數字個體的細節是不關心的:如果分數是[10, -100, -100]或者[10, 9, 9],對於SVM來說沒設麼不同,只要滿足超過邊界值等於1,那麼損失值就等於0。
對於softmax分類器,情況則不同。對於[10, 9, 9]來說,計算出的損失值就遠遠高於[10, -100, -100]的。換句話來說,softmax分類器對於分數是永遠不會滿意的:正確分類總能得到更高的可能性,錯誤分類總能得到更低的可能性,損失值總是能夠更小。但是,SVM只要邊界值被滿足了就滿意了,不會超過限制去細微地操作具體分數。這可以被看做是SVM的一種特性。舉例說來,一個汽車的分類器應該把他的大量精力放在如何分辨小轎車和大卡車上,而不應該糾結於如何與青蛙進行區分,因為區分青蛙得到的評分已經足夠低了。
策略#1:一個差勁的初始方案:隨機搜尋
既然確認引數集W的好壞蠻簡單的,那第一個想到的(差勁)方法,就是可以隨機嘗試很多不同的權重,然後看其中哪個最好。
當然也可以迭代取優
策略#2:隨機本地搜尋
第一個策略可以看做是每走一步都嘗試幾個隨機方向,如果某個方向是向山下的,就向該方向走一步。這次我們從一個隨機W開始,然後生成一個隨機的擾動\delta W ,只有當W \delta W的損失值變低,我們才會更新。
策略#3:跟隨梯度
前兩個策略中,我們是嘗試在權重空間中找到一個方向,沿著該方向能降低損失函式的損失值。其實不需要隨機尋找方向,因為可以直接計算出最好的方向,這就是從數學上計算出最陡峭的方向。這個方向就是損失函式的梯度(gradient)。在矇眼徒步者的比喻中,這個方法就好比是感受我們腳下山體的傾斜程度,然後向著最陡峭的下降方向下山。
在一維函式中,斜率是函式在某一點的瞬時變化率。梯度是函式的斜率的一般化表達,它不是一個值,而是一個向量。在輸入空間中,梯度是各個維度的斜率組成的向量(或者稱為導數derivatives)。對一維函式的求導公式如下:
frac{df(x)}{dx}=\lim_{h\to 0}\frac{f(x h)-f(x)}{h}
當函式有多個引數的時候,我們稱導數為偏導數。而梯度就是在每個維度上偏導數所形成的向量。
步長的影響:
梯度指明瞭函式在哪個方向是變化率最大的,但是沒有指明在這個方向上應該走多遠。在後續的課程中可以看到,選擇步長(也叫作學習率)將會是神經網路訓練中最重要(也是最頭痛)的超引數設定之一。還是用矇眼徒步者下山的比喻,這就好比我們可以感覺到腳朝向的不同方向上,地形的傾斜程度不同。但是該跨出多長的步長呢?不確定。如果謹慎地小步走,情況可能比較穩定但是進展較慢(這就是步長較小的情況)。相反,如果想盡快下山,那就大步走吧,但結果也不一定盡如人意。在上面的程式碼中就能看見反例,在某些點如果步長過大,反而可能越過最低點導致更高的損失值。
效率問題:你可能已經注意到,計算數值梯度的複雜性和引數的量線性相關。在本例中有30730個引數,所以損失函式每走一步就需要計算30731次損失函式的梯度。現代神經網路很容易就有上千萬的引數,因此這個問題只會越發嚴峻。顯然這個策略不適合大規模資料,我們需要更好的策略。
微分分析計算梯度
使用有限差值近似計算梯度比較簡單,但缺點在於終究只是近似(因為我們對於h值是選取了一個很小的數值,但真正的梯度定義中h趨向0的極限),且耗費計算資源太多。第二個梯度計算方法是利用微分來分析,能得到計算梯度的公式(不是近似),用公式計算梯度速度很快,唯一不好的就是實現的時候容易出錯。為了解決這個問題,在實際操作時常常將分析梯度法的結果和數值梯度法的結果作比較,以此來檢查其實現的正確性,這個步驟叫做梯度檢查。
梯度下降
現在可以計算損失函式的梯度了,程式重複地計算梯度然後對引數進行更新,這一過程稱為梯度下降,他的普通版本是這樣的:
普通的梯度下降
while True:
weights_grad = evaluate_gradient(loss_fun, data, weights)
weights = - step_size * weights_grad # 進行梯度更新
這個簡單的迴圈在所有的神經網路核心庫中都有。雖然也有其他實現最優化的方法(比如LBFGS),但是到目前為止,梯度下降是對神經網路的損失函式最優化中最常用的方法。課程中,我們會在它的迴圈細節增加一些新的東西(比如更新的具體公式),但是核心思想不變,那就是我們一直跟著梯度走,直到結果不再變化。
小批量資料梯度下降(Mini-batch gradient descent):在大規模的應用中(比如ILSVRC挑戰賽),訓練資料可以達到百萬級量級。如果像這樣計算整個訓練集,來獲得僅僅一個引數的更新就太浪費了。一個常用的方法是計算訓練集中的小批量(batches)資料。例如,在目前最高水平的卷積神經網路中,一個典型的小批量包含256個例子,而整個訓練集是多少呢?一百二十萬個。這個小批量資料就用來實現一個引數更新:
# 普通的小批量資料梯度下降
while True:
data_batch = sample_training_data(data, 256) # 256個資料
weights_grad = evaluate_gradient(loss_fun, data_batch, weights)
weights = - step_size * weights_grad # 引數更新
這個方法之所以效果不錯,是因為訓練集中的資料都是相關的。要理解這一點,可以想象一個極端情況:在ILSVRC中的120萬個影象是1000張不同圖片的複製(每個類別1張圖片,每張圖片有1200張複製)。那麼顯然計算這1200張複製影象的梯度就應該是一樣的。對比120萬張圖片的資料損失的均值與只計算1000張的子集的資料損失均值時,結果應該是一樣的。實際情況中,資料集肯定不會包含重複影象,那麼小批量資料的梯度就是對整個資料集梯度的一個近似。因此,在實踐中通過計算小批量資料的梯度可以實現更快速地收斂,並以此來進行更頻繁的引數更新。
小批量資料策略有個極端情況,那就是每個批量中只有1個資料樣本,這種策略被稱為隨機梯度下降(Stochastic Gradient Descent 簡稱SGD),有時候也被稱為線上梯度下降。這種策略在實際情況中相對少見,因為向量化操作的程式碼一次計算100個資料 比100次計算1個資料要高效很多。即使SGD在技術上是指每次使用1個資料來計算梯度,你還是會聽到人們使用SGD來指代小批量資料梯度下降(或者用MGD來指代小批量資料梯度下降,而BGD來指代則相對少見)。小批量資料的大小是一個超引數,但是一般並不需要通過交叉驗證來調參。它一般由儲存器的限制來決定的,或者乾脆設定為同樣大小,比如32,64,128等。之所以使用2的指數,是因為在實際中許多向量化操作實現的時候,如果輸入資料量是2的倍數,那麼運算更快。
卷積神經網路(CNNs / ConvNets)
普通的神經網路,如果用全連線,在CIFAR-10中,影象的尺寸是32x32x3,對應的的常規神經網路的第一個隱層中,每一個單獨的全連線神經元就有32x32x3=3072個權重,這太多,而且更大的影象還會更多
而網路中肯定不止一個神經元,那麼引數的量就會快速增加!顯而易見,這種全連線方式效率低下,大量的引數也很快會導致網路過擬合。
CNN層中的神經元將只與前一層中的一小塊區域連線,而不是採取全連線方式。
對於用來分類CIFAR-10中的影象的卷積網路,其最後的輸出層的維度是1x1x10,因為在卷積神經網路結構的最後部分將會把全尺寸的影象壓縮為包含分類評分的一個向量,向量是在深度方向排列的。下面是例子:
左邊是一個3層的神經網路。右邊是一個卷積神經網路,圖例中網路將它的神經元都排列成3個維度(寬、高和深度)。卷積神經網路的每一層都將3D的輸入資料變化為神經元3D的啟用資料並輸出。在這個例子中,紅色的輸入層裝的是影象,所以它的寬度和高度就是影象的寬度和高度,它的深度是3(代表了紅、綠、藍3種顏色通道)。
用來構建卷積網路的各種層
一個簡單的卷積神經網路是由各種層按照順序排列組成,網路中的每個層使用一個可以微分的函式將啟用資料從一個層傳遞到另一個層。卷積神經網路主要由三種型別的層構成:卷積層,匯聚(Pooling)層和全連線層(全連線層和常規神經網路中的一樣)。
網路結構例子:這僅僅是個概述,下面會更詳解的介紹細節。一個用於CIFAR-10影象資料分類的卷積神經網路的結構可以是[輸入層-卷積層-ReLU層-匯聚層-全連線層]。細節如下:
輸入[32x32x3]存有影象的原始畫素值,本例中影象寬高均為32,有3個顏色通道。
卷積層中,神經元與輸入層中的一個區域性區域相連,每個神經元都計算自己與輸入層相連的小區域與自己權重的內積。卷積層會計算所有神經元的輸出。如果我們使用12個濾波器(也叫作核),得到的輸出資料體的維度就是[32x32x12]。
ReLU層將會逐個元素地進行啟用函式操作,比如使用以0為閾值的max(0,x)作為啟用函式。該層對資料尺寸沒有改變,還是[32x32x12]。
匯聚層在在空間維度(寬度和高度)上進行降取樣(downsampling)操作,資料尺寸變為[16x16x12]。
全連線層將會計算分類評分,資料尺寸變為[1x1x10],其中10個數字對應的就是CIFAR-10中10個類別的分類評分值。正如其名,全連線層與常規神經網路一樣,其中每個神經元都與前一層中所有神經元相連線。
卷積神經網路一層一層地將影象從原始畫素值變換成最終的分類評分值。其中有的層含有引數,有的沒有。具體說來,卷積層和全連線層(CONV/FC)對輸入執行變換操作的時候,不僅會用到啟用函式,還會用到很多引數(神經元的突觸權值和偏差)。而ReLU層和匯聚層則是進行一個固定不變的函式操作。卷積層和全連線層中的引數會隨著梯度下降被訓練,這樣卷積神經網路計算出的分類評分就能和訓練集中的每個影象的標籤吻合了。
簡單案例中卷積神經網路的結構,就是一系列的層將輸入資料變換為輸出資料(比如分類評分)。
卷積神經網路結構中有幾種不同型別的層(目前最流行的有卷積層、全連線層、ReLU層和匯聚層)。
每個層的輸入是3D資料,然後使用一個可導的函式將其變換為3D的輸出資料。
有的層有引數,有的沒有(卷積層和全連線層有,ReLU層和匯聚層沒有)。
有的層有額外的超引數,有的沒有(卷積層、全連線層和匯聚層有,ReLU層沒有)。
卷積層
卷積層的引數是有一些可學習的濾波器集合構成的。每個濾波器在空間上(寬度和高度)都比較小,但是深度和輸入資料一致。舉例來說,卷積神經網路第一層的一個典型的濾波器的尺寸可以是5x5x3(寬高都是5畫素,深度是3是因為影象應為顏色通道,所以有3的深度)。
在前向傳播的時候,讓每個濾波器都在輸入資料的寬度和高度上滑動(更精確地說是卷積),然後計算整個濾波器和輸入資料任一處的內積。
當濾波器沿著輸入資料的寬度和高度滑過後,會生成一個2維的啟用圖(activation map),啟用圖給出了在每個空間位置處濾波器的反應。
直觀地來說,網路會讓濾波器學習到當它看到某些型別的視覺特徵時就啟用,具體的視覺特徵可能是某些方位上的邊界,或者在第一層上某些顏色的斑點,甚至可以是網路更高層上的蜂巢狀或者車輪狀圖案。
在每個卷積層上,我們會有一整個集合的濾波器(比如12個),每個都會生成一個不同的二維啟用圖。將這些啟用對映在深度方向上層疊起來就生成了輸出資料。
共享引數(以大腦做比喻):如果你喜歡用大腦和生物神經元來做比喻,那麼輸出的3D資料中的每個資料項可以被看做是神經元的一個輸出,而該神經元只觀察輸入資料中的一小部分,並且和空間上左右兩邊的所有神經元共享引數(因為這些數字都是使用同一個濾波器得到的結果)。現在開始討論神經元的連線,它們在空間中的排列,以及它們引數共享的模式。
區域性連線:在處理影象這樣的高維度輸入時,讓每個神經元都與前一層中的所有神經元進行全連線是不現實的。相反,我們讓每個神經元只與輸入資料的一個區域性區域連線。該連線的空間大小叫做神經元的感受野(receptive field),它的尺寸是一個超引數(其實就是濾波器的空間尺寸)。在深度方向上,這個連線的大小總是和輸入量的深度相等。需要再次強調的是,我們對待空間維度(寬和高)與深度維度是不同的:連線在空間(寬高)上是區域性的,但是在深度上總是和輸入資料的深度一致。
左邊:紅色的是輸入資料體(比如CIFAR-10中的影象),藍色的部分是第一個卷積層中的神經元。卷積層中的每個神經元都只是與輸入資料體的一個區域性在空間上相連,但是與輸入資料體的所有深度維度全部相連(所有顏色通道)。在深度方向上有多個神經元(本例中5個),它們都接受輸入資料的同一塊區域(感受野相同)。至於深度列的討論在下文中有。
右邊:神經網路章節中介紹的神經元保持不變,它們還是計算權重和輸入的內積,然後進行啟用函式運算,只是它們的連線被限制在一個區域性空間。
空間排列:
上文講解了卷積層中每個神經元與輸入資料體之間的連線方式,但是尚未討論輸出資料體中神經元的數量,以及它們的排列方式。3個超引數控制著輸出資料體的尺寸:深度(depth),步長(stride)和零填充(zero-padding)。下面是對它們的討論:
首先,輸出資料體的深度是一個超引數:它和使用的濾波器的數量一致,而每個濾波器在輸入資料中尋找一些不同的東西。舉例來說,如果第一個卷積層的輸入是原始影象,那麼在深度維度上的不同神經元將可能被不同方向的邊界,或者是顏色斑點啟用。我們將這些沿著深度方向排列、感受野相同的神經元集合稱為深度列(depth column),也有人使用纖維(fibre)來稱呼它們。
其次,在滑動濾波器的時候,必須指定步長。當步長為1,濾波器每次移動1個畫素。當步長為2(或者不常用的3,或者更多,這些在實際中很少使用),濾波器滑動時每次移動2個畫素。這個操作會讓輸出資料體在空間上變小。
在下文可以看到,有時候將輸入資料體用0在邊緣處進行填充是很方便的。這個零填充(zero-padding)的尺寸是一個超引數。零填充有一個良好性質,即可以控制輸出資料體的空間尺寸(最常用的是用來保持輸入資料體在空間上的尺寸,這樣輸入和輸出的寬高都相等)。
為什麼要用引數共享
注意引數共享的假設是有道理的:如果在影象某些地方探測到一個水平的邊界是很重要的,那麼在其他一些地方也會同樣是有用的,這是因為影象結構具有平移不變性。所以在卷積層的輸出資料體的55×55個不同位置中,就沒有必要重新學習去探測一個水平邊界了。
注意有時候引數共享假設可能沒有意義,特別是當卷積神經網路的輸入影象是一些明確的中心結構時候。這時候我們就應該期望在圖片的不同位置學習到完全不同的特徵。一個具體的例子就是輸入影象是人臉,人臉一般都處於圖片中心。你可能期望不同的特徵,比如眼睛特徵或者頭髮特徵可能(也應該)會在圖片的不同位置被學習。在這個例子中,通常就放鬆引數共享的限制,將層稱為區域性連線層(Locally-Connected Layer)。
把全連線層轉化成卷積層
全連線層和卷積層之間唯一的不同就是卷積層中的神經元只與輸入資料中的一個區域性區域連線,並且在卷積列中的神經元共享引數。然而在兩類層中,神經元都是計算點積,所以它們的函式形式是一樣的。因此,將此兩者相互轉化是可能的:
對於任一個卷積層,都存在一個能實現和它一樣的前向傳播函式的全連線層。權重矩陣是一個巨大的矩陣,除了某些特定塊(這是因為有區域性連線),其餘部分都是零。而在其中大部分塊中,元素都是相等的(因為引數共享)。
相反,任何全連線層都可以被轉化為卷積層。比如,一個K=4096的全連線層,輸入資料體的尺寸是7\times 7\times 512,這個全連線層可以被等效地看做一個F=7,P=0,S=1,K=4096的卷積層。換句話說,就是將濾波器的尺寸設定為和輸入資料體的尺寸一致了。因為只有一個單獨的深度列覆蓋並滑過輸入資料體,所以輸出將變成1\times 1\times 4096,這個結果就和使用初始的那個全連線層一樣了。
卷積神經網路的結構
卷積神經網路通常是由三種層構成:卷積層,匯聚層(除非特別說明,一般就是最大值匯聚)和全連線層(簡稱FC)。ReLU啟用函式也應該算是是一層,它逐元素地進行啟用函式操作。在本節中將討論在卷積神經網路中這些層通常是如何組合在一起的。
層的排列規律
卷積神經網路最常見的形式就是將一些卷積層和ReLU層放在一起,其後緊跟匯聚層,然後重複如此直到影象在空間上被縮小到一個足夠小的尺寸,在某個地方過渡成成全連線層也較為常見。最後的全連線層得到輸出,比如分類評分等。換句話說,最常見的卷積神經網路結構如下:
INPUT -> [[CONV -> RELU]*N -> POOL?]*M -> [FC -> RELU]*K -> FC
其中*指的是重複次數,POOL?指的是一個可選的匯聚層。其中N >=0,通常N<=3,M>=0,K>=0,通常K<3。例如,下面是一些常見的網路結構規律:
INPUT -> FC,實現一個線性分類器,此處N = M = K = 0。
INPUT -> CONV -> RELU -> FC
INPUT -> [CONV -> RELU -> POOL]*2 -> FC -> RELU -> FC。此處在每個匯聚層之間有一個卷積層。
INPUT -> [CONV -> RELU -> CONV -> RELU -> POOL]*3 -> [FC -> RELU]*2 -> FC。此處每個匯聚層前有兩個卷積層,這個思路適用於更大更深的網路,因為在執行具有破壞性的匯聚操作前,多重的卷積層可以從輸入資料中學習到更多的複雜特徵。
幾個小濾波器卷積層的組合比一個大濾波器卷積層好:假設你一層一層地重疊了3個3×3的卷積層(層與層之間有非線性啟用函式)。在這個排列下,第一個卷積層中的每個神經元都對輸入資料體有一個3×3的視野。第二個卷積層上的神經元對第一個卷積層有一個3×3的視野,也就是對輸入資料體有5×5的視野。同樣,在第三個卷積層上的神經元對第二個卷積層有3×3的視野,也就是對輸入資料體有7×7的視野。假設不採用這3個3×3的卷積層,二是使用一個單獨的有7×7的感受野的卷積層,那麼所有神經元的感受野也是7×7,但是就有一些缺點。首先,多個卷積層與非線性的啟用層交替的結構,比單一卷積層的結構更能提取出深層的更好的特徵。其次,假設所有的資料有C個通道,那麼單獨的7×7卷積層將會包含C\times (7\times 7\times C)=49C^2個引數,而3個3×3的卷積層的組合僅有3\times (C\times (3\times 3\times C))=27C^2個引數。直觀說來,最好選擇帶有小濾波器的卷積層組合,而不是用一個帶有大的濾波器的卷積層。前者可以表達出輸入資料中更多個強力特徵,使用的引數也更少。唯一的不足是,在進行反向傳播時,中間的卷積層可能會導致佔用更多的記憶體。
層的尺寸設定規律
到現在為止,我們都沒有提及卷積神經網路中每層的超引數的使用。現在先介紹設定結構尺寸的一般性規則,然後根據這些規則進行討論:
輸入層(包含影象的)應該能被2整除很多次。常用數字包括32(比如CIFAR-10),64,96(比如STL-10)或224(比如ImageNet卷積神經網路),384和512。
卷積層應該使用小尺寸濾波器(比如3×3或最多5×5),使用步長S=1。還有一點非常重要,就是對輸入資料進行零填充,這樣卷積層就不會改變輸入資料在空間維度上的尺寸。比如,當F=3,那就使用P=1來保持輸入尺寸。當F=5,P=2,一般對於任意F,當P=(F-1)/2的時候能保持輸入尺寸。如果必須使用更大的濾波器尺寸(比如7×7之類),通常只用在第一個面對原始影象的卷積層上。
匯聚層負責對輸入資料的空間維度進行降取樣。最常用的設定是用用2×2感受野(即F=2)的最大值匯聚,步長為2(S=2)。注意這一操作將會把輸入資料中75%的啟用資料丟棄(因為對寬度和高度都進行了2的降取樣)。另一個不那麼常用的設定是使用3×3的感受野,步長為2。最大值匯聚的感受野尺寸很少有超過3的,因為匯聚操作過於激烈,易造成資料資訊丟失,這通常會導致演算法效能變差。
減少尺寸設定的問題:上文中展示的兩種設定是很好的,因為所有的卷積層都能保持其輸入資料的空間尺寸,匯聚層只負責對資料體從空間維度進行降取樣。如果使用的步長大於1並且不對卷積層的輸入資料使用零填充,那麼就必須非常仔細地監督輸入資料體通過整個卷積神經網路結構的過程,確認所有的步長和濾波器都尺寸互相吻合,卷積神經網路的結構美妙對稱地聯絡在一起。
為什麼在卷積層使用1的步長?在實際應用中,更小的步長效果更好。上文也已經提過,步長為1可以讓空間維度的降取樣全部由匯聚層負責,卷積層只負責對輸入資料體的深度進行變換。
為何使用零填充?使用零填充除了前面提到的可以讓卷積層的輸出資料保持和輸入資料在空間維度的不變,還可以提高演算法效能。如果卷積層值進行卷積而不進行零填充,那麼資料體的尺寸就會略微減小,那麼影象邊緣的資訊就會過快地損失掉。
因為記憶體限制所做的妥協:在某些案例(尤其是早期的卷積神經網路結構)中,基於前面的各種規則,記憶體的使用量迅速飆升。例如,使用64個尺寸為3×3的濾波器對224x224x3的影象進行卷積,零填充為1,得到的啟用資料體尺寸是[224x224x64]。這個數量就是一千萬的啟用資料,或者就是72MB的記憶體(每張圖就是這麼多,啟用函式和梯度都是)。因為GPU通常因為記憶體導致效能瓶頸,所以做出一些妥協是必須的。在實踐中,人們傾向於在網路的第一個卷積層做出妥協。例如,可以妥協可能是在第一個卷積層使用步長為2,尺寸為7×7的濾波器(比如在ZFnet中)。在AlexNet中,濾波器的尺寸的11×11,步長為4。
計算上的考量
在構建卷積神經網路結構時,最大的瓶頸是記憶體瓶頸。大部分現代GPU的記憶體是3/4/6GB,最好的GPU大約有12GB的記憶體。要注意三種記憶體佔用來源:
來自中間資料體尺寸:卷積神經網路中的每一層中都有啟用資料體的原始數值,以及損失函式對它們的梯度(和啟用資料體尺寸一致)。通常,大部分啟用資料都是在網路中靠前的層中(比如第一個卷積層)。在訓練時,這些資料需要放在記憶體中,因為反向傳播的時候還會用到。但是在測試時可以聰明點:讓網路在測試執行時候每層都只儲存當前的啟用資料,然後丟棄前面層的啟用資料,這樣就能減少巨大的啟用資料量。
來自引數尺寸:即整個網路的引數的數量,在反向傳播時它們的梯度值,以及使用momentum、Adagrad或RMSProp等方法進行最優化時的每一步計算快取。因此,儲存引數向量的記憶體通常需要在引數向量的容量基礎上乘以3或者更多。
卷積神經網路實現還有各種零散的記憶體佔用,比如成批的訓練資料,擴充的資料等等。一旦對於所有這些數值的數量有了一個大略估計(包含啟用資料,梯度和各種雜項),數量應該轉化為以GB為計量單位。把這個值乘以4,得到原始的位元組數(因為每個浮點數佔用4個位元組,如果是雙精度浮點數那就是佔用8個位元組),然後多次除以1024分別得到佔用記憶體的KB,MB,最後是GB計量。如果你的網路工作得不好,一個常用的方法是降低批尺寸(batch size),因為絕大多數的記憶體都是被啟用資料消耗掉了。
写评论
很抱歉,必須登入網站才能發佈留言。