PyTorch 從 0 到 1:超詳細(xì)的安裝與入門(mén)實(shí)戰(zhàn)指南
PyTorch 是一個(gè)由 Meta (Facebook) AI 研究實(shí)驗(yàn)室主導(dǎo)開(kāi)發(fā)的開(kāi)源機(jī)器學(xué)習(xí)庫(kù)。它以其靈活性、易用性和強(qiáng)大的GPU加速功能而聞名,已成為學(xué)術(shù)界和工業(yè)界進(jìn)行深度學(xué)習(xí)研究和應(yīng)用開(kāi)發(fā)的首選框架之一。
PyTorch 的兩大核心特性:
- 張量 (Tensor) 計(jì)算:類(lèi)似于 NumPy 的多維數(shù)組,但提供了強(qiáng)大的 GPU 加速能力,使得大規(guī)模數(shù)值計(jì)算變得極其高效。
- 自動(dòng)微分 (Automatic Differentiation):PyTorch 內(nèi)置了名為 torch.autograd的自動(dòng)微分引擎,可以自動(dòng)計(jì)算神經(jīng)網(wǎng)絡(luò)中參數(shù)的梯度,這是訓(xùn)練深度學(xué)習(xí)模型的關(guān)鍵。
第一部分:PyTorch 安裝
安裝 PyTorch 最可靠的方式是遵循其官網(wǎng)的指導(dǎo)。因?yàn)椴煌牟僮飨到y(tǒng)、包管理器和硬件(CPU/GPU)組合需要不同的命令。
步驟 1: 確認(rèn)你的環(huán)境
在安裝前,你需要明確以下幾點(diǎn):
(1) 操作系統(tǒng) (OS):Windows, macOS, 還是 Linux?
(2) 包管理器 (Package Manager):你習(xí)慣使用pip還是conda?
- Conda:強(qiáng)烈推薦。Conda 不僅能管理 Python 包,還能管理 Python 解釋器本身和復(fù)雜的非 Python 依賴(如 CUDA 工具包),可以創(chuàng)建隔離的環(huán)境,避免版本沖突。
- Pip:Python 官方的包管理器,如果你不打算使用 GPU 或能自行管理好 CUDA 環(huán)境,Pip 也是一個(gè)不錯(cuò)的選擇。
(3) 硬件 (Compute Platform):你打算只使用 CPU 還是利用 NVIDIA GPU 進(jìn)行加速?
- CPU:所有電腦都支持。
- GPU (CUDA):如果你有 NVIDIA 顯卡,并且想利用它來(lái)加速訓(xùn)練,就需要安裝支持 CUDA 的 PyTorch 版本。你需要先確認(rèn)你的顯卡驅(qū)動(dòng)和 CUDA Toolkit 版本??梢栽诮K端(或 Windows 的 cmd/PowerShell)中輸入 nvidia-smi 命令來(lái)查看。
步驟 2: 訪問(wèn) PyTorch 官網(wǎng)生成安裝命令
(1) 開(kāi)PyTorch 官網(wǎng)的安裝頁(yè)面:https://pytorch.org/get-started/locally/
(2) 在頁(yè)面上,你會(huì)看到一個(gè)交互式的配置工具。請(qǐng)根據(jù)你的環(huán)境依次選擇:
① 如果你的電腦沒(méi)有 NVIDIA 顯卡,或者你暫時(shí)不想配置 GPU,請(qǐng)選擇 CPU。
② 如果你有 NVIDIA 顯卡并想使用它,請(qǐng)選擇一個(gè) CUDA 版本。通常選擇與你 nvidia-smi 命令顯示的 CUDA 版本最接近或稍低的版本(PyTorch 的 CUDA 版本是其編譯時(shí)依賴的,通常能向后兼容較新的驅(qū)動(dòng))。
- PyTorch Build: 選擇 Stable (穩(wěn)定版),適合絕大多數(shù)用戶。
- Your OS: 選擇你的操作系統(tǒng)。
- Package: 選擇 Conda 或 Pip。
- Language: 選擇 Python。
- Compute Platform: 這是最關(guān)鍵的一步。
③ 復(fù)制生成的命令。網(wǎng)站會(huì)根據(jù)你的選擇自動(dòng)生成一行安裝命令。
步驟 3: 執(zhí)行安裝命令
強(qiáng)烈建議在一個(gè)新的虛擬環(huán)境中安裝 PyTorch,以避免與系統(tǒng)中其他 Python 包沖突。
使用 Conda (推薦):
# 1. 創(chuàng)建一個(gè)新的 conda 環(huán)境 (例如,名為 'pytorch_env'),并指定 Python 版本
conda create -n pytorch_env pythnotallow=3.9
# 2. 激活這個(gè)新環(huán)境
conda activate pytorch_env
# 3. 粘貼并執(zhí)行從官網(wǎng)復(fù)制的命令。以下是一些示例:
# 示例 1: Conda, Linux/Windows, 只用 CPU
# conda install pytorch torchvision torchaudio cpuonly -c pytorch
# 示例 2: Conda, Linux/Windows, 使用 CUDA 11.8
# conda install pytorch torchvision torchaudio pytorch-cuda=11.8 -c pytorch -c nvidia
使用 Pip:
# 1. 創(chuàng)建一個(gè)新的虛擬環(huán)境 (例如,名為 'pytorch_venv')
python -m venv pytorch_venv
# 2. 激活環(huán)境
# Windows
# pytorch_venv\Scripts\activate
# Linux/macOS
# source pytorch_venv/bin/activate
# 3. 粘貼并執(zhí)行從官網(wǎng)復(fù)制的命令。以下是一些示例:
# 示例 1: Pip, Linux/Windows, 只用 CPU
# pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
# 示例 2: Pip, Linux/Windows, 使用 CUDA 11.8
# pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
步驟 4: 驗(yàn)證安裝
安裝完成后,在你的終端(確保虛擬環(huán)境已激活)中啟動(dòng) Python 解釋器,然后輸入以下代碼:
import torch
# 1. 打印 PyTorch 版本
print(f"PyTorch Version: {torch.__version__}")
# 2. 檢查一個(gè)張量是否可以被創(chuàng)建
x = torch.rand(5, 3)
print(x)
# 3. (關(guān)鍵) 檢查 CUDA 是否可用
is_cuda_available = torch.cuda.is_available()
print(f"CUDA Available: {is_cuda_available}")
if is_cuda_available:
# 4. 打印 CUDA 版本
print(f"CUDA Version: {torch.version.cuda}")
# 5. 打印 GPU 數(shù)量
print(f"GPU Count: {torch.cuda.device_count()}")
# 6. 打印當(dāng)前 GPU 名稱(chēng)
print(f"GPU Name: {torch.cuda.get_device_name(0)}")
我的電腦是CPU處理器,顯示如下。
如果以上代碼都能順利運(yùn)行,并且 CUDA Available 的狀態(tài)符合你的預(yù)期,那么恭喜你,PyTorch 已經(jīng)成功安裝!
第二部分:PyTorch 基礎(chǔ)使用
現(xiàn)在我們來(lái)學(xué)習(xí) PyTorch 的核心組件。
1. 張量 (Tensors)
張量是 PyTorch 中最基本的數(shù)據(jù)結(jié)構(gòu),可以看作是多維數(shù)組。
import torch
import numpy as np
# --- 創(chuàng)建張量 ---
# 從 Python 列表創(chuàng)建
data = [[1, 2], [3, 4]]
x_data = torch.tensor(data)
print(f"Tensor from list:\n {x_data}\n")
# 從 NumPy 數(shù)組創(chuàng)建 (共享內(nèi)存,修改一個(gè)會(huì)影響另一個(gè))
np_array = np.array(data)
x_np = torch.from_numpy(np_array)
print(f"Tensor from NumPy:\n {x_np}\n")
# 創(chuàng)建一個(gè)全為1的張量,形狀與 x_data 相同
x_ones = torch.ones_like(x_data)
print(f"Ones Tensor:\n {x_ones}\n")
# 創(chuàng)建一個(gè)隨機(jī)張量,形狀與 x_data 相同,值在 [0, 1) 之間
x_rand = torch.rand_like(x_data, dtype=torch.float) # 重載數(shù)據(jù)類(lèi)型
print(f"Random Tensor:\n {x_rand}\n")
# 直接指定形狀創(chuàng)建
shape = (2, 3,)
rand_tensor = torch.rand(shape)
ones_tensor = torch.ones(shape)
zeros_tensor = torch.zeros(shape)
print(f"Random tensor of shape {shape}:\n {rand_tensor}\n")
# --- 張量屬性 ---
tensor = torch.rand(3, 4)
print(f"Shape of tensor: {tensor.shape}")
print(f"Datatype of tensor: {tensor.dtype}")
print(f"Device tensor is stored on: {tensor.device}") # 默認(rèn)是 'cpu'
# --- 將張量移動(dòng)到 GPU ---
# 只有在 CUDA 可用時(shí)才能成功
if torch.cuda.is_available():
tensor_gpu = tensor.to("cuda")
print(f"Device tensor is now stored on: {tensor_gpu.device}")
# --- 張量操作 ---
tensor = torch.ones(4, 4)
tensor[:, 1] = 0 # 類(lèi)似 NumPy 的索引和切片
print(f"Tensor after slicing:\n {tensor}\n")
# 拼接張量
t1 = torch.cat([tensor, tensor, tensor], dim=1) # 按列拼接
print(f"Concatenated tensor:\n {t1}\n")
# 算術(shù)運(yùn)算
# 矩陣乘法
mat_mul = tensor.matmul(tensor.T) # .T 是轉(zhuǎn)置
# 或者使用 @ 符號(hào)
mat_mul_alt = tensor @ tensor.T
print(f"Matrix multiplication:\n {mat_mul}\n")
# 元素級(jí)乘法
elem_mul = tensor.mul(tensor)
# 或者使用 * 符號(hào)
elem_mul_alt = tensor * tensor
print(f"Element-wise multiplication:\n {elem_mul}\n")
# 單元素張量轉(zhuǎn)為 Python 數(shù)值
agg = tensor.sum()
agg_item = agg.item()
print(f"Sum as a tensor: {agg}, Sum as a Python number: {agg_item}")
2. torch.autograd:自動(dòng)微分
這是 PyTorch 的魔力所在。當(dāng)你創(chuàng)建一個(gè)張量時(shí),可以設(shè)置 requires_grad=True 來(lái)追蹤對(duì)它的所有操作。完成計(jì)算后,你可以調(diào)用 .backward() 來(lái)自動(dòng)計(jì)算所有梯度。
# 創(chuàng)建需要計(jì)算梯度的張量 (例如模型的權(quán)重)
w = torch.randn(1, requires_grad=True)
b = torch.randn(1, requires_grad=True)
# 創(chuàng)建輸入數(shù)據(jù)張量 (不需要計(jì)算梯度)
x = torch.tensor([2.0])
# 定義一個(gè)簡(jiǎn)單的線性模型
y = w * x + b
# 假設(shè)真實(shí)值為 5.0,我們計(jì)算損失 (loss)
# 損失必須是一個(gè)標(biāo)量 (單個(gè)數(shù)值)
loss = (y - 5.0).pow(2)
print(f"w: {w.item()}, b: {b.item()}, y: {y.item()}, loss: {loss.item()}")
# --- 關(guān)鍵步驟:反向傳播 ---
loss.backward()
# --- 查看梯度 ---
# 梯度被累積在 .grad 屬性中
# d(loss)/dw
print(f"Gradient of w: {w.grad.item()}")
# d(loss)/db
print(f"Gradient of b: {b.grad.item()}")
# 在評(píng)估模型或進(jìn)行預(yù)測(cè)時(shí),我們不需要梯度,可以使用 torch.no_grad() 來(lái)停止追蹤,節(jié)省內(nèi)存和計(jì)算資源
with torch.no_grad():
y_pred = w * x + b
print(f"Prediction with no_grad: {y_pred.item()}")
# 在這個(gè)代碼塊內(nèi),所有計(jì)算都不會(huì)被追蹤
print(w.requires_grad) # 仍然是 True
print((w * x).requires_grad) # 但是新計(jì)算出的張量是 False
3. nn.Module:構(gòu)建神經(jīng)網(wǎng)絡(luò)
PyTorch 使用 torch.nn.Module 作為所有神經(jīng)網(wǎng)絡(luò)模型的基類(lèi)。構(gòu)建一個(gè)自定義模型通常需要:
- 創(chuàng)建一個(gè)繼承自 nn.Module 的類(lèi)。
- 在 __init__ 方法中定義網(wǎng)絡(luò)的層次結(jié)構(gòu)(如線性層、卷積層等)。
- 在 forward 方法中定義數(shù)據(jù)如何通過(guò)這些層進(jìn)行前向傳播。
from torch import nn
# 定義一個(gè)簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)
class SimpleNet(nn.Module):
def __init__(self):
super(SimpleNet, self).__init__()
# 定義網(wǎng)絡(luò)層
# 輸入維度為 10,第一個(gè)隱藏層維度為 32
self.layer1 = nn.Linear(10, 32)
# 激活函數(shù)
self.relu = nn.ReLU()
# 第二個(gè)隱藏層
self.layer2 = nn.Linear(32, 16)
# 輸出層,維度為 2 (例如,一個(gè)二分類(lèi)問(wèn)題)
self.output_layer = nn.Linear(16, 2)
def forward(self, x):
# 定義數(shù)據(jù)流
x = self.layer1(x)
x = self.relu(x)
x = self.layer2(x)
x = self.relu(x)
logits = self.output_layer(x)
return logits
# 實(shí)例化模型
model = SimpleNet()
print(model)
# 我們可以傳入一個(gè)符合輸入尺寸的隨機(jī)數(shù)據(jù)來(lái)測(cè)試
input_data = torch.randn(1, 10) # 1個(gè)樣本,10個(gè)特征
output = model(input_data)
print(f"\nModel output for random data:\n {output}")
4. 損失函數(shù) (Loss Functions) 和優(yōu)化器 (Optimizers)
- 損失函數(shù):衡量模型輸出與真實(shí)標(biāo)簽之間的差距。torch.nn 提供了多種常見(jiàn)的損失函數(shù),如 nn.MSELoss (均方誤差,用于回歸) 和 nn.CrossEntropyLoss (交叉熵?fù)p失,用于分類(lèi))。
- 優(yōu)化器:根據(jù)損失函數(shù)計(jì)算出的梯度來(lái)更新模型的參數(shù)(權(quán)重和偏置)。torch.optim 提供了多種優(yōu)化算法,如 SGD (隨機(jī)梯度下降) 和 Adam。
第三部分:一個(gè)完整的簡(jiǎn)單示例:線性回歸
讓我們把以上所有概念串聯(lián)起來(lái),完成一個(gè)最簡(jiǎn)單的機(jī)器學(xué)習(xí)任務(wù):線性回歸。我們的目標(biāo)是讓模型學(xué)習(xí)函數(shù) y = 3x + 2。
import torch
from torch import nn, optim
# 1. 準(zhǔn)備數(shù)據(jù)
# 創(chuàng)建一些帶有噪聲的樣本數(shù)據(jù)
X = torch.randn(100, 1) * 10 # 100個(gè)樣本,1個(gè)特征
y_true = 3 * X + 2 + torch.randn(100, 1) * 2 # 真實(shí) y = 3x + 2 + 噪聲
# 2. 定義模型
# 對(duì)于線性回歸,一個(gè)線性層就足夠了
# 輸入維度是1 (x),輸出維度也是1 (y)
model = nn.Linear(1, 1)
# 我們可以查看模型初始化的隨機(jī)參數(shù)
print(f"Initial weights: {model.weight.item()}")
print(f"Initial bias: {model.bias.item()}")
# 3. 定義損失函數(shù)和優(yōu)化器
loss_fn = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.001) # lr 是學(xué)習(xí)率
# 4. 訓(xùn)練循環(huán)
epochs = 100 # 訓(xùn)練輪數(shù)
for epoch in range(epochs):
# --- 前向傳播 ---
y_pred = model(X)
# --- 計(jì)算損失 ---
loss = loss_fn(y_pred, y_true)
# --- 反向傳播與優(yōu)化 ---
# 梯度清零 (非常重要!否則梯度會(huì)累積)
optimizer.zero_grad()
# 計(jì)算梯度
loss.backward()
# 更新參數(shù)
optimizer.step()
# 打印訓(xùn)練過(guò)程
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.4f}')
# 5. 查看訓(xùn)練結(jié)果
# 訓(xùn)練結(jié)束后,模型參數(shù)應(yīng)該接近 w=3, b=2
print("\n--- Training Finished ---")
print(f"Learned weights: {model.weight.item():.4f}")
print(f"Learned bias: {model.bias.item():.4f}")
# 使用模型進(jìn)行預(yù)測(cè)
new_x = torch.tensor([[10.0]])
predicted_y = model(new_x)
print(f"\nPrediction for x=10: {predicted_y.item():.4f} (True value should be around 3*10+2=32)")
Initial weights: -0.006330609321594238
Initial bias: 0.10331559181213379
Epoch [10/100], Loss: 33.0378
Epoch [20/100], Loss: 7.6095
Epoch [30/100], Loss: 6.9261
Epoch [40/100], Loss: 6.8030
Epoch [50/100], Loss: 6.6967
Epoch [60/100], Loss: 6.5947
Epoch [70/100], Loss: 6.4967
Epoch [80/100], Loss: 6.4025
Epoch [90/100], Loss: 6.3120
Epoch [100/100], Loss: 6.2250
--- Training Finished ---
Learned weights: 3.0174
Learned bias: 0.3916
Prediction for x=10: 30.5654 (True value should be around 3*10+2=32)
這個(gè)例子展示了 PyTorch 訓(xùn)練一個(gè)模型的核心流程:
定義模型 -> 定義損失和優(yōu)化器 -> 循環(huán)(前向傳播 -> 計(jì)算損失 -> 梯度清零 -> 反向傳播 -> 更新參數(shù))
第四部分:進(jìn)階學(xué)習(xí)建議
當(dāng)你掌握了以上基礎(chǔ)后,可以繼續(xù)探索以下內(nèi)容:
(1) Dataset和DataLoader:torch.utils.data中的這兩個(gè)類(lèi)是處理和加載大型數(shù)據(jù)集的標(biāo)準(zhǔn)工具,可以實(shí)現(xiàn)數(shù)據(jù)批處理 (batching)、打亂 (shuffling) 和并行加載。
(2) 更復(fù)雜的網(wǎng)絡(luò)結(jié)構(gòu):
- 卷積神經(jīng)網(wǎng)絡(luò) (CNNs):用于圖像處理,核心是 nn.Conv2d 和 nn.MaxPool2d。
- 循環(huán)神經(jīng)網(wǎng)絡(luò)(RNNs):用于序列數(shù)據(jù)(如文本、時(shí)間序列),核心是 nn.RNN,nn.LSTM,nn.GRU。
(3) 保存和加載模型:使用torch.save()保存模型的狀態(tài)字典(model.state_dict()),使用torch.load()和model.load_state_dict() 來(lái)加載。
(4) TorchVision, TorchAudio, TorchText:PyTorch 官方的擴(kuò)展庫(kù),提供了針對(duì)計(jì)算機(jī)視覺(jué)、音頻處理和自然語(yǔ)言處理的常用數(shù)據(jù)集、預(yù)訓(xùn)練模型和轉(zhuǎn)換工具。
(5) 官方教程:PyTorch 官網(wǎng)提供了大量高質(zhì)量的教程,從基礎(chǔ)到高級(jí)應(yīng)用應(yīng)有盡有,是最好的學(xué)習(xí)資源。