อัลกอริธึมส่วนกลางแบบกำหนดเอง ส่วนที่ 1: บทนำสู่ Federated Core

ดูบน TensorFlow.org ทำงานใน Google Colab ดูแหล่งที่มาบน GitHub ดาวน์โหลดโน๊ตบุ๊ค

กวดวิชานี้เป็นส่วนแรกของชุดสองส่วนที่แสดงให้เห็นถึงวิธีการใช้ประเภทที่กำหนดเองของอัลกอริทึมแบบ federated ใน TensorFlow สหพันธ์ (ฉิบหาย) โดยใช้ สหพันธ์หลัก (FC) - ชุดของการเชื่อมต่อในระดับที่ต่ำกว่าที่ทำหน้าที่เป็นรากฐานตามที่ เราได้ดำเนินการ สหพันธ์การเรียนรู้ (FL) ชั้น

ส่วนแรกนี้เป็นแนวความคิดมากกว่า เราแนะนำแนวคิดหลักและโปรแกรมนามธรรมที่ใช้ใน TFF และเราสาธิตการใช้งานในตัวอย่างง่ายๆ ด้วยอาร์เรย์เซ็นเซอร์อุณหภูมิแบบกระจาย ใน ส่วนที่สองของชุดนี้ เราจะใช้กลไกที่เราแนะนำที่นี่จะใช้รุ่นที่เรียบง่ายของการฝึกอบรมและการประเมินผลแบบ federated อัลกอริทึม ในฐานะที่ติดตามเราขอแนะนำให้คุณเพื่อการศึกษา การดำเนินงาน ของสหพันธ์เฉลี่ย tff.learning

เมื่อจบซีรีส์นี้ คุณควรจะสามารถรับรู้ได้ว่าแอปพลิเคชันของ Federated Core ไม่ได้จำกัดอยู่เพียงการเรียนรู้เท่านั้น นามธรรมโปรแกรมที่เรานำเสนอนั้นค่อนข้างทั่วไป และสามารถนำมาใช้ได้ เช่น เพื่อใช้การวิเคราะห์และการคำนวณแบบกำหนดเองอื่นๆ เหนือข้อมูลแบบกระจาย

แม้ว่าการกวดวิชานี้ถูกออกแบบมาให้อยู่ในตัวเองเราขอแนะนำให้คุณอ่านบทเรียนครั้งแรกใน การจัดหมวดหมู่ภาพ และ รุ่นข้อความ สำหรับระดับที่สูงขึ้นและการแนะนำอ่อนโยนมากขึ้นในกรอบ TensorFlow สหพันธ์และ สหพันธ์การเรียนรู้ APIs ( tff.learning ) เช่น มันจะช่วยให้คุณใส่แนวคิดที่เราอธิบายที่นี่ในบริบท

วัตถุประสงค์การใช้งาน

สั้น, สหพันธ์แกน (เอฟซี) คือการพัฒนาสภาพแวดล้อมที่ทำให้มันเป็นไปได้ที่จะดานแสดงตรรกะโปรแกรมที่รหัสรวม TensorFlow กับผู้ประกอบการกระจายการสื่อสารเช่นผู้ที่จะใช้ใน สหพันธ์ Averaging - คำนวณผลรวมการกระจายค่าเฉลี่ยและประเภทอื่น ๆ ของการรวมแบบกระจายบนชุดอุปกรณ์ไคลเอนต์ในระบบ โมเดลการออกอากาศและพารามิเตอร์ไปยังอุปกรณ์เหล่านั้น เป็นต้น

คุณอาจจะต้องตระหนักถึง tf.contrib.distribute และธรรมชาติคำถามที่จะถามในจุดนี้อาจจะในทางใดกรอบนี้แตกต่างกันอย่างไร เฟรมเวิร์กทั้งสองพยายามทำให้การคำนวณ TensorFlow กระจายออกไป

วิธีหนึ่งที่จะคิดเกี่ยวกับมันก็คือว่าในขณะที่เป้าหมายที่กำหนดไว้ tf.contrib.distribute คือการอนุญาตให้ผู้ใช้สามารถใช้แบบจำลองที่มีอยู่และรหัสการฝึกอบรมที่มีการเปลี่ยนแปลงน้อยที่สุดเพื่อช่วยให้การฝึกอบรมการกระจายและมุ่งเน้นมากเกี่ยวกับวิธีการใช้ประโยชน์จากโครงสร้างพื้นฐานแบบกระจาย ในการทำให้รหัสการฝึกอบรมที่มีอยู่มีประสิทธิภาพมากขึ้น เป้าหมายของ Federated Core ของ TFF คือการให้นักวิจัยและผู้ปฏิบัติงานสามารถควบคุมรูปแบบเฉพาะของการสื่อสารแบบกระจายที่พวกเขาจะใช้ในระบบของตนได้ จุดเน้นใน FC อยู่ที่การจัดหาภาษาที่ยืดหยุ่นและขยายได้สำหรับการแสดงอัลกอริธึมการไหลของข้อมูลแบบกระจาย แทนที่จะเป็นชุดที่เป็นรูปธรรมของความสามารถในการฝึกอบรมแบบกระจายที่นำไปใช้

หนึ่งในกลุ่มเป้าหมายหลักสำหรับ FC API ของ TFF คือนักวิจัยและผู้ปฏิบัติงานที่อาจต้องการทดลองกับอัลกอริธึมการเรียนรู้แบบรวมศูนย์ใหม่และประเมินผลที่ตามมาของตัวเลือกการออกแบบที่ละเอียดอ่อนซึ่งส่งผลต่อลักษณะที่การไหลของข้อมูลในระบบแบบกระจายได้รับการประสาน โดยไม่ต้องจมอยู่กับรายละเอียดการใช้งานระบบ ระดับของนามธรรมที่ FC API ตั้งเป้าไว้นั้นสัมพันธ์กับรหัสเทียมอย่างคร่าวๆ ที่เราสามารถใช้อธิบายกลไกของอัลกอริธึมการเรียนรู้แบบสหพันธรัฐในสิ่งพิมพ์วิจัย - ข้อมูลใดที่มีอยู่ในระบบและวิธีที่มันถูกแปลง แต่ไม่ลดลงถึงระดับของ การแลกเปลี่ยนข้อความเครือข่ายแบบจุดต่อจุดแต่ละรายการ

TFF โดยรวมเป็นการกำหนดเป้าหมายสถานการณ์สมมติซึ่งมีการเผยแพร่ข้อมูล และต้องคงอยู่เช่นเดิม เช่น ด้วยเหตุผลด้านความเป็นส่วนตัว และการรวบรวมข้อมูลทั้งหมดในตำแหน่งที่รวมศูนย์อาจไม่ใช่ตัวเลือกที่ทำงานได้ สิ่งนี้มีความหมายต่อการใช้อัลกอริธึมการเรียนรู้ของเครื่องที่ต้องการระดับการควบคุมที่ชัดเจนเพิ่มขึ้น เมื่อเทียบกับสถานการณ์สมมติที่สามารถรวบรวมข้อมูลทั้งหมดในตำแหน่งส่วนกลางที่ศูนย์ข้อมูล

ก่อนที่เราจะเริ่มต้น

ก่อนที่เราจะเจาะลึกโค้ด โปรดลองเรียกใช้ตัวอย่าง "Hello World" ต่อไปนี้เพื่อให้แน่ใจว่าสภาพแวดล้อมของคุณได้รับการตั้งค่าอย่างถูกต้อง ถ้ามันไม่ทำงานโปรดดูที่ การติดตั้ง คู่มือสำหรับคำแนะนำ

!pip install --quiet --upgrade tensorflow-federated-nightly
!pip install --quiet --upgrade nest-asyncio

import nest_asyncio
nest_asyncio.apply()
import collections

import numpy as np
import tensorflow as tf
import tensorflow_federated as tff
@tff.federated_computation
def hello_world():
  return 'Hello, World!'

hello_world()
b'Hello, World!'

ข้อมูลส่วนกลาง

หนึ่งในคุณสมบัติเด่นของฉิบหายก็คือว่ามันช่วยให้คุณสามารถแสดงความดานคำนวณ TensorFlow-บนพื้นฐานของข้อมูลแบบ federated เราจะใช้ข้อมูล federated ระยะในการกวดวิชานี้เพื่ออ้างอิงถึงคอลเลกชันของรายการข้อมูลเจ้าภาพทั่วทั้งกลุ่มของอุปกรณ์ในระบบกระจาย ตัวอย่างเช่น แอปพลิเคชันที่ทำงานบนอุปกรณ์มือถืออาจรวบรวมข้อมูลและเก็บไว้ในเครื่อง โดยไม่ต้องอัปโหลดไปยังตำแหน่งที่รวมศูนย์ หรืออาร์เรย์ของเซ็นเซอร์แบบกระจายอาจรวบรวมและจัดเก็บการอ่านค่าอุณหภูมิที่ตำแหน่งของพวกเขา

ข้อมูลสหพันธ์เหมือนในตัวอย่างข้างต้นได้รับการปฏิบัติในฉิบหายเป็น พลเมืองชั้นแรก คือพวกเขาอาจปรากฏเป็นพารามิเตอร์และผลของการทำงานและพวกเขามีประเภท เพื่อเสริมสร้างความคิดนี้เราจะอ้างถึงชุดข้อมูลแบบ federated เป็นค่า federated หรือเป็นค่าของชนิด federated

จุดสำคัญที่ต้องทำความเข้าใจคือ เรากำลังสร้างแบบจำลองการรวบรวมข้อมูลทั้งหมดในทุกอุปกรณ์ (เช่น การอ่านอุณหภูมิการรวบรวมทั้งหมดจากเซ็นเซอร์ทั้งหมดในอาร์เรย์แบบกระจาย) เป็นค่ารวมเดียว

ตัวอย่างต่อไปนี้เป็นวิธีการหนึ่งที่จะกำหนดในฉิบหายประเภทของลอย federated เป็นเจ้าภาพโดยกลุ่มของอุปกรณ์ลูกค้า คอลเลกชันของการอ่านค่าอุณหภูมิที่เกิดขึ้นทั่วทั้งอาร์เรย์ของเซ็นเซอร์แบบกระจายสามารถจำลองเป็นค่าของประเภทรวมนี้

federated_float_on_clients = tff.type_at_clients(tf.float32)

โดยทั่วไปประเภทสหพันธ์ฉิบหายถูกกำหนดโดยการระบุชนิด T ขององค์ประกอบสมาชิก - รายการของข้อมูลที่อยู่ในอุปกรณ์แต่ละและกลุ่ม G ของอุปกรณ์ที่ค่า federated ประเภทนี้เป็นเจ้าภาพ (บวกสาม ข้อมูลทางเลือกที่เราจะพูดถึงในไม่ช้า) เราหมายถึงกลุ่ม G ของอุปกรณ์โฮสติ้งค่า federated เป็นตำแหน่งค่าของ ดังนั้น tff.CLIENTS เป็นตัวอย่างของตำแหน่งหนึ่ง

str(federated_float_on_clients.member)
'float32'
str(federated_float_on_clients.placement)
'CLIENTS'

ประเภท federated เป็นคนละเรื่องกับสมาชิก T และตำแหน่ง G สามารถแสดงดานเป็น {T}@G ที่แสดงด้านล่าง

str(federated_float_on_clients)
'{float32}@CLIENTS'

วงเล็บปีกกา {} ในกระชับนี้สัญกรณ์ทำหน้าที่เป็นตัวเตือนว่าประชาชนในเขตเลือกตั้งสมาชิก (รายการของข้อมูลบนอุปกรณ์ที่แตกต่างกัน) อาจแตกต่างกันในขณะที่คุณจะคาดหวังเช่นการอ่านเซ็นเซอร์อุณหภูมิเพื่อให้ลูกค้าเป็นกลุ่มจะร่วมกันเป็นเจ้าภาพ หลาย -SET ของ T -typed รายการที่ร่วมกันเป็นมูลค่า federated

มันเป็นสิ่งสำคัญที่จะทราบว่าเป็นคนละเรื่องกับสมาชิกของค่า federated โดยทั่วไปจะมีสีขาวขุ่นโปรแกรมเมอร์คือค่า federated ไม่ควรจะคิดว่าเป็นเรื่องง่ายที่ dict คีย์โดยระบุของอุปกรณ์ในระบบที่ใช้งาน - ค่าเหล่านี้มีวัตถุประสงค์เพื่อ ถูกเปลี่ยนรวมโดยเฉพาะผู้ประกอบการที่เป็นนามธรรม federated แทนชนิดของโปรโตคอลการสื่อสารแบบกระจาย (เช่นการรวม) หากฟังดูเป็นนามธรรมเกินไป ไม่ต้องกังวล เราจะกลับมาที่นี่ในไม่ช้า และเราจะอธิบายด้วยตัวอย่างที่เป็นรูปธรรม

ประเภทรวมใน TFF มีสองรสชาติ: แบบที่องค์ประกอบของสมาชิกของค่าส่วนกลางอาจแตกต่างกัน (ดังที่เห็นด้านบน) และที่ทราบกันว่าเท่าเทียมกันทั้งหมด นี้จะถูกควบคุมโดยสามตัวเลือก all_equal พารามิเตอร์ใน tff.FederatedType คอนสตรัค (ผิดนัด False )

federated_float_on_clients.all_equal
False

ประเภท federated กับตำแหน่ง G ซึ่งทั้งหมดของ T -typed คนละสมาชิกเป็นที่รู้จักกันจะเท่ากับสามารถแสดงดานเป็น T@G (เมื่อเทียบกับ {T}@G , ที่อยู่, มีวงเล็บปีกกาลดลงสะท้อนให้เห็นถึง ข้อเท็จจริงที่ว่าองค์ประกอบหลายชุดประกอบด้วยรายการเดียว)

str(tff.type_at_clients(tf.float32, all_equal=True))
'float32@CLIENTS'

ตัวอย่างหนึ่งของค่ารวมประเภทดังกล่าวที่อาจเกิดขึ้นในสถานการณ์จริงคือไฮเปอร์พารามิเตอร์ (เช่น อัตราการเรียนรู้ บรรทัดฐานการตัด ฯลฯ) ที่ได้รับการถ่ายทอดโดยเซิร์ฟเวอร์ไปยังกลุ่มอุปกรณ์ที่เข้าร่วมการฝึกอบรมแบบรวมศูนย์

อีกตัวอย่างหนึ่งคือชุดของพารามิเตอร์สำหรับโมเดลแมชชีนเลิร์นนิงที่ได้รับการฝึกอบรมล่วงหน้าที่เซิร์ฟเวอร์ จากนั้นจึงแพร่ภาพไปยังกลุ่มอุปกรณ์ไคลเอนต์ ซึ่งสามารถปรับให้เป็นแบบส่วนตัวสำหรับผู้ใช้แต่ละราย

