{"notes":[{"id":"classic-cnns/nfnet","category":"classic-cnns","legacyPath":"","legacySlug":"","legacyPaths":[],"title":"NFNet","subtitle":"BNのない日々","author":"Z. Yuan","paperDate":"2021-02-11","publishedOn":"2025-01-21","world":"external/nfnet","paperTitle":"High-Performance Large-Scale Image Recognition Without Normalization","paperUrl":"https://arxiv.org/abs/2102.06171","bibliography":{"title":"High-Performance Large-Scale Image Recognition Without Normalization","authors":["Andrew Brock","Soham De","Samuel L. Smith","Karen Simonyan"],"url":"https://arxiv.org/abs/2102.06171","pdfUrl":"https://arxiv.org/pdf/2102.06171v1","codeUrl":null,"preprint":{"id":"2102.06171","submittedOn":"2021-02-11","url":"https://arxiv.org/abs/2102.06171"},"publication":{"venue":"ICML","year":2021,"kind":"conference","url":"https://proceedings.mlr.press/v139/brock21a.html"},"citation":"@misc{classiccnnsnfnet2021,\n  title = {{High-Performance Large-Scale Image Recognition Without Normalization}},\n  author = {Andrew Brock and Soham De and Samuel L. Smith and Karen Simonyan},\n  year = {2021},\n  eprint = {2102.06171},\n  archivePrefix = {arXiv},\n  url = {https://arxiv.org/abs/2102.06171}\n}\n","citationPath":"/content/papers/citations/classic-cnns/nfnet.91baba59df96.bib"},"thumbnail":{"src":"/content/papers/assets/7552bff30433f4f33bec5edb2421acd94d61d452888dde6df17557778e8fb1c6.png","width":1004,"height":783},"locale":"ja","path":"/content/papers/ja/classic-cnns/nfnet.b4620c75dadb.md","headings":[{"id":"問題の定義","text":"問題の定義","depth":2},{"id":"batchnormは何をしてくれていたのか","text":"BatchNormは何をしてくれていたのか","depth":3},{"id":"平均シフトはどう見えるのか","text":"平均シフトはどう見えるのか","depth":3},{"id":"問題の解決","text":"問題の解決","depth":2},{"id":"まずnf-resnetを押さえておく","text":"まずNF-ResNetを押さえておく","depth":3},{"id":"適応的勾配クリッピング","text":"適応的勾配クリッピング","depth":3},{"id":"nfnetのアーキテクチャ","text":"NFNetのアーキテクチャ","depth":3},{"id":"考察","text":"考察","depth":2},{"id":"各変更の寄与","text":"各変更の寄与","depth":3},{"id":"bnを外すと本当に速いのか","text":"BNを外すと本当に速いのか","depth":3},{"id":"ほかのモデルと比べる","text":"ほかのモデルと比べる","depth":3},{"id":"事前学習してから微調整する","text":"事前学習してから微調整する","depth":3},{"id":"結論","text":"結論","depth":2}],"anchorAliases":{},"guide":null,"relatedReading":[{"id":"normalization/batchnorm","relation":"referenced","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":{"venue":"ICML","year":2015,"kind":"conference","url":"https://proceedings.mlr.press/v37/ioffe15.html"},"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":"ja","path":"/content/papers/ja/normalization/batchnorm.0bdafbaf4990.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":"正規化する軸の選び方"}]}],"text":"2015年以降、画像分類のネットワークにはほぼ必ずBatchNormが入っています。深いネットワークを学習しやすくし、大きな学習率を使えるようにして、おまけに多少の正則化の効果まであります。便利すぎて、その欠点を改めて考える人はほとんどいませんでした。\n\n\n> [!TIP]\n> \n> BatchNormは、先に私たちのノートで読めます。\n> \n> - **[[15.02] BatchNorm：バッチ正規化](/blog/papers/normalization/batchnorm)**\n\n\n実は欠点は少なくありません。バッチ統計量を計算する必要があり、メモリも時間も食います。学習時はバッチ統計、推論時は移動平均を使うので、両者で振る舞いが食い違います。さらに、同じバッチ内のサンプルどうしが影響し合います。これがいちばん厄介な点です。バッチが小さすぎると効果が落ち、分散学習ではトラブルが起きやすく、対照学習ではモデルがバッチ統計を使って答えを盗み見ないよう、特別な対処まで必要になります。\n\nDeepMindのAndrew Brock、Soham De、Samuel L. Smith、Karen Simonyanは、BatchNormを丸ごと取り除こうと考えました。彼らは前の論文で、正規化層を使わないNF-ResNetをすでに作り、同クラスのBN-ResNetに正解率で追いついています。この論文が取り組むのは、残った二つの問題です。\n\n## 問題の定義\n\n### BatchNormは何をしてくれていたのか\n\nBatchNormを取り除くには、まずそれが何をしているのかを知り、一つずつ代わりを見つけなければなりません。著者らは四つにまとめています。\n\n1. **残差分岐の出力を小さく抑える**。BNを残差分岐に置くと、初期化の段階では分岐の出力が比較的小さく、信号は主にショートカットを通るので、学習初期の勾配が安定します。\n2. **平均シフトをなくす**。ReLUやGELUといった活性化関数の出力は、平均が0ではありません。層を重ねるにつれて、異なるサンプルの特徴がどんどん似ていきます。BNは各層で平均を0に引き戻します。\n3. **正則化の効果**。バッチ統計量にはノイズがあり、学習中にノイズを加えるのと少し似ています。\n4. **大バッチ学習を可能にする**。BNは損失曲面をなめらかにし、より大きな学習率を使えるようにします。そうして初めて、大バッチ学習に意味が出てきます。\n\n前の論文のNF-ResNetは、初期化と重みの標準化で最初の二つに対処し、DropoutとStochastic Depthを加えて三つ目を補いました。残った問題は二つです。バッチが4096以上になると学習が不安定になること、そして最高の成績でもまだEfficientNetに追いつけないことです。\n\n### 平均シフトはどう見えるのか\n\n二つ目は少し抽象的なので、まず正規化がないと何が起きるかを見てみましょう。互いに無相関なランダムサンプルを64個用意し、ReLUとHe初期化の重み1層を通す処理を20層重ねて、サンプル間の平均cosine類似度を測ります。もう一組はNF-ResNetのやり方に置き換えたもので、これは後で説明します。\n\n```python\nimport math\nimport torch\nimport torch.nn.functional as F\n\ntorch.manual_seed(0)\nx = torch.randn(64, 512)                      # 互いに無相関な64個のサンプル、それぞれ512個の特徴\n\ndef ws(W):\n    \"\"\"Scaled Weight Standardization：各出力ユニットの重みから平均を引き、std·√Nで割る\"\"\"\n    N = W.shape[1]\n    return (W - W.mean(1, keepdim=True)) / (W.std(1, unbiased=False, keepdim=True) * math.sqrt(N))\n\ndef mean_cos(h):\n    \"\"\"異なるサンプル間の平均cosine類似度\"\"\"\n    h = F.normalize(h, dim=1)\n    sim = h @ h.T\n    return (sim.sum() - sim.diagonal().sum()).item() / (h.shape[0] * (h.shape[0] - 1))\n\ngamma = math.sqrt(2 / (1 - 1 / math.pi))      # ReLUのゲイン\nprint(f\"γ = {gamma:.4f}\")\nplain, std = x.clone(), x.clone()\nfor layer in range(1, 21):\n    W = torch.randn(512, 512)\n    plain = F.relu(plain) @ (W * math.sqrt(2 / 512)).T      # He初期化、正規化なし\n    std = (gamma * F.relu(std)) @ ws(W).T                   # 標準化した重み＋ゲイン\n    if layer in (1, 5, 10, 20):\n        print(f\"{layer:>2}層目｜He初期化：サンプル間の類似度 {mean_cos(plain):.2f}\"\n              f\"｜Scaled WS：類似度 {mean_cos(std):.2f}、分散 {std.var().item():.2f}\")\n```\n\n```text\nγ = 1.7129\n 1層目｜He初期化：サンプル間の類似度 0.31｜Scaled WS：類似度 0.00、分散 0.99\n 5層目｜He初期化：サンプル間の類似度 0.72｜Scaled WS：類似度 -0.00、分散 0.98\n10層目｜He初期化：サンプル間の類似度 0.87｜Scaled WS：類似度 0.00、分散 0.95\n20層目｜He初期化：サンプル間の類似度 0.96｜Scaled WS：類似度 0.00、分散 0.88\n```\n\n入力の64個のサンプルはもともと無相関でしたが、20層を通ると、He初期化の組の平均類似度は0.96に達し、ほぼすべてのサンプルが同じ姿になっています。原因は、ReLUの出力がすべて0以上で、どの層でも同じ正の平均値がすべてのサンプルに加わることです。論文が引用する研究によれば、このシフトのせいで、深いネットワークは初期化の時点で、すべてのサンプルに同じクラスを予測してしまいます。\n\n## 問題の解決\n\n### まずNF-ResNetを押さえておく\n\n右側の組で使っているのは、前の論文のNF-ResNetの二つの技法です。\n\n一つ目は**Scaled Weight Standardization**です。畳み込み層の各出力ユニットについて、重みからそのユニット自身の平均を引き、標準偏差と$\\sqrt{N}$で割ります。\n\n$$\n\\hat{W}_{ij}=\\frac{W_{ij}-\\mu_i}{\\sqrt{N}\\,\\sigma_i},\n$$\n\n$N$はfan-inです。平均を引くと、各出力ユニットの重みの合計は0になるので、活性化関数が持ち込む共通の正の値が打ち消されます。上で類似度がずっと0のままだったのは、このためです。\n\n二つ目は、活性化関数の後に掛けるゲイン$\\gamma$です。ReLUなら$\\gamma=\\sqrt{2/(1-1/\\pi)}$で、約1.71です。ReLUが負の値を切り捨てることで失われる分散を、ちょうど補います。二つを合わせると、各層の出力の分散はおおむね1に保たれます。20層後の0.88は1層ごとの小さなずれが積み重なったもので、もう一方の組でサンプルがほぼ同じものになってしまうのに比べれば、ずっと小さなものです。\n\n「各層でおおむね分散を保つ」分岐ができたので、NF-ResNetの残差ブロックは次のように書けます。\n\n$$\nh_{i+1}=h_i+\\alpha\\,f_i\\!\\left(h_i/\\beta_i\\right).\n$$\n\n$\\beta_i$は事前に計算しておいた入力の標準偏差で、分岐に入る信号はすべて分散1に縮められます。$\\alpha$は小さな定数（通常は0.2）で、各ブロックで分散をどれだけ増やすかを決めます。そのため主経路の分散は直接計算でき、ブロックを一つ通るたびに$\\alpha^2$ずつ増えます。12個のブロックを組んで確かめてみましょう。\n\n```python\nimport math\nimport torch\nimport torch.nn.functional as F\n\ntorch.manual_seed(0)\ngamma = math.sqrt(2 / (1 - 1 / math.pi))\n\ndef ws(W):\n    N = W.shape[1]\n    return (W - W.mean(1, keepdim=True)) / (W.std(1, unbiased=False, keepdim=True) * math.sqrt(N))\n\ndef branch(h):\n    \"\"\"残差分岐：「ゲイン付きReLU＋標準化した重み」を2層。出力の分散は入力とほぼ同じ\"\"\"\n    for _ in range(2):\n        h = (gamma * F.relu(h)) @ ws(torch.randn(512, 512)).T\n    return h\n\nalpha = 0.2\nh = torch.randn(4096, 512)\nexpected = 1.0\nfor i in range(1, 13):\n    beta = math.sqrt(expected)                # 事前に計算した入力の標準偏差\n    h = h + alpha * branch(h / beta)          # h_{i+1} = h_i + α·f(h_i / β_i)\n    expected += alpha ** 2                    # Var(h_{i+1}) = Var(h_i) + α²\n    if i in (1, 4, 8, 12):\n        print(f\"{i:>2}個目のブロックの後：予想される分散 {expected:.2f}、実際 {h.var().item():.2f}\")\n```\n\n```text\n 1個目のブロックの後：予想される分散 1.04、実際 1.04\n 4個目のブロックの後：予想される分散 1.16、実際 1.16\n 8個目のブロックの後：予想される分散 1.32、実際 1.32\n12個目のブロックの後：予想される分散 1.48、実際 1.48\n```\n\n実際の分散は予想と完全に一致しています。これがBatchNormの一つ目の機能の代わりになります。$\\alpha$が小さいので、信号は主にショートカットを通り、分岐は最初は小さな修正しかしません。特徴マップを縮小するブロックでは、ショートカットにもスケーリングした入力を渡し、分散は$1+\\alpha^2$から数え直しになります。さらに、各残差分岐の最後には0で初期化した学習可能なスカラー（SkipInit）があり、学習の始めには分岐全体がオフになっているのと同じです。\n\nここまでで、NF-ResNetはバッチ1024ならBN-ResNetに追いつけますが、バッチを大きくすると不安定になります。\n\n### 適応的勾配クリッピング\n\n大バッチ学習では大きな学習率を使うので、勾配が大きいと、パラメータが1ステップで遠くへ押し出されすぎることがあります。よくある解決策は勾配クリッピングです。\n\n$$\nG\\rightarrow\n\\begin{cases}\n\\lambda\\dfrac{G}{\\lVert G\\rVert} & \\text{if }\\lVert G\\rVert>\\lambda,\\\\\nG & \\text{otherwise.}\n\\end{cases}\n$$\n\n著者らは、これで確かにより大きなバッチまで持ちこたえられるものの、閾値$\\lambda$の調整が非常に難しいことに気づきました。モデルの深さ、バッチサイズ、学習率のどれかが変わるたびに、探し直さなければなりません。\n\n問題は、固定の閾値がパラメータ自体の大きさを考慮しないことです。同じ0.01の勾配でも、大きさ1の重みに加われば1%の変化にすぎませんが、大きさ0.01の重みに加われば丸ごとひっくり返ります。そこで著者らは、比率を見ることにしました。\n\n$$\n\\frac{\\lVert G^\\ell\\rVert_F}{\\lVert W^\\ell\\rVert_F},\n$$\n\nこの比率は、1回の更新で重みがどれくらいの割合変わるかをおおまかに表します。実際には層全体で1回計算するのではなく、**ユニット**単位、つまり重み行列の各行（畳み込みなら各出力チャネルと、その空間範囲）ごとに計算します。\n\n$$\nG_i^\\ell\\rightarrow\n\\begin{cases}\n\\lambda\\dfrac{\\lVert W_i^\\ell\\rVert_F^\\star}{\\lVert G_i^\\ell\\rVert_F}\\,G_i^\\ell & \\text{if }\\dfrac{\\lVert G_i^\\ell\\rVert_F}{\\lVert W_i^\\ell\\rVert_F^\\star}>\\lambda,\\\\[6pt]\nG_i^\\ell & \\text{otherwise.}\n\\end{cases}\n$$\n\n$\\lVert W_i\\rVert_F^\\star=\\max(\\lVert W_i\\rVert_F,\\epsilon)$、$\\epsilon=10^{-3}$で、0で初期化したパラメータの勾配がいつまでも0へクリップされるのを防ぎます。これがAdaptive Gradient Clipping（AGC）です。\n\nユニットが三つの小さな例で、どうクリップされるかを見てみましょう。\n\n```python\nimport torch\n\nW = torch.tensor([[1.0, 0.0, 0.0],\n                  [0.0, 0.1, 0.0],\n                  [0.0, 0.0, 2.0]])           # 3つの出力ユニット、重みの大きさはそれぞれ違う\nG = torch.tensor([[0.005, 0.0, 0.0],\n                  [0.0, 0.05, 0.0],\n                  [0.0, 0.0, 0.01]])          # 3行の勾配\n\nlam, eps = 0.01, 1e-3\nw_norm = W.norm(dim=1, keepdim=True).clamp(min=eps)\ng_norm = G.norm(dim=1, keepdim=True)\nratio = g_norm / w_norm\nclipped = torch.where(ratio > lam, G * (lam * w_norm / g_norm), G)\n\nfor i in range(3):\n    print(f\"ユニット{i}：‖W‖={w_norm[i].item():.2f}、‖G‖={g_norm[i].item():.3f}、比率 {ratio[i].item():.3f}\"\n          f\" → クリップ後 ‖G‖={clipped[i].norm().item():.4f}\")\nprint(\"全体の勾配ノルム：\", round(G.norm().item(), 4))\n```\n\n```text\nユニット0：‖W‖=1.00、‖G‖=0.005、比率 0.005 → クリップ後 ‖G‖=0.0050\nユニット1：‖W‖=0.10、‖G‖=0.050、比率 0.500 → クリップ後 ‖G‖=0.0010\nユニット2：‖W‖=2.00、‖G‖=0.010、比率 0.005 → クリップ後 ‖G‖=0.0100\n全体の勾配ノルム： 0.0512\n```\n\nクリップされたのはユニット1だけです。重みは0.1しかないのに勾配は0.05もあり、1ステップで半分も変わってしまうので、$\\lambda\\times0.1=0.001$まで抑えられました。ほかの二つのユニットは比率が閾値以下なので、そのままです。普通の全体クリッピングなら、三つのユニットが同じ係数でまとめて縮められ、本当に抑える必要のあるユニットが十分に抑えられるとは限りません。\n\n上の書き方は、timmの`timm.utils.agc.adaptive_clip_grad`と同じ結果になり、三つのユニットのクリップ後はそれぞれ0.005、0.001、0.01です。\n\n[![2枚の折れ線グラフ。(a)横軸はバッチサイズ（256〜4096）、縦軸はTop-1正解率。青線がBatchNorm、オレンジ線がNF-ResNet、緑線がNF-ResNet+AGCで、実線がResNet50、破線がResNet200。オレンジ線はバッチ2048を過ぎると急落し、緑線は終始、青線と同程度かそれより高い位置を保っている。(b)ResNet50の、さまざまなクリッピング閾値（0.01〜0.16）での正解率で、各線が一つのバッチサイズに対応する。バッチ4096の紫線は閾値0.02を過ぎると崩れている](/content/papers/assets/9c1e7cd2c8c545de3ebab245e654b0dd69b3921c4f0479f0e99131833bdfc5f2.png)](/content/papers/assets/9c1e7cd2c8c545de3ebab245e654b0dd69b3921c4f0479f0e99131833bdfc5f2.png)\n\n*原論文Figure 2。[**v1 PDFの4ページ**](https://arxiv.org/pdf/2102.06171v1#page=4)から抜粋。(a)AGCによって、NF-ResNetがより大きなバッチを使えるようになります。(b)クリッピング閾値$\\lambda$ごとの性能です。*\n\n左図のオレンジ線はAGCなしのNF-ResNetで、バッチが2048を超えると崩れます。AGCを加えた緑線は4096まで持ちこたえ、正解率はBatchNormの青線と同程度か、それ以上です。右図は閾値の比較です。バッチが大きいほど閾値を小さくする必要があり、バッチ4096で持ちこたえられるのは0.01と0.02だけです。\n\n著者らは、どの層をクリップする必要があるかも試しました。最後の全結合層はクリップしないほうが良く、最初の畳み込み層はクリップしなくても済むことが多い一方、4つのステージの重みは、バッチ4096ではすべてクリップしなければなりません。以降の実験では、最後の層を除くすべてのパラメータにAGCを使います。\n\n### NFNetのアーキテクチャ\n\nAGCを手にした著者らは、続いて新しいネットワークを設計します。今回の目標はFLOPsやパラメータ数ではなく、**TPUとGPUでの実際の学習速度**です。著者らは、EfficientNetはFLOPsがとても低いのに、学習速度はそれに見合って速くはならないと指摘します。EfficientNet-B0のFLOPsはResNet-50の10分の1しかないのに、GPUやTPUで学習すると同じくらい遅いのです。\n\n[![NFNetのbottleneckブロックの模式図。入力にまず1/βを掛け、1x1畳み込み、3x3畳み込み2つ、さらに1x1畳み込みを通り、αを掛けてからショートカットと足し合わされる。右側には各ステージの幅と深さが並ぶ。ResNetの幅は[256, 512, 1024, 2048]、NFNetの幅は[256, 512, 1536, 1536]。ResNetの深さは[3, 4, 6, 3]、[3, 4, 23, 3]…、NFNetの深さは[1, 2, 6, 3]にNを掛けたもの](/content/papers/assets/6dc27a9ccca4de619c057562ea6384aab3c095ddc08b22f475601ab03fcf03bb.png)](/content/papers/assets/6dc27a9ccca4de619c057562ea6384aab3c095ddc08b22f475601ab03fcf03bb.png)\n\n*原論文Figure 3。[**v1 PDFの5ページ**](https://arxiv.org/pdf/2102.06171v1#page=5)から抜粋。NFNetのbottleneckブロックと、ResNetとの幅・深さの違いです。*\n\n出発点はSE-ResNeXt-Dで、活性化関数をGELUに替え、さらに4か所を変えます。\n\n1. **グループ幅を128に固定**。グループを細かくするほどFLOPsは下がりますが、計算密度も下がるので、アクセラレータ上では実際には速くなりません。\n2. **深さの構成を[1, 2, 6, 3]に**。大きなモデルはこれにそのままNを掛け、たとえばF1は[2, 4, 12, 6]です。ResNetは伝統的に中央の2つのステージだけを深くしてきましたが、著者らはそれが最善のやり方ではないと考えています。\n3. **幅の構成を[256, 512, 1536, 1536]に**。容量を3番目のステージに集中させ、4番目のステージはやや縮めます。学習速度はほぼ変わりません。\n4. **ブロック内に$3\\times3$グループ畳み込みを1層追加**。図にある連続した二つの3x3がそれです。著者らは、FLOPsはほんの少ししか増えず、自分たちのアクセラレータでは学習時間にほとんど影響しないと述べています。\n\nモデルを大きくするときは深さと解像度だけを増やし、幅は増やしません。著者らは、幅を広げてもResNet系のバックボーンには効果が薄いことを見出しました。1段階上がるごとに学習時間はおよそ倍になり、Dropoutもそれに合わせて引き上げ、F0の0.2からF6の0.5までになります。BatchNormの暗黙の正則化がなくなるので、Dropoutのような明示的な正則化に頼らなければ、モデルはひどく過学習します。\n\n## 考察\n\n### 各変更の寄与\n\n| 設定 | F0 | F1 | F2 | F3 |\n| --- | ---: | ---: | ---: | ---: |\n| 出発点 | 80.4% | 81.7% | 82.0% | 82.3% |\n| ＋幅の変更 | 80.9% | 81.8% | 82.0% | 82.3% |\n| ＋2層目の$3\\times3$ | 81.3% | 82.2% | 82.4% | 82.7% |\n| ＋MixUp | 82.2% | 82.9% | 83.1% | 83.5% |\n| ＋RandAugment | 83.2% | 84.6% | 84.8% | 85.0% |\n| ＋CutMix | **83.6%** | **84.7%** | **85.1%** | **85.7%** |\n| 元の幅＋上記のデータ拡張 | 83.1% | 84.5% | 85.0% | 85.5% |\n\n*表：原論文Table 2から抜粋。ImageNetのtop-1正解率で、3つの乱数シードの平均です。360エポック学習、バッチ4096です。*\n\nアーキテクチャの二つの変更は、合わせて0.4〜0.9ポイントの改善です。本当に差をつけたのはデータ拡張で、RandAugmentだけで1〜1.7ポイントあります。こうした強いデータ拡張こそ元のNF-ResNetが耐えられなかったもので、AGCによって使えるようになりました。最後の行はResNet本来の幅の構成に戻したもので、四つのサイズすべてで悪くなっていて、幅の調整が確かに効いていることがわかります。\n\n著者らは、同じデータ拡張をEfficientNetにも適用しました。RandAugmentは効果がありましたが、層数を2より多くしても、さらにMixUpやCutMixを加えても、それ以上は良くなりませんでした。ここから著者らは、NFNetの進歩はデータ拡張だけによるものではないと考えています。\n\n### BNを外すと本当に速いのか\n\n同じアーキテクチャをBatchNormに戻して学習させたときの、正解率と1ステップあたりの学習時間は次のとおりです。\n\n| モデル | NF版 | BN版 |\n| --- | --- | --- |\n| F0 | 83.6%、73.3 ms | 83.4%、111.7 ms |\n| F1 | 84.7%、158.5 ms | 84.4%、258.0 ms |\n| F2 | 85.1%、295.8 ms | 85.1%、396.3 ms |\n\n*表：原論文Table 6から抜粋。ImageNetのtop-1正解率と、TPUv3での1ステップあたりの学習時間です。*\n\n正解率はほぼ同じで、NF版がわずかに上か互角です。一方、1ステップあたりの学習時間は25〜40%短くなっています。著者らはさらに、より大きなF4とF5はBatchNormにすると、AGCの有無にかかわらず学習が安定しなかったと述べ、メモリに収めるために使ったbfloat16が、バッチ統計量の計算と相性が悪いのだろうと推測しています。\n\n### ほかのモデルと比べる\n\n[![散布図に折れ線を重ねたグラフ。横軸はTPUv3での1ステップあたりの学習時間（秒）、縦軸はImageNetのTop-1正解率（80%〜87%）。赤の実線はNFNet-F0〜F5で、ほかのすべてのモデルの左上に位置する。青の破線はEfficientNet B2〜B7、緑はLambdaNet、オレンジはBoTNet、黒い点はDeiT。NFNet-F1の正解率は右端のEffNet-B7と同等だが、学習時間はずっと短い](/content/papers/assets/7552bff30433f4f33bec5edb2421acd94d61d452888dde6df17557778e8fb1c6.png)](/content/papers/assets/7552bff30433f4f33bec5edb2421acd94d61d452888dde6df17557778e8fb1c6.png)\n\n*原論文Figure 1。[**v1 PDFの1ページ**](https://arxiv.org/pdf/2102.06171v1#page=1)から抜粋。ImageNetの検証正解率とTPUv3での学習時間の関係で、単一モデル、シングルクロップです。*\n\n赤線は全体がほかのモデルの左上にあります。同じ学習時間なら、より高い正解率が得られるということです。最もよく引用されるのはNFNet-F1とEfficientNet-B7の組で、どちらも84.7%ですが、F1は1ステップ158.5 msで済み、B7は1397.0 msかかります。9倍近く速いことになります。最大のNFNet-F5は86.0%に達し、SAMオプティマイザを加えるとF5は86.3%、F6は86.5%になります。これは当時、追加データを使わない条件での最高成績でした。\n\nただし、この赤線は学習時間で描いたものです。パラメータ数で見ると、NFNetはまったく節約になっていません。F0はパラメータ71.5M、12.38 GFLOPsですが、EfficientNet-B0は5.3M、0.39 GFLOPsしかありません。F1のパラメータもB7の2倍です。著者らは論文ではっきり、最適化したのは学習時間で、FLOPsやパラメータ数は目標ではないと書いています。\n\n### 事前学習してから微調整する\n\n最後の実験では、著者らは3億枚のラベル付き画像で事前学習し、ImageNetで微調整しました。これほどのデータ量では、BatchNormの正則化の効果はかえって邪魔になるかもしれず、著者らは、BNのないネットワークのほうがこうした状況に向いていると推測しています。\n\n| モデル | 224px | 320px | 384px |\n| --- | ---: | ---: | ---: |\n| BN-ResNet-50 | 78.1% | 79.6% | 79.9% |\n| NF-ResNet-50 | **79.5%** | **80.9%** | **81.1%** |\n| BN-ResNet-200 | 81.8% | 83.1% | 83.5% |\n| NF-ResNet-200 | **82.9%** | **84.1%** | **84.3%** |\n\n*表：原論文Table 4から2組を抜粋。事前学習後にImageNetで微調整したtop-1正解率です。完全な表にはResNet-101と152もあり、結果の傾向は同じです。*\n\nどの組でもNF版が勝ち、差は約1ポイントです。著者らはさらに、少し幅を広げたNFNet-F4+を20エポック事前学習し、微調整後に89.2%を達成しました。これは当時、転移学習で得られた最高の成績です。\n\n## 結論\n\nBatchNormを取り除いたら、学習はかえって速くなりました。ただ、BatchNormがついでに片づけてくれていた仕事は、一つずつ自分で補わなければなりません。平均シフトはScaled Weight Standardizationとゲインに、残差分岐の大きさは$\\alpha$、$\\beta$とSkipInitに、正則化はDropoutと強いデータ拡張に任せ、大バッチ学習はAGCで支えます。\n\nすぐに使いたいなら、timmに`dm_nfnet_f0`から`dm_nfnet_f6`まであり、timmが独自に学習し、GPU向けに軽量化した`eca_nfnet_l0`シリーズもあります。AGCも`adaptive_clip_grad`で、自分のモデルに単独で適用できます。\n\nあ、そうそう。NFNetの派生モデルを学習させるなら、勾配クリッピングは忘れずにオンにしてくださいね。甘く見ちゃだめですよ！\n","imageSizes":{"/content/papers/assets/9c1e7cd2c8c545de3ebab245e654b0dd69b3921c4f0479f0e99131833bdfc5f2.png":{"width":1004,"height":417},"/content/papers/assets/6dc27a9ccca4de619c057562ea6384aab3c095ddc08b22f475601ab03fcf03bb.png":{"width":966,"height":288},"/content/papers/assets/7552bff30433f4f33bec5edb2421acd94d61d452888dde6df17557778e8fb1c6.png":{"width":1004,"height":783}}}
