一、什麼是張量?¶
在PyTorch中,張量(Tensor) 是存儲和操作數據的基本單位,類似於NumPy中的數組,但支持GPU加速,並且是神經網絡計算的核心數據結構。你可以把張量想象成一個“容器”,裏面裝着數字(如整數、浮點數),並且可以對這個容器進行各種數學操作。
二、創建張量¶
要開始使用張量,首先需要學會創建它。PyTorch提供了多種方式創建張量,以下是最常用的幾種:
- 從Python列表/NumPy數組創建
使用torch.tensor()或torch.as_tensor()直接從數據創建:
import torch
import numpy as np
# 從列表創建
data_list = [1, 2, 3, 4]
tensor_list = torch.tensor(data_list) # 結果:tensor([1, 2, 3, 4])
# 從NumPy數組創建
np_array = np.array([1, 2, 3])
tensor_np = torch.as_tensor(np_array) # 結果:tensor([1, 2, 3])
- 使用構造函數創建
-torch.zeros(*size):創建全0張量,size是形狀元組(如(2, 3)表示2行3列)。
-torch.ones(*size):創建全1張量。
-torch.rand(*size):創建隨機數張量(元素在 [0, 1) 之間)。
zeros_tensor = torch.zeros(2, 3) # 2行3列全0
ones_tensor = torch.ones(1, 4) # 1行4列全1
rand_tensor = torch.rand(3, 3) # 3x3隨機數矩陣
三、張量的基本屬性¶
創建張量後,需要了解它的基本屬性以便後續操作:
- 形狀(shape):用 .shape 或 .size() 查看,返回一個元組。
- 數據類型(dtype):用 .dtype 查看,如 torch.float32(默認)、torch.int64 等。
- 設備(device):用 .device 查看,默認是CPU,可通過 .to('cuda') 轉移到GPU。
tensor = torch.rand(2, 3)
print(tensor.shape) # torch.Size([2, 3])
print(tensor.dtype) # torch.float32
print(tensor.device) # cpu
# 轉換數據類型和設備
tensor = tensor.to(torch.float64).to('cuda') # 先轉double類型,再移到GPU
四、張量操作¶
張量的操作是PyTorch的核心,掌握這些操作才能靈活處理數據。
1. 算術操作¶
張量支持常見的算術運算,如加減乘除、取反等:
- 加法:+ 或 torch.add()
- 減法:- 或 torch.sub()
- 乘法:* 或 torch.mul()(注意:矩陣乘法用 @ 或 torch.matmul())
- 除法:/ 或 torch.div()
a = torch.tensor([1, 2, 3])
b = torch.tensor([4, 5, 6])
# 加法
print(a + b) # tensor([5, 7, 9])
print(torch.add(a, b)) # 同上
# 矩陣乘法(示例:2x2 * 2x2)
a = torch.tensor([[1, 2], [3, 4]])
b = torch.tensor([[5, 6], [7, 8]])
print(a @ b) # tensor([[19, 22], [43, 50]])
2. 索引與切片¶
張量的索引和切片與Python列表類似,支持多維索引:
tensor = torch.tensor([[1, 2, 3], [4, 5, 6]])
# 取第一行(維度0)
print(tensor[0]) # tensor([1, 2, 3])
# 取第二列(維度1)
print(tensor[:, 1]) # tensor([2, 5])
# 取第1-2行、第0-1列
print(tensor[0:2, 0:2]) # tensor([[1, 2], [4, 5]])
3. 變形操作¶
用於調整張量的維度(保持元素總數不變):
- reshape():改變形狀,返回新張量(若形狀不合法則報錯)。
- squeeze():移除維度爲1的軸(如 (1, 3, 1) → (3,))。
- unsqueeze():增加維度爲1的軸(如 (3,) → (1, 3))。
tensor = torch.rand(1, 2, 1, 4) # 形狀:(1,2,1,4)
print(tensor.shape) # torch.Size([1, 2, 1, 4])
# 移除維度1的軸
squeezed = tensor.squeeze() # 形狀:(2, 4)
print(squeezed.shape) # torch.Size([2, 4])
# 增加維度爲1的軸(在維度1處插入)
unsqueezed = tensor.unsqueeze(1) # 形狀:(1,1,2,1,4)
print(unsqueezed.shape) # torch.Size([1, 1, 2, 1, 4])
4. 拼接與拆分¶
torch.cat():按指定維度拼接多個張量(需保持其他維度一致)。torch.stack():新增一個維度拼接(需所有維度一致)。torch.split()/torch.chunk():拆分張量爲多個部分。
a = torch.tensor([[1, 2], [3, 4]])
b = torch.tensor([[5, 6], [7, 8]])
# 按維度0拼接(上下合併)
cat_dim0 = torch.cat([a, b], dim=0) # 形狀:(4, 2)
print(cat_dim0)
# 按維度1拼接(左右合併)
cat_dim1 = torch.cat([a, b], dim=1) # 形狀:(2, 4)
print(cat_dim1)
# 拆分:按每個部分大小拆分爲2份
split_tensor = torch.cat([a, b], dim=0)
split_parts = torch.split(split_tensor, split_size_or_sections=2, dim=0)
print(split_parts) # (tensor([[1,2],[3,4]]), tensor([[5,6],[7,8]]))
五、自動求導(Autograd)¶
自動求導是PyTorch實現神經網絡反向傳播的核心,用於自動計算梯度。
1. 核心概念¶
requires_grad:張量屬性,設爲True表示需要追蹤其梯度。- 計算圖:記錄張量操作的計算流程,用於反向傳播時自動計算梯度。
backward():對計算圖中的葉子節點調用,觸發梯度計算。grad:張量的梯度屬性,僅對requires_grad=True的張量有效。
2. 自動求導示例¶
以簡單函數 y = x² 爲例,演示如何計算梯度:
# 創建需要求導的張量,requires_grad=True
x = torch.tensor(3.0, requires_grad=True) # x=3.0,需要追蹤梯度
# 構建計算圖:y = x²
y = x ** 2
# 反向傳播:計算梯度(y對x的導數)
y.backward()
# 查看梯度:x.grad = dy/dx = 2x = 6
print(x.grad) # tensor(6.)
3. 注意事項¶
- 非葉子節點梯度:中間變量(非原始張量)的梯度在
backward()後會被釋放,如需保留需用retain_graph=True。 - 累加梯度:多次調用
backward()時,梯度會累加,需手動清空(x.grad.zero_())。 detach():分離張量,阻止其繼續參與梯度計算(返回無梯度的新張量)。
x = torch.tensor(2.0, requires_grad=True)
y = x ** 2
z = y ** 2 # 計算圖:z = (x²)² = x⁴
# 先對y求導(此時x的梯度會被計算)
y.backward()
print(x.grad) # tensor(4.) (因爲dy/dx=2x=4,此時z未參與計算)
# 若要計算z對x的梯度,需重新反向傳播(需設置retain_graph=True保留計算圖)
z.backward(retain_graph=True)
print(x.grad) # tensor(16.) (4+12=16,因爲grad是累加的)
六、總結¶
- 張量是PyTorch數據的基本單位,支持多種創建方式和操作(算術、索引、變形等)。
- 自動求導通過
requires_grad和backward()實現梯度計算,是神經網絡訓練的核心。 - 實踐中需注意張量形狀匹配、梯度累加、設備轉移等細節,多動手嘗試不同操作才能熟練掌握。
通過以上內容,你已掌握PyTorch基礎的張量操作和自動求導,爲後續學習神經網絡打下基礎!