JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

從 LeNet 到 AlexNet:卷積網路如何學會看世界

認識開啟一切的兩張藍圖——一個讀數字的小網路,以及那個贏得 ImageNet、點燃深度學習引信的模型。

一樣的磚塊,不一樣的建築

在認識第一個著名網路之前,先深呼吸:接下來要用到的每一塊磚,你其實都已經擁有了。在前面的學習軌中,你學過卷積(一個在影像上滑動、尋找局部圖樣的小濾波器)、池化(把特徵圖縮小、同時保留最強訊號的降採樣器)、ReLU 非線性,以及特徵圖的概念(濾波器產生的一整格回應)。你也看過最基本的生產線:用卷積偵測、用池化做摘要,最後用一兩層全連接層把這些特徵變成類別判斷。這條學習軌不會取代這些磚塊,我們只是要用越來越聰明的方式把它們堆起來。

這是整條學習軌最重要的一個觀念,所以我們把它說清楚:架構不是一種新運算,而是「如何堆疊你已經擁有的磚塊」的選擇。想想烘焙。麵粉、雞蛋、糖和奶油是固定的材料——就像卷積、池化和 ReLU。但是食譜決定了一切:同樣這四種材料,光是比例不同、順序不同、烤的時間不同,就能變成薄薄的鬆餅、有嚼勁的餅乾,或是高高的千層蛋糕。CNN 架構正是這份食譜:用幾層卷積、多寬、什麼順序、加上哪些技巧。換一份食譜,同樣的磚塊今天能讀懂郵票大小的數字,明天就能辨認上千種動物。

共用的藍圖:卷積與池化階段萃取特徵,全連接的「頭部」做出最後的類別判斷。

一張由左到右的流程圖:輸入影像依序流過交替的卷積與池化區塊,特徵圖越來越小但越來越深,接著攤平成全連接層,最後輸出各類別分數。

為了讓你心裡有張地圖,這裡先把本軌五篇導覽攤成一條「大想法」的時間線。(1) 1998 年——LeNet,那個小小的數字辨識器寫下了範本。(2) 2012 年——AlexNet 把這個範本放大,贏得 ImageNet,點燃了深度學習的引信。(3) 接著 VGG 與 Inception 做得更深、也更便宜。(4) ResNet 打破深度天花板,訓練出超過一百層的網路。(5) 最後我們追求效率(能塞進口袋的模型),甚至讓機器自己設計網路。這條路上的每一步,都是同一批磚塊的新食譜——所以一旦你真正讀懂前兩張藍圖,後面的內容都會像是你早已熟悉的主題變奏。

LeNet-5:開創一切的範本

我們的故事要從 1990 年代末一個非常實際的問題說起:銀行需要機器去讀數百萬張支票上手寫的數字。Yann LeCun 和同事打造了 LeNet-5,一個小巧的卷積網路,讀這些數字可靠到足以真正上線使用。以今天的標準來看它很迷你——只有寥寥幾層、大約六萬個參數——但它的佈局是本軌每一個網路的祖先。把 LeNet 學透,你就讀懂了 AlexNet、VGG 與 ResNet 全都繼承下來的那張藍圖。

  1. 卷積:一層小小的 5×5 濾波器在 32×32 的輸入上滑動,只要找到簡單的局部圖樣(筆畫、邊緣、轉角)就亮起來。
  2. 池化(降採樣):2×2 的平均池化把空間尺寸減半,保留每個鄰域的大意,丟掉精確的像素位置。
  3. 再一次卷積:第二組濾波器現在看的是池化後的特徵,學著把邊緣組合成更大的圖樣——圈、交叉、數字的某個部位。
  4. 再一次池化:又一個 2×2 池化把特徵圖再縮一次,讓後面的層看到的是緊湊的高層摘要。
  5. 全連接 → 全連接:把剩下的每個特徵接到一個密集層,再接一層,最後一層輸出十個分數——每個數字一個,從 0 到 9。

為什麼偏偏是這個順序合理?因為視覺天生就是階層式的。最前面的層一次只能看到一小塊,所以它們頂多只能偵測像邊緣、筆畫這種小小的局部圖樣。接著池化把精確位置模糊掉(知道「這附近有一條邊」就夠了),這既縮小了資料,也讓網路能容忍小小的位移。在上面再疊一層卷積,它就能把鄰近的邊緣組合成更大的部位;再疊第三層,就能把部位組合成完整形狀。一直要到最後,當網路已經建立起豐富、又能容忍位置變化的特徵,全連接層才一次看遍全部,做出判斷:「綜合來看,這是個 7。」先局部偵測、做摘要、再組合,最後全局判斷——這就是烤進這個排序裡的邏輯。