ตัวอย่างเช่นสมมติว่าเรามีคู่ของ float32 พารามิเตอร์ และ a b หาง่ายหนึ่งมิติรูปแบบการถดถอยเชิงเส้น เราสามารถสร้างประเภท (ไม่รวมศูนย์) ของโมเดลดังกล่าวเพื่อใช้ใน TFF ได้ดังนี้ วงเล็บมุม <> ในสตริงประเภทพิมพ์เป็นสัญกรณ์ฉิบหายขนาดกะทัดรัดสำหรับ tuples ชื่อหรือไม่มีชื่อ

simple_regression_model_type = (
    tff.StructType([('a', tf.float32), ('b', tf.float32)]))

str(simple_regression_model_type)
'<a=float32,b=float32>'

โปรดทราบว่าเราเป็นเพียงการระบุ dtype s ดังกล่าวข้างต้น นอกจากนี้ยังรองรับประเภทที่ไม่ใช่สเกลาร์ ในโค้ดข้างต้น tf.float32 เป็นสัญกรณ์ทางลัดสำหรับทั่วไปมากขึ้น tff.TensorType(dtype=tf.float32, shape=[])

เมื่อโมเดลนี้เผยแพร่ไปยังไคลเอนต์ ประเภทของค่ารวมที่เป็นผลลัพธ์สามารถแสดงได้ดังที่แสดงด้านล่าง

str(tff.type_at_clients(
    simple_regression_model_type, all_equal=True))
'<a=float32,b=float32>@CLIENTS'

ต่อสมมาตรกับลอย federated ข้างต้นเราจะอ้างถึงเช่นชนิดเป็น tuple federated โดยทั่วไปเรามักจะใช้ XYZ federated ระยะในการอ้างถึงค่า federated ซึ่งเป็นคนละเรื่องกับสมาชิกเป็นเหมือน XYZ ดังนั้นเราจะพูดคุยเกี่ยวกับสิ่งที่ชอบสิ่งอันดับ federated ลำดับ federated รูปแบบ federated และอื่น ๆ

ตอนนี้กลับไปมา float32@CLIENTS - ในขณะที่มันปรากฏจำลองแบบในอุปกรณ์หลายมันเป็นจริงเพียงหนึ่งเดียว float32 เนื่องจากสมาชิกเหมือนกันทั้งหมด โดยทั่วไปแล้วคุณอาจจะคิดว่าของทั้งหมดเท่ากับประเภท federated คือหนึ่งในรูปแบบ T@G เป็น isomorphic เป็นชนิดที่ไม่ใช่แบบ federated T ตั้งแต่ในทั้งสองกรณีมีจริงเพียงคนเดียว (แม้ว่าอาจจำลองแบบ) รายการ ประเภท T

ได้รับมอร์ฟระหว่าง T และ T@G คุณอาจสงสัยวัตถุประสงค์อะไรถ้ามีประเภทหลังอาจให้บริการ อ่านต่อ.

ตำแหน่ง

ภาพรวมการออกแบบ

ในส่วนก่อนหน้านี้เราได้นำแนวคิดของตำแหน่ง - กลุ่มของผู้เข้าร่วมระบบที่อาจจะมีการร่วมกันเป็นเจ้าภาพค่าส่วนกลางและเราได้แสดงให้เห็นถึงการใช้งานของ tff.CLIENTS เป็นสเปคตัวอย่างของตำแหน่ง

เพื่ออธิบายว่าทำไมความคิดของตำแหน่งจะให้พื้นฐานที่เราต้องการที่จะรวมไว้ในระบบการพิมพ์ฉิบหายให้จำสิ่งที่เรากล่าวถึงจุดเริ่มต้นของการกวดวิชานี้เกี่ยวกับบางส่วนของการใช้งานที่ตั้งใจฉิบหาย

แม้ว่าในบทช่วยสอนนี้ คุณจะเห็นเฉพาะโค้ด TFF ถูกเรียกใช้งานในเครื่องในสภาพแวดล้อมจำลอง เป้าหมายของเราคือให้ TFF เปิดใช้งานการเขียนโค้ดที่คุณสามารถปรับใช้สำหรับการดำเนินการกับกลุ่มของอุปกรณ์จริงในระบบแบบกระจาย ซึ่งอาจรวมถึงอุปกรณ์เคลื่อนที่หรืออุปกรณ์ฝังตัว ทำงานบน Android อุปกรณ์เหล่านี้แต่ละเครื่องจะได้รับชุดคำสั่งแยกต่างหากเพื่อดำเนินการในเครื่อง ขึ้นอยู่กับบทบาทของอุปกรณ์ในระบบ (อุปกรณ์ของผู้ใช้ปลายทาง ผู้ประสานงานส่วนกลาง เลเยอร์กลางในสถาปัตยกรรมหลายระดับ ฯลฯ) สิ่งสำคัญคือต้องสามารถให้เหตุผลว่าส่วนย่อยของอุปกรณ์ใดที่รันโค้ดใด และส่วนต่างๆ ของข้อมูลที่อาจจะเกิดขึ้นจริงอยู่ที่ใด

สิ่งนี้มีความสำคัญอย่างยิ่งเมื่อต้องรับมือกับข้อมูลแอปพลิเคชันบนอุปกรณ์มือถือ เนื่องจากข้อมูลมีความเป็นส่วนตัวและอาจมีความละเอียดอ่อน เราจึงต้องการความสามารถในการตรวจสอบแบบคงที่ว่าข้อมูลนี้จะไม่มีวันออกจากอุปกรณ์ (และพิสูจน์ข้อเท็จจริงเกี่ยวกับวิธีการประมวลผลข้อมูล) ข้อมูลจำเพาะของตำแหน่งเป็นหนึ่งในกลไกที่ออกแบบมาเพื่อรองรับสิ่งนี้

ฉิบหายได้รับการออกแบบเป็นศูนย์กลางข้อมูลสภาพแวดล้อมการเขียนโปรแกรมและเป็นเช่นนี้แตกต่างจากบางส่วนของกรอบที่มีอยู่ที่มุ่งเน้นการดำเนินงานและการดำเนินงานที่เหล่านั้นอาจทำงานฉิบหายมุ่งเน้นไปที่ข้อมูลที่มีข้อมูลที่ materializes และวิธีการที่จะถูกเปลี่ยน ดังนั้น การจัดวางจึงถูกจำลองเป็นคุณสมบัติของข้อมูลใน TFF แทนที่จะเป็นคุณสมบัติของการดำเนินการกับข้อมูล ที่จริงแล้ว ตามที่คุณจะเห็นในหัวข้อถัดไป การดำเนินการ TFF บางส่วนจะขยายไปตามสถานที่ต่างๆ และเรียกใช้ "ในเครือข่าย" แทนการดำเนินการด้วยเครื่องเดียวหรือกลุ่มเครื่อง

เป็นตัวแทนของประเภทของค่าบางอย่างเป็น T@G หรือ {T}@G (เมื่อเทียบกับเพียง T ) ทำให้การตัดสินใจตำแหน่งข้อมูลที่ชัดเจนและร่วมกับการวิเคราะห์คงที่ของโปรแกรมที่เขียนในฉิบหายมันสามารถทำหน้าที่เป็นรากฐานสำหรับการให้บริการ การรับประกันความเป็นส่วนตัวอย่างเป็นทางการสำหรับข้อมูลที่ละเอียดอ่อนบนอุปกรณ์

สิ่งสำคัญที่จะต้องทราบที่จุดนี้ก็คือว่าในขณะที่เราสนับสนุนให้ผู้ใช้ฉิบหายที่จะมีความชัดเจนเกี่ยวกับกลุ่มของอุปกรณ์ที่เข้าร่วมโครงการว่าข้อมูลโฮสต์ (ตำแหน่ง) โปรแกรมเมอร์ที่จะไม่จัดการกับข้อมูลดิบหรือตัวตนของผู้เข้าร่วมแต่ละคน .

