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

如何将多维点积矩阵改写为矩阵乘法(Fortran/NumPy优化)

多维点积张量收缩的Fortran高效实现优化

问题背景

我维护着一个数值模拟Fortran代码库,当前核心计算逻辑是通过嵌套concurrent循环结合dot_product完成多维点积计算,代码如下:

n_dimensions = 2 ! 二维场景
n_faces = n_dimensions + 1 ! 二维三角形对应3个面

do concurrent(l=1:n_different_orders, k=1:n_different_orders)
    do concurrent(j=1:size(W(k,l)%array, 3), i=1:size(W(k,l)%array, 2), &
                  face=1:n_faces, jdim=1:n_dimensions, kdim=1:n_dimensions)
    ! 对所有点维度执行内积计算
    A(k,l)%array(kdim,jdim,face,i,j) &
        = dot_product(C(kdim,jdim,face,:), W(k,l)%array(face,i,j,:))
    end do
end do

该操作在OpenMP循环中重复数十万次,且C随迭代动态变化,是程序的核心耗时模块。我尝试通过BLAS/LAPACK的zgemm进行张量收缩改写,但结果不正确,改写代码如下:

m = 2 * 2 * 3
i = num_points
! 提取W数组的最大尺寸
max_n = maxval(ndof_per_order)**2 * 3

allocate(Amat(m, max_n), Wmat(max_n, i))

Cmat = reshape(C, [m, i])

do l=1, n_different_orders
    do k=1, n_different_orders
        n = 3 * size(W(k,l)%array, 3) * size(W(k,l)%array, 2)

        Wmat(1:n, 1:i) = reshape(W(k,l)%array, [n, i])

        call zgemm('N','T',m,n,i,1.0,Cmat,m,Wmat,n,0.0,Amat,m)

        A(k,l)%array = reshape(Amat(1:m, 1:n), [2, 2, 3, size(W(k,l)%array, 2), size(W(k,l)%array, 3)])
    end do
end do

参数规模

  • num_points:60~100
  • ndof_per_order:最大60
  • n_different_orders:1~9

Python验证参考

我在Python中用numpy.einsum和矩阵乘法实现了正确逻辑,但存在矩阵冗余,效率不如直接点积;按面拆分调用矩阵乘法的方案,效率仍未达预期。

完整验证代码

import numpy as np

np.random.seed(1)

ndofi = ndofj = 55
jdim = kdim = 2
faces = jdim + 1
points = 120

C = np.random.rand(kdim, jdim, faces, points)
W = np.random.rand(faces, ndofi, ndofj, points)
AA = np.einsum("abcd,cefd->abcef", C, W)

path_info = np.einsum_path("abcd,cefd->abcef", C, W, optimize="optimal")
print(path_info[0])
print(path_info[1])

AB = np.zeros((kdim, jdim, faces, ndofi, ndofj))
for k in range(kdim):
    for d in range(jdim):
        for f in range(faces):
            for i in range(ndofi):
                for j in range(ndofj):
                    AB[k, d, f, i, j] = np.dot(C[k, d, f, :], W[f, i, j, :])

C_mat = C.reshape(kdim * jdim * faces, points)
W_mat = W.reshape(faces * ndofi * ndofj, points)
A_mat = C_mat @ W_mat.T
A_tmp = A_mat.reshape(kdim, jdim, faces, faces, ndofi, ndofj)
AC = np.zeros((kdim, jdim, faces, ndofi, ndofj))
for f in range(faces):
    AC[:, :, f, :, :] = A_tmp[:, :, f, f, :, :]

assert np.allclose(AA, AB)
assert np.allclose(AC, AB)

按面拆分的实现代码

A = np.zeros((kdim, jdim, faces, ndofi, ndofj))

for f in range(faces):
    C_f = C[:, :, f, :].reshape(kdim * jdim, points)
    W_f = W[f, :, :, :].reshape(ndofi * ndofj, points)

    A_f = C_f @ W_f.T

    A[:, :, f, :, :] = A_f.reshape(kdim, jdim, ndofi, ndofj)

需求

寻求更高效的Fortran实现方案,降低该操作的运行时占比。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 15:05:54