我正在使用非常高维的向量进行机器学习,并考虑使用numpy来减少使用的内存量。我运行了一个快速测试,看看使用numpy(1)(3):可以节省多少内存
标准列表
import random
random.seed(0)
vector = [random.random() for i in xrange(2**27)]
Numpy阵列
import numpy
import random
random.seed(0)
vector = numpy.fromiter((random.random() for i in xrange(2**27)), dtype=float)
内存使用率(2)
Numpy array: 1054 MB
Standard list: 2594 MB
正如我所料
通过分配具有本机浮点数的连续内存块,numpy只消耗标准列表使用的一半内存。
因为我知道我的数据非常空闲,所以我对稀疏数据进行了同样的测试。
标准列表
import random
random.seed(0)
vector = [random.random() if random.random() < 0.00001 else 0.0 for i in xrange(2 ** 27)]
Numpy阵列
from numpy import fromiter
from random import random
random.seed(0)
vector = numpy.fromiter((random.random() if random.random() < 0.00001 else 0.0 for i in xrange(2 ** 27)), dtype=float)
内存使用率(2)
Numpy array: 1054 MB
Standard list: 529 MB
现在突然之间,python列表使用的内存量是numpy数组使用的一半!为什么
我可以想到的一件事是,当python检测到它包含非常稀疏的数据时,它会动态切换到dict表示。检查这个可能会增加很多额外的运行时开销,所以我真的不认为会发生这种情况
票据
- 我为每次测试都启动了一个新的python shell
- 用htop测量内存
- 在32位Debian上运行
Python列表只是Python对象的引用(指针)数组。在CPython(通常的Python实现)中,为了提高扩展效率,列表被稍微超额分配,但它从未被转换为dict。有关更多详细信息,请参阅源代码:列表对象实现
在列表的稀疏版本中,有很多指向单个int
0对象的指针。这些指针占用32位=4字节,但您的numpy浮点值肯定更大,可能是64位。
FWIW,为了使稀疏列表/数组测试更准确,您应该在两个版本中使用相同的种子调用random.seed(some_const)
,以便在Python列表和numpy数组中获得相同数量的零。