NEWSIO+ 教育系列01 自己訓練一個 AI02 從照片還原 3D03 深度學習
主線 C · 模組 C3動手做 // 四個實驗台

又小
又 快

手機上的模型怎麼用 1/10 的參數做到差不多的準確率?FLOPs 少為什麼不一定快?

C2 的網路越做越大,但手機、手錶、微控制器放不下。這個模組講三招:把一個卷積拆成兩個便宜的卷積、把網路的深度、寬度、解析度一起按比例放大、讓小模型跟大模型學。中間會遇到一個反直覺的事實:算的次數少了,跑起來不一定比較快,因為搬資料也要時間。

SEC.01 / DECOMPOSITION

把一個卷積拆成兩個便宜的

標準卷積一次做兩件事:在空間上看鄰居(k×k 的小窗),同時把所有輸入通道混在一起。成本是 H·W·k²·Cin·Cout 次乘加。拆法有兩種:group conv 把通道分成 g 組,每組只跟自己組混;depthwise separable(MobileNet)把兩件事分開做,先每個通道各自看鄰居(depthwise),再用 1×1 把通道混起來(pointwise)。拉下面的滑桿,看三種做法各要多少。

PROBE A / 三種卷積的帳單動手做 // 拉尺寸、通道、k、g
參數量乘加次數depthwise 那一段高度以標準卷積為 100%
標準卷積 參數 / 乘加0
group conv 省了幾倍(剛好是 g)0
depthwise separable 省了幾倍0
公式 1/k² + 1/Cout0
separable 的乘加裡 1×1 占多少0
換一層看看:
這裡只算卷積本身(stride 1、不算 bias 和 Batch Norm),所以數字是精確的乘法,不是示意。看三件事。(1)k = 3、通道 128 時,separable 大約省 8 到 9 倍,就是講義說的「3×3 約 1/9 乘加」。(2)通道越多,1/Cout 越小,省的倍數越接近 k²;k 拉到 1,separable 反而比標準卷積多一點,因為 1×1 沒有空間可以省。(3)separable 的乘加幾乎都在 1×1 那一段:講義提到,MobileNet 約 95% 的計算量在 1×1 卷積上。下一步要省,就得對 1×1 動手,這是 ShuffleNet 的起點。
標準卷積同時做兩件事看空間鄰居、混通道。把兩件事拆開做,成本從「相乘」變成「相加」。
Group conv 是砍掉一部分連線分 g 組,每個輸出只看 1/g 的輸入通道,參數和乘加都變 1/g。g 等於通道數就是 depthwise。
拆開之後要記得再混組和組之間不交流,表達力會掉。MobileNet 用 1×1 混,ShuffleNet 用洗牌(channel shuffle)混。
細看 · 從壓縮到加速、SqueezeNet、CSPNet、group conv 一家人

Pruning vs 架構設計:講義的第一個結論是,一開始就設計一個有效率的網路,效果比把大網路剪小(pruning)更好;代價是小模型比較難訓練。兩條路可以一起走:講義的總結把 pruning 看成一種架構搜尋,預期能省 3 到 10 倍;量化(32 bit 變 8 bit,省 4 倍)是最先該試的。

從壓縮到加速:講義把執行時間拆成兩塊。

執行時間 = 計算時間 + 資料搬移時間 計算時間 ≈ 輸入 × model 大小 / 硬體平行度;搬移時間 ≈(model 大小 + 輸出入)/ 輸出入頻寬

Model 大小 = Cin × Cout × k² × bits。壓縮(pruning、量化)主要縮小 model,decomposition(拆卷積)則同時改變計算量和要搬的資料量。SEC.02 會看到後者常常才是瓶頸。

拆卷積的幾種方向(講義的整理,都可以套在現有的卷積層上):k×k 拆成 k×1 加 1×k(asymmetric);通道分組(g < Cout 是 group conv,g = Cout 是 depthwise);分組後用 1×1 或 shuffle 把組融回來(MobileNet、ShuffleNet);inverted residual(MobileNet v2);用 1×1 先減通道;通道分區,每區用不同 kernel(SqueezeNet)或只讓一部分通道進主路(CSPNet)。

SqueezeNet(fire module):目標是壓縮 AlexNet。三個策略:大部分 3×3 換成 1×1(參數少 9 倍);先用 squeeze 層(1×1)減少進入 3×3 的通道數;降採樣盡量放在網路後面,大的特徵圖準確率較高。fire module = squeeze(1×1)接 expand(1×1 和 3×3 並排)。標題說「參數少 50 倍、小於 0.5MB」,但講義特別提醒:0.5MB 是再加上 Deep Compression 才達到的;而且它的乘加約 861M,和 AlexNet 差不多。參數省了,計算沒省。

