【问题标题】:Finding maximum and minimum with CUBLAS使用 CUBLAS 找到最大值和最小值
【发布时间】:2012-05-05 22:44:12
【问题描述】:

我无法理解为什么我的函数使用 CUBLAS 在一系列双精度中找到最大值和最小值的函数不能正常工作。

代码如下:

void findMaxAndMinGPU(double* values, int* max_idx, int* min_idx, int n)
{
    double* d_values;
    cublasHandle_t handle;
    cublasStatus_t stat;
    safecall( cudaMalloc((void**) &d_values, sizeof(double) * n), "cudaMalloc     (d_values) in findMaxAndMinGPU");
    safecall( cudaMemcpy(d_values, values, sizeof(double) * n, cudaMemcpyHostToDevice), "cudaMemcpy (h_values > d_values) in findMaxAndMinGPU");
    cublasCreate(&handle);

    stat = cublasIdamax(handle, n, d_values, sizeof(double), max_idx);
    if (stat != CUBLAS_STATUS_SUCCESS)
        printf("Max failed\n");

    stat = cublasIdamin(handle, n, d_values, sizeof(double), min_idx);
    if (stat != CUBLAS_STATUS_SUCCESS)
        printf("min failed\n");

    cudaFree(d_values);
    cublasDestroy(handle);
}

其中 values 是要在其中搜索的值。 max_idx 和 min_idx 是值中找到的数字的索引。 CUBLAS 调用的结果似乎相当随机并且输出错误的索引。

有人对我的问题有很好的回答吗?我现在有点难过:(

【问题讨论】:

  • 尝试将max_idxmin_idx内部初始化为int而不是int *,并通过引用&max_idx将它们传递给cublas

标签: c++ c cuda cublas


【解决方案1】:

您对cublasIdamaxcublasIdamin 调用的一个论点是错误的。 BLAS 1 级调用中的incx 参数应始终是输入的字步幅,而不是字节。所以我怀疑你想要更多类似的东西:

stat = cublasIdamax(handle, n, d_values, 1, max_idx);
if (stat != CUBLAS_STATUS_SUCCESS)
    printf("Max failed\n");

stat = cublasIdamin(handle, n, d_values, 1, min_idx);
if (stat != CUBLAS_STATUS_SUCCESS)
    printf("min failed\n");

通过使用sizeof(double),您告诉例程使用步幅为 8,这将使调用超出输入数组的分配存储空间并进入未初始化的内存。我想你实际上在d_values 中的步幅为 1。


编辑:这是一个可以正常运行的完整示例。请注意,我将代码切换为单精度,因为我目前无法访问支持双精度的硬件:

#include <cuda_runtime.h>
#include <cublas_v2.h>
#include <cstdio>
#include <cstdlib>
#include <sys/time.h>


typedef float Real;

void findMaxAndMinGPU(Real* values, int* max_idx, int* min_idx, int n)
{
    Real* d_values;
    cublasHandle_t handle;
    cublasStatus_t stat;
    cudaMalloc((void**) &d_values, sizeof(Real) * n);
    cudaMemcpy(d_values, values, sizeof(Real) * n, cudaMemcpyHostToDevice);
    cublasCreate(&handle);

    stat = cublasIsamax(handle, n, d_values, 1, max_idx);
    if (stat != CUBLAS_STATUS_SUCCESS)
        printf("Max failed\n");

    stat = cublasIsamin(handle, n, d_values, 1, min_idx);
    if (stat != CUBLAS_STATUS_SUCCESS)
        printf("min failed\n");

    cudaFree(d_values);
    cublasDestroy(handle);
}

int main(void)
{
    const int vmax=1000, nvals=10000;

    float vals[nvals];
    srand ( time(NULL) );
    for(int j=0; j<nvals; j++) {
       vals[j] = float(rand() % vmax);
    }

    int minIdx, maxIdx;
    findMaxAndMinGPU(vals, &maxIdx, &minIdx, nvals);

    int cmin = 0, cmax=0;
    for(int i=1; i<nvals; i++) {
        cmin = (vals[i] < vals[cmin]) ? i : cmin;
        cmax = (vals[i] > vals[cmax]) ? i : cmax;
    }

    fprintf(stdout, "%d %d %d %d\n", minIdx, cmin, maxIdx, cmax);

    return 0;
}

编译和运行时会给出:

$ g++ -I/usr/local/cuda/include -L/usr/local/cuda/lib cublastest.cc -lcudart -lcublas
$ ./a.out
273 272 85 84

请注意,CUBLAS 遵循 FORTRAN 约定并使用 1 索引,而不是 0 索引,这就是 CUBLAS 和 CPU 版本之间存在 1 差异的原因。

【讨论】:

  • 不幸的是,这并不能解决我遇到的问题。仍然返回看似随机的结果。
  • @ssnielsen:运行我添加到答案中的完整重现案例会发生什么?
  • 它工作得很好。我没有注意到 1 索引以及 CUBLAS 对数字的绝对值起作用并查看数字是否已签名的事实。
【解决方案2】:

来自描述:最大幅度的元素: http://docs.nvidia.com/cuda/cublas/index.html#topic_6_1

if you have { 1, 2, 3, -33, 22, 11 }

结果将是 4!不是 5

abs(-33) > 22

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-16
    • 2012-06-21
    • 1970-01-01
    相关资源
    最近更新 更多