CUBLAS库入门教程(从环境配置讲起)

news/2024/11/28 5:31:00/

文章目录

  • 前言
  • 一、搭建环境
  • 二、简单介绍
  • 三、 具体例子
  • 四、疑问


前言

CUBLAS库是NVIDIA CUDA用于线性代数计算的库。使用CUBLAS库的原因是我不想去直接写核函数。
(当然,你还是得学习核函数该怎么写。但是人家写好的肯定比我自己写的更准确!)


一、搭建环境

  1. 安装CUDA库,具体可以看我上一篇文章:在C++项目中集成CUDA程序加速(从环境配置讲起)
  2. 如果你是装在默认路径下,那么 CUBLAS库的头文件就在:C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.0\include 路径下面,以cublas开头的.h文件。
  3. 所以,还是按照步骤1的文章进行环境配置,然后只需要多在添加依赖项中增加一个cublas.lib就可以了。

二、简单介绍

  1. CUBLAS Introdution 是官方文档。(全英文的,还有不少数学公式。大家有不理解的可以直接留言区问相关API,我们一起讨论学习。)
  2. CUBLAS Samples 是官方示例,所有API都有。
  3. 对于API名称,都是cublasl<t>...,其中有下述类型选择:
    在这里插入图片描述
  4. CUBLAS库的矩阵是列向量的,跟glm一致。
  5. CUBLAS对于矩阵或者向量的index是从1开始的。所以,如果有函数的返回结果是个index(比如查找矩阵中的最大值),记得要index - 1才是我们要的。

三、 具体例子

下面我以矩阵与向量相乘的函数进行举例,看看是怎么用的。

  1. 首先,通过查找官方文档,知道是如下的函数:
cublasStatus_t cublasDgemv(cublasHandle_t handle, cublasOperation_t trans,int m, int n,const double          *alpha,const double          *A, int lda,const double          *x, int incx,const double          *beta,double          *y, int incy)
/*
* handle		: CUBLAS的句柄,用以管理CUBLAS库的上下文和资源
* CUBLAS_OP_N	: 指定矩阵操作模式。CUBLAS_OP_N代表正常模式(列向量);CUBLAS_OP_T代表转置模式(行向量)
* m				: 矩阵A的行数
* n				: 矩阵A的列数
* alpha			: 与矩阵A相乘的标量
* A				: 指向存储在device上面的矩阵数据指针
* lda			: 矩阵的列数,代表矩阵在内存中的存储方式
* x				: 向量X
* incx			: 向量x中相邻两个元素的index间隔,一般为1
* beta			: 与向量y相乘的标量
* y				: 向量y
* incy			: 向量y中相邻两个元素的index间隔,一般为1
*/

具体计算公式如下:
这是具体的计算公式

  1. 如果我们只是想计算矩阵和向量相乘,那么我们只需要令 α = 1.0, β = 0.0,然后传入我们要的Ax就行了。
  2. 最后,具体代码如下:
