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

設計網路本身:NAS、RegNet 與 ConvNeXt

抵達前沿:讓機器自行搜尋架構、提煉設計原則而非單一網路,並見證現代化卷積網路與 Transformer 一較高下。

從手工設計到自動搜尋

讓我們花點時間回顧一路走來的旅程。LeNet 教會網路辨認數字;AlexNet 把這個想法放大、贏得 ImageNet;VGG 與 Inception 讓網路更深也更省;ResNet 的跳接讓我們得以訓練上百層;而 EfficientNet 找到一套有原則的方法去平衡深度、寬度與解析度。這每一個架構,都來自同一個源頭:一個人坐下來、畫方框、跑實驗、然後相信自己的直覺。進步是真實的,但很慢,而且仰賴稀有的專業能力。

於是出現一個很自然的下一個問題,也正是這篇收尾指南要談的:與其問「我該設計哪一個網路?」,不如問「機器能不能替我們設計網路?」這是你所學一切的「後設層次」。我們不再只是在既有架構之間做選擇——而是試圖去發掘那個一開始就能產出好架構的「過程」。這個核心想法叫做 神經架構搜尋,而這個領域後來更成熟、也更有野心:它要搜尋的不只是單一網路,而是能描述「一整族」好網路的設計規則。

神經架構搜尋:讓機器設計網路

任何 神經架構搜尋 系統,不管包裝得多花俏,本質上都只是三個彼此協作的零件。第一,搜尋空間:我們被允許搭建的所有網路所構成的集合。第二,搜尋策略:我們如何挑選要嘗試哪些候選者。第三,效能評估策略:拿到一個候選者後,我們如何替它打分數。把這三件事弄懂,你就懂 NAS 了,因為其餘的全是疊在上面的工程細節。

搜尋空間就是那份菜單。它列出一個區塊可以使用的運算——3×3 卷積、5×5 深度卷積、池化層、跳接等等——以及區塊之間可以如何連接的規則。菜單小而精,搜尋會很快,卻可能把最好的那道菜排除在外;菜單巨大,雖可能藏著絕妙的網路,規模卻大到天文數字。一個經典技巧是:只搜尋一個好的單元(cell)(一個可重複使用的小型子圖),再把它堆疊複製,這正是 VGG 與 ResNet 重複單一區塊的做法——於是被搜尋的是那個單元,而不是整個網路。

搜尋策略是我們探索那份菜單的方式,這裡用烹飪做比喻會很有幫助。想像一位廚師想發明最棒的食譜。一位強化學習廚師把做菜當成遊戲:一個控制器提出一份食譜、嚐嚐結果,味道好就得到獎勵,慢慢學會哪些選擇會贏得讚賞。一位演化廚師則維持一群食譜,淘汰最差的,再把最好的拿去交配、突變,產生下一代。而一位可微分廚師——也就是名為 DARTS 的方法——更聰明:它不是一次挑一種食材,而是把所有食材依可調整的權重「混在一起」,再用我們早就熟悉的普通梯度下降,把好的調強、把壞的調弱,把離散的搜尋變成一個我們本來就會解的平滑最佳化問題。

效能評估策略要回答一個殘酷的現實問題:要知道一個候選者好不好,照理你得把它完整訓練一遍,這可能要在許多 GPU 上花上好幾天——而一次搜尋可能想嘗試「成千上萬」個候選者。沒有人付得起這個帳。於是我們改用估計:只訓練幾個 epoch 再外推、用較小的資料集或縮小版的網路來訓練,或者——最關鍵的點子——讓所有候選者「共享權重」,如此只需訓練一個「超網路(supernetwork)」一次,每個子架構都能免費繼承它的權重。這些代理指標並不完美,但它們把一張付不起的帳單,變成了一張付得起的帳單。最早期的 NAS 成果曾惡名昭彰地燒掉上千個 GPU-天;正是這些較便宜的代理,把成本拉低到一般實驗室也跑得起的程度。

為什麼 NAS 在原理上這麼昂貴?因為它其實是兩個最佳化問題互相套疊——一個雙層(bilevel)問題。我們同時在搜尋「網路是什麼」與「網路怎麼訓練」。我們可以把目標寫成這樣:

