2017-07-15 11 views
12

Jestem ciekawy, w jaki sposób mogę dodać normalnie losowy 300 wektor wymiarowy (elements 'type = tf.float32) za każdym razem, gdy słowo nieznany uprzednio wyszkolonemu słownikowi. Używam wcześniej wyszkolonych embedowań słów GloVe, ale w niektórych przypadkach zdaję sobie sprawę, że napotykam nieznane słowa i chcę stworzyć normalnie losowy wektor słów dla tego nowego nieznanego słowa.Jak dodawać nowe embeddings dla nieznanych słów w Tensorflow (szkolenie i zestaw do testowania)

Problem polega na tym, że przy mojej obecnej konfiguracji używam tf.contrib.lookup.index_table_from_tensor do konwersji słów na liczby całkowite w oparciu o znane słownictwo. Ta funkcja może tworzyć nowe tokeny i mieszać je dla pewnej uprzednio zdefiniowanej liczby słów słów kluczowych, ale moja embed nie będzie zawierać osadzenia dla tej nowej nieznanej wartości hash. Nie jestem pewien, czy mogę po prostu dołączyć losowe osadzanie na końcu listy embed.

Chciałbym również zrobić to w sposób efektywny, więc wcześniej skonstruowana funkcja tensorflow lub metoda obejmująca funkcje tensorflow byłyby prawdopodobnie najbardziej wydajne. Definiuję znane wcześniej specjalne tokeny, takie jak token końca zdania i domyślny nieznany, jako pusty ciąg ("" w indeksie 0), ale ma to ograniczoną zdolność uczenia się różnych nieznanych słów. Obecnie używam tf.nn.embedding_lookup() jako końcowego etapu osadzania.

Chciałbym móc dodawać nowe losowe wektory 300d dla każdego nieznanego słowa w danych treningowych, a także chciałbym dodać gotowe losowe wektory słów dla nieznanych tokenów niewidocznych podczas treningu, które mogą się pojawić podczas testowania. Jaki jest najskuteczniejszy sposób na zrobienie tego?

def embed_tensor(string_tensor, trainable=True): 
    """  
    Convert List of strings into list of indicies then into 300d vectors 
    """ 
    # ordered lists of vocab and corresponding (by index) 300d vector 
    vocab, embed = load_pretrained_glove() 

    # Set up tensorflow look up from string word to unique integer 
    vocab_lookup = tf.contrib.lookup.index_table_from_tensor(
     mapping=tf.constant(vocab), 
     default_value = 0) 
    string_tensor = vocab_lookup.lookup(string_tensor) 

    # define the word embedding 
    embedding_init = tf.Variable(tf.constant(np.asarray(embed), 
           dtype=tf.float32), 
           trainable=trainable, 
           name="embed_init") 

    # return the word embedded version of the sentence (300d vectors/word) 
    return tf.nn.embedding_lookup(embedding_init, string_tensor) 

Odpowiedz

1

Nigdy tego nie próbowałem, ale mogę spróbować podać sposób użycia tych samych maszyn kodu, ale pomyślę o tym później.

Metoda przyjmuje parametr num_oov_buckets, który tasuje wszystkie twoje słowa owalne w predefiniowaną liczbę segmentów.

Jeśli ustawisz ten parametr na pewną "wystarczająco dużą" wartość, zobaczysz, że twoje dane rozprzestrzeniają się wśród tych segmentów (każda łyżka ma identyfikator> ID ostatniego słowa słownika).

Więc

  • if (przy każdym odnośnika) ustawić (tj assign) ostatnie rzędy (odpowiadające wiader) Twojego embedding_init zmienna wartość losową
  • jeśli popełnisz num_oov_buckets wystarczająco duże, że zderzenia zostaną zminimalizowane:

Możesz uzyskać zachowanie, które jest (przybliżenie), o co prosisz w bardzo skuteczny sposób.

Losowe zachowanie może być uzasadnione przez teorię podobną do tej z tablicami mieszającymi: jeśli liczba segmentów jest wystarczająco duża, metoda mieszania łańcuchów przypisze każde z tych słów do innego zasobnika z dużym prawdopodobieństwem (tj. kolizje do tych samych wiader). Ponieważ przypisujesz inną liczbę losową do każdego innego zasobnika, możesz uzyskać (prawie) różne odwzorowanie każdego słowa.

3

Przykładowy kod poniżej dostosowuje swoją funkcję embed_tensor takie, że słowa są osadzone w następujący sposób:

  • Do słów, które mają pretrained osadzanie, osadzanie jest zainicjowany z pretrained osadzania. Osadzenie może być utrwalone podczas treningu, jeśli trainable jest .
  • Dla słów w danych treningowych, które nie mają wstępnego osadzania, osadzanie jest inicjowane losowo. Osadzenie może być utrwalone podczas treningu, jeśli trainable jest .
  • Dla słów w danych testowych, które nie występują w danych treningowych i nie mają wstępnego osadzania, używany jest pojedynczy losowo zainicjowany wektor osadzania. Tego wektora nie można wytrenować.
import tensorflow as tf 
import numpy as np 

EMB_DIM = 300 
def load_pretrained_glove(): 
    return ["a", "cat", "sat", "on", "the", "mat"], np.random.rand(6, EMB_DIM) 

def get_train_vocab(): 
    return ["a", "dog", "sat", "on", "the", "mat"] 

def embed_tensor(string_tensor, trainable=True): 
    """ 
    Convert List of strings into list of indices then into 300d vectors 
    """ 
    # ordered lists of vocab and corresponding (by index) 300d vector 
    pretrained_vocab, pretrained_embs = load_pretrained_glove() 
    train_vocab = get_train_vocab() 
    only_in_train = set(train_vocab) - set(pretrained_vocab) 
    vocab = pretrained_vocab + only_in_train 

    # Set up tensorflow look up from string word to unique integer 
    vocab_lookup = tf.contrib.lookup.index_table_from_tensor(
    mapping=tf.constant(vocab), 
    default_value=len(vocab)) 
    string_tensor = vocab_lookup.lookup(string_tensor) 

    # define the word embedding 
    pretrained_embs = tf.get_variable(
     name="embs_pretrained", 
     initializer=tf.constant_initializer(np.asarray(pretrained_embs), dtype=tf.float32), 
     shape=pretrained_embs.shape, 
     trainable=trainable) 
    train_embeddings = tf.get_variable(
     name="embs_only_in_train", 
     shape=[len(only_in_train), EMB_DIM], 
     initializer=tf.random_uniform_initializer(-0.04, 0.04), 
     trainable=trainable) 
    unk_embedding = tf.get_variable(
     name="unk_embedding", 
     shape=[1, EMB_DIM], 
     initializer=tf.random_uniform_initializer(-0.04, 0.04), 
     trainable=False) 

    embeddings = tf.concat([pretrained_embs, train_embeddings, unk_embedding], axis=0) 

    return tf.nn.embedding_lookup(embeddings, string_tensor) 

FYI, aby mieć rozsądny, nielosowego reprezentację wyrazów, które nie występują w danych treningowych i nie mają pretrained osadzanie, można rozważyć mapowanie słów o niskiej częstotliwości w Twoje dane treningowe do unk token (którego nie ma w twoim słowniku) i sprawiają, że unk_embedding można trenować. W ten sposób uczysz się prototypu słów niewidocznych w danych treningowych.

0

Pomysł, który miałem na ten temat, polegał na uchwyceniu nowych słów do wcześniej przygotowanego osadzania poprzez dodanie nowego wymiaru dla każdego nowego słowa (w zasadzie zachowanie ich gorącej natury).

Zakładając, że liczba nowych słów jest niewielka, ale są one ważne, można na przykład zwiększyć wymiary osadzonych wyników z 300 do 300 + nowych słów, gdzie każde nowe słowo otrzymywałoby wszystkie zera oprócz 1 w swoim wymiar.

Powiązane problemy