Numpy 计算多个3x3矩阵乘法的最快方法

Numpy 计算多个3x3矩阵乘法的最快方法,numpy,gpu,matrix-multiplication,cupy,Numpy,Gpu,Matrix Multiplication,Cupy,我需要计算许多3x3旋转矩阵的组合 以下是使用numpy和cupy在matmul上应用functools.reduce的比较: import timeit 从functools导入reduce 将numpy作为np导入 作为cp导入cupy 从pyrr.matrix33导入从轴创建旋转 #生成随机旋转矩阵 轴=np.rand.rand(10000,3) 角度=np.pi*np.rand.rand(10000) 旋转=[从轴创建轴旋转(*params)用于zip中的参数(轴、角度)] #然后用ma

我需要计算许多3x3旋转矩阵的组合

以下是使用
numpy
cupy
matmul
上应用
functools.reduce
的比较:

import timeit
从functools导入reduce
将numpy作为np导入
作为cp导入cupy
从pyrr.matrix33导入从轴创建旋转
#生成随机旋转矩阵
轴=np.rand.rand(10000,3)
角度=np.pi*np.rand.rand(10000)
旋转=[从轴创建轴旋转(*params)用于zip中的参数(轴、角度)]
#然后用matmul还原
xp=np#numpy
xp_旋转=[xp.asarray(旋转)用于旋转中的旋转]
timexp=timeit.timeit(“reduce(xp.matmul,xp\u旋转)”,number=10,globals=globals()
打印(f“{xp.\uuuuuu name}:{timexp*1000:0.3}ms”)
xp=cp#cupy
xp_旋转=[xp.asarray(旋转)用于旋转中的旋转]
timexp=timeit.timeit(“reduce(xp.matmul,xp\u旋转)”,number=10,globals=globals()
打印(f“{xp.\uuuuuu name}:{timexp*1000:0.3}ms”)
在配备Titan GPU的好机器上,这将提供:

numpy: 1.63e+02ms
cupy: 8.78e+02ms
由于某些原因,GPU的速度要慢得多

在任何情况下,有没有一种方法可以大大加快计算速度

编辑 我发现了一个相当简单的解决方案,它适用于所有小线性变换链(并且可以很容易地扩展到仿射变换)


def reduce_循环(矩阵):
“”“非优化减少”“”
mat=矩阵[0]
对于矩阵[1:]中的_mat:
mat=mat@\u mat
回程垫
def减少_分割(矩阵):
“”“通过将矩阵对递归相乘来减少”“”
如果len(矩阵)==1:
返回矩阵[0]
neven=(len(矩阵)//2)*2
约化=矩阵[:neven:2]@矩阵[1:neven:2]
如果len(矩阵)>neven:#len(矩阵)是奇数
约化[-1]=约化[-1]@矩阵[-1]
返回减少分割(减少)
time=timeit.timeit(“减少循环(旋转)”,数字=10,全局=globals()
打印(f“减少循环:{time*1000:0.3}毫秒”)
time=timeit.timeit(“减少分割(旋转)”,数字=10,全局=globals()
打印(f“减少分割:{time*1000:0.3}毫秒”)
给予:

reduce_loop: 2.14e+02ms
reduce_split: 24.5ms
我确信它不是最优的,但它使用了
numpy
(可能还有
cupy
)优化

  • functools.reduce()已从核心python中删除,因为它效率低下且不符合python。没有cuPy等效项,只有functools库中的主机版本

  • 你的cuPy代码大部分时间都在徒劳地将数据从主机复制到设备,然后再复制回来。。。数千次-因为reduce()只在主机上运行,而不在GPU上运行。您正在使用PCI总线,而不是GPU

  • 考虑将列表“旋转”设置为cuPy矩阵,然后使用跨步(而不是python列表)

  • 使用cuPy还原内核执行matmul


  • 查看四元数。@QuangHoang谢谢,这很有趣,尽管我不想用四元数重新实现所有东西。然而,关于四元数乘法是否真的比矩阵乘法快,似乎仍有争论。谢谢。关于1和2:GPU将数据传输到CPU的确切时间我还不清楚。我实现的伪reduce函数(cf edit)在GPU上运行得并不好,并且不应该在每个循环中传输回数据。然而,GPU确实不适用于运行3x3矩阵乘法。4.找不到使用这些函数的方法(cupy.fuse也不是
    cupy.fuse
    ,这似乎更简单)。它仍然缺少一些文件。