\underbrace{\min_{\alpha}\ \mathcal{L}_{\text{val}}\big(w^{*}(\alpha),\,\alpha\big)}_{\text{outer: choose the architecture}}\qquad\text{where}\qquad \underbrace{w^{*}(\alpha)=\arg\min_{w}\ \mathcal{L}_{\text{train}}(w,\alpha)}_{\text{inner: train its weights}}

把 NAS 寫成雙層目標:外層在搜尋架構,內層在訓練權重,外層把內層包了起來。

從裡往外讀。符號 α(alpha)是架構選擇——也就是那些菜單上的勾選,告訴你「這裡用 5×5 深度卷積、那裡放一個跳接」。符號 w 是一般的網路權重,也就是梯度下降所學到的那些數字。內層問題 w*(α) = argmin_w L_train(w, α) 的意思是:一旦固定了某個架構 α,就去找出讓訓練損失最小的權重 w——這不過就是用平常的方式訓練一個網路,而獲勝的權重寫作 w*(α),也就是「該架構的最佳權重」。外層問題 min_α L_val(w*(α), α) 接著說:在所有架構之中,挑出那個訓練後模型在驗證損失上最低的 α。痛點就在這層相依——在外層即使只評估「一個」α,你都得先把「整個內層解完」,也就是完整訓練一個網路。最佳化裡面還包著一個最佳化:這種套疊正是天真的 NAS 如此昂貴的原因。而這不只是理論——第 4 篇裡 EfficientNet 的基礎網路,也就是那個之後再用複合縮放放大的小型「B0」,本身就是用 NAS 發掘出來的。所以當你欣賞 EfficientNet 那條乾淨的縮放規則時,你看到的其實早已是一個「機器設計」的網路。

RegNet:設計「設計空間」

神經架構搜尋 給你的是一位冠軍——一個特定的網路,通常很優秀,卻也很不透明:你得到一個贏家,卻沒學到它「為什麼」贏。RegNet(出自 Facebook AI Research,2020)問了一個更深的問題。它不去搜尋單一最佳網路,而是去搜尋最佳的設計空間——一組描述「一整族」強網路的簡單規則。它的口號是:NAS 找到一個個案;RegNet 找到的是那個型態。

你要怎麼去「搜尋設計空間」而不是「搜尋網路」?你先從一個非常寬鬆的空間出發(幾乎什麼都可以),從中隨機取樣許多網路,各自簡短訓練,然後觀察它們表現好壞的分布。接著你收緊這個空間——加上一條限制——再檢查整個族群是否變得更好。一條限制接著一條限制,你把一個又大又雜亂的空間,雕琢成一個狹窄的空間,在那裡幾乎你能畫出的每一個網路都是好的。最後存活下來的不是一個網路,而是一份配方——而且關鍵是,這份配方人類讀得懂。

最關鍵的發現美得出奇地簡單。當研究者去檢視那些存活下來的「好」網路時,連續區塊裡的通道數(也就是寬度)既不是隨機的、也不是手工調出來的——它沿著一條直線成長。具體來說,理想的「每區塊寬度」遵循一條量化的線性規則:

u_j = w_0 + w_a \cdot j

區塊寬度隨區塊索引 j 呈一條直線成長,接著每個數值再被取整到一個整齊的量化寬度。

這裡每個符號都很具體。j 是區塊索引——第一個區塊是 0、第二個是 1,隨著往深處走依此類推。w₀(讀作「w-零」)是初始寬度:最前面那個區塊有多少通道。wₐ 是那條直線的斜率——每深入一個區塊就多加多少通道。而 u_j 則是區塊 j 算出來的、尚未取整的連續寬度。舉個數字:若 w₀ = 24、wₐ = 16,那麼區塊 0 想要 24 個通道、區塊 1 想要 24 + 16 = 40、區塊 2 想要 56,依此類推——一道乾淨的階梯。由於真實的層需要整數、且對硬體友善的通道數,每個 u_j 接著會被量化:取整並分組,讓相鄰的區塊共用一個寬度,把那條直線切成幾個整齊的階段。最深刻之處在於這個對比:NAS 丟給你的是一張你讀不懂的雜亂的圖,RegNet 卻說一個優秀網路「深度對寬度」的整個故事,只用兩個數字 w₀ 與 wₐ 就能捕捉——一個人類讀得懂、記得住、也能據以推理的東西。

Transformer 的挑戰

