Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/jsf/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C DGEMM和DGEMV给出了不同的结果_C_Blas - Fatal编程技术网

C DGEMM和DGEMV给出了不同的结果

C DGEMM和DGEMV给出了不同的结果,c,blas,C,Blas,我想在C中实现以下等式: C[l,q,m] = A[m,q,k] * B[k,l] 其中重复索引k被求和 我通过三种方式实现了这一点: 使用循环的朴素实现 使用BLAS例程DGEMV(矩阵向量乘法) 使用BLAS例程DGEMM(矩阵乘法) 这是最小的不工作代码: #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <

我想在C中实现以下等式:

C[l,q,m] = A[m,q,k] * B[k,l]
其中重复索引k被求和

我通过三种方式实现了这一点:

  • 使用循环的朴素实现
  • 使用BLAS例程DGEMV(矩阵向量乘法)
  • 使用BLAS例程DGEMM(矩阵乘法)
这是最小的不工作代码:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <cblas.h>

void main()
{

    const size_t n = 3;
    const size_t n2 = n*n;
    const size_t n3 = n*n*n;

    /* Fill rank 3 tensor with random numbers */
    double a[n3];
    for (size_t i = 0; i < n3; i++) {
        a[i] = (double) rand() / RAND_MAX;
    }

    /* Fill matrix with random numbers */
    double b[n2];
    for (size_t i = 0; i < n2; i++) {
        b[i] = (double) rand() / RAND_MAX;
    }

    /* All loops */
    double c_exact[n3];
    memset(c_exact, 0, n3 * sizeof(double));
    for (size_t l = 0; l < n; l++) {
        for (size_t q = 0; q < n; q++) {
            for (size_t m = 0; m < n; m++) {
                for (size_t k = 0; k < n; k++) {
                    c_exact[l*n2+q*n+m] += a[m*n2+q*n+k] * b[k*n+l];
                }
            }
        }
    }

    /* Matrix-vector */
    double c_mv[n3];
    memset(c_mv, 0, n3 * sizeof(double));
    for (size_t m = 0; m < n; m++) {
        for (size_t l = 0; l < n; l++) {
            cblas_dgemv(
                    CblasRowMajor, CblasNoTrans, n, n, 1.0, &a[m*n2],
                    n, &b[l], n, 0.0, &c_mv[l*n2+m], n);
        }
    }

    /* Matrix-matrix */
    double c_mm[n3];
    memset(c_mm, 0, n3 * sizeof(double));
    for (size_t m = 0; m < n; m++) {
        cblas_dgemm(
                CblasRowMajor, CblasTrans, CblasTrans, n, n, n, 1.0, b, n,
                &a[m*n2], n, 0.0, &c_mm[m], n2);
    }

    /* Compute difference */
    double diff_mv = 0.0;
    double diff_mm = 0.0;
    for (size_t idx = 0; idx < n3; idx++) {
        diff_mv += c_mv[idx] - c_exact[idx];
        diff_mm += c_mm[idx] - c_exact[idx];
    }
    printf("Difference matrix-vector: %e\n", diff_mv);
    printf("Difference matrix-matrix: %e\n", diff_mm);
}
i、 e.DGEMV的实施是正确的,DGEMM不是-我真的不理解这一点。我切换了乘法(矩阵乘法是非交换的)并对两者进行了转置,以获得正确的顺序C[l,q,m],而不是C[q,l,m],但我也尝试了在没有切换/转置的情况下使用它,但它不起作用

有人能帮忙吗? 谢谢


编辑:我想了一下,觉得我在尝试做一些DGEMM不支持的事情?也就是说,我尝试在C[:,:,m]中插入一个子矩阵,这意味着前导索引和尾随索引在内存中都不是连续的。DGEMM允许我设置参数LDC,在本例中,该参数需要为n^2,但它不知道第二个索引也不连续,跨距为n(并且没有参数告诉它?)。那么为什么DGEMM不支持尾随维度跨距的第二个参数呢?

DGEMM支持足够的跨距(存储间距)参数,以允许对
a
B
C
的任意矩形子矩阵进行操作。这似乎很合理,但如果您需要了解更多有关设计原理的信息,请尝试联系BLAS的原始创建者之一。@njuffa任意子矩阵?那我一定错过了什么。假设所有维度的范围都是N,我可以看到如何插入子矩阵
C[I,:,:]
(设置
LDC
to N pass
&C[I*N^2]
),我可以看到如何插入
C[:,I,:]
(将
LDC
设置为N^2,pass
)&C[I*N>,但我看不到如何插入
C[,:,:,:,](
LDC
需要是N^2,我需要通过
&C[I]
,但BLAS不知道中间索引也有N的跨步).我遗漏了什么?在矩形子矩阵的索引计算中,
N**2
一词在我看来是错误的,这不应该是类似于
LDC*N
的吗?此外,没有插入带有
GEMM
的子矩阵这样的事情,比如(缩放)产品已添加到
C
。假设您试图实现的目标可以通过
GEMM
实现(我对此不确定),您可以尝试绘制矩阵,并使用
GEMM
参数对图形进行注释。请记住,列主存储顺序用于存储矩阵。但我的子矩阵是方形的(所有扩展都是N),不是矩形的。否则它就不是
N**2
,而是
N*M
或类似的。我的参数alpha是1.0,beta是0.0,这相当于插入到
C
。我使用CblasRowMajor作为第一个参数,我假设它与我的行主存储一致。这对我来说意味着什么“绘制矩阵”?很抱歉,我忘记了
C
上的比例因子。我发现总是区分子矩阵('N',…)的维度和完整矩阵('LDC',…)的维度是很有用的,即使它们在特定情况下恰好重合“我的意思是拿一支铅笔和一张纸来画2D矩阵的布局,作为BLAS操作推理过程的一部分。这就是我过去所做的,当时我试图混淆一些BLAS函数及其众多参数的内部工作,特别是转置模式。
Difference matrix-vector: 0.000000e+00
Difference matrix-matrix: -1.188678e+01