我有一段代码:
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import time
import numpy as np
for t in [np.uint8, np.int8]:
a=np.empty([480, 640], t)
v=[10, 245]
for y in range(480):
for x in range(640):
a[y, x]=v[x&1] # 50%=10, 50%=245
t1=time.clock()
a[a<32]=0
a[a>224]=0
t2=time.clock()
print("%2.3f ms"%((t2-t1)*1000), a.dtype)
我得到这个输出:
3.162 ms uint8
0.329 ms int8
如果它运行在一个有符号的数组上,为什么要快10倍?
有没有办法在无符号数组上加速呢?
是的…更多的样品也是一样的:
for t in [np.int8, np.uint8]:
a=np.empty([480, 640], t)
v=[10, 245]
for y in range(480):
for x in range(640):
a[y, x]=v[x&1] # 50%=10, 50%=235
t1=time.process_time()
for l in range(1000):
b=1*a # deep copy
b[b<32]=0
b[b>224]=0
t2=time.process_time()
print("%5.4f ms"%((t2-t1)*1000), a.dtype)
结果是:
328.0701 ms int8
3081.5300 ms uint8
最佳答案
为了确保每个人都知道时差从何而来,我将代码分解到每个单独的步骤:
整个密码
%%timeit
tmp = np.array(a, dtype=np.uint8, copy=True)
tmp[tmp < 30] = 0
tmp[tmp > 224] = 0
10个回路,最好3个:每个回路21.6 ms
%%timeit
tmp = np.array(a, dtype=np.int8, copy=True)
tmp[tmp < 30] = 0
tmp[tmp > 224] = 0
100个回路,最好3个:每个回路10.4 ms
所以是的,整个操作更快,但是让我们看看在每个设置操作中花费的时间:
%timeit tmp = np.array(a, dtype=np.uint8, copy=True); tmp[tmp < 30] = 0
tmp = np.array(a, dtype=np.uint8, copy=True)
tmp[tmp < 30] = 0
%timeit tmp2 = np.array(tmp, copy=True); tmp2[tmp2 > 224] = 0
100个回路,最好3个:每个回路19.3 ms
100个回路,最好3个:每个回路17.6 ms
因此,对于
int8
,每个设置都需要相同的时间:100个回路,最好3个:每个回路6.75ms
100个回路,最好3个:每个回路4.36ms
让我们看看如果只创建基于索引的新视图会发生什么:
%timeit tmp = np.array(a, dtype=np.uint8, copy=True); _ = tmp[tmp < 30]
tmp = np.array(a, dtype=np.uint8, copy=True)
tmp[tmp < 30] = 0
%timeit tmp2 = np.array(tmp, copy=True); _ = tmp2[tmp2 > 224]
100个回路,最好3个:每个回路17.9ms
100个回路,最好3个:每个回路16.2 ms
对于
int8
:100个回路,最好3个:每个回路7.64 ms
100个回路,最好3个:每个回路4.3 ms
仍然
int
更快。那么创建布尔掩码呢:%timeit tmp = np.array(a, dtype=np.uint8, copy=True); _ = tmp < 30
tmp = np.array(a, dtype=np.uint8, copy=True)
tmp[tmp < 30] = 0
%timeit tmp2 = np.array(tmp, copy=True); _ = tmp2 > 224
100个回路,最好3个:每个回路4.25 ms
100个回路,最好3个:每个回路2.58ms
对于
int8
:100个回路,最好3个:每个回路4.26 ms
100个回路,最好3个:每个回路4.08 ms
长话短说:在创建布尔掩码时,dtype并没有太大的区别,但是如果使用布尔掩码在数据上创建一个新视图,则使用
int
会更快但这只是一个幻觉,因为实际上numpy看到它在第一个操作中访问所有元素(因为在int8
中235 get被转换为-21),而在第二个操作中没有元素。两个操作的掩码都包含True和False(混合)。小结:因此numpy可以并且确实优化了获取和设置数组的所有/没有元素。
在你提到的评论中,
uint
对于v=[10,100]
更快,但是在我的计算机中,与上面相同的设置,两者都近似相同:uint: 10 loops, best of 3: 21.7 ms per loop
int: 10 loops, best of 3: 23.2 ms per loop
这是因为现在第一个操作有一个混合的布尔掩码,numpy不能像设置all/no元素那样优化它。但是第二个操作有一个布尔掩码,只有
uint
,所以numpy对uint和int都跳过这个。