mirror of
https://github.com/luxfi/torus-ml.git
synced 2026-10-30 15:15:23 +00:00
The distribution called itself torus-ml while shipping a package directory named concrete, so the name a user installs and the name they import disagreed — and most of the tree already said torus.ml, which could not resolve against src/concrete. Moved src/concrete to src/torus and pointed the include at it. The dependency was Zama's concrete-python from their index. It is torus-fhe from ours, which is what luxfhe/torus already ships: that frontend declares torus-fhe and ships a torus/fhe module, so every 'from torus.fhe' in this tree was already naming our compiler and only the dependency lagged. Two distributions share one namespace, which is the shape the upstream this forked from used and the reason the split works: torus-fhe gives torus.fhe, torus-ml gives torus.ml. Swept every other spelling — identifiers, enum members, workflow variables, filenames, notebooks. LICENSE and NOTICE keep the upstream attribution a fork owes; the figures carry the old name in JPEG metadata a text sweep cannot reach.
434 KiB
434 KiB
In [1]:
import torus.compiler
import torch
from cifar_utils import (
fhe_compatibility,
get_dataloader,
mapping_keys,
plot_baseline,
plot_dataset,
torch_inference,
train,
)
# As we follow the same methodology for quantization aware training for CIFAR-10 and CIFAR-100.
# Let's import some generic functions.
from models import QuantVGG11
from torchvision import datasetsIn [2]:
bit = 5
device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"Device Type: {device}")Device Type: cpu
In [ ]:
compilation_device = "cuda" if torus.compiler.check_gpu_available() else "cpu"
print(f"Is GPU enabled: {torus.compiler.check_gpu_enabled()}")
print(f"Is GPU available: {torus.compiler.check_gpu_available()}")In [3]:
param_c100 = {
"output_size": 100,
"batch_size": 128,
"training": "quant",
"dataset_name": "CIFAR_100",
"dataset": datasets.CIFAR100,
"mean": [0.485, 0.456, 0.406],
"std": [0.229, 0.224, 0.225],
"lr": 6e-5,
"seed": 727,
"epochs": 10,
"gamma": 0.01,
"milestones": [3, 5],
"criterion": torch.nn.CrossEntropyLoss(),
"accuracy_test": [],
"accuracy_train": [],
"loss_test_history": [],
"loss_train_history": [],
"dir": "./checkpoints/CIFAR_100",
"pre_trained_path": "fp32/CIFAR_100_fp32_state_dict.pt",
}In [4]:
# Load CIFAR-100 data-set.
train_loader_c100, test_loader_c100 = get_dataloader(param=param_c100)
# Let’s visualize `n` images from CIFAR-100 data-set.
plot_dataset(test_loader_c100, param_c100)Files already downloaded and verified Files already downloaded and verified
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
In [5]:
quant_vgg = QuantVGG11(bit=bit, output_size=param_c100["output_size"])In [6]:
checkpoint = torch.load(
f"{param_c100['dir']}/{param_c100['pre_trained_path']}", map_location=device
)In [7]:
quant_vgg = mapping_keys(checkpoint, quant_vgg, device)In [9]:
# It's better than a random classifier.
acc_before_ft = torch_inference(quant_vgg, test_loader_c100, device=device)
param_c100["accuracy_test"].append(acc_before_ft)
print(f"Top 1 accuracy before fine-tuning = {acc_before_ft * 100:.4f}%")Top 1 accuracy before fine-tuning = 7.3217%
In [10]:
# The user can either provide the entire train data-set or a smaller but representative subset.
# As each batch is shuffled and contains 128 samples, it's a potential subset.
data_calibration, _ = next(iter(train_loader_c100))
qmodel = fhe_compatibility(quant_vgg, data_calibration, device=compilation_device)
print(
f"With {param_c100['dataset_name']}, the maximum bit-width in the circuit = "
f"{qmodel.fhe_circuit.graph.maximum_integer_bit_width()}"
)In [10]:
quant_vgg = train(quant_vgg, train_loader_c100, test_loader_c100, param_c100, device=device)Epoch 0: Train loss = 0.5070 VS Test loss = 1.3996 - Accuracy train: 0.8428 VS Accuracy test: 0.6791 Epoch 1: Train loss = 0.3827 VS Test loss = 1.4884 - Accuracy train: 0.8800 VS Accuracy test: 0.6805 Epoch 2: Train loss = 0.3163 VS Test loss = 1.5556 - Accuracy train: 0.8996 VS Accuracy test: 0.6873 Epoch 3: Train loss = 0.2609 VS Test loss = 1.5615 - Accuracy train: 0.9170 VS Accuracy test: 0.6855 Epoch 4: Train loss = 0.2505 VS Test loss = 1.5604 - Accuracy train: 0.9189 VS Accuracy test: 0.6877 Epoch 5: Train loss = 0.2497 VS Test loss = 1.5592 - Accuracy train: 0.9218 VS Accuracy test: 0.6889 Epoch 6: Train loss = 0.2498 VS Test loss = 1.5576 - Accuracy train: 0.9219 VS Accuracy test: 0.6882 Epoch 7: Train loss = 0.2442 VS Test loss = 1.5540 - Accuracy train: 0.9222 VS Accuracy test: 0.6894 Epoch 8: Train loss = 0.2434 VS Test loss = 1.5576 - Accuracy train: 0.9228 VS Accuracy test: 0.6879 Epoch 9: Train loss = 0.2504 VS Test loss = 1.5537 - Accuracy train: 0.9205 VS Accuracy test: 0.6897 100%|██████████| 10/10 [11:03<00:00, 66.38s/it]
In [11]:
plot_baseline(param_c100, test_loader_c100, device)100%|██████████| 78/78 [00:02<00:00, 32.94it/s]
Running time: 0.0002 sec.
In [12]:
param_c10 = {
"output_size": 10,
"batch_size": 128,
"training": "quant",
"dataset_name": "CIFAR_10",
"dataset": datasets.CIFAR10,
"std": [0.247, 0.243, 0.261],
"mean": [0.4914, 0.4822, 0.4465],
"seed": 42,
"lr": 1e-5,
"epochs": 9,
"gamma": 0.1,
"milestones": [4],
"criterion": torch.nn.CrossEntropyLoss(),
"accuracy_test": [],
"accuracy_train": [],
"loss_test_history": [],
"loss_train_history": [],
"dir": "./checkpoints/CIFAR_10",
"pre_trained_path": "fp32/CIFAR_10_fp32_state_dict.pt",
}In [13]:
# Load CIFAR-10 data-set.
train_loader_c10, test_loader_c10 = get_dataloader(param=param_c10)
# Let’s visualize `n` images from CIFAR-100 data-set.
plot_dataset(test_loader_c10, param_c10)Files already downloaded and verified Files already downloaded and verified
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
In [14]:
# Instantiate our custom vgg11 network.
quant_vgg = QuantVGG11(bit=bit, output_size=param_c10["output_size"]).to(device)
checkpoint = torch.load(f"{param_c10['dir']}/{param_c10['pre_trained_path']}", map_location=device)
# checkpoint = torch.load("./checkpoints/CIFAR_10/fp32/CIFAR10_fp32_weights_acc_0.9013.pt")
# Mapping keys.
quant_vgg = mapping_keys(checkpoint, quant_vgg, device)In [15]:
# It's better than a random classifier.
acc_before_ft = torch_inference(quant_vgg, test_loader_c10, device=device)
param_c10["accuracy_test"].append(acc_before_ft)
print(f"Top-1 accuracy before fine-tuning = {acc_before_ft * 100:.4f}%")100%|██████████| 78/78 [00:05<00:00, 15.04it/s]
Running time: 0.0005 sec. Top-1 accuracy before fine-tuning = 29.3570%
In [16]:
# Check the FHE-compatibility.
data, _ = next(iter(train_loader_c10))
qmodel = fhe_compatibility(quant_vgg, data, device=compilation_device)
print(
f"With {param_c10['dataset_name']}, the circuit has a maximum bit-width of "
f"{qmodel.fhe_circuit.graph.maximum_integer_bit_width()}-bits."
)With CIFAR_10, the circuit has a maximum bit-width of 14-bits.
In [17]:
# Quantization Aware Training.
quant_vgg = train(quant_vgg, train_loader_c10, test_loader_c10, param_c10, device=device)Epoch 0: Train loss = 0.2612 VS Test loss = 0.3473 - Accuracy train: 0.9084 VS Accuracy test: 0.8895 Epoch 1: Train loss = 0.2136 VS Test loss = 0.3421 - Accuracy train: 0.9252 VS Accuracy test: 0.8902 Epoch 2: Train loss = 0.1629 VS Test loss = 0.3267 - Accuracy train: 0.9443 VS Accuracy test: 0.8986 Epoch 3: Train loss = 0.1578 VS Test loss = 0.3236 - Accuracy train: 0.9467 VS Accuracy test: 0.8999 Epoch 4: Train loss = 0.1521 VS Test loss = 0.3227 - Accuracy train: 0.9470 VS Accuracy test: 0.9006 Epoch 5: Train loss = 0.1520 VS Test loss = 0.3185 - Accuracy train: 0.9472 VS Accuracy test: 0.9042 100%|██████████| 6/6 [07:19<00:00, 73.27s/it]
In [18]:
plot_baseline(param_c10, test_loader_c10, device)