Problemas de optimización · Tema 30

Optimización de parámetros en programas

Aprendé a convertir rendimiento, memoria y calidad en un objetivo medible, encontrar un parámetro óptimo y validar que la solución matemática también funcione en el sistema real.

01 · Una decisión dentro del código

Los parámetros también son variables de optimización

Muchos programas exponen decisiones numéricas: tamaño de lote, cantidad de hilos, nivel de compresión, capacidad de una caché, número de iteraciones o intervalo entre actualizaciones. Elegirlas por costumbre puede desperdiciar recursos o degradar el resultado.

Representaremos con x un parámetro configurable y con J(x) el costo que queremos minimizar. El significado de «costo» depende del problema: puede ser tiempo, memoria, consumo, error o una combinación de varias métricas.

02 · Del sistema al modelo

Un ciclo de optimización reproducible

  1. Elegir el parámetro controlable x.
  2. Definir las métricas observables y sus unidades.
  3. Fijar el dominio factible y las restricciones duras.
  4. Construir o ajustar una función objetivo J(x).
  5. Hallar y clasificar los candidatos matemáticos.
  6. Traducir la solución a valores admitidos por el programa.
  7. Validar con mediciones nuevas y monitorear cambios.

El ciclo puede repetirse cuando cambian los datos, el hardware, la carga o los requisitos del producto.

03 · Qué significa «mejor»

Rendimiento, memoria y calidad

Una optimización útil comienza con métricas precisas. Por ejemplo:

DimensiónMétrica posibleObjetivo
Rendimientolatencia p95 en milisegundosminimizar
Capacidadsolicitudes por segundomaximizar
Memoriamáximo residente en MiBminimizar o acotar
Calidaderror, pérdida o tasa de fallosminimizar
Consumoenergía por operaciónminimizar

«El programa se siente rápido» no es una función objetivo. «Minimizar la latencia p95 con menos de 512 MiB y error menor que 2 %» sí describe una decisión comprobable.

04 · Una sola métrica

Objetivo simple y restricciones duras

Cuando existe una prioridad clara, conviene mantener un objetivo único. Si T(x) es la latencia, podemos plantear:

minimizar T(x), sujeto a M(x) ≤ 512 y E(x) ≤ 0,02

M representa memoria y E error. Las cotas no son preferencias: cualquier valor que las viole queda fuera del dominio factible.

Este enfoque conserva una interpretación directa y evita esconder un incumplimiento grave detrás de una mejora en otra métrica.

05 · Varios objetivos

Construir una función de costo compuesta

Si los compromisos son graduales, podemos convertir todas las métricas a costos y formar una suma ponderada:

J(x) = wtT̃(x) + wmM̃(x) + wqẼ(x)

Los símbolos con tilde indican métricas normalizadas. Los pesos no son «constantes mágicas»: expresan cuánto sacrificio en una dimensión aceptamos para mejorar otra.

  • Una métrica que queremos maximizar puede transformarse en costo, por ejemplo −R(x) o 1/R(x).
  • Todos los pesos deben ser no negativos si cada término representa una penalización.
  • Multiplicar todos los pesos por la misma constante cambia la escala de J, pero no su mínimo.

06 · Comparar magnitudes

Normalizar antes de sumar

No tiene sentido sumar directamente 180 milisegundos, 400 MiB y 0,03 de error. Además, la métrica con los números más grandes dominaría el cálculo por una elección accidental de unidades.

Una normalización sencilla usa un valor de referencia:

T̃(x) = T(x)/Tref   ·   M̃(x) = M(x)/Mref   ·   Ẽ(x) = E(x)/Eref

Así los términos son adimensionales. Otra alternativa es medir la variación relativa respecto de una configuración base. La fórmula elegida y sus referencias deben guardarse junto con el experimento.

07 · Modelo de trabajo

Esfuerzo computacional frente a error

Supongamos que x representa una cantidad de pasadas, muestras o unidades de esfuerzo. Más esfuerzo reduce el error, pero aumenta el consumo de tiempo y memoria. En el intervalo 4 ≤ x ≤ 100 usamos:

Q(x) = 120/x   (penalización por error)
R(x) = 0,075x   (penalización por recursos)
J(x) = Q(x) + R(x) = 120/x + 0,075x

El primer término decrece cada vez más lentamente. El segundo crece linealmente. El mínimo equilibra el beneficio marginal de aumentar el esfuerzo con su costo marginal.

08 · Solución analítica

Derivar, resolver y clasificar

J′(x) = −120/x² + 0,075

La condición estacionaria es:

−120/x² + 0,075 = 0 ⇒ x² = 1600 ⇒ x = 40

Descartamos x=−40 porque el esfuerzo no puede ser negativo. Para x>0:

J″(x) = 240/x³ > 0

La función es estrictamente convexa; por lo tanto, el punto estacionario es el único mínimo. Además, 40 pertenece al intervalo factible.

09 · Leer el resultado

Igualar cambios marginales

En x=40, los dos términos valen:

Q(40) = 3   ·   R(40) = 3   ·   J(40) = 6

Más importante que esa igualdad de niveles es la igualdad de magnitudes marginales:

Q′(40) = −0,075   ·   R′(40) = 0,075

Una pequeña mejora adicional en calidad compensa exactamente el aumento local del costo de recursos. Antes de 40 domina la mejora de calidad; después domina la penalización de recursos.

10 · Restricciones activas

Cuando el óptimo queda fuera del dominio

Para el modelo general J(x)=a/x+kx, con a,k>0, el candidato es:

x* = √(a/k)

Si el programa solo admite L ≤ x ≤ U, la solución continua se recorta al intervalo:

xfactible = min(U, max(L, √(a/k)))

Por ejemplo, con un límite de memoria que impone x≤32, el mínimo factible está en x=32, aunque J′(32)<0. La frontera impide seguir mejorando el objetivo.

11 · Del cálculo a la configuración

Parámetros enteros y valores permitidos

Muchos parámetros no son continuos. Un número de hilos debe ser entero; un tamaño de bloque puede admitir solo potencias de dos; una biblioteca puede ofrecer una lista cerrada de niveles.

Después de obtener x*, se evalúan los valores permitidos cercanos. Si solo se aceptan potencias de dos, alrededor de 40 comparamos:

J(32) = 6,15   ·   J(64) = 6,675

La mejor configuración disponible es x=32. Redondear a ciegas no alcanza cuando el conjunto permitido tiene saltos o la función es asimétrica.

12 · Qué tan estable es la decisión

Análisis de sensibilidad

En x*=√(a/k), aumentar la penalización de recursos k desplaza el óptimo hacia valores menores. Aumentar la importancia de la calidad a lo desplaza hacia valores mayores.

kx*Lectura
0,0363,25los recursos son relativamente baratos
0,07540modelo base
0,1231,62los recursos pesan más

Si varios valores tienen costos casi iguales, conviene elegir el más simple, robusto o económico de operar. Una cifra decimal extra en el óptimo no implica una mejora relevante.

13 · Datos reales

Benchmarking sin engañarse

Las funciones de un sistema real suelen estimarse con mediciones. Para que el modelo sea confiable:

  • usar una carga representativa y fijar versiones, hardware y configuración;
  • hacer calentamiento antes de medir código con JIT, cachés o pools;
  • repetir ejecuciones y registrar dispersión, no solo el promedio;
  • separar datos de ajuste y validación;
  • aleatorizar el orden de configuraciones para reducir sesgos temporales;
  • medir percentiles de latencia cuando importan los casos lentos.

Una curva suave es una aproximación de observaciones ruidosas. El mínimo estimado debe validarse contra configuraciones vecinas mediante nuevas ejecuciones.

14 · Exploración interactiva

Laboratorio: calidad frente a recursos

Modificá el esfuerzo y la penalización por recursos. El punto amarillo indica el mínimo continuo para el valor actual de k.

EXPERIMENTO 30

Ajuste de un parámetro

J(x) = 120/x + 0,075x

Los resultados del modelo aparecen debajo.
CalidadQ = 3
RecursosR = 3
Costo totalJ = 6
Óptimo continuox* = 40

La configuración seleccionada coincide con el mínimo continuo.

El gráfico compara la penalización por error, la penalización por recursos y su suma en el intervalo de 4 a 100.

Preguntas para explorar

  1. Mové x a ambos lados de 40. ¿Qué término domina el costo?
  2. Aumentá k. ¿Por qué el mínimo se desplaza hacia la izquierda?
  3. Compará el costo del óptimo con los enteros vecinos.
  4. Si solo se admitieran 8, 16, 32, 64 y 100, ¿qué valor elegirías?

15 · Implementación

Calcular el óptimo y respetar el dominio

function costo(x, calidad = 120, recursos = 0.075) {
  if (x <= 0) return Infinity;
  return calidad / x + recursos * x;
}

function optimoContinuo({ calidad = 120, recursos = 0.075, min = 4, max = 100 } = {}) {
  if (calidad <= 0 || recursos <= 0 || min <= 0 || min > max) {
    throw new RangeError("Parámetros inválidos");
  }

  const candidato = Math.sqrt(calidad / recursos);
  const x = Math.min(max, Math.max(min, candidato));
  return { x, costo: costo(x, calidad, recursos), candidato };
}

console.log(optimoContinuo());
// { x: 40, costo: 6, candidato: 40 }

