"""Create translation model and initialize or load parameters in session.""" (Создаем модель перевода и инициализируем или загружаем параметры в сеансе)
dtype = tf.float16 if FLAGS.use_fp16 else tf.float32
model = seq2seq_model.Seq2SeqModel(
FLAGS.en_vocab_size,
FLAGS.fr_vocab_size,
_buckets,
FLAGS.size,
FLAGS.num_layers,
FLAGS.max_gradient_norm,
FLAGS.batch_size,
FLAGS.learning_rate,
FLAGS.learning_rate_decay_factor,
forward_only=forward_only,
dtype=dtype)
Прежде чем вернуть эту модель, проверяем, нет ли других, сохраненных в контрольных точках и оставшихся с предыдущих обучающих запусков. Такая модель и ее параметры читаются в переменную и используются. Это позволяет прекратить обучение в контрольной точке и возобновить его не с нуля. Иначе в качестве основного объекта возвращается вновь созданная модель:
ckpt = tf.train.get_checkpoint_state(FLAGS.train_dir)
if ckpt and tf.train.checkpoint_exists(
ckpt.model_checkpoint_path):
print("Reading model parameters from %s" (Чтение параметров модели)
% ckpt.model_checkpoint_path)
model.saver.restore(session, ckpt.model_checkpoint_path)
else:
print("Created model with fresh parameters.") (Созданная модель с новыми параметрами)
session.run(tf.global_variables_initializer())
return model
Теперь рассмотрим конструктор seq2seq_model.Seq2SeqModel. Он создает весь граф вычислений и иногда вызывает определенные низкоуровневые конструкции. Прежде чем перейти к деталям, изучим код сверху вниз и детали общего графа вычислений.
Те же аргументы, сообщенные create_model(), передаются и этому конструктору, создаются несколько полей уровня класса:
class Seq2SeqModel(object):
def __init__(self,
source_vocab_size,
target_vocab_size,
buckets,
size,
num_layers,
max_gradient_norm,
batch_size,
learning_rate,
learning_rate_decay_factor,
use_lstm=False,
num_samples=512,
forward_only=False,
dtype=tf.float32):
self.source_vocab_size = source_vocab_size
self.target_vocab_size = target_vocab_size
self.buckets = buckets
self.batch_size = batch_size
self.learning_rate = tf.Variable(
float(learning_rate), trainable=False, dtype=dtype)
self.learning_rate_decay_op = self.learning_rate.assign(
self.learning_rate * learning_rate_decay_factor)
self.global_step = tf.Variable(0, trainable=False)
Следующая часть создает семплированную функцию мягкого максимума и проекцию вывода. Это улучшение по сравнению с базовыми моделями seq2seq, которое позволяет эффективно декодировать большие выходные словари и проецировать выходные логиты в нужное пространство:
# If we use sampled softmax, we need an output projection. (Если мы используем семплированную функцию мягкого максимума, нужна проекция вывода)
output_projection = None
softmax_loss_function = None
# Sampled softmax only makes sense if we sample less than
# vocabulary size. (Семплированная функция мягкого максимума нужна, только если мы делаем выборку меньше размера словаря)
if num_samples > 0 and num_samples <
self.target_vocab_size:
w_t = tf.get_variable("proj_w", [self.target_vocab_size,
size], dtype=dtype)
w = tf.transpose(w_t)
b = tf.get_variable("proj_b", [self.target_vocab_size],
dtype=dtype)
output_projection = (w, b)
def sampled_loss(inputs, labels):
labels = tf.reshape(labels, [-1, 1])
# We need to compute the sampled_softmax_loss using
# 32bit floats to avoid numerical instabilities. (Нужно вычислить значение семплированной функции мягкого максимума при помощи 32-битных плавающих запятых во избежание числовых нестабильностей)
local_w_t = tf.cast(w_t, tf.float32)
local_b = tf.cast(b, tf.float32)
local_inputs = tf.cast(inputs, tf.float32)
return tf.cast(
tf.nn.sampled_softmax_loss(local_w_t, local_b,
local_inputs, labels,
num_samples,
self.target_vocab_size),
dtype)
softmax_loss_function = sampled_loss
На основании флагов выбираем соответствующий нейрон РНС. Это может быть GRU, обычный или многослойный нейрон LSTM. На практике однослойные нейроны LSTM используются редко, но их гораздо быстрее обучать и они могут ускорить цикл отладки:
# Create the internal multi-layer cell for our RNN. (Создаем внутреннюю многослойную ячейку для РНС)
single_cell = tf.nn.rnn_cell.GRUCell(size)
if use_lstm:
single_cell = tf.nn.rnn_cell.BasicLSTMCell(size)
cell = single_cell
if num_layers > 1:
cell = tf.nn.rnn_cell.MultiRNNCell([single_cell] *
num_layers)
Рекуррентная функция seq2seq_f() определяется с seq2seq.embedding_attention_seq2seq(), о которой мы поговорим позже:
# The seq2seq function: we use embedding for the
# input and attention. (Функция seq2seq: для ввода и внимания используем вложение)
def seq2seq_f(encoder_inputs, decoder_inputs, do_decode):
return seq2seq.embedding_attention_seq2seq(
encoder_inputs,
decoder_inputs,
cell,
num_encoder_symbols=source_vocab_size,
num_decoder_symbols=target_vocab_size,
embedding_size=size,
output_projection=output_projection,
feed_previous=do_decode,
dtype=dtype)
Определяем заполнители для входных и выходных данных:
# Feeds for inputs. (Значения ввода)
self.encoder_inputs = []
self.decoder_inputs = []
self.target_weights = []
for i in xrange(buckets[-1][0]): # Last bucket is
# the biggest one. (Последняя группа — самая большая)
self.encoder_inputs.append(tf.placeholder(tf.int32,
shape=[None],
name="encoder{0}".format(i)))
for i in xrange(buckets[-1][1] + 1):
self.decoder_inputs.append(tf.placeholder(tf.int32,
shape=[None],
name="decoder{0}".format(i)))
self.target_weights.append(tf.placeholder(dtype,
shape=[None],
name="weight{0}".format(i)))
# Our targets are decoder inputs shifted by one. (Наши цели — вводы декодера со сдвигом 1)
targets = [self.decoder_inputs[i + 1]
for i in xrange(len(self.decoder_inputs) — 1)]
Вычисляем выходные данные и ошибку в функции seq2seq.model_with_buckets. Эта функция создает модель seq2seq, совместимую с группами, и вычисляет ошибку либо усреднением по всей примерной последовательности, либо как взвешенную ошибку перекрестной энтропии для последовательности логитов:
Читать дальше
Конец ознакомительного отрывка
Купить книгу