Training a simple Neural Network#
This tutorial introduces the basics of learning with the framework Aidge.
What you will learn: 1. creating a model using Aidge API 2. create and import a dataset 3. train a model
The folowinfg modules will be required:
[1]:
!pip install torchvision==0.14.1+cpu --extra-index-url https://download.pytorch.org/whl/cpu
!pip install numpy==1.24.1
Looking in indexes: https://pypi.org/simple, https://download.pytorch.org/whl/cpu
Collecting torchvision==0.14.1+cpu
Downloading https://download.pytorch.org/whl/cpu/torchvision-0.14.1%2Bcpu-cp310-cp310-linux_x86_64.whl (16.8 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 16.8/16.8 MB 77.7 MB/s eta 0:00:00
Requirement already satisfied: typing-extensions in /builds/eclipse/aidge/aidge/venv/lib/python3.10/site-packages (from torchvision==0.14.1+cpu) (4.12.2)
Requirement already satisfied: numpy in /builds/eclipse/aidge/aidge/venv/lib/python3.10/site-packages (from torchvision==0.14.1+cpu) (2.1.0)
Requirement already satisfied: requests in /builds/eclipse/aidge/aidge/venv/lib/python3.10/site-packages (from torchvision==0.14.1+cpu) (2.32.3)
Collecting torch==1.13.1 (from torchvision==0.14.1+cpu)
Downloading https://download.pytorch.org/whl/cpu/torch-1.13.1%2Bcpu-cp310-cp310-linux_x86_64.whl (199.1 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 199.1/199.1 MB 5.7 MB/s eta 0:00:00
Requirement already satisfied: pillow!=8.3.*,>=5.3.0 in /builds/eclipse/aidge/aidge/venv/lib/python3.10/site-packages (from torchvision==0.14.1+cpu) (10.4.0)
Requirement already satisfied: charset-normalizer<4,>=2 in /builds/eclipse/aidge/aidge/venv/lib/python3.10/site-packages (from requests->torchvision==0.14.1+cpu) (3.3.2)
Requirement already satisfied: idna<4,>=2.5 in /builds/eclipse/aidge/aidge/venv/lib/python3.10/site-packages (from requests->torchvision==0.14.1+cpu) (3.8)
Requirement already satisfied: urllib3<3,>=1.21.1 in /builds/eclipse/aidge/aidge/venv/lib/python3.10/site-packages (from requests->torchvision==0.14.1+cpu) (2.2.2)
Requirement already satisfied: certifi>=2017.4.17 in /builds/eclipse/aidge/aidge/venv/lib/python3.10/site-packages (from requests->torchvision==0.14.1+cpu) (2024.7.4)
Installing collected packages: torch, torchvision
Successfully installed torch-1.13.1+cpu torchvision-0.14.1+cpu
[notice] A new release of pip is available: 24.1 -> 24.2
[notice] To update, run: pip install --upgrade pip
Collecting numpy==1.24.1
Downloading numpy-1.24.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (5.6 kB)
Downloading numpy-1.24.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (17.3 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 17.3/17.3 MB 76.6 MB/s eta 0:00:00
Installing collected packages: numpy
Attempting uninstall: numpy
Found existing installation: numpy 2.1.0
Uninstalling numpy-2.1.0:
Successfully uninstalled numpy-2.1.0
Successfully installed numpy-1.24.1
[notice] A new release of pip is available: 24.1 -> 24.2
[notice] To update, run: pip install --upgrade pip
[2]:
import aidge_core
import aidge_backend_cpu
import aidge_learning
import numpy as np
# required to load CIFAR10 dataset
import torchvision
import torchvision.transforms as transforms
Creating Aidge model#
In this example, we will create a simple perceptron model. For this we will use the helper function sequential
which will connect the nodes in a sequential manner and will return the reuslting GraphView
.
[3]:
model = aidge_core.sequential([
aidge_core.FC(in_channels=32*32*3, out_channels=512),
aidge_core.ReLU(),
aidge_core.FC(in_channels=512, out_channels=256),
aidge_core.ReLU(),
aidge_core.FC(in_channels=256, out_channels=128),
aidge_core.ReLU(),
aidge_core.FC(in_channels=128, out_channels=10),
])
Once the model is created, we can set its backend, datatype and initialize the values of the parameters.
We will initialize FC
weights with the He filler and set all biases to 0.01
.
[4]:
# Set backend and datatype
model.set_backend("cpu")
model.set_datatype(aidge_core.dtype.float32)
# Initialize parameters (weights and biases)
for node in model.get_nodes():
if node.type() == "Producer":
prod_op = node.get_operator()
value = prod_op.get_output(0)
tuple_out = node.output(0)[0]
# No conv in current network
if tuple_out[0].type() == "Conv" and tuple_out[1]==1:
# Conv weight
aidge_core.xavier_uniform_filler(value)
elif tuple_out[0].type() == "Conv" and tuple_out[1]==2:
# Conv bias
aidge_core.constant_filler(value, 0.01)
elif tuple_out[0].type() == "FC" and tuple_out[1]==1:
# FC weight
aidge_core.he_filler(value)
elif tuple_out[0].type() == "FC" and tuple_out[1]==2:
# FC bias
aidge_core.constant_filler(value, 0.01)
else:
pass
Note: We could have initialized producers using graph matching.
Aidge database#
Now that the model is ready we need to prepare a database. For this we will use the possiiblity to create a custom database using aidge_core.Database
.
We will use the framework PyTorch to load CIFAR10 and then write a custom database to transform the tensors to one hot encoded Aidge tensor.
[5]:
def one_hot_encoding(cls, nb_cls):
values = [float(0.0)] * nb_cls
values[cls] = float(1.0)
t = aidge_core.Tensor(values)
t.set_datatype(aidge_core.dtype.float32)
return t
class aidge_cifar10(aidge_core.Database):
def __init__(self):
aidge_core.Database.__init__(self)
transform = transforms.Compose(
[transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
self.trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
download=True, transform=transform)
def get_item(self, idx):
data, label = self.trainset.__getitem__(idx)
return [aidge_core.Tensor(data.numpy()),
one_hot_encoding(label, 10)]
def len(self):
return len(self.trainset)
def get_nb_modalities(self):
return 2
Using this, we can now create a dataprovider that we will use to send data to the network.
[6]:
aidge_database = aidge_cifar10()
BATCH_SIZE = 64
aidge_dataprovider = aidge_core.DataProvider(aidge_database,
batch_size=BATCH_SIZE,
shuffle=True,
drop_last=True)
Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to ./data/cifar-10-python.tar.gz
100.0%
Extracting ./data/cifar-10-python.tar.gz to ./data
Set up learning objects#
We now have all the basic elements required to run the leanring. We just need to setup the object specific to the learning and we will be able to write our first training loop !
For propagation and backpropagation, Aidge use scheduler obejct, we will use the SequentialScheduler
.
[7]:
# Set object for learning
scheduler = aidge_core.SequentialScheduler(model)
To update weights, we will use an optimizer, in this case SGD.
[8]:
# setup optimizer
opt = aidge_learning.SGD()
learning_rates = aidge_learning.constant_lr(0.01)
opt.set_learning_rate_scheduler(learning_rates)
opt.set_parameters(list(aidge_core.producers(model)))
Training loop#
[9]:
tot_acc = 0
for i, (input, label) in enumerate(aidge_dataprovider):
# input.init_grad()
scheduler.forward(data=[input])
# Really long line should be a faster way ...
pred = list(model.get_output_nodes())[0].get_operator().get_output(0)
opt.reset_grad()
loss = aidge_learning.loss.MSE(pred, label)
acc = np.sum(np.argmax(pred, axis=1) == np.argmax(label, axis=1))
tot_acc += acc
scheduler.backward()
opt.update()
print(f"Nb samples {(i+1)*BATCH_SIZE}, loss: {loss[0]}, acc:{(acc/BATCH_SIZE)*100}%, tot_acc:{(tot_acc/((i+1)*BATCH_SIZE))*100}%")
# Break point
if i == 5:
break
Nb samples 64, loss: 0.9453436732292175, acc:9.375%, tot_acc:9.375%
Nb samples 128, loss: 0.749517560005188, acc:9.375%, tot_acc:9.375%
Nb samples 192, loss: 0.4656025469303131, acc:7.8125%, tot_acc:8.854166666666668%
Nb samples 256, loss: 0.25375890731811523, acc:10.9375%, tot_acc:9.375%
Nb samples 320, loss: 0.1999601274728775, acc:7.8125%, tot_acc:9.0625%
Nb samples 384, loss: 0.16076548397541046, acc:15.625%, tot_acc:10.15625%