Introducción

En la actualidad, muchas personas tienen conocimientos sobre Machine Learning, pero recién están explorando el mundo de MLOps.
En este artículo, te guiaremos paso a paso para crear tu aplicación web y añadirla a tu portafolio de Machine Learning en Hugging Face Spaces aplicando una interfaz gráfica con Gradio.  

Me interese en compartir con la comunidad sobre como crear un portfolio, sobretodo para personas que recién están comenzando, este fue uno de los ejercicios que hicimos en el bootcamp Data Science de Escuela de Datos Vivos :)

Vamos a utilizar como ejemplo un modelo de clasificación de clientes fraudulentos de una empresa de comercio electrónico.

Contenido

  1. Introducción
  2. ¿Por qué utilizar Hugging Face?
  3. Desarrollo de tu Primera Aplicación en Hugging Face Spaces
    3.1. Registro en Hugging Face
    3.2. Creación de un Espacio (Space)
    3.3. Carga de Archivos
    3.4. Construcción de la Aplicación
  4. Cómo crear la Interfaz Gráfica de nuestra App utilizando Gradio
  5. Comentarios finales
  6. Enlace a la App de Predicción de Clientes Fraudulentos

¿Por qué utilizar Hugging Face?

Hugging Face es un repositorio de modelos de machine learning y deep learning, así como conjuntos de datos. Se está convirtiendo en una de las plataformas open source de mayor crecimiento en la historia. Además, recientemente adquirió Gradio, una herramienta que nos permite crear interfaces gráficas de usuario de forma sencilla.

Desarrollando tu primer App en Hugging Face Spaces

Registro en Hugging Face

El primer paso es Registrarte en el sitio web de Hugging Face Hugging Face presionando el botón de "Sign Up", proporcionando algunos datos básicos y aceptando los términos y condiciones.

Registro en Hugging Face

Una vez creado tu perfil dirigite al ícono de Hugguing Face en la esquina superior izquierda de la pantalla.

Creación de un Espacio (Space)

Aquí vamos a crear un nuevo espacio seleccionando "New"y luego "Space".

En "Create New Space", te pedirá que proporciones un nombre para tu proyecto, el tipo de licencia que deseas utilizar (nosotros seleccionaremos el tipo MIT para que otros puedan visualizar nuestro tu código fuente), el kit de desarrollo de software (SDK) que utilizarás (nosotros utilizaremos Gradio), el hardware necesario (optaremos por la versión gratuita) y por último si querés que tu espacio sea público o privado (optaremos por público).

Una vez que hayas configurado todo, presiona "Create Space".

¡Felicitaciones! En este punto ya deberías tener tu espacio creado.


👩‍💻 Aprende a crear tu portfolio con modelos machine learning desde cero! Descarga programa completo del bootcamp Data Science MLops .


Carga de Archivos

Hugging Face te permite cargar los archivos asociados a tu proyecto de dos formas:
• Utilizando Git
• Utilizando una Interfaz de Hugguing Face Spaces
En este caso, explicaremos cómo utilizar la Interfaz, la cual es muy intuitiva.

Dirígete a la pestaña "Files" en la esquina superior derecha.

Ingresa a “+Add file” y luego a “Upload files”:

En el recuadro donde dice “Upload file(s)” vamos a arrastrar los archivos asociados a nuestro proyecto.
Recuerda que partimos de la base de que ya disponemos de un modelo de Machine Learning entrenado en un formato pickle.
En mi caso arrastraré todos los archivos asociados al Modelo de Detección de Clientes Fraudulentos por nivel de jerarquía donde pondremos:
• Nuestra “app” (aplicación generada en un archivo .py utilizando la librería Gradio)
requeriments.txt (librerías que vamos a utilizar para desarrollar nuestra app en Hugging Face)
• Carpeta “model”

Archivos en Mi PC

La carpeta “model” contiene archivos pickle con nuestro modelo de Machine Learning (en nuestro caso es el Modelo de clasificación de clientes fraudulentos) y otros archivos complementarios en formato pickle en caso de que el modelo lo requiera.

Para este ejemplo los archivos complementarios constaran de:
Categorias del dataframe posterior a la aplicación del One Hot encoding.
Puntos de corte generados para discretizar las variables "orderAmount" y "transactionAmount".

Archivos en Mi PC: carpeta model

IMPORTANTE: Es una condición necesaria el brindarle al sistema el archivo "requirements.txt", de lo contrario el sistema no será capaz de ejecutar la app.

Este es un ejemplo del contenido del archivo requirements.txt para este modelo de ejemplo.

Una vez que hayas arrastrado todos tus archivos se visualizará así:

Construcción de la Aplicación

En la parte superior de la pantalla vas a ver un cartel en amarillo que dice “No Application file” indicando que aun no se ha cargado la app al sistema.

Si queres, podes de agregar un comentario, y luego debes hacer click en "Commit changes to main".

Ahora vas a visualizar como el cartel de “No Application file”,  se transforma en “Building” en color azul (mientras se está construyendo tu App).

Es muy importante visualizar los pasos que está siguiendo la herramienta para generar la App segundo a segundo haciendo click en "Logs" en la parte superior de la pantalla. Esto te permitirá visualizar posibles errores, con un buen nivel de detalle, que te ayudarán a solucionarlos en caso de que se presenten.

Visualización de Logs mientras se construye la App

Una vez que el proceso finalice, el cartel “Building”cambiará de color azul a verde y lo verás como "Running".

Si vas a la pestaña "App" en la parte superior derecha de la pantalla, podrás ver tu aplicación corriendo, testearla y copiar el enlace para compartirlo con quien desees.

Visualización de la App creada

Cómo crear la Interfaz Gráfica de nuestra App utilizando Gradio

Uso de Gradio Blocks

Ahora vamos a utilizar Gradio para crear nuestra aplicación (archivo .py) y así tendrás el procedimiento desde cero.

Utilizaremos Gradio Blocks, que es una clase de bajo nivel que nos brinda control y flexibilidad al diseñar nuestra interfaz.

¿Qué componentes utilizaremos dentro de Gradio?

Utilizaremos Slider, Radio, Dropdown y Markdown (que es un lenguaje de marcado para integrar texto en nuestra interfaz).

Para generar la App, utilizaremos los componentes Row (fila) y Column (columna) para organizar los bloques.

El resultado final que queremos lograr es la App que visualizamos en la última figura.

Elementos de Entrada

Comencemos abriendo un nuevo archivo .py en nuestra PC, al que llamaremos "app".

Importaremos las librerías necesarias.

import gradio as gr
import pandas as pd
import pickle
import os

A continuación, definiremos la ubicación de la carpeta principal utilizando la biblioteca os y las variables de entrada para nuestro modelo de detección de fraudes.

# Definir nombres de parámetros de entrada
PARAMS_NAME = [
    "orderAmount",
    "orderState",
    "paymentMethodRegistrationFailure",
    "paymentMethodType",
    "paymentMethodProvider",
    "paymentMethodIssuer",
    "transactionAmount",
    "transactionFailed",
    "emailDomain",
    "emailProvider",
    "customerIPAddressSimplified",
    "sameCity"
]

Carga de archivos .pickle

Cargaremos el modelo que utilizaremos para la detección de fraudes ya entrenado.

# Cargar Modelo
with open("model/modelo_proyecto_final.pkl", "rb") as f:
    model = pickle.load(f)

Para este modelo aplicamos one-hot encoding, por lo que necesitamos cargar las columnas resultantes posterior a la aplicación de éste método.

# Cargar Columnas
COLUMNS_PATH = "model/categories_ohe_without_fraudulent.pickle"
with open(COLUMNS_PATH, 'rb') as handle:
    ohe_tr = pickle.load(handle)

En este modelo discretizamos dos de las variables : "orderAmount" y "transactionAmount".  Por ese motivo, cargaremos los puntos de corte que generamos para discretizar dichas variables.

