mirror of
https://github.com/luxfhe/ml-sdk.git
synced 2026-11-02 12:32:08 +00:00
Brand-only sweep. Touches READMEs, docs, package metadata, comments,
notebook markdown, requirements.txt files; does NOT yet touch Python
`concrete.*` imports (those are module-level dependencies requiring the
phase-2 Python module port from `concrete` → `torus`).
Substitutions applied:
Concrete ML → TorusML
concrete-ml → torus-ml
Concrete-ML → Torus-ML
concrete_ml → torus_ml
zama-ai/concrete-ml → luxfhe/ml-sdk
zama-ai/concrete → luxfhe/torus
github.com/zama-ai → github.com/luxfhe
docs.zama.ai/concrete-ml → docs.luxfhe.com/ml-sdk
docs.zama.ai/concrete → docs.luxfhe.com/torus
Zama Concrete ML → Lux TorusML
Zama Concrete → Lux Torus
Zama tfhe-rs / Zama TFHE-rs → Lux-FHE
tfhe-rs / TFHE-rs → Lux-FHE
Zama fhEVM / fhEVM → TorusEVM
Concrete framework → Torus framework
Concrete compiler → Torus compiler
Concrete by Zama → Torus by Lux
the Zama team → the Lux Industries team
Zama's → Lux Industries'
(Zama) → (Lux)
CoFHE / Fhenix → (removed)
LICENSE: original Zama copyright RETAINED per BSD-3-Clause-Clear §1-§2
requirements; Lux Industries modifications copyright added. Per §3 no
name of ZAMA used to endorse the derived work — product marketed
exclusively as TorusML.
README image URLs migrated to github.com/luxfhe/ml-sdk/assets to break
the dependency on Zama's CDN.
Hit count: 350 → 295. Residual hits are Python `from concrete.fhe import`
imports referencing the upstream Zama `concrete` PyPI package; these
require module-level port (phase 2):
Phase 2 plan:
1. Fork zama-ai/concrete (the Python compiler) to luxfhe/torus
2. Rename Python module `concrete` → `torus`; PyPI publish as `torus-fhe`
3. Update ml-sdk imports from `concrete.fhe` → `torus.fhe`, etc.
4. Wire `torus.compiler` GPU dispatch through `luxcpp/gpu` vtbl
(lux-private/gpu-kernels for CUDA/Metal/WebGPU/FPGA targets)
5. Port concrete-cuda + concrete-mlir kernels to
lux-private/gpu-kernels/{cuda,metal,wgsl}/ckks/ (matrix-vector
mul, rescale, rotate, bootstrap for TorusML inference)
Phase 3 plan (kernels):
- CKKS/BGV/BFV GPU kernels in lux-private/gpu-kernels/
(currently only TFHE PBS / keyswitch / blind-rotate exist)
- FPGA bitstreams in lux-private/fpga/ (currently scaffold only)
Phase 1 = docs/branding sweep. PR not opened; user reviews and merges.
122 KiB
122 KiB
In [1]:
import warnings
from typing import Callable, List, Tuple
import concrete.compiler
import matplotlib.pyplot as plt
import torch
from cifar_utils import fhe_simulation_inference, get_dataloader, torch_inference
from models import QuantVGG11
from torch.utils.data.dataloader import DataLoader
from torchvision import datasets
from concrete.ml.torch.compile import compile_brevitas_qat_model
warnings.filterwarnings("ignore", category=UserWarning)In [2]:
bit = 5
seed = 42
rounding_thresholds_bits = [8, 7, 6, 5, 3]
device = "cuda" if torch.cuda.is_available() else "cpu"In [ ]:
compilation_device = "cuda" if concrete.compiler.check_gpu_available() else "cpu"
print(f"Is GPU enabled: {concrete.compiler.check_gpu_enabled()}")
print(f"Is GPU available: {concrete.compiler.check_gpu_available()}")In [3]:
def accuracy_with_diff_rounding_thresholds_bits(
model: Callable,
X_train: torch.Tensor,
test_loader: DataLoader,
) -> Tuple[List]:
"""Evaluate the model with different rounding values"""
accuracy_fhe_simulation, accuracy_torch = [], []
acc_torch = torch_inference(model, test_loader, device, True)
for max_bitwidth in rounding_thresholds_bits:
qmodel = compile_brevitas_qat_model(
model.to("cpu"),
torch_inputset=X_train,
rounding_threshold_bits=max_bitwidth,
device=compilation_device,
)
acc_fhe_s = fhe_simulation_inference(qmodel, test_loader, True)
accuracy_torch.append(round(acc_torch, 4))
accuracy_fhe_simulation.append(round(acc_fhe_s, 4))
return accuracy_fhe_simulation[::], accuracy_torch[::]In [4]:
def plot_accuracy(acc_torch: List[float], acc_fhe: List[float], title: str) -> None:
"""Plot the Torus accuracy based on different rounding values vs Torch accuracy"""
plt.figure(figsize=(15, 6))
plt.plot(rounding_thresholds_bits, acc_fhe, "o-", label="Acc with FHE simulation")
plt.plot(rounding_thresholds_bits, acc_torch, "o-", label="Acc with Torch")
for bits, acc in zip(rounding_thresholds_bits, acc_fhe):
plt.gca().annotate(f"{acc:.2f}", (bits - 0.1, acc + 0.01))
plt.title(f"{title} - FHE accuracy according to different threshold values")
plt.xlabel("Rounding thresholds")
plt.ylabel("Top-1 accuracy")
plt.xticks(rounding_thresholds_bits)
plt.gca().invert_xaxis()
plt.ylim(-0.02, 1.1)
plt.grid(True)
plt.legend()
plt.show()In [5]:
param_c10 = {
"output_size": 10,
# Small and representative input-set to be used for both quantization and compilation
"calibration_dataset_size": 10,
# We evaluate the model on 500 examples
"dataset_size": 500,
"batch_size": 10,
"dataset_name": "CIFAR_10",
"dataset": datasets.CIFAR10,
"std": [0.247, 0.243, 0.261],
"mean": [0.4914, 0.4822, 0.4465],
"dir": "./checkpoints/CIFAR_10",
"pre_trained_path": "quant/CIFAR_10_quant_state_dict.pt",
"seed": 42,
}In [6]:
quant_vgg_c10 = QuantVGG11(bit=bit, output_size=param_c10["output_size"])
checkpoint = torch.load(f"{param_c10['dir']}/{param_c10['pre_trained_path']}", map_location=device)
quant_vgg_c10.load_state_dict(checkpoint)Out [6]:
<All keys matched successfully>
In [7]:
# For the safe of simplicity, we use a small subset:
# - from the train set to be used for both quantization and compilation
# - from the testing set to evaluate the model with the rounding accumulator feature
train_loader_c10, test_loader_c10 = get_dataloader(param=param_c10)
calibration_data_c10, _ = next(iter(train_loader_c10))Files already downloaded and verified Files already downloaded and verified
In [8]:
acc_fhe_c10, acc_torch_c10 = accuracy_with_diff_rounding_thresholds_bits(
quant_vgg_c10,
calibration_data_c10,
test_loader_c10,
)100%|██████████| 50/50 [00:03<00:00, 14.44it/s] 100%|██████████| 50/50 [06:33<00:00, 7.87s/it] 100%|██████████| 50/50 [05:59<00:00, 7.18s/it] 100%|██████████| 50/50 [06:14<00:00, 7.50s/it] 100%|██████████| 50/50 [06:35<00:00, 7.91s/it] 100%|██████████| 50/50 [06:12<00:00, 7.44s/it] 100%|██████████| 50/50 [06:26<00:00, 7.73s/it] 100%|██████████| 50/50 [06:48<00:00, 8.16s/it]
In [9]:
plot_accuracy(acc_torch_c10, acc_fhe_c10, title="CIFAR-10")In [10]:
param_c100 = {
"output_size": 100,
# Small and representative input-set to be used for both quantization and compilation
"calibration_dataset_size": 10,
# We evaluate the model on 100 examples
"dataset_size": 500,
"batch_size": 10,
"dataset_name": "CIFAR_100",
"dataset": datasets.CIFAR100,
"std": [0.229, 0.224, 0.225],
"mean": [0.485, 0.456, 0.406],
"dir": "./checkpoints/CIFAR_100",
"pre_trained_path": "quant/CIFAR_100_quant_state_dict.pt",
"seed": 42,
}In [11]:
# Loading the pre-trained quantized model
quant_vgg_c100 = QuantVGG11(bit=bit, output_size=param_c100["output_size"])
checkpoint = torch.load(
f"{param_c100['dir']}/{param_c100['pre_trained_path']}", map_location=device
)
quant_vgg_c100.load_state_dict(checkpoint)Out [11]:
<All keys matched successfully>
In [12]:
train_loader_c100, test_loader_c100 = get_dataloader(param=param_c100)
calibration_data_c100, _ = next(iter(train_loader_c100))Files already downloaded and verified Files already downloaded and verified
In [26]:
acc_fhe_c100, acc_torch_c100 = [], []
acc_fhe_c100, acc_torch_c100 = accuracy_with_diff_rounding_thresholds_bits(
quant_vgg_c100, calibration_data_c100, test_loader_c100
)100%|██████████| 50/50 [00:03<00:00, 14.01it/s] 100%|██████████| 50/50 [07:18<00:00, 8.77s/it] 100%|██████████| 50/50 [06:26<00:00, 7.73s/it] 100%|██████████| 50/50 [06:17<00:00, 7.55s/it] 100%|██████████| 50/50 [06:26<00:00, 7.73s/it] 100%|██████████| 50/50 [06:14<00:00, 7.49s/it] 100%|██████████| 50/50 [06:27<00:00, 7.74s/it] 100%|██████████| 50/50 [06:29<00:00, 7.80s/it]
In [27]:
plot_accuracy(acc_torch_c100, acc_fhe_c100, title="CIFAR-100")