binoua commited on
Commit
1bb01e9
1 Parent(s): ac693dc

chore: be closer to our template

Browse files
README.md CHANGED
@@ -1,3 +1,47 @@
1
  ---
2
  license: apache-2.0
3
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
  license: apache-2.0
3
  ---
4
+
5
+ # Template for Concrete ML
6
+
7
+ Concrete ML is Zama's open-source privacy-preserving ML package, based on fully homomorphic encryption (FHE). We refer the reader to fhe.org or Zama's websites for more information on FHE.
8
+
9
+ This directory is used:
10
+ - by ML practicioners, to create Concrete ML FHE-friendly models, and make them available to HF users
11
+ - by companies, institutions or people to deploy those models over HF inference endpoints
12
+ - by developers, to use these entry points to make applications on privacy-preserving ML
13
+
14
+ ## Creating models and making them available on HF
15
+
16
+ This is quite easy. Fork this template (maybe use this experimental tool https://huggingface.co/spaces/huggingface-projects/repo_duplicator for that), and then:
17
+ - install everything with: `pip install -r requirements.txt`
18
+ - edit `creating_models.py`, and fill the part between "# BEGIN: insert your ML task here" and
19
+ "# END: insert your ML task here"
20
+ - run the python file: `python creating_models.py`
21
+
22
+ At the end, if the script is successful, you'll have your compiled model ready in `compiled_model`. Now you can commit and push your repository (with in particular `compiled_model`, `handler.py`, `play_with_endpoint.py` and `requirements.txt`, but you can include the other files as well).
23
+
24
+ We recommend you to tag your Concrete ML compiled repository with `Concrete ML FHE friendly` tag, such that people can find them easily.
25
+
26
+ ## Deploying a compiled model on HF inference endpoint
27
+
28
+ If you find an `Concrete ML FHE friendly` repository that you would like to deploy, it is very easy.
29
+ - click on 'Deploy' button in HF interface
30
+ - chose "Inference endpoints"
31
+ - chose the right model repository
32
+ - (the rest of the options are classical to HF end points; we refer you to their documentation for more information)
33
+ and then click on 'Create endpoint'
34
+
35
+ And now, your model should be deployed, after few secunds of installation.
36
+
37
+ ## Using HF entry points on privacy-preserving models
38
+
39
+ Now, this is the final step: using the entry point. You should:
40
+ - if your inference endpoint is private, set an environment variable HF_TOKEN with your HF token
41
+ - edit `play_with_endpoint.py`
42
+ - replace `API_URL` by your entry point URL
43
+ - replace the part between "# BEGIN: replace this part with your privacy-preserving application" and
44
+ "# END: replace this part with your privacy-preserving application" with your application
45
+
46
+ Finally, you'll be able to launch your application with `python play_with_endpoint.py`.
47
+
compiled_model/client.zip CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:bf41c99b06817bd28d64c681a4294ca4e910e95c0b07837374420643bcec50f7
3
  size 7496
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:21eed25172b9c4988774dbe04306e22f38f2672f8ec9100860bdf0a60baaaa4b
3
  size 7496
compiled_model/server.zip CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:20941390f0eb4c8ac177344a9e5dbdafc93d99c01d16c6ebdb2b3d278fecc36b
3
  size 1258
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:60f49990dd019d24fcadc03ab25dc7788f38ecb38d2230f02a6ff874cb370489
3
  size 1258
create_zipfiles_and_check_local_endpoint.py DELETED
@@ -1,73 +0,0 @@
1
- from handler import EndpointHandler
2
- import numpy as np
3
- import shutil
4
-
5
- from pathlib import Path
6
-
7
- from sklearn.datasets import make_classification
8
- from sklearn.model_selection import train_test_split
9
-
10
- from concrete.ml.sklearn import LogisticRegression
11
- from concrete.ml.deployment import FHEModelClient, FHEModelDev
12
-
13
- # Fit a model. In the future, we should find an existing model on HF repository
14
- path_to_model = Path("compiled_model")
15
- do_training_and_compilation = True
16
-
17
- x, y = make_classification(n_samples=1000, class_sep=2, n_features=30, random_state=42)
18
- X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=42)
19
-
20
- if do_training_and_compilation:
21
- model_dev = LogisticRegression()
22
- model_dev.fit(X_train, y_train)
23
-
24
- # Compile into FHE
25
- model_dev.compile(X_train)
26
-
27
- # Saving the model
28
- shutil.rmtree(path_to_model, ignore_errors=True)
29
- fhemodel_dev = FHEModelDev(path_to_model, model_dev)
30
- fhemodel_dev.save(via_mlir=True)
31
-
32
- # Init the handler (compilation of the model is done on HF side)
33
- my_handler = EndpointHandler(path=".")
34
-
35
- # Recover parameters for client side
36
- fhemodel_client = FHEModelClient(path_to_model)
37
-
38
- # Generate the keys
39
- fhemodel_client.generate_private_and_evaluation_keys()
40
- evaluation_keys = fhemodel_client.get_serialized_evaluation_keys()
41
-
42
- # Test the handler
43
- nb_good = 0
44
- nb_samples = len(X_test)
45
- verbose = False
46
-
47
- for i in range(nb_samples):
48
-
49
- # Quantize the input and encrypt it
50
- encrypted_inputs = fhemodel_client.quantize_encrypt_serialize([X_test[i]])
51
-
52
- # Prepare the payload, including the evaluation keys which are needed server side
53
- payload = {
54
- "inputs": "fake",
55
- "encrypted_inputs": encrypted_inputs,
56
- "evaluation_keys": evaluation_keys,
57
- }
58
-
59
- # Run the inference on HF servers
60
- encrypted_prediction = my_handler(payload)
61
- encrypted_prediction = encrypted_prediction
62
-
63
- # Decrypt the result and dequantize
64
- prediction_proba = fhemodel_client.deserialize_decrypt_dequantize(encrypted_prediction)[0]
65
- prediction = np.argmax(prediction_proba)
66
-
67
- if verbose:
68
- print(f"for i-th input, {prediction=} with expected {y_test[i]}")
69
-
70
- # Measure accuracy
71
- nb_good += y_test[i] == prediction
72
-
73
- print(f"Accuracy on {nb_samples} samples is {nb_good * 1. / nb_samples}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
creating_models.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import shutil
2
+ import sys
3
+ from pathlib import Path
4
+
5
+ from concrete.ml.deployment import FHEModelDev
6
+ from concrete.ml.deployment import FHEModelClient
7
+
8
+
9
+ def compile_and_make_it_deployable(model_dev, X_train):
10
+
11
+ path_to_model = Path("compiled_model")
12
+
13
+ # Compile into FHE
14
+ model_dev.compile(X_train)
15
+
16
+ # Saving the model
17
+ shutil.rmtree(path_to_model, ignore_errors=True)
18
+ fhemodel_dev = FHEModelDev(path_to_model, model_dev)
19
+ fhemodel_dev.save(via_mlir=True)
20
+
21
+
22
+ # BEGIN: insert your ML task here
23
+ # Typically
24
+ from sklearn.datasets import make_classification
25
+ from sklearn.model_selection import train_test_split
26
+
27
+ from concrete.ml.sklearn import LogisticRegression
28
+
29
+ x, y = make_classification(n_samples=1000, class_sep=2, n_features=30, random_state=42)
30
+ X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=42)
31
+
32
+ model_dev = LogisticRegression()
33
+ model_dev.fit(X_train, y_train)
34
+ # END: insert your ML task here
35
+
36
+ compile_and_make_it_deployable(model_dev, X_train)
37
+ print("Your model is ready to be deployable.")
handler.py CHANGED
@@ -49,6 +49,17 @@ class EndpointHandler:
49
 
50
  return {"uid": uid}
51
 
 
 
 
 
 
 
 
 
 
 
 
52
  elif method == "inference":
53
 
54
  uid = data.pop("uid", data)
 
49
 
50
  return {"uid": uid}
51
 
52
+ elif method == "append_key":
53
+
54
+ # Get key piece
55
+ evaluation_keys = from_json(data.pop("evaluation_keys", data))
56
+
57
+ uid = data.pop("uid", data)
58
+
59
+ self.key_database[uid] += evaluation_keys
60
+
61
+ return
62
+
63
  elif method == "inference":
64
 
65
  uid = data.pop("uid", data)
play_with_endpoint.py CHANGED
@@ -53,21 +53,56 @@ fhemodel_client.generate_private_and_evaluation_keys()
53
  evaluation_keys = fhemodel_client.get_serialized_evaluation_keys()
54
 
55
  # Save the key in the database
56
- payload = {
57
- "inputs": "fake",
58
- "evaluation_keys": to_json(evaluation_keys),
59
- "method": "save_key",
60
- }
61
-
62
- uid = query(payload)["uid"]
63
- print(f"Storing the key in the database under {uid=}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
  # Test the handler
66
  nb_good = 0
67
  nb_samples = len(X_test)
68
- verbose = False
69
  time_start = time.time()
70
  duration = 0
 
71
 
72
  for i in range(nb_samples):
73
 
@@ -82,8 +117,9 @@ for i in range(nb_samples):
82
  "uid": uid,
83
  }