特徵圖就是某一個濾波器在整張影像上的回應:找到圖樣的地方亮起來,其他地方暗下去。

左邊是一個灰階數字,右邊是一格格小小的回應圖,每一張各自凸顯一種不同的局部特徵,例如垂直邊緣或曲線。

現在我們把「縮小」這件事講精確,因為盯著數字看,是最能體會 CNN 如何運作的方法。當卷積把一個方形濾波器在特徵圖上滑動時,輸出會比輸入小(濾波器不能掛在邊緣外面),而到底小多少,由一條乾淨俐落的公式決定:

\text{out} = \left\lfloor \dfrac{W - K + 2P}{S} \right\rfloor + 1

卷積輸出尺寸公式(沿單一維度計算;高度也同理)。

我們用白話把每個符號叫出名字。W 是輸入寬度(進來的特徵圖橫向有幾個像素)。K 是核大小(濾波器是 K×K;這裡 K = 5)。P 是填補(你在邊界外貼幾圈額外的零像素;LeNet 用 P = 0)。S 是步幅(濾波器每一步跳幾個像素;LeNet 用 S = 1)。那個小小的 ⌊ ⌋ 代表「向下取整」,因為輸出像素只能是整數個。一句話的直覺:分子 W − K + 2P 不過是「濾波器左上角能走多遠」,除以 S 算出它走了幾步,而 +1 算進起點本身。把 LeNet 第一層卷積代進去:out = ⌊(32 − 5 + 0)/1⌋ + 1 = ⌊27⌋ + 1 = 28。於是 32×32 的輸入變成 28×28 的特徵圖——正是 LeNet 用的縮法——而你剛剛親眼看著這個數字算出來。

# Track how a LeNet input changes shape, layer by layer.
# Format: (channels, height, width)

x = (1, 32, 32)     # one grayscale digit, 32x32 pixels

# Conv1: 6 filters, 5x5 kernel, stride 1, no padding
# out = floor((32 - 5 + 0)/1) + 1 = 28
x = (6, 28, 28)     # spatial 32 -> 28, depth 1 -> 6

# Pool1: 2x2 average pool, stride 2  (halves H and W)
x = (6, 14, 14)

# Conv2: 16 filters, 5x5  ->  floor((14 - 5)/1) + 1 = 10
x = (16, 10, 10)    # depth grows 6 -> 16

# Pool2: 2x2 average pool, stride 2
x = (16, 5, 5)

# Flatten: 16 * 5 * 5 = 400 numbers
# FC: 400 -> 120 -> 84 -> 10 class scores (digits 0-9)
整個 LeNet 形狀追蹤:空間尺寸一路縮小(32→28→14→10→5),深度一路增長(1→6→16)。

請注意這段追蹤裡的兩個趨勢,因為它們是幾乎每個 CNN 的心跳:空間尺寸縮小(32 → 28 → 14 → 10 → 5),而通道深度增長(1 → 6 → 16)。網路是在用「確切在哪裡」交換「是什麼、而且多麼豐富」。一個誠實的時代細節:LeNet 早於好幾個現代習慣。它用的是 tanh/sigmoid 激活(平滑的 S 形壓縮函數)而非 ReLU,用的是平均池化而非今天更常見的最大池化。在 1998 年這些選擇都很合理,網路在數字上表現得漂亮——但我們接下來就會看到,一旦你想把它放大到真實照片,這些選擇就會變成瓶頸。

ImageNet 時刻:AlexNet 登場

把時間快轉十四年,來到 2012 年——一般認為現代深度學習時代就是從這一刻開始的。當時所有人都在意的標竿是 ImageNet,一場每年舉辦、要把自然照片分進一千個類別的競賽。一年又一年,靠著人工設計的特徵,錯誤率只能緩慢地一點點往下挪。然後一個叫做 AlexNet 的 CNN 出場了——它一夜之間把前一年的最佳錯誤率幾乎砍半,把 top-5 錯誤率從大約 26% 降到大約 16%。這不是客氣的進步,而是那種讓整個領域停下來瞠目結舌的跳躍。幾乎是立刻,電腦視覺就從人工設計特徵轉向了學習式的深度網路。

影像分類:網路吃進一張照片,對每一個可能的類別標籤輸出一個機率。

左邊一張動物照片送進網路,右邊產生一張類別機率長條圖,正確的標籤分數最高。

讓這項成就格外鮮明的是它純粹的規模。AlexNet 是在大約 120 萬張帶標籤的訓練影像上訓練的,橫跨 1000 個類別——不是乾淨的 32×32 數字,而是亂糟糟的全彩照片:狗、香菇、船、鍵盤,每張都縮到 224×224 像素。訓練這麼大的網路之所以可行,是因為作者把它跑在 GPU(為大規模平行運算打造的繪圖處理器)上,把模型拆到兩顆 GPU 上跑了好幾天。資料的規模、模型的規模、運算的規模一次到齊——而這個組合,而非任何單一技巧,才是那一刻真正證明的事。

