国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

如何在NVIDIA CUDA Tile中編寫高性能矩陣乘法

NVIDIA英偉達企業解決方案 ? 來源:NVIDIA英偉達企業解決方案 ? 2026-01-22 16:43 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

本博文是系列課程的一部分,旨在幫助開發者學習 NVIDIA CUDA Tile 編程,掌握構建高性能 GPU 內核的方法,并以矩陣乘法作為核心示例。

在本文中,您將學習:

如何使用 NVIDIAcuTile實現高性能矩陣乘法:深入理解平鋪加載、計算與存儲的執行流程。

塊級并行編程思維的轉變:從線程級思考逐步過渡到以線程塊為核心的編程模式。

平鋪編程的優化實踐:通過實際代碼掌握性能調優的關鍵策略。

開始之前,請確認您的環境符合以下要求(更多詳情請參閱快速入門):

環境要求:

CUDA 13.1或更高版本

GPU 架構:NVIDIA Blackwell(例如,NVIDIA RTX 50 系列)

Python:3.10 及以上版本

安裝 cuTile Python:

pip install cuda-tile

注意:cuTile 是 NVIDIA 推出的新一代 GPU 編程框架。盡管目前僅支持針對 Blackwell(計算能力 10.x 和 12.x)架構的優化,但即將發布的 CUDA 工具包版本將擴展對更多架構的支持。

什么是矩陣乘法?

矩陣乘法是現代技術計算中的一項基本運算,它是求解方程組的基礎,支撐著圖形處理、模擬、優化以及多數機器學習任務,并能高效地映射到 GPU 等高性能硬件上。

給定輸入矩陣 A (M×K) 和 B (K×N),計算結果矩陣 C (M×N) 中各元素的公式如下。

wKgZPGlx416ATF80AAAC6lvx-v0316.jpg

從公式可以看出,矩陣 C 的元素是通過計算矩陣 A 的行與矩陣 B 的列的點積得到的。

圖塊編程可以通過將輸出矩陣劃分為多個圖塊,既能簡化實現,又能實現優異的性能。每個圖塊負責計算輸出矩陣的一個子塊,cuTile 會自動處理內存訪問和線程同步。具體而言:

每個塊處理輸出矩陣 C 的 (tm×tn) 圖塊。

沿 K 維度循環,依次加載矩陣 A 和 B 對應的圖塊。

調用ct.mma()執行矩陣乘積累加運算(自動啟用 Tensor Core)。

最終,將累積結果寫回全局內存。

圖 1 展示了計算過程,其方式類似于逐個元素的算法,但在本例中,圖塊取代了單個元素。

wKgZO2lx47iAOYkXAAJC4CVrmFM421.png

圖 1。矩陣乘法 (A + B + C) 分解為圖塊的示意圖

GPU 內核實現

在介紹完核心理念之后,我們來看一下完整的實現代碼。代碼分為兩部分:一部分是在 GPU 上運行的內核,另一部分是在 CPU 上啟動的代碼,如下所示。

import cuda.tile as ct
from math import ceil
import torch
# Type alias for compile-time constants
ConstInt = ct.Constant[int]
# Step 1: Define the kernel
@ct.kernel
def matmul_kernel(A, B, C, tm: ConstInt, tn: ConstInt, tk: ConstInt):
# 1.1 Get block ID and map to output tile position
# inside swizzle_2d, we access ct.bid(0) and output bidx and bidy
bidx, bidy = swizzle_2d(M, N, tm, tn, GROUP_SIZE_M)
# 1.2 Calculate the number of tiles along the K dimension
num_tiles_k = ct.num_tiles(A, axis=1, shape=(tm, tk))
# 1.3 Initialize accumulator
accumulator = ct.full((tm, tn), 0, dtype=ct.float32)
# 1.4 Loop over K dimension
for k in range(num_tiles_k):
# Load tiles from A and B
a = ct.load(A, index=(bidx, k), shape=(tm, tk))
b = ct.load(B, index=(k, bidy), shape=(tk, tn))
# Matrix multiply-accumulate
accumulator = ct.mma(a, b, accumulator)
# 1.5 Store result
ct.store(C, index=(bidx, bidy), tile=accumulator)
# Step 2: Launch the kernel
def cutile_matmul(A: torch.Tensor, B: torch.Tensor) -> torch.Tensor:
# Choose tile sizes
tm, tn, tk = 128, 256, 64 # for float16
# Calculate grid dimensions
grid_x = ceil(m / tm)
grid_y = ceil(n / tn)
grid = (grid_x * grid_y, 1, 1)
# Create output and launch
C = torch.empty((m, n), device=A.device, dtype=A.dtype)
ct.launch(stream, grid, matmul_kernel, (A, B, C, tm, tn, tk))
return C

