Optimización de rendimiento en Power BI
9 diciembre, 2020
Carta a los Reyes Magos
17 diciembre, 2020

Tradicionalmente los modelos de Machine Learning están en el dominio de los científicos de datos. Son éstos quienes se encargan de definir los modelos, entrenarlos y usarlos para realizar las predicciones.

Habitualmente los dispositivos son meros capturadores de información. Estos datos se envían a la nube dónde son procesados por dichos modelos.

Pero esta visión ha cambiado recientemente gracias a la posibilidad de crear modelos, entrenarlo y ejecutarlos en máquinas locales. Esto nos permite además poder publicarlos como módulos en el Edge lo que habilita el poder tomar decisiones en tiempo real en base a las predicciones.

Para poder realizar esta implementación, haremos uso de la librería ML.NET  de Microsoft.

 

¿Qué es ML.NET y cómo nos puede ayudar?

La iniciación en la creación de modelos de Inteligencia Artificial es una tarea que resulta muy compleja para desarrolladores que no son expertos en ciencia de datos.

Requiere el conocimiento y aplicación de modelos matemáticos que resultan complicados de implementar y utilizar en los desarrollos.

Pero las cosas han cambiado en parte tras la publicación por parte de Microsoft de la librería ML.NET.

No nos engañemos, si queremos entrar en materia no nos va a quedar más remedio que profundizar en el conocimiento de los modelos matemáticos a los que hacía referencia, pero, sin embargo, con esta librería se nos brinda la posibilidad de ver dichos modelos como una Caja Negra.

Pero, con ML.NET, Microsoft nos brinda la posibilidad de utilizar Visual Studio/Visual Studio Code y C# para crear, entrenar y publicar nuestro propio modelo de Machine Learning utilizando uno de los muchos algoritmos que vienen integrados por defecto en la propia librería.

De esta forma, prescindimos de la necesidad de aprender a desarrollar con alguno de los lenguajes de programación habituales para ello como por ejemplo Python, R, etc…

Adicionalmente, otra ventaja muy importante que conseguimos mediante el uso de esta librería es la posibilidad de entrenar nuestro modelo directamente en nuestra máquina local, prescindiendo de cualquier infraestructura Cloud.

Pero…, ¿es realmente tan sencillo de implementar como parece a primera vista?

Microsoft realmente está intentando facilitarle la vida al desarrollador lo máximo posible.

Un ejemplo de esto es que actualmente en Visual Studio podemos utilizar un pequeño asistente que nos crea toda la infraestructura necesaria para algunos de los casos de uso más comunes.

Esta extensión, denominada ML.NET Model Builder aun se encuentra en Preview, pero actualmente proporciona un asistente para algunos de los escenarios más comunes.

 

Preparación del entorno de desarrollo

Para realizar este laboratorio, es necesario instalar las siguientes herramientas en nuestra máquina:

  • Visual Studio 2019 o Visual Studio Code. En el lab he utilizado Visual Studio Code ya que es gratuito. Se puede descargar aquí.
  • Extensión de Azure IoT Edge instalada en Visual Studio Code. Se puede descargar aquí.
  • Extensión ML.NET Model Builder más reciente. Esto se puede realizar desde Visual Studio, con la gestión de extensiones o con descarga directa aquí.
  • Instalación reciente de Azure Cli, ya que lo usaremos para la comunicación con los servicios de Azure. Disponible para la descarga aquí.
  • Extensión azure iot para Az Cli. Se instala con el comando az extension add –name azure-iot
  • Es necesario tener instalado el SDK de .NET Core 3.1. Se puede descargar aquí.
  • Para poder crear y desplegar los módulos de IoT Edge, será necesario tener instalado Docker. Disponible para la descarga aquí.

También será necesario disponer de una suscripción de Azure para la provisión de todos los recursos utilizados en el laboratorio.

 

Construcción del Modelo de Machine Learning

Una vez que hemos cubierto los prerrequisitos en el entorno de desarrollo, podemos proceder a crear nuestro modelo.

Para ello, crearemos dos proyectos en Visual Studio. Uno de ellos contendrá el código necesario para la creación de nuestro modelo.

El otro, contendrá lo necesario para ejecutar predicciones contra dicho modelo.

Pese a que tenemos asistentes en Visual Studio para algunos escenarios, crearemos uno a medida con un algoritmo de detección de anomalías que no está cubierto en los escenarios predefinidos.

La estructura de nuestra solución será la siguiente:

El primer paso que debemos seguir consiste en añadir el paquete nuget Microsoft.ML en ambos proyectos.

De esta forma podremos crear, entrenar y publicar el modelo.

 

Definición del Modelo

Una vez agregado el paquete Nuget, podemos proceder a crear nuestra librería para definir el modelo.

Para ello, debemos analizar nuestro origen de datos para determinar la estructura.

Para facilitar este proceso, utilizaremos como origen de datos mediciones que incluyen:

  • Temperatura de una máquina
  • Presión de la máquina
  • Temperatura ambiente
  • Humedad ambiente

Y para entrenar nuestro modelo, dispondremos de un CSV con distintas mediciones y una columna que indicará si las mediciones son anómalas.

Nuestro CSV tendrá cinco columnas con los datos necesarios para realizar la predicción, incluyendo la columna que indica si la medición es anómala o no.

Con estos datos, procedemos a crear los artefactos necesarios para definir nuestro modelo.

En primer lugar, debemos definir las clases que representan la entrada de datos y la respuesta con la medición.

 

MachineData.cs

using System;
using Microsoft.ML.Data;

namespace PredictiveManteinance.Model
{
    public class MachinePrediction
    {
        public float Score { get; set; }

        [ColumnName("PredictedLabel")]
        public bool Anomally { get; set; }

        public float Probability { get; set; }
    }
}

MachinePrediction.cs

using System;
using Microsoft.ML.Data;

namespace PredictiveManteinance.Model
{
    public class MachinePrediction
    {
        public float Score { get; set; }

        [ColumnName("Anomally")]
        public bool Anomally { get; set; }

        public float Probability { get; set; }
    }
}

 

Creación del Modelo

Una vez hecho esto, debemos proporcionar los componentes necesarios para construir nuestro modelo.

Para ello, crearemos una clase denominada ModelBuilder en el proyecto PredictiveManteinance.Builder.

A continuación enumeraremos los pasos a seguir con los code snippets necesarios.

  1. En primer lugar, debemos agregar una referencia al proyecto PredictiveManteinance.Model.
  2. Debemos añadir las referencias necesarias para utilizar los paquetes Nuget ML.NET.
    using Microsoft.ML;
    using Microsoft.ML.Data;
  3. Declararemos el contexto ML como una propiedad estática de la clase.

    private static MLContext mlContext = new MLContext(seed: 1);
  4. Definiremos una propiedad estática que indique la ruta dónde está ubicado nuestro origen CSV y el destino de nuestro modelo.

    static readonly string TEMPERATURE_DATA_PATH = Path.Combine(Environment.CurrentDirectory, "Data", "temperature_data.csv");
    static readonly string MODEL_PATH = Path.Combine(Environment.CurrentDirectory, "Model", "model.zip");
  5. Realizamos la carga de los datos del CSV que alimentan el modelo.

    IDataView trainingDataView = mlContext.Data.LoadFromTextFile<ModelInput>(
                                                path: TEMPERATURE_DATA_PATH,
                                                hasHeader: true,
                                                separatorChar: ';',
                                                allowQuoting: true,
                                                allowSparse: false);
  6. Para nuestro modelo, vamos a utilizar un algoritmo de árbol de clasificación binaria denominado LightGbmBinaryTrainer.
    Para poder utilizarlo, debemos en primer lugar agregar el paquete Nuget Microsoft.ML.LightGbm a nuestro proyecto.
  7. En primer lugar, definimos las columnas que contienen los datos que utilizaremos como entrada.

    var dataProcessPipeline = mlContext.Transforms.Concatenate("Features", new[] { "machine_temperature", 
                                                    "machine_pressure", "ambient_temperature", "ambient_humidity" });
  8. A continuación, definimos el algoritmo que usaremos para la creación y entrenamiento del modelo y entrenamos el modelo.

    var trainer = mlContext.BinaryClassification.Trainers.LightGbm(labelColumnName: "anomally", 
                              featureColumnName: "Features"); 
    var trainingPipeline = dataProcessPipeline.Append(trainer); 
    ITransformer model = trainingPipeline.Fit(trainingDataView);
  9. Para verificar la fiabilidad del modelo con los datos de entrada, procedemos a evaluarlo.

    var crossValidationResults = mlContext.BinaryClassification.CrossValidate(trainingDataView, trainingPipeline, 
                                                      numberOfFolds: 5, labelColumnName: "anomally");
  10. Por último, grabaremos nuestro modelo exportado en un fichero .zip. Esto nos permitirá utilizarlo más adelante.

      mlContext.Model.Save(mlModel, modelInputSchema, GetAbsolutePath(MODEL_PATH));

 

