Spec-Zone.ru › TensorFlow

tf.compat.v1.distribute.MirroredStrategy

Синхронное обучение на нескольких репликах на одной машине.

Наследуется от: Strategy

tf.compat.v1.distribute.MirroredStrategy(
    devices=None, cross_device_ops=None
)

Используется в блокнотах

Используется в руководстве
  • Миграция обучения с использованием нескольких GPU на одном узле

Эта стратегия обычно используется для обучения на одной машине с несколькими GPU. Для TPU используйте tf.distribute.TPUStrategy. Для использования MirroredStrategy с несколькими рабочими узлами, обратитесь к tf.distribute.experimental.MultiWorkerMirroredStrategy.

Например, переменная, созданная в рамках MirroredStrategy, является MirroredVariable. Если в аргументе конструктора стратегии не указаны устройства, она будет использовать все доступные GPU. Если GPU не найдены, она будет использовать доступные CPU. Обратите внимание, что TensorFlow обрабатывает все CPU на машине как одно устройство и использует потоки внутри для параллелизма.

strategy = tf.distribute.MirroredStrategy(["GPU:0", "GPU:1"])
with strategy.scope():
  x = tf.Variable(1.)
x
MirroredVariable:{
  0: <tf.Variable ... shape=() dtype=float32, numpy=1.0>,
  1: <tf.Variable ... shape=() dtype=float32, numpy=1.0>
}

При использовании стратегий распределения все создание переменных должно выполняться в рамках области действия стратегии. Это позволит дублировать переменные по всем репликам и синхронизировать их с помощью алгоритма all-reduce.

Переменные, созданные внутри MirroredStrategy, которое обернуто с помощью tf.function, по-прежнему являются MirroredVariables.

x = []
@tf.function  # Wrap the function with tf.function.
def create_variable():
  if not x:
    x.append(tf.Variable(1.))
  return x[0]
strategy = tf.distribute.MirroredStrategy(["GPU:0", "GPU:1"])
with strategy.scope():
  _ = create_variable()
  print(x[0])
MirroredVariable:{
  0: <tf.Variable ... shape=() dtype=float32, numpy=1.0>,
  1: <tf.Variable ... shape=() dtype=float32, numpy=1.0>
}

experimental_distribute_dataset можно использовать для распределения набора данных по репликам при написании собственного цикла обучения. Если вы используете .fit и .compile методы, доступные в tf.keras, то tf.keras будет обрабатывать распределение за вас.

Например:

my_strategy = tf.distribute.MirroredStrategy()
with my_strategy.scope():
  @tf.function
  def distribute_train_epoch(dataset):
    def replica_fn(input):
      # process input and return result
      return result

    total_result = 0
    for x in dataset:
      per_replica_result = my_strategy.run(replica_fn, args=(x,))
      total_result += my_strategy.reduce(tf.distribute.ReduceOp.SUM,
                                         per_replica_result, axis=None)
    return total_result

  dist_dataset = my_strategy.experimental_distribute_dataset(dataset)
  for _ in range(EPOCHS):
    train_result = distribute_train_epoch(dist_dataset)
Аргументы
devices список строк устройств, таких как ['/gpu:0', '/gpu:1']. Если None, используются все доступные GPU. Если GPU не найдены, используется CPU.
cross_device_ops необязательный, потомок CrossDeviceOps. Если это не установлено, по умолчанию будет использоваться NcclAllReduce(). Это можно настроить, если NCCL недоступен или если доступна специальная реализация, которая использует конкретное оборудование.
Атрибуты
cluster_resolver Возвращает решатель кластера, связанный с этой стратегией.

В общем случае, при использовании многоузловой стратегии распределения, такой как tf.distribute.experimental.MultiWorkerMirroredStrategy или tf.distribute.TPUStrategy(), существует tf.distribute.cluster_resolver.ClusterResolver, связанный со стратегией, и такой экземпляр возвращается этим свойством.