現在,我們來逐步分解每個關鍵部分。

1.定義 GPU 內核

在 cuTile 中,@ct.kernel裝飾器用于將普通的 Python 函數標記為 GPU 內核:

@ct.kernel
def matmul_kernel(A, B, C, tm: ConstInt, tn: ConstInt, tk: ConstInt):
# Kernel code here

此裝飾器表示:

此函數將在 GPU 上執行。

每個線程塊將運行該函數的一個獨立實例。

它無法被直接調用,必須通過ct.launch()來啟動。

2. 編譯時優化:常量類型的標注

請注意,參數tm、tn和tk采用特殊類型標注ct.Constant[int]:

ConstInt = ct.Constant[int] # Define type alias
def matmul_kernel(A, B, C,
tm: ConstInt, # Tile size along M dimension
tn: ConstInt, # Tile size along N dimension
tk: ConstInt): # Tile size along K dimension

這表明它們是編譯時常量。cuTile 會針對不同的圖塊大小值生成專用的機器代碼,從而使編譯器能夠:

執行循環展開。

優化內存訪問模式。

生成高效 Tensor Core 指令。

3.確定工作范圍:塊 ID 映射

每個塊負責計算輸出矩陣的特定圖塊。通過swizzle_2d()函數,我們獲取當前正在處理的塊的索引

def swizzle_2d(M, N, tm, tn, GROUP_SIZE_M):
# Get the global IDs of the current CUDA block (CTA) in a 1D grid.
bid = ct.bid(0)
return swizzle_2d_from_bid(M, N, tm, tn, GROUP_SIZE_M, bid)
bidx, bidy = swizzle_2d(M, N, tm, tn, GROUP_SIZE_M)


此代碼的功能是確定當前塊應處理的輸出矩陣中的哪個圖塊。為了理解該過程,我們首先從主機端的網格劃分開始。

第 1 步:主機側網格劃分

在主機端啟動核函數時(如第 3 節所述),計算所需的任務塊數量:

grid_x = ceil(m / tm) # Number of Blocks needed for M dimension
grid_y = ceil(n / tn) # Number of Blocks needed for N dimension
grid_size = grid_x * grid_y # Total Blocks
grid = (grid_size, 1, 1) # Defined as a 1D grid

m和n: 輸出矩陣 C 的行和列。

tm: 輸出圖塊大小行方向 (M 維)由每個塊處理。

tn: 按列方向( N 維)輸出每個塊處理的圖塊大小。

從邏輯上講,啟動grid_x * grid_y塊并將其展平為一維網格:grid = (grid_size, 1, 1)。

第 2 步:在內核中獲取塊 ID

在內核內部,每個塊通過ct.bid(0)獲取其唯一的標識符:

bid = ct.bid(0) # Return value range: [0, grid_size-1]

ct.bid(0)在 x 軸維度中查詢當前塊的 ID。

參數 0 表示第一個維度 ( x 軸) ,對應網格定義中的第一個元素(grid_size, 1, 1).

每個塊都有一個唯一的一維坐標: bid = 0, 1, 2, …, grid_size-1.

第 3 步:將 1D 塊 ID 映射到 2D 圖塊坐標

現在的問題是塊 ID (bid) 為一維,而輸出矩陣是二維。需要明確該塊應處理的行和列圖塊。swizzle_2d_from_bid()函數可用于確定該塊所負責的行和列圖塊。

