{"notes":[{"id":"classic-cnns/xception","category":"classic-cnns","legacyPath":"","legacySlug":"","legacyPaths":[],"title":"Xception","subtitle":"Inceptionの果て","author":"Z. Yuan","paperDate":"2016-10-07","publishedOn":"2024-03-20","world":"external/xception","paperTitle":"Xception: Deep Learning with Depthwise Separable Convolutions","paperUrl":"https://arxiv.org/abs/1610.02357","bibliography":{"title":"Xception: Deep Learning with Depthwise Separable Convolutions","authors":["François Chollet"],"url":"https://arxiv.org/abs/1610.02357","pdfUrl":"https://arxiv.org/pdf/1610.02357v3","codeUrl":null,"preprint":{"id":"1610.02357","submittedOn":"2016-10-07","url":"https://arxiv.org/abs/1610.02357"},"publication":{"venue":"CVPR","year":2017,"kind":"conference","url":"https://openaccess.thecvf.com/content_cvpr_2017/html/Chollet_Xception_Deep_Learning_CVPR_2017_paper.html"},"citation":"@misc{classiccnnsxception2016,\n  title = {{Xception: Deep Learning with Depthwise Separable Convolutions}},\n  author = {François Chollet},\n  year = {2016},\n  eprint = {1610.02357},\n  archivePrefix = {arXiv},\n  url = {https://arxiv.org/abs/1610.02357}\n}\n","citationPath":"/content/papers/citations/classic-cnns/xception.3a6fa7188c36.bib"},"thumbnail":{"src":"/content/papers/assets/b56e8b540dd5a4cb9856460b3e47a6e3e624df308ab08b70809438075caf5f0a.png","width":917,"height":538},"locale":"ja","path":"/content/papers/ja/classic-cnns/xception.f8b2466408bf.md","headings":[{"id":"問題の定義","text":"問題の定義","depth":2},{"id":"問題の解決","text":"問題の解決","depth":2},{"id":"inceptionモジュールを別の角度から見る","text":"Inceptionモジュールを別の角度から見る","depth":3},{"id":"とことん分ける","text":"とことん分ける","depth":3},{"id":"スペクトルのもう一方の端","text":"スペクトルのもう一方の端","depth":3},{"id":"xception","text":"Xception","depth":3},{"id":"考察","text":"考察","depth":2},{"id":"imagenet","text":"ImageNet","depth":3},{"id":"jft","text":"JFT","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/inception-v1","relation":"referenced","topic":""},{"id":"classic-cnns/inception-v3","relation":"referenced","topic":""},{"id":"lightweight/mobilenet-v1","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":"ja","path":"/content/papers/ja/classic-cnns/inception-v1.e67514209915.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":"classic-cnns/inception-v3","category":"classic-cnns","legacyPath":"","legacySlug":"","legacyPaths":[],"title":"Inception-v3","subtitle":"大きなカーネルの退場","author":"Z. Yuan","paperDate":"2015-12-02","publishedOn":"2023-11-15","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":{"venue":"CVPR","year":2016,"kind":"conference","url":"https://openaccess.thecvf.com/content_cvpr_2016/html/Szegedy_Rethinking_the_Inception_CVPR_2016_paper.html"},"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":"ja","path":"/content/papers/ja/classic-cnns/inception-v3.c3a126bf40a9.md","headings":[{"id":"問題の定義","text":"問題の定義","depth":2},{"id":"問題の解決","text":"問題の解決","depth":2},{"id":"55を33の2層に分ける","text":"5×5を3×3の2層に分ける","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":"lightweight/mobilenet-v1","category":"lightweight","legacyPath":"lightweight/1704-mobilenet-v1","legacySlug":"1704-mobilenet-v1","legacyPaths":[],"title":"MobileNet-V1","subtitle":"深層分離可能な畳み込みの発揚者","author":"Z. Yuan","paperDate":"2017-04-17","publishedOn":"2024-06-25","paperTitle":"MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications","paperUrl":"https://arxiv.org/abs/1704.04861","bibliography":{"title":"MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications","authors":["Andrew G. Howard","Menglong Zhu","Bo Chen","Dmitry Kalenichenko","Weijun Wang","Tobias Weyand","Marco Andreetto","Hartwig Adam"],"url":"https://arxiv.org/abs/1704.04861","pdfUrl":"https://arxiv.org/pdf/1704.04861","codeUrl":null,"preprint":{"id":"1704.04861","submittedOn":"2017-04-17","url":"https://arxiv.org/abs/1704.04861"},"publication":null,"citation":"@misc{lightweightmobilenetv12017,\n  title = {{MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications}},\n  author = {Andrew G. Howard and Menglong Zhu and Bo Chen and Dmitry Kalenichenko and Weijun Wang and Tobias Weyand and Marco Andreetto and Hartwig Adam},\n  year = {2017},\n  eprint = {1704.04861},\n  archivePrefix = {arXiv},\n  url = {https://arxiv.org/abs/1704.04861}\n}\n","citationPath":"/content/papers/citations/lightweight/mobilenet-v1.e9c4c525fed4.bib"},"thumbnail":{"src":"/content/papers/assets/b8390bd8e0f21f1b1eaa6b2a5d4a1b0d9eba36e2fe5dd0878830d757839d30f1.jpg","width":1064,"height":1080},"locale":"ja","path":"/content/papers/ja/lightweight/mobilenet-v1.c46f4d7012f5.md","headings":[{"id":"問題の定義","text":"問題の定義","depth":2},{"id":"問題の解決","text":"問題の解決","depth":2},{"id":"深さ方向分離畳み込み","text":"深さ方向分離畳み込み","depth":3},{"id":"ネットワークアーキテクチャ","text":"ネットワークアーキテクチャ","depth":2},{"id":"トレーニングのテクニック","text":"トレーニングのテクニック","depth":2},{"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":"lightweight/mobilenet-v2","relation":"next","topic":"モバイル向けの効率的な畳み込み"}]}],"text":"2016年の時点で、Inceptionはすでに第4世代まで出ていました。GoogLeNetから、BNを加えたInception-v2、畳み込みを分解したInception-v3、そして残差接続を取り入れたInception-ResNetまでです。どの世代もImageNetで上位に入りましたが、モジュールは世代を追うごとに複雑になり、分岐、チャネル数、カーネルの形を一つずつ調整しなければなりませんでした。\n\n\n> [!TIP]\n> \n> Inceptionシリーズは、先にこの2本を読んでおくとよいでしょう。\n> \n> - **[[14.09] GoogLeNet：またの名を Inception-V1](/blog/papers/classic-cnns/inception-v1)**\n> - **[[15.12] Inception-v3：大きなカーネルの退場](/blog/papers/classic-cnns/inception-v3)**\n\n\nFrançois CholletはKerasの作者で、当時はGoogleにいました。彼は、Inceptionモジュールがなぜ効くのか、通常の畳み込みと何が違うのか、そしてInceptionの先にどこへ進めるのかを突き止めたいと考えました。\n\nこの論文がその答えです。\n\n## 問題の定義\n\n通常の畳み込み層では、各カーネルは立体的なフィルタで、幅と高さに加えてチャネルという次元を持ちます。256チャネルの入力を見る$3\\times3$カーネルには$3\\times3\\times256$個の重みがあり、同じ位置の異なるチャネル間の関係（チャネル間の相関）と、隣り合う位置どうしの関係（空間的な相関）を**同時に**扱います。\n\nInceptionモジュールは、この二つを分けて処理します。まずいくつかの$1\\times1$畳み込みでチャネル間の関係を扱い、入力を3〜4個の小さな空間に射影してから、それぞれの小さな空間の中で$3\\times3$や$5\\times5$の畳み込みによって空間的な関係を扱います。\n\n著者はこの設計の背後にある考え方を**Inception仮説**と呼んでいます。チャネル間の相関と空間的な相関は十分に独立していて、分けて扱うほうが一緒に扱うより良い、という仮説です。\n\n「一部を分ける」のが効くなら、もっと徹底的に分けたらどうなるでしょうか？\n\n## 問題の解決\n\n### Inceptionモジュールを別の角度から見る\n\n著者はまずInceptionモジュールを単純化し、$3\\times3$畳み込みの一種類だけを残して、平均プーリングの分岐を取り除きます。残る3本の分岐は、どれも先に$1\\times1$、次に$3\\times3$です。\n\nこの3つの$1\\times1$畳み込みは同じ入力を見ているので、出力チャネルの多い1つの$1\\times1$畳み込みにまとめられます。まとめた後は、3つの$3\\times3$畳み込みが、その出力チャネルのうちそれぞれ一区画ずつを処理する形になります。\n\n[![単純化したInceptionモジュールの等価な形。下から上へ、Inputが1つの1x1 convに入り、出力チャネル（Output channels）が波括弧で3区画に分けられ、各区画にそれぞれ3x3 convが1つずつつながり、最後にConcat](/content/papers/assets/9fc3c2cfbe884067fa627f67d745ee0ab6eaf44ed451260083932eb5fa0742e0.png)](/content/papers/assets/9fc3c2cfbe884067fa627f67d745ee0ab6eaf44ed451260083932eb5fa0742e0.png)\n\n*原論文Figure 3。[**v3 PDFの2ページ**](https://arxiv.org/pdf/1610.02357v3#page=2)から抜粋。単純化したInceptionモジュールと厳密に等価な書き方です。*\n\nこの二つの書き方は本当に同じなのでしょうか？64チャネルの入力で試してみましょう。3本の分岐は、それぞれ$1\\times1$（64から32）と$3\\times3$を行います。もう一方は、64から96への$1\\times1$畳み込み1つに、「96チャネルを3グループに分け、各グループで個別に$3\\times3$を行う」畳み込みを続けたもので、重みは3本の分岐からそのまま移します。\n\n```python\nimport torch\nimport torch.nn as nn\n\ntorch.manual_seed(0)\nx = torch.randn(1, 64, 8, 8)                       # 64チャネルの入力\n\n# Figure 2：3本の分岐、それぞれ先に1×1、次に3×3\npw = [nn.Conv2d(64, 32, 1, bias=False) for _ in range(3)]\nsp = [nn.Conv2d(32, 32, 3, padding=1, bias=False) for _ in range(3)]\ny2 = torch.cat([s(p(x)) for p, s in zip(pw, sp)], dim=1)\n\n# Figure 3：大きな1×1畳み込み1つの後、96個の出力チャネルを3区画に分け、それぞれ3×3を行う\nbig_pw = nn.Conv2d(64, 96, 1, bias=False)\ngrouped = nn.Conv2d(96, 96, 3, padding=1, groups=3, bias=False)\nwith torch.no_grad():\n    big_pw.weight.copy_(torch.cat([p.weight for p in pw]))\n    grouped.weight.copy_(torch.cat([s.weight for s in sp]))\ny3 = grouped(big_pw(x))\n\nprint(\"出力の形状：\", tuple(y2.shape), tuple(y3.shape))\nprint(\"二つの書き方の最大の差：\", (y2 - y3).abs().max().item())\n```\n\n```text\n出力の形状： (1, 96, 8, 8) (1, 96, 8, 8)\n二つの書き方の最大の差： 7.748603820800781e-07\n```\n\n差は浮動小数点の丸め誤差だけです。PyTorchの`groups=3`はまさに「チャネルを3区画に分け、各区画で個別に畳み込む」ことなので、この単純化したInceptionモジュールは、実は$1\\times1$畳み込み1つと、3グループに分けた$3\\times3$畳み込み1つでできています。\n\nこう見ると、単純化したInceptionモジュールで調整できる数字は、チャネルをいくつの区画に分けるかの一つだけです。\n\n### とことん分ける\n\n区画が多いほど、各区画のチャネルは少なくなります。極端まで分けると、各区画にはチャネルが1つしか残らず、どの出力チャネルにも専用の$3\\times3$畳み込みが1つずつ付きます。\n\n[![極端版のInceptionモジュール。下から上へ、Inputが1つの1x1 convに入り、出力チャネルが多数の区画に分けられ、各区画に3x3が1つだけつながり、最後にConcat](/content/papers/assets/b56e8b540dd5a4cb9856460b3e47a6e3e624df308ab08b70809438075caf5f0a.png)](/content/papers/assets/b56e8b540dd5a4cb9856460b3e47a6e3e624df308ab08b70809438075caf5f0a.png)\n\n*原論文Figure 4。[**v3 PDFの2ページ**](https://arxiv.org/pdf/1610.02357v3#page=2)から抜粋。「極端な」版のInceptionモジュールで、$1\\times1$畳み込みの出力チャネルごとに空間畳み込みが1つずつあります。*\n\n96チャネルに固定して、区画数を1から96まで増やしたとき、$3\\times3$の層の重みがどう変わるかを見てみましょう。\n\n```python\nimport torch.nn as nn\n\nC = 96\nfor groups in (1, 3, 4, 32, 96):\n    conv = nn.Conv2d(C, C, 3, padding=1, groups=groups, bias=False)\n    print(f\"groups={groups:>2}：各区画{C // groups:>2}チャネル、3×3畳み込みのパラメータ{conv.weight.numel():>6,}、重みの形状{tuple(conv.weight.shape)}\")\n```\n\n```text\ngroups= 1：各区画96チャネル、3×3畳み込みのパラメータ82,944、重みの形状(96, 96, 3, 3)\ngroups= 3：各区画32チャネル、3×3畳み込みのパラメータ27,648、重みの形状(96, 32, 3, 3)\ngroups= 4：各区画24チャネル、3×3畳み込みのパラメータ20,736、重みの形状(96, 24, 3, 3)\ngroups=32：各区画 3チャネル、3×3畳み込みのパラメータ 2,592、重みの形状(96, 3, 3, 3)\ngroups=96：各区画 1チャネル、3×3畳み込みのパラメータ   864、重みの形状(96, 1, 3, 3)\n```\n\n重みの形状の2番目の数字が、各カーネルから見える入力チャネルの数です。`groups=1`は通常の畳み込みで、各カーネルが96チャネルすべてを見ます。`groups=96`では、各カーネルは1チャネルしか見ず、空間方向の$3\\times3$だけが残ります。\n\n著者は、この並び全体を一本のスペクトルとして捉えます。一方の端は通常の畳み込み（前に$1\\times1$が付く）で、区画は1つだけです。もう一方の端はチャネルごとに1区画です。Inceptionモジュールはその中間にあり、数百のチャネルを3〜4区画に分けています。\n\n### スペクトルのもう一方の端\n\n著者は、スペクトルのもう一方の端にある極端なモジュールが、すでに存在していた**深さ方向分離畳み込み**（depthwise separable convolution）とほぼ同じだと指摘します。これは二つのステップに分かれます。\n\n1. **depthwise畳み込み**：入力チャネルごとに個別に空間畳み込みを行い、チャネル間でのやり取りはありません。\n2. **pointwise畳み込み**：$1\\times1$畳み込みで、前のステップの出力を新しいチャネル空間に射影します。\n\nTensorFlowやKerasでseparable convolutionと呼ばれているのがこれです。画像処理の分野にもseparable convolutionという名前があり、$7\\times7$を$1\\times7$と$7\\times1$に分けるような空間方向の分解を指します。Inception-v3でも使われていましたが、二つを混同しないようにしてください。\n\n\n> [!NOTE]\n> \n> 深さ方向分離畳み込みは、この論文が発明したものではありません。著者は論文の中で出どころを説明しています。Laurent Sifreが2013年にGoogle Brainでインターンをしていたときに開発し、AlexNetに使って、正解率はわずかに上がり、収束はずっと速くなり、モデルもずっと小さくなりました。GoogLeNetとBN-Inceptionの最初の層でも使われています。同じころ、GoogleのAndrew Howardはこれを使ってモバイル端末向けのMobileNetsを作っていました。私たちの[MobileNet-V1](/blog/papers/lightweight/mobilenet-v1)のノートも参照してください。\n\n\n「極端な」Inceptionモジュールと深さ方向分離畳み込みには、まだ小さな違いが二つあります。\n\n1. **順序**。深さ方向分離畳み込みは先にdepthwise、次に$1\\times1$を行いますが、Inceptionは先に$1\\times1$を行います。著者はこれは重要ではないと考えています。ネットワークは層を積み重ねたものなので、前のモジュールの$1\\times1$に次のモジュールのdepthwiseが続き、順序の違いは最初と最後だけだからです。\n2. **あいだに非線形性があるかどうか**。Inceptionでは二つのステップの後にどちらもReLUが付きますが、深さ方向分離畳み込みでは通常、二つのステップのあいだに活性化関数を入れません。著者は、この点は影響があるかもしれないと考え、実験で確かめることにしています。\n\n### Xception\n\nInception仮説が「チャネル間の関係と空間的な関係は部分的に分けられる」というものなら、著者はいっそもっと強い仮説を立て、二つは**完全に**分けられると考えます。この仮説にもとづくネットワークは、すべて深さ方向分離畳み込みで組み立てられ、Extreme Inceptionから名前をとってXceptionと呼ばれます。\n\n[![Xceptionのアーキテクチャ図で、3列に分かれている。Entry flow：299x299x3の画像が、Conv 32 3x3 stride 2、Conv 64 3x3を通り、続いて3つのモジュールがある。各モジュールは2層のSeparableConv（128、256、728チャネル）とMaxPooling 3x3 stride 2からなり、横にConv 1x1 stride 2のショートカットがあって、19x19x728を出力する。Middle flow：ReLUとSeparableConv 728の組が3層あり、外側に恒等ショートカットが1本あって、8回繰り返される。Exit flow：SeparableConv 728、SeparableConv 1024、MaxPoolingで、横にConv 1x1 stride 2のショートカット。続いてSeparableConv 1536、SeparableConv 2048、GlobalAveragePoolingで2048次元のベクトルを得て、オプションの全結合層を経て、最後にLogistic regression](/content/papers/assets/8b7417d8bf8ba80d77cf08ea108b8a7df9b994d3f4f08922532004a3ce0f7f69.png)](/content/papers/assets/8b7417d8bf8ba80d77cf08ea108b8a7df9b994d3f4f08922532004a3ce0f7f69.png)\n\n*原論文Figure 5。[**v3 PDFの5ページ**](https://arxiv.org/pdf/1610.02357v3#page=5)から抜粋。すべてのConvとSeparableConvの後にはBNが続きます（図では省略）。SeparableConvのdepthwise部分ではチャネルを増やしません。*\n\nデータは左から右へ三つの段を進みます。entry flowは$299\\times299$の画像から始まり、最初の2層は通常の畳み込みです。続く3つのモジュールがそれぞれ特徴マップを半分に縮めてチャネルを広げ、最後は$19\\times19\\times728$になります。middle flowは同じモジュールを8回繰り返し、大きさは変わりません。exit flowはもう一度縮小してチャネルを2048まで増やし、グローバル平均プーリングの後に分類層が続きます。\n\nネットワーク全体は36層の畳み込みからなり、14個のモジュールに分かれています。最初と最後のモジュールを除き、どのモジュールにも外側に残差接続が1本あります。縮小が不要なモジュールは恒等ショートカットを使い、縮小が必要なものはショートカット上にストライド2の$1\\times1$畳み込みを置きます。\n\nInception-v3と比べると、この図はずっと単純で、深さ方向分離畳み込みと残差接続を1層ずつ積み重ねただけです。著者によれば、Kerasで書けば30〜40行で済みます。図のとおりにPyTorchで組んでみましょう。\n\n```python\nimport torch\nimport torch.nn as nn\n\nclass SeparableConv(nn.Sequential):\n    \"\"\"チャネルごとの3×3畳み込みの後に1×1畳み込み。二つのあいだに活性化関数はなく、最後にBNを付ける\"\"\"\n    def __init__(self, cin, cout):\n        super().__init__(\n            nn.Conv2d(cin, cin, 3, padding=1, groups=cin, bias=False),   # depthwise\n            nn.Conv2d(cin, cout, 1, bias=False),                          # pointwise\n            nn.BatchNorm2d(cout))\n\nclass Block(nn.Module):\n    def __init__(self, cin, widths, relu_first=True, downsample=True):\n        super().__init__()\n        layers, c = [], cin\n        for i, w in enumerate(widths):\n            if relu_first or i > 0:\n                layers.append(nn.ReLU())\n            layers.append(SeparableConv(c, w))\n            c = w\n        if downsample:\n            layers.append(nn.MaxPool2d(3, 2, padding=1))\n            self.shortcut = nn.Sequential(nn.Conv2d(cin, c, 1, 2, bias=False), nn.BatchNorm2d(c))\n        else:\n            self.shortcut = nn.Identity()\n        self.body = nn.Sequential(*layers)\n\n    def forward(self, x):\n        return self.body(x) + self.shortcut(x)\n\ndef conv_bn_relu(cin, cout, stride):\n    return nn.Sequential(nn.Conv2d(cin, cout, 3, stride, bias=False), nn.BatchNorm2d(cout), nn.ReLU())\n\nentry = nn.Sequential(conv_bn_relu(3, 32, 2), conv_bn_relu(32, 64, 1),\n                      Block(64, [128, 128], relu_first=False), Block(128, [256, 256]), Block(256, [728, 728]))\nmiddle = nn.Sequential(*[Block(728, [728, 728, 728], downsample=False) for _ in range(8)])\nexit_ = nn.Sequential(Block(728, [728, 1024]),\n                      SeparableConv(1024, 1536), nn.ReLU(), SeparableConv(1536, 2048), nn.ReLU(),\n                      nn.AdaptiveAvgPool2d(1), nn.Flatten(), nn.Linear(2048, 1000))\nmodel = nn.Sequential(entry, middle, exit_)\n\nx = torch.randn(1, 3, 299, 299)\nfor name, part in [(\"entry flow\", entry), (\"middle flow\", middle)]:\n    x = part(x)\n    print(f\"{name}の後：\", tuple(x.shape[1:]))\nprint(\"exit flowの後：\", tuple(exit_(x).shape[1:]))\n\nparams = sum(p.numel() for p in model.parameters())\nprint(f\"パラメータ数：{params:,}\")\n```\n\n```text\nentry flowの後： (728, 19, 19)\nmiddle flowの後： (728, 19, 19)\nexit flowの後： (1000,)\nパラメータ数：22,855,952\n```\n\nパラメータ数は、論文が報告する22,855,952とぴったり同じです。PyTorchには既製のseparable convolution層がないので、このように`groups=入力チャネル数`の$3\\times3$畳み込みに$1\\times1$畳み込みを続ければ十分です。Kerasには`SeparableConv2D`がそのまま用意されていて、Xception自体もKeras Applicationsに収録されています。\n\n図の細部と照らし合わせると、各SeparableConvの前にはReLU、後ろにはBNが置かれ、depthwiseとpointwiseのあいだには何も入りません。entry flowの最初の残差モジュールでは、最初のSeparableConvの前にReLUがありません。その前のConv 64にすでにReLUが付いているからです。exit flowの最後の2層は、ReLUが後ろに置かれています。\n\n## 考察\n\n著者はInception-v3と比べています。両者のパラメータ数はほぼ同じなので、差をモデルの容量のせいにはできないからです。比較は二つのデータセットで行います。\n\n- **ImageNet**：1000クラスの単一ラベル分類。\n- **JFT**：Google社内のデータセットで、3.5億枚を超える高解像度画像、17,000クラスからなり、1枚に複数のラベルが付くことがあります。評価には別の14,000枚のFastEval14kを使い、1枚あたり平均36.5個のラベルがあります。指標は上位100件の予測に対するMAP@100で、各クラスがソーシャルメディアでどれだけよく見られるかで重み付けしています。\n\n二つのネットワークは同じ学習設定を使っています。この設定はInception-v3のために入念に調整されたもので、著者はXception向けに別途調整していません。唯一の例外はweight decayで、Inception-v3の4e-5はXceptionには明らかに合わず、1e-5に変えています。すべてのモデルはNVIDIA K80 60枚で学習し、ImageNetは1回あたり約3日、JFTは1回あたり1か月以上かかり、しかも収束するまでは学習させていません。\n\n### ImageNet\n\n| ネットワーク | Top-1正解率 | Top-5正解率 |\n| --- | ---: | ---: |\n| VGG-16 | 0.715 | 0.901 |\n| ResNet-152 | 0.770 | 0.933 |\n| Inception-v3 | 0.782 | 0.941 |\n| **Xception** | **0.790** | **0.945** |\n\n*表：原論文Table 1から抜粋。単一モデル、シングルクロップでの検証セットの結果です。Inception-v3は補助分類器を使っていません。*\n\nXceptionはInception-v3より0.8ポイント高く、差は大きくありません。VGG-16とResNet-152は参考として載せているだけです。\n\n### JFT\n\n| ネットワーク | FastEval14k MAP@100 |\n| --- | ---: |\n| Inception-v3、全結合層なし | 6.36 |\n| Xception、全結合層なし | 6.70 |\n| Inception-v3、全結合層あり | 6.50 |\n| **Xception、全結合層あり** | **6.78** |\n\n*表：原論文Table 2から抜粋。3,000万イテレーション（約1か月）学習した後の結果です。「全結合層あり」は、分類層の前に4096次元の全結合層を2層加えたものです。*\n\nJFTでは差がずっと大きく、全結合層ありの版で相対的に4.3%向上しています。著者の説明では、Inception-v3はImageNetを中心に開発されたので、設計の段階でこのデータセットに過剰に適合しているのかもしれません。JFTは、どちらのネットワークも調整していないデータセットです。\n\n### パラメータはほぼ同じで、少し遅い\n\n| ネットワーク | パラメータ数 | 1秒あたりの学習ステップ数 |\n| --- | ---: | ---: |\n| Inception-v3 | 23,626,728 | 31 |\n| Xception | 22,855,952 | 28 |\n\n*表：原論文Table 3から抜粋。ImageNetでK80 60枚を使い、同期学習した結果です。*\n\n両者のパラメータ数の差は3.5%未満です。そのため著者は、Xceptionの改善は容量が大きくなったことによるものではなく、パラメータをより効率よく使っていることによるものだとしています。\n\n速度の面では、Xceptionはむしろ少し遅くなっています。depthwise畳み込みはパラメータも計算量も少ないものの、GPU上ではそれに見合った速度が出にくいのです。\n\n### 残差接続\n\n著者は、残差接続をすべて取り除いたXceptionも学習させています。ImageNetでは、残差なしの版は収束がずっと遅く、最終的な正解率もはっきり低くなりました。\n\n著者は、残差なしの版にも同じ学習設定を使ったので、そちらには少し不公平かもしれないと断っています。また、この結果が示すのは、残差接続が**このアーキテクチャにとって**重要だということだけだとも注意しています。別の実験として、VGG風のネットワークの畳み込みをすべて深さ方向分離畳み込みに置き換え、残差を一切使わないものも試しており、JFTで同じパラメータ数のInception-v3にやはり勝っています。\n\n### あいだに活性化関数を入れるべきか\n\n先ほど保留にした問いに戻りましょう。depthwiseとpointwiseのあいだに非線形性を入れるべきでしょうか？著者は、入れない、ReLUを入れる、ELUを入れる、の3通りを試しました。\n\n[![ImageNetの検証正解率を勾配降下のステップ数に対してプロットした学習曲線。赤のNo intermediate activationが最も速く上がり、最後は0.79近くに達する。緑のIntermediate ELUがそれに次ぎ、0.78前後で止まる。青のIntermediate ReLUが最も遅く、0.77前後で止まる](/content/papers/assets/c1da1e28d13c72c20287fa73c73e3e10c9dc4f735991c6f580191ede66fd1b5b.png)](/content/papers/assets/c1da1e28d13c72c20287fa73c73e3e10c9dc4f735991c6f580191ede66fd1b5b.png)\n\n*原論文Figure 10。[**v3 PDFの7ページ**](https://arxiv.org/pdf/1610.02357v3#page=7)から抜粋。SeparableConvのdepthwiseとpointwiseのあいだに異なる活性化関数を使ったときの学習曲線です。*\n\n赤線は活性化関数を何も入れないもので、収束が最も速く、最終的な正解率も最も高くなっています。ELUを入れた緑線は中間で、ReLUを入れた青線が最も悪くなりました。\n\nこれはInception-v3の論文の結果とは逆です。Inception-v3では、$5\\times5$を2層の$3\\times3$に分解したとき、あいだにReLUを入れたほうが良いという結果でした。著者の推測では、鍵は空間畳み込みが行われる特徴空間がどれだけ「厚い」かにあります。Inceptionモジュールでは各区画に数十から100以上のチャネルがあり、非線形性が役に立ちます。深さ方向分離畳み込みでは各区画にチャネルが1つしかないので、ReLUが負の値を切り捨てると、そのまま情報が失われるのかもしれません。\n\nその後のMobileNetV2は、ネットワークの中で最も狭い層からReLUを取り除きましたが、その理由も「低次元空間で非線形性をかけると情報が失われる」というものでした。続けて[MobileNet-V2](/blog/papers/lightweight/mobilenet-v2)を読んでみてください。\n\n## 結論\n\nXceptionはInceptionを別の角度から見直しました。単純化したInceptionモジュールは、$1\\times1$畳み込みにいくつかのグループに分けた$3\\times3$畳み込みを続けたものにすぎず、グループ数を1からチャネル数まで変えると、通常の畳み込みから深さ方向分離畳み込みへと移っていきます。Xceptionはまっすぐその果てまで進み、パラメータ数はInception-v3とほぼ同じで、ImageNetではやや良く、JFTではかなり良くなりました。\n\n名前はExtreme Inceptionなのに、速度のほうはちっともエクストリームではなく、1秒あたりの学習ステップ数はInception-v3より3つ少なくなっています。著者は当時、depthwise畳み込みの実装が最適化されれば逆転すると見込んでいました。ところが待っているうちに何年も過ぎ、[EfficientNetV2](/blog/papers/classic-cnns/efficientnet-v2)は結局、ネットワーク前半のdepthwise畳み込みを丸ごと置き換えてしまいました。\n\n果てが最善の位置なのかどうかは、著者自身も確信していません。論文の最後で、スペクトルの途中のどこかの点のほうが良いかもしれないと書いています。その1か月あまり後に出た[ResNeXt](/blog/papers/classic-cnns/resnext)は32グループに分けた畳み込みを使い、ちょうどその中間に位置しています。\n","imageSizes":{"/content/papers/assets/9fc3c2cfbe884067fa627f67d745ee0ab6eaf44ed451260083932eb5fa0742e0.png":{"width":917,"height":554},"/content/papers/assets/b56e8b540dd5a4cb9856460b3e47a6e3e624df308ab08b70809438075caf5f0a.png":{"width":917,"height":538},"/content/papers/assets/8b7417d8bf8ba80d77cf08ea108b8a7df9b994d3f4f08922532004a3ce0f7f69.png":{"width":2054,"height":1417},"/content/papers/assets/c1da1e28d13c72c20287fa73c73e3e10c9dc4f735991c6f580191ede66fd1b5b.png":{"width":946,"height":716}}}
