В API набора данных Tensorflow: как использовать padded_batch, чтобы прокладки с определенным значением без указания количества прокладок

Если вы не укажете padding_values, то padded_batch будет автоматически дополнено 0. Однако, если вам нужно другое значение, например -1, вы не можете просто установить padded_batch = -1. Вам нужно ввести последовательность для каждого слота, который необходимо заполнить.

Однако я работаю с набором данных, который имеет случайные значения длины массива, поэтому я не могу этого сделать, так как я не знаю, сколько чисел мне нужно заполнить.

Поскольку padding_values автоматически заполнит оставшуюся часть значения 0, я надеюсь, что это можно сделать каким-то образом с другим значением, например «-1».

Вот минимальный пример

import math
import numpy as np
import tensorflow as tf

cells = np.array([[0,1,2,3], [2,3,4], [3,6,5,4,3], [3,9]])
mells = np.array([[0], [2], [3], [9]])
print(cells)

writer = tf.python_io.TFRecordWriter('test.tfrecords')
for index in range(mells.shape[0]):
    example = tf.train.Example(features=tf.train.Features(feature={
        'num_value':tf.train.Feature(int64_list=tf.train.Int64List(value=mells[index])),
        'list_value':tf.train.Feature(int64_list=tf.train.Int64List(value=cells[index]))
    }))
    writer.write(example.SerializeToString())
writer.close()

#Generate Samples with batch size of 2

filenames = ["test.tfrecords"]
dataset = tf.data.TFRecordDataset(filenames)
def _parse_function(example_proto):
    keys_to_features = {'num_value':tf.VarLenFeature(tf.int64),
                        'list_value':tf.VarLenFeature(tf.int64)}
    parsed_features = tf.parse_single_example(example_proto, keys_to_features)
    return tf.sparse.to_dense(parsed_features['num_value']), \
           tf.sparse.to_dense(parsed_features['list_value'])
# Parse the record into tensors.
dataset = dataset.map(_parse_function)
# Shuffle the dataset
dataset = dataset.shuffle(buffer_size=1)
# Repeat the input indefinitly
dataset = dataset.repeat()  
# Generate batches
dataset = dataset.padded_batch(2, padded_shapes=([None],[None]), padding_values=-1)
# Create a one-shot iterator
iterator = dataset.make_one_shot_iterator()
i, data = iterator.get_next()

Это сообщение об ошибке

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-8-65494605bf11> in <module>()
     14 dataset = dataset.repeat()
     15 # Generate batches
---> 16 dataset = dataset.padded_batch(2, padded_shapes=([None],[None]), padding_values=-1)
     17 # Create a one-shot iterator
     18 iterator = dataset.make_one_shot_iterator()

/usr/local/lib/python3.6/dist-packages/tensorflow/python/data/ops/dataset_ops.py in padded_batch(self, batch_size, padded_shapes, padding_values, drop_remainder)
    943     """
    944     return PaddedBatchDataset(self, batch_size, padded_shapes, padding_values,
--> 945                               drop_remainder)
    946 
    947   def map(self, map_func, num_parallel_calls=None):

/usr/local/lib/python3.6/dist-packages/tensorflow/python/data/ops/dataset_ops.py in __init__(self, input_dataset, batch_size, padded_shapes, padding_values, drop_remainder)
   2526     self._padding_values = nest.map_structure_up_to(
   2527         input_dataset.output_shapes, _padding_value_to_tensor, padding_values,
-> 2528         input_dataset.output_types)
   2529     self._drop_remainder = ops.convert_to_tensor(
   2530         drop_remainder, dtype=dtypes.bool, name="drop_remainder")

/usr/local/lib/python3.6/dist-packages/tensorflow/python/data/util/nest.py in map_structure_up_to(shallow_tree, func, *inputs)
    465     raise ValueError("Cannot map over no sequences")
    466   for input_tree in inputs:
--> 467     assert_shallow_structure(shallow_tree, input_tree)
    468 
    469   # Flatten each input separately, apply the function to corresponding elements,

/usr/local/lib/python3.6/dist-packages/tensorflow/python/data/util/nest.py in assert_shallow_structure(shallow_tree, input_tree, check_types)
    299       raise TypeError(
    300           "If shallow structure is a sequence, input must also be a sequence. "
--> 301           "Input has type: %s." % type(input_tree))
    302 
    303     if check_types and not isinstance(input_tree, type(shallow_tree)):

TypeError: If shallow structure is a sequence, input must also be a sequence. Input has type: <class 'int'>.

Проблемная линия

# Generate batches
dataset = dataset.padded_batch(2, padded_shapes=([None],[None]), padding_values=-1)

если вы удалите padding_values, он генерирует пакеты с дополненными нулями без проблем

with tf.Session() as sess:
    print(sess.run([i, data]))
    print(sess.run([i, data]))

[array([[0],
       [2]]), array([[0, 1, 2, 3],
       [2, 3, 4, 0]])]
[array([[3],
       [9]]), array([[3, 6, 5, 4, 3],
       [3, 9, 0, 0, 0]])]

person SantoshGupta7    schedule 27.12.2018    source источник


Ответы (1)


Вы должны изменить padding_values.

dataset = dataset.padded_batch(2, padded_shapes=([None],[None])
                               , padding_values=(tf.constant(-1, dtype=tf.int64)
                                                 ,tf.constant(-1, dtype=tf.int64)))
with tf.Session() as sess:
    print(sess.run([i, data]))
    print(sess.run([i, data]))

[array([[0],
       [2]]), array([[ 0,  1,  2,  3],
       [ 2,  3,  4, -1]])]
[array([[3],
       [9]]), array([[ 3,  6,  5,  4,  3],
       [ 3,  9, -1, -1, -1]])]

Объяснить

Каждая запись, указанная в padding_values, представляет значения заполнения, используемые для соответствующих компонентов. Это означает, что длина padded_shapes должна быть равна длине padding_values. Последний используется для заполнения всей длины каждого массива здесь, а первый имеет одинаковую длину и не требует заполнения -1. Например:

dataset = dataset.padded_batch(2, padded_shapes=([None],[None])
                               , padding_values=(tf.constant(-1, dtype=tf.int64)
                                                 ,tf.constant(-2, dtype=tf.int64)))
with tf.Session() as sess:
    print(sess.run([i, data]))
    print(sess.run([i, data]))

[array([[0],
       [2]]), array([[ 0,  1,  2,  3],
       [ 2,  3,  4, -2]])]
[array([[3],
       [9]]), array([[ 3,  6,  5,  4,  3],
       [ 3,  9, -2, -2, -2]])]
person giser_yugang    schedule 27.12.2018
comment
Спасибо! Мне интересно, как это работает? Для padding_values даны только две записи, но каким-то образом это работает, чтобы заполнить всю длину для каждого массива. - person SantoshGupta7; 27.12.2018
comment
@ SantoshGupta7 Я добавил это в ответ. - person giser_yugang; 27.12.2018