Сохранение и чтение списка переменных размера из TFRecord

Каким будет лучший способ хранить разреженный вектор для TFRecord? Мой разреженный вектор содержит только те и нули, поэтому я решил, что просто сохраню индексы, где "те" расположены так:

example = tf.train.Example(
        features=tf.train.Features(
            feature={
                'label': self._int64_feature(label),
                'features' : self._int64_feature_list(values)
            }
        )
    )

Здесь values - список, содержащий индексы 'ones'. Этот массив values иногда содержит сотни элементов, а иногда и вовсе. После этого я просто сохраняю сериализованный пример в tfrecord. Позже я читаю tfrecord следующим образом:

features = tf.parse_single_example(
    serialized_example,
    features={
        # We know the length of both fields. If not the
        # tf.VarLenFeature could be used
        'label': tf.FixedLenFeature([], dtype=tf.int64),
        'features': tf.VarLenFeature(dtype=tf.int64)
    }
)

label = features['label']
values = features['features']

Это не работает, потому что массив values распознается как разреженный массив, и я не получаю данные, которые я сохранил. Каков наилучший способ хранения разреженного тензора в tfrecords и как его читать?

Ответ 1

Если вы просто сериализуете местоположения 1s, вы можете немного разобраться с вашим правильным разреженным тензором:

Анализируемый разреженный тензор features['features'] будет выглядеть примерно так:

features['features'].indices: [[batch_id, position]...]

Где position - бесполезное перечисление.

но вы действительно хотите, чтобы feature['features'] выглядел как [[batch_id, one_position], ...]

Где one_position - фактическое значение, указанное в вашем разреженном тензоре.

Итак:

indices = features['features'].indices
indices = tf.transpose(indices) 
# Now looks like [[batch_id, batch_id, ...], [position, position, ...]]
indices = tf.stack([indices[0], features['features'].values])
# Now looks like [[batch_id, batch_id, ...], [one_position, one_position, ...]]
indices = tf.transpose(indices)
# Now looks like [[batch_id, one_position], [batch_id, one_position], ...]]
features['features'] = tf.SparseTensor(
   indices=indices,
   values=tf.ones(shape=tf.shape(indices)[:1])
   dense_shape=1 + tf.reduce_max(indices, axis=[0])
)

Voila! features['features'] теперь представляет собой матрицу, которая является вашей партией разреженных векторов, конкатенированных.

ПРИМЕЧАНИЕ: если вы хотите рассматривать это как плотный тензор, вам нужно будет сделать tf.sparse_to_dense И плотный тензор будет иметь форму [None, None] (что делает его трудным для работы). Если вы знаете максимальная длина вектора, которую вы, возможно, захотите сделать с жестким кодом: dense_shape=[batch_size, max_vector_length]