¿Hay alguna manera de convertir un tensor denso en un tensor disperso? Aparentemente, el Estimator.fit de Tensorflow no acepta SparseTensors como tags. Una razón por la que me gustaría pasar SparseTensors al Estimator.fit de Tensorflow es poder usar tensorflow ctc_loss. Aquí está el código:
import dataset_utils import tensorflow as tf import numpy as np from tensorflow.contrib import grid_rnn, learn, layers, framework def grid_rnn_fn(features, labels, mode): input_layer = tf.reshape(features["x"], [-1, 48, 1596]) indices = tf.where(tf.not_equal(labels, tf.constant(0, dtype=tf.int32))) values = tf.gather_nd(labels, indices) sparse_labels = tf.SparseTensor(indices, values, dense_shape=tf.shape(labels, out_type=tf.int64)) cell_fw = grid_rnn.Grid2LSTMCell(num_units=128) cell_bw = grid_rnn.Grid2LSTMCell(num_units=128) bidirectional_grid_rnn = tf.nn.bidirectional_dynamic_rnn(cell_fw, cell_bw, input_layer, dtype=tf.float32) outputs = tf.reshape(bidirectional_grid_rnn[0], [-1, 256]) W = tf.Variable(tf.truncated_normal([256, 80], stddev=0.1, dtype=tf.float32), name='W') b = tf.Variable(tf.constant(0., dtype=tf.float32, shape=[80], name='b')) logits = tf.matmul(outputs, W) + b logits = tf.reshape(logits, [tf.shape(input_layer)[0], -1, 80]) logits = tf.transpose(logits, (1, 0, 2)) loss = None train_op = None if mode != learn.ModeKeys.INFER: #Error occurs here loss = tf.nn.ctc_loss(inputs=logits, labels=sparse_labels, sequence_length=320) ... # returning ModelFnOps def main(_): image_paths, labels = dataset_utils.read_dataset_list('../test/dummy_labels_file.txt') data_dir = "../test/dummy_data/" images = dataset_utils.read_images(data_dir=data_dir, image_paths=image_paths, image_extension='png') print('Done reading images') images = dataset_utils.resize(images, (1596, 48)) images = dataset_utils.transpose(images) labels = dataset_utils.encode(labels) x_train, x_test, y_train, y_test = dataset_utils.split(features=images, test_size=0.5, labels=labels) train_input_fn = tf.estimator.inputs.numpy_input_fn( x={"x": np.array(x_train)}, y=np.array(y_train), num_epochs=1, shuffle=True, batch_size=1 ) classifier = learn.Estimator(model_fn=grid_rnn_fn, model_dir="/tmp/grid_rnn_ocr_model") classifier.fit(input_fn=train_input_fn)
ACTUALIZACIÓN :
Resulta que esta solución desde aquí convierte el tensor denso en uno disperso:
indices = tf.where(tf.not_equal(labels, tf.constant(0, dtype=tf.int32))) values = tf.gather_nd(labels, indices) sparse_labels = tf.SparseTensor(indices, values, dense_shape=tf.shape(labels, out_type=tf.int64))
Sin embargo, encuentro este error ahora provocado por ctc_loss:
ValueError: Shape must be rank 1 but is rank 0 for 'CTCLoss' (op: 'CTCLoss') with input shapes: [?,?,80], [?,2], [?], [].
Tengo este código que convierte tags densas en dispersas:
def convert_to_sparse(labels, dtype=np.int32): indices = [] values = [] for n, seq in enumerate(labels): indices.extend(zip([n] * len(seq), range(len(seq)))) values.extend(seq) indices = np.asarray(indices, dtype=dtype) values = np.asarray(values, dtype=dtype) shape = np.asarray([len(labels), np.asarray(indices).max(0)[1] + 1], dtype=dtype) return indices, values, shape
y_train
en tags dispersas, y SparseTensor
los valores dentro de un SparseTensor
:
sparse_y_train = convert_to_sparse(y_train) print(tf.SparseTensor( indices=sparse_y_train[0], values=sparse_y_train[1], dense_shape=sparse_y_train ))
Y lo comparó con el SparseTensor
creado dentro de grid_rnn_fn:
indices = tf.where(tf.not_equal(labels, tf.constant(0, dtype=tf.int32))) values = tf.gather_nd(labels, indices) sparse_labels = tf.SparseTensor(indices, values, dense_shape=tf.shape(labels, out_type=tf.int64))
Esto es lo que tengo:
Para sparse_y_train
:
SparseTensor(indices=Tensor("SparseTensor/indices:0", shape=(33, 2), dtype=int64), values=Tensor("SparseTensor/values:0", shape=(33,), dtype=int32), dense_shape=Tensor("SparseTensor/dense_shape:0", shape=(2,), dtype=int64))
Para sparse_labels
:
SparseTensor(indices=Tensor("Where:0", shape=(?, 2), dtype=int64), values=Tensor("GatherNd:0", shape=(?,), dtype=int32), dense_shape=Tensor("Shape:0", shape=(2,), dtype=int64))
Lo que me lleva a pensar que parece que ctc_loss no puede manejar SparseTensors
como tags con formas dinámicas.
Sí. Es posible convertir un tensor en un tensor disperso y volver:
Sea sparse
un tensor escaso y dense
sea un tensor denso.
De escaso a denso:
dense = tf.sparse_to_dense(sparse.indices, sparse.shape, sparse.values)
De denso a escaso:
zero = tf.constant(0, dtype=tf.float32) where = tf.not_equal(dense, zero) indices = tf.where(where) values = tf.gather_nd(dense, indices) sparse = tf.SparseTensor(indices, values, dense.shape)