Skip to content

Commit

Permalink
feat: add multi-output support
Browse files Browse the repository at this point in the history
  • Loading branch information
fd0r committed Dec 5, 2023
1 parent 0b57c71 commit 9543d4b
Show file tree
Hide file tree
Showing 51 changed files with 4,363 additions and 4,646 deletions.
5 changes: 4 additions & 1 deletion .gitleaksignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@
2d3b4ca188efb338c03d8d2c921ef39ffc5537e3:tests/deployment/test_deployment.py:generic-api-key:59
198d3fef188aaf3e3a582b9f7943f7ac6e9b5186:tests/deployment/test_deployment.py:generic-api-key:59
5abc7e86bb192e1f9f829bb2f22173c9d663e1d1:use_case_examples/credit_scoring/CreditScoringWithGraphics.ipynb:easypost-test-api-token:1414
e2904473898ddd325f245f4faca526a0e9520f49:builders/Dockerfile.zamalang-env:generic-api-key:5
a99389ee01cbb972e46a892d3d0e9c7f8ee23f59:use_case_examples/training/analyze.ipynb:easypost-api-token:4651
a99389ee01cbb972e46a892d3d0e9c7f8ee23f59:use_case_examples/training/analyze.ipynb:aws-access-token:18379
f41de03048a9ed27946b875e81b34138bb4bb17b:use_case_examples/training/analyze.ipynb:aws-access-token:6404
e2904473898ddd325f245f4faca526a0e9520f49:builders/Dockerfile.zamalang-env:generic-api-key:5
20 changes: 10 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ OPEN_PR="true"
# Force the installation of a Concrete Python version, which is very useful with nightly versions
# /!\ WARNING /!\: This version should NEVER be a wildcard as it might create some
# issues when trying to run it in the future.
CONCRETE_PYTHON_VERSION="concrete-python==2.5.0rc1"
CONCRETE_PYTHON_VERSION="concrete-python==2023.12.5"

# Force the installation of Concrete Python's latest version, release-candidates included
# CONCRETE_PYTHON_VERSION="$$(poetry run python \
Expand All @@ -32,30 +32,30 @@ setup_env:
@# The keyring install is to allow pip to fetch credentials for our internal repo if needed
PIP_INDEX_URL=https://pypi.org/simple \
PIP_EXTRA_INDEX_URL=https://pypi.org/simple \
poetry run python --version
poetry run python -m pip install keyring
poetry run python -m pip install -U pip wheel
python -m poetry run python --version
python -m poetry run python -m pip install keyring
python -m poetry run python -m pip install -U pip wheel

@# Only for linux and docker, reinstall setuptools. On macOS, it creates warnings, see 169
if [[ $$(uname) != "Darwin" ]]; then \
poetry run python -m pip install -U --force-reinstall setuptools; \
python -m poetry run python -m pip install -U --force-reinstall setuptools; \
fi
if [[ $$(uname) != "Linux" ]] && [[ $$(uname) != "Darwin" ]]; then \
poetry install --only dev; \
python -m poetry install --only dev; \
else \
poetry install; \
python -m poetry install; \
fi

echo "Installing $(CONCRETE_PYTHON_VERSION)" && \
poetry run python -m pip install -U --pre "$(CONCRETE_PYTHON_VERSION)" --no-deps
python -m poetry run python -m pip install -U --pre "$(CONCRETE_PYTHON_VERSION)"
"$(MAKE)" fix_omp_issues_for_intel_mac

.PHONY: sync_env # Synchronise the environment
sync_env: check_poetry_version
if [[ $$(uname) != "Linux" ]] && [[ $$(uname) != "Darwin" ]]; then \
poetry install --remove-untracked --only dev; \
python -m poetry install --remove-untracked --only dev; \
else \
poetry install --remove-untracked; \
python -m poetry install --remove-untracked; \
fi
"$(MAKE)" setup_env

Expand Down
1 change: 0 additions & 1 deletion benchmarks/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,6 @@
enable_unsafe_features=True,
use_insecure_key_cache=True,
insecure_key_cache_location="ConcreteNumpyKeyCache",
jit=False,
)


Expand Down
4 changes: 3 additions & 1 deletion benchmarks/deep_learning.py
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,9 @@ def evaluate_pre_trained_cnn_model(dataset: str, cnn_class: type, config: dict,
metric_label_prefix="Torch fp32",
)

circuit_bitwidth = fhe_module.fhe_circuit.graph.maximum_integer_bit_width()
circuit_bitwidth = fhe_module.fhe_circuit.graph.maximum_integer_bit_width(
is_encrypted_filter=True
)

progress.measure(
id="maximum-circuit-bit-width",
Expand Down
2 changes: 1 addition & 1 deletion conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ def check_circuit_has_no_tlu_impl(circuit: Circuit):

def check_circuit_precision_impl(circuit: Circuit):
"""Check a circuit doesn't need too much precision."""
circuit_precision = circuit.graph.maximum_integer_bit_width()
circuit_precision = circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)
if circuit_precision > MAXIMUM_TLU_BIT_WIDTH:
raise AssertionError(
f"The circuit is precision is expected to be less than {MAXIMUM_TLU_BIT_WIDTH}. "
Expand Down
4 changes: 2 additions & 2 deletions deps_licenses/licenses_linux_user.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.5.0rc1, BSD-3-Clause
concrete-python, 2023.12.5, BSD-3-Clause
dependencies, 2.0.1, BSD License
dill, 0.3.7, BSD License
exceptiongroup, 1.1.3, MIT License
Expand Down Expand Up @@ -72,4 +72,4 @@ typing_extensions, 4.5.0, Python Software Foundation License
urllib3, 1.26.16, MIT License
uvicorn, 0.21.1, BSD License
xgboost, 1.6.2, Apache Software License
z3-solver, 4.12.2.0, MIT License
z3-solver, 4.12.3.0, MIT License
2 changes: 1 addition & 1 deletion deps_licenses/licenses_linux_user.txt.md5
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6e23de913fba55c72e9420fdef5e78de
b19adb1c64bd8c6e86f8374568b1cca7
4 changes: 2 additions & 2 deletions deps_licenses/licenses_mac_intel_user.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.5.0rc1, BSD-3-Clause
concrete-python, 2023.12.5, BSD-3-Clause
dependencies, 2.0.1, BSD License
dill, 0.3.7, BSD License
exceptiongroup, 1.1.3, MIT License
Expand Down Expand Up @@ -68,4 +68,4 @@ typing_extensions, 4.5.0, Python Software Foundation License
urllib3, 1.26.16, MIT License
uvicorn, 0.21.1, BSD License
xgboost, 1.6.2, Apache Software License
z3-solver, 4.12.2.0, MIT License
z3-solver, 4.12.3.0, MIT License
2 changes: 1 addition & 1 deletion deps_licenses/licenses_mac_intel_user.txt.md5
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6e23de913fba55c72e9420fdef5e78de
b19adb1c64bd8c6e86f8374568b1cca7
4 changes: 2 additions & 2 deletions deps_licenses/licenses_mac_silicon_user.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.5.0rc1, BSD-3-Clause
concrete-python, 2023.12.5, BSD-3-Clause
dependencies, 2.0.1, BSD License
dill, 0.3.7, BSD License
exceptiongroup, 1.1.3, MIT License
Expand Down Expand Up @@ -68,4 +68,4 @@ typing_extensions, 4.5.0, Python Software Foundation License
urllib3, 1.26.16, MIT License
uvicorn, 0.21.1, BSD License
xgboost, 1.6.2, Apache Software License
z3-solver, 4.12.2.0, MIT License
z3-solver, 4.12.3.0, MIT License
2 changes: 1 addition & 1 deletion deps_licenses/licenses_mac_silicon_user.txt.md5
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6e23de913fba55c72e9420fdef5e78de
b19adb1c64bd8c6e86f8374568b1cca7
4 changes: 2 additions & 2 deletions docs/advanced-topics/compilation.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ Moreover, the maximum accumulator bit-width is determined as follows:
<!--pytest-codeblocks:skip-->

```python
bit_width = clf.quantized_module_.fhe_circuit.graph.maximum_integer_bit_width()
bit_width = clf.quantized_module_.fhe_circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)
```

## A simple Concrete example
Expand Down Expand Up @@ -127,7 +127,7 @@ inputset = numpy.arange(0, 2**n_bits_input).reshape(-1, 1)
circuit = linear_model.compile(inputset)

# Use the API to get the maximum bit-width in the circuit
max_bit_width = circuit.graph.maximum_integer_bit_width()
max_bit_width = circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)
print("Max bit_width = ", max_bit_width)
# Max bit_width = 4

Expand Down
3 changes: 2 additions & 1 deletion docs/advanced_examples/DecisionTreeClassifier.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,8 @@
}
],
"source": [
"print(f\"Generating a key for an {circuit.graph.maximum_integer_bit_width()}-bit circuit\")"
"max_bit_width = circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)\n",
"print(f\"Generating a key for an {max_bit_width}-bit circuit\")"
]
},
{
Expand Down
6 changes: 4 additions & 2 deletions docs/advanced_examples/DecisionTreeRegressor.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,8 @@
}
],
"source": [
"print(f\"Generating a key for an {circuit.graph.maximum_integer_bit_width()}-bit circuit\")\n",
"max_bit_width = circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)\n",
"print(f\"Generating a key for an {max_bit_width}-bit circuit\")\n",
"time_begin = time.time()\n",
"circuit.client.keygen(force=False)\n",
"print(f\"Key generation time: {time.time() - time_begin:.2f} seconds\")"
Expand Down Expand Up @@ -700,7 +701,8 @@
" begin = time.time()\n",
" circuit = model.compile(x_train)\n",
" print(f\"Circuit compiled with {len(x_train)} samples in {(time.time() - begin):.4f} seconds\")\n",
" print(f\"Generating a key for an {circuit.graph.maximum_integer_bit_width()}-bit circuit\")\n",
" max_bit_width = circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)\n",
" print(f\"Generating a key for an {max_bit_width}-bit circuit\")\n",
" time_begin = time.time()\n",
" circuit.client.keygen(force=False)\n",
" print(f\"Key generation time: {time.time() - time_begin:.2f} seconds\")\n",
Expand Down
3 changes: 2 additions & 1 deletion docs/advanced_examples/FullyConnectedNeuralNetwork.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@
}
],
"source": [
"print(\"Generating a key for a \" f\"{fhe_circuit.graph.maximum_integer_bit_width()}-bit circuit\")"
"max_bit_width = fhe_circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)\n",
"print(\"Generating a key for a \" f\"{max_bit_width}-bit circuit\")"
]
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,8 @@
"simulated_fhe_circuit = model.compile(inputset)\n",
"\n",
"# Print the circuit's maximum bit-width reached during compilation\n",
"print(f\"Circuit of {simulated_fhe_circuit.graph.maximum_integer_bit_width()}-bits (FHE simulation)\")"
"max_bit_width = simulated_fhe_circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)\n",
"print(f\"Circuit of {max_bit_width}-bits (FHE simulation)\")"
]
},
{
Expand Down Expand Up @@ -360,7 +361,8 @@
],
"source": [
"# Print the circuit's maximum bit-width reached during compilation\n",
"print(f\"FHE circuit of {model.fhe_circuit.graph.maximum_integer_bit_width()}-bits\")\n",
"max_bit_width = model.fhe_circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)\n",
"print(f\"FHE circuit of {max_bit_width}-bits\")\n",
"\n",
"time_begin = time.time()\n",
"model.fhe_circuit.client.keygen(force=True)\n",
Expand Down
6 changes: 2 additions & 4 deletions docs/advanced_examples/GLMComparison.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -452,10 +452,8 @@
" circuit = concrete_glm.compile(x_train_subset)\n",
"\n",
" # Generate the key\n",
" print(\n",
" \"Generating a key for an \"\n",
" f\"{circuit.graph.maximum_integer_bit_width()}-bit circuit\"\n",
" )\n",
" max_bit_width = circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)\n",
" print(\"Generating a key for an \" f\"{max_bit_width}-bit circuit\")\n",
" sys.stdout.flush()\n",
"\n",
" time_begin = time.time()\n",
Expand Down
3 changes: 2 additions & 1 deletion docs/advanced_examples/KNearestNeighbors.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@
}
],
"source": [
"print(f\"Maximum bit-width reached in the circuit: {circuit.graph.maximum_integer_bit_width()}\")"
"max_bit_width = circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)\n",
"print(f\"Maximum bit-width reached in the circuit: {max_bit_width}\")"
]
},
{
Expand Down
3 changes: 2 additions & 1 deletion docs/advanced_examples/LinearRegression.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,8 @@
}
],
"source": [
"print(f\"Generating a key for a {fhe_circuit.graph.maximum_integer_bit_width()}-bit circuit\")"
"max_bit_width = fhe_circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)\n",
"print(f\"Generating a key for a {max_bit_width}-bit circuit\")"
]
},
{
Expand Down
3 changes: 2 additions & 1 deletion docs/advanced_examples/LinearSVR.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -573,8 +573,9 @@
}
],
"source": [
"max_bit_width = circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)\n",
"# Generate the key\n",
"print(f\"Generating a key for an {circuit.graph.maximum_integer_bit_width()}-bit circuit\")"
"print(f\"Generating a key for an {max_bit_width}-bit circuit\")"
]
},
{
Expand Down
3 changes: 2 additions & 1 deletion docs/advanced_examples/LogisticRegression.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,8 @@
}
],
"source": [
"print(f\"Generating a key for an {fhe_circuit.graph.maximum_integer_bit_width()}-bit circuit\")"
"max_bit_width = fhe_circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)\n",
"print(f\"Generating a key for an {max_bit_width}-bit circuit\")"
]
},
{
Expand Down
6 changes: 4 additions & 2 deletions docs/advanced_examples/PoissonRegression.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,8 @@
}
],
"source": [
"print(f\"Generating a key for an {fhe_circuit.graph.maximum_integer_bit_width()}-bit circuit\")"
"max_bit_width = fhe_circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)\n",
"print(f\"Generating a key for an {max_bit_width}-bit circuit\")"
]
},
{
Expand Down Expand Up @@ -1062,7 +1063,8 @@
}
],
"source": [
"print(f\"Generating a key for an {fhe_circuit.graph.maximum_integer_bit_width()}-bit circuit\")"
"max_bit_width = fhe_circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)\n",
"print(f\"Generating a key for an {max_bit_width}-bit circuit\")"
]
},
{
Expand Down
4 changes: 3 additions & 1 deletion docs/advanced_examples/QuantizationAwareTraining.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,9 @@
" print(f\"Compilation finished in {end_compile - start_compile:.2f} seconds\")\n",
"\n",
" # Check that the network is compatible with FHE constraints\n",
" bitwidth = quantized_numpy_module.fhe_circuit.graph.maximum_integer_bit_width()\n",
" bitwidth = quantized_numpy_module.fhe_circuit.graph.maximum_integer_bit_width(\n",
" is_encrypted_filter=True\n",
" )\n",
" print(\n",
" f\"Max bit-width: {bitwidth} bits\" + \" -> it works in FHE!!\"\n",
" if bitwidth <= 16\n",
Expand Down
7 changes: 3 additions & 4 deletions docs/advanced_examples/RegressorComparison.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,8 @@
" # Compile the Contrete-ML model\n",
" circuit = concrete_model.compile(X_poly_train)\n",
"\n",
" print(\n",
" \"Generating a key for a \" f\"{circuit.graph.maximum_integer_bit_width()}-bit circuit\"\n",
" )\n",
" max_bit_width = circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)\n",
" print(\"Generating a key for a \" f\"{max_bit_width}-bit circuit\")\n",
"\n",
" time_begin = time.time()\n",
" circuit.client.keygen(force=False)\n",
Expand Down Expand Up @@ -273,7 +272,7 @@
" # reached within its circuit.\n",
" bitwidth = None\n",
" if not is_a_tree_based_model:\n",
" bitwidth = circuit.graph.maximum_integer_bit_width()\n",
" bitwidth = circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)\n",
"\n",
" # Plot the predictions\n",
" ax.plot(X_test, concrete_y_pred, c=\"blue\", linewidth=2.5, label=\"Concrete-ML\")\n",
Expand Down
3 changes: 2 additions & 1 deletion docs/advanced_examples/SVMClassifier.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,8 @@
"y_pred = svm_concrete.predict(X_test, fhe=\"execute\")\n",
"accuracy = accuracy_score(y_test, y_pred)\n",
"# print the accuracy\n",
"print(f\"FHE Accuracy: {accuracy:.4f} (bit width: {circuit.graph.maximum_integer_bit_width()})\")"
"max_bit_width = circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)\n",
"print(f\"FHE Accuracy: {accuracy:.4f} (bit width: {max_bit_width})\")"
]
},
{
Expand Down
3 changes: 2 additions & 1 deletion docs/advanced_examples/XGBClassifier.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,8 @@
],
"source": [
"# Generate the key\n",
"print(f\"Generating a key for an {circuit.graph.maximum_integer_bit_width()}-bit circuit\")"
"max_bit_width = circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)\n",
"print(f\"Generating a key for an {max_bit_width}-bit circuit\")"
]
},
{
Expand Down
3 changes: 2 additions & 1 deletion docs/advanced_examples/XGBRegressor.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,8 @@
"# an exhaustive set of data to mainly evaluate the maximum integer bit-width within the graph,\n",
"# needed during the FHE computations.\n",
"circuit = concrete_reg.compile(X_train)\n",
"print(f\"Generating a key for an {circuit.graph.maximum_integer_bit_width()}-bits circuit\")\n",
"max_bit_width = circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)\n",
"print(f\"Generating a key for an {max_bit_width}-bits circuit\")\n",
"\n",
"# Key generation:\n",
"# The compiler returns a circuit, which can then be used for the key generation.\n",
Expand Down
4 changes: 2 additions & 2 deletions docs/advanced_examples/utils/classifier_comparison_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def make_classifier_comparison(title, classifiers, decision_level, verbose=False
if verbose:
print(
"Generating a key for a "
f"{circuit.graph.maximum_integer_bit_width()}-bit circuit"
f"{circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)}-bit circuit"
)

time_begin = time.time()
Expand Down Expand Up @@ -167,7 +167,7 @@ def make_classifier_comparison(title, classifiers, decision_level, verbose=False
# reached within its circuit.
bitwidth = None
if not is_a_tree_based_model:
bitwidth = circuit.graph.maximum_integer_bit_width()
bitwidth = circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True)

# Plot the decision boundaries.
# For that, a color is assigned to each point in the mesh, which is obtained as a
Expand Down
2 changes: 1 addition & 1 deletion docs/deep-learning/fhe_assistant.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ Retrieving the bit-width of the circuit is then simply:
<!--pytest-codeblocks:cont-->

```python
print(quantized_numpy_module.fhe_circuit.graph.maximum_integer_bit_width())
print(quantized_numpy_module.fhe_circuit.graph.maximum_integer_bit_width(is_encrypted_filter=True))
```

Decreasing the number of bits and the number of PBS applications induces large reductions in the computation time of the compiled circuit.
Loading

0 comments on commit 9543d4b

Please sign in to comment.