基本操作的Einsum优化失败

时间:2018-02-11 00:42:53

标签: python numpy matrix scipy numpy-einsum

随着Numpy(1.14)的最新更新,我发现它打破了我的整个代码库。这是基于将默认的numpy einsum optimize参数从False更改为True。

结果,以下基本操作现在失败:

a = np.random.random([50, 2, 2])
b = np.random.random([50, 2])

np.einsum('bdc, ac -> ab', a, b, optimize=True)

带有以下错误跟踪:

ValueError                                Traceback (most recent call last)
<ipython-input-71-b0f9ce3c71a3> in <module>()
----> 1 np.einsum('bdc, ac -> ab', a, b, optimize=True)

C:\ProgramData\Anaconda3\lib\site-packages\numpy\core\einsumfunc.py in 
einsum(*operands, **kwargs)
   1118 
   1119             # Contract!
-> 1120             new_view = tensordot(*tmp_operands, axes=
(tuple(left_pos), tuple(right_pos)))
   1121 
   1122             # Build a new view if needed

C:\ProgramData\Anaconda3\lib\site-packages\numpy\core\numeric.py in 
tensordot(a, b, axes)
   1301     oldb = [bs[axis] for axis in notin]
   1302 
-> 1303     at = a.transpose(newaxes_a).reshape(newshape_a)
   1304     bt = b.transpose(newaxes_b).reshape(newshape_b)
   1305     res = dot(at, bt)

 ValueError: axes don't match array

我从einsum请求的操作看起来非常简单......为什么它会失败?如果我设置&#34; optimize = False&#34;,它可以正常工作。

我尝试使用einsum_path进行探索,但结果路径信息在优化和不优化时都是相同的。

1 个答案:

答案 0 :(得分:2)

In [40]: a=np.ones((50,2,2),int); b=np.ones((50,2),int)
In [41]: np.einsum('bdc,ac->ab', a, b)
... 
ValueError: axes don't match array

我没有看到优化与此错误有什么关系。

第一个参数b,d,c是50,2,2。第二个a,c是50,2。结果应该是50,50。但是d发生了什么?

In [43]: np.einsum('bdc,ac->abd', a, b).shape
Out[43]: (50, 50, 2)

糟糕:

In [49]: np.einsum('bdc,ac->ab', a, b, optimize=False).shape
Out[49]: (50, 50)

所以它在d上汇总。

请注意错误 - 通过优化,它使用tensordot(转置加dot),而不是原始einsum nditer方法。

c_einsum可以处理丢失的d

# If no optimization, run pure einsum
if optimize_arg is False:
    return c_einsum(*operands, **kwargs)

尝试了一些时间:

使用默认优化的两步计算:

In [64]: timeit np.einsum('abd->ab', np.einsum('bdc,ac->abd', a, b))
288 µs ± 518 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)

所需的c_einsum更快

In [65]: timeit np.einsum('bdc,ac->ab', a, b, optimize=False)
170 µs ± 83.2 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

事实上即使c_einsum版本有效,tensordot也会更快

In [67]: timeit np.einsum('bdc,ac->abd', a, b,optimize=False)
73.1 µs ± 46.6 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [68]: timeit np.einsum('bdc,ac->abd', a, b,optimize=True)
207 µs ± 6.97 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

此示例可能太小,无法显示tensordot/blas的优势。

看起来这已经在github上引发了 - 失败和慢速'优化'速度:https://github.com/numpy/numpy/issues/10343“einsum broadcast regression(优化= True)”