目錄
一、張量基本操作
1.1 執行代碼
?1.2 運行結果
1.3?代碼解析
?? 1. 創建張量(tensor、randn、zeros)
? 2. 索引與切片(類似 NumPy)
? 3. 形狀變換(reshape、轉置、壓縮)
? 4. 數學運算(逐元素 + 矩陣乘 + 求和)
? 5. 廣播機制(不同維度也能加)
? 6. 內存共享驗證(view 是原數據的視圖)
二、什么是張量(Tensor)
三、示例代碼中有哪些“張量”
四、小結一句話:
一、張量基本操作
1.1 執行代碼
#張量的基本操作import torch
# ==============================
# 1. 張量的基本操作
# ==============================
print("="*50)
print("1. 張量基本操作示例")
print("="*50)# 創建張量
x = torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.float32)
y = torch.randn(2, 3) # 正態分布隨機張量
z = torch.zeros(3, 2)
print(f"創建張量:\n x={x}\n y={y}\n z={z}")# 索引和切片
print("\n索引和切片:")
print("x[1, 2] =", x[1, 2].item()) # 獲取標量值
print("x[:, 1:] =\n", x[:, 1:])# 形狀變換
reshaped = x.view(3, 2) # 視圖操作(不復制數據)
transposed = x.t() # 轉置
squeezed = torch.randn(1, 3, 1).squeeze() # 壓縮維度
print(f"\n形狀變換:\n 重塑后: {reshaped.shape}\n 轉置后: {transposed.shape}\n 壓縮后: {squeezed.shape}")# 數學運算
add = x + y # 逐元素加法
matmul = x @ transposed # 矩陣乘法
sum_x = x.sum(dim=1) # 沿維度求和
print(f"\n數學運算:\n 加法:\n{add}\n 矩陣乘法:\n{matmul}\n 行和: {sum_x}")# 廣播機制
a = torch.tensor([1, 2, 3])
b = torch.tensor([[10], [20]])
print(a.shape)
print(b.shape)
print(f"\n廣播加法:\n{a + b}")# 內存共享驗證
view_tensor = x.view(6)
view_tensor[0] = 100
print("\n內存共享驗證(修改視圖影響原始張量):")
print(f"視圖: {view_tensor}\n原始: {x}")
?1.2 運行結果
==================================================
1. 張量基本操作示例
==================================================
創建張量:
?x=tensor([[1., 2., 3.],
? ? ? ? [4., 5., 6.]])
?y=tensor([[ 0.1558, -1.4728, ?0.0306],
? ? ? ? [ 0.8278, ?1.3076, ?0.5648]])
?z=tensor([[0., 0.],
? ? ? ? [0., 0.],
? ? ? ? [0., 0.]])索引和切片:
x[1, 2] = 6.0
x[:, 1:] =
?tensor([[2., 3.],
? ? ? ? [5., 6.]])形狀變換:
?重塑后: torch.Size([3, 2])
?轉置后: torch.Size([3, 2])
?壓縮后: torch.Size([3])數學運算:
?加法:
tensor([[1.1558, 0.5272, 3.0306],
? ? ? ? [4.8278, 6.3076, 6.5648]])
?矩陣乘法:
tensor([[14., 32.],
? ? ? ? [32., 77.]])廣播加法:
tensor([[11, 12, 13],
? ? ? ? [21, 22, 23]])內存共享驗證(修改視圖影響原始張量):
視圖: tensor([100., ? 2., ? 3., ? 4., ? 5., ? 6.])
原始: tensor([[100., ? 2., ? 3.],
? ? ? ? [ ?4., ? 5., ? 6.]])
1.3?代碼解析
?? 1. 創建張量(
tensor
、randn
、zeros
)x = torch.tensor([[1, 2, 3], [4, 5, 6]], dtype=torch.float32) y = torch.randn(2, 3) # 標準正態分布隨機數 z = torch.zeros(3, 2)
x
是一個 2行3列 的手動定義張量。
y
是一個 2x3 的 隨機張量,服從 N(0,1)。
z
是一個 3x2 的 全零張量。
? 2. 索引與切片(類似 NumPy)
x[1, 2].item() # 取第1行第2列的數,結果是 6.0 x[:, 1:] # 所有行,保留第1列以后(含1)
x[1, 2] = 6
,就是第2行第3列的元素;
x[:, 1:]
等價于:[[2, 3],[5, 6]]
? 3. 形狀變換(reshape、轉置、壓縮)
x.view(3, 2) # 重塑形狀為 3行2列(原數據數量不變) x.t() # 轉置(只支持二維):行變列、列變行 torch.randn(1, 3, 1).squeeze() # 刪除維度為1的維
.view()
是 PyTorch 的 reshape,不復制數據;變形后變成:
[[1, 2],[3, 4],[5, 6]]
🔑 核心規則:總元素數量不變(2×3 = 3×2 = 6),只是重新安排形狀。
.t()
是轉置:原來 2x3 → 3x2;用
.t()
進行轉置,行變列、列變行,結果是:[[1, 4],[2, 5],[3, 6]]
就像把矩陣繞主對角線翻了一下。
📌 注意:
.t()
只適用于二維張量;如果是三維或更高,需要用
.transpose(dim0, dim1)
。
.squeeze()
把 [1, 3, 1] 變成 [3],因為它刪除所有 維度=1 的軸。原始張量:
a = torch.randn(1, 3, 1) print(a.shape) # torch.Size([1, 3, 1])
這代表一個形狀是
[1, 3, 1]
的張量:它有 3 個元素,但加了兩個維度為 1 的“殼”:
第 1 個維度是 1(只有 1 個“通道”)
第 3 個維度是 1(每個值外面包了一層)
【為啥會有維度為1的“殼”?】
很多場景(圖像、批處理、模型輸出)為了格式統一,會多包幾層:
比如:
[Batch, Features, Channel]
即使某些維度大小為1,也會保留,以統一接口。
? 4. 數學運算(逐元素 + 矩陣乘 + 求和)
x + y # 對應位置相加(維度一樣) x @ x.t() # 矩陣乘法(2x3 與 3x2) x.sum(dim=1) # 每一行求和,返回 [6, 15]
x + y
是元素加(相同位置相加);x = [[1, 2, 3],[4, 5, 6]]y = [[0.1, 0.2, 0.3],[0.4, 0.5, 0.6]]x + y = [[1+0.1, 2+0.2, 3+0.3],[4+0.4, 5+0.5, 6+0.6]] = [[1.1, 2.2, 3.3],[4.4, 5.5, 6.6]]#最終結果 tensor([[1.1, 2.2, 3.3],[4.4, 5.5, 6.6]])
x @ x.T
是線性代數中的矩陣乘法;這表示:
注意:
@
表示矩陣乘法,不是逐元素乘法!x = [[1, 2, 3],[4, 5, 6]]x.t() = [[1, 4],[2, 5],[3, 6]]
計算過程
第一行 dot 第一列: 1×1 + 2×2 + 3×3 = 1 + 4 + 9 = 14第一行 dot 第二列: 1×4 + 2×5 + 3×6 = 4 + 10 + 18 = 32第二行 dot 第一列: 4×1 + 5×2 + 6×3 = 4 + 10 + 18 = 32第二行 dot 第二列: 4×4 + 5×5 + 6×6 = 16 + 25 + 36 = 77? 結果: x @ x.t() = [[14, 32],[32, 77]]
x.sum(dim=1)
結果是:x.sum(dim=1):每一行求和x = [[1, 2, 3],[4, 5, 6]]沿著“行的方向”(dim=1)求和:第一行:1 + 2 + 3 = 6第二行:4 + 5 + 6 = 15 [1+2+3, 4+5+6] → [6, 15]? 輸出: tensor([6, 15])
? 5. 廣播機制(不同維度也能加)
a = torch.tensor([1, 2, 3]) # shape: [3] b = torch.tensor([[10], [20]]) # shape: [2, 1] a + b
a.shape = [3]
b.shape = [2, 1]
通過廣播規則:
a
是一個長度為 3 的一維張量[1, 2, 3]
,形狀是[3]
b
是一個二維張量:[[10],[20]]
形狀是
[2, 1]
🔁廣播規則回顧(Broadcasting Rules)
從后往前比較維度(右對齊),滿足以下任一即可廣播:
維度相等 ?
其中一個維度為 1 ?
缺失維度視為 1 ?
記憶口訣:“廣播先對齊,缺1來撐齊,橫豎補成行列齊”
▲第一步:把
a
和b
的形狀寫完整!即把它們“補齊維度”,方便對齊:
張量 原始形狀 看作是二維矩陣 a [3]
[1, 3]
→ 橫向一排b [2, 1]
[2, 1]
→ 縱向兩列你可以這樣想象:
a = [1, 2, 3] → [[1, 2, 3]] ← 橫排,1行3列 b = [[10], [20]] → [[10], ← 豎排,2行1列[20]]
▲第二步:廣播機制讓它們形狀“變一樣”
原則是:當兩個張量維度不一致時,PyTorch 會嘗試擴展它們
我們來手動畫一下:
a 的形狀
[1, 3]
:[[1, 2, 3]]
想和 b 的
[2, 1]
相加,就會自動復制 2 行,變成:[[1, 2, 3],[1, 2, 3]] ← 廣播成 [2, 3]
b 的形狀
[2, 1]
:[[10],[20]]
要和
[2, 3]
相加,就會復制每行的 1 個值成 3 列,變成:[[10, 10, 10],[20, 20, 20]] ← 廣播成 [2, 3]
▲第三步:相加
兩個
[2, 3]
的矩陣對應位置相加:[[1+10, 2+10, 3+10], = [11, 12, 13][1+20, 2+20, 3+20]] = [21, 22, 23]
最終結果是:
廣播加法: tensor([[11, 12, 13],[21, 22, 23]])
? 6. 內存共享驗證(view 是原數據的視圖)
view_tensor = x.view(6) view_tensor[0] = 100 print(x)
x.view(6)
是將 x 展平成 1 維數組(6個元素);修改
view_tensor[0] = 100
,同時修改了原始 x 的第一個值;因為
.view()
是 共享內存的視圖,不是拷貝副本。原始張量 x 是: x = torch.tensor([[1, 2, 3],[4, 5, 6]]) 形狀是 (2, 3),也就是: 行 0: [1, 2, 3] 行 1: [4, 5, 6]
▲第一步:
view_tensor = x.view(6)
這一步是把
x
重塑成一個一維向量,有 6 個元素:view_tensor = [1, 2, 3, 4, 5, 6] # shape: [6]
?? 注意:不是復制數據!只是換了形狀!它和
x
共用同一塊內存。▲第二步:
view_tensor[0] = 100
修改了第一個元素,把原來的 1 改成了 100:
view_tensor = [100, 2, 3, 4, 5, 6]
因為它和
x
共享內存,所以x
的第一個元素(也就是x[0, 0]
)也被改了!▲第三步:
print(x)
現在
x
的原始矩陣變成了:x = [[100, 2, 3],[ 4, 5, 6]]
最終結果:
x = tensor([[100., 2., 3.],[4., 5., 6.]])
🔚 總結
🔚 內存共享與不共享對比圖
操作 功能 易錯點 .view()
重塑形狀 會共享內存,修改影響原張量 .t()
轉置 僅支持2D .squeeze()
去掉維度=1 的軸 常用于數據降維 +
元素加 維度不一樣時會廣播 @
矩陣乘法 對應線性代數矩陣運算
二、什么是張量(Tensor)
張量(Tensor)就是“任意維度的數值容器”,一維、二維、三維、甚至 N 維都可以。
在 PyTorch 中,所有通過 torch.tensor()
、torch.randn()
、torch.zeros()
、torch.view()
等操作得到的對象,都是張量。
張量就是一種 可以包含數字、并支持數學操作的多維數組。它是 PyTorch 的核心數據結構,類似于 NumPy 的 ndarray
,但支持自動求導、GPU 運算等。
🎯 更清晰地說:
維度 | 名稱 | 舉例 | PyTorch 類型 |
---|---|---|---|
0 維 | 標量 | 3.14 | 不是張量,float |
1 維 | 向量 | [1, 2, 3] | 張量(shape=[3] ) |
2 維 | 矩陣 | [[1, 2], [3, 4]] | 張量(shape=[2, 2] ) |
3 維 | 張量 | RGB圖像(3通道) | 張量(如 shape=[3, H, W] ) |
N 維 | 高維張量 | NLP中詞向量batch等 | 張量 |
? 所以說:
所有的矩陣、向量,乃至于多維數組,在 PyTorch 中都是張量。
早期數學/物理中張量的嚴格定義:
張量通常是二維或更高的數學對象
標量是 0階張量,向量是 1階張量,矩陣是 2階張量……
所以有時人們說“張量是多維結構”,把標量另算
但在 PyTorch / NumPy / 深度學習實際編程中:
所有數字類型(0維、1維、2維……)統一叫 張量
角度 標量是不是張量? 解釋 數學傳統 ? 不一定 有時專門分開談 PyTorch 實際編程 ? 是 torch.Size([])
代表 0維張量NumPy 一致行為 ? 是 np.array(3.14).ndim == 0
?? 但注意:不是“多維才是張量”
0維(只有一個數的情況)也是張量!
例子:
x = torch.tensor(7)
print(x.shape) # torch.Size([])
這是一個0維張量,只是你看不到形狀,它只有一個數字。
張量 = 標量(0維) + 向量(1維) + 矩陣(2維) + 多維數組(3維以上)
可以理解為:
“張量 = 包括所有維度的數組”
“維度越高,數據結構越復雜,但都是張量”
三、示例代碼中有哪些“張量”
變量名 | 是不是張量 | 來源 | 注釋說明 |
---|---|---|---|
x | ? 是 | torch.tensor(...) | 2x3 手動創建的浮點張量 |
y | ? 是 | torch.randn(...) | 2x3 正態分布隨機張量 |
z | ? 是 | torch.zeros(...) | 3x2 全 0 張量 |
x[1, 2] | ? 不是 | 張量的元素 | 是張量中的標量值(float),用 .item() 取出 |
x[:, 1:] | ? 是 | x 的切片 | 子張量,仍然是張量 |
reshaped | ? 是 | x.view(...) | 同一塊內存的不同形狀張量 |
transposed | ? 是 | x.t() | 轉置后張量(2x3 → 3x2) |
squeezed | ? 是 | squeeze() | 壓縮維度后的張量 |
add | ? 是 | x + y | 張量加法結果(形狀相同) |
matmul | ? 是 | x @ x.t() | 張量矩陣乘法結果 |
sum_x | ? 是 | x.sum(dim=1) | 每行求和后的張量(形狀為 [2] ) |
a | ? 是 | torch.tensor(...) | 一維張量,shape: [3] |
b | ? 是 | torch.tensor(...) | 二維張量,shape: [2, 1] |
a + b | ? 是 | 廣播相加后的結果 | shape: [2, 3] |
view_tensor | ? 是 | x.view(6) | 原張量的“扁平化視圖” |
view_tensor[0] | ? 不是 | 單個元素 | 張量里的一個標量,不再是張量本體 |
?
四、小結一句話:
只要是
torch.xxx(...)
創建出來的、或張量切片、變換、計算出來的結果,都是張量;
只有.item()
或[i][j]
取出的是具體數字(標量),不是張量。
?