🐇明明跟你說過:個人主頁
🏅個人專欄:《深度探秘:AI界的007》?🏅
🔖行路有良友,便是天堂🔖
目錄
一、引言
1、CUDA為何重要:并行計算的時代
2、NVIDIA在GPU計算領域的角色
二、CUDA簡介
1、什么是CUDA
2、CUDA的歷史與發展
三、CUDA架構解析
1、GPU vs CPU:架構對比
2、CUDA核心組件
四、CUDA編程模型
1、CUDA程序的基本結構
2、Kernel函數與線程層級
3、內存管理與數據傳輸(Host ? Device)
一、引言
1、CUDA為何重要:并行計算的時代
🧠 單核時代的終結
曾幾何時,我們對計算性能的追求是這樣的:
“CPU 主頻越高越好,單核越強越牛!” 🐎
但摩爾定律漸趨放緩,散熱瓶頸越來越明顯,頻率提升也越來越難……
于是,計算行業悄悄轉向了一條新路:并行計算。
?🔀 串行 vs 并行:一次做一件事 vs 同時做很多事
場景 | 串行(CPU) | 并行(GPU) |
---|---|---|
洗100個蘋果 | 一人洗100個 🍎 | 100個人各洗一個 🍎 |
圖像渲染 | 一像素一像素地算 🐢 | 一次處理上萬像素 🚀 |
視頻編解碼 | 一幀幀慢慢處理 🎞? | 多線程同時壓縮處理 📽? |
🎮 CUDA 的登場:讓 GPU 不只是打游戲!
NVIDIA 發現:
“嘿,我們家顯卡這么猛,為什么不拿來干點科研的活呢?”
于是他們發布了 CUDA(Compute Unified Device Architecture)
2、NVIDIA在GPU計算領域的角色
💬 “為啥大家一提 GPU 計算就想到 NVIDIA?”
?🏆 NVIDIA 在 GPU 計算領域的角色
💡 從顯卡廠商到計算王者的轉型
在很多人眼中,NVIDIA 一開始只是“做顯卡的公司”:
🎮 給游戲加速
🎬 給影視渲染
🎨 給設計師畫圖更絲滑
BUT!
NVIDIA 真正的雄心,從來不止于此 —— 它要讓 GPU 成為 通用計算平臺,改變整個計算產業的未來。
?📊 市場格局:幾乎壟斷的存在
領域 | NVIDIA 份額(粗略估計) | 代表產品 |
---|---|---|
深度學習訓練硬件 | 90%+ | A100、H100、DGX |
高性能計算(HPC) | 80%+ | Tesla 系列、NVLink |
AI 推理 & 云計算加速器 | 快速增長中 | L40、T4、Grace Hopper |
二、CUDA簡介
1、什么是CUDA
你有沒有想過,電腦里的 顯卡(GPU) 除了打游戲、看電影,其實還可以幫我們做科學計算、跑 AI 模型、挖礦(沒錯,就是你聽說過的那個)🤯
這背后,有一項“黑科技”功不可沒——CUDA!
🧠 簡單來說,CUDA 是什么?
CUDA,全稱是 Compute Unified Device Architecture,由 NVIDIA 開發。
通俗點說,它是讓顯卡“聽懂”程序員指令的工具,讓 GPU 不只是畫畫圖,還能做“正經數學題”。🎨 ?? 📐📊
🎮 CPU vs GPU:一場角色扮演大比拼
屬性 | CPU(中央處理器)🧑?💻 | GPU(圖形處理器)🕹? |
---|---|---|
核心數量 | 少(通常 4~16) | 多(上千個) |
單核能力 | 強(能干大事) | 弱(擅長干重復的活) |
擅長任務 | 串行處理(一步步來) | 并行處理(群體作戰) |
應用場景 | 系統操作、邏輯控制等 | 圖形渲染、AI計算等 |
舉個栗子 🌰:
想象一下,CPU 是“全能型學霸”,擅長一心一用,解決復雜邏輯題;
而 GPU 是“搬磚小能手”,擅長一口氣搬 100 塊磚,非常適合干重復又密集的活兒,比如矩陣運算、圖像處理、深度學習。
👷 CUDA:讓程序員調動顯卡的“千軍萬馬”
以前 GPU 只能畫畫圖,程序員很難直接讓它干別的活。
CUDA 的出現就像給程序員發了一把鑰匙🔑,可以“呼叫”GPU,讓它幫忙處理計算任務!
? 支持 C/C++/Python 編程語言
? 你寫的代碼可以運行在 GPU 上,而不是 CPU
? 支持大規模并行運算,速度飛快!
🎯 舉個實際例子
假如你要給 1 億個數字都加上 1。
-
用 CPU:你排隊慢慢加,每次處理一個(像銀行窗口🙃)
-
用 CUDA + GPU:你開 10,000 個窗口一起加(像春運高速收費站🏁)
速度那叫一個快!
🤖 CUDA 用在哪里?
💡 深度學習模型訓練(比如 ChatGPT 的訓練就靠它)
🧬 生物醫學模擬
🎞? 視頻轉碼、圖像處理
🌍 天氣預測、地震模擬、金融風險分析……
?
2、CUDA的歷史與發展
🎬 1. 起點:GPU 只是“畫面小工”
🔙 時間回到 2000 年前后——那時的 GPU(比如 GeForce2)基本只是負責“畫圖”的:
-
把游戲渲染得更炫酷
-
把視頻播放得更順滑
完全是為顯示服務的「圖形小助手」🎨,離“通用計算”還差十萬八千里。
💡 2. 萌芽:聰明人發現“GPU 運算能力好猛!”
在科研圈,有人開始偷偷用 GPU 來做“非圖形計算”。他們發現:
?“這玩意居然跑矩陣比 CPU 快多了?”
那時的 GPU 沒有專門支持“通用計算”的編程接口,只能用很復雜的 OpenGL/DirectX Shader 技巧“曲線救國”,開發難度堪比修仙??
🚀 3. 決定性轉折:2006 年 CUDA 橫空出世
NVIDIA 看到機會來了,果斷出手!
🗓? 2006 年:CUDA 1.0 正式發布!
它是全球第一個面向 GPU 的通用計算平臺,程序員終于可以用 C 語言控制 GPU 干活了🔥
從此,GPU 不再是“圖形工具人”,而成為了“并行計算的加速王”。
📈 4. 快速進化:從 Fermi 到 Hopper,一代更比一代猛
CUDA 平臺與 NVIDIA GPU 架構是配套演進的:
年份 | 架構代號 | 特點亮點 |
---|---|---|
2008 | Tesla | 第一代 GPGPU,支持雙精度浮點 |
2010 | Fermi | 引入 L1/L2 緩存,提升通用計算性能 |
2012 | Kepler | 提升能效,支持動態并行 |
2016 | Pascal | 加入 Tensor 核心前奏,HPC 友好 |
2017 | Volta | 初代 Tensor Cores,AI 訓練神器 |
2020 | Ampere | 強化 AI 計算,支持多精度并行 |
2022 | Hopper | 全面 AI 化身,專為 Transformer 打造 |
2024 | Blackwell | 最新旗艦,推理性能暴漲 |
每一代 CUDA Toolkit 也在同步升級,支持更強的編譯器、更高級的優化、更豐富的庫。
🧠 5. 與 AI 深度綁定:CUDA 成為 AI 的發動機
-
2012:AlexNet 橫空出世,用 NVIDIA GTX 580 訓練,AI 炸裂出圈💥
-
之后:PyTorch、TensorFlow 等深度學習框架,幾乎都離不開 CUDA 后端
-
現在:從 ChatGPT 到 Stable Diffusion,背后 GPU 加速都是靠 CUDA ?
🧩 6. 今日 CUDA:不僅僅是一個庫,更是一整個宇宙
CUDA 不再只是“讓 GPU 干活”,它成了一個完整的開發生態:
-
📦 各種庫:cuDNN、cuBLAS、TensorRT、NCCL…
-
🧰 工具鏈:Nsight、Visual Profiler、CUDA Graph…
-
🌍 平臺支持:從嵌入式 Jetson 到數據中心 DGX 全都能用
?
CUDA 的成長 = 從一把螺絲刀 🪛 ?? 到一整套核武庫 💣
它改變了 GPU 的命運,也重新定義了“計算”的方式。
今天,如果你說你搞 AI、做科學計算、研究機器學習,卻沒聽說過 CUDA——那就像學魔法不知道哈利波特🧙?♂?。
三、CUDA架構解析
1、GPU vs CPU:架構對比
在 CUDA 的世界里,最常聽到的問題之一就是:
“既然我有 CPU,為什么還要用 GPU 來計算呢?”
這個問題就像問:
“我有一輛小轎車,為什么還需要火車?”🚗 vs 🚄
它們各有專長!CPU 和 GPU 不是誰更好,而是適合干不同的活。
?🏗? 架構對比:一個是多面手,一個是并行狂魔
特性 | 🧑?💻 CPU(中央處理器) | 🕹? GPU(圖形處理器) |
---|---|---|
核心數量 | 少(4~16個高性能核心) | 多(數百到上萬個) |
每個核心的能力 | 強,能處理復雜指令 | 弱,專注簡單重復計算 |
控制單元 | 多,負責調度和決策 | 少,更依賴外部控制 |
緩存系統 | 大,層次復雜(L1/L2/L3) | 小而專注 |
適合的任務類型 | 串行任務、多任務處理 | 數據并行、大規模計算 |
延遲 vs 吞吐量 | 低延遲、決策快 | 高吞吐、批量處理猛 |
編程難度 | 簡單,工具成熟 | 相對復雜(CUDA等) |
舉個例子 | 跑操作系統、打開網頁 | 訓練 AI、視頻渲染 |
🧩 用生活舉個例子!
-
CPU 像一位博士👨?🎓:一個人能力特別強,但只能一心一用,適合解決邏輯復雜、步驟多的問題。
-
GPU 像一群工人👷?♂?👷?♀?:單個能力可能不高,但可以分工協作,把重復性的任務快速干完,效率爆表!
?💡 實際場景誰上場?
場景 | 誰更合適 |
---|---|
打開瀏覽器、運行操作系統 | ? CPU |
視頻渲染、圖形處理 | ? GPU |
訓練深度神經網絡(AI) | ? GPU |
數據庫查詢、事務處理 | ? CPU |
模擬氣候、科學建模、并行計算 | ? GPU |
編譯代碼、跑腳本 | ? CPU |
游戲里的實時光影渲染 | ? GPU |
🚦 并行模型上的區別
特性 | CPU | GPU |
---|---|---|
并行粒度 | 粗粒度(每核處理獨立任務) | 細粒度(線程塊內高度同步) |
指令模型 | MIMD(多指令多數據) | SIMT(單指令多線程) |
控制邏輯 | 多樣化、復雜 | 簡化、統一控制 |
?📘 名詞解釋:
-
MIMD:每個核心都可以執行不同的指令
-
SIMT:多個線程執行相同的指令,但處理不同的數據
?🧠 小結一句話!
CPU 負責“聰明的決策”,GPU 擅長“傻快的計算”
它們不是敵人,而是互補搭檔,現代計算中通常是搭配使用的!
?
2、CUDA核心組件
🔧 CUDA 核心組件:構建 GPU 編程的四大金剛
你可以把 CUDA 想象成一個“GPU 軟件開發的操作系統”,它不是一個單一的程序,而是由一整套核心組件組成的“超級工具箱”。
下面我們來看看構成 CUDA 的四大金剛 🔥
1?? CUDA Runtime API(運行時 API)
💬 它是開發者最常打交道的接口,是你用 C/C++ 寫 CUDA 程序的“入口”。
📌 功能包括:
-
GPU 內存分配和釋放(
cudaMalloc
/cudaFree
) -
設備信息查詢(
cudaGetDeviceProperties
) -
啟動 kernel(
<<< >>>
語法就是它支持的)
🧠 類比一下:
就像你用 Python 寫腳本,Python 幫你處理內存、線程這些底層細節,CUDA Runtime API 就是幫你“簡單調用 GPU”。
?2?? CUDA Driver API(驅動層 API)
🛠? 更底層、更靈活、更復雜。適用于需要細粒度控制 GPU 資源的場景。
📌 功能包括:
-
設備初始化與上下文管理(更手動)
-
加載 PTX、模塊化內核編程
-
編譯時更靈活地控制 GPU 行為
🎯 誰在用?
-
深度學習框架開發者(例如 PyTorch 底層封裝)
-
系統級別的 GPU 控制和調優
🧠 類比一下:
Runtime API 是自動擋 🚗,Driver API 是手動擋賽車 🏎?,能玩得更極限,但也更難操作。
3?? CUDA 核函數(Kernel Function)
🚀 這是你寫的代碼真正運行在 GPU 上的“主力部隊”。
📌 特點:
-
用
__global__
關鍵字聲明 -
用
<<<grid, block>>>
語法來啟動(指定并行粒度) -
每個線程獨立執行一份 kernel 的代碼
🧠 類比一下:
Kernel 像是“工廠車間的流水線工人”👷,你一次下達指令,成百上千個“工人”在不同崗位同步干活。
__global__ void add(int *a, int *b, int *c) {int i = threadIdx.x;c[i] = a[i] + b[i];
}
4?? CUDA 內存模型(Memory Model)
💾 GPU 的內存系統是多層次的,用得好 = 性能飛起🚀
類型 | 特性 | 示例 |
---|---|---|
Global Memory | 所有線程可訪問,容量大,訪問慢 | cudaMalloc 分配的內存 |
Shared Memory | 每個線程塊共享,訪問速度快 | 用 __shared__ 聲明 |
Local Memory | 每線程獨享,實為全局空間 | 局部變量(寄存器不足時) |
Registers | 每線程專屬,最快 | 編譯器自動分配 |
Constant Memory | 只讀緩存,供所有線程共享,適合常量傳遞 | __constant__ |
Texture/Surface | 專用于圖像處理,帶緩存優化 | 適合做圖像/矩陣采樣等 |
🧠 類比一下:
內存就像廚房里的原料分區,寄存器是你手邊的調料臺,Global memory 是倉庫,Shared memory 是工位中間的調料包。
?
四、CUDA編程模型
1、CUDA程序的基本結構
🧱 CUDA 程序的基本結構:從 CPU 到 GPU 的“打工外包流程”
要寫一個 CUDA 程序,其實核心流程就一句話:
🗣? 主程序在 CPU 上運行,但把計算“打包”交給 GPU 干
下面我們一步步拆解這個“GPU 打工隊”的工作流程 👷?♂?
🧭 基本結構總覽(5 個步驟)
一個典型 CUDA 程序結構可分為以下 5 步:
1?? 準備數據(在 CPU 上)
2?? 分配 GPU 內存并復制數據(Host ? Device)
3?? 編寫并調用 CUDA 核函數(Kernel)
4?? 把計算結果從 GPU 拷回 CPU(Device ? Host)
5?? 釋放內存資源,程序結束
?🧪 示例:兩個數組相加(Vector Add)
我們用一個經典的例子來演示 CUDA 程序的完整結構:向量加法
📌 功能:
c[i] = a[i] + b[i];
🧾 完整代碼框架:
#include <stdio.h>
#include <cuda_runtime.h>// CUDA 核函數:每個線程負責加一個元素
__global__ void vectorAdd(int *a, int *b, int *c, int n) {int i = threadIdx.x;if (i < n)c[i] = a[i] + b[i];
}int main() {const int N = 10;int a[N], b[N], c[N]; // 在 CPU(host)上的數組int *d_a, *d_b, *d_c; // GPU(device)上的指針// 初始化數據for (int i = 0; i < N; i++) {a[i] = i;b[i] = i * 2;}// 1. 分配 GPU 內存cudaMalloc((void**)&d_a, N * sizeof(int));cudaMalloc((void**)&d_b, N * sizeof(int));cudaMalloc((void**)&d_c, N * sizeof(int));// 2. 拷貝數據到 GPUcudaMemcpy(d_a, a, N * sizeof(int), cudaMemcpyHostToDevice);cudaMemcpy(d_b, b, N * sizeof(int), cudaMemcpyHostToDevice);// 3. 啟動 Kernel(讓 GPU 干活!)vectorAdd<<<1, N>>>(d_a, d_b, d_c, N);// 4. 把結果拷回 CPUcudaMemcpy(c, d_c, N * sizeof(int), cudaMemcpyDeviceToHost);// 5. 打印結果printf("Result:\n");for (int i = 0; i < N; i++)printf("%d + %d = %d\n", a[i], b[i], c[i]);// 6. 釋放 GPU 內存cudaFree(d_a); cudaFree(d_b); cudaFree(d_c);return 0;
}
🧠 每步拆解說明:
步驟 | 內容 | 說明 📝 |
---|---|---|
1 | cudaMalloc | 在 GPU 上申請內存 |
2 | cudaMemcpy (Host ? Device) | 把 CPU 數據傳給 GPU |
3 | <<<blocks, threads>>> 啟動 kernel | 設置并行維度、執行函數 |
4 | cudaMemcpy (Device ? Host) | 把結果從 GPU 拷回 CPU |
5 | cudaFree | 清理資源,避免內存泄露 |
🔍 補充:線程模型簡要說明
-
<<<1, N>>>
:意思是啟動 1 個 block,每個 block 有 N 個線程 -
threadIdx.x
:獲取當前線程在 block 中的編號(0 ~ N-1)
🧠 可以把每個線程想成一個“工人”,threadIdx.x
就是工號,它負責數組中第幾個元素的加法。
📦 小貼士:想學得更好,可以試試…
-
把
N
改大點,看 GPU 性能 -
改成 2D/3D grid/block,理解多維并行
-
加個計時器看看 GPU 比 CPU 快多少(
cudaEvent
)
? 小結一句話!
CUDA 程序結構 = 在 CPU 上安排好任務,然后啟動成千上萬個線程去 GPU 上“并行開工”💪
?
2、Kernel函數與線程層級
🧩 Kernel 函數與線程層級:并行計算的發動機 🚀
在 CUDA 編程中,我們不會一個個處理數據,而是:
把任務切片,丟給成千上萬個線程同時運行!
這些線程由 GPU 上的 Kernel 函數統一調度執行。那么:
-
什么是 Kernel 函數?
-
怎么安排線程分工?
-
什么是 Block、Grid、Thread?
接下來逐一拆解!
🔧 什么是 Kernel 函數?
Kernel 是 CUDA 程序中由 GPU 執行的函數,它是并行計算的核心。
__global__ void myKernel(...) {// 每個線程執行這段代碼
}
🔹 __global__
關鍵字告訴編譯器:
這個函數運行在 GPU 上,但可以被 CPU 調用。
🔹 啟動方式:
myKernel<<<gridSize, blockSize>>>(...);
這不是語法糖,而是在告訴 CUDA:
“我要啟動多少線程來跑這個函數。”
?🧱 線程的三層層級結構
CUDA 中線程的組織就像軍隊建制,非常有層級感:
?
層級 | 作用說明 | 舉例(1D) |
---|---|---|
Grid | 由多個 Block 組成(可以是1D/2D/3D) | 一個網格網(任務總量) |
Block | 一個線程塊,包含若干線程 | 一組線程在同一塊中 |
Thread | 最小執行單位 | 每個處理一小段任務 |
?🧠 類比一下:
-
Grid:公司里的整個部門 🏢
-
Block:每個小組 👥
-
Thread:組員 👤
🧮 每個線程怎么知道“我是誰”?
CUDA 提供了 3 個內置變量,線程啟動時自動可用:
變量 | 說明 | 類型 |
---|---|---|
threadIdx | 當前線程在 Block 中的索引 | uint3 |
blockIdx | 當前 Block 在 Grid 中的索引 | uint3 |
blockDim | 每個 Block 有多少線程 | dim3 |
gridDim | Grid 中有多少個 Block | dim3 |
🧠 小結一句話!
Kernel 是執行體,Grid 是組織方式,Thread 是計算單位
你寫一次 Kernel,CUDA 幫你復制成千上萬份“工人”去同時執行💥
?
3、內存管理與數據傳輸(Host ? Device)
💾 內存管理與數據傳輸(Host ? Device)
在 CUDA 編程中,CPU(Host) 和 GPU(Device) 是兩套完全獨立的世界,它們各自有自己的內存空間:
🧠 CPU 內存 = 主內存(RAM)
🎮 GPU 內存 = 顯存(VRAM)
CUDA 編程最重要的一步就是:
想辦法把數據在 Host 和 Device 之間“搬來搬去” 🚚
?🧭 你必須搞懂的三件事:
內容 | 作用 | 類比(搬磚打工) |
---|---|---|
cudaMalloc() | 在 GPU 上分配顯存 | 給 GPU 準備磚堆 🧱 |
cudaMemcpy() | Host ? Device 數據傳輸 | 搬磚車來回運材料 🚛 |
cudaFree() | 釋放 GPU 分配的內存資源 | 工地收工,清理現場 🧹 |
🧪 示例代碼:準備一批數據送去 GPU 加工
const int N = 100;
int a[N], b[N], c[N];
int *d_a, *d_b, *d_c;// 1. 在 GPU 上分配內存
cudaMalloc((void**)&d_a, N * sizeof(int));
cudaMalloc((void**)&d_b, N * sizeof(int));
cudaMalloc((void**)&d_c, N * sizeof(int));// 2. 把 CPU 上的原材料送到 GPU
cudaMemcpy(d_a, a, N * sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(d_b, b, N * sizeof(int), cudaMemcpyHostToDevice);// 3. 執行 Kernel 計算(略)// 4. 把結果從 GPU 拷回 CPU
cudaMemcpy(c, d_c, N * sizeof(int), cudaMemcpyDeviceToHost);// 5. 清理資源
cudaFree(d_a);
cudaFree(d_b);
cudaFree(d_c);
🚥 cudaMemcpy
的四種傳輸方向
常量名 | 從哪傳 → 傳到哪 | 場景 |
---|---|---|
cudaMemcpyHostToDevice | 🧠 CPU → 🎮 GPU | 把數據送去計算 |
cudaMemcpyDeviceToHost | 🎮 GPU → 🧠 CPU | 拿結果回來用 |
cudaMemcpyDeviceToDevice | 🎮 GPU → 🎮 GPU | GPU 內部數據拷貝 |
cudaMemcpyHostToHost | 🧠 CPU → 🧠 CPU | 和普通 memcpy 類似 |
📦 內存管理流程圖(邏輯圖)
?
? 小結一句話
CUDA 內存管理 = 分配 + 拷貝 + 回收,像操作 GPU 的物流倉庫一樣💼
?
?💕💕💕每一次的分享都是一次成長的旅程,感謝您的陪伴和關注。希望這些文章能陪伴您走過技術的一段旅程,共同見證成長和進步!😺😺😺
🧨🧨🧨讓我們一起在技術的海洋中探索前行,共同書寫美好的未來!!!?