Używanie wstępnie wytrenowanego osadzania słów (word2vec lub Glove) w TensorFlow

95

Niedawno przejrzałem interesującą implementację klasyfikacji konwolucyjnej tekstu . Jednak cały kod TensorFlow, który sprawdziłem, używa losowych (nie wstępnie wytrenowanych) wektorów osadzających, takich jak następujące:

with tf.device('/cpu:0'), tf.name_scope("embedding"):
    W = tf.Variable(
        tf.random_uniform([vocab_size, embedding_size], -1.0, 1.0),
        name="W")
    self.embedded_chars = tf.nn.embedding_lookup(W, self.input_x)
    self.embedded_chars_expanded = tf.expand_dims(self.embedded_chars, -1)

Czy ktoś wie, jak używać wyników osadzania słów z Word2vec lub wstępnie wytrenowanego słowa GloVe zamiast losowego?

user3147590
źródło

Odpowiedzi:

130

Istnieje kilka sposobów wykorzystania wstępnie wytrenowanego osadzania w TensorFlow. Powiedzmy, że masz osadzenie w tablicy NumPy o nazwie embedding, z vocab_sizewierszami i embedding_dimkolumnami, i chcesz utworzyć tensor, Wktórego można użyć w wywołaniu funkcji tf.nn.embedding_lookup().

  1. Po prostu stwórz Wjako, tf.constant()który przyjmuje embeddingwartość:

    W = tf.constant(embedding, name="W")

    Jest to najłatwiejsze podejście, ale nie jest wydajne pod względem pamięci, ponieważ wartość a tf.constant()jest przechowywana w pamięci wiele razy. Ponieważ embeddingmoże być bardzo duży, tego podejścia należy używać tylko w przypadku zabawek.

  2. Utwórz Wjako a tf.Variablei zainicjalizuj go z tablicy NumPy za pomocą tf.placeholder():

    W = tf.Variable(tf.constant(0.0, shape=[vocab_size, embedding_dim]),
                    trainable=False, name="W")
    
    embedding_placeholder = tf.placeholder(tf.float32, [vocab_size, embedding_dim])
    embedding_init = W.assign(embedding_placeholder)
    
    # ...
    sess = tf.Session()
    
    sess.run(embedding_init, feed_dict={embedding_placeholder: embedding})

    Pozwala to uniknąć przechowywania kopii embeddingna wykresie, ale wymaga wystarczającej ilości pamięci, aby jednocześnie przechowywać dwie kopie macierzy w pamięci (jedną dla tablicy NumPy i jedną dla tf.Variable). Zauważ, że założyłem, że chcesz zachować stałą matrycę osadzania podczas treningu, więc Wjest tworzony za pomocą trainable=False.

  3. Jeśli osadzanie zostało przeszkolone jako część innego modelu TensorFlow, możesz użyć a, tf.train.Saveraby załadować wartość z pliku punktu kontrolnego innego modelu. Oznacza to, że matryca osadzania może całkowicie ominąć Pythona. Utwórz Wjak w opcji 2, a następnie wykonaj następujące czynności:

    W = tf.Variable(...)
    
    embedding_saver = tf.train.Saver({"name_of_variable_in_other_model": W})
    
    # ...
    sess = tf.Session()
    embedding_saver.restore(sess, "checkpoint_filename.ckpt")
