{"notes":[{"id":"classic-cnns/cam","category":"classic-cnns","legacyPath":"","legacySlug":"","legacyPaths":[],"title":"CAM","subtitle":"模型在看哪裡？","author":"Z. Yuan","paperDate":"2015-12-14","publishedOn":"2026-01-05","world":"external/cam","paperTitle":"Learning Deep Features for Discriminative Localization","paperUrl":"https://arxiv.org/abs/1512.04150","bibliography":{"title":"Learning Deep Features for Discriminative Localization","authors":["Bolei Zhou","Aditya Khosla","Agata Lapedriza","Aude Oliva","Antonio Torralba"],"url":"https://arxiv.org/abs/1512.04150","pdfUrl":"https://arxiv.org/pdf/1512.04150v1","codeUrl":null,"preprint":{"id":"1512.04150","submittedOn":"2015-12-14","url":"https://arxiv.org/abs/1512.04150"},"publication":null,"citation":"@misc{classiccnnscam2015,\n  title = {{Learning Deep Features for Discriminative Localization}},\n  author = {Bolei Zhou and Aditya Khosla and Agata Lapedriza and Aude Oliva and Antonio Torralba},\n  year = {2015},\n  eprint = {1512.04150},\n  archivePrefix = {arXiv},\n  url = {https://arxiv.org/abs/1512.04150}\n}\n","citationPath":"/content/papers/citations/classic-cnns/cam.2ce837236f9d.bib"},"thumbnail":{"src":"/content/papers/assets/c3c6af7f1943634784331ca03a55efc3e68a7714d936d953a14f11b0828d9cf8.png","width":1372,"height":615},"locale":"zh-hant","path":"/content/papers/zh-hant/classic-cnns/cam.b0cd5bb57b0b.md","headings":[{"id":"定義問題","text":"定義問題","depth":2},{"id":"解決問題","text":"解決問題","depth":2},{"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/nin","relation":"referenced","topic":""},{"id":"classic-cnns/zfnet","relation":"referenced","topic":""},{"id":"classic-cnns/resnet","relation":"referenced","topic":""}]},{"id":"classic-cnns/nin","category":"classic-cnns","legacyPath":"","legacySlug":"","legacyPaths":[],"title":"NiN","subtitle":"一乘一的伏筆","author":"Z. Yuan","paperDate":"2013-12-16","publishedOn":"2025-09-24","world":"external/network-in-network","paperTitle":"Network In Network","paperUrl":"https://arxiv.org/abs/1312.4400","bibliography":{"title":"Network In Network","authors":["Min Lin","Qiang Chen","Shuicheng Yan"],"url":"https://arxiv.org/abs/1312.4400","pdfUrl":"https://arxiv.org/pdf/1312.4400v3","codeUrl":null,"preprint":{"id":"1312.4400","submittedOn":"2013-12-16","url":"https://arxiv.org/abs/1312.4400"},"publication":null,"citation":"@misc{classiccnnsnin2013,\n  title = {{Network In Network}},\n  author = {Min Lin and Qiang Chen and Shuicheng Yan},\n  year = {2013},\n  eprint = {1312.4400},\n  archivePrefix = {arXiv},\n  url = {https://arxiv.org/abs/1312.4400}\n}\n","citationPath":"/content/papers/citations/classic-cnns/nin.db58639ac47c.bib"},"thumbnail":{"src":"/content/papers/assets/8024fc245eb852a2c0cd34b59c18c680b92766c33d621b934dbf102c1cacda13.png","width":896,"height":330},"locale":"zh-hant","path":"/content/papers/zh-hant/classic-cnns/nin.9892cb25b0b4.md","headings":[{"id":"定義問題","text":"定義問題","depth":2},{"id":"解決問題","text":"解決問題","depth":2},{"id":"在每個區塊上跑一個小-mlp","text":"在每個區塊上跑一個小 MLP","depth":3},{"id":"把全連接層換成平均","text":"把全連接層換成平均","depth":3},{"id":"整個網路","text":"整個網路","depth":3},{"id":"討論","text":"討論","depth":2},{"id":"cifar-10-與-cifar-100","text":"CIFAR-10 與 CIFAR-100","depth":3},{"id":"svhn-與-mnist","text":"SVHN 與 MNIST","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":"classic-cnns/resnet","relation":"referenced","topic":""},{"id":"classic-cnns/cam","relation":"referenced","topic":""}]},{"id":"classic-cnns/zfnet","category":"classic-cnns","legacyPath":"","legacySlug":"","legacyPaths":[],"title":"ZFNet","subtitle":"黑盒子裡的風景","author":"Z. Yuan","paperDate":"2013-11-12","publishedOn":"2025-09-06","world":"external/zfnet","paperTitle":"Visualizing and Understanding Convolutional Networks","paperUrl":"https://arxiv.org/abs/1311.2901","bibliography":{"title":"Visualizing and Understanding Convolutional Networks","authors":["Matthew D Zeiler","Rob Fergus"],"url":"https://arxiv.org/abs/1311.2901","pdfUrl":"https://arxiv.org/pdf/1311.2901v3","codeUrl":null,"preprint":{"id":"1311.2901","submittedOn":"2013-11-12","url":"https://arxiv.org/abs/1311.2901"},"publication":null,"citation":"@misc{classiccnnszfnet2013,\n  title = {{Visualizing and Understanding Convolutional Networks}},\n  author = {Matthew D Zeiler and Rob Fergus},\n  year = {2013},\n  eprint = {1311.2901},\n  archivePrefix = {arXiv},\n  url = {https://arxiv.org/abs/1311.2901}\n}\n","citationPath":"/content/papers/citations/classic-cnns/zfnet.6d4dd35e9f91.bib"},"thumbnail":{"src":"/content/papers/assets/6c45d745e8a2f4b60cc45bea1029353e303d5e3bbee1e62f438c71874fddf883.png","width":1200,"height":1329},"locale":"zh-hant","path":"/content/papers/zh-hant/classic-cnns/zfnet.5180edea6fef.md","headings":[{"id":"定義問題","text":"定義問題","depth":2},{"id":"解決問題","text":"解決問題","depth":2},{"id":"反向走一遍卷積網路","text":"反向走一遍卷積網路","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":3},{"id":"討論","text":"討論","depth":2},{"id":"imagenet-2012","text":"ImageNet 2012","depth":3},{"id":"拆掉哪幾層影響最大","text":"拆掉哪幾層影響最大？","depth":3},{"id":"換一個資料集","text":"換一個資料集","depth":3},{"id":"越高層越好用嗎","text":"越高層越好用嗎？","depth":3},{"id":"結論","text":"結論","depth":2}],"anchorAliases":{},"guide":null,"relatedReading":[{"id":"classic-cnns/alexnet","relation":"referenced","topic":""},{"id":"classic-cnns/vgg","relation":"referenced","topic":""},{"id":"classic-cnns/resnet","relation":"referenced","topic":""}]},{"id":"classic-cnns/resnet","category":"classic-cnns","legacyPath":"classic-cnns/1512-resnet","legacySlug":"1512-resnet","legacyPaths":[],"title":"ResNet","subtitle":"卷積網路 100 層","author":"Z. Yuan","paperDate":"2015-12-10","publishedOn":"2024-08-08","paperTitle":"Deep Residual Learning for Image Recognition","paperUrl":"https://arxiv.org/abs/1512.03385","bibliography":{"title":"Deep Residual Learning for Image Recognition","authors":["Kaiming He","Xiangyu Zhang","Shaoqing Ren","Jian Sun"],"url":"https://arxiv.org/abs/1512.03385","pdfUrl":"https://arxiv.org/pdf/1512.03385","codeUrl":null,"preprint":{"id":"1512.03385","submittedOn":"2015-12-10","url":"https://arxiv.org/abs/1512.03385"},"publication":{"venue":"CVPR","year":2016,"kind":"conference","url":"https://doi.org/10.1109/cvpr.2016.90"},"citation":"@misc{classiccnnsresnet2015,\n  title = {{Deep Residual Learning for Image Recognition}},\n  author = {Kaiming He and Xiangyu Zhang and Shaoqing Ren and Jian Sun},\n  year = {2015},\n  eprint = {1512.03385},\n  archivePrefix = {arXiv},\n  url = {https://arxiv.org/abs/1512.03385}\n}\n","citationPath":"/content/papers/citations/classic-cnns/resnet.cf4014e8baae.bib"},"thumbnail":{"src":"/content/papers/assets/b8fe87fe757249ea6d7bb667fef3196754b9f80e28bf842a69b540ca94585d08.jpg","width":1224,"height":408},"locale":"zh-hant","path":"/content/papers/zh-hant/classic-cnns/resnet.859f62e9e37d.md","headings":[{"id":"定義問題","text":"定義問題","depth":2},{"id":"解決問題","text":"解決問題","depth":2},{"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":"resnet-18-vs-resnet-34","text":"ResNet-18 vs ResNet-34","depth":3},{"id":"更深的瓶頸架構","text":"更深的瓶頸架構","depth":3},{"id":"在-imagenet-上的表現","text":"在 ImageNet 上的表現","depth":3},{"id":"結論","text":"結論","depth":2}],"anchorAliases":{},"guide":null,"relatedReading":[{"id":"classic-cnns/vgg","relation":"background","topic":"如何訓練更深的卷積網路"},{"id":"classic-cnns/densenet","relation":"next","topic":"如何訓練更深的卷積網路"}]}],"text":"一個只看過類別標籤的分類網路，知道物體在哪裡嗎？\n\nMIT 的 Bolei Zhou 等人在前一年的研究裡發現，答案多半是肯定的：用場景分類訓練出來的卷積網路，各層卷積單元的行為很像物體偵測器，雖然訓練時沒有人告訴它物體在哪。可是這份能力到了全連接層就不見了。卷積層的輸出還保留空間位置，攤平送進全連接層之後，「哪裡」和「是什麼」就混在一起，分不開了。\n\n2015 年 12 月，同一組人（Bolei Zhou、Aditya Khosla、Agata Lapedriza、Aude Oliva、Antonio Torralba）放出這篇論文，後來發表在 CVPR 2016。他們把目光放在一個已經存在的零件上：NiN 提出、GoogLeNet 也用了的全域平均池化。\n\n\n> [!TIP]\n> \n> 全域平均池化的來歷，以及 NiN 最後一層特徵圖的樣子，可以先看我們的筆記：\n> \n> - **[[13.12] NiN：一乘一的伏筆](/blog/papers/classic-cnns/nin)**\n\n\n## 定義問題\n\n這篇論文處理的是**弱監督物體定位**：訓練時只有影像層級的類別標籤，測試時卻要框出物體的位置。\n\n當時已經有幾種做法。有的把影像一塊一塊遮住，看哪裡被遮掉時反應掉最多；有的把多示例學習和卷積特徵結合；有的在大量重疊的小區塊上各跑一次網路。這些方法不是端到端訓練，而且要跑很多次前向傳播，很難用在大規模資料上。\n\n最接近的是 Oquab 等人的方法：用全域**最大**池化定位物體。它只能找到物體邊界上的一個點，說不出物體的範圍。\n\n另一條相關的研究是視覺化卷積網路。[ZFNet](/blog/papers/classic-cnns/zfnet) 用反卷積看每個單元在找什麼樣式，Zhou 等人自己的前作則發現場景網路裡有物體偵測器；這些研究都只分析卷積層，跳過了全連接層。\n\n作者想做的是：網路只要跑一次前向傳播，就能說出它是根據影像的哪些區域，判斷出這個類別。\n\n## 解決問題\n\n### 把分數拆回空間\n\n作者用的網路結構和 NiN、GoogLeNet 類似：前面大多是卷積層，最後一層卷積之後做全域平均池化，接一層全連接，再接 softmax。\n\n設 $f_k(x, y)$ 是最後一層卷積第 $k$ 個單元在位置 $(x, y)$ 的激活。全域平均池化把每張特徵圖壓成一個數：\n\n$$\nF_k = \\sum_{x,y} f_k(x, y)\n$$\n\n論文這裡直接寫成加總，省略了除以位置數；差一個常數，不影響後面的推導。\n\n類別 $c$ 的分數，是這些數的加權和：\n\n$$\nS_c = \\sum_k w_k^c F_k\n$$\n\n$w_k^c$ 是全連接層的權重，代表第 $k$ 張特徵圖對類別 $c$ 有多重要。作者把 softmax 的偏置設成 0，說它對分類幾乎沒有影響。\n\n接下來是整篇論文的關鍵。把 $F_k$ 代進去，交換兩個加總的順序：\n\n$$\nS_c = \\sum_k w_k^c \\sum_{x,y} f_k(x, y) = \\sum_{x,y} \\sum_k w_k^c f_k(x, y)\n$$\n\n內層的 $\\sum_k w_k^c f_k(x, y)$ 還帶著位置 $(x, y)$。作者把它定義成類別 $c$ 的**類別激活圖**（class activation map，CAM）：\n\n$$\nM_c(x, y) = \\sum_k w_k^c f_k(x, y)\n$$\n\n於是 $S_c = \\sum_{x,y} M_c(x, y)$。類別分數就是 CAM 上所有位置的總和，$M_c(x, y)$ 直接說明了位置 $(x, y)$ 對這個分數貢獻多少。\n\n換句話說，分類時先平均、再加權；CAM 把順序倒過來，先加權、留著空間不平均。我們用小例子驗證：\n\n```python\nimport torch\n\ntorch.manual_seed(0)\nK, C = 4, 3                                   # 4 張特徵圖、3 個類別\nf = torch.relu(torch.randn(K, 7, 7))          # 最後一層卷積的輸出：4 × 7 × 7\nw = torch.randn(C, K)                         # GAP 後面的全連接層：每個類別一組 4 個權重\n\n# 分類：先平均，再加權\nscores = w @ f.mean(dim=(1, 2))               # [3]\n\n# CAM：先加權，保留空間\ncams = torch.einsum('ck,khw->chw', w, f)      # [3, 7, 7]\n\nprint(\"分類分數：      \", scores)\nprint(\"每張 CAM 的平均：\", cams.mean(dim=(1, 2)))\nprint(cams.shape)\n```\n\n```text\n分類分數：       tensor([-1.0399, -0.8521, -0.5210])\n每張 CAM 的平均： tensor([-1.0399, -0.8521, -0.5210])\ntorch.Size([3, 7, 7])\n```\n\n兩組數字完全一樣。CAM 沒有用到任何新的參數，也不需要再跑一次網路，只是把已經學好的全連接權重，「投影」回最後一層卷積的特徵圖上。\n\n[![上半部是網路：一張男孩抱著狗的照片，經過一連串卷積層，最後一層卷積的多張特徵圖經過 GAP，以權重 w1、w2 到 wn 連到 Australian terrier 這個類別。下半部標題是 Class Activation Mapping：w1、w2、wn 分別乘上對應的特徵圖再相加，得到一張疊在原圖上的熱力圖，最亮的位置在狗身上](/content/papers/assets/c3c6af7f1943634784331ca03a55efc3e68a7714d936d953a14f11b0828d9cf8.png)](/content/papers/assets/c3c6af7f1943634784331ca03a55efc3e68a7714d936d953a14f11b0828d9cf8.png)\n\n*原論文 Figure 2，取自 [**v1 PDF 第 3 頁**](https://arxiv.org/pdf/1512.04150v1#page=3)。預測的類別分數被映射回前一層卷積，產生類別激活圖。*\n\n圖的下半部就是 $M_c$ 的計算。每張特徵圖各自偵測某種視覺樣式：有的亮在狗的頭部，有的亮在下方的身體；乘上「Australian terrier」這個類別的權重再加起來，就是這個類別的熱力圖。最後一層卷積的解析度很低（論文裡是 $13\\times13$ 或 $14\\times14$），把 CAM 放大到輸入影像的大小，就能看出影像上的哪些區域和這個類別最相關。\n\n同一張影像，換一個類別，就換一組權重，CAM 也跟著不同：\n\n[![左上是一張夜間圓頂建築的照片，標題為 dome。其餘五格是預測前五名類別的 CAM 與分數：palace 0.459 亮在下方橫向的宮殿主體；dome 0.195 亮在上方的圓頂；church 0.146、altar 0.091、monastery 0.051 的亮點集中在建築的左下角與尖塔一帶](/content/papers/assets/5feae5d21639fe423e9457b6eee11d7c4357e0fab4014dac2dd2482a810f0c45.png)](/content/papers/assets/5feae5d21639fe423e9457b6eee11d7c4357e0fab4014dac2dd2482a810f0c45.png)\n\n*原論文 Figure 4，取自 [**v1 PDF 第 4 頁**](https://arxiv.org/pdf/1512.04150v1#page=4)。真實類別是 dome（圓頂），其餘五格是預測前五名的 CAM，每格上方是類別與分數。*\n\npalace（宮殿）亮在下方平平的建築主體，dome 亮在上方的圓頂。網路判斷兩個類別時看的是同一張圖的不同地方。\n\n### 平均和最大，差在哪裡\n\n既然 Oquab 等人用的是全域最大池化，作者特別解釋了為什麼要用平均。\n\n他們的直覺是：取平均時，要讓分數變高，最好的辦法是找出物體**所有**有辨識度的部分，因為任何一處低的激活都會拉低平均；取最大值時，只有最強的那個位置算數，其他位置高低都沒有影響。\n\n這個差別在反向傳播時看得最清楚：\n\n```python\nimport torch\n\ntorch.manual_seed(0)\nx = torch.rand(1, 1, 4, 4, requires_grad=True)\n\nx.mean().backward()                           # 全域平均池化\nprint(\"GAP 的梯度：\\n\", x.grad[0, 0])\n\nx.grad = None\nx.amax().backward()                           # 全域最大池化\nprint(\"GMP 的梯度：\\n\", x.grad[0, 0])\n```\n\n```text\nGAP 的梯度：\n tensor([[0.0625, 0.0625, 0.0625, 0.0625],\n        [0.0625, 0.0625, 0.0625, 0.0625],\n        [0.0625, 0.0625, 0.0625, 0.0625],\n        [0.0625, 0.0625, 0.0625, 0.0625]])\nGMP 的梯度：\n tensor([[0., 0., 0., 0.],\n        [0., 0., 0., 1.],\n        [0., 0., 0., 0.],\n        [0., 0., 0., 0.]])\n```\n\n平均池化把梯度平均分給 16 個位置，每個位置都會被訓練；最大池化只把梯度送給最大的那一格，其他 15 格這一步什麼都學不到。後面的實驗會檢查這個直覺在定位上是否成立。\n\n### 讓最後一層的解析度高一點\n\n作者拿 AlexNet、VGGnet、GoogLeNet 三個網路來改：拿掉最後的全連接層，換成 GAP 再接一層全連接的 softmax。\n\n他們發現，GAP 前最後一層卷積的空間解析度越高，定位能力越好。作者把這個解析度稱為 mapping resolution。為了提高它，他們還多刪了幾層：\n\n- **AlexNet**：刪掉 conv5 之後的所有層，得到 $13\\times13$。\n- **VGGnet**：刪掉 conv5-3 之後的所有層，得到 $14\\times14$。\n- **GoogLeNet**：刪掉 inception4e 之後的所有層，得到 $14\\times14$。\n\n每個網路再加一層 $3\\times3$、步幅 1、補零 1、1024 個單元的卷積，接 GAP 與 softmax，然後在 ILSVRC 的 130 萬張訓練影像上微調 1000 類分類。得到的網路分別叫 AlexNet-GAP、VGGnet-GAP、GoogLeNet-GAP。作者在註腳提到，從頭訓練的結果也差不多。\n\n### 從熱力圖到框\n\nILSVRC 的定位評估要的是一個框。作者用的方法很簡單：\n\n1. 把 CAM 放大到影像大小。\n2. 留下數值超過最大值 20% 的區域。\n3. 取最大的那塊連通區域，畫出它的外接框。\n\n我們拿一張假的 $14\\times14$ CAM 走一次。左邊有一塊大的反應，右上角有一塊小的：\n\n```python\nimport torch\nimport torch.nn.functional as F\nfrom scipy import ndimage\n\n# 一張 14×14 的 CAM：左邊一塊大的反應，右上角一塊小的\nyy, xx = torch.meshgrid(torch.arange(14.), torch.arange(14.), indexing='ij')\ncam = 1.0 * torch.exp(-((yy - 8) ** 2 / 6 + (xx - 4) ** 2 / 4)) \\\n    + 0.6 * torch.exp(-((yy - 2) ** 2 + (xx - 11) ** 2) / 1.5)\n\n# 1. 放大回輸入影像的大小\ncam = F.interpolate(cam[None, None], size=(224, 224), mode='bilinear', align_corners=False)[0, 0]\n\n# 2. 留下超過最大值 20% 的區域\nmask = (cam > 0.2 * cam.max()).numpy()\n\n# 3. 找最大的連通區域，取外接框\nlabels, n = ndimage.label(mask)\nsizes = ndimage.sum(mask, labels, range(1, n + 1))\nlargest = labels == (sizes.argmax() + 1)\nrows, cols = largest.any(axis=1).nonzero()[0], largest.any(axis=0).nonzero()[0]\n\nprint(\"連通區域數：\", n, \"，各自的像素數：\", sizes.astype(int).tolist())\nprint(\"框（x0, y0, x1, y1）：\", cols[0], rows[0], cols[-1], rows[-1])\n```\n\n```text\n連通區域數： 2 ，各自的像素數： [1344, 6552]\n框（x0, y0, x1, y1）： 30 85 113 186\n```\n\n右上角那塊也超過門檻，但面積小，最後的框只圍住左邊的大區域。這也看得出這個方法的限制：同一張圖有兩個物體時，只會框出其中一個。top-5 的定位評估，則是對預測前五名的類別各做一次。\n\n## 討論\n\n### 拿掉全連接層，分類變差多少？\n\n| 網路 | Top-1 錯誤率 | Top-5 錯誤率 |\n| --- | ---: | ---: |\n| AlexNet | 42.6 | 19.5 |\n| AlexNet-GAP | 51.1 | 26.3 |\n| AlexNet\\*-GAP | 44.9 | 20.9 |\n| VGGnet | 31.2 | 11.4 |\n| VGGnet-GAP | 33.4 | 12.2 |\n| GoogLeNet | 31.9 | 11.3 |\n| GoogLeNet-GAP | 35.0 | 13.2 |\n| GoogLeNet-GMP | 35.6 | 13.9 |\n| NIN | 41.9 | 19.6 |\n\n*表：摘自原論文 Table 1，ILSVRC 驗證集，單位為百分比；列的順序重新排過，方便和原本的網路對照。*\n\nVGGnet 和 GoogLeNet 拿掉幾層之後，top-1 錯誤率分別多了 2.2 和 3.1 個百分點，top-5 都多了不到 2 個百分點。AlexNet 受影響最大，top-1 從 42.6% 掉到 51.1%；作者在 GAP 前多加兩層卷積，得到的 AlexNet\\*-GAP 就和原本的 AlexNet 差不多了。GAP 和 GMP 在分類上的表現也相近，這和預期一致。\n\n分類不能差太多，因為定位的評估要求類別和框都對。\n\n### 弱監督定位\n\n| 方法 | Top-1 錯誤率 | Top-5 錯誤率 |\n| --- | ---: | ---: |\n| **GoogLeNet-GAP** | **56.40** | **43.00** |\n| VGGnet-GAP | 57.20 | 45.14 |\n| GoogLeNet-GMP | 57.78 | 45.26 |\n| GoogLeNet | 60.09 | 49.34 |\n| AlexNet\\*-GAP | 63.75 | 49.53 |\n| Backprop on GoogLeNet | 61.31 | 50.55 |\n| Backprop on VGGnet | 61.12 | 51.46 |\n| AlexNet-GAP | 67.19 | 52.16 |\n| Backprop on AlexNet | 65.17 | 52.64 |\n| NIN | 65.47 | 54.19 |\n\n*表：摘自原論文 Table 2，ILSVRC 驗證集的定位錯誤率，依 top-5 排序。Backprop 指用 Simonyan 等人的反向傳播顯著圖取代 CAM。*\n\n幾個比較：\n\n- **CAM 對上反向傳播**：在 GoogLeNet 和 VGGnet 上，CAM 的 top-5 錯誤率比反向傳播低了 6 個百分點以上；AlexNet 上兩者接近（52.16 對 52.64），top-1 反而是反向傳播好一點。\n- **GoogLeNet-GAP 對上 GoogLeNet**：原本的 GoogLeNet 分類比較好，定位卻輸給刪過層的 GoogLeNet-GAP。作者認為原因是原本的 GoogLeNet 最後一層只有 $7\\times7$，解析度太低。\n- **GAP 對上 GMP**：分類差不多，定位上 GAP 的 top-5 錯誤率低了 2.26 個百分點，支持前面平均池化的直覺。\n\n[![左右兩組。a) 四個例子，各有一張原圖與一張 CAM：美洲短吻鱷、迷宮、喜樂蒂牧羊犬、蚱蜢；原圖上綠色是標註的框，紅色是從 CAM 推出的框，兩者大致重疊。b) 上排兩個例子是 GoogLeNet-GAP 對雪地摩托車與圍裙的定位，熱力圖集中在物體上；下排兩個例子是 AlexNet 反向傳播的結果，熱力圖是零散的點，推出的框偏大](/content/papers/assets/dce42d560109e416d7229359699d2bca63f7ec9a74374b2d62fce387c9bbed22.png)](/content/papers/assets/dce42d560109e416d7229359699d2bca63f7ec9a74374b2d62fce387c9bbed22.png)\n\n*原論文 Figure 6，取自 [**v1 PDF 第 6 頁**](https://arxiv.org/pdf/1512.04150v1#page=6)。a) GoogLeNet-GAP 的定位例子；b) 上排兩例是 GoogLeNet-GAP，下排兩例是 AlexNet 的反向傳播。綠框是標註，紅框是從熱力圖推出的框。*\n\n右邊的對照很直觀：反向傳播的顯著圖是一片散開的亮點，閾值切下去之後框得太大；CAM 的熱區集中，框也比較貼近物體。\n\n在測試集上，作者換了一個挑框的策略：前兩名的類別各取一個緊的框和一個鬆的框，第三名取一個鬆的框；這個啟發式做法是在驗證集上調出來的。\n\n| 方法 | 監督方式 | Top-5 測試錯誤率 |\n| --- | --- | ---: |\n| GoogLeNet-GAP（啟發式挑框） | 弱監督 | **37.1** |\n| GoogLeNet-GAP | 弱監督 | 42.9 |\n| Backprop | 弱監督 | 46.4 |\n| GoogLeNet | 全監督 | 26.7 |\n| OverFeat | 全監督 | 29.9 |\n| AlexNet | 全監督 | 34.2 |\n\n*表：摘自原論文 Table 3，ILSVRC 測試集。*\n\n37.1% 已經接近全監督的 AlexNet（34.2%），而 GoogLeNet-GAP 訓練時沒有看過任何一個框。作者也承認差距還很大：同樣的 GoogLeNet 架構，全監督可以做到 26.7%。\n\n### 換到其他任務\n\n作者還想知道，這種會定位的特徵能不能直接拿去用在別的資料集。做法是固定 GoogLeNet-GAP，在 GAP 的輸出上訓練一個線性 SVM，再用 SVM 的權重取代原本的 softmax 權重來算 CAM。\n\n當成一般的影像特徵，GoogLeNet-GAP 在 SUN397、MIT Indoor67、Caltech256 等八個資料集上，和原本 GoogLeNet 平均池化層的特徵表現相近，大多明顯好過 AlexNet 的 fc7。\n\n細分類的 CUB-200-2011 鳥類資料集比較有意思。它有 200 種鳥、5,994 張訓練影像、5,794 張測試影像，還附了鳥的框。\n\n| 方法 | 訓練／測試用到的標註 | 準確率 |\n| --- | --- | ---: |\n| GoogLeNet-GAP，整張影像 | 無 | 63.0% |\n| GoogLeNet-GAP，CAM 推出的框 | 無 | 67.8% |\n| GoogLeNet-GAP，標註的框 | 框 | 70.5% |\n| PANDA R-CNN | 框＋部位 | 76.4% |\n\n*表：摘自原論文 Table 4 的部分列。*\n\n用 CAM 先把鳥框出來，再從框裡重新抽特徵，準確率從 63.0% 升到 67.8%，沒有用到任何標註。CAM 推出的框，在 IoU 0.5 的標準下有 41.0% 是對的；隨機猜的機率是 5.5%。細分類的差別常常只在某些細節上，先把注意力集中到鳥身上，幫助很明顯。\n\n最後一組實驗是「找樣式」：給一群有共同概念的影像，看 CAM 會不會亮在那個概念上。其中一個例子和文字偵測有關：\n\n[![上排六張街景店面照片，下排是對應的 CAM。熱區都落在店家招牌的文字上，例如遮陽棚上的店名、門口上方的招牌](/content/papers/assets/89c6a4410389b611bdcc7e40a414223d52106f89494e17ede86188b4552d73a0.png)](/content/papers/assets/89c6a4410389b611bdcc7e40a414223d52106f89494e17ede86188b4552d73a0.png)\n\n*原論文 Figure 11，取自 [**v1 PDF 第 8 頁**](https://arxiv.org/pdf/1512.04150v1#page=8)。弱監督的文字偵測器：網路沒有用文字或任何框訓練，CAM 仍然亮在文字上。*\n\n正樣本是 SVT 資料集中 350 張有文字的 Google 街景影像，負樣本是 SUN 資料集裡隨機抽的戶外場景。只靠「這張圖有沒有字」的二元標籤，CAM 就落在招牌的文字上。論文另外也試了場景中的關鍵物體、短語概念的定位，以及解釋視覺問答模型的答案。\n\n作者還做了一件事：用 GAP 後面的權重，把最後一層卷積的單元依照對某個類別的重要性排序，直接看出哪些單元在判斷這個類別時最重要。例如對 lakeland terrier 這種㹴犬重要的單元，偵測的是狗臉和身上的毛；對客廳重要的，是沙發、桌子和壁爐。\n\n## 結論\n\nCAM 本身只有一行公式：把分類層的權重乘回最後一層特徵圖。它能成立，是因為 GAP 之後只接一層線性層，類別分數可以拆回每個位置。這也是它的前提：網路得是「卷積、GAP、一層全連接」的結構，其他網路要先改架構、重新微調，分類準確率可能因此下降。\n\n實驗上，CAM 在 ILSVRC 的弱監督定位得到 37.1% 的 top-5 錯誤率，和全監督的 AlexNet 相近，但離同架構的全監督 GoogLeNet 還有一段距離。一張圖只取最大連通區域的框，也讓它比較適合一張圖一個主要物體的情況。\n\nCAM 對架構的限制，很快有人處理：2016 年 10 月的 [Grad-CAM](https://arxiv.org/abs/1610.02391) 用梯度來決定每張特徵圖的權重，不必改成 GAP 架構，也不用重新訓練。\n\nCAM 的門檻很低：只要網路尾端是 GAP 接一層全連接，幾行程式就能算出來。現在常見的 [ResNet](/blog/papers/classic-cnns/resnet) 剛好就是這個結構，想知道模型在看哪裡，隨手就能畫一張。\n\n不過別把熱力圖看得太認真。它標出的是最有辨識度的部位，像動物的頭，常常只涵蓋物體的一部分。\n","imageSizes":{"/content/papers/assets/c3c6af7f1943634784331ca03a55efc3e68a7714d936d953a14f11b0828d9cf8.png":{"width":1372,"height":615},"/content/papers/assets/5feae5d21639fe423e9457b6eee11d7c4357e0fab4014dac2dd2482a810f0c45.png":{"width":672,"height":462},"/content/papers/assets/dce42d560109e416d7229359699d2bca63f7ec9a74374b2d62fce387c9bbed22.png":{"width":1381,"height":304},"/content/papers/assets/89c6a4410389b611bdcc7e40a414223d52106f89494e17ede86188b4552d73a0.png":{"width":669,"height":235}}}
