在深度学习的世界里,张量(Tensor)是所有数据的载体,也是PyTorch框架的基石。无论你是刚接触Python的新手,还是熟悉C++、Java或Go的开发者,掌握张量操作都是迈向模型构建的第一步。本文将从零开始,系统讲解张量的创建、变形、索引、运算和广播机制,并用大量实例帮你避开常见陷阱。
一、张量是什么?为什么它如此重要?
张量本质上就是多维数组,但它比NumPy数组更强大——支持GPU加速和自动求导。你可以把它想象成“跑在GPU上的NumPy数组”。在PyTorch中,几乎所有数据(图像、文本、音频)和模型参数都以张量形式存在。
维度速查:标量是0维张量,向量是1维,矩阵是2维,彩色图像通常是4维(批次、通道、高、宽)。

很多新手一上来就写神经网络,却因为数据处理错误、形状不匹配、设备不一致而报错。根本原因就是张量操作不熟。本文将通过大量代码实例,带你系统掌握张量的核心操作,彻底告别形状错误。

二、创建张量的10种常用方法
首先导入PyTorch库:
import torch
import numpy as np
2.1 从数据直接创建
最直观的方式是从Python列表或NumPy数组创建张量:
# 从列表创建
a = torch.tensor([1, 2, 3])
b = torch.tensor([[1.0, 2.0], [3.0, 4.0]])
print(a, a.dtype) # torch.int64
print(b, b.dtype) # torch.float32
2.2 与NumPy互相转换
张量和NumPy数组共享内存,转换几乎零开销:
y([1, 2, 3]) t = torch.from_numpy(arr) # numpy -> tensor,共享内存 t2 = torch.tensor(arr) # 会复制一份 # tensor 转 numpy n = t.numpy() # 同样共享内存
注意: 创建出来的张量和原数组共享内存,修改其中一个,另一个也会变。 则是深拷贝。
2.3 创建特殊张量
初始化常用全零、全一、单位矩阵或随机张量:
zeros = torch.zeros(2, 3) # 全 0
ones = torch.ones(2, 3) # 全 1
eye = torch.eye(3) # 单位矩阵
rand = torch.rand(2, 3) # [0,1) 均匀分布
randn = torch.randn(2, 3) # 标准正态分布 N(0,1)
2.4 按范围创建
类似Python的range():
arange = torch.arange(0, 10, step=2) # tensor([0,2,4,6,8])
linspace = torch.linspace(0, 1, steps=5) # tensor([0.00, 0.25, 0.50, 0.75, 1.00])
2.5 创建同形状张量
保持形状不变,快速生成新张量:
x = torch.ones(2, 3)
y = torch.zeros_like(x) # 形状同 x,全 0
z = torch.randn_like(x) # 形状同 x,正态分布
2.6 指定数据类型和设备
⚠️ 重要:训练时务必统一dtype和device,否则会报RuntimeError:
f = torch.tensor([1, 2], dtype=torch.float32, device='cuda')

三、张量的基本属性
每个张量都自带以下属性,调试时非常有用:
t = torch.randn(2, 3, 4)
print(t.shape) # torch.Size([2, 3, 4])
print(t.size()) # 功能同上
print(t.dtype) # torch.float32
print(t.device) # cpu 或 cuda:0
print(t.ndim) # 维度数 3
print(t.numel()) # 元素总数 2*3*4=24
- shape:维度大小元组
- dtype:数据类型(如torch.float32)
- device:所在设备(CPU/GPU)
- ndim:维度数量
- numel:元素总数
四、张量索引与切片:和NumPy一模一样
索引方式完全遵循Python/NumPy规范,上手极快:
t = torch.arange(12).reshape(3, 4)
print(t)
# tensor([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])
# 取第 1 行
print(t[0]) # tensor([0, 1, 2, 3])
# 取第 1 列
print(t[:, 0]) # tensor([0, 4, 8])
# 区域切片
print(t[0:2, 1:3]) # 前 2 行,第 1-2 列
# 步长步取
print(t[::2, ::2]) # 每隔一行一列取一次
高级索引(Fancy Indexing)同样支持:
# 整数数组索引
idx = [0, 2]
print(t[idx]) # 取第 0 和第 2 行
# 布尔索引
mask = t > 5
print(t[mask]) # tensor([6, 7, 8, 9, 10, 11])
提示:如果你熟悉NumPy,这里几乎零学习成本。如果你更习惯C++或Java的数组操作,记住Python索引从0开始,且支持负索引。