Стратегии, которые намерены иметь связанный tf.distribute.cluster_resolver.ClusterResolver, должны установить соответствующий атрибут или переопределить это свойство; в противном случае, по умолчанию возвращается None. Эти стратегии также должны предоставить информацию о том, что возвращается этим свойством.

Одноузловые стратегии обычно не имеют tf.distribute.cluster_resolver.ClusterResolver, и в этих случаях это свойство вернет None.

tf.distribute.cluster_resolver.ClusterResolver может быть полезен, когда пользователю нужно получить доступ к информации, такой как спецификация кластера, тип задачи или идентификатор задачи. Например,

os.environ['TF_CONFIG'] = json.dumps({
  'cluster': {
      'worker': ["localhost:12345", "localhost:23456"],
      'ps': ["localhost:34567"]
  },
  'task': {'type': 'worker', 'index': 0}
})

# This implicitly uses TF_CONFIG for the cluster and current task info.
strategy = tf.distribute.experimental.MultiWorkerMirroredStrategy()

...

if strategy.cluster_resolver.task_type == 'worker':
  # Perform something that's only applicable on workers. Since we set this
  # as a worker above, this block will run on this particular instance.
elif strategy.cluster_resolver.task_type == 'ps':
  # Perform something that's only applicable on parameter servers. Since we
  # set this as a worker above, this block will not run on this particular
  # instance.

Для получения дополнительной информации см. документацию API tf.distribute.cluster_resolver.ClusterResolver.

extended tf.distribute.StrategyExtended с дополнительными методами.
num_replicas_in_sync Возвращает количество реплик, по которым агрегируются градиенты.

Методы

distribute_datasets_from_function

Посмотреть исходный код

distribute_datasets_from_function(
    dataset_fn, options=None
)

Распределяет экземпляры tf.data.Dataset, созданные при вызовах dataset_fn.

Аргумент dataset_fn, который пользователи передают, представляет собой функцию ввода, имеющую аргумент tf.distribute.InputContext и возвращающую экземпляр tf.data.Dataset. Ожидается, что возвращаемый набор данных из dataset_fn уже сгруппирован по размеру пакета на реплику (т. е. глобальный размер пакета, деленный на количество реплик в синхронизации), и поделен. tf.distribute.Strategy.distribute_datasets_from_function не группирует и не разделяет экземпляр tf.data.Dataset, возвращаемый функцией ввода. dataset_fn будет вызываться на устройстве CPU каждого из рабочих узлов, и каждый создаёт набор данных, в котором каждая реплика на этом узле будет декьюить одну партию ввода (т. е. если у узла две реплики, две партии будут декьюироваться из Dataset на каждом шаге).

Этот метод может использоваться для нескольких целей. Во-первых, он позволяет указать собственную логику группирования и разделения. (В отличие от tf.distribute.experimental_distribute_dataset, которая выполняет группировку и разделение за вас.) Например, где experimental_distribute_dataset не может разделить входные файлы, этот метод может быть использован для ручного разделения набора данных (избегая медленного поведения по умолчанию в experimental_distribute_dataset). В случаях, когда набор данных бесконечен, это разделение можно выполнить, создав реплики набора данных, которые отличаются только своим случайным начальным значением.

dataset_fn должен принимать экземпляр tf.distribute.InputContext, где можно получить информацию о группировании и дублировании входных данных.

Вы можете использовать свойство element_spec возвращаемого tf.distribute.DistributedDataset этим API, чтобы запросить tf.TypeSpec элементов, возвращаемых итератором. Это можно использовать для установки свойства input_signature tf.function. Последовайте tf.distribute.DistributedDataset.element_spec, чтобы увидеть пример.

