【问题标题】:How do you use cblas_dgemm to do a vector outer product?如何使用 cblas_dgemm 做向量外积?
【发布时间】:2015-05-16 01:29:46
【问题描述】:

我正在尝试将列向量与行向量相乘。我可以使用 dgemm 吗?

换句话说 D = A * B 其中 D 是矩阵,A 是列向量,B 是行向量。

我按照https://software.intel.com/en-us/node/520775 此处的文档进行操作。我似乎无法为 cblas_dgemm 获得正确的参数

这是我的尝试。在我的情况下,m = nRows,n = nCols,k = 1

问题似乎是lda、ldb和ldc。我已将它们分别定义为 nCols、k、nRows。

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>

#include <math.h>
#include <mkl.h>

#define nCols 5
#define nRows 20
#define k 1

void PrintMatrix(double* pMatrix, const size_t nR, const size_t nC, const CBLAS_ORDER Order) {
    unsigned int i, j;
    if (Order == CblasRowMajor)
    {
        for (i = 0; i < nR; i++)
        {
            for (j = 0; j < nC; j++)
            {
                printf("%f \t ", pMatrix[i * nC + j]); // !!!
            }
            printf("\n"); // !!!
        }

    }

    else

    {
        for (i = 0; i < nR; i++) {
            for (j = 0; j < nC; j++) {
                printf("%f \t ", pMatrix[i + j* nR ]); // !!!
            }
            printf("\n"); // !!!
        }

    }
    printf("\n"); // !!!

}

int main(void) {

    double A[] = { 8, 4, 7, 3, 5, 1, 1, 3, 2, 1, 2, 3, 2, 0, 1, 1 , 2, 3, 4, 1};

    double B[] = { -1, 2, -1, 1, 2 };


    double alpha = 1.0, beta = 0.0;
    int i, lda, ldb, ldc;
    double *C, *D;
    D = (double*) malloc(nRows * nCols * sizeof(double));
    C = (double*) malloc(nRows * nCols * sizeof(double));

    for (i = 0; i < nRows*nCols; i++)
        D[i] = 0.0;
    for (i = 0; i < nRows*nCols; i++)
        C[i] = 0.0;

    lda = nCols;
    ldb = k;
    ldc = nRows;

    cblas_dger(CblasRowMajor, nRows, nCols, alpha, A, 1, B, 1, C, nCols);

    PrintMatrix(C, nRows, nCols,CblasRowMajor);
    cblas_dgemm (CblasRowMajor, CblasNoTrans, CblasNoTrans, nRows,  nCols, k, alpha, A, lda, B, ldb, beta, D, ldc);

    PrintMatrix(D, nRows, nCols, CblasRowMajor);

    free(D);
    free(C);

    return 0;
}

【问题讨论】:

标签: c matrix vector blas intel-mkl


【解决方案1】:

简短的回答是,是的,您可以使用 dgemm 进行 rank-1 更新。当然建议使用dger,因为它有望针对此操作进行更好的优化。

cblas_dgemm的使用而言。如您所知,前导维度的定义是:

lda:矩阵A第一维的大小

您尝试执行的操作是: D(20x5) = A(20x1) * B(1x5)

您正在使用CblasRowMajor,因此所有矩阵的列数都是前导维度(有关说明,请参见https://stackoverflow.com/a/30208420/2707697)。含义:

lda = 1;
ldb = 5;
ldc = 5;

【讨论】:

  • 非常感谢 ctheo。我试过了,但是我遇到了同样的问题。它正在崩溃。
  • @themaze 我检查了程序并且在我的电脑上运行良好。检查您包含在源中的cblas.hCblasRowMajorCblasNoTrans 是如何定义的?
  • 我在不同的 Linux 发行版上对此进行了测试。 Fedora 和它的工作:)。谢谢
  • @themaze 看来这些变量在某些库中是不小心实现的。
  • 这是一个后续问题。由于其他一些原因,我切换回 OpenSuSE 42.2 并且代码给出了核心转储。尽管它在 Fedora 23-24 中运行良好。我试图找出问题所在。你有什么想法?我正在使用 MKL 11.3
【解决方案2】:

以下代码有效。我切换到列专业是因为在 Fortran BLAS 文档的上下文中更容易理解前导维度问题。很抱歉,我无法按照您提出的要求准确解决您的问题

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>

#include <math.h>
#include <mkl.h>

void PrintMatrix(double* pMatrix, const size_t nR, const size_t nC, const CBLAS_ORDER Order) {
    unsigned int i, j;
    if (Order == CblasRowMajor) {
        for (i = 0; i < nR; i++) {
            for (j = 0; j < nC; j++) {
                printf("%f \t ", pMatrix[i * nC + j]); // !!!
            }
            printf("\n"); // !!!
        }
    } else {
        for (i = 0; i < nR; i++) {
            for (j = 0; j < nC; j++) {
                printf("%f \t ", pMatrix[i + j* nR ]); // !!!
            }
            printf("\n"); // !!!
        }
    }
    printf("\n"); // !!!
}

int main(void)
{
    const int m = 20;
    const int n = 5;
    const int k = 1;

    double A[] = { 8, 4, 7, 3, 5, 1, 1, 3, 2, 1, 2, 3, 2, 0, 1, 1, 2, 3, 4, 1};
    double B[] = { -1, 2, -1, 1, 2 };

    double alpha = 1.0, beta = 0.0;

    double * C = (double*) malloc(m * n * sizeof(double));
    double * D = (double*) malloc(m * n * sizeof(double));

    for (int i = 0; i < m*n; i++) C[i] = 0.0;
    for (int i = 0; i < m*n; i++) D[i] = 0.0;

    int lda = 20;
    int ldb = 1;
    int ldc = 20;

    cblas_dger(CblasColMajor, m, n, alpha, A, 1, B, 1, C, ldc);

    cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, 
                m, n, k, 
                alpha, A, lda, 
                B, ldb, beta, 
                D, ldc);

    PrintMatrix(C, m, n, CblasRowMajor);
    PrintMatrix(D, m, n, CblasRowMajor);

    free(D);
    free(C);

    return 0;
}

【讨论】:

  • 谢谢杰夫。奇怪的是 cblas_dgemm 没有在我的系统上运行。
  • 什么版本的 MKL?平台信息?您可以尝试其他实现(GSL、ATLAS、OpenBLAS)来验证。
  • 我使用的是最新的 MKL 版本 11.2。我会尝试 OpenBlas 和 GSL。问题是我正在使用 vdMul,它似乎只在 MKL 中。您知道进行元素乘法的有效方法吗?
  • 您需要具体。对我来说,“最新”意味着夜间工程构建;-)
  • 逐元素矩阵乘法是带宽有限的,应该可以用循环实现。如果您发现 vdmul 运行速度明显加快,请发布该问题,我会尽力提供帮助。
猜你喜欢
  • 1970-01-01
  • 2013-01-17
  • 2023-04-08
  • 1970-01-01
  • 2016-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多