The field of machine learning changes continuously. There are new algorithms and library updates every few weeks. I have a set of standard examples I run every now and then to make sure that no breaking changes have occurred in PyTorch. One of my machines was upgraded from Windows 10 to Windows 11, and PyTorch 1.10.x had been released, so I figured I’d better run my Iris Dataset example.
Note: code slighlty updated on 04/22/2022
The goal of the Iris problem is to predict the species of an iris flower (setosa = 0, versicolor = 1, virginica = 2) from sepal length and width, and petal length and width. A sepal is a leaf-like structure.
My demo worked as expected. The PyTorch code is very dense, meaning there are a lot of alternatives for each block of statements. For example, I use uniform_(-0.01, +0.01) weight initialization. There are many alternatives including normal_(), xavier_uniform_(), and kaiming_uniform_(). I use log_softmax() activation with NLLLoss() loss. An equivalent design is no activation (sometimes called identity activation) with CrossEntropyLoss(). And so on, and so on, and so on.
# iris_nn.py
# PyTorch 1.10.0-CPU Anaconda3-2020.02 Python 3.7.6
# Windows 10/11
import numpy as np
import torch as T
device = T.device('cpu') # apply to Tensor or Module
# -----------------------------------------------------------
class IrisDataset(T.utils.data.Dataset):
def __init__(self, src_file, num_rows=None):
# 5.0, 3.5, 1.3, 0.3, 0
tmp_x = np.loadtxt(src_file, max_rows=num_rows,
usecols=range(0,4), delimiter=",", comments="#",
dtype=np.float32)
tmp_y = np.loadtxt(src_file, max_rows=num_rows,
usecols=4, delimiter=",", comments="#",
dtype=np.int64)
self.x_data = T.tensor(tmp_x, dtype=T.float32).to(device)
self.y_data = T.tensor(tmp_y, dtype=T.int64).to(device)
def __len__(self):
return len(self.x_data)
def __getitem__(self, idx):
preds = self.x_data[idx]
spcs = self.y_data[idx]
sample = { 'predictors' : preds, 'species' : spcs }
return sample # as Dictionary
# -----------------------------------------------------------
class Net(T.nn.Module):
def __init__(self):
super(Net, self).__init__() # Python 3.2 and earlier
# super().__init__() # shortcut syntax 3.3 and later
self.hid1 = T.nn.Linear(4, 7) # 4-7-3
self.oupt = T.nn.Linear(7, 3)
lo = -0.10; hi = +0.10
T.nn.init.uniform_(self.hid1.weight, lo, hi)
T.nn.init.zeros_(self.hid1.bias)
T.nn.init.uniform_(self.oupt.weight, lo, hi)
T.nn.init.zeros_(self.oupt.bias)
def forward(self, x):
z = T.tanh(self.hid1(x))
z = T.log_softmax(self.oupt(z), dim=1) # NLLLoss()
return z
# -----------------------------------------------------------
def accuracy(model, dataset):
# assumes model.eval()
dataldr = T.utils.data.DataLoader(dataset, batch_size=1,
shuffle=False)
n_correct = 0; n_wrong = 0
for (_, batch) in enumerate(dataldr):
X = batch['predictors']
Y = batch['species'] # already 1D shaped by Dataset
with T.no_grad():
oupt = model(X) # logits form
big_idx = T.argmax(oupt)
# if big_idx.item() == Y.item():
if big_idx == Y:
n_correct += 1
else:
n_wrong += 1
acc = (n_correct * 1.0) / (n_correct + n_wrong)
return acc
# -----------------------------------------------------------
def main():
# 0. get started
print("\nBegin Iris dataset using PyTorch demo ")
T.manual_seed(1)
np.random.seed(1)
# 1. create DataLoader objects
print("\nCreating Iris train and test Datasets ")
train_file = ".\\Data\\iris_train.txt"
test_file = ".\\Data\\iris_test.txt"
train_ds = IrisDataset(train_file) # 120 items
test_ds = IrisDataset(test_file) # 30
bat_size = 4
train_ldr = T.utils.data.DataLoader(train_ds,
batch_size=bat_size, shuffle=True)
# -----------------------------------------------------------
# 2. create network
print("\nCreating 4-7-3 neural network ")
net = Net().to(device)
# 3. train model
max_epochs = 50
ep_log_interval = 10
lrn_rate = 0.01
loss_func = T.nn.NLLLoss() # assumes log_softmax()
optimizer = T.optim.SGD(net.parameters(), lr=lrn_rate)
print("\nbat_size = %3d " % bat_size)
print("loss = " + str(loss_func))
print("optimizer = SGD")
print("max_epochs = %3d " % max_epochs)
print("lrn_rate = %0.3f " % lrn_rate)
print("\nStarting training")
net.train()
for epoch in range(0, max_epochs):
epoch_loss = 0 # for one full epoch
for (batch_idx, batch) in enumerate(train_ldr):
X = batch['predictors'] # [10,4]
Y = batch['species'] # OK; alreay flattened
optimizer.zero_grad()
oupt = net(X)
loss_val = loss_func(oupt, Y) # a tensor
epoch_loss += loss_val.item() # accumulate
loss_val.backward() # compute gradients
optimizer.step() # update weights and biases
if epoch % ep_log_interval == 0:
print("epoch = %4d | loss = %8.4f | " % \
(epoch, epoch_loss), end="")
net.eval()
train_acc = accuracy(net, train_ds)
print(" acc = %8.4f " % train_acc)
net.train()
print("Done ")
# -----------------------------------------------------------
# 4. evaluate model accuracy
print("\nComputing model accuracy")
net.eval()
acc = accuracy(net, test_ds) # item-by-item
print("Accuracy on test data = %0.4f" % acc)
# -----------------------------------------------------------
# 4b. inspect model
# print("\nTrained model weights and biases: ")
# print(net.hid1.weight)
# print(net.hid1.bias)
# print(net.oupt.weight)
# print(net.oupt.bias)
# -----------------------------------------------------------
# 5. make a prediction
print("\nPredicting species for [6.1, 3.1, 5.1, 1.1]: ")
x = np.array([[6.1, 3.1, 5.1, 1.1]], dtype=np.float32)
x = T.tensor(x, dtype=T.float32).to(device)
with T.no_grad():
logits = net(x) # as log_softmax
probs = T.exp(logits) # pseudo-probs
T.set_printoptions(precision=4)
print(probs)
# -----------------------------------------------------------
# 6. save model (state_dict approach)
print("\nSaving trained model state")
fn = ".\\Models\\iris_model.pt"
# T.save(net.state_dict(), fn)
# saved_model = Net()
# saved_model.load_state_dict(T.load(fn))
# use saved_model to make prediction(s)
print("\nEnd Iris demo")
if __name__ == "__main__":
main()
Training data:
# iris_train.txt # # https://archive.ics.uci.edu/ml/datasets/iris # sepal len, sepal wid, petal len, petal wid, species # 0 = setosa, 1 = versicolor, 2 = virginica # 5.1, 3.5, 1.4, 0.2, 0 4.9, 3.0, 1.4, 0.2, 0 4.7, 3.2, 1.3, 0.2, 0 4.6, 3.1, 1.5, 0.2, 0 5.0, 3.6, 1.4, 0.2, 0 5.4, 3.9, 1.7, 0.4, 0 4.6, 3.4, 1.4, 0.3, 0 5.0, 3.4, 1.5, 0.2, 0 4.4, 2.9, 1.4, 0.2, 0 4.9, 3.1, 1.5, 0.1, 0 5.4, 3.7, 1.5, 0.2, 0 4.8, 3.4, 1.6, 0.2, 0 4.8, 3.0, 1.4, 0.1, 0 4.3, 3.0, 1.1, 0.1, 0 5.8, 4.0, 1.2, 0.2, 0 5.7, 4.4, 1.5, 0.4, 0 5.4, 3.9, 1.3, 0.4, 0 5.1, 3.5, 1.4, 0.3, 0 5.7, 3.8, 1.7, 0.3, 0 5.1, 3.8, 1.5, 0.3, 0 5.4, 3.4, 1.7, 0.2, 0 5.1, 3.7, 1.5, 0.4, 0 4.6, 3.6, 1.0, 0.2, 0 5.1, 3.3, 1.7, 0.5, 0 4.8, 3.4, 1.9, 0.2, 0 5.0, 3.0, 1.6, 0.2, 0 5.0, 3.4, 1.6, 0.4, 0 5.2, 3.5, 1.5, 0.2, 0 5.2, 3.4, 1.4, 0.2, 0 4.7, 3.2, 1.6, 0.2, 0 4.8, 3.1, 1.6, 0.2, 0 5.4, 3.4, 1.5, 0.4, 0 5.2, 4.1, 1.5, 0.1, 0 5.5, 4.2, 1.4, 0.2, 0 4.9, 3.1, 1.5, 0.1, 0 5.0, 3.2, 1.2, 0.2, 0 5.5, 3.5, 1.3, 0.2, 0 4.9, 3.1, 1.5, 0.1, 0 4.4, 3.0, 1.3, 0.2, 0 5.1, 3.4, 1.5, 0.2, 0 7.0, 3.2, 4.7, 1.4, 1 6.4, 3.2, 4.5, 1.5, 1 6.9, 3.1, 4.9, 1.5, 1 5.5, 2.3, 4.0, 1.3, 1 6.5, 2.8, 4.6, 1.5, 1 5.7, 2.8, 4.5, 1.3, 1 6.3, 3.3, 4.7, 1.6, 1 4.9, 2.4, 3.3, 1.0, 1 6.6, 2.9, 4.6, 1.3, 1 5.2, 2.7, 3.9, 1.4, 1 5.0, 2.0, 3.5, 1.0, 1 5.9, 3.0, 4.2, 1.5, 1 6.0, 2.2, 4.0, 1.0, 1 6.1, 2.9, 4.7, 1.4, 1 5.6, 2.9, 3.6, 1.3, 1 6.7, 3.1, 4.4, 1.4, 1 5.6, 3.0, 4.5, 1.5, 1 5.8, 2.7, 4.1, 1.0, 1 6.2, 2.2, 4.5, 1.5, 1 5.6, 2.5, 3.9, 1.1, 1 5.9, 3.2, 4.8, 1.8, 1 6.1, 2.8, 4.0, 1.3, 1 6.3, 2.5, 4.9, 1.5, 1 6.1, 2.8, 4.7, 1.2, 1 6.4, 2.9, 4.3, 1.3, 1 6.6, 3.0, 4.4, 1.4, 1 6.8, 2.8, 4.8, 1.4, 1 6.7, 3.0, 5.0, 1.7, 1 6.0, 2.9, 4.5, 1.5, 1 5.7, 2.6, 3.5, 1.0, 1 5.5, 2.4, 3.8, 1.1, 1 5.5, 2.4, 3.7, 1.0, 1 5.8, 2.7, 3.9, 1.2, 1 6.0, 2.7, 5.1, 1.6, 1 5.4, 3.0, 4.5, 1.5, 1 6.0, 3.4, 4.5, 1.6, 1 6.7, 3.1, 4.7, 1.5, 1 6.3, 2.3, 4.4, 1.3, 1 5.6, 3.0, 4.1, 1.3, 1 5.5, 2.5, 4.0, 1.3, 1 6.3, 3.3, 6.0, 2.5, 2 5.8, 2.7, 5.1, 1.9, 2 7.1, 3.0, 5.9, 2.1, 2 6.3, 2.9, 5.6, 1.8, 2 6.5, 3.0, 5.8, 2.2, 2 7.6, 3.0, 6.6, 2.1, 2 4.9, 2.5, 4.5, 1.7, 2 7.3, 2.9, 6.3, 1.8, 2 6.7, 2.5, 5.8, 1.8, 2 7.2, 3.6, 6.1, 2.5, 2 6.5, 3.2, 5.1, 2.0, 2 6.4, 2.7, 5.3, 1.9, 2 6.8, 3.0, 5.5, 2.1, 2 5.7, 2.5, 5.0, 2.0, 2 5.8, 2.8, 5.1, 2.4, 2 6.4, 3.2, 5.3, 2.3, 2 6.5, 3.0, 5.5, 1.8, 2 7.7, 3.8, 6.7, 2.2, 2 7.7, 2.6, 6.9, 2.3, 2 6.0, 2.2, 5.0, 1.5, 2 6.9, 3.2, 5.7, 2.3, 2 5.6, 2.8, 4.9, 2.0, 2 7.7, 2.8, 6.7, 2.0, 2 6.3, 2.7, 4.9, 1.8, 2 6.7, 3.3, 5.7, 2.1, 2 7.2, 3.2, 6.0, 1.8, 2 6.2, 2.8, 4.8, 1.8, 2 6.1, 3.0, 4.9, 1.8, 2 6.4, 2.8, 5.6, 2.1, 2 7.2, 3.0, 5.8, 1.6, 2 7.4, 2.8, 6.1, 1.9, 2 7.9, 3.8, 6.4, 2.0, 2 6.4, 2.8, 5.6, 2.2, 2 6.3, 2.8, 5.1, 1.5, 2 6.1, 2.6, 5.6, 1.4, 2 7.7, 3.0, 6.1, 2.3, 2 6.3, 3.4, 5.6, 2.4, 2 6.4, 3.1, 5.5, 1.8, 2 6.0, 3.0, 4.8, 1.8, 2 6.9, 3.1, 5.4, 2.1, 2
Test data:
# iris_test.txt # # https://archive.ics.uci.edu/ml/datasets/iris # sepal len, sepal wid, petal len, petal wid, species # 0 = setosa, 1 = versicolor, 2 = virginica # 5.0, 3.5, 1.3, 0.3, 0 4.5, 2.3, 1.3, 0.3, 0 4.4, 3.2, 1.3, 0.2, 0 5.0, 3.5, 1.6, 0.6, 0 5.1, 3.8, 1.9, 0.4, 0 4.8, 3.0, 1.4, 0.3, 0 5.1, 3.8, 1.6, 0.2, 0 4.6, 3.2, 1.4, 0.2, 0 5.3, 3.7, 1.5, 0.2, 0 5.0, 3.3, 1.4, 0.2, 0 5.5, 2.6, 4.4, 1.2, 1 6.1, 3.0, 4.6, 1.4, 1 5.8, 2.6, 4.0, 1.2, 1 5.0, 2.3, 3.3, 1.0, 1 5.6, 2.7, 4.2, 1.3, 1 5.7, 3.0, 4.2, 1.2, 1 5.7, 2.9, 4.2, 1.3, 1 6.2, 2.9, 4.3, 1.3, 1 5.1, 2.5, 3.0, 1.1, 1 5.7, 2.8, 4.1, 1.3, 1 6.7, 3.1, 5.6, 2.4, 2 6.9, 3.1, 5.1, 2.3, 2 5.8, 2.7, 5.1, 1.9, 2 6.8, 3.2, 5.9, 2.3, 2 6.7, 3.3, 5.7, 2.5, 2 6.7, 3.0, 5.2, 2.3, 2 6.3, 2.5, 5.0, 1.9, 2 6.5, 3.0, 5.2, 2.0, 2 6.2, 3.4, 5.4, 2.3, 2 5.9, 3.0, 5.1, 1.8, 2

.NET Test Automation Recipes
Software Testing
SciPy Programming Succinctly
Keras Succinctly
R Programming
2026 Visual Studio Live
2025 Summer MLADS Conference
2026 DevIntersection Conference
2025 Machine Learning Week
2025 Ai4 Conference
2026 G2E Conference
2026 iSC West Conference
Pingback: The Iris Dataset Example with Keras 2.8 on Windows 11 | James D. McCaffrey