cuDNN深度神经网络计算库简介及卷积操作示例

张开发
2026/4/19 21:29:27 15 分钟阅读

分享文章

cuDNN深度神经网络计算库简介及卷积操作示例
cuDNN深度神经网络计算库简介及卷积操作示例​ cuDNN全称为NIVIDIA CUDA Deep Neural Network Library是深度神经网络算子层级GPU加速库集合提供了深度学习算法中常见算子的高效实现专门为深度学习框架如TensorFlow,PyTorchℎ,Caffe, MXNet等实现常见的神经网络层提供极致的优化的实现 ,所以也直接成为了很多上层推理引擎底层调优的算子备选实现比如TensorRT比如TVM。再换个角度理解之前在该系列笔记的第一篇提到宗旨“解读介绍英伟达软件生态之CUDA”中介绍了GPU的编程语言CUDACUDA C“调用CUDACUDA C其实就是为了写一些kernel而这里的cuDNN 则是提供一些写好的高效的CUDA C kernel的集合。正如该系列笔记介绍的cuFFTcuBLAS 区别就在于它们面向的应用场景不同这里的cuDNN就是面向深度神经网络算子的高效实现。​1.cuDNN的句柄与描述子在cuDNNcuDNN里几乎所有操作都需要以下几个基本对象我们这些基本对象进行描述A.句柄cudnnHandle_t​ 在使用cuDNN进行任何操作之前需要初始化cuDNN上下文。可以使用cudnnCreate()函数来创建一个cuDNN上下文句柄后续的所有cuDNN操作都将基于这个句柄进行。句柄(cudnnHandle_t)是cuDNN中一个非常重要的概念它本质是一个指向cuDNN内部状态数据数据结构的指针句柄的作用类似于“会化ID”cuDNN通过它识别并管理当前的计算环境确保所有操作在正确的上下文如特定GPU设备、资源分配状态等中执行。​ handle是cudnnHandle_t类型的变量的指针。cudnCreate函数接收这个地址后就能在函数内部将创建的上下文句柄直接赋值到cudnn变量所在的内存空间这样在函数调用结束后外部的handle变量就保存了有效的上下文句柄供后续操作使用。cudnnStatus_t cudnnCreate(cudnnHandle_t *handle); cudnnStatus_t cudnnDestroy(cudnnHandle_t handle);作用创建cuDNNcuDNN上下文句柄类似于CUDA runtimeCUDA runtime的cudaStream。所有操作都依赖它参数handleℎ 是cuDNNcuDNN运行环境的句柄;创建与销毁句柄通过cudnnCreate()函数创建在使用完成后必须通过cudnnDestroy()函数进行销毁以释放句柄所占用的资源避免内存泄漏线性安全性cuDNN句柄不是线性安全的每个线程应该使用独立的句柄对象。如果在多个线程环境中使用同一个句柄可能导致不可预测的错误。因此在多线程编程时需要为每个线程单独创建和管理句柄。与CUDA上下文的关联cuDNN句柄通常是管理GPU资源的基础cuDNN句柄通过关联的CUDA上下文来访问GPU硬件资源进行数据传输和计算操作。cudnnStatus_t是cuDNN所有函数调用的返回状态类型理解它非常重要因为它决定了你能否成功调用cuDNN APIcuDNN API 。typedef enum { CUDNN_STATUS_SUCCESS 0, CUDNN_STATUS_NOT_INITIALIZED 1, CUDNN_STATUS_ALLOC_FAILED 2, CUDNN_STATUS_BAD_PARAM 3, CUDNN_STATUS_INTERNAL_ERROR 4, CUDNN_STATUS_INVALID_VALUE 5, CUDNN_STATUS_ARCH_MISMATCH 6, CUDNN_STATUS_MAPPING_ERROR 7, CUDNN_STATUS_EXECUTION_FAILED 8, CUDNN_STATUS_NOT_SUPPORTED 9, CUDNN_STATUS_LICENSE_ERROR 10, CUDNN_STATUS_RUNTIME_PREREQUISITE_MISSING 11 } cudnnStatus_t;枚举值含义说明CUDNN_STATUS_SUCCESS成功调用成功没有错误CUDNN_STATUS_NOT_INITIALIZED未初始化cuDNN handle 未创建或初始化失败CUDNN_STATUS_ALLOC_FAILED内存分配失败GPU 内存不足cudaMalloc 失败CUDNN_STATUS_BAD_PARAM参数错误函数参数有误类型或维度不匹配CUDNN_STATUS_INTERNAL_ERROR内部错误cuDNN 内部执行错误不是你传的参数问题CUDNN_STATUS_INVALID_VALUE数值错误数值超出范围例如 stride、padding 不合理CUDNN_STATUS_ARCH_MISMATCH架构不匹配当前 GPU 架构不支持所选算法CUDNN_STATUS_MAPPING_ERROR内存映射错误GPU 内存映射出错CUDNN_STATUS_EXECUTION_FAILED执行失败kernel 执行失败例如溢出或 cuda kernel 错误CUDNN_STATUS_NOT_SUPPORTED不支持该功能或数据类型不被支持CUDNN_STATUS_LICENSE_ERROR许可错误需要授权许可但未满足条件CUDNN_STATUS_RUNTIME_PREREQUISITE_MISSING依赖缺失运行时依赖库缺失或版本不匹配​ 描述符是cuDNN 中用于描述各种对象属性的数据结构它为cuDNN函数提供了执行操作所需的元数据信息。cuDNN中存在多种类型的描述符如张量描述符(cudnnTensorDescriptor_t)卷积描述符(cudnnConvolutionDescriptor_t)池化描述符cudnnPoolingDescriptor_t等不同类型的描述符用于描述不同的操作。​B.张量描述子cudnnTensorDescriptor_t​ 张量描述符(cudnnTensorDescriptor_t) 用于描述各种对象属性的数据结构它为cuDNN函数提供了执行操作所需的元数据信息。包括数据张量的如批量大小、通道数、高度、宽度等、数据类型如CUDNN_DATA_FLOAT表示32位浮点数、张量布局如CUDNN_TENSOR_NCHW表示数据批量-通道-高度-宽度的布局。通过cudnnCreateTensorDescriptor()创建cudnnSetTensor4dDescriptor()等函数设置属性cudnnDestroyDescriptor()销毁。cudnnStatus_t cudnnCreateTensorDescriptor(cudnnTensorDescriptor_t *tensorDesc); cudnnStatus_t cudnnSetTensor4dDescriptor( cudnnTensorDescriptor_t tensorDesc, cudnnTensorFormat_t format, // NCHW 或 NHWC cudnnDataType_t dataType, // float, half, double... int n, int c, int h, int w // 维度 ); cudnnStatus_t cudnnDestroyTensorDescriptor(cudnnTensorDescriptor_t tensorDesc);作用描述输入、输出张量的维度和数据类型。张量在cuDNN中通常按照4D格式(N,C,H,W)4D格式(N,C,H,W)假设NCHW格式存储Nbatch size代表一批量输入样本的数量C通道数例如RGB图像就是3个通道灰度图就是1个通道H图像的行数高度W 图像的列数宽度cudnnTensorFormat_t代表张量的格式typedef enum { CUDNN_TENSOR_NCHW 0, // [batch, channels, height, width] CUDNN_TENSOR_NHWC 1, // [batch, height, width, channels] CUDNN_TENSOR_NCHW_VECT_C 2 // 向量化通道格式 (主要用于部分卷积加速) } cudnnTensorFormat_t;枚举值说明CUDNN_TENSOR_NCHW最常用格式张量按[N, C, H, W]存储适合大多数卷积、批量计算。CUDNN_TENSOR_NHWC张量按[N, H, W, C]存储在某些 GPU 架构如 Tensor Core上可能更快CUDNN_TENSOR_NCHW_VECT_C向量化通道存储格式一般用于卷积加速通道数必须是 4 的倍数cudnnDataType_t是cuDNNcuDNN库中用于指定张量数据类型的枚举类型它定义了深度学习操作中支持的数据格式包括精度和存储方式。typedef enum { CUDNN_DATA_FLOAT 0, // 32-bit float CUDNN_DATA_DOUBLE 1, // 64-bit double CUDNN_DATA_HALF 2, // 16-bit float (FP16) CUDNN_DATA_INT8 3, // 8-bit integer CUDNN_DATA_INT32 4, // 32-bit integer CUDNN_DATA_INT8x4 5, // 8-bit integer pack of 4 CUDNN_DATA_UINT8 6, // 8-bit unsigned integer CUDNN_DATA_INT8x32 7 // 8-bit integer pack of 32 } cudnnDataType_t;其枚举值的含义如下cudnnDataType_t枚举值数据类型参数说明CUDNN_DATA_FLOATfloat32最常用数据类型精度高CUDNN_DATA_DOUBLEfloat64双精度GPU 上使用少性能低CUDNN_DATA_HALFfloat16半精度适合 Tensor Core 加速CUDNN_DATA_INT8int8量化神经网络使用CUDNN_DATA_INT32int32常用于累加或输出量化后的结果CUDNN_DATA_INT8x4 / INT8x32int8 pack8-bit 数据打包存储加速卷积CUDNN_DATA_UINT8uint8无符号 8-bit 数据C.卷积描述子(cudnnConvolutionDescriptor_t)​卷积描述符cudaConvolutionDescriptor_t)用于描述卷积张量操作的参数如填充大小(pad_h,pad_w)步长stride_h,stride_wdilation用于空洞卷积、卷积模式如CUDNN_CROSS_CORRELATION表示互相关模式在深度学习中通常等同于卷积操作)。由cudnnCreateConvolutionDescriptor()创建、cudnnSetConvolution2dDescriptor()设置属性cudnnDestroyConvolutionDescriptor()销毁。cudnnStatus_t cudnnCreateConvolutionDescriptor(cudnnConvolutionDescriptor_t *convDesc); cudnnStatus_t cudnnSetConvolution2dDescriptor( cudnnConvolutionDescriptor_t convDesc, int pad_h, int pad_w, // 填充 int u, int v, // 步长 (stride) int dilation_h, int dilation_w, cudnnConvolutionMode_t mode, // CUDNN_CONVOLUTION or CUDNN_CROSS_CORRELATION cudnnDataType_t computeType // 计算精度 ); cudnnStatus_t cudnnDestroyConvolutionDescriptor(cudnnConvolutionDescriptor_t convDesc);cudnnConvolutionMode_t是cuDNN库中用于指定卷积操作类型的枚举类型主要定义两种模式标准卷积和互相关。typedef enum { CUDNN_CONVOLUTION 0, // 标准卷积 CUDNN_CROSS_CORRELATION 1 // 互相关 (默认) } cudnnConvolutionMode_t;其枚举值含义枚举值含义说明CUDNN_CONVOLUTION卷积卷积核会翻转 180° 再做滑动窗口求和。数学上是标准卷积公式。CUDNN_CROSS_CORRELATION互相关卷积核不翻转直接在输入上做滑动窗口求和。cuDNN 默认使用这个模式。注意大多数深度学习框架PyTorch、TensorFlow默认使用互相关所以cuDNNcuDNN也默认使用CUDNN_CROSS_CORRELATION。​过滤器卷积核描述子(cudnnFilterDescriptor_t)是cuDNN中用于描述卷积滤波器(权重)张量的核心数据类型。它是cuDNN卷积操作中不同或缺的组成部分。由cudnnCreateConvolutionDescriptor()来创建cudnnSetFilter4dDescriptor()来设置卷积算子cudnnDestroyFilterDescriptor() 销毁cudnnStatus_t cudnnCreateFilterDescriptor(cudnnFilterDescriptor_t *filterDesc); cudnnStatus_t cudnnSetFilter4dDescriptor( cudnnFilterDescriptor_t filterDesc, cudnnDataType_t dataType, cudnnTensorFormat_t format, int k, int c, int h, int w ); cudnnStatus_t cudnnDestroyFilterDescriptor(cudnnFilterDescriptor_t filterDesc);D. 卷积操作算子cudnnConvolutionForward计算卷积算子的输出尺寸cudnnStatus_t cudnnGetConvolution2dForwardOutputDim( const cudnnConvolutionDescriptor_t convDesc, // 卷积描述子 const cudnnTensorDescriptor_t inputTensorDesc, // 输入张量描述子 const cudnnFilterDescriptor_t filterDesc, // 卷积核描述子 int* n, int* c, int* h, int* w // 输出张量尺寸 );参数类型说明convDesccudnnConvolutionDescriptor_t卷积参数描述子包括 padding、stride、dilation、卷积模式等inputTensorDesccudnnTensorDescriptor_t输入张量描述子包含 N、C、H、W 以及数据类型、存储格式filterDesccudnnFilterDescriptor_t卷积核描述子包含 K、C、R、Sn, c, h, wint*输出张量的N、C、H、W由函数计算后返回对于输入尺寸Hin×Win× 和卷积核R×S×:Hout[Hin2⋅padh−dilationh⋅(R−1)−121]Wout[Wout2⋅padh−dilationw⋅(S−1)−121][2⋅ℎ−ℎ⋅(−1)−121][2⋅ℎ−⋅(−1)−121]选择卷积算法调用 cuDNN 核心 API在 GPU 上执行 3D 卷积计算结果存储到 GPU 输出内存 d_output 中。float alpha 1.0f, beta 0.0f; CHECK_CUDNN(cudnnConvolutionForward(cudnn, alpha, inputDesc, d_input, filterDesc, d_filter,convDesc, perfResults.algo, d_workspace, workspace_bytes, beta, outputDesc, d_output));alpha1.0f、beta0.0f卷积计算的系数对应公式outputα×conv(input,kernel)β×outputcudnnConvolutionForwardcuDNN 前向卷积核心 API参数依次是cuDNN 句柄 → 系数 α → 输入描述符 → GPU 输入数据 → 卷积核描述符 → GPU 卷积核 → 卷积规则描述符 → 最优算法 → 工作空间 → 工作空间大小 → 系数 β → 输出描述符 → GPU 输出数据。2.卷积案例在 CUDA 上通过 cuDNN 进行 3D 卷积计算一般需要做以下几步工作初始化 cuDNN 句柄创建 cuDNN 的核心句柄作为后续所有 cuDNN 操作的基础cudnnCreate()接口。构造输入张量描述符定义输入张量的维度NCHW 格式包含批次、通道、深度 / 高度 / 宽度、数据类型和内存步长步长通过自定义compute_stride函数计算。涉及cudnnCreateTensorDescriptor()、cudnnSetTensorNdDescriptor()接口。构造卷积核滤波器描述符定义卷积核的维度输出通道、输入通道、核深度 / 高度 / 宽度、数据类型和存储格式。涉及cudnnCreateFilterDescriptor()、cudnnSetFilterNdDescriptor()接口。计算 SAME 填充并构造卷积描述符先计算 SAME 卷积模式下的填充值再设置卷积的步长、膨胀系数指定卷积计算模式如互相关。涉及cudnnCreateConvolutionDescriptor()、cudnnSetConvolutionNdDescriptor()接口。计算输出张量尺寸并构造输出张量描述符通过 cuDNN 接口自动计算卷积输出的张量尺寸再定义输出张量的维度、数据类型和内存步长。涉及cudnnGetConvolutionNdForwardOutputDim()、cudnnCreateTensorDescriptor()、cudnnSetTensorNdDescriptor()接口。选取最优卷积算法并计算工作空间大小获取 cuDNN 推荐的最优前向卷积算法同时计算该算法所需的 GPU 工作空间大小。涉及cudnnGetConvolutionForwardAlgorithm_v7()、cudnnGetConvolutionForwardWorkspaceSize()接口。分配 GPU 设备内存并拷贝数据在设备端为输入、卷积核、输出张量及工作空间分配内存将主机端的输入数据和卷积核数据拷贝到设备端cudaMalloc、cudaMemcpy(cudaMemcpyHostToDevice)接口。执行 3D 卷积前向计算调用 cuDNN 卷积前向计算接口使用选定的最优算法完成 3D 卷积核心计算。涉及cudnnConvolutionForward()接口。拷贝输出数据到主机端将设备端完成卷积计算后的输出数据拷贝回主机端cudaMemcpy(cudaMemcpyDeviceToHost)接口。资源释放若不再需要相关资源释放设备端分配的内存销毁 cuDNN 的各类描述符张量、卷积核、卷积和 cuDNN 句柄。涉及cudaFree()、cudnnDestroyTensorDescriptor()、cudnnDestroyFilterDescriptor()、cudnnDestroyConvolutionDescriptor()、cudnnDestroy()接口。void compute_stride(const int* size, int* stride) { for (int i 4; i 0; i--) stride[i] (i 4) ? 1 : size[i 1] * stride[i 1]; } void cudnn_conv_3d(const float* input, const float* kernel, float* output, const int input_dims[3], const int kernel_dims[3]) { // -------------------------- 1. 初始化CUDNN句柄 -------------------------- cudnnHandle_t cudnn; CHECK_CUDNN(cudnnCreate(cudnn)); // -------------------------- 2. 构造输入张量描述符 -------------------------- int inputDims[5] { 1, 1, input_dims[0], input_dims[1], input_dims[2] }; // N1, C1, D/H/W int input_stride[5]; compute_stride(inputDims, input_stride); cudnnTensorDescriptor_t inputDesc; CHECK_CUDNN(cudnnCreateTensorDescriptor(inputDesc)); CHECK_CUDNN(cudnnSetTensorNdDescriptor(inputDesc, CUDNN_DATA_FLOAT, 5, inputDims, input_stride)); // -------------------------- 3. 构造卷积核描述符 -------------------------- int filterDims[5] { 1, 1, kernel_dims[0], kernel_dims[1], kernel_dims[2] }; // 输出通道1, 输入通道1, 核尺寸 cudnnFilterDescriptor_t filterDesc; CHECK_CUDNN(cudnnCreateFilterDescriptor(filterDesc)); CHECK_CUDNN(cudnnSetFilterNdDescriptor(filterDesc, CUDNN_DATA_FLOAT, CUDNN_TENSOR_NCHW, 5, filterDims)); // -------------------------- 4. 计算SAME填充并构造卷积描述符 -------------------------- int conmv_padA[3]; for (int i 0; i 3; i) { conmv_padA[i] (kernel_dims[i] - 1) / 2; // 计算SAME填充 } int conv_filterStrideA[3] { 1, 1, 1 }; // 步长1 int conv_dilationA[3] { 1, 1, 1 }; // 膨胀1 cudnnConvolutionDescriptor_t convDesc; CHECK_CUDNN(cudnnCreateConvolutionDescriptor(convDesc)); CHECK_CUDNN(cudnnSetConvolutionNdDescriptor(convDesc, 3, conmv_padA, conv_filterStrideA, conv_dilationA, CUDNN_CROSS_CORRELATION, CUDNN_DATA_FLOAT)); // -------------------------- 5. 计算输出张量尺寸并构造描述符 -------------------------- int outputDims[5]; CHECK_CUDNN(cudnnGetConvolutionNdForwardOutputDim(convDesc, inputDesc, filterDesc, 5, outputDims)); int output_stride[5]; compute_stride(outputDims, output_stride); cudnnTensorDescriptor_t outputDesc; CHECK_CUDNN(cudnnCreateTensorDescriptor(outputDesc)); CHECK_CUDNN(cudnnSetTensorNdDescriptor(outputDesc, CUDNN_DATA_FLOAT, 5, outputDims, output_stride)); // -------------------------- 6. 选取最优卷积算法 -------------------------- size_t in_bytes, out_bytes; CHECK_CUDNN(cudnnGetTensorSizeInBytes(inputDesc, in_bytes)); CHECK_CUDNN(cudnnGetTensorSizeInBytes(outputDesc, out_bytes)); size_t filt_bytes 1; for (int i 0; i 5; i) filt_bytes * filterDims[i]; filt_bytes * sizeof(float); // 获取最优卷积算法 int returnedAlgoCount 0; cudnnConvolutionFwdAlgoPerf_t perfResults; CHECK_CUDNN(cudnnGetConvolutionForwardAlgorithm_v7(cudnn, inputDesc, filterDesc, convDesc, outputDesc, 1, returnedAlgoCount, perfResults)); // 计算工作空间大小 size_t workspace_bytes 0; CHECK_CUDNN(cudnnGetConvolutionForwardWorkspaceSize(cudnn, inputDesc, filterDesc, convDesc, outputDesc, perfResults.algo, workspace_bytes)); // -------------------------- 7. 分配设备内存并拷贝数据 -------------------------- float* d_input nullptr, * d_filter nullptr, * d_output nullptr; void* d_workspace nullptr; CHECK_CUDA(cudaMalloc((void**)d_input, in_bytes)); CHECK_CUDA(cudaMalloc((void**)d_filter, filt_bytes)); CHECK_CUDA(cudaMalloc((void**)d_output, out_bytes)); if (workspace_bytes 0) { CHECK_CUDA(cudaMalloc((void**)d_workspace, workspace_bytes)); } // 主机到设备拷贝 CHECK_CUDA(cudaMemcpy(d_input, input, in_bytes, cudaMemcpyHostToDevice)); CHECK_CUDA(cudaMemcpy(d_filter, kernel, filt_bytes, cudaMemcpyHostToDevice)); // -------------------------- 8. 执行卷积计算 -------------------------- float alpha 1.0f, beta 0.0f; CHECK_CUDNN(cudnnConvolutionForward(cudnn, alpha, inputDesc, d_input, filterDesc, d_filter, convDesc, perfResults.algo, d_workspace, workspace_bytes, beta, outputDesc, d_output)); // -------------------------- 9. 设备到主机拷贝输出 -------------------------- CHECK_CUDA(cudaMemcpy(output, d_output, out_bytes, cudaMemcpyDeviceToHost)); // -------------------------- 10. 资源释放 -------------------------- CHECK_CUDA(cudaFree(d_input)); CHECK_CUDA(cudaFree(d_filter)); CHECK_CUDA(cudaFree(d_output)); CHECK_CUDA(cudaFree(d_workspace)); CHECK_CUDNN(cudnnDestroyTensorDescriptor(outputDesc)); CHECK_CUDNN(cudnnDestroyConvolutionDescriptor(convDesc)); CHECK_CUDNN(cudnnDestroyFilterDescriptor(filterDesc)); CHECK_CUDNN(cudnnDestroyTensorDescriptor(inputDesc)); CHECK_CUDNN(cudnnDestroy(cudnn)); }#define _CRT_SECURE_NO_WARNINGS #include rscudaalgo.h #include cstdio #include cstdlib #include chrono #include cmath #include vector #include fundamental.h #include segy.h #include alloc.h #include qdebug.h //测试三维卷积 void test_conv3d() { const char* filename_input smallCube.sgy; //输入文件名 const char* filename_output conv_small.sgy; //输出文件名 FILE* fp_input nullptr; //输入文件的文件指针 FILE* fp_output nullptr; //输出文件的文件指针 bhed fileheader; //定义文件头 segy* traceheader_array nullptr; //道头数组指针 float* datacube_input nullptr; //输入地震数据的三维指针 float* datacube_output nullptr; //输出地震数据的三维指针 unsigned int size_fileheader sizeof(fileheader); unsigned int size_traceheader sizeof(segy); unsigned int nline 0; //三维地震数据的测线数 unsigned int ncdp 0; //三维地震数据的CDP数 unsigned int nt 0; //三维地震数据的时间采样数 long long ntrace 0; long long size_inputcube 0; long long size_trace 0; nline 100; ncdp 500; fp_input fopen(filename_input, rb); if (fp_input nullptr) { printf(Cannot open this input file!!!\n); qDebug() Cannot open this input file!!!\n; system(pause); return; }//end if(fp_inputnullptr) fp_output fopen(filename_output, wb); if (fp_output nullptr) { printf(Cannot open\create this output file!!!\n); qDebug() Cannot open\create this output file!!!\n; system(pause); return; }//end if(fp_outputnullptr) /*判断地震数据是否为规则的*/ fread(fileheader, size_fileheader, 1, fp_input); nt fileheader.hns; size_trace size_traceheader nt * sizeof(float); _fseeki64(fp_input, 0, SEEK_END); size_inputcube _ftelli64(fp_input); ntrace (size_inputcube - size_fileheader) / (size_trace); _fseeki64(fp_input, size_fileheader, SEEK_SET); if (ntrace ! (nline * ncdp)) { printf(Cube is not regularized!!!\n); return; } /*读取规则的地震数据体及处理输出*/ int input_dims[3] { nline, ncdp, nt }; int nAllSize input_dims[0] * input_dims[1] * input_dims[2]; datacube_input new float[nAllSize]; memset(datacube_input, 0, nAllSize * sizeof(float)); traceheader_array (segy*)calloc(nline * ncdp, size_traceheader); datacube_output new float[nAllSize]; memset(datacube_output, 0, nline * ncdp * nt * sizeof(float)); for (int iline 0; iline nline; iline) { //读取三维地震属性体 for (int icdp 0; icdp ncdp; icdp) { int nIndex (iline * ncdp icdp) * nt; //printf(iline%d,icdp%d,nIndex%d\n, iline, icdp, nIndex); fread(traceheader_array[iline * ncdp icdp], size_traceheader, 1, fp_input); fread(datacube_input[nIndex], nt * sizeof(float), 1, fp_input); }//end for(int icdp 0; icdp ncdp;icdp) }//end for(int iline 0; iline nline; iline) int cube2_dims[3] { 21,21,21 }; int nCube2Size cube2_dims[0] * cube2_dims[1] * cube2_dims[2]; float* pCube2 new float[nCube2Size]; memset(pCube2, 0, sizeof(float) * nCube2Size); getCube2(cube2_dims[0], cube2_dims[1], cube2_dims[2], pCube2); //开始计时 clock_t start_clock, end_clock; start_clock clock(); // 初始化输入数据主机到设备 // -------------------------- 8. 执行卷积并计时 -------------------------- cudnn_conv_3d(datacube_input, pCube2, datacube_output, input_dims, cube2_dims); //结束计时 end_clock clock(); double endtime (double)(end_clock - start_clock) / CLOCKS_PER_SEC; std::cout Total time: endtime s std::endl; //ms为单位 qDebug() Total time: endtime s endl; fwrite(fileheader, size_fileheader, 1, fp_output); for (int iline 0; iline nline; iline) { //写出三维地震属性体 for (int icdp 0; icdp ncdp; icdp) { int nIndex (iline * ncdp icdp) * nt; fwrite(traceheader_array[iline * ncdp icdp], size_traceheader, 1, fp_output); fwrite(datacube_output[nIndex], nt * sizeof(float), 1, fp_output); }//end for(int icdp 0; icdp ncdp;icdp) }//end for(int iline 0; iline nline; iline) // -------------------------- 9. 释放资源 -------------------------- fclose(fp_input); fclose(fp_output); delete[]datacube_input; delete[]datacube_output; free(traceheader_array); } int main() { test_conv3d(); return 0; }

更多文章