CSPNet(channel partition,YOLOv4 用的):把一個 stage 的通道切成兩半,一半走 dense block,另一半直接繞過去,最後才合併。目的:增加梯度路徑的組合、讓每層計算量平均、減少記憶體流量。講義的 ablation:合併放在 transition 之後(late fusion)計算量少 21%、準確率只掉 0.1%;放在之前(early fusion)少 26% 但掉 1.5%;CSPPeleeNet 少 13% 還多 0.2%。

Group conv 與 ResNeXt:參數從 C²k² 變成 (C/g)²·g·k² = C²k²/g。最早出現在 AlexNet,當時是為了切到兩張 GPU 上跑。ResNeXt 把 ResNet bottleneck 中間的 128 通道切成 32 組 × 4 通道,提出 cardinality(組數)這個新維度:模型大小不變,表示能力更強。g 等於 Cout、kernel 等於整張特徵圖時叫 global depthwise conv(MobileFaceNet)。

MobileNet v1(depthwise separable):2D 的空間混合(depthwise)之後接所有通道的混合(1×1 pointwise)。講義的數字:3×3 時約 1/7 參數、1/9 乘加。除了第一層,全部用 separable;不用 pooling 降採樣,用 stride 2。

量化友善的 separable conv:MobileNet 直接量化到 8 bit 時準確率掉很多,講義引用一篇專門改 separable 結構的論文,讓它量化後仍穩定(筆記裡提到的其中一招是加 L2 regularization 壓住權重範圍)。

ShuffleNet v1(channel shuffle):MobileNet 的問題是 1×1 太貴,ShuffleNet 把 1×1 也改成 group conv。副作用是組和組之間不交流,所以在兩層之間做 channel shuffle:把每組的通道再分小份,發給下一層的不同組。講義也提醒:shuffle 打亂了資料在記憶體裡的連續性,對 CPU 的 SIMD 不友善。

Filter decomposition / asymmetric:5×5 有 25 個權重;兩個 3×3 疊起來看到一樣大的範圍,只要 18 個;1×5 加 5×1 只要 10 個。ADSCNet 把 asymmetric 和 depthwise separable 合在一起做即時語意分割。

Depthwise 的變體:MixNet 問「kernel 越大越準嗎」:單一 kernel 大小在 9×9 時準確率最高,再大反而下降,所以在同一層混用 3×3、5×5、7×7。Shift 用「把通道整片平移一格」取代 depthwise,零 FLOPs、零參數,約 10% 的通道需要移;硬體效率高、表達力弱,模型要變大。GhostNet 觀察到特徵圖裡有很多「長得很像的一對」,所以只算一半,另一半用便宜的運算(例如 depthwise 3×3)從前一半變出來;講義引用的實驗在 CIFAR-10 上參數和 FLOPs 都約減半、準確率差不多。ShiftAddNet 把乘法換成位移和加法(距離量測從內積換成 L1)。另外還有依 kernel 大小分組(Big-Little Net)、依輸入解析度分組(Octave conv)、依數值精度分組。

SEC.02 / FLOPS IS NOT SPEED

FLOPs 一樣,速度可以差很多

FLOPs(乘加次數)是間接指標,真正要的是延遲(latency)這個直接指標。ShuffleNet v2 量過:FLOPs 差不多的網路,在 GPU 和手機 ARM 上速度可以差很遠。漏掉的是兩件事:記憶體存取成本(MAC),也就是讀寫特徵圖和權重要搬多少資料;以及平行度,硬體能不能一次把事情做完。它整理出四條守則,下面每一條都可以拉。

PROBE B / 四條守則動手做 // 固定 FLOPs,改形狀
FLOPs(1×1 卷積的乘加,固定)0
現在的形狀 c₁ → c₂(56×56 特徵圖)0
MAC(要讀寫的數值個數)0
估計延遲(示意)0
這台硬體卡在哪0
FLOPs 和 MAC 是照 ShuffleNet v2 的公式真的算:1×1 卷積 B = hw·c₁·c₂/g、MAC = hw(c₁+c₂) + c₁c₂/g,每次改形狀都把 c₁、c₂ 重新調到 B 不變。延遲是示意:用「計算時間 + 搬移時間 + 每個 kernel 的啟動成本」估,三種硬體的算力和頻寬是為了說明而設的數字。試試看:在手機加速器上把 G1 拉到 1:16,FLOPs 一樣,延遲變成將近兩倍;換到手機 CPU,同樣的動作只慢一成左右,因為它卡在算力不是頻寬。G3 在 GPU 上最痛:每多一條支路就多一次啟動和同步,算力閒著。G4 的 ReLU 和相加幾乎不加 FLOPs,卻要把整張特徵圖多讀寫幾次。
算得少 ≠ 搬得少1×1 卷積的權重很小,但輸入輸出的特徵圖每次都要讀寫。FLOPs 低的層常常卡在搬資料。
寬窄一致最省FLOPs 固定時,c₁ = c₂ 讓 MAC 最小,這是算幾平均不等式的結果。group 越多,同 FLOPs 下通道要越寬,MAC 越大。
硬體決定瓶頸同一個模型,在算力弱的 CPU 上要省乘加,在頻寬小的加速器上要省搬移。MobileNet v4 用 Roofline 模型把兩邊一起考慮。
細看 · 四守則的推導、MobileNet v2 / v3 / v4、重參數化

