logo

Jäljellä olevat verkot (ResNet) – syvällinen oppiminen

Ensimmäisen CNN-pohjaisen arkkitehtuurin (AlexNet) jälkeen, joka voitti ImageNet 2012 -kilpailun, jokainen myöhempi voittanut arkkitehtuuri käyttää enemmän kerroksia syvässä hermoverkossa virhesuhteen vähentämiseksi. Tämä toimii pienemmällä määrällä tasoja, mutta kun lisäämme tasojen määrää, syväoppimisessa on yleinen ongelma, joka liittyy katoavaksi/räjähtäväksi gradienttiin. Tämä saa gradientin olemaan 0 tai liian suuri. Siten kun lisäämme kerrosten määrää, myös koulutus- ja testausvirheprosentti kasvaa.

20-kerroksen ja 56-kerroksen arkkitehtuurin vertailu



java-kytkinkotelo

Yllä olevassa kaaviossa voimme havaita, että 56-kerroksinen CNN antaa enemmän virheprosenttia sekä koulutus- että testaustietojoukossa kuin 20-kerroksinen CNN-arkkitehtuuri. Analysoituaan enemmän virhetasoa, kirjoittajat päätyivät siihen johtopäätökseen, että sen aiheuttaa katoava/räjähtävä gradientti.
Microsoft Researchin tutkijoiden vuonna 2015 ehdottama ResNet esitteli uuden arkkitehtuurin nimeltä Residual Network.

Jäljellä oleva verkko: Ratkaistakseen katoavan/räjähtävän gradientin ongelman, tämä arkkitehtuuri esitteli konseptin nimeltä Residual Blocks. Tässä verkossa käytämme tekniikkaa nimeltä ohittaa yhteydet . Ohitusyhteys yhdistää kerroksen aktivaatiot muihin kerroksiin ohittamalla joitain kerroksia väliltä. Tämä muodostaa jäännöslohkon. Resnetit tehdään pinoamalla nämä jäännöslohkot yhteen.
Tämän verkon taustalla oleva lähestymistapa on sen sijaan, että kerrokset oppisivat taustalla olevan kartoituksen, vaan annamme verkon sovittaa jäännöskartoituksen. Joten sanotaan H(x) sijaan alkukartoitus , anna verkon sopia,

 F(x) := H(x) - x  which gives H(x) := F(x) + x .>

Ohita (pikavalinta) yhteys



Tämän tyyppisen ohitusyhteyden lisäämisen etuna on, että jos jokin kerros heikentää arkkitehtuurin suorituskykyä, se ohitetaan säännöllisyyden vuoksi. Tämä johtaa siis erittäin syvän hermoverkon harjoittamiseen ilman katoavan/räjähtävän gradientin aiheuttamia ongelmia. Paperin kirjoittajat kokeilivat 100-1000 CIFAR-10-tietojoukon kerrosta.
On olemassa samanlainen lähestymistapa, jota kutsutaan moottoritieverkoiksi, nämä verkot käyttävät myös ohitusyhteyttä. Kuten LSTM, myös näissä ohitusliitännöissä käytetään parametrisia portteja. Nämä portit määrittävät, kuinka paljon tietoa kulkee ohitusyhteyden läpi. Tämä arkkitehtuuri ei kuitenkaan ole tarjonnut parempaa tarkkuutta kuin ResNet-arkkitehtuuri.

Verkkoarkkitehtuuri: Tämä verkko käyttää VGG-19:n inspiroimaa 34-kerroksista tavallista verkkoarkkitehtuuria, johon sitten lisätään pikayhteys. Nämä pikakuvakeyhteydet muuttavat sitten arkkitehtuurin jäännösverkoksi.

ResNet -34-arkkitehtuuri



Toteutus: Käyttämällä Tensorflow- ja Keras-sovellusliittymää voimme suunnitella ResNet-arkkitehtuurin (mukaan lukien jäännöslohkot) alusta alkaen. Alla on erilaisten ResNet-arkkitehtuurien toteutus. Käytämme tähän toteutukseen CIFAR-10-tietojoukkoa. Tämä tietojoukko sisältää 60 000 32 × 32 värikuvaa 10 eri luokassa (lentokoneita, autoja, lintuja, kissoja, hirviä, koiria, sammakoita, hevosia, laivoja ja kuorma-autoja) jne. Tämä tietojoukko voidaan arvioida k. eras.datasets API-toiminto.

Vaihe 1: Ensin tuomme keras-moduulin ja sen API:t. Nämä API:t auttavat rakentamaan ResNet-mallin arkkitehtuuria.

Koodi: Kirjastojen tuonti

# 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>

Vaihe 2: Nyt asetamme erilaisia ​​hyperparametreja, joita tarvitaan ResNet-arkkitehtuurille. Teimme myös esikäsittelyä tietojoukollemme valmistellaksemme sitä koulutusta varten.

Koodi: Harjoittelun hyperparametrien asettaminen

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)>

>

>

Vaihe 3: Tässä vaiheessa asetamme oppimisnopeuden aikakausien lukumäärän mukaan. Epookkien lukumääränä oppimisnopeutta on vähennettävä paremman oppimisen varmistamiseksi.

Koodi: LR:n asettaminen eri jaksojen määrälle

python3




# Setting LR for different number of Epochs> def> lr_schedule(epoch):> >lr>=> 1e>->3> >if> epoch>>>:> >lr>*>=> 0.5e>->3> >elif> epoch>>>:> >lr>*>=> 1e>->3> >elif> epoch>>>:> >lr>*>=> 1e>->2> >elif> epoch>>>:> >lr>*>=> 1e>->1> >print>(>'Learning rate: '>, lr)> >return> lr>

javan perusteet

>

>

Vaihe 4: Määrittele ResNet-perusrakennuspalikka, jota voidaan käyttää ResNet V1- ja V2-arkkitehtuurin määrittämiseen.

Koodi: ResNetin perusrakennuspalikka

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>

>

>

Vaihe 5: Määritä ResNet V1 -arkkitehtuuri, joka perustuu edellä määrittämäämme ResNet-rakennuslohkoon:

Koodi: ResNet V1 -arkkitehtuuri

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>

>

>

Vaihe 6: Määritä ResNet V2 -arkkitehtuuri, joka perustuu edellä määrittämäämme ResNet-rakennuslohkoon:

Koodi: ResNet V2 -arkkitehtuuri

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>

>

>

Vaihe 7: Alla olevaa koodia käytetään yllä määrittämämme ResNet v1- ja v2-arkkitehtuurin kouluttamiseen ja testaamiseen:

t varvastossu

Koodi: Päätoiminto

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>])>

>

>

Tulokset ja johtopäätökset:
ImageNet-tietojoukossa kirjoittajat käyttävät 152-kerroksista ResNetiä, joka on 8 kertaa syvempi kuin VGG19, mutta jossa on silti vähemmän parametreja. Näiden ResNet-laitteiden kokonaisuus tuotti vain 3,7 %:n virheen ImageNet-testisarjassa, joka voitti ILSVRC 2015 -kilpailun. COCO-objektien tunnistustietojoukossa se tuottaa myös 28 %:n suhteellisen parannuksen erittäin syvän esityksensä ansiosta.

ResNet Architecturen virheprosentti

  • Yllä oleva tulos osoittaa, että pikaliitännät pystyisivät ratkaisemaan kerrosten lisäämisen aiheuttaman ongelman, koska kun nostamme tasoja 18:sta 34:ään, myös ImageNet Validation Setin virheprosentti pienenee toisin kuin tavallisessa verkossa.

Top-1 ja Top-5 Virheprosentti ImageNet Validation Setissä.

  • Alla ovat ImageNet Test Setin tulokset. The 3,57 % ResNetin viiden parhaan virheprosentti oli alhaisin ja siten ResNet-arkkitehtuuri oli ensimmäinen ImageNet-luokitushaasteessa vuonna 2015.