Consumo del Modelo

Una vez que hemos definido y creado el modelo, sólo tenemos que importarlo en nuestra aplicación y utilizarlo para realizar las predicciones.

Para ello, vamos a agregar una clase que nos permita el consumo en el proyecto PredictiveManteinance.Model.

Esta clase la denominaremos ModelConsumer.cs y permitirá carga el modelo y ejecutar una predicción sobre el mismo.

  1. En primer lugar debemos crear el PredictionEngine que es el encargado de cargar el modelo y nos permitirá ejecutar las predicciones contra el mismo.

    MLContext mlContext = new MLContext();
    string modelPath = "model.zip";
    
    ITransformer mlModel = mlContext.Model.Load(modelPath, out var modelInputSchema);
    var predEngine = mlContext.Model.CreatePredictionEngine<MachineData, MachinePrediction>(mlModel);

    Lo que hacemos es cargar el modelo creado anteriormente en el fichero .zip y a partir del mismo crear el motor de predicción.

  2. A continuación, ya podremos ejecutar la predicción invocando al método Predict del motor de predicción.

    MachineData sampleData = new MachineData ()
                {
                    Machine_temperature = Convert.ToSingle(101.937256),
                    Machine_pressure = Convert.ToSingle(10.2207),
                    Ambient_temperature = Convert.ToSingle(21.497833),
                    Ambient_humidity = Convert.ToSingle(26)
                };
    MachinePrediction result = PredictionEngine.Value.Predict(input);

    Como respuesta obtendremos un objeto MachinePrediction con una propiedad denominada Anomally que indica si la medición es anómala o no.
    Adicionalmente devuelve una propiedad Probability que devuelve un porcentaje de certeza sobre la medición.

 

Implementación del Modelo en el Edge

El siguiente paso del laboratorio consiste en publicar el modelo como un módulo en el Edge.

Gracias al uso de ML.NET, no tendremos ninguna complicación para utilizar el modelo en un contenedor.

Para ello, crearemos un proyecto en  Visual Studio Code con la plantilla de módulo de Azure IoT Edge. Este asistente nos creará el esqueleto del proyecto para añadir nosotros nuestro código.

Una vez creado el proyecto del módulo, copiaremos las clases del modelo del proyecto PredictiveManteinance.Model, de esta forma evitaremos dependencias externas al crear la imagen.

Es importante que añadamos el fichero con el modelo generado model.zip como recurso del proyecto para que siempre se copie cuando se genere la imagen de Docker del módulo.

Si hacemos todos los pasos correctos, tendremos una estructura de proyecto similar a esta..

 

Nuestro IoT Edge utilizará como origen de datos el módulo que genera simulaciones de datos de temperatura.

Para recibir correctamente estos datos en nuestro módulo de predicción, definimos la clase MachineSensorData.cs, la cuál usaremos para representar el objeto JSON que recibimos de dicho módulo.

 

public partial class Temperatures
{
        [JsonProperty("machine")]
        public Machine Machine { get; set; }

        [JsonProperty("ambient")]
        public Ambient Ambient { get; set; }

        [JsonProperty("timeCreated")]
        public DateTimeOffset TimeCreated { get; set; }

        [JsonProperty("anomally")]
        public bool? Anomally { get; set; } 
}

public partial class Ambient
{
        [JsonProperty("temperature")]
        public float Temperature { get; set; }

        [JsonProperty("humidity")]
        public float Humidity { get; set; }
}

public partial class Machine
{
        [JsonProperty("temperature")]
        public float Temperature { get; set; }

        [JsonProperty("pressure")]
        public float Pressure { get; set; }
}

 

La lógica del módulo la implementaremos en el fichero Program.cs de nuestro proyecto de IoT Edge.

En el fondo no es más que una aplicación de consola que se queda en ejecución de forma indefinida cuando se inicia el contenedor del módulo en Docker o Moby.

El asistente de IoT Edge nos genera un Program.cs con una estructura predefinida que nos permite recibir los datos en el método PipeMessage.

Nosotros lo modificaremos para que consuma nuestro modelo de predicción y enriquezca el mensaje de salida añadiendo una propiedad para indicar si la medición es anómala o no.

Para conseguir esto, modificaremos la clase de la siguiente forma:

  • En primer lugar recibiremos los datos del mensaje y los transformaremos en su representación en la clase Temperatures.
byte[] messageBytes = message.GetBytes();
string messageString = Encoding.UTF8.GetString(messageBytes);

