{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Split Learning—Bank Marketing" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ">The following codes are demos only. It's **NOT for production** due to system security concerns, please **DO NOT** use it directly in production." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this tutorial, we will use the bank's marketing model as an example to show how to accomplish split learning in vertical scenarios under the SecretFlow framework.\n", "SecretFlow provides a user-friendly Api that makes it easy to apply your Keras model or PyTorch model to split learning scenarios to complete joint modeling tasks for vertical scenarios.\n", "\n", "In this tutorial we will show you how to turn your existing 'Keras' model into a split learning model under Secretflow to complete federated multi-party modeling tasks." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## What is Split Learning?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The core idea of split learning is to split the network structure. Each device (silo) retains only a part of the network structure, and the sub-network structure of all devices is combined together to form a complete network model. \n", "In the training process, different devices (silos) only perform forward or reverse calculation on the local network structure, and transfer the calculation results to the next device. Multiple devices complete the training through joint model until convergence.\n", "\n", " \"split_learning_tutorial.png\" \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Alice**:have *data\\_alice*,*model\\_base\\_alice* \n", "**Bob**: have *data\\_bob*,*model\\_base\\_bob*,*model\\_fuse* \n", "\n", "1. **Alice** uses its data to get *hidden0* through *model\\_base\\_Alice* and send it to Bob. \n", "2. **Bob** gets *hidden1* with its data through *model\\_base\\_bob*.\n", "3. *hidden\\_0* and *hidden\\_1* are input to the *AggLayer* for aggregation, and the aggregated *hidden\\_merge* is the output.\n", "4. **Bob** input *hidden\\_merge* to *model\\_fuse*, get the gradient with *label* and send it back.\n", "5. The gradient is split into two parts *g\\_0*, *g\\_1* through *AggLayer*, which are sent to **Alice** and **Bob** respectively.\n", "6. Then **Alice** and **Bob** update their local base net with *g\\_0* or *g\\_1*.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Task" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Marketing is the banking industry in the ever-changing market environment, to meet the needs of customers, to achieve business objectives of the overall operation and sales activities. In the current environment of big data, data analysis provides a more effective analysis means for the banking industry. Customer demand analysis, understanding of target market trends and more macro market strategies can provide the basis and direction. \n", " \n", "The data from [kaggle](https://www.kaggle.com/janiobachmann/bank-marketing-dataset) is a set of classic marketing data bank, is a Portuguese bank agency telephone direct marketing activities, The target variable is whether the customer subscribes to deposit product." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Data\n", "\n", "1. The total sample size was 11162, including 8929 training set and 2233 test set.\n", "2. Feature dim is 16, target is binary classification.\n", "3. We have cut the data in advance. Alice holds the 4-dimensional basic attribute features, Bob holds the 12-dimensional bank transaction features, and only Alice holds the corresponding label." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's start by looking at what our bank's marketing data look like? \n", "\n", "The original data is divided into Bank Alice and Bank Bob, which stores in Alice and Bob respectively. Here, CSV is the original data that has only been separated without pre-processing, we will use `secretflow preprocess` for FedData preprocess." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2023-04-27 15:30:12,356\tINFO worker.py:1538 -- Started a local Ray instance.\n" ] } ], "source": [ "%load_ext autoreload\n", "%autoreload 2\n", "\n", "import secretflow as sf\n", "import matplotlib.pyplot as plt\n", "\n", "sf.init(['alice', 'bob'], address='local')\n", "alice, bob = sf.PYU('alice'), sf.PYU('bob')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### prepare data" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "from secretflow.utils.simulation.datasets import dataset\n", "\n", "df = pd.read_csv(dataset('bank_marketing'), sep=';')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We assume that Alice is a new bank, and they only have the basic information of the user and purchased the label of financial products from other bank." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
agejobmaritaleducationy
030unemployedmarriedprimaryno
133servicesmarriedsecondaryno
235managementsingletertiaryno
330managementmarriedtertiaryno
459blue-collarmarriedsecondaryno
..................
451633servicesmarriedsecondaryno
451757self-employedmarriedtertiaryno
451857technicianmarriedsecondaryno
451928blue-collarmarriedsecondaryno
452044entrepreneursingletertiaryno
\n", "

4521 rows × 5 columns

\n", "
" ], "text/plain": [ " age job marital education y\n", "0 30 unemployed married primary no\n", "1 33 services married secondary no\n", "2 35 management single tertiary no\n", "3 30 management married tertiary no\n", "4 59 blue-collar married secondary no\n", "... ... ... ... ... ..\n", "4516 33 services married secondary no\n", "4517 57 self-employed married tertiary no\n", "4518 57 technician married secondary no\n", "4519 28 blue-collar married secondary no\n", "4520 44 entrepreneur single tertiary no\n", "\n", "[4521 rows x 5 columns]" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "alice_data = df[[\"age\", \"job\", \"marital\", \"education\", \"y\"]]\n", "alice_data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Bob is an old bank, they have the user's account balance, house, loan, and recent marketing feedback." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
defaultbalancehousingloancontactdaymonthdurationcampaignpdayspreviouspoutcome
0no1787nonocellular19oct791-10unknown
1no4789yesyescellular11may22013394failure
2no1350yesnocellular16apr18513301failure
3no1476yesyesunknown3jun1994-10unknown
4no0yesnounknown5may2261-10unknown
.......................................
4516no-333yesnocellular30jul3295-10unknown
4517yes-3313yesyesunknown9may1531-10unknown
4518no295nonocellular19aug15111-10unknown
4519no1137nonocellular6feb12942113other
4520no1136yesyescellular3apr34522497other
\n", "

4521 rows × 12 columns

\n", "
" ], "text/plain": [ " default balance housing loan contact day month duration campaign \\\n", "0 no 1787 no no cellular 19 oct 79 1 \n", "1 no 4789 yes yes cellular 11 may 220 1 \n", "2 no 1350 yes no cellular 16 apr 185 1 \n", "3 no 1476 yes yes unknown 3 jun 199 4 \n", "4 no 0 yes no unknown 5 may 226 1 \n", "... ... ... ... ... ... ... ... ... ... \n", "4516 no -333 yes no cellular 30 jul 329 5 \n", "4517 yes -3313 yes yes unknown 9 may 153 1 \n", "4518 no 295 no no cellular 19 aug 151 11 \n", "4519 no 1137 no no cellular 6 feb 129 4 \n", "4520 no 1136 yes yes cellular 3 apr 345 2 \n", "\n", " pdays previous poutcome \n", "0 -1 0 unknown \n", "1 339 4 failure \n", "2 330 1 failure \n", "3 -1 0 unknown \n", "4 -1 0 unknown \n", "... ... ... ... \n", "4516 -1 0 unknown \n", "4517 -1 0 unknown \n", "4518 -1 0 unknown \n", "4519 211 3 other \n", "4520 249 7 other \n", "\n", "[4521 rows x 12 columns]" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "bob_data = df[\n", " [\n", " \"default\",\n", " \"balance\",\n", " \"housing\",\n", " \"loan\",\n", " \"contact\",\n", " \"day\",\n", " \"month\",\n", " \"duration\",\n", " \"campaign\",\n", " \"pdays\",\n", " \"previous\",\n", " \"poutcome\",\n", " ]\n", "]\n", "bob_data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create Secretflow Environment" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Create 2 entities in the Secretflow environment [Alice, Bob] \n", "Where 'Alice' and 'Bob' are two `PYU`. \n", "Once you've constructed the two objects, you can happily start Splitting Learning." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Import Dependency" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "from secretflow.data.split import train_test_split\n", "from secretflow.ml.nn import SLModel" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Prepare Data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Build Federated Table**\n", "\n", "\n", "Federated table is a virtual concept that cross multiple parties, We define `VDataFrame` for vertical setting\n", ". \n", "\n", "1. The data of all parties in a federated table is stored locally and is not allowed to go out of the domain.\n", "\n", "2. No one has access to data store except the party that owns the data.\n", "\n", "3. Any operation performed on the federated table is scheduled by the driver to each worker, and the execution instructions are delivered layer by layer until the Python runtime of the specific worker. The framework ensures that only the worker with `worker.device` equal to the `Object.device` can operate on the data.\n", "\n", "4. Federated tables are designed for managing and manipulating multi-party data from a central perspective.\n", "\n", "5. Interfaces to `Federated Tables` are aligned to `pandas.DataFrame` to reduce the cost of multi-party data operations.\n", "\n", "6. The SecretFlow framework provides Plain&Ciphertext hybrid programming capabilities. Vertical federated tables are built using `SPU`, and `MPC-PSI` is used to safely get intersection and align data from all parties.\n", "\n", "\"vdataframe.png\" \n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "VDataFrame provides `read_csv` interface similar to pandas, the difference is that `secretflow.read_csv` receives a dictionary that defines the path of data for both parties. We can use `secretflow.vertical.read_csv` to build the `VDataFrame`.\n", "```\n", "read_csv(file_dict,delimiter,ppu,keys,drop_key)\n", " filepath: Path of the participant file. The address can be a relative or absolute path to a local file\n", " spu: SPU Device for PSI; If this parameter is not specified, data must be prealigned\n", " keys: Key for intersection.\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Create spu object" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "spu = sf.SPU(sf.utils.testing.cluster_def(['alice', 'bob']))" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "from secretflow.utils.simulation.datasets import load_bank_marketing\n", "\n", "# Alice has the first four features,\n", "# while bob has the left features\n", "data = load_bank_marketing(parts={alice: (0, 4), bob: (4, 16)}, axis=1)\n", "# Alice holds the label.\n", "label = load_bank_marketing(parts={alice: (16, 17)}, axis=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`data` is a vertically federated table. It only has the `Schema` of all the data globally." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's examine the data management of `VDF` more closely.\n", "\n", "As shown in the example, the `age` field belongs to `Alice`, so the corresponding column can be obtained from `Alice`'s partition. However, if `Bob` tries to obtain the `age` field, a `KeyError` error will be reported.\n", "\n", "We have a concept called Partition, which is a defined data fragment. Each partition has its own device to which it belongs, and only the device to which it belongs can operate on its data." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "data['age'].partitions[alice].data" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# You can uncomment this and you will get a KeyError.\n", "# data['age'].partitions[bob]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, we perform data preprocessing on the `VDataFrame`. \n", "We use LabelEncoder and MinMaxScaler as examples. These two preprocessing functions have corresponding concepts in SkLearn, and their usage methods are similar to those in **sklearn**." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "from secretflow.preprocessing.scaler import MinMaxScaler\n", "from secretflow.preprocessing.encoder import LabelEncoder" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "encoder = LabelEncoder()\n", "data['job'] = encoder.fit_transform(data['job'])\n", "data['marital'] = encoder.fit_transform(data['marital'])\n", "data['education'] = encoder.fit_transform(data['education'])\n", "data['default'] = encoder.fit_transform(data['default'])\n", "data['housing'] = encoder.fit_transform(data['housing'])\n", "data['loan'] = encoder.fit_transform(data['loan'])\n", "data['contact'] = encoder.fit_transform(data['contact'])\n", "data['poutcome'] = encoder.fit_transform(data['poutcome'])\n", "data['month'] = encoder.fit_transform(data['month'])\n", "label = encoder.fit_transform(label)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "label= ,\n", "data = \n" ] } ], "source": [ "print(f\"label= {type(label)},\\ndata = {type(data)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Standardize data via MinMaxScaler" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "\u001b[2m\u001b[36m(_run pid=37133)\u001b[0m /Users/zhangxingmeng/miniconda3/envs/secretflow/lib/python3.8/site-packages/sklearn/base.py:443: UserWarning: X has feature names, but MinMaxScaler was fitted without feature names\n", "\u001b[2m\u001b[36m(_run pid=37133)\u001b[0m warnings.warn(\n", "\u001b[2m\u001b[36m(_run pid=37133)\u001b[0m /Users/zhangxingmeng/miniconda3/envs/secretflow/lib/python3.8/site-packages/sklearn/base.py:443: UserWarning: X has feature names, but MinMaxScaler was fitted without feature names\n", "\u001b[2m\u001b[36m(_run pid=37133)\u001b[0m warnings.warn(\n" ] } ], "source": [ "scaler = MinMaxScaler()\n", "\n", "data = scaler.fit_transform(data)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next we divide the data set into train-set and test-set." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "from secretflow.data.split import train_test_split\n", "\n", "random_state = 1234\n", "train_data, test_data = train_test_split(\n", " data, train_size=0.8, random_state=random_state\n", ")\n", "train_label, test_label = train_test_split(\n", " label, train_size=0.8, random_state=random_state\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Summary:** At this stage, we have finished defining `federated tables`, performing `data preprocessing`, and partitioning the `training set` and `test set`.\n", "The secretFlow framework defines a set of operations to be built on the federated table (which is the logical counterpart of `pandas.DataFrame`). The secretflow framework defines a set of operations to be built on the federated table (its logical counterpart is `sklearn`) Refer to our documentation and API introduction to learn more about other features." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Introduce Model" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**local version**: \n", "For this task, a simple DNN can be trained to take in 16-dimensional features, process them through a neural network, and output the probability of positive and negative samples.\n", "\n", "\n", "**Federate version**: \n", "\n", "* Alice: \n", "\n", " - base_net: Input 4-dimensional feature and go through a DNN network to get hidden. \n", " \n", " - fuse_net: Receive hidden features calculated by Alice and Bob, input them to fusenet for feature fusion, and complete the forward process and backward process. \n", " \n", "* Bob: \n", "\n", " - base_net: Input 12-dimensional features, get hidden through a DNN network, and then send hidden to Alice to complete the following operation. \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Define Model" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, we will start creating the federated model. \n", "\n", "We have defined the SLTFModel and SLTorchModel, which are used to build split learning for vertically partitioned data. We have also created a simple and easy-to-use extensible interface, allowing you to easily transform your existing model into an SF-Model and perform vertically partitioned federated modeling." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Split learning is to break up a model so that one part is executed locally on the data and the other part is executed on the label side.\n", "First let's define the locally executed model -- base_model." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "def create_base_model(input_dim, output_dim, name='base_model'):\n", " # Create model\n", " def create_model():\n", " from tensorflow import keras\n", " from tensorflow.keras import layers\n", " import tensorflow as tf\n", "\n", " model = keras.Sequential(\n", " [\n", " keras.Input(shape=input_dim),\n", " layers.Dense(100, activation=\"relu\"),\n", " layers.Dense(output_dim, activation=\"relu\"),\n", " ]\n", " )\n", " # Compile model\n", " model.summary()\n", " model.compile(\n", " loss='binary_crossentropy',\n", " optimizer='adam',\n", " metrics=[\"accuracy\", tf.keras.metrics.AUC()],\n", " )\n", " return model\n", "\n", " return create_model" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We use create_base_model to create their base models for 'Alice' and 'Bob', respectively." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "# prepare model\n", "hidden_size = 64\n", "\n", "model_base_alice = create_base_model(4, hidden_size)\n", "model_base_bob = create_base_model(12, hidden_size)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Model: \"sequential\"\n", "_________________________________________________________________\n", " Layer (type) Output Shape Param # \n", "=================================================================\n", " dense (Dense) (None, 100) 500 \n", " \n", " dense_1 (Dense) (None, 64) 6464 \n", " \n", "=================================================================\n", "Total params: 6,964\n", "Trainable params: 6,964\n", "Non-trainable params: 0\n", "_________________________________________________________________\n", "Model: \"sequential_1\"\n", "_________________________________________________________________\n", " Layer (type) Output Shape Param # \n", "=================================================================\n", " dense_2 (Dense) (None, 100) 1300 \n", " \n", " dense_3 (Dense) (None, 64) 6464 \n", " \n", "=================================================================\n", "Total params: 7,764\n", "Trainable params: 7,764\n", "Non-trainable params: 0\n", "_________________________________________________________________\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model_base_alice()\n", "model_base_bob()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next we define the side with the label, or the server-side model -- fuse_model\n", "In the definition of fuse_model, we need to correctly define `loss`, `optimizer`, and `metrics`. This is compatible with all configurations of your existing Keras model." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "def create_fuse_model(input_dim, output_dim, party_nums, name='fuse_model'):\n", " def create_model():\n", " from tensorflow import keras\n", " from tensorflow.keras import layers\n", " import tensorflow as tf\n", "\n", " # input\n", " input_layers = []\n", " for i in range(party_nums):\n", " input_layers.append(\n", " keras.Input(\n", " input_dim,\n", " )\n", " )\n", "\n", " merged_layer = layers.concatenate(input_layers)\n", " fuse_layer = layers.Dense(64, activation='relu')(merged_layer)\n", " output = layers.Dense(output_dim, activation='sigmoid')(fuse_layer)\n", "\n", " model = keras.Model(inputs=input_layers, outputs=output)\n", " model.summary()\n", "\n", " model.compile(\n", " loss='binary_crossentropy',\n", " optimizer='adam',\n", " metrics=[\"accuracy\", tf.keras.metrics.AUC()],\n", " )\n", " return model\n", "\n", " return create_model" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "model_fuse = create_fuse_model(input_dim=hidden_size, party_nums=2, output_dim=1)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Model: \"model\"\n", "__________________________________________________________________________________________________\n", " Layer (type) Output Shape Param # Connected to \n", "==================================================================================================\n", " input_3 (InputLayer) [(None, 64)] 0 [] \n", " \n", " input_4 (InputLayer) [(None, 64)] 0 [] \n", " \n", " concatenate (Concatenate) (None, 128) 0 ['input_3[0][0]', \n", " 'input_4[0][0]'] \n", " \n", " dense_4 (Dense) (None, 64) 8256 ['concatenate[0][0]'] \n", " \n", " dense_5 (Dense) (None, 1) 65 ['dense_4[0][0]'] \n", " \n", "==================================================================================================\n", "Total params: 8,321\n", "Trainable params: 8,321\n", "Non-trainable params: 0\n", "__________________________________________________________________________________________________\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model_fuse()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Create Split Learning Model \n", "Secretflow provides the split learning model `SLModel`. \n", "To initial SLModel only need 3 parameters. \n", "\n", "* base_model_dict: A dictionary needs to be passed in all clients participating in the training along with base_model mappings \n", "* device_y: PYU, which device has label \n", "* model_fuse: The fusion model " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Define base_model_dict. \n", "```python\n", "base_model_dict:Dict[PYU,model_fn]\n", "```" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "base_model_dict = {alice: model_base_alice, bob: model_base_bob}" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "from secretflow.security.privacy import DPStrategy, LabelDP\n", "from secretflow.security.privacy.mechanism.tensorflow import GaussianEmbeddingDP\n", "\n", "# Define DP operations\n", "train_batch_size = 128\n", "gaussian_embedding_dp = GaussianEmbeddingDP(\n", " noise_multiplier=0.5,\n", " l2_norm_clip=1.0,\n", " batch_size=train_batch_size,\n", " num_samples=train_data.values.partition_shape()[alice][0],\n", " is_secure_generator=False,\n", ")\n", "label_dp = LabelDP(eps=64.0)\n", "dp_strategy_alice = DPStrategy(label_dp=label_dp)\n", "dp_strategy_bob = DPStrategy(embedding_dp=gaussian_embedding_dp)\n", "dp_strategy_dict = {alice: dp_strategy_alice, bob: dp_strategy_bob}\n", "dp_spent_step_freq = 10" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO:root:Create proxy actor with party alice.\n", "INFO:root:Create proxy actor with party bob.\n" ] } ], "source": [ "sl_model = SLModel(\n", " base_model_dict=base_model_dict,\n", " device_y=alice,\n", " model_fuse=model_fuse,\n", " dp_strategy_dict=dp_strategy_dict,\n", ")" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "( age job marital education\n", " 1426 0.279412 0.181818 0.5 0.333333\n", " 416 0.176471 0.636364 1.0 0.333333\n", " 3977 0.264706 0.000000 0.5 0.666667\n", " 2291 0.338235 0.000000 0.5 0.333333\n", " 257 0.132353 0.909091 1.0 0.333333\n", " ... ... ... ... ...\n", " 1508 0.264706 0.818182 1.0 0.333333\n", " 979 0.544118 0.090909 0.0 0.000000\n", " 3494 0.455882 0.090909 0.5 0.000000\n", " 42 0.485294 0.090909 0.5 0.333333\n", " 1386 0.455882 0.636364 0.5 0.333333\n", " \n", " [905 rows x 4 columns],\n", " y\n", " 1426 0\n", " 416 0\n", " 3977 0\n", " 2291 0\n", " 257 0\n", " ... ..\n", " 1508 0\n", " 979 0\n", " 3494 0\n", " 42 0\n", " 1386 0\n", " \n", " [905 rows x 1 columns])" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sf.reveal(test_data.partitions[alice].data), sf.reveal(\n", " test_label.partitions[alice].data\n", ")" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "( age job marital education\n", " 1106 0.235294 0.090909 0.5 0.333333\n", " 1309 0.176471 0.363636 0.5 0.333333\n", " 2140 0.411765 0.272727 1.0 0.666667\n", " 2134 0.573529 0.454545 0.5 0.333333\n", " 960 0.485294 0.818182 0.5 0.333333\n", " ... ... ... ... ...\n", " 664 0.397059 0.090909 1.0 0.333333\n", " 3276 0.235294 0.181818 0.5 0.666667\n", " 1318 0.220588 0.818182 0.5 0.333333\n", " 723 0.220588 0.636364 0.5 0.333333\n", " 2863 0.176471 0.363636 1.0 0.666667\n", " \n", " [3616 rows x 4 columns],\n", " y\n", " 1106 0\n", " 1309 0\n", " 2140 1\n", " 2134 0\n", " 960 0\n", " ... ..\n", " 664 0\n", " 3276 0\n", " 1318 0\n", " 723 0\n", " 2863 0\n", " \n", " [3616 rows x 1 columns])" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sf.reveal(train_data.partitions[alice].data), sf.reveal(\n", " train_label.partitions[alice].data\n", ")" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO:root:SL Train Params: {'self': , 'x': VDataFrame(partitions={alice: Partition(data=), bob: Partition(data=)}, aligned=True), 'y': VDataFrame(partitions={alice: Partition(data=)}, aligned=True), 'batch_size': 128, 'epochs': 10, 'verbose': 1, 'callbacks': None, 'validation_data': (VDataFrame(partitions={alice: Partition(data=), bob: Partition(data=)}, aligned=True), VDataFrame(partitions={alice: Partition(data=)}, aligned=True)), 'shuffle': True, 'sample_weight': None, 'validation_freq': 1, 'dp_spent_step_freq': 10, 'dataset_builder': None, 'audit_log_dir': None, 'audit_log_params': {}, 'random_seed': 19860}\n", "E0427 15:30:54.132951000 4559730176 fork_posix.cc:76] Other threads are currently calling into gRPC, skipping fork() handlers\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m Model: \"sequential\"\n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m _________________________________________________________________\n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m Layer (type) Output Shape Param # \n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m =================================================================\n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m dense (Dense) (None, 100) 500 \n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m \n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m dense_1 (Dense) (None, 64) 6464 \n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m \n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m =================================================================\n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m Total params: 6,964\n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m Trainable params: 6,964\n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m Non-trainable params: 0\n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m _________________________________________________________________\n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m Model: \"model\"\n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m __________________________________________________________________________________________________\n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m Layer (type) Output Shape Param # Connected to \n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m ==================================================================================================\n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m input_2 (InputLayer) [(None, 64)] 0 [] \n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m \n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m input_3 (InputLayer) [(None, 64)] 0 [] \n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m \n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m concatenate (Concatenate) (None, 128) 0 ['input_2[0][0]', \n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m 'input_3[0][0]'] \n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m \n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m dense_2 (Dense) (None, 64) 8256 ['concatenate[0][0]'] \n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m \n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m dense_3 (Dense) (None, 1) 65 ['dense_2[0][0]'] \n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m \n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m ==================================================================================================\n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m Total params: 8,321\n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m Trainable params: 8,321\n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m Non-trainable params: 0\n", "\u001b[2m\u001b[36m(PYUSLTFModel pid=37975)\u001b[0m __________________________________________________________________________________________________\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "\r\n", " 0%| | 0/29 [00:00" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Plot the change of loss during training\n", "plt.plot(history['train_loss'])\n", "plt.plot(history['val_loss'])\n", "plt.title('Model loss')\n", "plt.ylabel('Loss')\n", "plt.xlabel('Epoch')\n", "plt.legend(['Train', 'Val'], loc='upper right')\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "image/png": "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w4YNSsWKFZWRI0eazpk6dapSoUIFZc2aNcrZs2eVFStWKGXKlFH+97//mc75+OOPFTc3N2X16tXKwYMHleeff17x9/dXbt26le/YExMTFUBJTEws0HsuyX6JuKhU/WCN0m7mVrVDEUIIIXKV389vjaLcNbRSAKdOneK///7D0dGROnXqULVq1QJfIzg4mMaNGzN79mwADAYDvr6+DB8+nNGjR+c4f9iwYURGRpptafLOO++wZ88etm/fDsBzzz2Hl5cX8+fPN53TtWtXHB0d+emnn1AUBR8fH9555x3effddABITE/Hy8uL777/P9yhYUlISbm5uJCYm4urqWuD3XhK98WME649G89bT1RnVLlDtcIQQQogc8vv5/dBbjdSoUYOXX36Z55577qGSo4yMDCIiIggJCbkTjFZLSEgIu3btyvU5zZs3JyIiwjQNFxUVxbp16+jUqZPZOeHh4Zw8eRIw1kZt376djh07AnD27Fmio6PNXtfNzY3g4OD7vq54sLRMPVtPxgHQTuqPhBBCWLkCr+LXtWtXmjRpwgcffGB2fMaMGezbty/XNZJyEx8fj16vx8vLvFbFy8uL48eP5/qcHj16EB8fT8uWLVEUhaysLN544w3Gjh1rOmf06NEkJSURFBSETqdDr9czdepUevbsCUB0dLTpde593ezHcpOenk56errp66SkpHy9z9Lin1Px3MrUU6msI7V9ZERNCCGEdSvwCNK2bdvMRmyydezYkW3bthVKUPezZcsWpk2bxty5czlw4ACrVq1i7dq1TJkyxXTOzz//zOLFi1myZAkHDhxg0aJFfPbZZ4+8iOX06dNxc3Mz3Xx9fR/17ZQo2atnP1PLS/ZeE0IIYfUKPIJ08+ZN7Ozschy3tbUt0KiKu7s7Op2OmJgYs+MxMTF4e+c+RRMWFkavXr0YOHAgAHXq1CElJYXBgwczbtw4tFot7733HqNHjzbVEtWpU4fz588zffp0+vTpY7p2TEwMFStWNHvd+vXr3zfeMWPGMGrUKNPXSUlJkiTdlqU3sDny9urZtaV7TQghhPUr8AhSnTp1WL58eY7jy5Yto1atWvm+jp2dHQ0bNjQruDYYDISHh9OsWbNcn5OamopWax6yTqcDMLXx3+8cg8EAgL+/P97e3mavm5SUxJ49e+77ugD29va4urqa3YTR/vM3uJGaSVknW5r4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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Plot the change of accuracy during training\n", "plt.plot(history['train_accuracy'])\n", "plt.plot(history['val_accuracy'])\n", "plt.title('Model accuracy')\n", "plt.ylabel('Accuracy')\n", "plt.xlabel('Epoch')\n", "plt.legend(['Train', 'Val'], loc='upper left')\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "image/png": "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RHJZoUKFmDJlCqNHj6Z9+/Y3bdeuXTtsNhuTJ09Os//jjz/GYrGk3kl27b//vIts4sSJabatViuPP/443377Lbt37073fufPn8/yZ5kzZw733nsvXbp0oXPnzmker7/+OgDffPPNLc+RlbquhSzjhmkANm7cyPr16zNVb7t27Th16hRLlixJsz8xMZEvvviCgIAA7rrrrkyd65/nTUlJYcqUKan7bDYbn376aZp2AQEBtGjRgs8//5yzZ8+mO8/t/Ayu6dy5M3Xq1GHs2LEZ/nnExsYybNiw1O1KlSqxYcMGkpKSUvctW7aMkydPZul9a9SoQZ06dZg/fz7z588nKCiI++67L/V4TvzeiWQH9QCJmOBmlwJu1L59e1q2bMmwYcM4duwY9erV46effuL777/nlVdeSR3zU79+fbp168b//vc/oqOjadq0KWFhYRw6dCjdOd99911+/fVXQkJC6Nu3LzVr1uTixYts3bqV1atXc/HixUx/ho0bN3Lo0CFeeumlDI+XLl2au+66izlz5vDGG2/c8lyZreuRRx5h8eLFPProozz88MMcPXqUqVOnUrNmTS5fvvyvNT///PPMnDmTJ554gt69e9OgQQMuXLjA/Pnz2b17N19//XXqIOusaN++Pc2aNWPIkCEcO3aMmjVrsnjxYqKjo9O1/eyzz2jevDl16tShb9++VKxYkYiICNavX8+pU6fYsWNHlt8fHL1KixcvJjQ0lPvuu48nn3ySZs2a4ebmxp49e5g7dy5FixZNnQvoueeeY9GiRbRp04Ynn3ySw4cPM3v27HRjyTKjS5cujBw5Ek9PT/r06YOLS9p/W2fn751ItjHt/jMRJ3HjbfC3ktEt2rGxscarr75qlCpVynBzczOqVKlifPDBB4bdbk/T7sqVK8bLL79sFC9e3PDx8THat29vnDx5Mt1t8IbhuG29f//+RnBwsOHm5maULFnSePDBB41p06altsnMbfADBgwwAOPw4cM3bTN69GgDMHbs2GEYhuM2+P79+2fYNjN12e12Y9y4cUa5cuUMDw8Po0GDBsayZcuMHj16GOXKlbtpHTe6dOmS8eqrrxoVKlQw3NzcDF9fX6Nly5bGjz/+mK5tjx49DB8fn3T7R40aZfzzr88LFy4Yzz77rOHr62v4+fkZzz77rLFt27YM/xwPHz5sdO/e3ShZsqTh5uZm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AoBhEL/4ZbztyYTZGlCs0eP0albe7KpEROQmstwDVLNmTf744490+xctWkSDBg2ypajMmjFjBnXq1KFx48Z3dJ7x48fj5+eX+ggODs6mCsVZxG78Gu+zG7hiuPN9qVd4q6Pu+BIRycuy3AM0cuRIevTowenTp7Hb7SxevJj9+/fz9ddfs2zZsiydy9/fH6vVSkRERJr9ERERlCxZ8pavjYuLY968ebz99ttp9l97XUREBEFBQWnOWb9+/QzPNXToUAYNGpS6HRMToxAkmZYQfQ5j1XAAvvboxts92uFm1TrDIiJ5WZb/lu7YsSM//PADq1evxsfHh5EjR7J3715++OEHWrVqlaVzubu707BhQ8LCwlL32e12wsLCaNKkyS1fu3DhQhITE3nmmWfS7K9QoQIlS5ZMc86YmBg2btx403N6eHjg6+ub5iGSGYZhsGPmy/gaMRygLKG936KIt+74EhHJ67LcAwRw77338vPPP2dLAYMGDaJHjx40atSIxo0bM3HiROLi4ujVqxcA3bt3p3Tp0owfPz7N62bMmEGnTp0oXrx4mv0Wi4VXXnmFd955hypVqlChQgVGjBhBqVKl6NSpU7bULHLNd0sW8lj0jwBceehD6pUsanJFIiKSGbcVgLJTly5dOH/+PCNHjiQ8PJz69euzcuXK1EHMJ06cSLf8xv79+1m7di0//fRThuf873//S1xcHM8//zxRUVE0b96clStX4unpmeOfR5zHqp3HqbNtNLjAgTKdqde0tdkliYhIJmVqLbCiRYtmekDnxYsX77gos2ktMPk3u09H8/Pn/+VVl3lcdi1Kode2gZd6f0REzJTta4FNnDgx9fmFCxd45513aN26deqYmvXr17Nq1SpGjBhx+1WL5BPnYhIY/dUyZlu+BcDrkXcVfkRE8pksrwb/+OOP07JlS1566aU0+ydPnszq1asLxGzL6gGSm0lIttFl6joGnXuT+607SS53P249vwfd8i4iYrqsfH9n+S6wVatW0aZNm3T727Rpw+rVq7N6OpF8wzAMBi/cQfDZVdxv3Ylh9cCtw8cKPyIi+VCWA1Dx4sX5/vvv0+3//vvv092RJVKQfBJ2kN93HmKk2/8BYLn3NSheyeSqRETkdmT5LrC33nqL5557jjVr1hASEgLAxo0bWblyJdOnT8/2AkXygh92nGHi6oO87bqAAEsU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ESN4/PHH2bFjB08//TRdu3Zl7969AMTFxdG6dWuKFi3K5s2bWbhwIatXr04TcKZMmUL//v15/vnn2bVrF0uXLqVy5cpp3uOtt97iySefZOfOnbRr146nn36aixcv5urnFJFsYoiI5HE9evQwrFar4ePjk+YxduxYwzAMAzBeeOGFNK8JCQkx+vXrZxiGYUybNs0oWrSocfny5dTjy5cvN1xcXIzw8HDDMAyjVKlSxrBhw25aA2AMHz48dfvy5csGYPz444/Z9jlFJPdoDJCI5AstW7ZkypQpafYVK1Ys9XmTJk3SHGvSpAnbt28HYO/evdSrVw8fH5/U482aNcNut7N//34sFgtnzpzhwQcfvGUNdevWTX3u4+ODr68v586du92PJCImUgASkXzBx8cn3SWp7OLl5ZWpdm5ubmm2LRYLdrs9J0oSkRymMUAiUiBs2LAh3XaNGjUAqFGjBjt27CAuLi71+J9//omLiwvVqlWjcOHClC9fnrCwsFytWUTMox4gEckXEhMTCQ8PT7PP1dUVf39/ABYuXEijRo1o3rw5c+bMYdOmTcyYMQOAp59+mlGjRtGjRw9Gjx7N+fPnGTBgAM8++yyBgYEAjB49mhdeeIGAgADatm1LbGwsf/75JwMGDMjdDyoiuUIBSETyhZUrVxIUFJRmX7Vq1di3bx/guENr3rx5vPjiiwQFBfHNN99Qs2ZNALy9vVm1ahUDBw7k7rvvxtvbm8cff5wJEyaknqtHjx4kJCTw8ccfM3jwYPz9/encuXPufUARyVUWwzAMs4sQEbkTFouF7777jk6dOpldiojkExoDJCIiIk5HAUhEREScjsYAiUi+pyv5IpJV6gESERERp6MAJCIiIk5HAUhEREScjgKQiIiIOB0FIBEREXE6CkAiIiLidBSARERExOkoAImIiIjTUQASERERp/P/SL07g5FK2BIAAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Plot the Area Under Curve(AUC) of loss during training\n", "plt.plot(history['train_auc_1'])\n", "plt.plot(history['val_auc_1'])\n", "plt.title('Model Area Under Curve')\n", "plt.ylabel('Area Under Curve')\n", "plt.xlabel('Epoch')\n", "plt.legend(['Train', 'Val'], loc='upper left')\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's call the evaluation function" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Evaluate Processing:: 100%|█████████████████████████████████████████████████████████████████████████████████████| 8/8 [00:00<00:00, 171.46it/s, loss:0.2899125814437866 accuracy:0.8751381039619446 auc_1:0.8452339172363281]\n" ] } ], "source": [ "global_metric = sl_model.evaluate(test_data, test_label, batch_size=128)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Compare to local model" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Model \n", "Here, we use the same model structure as the one used in the split learning example, but only the model structure for Alice is used in this case. The code for defining the model is shown below. \n", "#### Data \n", "The data also use kaggle's anti-fraud data. Here, we just use Alice's data of the new bank. \n", "1. The total sample size was 11162, including 8929 training set and 2233 test set. \n", "2. The feature dimension is 4. " ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "from tensorflow import keras\n", "from tensorflow.keras import layers\n", "import tensorflow as tf\n", "from sklearn.model_selection import train_test_split\n", "\n", "\n", "def create_model():\n", " model = keras.Sequential(\n", " [\n", " keras.Input(shape=4),\n", " layers.Dense(100, activation=\"relu\"),\n", " layers.Dense(64, activation='relu'),\n", " layers.Dense(64, activation='relu'),\n", " layers.Dense(1, activation='sigmoid'),\n", " ]\n", " )\n", " model.compile(\n", " loss='binary_crossentropy',\n", " optimizer='adam',\n", " metrics=[\"accuracy\", tf.keras.metrics.AUC()],\n", " )\n", " return model\n", "\n", "\n", "single_model = create_model()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Data process" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "from sklearn.model_selection import train_test_split\n", "from sklearn.preprocessing import MinMaxScaler\n", "from sklearn.preprocessing import LabelEncoder\n", "\n", "encoder = LabelEncoder()\n", "single_part_data = alice_data.copy()\n", "\n", "single_part_data['job'] = encoder.fit_transform(alice_data['job'])\n", "single_part_data['marital'] = encoder.fit_transform(alice_data['marital'])\n", "single_part_data['education'] = encoder.fit_transform(alice_data['education'])\n", "single_part_data['y'] = encoder.fit_transform(alice_data['y'])" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "y = single_part_data['y']\n", "alice_data = single_part_data.drop(columns=['y'], inplace=False)" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [], "source": [ "scaler = MinMaxScaler()\n", "alice_data = scaler.fit_transform(alice_data)" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "train_data, test_data = train_test_split(\n", " alice_data, train_size=0.8, random_state=random_state\n", ")\n", "train_label, test_label = train_test_split(y, train_size=0.8, random_state=random_state)" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(4521, 4)" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "alice_data.shape" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/10\n", "29/29 [==============================] - 1s 10ms/step - loss: 0.5564 - accuracy: 0.8261 - auc_3: 0.4520 - val_loss: 0.4089 - val_accuracy: 0.8729 - val_auc_3: 0.4384\n", "Epoch 2/10\n", "29/29 [==============================] - 0s 3ms/step - loss: 0.3771 - accuracy: 0.8877 - auc_3: 0.4524 - val_loss: 0.3969 - val_accuracy: 0.8729 - val_auc_3: 0.4322\n", "Epoch 3/10\n", "29/29 [==============================] - 0s 3ms/step - loss: 0.3653 - accuracy: 0.8877 - auc_3: 0.4417 - val_loss: 0.3911 - val_accuracy: 0.8729 - val_auc_3: 0.4316\n", "Epoch 4/10\n", "29/29 [==============================] - 0s 3ms/step - loss: 0.3601 - accuracy: 0.8877 - auc_3: 0.4514 - val_loss: 0.3875 - val_accuracy: 0.8729 - val_auc_3: 0.4443\n", "Epoch 5/10\n", "29/29 [==============================] - 0s 3ms/step - loss: 0.3585 - accuracy: 0.8877 - auc_3: 0.4626 - val_loss: 0.3855 - val_accuracy: 0.8729 - val_auc_3: 0.4680\n", "Epoch 6/10\n", "29/29 [==============================] - 0s 3ms/step - loss: 0.3571 - accuracy: 0.8877 - auc_3: 0.4737 - val_loss: 0.3839 - val_accuracy: 0.8729 - val_auc_3: 0.4867\n", "Epoch 7/10\n", "29/29 [==============================] - 0s 3ms/step - loss: 0.3557 - accuracy: 0.8877 - auc_3: 0.4879 - val_loss: 0.3828 - val_accuracy: 0.8729 - val_auc_3: 0.5052\n", "Epoch 8/10\n", "29/29 [==============================] - 0s 2ms/step - loss: 0.3547 - accuracy: 0.8877 - auc_3: 0.5001 - val_loss: 0.3818 - val_accuracy: 0.8729 - val_auc_3: 0.5164\n", "Epoch 9/10\n", "29/29 [==============================] - 0s 2ms/step - loss: 0.3539 - accuracy: 0.8877 - auc_3: 0.5107 - val_loss: 0.3807 - val_accuracy: 0.8729 - val_auc_3: 0.5290\n", "Epoch 10/10\n", "29/29 [==============================] - 0s 2ms/step - loss: 0.3530 - accuracy: 0.8877 - auc_3: 0.5212 - val_loss: 0.3799 - val_accuracy: 0.8729 - val_auc_3: 0.5368\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "single_model.fit(\n", " train_data,\n", " train_label,\n", " validation_data=(test_data, test_label),\n", " batch_size=128,\n", " epochs=10,\n", " shuffle=False,\n", ")" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "8/8 [==============================] - 0s 1ms/step - loss: 0.3799 - accuracy: 0.8729 - auc_3: 0.5368\n" ] }, { "data": { "text/plain": [ "[0.3799220025539398, 0.8729282021522522, 0.5367639064788818]" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "single_model.evaluate(test_data, test_label, batch_size=128)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Summary\n", "The above two experiments simulate a typical vertical scene training problem. Alice and Bob have the same sample group, but each side has only a part of the features. If Alice only uses her own data to train the model, an accuracy of **0.872**, AUC **0.53** model can be obtained. However, if Bob's data are combined, a model with an accuracy of **0.875** and AUC **0.885** can be obtained." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Conclusion" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* This tutorial introduces what is split learning and how to do it in secretFlow. \n", "* It can be seen from the experimental data that split learning has significant advantages in expanding sample dimension and improving model effect through joint multi-party training.\n", "* This tutorial uses plaintext aggregation to demonstrate, without considering the leakage problem of hidden layer. Secretflow provides AggLayer to avoid the leakage problem of hidden layer plaintext transmission through MPC,TEE,HE, and DP. If you are interested, please refer to relevant documents.\n", "* Next, you may want to try different data sets, you need to vertically shard the data first and then follow the flow of this tutorial.\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.16" }, "vscode": { "interpreter": { "hash": "ae1fdd5fd034b7d694352220485921694ff89198520409089b4646721fce11ca" } } }, "nbformat": 4, "nbformat_minor": 4 }