4

假设我有两个 int8 类型的数组。我想在它们上使用 einsum,这样所有的计算都将作为 int64 完成,但我不想将整个数组转换为 int64。如果我理解正确,这就是 dtype 参数的用途。但它似乎并不总是有效。

它确实按预期工作的示例:

>>> A = np.array([[123, 45],[67,89]], dtype='int8')
>>> np.einsum(A,[0,1],A,[0,1],[1]) ## => integer overflow
array([-94, -38], dtype=int8)
>>> np.einsum(A,[0,1],A,[0,1],[1], dtype='int64') ## => no overflow
array([19618,  9946], dtype=int64)

无法按预期工作的示例:

>>> A = np.array([[123, 45],[67,89]], dtype='int8')
>>> np.einsum(A,[0,1],A,[1,2],[0,2]) ## => integer overflow
array([[-32,  68],
       [124, -72]], dtype=int8)
>>> np.einsum(A,[0,1],A,[1,2],[0,2], dtype='int64') ## => should not overflow, but it does
array([[-32,  68],
       [124, -72]], dtype=int8)

对于这些示例,我在带有 numpy 1.14.0 的 Windows 上使用了 python 3.6.4

当我尝试其他 dtypes 时也会发生同样的情况,例如 float64,即使我使用 cast='unsafe'。

为什么会发生这种情况,我怎样才能让它发挥作用?



更新
einsum 有 optimize=True 作为默认值,至少在 numpy 1.14.0 中。当使用 optimize=False 时,它​​会按预期工作(虽然对于大型数组来说要慢得多):

>>> A = np.array([[123, 45],[67,89]], dtype='int8')
>>> np.einsum(A,[0,1],A,[1,2],[0,2]) ## => integer overflow
array([[-32,  68],
       [124, -72]], dtype=int8)
>>> np.einsum(A,[0,1],A,[1,2],[0,2], dtype='int64', optimize=False)
array([[18144,  9540],
       [14204, 10936]], dtype=int64)


从 einsum.py 的简要介绍来看,似乎当 optimize=True 时,它​​会检查使用 numpy.tensordot 是否比 einsum 实现更好。如果是(它应该在我的第二个示例中,因为它只是一个常规矩阵乘法),那么它使用 tensordot,但它不会将 dtype 参数传递给它。事实上, tensordot 甚至没有 dtype 参数。


如果这是正确的,那么需要一个后续问题(这可能值得它自己的帖子?):
我如何矩阵乘以某个 dtype 的两个矩阵,比如 int8,这样所有的计算都将完成例如,int64 或 float64(因此不会溢出/丢失精度,除非 int64/float64 也会),但不必先将它们转换为所需的类型,此外,操作的实现本身不应转换矩阵总的来说,每次只有一小部分(因此操作所需的内存不会比保存这些矩阵和结果所需的内存大很多)?
这可以以与 numpy.dot 相当的效率完成吗?

4

0 回答 0