Elegir entre configuraciones permitidas

function costo(x, calidad = 120, recursos = 0.075) {
  if (x <= 0) return Infinity;
  return calidad / x + recursos * x;
}

function mejorPermitido(valores, funcionCosto) {
  if (valores.length === 0) throw new Error("No hay configuraciones");

  return valores.reduce((mejor, x) => {
    const actual = { x, costo: funcionCosto(x) };
    return actual.costo < mejor.costo ? actual : mejor;
  }, { x: null, costo: Infinity });
}

const permitidos = [8, 16, 32, 64, 100];
console.log(mejorPermitido(permitidos, x => costo(x)));
// { x: 32, costo: 6.15 }

16 · Lo que el modelo no garantiza

No todas las curvas son suaves o unimodales

En software aparecen discontinuidades por recolección de basura, paginación, vectorización, límites de caché o cambios de algoritmo. También puede haber varios mínimos locales y mesetas.

Si las mediciones contradicen la forma supuesta, no debemos forzar el cálculo diferencial. Una búsqueda en grilla, un modelo por tramos o un método sin derivadas puede ser más apropiado. El siguiente tema desarrollará la búsqueda exhaustiva.

Además, optimizar una carga fija puede producir sobreajuste: la configuración ganadora del benchmark quizá no generalice a producción.

17 · Comprensión

Confusiones frecuentes

«Solo hay que minimizar el tiempo promedio»

El promedio puede ocultar latencias extremas, errores o un consumo de memoria inaceptable. La métrica debe reflejar el requisito real.

«Puedo sumar métricas aunque tengan unidades distintas»

Primero deben normalizarse o convertirse mediante costos comparables; de lo contrario, la escala elegida domina el resultado.

«Los pesos son objetivos»

Los pesos codifican preferencias. Conviene documentarlos y estudiar cómo cambia la solución al modificarlos.

«J′(x)=0 siempre entrega la configuración final»

Genera un candidato continuo. Hay que comprobar clasificación, fronteras, restricciones y valores discretos admitidos.

«Una medición por configuración es suficiente»

El ruido del sistema puede invertir diferencias pequeñas. Se necesitan repeticiones y una validación independiente.

«El óptimo durará para siempre»

La carga, el hardware y el programa cambian. El ajuste debe monitorearse y repetirse cuando dejan de cumplirse sus supuestos.

18 · Práctica guiada

Ejercicios de aplicación

Ejercicio 1: localizar el mínimo

Sea J(x)=200/x+0,08x, con 5≤x≤80. Hallá el candidato continuo.

Ver solución

J′(x)=−200/x²+0,08. Entonces x²=2500 y x=50. Como J″(x)=400/x³>0, es el mínimo.

Ejercicio 2: frontera activa

En el ejercicio anterior, una restricción de memoria obliga a usar x≤32. ¿Cuál es el mínimo factible?

Ver respuesta

En [5,32] la función todavía decrece, de modo que el mínimo factible es la frontera x=32.

Ejercicio 3: conjunto discreto

Para el modelo principal, compará x=32 y x=48.

Ver solución

J(32)=120/32+0,075·32=6,15. J(48)=120/48+0,075·48=6,1. Entre ambos, conviene 48, aunque ninguno coincide con el mínimo continuo.

Ejercicio 4: transformar un objetivo

Si R(x)>0 es el rendimiento que queremos maximizar, mencioná dos formas de expresarlo como costo.

Ver respuesta

Podemos minimizar −R(x) o 1/R(x). No son equivalentes al combinarlas con otros términos, por lo que debe elegirse la transformación según la interpretación deseada.

Ejercicio 5: diseñar un experimento

¿Por qué conviene alternar aleatoriamente el orden de las configuraciones durante un benchmark?

Ver respuesta

Porque temperatura, carga de fondo, cachés u otras condiciones pueden cambiar con el tiempo. Aleatorizar evita asociar sistemáticamente ese cambio con valores crecientes o decrecientes del parámetro.

19 · Síntesis

Ideas para recordar

  • Un parámetro de programa se convierte en una variable de decisión.
  • Las métricas deben ser observables, tener unidades y representar el requisito real.
  • Las restricciones duras delimitan el dominio factible.
  • Las métricas de una suma ponderada deben normalizarse.
  • Los pesos expresan preferencias y requieren análisis de sensibilidad.
  • La solución continua debe traducirse al conjunto de configuraciones admitidas.
  • Las mediciones necesitan repeticiones, control del entorno y validación.
  • Si la curva real no es suave, corresponde usar otro método de búsqueda.

En el próximo tema construiremos una búsqueda exhaustiva sobre una grilla, útil cuando no conocemos la derivada o solo podemos evaluar el programa.