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.
279 lines
11 KiB
Python
279 lines
11 KiB
Python
"""Implement DecisionTree models."""
|
|
|
|
from typing import Any, Dict, Union
|
|
|
|
import numpy
|
|
import sklearn.tree
|
|
|
|
from ..sklearn.tree_to_numpy import tree_to_numpy
|
|
from .base import BaseTreeClassifierMixin, BaseTreeEstimatorMixin, BaseTreeRegressorMixin
|
|
|
|
|
|
# pylint: disable-next=too-many-instance-attributes
|
|
class DecisionTreeClassifier(BaseTreeClassifierMixin):
|
|
"""Implements the sklearn DecisionTreeClassifier."""
|
|
|
|
sklearn_model_class = sklearn.tree.DecisionTreeClassifier
|
|
framework = "sklearn"
|
|
_is_a_public_cml_model = True
|
|
|
|
# pylint: disable-next=too-many-arguments
|
|
def __init__(
|
|
self,
|
|
criterion="gini",
|
|
splitter="best",
|
|
max_depth=None,
|
|
min_samples_split=2,
|
|
min_samples_leaf=1,
|
|
min_weight_fraction_leaf=0.0,
|
|
max_features=None,
|
|
random_state=None,
|
|
max_leaf_nodes=None,
|
|
min_impurity_decrease=0.0,
|
|
class_weight=None,
|
|
ccp_alpha: float = 0.0,
|
|
monotonic_cst=None,
|
|
n_bits: Union[int, Dict[str, int]] = 6,
|
|
):
|
|
"""Initialize the DecisionTreeClassifier.
|
|
|
|
# noqa: DAR101
|
|
|
|
"""
|
|
# Call BaseClassifier's __init__ method
|
|
super().__init__(n_bits=n_bits)
|
|
|
|
self.criterion = criterion
|
|
self.splitter = splitter
|
|
self.max_depth = max_depth
|
|
self.min_samples_split = min_samples_split
|
|
self.min_samples_leaf = min_samples_leaf
|
|
self.min_weight_fraction_leaf = min_weight_fraction_leaf
|
|
self.max_features = max_features
|
|
self.max_leaf_nodes = max_leaf_nodes
|
|
self.class_weight = class_weight
|
|
self.random_state = random_state
|
|
self.min_impurity_decrease = min_impurity_decrease
|
|
self.ccp_alpha = ccp_alpha
|
|
self.monotonic_cst = monotonic_cst
|
|
|
|
def __getattr__(self, attr: str):
|
|
# We directly expose the following methods as they are commonly used with decision trees
|
|
# and only represent their topological structure
|
|
if (
|
|
attr in ["get_depth", "get_n_leaves"]
|
|
and getattr(self, "sklearn_model", None) is not None
|
|
):
|
|
return getattr(self.sklearn_model, attr)
|
|
|
|
return super().__getattr__(attr)
|
|
|
|
def post_processing(self, y_preds: numpy.ndarray) -> numpy.ndarray:
|
|
# Here, we want to use BaseTreeEstimatorMixin's `post-processing` method as
|
|
# DecisionTreeClassifier models directly computes probabilities and therefore don't require
|
|
# to apply a sigmoid or softmax in post-processing
|
|
return BaseTreeEstimatorMixin.post_processing(self, y_preds)
|
|
|
|
def dump_dict(self) -> Dict[str, Any]:
|
|
metadata: Dict[str, Any] = {}
|
|
|
|
# TorusML
|
|
metadata["n_bits"] = self.n_bits
|
|
metadata["sklearn_model"] = self.sklearn_model
|
|
metadata["_is_fitted"] = self._is_fitted
|
|
metadata["_is_compiled"] = self._is_compiled
|
|
metadata["input_quantizers"] = self.input_quantizers
|
|
metadata["output_quantizers"] = self.output_quantizers
|
|
metadata["onnx_model_"] = self.onnx_model_
|
|
metadata["framework"] = self.framework
|
|
metadata["post_processing_params"] = self.post_processing_params
|
|
metadata["_fhe_ensembling"] = self._fhe_ensembling
|
|
|
|
# Scikit-Learn
|
|
metadata["criterion"] = self.criterion
|
|
metadata["splitter"] = self.splitter
|
|
metadata["max_depth"] = self.max_depth
|
|
metadata["min_samples_split"] = self.min_samples_split
|
|
metadata["min_samples_leaf"] = self.min_samples_leaf
|
|
metadata["min_weight_fraction_leaf"] = self.min_weight_fraction_leaf
|
|
metadata["max_features"] = self.max_features
|
|
metadata["max_leaf_nodes"] = self.max_leaf_nodes
|
|
metadata["class_weight"] = self.class_weight
|
|
metadata["random_state"] = self.random_state
|
|
metadata["min_impurity_decrease"] = self.min_impurity_decrease
|
|
metadata["ccp_alpha"] = self.ccp_alpha
|
|
metadata["monotonic_cst"] = self.monotonic_cst
|
|
|
|
return metadata
|
|
|
|
@classmethod
|
|
def load_dict(cls, metadata: Dict):
|
|
|
|
# Instantiate the model
|
|
obj = cls(n_bits=metadata["n_bits"])
|
|
|
|
# TorusML
|
|
obj.sklearn_model = metadata["sklearn_model"]
|
|
obj._is_fitted = metadata["_is_fitted"]
|
|
obj._is_compiled = metadata["_is_compiled"]
|
|
obj.input_quantizers = metadata["input_quantizers"]
|
|
obj.framework = metadata["framework"]
|
|
obj.onnx_model_ = metadata["onnx_model_"]
|
|
obj.output_quantizers = metadata["output_quantizers"]
|
|
obj._fhe_ensembling = metadata["_fhe_ensembling"]
|
|
obj._tree_inference = tree_to_numpy(
|
|
obj.sklearn_model,
|
|
numpy.zeros((len(obj.input_quantizers),))[None, ...],
|
|
framework=obj.framework,
|
|
output_n_bits=obj.n_bits["op_leaves"] if isinstance(obj.n_bits, Dict) else obj.n_bits,
|
|
fhe_ensembling=obj._fhe_ensembling,
|
|
)[0]
|
|
obj.post_processing_params = metadata["post_processing_params"]
|
|
|
|
# Scikit-Learn
|
|
obj.criterion = metadata["criterion"]
|
|
obj.splitter = metadata["splitter"]
|
|
obj.max_depth = metadata["max_depth"]
|
|
obj.min_samples_split = metadata["min_samples_split"]
|
|
obj.min_samples_leaf = metadata["min_samples_leaf"]
|
|
obj.min_weight_fraction_leaf = metadata["min_weight_fraction_leaf"]
|
|
obj.max_features = metadata["max_features"]
|
|
obj.max_leaf_nodes = metadata["max_leaf_nodes"]
|
|
obj.class_weight = metadata["class_weight"]
|
|
obj.random_state = metadata["random_state"]
|
|
obj.min_impurity_decrease = metadata["min_impurity_decrease"]
|
|
obj.ccp_alpha = metadata["ccp_alpha"]
|
|
obj.monotonic_cst = metadata["monotonic_cst"]
|
|
|
|
return obj
|
|
|
|
|
|
# pylint: disable-next=too-many-instance-attributes
|
|
class DecisionTreeRegressor(BaseTreeRegressorMixin):
|
|
"""Implements the sklearn DecisionTreeClassifier."""
|
|
|
|
sklearn_model_class = sklearn.tree.DecisionTreeRegressor
|
|
framework = "sklearn"
|
|
_is_a_public_cml_model = True
|
|
|
|
# pylint: disable-next=too-many-arguments
|
|
def __init__(
|
|
self,
|
|
criterion="squared_error",
|
|
splitter="best",
|
|
max_depth=None,
|
|
min_samples_split=2,
|
|
min_samples_leaf=1,
|
|
min_weight_fraction_leaf=0.0,
|
|
max_features=None,
|
|
random_state=None,
|
|
max_leaf_nodes=None,
|
|
min_impurity_decrease=0.0,
|
|
ccp_alpha=0.0,
|
|
monotonic_cst=None,
|
|
n_bits: Union[int, Dict[str, int]] = 6,
|
|
):
|
|
"""Initialize the DecisionTreeRegressor.
|
|
|
|
# noqa: DAR101
|
|
|
|
"""
|
|
# Call BaseTreeEstimatorMixin's __init__ method
|
|
super().__init__(n_bits=n_bits)
|
|
|
|
self.criterion = criterion
|
|
self.splitter = splitter
|
|
self.max_depth = max_depth
|
|
self.min_samples_split = min_samples_split
|
|
self.min_samples_leaf = min_samples_leaf
|
|
self.min_weight_fraction_leaf = min_weight_fraction_leaf
|
|
self.max_features = max_features
|
|
self.max_leaf_nodes = max_leaf_nodes
|
|
self.random_state = random_state
|
|
self.min_impurity_decrease = min_impurity_decrease
|
|
self.ccp_alpha = ccp_alpha
|
|
self.monotonic_cst = monotonic_cst
|
|
|
|
def __getattr__(self, attr: str):
|
|
# We directly expose the following methods as they are commonly used with decision trees
|
|
# and only represent their topological structure
|
|
if (
|
|
attr in ["get_depth", "get_n_leaves"]
|
|
and getattr(self, "sklearn_model", None) is not None
|
|
):
|
|
return getattr(self.sklearn_model, attr)
|
|
|
|
return super().__getattr__(attr)
|
|
|
|
def dump_dict(self) -> Dict[str, Any]:
|
|
metadata: Dict[str, Any] = {}
|
|
|
|
# TorusML
|
|
metadata["n_bits"] = self.n_bits
|
|
metadata["sklearn_model"] = self.sklearn_model
|
|
metadata["_is_fitted"] = self._is_fitted
|
|
metadata["_is_compiled"] = self._is_compiled
|
|
metadata["input_quantizers"] = self.input_quantizers
|
|
metadata["output_quantizers"] = self.output_quantizers
|
|
metadata["onnx_model_"] = self.onnx_model_
|
|
metadata["framework"] = self.framework
|
|
metadata["post_processing_params"] = self.post_processing_params
|
|
metadata["_fhe_ensembling"] = self._fhe_ensembling
|
|
|
|
# Scikit-Learn
|
|
metadata["criterion"] = self.criterion
|
|
metadata["splitter"] = self.splitter
|
|
metadata["max_depth"] = self.max_depth
|
|
metadata["min_samples_split"] = self.min_samples_split
|
|
metadata["min_samples_leaf"] = self.min_samples_leaf
|
|
metadata["min_weight_fraction_leaf"] = self.min_weight_fraction_leaf
|
|
metadata["max_features"] = self.max_features
|
|
metadata["max_leaf_nodes"] = self.max_leaf_nodes
|
|
metadata["random_state"] = self.random_state
|
|
metadata["min_impurity_decrease"] = self.min_impurity_decrease
|
|
metadata["ccp_alpha"] = self.ccp_alpha
|
|
metadata["monotonic_cst"] = self.monotonic_cst
|
|
|
|
return metadata
|
|
|
|
@classmethod
|
|
def load_dict(cls, metadata: Dict):
|
|
|
|
# Instantiate the model
|
|
obj = cls(n_bits=metadata["n_bits"])
|
|
|
|
# TorusML
|
|
obj.sklearn_model = metadata["sklearn_model"]
|
|
obj._is_fitted = metadata["_is_fitted"]
|
|
obj._fhe_ensembling = metadata["_fhe_ensembling"]
|
|
obj._is_compiled = metadata["_is_compiled"]
|
|
obj.input_quantizers = metadata["input_quantizers"]
|
|
obj.framework = metadata["framework"]
|
|
obj.onnx_model_ = metadata["onnx_model_"]
|
|
obj.output_quantizers = metadata["output_quantizers"]
|
|
obj._fhe_ensembling = metadata["_fhe_ensembling"]
|
|
obj._tree_inference = tree_to_numpy(
|
|
obj.sklearn_model,
|
|
numpy.zeros((len(obj.input_quantizers),))[None, ...],
|
|
framework=obj.framework,
|
|
output_n_bits=obj.n_bits["op_leaves"] if isinstance(obj.n_bits, Dict) else obj.n_bits,
|
|
fhe_ensembling=obj._fhe_ensembling,
|
|
)[0]
|
|
obj.post_processing_params = metadata["post_processing_params"]
|
|
|
|
# Scikit-Learn
|
|
obj.criterion = metadata["criterion"]
|
|
obj.splitter = metadata["splitter"]
|
|
obj.max_depth = metadata["max_depth"]
|
|
obj.min_samples_split = metadata["min_samples_split"]
|
|
obj.min_samples_leaf = metadata["min_samples_leaf"]
|
|
obj.min_weight_fraction_leaf = metadata["min_weight_fraction_leaf"]
|
|
obj.max_features = metadata["max_features"]
|
|
obj.max_leaf_nodes = metadata["max_leaf_nodes"]
|
|
obj.random_state = metadata["random_state"]
|
|
obj.min_impurity_decrease = metadata["min_impurity_decrease"]
|
|
obj.ccp_alpha = metadata["ccp_alpha"]
|
|
obj.monotonic_cst = metadata["monotonic_cst"]
|
|
|
|
return obj
|