Skip to main content
LadeStack LogoLadeStack
AI Development 7 min de lectura 25 de junio de 2024

Pipelines de Machine Learning para Desarrolladores Web: de la Ingesta a la Inferencia en Navegador y Servidor

Guía completa de MLOps para ingenieros web: ingesta de datos, prevención de data leakage, inferencia en navegador con ONNX Runtime Web, microservicios FastAPI y monitorización de drift.

Diagrama arquitectónico de un pipeline de machine learning conectando ingesta de datos, entrenamiento, inferencia en navegador ONNX y microservicio FastAPI

En las aplicaciones web contemporáneas, el Machine Learning (ML) ha dejado de ser una disciplina teórica aislada para convertirse en un elemento fundamental de la experiencia de usuario. Desde recomendaciones personalizadas y comprensión de intención de búsqueda hasta prevención de fraude en tiempo real y procesamiento multimedia en cliente, los ingenieros web deben integrar modelos predictivos directamente en sus pilas tecnológicas de producción.

Sin embargo, para muchos equipos de desarrollo, llevar modelos creados en Jupyter Notebooks por científicos de datos hacia arquitecturas web de alta concurrencia entraña serios riesgos. Las discrepancias de preprocesamiento entre entrenamiento e inferencia (training-serving skew), la fuga de datos (data leakage), la latencia de red y la degradación predictiva a lo largo del tiempo (data drift) son obstáculos frecuentes.

Esta guía examina la construcción de pipelines de machine learning robustos desde la perspectiva del desarrollo web: desde la ingesta y validación de datos hasta los compromisos entre inferencia en cliente y servidor, con implementaciones prácticas en ONNX Runtime Web y FastAPI, además de pautas de observabilidad en producción.


1. Arquitectura Integral de un Pipeline de Machine Learning

Un sistema de ML fiable en producción se estructura en cuatro ciclos de vida desacoplados:

[ ETAPA 1: Recolección y Validación ]
Registros de Actividad / RDBMS / Colas de Streaming
       │
       ▼
Validación de Esquema y Limpieza (Pydantic / Great Expectations)
       │
       ▼
División Temporal Train / Val / Test (Prevención de Fuga de Datos)

─────────────────────────────────────────────────────────────────

[ ETAPA 2: Entrenamiento y Exportación de Modelos ]
Feature Store y Entrenamiento de Pipelines (Scikit-Learn / PyTorch)
       │
       ▼
Estandarización de Formatos (ONNX / TorchScript) y Cuantización (INT8 / FP16)
       │
       ▼
Registro de Modelos (S3 / MLflow) y Control de Versiones

─────────────────────────────────────────────────────────────────

[ ETAPA 3: Despliegue e Inferencia ]
       ┌───────────────────────────────┐
       ▼                               ▼
[ Inferencia en Navegador (Cliente) ] [ Microservicio en Servidor ]
ONNX Runtime Web (WASM / WebGPU)       Servidor de Inferencia FastAPI / Triton
Cero coste de servidor・Privacidad     Modelos complejos・Protección de IP

─────────────────────────────────────────────────────────────────

[ ETAPA 4: MLOps y Monitorización de Drift ]
Seguimiento de Distribución de Features (Test KS / PSI) y Pérdida de Precisión

2. Recolección de Datos y Prevención de Fugas (Data Leakage)

El fallo más destructivo y sutil al diseñar un pipeline de aprendizaje automático es la fuga de datos (Data Leakage).

Causas Frecuentes de Fuga de Datos

  1. Fuga de Parámetros de Escalado: Ejecutar StandardScaler.fit() sobre todo el conjunto de datos antes de la división de entrenamiento y prueba permite que medias y varianzas futuras contaminen el entrenamiento, inflando artificialmente las métricas de validación.
  2. Aleatorización de Series Temporales: Aplicar validación cruzada aleatoria (K-Fold) sobre registros con dependencia cronológica hace que el modelo utilice información del futuro para predecir el pasado.

Pipeline de Preprocesamiento sin Fugas (Python)

# pipeline/preprocess.py
import pandas as pd
import numpy as np
from sklearn.model_selection import TimeSeriesSplit
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression

def build_leak_free_pipeline(df: pd.DataFrame, target_col: str, timestamp_col: str):
    # Ordenación cronológica estricta para garantizar la causalidad
    df = df.sort_values(timestamp_col).reset_index(drop=True)
    X = df.drop(columns=[target_col, timestamp_col])
    y = df[target_col]

    # El 20% más reciente se reserva como conjunto de prueba de producción
    split_index = int(len(df) * 0.8)
    X_train, X_test = X.iloc[:split_index], X.iloc[split_index:]
    y_train, y_test = y.iloc[:split_index], y.iloc[split_index:]

    # Encapsulamos el escalador en el Pipeline para eliminar discrepancias en inferencia
    pipeline = Pipeline([
        ('scaler', StandardScaler()),
        ('classifier', LogisticRegression(C=1.0, solver='lbfgs', max_iter=500))
    ])

    pipeline.fit(X_train, y_train)
    holdout_score = pipeline.score(X_test, y_test)
    print(f"Precisión en conjunto de prueba: {holdout_score:.4f}")

    return pipeline

3. Inferencia en Navegador vs Servidor: Matriz de Decisiones

El entorno de ejecución del cálculo de inferencia define la estructura de costes y la velocidad de respuesta.

Dimensión Inferencia en Navegador (ONNX Runtime Web) Inferencia en Servidor (FastAPI / Triton)
Latencia de Red 0 ms (sin comunicación de red) Sujeta al retardo de red (50–250 ms)
Coste de Servidor Cero (cómputo en el dispositivo cliente) Costes de infraestructura y autoescalado
Modo Offline Total (compatible con Service Workers) Imposible (requiere conexión activa)
Privacidad de Datos Máxima (datos sensibles nunca salen del cliente) Datos enviados al servidor (auditoría requerida)
Protección de Propiedad (IP) Nula (los pesos se descargan en el navegador) Máxima (pesos y modelos ocultos en el servidor)
Tamaño Máximo del Modelo Ligero (< 50 MB recomendado) Ilimitado (modelos de decenas de gigabytes)

4. Implementación de Inferencia en Cliente: ONNX Runtime Web

Para modelos de clasificación ligeros o procesamiento de imágenes, ONNX Runtime Web con aceleración WebAssembly (WASM) y WebGPU ofrece el rendimiento más predecible.

// src/lib/ml/browserInference.ts
import * as ort from 'onnxruntime-web';

ort.env.wasm.numThreads = 2;
ort.env.wasm.simd = true;

export interface PredictionResult {
  probabilities: number[];
  predictedClass: number;
  inferenceDurationMs: number;
}

export class BrowserInferenceService {
  private session: ort.InferenceSession | null = null;

  async loadModel(modelPath: string): Promise<void> {
    this.session = await ort.InferenceSession.create(modelPath, {
      executionProviders: ['wasm'],
      graphOptimizationLevel: 'all'
    });
  }

  async predict(features: number[]): Promise<PredictionResult> {
    if (!this.session) {
      throw new Error("Sesión del modelo no inicializada. Ejecute loadModel() previamente.");
    }

    const start = performance.now();
    const inputTensor = new ort.Tensor('float32', Float32Array.from(features), [1, features.length]);
    const inputName = this.session.inputNames[0];
    const feeds: Record<string, ort.Tensor> = {};
    feeds[inputName] = inputTensor;

    const results = await this.session.run(feeds);
    const outputName = this.session.outputNames[0];
    const outputTensor = results[outputName];
    const outputData = Array.from(outputTensor.data as Float32Array);

    let maxIdx = 0;
    let maxVal = outputData[0];
    for (let i = 1; i < outputData.length; i++) {
      if (outputData[i] > maxVal) {
        maxVal = outputData[i];
        maxIdx = i;
      }
    }

    return {
      probabilities: outputData,
      predictedClass: maxIdx,
      inferenceDurationMs: performance.now() - start
    };
  }
}

5. Microservicio de Inferencia en Servidor con FastAPI

Cuando la confidencialidad de los algoritmos es prioritaria o se emplean modelos pesados, construir un microservicio asíncrono en FastAPI es la arquitectura idónea.

# server/app.py
from fastapi import FastAPI, HTTPException, status
from pydantic import BaseModel, Field
import numpy as np
import onnxruntime as ort
import time

app = FastAPI(title="Servicio de Inferencia ML", version="1.0.0")

class InferenceRequest(BaseModel):
    user_id: str
    features: list[float] = Field(..., min_items=5, max_items=5)

class InferenceResponse(BaseModel):
    user_id: str
    prediction: int
    confidence: float
    latency_ms: float

session = ort.InferenceSession("models/production_classifier.onnx")
input_name = session.get_inputs()[0].name

@app.post("/api/v1/predict", response_model=InferenceResponse)
async def predict_endpoint(payload: InferenceRequest):
    try:
        start_time = time.perf_counter()
        input_array = np.array([payload.features], dtype=np.float32)

        raw_outputs = session.run(None, {input_name: input_array})
        probabilities = raw_outputs[0][0]
        predicted_class = int(np.argmax(probabilities))
        confidence = float(probabilities[predicted_class])
        duration_ms = (time.perf_counter() - start_time) * 1000

        return InferenceResponse(
            user_id=payload.user_id,
            prediction=predicted_class,
            confidence=confidence,
            latency_ms=duration_ms
        )
    except Exception as exc:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Error en el motor de inferencia: {str(exc)}"
        )

6. MLOps y Monitorización de Data Drift en Producción

Con el paso del tiempo, las variaciones en las conductas de los usuarios provocan inevitablemente una caída de rendimiento conocida como deriva de datos (Data Drift).

Métricas Críticas de Monitorización

  1. Deriva de Features de Entrada: Uso del test Kolmogorov-Smirnov (KS) o del Population Stability Index (PSI) para verificar si las peticiones reales difieren estadísticamente del conjunto de entrenamiento.
  2. Caída de Confianza: Descensos notables en la probabilidad media de las predicciones señalan entradas anómalas no contempladas en el entrenamiento.
  3. Despliegues en la Sombra (Shadow Deployment): Ejecución de una nueva versión (v2) en paralelo con tráfico real sin enviar el resultado al usuario, evaluando latencia y estabilidad de forma segura.

7. Conclusión

Para que el Machine Learning aporte un valor duradero en la web, los ingenieros deben estructurar pipelines que garanticen la ausencia de fugas de datos, optimicen la ubicación de la inferencia y monitoricen el comportamiento predictivo de forma continua.

Para profundizar en arquitecturas de inteligencia artificial aplicadas, consulte nuestras guías sobre Creación de Aplicaciones RAG con Bases de Datos Vectoriales y Ajuste Fino (Fine-Tuning) de LLMs para Tareas Especializadas.

More Engineering Articles