Machine Learning | Clasificar imágenes usando ONNX Runtime y Blazor

Este ejemplo es una aplicación Web con Blazor que consume un modelo de clasificación de imágenes utilizando ONNX Runtime y C#

GitHub

El código del proyecto puede descargarse del siguiente repositorio de GitHub: demo-ortblazor

Prerequisitos

Setup

Crear un proyecto nuevo

Crear la aplicación Web Blazor (servidor) con el siguiente comando

dotnet new blazorserver -o demo-ortblazor --no-https

Añadir paquetes

Agregar los siguientes paquetes al proyecto

dotnet add package Microsoft.ML.OnnxRuntime
dotnet add package SixLabors.ImageSharp

Código

Procesamiento de la imagen

Lo más complicado para consumir un modelo ONNX con ONNX Runtime es el procesamiento previo de los datos, en este caso vamos a consumir un modelo de clasificación de imágenes llamado resnet50v2.onnx

Para consumir este modelo se necesita previamente procesar la imagen que queremos clasificar para que la imagen esté en el formato requerido por el modelo

Este procesamiento se realiza con las siguientes clases en la carpeta Util

Carpetas Onnx Runtime Blazor

La función principal es: GetImageTensorFromString, esta función recibe una imagen en Base64 y la transforma en un tensor con el formato que el modelo resnet50v2.onnx requiere para procesarlo y dar una respuesta, a continuación el código de la función

public static Tensor<float> GetImageTensorFromString(string strBase64, int imgWidth = 224, int imgHeight=224)
{
    // Read image
    using Image<Rgb24> image = Image.Load<Rgb24>(Convert.FromBase64String(strBase64));

    // Resize image
    image.Mutate(x =>
    {
        x.Resize(new ResizeOptions
        {
            Size = new Size(imgWidth, imgHeight),
            Mode = ResizeMode.Crop
        });
    });

    // Preprocess image
    Tensor<float> input = new DenseTensor<float>(new[] { 1, 3, 224, 224 });
    var mean = new[] { 0.485f, 0.456f, 0.406f };
    var stddev = new[] { 0.229f, 0.224f, 0.225f };
    for (int y = 0; y < image.Height; y++)
    {
        image.ProcessPixelRows(accesor => {
            Span<Rgb24> pixelSpan = accesor.GetRowSpan(y);
        for (int x = 0; x < image.Width; x++)
        {
            input[0, 0, y, x] = ((pixelSpan[x].R / 255f) - mean[0]) / stddev[0];
            input[0, 1, y, x] = ((pixelSpan[x].G / 255f) - mean[1]) / stddev[1];
            input[0, 2, y, x] = ((pixelSpan[x].B / 255f) - mean[2]) / stddev[2];
        }
        });
    }

    return input;
}

Consumo del modelo desde la aplicación web

El objetivo de la aplicación es que se pueda seleccionar una imagen y enviarla como parámetro de entrada al modelo de clasificación de imágenes (resnet50v2.onnx) y mostrar la respuesta del modelo en la misma página

Demo ONNX Runtime y Blazor

Lo primero que debemos hacer es agregar el modelo al proyecto, este está ubicado en la carpeta:

demo-ortblazor/Model/resnet50v2.onnx

En el archivo demo-ortblazor.csproj debemos agregar un ItemGroup para que el modelo sea parte del compilado del proyecto

<ItemGroup>
  <Content Include="Model\*" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

Solo nos queda agregar una página Blazor en la carpeta Pages: Pages/OrtBlazor.razor

El código de esta página tiene dos secciones. La primera sección se encarga de cargar la imagen seleccionada en base64 y mostrarla un un componente <img>

@code {
	public List<ImageFile> filesBase64 = new List<ImageFile>();
	string message = "InputFile";
	bool isDisabled = false;

	async Task OnChange(InputFileChangeEventArgs e)
	{
		var files = e.GetMultipleFiles(); // get the files selected by the users
		foreach(var file in files)
		{
			var resizedFile = await file.RequestImageFileAsync(file.ContentType, 640, 480); // resize the image file
			var buf = new byte[resizedFile.Size]; // allocate a buffer to fill with the file's data
			using (var stream = resizedFile.OpenReadStream())
			{
				await stream.ReadAsync(buf); // copy the stream to the buffer
			}
			filesBase64.Add(new ImageFile { base64data = Convert.ToBase64String(buf), contentType = file.ContentType, fileName = file.Name }); // convert to a base64 string!!
		}
		message = "Click to continue ->";
	}
}

La segunda sección de código se encarga de enviar la imagen en base64 al modelo de clasificación ONNX -pasando por el procesamiento previo de la clase ImageHelper- y recibir la respuesta del modelo y mostrarlo en una tabla

@code {

    private List<Prediction> top10 = new List<Prediction> { new Prediction { Label = "Label Ejemplo", Confidence = 0.0f }};
    private void Predict()
    {
        string modelFilePath = @"Model/resnet50v2.onnx";
        //string imageFilePath = @"/Users/diegomera/repos/demo-ortcsharp/data/dog.jpeg";
        //Microsoft.ML.OnnxRuntime.Tensors.Tensor<float> input = ImageHelper.GetImageTensorFromPath(imageFilePath);
        Microsoft.ML.OnnxRuntime.Tensors.Tensor<float> input = ImageHelper.GetImageTensorFromString(filesBase64.First().base64data);
        top10 = ModelHelper.GetPredictions(input, modelFilePath);

        // Print results to console
        foreach (var t in top10)
        {
            Console.WriteLine($"Label: {t.Label}, Confidence: {t.Confidence}");
        }
    }    
}

Ejecutar el proyecto

Para ejecutar el proyecto localmente usamos el comando

dotnet run

En la aplicación web abra la pestaña del menú «Ort Blazor» Seleccione la imagen de un perro ubicado en el mismo proyecto demo-ortblazor/SampleImg/dog.jpeg

Si el proyecto se ejecuta correctamente, debería mostrar el siguiente resultado:

Golden Retriever	0.7550826
Kuvasz	0.1418474
Clumber Spaniel	0.02673398
Otterhound	0.011237004
Sussex Spaniel	0.008394765
Pyrenean Mountain Dog	0.007158577
Labrador Retriever	0.004976533
Saluki	0.0046295193
Tibetan Terrier	0.004320859
English Setter	0.003663472

Artículos relacionados

Azure Functions SQL Binding con Python

DALL-E 2 | ¿Puede una IA hacer el trabajo de un diseñador?

Un comentario sobre “Machine Learning | Clasificar imágenes usando ONNX Runtime y Blazor

Los comentarios están cerrados.

Blog de WordPress.com.

Subir ↑

A %d blogueros les gusta esto: