Szkolenie rozproszone

Uczenie rozproszone to rodzaj uczenia modelowego, w którym wymagania dotyczące zasobów obliczeniowych (np. procesora, pamięci RAM) są rozdzielone pomiędzy wiele komputerów. Uczenie rozproszone pozwala trenować szybciej i na większych zbiorach danych (aż do kilku miliardów przykładów).

Uczenie rozproszone jest również przydatne w przypadku automatycznej optymalizacji parametrów, w której równolegle szkolonych jest wiele modeli.

W tym dokumencie dowiesz się, jak:

  • Trenuj model TF-DF za pomocą szkolenia rozproszonego.
  • Dostosuj hiperparametry modelu TF-DF za pomocą szkolenia rozproszonego.

Ograniczenia

Obecnie szkolenia rozproszone są obsługiwane dla:

  • Trenowanie modeli drzew wzmocnionych gradientem za pomocą tfdf.keras.DistributedGradientBoostedTreesModel . Modele rozproszonych drzew wzmocnionych gradientem są równoważne ich nierozproszonym odpowiednikom.
  • Wyszukiwanie hiperparametrów dla dowolnego typu modelu TF-DF.

Jak włączyć szkolenie rozproszone

W tej sekcji wymieniono kroki umożliwiające włączenie szkolenia rozproszonego. Pełne przykłady można znaleźć w następnej sekcji.

Zakres ParameterServerStrategy

Model i zestaw danych są zdefiniowane w zakresie ParameterServerStrategy .

strategy = tf.distribute.experimental.ParameterServerStrategy(...)
with strategy.scope():
  model = tfdf.keras.DistributedGradientBoostedTreesModel()
  distributed_train_dataset = strategy.distribute_datasets_from_function(dataset_fn)
model.fit(distributed_train_dataset)

Format zbioru danych

Podobnie jak w przypadku szkolenia nierozproszonego, zbiory danych mogą być dostarczane jako

  1. Skończony rozproszony zbiór danych tensorflow lub
  2. ścieżka do plików zestawu danych przy użyciu jednego ze zgodnych formatów zestawu danych .

Korzystanie z plików podzielonych na fragmenty jest znacznie prostsze niż stosowanie podejścia rozproszonego zbioru danych o skończonym przepływie tensorflow (1 linia zamiast ~ 20 linii kodu). Jednak tylko podejście oparte na zestawie danych tensorflow obsługuje przetwarzanie wstępne TensorFlow. Jeśli potok nie zawiera żadnego przetwarzania wstępnego, zalecana jest opcja zestawu danych podzielonego na fragmenty.

W obu przypadkach zbiór danych należy podzielić na wiele plików, aby efektywnie rozłożyć odczyt zbioru danych.

Ustawiaj pracowników

Głównym procesem jest program uruchamiający kod Pythona, który definiuje model TensorFlow. W tym procesie nie są wykonywane żadne skomplikowane obliczenia. Obliczenia efektywnego treningu dokonują pracownicy . Procesy robocze to procesy, na których działa serwer parametrów TensorFlow.

Szef powinien być skonfigurowany z adresem IP pracowników. Można to zrobić za pomocą zmiennej środowiskowej TF_CONFIG lub tworząc ClusterResolver . Aby uzyskać więcej informacji, zobacz Szkolenie serwera parametrów za pomocą ParameterServerStrategy .

ParameterServerStrategy TensorFlow definiuje dwa typy procesów roboczych: „pracownicy” i „serwer parametrów”. TensorFlow wymaga utworzenia instancji co najmniej jednego procesu roboczego każdego typu. Jednak TF-DF wykorzystuje tylko „pracowników”. Zatem należy utworzyć instancję jednego „serwera parametrów”, ale nie będzie on używany przez TF-DF. Przykładowo konfiguracja szkolenia TF-DF może wyglądać następująco:

  • 1 Szef
  • 50 pracowników
  • 1 Serwer parametrów

Pracownicy wymagają dostępu do niestandardowych operacji szkoleniowych TensorFlow Decision Forests. Istnieją dwie możliwości umożliwienia dostępu:

  1. Użyj wstępnie skonfigurowanego serwera parametrów TF-DF C++ //third_party/tensorflow_decision_forests/tensorflow/distribute:tensorflow_std_server .
  2. Utwórz serwer parametrów, wywołując tf.distribute.Server() . W takim przypadku TF-DF należy zaimportować import tensorflow_decision_forests .

Przykłady

W tej sekcji przedstawiono pełne przykłady rozproszonych konfiguracji szkoleniowych. Więcej przykładów znajdziesz w testach jednostkowych TF-DF .

Przykład: Rozproszone szkolenie dotyczące ścieżki zestawu danych

Podziel zbiór danych na zbiór plików podzielonych na fragmenty, korzystając z jednego ze zgodnych formatów zbiorów danych . Zaleca się na przykład nadawanie plikom nazw w następujący sposób: /path/to/dataset/train-<5 digit index>-of-<total files>

/path/to/dataset/train-00000-of-00100
/path/to/dataset/train-00001-of-00005
/path/to/dataset/train-00002-of-00005
...

Aby uzyskać maksymalną wydajność, liczba plików powinna być co najmniej 10 razy większa od liczby pracowników. Na przykład, jeśli szkolisz 100 pracowników, upewnij się, że zbiór danych jest podzielony na co najmniej 1000 plików.

Do plików można następnie odwoływać się za pomocą wyrażenia fragmentującego, takiego jak:

  • /ścieżka/do/zestawu danych/pociąg@1000
  • /ścieżka/do/zestawu danych/pociąg@*

Szkolenie rozproszone odbywa się w następujący sposób. W tym przykładzie zestaw danych jest przechowywany jako TFRecord przykładów TensorFlow (zdefiniowany przez klucz tfrecord+tfe ).

import tensorflow_decision_forests as tfdf
import tensorflow as tf

strategy = tf.distribute.experimental.ParameterServerStrategy(...)

with strategy.scope():
  model = tfdf.keras.DistributedGradientBoostedTreesModel()

model.fit_on_dataset_path(
    train_path="/path/to/dataset/train@1000",
    label_key="label_key",
    dataset_format="tfrecord+tfe")

print("Trained model")
model.summary()

Przykład: Rozproszone szkolenie na skończonym rozproszonym zestawie danych TensorFlow

TF-DF oczekuje rozproszonego, skończonego zbioru danych TensorFlow podzielonego na elementy robocze:

  • Rozproszony : nierozproszony zbiór danych jest opakowany w strategy.distribute_datasets_from_function .
  • finite : Zbiór danych powinien przeczytać każdy przykład dokładnie raz. Zbiór danych nie powinien zawierać żadnych repeat instrukcji.
  • worker-sharded : każdy proces roboczy powinien przeczytać osobną część zbioru danych.

Oto przykład:

import tensorflow_decision_forests as tfdf
import tensorflow as tf


def dataset_fn(context, paths):
  """Create a worker-sharded finite dataset from paths.

  Like for non-distributed training, each example should be visited exactly
  once (and by only one worker) during the training. In addition, for optimal
  training speed, the reading of the examples should be distributed among the
  workers (instead of being read by a single worker, or read and discarded
  multiple times).

  In other words, don't add a "repeat" statement and make sure to shard the
  dataset at the file level and not at the example level.
  """

  # List the dataset files
  ds_path = tf.data.Dataset.from_tensor_slices(paths)

  # Make sure the dataset is used with distributed training.
  assert context is not None


  # Split the among the workers.
  #
  # Note: The "shard" is applied on the file path. The shard should not be
  # applied on the examples directly.
  # Note: You cannot use 'context.num_input_pipelines' with ParameterServerV2.
  current_worker = tfdf.keras.get_worker_idx_and_num_workers(context)
  ds_path = ds_path.shard(
      num_shards=current_worker.num_workers,
      index=current_worker.worker_idx)

  def read_csv_file(path):
    """Reads a single csv file."""

    numerical = tf.constant([0.0], dtype=tf.float32)
    categorical_string = tf.constant(["NA"], dtype=tf.string)
    csv_columns = [
        numerical,  # feature 1
        categorical_string,  # feature 2
        numerical,  # feature 3
        # ... define the features here.
    ]
    return tf.data.experimental.CsvDataset(path, csv_columns, header=True)

  ds_columns = ds_path.interleave(read_csv_file)

  # We assume a binary classification label with the following possible values.
  label_values = ["<=50K", ">50K"]

  # Convert the text labels into integers:
  # "<=50K" => 0
  # ">50K" => 1
  init_label_table = tf.lookup.KeyValueTensorInitializer(
      keys=tf.constant(label_values),
      values=tf.constant(range(label_values), dtype=tf.int64))
  label_table = tf.lookup.StaticVocabularyTable(
      init_label_table, num_oov_buckets=1)

  def extract_label(*columns):
    return columns[0:-1], label_table.lookup(columns[-1])

  ds_dataset = ds_columns.map(extract_label)

  # The batch size has no impact on the quality of the model. However, a larger
  # batch size generally is faster.
  ds_dataset = ds_dataset.batch(500)
  return ds_dataset


strategy = tf.distribute.experimental.ParameterServerStrategy(...)
with strategy.scope():
  model = tfdf.keras.DistributedGradientBoostedTreesModel()

  train_dataset = strategy.distribute_datasets_from_function(
      lambda context: dataset_fn(context, [...list of csv files...])
  )

model.fit(train_dataset)

print("Trained model")
model.summary()

Przykład: rozproszone dostrajanie hiperparametrów na ścieżce zestawu danych

Rozproszone dostrajanie parametrów na ścieżce zestawu danych jest podobne do szkolenia rozproszonego. Jedyna różnica polega na tym, że ta opcja jest kompatybilna z modelami niedystrybuowanymi. Na przykład można rozpowszechniać dostrajanie hiperparametrów (nierozproszonego) modelu drzew ze wzmocnionym gradientem.

with strategy.scope():
  tuner = tfdf.tuner.RandomSearch(num_trials=30, use_predefined_hps=True)
  model = tfdf.keras.GradientBoostedTreesModel(tuner=tuner)

training_history = model.fit_on_dataset_path(
  train_path=train_path,
  label_key=label,
  dataset_format="csv",
  valid_path=test_path)

logging.info("Trained model:")
model.summary()

Przykład: testowanie jednostkowe

Aby przeprowadzić test jednostkowy szkolenia rozproszonego, można utworzyć próbne procesy robocze. Aby uzyskać więcej informacji, zobacz metodę _create_in_process_tf_ps_cluster w testach jednostkowych TF-DF .