Что делает функция tf.nn.embedding_lookup?
tf.nn.embedding_lookup(params, ids, partition_strategy='mod', name=None)
Я не могу понять обязанность этой функции. Это как справочная таблица? Что значит вернуть параметры, соответствующие каждому идентификатору (в идентификаторах)?
Например, в skip-gram
модель, если мы используем tf.nn.embedding_lookup(embeddings, train_inputs)
то для каждого train_input
находит соответствующее вложение?
9 ответов
embedding_lookup
функция извлекает строки params
тензор. Поведение аналогично использованию индексации с массивами в numpy. Например
matrix = np.random.random([1024, 64]) # 64-dimensional embeddings
ids = np.array([0, 5, 17, 33])
print matrix[ids] # prints a matrix of shape [4, 64]
params
Аргумент может быть также списком тензоров, в этом случае ids
будет распределен среди тензоров. Например, дан список из 3 тензоров [2, 64]
поведение по умолчанию таково, что они будут представлять ids
: [0, 3]
, [1, 4]
, [2, 5]
,
partition_strategy
контролирует, как ids
распределяются среди списка. Разделение полезно для более масштабных задач, когда матрица может быть слишком большой, чтобы ее можно было сохранить в одной части.
Да, эту функцию трудно понять, пока вы не поймете смысл.
В простейшем виде он похож на tf.gather
, Возвращает элементы params
в соответствии с индексами, указанными ids
,
Например (при условии, что вы внутри tf.InteractiveSession()
)
params = tf.constant([10,20,30,40])
ids = tf.constant([0,1,2,3])
print tf.nn.embedding_lookup(params,ids).eval()
вернется [10 20 30 40]
потому что первый элемент (индекс 0) params 10
, второй элемент params (индекс 1) 20
, так далее.
Так же,
params = tf.constant([10,20,30,40])
ids = tf.constant([1,1,3])
print tf.nn.embedding_lookup(params,ids).eval()
вернется [20 20 40]
,
Но embedding_lookup
это больше, чем это. params
Аргумент может быть списком тензоров, а не одним тензором.
params1 = tf.constant([1,2])
params2 = tf.constant([10,20])
ids = tf.constant([2,0,2,1,2,3])
result = tf.nn.embedding_lookup([params1, params2], ids)
В таком случае индексы, указанные в ids
, соответствуют элементам тензоров в соответствии со стратегией секционирования, где стратегией секционирования по умолчанию является 'mod'.
В стратегии "mod" индекс 0 соответствует первому элементу первого тензора в списке. Индекс 1 соответствует первому элементу второго тензора. Индекс 2 соответствует первому элементу третьего тензора и т. Д. Просто индекс i
соответствует первому элементу (i+1) -го тензора, для всех индексов 0..(n-1)
, предполагая, что params - это список n
тензоры.
Теперь индекс n
не может соответствовать тензору n+1, потому что список params
содержит только n
тензоры. Итак индекс n
соответствует второму элементу первого тензора. Аналогично, индекс n+1
соответствует второму элементу второго тензора и т. д.
Итак, в коде
params1 = tf.constant([1,2])
params2 = tf.constant([10,20])
ids = tf.constant([2,0,2,1,2,3])
result = tf.nn.embedding_lookup([params1, params2], ids)
Индекс 0 соответствует первому элементу первого тензора: 1
Индекс 1 соответствует первому элементу второго тензора: 10
индекс 2 соответствует второму элементу первого тензора: 2
Индекс 3 соответствует второму элементу второго тензора: 20
Таким образом, результатом будет:
[ 2 1 2 10 2 20]
Да, цель tf.nn.embedding_lookup()
Функция состоит в том, чтобы выполнить поиск в матрице вложения и вернуть вложения (или, проще говоря, векторное представление) слов.
Простая встраиваемая матрица (формы: vocabulary_size x embedding_dimension
) будет выглядеть ниже. (т.е. каждое слово будет представлено вектором чисел; отсюда и название word2vec)
Матрица встраивания
the 0.418 0.24968 -0.41242 0.1217 0.34527 -0.044457 -0.49688 -0.17862
like 0.36808 0.20834 -0.22319 0.046283 0.20098 0.27515 -0.77127 -0.76804
between 0.7503 0.71623 -0.27033 0.20059 -0.17008 0.68568 -0.061672 -0.054638
did 0.042523 -0.21172 0.044739 -0.19248 0.26224 0.0043991 -0.88195 0.55184
just 0.17698 0.065221 0.28548 -0.4243 0.7499 -0.14892 -0.66786 0.11788
national -1.1105 0.94945 -0.17078 0.93037 -0.2477 -0.70633 -0.8649 -0.56118
day 0.11626 0.53897 -0.39514 -0.26027 0.57706 -0.79198 -0.88374 0.30119
country -0.13531 0.15485 -0.07309 0.034013 -0.054457 -0.20541 -0.60086 -0.22407
under 0.13721 -0.295 -0.05916 -0.59235 0.02301 0.21884 -0.34254 -0.70213
such 0.61012 0.33512 -0.53499 0.36139 -0.39866 0.70627 -0.18699 -0.77246
second -0.29809 0.28069 0.087102 0.54455 0.70003 0.44778 -0.72565 0.62309
Я разбил вышеупомянутую матрицу встраивания и загрузил только слова в vocab
который будет нашим словарем и соответствующими векторами в emb
массив.
vocab = ['the','like','between','did','just','national','day','country','under','such','second']
emb = np.array([[0.418, 0.24968, -0.41242, 0.1217, 0.34527, -0.044457, -0.49688, -0.17862],
[0.36808, 0.20834, -0.22319, 0.046283, 0.20098, 0.27515, -0.77127, -0.76804],
[0.7503, 0.71623, -0.27033, 0.20059, -0.17008, 0.68568, -0.061672, -0.054638],
[0.042523, -0.21172, 0.044739, -0.19248, 0.26224, 0.0043991, -0.88195, 0.55184],
[0.17698, 0.065221, 0.28548, -0.4243, 0.7499, -0.14892, -0.66786, 0.11788],
[-1.1105, 0.94945, -0.17078, 0.93037, -0.2477, -0.70633, -0.8649, -0.56118],
[0.11626, 0.53897, -0.39514, -0.26027, 0.57706, -0.79198, -0.88374, 0.30119],
[-0.13531, 0.15485, -0.07309, 0.034013, -0.054457, -0.20541, -0.60086, -0.22407],
[ 0.13721, -0.295, -0.05916, -0.59235, 0.02301, 0.21884, -0.34254, -0.70213],
[ 0.61012, 0.33512, -0.53499, 0.36139, -0.39866, 0.70627, -0.18699, -0.77246 ],
[ -0.29809, 0.28069, 0.087102, 0.54455, 0.70003, 0.44778, -0.72565, 0.62309 ]])
emb.shape
# (11, 8)
Встраивание поиска в TensorFlow
Теперь мы увидим, как мы можем выполнить поиск вложения для произвольного входного предложения.
In [54]: from collections import OrderedDict
# embedding as TF tensor (for now constant; could be tf.Variable() during training)
In [55]: tf_embedding = tf.constant(emb, dtype=tf.float32)
# input for which we need the embedding
In [56]: input_str = "like the country"
# build index based on our `vocabulary`
In [57]: word_to_idx = OrderedDict({w:vocab.index(w) for w in input_str.split() if w in vocab})
# lookup in embedding matrix & return the vectors for the input words
In [58]: tf.nn.embedding_lookup(tf_embedding, list(word_to_idx.values())).eval()
Out[58]:
array([[ 0.36807999, 0.20834 , -0.22318999, 0.046283 , 0.20097999,
0.27515 , -0.77126998, -0.76804 ],
[ 0.41800001, 0.24968 , -0.41242 , 0.1217 , 0.34527001,
-0.044457 , -0.49687999, -0.17862 ],
[-0.13530999, 0.15485001, -0.07309 , 0.034013 , -0.054457 ,
-0.20541 , -0.60086 , -0.22407 ]], dtype=float32)
Посмотрите, как мы получили вложения из нашей исходной матрицы вложения (со словами), используя индексы слов в нашем словаре.
Обычно такой поиск внедрения выполняется первым уровнем (называемым уровнем внедрения), который затем передает эти внедрения уровням RNN/LSTM/GRU для дальнейшей обработки.
Примечание: как правило, словарь также имеет специальный unk
маркер. Таким образом, если токен из нашего входного предложения отсутствует в нашем словаре, то индекс, соответствующий unk
будет найден в матрице встраивания.
PS Обратите внимание, что embedding_dimension
это гиперпараметр, который нужно настроить для своего приложения, но популярные модели, такие как Word2Vec и GloVe, используют 300
размерный вектор для представления каждого слова.
Бонус Чтение word2vec модель скип-грамм
Вот изображение, изображающее процесс встраивания поиска.
Вкратце, он получает соответствующие строки уровня внедрения, заданные списком идентификаторов, и предоставляет его в качестве тензора. Это достигается с помощью следующего процесса.
- Определить заполнитель
lookup_ids = tf.placeholder([10])
- Определите слой встраивания
embeddings = tf.Variable([100,10],...)
- Определить операцию тензорного потока
embed_lookup = tf.embedding_lookup(embeddings, lookup_ids)
- Получить результаты, запустив
lookup = session.run(embed_lookup, feed_dict={lookup_ids:[95,4,14]})
Когда тензор параметров имеет большие размеры, идентификаторы относятся только к верхнему размеру. Может быть, это очевидно для большинства людей, но я должен запустить следующий код, чтобы понять это:
embeddings = tf.constant([[[1,1],[2,2],[3,3],[4,4]],[[11,11],[12,12],[13,13],[14,14]],
[[21,21],[22,22],[23,23],[24,24]]])
ids=tf.constant([0,2,1])
embed = tf.nn.embedding_lookup(embeddings, ids, partition_strategy='div')
with tf.Session() as session:
result = session.run(embed)
print (result)
Просто пробуя стратегию div и для одного тензора, это не имеет значения.
Вот вывод:
[[[ 1 1]
[ 2 2]
[ 3 3]
[ 4 4]]
[[21 21]
[22 22]
[23 23]
[24 24]]
[[11 11]
[12 12]
[13 13]
[14 14]]]
Поскольку эта функция меня тоже заинтриговала, я дам свои два цента.
То, как я это вижу в двумерном случае, является просто умножением матрицы (его легко обобщить в другие измерения).
Рассмотрим словарь с N символов. Затем вы можете представить символ x в виде вектора измерений Nx1 с горячим кодированием.
Но вы хотите, чтобы представление этого символа было не вектором Nx1, а вектором с размерами Mx1, называемым y.
Итак, чтобы преобразовать x в y, вы можете использовать и встраивать матрицу E с размерами MxN:
y = E x.
По сути, это то, что делает tf.nn.embedding_lookup(params, ids, ...), с нюансом, что ids - это просто одно число, представляющее позицию 1 в векторе с горячим кодированием x.
Другой способ взглянуть на это - предположить, что выровняли тензоры в одномерном массиве, а затем выполняете поиск
(например) Tensor0=[1,2,3], Tensor1=[4,5,6], Tensor2=[7,8,9]
Выровненный тензор будет следующим [1,4,7,2,5,8,3,6,9]
Теперь, когда вы сделаете поиск [0,3,4,1,7], вы получите [1,2,5,4,6]
(i, e) если значение поиска равно 7, например, и у нас есть 3 тензора (или тензор с 3 строками), тогда,
7/3: (Напоминание 1, Коэффициент 2) Так что будет показан 2-й элемент Tensor1, который равен 6
Существующих объяснений недостаточно. Основная цель этой функции — эффективно извлекать векторы для каждого слова в заданной последовательности индексов слов. Предположим, у нас есть следующая матрица вложений:
embds = np.array([[0.2, 0.32,0.9],
[0.8, 0.62,0.19],
[0.0, -0.22,-1.9],
[1.2, 2.32,6.0],
[0.11, 0.10,5.9]])
Допустим, у нас есть следующие последовательности индексов слов:
data=[[0,1],
[3,4]]
Теперь, чтобы получить соответствующее вложение для каждого слова в наших данных:
tf.nn.embedding_lookup(
embds, data
)
вне:
array([[[0.2 , 0.32, 0.9 ],
[0.8 , 0.62, 0.19]],
[[1.2 , 2.32, 6. ],
[0.11, 0.1 , 5.9 ]]])>
Примечание. Если embds не является массивом или тензором, вывод будет не таким (не буду вдаваться в подробности). Например, если бы embds были списком, вывод был бы таким:
array([[0.2 , 0.32],
[0.8 , 0.62]], dtype=float32)>
Добавляя к ответу Ашера Стерна, params
интерпретируется как разбиение большого тензора вложения. Это может быть один тензор, представляющий полный тензор вложения, или список X-тензоров, имеющих одинаковую форму, за исключением первого измерения, представляющего тензеры вложения с осколками.
Функция tf.nn.embedding_lookup
написано с учетом того, что вложение (params) будет большим. Поэтому нам нужно partition_strategy
,