连接具有最少内存的Numpy数组

时间:2018-07-18 09:10:20

标签: python arrays numpy memory

不是,我有50GB的数据集另存为h5py,这是其中的字典。字典包含从0到n的键,值是numpy ndarray(3维),具有相同的形状。例如:

dictionary [0] = np.array([[[...],[...]] ...])

我想连接所有这些np数组,像这样的代码

sample = np.concatenate(list(dictionary.values))

此操作浪费100GB内存!如果我使用

del dictionary

它将减少到50GB内存。但是我想在加载数据时将内存使用控制为50GB。我尝试过的另一种方式

    sample = np.concatenate(sample,dictionary[key])

它仍在使用100GB内存。我认为以上所有情况,右侧都会创建一个要保存的新内存块,然后分配给左侧,这将在计算期间将内存增加一倍。因此,我尝试这样的第三种方式

sample = np.empty(shape)
with h5py.File(...) as dictionary:
    for key in dictionary.keys():
        sample[key] = dictionary[key]

我认为这段代码有一个优势。将值di​​ctionary [key]分配给样本的某一行,然后会清除dictionary [key]的内存。但是,我对其进行了测试,发现内存使用量也为100GB。为什么?

是否有任何好的方法将内存使用量限制为50GB?

2 个答案:

答案 0 :(得分:1)

您的问题是您需要在内存中存储2个相同数据的副本。 如果像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)

结果:

enter image description here

test1 : 0.71 s
test2 : 1.39 s

第一次测试是针对test1的,虽然位置不正确,但是可以大大降低内存使用量。

答案 1 :(得分:0)

SELECT DISTINCT Id, ColumnId, (SELECT MAX(Type) FROM blog) AS type FROM Blog 是文件上的数据集。 dictionary[key]将是一个numpy数组,该数据集已下载。

我想像

dictionary[key][...]

被评估为

sample[key] = dictionary[key]

下载数据集,然后将其复制到sample[key,...] = dictionary[key][...] 数组的一部分。该下载的阵列应免费回收。但是是否numpy / python这样做是另一回事。我不习惯提高内存限制。

您不想执行增量连接-这很慢。列表上的单个串联应该更快。我不知道为什么这样

sample

包含。它是对数据集或下载的数组的引用吗?无论该列表上的list(dictionary.values) ,都必须使用下载的阵列。


有一件事使我感到困惑-您如何使用相同的concatenate(...)来索引key的第一维和sample中的数据集? dictionary键应该是字符串,而不是整数。


一些测试

请注意,我正在使用字符串数据集名称:

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(list(dictionary.values))

()

因此,这只是数据集的列表。当In [25]: f.values Out[25]: <bound method MappingHDF5.values of <HDF5 file "test.hf" (mode r+)>> In [26]: f.values() Out[26]: ValuesViewHDF5(<HDF5 file "test.hf" (mode r+)>) In [27]: list(f.values()) Out[27]: [<HDF5 dataset "0": shape (2, 3), type "<f8">, <HDF5 dataset "1": shape (2, 3), type "<f8">, <HDF5 dataset "2": shape (2, 3), type "<f8">, <HDF5 dataset "3": shape (2, 3), type "<f8">] 对列表的每个元素执行concatenate时,就会进行下载:

np.asarray(a)

例如:

In [28]: np.concatenate(list(f.values()))
Out[28]: 
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.]])

让我们看看使用迭代方法时会发生什么:

制作一个可以为每个“行”取一个数据集的数组:

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()]
    ....

在这个小例子中,它回收了其他所有数据缓冲区块。第2次迭代释放了第一个迭代中使用的数据缓冲区,然后可以在第3个迭代中重复使用,依此类推。

这些是交互式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.]]]) 会话中的小数组。我不知道这些观察是否适用于大案子。