Treinar seu modelo de análise de dados com o PyTorch

No estágio anterior deste tutorial, criamos o conjunto de dados a ser usado para treinar um modelo de análise de dados com o PyTorch. Agora, é hora de colocar esses dados em uso.

Para treinar o modelo de análise de dados com o PyTorch, é preciso seguir estas etapas:

  1. Carregue os dados. Se você concluiu a etapa anterior deste tutorial, já lidou com isso.
  2. Defina uma rede neural.
  3. Defina uma função de perda.
  4. Treine o modelo nos dados de treinamento.
  5. Teste a rede nos dados de teste.

Definir uma rede neural

Neste tutorial, você criará um modelo básico de rede neural com três camadas lineares. Esta é a estrutura do modelo:

Linear -> ReLU -> Linear -> ReLU -> Linear

A camada Linear faz a transformação linear dos dados de entrada. No entanto, você precisa especificar o número de recursos de entrada e saída, que deve ser igual ao número de classes.

A camada ReLu é uma função de ativação para definir todos os recursos de entrada como zero ou mais. Portanto, ao usá-la, todo número menor que zero é alterado para zero, e os outros serão mantidos da mesma forma. Vamos aplicar a camada de ativação às duas camadas ocultas, e a última camada Linear ficará sem ativação.

Parâmetros de modelo

Os parâmetros de modelo dependem da meta e dos dados de treinamento. Já o tamanho da entrada depende do número de recursos colocados no modelo – quatro, neste caso. O tamanho da saída é de três, pois há três espécies possíveis de Íris.

Com três camadas lineares, (4,24) -> (24,24) -> (24,3), a rede terá 744 pesos (96+576+72).

A lr (taxa de aprendizado) define o controle de quanto você está ajustando os pesos da rede em relação ao gradiente de perda. Quanto menor for, mais lento será o treinamento. Defina a lr como 0,01 neste tutorial.

Como funciona a rede?

Aqui, você está criando uma rede direta. Durante o processo de treinamento, a rede processará a entrada em todas as camadas, calculará a perda para entender a qual distância um o rótulo previsto da imagem está da imagem correta e propagará os gradientes de volta para a rede para atualizar os pesos das camadas. Ao iterar em um grande conjunto de dados de entradas, a rede aprenderá a definir seus pesos para obter os melhores resultados.

Uma função forward calcula o valor da função de perda, e uma função backward calcula os gradientes dos parâmetros que podem ser aprendidos. Ao criar nossa rede neural com PyTorch, você só precisa definir a função forward. A função backward será definida automaticamente.

  1. Copie o código a seguir para o arquivo DataClassifier.py no Visual Studio a fim de definir os parâmetros de modelo e a rede neural.
# Define model parameters 
input_size = list(input.shape)[1]   # = 4. The input depends on how many features we initially feed the model. In our case, there are 4 features for every predict value  
learning_rate = 0.01 
output_size = len(labels)           # The output is prediction results for three types of Irises.  


# Define neural network 
class Network(nn.Module): 
   def __init__(self, input_size, output_size): 
       super(Network, self).__init__() 
        
       self.layer1 = nn.Linear(input_size, 24) 
       self.layer2 = nn.Linear(24, 24) 
       self.layer3 = nn.Linear(24, output_size) 


   def forward(self, x): 
       x1 = F.relu(self.layer1(x)) 
       x2 = F.relu(self.layer2(x1)) 
       x3 = self.layer3(x2) 
       return x3 
 
# Instantiate the model 
model = Network(input_size, output_size) 

Também será necessário definir o dispositivo de execução de acordo com o que você tem no seu computador. O PyTorch não tem uma biblioteca dedicada para GPU, mas você pode definir manualmente o dispositivo de execução. Esse dispositivo será uma GPU Nvidia, se você a tiver em seu computador, ou a CPU, caso não tenha.

  1. Copie o código seguinte para definir o dispositivo de execução:
# Define your execution device 
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") 
print("The model will be running on", device, "device\n") 
model.to(device)    # Convert model parameters and buffers to CPU or Cuda 
  1. A última etapa é definir uma função para salvar o modelo:
