Los modelos de Machine Learning son herramientas poderosas para hacer predicciones basadas en los datos disponibles. Para que estos modelos sean útiles para la sociedad, deben implementarse para que otros puedan acceder fácilmente a ellos para hacer predicciones. Esto se puede hacer usando Flask y Heroku.
Flask es un marco web de Python pequeño y liviano que proporciona herramientas y características útiles que facilitan la creación de aplicaciones web usando solo un archivo de Python.
Heroku es una plataforma en la nube que le permite crear, entregar, monitorear y escalar aplicaciones. Heroku hace que los procesos de implementación, configuración, escalado, ajuste y administración de aplicaciones sean lo más simple y directos posible para que los desarrolladores puedan concentrarse en crear excelentes aplicaciones. También incluye un rico ecosistema de servicios de datos administrados.
Imaginemos que acabamos de terminar de crear nuestro modelo de predicción de supervivencia del Titanic. ¿Ahora qué?
Para predecir con datos desconocidos, tenemos que implementarlos en Internet para que el mundo exterior pueda usarlos.
Para eso, necesitaremos guardar el modelo para que podamos predecir los valores más tarde. Hacemos uso de Pickle en Python, que es un poderoso algoritmo para serializar y deserializar una estructura de objeto de Python, pero también hay otras herramientas. El siguiente código guarda el modelo usando Pickle:
1# Serializando nuestro modelo a un archivo llamado model.pkl 2import pickle 3filename = 'model.pkl' 4pickle.dump(classifier, open(filename,'wb'))
Para predecir la supervivencia en el Titanic a partir de varios atributos, primero debemos recopilar los datos (nuevos valores de atributos) y luego usar el modelo que construimos para predecir si un pasajero sobreviviría o no en el Titanic. Por lo tanto, para recopilar los datos, creamos un formulario html que contendría todas las diferentes opciones para seleccionar de cada atributo. Aquí, he creado un formulario simple usando solo html. Si deseas que el formulario sea más interactivo, también puedes hacerlo.
En la línea de comando ingresa el directorio de tu proyecto. Una vez allí, activa su entorno y usa pip
para instalar Flask.
1pip install Flask
En tu directorio, abre un archivo llamado hello.py
para editarlo. Este archivo servirá como un ejemplo mínimo de cómo manejar las solicitudes HTTP. En el interior, importa el objeto Flask y crea una función que devuelva una respuesta HTTP. Escribe el siguiente código dentro de hello.py
:
1from flask import Flask 2 3app = Flask(__name__) 4 5 6@app.route('/') 7def hello(): 8 return 'Hello, World!'
Expliquemos lo que acaba de hacer el código anterior. Primero importa el objeto Flask del paquete Flask. Luego lo usará para crear su instancia de la aplicación Flask con el nombre app. Pasa la variable especial __name__
que contiene el nombre del módulo de Python actual. Se utiliza para decirle a la instancia dónde se encuentra. Deberá hacer esto porque Flask configura algunas rutas en segundo plano.
Una vez que crea la instancia de la aplicación, la usa para manejar las solicitudes web entrantes y enviar respuestas al usuario. @app.route
es un decorador que convierte una función normal de Python en una función de vista Flask, que convierte el valor de retorno de la función en una respuesta HTTP que mostrará un cliente HTTP, como un navegador web. Pasa el valor '/'
a @app.route()
para indicar que esta función responderá a las solicitudes web de la URL /
, que es la URL principal.
La función de vista hello()
devuelve la cadena 'Hello, World!' en respuesta.
Guarda y cierra el archivo.
Para ejecutar su aplicación web, primero le indicarás a Flask dónde encontrar la aplicación (el archivo hello.py
en su caso) con la variable de entorno FLASK_APP
:
1export FLASK_APP=hello
Luego, ejecútalo en modo desarrollo con la variable de entorno FLASK_ENV
:
1export FLASK_ENV=development
Finalmente, ejecuta la aplicación usando flask run
:
1flask run
Una vez que se está ejecutando, el resultado debería ser similar a este:
1Output 2 * Serving Flask app "hello" (lazy loading) 3 * Environment: development 4 * Debug mode: on 5 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) 6 * Restarting with stat 7 * Debugger is active! 8 * Debugger PIN: 813-894-335
El resultado anterior contiene diversa información, tal como:
El nombre de la aplicación que estás ejecutando.
El entorno en el que se ejecuta la aplicación.
Debug mode: on significa que el depurador Flask se está ejecutando. Esto es útil durante el desarrollo porque nos brinda mensajes de error detallados cuando algo sale mal, lo que facilita la resolución de problemas.
La aplicación se ejecuta localmente en la URL http://127.0.0.1:5000/
, 127.0.0.1 es la IP que representa el host local de su computadora y :5000 es el número de puerto.
Ahora tienes una pequeña aplicación web Flask. Ha ejecutado su aplicación y ha mostrado información en el navegador web. A continuación, utilizará los archivos HTML en su aplicación.
Actualmente, su aplicación solo muestra un mensaje simple sin HTML. Las aplicaciones web utilizan principalmente HTML para mostrar información al visitante, por lo que ahora trabajarás para incorporar un archivo HTML en tu aplicación, que se puede mostrar en el navegador web.
Flask proporciona una función auxiliar render_template()
que permite el uso del motor de plantillas Jinja. Esto hará que la administración de HTML sea mucho más fácil al escribir su código HTML en archivos .html
, además de usar la lógica en su código HTML. Utilizarás estos archivos HTML (plantillas) para crear tu aplicación web.
En este paso, crearás tu aplicación Flask principal en un archivo nuevo.
Primero, en el directorio de tu proyecto, usa tu editor de texto favorito para crear y editar tu archivo app.py
. Anteriormente, has estado usando app.py
para escribir el código de tu modelo final. Para evitar confusiones, ahora usarás model.py
o titanic.py
para eso, y el app.py
será exclusivamente para construir tu aplicación web. Esto albergará todo el código que utilizarás para crear la aplicación.
En este nuevo archivo, importarás el objeto Flask para crear una instancia de la aplicación Flask, como lo hiciste antes. También importará la función auxiliar render_template()
que le permite renderizar archivos de plantilla HTML que existen en la carpeta de plantillas que estás a punto de crear. El archivo tendrá una función de vista única que se encargará de manejar las solicitudes en la ruta principal /
. Agrega el siguiente contenido:
1import numpy as np 2import flask 3import pickle 4from flask import Flask, render_template, request 5 6app = Flask(__name__) 7 8@app.route('/') 9def index(): 10 return render_template('index.html')
La función de vista index()
devuelve el resultado de invocar render_template()
con index.html
como argumento; esto le indica a render_template()
que busque un archivo llamado index.html
en la carpeta templates
. La carpeta y el archivo aún no existen y recibirá un error si ejecutas la aplicación en este momento. Lo ejecutarás de todos modos, para que estés familiarizado con esta excepción que se encuentra comúnmente. Luego lo resolverá creando la carpeta y el archivo necesarios.
Guarda el archivo y ciérralo.
Detén el servidor de desarrollo en tu otro terminal ejecutando la aplicación hello con Ctrl + c
.
Antes de ejecutar la aplicación, asegúrate de especificar correctamente el valor de la variable de entorno FLASK_APP, ya que ahora no estás utilizando la aplicación hello.
1export FLASK_APP=app 2flask run
Si haces clic en esta línea, el depurador revelará más código para que tengas más contexto que te ayude a resolver el problema.
Probablemente, verás un error que muestra template not found (index.html).
Vamos a crear plantillas de carpetas. En tu aplicación, utilizarás plantillas para representar HTML que se mostrará en el navegador del usuario. Esta carpeta contiene nuestro archivo de formulario HTML index.html
. Comienza a editar tu archivo index.html
escribiendo el siguiente código:
1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <title>ML app</title> 6</head> 7<body> 8 <h1>Welcome to my Titanic Survival prediction app</h1> 9</body> 10</html>
Además de la carpeta de plantillas, las aplicaciones web de Flask también suelen tener una carpeta estática para albergar archivos, como los archivos CSS, los archivos JavaScript y las imágenes que utiliza la aplicación.
Puedes crear un archivo de hoja de estilo style.css
para agregar CSS a tu aplicación. Primero, crea un directorio llamado static
dentro de tu directorio principal del proyecto. Luego crea otro directorio llamado css
dentro de static
para alojar los archivos .css
. Se puede hacer lo mismo con archivos js e imágenes para aplicaciones más complejas.
Dentro de su directorio css
, crea un archivo style.css
y agrega la siguiente regla:
1h1 { 2 border: 2px #eee solid; 3 color: brown; 4 text-align: center; 5 padding: 10px; 6}
Este código agregará un borde, cambiará el color a marrón, centrará el texto y agregará un pequeño relleno a los tags h1.
Guarda y cierra el archivo.
En tu archivo index.html
agregarás un enlace a tu archivo style.css
:
1<head> 2 <meta charset="UTF-8"> 3 <link rel="stylesheet" href="{{ url_for('static', filename= 'css/style.css') }}"> 4 <title>Welcome to my Titanic Survival prediction app</title> 5</head>
Aquí utilizas la función auxiliar url_for()
para generar la ubicación de archivo adecuada. El primer argumento especifica que está vinculando a un archivo estático y el segundo argumento es la ruta al archivo dentro del directorio estático.
Guarda y cierra el archivo.
Después de actualizar la página index de tu aplicación, notarás que el texto Welcome to my Titanic Survival prediction app ahora es marrón, está centrado y enmarcado dentro de un borde.
Puedes poner el estilo que desees en tu archivo style.css
. Sin embargo, el kit de herramientas de Bootstrap puede ayudarte con esto si no eres un experto. Ahora, si tu aplicación tendrá más de una página, puedes evitar la repetición innecesaria de código con la ayuda de un archivo de plantilla base, del cual heredarán todos tus archivos HTML. Si ese es el caso, puedes escribir el siguiente código en tu archivo base.html
:
1<!doctype html> 2<html lang="en"> 3 <head> 4 <!-- Required meta tags --> 5 <meta charset="utf-8"> 6 <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> 7 8 <!-- Bootstrap CSS --> 9 <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> 10 11 <title>{% block title %} {% endblock %}</title> 12 </head> 13 <body> 14 <nav class="navbar navbar-expand-md navbar-light bg-light"> 15 <a class="navbar-brand" href="{{ url_for('index')}}">FlaskBlog</a> 16 <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"> 17 <span class="navbar-toggler-icon"></span> 18 </button> 19 <div class="collapse navbar-collapse" id="navbarNav"> 20 <ul class="navbar-nav"> 21 <li class="nav-item active"> 22 <a class="nav-link" href="#">About</a> 23 </li> 24 </ul> 25 </div> 26 </nav> 27 <div class="container"> 28 {% block content %} {% endblock %} 29 </div> 30 31 <!-- Optional JavaScript --> 32 <!-- jQuery first, then Popper.js, then Bootstrap JS --> 33 <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> 34 <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> 35 <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> 36 </body> 37</html>
Guarda y cierra el archivo una vez que hayas terminado de editarlo.
La mayor parte del código en el bloque anterior es HTML estándar y código requerido para Bootstrap. Los tags <meta>
brindan información para el navegador web, el tag <link>
vincula a los archivos CSS de Bootstrap y los tags <script>
son vínculos al código JavaScript que habilita alguna funcionalidad adicional de Bootstrap.
Sin embargo, las siguientes partes resaltadas son específicas del motor de plantillas Jinja:
{% block title %} {% endblock %}
: un bloque que sirve como marcador de posición para un título. Luego lo usarás en otras plantillas para dar un título personalizado a cada página de tu aplicación sin tener que volver a escribir la sección <head>
completa cada vez.
{{ url_for('index')}}
: una invocación de función que devolverá la URL para la función de vista index()
. Esto es diferente de la invocación anterior de url_for()
que usó para vincular a un archivo CSS estático, porque solo requiere un argumento, que es el nombre de la función de vista, y vincula a la ruta asociada con la función en lugar de a un archivo estático expediente.
{% block content %} {% endblock %}
: otro bloque que será reemplazado por contenido dependiendo de la plantilla secundaria (plantillas que heredan de base.html
) que lo anulará.
Ahora que tienes una plantilla base.html
, puedes heredar ese código a index.html
agregando solo el siguiente código en tu index.html
:
1{% extends 'base.html' %} 2 3{% block content %} 4 <h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1> 5{% endblock %}
Has utilizado plantillas HTML y archivos estáticos en Flask de forma limpia. Sin embargo, para simplificar las cosas para su primera aplicación web, conservaremos solo el archivo index.html
.
Veamos cómo debemos codificar un formulario solicitando los atributos de nuestros pasajeros.
Para poder predecir los datos correctamente, los valores correspondientes de cada etiqueta deben coincidir con el valor de cada entrada seleccionada.
En el formulario Titanic que viste al comienzo de esta lección, solo solicitamos las características numéricas para la predicción, pero en el caso de que incluyamos características categóricas que fueron previamente codificadas con etiquetas, necesitamos poner los mismos valores en el formulario HTML. El siguiente ejemplo muestra cómo se debe codificar el formulario en caso de que a nuestra función 'Sex' se le haya asignado 0 para Hombre (Male) y 1 para Mujer (Female):
1<label for="Sex">Gender</label> 2 <select id="relation" name="relation"> 3 <option value="0">Male</option> 4 <option value="1">Female</option> 5 </select>
Puedes encontrar un par de ejemplos de formularios en el siguiente enlace:
https://www.geeksforgeeks.org/html-design-form/
Ejecutemos la aplicación.
1export FLASK_APP=app.py 2run flask
Cuando alguien envía el formulario, la página web debe mostrar el resultado si un pasajero sobreviviría o moriría en el Titanic. Para esto, necesitamos el archivo modelo (model.pkl
) que creamos antes, en la misma carpeta del proyecto. Agregamos el siguiente código al archivo app.py
:
1# Función de predicción 2def ValuePredictor(to_predict_list): 3 to_predict = np.array(to_predict_list).reshape(1,12) 4 loaded_model = pickle.load(open("model.pkl","rb")) 5 result = loaded_model.predict(to_predict) 6 return result[0] 7 8 9@app.route('/result',methods = ['POST']) 10def result(): 11 if request.method == 'POST': 12 to_predict_list = request.form.to_dict() 13 to_predict_list = list(to_predict_list.values()) 14 to_predict_list = list(map(int, to_predict_list)) 15 result = ValuePredictor(to_predict_list) 16 17 if int(result)==1: 18 prediction='Passenger survives' 19 else: 20 prediction='Passenger dies' 21 22 return render_template("result.html",prediction=prediction)
Aquí, después de enviar el formulario, los valores del formulario se almacenan en la variable to_predict_list
en forma de diccionario. Lo convertimos en una lista de los valores del diccionario y lo pasamos como argumento a la función ValuePredictor()
. En esta función, cargamos el archivo model.pkl
y predecimos los nuevos valores y devolvemos el resultado.
Este resultado/predicción (si el pasajero sobrevive o no) se pasa como argumento al motor de plantilla con la página HTML que se mostrará.
Crea el siguiente archivo result.html
y agrégalo a la carpeta templates.
1<!doctype html> 2<html> 3 <body> 4 <h1>{{ prediction }}</h1> 5 </body> 6</html>
Un código alternativo para todo el archivo app.py
podría ser:
1import numpy as np 2from flask import Flask, request, render_template 3import pickle 4 5app = Flask(__name__) 6model = pickle.load(open('model.pkl', 'rb')) 7 8@app.route('/') # http://www.google.com/ 9def home(): 10 return render_template('index.html') 11@app.route('/predict', methods=['POST']) 12def predict(): 13 ''' 14 For rendering results on HTML GUI 15 ''' 16 int_features = [int(x) for x in request.form.values()] 17 final_features = [np.array(int_features)] 18 prediction = model.predict(final_features) 19 20 output = round(prediction[0], 2) 21 22 return render_template('index.html', prediction_text='Would you survive? {} (1=survived, 0=deceased)'.format(output)) 23 24if __name__=="__main__": 25 app.run(port=5000, debug=True)
Vuelve a ejecutar la aplicación y debería predecir el resultado después de enviar el formulario. Hemos creado con éxito la aplicación Web. Ahora es el momento de usar Heroku para implementarlo.
Ya deberías tener una cuenta en Heroku, pero si no la tienes, continúa y crea tu cuenta en 'https://www.heroku.com'.
Asegurémonos de tener también lo siguiente antes de implementar en Heroku:
gunicorn
en tu entorno virtual. Puedes usar pip
para descargarlo.1pip install gunicorn
Hemos instalado muchas bibliotecas y otros archivos importantes como flask, gunicorn, sklearn, etc. Necesitamos decirle a Heroku que nuestro proyecto requiere todas estas bibliotecas para ejecutar la aplicación con éxito. Esto se hace creando un archivo requirements.txt
.
Procfile
es un archivo de texto en el directorio raíz de tu aplicación, para declarar explícitamente qué comando debe ejecutarse para iniciar tu aplicación. Este es un requisito esencial para Heroku. Este archivo le dice a Heroku que queremos usar el proceso web con el comando gunicorn y el nombre de la aplicación.
1web: gunicorn app:app
Tu estructura actual debería ser algo como esto:
.gitignore
para excluir archivos innecesarios que no queremos implementar en Heroku.¡Estamos listos! ¡Envía tu proyecto a Heroku! Si deseas hacerlo directamente en el sitio web de Heroku, puedes hacerlo de la siguiente manera:
Haz clic en 'Create a new app'
En la pestaña 'deploy': vincula la aplicación Heroku a tu cuenta de GitHub y selecciona el repositorio para conectarse.
Desplázate hacia abajo y elige 'manual deploy'. Después de asegurarte de que estás en la rama que deseas implementar (en este caso: main
), haz clic en 'Deploy branch'. Verás que se han instalado todos los paquetes necesarios como en la siguiente imagen:
Si te sientes más cómodo con la línea de comandos, deberás tener instalados git y Heroku CLI, y luego seguir estos pasos:
Puedes hacer clic en el siguiente enlace para instalar Heroku CLI: https://devcenter.heroku.com/articles/heroku-cli
1heroku login
1heroku create
1git init 2git add . 3git commit -m 'initial commit'
1git push heroku master 2heroku open
¡Anímate y prueba tu aplicación web!
Fuente: