El objetivo de la tarea es habilitar la sección A jugar para que tengamos un panel como el siguiente:
en el cual podamos ejecutar una operación matemática sencilla y evaluar su resultado.
Tenemos entonces tres tipos de input en nuestro canvas:
- Exponentes: 3 posibles referentes a los cuadrados morados. Deben ser números del 0 al 9.
- Operadores: 2 posibles referentes a los cuadrados azules. Explicados en la siguiente sección.
- Números: 3 posibles referentes a los cuadrados rojos. Deben ser números del 0 al 9.
El dataset debe ser creado por ustedes! La cantidad de imágenes, estilo, resolución y cualquier elemento que consideren relevante debe ser decidido por ustedes: sean creativos. En el notebook referente al modelo de operadores, es necesaria una sección que explique toda la toma decisiones.
Solo vamos a usar las 4 operaciones fundamentales: suma, resta, multiplicación y división.
En el caso de suma y resta las únicas opciones posibles son: + (ASCII Code 43) y - (ASCII Code 45), respectivamente.
En el caso de multiplicación y división tendremos 2 opciones como sigue:
Una x (ASCII Code 215) o un asterisco * (ASCII Code 42)
Un slash / (ASCII code 47) o el operando convencional (ASCII code 247)
Ya disponible en el código
from keras.datasets import mnist
from functools import lru_cache
@lru_cache(maxsize=1)
def get_mnist_data():
return mnist.load_data()Usaremos el dataset mnist con la interfaz de Keras para facilitar consistencia en todos los proyectos.
- En la sección
notebooksdeben crear uno o dos archivos.ipynbdonde expliquen claramente todo el pipeline que usaron para crear los modelos, explicar el proceso de preprocesamiento, creación de datos (de ser necesario) y cualquier elemento que consideren relevante. - Los modelos asociados a la solución principal deben haber sido vistos en clase.
- Los modelos extras que quisieran agregar para comparar rendimiento pueden no haber sido vistos en clases (redes neuronales convolucionales usando PyTorch por ejemplo)
Una vez que hayas entrenado tu modelo en el notebook, guárdalo con joblib:
import joblib
# modelo = ... (tu modelo ya entrenado)
joblib.dump(modelo, "mi_modelo_digitos.joblib")Luego sube el archivo .joblib en la página Cargar Modelos de la app.
Edita math_recognizer/utils/image_processing.py para que los pasos coincidan exactamente con lo que hiciste en tu notebook. Por ejemplo, si entrenaste sin ecualización y sin inversión:
def prepare_digit_image(image):
gray = _to_grayscale(image)
gray = _ensure_light_bg(gray)
resized = cv2.resize(gray, (28, 28), interpolation=cv2.INTER_AREA)
# sin equalizeHist, sin bitwise_not
return resizedSi entrenaste con umbral binario:
def prepare_digit_image(image):
gray = _to_grayscale(image)
gray = _ensure_light_bg(gray)
resized = cv2.resize(gray, (28, 28), interpolation=cv2.INTER_AREA)
equalized = cv2.equalizeHist(resized)
_, binary = cv2.threshold(equalized, 127, 255, cv2.THRESH_BINARY)
inverted = cv2.bitwise_not(binary)
return inverted| Formato | Extensión | Librería |
|---|---|---|
| Joblib | .joblib |
joblib.dump(modelo, "archivo.joblib") |
| Pickle | .pkl, .pickle |
joblib.dump(modelo, "archivo.pkl") |
| Keras | .h5, .keras |
modelo.save("archivo.h5") |
Cualquier clasificador de scikit-learn funciona sin modificar el código de la app:
KNeighborsClassifier— soportapredict_proba()automáticamenteSVC/NuSVC— la app usadecision_function()como fallback si no tienepredict_proba()LinearSVC— igual que SVC, usadecision_function()RandomForestClassifier,DecisionTreeClassifier,GaussianNB,MLPClassifier, etc.
El código está hecho en Reflex un framework para desarrollar aplicaciones web completas en Python.
La Documentación de Reflex es bastante sencilla de entender y la mayoría de funcionalidades necesarias ya están implementadas.
pip install -r requirements.txtinstala las dependenciasreflex initinicializa el proyectoreflex runejecuta la aplicación enhttp://localhost:3000
docker compose buildcrea el contenedordocker compose uplo ejecuta en modo desarrolladordocker compose up -dlo ejecuta modo daemon
- Asumimos que la aplicación siempre será usada por un agente honesto. No se debe validar para datos que no sean los referentes al modelo (aunque es un problema interesante de resolver)
- Somos consistentes en la entrada de cada canvas así como en el orden de las operaciones: de izquierda a derecha y con prioridad de operadores: ^, ( *, /), (+, -).
La aplicación tiene las siguientes páginas:
- Inicio (
/): Página principal con instrucciones - A Jugar (
/jugar): Panel con 8 canvas (3 números, 3 exponentes, 2 operadores) para evaluar expresiones - MNIST (
/canvas-demo): Explorador del dataset MNIST - Cargar Modelos (
/cargar-modelos): Carga de modelos ML (.joblib, .pickle)
math_recognizer/ # Paquete principal de la app Reflex
state/ # Clases de estado (canvas, game, model, mnist)
components/ # Componentes reutilizables (canvas, navbar)
pages/ # Páginas de la aplicación
utils/ # Utilidades (procesamiento de imagen)
assets/ # Recursos estáticos (imágenes, JS)
models/ # Modelos ML (input/output)
backup/ # Archivos Streamlit originales (referencia)