bidx, bidy = swizzle_2d_from_bid(M, N, tm, tn, GROUP_SIZE_M, bid)

輸出結果:

bidx:當前塊負責的輸出圖塊在 M 維度上的行索引。取值范圍:【0,grid_x -1】。

bidy:當前塊負責的輸出圖塊在 N 維度上的列索引。取值范圍:【0,grid_y -1】。

特定的映射邏輯涉及 Swizzling(用于提升內存訪問效率),我們將在第 4 節中詳細解釋這一點。目前,只需理解它將 1D 塊 ID 轉換為 2D 圖塊坐標即可。

5. 準備累加器:初始化輸出圖塊

在循環執行 K 維度之前,您需要先創建一個累加器以存儲中間結果:

num_tiles_k = ct.num_tiles(A, axis=1, shape=(tm, tk))
accumulator = ct.full((tm, tn), 0, dtype=ct.float32)

num_tiles_k: 計算在 K 維度中需要處理的圖塊數量。

accumulator: 用于累加結果的形狀 (tm,tn) 零矩陣。

使用 float32 可確保數值精度并避免累積錯誤。

6. 核心計算循環:沿 K 維遍歷

這是矩陣乘法的核心。接下來,循環遍歷 K 維度中的每個圖塊,并累加結果:

for k in range(num_tiles_k):
# Load tiles
a = ct.load(A, index=(bidx, k), shape=(tm, tk), padding_mode=zero_pad)
b = ct.load(B, index=(k, bidy), shape=(tk, tn), padding_mode=zero_pad)
# Accumulate
accumulator = ct.mma(a, b, accumulator)

加載數據:

ct.load(A, index=(bidx, k), shape=(tm, tk)): 從矩陣 A 中加載圖塊。

index=(bidx, k): 指定要在圖塊空間中加載的圖塊坐標。

shape=(tm, tk): 圖塊的大小。

padding_mode=zero_pad: 如果負載數據超出范圍,則用 0 填充。

矩陣乘積累加:

ct.mma(a, b, accumulator): 乘a*b, 加到accumulator,然后把結果保存至accumulator(mma表示矩陣乘積累加)

當a和b的形狀滿足 Tensor Core 要求時,cuTile 會自動調用 GPU 的 Tensor Core 來加速此操作。

循環結束后,累加器將保存輸出圖塊的完整結果。

寫回結果:存儲到全局內存

隨后,將計算結果寫回全局內存:

accumulator = ct.astype(accumulator, C.dtype)
ct.store(C, index=(bidx, bidy), tile=accumulator)

首先,將 float32 累加器轉換為輸出矩陣的數據類型。

使用ct.store()將圖塊寫回到全局內存中的對應位置。

啟動核函數:主機側代碼

現在從主機啟動內核。首先,查看全部代碼。

def cutile_matmul(A: torch.Tensor, B: torch.Tensor) -> torch.Tensor:
# Determine tile sizes based on dtype
if A.dtype.itemsize == 2: # float16/bfloat16
tm, tn, tk = 128, 256, 64
else: # float32
tm, tn, tk = 32, 32, 32
m, k = A.shape
_, n = B.shape
# Calculate grid dimensions
grid_x = ceil(m / tm)
grid_y = ceil(n / tn)
grid_size = grid_x * grid_y
grid = (grid_size, 1, 1)
# Create output tensor
C = torch.empty((m, n), device=A.device, dtype=A.dtype)
# Launch kernel
ct.launch(torch.cuda.current_stream(), grid, matmul_kernel,
(A, B, C, tm, tn, tk))
return C

在主機側啟動內核需要完成三個關鍵步驟:

第 1 步:計算網格大小

根據輸入矩陣的維度和圖塊大小,計算所需塊的數量:

m, k = A.shape # Matrix A dimensions: m rows, k columns
_, n = B.shape # Matrix B dimensions: k rows, n columns
# Calculate number of Blocks needed
grid_x = ceil(m / tm) # How many tiles needed for M dimension
grid_y = ceil(n / tn) # How many tiles needed for N dimension
grid_size = grid_x * grid_y # Total Blocks
grid = (grid_size, 1, 1) # Defined as 1D grid

ceil()向上取整,確保覆蓋所有元素 (即使矩陣維度無法被圖塊大小整除) 。

將 2D 塊布局扁平化為 1D 網格可簡化啟動邏輯。

第 2 步:設置圖塊大小 (編譯時常量)

根據數據類型選擇合適的圖塊大小:

if A.dtype.itemsize == 2: # float16/bfloat16 (2 bytes per element)
tm, tn, tk = 128, 256, 64
else: # float32 (4 bytes per element)
tm, tn, tk = 32, 32, 32

這些參數作為編譯期常量傳遞給內核:

tm: 輸出圖塊行 ( M 維) 。

tn: 輸出圖塊列 ( N 個維度) 。

tk: 每次以 K 維加載的圖塊大小。

注意:此處的圖塊大小配置僅為示例。在實踐中,不同的 GPU 架構需要相應的參數配置以達到理想性能。合適的配置取決于 M/ N/ K 大小、GPU 架構、共享內存大小、寄存器數量、SM 數量等因素。在開發過程中,建議使用性能分析工具(如 NVIDIA Nsight Compute)確定較優參數。TileGym 提供了一個自動調整程序,可用于自動獲取較優參數。

第 3 步:調用ct.launch()啟動核函數

C = torch.empty((m, n), device=A.device, dtype=A.dtype) # Create output tensor
ct.launch(
torch.cuda.current_stream(), # CUDA stream
grid, # Grid dimensions: (grid_size, 1, 1)
matmul_kernel, # Kernel function
(A, B, C, tm, tn, tk) # Arguments passed to kernel
)

Stream:指定核函數在哪個 CUDA 流上執行(用于實現異步執行與多流并發)。

網格:定義要啟動的線程塊數量。

內核函數:要執行的 GPU 內核(即使用 ct.kernel 裝飾的函數)。

參數元組: 傳遞給內核的所有參數;其中tm、tn和tk將被編譯器識別為常量。

性能優化:Swizzle

為了提升性能,我們引入了早期的 Swizzle。如swizzle_2d_from_bid的代碼所示。

def swizzle_2d_from_bid(M, N, tm, tn, GROUP_SIZE_M, bid):
# Get the global IDs of a given CUDA block in a 1D grid.
num_bid_m = ct.cdiv(M, tm)
num_bid_n = ct.cdiv(N, tn)
num_bid_in_group = GROUP_SIZE_M * num_bid_n
group_id = bid // num_bid_in_group
first_bid_m = group_id * GROUP_SIZE_M
group_size_m = min(num_bid_m - first_bid_m, GROUP_SIZE_M)
bid_m = first_bid_m + (bid % group_size_m)
bid_n = (bid % num_bid_in_group) // group_size_m
return bid_m, bid_n

Swizzle 如何提高性能?

它通過分組與交錯的方式,將塊 ID 重新映射到平鋪索引,以更高效地利用緩存。

本圖以輸出矩陣的四個元素(著色區域)為例,對比了線性內存訪問與 Swizzled 內存訪問方式。

wKgZO2lx49KAJAsRAAp5v8bwbzc404.png

圖 2。線性行訪問與分塊平鋪訪問的直觀對比

方法 1:線性行訪問

計算結果矩陣中的一行數據(例如四個元素)時,

需要讀取左側矩陣的四個塊以及右側矩陣的全部 16 個塊。

總的內存訪問量:20 個數據塊。

由于正確的矩陣數據會被頻繁加載并迅速替換,導致緩存命中率降低。

方法 2:Swizzle/ 平鋪塊訪問

將計算重新組織為 2 × 2 的本地塊。

僅需讀取左側矩陣中的 8 個相關塊和右側矩陣中的 8 個相關塊。

總顯存訪問量: 16 個數據塊 (減少 20%).

