第三部分:提出研究方案#


Propose research study

第一部分第二部分中,我们完全从数据所有者的角度学习了PySyft的功能。

作为实验室管理员的职责和PySyft数据所有者,Owen通过创建并上传"乳腺癌生物标志物"数据集,以及为Rachel创建远程访问凭证来建立数据站点。

现在我们将探讨Rachel作为数据科学家如何与Datasite进行交互,以及PySyft如何确保外部用户无法查看或访问非公开信息。

使用PySyft在私有数据集上进行远程数据科学的工作流程包含三个部分:

  • (1) 准备研究项目: 这是最全面的部分,也将是本部分的重点;数据科学家会参与这里的每一步。

  • (2) 真实数据计算: 研究项目中嵌入的代码使用私有数据作为输入运行,以计算真实结果(参见第4部分

  • (3) 结果审批与发布: 对真实结果进行检查以确保其符合数据集的隐私政策;若一切正常,则将真实结果返回给数据科学家(参见第五部分

使用PySyft对非公开数据进行研究的第一步是准备一个研究项目提交

你将学习的内容#

第三部分结束时,你将学会:

  • 如何以数据科学家的身份访问数据站点,并探索可用的数据集;

  • 如何使用模拟数据来准备数据分析代码;

  • 如何创建一个PySyft 远程代码请求;

  • 如何创建并向数据站点提交项目提案。

|:data_owner:| 3.1. 登录数据站点#


Data Scientist Login

首先,请确保本地开发数据站点正在运行。如果没有运行,syft.orchestra.launch将再次启动服务器实例。

import syft as sy

data_site = sy.orchestra.launch(name="cancer-research-centre")

现在轮到Rachel使用Owen单独发送的新凭证登录数据站点:

client = data_site.login(email="[email protected]", password="syftrocks")

登录领域后,作为数据科学家的Rachel可以浏览Datasite中可用的数据集。我们可以通过访问client.datasets轻松实现这一点。

client.datasets

如预期所示,Datasite包含一个名为Breast Cancer Biomarker的数据集,其中包含2个资产。

一旦确定我们感兴趣的数据集,就可以通过index索引或唯一的name名称来访问它们:

bc_dataset = client.datasets["Breast Cancer Biomarker"]

我们获取了bc_dataset,这是一个指向远程数据集的指针。

bc_dataset

使用指向远程数据集的指针,我们可以通过index或其唯一名称访问其内部资产。 在我们的示例中,我们可以创建一个指向features资产和targets资产的指针:

features, targets = bc_dataset.assets  # using Python tuple unpacking

现在让我们验证以下假设:数据科学家只能访问mock数据,而data无法访问的。我们将通过使用featurestargets这两个变量来实现验证,它们实际上是指向其对应远程资产的指针。

记住

在第一部分中,这两个资产被创建并存储为pandas.DataFrame对象。

features.mock.head(n=3)  # pandas.DataFrame

让我们尝试对targets做同样的操作:

targets.mock.head(n=3)

太棒了! 那关于 data 呢?🧐

features.data
targets.data

正如预期的那样,作为数据科学家的Rachel没有对远程资产中存储的非公开信息的读取权限也没有任何其他权限,编者注)。

资产主要组成部分之间的这种明确区分具有以下优势:

  1. 模拟数据是开放获取的,不会给数据所有者带来公开分享非公开信息的风险;

  2. 它为数据科学家创建一个模拟环境,以真实的方式模拟他们预期的研究;

  3. 降低数据科学家的责任风险,他们不再需要负责安全存储非公开数据;

  4. 使数据所有者能够控制数据科学家如何在其研究中使用非公开资产。

|:data_owner:| 3.2. 使用模拟数据准备代码#


DS Code Preparation

Getting access to the mock data allows to get a general understanding of what non-public data would look like. So we can use this data to start preparing our code, to run on this data.

Rachel决定通过使用scikit-learn库运行一个简单的监督机器学习实验来研究乳腺癌数据。 数据集以pandas.DataFrame格式表示,且特征已经符合机器学习模型预期的格式:samples x features矩阵。 这个结论是通过查看模拟数据得出的,因此我们可以假设它同样适用于真实的实际数据。

X, y = features.mock, targets.mock

简而言之,以下是Rachel设想的机器学习实验步骤:

  1. 使用train_test_split函数生成训练测试分区;

  2. 应用 StandardScaler 来标准化特征;

  3. 训练一个LogisticRegression模型;

  4. 计算训练数据和测试数据上的accuracy_score

为简化操作,我们将整个流程封装成一个单一Python函数。这样能更方便地准备要发送给PySyft执行的代码请求。

def ml_experiment_on_breast_cancer_data(features_data, labels, seed: int = 12345) -> tuple[float, float]:
    # include the necessary imports in the main body of the function
    # to prepare for what PySyft would expect for submitted code.
    from sklearn.model_selection import train_test_split
    from sklearn.preprocessing import StandardScaler
    from sklearn.linear_model import LogisticRegression
    from sklearn.metrics import accuracy_score
    
    X, y = features_data, labels.values.ravel()
    # 1. Data Partition
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=seed, stratify=y)
    # 2. Data normalisation
    scaler = StandardScaler()
    scaler.fit(X_train, y_train)
    X_train = scaler.transform(X_train)
    X_test = scaler.transform(X_test)
    # 3. Model training
    model = LogisticRegression().fit(X_train, y_train)
    # 4. Metrics Calculation
    acc_train = accuracy_score(y_train, model.predict(X_train))
    acc_test = accuracy_score(y_test, model.predict(X_test))
    
    return acc_train, acc_test

让我们在模拟数据上调用这个函数,检查一切是否正常运行:

ml_experiment_on_breast_cancer_data(features_data=features.mock, labels=targets.mock)

|:data_owner:| 3.3. 提交研究项目#

现在我们的代码已经在本地测试完毕,可以开始准备进行远程执行,然后创建一个新的研究项目提交到Datasite。


Propose research study

在上一节中,我们已经验证了ml_experiment_on_breast_cancer_data可以在模拟数据上成功本地运行。现在,我们有兴趣使用PySyft在真实数据上测试该函数。具体来说,我们需要将(本地)Python函数转换远程代码请求:这是一个PySyft可以处理并在数据站点远程执行的函数,而真实数据就存储在那里。

为此,我们只需要用特殊的装饰器包装我们的Python函数:syft_function_single_use

remote_user_code = sy.syft_function_single_use(features_data=features, labels=targets)(ml_experiment_on_breast_cancer_data)

syft_function_single_use 装饰器

syft_function_single_use装饰器是更通用的syft_function装饰器的简化快捷方式。该装饰器需要两个主要参数:input_policyoutput_policy。前者让数据所有者确信提交的代码仅会在选定的输入资产上运行;后者用于在多次执行间保持状态,例如限制指定代码允许运行的次数上限。

请查看Syft Policy Component获取更多详情。

此时,我们可以继续提交remote_user_code请求。然而,这将给Owen带来极大困扰,因为他们完全无法理解这段代码的意图,也不清楚Rachel计划在"癌症研究中心"数据上进行何种研究!

为了解决这些问题,PySyft允许创建并提交一个研究项目!本质上,一个项目(即syft.Project由一个(或多个)代码请求组成,并包含一个(简短的)描述,用于向数据所有者传达研究意图。


Project

description = """
    The purpose of this study will be to run a machine learning
    experimental pipeline on breast cancer data. 
    As first attempt, the pipelines includes a normalisation steps for 
    features and labels using a StandardScaler and a LabelEncoder. 
    The selected ML model is Logistic regression, with the intent
    to gather the accuracy scores on both training, and testing 
    data partitions, randomly generated.
"""

# Create a project

research_project = client.create_project(
    name="Breast Cancer ML Project",
    description=description,
    user_email_address="[email protected]"
)

我们可以通过client访问可用的projects列表:

client.projects

唯一项目名称

项目通过其唯一名称进行标识。这意味着重复提交会导致PySyft报错。

我们可以使用create_code_request方法将新的代码请求附加到我们的syft.Project实例上,即research_project

code_request = research_project.create_code_request(remote_user_code, client)
code_request

现在我们可以通过访问client.code来检查代码请求是否已到达项目:

client.code

我们确实有一个代码请求,状态为PENDING。同样地,我们可以通过访问client.requests来查看现有的请求:

client.requests

更多关于用户代码请求的内容可在组件部分查看。

继续之前#

假设Rachel非常没有耐心,会试图强制执行一个尚未批准尚未审核)的请求。让我们看看PySyft允许的操作:

client.code.ml_experiment_on_breast_cancer_data(features_data=features, labels=targets)

正如预期的那样,如果我们尝试执行一个尚未被批准的代码请求,将会返回一个SyftError错误!

恭喜完成第3部分 🎉#

恭喜你完成了教程的第三部分!👏

现在Rachel已经准备并完成了他们的研究项目,该项目已发送给Owen进行评审。 这个项目包含了Rachel在模拟数据上准备和测试的机器学习流程,并已附加到项目中以便在真实数据上远程执行。

第4部分中,我们将探讨PySyft中的代码修改请求流程如何运作,再次将视角切换到需要审核请求的数据所有者一方,必要时批准这些请求。