کار با ClientData tff.

مشاهده در TensorFlow.org در Google Colab اجرا شود مشاهده منبع در GitHub دانلود دفترچه یادداشت

مفهوم مجموعه داده کلید شده توسط مشتریان (به عنوان مثال کاربران) برای محاسبات فدرال همانطور که در TFF مدل شده است ضروری است. TFF فراهم می کند رابط tff.simulation.datasets.ClientData به انتزاعی بیش از این مفهوم، و مجموعه داده که میزبان TFF ( استک اورفلو ، شکسپیر ، emnist ، cifar100 و gldv2 ) تمام پیاده سازی این رابط.

اگر شما در حال کار بر یادگیری فدرال با مجموعه داده های خود را، TFF شدت تشویق می کند به شما یا اجرای ClientData رابط یا استفاده از یکی از توابع کمکی TFF به تولید یک ClientData که نشان دهنده داده های خود را بر روی دیسک، به عنوان مثال tff.simulation.datasets.ClientData.from_clients_and_fn .

همانطور که بسیاری از نمونه های پایان به پایان TFF با شروع ClientData اشیاء، اجرای ClientData رابط با مجموعه داده های سفارشی خود را آن را به spelunk آسان تر از طریق کد موجود نوشته شده با TFF خواهد شد. علاوه بر این، tf.data.Datasets که ClientData سازه می تواند بیش از تکرار به طور مستقیم به عملکرد ساختارهای numpy آرایه، بنابراین ClientData اشیاء را می توان با هر چارچوب ML بر اساس پایتون قبل از حرکت به TFF استفاده می شود.

الگوهای مختلفی وجود دارد که با استفاده از آنها می‌توانید زندگی خود را آسان‌تر کنید، اگر قصد دارید شبیه‌سازی‌های خود را به ماشین‌های زیادی افزایش دهید یا آنها را به کار بگیرید. در زیر ما از طریق چند از راه های ما می توانید استفاده کنید راه رفتن ClientData و TFF به مقیاس کوچک تکرار به مقیاس بزرگ آزمایش به تجربه تولید استقرار ما را به عنوان که ممکن است صاف.

از کدام الگو برای انتقال ClientData به TFF استفاده کنم؟

ما دو کاربرد از TFF مورد بحث قرار خواهد ClientData در عمق. اگر در هر یک از دو دسته زیر قرار می گیرید، به وضوح یکی را بر دیگری ترجیح می دهید. اگر نه، ممکن است برای انتخاب دقیق‌تر به درک دقیق‌تری از مزایا و معایب هر کدام نیاز داشته باشید.

  • من می خواهم در سریع ترین زمان ممکن روی یک ماشین محلی تکرار کنم. نیازی نیست که بتوانم به راحتی از زمان اجرای توزیع شده TFF استفاده کنم.

    • شما می خواهید به تصویب tf.data.Datasets به TFF به طور مستقیم.
    • این اجازه می دهد تا شما را به برنامه آمرانه با tf.data.Dataset اشیاء، و پردازش آنها را خودسرانه.
    • انعطاف پذیری بیشتری نسبت به گزینه زیر فراهم می کند. فشار دادن منطق به مشتریان مستلزم آن است که این منطق قابل سریال سازی باشد.
  • من می خواهم محاسبات فدرال خود را در زمان اجرا از راه دور TFF اجرا کنم، یا قصد دارم به زودی این کار را انجام دهم.

    • در این مورد شما می خواهید ساخت و پیش پردازش مجموعه داده را به مشتریان نگاشت کنید.
    • این نتایج در شما عبور سادگی یک لیست از client_ids به طور مستقیم به محاسبات فدرال خود را.
    • فشار ساختن مجموعه داده و پیش پردازش برای مشتریان از تنگناها در سریال سازی جلوگیری می کند و عملکرد صدها تا هزاران مشتری را به طور قابل توجهی افزایش می دهد.

محیط متن باز را تنظیم کنید

بسته های وارداتی

دستکاری یک شی ClientData

بیایید با بارگیری و کاوش EMNIST TFF شروع ClientData :

client_data, _ = tff.simulation.datasets.emnist.load_data()
Downloading emnist_all.sqlite.lzma: 100%|██████████| 170507172/170507172 [00:19<00:00, 8831921.67it/s]
2021-10-01 11:17:58.718735: E tensorflow/stream_executor/cuda/cuda_driver.cc:271] failed call to cuInit: CUDA_ERROR_NO_DEVICE: no CUDA-capable device is detected

بازرسی مجموعه داده اول توانید به ما بگویید که چه نوع از نمونه در می ClientData .

first_client_id = client_data.client_ids[0]
first_client_dataset = client_data.create_tf_dataset_for_client(
    first_client_id)
print(first_client_dataset.element_spec)
# This information is also available as a `ClientData` property:
assert client_data.element_type_structure == first_client_dataset.element_spec
OrderedDict([('label', TensorSpec(shape=(), dtype=tf.int32, name=None)), ('pixels', TensorSpec(shape=(28, 28), dtype=tf.float32, name=None))])

توجه داشته باشید که بازده مجموعه داده collections.OrderedDict اشیاء است که pixels و label کلید، که در آن پیکسل یک تانسور با شکل است [28, 28] . فرض کنید ما به پهن ورودی ما به شکل [784] . یکی از راه های ممکن ما می توانیم این کار را انجام، می تواند اعمال یک تابع قبل از پردازش به ما ClientData شی.

def preprocess_dataset(dataset):
  """Create batches of 5 examples, and limit to 3 batches."""

  def map_fn(input):
    return collections.OrderedDict(
        x=tf.reshape(input['pixels'], shape=(-1, 784)),
        y=tf.cast(tf.reshape(input['label'], shape=(-1, 1)), tf.int64),
    )

  return dataset.batch(5).map(
      map_fn, num_parallel_calls=tf.data.experimental.AUTOTUNE).take(5)


preprocessed_client_data = client_data.preprocess(preprocess_dataset)

# Notice that we have both reshaped and renamed the elements of the ordered dict.
first_client_dataset = preprocessed_client_data.create_tf_dataset_for_client(
    first_client_id)
print(first_client_dataset.element_spec)
OrderedDict([('x', TensorSpec(shape=(None, 784), dtype=tf.float32, name=None)), ('y', TensorSpec(shape=(None, 1), dtype=tf.int64, name=None))])

ممکن است بخواهیم علاوه بر این، پیش پردازش پیچیده تری (و احتمالاً حالتی) را انجام دهیم، برای مثال درهم ریختن.

def preprocess_and_shuffle(dataset):
  """Applies `preprocess_dataset` above and shuffles the result."""
  preprocessed = preprocess_dataset(dataset)
  return preprocessed.shuffle(buffer_size=5)

preprocessed_and_shuffled = client_data.preprocess(preprocess_and_shuffle)

# The type signature will remain the same, but the batches will be shuffled.
first_client_dataset = preprocessed_and_shuffled.create_tf_dataset_for_client(
    first_client_id)
print(first_client_dataset.element_spec)
OrderedDict([('x', TensorSpec(shape=(None, 784), dtype=tf.float32, name=None)), ('y', TensorSpec(shape=(None, 1), dtype=tf.int64, name=None))])

واسط با tff.Computation

حالا که ما می توانیم برخی دستکاری اساسی با انجام ClientData اشیاء، ما آماده به داده های خوراک به یک هستند tff.Computation . تعریف می کنیم tff.templates.IterativeProcess که پیاده سازی فدرال به طور متوسط ، اکتشاف و روش های مختلف انتقال آن داده است.

def model_fn():
  model = tf.keras.models.Sequential([
      tf.keras.layers.InputLayer(input_shape=(784,)),
      tf.keras.layers.Dense(10, kernel_initializer='zeros'),
  ])
  return tff.learning.from_keras_model(
      model,
      # Note: input spec is the _batched_ shape, and includes the 
      # label tensor which will be passed to the loss function. This model is
      # therefore configured to accept data _after_ it has been preprocessed.
      input_spec=collections.OrderedDict(
          x=tf.TensorSpec(shape=[None, 784], dtype=tf.float32),
          y=tf.TensorSpec(shape=[None, 1], dtype=tf.int64)),
      loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
      metrics=[tf.keras.metrics.SparseCategoricalAccuracy()])

trainer = tff.learning.build_federated_averaging_process(
    model_fn,
    client_optimizer_fn=lambda: tf.keras.optimizers.SGD(learning_rate=0.01))

قبل از شروع به کار با این IterativeProcess ، یک نظر در معناشناسی ClientData در نظم است. ClientData شیء نشان دهنده کل جمعیت در دسترس برای آموزش فدرال، که به طور کلی در دسترس نیست به محیط زیست اجرای یک سیستم FL تولید و خاص به شبیه سازی است. ClientData واقع به کاربر اجازه میدهد ظرفیت برای دور زدن محاسبات فدرال به طور کامل و به سادگی آموزش یک مدل در سمت سرور به طور معمول از طریق ClientData.create_tf_dataset_from_all_clients .

محیط شبیه سازی TFF محقق را در کنترل کامل حلقه بیرونی قرار می دهد. به طور خاص این به معنی ملاحظات در دسترس بودن کلاینت، خروج مشتری و غیره است که باید توسط کاربر یا اسکریپت درایور پایتون مورد توجه قرار گیرد. یک نفر می تواند برای مثال مدل ترک تحصیل مشتری با تنظیم توزیع نمونه خود را بیش از ClientData's client_ids به طوری که کاربران با داده ها (و نسبت به دیگر در حال اجرا محاسبات محلی) خواهد بود که با احتمال کمتر انتخاب شده است.

با این حال، در یک سیستم فدرال واقعی، مشتریان نمی توانند به صراحت توسط مربی مدل انتخاب شوند. انتخاب مشتریان به سیستمی که محاسبات فدرال را اجرا می کند، واگذار می شود.

عبور tf.data.Datasets به طور مستقیم به TFF

یکی از گزینه های ما برای واسط بین دارند ClientData و IterativeProcess که ساخت است tf.data.Datasets در پایتون، و عبور این مجموعه داده ها به TFF.

توجه داشته باشید که اگر ما با استفاده پیش پردازش ما ClientData مجموعه داده های عملکرد ما از نوع مناسب انتظار می رود توسط مدل ما در بالا تعریف شده است.

selected_client_ids = preprocessed_and_shuffled.client_ids[:10]

preprocessed_data_for_clients = [
    preprocessed_and_shuffled.create_tf_dataset_for_client(
        selected_client_ids[i]) for i in range(10)
]

state = trainer.initialize()
for _ in range(5):
  t1 = time.time()
  state, metrics = trainer.next(state, preprocessed_data_for_clients)
  t2 = time.time()
  print('loss {}, round time {}'.format(metrics['train']['loss'], t2 - t1))
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow_federated/python/core/impl/compiler/tensorflow_computation_transformations.py:62: extract_sub_graph (from tensorflow.python.framework.graph_util_impl) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.compat.v1.graph_util.extract_sub_graph`
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow_federated/python/core/impl/compiler/tensorflow_computation_transformations.py:62: extract_sub_graph (from tensorflow.python.framework.graph_util_impl) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.compat.v1.graph_util.extract_sub_graph`
loss 2.9005744457244873, round time 4.576513767242432
loss 3.113278388977051, round time 0.49641919136047363
loss 2.7581865787506104, round time 0.4904160499572754
loss 2.87259578704834, round time 0.48976993560791016
loss 3.1202380657196045, round time 0.6724586486816406

اگر ما به این مسیر، با این حال، ما قادر به بدیهی به شبیه سازی multimachine حرکت می کند. مجموعه داده های ما در زمان اجرا TensorFlow محلی ساخت می تواند دولت را از محیط اطراف پایتون ضبط، و شکست در ترتیب و یا deserialization زمانی که آنها به دولت مرجع است که دیگر به آنها در دسترس نیست تلاش. این می تواند به عنوان مثال در خطا مرموز از TensorFlow را آشکار tensor_util.cc :

Check failed: DT_VARIANT == input.dtype() (21 vs. 20)

نقشه برداری ساخت و ساز و پیش پردازش بر روی مشتریان

برای جلوگیری از این مسئله، TFF توصیه کاربران آن به در نظر گرفتن مجموعه داده نمونه و پیش پردازش به عنوان چیزی که به صورت محلی بر هر مشتری اتفاق می افتد، و برای استفاده از یاران TFF یا federated_map به صراحت این کد از پیش پردازش در هر اجرا می شود.

از نظر مفهومی، دلیل ترجیح این امر واضح است: در زمان اجرا محلی TFF، مشتریان تنها "به طور تصادفی" به محیط جهانی پایتون دسترسی دارند، زیرا کل ارکستراسیون فدرال روی یک ماشین واحد انجام می شود. در این مرحله شایان ذکر است که تفکر مشابه باعث ایجاد فلسفه عملکردی بین پلتفرمی و همیشه سریال‌پذیر TFF می‌شود.

TFF باعث می شود چنین ساده تغییر از طریق ClientData's ویژگی dataset_computation ، یک tff.Computation که طول می کشد client_id و ارتباط گرداند tf.data.Dataset .

توجه داشته باشید که preprocess به سادگی با این نسخهها کار dataset_computation ؛ dataset_computation ویژگی از پیش پردازش ClientData شامل کل خط لوله پردازش ما فقط تعریف می شود:

print('dataset computation without preprocessing:')
print(client_data.dataset_computation.type_signature)
print('\n')
print('dataset computation with preprocessing:')
print(preprocessed_and_shuffled.dataset_computation.type_signature)
dataset computation without preprocessing:
(string -> <label=int32,pixels=float32[28,28]>*)


dataset computation with preprocessing:
(string -> <x=float32[?,784],y=int64[?,1]>*)

ما می توانیم استناد dataset_computation و دریافت مجموعه داده مشتاق در زمان اجرا پایتون، اما قدرت واقعی این رویکرد اعمال می شود زمانی که ما با یک روند تکراری و یا محاسبات دیگر برای جلوگیری از تحقق این مجموعه داده ها در زمان اجرا مشتاق جهانی در همه آهنگسازی. TFF یک تابع کمکی فراهم می کند tff.simulation.compose_dataset_computation_with_iterative_process است که می تواند مورد استفاده قرار گیرد به دقیقا این است.

trainer_accepting_ids = tff.simulation.compose_dataset_computation_with_iterative_process(
    preprocessed_and_shuffled.dataset_computation, trainer)

هر دو این tff.templates.IterativeProcesses و یکی در بالا اجرا به همان شیوه. اما سابق می پذیرد مجموعه داده مشتری پیش پردازش، و دومی رشته به نمایندگی شناسه مشتری، دست زدن به هر دو ساخت و ساز مجموعه داده ها و پیش پردازش در بدن خود می پذیرد - در واقع state را می توان بین این دو به تصویب رسید.

for _ in range(5):
  t1 = time.time()
  state, metrics = trainer_accepting_ids.next(state, selected_client_ids)
  t2 = time.time()
  print('loss {}, round time {}'.format(metrics['train']['loss'], t2 - t1))
loss 2.8417396545410156, round time 1.6707067489624023
loss 2.7670371532440186, round time 0.5207102298736572
loss 2.665048122406006, round time 0.5302855968475342
loss 2.7213189601898193, round time 0.5313887596130371
loss 2.580148935317993, round time 0.5283482074737549

مقیاس بندی به تعداد زیادی مشتری

trainer_accepting_ids می توانید بلافاصله در زمان اجرا multimachine TFF استفاده می شود، و اجتناب تحقق tf.data.Datasets و کنترل (و در نتیجه serialize کردن آنها و ارسال آنها را به کارگران).

این امر به طور قابل توجهی شبیه‌سازی‌های توزیع‌شده را، به‌ویژه با تعداد زیادی از مشتریان، سرعت می‌بخشد و تجمیع میانی را قادر می‌سازد تا از هزینه‌های سربار سریال‌سازی/آسیالی‌زدایی مشابه جلوگیری کند.

Deepdive اختیاری: نوشتن دستی منطق پیش پردازش در TFF

TFF برای ترکیب بندی از ابتدا طراحی شده است. نوع ترکیبی که فقط توسط کمک کننده TFF انجام می شود کاملاً تحت کنترل ما به عنوان کاربران است. ما می توانیم به صورت دستی دارند نوشتن محاسبات پیش پردازش ما فقط با تعریف مربی خود next کاملا به سادگی:

selected_clients_type = tff.FederatedType(preprocessed_and_shuffled.dataset_computation.type_signature.parameter, tff.CLIENTS)

@tff.federated_computation(trainer.next.type_signature.parameter[0], selected_clients_type)
def new_next(server_state, selected_clients):
  preprocessed_data = tff.federated_map(preprocessed_and_shuffled.dataset_computation, selected_clients)
  return trainer.next(server_state, preprocessed_data)

manual_trainer_with_preprocessing = tff.templates.IterativeProcess(initialize_fn=trainer.initialize, next_fn=new_next)

در واقع، این عملاً همان کاری است که کمکی که ما استفاده کردیم در زیر کاپوت انجام می دهد (به علاوه انجام بررسی و دستکاری نوع مناسب). ما حتی می تواند از همین منطق را ابراز کرده اند کمی متفاوت، توسط serialize کردن preprocess_and_shuffle به یک tff.Computation ، و تجزیه federated_map به یک مرحله که ساخت مجموعه داده سازمان ملل متحد پیش پردازش و دیگری اجرا می شود که preprocess_and_shuffle در هر مشتری.

ما می‌توانیم تأیید کنیم که این مسیر دستی‌تر منجر به محاسباتی با همان نوع امضای کمکی TFF می‌شود (نام پارامترهای مدول):

print(trainer_accepting_ids.next.type_signature)
print(manual_trainer_with_preprocessing.next.type_signature)
(<server_state=<model=<trainable=<float32[784,10],float32[10]>,non_trainable=<>>,optimizer_state=<int64>,delta_aggregate_state=<value_sum_process=<>,weight_sum_process=<>>,model_broadcast_state=<>>@SERVER,federated_dataset={string}@CLIENTS> -> <<model=<trainable=<float32[784,10],float32[10]>,non_trainable=<>>,optimizer_state=<int64>,delta_aggregate_state=<value_sum_process=<>,weight_sum_process=<>>,model_broadcast_state=<>>@SERVER,<broadcast=<>,aggregation=<mean_value=<>,mean_weight=<>>,train=<sparse_categorical_accuracy=float32,loss=float32>,stat=<num_examples=int64>>@SERVER>)
(<server_state=<model=<trainable=<float32[784,10],float32[10]>,non_trainable=<>>,optimizer_state=<int64>,delta_aggregate_state=<value_sum_process=<>,weight_sum_process=<>>,model_broadcast_state=<>>@SERVER,selected_clients={string}@CLIENTS> -> <<model=<trainable=<float32[784,10],float32[10]>,non_trainable=<>>,optimizer_state=<int64>,delta_aggregate_state=<value_sum_process=<>,weight_sum_process=<>>,model_broadcast_state=<>>@SERVER,<broadcast=<>,aggregation=<mean_value=<>,mean_weight=<>>,train=<sparse_categorical_accuracy=float32,loss=float32>,stat=<num_examples=int64>>@SERVER>)