将.npy(numpy文件)送入tensorflow数据管道
Tensorflow似乎缺少“.npy”文件的读取器。 如何将数据文件读入新的tensorflow.data.Dataset管线? 我的数据无法存储在内存中将.npy(numpy文件)送入tensorflow数据管道,numpy,tensorflow,dataset,data-pipeline,Numpy,Tensorflow,Dataset,Data Pipeline,Tensorflow似乎缺少“.npy”文件的读取器。 如何将数据文件读入新的tensorflow.data.Dataset管线? 我的数据无法存储在内存中 每个对象都保存在单独的“.npy”文件中。每个文件包含两个不同的数据阵列作为特征,一个标量作为标签。您的数据适合内存吗?如果是,您可以按照文档部分的说明进行操作: 使用NumPy数组 如果所有输入数据都适合内存,那么从它们创建数据集的最简单方法是将它们转换为tf.Tensor对象并使用Dataset.from_Tensor_slices()
每个对象都保存在单独的“.npy”文件中。每个文件包含两个不同的数据阵列作为特征,一个标量作为标签。您的数据适合内存吗?如果是,您可以按照文档部分的说明进行操作: 使用NumPy数组 如果所有输入数据都适合内存,那么从它们创建数据集的最简单方法是将它们转换为tf.Tensor对象并使用Dataset.from_Tensor_slices() 如果文件不适合内存,唯一推荐的方法似乎是首先将
npy
数据转换为TFRecord
格式,然后使用TFRecord
数据集格式,该格式可以在不完全加载内存的情况下进行流式传输
FWIW,对我来说,TFRecord
不能直接用npy文件的目录名或文件名实例化似乎很疯狂,但这似乎是纯Tensorflow的一个限制
如果您可以将单个大型npy文件拆分为较小的文件,每个文件大致代表一个训练批,那么您可以在Keras中编写一个自定义数据生成器,只生成当前批所需的数据
一般来说,如果数据集无法放入内存,将其存储为单个大型npy文件会使处理变得非常困难,最好先将数据重新格式化为TFRecord或多个npy文件,然后使用其他方法。您可以使用tf.py_func执行此操作,请参见示例。
parse函数只需将文件名从字节解码为字符串,然后调用np.load 更新:类似以下内容:
def read_npy_file(item):
data = np.load(item.decode())
return data.astype(np.float32)
file_list = ['/foo/bar.npy', '/foo/baz.npy']
dataset = tf.data.Dataset.from_tensor_slices(file_list)
dataset = dataset.map(
lambda item: tuple(tf.py_func(read_npy_file, [item], [tf.float32,])))
def npy_header_offset(npy_path):
with open(str(npy_path), 'rb') as f:
if f.read(6) != b'\x93NUMPY':
raise ValueError('Invalid NPY file.')
version_major, version_minor = f.read(2)
if version_major == 1:
header_len_size = 2
elif version_major == 2:
header_len_size = 4
else:
raise ValueError('Unknown NPY file version {}.{}.'.format(version_major, version_minor))
header_len = sum(b << (8 * i) for i, b in enumerate(f.read(header_len_size)))
header = f.read(header_len)
if not header.endswith(b'\n'):
raise ValueError('Invalid NPY file.')
return f.tell()
import tensorflow as tf
npy_file = 'my_file.npy'
num_features = ...
dtype = tf.float32
header_offset = npy_header_offset(npy_file)
dataset = tf.data.FixedLengthRecordDataset([npy_file], num_features * dtype.size, header_bytes=header_offset)
实际上,使用TensorFlow而不是TFRecords直接读取NPY文件是可能的。关键的部分是和,并查看了的文档。为简单起见,假设给定了一个float32 NPY文件,其中包含一个具有形状
(N,K)
的数组,并且您事先知道特性K
的数量,以及它是float32数组的事实。NPY文件只是一个带有小标题的二进制文件,后跟原始数组数据(对象数组不同,但我们现在考虑的是数字)。简而言之,您可以使用如下函数查找此标头的大小:
def read_npy_file(item):
data = np.load(item.decode())
return data.astype(np.float32)
file_list = ['/foo/bar.npy', '/foo/baz.npy']
dataset = tf.data.Dataset.from_tensor_slices(file_list)
dataset = dataset.map(
lambda item: tuple(tf.py_func(read_npy_file, [item], [tf.float32,])))
def npy_header_offset(npy_path):
with open(str(npy_path), 'rb') as f:
if f.read(6) != b'\x93NUMPY':
raise ValueError('Invalid NPY file.')
version_major, version_minor = f.read(2)
if version_major == 1:
header_len_size = 2
elif version_major == 2:
header_len_size = 4
else:
raise ValueError('Unknown NPY file version {}.{}.'.format(version_major, version_minor))
header_len = sum(b << (8 * i) for i, b in enumerate(f.read(header_len_size)))
header = f.read(header_len)
if not header.endswith(b'\n'):
raise ValueError('Invalid NPY file.')
return f.tell()
import tensorflow as tf
npy_file = 'my_file.npy'
num_features = ...
dtype = tf.float32
header_offset = npy_header_offset(npy_file)
dataset = tf.data.FixedLengthRecordDataset([npy_file], num_features * dtype.size, header_bytes=header_offset)
此数据集的每个元素都包含一个表示单个示例的长字节字符串。现在可以对其进行解码以获得实际阵列:
dataset = dataset.map(lambda s: tf.io.decode_raw(s, dtype))
不过,这些元素将具有不确定的形状,因为TensorFlow不跟踪字符串的长度。您可以强制执行形状,因为您知道特征的数量:
dataset = dataset.map(lambda s: tf.reshape(tf.io.decode_raw(s, dtype), (num_features,)))
类似地,您可以选择在批处理之后执行此步骤,或者以您喜欢的任何方式组合它
限制是您必须提前知道功能的数量。但是,从NumPy头中提取它是可能的,这有点麻烦,而且在任何情况下都很难从TensorFlow中提取,因此需要提前知道文件名。另一个限制是,实际上,解决方案要求每个数据集只使用一个文件,或者使用具有相同头大小的文件,尽管您知道所有数组的大小实际上应该是相同的
诚然,如果考虑这种方法,最好是使用一个没有标题的纯二进制文件,或者硬编码功能的数量,或者从不同的源读取它们…问题设置
我有一个文件夹,里面的图像被输入到一个InceptionV3模型中,用于提取特征。这似乎是整个过程的一个巨大瓶颈。作为一种解决方法,我从每张图像中提取特征,然后将它们以.npy
格式存储在磁盘上
现在我有两个文件夹,一个用于图像,另一个用于相应的.npy
文件。在tf.data.Dataset
管道中加载.npy
文件时存在明显问题
变通办法
我遇到了TensorFlow的官方教程,该教程为这个线程(和我)遇到的问题提供了一个很好的解决方法
加载nummpy文件
首先,我们需要创建一个映射函数,该函数接受.npy
文件名并返回numpy数组
#加载numpy文件
定义映射函数(特征路径):
特征=np.加载(特征路径)
返回特性
使用tf.numpy\u功能
使用,我们可以包装任何python函数并将其用作TensorFlow操作。该函数必须接受numpy对象(这正是我们想要的)
我们用所有.npy
文件名的列表创建一个tf.data.Dataset
dataset=tf.data.dataset.from\u tensor\u切片(特征路径)
然后,我们使用tf.data.Dataset
API的map
函数来完成剩下的任务
#使用map并行加载numpy文件
dataset=dataset.map(lambda项:tf.numpy_函数(
地图功能[item],tf.16),
num_parallel_calls=tf.data.AUTOTUNE)
我看过该指南,但不幸的是,它不适合记忆!非常感谢,但将我的numpy文件转换为TFRecord是我最不想做的事情,因为我有大约5000000个文件,这将需要很长时间才能完成。我想我会同意keras发电机的想法。再次感谢!您的5000000个文件中的每个文件都无法放入内存?我的情况与OP类似,我有大约一百万个小文件,使用一个简单的Keras生成器工作起来很有魅力。不幸的是,它不能很好地用于多处理,并且比tf.data API慢,因此我最终将整个数据集转换为TFRecord文件,性能比Keras生成器提高了很多,但这只是我的问题,可能有所不同