Skip to content

Commit

Permalink
docs: update documentation on client / server API (#663)
Browse files Browse the repository at this point in the history
  • Loading branch information
jfrery authored May 21, 2024
1 parent 55f681a commit f864407
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 16 deletions.
3 changes: 0 additions & 3 deletions docs/advanced_examples/ClientServer.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,6 @@
"fhemodel_client = FHEModelClient(network.client_dir.name, key_dir=network.client_dir.name)\n",
"\n",
"# The client first need to create the private and evaluation keys.\n",
"fhemodel_client.generate_private_and_evaluation_keys()\n",
"\n",
"# Get the serialized evaluation keys\n",
"serialized_evaluation_keys = fhemodel_client.get_serialized_evaluation_keys()"
]
},
Expand Down
63 changes: 62 additions & 1 deletion docs/guides/client_server.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,68 @@ The diagram above shows the steps that a developer goes through to prepare a mod

The compiled model (`server.zip`) is deployed to a server and the cryptographic parameters (`client.zip`) are shared with the clients. In some settings, such as a phone application, the `client.zip` can be directly deployed on the client device and the server does not need to host it.

Note that for built-in models, the server output + post-processing adheres to the following guidelines: if the model is a regressor, the output follows the format of the scikit-learn `.predict()` method; if the model is a classifier, the output follows the format of the scikit-learn `.predict_proba()` method.
> **Important Note:** In a client-server production using FHE, the server's output format depends on the model type. For regressors, the output matches the `predict()` method from scikit-learn, providing direct predictions. For classifiers, the output uses the `predict_proba()` method format, offering probability scores for each class, which allows clients to determine class membership by applying a threshold (commonly 0.5).
### Using the API Classes

The `FHEModelDev`, `FHEModelClient`, and `FHEModelServer` classes in the `concrete.ml.deployment` module make it easy to deploy and interact between the client and server:

- **`FHEModelDev`**: This class is used during the development phase to prepare and save the model artifacts (`client.zip` and `server.zip`). It handles the serialization of the underlying FHE circuit as well as the crypto-parameters used for generating the keys.

- **`FHEModelClient`**: This class is used on the client side to generate and serialize the cryptographic keys, encrypt the data before sending it to the server, and decrypt the results received from the server. It also handles the loading of quantization parameters and pre/post-processing from `serialized_processing.json`.

- **`FHEModelServer`**: This class is used on the server side to load the FHE circuit from `server.zip` and execute the model on encrypted data received from the client.

### Example Usage

```python
from concrete.ml.sklearn import DecisionTreeClassifier
from concrete.ml.deployment import FHEModelDev, FHEModelClient, FHEModelServer
import numpy as np

# Define the directory for FHE client/server files
fhe_directory = '/tmp/fhe_client_server_files/'

# Initialize the Decision Tree model
model = DecisionTreeClassifier()

# Generate some random data for training
X = np.random.rand(100, 20)
y = np.random.randint(0, 2, size=100)

# Train and compile the model
model.fit(X, y)
model.compile(X)

# Setup the development environment
dev = FHEModelDev(path_dir=fhe_directory, model=model)
dev.save()

# Setup the client
client = FHEModelClient(path_dir=fhe_directory, key_dir="/tmp/keys_client")
serialized_evaluation_keys = client.get_serialized_evaluation_keys()

# Client pre-processes new data
X_new = np.random.rand(1, 20)
encrypted_data = client.quantize_encrypt_serialize(X_new)

# Setup the server
server = FHEModelServer(path_dir=fhe_directory)
server.load()

# Server processes the encrypted data
encrypted_result = server.run(encrypted_data, serialized_evaluation_keys)

# Client decrypts the result
result = client.deserialize_decrypt_dequantize(encrypted_result)
```

> **Data Transfer Overview:**
>
> - **From Client to Server:** `serialized_evaluation_keys` (once), `encrypted_data`.
> - **From Server to Client:** `encrypted_result`.
These objects are serialized into bytes to streamline the data transfer between the client and server.

## Serving

Expand Down
3 changes: 3 additions & 0 deletions src/concrete/ml/deployment/fhe_client_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,9 @@ def get_serialized_evaluation_keys(self) -> bytes:
Returns:
bytes: the evaluation keys
"""
# Generate private and evaluation keys if not already generated
self.generate_private_and_evaluation_keys(force=False)

return self.client.evaluation_keys.serialize()

def quantize_encrypt_serialize(self, x: numpy.ndarray) -> bytes:
Expand Down
3 changes: 1 addition & 2 deletions src/concrete/ml/torch/hybrid_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,8 @@ def init_fhe_client(
path_dir=str(path_to_client.resolve()), key_dir=str(self.path_to_keys.resolve())
)
# The client first need to create the private and evaluation keys.
client.generate_private_and_evaluation_keys()
# Get the serialized evaluation keys
serialized_evaluation_keys = client.get_serialized_evaluation_keys()

if self.verbose:
print(f"Evaluation keys size: {len(serialized_evaluation_keys) / (10**6):.2f} MB")
assert isinstance(serialized_evaluation_keys, bytes)
Expand Down
1 change: 0 additions & 1 deletion tests/deployment/test_client_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,6 @@ def check_client_server_execution(
fhe_model_server.load()

# Client side : Generate all keys and serialize the evaluation keys for the server
fhe_model_client.generate_private_and_evaluation_keys()
evaluation_keys = fhe_model_client.get_serialized_evaluation_keys()

# Client side : Encrypt the data
Expand Down
4 changes: 1 addition & 3 deletions use_case_examples/deployment/breast_cancer/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,8 @@
client = FHEModelClient(path_dir=str(ROOT.resolve()), key_dir=str((ROOT / "keys").resolve()))

# The client first need to create the private and evaluation keys.
client.generate_private_and_evaluation_keys()

# Get the serialized evaluation keys
serialized_evaluation_keys = client.get_serialized_evaluation_keys()

assert isinstance(serialized_evaluation_keys, bytes)

# Evaluation keys can be quite large files but only have to be shared once with the server.
Expand Down
4 changes: 1 addition & 3 deletions use_case_examples/deployment/cifar/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,8 @@ def main():
client = FHEModelClient(path_dir="./", key_dir="./keys")

# The client first need to create the private and evaluation keys.
client.generate_private_and_evaluation_keys()

# Get the serialized evaluation keys
serialized_evaluation_keys = client.get_serialized_evaluation_keys()

assert isinstance(serialized_evaluation_keys, bytes)

# Evaluation keys can be quite large files but only have to be shared once with the server.
Expand Down
4 changes: 1 addition & 3 deletions use_case_examples/deployment/sentiment_analysis/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,8 @@ def main():
client = FHEModelClient(path_dir="./", key_dir="./keys")

# The client first need to create the private and evaluation keys.
client.generate_private_and_evaluation_keys()

# Get the serialized evaluation keys
serialized_evaluation_keys = client.get_serialized_evaluation_keys()

assert isinstance(serialized_evaluation_keys, bytes)
# Evaluation keys can be quite large files but only have to be shared once with the server.
# Check the size of the evaluation keys (in MB)
Expand Down

0 comments on commit f864407

Please sign in to comment.