Multi-class classification using simple deep learning structure in Pytorch with iris dataset


As one can see from the following example, it is very easy to apply deep learning structure in Pytorch
to perform multi-class classificatoin task. The valuation performance of this iris dataset is almost perfect.

import torch.nn as nn
import torch
#import matplotlib.pyplot as plt
import pandas as pd

from sklearn.datasets import load_iris
import numpy as np
torch.manual_seed(1121)
<torch._C.Generator at 0x19734b24a70>

load iris dataset for training and valuation

iris = load_iris()
X = iris.data
Y = iris.target
X=pd.DataFrame(X)
Y=pd.DataFrame(Y)
display(X)
display(Y)

0 1 2 3
0 5.1 3.5 1.4 0.2
1 4.9 3.0 1.4 0.2
2 4.7 3.2 1.3 0.2
3 4.6 3.1 1.5 0.2
4 5.0 3.6 1.4 0.2
... ... ... ... ...
145 6.7 3.0 5.2 2.3
146 6.3 2.5 5.0 1.9
147 6.5 3.0 5.2 2.0
148 6.2 3.4 5.4 2.3
149 5.9 3.0 5.1 1.8

150 rows × 4 columns

0
0 0
1 0
2 0
3 0
4 0
... ...
145 2
146 2
147 2
148 2
149 2

150 rows × 1 columns

train and valuation dataset split

X=X.values
Y=Y.values

from sklearn.model_selection import train_test_split
x, x_val, y, y_val = train_test_split(X, Y, test_size=0.33, random_state=42)
x.shape, y.shape, x_val.shape, y_val.shape
((100, 4), (100, 1), (50, 4), (50, 1))

notice that: y needs to be one dimension indicating the class type, not encoded vectors

x_train = x.reshape(-1, x.shape[1]).astype('float32')
y_train = y.reshape(-1)

x_val = x_val.reshape(-1, x_val.shape[1]).astype('float32')
y_val = y_val.reshape(-1)




put data into dataloader, so we could train by batches easily

from torch.utils.data import Dataset, DataLoader
class Data(Dataset):
def __init__(self):
self.x=torch.from_numpy(x_train)
self.y=torch.from_numpy(y_train).long()
self.len=self.x.shape[0]
def __getitem__(self,index):
return self.x[index], self.y[index]
def __len__(self):
return self.len
data_set=Data()

# define batch sizes here
batch_size = 16
trainloader=DataLoader(dataset=data_set,batch_size=batch_size)

build softmax classifier

# D_in, dimension of input layer
# H , dimension of hidden layer
# D_out, dimension of output layer
class Net(nn.Module):
def __init__(self,D_in,H,D_out):
super(Net,self).__init__()
self.linear1=nn.Linear(D_in,H)
self.linear2=nn.Linear(H,D_out)


def forward(self,x):
x=torch.sigmoid(self.linear1(x))
x=self.linear2(x)
return x


input_dim=4     # how many features are in the dataset or how many input nodes in the input layer
hidden_dim = 20 # hidden layer size
output_dim=3 # number of classes
print(input_dim,hidden_dim,output_dim)


# Instantiate model
model=Net(input_dim,hidden_dim,output_dim)

print('W:',list(model.parameters())[0].size())
print('b',list(model.parameters())[1].size())


# loss function
criterion=nn.CrossEntropyLoss()

4 20 3
W: torch.Size([20, 4])
b torch.Size([20])

define the optimizer

learning_rate=0.05
optimizer=torch.optim.SGD(model.parameters(), lr=learning_rate)

n_epochs=1000
loss_list=[]

#n_epochs
for epoch in range(n_epochs):
if epoch %100==0:
print(epoch)
for x, y in trainloader:


#clear gradient
optimizer.zero_grad()
#make a prediction
z=model(x)
#print(z)
# calculate loss, da Cross Entropy benutzt wird muss ich in den loss Klassen vorhersagen,
# also Wahrscheinlichkeit pro Klasse. Das mach torch.max(y,1)[1])
loss=criterion(z,y)
# calculate gradients of parameters
loss.backward()
# update parameters
optimizer.step()

loss_list.append(loss.data)


#print('epoch {}, loss {}'.format(epoch, loss.item()))
0
100
200
300
400
500
600
700
800
900

check performance using the valuation data

