tf.compat.v1.distribute.OneDeviceStrategy
Стратегия распределения для выполнения на одном устройстве.
Наследуется от: Strategy
tf.compat.v1.distribute.OneDeviceStrategy(
device
)
Использование этой стратегии разместит все переменные, созданные в её области видимости, на указанном устройстве. Входные данные, распределённые с помощью этой стратегии, будут предварительно загружены на указанное устройство. Кроме того, все функции, вызываемые через strategy.run, также будут размещены на указанном устройстве.
Типичное использование этой стратегии — тестирование кода с помощью API tf.distribute.Strategy перед переключением на другие стратегии, которые фактически распределяют вычисления по нескольким устройствам/машинам.
Например:
tf.enable_eager_execution() strategy = tf.distribute.OneDeviceStrategy(device="/gpu:0") with strategy.scope(): v = tf.Variable(1.0) print(v.device) # /job:localhost/replica:0/task:0/device:GPU:0 def step_fn(x): return x * 2 result = 0 for i in range(10): result += strategy.run(step_fn, args=(i,)) print(result) # 90
| Аргументы | |
|---|---|
device | Идентификатор строки устройства, на котором должны быть размещены переменные. См. документацию класса для получения более подробной информации о том, как используется устройство. Примеры: "/cpu:0", "/gpu:0", "/device:CPU:0", "/device:GPU:0" |
| Атрибуты | |
|---|---|
cluster_resolver | Возвращает решатель кластера, связанный с этой стратегией. В общем случае, при использовании многоузловой Стратегии, которые намерены иметь связанный Стратегии с одним узлом обычно не имеют Решатель кластера может быть полезен, когда пользователю нужно получить доступ к информации, такой как описание кластера, тип задачи или идентификатор задачи. Например,
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 | Возвращает количество реплик, по которым агрегируются градиенты. |
Методы
experimental_distribute_dataset
experimental_distribute_dataset(
dataset, options=None
)
Создаёт tf.distribute.DistributedDataset из tf.data.Dataset.
Возвращаемый tf.distribute.DistributedDataset можно перебирать аналогично обычным наборам данных. ВАЖНО: пользователь не может добавлять больше преобразований к tf.distribute.DistributedDataset.
Следующий пример:
strategy = tf.distribute.MirroredStrategy() # Create a dataset dataset = dataset_ops.Dataset.TFRecordDataset([ "/a/1.tfr", "/a/2.tfr", "/a/3.tfr", "/a/4.tfr"]) # Distribute that dataset dist_dataset = strategy.experimental_distribute_dataset(dataset) # Iterate over the `tf.distribute.DistributedDataset` for x in dist_dataset: # process dataset elements strategy.run(replica_fn, args=(x,))
В фрагменте кода выше tf.distribute.DistributedDataset dist_dataset сгруппирован по GLOBAL_BATCH_SIZE, и мы перебираем его с помощью for x in dist_dataset. x tf.distribute.DistributedValues содержащий данные для всех реплик, которые агрегируются в пакет из GLOBAL_BATCH_SIZE. tf.distribute.Strategy.run позаботится о подаче правильных данных для каждой реплики в x к соответствующей replica_fn, выполненной на каждой реплике.
Что происходит под капотом этого метода, когда мы говорим, что экземпляр tf.data.Dataset — dataset — распределяется? Это зависит от того, как вы установили tf.data.experimental.AutoShardPolicy через tf.data.experimental.DistributeOptions. По умолчанию он устанавливается в значение tf.data.experimental.AutoShardPolicy.AUTO. В многоузловой настройке мы сначала попытаемся распределить dataset путем определения, создаётся ли dataset из наборов данных читателя (например, tf.data.TFRecordDataset, tf.data.TextLineDataset и т. д.) и, если да, попытаемся разбить входные файлы. Обратите внимание, что должно быть по крайней мере один входной файл на каждый узел. Если у вас меньше одного входного файла на узел, мы рекомендуем отключить фрагментацию наборов данных между узлами, установив tf.data.experimental.DistributeOptions.auto_shard_policy в значение tf.data.experimental.AutoShardPolicy.OFF.
Если попытка фрагментации по файлам не удалась (т. е. набор данных не считывается из файлов), мы равномерно разделим набор данных в конце, добавив операцию .shard в конец потока обработки. Это приведет к выполнению всей предварительной обработки данных на каждом узле, и каждый узел будет выполнять избыточные вычисления. Мы выведем предупреждение, если этот вариант будет выбран.
Как упоминалось ранее, на каждом узле мы также разделим данные между всеми устройствами узла (если их несколько). Это произойдёт, даже если многоузловая фрагментация отключена.
Если описанная выше логика разделения по партиям и фрагментации наборов данных нежелательна, используйте tf.distribute.Strategy.experimental_distribute_datasets_from_function вместо этого, который не выполняет автоматического разделения или фрагментации.
Вы также можете использовать свойство element_spec экземпляра tf.distribute.DistributedDataset, возвращаемого этим API, для запроса tf.TypeSpec элементов, возвращаемых итератором. Это можно использовать для установки свойства input_signature tf.function.
strategy = tf.distribute.MirroredStrategy() # Create a dataset dataset = dataset_ops.Dataset.TFRecordDataset([ "/a/1.tfr", "/a/2.tfr", "/a/3.tfr", "/a/4.tfr"]) # Distribute that dataset dist_dataset = strategy.experimental_distribute_dataset(dataset) @tf.function(input_signature=[dist_dataset.element_spec]) def train_step(inputs): # train model with inputs return # Iterate over the `tf.distribute.DistributedDataset` for x in dist_dataset: # process dataset elements strategy.run(train_step, args=(x,))
Примечание: Порядок обработки данных рабочими узлами при использованииtf.distribute.Strategy.experimental_distribute_datasetилиtf.distribute.Strategy.experimental_distribute_datasets_from_functionне гарантируется. Это обычно необходимо, если вы используетеtf.distributeдля масштабирования предсказания. Вы можете, однако, вставить индекс для каждого элемента в пакет и упорядочить выходы соответственно. Обратитесь к этому фрагменту для получения примера, как упорядочить выходы.
| Аргументы | |
|---|---|
dataset | tf.data.Dataset, который будет разбит по всем репликам в соответствии с указанными выше правилами. |
options | tf.distribute.InputOptions, используемые для управления параметрами распределения этого набора данных. |
| Возвращаемое значение | |
|---|---|
tf.distribute.DistributedDataset. |
experimental_distribute_datasets_from_function
experimental_distribute_datasets_from_function(
dataset_fn, options=None
)
Распределяет экземпляры tf.data.Dataset, созданные вызовами dataset_fn.
dataset_fn будет вызван один раз для каждого узла в стратегии. Каждая реплика на этом узле будет декьюить один пакет входных данных из локального Dataset (т. е., если у узла две реплики, две партии будут декьюированы из Dataset на каждом шаге).
Этот метод можно использовать для нескольких целей. Например, когда 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.
global_batch_size = 8
def dataset_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)
strategy = tf.distribute.MirroredStrategy() ds = strategy.experimental_distribute_datasets_from_function(dataset_fn)
def train(ds):
@tf.function(input_signature=[ds.element_spec])
def step_fn(inputs):
# train the model with inputs
return inputs
... for batch in ds: ... replica_results = strategy.run(replica_fn, args=(batch,))
train(ds)
Примечание: Порядок, в котором данные обрабатываются рабочими при использованииtf.distribute.Strategy.experimental_distribute_datasetилиtf.distribute.Strategy.experimental_distribute_datasets_from_function, не гарантируется. Это обычно требуется, если вы используетеtf.distributeдля масштабирования предсказаний. Однако вы можете вставить индекс для каждого элемента в пакет и упорядочить выводы соответственно. Обратитесь к этому фрагменту для примера того, как упорядочить выводы.
| Аргументы | |
|---|---|
dataset_fn | Функция, принимающая экземпляр tf.distribute.InputContext и возвращающая 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 на возвращенном итераторе. |
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() . |
reduce
reduce(
reduce_op, value, axis=None
)
Сведение value по репликам.
При заданном значении на реплику, возвращаемом run, например, потере на пример, пакет будет разделен между всеми репликами. Эта функция позволяет агрегировать значения по репликам и, необязательно, также по элементам пакета. Например, если у вас есть глобальный размер пакета 8 и 2 реплики, значения для примеров [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.
| Аргументы | |
|---|---|
reduce_op | Значение tf.distribute.ReduceOp, указывающее, как следует комбинировать значения. |
value | Значение «на реплику», например, возвращаемое run для объединения в один тензор. |
axis | Указывает измерение, по которому следует выполнить уменьшение в тензоре каждой реплики. Обычно следует установить в измерение пакета или None для уменьшения только по репликам (например, если тензор не имеет измерения пакета). |
| Возвращаемые значения | |
|---|---|
A Tensor. |
run
run(
fn, args=(), kwargs=None, options=None
)
Выполнение fn на каждой реплике с заданными аргументами.
Выполняет операции, указанные в fn, на каждой реплике. Если args или kwargs содержат tf.distribute.DistributedValues, такие как те, которые создаются tf.distribute.DistributedDataset из tf.distribute.Strategy.experimental_distribute_dataset или tf.distribute.Strategy.experimental_distribute_datasets_from_function, когда fn выполняется на определенной реплике, она будет выполнена с компонентом tf.distribute.DistributedValues, соответствующим этой реплике.
fn может вызвать tf.distribute.get_replica_context() для доступа к членам, таким как all_reduce.
Все аргументы в args или kwargs должны быть либо вложенными тензорами, либо tf.distribute.DistributedValues, содержащими тензоры или составные тензоры.
Пример использования:
- Входной тензор со постоянными значениями.
strategy = tf.distribute.MirroredStrategy() 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 <tf.Tensor: shape=(), dtype=float32, numpy=6.0>
- Вход DistributedValues.
strategy = tf.distribute.MirroredStrategy()
@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=2>
| Аргументы | |
|---|---|
fn | Функция для выполнения. Результат должен быть tf.nest из Tensors. |
args | (Необязательно) Позиционные аргументы для fn. |
kwargs | (Необязательно) Именованные аргументы для fn. |
options | (Необязательно) Экземпляр tf.distribute.RunOptions, задающий параметры выполнения fn. |
| Возвращаемые значения | |
|---|---|
Объединённое возвращаемое значение fn по репликам. Структура возвращаемого значения такая же, как структура возвращаемого значения из fn. Каждый элемент структуры может быть tf.distribute.DistributedValues, объектами Tensor или Tensor (например, при выполнении на одной реплике). |
scope
scope()
Менеджер контекста для установки текущей стратегии и распределения переменных.
Этот метод возвращает менеджер контекста и используется следующим образом:
strategy = tf.distribute.MirroredStrategy()
# 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>
}
# 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.functions, которые представляют шаг обучения ** 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.3/api_docs/python/tf/compat/v1/distribute/OneDeviceStrategy