# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# +
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
# %matplotlib inline

from torch.autograd import Variable

from data import iris
# -

# ### simple classification dataset
#
# ![iris](data/iris.jpg)
#
# The **Iris** flower.
#
#
# | sepal_length_cm | sepal_width_cm | petal_length_cm | petal_width_cm | class           |
# |-----------------|----------------|-----------------|----------------|-----------------|
# | 5.1             | 3.5            | 1.4             | 0.2            | Iris-setosa     |
# | 7.0             | 3.2            | 4.7             | 1.4            | Iris-versicolor |
# | 6.3             | 3.3            | 6.0             | 2.5            | Iris-virginica  |
#
#
# * Total instances: 150 (we have separated 20% into validation set, the rest forms the training set)

# !head data/iris.data.txt



# ### Model: Fully Connected Feed-Forward Neural Network

class IrisNet(nn.Module):
    
    def __init__(self, input_size, hidden1_size, hidden2_size, num_classes):
        
        super(IrisNet, self).__init__()
        self.fc1 = nn.Linear(input_size, hidden1_size)
        self.relu1 = nn.ReLU()
        self.fc2 = nn.Linear(hidden1_size, hidden2_size)
        self.relu2 = nn.ReLU()
        self.fc3 = nn.Linear(hidden2_size, num_classes)  
    
    def forward(self, x):
        
        out = self.fc1(x)
        out = self.relu1(out)
        out = self.fc2(out)
        out = self.relu2(out)
        out = self.fc3(out)
        return out


# ### Data Loader

batch_size = 60
iris_data_file = 'data/iris.data.txt'

# +
train_ds, test_ds = iris.get_datasets(iris_data_file)

print('# instances in training set: ', len(train_ds))
print('# instances in testing/validation set: ', len(test_ds))

train_loader = torch.utils.data.DataLoader(dataset=train_ds, batch_size=batch_size, shuffle=True)
test_loader  = torch.utils.data.DataLoader(dataset=test_ds, batch_size=batch_size, shuffle=True)
# -

# ### Initialization

model = IrisNet(4, 100, 50, 3)
print(model)

# +
criterion = nn.CrossEntropyLoss()

learning_rate = 0.001
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate, nesterov=True, momentum=0.9, dampening=0) 
# -

# ### Training

# +
num_epochs = 500

train_loss = []
test_loss = []
train_accuracy = []
test_accuracy = []

for epoch in range(num_epochs):
    
    train_correct = 0
    train_total = 0
    
    for i, (items, classes) in enumerate(train_loader):
        
        # tensor to variable conversion
        items = Variable(items)
        classes = Variable(classes)
        
        model.train()           # begin training
        
        optimizer.zero_grad() # zero out gradients
        outputs = model(items)  # forward pass
        loss = criterion(outputs, classes) # get loss
        loss.backward()       # update gradients (backprop)
        optimizer.step()      # update parameters based on gradients
        
        # record predictions
        train_total += classes.size(0)    
        _, predicted = torch.max(outputs.data, 1)
        train_correct += (predicted == classes.data).sum()

        print ('Epoch %d/%d, Iteration %d/%d, Loss: %.4f' 
               %(epoch+1, num_epochs, i+1, len(train_ds)//batch_size, loss.data[0]))

    model.eval()                 # begin evaluation
    
    # save loss
    train_loss.append(loss.data[0])

    # calculate accuracy
    train_accuracy.append((100 * train_correct / train_total))
    
    # test set score
    # save predictions on test set
    test_items = torch.FloatTensor(test_ds.data.values[:, 0:4])
    test_classes = torch.LongTensor(test_ds.data.values[:, 4])

    outputs = model(Variable(test_items))
    loss = criterion(outputs, Variable(test_classes))
    test_loss.append(loss.data[0])
    _, predicted = torch.max(outputs.data, 1)
    total = test_classes.size(0)
    correct = (predicted == test_classes).sum()
    test_accuracy.append((100 * correct / total))
# -

# ### Evaluate Results

fig = plt.figure(figsize=(12, 8))
plt.plot(train_loss, label='train loss')
plt.plot(test_loss, label='test loss')
plt.title("Train and Test Loss")
plt.legend()
plt.show()

fig = plt.figure(figsize=(12, 8))
plt.plot(train_accuracy, label='train accuracy')
plt.plot(test_accuracy, label='test accuracy')
plt.title("Train and Test Accuracy")
plt.legend()
plt.show()

# ### Save the Trained Model

torch.save(model.state_dict(), "./irisnet.model")

loaded_model = IrisNet(4, 100, 50, 3)
loaded_model.load_state_dict(torch.load("./irisnet.model"))

output = loaded_model(Variable(torch.FloatTensor([[5.1, 3.5, 1.4, 0.2]])))

_, predicted_class = torch.max(output.data, 1)
print('Predicted class: ', predicted_class.numpy()[0])
print('Expected class: ', 0 )



StarcoderdataJupyterScriptsDedupFiltered