ภายในร่างกายของรหัสฉิบหายโดยการออกแบบมีวิธีที่จะระบุอุปกรณ์ที่เป็นกลุ่มที่แสดงโดยไม่มี tff.CLIENTS หรือเพื่อสอบสวนการดำรงอยู่ของอุปกรณ์เฉพาะในกลุ่ม ไม่มีแนวคิดเกี่ยวกับข้อมูลประจำตัวของอุปกรณ์หรือไคลเอ็นต์ใน Federated Core API ชุดที่เป็นนามธรรมทางสถาปัตยกรรม หรือโครงสร้างพื้นฐานรันไทม์หลักที่เราจัดเตรียมไว้เพื่อรองรับการจำลอง ตรรกะการคำนวณทั้งหมดที่คุณเขียนจะแสดงเป็นการดำเนินการในกลุ่มลูกค้าทั้งหมด

จำนี่คือสิ่งที่เรากล่าวก่อนหน้านี้เกี่ยวกับค่าของชนิด federated เป็นแตกต่างจากงูหลาม dict ในที่หนึ่งไม่สามารถระบุเพียงแค่คนละสมาชิกของพวกเขา ลองนึกถึงค่าที่ตรรกะโปรแกรม TFF ของคุณจัดการว่ามีความเกี่ยวข้องกับตำแหน่ง (กลุ่ม) มากกว่ากับผู้เข้าร่วมแต่ละคน

ตำแหน่งที่ถูกออกแบบมาให้เป็นพลเมืองชั้นแรกในฉิบหายเป็นอย่างดีและสามารถปรากฏเป็นพารามิเตอร์และผลของ placement ประเภท (จะแสดงโดย tff.PlacementType ในของ API) ในอนาคต เราวางแผนที่จะจัดหาโอเปอเรเตอร์ที่หลากหลายเพื่อแปลงหรือรวมตำแหน่ง แต่สิ่งนี้อยู่นอกเหนือขอบเขตของบทช่วยสอนนี้ สำหรับตอนนี้ก็พอเพียงที่จะคิดว่า placement เป็นสีขาวขุ่นดั้งเดิมในตัวพิมพ์ฉิบหายคล้ายกับ int และ bool ในตัวสีขาวขุ่นชนิดในหลามกับ tff.CLIENTS เป็นตัวอักษรคงที่ของประเภทนี้ไม่แตกต่างจาก 1 เป็นตัวอักษรคงที่ของประเภท int

การระบุตำแหน่ง

ฉิบหายให้สองตัวอักษรตำแหน่งพื้นฐาน tff.CLIENTS และ tff.SERVER ที่จะทำให้มันง่ายที่จะแสดงความหลากหลายของสถานการณ์การปฏิบัติที่เป็นรูปแบบธรรมชาติเช่นเดียวกับสถาปัตยกรรมไคลเอ็นต์เซิร์ฟเวอร์กับอุปกรณ์ที่ลูกค้าหลาย (โทรศัพท์มือถืออุปกรณ์ฝังตัวกระจายฐานข้อมูล เซ็นเซอร์ ฯลฯ ) บงการโดยผู้ประสานงานเซิร์ฟเวอร์เดียวจากส่วนกลาง TFF ได้รับการออกแบบมาเพื่อรองรับตำแหน่งที่กำหนดเอง กลุ่มลูกค้าหลายกลุ่ม หลายชั้น และอื่นๆ สถาปัตยกรรมแบบกระจายทั่วไปมากขึ้น แต่การพูดคุยเรื่องเหล่านี้อยู่นอกขอบเขตของบทช่วยสอนนี้

ฉิบหายไม่ได้กำหนดสิ่งที่ทั้ง tff.CLIENTS หรือ tff.SERVER แทนจริง

โดยเฉพาะอย่างยิ่ง tff.SERVER อาจจะเป็นอุปกรณ์ทางกายภาพเดียว (เป็นสมาชิกของกลุ่มเดี่ยว) แต่มันก็เช่นกันอาจจะเป็นกลุ่มของแบบจำลองในการจำลองเครื่องรัฐคลัสเตอร์ความผิดพลาดการทำงาน - เราไม่ได้ทำสถาปัตยกรรมพิเศษใด ๆ สมมติฐาน แต่เราใช้ all_equal บิตกล่าวถึงในส่วนก่อนหน้านี้ที่จะแสดงความจริงที่ว่าเรากำลังจัดการกับทั่วไปเพียงรายการเดียวของข้อมูลที่เซิร์ฟเวอร์

ในทำนองเดียวกัน tff.CLIENTS ในการใช้งานบางอย่างอาจเป็นตัวแทนของลูกค้าทั้งหมดในระบบ - สิ่งที่อยู่ในบริบทของการเรียนรู้แบบ federated บางครั้งเราจะเรียกว่าประชากร แต่เช่นใน การใช้งานการผลิตของสหพันธ์ Averaging มันอาจหมายถึงการศึกษา - การเซตของ ลูกค้าที่ได้รับการคัดเลือกให้เข้าร่วมการฝึกอบรมในรอบนั้นๆ ตำแหน่งที่กำหนดเป็นนามธรรมจะได้รับความหมายที่เป็นรูปธรรมเมื่อมีการปรับใช้การคำนวณที่ปรากฏสำหรับการดำเนินการ (หรือเรียกง่ายๆ เช่น ฟังก์ชัน Python ในสภาพแวดล้อมจำลองดังที่แสดงในบทช่วยสอนนี้) ในการจำลองในพื้นที่ของเรา กลุ่มลูกค้าจะถูกกำหนดโดยข้อมูลรวมที่ให้มาเป็นอินพุต

การคำนวณแบบสหพันธรัฐ

ประกาศการคำนวณแบบรวมศูนย์

TFF ได้รับการออกแบบให้เป็นสภาพแวดล้อมการเขียนโปรแกรมเชิงฟังก์ชันที่มีการพิมพ์สูงซึ่งสนับสนุนการพัฒนาแบบแยกส่วน

หน่วยพื้นฐานขององค์ประกอบในฉิบหายคือการคำนวณแบบ federated - ส่วนของตรรกะที่อาจยอมรับค่า federated เป็น input และค่าตอบแทนแบบ federated เป็นผลผลิต ต่อไปนี้คือวิธีที่คุณสามารถกำหนดการคำนวณที่คำนวณค่าเฉลี่ยของอุณหภูมิที่รายงานโดยอาร์เรย์เซ็นเซอร์จากตัวอย่างก่อนหน้าของเรา

@tff.federated_computation(tff.type_at_clients(tf.float32))
def get_average_temperature(sensor_readings):
  return tff.federated_mean(sensor_readings)

มองไปที่รหัสข้างต้นที่จุดนี้คุณอาจจะถาม - ไม่ได้มีอยู่แล้วมัณฑนากรโครงสร้างการกำหนดหน่วย composable เช่น tf.function ใน TensorFlow และถ้าเป็นเช่นนั้นทำไมแนะนำอีกหนึ่งและวิธีการที่จะแตกต่างกันอย่างไร

คำตอบสั้น ๆ ว่ารหัสที่สร้างโดย tff.federated_computation เสื้อคลุมเป็นค่า TensorFlow และไม่เป็นมันหลาม - เป็นสเปคของระบบกระจายในแพลตฟอร์มภาษากาวภายใน ณ จุดนี้ ไม่ต้องสงสัยเลยว่าจะฟังดูคลุมเครือ แต่โปรดแบกรับการตีความโดยสัญชาตญาณของการคำนวณแบบรวมศูนย์เป็นข้อกำหนดเชิงนามธรรมของระบบแบบกระจายในใจ เราจะอธิบายในนาทีนี้

ก่อนอื่น มาเล่นนิยามกันสักหน่อย โดยทั่วไปแล้ว การคำนวณ TFF จะสร้างแบบจำลองเป็นฟังก์ชัน - มีหรือไม่มีพารามิเตอร์ แต่มีลายเซ็นประเภทที่กำหนดไว้อย่างดี คุณสามารถพิมพ์ลายเซ็นประเภทของการคำนวณโดยการสอบถามของ type_signature คุณสมบัติดังต่อไปนี้

str(get_average_temperature.type_signature)
'({float32}@CLIENTS -> float32@SERVER)'

ลายเซ็นประเภทบอกเราว่าการคำนวณยอมรับคอลเลกชันของการอ่านเซ็นเซอร์ต่างๆ บนอุปกรณ์ไคลเอ็นต์ และส่งคืนค่าเฉลี่ยเดียวบนเซิร์ฟเวอร์

ก่อนที่เราจะไปเพิ่มเติมใด ๆ ขอสะท้อนให้เห็นเกี่ยวกับเรื่องนี้สำหรับนาที - อินพุตและเอาต์พุตของการคำนวณนี้อยู่ในสถานที่ที่แตกต่างกัน (ใน CLIENTS เทียบกับที่ SERVER ) จำสิ่งที่เรากล่าวว่าในส่วนก่อนหน้านี้ในตำแหน่งที่เกี่ยวกับวิธีการดำเนินงานอาจฉิบหายช่วงข้ามสถานที่และทำงานในเครือข่ายและสิ่งที่เราเพียงแค่กล่าวว่าเกี่ยวกับการคำนวณแบบ federated เป็นคิดเป็นข้อกำหนดนามธรรมของระบบการกระจาย เรามีเพียงการคำนวณที่กำหนดไว้ - ระบบกระจายอย่างง่ายซึ่งข้อมูลถูกใช้ที่อุปกรณ์ไคลเอนต์และผลลัพธ์โดยรวมจะปรากฏที่เซิร์ฟเวอร์

ในสถานการณ์ทางปฏิบัติหลายคำนวณที่เป็นตัวแทนของงานระดับบนสุดจะมีแนวโน้มที่จะยอมรับปัจจัยการผลิตของพวกเขาและรายงานผลของพวกเขาที่เซิร์ฟเวอร์ - นี้สะท้อนให้เห็นถึงความคิดที่ว่าอาจจะมีการคำนวณเรียกโดยคำสั่งที่มาและยุติบนเซิร์ฟเวอร์

อย่างไรก็ตามเอฟซี API ไม่ได้กำหนดสมมติฐานนี้และอีกหลายแห่งการก่อสร้างตึกที่เราใช้ภายใน (รวมหลาย tff.federated_... ประกอบคุณอาจพบใน API) ที่มีปัจจัยการผลิตและผลที่มีตำแหน่งที่แตกต่างกันดังนั้นโดยทั่วไปคุณควร ไม่ได้คิดเกี่ยวกับการคำนวณแบบ federated เป็นสิ่งที่รันบนเซิร์ฟเวอร์หรือดำเนินการโดยเซิร์ฟเวอร์ เซิร์ฟเวอร์เป็นเพียงผู้เข้าร่วมประเภทหนึ่งในการคำนวณแบบรวมศูนย์ ในการคิดเกี่ยวกับกลไกของการคำนวณดังกล่าว เป็นการดีที่สุดที่จะเริ่มต้นในมุมมองของทั่วทั้งเครือข่ายทั่วโลก แทนที่จะเป็นมุมมองของผู้ประสานงานแบบรวมศูนย์เพียงคนเดียว

โดยทั่วไปประเภทการทำงานลายเซ็นจะแสดงเป็นดาน (T -> U) ชนิด T และ U ของปัจจัยการผลิตและผลตามลำดับ ประเภทของพารามิเตอร์อย่างเป็นทางการ (เช่น sensor_readings ในกรณีนี้) มีการระบุเป็นข้อโต้แย้งที่จะมัณฑนากร คุณไม่จำเป็นต้องระบุประเภทของผลลัพธ์ - ผลลัพธ์จะถูกกำหนดโดยอัตโนมัติ

แม้ว่า TFF จะนำเสนอรูปแบบที่หลากหลายที่จำกัด แต่โปรแกรมเมอร์ก็ควรที่จะมีความชัดเจนเกี่ยวกับประเภทของข้อมูลที่พวกเขาทำงานด้วย ซึ่งจะทำให้ความเข้าใจ การดีบัก และการตรวจสอบคุณสมบัติของโค้ดของคุณอย่างเป็นทางการง่ายขึ้น ในบางกรณี การระบุประเภทอย่างชัดเจนเป็นข้อกำหนด (เช่น การคำนวณแบบโพลีมอร์ฟิคไม่สามารถดำเนินการได้โดยตรงในขณะนี้)

กำลังดำเนินการคำนวณแบบรวมศูนย์

เพื่อรองรับการพัฒนาและการดีบัก TFF อนุญาตให้คุณเรียกใช้การคำนวณที่กำหนดในลักษณะนี้เป็นฟังก์ชัน Python ได้โดยตรง ดังที่แสดงด้านล่าง ไหนคำนวณคาดว่ามูลค่าของประเภท federated กับ all_equal ชุดบิตเพื่อ False คุณสามารถให้อาหารมันเป็นธรรมดา list ในหลามและประเภท federated กับ all_equal ชุดบิตเพื่อ True คุณก็สามารถโดยตรงเลี้ยง (เดี่ยว) องค์ประกอบของสมาชิก นี่เป็นวิธีการรายงานผลกลับมาให้คุณทราบด้วย

get_average_temperature([68.5, 70.3, 69.8])
69.53334

เมื่อเรียกใช้การคำนวณเช่นนี้ในโหมดจำลอง คุณจะทำหน้าที่เป็นผู้สังเกตการณ์ภายนอกด้วยมุมมองทั้งระบบ ซึ่งสามารถจัดหาอินพุตและบริโภคเอาต์พุตที่ตำแหน่งใดๆ ในเครือข่ายได้ เช่นเดียวกับในกรณีนี้ - คุณระบุค่าไคลเอ็นต์ ที่อินพุตและใช้ผลลัพธ์ของเซิร์ฟเวอร์

ตอนนี้กลับมาให้ของที่จะต้องทราบที่เราทำก่อนหน้านี้เกี่ยวกับ tff.federated_computation รหัสมัณฑนากรเปล่งแสงในภาษากาว แม้ว่าเหตุผลของการคำนวณฉิบหายที่สามารถแสดงเป็นฟังก์ชั่นสามัญในหลาม (คุณเพียงแค่ต้องตกแต่งด้วย tff.federated_computation ที่เราเคยทำมาแล้วข้างต้น) และคุณสามารถโดยตรงวิงวอนขอให้พวกเขามีข้อโต้แย้งงูใหญ่เช่นเดียวกับฟังก์ชั่นงูใหญ่อื่น ๆ ในนี้ โน๊ตบุ๊ค, เบื้องหลังที่เราระบุไว้ก่อนหน้านี้ที่คำนวณฉิบหายเป็นจริงไม่ได้หลาม

สิ่งที่เราหมายถึงนี้ก็คือว่าเมื่อล่ามหลามพบฟังก์ชั่นการตกแต่งด้วย tff.federated_computation มันร่องรอยงบในร่างกายของฟังก์ชั่นนี้เพียงครั้งเดียว (ในเวลานิยาม) และจากนั้นจะสร้าง ตัวแทนเนื่อง ของตรรกะการคำนวณสำหรับการใช้งานในอนาคต - ไม่ว่า เพื่อดำเนินการหรือรวมเป็นส่วนประกอบย่อยในการคำนวณอื่น

คุณสามารถตรวจสอบได้โดยเพิ่มคำสั่งพิมพ์ดังนี้:

@tff.federated_computation(tff.type_at_clients(tf.float32))
def get_average_temperature(sensor_readings):

  print ('Getting traced, the argument is "{}".'.format(
      type(sensor_readings).__name__))

  return tff.federated_mean(sensor_readings)
Getting traced, the argument is "ValueImpl".

คุณสามารถนึกถึงโค้ด Python ที่กำหนดการคำนวณแบบรวมศูนย์ได้ เช่นเดียวกับที่คุณคิดเกี่ยวกับโค้ด Python ที่สร้างกราฟ TensorFlow ในบริบทที่ไม่กระตือรือร้น (หากคุณไม่คุ้นเคยกับการใช้ TensorFlow แบบไม่กระตือรือร้น ให้นึกถึง รหัส Python กำหนดกราฟของการดำเนินการที่จะดำเนินการในภายหลัง แต่ไม่ได้เรียกใช้ทันที) โค้ดสำหรับสร้างกราฟที่ไม่กระตือรือร้นใน TensorFlow คือ Python แต่กราฟ TensorFlow ที่สร้างโดยโค้ดนี้ไม่ขึ้นกับแพลตฟอร์มและเป็นแบบซีเรียลไลซ์ได้

ในทำนองเดียวกันการคำนวณฉิบหายมีการกำหนดไว้ในหลาม แต่งบหลามในร่างกายของพวกเขาเช่น tff.federated_mean ในตัวอย่างใดก็ตามเราแสดงให้เห็นเพียงแค่มีการเรียบเรียงแบบพกพาและแพลตฟอร์มการแสดง serializable ภายใต้ประทุน

ในฐานะนักพัฒนา คุณไม่จำเป็นต้องกังวลเกี่ยวกับรายละเอียดของการนำเสนอนี้ เนื่องจากคุณไม่จำเป็นต้องทำงานกับมันโดยตรง แต่คุณควรตระหนักถึงการมีอยู่ของมัน ความจริงที่ว่าการคำนวณ TFF โดยพื้นฐานแล้วไม่กระตือรือร้น และไม่สามารถจับสถานะ Python โดยพลการได้ รหัสงูใหญ่ที่มีอยู่ในร่างกายคำนวณฉิบหายของจะถูกดำเนินการในเวลาที่ความหมายเมื่อร่างกายของฟังก์ชั่นงูใหญ่ตกแต่งด้วย tff.federated_computation เป็น traced ก่อนที่จะต่อเนื่องกัน จะไม่ย้อนกลับอีกครั้งในเวลาที่เรียกใช้ (ยกเว้นเมื่อฟังก์ชันเป็นแบบ polymorphic โปรดดูรายละเอียดที่หน้าเอกสารประกอบ)

คุณอาจสงสัยว่าเหตุใดเราจึงเลือกที่จะแนะนำตัวแทนภายในที่ไม่ใช่ Python โดยเฉพาะ เหตุผลหนึ่งก็คือในท้ายที่สุด การคำนวณ TFF นั้นตั้งใจที่จะปรับใช้กับสภาพแวดล้อมทางกายภาพจริง และโฮสต์บนอุปกรณ์พกพาหรืออุปกรณ์ฝังตัว ซึ่ง Python อาจไม่พร้อมใช้งาน

อีกเหตุผลหนึ่งคือการคำนวณ TFF แสดงพฤติกรรมทั่วโลกของระบบแบบกระจาย ซึ่งต่างจากโปรแกรม Python ที่แสดงพฤติกรรมท้องถิ่นของผู้เข้าร่วมแต่ละคน คุณจะเห็นว่าในตัวอย่างง่ายๆข้างต้นกับผู้ประกอบการพิเศษ tff.federated_mean ที่รับข้อมูลบนอุปกรณ์ของลูกค้าเงินฝาก แต่ผลบนเซิร์ฟเวอร์

ผู้ประกอบการ tff.federated_mean ไม่สามารถสร้างแบบจำลองได้อย่างง่ายดายเช่นผู้ประกอบการสามัญในหลามเพราะมันไม่ได้ดำเนินการในประเทศ - ตามที่ระบุไว้ก่อนหน้านี้มันหมายถึงระบบกระจายพิกัดพฤติกรรมของผู้เข้าร่วมหลายระบบ เราจะหมายถึงผู้ประกอบการดังกล่าวเป็นผู้ประกอบการที่ federated จะแตกต่างจากสามัญผู้ประกอบการ (ท้องถิ่น) ในหลาม

ระบบประเภท TFF และชุดปฏิบัติการพื้นฐานที่รองรับในภาษาของ TFF จึงเบี่ยงเบนไปจากภาษา Python อย่างมาก จำเป็นต้องใช้การแสดงแทนโดยเฉพาะ

การเขียนการคำนวณแบบรวมศูนย์

ดังที่กล่าวไว้ข้างต้น การคำนวณแบบรวมศูนย์และองค์ประกอบของการคำนวณนั้นเป็นที่เข้าใจได้ดีที่สุดว่าเป็นแบบจำลองของระบบแบบกระจาย และคุณสามารถนึกถึงการเขียนการคำนวณแบบรวมศูนย์ด้วยการเขียนระบบแบบกระจายที่ซับซ้อนมากขึ้นจากระบบที่ง่ายกว่า คุณสามารถคิดของ tff.federated_mean ประกอบเป็นชนิดของในตัวแม่แบบการคำนวณแบบ federated ที่มีลายเซ็นชนิดหนึ่ง ({T}@CLIENTS -> T@SERVER) (ที่จริงเช่นเดียวกับการคำนวณที่คุณเขียนดำเนินการนี้นอกจากนี้ยังมีความซับซ้อน โครงสร้าง - ภายใต้ประทุนเราแบ่งมันออกเป็นโอเปอเรเตอร์ที่ง่ายกว่า)

เช่นเดียวกับการเขียนการคำนวณแบบรวมศูนย์ การคำนวณ get_average_temperature อาจเรียกได้ในร่างกายของฟังก์ชั่นอื่นหลามตกแต่งด้วย tff.federated_computation - การทำเช่นนั้นจะทำให้มันถูกฝังอยู่ในร่างกายของแม่มากในทางเดียวกัน tff.federated_mean ถูกฝังอยู่ในร่างกายของตัวเองก่อนหน้านี้

ข้อ จำกัด สำคัญที่จะต้องระวังก็คือร่างของฟังก์ชั่นการตกแต่งด้วยงูหลาม tff.federated_computation ต้องประกอบด้วยเฉพาะของผู้ประกอบการ federated คือพวกเขาไม่สามารถมีการดำเนินงาน TensorFlow ตัวอย่างเช่นคุณไม่สามารถใช้ tf.nest อินเตอร์เฟซที่จะเพิ่มคู่ของค่า federated รหัส TensorFlow จะต้องถูกคุมขังในกลุ่มของรหัสตกแต่งด้วย tff.tf_computation กล่าวถึงในส่วนต่อไปนี้ เฉพาะเมื่อห่อในลักษณะนี้สามารถรหัส TensorFlow ห่อถูกเรียกในร่างกายของที่ tff.federated_computation

