Нихиль Будума - Основы глубокого обучения
- Название:Основы глубокого обучения
- Автор:
- Жанр:
- Издательство:Манн, Иванов и Фербер
- Год:2020
- Город:Москва
- ISBN:9785001464723
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Нихиль Будума - Основы глубокого обучения краткое содержание
Основы глубокого обучения - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
model.batch_size = 1
# We decode one sentence at a time. (Декодируем по предложению за раз)
# Load vocabularies. (Загружаем словари)
en_vocab_path = os.path.join(FLAGS.data_dir,
"vocab%d.en" %
FLAGS.en_vocab_size)
fr_vocab_path = os.path.join(FLAGS.data_dir,
"vocab%d.fr" %
FLAGS.fr_vocab_size)
en_vocab, _ = data_utils.initialize_vocabulary(
en_vocab_path)
_, rev_fr_vocab = data_utils.initialize_vocabulary(
fr_vocab_path)
Читаем входные данные со стандартного ввода, чтобы запрашивать предложения у пользователя:
# Decode from standard input. (Декодировать стандартный ввод)
sys.stdout.write("> ")
sys.stdout.flush()
sentence = sys.stdin.readline()
Если полученное предложение не пустое, оно разбивается на токены и обрезается при превышении определенной длины:
while sentence:
# Get token-ids for the input sentence. (Получаем токены для входящего предложения)
token_ids = data_utils.sentence_to_token_ids(
tf.compat.as_bytes(sentence), en_vocab)
# Which bucket does it belong to? (К какой группе оно принадлежит?)
bucket_id = len(_buckets) — 1
for i, bucket in enumerate(_buckets):
if bucket[0] >= len(token_ids):
bucket_id = i
break
else:
logging.warning("Sentence truncated: %s", sentence)
Хотя мы не загружаем никаких данных, get_batch() преобразует введенные данные в нужный формат и готовит к использованию в step():
# Get a 1-element batch to feed the sentence to
# the model. (Получаем одноэлементный пакет для ввода предложения в модель)
encoder_inputs, decoder_inputs, target_weights =
model.get_batch(
{bucket_id: [(token_ids, [])]}, bucket_id)
Мы делаем шаг вперед в рамках модели. На этот раз нам нужны output_logits, то есть ненормализованные вероятности выходных токенов, а не величина функции потерь. Декодируем их при помощи выходного словаря и останавливаем декодирование при первом появлении метки EOS.
Теперь выводим французское предложение или фразу пользователю и ожидаем следующую фразу:
# Get output logits for the sentence. (Получаем логиты вывода для предложения)
_, _, output_logits = model.step(sess, encoder_inputs,
decoder_inputs,
target_weights,
bucket_id, True)
# This is a greedy decoder — outputs are just argmaxes
# of output_logits. (Это жадный декодер: выводы — просто номера максимумов в output_logits)
outputs = [int(np.argmax(logit, axis=1))
for logit in output_logits]
# If there is an EOS symbol in outputs, cut them
# at that point. (Если в выводах есть символ EOS, обрезаем их в этом месте)
if data_utils.EOS_ID in outputs:
outputs = outputs[: outputs.index(data_utils.EOS_ID)]
# Print out French sentence corresponding to outputs. (Выдаем французское предложение, соответствующее выводам)
print(" ".join([tf.compat.as_str(rev_fr_vocab[output])
for output in outputs]))
print("> ", end="")
sys.stdout.flush()
sentence = sys.stdin.readline()
На этом мы заканчиваем высокоуровневое рассмотрение обучения и использования моделей. Мы сильно абстрагировались от самой модели, и некоторым пользователям достаточно и этого. Но следует рассказать и об особенностях функции step(). Она отвечает за расчет целевой функции модели, соответствующее обновление весов и задание графа вычислений для модели. Начнем с первого.
Функция step() получает несколько аргументов: сессия TensorFlow, список векторов для ввода в кодер, входные данные для декодера, целевые веса, выбранное во время обучения значение bucket_id и логический флаг forward_only, который определяет, использовать градиентную оптимизацию для обновления весов или заморозить их. Отметим, что изменение этого флага с False на True позволило нам декодировать произвольное предложение и оценить работу модели на тестовом наборе данных:
def step(self, session, encoder_inputs, decoder_inputs,
target_weights, bucket_id, forward_only):
После нескольких защитных проверок того, что все векторы имеют совместимые размеры, мы готовим функции для прямого и обратного прохода. Метод прямого прохода получает всю информацию, изначально переданную функции step(), то есть необходимую при вычислении величины ошибки для одного примера:
# Check if the sizes match. (Проверяем, сходятся ли размеры)
encoder_size, decoder_size = self.buckets[bucket_id]
if len(encoder_inputs)!= encoder_size:
raise ValueError("Encoder length must be equal to the one in bucket,"
" %d!= %d." % (len(
encoder_inputs), encoder_size))
if len(decoder_inputs)!= decoder_size:
raise ValueError("Decoder length must be equal to the one
in bucket,"
" %d!= %d." % (len(decoder_inputs),
decoder_size))
if len(target_weights)!= decoder_size:
raise ValueError("Weights length must be equal to the one
in bucket,"
" %d!= %d." % (len(target_weights),
decoder_size))
# Input feed: encoder inputs, decoder inputs, target_weights,
# as provided. (Ввод: вводы кодера, вводы декодера, target_weights в данном порядке)
input_feed = {}
for l in xrange(encoder_size):
input_feed[self.encoder_inputs[l].name] = encoder_inputs[l]
for l in xrange(decoder_size):
input_feed[self.decoder_inputs[l].name] = decoder_inputs[l]
input_feed[self.target_weights[l].name] = target_weights[l]
# Since our targets are decoder inputs shifted by one,
# we need one more. (Поскольку наши цели — вводы декодера со сдвигом 1, нужна еще одна цель)
last_target = self.decoder_inputs[decoder_size].name
input_feed[last_target] = np.zeros([self.batch_size],
dtype=np.int32)
Метод обратного прохода, если ошибка рассчитана и необходимо ее распространить обратно по сети, содержит операцию обновления, которая выполняет стохастический градиентный спуск, вычисляет норму градиента и потери на пакет:
# Output feed: depends on whether we do a backward step or
# not. (Вывод: зависит от того, делается шаг назад или нет)
if not forward_only:
output_feed = [self.updates[bucket_id], # Update Op that
# does SGD. (Операция обновления запускает обратный градиентный спуск)
self.gradient_norms[bucket_id], # Gradient
# norm. (норма градиента)
self.losses[bucket_id]] # Loss for this
# batch. (Потери на пакет)
else:
output_feed = [self.losses[bucket_id]] # Loss for this
# batch. (потери на пакет)
for l in xrange(decoder_size): # Output logits. (Исходящие логиты)
output_feed.append(self.outputs[bucket_id][l])
Два этих метода передаются в session.run(). В зависимости от флага forward_only возвращаются либо норма градиента и ошибка для сбора статистики, либо выходные данные для декодирования:
outputs = session.run(output_feed, input_feed)
if not forward_only:
return outputs[1], outputs[2], None #, attns
# Gradient norm, loss, no outputs. (Норма градиента, потери, без исходящих)
else:
return None, outputs[0], outputs[1:] #, attns
# No gradient norm, loss, outputs. (Без нормы градиента, потерь, исходящие данные)
Теперь можно изучить саму модель. Ее конструктор задает граф вычислений на основе созданных высокоуровневых компонентов. Сначала дадим краткий обзор метода create_model(), вызывающего этот конструктор, а затем подробно рассмотрим сам конструктор.
Метод create_model() сам по себе несложен: он задействует ряд определенных пользователем или заданных по умолчанию флагов, таких как размеры английского и французского словарей и размер пакета для создания модели с помощью конструктора seq2seq_model.Seq2SeqModel. Очень интересен здесь флаг use_fp16 flag. Используется тип данных в массивах NumPy с пониженной точностью, что приводит к ускорению работы ценой некоторых потерь в точности. Но часто 16-битных представлений потерь и обновлений градиента достаточно: они нередко близки по величине к 32-битным. Создать модель можно при помощи следующего кода:
def create_model(session, forward_only):
"""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)
Прежде чем вернуть эту модель, проверяем, нет ли других, сохраненных в контрольных точках и оставшихся с предыдущих обучающих запусков. Такая модель и ее параметры читаются в переменную и используются. Это позволяет прекратить обучение в контрольной точке и возобновить его не с нуля. Иначе в качестве основного объекта возвращается вновь созданная модель:
Читать дальшеИнтервал:
Закладка: