Python uint8 numpy阵列的内存效率绝对差
我有两个大的np.uint8数组,a和b。我需要计算:Python uint8 numpy阵列的内存效率绝对差,python,arrays,numpy,integer-overflow,Python,Arrays,Numpy,Integer Overflow,我有两个大的np.uint8数组,a和b。我需要计算:c=np.sum(np.abs(a-b),axis=(-2,-1)) 因为它们是未签名的,所以我不能将它们减去。解决这个问题的一种天真的方法是将它们转换为更大的数据类型: c=np.sum(np.abs(a.astype(np.int16)-b.astype(np.int16)),轴=(-2,-1,) 总共使用了阵列内存的4*倍。在一个理想的世界里,我想成为一个会做这样事情的人: c=np.sum(np.abssub(a,b),轴=(-2,
c=np.sum(np.abs(a-b),axis=(-2,-1))
因为它们是未签名的,所以我不能将它们减去。解决这个问题的一种天真的方法是将它们转换为更大的数据类型:
c=np.sum(np.abs(a.astype(np.int16)-b.astype(np.int16)),轴=(-2,-1,)
总共使用了阵列内存的4*倍。在一个理想的世界里,我想成为一个会做这样事情的人:
c=np.sum(np.abssub(a,b),轴=(-2,-1,)
这将使用与阵列相同的内存量。遗憾的是,我在numpy的文档中找不到这样的函数。目前,我正在做以下工作:
diff=np.empty\u like(a)
掩码=a>b
差异[遮罩]=(a-b)[遮罩]
#b形状不同,但向a广播
#这就是为什么我在减法后使用掩码
掩码=np。逻辑\u非(掩码,输出=掩码)
差异[遮罩]=(b-a)[遮罩]
c=np.sum(np.abs(diff,out=diff),轴=(-2,-1,)
它使用的内存量仅为阵列的2.5**倍
有更好的方法吗
提供了一个非常简单但内存效率很高的环境,可在此处使用。在执行算术运算时,它会自动处理溢出。让我们来看看一个示例案例,看看如何解决我们的问题-< /P>
In [63]: a = np.array([3,252,89],dtype=np.uint8)
...: b = np.array([10,255,19],dtype=np.uint8)
In [64]: import numexpr as ne
In [65]: ne.evaluate('abs(a-b)')
Out[65]: array([ 7., 3., 70.])
因此,要获得所需的输出-
In [66]: int(ne.evaluate('sum(abs(a-b))'))
Out[66]: 80
与向上铸造的NumPy版本进行比较-
In [67]: np.sum(np.abs(a.astype(np.int16) - b.astype(np.int16)))
Out[67]: 80
内存效率
现在,让我们扩展到一个非常大的阵列,并检查问题的症结所在,即内存效率。我们将使用memory\u profiler
模块对其进行测试
Python脚本,其NumPy和numexpr
版本列为NumPy\u numexpr\u memeff.py
-
import numpy as np
import numexpr as ne
from memory_profiler import profile
np.random.seed(0)
a = np.random.randint(0,256,(1000000))
b = np.random.randint(0,256,(1000000))
@profile(precision=10)
def numpy1():
return np.sum(np.abs(a.astype(np.int16) - b.astype(np.int16)))
@profile(precision=10)
def numexpr():
return int(ne.evaluate('sum(abs(a-b))'))
if __name__ == '__main__':
numpy1()
if __name__ == '__main__':
numexpr()
import numpy as np
from memory_profiler import profile
np.random.seed(0)
a = np.random.randint(0,256,(1000000))
b = np.random.randint(0,256,(1000000))
@profile(precision=10)
def numpy1():
return np.sum(np.abs(a.astype(np.int16) - b.astype(np.int16)))
@profile(precision=10)
def numpy2():
return np.sum(np.abs(a.astype(np.int16) - b))
if __name__ == '__main__':
numpy1()
if __name__ == '__main__':
numpy2()
脚本的命令行运行结果-
$ python -m memory_profiler numpy_numexpr_memeff.py
Filename: numpy_numexpr_memeff.py
Line # Mem usage Increment Line Contents
================================================
9 63.0468750000 MiB 0.0000000000 MiB @profile(precision=10)
10 def numpy1():
11 65.3437500000 MiB 2.2968750000 MiB return np.sum(np.abs(a.astype(np.int16) - b.astype(np.int16)))
Filename: numpy_numexpr_memeff.py
Line # Mem usage Increment Line Contents
================================================
13 65.3437500000 MiB 0.0000000000 MiB @profile(precision=10)
14 def numexpr():
15 65.5859375000 MiB 0.2421875000 MiB return int(ne.evaluate('sum(abs(a-b))'))
因此,与NumPy版本相比,numexpr
version占用了十分之一的内存
性能
时间安排-
In [68]: np.random.seed(0)
...: a = np.random.randint(0,256,(1000000))
...: b = np.random.randint(0,256,(1000000))
In [71]: %timeit np.sum(np.abs(a.astype(np.int16) - b.astype(np.int16)))
3.99 ms ± 88.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [72]: %timeit int(ne.evaluate('sum(abs(a-b))'))
4.71 ms ± 112 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
因此,就性能而言,numexpr
version接近,但不如NumPy版本
另一个可能是,如果我们输入一个放大的,另一个在执行算术运算时会自动放大。所以,我们可以简单地做-
np.sum(np.abs(a.astype(np.int16) - b))
Python脚本来测试这一个的内存效率,如numpys\u memeff.py
-
import numpy as np
import numexpr as ne
from memory_profiler import profile
np.random.seed(0)
a = np.random.randint(0,256,(1000000))
b = np.random.randint(0,256,(1000000))
@profile(precision=10)
def numpy1():
return np.sum(np.abs(a.astype(np.int16) - b.astype(np.int16)))
@profile(precision=10)
def numexpr():
return int(ne.evaluate('sum(abs(a-b))'))
if __name__ == '__main__':
numpy1()
if __name__ == '__main__':
numexpr()
import numpy as np
from memory_profiler import profile
np.random.seed(0)
a = np.random.randint(0,256,(1000000))
b = np.random.randint(0,256,(1000000))
@profile(precision=10)
def numpy1():
return np.sum(np.abs(a.astype(np.int16) - b.astype(np.int16)))
@profile(precision=10)
def numpy2():
return np.sum(np.abs(a.astype(np.int16) - b))
if __name__ == '__main__':
numpy1()
if __name__ == '__main__':
numpy2()
结果-
$ python -m memory_profiler numpys_memeff.py
Filename: numpys_memeff.py
Line # Mem usage Increment Line Contents
================================================
8 56.6015625000 MiB 0.0000000000 MiB @profile(precision=10)
9 def numpy1():
10 59.1210937500 MiB 2.5195312500 MiB return np.sum(np.abs(a.astype(np.int16) - b.astype(np.int16)))
Filename: numpys_memeff.py
Line # Mem usage Increment Line Contents
================================================
12 59.1210937500 MiB 0.0000000000 MiB @profile(precision=10)
13 def numpy2():
14 59.3632812500 MiB 0.2421875000 MiB return np.sum(np.abs(a.astype(np.int16) - b))
在性能上,似乎也稍好一些-
In [68]: np.random.seed(0)
...: a = np.random.randint(0,256,(1000000))
...: b = np.random.randint(0,256,(1000000))
In [71]: %timeit np.sum(np.abs(a.astype(np.int16) - b.astype(np.int16)))
3.99 ms ± 88.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [73]: %timeit np.sum(np.abs(a.astype(np.int16) - b))
3.84 ms ± 29.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
您可以使用
#sizeof(a)
差异=a-b
#sizeof(a)
遮罩=b>a
np.负值(差异,其中=掩模,输出=差异)
c=np.和(差,轴=(-2,-1,)
或者用另一种方式:
def abssub(a, b):
diff = a - b
mask = b > a
return np.negative(diff, where=mask, out=diff)
c = np.sum(abssub(a, b), axis=(-2,-1,))
感谢您教我们如何使用
内存\u分析器
-迫不及待地想亲自尝试一下您是否愿意对a
和b
进行适当的变异以重用它们的内存?np.copyto(diff,(b-a),where=mask)
使用的内存比diff[mask]=(b-a)[mask]