ImageNet 2012 コンペティションで最初の CNN ベースのアーキテクチャ (AlexNet) が優勝した後、その後の優勝アーキテクチャではエラー率を下げるためにディープ ニューラル ネットワークでより多くの層が使用されています。これは層の数が少ない場合には機能しますが、層の数が増えると、消失/爆発勾配と呼ばれる問題に関連するディープ ラーニングの一般的な問題が発生します。これにより、勾配が 0 になるか、大きくなりすぎます。したがって、層の数が増えると、トレーニングとテストのエラー率も増加します。
順番に

20層アーキテクチャと56層アーキテクチャの比較
上のプロットでは、56 層 CNN は 20 層 CNN アーキテクチャよりもトレーニング データセットとテスト データセットの両方でエラー率が高いことがわかります。エラー率についてさらに詳しく分析した結果、著者らはそれが勾配の消失/爆発によって引き起こされているという結論に達することができました。
Microsoft Research の研究者によって 2015 年に提案された ResNet では、Residual Network と呼ばれる新しいアーキテクチャが導入されました。
残留ネットワーク: 勾配の消失/爆発の問題を解決するために、このアーキテクチャでは Residual Blocks と呼ばれる概念が導入されました。このネットワークでは、と呼ばれる技術を使用します。 接続をスキップする 。スキップ接続は、間のいくつかのレイヤーをスキップすることによって、レイヤーのアクティブ化をさらなるレイヤーに接続します。これにより残留ブロックが形成されます。 Resnet は、これらの残りのブロックを積み重ねることによって作成されます。
このネットワークの背後にあるアプローチは、層が基礎となるマッピングを学習するのではなく、ネットワークが残差マッピングに適合できるようにすることです。したがって、H(x) の代わりに、初期マッピング 、 ネットワークを適合させて、
F(x) := H(x) - x which gives H(x) := F(x) + x .>

スキップ(ショートカット)接続
このタイプのスキップ接続を追加する利点は、アーキテクチャのパフォーマンスに悪影響を与えるレイヤーがある場合、そのレイヤーが正則化によってスキップされることです。したがって、これにより、勾配の消失/爆発によって引き起こされる問題を発生させることなく、非常に深いニューラル ネットワークをトレーニングすることができます。この論文の著者は、CIFAR-10 データセットの 100 ~ 1000 層で実験を行いました。
高速道路ネットワークと呼ばれる同様のアプローチがあり、これらのネットワークもスキップ接続を使用します。 LSTM と同様に、これらのスキップ接続でもパラメトリック ゲートが使用されます。これらのゲートは、スキップ接続を通過する情報の量を決定します。ただし、このアーキテクチャは ResNet アーキテクチャよりも優れた精度を提供していません。
ネットワークアーキテクチャ: このネットワークは、VGG-19 からインスピレーションを得た 34 層のプレーン ネットワーク アーキテクチャを使用しており、そこにショートカット接続が追加されています。これらのショートカット接続は、アーキテクチャを残留ネットワークに変換します。

ResNet -34 アーキテクチャ
実装: Tensorflow と Keras API を使用すると、ResNet アーキテクチャ (Residual Blocks を含む) を最初から設計できます。以下は、さまざまな ResNet アーキテクチャの実装です。この実装では、CIFAR-10 データセットを使用します。このデータセットには、10 の異なるクラス (飛行機、車、鳥、猫、鹿、犬、カエル、馬、船、トラック) などの 60,000 個の 32×32 カラー画像が含まれています。このデータセットは k から評価できます。 時代.データセット API関数。
ステップ1: まず、keras モジュールとその API をインポートします。これらの API は、ResNet モデルのアーキテクチャの構築に役立ちます。
コード: ライブラリのインポート
# Import Keras modules and its important APIs import keras from keras.layers import Dense, Conv2D, BatchNormalization, Activation from keras.layers import AveragePooling2D, Input, Flatten from keras.optimizers import Adam from keras.callbacks import ModelCheckpoint, LearningRateScheduler from keras.callbacks import ReduceLROnPlateau from keras.preprocessing.image import ImageDataGenerator from keras.regularizers import l2 from keras import backend as K from keras.models import Model from keras.datasets import cifar10 import numpy as np import os>
ステップ2: 次に、ResNet アーキテクチャに必要なさまざまなハイパー パラメーターを設定します。また、データセットをトレーニング用に準備するために、いくつかの前処理も行いました。
コード: トレーニングのハイパーパラメータの設定
Python3
設定メニューアンドロイド
# Setting Training Hyperparameters> batch_size>=> 32> # original ResNet paper uses batch_size = 128 for training> epochs>=> 200> data_augmentation>=> True> num_classes>=> 10> > # Data Preprocessing> subtract_pixel_mean>=> True> n>=> 3> > # Select ResNet Version> version>=> 1> > # Computed depth of> if> version>=>=> 1>:> >depth>=> n>*> 6> +> 2> elif> version>=>=> 2>:> >depth>=> n>*> 9> +> 2> > # Model name, depth and version> model_type>=> 'ResNet % dv % d'> %> (depth, version)> > # Load the CIFAR-10 data.> (x_train, y_train), (x_test, y_test)>=> cifar10.load_data()> > # Input image dimensions.> input_shape>=> x_train.shape[>1>:]> > # Normalize data.> x_train>=> x_train.astype(>'float32'>)>/> 255> x_test>=> x_test.astype(>'float32'>)>/> 255> > # If subtract pixel mean is enabled> if> subtract_pixel_mean:> >x_train_mean>=> np.mean(x_train, axis>=> 0>)> >x_train>->=> x_train_mean> >x_test>->=> x_train_mean> > # Print Training and Test Samples> print>(>'x_train shape:'>, x_train.shape)> print>(x_train.shape[>0>],>'train samples'>)> print>(x_test.shape[>0>],>'test samples'>)> print>(>'y_train shape:'>, y_train.shape)> > # Convert class vectors to binary class matrices.> y_train>=> keras.utils.to_categorical(y_train, num_classes)> y_test>=> keras.utils.to_categorical(y_test, num_classes)> |
>
>
ステップ 3: このステップでは、エポック数に応じて学習率を設定します。エポック数が増えるにつれて、学習を確実に改善するには学習率を下げる必要があります。
コード: 異なるエポック数に対する LR の設定
Python3
# Setting LR for different number of Epochs> def> lr_schedule(epoch):> >lr>=> 1e>->3> >if> epoch>>>180>:> >lr>*>=> 0.5e>->3> >elif> epoch>>>160>:> >lr>*>=> 1e>->3> >elif> epoch>>>120>:> >lr>*>=> 1e>->2> >elif> epoch>>>80>:> >lr>*>=> 1e>->1> >print>(>'Learning rate: '>, lr)> >return> lr> |
>
>
ステップ 4: ResNet V1 および V2 アーキテクチャの定義に使用できる基本的な ResNet ビルディング ブロックを定義します。
コード: 基本的な ResNet ビルディング ブロック
Python3
# Basic ResNet Building Block> > > def> resnet_layer(inputs,> >num_filters>=>16>,> >kernel_size>=>3>,> >strides>=>1>,> >activation>=>'relu'>,> >batch_normalization>=>True>,> >conv>=>Conv2D(num_filters,> >kernel_size>=>kernel_size,> >strides>=>strides,> >padding>=>'same'>,> >kernel_initializer>=>'he_normal'>,> >kernel_regularizer>=>l2(>1e>->4>))> > >x>=>inputs> >if> conv_first:> >x>=> conv(x)> >if> batch_normalization:> >x>=> BatchNormalization()(x)> >if> activation>is> not> None>:> >x>=> Activation(activation)(x)> >else>:> >if> batch_normalization:> >x>=> BatchNormalization()(x)> >if> activation>is> not> None>:> >x>=> Activation(activation)(x)> >x>=> conv(x)> >return> x> |
>
>
ネットワークにおける OSI 参照モデル
ステップ5: 上で定義した ResNet ビルディング ブロックに基づく ResNet V1 アーキテクチャを定義します。
コード: ResNet V1 アーキテクチャ
Python3
def> resnet_v1(input_shape, depth, num_classes>=>10>):> > >if> (depth>-> 2>)>%> 6> !>=> 0>:> >raise> ValueError(>'depth should be 6n + 2 (eg 20, 32, 44 in [a])'>)> ># Start model definition.> >num_filters>=> 16> >num_res_blocks>=> int>((depth>-> 2>)>/> 6>)> > >inputs>=> Input>(shape>=>input_shape)> >x>=> resnet_layer(inputs>=>inputs)> ># Instantiate the stack of residual units> >for> stack>in> range>(>3>):> >for> res_block>in> range>(num_res_blocks):> >strides>=> 1> >if> stack & gt> >0> and> res_block>=>=> 0>:># first layer but not first stack> >strides>=> 2> # downsample> >y>=> resnet_layer(inputs>=>x,> >num_filters>=>num_filters,> >strides>=>strides)> >y>=> resnet_layer(inputs>=>y,> >num_filters>=>num_filters,> >activation>=>None>)> >if> stack & gt> >0> and> res_block>=>=> 0>:># first layer but not first stack> ># linear projection residual shortcut connection to match> ># changed dims> >x>=> resnet_layer(inputs>=>x,> >num_filters>=>num_filters,> >kernel_size>=>1>,> >strides>=>strides,> >activation>=>None>,> >batch_normalization>=>False>)> >x>=> keras.layers.add([x, y])> >x>=> Activation(>'relu'>)(x)> >num_filters>*>=> 2> > ># Add classifier on top.> ># v1 does not use BN after last shortcut connection-ReLU> >x>=> AveragePooling2D(pool_size>=>8>)(x)> >y>=> Flatten()(x)> >outputs>=> Dense(num_classes,> >activation>=>'softmax'>,> >kernel_initializer>=>'he_normal'>)(y)> > ># Instantiate model.> >model>=> Model(inputs>=>inputs, outputs>=>outputs)> >return> model> |
>
>
ステップ6: 上で定義した ResNet ビルディング ブロックに基づく ResNet V2 アーキテクチャを定義します。
YouTubeをダウンロードするにはvlc
コード: ResNet V2 アーキテクチャ
Python3
# ResNet V2 architecture> def> resnet_v2(input_shape, depth, num_classes>=>10>):> >if> (depth>-> 2>)>%> 9> !>=> 0>:> >raise> ValueError(>'depth should be 9n + 2 (eg 56 or 110 in [b])'>)> ># Start model definition.> >num_filters_in>=> 16> >num_res_blocks>=> int>((depth>-> 2>)>/> 9>)> > >inputs>=> Input>(shape>=>input_shape)> ># v2 performs Conv2D with BN-ReLU on input before splitting into 2 paths> >x>=> resnet_layer(inputs>=>inputs,> >num_filters>=>num_filters_in,> >conv_first>=>True>)> > ># Instantiate the stack of residual units> >for> stage>in> range>(>3>):> >for> res_block>in> range>(num_res_blocks):> >activation>=> 'relu'> >batch_normalization>=> True> >strides>=> 1> >if> stage>=>=> 0>:> >num_filters_out>=> num_filters_in>*> 4> >if> res_block>=>=> 0>:># first layer and first stage> >activation>=> None> >batch_normalization>=> False> >else>:> >num_filters_out>=> num_filters_in>*> 2> >if> res_block>=>=> 0>:># first layer but not first stage> >strides>=> 2> # downsample> > ># bottleneck residual unit> >y>=> resnet_layer(inputs>=>x,> >num_filters>=>num_filters_in,> >kernel_size>=>1>,> >strides>=>strides,> >activation>=>activation,> >batch_normalization>=>batch_normalization,> >conv_first>=>False>)> >y>=> resnet_layer(inputs>=>y,> >num_filters>=>num_filters_in,> >conv_first>=>False>)> >y>=> resnet_layer(inputs>=>y,> >num_filters>=>num_filters_out,> >kernel_size>=>1>,> >conv_first>=>False>)> >if> res_block>=>=> 0>:> ># linear projection residual shortcut connection to match> ># changed dims> >x>=> resnet_layer(inputs>=>x,> >num_filters>=>num_filters_out,> >kernel_size>=>1>,> >strides>=>strides,> >activation>=>None>,> >batch_normalization>=>False>)> >x>=> keras.layers.add([x, y])> > >num_filters_in>=> num_filters_out> > ># Add classifier on top.> ># v2 has BN-ReLU before Pooling> >x>=> BatchNormalization()(x)> >x>=> Activation(>'relu'>)(x)> >x>=> AveragePooling2D(pool_size>=>8>)(x)> >y>=> Flatten()(x)> >outputs>=> Dense(num_classes,> >activation>=>'softmax'>,> >kernel_initializer>=>'he_normal'>)(y)> > ># Instantiate model.> >model>=> Model(inputs>=>inputs, outputs>=>outputs)> >return> model> |
ラテックスの偏微分
>
>
ステップ 7: 以下のコードは、上で定義した ResNet v1 および v2 アーキテクチャのトレーニングとテストに使用されます。
コード: メイン関数
Python3
# Main function> if> version>=>=> 2>:> >model>=> resnet_v2(input_shape>=> input_shape, depth>=> depth)> else>:> >model>=> resnet_v1(input_shape>=> input_shape, depth>=> depth)> > model.>compile>(loss>=>'categorical_crossentropy'>,> >optimizer>=> Adam(learning_rate>=> lr_schedule(>0>)),> >metrics>=>[>'accuracy'>])> model.summary()> print>(model_type)> > # Prepare model saving directory.> save_dir>=> os.path.join(os.getcwd(),>'saved_models'>)> model_name>=> 'cifar10_% s_model.{epoch:03d}.h5'> %> model_type> if> not> os.path.isdir(save_dir):> >os.makedirs(save_dir)> filepath>=> os.path.join(save_dir, model_name)> > # Prepare callbacks for model saving and for learning rate adjustment.> checkpoint>=> ModelCheckpoint(filepath>=> filepath,> >monitor>=>'val_acc'>,> >verbose>=> 1>,> >save_best_only>=> True>)> > lr_scheduler>=> LearningRateScheduler(lr_schedule)> > lr_reducer>=> ReduceLROnPlateau(factor>=> np.sqrt(>0.1>),> >cooldown>=> 0>,> >patience>=> 5>,> >min_lr>=> 0.5e>->6>)> > callbacks>=> [checkpoint, lr_reducer, lr_scheduler]> > # Run training, with or without data augmentation.> if> not> data_augmentation:> >print>(>'Not using data augmentation.'>)> >model.fit(x_train, y_train,> >batch_size>=> batch_size,> >epochs>=> epochs,> >validation_data>=>(x_test, y_test),> >shuffle>=> True>,> >callbacks>=> callbacks)> else>:> >print>(>'Using real-time data augmentation.'>)> ># This will do preprocessing and realtime data augmentation:> >datagen>=> ImageDataGenerator(> ># set input mean to 0 over the dataset> >featurewise_center>=> False>,> ># set each sample mean to 0> >samplewise_center>=> False>,> ># divide inputs by std of dataset> >featurewise_std_normalization>=> False>,> ># divide each input by its std> >samplewise_std_normalization>=> False>,> ># apply ZCA whitening> >zca_whitening>=> False>,> ># epsilon for ZCA whitening> >zca_epsilon>=> 1e>->06>,> ># randomly rotate images in the range (deg 0 to 180)> >rotation_range>=> 0>,> ># randomly shift images horizontally> >width_shift_range>=> 0.1>,> ># randomly shift images vertically> >height_shift_range>=> 0.1>,> ># set range for random shear> >shear_range>=> 0.>,> ># set range for random zoom> >zoom_range>=> 0.>,> ># set range for random channel shifts> >channel_shift_range>=> 0.>,> ># set mode for filling points outside the input boundaries> >fill_mode>=>'nearest'>,> ># value used for fill_mode = 'constant'> >cval>=> 0.>,> ># randomly flip images> >horizontal_flip>=> True>,> ># randomly flip images> >vertical_flip>=> False>,> ># set rescaling factor (applied before any other transformation)> >rescale>=> None>,> ># set function that will be applied on each input> >preprocessing_function>=> None>,> ># image data format, either 'channels_first' or 'channels_last'> >data_format>=> None>,> ># fraction of images reserved for validation (strictly between 0 and 1)> >validation_split>=> 0.0>)> > ># Compute quantities required for featurewise normalization> ># (std, mean, and principal components if ZCA whitening is applied).> >datagen.fit(x_train)> > ># Fit the model on the batches generated by datagen.flow().> >model.fit_generator(datagen.flow(x_train, y_train, batch_size>=> batch_size),> >validation_data>=>(x_test, y_test),> >epochs>=> epochs, verbose>=> 1>, workers>=> 4>,> >callbacks>=> callbacks)> > # Score trained model.> scores>=> model.evaluate(x_test, y_test, verbose>=> 1>)> print>(>'Test loss:'>, scores[>0>])> print>(>'Test accuracy:'>, scores[>1>])> |
>
>
結果と結論:
ImageNet データセットでは、著者らは 152 層の ResNet を使用しています。これは VGG19 の 8 倍の深さですが、パラメータはまだ少ないです。これらの ResNet のアンサンブルは、ImageNet テスト セットでわずか 3.7% の誤差を生成し、その結果が ILSVRC 2015 コンペティションで優勝しました。 COCO 物体検出データセットでは、非常に深い表現により 28% の相対的な改善も得られます。

ResNet アーキテクチャのエラー率
- 上記の結果は、層を 18 から 34 に増やすと、プレーン ネットワークとは異なり、ImageNet Validation Set でのエラー率も減少するため、ショートカット接続は層の増加によって引き起こされる問題を解決できることを示しています。

ImageNet 検証セットのトップ 1 およびトップ 5 エラー率。
- 以下は ImageNet Test Set での結果です。の 3.57% ResNet のトップ 5 エラー率が最も低かったため、ResNet アーキテクチャは 2015 年の ImageNet 分類チャレンジで 1 位になりました。
