復讐: 本チュートリアルシリーズのパート2で、私たちはFederated Learningを使ってトイモデル(初歩的なモデル)のトレーニングを行いました。その際、データ所有者たちは自分たちの勾配ベクトルを見るためにモデル所有者を信頼する必要がありました。
要約: このチュートリアルでは、パート3で紹介した高度なツールを使うことで、学習済みモデルをモデル所有者(ここでは私たち)に戻す前に、モデルの集計を行います。モデルの平均化は、信頼できる第三者に任せます。
集計担当の信頼できる第三者を本チュートリアルではセキュアワーカー(secure worker)と呼びます。
こうすることで、誰がどのようなウェイト(勾配ベクトル)を送ってきたのかを知りうるのはセキュアワーカーだけになります。モデル所有者はモデルのどの部分がアップデートされたのかは知る事ができるかもしれませんが、どのワーカー(BobなのかAliceなのか)がその部分もモデルをアップデートしたのかを知る事はできません。これはデータの秘匿性がワンランク上がったことを意味します。
Authors:
In [ ]:
import torch
import syft as sy
import copy
hook = sy.TorchHook(torch)
from torch import nn, optim
In [ ]:
# データ所有者を2名(BobとAlice)作成します。
bob = sy.VirtualWorker(hook, id="bob")
alice = sy.VirtualWorker(hook, id="alice")
secure_worker = sy.VirtualWorker(hook, id="secure_worker")
# トイデータセット(初歩的なモデルで使用するデータセット)の準備
data = torch.tensor([[0,0],[0,1],[1,0],[1,1.]], requires_grad=True)
target = torch.tensor([[0],[0],[1],[1.]], requires_grad=True)
# データを各ワーカーへ送り、そのポインタを取得しておきます。
bobs_data = data[0:2].send(bob)
bobs_target = target[0:2].send(bob)
alices_data = data[2:].send(alice)
alices_target = target[2:].send(alice)
In [ ]:
# トイモデルを初期化
model = nn.Linear(2,1)
In [ ]:
bobs_model = model.copy().send(bob)
alices_model = model.copy().send(alice)
bobs_opt = optim.SGD(params=bobs_model.parameters(),lr=0.1)
alices_opt = optim.SGD(params=alices_model.parameters(),lr=0.1)
In [ ]:
In [ ]:
for i in range(10):
# Bobのモデルを学習
bobs_opt.zero_grad()
bobs_pred = bobs_model(bobs_data)
bobs_loss = ((bobs_pred - bobs_target)**2).sum()
bobs_loss.backward()
bobs_opt.step()
bobs_loss = bobs_loss.get().data
# Aliceのモデルを学習
alices_opt.zero_grad()
alices_pred = alices_model(alices_data)
alices_loss = ((alices_pred - alices_target)**2).sum()
alices_loss.backward()
alices_opt.step()
alices_loss = alices_loss.get().data
print("Bob:" + str(bobs_loss) + " Alice:" + str(alices_loss))
In [ ]:
alices_model.move(secure_worker)
In [ ]:
bobs_model.move(secure_worker)
最後に、トレーニングエポックの最後のステップとして、BobとAliceの学習済みモデルを集計し、結果のウェイトをモデル所有者(この場合は私たち)のモデルのウェイトにセットします。
In [ ]:
with torch.no_grad():
model.weight.set_(((alices_model.weight.data + bobs_model.weight.data) / 2).get())
model.bias.set_(((alices_model.bias.data + bobs_model.bias.data) / 2).get())
In [ ]:
iterations = 10
worker_iters = 5
for a_iter in range(iterations):
bobs_model = model.copy().send(bob)
alices_model = model.copy().send(alice)
bobs_opt = optim.SGD(params=bobs_model.parameters(),lr=0.1)
alices_opt = optim.SGD(params=alices_model.parameters(),lr=0.1)
for wi in range(worker_iters):
# Bobのモデルをトレーニング
bobs_opt.zero_grad()
bobs_pred = bobs_model(bobs_data)
bobs_loss = ((bobs_pred - bobs_target)**2).sum()
bobs_loss.backward()
bobs_opt.step()
bobs_loss = bobs_loss.get().data
# Aliceのモデルをトレーニング
alices_opt.zero_grad()
alices_pred = alices_model(alices_data)
alices_loss = ((alices_pred - alices_target)**2).sum()
alices_loss.backward()
alices_opt.step()
alices_loss = alices_loss.get().data
alices_model.move(secure_worker)
bobs_model.move(secure_worker)
with torch.no_grad():
model.weight.set_(((alices_model.weight.data + bobs_model.weight.data) / 2).get())
model.bias.set_(((alices_model.bias.data + bobs_model.bias.data) / 2).get())
print("Bob:" + str(bobs_loss) + " Alice:" + str(alices_loss))
最後にテストデータを使って、モデルが正しく学習したことを確認しましょう。このトイモデルのケースでは、トレーニングで使用したものと同じデータセットをテストデータにも使用します。しかし、実際のプロジェクトでは、学習で使わなかったデータをテストデータとして使います。
In [ ]:
preds = model(data)
loss = ((preds - target) ** 2).sum()
In [ ]:
print(preds)
print(target)
print(loss.data)
このトイモデルの例では、Federated Learningを使ったモデルは一般的なPytorchの手法(ローカルだけで)だけで学習したものと比べると精度が低く、学習が不十分な感じがします。しかし、各ワーカー(今回のケースではAliceとBob)のデータを露出せずにモデルの学習を行えています。また、各ワーカーの環境にて部分的に学習されたモデルをセキュアワーカー環境化で集計することにより、モデル所有者が学習途中のモデルからデータを推測することも防いでいます。
次のチュートリアルでは、信頼できるセキュアワーカーが、集計作業を勾配ベクトルから直接行えるよう変更を加えます。そうすることで、より高い制度で集計ができ、精度の向上も期待できます。
In [ ]:
本チュートリアルを完了しました。おめでとうございます!もし、このチュートリアルを気に入って、プライバシーに配慮した非中央集権的なAI技術や付随する(データやモデルの)サプライチェーンにご興味があって、プロジェクトに参加したいと思われるなら、以下の方法で可能です。
一番簡単に貢献できる方法はこのGitHubのレポジトリにスターを付けていただくことです。スターが増えると露出が増え、より多くのデベロッパーにこのクールな技術の事を知って貰えます。
最新の開発状況のトラッキングする一番良い方法はSlackに入ることです。 下記フォームから入る事ができます。 http://slack.openmined.org
コミュニティに貢献する一番良い方法はソースコードのコントリビューターになることです。PySyftのGitHubへアクセスしてIssueのページを開き、"Projects"で検索してみてください。参加し得るプロジェクトの状況を把握することができます。また、"good first issue"とマークされているIssueを探す事でミニプロジェクトを探すこともできます。
もし、ソースコードで貢献できるほどの時間は取れないけど、是非何かサポートしたいという場合は、寄付をしていただくことも可能です。寄附金の全ては、ハッカソンやミートアップの開催といった、コミュニティ運営経費として利用されます。
In [ ]: