想象一座 24 小时运转的数学快递分拣中心:你递上一车车数字,传送带把包裹按目的地分流,机械臂一秒钟抓取十几次,整条系统几乎不用人操心。深度学习里的每一层神经网络,本质上都在派发这种“数学包裹”——尤其是一个叫矩阵乘法的大家伙。如果全靠手工循环去算,训练一次大模型要等到天荒地老。NVIDIA 的 cuBLAS 就是这座专为 GPU 建造的自动分拣中心:它把线性代数中最常见的搬运任务分成三个级别,搬一个包裹、搬一车货、整仓联动;其中最让 AI 工程师着迷的,是整仓联动的 GEMM 矩阵乘法。它还要求你遵守“列主序”的运单填写习惯,用句柄作为长期会员卡。读完这篇,你会用快递员的视角,看懂 cuBLAS 的 API、内存布局,以及神经网络前向传播背后的矩阵引擎。

岗位关联

对 AI 从业者而言,cuBLAS 是连接算法与 GPU 算力的桥梁。理解它,你才能写出高效且正确的高性能推理代码,也能在框架报错时一眼定位内存布局与句柄管理的坑。

目录
  1. 可视化演示
  2. 初识cuBLAS
  3. 三级运算接口
  4. GEMM核心
  5. 句柄管理
  6. 数据布局的暗礁
  7. 性能调优
  8. 神经网络中的应用
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

三步展示cuBLAS线性代数库:BLAS Level 1-3层级与性能对比、GEMM核心运算流程与参数、数据布局(列主序vs行主序)与精度演进(FP32→FP8)。

本节配有交互动效(进入视口后自动加载,约 3KB)。

BLAS Level 1-3层级 L1:向量运算(dot/axpy/nrm2)→10%峰值 L2:矩阵-向量(gemv/ger)→30%峰值 L3:矩阵-矩阵(gemm/symm)→95%峰值 perf ↑ with operand size cuBLAS针对GPU架构优化,L3操作因数据复用率高接近理论峰值。

初识cuBLAS

走进一座数学快递分拣中心,你会看到传送带、机械臂和密密麻麻的轨道。你不需要关心每个包裹经过了多少只手,只需要把它放进入口,就能在另一头拿到整理好的货箱。NVIDIA 的 cuBLAS 就是给 GPU 准备的一座这样的分拣中心:它专门处理数字包裹,也就是线性代数运算。

在 AI 计算中,矩阵乘法不是偶尔出现,而是每一层神经网络都在进行的大宗交易。如果让工程师手写 CUDA kernel,就像让快递员记住每一条包裹路线,又慢又容易出错。cuBLAS 全称是 CUDA Basic Linear Algebra Subprograms,即 CUDA 版基础线性代数子程序库,它把 BLAS 这一套标准运算完整搬到了 GPU 上。

cuBLAS 提供了大量 API:从创建句柄的 cublasCreate,到单精度矩阵乘法的 cublasSgemm,几乎每个常用线性代数操作都有对应函数。它既能在科学计算里做数值分解,也能在深度学习中做矩阵相乘。由于是 NVIDIA 官方出品,它天然适配 CUDA 生态,也是最著名的深度学习库 cuDNN 的重要地基。

所以,理解 cuBLAS 的第一层认知是:它不只是一堆函数,而是一座把“数学搬运”自动化的分拣中心。GPU 负责提供蛮力,cuBLAS 负责让蛮力用在正确的轨道上。

三级运算接口

这座分拣中心有三个等级的快递业务。第一级只处理一个包裹:比如把某个数加到向量的每个元素上;第二级是一辆货车的批量作业:矩阵乘以一个向量;第三级则是整个仓库之间的联合作业:两个矩阵相乘。BLAS 官方就把这些运算分成 Level 1、Level 2 和 Level 3。

级别越高,一次调用处理的数据量越大,也越能在 GPU 上隐藏访存延迟。Level 1 是向量与向量之间的操作,例如 y = alpha*x + y;Level 2 是矩阵与向量之间的操作,例如 y = alpha*A*x + beta*y;Level 3 是矩阵与矩阵之间的操作,也就是 GEMM。cuBLAS 对应提供了 cublasSaxpy、cublasSgemv、cublasSgemm 等函数,命名里的 S 表示单精度,D 表示双精度,H 表示半精度。

从计算量上看,三级业务的复杂度完全不同:

这就是为什么 GEMM 是深度学习中最该被“自动分拣”的操作:数据量越大,第三级业务的计算密度优势越明显,GPU 的并行火力也越能发挥出来。

T1=O(n),T2=O(n2),T3=O(n3)\displaystyle T_1 = O(n),\qquad T_2 = O(n^2),\qquad T_3 = O(n^3)
  1. T₁ 表示 Level 1 的工作量它只跟向量长度 n 成正比,像逐个扫描 n 个包裹,是最轻量的业务。
    T1=O(n)T_1 = O(n)
  2. O 记号表示增长上界大 O 忽略常数项,只描述 n 很大时运算规模增长的主趋势。
    O(n)O(n)
  3. T₂ 表示 Level 2 的工作量矩阵与向量相乘要访问 m×n 个元素,约 n² 次操作,像一车货逐格检查。
    T2=O(n2)T_2 = O(n^2)
  4. T₃ 表示 Level 3 的工作量矩阵乘法需要约 n³ 次乘加,像三个仓库里的货物两两配对。
    T3=O(n3)T_3 = O(n^3)

GEMM核心

快递中心的招牌业务是“整仓调拨”:把 A 仓的货物与 B 仓的参数两两配对,生成 C 仓的编排结果。深度学习中的卷积和全连接层,最终都会被翻译成这种调拨单。它的正式名字叫 GEMM,即 General Matrix Multiply,通用矩阵乘法。

GEMM 的数学形式非常简洁:输出矩阵 C 等于 A 和 B 相乘,再用 alpha 缩放,并可选地叠加原来的 C。cuBLAS 的函数签名把所有的控制信息都暴露出来,开发者不需要告诉库如何并行,只要把矩阵指针、维度、alpha/beta 和转置标志交给它。

以 cublasSgemm 为例,参数顺序是 handle, transa, transb, m, n, k, &alpha, A, lda, B, ldb, &beta, C, ldc。A 的形状是 m×k,B 是 k×n,C 是 m×n;transa 或 transb 为真时,表示先取 A 或 B 的转置参与运算。alpha 和 beta 是标量,分别控制新结果的缩放和旧 C 的保留程度。

GEMM 是 cuBLAS 的摇钱树,也是深度学习的算力计量表。熟记这句话:一个线性层的前向传播就是一次 GEMM,而反向传播还需要更多 GEMM。

C=α op(A) op(B)+β C\displaystyle \mathbf{C} = \alpha\, \mathrm{op}(\mathbf{A})\, \mathrm{op}(\mathbf{B}) + \beta\, \mathbf{C}
  1. C 是输出矩阵它相当于调拨后最终装货的仓库,形状是 m×n。
    C\mathbf{C}
  2. op(A) 与 op(B) 是可选转置后的矩阵transa/transb 决定是否把矩阵翻个方向参与乘法。
    op(A) op(B)\mathrm{op}(\mathbf{A})\, \mathrm{op}(\mathbf{B})
  3. alpha 是整体缩放倍数它让 A 乘 B 的结果放大 alpha 倍,通常设为 1.0。
    α\alpha
  4. beta 叠加旧 Cbeta=0 表示从零开始,beta=1 表示在原有 C 上累加新结果。
    β C\beta\, \mathbf{C}

句柄管理

如果你是快递公司的长期客户,不会每次发货都重新签约,而是办一张会员卡。cuBLAS 里的 handle(句柄)就是这张卡:它记录你使用的 GPU 设备、算法工作空间和流设置,让后续调用直接走 VIP 通道。

使用 cuBLAS 的经典流程是:cublasCreate(&handle),接着执行若干 cublasXxx 运算,最后 cublasDestroy(handle)。句柄的创建和销毁会分配 GPU 资源,代价不小。如果在一个训练循环里反复创建句柄,就像每寄一个包裹都重新开一家快递公司,性能会惨不忍睹。

句柄还和工作空间、CUDA 流深度绑定。工作空间是 cuBLAS 临时计算的“暂存区”,由库按需申请;流(stream)则决定这些矩阵运算是否与别的 CUDA 任务并发。合理复用句柄、提前设置好流,能让 GPU 一直保持满负荷,而不是频繁停下来做初始化。

回到比喻:handle 就是那张会员卡。GPU 不认识你的脸,只认这张卡;在把矩阵运算交给 cuBLAS 之前,先刷卡、再办事。

数据布局的暗礁

快递单上的地址,有的人习惯先写省再写市,有的人习惯先写街道再写小区。同样一堆数字,在内存里按行排还是按列排,会让 cuBLAS 得到完全不同的矩阵。这就是数据布局问题。

BLAS 诞生于 Fortran 语言,默认按列主序(column-major)存储:先存第一列,再存第二列。而 C/C++ 和 Python 的 NumPy 默认按行主序(row-major)。如果把行主序矩阵直接传给 cuBLAS,等于把地址顺序填反,计算结果自然错得离谱。

两种布局计算内存下标的规则正好相反:

解决方式有两种:一种是在调用前把数据转成列主序;另一种更常用的是设置 transa / transb 为转置,让 cuBLAS 在 kernel 内部按转置后的视角读取。同时必须正确提供前导维度 lda,它表示内存中一列的存储跨度,列主序下通常等于矩阵的行数。

在快递分拣中心,包裹单的填写顺序决定分拣效率。对 cuBLAS 而言,transa/transb 和 lda 就是那份“填写说明”;填对了,矩阵才能被 GPU 顺利认出来。

idxrow=i×lda+j,idxcol=j×lda+i\displaystyle \mathrm{idx}_{\mathrm{row}} = i \times \mathrm{lda} + j, \qquad \mathrm{idx}_{\mathrm{col}} = j \times \mathrm{lda} + i
  1. idx_row 是行主序下标第 i 行第 j 列的元素先跳过 i 个整行,再偏移 j。
    idxrow=i×lda+j\mathrm{idx}_{\mathrm{row}} = i \times \mathrm{lda} + j
  2. lda 是前导维度也就是矩阵在内存中“跨行或跨列”的步长,是 BLAS 最容易被忽略的参数。
    lda\mathrm{lda}
  3. idx_col 是列主序下标先跳过 j 个整列,再偏移 i。
    idxcol=j×lda+i\mathrm{idx}_{\mathrm{col}} = j \times \mathrm{lda} + i
  4. i 与 j 是行列坐标它们是理解两种布局差异的最小单元。
    i, ji,\ j

性能调优

分拣中心最值钱的是调度系统:看到小包裹,自动走小型传送带;看到整卡车的货,自动调度机械臂。cuBLAS 的 kernel 自动选择机制就是这个调度员。

cuBLAS 针对不同 GPU 架构维护了多个 kernel 实现,运行时根据矩阵大小、数据类型、转置方式和是否可用 Tensor Core,自动挑选最优实现。开发者不需要手写汇编,但需要给“择优选路”留出空间:让数据在显存里连续、大小尽量对齐,并减少 kernel 启动次数。一个常用的性能指标是 TFLOPS,即每秒万亿次浮点运算:

在实际工程里,还能用批处理 GEMM(batched GEMM)一次处理多组矩阵,共享句柄和调度开销;也可以借助 CUDA 流让多个 GEMM 重叠执行。在支持 Tensor Core 的 GPU 上,cuBLAS 会自动使用混合精度,让矩阵乘法的吞吐量再上一个台阶。

性能优化的本质,是让分拣中心每种尺寸的货物都走上最合适的那条传送带。cuBLAS 把这份选择自动化,你要做的只是别把货物绑成奇怪的形状。

TFLOPS=2 m n kt×1012\displaystyle \text{TFLOPS} = \frac{2\,m\,n\,k}{t \times 10^{12}}
  1. TFLOPS 表示分拣中心的吞吐量每秒能完成多少万亿次浮点运算,是衡量 GPU 算力的常用单位。
    TFLOPS\text{TFLOPS}
  2. 2mnk 是矩阵乘法的总操作数一次乘加包含一次乘法和一次加法,所以约 2mnk 次浮点操作。
    2 m n k2\,m\,n\,k
  3. t 是实际耗时运行一次 GEMM 所用的秒数,耗得越少,性能越高。
    tt
  4. 10¹² 是单位换算把“次/秒”换算成“万亿次/秒”。
    101210^{12}

神经网络中的应用

现在把快递中心装进神经网络:输入一批样本 X,经过一个全连接层,输出 Y。在 cuBLAS 眼中,这不过是一张调拨单:X 和权重 W 相乘,再加上偏置 b。

前向传播的核心公式是:

一个最小调用方案是:先 cublasCreate(&handle),然后调用 cublasSgemm(handle, CUBLAS_OP_N, CUBLAS_OP_T, m, n, k, &alpha, X, m, W, n, &beta, Y, m),最后 cublasDestroy(handle)。这里的 CUBLAS_OP_T 表示把权重 W 转置后再乘,正好对应公式里的 Wᵀ。

卷积层也常通过 im2col 把图像补丁展开成矩阵,再统一交给 GEMM。批归一化、注意力机制里的 QKV 投影,也都能拆成矩阵乘法或 Level 1/2 操作。cuDNN 在优化卷积时,内部同样离不开 GEMM 这类基础矩阵运算;可以说,cuBLAS 是神经网络算力的重要地基。

从一座快递分拣中心出发,我们已经走到了神经网络的核心数学结构。无论上层框架是 PyTorch 还是 TensorFlow,最终在 GPU 上刷屏的,往往就是 cuBLAS 的 GEMM。

Y=X W⊤+b\displaystyle \mathbf{Y} = \mathbf{X}\,\mathbf{W}^{\top} + \mathbf{b}
  1. Y 是输出特征矩阵形状是 batch×out_features,代表这一层送出的一批结果。
    Y\mathbf{Y}
  2. X 是输入矩阵形状是 batch×in_features,表示一批样本的原始特征。
    X\mathbf{X}
  3. Wᵗ 是转置后的权重把 out_features×in_features 变成 in_features×out_features,才能与 X 相乘。
    W⊤\mathbf{W}^{\top}
  4. b 是偏置项它加到输出矩阵的每一行上,相当于每个输出神经元的固定偏移。
    b\mathbf{b}

AI 应用场景

深度学习框架矩阵加速

阶段:模型训练与推理中的前向计算

解决的问题:手写 GPU 矩阵乘法容易造成访存局部性差、并行度低,性能和正确性都难保证。cuBLAS 提供工业级 GEMM,能根据 GPU 自动选择最优 kernel,让矩阵乘法接近硬件峰值性能。

具体案例:PyTorch 中 torch.mm 在 CUDA 上底层会调用 cuBLAS 的 GEMM。一个 4096×4096×4096 的矩阵乘法,在 A100 上可以轻松达到数十 TFLOPS,而普通 CUDA 实现往往只有几分之一。

大模型推理中的批量 GEMM

阶段:LLM 推理时的注意力与全连接层

解决的问题:多头注意力中 Q、K、V 的投影本质是多组小矩阵乘法,逐个调用 kernel 会带来巨大启动开销。cuBLAS 的 batched GEMM 能一次调度多组矩阵乘法,提高 GPU 利用率。

具体案例:在 LLM 服务框架中,把 32 个 attention head 的 QKV 投影拼成 batch,调用 cublasGemmBatched 一次算完,推理延迟可明显下降。

Python 演示

python31 行
import numpy as np def sgemm_simulate(alpha, A, transa, B, transb, beta, C):    """Simulate cuBLAS SGEMM: C = alpha * op(A) @ op(B) + beta * C"""    A_op = A.T if transa == 1 else A    B_op = B.T if transb == 1 else B    C[...] = alpha * (A_op @ B_op) + beta * C    return C  def linear_forward(X, W, b):    """Forward pass of a fully connected layer via gemm simulation"""    m, k = X.shape    n = W.shape[0]    Y = np.zeros((m, n), dtype=np.float32)    sgemm_simulate(1.0, X, 0, W, 1, 0.0, Y)    Y += b.astype(np.float32)    return Y  if __name__ == "__main__":    rng = np.random.default_rng(0)    x = rng.standard_normal((4, 8)).astype(np.float32)    w = rng.standard_normal((5, 8)).astype(np.float32)    b = rng.standard_normal(5).astype(np.float32)     y = linear_forward(x, w, b)    y_ref = x @ w.T + b     np.testing.assert_allclose(y, y_ref, rtol=1e-5, atol=1e-6)    print("simulated cublas sgemm passed")
目的:用 NumPy 模拟 cuBLAS 的 sgemm 核心语义,并演示如何用一次 GEMM 完成全连接层的前向传播。
  1. A_op = A.T if transa == 1 else A模拟 cuBLAS 的转置开关,决定是否把矩阵转个方向参与乘法。
  2. C[...] = alpha * (A_op @ B_op) + beta * C正是 GEMM 的数学表达式:缩放新结果,再与旧 C 叠加。
  3. Y = np.zeros((m, n), dtype=np.float32)提前分配输出矩阵,对应 cuBLAS 调用方准备 C 矩阵的过程。
  4. sgemm_simulate(1.0, X, 0, W, 1, 0.0, Y)把权重 W 转置后参与乘法,对应全连接层的 W^T。
  5. Y += b.astype(np.float32)在 GEMM 结果上叠加偏置,完成线性层前向。
  6. np.testing.assert_allclose(y, y_ref, rtol=1e-5, atol=1e-6)用 NumPy 直接计算结果,验证模拟 SGEMM 实现没有偏差。

