当 dtype=object 时,迭代地读取一个大的 numpy 保存文件(即使用生成器)
Reading a large numpy save file iteratively (i.e. with a generator) when the dtype=object
我有一个很大的 numpy 保存文件(可能比内存大)。 dtype
是 object
(它是可变长度 numpy 数组的 numpy 数组)。
Can I avoid reading the entire file into memory?
E.g. build a generator to read elements iteratively.
使用标准的 numpy dtypes
np.load(filename, mmap_mode='r')
可以解决问题,但您不能将 mmap_mode
与对象数据类型一起使用。
我是否有机会通过 reader 流式传输字节?或者我不知道的其他技巧?
您可能想看一下 numpy memmap。
来自官方文档:
Memory-mapped files are used for accessing small segments of large files on disk, without reading the entire file into memory. NumPy’s memmap’s are array-like objects. This differs from Python’s mmap module, which uses file-like objects.
https://docs.scipy.org/doc/numpy/reference/generated/numpy.memmap.html
non-object dtype 的基本格式是一个 header 块(具有形状、dtype、步幅等),后跟其数据缓冲区的字节副本。
换句话说,类似于这个序列:
In [129]: x
Out[129]:
array([[1, 2, 3],
[4, 5, 6]])
In [130]: x.tostring()
Out[130]: b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00\x06\x00\x00\x00'
In [132]: np.frombuffer(__, dtype=int)
Out[132]: array([1, 2, 3, 4, 5, 6])
但是如果我将 dtype 更改为 object:
In [134]: X = x.astype(object)
In [135]: X
Out[135]:
array([[1, 2, 3],
[4, 5, 6]], dtype=object)
In [136]: X.tostring()
Out[136]: b'`\x1bO\x08p\x1bO\x08\x80\x1bO\x08\x90\x1bO\x08\xa0\x1bO\x08\xb0\x1bO\x08'
那些数据缓冲区字节指向内存中的位置。由于这些是小整数,它们可能指向唯一的缓存值
In [137]: id(1)
Out[137]: 139402080
In [138]: id(2)
Out[138]: 139402096
如果元素是数组,它们将指向存储在内存中其他地方的那些数组(指向 ndarray
objects,而不是它们的数据缓冲区)。
要像这样处理 objects np.save
使用 pickle。现在 ndarray
的 pickle 是它的 save
字符串。我不知道 np.save
将这些字符串放在哪里。也许它在线流式传输,也许使用指向文件后面的点的指针。
You/we 必须研究 np.save
(和函数调用)以确定如何保存此数据。我已经看够了如何从一个文件中保存和加载多个数组,但没有关注 object dtype 布局。相关代码在numpy/lib/npyio.py
、numpy/lib/format.py
format
文件有一个关于保存格式的文档块。
np.save
format.write_array
如果non-object write_array
使用array.tofile(fp)
。如果 object
,则使用 pickle.dump(array, fp)
同样 read_array
使用 np.fromfile(fp, dtype)
和 pickle.load
。
所以这意味着我们需要深入研究 array
pickle.dump
是如何完成的。
我有一个很大的 numpy 保存文件(可能比内存大)。 dtype
是 object
(它是可变长度 numpy 数组的 numpy 数组)。
Can I avoid reading the entire file into memory?
E.g. build a generator to read elements iteratively.
使用标准的 numpy dtypes
np.load(filename, mmap_mode='r')
可以解决问题,但您不能将 mmap_mode
与对象数据类型一起使用。
我是否有机会通过 reader 流式传输字节?或者我不知道的其他技巧?
您可能想看一下 numpy memmap。
来自官方文档:
Memory-mapped files are used for accessing small segments of large files on disk, without reading the entire file into memory. NumPy’s memmap’s are array-like objects. This differs from Python’s mmap module, which uses file-like objects.
https://docs.scipy.org/doc/numpy/reference/generated/numpy.memmap.html
non-object dtype 的基本格式是一个 header 块(具有形状、dtype、步幅等),后跟其数据缓冲区的字节副本。
换句话说,类似于这个序列:
In [129]: x
Out[129]:
array([[1, 2, 3],
[4, 5, 6]])
In [130]: x.tostring()
Out[130]: b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00\x06\x00\x00\x00'
In [132]: np.frombuffer(__, dtype=int)
Out[132]: array([1, 2, 3, 4, 5, 6])
但是如果我将 dtype 更改为 object:
In [134]: X = x.astype(object)
In [135]: X
Out[135]:
array([[1, 2, 3],
[4, 5, 6]], dtype=object)
In [136]: X.tostring()
Out[136]: b'`\x1bO\x08p\x1bO\x08\x80\x1bO\x08\x90\x1bO\x08\xa0\x1bO\x08\xb0\x1bO\x08'
那些数据缓冲区字节指向内存中的位置。由于这些是小整数,它们可能指向唯一的缓存值
In [137]: id(1)
Out[137]: 139402080
In [138]: id(2)
Out[138]: 139402096
如果元素是数组,它们将指向存储在内存中其他地方的那些数组(指向 ndarray
objects,而不是它们的数据缓冲区)。
要像这样处理 objects np.save
使用 pickle。现在 ndarray
的 pickle 是它的 save
字符串。我不知道 np.save
将这些字符串放在哪里。也许它在线流式传输,也许使用指向文件后面的点的指针。
You/we 必须研究 np.save
(和函数调用)以确定如何保存此数据。我已经看够了如何从一个文件中保存和加载多个数组,但没有关注 object dtype 布局。相关代码在numpy/lib/npyio.py
、numpy/lib/format.py
format
文件有一个关于保存格式的文档块。
np.save
format.write_array
如果non-object write_array
使用array.tofile(fp)
。如果 object
,则使用 pickle.dump(array, fp)
同样 read_array
使用 np.fromfile(fp, dtype)
和 pickle.load
。
所以这意味着我们需要深入研究 array
pickle.dump
是如何完成的。