數據局部性更優,緩存命中率隨之提高。

性能基準測試

為了驗證已實現的矩陣乘法內核的性能,測試在NVIDIA GeForce RTX 5080(計算能力 12.0)上進行。完整的基準測試代碼可在TileGym資源庫中找到。 請按照安裝說明完成配置后,參照快速入門指南運行本測試及其他相關測試。

測試配置:

數據類型: float16

矩陣形狀: 標準方形矩陣(N × N)

測試規模: N = 1024、2048、4096、8192、16384(即 21? 到 21?)

下圖展示了不同矩陣規模下的性能表現。

wKgZO2lx4-aAACObAAFfilgxNo8424.png

圖 3. NVIDIA GeForce RTX 5080 上 cuTile 與 PyTorch 的 TFLOP/s 性能隨矩陣大小變化的對比

結果表明:

在大型矩陣規模下,cuTile 實現能夠充分釋放 GPU 的計算能力。

通過合理的圖塊大小配置與 swizzle 優化,cuTile 實現的性能較業界先進實現(PyTorch 調用 cuBLAS)提升90% 以上。

總結

這個經典的矩陣乘法示例展示了使用 cuTile 實現 GPU 內核的完整過程。盡管矩陣乘法較為簡單,但它涵蓋了 Tile 編程的核心理念。掌握這些概念后,您將能夠運用 cuTile 實現多種高性能 GPU 內核。請在TileGym 庫中查看完整的矩陣乘法示例及其他相關內容,立即開始編寫高效的圖塊代碼。

關于作者

Jinman Xie 是 NVIDIA 的深度學習性能架構師。她畢業于浙江大學計算機科學與技術學院。Jinman 的主要關注領域包括深度學習模型加速、內核優化和深度學習編譯器技術。

Qiqi Xiao 畢業于北京大學計算機科學專業,并獲得卡內基梅隆大學碩士學位。Qiqi 專注于 AI 推理框架、深度學習模型優化和編譯器技術。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 內核
    +關注

    關注

    4

    文章

    1467

    瀏覽量

    42869
  • NVIDIA
    +關注

    關注

    14

    文章

    5592

    瀏覽量

    109716
  • gpu
    gpu
    +關注

    關注

    28

    文章

    5194

    瀏覽量

    135427
  • 編程
    +關注

    關注

    90

    文章

    3716

    瀏覽量

    97178

原文標題:如何在 NVIDIA CUDA Tile 中編寫高性能矩陣乘法

