Programación Diferenciable: Métodos Forward¶
Fecha: 27/05/2026
Programación diferenciable¶
Se tiene una función de costo
donde representa los parámetros de un modelo de muchas dimensiones.
Optimización de Parámetros¶
Para resolver el problema de minimización de la función de costo:
se requiere, por ejemplo, realizar actualizaciones iterativas del parámetro mediante el algoritmo de descenso de gradiente. La regla de actualización en el paso se define como:
donde representa la tasa de aprendizaje (learning rate) en la iteración . Este esquema de optimización basado en gradientes es fundamental en el entrenamiento de modelos como Redes Neuronales Informadas por la Física (PINNs) y Ecuaciones Diferenciales Universales (UDEs).
En este marco, desde una perspectiva frecuentista, el proceso busca obtener un estimador puntual óptimo . Sin embargo, la optimización y el cálculo de estos gradientes son herramientas necesarias en ambos paradigmas: Frecuentista: Para converger directamente al óptimo global o local . Bayesiano: Aunque el objetivo principal es obtener la distribución de probabilidad a posteriori, la optimización basada en gradientes sigue siendo indispensable. Hay varios métodos que permiten calcular , a nosotros nos interesan los métodos de programación diferenciable para ecuaciones diferenciales.
Métodos de PD para ecs. diferenciables¶
Para UDEs y para NODEs se puede definir la función de costo asociada utilizando la norma al cuadrado:
donde representa la solución de una ecuación diferencial evaluada en el instante .
Dado que esta función de costo tiene dentro una ecuación diferencial, su evaluación no es analítica y requiere el uso de un solver numérico. A nivel de implementación, no importa estrictamente cómo se evalúa en su totalidad, ya que la computadora resuelve el problema descomponiéndolo en una secuencia de operaciones atómicas e iterativas.
Para calcular los gradientes y optimizar este sistema, los enfoques se pueden dividir según dos ejes principales, generando cuatro categorías conceptuales:
1. Eje del momento de discretización: Continuo vs. Discreto¶
Método Discreto (Discretizar y luego Optimizar): El algoritmo primero discretiza la función de costo y las ecuaciones diferenciales involucradas, y luego calcula los gradientes sobre ese sistema ya discretizado.
Método Continuo (Optimizar y luego Discretizar): Primero se calculan las ecuaciones diferenciales exactas que definen las sensibilidades o gradientes en el dominio continuo (diferenciación analítica) y, en un segundo paso, estas nuevas ecuaciones se resuelven numéricamente (se discretizan).
2. Eje de propagación de derivadas: Forward vs. Reverse¶
Modo Forward (Hacia adelante): Propaga las derivadas desde los parámetros de entrada hacia la salida de la función. El problema de este enfoque es que escala mal respecto a la cantidad de parámetros (). Como nuestra función tiene entradas (los parámetros ) y 1 sola salida (el valor de ), el modo Forward se ve obligado a propagar y calcular derivadas distintas en todo el grafo computacional, lo cual es ineficiente si .
Modo Reverse (Hacia atrás / Adjunto): Propaga las derivadas desde la salida de la función (el error o pérdida) hacia las entradas. Al tener 1 sola salida y entradas, computacionalmente es mucho más económico propagar el gradiente “hacia atrás” en una sola pasada. Por este motivo, el modo Reverse (base del algoritmo de Backpropagation) es el estándar utilizado para entrenar redes neuronales, y representa el punto de partida óptimo para trabajar con arquitecturas de gran escala.
Diferencias finitas¶
Diferenciacion compleja¶
Proponemos una función de costo simplificada de un solo parámetro:
Si la función es localmente analítica (una condición que no siempre se puede garantizar teóricamente, pero que en la práctica general se cumple para la mayoría de los modelos), es posible realizar una extensión analítica de hacia el plano complejo. De esta forma, el dominio de la función pasa a aceptar parámetros complejos:
A nivel operativo, si partimos de una variable real y la extendemos a una variable compleja (con ), las transformaciones de las funciones elementales se comportan de la siguiente manera:
Funciones exponenciales:
Funciones trigonométricas:
Funciones polinómicas:
Nota computacional: Extender las funciones al plano complejo es la base conceptual del método de diferenciación numérica por Paso Complejo (Complex-Step Derivative). Esta técnica permite calcular gradientes perturbando el sistema en el eje imaginario, lo que evita por completo los errores por cancelación catastrófica (resta de números muy parecidos) que sufren los métodos discretos tradicionales como las diferencias finitas.
Definiendo a nuestro parámetro en el dominio complejo como (donde cuando ), podemos expresar nuestra función descompuesta en su parte real e imaginaria:
Si es localmente analítica (diferenciable en el sentido complejo) alrededor de , podemos aplicar:
Teorema de Cauchy-Riemann¶
Hipótesis: Sea una función de variable compleja que es analítica en un entorno del punto .
Resultado: Las derivadas parciales de primer orden de y existen, son continuas y satisfacen las ecuaciones:
De este modo, sabemos que la derivada de la función respecto al parámetro real equivale a la derivada parcial respecto a . Y por las ecuaciones de Cauchy-Riemann, esto es igual a la derivada de la parte imaginaria respecto a :
Por lo tanto
Dado que partimos de un parámetro estrictamente real , estamos evaluando en . Además, como devuelve una función de costo real, su parte imaginaria inicial es cero (). Reemplazando esto en la expresión:
En conclusión, si admite extensión compleja, podemos calcular su derivada de la siguiente manera:
Pros:
Precisión extrema: A diferencia de las diferencias finitas convencionales, no sufre errores de cancelación catastrófica al restar números muy cercanos, porque no hay resta en el numerador. Permite usar valores de tan chicos como la precisión de la máquina lo permita.
Fácil implementación: La mayoría de los lenguajes de programación modernos tienen soporte nativo para aritmética de números complejos.
Contras:
Restricción de dominio: Depende de que podamos evaluar y extender toda la función de costo a variables complejas. No todas las funciones admiten esto (por ejemplo, funciones que usan valores absolutos o condiciones lógicas muy rígidas).
Sobrecarga computacional: Matemáticamente, este enfoque termina siendo equivalente a la Diferenciación Automática (Forward AutoDiff), pero requiere operar algebraicamente con números complejos en cada paso, lo que consume más memoria y tiempo de cómputo.
Error residual: Aunque elimina el error de cancelación, sigue siendo una aproximación numérica sujeta al error de truncamiento del orden de .
Tanto el método de diferencias finitas como el de diferenciación compleja presentan un error de aproximación (de orden ). Por el contrario, Forward AD nos permite obtener la derivada numérica exacta, sin error de aproximación.
3. Diferenciación Automática Forward (Forward AD)¶
Concepto: Grafo Computacional¶
Para entender AD, primero debemos modelar nuestra función como un Grafo Dirigido Acíclico (DAG). En este esquema, definimos un conjunto de variables de entrada, variables intermedias y una variable de salida. Las variables de entrada se denotan como . Estas variables corresponden a los parámetros del modelo, por lo que forman el vector de entrada . Luego, tenemos las variables intermedias, que se denotan desde hasta . Finalmente, la variable representa el output de nuestra función. En este grafo computacional, una variable depende de siempre que . Las aristas del DAG representan las operaciones elementales que conectan a las variables de una capa con la siguiente.
Ejemplo:
Podemos representar esta función mediante un DAG de tres capas. En la primera capa, definimos la variable de entrada . La arista hacia la segunda capa aplica la operación , generando la variable intermedia . La arista hacia la tercera capa aplica la operación , generando el output . De esta manera, obtenemos el resultado final .
En el DAG general, nos interesa calcular la derivada del output con respecto a una de las entradas, es decir, . Para ello, utilizamos la Fórmula de Bauer. La Fórmula de Bauer establece que (con ) es igual a la sumatoria, sobre todos los caminos posibles (donde y ), del producto de las derivadas locales .
Implementación de Forward AD: Números Duales¶
Una manera de implementar Forward AD es mediante el uso de Números Duales. Un número dual extiende los números reales introduciendo una componente abstracta . Esta componente cumple con la propiedad de que , con . Un número dual se escribe de la forma . En este es el valor real de la variable y representa la variable derivada. Ambos coeficientes, y , pertenecen a los números reales.
Propiedades de los Números Duales:
Si tenemos dos números duales e , se cumplen las siguientes propiedades:
Suma: .
Producto: . Notemos que la componente del producto es estructuralmente idéntica a la regla de la derivada del producto.
En este contexto, almacena el valor de la variable original y almacena la derivada de esa variable con respecto a un parámetro. Por simplicidad, asumiendo , tenemos que e . Reemplazando en la regla del producto, obtenemos . Esto equivale directamente a .
Implementación Computacional
Para implementar esto, extendemos el concepto de “número” en nuestro código al de “número dual”. De esta forma, cada operación matemática atómica sabe cómo multiplicar números duales y, en consecuencia, propaga la derivada automáticamente. En el Modo Forward (a diferencia del modo Reverse), la evaluación avanza desde las entradas hacia la salida. Para ello, inicializamos nuestras variables de entrada emparejando su valor con su derivada direccional. Por ejemplo, el número dual inicializado para la entrada sería: .