Важно: tf.data.Dataset, возвращаемый dataset_fn, должен иметь размер пакета на реплику, в отличие от experimental_distribute_dataset, использующего глобальный размер пакета. Это можно вычислить, используя input_context.get_per_replica_batch_size.
Примечание: Если вы используете TPUStrategy, порядок, в котором данные обрабатываются рабочими узлами при использовании tf.distribute.Strategy.experimental_distribute_dataset или tf.distribute.Strategy.distribute_datasets_from_function, не гарантируется. Это обычно требуется, если вы используете tf.distribute для масштабирования предсказания. Однако вы можете вставить индекс для каждого элемента в партии и упорядочить выводы соответственно. Обратитесь к этому фрагменту для примера того, как упорядочить выводы.
Примечание: Состоятельные преобразования набора данных в настоящее время не поддерживаются с tf.distribute.experimental_distribute_dataset или tf.distribute.distribute_datasets_from_function. Любые состоятельные операции, которые может иметь набор данных, в настоящее время игнорируются. Например, если ваш набор данных имеет map_fn, который использует tf.random.uniform для поворота изображения, у вас есть граф набора данных, который зависит от состояния (например, случайного начального значения) на локальном компьютере, где выполняется работа python-процесса.

Для ознакомления с более подробным использованием и свойствами этого метода, обратитесь к руководству по распределённому вводу. Если вас интересует обработка последней частичной партии, прочтите эту секцию.

Аргументы
dataset_fn Функция, принимающая экземпляр tf.distribute.InputContext и возвращающая tf.data.Dataset.
options tf.distribute.InputOptions, используемый для управления параметрами распределения набора данных.
Возвращает
A tf.distribute.DistributedDataset.

experimental_distribute_dataset

Просмотреть исходный код

experimental_distribute_dataset(
    dataset, options=None
)

Создаёт tf.distribute.DistributedDataset из tf.data.Dataset.

Возвращаемый tf.distribute.DistributedDataset можно перебирать, как и обычные наборы данных. ВАЖНО: пользователь не может добавить больше преобразований к tf.distribute.DistributedDataset. Вы можете только создать итератор или проверить tf.TypeSpec данных, генерируемых им. Подробнее см. документацию API tf.distribute.DistributedDataset.

Ниже приведён пример:

global_batch_size = 2
# Passing the devices is optional.
strategy = tf.distribute.MirroredStrategy(devices=["GPU:0", "GPU:1"])
# Create a dataset
dataset = tf.data.Dataset.range(4).batch(global_batch_size)
# Distribute that dataset
dist_dataset = strategy.experimental_distribute_dataset(dataset)
@tf.function
def replica_fn(input):
  return input*2
result = []
# Iterate over the `tf.distribute.DistributedDataset`
for x in dist_dataset:
  # process dataset elements
  result.append(strategy.run(replica_fn, args=(x,)))
print(result)
[PerReplica:{
  0: <tf.Tensor: shape=(1,), dtype=int64, numpy=array([0])>,
  1: <tf.Tensor: shape=(1,), dtype=int64, numpy=array([2])>
}, PerReplica:{
  0: <tf.Tensor: shape=(1,), dtype=int64, numpy=array([4])>,
  1: <tf.Tensor: shape=(1,), dtype=int64, numpy=array([6])>
}]

Три ключевых действия, происходящих под капотом этого метода, это группировка, фрагментация и предварительная загрузка.

В приведённом фрагменте кода dataset сгруппирован по global_batch_size, а вызов experimental_distribute_dataset на нём перегруппирует dataset в новый размер пакета, равный общему размеру пакета, делённому на количество реплик в синхронизации. Мы перебираем его с помощью питоновского цикла for. x — это tf.distribute.DistributedValues, содержащий данные для всех реплик, и каждая реплика получает данные нового размера пакета. tf.distribute.Strategy.run позаботится о подаче правильных данных для каждой реплики в x в соответствующий replica_fn, выполняемый на каждой реплике.

