Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Aprenda Treinamento do Modelo | Seção
Essenciais do PyTorch para Engenheiro de ML

bookTreinamento do Modelo

Preparação para o Treinamento

Primeiro, é necessário garantir que o modelo, a função de perda e o otimizador estejam devidamente definidos. Vamos analisar cada etapa:

  1. Função de perda: para classificação, pode-se utilizar CrossEntropyLoss, que espera valores contínuos brutos (logits) como entrada e aplica automaticamente o softmax;
  2. Otimizador: pode-se utilizar o otimizador Adam para atualizações eficientes dos gradientes.
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)

No PyTorch, a função de perda cross-entropy combina log-softmax e negative log-likelihood (NLL) em uma única função de perda:

L=log(ezyj=1Cezj)\mathcal{L} = - \log{\left( \frac{e^{z_y}}{\sum^C_{j=1}e^{z_j}} \right)}

onde:

  • zy é o logit correspondente à classe correta;
  • C é o número total de classes.

Também é importante dividir os dados em conjuntos de treinamento e validação (idealmente, deve existir também um conjunto de teste separado). Como o conjunto de dados é relativamente pequeno (1143 linhas), utilizamos uma divisão de 80% para 20%. Neste caso, o conjunto de validação também servirá como conjunto de teste.

Note
Aprofunde-se

80% para treinamento e 20% para teste costuma ser adequado para muitos cenários. No entanto, para conjuntos de dados maiores, como aqueles com milhões de registros, até mesmo uma porcentagem menor destinada ao conjunto de teste (10% ou menos) pode ser suficiente para obter uma avaliação confiável de desempenho. Por outro lado, em conjuntos de dados muito pequenos (por exemplo, menos de mil registros), é fundamental garantir que o conjunto de teste seja suficientemente grande (25-30%) para fornecer uma avaliação significativa do desempenho do modelo.

Além disso, os arrays NumPy resultantes devem ser convertidos em tensores, pois os modelos PyTorch exigem entradas do tipo tensor para realizar os 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)

Loop de Treinamento

O loop de treinamento envolve as seguintes etapas para cada época:

  1. Passagem direta: passar as características de entrada pelo modelo para gerar previsões;
  2. Cálculo da perda: comparar as previsões com os valores reais utilizando a função de perda;
  3. Passagem reversa: calcular os gradientes em relação aos parâmetros do modelo utilizando retropropagação;
  4. Atualização dos parâmetros: ajustar os parâmetros do modelo utilizando o otimizador;
  5. Monitoramento do progresso: exibir periodicamente a perda para observar a convergência.

Como pode ser observado, o processo de treinamento é semelhante ao da regressão linear.

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
import 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()
copy
Note
Nota

Chamar model(input) invoca automaticamente o método forward() do modelo. Isso ocorre porque nn.Module sobrescreve o método __call__, que internamente chama forward(). Recomenda-se utilizar model(input) em vez de model.forward(input), pois o primeiro garante que quaisquer hooks ou funcionalidades adicionais (por exemplo, model.train() ou model.eval()) sejam devidamente aplicados.

Observando a Convergência

Além de treinar o modelo, também registramos a perda de treinamento em cada época e a plotamos ao longo do tempo. Como mostrado no gráfico, a perda de treinamento inicialmente diminui rapidamente e depois se estabiliza gradualmente por volta da época 60. A partir desse ponto, a perda diminui em um ritmo muito mais lento, sugerindo que o modelo provavelmente convergiu. Portanto, utilizar cerca de 40 épocas para este modelo seria suficiente.

question mark

Qual das alternativas a seguir apresenta a sequência correta de etapas em um loop de treinamento do PyTorch?

Select the correct answer

Tudo estava claro?

Como podemos melhorá-lo?

Obrigado pelo seu feedback!

Seção 1. Capítulo 18

Pergunte à IA

expand

Pergunte à IA

