{"notes":[{"id":"classic-cnns/inception-v3","category":"classic-cnns","legacyPath":"","legacySlug":"","legacyPaths":[],"title":"Inception-v3","subtitle":"大卷積核退場","author":"Z. Yuan","paperDate":"2015-12-02","publishedOn":"2025-12-16","world":"external/inception-v3","paperTitle":"Rethinking the Inception Architecture for Computer Vision","paperUrl":"https://arxiv.org/abs/1512.00567","bibliography":{"title":"Rethinking the Inception Architecture for Computer Vision","authors":["Christian Szegedy","Vincent Vanhoucke","Sergey Ioffe","Jonathon Shlens","Zbigniew Wojna"],"url":"https://arxiv.org/abs/1512.00567","pdfUrl":"https://arxiv.org/pdf/1512.00567v3","codeUrl":null,"preprint":{"id":"1512.00567","submittedOn":"2015-12-02","url":"https://arxiv.org/abs/1512.00567"},"publication":null,"citation":"@misc{classiccnnsinceptionv32015,\n  title = {{Rethinking the Inception Architecture for Computer Vision}},\n  author = {Christian Szegedy and Vincent Vanhoucke and Sergey Ioffe and Jonathon Shlens and Zbigniew Wojna},\n  year = {2015},\n  eprint = {1512.00567},\n  archivePrefix = {arXiv},\n  url = {https://arxiv.org/abs/1512.00567}\n}\n","citationPath":"/content/papers/citations/classic-cnns/inception-v3.5636c0bddf2d.bib"},"thumbnail":{"src":"/content/papers/assets/c87d3d6fa9ea76d954eba2570f702150eca32d62c7cdb3d724075a4be9a63080.png","width":419,"height":358},"locale":"zh-hant","path":"/content/papers/zh-hant/classic-cnns/inception-v3.b02feaa71206.md","headings":[{"id":"定義問題","text":"定義問題","depth":2},{"id":"解決問題","text":"解決問題","depth":2},{"id":"把-55-拆成兩層-33","text":"把 5×5 拆成兩層 3×3","depth":3},{"id":"再拆成-1n-與-n1","text":"再拆成 1×n 與 n×1","depth":3},{"id":"輔助分類器的真正作用","text":"輔助分類器的真正作用","depth":3},{"id":"縮小特徵圖又不想卡住資訊","text":"縮小特徵圖，又不想卡住資訊","depth":3},{"id":"把零件組起來","text":"把零件組起來","depth":3},{"id":"讓模型別太有把握","text":"讓模型別太有把握","depth":3},{"id":"訓練設定","text":"訓練設定","depth":3},{"id":"討論","text":"討論","depth":2},{"id":"一項一項加上去","text":"一項一項加上去","depth":3},{"id":"解析度低一點差多少","text":"解析度低一點，差多少？","depth":3},{"id":"和其他模型比","text":"和其他模型比","depth":3},{"id":"結論","text":"結論","depth":2}],"anchorAliases":{},"guide":null,"relatedReading":[{"id":"classic-cnns/inception-v1","relation":"referenced","topic":""},{"id":"normalization/batchnorm","relation":"referenced","topic":""},{"id":"classic-cnns/convnext","relation":"referenced","topic":""}]},{"id":"classic-cnns/inception-v1","category":"classic-cnns","legacyPath":"classic-cnns/1409-inception-v1","legacySlug":"1409-inception-v1","legacyPaths":[],"title":"GoogLeNet","subtitle":"或叫做 Inception-V1","author":"Z. Yuan","paperDate":"2014-09-17","publishedOn":"2024-09-22","paperTitle":"Going Deeper with Convolutions","paperUrl":"https://arxiv.org/abs/1409.4842","bibliography":{"title":"Going Deeper with Convolutions","authors":["Christian Szegedy","Wei Liu","Yangqing Jia","Pierre Sermanet","Scott Reed","Dragomir Anguelov","Dumitru Erhan","Vincent Vanhoucke","Andrew Rabinovich"],"url":"https://arxiv.org/abs/1409.4842","pdfUrl":"https://arxiv.org/pdf/1409.4842","codeUrl":null,"preprint":{"id":"1409.4842","submittedOn":"2014-09-17","url":"https://arxiv.org/abs/1409.4842"},"publication":{"venue":"CVPR","year":2015,"kind":"conference","url":"https://doi.org/10.1109/cvpr.2015.7298594"},"citation":"@misc{classiccnnsinceptionv12014,\n  title = {{Going Deeper with Convolutions}},\n  author = {Christian Szegedy and Wei Liu and Yangqing Jia and Pierre Sermanet and Scott Reed and Dragomir Anguelov and Dumitru Erhan and Vincent Vanhoucke and Andrew Rabinovich},\n  year = {2014},\n  eprint = {1409.4842},\n  archivePrefix = {arXiv},\n  url = {https://arxiv.org/abs/1409.4842}\n}\n","citationPath":"/content/papers/citations/classic-cnns/inception-v1.3d20e0e32bcd.bib"},"thumbnail":{"src":"/content/papers/assets/254b970b1374c24267b60c2d684338760e9ba8b10dad761a5fa15f1bb8bcf6ef.jpg","width":1330,"height":394},"locale":"zh-hant","path":"/content/papers/zh-hant/classic-cnns/inception-v1.91efdf81ddcf.md","headings":[{"id":"解決問題","text":"解決問題","depth":2},{"id":"inception-模塊","text":"Inception 模塊","depth":3},{"id":"參數配置","text":"參數配置","depth":3},{"id":"模型架構","text":"模型架構","depth":3},{"id":"討論","text":"討論","depth":2},{"id":"在-ilsvrc-2014-上的表現","text":"在 ILSVRC 2014 上的表現","depth":3},{"id":"結論","text":"結論","depth":2}],"anchorAliases":{},"guide":null,"relatedReading":[{"id":"classic-cnns/resnext","relation":"comparison","topic":"分支、分組卷積與特徵重用"},{"id":"classic-cnns/cspnet","relation":"comparison","topic":"分支、分組卷積與特徵重用"}]},{"id":"normalization/batchnorm","category":"normalization","legacyPath":"normalization/1502-batchnorm","legacySlug":"1502-batchnorm","legacyPaths":[],"title":"BatchNorm","subtitle":"批次標準化","author":"Z. Yuan","paperDate":"2015-02-11","publishedOn":"2024-08-01","paperTitle":"Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift","paperUrl":"https://arxiv.org/abs/1502.03167","bibliography":{"title":"Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift","authors":["Sergey Ioffe","Christian Szegedy"],"url":"https://arxiv.org/abs/1502.03167","pdfUrl":"https://arxiv.org/pdf/1502.03167","codeUrl":null,"preprint":{"id":"1502.03167","submittedOn":"2015-02-11","url":"https://arxiv.org/abs/1502.03167"},"publication":null,"citation":"@misc{normalizationbatchnorm2015,\n  title = {{Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift}},\n  author = {Sergey Ioffe and Christian Szegedy},\n  year = {2015},\n  eprint = {1502.03167},\n  archivePrefix = {arXiv},\n  url = {https://arxiv.org/abs/1502.03167}\n}\n","citationPath":"/content/papers/citations/normalization/batchnorm.bfa8abb33f32.bib"},"thumbnail":{"src":"/content/papers/assets/48b236d4b897164b93764eccfe22db29e5b9bce290d864336b8f12ec127c1e4b.jpg","width":1016,"height":824},"locale":"zh-hant","path":"/content/papers/zh-hant/normalization/batchnorm.062711be4913.md","headings":[{"id":"定義問題","text":"定義問題","depth":2},{"id":"解決問題","text":"解決問題","depth":2},{"id":"提高學習率","text":"提高學習率","depth":3},{"id":"不需要-dropout","text":"不需要 Dropout","depth":3},{"id":"討論","text":"討論","depth":2},{"id":"在-mnist-實驗","text":"在 MNIST 實驗","depth":3},{"id":"在-imagenet-實驗","text":"在 ImageNet 實驗","depth":3},{"id":"結論","text":"結論","depth":2}],"anchorAliases":{},"guide":null,"relatedReading":[{"id":"normalization/layernorm","relation":"next","topic":"正規化究竟沿哪個維度算"}]},{"id":"classic-cnns/convnext","category":"classic-cnns","legacyPath":"classic-cnns/2201-convnext","legacySlug":"2201-convnext","legacyPaths":[],"title":"ConvNeXt","subtitle":"讓卷積再次偉大","author":"Z. Yuan","paperDate":"2022-01-10","publishedOn":"2024-06-30","paperTitle":"A ConvNet for the 2020s","paperUrl":"https://arxiv.org/abs/2201.03545","bibliography":{"title":"A ConvNet for the 2020s","authors":["Zhuang Liu","Hanzi Mao","Chao-Yuan Wu","Christoph Feichtenhofer","Trevor Darrell","Saining Xie"],"url":"https://arxiv.org/abs/2201.03545","pdfUrl":"https://arxiv.org/pdf/2201.03545","codeUrl":"https://github.com/facebookresearch/ConvNeXt","preprint":{"id":"2201.03545","submittedOn":"2022-01-10","url":"https://arxiv.org/abs/2201.03545"},"publication":{"venue":"CVPR","year":2022,"kind":"conference","url":"https://arxiv.org/abs/2201.03545"},"citation":"@misc{classiccnnsconvnext2022,\n  title = {{A ConvNet for the 2020s}},\n  author = {Zhuang Liu and Hanzi Mao and Chao-Yuan Wu and Christoph Feichtenhofer and Trevor Darrell and Saining Xie},\n  year = {2022},\n  eprint = {2201.03545},\n  archivePrefix = {arXiv},\n  url = {https://arxiv.org/abs/2201.03545}\n}\n","citationPath":"/content/papers/citations/classic-cnns/convnext.801b4060b807.bib"},"thumbnail":{"src":"/content/papers/assets/37882616c5c72df33699003256d14bf7c58c8ea5d1e9e4fb5b1c33268c9a6923.jpg","width":1224,"height":432},"locale":"zh-hant","path":"/content/papers/zh-hant/classic-cnns/convnext.667fd92d121a.md","headings":[{"id":"定義問題","text":"定義問題","depth":2},{"id":"解決問題","text":"解決問題","depth":2},{"id":"重新設計網路架構","text":"重新設計網路架構","depth":3},{"id":"引入現代訓練技術","text":"引入現代訓練技術","depth":3},{"id":"宏觀設計","text":"宏觀設計","depth":3},{"id":"resnext-ify","text":"ResNeXt-ify","depth":3},{"id":"inverted-bottleneck","text":"Inverted Bottleneck","depth":3},{"id":"大核卷積","text":"大核卷積","depth":3},{"id":"微觀設計","text":"微觀設計","depth":3},{"id":"討論","text":"討論","depth":2},{"id":"總結模型配置","text":"總結模型配置","depth":3},{"id":"imagenet-上的性能","text":"ImageNet 上的性能","depth":3},{"id":"結論","text":"結論","depth":2}],"anchorAliases":{},"guide":null,"relatedReading":[{"id":"vision-transformers/convmixer","relation":"comparison","topic":"用卷積混合影像切塊"},{"id":"vision-transformers/caformer","relation":"comparison","topic":"用卷積混合影像切塊"},{"id":"reparameterization/replknet","relation":"comparison","topic":"大卷積核與簡化骨架"}]}],"text":"GoogLeNet 拿下 ILSVRC 2014 分類賽冠軍時，只用了大約 500 萬個參數，是 AlexNet 的十二分之一。\n\n這個效率很誘人，但想改它的人很快會碰到麻煩。GoogLeNet 的論文沒有說清楚每個設計決定是怎麼來的；Inception 模組的分支又多，想把模型放大，最直覺的做法是把每一組濾波器的數量都翻倍，結果計算量和參數量一起變成四倍。\n\n2015 年 12 月，Google 的 Christian Szegedy、Vincent Vanhoucke、Sergey Ioffe、Jonathon Shlens 與倫敦大學學院的 Zbigniew Wojna 放出這篇論文，後來發表在 CVPR 2016。標題裡的「Rethinking」說的就是這件事：把 Inception 拆開重新想一遍，看看哪些做法能在放大網路的同時，讓多出來的計算花得值得。\n\n\n> [!TIP]\n> \n> Inception 模組的基本樣子，可以先看我們的筆記：\n> \n> - **[[14.09] GoogLeNet：或叫做 Inception-V1](/blog/papers/classic-cnns/inception-v1)**\n\n\n## 定義問題\n\n作者想回答的是：計算預算有限時，網路要怎麼放大？\n\n他們從大量的架構實驗裡整理出四條原則。作者自己說得很保守：這些原則還帶有推測成分，需要更多實驗確認適用範圍；建議只在拿不定主意時參考。不過實驗中明顯違反它們的網路，品質通常會變差，修正之後又會變好。\n\n1. **避免表示瓶頸，尤其在網路前段**。從輸入到輸出，特徵的大小應該慢慢縮小，不要在某一層突然壓得很扁。作者也提醒，維度只是資訊量的粗略估計。\n2. **高維度的表示比較容易在局部處理**。每個位置的激活數多一些，特徵比較容易解開，訓練也比較快。\n3. **空間上的聚合可以在低維度上做**。例如做 $3\\times3$ 卷積之前，先把通道數降下來，表達能力不太會受損。作者的猜測是：相鄰位置的輸出高度相關，降維時資訊損失不大。\n4. **寬度和深度要平衡**。兩者都加會更好；在固定的計算量下，同時增加寬度和深度，效果最好。\n\nGoogLeNet 早期的收益，很大一部分來自大量使用 $1\\times1$ 卷積降維，也就是第 3 條。作者把降維看成「分解卷積」的一個特例，接下來要找其他的分解方法。\n\n## 解決問題\n\n### 把 5×5 拆成兩層 3×3\n\n大的卷積核很貴。在相同的輸入、輸出通道數下，$5\\times5$ 卷積的計算量是 $3\\times3$ 的 $25/9\\approx2.78$ 倍。\n\n可是大卷積核也看得比較遠。能不能用比較少的參數，得到一樣大的視野？\n\n作者換了一個角度看 $5\\times5$ 卷積：每個輸出，都是一個小型的全連接網路，滑過輸入上一塊 $5\\times5$ 的區域。既然是視覺網路，這個小網路本身也可以利用平移不變性，改成兩層：第一層是 $3\\times3$ 卷積，第二層在第一層輸出的 $3\\times3$ 格子上做全連接。把這個兩層的小網路滑過整張輸入，就等於兩層 $3\\times3$ 卷積。\n\n[![三層藍色方格疊在一起。最下層是一塊 5×5 的輸入區域，中間是一個 3×3 的格子，最上層是一個輸出格子；紅線標出最上層的格子連到中間整個 3×3 區域，中間每一格又連到下方的一塊 3×3 區域](/content/papers/assets/c87d3d6fa9ea76d954eba2570f702150eca32d62c7cdb3d724075a4be9a63080.png)](/content/papers/assets/c87d3d6fa9ea76d954eba2570f702150eca32d62c7cdb3d724075a4be9a63080.png)\n\n*原論文 Figure 1，取自 [**v3 PDF 第 3 頁**](https://arxiv.org/pdf/1512.00567v3#page=3)。取代 $5\\times5$ 卷積的小網路：上層的一個輸出看中層的 $3\\times3$，中層每格再看輸入的 $3\\times3$。*\n\n先算省了多少。拿一張 $35\\times35$、64 個通道的特徵圖，輸出通道數不變：\n\n```python\nimport torch\nimport torch.nn as nn\n\nx = torch.randn(1, 64, 35, 35)                 # 35×35 的特徵圖，64 個通道\n\nbig = nn.Conv2d(64, 64, 5, padding=2, bias=False)\nsmall = nn.Sequential(nn.Conv2d(64, 64, 3, padding=1, bias=False),\n                      nn.Conv2d(64, 64, 3, padding=1, bias=False))\n\ndef params(m):\n    return sum(p.numel() for p in m.parameters())\n\nprint(big(x).shape, small(x).shape)\nprint(\"5×5 參數：\", params(big))\nprint(\"兩層 3×3 參數：\", params(small), f\"（{params(small) / params(big):.0%}）\")\n```\n\n```text\ntorch.Size([1, 64, 35, 35]) torch.Size([1, 64, 35, 35])\n5×5 參數： 102400\n兩層 3×3 參數： 73728 （72%）\n```\n\n輸出形狀一樣，參數剩 $(9+9)/25 = 72\\%$，省下 28%。卷積網路裡每個權重在每個輸出位置剛好用一次，所以計算量也省下同樣的比例。這裡假設中間層的通道數和輸入相同；論文的分析也是這樣簡化的。\n\n再確認視野。把兩層 $3\\times3$ 的權重都設成 1，看中心那一個輸出對輸入的梯度：\n\n```python\nimport torch\nimport torch.nn as nn\n\nstack = nn.Sequential(nn.Conv2d(1, 1, 3, padding=1), nn.ReLU(),\n                      nn.Conv2d(1, 1, 3, padding=1))\nfor conv in (stack[0], stack[2]):              # 權重設成 1，讓每條連線都看得見\n    nn.init.ones_(conv.weight)\n    nn.init.zeros_(conv.bias)\n\nx = torch.rand(1, 1, 9, 9, requires_grad=True)\nstack(x)[0, 0, 4, 4].backward()                # 只看中心的一個輸出\n\nprint(x.grad[0, 0].int())\n```\n\n```text\ntensor([[0, 0, 0, 0, 0, 0, 0, 0, 0],\n        [0, 0, 0, 0, 0, 0, 0, 0, 0],\n        [0, 0, 1, 2, 3, 2, 1, 0, 0],\n        [0, 0, 2, 4, 6, 4, 2, 0, 0],\n        [0, 0, 3, 6, 9, 6, 3, 0, 0],\n        [0, 0, 2, 4, 6, 4, 2, 0, 0],\n        [0, 0, 1, 2, 3, 2, 1, 0, 0],\n        [0, 0, 0, 0, 0, 0, 0, 0, 0],\n        [0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=torch.int32)\n```\n\n非零的區域剛好是 $5\\times5$。格子裡的數字是「從這個輸入點走到輸出，有幾條路」：中心有 9 條，角落只有 1 條。兩層 $3\\times3$ 看得和 $5\\times5$ 一樣遠，只是中間的位置被看得比較重。\n\n這種替換留下兩個問題。第一，表達能力會不會變差？第二，既然要分解的是 $5\\times5$ 這個線性運算，第一層是不是應該保持線性，不加 ReLU？\n\n作者做了幾組對照實驗，其中一組比較兩個 Inception 模型：一個在分解出來的第一層用線性激活，另一個兩層都用 ReLU，最後在驗證集上分別停在 76.2% 和 77.2% 的 top-1 準確率。作者說，所有對照實驗裡，線性版本都比較差；他們的解釋是多一層非線性讓網路能學的變化變多，加上 batch normalization 時尤其明顯。\n\n### 再拆成 1×n 與 n×1\n\n這樣看來，比 $3\\times3$ 大的卷積核都可以換成一串 $3\\times3$。那 $3\\times3$ 能不能再拆？\n\n拆成兩層 $2\\times2$，只省 11%。作者找到更好的拆法：不對稱的卷積。先做 $3\\times1$，再做 $1\\times3$，視野一樣是 $3\\times3$。\n\n[![一個上窄下寬的示意圖：底部是 3×3 的輸入區域，中間一列 3×1 的格子，頂端是一個輸出格子；紅線標出輸出先連到中間這一列 3 格，這 3 格再各自連到輸入的一整列](/content/papers/assets/26d9fd5f020cc9ce53cac89b03dbc710d155db812e4745d2e1c47a456faa3b1a.png)](/content/papers/assets/26d9fd5f020cc9ce53cac89b03dbc710d155db812e4745d2e1c47a456faa3b1a.png)\n\n*原論文 Figure 3，取自 [**v3 PDF 第 4 頁**](https://arxiv.org/pdf/1512.00567v3#page=4)。取代 $3\\times3$ 卷積的小網路：下層是有 3 個輸出的 $3\\times1$ 卷積。*\n\n用同樣的方法檢查：\n\n```python\nimport torch\nimport torch.nn as nn\n\npair = nn.Sequential(nn.Conv2d(1, 1, (1, 3), padding=(0, 1)),   # 1×3：只往左右看\n                     nn.Conv2d(1, 1, (3, 1), padding=(1, 0)))   # 3×1：只往上下看\nfor conv in pair:\n    nn.init.ones_(conv.weight)\n    nn.init.zeros_(conv.bias)\n\nx = torch.rand(1, 1, 7, 7, requires_grad=True)\npair(x)[0, 0, 3, 3].backward()\nprint(x.grad[0, 0].int())\n\nfor name, cost in [(\"3×3\", 9), (\"1×3 + 3×1\", 3 + 3), (\"兩層 2×2\", 4 + 4),\n                   (\"7×7\", 49), (\"1×7 + 7×1\", 7 + 7)]:\n    print(f\"{name}：{cost}\")\n```\n\n```text\ntensor([[0, 0, 0, 0, 0, 0, 0],\n        [0, 0, 0, 0, 0, 0, 0],\n        [0, 0, 1, 1, 1, 0, 0],\n        [0, 0, 1, 1, 1, 0, 0],\n        [0, 0, 1, 1, 1, 0, 0],\n        [0, 0, 0, 0, 0, 0, 0],\n        [0, 0, 0, 0, 0, 0, 0]], dtype=torch.int32)\n3×3：9\n1×3 + 3×1：6\n兩層 2×2：8\n7×7：49\n1×7 + 7×1：14\n```\n\n下面幾行是每個輸出、每對輸入輸出通道要做的乘法數。$1\\times3$ 加 $3\\times1$ 是 6 次，比 $3\\times3$ 少三分之一；兩層 $2\\times2$ 是 8 次，只少九分之一。卷積核越大，省得越多：$7\\times7$ 要 49 次，拆成 $1\\times7$ 加 $7\\times1$ 只要 14 次。\n\n不過這招不是到處都好用。作者發現放在網路前段效果不好，放在中等大小的特徵圖上（邊長大約 12 到 20）效果很好。實際的網路在 $17\\times17$ 的特徵圖上用 $1\\times7$ 接 $7\\times1$：\n\n[![Inception 模組示意圖：最下方是 Base，往上分成四條分支。最左邊是 1x1 後接 1xn、nx1、1xn、nx1 共四層；第二條是 1x1 後接 1xn、nx1；第三條是 Pool 後接 1x1；最右邊只有 1x1。四條分支最後在 Filter Concat 合併](/content/papers/assets/d7b13cfd7a93816701d9571a2e87bd67983a5e6ffe9a7b93cbcf40e82db76a2f.png)](/content/papers/assets/d7b13cfd7a93816701d9571a2e87bd67983a5e6ffe9a7b93cbcf40e82db76a2f.png)\n\n*原論文 Figure 6，取自 [**v3 PDF 第 5 頁**](https://arxiv.org/pdf/1512.00567v3#page=5)。分解 $n\\times n$ 卷積後的 Inception 模組；在 $17\\times17$ 的特徵圖上，作者取 $n=7$。*\n\n把它和 GoogLeNet 原本的模組對照：原本是 $1\\times1$、$3\\times3$、$5\\times5$ 與池化四條分支。這裡最左邊那條，相當於把兩層 $7\\times7$ 各拆成一對不對稱卷積；第二條則是一層 $7\\times7$ 的拆法。$35\\times35$ 那一段用的是 Figure 5 的模組，也就是把 $5\\times5$ 換成兩層 $3\\times3$。\n\n到了最小的 $8\\times8$ 特徵圖，作者換了一種用法：\n\n[![Inception 模組示意圖：最左邊的分支是 1x1、3x3，之後同時分出 1x3 與 3x1 兩個並排的卷積；第二條是 1x1 後同時分出 1x3 與 3x1；另外還有 Pool 接 1x1，以及單獨的 1x1。所有輸出在 Filter Concat 合併](/content/papers/assets/1475f4de3132dd0d1dbd081ddc453fb140796cb802987fa051a70356070b1b41.png)](/content/papers/assets/1475f4de3132dd0d1dbd081ddc453fb140796cb802987fa051a70356070b1b41.png)\n\n*原論文 Figure 7，取自 [**v3 PDF 第 5 頁**](https://arxiv.org/pdf/1512.00567v3#page=5)。擴展輸出濾波器的 Inception 模組，只用在最粗的 $8\\times8$ 特徵圖上。*\n\n注意 $1\\times3$ 和 $3\\times1$ 在這裡是**並排**的，兩個輸出直接接到最後的合併，沒有串起來。這樣做讓輸出的通道數變多，對應第 2 條原則：在最後的特徵圖上產生高維度的表示。作者只在 $8\\times8$ 這裡用它，理由是到了這個階段，$1\\times1$ 卷積做的局部處理，比空間上的聚合更重要。\n\n### 輔助分類器的真正作用\n\nGoogLeNet 在網路中間掛了兩個輔助分類器，原本的想法是把有用的梯度送到前面幾層，對抗梯度消失、加快收斂。\n\n作者重新觀察後，發現事情不是這樣。訓練前期，有沒有輔助分類器的兩條曲線幾乎一樣；要到訓練快結束時，有輔助分類器的網路才開始超前，最後停在稍高的位置。把位置比較低的那個輔助分類器拿掉，最終品質也沒有變差。\n\n所以 GoogLeNet 當初的假設，也就是輔助分支幫助底層特徵演化，作者認為多半不成立。他們的新解釋是：輔助分類器是一種**正則化**。證據是，輔助分支加上 batch normalization 或 dropout 時，主分類器的表現會更好；在輔助分支加 batch normalization，top-1 準確率絕對值提升 0.4%。Inception-v3 的輔助分類器接在最後一層 $17\\times17$ 的特徵圖上。\n\n作者也順帶提了一句：這個現象對「batch normalization 有正則化效果」的猜想，算是一點微弱的支持。\n\n### 縮小特徵圖，又不想卡住資訊\n\n卷積網路通常靠池化把特徵圖縮小。假設要把 $35\\times35\\times320$ 變成 $17\\times17\\times640$，有兩種直接的做法：\n\n- **先卷積再池化**：先在 $35\\times35$ 上把通道從 320 加到 640，再池化。資訊沒有被卡住，但最貴的卷積是在大的特徵圖上做。\n- **先池化再卷積**：先池化到 $17\\times17$，再加通道。便宜很多，但中間有一步只剩 $17\\times17\\times320$，違反第 1 條原則。\n\n我們用一層 $3\\times3$ 卷積粗略算一下：\n\n```python\nd, k = 35, 320                               # 35×35×320，要變成 17×17×640\nh = 17\n\nconv_then_pool = d * d * k * (2 * k) * 9     # 先在 35×35 上做 320→640 的 3×3 卷積\npool_then_conv = h * h * k * (2 * k) * 9     # 先池化到 17×17，再做 320→640\nparallel = h * h * k * k * 9                 # 步幅 2 的卷積只出 320 個通道，另一半交給池化\n\nfor name, macs in [(\"先卷積再池化\", conv_then_pool), (\"先池化再卷積\", pool_then_conv), (\"卷積與池化並排\", parallel)]:\n    print(f\"{name}：{macs / 1e6:7.1f} M 次乘加\")\n\nprint(\"先池化後，中間只剩\", h * h * k, \"個數；輸入有\", d * d * k, \"個\")\n```\n\n```text\n先卷積再池化： 2257.9 M 次乘加\n先池化再卷積：  532.7 M 次乘加\n卷積與池化並排：  266.3 M 次乘加\n先池化後，中間只剩 92480 個數；輸入有 392000 個\n```\n\n先卷積的做法，計算量是先池化的四倍多。\n\n作者的解法是第三行：讓步幅 2 的卷積和步幅 2 的池化**並排**，各自直接把特徵圖縮小，再把兩邊的通道接起來：\n\n[![左右兩張圖。左邊是模組的運算：Base 往上分成三條分支，兩條是 1x1 後接步幅 2 的 3x3 卷積（其中一條在前面多一層步幅 1 的 3x3），第三條是步幅 2 的池化，最後在 Filter Concat 合併。右邊從特徵圖大小來看：35x35x320 分成 conv 與 pool 兩邊，各得到 17x17x320，接起來成為 17x17x640](/content/papers/assets/9d6b75a1dd143d0b517f52adf42c4fe794cb400e3276a8109561db2277fb2fb6.png)](/content/papers/assets/9d6b75a1dd143d0b517f52adf42c4fe794cb400e3276a8109561db2277fb2fb6.png)\n\n*原論文 Figure 10，取自 [**v3 PDF 第 6 頁**](https://arxiv.org/pdf/1512.00567v3#page=6)。左邊是縮小特徵圖、同時增加通道的 Inception 模組；右邊從特徵圖大小的角度看同一件事。*\n\n右邊那張圖最好讀：$35\\times35\\times320$ 分成兩路，卷積那路輸出 $17\\times17\\times320$，池化那路也是 $17\\times17\\times320$，接起來就是 $17\\times17\\times640$。卷積只需要輸出一半的通道，計算量又比先池化的做法少一半；而輸出直接就是 640 個通道，沒有經過被壓扁的那一步。\n\n### 把零件組起來\n\n作者把上面這些零件組成一個新網路：\n\n| 類型 | 卷積核／步幅或說明 | 輸入大小 |\n| --- | --- | --- |\n| conv | $3\\times3$／2 | $299\\times299\\times3$ |\n| conv | $3\\times3$／1 | $149\\times149\\times32$ |\n| conv（補零） | $3\\times3$／1 | $147\\times147\\times32$ |\n| pool | $3\\times3$／2 | $147\\times147\\times64$ |\n| conv | $3\\times3$／1 | $73\\times73\\times64$ |\n| conv | $3\\times3$／2 | $71\\times71\\times80$ |\n| conv | $3\\times3$／1 | $35\\times35\\times192$ |\n| 3 × Inception | 同 Figure 5 | $35\\times35\\times288$ |\n| 5 × Inception | 同 Figure 6 | $17\\times17\\times768$ |\n| 2 × Inception | 同 Figure 7 | $8\\times8\\times1280$ |\n| pool | $8\\times8$ | $8\\times8\\times2048$ |\n| linear | logits | $1\\times1\\times2048$ |\n| softmax | 分類器 | $1\\times1\\times1000$ |\n\n*表：摘自原論文 Table 1。每一列的輸入大小，就是上一列的輸出大小。*\n\n開頭三層 $3\\times3$ 卷積，是把傳統的 $7\\times7$ 第一層拆開來的結果，和 $5\\times5$ 換成兩層 $3\\times3$ 是同一個想法。三段 Inception 之間，用 Figure 10 那類模組縮小特徵圖。整個網路有 42 層。\n\n你可能會好奇，輸入為什麼是 $299\\times299$ 這麼奇怪的數字。照表上的設定算一次：\n\n```python\ndef out(n, k, s, pad=0):\n    return (n + 2 * pad - k) // s + 1\n\nn = 299\nfor name, k, s, pad in [(\"conv 3×3/2\", 3, 2, 0), (\"conv 3×3/1\", 3, 1, 0), (\"conv 3×3/1 補零\", 3, 1, 1),\n                        (\"pool 3×3/2\", 3, 2, 0), (\"conv 3×3/1\", 3, 1, 0), (\"conv 3×3/2\", 3, 2, 0)]:\n    m = out(n, k, s, pad)\n    print(f\"{name}：{n} → {m}，餘數 {(n + 2 * pad - k) % s}\")\n    n = m\n\nfor name in [\"縮小到 17×17\", \"縮小到 8×8\"]:\n    m = out(n, 3, 2)\n    print(f\"{name}：{n} → {m}，餘數 {(n - 3) % 2}\")\n    n = m\n```\n\n```text\nconv 3×3/2：299 → 149，餘數 0\nconv 3×3/1：149 → 147，餘數 0\nconv 3×3/1 補零：147 → 147，餘數 0\npool 3×3/2：147 → 73，餘數 0\nconv 3×3/1：73 → 71，餘數 0\nconv 3×3/2：71 → 35，餘數 0\n縮小到 17×17：35 → 17，餘數 0\n縮小到 8×8：17 → 8，餘數 0\n```\n\n每一個步幅 2、不補零的層都剛好整除，沒有任何一列像素被丟掉，最後落在表上的 $35$、$17$、$8$。論文沒有解釋為什麼選 299，但這組數字確實讓整條路徑對得很整齊。\n\n### 讓模型別太有把握\n\n最後一個零件和架構無關，處理的是標籤。\n\n對一張訓練影像 $x$，模型用 softmax 算出每個類別的機率：\n\n$$\np(k\\mid x) = \\frac{\\exp(z_k)}{\\sum_{i=1}^{K}\\exp(z_i)}\n$$\n\n$z_k$ 是 logits。真實標籤的分布記為 $q(k\\mid x)$，交叉熵損失是：\n\n$$\n\\ell = -\\sum_{k=1}^{K} \\log p(k)\\, q(k)\n$$\n\n它對 logits 的梯度很簡單：$\\partial\\ell/\\partial z_k = p(k) - q(k)$，大小落在 $-1$ 到 $1$ 之間。\n\n一般的訓練用 one-hot 標籤：正確類別 $y$ 的 $q(y)=1$，其他都是 0。要讓損失降到最低，$p(y)$ 要等於 1，這在有限的 logits 下做不到，只能讓 $z_y$ 一路比其他 logits 大下去。\n\n作者指出這會造成兩個問題。第一，模型學會對每張訓練影像都給出百分之百的信心，不一定能推廣。第二，最大的 logit 和其他 logits 的差距被推得很大，梯度又有上限，模型就比較難再調整。直白地說，模型對自己的預測太有把握了。\n\n他們的做法是把標籤分布換掉：\n\n$$\nq'(k\\mid x) = (1-\\epsilon)\\,\\delta_{k,y} + \\epsilon\\, u(k)\n$$\n\n$u(k)$ 是一個和影像無關的固定分布，作者用均勻分布 $u(k)=1/K$。這個做法叫 label smoothing regularization（LSR）。ImageNet 有 $K=1000$ 類，$\\epsilon=0.1$。\n\n我們直接把 logits 當成參數，看兩種標籤會把它推到哪裡：\n\n```python\nimport torch\nimport torch.nn.functional as F\n\nK, eps, y = 1000, 0.1, 0\nhard = torch.zeros(K); hard[y] = 1\nsmooth = (1 - eps) * hard + eps / K\nprint(\"平滑後的目標：正確類別\", round(smooth[y].item(), 4), \"，其他類別\", round(smooth[1].item(), 4))\n\nfor name, q in [(\"one-hot\", hard), (\"label smoothing\", smooth)]:\n    z = torch.zeros(K, requires_grad=True)               # 直接把 logits 當參數，看損失把它推向哪裡\n    opt = torch.optim.SGD([z], lr=1.0)\n    for step in range(1, 20001):\n        loss = -(q * F.log_softmax(z, 0)).sum()\n        opt.zero_grad(); loss.backward(); opt.step()\n        if step in (100, 1000, 20000):\n            gap = (z[y] - z[1:].max()).item()\n            print(f\"{name:15s} 第 {step:5d} 步：正確類別的 logit 領先 {gap:6.3f}\")\n\nprint(\"label smoothing 的終點：ln(0.9001 / 0.0001) =\", round(torch.log(torch.tensor(0.9001 / 0.0001)).item(), 3))\n```\n\n```text\n平滑後的目標：正確類別 0.9001 ，其他類別 0.0001\none-hot         第   100 步：正確類別的 logit 領先 11.417\none-hot         第  1000 步：正確類別的 logit 領先 13.805\none-hot         第 20000 步：正確類別的 logit 領先 16.810\nlabel smoothing 第   100 步：正確類別的 logit 領先  9.105\nlabel smoothing 第  1000 步：正確類別的 logit 領先  9.105\nlabel smoothing 第 20000 步：正確類別的 logit 領先  9.105\nlabel smoothing 的終點：ln(0.9001 / 0.0001) = 9.105\n```\n\n用 one-hot 時，差距一直在長，訓練多久就推多遠。換成平滑的標籤，差距停在 9.105。這個數字可以直接算出來：損失最小時 $p = q'$，而 softmax 下兩個類別的 logit 差，等於它們機率比的對數，也就是 $\\ln(0.9001/0.0001)$。\n\n作者還給了另一個看法。把交叉熵展開：\n\n$$\nH(q', p) = (1-\\epsilon)\\,H(q, p) + \\epsilon\\, H(u, p)\n$$\n\n等於在原本的損失之外，多加一項懲罰：預測分布 $p$ 離均勻分布 $u$ 太遠，就要付出代價。\n\n在 ILSVRC 2012 上，加上 LSR 讓 top-1 錯誤率從 23.1% 降到 22.8%，top-5 從 6.3% 降到 6.1%。\n\n\n> [!NOTE]\n> \n> 四年後，Rafael Müller、Simon Kornblith 與 Geoffrey Hinton 在 NeurIPS 2019 的 [When Does Label Smoothing Help?](https://arxiv.org/abs/1906.02629) 回頭研究這個技巧。他們發現 label smoothing 能改善模型的校準，也會讓同一類訓練樣本的倒數第二層表示聚得更緊；代價是 logits 裡「這張圖和其他類別有多像」的資訊變少了，所以用 label smoothing 訓練的老師模型，做知識蒸餾的效果會差很多。\n\n\n### 訓練設定\n\n作者用 TensorFlow 的分散式訓練，50 個副本各跑在一張 NVIDIA Kepler GPU 上，每個副本的批次大小是 32，訓練 100 個 epoch。\n\n早期的實驗用 momentum，最好的模型改用 RMSProp（decay 0.9、$\\epsilon=1.0$）。學習率 0.045，每兩個 epoch 乘上 0.94。梯度裁剪設在 2.0，用來穩定訓練；評估時使用參數的移動平均。\n\n## 討論\n\n### 一項一項加上去\n\n| 網路 | Top-1 錯誤率 | Top-5 錯誤率 | 計算量（十億次運算） |\n| --- | ---: | ---: | ---: |\n| GoogLeNet | 29% | 9.2% | 1.5 |\n| BN-GoogLeNet | 26.8% | – | 1.5 |\n| BN-Inception | 25.2% | 7.8% | 2.0 |\n| Inception-v2 | 23.4% | – | 3.8 |\n| ＋ RMSProp | 23.1% | 6.3% | 3.8 |\n| ＋ Label Smoothing | 22.8% | 6.1% | 3.8 |\n| ＋ 分解 7×7 | 21.6% | 5.8% | 4.8 |\n| ＋ BN 輔助分類器 | **21.2%** | **5.6%** | 4.8 |\n\n*表：摘自原論文 Table 3。ILSVRC 2012 驗證集，單一裁切。Inception-v2 以下每一列都包含前面所有的改動。*\n\n這張表是累加的：每一列都在上一列的基礎上多加一項。最後一列「BN 輔助分類器」指輔助分類器裡的全連接層也加上 batch normalization，不只是卷積層。**加完所有改動的版本，作者稱為 Inception-v3**。\n\n幾個值得看的地方：\n\n- 光換成新的架構（Inception-v2 那一列），top-1 錯誤率就從 BN-Inception 的 25.2% 降到 23.4%，但計算量也從 2.0 漲到 3.8。\n- RMSProp 和 label smoothing 都不增加計算量，各自拿到 0.3 個百分點左右的 top-1 改善。\n- 把第一層 $7\\times7$ 拆成三層 $3\\times3$，計算量從 3.8 漲到 4.8，top-1 進步 1.2 個百分點，是後面幾項裡最大的一步。\n\n整體來看，Inception-v3 的計算量大約是 BN-Inception 的 2.4 倍、GoogLeNet 的 3.2 倍。\n\n\n> [!TIP]\n> \n> 這裡的命名有點亂。這篇論文把新架構叫 Inception-v2，所有改動加上去才叫 Inception-v3。可是隔年的 Inception-v4 論文回顧家族歷史時，把加了 batch normalization 的 BN-Inception 稱為 Inception-v2。之後看到「Inception-v2」，要先確認指的是哪一個。\n> \n> BN-Inception 的來源可以看我們的筆記：\n> \n> - **[[15.02] BatchNorm：批次標準化](/blog/papers/normalization/batchnorm)**\n\n\n所有評估都用 ILSVRC 2012 驗證集裡沒有被列入黑名單的 48,238 張影像。作者也試過用全部 50,000 張，top-5 錯誤率大約差 0.1 個百分點，top-1 大約差 0.2 個百分點。\n\n### 解析度低一點，差多少？\n\n偵測系統常常要分類一小塊影像，物體又小又模糊。一般認為輸入解析度越高越好，但作者指出，這裡混了兩件事：第一層感受野的解析度，以及模型本身的容量和計算量。如果只把輸入縮小、模型不動，等於用一個便宜很多的模型去解更難的問題。\n\n所以他們固定計算量，只改輸入解析度。輸入變小時，就拿掉前面的步幅或池化，讓後面的特徵圖大小維持差不多：\n\n| 感受野大小 | 調整方式 | Top-1 準確率 |\n| --- | --- | ---: |\n| $79\\times79$ | 第一層步幅 1，之後不池化 | 75.2% |\n| $151\\times151$ | 第一層步幅 1，之後最大池化 | 76.4% |\n| $299\\times299$ | 第一層步幅 2，之後最大池化 | 76.6% |\n\n*表：摘自原論文 Table 2，調整方式整理自第 9 節的實驗說明。*\n\n三個網路的計算量幾乎相同。解析度低的網路訓練得比較久，但最後的成績和 $299\\times299$ 相差不大：$151\\times151$ 只差 0.2 個百分點，$79\\times79$ 差 1.4 個百分點。\n\n作者由此建議，在 R-CNN 這類偵測流程裡，可以考慮為小物體準備專門的、低解析度但計算量不低的網路。\n\n### 和其他模型比\n\n單一模型、多個裁切的比較：\n\n| 網路 | 裁切數 | Top-1 錯誤率 | Top-5 錯誤率 |\n| --- | ---: | ---: | ---: |\n| GoogLeNet | 144 | – | 7.89% |\n| VGG | – | 24.4% | 6.8% |\n| BN-Inception | 144 | 22% | 5.82% |\n| PReLU | – | 21.59% | 5.71% |\n| Inception-v3 | 12 | 19.47% | 4.48% |\n| **Inception-v3** | **144** | **18.77%** | **4.2%** |\n\n*表：摘自原論文 Table 4 的部分列。*\n\n多個模型集成的比較：\n\n| 網路 | 模型數 | 裁切數 | Top-1 錯誤率 | Top-5 錯誤率 |\n| --- | ---: | ---: | ---: | ---: |\n| VGGNet | 2 | – | 23.7% | 6.8% |\n| GoogLeNet | 7 | 144 | – | 6.67% |\n| PReLU | – | – | – | 4.94% |\n| BN-Inception | 6 | 144 | 20.1% | 4.9% |\n| **Inception-v3** | **4** | **144** | **17.2%** | **3.58%** |\n\n*表：摘自原論文 Table 5。Inception-v3 的 3.58% 是測試集結果，其餘來自驗證集。*\n\n結論裡，作者拿 He 等人的 PReLU 網路比較：Inception-v3 的 top-5 和 top-1 錯誤率相對降低了 25% 和 14%，計算量卻便宜六倍，參數也少了至少五倍（作者標明是估計值）。四個模型的集成，top-5 錯誤率大約是 2014 年 GoogLeNet 冠軍集成的一半。\n\n## 結論\n\n這篇論文讀起來更像一本設計筆記。Table 3 一項一項累加，讓每個改動的貢獻都看得到；四條設計原則，作者也坦白標成還需要驗證的經驗法則。\n\n最後整理一下這篇留下的零件：\n\n1. **大卷積核拆成小的**：$5\\times5$ 換成兩層 $3\\times3$，$n\\times n$ 換成 $1\\times n$ 接 $n\\times1$。\n2. **縮小特徵圖時，卷積和池化並排**，避免資訊被卡住。\n3. **輔助分類器的作用更像正則化**。\n4. **Label smoothing**，讓模型別對答案太有把握。\n\n如果只能帶走一個，大概就是 label smoothing：它和架構無關，加幾行程式就能用，[ConvNeXt](/blog/papers/classic-cnns/convnext) 的訓練配方裡也有它。下一版的 Inception 就要和 ResNet 碰面了，我們[下一篇](/blog/papers/classic-cnns/inception-v4)接著看。\n","imageSizes":{"/content/papers/assets/c87d3d6fa9ea76d954eba2570f702150eca32d62c7cdb3d724075a4be9a63080.png":{"width":419,"height":358},"/content/papers/assets/26d9fd5f020cc9ce53cac89b03dbc710d155db812e4745d2e1c47a456faa3b1a.png":{"width":293,"height":401},"/content/papers/assets/d7b13cfd7a93816701d9571a2e87bd67983a5e6ffe9a7b93cbcf40e82db76a2f.png":{"width":623,"height":824},"/content/papers/assets/1475f4de3132dd0d1dbd081ddc453fb140796cb802987fa051a70356070b1b41.png":{"width":625,"height":539},"/content/papers/assets/9d6b75a1dd143d0b517f52adf42c4fe794cb400e3276a8109561db2277fb2fb6.png":{"width":635,"height":365}}}
