Day 26 PyTorch 安裝與張量
引言
走到今天,Python 基礎、資料處理、視覺化與數學都準備好了。從明天起,我們要正式踏入 PyTorch 的世界。PyTorch 是目前最主流的深度學習框架之一,語法直覺、偵錯方便,被學術界與產業界廣泛使用。Meta 在 2016 年開源釋出,經過多年的迭代,已經成為研究者與工程師的首選工具之一。相較於 TensorFlow 1.x 的靜態計算圖,PyTorch 採用「動態計算圖」,讓你能像寫普通 Python 一樣即時偵錯,這對新手特別友善。
今天的目標有兩個:把 PyTorch 安裝好,並理解「張量」(Tensor)是什麼。張量可以想成是 NumPy ndarray 的強化版:除了支援 CPU 運算,還能搬到 GPU 上跑;除了基本運算,還內建自動微分(明天的主題)。學會張量,就掌握了 PyTorch 一切的起點。為了確保環境一致,這篇的所有範例都假設 Python 3.12、PyTorch 2.5 系列。
在虛擬環境中安裝 PyTorch
強烈建議在獨立的虛擬環境中安裝 PyTorch,避免不同專案的套件版本互相衝突。Day 12 學過的 venv 在這裡一樣適用。當你同時有多個深度學習專案時,虛擬環境能避免「某個專案升級了套件,結果另一個專案壞掉」這種慘劇。
# 建立並啟動虛擬環境
python -m venv .venv
# Windows 啟動
.venv\Scripts\activate
# macOS / Linux 啟動
source .venv/bin/activate
pip install --upgrade pip
接下來到 PyTorch 官方網站的「Get Started」頁面,根據你的作業系統、套件管理器(這裡用 pip)、Python 版本與 CUDA 版本,產生對應的安裝指令。截至 2024 年 11 月,PyTorch 穩定版是 2.5 系列。CPU 版的安裝指令如下:
# CPU 版(沒有 NVIDIA GPU 或暫時不需要 GPU 加速)
pip install torch torchvision torchaudio
如果電腦有 NVIDIA GPU,並且已經裝好 CUDA,可以安裝 GPU 版獲得明顯的加速。安裝指令需要在 PyTorch 官網依你的 CUDA 版本選擇對應的 wheel。2024 年 11 月時,PyTorch 2.5 支援 CUDA 11.8 與 CUDA 12.1/12.4 三個版本。GPU 版在大規模訓練時可以比 CPU 快上幾十倍,但在小型實驗或學習階段,CPU 版已經足夠。
# CUDA 12.1 範例(GPU 版)
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
安裝完成後,進入 Python 環境檢查版本與 CUDA 是否可用:
import torch
print("PyTorch 版本:", torch.__version__)
print("CUDA 是否可用:", torch.cuda.is_available())
if torch.cuda.is_available():
print("CUDA 版本:", torch.version.cuda)
print("GPU 名稱:", torch.cuda.get_device_name(0))
輸出(依環境而異):
PyTorch 版本: 2.5.1
CUDA 是否可用: True
CUDA 版本: 12.1
GPU 名稱: NVIDIA GeForce RTX 4070
如果 torch.cuda.is_available() 回傳 False,最常見的原因是:驅動程式太舊、CUDA toolkit 沒裝、或 pip 安裝時選到 CPU 版。要查 GPU 對應的 CUDA 版本,可以在命令提示字元輸入 nvidia-smi,最上方會顯示 CUDA Version(這是「驅動能支援的最高 CUDA 版本」,不是已經裝好的 toolkit 版本)。
如何選擇正確的 CUDA 版本
CUDA 版本沒選對,安裝會直接失敗或執行時出錯。選擇時請依照這個順序檢查:
- 查 GPU 驅動支援的 CUDA 版本:執行
nvidia-smi,右上角的「CUDA Version」告訴你這個驅動最多能跑哪個 CUDA。例如看到 12.6,代表你的驅動可以支援到 CUDA 12.6。 - 選一個 PyTorch 有支援、且不高於上面數字的 CUDA:截至 2024 年 11 月,PyTorch 2.5 提供 CUDA 11.8、12.1、12.4 的 wheel。若驅動能支援到 12.6,可以安裝 12.1 或 12.4 的 wheel;若驅動只支援到 12.0,則要改裝 CUDA 11.8 版(向前相容)。
- 若不確定,就先用 CPU 版:CPU 版可以完整執行所有 PyTorch 功能,只是會比較慢。等到確認 GPU 環境沒問題,再切換成 GPU 版。
記得 PyTorch 的 CUDA 版本和 NVIDIA 驅動的 CUDA 版本是「分開的」。驅動向後相容,舊驅動可以執行新 CUDA toolkit 編譯出的應用;但 PyTorch 的 wheel 是預先編譯的,必須裝對應版本的 wheel,否則會在 import 時報錯。常見的錯誤是「用 CUDA 12.6 驅動裝了 CUDA 12.1 的 wheel,結果 import 時出現 undefined symbol」——這時只要重新裝對應版本的 wheel 即可解決。
張量:NumPy ndarray 的強化版
張量(Tensor)是 PyTorch 的核心資料結構。最簡單的理解方式是:它是 NumPy 的 ndarray 加上三個額外能力——能跑在 GPU 上、能記錄運算過程以支援自動微分、能整合進神經網路層的計算圖。理解張量,就等於理解 PyTorch 的「資料」概念,後續所有模型、訓練、推論都建立在張量之上。
import torch
# 從 Python 串列建立張量
t = torch.tensor([[1, 2, 3], [4, 5, 6]])
print("張量 t:")
print(t)
print("形狀 =", t.shape)
print("資料型別 =", t.dtype)
print("裝置 =", t.device)
輸出:
張量 t:
tensor([[1, 2, 3],
[4, 5, 6]])
形狀 = torch.Size([2, 3])
資料型別 = torch.int64
裝置 = cpu
預設情況下,張量建在 CPU 上、整數資料會用 int64。如果想指定資料型別與裝置,可以在建立時加上參數。深度學習中幾乎所有運算都用浮點數(float32 居多),所以實務上常常會這樣寫:torch.tensor([1.0, 2.0, 3.0]) 或 torch.tensor([1, 2, 3], dtype=torch.float32)。
t_float = torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.float32)
print("資料型別 =", t_float.dtype)
PyTorch 還有幾個常用的張量建立函式:
zeros = torch.zeros(2, 3) # 2×3 全零
ones = torch.ones(2, 3) # 2×3 全一
rand = torch.rand(2, 3) # 2×3 介於 [0, 1) 的均勻亂數
randn = torch.randn(2, 3) # 2×3 標準常態分佈亂數
arange = torch.arange(0, 10, 2) # [0, 2, 4, 6, 8]
這些函式的行為和 NumPy 非常相似,熟悉 Day 15、Day 16 的 NumPy 章節後應該不陌生。torch.rand() 與 torch.randn() 的差異是:前者是均勻分佈,後者是常態分佈。神經網路初始化權重時常用 randn(),讓初始權重以 0 為中心對稱分佈。
張量運算與 NumPy 互轉
張量之間的運算、索引、切片都和 NumPy ndarray 幾乎一樣,可以用熟悉的 NumPy 語法操作 PyTorch 張量。當你需要從熟悉的 NumPy 切換到 PyTorch 時,這種語法一致性會大幅降低學習門檻。
import torch
a = torch.tensor([[1.0, 2.0], [3.0, 4.0]])
b = torch.tensor([[5.0, 6.0], [7.0, 8.0]])
print("逐元素相加:\n", a + b)
print("逐元素相乘:\n", a * b)
print("矩陣乘法:\n", a @ b)
print("第 0 列:", a[0])
print("第 1 欄:", a[:, 1])
輸出:
逐元素相加:
tensor([[ 6., 8.],
[10., 12.]])
逐元素相乘:
tensor([[ 5., 12.],
[21., 32.]])
矩陣乘法:
tensor([[19., 22.],
[43., 50.]])
第 0 列: tensor([1., 2.])
第 1 欄: tensor([2., 4.])
張量也常常需要和 NumPy 陣列互轉,特別是在載入資料或繪圖時。Pandas 讀進來的資料是 DataFrame,要先轉 NumPy 再轉張量;畫圖時則需要反向從張量轉回 NumPy。這兩個方向的轉換是日常開發的高頻操作。
import torch
import numpy as np
# NumPy 轉張量
arr = np.array([1.0, 2.0, 3.0])
t_from_numpy = torch.from_numpy(arr)
print("從 NumPy 建立:", t_from_numpy)
# 張量轉 NumPy
t = torch.tensor([4.0, 5.0, 6.0])
arr_back = t.numpy()
print("轉回 NumPy:", arr_back)
需要注意,torch.from_numpy() 與 tensor.numpy() 預設會共用同一塊記憶體——改其中一邊,另一邊也會跟著改。如果不要這種行為,要用 torch.tensor(arr).clone() 先複製一份。這種「共享記憶體」的設計在效能上很高效,但在改資料時容易踩到坑,特別是用 GPU 張量時還會直接報錯。
裝置切換:在 CPU 與 GPU 之間搬運張量
要讓神經網路跑在 GPU 上,所有相關的張量與模型都必須在同一個裝置上。實務上會用一個 device 變數統一管理,並在建立張量或模型時指定裝置。這個寫法讓同一支程式不論在有沒有 GPU 的機器上都能跑——沒 GPU 時自動用 CPU,有 GPU 時自動用 GPU。
import torch
device = "cuda" if torch.cuda.is_available() else "cpu"
print("使用裝置:", device)
# 建立張量時直接指定裝置
x = torch.rand(3, 4, device=device)
print("張量裝置:", x.device)
# 既有張量用 .to() 搬裝置
y = torch.rand(3, 4)
y = y.to(device)
print("搬動後裝置:", y.device)
# 不同裝置的張量不能直接運算
cpu_t = torch.tensor([1.0, 2.0])
if torch.cuda.is_available():
gpu_t = cpu_t.to("cuda")
result = cpu_t + gpu_t
print(result)
else:
print("目前是 CPU 環境,跳過 GPU 運算測試")
最後一行的混合運算在 CPU 環境下會跳過、只在有 GPU 的環境下執行——這就是實務上寫 PyTorch 程式的標準起手式:把 device 寫成一個動態判斷的變數,這樣同一支程式不論在有沒有 GPU 的機器上都能跑。常見的錯誤是「忘記把模型搬到 GPU 上,結果輸入資料在 GPU、模型在 CPU」,這時只要把模型也 .to(device) 即可解決。
結語
今天把 PyTorch 安裝好、理解了 CUDA 與驅動版本的搭配原則,並認識了張量這個核心資料結構。從明天開始,我們會在張量之上加入「自動微分」——這也是 PyTorch 名字中 Torch(火焰)真正燃燒的地方。明天學習 requires_grad 與計算圖,看神經網路是怎麼自動算出每一個參數的梯度。PyTorch 的 autograd 是整個深度學習革命的重要推手之一,能讓你專注在模型設計上,把繁瑣的偏導數計算交給框架處理。
明天,我們會在張量之上加入「自動微分」——這也是 PyTorch 名字中 Torch(火焰)真正燃燒的地方。明天學習 requires_grad 與計算圖,看神經網路是怎麼自動算出每一個參數的梯度。
留言
張貼留言