常见误区

误区我平时只听过 `cublasSgemm`,所以 cuBLAS 就是专门做矩阵乘法的库,其他 BLAS 函数都不重要。

正解cuBLAS 是整套 BLAS 线性代数运算的 GPU 实现,Level 1、Level 2、Level 3 都有对应接口。虽然深度学习最常用 GEMM,但向量加法、矩阵乘向量、批量缩放等操作同样会用到其他接口。只盯着 GEMM,就像只给快递中心修一条主干道却没有支线。

为何常见:深度学习框架里 GEMM 出现频率最高,教程也总拿它举例,容易让人以偏概全。

误区我写的矩阵是一行一行连续存的,直接把这个指针传给 cuBLAS 应该没问题吧?

正解BLAS 来自 Fortran,默认按列主序。行主序数据直接传给 cublasSgemm,轻则结果转置,重则维度错乱。正确做法是设置 transa/transb,或者把数据显式转成列主序,同时正确设置 lda。好比把地址单从横排改成竖排,快递员才能看懂。

为何常见:现代语言大多默认行主序,而 cuBLAS 文档仍以 Fortran 视角描述,初学者很容易忽略这一点。

误区每次都 `cublasCreate` 再 `cublasDestroy`,代码看起来很干净,资源也不会泄漏,应该没问题。

正解cublasCreate 和 cublasDestroy 会分配和释放 GPU 工作空间,开销非常高。在循环或神经网络每一层都创建句柄,性能会急剧下降。正确做法是在程序初始化时创建一次,整体结束再销毁,像长期客户刷卡而不是反复开户。

为何常见:初学者习惯用 RAII 思想管理资源,但没意识到 GPU API 初始化的成本远高于普通内存对象。

误区厂商宣传说 cuBLAS 会自动选择最优 kernel,那我矩阵形状随便来,内存不连续也该被自动优化。

正解自动选核是在你给的数据布局里选,不会帮你修复残缺的输入。内存不连续、lda 不对、数据未对齐,仍会导致性能骤降甚至错误。快递中心再智能,包裹单写错街道也救不回来。

为何常见:自动调优的宣传太响亮,让人忽略了输入约束始终是正确性的前提。

误区cuDNN 和 cuBLAS 都是 NVIDIA 的加速库,名字也像,那用 cuDNN 做矩阵乘法应该也行。

正解cuDNN 面向神经网络原语,如卷积、池化、归一化;cuBLAS 面向通用 BLAS 线性代数。虽然 cuDNN 内部可能用到矩阵乘,但它们是独立库,API 和优化目标都不同。工程里需要通用矩阵乘法应该用 cuBLAS,需要卷积才用 cuDNN。

为何常见:两者常一起出现在 CUDA 安装目录,名字相似,功能边界容易被忽略。

面试题

Q1. cuBLAS 是由哪家公司提供、面向 GPU 的 BLAS 实现?

单选题 · easy

  • A.NVIDIA 官方提供的 GPU 计算库← 正确答案
  • B.AMD 官方提供的 GPU 计算库
  • C.Intel 官方提供的 CPU 计算库
  • D.开源社区提供的跨平台计算库

答案:A。cuBLAS 是 NVIDIA 在 CUDA 生态中提供的 BLAS 库,专门针对自家 GPU 做深度优化。AMD 对应的是 rocBLAS,Intel 有 oneMKL,而开源社区方案通常不是 NVIDIA 官方首选。

Q2. BLAS Level 1 主要处理哪类运算?

单选题 · easy

  • A.向量与向量之间的基础运算← 正确答案
  • B.矩阵与矩阵之间的乘法运算
  • C.矩阵与向量之间的变换运算
  • D.标量与矩阵之间的乘法运算

答案:A。Level 1 是向量-向量操作,比如 y = alpha*x + y;Level 2 是矩阵-向量操作;Level 3 才是矩阵-矩阵操作。级别越高,单次运算的计算密度越高。

Q3. 下列哪个函数对应 cuBLAS 中的矩阵乘法?

单选题 · easy

  • A.cublasSgemm← 正确答案
  • B.cublasSgemv
  • C.cublasSaxpy
  • D.cublasSdot

答案:A。Sgemm 中的 gemm 指 General Matrix Multiply,即通用矩阵乘法。Sgemv 是矩阵乘向量,Saxpy 是标量乘向量加向量,Sdot 是向量点积。

Q4. 在 GEMM 公式 C = alpha*A*B + beta*C 中,若希望输出完全不叠加旧 C,beta 应设为多少?

单选题 · mid

  • A.数值 0← 正确答案
  • B.数值 1
  • C.数值 alpha
  • D.数值 -1

答案:A。beta=0 时,旧 C 被完全丢弃,只保留 alpha*A*B 的结果。beta=1 时则会在原 C 上累加。实际调用中,C 矩阵初始为零时也常见 beta=0。

Q5. cuBLAS 默认采用哪种内存布局?

单选题 · mid

  • A.列主序(column-major)← 正确答案
  • B.行主序(row-major)
  • C.蛇形序(snake-order)
  • D.CSR 稀疏压缩格式

答案:A。BLAS 起源于 Fortran,Fortran 数组默认列主序,因此 cuBLAS 也默认按列主序解释数据。C/C++ 数组想直接使用,需要借助转置标志或显式转换。

Q6. 在 cublasSgemm 参数中,哪个参数用于指定矩阵的前导维度?

单选题 · mid

  • A.lda 参数← 正确答案
  • B.m 参数
  • C.k 参数
  • D.n 参数

答案:A。lda 是 leading dimension,表示矩阵在主存储方向上的跨度。m、n、k 分别描述三个矩阵的维度,不是前导维度。忘记设置正确的 lda 是新手最常见的错误之一。

Q7. 列主序存储一个 3×2 矩阵,元素 4 在内存中的索引是几?

单选题 · extreme

  • A.内存索引 4← 正确答案
  • B.内存索引 3
  • C.内存索引 5
  • D.内存索引 2

答案:A。列主序先存第一列再存第二列。3×2 矩阵的存储序列是 1、3、5、2、4、6,因此元素 4 是第 5 个元素,内存索引为 4。这个题目专门考察是否真正理解列主序。

Q8. 关于 cuBLAS 句柄,下列哪些做法是正确的?

多选题 · mid

  • A.创建一次后长期复用句柄← 正确答案
  • B.每次矩阵乘法都创建新句柄
  • C.结合 CUDA 流控制并发执行← 正确答案
  • D.结束前调用销毁释放资源← 正确答案

答案:ACD。句柄创建和销毁开销很大,应该复用,因此 B 错误。句柄可以与 CUDA 流绑定,控制异步执行顺序;程序退出前调用 cublasDestroy 释放 GPU 资源是正确习惯。

Q9. 使用 cuBLAS 加速神经网络前向传播时,哪些做法合理?

多选题 · hard

  • A.多个小 GEMM 合并成 batched GEMM← 正确答案
  • B.直接传行主序数据且忽略转置参数
  • C.利用 alpha 和 beta 完成结果缩放← 正确答案
  • D.选择合适布局以减少数据拷贝← 正确答案

答案:ACD。批处理 GEMM 能减少 kernel 启动次数,alpha/beta 可以完成缩放与累加,合理布局能避免额外拷贝。行主序数据不能直接忽略转置,否则结果会错,因此 B 错误。

Q10. 关于 cuBLAS 性能优化,下列说法正确的是?

多选题 · hard

  • A.cuBLAS 自动选择最优 kernel← 正确答案
  • B.显存数据不连续也能自动对齐加速
  • C.batched GEMM 减少内核启动开销← 正确答案
  • D.Tensor Core 加速混合精度运算← 正确答案

答案:ACD。cuBLAS 会根据架构和形状自动选 kernel,批处理 GEMM 能摊薄启动成本,Tensor Core 可为混合精度矩阵乘提供巨大加速。但数据不连续不会自动变对齐,仍需开发者保证内存布局合理,因此 B 错误。