Spec-Zone.ru › TensorFlow

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 Возвращает решатель кластера, связанный с данной стратегией.

В общем случае, при использовании стратегии для нескольких рабочих узлов, такой как tf.distribute.experimental.MultiWorkerMirroredStrategy или tf.distribute.TPUStrategy(), есть решатель кластера, связанный со стратегией, и экземпляр такого решателя возвращается этим свойством.

Стратегии, которые намерены иметь связанный решатель кластера, должны установить соответствующий атрибут или переопределить это свойство; в противном случае по умолчанию возвращается None. Эти стратегии также должны предоставить информацию о том, что возвращает это свойство.

Стратегии для одной машины обычно не имеют решателя кластера, и в этих случаях это свойство вернёт None.

Решатель кластера может быть полезен, когда пользователю требуется получить доступ к информации, такой как спецификация кластера, тип задачи или идентификатор задачи. Например,

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 tf.distribute.cluster_resolver.ClusterResolver.

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 для примера.

Важно: tf.data.Dataset, возвращаемый dataset_fn, должен иметь размер пакета на реплику, в отличие от experimental_distribute_dataset, который использует глобальный размер пакета. Это может быть вычислено с помощью input_context.get_per_replica_batch_size.
Примечание: Если вы используете 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. (устарело)

Устарело: ЭТА ФУНКЦИЯ УСТАРЕЛА. Она будет удалена в будущей версии. Инструкции по обновлению: Этот метод недоступен в TF 2.x. Пожалуйста, переключитесь на использование run вместо него.
Устарело: Этот метод недоступен в TF 2.x. Пожалуйста, переключитесь на использование run вместо него.

При включённом режиме выполнения eager, выполняет операторы, указанные в fn, на каждой реплике. В противном случае создаёт граф для выполнения операторов на каждой реплике.

Каждая реплика возьмёт один, разный вход из входов, предоставленных одним вызовом get_next на итераторе ввода.

fn может вызвать tf.distribute.get_replica_context() для доступа к элементам, таким как replica_id_in_sync_group.

Важно: В зависимости от реализации tf.distribute.Strategy, используемой, и от того, включён ли режим eager execution, fn может быть вызван один или несколько раз (по одному разу для каждой реплики).
Аргументы
fn Функция для выполнения. Входы в функцию должны соответствовать выходам input_iterator.get_next(). Выход должен быть tf.nest из Tensor.
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, если хочет настроить, какой вход подается на какую реплику/рабочий и т. д.

class="responsive fixed orange">
Аргументы
dataset tf.data.Dataset, который будет равномерно распределен по всем репликам.
class="responsive fixed orange">
Возвращаемое значение
Итератор 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
)

Возвращает итератор, разделенный по репликам, созданный из функции входных данных.

Устаревший: Этот метод недоступен в 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.

class="responsive fixed orange">
Аргументы
input_fn Функция, принимающая объект tf.distribute.InputContext и возвращающая набор данных tf.data.Dataset.
replication_mode значение перечисления tf.distribute.InputReplicationMode. В настоящее время поддерживается только PER_WORKER, что означает, что для каждого рабочего будет выполнен единственный вызов input_fn. Реплики будут извлекать данные из локального набора данных tf.data.Dataset на своих рабочих узлах.
class="responsive fixed orange">
Возвращаемое значение
Объект итератора, который необходимо сначала использовать с .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.

class="responsive fixed orange">
Аргументы
reduce_op значение tf.distribute.ReduceOp, указывающее, как следует комбинировать значения. Разрешает использование строкового представления перечисления, такого как «SUM», «MEAN».
value экземпляр tf.distribute.DistributedValues, например, возвращаемый Strategy.run, для объединения в один тензор. Он также может быть обычным тензором, когда используется с OneDeviceStrategy или стратегией по умолчанию.
axis Указывает размерность для сведения по каждой реплике. Обычно устанавливается в размерность пакета или None, чтобы выполнить сведение только по репликам (например, если тензор не имеет размерности пакета).
class="responsive fixed orange">
Возвращаемое значение
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, которые не являются указанных типов, не поддерживаются.

Важно: В зависимости от реализации tf.distribute.Strategy и от того, включено ли выполнение с немедленной передачей, fn может быть вызвано один или несколько раз. Если fn аннотировано с помощью tf.function или вызвано tf.distribute.Strategy.run внутри tf.function (выполнение с немедленной передачей отключено внутри tf.function по умолчанию), fn вызывается один раз на реплику для генерации графа Tensorflow, который затем будет повторно использован для выполнения с новыми входными данными. В противном случае, если выполнение с немедленной передачей включено, fn будет вызываться один раз на реплику на каждом шаге, как и обычный код Python.

Пример использования:

  1. Ввод тензора константы.

    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>
        }
        
  2. Вход 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>
        
  3. Используйте 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".
Примечание: Вход в область действия не автоматически распределяет вычисление, за исключением случаев высокоуровневых обучающих фреймворков, таких как keras model.fit. Если вы не используете model.fit, вам нужно использовать API strategy.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, изменённую для использования с этой стратегией.

Устарело: Этот метод недоступен в TF 2.x.

Обновлённая конфигурация содержит необходимые данные для запуска стратегии, например, настройки для запуска коллективных операций или фильтры устройств для повышения производительности распределённого обучения.

Аргументы
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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API