【问题标题】:Einsum optimize fails for basic operationEinsum 优化基本操作失败
【发布时间】:2018-02-11 00:42:52
【问题描述】:

随着最近对 Numpy (1.14) 的更新,我发现它破坏了我的整个代码库。这是基于将默认的 numpy einsum 优化参数从 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 请求的操作看起来很简单……那为什么会失败呢?如果我设置“optimize=False”,它工作得很好。

我尝试使用 einsum_path 进行探索,但得到的路径信息在优化和不优化的情况下是相同的。

【问题讨论】:

  • 可能是因为代码现在“尽可能”尝试使用 BLAS - 请参阅 github.com/numpy/numpy/blob/master/doc/release/1.14.0-notes.rst ?也许在github.com/numpy/numpy 上打开一个问题会更好
  • 我认为 path 在有 3 个或更多参数时很有用,并且有一个问题是应该先进行哪个 dot 收缩(以最快地减少问题空间)。这是一种不同类型的收缩问题。
  • 在推荐einsum的时候需要多注意这个optimize参数,尤其是在使用timeit测试的时候。很难知道它是使用原始的 c_einsum 还是这些假定的优化之一。
  • 我发现了错误问题,#10343。

标签: python numpy matrix scipy numpy-einsum


【解决方案1】:
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),而不是原来的einsumnditer 方法。

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 广播回归(优化=True)”

【讨论】:

  • 因为在 v1.13 中优化标志默认为 False。如果您运行此代码并手动设置标志,它确实有效: np.einsum('bdc,ac->ab', a, b, optimize=False) 给出 array([[4, 4, 4, .. ., 4, 4, 4], [4, 4, 4, ..., 4, 4, 4], [4, 4, 4, ..., 4, 4, 4], ..., [ 4, 4, 4, ..., 4, 4, 4], [4, 4, 4, ..., 4, 4, 4], [4, 4, 4, ..., 4, 4, 4]])
  • 类似地,在 v1.13 中,如果您手动设置 optimize=True,则会出现错误。因此,我觉得问题出在优化功能上?谁能证实这一点?
  • 我没有安装 1.13,所以无法测试这种行为。我可能应该删除这个答案。回了几个版本深入研究了einsum,但是最近没怎么关注优化。
  • 好的,当然。谢谢你的帮助。我相信这个问题仍然存在。
  • 我刚刚意识到,通过优化它不使用我研究过的nditer 方法 - 它使用tensordot
猜你喜欢
  • 2012-04-03
  • 1970-01-01
  • 2021-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-29
  • 2021-10-01
  • 2015-03-08
相关资源
最近更新 更多