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的核心,掌握維度變換和常用操作是構建模型的基礎。建議通過以下練習鞏固:

  1. 創建一個形狀爲(2, 2, 1)的張量,用squeeze()去掉多餘維度,再用unsqueeze()恢復維度。
  2. 嘗試不同維度張量的加法,觀察廣播機制如何自動擴展維度。
  3. permute()將(1, 2, 3)的張量變爲(3, 2, 1)。

通過實際操作,你會逐漸熟悉張量的“形狀語言”,爲後續學習神經網絡和深度學習模型打下堅實基礎!

小夜