Temperatures sensorData = JsonConvert.DeserializeObject<Temperatures>(messageString, 
                                                      serializerSettings);
  • A continuación, generaremos la petición para realizar la llamada al modelo a partir de estos datos, e invocaremos a la predicción.
MachineData input = new MachineData()
{
         Machine_pressure = sensorData.Machine.Pressure,
         Machine_temperature = sensorData.Machine.Temperature,
         Ambient_humidity = sensorData.Ambient.Humidity,
         Ambient_temperature = sensorData.Ambient.Temperature
};

var modelOutput = ModelConsumer.Predict(input);
  • Por último, actualizaremos el mensaje indicando el resultado de la predicción y lo enviaremos como respuesta al siguiente proceso, que en nuestro caso es el IoT Hub
sensorData.Anomally = modelOutput.Anomally;

messageString = JsonConvert.SerializeObject(sensorData, serializerSettings);
messageBytes = Encoding.UTF8.GetBytes(messageString);

using var pipeMessage = new Message(messageBytes);

await moduleClient.SendEventAsync("output1", pipeMessage);

 

Creación de la Infraestructura

Una vez hemos desarrollado el módulo para el Edge, debemos realizar toda la provisión de la infraestructura.

en primer lugar aprovisionaremos una máquina virtual basada en una plantilla de dispositivo IoT Edge para desplegar nuestro módulo.

Adicionalmente aprovisionaremos un Container Registry  para subir los módulos y un IoT Hub para el envío de mensajería y gobierno del dispositivo.

 

