
Finalmente terminaste tu modelo de machine learning y ahora la gran pregunta es 🤔 ¿cómo rayos hago que este disponible en internet? En este post te mostrare una solucion util y rapida para ello. Y si no tienes conocimientos altos en programación no te preocupes. Y si eres amante de la programación compartire algunos recursos para profundizar en ello.
Requisitos:
- Una cuenta de heroku. Puedes crearlo desde aqui
- Tener instalado git.
- Tener python 3 o superior.
- Un editor de codigo. Yo usare Visual Studio Code (VCode).
Nuestro Modelo de Machine Learning
Para desplegar la aplicacion debes tener los archivos de tu modelo y si hubiera pesos o transformadores tambien. Ya sea que su modelo este construido con sklearn, h2o u otro; el proceso de despliegue es el mismo. Para este caso usare «joblib» para generar los archivos de un modelo de sklearn. Si tiene su modelo listo entonces vaya hasta la parte Generar Modelo. De lo contrario te presento la construccion de un modelo no perfecto y sencillo de RandomForestClassifier entrenada con la data de titanic.
Nota: El siguiente codigo es para la generacion del modelo. Use jupyter notebook para una mejor visualizacion, aunque tambien puedes ejecutarlo como un archivo py.
# Cargamos las librerias necesarias para nuestro ejemplo
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import accuracy_score
from joblib import dump, load
import pandas as pd
# Cargamos la data de titanic
data = pd.read_csv("titanic.csv")
data.head(5)
# Eliminamos 'Name', 'Ticket', 'PassengerId', 'Embarked' por no ser relevantes debido a los valores que tienen,
# por otro lado 'Cabin' tiene muchos valores ausentes (aprox 77%)
# Podemos ser mas exigentes y tecnicos con la seleccion de variables,
# pero para que el ejemplo sea sencillo tambien eliminaremos "SibSp", "Parch" y "Fare"
data.drop(columns=["Name", "Ticket", "Cabin", "PassengerId", "Embarked", "SibSp", "Parch", "Fare"], inplace=True)
data.head(5)
# Eliminaremos todas las filas con nulos por ser practico.
# En un caso real se debe hacer un analisis exploratorio.
data.dropna(axis=0, inplace=True)
x = data.drop(columns="Survived")
y = data["Survived"]
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=0)
encoder = LabelEncoder()
x_train["Sex"] = encoder.fit_transform(x_train["Sex"])
x_test["Sex"] = encoder.transform(x_test["Sex"])
model = RandomForestClassifier(criterion="gini", max_depth=3, n_estimators=170, random_state=0)
model.fit(x_train, y_train)
pred_train = model.predict(x_train)
accuracy_score(y_train, pred_train)
pred_test = model.predict(x_test)
accuracy_score(y_test, pred_test)
#
Generar Modelo
# Esto generaran el archivo del modelo y otro archivo del encoder
# Si tuvieramos alguna normalizacion o estandarizacion podriamos hacer similar
dump(model, 'modelo_titanic.joblib')
dump(encoder, 'label_encoder.joblib')
model_loaded = load('modelo_titanic.joblib')
model_loaded.predict(x_test)
encoder_loaded = load('label_encoder.joblib')
type(encoder_loaded)
#
Entorno virtual
Ahora crearemos un entorno virtual. Mm… y ¿Qué es eso? Primero un entorno en python es la plataforma donde esta instalado python y sus librerias. Por ejemplo: Cuando hacemos ‘pip install libreria_ejemplo’ estamos instalando ‘libreria_ejemplo’ en el entorno de nuestro sistema operativo. Entonces cuando hagamos ‘import libreria_ejemplo’ traeremos la instancia de la libreria que esta en el entorno de nuestro sistema operativo.
Supongamos ahora que de tantas aplicaciones de python que tengas quizas no todas puedan trabajar con la misma version instalada de una libreria. Por ejemplo: Si la aplicación A necesita la versión 1.0 de un módulo particular y la aplicación B necesita la versión 2.0, entonces los requerimientos entran en conflicto e instalar la versión 1.0 o 2.0 dejará una de las aplicaciones sin funcionar.
La solución a este problema es crear un entorno virtual, un directorio que contiene una instalación de Python de una versión en particular y además de los paquetes adicionales que instalaremos.
Diferentes aplicaciones pueden entonces usar entornos virtuales diferentes. Para resolver el ejemplo de requerimientos en conflicto citado anteriormente, la aplicación A puede tener su propio entorno virtual con la versión 1.0 instalada mientras que la aplicación B tiene otro entorno virtual con la versión 2.0. Si la aplicación B requiere que actualizar la librería a la versión 3.0, ésto no afectará el entorno virtual de la aplicación A.
Antes de continuar copia los archivos del modelo en tu carpeta de trabajo, para este ejemplo copiare los dos archivos generados anteriormente en mi carpeta de trabajo que llamare ‘titanic project’. Ademas añadire otros archivos y carpetas (explicare más adelante)que seran de la aplicacion, el despliegue y otros. La estructura deberia quedar algo asi:
/titanic project |---modelo_titanic.joblib |---label_encoder.joblib |---RunApp.py |---/templates |---index.html |---Procfile |---requirements.txt |---.gitignore
Entendido lo anterior procederemos a hacer uso de una libreria de entorno virtual, de todas las que hay usaremos virtualenv por preferencia personal. Pero puede sentirce libre de investigar sobre las otras 😉.
Abrimos nuestro carpeta de trabajo con un editor de codigo, en mi caso usare VCode. Una vez hecho ello abrimos el terminal que nos ofrece vcode. Si estas usando otro editor de codigo puede abrir el cmd u otro terminal y asegurate de estar posicionado dentro de tu carpeta de trabajo; por ejemplo si tu projecto esta en «D:\trabajo\social_data_consulting\blog\titanic project>» entonces puedes posicionarte en ello ejecutando el siguiente comando en tu terminal:
$ cd "D:\trabajo\social_data_consulting\blog\titanic project>"
A continuación para instalar virtualenv en nuestro sistema operativo ejecutamos
// Solo se instala una vez $ pip install virtualenv
Ahora crearemos nuestro entorno virtual. En mi caso lo llamare ‘mientorno’ usando el siguiente comando
$ virtualenv mientorno
Activamos nuestro entorno virtual ejecutando lo siguiente
// Windows $ mientorno\Scripts\activate // Linux $ source mientorno\bin\activate
Esto hara que aparesca el nombre de nuestor entorno virtual al inicio y entre parentesis. Lo que indicara que se activo nuestro entorno virtual. En mi caso aparecera asi:
(MIENTO~1) D:\trabajo\social_data_consulting\blog\titanic project>
Una vez nuestro entorno virtual este activo podremos instalar todas las librerias a usar. Para el ejemplo instalaremos las siguientes librerias ejecutando lo siguiente:
$ pip install flask sklearn joblib pandas
Flask
Para realizar un aplicacion web nos apoyaremos en el microframework Flask. Y ¿Qué es esto? En pocas palabras es un marco de trabajo ligero para realizar en pocas lineas aplicaciones web con python. Considerememos el siguiente codigo que sera de ejemplo y lo pondremos en «RunApp.py».
from flask import Flask from flask import request from flask import render_template from joblib import load import pandas as pd # Le pasamos el control de la aplicacion a Flask app = Flask(__name__) modelo = load('modelo_titanic.joblib')# Cargamos el modelo encoder = load('label_encoder.joblib')# Cargarmo el label encoder # Cuando carge la aplicacion en "/" mostraremos el index.html que esta en la carpeta templates @app.route('/', methods=["GET"]) def main(): return render_template('index.html') # Haremos la peticion a esta ruta para la prediccion @app.route('/predecir', methods=["POST"]) def predecir(): datos = request.json message = titanicPred(datos["input_clase"], datos["input_sexo"], datos["input_edad"]) return message # la funcion de prediccion def titanicPred(input_clase, input_sexo, input_edad): newEntry = { 'Pclass': [input_clase], 'Sex': [input_sexo], 'Age': [input_edad], } newEntry = pd.DataFrame(newEntry) newEntry["Sex"] = encoder.transform(newEntry["Sex"]) prediccion = modelo.predict(newEntry)[0] return 'La prediccion es '+("SOBREVIVIO" if prediccion == 1 else "MURIO") # Lo que ejecutara con el comando "python RunApp.py" if __name__ == '__main__': app.run(debug=True) # Se inicia la aplicacion en modo debug
<!doctype html> <html> <head> <title>Titanic Demo</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> </head> <body> <section class="container"> <header> <h1 align="center">Prediccion Titanic Survived</h1> </header> <div class="card"> <h5 class="card-header">Demo de un modelo predictivo</h5> <div class="card-body"> <div class="message alert alert-info alert-dismissible fade show" role="alert"> <span>todos los campos</span> <button type="button" class="close" data-dismiss="alert" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <form method="post" action="predecir"> <div class="form-group"> <label for="input_clase">Clase</label> <select class="form-control" id="input_clase" name="input_clase"> <option value="1">Clase 1</option> <option value="2">Clase 2</option> <option value="3">Clase 3</option> </select> </div> <div> <div class="form-check"> <input class="form-check-input" type="radio" name="input_sexo" id="radio1" value="female" checked> <label class="form-check-label" for="radio1">Femenino</label> </div> <div class="form-check"> <input class="form-check-input" type="radio" name="input_sexo" id="radio2" value="male"> <label class="form-check-label" for="exampleRadios2">Masculino</label> </div> </div> <div class="form-group"> <label for="input_edad">Edad</label> <input type="number" min="0" max="74" class="form-control" name="input_edad" id="input_edad" placeholder="Edad"> </div> <button type="submit" class="btn btn-primary">Predecir</button> </form> </div> </div> </section> </body> </html> <script> var form = document.querySelector("form"); form.addEventListener("submit", function(event){ event.preventDefault(); axios.post('/predecir', { "input_clase": form.querySelector("#input_clase").value, "input_sexo": form.querySelector("input[name=input_sexo]").value, "input_edad": form.querySelector("#input_edad").value }).then(function (response) { console.log(response); document.querySelector(".message > span").innerHTML = response.data; }).catch(function (error) { console.log(error); }) }); </script>
$ python RunApp.py
mientorno
Tambien añadimos el archivo «Procfile» que indicara al heroku(más adelante explicare) que ejecute nuestra aplicacion. Note que «Procfile» no tiene ninguna extencion. Este es su contenido:
web: gunicorn RunApp:app
Ya casi terminamos 😆. Ahora urge resguardar todas las librerias con sus versiones que hemos usado en nuestro entorno virtual, para que una vez puesta en heroku(más adelante explicare) se instalen esas mismas. De esta forma nuestra app funcionara con las mismas librerias y versiones con que se desarrollo en nuestra computadora local. Ejecutaremos este comando que generara un archivo con todas las librerias usadas en nuestro entorno virtual.
$ pip freeze > requirements.txt
Heroku
Es una plataforma en la nube que permite desplegar nuestra aplicación de forma facil y rapida.
Heroku es una plataforma en la nube que permite a las empresas construir, entregar, monitorear y escalar aplicaciones; somos la forma más rápida de pasar de la idea a la URL, evitando todos esos dolores de cabeza de infraestructura.
- Crear una aplicacion en heroku dashboard. Si no encuentras la opcion dale click aqui
- Colocarle un nombre a tu aplicacion. Yo le llame sdc-titanic-demo.
- Añadir un pipeline, que es donde heroku guardara la linea base de nuestro codigo.
- Colocar cualquier nombre al pipeline.
- Y finalmente selccionar «create app».
Ya tenemos «creado la aplicacion» en heroku, pero nos falta subir el codigo que hemos hecho…¿hemos? 😆. Y para ello nos ayudamos del instructivo de la aplicacion creada recientemente en heroku al cual llegaras de la siguiente forma: seleccionando tu aplicacion en heroku, luego el pipeline que creaste y finalmente la opcion deploy. Asegurece de estar en su carpeta de trabajo. Si no encontro el instructivo te muestro los comandos que utiliza:
// Nos conectamos a heroku. Nos mostrara unas instrucciones, sigalas. $ heroku login // Inicializamos el repositorio Git en nuestra carpeta de trabajo $ git init // Hacemos el vinculo con la aplicacion creada en heroku. // Remplace sdc-titanic-demo con el nombre de su aplicacion de heroku. $ heroku git:remote -a sdc-titanic-demo // Agregamos todos los archivos al repositorio git $ git add . // Guardamos los cambios con un comentario $ git commit -am "make it better" // Finalmente subimos nuestro codigo a heroku $ git push heroku master