# Cargar puntos de corte
BINS_ORDER = os.path.join(MAIN_FOLDER, "model/saved_bins_order.pickle")
with open(BINS_ORDER, 'rb') as handle:
    new_saved_bins_order = pickle.load(handle)

BINS_TRANSACTION = os.path.join(MAIN_FOLDER, "model/saved_bins_transaction.pickle")
with open(BINS_TRANSACTION, 'rb') as handle:
    new_saved_bins_transaction = pickle.load(handle)

Definición de la Función predict

Ahora definiremos la función predict que acepta un número variable de argumentos (*args). La función creará un diccionario vacío llamado answer_dict y asignará cada argumento dado a la correspondiente clave en answer_dict.

Luego, creará un DataFrame llamado single_instancea partir de answer_dict.

En el DataFrame single_instance, convertiremos los valores en la columna "orderAmount"a tipo float y los dividiremos en intervalos utilizando el método pd.cut.

Utilizaremos los puntos de corte almacenados en new_saved_bins_order, asegurándonos de que los intervalos incluyan el valor más bajo. Realizaremos el mismo procedimiento para la columna "transactionAmount".

Aplicaremos el one-hot encoding al DataFrame single_instance utilizando el método pd.get_dummies.

El resultado se almacenará en single_instance_ohey se reindexará para tener solo las columnas presentes en ohe_tr. Los valores faltantes se llenarán con ceros.

Realizaremos una predicción utilizando nuestro modelo (model) en el data frame single_instance_ohe.

El resultado se almacenará en la variable prediction.

Convertiremos el tipo de dato de prediction de numpy.int64 a integer. Luego, asignaremos una respuesta inicial de "Error parsing value".

Dependiendo del valor de type_of_fraud, actualizaremos la respuesta a "False" si es 0, "True"si es 1 y "Warning" si es 2. Por último, devolveremos la respuesta.

def predict(*args):
    answer_dict = {}

    for i in range(len(PARAMS_NAME)):
        answer_dict[PARAMS_NAME[i]] = [args[i]]

    # Crear dataframe
    single_instance = pd.DataFrame.from_dict(answer_dict)

    # Manejar puntos de corte o bins
    single_instance["orderAmount"] = single_instance["orderAmount"].astype(float)
    single_instance["orderAmount"] = pd.cut(single_instance['orderAmount'],
                                 bins=new_saved_bins_order, 
                                 include_lowest=True)

    single_instance["transactionAmount"] = single_instance["transactionAmount"].astype(int)
    single_instance["transactionAmount"] = pd.cut(single_instance['transactionAmount'],
                                 bins=new_saved_bins_order, 
                                 include_lowest=True)

    # One hot encoding
    single_instance_ohe = pd.get_dummies(single_instance).reindex(columns = ohe_tr).fillna(0)

    prediction = model.predict(single_instance_ohe)

    # Cast numpy.int64 to just a int
    type_of_fraud = int(prediction[0])

    # Adaptación respuesta
    response = "Error parsing value"
    if type_of_fraud == 0:
        response = "False"
    if type_of_fraud == 1:
        response = "True"
    if type_of_fraud == 2:
        response = "Warning"

    return response

Construcción de la interfaz gráfica

A continuación, comenzaremos a construir la interfaz utilizando Gradio Blocks.

Utilizaremos el contexto with gr.Blocks() as demo para definir un bloque de construcción para la interfaz de usuario.

Títulos y Subtítulos (gr.Markdown)

Utilizaremos gr.Markdown para mostrar un encabezado en formato Markdown que indique "Prevención de Fraude".

with gr.Blocks() as demo:
    gr.Markdown(
        """
        # Prevención de Fraude 🔍 🔍 
        """
    )

Utilizaremos gr.Row() para crear una fila en la interfaz de usuario. Dentro de la fila, utilizaremos gr.Column() para crear dos columnas en la interfaz de usuario acorde a donde queremos llegar.

