Spec-Zone.ru › TensorFlow

tf.compat.v1.distribute.OneDeviceStrategy

Стратегия распределения для выполнения на одном устройстве.

Наследует: Strategy

tf.compat.v1.distribute.OneDeviceStrategy(
    device
)

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

Эту стратегию можно использовать, например, для проверки кода с помощью API tf.distribute.Strategy перед переходом к другим стратегиям, которые действительно распределяют вычисления между несколькими устройствами или машинами.

Например:

tf.enable_eager_execution()
strategy = tf.distribute.OneDeviceStrategy(device="/gpu:0")

with strategy.scope():
  v = tf.Variable(1.0)
  print(v.device)  # /job:localhost/replica:0/task:0/device:GPU:0

def step_fn(x):
  return x * 2

result = 0
for i in range(10):
  result += strategy.run(step_fn, args=(i,))
print(result)  # 90
Аргументы
device Строковый идентификатор устройства, на котором следует разместить переменные. Дополнительные сведения об использовании устройства см. в документации класса. Примеры: "/cpu:0", "/gpu:0", "/device:CPU:0", "/device:GPU:0"
Атрибуты
cluster_resolver Возвращает сопоставитель кластера, связанный с этой стратегией.

Как правило, при использовании стратегии tf.distribute с несколькими рабочими узлами, такой как 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 будет вызвана на устройстве ЦП каждого рабочего узла; каждая такая функция создаёт набор данных, из которого каждая реплика этого рабочего узла извлекает по одному пакету входных данных (то есть, если у рабочего узла две реплики, на каждом шаге из Dataset будут извлечены два пакета).

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

Функция dataset_fn должна принимать экземпляр tf.distribute.InputContext, содержащий сведения о формировании пакетов и репликации входных данных.

С помощью свойства element_spec у возвращённого этим API объекта tf.distribute.DistributedDataset можно получить 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, используемый для управления параметрами распределения этого набора данных.
Возвращает
Объект 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 в стиле Python. 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, используемый для управления параметрами распределения этого набора данных.
Возвращает
Объект 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.

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

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

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

Важно: В зависимости от используемой реализации tf.distribute.Strategy и от того, включено ли немедленное выполнение, 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)

Размер пакета на реплику у возвращаемого функцией input_fn объекта tf.data.Dataset может быть вычислен с помощью 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 и двумя графическими процессорами:

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 с несколькими клиентами это ЦП каждого рабочего узла.

В tf.distribute есть несколько API для сведения значений по репликам:

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

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

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

Например, если глобальный размер пакета равен 8, а реплик две, значения для примеров [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)

Иногда требуется выполнить агрегирование и по всему глобальному пакету, и по всем репликам. Для этого задайте измерение пакета в качестве 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/8, а другие — 1/4.

Аргументы
reduce_op значение tf.distribute.ReduceOp, указывающее, как следует объединять значения. Позволяет использовать строковое представление перечисления, например "SUM", "MEAN".
value экземпляр tf.distribute.DistributedValues, например возвращённый Strategy.run, который нужно объединить в один тензор. Также может быть обычным тензором при использовании с OneDeviceStrategy или стратегией по умолчанию.
axis задаёт измерение, по которому нужно выполнить свёртку в тензоре каждой реплики. Обычно следует задавать измерение пакета или 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-выполнение, fn может вызываться один или несколько раз. Если для fn указана аннотация tf.function или tf.distribute.Strategy.run вызывается внутри tf.function (по умолчанию внутри tf.function eager-выполнение отключено), fn вызывается один раз для каждой реплики, чтобы создать граф TensorFlow, который затем будет повторно использоваться при выполнении с новыми входными данными. В противном случае, если eager-выполнение включено, 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 для выполнения all-reduce значений.

    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, который автоматически войдёт в неё. Переменные, созданные за пределами области, не будут распределёнными, что может повлиять на производительность. К распространённым объектам TensorFlow, создающим переменные, относятся модели, оптимизаторы и метрики. Такие объекты всегда следует инициализировать в области; любые функции, которые могут создавать переменные отложенно (например, Model.call(), трассировка tf.function и т. д.), также следует вызывать внутри области. Переменные могут создаваться и при восстановлении контрольной точки, если это происходит отложенно. Обратите внимание, что любая переменная, созданная внутри стратегии, сохраняет информацию о стратегии. Поэтому чтение и запись таких переменных за пределами strategy.scope также могут выполняться без проблем, и пользователю не нужно входить в область.
  • Некоторые API стратегии (например, strategy.run и strategy.reduce), для которых требуется находиться в области стратегии, автоматически входят в неё. Это значит, что при использовании этих API явно входить в область не нужно.
  • Когда tf.keras.Model создаётся внутри strategy.scope, объект Model сохраняет информацию об области. При последующем вызове методов высокоуровневой обучающей платформы, таких как 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/OneDeviceStrategy

Spec-Zone.ru

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