G1 推導:1×1 卷積,B = hw·c₁c₂,MAC = hw(c₁+c₂) + c₁c₂。由算幾平均 c₁+c₂ ≥ 2√(c₁c₂),代入得 MAC ≥ 2√(hwB) + B/hw,等號在 c₁ = c₂。G2:MAC = hw·c₁ + Bg/c₁ + B/hw,其他固定時隨 g 增加。G3:網路的支路(fragment)越多,越不利平行計算,同 FLOPs 下單一卷積最快。G4:element-wise 運算(ReLU、shortcut 相加、加 bias)FLOPs 很低但 MAC 高,不能忽略;depthwise 也被看成這一類:FLOPs 低、MAC 高。

其他被 FLOPs 漏掉的事:cuDNN 對 3×3 特別最佳化,所以不能以為 3×3 一定比 1×1 慢 9 倍。group conv 這種低複雜度層裡,MAC 占的比例很大;在 GPU 這種算力強的裝置上,MAC 更是瓶頸。筆記也提到,訓練過 ResNeXt 的人都有感覺:同樣層數,它大約只有 ResNet 一半快。

拿守則檢查前人:ShuffleNet v1 大量用 group conv(違反 G2)、用 bottleneck 結構(違反 G1);MobileNet v2 的 inverted bottleneck 違反 G1,在很厚的特徵圖上做 depthwise 和 ReLU 違反 G4;NASNet 的碎片結構違反 G3。ShuffleNet v2 的改法:開頭做 channel split(一半通道直接過)、1×1 拿掉 group、相加改成 concat。

MobileNet v2:ResNet 的 bottleneck 是「壓縮 → 卷積 → 擴張」,v2 反過來做 inverted residual:「擴張 → depthwise 卷積 → 壓縮」,先用 1×1 把通道撐開,才有足夠的特徵給 depthwise 處理。最後那個 1×1 壓縮後面不接 ReLU,改成線性(linear bottleneck),因為在低維的地方 ReLU 會破壞特徵。

MobileNet v3:用 platform-aware NAS 搜整體架構,再手工修。加入 Squeeze-and-Excitation(SE):先 global average pooling 得到每個通道的整體資訊,再學一組通道權重,等於通道注意力;SE 的大小固定為擴張層通道數的 1/4。把 swish 換成 hard swish(用 ReLU6 拼出來),量化時誤差小、跑得快。Redesign expensive layers:v2 最後在 7×7 上做 1×1 很貴,v3 先 pooling 到 1×1 再做分類前的運算;並使用 5×5 depthwise。

MobileNet v4:目標是一個模型在手機 CPU、GPU、DSP、加速器上都有效率,組成是 UIB + Mobile MQA + NAS。UIB(Universal Inverted Bottleneck)= inverted bottleneck 加兩個可選的 depthwise,可以變成 IB、ConvNext 式、ExtraDW、FFN 四種,便宜地調整深度和感受野。Roofline 模型:運算強度 = 乘加數 ÷ 搬移的資料量;硬體的 ridge point = 峰值算力 ÷ 峰值頻寬。ridge point 低(CPU)時省乘加有用,高(加速器)時要省搬移。Mobile MQA:所有 head 共用 key 和 value,大幅減少記憶體存取;講義引用的數字是推理快 39% 以上,參數和 MACs 也減少 25% 以上。

重參數化:訓練時多分支、推論時一條路。多分支(例如 ResNet 的 shortcut)好訓練,但推論時多讀寫、不利平行;講義提到 ResNet-50 的殘差連接約占特徵圖記憶體的 40%。RepVGG 訓練時每層有 3×3、1×1、identity 三條支路,訓練完把三條線性地合成一個 3×3,推論時就是像 VGG 的直筒網路;缺點是訓練時要更多顯存和時間。RepOptVGG 改成把這個結構先驗放進 optimizer:用 CSLA(Constant-Scale Linear Addition,每條支路一個可訓練參數乘上常數縮放)推出梯度的乘數,訓練時就只有一條路,batch 可以更大、對量化也友善;縮放值先在小資料集上帶 BN 訓練找出來。RMNet 用 reserving and merging 直接把殘差拿掉:在第一個卷積加入 Dirac 初始化的 filter 保留輸入、讓 BN 變 identity、ReLU 改 PReLU 參數設 1,再把通道併進第二個卷積;它解決 RepVGG 在很深時退化的問題。MobileOne = MobileNet + RepVGG + 訓練技巧,針對 iPhone 12 最佳化,ImageNet 推理約 1ms;講義引用的觀察是 FLOPs 和參數量與手機上的延遲相關性很弱(iPhone 12 上 Spearman 相關小於 0.5)。

SEC.03 / COMPOUND SCALING

要放大,就三個方向一起放

有了一個好的小網路,資源多一點時怎麼放大?可以加深(depth d)、加寬(width w,通道變多)、或吃更大的圖(resolution r)。任何一個方向都會變準,但講義的觀察是:只放大一個方向,報酬很快遞減。EfficientNet 的做法是三個一起按固定比例放大。成本也不對稱:卷積的 FLOPs ∝ d·w²·r²,寬度或解析度翻倍,FLOPs 變 4 倍。

PROBE C / 深、寬、解析度動手做 // 拉 d、w、r 或 φ
只放大 d只放大 w只放大 r複合縮放(1.2, 1.1, 1.15)
FLOPs 是基準的幾倍 = d · w² · r²0
示意準確率0
同樣 FLOPs 只放大一個方向(d / w / r)0
對應到網路0
FLOPs 那一欄是公式 d·w²·r² 真的算出來的。準確率是示意:每個方向各給一條會飽和的曲線(越放大,多出來的越少),數字是為了說明而設,不是講義的數據。拉 φ 會照講義 EfficientNet-B0 的係數 α = 1.2、β = 1.1、γ = 1.15 把 d、w、r 一起設成 αφ、βφ、γφ。比較同一個 FLOPs 下橘色和其他三條:一開始差不多,FLOPs 越大差距越明顯,花一樣的錢,分散投資比押在一個方向好。
三個方向互相需要圖變大,要更多層才看得到整張圖、要更多通道才抓得到細節。只放一個,另外兩個會變成瓶頸。
成本不對稱深度翻倍 FLOPs ×2;寬度或解析度翻倍 FLOPs ×4。所以 β、γ 都比 α 小。
先找比例,再整組放大α·β²·γ² ≈ 2,所以 φ 每加 1,FLOPs 大約翻倍。B1 到 B7 只是同一個比例放大不同次。
細看 · EfficientNet、EfficientFormerV2、TinyML、動態執行
d = αφ,w = βφ,r = γφ  α · β² · γ² ≈ 2 (α, β, γ ≥ 1;FLOPs 約為 2φ 倍)

EfficientNet:先固定 φ = 1(假設多兩倍資源),在基準網路上做小規模格點搜尋,得到 α = 1.2、β = 1.1、γ = 1.15(EfficientNet-B0)。之後固定這三個數,改 φ 得到 B1 到 B7。講義的數字:最大的版本 ImageNet top-1 84.4%、top-5 97.1%,比當時最好的 CNN 小 8.4 倍、推理快 6.1 倍;遷移到 CIFAR-100 約 91%、Flowers 98.8%。

EfficientFormerV2(輕量 ViT):在 FFN 裡加 depthwise 3×3,用 FFN 取代原本的 local token mixer;只在 1/32 的低解析度做 attention,因為 attention 的成本和解析度是平方關係;MHSA 也改良:對 value 加 depthwise 3×3 注入局部資訊、在 head 之間加一層全連接(talking head)讓 head 互通;再加上雙路徑的 attention。

TinyML / MCUNet v2:在微控制器(MCU)上,瓶頸是晶片上的那一點記憶體,而且記憶體用量很不平均:以 224×224 輸入的 MobileNetV2 為例,前面幾層的特徵圖最大。MCUNet v2 的做法是在記憶體最密集的那段改成一塊一塊(patch-by-patch)算,其他地方照常一層一層算;patch 會有重疊造成重複計算,所以再重新分配感受野:縮小 patch 階段的感受野、加大後面的,補回準確率。

