Python uint8 numpy阵列的内存效率绝对差

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,

我有两个大的np.uint8数组,ab。我需要计算:
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]