Entrenamiento del Modelo
Preparación para el entrenamiento
Primero, es necesario asegurarse de que el modelo, la función de pérdida y el optimizador estén correctamente definidos. Revisemos cada paso:
- Función de pérdida: para clasificación, se puede utilizar
CrossEntropyLoss, que espera valores continuos sin procesar (logits) como entrada y aplica automáticamentesoftmax; - Optimizador: se puede utilizar el optimizador Adam para actualizaciones eficientes del gradiente.
import torch.nn as nn
import torch.optim as optim
# Define the loss function (cross-entropy for multi-class classification)
criterion = nn.CrossEntropyLoss()
# Define the optimizer (Adam with a learning rate of 0.01)
optimizer = optim.Adam(model.parameters(), lr=0.01)
En PyTorch, la pérdida de entropía cruzada combina log-softmax y negative log-likelihood (NLL) en una sola función de pérdida:
donde:
- zy es el logit correspondiente a la clase correcta;
- C es el número total de clases.
También es importante dividir los datos en conjuntos de entrenamiento y validación (idealmente, también debería existir un conjunto de prueba separado). Dado que el conjunto de datos es relativamente pequeño (1143 filas), utilizamos una división de 80% a 20%. En este caso, el conjunto de validación también servirá como conjunto de prueba.
80% para entrenamiento y 20% para prueba suele ser adecuado en muchos escenarios. Sin embargo, para conjuntos de datos grandes, como aquellos con millones de registros, incluso un porcentaje menor asignado al conjunto de prueba (10% o menos) puede ser suficiente para lograr una evaluación confiable del rendimiento. Por el contrario, con conjuntos de datos muy pequeños (por ejemplo, menos de mil registros), es crucial asegurarse de que el conjunto de prueba sea lo suficientemente grande (25-30%) para proporcionar una evaluación significativa del rendimiento del modelo.
Además, los arrays de NumPy resultantes deben convertirse en tensores, ya que los modelos de PyTorch requieren entradas en formato tensor para realizar los cálculos.
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
X_train = torch.tensor(X_train, dtype=torch.float32)
X_test = torch.tensor(X_test, dtype=torch.float32)
y_train = torch.tensor(y_train, dtype=torch.long)
y_test = torch.tensor(y_test, dtype=torch.long)
Bucle de entrenamiento
El bucle de entrenamiento implica los siguientes pasos para cada época:
- Propagación hacia adelante: pasar las características de entrada a través del modelo para generar predicciones;
- Cálculo de la pérdida: comparar las predicciones con los valores reales utilizando la función de pérdida;
- Propagación hacia atrás: calcular los gradientes con respecto a los parámetros del modelo mediante retropropagación;
- Actualización de parámetros: ajustar los parámetros del modelo utilizando el optimizador;
- Monitoreo del progreso: imprimir la pérdida periódicamente para observar la convergencia.
Como se puede observar, el proceso de entrenamiento es similar al de la regresión lineal.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849import torch.nn as nn import torch import torch.optim as optim import matplotlib.pyplot as plt import os os.system('wget https://staging-content-media-cdn.codefinity.com/courses/1dd2b0f6-6ec0-40e6-a570-ed0ac2209666/section_3/model_definition.py 2>/dev/null') from model_definition import model, X, y from sklearn.model_selection import train_test_split # Set manual seed for reproducibility torch.manual_seed(42) # Reinitialize model after setting seed model.apply(lambda m: m.reset_parameters() if hasattr(m, "reset_parameters") else None) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) X_train = torch.tensor(X_train, dtype=torch.float32) X_test = torch.tensor(X_test, dtype=torch.float32) y_train = torch.tensor(y_train, dtype=torch.long) y_test = torch.tensor(y_test, dtype=torch.long) # Define the loss function (Cross-Entropy for multi-class classification) criterion = nn.CrossEntropyLoss() # Define the optimizer (Adam with a learning rate of 0.01) optimizer = optim.Adam(model.parameters(), lr=0.01) # Number of epochs epochs = 100 # Store losses for plotting training_losses = [] # Training loop for epoch in range(epochs): # Zero out gradients from the previous step optimizer.zero_grad() # Compute predictions predictions = model(X_train) # Compute the loss loss = criterion(predictions, y_train) # Compute gradients loss.backward() # Update parameters optimizer.step() # Store the loss training_losses.append(loss.item()) # Plot the training loss plt.plot(range(epochs), training_losses, label="Training Loss") plt.xlabel("Epoch") plt.ylabel("Loss") plt.title("Training Loss over Epochs") plt.legend() plt.show()
Llamar a model(input) invoca automáticamente el método forward() del modelo. Esto se debe a que nn.Module sobrescribe el método __call__, que internamente llama a forward(). Se recomienda utilizar model(input) en lugar de model.forward(input), ya que el primero garantiza que cualquier hook o funcionalidad adicional (por ejemplo, model.train() o model.eval()) se aplique correctamente.
Observación de la convergencia
Además de entrenar el modelo, también se registra la pérdida de entrenamiento en cada época y se grafica a lo largo del tiempo. Como se muestra en la gráfica, la pérdida de entrenamiento inicialmente disminuye rápidamente y luego se estabiliza gradualmente alrededor de la época 60. A partir de este punto, la pérdida disminuye a un ritmo mucho más lento, lo que sugiere que el modelo probablemente ha convergido. Por lo tanto, utilizar alrededor de 40 épocas para este modelo sería suficiente.
¡Gracias por tus comentarios!
Pregunte a AI
Pregunte a AI
Pregunte lo que quiera o pruebe una de las preguntas sugeridas para comenzar nuestra charla
Genial!
Completion tasa mejorada a 5
Entrenamiento del Modelo
Desliza para mostrar el menú
Preparación para el entrenamiento
Primero, es necesario asegurarse de que el modelo, la función de pérdida y el optimizador estén correctamente definidos. Revisemos cada paso:
- Función de pérdida: para clasificación, se puede utilizar
CrossEntropyLoss, que espera valores continuos sin procesar (logits) como entrada y aplica automáticamentesoftmax; - Optimizador: se puede utilizar el optimizador Adam para actualizaciones eficientes del gradiente.
import torch.nn as nn
import torch.optim as optim
# Define the loss function (cross-entropy for multi-class classification)
criterion = nn.CrossEntropyLoss()
# Define the optimizer (Adam with a learning rate of 0.01)
optimizer = optim.Adam(model.parameters(), lr=0.01)
En PyTorch, la pérdida de entropía cruzada combina log-softmax y negative log-likelihood (NLL) en una sola función de pérdida:
donde:
- zy es el logit correspondiente a la clase correcta;
- C es el número total de clases.
También es importante dividir los datos en conjuntos de entrenamiento y validación (idealmente, también debería existir un conjunto de prueba separado). Dado que el conjunto de datos es relativamente pequeño (1143 filas), utilizamos una división de 80% a 20%. En este caso, el conjunto de validación también servirá como conjunto de prueba.
80% para entrenamiento y 20% para prueba suele ser adecuado en muchos escenarios. Sin embargo, para conjuntos de datos grandes, como aquellos con millones de registros, incluso un porcentaje menor asignado al conjunto de prueba (10% o menos) puede ser suficiente para lograr una evaluación confiable del rendimiento. Por el contrario, con conjuntos de datos muy pequeños (por ejemplo, menos de mil registros), es crucial asegurarse de que el conjunto de prueba sea lo suficientemente grande (25-30%) para proporcionar una evaluación significativa del rendimiento del modelo.
Además, los arrays de NumPy resultantes deben convertirse en tensores, ya que los modelos de PyTorch requieren entradas en formato tensor para realizar los cálculos.
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
X_train = torch.tensor(X_train, dtype=torch.float32)
X_test = torch.tensor(X_test, dtype=torch.float32)
y_train = torch.tensor(y_train, dtype=torch.long)
y_test = torch.tensor(y_test, dtype=torch.long)
Bucle de entrenamiento
El bucle de entrenamiento implica los siguientes pasos para cada época:
- Propagación hacia adelante: pasar las características de entrada a través del modelo para generar predicciones;
- Cálculo de la pérdida: comparar las predicciones con los valores reales utilizando la función de pérdida;
- Propagación hacia atrás: calcular los gradientes con respecto a los parámetros del modelo mediante retropropagación;
- Actualización de parámetros: ajustar los parámetros del modelo utilizando el optimizador;
- Monitoreo del progreso: imprimir la pérdida periódicamente para observar la convergencia.
Como se puede observar, el proceso de entrenamiento es similar al de la regresión lineal.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849import torch.nn as nn import torch import torch.optim as optim import matplotlib.pyplot as plt import os os.system('wget https://staging-content-media-cdn.codefinity.com/courses/1dd2b0f6-6ec0-40e6-a570-ed0ac2209666/section_3/model_definition.py 2>/dev/null') from model_definition import model, X, y from sklearn.model_selection import train_test_split # Set manual seed for reproducibility torch.manual_seed(42) # Reinitialize model after setting seed model.apply(lambda m: m.reset_parameters() if hasattr(m, "reset_parameters") else None) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) X_train = torch.tensor(X_train, dtype=torch.float32) X_test = torch.tensor(X_test, dtype=torch.float32) y_train = torch.tensor(y_train, dtype=torch.long) y_test = torch.tensor(y_test, dtype=torch.long) # Define the loss function (Cross-Entropy for multi-class classification) criterion = nn.CrossEntropyLoss() # Define the optimizer (Adam with a learning rate of 0.01) optimizer = optim.Adam(model.parameters(), lr=0.01) # Number of epochs epochs = 100 # Store losses for plotting training_losses = [] # Training loop for epoch in range(epochs): # Zero out gradients from the previous step optimizer.zero_grad() # Compute predictions predictions = model(X_train) # Compute the loss loss = criterion(predictions, y_train) # Compute gradients loss.backward() # Update parameters optimizer.step() # Store the loss training_losses.append(loss.item()) # Plot the training loss plt.plot(range(epochs), training_losses, label="Training Loss") plt.xlabel("Epoch") plt.ylabel("Loss") plt.title("Training Loss over Epochs") plt.legend() plt.show()
Llamar a model(input) invoca automáticamente el método forward() del modelo. Esto se debe a que nn.Module sobrescribe el método __call__, que internamente llama a forward(). Se recomienda utilizar model(input) en lugar de model.forward(input), ya que el primero garantiza que cualquier hook o funcionalidad adicional (por ejemplo, model.train() o model.eval()) se aplique correctamente.
Observación de la convergencia
Además de entrenar el modelo, también se registra la pérdida de entrenamiento en cada época y se grafica a lo largo del tiempo. Como se muestra en la gráfica, la pérdida de entrenamiento inicialmente disminuye rápidamente y luego se estabiliza gradualmente alrededor de la época 60. A partir de este punto, la pérdida disminuye a un ritmo mucho más lento, lo que sugiere que el modelo probablemente ha convergido. Por lo tanto, utilizar alrededor de 40 épocas para este modelo sería suficiente.
¡Gracias por tus comentarios!