En la primera columna, utilizaremos gr.Markdown para mostrar un sub encabezado en formato Markdown que indique "Predecir si un cliente es fraudulento o no".

    with gr.Row():
        with gr.Column():

            gr.Markdown(
                """
                ## Predecir si un cliente es fraudulento o no.
                """
            )

Deslizadores (gr.Slider), Botones de radio (gr.Radio) y Menús desplegables (gr.Dropdown)

Luego, definiremos varios elementos de entrada, como deslizadores (gr.Slider), botones de radio (gr.Radio) y menús desplegables (gr.Dropdown), para que el usuario ingrese los valores necesarios para la predicción.

A cada variable de entrada se le asignará una etiqueta, valores mínimos y máximos para dicha variable, los escalones de cuanto en cuanto se puede seleccionar y se definirá el valor en el que aparecerá cada variable previo a seleccionar un valor (puede ser un valor random o un valor predeterminado).

A continuación veremos los ejemplos del fragmento de código para cada variable y como se visualiza en la App.  El primer Slider(gr.Slider). para order amount:

            orderAmount = gr.Slider(label="Order amount", minimum=0, maximum=355, step=2, randomize=True)

Luego crearemos tres elementos de entrada tipo botones de Radio (gr.Radio). Cada uno tiene una etiqueta, una lista de opciones y un valor predeterminado:

  1. orderState: Permite al usuario seleccionar el estado de la orden, con opciones de "fulfilled", "failed" o "pending", y el valor predeterminado es "failed".
  2. paymentMethodRegistrationFailure: Permite al usuario seleccionar si hubo un fallo en el registro del método de pago, con opciones "False" o "True", y el valor predeterminado es "True".
  3. paymentMethodType: Permite al usuario seleccionar el tipo de método de pago, con opciones de "card", "apple pay", "paypal" o "bitcoin", y el valor predeterminado es "bitcoin".
            orderState = gr.Radio(
                label="Order state",
                choices=["fulfilled", "failed", "pending"],
                value="failed"
                )

            paymentMethodRegistrationFailure = gr.Radio(
                label="Payment method registration failure",
                choices=["False", "True"],
                value="True"
                )

            paymentMethodType = gr.Radio(
                label="Payment method type",
                choices=["card", "apple pay ", "paypal", "bitcoin"],
                value="bitcoin"
                )

Luego crearemos dos menús desplegables utilizando Dropdown(gr.Dropdown) para que los usuarios seleccionen el proveedor y el emisor del método de pago. Cada menú desplegable tiene una etiqueta, una lista de opciones, la capacidad de seleccionar solo una opción (configurada con multiselect=False) y un valor predeterminado.

Estos menús desplegables permiten a los usuarios elegir entre una lista de opciones predefinidas, lo que facilita la entrada de información necesaria para la predicción en tu aplicación.

            paymentMethodProvider = gr.Dropdown(
                label="Payment method provider",
                choices=["JCB 16 digit", "VISA 16 digit", "Voyager", "Diners Club / Carte Blanche", "Maestro", "VISA 13 digit", "Discover", "American Express", "JCB 15 digit", "Mastercard"],
                multiselect=False,
                value="American Express"
                )
            
            paymentMethodIssuer = gr.Dropdown(
                label="Payment method issuer",
                choices=["Her Majesty Trust", "Vertex Bancorp", "Fountain Financial Inc.", "His Majesty Bank Corp.", "Bastion Banks", "Bulwark Trust Corp.", "weird", "Citizens First Banks", "Grand Credit Corporation", "Solace Banks", "Rose Bancshares"],
                multiselect=False,
                value="Bastion Banks"
                )

Ahora definiremos varias variables de entrada para que los usuarios ingresen valores necesarios para la predicción. Cada variable tiene una etiqueta, valores mínimos y máximos (en el caso del Slider transactionAmount), un valor predeterminado y opciones de selección predefinidas (en el caso de los botones de radio).