這篇導覽的關鍵收尾就在這裡:從高層次看,AlexNet 就是和 LeNet 一模一樣的範本,只是大很多。它疊了五層卷積(有些後面接池化)來萃取特徵,再用三層全連接來分類——卷積→池化的特徵萃取器,接上密集的分類頭,跟先前一模一樣。差別只在程度與材料:多得多的濾波器與通道、真正的 224×224 彩色輸入而非小小的數字,以及一組 LeNet 沒有的訓練技巧。同一份食譜,放大並現代化了。這就是為什麼先搞懂 LeNet 這麼快就回本——AlexNet 是它長大的後代,而不是另一個物種。

AlexNet 真正成功的關鍵

光是「更大」並不夠——一個巨大的網路可能根本訓練不動,而且很快就把訓練資料背起來。AlexNet 之所以行,是因為它把規模和三項訓練創新搭配在一起。我們一個一個來,把每一項的直覺建起來,因為它們到今天每一個都還是標準做法。

創新一:用 ReLU 取代 sigmoid/tanh。LeNet 那種平滑的 S 形激活有個隱藏缺陷:對於很大的正輸入或很大的負輸入,它們會飽和——輸出變平,於是斜率(梯度)幾乎變成零。訓練時,學習訊號是靠著一層一層相乘梯度往回傳的,所以一個接近零的斜率會把這個訊號掐住,讓學習慢如蝸牛;在深層網路裡甚至可能完全停擺(這就是「梯度消失」問題)。ReLU 用一種簡單到幾乎令人不好意思的方式繞過了這個問題:

f(x) = \max(0,\, x)

修正線性單元(ReLU):保留正的輸入,把負的歸零。

逐符號來看:x 是預激活值——在任何非線性之前,進入這個神經元的原始數字。max(0, x) 就只是回傳 0 和 x 之中比較大的那個。所以 x 是正的就原封不動地讓它通過;x 是負的,輸出就被壓成正好 0。把它想成一個單向閥,或一道只對正向流動打開的閘門。接著來看對訓練最關鍵的部分:對任何 x > 0,這個函數就只是直線 y = x,它的斜率是常數 1——一個滿格、毫不衰減的梯度,學習訊號可以一路順順地騎過去。拿它對比飽和的 sigmoid,後者在平坦區的斜率接近 0,把訊號掐成涓涓細流。常數 1 對上接近 0 的梯度,正是 ReLU 網路訓練快上好幾倍的原因,也是 AlexNet 之所以根本訓練得起來的一大關鍵。

ReLU:負輸入時是一條平平的零線,正輸入時是斜率為 1 的直線——一道簡單的單向閘門。

f(x)=max(0,x) 的圖:x<0 時是貼在零的水平線,x>0 時則是上升的 45 度直線。

創新二:在全連接層使用 dropout。一個有數千萬參數的網路,大可以乾脆把訓練資料背下來——對看過的範例表現超好,對新範例卻垮掉,這種失敗我們叫做過擬合。Dropout 對抗它的方式是:在每一個訓練步驟中,隨機關掉一部分神經元(AlexNet 在它的密集層用了 50%)。打個比方:想像一支球隊,每次練習都隨機讓一半的球員坐板凳。沒有哪個明星能變成不可或缺,於是全隊學會了冗餘、強韌的技能——每個球員都得頂得上去。同理,沒有哪個神經元能仰賴某個特定夥伴永遠在場,於是網路學到的是更通用、更有韌性的特徵,而不是脆弱的死背。

過擬合:一個把訓練點背得完美的模型,對新資料仍可能預測得很差——dropout 和資料增強就是在抵抗它。

一堆散佈的點配上兩條曲線:一條平滑、抓住趨勢且能類化,另一條彎彎曲曲地穿過每個訓練點卻錯失新資料。

創新三:資料增強。即使有 120 萬張影像,模型仍渴求更多變化,於是作者用「不改變標籤」的方式變換每張影像,免費把資料變多:做隨機裁切水平翻轉(鏡像的貓還是貓),以及小小的色彩抖動(輕推亮度與色調)。每一輪訓練,網路看到的都是每張照片略有不同的版本,這教會它:不管位置、鏡像或光線怎樣,貓就是貓——這同樣在對抗過擬合,只是這次是靠豐富輸入,而不是削薄網路。最後補一個歷史註腳:AlexNet 還用了局部反應正規化(LRN),一種讓強烈激發的神經元壓制鄰居的機制。它在當時帶來一點點提升,但後來發現幫助不大,所以現代網路把它拿掉了——以後再也看不到它時,別困惑。

