
Случайность, как определено самым популярным языком машинного обучения
25 июля 2025 г.Обзор контента
- Настраивать
- TF.Random.Generator Class
- Создание независимых случайных потоков
- Взаимодействие с tf.function
- Взаимодействие с стратегиями распространения
- Сохранение генераторов
- Без гражданства RNGS
- Алгоритмы
- Общий
- XLA устройства
TensorFlow предоставляет набор генераторов псевдолупиточных чисел (RNG), вtf.random
модуль. В этом документе описывается, как вы можете управлять генераторами случайных чисел, и как эти генераторы взаимодействуют с другими подсистемами Tensorflow.
Примечание:Случайные числа не гарантируются согласованными в рамках версий Tensorflow. Видеть:
Tensorflow предоставляет два подхода для управления процессом генерации случайных чисел:
- Через явное использование
tf.random.Generator
объекты Каждый такой объект поддерживает состояние (вtf.Variable
) это будет изменено после каждой генерации номеров. - Через чисто функциональные случайные функции без состояния, такие как
tf.random.stateless_uniform
Полем Вызов эти функции с помощью одних и тех же аргументов (которые включают семена) и на одном и том же устройстве всегда даст одни и те же результаты.
Предупреждение:Старые RNG от TF 1.x, такие какtf.random.uniform
иtf.random.normal
еще не устарели, но сильно обескуражены.
Настраивать
import tensorflow as tf
# Creates some virtual devices (cpu:0, cpu:1, etc.) for using distribution strategy
physical_devices = tf.config.list_physical_devices("CPU")
tf.config.experimental.set_virtual_device_configuration(
physical_devices[0], [
tf.config.experimental.VirtualDeviceConfiguration(),
tf.config.experimental.VirtualDeviceConfiguration(),
tf.config.experimental.VirtualDeviceConfiguration()
])
2024-08-15 01:43:41.157432: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:485] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered
2024-08-15 01:43:41.178819: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:8454] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered
2024-08-15 01:43:41.185039: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1452] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
I0000 00:00:1723686223.758551 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686223.762466 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686223.765643 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686223.769228 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686223.780976 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686223.784469 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686223.787369 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686223.790779 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686223.794250 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686223.797851 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686223.800627 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686223.804177 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
Аtf.random.Generator
сорт
Аtf.random.Generator
Класс используется в тех случаях, когда вы хотите, чтобы каждый вызов RNG давал разные результаты. Он поддерживает внутреннее состояние (управляетсяtf.Variable
объект), который будет обновляться каждый раз, когда генерируются случайные числа. Потому что государством управляетсяtf.Variable
, он пользуется всеми объектами, предоставленнымиtf.Variable
такие как легкая контрольная точка, автоматическая зависимость управления и безопасность потоков.
Вы можете получитьtf.random.Generator
вручную создавая объект класса или вызовtf.random.get_global_generator()
Чтобы получить глобальный генератор по умолчанию:
g1 = tf.random.Generator.from_seed(1)
print(g1.normal(shape=[2, 3]))
g2 = tf.random.get_global_generator()
print(g2.normal(shape=[2, 3]))
I0000 00:00:1723686225.040869 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.043016 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.045041 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.047115 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.049184 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.051188 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.053162 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.055160 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.057105 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.059113 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.061029 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
tf.Tensor(
[[ 0.43842277 -0.53439844 -0.07710262]
[ 1.5658045 -0.1012345 -0.2744976 ]], shape=(2, 3), dtype=float32)
tf.Tensor(
[[ 1.3061213 0.6299361 0.52625704]
[ 1.3733886 0.29277426 -0.7945693 ]], shape=(2, 3), dtype=float32)
I0000 00:00:1723686225.063243 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.101904 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.103956 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.105919 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.107957 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.109922 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.111909 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.113815 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.115823 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.117783 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.120279 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.122678 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1723686225.125117 55391 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
Есть несколько способов создания объекта генератора. Самый простой естьGenerator.from_seed
, как показано выше, это создает генератор из семян. Семена-это нетрицательное целое число.from_seed
Также принимает дополнительный аргументalg
который является алгоритмом RNG, который будет использоваться этим генератором:
g1 = tf.random.Generator.from_seed(1, alg='philox')
print(g1.normal(shape=[2, 3]))
tf.Tensor(
[[ 0.43842277 -0.53439844 -0.07710262]
[ 1.5658045 -0.1012345 -0.2744976 ]], shape=(2, 3), dtype=float32)
УвидетьАлгоритмыРаздел ниже для получения дополнительной информации об этом.
Другой способ создать генератор - сGenerator.from_non_deterministic_state
Полем Генератор, созданный таким образом, начнется с неэтерминированного состояния, в зависимости от, например, времени и ОС.
g = tf.random.Generator.from_non_deterministic_state()
print(g.normal(shape=[2, 3]))
tf.Tensor(
[[ 0.9104948 -0.23143363 -0.09841432]
[-0.91448975 0.1579936 1.3923475 ]], shape=(2, 3), dtype=float32)
Есть еще другие способы создания генераторов, например, из явных состояний, которые не покрываются этим руководством.
При использованииtf.random.get_global_generator
Чтобы получить глобальный генератор, вы должны быть осторожны с размещением устройств. Глобальный генератор создается (из нетериминационного состояния) в первый разtf.random.get_global_generator
вызывается и помещается на устройство по умолчанию при этом вызове. Так, например, если первый сайт, который вы звонитеtf.random.get_global_generator
находится в пределахtf.device("gpu")
Scope, глобальный генератор будет размещен на графическом процессоре, а использование глобального генератора позже из процессора будет понести копию GPU-CPU.
Есть также функцияtf.random.set_global_generator
Для замены глобального генератора другим объектом генератора. Эта функция должна использоваться с осторожностью, потому что старый глобальный генератор мог быть захваченtf.function
(как слабая ссылка), и замена его приведетtf.function
Полем Лучший способ сбросить глобальный генератор - использовать одну из функций «сброса», таких какGenerator.reset_from_seed
, который не создаст новые объекты генератора.
g = tf.random.Generator.from_seed(1)
print(g.normal([]))
print(g.normal([]))
g.reset_from_seed(1)
print(g.normal([]))
tf.Tensor(0.43842277, shape=(), dtype=float32)
tf.Tensor(1.6272374, shape=(), dtype=float32)
tf.Tensor(0.43842277, shape=(), dtype=float32)
Создание независимых случайных потоков
Во многих приложениях нужно несколько независимых потоков случайных номеров, независимых в том смысле, что они не совпадают и не будут иметь каких-либо статистически обнаруживаемых корреляций. Это достигается с помощью использованияGenerator.split
Создать несколько генераторов, которые гарантируют независимо друг от друга (то есть генерирование независимых потоков).
g = tf.random.Generator.from_seed(1)
print(g.normal([]))
new_gs = g.split(3)
for new_g in new_gs:
print(new_g.normal([]))
print(g.normal([]))
tf.Tensor(0.43842277, shape=(), dtype=float32)
tf.Tensor(2.536413, shape=(), dtype=float32)
tf.Tensor(0.33186463, shape=(), dtype=float32)
tf.Tensor(-0.07144657, shape=(), dtype=float32)
tf.Tensor(-0.79253083, shape=(), dtype=float32)
split
изменит состояние генератора, на котором он называется (g
в приведенном выше примере), аналогично методу RNG, таким какnormal
Полем В дополнение к тому, чтобы быть независимыми друг от друга, новые генераторы (new_gs
) также гарантированно не зависит от старого (g
)
Сокращение новых генераторов также полезна, когда вы хотите убедиться, что используемый вами генератор находится на том же устройстве, что и другие вычисления, чтобы избежать накладных расходов копии перекрестных устройств. Например:
with tf.device("cpu"): # change "cpu" to the device you want
g = tf.random.get_global_generator().split(1)[0]
print(g.normal([])) # use of g won't cause cross-device copy, unlike the global generator
tf.Tensor(-0.66787744, shape=(), dtype=float32)
Примечание:Теоретически, вы можете использовать конструкторы, такие какfrom_seed
вместоsplit
Здесь, чтобы получить новый генератор, но при этом вы теряете гарантию, что новый генератор не зависит от глобального генератора. Вы также будете использовать риск того, что вы можете случайно создать два генератора с тем же семенем или с семенами, которые приводят к перекрывающимся потокам случайных номеров.
Вы можете делать рекурсивно расщеплять, вызываяsplit
На разделенных генераторах. Там нет ограничений (за исключением целочисленного переполнения) на глубине рекурсий.
Взаимодействие сtf.function
tf.random.Generator
подчиняется тем же правилам, что иtf.Variable
При использовании сtf.function
Полем Это включает в себя три аспекта.
Создание генераторов снаружиtf.function
tf.function
может использовать генератор, созданный вне его.
g = tf.random.Generator.from_seed(1)
@tf.function
def foo():
return g.normal([])
print(foo())
tf.Tensor(0.43842277, shape=(), dtype=float32)
Пользователь должен убедиться, что объект генератора все еще жив (а не составлен из мусора) при вызванной функции.
Создание генераторов внутриtf.function
Создание генераторов внутриtf.function
может произойти только во время первого запуска функции.
g = None
@tf.function
def foo():
global g
if g is None:
g = tf.random.Generator.from_seed(1)
return g.normal([])
print(foo())
print(foo())
tf.Tensor(0.43842277, shape=(), dtype=float32)
tf.Tensor(1.6272374, shape=(), dtype=float32)
Прохождение генераторов в качестве аргументовtf.function
При использовании в качестве аргументаtf.function
разные объекты генератора вызовут обращениеtf.function
Полем
num_traces = 0
@tf.function
def foo(g):
global num_traces
num_traces += 1
return g.normal([])
foo(tf.random.Generator.from_seed(1))
foo(tf.random.Generator.from_seed(2))
print(num_traces)
2
Обратите внимание, что это повторное поведение соответствуетtf.Variable
:
num_traces = 0
@tf.function
def foo(v):
global num_traces
num_traces += 1
return v.read_value()
foo(tf.Variable(1))
foo(tf.Variable(2))
print(num_traces)
1
Взаимодействие с стратегиями распространения
Есть два способа, которымиGenerator
взаимодействует со стратегиями распространения.
Создание генераторов вне стратегий распространения
Если генератор создается внешним стратегическим областям, все реплики к генератору будут сериализованы, и, следовательно, реплики получат разные случайные числа.
g = tf.random.Generator.from_seed(1)
strat = tf.distribute.MirroredStrategy(devices=["cpu:0", "cpu:1"])
with strat.scope():
def f():
print(g.normal([]))
results = strat.run(f)
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:CPU:0', '/job:localhost/replica:0/task:0/device:CPU:1')
WARNING:tensorflow:Using MirroredStrategy eagerly has significant overhead currently. We will be working on improving this in the future, but for now please wrap `call_for_each_replica` or `experimental_run` or `run` inside a tf.function to get the best performance.
tf.Tensor(0.43842274, shape=(), dtype=float32)
tf.Tensor(1.6272374, shape=(), dtype=float32)
Обратите внимание, что это использование может иметь проблемы с производительностью, потому что устройство генератора отличается от реплик.
Создание генераторов внутри стратегий распространения
Если в рамках стратегии создается генератор, каждая копия получит свой и независимый поток случайных чисел.
strat = tf.distribute.MirroredStrategy(devices=["cpu:0", "cpu:1"])
with strat.scope():
g = tf.random.Generator.from_seed(1)
print(strat.run(lambda: g.normal([])))
print(strat.run(lambda: g.normal([])))
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:CPU:0', '/job:localhost/replica:0/task:0/device:CPU:1')
WARNING:tensorflow:Using MirroredStrategy eagerly has significant overhead currently. We will be working on improving this in the future, but for now please wrap `call_for_each_replica` or `experimental_run` or `run` inside a tf.function to get the best performance.
PerReplica:{
0: tf.Tensor(-0.87930447, shape=(), dtype=float32),
1: tf.Tensor(0.020661574, shape=(), dtype=float32)
}
WARNING:tensorflow:Using MirroredStrategy eagerly has significant overhead currently. We will be working on improving this in the future, but for now please wrap `call_for_each_replica` or `experimental_run` or `run` inside a tf.function to get the best performance.
PerReplica:{
0: tf.Tensor(-1.5822568, shape=(), dtype=float32),
1: tf.Tensor(0.77539235, shape=(), dtype=float32)
}
Примечание:В настоящее времяtf.random.Generator
Не предоставляет возможность позволить разным репликам получить идентичные (вместо разных) потоков (что технически не сложно). Если у вас есть вариант использования для этой функции, сообщите о разработчиках TensorFlow.
Если генератор посеян (например, созданGenerator.from_seed
), случайные числа определяются семенами, хотя разные реплики получают разные и некоррелированные числа. Можно придумать случайное число, сгенерированное в реплике как хэш идентификатора реплики и «первичное» случайное число, которое является общим для всех реплик. Следовательно, вся система все еще детерминированная.
tf.random.Generator
также может быть создан внутриStrategy.run
:
strat = tf.distribute.MirroredStrategy(devices=["cpu:0", "cpu:1"])
with strat.scope():
def f():
g = tf.random.Generator.from_seed(1)
a = g.normal([])
b = g.normal([])
return tf.stack([a, b])
print(strat.run(f))
print(strat.run(f))
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:CPU:0', '/job:localhost/replica:0/task:0/device:CPU:1')
WARNING:tensorflow:Using MirroredStrategy eagerly has significant overhead currently. We will be working on improving this in the future, but for now please wrap `call_for_each_replica` or `experimental_run` or `run` inside a tf.function to get the best performance.
PerReplica:{
0: tf.Tensor([-0.87930447 -1.5822568 ], shape=(2,), dtype=float32),
1: tf.Tensor([0.02066157 0.77539235], shape=(2,), dtype=float32)
}
WARNING:tensorflow:Using MirroredStrategy eagerly has significant overhead currently. We will be working on improving this in the future, but for now please wrap `call_for_each_replica` or `experimental_run` or `run` inside a tf.function to get the best performance.
PerReplica:{
0: tf.Tensor([-0.87930447 -1.5822568 ], shape=(2,), dtype=float32),
1: tf.Tensor([0.02066157 0.77539235], shape=(2,), dtype=float32)
}
Мы больше не рекомендуем пройтиtf.random.Generator
как аргументыStrategy.run
, потому чтоStrategy.run
Как правило, ожидает, что аргументы будут тензорами, а не генераторами.
Сохранение генераторов
Обычно для сохранения или сериализации вы можете справитьсяtf.random.Generator
так же, как вы бы справились сtf.Variable
илиtf.Module
(или его подклассы). В TF есть два механизма для сериализации:Контрольная точкаиСохраняйте модельПолем
Контрольная точка
Генераторы могут быть свободно сохранены и восстановлены с помощьюtf.train.Checkpoint
Полем Случайный поток из точки восстановления будет таким же, как и из точки сохранения.
filename = "./checkpoint"
g = tf.random.Generator.from_seed(1)
cp = tf.train.Checkpoint(generator=g)
print(g.normal([]))
tf.Tensor(0.43842277, shape=(), dtype=float32)
cp.write(filename)
print("RNG stream from saving point:")
print(g.normal([]))
print(g.normal([]))
RNG stream from saving point:
tf.Tensor(1.6272374, shape=(), dtype=float32)
tf.Tensor(1.6307176, shape=(), dtype=float32)
cp.restore(filename)
print("RNG stream from restoring point:")
print(g.normal([]))
print(g.normal([]))
RNG stream from restoring point:
tf.Tensor(1.6272374, shape=(), dtype=float32)
tf.Tensor(1.6307176, shape=(), dtype=float32)
Вы также можете сохранить и восстановить в рамках стратегии распространения:
filename = "./checkpoint"
strat = tf.distribute.MirroredStrategy(devices=["cpu:0", "cpu:1"])
with strat.scope():
g = tf.random.Generator.from_seed(1)
cp = tf.train.Checkpoint(my_generator=g)
print(strat.run(lambda: g.normal([])))
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:CPU:0', '/job:localhost/replica:0/task:0/device:CPU:1')
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:CPU:0', '/job:localhost/replica:0/task:0/device:CPU:1')
PerReplica:{
0: tf.Tensor(-0.87930447, shape=(), dtype=float32),
1: tf.Tensor(0.020661574, shape=(), dtype=float32)
}
with strat.scope():
cp.write(filename)
print("RNG stream from saving point:")
print(strat.run(lambda: g.normal([])))
print(strat.run(lambda: g.normal([])))
RNG stream from saving point:
PerReplica:{
0: tf.Tensor(-1.5822568, shape=(), dtype=float32),
1: tf.Tensor(0.77539235, shape=(), dtype=float32)
}
PerReplica:{
0: tf.Tensor(-0.5039703, shape=(), dtype=float32),
1: tf.Tensor(0.1251838, shape=(), dtype=float32)
}
with strat.scope():
cp.restore(filename)
print("RNG stream from restoring point:")
print(strat.run(lambda: g.normal([])))
print(strat.run(lambda: g.normal([])))
RNG stream from restoring point:
PerReplica:{
0: tf.Tensor(-1.5822568, shape=(), dtype=float32),
1: tf.Tensor(0.77539235, shape=(), dtype=float32)
}
PerReplica:{
0: tf.Tensor(-0.5039703, shape=(), dtype=float32),
1: tf.Tensor(0.1251838, shape=(), dtype=float32)
}
Вы должны убедиться, что реплики не расходится в их истории вызовов RNG (например, одна копия делает один вызов RNG, в то время как другой делает два вызова RNG) перед сохранением. В противном случае их внутренние государства RNG будут расходятся иtf.train.Checkpoint
(Что сохраняет только состояние первой реплики) не будет должным образом восстановить все копии.
Вы также можете восстановить сохраненную контрольную точку в другую стратегию распределения с другим количеством реплик. Потому что аtf.random.Generator
Объект, созданный в стратегии, может использоваться только в одной и той же стратегии, чтобы восстановить другую стратегию, вы должны создать новыйtf.random.Generator
в целевой стратегии и новойtf.train.Checkpoint
Для этого, как показано в этом примере:
filename = "./checkpoint"
strat1 = tf.distribute.MirroredStrategy(devices=["cpu:0", "cpu:1"])
with strat1.scope():
g1 = tf.random.Generator.from_seed(1)
cp1 = tf.train.Checkpoint(my_generator=g1)
print(strat1.run(lambda: g1.normal([])))
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:CPU:0', '/job:localhost/replica:0/task:0/device:CPU:1')
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:CPU:0', '/job:localhost/replica:0/task:0/device:CPU:1')
PerReplica:{
0: tf.Tensor(-0.87930447, shape=(), dtype=float32),
1: tf.Tensor(0.020661574, shape=(), dtype=float32)
}
with strat1.scope():
cp1.write(filename)
print("RNG stream from saving point:")
print(strat1.run(lambda: g1.normal([])))
print(strat1.run(lambda: g1.normal([])))
RNG stream from saving point:
PerReplica:{
0: tf.Tensor(-1.5822568, shape=(), dtype=float32),
1: tf.Tensor(0.77539235, shape=(), dtype=float32)
}
PerReplica:{
0: tf.Tensor(-0.5039703, shape=(), dtype=float32),
1: tf.Tensor(0.1251838, shape=(), dtype=float32)
}
strat2 = tf.distribute.MirroredStrategy(devices=["cpu:0", "cpu:1", "cpu:2"])
with strat2.scope():
g2 = tf.random.Generator.from_seed(1)
cp2 = tf.train.Checkpoint(my_generator=g2)
cp2.restore(filename)
print("RNG stream from restoring point:")
print(strat2.run(lambda: g2.normal([])))
print(strat2.run(lambda: g2.normal([])))
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:CPU:0', '/job:localhost/replica:0/task:0/device:CPU:1', '/job:localhost/replica:0/task:0/device:CPU:2')
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:CPU:0', '/job:localhost/replica:0/task:0/device:CPU:1', '/job:localhost/replica:0/task:0/device:CPU:2')
RNG stream from restoring point:
PerReplica:{
0: tf.Tensor(-1.5822568, shape=(), dtype=float32),
1: tf.Tensor(0.77539235, shape=(), dtype=float32),
2: tf.Tensor(0.6851049, shape=(), dtype=float32)
}
PerReplica:{
0: tf.Tensor(-0.5039703, shape=(), dtype=float32),
1: tf.Tensor(0.1251838, shape=(), dtype=float32),
2: tf.Tensor(-0.58519536, shape=(), dtype=float32)
}
Хотяg1
иcp1
разные объекты изg2
иcp2
, они связаны через общий файл контрольной точкиfilename
и имя объектаmy_generator
Полем Перекрывающиеся реплики между стратегиями (например,cpu:0
иcpu:1
Выше) будут иметь свои потоки RNG должным образом восстановленные, как в предыдущих примерах. Эта гарантия не охватывает случай, когда генератор сохраняется в сфере стратегии и восстанавливается за пределами какой -либо стратегии или наоборот, потому что устройство вне стратегии, находящиеся вне стратегии, рассматривается как отличная от любой копии в стратегии.
Сохраняйте модель
tf.random.Generator
можно сохранить в спасении. Генератор может быть создан в рамках стратегии. Сохранение также может произойти в рамках стратегии.
filename = "./saved_model"
class MyModule(tf.Module):
def __init__(self):
super(MyModule, self).__init__()
self.g = tf.random.Generator.from_seed(0)
@tf.function
def __call__(self):
return self.g.normal([])
@tf.function
def state(self):
return self.g.state
strat = tf.distribute.MirroredStrategy(devices=["cpu:0", "cpu:1"])
with strat.scope():
m = MyModule()
print(strat.run(m))
print("state:", m.state())
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:CPU:0', '/job:localhost/replica:0/task:0/device:CPU:1')
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:CPU:0', '/job:localhost/replica:0/task:0/device:CPU:1')
PerReplica:{
0: tf.Tensor(-1.4154755, shape=(), dtype=float32),
1: tf.Tensor(-0.11388441, shape=(), dtype=float32)
}
state: tf.Tensor([256 0 0], shape=(3,), dtype=int64)
with strat.scope():
tf.saved_model.save(m, filename)
print("RNG stream from saving point:")
print(strat.run(m))
print("state:", m.state())
print(strat.run(m))
print("state:", m.state())
INFO:tensorflow:Assets written to: ./saved_model/assets
INFO:tensorflow:Assets written to: ./saved_model/assets
RNG stream from saving point:
PerReplica:{
0: tf.Tensor(-0.68758255, shape=(), dtype=float32),
1: tf.Tensor(0.8084062, shape=(), dtype=float32)
}
state: tf.Tensor([512 0 0], shape=(3,), dtype=int64)
PerReplica:{
0: tf.Tensor(-0.27342677, shape=(), dtype=float32),
1: tf.Tensor(-0.53093255, shape=(), dtype=float32)
}
state: tf.Tensor([768 0 0], shape=(3,), dtype=int64)
imported = tf.saved_model.load(filename)
print("RNG stream from loading point:")
print("state:", imported.state())
print(imported())
print("state:", imported.state())
print(imported())
print("state:", imported.state())
RNG stream from loading point:
state: tf.Tensor([256 0 0], shape=(3,), dtype=int64)
tf.Tensor(-1.0359411, shape=(), dtype=float32)
state: tf.Tensor([512 0 0], shape=(3,), dtype=int64)
tf.Tensor(-0.06425078, shape=(), dtype=float32)
state: tf.Tensor([768 0 0], shape=(3,), dtype=int64)
Загрузка сохраненной модели, содержащейtf.random.Generator
В стратегию распределения не рекомендуется, потому что все реплики будут генерировать один и тот же случайный поток (это потому, что идентификатор реплики заморожен на графике SaveedModel).
Загрузка распределенногоtf.random.Generator
(Генератор, созданный в рамках стратегии распределения) в не стратегическую среду, как приведенный выше пример, также имеет предостережение. Состояние RNG будет должным образом восстановлено, но генерируемые случайные числа будут отличаться от исходного генератора в своей стратегии (опять же, потому что устройство вне стратегий, находящихся в стороне, рассматривается как отличная от любой реплики в стратегии).
Без гражданства RNGS
Использование RNG без состояния просто. Поскольку они просто чистые функции, не существует состояния или побочного эффекта.
print(tf.random.stateless_normal(shape=[2, 3], seed=[1, 2]))
print(tf.random.stateless_normal(shape=[2, 3], seed=[1, 2]))
tf.Tensor(
[[ 0.5441101 0.20738031 0.07356433]
[ 0.04643455 -1.30159 -0.95385665]], shape=(2, 3), dtype=float32)
tf.Tensor(
[[ 0.5441101 0.20738031 0.07356433]
[ 0.04643455 -1.30159 -0.95385665]], shape=(2, 3), dtype=float32)
Каждое RNG без гражданства требуетseed
аргумент, который должен быть целочисленным тензором формы[2]
Полем Результаты ОП полностью определены этим семенем.
Алгоритм RNG, используемый RNG без состояния, зависит от устройства, что означает, что один и тот же OP, работающий на другом устройстве, может создавать разные выходы.
Алгоритмы
Общий
Обаtf.random.Generator
класс иstateless
функции поддерживают алгоритм Philox (написано как"philox"
илиtf.random.Algorithm.PHILOX
) на всех устройствах.
Различные устройства будут генерировать одинаковые целочисленные числа, при использовании одного и того же алгоритма и начнутся с того же состояния. Они также будут генерировать «практически одинаковые» числа точек, хотя могут возникнуть небольшие числовые расхождения, вызванные различными способами, которыми устройства выполняют вычисление с плавающей точкой (например, порядок сокращения).
XLA устройства
На устройствах, управляемых xLA (например, TPU, а также процессором/графическим процессором при включении XLA) Алгоритм ThreeFry (написано как"threefry"
илиtf.random.Algorithm.THREEFRY
) также поддерживается. Этот алгоритм быстрый на TPU, но медленно на процессоре/графическом процессоре по сравнению с Philox.
Смотрите бумагу'Параллельные случайные числа: просто 1, 2, 3'Для получения более подробной информации об этих алгоритмах.
Первоначально опубликовано на
Оригинал