PyTorch: MNIST
A small convolutional network on the real MNIST dataset, downloaded through torchvision. Shows the seed, model card, phases, per-epoch metrics, and a final claim.
Install
The framework, plus the K-Veritas CLI (see the Overview for install).
pip install torch torchvision
train.py
The complete script. The KVERITAS_ lines are the only additions to an ordinary training script; everything else is standard PyTorch.
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
SEED = 42
torch.manual_seed(SEED)
print(f"KVERITAS_INPUT src=seed:{SEED}", flush=True)
device = "cuda" if torch.cuda.is_available() else "cpu"
print("KVERITAS_PHASE name=data", flush=True)
tfm = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))])
train_ds = datasets.MNIST("./data", train=True, download=True, transform=tfm)
test_ds = datasets.MNIST("./data", train=False, download=True, transform=tfm)
train_loader = DataLoader(train_ds, batch_size=128, shuffle=True)
test_loader = DataLoader(test_ds, batch_size=512)
class Net(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(1, 32, 3, padding=1)
self.conv2 = nn.Conv2d(32, 64, 3, padding=1)
self.fc1 = nn.Linear(64 * 7 * 7, 128)
self.fc2 = nn.Linear(128, 10)
def forward(self, x):
x = F.max_pool2d(F.relu(self.conv1(x)), 2)
x = F.max_pool2d(F.relu(self.conv2(x)), 2)
x = x.flatten(1)
x = F.relu(self.fc1(x))
return self.fc2(x)
model = Net().to(device)
n_params = sum(p.numel() for p in model.parameters())
print(f"KVERITAS_MODEL params={n_params} arch=cnn precision=fp32", flush=True)
print(f"KVERITAS_WORKLOAD dataset_size={len(train_ds)} epochs=3 batch_size=128", flush=True)
opt = torch.optim.Adam(model.parameters(), lr=1e-3)
def accuracy(loader):
model.eval()
correct = total = 0
with torch.no_grad():
for x, y in loader:
x, y = x.to(device), y.to(device)
correct += (model(x).argmax(1) == y).sum().item()
total += y.size(0)
return correct / total
print("KVERITAS_PHASE name=train", flush=True)
for epoch in range(1, 4):
model.train()
running = 0.0
for x, y in train_loader:
x, y = x.to(device), y.to(device)
opt.zero_grad()
loss = F.cross_entropy(model(x), y)
loss.backward()
opt.step()
running += loss.item() * y.size(0)
train_loss = running / len(train_ds)
test_acc = accuracy(test_loader)
print(f"KVERITAS_METRIC name=train_loss value={train_loss:.4f} step={epoch}", flush=True)
print(f"KVERITAS_METRIC name=test_accuracy value={test_acc:.4f} step={epoch}", flush=True)
print(f"epoch {epoch}/3 train_loss={train_loss:.4f} test_acc={test_acc:.4f}", flush=True)
print("KVERITAS_PHASE name=evaluate", flush=True)
final_acc = accuracy(test_loader)
print(f"KVERITAS_CLAIM metric=test_accuracy value={final_acc:.4f}", flush=True)
print(f"final test_accuracy={final_acc:.4f}", flush=True)Run and seal
Wrap the script, seal a signed report, and verify it offline.
kveritas init kveritas run -- python train.py kveritas seal --output report.pdf kveritas verify report.pdf
What it produced here
3 epochs on a single GPU reached about 99.0% test accuracy. The report sealed 6 metrics, 3 phases, a seed commitment, and one claim.