¿Cómo creamos un modelo de regresión lineal en PyTorch?
¡Bienvenido! Hoy nos adentraremos en el fascinante mundo de la regresión lineal utilizando PyTorch. Este enfoque es similar al que exploramos en la clase "Hola Mundo", pero con nuevas piezas y conexiones que nos permitirán lograr nuestras metas de manera más efectiva. Para ello, necesitaremos familiarizarnos con algunas librerías clave: torch.nn, torch.optim, Dataset y DataLoader. Aunque en este momento solo utilizaremos las dos primeras, entender su papel es crucial para el desarrollo en PyTorch.
¿Qué son y cómo inicializamos los parámetros del modelo?
El modelo que crearemos se basará en dos parámetros esenciales: volumen y sesgo. Estos parámetros se entrenan y mejoran durante el proceso de optimización. Para ello, iniciamos con valores aleatorios, con la finalidad de ajustar los pesos hasta alcanzar la regresión lineal deseada.
import torch
from torch import nn
classModeloRegresion(nn.Module):def__init__(self):super().__init__() self.volumen = nn.Parameter(torch.rand(1, dtype=torch.float, requires_grad=True)) self.sesgo = nn.Parameter(torch.rand(1, dtype=torch.float, requires_grad=True))
Los parámetros se definen utilizando nn.Parameter, permitiendo que sean entrenables y ajustables durante el entrenamiento. Comenzar con valores aleatorios ofrece flexibilidad en la optimización, algo fundamental en modelos de machine learning.
¿Cómo se realiza la función forward?
La función forward es indispensable, ya que especifica el flujo de datos a través de nuestro modelo, permitiendo que realice predicciones. Se utiliza para aplicar operaciones a los datos de entrada, y en este caso, calculamos la regresión lineal.
defforward(self, x: torch.Tensor)-> torch.Tensor:return self.volumen * x + self.sesgo
Aquí, multiplicamos el volumen por el dato de entrada x y sumamos el sesgo. Este paso es clave para definir el comportamiento del modelo.
¿Cómo inicializamos el modelo y preparamos para la predicción?
Antes de inicializar nuestro modelo, configuramos una semilla aleatoria con torch.manual_seed para garantizar la reproducibilidad. Este paso es vital, especialmente cuando trabajamos con valores aleatorios.
torch.manual_seed(42)modelo1 = ModeloRegresion()
Después, utilizamos la función state_dict para inspeccionar el estado actual del modelo con sus parámetros iniciales. Esto nos permite seguir el progreso del modelo a lo largo del entrenamiento.
¿Cómo hacemos predicciones con el modelo no entrenado?
Mientras que el modelo no está entrenado, podemos comenzar a obtener predicciones. Usamos el inferenceMode de Torch para desactivar el gradiente durante la predicción, ya que solo se necesita durante el entrenamiento.
with torch.inference_mode(): y_pred = modelo1(torch.tensor([x_values], dtype=torch.float))
Estas predicciones iniciales, basadas en ajustes aleatorios, son inexactas, pero nos proporcionan un punto de partida para medir el progreso del modelo durante el entrenamiento.
¡Anímate a seguir profundizando! Aunque pueda parecer desafiante, entender estos conceptos te abrirá puertas en el mundo de la programación en inteligencia artificial. Cada paso que des te acercará más a la maestría en machine learning con PyTorch.
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.