# Create target_weights to be 0 for targets that
# are padding. (Назначаем target_weights равными 0 для дополнений в целевой последовательности)
batch_weight = np.ones(self.batch_size, dtype=np.float32)
for batch_idx in xrange(self.batch_size):
# We set weight to 0 if the corresponding target is
# a PAD symbol. (Назначаем вес 0, если соответствующая цель — символ PAD)
# The corresponding target is decoder_input shifted
# by 1 forward. (Соответствующая цель — decoder_input со сдвигом вперед на 1)
if length_idx < decoder_size — 1:
target = decoder_inputs[batch_idx][length_idx + 1]
if length_idx == decoder_size — 1 or
target == data_utils.PAD_ID:
batch_weight[batch_idx] = 0.0
batch_weights.append(batch_weight)
return batch_encoder_inputs, batch_decoder_inputs,
batch_weights
Наконец, назначаем нулевые целевые веса для токенов-заполнителей. Подготовка данных завершена, и мы можем начать строить и обучать модель! Сначала определяем код, используемый при обучении и тестировании, на время абстрагируясь от модели. Так можно убедиться, что мы понимаем процесс в общих чертах. Потом можно перейти к более глубокому анализу модели seq2seq. Как всегда, первый шаг в обучении — загрузка данных:
def train():
"""Train a en->fr translation model using WMT data."""
# Prepare WMT data. (Готовим данные WMT)
print("Preparing WMT data in %s" % FLAGS.data_dir)
en_train, fr_train, en_dev, fr_dev, _, _ =
data_utils.prepare_wmt_data(
FLAGS.data_dir, FLAGS.en_vocab_size, FLAGS.fr_vocab_size)
Запустив сессию TensorFlow, первым делом создаем модель. Отметим, что этот метод применим к ряду архитектур, если они удовлетворяют требованиям к формату входных и выходных данных, описанным в методе train():
with tf.Session() as sess:
# Create model. (Создаем модель)
print("Creating %d layers of %d units." % (FLAGS.num_layers, FLAGS.size))
model = create_model(sess, False)
Теперь при помощи разных функций группируем данные; группы позже будут использованы get_batch() для извлечения информации. Создаем набор действительных чисел от 0 до 1, который будет приблизительно определять вероятность выбора группы, нормализованную на размер последней. Метод get_batch() выбирает группы с учетом этих вероятностей:
# Read data into buckets and compute their sizes. (Группируем данные и вычисляем размеры групп)
print ("Reading development and training data (limit: %d)."
% FLAGS.max_train_data_size)
dev_set = read_data(en_dev, fr_dev)
train_set = read_data(en_train, fr_train,
FLAGS.max_train_data_size)
train_bucket_sizes = [len(train_set[b]) for b in xrange(
len(_buckets))]
train_total_size = float(sum(train_bucket_sizes))
# A bucket scale is a list of increasing numbers
# from 0 to 1 that we'll use to select a bucket. (Масштаб группы — список чисел от 0 до 1 по возрастающей, используемых для выбора группы)
# Length of [scale[i], scale[i+1]] is proportional to
# the size if i-th training bucket, as used later. (Длина [scale[i], scale[i+1]] пропорциональна размеру при i-й обучающей группе как показано ниже)
train_buckets_scale = [sum(train_bucket_sizes[: i + 1]) /
train_total_size
for i in xrange(len(
train_bucket_sizes))]
Теперь, когда данные готовы, запускаем основной цикл обучения. Мы инициализируем различные его переменные — например, current_step и previous_losses, делая их пустыми или равными 0. Важно отметить, что каждая итерация цикла соотносится с одной эпохой — полной обработкой пакета обучающих данных. Для эпохи мы выбираем bucket_id, получаем пакет при помощи get_batch, а затем делаем шаг вперед в рамках модели:
# This is the training loop. (Это цикл обучения)
step_time, loss = 0.0, 0.0
current_step = 0
previous_losses = []
while True:
# Choose a bucket according to data distribution. (Выбираем группу на основании распределения данных)
# We pick a random number
# in [0, 1] and use the corresponding interval
# in train_buckets_scale. (Берем случайное число из [0, 1] и используем соответствующий интервал в train_buckets_scale)
random_number_01 = np.random.random_sample()
bucket_id = min([i for i in xrange(len(
train_buckets_scale))
if train_buckets_scale[i] >
random_number_01])
# Get a batch and make a step. (Получаем пакет и делаем шаг)
start_time = time.time()
encoder_inputs, decoder_inputs, target_weights =
model.get_batch(
train_set, bucket_id)
_, step_loss, _ = model.step(sess, encoder_inputs,
decoder_inputs,
target_weights, bucket_id,
False)
Оцениваем потери при предсказании и запоминаем все остальные метрики:
step_time += (time.time() — start_time) /
FLAGS.steps_per_checkpoint
loss += step_loss / FLAGS.steps_per_checkpoint
current_step += 1
Наконец, после некоторого числа итераций, которое предписывается глобальной переменной, нам нужно выполнить ряд дополнительных операций. Сначала выводим статистику для предыдущего пакета: это размер функции потери, темп обучения и перплексия [95]. Если потери не уменьшаются, возможно, модель оказалась в локальном минимуме. Чтобы помочь ей этого избежать, снижаем темп обучения: тогда не будет больших скачков ни в одном направлении. В это же время мы сохраняем копию модели с весами и активациями на диск:
# Once in a while, we save checkpoint, print statistics,
# and run evals. (В определенный момент сохраняем контрольную точку, выводим статистику и проводим оценку)
if current_step % FLAGS.steps_per_checkpoint == 0:
# Print statistics for the previous epoch. (Выводим статистику для предыдущей эпохи)
Читать дальше
Конец ознакомительного отрывка
Купить книгу