web-dev-qa-db-fra.com

Conversion efficace des jetons en vecteurs Word avec TensorFlow Transform

J'aimerais utiliser TensorFlow Transform pour convertir des jetons en vecteurs Word lors de ma phase de formation, de validation et d'inférence. 

J'ai suivi cette StackOverflow post et implémenté la conversion initiale des jetons en vecteurs. La conversion fonctionne comme prévu et j'obtiens des vecteurs de EMB_DIM pour chaque jeton.

import numpy as np
import tensorflow as tf

tf.reset_default_graph()
EMB_DIM = 10

def load_pretrained_glove():
    tokens = ["a", "cat", "plays", "piano"]
    return tokens, np.random.Rand(len(tokens), EMB_DIM)

# sample string 
string_tensor = tf.constant(["plays", "piano", "unknown_token", "another_unknown_token"])


pretrained_vocab, pretrained_embs = load_pretrained_glove()

vocab_lookup = tf.contrib.lookup.index_table_from_tensor(
    mapping = tf.constant(pretrained_vocab),
    default_value = len(pretrained_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=False)

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.cast(tf.concat([pretrained_embs, unk_embedding], axis=0), tf.float32)
Word_vectors = tf.nn.embedding_lookup(embeddings, string_tensor)

with tf.Session() as sess:
    tf.tables_initializer().run()
    tf.global_variables_initializer().run()
    print(sess.run(Word_vectors))

Lorsque je refactorise le code pour qu'il s'exécute en tant que graphe de transformation TFX, j'obtiens le message d'erreur ConversionError ci-dessous.

import pprint
import tempfile
import numpy as np
import tensorflow as tf
import tensorflow_transform as tft
import tensorflow_transform.beam.impl as beam_impl
from tensorflow_transform.tf_metadata import dataset_metadata
from tensorflow_transform.tf_metadata import dataset_schema

tf.reset_default_graph()

EMB_DIM = 10

def load_pretrained_glove():
    tokens = ["a", "cat", "plays", "piano"]
    return tokens, np.random.Rand(len(tokens), EMB_DIM)


def embed_tensor(string_tensor, trainable=False):
    """
    Convert List of strings into list of indices then into EMB_DIM vectors
    """

    pretrained_vocab, pretrained_embs = load_pretrained_glove()

    vocab_lookup = tf.contrib.lookup.index_table_from_tensor(
        mapping=tf.constant(pretrained_vocab),
        default_value=len(pretrained_vocab))
    string_tensor = vocab_lookup.lookup(string_tensor)

    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)
    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.cast(tf.concat([pretrained_embs, unk_embedding], axis=0), tf.float32)
    return tf.nn.embedding_lookup(embeddings, string_tensor)

def preprocessing_fn(inputs):
    input_string = tf.string_split(inputs['sentence'], delimiter=" ") 
    return {'Word_vectors': tft.apply_function(embed_tensor, input_string)}


raw_data = [{'sentence': 'This is a sample sentence'},]
raw_data_metadata = dataset_metadata.DatasetMetadata(dataset_schema.Schema({
  'sentence': dataset_schema.ColumnSchema(
      tf.string, [], dataset_schema.FixedColumnRepresentation())
}))

with beam_impl.Context(temp_dir=tempfile.mkdtemp()):
    transformed_dataset, transform_fn = (  # pylint: disable=unused-variable
        (raw_data, raw_data_metadata) | beam_impl.AnalyzeAndTransformDataset(
            preprocessing_fn))

    transformed_data, transformed_metadata = transformed_dataset  # pylint: disable=unused-variable
    pprint.pprint(transformed_data)

Message d'erreur

TypeError: Failed to convert object of type <class 
'tensorflow.python.framework.sparse_tensor.SparseTensor'> to Tensor. 
Contents: SparseTensor(indices=Tensor("StringSplit:0", shape=(?, 2), 
dtype=int64), values=Tensor("hash_table_Lookup:0", shape=(?,), 
dtype=int64), dense_shape=Tensor("StringSplit:2", shape=(2,), 
dtype=int64)). Consider casting elements to a supported type.

Questions

  1. Pourquoi l’étape TF Transform nécessiterait-elle une conversion/une conversion supplémentaire?
  2. Cette approche de conversion de jetons en vecteurs Word est-elle réalisable? Les vecteurs Word peuvent avoir plusieurs gigaoctets en mémoire. Comment Apache Beam gère-t-il les vecteurs? Si Transmettre dans une installation distribuée, aurait-il besoin de N x vector memory avec N le nombre de travailleurs?
13
Tony Yotto

L'erreur liée à SparseTensor est due au fait que vous appelez string_split qui renvoie un SparseTensor. Votre code de test n'appelle pas string_split, c'est pourquoi il ne se produit qu'avec votre code de transformation.

En ce qui concerne la mémoire, vous avez raison, la matrice d’incorporation doit être chargée dans chaque opérateur.

3
Kester Tong

On ne peut pas mettre un SparseTensor dans le dictionnaire, renvoyé par TFX Transform, dans votre cas par la fonction "preprocessing_fn". La raison en est que SparseTensor n’est pas un tenseur, c’est en fait un petit sous-graphe. 

Pour corriger votre code, vous pouvez convertir votre SparseTensor en Tenseur. Il y a plusieurs façons de le faire. Je vous recommanderais d'utiliser tf.serialize_sparse pour SparseTensor standard et tf.serialize_many_sparse pour un traitement par lots.

Pour utiliser un tel tenseur sérialisé dans Trainer, vous pouvez appeler la fonction tf. deserialize_many_sparse.

0
Michael Simbirsky