# predict the class and give probablity for each class label
x_val = torch.from_numpy(x_val)
z=model(x_val)
display(z)
tensor([[-3.1493e+00,  3.6905e+00, -5.0090e-01],
        [ 8.6639e+00,  2.5913e+00, -1.1538e+01],
        [-7.7513e+00,  4.1365e-01,  7.2997e+00],
        [-3.1786e+00,  3.3443e+00, -1.6125e-01],
        [-3.0974e+00,  3.8265e+00, -6.9203e-01],
        [ 8.4413e+00,  2.6384e+00, -1.1355e+01],
        [-1.4718e-02,  4.3311e+00, -4.3462e+00],
        [-5.4910e+00,  1.5831e+00,  3.8781e+00],
        [-4.7908e+00,  2.2980e+00,  2.5141e+00],
        [-1.2132e+00,  4.3453e+00, -3.1134e+00],
        [-5.0060e+00,  1.9947e+00,  2.9958e+00],
        [ 8.1200e+00,  2.7792e+00, -1.1151e+01],
        [ 8.8828e+00,  2.5214e+00, -1.1683e+01],
        [ 8.0960e+00,  2.7942e+00, -1.1141e+01],
        [ 8.8283e+00,  2.5107e+00, -1.1654e+01],
        [-2.5941e+00,  3.7417e+00, -1.1520e+00],
        [-7.0112e+00,  6.8188e-01,  6.2887e+00],
        [-1.7457e+00,  4.1789e+00, -2.4035e+00],
        [-3.3078e+00,  3.3204e+00,  6.4886e-03],
        [-7.0187e+00,  6.5605e-01,  6.3214e+00],
        [ 7.9682e+00,  2.8094e+00, -1.1046e+01],
        [-4.8998e+00,  2.0493e+00,  2.8430e+00],
        [ 8.2123e+00,  2.6980e+00, -1.1198e+01],
        [-6.9197e+00,  7.3409e-01,  6.1537e+00],
        [-5.4359e+00,  2.1912e+00,  3.2544e+00],
        [-6.1038e+00,  1.1452e+00,  4.9261e+00],
        [-6.9835e+00,  8.1716e-01,  6.1667e+00],
        [-6.8937e+00,  7.5489e-01,  6.1001e+00],
        [ 8.0317e+00,  2.7680e+00, -1.1061e+01],
        [ 7.8392e+00,  2.8607e+00, -1.0952e+01],
        [ 9.1619e+00,  2.3973e+00, -1.1890e+01],
        [ 9.2721e+00,  2.3691e+00, -1.1973e+01],
        [-1.2764e+00,  4.5603e+00, -3.2536e+00],
        [ 8.2595e+00,  2.7126e+00, -1.1257e+01],
        [ 8.4267e+00,  2.6317e+00, -1.1359e+01],
        [-6.1753e+00,  1.1836e+00,  4.9843e+00],
        [-1.8449e+00,  4.1870e+00, -2.3373e+00],
        [ 8.5922e+00,  2.6133e+00, -1.1488e+01],
        [ 8.7905e+00,  2.5362e+00, -1.1630e+01],
        [ 9.1236e+00,  2.4451e+00, -1.1888e+01],
        [-6.4186e+00,  9.5598e-01,  5.4381e+00],
        [-1.9872e+00,  3.8494e+00, -1.8866e+00],
        [-2.3989e+00,  4.0929e+00, -1.6734e+00],
        [ 9.1132e+00,  2.4113e+00, -1.1844e+01],
        [ 8.8116e+00,  2.5441e+00, -1.1646e+01],
        [-1.2458e+00,  4.3741e+00, -3.0913e+00],
        [-4.9320e+00,  2.3103e+00,  2.6452e+00],
        [-5.8854e+00,  1.5035e+00,  4.3829e+00],
        [-1.6208e+00,  4.4212e+00, -2.7724e+00],
        [-6.7249e+00,  8.5383e-01,  5.8288e+00]], grad_fn=<AddmmBackward>)
# choose the predicted class to be the one with maximum probablity
yhat=torch.max(z.data,1)
display(yhat)
torch.return_types.max(
values=tensor([3.6905, 8.6639, 7.2997, 3.3443, 3.8265, 8.4413, 4.3311, 3.8781, 2.5141,
        4.3453, 2.9958, 8.1200, 8.8828, 8.0960, 8.8283, 3.7417, 6.2887, 4.1789,
        3.3204, 6.3214, 7.9682, 2.8430, 8.2123, 6.1537, 3.2544, 4.9261, 6.1667,
        6.1001, 8.0317, 7.8392, 9.1619, 9.2721, 4.5603, 8.2595, 8.4267, 4.9843,
        4.1870, 8.5922, 8.7905, 9.1236, 5.4381, 3.8494, 4.0929, 9.1132, 8.8116,
        4.3741, 2.6452, 4.3829, 4.4212, 5.8288]),
indices=tensor([1, 0, 2, 1, 1, 0, 1, 2, 2, 1, 2, 0, 0, 0, 0, 1, 2, 1, 1, 2, 0, 2, 0, 2,
        2, 2, 2, 2, 0, 0, 0, 0, 1, 0, 0, 2, 1, 0, 0, 0, 2, 1, 1, 0, 0, 1, 2, 2,
        1, 2]))
# get the indicies
y_pred=yhat.indices.detach().numpy()
display(y_pred)
array([1, 0, 2, 1, 1, 0, 1, 2, 2, 1, 2, 0, 0, 0, 0, 1, 2, 1, 1, 2, 0, 2,
       0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 1, 0, 0, 2, 1, 0, 0, 0, 2, 1, 1, 0,
       0, 1, 2, 2, 1, 2], dtype=int64)
display(y_val)
array([1, 0, 2, 1, 1, 0, 1, 2, 1, 1, 2, 0, 0, 0, 0, 1, 2, 1, 1, 2, 0, 2,
       0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 1, 0, 0, 2, 1, 0, 0, 0, 2, 1, 1, 0,
       0, 1, 2, 2, 1, 2])

check the multi-class confusion matric

from sklearn.metrics import multilabel_confusion_matrix
display(multilabel_confusion_matrix(y_val, y_pred))
array([[[31,  0],
        [ 0, 19]],

       [[35,  0],
        [ 1, 14]],

       [[33,  1],
        [ 0, 16]]], dtype=int64)


Author: robot learner
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source robot learner !
  TOC