ChatGPT

Pergunte o que quiser ou experimente uma das perguntas sugeridas para iniciar nosso bate-papo

bookTreinamento do Modelo

Deslize para mostrar o menu

Preparação para o Treinamento

Primeiro, é necessário garantir que o modelo, a função de perda e o otimizador estejam devidamente definidos. Vamos analisar cada etapa:

  1. Função de perda: para classificação, pode-se utilizar CrossEntropyLoss, que espera valores contínuos brutos (logits) como entrada e aplica automaticamente o softmax;
  2. Otimizador: pode-se utilizar o otimizador Adam para atualizações eficientes dos gradientes.
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)

No PyTorch, a função de perda cross-entropy combina log-softmax e negative log-likelihood (NLL) em uma única função de perda:

L=log(ezyj=1Cezj)\mathcal{L} = - \log{\left( \frac{e^{z_y}}{\sum^C_{j=1}e^{z_j}} \right)}

onde:

  • zy é o logit correspondente à classe correta;
  • C é o número total de classes.

Também é importante dividir os dados em conjuntos de treinamento e validação (idealmente, deve existir também um conjunto de teste separado). Como o conjunto de dados é relativamente pequeno (1143 linhas), utilizamos uma divisão de 80% para 20%. Neste caso, o conjunto de validação também servirá como conjunto de teste.

Note
Aprofunde-se

80% para treinamento e 20% para teste costuma ser adequado para muitos cenários. No entanto, para conjuntos de dados maiores, como aqueles com milhões de registros, até mesmo uma porcentagem menor destinada ao conjunto de teste (10% ou menos) pode ser suficiente para obter uma avaliação confiável de desempenho. Por outro lado, em conjuntos de dados muito pequenos (por exemplo, menos de mil registros), é fundamental garantir que o conjunto de teste seja suficientemente grande (25-30%) para fornecer uma avaliação significativa do desempenho do modelo.

Além disso, os arrays NumPy resultantes devem ser convertidos em tensores, pois os modelos PyTorch exigem entradas do tipo tensor para realizar os 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)

Loop de Treinamento

O loop de treinamento envolve as seguintes etapas para cada época:

  1. Passagem direta: passar as características de entrada pelo modelo para gerar previsões;
  2. Cálculo da perda: comparar as previsões com os valores reais utilizando a função de perda;
  3. Passagem reversa: calcular os gradientes em relação aos parâmetros do modelo utilizando retropropagação;
  4. Atualização dos parâmetros: ajustar os parâmetros do modelo utilizando o otimizador;
  5. Monitoramento do progresso: exibir periodicamente a perda para observar a convergência.

Como pode ser observado, o processo de treinamento é semelhante ao da regressão linear.

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
import 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()
copy
Note
Nota

Chamar model(input) invoca automaticamente o método forward() do modelo. Isso ocorre porque nn.Module sobrescreve o método __call__, que internamente chama forward(). Recomenda-se utilizar model(input) em vez de model.forward(input), pois o primeiro garante que quaisquer hooks ou funcionalidades adicionais (por exemplo, model.train() ou model.eval()) sejam devidamente aplicados.

Observando a Convergência

Além de treinar o modelo, também registramos a perda de treinamento em cada época e a plotamos ao longo do tempo. Como mostrado no gráfico, a perda de treinamento inicialmente diminui rapidamente e depois se estabiliza gradualmente por volta da época 60. A partir desse ponto, a perda diminui em um ritmo muito mais lento, sugerindo que o modelo provavelmente convergiu. Portanto, utilizar cerca de 40 épocas para este modelo seria suficiente.

question mark

Qual das alternativas a seguir apresenta a sequência correta de etapas em um loop de treinamento do PyTorch?

Select the correct answer

Tudo estava claro?

Como podemos melhorá-lo?

Obrigado pelo seu feedback!

Seção 1. Capítulo 18
some-alt