Aplicación Web con DL
Creación de una aplicación web que use un modelo entrenado con Deep Learning a partir del curso de Fastai
Creación de una aplicación web que use un modelo entrenado con Deep Learning a partir del curso de Fastai
Motivación
En la lección 2 se ofrecen diferentes opciones para poder usar el modelo entrenando en el curso a través de la web. Recomiendan hacerlo a través de Voila y Binder por ser una forma sencilla de publicar Jupyter notebooks.
Yo, en cambio, he querido ir más allá y crear una aplicación web en la cual se realice la predicción del modelo entrenado en el lado del servidor. Esta aproximación tiene la ventaja de poder implementarse de forma fácil también en apps de dispositivos móviles.
De esta forma, se podrá subir la imagen desde la web al servidor, devolviendo el resultado obtenido.
Preparación del entorno
Crea un entorno virtual donde trabajar:
En el terminal:
- python3 -m venv env1
- source env1/bin/activate
Si se quiere salir del entorno:
- deactivate
</p>
Instala Flask: framework que permite crear aplicaciones web rápidamente
- pip3 install flask
- python -m flask --version
Crea directorio donde alojar la web y dos subcarpetas que usará la app
- mkdir web
- cd web
- mkdir templates
- mkdir static
Nota: no cambiar el nombre de templates y static ya que los usará Flask
</div> </div> </div>Archivos de la aplicación
Crea un archivo de python con tu editor de textos (yo uso VS Code) en la carpeta “web”.
Combinaremos el código de nuestro modelo de Deep Learning usado para el curso y escrito en un Jupyter Notebook y el código específico de Flask que generará la web.
import fastbook
from fastbook import *
from fastai.vision import *
from flask import Flask, render_template, request, redirect, url_for, abort, send_from_directory
import os
from werkzeug.utils import secure_filename
import imghdr
fastbook.setup_book()
# Se importa nuestro modelo preentrenado “export.pkl”
path=Path()
path.ls(file_exts='.pkl')
learn_inf=load_learner(path/'export.pkl')
# valores para uso de Flask
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 2 * 1024 * 1024
app.config['UPLOAD_EXTENSIONS'] = ['.jpg', '.png', '.gif']
app.config['UPLOAD_PATH'] = 'static'
# función que valida la extensión del archivo
def validate_image(stream):
header = stream.read(512)
stream.seek(0)
format = imghdr.what(None, header)
if not format:
return None
return '.' + (format if format != 'jpeg' else 'jpg')
# función que valida el tamaño del archivo
@app.errorhandler(413)
def too_large(e):
return "File is too large", 413
# función de genera la página pricipal
@app.route('/')
def index():
for f in os.listdir(app.config['UPLOAD_PATH']):
os.remove(os.path.join(app.config['UPLOAD_PATH'], f))
return render_template('inicio.html')
# función generada tras pulsar boton de Clasificación
@app.route('/', methods=['POST'])
def upload_files():
files = os.listdir(app.config['UPLOAD_PATH'])
uploaded_file = request.files['file']
filename = secure_filename(uploaded_file.filename)
if filename != '':
file_ext = os.path.splitext(filename)[1]
if file_ext not in app.config['UPLOAD_EXTENSIONS'] or \
file_ext != validate_image(uploaded_file.stream):
return "Invalid image", 400
filenamefull =os.path.join(app.config['UPLOAD_PATH'], filename)
uploaded_file.save(filenamefull) #guardar la imagen, se mostrará en el resultado
img = PILImage.create(os.path.join(filenamefull))
pred,pred_inx,prob=learn_inf.predict(img) # uso del modelo para hacer la predicción
prediccion=f'Prediccion: {pred}; probabilidad: {prob[pred_inx]:.04f}'
return render_template('resultado.html',prediccion=prediccion, files=files,imagen=filenamefull)
Dentro de las carpetas “templates” creamos dos archivos html “inicio.html” y “resultado.html”
inicio.html
<!doctype html>
<!--Aplicacion web basica: se elige una imagen, se envia al servidor para pasarla por el modelo entrenado-->
<html>
<head>
<title>Clasificador de lunares</title>
</head>
<body>
<h1>Clasificador de lunares</h1>
<form method="POST" action="" enctype="multipart/form-data">
<p><input type="file" name="file"></p>
<p><input type="submit" value="Clasificar"></p>
</form>
</body>
</html>
resultado.html
<!doctype html>
<!--Aplicacion web basica: se muestra la imagen elegida y el resultado de la prediccion-->
<html>
<head>
<title>Clasificador de lunares</title>
</head>
<body>
<h1>Clasificador de lunares</h1>
<img src="{{imagen}}" style="width: 128px">
<p>{{prediccion}}</p>
<br>
<button onclick="goBack()">Volver</button>
<script>
function goBack() {
window.history.back();
}
</script>
</body>
</html>
Publicación de la aplicación
Iniciar el servidor web con Flask en modo local:
- export FLASK_APP=app
- flask run
Abrir navegador y colocar en la barra de direcciones:
Averiguar la dirección ip en mi red:
- ip a
Ejecutar la aplicación de forma visible dentro de mi red:
- flask run --host=0.0.0.0
Ahora podrás acceder desde cualquier dispositivo que esté conectado a tu red (a tu WIFI, por ejemplo)
Ejecutar flask de forma visible fuera de mi red:
Para ello necesitaremos un servidor con acceso a la red que ejecute nuestra aplicación. Podemos montarlo nosotros o usar los servicios de otras empresas como, por ejemplo: