mirror of
https://github.com/luxfhe/ml-sdk.git
synced 2026-10-30 18:13:04 +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.
355 KiB
355 KiB
In [1]:
import warnings
warnings.simplefilter(action="ignore", category=FutureWarning)
import time
import matplotlib.pyplot as plt
import numpy
from concrete.compiler import check_gpu_available
from matplotlib.colors import ListedColormap
from sklearn.datasets import fetch_openml, make_circles
from sklearn.metrics import accuracy_score, make_scorer, matthews_corrcoef
from sklearn.model_selection import GridSearchCV, train_test_split
from xgboost.sklearn import XGBClassifier as SklearnXGBClassifier
from concrete.ml.sklearn import XGBClassifier as ConcreteXGBClassifier
use_gpu_if_available = False
device = "cuda" if use_gpu_if_available and check_gpu_available() else "cpu"
%matplotlib inlineIn [2]:
X, y = make_circles(n_samples=1000, noise=0.1, factor=0.6, random_state=0)In [3]:
# Define the figure size and color
plt.figure(figsize=(10, 6))
cm_bright = ListedColormap(["#FF0000", "#FFFFFF", "#0000FF"])
plt.scatter(X[:, 0], X[:, 1], c=y, s=10, cmap=cm_bright)
plt.show()In [4]:
# Define the parameters used for initialization
n_estimators = 50
max_depth = 4
n_bits = 6
# Define the parameters used for training
fit_extra_param = {"eval_metric": "logloss"}In [5]:
sklearn_model = SklearnXGBClassifier(n_estimators=n_estimators, max_depth=max_depth)
sklearn_model.fit(X, y, **fit_extra_param);In [6]:
concrete_model = ConcreteXGBClassifier(
n_bits=n_bits, n_estimators=n_estimators, max_depth=max_depth
)
concrete_model.fit(X, y);In [7]:
def plot_contour(model, X, y, title=""):
"""Plot the contour lines given a model and a data-set."""
# Create a grid will lots of point to plot the contour of the decision function
x_min, x_max = X[:, 0].min() - 0.1, X[:, 0].max() + 0.1
y_min, y_max = X[:, 1].min() - 0.1, X[:, 1].max() + 0.1
grid_x, grid_y = numpy.meshgrid(
numpy.arange(x_min, x_max, 0.1), numpy.arange(y_min, y_max, 0.1)
)
# Predict the function value on the grid. For the TorusML model, this inference is done in
# the clear, which is expected to exactly match the FHE inference.
grid_z = model.predict_proba(numpy.c_[grid_x.ravel(), grid_y.ravel()])[:, 1]
grid_z = grid_z.reshape(grid_x.shape)
# Define the plot size
plt.figure(figsize=(10, 6))
# Plot the contour and training examples
plt.contourf(grid_x, grid_y, grid_z, cmap=cm_bright, alpha=0.2)
plt.scatter(X[:, 0], X[:, 1], c=y, s=1, cmap=cm_bright)
plt.title(title)
plt.show()In [8]:
plot_contour(sklearn_model, X, y, title="Scikit-Learn XGBoost Classifier")In [9]:
plot_contour(concrete_model, X, y, title="TorusML XGBoost Classifier")In [10]:
# Load the data-set
X, y = fetch_openml(name="diabetes", as_frame=False, cache=True, return_X_y=True)
# Replace (binary) target values by integers
y[y == "tested_positive"] = 1
y[y == "tested_negative"] = 0
y = y.astype(numpy.int64)In [11]:
# Create scorer with the MCC metric
grid_scorer = make_scorer(matthews_corrcoef, greater_is_better=True)
# Define the number of estimators to consider for the following gridsearch
n_estimators = [1, 5, 10, 20] + [20 * i for i in range(2, 11)] + [50 * i for i in range(5, 11)]In [12]:
param_grid = {
"max_depth": [2],
"n_estimators": n_estimators,
}
sklearn_grid_search = GridSearchCV(
SklearnXGBClassifier(),
param_grid,
cv=5,
scoring=grid_scorer,
error_score="raise",
verbose=1,
)
sklearn_grid_search.fit(X, y, **fit_extra_param);Fitting 5 folds for each of 19 candidates, totalling 95 fits
In [13]:
param_grid = {
"n_bits": [6],
"max_depth": [2],
"n_estimators": n_estimators,
}
concrete_grid_search = GridSearchCV(
ConcreteXGBClassifier(),
param_grid,
cv=5,
scoring=grid_scorer,
error_score="raise",
verbose=1,
)
concrete_grid_search.fit(X, y);Fitting 5 folds for each of 19 candidates, totalling 95 fits
In [14]:
# Print the best MCC score for both models
print(f"Best MCC score for Scikit-Learn: {sklearn_grid_search.best_score_:.2f}")
print(f"Best MCC score TorusML: {concrete_grid_search.best_score_:.2f}")Best MCC score for Scikit-Learn: 0.48 Best MCC score TorusML: 0.52
In [15]:
# Define the figure size
plt.figure(figsize=(10, 6))
# Plot the mean_test_score of both model along the n_estimators hyper parameter
plt.plot(
concrete_grid_search.cv_results_["param_n_estimators"],
concrete_grid_search.cv_results_["mean_test_score"],
label="TorusML",
)
plt.plot(
sklearn_grid_search.cv_results_["param_n_estimators"],
sklearn_grid_search.cv_results_["mean_test_score"],
label="Scikit-Learn",
)
plt.xlabel("n_estimators")
plt.ylabel("MCC")
plt.legend()
plt.show()In [16]:
best_params_sklearn = sklearn_grid_search.best_params_
print(f"Best parameters found for the Scikit-Learn model: {best_params_sklearn}")
best_params_concrete = concrete_grid_search.best_params_
print(f"Best parameters found for the TorusML model: {best_params_concrete}")Best parameters found for the Scikit-Learn model: {'max_depth': 2, 'n_estimators': 40}
Best parameters found for the TorusML model: {'max_depth': 2, 'n_bits': 6, 'n_estimators': 80}
In [17]:
# Define the TorusML and Scikit-Learn models
concrete_model = ConcreteXGBClassifier(**best_params_concrete)
sklearn_model = SklearnXGBClassifier(**best_params_sklearn)
# Split the data into a train and test set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=42)
# Fit both models
concrete_model.fit(X_train, y_train, **fit_extra_param)
sklearn_model.fit(X_train, y_train, **fit_extra_param);In [18]:
# Compile the TorusML model using the training data
circuit = concrete_model.compile(X_train, device=device)In [19]:
print(f"Generating a key for an {circuit.graph.maximum_integer_bit_width()}-bits circuit")
# Generate the key
time_begin = time.time()
circuit.client.keygen(force=False)
print(f"Key generation time: {time.time() - time_begin:.2f} seconds")Generating a key for an 8-bits circuit Key generation time: 0.75 seconds
In [20]:
# Compute the predictions using the Scikit-Learn model
y_pred_sklearn = sklearn_model.predict(X_test)
# Compute the predictions using the TorusML model with FHE simulation
y_pred_simulated = concrete_model.predict(X_test, fhe="simulate")In [21]:
print("Accuracy scores:")
print(
f"- Scikit-Learn (clear floating points): {accuracy_score(y_test, y_pred_sklearn)*100:.2f}%\n"
f"- TorusML (clear quantized): {accuracy_score(y_test, y_pred_simulated)*100:.2f}\n"
)Accuracy scores: - Scikit-Learn (clear floating points): 71.43% - TorusML (clear quantized): 68.83
In [22]:
N_SAMPLE_FHE = 10
# Pick N_SAMPLE_FHE random samples from the test set
idx_test = numpy.random.choice(X_test.shape[0], N_SAMPLE_FHE, replace=False)
X_test_fhe = X_test[idx_test]
y_test_fhe = y_test[idx_test]
# Compute the predictions using the TorusML (quantized) model in the clear
y_preds_clear = concrete_model.predict(X_test_fhe)
# Compute the predictions using the TorusML model in FHE
time_begin = time.time()
y_preds_fhe = concrete_model.predict(X_test_fhe, fhe="execute")
print(f"FHE execution time: {(time.time() - time_begin) / len(X_test_fhe):.2f} seconds per sample")FHE execution time: 0.65 seconds per sample
In [23]:
# Compare the clear quantized inference vs FHE inference
print(
f"{(y_preds_fhe == y_preds_clear).sum()}/{N_SAMPLE_FHE} "
"FHE predictions match the clear quantized predictions"
)10/10 FHE predictions match the clear quantized predictions