1. 張量基礎:從數據到Pytorch的核心結構¶
在Pytorch中,張量(Tensor) 是存儲數據的基本結構,類似於NumPy的數組,但支持GPU加速和自動求導。理解張量是掌握Pytorch的第一步。
1.1 張量的創建¶
- 從列表/數值創建:直接用
torch.tensor()將Python列表轉換爲張量。
import torch
# 創建1維張量
x = torch.tensor([1, 2, 3])
print(x) # 輸出: tensor([1, 2, 3])
print(x.shape) # 輸出: torch.Size([3]) (形狀爲3)
- 從NumPy數組創建:通過
torch.from_numpy()將NumPy數組轉爲張量(反之用.numpy())。
import numpy as np
a = np.array([[1, 2], [3, 4]]) # NumPy數組
b = torch.from_numpy(a) # 轉爲Pytorch張量
print(b) # 輸出: tensor([[1, 2], [3, 4]], dtype=torch.int64)
- 用Pytorch內置函數創建:快速生成全0/全1/隨機張量。
# 2x3全0張量
zeros = torch.zeros(2, 3)
# 3x2全1張量
ones = torch.ones(3, 2)
# 1x4隨機數張量(均勻分佈)
rand = torch.rand(1, 4)
# 1x4隨機數張量(標準正態分佈)
randn = torch.randn(1, 4)
2. 張量維度變換:調整形狀的核心操作¶
在深度學習中,數據的維度(形狀)經常需要調整。Pytorch提供了多種工具實現維度變換,以下是最常用的操作:
2.1 reshape():靈活調整形狀¶
reshape(new_shape)可以將張量的形狀變爲new_shape,元素總數必須保持不變。
適用場景:無論原張量是否連續存儲,均可直接調整形狀(更安全)。
# 創建2x3的張量(6個元素)
x = torch.rand(2, 3)
print("原形狀:", x.shape) # 輸出: torch.Size([2, 3])
# 轉爲3x2形狀(元素總數6=3*2)
y = x.reshape(3, 2)
print("reshape後形狀:", y.shape) # 輸出: torch.Size([3, 2])
2.2 view():高效調整連續存儲的形狀¶
view(new_shape)與reshape()類似,但僅適用於原張量是連續存儲的情況(如未被transpose等操作破壞)。
適用場景:當張量是連續存儲時,view()比reshape()更快。
# 2x3的張量轉爲3x2(連續存儲時可用view)
x = torch.rand(2, 3)
y = x.view(3, 2) # 與reshape(3,2)效果相同
print(y.shape) # 輸出: torch.Size([3, 2])
2.3 squeeze():去掉維度大小爲1的維度¶
squeeze(dim=None)會移除所有維度大小爲1的維度,是“壓縮”操作。
若需指定移除某個維度,用dim=index。
# 原張量形狀: (1, 2, 1, 3)(多個維度爲1)
x = torch.rand(1, 2, 1, 3)
print("原形狀:", x.shape) # 輸出: torch.Size([1, 2, 1, 3])
# 去掉所有維度爲1的維度
y = x.squeeze()
print("squeeze後形狀:", y.shape) # 輸出: torch.Size([2, 3])
# 僅去掉第0維(大小爲1)
z = x.squeeze(0)
print("squeeze第0維後形狀:", z.shape) # 輸出: torch.Size([2, 1, 3])
2.4 unsqueeze():增加維度大小爲1的維度¶
unsqueeze(dim)會在指定位置插入一個維度大小爲1的新維度,是“擴展”操作。
適用場景:模型輸入需要固定維度時(如卷積層要求通道維度)。
# 原張量形狀: (2, 3)
x = torch.rand(2, 3)
print("原形狀:", x.shape) # 輸出: torch.Size([2, 3])
# 在第0維插入維度1(變爲1x2x3)
y = x.unsqueeze(0)
print("unsqueeze後形狀:", y.shape) # 輸出: torch.Size([1, 2, 3])
# 在第2維插入維度1(變爲2x3x1)
z = x.unsqueeze(2)
print("unsqueeze第2維後形狀:", z.shape) # 輸出: torch.Size([2, 3, 1])
2.5 transpose()與permute():交換維度¶
transpose(dim0, dim1):交換兩個維度,返回新張量。permute(dims):交換多個維度(參數爲維度索引元組),更靈活。
# 原張量形狀: (2, 3)
x = torch.rand(2, 3)
print("原形狀:", x.shape) # 輸出: torch.Size([2, 3])
# 交換第0維和第1維 → (3, 2)
y = x.transpose(0, 1)
print("transpose後形狀:", y.shape) # 輸出: torch.Size([3, 2])
# 原張量形狀: (1, 2, 3)
x = torch.rand(1, 2, 3)
# 交換維度順序爲 (2, 0, 1)
y = x.permute(2, 0, 1)
print("permute後形狀:", y.shape) # 輸出: torch.Size([3, 1, 2])
3. 張量常用操作:從運算到聚合¶
除了維度變換,張量還支持多種基礎運算和聚合操作,是模型計算的核心。
3.1 基礎算術運算¶
支持+、-、*、/等元素級運算,操作後形狀不變(除非觸發廣播)。
x = torch.tensor([1, 2, 3])
y = torch.tensor([4, 5, 6])
print("x + y:", x + y) # 輸出: tensor([5, 7, 9])
print("x * y:", x * y) # 輸出: tensor([4, 10, 18])
print("x / y:", x / y) # 輸出: tensor([0.2500, 0.4000, 0.5000])
3.2 矩陣乘法:matmul()¶
深度學習中常用矩陣乘法(而非元素級乘法),用matmul()實現。
# 2x3矩陣 × 3x4矩陣 → 2x4矩陣
x = torch.rand(2, 3)
y = torch.rand(3, 4)
z = torch.matmul(x, y)
print("matmul後形狀:", z.shape) # 輸出: torch.Size([2, 4])
3.3 廣播機制(Broadcasting)¶
當兩個張量維度不同但滿足條件時,Pytorch會自動擴展維度進行運算(類似NumPy的廣播)。
規則:維度從右向左對齊,大小爲1的維度會被擴展到匹配對方。
# 形狀(2,1) + 形狀(1,3) → 自動擴展爲(2,3)
a = torch.tensor([[1], [2]]) # 形狀(2,1)
b = torch.tensor([[3, 4, 5]]) # 形狀(1,3)
c = a + b
print("c的形狀:", c.shape) # 輸出: torch.Size([2, 3])
print("c的內容:\n", c)
# 結果:
# [[4, 5, 6],
# [5, 6, 7]]
3.4 聚合操作:sum()、mean()、max()¶
對張量按維度進行求和、均值、最大/最小值等統計,是模型計算損失的關鍵。
x = torch.tensor([[1, 2], [3, 4]])
print("總和:", x.sum()) # 輸出: 10(所有元素相加)
print("按行求和:", x.sum(dim=1)) # 輸出: tensor([3, 7])(每行相加)
print("均值:", x.mean()) # 輸出: 2.5(所有元素均值)
print("按列最大值:", x.max(dim=0)) # 輸出: (tensor([3, 4]), tensor([1, 1]))
4. 總結與練習¶
張量是Pytorch的核心,掌握維度變換和常用操作是構建模型的基礎。建議通過以下練習鞏固:
- 創建一個形狀爲(2, 2, 1)的張量,用
squeeze()去掉多餘維度,再用unsqueeze()恢復維度。 - 嘗試不同維度張量的加法,觀察廣播機制如何自動擴展維度。
- 用
permute()將(1, 2, 3)的張量變爲(3, 2, 1)。
通過實際操作,你會逐漸熟悉張量的“形狀語言”,爲後續學習神經網絡和深度學習模型打下堅實基礎!