Python 用最少的内存连接Numpy数组
不是我有50GB的数据集保存为h5py,这是一个字典里面。字典包含从0到n的键,值为numpy ndarray(三维),形状相同。例如: 字典[0]=np.array([[…],[…]] 我想对所有这些np数组进行压缩,代码如下Python 用最少的内存连接Numpy数组,python,arrays,numpy,memory,Python,Arrays,Numpy,Memory,不是我有50GB的数据集保存为h5py,这是一个字典里面。字典包含从0到n的键,值为numpy ndarray(三维),形状相同。例如: 字典[0]=np.array([[…],[…]] 我想对所有这些np数组进行压缩,代码如下 sample = np.concatenate(list(dictionary.values)) 此操作浪费100GB内存!如果我使用 del dictionary 它将减少到50GB内存。但我希望在加载数据期间将内存使用控制为50GB。我试过的另一种方法是这样
sample = np.concatenate(list(dictionary.values))
此操作浪费100GB内存!如果我使用
del dictionary
它将减少到50GB内存。但我希望在加载数据期间将内存使用控制为50GB。我试过的另一种方法是这样
sample = np.concatenate(sample,dictionary[key])
sample = np.empty(shape)
with h5py.File(...) as dictionary:
for key in dictionary.keys():
sample[key] = dictionary[key]
它仍在使用100GB内存。我认为在上述所有情况下,右侧将创建一个新的内存块进行保存,然后分配给左侧,这将在计算期间使内存加倍。因此,第三种方法我是这样尝试的
sample = np.concatenate(sample,dictionary[key])
sample = np.empty(shape)
with h5py.File(...) as dictionary:
for key in dictionary.keys():
sample[key] = dictionary[key]
我认为这个代码有一个优势。将值dictionary[key]分配给样本的某一行,那么dictionary[key]的内存将被清除。但是,我测试了它,发现内存使用量也是100GB。为什么?
有没有什么好方法将内存使用限制为50GB 您的问题是,内存中需要有相同数据的两个副本。 如果按照
test1
中的方式构建数组,那么一次所需的内存将少得多,但代价是丢失字典
import numpy as np
import time
def test1(n):
a = {x:(x, x, x) for x in range(n)} # Build sample data
b = np.array([a.pop(i) for i in range(n)]).reshape(-1)
return b
def test2(n):
a = {x:(x, x, x) for x in range(n)} # Build sample data
b = np.concatenate(list(a.values()))
return b
x1 = test1(1000000)
del x1
time.sleep(1)
x2 = test2(1000000)
结果:
第一次查看是针对test1的,它没有完全就位,但它大大减少了内存使用。
字典[key]
是文件中的数据集dictionary[key][…]
将是一个numpy数组,数据集已下载
我想
sample[key] = dictionary[key]
被评估为
sample[key,...] = dictionary[key][...]
下载数据集,然后将其复制到样本
数组的一个片段中。下载的阵列应该可以免费回收。但numpy/python是否做到这一点则是另一回事。我没有打破记忆极限的习惯
您不想进行增量连接-这太慢了。列表上的单个连接应该更快。我不知道为什么会这样
list(dictionary.values)
包含。它是对数据集的引用,还是下载的数组?无论如何,concatenate(…)
在该列表中必须使用下载的数组
有一件事让我感到困惑-您如何使用相同的
键
索引示例
的第一维度和字典中的数据集
h5py
键应该是字符串,而不是整数
一些测试 请注意,我使用的是字符串数据集名称:
In [21]: d = f.create_dataset('0',data=np.zeros((2,3)))
In [22]: d = f.create_dataset('1',data=np.zeros((2,3)))
In [23]: d = f.create_dataset('2',data=np.ones((2,3)))
In [24]: d = f.create_dataset('3',data=np.arange(6.).reshape(2,3))
您的np.concatenate(列表(dictionary.values))
代码缺失()
:
e、 g:
让我们看看使用迭代方法时会发生什么:
创建一个数组,该数组可以为每个“行”获取一个数据集:
In [34]: samples = np.zeros((4,2,3),float)
In [35]: for i,d in enumerate(f.values()):
...: v = d[...]
...: print(v.__array_interface__['data']) # databuffer location
...: samples[i,...] = v
...:
(27845184, False)
(27815504, False)
(27845184, False)
(27815504, False)
In [36]: samples
Out[36]:
array([[[0., 0., 0.],
[0., 0., 0.]],
[[0., 0., 0.],
[0., 0., 0.]],
[[1., 1., 1.],
[1., 1., 1.]],
[[0., 1., 2.],
[3., 4., 5.]]])
在这个小示例中,它循环使用其他每个databuffer块。第二次迭代释放了第一次迭代中使用的数据缓冲区,然后可以在第三次迭代中重用,以此类推
这些是交互式
ipython
会话中的小数组。我不知道这些观察结果是否适用于大型情况。如何绘制RAM图片?变量a不是必需的,我连接到h5py,并从中获取数据,如何在不将其放入字典的情况下弹出它?它不应该是“np.array([a.pop(0)表示范围(n)中的I)]。重塑(-1)”(0,不是I)?此外,它对我也不起作用,当使用它而不是“a=np.concatenate(mylist,axis=0)”列表(dictionary.values)引用到数据集时,仍然会出现内存错误,concatenate将添加新的RAM。我自己的程序中的键已转换为int类型。迭代案例是一项很好的工作。可能与:
In [29]: [np.array(a) for a in f.values()]
Out[29]:
[array([[0., 0., 0.],
[0., 0., 0.]]), array([[0., 0., 0.],
[0., 0., 0.]]), array([[1., 1., 1.],
[1., 1., 1.]]), array([[0., 1., 2.],
[3., 4., 5.]])]
In [30]: [a[...] for a in f.values()]
....
In [34]: samples = np.zeros((4,2,3),float)
In [35]: for i,d in enumerate(f.values()):
...: v = d[...]
...: print(v.__array_interface__['data']) # databuffer location
...: samples[i,...] = v
...:
(27845184, False)
(27815504, False)
(27845184, False)
(27815504, False)
In [36]: samples
Out[36]:
array([[[0., 0., 0.],
[0., 0., 0.]],
[[0., 0., 0.],
[0., 0., 0.]],
[[1., 1., 1.],
[1., 1., 1.]],
[[0., 1., 2.],
[3., 4., 5.]]])