Tf.Sequence Пример с многомерными массивами
В Tensorflow я хочу сохранить многомерный массив в TFRecord. Например:
[[1, 2, 3], [1, 2], [3, 2, 1]]
Поскольку задача, которую я пытаюсь решить, является последовательной, я пытаюсь использовать Tensorflow tf.train.SequenceExample()
, и при записи данных мне удаётся записать данные в файл TFRecord. Однако, когда я пытаюсь загрузить данные из файла TFRecord с помощью tf.parse_single_sequence_example
, меня приветствует большое количество загадочных ошибок:
W tensorflow/core/framework/op_kernel.cc:936] Invalid argument: Name: , Key: input_characters, Index: 1. Number of int64 values != expected. values size: 6 but output shape: []
E tensorflow/core/client/tensor_c_api.cc:485] Name: , Key: input_characters, Index: 1. Number of int64 values != expected. values size: 6 but output shape: []
Функция, которую я использую для загрузки моих данных, приведен ниже:
def read_and_decode_single_example(filename):
filename_queue = tf.train.string_input_producer([filename],
num_epochs=None)
reader = tf.TFRecordReader()
_, serialized_example = reader.read(filename_queue)
context_features = {
"length": tf.FixedLenFeature([], dtype=tf.int64)
}
sequence_features = {
"input_characters": tf.FixedLenSequenceFeature([], dtype=tf.int64),
"output_characters": tf.FixedLenSequenceFeature([], dtype=tf.int64)
}
context_parsed, sequence_parsed = tf.parse_single_sequence_example(
serialized=serialized_example,
context_features=context_features,
sequence_features=sequence_features
)
context = tf.contrib.learn.run_n(context_parsed, n=1, feed_dict=None)
print context
Функция, которую я использую для сохранения данных, находится здесь:
# http://www.wildml.com/2016/08/rnns-in-tensorflow-a-practical-guide-and-undocumented-features/
def make_example(input_sequence, output_sequence):
"""
Makes a single example from Python lists that follows the
format of tf.train.SequenceExample.
"""
example_sequence = tf.train.SequenceExample()
# 3D length
sequence_length = sum([len(word) for word in input_sequence])
example_sequence.context.feature["length"].int64_list.value.append(sequence_length)
input_characters = example_sequence.feature_lists.feature_list["input_characters"]
output_characters = example_sequence.feature_lists.feature_list["output_characters"]
for input_character, output_character in izip_longest(input_sequence,
output_sequence):
# Extend seems to work, therefore it replaces append.
if input_sequence is not None:
input_characters.feature.add().int64_list.value.extend(input_character)
if output_characters is not None:
output_characters.feature.add().int64_list.value.extend(output_character)
return example_sequence
Любая помощь будет приветствоваться.
Ответы
Ответ 1
С предоставленным кодом я не смог воспроизвести вашу ошибку, но некоторые образованные предположения дали следующий рабочий код.
import tensorflow as tf
import numpy as np
import tempfile
tmp_filename = 'tf.tmp'
sequences = [[1, 2, 3], [1, 2], [3, 2, 1]]
label_sequences = [[0, 1, 0], [1, 0], [1, 1, 1]]
def make_example(input_sequence, output_sequence):
"""
Makes a single example from Python lists that follows the
format of tf.train.SequenceExample.
"""
example_sequence = tf.train.SequenceExample()
# 3D length
sequence_length = len(input_sequence)
example_sequence.context.feature["length"].int64_list.value.append(sequence_length)
input_characters = example_sequence.feature_lists.feature_list["input_characters"]
output_characters = example_sequence.feature_lists.feature_list["output_characters"]
for input_character, output_character in zip(input_sequence,
output_sequence):
if input_sequence is not None:
input_characters.feature.add().int64_list.value.append(input_character)
if output_characters is not None:
output_characters.feature.add().int64_list.value.append(output_character)
return example_sequence
# Write all examples into a TFRecords file
def save_tf(filename):
with open(filename, 'w') as fp:
writer = tf.python_io.TFRecordWriter(fp.name)
for sequence, label_sequence in zip(sequences, label_sequences):
ex = make_example(sequence, label_sequence)
writer.write(ex.SerializeToString())
writer.close()
def read_and_decode_single_example(filename):
filename_queue = tf.train.string_input_producer([filename],
num_epochs=None)
reader = tf.TFRecordReader()
_, serialized_example = reader.read(filename_queue)
context_features = {
"length": tf.FixedLenFeature([], dtype=tf.int64)
}
sequence_features = {
"input_characters": tf.FixedLenSequenceFeature([], dtype=tf.int64),
"output_characters": tf.FixedLenSequenceFeature([], dtype=tf.int64)
}
return serialized_example, context_features, sequence_features
save_tf(tmp_filename)
ex,context_features,sequence_features = read_and_decode_single_example(tmp_filename)
context_parsed, sequence_parsed = tf.parse_single_sequence_example(
serialized=ex,
context_features=context_features,
sequence_features=sequence_features
)
sequence = tf.contrib.learn.run_n(sequence_parsed, n=1, feed_dict=None)
#check if the saved data matches the input data
print(sequences[0] in sequence[0]['input_characters'])
Необходимые изменения:
-
sequence_length = sum([len(word) for word in input_sequence])
to sequence_length = len(input_sequence)
В противном случае он не работает для ваших данных примера
-
extend
был изменен на append
Ответ 2
У меня была та же проблема. Я думаю, что он полностью доступен для решения, но вам нужно определить формат вывода, а затем выяснить, как вы собираетесь его использовать.
Первая, какова ваша ошибка?
Сообщение об ошибке сообщает вам, что то, что вы пытаетесь прочитать, не вписывается в указанный вами размер функции. Итак, где вы это указали? Прямо здесь:
sequence_features = {
"input_characters": tf.FixedLenSequenceFeature([], dtype=tf.int64),
"output_characters": tf.FixedLenSequenceFeature([], dtype=tf.int64)
}
Это говорит о том, что "мои входные символы являются последовательностью одиночных значений", но это неверно; у вас есть последовательность последовательностей одиночных значений и, следовательно, ошибка.
Второй, что вы можете сделать?
Если вы вместо этого используете:
a = [[1,2,3], [2,3,1], [3,2,1]]
sequence_features = {
"input_characters": tf.FixedLenSequenceFeature([3], dtype=tf.int64),
"output_characters": tf.FixedLenSequenceFeature([3], dtype=tf.int64)
}
У вас не будет ошибки с кодом, потому что вы указали, что каждый элемент последовательности верхнего уровня имеет длину 3 элемента.
В качестве альтернативы, если у вас нет фиксированных последовательностей длины, вам придется использовать другой тип функции.
sequence_features = {
"input_characters": tf.VarLenFeature(tf.int64),
"output_characters": tf.VarLenFeature(tf.int64)
}
Функция VarLenFeature сообщает, что перед чтением длина неизвестна. К сожалению, это означает, что ваши входные символы больше не могут считаться плотным вектором за один шаг. Вместо этого по умолчанию будет SparseTensor. Вы можете превратить это в плотный тензор с tf.sparse_tensor_to_dense, например:
input_densified = tf.sparse_tensor_to_dense(sequence_parsed['input_characters'])
Как упоминалось в статье, на которую вы смотрели, если ваши данные не всегда имеют одинаковую длину, вам придется в вашем словаре будет слово "not_really_a_word", которое вы используете как индекс по умолчанию. например скажем, у вас есть отображение индекса 0 на слово "not_really_a_word", а затем используйте
a = [[1,2,3], [2,3], [3,2,1]]
список python будет
array((1,2,3), (2,3,0), (3,2,1))
тензором.
Будьте предупреждены; Я не уверен, что обратное распространение "просто работает" для SparseTensors, как и для плотных тензоров. статья wildml рассказывает о заполнении 0s для каждой последовательности, маскирующей потерю слова "not_actually_a_word" (см. "ОБРАТНАЯ СВЯЗЬ: ОСТОРОЖНО: 0S IN ВАШИ ЛОКАЛЫ/КЛАССЫ" в своей статье). Это, по-видимому, предполагает, что первый метод будет проще реализовать.
Обратите внимание, что это отличается от случая, описанного здесь, где каждый пример представляет собой последовательность последовательностей. Насколько я понимаю, причина, по которой этот вид метода не очень хорошо поддерживается, заключается в том, что это злоупотребление случаем, что это предназначено для поддержки; загружать вложения фиксированного размера напрямую.
Я предполагаю, что самое следующее, что вы хотите сделать, - превратить эти числа в словарные вложения. Вы можете превратить список индексов в список вложений с tf.nn.embedding_lookup