Numba 函数比 C++ 慢,循环重新排序进一步减慢 x10
Numba function slower than C++ and loop re-order further slows down x10
以下代码模拟从一组图像中的不同位置提取二进制字。
下面代码中的 Numba 包装函数 wordcalc 有 2 个问题:
- 与 C++ 中的类似实现相比,它慢了 3 倍。
- 最奇怪的是,如果您调换 "ibase" 和 "ibit" for 循环的顺序,速度会下降 10 倍 (!)。这不会发生在 C++ 实现中,它仍然不受影响。
我正在使用 WinPython 2.7 中的 Numba 0.18.2
可能是什么原因造成的?
imDim = 80
numInsts = 10**4
numInstsSub = 10**4/4
bitsNum = 13;
Xs = np.random.rand(numInsts, imDim**2)
iInstInds = np.array(range(numInsts)[::4])
baseInds = np.arange(imDim**2 - imDim*20 + 1)
ofst1 = np.random.randint(0, imDim*20, bitsNum)
ofst2 = np.random.randint(0, imDim*20, bitsNum)
@nb.jit(nopython=True)
def wordcalc(Xs, iInstInds, baseInds, ofst, bitsNum, newXz):
count = 0
for i in iInstInds:
Xi = Xs[i]
for ibit in range(bitsNum):
for ibase in range(baseInds.shape[0]):
u = Xi[baseInds[ibase] + ofst[0, ibit]] > Xi[baseInds[ibase] + ofst[1, ibit]]
newXz[count, ibase] = newXz[count, ibase] | np.uint16(u * (2**ibit))
count += 1
return newXz
ret = wordcalc(Xs, iInstInds, baseInds, np.array([ofst1, ofst2]), bitsNum, np.zeros((iInstInds.size, baseInds.size), dtype=np.uint16))
通过从 np.uint16(u * (2**ibit))
更改为 np.uint16(u << ibit)
,我获得了 4 倍的加速;即用移位替换 2 的幂,这应该是等效的(对于整数)。
您的 C++ 编译器很可能会自行进行此替换。
交换两个循环的顺序对我来说对于你的原始版本 (5%) 和我的优化版本 (15%) 都有很小的不同,所以我认为我无法对此做出有用的评论.
如果您真的想比较 Numba 和 C++,可以在导入 Numba 之前通过执行 os.environ['NUMBA_DUMP_ASSEMBLY']='1'
查看编译后的 Numba 函数。 (虽然这显然很复杂)。
作为参考,我使用的是 Numba 0.19.1。
以下代码模拟从一组图像中的不同位置提取二进制字。
下面代码中的 Numba 包装函数 wordcalc 有 2 个问题:
- 与 C++ 中的类似实现相比,它慢了 3 倍。
- 最奇怪的是,如果您调换 "ibase" 和 "ibit" for 循环的顺序,速度会下降 10 倍 (!)。这不会发生在 C++ 实现中,它仍然不受影响。
我正在使用 WinPython 2.7 中的 Numba 0.18.2
可能是什么原因造成的?
imDim = 80
numInsts = 10**4
numInstsSub = 10**4/4
bitsNum = 13;
Xs = np.random.rand(numInsts, imDim**2)
iInstInds = np.array(range(numInsts)[::4])
baseInds = np.arange(imDim**2 - imDim*20 + 1)
ofst1 = np.random.randint(0, imDim*20, bitsNum)
ofst2 = np.random.randint(0, imDim*20, bitsNum)
@nb.jit(nopython=True)
def wordcalc(Xs, iInstInds, baseInds, ofst, bitsNum, newXz):
count = 0
for i in iInstInds:
Xi = Xs[i]
for ibit in range(bitsNum):
for ibase in range(baseInds.shape[0]):
u = Xi[baseInds[ibase] + ofst[0, ibit]] > Xi[baseInds[ibase] + ofst[1, ibit]]
newXz[count, ibase] = newXz[count, ibase] | np.uint16(u * (2**ibit))
count += 1
return newXz
ret = wordcalc(Xs, iInstInds, baseInds, np.array([ofst1, ofst2]), bitsNum, np.zeros((iInstInds.size, baseInds.size), dtype=np.uint16))
通过从 np.uint16(u * (2**ibit))
更改为 np.uint16(u << ibit)
,我获得了 4 倍的加速;即用移位替换 2 的幂,这应该是等效的(对于整数)。
您的 C++ 编译器很可能会自行进行此替换。
交换两个循环的顺序对我来说对于你的原始版本 (5%) 和我的优化版本 (15%) 都有很小的不同,所以我认为我无法对此做出有用的评论.
如果您真的想比较 Numba 和 C++,可以在导入 Numba 之前通过执行 os.environ['NUMBA_DUMP_ASSEMBLY']='1'
查看编译后的 Numba 函数。 (虽然这显然很复杂)。
作为参考,我使用的是 Numba 0.19.1。