看架構史最容易迷路的地方,是把它當成一串名字。換個讀法:每一代都在回答上一代留下的一個問題。點下面任一個節點,右邊會列出上一代卡在哪、這一代怎麼解、又留下什麼代價。長條是 ImageNet 比賽(ILSVRC)的 top-5 error:模型猜五次,五次都沒猜中的比例。
—
—
—
LeNet-5(1998):結構是 CONV-POOL-CONV-POOL-FC-FC,卷積是 5×5、stride 1,池化用 average pooling、stride 2,activation 是 sigmoid 或 tanh,訓練資料是 MNIST 的 6 萬張手寫數字。講義用它算感受野:rl = (rl−1 − 1) × sl + kl,一路是 5 → 10 → 14 → 28 → 32,到 C5 時每個神經元看得到整張 32×32 的圖。
ImageNet 與 ILSVRC:ImageNet 約 1,400 萬張標註圖、2 萬類,靠網路收集、用 Amazon MTurk 請人標。ILSVRC 比賽用其中 120 萬張訓練圖、1,000 類。
AlexNet(ILSVRC 2012 冠軍,top-5 15.3%):骨架和 LeNet 類似,但改用 max pooling 和 ReLU,模型大很多(7 個隱藏層、65 萬個神經元、6,000 萬個參數),用 GPU 實作(比 CPU 快 50 倍),在兩張 GPU 上訓練一週,加上 dropout。完整結構:
訓練細節:第一次用 ReLU、用了 Norm 層(現在已經不用)、大量 data augmentation、dropout 0.5、batch size 128、SGD momentum 0.9、learning rate 1e-2(validation 準確率停住時手動除以 10)、L2 weight decay 5e-4。7 個 CNN 的 ensemble 把錯誤率從 18.2% 降到 15.4%。
CaffeNet:AlexNet 的單 GPU 版本。原版因為一張 GPU 放不下,把網路拆成上下兩條平行的流;CaffeNet 把它合回一條。
ZFNet(ILSVRC 2013 冠軍,top-5 11.7%):作者把 AlexNet 每一層學到的東西視覺化,發現第一層有些濾波器沒收斂好,第二層出現 aliasing(取樣太粗產生的假紋路)。解法是把 CONV1 從 11×11 stride 4 改成 7×7 stride 2,CONV3、4、5 的濾波器數從 384、384、256 改成 512、1024、512。重點不是數字,而是「先看懂網路在學什麼,再決定架構」。
VGG 和 GoogLeNet 之後大家都想:再疊更多層就好。講義的實驗把 3×3 卷積單純往上疊,結果 56 層的網路在 CIFAR-10 上 training error 和 test error 都比 20 層高。連訓練集都學不好,所以不是過擬合,是最佳化出了問題。ResNet 的解法是讓每兩層多一條 shortcut:輸出 = F(x) + x。這一層如果沒用,只要把 F 學成 0 就好。
退化不是過擬合:過擬合是訓練集好、測試集差。講義的圖是 56 層的 training error 從頭到尾都比 20 層高,這是最佳化問題:更深的模型更難最佳化。
用構造法想:更深的模型至少能做到和淺的一樣好,因為可以把淺模型學好的層照抄,多出來的層設成 identity mapping。既然解存在而 solver 找不到,代表「用好幾層非線性去逼近 identity」很難。所以 ResNet 改成讓那幾層去擬合殘差 F(x) = H(x) − x:如果 identity 就是最佳,把權重推到 0 就好;如果最佳映射接近 identity,找一點小擾動比從頭學一個新函數容易。
完整結構:疊 residual block,每個 block 兩層 3×3 conv;每隔一段把濾波器數加倍、用 stride 2 把空間縮一半;開頭多一層 conv;最後是 global average pooling 加一層 FC 1000,沒有其他 FC。ResNet-50 以上改用 1×1 bottleneck(SEC.03)。152 層的版本拿下 ILSVRC 2015(top-5 3.57%),同年 ILSVRC 和 COCO 的分類、偵測項目全拿。訓練配方:每層 conv 後接 Batch Norm、He 初始化、SGD + momentum 0.9、learning rate 0.1(validation error 停住就除以 10)、mini-batch 256、weight decay 1e-5、不用 dropout。
Identity mapping:從 100 層到 1000 層:一個 block 寫成 y = f(h(x) + F(x))。shortcut 上的 h 和加完之後的 f 如果都是 identity,前向時任何一層的特徵都是前面各層的「相加」,反向時梯度也是相加,有一條最短的路可以直通。如果 h 不是 identity,例如乘上一個係數 λ,訊號每經過一個 block 就乘一次 λ,疊 1000 層就是 λ1000:λ 小於 1 會消失、大於 1 會爆掉。讓 f 也是 identity 的做法是把 activation 移進殘差分支裡(加法之後不再過 ReLU)。講義的結論:讓最短路徑盡量平滑,1000 層的 ResNet 就能輕鬆訓練、而且更準。
為什麼有效:unraveled view:把每個 block 拆成「走 shortcut」或「走分支」兩種選擇,N 個 block 就展開成 2N 條路徑;以前的網路只有一條。三個實驗支持「它像集成」:
講義的結論:讓殘差網路變強的不是深度本身,而是集成;它推高的是路徑的數量(multiplicity),不是深度。這些路徑雖然一起訓練,彼此卻不太依賴。
Loss surface:講義最後拿 loss 地形的視覺化做對照。直覺是:shortcut 讓地形比較平滑,optimizer 比較容易走到底,這也是 A3 講的「地形決定 optimizer 好不好走」。
Wide ResNet(寬度):超過 1000 層時,層數加倍只換來一點點改善,訓練又慢。WRN 主張重要的是殘差,不是深度:減少層數、加寬每一層(寬的層也更適合 GPU 平行運算),用 dropout 做 regularization。16 層的 WRN 贏過 1000 多層的 ResNet,50 層的 WRN 贏過 152 層的 ResNet。講義備註的三點:加寬能提升表現;深度和寬度都有幫助,直到參數多到 regularization 壓不住;同樣參數量下,寬比深好訓練。
Stochastic depth:訓練時每一輪隨機丟掉一部分 block,用 identity 頂替;測試時用完整的深網路。訓練時網路短、梯度消失少、也比較快,等於隱式地訓練一個集成。
DenseNet(2017):shortcut 的極端版。dense block 裡每一層都拿前面所有層的 feature map 當輸入,自己的輸出也送給後面所有層。好處是緩解梯度消失、加強特徵傳遞、鼓勵特徵重用,參數大約只要 ResNet 的一半就有相近表現。代價是 feature map 一路接起來,記憶體和頻寬壓力大。
Inception v4:Inception 加上殘差連接(Inception-ResNet),兩條路線合流。
變深要付錢:每多一層就多一批參數和乘加運算。2014 年兩支隊伍各找到一招省錢的方法,而且後來每一代都在用。GoogLeNet 用 1×1 卷積先把 channel 數降下來,再做昂貴的大濾波器;VGG 用 兩個 3×3 取代一個 5×5,看到的範圍一樣,參數更少,還多一次非線性。
VGG(ILSVRC 2014 分類第二、定位第一):講義的問題是「能不能只靠 3×3 就做到要的準確率?」VGG 從頭到尾只有 3×3 conv(stride 1、pad 1)和 2×2 max pool(stride 2),層數從 AlexNet 的 8 層變成 16 到 19 層,top-5 error 從 ZFNet 的 11.7% 降到 7.3%。不用 AlexNet 的 LRN(實驗顯示沒有幫助);VGG19 只比 VGG16 好一點、記憶體更多;最好的結果要靠 ensemble;FC7 的特徵拿到別的任務也很好用。講義列的實驗結論:LRN 沒有增益、越深越好、兩個 3×3 比一個 5×5 好。另外 C 組多加的 1×1 conv,是在不改感受野的前提下增加非線性。
VGG-16 的帳:總共 1.38 億個參數(不算 bias),每張圖 forward 要約 24M 個數字 × 4 bytes ≈ 96MB 記憶體(backward 再約 ×2)。分佈很不平均:記憶體多在前面的 conv(第一層 224×224×64 就 3.2M 個數),參數多在後面的 FC(第一個 FC 是 7×7×512×4096 ≈ 1.03 億,佔全部的四分之三)。代價是運算和參數都重,於是需要更有效率的網路。
Network in Network(NiN):兩個點子。一是 1×1 conv(mlpconv):在每個局部感受野裡放一個小型多層網路,增加非線性、也能改 channel 數。二是 global average pooling(GAP):最後一層每張 feature map 直接取平均變成一個數,取代全連接層。全連接層參數多、容易過擬合,GAP 沒有參數。
GoogLeNet(ILSVRC 2014 冠軍,6.67%):動機是單純把網路做深做寬,代價是計算、參數、資料都要更多。Inception module 讓同一層並排 1×1、3×3、5×5 和 max pooling,用不同大小的感受野抓特徵(filter-level sparsity)。naive 版本的問題:每個分支的輸出要接在一起,pooling 分支的輸出 channel 數又等於輸入,channel 數一層一層往上長,5×5 在頂層變得非常貴。解法就是 PROBE C 的 1×1 bottleneck。結果:22 層、沒有 FC 層、只有 500 萬個參數(比 AlexNet 少 12 倍)。越高層的特徵越抽象、空間上越分散,所以越高層 3×3 和 5×5 的比例越高。
Auxiliary classifier:網路很深,擔心梯度傳不回前面。GoogLeNet 在中間層接兩個小分類器,訓練時它們的 loss 以 0.3 的折扣權重加進總 loss,替前面的層補梯度、也有一點 regularization 的效果。測試時不用。
Inception v2、v3:加入 Batch Norm 讓訓練變穩,auxiliary classifier 就沒那麼重要了;同時把濾波器更積極地拆解(factorization),例如大濾波器拆成幾個小的。v4 則和 ResNet 合流(見 SEC.02)。
ResNeXt(cardinality):同樣來自 ResNet 團隊。GoogLeNet 的 split-transform-merge 很有效,但每個分支都要手調、超參數太多、很難搬到別的任務。ResNeXt 把一個 block 拆成 C 條一模一樣的窄分支(C 叫 cardinality,是深度、寬度之外的第三個維度),用 group convolution 實作。講義的算式 C · (256·d + 3·3·d·d + d·256),C = 32、d = 4 時約 70K,和 ResNet bottleneck 一樣;同樣參數量下表現更好,101 層的 ResNeXt 約等於 200 層的 ResNet,計算量只有一半。
到 ResNet 為止,卷積有一個共同點:訓練完之後,不管進來的是什麼圖,channel 的組合方式都一樣。SENet(2017)問:不是每個 channel 都一樣重要,能不能看了這張圖再決定?做法很便宜:每個 channel 先取平均變成一個數(squeeze),用兩層小網路算出每個 channel 的權重(excitation),再乘回去。下面是六個 channel 的迷你版。
| Block | Spatial / token mixing(位置之間交換資訊) | Channel mixing(同一位置重組特徵) |
|---|---|---|
| Standard CNN | K×K convolution 兩件事一起做一部分 | |
| MobileNet | Depthwise conv | 1×1 conv |
| ConvNeXt | Large depthwise conv | Pointwise MLP |
| ViT | Self-attention | FFN |
| MLP-Mixer | Token MLP | Channel MLP |
講義把現代網路統一成「spatial / token mixing + channel mixing」。CNN 和 Transformer 真正的差別在怎麼做 spatial mixing:CNN 用固定、共享、局部的權重(fixed spatial mixing),Transformer 用依內容決定的 attention 權重(content-dependent spatial mixing)。SE 和 deformable conv 就是 CNN 往「看內容」這邊靠的幾步。
為什麼要注意力:講義的說法是「增強或壓抑資訊」。在空間方向已經有很多做法(多尺度濾波器、上下文嵌入),SE 改從 channel 方向下手:明確建模 channel 之間的相互依賴,做 feature recalibration,選擇性地放大有用的特徵、壓抑沒用的。
SE block:squeeze 用 global average pooling 把每張 feature map 縮成一個數,等於讓靠近輸入的層也拿到全域資訊;excitation 是兩層 FC(先降到 1/16,過 ReLU,再升回來)加 sigmoid,得到每個 channel 0 到 1 的權重;最後逐 channel 相乘。用兩層而不是一層,是為了多一點非線性、也大幅減少參數。它幾乎能插進任何 backbone:SE-Inception、SE-ResNet、SE-ResNeXt。放進 ResNet 時要乘在殘差分支上、相加之前;如果乘在主幹上,深網路的梯度會被 0 到 1 的 scale 一路壓小。效果:SE-ResNet-50 約等於 ResNet-101 的準確率。限制:global pooling 丟掉了空間位置;它主要建模 channel,不是完整的空間關係。
ECA:問的是「能不能更有效率地學 channel attention?」它認為 SE 的降維有副作用,而且讓所有 channel 兩兩互相影響既沒效率也沒必要。改成 GAP + 1D conv(只看相鄰 k 個 channel)+ sigmoid,不降維,k 依 channel 數自動決定。掛在 ResNet-50(24.37M 參數)上只多 80 個參數,top-1 準確率提升 2.28%。
Pixel attention:對 feature map 的每一個像素算一個注意力係數,用 1×1 conv 加 sigmoid 就能做到,講義舉的應用是超解析度。
CBAM:先 channel 再 spatial,串起來做。channel 部分同時用 GAP 和 global max pooling,兩個向量共用一個 MLP 後相加過 sigmoid;spatial 部分沿 channel 方向做平均和最大值,拼成兩張圖,過 7×7 conv 和 sigmoid。講義的比喻:先決定看「什麼」(what),再決定看「哪裡」(where)。
Deformable convolution:標準卷積用固定網格 {(−1,−1), (−1,0), …, (1,1)}。deformable conv 另開一條分支,用和原本相同的卷積輸出一張位移圖,替每個取樣點學一個 Δp,讓取樣位置隨物體形狀、姿勢、尺度改變;Δp 不是整數時用 bilinear interpolation 取值。用途是物件偵測、instance segmentation、遙測等複雜場景。限制:要預測位移、要插值、記憶體存取不規則,硬體很難做快。InternImage 把改良的 deformable conv 擴成大型 backbone,顯示內容自適應卷積也能隨資料和參數擴展。
ConvNeXt(2022):Transformer 出現後的回應。把 Transformer 的訓練方法搬過來(LayerNorm、GELU、更大的感受野、資料配方),再一步一步微調 ResNet 的結構。講義的結論是 ConvNeXt 的表現都超越相似複雜度的 Transformer。講義表格列的限制是:大核和 depthwise 運算在不同硬體平台上的效率不一致。
CNN 和 Transformer 的分工:CNN 把「影像大多是局部規律」寫進模型(locality 和 weight sharing),所以便宜、穩定、需要的資料比較少;最大的限制是資訊交換靠局部 kernel,要一層一層疊才看得遠。Transformer 讓模型自己學「哪些位置該互相看」,彈性高、全域能力強,但丟掉了這些對影像很合理的假設。兩個講義的例子:
講義建議換一個問題問:什麼任務值得付出 attention 的成本?只是在找邊、紋理、角、局部形狀,卷積就很合理;需要物體之間的關係、全域語意一致、遠距離對應,才用 attention 或 SSM。理想的模型可能是 Local CNN + Large / Deformable Conv + Selective Attention / SSM。Large kernel(31×31、51×51)解決「看得夠不夠遠」,deformable 讓「看哪裡」變動態,只有 self-attention 讓「看誰」和「看多重要」都由內容決定。
演進脈絡總結:1990s 到 2012 是可行性驗證到大規模成功;2014 到 2016 是加深、加寬與訊息流(避免退化),換準確度;2016 到 2019 是效率化與自動化(Xception、MobileNet、EfficientNet,C3 的主題),換實際部署效率;2019 之後是與 Transformer 互補、配方現代化。講義最後把「parameter efficient:怎麼有效地產生和組合特徵」整理成四類:重用 feature map(DenseNet、CSPNet)、拆解 channel 或 kernel(group conv、MobileNet)、注意力(SE-Net、ResNeSt)、把訓練和推論的結構分開(RepVGG)。
這個模組最常被講錯的幾句話。