Фрагментация включает автоматическое фрагментирование по нескольким рабочим узлам и внутри каждого рабочего узла. Во-первых, в распределённом обучении по нескольким рабочим узлам (т. е. когда вы используете tf.distribute.experimental.MultiWorkerMirroredStrategy или tf.distribute.TPUStrategy), автоматическое фрагментирование набора данных по рабочим узлам означает, что каждому рабочему узлу назначается подмножество всего набора данных (если установлен правильный tf.data.experimental.AutoShardPolicy). Это гарантирует, что на каждом шаге весь глобальный размер пакета непересекающихся элементов набора данных будет обработан каждым рабочим узлом. Автоматическое фрагментирование имеет несколько различных вариантов, которые можно указать с помощью tf.data.experimental.DistributeOptions. Затем фрагментация внутри каждого рабочего узла означает, что метод разделит данные между всеми устройствами рабочего узла (если их более одного). Это произойдёт независимо от автоматического фрагментирования по нескольким рабочим узлам.

Примечание: для автоматического фрагментирования по нескольким рабочим узлам, по умолчанию используется режим tf.data.experimental.AutoShardPolicy.AUTO. Этот режим попытается фрагментировать входной набор данных по файлам, если набор данных создаётся из наборов данных читателей (например, tf.data.TFRecordDataset, tf.data.TextLineDataset и т. д.), или иначе фрагментировать набор данных по данным, где каждый из рабочих узлов будет читать весь набор данных и обрабатывать только назначенный ему фрагмент. Однако, если у вас менее одного входного файла на рабочий узел, рекомендуется отключить автоматическое фрагментирование набора данных по рабочим узлам, установив tf.data.experimental.DistributeOptions.auto_shard_policy в tf.data.experimental.AutoShardPolicy.OFF.

По умолчанию этот метод добавляет преобразование предварительной загрузки в конец предоставленного пользователем экземпляра tf.data.Dataset. Аргумент преобразования предварительной загрузки, который является buffer_size, равен числу реплик в синхронизации.

Если описанная выше логика разделения пакета и фрагментации набора данных нежелательна, используйте tf.distribute.Strategy.distribute_datasets_from_function вместо этого, который не выполняет автоматической группировки или фрагментации.

Примечание: Если вы используете TPUStrategy, порядок обработки данных рабочими узлами при использовании tf.distribute.Strategy.experimental_distribute_dataset или tf.distribute.Strategy.distribute_datasets_from_function не гарантируется. Это обычно требуется, если вы используете tf.distribute для масштабирования прогнозирования. Однако вы можете вставить индекс для каждого элемента в пакете и упорядочить выходные данные соответственно. Обратитесь к этому фрагменту для примера, как упорядочить выходные данные.
Примечание: Состоятельные преобразования набора данных в настоящее время не поддерживаются с tf.distribute.experimental_distribute_dataset или tf.distribute.distribute_datasets_from_function. Любые состоятельные операции, которые может иметь набор данных, в настоящее время игнорируются. Например, если ваш набор данных имеет map_fn, который использует tf.random.uniform для поворота изображения, тогда у вас есть граф набора данных, который зависит от состояния (т. е. случайного семени) на локальном компьютере, где выполняется процесс Python.

Для получения дополнительных примеров использования и свойств этого метода обратитесь к учебнику по распределённому вводу. Если вас интересует обработка последних частичных пакетов, прочитайте эту секцию.

Аргументы
dataset tf.data.Dataset, который будет фрагментирован по всем репликам с использованием описанных выше правил.
options tf.distribute.InputOptions, используемый для управления параметрами распределения этого набора данных.
Возвращает
A tf.distribute.DistributedDataset.

experimental_local_results

Просмотреть исходный код

experimental_local_results(
    value
)

Возвращает список всех локальных значений каждой реплики, содержащихся в value.

