Tutorial: Training a Network¶
This tutorial walks through the end-to-end training pipeline, from loading motion data to training a neural network and exporting it for inference.
Pipeline Overview¶
graph LR
A[Dataset] --> B[DataSampler]
B --> C[FeedTensor]
C --> D[Network]
D --> E[ReadTensor]
E --> F[Loss]
F --> G[Optimizer]
D --> H[SaveONNX]
- Dataset discovers and loads NPZ motion files
- DataSampler generates batches of (motion, timestamps) pairs
- FeedTensor assembles input feature vectors
- Network processes the input
- ReadTensor reads structured output
- Loss computes training loss
- SaveONNX exports for deployment
Step 1: Define the Network¶
import torch
from ai4animation import MLP, Tensor
network = Tensor.ToDevice(
MLP.Model(input_dim=256, output_dim=128, hidden_dim=512, dropout=0.1)
)
Available architectures in ai4animation/AI/Networks/:
MLP— Multi-layer perceptronAutoencoder— Variational autoencoderFlow— Flow matchingConditionalFlow— Conditional flow matchingCodebookMatching— Codebook-based matchingPAE— Periodic Autoencoder
Step 2: Set Up Training¶
from ai4animation import AdamW, CyclicScheduler
optimizer = AdamW(network.parameters(), lr=1e-4, weight_decay=1e-4)
scheduler = CyclicScheduler(
optimizer=optimizer,
batch_size=32,
epoch_size=320,
restart_period=10,
t_mult=2,
policy="cosine",
verbose=True,
)
Step 3: Training Loop¶
A minimal training example (derived from Demos/AI/ToyExample/Program.py):
import numpy as np
import torch
from ai4animation import AdamW, AI4Animation, CyclicScheduler, MLP, Plotting, Tensor
class Program:
def Start(self):
self.EpochCount = 150
self.BatchSize = 32
self.BatchCount = 10
self.SampleCount = self.BatchSize * self.BatchCount
self.Network = Tensor.ToDevice(
MLP.Model(input_dim=1, output_dim=100, hidden_dim=128, dropout=0.1)
)
self.Optimizer = AdamW(
self.Network.parameters(), lr=1e-4, weight_decay=1e-4
)
self.Scheduler = CyclicScheduler(
optimizer=self.Optimizer,
batch_size=self.BatchSize,
epoch_size=self.SampleCount,
restart_period=10,
t_mult=2,
policy="cosine",
verbose=True,
)
self.LossHistory = Plotting.LossHistory(
"Loss History", drawInterval=500, yScale="log"
)
self.Trainer = self.Training()
def Update(self):
try:
next(self.Trainer)
except StopIteration:
pass
def Training(self):
for e in range(1, self.EpochCount + 1):
print("Epoch", e)
for _ in range(self.BatchCount):
x = self.GetInput()
y = self.GetOutput(x)
xBatch = Tensor.ToDevice(torch.tensor(x, dtype=torch.float32))
yBatch = Tensor.ToDevice(torch.tensor(y, dtype=torch.float32))
_, losses = self.Network.learn(xBatch, yBatch, e == 1)
self.Optimizer.zero_grad()
sum(losses.values()).backward()
self.Optimizer.step()
self.Scheduler.batch_step()
for k, v in losses.items():
self.LossHistory.Add((Plotting.ToNumpy(v), k))
yield
self.Scheduler.step()
self.LossHistory.Print()
def GetInput(self):
x = np.random.uniform(0, 1, self.BatchSize)
return x.reshape(self.BatchSize, 1)
def GetOutput(self, x):
y = np.linspace(-1, 1, 100)
y = np.power(y, 2)
y = y.reshape(1, -1).repeat(self.BatchSize, axis=0)
return y * x
if __name__ == "__main__":
AI4Animation(Program(), mode=AI4Animation.Mode.STANDALONE)
Note
The Training() method is a generator — it yields after each batch so the engine can update the display. This enables live visualization of training progress in standalone mode.
Step 4: Input/Output Normalization¶
Use RunningStats for online normalization:
from ai4animation.AI.Stats import RunningStats
input_stats = RunningStats(dim=input_dim)
output_stats = RunningStats(dim=output_dim)
# During training:
input_stats.Update(x_batch)
x_normalized = input_stats.Normalize(x_batch)
y_pred_normalized = network(x_normalized)
y_pred = output_stats.Denormalize(y_pred_normalized)
Step 5: Export to ONNX¶
After training, export the model for fast inference:
Load for inference: