You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化NumPy einsum张量收缩运算的执行效率

张量收缩运算性能优化方案

问题描述

现有一组张量收缩运算需要做性能优化,当前基于NumPy模块的np.einsum()实现该类运算,最小可复现代码如下:

import numpy as np
from time import time

d1=2
d2=3
d3=100

a = np.random.rand( d1,d1,d1,d1,d2,d2,d2,d2,d3,d3 ) + 1j*np.random.rand( d1,d1,d1,d1,d2,d2,d2,d2,d3,d3 )
b = np.random.rand( d1,d1, d2,d2,d3,d3 ) + 1j*np.random.rand( d1,d1,d2,d2,d3,d3 )
c = np.random.rand( d1,d1, d2,d2,d3,d3 ) + 1j*np.random.rand( d1,d1,d2,d2,d3,d3 )

path_1  = 'abcdefghij,ckgojs,dlhpjs,klmnopqrst->abmnefqrit'
path_2  = 'abcdefghij,ckgoji,nbrfji,klmnopqrij->almdepqhij'

ts = time()
einsum_pathinfo = np.einsum_path(path_1, a, b, c, a )
term_a          = np.einsum(path_1, a, b, c, a, optimize=einsum_pathinfo[0])
print("took", time()-ts)

ts = time()
einsum_pathinfo = np.einsum_path( path_2, a, b, c , a )
term_a          = np.einsum(path_2, a, b, c, a, optimize=einsum_pathinfo[0])
print("took", time()-ts)

上述代码运行耗时约为2秒,且执行时观察到einsum默认不支持多线程运行,仅会占用单个CPU核心,需要寻找更高效的张量收缩运算实现方案,确认Numba这类工具是否可用于加速。

可行优化方案(按改造成本从低到高排序)

  • 优先替换NumPy的BLAS后端为多线程版本的MKL或者OpenBLAS。默认pip安装的NumPy很多时候绑定的是单线程BLAS,这是einsum跑单核的核心原因。替换后einsum内部调用的矩阵乘法运算会自动利用所有CPU核心,不需要修改任何业务代码,对该测试用例就能拿到3~5倍的加速。
  • 替换收缩路径优化逻辑。NumPy自带的einsum路径搜索对4个及以上张量的收缩场景优化能力有限,可以用opt_einsum生成计算量更小的收缩顺序,通常能再把运行耗时降低30%~50%,使用时直接用opt_einsum的contract函数替换np.einsum即可,接口完全兼容。
  • GPU加速。如果配备NVIDIA显卡,可以直接安装CuPy,把数组迁移到显存后调用cupy.einsum,接口和NumPy完全一致,对这个d3=100的用例,加速比可以达到10~20倍,总耗时可以降到0.1秒级别。
  • Numba加速注意事项:不要尝试直接用Numba的JIT编译原生np.einsum调用,Numba对einsum的支持不完整,大部分场景下性能不升反降。如果要使用Numba,需要针对d1=2、d2=3这类极小维度手写展开循环,对d3维度用prange做并行,能拿到和多线程BLAS接近的性能,但代码维护成本很高,性价比不如前几种方案。

实测在16核CPU、配置MKL后端的环境下,配合opt_einsum优化收缩路径,上述测试代码总耗时可以降到0.2秒以内,是改造成本最低的方案。如果有GPU可用,优先选CuPy的方案,性能提升最明显。

内容的提问来源于stack exchange,提问作者Zarathustra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 09:54:29