Partilhar via


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

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:

imagem de pizzaursinho imagemtorradeira imagem torradeira

Nota

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

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

Diagrama de transformação do TensorFlow ML.NET Arch

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

  1. Crie uma Aplicação de Consola C# denominada "TransferLearningTF". Clique no botão Seguinte .

  2. Selecione .NET 6 como a arquitetura a utilizar. Clique no botão Criar.

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

  1. Transfira o ficheiro zip do diretório de recursos do projeto e deszipe.

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

  3. Transfira o modelo Inception e deszipe.

  4. Copie o conteúdo do inception5h diretório deszipado para o diretório de projeto assets/inceptionTransferLearningTF. Este diretório contém o modelo e os ficheiros de suporte adicionais necessários para este tutorial, conforme mostrado na imagem seguinte:

    Conteúdo do diretório de criação

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

  1. Adicione as seguintes instruções adicionais using à parte superior do ficheiro Program.cs :

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

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

Criar uma estrutura para parâmetros de modelo de Inception

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

  1. Crie o DisplayResults() método logo após a InceptionSettings estrutura, com 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 predição

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

    void ClassifySingleImage(MLContext mlContext, ITransformer model)
    {
    
    }
    
  2. Crie um ImageData objeto que contenha o caminho completamente qualificado e o nome do ficheiro de imagem para o único ImagePath. Adicione o seguinte código como as linhas seguintes no ClassifySingleImage() método :

    var imageData = new ImageData()
    {
        ImagePath = _predictSingleImage
    };
    
  3. 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 o PredictionEnginePool serviço, que cria um ObjectPool dos PredictionEngine objetos para utilização em toda a sua aplicação. Veja este guia sobre como utilizar PredictionEnginePool numa API Web ASP.NET Core.

    Nota

    PredictionEnginePool A extensão de serviço está atualmente em pré-visualização.

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

  1. 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 a InceptionSettings estrutura e imediatamente antes do DisplayResults() método, com o seguinte código:

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

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

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

  5. Adicione o algoritmo de preparação ML.NET:

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

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

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

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

  2. 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 labelsteste ).
    • Devolve as métricas de desempenho do modelo.
  3. 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.
  4. Adicione o seguinte código para devolver o modelo preparado como a linha seguinte:

    return model;
    

Execute a aplicação!

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

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

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