tf.compat.v1.distribute.experimental.CentralStorageStrategy
Стратегия для одной машины, которая размещает все переменные на одном устройстве.
Наследуется от: Strategy
tf.compat.v1.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
)
Распределяет экземпляры наборов данных, созданные вызовами dataset_fn.
Передаваемая пользователем переменная dataset_fn — это функция ввода, имеющая аргумент tf.distribute.InputContext и возвращающая экземпляр набора данных. Ожидается, что возвращаемый набор данных из dataset_fn уже разбит на пакеты по размеру пакета на реплику (т. е. глобальный размер пакета, деленный на количество реплик в синхронизации) и поделен. tf.distribute.Strategy.distribute_datasets_from_function не разбивает и не делит экземпляр набора данных, возвращаемый функцией ввода. 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 для примера.
Примечание: Если вы используете 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, выполняемым на каждой реплике.
Разбиение данных (sharding) включает в себя автоматическое разбиение (autosharding) по нескольким рабочим узлам и внутри каждого рабочего узла. Во-первых, при распределённом обучении на нескольких рабочих узлах (т.е. когда вы используете tf.distribute.experimental.MultiWorkerMirroredStrategy или tf.distribute.TPUStrategy), автоматическое разбиение набора данных по рабочим узлам означает, что каждому рабочему узлу назначается подмножество всего набора данных (если задан соответствующий tf.data.experimental.AutoShardPolicy). Это гарантирует, что на каждом шаге глобальный размер пакета (batch size) из неперекрывающихся элементов набора данных будет обрабатываться каждым рабочим узлом. Автоматическое разбиение имеет несколько различных вариантов, которые можно указать, используя 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.
По умолчанию этот метод добавляет преобразование prefetch в конец предоставленного пользователем объекта tf.data.Dataset. Аргумент преобразования prefetch, который является 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 на возвращенном итераторе. |
data-text="make_input_fn_iterator" id="make_input_fn_iterator" tabindex="-1">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(). |
data-text="reduce" id="reduce" tabindex="-1">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, например, потерю на пример, пакет будет разделен между всеми репликами. Эта функция позволяет агрегировать по репликам и необязательно также по элементам пакета, указав параметр оси соответственно.
Например, если у вас есть глобальный размер пакета 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. |
data-text="run" id="run" tabindex="-1">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для allreduce значений.strategy = tf.distribute.MirroredStrategy(["gpu:0", "gpu:1"]) @tf.function def run(): def value_fn(value_context): return tf.constant(value_context.replica_id_in_sync_group) distributed_values = ( strategy.experimental_distribute_values_from_function( value_fn)) def replica_fn(input): return tf.distribute.get_replica_context().all_reduce( "sum", input) return strategy.run(replica_fn, args=(distributed_values,)) result = run() result PerReplica:{ 0: <tf.Tensor: shape=(), dtype=int32, numpy=1>, 1: <tf.Tensor: shape=(), dtype=int32, numpy=1> }
| Аргументы | |
|---|---|
fn | Функция, выполняемая на каждой реплике. |
args | Необязательные позиционные аргументы для fn. Его элемент может быть тензором, вложенной структурой тензоров или tf.distribute.DistributedValues. |
kwargs | Необязательные именованные аргументы для fn. Его элемент может быть тензором, вложенной структурой тензоров или tf.distribute.DistributedValues. |
options | Необязательный экземпляр tf.distribute.RunOptions, определяющий параметры запуска fn. |
| Возвращаемые значения | |
|---|---|
Объединенное возвращаемое значение fn по всем репликам. Структура возвращаемого значения такая же, как возвращаемое значение от fn. Каждый элемент структуры может быть tf.distribute.DistributedValues, объектами Tensor или Tensor (например, при выполнении на одной реплике). |
scope
scope()
Менеджер контекста для установки стратегии по умолчанию и распределения переменных.
Этот метод возвращает менеджер контекста и используется следующим образом:
strategy = tf.distribute.MirroredStrategy(["GPU:0", "GPU:1"])
# Variable created inside scope:
with strategy.scope():
mirrored_variable = tf.Variable(1.)
mirrored_variable
MirroredVariable:{
0: <tf.Variable 'Variable:0' shape=() dtype=float32, numpy=1.0>,
1: <tf.Variable 'Variable/replica_1:0' shape=() dtype=float32, numpy=1.0>
}
# Variable created outside scope:
regular_variable = tf.Variable(1.)
regular_variable
<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=1.0>Что происходит при входе в область действия Strategy.scope?
-
strategyустанавливается в глобальном контексте как текущая стратегия. В пределах этой области,tf.distribute.get_strategy()теперь вернёт эту стратегию. За пределами этой области, она возвращает стратегию по умолчанию. - Вход в область также означает вход в "контекст между репликами". См.
tf.distribute.StrategyExtendedдля объяснения контекстов между репликами и реплик. - Создание переменных внутри
scopeперехватывается стратегией. Каждая стратегия определяет, как она хочет повлиять на создание переменной. Синхронные стратегии, такие какMirroredStrategy,TPUStrategyиMultiWorkerMiroredStrategy, создают переменные, дублированные на каждой реплике, в то время какParameterServerStrategyсоздаёт переменные на серверах параметров. Это делается с помощью настраиваемогоtf.variable_creator_scope. - В некоторых стратегиях может также быть введён контекст устройства по умолчанию: в
MultiWorkerMiroredStrategyна каждом работнике вводится контекст устройства по умолчанию "/CPU:0".
Примечание: Вход в область действия не автоматически распределяет вычисление, за исключением случаев высокоуровневых обучающих фреймворков, таких как 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.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/CentralStorageStrategy