# Function to save the model 
def saveModel(): 
    path = "./NetModel.pth" 
    torch.save(model.state_dict(), path) 

Observação

Interessado em saber mais sobre rede neural com PyTorch? Confira a documentação do PyTorch.

Definir uma função de perda

Uma função de perda calcula um valor que estima a distância que uma saída está do destino. O objetivo principal é reduzir o valor da função de perda alterando os valores de vetor de peso por meio de retropropagação em redes neurais.

O valor de perda é diferente de precisão do modelo. A função de perda mostra como um modelo se comporta após cada iteração de otimização no conjunto de treinamento. Já a precisão do modelo é calculada nos dados de teste e mostra o percentual de previsões corretas.

No PyTorch, o pacote de rede neural contém várias funções de perda que formam os blocos de construção de redes neurais profundas. Para saber mais sobre essas especificações, confira a observação acima. Aqui, vamos usar as funções existentes otimizadas para classificação desta maneira, além de usar uma função de perda de classificação de entropia cruzada e um otimizador Adam. No otimizador, a lr (Taxa de aprendizado) define o controle de quanto você está ajustando os pesos da rede em relação ao gradiente de perda. Aqui, ele será de 0,001 – quanto menor, mais lento será o treinamento.

  1. Copie o código a seguir no arquivo DataClassifier.py no Visual Studio para definir a função de perda e um otimizador.
# Define the loss function with Classification Cross-Entropy loss and an optimizer with Adam optimizer
loss_fn = nn.CrossEntropyLoss()
optimizer = Adam(model.parameters(), lr=0.001, weight_decay=0.0001)

Treine o modelo nos dados de treinamento.

Para treinar o modelo, você precisa fazer um loop em nosso iterador de dados, alimentar as entradas na rede e otimizar. Para validar os resultados, basta comparar os rótulos previstos com os reais no conjunto de dados de validação após cada época de treinamento.

O programa exibirá a perda de treinamento, a perda de validação e a precisão do modelo para cada época ou para cada iteração completa no conjunto de treinamento. Além disso, salvará o modelo com a precisão mais alta e, após dez épocas, mostrará a precisão final.

  1. Adicione o seguinte código ao arquivo DataClassifier.py
# Training Function 
def train(num_epochs): 
    best_accuracy = 0.0 
     
    print("Begin training...") 
    for epoch in range(1, num_epochs+1): 
        running_train_loss = 0.0 
        running_accuracy = 0.0 
        running_vall_loss = 0.0 
        total = 0 
 
        # Training Loop 
        for data in train_loader: 
        #for data in enumerate(train_loader, 0): 
            inputs, outputs = data  # get the input and real species as outputs; data is a list of [inputs, outputs] 
            optimizer.zero_grad()   # zero the parameter gradients          
            predicted_outputs = model(inputs)   # predict output from the model 
            train_loss = loss_fn(predicted_outputs, outputs)   # calculate loss for the predicted output  
            train_loss.backward()   # backpropagate the loss 
            optimizer.step()        # adjust parameters based on the calculated gradients 
            running_train_loss +=train_loss.item()  # track the loss value 
 
        # Calculate training loss value 
        train_loss_value = running_train_loss/len(train_loader) 
 
        # Validation Loop 
        with torch.no_grad(): 
            model.eval() 
            for data in validate_loader: 
               inputs, outputs = data 
               predicted_outputs = model(inputs) 
               val_loss = loss_fn(predicted_outputs, outputs) 
             
               # The label with the highest value will be our prediction 
               _, predicted = torch.max(predicted_outputs, 1) 
               running_vall_loss += val_loss.item()  
               total += outputs.size(0) 
               running_accuracy += (predicted == outputs).sum().item() 
 
        # Calculate validation loss value 
        val_loss_value = running_vall_loss/len(validate_loader) 
                
        # Calculate accuracy as the number of correct predictions in the validation batch divided by the total number of predictions done.  
        accuracy = (100 * running_accuracy / total)     
 
        # Save the model if the accuracy is the best 
        if accuracy > best_accuracy: 
            saveModel() 
            best_accuracy = accuracy 
         
        # Print the statistics of the epoch 
        print('Completed training batch', epoch, 'Training Loss is: %.4f' %train_loss_value, 'Validation Loss is: %.4f' %val_loss_value, 'Accuracy is %d %%' % (accuracy))

