Appearance
张量 Tensor:一切数据的载体
张量(Tensor)是 PyTorch 中最基本的数据结构。模型参数是张量,输入数据是张量,中间计算结果还是张量。理解张量,重点是理解它的三要素:形状(shape)、数据类型(dtype)、设备(device)。
创建张量的 4 种方式
以下代码可在任意 Python 环境运行(终端执行 python 进入交互模式,或写入 .py 文件后 python 文件名.py):
python
import torch
# 1. 从 Python 列表创建
a = torch.tensor([[1.0, 2.0], [3.0, 4.0]])
# 2. 创建特殊值张量(调试和初始化常用)
zeros = torch.zeros(2, 3) # 全 0,形状 [2, 3]
ones = torch.ones(2, 3) # 全 1
rand = torch.rand(2, 3) # [0,1) 均匀分布随机数
seq = torch.arange(0, 10, 2) # [0, 2, 4, 6, 8]
# 3. 基于已有张量创建(自动继承 dtype 和 device,推荐)
b = torch.zeros_like(a) # 与 a 同形状同类型的全 0 张量
# 4. 从 NumPy 数组转换(打通科学计算生态)
import numpy as np
c = torch.from_numpy(np.array([1, 2, 3]))
back = c.numpy() # 转回 NumPy为什么推荐
zeros_like? 显式写torch.zeros(2, 3, dtype=torch.float32)时 dtype 容易和模型不匹配报错;*_like自动对齐,少踩一类坑。
张量三要素之一:shape(形状)
形状是深度学习代码的第一公民。 每个张量都有 shape,代表各维度上的大小:
python
x = torch.rand(32, 3, 28, 28)
print(x.shape) # torch.Size([32, 3, 28, 28])
print(x.dim()) # 4,维度数(也叫阶/rank)
print(x.numel()) # 802816,元素总数这个 [32, 3, 28, 28] 是图像批次的典型形状,读法是从外到内:
32 张图片 → 每张 3 通道(RGB) → 每通道 28 行 28 列像素
[ batch, channel, height, width ] # 简称 NCHW 格式而文本批次的典型形状是 [batch, 序列长度] 或 [batch, 序列长度, 词向量维度]。看到任何张量,先问自己每个维度代表什么,shape 想清楚了,代码就对了一大半。
改变形状的常用操作
python
x = torch.rand(32, 3, 28, 28)
# 展平:把后三个维度压成一维,常用于图像进入全连接层之前
flat = x.flatten(start_dim=1) # [32, 2352],batch 维保持不动
# reshape:任意重排(元素总数不变)
y = x.reshape(32, -1) # -1 表示自动推算,等价于上面的 flatten
# 交换/升/降维
t = x.permute(0, 2, 3, 1) # [32, 28, 28, 3],调整维度顺序
img = x[0] # 取下标,[3, 28, 28]——索引减少一维
img1 = x[0:1] # 取切片,[1, 3, 28, 28]——维度数不变!
uns = x.unsqueeze(1) # 在 1 号位插入一个 1 维:[32, 1, 3, 28, 28]坑预警:
x[0]与x[0:1]的区别。 前者形状降一维[3,28,28],后者保持[1,3,28,28]。需要保持 batch 维时(模型永远期望 batch 输入),用切片或unsqueeze(0)。单个样本推理报错,八成是这个。
view 与 reshape 的区别(面试高频)
view 要求张量内存连续,reshape 不连续时会先自动拷贝。日常建议:不确定就用 reshape;追求性能、明确连续时用 view。报错 view size is not compatible with input tensor's size 时,先 x.contiguous() 再 view,或直接换 reshape。
张量三要素之二:dtype(数据类型)
python
a = torch.tensor([1, 2, 3]) # int64
b = torch.tensor([1.0, 2.0, 3.0]) # float32(默认浮点类型)
c = b.to(torch.float16) # 半精度,训练大模型省显存常用
d = b.to(torch.bfloat16) # AI 领域主流半精度格式
a + b # 报错!dtype 不匹配,PyTorch 不会把 int 和 float 隐式混合运算深度学习里 95% 的参数张量是 float32(torch.float 是其别名),混合精度训练时才出现 float16/bfloat16。标签(分类任务的正确答案)通常是 int64(torch.long)——后面实战中损失函数对 dtype 的要求会再次强调这点。
转换写法:x.to(torch.float32) 或创建时指定 torch.zeros(2, 2, dtype=torch.float32)。
张量三要素之三:device(设备)
张量可以住在 CPU 也可以住在 GPU 上,两个张量运算前必须在同一设备上:
python
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
x = torch.rand(3, 3).to(device) # 搬到 GPU(没有 GPU 时这行无害)python
# 验证 GPU 是否可用,终端执行:
python -c "import torch; print(torch.cuda.is_available()); print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'CPU only')"坑预警: CPU 张量和 GPU 模型(或反之)相遇会报
Expected all tensors to be on the same device。规则很简单:模型和数据,一起.to(device)。另外把 GPU 张量转回 NumPy 前必须先.cpu()。
基础运算
python
a = torch.rand(2, 3)
b = torch.rand(2, 3)
print(a + b) # 逐元素加(广播规则同 NumPy)
print(a * b) # 逐元素乘
print(a @ b.T) # 矩阵乘(@ 运算符),[2,3]@[3,2] → [2,2]
print(torch.sigmoid(a)) # 激活函数等数学函数
print(a.max(), a.sum()) # 归约运算矩阵乘法 @ 的形状规则是排查网络报错的核心功夫:[m, k] @ [k, n] → [m, n],中间维度必须相等。全连接层本质就是矩阵乘,后面搭模型时会反复用到。
原地操作与内存
python
a.add_(1) # 带下划线后缀 = 原地修改 a 本身
a = a + 1 # 创建新张量训练循环中偶尔用原地操作提升性能,但对需要求梯度的张量做原地操作会报错(破坏了计算图)。新手阶段记住:拿不准就不用带 _ 的函数。
小结
| 要素 | 属性 | 为什么重要 |
|---|---|---|
| 形状 | .shape | 80% 的 bug 是形状问题;先想清每个维度含义 |
| 类型 | .dtype | 参数 float32、标签 int64,不匹配就报错 |
| 设备 | .device | 运算双方必须同设备;模型和数据一起 .to(device) |
下一篇我们看 PyTorch 真正的魔法:自动求导 Autograd。