Использование tf.set_random_seed с tf.estimator.Estimator - PullRequest
0 голосов
/ 28 июня 2018

Я использую tf.estimator.Estimator для управления обучением и тестированием части моего кода. Я настраиваю некоторые гиперпараметры, поэтому мне нужно убедиться, что веса инициализируются одним и тем же случайным начальным числом. Есть ли в любом случае set_random_seed для сеанса, созданного tf.estimator?

1 Ответ

0 голосов
/ 03 июля 2018

Вы должны определить случайное начальное число в конфигурации, передаваемой в оценщик:

seed = 2018
config = tf.estimator.RunConfig(model_dir=model_dir, tf_random_seed=seed)

estimator = tf.estimator.Estimator(model_fn, config=config, params=params)

Вот документация для RunConfig.


Одна вещь, о которой следует быть осторожным, заключается в том, что каждый раз, когда вы запускаете estimator.train(train_input_fn), создается новый график для обучения модели (вызывая train_input_fn для создания входного конвейера и вызывая model_fn на выходе train_input_fn).

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


Пример

Позвольте мне объяснить на примере. Предположим, что вы выполняете увеличение данных в своем входном конвейере, и вы оцениваете свою модель каждую эпоху. Это даст вам что-то вроде этого:

def train_input_fn():
    features = tf.random_uniform([])
    labels = tf.random_uniform([])
    dataset = tf.data.Dataset.from_tensors((features, labels))
    return dataset


def model_fn(features, labels, mode, params):
    loss = features
    global_step = tf.train.get_global_step()
    train_op = global_step.assign_add(1)
    return tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)


seed = 2018
config = tf.estimator.RunConfig(model_dir="test", tf_random_seed=seed)
estimator = tf.estimator.Estimator(model_fn, config=config)

num_epochs = 10
for epoch in range(num_epochs):
    estimator.train(train_input_fn, steps=1)
    estimator.evaluate(train_input_fn, steps=1)

Функция ввода создает случайные объекты (и метки). Что происходит, так это то, что созданные функции будут одинаковыми в каждой эпохе. Вывод будет выглядеть так:

INFO:tensorflow:loss = 0.17983198, step = 1
INFO:tensorflow:Saving dict for global step 1: global_step = 1, loss = 0.006007552
INFO:tensorflow:loss = 0.17983198, step = 2
INFO:tensorflow:Saving dict for global step 2: global_step = 2, loss = 0.006007552
INFO:tensorflow:loss = 0.17983198, step = 3
INFO:tensorflow:Saving dict for global step 3: global_step = 3, loss = 0.006007552
...

Вы можете видеть, что потери (равные входным характеристикам) одинаковы в каждой эпохе, что означает, что в каждой эпохе используется одно и то же случайное начальное число.

Это проблема, если вы хотите оценивать каждую эпоху и выполнять увеличение данных, потому что в итоге вы получите одинаковое увеличение данных в каждую эпоху.


Решение

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

Еще одним лучшим решением является создание новой оценки в каждой эпохе с тем же model_fn, но другим случайным начальным числом:

seed = 2018

num_epochs = 10
for epoch in range(num_epochs):
    config = tf.estimator.RunConfig(model_dir="test", tf_random_seed=seed + epoch)
    estimator = tf.estimator.Estimator(model_fn, config=config)

    estimator.train(train_input_fn, steps=1)
    estimator.evaluate(train_input_fn, steps=1)

Функции будут корректно меняться в каждую эпоху:

INFO:tensorflow:loss = 0.17983198, step = 1
INFO:tensorflow:Saving dict for global step 1: global_step = 1, loss = 0.006007552
INFO:tensorflow:loss = 0.22154999, step = 2
INFO:tensorflow:Saving dict for global step 2: global_step = 2, loss = 0.70446754
INFO:tensorflow:loss = 0.48594844, step = 3
...