Teste o modelo com base nos dados de teste.

Agora que você já fez o treinamento, teste o modelo com o conjunto de dados de teste.

Adicione duas funções de teste. A primeira testa o modelo salvo na parte anterior com o conjunto de dados de teste de 45 itens e imprime a precisão do modelo. A segunda é uma função opcional para testar a confiança do modelo na previsão de cada uma das três espécies de íris, representada pela probabilidade de classificação bem-sucedida de cada espécie.

  1. Adicione o seguinte código ao arquivo DataClassifier.py.
# Function to test the model 
def test(): 
    # Load the model that we saved at the end of the training loop 
    model = Network(input_size, output_size) 
    path = "NetModel.pth" 
    model.load_state_dict(torch.load(path)) 
     
    running_accuracy = 0 
    total = 0 
 
    with torch.no_grad(): 
        for data in test_loader: 
            inputs, outputs = data 
            outputs = outputs.to(torch.float32) 
            predicted_outputs = model(inputs) 
            _, predicted = torch.max(predicted_outputs, 1) 
            total += outputs.size(0) 
            running_accuracy += (predicted == outputs).sum().item() 
 
        print('Accuracy of the model based on the test set of', test_split ,'inputs is: %d %%' % (100 * running_accuracy / total))    
 
 
# Optional: Function to test which species were easier to predict  
def test_species(): 
    # Load the model that we saved at the end of the training loop 
    model = Network(input_size, output_size) 
    path = "NetModel.pth" 
    model.load_state_dict(torch.load(path)) 
     
    labels_length = len(labels) # how many labels of Irises we have. = 3 in our database. 
    labels_correct = list(0. for i in range(labels_length)) # list to calculate correct labels [how many correct setosa, how many correct versicolor, how many correct virginica] 
    labels_total = list(0. for i in range(labels_length))   # list to keep the total # of labels per type [total setosa, total versicolor, total virginica] 
  
    with torch.no_grad(): 
        for data in test_loader: 
            inputs, outputs = data 
            predicted_outputs = model(inputs) 
            _, predicted = torch.max(predicted_outputs, 1) 
             
            label_correct_running = (predicted == outputs).squeeze() 
            label = outputs[0] 
            if label_correct_running.item():  
                labels_correct[label] += 1 
            labels_total[label] += 1  
  
    label_list = list(labels.keys()) 
    for i in range(output_size): 
        print('Accuracy to predict %5s : %2d %%' % (label_list[i], 100 * labels_correct[i] / labels_total[i])) 

Por fim, adicione o código principal. Isso inicia o treinamento do modelo, salva o modelo e exibe os resultados na tela. Executaremos apenas duas iterações [num_epochs = 25] no conjunto de treinamento, assim o processo de treinamento não levará muito tempo.

  1. Adicione o seguinte código ao arquivo DataClassifier.py.
if __name__ == "__main__": 
    num_epochs = 10
    train(num_epochs) 
    print('Finished Training\n') 
    test() 
    test_species() 

Vamos executar o teste! Verifique se os menus suspensos na barra de ferramentas superior estão definidos como Debug. Altere Solution Platform para x64 para executar o projeto no computador local se o dispositivo for de 64 bits, ou x86 se ele for de 32 bits.

  1. Para executar o projeto, clique no botão Start Debugging na barra de ferramentas ou pressione F5.

Isso abre a janela do console, em que é possível ver o processo de treinamento. Como você definiu, o valor de perda será impresso a cada época. A expectativa é que o valor de perda diminua a cada loop.

Depois que o treinamento terminar, você deverá ver uma saída semelhante à abaixo. Seus números não serão exatamente os mesmos, pois o treinamento depende de muitos fatores e nem sempre retornará resultados idênticos, mas eles devem ser semelhantes.

Output from initial model training

Próximas etapas

Agora que você tem um modelo de classificação, a próxima etapa é converter o modelo para o formato ONNX.