如何解决将具有张量特征的 tf.train.Dataset 序列化为 tfrecord 文件?
我的数据集如下所示:
dataset1 = tf.data.Dataset.from_tensor_slices((
tf.random.uniform([4,100],maxval=100,dtype=tf.int32),tf.random.uniform([4])))
for record in dataset1.take(2):
print(record)
print(type(record))
(<tf.Tensor: shape=(100,),dtype=int32,numpy=
array([28,96,6,22,36,33,34,29,20,77,40,82,45,81,62,59,30,86,44,17,43,32,19,24,14,65,54,31,88,72,55,57,63,92,50,95,76,99,87,56,12,27,66,97,58,52,42,78,3,98,67,39,25,16,46,68,53,71,93,13,21],dtype=int32)>,<tf.Tensor: shape=(),dtype=float32,numpy=0.42071342>)
(<tf.Tensor: shape=(100,numpy=
array([71,9,94,64,10,41,37,38,11,26,28,7,89,2,4,84,75,35,60,83,80,69,5,74,1,79,91,44],numpy=0.73927164>)
<class 'tuple'>
所以每条记录都是两个张量的元组,一个是输入,另一个是模型的输出。我正在尝试将此数据集转换为 .tfrecord
文件,这要求我从每条记录中生成一个 Example
。这是我的尝试:
def _bytes_feature(value):
"""Returns a bytes_list from a string / byte."""
if isinstance(value,type(tf.constant(0))):
value = value.numpy() # BytesList won't unpack a string from an EagerTensor.
return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))
def _float_feature(value):
"""Returns a float_list from a float / double."""
return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))
def serialize_example(feature1,feature2):
feature = {
'feature1': _bytes_feature(tf.io.serialize_tensor(feature1)),'feature2': _float_feature(feature2),}
example_proto = tf.train.Example(features=tf.train.Features(feature=feature))
return example_proto.SerializetoString()
当我执行 dataset1.map(serialize_example)
时,我希望我的代码在执行之前可以工作
writer = tf.data.experimental.TFRecordWriter(some_path)
writer.write(dataset1)
但是,当我尝试 dataset1.map(serialize_example)
时出现以下错误:
...
value = value.numpy() # BytesList won't unpack a string from an EagerTensor.
AttributeError: 'Tensor' object has no attribute 'numpy'
我应该如何将此数据集转换为 .tfrecord
文件?
解决方法
我尝试遵循 doc,这就是我能想到的(您可以立即对其进行测试 here in a colab):
import tensorflow as tf
dataset1 = tf.data.Dataset.from_tensor_slices((
tf.random.uniform([4,100],maxval=100,dtype=tf.int32),tf.random.uniform([4])))
def _bytes_feature(value):
"""Returns a bytes_list from a string / byte."""
if isinstance(value,type(tf.constant(0))):
value = value.numpy() # BytesList won't unpack a string from an EagerTensor.
return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))
def _float_feature(value):
"""Returns a float_list from a float / double."""
return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))
def serialize_example(feature1,feature2):
feature = {
'feature1': _bytes_feature(tf.io.serialize_tensor(feature1)),'feature2': _float_feature(feature2),}
example_proto = tf.train.Example(features=tf.train.Features(feature=feature))
return example_proto.SerializeToString()
def tf_serialize_example(f0,f1):
tf_string = tf.py_function(
serialize_example,(f0,f1),# Pass these args to the above function.
tf.string) # The return type is `tf.string`.
return tf.reshape(tf_string,()) # The result is a scalar.
dataset1 = dataset1.map(tf_serialize_example)
writer = tf.data.experimental.TFRecordWriter('test.tfrecord')
writer.write(dataset1)
基本上主要部分是写一个tf.py_function
。这是因为 serialize_example
是一个非张量函数:您不能在图形模式下使用 .numpy()
。这就是AttributeError: 'Tensor' object has no attribute 'numpy'
(虽然笨拙)试图告诉你的。
不同之处在于 EagerTensor
将具有 .numpy()
方法。
另外一件事:如果您不需要 tf.int32
作为输入的数据类型,您可以使用 tf.int64
并使用以下函数:
def _int64_feature(value):
"""Returns an int64_list from a bool / enum / int / uint."""
return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))
我认为此函数类似于张量,因此您不需要 tf.py_function
,但我还没有尝试过。
当然,您也可以强制转换为 float32
或 float64
,但这样存储起来会更重。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。