เหตุผลในการแยกนี้ทางเทคนิค (มันเป็นเรื่องยากที่จะหลอกลวงผู้ประกอบการเช่น tf.add ในการทำงานกับผู้ที่ไม่ใช่เทนเซอร์) เช่นเดียวกับสถาปัตยกรรม ภาษาของการคำนวณแบบ federated (เช่นตรรกะสร้างจากร่างกายต่อเนื่องของฟังก์ชั่นการตกแต่งด้วยงูหลาม tff.federated_computation ) ถูกออกแบบมาเพื่อใช้เป็นภาษากาวแพลตฟอร์ม ภาษากาวในปัจจุบันนี้จะใช้ในการสร้างระบบการกระจายจากส่วนที่ฝังตัวของรหัส TensorFlow (ถูกคุมขังใน tff.tf_computation บล็อก) ในบูรณภาพของเวลาที่เราคาดว่าจะจำเป็นที่จะต้องฝังส่วนของตรรกะอื่น ๆ ที่ไม่ใช่ TensorFlow เช่นการสืบค้นฐานข้อมูลเชิงสัมพันธ์ที่อาจเป็นตัวแทนของท่อป้อนข้อมูลทั้งหมดที่เชื่อมต่อกันโดยใช้ภาษาเดียวกันกาว (คน tff.federated_computation บล็อก)

ตรรกะเทนเซอร์โฟลว์

ประกาศการคำนวณ TensorFlow

TFF ออกแบบมาเพื่อใช้กับ TensorFlow ดังนั้น โค้ดจำนวนมากที่คุณจะเขียนใน TFF จึงน่าจะเป็นโค้ด TensorFlow ธรรมดา (เช่น รันในเครื่อง) เพื่อที่จะใช้รหัสดังกล่าวกับฉิบหายตามที่ระบุไว้ข้างต้นเป็นเพียงความต้องการที่จะได้รับการตกแต่งด้วย tff.tf_computation

ยกตัวอย่างเช่นนี่คือวิธีการที่เราสามารถใช้ฟังก์ชั่นที่ใช้เวลาจำนวนและเพิ่ม 0.5 กับมัน

@tff.tf_computation(tf.float32)
def add_half(x):
  return tf.add(x, 0.5)

อีกครั้งหนึ่งที่กำลังมองหาที่นี้คุณอาจจะสงสัยว่าทำไมเราควรกำหนดมัณฑนากรอีก tff.tf_computation แทนที่จะใช้กลไกที่มีอยู่เช่น tf.function ต่างจากในส่วนก่อนหน้านี้ เรากำลังจัดการกับบล็อกทั่วไปของโค้ด TensorFlow

มีเหตุผลสองสามประการ ซึ่งการรักษาแบบสมบูรณ์นั้นอยู่นอกเหนือขอบเขตของบทช่วยสอนนี้ แต่ก็คุ้มค่าที่จะตั้งชื่อเหตุผลหลัก:

  • ในการฝังบล็อคการสร้างที่นำกลับมาใช้ใหม่ได้ซึ่งใช้งานโดยใช้โค้ด TensorFlow ในส่วนเนื้อหาของการคำนวณแบบรวมศูนย์ พวกเขาจำเป็นต้องปฏิบัติตามคุณสมบัติบางอย่าง เช่น การติดตามและการทำให้เป็นอนุกรมในเวลาที่กำหนด การมีลายเซ็นประเภท ฯลฯ ซึ่งโดยทั่วไปต้องใช้รูปแบบบางอย่างของมัณฑนากร

โดยทั่วไปเราขอแนะนำให้ใช้กลไกพื้นเมือง TensorFlow สำหรับองค์ประกอบเช่น tf.function ใดก็ตามที่เป็นไปได้เป็นลักษณะที่แน่นอนในการที่ฉิบหายของปฏิสัมพันธ์มัณฑนากรที่มีฟังก์ชั่นความกระตือรือร้นที่สามารถคาดหวังที่จะพัฒนาขึ้น

ตอนนี้กลับมาถึงโค้ดตัวอย่างข้อมูลข้างต้นคำนวณ add_half เราเพียงแค่กำหนดสามารถรักษาได้โดยฉิบหายเช่นเดียวกับการคำนวณฉิบหายอื่น ๆ โดยเฉพาะอย่างยิ่ง มีลายเซ็นประเภท TFF

str(add_half.type_signature)
'(float32 -> float32)'

โปรดทราบว่าลายเซ็นประเภทนี้ไม่มีตำแหน่ง การคำนวณ TensorFlow ไม่สามารถใช้หรือส่งคืนประเภทรวม

ขณะนี้คุณสามารถใช้ add_half เป็นอาคารบล็อกในการคำนวณอื่น ๆ ยกตัวอย่างเช่นนี่เป็นวิธีที่คุณสามารถใช้ tff.federated_map ผู้ประกอบการที่จะใช้ add_half pointwise ประชาชนในเขตเลือกตั้งสมาชิกทั้งหมดของลอย federated บนอุปกรณ์ของลูกค้า

@tff.federated_computation(tff.type_at_clients(tf.float32))
def add_half_on_clients(x):
  return tff.federated_map(add_half, x)
str(add_half_on_clients.type_signature)
'({float32}@CLIENTS -> {float32}@CLIENTS)'

ดำเนินการคำนวณ TensorFlow

การดำเนินการของการคำนวณที่กำหนดไว้กับ tff.tf_computation ตามกฎเช่นเดียวกับคนที่เราอธิบาย tff.federated_computation สามารถเรียกใช้เป็น callables ธรรมดาใน Python ได้ดังนี้

add_half_on_clients([1.0, 3.0, 2.0])
[<tf.Tensor: shape=(), dtype=float32, numpy=1.5>,
 <tf.Tensor: shape=(), dtype=float32, numpy=3.5>,
 <tf.Tensor: shape=(), dtype=float32, numpy=2.5>]

อีกครั้งก็เป็นที่น่าสังเกตว่าการเรียกคำนวณ add_half_on_clients ในลักษณะนี้จำลองกระบวนการกระจาย ข้อมูลถูกใช้ในไคลเอนต์และส่งคืนบนไคลเอนต์ อันที่จริง การคำนวณนี้ทำให้ลูกค้าแต่ละรายดำเนินการในพื้นที่ ไม่มีเป็น tff.SERVER กล่าวถึงอย่างชัดเจนในระบบนี้ (แม้ว่าในทางปฏิบัติผู้กำกับการประมวลผลดังกล่าวอาจเกี่ยวข้องกับการอย่างใดอย่างหนึ่ง) คิดว่าการคำนวณที่กำหนดไว้ด้วยวิธีนี้ว่าคล้ายแนวคิดกับ Map ในเวที MapReduce

นอกจากนี้ยังเก็บไว้ในใจว่าสิ่งที่เรากล่าวว่าในส่วนก่อนหน้านี้เกี่ยวกับการคำนวณฉิบหายได้รับการต่อเนื่องในขณะที่ยังคงความหมายที่แท้จริงสำหรับ tff.tf_computation รหัสเป็นอย่างดี - ร่างกายของงูหลาม add_half_on_clients ได้รับการตรวจสอบครั้งเดียวในเวลาที่ความหมาย ในการเรียกใช้ที่ตามมา TFF จะใช้การแทนค่าแบบอนุกรม

ข้อแตกต่างระหว่างวิธีหลามตกแต่งด้วย tff.federated_computation และผู้ที่ตกแต่งด้วย tff.tf_computation เป็นที่หลังจะต่อเนื่องกันเป็นกราฟ TensorFlow (ในขณะที่อดีตไม่ได้รับอนุญาตให้มีรหัส TensorFlow ฝังโดยตรงในพวกเขา)

