Нихиль Будума - Основы глубокого обучения
- Название:Основы глубокого обучения
- Автор:
- Жанр:
- Издательство:Манн, Иванов и Фербер
- Год:2020
- Город:Москва
- ISBN:9785001464723
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Нихиль Будума - Основы глубокого обучения краткое содержание
Основы глубокого обучения - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
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, совместимую с группами, и вычисляет ошибку либо усреднением по всей примерной последовательности, либо как взвешенную ошибку перекрестной энтропии для последовательности логитов:
# Training outputs and losses. (Выводы и потери при обучении)
if forward_only:
self.outputs, self.losses = seq2seq.model_with_buckets(
self.encoder_inputs, self.decoder_inputs, targets,
self.target_weights, buckets, lambda x, y:
seq2seq_f(x, y, True),
softmax_loss_function=softmax_loss_function)
# If we use output projection, we need to project outputs
# for decoding. (Если используется проекция вывода, для декодирования необходимо проецировать выводы)
if output_projection is not None:
for b in xrange(len(buckets)):
self.outputs[b] = [
tf.matmul(output, output_projection[0]) +
output_projection[1]
for output in self.outputs[b]
]
else:
self.outputs, self.losses = seq2seq.model_with_buckets(
self.encoder_inputs, self.decoder_inputs, targets,
self.target_weights, buckets,
lambda x, y: seq2seq_f(x, y, False),
softmax_loss_function=softmax_loss_function)
Наконец, нужно обновить параметры модели (ведь это обучающиеся переменные) при помощи градиентного спуска. Мы берем обычный стохастический спуск с обрезанием градиента, но с тем же успехом можно использовать любой оптимизатор: результаты улучшатся, и обучение пойдет гораздо быстрее. Затем сохраняем все переменные.
# Gradients and SGD update operation for training the model. (Градиенты и стохастический градиентный спуск позволяют обновить операцию для обучения модели)
params = tf.trainable_variables()
if not forward_only:
self.gradient_norms = []
self.updates = []
opt = tf.train.GradientDescentOptimizer(
self.learning_rate)
for b in xrange(len(buckets)):
gradients = tf.gradients(self.losses[b], params)
clipped_gradients, norm = tf.clip_by_global_norm(
gradients,
max_gradient_norm)
self.gradient_norms.append(norm)
self.updates.append(opt.apply_gradients(
zip(clipped_gradients, params), global_step=
self.global_step))
self.saver = tf.train.Saver(tf.all_variables())
Описав высокоуровневые детали графа вычислений, переходим к последнему и самому нижнему уровню модели — внутренним элементам seq2seq.embedding_attention_seq2seq(). При инициализации модели некоторые флаги и аргументы передаются как параметры функции. Подробнее изучим аргумент feed_previous. При его значении true декодер будет использовать выведенный логит на временном шаге T как вход на временном шаге T+1. Он станет последовательно декодировать очередной токен на основе всех предыдущих. Такой тип декодирования, при котором каждое выходное значение зависит от всех предыдущих, можно назвать авторегрессионным :
def embedding_attention_seq2seq(encoder_inputs,
decoder_inputs,
cell,
num_encoder_symbols,
num_decoder_symbols,
embedding_size,
output_projection=None,
feed_previous=False,
dtype=None,
scope=None,
initial_state_attention=False):
Сначала создаем обертку для декодера.
with variable_scope.variable_scope(
scope or "embedding_attention_seq2seq", dtype=dtype)
as scope:
dtype = scope.dtype
encoder_cell = rnn_cell.EmbeddingWrapper(
cell,
embedding_classes=num_encoder_symbols,
embedding_size=embedding_size)
encoder_outputs, encoder_state = rnn.rnn(
encoder_cell, encoder_inputs, dtype=dtype)
В следующем фрагменте кода вычисляем конкатенацию выходных данных кодера, на которые нужно обратить внимание. Это важно, поскольку позволяет декодеру проходить по этим состояниям как по распределению:
# First calculate a concatenation of encoder outputs
Читать дальшеИнтервал:
Закладка: