web-dev-qa-db-fra.com

Comment ajouter de nouvelles intégrations de mots inconnus dans Tensorflow (formation et pré-réglage pour les tests)

Je suis curieux de savoir comment ajouter un vecteur de dimension 300 aléatoire normal (éléments de type = tf.float32) chaque fois qu'un mot inconnu du vocabulaire pré-formé est rencontré. J'utilise des systèmes GloVe Word pré-formés, mais dans certains cas, je me rends compte que je rencontre des mots inconnus et que je souhaite créer un vecteur Word normal-aléatoire pour ce nouveau mot inconnu. 

Le problème est qu'avec ma configuration actuelle, j'utilise tf.contrib.lookup.index_table_from_tensor pour convertir des mots en entiers en fonction du vocabulaire connu. Cette fonction peut créer de nouveaux jetons et les hacher pour un nombre prédéfini de mots hors vocabulaire, mais ma embed ne contiendra pas d'incorporation de cette nouvelle valeur de hachage inconnue. Je ne sais pas si je peux simplement ajouter une incorporation aléatoire à la fin de la liste embed.

Je voudrais aussi le faire de manière efficace, de sorte qu'une fonction ou une méthode de tensorflow prédéfinie impliquant des fonctions de tensorflow serait probablement la plus efficace. Je définis des jetons spéciaux pré-connus tels qu'un jeton de fin de phrase et un inconnu par défaut comme étant la chaîne vide ("à l'index 0), mais son pouvoir d'apprentissage est limité pour différents mots inconnus. J'utilise actuellement tf .nn.embedding_lookup () en tant que dernière étape d'intégration.

J'aimerais pouvoir ajouter de nouveaux vecteurs 300d aléatoires pour chaque mot inconnu dans les données de formation, ainsi que des vecteurs de mot aléatoires prédéfinis pour tous les jetons inconnus non vus au cours de la formation et éventuellement rencontrés lors des tests. Quel est le moyen le plus efficace de le faire?

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)
17
prijatelj

L'exemple de code ci-dessous adapte votre fonction embed_tensor de sorte que les mots soient incorporés comme suit:

  • Pour les mots ayant une insertion pré-entraînée, l’incorporation est initialisée avec l’incorporation pré-entraînée. L’intégration peut être conservée pendant l’entraînement si trainable est False.
  • Pour les mots dans les données d'apprentissage qui n'ont pas d'incorporation pré-entraînée, l'intégration est initialisée de manière aléatoire. L’intégration peut être conservée pendant l’entraînement si trainable est False.
  • Pour les mots dans les données de test qui ne figurent pas dans les données d'apprentissage et qui n'ont pas une incorporation pré-entraînée, un seul vecteur d'intégration initialisé aléatoirement est utilisé. Ce vecteur ne peut pas être formé.
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 = list(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)

Pour votre information, afin d’obtenir une représentation raisonnable et non aléatoire des mots qui ne figurent pas dans les données d’entraînement et qui n’ont pas une incorporation pré-entraînée, vous pouvez envisager de mapper des mots avec une faible fréquence dans vos données d’entraînement sur un jeton unk. (ce n'est pas dans votre vocabulaire) et rendre le unk_embedding apte à être entraîné. De cette façon, vous apprenez un prototype pour les mots qui ne sont pas vus dans les données d'apprentissage.

9
GeertH

Je n'ai jamais essayé, mais je peux essayer de trouver un moyen d'utiliser les mêmes mécanismes que votre code, mais j'y penserai plus tard.

La méthode index_table_from_tensor accepte un paramètre num_oov_buckets qui mélange tous vos mots vides dans un nombre prédéfini de compartiments. 

Si vous définissez ce paramètre sur une valeur "assez grande", vos données se répartiront entre ces compartiments (chaque compartiment contient un ID> ID du dernier mot en vocabulaire).

Alors,

  • si (à chaque recherche) vous définissez (c'est-à-dire assign) les dernières lignes (celles correspondant aux compartiments) de votre variable embedding_init à une valeur aléatoire
  • si vous faites num_oov_bucketssimple assez grand que les collisions seront minimisées

vous pouvez obtenir un comportement qui est (approximativement) ce que vous demandez de manière très efficace.

Le comportement aléatoire peut être justifié par une théorie similaire à celle de la table de hachage: si le nombre de compartiments est suffisamment grand, la méthode de hachage des chaînes affectera chaque mot oov à un compartiment différent avec une probabilité élevée seaux). Étant donné que vous attribuez un nombre aléatoire différent à chaque compartiment, vous pouvez obtenir un mappage (presque) différent de chaque mot oov.

3
Giuseppe Marra

Une idée que j’avais pour cela était de capturer les nouveaux mots de l’intégration pré-entraînée en ajoutant une nouvelle dimension à chaque nouveau mot (en maintenant essentiellement la nature unique de ces mots). 

En supposant que le nombre de nouveaux mots soit petit mais important, vous pouvez par exemple augmenter les dimensions de vos résultats incorporés de 300 à 300 + # de nouveaux mots, chaque nouveau mot contenant tous les zéros sauf un dans sa dimension.

0
Alex Schokking