Это целевая функция, которую мы желаем минимизировать (при оптимальном сценарии, в котором производительность модели идеальна, значение будет равно –1). NCE в TensorFlow реализуется следующим фрагментом кода:
tf.nn.nce_loss(weights, biases, inputs, labels, num_sampled,
num_classes, num_true=1, sampled_values=None,
remove_accidental_hits=False, partition_strategy=‘mod',
name='nce_loss')
Веса (weights) должны иметь ту же размерность, что и матрица плотных векторных представлений, а смещения (biases) — быть тензорами с размером, эквивалентным размеру словаря. Входные значения (inputs) — результаты из таблицы представлений, num_sampled, число отрицательных образцов, использованных при вычислении NCE, а num_classes — размер словаря.
Хотя Word2Vec не относится к моделям глубокого обучения, мы обсуждаем этот инструмент по ряду причин. Во-первых, он представляет стратегию (нахождение плотных векторных представлений по контексту), которая обобщается до многих моделей глубокого обучения. Когда в главе 7 мы будем рассматривать модели для анализа последовательностей, мы увидим реализацию этой стратегии для порождения векторов с компактным представлением предложений. Более того, когда мы начнем строить все больше языковых моделей, окажется, что плотные векторные представления Word2Vec для слов обеспечивают гораздо лучшие результаты, чем прямые унитарные векторы.
Теперь понятно, как строить модель Skip-Gram, мы оценили ее важность. Пора реализовать ее в TensorFlow.
Реализация архитектуры Skip-Gram
Чтобы построить набор данных для модели Skip-Gram, воспользуемся модифицированной версией программы чтения данных в TensorFlow Word2Vec — input_word_data.py. Для начала зададим пару важных параметров для обучения и регулярной проверки модели. Мы берем мини-пакет из 32 примеров и обучаем в течение пяти эпох (полных проходов по всему набору данных). Будем пользоваться плотными векторными представлениями размера 128. Зададим контекстное окно в пять слов слева и справа от каждого текущего и семплируем четыре контекстных слова из этого окна. Наконец, возьмем 64 случайно выбранных неконтекстных слова для NCE.
Реализация слоя, строящего плотные векторные представления, не особенно сложна. Достаточно инициализировать таблицу матрицей значений:
def embedding_layer(x, embedding_shape):
with tf.variable_scope("embedding"):
embedding_init = tf.random_uniform(embedding_shape, -1.0, 1.0)
embedding_matrix = tf.get_variable("E", initializer=embedding_init)
return tf.nn.embedding_lookup(embedding_matrix, x),
embedding_matrix
Воспользуемся встроенным в TensorFlow вариантом tf.nn.nce_loss для вычисления потерь NCE на каждом обучающем примере, а затем соберем все результаты по мини-пакету в единый показатель:
def noise_contrastive_loss(embedding_lookup, weight_shape, bias_shape, y):
with tf.variable_scope("nce"):
nce_weight_init = tf.truncated_normal(weight_shape, stddev=1.0/(
weight_shape[1])**0.5)
nce_bias_init = tf.zeros(bias_shape)
nce_W = tf.get_variable("W", initializer=nce_weight_init)
nce_b = tf.get_variable("b", initializer=nce_bias_init)
total_loss = tf.nn.nce_loss(nce_W, nce_b, embedding_lookup, y, neg_size, data.vocabulary_size)
return tf.reduce_mean(total_loss)
Наша целевая функция выражена как среднее потерь NCE, и мы запускаем обучение обычным путем. Здесь мы следуем по стопам Миколова и коллег и задействуем стохастический градиентный спуск с темпом обучения 0,1:
def training(cost, global_step):
with tf.variable_scope("training"):
summary_op = tf.scalar_summary("cost", cost)
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
train_op = optimizer.minimize(cost, global_step=global_step)
return train_op, summary_op
Также мы регулярно проверяем модель с помощью функции, которая нормализует плотные векторные представления в таблице и использует косинусную меру близости, чтобы вычислить расстояния для набора проверочных слов до всех остальных в словаре:
def validation(embedding_matrix, x_val):
norm = tf.reduce_sum(embedding_matrix**2, 1, keep_dims=True)**0.5
normalized = embedding_matrix/norm
val_embeddings = tf.nn.embedding_lookup(normalized, x_val)
cosine_similarity = tf.matmul(val_embeddings, normalized, transpose_b=True)
return normalized, cosine_similarity
Сведя вместе все компоненты, мы готовы запустить модель Skip-Gram. Этот фрагмент кода даем без комментариев, ведь он очень похож на прежние модели. Единственная разница — дополнительный код на шаге проверки. Мы случайным образом выбираем 20 слов из 500 самых распространенных в словаре из 10 000 единиц. Для каждого мы используем построенную ранее функцию косинусной меры близости, чтобы найти ближайших соседей:
if __name__ == ‘__main__':
with tf.Graph(). as_default():
with tf.variable_scope("skipgram_model"):
x = tf.placeholder(tf.int32, shape=[batch_size])
y = tf.placeholder(tf.int32, [batch_size, 1])
val = tf.constant(val_examples, dtype=tf.int32)
global_step = tf.Variable(0, name='global_step', trainable=False)
e_lookup, e_matrix = embedding_layer(x,
[data.vocabulary_size, embedding_size])
cost = noise_contrastive_loss(e_lookup,
[data.vocabulary_size, embedding_size],
[data.vocabulary_size], y)
train_op, summary_op = training(cost, global_step)
val_op = validation(e_matrix, val)
Читать дальше
Конец ознакомительного отрывка
Купить книгу