romanbredehoft-zama commited on
Commit
8e0d56d
1 Parent(s): 61cd73f

Rename to applicant and credit bureau

Browse files
app.py CHANGED
@@ -22,9 +22,9 @@ from settings import (
22
  )
23
  from backend import (
24
  keygen_send,
25
- pre_process_encrypt_send_user,
26
  pre_process_encrypt_send_bank,
27
- pre_process_encrypt_send_cs_agency,
28
  run_fhe,
29
  get_output_and_decrypt,
30
  explain_encrypt_run_decrypt,
@@ -61,7 +61,7 @@ with demo:
61
  """
62
  )
63
 
64
- gr.Markdown("# Client, Bank and Credit Scoring Agency setup")
65
 
66
  gr.Markdown("## Step 1: Generate the keys.")
67
  gr.Markdown(
@@ -90,10 +90,11 @@ with demo:
90
  """
91
  Select the information that corresponds to the profile you want to evaluate. Three sources
92
  of information are represented in this model:
93
- - a user's personal information in order to evaluate his/her credit card eligibility;
94
- - the user’s bank account history, which provides any type of information on the user's
95
- banking information relevant to the decision (here, we consider duration of account);
96
- - and credit scoring agency information, which represents any other information (here,
 
97
  employment history) that could provide additional insight relevant to the decision.
98
 
99
  Please always encrypt and send the values (through the buttons on the right) once updated
@@ -103,7 +104,7 @@ with demo:
103
 
104
  with gr.Row():
105
  with gr.Column():
106
- gr.Markdown("### User")
107
  bool_inputs = gr.CheckboxGroup(
108
  ["Car", "Property", "Mobile phone"],
109
  label="Which of the following do you actively hold or own?"
@@ -167,15 +168,15 @@ with demo:
167
  )
168
 
169
  with gr.Column():
170
- encrypt_button_user = gr.Button("Encrypt the inputs and send to server.")
171
 
172
- encrypted_input_user = gr.Textbox(
173
  label="Encrypted input representation:", max_lines=2, interactive=False
174
  )
175
 
176
  with gr.Row():
177
  with gr.Column(scale=2):
178
- gr.Markdown("### Bank ")
179
  account_age = gr.Slider(
180
  **ACCOUNT_MIN_MAX,
181
  step=1,
@@ -192,7 +193,7 @@ with demo:
192
 
193
  with gr.Row():
194
  with gr.Column(scale=2):
195
- gr.Markdown("### Credit Scoring Agency ")
196
  employed = gr.Radio(["Yes", "No"], label="Is the person employed ?", value="Yes")
197
  years_employed = gr.Dropdown(
198
  choices=YEARS_EMPLOYED_BINS,
@@ -202,19 +203,19 @@ with demo:
202
  )
203
 
204
  with gr.Column():
205
- encrypt_button_cs_agency = gr.Button("Encrypt the inputs and send to server.")
206
 
207
- encrypted_input_cs_agency = gr.Textbox(
208
  label="Encrypted input representation:", max_lines=2, interactive=False
209
  )
210
 
211
- # Button to pre-process, generate the key, encrypt and send the user inputs from the client
212
  # side to the server
213
- encrypt_button_user.click(
214
- pre_process_encrypt_send_user,
215
  inputs=[client_id, bool_inputs, num_children, household_size, total_income, age, \
216
  income_type, education_type, family_status, occupation_type, housing_type],
217
- outputs=[encrypted_input_user],
218
  )
219
 
220
  # Button to pre-process, generate the key, encrypt and send the bank inputs from the client
@@ -225,12 +226,12 @@ with demo:
225
  outputs=[encrypted_input_bank],
226
  )
227
 
228
- # Button to pre-process, generate the key, encrypt and send the credit scoring agency inputs from the
229
  # client side to the server
230
- encrypt_button_cs_agency.click(
231
- pre_process_encrypt_send_cs_agency,
232
  inputs=[client_id, years_employed, employed],
233
- outputs=[encrypted_input_cs_agency],
234
  )
235
 
236
  gr.Markdown("# Server side")
@@ -253,10 +254,10 @@ with demo:
253
  # Button to send the encodings to the server using post method
254
  execute_fhe_button.click(run_fhe, inputs=[client_id], outputs=[fhe_execution_time])
255
 
256
- gr.Markdown("# Client, Bank and Credit Scoring Agency decryption")
257
  gr.Markdown(
258
  """
259
- Once the server completed the inference, the encrypted output is returned to the user.
260
 
261
  The three entities that provide the information to compute the credit score are the only
262
  ones that can decrypt the result. They take part in a decryption protocol that allows to
@@ -269,7 +270,7 @@ with demo:
269
  """
270
  The first value displayed below is a shortened byte representation of the actual encrypted
271
  output.
272
- The user is then able to decrypt the value using its private key.
273
  """
274
  )
275
 
@@ -291,7 +292,7 @@ with demo:
291
  gr.Markdown("## Step 6 (optional): Explain the prediction.")
292
  gr.Markdown(
293
  """
294
- In case the credit card is likely to be denied, the user can ask for how many years of
295
  employment would most likely be required in order to increase the chance of getting a
296
  credit card approval.
297
 
 
22
  )
23
  from backend import (
24
  keygen_send,
25
+ pre_process_encrypt_send_applicant,
26
  pre_process_encrypt_send_bank,
27
+ pre_process_encrypt_send_credit_bureau,
28
  run_fhe,
29
  get_output_and_decrypt,
30
  explain_encrypt_run_decrypt,
 
61
  """
62
  )
63
 
64
+ gr.Markdown("# Applicant, Bank and Credit bureau setup")
65
 
66
  gr.Markdown("## Step 1: Generate the keys.")
67
  gr.Markdown(
 
90
  """
91
  Select the information that corresponds to the profile you want to evaluate. Three sources
92
  of information are represented in this model:
93
+ - the applicant's personal information in order to evaluate his/her credit card eligibility;
94
+ - the applicant bank account history, which provides any type of information on the
95
+ applicant's banking information relevant to the decision (here, we consider duration of
96
+ account);
97
+ - and credit bureau information, which represents any other information (here,
98
  employment history) that could provide additional insight relevant to the decision.
99
 
100
  Please always encrypt and send the values (through the buttons on the right) once updated
 
104
 
105
  with gr.Row():
106
  with gr.Column():
107
+ gr.Markdown("### Applicant information")
108
  bool_inputs = gr.CheckboxGroup(
109
  ["Car", "Property", "Mobile phone"],
110
  label="Which of the following do you actively hold or own?"
 
168
  )
169
 
170
  with gr.Column():
171
+ encrypt_button_applicant = gr.Button("Encrypt the inputs and send to server.")
172
 
173
+ encrypted_input_applicant = gr.Textbox(
174
  label="Encrypted input representation:", max_lines=2, interactive=False
175
  )
176
 
177
  with gr.Row():
178
  with gr.Column(scale=2):
179
+ gr.Markdown("### Bank information")
180
  account_age = gr.Slider(
181
  **ACCOUNT_MIN_MAX,
182
  step=1,
 
193
 
194
  with gr.Row():
195
  with gr.Column(scale=2):
196
+ gr.Markdown("### Credit bureau information ")
197
  employed = gr.Radio(["Yes", "No"], label="Is the person employed ?", value="Yes")
198
  years_employed = gr.Dropdown(
199
  choices=YEARS_EMPLOYED_BINS,
 
203
  )
204
 
205
  with gr.Column():
206
+ encrypt_button_credit_bureau = gr.Button("Encrypt the inputs and send to server.")
207
 
208
+ encrypted_input_credit_bureau = gr.Textbox(
209
  label="Encrypted input representation:", max_lines=2, interactive=False
210
  )
211
 
212
+ # Button to pre-process, generate the key, encrypt and send the applicant inputs from the client
213
  # side to the server
214
+ encrypt_button_applicant.click(
215
+ pre_process_encrypt_send_applicant,
216
  inputs=[client_id, bool_inputs, num_children, household_size, total_income, age, \
217
  income_type, education_type, family_status, occupation_type, housing_type],
218
+ outputs=[encrypted_input_applicant],
219
  )
220
 
221
  # Button to pre-process, generate the key, encrypt and send the bank inputs from the client
 
226
  outputs=[encrypted_input_bank],
227
  )
228
 
229
+ # Button to pre-process, generate the key, encrypt and send the credit bureau inputs from the
230
  # client side to the server
231
+ encrypt_button_credit_bureau.click(
232
+ pre_process_encrypt_send_credit_bureau,
233
  inputs=[client_id, years_employed, employed],
234
+ outputs=[encrypted_input_credit_bureau],
235
  )
236
 
237
  gr.Markdown("# Server side")
 
254
  # Button to send the encodings to the server using post method
255
  execute_fhe_button.click(run_fhe, inputs=[client_id], outputs=[fhe_execution_time])
256
 
257
+ gr.Markdown("# Applicant, Bank and Credit bureau decryption")
258
  gr.Markdown(
259
  """
260
+ Once the server completed the inference, the encrypted output is returned to the applicant.
261
 
262
  The three entities that provide the information to compute the credit score are the only
263
  ones that can decrypt the result. They take part in a decryption protocol that allows to
 
270
  """
271
  The first value displayed below is a shortened byte representation of the actual encrypted
272
  output.
273
+ The applicant is then able to decrypt the value using its private key.
274
  """
275
  )
276
 
 
292
  gr.Markdown("## Step 6 (optional): Explain the prediction.")
293
  gr.Markdown(
294
  """
295
+ In case the credit card is likely to be denied, the applicant can ask for how many years of
296
  employment would most likely be required in order to increase the chance of getting a
297
  credit card approval.
298
 
backend.py CHANGED
@@ -18,13 +18,13 @@ from settings import (
18
  PROCESSED_INPUT_SHAPE,
19
  INPUT_INDEXES,
20
  INPUT_SLICES,
21
- PRE_PROCESSOR_USER_PATH,
22
  PRE_PROCESSOR_BANK_PATH,
23
- PRE_PROCESSOR_CS_AGENCY_PATH,
24
  CLIENT_TYPES,
25
- USER_COLUMNS,
26
  BANK_COLUMNS,
27
- CS_AGENCY_COLUMNS,
28
  YEARS_EMPLOYED_BINS,
29
  YEARS_EMPLOYED_BIN_NAME_TO_INDEX,
30
  )
@@ -37,13 +37,13 @@ DENIED_MESSAGE = "Credit card is likely to be denied ❌"
37
 
38
  # Load pre-processor instances
39
  with (
40
- PRE_PROCESSOR_USER_PATH.open('rb') as file_user,
41
  PRE_PROCESSOR_BANK_PATH.open('rb') as file_bank,
42
- PRE_PROCESSOR_CS_AGENCY_PATH.open('rb') as file_cs_agency,
43
  ):
44
- PRE_PROCESSOR_USER = pickle.load(file_user)
45
  PRE_PROCESSOR_BANK = pickle.load(file_bank)
46
- PRE_PROCESSOR_CS_AGENCY = pickle.load(file_cs_agency)
47
 
48
 
49
  def shorten_bytes_object(bytes_object, limit=500):
@@ -114,8 +114,8 @@ def _get_client_file_path(name, client_id, client_type=None):
114
  name (str): The desired file name (either 'evaluation_key', 'encrypted_inputs' or
115
  'encrypted_outputs').
116
  client_id (int): The client ID to consider.
117
- client_type (Optional[str]): The type of user to consider (either 'user', 'bank',
118
- 'cs_agency' or None). Default to None, which is used for evaluation key and output.
119
 
120
  Returns:
121
  pathlib.Path: The file path.
@@ -135,8 +135,8 @@ def _send_to_server(client_id, client_type, file_name):
135
 
136
  Args:
137
  client_id (int): The client ID to consider.
138
- client_type (Optional[str]): The type of client to consider (either 'user', 'bank',
139
- 'cs_agency' or None).
140
  file_name (str): File name to send (either 'evaluation_key' or 'encrypted_inputs').
141
  """
142
  # Get the paths to the encrypted inputs
@@ -208,7 +208,8 @@ def _encrypt_send(client_id, inputs, client_type):
208
  Args:
209
  client_id (str): The current client ID to consider.
210
  inputs (numpy.ndarray): The inputs to encrypt.
211
- client_type (str): The type of client to consider (either 'user', 'bank' or 'cs_agency').
 
212
 
213
  Returns:
214
  encrypted_inputs_short (str): A short representation of the encrypted input to send in hex.
@@ -244,8 +245,8 @@ def _encrypt_send(client_id, inputs, client_type):
244
  return encrypted_inputs_short
245
 
246
 
247
- def pre_process_encrypt_send_user(client_id, *inputs):
248
- """Pre-process, encrypt and send the user inputs for a specific client to the server.
249
 
250
  Args:
251
  client_id (str): The current client ID to consider.
@@ -262,7 +263,7 @@ def pre_process_encrypt_send_user(client_id, *inputs):
262
  own_property = "Property" in bool_inputs
263
  mobile_phone = "Mobile phone" in bool_inputs
264
 
265
- user_inputs = pandas.DataFrame({
266
  "Own_car": [own_car],
267
  "Own_property": [own_property],
268
  "Mobile_phone": [mobile_phone],
@@ -277,11 +278,11 @@ def pre_process_encrypt_send_user(client_id, *inputs):
277
  "Housing_type": [housing_type],
278
  })
279
 
280
- user_inputs = user_inputs.reindex(USER_COLUMNS, axis=1)
281
 
282
- preprocessed_user_inputs = PRE_PROCESSOR_USER.transform(user_inputs)
283
 
284
- return _encrypt_send(client_id, preprocessed_user_inputs, "user")
285
 
286
 
287
  def pre_process_encrypt_send_bank(client_id, *inputs):
@@ -307,8 +308,8 @@ def pre_process_encrypt_send_bank(client_id, *inputs):
307
  return _encrypt_send(client_id, preprocessed_bank_inputs, "bank")
308
 
309
 
310
- def pre_process_encrypt_send_cs_agency(client_id, *inputs):
311
- """Pre-process, encrypt and send the credit scoring agency inputs for a specific client to the server.
312
 
313
  Args:
314
  client_id (str): The current client ID to consider.
@@ -322,15 +323,15 @@ def pre_process_encrypt_send_cs_agency(client_id, *inputs):
322
  years_employed = YEARS_EMPLOYED_BIN_NAME_TO_INDEX[years_employed_bin]
323
  is_employed = employed == "Yes"
324
 
325
- cs_agency_inputs = pandas.DataFrame({
326
  "Years_employed": [years_employed],
327
  "Employed": [is_employed],
328
  })
329
 
330
- cs_agency_inputs = cs_agency_inputs.reindex(CS_AGENCY_COLUMNS, axis=1)
331
- preprocessed_cs_agency_inputs = PRE_PROCESSOR_CS_AGENCY.transform(cs_agency_inputs)
332
 
333
- return _encrypt_send(client_id, preprocessed_cs_agency_inputs, "cs_agency")
334
 
335
 
336
  def run_fhe(client_id):
@@ -426,7 +427,7 @@ def explain_encrypt_run_decrypt(client_id, prediction_output, *inputs):
426
  "Explaining the prediction can only be done if the credit card is likely to be denied."
427
  )
428
 
429
- # Retrieve the credit scoring agency inputs
430
  years_employed, employed = inputs
431
 
432
  # Years_employed is divided into several ordered bins. Here, we retrieve the index representing
@@ -435,14 +436,14 @@ def explain_encrypt_run_decrypt(client_id, prediction_output, *inputs):
435
 
436
  # If the bin is not the last (representing the most years of employment), we run the model in
437
  # FHE for each bins "older" or equal to the given bin, in order. Then, we retrieve the first
438
- # bin that changes the model's prediction to "approval" and display it to the user.
439
  if bin_index != len(YEARS_EMPLOYED_BINS) - 1:
440
 
441
  # Loop over the bins starting with "older" or equal to the given bin
442
  for years_employed_bin in YEARS_EMPLOYED_BINS[bin_index:]:
443
 
444
  # Send the new encrypted input
445
- pre_process_encrypt_send_cs_agency(client_id, years_employed_bin, employed)
446
 
447
  # Run the model in FHE
448
  run_fhe(client_id)
@@ -450,16 +451,16 @@ def explain_encrypt_run_decrypt(client_id, prediction_output, *inputs):
450
  # Retrieve the new prediction
451
  output_prediction = get_output_and_decrypt(client_id)
452
 
453
- # If the bin made the model predict an approval, share it to the user
454
  if "approved" in output_prediction[0]:
455
 
456
- # If the approval was made using the given input, that means the user most likely
457
- # tried the bin suggested in a previous explainability run. In that case, we
458
  # confirm that the credit card is likely to be approved
459
  if years_employed_bin == years_employed:
460
  return APPROVED_MESSAGE
461
 
462
- # Else, that means the users is looking for some explainability. We therefore
463
  # suggest to try the obtained bin
464
  return (
465
  DENIED_MESSAGE + f" However, having at least {years_employed_bin} years of "
@@ -474,7 +475,7 @@ def explain_encrypt_run_decrypt(client_id, prediction_output, *inputs):
474
  "bigger impact in this particular case."
475
  )
476
 
477
- # In case the user tried the "oldest" bin (but still got denied), explain why
478
  return (
479
  DENIED_MESSAGE + " Unfortunately, you already have the maximum amount of years of "
480
  f"employment ({years_employed} years). Other inputs like the income or the account's age "
 
18
  PROCESSED_INPUT_SHAPE,
19
  INPUT_INDEXES,
20
  INPUT_SLICES,
21
+ PRE_PROCESSOR_APPLICANT_PATH,
22
  PRE_PROCESSOR_BANK_PATH,
23
+ PRE_PROCESSOR_CREDIT_BUREAU_PATH,
24
  CLIENT_TYPES,
25
+ APPLICANT_COLUMNS,
26
  BANK_COLUMNS,
27
+ CREDIT_BUREAU_COLUMNS,
28
  YEARS_EMPLOYED_BINS,
29
  YEARS_EMPLOYED_BIN_NAME_TO_INDEX,
30
  )
 
37
 
38
  # Load pre-processor instances
39
  with (
40
+ PRE_PROCESSOR_APPLICANT_PATH.open('rb') as file_applicant,
41
  PRE_PROCESSOR_BANK_PATH.open('rb') as file_bank,
42
+ PRE_PROCESSOR_CREDIT_BUREAU_PATH.open('rb') as file_credit_bureau,
43
  ):
44
+ PRE_PROCESSOR_APPLICANT = pickle.load(file_applicant)
45
  PRE_PROCESSOR_BANK = pickle.load(file_bank)
46
+ PRE_PROCESSOR_CREDIT_BUREAU = pickle.load(file_credit_bureau)
47
 
48
 
49
  def shorten_bytes_object(bytes_object, limit=500):
 
114
  name (str): The desired file name (either 'evaluation_key', 'encrypted_inputs' or
115
  'encrypted_outputs').
116
  client_id (int): The client ID to consider.
117
+ client_type (Optional[str]): The type of client to consider (either 'applicant', 'bank',
118
+ 'credit_bureau' or None). Default to None, which is used for evaluation key and output.
119
 
120
  Returns:
121
  pathlib.Path: The file path.
 
135
 
136
  Args:
137
  client_id (int): The client ID to consider.
138
+ client_type (Optional[str]): The type of client to consider (either 'applicant', 'bank',
139
+ 'credit_bureau' or None).
140
  file_name (str): File name to send (either 'evaluation_key' or 'encrypted_inputs').
141
  """
142
  # Get the paths to the encrypted inputs
 
208
  Args:
209
  client_id (str): The current client ID to consider.
210
  inputs (numpy.ndarray): The inputs to encrypt.
211
+ client_type (str): The type of client to consider (either 'applicant', 'bank' or
212
+ 'credit_bureau').
213
 
214
  Returns:
215
  encrypted_inputs_short (str): A short representation of the encrypted input to send in hex.
 
245
  return encrypted_inputs_short
246
 
247
 
248
+ def pre_process_encrypt_send_applicant(client_id, *inputs):
249
+ """Pre-process, encrypt and send the applicant inputs for a specific client to the server.
250
 
251
  Args:
252
  client_id (str): The current client ID to consider.
 
263
  own_property = "Property" in bool_inputs
264
  mobile_phone = "Mobile phone" in bool_inputs
265
 
266
+ applicant_inputs = pandas.DataFrame({
267
  "Own_car": [own_car],
268
  "Own_property": [own_property],
269
  "Mobile_phone": [mobile_phone],
 
278
  "Housing_type": [housing_type],
279
  })
280
 
281
+ applicant_inputs = applicant_inputs.reindex(APPLICANT_COLUMNS, axis=1)
282
 
283
+ preprocessed_applicant_inputs = PRE_PROCESSOR_APPLICANT.transform(applicant_inputs)
284
 
285
+ return _encrypt_send(client_id, preprocessed_applicant_inputs, "applicant")
286
 
287
 
288
  def pre_process_encrypt_send_bank(client_id, *inputs):
 
308
  return _encrypt_send(client_id, preprocessed_bank_inputs, "bank")
309
 
310
 
311
+ def pre_process_encrypt_send_credit_bureau(client_id, *inputs):
312
+ """Pre-process, encrypt and send the credit bureau inputs for a specific client to the server.
313
 
314
  Args:
315
  client_id (str): The current client ID to consider.
 
323
  years_employed = YEARS_EMPLOYED_BIN_NAME_TO_INDEX[years_employed_bin]
324
  is_employed = employed == "Yes"
325
 
326
+ credit_bureau_inputs = pandas.DataFrame({
327
  "Years_employed": [years_employed],
328
  "Employed": [is_employed],
329
  })
330
 
331
+ credit_bureau_inputs = credit_bureau_inputs.reindex(CREDIT_BUREAU_COLUMNS, axis=1)
332
+ preprocessed_credit_bureau_inputs = PRE_PROCESSOR_CREDIT_BUREAU.transform(credit_bureau_inputs)
333
 
334
+ return _encrypt_send(client_id, preprocessed_credit_bureau_inputs, "credit_bureau")
335
 
336
 
337
  def run_fhe(client_id):
 
427
  "Explaining the prediction can only be done if the credit card is likely to be denied."
428
  )
429
 
430
+ # Retrieve the credit bureau inputs
431
  years_employed, employed = inputs
432
 
433
  # Years_employed is divided into several ordered bins. Here, we retrieve the index representing
 
436
 
437
  # If the bin is not the last (representing the most years of employment), we run the model in
438
  # FHE for each bins "older" or equal to the given bin, in order. Then, we retrieve the first
439
+ # bin that changes the model's prediction to "approval" and display it to the applicant.
440
  if bin_index != len(YEARS_EMPLOYED_BINS) - 1:
441
 
442
  # Loop over the bins starting with "older" or equal to the given bin
443
  for years_employed_bin in YEARS_EMPLOYED_BINS[bin_index:]:
444
 
445
  # Send the new encrypted input
446
+ pre_process_encrypt_send_credit_bureau(client_id, years_employed_bin, employed)
447
 
448
  # Run the model in FHE
449
  run_fhe(client_id)
 
451
  # Retrieve the new prediction
452
  output_prediction = get_output_and_decrypt(client_id)
453
 
454
+ # If the bin made the model predict an approval, share it to the applicant
455
  if "approved" in output_prediction[0]:
456
 
457
+ # If the approval was made using the given input, that means the applicant most
458
+ # likely tried the bin suggested in a previous explainability run. In that case, we
459
  # confirm that the credit card is likely to be approved
460
  if years_employed_bin == years_employed:
461
  return APPROVED_MESSAGE
462
 
463
+ # Else, that means the applicant is looking for some explainability. We therefore
464
  # suggest to try the obtained bin
465
  return (
466
  DENIED_MESSAGE + f" However, having at least {years_employed_bin} years of "
 
475
  "bigger impact in this particular case."
476
  )
477
 
478
+ # In case the applicant tried the "oldest" bin (but still got denied), explain why
479
  return (
480
  DENIED_MESSAGE + " Unfortunately, you already have the maximum amount of years of "
481
  f"employment ({years_employed} years). Other inputs like the income or the account's age "
deployment_files/model/{pre_processor_user.pkl → pre_processor_applicant.pkl} RENAMED
File without changes
deployment_files/model/{pre_processor_cs_agency.pkl → pre_processor_credit_bureau.pkl} RENAMED
File without changes
deployment_files/{pre_processor_user.pkl → pre_processor_applicant.pkl} RENAMED
File without changes
deployment_files/{pre_processor_cs_agency.pkl → pre_processor_credit_bureau.pkl} RENAMED
File without changes
development.py CHANGED
@@ -9,12 +9,12 @@ from settings import (
9
  DEPLOYMENT_PATH,
10
  DATA_PATH,
11
  INPUT_SLICES,
12
- PRE_PROCESSOR_USER_PATH,
13
  PRE_PROCESSOR_BANK_PATH,
14
- PRE_PROCESSOR_CS_AGENCY_PATH,
15
- USER_COLUMNS,
16
  BANK_COLUMNS,
17
- CS_AGENCY_COLUMNS,
18
  )
19
  from utils.client_server_interface import MultiInputsFHEModelDev
20
  from utils.model import MultiInputDecisionTreeClassifier, MultiInputDecisionTreeRegressor
@@ -31,9 +31,9 @@ def get_multi_inputs(data):
31
  (Tuple[numpy.ndarray]): The inputs for all three parties.
32
  """
33
  return (
34
- data[:, INPUT_SLICES["user"]],
35
  data[:, INPUT_SLICES["bank"]],
36
- data[:, INPUT_SLICES["cs_agency"]]
37
  )
38
 
39
 
@@ -47,18 +47,18 @@ data_x = data.copy()
47
  data_y = data_x.pop("Target").copy().to_frame()
48
 
49
  # Get data from all parties
50
- data_user = data_x[USER_COLUMNS].copy()
51
  data_bank = data_x[BANK_COLUMNS].copy()
52
- data_cs_agency = data_x[CS_AGENCY_COLUMNS].copy()
53
 
54
  # Feature engineer the data
55
- pre_processor_user, pre_processor_bank, pre_processor_cs_agency = get_pre_processors()
56
 
57
- preprocessed_data_user = pre_processor_user.fit_transform(data_user)
58
  preprocessed_data_bank = pre_processor_bank.fit_transform(data_bank)
59
- preprocessed_data_cs_agency = pre_processor_cs_agency.fit_transform(data_cs_agency)
60
 
61
- preprocessed_data_x = numpy.concatenate((preprocessed_data_user, preprocessed_data_bank, preprocessed_data_cs_agency), axis=1)
62
 
63
 
64
  print("\nTrain and compile the model")
@@ -83,12 +83,12 @@ fhe_model_dev.save(via_mlir=True)
83
 
84
  # Save pre-processors
85
  with (
86
- PRE_PROCESSOR_USER_PATH.open('wb') as file_user,
87
  PRE_PROCESSOR_BANK_PATH.open('wb') as file_bank,
88
- PRE_PROCESSOR_CS_AGENCY_PATH.open('wb') as file_cs_agency,
89
  ):
90
- pickle.dump(pre_processor_user, file_user)
91
  pickle.dump(pre_processor_bank, file_bank)
92
- pickle.dump(pre_processor_cs_agency, file_cs_agency)
93
 
94
  print("\nDone !")
 
9
  DEPLOYMENT_PATH,
10
  DATA_PATH,
11
  INPUT_SLICES,
12
+ PRE_PROCESSOR_APPLICANT_PATH,
13
  PRE_PROCESSOR_BANK_PATH,
14
+ PRE_PROCESSOR_CREDIT_BUREAU_PATH,
15
+ APPLICANT_COLUMNS,
16
  BANK_COLUMNS,
17
+ CREDIT_BUREAU_COLUMNS,
18
  )
19
  from utils.client_server_interface import MultiInputsFHEModelDev
20
  from utils.model import MultiInputDecisionTreeClassifier, MultiInputDecisionTreeRegressor
 
31
  (Tuple[numpy.ndarray]): The inputs for all three parties.
32
  """
33
  return (
34
+ data[:, INPUT_SLICES["applicant"]],
35
  data[:, INPUT_SLICES["bank"]],
36
+ data[:, INPUT_SLICES["credit_bureau"]]
37
  )
38
 
39
 
 
47
  data_y = data_x.pop("Target").copy().to_frame()
48
 
49
  # Get data from all parties
50
+ data_applicant = data_x[APPLICANT_COLUMNS].copy()
51
  data_bank = data_x[BANK_COLUMNS].copy()
52
+ data_credit_bureau = data_x[CREDIT_BUREAU_COLUMNS].copy()
53
 
54
  # Feature engineer the data
55
+ pre_processor_applicant, pre_processor_bank, pre_processor_credit_bureau = get_pre_processors()
56
 
57
+ preprocessed_data_applicant = pre_processor_applicant.fit_transform(data_applicant)
58
  preprocessed_data_bank = pre_processor_bank.fit_transform(data_bank)
59
+ preprocessed_data_credit_bureau = pre_processor_credit_bureau.fit_transform(data_credit_bureau)
60
 
61
+ preprocessed_data_x = numpy.concatenate((preprocessed_data_applicant, preprocessed_data_bank, preprocessed_data_credit_bureau), axis=1)
62
 
63
 
64
  print("\nTrain and compile the model")
 
83
 
84
  # Save pre-processors
85
  with (
86
+ PRE_PROCESSOR_APPLICANT_PATH.open('wb') as file_applicant,
87
  PRE_PROCESSOR_BANK_PATH.open('wb') as file_bank,
88
+ PRE_PROCESSOR_CREDIT_BUREAU_PATH.open('wb') as file_credit_bureau,
89
  ):
90
+ pickle.dump(pre_processor_applicant, file_applicant)
91
  pickle.dump(pre_processor_bank, file_bank)
92
+ pickle.dump(pre_processor_credit_bureau, file_credit_bureau)
93
 
94
  print("\nDone !")
server.py CHANGED
@@ -19,8 +19,8 @@ def _get_server_file_path(name, client_id, client_type=None):
19
  name (str): The desired file name (either 'evaluation_key', 'encrypted_inputs' or
20
  'encrypted_outputs').
21
  client_id (int): The client ID to consider.
22
- client_type (Optional[str]): The type of user to consider (either 'user', 'bank',
23
- 'cs_agency' or None). Default to None, which is used for evaluation key and output.
24
 
25
  Returns:
26
  pathlib.Path: The file path.
 
19
  name (str): The desired file name (either 'evaluation_key', 'encrypted_inputs' or
20
  'encrypted_outputs').
21
  client_id (int): The client ID to consider.
22
+ client_type (Optional[str]): The type of client to consider (either 'applicant', 'bank',
23
+ 'credit_bureau' or None). Default to None, which is used for evaluation key and output.
24
 
25
  Returns:
26
  pathlib.Path: The file path.
settings.py CHANGED
@@ -16,9 +16,9 @@ SERVER_FILES = REPO_DIR / "server_files"
16
  DEPLOYMENT_PATH = DEPLOYMENT_PATH / "model"
17
 
18
  # Path targeting pre-processor saved files
19
- PRE_PROCESSOR_USER_PATH = DEPLOYMENT_PATH / 'pre_processor_user.pkl'
20
  PRE_PROCESSOR_BANK_PATH = DEPLOYMENT_PATH / 'pre_processor_bank.pkl'
21
- PRE_PROCESSOR_CS_AGENCY_PATH = DEPLOYMENT_PATH / 'pre_processor_cs_agency.pkl'
22
 
23
  # Create the necessary directories
24
  FHE_KEYS.mkdir(exist_ok=True)
@@ -34,26 +34,26 @@ DATA_PATH = "data/data.csv"
34
  # Development settings
35
  PROCESSED_INPUT_SHAPE = (1, 39)
36
 
37
- CLIENT_TYPES = ["user", "bank", "cs_agency"]
38
  INPUT_INDEXES = {
39
- "user": 0,
40
  "bank": 1,
41
- "cs_agency": 2,
42
  }
43
  INPUT_SLICES = {
44
- "user": slice(0, 36), # First position: start from 0
45
- "bank": slice(36, 37), # Second position: start from n_feature_user
46
- "cs_agency": slice(37, 39), # Third position: start from n_feature_user + n_feature_bank
47
  }
48
 
49
  # Fix column order for pre-processing steps
50
- USER_COLUMNS = [
51
  'Own_car', 'Own_property', 'Mobile_phone', 'Num_children', 'Household_size',
52
  'Total_income', 'Age', 'Income_type', 'Education_type', 'Family_status', 'Housing_type',
53
  'Occupation_type',
54
  ]
55
  BANK_COLUMNS = ["Account_age"]
56
- CS_AGENCY_COLUMNS = ["Years_employed", "Employed"]
57
 
58
  _data = pandas.read_csv(DATA_PATH, encoding="utf-8")
59
 
 
16
  DEPLOYMENT_PATH = DEPLOYMENT_PATH / "model"
17
 
18
  # Path targeting pre-processor saved files
19
+ PRE_PROCESSOR_APPLICANT_PATH = DEPLOYMENT_PATH / 'pre_processor_applicant.pkl'
20
  PRE_PROCESSOR_BANK_PATH = DEPLOYMENT_PATH / 'pre_processor_bank.pkl'
21
+ PRE_PROCESSOR_CREDIT_BUREAU_PATH = DEPLOYMENT_PATH / 'pre_processor_credit_bureau.pkl'
22
 
23
  # Create the necessary directories
24
  FHE_KEYS.mkdir(exist_ok=True)
 
34
  # Development settings
35
  PROCESSED_INPUT_SHAPE = (1, 39)
36
 
37
+ CLIENT_TYPES = ["applicant", "bank", "credit_bureau"]
38
  INPUT_INDEXES = {
39
+ "applicant": 0,
40
  "bank": 1,
41
+ "credit_bureau": 2,
42
  }
43
  INPUT_SLICES = {
44
+ "applicant": slice(0, 36), # First position: start from 0
45
+ "bank": slice(36, 37), # Second position: start from n_feature_applicant
46
+ "credit_bureau": slice(37, 39), # Third position: start from n_feature_applicant + n_feature_bank
47
  }
48
 
49
  # Fix column order for pre-processing steps
50
+ APPLICANT_COLUMNS = [
51
  'Own_car', 'Own_property', 'Mobile_phone', 'Num_children', 'Household_size',
52
  'Total_income', 'Age', 'Income_type', 'Education_type', 'Family_status', 'Housing_type',
53
  'Occupation_type',
54
  ]
55
  BANK_COLUMNS = ["Account_age"]
56
+ CREDIT_BUREAU_COLUMNS = ["Years_employed", "Employed"]
57
 
58
  _data = pandas.read_csv(DATA_PATH, encoding="utf-8")
59
 
utils/client_server_interface.py CHANGED
@@ -46,8 +46,8 @@ class MultiInputsFHEModelClient(FHEModelClient):
46
  Args:
47
  x (numpy.ndarray): The input to consider. Here, the input should only represent a
48
  single party.
49
- input_index (int): The index representing the type of model (0: "user", 1: "bank",
50
- 2: "cs_agency")
51
  processed_input_shape (Tuple[int]): The total input shape (all parties combined) after
52
  pre-processing.
53
  input_slice (slice): The slices to consider for the given party.
 
46
  Args:
47
  x (numpy.ndarray): The input to consider. Here, the input should only represent a
48
  single party.
49
+ input_index (int): The index representing the type of model (0: "applicant", 1: "bank",
50
+ 2: "credit_bureau")
51
  processed_input_shape (Tuple[int]): The total input shape (all parties combined) after
52
  pre-processing.
53
  input_slice (slice): The slices to consider for the given party.
utils/pre_processing.py CHANGED
@@ -22,7 +22,7 @@ def _replace_values_eq(column, value):
22
  return column
23
 
24
  def get_pre_processors():
25
- pre_processor_user = ColumnTransformer(
26
  transformers=[
27
  (
28
  "replace_occupation_type_labor",
@@ -55,10 +55,10 @@ def get_pre_processors():
55
  verbose_feature_names_out=False,
56
  )
57
 
58
- pre_processor_cs_agency = ColumnTransformer(
59
  transformers=[],
60
  remainder='passthrough',
61
  verbose_feature_names_out=False,
62
  )
63
 
64
- return pre_processor_user, pre_processor_bank, pre_processor_cs_agency
 
22
  return column
23
 
24
  def get_pre_processors():
25
+ pre_processor_applicant = ColumnTransformer(
26
  transformers=[
27
  (
28
  "replace_occupation_type_labor",
 
55
  verbose_feature_names_out=False,
56
  )
57
 
58
+ pre_processor_credit_bureau = ColumnTransformer(
59
  transformers=[],
60
  remainder='passthrough',
61
  verbose_feature_names_out=False,
62
  )
63
 
64
+ return pre_processor_applicant, pre_processor_bank, pre_processor_credit_bureau