CUDNN详解

文章目录

CUDNN详解

一、引言

cuDNN(CUDA Deep Neural Network library)是NVIDIA为深度神经网络开发的GPU加速库。它提供了高效实现深度学习算法所需的基本构建块,如卷积、池化、激活函数等。cuDNN通过优化这些操作,显著提高了深度学习模型的训练和推理速度,是深度学习框架(如TensorFlow、PyTorch)在GPU上高效运行的关键组件。

二、cuDNN的基本使用

1、初始化cuDNN句柄

在使用cuDNN之前,需要创建一个cuDNN句柄,该句柄用于管理cuDNN的上下文。例如:

cpp 复制代码
cudnnHandle_t cudnn;
checkCUDNN(cudnnCreate(&cudnn));

这里使用了checkCUDNN宏来检查cuDNN函数调用的返回值,确保操作成功。

2、创建和设置描述符

cuDNN使用描述符(Descriptor)来描述张量(Tensor)、卷积核(Filter)和卷积操作(Convolution)等。例如,创建一个输入张量描述符并设置其属性:

cpp 复制代码
cudnnTensorDescriptor_t input_descriptor;
checkCUDNN(cudnnCreateTensorDescriptor(&input_descriptor));
checkCUDNN(cudnnSetTensor4dDescriptor(input_descriptor,
                                      CUDNN_TENSOR_NCHW,
                                      CUDNN_DATA_FLOAT,
                                      batch_size, channels, height, width));

这里设置了输入张量的格式(NCHW)、数据类型(float)和维度(批量大小、通道数、高度、宽度)。

三、执行卷积操作

1、设置卷积参数

在执行卷积操作之前,需要设置卷积核描述符和卷积描述符。例如:

cpp 复制代码
cudnnFilterDescriptor_t kernel_descriptor;
checkCUDNN(cudnnCreateFilterDescriptor(&kernel_descriptor));
checkCUDNN(cudnnSetFilter4dDescriptor(kernel_descriptor,
                                      CUDNN_DATA_FLOAT,
                                      CUDNN_TENSOR_NCHW,
                                      output_channels, input_channels, kernel_height, kernel_width));

cudnnConvolutionDescriptor_t convolution_descriptor;
checkCUDNN(cudnnCreateConvolutionDescriptor(&convolution_descriptor));
checkCUDNN(cudnnSetConvolution2dDescriptor(convolution_descriptor,
                                           padding_height, padding_width,
                                           vertical_stride, horizontal_stride,
                                           dilation_height, dilation_width,
                                           CUDNN_CROSS_CORRELATION,
                                           CUDNN_DATA_FLOAT));

这里设置了卷积核的大小、输入和输出通道数、步长、填充等参数。

2、选择卷积算法

cuDNN提供了多种卷积算法,可以选择最适合当前硬件和数据的算法。例如:

cpp 复制代码
int algo_count;
checkCUDNN(cudnnGetConvolutionForwardAlgorithmMaxCount(cudnn, &algo_count));
cudnnConvolutionFwdAlgo_t algo;
checkCUDNN(cudnnGetConvolutionForwardAlgorithm(cudnn,
                                               input_descriptor,
                                               kernel_descriptor,
                                               convolution_descriptor,
                                               output_descriptor,
                                               CUDNN_CONVOLUTION_FWD_PREFER_FASTEST,
                                               0,
                                               &algo));

这里选择了最快的卷积算法。

3、执行卷积

最后,使用选择的算法执行卷积操作:

cpp 复制代码
float alpha = 1.0f, beta = 0.0f;
checkCUDNN(cudnnConvolutionForward(cudnn,
                                   &alpha,
                                   input_descriptor, input_data,
                                   kernel_descriptor, kernel_data,
                                   convolution_descriptor,
                                   algo,
                                   workspace, workspace_size,
                                   &beta,
                                   output_descriptor, output_data));

这里alphabeta是缩放因子,input_datakernel_dataoutput_data分别是输入、卷积核和输出数据的指针。

四、使用示例

以下是一个完整的cuDNN卷积操作示例,包括初始化、设置描述符、执行卷积和清理资源:

cpp 复制代码
#include <iostream>
#include <cuda_runtime.h>
#include <cudnn.h>

#define CHECK_CUDNN(call) \
{ \
    cudnnStatus_t status = call; \
    if (status != CUDNN_STATUS_SUCCESS) { \
        std::cerr << "cuDNN error: " << cudnnGetErrorString(status) << std::endl; \
        exit(1); \
    } \
}

int main() {
    int batch_size = 1, channels = 1, height = 28, width = 28;
    int output_channels = 16, kernel_height = 3, kernel_width = 3;

    // 创建cuDNN句柄
    cudnnHandle_t cudnn;
    CHECK_CUDNN(cudnnCreate(&cudnn));

    // 创建输入张量描述符
    cudnnTensorDescriptor_t input_descriptor;
    CHECK_CUDNN(cudnnCreateTensorDescriptor(&input_descriptor));
    CHECK_CUDNN(cudnnSetTensor4dDescriptor(input_descriptor,
                                           CUDNN_TENSOR_NCHW,
                                           CUDNN_DATA_FLOAT,
                                           batch_size, channels, height, width));

    // 创建输出张量描述符
    cudnnTensorDescriptor_t output_descriptor;
    CHECK_CUDNN(cudnnCreateTensorDescriptor(&output_descriptor));
    CHECK_CUDNN(cudnnSetTensor4dDescriptor(output_descriptor,
                                           CUDNN_TENSOR_NCHW,
                                           CUDNN_DATA_FLOAT,
                                           batch_size, output_channels, height, width));

    // 创建卷积核描述符
    cudnnFilterDescriptor_t kernel_descriptor;
    CHECK_CUDNN(cudnnCreateFilterDescriptor(&kernel_descriptor));
    CHECK_CUDNN(cudnnSetFilter4dDescriptor(kernel_descriptor,
                                           CUDNN_DATA_FLOAT,
                                           CUDNN_TENSOR_NCHW,
                                           output_channels, channels, kernel_height, kernel_width));

    // 创建卷积描述符
    cudnnConvolutionDescriptor_t convolution_descriptor;
    CHECK_CUDNN(cudnnCreateConvolutionDescriptor(&convolution_descriptor));
    CHECK_CUDNN(cudnnSetConvolution2dDescriptor(convolution_descriptor,
                                                1, 1, 1, 1, 1, 1,
                                                CUDNN_CROSS_CORRELATION,
                                                CUDNN_DATA_FLOAT));

    // 选择卷积算法
    cudnnConvolutionFwdAlgo_t algo;
    CHECK_CUDNN(cudnnGetConvolutionForwardAlgorithm(cudnn,
                                                    input_descriptor,
                                                    kernel_descriptor,
                                                    convolution_descriptor,
                                                    output_descriptor,
                                                    CUDNN_CONVOLUTION_FWD_PREFER_FASTEST,
                                                    0,
                                                    &algo));

    // 分配内存
    float *input_data, *kernel_data, *output_data, *workspace;
    size_t workspace_size;
    cudaMalloc(&input_data, batch_size * channels * height * width * sizeof(float));
    cudaMalloc(&kernel_data, output_channels * channels * kernel_height * kernel_width * sizeof(float));
    cudaMalloc(&output_data, batch_size * output_channels * height * width * sizeof(float));
    CHECK_CUDNN(cudnnGetConvolutionForwardWorkspaceSize(cudnn,
                                                        input_descriptor,
                                                        kernel_descriptor,
                                                        convolution_descriptor,
                                                        output_descriptor,
                                                        algo,
                                                        &workspace_size));
    cudaMalloc(&workspace, workspace_size);

    // 执行卷积
    float alpha = 1.0f, beta = 0.0f;
    CHECK_CUDNN(cudnnConvolutionForward(cudnn,
                                        &alpha,
                                        input_descriptor, input_data,
                                        kernel_descriptor, kernel_data,
                                        convolution_descriptor,
                                        algo,
                                        workspace, workspace_size,
                                        &beta,
                                        output_descriptor, output_data));

    // 清理资源
    cudaFree(input_data);
    cudaFree(kernel_data);
    cudaFree(output_data);
    cudaFree(workspace);
    cudnnDestroyTensorDescriptor(input_descriptor);
    cudnnDestroyTensorDescriptor(output_descriptor);
    cudnnDestroyFilterDescriptor(kernel_descriptor);
    cudnnDestroyConvolutionDescriptor(convolution_descriptor);
    cudnnDestroy(cudnn);

    return 0;
}

这个示例展示了如何使用cuDNN进行二维卷积操作,包括初始化、设置描述符、选择算法、执行卷积和清理资源。

五、总结

cuDNN是深度学习中不可或缺的加速库,通过优化卷积、池化、激活等操作,显著提高了模型的训练和推理速度。掌握cuDNN的基本使用方法,可以帮助开发者更高效地实现深度学习模型。在实际应用中,cuDNN与CUDA、深度学习框架(如TensorFlow、PyTorch)紧密配合,提供了强大的计算支持。


版权声明:本博客内容为原创,转载请保留原文链接及作者信息。

参考文章

相关推荐
Little_Yuu4 天前
windows11(或centos7)安装nvidia显卡驱动、CUDA、cuDNN
cuda·cudnn
黄白柴柴22 天前
cudnn版本gpu架构
cuda·cudnn
因为风的缘故~1 个月前
Ubuntu22.04安装cuda12.1+cudnn8.9.2+TensorRT8.6.1+pytorch2.3.0+opencv_cuda4.9+onnxruntime-gpu1.18
pytorch·深度学习·tensorrt·cuda·anaconda·cudnn
leboop-L3 个月前
Windows11安装CUDA、cuDNN、PyTorch详解
pytorch·深度学习·gpu·cuda·windows11·cudnn
F_D_Z3 个月前
CUDNN下载&配置
cuda·cudnn
晨同学03273 个月前
RTX4060+ubuntu22.04+cuda11.8.0+cuDNN8.6.0 & 如何根据显卡型号和系统配置cuda和cuDNN所需的安装环境
cuda·cudnn
DogDaoDao3 个月前
Windows 环境搭建 CUDA 和 cuDNN 详细教程
人工智能·windows·python·深度学习·nvidia·cuda·cudnn
程序员小川4 个月前
Ubuntu22.04安装paddle
ai·cuda·paddle·cudnn
LiDAR点云5 个月前
ubuntu 20.04系统安装pytorch
cuda·cudnn·pytorch安装·ubuntu系统