python - Tensorflow One Hot Encoder?
placeholder in tensorflow (14)
¿Tensorflow tiene algo similar al codificador activo de scikit learn para procesar datos categóricos? ¿Usar un marcador de posición de tf.string se comportaría como datos categóricos?
Me doy cuenta de que puedo preprocesar manualmente los datos antes de enviarlos a Tensorflow, pero tenerlos integrados es muy conveniente.
A partir de TensorFlow 0.8, ahora hay una
tf.one_hot
nativa de un solo uso,
tf.one_hot
,
que puede convertir un conjunto de etiquetas dispersas en una representación densa de un solo calor.
Esto se suma a
tf.nn.sparse_softmax_cross_entropy_with_logits
, que en algunos casos puede permitirle calcular la entropía cruzada directamente en las etiquetas dispersas en lugar de convertirlas en un hot.
Respuesta anterior, en caso de que quiera hacerlo a la antigua usanza: la respuesta de @ Salvador es correcta: (solía haber) ninguna operación nativa para hacerlo. Sin embargo, en lugar de hacerlo en numpy, puede hacerlo de forma nativa en flujo de tensor utilizando los operadores dispersos a densos:
num_labels = 10
# label_batch is a tensor of numeric labels to process
# 0 <= label < num_labels
sparse_labels = tf.reshape(label_batch, [-1, 1])
derived_size = tf.shape(label_batch)[0]
indices = tf.reshape(tf.range(0, derived_size, 1), [-1, 1])
concated = tf.concat(1, [indices, sparse_labels])
outshape = tf.pack([derived_size, num_labels])
labels = tf.sparse_to_dense(concated, outshape, 1.0, 0.0)
La salida, etiquetas, es una matriz única de lote_tamaño x número_etiquetas.
Tenga en cuenta también que a partir del 12/02/2016 (que supongo que eventualmente formará parte de una versión 0.7), TensorFlow también tiene el
tf.nn.sparse_softmax_cross_entropy_with_logits
op, que en algunos casos puede permitirle hacer entrenamiento sin necesidad de convertirse a un codificación one-hot.
Editado para agregar: al final, es posible que deba establecer explícitamente la forma de las etiquetas. La inferencia de forma no reconoce el tamaño del componente num_labels. Si no necesita un tamaño de lote dinámico con derivado de tamaño, esto se puede simplificar.
Editado el 12/02/2016 para cambiar la asignación de outhape por comentario a continuación.
Como se mencionó anteriormente por @dga, Tensorflow tiene tf.one_hot ahora:
labels = tf.constant([5,3,2,4,1])
highest_label = tf.reduce_max(labels)
labels_one_hot = tf.one_hot(labels, highest_label + 1)
array([[ 0., 0., 0., 0., 0., 1.],
[ 0., 0., 0., 1., 0., 0.],
[ 0., 0., 1., 0., 0., 0.],
[ 0., 0., 0., 0., 1., 0.],
[ 0., 1., 0., 0., 0., 0.]], dtype=float32)
Debes especificar la profundidad, de lo contrario obtendrás un tensor podado de un solo calor.
Si te gusta hacerlo manualmente:
labels = tf.constant([5,3,2,4,1])
size = tf.shape(labels)[0]
highest_label = tf.reduce_max(labels)
labels_t = tf.reshape(labels, [-1, 1])
indices = tf.reshape(tf.range(size), [-1, 1])
idx_with_labels = tf.concat([indices, labels_t], 1)
labels_one_hot = tf.sparse_to_dense(idx_with_labels, [size, highest_label + 1], 1.0)
array([[ 0., 0., 0., 0., 0., 1.],
[ 0., 0., 0., 1., 0., 0.],
[ 0., 0., 1., 0., 0., 0.],
[ 0., 0., 0., 0., 1., 0.],
[ 0., 1., 0., 0., 0., 0.]], dtype=float32)
Observe el orden de los argumentos en tf.concat ()
Echa un vistazo a tf.nn.embedding_lookup . Asigna desde ID categóricas a sus incrustaciones.
Para ver un ejemplo de cómo se usa para los datos de entrada, consulte here .
Hay embedding_ops en Scikit Flow y ejemplos que tratan con variables categóricas, etc.
Si recién comienza a aprender TensorFlow, le sugiero que TensorFlow/skflow examples en TensorFlow/skflow primero y luego, una vez que esté más familiarizado con TensorFlow, sería bastante fácil insertar el código TensorFlow para crear el modelo personalizado que desee (hay también ejemplos para esto).
¡Espero que esos ejemplos de comprensión de imágenes y texto puedan ayudarlo a comenzar y háganos saber si encuentra algún problema! (publicar problemas o etiquetar skflow en SO).
Hay un par de formas de hacerlo.
ans = tf.constant([[5, 6, 0, 0], [5, 6, 7, 0]]) #batch_size*max_seq_len
labels = tf.reduce_sum(tf.nn.embedding_lookup(np.identity(10), ans), 1)
>>> [[ 0. 0. 0. 0. 0. 1. 1. 0. 0. 0.]
>>> [ 0. 0. 0. 0. 0. 1. 1. 1. 0. 0.]]
La otra forma de hacerlo es.
labels2 = tf.reduce_sum(tf.one_hot(ans, depth=10, on_value=1, off_value=0, axis=1), 2)
>>> [[0 0 0 0 0 1 1 0 0 0]
>>> [0 0 0 0 0 1 1 1 0 0]]
Las versiones actuales de tensorflow implementan la siguiente función para crear tensores de un solo calor:
Las versiones recientes de TensorFlow (nightlies y quizás incluso 0.7.1) tienen una operación llamada tf.one_hot que hace lo que quieres. ¡Echale un vistazo!
Por otro lado, si tiene una matriz densa y desea buscar y agregar valores en ella, debería usar la función embedding_lookup.
Mi versión del ejemplo @CFB y @dga, se acortó un poco para facilitar la comprensión.
num_labels = 10
labels_batch = [2, 3, 5, 9]
sparse_labels = tf.reshape(labels_batch, [-1, 1])
derived_size = len(labels_batch)
indices = tf.reshape(tf.range(0, derived_size, 1), [-1, 1])
concated = tf.concat(1, [indices, sparse_labels])
labels = tf.sparse_to_dense(concated, [derived_size, num_labels], 1.0, 0.0)
Puede usar tf.sparse_to_dense :
El argumento sparse_indices indica a dónde deben ir las unidades, output_shape debe establecerse en el número de salidas posibles (por ejemplo, el número de etiquetas) y sparse_values debe ser 1 con el tipo deseado (determinará el tipo de salida del tipo de valores dispersos).
Tal vez se deba a cambios en Tensorflow desde noviembre de 2015, pero la respuesta de @ dga produjo errores. Lo hice funcionar con las siguientes modificaciones:
sparse_labels = tf.reshape(label_batch, [-1, 1])
derived_size = tf.shape(sparse_labels)[0]
indices = tf.reshape(tf.range(0, derived_size, 1), [-1, 1])
concated = tf.concat(1, [indices, sparse_labels])
outshape = tf.concat(0, [tf.reshape(derived_size, [1]), tf.reshape(num_labels, [1])])
labels = tf.sparse_to_dense(concated, outshape, 1.0, 0.0)
Una forma simple y corta de codificar en caliente cualquier número entero o lista de números enteros:
a = 5
b = [1, 2, 3]
# one hot an integer
one_hot_a = tf.nn.embedding_lookup(np.identity(10), a)
# one hot a list of integers
one_hot_b = tf.nn.embedding_lookup(np.identity(max(b)+1), b)
tf.one_hot()
está disponible en TF y es fácil de usar.
Supongamos que tiene 4 categorías posibles (gato, perro, pájaro, humano) y 2 instancias (gato, humano).
Entonces tu
depth=4
y tus
indices=[0, 3]
import tensorflow as tf
res = tf.one_hot(indices=[0, 3], depth=4)
with tf.Session() as sess:
print sess.run(res)
Tenga en cuenta que si proporciona index = -1 obtendrá todos los ceros en su vector único.
Antigua respuesta, cuando esta función no estaba disponible.
Después de mirar la
documentación de Python
, no he encontrado nada similar.
Una cosa que fortalece mi creencia de que no existe es que, en
su propio ejemplo
, escriben
one_hot
manualmente.
def dense_to_one_hot(labels_dense, num_classes=10):
"""Convert class labels from scalars to one-hot vectors."""
num_labels = labels_dense.shape[0]
index_offset = numpy.arange(num_labels) * num_classes
labels_one_hot = numpy.zeros((num_labels, num_classes))
labels_one_hot.flat[index_offset + labels_dense.ravel()] = 1
return labels_one_hot
También puedes hacer esto en scikitlearn .
numpy
hace!
import numpy as np
np.eye(n_labels)[target_vector]
In [7]: one_hot = tf.nn.embedding_lookup(np.eye(5), [1,2])
In [8]: one_hot.eval()
Out[8]:
array([[ 0., 1., 0., 0., 0.],
[ 0., 0., 1., 0., 0.]])
funciona en TF versión 1.3.0. A partir de septiembre de 2017.