計算成本:參數都藏在哪裡

我們一直說這些網路「很大」,那就來學著精確地量它——方法是數參數,也就是網路在訓練時調整的可學習權重與偏置。數參數是個非常具體又好用的技能,而且它正好鋪好了驅動本軌其餘部分的效率主題。要知道的公式只有兩條,一條給卷積層,一條給全連接層:

P_{\text{conv}} = (K \cdot K \cdot C_{\text{in}} + 1)\cdot C_{\text{out}}, \qquad P_{\text{fc}} = (N_{\text{in}} + 1)\cdot N_{\text{out}}

參數量:卷積層(左)與全連接層(右)。

我們把每個符號叫出名字。卷積層:K 是核大小(一個濾波器是 K×K 像素),C_in 是輸入通道數(進來的特徵圖的深度),C_out 是濾波器的數量,也等於輸出通道數。乘積 K·K·C_in 是「單一個濾波器」內部的權重數(它橫跨整個輸入深度);+1 是每個濾波器配到的一個偏置;再乘以 C_out,是因為我們有那麼多個濾波器。全連接層:N_in 是輸入數(送進來的神經元),N_out 是輸出數(這一層的神經元);每個輸入都連到每個輸出,得到 N_in·N_out 個權重,再加上 N_out 個偏置——正好就是 (N_in + 1)·N_out。全連接層之所以這麼吃參數,深層原因是:卷積濾波器在影像的每個位置都重複使用它那一小組權重,而全連接層卻給每一對輸入-輸出配一個自己專屬的權重,完全沒有共享。

def conv_params(k, c_in, c_out):
    return (k * k * c_in + 1) * c_out   # +1 is one bias per filter

def fc_params(n_in, n_out):
    return (n_in + 1) * n_out           # +1 is one bias per output neuron

# AlexNet's FIRST conv layer: 11x11 kernel, 3 input channels (RGB), 96 filters
print(conv_params(11, 3, 96))      # 34,944        (~35 thousand)

# AlexNet's FIRST fully-connected layer (FC6):
# input  = 256 channels x 6 x 6 = 9216 numbers
# output = 4096 neurons
print(fc_params(9216, 4096))       # 37,752,832    (~37.7 million)
AlexNet 裡一層卷積對上一層全連接——看著全連接層以大約一千倍的差距輾壓卷積層。

好好端詳這兩個數字,因為它們正是這篇導覽的驚奇所在。第一層卷積——在原始像素上扛起繁重視覺工作的那一層——只有大約 3.5 萬個參數。第一層全連接卻有大約 3770 萬個,光一層就大約是前者的一千倍。AlexNet 總共約有 6000 萬個參數,而它那三層密集層幾乎佔了全部(95% 以上);五層卷積加起來反而是少數。同樣失衡的格局也出現在 VGG 身上,下一篇就會看到。所以重點可以濃縮成一句好記的口號:視覺工作發生在深度裡,但參數藏在全連接層裡。

重點回顧與接下來的路

我們把心智模型鎖定下來。我們見過的每一個 CNN——以及我們將要見到的每一個——都是同一個範本:一個由堆疊的卷積層與池化層構成的特徵萃取器,後面接上一個把特徵變成類別分數的分類頭。LeNet 為數字寫下了這個範本;AlexNet 把它放大,並證明它在上百萬張真實照片上行得通。沒有任何東西被重新發明;磚塊還是那些磚塊。變的是食譜。

而你現在知道,這個領域的進步,來自只拉三根操縱桿:深度(疊幾層,讓網路把簡單圖樣組合成複雜圖樣)、寬度(每層有幾個濾波器/通道,也就是它一次能看多少),以及訓練技巧(ReLU、dropout、資料增強等等,讓一個大網路真的訓練得動,並阻止它淪為死背)。把這三根桿子放在心裡,本軌其餘部分就變成一個故事:誰拉了哪根桿、拉了多遠、以及為了安全地拉它需要什麼新點子。

接下來會發生什麼,具體說明。第 2 篇把深度桿再往前推,同時攻擊那個參數臃腫問題:VGG 證明一疊小小的 3×3 卷積勝過大卷積,而 Inception(GoogLeNet) 引入 1×1 卷積與平行的多尺度分支,用更低的成本做得更深。第 3 篇是轉捩點:ResNet 加上「跳接」,終於讓我們能訓練超過一百層的網路而訊號不會死掉。第 4 篇追求效率——瘦到能在你手機上跑的模型。第 5 篇則收尾,讓演算法自己設計網路(NAS、RegNet、ConvNeXt)。一路上都是同一批磚塊;你現在已經準備好,看著這些建築變得更高、更精瘦、也更聰明。