Compartilhar via


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

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.

imagem de pizzaimagem do urso de pelúciaimagem da torradeira

Nota

As imagens anteriores pertencem ao Wikimedia Commons e são atribuídas da seguinte maneira:

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 modelde 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 à TensorFlowbiblioteca nativa que permite escrever código que carrega um TensorFlow arquivo de modelo treinado existente.

Diagrama de arco da transformação do TensorFlow do ML.NET

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

  1. Crie um aplicativo de console C# chamado "TransferLearningTF". Clique no botão Avançar.

  2. Escolha .NET 8 como a estrutura a ser usada. Selecione o botão Criar.

  3. 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

  1. Baixe o arquivo zip do diretório de materiais do projeto e descompacte.

  2. 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.

  3. Baixe o modelo Concepção e descompacte-o.

  4. 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:

    conteúdo do diretório Inception

  5. 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

  1. Adicione as seguintes diretivas using adicionais ao início do arquivo Program.cs:

    using Microsoft.ML;
    using Microsoft.ML.Data;
    
  2. 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");
    
  3. 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.
  4. 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 um string (ImagePath) para o demarcador da imagem. O Label é usado para reutilizar e treinar o modelo. O PredictedLabelValue é 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

  1. Inicialize a variável mlContext com uma nova instância de MLContext. Substitua a linha Console.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, a DBContext no Entity Framework.

Criar uma estrutura para os parâmetros do modelo Inception

  1. 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.

  1. Crie o método DisplayResults(), logo após o struct InceptionSettings, usando o seguinte código:

    void DisplayResults(IEnumerable<ImagePrediction> imagePredictionData)
    {
    
    }
    
  2. 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

  1. Crie o método ClassifySingleImage(), pouco antes do método DisplayResults(), usando o seguinte código:

    void ClassifySingleImage(MLContext mlContext, ITransformer model)
    {
    
    }
    
  2. Crie um ImageDataobjeto que contenha o caminho totalmente qualificado e o nome do arquivo de imagem para o arquivo ImagePath. Adicione o seguinte código como as próximas linhas no método ClassifySingleImage():

    var imageData = new ImageData()
    {
        ImagePath = _predictSingleImage
    };
    
  3. 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ço PredictionEnginePool, que cria uma ObjectPool de objetos PredictionEngine para uso em todo o seu aplicativo. Confira este guia sobre como usar o PredictionEnginePool em uma API Web ASP.NET Core.

    Nota

    A extensão de serviço PredictionEnginePool está atualmente em versão prévia.

  4. 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.

  1. 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 struct InceptionSettings e pouco antes do método DisplayResults(), usando o seguinte código:

    ITransformer GenerateModel(MLContext mlContext)
    {
    
    }
    
  2. 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.

  3. 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.

  4. 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.

  5. Adicione o algoritmo de treinamento ML.NET:

    .Append(mlContext.MulticlassClassification.Trainers.LbfgsMaximumEntropy(labelColumnName: "LabelKey", featureColumnName: "softmax2_pre_activation"))
    
  6. 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

  1. 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 objeto IDataView.

  2. 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

  1. 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.

  2. 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.
  3. 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.
  4. Adicione o seguinte código para retornar o modelo treinado como a próxima linha:

    return model;
    

Executar o aplicativo

  1. Adicione a chamada após GenerateModel a criação da MLContext classe:

    ITransformer model = GenerateModel(mlContext);
    
  2. Adicione a chamada ao método ClassifySingleImage() após a chamada ao método GenerateModel():

    ClassifySingleImage(mlContext, model);
    
  3. 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.