From 274f0e440b3aae5445a90cf725cdd8d227d411ac Mon Sep 17 00:00:00 2001 From: Benoit Chevallier-Mames <64148533+bcm-at-zama@users.noreply.github.com> Date: Thu, 28 Sep 2023 10:08:55 +0200 Subject: [PATCH] chore: updating the CP version --- Makefile | 2 +- deps_licenses/licenses_linux_user.txt | 2 +- deps_licenses/licenses_linux_user.txt.md5 | 2 +- .../ConvolutionalNeuralNetwork.ipynb | 3 - src/concrete/ml/common/utils.py | 34 ----- src/concrete/ml/sklearn/base.py | 121 ++++++++---------- 6 files changed, 57 insertions(+), 107 deletions(-) diff --git a/Makefile b/Makefile index d00d2447a..c7f681116 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ OPEN_PR="true" # If one wants to force the installation of a given rc version # /!\ WARNING /!\: This version should NEVER be a wildcard as it might create some # issues when trying to run it in the future. -CP_VERSION_SPEC_FOR_RC="concrete-python==2.2.0" +CP_VERSION_SPEC_FOR_RC="concrete-python==2.4.0rc1" # If one wants to use the last RC version # CP_VERSION_SPEC_FOR_RC="$$(poetry run python \ diff --git a/deps_licenses/licenses_linux_user.txt b/deps_licenses/licenses_linux_user.txt index 4d91dbb7e..15ccaca94 100644 --- a/deps_licenses/licenses_linux_user.txt +++ b/deps_licenses/licenses_linux_user.txt @@ -9,7 +9,7 @@ certifi, 2023.7.22, Mozilla Public License 2.0 (MPL 2.0) charset-normalizer, 3.2.0, MIT License click, 8.1.7, BSD License coloredlogs, 15.0.1, MIT License -concrete-python, 2.2.0, BSD-3-Clause +concrete-python, 2.4.0rc1, BSD-3-Clause dependencies, 2.0.1, BSD License dill, 0.3.7, BSD License exceptiongroup, 1.1.3, MIT License diff --git a/deps_licenses/licenses_linux_user.txt.md5 b/deps_licenses/licenses_linux_user.txt.md5 index f30af8929..a1e7515a2 100644 --- a/deps_licenses/licenses_linux_user.txt.md5 +++ b/deps_licenses/licenses_linux_user.txt.md5 @@ -1 +1 @@ -88fe2fa1ad3c3d2c74d44e85dd4d9662 +60ba8097c49614bc52a447b05062107f diff --git a/docs/advanced_examples/ConvolutionalNeuralNetwork.ipynb b/docs/advanced_examples/ConvolutionalNeuralNetwork.ipynb index d11009f68..b5902e4fc 100644 --- a/docs/advanced_examples/ConvolutionalNeuralNetwork.ipynb +++ b/docs/advanced_examples/ConvolutionalNeuralNetwork.ipynb @@ -525,9 +525,6 @@ "metadata": { "execution": { "timeout": 10800 - }, - "language_info": { - "name": "python" } }, "nbformat": 4, diff --git a/src/concrete/ml/common/utils.py b/src/concrete/ml/common/utils.py index 5e08cbe71..77230f15d 100644 --- a/src/concrete/ml/common/utils.py +++ b/src/concrete/ml/common/utils.py @@ -9,8 +9,6 @@ import numpy import onnx import torch -from concrete.fhe import ParameterSelectionStrategy -from concrete.fhe.compilation.configuration import Configuration from concrete.fhe.dtypes import Integer from sklearn.base import is_classifier, is_regressor @@ -584,35 +582,3 @@ def all_values_are_of_dtype(*values: Any, dtypes: Union[str, List[str]]) -> bool supported_dtypes[dtype] = supported_dtype return all(_is_of_dtype(value, supported_dtypes) for value in values) - - -# Remove this function once Concrete Python fixes the multi-parameter bug with KNN -# circuits -# FIXME: https://github.com/zama-ai/concrete-ml-internal/issues/3978 -def force_mono_parameter_in_configuration(configuration: Optional[Configuration], **kwargs): - """Force configuration to mono-parameter strategy. - - If the given Configuration instance is None, build a new instance with mono-parameter and the - additional keyword arguments. - - Args: - configuration (Optional[Configuration]): The configuration to consider. - **kwargs: Additional parameters to use for instantiating a new Configuration instance, if - configuration is None. - - Returns: - configuration (Configuration): A configuration with mono-parameter strategy. - """ - assert ( - "parameter_selection_strategy" not in kwargs - ), "Please do not provide a parameter_selection_strategy parameter as it will be set to MONO." - - if configuration is None: - configuration = Configuration( - parameter_selection_strategy=ParameterSelectionStrategy.MONO, **kwargs - ) - - else: - configuration.parameter_selection_strategy = ParameterSelectionStrategy.MONO - - return configuration diff --git a/src/concrete/ml/sklearn/base.py b/src/concrete/ml/sklearn/base.py index c7c8d812c..1978f0fdf 100644 --- a/src/concrete/ml/sklearn/base.py +++ b/src/concrete/ml/sklearn/base.py @@ -14,6 +14,7 @@ from typing import Any, Callable, Dict, List, Optional, Set, TextIO, Type, Union import brevitas.nn as qnn +import concrete.fhe as cnp import numpy import onnx import sklearn @@ -37,7 +38,6 @@ USE_OLD_VL, FheMode, check_there_is_no_p_error_options_in_configuration, - force_mono_parameter_in_configuration, generate_proxy_function, manage_parameters_for_pbs_errors, ) @@ -1999,56 +1999,59 @@ def scatter1d(x, v, indices): # d: Length of the bitonic sequence d = p - for bq in range(ln2n - 1, t - 1, -1): - q = 2**bq - # Determine the range of indexes to be compared - range_i = numpy.array( - [i for i in range(0, n - d) if i & p == r and comparisons[i] < k] - ) - if len(range_i) == 0: - # Edge case, for k=1 - continue - - # Select 2 bitonic sequences `a` and `b` of length `d` - # a = x[range_i]: first bitonic sequence - # a_i = idx[range_i]: Indexes of a_i elements in the original x - a = gather1d(x, range_i) - # a_i = gather1d(idx, range_i) - # b = x[range_i + d]: Second bitonic sequence - # b_i = idx[range_i + d]: Indexes of b_i elements in the original x - b = gather1d(x, range_i + d) - # b_i = gather1d(idx, range_i + d) - - labels_a = gather1d(labels, range_i) # - labels_b = gather1d(labels, range_i + d) # idx[range_i + d] - - # Select max(a, b) - diff = a - b - max_x = a + numpy.maximum(0, b - a) - - # Swap if a > b - # x[range_i] = max_x(a, b): First bitonic sequence gets min(a, b) - x = scatter1d(x, a + b - max_x, range_i) - # x[range_i + d] = min(a, b): Second bitonic sequence gets max(a, b) - x = scatter1d(x, max_x, range_i + d) - - # Max index selection - is_a_greater_than_b = diff <= 0 - - # Update labels array according to the max items - max_labels = labels_a + (labels_b - labels_a) * is_a_greater_than_b - labels = scatter1d(labels, labels_a + labels_b - max_labels, range_i) - labels = scatter1d(labels, max_labels, range_i + d) - - # Update - comparisons[range_i + d] = comparisons[range_i + d] + 1 - d = q - p - r = p - - # Return only the topk indexes - topk_labels = fhe_array(labels[:k]) - - return topk_labels + with cnp.tag(f"top_k_t_{t}"): + for bq in range(ln2n - 1, t - 1, -1): + q = 2**bq + # Determine the range of indexes to be compared + range_i = numpy.array( + [i for i in range(0, n - d) if i & p == r and comparisons[i] < k] + ) + if len(range_i) == 0: + # Edge case, for k=1 + continue + + # Select 2 bitonic sequences `a` and `b` of length `d` + # a = x[range_i]: first bitonic sequence + # a_i = idx[range_i]: Indexes of a_i elements in the original x + a = gather1d(x, range_i) + # a_i = gather1d(idx, range_i) + # b = x[range_i + d]: Second bitonic sequence + # b_i = idx[range_i + d]: Indexes of b_i elements in the original x + b = gather1d(x, range_i + d) + # b_i = gather1d(idx, range_i + d) + + labels_a = gather1d(labels, range_i) # + labels_b = gather1d(labels, range_i + d) # idx[range_i + d] + + with cnp.tag("max"): + # Select max(a, b) + diff = a - b + max_x = a + numpy.maximum(0, b - a) + + # Swap if a > b + # x[range_i] = max_x(a, b): First bitonic sequence gets min(a, b) + x = scatter1d(x, a + b - max_x, range_i) + # x[range_i + d] = min(a, b): Second bitonic sequence gets max(a, b) + x = scatter1d(x, max_x, range_i + d) + + with cnp.tag("sign"): + # Max index selection + is_a_greater_than_b = diff <= 0 + + # Update labels array according to the max items + with cnp.tag("label_swap"): + max_labels = labels_a + (labels_b - labels_a) * is_a_greater_than_b + + with cnp.tag("label_set"): + labels = scatter1d(labels, labels_a + labels_b - max_labels, range_i) + labels = scatter1d(labels, max_labels, range_i + d) + + # Update + comparisons[range_i + d] = comparisons[range_i + d] + 1 + d = q - p + r = p + + return labels[0 : self.n_neighbors] # 1. Pairwise_euclidiean distance distance_matrix = pairwise_euclidean_distance(q_X) @@ -2062,23 +2065,7 @@ def scatter1d(x, v, indices): return numpy.expand_dims(topk_labels, axis=0) - # KNN works only for MONO in the latest concrete Python version - # FIXME: https://github.com/zama-ai/concrete-ml-internal/issues/3978 def compile(self, *args, **kwargs) -> Circuit: - # If a configuration instance is given as a positional parameter, set the strategy to - # multi-parameter - if len(args) >= 2: - configuration = force_mono_parameter_in_configuration(args[1]) - args_list = list(args) - args_list[1] = configuration - args = tuple(args_list) - - # Else, retrieve the configuration in kwargs if it exists, or create a new one, and set the - # strategy to multi-parameter - else: - configuration = kwargs.get("configuration", None) - kwargs["configuration"] = force_mono_parameter_in_configuration(configuration) - return BaseEstimator.compile(self, *args, **kwargs) def post_processing(self, y_preds: numpy.ndarray) -> numpy.ndarray: