Main Content

Entrenar redes de deep learning para clasificar nuevas imágenes

Este ejemplo muestra cómo usar la transferencia del aprendizaje para volver a entrenar una red neuronal convolucional para clasificar un nuevo conjunto de imágenes.

Las redes de clasificación de imágenes preentrenadas se han entrenado con más de un millón de imágenes y pueden clasificarlas en 1000 categorías de objetos, como teclado, taza de café, lápiz y muchos animales. Las redes han aprendido representaciones ricas en características para una amplia gama de imágenes. La red toma una imagen como entrada y, a continuación, emite una etiqueta para el objeto de la imagen junto con las probabilidades de cada una de las categorías de objetos.

La transferencia del aprendizaje se suele usar en aplicaciones de deep learning. Se puede usar una red preentrenada como punto de partida para aprender una nueva tarea. Ajustar una red con transferencia del aprendizaje suele ser más rápido y fácil que entrenarla de cero con pesos inicializados al azar. Puede transferir de forma rápida las características aprendidas a una nueva tarea con menos imágenes de entrenamiento.

Cargar datos

Descomprima y cargue las nuevas imágenes como un almacén de datos de imágenes. Este pequeño conjunto de datos contiene solo 75 imágenes. Divida los datos en conjuntos de datos de entrenamiento y de validación. Utilice el 70% de las imágenes para el entrenamiento y el 30% para la validación.

unzip('MerchData.zip');
imds = imageDatastore('MerchData', ...
    'IncludeSubfolders',true, ...
    'LabelSource','foldernames'); 
[imdsTrain,imdsValidation] = splitEachLabel(imds,0.7);

Cargar una red preentrenada

Cargue una red GoogLeNet preentrenada. Si no se ha instalado el paquete de soporte Deep Learning Toolbox™ Model for GoogLeNet Network, el software proporciona un enlace de descarga.

Para probar otra red preentrenada, abra este ejemplo en MATLAB® y seleccione una diferente. Por ejemplo, puede probar squeezenet, una red que es incluso más rápida que googlenet. Puede llevar a cabo el ejemplo con más redes preentrenadas. Para obtener una lista de todas las redes disponibles, consulte Load Pretrained Networks.

net = googlenet;

Utilice analyzeNetwork para obtener una visualización interactiva de la arquitectura de la red e información detallada sobre sus capas.

analyzeNetwork(net)

El primer elemento de la propiedad Layers de la red es la capa de entrada de la imagen. Para una red GoogLeNet, esta capa requiere imágenes de entrada de un tamaño de 224 por 224 por 3, donde 3 es el número de canales de color. Otras redes pueden requerir imágenes de entrada con diferentes tamaños. Por ejemplo, la red Xception requiere imágenes de un tamaño de 299 por 299 por 3.

net.Layers(1)
ans = 
  ImageInputLayer with properties:

                      Name: 'data'
                 InputSize: [224 224 3]

   Hyperparameters
          DataAugmentation: 'none'
             Normalization: 'zerocenter'
    NormalizationDimension: 'auto'
                      Mean: [224×224×3 single]

inputSize = net.Layers(1).InputSize;

Sustituir capas finales

Las capas convolucionales de la red extraen características de la imagen que la última capa de aprendizaje y la capa de clasificación final utilizan para clasificar la imagen de entrada. Estas dos capas, 'loss3-classifier' y 'output' en GoogLeNet, contienen información sobre cómo combinar las características que la red extrae en probabilidades de clase, un valor de pérdida y etiquetas predichas. Para volver a entrenar una red preentrenada para clasificar nuevas imágenes, hay que sustituir estas dos capas por otras adaptadas al nuevo conjunto de datos.

Convierta la red entrenada en una gráfica de capas.

lgraph = layerGraph(net);

Busque los nombres de las dos capas que ha de sustituir. Puede hacerlo manualmente o puede utilizar la función de ayuda findLayersToReplace para encontrar estas capas automáticamente.