/// MyCublas.cuh#pragma once#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include "cublas_v2.h"extern "C" void MatrixMulVectorCublas(const double* matrix, const int row, const int col, const double* vector, double* result
);
/// MyCublas.cu#include "MyCublas.cuh"
#include "CublasUtility.h"void MatrixMulVectorCublas(const double* matrix, const int row, const int col,const double* vector, double* result)
{// 1. 初始化句柄cublasHandle_t handle;CUBLAS_CHECK(cublasCreate(&handle));// 2. 分配内存double* dev_matrix = NULL;double* dev_vector = NULL;CUDA_CHECK(cudaMalloc((void**)&dev_matrix, sizeof(double) * row * col));CUDA_CHECK(cudaMalloc((void**)&dev_vector, sizeof(double) * row));CUDA_CHECK(cudaMemcpy(dev_matrix, matrix, sizeof(double) * row * col, cudaMemcpyHostToDevice));CUDA_CHECK(cudaMemcpy(dev_vector, vector, sizeof(double) * row, cudaMemcpyHostToDevice));// 3. 执行矩阵乘法double* dev_result = NULL;CUDA_CHECK(cudaMalloc((void**)&dev_result, sizeof(double) * col));CUDA_CHECK(cudaMemset(dev_result, 0, sizeof(double) * col));const double alpha = 1.0;const double beta = 0.0;CUBLAS_CHECK(cublasDgemv(handle, CUBLAS_OP_N, row, col, &alpha, dev_matrix, col, dev_vector, 1, &beta, dev_result, 1));CUDA_CHECK(cudaMemcpy(result, dev_result, sizeof(double) * col, cudaMemcpyDeviceToHost));// 4. 释放内存CUDA_CHECK(cudaFree(dev_matrix));CUDA_CHECK(cudaFree(dev_vector));CUDA_CHECK(cudaFree(dev_result));CUBLAS_CHECK(cublasDestroy(handle));}
/// CublasUtility.h#pragma once
#include <string>
#include <stdexcept>
// CUDA API error checking
#define CUDA_CHECK(err)                                                                            \do {                                                                                           \cudaError_t err_ = (err);                                                                  \if (err_ != cudaSuccess) {                                                                 \std::printf("CUDA error %d at %s:%d\n", err_, __FILE__, __LINE__);                     \throw std::runtime_error("CUDA error");                                                \}                                                                                          \} while (0)// cublas API error checking
#define CUBLAS_CHECK(err)                                                                          \do {                                                                                           \cublasStatus_t err_ = (err);                                                               \if (err_ != CUBLAS_STATUS_SUCCESS) {                                                       \std::printf("cublas error %d at %s:%d\n", err_, __FILE__, __LINE__);                   \throw std::runtime_error("cublas error");                                              \}                                                                                          \} while (0)
/// main.cpp#include "MyCublas.cuh"#include <iostream>int main()
{double matrix[12] = { 1.0, 2.0, 3.0, 4.0,5.0, 6.0, 7.0, 8.0,9.0, 10.0, 11.0, 12.0};double vector[4] = { 1.0, 2.0, 3.0};double result[4] = { 0.0 };MatrixMulVectorCublas(matrix, 3, 4, vector, result);for (int i = 0; i < 4; ++i){std::cout << result[i] << ", ";}return 0;
}

四、疑问

对于上述代码,我还有以下的疑问:

  1. 我在运行下面这句的时候,VS显示我的进程内存会到2.2GB左右,难道真的需要这么大吗?
CUBLAS_CHECK(cublasCreate(&handle));
  1. 上述代码运行的结果是:38, 44, 50, 0。但是实际结果应该是:38, 44, 50, 56。查了很久还是没差出来为什么。希望有细心的小伙伴帮我检查一下!

http://www.ppmy.cn/news/1077441.html

相关文章

终端登录github两种方式

第一种方式 添加token&#xff0c;Setting->Developer Setting 第二种方式SSH 用下面命令查看远程仓库格式 git remote -v 用下面命令更改远程仓库格式 git remote set-url origin gitgithub.com:用户名/仓库名.git 然后用下面命令生成新的SSH秘钥 ssh-keygen -t ed2…

基于单片机的遥控器设计

一、项目介绍 随着科技的不断发展&#xff0c;红外遥控器已经成为我们日常生活中普遍使用的一种电子设备。它能够给我们带来便捷和舒适&#xff0c;减少人工操作的繁琐性。然而&#xff0c;在实际应用中&#xff0c;有时候我们可能需要制作一个自己的红外遥控器&#xff0c;以…

K8s 持久化存储有几种方式?一文了解本地盘/CSI 外接存储/K8s 原生存储的优缺点

当今云原生环境中&#xff0c;Kubernetes&#xff08;K8s&#xff09;已成为既定的容器编排工具。随着 K8s 的普及&#xff0c;存储也成为 K8s 用户关注的一个重要问题&#xff1a;为了满足不同的场景需求&#xff0c;K8s 可以支持基于不同架构的多种存储方案。这些方案间有什么…

django/CVE-2017-12794XSS漏洞复现

docker搭建漏洞复现环境 漏洞原理看帮助文档 # Django debug page XSS漏洞&#xff08;CVE-2017-12794&#xff09;分析Django发布了新版本1.11.5&#xff0c;修复了500页面中可能存在的一个XSS漏洞&#xff0c;这篇文章说明一下该漏洞的原理和复现&#xff0c;和我的一点点评…

【OJ比赛日历】快周末了,不来一场比赛吗? #09.03-09.09 #12场

CompHub[1] 实时聚合多平台的数据类(Kaggle、天池…)和OJ类(Leetcode、牛客…&#xff09;比赛。本账号会推送最新的比赛消息&#xff0c;欢迎关注&#xff01; 以下信息仅供参考&#xff0c;以比赛官网为准 目录 2023-09-03&#xff08;周日&#xff09; #5场比赛2023-09-04…

【元宇宙】游戏应用商城对元宇宙的影响

游戏行业不仅是创意设计原则的信息源&#xff0c;还是构建“下一代互联网”的基础技术。它也是元宇宙的经济活动先例。 究竟为什么会认为应用商城设置的30%佣金将导致元宇宙“无法实现”呢&#xff1f;有三个核心原因。首先&#xff0c;应用商城阻止了企业对元宇宙的投资&…

AI:04-基于机器学习的蘑菇分类

蘑菇是一类广泛分布的真菌,其中许多种类具有重要的食用和药用价值,但也存在着一些有毒蘑菇。因此,准确地区分可食用和有毒的蘑菇对于保障人们的食品安全和健康至关重要。本研究旨在基于机器学习技术开发一种蘑菇分类系统,以实现对蘑菇的自动分类和识别。通过构建合适的数据…

数据关联算法总结(不断更新)

数据关联的步骤&#xff1a; &#xff08;1&#xff09;建立关联门&#xff0c;确定关联门限 &#xff08;2&#xff09;门限过滤 &#xff08;3&#xff09;确定相似性度量方法 &#xff08;4&#xff09;建立关联矩阵 &#xff08;5&#xff09;确定关联判定准则 &#xff08…