Результат cublasGemmEx всегда равен нулю

#c #cuda #cublas

#c #cuda #cublas

Вопрос:

Я попробовал умножение матрицы с помощью cublasGemmEx. A и b представляют собой половинную матрицу 1X1. Результат всегда равен нулю, если я задаю тип вычисления и тип даты вывода CUDA_R_16F . И результат будет правильным, если я установлю тип вычисления и тип даты вывода в CUDA_R_32F.

Кто-нибудь знает, почему результат равен нулю, если я устанавливаю типы в CUDA_R_16F? Заранее спасибо за ваши ответы.

Моя версия cuda — 10.2, графический процессор — T4. Я создаю приведенный ниже код с помощью команды ‘nvcc -arch= sm_75 test_cublas.cu -o тест_кублас -lcublas’

 #include "cublas_v2.h"
#include "library_types.h"
#include <stdio.h>

__global__ void init_kernel(half *a, half *b, half *c_half, float *c_float)
{
    *a = __float2half_rn(1.0);
    *b = __float2half_rn(1.5);
    *c_half = __float2half_rn(0.0);
    *c_float = 0.0;
}

__global__ void print_gpu_values(half *a, half *b, half *c_half, float *c_float)
{
    printf("a %f, b %f, c_half %f, c_float %fn", __half2float(*a), __half2float(*b), __half2float(*c_half), *c_float);
}

int main(int argc, char **argv)
{
    cudaStream_t cudaStream;
    if (cudaSuccess != cudaStreamCreateWithFlags(amp;cudaStream, cudaStreamNonBlocking))
    {
        printf("create cuda stream failedn");
        exit(-1);
    }

    cublasHandle_t handle;
    cublasCreate(amp;handle);
    if (CUBLAS_STATUS_SUCCESS != cublasSetStream(handle, cudaStream))
    {
        printf("cublas set stream failedn");
        exit(-1);
    }

    half *a;
    half *b;
    half *c_half;
    float *c_float;
    cudaMalloc(amp;a, sizeof(half));
    cudaMalloc(amp;b, sizeof(half));
    cudaMalloc(amp;c_half, sizeof(half));
    cudaMalloc(amp;c_float,sizeof(float));
    float alpha = 1.0;
    float beta = 1.0;

    init_kernel<<<1, 1, 0, cudaStream>>>(a, b, c_half, c_float);

    if (CUBLAS_STATUS_SUCCESS != cublasGemmEx(handle, CUBLAS_OP_N, CUBLAS_OP_N, 1, 1, 1,
        amp;alpha, b, CUDA_R_16F, 1, a, CUDA_R_16F, 1, amp;beta, c_half, CUDA_R_16F, 1, CUDA_R_16F, CUBLAS_GEMM_DEFAULT_TENSOR_OP))
    {
        printf("cublasGemmEx failedn");
        exit(-1);
    }

    if (CUBLAS_STATUS_SUCCESS != cublasGemmEx(handle, CUBLAS_OP_N, CUBLAS_OP_N, 1, 1, 1,
        amp;alpha, b, CUDA_R_16F, 1, a, CUDA_R_16F, 1, amp;beta, c_float, CUDA_R_32F, 1, CUDA_R_32F, CUBLAS_GEMM_DEFAULT_TENSOR_OP))
    {
        printf("cublasGemmEx failedn");
        exit(-1);
    }

    print_gpu_values<<<1, 1, 0, cudaStream>>>(a, b, c_half, c_float);
    cudaStreamSynchronize(cudaStream);

    return 0;

}
  

Ответ №1:

Согласно документации для cublasGemmEx, в частности для alpha beta параметров и, оба говорят:

того же типа, что и computeType

Однако ваш код не удовлетворяет этому требованию. Для (рабочего) CUDA_R_32F случая ваши alpha аргументы и beta аргументы типа float совпадают. Для (нерабочего) CUDA_R_16F случая они не совпадают.

Когда я изменяю ваш код с этим изменением, я получаю правильный результат на CUDA 11.0:

 # cat t3.cu
#include "cublas_v2.h"
#include "library_types.h"
#include <stdio.h>

__global__ void init_kernel(half *a, half *b, half *c_half, float *c_float)
{
    *a = __float2half_rn(1.0);
    *b = __float2half_rn(1.5);
    *c_half = __float2half_rn(0.0);
    *c_float = 0.0;
}

__global__ void print_gpu_values(half *a, half *b, half *c_half, float *c_float)
{
    printf("a %f, b %f, c_half %f, c_float %fn", __half2float(*a), __half2float(*b), __half2float(*c_half), *c_float);
}

int main(int argc, char **argv)
{
    cudaStream_t cudaStream;
    if (cudaSuccess != cudaStreamCreateWithFlags(amp;cudaStream, cudaStreamNonBlocking))
    {
        printf("create cuda stream failedn");
        exit(-1);
    }

    cublasHandle_t handle;
    cublasCreate(amp;handle);
    if (CUBLAS_STATUS_SUCCESS != cublasSetStream(handle, cudaStream))
    {
        printf("cublas set stream failedn");
        exit(-1);
    }

    half *a;
    half *b;
    half *c_half;
    float *c_float;
    cudaMalloc(amp;a, sizeof(half));
    cudaMalloc(amp;b, sizeof(half));
    cudaMalloc(amp;c_half, sizeof(half));
    cudaMalloc(amp;c_float,sizeof(float));
    float alpha = 1.0;
    float beta = 1.0;
    half halpha = __float2half_rn(alpha);
    half hbeta =  __float2half_rn(beta);

    init_kernel<<<1, 1, 0, cudaStream>>>(a, b, c_half, c_float);

    if (CUBLAS_STATUS_SUCCESS != cublasGemmEx(handle, CUBLAS_OP_N, CUBLAS_OP_N, 1, 1, 1,
        amp;halpha, b, CUDA_R_16F, 1, a, CUDA_R_16F, 1, amp;hbeta, c_half, CUDA_R_16F, 1, CUDA_R_16F, CUBLAS_GEMM_DEFAULT_TENSOR_OP))
    {
        printf("cublasGemmEx failedn");
        exit(-1);
    }

    if (CUBLAS_STATUS_SUCCESS != cublasGemmEx(handle, CUBLAS_OP_N, CUBLAS_OP_N, 1, 1, 1,
        amp;alpha, b, CUDA_R_16F, 1, a, CUDA_R_16F, 1, amp;beta, c_float, CUDA_R_32F, 1, CUDA_R_32F, CUBLAS_GEMM_DEFAULT_TENSOR_OP))
    {
        printf("cublasGemmEx failedn");
        exit(-1);
    }

    print_gpu_values<<<1, 1, 0, cudaStream>>>(a, b, c_half, c_float);
    cudaStreamSynchronize(cudaStream);

    return 0;

}
# nvcc t3.cu -o t3 -lcublas
# cuda-memcheck ./t3
========= CUDA-MEMCHECK
a 1.000000, b 1.500000, c_half 1.500000, c_float 1.500000
========= ERROR SUMMARY: 0 errors
# nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2020 NVIDIA Corporation
Built on Wed_Jul_22_19:09:09_PDT_2020
Cuda compilation tools, release 11.0, V11.0.221
Build cuda_11.0_bu.TC445_37.28845127_0
#
  

Комментарии:

1. Спасибо, это работает! Я не внимательно прочитал документ.