動態執行(依輸入決定算多少):不是每張輸入都一樣難。SBNet 先算一張計算遮罩(例如 LiDAR 偵測時,路面以外的區域不用算),轉成 tile 清單,把要算的 tile 沿 batch 維度堆起來(gather)用一般的密集卷積算,再寫回去(scatter)。Dynamic network slimming:一個預測器看輸入,輸出一組門檻,當場把模型剪成適合這張圖的大小。Input-dependent depth:語音辨識的 Transformer 依輸入決定要走幾層。講義強調動態執行和其他方法正交,可以疊著用。

SEC.04 / KNOWLEDGE DISTILLATION

小模型跟大模型學:蒸餾

小模型難訓練,一個原因是標準答案太「瘦」:一張貓的圖,標籤只說「是貓」(hard target)。訓練好的大模型(老師)知道更多:它會說「九成是貓,有一點像狗,完全不像卡車」。用老師的機率分佈當學生的目標(soft target),學生就多學到「類別之間誰像誰」。問題是老師的 softmax 太尖,第二名以後幾乎都是 0。解法是在 softmax 裡除以一個溫度 T:pi = ezi/T / Σ ezj/T。

PROBE D / 調高溫度,看暗知識浮出來動手做 // 拉溫度 T
第一名的機率0
第二、三名(暗知識)0
分佈的 entropy(最大 3.32 bits)0
第二名是最後一名的幾倍0T 越高,排名不變,但差距被壓扁
機率是用 softmax(z/T) 真的算出來的;老師的 10 個 logits 是為了說明而設的固定數字。看 T 從 1 拉到 3。T = 1 時,貓的機率接近 1,狗只有約 2%,其他幾乎看不到,和 hard target 沒差多少。T = 3 時,狗、鹿、馬浮出來了,而飛機、卡車還是很低:這個「貓有點像狗、完全不像卡車」的資訊就是 dark knowledge。T 拉到 20,分佈幾乎變平,排名還在,但每一類都差不多,資訊又變少了。所以 T 不是越大越好,講義說一般用 3 左右。
錯的答案也有資訊「不太像狗」和「完全不像卡車」是兩件不同的事。hard target 把它們都寫成 0。
溫度只改形狀,不改排名除以 T 等於把 logits 的差距縮小,指數之後就沒那麼極端。T = 1 就是原本的 softmax。
老師可以是一群把很多模型(ensemble)的輸出平均起來當老師,再蒸餾到一個小模型,部署時只要跑一個。
細看 · soft target 怎麼用、老師模型裡有哪幾種知識

做法:學生(小網路)和老師(大網路)看同一張圖,都用同一個溫度 T 算 softmax,學生最小化和老師分佈之間的 cross-entropy(soft target);通常再加上一項和真實標籤的 cross-entropy(hard target)。推論時學生用回 T = 1。原始論文(2015)提出 softmax temperature 就是為了解決「老師太有自信、soft target 太尖」這件事。

為什麼有用:soft target 用機率分佈,而不只是對或錯,提供更多隱含資訊:哪些類別彼此相似、哪些差很遠,等於在訓練中多加了很多判斷條件。講義也提到 ensemble:把 N 個網路的輸出平均後當老師。

老師模型裡的幾種知識(講義引用的 knowledge distillation survey 的分法):response-based,學老師最後的輸出(就是這一節的 soft target);feature-based,學老師中間層的特徵圖;relation-based,學不同層之間、或不同樣本之間的關係。

和其他方法的關係:講義把蒸餾列為「恢復準確率」的工具之一,和放大輸入、depth、width,混用 kernel 大小,SE attention 並列。講義的總結也說:先訓練大模型再壓縮是一條路,而 fine-tuning 是恢復準確率最好的朋友。

SEC.05 / MISCONCEPTIONS

常見誤解

這個模組最常被講錯的幾句話。講義的結論第一句就是:模型大小和 FLOPs 不等於執行時間。

FLOPs 少一半,跑起來就快一倍。執行時間 = 計算 + 搬資料 + 啟動成本。同 FLOPs 的網路,速度可以差很多;要量真實硬體上的延遲,還要看函式庫有沒有支援。
參數少,就省記憶體、跑得快。參數只是權重。SqueezeNet 參數少 50 倍,乘加卻和 AlexNet 差不多;執行時大部分記憶體是特徵圖,ResNet-50 的殘差連接就占了約 40%。
depthwise separable 少了 8、9 倍乘加,一定比較快。depthwise 的 FLOPs 低但 MAC 高,被當成 element-wise 那一類;在頻寬小的硬體上,它省下的乘加可能被搬資料吃掉。
蒸餾只是把大模型壓小的一種壓縮法。蒸餾是換一個更有資訊的訓練目標。學生的架構可以完全不同,老師也可以是一群模型;它常拿來補回小模型損失的準確率。