Tutorial: Treinar um modelo de classificação de ML.NET para categorizar imagens
Saiba como treinar um modelo de classificação para categorizar imagens usando um modelo tensorFlow pré-treinado para processamento de imagem.
O modelo TensorFlow foi treinado para classificar imagens em mil categorias. Como o modelo tensorFlow sabe como reconhecer padrões em imagens, o modelo de 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:
- Entender o problema
- Incorpore o modelo pré-treinado do TensorFlow ao pipeline do ML.NET
- Treinar e avaliar o modelo de ML.NET
- Classificar uma imagem de teste
Você pode encontrar o código-fonte deste tutorial no dotnet/samples repositório. Por padrão, a configuração do projeto .NET para este tutorial tem como destino 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 InceptionV1
Selecione a tarefa de machine learning correta
Aprendizado profundo
Aprendizado profundo é um subconjunto do Aprendizado de Máquina, que está revolucionando áreas como visão computacional e reconhecimento de fala.
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:
- Tem um desempenho melhor em algumas tarefas, como visão computacional.
- Requer grandes quantidades de dados de treinamento.
A classificação de imagem é uma tarefa de classificação específica que nos permite classificar automaticamente imagens em categorias como:
- Detectar a presença de um rosto humano em uma imagem ou sua ausência.
- Detectando gatos versus cães.
Ou como nas seguintes imagens, determinando se uma imagem é um alimento, um brinquedo ou um eletrodoméstico.
Nota
As imagens anteriores pertencem ao Wikimedia Commons e são atribuídas da seguinte maneira:
- "220px-Pepperoni_pizza.jpg" Domínio Público, 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 definiçã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, usar um modelo pré-treinado permite que você simplifique esse processo, trabalhando com milhares de imagens em comparação com milhões de imagens rotuladas, e crie um modelo personalizado rapidamente (em menos de uma hora em uma máquina sem GPU). Este tutorial reduz ainda mais o 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 imagens em um conjunto de categorias menor e apenas nessas categorias. Você pode usar a capacidade do Inception model
de reconhecer e classificar imagens para as novas categorias limitadas do classificador de imagem personalizado.
- Alimento
- Brinquedo
- Aparelho
Este tutorial usa o modelo de aprendizado profundo do TensorFlow Inception, um modelo de reconhecimento de imagem popular treinado no conjunto de dados ImageNet
. 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, ele contém internamente os recursos de imagem necessários para identificação de 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 NuGet ML.NET em seus aplicativos .NET 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 de inicialização do TensorFlow para extrair recursos adequados como entrada para um algoritmo de aprendizado de máquina clássico, adicione um classificador multiclasse ML.NET .
O treinador específico usado nesse caso é o algoritmo de regressão logística multinomial .
O algoritmo implementado por esse treinador tem um bom desempenho em problemas com um grande número de recursos, que é o caso de um modelo de aprendizado profundo operando em dados de imagem.
Para obter mais informações, consulte Aprendizado profundo versusde aprendizado de máquina.
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 tem uma linha de cabeçalho e tem esta 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 ativos que você baixará em um arquivo zip. Essas imagens pertencem ao Wikimedia Commons.
Wikimedia Commons, o repositório de mídia gratuito. Recuperado 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 .NET 8 como a estrutura a ser usada. Selecione o botão Criar.
Instale o Pacote NuGet Microsoft.ML :
Nota
Este exemplo usa a versão estável mais recente dos pacotes NuGet mencionados, a menos que indicado de outra forma.
- No Gerenciador de Soluções, clique com o botão direito do mouse em seu projeto e selecione Gerenciar Pacotes NuGet.
- Escolha "nuget.org" como a origem do pacote, selecione a guia Procurar, pesquise 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 da Licença se concordar com os termos de licença dos pacotes listados.
- Repita estas etapas para Microsoft.ML.ImageAnalytics, SciSharp.TensorFlow.Rediste microsoft.ML.TensorFlow.
Baixar ativos
Baixe o arquivo zip do diretório de materiais do projeto e descompacte.
Copie o diretório
para o diretório do projeto TransferLearningTF. Esse diretório e seus subdiretórios contêm os dados e os arquivos de suporte (exceto para o modelo Inception, que você 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 de ativos e subdiretórios e selecione Propriedades. Em Avançado, altere o valor de Copiar para Diretório de Saída para Copiar se for mais novo.
Criar classes e definir caminhos
Adicione as seguintes diretivas
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 diretivas de
using
para especificar os caminhos do ativo: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 dados de imagem de entrada e tem os seguintes campos de String:ImagePath
contém o nome do arquivo de imagem.Label
contém um valor para o rótulo de imagem.
Adicione uma nova classe ao projeto para
ImagePrediction
:public class ImagePrediction : ImageData { public float[]? Score; public string? PredictedLabelValue; }
ImagePrediction
é a classe de previsão de imagem e tem 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 é treinado. Tem umstring
(ImagePath
) para o demarcador da imagem. OLabel
é usado para reutilizar e treinar o modelo. OPredictedLabelValue
é usado durante a previsão e a 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 seguinte código:MLContext mlContext = new MLContext();
A classe MLContext é um ponto de partida para todas as operações de ML.NET e inicializar
mlContext
cria um novo ambiente ML.NET que pode ser compartilhado entre os objetos de fluxo de trabalho de criação de modelo. É 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 passar. Crie um struct para mapear os valores de parâmetro para nomes amigáveis com o seguinte código, logo após a inicialização da variável
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; }
Criar um método de utilitário de exibição
Como você exibirá os dados da 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 da imagem e da 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()
, pouco 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 no métodoClassifySingleImage()
:var imageData = new ImageData() { ImagePath = _predictSingleImage };
Faça uma única previsão adicionando o seguinte código como a próxima linha no método
ClassifySingleImage
:// 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 que você execute uma previsão em uma única instância de dados. PredictionEngine
não é thread-safe. É aceitável usá-lo em ambientes de thread único ou de protótipo. Para melhorar o desempenho e a segurança das threads em ambientes de produção, use o serviçoPredictionEnginePool
, que cria umaObjectPool
de objetosPredictionEngine
para uso em todo o seu aplicativo. Confira este guia sobre como usar oPredictionEnginePool
em uma API Web ASP.NET Core.Nota
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 ocorre 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
Esse método é o cerne do tutorial. Ele cria um pipeline para o modelo e treina o pipeline para produzir o modelo de 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 pouco 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 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 avalie-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 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 dessa camada é efetivamente um vetor de recursos que caracterizam as imagens de entrada originais.Esse vetor de recurso 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 novamente o valor de chave previsto 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 como a próxima linha no método
GenerateModel()
:IDataView trainingData = mlContext.Data.LoadFromTextFile<ImageData>(path: _trainTagsTsv, hasHeader: false);
Os dados em 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 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);
Há algumas imagens de exemplo 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 método
GenerateModel()
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 sobre elas:
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
- Consulte a Perda de log. Convém que a Perda de log seja tão próxima de zero quanto possível. -
Per class Log-loss
. Você deseja que a perda logística por classe seja o mais próxima possível de zero.
-
Adicione o seguinte código para retornar o modelo treinado como a próxima linha:
return model;
Executar o aplicativo
Adicione a chamada após
GenerateModel
a criação da MLContext classe:ITransformer model = GenerateModel(mlContext);
Adicione a chamada ao método
ClassifySingleImage()
após a chamada ao métodoGenerateModel()
:ClassifySingleImage(mlContext, model);
Execute seu aplicativo de console (Ctrl + F5). Seus resultados devem ser semelhantes ao resultado a seguir. (Você pode ver avisos ou mensagens de processamento, mas essas 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! Agora você criou com êxito um modelo de classificação em ML.NET para categorizar imagens usando um TensorFlow pré-treinado para processamento de imagem.
Você pode encontrar o código-fonte deste tutorial no dotnet/samples repositório.
Neste tutorial, você aprendeu a:
- Entender o problema
- Incorpore o modelo pré-treinado do TensorFlow ao pipeline do ML.NET
- Treinar e avaliar o modelo de ML.NET
- Classificar uma imagem de teste
Confira o repositório GitHub de exemplos do Machine Learning para explorar uma amostra de classificação de imagem expandida.