Dopo la prima architettura basata sulla CNN (AlexNet) che ha vinto il concorso ImageNet 2012, ogni architettura vincitrice successiva utilizza più strati in una rete neurale profonda per ridurre il tasso di errore. Funziona con un numero inferiore di livelli, ma quando aumentiamo il numero di livelli, si verifica un problema comune nel deep learning associato a quello chiamato gradiente di scomparsa/esplosione. Ciò fa sì che il gradiente diventi 0 o troppo grande. Pertanto, quando si aumenta il numero di livelli, aumenta anche il tasso di errore di addestramento e test.

Confronto tra l'architettura a 20 strati e quella a 56 strati
Nel grafico sopra, possiamo osservare che una CNN a 56 strati fornisce un tasso di errore maggiore sia sul set di dati di addestramento che su quello di test rispetto a un'architettura CNN a 20 strati. Dopo aver analizzato più a fondo il tasso di errore, gli autori sono stati in grado di giungere alla conclusione che è causato dal gradiente di scomparsa/esplosione.
ResNet, proposto nel 2015 dai ricercatori di Microsoft Research, ha introdotto una nuova architettura chiamata Residual Network.
Rete Residua: Per risolvere il problema del gradiente di scomparsa/esplosione, questa architettura ha introdotto il concetto chiamato Residual Blocks. In questa rete utilizziamo una tecnica chiamata saltare le connessioni . La connessione salta collega le attivazioni di un livello a ulteriori livelli saltando alcuni livelli intermedi. Questo forma un blocco residuo. I Resnet vengono realizzati impilando insieme questi blocchi residui.
L'approccio alla base di questa rete prevede che invece di strati che apprendono la mappatura sottostante, consentiamo alla rete di adattarsi alla mappatura residua. Quindi, invece di dire H(x), mappatura iniziale , lascia che la rete si adatti,
F(x) := H(x) - x which gives H(x) := F(x) + x .>

Salta la connessione (scorciatoia).
Il vantaggio di aggiungere questo tipo di connessione saltata è che se un livello danneggia le prestazioni dell'architettura, verrà saltato dalla regolarizzazione. Ciò si traduce quindi nell'addestramento di una rete neurale molto profonda senza i problemi causati dal gradiente di scomparsa/esplosione. Gli autori dell'articolo hanno sperimentato su 100-1000 livelli del set di dati CIFAR-10.
Esiste un approccio simile chiamato reti autostradali, anche queste reti utilizzano la connessione salta. Similmente a LSTM, anche queste connessioni skip utilizzano porte parametriche. Queste porte determinano la quantità di informazioni che passano attraverso la connessione skip. Questa architettura tuttavia non ha fornito una precisione migliore dell'architettura ResNet.
Architettura di rete: Questa rete utilizza un'architettura di rete semplice a 34 livelli ispirata a VGG-19 in cui viene poi aggiunta la connessione di scelta rapida. Queste connessioni rapide convertono quindi l'architettura in una rete residua.

Architettura ResNet-34
Implementazione: Utilizzando Tensorflow e Keras API, possiamo progettare da zero l'architettura ResNet (inclusi i Residual Blocks). Di seguito è riportata l'implementazione di diverse architetture ResNet. Per questa implementazione, utilizziamo il set di dati CIFAR-10. Questo set di dati contiene 60.000 immagini a colori 32×32 in 10 classi diverse (aerei, automobili, uccelli, gatti, cervi, cani, rane, cavalli, navi e camion), ecc. Questo set di dati può essere valutato da k eras.datasets Funzione API.
Passo 1: Per prima cosa importiamo il modulo Keras e le sue API. Queste API aiutano a costruire l'architettura del modello ResNet.
Codice: Importazione di librerie
# 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>
Passo 2: Ora impostiamo diversi parametri iper richiesti per l'architettura ResNet. Abbiamo anche eseguito alcune pre-elaborazioni sul nostro set di dati per prepararlo per l'addestramento.
Shloka Mehta
Codice: Impostazione degli iperparametri di addestramento
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)> |
>
>
Passaggio 3: In questo passaggio, impostiamo la velocità di apprendimento in base al numero di epoche. Poiché il numero di epoche è necessario ridurre il tasso di apprendimento per garantire un migliore apprendimento.
Codice: Impostazione LR per diversi numeri di epoche
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> |
>
sonu nigam
>
operatori nella programmazione Python
Passaggio 4: Definire il building block ResNet di base che può essere utilizzato per definire l'architettura ResNet V1 e V2.
Codice: Elemento costitutivo di base di 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> |
>
>
Passaggio 5: Definire l'architettura ResNet V1 basata sul building block ResNet definito sopra:
Codice: Architettura 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> |
>
>
10 alla potenza di 6
Passaggio 6: Definire l'architettura ResNet V2 basata sul building block ResNet definito sopra:
Codice: Architettura 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> |
>
>
Passaggio 7: Il codice seguente viene utilizzato per addestrare e testare l'architettura ResNet v1 e v2 definita sopra:
Codice: funzione principale
python3
coda di priorità Java
# 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>])> |
>
>
Risultati e conclusioni:
Sul set di dati ImageNet, gli autori utilizzano un ResNet a 152 livelli, che è 8 volte più profondo di VGG19 ma ha ancora meno parametri. Un insieme di questi ResNet ha generato un errore di solo il 3,7% sul set di test ImageNet, il risultato che ha vinto il concorso ILSVRC 2015. Sul set di dati di rilevamento oggetti COCO, genera anche un miglioramento relativo del 28% grazie alla sua rappresentazione molto profonda.

Tasso di errore sull'architettura ResNet
- Il risultato sopra mostra che le connessioni di scelta rapida sarebbero in grado di risolvere il problema causato dall'aumento dei livelli perché aumentando i livelli da 18 a 34 diminuisce anche il tasso di errore su ImageNet Validation Set a differenza della rete semplice.

Tasso di errori principali 1 e principali 5 sul set di convalida ImageNet.
- Di seguito sono riportati i risultati su ImageNet Test Set. IL 3,57% il tasso di errore dei primi 5 di ResNet è stato il più basso e quindi l'architettura ResNet è arrivata prima nella sfida di classificazione di ImageNet nel 2015.
