本教程演示了如何使用联合学习(Federated Learning),目的是使用来自不同用户的数据训练机器学习模型,而无需用户共享数据。 这些步骤在使用 UI 和 XGPBoost 框架的少量代码环境中完成。 使用 UCI: Adult - Predict income 数据集,训练好的模型会根据人口普查数据预测收入是否超过 $50K/yr 。 该数据集也被称为 "人口普查收入 "数据集。
在本教程中,您将完成这些任务:
注:
- 这是用于运行 UI 驱动的 Federated Learning 试验的逐步教程。 要查看 API 驱动方法的代码样本,请转至 Federated Learning XGBoost 样本。
- 在本教程中, admin 指的是启动 Federated Learning 试验的用户, party 指的是在该试验由管理员启动后发送其模型结果的一个或多个用户。 虽然本教程可以由管理员和多个参与方完成,但单个用户也可以作为管理员和参与方完成完整运行。 为更简单地进行演示,在以下教程中,一个参与方仅提交一个数据集。 有关管理员和参与方的更多信息,请参阅 术语。
先决条件
验证 Python 版本
确保您正在使用与管理员相同的 Python 版本。 使用不同的 Python 版本可能会导致兼容性问题。 要查看与不同框架兼容的 Python 版本,请参阅 框架和 Python 版本兼容性。
打开项目
使用现有 项目 或创建新的项目。 您必须至少具有管理许可权。
将watsonx.aiRuntime 服务与您的项目关联。
- 在项目中,单击 管理> 服务和集成。
- 单击 关联服务。
- 从列表中选择 "watsonx.ai运行时实例,然后点击 "协理;如果没有设置实例,则点击 "新服务。
任务 1:启动联合学习
在本节中,您将创建、配置并启动一个联合学习实验。
任务 1a: 创建联合学习实验资产
在项目中,单击 Assets 选项卡。
单击 New asset > 在分布式数据上训练模型,创建 Federated learning experiment asset。
输入试验的 名称 和 (可选) 描述。
在 "选择机器学习实例"下验证相关的watsonx.aiRuntime 实例。 如果没有看到相关的watsonx.aiRuntime 实例,请按照以下步骤操作:
单击 关联 Machine Learning 服务实例。
选择现有实例并单击 关联,或者创建 新服务。
单击 重新装入 以查看关联的服务。
单击下一步。
任务 1b: 配置实验
在 " 配置 " 页面上,选择 硬件规范。
在 机器学习框架 下拉列表下,选择 scikit-learn。
对于 模型类型,选择 XGBoost。
对于 Fusion 方法,选择 XGBoost 分类融合。
单击下一步。
任务 1c: 定义超参数
将 Rounds 字段的值设置为
5
。接受其余字段的缺省值。
单击下一步。
任务 1d: 选择远程培训系统
单击添加新系统。
键入远程培训系统的名称。
在 允许的身份下,选择将参与试验的用户,然后单击 添加。 您可以在此联合实验训练实例中添加与参与者一样多的允许身份。
任何允许的身份都必须是项目的合作者,并至少拥有 Admin 权限。 针对您打算使用的每个远程参与方重复此步骤,以添加其他系统。完成后,请单击添加系统。
返回到 " 选择远程训练系统 " 页面,验证是否选择了系统,然后单击 下一步。
任务 1e: 查看设置
复查设置,然后单击创建。
监视状态。 该 Federated Learning 试验启动后,其状态为暂挂中。 当该试验准备就绪,可供参与方连接时,状态会更改为设置 - 正在等待远程系统。 这可能需要几分钟。
单击 查看设置信息,下载聚会配置和聚会连接器脚本,您可以在远程聚会上运行这些配置和脚本。
单击您创建的每个远程培训系统旁边的 Download config 图标 。 将派对连接器脚本保存到您机器上的目录中,名称如下:
remote-test-system-configuration.py
单击完成。
检查您的进度
The following image shows the experiment with status 'waiting for remote systems'.
任务 2:将模型作为派对进行培训
要训练模型,需要下载数据集,然后编辑并运行 python 脚本。 请按照以下步骤将模型作为一方进行训练:
任务 2a: 下载数据集和脚本
新建一个本地目录,并将下载的 Party Connector 脚本放入 Task 中1e进入新目录。
右键单击文件名下载以下文件,然后单击保存链接为。 将其保存到与参与方连接器脚本相同的目录。
验证您是否拥有派对连接器脚本,成人数据集、数据处理程序和日志配置文件位于同一目录中。 如果列出目录中的文件,就会看到这些文件:
adult.csv adult_sklearn_data_handler.py remote-test-system-configuration.py log_config.yaml
任务2b:安装watsonx.ai运行时
如果使用 Windows 或 Linux 操作系统,请运行
pip install 'ibm_watsonx_ai[fl-rt23.1-py3.10]'
。如果您使用的是配备 M 系列 CPU 和 Conda 的 Mac OS,请下载 安装脚本,然后运行
./install_fl_rt23.1_macos.sh <name for new conda environment>
。
任务 2c: 编辑并运行聚会连接器脚本
编辑聚会连接器文件 remote-test-systm-configuration.py
,并作出以下更改:
将以下代码添加为python文件的第二行。
log_config_path = "log_config.yaml"
提供您的证书:粘贴远程培训系统中定义的用户的 API 密钥。 如果您没有 API 密钥,请转到IBM CloudAPI 密钥页面,然后单击创建 API 密钥,填写字段并单击创建。
为了party_metadata字段,提供名称、路径和信息,应类似于以下 JSON 文本。
party_metadata = { wml_client.remote_training_systems.ConfigurationMetaNames.DATA_HANDLER: { "info": {"txt_file": "./adult.csv"}, "name": "AdultSklearnDataHandler", "path": "./adult_sklearn_data_handler.py" } }
其中:
name
: 为数据处理程序定义的类名。path
: 数据处理程序所在位置的路径。info
: 为本地数据集的文件类型或数据集的路径创建键值对。
保存聚会连接器脚本。
使用
python
或python3
运行聚会连接器脚本,具体取决于您安装的脚本。python remote-test-system-configuration.py
从 UI 中,可以监视该 Federated Learning 试验的状态。 当所有参与方都连接到聚集器时,聚集器将促进本地模型训练和全局模型更新。 其状态为 培训。 您可以从用户界面监视 Federated Learning 试验的状态。 培训完成后,当事人会收到一个关于当事人的 Received STOP message
。 现在,您可以保存已训练的模型并将其部署到空间。
检查您的进度
下图显示了已完成的实验
任务 3:保存并在线部署模型
在本部分中,您将学习如何保存和部署训练的模型。
任务 3a: 保存模型
- 在已完成的联合学习实验中,单击 保存聚合。
- 在 Save aggregated model to project 屏幕上,键入模型名称。 然后单击 创建。
- 看到模型已创建的通知后,单击 在项目中查看。 如果错过了通知,请单击项目名称返回资产选项卡,然后单击模型名称查看。
任务 3b: 将模型提升到空间
- 在 模型 部分中,单击模型以查看其详细信息页面。
- 单击 "推广 "到部署空间"。
- 从列表中选择 目标空间,或创建新的部署空间。
选择 创建新部署空间。
键入部署空间的名称。
选择您的存储服务。
选择您的机器学习服务。
单击创建。
创建部署空间后,关闭窗口。
- 选择 提升模型后转至空间中的模型 选项。
- 单击提升。
任务 3c: 创建并查看在线部署
- 当模型显示在部署空间内时,单击 新建部署。
- 选择 联机 作为 部署类型。
- 指定部署名称。
- 单击创建。
- 等待部署状态更改为 已部署,然后单击部署名称。
- 查看端点和代码片段,以便在应用程序中使用此部署。
检查您的进度
下图显示了在线部署情况,
任务 4:为模型评分
在本节中,您将学习如何创建一个 Python 函数来处理评分数据,以确保其格式与训练时使用的格式相同。 为了便于比较,您还将通过调用我们创建的 Python 函数对原始数据集进行评分。
您可以创建一个Python脚本并在本地运行该脚本,也可以创建一个Jupyter笔记本并在笔记本中运行代码。
设置环境
这段代码导入了必要的库和软件包,并设置了访问机器学习 API 客户端的凭据。
# import the library and package and set the credentials
from ibm_watsonx_ai import APIClient
wml_credentials = {
"url": "https://us-south.ml.cloud.ibm.com",
"apikey": "<insert-api-key-here>"
}
client = APIClient(wml_credentials)
client.set.default_space('<insert-deployment-space-id-here>')
software_spec_id = client.software_specifications.get_id_by_name('default_py3.10')
- 在
apikey
字段中粘贴您的 IBM Cloud API 密钥。 - 粘贴您的部署空间 ID。 按照以下步骤查找部署空间 ID。
- 导航至部署空间。
- 打开部署空间。
- 单击 Manage 选项卡。
- 复制 Space GUID 并粘贴到代码中
<insert-deployment-space-id-here>
的位置。
加载数据集
该代码读取存储在资源中心的数据集。
# read the data set
import pandas as pd
import io
import requests
url = "https://api.dataplatform.cloud.ibm.com/v2/gallery-assets/entries/5fcc01b02d8f0e50af8972dc8963f98e/data"
s = requests.get(url).content
adult_csv = pd.read_csv(io.StringIO(s.decode('utf-8')))
adult_csv.head(5)
创建训练数据集
该代码从数据集中随机选择 10 行进行评分。
# choose 10 random rows for the test data set
training_data = adult_csv.sample(n=10)
training_data.head(10)
定义准备培训数据的函数
该代码定义了一个函数,用于加载原始格式的评分数据,并完全按照训练时的方法处理数据。 然后,对处理过的数据进行评分
代码会对成人训练数据和测试数据进行以下预处理:
去掉以下特征:工薪阶层"、"家庭收入"、"教育"、"婚姻状况"、"职业"、"关系"、"资本收益"、"资本损失"、"每周工时"、"原籍国
地图(M):
- 种族"、"性别 "和 "阶级 "值为 0/1
- 白人":1,"美洲-印第安-爱斯基摩人":0,"亚洲-太平洋-印度人":00,"黑人": 00,"其他":0
- 男": 11, ' 女':0
更多详情,请参阅Kamiran, F. 和 Calders, T. 《无差别分类的数据预处理技术》
根据值将 "年龄 "和 "教育 "列拆分为多列
# define the preprocess function to prepare the data for scoring
def preprocess(training_data):
if len(training_data.columns)==15:
# drop 'fnlwgt' column
training_data = training_data.drop(training_data.columns[2], axis='columns')
training_data.columns = ['age',
'workclass',
'education',
'education-num',
'marital-status',
'occupation',
'relationship',
'race',
'sex',
'capital-gain',
'capital-loss',
'hours-per-week',
'native-country',
'class']
# filter out columns unused in training, and reorder columns
training_dataset = training_data[['race', 'sex', 'age', 'education-num', 'class']]
# map 'sex' and 'race' feature values based on sensitive attribute privileged/unpriveleged groups
training_dataset['sex'] = training_dataset['sex'].map({
' Female': 0,
' Male': 1
})
training_dataset['race'] = training_dataset['race'].map({
' Asian-Pac-Islander': 0,
' Amer-Indian-Eskimo': 0,
' Other': 0,
' Black': 0,
' White': 1
})
# map 'class' values to 0/1 based on positive and negative classification
training_dataset['class'] = training_dataset['class'].map({' <=50K': 0, ' >50K': 1})
training_dataset['age'] = training_dataset['age'].astype(int)
training_dataset['education-num'] = training_dataset['education-num'].astype(int)
# split age column into category columns
for i in range(8):
if i != 0:
training_dataset['age' + str(i)] = 0
for index, row in training_dataset.iterrows():
if row['age'] < 20:
training_dataset.loc[index, 'age1'] = 1
elif ((row['age'] < 30) & (row['age'] >= 20)):
training_dataset.loc[index, 'age2'] = 1
elif ((row['age'] < 40) & (row['age'] >= 30)):
training_dataset.loc[index, 'age3'] = 1
elif ((row['age'] < 50) & (row['age'] >= 40)):
training_dataset.loc[index, 'age4'] = 1
elif ((row['age'] < 60) & (row['age'] >= 50)):
training_dataset.loc[index, 'age5'] = 1
elif ((row['age'] < 70) & (row['age'] >= 60)):
training_dataset.loc[index, 'age6'] = 1
elif row['age'] >= 70:
training_dataset.loc[index, 'age7'] = 1
# split age column into multiple columns
training_dataset['ed6less'] = 0
for i in range(13):
if i >= 6:
training_dataset['ed' + str(i)] = 0
training_dataset['ed12more'] = 0
for index, row in training_dataset.iterrows():
if row['education-num'] < 6:
training_dataset.loc[index, 'ed6less'] = 1
elif row['education-num'] == 6:
training_dataset.loc[index, 'ed6'] = 1
elif row['education-num'] == 7:
training_dataset.loc[index, 'ed7'] = 1
elif row['education-num'] == 8:
training_dataset.loc[index, 'ed8'] = 1
elif row['education-num'] == 9:
training_dataset.loc[index, 'ed9'] = 1
elif row['education-num'] == 10:
training_dataset.loc[index, 'ed10'] = 1
elif row['education-num'] == 11:
training_dataset.loc[index, 'ed11'] = 1
elif row['education-num'] == 12:
training_dataset.loc[index, 'ed12'] = 1
elif row['education-num'] > 12:
training_dataset.loc[index, 'ed12more'] = 1
training_dataset.drop(['age', 'education-num'], axis=1, inplace=True)
# move class column to be last column
label = training_dataset['class']
training_dataset.drop('class', axis=1, inplace=True)
training_dataset['class'] = label
return training_dataset
处理训练数据
该代码使用预处理函数来准备数据。
# use the preprocess function to prepare the data
processed_dataset = preprocess(training_data)
# drop class column
processed_dataset.drop('class', inplace=True, axis='columns')
processed_dataset.head(10)
创建用于评分的数据有效载荷
该代码将创建评分数据集。
# create data payload for scoring
fields = processed_dataset.columns.values.tolist()
values = processed_dataset.values.tolist()
scoring_dataset = {client.deployments.ScoringMetaNames.INPUT_DATA: [{'fields': fields, 'values': values}]}
import json
print("Scoring data: ")
scoring_formatted = json.dumps(scoring_dataset, indent=2)
print(scoring_formatted)
对模型进行评分
该代码使用 scoring_dataset 向模型发送评分请求。 您需要在此代码中包含您的在线部署 ID。 请按照以下步骤查找在线部署 ID。
- 导航至部署空间。
- 打开部署空间。
- 单击部署选项卡。
- 打开在线部署。
- 在 Information 窗格中,复制 Deployment ID 并粘贴到下面单元格中
<insert-your-online-deployment-id-here>
的位置。
# score data
prediction = client.deployments.score('<insert-your-online-deployment-id-here>', scoring_dataset)
print("Predictions and probabilities: ")
prediction_formatted = json.dumps(prediction, indent=2)
print(prediction_formatted)
检查您的进度
下图显示了已完成评分请求的预测结果和概率
后续步骤
准备好创建您自己的定制联合试验了吗? 请参阅创建 Federated Learning 试验中的高级步骤。