Crear un modelo de regresión lineal en PyTorch se logra usando nn.Module junto con parámetros entrenables como volumen y sesgo. Si ya construiste un Hola Mundo con PyTorch, este paso te resultará familiar: misma estructura, distintos bloques de Lego. Esta guía es para ti si estás empezando con redes neuronales y quieres entender cómo se arma un modelo desde cero.
¿Qué librerías necesito para construir un modelo en PyTorch?
Antes de escribir código, conviene tener claras las cuatro librerías base que sostienen casi cualquier proyecto en PyTorch.
torch.nn: clases y funciones para definir redes neuronales.
torch.optim: herramientas para optimizar el modelo durante el entrenamiento.
Dataset (de utils): representa tus datos en un formato compatible con PyTorch.
DataLoader (de utils): agrupa los datos en batches y los envía al modelo o a la GPU.
En esta etapa solo usarás las dos primeras, pero las cuatro forman el kit completo para flujos más serios.
¿Para qué sirve torch.nn en PyTorch? Es el módulo que contiene las clases base para construir redes neuronales, incluyendo nn.Module y nn.Parameter. Lo usas como punto de partida para definir cualquier modelo.
¿Cómo definir un modelo de regresión lineal con nn.Module?
Un modelo de regresión lineal en PyTorch necesita dos parámetros entrenables: volumen (la pendiente) y sesgo (el intercepto). Ambos se inicializan con valores aleatorios y se ajustan durante el entrenamiento.
¿Qué hace nn.Parameter dentro del modelo?
Usas nn.Parameter para indicarle a PyTorch que un tensor es entrenable. Eso significa que tendrá un gradiente asociado y podrá actualizarse en cada iteración del entrenamiento.
def forward(self,x: torch.Tensor)-> torch.Tensor:return self.volumen* x + self.sesgo
Nota un detalle importante: requires_grad=True activa el seguimiento del gradiente, que es la señal que indica si un peso debe crecer o disminuir para mejorar las predicciones.
¿Por qué usar torch.float y un tensor de dimensión 1?
Los pesos se entrenan mejor en formato float que en enteros, porque los ajustes son fracciones pequeñas. Y al ser una regresión lineal sencilla, basta con un escalar de dimensión uno para cada parámetro.
A diferencia del modelo Hola Mundo, aquí no le pides al usuario que ingrese valores iniciales: el modelo se inicializa solo con números aleatorios.
¿Cómo inicializar y reproducir el modelo con torch.manual_seed?
Antes de instanciar el modelo, conviene fijar una semilla para que los valores aleatorios sean reproducibles entre ejecuciones.
El número 42 es arbitrario; lo importante es que cada vez que uses la misma semilla, los pesos iniciales serán idénticos. Esto es clave cuando quieres comparar experimentos o compartir resultados con otras personas.
¿Qué hace torch.manual_seed? Fija el generador de números aleatorios para que los valores iniciales se repitan en cada ejecución. Es buena práctica usarlo siempre que quieras reproducibilidad.
¿Qué es el state_dict y por qué importa?
Llamando a model1.state_dict() obtienes un OrderedDict con los pesos actuales del modelo. Por ejemplo, podrías ver algo como volumen: tensor([0.3367]) y sesgo: tensor([0.1288]), valores aleatorios producto de la semilla.
El state_dict te será fundamental más adelante para guardar y cargar modelos, porque almacena el valor exacto de cada peso entrenado.
¿Cómo hacer predicciones con un modelo sin entrenar?
Aunque el modelo todavía no aprende nada útil, ya puede generar predicciones. Para eso usas el modo de inferencia, que desactiva el cálculo del gradiente y hace todo más eficiente.
python
with torch.inference_mode():
y_pred_c = model1(X_pred)
El inference_mode se usa cuando solo quieres predecir, no entrenar. El gradiente solo es necesario durante el entrenamiento, así que apagarlo ahorra memoria y cómputo.
Al graficar y_pred_c con Matplotlib junto a los datos de entrenamiento (verdes) y de prueba (amarillos), notarás que las predicciones en rojo están muy lejos de la línea esperada. No coinciden ni en pendiente ni en sesgo, y eso es completamente normal: el modelo arrancó con números aleatorios.
¿Qué cambió respecto al modelo Hola Mundo de PyTorch?
La estructura sigue siendo la misma: heredas de nn.Module, defines __init__ con super().__init__() y construyes la lógica en forward. Lo que cambia son los bloques de Lego que usas y cómo los conectas.
En el Hola Mundo conectabas piezas predefinidas; aquí defines tus propios parámetros con nn.Parameter y los combinas en una operación lineal volumen * x + sesgo. Mismo proceso, distinto nivel de control.
Si llegaste hasta aquí, ya tienes un modelo funcional listo para ser entrenado. Cuéntame en los comentarios qué semilla usaste y qué valores iniciales obtuviste para tus pesos.
Gracias profe sus clases son las que mas me han gustado
es buenisimo que tenga las plantillas para que uno desarrolle la clase
Claro, la estructura de un modelo en PyTorch se define comúnmente utilizando el módulo torch.nn, que proporciona herramientas para construir redes neuronales de manera eficiente. A continuación, te explico cómo se construye un modelo y te doy un ejemplo.
### Estructura de un Modelo en PyTorch
1. **Definición de la Clase del Modelo:**
- Se crea una clase que hereda de torch.nn.Module.
- En el constructor \_\_init\_\_, se definen las capas de la red neuronal (como Linear, Conv2d, etc.).
- En el método forward, se definen las operaciones que se aplican a las entradas a través de las capas.
2. **Método forward:**
- Este método toma la entrada y la pasa a través de las diferentes capas de la red en el orden que se definieron en \_\_init\_\_.
3. **Instanciación y Uso:**
- Una vez definido el modelo, se puede instanciar y utilizar para realizar predicciones o entrenarlo con datos.
### Ejemplo de un Modelo Simple
Aquí tienes un ejemplo de un modelo de red neuronal simple con una capa oculta:
import torch
import torch.nn as nn
import torch.optim as optim
\# Definición del modelo
classSimpleNN(nn.Module):  def \_\_init\_\_(self, input\_size, hidden\_size, output\_size):  super(SimpleNN, self).\_\_init\_\_()  \# Definir las capas  self.fc1 = nn.Linear(input\_size, hidden\_size) # Capa oculta  self.fc2 = nn.Linear(hidden\_size, output\_size) # Capa de salida  self.relu = nn.ReLU() # Función de activación ReLU  def forward(self, x):  \# Pasar la entrada a través de las capas  x = self.fc1(x) # Capa oculta  x = self.relu(x) # Activación  x = self.fc2(x) # Capa de salida  return x\# Parámetros del modelo
input\_size =10# Número de características de entradahidden\_size =5# Número de neuronas en la capa ocultaoutput\_size =1# Número de neuronas en la capa de salida (por ejemplo, para regresión)\# Crear una instancia del modelo
model = SimpleNN(input\_size, hidden\_size, output\_size)\# Ver la arquitectura del modelo
print(model)
\# Ejemplo de uso
\# Crear un tensor de entrada aleatorio
input\_tensor = torch.randn(1,input\_size)# Tamaño del batch = 1output\_tensor = model(input\_tensor)# Pasar la entrada a través del modeloprint("Output:", output\_tensor)
### Explicación del Ejemplo
1. **Definición de la Clase SimpleNN:**
- La clase SimpleNN hereda de nn.Module.
- Se definen dos capas lineales (fc1 y fc2) y una función de activación ReLU.
2. **Método forward:**
- En este método, la entrada se pasa primero a través de la capa oculta y luego se aplica la activación, seguida de la capa de salida.
3. **Instanciación y Uso:**
- Se crea una instancia del modelo y se imprime su arquitectura.
- Un tensor de entrada aleatorio se crea y se pasa a través del modelo para obtener la salida.
### Compilación y Entrenamiento
Para entrenar el modelo, deberás definir una función de pérdida y un optimizador, y luego ejecutar un bucle de entrenamiento que actualice los pesos del modelo en función de los datos.
¿Por qué se usa el valor 42 en torch.manual_seed?
Por lo que he indagado, el número 42 se usa en muchos ejemplos y tutoriales, principalmente por razones culturales y de popularidad, ya que es conocido como "la respuesta a la vida, el universo y todo" en la obra Guía del autoestopista galáctico de Douglas Adams.
En términos técnicos, cualquier valor puede ser usado como seed, pero utilizar uno constante como 42 ayuda a garantizar que los resultados sean reproducibles en experimentos, lo que es crucial en entrenamiento de modelos en PyTorch.
Sin embargo, ¿también puede implicar sesgo? Usar el mismo valor en todos los experimentos puede llevar a un sobreajuste a una configuración específica, limitando la variabilidad en los resultados. Puede que no siempre sea el mejor valor para todos los modelos o datasets, y otros valores pueden ofrecer mejores resultados.
¿Podría usarse otro número? Cualquier número entero serviría. Lo importante es:
Usar el mismo valor en todas las semillas relevantes (torch, numpy, random).
Documentarlo para que otros puedan replicar tus resultados.
Les dejo un código por si quieren calcular de manera casi manual la perdida
with torch.inference_mode():#Probamos el modelo con los pesos aleatorios resultado = model_lr.forward(X_test)#Calculamos la precisión del modelo resutlado_ = torch.mean((Y_test - resultado)**2)print(resultado_)#output -> tensor(0.2125)
Devuelve un tensor en 0.213 lo cual en la regresión lineal el valor tiene que estar ≈ 0 de esa manera podemos ver que tan mal el modelo está
Luego si les interesa saber pueden buscar como funciona el proceso del backpropagation ya que en este punto hicimos forward que consiste en mirar con los pesos que hay , como se comporta el modelo usando la función de costo mostrada, pero luego en el back , tenemos que se deriva esa función respecto a los pesos el w1 y w0 que acá conocemos como volumen y sesgo, esto para calcular el gradiente que indica la dirección del error, luego con el descenso del gradiente se encarga de iterar constantemente una n cantidad de veces hasta que este error disminuye, eso gráficamente se puede ver como. Tenemos una grafica , iniciamos en un punto pero tenemos que estar abajo de del todo , el gradiente nos dice donde estamos ubicados, para poder definir hacia donde ir , luego damos paso x pasos (lr - α) hasta llegar a el ≈ 0
import matplotlib.pyplotas plt
import torch
modelo1.eval()with torch.inference_mode(): pred_test =modelo1(X_test)# si están en GPU los bajamos
x =X_test.detach().cpu().numpy()y_real =Y_test.detach().cpu().numpy()y_pred = pred_test.detach().cpu().numpy()plt.figure()plt.scatter(x, y_real, label="Real")plt.scatter(x, y_pred, label="Predicción")plt.legend()plt.title("Modelo de Regresión Lineal")plt.xlabel("X")plt.ylabel("Y")plt.show()
■ Resumen:
En este fragmento crearemos un conjunto de datos (Tran, test) lineales con el propósito de evaluar un modelo lineal de torch que también crearemos usando nnModule. La idea central es validar las etapas pre-entrenamiento, post-entrenamiento y su desempeño en cada etapa, así podremos apreciar paso a paso la importancia de los pasos en el proceso.