Примечание: Это возвращает только значения на рабочем узле, инициированном этим клиентом. При использовании tf.distribute.Strategy, например, tf.distribute.experimental.MultiWorkerMirroredStrategy, каждый рабочий узел будет своим клиентом, и эта функция вернёт только значения, вычисленные на этом рабочем узле.
Аргументы
value Значение, возвращённое experimental_run(), run(), or a variable created inscope`.
Возвращает
Кортеж значений, содержащихся в value, где i-й элемент соответствует i-й реплике. Если 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. Переключитесь на использование run вместо этого.
Устарело: Этот метод недоступен в TF 2.x. Переключитесь на использование run вместо этого.

При включённом режиме выполнения Eager, выполняет операции, заданные fn на каждой реплике. В противном случае создаёт граф для выполнения операций на каждой реплике.

Каждая реплика получит один, отличающийся вход из входных данных, предоставленных одним вызовом get_next для итератора ввода.

fn может вызвать tf.distribute.get_replica_context() для доступа к членам, таким как replica_id_in_sync_group.

Важно: В зависимости от реализации tf.distribute.Strategy и включения режима eager execution, fn может быть вызван один или несколько раз (по одному разу для каждой реплики).
Аргументы
fn Функция для выполнения. Входные данные функции должны соответствовать выходным данным input_iterator.get_next(). Выход должен быть tf.nest из Tensor.
input_iterator (Необязательно) итератор входных данных, из которого берутся входные значения.
Возвращаемое значение
Объединённое возвращаемое значение fn по всем репликам. Структура возвращаемого значения такая же, как у возвращаемого значения от fn. Каждый элемент структуры может быть PerReplica (если значения не синхронизированы), Mirrored (если значения синхронизированы), или 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 по репликам и возвращает результат на текущем устройстве.

strategy = tf.distribute.MirroredStrategy(["GPU:0", "GPU:1"])
def step_fn():
  i = tf.distribute.get_replica_context().replica_id_in_sync_group
  return tf.identity(i)

per_replica_result = strategy.run(step_fn)
total = strategy.reduce("SUM", per_replica_result, axis=None)
total
<tf.Tensor: shape=(), dtype=int32, numpy=1>

Чтобы увидеть, как это будет выглядеть с несколькими репликами, рассмотрите тот же пример с MirroredStrategy на 2-ух GPU:

strategy = tf.distribute.MirroredStrategy(devices=["GPU:0", "GPU:1"])
def step_fn():
  i = tf.distribute.get_replica_context().replica_id_in_sync_group
  return tf.identity(i)

per_replica_result = strategy.run(step_fn)
# Check devices on which per replica result is:
strategy.experimental_local_results(per_replica_result)[0].device
# /job:localhost/replica:0/task:0/device:GPU:0
strategy.experimental_local_results(per_replica_result)[1].device
# /job:localhost/replica:0/task:0/device:GPU:1

total = strategy.reduce("SUM", per_replica_result, axis=None)
# Check device on which reduced result is:
total.device
# /job:localhost/replica:0/task:0/device:CPU:0

Этот API обычно используется для агрегирования результатов, возвращаемых различными репликами, например, для отчётов. Например, потерю, вычисленную различными репликами, можно усреднить с помощью этого API перед выводом.

Примечание: Результат копируется на "текущее" устройство — обычно это ЦПУ рабочего узла, на котором выполняется программа. Для TPUStrategy это первый хост TPU. Для многоклиентского MultiWorkerMirroredStrategy это ЦПУ каждого рабочего узла.

Существует ряд разных API tf.distribute для сведения значений по репликам:

  • tf.distribute.ReplicaContext.all_reduce: Отличается от Strategy.reduce тем, что предназначен для контекста реплики и не копирует результаты на устройство хоста. all_reduce обычно используется для операций сведения внутри шага обучения, таких как градиенты.
  • tf.distribute.StrategyExtended.reduce_to и tf.distribute.StrategyExtended.batch_reduce_to: Более расширенные версии Strategy.reduce, позволяющие настраивать место назначения результата. Также вызываются в межрепликационном контексте.

Что должно быть значением axis?

Учитывая значение на реплику, возвращаемое функцией run, например, потерю на пример, пакет будет разделен между всеми репликами. Эта функция позволяет агрегировать по репликам и, необязательно, по элементам пакета, указав параметр axis соответственно.

Например, если у вас глобальный размер пакета 8 и 2 реплики, значения для примеров [0, 1, 2, 3] будут на реплике 0, а [4, 5, 6, 7] на реплике 1. С помощью axis=None, reduce будет агрегировать только по репликам, возвращая [0+4, 1+5, 2+6, 3+7]. Это полезно, когда каждая реплика вычисляет скаляр или какое-либо другое значение без измерения «пакета» (например, градиент или потерю).

strategy.reduce("sum", per_replica_result, axis=None)

Иногда вы захотите агрегировать как по глобальному пакету, так и по всем репликам. Это можно получить, установив batch dimension как значение параметра axis, обычно axis=0. В этом случае он вернёт скаляр 0+1+2+3+4+5+6+7.

strategy.reduce("sum", per_replica_result, axis=0)

Если есть последний неполный пакет, вам необходимо указать axis, чтобы форма результата была согласована между репликами. Если последний пакет имеет размер 6 и разделён на [0, 1, 2, 3] и [4, 5], у вас будет несоответствие формы, если не указать axis=0. Если вы укажете tf.distribute.ReduceOp.MEAN, используя axis=0, будет использоваться правитель знаменатель 6. Противопоставьте это вычислению reduce_mean для получения скалярного значения на каждой реплике и этой функции для усреднения этих средних, что будет взвешивать некоторые значения 1/4 и другие 1/4.

Аргументы
reduce_op Значение tf.distribute.ReduceOp, определяющее, как следует объединять значения. Допускается использование строкового представления перечисления, например, "SUM", "MEAN".
value Объект tf.distribute.DistributedValues, например, возвращаемый функцией Strategy.run, который нужно объединить в один тензор. Также может быть обычный тензор, если используется с OneDeviceStrategy или стандартной стратегией.
axis Определяет размерность, по которой нужно выполнить сведение внутри тензора каждой реплики. Обычно нужно устанавливать значение dimension размерности пакета, или None для сведения только по репликам (например, если тензор не имеет размерности пакета).
Возвращаемое значение
Tensor.

run

Посмотреть исходный код

run(
    fn, args=(), kwargs=None, options=None
)

Вызывает fn на каждой реплике с указанными аргументами.

Этот метод является основным способом распределения вычислений с помощью объекта tf.distribute. Он вызывает fn на каждой реплике. Если args или kwargs содержат tf.distribute.DistributedValues, такие как те, которые создаются tf.distribute.DistributedDataset из tf.distribute.Strategy.experimental_distribute_dataset или tf.distribute.Strategy.distribute_datasets_from_function, при выполнении fn на конкретной реплике, оно будет выполнено с компонентом tf.distribute.DistributedValues, соответствующим этой реплике.

fn вызывается в контексте реплики. fn может вызвать tf.distribute.get_replica_context(), чтобы получить доступ к таким членам, как all_reduce. Обратитесь к документированию модуля tf.distribute для понятия контекста реплики.

Все аргументы в args или kwargs могут быть вложенной структурой тензоров, например, списком тензоров, в этом случае args и kwargs будут переданы в fn, вызываемый на каждой реплике. Или args или kwargs могут быть tf.distribute.DistributedValues, содержащими тензоры или составные тензоры, т.е. tf.compat.v1.TensorInfo.CompositeTensor, в этом случае каждый вызов fn получит компонент tf.distribute.DistributedValues, соответствующий своей реплике. Обратите внимание, что произвольные значения Python, не являющиеся указанными выше типами, не поддерживаются.

Важно: В зависимости от реализации tf.distribute.Strategy и включения режима eager execution, fn может быть вызван один или несколько раз. Если fn аннотирован с tf.function или вызывается tf.distribute.Strategy.run внутри tf.function (режим eager execution отключен внутри tf.function по умолчанию), fn вызывается один раз на реплику для генерации графа TensorFlow, который затем будет повторно использован для выполнения с новыми входными данными. В противном случае, если режим eager execution включен, fn будет вызываться один раз на каждую реплику на каждом шаге, как и обычный Python-код.

Пример использования:

  1. Входной тензор константы.

    strategy = tf.distribute.MirroredStrategy(["GPU:0", "GPU:1"])
    tensor_input = tf.constant(3.0)
    @tf.function
    def replica_fn(input):
      return input*2.0
    result = strategy.run(replica_fn, args=(tensor_input,))
    result
        PerReplica:{
          0: <tf.Tensor: shape=(), dtype=float32, numpy=6.0>,
          1: <tf.Tensor: shape=(), dtype=float32, numpy=6.0>
        }
        
  2. Входной DistributedValues.

    strategy = tf.distribute.MirroredStrategy(["GPU:0", "GPU:1"])
    @tf.function
    def run():
      def value_fn(value_context):
        return value_context.num_replicas_in_sync
      distributed_values = (
        strategy.experimental_distribute_values_from_function(
          value_fn))
      def replica_fn2(input):
        return input*2
      return strategy.run(replica_fn2, args=(distributed_values,))
    result = run()
    result
        <tf.Tensor: shape=(), dtype=int32, numpy=4>
        
  3. Использование tf.distribute.ReplicaContext для allreduce значений.

    strategy = tf.distribute.MirroredStrategy(["gpu:0", "gpu:1"])
    @tf.function
    def run():
       def value_fn(value_context):
         return tf.constant(value_context.replica_id_in_sync_group)
       distributed_values = (
           strategy.experimental_distribute_values_from_function(
               value_fn))
       def replica_fn(input):
         return tf.distribute.get_replica_context().all_reduce(
             "sum", input)
       return strategy.run(replica_fn, args=(distributed_values,))
    result = run()
    result
        PerReplica:{
          0: <tf.Tensor: shape=(), dtype=int32, numpy=1>,
          1: <tf.Tensor: shape=(), dtype=int32, numpy=1>
        }
        
Аргументы
fn Функция, выполняемая на каждой реплике.
args Необязательные позиционные аргументы для fn. Его элементы могут быть тензором, вложенной структурой тензоров или tf.distribute.DistributedValues.
kwargs Необязательные именованные аргументы для fn. Его элементы могут быть тензором, вложенной структурой тензоров или tf.distribute.DistributedValues.
options Необязательный экземпляр tf.distribute.RunOptions, определяющий параметры выполнения fn.
Возвращаемое значение
Объединенное возвращаемое значение fn по всем репликам. Структура возвращаемого значения такая же, как у возвращаемого значения fn. Каждый элемент структуры может быть tf.distribute.DistributedValues, объектами Tensor или тензорами Tensor (например, при выполнении на одной реплике).

scope

Посмотреть исходный код

scope()

Менеджер контекста, делающий стратегию текущей и распределяющий переменные.

Этот метод возвращает менеджер контекста и используется следующим образом:

strategy = tf.distribute.MirroredStrategy(["GPU:0", "GPU:1"])
# Variable created inside scope:
with strategy.scope():
  mirrored_variable = tf.Variable(1.)
mirrored_variable
MirroredVariable:{
  0: <tf.Variable 'Variable:0' shape=() dtype=float32, numpy=1.0>,
  1: <tf.Variable 'Variable/replica_1:0' shape=() dtype=float32, numpy=1.0>
}
# Variable created outside scope:
regular_variable = tf.Variable(1.)
regular_variable
<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=1.0>

Что происходит при входе в Strategy.scope?

  • strategy устанавливается в глобальный контекст как текущая стратегия. Внутри этого области tf.distribute.get_strategy() теперь вернёт эту стратегию. За пределами этой области она возвращает стратегию по умолчанию (без операций).
  • Вход в область также означает вход в "межрепликационный контекст". См. tf.distribute.StrategyExtended для объяснения межрепликационного и репликационного контекстов.
  • Создание переменных внутри scope перехватывается стратегией. Каждая стратегия определяет, как она хочет повлиять на создание переменных. Синхронные стратегии, такие как MirroredStrategy, TPUStrategy и MultiWorkerMiroredStrategy, создают переменные, дублированные на каждой реплике, в то время как ParameterServerStrategy создаёт переменные на серверах параметров. Это выполняется с помощью настраиваемого tf.variable_creator_scope.
  • В некоторых стратегиях также может быть введён контекст устройства по умолчанию: в MultiWorkerMiroredStrategy в каждой рабочей машине вводится контекст устройства по умолчанию "/CPU:0".
Примечание: Вход в область не автоматически распределяет вычисление, за исключением случаев использования высокоуровневых фреймворков обучения, таких как Keras model.fit. Если вы не используете model.fit, вам необходимо использовать API strategy.run для явного распределения этого вычисления. См. пример в учебнике по пользовательскому циклу обучения .

Что должно быть в области, а что вне её?

Существует ряд требований к тому, что должно происходить внутри области. Однако в местах, где у нас есть информация о используемой стратегии, мы часто входим в область за пользователя, чтобы он не должен был делать это явно (т.е. вызов внутри или вне области допустим).

  • Все, что создаёт переменные, которые должны быть распределёнными переменными, должно вызываться в strategy.scope. Это можно сделать, либо напрямую вызвав функцию создания переменных в контексте области, либо полагаясь на другой API, такой как strategy.run или keras.Model.fit для автоматического входа в него. Любая переменная, созданная вне области, не будет распределена и может повлиять на производительность. Некоторые распространённые объекты, создающие переменные в TF, — это модели, оптимизаторы, метрики. Такие объекты всегда должны быть инициализированы в области, а все функции, которые могут лениво создавать переменные (например, Model.call(), отслеживание tf.function и т. д.), должны аналогичным образом вызываться внутри области. Другим источником создания переменных может быть восстановление контрольной точки — когда переменные создаются лениво. Обратите внимание, что любая переменная, созданная внутри стратегии, сохраняет информацию о стратегии. Таким образом, чтение и запись этих переменных вне strategy.scope также могут работать без проблем, без необходимости ввода пользователем области.
  • Некоторые API стратегии (например, strategy.run и strategy.reduce), которые требуют нахождения в области стратегии, автоматически входят в область, что означает, что при использовании этих API вам не нужно явно вводить область.
  • Когда tf.keras.Model создаётся внутри strategy.scope, объект модели сохраняет информацию о области. Когда вызываются методы высокоуровневых фреймворков обучения, такие как model.compile, model.fit и т. д., пойманная область будет автоматически введена, и связанная стратегия будет использована для распределения обучения и т. д. См. подробный пример в учебнике по распределённому Keras. ПРЕДУПРЕЖДЕНИЕ: простой вызов model(..) не приводит к автоматическому вводу пойманной области — только API высокоуровневых фреймворков обучения поддерживают это поведение: model.compile, model.fit, model.evaluate, model.predict и model.save могут быть вызваны внутри или вне области.
  • Следующее может быть как внутри, так и вне области:
    • Создание наборов данных для входа
    • Определение tf.function которые представляют ваш шаг обучения
    • API сохранения, такие как tf.saved_model.save. Загрузка создаёт переменные, поэтому это должно выполняться внутри области, если вы хотите обучить модель в распределённом режиме.
    • Сохранение контрольных точек. Как упоминалось выше — checkpoint.restore иногда может потребоваться находиться в области, если оно создаёт переменные.
Возвращаемое значение
Менеджер контекста.

update_config_proto

Посмотреть исходный код

update_config_proto(
    config_proto
)

Возвращает копию config_proto, модифицированную для использования с этой стратегией.

Устарело: Этот метод недоступен в TF 2.x.

Обновлённая конфигурация содержит необходимые элементы для работы стратегии, например, конфигурацию для запуска коллективных операций или фильтры устройств для повышения производительности распределённого обучения.

Аргументы
config_proto Объект tf.ConfigProto.
Возвращаемое значение
Обновлённая копия config_proto.

© 2022 The TensorFlow Authors. All rights reserved.
Licensed under the Creative Commons Attribution License 4.0.
Code samples licensed under the Apache 2.0 License.
https://www.tensorflow.org/api_docs/python/tf/compat/v1/distribute/MirroredStrategy

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API