Guía de Trabajo Práctico 2#
Materia: Aprendizaje Profundo Basado en la Física (optativa del Instituto Balseiro)
Docente: José I. Robledo
Edición: abril-mayo 2026
Ejercicio 1 — Autograd sobre energía potencial#
La idea de este ejercicio es explorar la capacidad de diferenciación automática de PyTorch. Analizaremos la energía potencial del sistema físico simple compuesto por un resorte sometido a gravedad. Consideremos una partícula de masa \(m\) unida a un resorte de constante elástica \(k\), en presencia de un campo gravitatorio \(g\). La energía potencial del sistema está dada por la elástica \(\frac{1}{2}k x^2\) y la gravitatoria \(mgx\). Sabemos que el negativo del gradiente de esta energía respecto a \(x\) representa la fuerza.
Consignas#
Definir un tensor unidimensional
xconrequires_grad=True. Inicializarxen algún valor.Definir una variable para la energía potencial
U = 0.5 k x^2 + m g xen función de \(x\). Puede utilizar una constante elástica de \(2 \frac{N}{m}\), masa de \(1.5kg\) y aceleración de la gravedad de de \(9.8\frac{m}{s^2}\).Calcular
dU/dxcon el métodobackward()de PyTorch y extraer el gradiente mediantex.grad.Comparar este valor con la derivada analítica.
Explorar varios valores de
xy graficar energía y su derivada. Identifique el punto de equilibrio.Implementar descenso por gradiente para encontrar el mínimo de la energía.
(Opcional): Utilizar PyTorch para el descenso (pasar
xal optimizador) y comparar con descenso por gradiente estocástico (SGD)(Opcional): extender el problema a 2 o 3 dimensiones.
# TODO: definir x, k, m, g
# TODO: calcular U(x) y su gradiente con autograd
# TODO: comparar con derivada analítica
# TODO: implementar descenso por el gradiente.
Ejercicio 2 — MLP de regresión para la deflexión de una viga#
Desarrollar un modelo de regresión basado en una red neuronal (MLP) que estime la deflexión máxima de una viga simplemente apoyada sometida a una carga puntual.