Estas variables permiten a los usuarios especificar información relevante para la predicción, como el monto de la transacción, si la transacción falló, el dominio de correo electrónico, el proveedor de correo electrónico, la simplicidad de la dirección IP del cliente y si están en la misma ciudad. Esto facilita la entrada de datos y la interacción del usuario con tu aplicación.

            transactionAmount = gr.Slider(label="Transaction amount", minimum=0, maximum=355, step=2, randomize=True)

            transactionFailed = gr.Radio(
                label="Transaction failed",
                choices=["False", "True"],
                value="False"
                )

            emailDomain = gr.Radio(
                label="Email domain",
                choices=["com", "biz", "org", "net", "info", "weird"],
                value="com"
                )

            emailProvider = gr.Radio(
                label="Email provider",
                choices=["gmail", "hotmail", "yahoo", "other", "weird"],
                value="gmail"
                )

            customerIPAddressSimplified = gr.Radio(
                label="Customer IP Address",
                choices=["only_letters", "digits_and_letters"],
                value="only_letter"
                )

            sameCity = gr.Radio(
                label="Same city",
                choices=["unknown", "no", "yes"],
                value="unknown"
                )

Ahora acabamos de finalizar la primer columna de nuestra App, por lo que ahora pasaremos a la segunda.

En la segunda columna, utilizaremos gr.Markdownpara mostrar un subencabezado en formato Markdown que indique "Predicción".

Etiqueta (gr.Label) y Definición de la Función de Predicción

Luego, crearemos una etiqueta (gr.Label) que mostrará el resultado de la predicción. También crearemos un botón (gr.Button) con el valor "Evaluar". Este botón llamará a la función predict cuando se haga click en él.

Especificaremos la función predict como la función a llamar cuando se haga click en el botón y pasaremos los elementos de entrada necesarios como argumentos para la función predict.

La etiqueta se especifica como una salida que mostrará el resultado de la predicción.

        with gr.Column():

            gr.Markdown(
                """
                ## Predicción
                """
            )

            label = gr.Label(label="Score")
            predict_btn = gr.Button(value="Evaluar")
            predict_btn.click(
            predict,
            inputs=[
                orderAmount,
                orderState,
                paymentMethodRegistrationFailure,
                paymentMethodType,
                paymentMethodProvider,
                paymentMethodIssuer,
                transactionAmount,
                transactionFailed,
                emailDomain,
                emailProvider,
                customerIPAddressSimplified,
                sameCity,
            ],
            outputs=[label],
            api_name="prediccion"
            )

Utilizaremos gr.Markdown para mostrar un texto debajo en la App que diga "Proyecto Final Kari".

    gr.Markdown(
        """
        <p style='text-align: center'>
            <a >Proyecto Final Kari 
            </a>
        </p>
        """
    )

Por último, llamaremos al método launch() del bloque de construcción demo para lanzar la interfaz de usuario.

El argumento share=True dentro de launch() indica que se puede compartir la App mediante una Url publica que estará disponible por 72 hs siempre y cuando mantenga la app corriendo en mi PC.

Es importante recalcar que cuando usamos Hugguing Face NO se debe utilizar dicho argumento, solo se utiliza en caso de querer generar un túnel de acceso para las personas a las que quiero compartirles mi App disponibilizándola en una URL pública en Python desde Mi PC.

demo.launch()

Comentarios finales

En este tutorial, hemos explorado cómo crear una aplicación de Machine Learning en Hugging Face Spaces con Gradio. Espero que hayas encontrado este tutorial útil para iniciarte en este emocionante campo en constante evolución.

Sigue estos pasos y estarás en camino de desarrollar aplicaciones de forma sencilla y visualmente atractiva.

Enlace a la App de Predicción de Clientes Fraudulentos

Aquí te dejo el link a la App que hemos creado:

Predicción de Clientes Fraudulentos

Si deseas explorar más sobre este proyecto, hacer alguna consulta o colaborar, no dudes en visitar mi perfil en LinkedIn o Github, donde comparto contenido relacionado con machine learning.

Por Karina Cardozo


👩‍💻 Empezá tu carrera en Data Science MLops con EDVai, inscripción al bootcamp abierta! Ver programa completo.