mrry
źródło
Tworzę W w następujący sposób: W = np.loadtxt ("/ media / w2vTest.txt", dtype = 'string', delimiter = ''), który tworzy jako wiersz: ['in' '0.070312 ...... „-0,0625”]. Tu są problemy! czy powinienem traktować to jako moje W po usunięciu „in” i przekonwertowaniu liczb z string na float32? jeśli tak jest, to jak połączyć „in” z odpowiednim wektorem? LUB muszę przekonwertować dane na float32, a następnie pozostawić „in” bez zmian; spodziewasz się, że tensorflow wykona wszystkie wymagane procesy? Dzięki!
user3147590
4
Ach, masz tutaj kilka opcji. Państwo mogli skorzystać z TensorFlow tf.decode_csv()op przekonwertować plik tekstowy do tensora, ale może to być drogie (zwłaszcza, że wymaga, aby utworzyć jeden Tensorna kolumnę, a następnie złączyć te numerycznych razem). Być może łatwiejszą alternatywą byłoby użycie pandas.read_csv()i pandas.DataFrame.as_matrix()pobranie danych wejściowych jako tablicy NumPy.
mrry
3
Tablica NumPy powinna zostać usunięta po wywołaniu funkcji sess.run(embedding_init, ...)return (zakładając, że nie przechowujesz odniesienia do niej w swoim programie). W zależności od struktury programu możesz chcieć del embedding(gdzie embeddingjest tablica NumPy) zwolnić tablicę wcześniej.
mrry
1
@mrry: czy możesz powiedzieć więcej o opcji 1, a dokładniej „nie jest to wydajna pamięć, ponieważ wartość tf.constant () jest przechowywana wielokrotnie w pamięci”. Niewystarczająca ilość pamięci dla GPU lub CPU? Mówiąc bardziej ogólnie, dlaczego tf.constant () musi mieć wiele kopii w pamięci, podczas gdy element zastępczy tf.Variable () + karmienie opcji 2 nie ma tego problemu?
Gabriel Parent
1
Jeśli zastanawiasz się również, dlaczego „wartość tf.constant () jest przechowywana wiele razy w pamięci”, spójrz na tę odpowiedź: stackoverflow.com/a/42450418/5841473
alyaxey
33

Używam tej metody do ładowania i udostępniania osadzania.

W = tf.get_variable(name="W", shape=embedding.shape, initializer=tf.constant_initializer(embedding), trainable=False)
LiuJia
źródło
Czy osadzanie powinno być kolumnami lub wierszami w macierzy numpy?
Greyshack,
6

Odpowiedź @mrry nie jest właściwa, ponieważ prowokuje nadpisywanie wag osadzania w każdej sieci, więc jeśli stosujesz podejście minibatch do trenowania sieci, nadpisujesz wagi osadzeń. Tak więc, z mojego punktu widzenia, właściwą drogą do wcześniej wytrenowanego osadzania jest:

embeddings = tf.get_variable("embeddings", shape=[dim1, dim2], initializer=tf.constant_initializer(np.array(embeddings_matrix))
Eugenio Martínez Cámara
źródło
Dokładny duplikat odpowiedzi LiuJia.
TimZaman
4
@TimZaman .. W rzeczywistości brakuje mu argumentu trainable = False, więc ostatecznie dostroi swoje osadzenie w procesie.
Shatu
4
Myślę też, że rozumowanie Eugenio jest błędne. Po prostu nie musisz uruchamiać operacji "embedding_init" przy każdej mini-partii i wszystko będzie dobrze. Oznacza to, że po prostu uruchom inicjalizację osadzania tylko raz na początku uczenia.
Shatu
@Shatu Jak mam zapewnić, że inicjalizacja osadzania jest uruchamiana tylko na początku szkolenia?
1
@ dust0x .. Jeśli rozmiar osadzeń jest wystarczająco mały, możesz po prostu określić je jako wartość początkową. Jeśli są dość duże, możesz je przekazać w feed_dict po uruchomieniu inicjalizatora dla wszystkich zmiennych. Daj mi znać, jeśli nie jest to wystarczająco jasne, a postaram się opublikować przykładowy kod dla obu podejść.
Shatu
6

Odpowiedź zgodna z wersją 2.0 : Istnieje wiele wstępnie wytrenowanych osadzeń, które zostały opracowane przez Google i które zostały oparte na otwartym źródle.

Niektóre z nich są Universal Sentence Encoder (USE), ELMO, BERTitd. I bardzo łatwo jest je ponownie wykorzystać w kodzie.

Kod do ponownego wykorzystania Pre-Trained Embedding,Universal Sentence Encoder przedstawiono poniżej:

  !pip install "tensorflow_hub>=0.6.0"
  !pip install "tensorflow>=2.0.0"

  import tensorflow as tf
  import tensorflow_hub as hub

  module_url = "https://tfhub.dev/google/universal-sentence-encoder/4"
  embed = hub.KerasLayer(module_url)
  embeddings = embed(["A long sentence.", "single-word",
                      "http://example.com"])
  print(embeddings.shape)  #(3,128)

Aby uzyskać więcej informacji na temat wstępnie wytrenowanych osadzeń opracowanych i udostępnionych na zasadach open source przez Google, zapoznaj się z TF Hub Link .

Wsparcie Tensorflow
źródło
5

W przypadku tensorflow w wersji 2 jest to całkiem proste, jeśli używasz warstwy osadzania

X=tf.keras.layers.Embedding(input_dim=vocab_size,
                            output_dim=300,
                            input_length=Length_of_input_sequences,
                            embeddings_initializer=matrix_of_pretrained_weights
                            )(ur_inp)
Fei Yan
źródło
3

Miałem też problem z osadzaniem, więc napisałem szczegółowy samouczek z zestawem danych. Tutaj chciałbym dodać to, co wypróbowałem Możesz też wypróbować tę metodę,

import tensorflow as tf

tf.reset_default_graph()

input_x=tf.placeholder(tf.int32,shape=[None,None])

#you have to edit shape according to your embedding size


Word_embedding = tf.get_variable(name="W", shape=[400000,100], initializer=tf.constant_initializer(np.array(word_embedding)), trainable=False)
embedding_loopup= tf.nn.embedding_lookup(Word_embedding,input_x)

with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        for ii in final_:
            print(sess.run(embedding_loopup,feed_dict={input_x:[ii]}))

Oto szczegółowy przykład samouczka Ipython, jeśli chcesz zrozumieć od zera, spójrz.

Aaditya Ura
źródło