Después de que la primera arquitectura basada en CNN (AlexNet) ganara el concurso ImageNet 2012, cada arquitectura ganadora posterior utiliza más capas en una red neuronal profunda para reducir la tasa de error. Esto funciona para una menor cantidad de capas, pero cuando aumentamos la cantidad de capas, hay un problema común en el aprendizaje profundo asociado con lo que se llama gradiente de desaparición/explosión. Esto hace que el gradiente se vuelva 0 o demasiado grande. Por lo tanto, cuando aumentamos el número de capas, la tasa de error de entrenamiento y prueba también aumenta.

Comparación de la arquitectura de 20 capas frente a la de 56 capas
En el gráfico anterior, podemos observar que una CNN de 56 capas proporciona una mayor tasa de error tanto en el conjunto de datos de entrenamiento como en las de prueba que una arquitectura CNN de 20 capas. Después de analizar más la tasa de error, los autores pudieron llegar a la conclusión de que se debe a un gradiente que desaparece o explota.
ResNet, que fue propuesta en 2015 por investigadores de Microsoft Research, introdujo una nueva arquitectura llamada Red Residual.
Red Residual: Para resolver el problema del gradiente que desaparece/explota, esta arquitectura introdujo el concepto llamado Bloques Residuales. En esta red utilizamos una técnica llamada saltar conexiones . La conexión de salto conecta las activaciones de una capa con otras capas omitiendo algunas capas intermedias. Esto forma un bloque residual. Los resnets se crean apilando estos bloques residuales.
El enfoque detrás de esta red es que, en lugar de que las capas aprendan el mapeo subyacente, permitimos que la red se ajuste al mapeo residual. Entonces, en lugar de decir H(x), el mapeo inicial , deja que la red encaje,
F(x) := H(x) - x which gives H(x) := F(x) + x .>

Saltar conexión (atajo)
La ventaja de agregar este tipo de conexión de omisión es que si alguna capa perjudica el rendimiento de la arquitectura, la regularización la omitirá. Entonces, esto da como resultado el entrenamiento de una red neuronal muy profunda sin los problemas causados por el gradiente que desaparece o explota. Los autores del artículo experimentaron con entre 100 y 1000 capas del conjunto de datos CIFAR-10.
Existe un enfoque similar llamado redes de autopistas, estas redes también utilizan conexiones de salto. Al igual que LSTM, estas conexiones de salto también utilizan puertas paramétricas. Estas puertas determinan cuánta información pasa a través de la conexión de omisión. Sin embargo, esta arquitectura no ha proporcionado una precisión mejor que la arquitectura ResNet.
Red de arquitectura: Esta red utiliza una arquitectura de red simple de 34 capas inspirada en VGG-19 en la que luego se agrega la conexión de acceso directo. Estas conexiones de acceso directo convierten la arquitectura en una red residual.

Arquitectura ResNet-34
Implementación: Usando Tensorflow y Keras API, podemos diseñar la arquitectura ResNet (incluidos los bloques residuales) desde cero. A continuación se muestra la implementación de diferentes arquitecturas ResNet. Para esta implementación, utilizamos el conjunto de datos CIFAR-10. Este conjunto de datos contiene 60.000 imágenes en color de 32 × 32 en 10 clases diferentes (aviones, automóviles, pájaros, gatos, ciervos, perros, ranas, caballos, barcos y camiones), etc. Este conjunto de datos se puede evaluar a partir de k eras.conjuntos de datos Función API.
Paso 1: Primero, importamos el módulo keras y sus API. Estas API ayudan a construir la arquitectura del modelo ResNet.
Código: Importando bibliotecas
# 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>
Paso 2: Ahora, configuramos diferentes hiperparámetros necesarios para la arquitectura ResNet. También hicimos un preprocesamiento en nuestro conjunto de datos para prepararlo para el entrenamiento.
Código: Configuración de hiperparámetros de entrenamiento
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)> |
java concatenar cadenas
>
>
Paso 3: En este paso, establecemos la tasa de aprendizaje según el número de épocas. A medida que aumenta el número de épocas, la tasa de aprendizaje debe disminuir para garantizar un mejor aprendizaje.
Código: Configuración de LR para diferentes números de épocas
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> |
>
>
Etapa 4: Defina el bloque de construcción básico de ResNet que se puede utilizar para definir la arquitectura ResNet V1 y V2.
Código: Bloque de construcción básico de 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> |
>
>
Paso 5: Defina la arquitectura ResNet V1 que se basa en el bloque de construcción ResNet que definimos anteriormente:
Código: Arquitectura ResNet V1
python3
git pull origen maestro
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> |
>
>
Paso 6: Defina la arquitectura ResNet V2 que se basa en el bloque de construcción ResNet que definimos anteriormente:
Código: Arquitectura 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> |
>
>
Paso 7: El siguiente código se utiliza para entrenar y probar la arquitectura ResNet v1 y v2 que definimos anteriormente:
Código: Función principal
python3
tabla hash 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>])> |
>
>
Resultados y conclusión:
En el conjunto de datos ImageNet, los autores utilizan un ResNet de 152 capas, que es 8 veces más profundo que VGG19 pero aún tiene menos parámetros. Un conjunto de estos ResNets generó un error de solo el 3,7% en el conjunto de pruebas de ImageNet, resultado que ganó la competencia ILSVRC 2015. En el conjunto de datos de detección de objetos COCO, también genera una mejora relativa del 28% debido a su representación muy profunda.

Tasa de errores en la arquitectura ResNet
- El resultado anterior muestra que las conexiones de acceso directo podrían resolver el problema causado por el aumento de las capas porque a medida que aumentamos las capas de 18 a 34, la tasa de error en el Conjunto de validación de ImageNet también disminuye a diferencia de la red simple.

Tasa de error top-1 y top-5 en el conjunto de validación de ImageNet.
- A continuación se muestran los resultados del conjunto de pruebas de ImageNet. El 3.57% La tasa de error entre los 5 primeros de ResNet fue la más baja y, por lo tanto, la arquitectura ResNet ocupó el primer lugar en el desafío de clasificación de ImageNet en 2015.