84
 
85
- if verbose or True:
86
- print(f"Size of the payload: {sys.getsizeof(payload) / 1024} kilobytes")
 
87
 
88
  # Run the inference on HF servers
89
  duration -= time.time()
@@ -98,7 +134,7 @@ for i in range(nb_samples):
98
  prediction_proba = fhemodel_client.deserialize_decrypt_dequantize(encrypted_prediction)[0]
99
  prediction = np.argmax(prediction_proba)
100
 
101
- if verbose or True:
102
  print(
103
  f"for {i}-th input, {prediction=} with expected {Y_test[i]} in {duration_inference:.3f} seconds"
104
  )
@@ -107,6 +143,5 @@ for i in range(nb_samples):
107
  nb_good += Y_test[i] == prediction
108
 
109
  print(f"Accuracy on {nb_samples} samples is {nb_good * 1. / nb_samples}")
110
- print(f"Total time: {time.time() - time_start} seconds")
111
- print(f"Duration in inferences: {duration} seconds")
112
- print(f"Duration per inference: {duration / nb_samples} seconds")
 
53
  evaluation_keys = fhemodel_client.get_serialized_evaluation_keys()
54
 
55
  # Save the key in the database
56
+ evaluation_keys_remaining = evaluation_keys[:]
57
+ uid = None
58
+ is_first = True
59
+ is_finished = False
60
+ i = 0
61
+ packet_size = 1024 * 1024 * 100
62
+
63
+ while not is_finished:
64
+
65
+ # Send by packets of 100M
66
+ if sys.getsizeof(evaluation_keys_remaining) > packet_size:
67
+ evaluation_keys_piece = evaluation_keys_remaining[:packet_size]
68
+ evaluation_keys_remaining = evaluation_keys_remaining[packet_size:]
69
+ else:
70
+ evaluation_keys_piece = evaluation_keys_remaining
71
+ is_finished = True
72
+
73
+ print(
74
+ f"Sending {i}-th piece of the key (remaining size is {sys.getsizeof(evaluation_keys_remaining) / 1024:.2f} kbytes)"
75
+ )
76
+ i += 1
77
+
78
+ if is_first:
79
+ is_first = False
80
+ payload = {
81
+ "inputs": "fake",
82
+ "evaluation_keys": to_json(evaluation_keys_piece),
83
+ "method": "save_key",
84
+ }
85
+
86
+ uid = query(payload)["uid"]
87
+ print(f"Storing the key in the database under {uid=}")
88
+
89
+ else:
90
+ payload = {
91
+ "inputs": "fake",
92
+ "evaluation_keys": to_json(evaluation_keys_piece),
93
+ "method": "append_key",
94
+ "uid": uid,
95
+ }
96
+
97
+ query(payload)
98
 
99
  # Test the handler
100
  nb_good = 0
101
  nb_samples = len(X_test)
102
+ verbose = True
103
  time_start = time.time()
104
  duration = 0
105
+ is_first = True
106
 
107
  for i in range(nb_samples):
108
 
 
117
  "uid": uid,
118
  }
119
 
120
+ if is_first:
121
+ print(f"Size of the payload: {sys.getsizeof(payload) / 1024:.2f} kilobytes")
122
+ is_first = False
123
 
124
  # Run the inference on HF servers
125
  duration -= time.time()
 
134
  prediction_proba = fhemodel_client.deserialize_decrypt_dequantize(encrypted_prediction)[0]
135
  prediction = np.argmax(prediction_proba)
136
 
137
+ if verbose:
138
  print(
139
  f"for {i}-th input, {prediction=} with expected {Y_test[i]} in {duration_inference:.3f} seconds"
140
  )
 
143
  nb_good += Y_test[i] == prediction
144
 
145
  print(f"Accuracy on {nb_samples} samples is {nb_good * 1. / nb_samples}")
146
+ print(f"Total time: {time.time() - time_start:.3f} seconds")
147
+ print(f"Duration per inference: {duration / nb_samples:.3f} seconds")