ImageNet 2012 대회에서 우승한 최초의 CNN 기반 아키텍처(AlexNet) 이후 모든 후속 우승 아키텍처는 오류율을 줄이기 위해 심층 신경망에서 더 많은 레이어를 사용합니다. 이는 적은 수의 레이어에서 작동하지만 레이어 수를 늘리면 Vanishing/Exploding Gradient라는 것과 관련된 딥러닝의 일반적인 문제가 있습니다. 이로 인해 그라데이션이 0이 되거나 너무 커집니다. 따라서 레이어 수를 늘리면 학습 및 테스트 오류율도 증가합니다.

20레이어와 56레이어 아키텍처 비교
위 플롯에서 56레이어 CNN이 20레이어 CNN 아키텍처보다 훈련 및 테스트 데이터세트 모두에서 더 높은 오류율을 제공한다는 것을 확인할 수 있습니다. 오류율에 대해 더 자세히 분석한 후 저자는 경사도 소멸/폭발로 인해 오류가 발생한다는 결론에 도달할 수 있었습니다.
2015년 Microsoft Research 연구원들이 제안한 ResNet은 Residual Network라는 새로운 아키텍처를 도입했습니다.
잔여 네트워크: Vanishing/Exploding Gradient 문제를 해결하기 위해 이 아키텍처에서는 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 아키텍처(잔차 블록 포함)를 처음부터 설계할 수 있습니다. 다음은 다양한 ResNet 아키텍처의 구현입니다. 이 구현을 위해 CIFAR-10 데이터세트를 사용합니다. 이 데이터 세트에는 10가지 클래스(비행기, 자동차, 새, 고양이, 사슴, 개, 개구리, 말, 배, 트럭) 등의 60,000개의 32×32 컬러 이미지가 포함되어 있습니다. 이 데이터 세트는 k에서 평가할 수 있습니다. eras.datasets 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 아키텍처에 필요한 다양한 하이퍼 매개변수를 설정합니다. 또한 훈련을 준비하기 위해 데이터 세트에 대해 몇 가지 사전 처리를 수행했습니다.
암호: 훈련 하이퍼파라미터 설정
파이썬3
# 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단계: 이번 단계에서는 Epoch 횟수에 따라 학습률을 설정합니다. 더 나은 학습을 보장하려면 Epoch 수가 증가함에 따라 학습 속도를 줄여야 합니다.
암호: 다양한 Epoch 수에 대해 LR 설정
파이썬3
# 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> |
>
VLC 유튜브 비디오 다운로드
>
4단계: ResNet V1 및 V2 아키텍처를 정의하는 데 사용할 수 있는 기본 ResNet 빌딩 블록을 정의합니다.
암호: 기본 ResNet 빌딩 블록
파이썬3
# 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> |
>
>
5단계: 위에서 정의한 ResNet 빌딩 블록을 기반으로 하는 ResNet V1 아키텍처를 정의합니다.
암호: ResNet V1 아키텍처
파이썬3
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 아키텍처를 정의합니다.
암호: ResNet V2 아키텍처
nfa를 dfa로 변환하다
파이썬3
# 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 아키텍처를 훈련하고 테스트하는 데 사용됩니다.
코드: 주요 기능
파이썬3
# 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 데이터세트에서 저자는 VGG19보다 8배 더 깊지만 여전히 매개변수가 더 적은 152개 레이어 ResNet을 사용합니다. 이러한 ResNet의 앙상블은 ImageNet 테스트 세트에서 단 3.7%의 오류를 생성했으며, 그 결과 ILSVRC 2015 대회에서 우승했습니다. COCO 객체 감지 데이터 세트에서는 매우 깊은 표현으로 인해 상대적으로 28%의 개선이 발생합니다.

ResNet 아키텍처의 오류율
- 위의 결과는 레이어를 18에서 34로 늘리면 일반 네트워크와 달리 ImageNet Validation Set의 오류율도 감소하기 때문에 바로 가기 연결을 통해 레이어 증가로 인해 발생하는 문제를 해결할 수 있음을 보여줍니다.

ImageNet 검증 세트의 top-1 및 top-5 오류율.
- 아래는 ImageNet 테스트 세트의 결과입니다. 그만큼 3.57% ResNet의 top-5 오류율은 가장 낮았으며 따라서 ResNet 아키텍처는 2015년 ImageNet 분류 대회에서 1위를 차지했습니다.