ภายใต้ประทุนแต่ละวิธีการตกแต่งด้วย tff.tf_computation ชั่วคราวปิดการใช้งานการดำเนินการกระตือรือร้นในการที่จะช่วยให้โครงสร้างการคำนวณที่จะถูกจับ ในขณะที่การดำเนินการอย่างกระตือรือร้นนั้นถูกปิดใช้งานในเครื่อง คุณสามารถใช้โครงสร้าง TensorFlow, AutoGraph, TensorFlow 2.0 และอื่นๆ ได้ ตราบใดที่คุณเขียนตรรกะของการคำนวณในลักษณะที่สามารถจัดลำดับได้อย่างถูกต้อง

ตัวอย่างเช่น รหัสต่อไปนี้จะล้มเหลว:

try:

  # Eager mode
  constant_10 = tf.constant(10.)

  @tff.tf_computation(tf.float32)
  def add_ten(x):
    return x + constant_10

except Exception as err:
  print (err)
Attempting to capture an EagerTensor without building a function.

ดังกล่าวข้างต้นล้มเหลวเนื่องจาก constant_10 ได้ถูกสร้างขึ้นนอกของกราฟที่ tff.tf_computation โครงสร้างภายในในร่างกายของ add_ten ในระหว่างกระบวนการอันดับ

บนมืออื่น ๆ เรียกฟังก์ชั่นหลามที่ปรับเปลี่ยนรูปแบบของกราฟในปัจจุบันเมื่อเรียกภายใน tff.tf_computation ดี:

def get_constant_10():
  return tf.constant(10.)

@tff.tf_computation(tf.float32)
def add_ten(x):
  return x + get_constant_10()

add_ten(5.0)
15.0

โปรดทราบว่ากลไกการทำให้เป็นอนุกรมใน TensorFlow กำลังพัฒนา และเราคาดหวังรายละเอียดว่า TFF จะทำให้การคำนวณเป็นอนุกรมมีวิวัฒนาการไปอย่างไรเช่นกัน

การทำงานกับ tf.data.Dataset s

ตามที่ระบุไว้ก่อนหน้านี้คุณลักษณะเฉพาะของ tff.tf_computation คือว่าพวกเขาช่วยให้คุณสามารถทำงานร่วมกับ tf.data.Dataset s กำหนด abstractly เป็นพารามิเตอร์อย่างเป็นทางการโดยรหัสของคุณ พารามิเตอร์ที่จะเป็นตัวแทนใน TensorFlow เป็นชุดข้อมูลที่จะต้องมีการประกาศใช้ tff.SequenceType คอนสตรัค

ยกตัวอย่างเช่นชนิดสเป tff.SequenceType(tf.float32) กำหนดลำดับนามธรรมขององค์ประกอบลอยในฉิบหาย ลำดับสามารถมีเทนเซอร์หรือโครงสร้างที่ซ้อนกันแบบซับซ้อนได้ (เราจะเห็นตัวอย่างในภายหลัง) การเป็นตัวแทนรัดกุมของลำดับของ T -typed รายการคือ T* *

float32_sequence = tff.SequenceType(tf.float32)

str(float32_sequence)
'float32*'

Suppose that in our temperature sensor example, each sensor holds not just one temperature reading, but multiple. Here's how you can define a TFF computation in TensorFlow that calculates the average of temperatures in a single local data set using the tf.data.Dataset.reduce operator.

@tff.tf_computation(tff.SequenceType(tf.float32))
def get_local_temperature_average(local_temperatures):
  sum_and_count = (
      local_temperatures.reduce((0.0, 0), lambda x, y: (x[0] + y, x[1] + 1)))
  return sum_and_count[0] / tf.cast(sum_and_count[1], tf.float32)
str(get_local_temperature_average.type_signature)
'(float32* -> float32)'

In the body of a method decorated with tff.tf_computation , formal parameters of a TFF sequence type are represented simply as objects that behave like tf.data.Dataset , ie, support the same properties and methods (they are currently not implemented as subclasses of that type - this may change as the support for data sets in TensorFlow evolves).

You can easily verify this as follows.

@tff.tf_computation(tff.SequenceType(tf.int32))
def foo(x):
  return x.reduce(np.int32(0), lambda x, y: x + y)

foo([1, 2, 3])
6

Keep in mind that unlike ordinary tf.data.Dataset s, these dataset-like objects are placeholders. They don't contain any elements, since they represent abstract sequence-typed parameters, to be bound to concrete data when used in a concrete context. Support for abstractly-defined placeholder data sets is still somewhat limited at this point, and in the early days of TFF, you may encounter certain restrictions, but we won't need to worry about them in this tutorial (please refer to the documentation pages for details).

When locally executing a computation that accepts a sequence in a simulation mode, such as in this tutorial, you can feed the sequence as Python list, as below (as well as in other ways, eg, as a tf.data.Dataset in eager mode, but for now, we'll keep it simple).

get_local_temperature_average([68.5, 70.3, 69.8])
69.53333

Like all other TFF types, sequences like those defined above can use the tff.StructType constructor to define nested structures. For example, here's how one could declare a computation that accepts a sequence of pairs A , B , and returns the sum of their products. We include the tracing statements in the body of the computation so that you can see how the TFF type signature translates into the dataset's output_types and output_shapes .

@tff.tf_computation(tff.SequenceType(collections.OrderedDict([('A', tf.int32), ('B', tf.int32)])))
def foo(ds):
  print('element_structure = {}'.format(ds.element_spec))
  return ds.reduce(np.int32(0), lambda total, x: total + x['A'] * x['B'])
element_structure = OrderedDict([('A', TensorSpec(shape=(), dtype=tf.int32, name=None)), ('B', TensorSpec(shape=(), dtype=tf.int32, name=None))])
str(foo.type_signature)
'(<A=int32,B=int32>* -> int32)'
foo([{'A': 2, 'B': 3}, {'A': 4, 'B': 5}])
26

The support for using tf.data.Datasets as formal parameters is still somewhat limited and evolving, although functional in simple scenarios such as those used in this tutorial.

Putting it all together

Now, let's try again to use our TensorFlow computation in a federated setting. Suppose we have a group of sensors that each have a local sequence of temperature readings. We can compute the global temperature average by averaging the sensors' local averages as follows.

@tff.federated_computation(
    tff.type_at_clients(tff.SequenceType(tf.float32)))
def get_global_temperature_average(sensor_readings):
  return tff.federated_mean(
      tff.federated_map(get_local_temperature_average, sensor_readings))

Note that this isn't a simple average across all local temperature readings from all clients, as that would require weighing contributions from different clients by the number of readings they locally maintain. We leave it as an exercise for the reader to update the above code; the tff.federated_mean operator accepts the weight as an optional second argument (expected to be a federated float).

Also note that the input to get_global_temperature_average now becomes a federated float sequence . Federated sequences is how we will typically represent on-device data in federated learning, with sequence elements typically representing data batches (you will see examples of this shortly).

str(get_global_temperature_average.type_signature)
'({float32*}@CLIENTS -> float32@SERVER)'

Here's how we can locally execute the computation on a sample of data in Python. Notice that the way we supply the input is now as a list of list s. The outer list iterates over the devices in the group represented by tff.CLIENTS , and the inner ones iterate over elements in each device's local sequence.

get_global_temperature_average([[68.0, 70.0], [71.0], [68.0, 72.0, 70.0]])
70.0

This concludes the first part of the tutorial... we encourage you to continue on to the second part .