文章出處:【微信號:NVIDIA-Enterprise,微信公眾號:NVIDIA英偉達企業解決方案】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    使用CUDA并行化矩陣乘法加速Blender Python

      這篇文章描述了兩種不同的加速矩陣乘法的方法。第一種方法使用 Numba 編譯器來減少 Python 代碼與循環相關的開銷。第二種方法使用 CUDA 并行化
    的頭像 發表于 04-24 17:04 ?6636次閱讀
    使用<b class='flag-5'>CUDA</b>并行化<b class='flag-5'>矩陣</b><b class='flag-5'>乘法</b>加速Blender Python

    NVIDIA火熱招聘深度學習/高性能計算解決方案架構師

    目前NVIDIA在中國熱招解決方案架構師, 該崗位致力于協同客戶經理將NVIDIA最新的深度學習/高性能計算解決方案與技術帶給我們的客戶, 幫助客戶通過實施NVIDIA技術解決方案來提
    發表于 08-25 17:02

    NVIDIA火熱招聘GPU高性能計算架構師

    GPU架構設計者提供反饋,以改善和推進未來GPU的架構設計基本要求(其一即可): * 嚴謹的邏輯思維和分析能力* 有CUDA代碼調優經驗(或者SIMD等架構的調優經驗)* 熟悉矩陣計算的優化和加速* 較強C++編程能力、算法分析和實現* 熟悉計算機體系結構*了解GPU架構
    發表于 09-01 17:22

    NVIDIA Grid SERIES K2卡兼容CUDA

    你好我有一個裸機Windows 2002 RC 2 x64bit服務器,帶有物理NVIDIA Grid SERIES K2卡(不是vGPU vGRID)。這張卡與CUDA兼容嗎?我使用的軟件沒有將其
    發表于 09-10 17:18

    NVIDIA CUDA 計算統一設備架構

    NVIDIA CUDA參考文件
    發表于 03-05 08:00

    探求NVIDIA GPU極限性能的利器

    1、探求 NVIDIA GPU 極限性能的利器  在通常的 CUDA 編程,用戶主要通過 CUDA C/C++ 或 python 語言實現
    發表于 10-11 14:35

    Adreno GPU 矩陣乘法——第1講:OpenCL優化

    文章的概念和下一篇文章的OpenCL代碼清單,表示Adreno 4xx和5xx GPU系列設備端矩陣乘法內核函數和主機端參考代碼的優化實現。我們希望本系列文章將幫助和鼓勵您使用這些
    發表于 09-18 19:15 ?2167次閱讀

    如何使用Warp在Python環境編寫CUDA內核

      通常,實時物理模擬代碼是用低級 CUDA C ++編寫的,以獲得最佳性能。在這篇文章,我們將介紹 NVIDIA Warp ,這是一個新
    的頭像 發表于 04-02 16:15 ?3631次閱讀

    NVIDIA cuSPARSELt v0.2.0提高激活函數

      NVIDIA CUSPASSELT 是一個高性能 CUDA 庫,專用于一般矩陣運算,其中至少有一個操作數是稀疏矩陣
    的頭像 發表于 04-15 10:08 ?1043次閱讀

    NVIDIA CUDA工具包的概念及主要功能

    NVIDIA CUDA 工具包提供了開發環境,可供開發、優化和部署經 GPU 加速的高性能應用。
    的頭像 發表于 06-10 12:03 ?5205次閱讀

    CUDA矩陣乘法優化手段詳解

    單精度矩陣乘法(SGEMM)幾乎是每一位學習 CUDA 的同學繞不開的案例,這個經典的計算密集型案例可以很好地展示 GPU 編程中常用的優化技巧。本文將詳細介紹 CUDA SGEMM
    的頭像 發表于 09-28 09:46 ?2831次閱讀

    NVIDIA Hopper GPU上的新cuBLAS12.0功能和矩陣乘法性能

    NVIDIA Hopper GPU 上的新 cuBLAS 12.0 功能和矩陣乘法性能
    的頭像 發表于 07-05 16:30 ?4501次閱讀
    <b class='flag-5'>NVIDIA</b> Hopper GPU上的新cuBLAS12.0功能和<b class='flag-5'>矩陣</b><b class='flag-5'>乘法</b><b class='flag-5'>性能</b>

    在Python借助NVIDIA CUDA Tile簡化GPU編程

    NVIDIA CUDA 13.1 版本新增了基于 Tile 的GPU 編程模式。它是自 CUDA 發明以來 GPU 編程最核心的更新之一。借助 GPU
    的頭像 發表于 12-13 10:12 ?1190次閱讀
    在Python<b class='flag-5'>中</b>借助<b class='flag-5'>NVIDIA</b> <b class='flag-5'>CUDA</b> <b class='flag-5'>Tile</b>簡化GPU編程

    NVIDIA CUDA Tile的創新之處、工作原理以及使用方法

    NVIDIA CUDA 13.1 推出 NVIDIA CUDA Tile,這是自 2006 年 NVID
    的頭像 發表于 12-24 10:17 ?459次閱讀
    <b class='flag-5'>NVIDIA</b> <b class='flag-5'>CUDA</b> <b class='flag-5'>Tile</b>的創新之處、工作原理以及使用方法

    借助NVIDIA CUDA Tile IR后端推進OpenAI Triton的GPU編程

    NVIDIA CUDA Tile 是基于 GPU 的編程模型,其設計目標是為 NVIDIA Tensor Cores 提供可移植性,從而釋放 GPU 的極限
    的頭像 發表于 02-10 10:31 ?238次閱讀