五、张量变形:reshape、view、transpose、permute
变形是实际编码中出错最多的地方,务必牢记。
5.1 reshape vs view
x = torch.arange(12)
a = x.reshape(3, 4) # 安全,但可能复制
b = x.view(3, 4) # 必须内存连续,否则报错
c = x.contiguous().view(3, 4) # 保证内存连续后再 view
核心规则: 和 reshape 功能类似,但 view 要求张量内存连续,否则会报错;viewreshape 更保险,但在非连续时会复制一份,不共享数据。
5.2 增加/移除维度
x = torch.tensor([1, 2, 3]) # shape (3,)
print(x.unsqueeze(0)) # shape (1,3) 在第 0 维前加一维
print(x.unsqueeze(1)) # shape (3,1) 在第 1 维后加一维
y = torch.randn(1, 3, 1, 4)
print(y.squeeze()) # 移除所有大小为 1 的维度,变成 (3,4)
print(y.squeeze(0)) # 只移除第 0 维,若它等于 1
5.3 transpose 和 permute
t = torch.randn(2, 3, 4)
# 交换两维
t1 = t.transpose(0, 2) # shape (4,3,2)
# 多重转置用 permute
t2 = t.permute(2, 1, 0) # shape (4,3,2)
一次只能交换两个维度, 可以一次性对全部维度重新排列。
5.4 扩维广播:unsqueeze 与 expand
a = torch.tensor([[1], [2], [3]]) # shape (3,1)
b = a.expand(3, 4) # 广播成 (3,4),不复制数据
c = a.repeat(1, 4) # 实际复制数据成 (3,4)
性能建议: 只在需要时扩展,不分配新内存;expand 是真正复制,占用更多内存。repeat
六、张量的数学运算
6.1 基本运算
a = torch.tensor([1.0, 2.0])
b = torch.tensor([3.0, 4.0])
print(a + b) # 按元素加
print(a * b) # 按元素乘(不是矩阵乘法)
print(a @ b) # 点积
print(a.pow(2)) # 平方
print(a.sqrt()) # 开方
6.2 矩阵乘法
x = torch.randn(2, 3)
y = torch.randn(3, 4)
result = torch.mm(x, y) # 矩阵乘,结果 (2,4)
result = x @ y # 等价写法
# 对于批量矩阵乘用 torch.bmm 或 torch.matmul
6.3 聚合操作
t = torch.randn(3, 4)
print(t.sum()) # 所有元素和
print(t.sum(dim=0)) # 按行方向求和(压缩第 0 维),形状 (4,)
print(t.sum(dim=1, keepdim=True)) # 按列方向求和并保持维度,形状 (3,1)
print(t.mean(), t.max(), t.min())
print(t.argmax(dim=1)) # 每行最大值的索引
参数必须理解清楚: 就是把第 0 维压缩掉,你可以想象成“在这个方向上拍扁”。
七、广播机制(Broadcasting)
广播是PyTorch最重要的隐式操作之一,允许形状不同的张量运算时自动扩展。规则很简单:从最后一个维度向前对比,满足以下任一条件即可广播:
- 两个维度大小相等
- 其中一个维度是1
- 其中一个维度不存在

示例:
a = torch.randn(3, 1) # shape (3,1)
b = torch.randn(1, 4) # shape (1,4)
c = a + b # 广播成 (3,4)
❌ 常见错误:形状 与 (3,4) + (3,) 无法广播,因为最后一个维度4 vs 3不匹配。需要显式调整为 (3,) 或 (3,1)。(1,4)
八、张量在CPU与GPU间移动
x = torch.randn(3, 3)
if torch.cuda.is_available():
device = torch.device("cuda")
x_gpu = x.to(device) # 搬到 GPU
# 或者 x.cuda()
x_cpu = x_gpu.cpu() # 搬回 CPU
⚠️ 重要:模型和数据必须在同一设备上,否则报RuntimeError。如果你同时使用TypeScript或Go做后端服务,记得在推理前检查设备一致性。
九、张量与自动求导的初遇

张量通过 开启梯度追踪:requires_grad=True
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
y = x.pow(2).sum()
y.backward()
print(x.grad) # tensor([2., 4., 6.])
当对标量调用 时,所有路径上的梯度自动计算并累加到张量的 backward() 属性中。这是反向传播的核心机制。.grad
[AFFILIATE_SLOT_1]这也是后面要详细讲解的 autograd 机制,现在你只需要知道张量自带这个超级能力。
十、本讲总结与练习
今天我们全面拆解了张量的创建、索引、变形、运算和广播机制。掌握这些操作,你就拿到了玩转PyTorch的钥匙。与NumPy的相似性让你可以快速迁移经验,而GPU加速和自动求导则是PyTorch的独特优势。
试试做几个练习:
- 用
创建一个形状为torch.randn的张量,提取出第1、3行和第2、4列构成的子矩阵。(4, 5) - 实现一个形状为
的张量与形状为(3, 1)的向量相加,结果形状是什么?(4,) - 将上面创建的张量搬到GPU并验证device。
如果你平时主要用Python或NumPy,张量操作会非常自然;如果你来自C++、Java或Go背景,多写多练就能快速掌握。下篇我们将继续拆解PyTorch的核心组件,敬请期待!
from_numpytorch.tensor()transposepermutedimsum(dim=0)
浙公网安备 33010602011771号