Tutorial: Preparar um modelo de classificação de ML.NET para categorizar imagens
Saiba como preparar um modelo de classificação para categorizar imagens com um modelo do TensorFlow pré-preparado para processamento de imagens.
O modelo TensorFlow foi preparado para classificar imagens em mil categorias. Uma vez que o modelo tensorFlow sabe como reconhecer padrões em imagens, o modelo de ML.NET pode utilizar parte do mesmo no seu pipeline para converter imagens não processadas em funcionalidades ou entradas para preparar um modelo de classificação.
Neste tutorial, ficará a saber como:
- Compreender o problema
- Incorporar o modelo do TensorFlow pré-preparado no pipeline de ML.NET
- Preparar e avaliar o modelo de ML.NET
- Classificar uma imagem de teste
Pode encontrar o código fonte deste tutorial no repositório dotnet/samples . Por predefinição, a configuração do projeto .NET para este tutorial destina-se ao .NET Core 2.2.
Pré-requisitos
- Visual Studio 2022
- O ficheiro de .ZIP do diretório de recursos do tutorial
- O modelo de machine learning InceptionV1
Selecione a tarefa de machine learning correta
Aprendizagem aprofundada
A aprendizagem profunda é um subconjunto do Machine Learning, que está a revolucionar áreas como a imagem digitalizada e o reconhecimento de voz.
Os modelos de aprendizagem profunda são preparados através de grandes conjuntos de dados etiquetados e redes neurais que contêm várias camadas de aprendizagem. Aprendizagem profunda:
- Tem um melhor desempenho em algumas tarefas, como a imagem digitalizada.
- Requer enormes quantidades de dados de preparação.
A classificação de imagens é uma tarefa de classificação específica que nos permite classificar automaticamente imagens em categorias como:
- Detetar ou não um rosto humano numa imagem.
- Detetar gatos vs. cães.
Ou, tal como nas seguintes imagens, determinar se uma imagem é um alimento, um toy ou uma aplicação:
Nota
As imagens anteriores pertencem à Wikimedia Commons e são atribuídas da seguinte forma:
- Domínio Público "220px-Pepperoni_pizza.jpg", , https://commons.wikimedia.org/w/index.php?curid=79505
- "119px-Nalle_-_a_small_brown_teddy_bear.jpg" de Jonik - Auto-fotografado, CC BY-SA 2.0, https://commons.wikimedia.org/w/index.php?curid=48166.
- "193px-Broodrooster.jpg" By M.Minderhoud - Own work, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=27403
Preparar um modelo de classificação de imagens do zero requer a definição de milhões de parâmetros, uma tonelada de dados de preparação etiquetados e uma grande quantidade de recursos de computação (centenas de horas de GPU). Embora não seja tão eficaz como preparar um modelo personalizado de raiz, a utilização de um modelo pré-preparado permite-lhe atalho deste processo ao trabalhar com milhares de imagens vs. milhões de imagens etiquetadas e criar um modelo personalizado bastante rapidamente (dentro de uma hora num computador sem GPU). Este tutorial dimensiona ainda mais esse processo, utilizando apenas uma dezena de imagens de preparação.
O Inception model
é preparado para classificar imagens em mil categorias, mas para este tutorial, tem de classificar imagens num conjunto de categorias mais pequeno e apenas nessas categorias. Pode utilizar a Inception model
capacidade de reconhecer e classificar imagens para as novas categorias limitadas do classificador de imagens personalizadas.
- Comida
- Toy
- Aplicação
Este tutorial utiliza o modelo de aprendizagem profunda TensorFlow Inception , um modelo de reconhecimento de imagem popular preparado no ImageNet
conjunto de dados. O modelo TensorFlow classifica imagens inteiras em mil classes, como "Guarda-chuva", "Jersey" e "Máquina de Lavar Louça".
Uma vez que o Inception model
já foi pré-preparado em milhares de imagens diferentes, contém internamente as funcionalidades de imagem necessárias para a identificação de imagens. Podemos utilizar estas funcionalidades de imagem interna no modelo para preparar um novo modelo com muito menos classes.
Conforme mostrado no diagrama seguinte, adiciona uma referência aos pacotes NuGet ML.NET nas suas aplicações .NET Core ou .NET Framework. Nos limites, ML.NET inclui e referencia a biblioteca nativa TensorFlow
que lhe permite escrever código que carrega um ficheiro de modelo preparado TensorFlow
existente.
Classificação de várias classes
Depois de utilizar o modelo de criação do TensorFlow para extrair funcionalidades adequadas como entrada para um algoritmo de machine learning clássico, adicionamos um ML.NET classificador de várias classes.
O formador específico utilizado neste caso é o algoritmo de regressão logística multinomial.
O algoritmo implementado por este formador tem um bom desempenho em problemas com um grande número de funcionalidades, o que é o caso de um modelo de aprendizagem profunda que opera em dados de imagem.
Veja Aprendizagem profunda vs. machine learning para obter mais informações.
Dados
Existem duas origens de dados: o .tsv
ficheiro e os ficheiros de imagem. O tags.tsv
ficheiro contém duas colunas: a primeira é definida como ImagePath
e a segunda é a Label
correspondente à imagem. O ficheiro de exemplo seguinte não tem uma linha de cabeçalho e tem o seguinte aspeto:
broccoli.jpg food
pizza.jpg food
pizza2.jpg food
teddy2.jpg toy
teddy3.jpg toy
teddy4.jpg toy
toaster.jpg appliance
toaster2.png appliance
As imagens de preparação e teste estão localizadas nas pastas de recursos que irá transferir num ficheiro zip. Estas imagens pertencem à Wikimedia Commons.
Wikimedia Commons, o repositório de meios de comunicação gratuito. Obtido 10:48, 17 de outubro de 2018 a partir de: https://commons.wikimedia.org/wiki/Pizzahttps://commons.wikimedia.org/wiki/Toasterhttps://commons.wikimedia.org/wiki/Teddy_bear
Configuração
Criar um projeto
Crie uma Aplicação de Consola C# denominada "TransferLearningTF". Clique no botão Seguinte .
Selecione .NET 6 como a arquitetura a utilizar. Clique no botão Criar.
Instale o Pacote NuGet Microsoft.ML:
Nota
Este exemplo utiliza a versão estável mais recente dos pacotes NuGet mencionados, salvo indicação em contrário.
- No Explorador de Soluções, clique com o botão direito do rato no projeto e selecione Gerir Pacotes NuGet.
- Selecione "nuget.org" como origem do pacote, selecione o separador Procurar e procure Microsoft.ML.
- Selecione o botão Instalar .
- Selecione o botão OK na caixa de diálogo Pré-visualizar Alterações .
- Selecione o botão Aceito na caixa de diálogo Aceitação da Licença se concordar com os termos de licenciamento dos pacotes listados.
- Repita estes passos para Microsoft.ML.ImageAnalytics, SciSharp.TensorFlow.Redist e Microsoft.ML.TensorFlow.
Transferir recursos
Transfira o ficheiro zip do diretório de recursos do projeto e deszipe.
Copie o diretório para o
assets
diretório do projeto TransferLearningTF . Este diretório e os respetivos subdiretórios contêm os dados e os ficheiros de suporte (exceto o modelo Inception, que irá transferir e adicionar no próximo passo) necessários para este tutorial.Transfira o modelo Inception e deszipe.
Copie o conteúdo do
inception5h
diretório deszipado para o diretório de projetoassets/inception
TransferLearningTF. Este diretório contém o modelo e os ficheiros de suporte adicionais necessários para este tutorial, conforme mostrado na imagem seguinte:No Explorador de Soluções, clique com o botão direito do rato em cada um dos ficheiros no diretório de recursos e subdiretórios e selecione Propriedades. Em Avançadas, altere o valor de Copiar para Diretório de Saída para Copiar se for mais recente.
Criar classes e definir caminhos
Adicione as seguintes instruções adicionais
using
à parte superior do ficheiro Program.cs :using Microsoft.ML; using Microsoft.ML.Data;
Adicione o seguinte código à linha abaixo das instruções using para especificar os caminhos do 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");
Crie classes para os seus dados de entrada e predições.
public class ImageData { [LoadColumn(0)] public string? ImagePath; [LoadColumn(1)] public string? Label; }
ImageData
é a classe de dados de imagem de entrada e tem os seguintes String campos:ImagePath
contém o nome do ficheiro de imagem.Label
contém um valor para a etiqueta de imagem.
Adicione uma nova classe ao seu projeto para
ImagePrediction
:public class ImagePrediction : ImageData { public float[]? Score; public string? PredictedLabelValue; }
ImagePrediction
é a classe de predição de imagem e tem os seguintes campos:Score
contém a percentagem de confiança para uma determinada classificação de imagens.PredictedLabelValue
contém um valor para a etiqueta de classificação de imagens prevista.
ImagePrediction
é a classe utilizada para predição depois de o modelo ter sido preparado. Tem umstring
(ImagePath
) para o caminho da imagem. OLabel
é utilizado para reutilizar e preparar o modelo. OPredictedLabelValue
é utilizado durante a predição e avaliação. Para avaliação, é utilizada uma entrada com dados de preparação, os valores previstos e o modelo.
Inicializar variáveis
Inicialize a
mlContext
variável com uma nova instância deMLContext
. Substitua aConsole.WriteLine("Hello World!")
linha pelo seguinte código:MLContext mlContext = new MLContext();
A MLContext classe é um ponto de partida para todas as operações de ML.NET e inicializar
mlContext
cria um novo ambiente de ML.NET que pode ser partilhado entre os objetos de fluxo de trabalho de criação de modelos. É semelhante, conceptualmente, aDBContext
no Entity Framework.
Criar uma estrutura para parâmetros de modelo de Inception
O modelo Inception tem vários parâmetros que precisa de transmitir. Crie uma estrutura para mapear os valores dos parâmetros para nomes amigáveis com o seguinte código, logo após inicializar a
mlContext
variável: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; }
Criar um método de utilitário de apresentação
Uma vez que irá apresentar os dados da imagem e as predições relacionadas mais do que uma vez, crie um método de utilitário de apresentação para processar a apresentação dos resultados da imagem e da predição.
Crie o
DisplayResults()
método logo após aInceptionSettings
estrutura, com o seguinte código:void DisplayResults(IEnumerable<ImagePrediction> imagePredictionData) { }
Preencha o corpo do
DisplayResults
método:foreach (ImagePrediction prediction in imagePredictionData) { Console.WriteLine($"Image: {Path.GetFileName(prediction.ImagePath)} predicted as: {prediction.PredictedLabelValue} with score: {prediction.Score?.Max()} "); }
Criar um método para fazer uma predição
Crie o
ClassifySingleImage()
método, imediatamente antes doDisplayResults()
método, com o seguinte código:void ClassifySingleImage(MLContext mlContext, ITransformer model) { }
Crie um
ImageData
objeto que contenha o caminho completamente qualificado e o nome do ficheiro de imagem para o únicoImagePath
. Adicione o seguinte código como as linhas seguintes noClassifySingleImage()
método :var imageData = new ImageData() { ImagePath = _predictSingleImage };
Faça uma única predição ao adicionar o seguinte código como a linha seguinte no
ClassifySingleImage
método :// Make prediction function (input = ImageData, output = ImagePrediction) var predictor = mlContext.Model.CreatePredictionEngine<ImageData, ImagePrediction>(model); var prediction = predictor.Predict(imageData);
Para obter a predição, utilize o método Predict( ). PredictionEngine é uma API de conveniência, que lhe permite efetuar uma predição numa única instância de dados.
PredictionEngine
não é seguro para threads. É aceitável utilizar em ambientes de thread único ou protótipo. Para melhorar o desempenho e a segurança dos threads em ambientes de produção, utilize oPredictionEnginePool
serviço, que cria umObjectPool
dosPredictionEngine
objetos para utilização em toda a sua aplicação. Veja este guia sobre como utilizarPredictionEnginePool
numa API Web ASP.NET Core.Nota
PredictionEnginePool
A extensão de serviço está atualmente em pré-visualização.Apresentar o resultado da predição como a próxima linha de código no
ClassifySingleImage()
método :Console.WriteLine($"Image: {Path.GetFileName(imageData.ImagePath)} predicted as: {prediction.PredictedLabelValue} with score: {prediction.Score?.Max()} ");
Construir o pipeline do modelo de ML.NET
Um pipeline de modelo ML.NET é uma cadeia de avaliadores. Não ocorre nenhuma execução durante a construção do pipeline. Os objetos do avaliador são criados, mas não executados.
Adicionar um método para gerar o modelo
Este método é o centro do tutorial. Cria um pipeline para o modelo e prepara o pipeline para produzir o modelo de ML.NET. Também avalia o modelo em relação a alguns dados de teste não vistos anteriormente.
Crie o
GenerateModel()
método logo após aInceptionSettings
estrutura e imediatamente antes doDisplayResults()
método, com o seguinte código:ITransformer GenerateModel(MLContext mlContext) { }
Adicione os avaliadores para carregar, redimensionar e extrair os pixéis dos dados da imagem:
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))
Os dados da imagem têm de ser processados no formato esperado pelo modelo TensorFlow. Neste caso, as imagens são carregadas para a memória, redimensionadas para um tamanho consistente e os píxeis são extraídos para um vetor numérico.
Adicione o avaliador para carregar o modelo tensorFlow e classificar:
.Append(mlContext.Model.LoadTensorFlowModel(_inceptionTensorFlowModel). ScoreTensorFlowModel(outputColumnNames: new[] { "softmax2_pre_activation" }, inputColumnNames: new[] { "input" }, addBatchDimensionInput: true))
Esta fase no pipeline carrega o modelo tensorFlow para a memória e, em seguida, processa o vetor de valores de píxeis através da rede do modelo TensorFlow. Aplicar entradas a um modelo de aprendizagem profunda e gerar uma saída com o modelo é referida como Classificação. Ao utilizar o modelo na sua totalidade, a classificação faz uma inferência ou predição.
Neste caso, vai utilizar todo o modelo tensorFlow, exceto a última camada, que é a camada que faz a inferência. O resultado da penúltima camada está etiquetado
softmax_2_preactivation
como . O resultado desta camada é efetivamente um vetor de funcionalidades que caracteriza as imagens de entrada originais.Este vetor de funcionalidade gerado pelo modelo tensorFlow será utilizado como entrada para um algoritmo de preparação ML.NET.
Adicione o avaliador para mapear as etiquetas de cadeia nos dados de preparação para valores de chave de número inteiro:
.Append(mlContext.Transforms.Conversion.MapValueToKey(outputColumnName: "LabelKey", inputColumnName: "Label"))
O ML.NET formador que é acrescentado a seguir requer que as etiquetas estejam no
key
formato em vez de cadeias arbitrárias. Uma chave é um número que tem um mapeamento de um para um para um valor de cadeia.Adicione o algoritmo de preparação ML.NET:
.Append(mlContext.MulticlassClassification.Trainers.LbfgsMaximumEntropy(labelColumnName: "LabelKey", featureColumnName: "softmax2_pre_activation"))
Adicione o avaliador para mapear o valor da chave prevista de volta para uma cadeia:
.Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabelValue", "PredictedLabel")) .AppendCacheCheckpoint(mlContext);
Preparar o modelo
Carregue os dados de preparação com o wrapper LoadFromTextFile . Adicione o seguinte código como a linha seguinte no
GenerateModel()
método :IDataView trainingData = mlContext.Data.LoadFromTextFile<ImageData>(path: _trainTagsTsv, hasHeader: false);
Os dados no ML.NET são representados como uma interface IDataView.
IDataView
é uma forma flexível e eficiente de descrever dados tabulares (numéricos e texto). Os dados podem ser carregados a partir de um ficheiro de texto ou em tempo real (por exemplo, base de dados SQL ou ficheiros de registo) para umIDataView
objeto.Prepare o modelo com os dados carregados acima:
ITransformer model = pipeline.Fit(trainingData);
O
Fit()
método prepara o seu modelo ao aplicar o conjunto de dados de preparação ao pipeline.
Avaliar a precisão do modelo
Carregue e transforme os dados de teste ao adicionar o seguinte código à linha seguinte do
GenerateModel
método: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);
Existem algumas imagens de exemplo que pode utilizar para avaliar o modelo. Tal como os dados de preparação, estes têm de ser carregados para um
IDataView
, para que possam ser transformados pelo modelo.Adicione o seguinte código ao
GenerateModel()
método para avaliar o modelo:MulticlassClassificationMetrics metrics = mlContext.MulticlassClassification.Evaluate(predictions, labelColumnName: "LabelKey", predictedLabelColumnName: "PredictedLabel");
Assim que tiver o conjunto de predição, o método Evaluate( ):
- Avalia o modelo (compara os valores previstos com o conjunto de dados de
labels
teste ). - Devolve as métricas de desempenho do modelo.
- Avalia o modelo (compara os valores previstos com o conjunto de dados de
Apresentar as métricas de precisão do modelo
Utilize o seguinte código para apresentar as métricas, partilhar os resultados e, em seguida, agir sobre as mesmas:
Console.WriteLine($"LogLoss is: {metrics.LogLoss}"); Console.WriteLine($"PerClassLogLoss is: {String.Join(" , ", metrics.PerClassLogLoss.Select(c => c.ToString()))}");
As seguintes métricas são avaliadas para classificação de imagens:
Log-loss
- veja Perda de Registo. Quer que a perda de registo seja o mais próxima possível de zero.Per class Log-loss
. Por classe, a perda de registo deve estar o mais próxima possível de zero.
Adicione o seguinte código para devolver o modelo preparado como a linha seguinte:
return model;
Execute a aplicação!
Adicione a chamada a
GenerateModel
após a criação da MLContext classe:ITransformer model = GenerateModel(mlContext);
Adicione a chamada ao
ClassifySingleImage()
método após a chamada aoGenerateModel()
método :ClassifySingleImage(mlContext, model);
Execute a aplicação de consola (Ctrl + F5). Os resultados devem ser semelhantes ao seguinte resultado. (Poderá ver avisos ou mensagens de processamento, mas estas mensagens foram removidas dos seguintes resultados para maior clareza.)
=============== 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
Parabéns! Criou um modelo de classificação no ML.NET para categorizar imagens com um TensorFlow pré-preparado para processamento de imagens.
Pode encontrar o código fonte deste tutorial no repositório dotnet/samples .
Neste tutorial, ficou a saber como:
- Compreender o problema
- Incorporar o modelo do TensorFlow pré-preparado no pipeline de ML.NET
- Preparar e avaliar o modelo de ML.NET
- Classificar uma imagem de teste
Veja o repositório do GitHub de exemplos do Machine Learning para explorar um exemplo de classificação de imagens expandido.