Los pasos que seguiremos para la provisión de la infraestructura son los siguientes.

 

  1. Login en nuestra suscripción de Azure con AZ CLI. En este paso nos conectaremos a Azure y seleccionaremos la suscripción dónde queremos trabajar.

    az login
    az account set --subscription <subscriptionId>
  2. El segundo paso consiste en crear el grupo de recursos. En el laboratorio crearemos un grupo de recursos llamado predictive-manteinance-weu-rg en la región Western Europe con el siguiente comando.

    az group create --location westeurope --resource-group predictive-manteinance-weu-rg --subscription <subscriptionId>
  3. A continuación creamos el Azure Container Registry para alojar nuestros módulos en el grupo de recursos.

    az acr create -n labacrpredman -g predictive-manteinance-weu-rg --sku Standard
  4. A continuación provisionamos el IoT Hub y definiremos un dispositivo que será el que represente nuestro Edge. Crearemos un IoT Hub con tier Free, que será suficiente para las pruebas.
    Lo llamaremos predictive-manteinance-weu-ih. Al dispositivo le llamaremos EdgeDevice_01

    az iot hub create --resource-group predictive-manteinance-weu-rg --name predictive-manteinance-weu-ih --sku F1 --partition-count 2
    az iot hub device-identity create --hub-name predictive-manteinance-weu-ih --device-id EdgeDevice_01 --edge-enabled
    
  5. Por último, crearemos la máquina virtual con un template ARM que nos permite configurar automáticamente el motor de Edge y conectarlo con el IoT Hub.

    az group deployment create --name EdgeDevice_01 --resource-group predictive-manteinance-weu-rg --template-uri "https://aka.ms/iotedge-vm-deploy" --parameters dnsLabelPrefix='edge-device-01-vm' 
    --parameters adminUsername='adminlab' --parameters deviceConnectionString=$(az iot hub device-identity show-connection-string --device-id EdgeDevice_01 --hub-name predictive-manteinance-weu-ih -o tsv) 
    --parameters authenticationType='password' --parameters adminPasswordOrKey="development1A"

     

    Con este comando lo que estamos haciendo es crear una máquina virtual en Azure con el DNS edge-device-01-vm.

    Esta máquina se provisiona con la plantilla de máquina de IoT Edge (https://aka.ms/iotedge-vm-deploy) y hacemos que se configure el motor del IoT Edge de la máquina.

    Si hemos hecho todo correctamente y no han surgido errores, deberíamos tener algo similar a esto en el grupo de recursos de Azure.

 

Una vez provisionada la infraestructura, podemos conectarnos por ssh a la máquina y verificar que el motor del IoT Edge está funcionando correctamente.

ssh adminlab@edge-device-01-vm.westeurope.cloudapp.azure.com

Para verificar el estado ejecutaremos el comando iotedge status.

sudo -i
systemctl status iotedge

Si todo está bien configurado obtendremos una respuesta similar a la siguiente.

 

Publicación y Despliegue del Módulo Edge

Una vez tenemos provisionada toda la infraestructura requerida, el siguiente paso consiste en la publicación de nuestro módulo.

Esta tarea conlleva la realización de los siguientes pasos.

 

Configuración del ACR para permitir login de Administrador

Para ello, es necesario en primer lugar habilitar el usuario administrador en nuestro Azure Container Registry labacrpredman.

Esto lo realizamos con el siguiente comando.

az acr update --admin-enabled true --name labacrpredman

Y con el siguiente comando obtendremos las credenciales para subir las imágenes.

az acr credential show --name labacrpredman

Una vez obtenemos esta información, debemos actualizar el fichero deployment.json de nuestra solución añadiendo estas credenciales.

 

Publicación de la imagen de Docker en el ACR

A continuación, ejecutaremos el comando Build and Push IoT Edge Module en Visual Studio Code para publicar la imagen de docker en el ACR.

Será necesario adaptar el fichero module.json para establecer el nombre correcto de la imagen en el ACR.

{
    "$schema-version": "0.0.1",
    "description": "",
    "image": {
        "repository": "labacrpredman.azurecr.io/predictivemanteinance",
        "tag": {
            "version": "0.0.1",
            "platforms": {
                "amd64": "./Dockerfile.amd64", 
                "amd64.debug": "./Dockerfile.amd64.debug",
                "arm32v7": "./Dockerfile.arm32v7",
                "arm32v7.debug": "./Dockerfile.arm32v7.debug",
                "arm64v8": "./Dockerfile.arm64v8",
                "arm64v8.debug": "./Dockerfile.arm64v8.debug",
                "windows-amd64": "./Dockerfile.windows-amd64"
            }
        },
        "buildOptions": [],
        "contextPath": "./"
    },
    "language": "csharp"
}

Si todo funciona correctamente, deberíamos tener en la respuesta de Visual Studio Code algo similar a esto.

The push refers to repository [labacrpredman.azurecr.io/predictivemanteinance]
32e54520ea3b: Pushed
0c457dc75b8b: Pushed
024bb70514d8: Pushed
ba809ad0e044: Pushed
31bd36e157b6: Pushed
6185ed1ad590: Pushed
f5600c6330da: Pushed
0.0.1-amd64: digest: sha256:d270298c033b2de7376155a6e2f07e15011772d1ebbff1fac3dcc4882ca8a623 size: 1790

 

Generación del Manifiesto de Despliegue

A continuación generaremos un manifiesto de despliegue para el dispositivo.

Para ello ejecutaremos el comando Azure IoT Edge: Generate IoT Edge Deployment Manifest, al que le pasaremos como parámetro el fichero deployment.template.json.

Este comando lo que nos generaré es el template definitivo que se podrá aplicar sobre el dispositivo en la carpeta config del proyecto.

Si queremos aplicar este deployment en nuestro dispositivo, será necesario que nos conectemos con el Iot Hub desde Visual Studio Code.

Esto lo llevaremos a cabo de la siguiente forma.

 

Despliegue en el Dispositivo Edge

Una vez conectado al IoT Hub, podemos seleccionar la opción Azure IoT Edge: Create Deployment for Single Device.
Esta opción desencadena un pequeño asistente que solicita seleccionar el dispositivo en el IoT Hub y el deployment que se quiere aplicar.

Al seleccionarlos, aplica la configuración al dispositivo en el IoT Hub, con lo que si accedemos a través del portal de Azure, podremos ver lo siguiente.

Y si accedemos por SSH al dispositivo y ejecutamos el comando docker logs PredictiveMaintenante, podremos comprobar como nuestro módulo estará generando mensajes con la propiedad Anomally que indica si la predicción es anómala o no en base al modelo.

 

Conclusión

Con ML.NET crear, entrenar y publicar un modelo de Machine Learning está a la alcance de los desarrolladores, incluso para proyectos IoT.

Existen multitud de algoritmos que se pueden utilizar para la creación de los modelos y la mayor complejidad radica en saber cuál utilizar en cada caso.

Todo el código utilizado es Open Source y se puede descargar del siguiente repositorio GitHub.

 

Si queréis poneros en contacto con nosotros, podéis hacerlo en info@kabel.es
También podéis seguirnos en Twitter, LinkedIn, Facebook

 

Licencia de Creative Commons

Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial 4.0 Internación 

 

Compártelo: Share on FacebookTweet about this on TwitterShare on LinkedInPin on Pinterest

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

NEWSLETTER