tf.distribute.experimental.CentralStorageStrategy
Стратегия для одной машины, которая размещает все переменные на одном устройстве.
Наследуется от: Strategy
tf.distribute.experimental.CentralStorageStrategy(
compute_devices=None, parameter_device=None
)
Используется в блокнотах
| Используется в руководстве |
|---|
Переменные назначаются локальному ЦП или единственному графическому процессору. Если графических процессоров несколько, вычислительные операции (за исключением операций обновления переменных) будут выполняться на всех графических процессорах.
Например:
strategy = tf.distribute.experimental.CentralStorageStrategy()
# Create a dataset
ds = tf.data.Dataset.range(5).batch(2)
# Distribute that dataset
dist_dataset = strategy.experimental_distribute_dataset(ds)
with strategy.scope():
@tf.function
def train_step(val):
return val + 1
# Iterate over the distributed dataset
for x in dist_dataset:
# process dataset elements
strategy.run(train_step, args=(x,))
| Атрибуты | |
|---|---|
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.data.Dataset, переданный через dataset.
Возвращаемый набор данных — это обёрнутый набор данных стратегии, который под капотом создаёт многодевайсный итератор. Он предварительно загружает входные данные на указанные устройства рабочего узла. Возвращаемый распределённый набор данных можно перебирать так же, как обычные наборы данных.
Примечание: В настоящее время пользователь не может добавлять другие преобразования к распределённому набору данных.
Например:
strategy = tf.distribute.CentralStorageStrategy() # with 1 CPU and 1 GPU dataset = tf.data.Dataset.range(10).batch(2) dist_dataset = strategy.experimental_distribute_dataset(dataset) for x in dist_dataset: print(x) # Prints PerReplica values [0, 1], [2, 3],...
Аргументы: dataset: набор данных tf.data.Dataset, который нужно предварительно загрузить на устройство. options: tf.distribute.InputOptions, используемый для управления параметрами распределения этого набора данных.
| Возвращает | |
|---|---|
«Распределённый Dataset», который вызывающий код может перебирать. |
experimental_distribute_values_from_function
experimental_distribute_values_from_function(
value_fn
)
Создаёт tf.distribute.DistributedValues из value_fn.
Эта функция предназначена для создания tf.distribute.DistributedValues, передаваемых в run, reduce или другие методы, принимающие распределённые значения, при использовании без наборов данных.
| Аргументы | |
|---|---|
value_fn | Функция для создания значений. Она вызывается для каждой реплики, а единственным аргументом ей передаётся tf.distribute.ValueContext. Она должна возвращать Tensor или тип, который можно преобразовать в Tensor. |
| Возвращает | |
|---|---|
Объект tf.distribute.DistributedValues, содержащий значение для каждой реплики. |
Примеры использования:
-
Возврат константного значения для каждой реплики:
strategy = tf.distribute.MirroredStrategy(["GPU:0", "GPU:1"]) def value_fn(ctx): return tf.constant(1.) distributed_values = ( strategy.experimental_distribute_values_from_function( value_fn)) local_result = strategy.experimental_local_results( distributed_values) local_result (<tf.Tensor: shape=(), dtype=float32, numpy=1.0>, <tf.Tensor: shape=(), dtype=float32, numpy=1.0>) -
Распределение значений в массиве на основе replica_id:
strategy = tf.distribute.MirroredStrategy(["GPU:0", "GPU:1"]) array_value = np.array([3., 2., 1.]) def value_fn(ctx): return array_value[ctx.replica_id_in_sync_group] distributed_values = ( strategy.experimental_distribute_values_from_function( value_fn)) local_result = strategy.experimental_local_results( distributed_values) local_result (3.0, 2.0) -
Указание значений с помощью num_replicas_in_sync:
strategy = tf.distribute.MirroredStrategy(["GPU:0", "GPU:1"]) def value_fn(ctx): return ctx.num_replicas_in_sync distributed_values = ( strategy.experimental_distribute_values_from_function( value_fn)) local_result = strategy.experimental_local_results( distributed_values) local_result (2, 2) -
Размещение значений на устройствах и их распределение:
strategy = tf.distribute.TPUStrategy() worker_devices = strategy.extended.worker_devices multiple_values = [] for i in range(strategy.num_replicas_in_sync): with tf.device(worker_devices[i]): multiple_values.append(tf.constant(1.0)) def value_fn(ctx): return multiple_values[ctx.replica_id_in_sync_group] distributed_values = strategy. experimental_distribute_values_from_function( value_fn)
experimental_local_results
experimental_local_results(
value
)
Возвращает список всех локальных значений для реплик, содержащихся в value.
В CentralStorageStrategy есть только один рабочий узел, поэтому возвращаемое значение будет содержать все значения этого рабочего узла.
| Аргументы | |
|---|---|
value | Значение, возвращённое run(), extended.call_for_each_replica() или переменная, созданная в scope. |
| Возвращает | |
|---|---|
Кортеж значений, содержащихся в value. Если value представляет одно значение, возвращается (value,). |
gather
gather(
value, axis
)
Собирает value с разных реплик вдоль axis на текущем устройстве.
Для объекта tf.distribute.DistributedValues или объекта, подобного tf.Tensor, value этот API собирает и объединяет конкатенацией value с разных реплик вдоль измерения axis. Результат копируется на «текущее» устройство, которым обычно является ЦП рабочего узла, на котором выполняется программа. Для tf.distribute.TPUStrategy это первый хост TPU. Для многоклиентской tf.distribute.MultiWorkerMirroredStrategy это ЦП каждого рабочего узла.
Этот API можно вызывать только в контексте между репликами. Аналог для контекста реплики см. в разделе tf.distribute.ReplicaContext.all_gather.
Примечание: Для всех стратегий, кромеtf.distribute.TPUStrategy, входное значениеvalueна разных репликах должно иметь одинаковый ранг, а их формы должны совпадать по всем измерениям, кроме измеренияaxis-й размерности. Иными словами, формы не могут различаться в измеренииd, гдеdне равно аргументуaxis. Например, если объектtf.distribute.DistributedValuesсодержит тензоры-компоненты формы(1, 2, 3)и(1, 3, 3)на двух репликах, для него можно вызватьgather(..., axis=1, ...), но нельзяgather(..., axis=0, ...)илиgather(..., axis=2, ...). Однако дляtf.distribute.TPUStrategy.gatherвсе тензоры должны иметь совершенно одинаковый ранг и форму.
Примечание: У объектаtf.distribute.DistributedValuesvalueтензоры-компоненты должны иметь ненулевой ранг. В противном случае перед сбором рассмотрите возможность использованияtf.expand_dims.
strategy = tf.distribute.MirroredStrategy(["GPU:0", "GPU:1"])
# A DistributedValues with component tensor of shape (2, 1) on each replica
distributed_values = strategy.experimental_distribute_values_from_function(lambda _: tf.identity(tf.constant([[1], [2]])))
@tf.function
def run():
return strategy.gather(distributed_values, axis=0)
run()
<tf.Tensor: shape=(4, 1), dtype=int32, numpy=
array([[1],
[2],
[1],
[2]], dtype=int32)>Дополнительные сочетания рассмотрены в следующем примере:
strategy = tf.distribute.MirroredStrategy(["GPU:0", "GPU:1", "GPU:2", "GPU:3"])
single_tensor = tf.reshape(tf.range(6), shape=(1,2,3))
distributed_values = strategy.experimental_distribute_values_from_function(lambda _: tf.identity(single_tensor))
@tf.function
def run(axis):
return strategy.gather(distributed_values, axis=axis)
axis=0
run(axis)
<tf.Tensor: shape=(4, 2, 3), dtype=int32, numpy=
array([[[0, 1, 2],
[3, 4, 5]],
[[0, 1, 2],
[3, 4, 5]],
[[0, 1, 2],
[3, 4, 5]],
[[0, 1, 2],
[3, 4, 5]]], dtype=int32)>
axis=1
run(axis)
<tf.Tensor: shape=(1, 8, 3), dtype=int32, numpy=
array([[[0, 1, 2],
[3, 4, 5],
[0, 1, 2],
[3, 4, 5],
[0, 1, 2],
[3, 4, 5],
[0, 1, 2],
[3, 4, 5]]], dtype=int32)>
axis=2
run(axis)
<tf.Tensor: shape=(1, 2, 12), dtype=int32, numpy=
array([[[0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2],
[3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5]]], dtype=int32)>| Аргументы | |
|---|---|
value | Экземпляр tf.distribute.DistributedValues, например возвращённый методом Strategy.run, который нужно объединить в один тензор. При использовании с tf.distribute.OneDeviceStrategy или стратегией по умолчанию также может быть обычным тензором. Тензоры, составляющие DistributedValues, могут быть только плотными тензорами ненулевого ранга, но не объектами tf.IndexedSlices. |
axis | Тензор int32 нулевой размерности. Измерение, вдоль которого выполняется сбор. Должно находиться в диапазоне [0, rank(value)). |
| Возвращает | |
|---|---|
Tensor, представляющий конкатенацию value между репликами вдоль измерения axis. |
reduce
reduce(
reduce_op, value, axis
)
Выполняет редукцию value между репликами.
Для значения на реплику, возвращённого методом run, например потерь на примере, пакет распределяется между всеми репликами. Эта функция позволяет выполнять агрегацию между репликами и, при необходимости, также между элементами пакета. Например, если глобальный размер пакета равен 8, а реплик две, значения для примеров [0, 1, 2, 3] будут находиться на реплике 0, а [4, 5, 6, 7] — на реплике 1. По умолчанию reduce будет выполнять агрегацию только между репликами и возвращать [0+4, 1+5, 2+6, 3+7]. Это удобно, когда каждая реплика вычисляет скалярное или другое значение без измерения «пакета» (например, градиент). Чаще требуется агрегировать значения по глобальному пакету; для этого укажите измерение пакета в качестве axis, обычно axis=0. В этом случае будет возвращён скаляр 0+1+2+3+4+5+6+7.
Если последний пакет неполный, необходимо указать ось, чтобы результирующая форма была одинаковой для всех реплик. Например, если последний пакет содержит 6 элементов и разделён на [0, 1, 2, 3] и [4, 5], без указания axis=0 возникнет несовпадение форм. Если указать tf.distribute.ReduceOp.MEAN, использование axis=0 позволит применить правильный знаменатель — 6. Сравните это с вычислением reduce_mean для получения скалярного значения на каждой реплике и последующим усреднением этих средних с помощью этой функции: в таком случае некоторые значения будут иметь вес 1/8, а другие — 1/4.
Например:
strategy = tf.distribute.experimental.CentralStorageStrategy(
compute_devices=['CPU:0', 'GPU:0'], parameter_device='CPU:0')
ds = tf.data.Dataset.range(10)
# Distribute that dataset
dist_dataset = strategy.experimental_distribute_dataset(ds)
with strategy.scope():
@tf.function
def train_step(val):
# pass through
return val
# Iterate over the distributed dataset
for x in dist_dataset:
result = strategy.run(train_step, args=(x,))
result = strategy.reduce(tf.distribute.ReduceOp.SUM, result,
axis=None).numpy()
# result: array([ 4, 6, 8, 10])
result = strategy.reduce(tf.distribute.ReduceOp.SUM, result, axis=0).numpy()
# result: 28
| Аргументы | |
|---|---|
reduce_op | Значение tf.distribute.ReduceOp, указывающее, как следует объединять значения. |
value | Значение «на реплику», например возвращённое методом run, которое нужно объединить в один тензор. |
axis | Задаёт измерение, вдоль которого выполняется редукция в тензоре каждой реплики. Обычно следует указывать измерение пакета или None, чтобы выполнять редукцию только между репликами (например, если у тензора нет измерения пакета). |
| Возвращает | |
|---|---|
Объект Tensor. |
run
run(
fn, args=(), kwargs=None, options=None
)
Выполняет fn на каждой реплике с указанными аргументами.
В CentralStorageStrategy функция fn вызывается для каждой вычислительной реплики с переданными аргументами «на реплику», соответствующими конкретному устройству.
| Аргументы | |
|---|---|
fn | Выполняемая функция. Результатом должен быть объект tf.nest, состоящий из Tensor. |
args | (Необязательно) Позиционные аргументы для fn. |
kwargs | (Необязательно) Именованные аргументы для fn. |
options | (Необязательно) Экземпляр tf.distribute.RunOptions, задающий параметры выполнения fn. |
| Возвращает | |
|---|---|
Значение, возвращаемое при выполнении fn. |
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, который автоматически войдёт в неё. Переменные, созданные за пределами области действия, не будут распределены, что может повлиять на производительность. Некоторые распространённые объекты TF, создающие переменные: модели, оптимизаторы и метрики. Такие объекты всегда следует инициализировать в области действия; функции, которые могут создавать переменные с задержкой (например,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необходимо выполнять внутри области действия, если при этом создаются переменные.
| Возвращает | |
|---|---|
| Менеджер контекста. |
© 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/distribute/experimental/CentralStorageStrategy