Tras la fase de desarrollo del modelo, tendremos un modelo resolutivo según nuestras expectativas y que satisface nuestras necesidades. Para que este modelo sea útil y cumpla la función para la que ha sido entrenado, debemos ponerlo a disposición en algún entorno que nos permita su utilización. Aquí proponemos un entorno gratuito llamado Render
, pero puede trasladarse a otros entornos, gratuitos o de pago.
Render es una plataforma de computación en la nube que facilita el despliegue, el hosting y la ejecución de aplicaciones, bases de datos, tareas programadas y otros servicios. A menudo se describe como una plataforma fácil de usar que combina la facilidad de las plataformas como Heroku con el poder y la flexibilidad de los proveedores de nube más tradicionales como AWS.
Algunas características y ofertas clave de Render incluyen:
Render se ha ganado una reputación positiva por ser una opción atractiva para desarrolladores y startups que buscan una forma rápida y sencilla de desplegar y escalar aplicaciones sin la sobrecarga administrativa de las soluciones más tradicionales.
Para poder acceder a Render debemos tener una cuenta. Para registrarse se debe acceder al siguiente enlace. Una vez tenemos una cuenta, se nos habilita el acceso a todas las funcionalidades de Render:
Podemos crear servicios de bases de datos, de despliegue web, tareas programadas...
En esta lección integraremos el modelo de clasificación que hemos desarrollado en el módulo de los árboles de decisión.
El modelo decision_tree_classifier_default_42.sav
se ha guardado en un objeto Pickle
de tal forma que pueda ser utilizado, por ejemplo, para desplegarlo en un servicio web, como este caso.
Para integrar algo en Render primero debemos haber creado un repositorio en Git. El Git que vamos a generar en esta lección se encuentra aquí, que deriva del Machine Learning Template de 4Geeks.
Ahora generaremos una aplicación sencilla utilizando la librería Flask
. En el directorio src
, creamos un archivo nuevo llamado app.py
que modificaremos con el siguiente código:
1from flask import Flask 2app = Flask(__name__) 3 4@app.route("/") 5def hello_world(): 6 return "Hello, World!"
El archivo creado servirá como un ejemplo mínimo de cómo manejar las solicitudes HTTP. En él se importa el objeto Flask
y se crea una función que devuelve una respuesta HTTP.
Ahora mismo el repositorio luce de la siguiente forma:
Para ejecutar la aplicación en local necesitamos la librería de Python gunicorn
. Simplemente debemos instalarla, acceder con la consola al directorio donde se encuentra el script y ejecutar gunicorn app:app
.
Al terminar se pondra a disposición una dirección a través de la cual podemos acceder a la aplicación web:
En este caso, como estamos desarrollándolo en un Codespace, el enlace es distinto al que se generaría en local, que sería http://127.0.0.1:8000
.
En este punto tenemos una pequeña aplicación web Flask con poca o casi ninguna funcionalidad. A continuación, añadiremos archivos HTML para personalizar la aplicación.
Como hemos mencionado al inicio de la lección, queremos integrar el árbol de decisión entrenado para el conjunto de datos de Iris del repositorio UCI de Machine Learning. Este conjunto de datos cuenta con 4 variables predictoras: anchura del pétalo (petal width (cm)
), longitud del pétalo (petal length (cm)
), anchura del sépalo (sepal width (cm)
) y longitud del sépalo (sepal length (cm)
).
Crearemos un HTML que permita introducir un valor para cada variable para poder llevar a cabo la predicción:
1<!DOCTYPE html> 2<html> 3<head> 4 <title>Iris - Model prediction</title> 5</head> 6<body> 7 <h2>Introduce the values</h2> 8 9 <form action="/" method="post"> 10 Petal width: <input type="number" step="any" name="val1" required><br><br> 11 Petal length: <input type="number" step="any" name="val2" required><br><br> 12 Sepal width: <input type="number" step="any" name="val3" required><br><br> 13 Sepal length: <input type="number" step="any" name="val4" required><br><br> 14 <input type="submit" value="Predict"> 15 </form> 16 17 {% if prediction != None %} 18 <h3>Prediction: {{ prediction }}</h3> 19 {% endif %} 20</body> 21</html>
Este HTML contiene un título y un formulario en el que se deben introducir los valores asociados a cada campo. A continuación, pulsando sobre el botón Predict
aparecerá un elemento que contiene la predicción del modelo, en función de los valores introducidos. En el HTML hay unas sentencias entre llaves que es código Python puro, una curiosa sintaxis que utiliza Flask para introducir valores de manera dinámica.
Todas las plantillas HTML que generemos deben ir en una carpeta templates
que se debe crear al mismo nivel que el app.py
. Llamamos a este fichero index.html
y lo almacenamos en la carpeta.
Además de crear la plantilla anterior, debemos actualizar el código para que se alimente del HTML, reciba los campos y pueda devolver una predicción. Así, el archivo app.py
lo actualizaríamos:
1from flask import Flask, request, render_template 2from pickle import load 3 4app = Flask(__name__) 5model = load(open("/workspaces/flask-render-integration/models/decision_tree_classifier_default_42.sav", "rb")) 6class_dict = { 7 "0": "Iris setosa", 8 "1": "Iris versicolor", 9 "2": "Iris virginica" 10} 11 12@app.route("/", methods = ["GET", "POST"]) 13def index(): 14 if request.method == "POST": 15 16 val1 = float(request.form["val1"]) 17 val2 = float(request.form["val2"]) 18 val3 = float(request.form["val3"]) 19 val4 = float(request.form["val4"]) 20 21 data = [[val1, val2, val3, val4]] 22 prediction = str(model.predict(data)[0]) 23 pred_class = class_dict[prediction] 24 else: 25 pred_class = None 26 27 return render_template("index.html", prediction = pred_class)
Hemos creado la función index
, que reemplaza a la antigua hello_world
y que se nutre de los valores que se introduzcan en el HTML para desencadenar el proceso de predicción. Esto es así porque cuando se hace clic sobre el botón Predict
, se envía una petición POST al script y se leen los valores introducidos en el formulario del HTML para realizar la predicción.
En última instancia, el método devuelve el HTML renderizado, en este caso con el valor de la predicción en función de los valores.
Ahora mismo el repositorio luce de la siguiente forma:
Si guardamos los cambios y ejecutamos de nuevo la aplicación (gunicorn app:app
), tras navegar a nuestra aplicación web en local veremos lo siguiente:
Tras rellenar los valores y hacer clic sobre Predict
, el resultado se muestra también en la propia interfaz:
Al introducir cualquier valor se predice una clase. Además, la efectividad del modelo es la observada en el módulo pasado.
La interfaz web parece muy simple y poco atractiva de cara a los usuarios. El siguiente paso es darle algo de estilo.
Una manera fácil de añadir estilos es utilizando CSS. Podemos agregar un bloque <style>
justo encima del HTML para mejorarlo visualmente. El código CSS
que incluiremos será el siguiente:
1body { 2 font-family: Arial, sans-serif; 3 margin: 40px; 4 background-color: #f4f4f4; 5} 6form { 7 background-color: #fff; 8 padding: 20px; 9 border-radius: 8px; 10 box-shadow: 0px 0px 15px rgba(0,0,0,0.1); 11} 12input[type="number"] { 13 width: 100%; 14 padding: 10px; 15 margin: 10px 0; 16 border-radius: 4px; 17 border: 1px solid #ccc; 18} 19input[type="submit"] { 20 background-color: #333; 21 color: #fff; 22 padding: 10px 15px; 23 border: none; 24 border-radius: 4px; 25 cursor: pointer; 26} 27input[type="submit"]:hover { 28 background-color: #555; 29} 30h3 { 31 margin-top: 20px; 32 background-color: #fff; 33 padding: 10px; 34 border-radius: 4px; 35}
El código anterior establece un fondo claro para toda la página, y destaca el formulario y el encabezado con un fondo blanco y bordes suavemente redondeados. Los campos de entrada son más espaciosos y visuales, con bordes y rellenos adecuados, y el botón de envío presenta un cambio de color cuando se pasa el cursor sobre él, proporcionando retroalimentación visual. Además, se emplea una tipografía más legible y se separan adecuadamente los elementos con márgenes para evitar que se sientan apretados.
Al introducirlo en el HTML, el código quedaría tal que así:
1<!DOCTYPE html> 2<html> 3<head> 4 <title>Iris - Model prediction</title> 5 <style> 6 body { 7 font-family: Arial, sans-serif; 8 margin: 40px; 9 background-color: #f4f4f4; 10 } 11 form { 12 background-color: #fff; 13 padding: 20px; 14 border-radius: 8px; 15 box-shadow: 0px 0px 15px rgba(0,0,0,0.1); 16 } 17 input[type="number"] { 18 width: 100%; 19 padding: 10px; 20 margin: 10px 0; 21 border-radius: 4px; 22 border: 1px solid #ccc; 23 } 24 input[type="submit"] { 25 background-color: #333; 26 color: #fff; 27 padding: 10px 15px; 28 border: none; 29 border-radius: 4px; 30 cursor: pointer; 31 } 32 input[type="submit"]:hover { 33 background-color: #555; 34 } 35 h3 { 36 margin-top: 20px; 37 background-color: #fff; 38 padding: 10px; 39 border-radius: 4px; 40 } 41 </style> 42</head> 43<body> 44 <h2>Introduce the values</h2> 45 46 <form action="/" method="post"> 47 Petal width: <input type="number" step="any" name="val1" required><br><br> 48 Petal length: <input type="number" step="any" name="val2" required><br><br> 49 Sepal width: <input type="number" step="any" name="val3" required><br><br> 50 Sepal length: <input type="number" step="any" name="val4" required><br><br> 51 <input type="submit" value="Predict"> 52 </form> 53 54 {% if prediction != None %} 55 <h3>Prediction: {{ prediction }}</h3> 56 {% endif %} 57</body> 58</html>
Tras volver a ejecutar la aplicación y acceder de nuevo a la interfaz web, este es su nuevo aspecto:
Y nuevamente, al rellenar los valores y lanzar la predicción, así se muestra en el front:
Tras desarrollar la funcionalidad deseada y contar con un front que satisface nuestras necesidades, integraremos todo esto en Render.
El último paso es configurar el servicio en Render y conectarlo con nuestro repositorio Git. Debemos ir al Dashboard de Render, seleccionar el apartado de Web Services
y elegir el repositorio en el que hayamos subido todo el código y las carpetas anteriores.
Una vez lo seleccionemos nos aparecerá un formulario como el siguiente:
Deberemos rellenarlo con la siguiente información:
Name
: El nombre que queramos que tenga nuestro servicio. En este caso introduciremos 4geeks-flask-integration
Branch
: La rama en la que se encuentra nuestro código actualizado, siempre en la última versión. Deberemos dejar el valor por defecto, main
.Root Directory
: En este caso hemos desarrollado el código dentro de la carpeta src
, que incluye el script de Python, el template HTML y las librerías del proyecto (archivo requirements.txt
), por lo que deberemos introducir src
.Runtime
: El código es Python, así que dejaremos el valor por defecto, Python 3
.Build Command
: Dejaremos el valor por defecto, pip install -r requirements.txt
.Start Command
: Ya conocemos este comando, lo hemos utilizado en el desarrollo, así que dejaremos el valor por defecto, gunicorn app:app
.Por último, elegiremos la tarifa gratuita. El formulario, una vez relleno, debería tener la siguiente información:
En el siguiente paso nos aparecerá una consola con los registros (logs) del despliegue de la aplicación. El despliegue se hace paso a paso, clonando en primer lugar el repositorio, construyéndolo (build), instalando las dependencias, y, en último lugar, ejecutando el comando para lanzar la aplicación web.
Debido a que el entorno de Render es diferente a nuestro entorno de desarrollo (especialmente en la versión de Python, ya que se utiliza por defecto la 3.7 y en este caso nosotros usamos de la 3.10 hacia arriba), puede que nos arroje un error la build del proyecto. En este caso su resolución es muy simple:
Tenemos que acceder, en la misma pantalla donde se abre el log de la ejecución, al apartado Environment
e introducir una nueva variable de entorno. En este caso nosotros tenemos la versión 3.11.4
de Python, pero se podría introducir cualquier otra (siempre y cuando sea a partir de la 3.7).
Volvemos a lanzar el despliegue y ahora debería funcionar.
Una vez el despliegue haya sido satisfactorio, este será el log que se mostrará:
De hecho, hay disponible un apartado en el que podemos visualizar los distintos despliegues de nuestra aplicación web y el status de cada uno de ellos:
Una vez que el despliegue ha sido satisfactorio, accedemos a la aplicación desde el enlace situado ju sto debajo del nombre del servicio, y ya podemos utilizar la aplicación y compartírsela a nuestros amigos/compañeros/clientes. La que hemos creado en esta lección está accesible en el siguiente enlace: https://fourgeeks-flask-integration.onrender.com/
.
Nota: Al haber utilizado el plan gratuito, puede que Render tire la aplicación si no se utiliza. Depende de cuando leas esto la aplicación estará operativa o no.