tf.compat.v1.distribute.experimental.ParameterServerStrategy
Асинхронная стратегия tf.distribute для многоузлового сервера параметров.
Наследуется от: Strategy
tf.compat.v1.distribute.experimental.ParameterServerStrategy(
cluster_resolver=None
)
Эта стратегия требует двух ролей: рабочих узлов и серверов параметров. Переменные и обновления этих переменных будут назначены серверам параметров, а другие операции — рабочим узлам.
Когда каждый рабочий узел имеет более одного графического процессора, операции будут дублироваться на всех графических процессорах. Несмотря на то, что операции могут дублироваться, переменные не дублируются, и каждый рабочий узел имеет общий вид, для которого серверу параметров назначена переменная.
По умолчанию используется TFConfigClusterResolver для определения конфигураций для многоузлового обучения. Это требует переменной среды 'TF_CONFIG', и '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 будет вызываться на процессоре CPU каждого рабочего узла, и каждый создает набор данных, где каждая реплика на этом рабочем узле будет извлекать одну партию входных данных (т. е. если рабочий узел имеет две реплики, две партии будут извлекаться из 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 для примера.
Примечание: Если вы используете 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. 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(), extended.call_for_each_replica(), или переменной, созданной в scope. |
| Возвращаемое значение | |
|---|---|
Кортеж значений, содержащихся в value. Если value представляет собой единственное значение, это возвращает (value,). |
experimental_make_numpy_dataset
experimental_make_numpy_dataset(
numpy_input, session=None
)
Создаёт tf.data.Dataset для входных данных, предоставленных через массив NumPy.
Это позволяет избежать добавления numpy_input как большого константы в граф и копирует данные на машину или машины, которые будут обрабатывать входные данные.
Обратите внимание, что вам, вероятно, потребуется использовать tf.distribute.Strategy.experimental_distribute_dataset с возвращаемым набором данных для дальнейшего распределения его с помощью стратегии.
Пример:
numpy_input = np.ones([10], dtype=np.float32) dataset = strategy.experimental_make_numpy_dataset(numpy_input) dist_dataset = strategy.experimental_distribute_dataset(dataset)
| Аргументы | |
|---|---|
numpy_input | Вложенный массив NumPy входных данных, который будет преобразован в набор данных. Обратите внимание, что списки массивов NumPy складываются, так как это обычное поведение tf.data.Dataset. |
session | (Только для выполнения графа TensorFlow v1.x) Сессия, используемая для инициализации. |
| Возвращаемое значение | |
|---|---|
tf.data.Dataset, представляющий numpy_input. |
experimental_run
experimental_run(
fn, input_iterator=None
)
Выполняет операции в fn на каждой реплике с входными данными из input_iterator.
УСТАРЕЛО: Этот метод недоступен в TF 2.x. Пожалуйста, переключитесь на использование run вместо этого.
При включённом режиме выполнения Eager выполняет операции, указанные в fn на каждой реплике. В противном случае создаёт граф для выполнения операций на каждой реплике.
Каждая реплика получит одиночные, разные входные данные из входных данных, предоставленных одним вызовом get_next на итераторе входных данных.
fn может вызвать tf.distribute.get_replica_context() для доступа к элементам, таким как replica_id_in_sync_group.
| Аргументы | |
|---|---|
fn | Функция для выполнения. Входные данные функции должны соответствовать выходным данным input_iterator.get_next(). Выходные данные должны быть вложенным tf.nest Tensors. |
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 для возвращенного итератора. |
data-text="make_input_fn_iterator" id="make_input_fn_iterator">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() или получить следующее значение для передачи в strategy.extended.call_for_each_replica() с помощью iterator.get_next(). |
data-text="reduce" id="reduce">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 графическими процессорами:
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: Эти API являются более сложными версиямиStrategy.reduce, поскольку позволяют настраивать место назначения результата. Они также вызываются в контексте между репликами.
Каким должен быть ось?
Учитывая значение на реплику, возвращаемое 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=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. |
data-text="run" id="run">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 должны быть либо Python-значениями вложенной структуры тензоров, например, список тензоров, в этом случае args и kwargs будут переданы в вызов fn для каждой реплики. Либо args или kwargs могут быть tf.distribute.DistributedValues содержащими тензоры или составные тензоры, т.е. tf.compat.v1.TensorInfo.CompositeTensor, в этом случае каждый вызов fn получит компонент tf.distribute.DistributedValues, соответствующий его реплике.
data-text="Example usage:" id="example_usage">Пример использования:
- Входной тензор с константой.
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для 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. Его элемент может быть значением Python, тензором или tf.distribute.DistributedValues. |
kwargs | Необязательные именованные аргументы для fn. Его элемент может быть значением Python, тензором или 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илиmodel.fitдля автоматического входа в него. Любая переменная, созданная вне области видимости, не будет распределена и может привести к снижению производительности. Типичные действия, создающие переменные в TF: модели, оптимизаторы, метрики. Они всегда должны создаваться внутри области видимости. Другим источником создания переменных может быть восстановление контрольной точки — когда переменные создаются лениво. Обратите внимание, что любая переменная, созданная внутри стратегии, фиксирует информацию о стратегии. Поэтому чтение и запись этих переменных вне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. |
© 2020 The TensorFlow Authors. All rights reserved.
Licensed under the Creative Commons Attribution License 3.0.
Code samples licensed under the Apache 2.0 License.
https://www.tensorflow.org/versions/r2.4/api_docs/python/tf/compat/v1/distribute/experimental/ParameterServerStrategy