tf.nn.embedding_lookup(params, ids, partition_strategy='mod', name=None)
Não consigo entender o dever dessa função. É como uma tabela de pesquisa? O que significa retornar os parâmetros correspondentes a cada ID (em IDs)?
Por exemplo, no skip-gram
modelo se usarmos tf.nn.embedding_lookup(embeddings, train_inputs)
, então para cada train_input
um deles ele encontrará a incorporação correspondente?
Respostas:
embedding_lookup
A função recupera linhas doparams
tensor. O comportamento é semelhante ao uso de indexação com matrizes numpy. Por exemploparams
O argumento também pode ser uma lista de tensores; nesse caso,ids
eles serão distribuídos entre os tensores. Por exemplo, dada uma lista de 3 tensores[2, 64]
, o comportamento padrão é que eles vão representarids
:[0, 3]
,[1, 4]
,[2, 5]
.partition_strategy
controla a maneira como osids
são distribuídos entre a lista. O particionamento é útil para problemas de escala maiores quando a matriz pode ser muito grande para ser mantida em uma única peça.fonte
select_rows
?embedding_lookup
simplesmente fornece uma maneira conveniente (e paralela) de recuperar incorporações correspondentes ao IDids
. Oparams
tensor geralmente é uma variável tf que é aprendida como parte do processo de treinamento - uma variável tf cujos componentes são usados, direta ou indiretamente, em uma função de perda (comotf.l2_loss
) que é otimizada por um otimizador (comotf.train.AdamOptimizer
).Sim, esta função é difícil de entender, até você entender.
Na sua forma mais simples, é semelhante a
tf.gather
. Retorna os elementos deparams
acordo com os índices especificados porids
.Por exemplo (supondo que você esteja lá dentro
tf.InteractiveSession()
)retornaria
[10 20 30 40]
, porque o primeiro elemento (índice 0) dos parâmetros é10
o segundo elemento dos parâmetros (índice 1)20
etc.Similarmente,
voltaria
[20 20 40]
.Mas
embedding_lookup
é mais do que isso. Oparams
argumento pode ser uma lista de tensores, em vez de um único tensor.Nesse caso, os índices especificados em
ids
correspondem aos elementos dos tensores de acordo com uma estratégia de partição , onde a estratégia de partição padrão é 'mod'.Na estratégia 'mod', o índice 0 corresponde ao primeiro elemento do primeiro tensor na lista. O índice 1 corresponde ao primeiro elemento do segundo tensor. O índice 2 corresponde ao primeiro elemento do terceiro tensor e assim por diante. Simplesmente o índice
i
corresponde ao primeiro elemento do (i + 1) th tensor, para todos os índices0..(n-1)
, assumindo que os parâmetros são uma lista den
tensores.Agora, o índice
n
não pode corresponder ao tensor n + 1, porque a listaparams
contém apenasn
tensores. Portanto, o índicen
corresponde ao segundo elemento do primeiro tensor. Da mesma forma, o índicen+1
corresponde ao segundo elemento do segundo tensor, etc.Então, no código
O índice 0 corresponde ao primeiro elemento do primeiro tensor: 1
o índice 1 corresponde ao primeiro elemento do segundo tensor: 10
o índice 2 corresponde ao segundo elemento do primeiro tensor: 2
o índice 3 corresponde ao segundo elemento do segundo tensor: 20
Assim, o resultado seria:
fonte
partition_strategy='div'
e obteria[10, 1, 10, 2, 10, 20]
, ou seja,id=1
é o segundo elemento do primeiro parâmetro. Basicamente:partition_strategy=mod
(padrão)id%len(params)
: índice do parâmetro nos parâmetrosid//len(params)
: índice do elemento no parâmetro acimapartition_strategy=*div*
ao contrárioSim, o objetivo da
tf.nn.embedding_lookup()
função é realizar uma pesquisa na matriz de incorporação e retornar os incorporamentos (ou, em termos simples, a representação vetorial) das palavras.Uma matriz de incorporação simples (de forma :)
vocabulary_size x embedding_dimension
seria semelhante a abaixo. (ou seja, cada palavra será representada por um vetor de números; daí o nome word2vec )Matriz de incorporação
Dividi a matriz de incorporação acima e carreguei apenas as palavras em
vocab
que será o nosso vocabulário e os vetores correspondentes naemb
matriz.Incorporando pesquisa no TensorFlow
Agora veremos como podemos realizar a pesquisa de incorporação para alguma sentença de entrada arbitrária.
Observe como obtivemos as incorporação de nossa matriz de incorporação original (com palavras) usando os índices de palavras em nosso vocabulário.
Normalmente, essa pesquisa de incorporação é realizada pela primeira camada (chamada camada de incorporação ), que passa essas incorporação para as camadas RNN / LSTM / GRU para processamento adicional.
Nota : Normalmente, o vocabulário também terá um
unk
token especial . Portanto, se um token de nossa frase de entrada não estiver presente em nosso vocabulário, o índice correspondenteunk
será pesquisado na matriz de incorporação.PS Observe que
embedding_dimension
é um hiperparâmetro que é necessário ajustar para sua aplicação, mas modelos populares como Word2Vec e GloVe usam300
vetor de dimensão para representar cada palavra.Bônus de leitura word2vec skip-gram model
fonte
Aqui está uma imagem que descreve o processo de incorporação da pesquisa.
Concisa, ele obtém as linhas correspondentes de uma camada de incorporação, especificadas por uma lista de IDs e fornece isso como um tensor. É alcançado através do seguinte processo.
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]})
fonte
Quando o tensor dos parâmetros está em altas dimensões, os IDs se referem apenas à dimensão superior. Talvez seja óbvio para a maioria das pessoas, mas eu tenho que executar o seguinte código para entender isso:
Apenas tentando a estratégia 'div' e para um tensor, não faz diferença.
Aqui está a saída:
fonte
Outra maneira de ver isso é, suponha que você alise os tensores em uma matriz dimensional e, em seguida, faça uma pesquisa
(por exemplo) Tensor0 = [1,2,3], Tensor1 = [4,5,6], Tensor2 = [7,8,9]
O tensor achatado será o seguinte [1,4,7,2,5,8,3,6,9]
Agora, quando você fizer uma pesquisa de [0,3,4,1,7], ele exibirá [1,2,5,4,6]
(i, e) se o valor da pesquisa for 7, por exemplo, e tivermos 3 tensores (ou um tensor com 3 linhas),
7/3: (Lembrete é 1, Quociente é 2) Portanto, o segundo elemento do Tensor1 será mostrado, que é 6
fonte
Como também fiquei intrigado com essa função, darei meus dois centavos.
A maneira como vejo isso no caso 2D é apenas uma multiplicação de matrizes (é fácil generalizar para outras dimensões).
Considere um vocabulário com N símbolos. Então, você pode representar um símbolo x como um vetor de dimensões Nx1, codificado um a quente.
Mas você deseja uma representação desse símbolo não como um vetor de Nx1, mas como um com as dimensões Mx1, chamado y .
Portanto, para transformar x em y , você pode usar e incorporar a matriz E , com as dimensões MxN:
y = E x .
Isso é essencialmente o que tf.nn.embedding_lookup (params, ids, ...) está fazendo, com a nuance de que ids são apenas um número que representa a posição do 1 no vetor x um codificado a quente .
fonte
Adicionando à resposta de Asher Stern,
params
é interpretado como um particionamento de um grande tensor de incorporação. Pode ser um único tensor representando o tensor de incorporação completo ou uma lista de tensores X com a mesma forma, exceto na primeira dimensão, representando tensores de incorporação fragmentados.A função
tf.nn.embedding_lookup
é escrita considerando o fato de que a incorporação (parâmetros) será grande. Portanto, precisamospartition_strategy
.fonte