tf.distribute.experimental.MultiWorkerMirroredStrategy
| Просмотреть исходный код на GitHub |
Стратегия распределения для синхронного обучения на нескольких узлах.
Наследуется от: Strategy
tf.distribute.experimental.MultiWorkerMirroredStrategy(
communication=tf.distribute.experimental.CollectiveCommunication.AUTO
)
Эта стратегия реализует синхронное распределенное обучение на нескольких узлах, каждый из которых может иметь несколько графических процессоров. Подобно tf.distribute.MirroredStrategy, она создаёт копии всех переменных модели на каждом устройстве на всех узлах.
Она использует реализацию multi-worker all-reduce CollectiveOps для синхронизации переменных. Коллективная операция — это отдельная операция в графе TensorFlow, которая может автоматически выбирать алгоритм all-reduce в среде выполнения TensorFlow в соответствии с аппаратным обеспечением, топологией сети и размерами тензоров.
По умолчанию она использует все локальные графические процессоры или ЦП для обучения на одном узле.
Когда переменная окружения 'TF_CONFIG' установлена, она анализирует cluster_spec, task_type и task_id из 'TF_CONFIG' и преобразует их в стратегию для нескольких узлов, которая дублирует модели на графических процессорах всех машин в кластере. В текущей реализации она использует все графические процессоры в кластере и предполагает, что все узлы имеют одинаковое количество графических процессоров.
Она поддерживает как режим eager, так и режим графа. Однако для режима eager ей необходимо настроить контекст eager в конструкторе, поэтому все операции в режиме eager должны выполняться после создания объекта стратегии.
| Атрибуты | |
|---|---|
extended | tf.distribute.StrategyExtended с дополнительными методами. |
num_replicas_in_sync | Возвращает количество реплик, по которым агрегируются градиенты. |
Методы
experimental_distribute_dataset
experimental_distribute_dataset(
dataset
)
Распределяет экземпляр tf.data.Dataset, предоставленный через dataset.
Возвращаемый распределённый набор данных можно перебирать аналогично тому, как можно перебирать обычные наборы данных. ПРИМЕЧАНИЕ: В настоящее время пользователь не может добавлять дополнительные преобразования к распределённому набору данных.
Вот пример:
strategy = tf.distribute.MirroredStrategy() # Create a dataset dataset = dataset_ops.Dataset.TFRecordDataset([ "/a/1.tfr", "/a/2.tfr", "/a/3.tfr", "/a/4.tfr"]) # Distribute that dataset dist_dataset = strategy.experimental_distribute_dataset(dataset) # Iterate over the distributed dataset for x in dist_dataset: # process dataset elements strategy.experimental_run_v2(train_step, args=(x,))
Мы будем предполагать, что входной набор данных сгруппирован по глобальному размеру пакета. При этом предположении мы будем стараться разделить каждый пакет на все реплики (один или несколько узлов).
В многоузловой среде мы сначала попытаемся распределить набор данных, пытаясь определить, создаётся ли набор данных из ReaderDatasets (например, TFRecordDataset, TextLineDataset и т. д.), и если да, то попытаться разделить входные файлы. Обратите внимание, что по крайней мере один входной файл должен приходиться на один узел. Если у вас меньше одного входного файла на узел, мы рекомендуем отключить распределение вашего набора данных с помощью метода ниже.
Если эта попытка окажется неудачной (например, набор данных создаётся из Dataset.range), мы разделим набор данных равномерно в конце, добавив операцию .shard в конец потока обработки. Это приведёт к тому, что весь поток предобработки всех данных будет выполняться на каждом узле, и каждый узел будет выполнять избыточную работу. Мы выведем предупреждение, если этот метод фрагментации выбран. В этом случае рассмотрите использование experimental_distribute_datasets_from_function вместо этого.
Вы можете отключить фрагментацию наборов данных между узлами, используя опцию auto_shard в tf.data.experimental.DistributeOptions.
Внутри каждого узла мы также разделим данные между всеми устройствами узла (если присутствует более одного), и это произойдёт даже если многоузловая фрагментация отключена с помощью метода выше.
Если вышеупомянутая логика разделения пакетов и фрагментации наборов данных нежелательна, используйте experimental_distribute_datasets_from_function вместо этого, который не выполняет автоматического разделения или фрагментации.
| Аргументы | |
|---|---|
dataset | tf.data.Dataset, который будет распределен по всем репликам с использованием вышеуказанных правил. |
| Возвращаемое значение | |
|---|---|
"Распределённый Dataset", который ведет себя как tf.data.Dataset, за исключением того, что он производит значения "по реплике". |
experimental_distribute_datasets_from_function
experimental_distribute_datasets_from_function(
dataset_fn
)
Распределяет экземпляры tf.data.Dataset, созданные вызовами dataset_fn.
dataset_fn будет вызван один раз для каждого узла в стратегии. Каждая реплика на этом узле будет извлекать одну партию входных данных из локального Dataset (то есть, если у узла две реплики, две партии будут извлекаться из Dataset на каждом шаге).
Этот метод может использоваться для нескольких целей. Например, там, где experimental_distribute_dataset не может разделить входные файлы, этот метод может использоваться для ручного разделения набора данных (избегая медленного поведения по умолчанию в experimental_distribute_dataset). В случаях, когда набор данных бесконечен, это разделение можно выполнить, создав реплики наборов данных, отличающиеся только случайным зерном. experimental_distribute_dataset иногда также может не преуспеть в разделении пакета между репликами на узле. В этом случае этот метод может быть использован там, где такого ограничения нет.
dataset_fn должен принимать экземпляр tf.distribute.InputContext, где можно получить информацию о пакетировании и репликации входных данных:
def dataset_fn(input_context):
batch_size = input_context.get_per_replica_batch_size(global_batch_size)
d = tf.data.Dataset.from_tensors([[1.]]).repeat().batch(batch_size)
return d.shard(
input_context.num_input_pipelines, input_context.input_pipeline_id)
inputs = strategy.experimental_distribute_datasets_from_function(dataset_fn)
for batch in inputs:
replica_results = strategy.experimental_run_v2(replica_fn, args=(batch,))
| Аргументы | |
|---|---|
dataset_fn | Функция, принимающая экземпляр tf.distribute.InputContext и возвращающая tf.data.Dataset. |
| Возвращаемое значение | |
|---|---|
"Распределённый Dataset", который ведет себя как tf.data.Dataset, за исключением того, что он производит значения "по реплике". |
experimental_local_results
experimental_local_results(
value
)
Возвращает список всех локальных значений по реплике, содержащихся в value.
Примечание: Это возвращает только значения на узле, инициированном этим клиентом. При использованииtf.distribute.Strategy, например,tf.distribute.experimental.MultiWorkerMirroredStrategy, каждый узел будет своим клиентом, и эта функция вернёт только значения, вычисленные на этом узле.
| Аргументы | |
|---|---|
value | Значение, возвращённое experimental_run(), experimental_run_v2(), extended.call_for_each_replica() или переменная, созданная в scope. |
| Возвращаемое значение | |
|---|---|
Кортеж значений, содержащихся в value. Если value представляет одно значение, это возвращает (value,). |
experimental_make_numpy_dataset
experimental_make_numpy_dataset(
numpy_input, session=None
)
Создаёт tf.data.Dataset для входных данных, предоставленных через массив NumPy.
Это позволяет избежать добавления numpy_input как большой константы в граф и копирует данные на машину или машины, которые будут обрабатывать ввод.
Обратите внимание, что вам, скорее всего, потребуется использовать tf.distribute.Strategy.experimental_distribute_dataset с возвращённым набором данных, чтобы дополнительно распределить его с помощью стратегии.
Пример:
numpy_input = np.ones([10], dtype=np.float32) dataset = strategy.experimental_make_numpy_dataset(numpy_input) dist_dataset = strategy.experimental_distribute_dataset(dataset)
| Аргументы | |
|---|---|
numpy_input | Вложенный массив NumPy входных данных, который будет преобразован в набор данных. Обратите внимание, что списки массивов NumPy складываются, так как это стандартное поведение tf.data.Dataset. |
session | (Только для выполнения графа TensorFlow v1.x) Сессия, используемая для инициализации. |
| Возвращаемое значение | |
|---|---|
tf.data.Dataset, представляющий numpy_input. |
experimental_run
experimental_run(
fn, input_iterator=None
)
Выполняет операции в fn на каждой реплике с входными данными из input_iterator.
УСТАРЕЛО: Этот метод недоступен в TF 2.x. Переключитесь на использование experimental_run_v2 вместо этого.
При включённом режиме eager выполнения, выполняет операции, указанные в fn на каждой реплике. В противном случае создаёт граф для выполнения операций на каждой реплике.
Каждая копия будет принимать один, отличающийся ввод из ввода, предоставленного одним get_next вызовом итератора ввода.
fn может вызвать tf.distribute.get_replica_context() для доступа к членам, таким как replica_id_in_sync_group.
| Аргументы | |
|---|---|
fn | Функция для выполнения. Ввод в функцию должен соответствовать выводу input_iterator.get_next(). Вывод должен быть tf.nest из Tensor. |
input_iterator | (Необязательно) итератор ввода, из которого берутся вводные данные. |
| Возвращаемое значение | |
|---|---|
Объединённое возвращаемое значение fn по всем копиям. Структура возвращаемого значения такая же, как у возвращаемого значения от fn. Каждый элемент в структуре может быть либо PerReplica (если значения не синхронизированы), либо Mirrored (если значения хранятся в синхронизированном состоянии), либо Tensor (если выполняется на одной копии). |
experimental_run_v2
experimental_run_v2(
fn, args=(), kwargs=None
)
Выполнить fn на каждой копии с заданными аргументами.
Выполняет операции, заданные fn на каждой копии. Если args или kwargs имеют значения «на копию», например, те, что созданы распределённым Dataset, когда fn выполняется на конкретной копии, она будет выполнена с компонентом этих значений «на копию», который соответствует этой копии.
fn может вызвать tf.distribute.get_replica_context() для доступа к членам, таким как all_reduce.
Все аргументы в args или kwargs должны быть либо вложенными тензорами, либо объектами «на копию», содержащими тензоры или составные тензоры.
| Аргументы | |
|---|---|
fn | Функция для выполнения. Вывод должен быть tf.nest из Tensor. |
args | (Необязательно) Позиционные аргументы для fn. |
kwargs | (Необязательно) Именованные аргументы для fn. |
| Возвращаемое значение | |
|---|---|
Объединённое возвращаемое значение fn по всем копиям. Структура возвращаемого значения такая же, как у возвращаемого значения от fn. Каждый элемент в структуре может быть объектом «на копию» Tensor или Tensor (например, при работе на одной копии). |
make_dataset_iterator
make_dataset_iterator(
dataset
)
Создаёт итератор для ввода, предоставленного через dataset.
УСТАРЕЛО: Этот метод недоступен в TF 2.x.
Данные из заданного набора данных будут распределены равномерно по всем копиям вычислительных узлов. Мы будем считать, что набор данных ввода сгруппирован по глобальному размеру пакета. С этим предположением мы будем прилагать все усилия для разделения каждого пакета по всем копиям (один или несколько рабочих узлов). Если эти усилия окажутся безуспешными, будет выброшено исключение, и пользователь должен вместо этого использовать make_input_fn_iterator, который предоставляет больше контроля пользователю и не пытается разделить пакет по копиям.
Пользователь также может использовать make_input_fn_iterator, если хочет настроить ввод, подаваемый для каждой копии/рабочего узла и т. д.
| Аргументы | |
|---|---|
dataset | tf.data.Dataset, который будет распределён равномерно по всем копиям. |
| Возвращаемое значение | |
|---|---|
tf.distribute.InputIterator, который возвращает входные данные для каждого шага вычисления. Пользователь должен вызвать initialize для возвращённого итератора. |
make_input_fn_iterator
make_input_fn_iterator(
input_fn, replication_mode=tf.distribute.InputReplicationMode.PER_WORKER
)
Возвращает итератор, разделённый по копиям, созданный из функции ввода.
УСТАРЕЛО: Этот метод недоступен в TF 2.x.
input_fn должна принять объект tf.distribute.InputContext, где можно получить информацию о пакетировании и фрагментации ввода:
def input_fn(input_context):
batch_size = input_context.get_per_replica_batch_size(global_batch_size)
d = tf.data.Dataset.from_tensors([[1.]]).repeat().batch(batch_size)
return d.shard(input_context.num_input_pipelines,
input_context.input_pipeline_id)
with strategy.scope():
iterator = strategy.make_input_fn_iterator(input_fn)
replica_results = strategy.experimental_run(replica_fn, iterator)
Возвращаемый tf.data.Dataset из input_fn должен иметь размер пакета на копию, который можно вычислить с помощью input_context.get_per_replica_batch_size.
| Аргументы | |
|---|---|
input_fn | Функция, принимающая объект tf.distribute.InputContext и возвращающая tf.data.Dataset. |
replication_mode | значение перечисления tf.distribute.InputReplicationMode. В настоящее время поддерживается только PER_WORKER, что означает, что для каждого рабочего узла будет сделан один вызов input_fn. Копии будут извлекать данные из локального tf.data.Dataset на своих рабочих узлах. |
| Возвращаемое значение | |
|---|---|
Объект итератора, который в первую очередь необходимо вызвать с .initialize(). Затем его можно передать в strategy.experimental_run() или получить следующее значение с помощью iterator.get_next(), чтобы передать его в strategy.extended.call_for_each_replica(). |
reduce
reduce(
reduce_op, value, axis=None
)
Сведение value по копиям.
Учитывая значение на копию, возвращённое experimental_run_v2, скажем, потерю на пример, пакет будет разделён между всеми копиями. Эта функция позволяет агрегировать по копиям и, необязательно, также по элементам пакета. Например, если у вас есть глобальный размер пакета 8 и 2 копии, значения для примеров [0, 1, 2, 3] будут на копии 0, а [4, 5, 6, 7] на копии 1. По умолчанию reduce просто агрегирует по копиям, возвращая [0+4, 1+5, 2+6, 3+7]. Это полезно, когда каждая копия вычисляет скаляр или какое-либо другое значение, у которого нет «размера пакета» (например, градиент). Чаще всего вы захотите агрегировать по глобальному пакету, что можно сделать, задав размер пакета как axis, обычно axis=0. В этом случае она вернёт скаляр 0+1+2+3+4+5+6+7.
Если есть последний частичный пакет, вам необходимо указать ось, чтобы размер получившейся формы был согласован между копиями. Так, если последний пакет имеет размер 6 и разделён на [0, 1, 2, 3] и [4, 5], у вас возникнет несоответствие размеров формы, если вы не укажете axis=0. Если вы укажете tf.distribute.ReduceOp.MEAN, используя axis=0 будет использоваться правильный знаменатель 6. В отличие от вычисления reduce_mean для получения скалярного значения на каждой копии и этой функции для усреднения этих средних, которые будут взвешивать некоторые значения 1/8, а другие 1/4.
| Аргументы | |
|---|---|
reduce_op | Значение tf.distribute.ReduceOp, указывающее, как следует объединять значения. |
value | Значение «на копию», например, возвращённое experimental_run_v2, которое нужно объединить в один тензор. |
axis | Указывает размерность, по которой следует сводить значения внутри тензора каждой копии. Обычно устанавливается на размер пакета или None для сведения только по копиям (например, если тензор не имеет размера пакета). |
| Возвращаемое значение | |
|---|---|
Tensor. |
scope
scope()
Возвращает менеджер контекста, выбирающий эту стратегию в качестве текущей.
Внутри блока кода with strategy.scope(): этот поток будет использовать создатель переменной, установленный strategy, и войдёт в свой «межкопийный контекст».
| Возвращаемое значение | |
|---|---|
| Менеджер контекста. |
update_config_proto
update_config_proto(
config_proto
)
Возвращает копию config_proto, изменённую для использования с этой стратегией.
УСТАРЕЛО: Этот метод недоступен в TF 2.x.
Обновлённая конфигурация содержит необходимые для запуска стратегии элементы, например, конфигурацию для запуска коллективных операций или фильтры устройств для повышения производительности распределённого обучения.
| Аргументы | |
|---|---|
config_proto | объект tf.ConfigProto. |
| Возвращаемое значение | |
|---|---|
Обновлённую копию config_proto. |
© 2020 The TensorFlow Authors. All rights reserved.
Licensed under the Creative Commons Attribution License 3.0.
Code samples licensed under the Apache 2.0 License.
https://www.tensorflow.org/versions/r1.15/api_docs/python/tf/distribute/experimental/MultiWorkerMirroredStrategy