Tutorial: Treinar um modelo de classificação ML.NET para categorizar imagens
Saiba como treinar um modelo de classificação para categorizar imagens usando um modelo pré-treinado do TensorFlow para processamento de imagens.
O modelo TensorFlow foi treinado para classificar imagens em mil categorias. Como o modelo TensorFlow sabe reconhecer padrões em imagens, o modelo ML.NET pode usar parte dele em seu pipeline para converter imagens brutas em recursos ou entradas para treinar um modelo de classificação.
Neste tutorial, você aprenderá a:
- Compreender o problema
- Incorpore o modelo pré-treinado do TensorFlow ao pipeline ML.NET
- Treinar e avaliar o modelo ML.NET
- Classificar uma imagem de teste
Você pode encontrar o código-fonte para este tutorial no repositório dotnet/samples. Por padrão, a configuração do projeto .NET para este tutorial tem como alvo o .NET core 2.2.
Pré-requisitos
- Visual Studio 2022
- O arquivo .ZIP do diretório de recursos do tutorial
- O modelo de machine learning do InceptionV1
Selecione a tarefa de aprendizado de máquina correta
Aprendizado
Aprendizado profundo é um subconjunto do aprendizado de máquina, que está revolucionando áreas como Pesquisa Visual Computacional e Reconhecimento de Fala.
Os modelos de aprendizado profundo são treinados usando grandes conjuntos de dados rotulados e redes neurais que contêm várias camadas de aprendizado. Aprendizado profundo:
- Executa melhor em algumas tarefas, como visão computacional.
- Requer grandes quantidades de dados de treinamento.
A classificação de imagens é uma tarefa de classificação específica que nos permite classificar automaticamente as imagens em categorias como:
- Detectar uma face humana em uma imagem ou não.
- Detecção de gatos vs. cães.
Ou como nas imagens a seguir, determinando se uma imagem é um alimento, brinquedo ou aparelho:
Observação
As imagens anteriores pertencem ao Wikimedia Commons e são atribuídas da seguinte forma:
- "220px-Pepperoni_pizza.jpg" Public Domain, https://commons.wikimedia.org/w/index.php?curid=79505,
- "119px-Nalle_-_a_small_brown_teddy_bear.jpg" By Jonik - Self-photographed, 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
Treinar um modelo de classificação de imagem do zero requer a configuração de milhões de parâmetros, uma tonelada de dados de treinamento rotulados e uma grande quantidade de recursos de computação (centenas de horas de GPU). Embora não seja tão eficaz quanto treinar um modelo personalizado do zero, o uso de um modelo pré-treinado permite abreviar esse processo trabalhando com milhares de imagens versus milhões de imagens rotuladas e criar um modelo personalizado com bastante rapidez (dentro de uma hora em uma máquina sem GPU). Este tutorial reduz ainda mais esse processo, usando apenas uma dúzia de imagens de treinamento.
O Inception model
é treinado para classificar imagens em mil categorias, mas para este tutorial, você precisa classificar as imagens em um conjunto de categorias menor e apenas essas categorias. Você pode usar a capacidade de Inception model
de reconhecer e classificar imagens para as novas categorias limitadas do seu classificador de imagens personalizado.
- Alimentos
- Brinquedos
- Dispositivo
Este tutorial usa o modelo de aprendizado profundo TensorFlow Inception, um modelo popular de reconhecimento de imagem treinado no ImageNet
conjunto de dados. O modelo TensorFlow classifica imagens inteiras em mil classes, como “Umbrella”, “Jersey” e “Dishwasher”.
Como o Inception model
já foi pré-treinado em milhares de imagens diferentes, internamente ele contém os recursos de imagem necessários para a identificação da imagem. Podemos usar esses recursos de imagem interna no modelo para treinar um novo modelo com muito menos classes.
Conforme mostrado no diagrama a seguir, você adiciona uma referência aos pacotes ML.NET NuGet em seus aplicativos .NET Core ou .NET Framework. Nos bastidores, o ML.NET inclui e faz referência à TensorFlow
biblioteca nativa que permite escrever código que carrega um TensorFlow
arquivo de modelo treinado existente.
Classificação multiclasse
Depois de usar o modelo inicial do TensorFlow para extrair recursos adequados como entrada para um algoritmo clássico de aprendizado de máquina, adicionamos um classificador multiclasse ML.NET.
O treinador específico usado neste caso é o algoritmo de regressão logística multinomial.
O algoritmo implementado por este treinador funciona bem em problemas com um grande número de recursos, como é o caso de um modelo de aprendizado profundo operando em dados de imagem.
Consulte Aprendizado profundo versus aprendizado de máquina para obter mais informações.
Dados
Há duas fontes de dados: o arquivo .tsv
e os arquivos de imagem. O arquivo tags.tsv
contém duas colunas: a primeira é definida como ImagePath
e a segunda é a Label
correspondente à imagem. O arquivo de exemplo a seguir não possui uma linha de cabeçalho e tem a seguinte aparência:
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 treinamento e teste estão localizadas nas pastas de recursos que você baixará em um arquivo zip. Essas imagens pertencem ao Wikimedia Commons.
Wikimedia Commons, o repositório de mídia gratuito. Recuperado em 10:48, 17 de outubro de 2018 de: https://commons.wikimedia.org/wiki/Pizzahttps://commons.wikimedia.org/wiki/Toasterhttps://commons.wikimedia.org/wiki/Teddy_bear
Configuração
Criar um projeto
Crie um aplicativo de console C# chamado "TransferLearningTF". Clique no botão Avançar.
Escolha o .NET 6 como a estrutura a ser usada. Selecione o botão Criar.
Instalar o Pacote NuGet Microsoft.ML:
Observação
Este exemplo usa a versão estável mais recente dos pacotes NuGet mencionados, salvo indicação em contrário.
- No Gerenciador de Soluções, clique com o botão direito do mouse no seu projeto e selecione Gerenciar Pacotes NuGet.
- Escolha "nuget.org" como a fonte do pacote, selecione a guia Browse, procure por Microsoft.ML.
- Selecione o botão Instalar.
- Clique no botão OK na caixa de diálogo Pré-visualização de alterações.
- Selecione o botão Aceito na caixa de diálogo Aceitação de Licença se você concordar com os termos de licença para os pacotes listados.
- Repita essas etapas para Microsoft.ML.ImageAnalytics, SciSharp.TensorFlow.Redist e Microsoft.ML.TensorFlow.
Baixar ativos
Baixe o arquivo zip do diretório de materiais do projeto e descompacte.
Copie o diretório
assets
no diretório do projeto TransferLearningTF. Este diretório e seus subdiretórios contêm os arquivos de dados e de suporte (exceto o modelo Concepção, que você irá baixar e adicionar na próxima etapa) necessários para este tutorial.Baixe o modelo Concepção e descompacte-o.
Copie o conteúdo do diretório
inception5h
apenas descompactado em seu diretório de projeto TransferLearningTFassets/inception
. Este diretório contém o modelo e os arquivos de suporte adicionais necessários para este tutorial, conforme mostrado na imagem a seguir:No Gerenciador de Soluções, clique com o botão direito do mouse em cada um dos arquivos no diretório e nos subdiretórios do ativo e selecionePropriedades. Em Avançado, altere o valor de Copiar para Diretório de Saída para Copiar se for mais novo.
Criar classes e definir demarcadores
Adicione as seguintes instruções
using
adicionais ao início do arquivo Program.cs:using Microsoft.ML; using Microsoft.ML.Data;
Adicione o seguinte código à linha logo abaixo das instruções de uso para especificar os caminhos dos ativos:
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 seus dados de entrada e previsões.
public class ImageData { [LoadColumn(0)] public string? ImagePath; [LoadColumn(1)] public string? Label; }
ImageData
é a classe de conjunto de dados de entrada e tem os seguintes campos String:ImagePath
contém o nome do arquivo de imagem.Label
contém um valor para o rótulo da imagem.
Adicione uma nova classe ao seu projeto para
ImagePrediction
:public class ImagePrediction : ImageData { public float[]? Score; public string? PredictedLabelValue; }
ImagePrediction
é a classe de previsão de imagem e possui os seguintes campos:Score
contém a porcentagem de confiança para uma determinada classificação de imagem.PredictedLabelValue
contém um valor para o rótulo de classificação de imagem previsto.
ImagePrediction
é a classe usada para previsão depois que o modelo foi treinado. Tem umstring
(ImagePath
) para o demarcador da imagem. OLabel
é usado para reutilizar e treinar o modelo. OPredictedLabelValue
é usado durante a previsão e avaliação. Para avaliação, uma entrada com dados de treinamento, os valores previstos e o modelo são usados.
Inicializar variáveis
Inicialize a variável
mlContext
com uma nova instância deMLContext
. Substitua a linhaConsole.WriteLine("Hello World!")
pelo código a seguir:MLContext mlContext = new MLContext();
A MLContext classe é um ponto de partida para todas as operações ML.NET, e a inicialização
mlContext
cria um novo ambiente ML.NET que pode ser compartilhado entre os objetos de fluxo de trabalho de criação de modelo. Ele é semelhante, conceitualmente, aDBContext
no Entity Framework.
Criar uma estrutura para os parâmetros do modelo Inception
O modelo Inception tem vários parâmetros que você precisa verificar. Crie uma estrutura para mapear os valores de parâmetro 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 exibição
Uma vez que você exibirá os dados de imagem e as previsões relacionadas mais de uma vez, crie um método de utilitário de exibição para lidar com a exibição dos resultados de imagem e previsão.
Crie o método
DisplayResults()
, logo após o structInceptionSettings
, usando 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 previsão
Crie o método
ClassifySingleImage()
, logo antes do métodoDisplayResults()
, usando o seguinte código:void ClassifySingleImage(MLContext mlContext, ITransformer model) { }
Crie um
ImageData
objeto que contenha o caminho totalmente qualificado e o nome do arquivo de imagem para o arquivoImagePath
. Adicione o seguinte código como as próximas linhas noClassifySingleImage()
método:var imageData = new ImageData() { ImagePath = _predictSingleImage };
Faça uma única previsão, adicionando o código a seguir como a próxima linha 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 previsão, use o método Predict(). O PredictionEngine é uma API de conveniência, que permite executar uma previsão em uma instância individual de dados.
PredictionEngine
não é thread-safe. É aceitável usá-lo em ambientes de thread único ou de protótipo. Para aprimorar o desempenho e o acesso thread-safe em ambientes de produção, use o serviçoPredictionEnginePool
, que cria umObjectPool
de objetosPredictionEngine
para uso em todo o aplicativo. Confira este guia sobre como usar oPredictionEnginePool
em uma API Web ASP.NET Core.Observação
A extensão de serviço
PredictionEnginePool
está atualmente em versão prévia.Exiba o resultado da previsão como a próxima linha de código no método
ClassifySingleImage()
:Console.WriteLine($"Image: {Path.GetFileName(imageData.ImagePath)} predicted as: {prediction.PredictedLabelValue} with score: {prediction.Score?.Max()} ");
Construir o pipeline do modelo ML.NET
Um pipeline de modelo ML.NET é uma cadeia de estimadores. Nenhuma execução acontece durante a construção do pipeline. Os objetos do estimador são criados, mas não executados.
Adicionar um método para gerar o modelo
Este método é o coração do tutorial. Ele cria um pipeline para o modelo e treina o pipeline para produzir o modelo ML.NET. Ele também avalia o modelo em relação a alguns dados de teste não vistos anteriormente.
Crie o método
GenerateModel()
logo após o structInceptionSettings
e antes do métodoDisplayResults()
, usando o seguinte código:ITransformer GenerateModel(MLContext mlContext) { }
Adicione os estimadores para carregar, redimensionar e extrair os pixels 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 precisam ser processados no formato que o modelo do TensorFlow espera. Nesse caso, as imagens são carregadas na memória, redimensionadas para um tamanho consistente e os pixels são extraídos em um vetor numérico.
Adicione o estimador para carregar o modelo TensorFlow e marque-o:
.Append(mlContext.Model.LoadTensorFlowModel(_inceptionTensorFlowModel). ScoreTensorFlowModel(outputColumnNames: new[] { "softmax2_pre_activation" }, inputColumnNames: new[] { "input" }, addBatchDimensionInput: true))
Esse estágio no pipeline carrega o modelo do TensorFlow na memória e processa o vetor de valores de pixel por meio da rede do modelo do TensorFlow. Aplicar entradas a um modelo de aprendizado profundo e gerar uma saída usando o modelo é chamado de Pontuação . Ao usar o modelo em sua totalidade, a pontuação faz uma inferência ou previsão.
Nesse caso, você usa todo o modelo do TensorFlow, exceto a última camada, que é a camada que faz a inferência. A saída da penúltima camada é rotulada
softmax_2_preactivation
. A saída desta camada é efetivamente um vetor de características que caracterizam as imagens de entrada originais.Esse vetor de recursos gerado pelo modelo TensorFlow será usado como entrada para um algoritmo de treinamento ML.NET.
Adicione o estimador para mapear os rótulos de string nos dados de treinamento para valores de chave inteiros:
.Append(mlContext.Transforms.Conversion.MapValueToKey(outputColumnName: "LabelKey", inputColumnName: "Label"))
O treinador ML.NET que é anexado a seguir exige que seus rótulos estejam em
key
formato em vez de cadeias de caracteres arbitrárias. Uma chave é um número que tem um mapeamento de um para um para uma cadeia de caracteres.Adicione o algoritmo de treinamento ML.NET:
.Append(mlContext.MulticlassClassification.Trainers.LbfgsMaximumEntropy(labelColumnName: "LabelKey", featureColumnName: "softmax2_pre_activation"))
Adicione o estimador para mapear o valor da chave previsto de volta em uma cadeia de caracteres:
.Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabelValue", "PredictedLabel")) .AppendCacheCheckpoint(mlContext);
Treinar o modelo
Carregue os dados de treinamento usando o wrapper LoadFromTextFile. Adicione o seguinte código ao método
GenerateModel()
como a linha seguinte:IDataView trainingData = mlContext.Data.LoadFromTextFile<ImageData>(path: _trainTagsTsv, hasHeader: false);
Os dados no ML.NET são representados como uma interface IDataView.
IDataView
é uma maneira flexível e eficiente de descrever dados tabulares (numéricos e texto). Os dados podem ser carregados de um arquivo de texto ou em tempo real (por exemplo, banco de dados SQL ou arquivos de log) para um objetoIDataView
.Treine o modelo com os dados carregados acima:
ITransformer model = pipeline.Fit(trainingData);
O
Fit()
método treina seu modelo aplicando o conjunto de dados de treinamento ao pipeline.
Avaliar a precisão do modelo
Carregue e transforme os dados de teste, adicionando o seguinte código à próxima linha 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 amostra que você pode usar para avaliar o modelo. Assim como os dados de treinamento, eles precisam ser carregados em 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");
Depois de determinar a previsão, o método Evaluate ():
- Avalia o modelo (compara os valores previstos com o conjunto de dados de teste
labels
). - Retorna as métricas de desempenho do modelo.
- Avalia o modelo (compara os valores previstos com o conjunto de dados de teste
Exibir as métricas de precisão do modelo
Use o código a seguir para exibir as métricas, compartilhar os resultados e, em seguida, agir com relação a eles:
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 imagem:
Log-loss
- confira Perda de log. Convém que a Perda de log seja tão próxima de zero quanto possível.Per class Log-loss
. Convém que a Perda de log por classe seja tão próxima de zero quanto possível.
Adicione o seguinte código para retornar o modelo treinado como a próxima linha:
return model;
Execute o aplicativo!
Adicione a chamada após
GenerateModel
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 seu aplicativo de console (Ctrl + CtrlF5). O resultado deverá ser semelhante à seguinte saída. (Você poderá ver avisos ou mensagens de processamento, mas essas mensagens foram removidas dos resultados a seguir 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! Agora você criou com sucesso um modelo de classificação no ML.NET para categorizar imagens usando um TensorFlow pré-treinado para processamento de imagens.
Você pode encontrar o código-fonte para este tutorial no repositório dotnet/samples.
Neste tutorial, você aprendeu a:
- Compreender o problema
- Incorpore o modelo pré-treinado do TensorFlow ao pipeline ML.NET
- Treinar e avaliar o modelo ML.NET
- Classificar uma imagem de teste
Conferir o repositório GitHub de Amostras de Aprendizado de Máquina para explorar uma amostra de classificação de imagem expandida.
Comentários
https://aka.ms/ContentUserFeedback.
Em breve: Ao longo de 2024, eliminaremos os problemas do GitHub como o mecanismo de comentários para conteúdo e o substituiremos por um novo sistema de comentários. Para obter mais informações, consulteEnviar e exibir comentários de