【AI算法工程师必知必会】什么是CUDA?

在这里插入图片描述

什么是CUDA?

CUDA(Compute Unified Device Architecture)是NVIDIA推出的并行计算平台和编程模型,它允许开发者利用NVIDIA GPU的并行计算能力进行通用计算(即GPGPU,General-Purpose computing on Graphics Processing Units)。

传统上,GPU主要用于图形渲染,而CUDA通过扩展C/C++等语言,让开发者可以直接编写代码控制GPU的大规模并行线程,从而加速需要高并行度的任务(如深度学习、科学计算、图像处理等)。其核心是核函数(Kernel)——在GPU上并行执行的函数,由成百上千个线程同时运行。

如何入门CUDA开发?

入门CUDA开发需要掌握基础概念、搭建环境,并通过实践逐步深入,步骤如下:

1. 前置知识
  • C/C++基础:CUDA基于C扩展,核心语法与C兼容;
  • 并行计算概念:理解“线程(Thread)、线程块(Block)、网格(Grid)”的层次结构(GPU的并行单元组织方式);
  • GPU架构基础:了解GPU与CPU的差异(GPU核心数量远多于CPU,适合数据并行任务)。
2. 环境搭建
  • 硬件要求:需要支持CUDA的NVIDIA显卡(查看显卡型号是否在NVIDIA兼容列表中,计算能力≥3.0即可入门);
  • 软件安装
    • 安装CUDA Toolkit(包含编译器nvcc、调试工具Nsight、示例代码等);
    • 验证安装:终端运行nvcc --version查看版本,或运行/usr/local/cuda/samples/1_Utilities/deviceQuery检测设备是否正常。
3. 学习路径
  • 官方文档CUDA C++ Programming Guide(最权威的入门资料);
  • 实践入门:从简单的并行任务(如向量加法、矩阵乘法)开始,理解核函数调用、内存管理;
  • 深入优化:学习GPU内存模型(全局内存、共享内存、常量内存等)、线程同步、指令优化等。

优秀的CUDA开源库

CUDA生态有大量成熟的开源库,可避免重复开发,直接复用高性能并行算法:

库名称用途特点
Thrust并行算法库(类似STL)接口简单,支持排序、reduce、transform等
cuBLAS线性代数运算(矩阵/向量)高度优化,比CPU版本快10-100倍
cuFFT快速傅里叶变换支持多维FFT,适合信号处理
cuSPARSE稀疏矩阵运算针对稀疏数据的高效计算
TensorRT深度学习推理加速优化神经网络模型,提升推理速度

示例代码

下面通过两个例子展示CUDA开发:原生CUDA向量加法(理解核函数)和Thrust库实现(简化开发)。

示例1:原生CUDA实现向量加法

功能:计算两个向量ab的和,结果存到c(即c[i] = a[i] + b[i])。

#include <iostream>
#include <cassert>

// 核函数:在GPU上并行执行,每个线程处理一个元素
__global__ void vectorAdd(const float* a, const float* b, float* c, int n) {
    // 计算当前线程的全局索引(每个线程处理一个元素)
    int i = blockIdx.x * blockDim.x + threadIdx.x;
    // 避免索引越界(当n不是线程块大小的整数倍时)
    if (i < n) {
        c[i] = a[i] + b[i];
    }
}

int main() {
    const int n = 1000000;  // 向量长度
    size_t size = n * sizeof(float);

    // 1. 主机(CPU)内存分配
    float* h_a = new float[n];
    float* h_b = new float[n];
    float* h_c = new float[n];

    // 初始化输入数据
    for (int i = 0; i < n; ++i) {
        h_a[i] = static_cast<float>(i);
        h_b[i] = static_cast<float>(i * 2);
    }

    // 2. 设备(GPU)内存分配
    float* d_a;
    float* d_b;
    float* d_c;
    cudaMalloc(&d_a, size);  // 分配GPU全局内存
    cudaMalloc(&d_b, size);
    cudaMalloc(&d_c, size);

    // 3. 数据从CPU传输到GPU
    cudaMemcpy(d_a, h_a, size, cudaMemcpyHostToDevice);
    cudaMemcpy(d_b, h_b, size, cudaMemcpyHostToDevice);

    // 4. 启动核函数(配置线程结构)
    int blockSize = 256;  // 每个线程块的线程数(通常取128/256/512)
    int gridSize = (n + blockSize - 1) / blockSize;  // 网格中的线程块数
    vectorAdd<<<gridSize, blockSize>>>(d_a, d_b, d_c, n);  // 核函数调用语法

    // 检查核函数是否执行成功
    cudaError_t err = cudaGetLastError();
    if (err != cudaSuccess) {
        std::cerr << "Kernel launch failed: " << cudaGetErrorString(err) << std::endl;
        return 1;
    }

    // 5. 结果从GPU传输回CPU
    cudaMemcpy(h_c, d_c, size, cudaMemcpyDeviceToHost);

    // 验证结果(检查前10个和最后10个元素)
    for (int i = 0; i < 10; ++i) {
        assert(h_c[i] == h_a[i] + h_b[i]);
    }
    for (int i = n - 10; i < n; ++i) {
        assert(h_c[i] == h_a[i] + h_b[i]);
    }
    std::cout << "Vector addition successful!" << std::endl;

    // 6. 释放内存
    delete[] h_a;
    delete[] h_b;
    delete[] h_c;
    cudaFree(d_a);  // 释放GPU内存
    cudaFree(d_b);
    cudaFree(d_c);

    return 0;
}

关键说明

  • 核函数用__global__修饰,必须通过<<<gridSize, blockSize>>>指定线程结构(网格包含多少块,每块包含多少线程);
  • 线程索引计算:blockIdx.x(块编号)、threadIdx.x(块内线程编号),组合得到全局索引i
  • 内存管理:cudaMalloc分配GPU内存,cudaMemcpy在CPU和GPU间传输数据。
示例2:Thrust库简化实现

Thrust提供了类似STL的接口,无需手动编写核函数,直接调用并行算法:

#include <thrust/device_vector.h>
#include <thrust/transform.h>
#include <thrust/functional.h>
#include <iostream>

int main() {
    const int n = 1000000;

    // 1. 初始化CPU数据
    float* h_a = new float[n];
    float* h_b = new float[n];
    for (int i = 0; i < n; ++i) {
        h_a[i] = static_cast<float>(i);
        h_b[i] = static_cast<float>(i * 2);
    }

    // 2. 用Thrust的device_vector管理GPU内存(自动分配/释放)
    thrust::device_vector<float> d_a(h_a, h_a + n);  // 从CPU数据初始化
    thrust::device_vector<float> d_b(h_b, h_b + n);
    thrust::device_vector<float> d_c(n);

    // 3. 调用thrust::transform执行并行加法(内部自动优化核函数)
    thrust::transform(d_a.begin(), d_a.end(),  // 输入1
                      d_b.begin(),            // 输入2
                      d_c.begin(),            // 输出
                      thrust::plus<float>()); // 加法操作

    // 4. 验证结果(复制回CPU)
    thrust::host_vector<float> h_c = d_c;  // host_vector自动从GPU复制数据
    for (int i = 0; i < 10; ++i) {
        std::cout << h_c[i] << " ";  // 输出:0 3 6 ... 27
    }
    std::cout << std::endl;

    // 自动释放内存(无需手动free)
    delete[] h_a;
    delete[] h_b;
    return 0;
}

编译运行
两个示例均用nvcc编译(CUDA编译器):

nvcc vector_add.cu -o vector_add  # 原生CUDA版本
nvcc thrust_add.cu -o thrust_add  # Thrust版本
./vector_add  # 运行

总结

CUDA是利用NVIDIA GPU并行能力的核心工具,入门需掌握线程模型和内存管理,通过简单示例(如向量加法)实践;开源库(如Thrust、cuBLAS)可大幅简化开发,建议优先复用。随着实践深入,可逐步学习性能优化(如共享内存利用、指令重排),应对更复杂的并行任务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Andrew-国星宇航

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值