tf.compat.v1.distribute.experimental.ParameterServerStrategy
Асинхронная стратегия tf.distribute с несколькими рабочими узлами и сервером параметров.
Наследуется от: Strategy
tf.compat.v1.distribute.experimental.ParameterServerStrategy(
cluster_resolver=None
)
Для этой стратегии требуются две роли: рабочие узлы и серверы параметров. Переменные и обновления этих переменных назначаются серверам параметров, а остальные операции — рабочим узлам.
Если на каждом рабочем узле установлено несколько графических процессоров, операции будут реплицироваться на всех графических процессорах. Хотя операции могут реплицироваться, переменные не реплицируются, и на каждом рабочем узле используется общее представление о том, какому серверу параметров назначена переменная.
По умолчанию для обнаружения конфигураций обучения на нескольких рабочих узлах используется TFConfigClusterResolver. Для этого требуется переменная окружения 'TF_CONFIG', которая должна содержать спецификацию кластера.
Этот класс предполагает, что каждый рабочий узел независимо выполняет один и тот же код, а серверы параметров запускают стандартный сервер. Это означает, что каждый рабочий узел синхронно вычисляет одно обновление градиента на всех графических процессорах, но обновления между рабочими узлами выполняются асинхронно. Операции, выполняемые только на первой реплике (например, увеличение глобального шага), будут выполняться на первой реплике каждого рабочего узла.
Ожидается, что для любых операций, которые потенциально могут реплицироваться между репликами (то есть между несколькими графическими процессорами), будет вызываться call_for_each_replica(fn, ...), даже если имеется только центральный процессор или один графический процессор. При определении fn необходимо соблюдать особую осторожность:
1) Как правило, не рекомендуется открывать область устройства в области стратегии. Область устройства (то есть вызов tf.device) объединяется с назначением устройства для операций или переопределяет его, но не изменяет устройство для переменных.
2) Также не рекомендуется открывать область совместного размещения (то есть вызывать tf.compat.v1.colocate_with) в области стратегии. Для совместного размещения переменных используйте вместо этого strategy.extended.colocate_vars_with. Совместное размещение операций может привести к конфликтам при назначении устройств.
Примечание: Эта стратегия работает только с API Estimator. Передайте экземпляр этой стратегии аргументуexperimental_distributeпри созданииRunConfig. Затем этот экземплярRunConfigследует передать экземпляруEstimator, для которого вызываетсяtrain_and_evaluate.
Например:
strategy = tf.distribute.experimental.ParameterServerStrategy()
run_config = tf.estimator.RunConfig(
experimental_distribute.train_distribute=strategy)
estimator = tf.estimator.Estimator(config=run_config)
tf.estimator.train_and_evaluate(estimator,...)
| Аргументы | |
|---|---|
cluster_resolver | Необязательный объект tf.distribute.cluster_resolver.ClusterResolver. По умолчанию используется tf.distribute.cluster_resolver.TFConfigClusterResolver. |
| Атрибуты | |
|---|---|
cluster_resolver | Возвращает сопоставитель кластера, связанный с этой стратегией. Как правило, при использовании стратегии Стратегии, которым требуется связанный Стратегии с одним рабочим узлом обычно не имеют
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 для |
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 объекта tf.distribute.DistributedDataset, возвращаемого этим API, можно получить tf.TypeSpec элементов, возвращаемых итератором. Это можно использовать для настройки свойства input_signature объекта tf.function. Пример см. в разделе tf.distribute.DistributedDataset.element_spec.
Примечание: При использовании 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. (Устарел.)
Если включено 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 (при выполнении на одной реплике). |
make_dataset_iterator
make_dataset_iterator(
dataset
)
Создаёт итератор для входных данных, предоставленных через dataset.
Данные из указанного набора данных будут равномерно распределены между всеми вычислительными репликами. Предполагается, что входной набор данных разбит на пакеты глобального размера. Исходя из этого предположения, будет предпринята попытка распределить каждый пакет между всеми репликами (на одном или нескольких рабочих узлах). Если это не удастся, будет выдана ошибка. В таком случае вместо этого следует использовать 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
)
Возвращает распределённый между репликами итератор, созданный на основе входной функции.
Функция 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 и двумя графическими процессорами:
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, а реплик 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)
Иногда требуется выполнить агрегирование и по глобальному пакету, и по всем репликам. Для этого укажите измерение пакета в качестве axis, обычно axis=0. В этом случае будет возвращено скалярное значение 0+1+2+3+4+5+6+7.
strategy.reduce("sum", per_replica_result, axis=0)
Если последний пакет неполный, необходимо указать ось, чтобы результирующая форма была одинаковой для всех реплик. Например, если размер последнего пакета равен 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, не относящиеся к перечисленным выше типам, не поддерживаются.
Пример использования:
-
Входные данные — константный тензор.
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> } -
Входные данные — 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> -
Использование
tf.distribute.ReplicaContextдля выполнения всесокращения значений.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".
Примечание: Вход в область не приводит к автоматическому распределению вычислений, за исключением высокоуровневых обучающих сред, таких как kerasmodel.fit. Если вы не используетеmodel.fit, для явного распределения вычислений необходимо использовать APIstrategy.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, измененную для использования с этой стратегией.
Обновленная конфигурация содержит необходимые для работы стратегии параметры, например настройки для запуска коллективных операций или фильтры устройств, повышающие производительность распределенного обучения.
| Аргументы | |
|---|---|
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/experimental/ParameterServerStrategy