《CUDA与TensorRT入门知识框架》

课程导入:学习目标、课程结构与环境准备

欢迎来到《CUDA与TensorRT入门知识框架》的第一章。本章是整个课程的地基,我们将明确三个核心问题:学完这门课你能做什么、课程如何组织,以及如何搭建可用的开发环境。CUDA是NVIDIA GPU的通用并行计算平台,TensorRT则是基于CUDA的高性能推理优化引擎。理解两者的关系,是后续所有实践的前提。

1.1 学习目标:从“能跑”到“会优化”

本课程不追求面面俱到的理论推导,而是聚焦于工程落地中最常用的知识链路。完成本课程后,你应该具备以下能力:

  • 理解GPU异构计算模型:清楚Host(CPU)与Device(GPU)的分工,掌握线程层次结构(Grid、Block、Thread)与内存层次结构(全局内存、共享内存、寄存器)。
  • 编写并调试CUDA程序:能够使用nvcc编译、运行简单的kernel,并利用cuda-memcheck或compute-sanitizer排查越界与同步错误。
  • 掌握TensorRT优化流程:能够将训练好的PyTorch/ONNX模型转换为TensorRT引擎,理解精度校准(FP16/INT8)与动态形状(Dynamic Shape)的配置方法。
  • 具备性能分析意识:会使用Nsight Systems与Nsight Compute定位瓶颈,区分“访存密集”与“计算密集”算子,并据此选择优化策略。
学习建议:本课程每章都配有可运行的代码示例。建议你准备一台带有NVIDIA GPU(Compute Capability 7.5及以上,如RTX 20/30/40系列)的Linux或Windows机器,并确保驱动版本≥470,否则后续TensorRT的某些特性无法启用。

1.2 课程结构:四阶段递进式设计

整个课程共30章,分为四个阶段。每个阶段都有明确的交付物,避免“学完就忘”。

阶段章节范围核心主题阶段产出
基础入门第1-8章CUDA编程模型、内存管理、线程同步手写向量加法、矩阵乘法kernel
性能优化第9-15章访存优化、占用率调优、算子融合GEMM性能达到cuBLAS的60%以上
推理部署第16-24章TensorRT API、ONNX解析、INT8量化YOLOv5模型TensorRT加速部署
工程实战第25-30章多流并发、TensorRT-LLM、性能剖析高并发推理服务端Demo

这种结构遵循“原理→实践→优化→部署”的认知路径。前8章如果基础不牢,后续的优化章节会非常吃力,尤其是共享内存的bank conflict问题,需要反复动手实验才能理解。

1.3 环境准备:CUDA与TensorRT安装

环境搭建是初学者最容易受挫的环节。这里我们采用“驱动→CUDA Toolkit→cuDNN→TensorRT”的安装顺序,每一步都验证后再进入下一步。

1.3.1 检查GPU与驱动

首先确认GPU型号与驱动版本。在Linux终端执行:

nvidia-smi
# 输出示例:
# +-----------------------------------------------------------------------------+
# | NVIDIA-SMI 525.85.12    Driver Version: 525.85.12    CUDA Version: 12.0      |
# |-------------------------------+----------------------+----------------------+
# | GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
# |   0  NVIDIA GeForce RTX 4090  | On                 | N/A                  |
# +-------------------------------+----------------------+----------------------+

注意右上角的CUDA Version是驱动支持的最高CUDA版本,并不代表已安装CUDA Toolkit。驱动版本必须≥450.80.02(CUDA 11.0的最低要求),推荐使用最新稳定版驱动。

1.3.2 安装CUDA Toolkit

CUDA Toolkit包含编译器nvcc、运行时库和开发工具。推荐使用runfile(本地安装包)方式,便于自定义安装路径。以CUDA 12.1为例:

wget https://developer.download.nvidia.com/compute/cuda/12.1.1/local_installers/cuda_12.1.1_530.30.02_linux.run
sudo sh cuda_12.1.1_530.30.02_linux.run
# 安装时取消勾选Driver(因为已安装),只保留Toolkit和Samples

安装完成后,设置环境变量。在~/.bashrc末尾添加:

export PATH=/usr/local/cuda-12.1/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda-12.1/lib64:$LD_LIBRARY_PATH

验证安装:

nvcc --version
# 输出应包含 "Cuda compilation tools, release 12.1, V12.1.105"
常见误区:不要使用sudo apt install nvidia-cuda-toolkit安装,Ubuntu仓库中的版本通常较旧,且与TensorRT的兼容性难以保证。务必从NVIDIA官网下载对应版本的runfile。

1.3.3 安装cuDNN与TensorRT

cuDNN是深度神经网络的加速库,TensorRT依赖它进行卷积等算子的底层优化。下载cuDNN需要NVIDIA开发者账号,选择与CUDA 12.1匹配的版本(如cuDNN 8.9.x)。安装步骤:

# 解压后复制到CUDA目录
tar -xvf cudnn-linux-x86_64-8.9.2.26_cuda12-archive.tar.xz
sudo cp cudnn-*-archive/include/cudnn*.h /usr/local/cuda-12.1/include/
sudo cp -P cudnn-*-archive/lib/libcudnn* /usr/local/cuda-12.1/lib64/
sudo chmod a+r /usr/local/cuda-12.1/lib64/libcudnn*

TensorRT的安装推荐使用tar包方式,便于管理版本。以TensorRT 8.6.1为例:

tar -xzvf TensorRT-8.6.1.6.Linux.x86_64-gnu.cuda-12.0.tar.gz
# 将路径加入环境变量
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/TensorRT-8.6.1.6/lib

验证TensorRT是否可用,运行Python测试:

python3 -c "import tensorrt as trt; print(trt.__version__)"
# 输出应为 8.6.1

1.4 核心原理:CUDA与TensorRT的分工

为了后续章节的展开,这里必须厘清两个关键概念。CUDA是通用并行计算平台,它允许你直接编写GPU kernel,控制线程调度与内存布局。而TensorRT是推理优化引擎,它读取训练好的模型,通过层融合、精度校准、内核自动调优等手段,生成一个针对特定GPU和输入尺寸高度优化的推理引擎。

下图展示了从模型到部署的完整链路,以及CUDA与TensorRT在其中的位置:

CUDA与TensorRT在推理部署链路中的分工 训练框架 PyTorch / TensorFlow 输出 .pt / .pth 权重 导出 ONNX 中间表示 算子图 + 权重 解析 TensorRT 层融合 / 精度校准 内核自动调优 动态形状处理 生成 .engine 文件 加载 推理服务 TensorRT Runtime CUDA 上下文 CUDA 并行计算平台 线程管理 · 内存分配 · 内核调度 · 流并发 依赖 依赖 关键理解: 1. TensorRT 不替代 CUDA,而是构建在 CUDA 之上的优化层。 2. 手写 CUDA kernel 适合自定义算子;TensorRT 适合标准模型的高效部署。 3. 实际项目中两者常结合:TensorRT 处理主流网络,CUDA 扩展特殊算子。

从图中可以看到,TensorRT位于ONNX与推理服务之间,它输出的.engine文件是经过优化的、与具体GPU绑定的二进制序列化引擎。而CUDA作为最底层的平台,为TensorRT提供运行时支撑。理解这条链路,你就明白了为什么安装顺序必须是“驱动→CUDA→cuDNN→TensorRT”——每一层都依赖下一层的API。

1.5 案例:一个最小可运行的CUDA程序

为了验证环境是否真正可用,我们编写一个经典的向量加法程序。创建vector_add.cu:

#include <stdio.h>

__global__ void vecAdd(float *a, float *b, float *c, int n) {
    int i = blockIdx.x * blockDim.x + threadIdx.x;
    if (i < n) {
        c[i] = a[i] + b[i];
    }
}

int main() {
    int n = 1024;
    size_t bytes = n * sizeof(float);

    float *h_a, *h_b, *h_c;
    float *d_a, *d_b, *d_c;

    // 分配主机内存
    h_a = (float*)malloc(bytes);
    h_b = (float*)malloc(bytes);
    h_c = (float*)malloc(bytes);

    // 初始化数据
    for (int i = 0; i < n; i++) {
        h_a[i] = 1.0f;
        h_b[i] = 2.0f;
    }

    // 分配设备内存
    cudaMalloc(&d_a, bytes);
    cudaMalloc(&d_b, bytes);
    cudaMalloc(&d_c, bytes);

    // 拷贝数据到设备
    cudaMemcpy(d_a, h_a, bytes, cudaMemcpyHostToDevice);
    cudaMemcpy(d_b, h_b, bytes, cudaMemcpyHostToDevice);

    // 启动kernel:256线程/块,共4块
    vecAdd<<<4, 256>>>(d_a, d_b, d_c, n);

    // 拷贝结果回主机
    cudaMemcpy(h_c, d_c, bytes, cudaMemcpyDeviceToHost);

    // 验证结果
    for (int i = 0; i < 10; i++) {
        printf("c[%d] = %f\n", i, h_c[i]);
    }

    // 释放内存
    cudaFree(d_a); cudaFree(d_b); cudaFree(d_c);
    free(h_a); free(h_b); free(h_c);

    return 0;
}

编译并运行:

nvcc -o vector_add vector_add.cu
./vector_add
# 预期输出:c[0] = 3.000000, c[1] = 3.000000, ...

如果程序输出正确,说明CUDA环境完全可用。这里<<<4, 256>>>表示启动4个Block,每个Block有256个Thread,总共1024个线程,恰好对应数组长度。

1.6 误区与复盘:环境搭建的常见陷阱

根据过往学员的反馈,以下三个问题出现频率最高,值得提前规避:

陷阱1:CUDA版本与PyTorch不匹配。PyTorch在安装时会自带CUDA运行时(如cu11.8),但这与系统级CUDA Toolkit无关。如果你用PyTorch的CUDA去编译TensorRT,会报版本冲突。建议:系统CUDA用于编译,PyTorch的CUDA用于运行,两者可以共存,但TensorRT必须与系统CUDA版本一致。
陷阱2:忘记设置LD_LIBRARY_PATH。TensorRT的Python包在导入时依赖libnvinfer.so,如果未将TensorRT的lib目录加入环境变量,会出现ImportError: libnvinfer.so.8: cannot open shared object file。每次新开终端都需要重新export,建议写入~/.bashrc。
复盘建议:完成本章后,请务必自己动手走一遍“nvidia-smi → nvcc --version → python3 -c 'import tensorrt'”的验证链路。如果中途失败,优先检查驱动版本与CUDA Toolkit的兼容性矩阵(NVIDIA官网有详细表格)。不要跳过任何一步,因为后续章节的代码示例都默认环境已就绪。