<jupyter_start><jupyter_text>Minimal PyTorch Example This notebooks shows a very minimal example on how to use PyTorch for training a neural network on the Iris data set.  0. Preamble<jupyter_code>import torch
import torch.nn.functional as F
import torch.nn as nn

torch.manual_seed(1)<jupyter_output><empty_output><jupyter_text>The following lines checks for GPU availability on the machine and sets the GPU as processing device (if available).If you are on Colab you can enable GPU support in the menu via  "Runtime > Change runtime type" and select "GPU" as hardware accelerator.<jupyter_code>if(torch.cuda.is_available()):
  processing_chip = "cuda:0"
  print(f"{torch.cuda.get_device_name(0)} available")
else:
  processing_chip = "cpu"
  print("No GPU available")

device = torch.device(processing_chip)
device<jupyter_output>No GPU available<jupyter_text>1. Data Preperation For this small example we use the [Iris flower data set](https://en.wikipedia.org/wiki/Iris_flower_data_set). The data set consists of 50 samples from each of three species of Iris (Iris setosa, Iris virginica and Iris versicolor). Four features were measured from each sample: the length and the width of the sepals and petals, in centimeters. Based on these four features, we want to train a model that can predict the species.In the first step we load the data into a Pandas.<jupyter_code>import pandas as pd

url = 'data/iris.csv'
dataset = pd.read_csv(url)
dataset.head(5)<jupyter_output><empty_output><jupyter_text>To be able to train a model, we first need to transform the *species* column into a numeric:<jupyter_code>dataset.loc[dataset.species=='Iris-setosa', 'species'] = 0
dataset.loc[dataset.species=='Iris-versicolor', 'species'] = 1
dataset.loc[dataset.species=='Iris-virginica', 'species'] = 2
dataset.head()<jupyter_output><empty_output><jupyter_text>Next, we specify which columns we want to use as features and which as label:<jupyter_code>X = dataset[dataset.columns[0:4]].values
y = dataset.species.values.astype(int)<jupyter_output><empty_output><jupyter_text>We then split our data into training and test data.<jupyter_code>from sklearn.model_selection import train_test_split

train_X, test_X, train_y, test_y = train_test_split(X, y, test_size=0.2)
print(train_X.shape, test_X.shape)<jupyter_output>(120, 4) (30, 4)<jupyter_text>To be able to use the data in PyTorch, we need to convert them into PyTorch tensors. Such a tensor can be thought of an efficient way to represent lists and matrices (similar to Numpy), with the additional benefit that they can be moved to the GPU (the `.to(device)` part in the code below) and that they support automatic backpropagation (more on this later):<jupyter_code>train_x = torch.Tensor(train_X).float().to(device)
test_x = torch.Tensor(test_X).float().to(device)
train_y =torch.Tensor(train_y).long().to(device)
test_y = torch.Tensor(test_y).long().to(device)<jupyter_output><empty_output><jupyter_text>2. Model definitionWe define now the strucutre of our neural network. For this we create a class that is a subclass from PyTorch's `nn.Module`.By convention we put in the `__init__` method the layers we want to use in the network and in the `forward` method how data flows through this network.Our network has 4 input features, 7 hidden layer nodes and 3 output neurons. The hidden layer uses a Relu activation function. Note that the output layer does not have a softmax activation (unlike we have seen it in the lecture). It rather gives out a raw score for each class (more on this later).<jupyter_code>class Net(nn.Module):
  def __init__(self):
    super(Net, self).__init__()
    self.hidden = nn.Linear(4, 7)  
    self.output = nn.Linear(7, 3)

  def forward(self, x):
    z1 = self.hidden(x)
    z2 = F.relu(z1)
    z3 = self.output(z2)  # no softmax. see CrossEntropyLoss() 
    return z3<jupyter_output><empty_output><jupyter_text>3. Model TrainingWe can now start training our network. We run several epochs in which we first predict on the training data with our network and than backpropagate the loss. For this we use PyTorch's build-in optimizer that runs gradient descent on the weights of the network. Hence, in every episode we reduce the loss on the training data and improve our network.As loss function we use cross entropy, which consumes the raw scores from the prediction and internally applies a softmax (that is why we do not need the softmax as last layer in the network).Note that all training data is passed at once to our network (line `net(train_x)`), since PyTorch will predict on all data points in parallel.<jupyter_code># create network, move it to device (either CPU or GPU)
net = Net().to(device)

# define the parameters for training
no_epochs = 100
learning_rate = 0.04
loss_func = nn.CrossEntropyLoss()  # applies softmax() internally
optimizer = torch.optim.SGD(net.parameters(), lr=learning_rate)

print("\nStarting training ")

train_losses = []
for epoch in range(0, no_epochs):

  optimizer.zero_grad()  # set gradients to zero 
  predictions = net(train_x)  # predict on the training data, this calls net.forward() 

  loss = loss_func(predictions, train_y)  # compute loss between prediction and true labels
  loss.backward() # calculate the gradients for every weight
  optimizer.step() # do one step of gradient descent

  train_losses.append(loss.item())
  
  if epoch % 10 == 0:
    print(f"Loss in epoch {epoch} is {loss.item()}")

print("Done training ")
import matplotlib.pyplot as plt

fig = plt.figure()
plt.plot(range(0, no_epochs), train_losses, color='blue')
plt.legend(['Train Loss'], loc='upper right')
plt.xlabel('number of epochs')
plt.ylabel('loss')<jupyter_output><empty_output><jupyter_text>4. Model EvaluationFinally, we check the model accuracy on the test data. For this we predict on the test data, identify the class with the highest score and compare it to the true label.<jupyter_code>predictions = net(test_x)
_, predicted = torch.max(predictions.data, 1) # get the class with highest score
correct = (predicted == test_y).sum().item() # compare predicted class with real class
print(f"Accuarcy is {100. * correct / len(test_x)}%")<jupyter_output>Accuarcy is 76.66666666666667%
{'fraction_non_alphanumeric': 0.09011768499113332, 'fraction_numerical': 0.0111236498468483, 'mean_word_length': 5.273003033367037, 'pattern_counts': {'":': 0, '<': 38, '<?xml version=': 0, '>': 39, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '364983', 'license': 'MIT', 'n_tokens_mistral': 1960, 'n_tokens_neox': 1872, 'n_words': 732, 'path': '4_PyTorch_Example.ipynb', 'repo_name': 'younishd/rl-course-ws21', 'size': '6203'}