[learnableLayer,classLayer] = findLayersToReplace(lgraph);
[learnableLayer,classLayer] 
ans = 
  1×2 Layer array with layers:

     1   'loss3-classifier'   Fully Connected         1000 fully connected layer
     2   'output'             Classification Output   crossentropyex with 'tench' and 999 other classes

En la mayoría de las redes, la última capa con pesos que se pueden aprender es una capa totalmente conectada. Sustitúyala por una nueva capa totalmente conectada con un número de salidas igual al número de clases del nuevo conjunto de datos (cinco en este ejemplo). En algunas redes, como SqueezeNet, la última capa que se puede aprender es una capa convolucional de 1 por 1. En este caso, sustitúyala por una nueva capa convolucional con un número de filtros igual al número de clases. Para aprender más rápido en la nueva capa que en las capas transferidas, aumente los factores de la tasa de aprendizaje de la capa.

numClasses = numel(categories(imdsTrain.Labels));

if isa(learnableLayer,'nnet.cnn.layer.FullyConnectedLayer')
    newLearnableLayer = fullyConnectedLayer(numClasses, ...
        'Name','new_fc', ...
        'WeightLearnRateFactor',10, ...
        'BiasLearnRateFactor',10);
    
elseif isa(learnableLayer,'nnet.cnn.layer.Convolution2DLayer')
    newLearnableLayer = convolution2dLayer(1,numClasses, ...
        'Name','new_conv', ...
        'WeightLearnRateFactor',10, ...
        'BiasLearnRateFactor',10);
end

lgraph = replaceLayer(lgraph,learnableLayer.Name,newLearnableLayer);

La capa de clasificación especifica las clases de salida de la red. Sustituya la capa de clasificación por una nueva sin etiquetas de clase. trainNetwork establece automáticamente las clases de salida de la capa en el momento del entrenamiento.

newClassLayer = classificationLayer('Name','new_classoutput');
lgraph = replaceLayer(lgraph,classLayer.Name,newClassLayer);

Para comprobar que las nuevas capas están conectadas correctamente, represente la gráfica de las nuevas capas y amplíe las últimas capas de la red.

figure('Units','normalized','Position',[0.3 0.3 0.4 0.4]);
plot(lgraph)
ylim([0,10])

Congelar las capas iniciales

La red está ahora lista para volver a entrenarla con el nuevo conjunto de imágenes. Opcionalmente, puede "congelar" los pesos de las capas anteriores de la red estableciendo las tasas de aprendizaje de esas capas en cero. Durante el entrenamiento, trainNetwork no actualiza los parámetros de las capas congeladas. Como no es necesario calcular los gradientes de las capas congeladas, la congelación de los pesos de muchas capas iniciales puede acelerar de forma considerable el entrenamiento de la red. Si el nuevo conjunto de datos es pequeño, congelar las capas anteriores de la red también puede evitar que esas capas se sobreajusten al nuevo conjunto de datos.

Extraiga las capas y las conexiones de la gráfica de capas y seleccione las capas que desea congelar. En GoogLeNet, las 10 primeras capas constituyen el "tallo" inicial de la red. Utilice la función de ayuda freezeWeights para establecer en cero los índices de aprendizaje en las primeras diez capas. Utilice la función de ayuda createLgraphUsingConnections para volver a conectar todas las capas en el orden original. La nueva gráfica de capas contiene las mismas capas, pero con las tasas de aprendizaje de las capas anteriores establecidas en cero.

layers = lgraph.Layers;
connections = lgraph.Connections;

layers(1:10) = freezeWeights(layers(1:10));
lgraph = createLgraphUsingConnections(layers,connections);

Entrenar la red

La red requiere imágenes de entrada de un tamaño de 224 por 224 por 3, pero las imágenes del almacén de datos de imágenes tienen diferentes tamaños. Utilice un almacén de datos de imágenes aumentado para cambiar automáticamente el tamaño de las imágenes de entrenamiento. Especifique operaciones de aumento adicionales que realizar en las imágenes de entrenamiento: voltear aleatoriamente las imágenes de entrenamiento a lo largo del eje vertical y trasladarlas aleatoriamente hasta 30 píxeles y escalarlas hasta un 10% horizontal y verticalmente. El aumento de datos ayuda a evitar que la red se sobreajuste y memorice los detalles exactos de las imágenes de entrenamiento.

pixelRange = [-30 30];
scaleRange = [0.9 1.1];
imageAugmenter = imageDataAugmenter( ...
    'RandXReflection',true, ...
    'RandXTranslation',pixelRange, ...
    'RandYTranslation',pixelRange, ...
    'RandXScale',scaleRange, ...
    'RandYScale',scaleRange);
augimdsTrain = augmentedImageDatastore(inputSize(1:2),imdsTrain, ...
    'DataAugmentation',imageAugmenter);

Para cambiar el tamaño de las imágenes de validación de forma automática sin realizar más aumentos de datos, utilice un almacén de datos de imágenes aumentadas sin especificar ninguna operación adicional de preprocesamiento.

augimdsValidation = augmentedImageDatastore(inputSize(1:2),imdsValidation);

Especifique las opciones de entrenamiento. Establezca InitialLearnRate en un valor pequeño para ralentizar el aprendizaje en las capas transferidas que todavía no se han congelado. En el paso anterior, aumentó los factores de la tasa de aprendizaje de la última capa que se puede aprender para acelerar el aprendizaje en las nuevas capas finales. Esta combinación de ajustes de la tasa de aprendizaje da como resultado un aprendizaje rápido en las nuevas capas, un aprendizaje más lento en las capas intermedias y ningún aprendizaje en las capas anteriores congeladas.

Especifique el número de épocas que entrenar. Al realizar la transferencia del aprendizaje, no es necesario entrenar durante tantas épocas. Una época es un ciclo de entrenamiento completo en el conjunto total de datos de entrenamiento. Especifique el tamaño del minilote y los datos de validación. Calcule la precisión de la validación una vez por época.

miniBatchSize = 10;
valFrequency = floor(numel(augimdsTrain.Files)/miniBatchSize);
options = trainingOptions('sgdm', ...
    'MiniBatchSize',miniBatchSize, ...
    'MaxEpochs',6, ...
    'InitialLearnRate',3e-4, ...
    'Shuffle','every-epoch', ...
    'ValidationData',augimdsValidation, ...
    'ValidationFrequency',valFrequency, ...
    'Verbose',false, ...
    'Plots','training-progress');

Entrene la red con los datos de entrenamiento. De forma predeterminada, trainNetwork usa GPU en caso de que esté disponible. Se requiere Parallel Computing Toolbox™ y un dispositivo GPU compatible. Para obtener información sobre los dispositivos compatibles, consulte GPU Computing Requirements (Parallel Computing Toolbox). De lo contrario, trainNetwork usa una CPU. También puede especificar el entorno de ejecución con el argumento de par nombre-valor 'ExecutionEnvironment' de trainingOptions. Como el conjunto de datos es tan pequeño, el entrenamiento es rápido.

net = trainNetwork(augimdsTrain,lgraph,options);

Clasificar imágenes de validación

Clasifique las imágenes de validación utilizando la red ajustada y calcule la precisión de la clasificación.

[YPred,probs] = classify(net,augimdsValidation);
accuracy = mean(YPred == imdsValidation.Labels)
accuracy = 0.9000

Visualice cuatro imágenes de validación de muestra con etiquetas predichas y las probabilidades predichas de que las imágenes tengan esas etiquetas.

idx = randperm(numel(imdsValidation.Files),4);
figure
for i = 1:4
    subplot(2,2,i)
    I = readimage(imdsValidation,idx(i));
    imshow(I)
    label = YPred(idx(i));
    title(string(label) + ", " + num2str(100*max(probs(idx(i),:)),3) + "%");
end

Referencias

[1] Szegedy, Christian, Wei Liu, Yangqing Jia, Pierre Sermanet, Scott Reed, Dragomir Anguelov, Dumitru Erhan, Vincent Vanhoucke, and Andrew Rabinovich. "Going deeper with convolutions." In Proceedings of the IEEE conference on computer vision and pattern recognition, pp. 1-9. 2015.

Consulte también

| | | | | | | | |

Temas relacionados