為了鋪陳這場壓軸戲,我們得暫時走出「純卷積」的世界一下。大約在 2020 年,一個來自語言領域的勁敵登場了:視覺 Transformer(Vision Transformer,簡稱 ViT)。在夠大的資料集上,它在影像分類上開始擊敗卷積網路,這在整個領域點起了一把火。人們開始問:如果一個「完全沒有卷積」的模型都能贏,那麼卷積——這整個學習路徑賴以建立的核心想法——是不是要被淘汰了?

視覺 Transformer 把影像切成一格格固定大小的區塊(patch),把每個區塊變成一個向量,再用注意力機制讓每個區塊與其他所有區塊互相比較。

一張被切成方形區塊網格的影像,每個區塊被攤平成一個 token,箭頭顯示每個 token 都對其他所有 token 進行注意力運算。

這裡只講大意,刻意講得很輕,因為之後會有專門的學習路徑好好教注意力。ViT 把影像切成一格格小方塊區塊(patch)——比如每塊 16×16 像素——並把每個區塊當成一個「字詞」。接著它用一種叫做注意力(attention)的機制,讓每個區塊都能去「看」影像中其他每一個區塊、並與之交換資訊,不論彼此相隔多遠。把這拿來和卷積比一比:卷積那個小小的核,每次永遠只看得到一小片鄰域。Transformer 的魅力,正是這種從第一層起就有的「全域視野」。

但這裡有個微妙的問題,正是 ConvNeXt 的作者們緊盯不放的。視覺 Transformer 並不是單槍匹馬登場——它是和一整袋全新的訓練設計習慣綑綁在一起來的:以區塊為基礎的 stem、少得多的正規化層、不同的激活函數、大量的資料增強、更長的訓練排程。所以當一個 ViT 擊敗一個 ResNet 時,真正獲勝的到底是什麼?是注意力機制取代了卷積嗎?還是說卷積一直都好好的,只是那個 ResNet 被用一份過時的設計配方來評斷了?下一節正是要回答這個問題。

ConvNeXt:讓卷積網路現代化

ConvNeXt(2022)就是那個令人滿意的答案,而它也是替這條學習路徑收尾的完美音符,因為它純粹是一場「綜合」——你需要的每一個想法,你都已經有了。作者們做了一個很有紀律的實驗。他們拿了一個平凡無奇的 ResNet-50——正是第 3 篇那個網路,連 殘差連接 都原封不動——然後一次只改一處,逐一套上 Transformer 時代帶來的設計選擇,每改一處就量一次準確率。沒有新的魔法運算;只是把一個老設計一步一步現代化。

起點:一個標準的 ResNet 殘差區塊。ConvNeXt 保留了殘差跳接,卻逐步重建了它內部的一切。

一個 ResNet 殘差區塊:輸入分成一條捷徑路徑與一疊卷積—正規化—激活層,最後兩者再相加在一起。

  1. 把 stem 改成「切塊」。用一個 4×4、步幅 4 的卷積取代 ResNet 那個溫和的 7×7、步幅 2 入口,直接把影像切成互不重疊的區塊——這完全照抄了 ViT 的區塊想法。
  2. 改用「大核」的深度卷積。把密集的 3×3 卷積換成深度卷積(每個通道一個濾鏡,出自第 4 篇的 MobileNet),並把核放大到 7×7,讓每一層都像注意力那樣看到一片寬廣的鄰域。
  3. 採用「倒置瓶頸」。不再是先壓縮再擴張,而是在區塊中段把通道擴張、再投影縮回——正是 MobileNetV2 在第 4 篇引入的那個形狀。
  4. 用更少的正規化層與激活層。ResNet 區塊在每個卷積後都撒一個正規化與一個 ReLU;ConvNeXt 每個區塊只保留一個正規化與一個激活,呼應 Transformer 區塊那種精簡風格。
  5. 改用 LayerNorm 與 GELU。把 BatchNorm 換成 LayerNorm、把 ReLU 換成更平滑的 GELU 激活——同樣,都是 Transformer 一併帶來的那些選擇。
