Tutorial: entrenamiento de un modelo ML.NET de clasificación para clasificar imágenes
Aprenda a entrenar un modelo de clasificación para clasificar imágenes mediante un modelo de TensorFlow entrenado previamente para el procesamiento de imágenes.
El modelo de TensorFlow se entrenó para clasificar las imágenes en mil categorías. Dado que el modelo de TensorFlow sabe cómo reconocer patrones en imágenes, el modelo ML.NET puede hacer uso de parte de él en su canalización para convertir imágenes sin procesar en características o entradas para entrenar un modelo de clasificación.
En este tutorial aprenderá a:
- Entender el problema
- Incorporación del modelo de TensorFlow entrenado previamente en la canalización de ML.NET
- Entrenamiento y evaluación del modelo de ML.NET
- Clasificación de una imagen de prueba
Puede encontrar el código fuente para este tutorial en el repositorio dotnet/samples. De forma predeterminada, la configuración del proyecto de .NET de este tutorial tiene como destino .NET Core 2.2.
Requisitos previos
- Visual Studio 2022
- El archivo ZIP del directorio de recursos del tutorial
- El modelo de Machine Learning de InceptionV1
Selección de la tarea de aprendizaje automático adecuada
Aprendizaje profundo
El aprendizaje profundo es un subconjunto de Machine Learning, que está revolucionando áreas como Computer Vision y reconocimiento de voz.
Los modelos de aprendizaje profundo se entrenan mediante el uso de grandes conjuntos de datos etiquetados y redes neuronales que contienen varias capas de conocimiento. Aprendizaje profundo:
- Funciona mejor en algunas tareas como Computer Vision.
- Requiere enormes cantidades de datos de entrenamiento.
La clasificación de imágenes es una tarea que nos permite clasificar imágenes automáticamente en categorías como:
- Detectar o no una cara humana en una imagen.
- Detectar gatos o perros.
O bien, como en las imágenes siguientes, determinar si una imagen es un alimento, un juguete o un dispositivo:
Nota
Las imágenes anteriores pertenecen a Wikimedia Commons y tienen los siguientes atributos:
- "220px-Pepperoni_pizza.jpg" de dominio público, https://commons.wikimedia.org/w/index.php?curid=79505,
- "119px-Nalle_-_a_small_brown_teddy_bear.jpg" de Jonik, autofotografía, CC BY-SA 2.0, https://commons.wikimedia.org/w/index.php?curid=48166.
- "193px-Broodrooster.jpg" de M.Minderhoud, trabajo propio, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=27403
Entrenar un modelo de clasificación de imágenes desde cero requiere establecer millones de parámetros, una enorme cantidad de datos de aprendizaje etiquetados y una gran cantidad de recursos informáticos (cientos de horas de GPU). Si bien no es tan eficaz como entrenar un modelo entrenado previamente, el aprendizaje por transferencia permite acortar este proceso al trabajar con miles de imágenes frente a millones de imágenes etiquetadas y crear un modelo personalizado con bastante rapidez (menos de una hora en una máquina sin GPU). En este tutorial se amplía aún más ese proceso, con solo una docena de imágenes de aprendizaje.
Inception model
está entrenado para clasificar imágenes en miles de categorías, pero, en este tutorial, el usuario deberá clasificar las imágenes en un conjunto de categorías más pequeño y solo en esas categorías. Puede usar la capacidad de Inception model
para reconocer y clasificar imágenes en las nuevas categorías limitadas del clasificador personalizado de imágenes.
- Alimentos
- Juguetes
- Dispositivos
En este tutorial se usa el modelo de aprendizaje profundo del Inicio de TensorFlow, un modelo de reconocimiento de imágenes popular entrenado en el conjunto de datos ImageNet
. El modelo de TensorFlow clasifica imágenes completas en miles de clases como "Paraguas", "Jersey" y "Lavavajillas".
Como Inception model
se ha entrenado previamente en miles de imágenes distintas, contiene internamente las características de imagen necesarias para la identificación de imágenes. Podemos usar estas características de imagen internas en el modelo para entrenar un modelo nuevo con muchas menos clases.
Como se muestra en el diagrama siguiente, puede agregar una referencia a los paquetes NuGet de ML.NET en las aplicaciones de .NET Core o .NET Framework. En segundo plano, ML.NET incluye y hace referencia a la biblioteca nativa de TensorFlow
que permite escribir código que carga un archivo de modelo de TensorFlow
entrenado existente.
Clasificación multiclase
Después de usar el modelo de inicio de TensorFlow para extraer características adecuadas como entrada para un algoritmo de aprendizaje automático clásico, se agrega un clasificador multiclase de ML.NET.
El entrenador específico que se usa en este caso es el algoritmo de regresión logística multinomial.
El algoritmo que implementa este entrenador funciona con un gran número de características, que es el caso de un modelo de aprendizaje profundo que funciona con datos de imagen.
Consulte Aprendizaje profundo frente a aprendizaje automático para obtener más información.
Datos
Hay dos orígenes de datos: el archivo .tsv
y los archivos de imagen. El archivo tags.tsv
contiene dos columnas: la primera está definida como ImagePath
y la segunda es la Label
que corresponde a la imagen. El archivo de ejemplo siguiente no tiene una fila de encabezado y se ve así:
broccoli.jpg food
pizza.jpg food
pizza2.jpg food
teddy2.jpg toy
teddy3.jpg toy
teddy4.jpg toy
toaster.jpg appliance
toaster2.png appliance
Las imágenes de entrenamiento y prueba se encuentran en las carpetas de recursos que descargará en un archivo ZIP. Estas imágenes pertenecen a Wikimedia Commons.
Wikimedia Commons, el repositorio multimedia gratuito. Recuperado a las 10:48 del 17 de octubre de 2018 desde: https://commons.wikimedia.org/wiki/Pizzahttps://commons.wikimedia.org/wiki/Toasterhttps://commons.wikimedia.org/wiki/Teddy_bear
Programa de instalación
Crear un proyecto
Cree una aplicación de consola en C# llamada "TransferLearningTF". Haga clic en el botón Next (Siguiente).
Seleccione .NET 6 como marco de trabajo que va a usarse. Haga clic en el botón Crear.
Instale el paquete NuGet Microsoft.ML:
Nota
En este ejemplo se usa la versión estable más reciente de los paquetes NuGet mencionados, a menos que se indique lo contrario.
- En el Explorador de soluciones, haga clic con el botón derecho en Administrar paquetes NuGet.
- Elija "nuget.org" como origen del paquete, seleccione la pestaña Examinar y busque Microsoft.ML.
- Seleccione el botón Instalar.
- Seleccione el botón Aceptar en el cuadro de diálogo Vista previa de los cambios.
- Haga clic en el botón Acepto en el cuadro de diálogo Aceptación de la licencia si está de acuerdo con los términos de licencia de los paquetes que aparecen.
- Repita estos pasos para Microsoft.ML.ImageAnalytics, SciSharp.TensorFlow.Redist y Microsoft.ML.TensorFlow.
Descarga de activos
Descargue el archivo ZIP del directorio de recursos del proyecto y descomprímalo.
Copie el directorio
assets
en el directorio de proyecto TransferLearningTF. Este directorio y sus subdirectorios contienen los datos y los archivos auxiliares (excepto los del modelo de inicio, que descargará y agregará en el paso siguiente) que se necesitan en este tutorial.Descargue el modelo de inicio y descomprímalo.
Copie el contenido del directorio
inception5h
que acaba de descomprimir en el directorioassets/inception
del proyecto TransferLearningTF. En este directorio está el modelo y los archivos auxiliares adicionales que se necesitan en este tutorial, tal como se muestra en la imagen siguiente:En el Explorador de soluciones, haga clic con el botón derecho en cada uno de los archivos del directorio de recursos y los subdirectorios y seleccione Propiedades. En Avanzadas, cambie el valor de Copiar en el directorio de salida por Copiar si es posterior.
Crear clases y definir rutas de acceso
Agregue las siguientes instrucciones
using
adicionales a la parte superior del archivo Program.cs:using Microsoft.ML; using Microsoft.ML.Data;
Agregue el código siguiente a la línea justo debajo de las instrucciones using para especificar las rutas de acceso del recurso:
string _assetsPath = Path.Combine(Environment.CurrentDirectory, "assets"); string _imagesFolder = Path.Combine(_assetsPath, "images"); string _trainTagsTsv = Path.Combine(_imagesFolder, "tags.tsv"); string _testTagsTsv = Path.Combine(_imagesFolder, "test-tags.tsv"); string _predictSingleImage = Path.Combine(_imagesFolder, "toaster3.jpg"); string _inceptionTensorFlowModel = Path.Combine(_assetsPath, "inception", "tensorflow_inception_graph.pb");
Cree clases para los datos de entrada y las predicciones.
public class ImageData { [LoadColumn(0)] public string? ImagePath; [LoadColumn(1)] public string? Label; }
ImageData
es la clase de datos de imagen de entrada y tiene los campos String siguientes:ImagePath
contiene el nombre del archivo de imagen.Label
contiene un valor para la etiqueta de imagen.
Agregue una clase nueva al proyecto para
ImagePrediction
:public class ImagePrediction : ImageData { public float[]? Score; public string? PredictedLabelValue; }
ImagePrediction
es la clase de predicción de imagen y tiene los campos siguientes:Score
contiene el porcentaje de confianza de una clasificación de imágenes determinada.PredictedLabelValue
contiene un valor para la etiqueta de clasificación de imágenes prevista.
ImagePrediction
es la clase usada para la predicción una vez entrenado el modelo. Tiene unastring
(ImagePath
) para la ruta de acceso a la imagen.Label
se usa para reutilizar y entrenar el modelo.PredictedLabelValue
se usa durante la predicción y la evaluación. Para la evaluación, se utiliza una entrada con los datos de entrenamiento, los valores de predicción y el modelo.
Inicialización de variables
Inicialice la variable
mlContext
con una instancia nueva deMLContext
. Reemplace la líneaConsole.WriteLine("Hello World!")
por el código siguiente:MLContext mlContext = new MLContext();
La clase MLContext es un punto de partida para todas las operaciones de ML.NET. Al inicializar
mlContext
se crea un entorno de ML.NET que se puede compartir entre los objetos del flujo de trabajo de creación de modelos. Como concepto, se parece aDBContext
en Entity Framework.
Creación de una estructura para los parámetros del modelo de inicio
El modelo de inicio tiene varios parámetros que se deben transmitir. Cree una estructura para asignar los valores de parámetros a nombres descriptivos con el código siguiente, justo después de inicializar la variable
mlContext
:struct InceptionSettings { public const int ImageHeight = 224; public const int ImageWidth = 224; public const float Mean = 117; public const float Scale = 1; public const bool ChannelsLast = true; }
Crear un método de utilidad para mostrar
Dado que se mostrarán los datos de imagen y las predicciones relacionadas más de una vez, cree un método de utilidad para mostrar a fin de controlar la visualización de los resultados de la imagen y la predicción.
Cree el método
DisplayResults()
justo después de la estructuraInceptionSettings
con el código siguiente:void DisplayResults(IEnumerable<ImagePrediction> imagePredictionData) { }
Rellene el cuerpo del método
DisplayResults
:foreach (ImagePrediction prediction in imagePredictionData) { Console.WriteLine($"Image: {Path.GetFileName(prediction.ImagePath)} predicted as: {prediction.PredictedLabelValue} with score: {prediction.Score?.Max()} "); }
Creación de un método para hacer una predicción
Cree el método
ClassifySingleImage()
, justo antes del métodoDisplayResults()
, mediante el código siguiente:void ClassifySingleImage(MLContext mlContext, ITransformer model) { }
Cree un objeto
ImageData
que contenga la ruta de acceso completa y el nombre del archivo de imagen para laImagePath
única. Agregue el código siguiente como las siguientes líneas en el métodoClassifySingleImage()
:var imageData = new ImageData() { ImagePath = _predictSingleImage };
Para hacer una predicción única, agregue el código siguiente como la línea siguiente en el método
ClassifySingleImage
:// Make prediction function (input = ImageData, output = ImagePrediction) var predictor = mlContext.Model.CreatePredictionEngine<ImageData, ImagePrediction>(model); var prediction = predictor.Predict(imageData);
Para obtener la predicción, use el método Predict(). PredictionEngine es una API de conveniencia, que le permite realizar una predicción en una única instancia de datos.
PredictionEngine
no es seguro para subprocesos. Es aceptable usarlo en entornos de un solo subproceso o prototipo. Para mejorar el rendimiento y la seguridad para subprocesos en entornos de producción, use el servicioPredictionEnginePool
, que crea unObjectPool
de objetos dePredictionEngine
para su uso en toda la aplicación. Consulte esta guía sobre cómo usarPredictionEnginePool
en una API web de ASP.NET Core.Nota
La extensión del servicio
PredictionEnginePool
está actualmente en versión preliminar.Muestre el resultado de la predicción como la línea de código siguiente en el método
ClassifySingleImage()
:Console.WriteLine($"Image: {Path.GetFileName(imageData.ImagePath)} predicted as: {prediction.PredictedLabelValue} with score: {prediction.Score?.Max()} ");
Construcción de la canalización del modelo de ML.NET
Una canalización del modelo de ML.NET es una cadena de estimadores. No se produce ninguna ejecución durante la construcción de la canalización. Se crean los objetos del estimador, pero no se ejecutan.
Agregue un método para generar el modelo
Este método es la parte central del tutorial. Crea una canalización para el modelo y entrena la canalización para generar el modelo de ML.NET. También evalúa el modelo con respecto a algunos datos de prueba previamente desconocidos.
Cree el método
GenerateModel()
justo después de la estructuraInceptionSettings
y antes del métodoDisplayResults()
con el código siguiente:ITransformer GenerateModel(MLContext mlContext) { }
Agregue los estimadores para cargar, cambiar el tamaño y extraer los píxeles de los datos de la imagen:
IEstimator<ITransformer> pipeline = mlContext.Transforms.LoadImages(outputColumnName: "input", imageFolder: _imagesFolder, inputColumnName: nameof(ImageData.ImagePath)) // The image transforms transform the images into the model's expected format. .Append(mlContext.Transforms.ResizeImages(outputColumnName: "input", imageWidth: InceptionSettings.ImageWidth, imageHeight: InceptionSettings.ImageHeight, inputColumnName: "input")) .Append(mlContext.Transforms.ExtractPixels(outputColumnName: "input", interleavePixelColors: InceptionSettings.ChannelsLast, offsetImage: InceptionSettings.Mean))
Los datos de la imagen se deben procesar en el formato que el modelo de TensorFlow espera. En este caso, las imágenes se cargan en la memoria, se cambia el tamaño a un tamaño coherente y los píxeles se extraen en un vector numérico.
Agregue el estimador para cargar el modelo de TensorFlow y puntúelo:
.Append(mlContext.Model.LoadTensorFlowModel(_inceptionTensorFlowModel). ScoreTensorFlowModel(outputColumnNames: new[] { "softmax2_pre_activation" }, inputColumnNames: new[] { "input" }, addBatchDimensionInput: true))
Esta fase de la canalización carga el modelo de TensorFlow en la memoria y, a continuación, procesa el vector de valores de píxeles a través de la red del modelo de TensorFlow. La aplicación de entradas a un modelo de aprendizaje profundo y la generación de una salida mediante el modelo se conoce como Puntuación. Al utilizar el modelo en su totalidad, la puntuación hace una inferencia o predicción.
En este caso, se usa todo el modelo de TensorFlow, excepto la última capa, que es la que realiza la inferencia. El resultado de la penúltima capa tiene la etiqueta
softmax_2_preactivation
. La salida de esta capa es, de hecho, un vector de las características que caracterizan las imágenes de entrada originales.Este vector de características generado por el modelo de TensorFlow se usará como entrada para un algoritmo de aprendizaje de ML.NET.
Agregue el estimador para asignar las etiquetas de cadena en los datos de entrenamiento a los valores de clave entera:
.Append(mlContext.Transforms.Conversion.MapValueToKey(outputColumnName: "LabelKey", inputColumnName: "Label"))
El entrenador de ML.NET que se anexa a continuación requiere que sus etiquetas estén en formato
key
en lugar de cadenas arbitrarias. Una clave es un número que tiene una asignación de uno a uno a un valor de cadena.Agregue el algoritmo de aprendizaje de ML.NET:
.Append(mlContext.MulticlassClassification.Trainers.LbfgsMaximumEntropy(labelColumnName: "LabelKey", featureColumnName: "softmax2_pre_activation"))
Agregue el estimador para asignar el valor de clave de predicción a una cadena:
.Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabelValue", "PredictedLabel")) .AppendCacheCheckpoint(mlContext);
Entrenar el modelo
Cargue los datos de entrenamiento con el contenedor LoadFromTextFile. Agregue el siguiente código como la siguiente línea en el método
GenerateModel()
:IDataView trainingData = mlContext.Data.LoadFromTextFile<ImageData>(path: _trainTagsTsv, hasHeader: false);
Los datos de ML.NET se representan como una interfaz IDataView.
IDataView
es una manera flexible y eficiente de describir datos tabulares (numéricos y de texto). Los datos se pueden cargar desde un archivo de texto o en tiempo real (por ejemplo, archivos de registro o base de datos SQL) en un objetoIDataView
.Entrene el modelo con los datos cargados anteriormente:
ITransformer model = pipeline.Fit(trainingData);
El método
Fit()
entrena el modelo mediante la aplicación del conjunto de datos de entrenamiento a la canalización.
Evaluación de la precisión del modelo
Cargue y transforme los datos de prueba agregando el código siguiente a la siguiente línea del método
GenerateModel
:IDataView testData = mlContext.Data.LoadFromTextFile<ImageData>(path: _testTagsTsv, hasHeader: false); IDataView predictions = model.Transform(testData); // Create an IEnumerable for the predictions for displaying results IEnumerable<ImagePrediction> imagePredictionData = mlContext.Data.CreateEnumerable<ImagePrediction>(predictions, true); DisplayResults(imagePredictionData);
Hay algunas imágenes de ejemplo que puede usar para evaluar el modelo. Al igual que los datos de entrenamiento, deben cargarse en
IDataView
, de modo que el modelo pueda transformarlos.Agregue el código siguiente al método
GenerateModel()
para evaluar el modelo:MulticlassClassificationMetrics metrics = mlContext.MulticlassClassification.Evaluate(predictions, labelColumnName: "LabelKey", predictedLabelColumnName: "PredictedLabel");
Una vez que establece la predicción, el método Evaluate():
- Evalúa el modelo (compara los valores previstos con el conjunto de datos
labels
de prueba). - Devuelve las métricas de rendimiento del modelo.
- Evalúa el modelo (compara los valores previstos con el conjunto de datos
Visualización de las métricas de precisión del modelo
Utilice el código siguiente para mostrar las métricas, compartir los resultados y, a continuación, trabajar con ellos:
Console.WriteLine($"LogLoss is: {metrics.LogLoss}"); Console.WriteLine($"PerClassLogLoss is: {String.Join(" , ", metrics.PerClassLogLoss.Select(c => c.ToString()))}");
Las siguiente métricas se evalúan para la clasificación de imágenes:
Log-loss
: consulte Pérdida de registro. Le recomendamos que la pérdida logarítmica esté lo más cerca posible de 0.Per class Log-loss
. Le recomendamos que la pérdida logarítmica por clase esté lo más cerca posible de 0.
Agregue el siguiente código para devolver el modelo entrenado, como la siguiente línea:
return model;
Ejecución de la aplicación
Agregue la llamada a
GenerateModel
después de la creación de la clase MLContext:ITransformer model = GenerateModel(mlContext);
Agregue la llamada al método
ClassifySingleImage()
después de la llamada al métodoGenerateModel()
:ClassifySingleImage(mlContext, model);
Ejecute la aplicación de consola (Ctrl + F5). Los resultados deberían ser similares a la salida siguiente. (Es posible que vea advertencias o mensajes de procesamiento, si bien se han quitado de los resultados siguientes para mayor claridad).
=============== Training classification model =============== Image: broccoli2.jpg predicted as: food with score: 0.8955513 Image: pizza3.jpg predicted as: food with score: 0.9667718 Image: teddy6.jpg predicted as: toy with score: 0.9797683 =============== Classification metrics =============== LogLoss is: 0.0653774699265059 PerClassLogLoss is: 0.110315812569315 , 0.0204391272836966 , 0 =============== Making single image classification =============== Image: toaster3.jpg predicted as: appliance with score: 0.9646884
¡Enhorabuena! Ahora ha creado correctamente un modelo de clasificación en ML.NET para clasificar imágenes mediante un TensorFlow entrenado previamente para el procesamiento de imágenes.
Puede encontrar el código fuente para este tutorial en el repositorio dotnet/samples.
En este tutorial ha aprendido a:
- Entender el problema
- Incorporación del modelo de TensorFlow entrenado previamente en la canalización de ML.NET
- Entrenamiento y evaluación del modelo de ML.NET
- Clasificación de una imagen de prueba
Consulte el repositorio de GitHub con ejemplos de Machine Learning para explorar un ejemplo expandido de clasificación de imágenes.