以前、LeNet、AlexNet、Vgg についてお話しましたが、今週は GoogLeNet についてお話します。 GoogLeNet は、Google の Christian Szegedy らが 2014 年の論文「Going Deeper with Convolutions」で提案したものです。最大のハイライトは、Inception と呼ばれる構造の提案でした。これは GoogLeNet の構築の基礎として使用され、その年の ImageNet 分類および検出タスクで 1 位を獲得しました。追記: GoogLeNet は、YannLeCun の LeNet シリーズに敬意を表して命名されました。 (このシリーズのすべてのコードは github にあります: https://github.com/huxiaoman7/PaddlePaddle_code)
ディープネットワークに関する考察 このシリーズの最初の数回の記事では、畳み込みニューラル ネットワークについて説明しました。設計されたネットワーク構造も非常に単純で、3 層畳み込みニューラル ネットワークなどの浅いニューラル ネットワークに属します。ただし、層の数が比較的少ない場合、効果があまり良くないことがよくあります。実験の過程で、ネットワークの層の数を増やしたり、ネットワークの各層のニューロンの数を増やしたりすると、精度がある程度向上することがわかりました。簡単に言えば、ネットワークの深さと幅を増やすことですが、これには 2 つの明らかな欠点があります。 - ネットワークが深く広くなると、パラメータも増えるため、モデルの複雑さが増し、特にトレーニング データがあまりない場合や特定のラベルのトレーニング データが不十分な場合に、過剰適合のリスクが大幅に高まります。
- コンピューティング リソースの消費量が増加します。実際の状況では、データのスパース性や拡張されたネットワーク構造の不十分な利用 (たとえば、多くの重みが 0 に近い) が原因で、コンピューティング リソースの無駄が多くなります。
上記の 2 つの問題を解決するための基本的な方法は、完全接続または畳み込み接続をスパース接続に変更することです。スパース性は、生物学と機械学習の両方の観点から優れたパフォーマンスを発揮します。AlexNet セクションで紹介した Dropout ネットワークと ReLU 活性化関数を思い出してください。その本質は、スパース性を使用してモデルの一般化を向上させることです (ただし、計算する必要のあるパラメーターの数は減少していません)。 スパース性の簡単な説明は、特徴空間全体が非線形または不連続である場合です。 - ローカル空間の特徴セットを学習すると、Maxout ネットワークで複数のローカル線形関数の組み合わせを使用して非線形関数を適合させるというアイデアと同様に、パフォーマンスを向上させることができます。
- 特徴空間全体が N 個の不連続なローカル特徴空間セットで構成されていると仮定します。任意のサンプルはこれらの N 個の空間にマッピングされ、対応する特徴次元をアクティブ化/非アクティブ化します。C1 が特定の種類のサンプルのアクティブ化された特徴次元セットを表し、C2 が別の種類のサンプルの特徴次元セットを表す場合、データ量が十分でないときに、特徴の識別性を高めて 2 種類のサンプルをうまく区別するには、C1 と C2 の重なりを減らす必要があります (たとえば、Jaccard 距離で測定できます)。つまり、C1 と C2 のサイズを小さくする必要があります。これは、対応する特徴次元セットがスパースになることを意味します。
しかし、困ったことに、現在のコンピュータ アーキテクチャは、高密度データの計算には優れていますが、非均一に分散されたスパース データに対する計算効率は極めて低いです。たとえば、スパース性により、キャッシュ ミス率が極めて高くなります。そのため、計算効率を確保しながらスパース ネットワークを活用する方法が必要です。幸いなことに、先人たちは多くの実験(「2次元スパース行列の分割について:モデル、方法、レシピ」など)を行い、スパース行列をクラスタリングして比較的密度の高いサブ行列を取得すると、スパース行列の乗算のパフォーマンスが大幅に向上することを発見しました。このアイデアに基づいて、著者はインセプション構造を提案しました。 図1 インセプション構造 - 異なるサイズの畳み込みカーネルによって抽象化された特徴空間は、サブ特徴空間とみなされます。各サブ特徴空間はスパースです。異なるスケールのこれらの特徴を融合することは、比較的密度の高い空間を取得することと同じです。
- 出力特徴次元の位置合わせを容易にするために、1×1、3×3、5×5 畳み込みカーネル (必須ではありません、他のサイズも可能)、ストライド 1、パディングを使用します。
- 多くの事実から、プーリング層は畳み込みネットワークの効果を効果的に改善できることが示されているため、最大プーリング パスが追加されます。
- この構造は直感的な理解と一致しています。視覚情報は、さまざまなスケールの変換を通じて、次の段階の特徴として集約されます。たとえば、人の身長、体重、年齢などの情報は、次の判断ステップのために集約されます。
このネットワークの最大の問題は、5×5畳み込みが膨大な計算負荷をもたらすことです。例えば、上位層の入力が28×28×192であると仮定します。 - 96 個の 5×5 畳み込み層 (ストライド = 1、パディング = 2) を直接通過した後、出力は 28×28×96 になり、畳み込み層パラメータの数は 192×5×5×96 = 460800 になります。
- NIN ネットワーク (Network in Network、後述) を使用し、32 個の 1×1 畳み込みカーネルを使用して 5×5 畳み込み前の次元を削減し、28×28×32 にします。96 個の 5×5 畳み込み層 (ストライド = 1、パディング = 2) の後、出力は 28×28×96 ですが、すべての畳み込み層のパラメータ数は 192×1×1×32+32×5×5×96=82944 です。パラメータの総数は元の 1/5.5 であり、効果に大きな損失がないことがわかります。
新しいネットワーク構造は
図2 新しいインセプションの構造
GoogLeNet ネットワーク構造 上記のInceptionモジュールを使用してGoogLeNetを構築すると、実験により、Inceptionモジュールは高レベルの特徴抽象化に登場した場合により効果的であることが示されています(構造上の特徴により、高次特徴の抽出に適しており、低次特徴を抽出させると特徴情報の損失につながると理解しています)。そのため、低層では従来の畳み込み層が依然として使用されています。ネットワーク全体の構造は次のようになります。 図3 GoogLeNetネットワーク構造 図4 GoogLeNetの詳細なネットワーク構造図 ネットワークの説明: - すべての畳み込み層は、1×1畳み込み次元削減後の活性化も含め、ReLU活性化関数を使用します。
- 完全接続層を削除し、NIN のような Global Average Pooling を使用すると、Top 1 の精度が 0.6% 向上します。ただし、GAP はカテゴリの数に関連しているため、モデルの微調整を容易にするために完全接続層が追加されます。
- 前回のResNetと同様に、実験では、比較的浅いニューラルネットワーク層がモデル効果に大きく貢献していることが観察されました。トレーニング段階では、バックプロパゲーション中に勾配信号を強化するために、Inception(4a、4d)に2つの分類器が追加されますが、最も重要なのは正則化効果であり、これはGoogLeNet v3で実験的に確認され、GoogLeNet V2でのBNの正則化効果が間接的に確認されています。これら2つの分類器の損失は、0.3の重みで全体の損失に追加されます。モデル推論段階では、これら2つの分類器は削除されます。
- 次元削減に使用される 1×1 畳み込みカーネルの数は 128 です。
- 完全結合層は 1024 個のニューロンを使用します。
- ドロップアウト確率が 0.7 のドロップアウト レイヤーを使用します。
ネットワーク構造の詳細な説明: 入力データは224×224×3のRGB画像です。図中の「S」はsame-padding、「V」はsame-paddingなしを表します。 - C1 畳み込み層: 64 個の 7×7 畳み込みカーネル (ストライド = 2、パディング = 3)、出力: 112×112×64。
- P1サンプリング層: 64個の3×3畳み込みカーネル(ストライド=2)、出力は56×56×64、ここで56=(112-3+1)/2+1
- C2 畳み込み層: 192 個の 3×3 畳み込みカーネル (ストライド = 1、パディング = 1)、出力: 56×56×192。
- P2サンプリング層: 192 3×3畳み込みカーネル(ストライド=2)、出力は28×28×192、ここで: 28=(56-3+1)/2+1、その後データは4つのブランチに分割され、インセプションに入ります(3a)
- インセプション(3a):4つの部分から構成
- 64 個の 1×1 畳み込みカーネル、出力は 28×28×64 です。
- 次元削減には 96 個の 1×1 畳み込みカーネルが使用され、出力は 28×28×96 になります。次に 128 個の 3×3 畳み込みカーネル (ストライド = 1、パディング = 1) が使用され、出力は次のようになります: 28×28×128
- 次元削減には16個の1×1畳み込みカーネルが使用され、出力は28×28×16になります。次に、32個の5×5畳み込みカーネル(ストライド=1、パディング=2)が使用され、出力は次のようになります: 28×28×32
- 192 個の 3×3 畳み込みカーネル (ストライド = 1、パディング = 1)、出力は 28×28×192、32 個の 1×1 畳み込みカーネル、出力は 28×28×32
***4つのブランチの出力は「深さ」方向に結合され、28×28×256の出力が得られます。次に、データは4つのブランチに分割され、インセプション(3b)に入ります。
- インセプション(3b):4つの部分から構成
- 128 個の 1×1 畳み込みカーネル、出力は 28×28×128 です。
- 次元削減には128個の1×1畳み込みカーネルが使用され、出力は28×28×128です。192個の3×3畳み込みカーネル(ストライド=1、パディング=1)が使用され、出力は28×28×192です。
- 次元削減には 32 個の 1×1 畳み込みカーネルが使用され、出力は 28×28×32 になります。96 個の 5×5 畳み込みカーネル (ストライド = 1、パディング = 2) が使用され、出力は次のようになります: 28×28×96
- 256 個の 3×3 畳み込みカーネル (ストライド = 1、パディング = 1)、出力は 28×28×256、64 個の 1×1 畳み込みカーネル、出力は 28×28×64 です。
*** 4 つのブランチの出力を「深さ」方向に結合すると、出力は 28×28×480 になります。 次の構造も同様です。
PaddlePaddle を使用した GoogLeNet の実装 1. ネットワーク構造 googlenet.py PaddlePaddle のモデルの下に、GoogLeNet の実装コードがあります。これを直接学習して実行できます。 - 1 paddle.v2をpaddleとしてインポートする
- 2
- 3 __all__ = [ 'googlenet' ]
- 4
- 5
- 6 def inception(名前、入力、チャンネル、フィルター1、フィルター3R、フィルター3、フィルター5R、
- 7 フィルター5、proj):
- 8 cov1 = パドル.レイヤー.img_conv(
- 9名前=名前+ '_1' 、
- 10 入力=入力、
- 11 フィルターサイズ=1、
- 12 num_channels=チャンネル、
- 13 num_filters=フィルター1、
- 14 歩幅=1、
- 15パディング=0)
- 16
- 17 cov3r = パドル.レイヤー.img_conv(
- 18名前=名前+ '_3r' 、
- 19 入力=入力、
- 20 フィルターサイズ=1、
- 21 num_channels=チャンネル数、
- 22 num_filters=filter3R、
- 23 歩幅=1、
- 24パディング=0)
- 25 cov3 = パドル.レイヤー.img_conv(
- 26名前=名前+ '_3' 、
- 27 入力=cov3r、
- 28 フィルターサイズ=3、
- 29 num_filters=フィルター3、
- 30 歩幅=1、
- 31パディング=1)
- 32
- 33 cov5r = パドル.レイヤー.img_conv(
- 34名前=名前+ '_5r' 、
- 35 入力=入力、
- 36 フィルターサイズ=1、
- 37 num_channels=チャンネル、
- 38 num_filters=filter5R、
- 39 歩幅=1、
- 40パディング=0)
- 41 cov5 = パドル.レイヤー.img_conv(
- 42名前=名前+ '_5' 、
- 43 入力=cov5r、
- 44 フィルターサイズ=5、
- 45 num_filters=フィルター5、
- 46 歩幅=1、
- 47パディング=2)
- 48
- 49 プール1 = パドル.レイヤー.img_pool(
- 50名前=名前+ '_max' 、
- 51 入力=入力、
- 52 プールサイズ=3、
- 53 num_channels=チャンネル数、
- 54 ストライド=1、
- 55パディング=1)
- 56 covprj = パドル.レイヤー.img_conv(
- 57名前=名前+ '_proj' 、
- 58 入力=プール1、
- 59 フィルターサイズ=1、
- 60 num_filters=プロジェクト、
- 61 歩幅=1、
- 62 パディング=0)
- 63
- 64 cat = paddle.layer.concat( name = name 、 input=[cov1, cov3, cov5, covprj])
- 65リターンキャット
- 66
- 67
- 68 定義 googlenet(入力、class_dim):
- 69 # ステージ 1
- 70 conv1 = パドル.レイヤー.img_conv(
- 71名前= "conv1" 、
- 72 入力=入力、
- 73 フィルターサイズ=7、
- 74 チャンネル数=3,
- 75 フィルター数=64,
- 76 ストライド=2、
- 77 パディング=3)
- 78 プール1 = パドル.レイヤー.img_pool(
- 79名前= "pool1" 、入力 = conv1、プールサイズ = 3、チャネル数 = 64、ストライド = 2)
- 80
- 81 # ステージ2
- 82 conv2_1 = パドル.レイヤー.img_conv(
- 83名前= "conv2_1" 、
- 84 入力=プール1、
- 85 フィルターサイズ=1、
- 86 フィルター数=64、
- 87 歩幅=1、
- 88 パディング=0)
- 89 conv2_2 = パドル.レイヤー.img_conv(
- 90名前= "conv2_2" 、
- 91 入力=conv2_1、
- 92 フィルターサイズ=3、
- 93 フィルター数=192,
- 94 ストライド=1、
- 95パディング=1)
- 96 プール2 = パドル.レイヤー.img_pool(
- 97名前= "pool2" 、入力 = conv2_2、プールサイズ = 3、チャネル数 = 192、ストライド = 2)
- 98
- 99 # ステージ3
- 100 ince3a = インセプション( "ince3a" , プール2, 192, 64, 96, 128, 16, 32, 32)
- 101 ince3b = インセプション( "ince3b" , ince3a, 256, 128, 128, 192, 32, 96, 64)
- 102 プール3 = パドル.レイヤー.img_pool(
- 103名前= "pool3" 、入力 = ince3b、num_channels = 480、pool_size = 3、stride = 2)
- 104
- 105 # ステージ4
- 106 ince4a = インセプション( "ince4a" 、プール3、480、192、96、208、16、48、64)
- 107 ince4b = インセプション( "ince4b" , ince4a, 512, 160, 112, 224, 24, 64, 64)
- 108 ince4c = インセプション( "ince4c" , ince4b, 512, 128, 128, 256, 24, 64, 64)
- 109 ince4d = インセプション( "ince4d" , ince4c, 512, 112, 144, 288, 32, 64, 64)
- 110 ince4e = インセプション( "ince4e" , ince4d, 528, 256, 160, 320, 32, 128, 128)
- 111 プール4 = パドル.レイヤー.img_pool(
- 112名前= "pool4" 、入力 = ince4e、num_channels = 832、pool_size = 3、stride = 2)
- 113
- 114 # ステージ5
- 115 ince5a = インセプション( "ince5a" , プール4, 832, 256, 160, 320, 32, 128, 128)
- 116 ince5b = インセプション( "ince5b" , ince5a, 832, 384, 192, 384, 48, 128, 128)
- 117 プール5 = パドル.レイヤー.img_pool(
- 118名前= "pool5" 、
- 119 入力=ince5b、
- 120 チャンネル数=1024、
- 121 プールサイズ=7、
- 122 歩幅=7、
- 123 pool_type = paddle.pooling.Avg ()) プールタイプ = paddle.pooling.Avg())
- 124 ドロップアウト = paddle.layer.addto(
- 125 入力=プール5、
- 126 レイヤー属性 = パドル属性.Extra(ドロップ率=0.4)、
- 127 行為 = paddle.activation.Linear())
- 128
- 129アウト= パドル.レイヤー.fc(
- 130 入力 = ドロップアウト、サイズ= class_dim、動作 = paddle.activation.Softmax())
- 131
- 132 # fc用 出力1
- 133 pool_o1 = パドル.レイヤー.img_pool(
- 134名前= "pool_o1" 、
- 135 入力=ince4a、
- 136 チャンネル数=512、
- 137 プールサイズ=5、
- 138 歩幅=3、
- 139 pool_type = paddle.pooling.Avg ()) プールタイプ = paddle.pooling.Avg())
- 140 conv_o1 = パドル.レイヤー.img_conv(
- 141名前= "conv_o1" 、
- 142 入力=pool_o1、
- 143 フィルターサイズ=1、
- 144 フィルター数=128,
- 145 歩幅=1、
- 146 パディング=0)
- 147 fc_o1 = パドル.レイヤー.fc(
- 148名前= "fc_o1" 、
- 149 入力=conv_o1、
- 150サイズ= 1024、
- 151 レイヤー_attr = パドル.attr.Extra(ドロップレート=0.7)、
- 152 act=paddle.activation.Relu())
- 153 out1 = パドル.レイヤー.fc(
- 154 入力 = fc_o1、サイズ= class_dim、動作 = paddle.activation.Softmax())
- 155
- 156 # fc用 出力2
- 157 pool_o2 = パドル.レイヤー.img_pool(
- 158名前= "pool_o2" 、
- 159 入力=ince4d、
- 160 チャンネル数=528、
- 161 プールサイズ=5、
- 162 歩幅=3、
- 163 pool_type = paddle.pooling.Avg ()) プールタイプ = paddle.pooling.Avg())
- 164 conv_o2 = パドル.レイヤー.img_conv(
- 165名前= "conv_o2" 、
- 166 入力=pool_o2、
- 167 フィルターサイズ=1、
- 168 フィルター数=128、
- 169 歩幅=1、
- 170 パディング=0)
- 171 fc_o2 = パドル.レイヤー.fc(
- 172名前= "fc_o2" 、
- 173 入力=conv_o2、
- 174サイズ= 1024、
- 175 レイヤー属性 = パドル属性.Extra(ドロップ率=0.7)、
- 176 act=paddle.activation.Relu())
- 177 out2 = パドル.レイヤー.fc(
- 178 入力 = fc_o2、サイズ= class_dim、動作 = paddle.activation.Softmax())
- 179
- 180戻る アウト、アウト1、アウト2
2. モデルのトレーニング - 1 インポート gzip
- 2 paddle.v2.dataset.flowersをflowersとしてインポートする
- 3 paddle.v2をpaddleとしてインポートする
- 4 インポートリーダー
- 5 インポートvgg
- 6 resnetをインポートする
- 7 インポート alexnet
- 8 googlenet をインポート
- 9 argparseをインポートする
- 10
- 11 データ次元 = 3 * 224 * 224
- 12 クラス_次元 = 102
- 13 バッチサイズ = 128
- 14
- 15
- 16 定義main():
- 17 # 引数を解析する
- 18 パーサー = argparse.ArgumentParser()
- 19 パーサー.add_argument(
- 20 「モデル」 、
- 21 help= '画像分類モデル' ,
- 22 の選択肢 = [ 'alexnet' 、 'vgg13' 、 'vgg16' 、 'vgg19' 、 'resnet' 、 'googlenet' ])
- 23 引数 = parser.parse_args()
- 24
- 25 # パドルパドルの初期化
- 26 パドル.init(use_gpu= True 、trainer_count=7)
- 27
- 28 イメージ = paddle.layer.data(
- 29名前= "image" 、タイプ = paddle.data_type.dense_vector(DATA_DIM))
- 30 lbl = パドル.レイヤー.データ(
- 31名前= "ラベル" 、タイプ = paddle.data_type.integer_value(CLASS_DIM))
- 32
- 33 extra_layers = なし
- 34 学習率 = 0.01
- 35 args.model == 'alexnet'の場合:
- 36出力= alexnet.alexnet(画像、class_dim=CLASS_DIM)
- 37 elif args.model == 'vgg13' :
- 38出力= vgg.vgg13(画像、class_dim=CLASS_DIM)
- 39 elif args.model == 'vgg16' :
- 40出力= vgg.vgg16(画像、class_dim=CLASS_DIM)
- 41 elif args.model == 'vgg19' :
- 42出力= vgg.vgg19(画像、class_dim=CLASS_DIM)
- 43 elif args.model == 'resnet' :
- 44出力= resnet.resnet_imagenet(image, class_dim=CLASS_DIM)
- 45 学習率 = 0.1
- 46 elif args.model == 'googlenet' :
- 47出力、out1、out2 = googlenet.googlenet(画像、class_dim=CLASS_DIM)
- 48 損失1 = パドル.レイヤー.クロスエントロピーコスト(
- 49 入力=out1、ラベル=lbl、係数=0.3)
- 50 パドル.評価者.分類エラー(入力=out1、ラベル=lbl)
- 51 loss2 = パドル.レイヤー.クロスエントロピーコスト(
- 52 入力=out2、ラベル=lbl、係数=0.3)
- 53 パドル.評価者.分類エラー(入力=out2、ラベル=lbl)
- 54 追加レイヤー = [損失1、損失2]
- 55
- 56 コスト = paddle.layer.classification_cost(入力 = out 、ラベル = lbl)
- 57
- 58 #パラメータを作成する
- 59 パラメータ = paddle.parameters.create (コスト)
- 60
- 61 #オプティマイザを作成する
- 62 オプティマイザ = paddle.optimizer.Momentum(
- 63 運動量=0.9、
- 64 正規化 = paddle.optimizer.L2Regularization(レート = 0.0005 *
- 65 バッチサイズ)、
- 66 学習率=学習率 / バッチサイズ、
- 67 学習率減衰率=0.1、
- 68 学習率減衰率b=128000 * 35、
- 69 学習率スケジュール = "discexp" 、 )
- 70
- 71 train_reader = paddle.batch(
- 72 パドル.リーダー.シャッフル(
- 73 flowers.train(),
- 74 #他のデータを使用するには、上記の行を次のように置き換えます。
- 75 # reader.train_reader( 'train.list' ),
- 76 バッファサイズ=1000)、
- 77 バッチサイズ=BATCH_SIZE)
- 78 test_reader = パドル.batch(
- 79 flowers.valid()、
- 80 #他のデータを使用するには、上記の行を次のように置き換えます。
- 81 # reader.test_reader( 'val.list' ),
- 82 バッチサイズ=BATCH_SIZE)
- 83
- 84 #トレーナーを作成する
- 85 トレーナー = paddle.trainer.SGD(
- 86 コスト=コスト、
- 87 パラメータ=パラメータ、
- 88 update_equation=オプティマイザー、
- 89 extra_layers=追加レイヤー)
- 90
- 91 #バッチを終了し、 パスイベントハンドラの終了
- 92 定義イベントハンドラ(イベント):
- 93 インスタンスの場合(イベント、paddle.event.EndIteration):
- 94 event.batch_id % 1 == 0の場合:
- 95 印刷"\nパス %d、バッチ %d、コスト %f、%s" % (
- 96 イベント.pass_id、イベント.batch_id、イベント.cost、イベント.metrics)
- 97 インスタンスの場合(イベント、paddle.event.EndPass):
- 98でgzip.open ( 'params_pass_%d.tar.gz' % event.pass_id, ' w' )を fとして:
- 99 トレーナー.save_parameter_to_tar(f)
- 100
- 101 結果 = trainer.test(reader=test_reader)
- 102 印刷"\n合格したテスト %d、%s" % (event.pass_id、result.metrics)
- 103
- 104 トレーナー.train(
- 105 リーダー = train_reader、num_passes = 200、イベント ハンドラー = イベント ハンドラー)
- 106
- 107
- 108 __name__ == '__main__'の場合:
- 109 メイン()
3. 動作モード - 1 python train.py googlenet
このうち、最初の googlenet はオプションのネットワーク モデルです。alexnet、vgg3、vgg6 などの他のネットワーク モデルを入力することで、さまざまなネットワーク構造をトレーニングに使用できます。
Tensorflow で GoogLeNet を実装する tensorflow の実装はモデル内に非常に詳細なコードがあるため、ここですべてを公開することはしません。InceptionV1 ~InceptionV4 の実装が含まれる models/research/slim/nets/ を詳しく見ることができます。 ps: ここでの slim は、Tensorflow の contrib の下の slim ではなく、models の下の slim です。混乱しないでください。Slim は、Tensorflow の高レベル API として理解できます。これらの複雑なネットワーク構造を構築するときは、ネットワーク構造全体を最初から記述しなくても、slim によってカプセル化されたネットワーク構造を直接呼び出すことができます。スリムに関する詳細はインターネットで検索できるのでとても便利です。
要約する 実は、GoogLeNetの最も重要な点はInception構造です。これのメリットは何でしょうか?本来、精度を上げたい場合、より深い層を積み重ねたり、ニューロンの数を増やしたりする必要がありますが、ある層まで積み重ねた後は、結果の精度が向上しない可能性があります。これは、パラメータが多くなり、モデルがより複雑になり、オーバーフィットしやすくなるためです。ただし、実験では、よりスパースでより正確な構造にすることでも良い結果が得られたため、このアイデアに従って継続することができます。そのため、InceptionV2、V3、V4などがあり、そのパフォーマンスも非常に優れています。これは、レイヤーを積み重ねることで精度を向上させるという従来の考え方に新たなアイデアをもたらします。 |