このチュートリアルでは、ユーザーがデータを共有することなく、異なるユーザーからのデータで機械学習モデルをトレーニングすることを目的としたFederated Learningの使い方を示します。 このステップは、UI と XGBoost フレームワークを使用するロー・コード環境で実行されます。 UCI: Adult - Predict incomeデータセットを使用し、訓練されたモデルは、国勢調査データに基づき、所得が$50K/yrを超えるかどうかを予測する。 このデータセットは「国勢調査所得」データセットとしても知られている。
このチュートリアルでは、以下のタスクを実行します:
注:
- これは、UI主導のFederated Learning実験を実行するためのステップバイステップのチュートリアルです。 APIドリブンアプローチのコードサンプルを見るには、Federated Learning XGBoost samplesをご覧ください。
- このチュートリアルでは、adminは Federated Learning の実験を開始するユーザーを指し、partyは admin によって実験が開始された後に、モデルの結果を送信する1人以上のユーザーを指します。 チュートリアルは、管理者と複数の関係者が行うことができますが、1人のユーザーが管理者と関係者の両方として、全行程を完了することもできます。 より簡潔に説明するために、下記のチュートリアルでは、1 つのデータ・セットのみが 1 つのパーティーによって実行依頼されます。 管理者とパーティーについての詳細は、「用語」を参照。
前提条件
Pythonのバージョンを確認する
管理者と同じ Python バージョンを使用していることを確認してください。 別の Python バージョンを使用すると、互換性の問題が発生する可能性があります。 さまざまなフレームワークと互換性のある Python のバージョンについては、 フレームワークと Python バージョンの互換性を参照してください。
プロジェクトを開きます
既存のプロジェクトを使用するか、新しいプロジェクトを作成します。 少なくとも管理者権限が必要です。
watsonx.aiRuntime サービスをプロジェクトに関連付けます。
- プロジェクトで、[管理] > [サービスと統合]をクリックします。
- Associate serviceをクリックします。
- リストから'watsonx.aiランタイムインスタンスを選択し、'アソシエイトをクリックします。インスタンスをセットアップするためにインスタンスを持っていない場合は、'新サービスをクリックします。
タスク1:フェデレーテッド・ラーニングの開始
このセクションでは、Federated Learning 実験を作成、設定、開始します。
タスク1a:Federated学習実験アセットの作成
プロジェクトのAssetsタブをクリックします。
New asset > Train models on distributed dataをクリックして、Federated learning experiment アセットを作成します。
実験の名前(Name)と説明(Description)を入力する。
機械学習インスタンスの選択」で、関連するwatsonx.aiRuntime インスタンスを確認します。 関連するwatsonx.aiRuntime インスタンスが表示されない場合は、以下の手順に従ってください:
Associate aMachine LearningService Instance」をクリックする。
既存のインスタンスを選択して[Associate]をクリックするか、新規サービスを作成します。
再ロード をクリックして、関連付けられたサービスを表示します。
次へ をクリックします。
タスク1b:実験の設定
Configureページで、ハードウェアの仕様を選択します。
機械学習フレームワークのドロップダウンで、scikit-learnを選択する。
モデルタイプは XGBoostを選択する。
フュージョン法には、XGBoost分類フュージョンを選択する。
次へ をクリックします。
タスク1c:ハイパーパラメーターを定義する
Roundsフィールドの値を'
5
に設定する。残りのフィールドのデフォルト値を受け入れる。
次へ をクリックします。
タスク1d:遠隔トレーニングシステムの選択
「新規システムの追加」をクリックします。
リモートトレーニングシステムの名前を入力します。
Allowed identities で、実験に参加するユーザーを選択し、Add をクリックします。 この Federated Experiment Training インスタンスには、参加者として許可される ID をいくつでも追加できます。 このチュートリアルでは、あなた自身だけを選択してください。
許可されたIDは、プロジェクトの共同作業者であり、少なくともAdmin権限を持っていなければなりません。 使用するリモート・パーティーごとにこのステップを繰り返して、さらにシステムを追加します。完了したら、 システムの追加をクリックしてください。
Select remote training systems(リモートトレーニングシステムの選択)ページに戻り、システムが選択されていることを確認し、Next(次へ)をクリックします。
タスク1e:設定を見直す
設定を確認し、 作成をクリックしてください。
状況を見てください。 統合学習エクスペリメントの開始時の状況は 保留中 です。 エクスペリメントでパーティーが接続する準備ができると、状況が セットアップ - リモート・システム待ちに変わります。 これには数分かかることがあります。
セットアップ情報の表示]をクリックすると、リモートパーティで実行できるパーティ構成とパーティ コネクタ スクリプトがダウンロードされます。
作成した各リモートトレーニングシステムの横にあるダウンロード設定アイコン「」をクリックします。 パーティ・コネクタ・スクリプトをマシン上のディレクトリに名前を付けて保存します:
remote-test-system-configuration.py
「完了」をクリックします。
進捗状況を確認する
次の画像は、ステータスが'waiting for remote systems'の実験である。
'
タスク2:パーティーとしてモデルを訓練する
モデルを訓練するには、データセットをダウンロードし、パイソン・スクリプトを編集して実行する必要がある。 以下の手順に従って、パーティーとしてのモデルをトレーニングしてください:
タスク2a:データセットとスクリプトをダウンロードする
新しいローカル ディレクトリを作成し、タスク1eでダウンロードしたパーティ コネクタ スクリプトを新しいディレクトリに移動します。
ファイル名を右クリックし、「名前を付けてリンク先を保存」をクリックして、以下のファイルをダウンロードしてください。 パーティー・コネクター・スクリプトと同じディレクトリーに保存します。
パーティ コネクタ スクリプト、Adultデータセット、データ ハンドラ、およびログ構成ファイルが同じディレクトリにあることを確認します。 ディレクトリ内のファイルをリストアップすると、これらのファイルが表示されるはずだ:
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ファイルの2行目に以下のコードを追加する。
log_config_path = "log_config.yaml"
認証情報を入力します:リモートトレーニングシステムで定義されたユーザのAPIキーを貼り付けます。 API キーをお持ちでない場合は、IBM CloudAPI keys ページに移動し、Create API key をクリックしてフィールドに入力し、Create をクリックします。
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実験のステータスは、ユーザーインターフェースからモニターすることができます。 トレーニングが終了すると、パーティーには「Received STOP message
」が与えられる。 学習したモデルを保存し、スペースに配置することができます。
進捗状況を確認する
次の画像は、完成した実験である。
'
タスク3:モデルを保存し、オンラインで展開する
このセクションでは、トレーニングしたモデルを保存し、デプロイする方法を学びます。
タスク3a:モデルの保存
- 完成した Federated Learning 実験で、Save aggregate をクリックします。
- Save aggregated model to project画面で、モデルの名前を入力します。 をクリックし、「作成」をクリックする。
- モデルが作成されたという通知が表示されたら、View in 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 CloudAPI キーを貼り付けます。- 配備スペースのIDを貼り付ける。 以下の手順に従って、配置スペース ID を検索してください。
- 配置スペースに移動します。
- 展開スペースを開く。
- 「管理」 タブをクリックします。
- スペース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)
トレーニングデータを準備する関数を定義する
このコードでは、採点データを生のフォーマットでロードし、トレーニング時とまったく同じようにデータを処理する関数を定義している。 そして、処理されたデータを採点する
このコードは、成人のトレーニングデータとテストデータに対して以下の前処理を行う:
以下の特徴を削除する:ワーククラス」、「fnlwgt」、「学歴」、「婚姻状況」、「職業」、「人間関係」、「キャピタル・ゲイン」、「キャピタル・ロス」、「週労働時間」、「出身国」
地図
- 'race'、'sex'、'class'の値を0/1にする
- 白人」: 1、「アメリカ・インディアン・エスキモー」: 0、「アジア・パック・アイスランダー」:0, ' 黒人':0, ' その他': 0
- 男性」:1, ' 女性 ':0
詳細はKamiran, F. and Calders, T. Data preprocessing techniques for classification without discriminationを参照のこと
年齢'と'学歴'カラムを値に基づいて複数のカラムに分割する
# 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を検索してください。
- 配置スペースに移動します。
- 展開スペースを開く。
- デプロイメント タブをクリックしてください。
- オンライン配備を開きます。
- 情報」ペインで「デプロイメント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)
進捗状況を確認する
次の画像は、完了したスコアリング・リクエストからの予測と確率を示している。
'
次のステップ
カスタマイズされた独自の統合エクスペリメントを作成する準備ができたら、 統合学習エクスペリメントの作成の手順の概要を参照してください。