Tensorflow:RaggedTensor.from_tensor 将所有数组中的值展平到一个数组中,而不是保留数组的原始数量
Tensorflow: RaggedTensor.from_tensor flattening values from all arrays into one array, instead of preserving original number of arrays
在官方文档中,RaggedTensor.from_tensor
会像这样工作。
x = [[1, 3, -1, -1], [2, -1, -1, -1], [4, 5, 8, 9]]
print(tf.RaggedTensor.from_tensor(x, padding=-1))
输出:
<tf.RaggedTensor [[1, 3], [2], [4, 5, 8, 9]]>
保留数组的原始数量。
但是,当处理由数据集 api 迭代器输出的批次时,它会将其展平为一个数组。这是代码的关键部分。
dataset = dataset.padded_batch(3, padded_shapes=([None],[None]), padding_values=(tf.constant(-1, dtype=tf.int64)
,tf.constant(-1, dtype=tf.int64)))
iterator = dataset.make_one_shot_iterator()
i, data = iterator.get_next()
data2= tf.RaggedTensor.from_tensor(data, padding=-1)
with tf.Session() as sess:
print(sess.run([ data, data2 ]))
print(sess.run([ data, data2 ]))
print(sess.run([ data, data2 ]))
这是输出
[array([[ 0, 1, 2, 3, -1],
[ 2, 3, 4, -1, -1],
[ 3, 6, 5, 4, 3]]), tf.RaggedTensorValue(values=array([0, 1, 2, 3, 2, 3, 4, 3, 6, 5, 4, 3]), row_splits=array([ 0, 4, 7, 12]))]
[array([[ 3, 9, -1, -1],
[ 0, 1, 2, 3],
[ 2, 3, 4, -1]]), tf.RaggedTensorValue(values=array([3, 9, 0, 1, 2, 3, 2, 3, 4]), row_splits=array([0, 2, 6, 9]))]
[array([[ 3, 6, 5, 4, 3],
[ 3, 9, -1, -1, -1],
[ 0, 1, 2, 3, -1]]), tf.RaggedTensorValue(values=array([3, 6, 5, 4, 3, 3, 9, 0, 1, 2, 3]), row_splits=array([ 0, 5, 7, 11]))]
这是重现结果的最小示例的完整代码
!pip install -q tf-nightly
import math
import numpy as np
import tensorflow as tf
#Generate Test data
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)
#Write test data to tf.records file
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()
#Open tfrecords file and generate batch from data
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(3, padded_shapes=([None],[None]), padding_values=(tf.constant(-1, dtype=tf.int64)
,tf.constant(-1, dtype=tf.int64)))
iterator = dataset.make_one_shot_iterator()
i, data = iterator.get_next()
#Remove padding
data2= tf.RaggedTensor.from_tensor(data, padding=-1)
#Print data
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run([ data, data2 ]))
print(sess.run([ data, data2 ]))
print(sess.run([ data, data2 ]))
这里是不规则张量的官方 Tensorflow 指南
https://www.tensorflow.org/guide/ragged_tensors
以及 Tensorflow 官方文档
https://www.tensorflow.org/versions/r1.13/api_docs/python/tf/RaggedTensor
事实证明它并没有展平它,不确定它是如何工作的,但它看起来像是通过跟踪换行符的位置,然后在评估时执行它们。
tf.RaggedTensorValue(values=array([3, 6, 5, 4, 3, 3, 9, 0, 1, 2, 3]), row_splits=array([ 0, 5, 7, 11]))]
'row_splits' 跟踪拆分行的位置。
以下是急切执行的一些结果。
i, data = iterator.get_next()
#Remove padding
data2= tf.RaggedTensor.from_tensor(data, padding=-1)
print(data2)
i, data = iterator.get_next()
#Remove padding
data2= tf.RaggedTensor.from_tensor(data, padding=-1)
print(data2)
i, data = iterator.get_next()
#Remove padding
data2= tf.RaggedTensor.from_tensor(data, padding=-1)
print(data2)
i, data = iterator.get_next()
#Remove padding
data2= tf.RaggedTensor.from_tensor(data, padding=-1)
print(data2)
结果
<tf.RaggedTensor [[3, 9], [0, 1, 2, 3], [2, 3, 4]]>
<tf.RaggedTensor [[3, 6, 5, 4, 3], [3, 9], [0, 1, 2, 3]]>
<tf.RaggedTensor [[2, 3, 4], [3, 6, 5, 4, 3], [3, 9]]>
<tf.RaggedTensor [[0, 1, 2, 3], [2, 3, 4], [3, 6, 5, 4, 3]]>
如您所见,RaggedTensor
实际上并没有变平。在内部,2D RaggedTensor
使用两个 Tensors/arrays 进行编码:一个包含平面值列表,另一个包含行拆分。有关如何使用基础 tensors/arrays 对 RaggedTensor
进行编码的更多详细信息,请参阅:https://www.tensorflow.org/guide/ragged_tensors#raggedtensor_encoding
混淆可能来自打印时 RaggedTensors 的显示方式。 Python有两种字符串转换方式:__str__
和__repr__
。 __str__
如果您只打印一个值本身,则使用 __repr__
如果该值嵌入到某个更大的结构(例如列表)中,则使用 __repr__
。
对于 RaggedTensorValue,__str__
方法 returns "<tf.RaggedTensorValue %s>" % self.to_list()
。即,它将向您显示格式化为列表的值。但是__repr__
方法returns"tf.RaggedTensorValue(values=%r, row_splits=%r)" % (self._values, self._row_splits)
。即,它将向您展示用于编码 RaggedTensorValue 的底层 numpy 数组。
在官方文档中,RaggedTensor.from_tensor
会像这样工作。
x = [[1, 3, -1, -1], [2, -1, -1, -1], [4, 5, 8, 9]]
print(tf.RaggedTensor.from_tensor(x, padding=-1))
输出:
<tf.RaggedTensor [[1, 3], [2], [4, 5, 8, 9]]>
保留数组的原始数量。
但是,当处理由数据集 api 迭代器输出的批次时,它会将其展平为一个数组。这是代码的关键部分。
dataset = dataset.padded_batch(3, padded_shapes=([None],[None]), padding_values=(tf.constant(-1, dtype=tf.int64)
,tf.constant(-1, dtype=tf.int64)))
iterator = dataset.make_one_shot_iterator()
i, data = iterator.get_next()
data2= tf.RaggedTensor.from_tensor(data, padding=-1)
with tf.Session() as sess:
print(sess.run([ data, data2 ]))
print(sess.run([ data, data2 ]))
print(sess.run([ data, data2 ]))
这是输出
[array([[ 0, 1, 2, 3, -1],
[ 2, 3, 4, -1, -1],
[ 3, 6, 5, 4, 3]]), tf.RaggedTensorValue(values=array([0, 1, 2, 3, 2, 3, 4, 3, 6, 5, 4, 3]), row_splits=array([ 0, 4, 7, 12]))]
[array([[ 3, 9, -1, -1],
[ 0, 1, 2, 3],
[ 2, 3, 4, -1]]), tf.RaggedTensorValue(values=array([3, 9, 0, 1, 2, 3, 2, 3, 4]), row_splits=array([0, 2, 6, 9]))]
[array([[ 3, 6, 5, 4, 3],
[ 3, 9, -1, -1, -1],
[ 0, 1, 2, 3, -1]]), tf.RaggedTensorValue(values=array([3, 6, 5, 4, 3, 3, 9, 0, 1, 2, 3]), row_splits=array([ 0, 5, 7, 11]))]
这是重现结果的最小示例的完整代码
!pip install -q tf-nightly
import math
import numpy as np
import tensorflow as tf
#Generate Test data
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)
#Write test data to tf.records file
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()
#Open tfrecords file and generate batch from data
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(3, padded_shapes=([None],[None]), padding_values=(tf.constant(-1, dtype=tf.int64)
,tf.constant(-1, dtype=tf.int64)))
iterator = dataset.make_one_shot_iterator()
i, data = iterator.get_next()
#Remove padding
data2= tf.RaggedTensor.from_tensor(data, padding=-1)
#Print data
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run([ data, data2 ]))
print(sess.run([ data, data2 ]))
print(sess.run([ data, data2 ]))
这里是不规则张量的官方 Tensorflow 指南
https://www.tensorflow.org/guide/ragged_tensors
以及 Tensorflow 官方文档
https://www.tensorflow.org/versions/r1.13/api_docs/python/tf/RaggedTensor
事实证明它并没有展平它,不确定它是如何工作的,但它看起来像是通过跟踪换行符的位置,然后在评估时执行它们。
tf.RaggedTensorValue(values=array([3, 6, 5, 4, 3, 3, 9, 0, 1, 2, 3]), row_splits=array([ 0, 5, 7, 11]))]
'row_splits' 跟踪拆分行的位置。
以下是急切执行的一些结果。
i, data = iterator.get_next()
#Remove padding
data2= tf.RaggedTensor.from_tensor(data, padding=-1)
print(data2)
i, data = iterator.get_next()
#Remove padding
data2= tf.RaggedTensor.from_tensor(data, padding=-1)
print(data2)
i, data = iterator.get_next()
#Remove padding
data2= tf.RaggedTensor.from_tensor(data, padding=-1)
print(data2)
i, data = iterator.get_next()
#Remove padding
data2= tf.RaggedTensor.from_tensor(data, padding=-1)
print(data2)
结果
<tf.RaggedTensor [[3, 9], [0, 1, 2, 3], [2, 3, 4]]>
<tf.RaggedTensor [[3, 6, 5, 4, 3], [3, 9], [0, 1, 2, 3]]>
<tf.RaggedTensor [[2, 3, 4], [3, 6, 5, 4, 3], [3, 9]]>
<tf.RaggedTensor [[0, 1, 2, 3], [2, 3, 4], [3, 6, 5, 4, 3]]>
如您所见,RaggedTensor
实际上并没有变平。在内部,2D RaggedTensor
使用两个 Tensors/arrays 进行编码:一个包含平面值列表,另一个包含行拆分。有关如何使用基础 tensors/arrays 对 RaggedTensor
进行编码的更多详细信息,请参阅:https://www.tensorflow.org/guide/ragged_tensors#raggedtensor_encoding
混淆可能来自打印时 RaggedTensors 的显示方式。 Python有两种字符串转换方式:__str__
和__repr__
。 __str__
如果您只打印一个值本身,则使用 __repr__
如果该值嵌入到某个更大的结构(例如列表)中,则使用 __repr__
。
对于 RaggedTensorValue,__str__
方法 returns "<tf.RaggedTensorValue %s>" % self.to_list()
。即,它将向您显示格式化为列表的值。但是__repr__
方法returns"tf.RaggedTensorValue(values=%r, row_splits=%r)" % (self._values, self._row_splits)
。即,它将向您展示用于编码 RaggedTensorValue 的底层 numpy 数组。