# A ConvNeXt block (PyTorch-style pseudocode).
# Input and output both have shape (N, C, H, W): N images, C channels.
def convnext_block(x):
    shortcut = x
    # 1) depthwise conv with a LARGE 7x7 kernel: cheap spatial mixing, stays at C channels
    x = depthwise_conv(x, kernel=7, padding=3)
    x = layer_norm(x)                 # ONE normalization, LayerNorm (not BatchNorm)
    # 2) inverted bottleneck: widen 4x with a 1x1 conv, then narrow back
    x = pointwise_conv(x, out=4 * C)  # 1x1 conv expands the channels
    x = gelu(x)                       # ONE activation, GELU (not ReLU)
    x = pointwise_conv(x, out=C)      # 1x1 conv projects back down
    # 3) residual add: the idea straight from ResNet, untouched
    return shortcut + x
一個 ConvNeXt 區塊。注意它如何重用深度卷積(第 4 篇)、倒置瓶頸(第 4 篇)與殘差相加(第 3 篇)——這裡沒有任何東西是真正全新的。

當塵埃落定,這個「純卷積」的網路在同樣的計算預算下,追平了——在某些基準上甚至擊敗了——與它較勁的視覺 Transformer。這帶出整篇指南最深刻的結論:卷積從來都不是瓶頸。那個從 LeNet 一路驅動到 ResNet 的運算,其實一直都好好的。真正老化的,是它周圍的那份配方——stem、核的大小、瓶頸的形狀、正規化與激活層的數量與種類。把配方更新、把卷積留著,與 Transformer 之間的差距就會收斂。ConvNeXt 本質上就是一封情書,把第 3 篇的殘差心法與第 4 篇的效率心法,揉進一個現代、快速又簡潔的設計裡。

全局視野:架構設計的原則

把鏡頭完全拉遠,整條學習路徑就濃縮成一份簡短的、反覆出現的設計槓桿清單——就是那麼幾個旋鈕,以不同的組合,造出了我們遇過的每一個架構。深度:堆更多層以得到更豐富的特徵(VGG、ResNet)。寬度:每層更多通道以提高容量(Wide ResNet、RegNet)。解析度:餵入更大的影像以看到更細的細節(EfficientNet 的第三個維度)。跳接/殘差連接:讓梯度與訊號越過層往前流,使極深的網路得以訓練(ResNet)。基數與分組:把工作拆成平行的群組,包括深度卷積(ResNeXt、MobileNet)。通道注意力:讓網路依重要性替自己的通道重新加權(Squeeze-and-Excitation)。效率分解:把昂貴的運算拆解成便宜的(1×1 卷積、深度可分離卷積)。而現在,還多了兩根後設槓桿:自動搜尋有原則的設計空間

這條學習路徑裡的每個分類器都共用同一副骨架:一個 stem、一段段重複的區塊階段(縮小解析度、同時增加寬度),最後接一個池化並做出預測的 head。各種架構的差別,主要只在於它們如何填滿那些區塊。

一條由左到右的流程:輸入影像、stem、數個重複區塊組成的階段(空間尺寸逐漸縮小、通道深度逐漸增加)、全域池化,以及一個分類 head。

那麼,面對一個真實任務,你到底要怎麼一個?老實說,這件事與其說是去追排行榜的榜首,不如說主要是由你的計算與延遲預算決定的。一套合理的預設流程是:

  1. 要在手機、瀏覽器或嵌入式裝置上跑?選 MobileNet 或小型的 EfficientNet——它們本就是用深度可分離卷積與複合縮放,為了達成延遲預算而設計的。
  2. 要在伺服器或 GPU 上跑、想要穩健又眾所周知的準確率?ResNet 至今仍是一個極佳、難以擊敗的基線,而現代的 ConvNeXt 則把同一個卷積家族推上了準確率的前沿。
  3. 需要在一系列尺寸上榨出最佳的「每 FLOP 準確率」?用一個經搜尋或設計空間產生的家族(EfficientNet、RegNet),轉動它的縮放旋鈕,挑出剛好符合你預算的那一員。
  4. 永遠要在你自己的硬體與你自己的資料上實測。理論上的 FLOPs 不等於實際的牆鐘延遲,而一個體型較小、卻恰好合適的模型,常常會贏過一個體型較大、名氣較響的模型。

那副透鏡,才是這整條學習路徑真正的獎賞。你一開始只是看著一個小小的網路學會辨認數字;走到最後,你已經能對「機器設計的網路」以及「能與 Transformer 互有勝負的現代化 ConvNet」進行推理。具體的架構會不斷改變——但「看待它們的方式」、那個總是去問「是哪一條原則在發揮作用」的習慣,將永遠屬於你。去讀那片前沿吧。