Según la teoría de vigas de Euler-Bernoulli 1, la deflexión máxima \(\delta\) de una viga simplemente apoyada con una carga puntual \(P\) aplicada en el centro está dada por:
donde:
( P ): carga aplicada (N)
( L ): longitud de la viga (m)
( E ): módulo de elasticidad del material (Pa)
( I ): momento de inercia de la sección (m\(^4\))
( EI ): rigidez flexional
Para este ejercicio, se utilizará una versión simplificada y con ruido de esta relación. La base de datos se encuentra en ./data/beam_dataset.csv, en donde se mide la deflexión máxima para distintos valores de \(P\), \(L\), \(EI\).
Cargar los datos a partir del archivo csv
beam_dataset.csv.Entrenar un modelo de regresión basado en un MLP (Multi-Layer Perceptron) que prediga \(\delta\) a partir de ( \(P\), \(L\), \(EI\) ).
Calcular el error medio absoluto (MAE) sobre el conjunto de test. Graficar \( y_{\text{true}} \) vs \( y_{\text{pred}} \) y el error residual.
# TODO: cargar dataset de deflexión
# TODO: entrenar MLP de regresión
# TODO: calcular MAE y graficar y_true vs y_pred
Ejercicio 3 — Clasificación de fases en Modelo Ising 2D#
En este ejercicio se trabajará con un conjunto de datos generado a partir de simulaciones del modelo de Ising bidimensional (2D) utilizando métodos de Monte Carlo (algoritmo de Metropolis).
El modelo de Ising describe un sistema de espines en una red cuadrada, donde cada sitio puede tomar valores:
(+1) (espín “arriba”)
(-1) (espín “abajo”)
Los espines vecinos tienden a alinearse, pero la temperatura introduce fluctuaciones térmicas que pueden desordenar el sistema.
El comportamiento del sistema depende de la temperatura:
Temperatura baja \((T < T_c)\): el sistema tiende a ordenarse, formando dominios grandes de espines alineados.
Temperatura alta \((T > T_c)\): el sistema permanece desordenado debido a las fluctuaciones térmicas.
Existe una temperatura crítica conocida:
en la cual ocurre una transición de fase entre el estado ordenado y desordenado.
Se provee un dataset compuesto por configuraciones del modelo de Ising. Los datos se encuentran en .data/ising_dataset.pt. Cada muestra corresponde a un vector de 625 elementos, que corresponden al aplanamiento de imagen (grilla 2D) \(25\times 25\) de espines. Cada imagen fue generada a una cierta temperatura y tiene una etiqueta asociada a si se encuentra por encima o por debajo de \(T_C\):
\(y = 0\): temperatura por debajo de \(T_c\)
\(y = 1\): temperatura por encima de \(T_c\)
Entrenar un modelo de clasificación supervisada que, dada una configuración del sistema, sea capaz de predecir si corresponde a:
fase ordenada ((T < T_c))
fase desordenada ((T > T_c))
utilizando un perceptrón multicapa (MLP) utilizando el vector de datos provisto y una red neuronal convolucional (CNN) transformando el vector en un arreglo de 2 dimensiones (imagen). Para esto, utilizar una función de pérdida adecuada para clasificación binaria. Comparar los resultados entre ambas arquitecturas comparando la accuracy en cada caso.
# cargar datos de ising_dataset.pt
data = torch.load("data/ising_dataset.pt")
# TODO: definir y entrenar clasificadores
# TODO: calcular accuracy
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[3], line 2
1 # cargar datos de ising_dataset.pt
----> 2 data = torch.load("data/ising_dataset.pt")
3
4 # TODO: definir y entrenar clasificadores
5 # TODO: calcular accuracy
NameError: name 'torch' is not defined
Ejercicio 4 — Gradiente por diferencias finitas vs backprop#
Antes de usar restricciones físicas conviene verificar que entendemos cómo se propagan los gradientes. En este ejercicio vas a comparar dos formas de estimar la derivada de una función de costo respecto de un parámetro.
Definir una red pequeña y una función de pérdida simple.
Calcular el gradiente con
backward()e imprimir el gradiente de un parámetro a elección del modelo. Para acceder a los gradientes de los pesos de la capa \(i\) del modelo se puede usarmodel[i].weight.grad.Aproximar ese mismo gradiente mediante diferencias finitas. Para esto, vamos a aproximar \(\partial f_w(x) / \partial w_i \approx (f_{w_i+\epsilon}(x)-f_{w_i-\epsilon}(x))/(2\epsilon)\). consejo: utilizar
with torch.no_gradpara no trackear los cambios manuales en los parámetros en el grafo.Comparar ambos valores y comentar si la diferencia es pequeña.
# TODO: definir una red pequeña y una loss
# TODO: calcular gradiente por backward
# TODO: aproximar el gradiente por diferencias finitas
# TODO: comparar ambos valores
Ejercicio 5 — Positividad de un coeficiente físico#
Muchos parámetros físicos no pueden tomar cualquier valor. Por ejemplo, un coeficiente de difusión o un amortiguamiento deben ser positivos. Si el modelo predice valores negativos, el ajuste puede ser numéricamente correcto pero físicamente inválido.
Generaremos un dataset sintético donde el coeficiente objetivo deba ser siempre positivo.
Entrenar un modelo con salida libre.
Entrenar otro modelo que garantice positividad usando
softplusen la salida.Comparar predicciones y detectar si el modelo libre produce valores sin sentido físico.
T = torch.linspace(300, 900, 300).view(-1, 1)
def generador_de_datos(T):
return 0.05 + 0.0002 * (T - 300) + 0.005 * torch.rand_like(T)
# TODO: entrenar un modelo libre y otro con salida softplus
# TODO: comparar si aparecen valores no físicos
Ejercicio 6 — Penalización física por constraint#
En muchos sistemas físicos no solo importa el valor predicho, sino también cómo cambia respecto a las variables de entrada. Por ejemplo, en flujo en tuberías, la caída de presión debe ser una función creciente del caudal.
Verificar que el código presentado para la generación de datos genere datos de la forma \(\Delta P \propto \frac{Q^2}{D^5}\)
Definir una red cuyo objetivo sea predecir el logaritmo de la caída de presión (\(\log \Delta P\)) en función del logaritmo del caudal \(\log Q\) y el logaritmo del diámetro \(\log D\).
Utilizar autograd para calcular la derivada de la predicción respecto de las entradas.
Agregar una penalización que castigue regiones donde
dP/dQ < 0(para esto tener en cuenta la desnormalización y la transformada inversa del logaritmo).Entrenar con pérdida total = pérdida de datos + cte * penalización física (inclusión de sesgo inductivo).
Q = torch.rand(400, 1) * 5.0 # Caudal
D = 0.05 + 0.15 * torch.rand(400, 1) # Diámetro
X = torch.cat([torch.log(Q + 1e-8), torch.log(D)], dim=1)
y = 10.0 * Q**2 / D**5
y = torch.log(y+ 1e-8) + 0.01 * torch.randn_like(Q)
X_mean = X.mean(0, keepdim=True)
X_std = X.std(0, keepdim=True)
y_mean = y.mean()
y_std = y.std()
Xn = (X - X_mean) / X_std
yn = (y - y_mean) / y_std
# TODO: definir una penalización de monotonicidad dP/dQ >= 0
# TODO: entrenar con loss de datos + penalidad