No soy profesional, pero tengo entendido que hacer el llamado a la predicción directamente desde Flask es mala práctica, porque consume recursos de forma innecesariamente.
por ejemplo cada vez que se ejecuta la línea sc = smartcities() estás cargando un modelo nuevo el costo de esa sola línea en producción es muy alto, teniendo en cuenta que entre más existoso sea tu producto (más llamadas al servicio) mayor es el costo computacional, esto lo puedes resolver sacando esta línea del método y convertirlo en atributo de la clase, por otro lado llamar al método predict() del modelo no es eficiente en producción, TensorFlow recomienta usar TensorFlow Serving (Docker) o incluso en el mismo GCP puedes gestionar tus modelos sin siquiera manejar Docker, lo que es mucho más eficiente y escalable.
Hola Daniel, excelente aporte claro que si, aqui pudiesemos desplegar una arquitectura completa para lograr que este sistema sea optimo y a su vez que nos permita escalar de manera dinamica, si quizas tienes en mente una arquitectura para compartir a los compañeros de la clase dejala por acá, todos los aportes contribuyen al curso.
Muchas gracias!
Harías un gran aporte a lo comunidad si expresas en código tu comentario, yo también veo que se puede mejorar... pero me confundo un poco al plantear la solución.
¿Por qué es muy importante poner el nombre de la clase en minúsculas?, ¿El estándar no dice que debe empezar con mayúscula?
El postprocesamiento de modelos en Machine Learning implica tomar las predicciones del modelo y transformarlas o interpretarlas de una manera que sea útil para los usuarios o los sistemas que consumen esos resultados. Este proceso varía según el tipo de modelo, los datos y los requisitos de la aplicación. A continuación, se describen algunas técnicas comunes de postprocesamiento de modelos, así como una guía de implementación para algunos de estos métodos.
### 1. **Escalado y Normalización de Resultados**
Si el modelo devuelve valores en una escala que no es adecuada para la aplicación final, es común reescalar estos resultados. Por ejemplo, algunos modelos de redes neuronales pueden dar como salida valores no acotados, por lo que se utiliza una función de activación final para comprimir los valores en un rango específico (ej., [0, 1] o [-1, 1]).
import numpy as np
\# Supón que `predicciones` es un array de predicciones que necesitas reescalar a \[0,1]defrescale(predictions):  return (predictions - predictions.min()) / (predictions.max() - predictions.min())   
\# Aplicar reescalado
predictions\_rescaled = rescale(predictions)
### 2. **Filtrado de Ruido en Resultados**
Para evitar resultados erráticos, especialmente en aplicaciones de visión por computadora o series temporales, se pueden aplicar técnicas de suavizado como filtros de media o mediana, filtros gausianos, o algoritmos de suavizado exponencial.
\# Ejemplo de suavizado usando un filtro de media simple
def moving\_average(predictions, window\_size=3):  return np.convolve(predictions, np.ones(window\_size)/window\_size, mode='valid')   
\# Aplicar suavizado
smoothed\_predictions = moving\_average(predictions)
### 3. **Umbralización para Detección Binaria**
En algunos modelos, como los de clasificación binaria, la salida del modelo es una probabilidad. Para clasificar estos resultados, es común establecer un umbral que determina si el resultado se considera positivo o negativo.
En clasificación multiclase, los modelos suelen devolver probabilidades para cada clase. Si necesitas obtener la clase final, toma el índice de la probabilidad más alta como la predicción.
\# Supón que `predicciones` es una matriz donde cada fila contiene las probabilidades para cada clase
def decode\_classes(predictions):  return np.argmax(predictions, axis=1)
\# Obtener clases predichas
predicted\_classes = decode\_classes(predictions)
### 5. **Agrupación y Agravación de Resultados**
Para aplicaciones donde se necesita tomar decisiones basadas en secuencias de predicciones (por ejemplo, en reconocimiento de voz o análisis de series temporales), se pueden aplicar técnicas de agrupación para unificar varias predicciones en un resultado final, como el método de votación mayoritaria.
from scipy.stats import mode
def aggregate\_predictions(predictions, method='majority'):  if method == 'majority':  return mode(predictions)\[0]\[0]  \# Agrega más métodos según sea necesario
\# Ejemplo de uso
aggregated\_result = aggregate\_predictions(predicted\_classes)
### 6. **Explicabilidad y Generación de Reportes**
En algunos casos, es importante que los resultados sean interpretables para los usuarios. Herramientas como **SHAP** o **LIME** pueden ayudar a entender cómo el modelo llegó a sus predicciones.
import shap
\# Supón que tienes un modelo de Scikit-Learn y datos de entrada para el análisis
explainer = shap.TreeExplainer(model)shap\_values = explainer.shap\_values(X\_test)
\# Visualización con SHAP
shap.summary\_plot(shap\_values, X\_test, plot\_type="bar")
### 7. **Conversión a Formatos Requeridos (JSON, CSV, ProtoBuf)**
Para que los resultados sean consumidos por otras aplicaciones o servicios, puedes convertir las predicciones a un formato específico. JSON es común para servicios web, mientras que CSV puede ser útil para reportes.
import json
import pandas as pd
\# Convertir predicciones a JSON
predictions\_json = json.dumps(predictions.tolist())
\# Convertir predicciones a CSV
pd.DataFrame(predictions).to\_csv("predictions.csv", index=False)
### 8. **Redondeo y Acondicionamiento de Resultados**
Si los valores predichos representan cantidades que requieren redondeo (como precios, cantidad de unidades, etc.), puedes redondear los resultados según sea necesario.
\# Redondeo a dos decimales para valores monetarios
predictions\_rounded = np.round(predictions,2)
### 9. **Postprocesamiento de Detección de Objetos**
Para detección de objetos (usualmente en visión por computadora), el postprocesamiento puede incluir la eliminación de detecciones duplicadas usando **Non-Maximum Suppression (NMS)**.
import cv2
\# Suponiendo que tienes las predicciones de bounding boxes y sus probabilidades
def non\_maximum\_suppression(boxes, scores, threshold=0.5):  indices = cv2.dnn.NMSBoxes(boxes, scores, score\_threshold=threshold, nms\_threshold=0.4)  return \[boxes\[i] for i in indices]
\# Aplicar NMS
final\_boxes = non\_maximum\_suppression(boxes, scores)
### 10. **Automatización del Postprocesamiento en Google Cloud**
Para sistemas en producción, puedes configurar una función de postprocesamiento en **Cloud Functions** o **Vertex AI Pipelines** en Google Cloud Platform.
#### Ejemplo usando Cloud Functions:
from google.cloud import storage
import json
defpostprocess(event, context):  client = storage.Client()  bucket = client.get\_bucket(event\['bucket'])  blob = bucket.blob(event\['name'])     \# Cargar las predicciones desde el archivo  predictions = json.loads(blob.download\_as\_string())     \# Ejemplo de umbralización  thresholded\_predictions = apply\_threshold(predictions)     \# Guardar el resultado postprocesado  result\_blob = bucket.blob("processed/" + event\['name'])  result\_blob.upload\_from\_string(json.dumps(thresholded\_predictions))
Para activar esta función, configúrala para que se ejecute automáticamente cada vez que se suban nuevas predicciones al bucket de GCS.
### Resumen de Postprocesamiento
1. **Escalado y Normalización**: Reescalar valores según el rango deseado.
2. **Filtrado de Ruido**: Suavizar predicciones para evitar cambios abruptos.
3. **Umbralización**: Convertir probabilidades en etiquetas binarias.
4. **Decodificación de Clases**: Obtener las clases predichas en clasificación multiclase.
5. **Agrupación**: Combinar múltiples predicciones en una sola salida.
6. **Explicabilidad**: Utilizar herramientas como SHAP para entender las predicciones.
7. **Conversión de Formatos**: Convertir resultados a JSON, CSV u otros formatos requeridos.
8. **Redondeo y Acondicionamiento**: Ajustar valores numéricos finales.
9. **Non-Maximum Suppression (NMS)**: Filtrar detecciones en visión por computadora.
10. **Automatización**: Configurar postprocesamiento automático en Google Cloud.
Este enfoque asegura que tus resultados sean precisos, limpios y fácilmente interpretables para la aplicación final.
Aqui se puede ver la importancia de utilizar bien desde un principio la indentación del código. El vídeo quedó extremadamente confuso de forma innecesaria por reutilizar ese fragmento d código mal indentado. Por algo existen las “buenas prácticas”.
Ese tipo de detalles pueden ser la diferencia entre que alguien incursionando en estos temas pueda avanzar o abandone definitivamente. Podría ser mucho mas didáctico y fluido el aprendizaje cuidando esos pequeños detalles.
Revisen la identacion. lo que dice el profe es tal cual