PyTorch 张量(Tensor)(手把手讲解)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观
在深度学习与机器学习领域,PyTorch 作为主流框架之一,凭借其动态计算图和直观的 API 设计,成为开发者实现复杂模型的重要工具。而 PyTorch 张量(Tensor) 作为 PyTorch 的核心数据结构,几乎贯穿了从数据预处理到模型训练的每一个环节。无论是构建神经网络的权重矩阵,还是处理图像、文本等多维数据,张量的高效运算与灵活操作都是算法工程师必备的技能。本文将从基础概念、核心操作到实际应用,系统性地解析 PyTorch 张量的使用方法,并通过案例演示帮助读者快速掌握这一关键技术。
一、张量的基本概念与特点
1.1 张量的定义与类比
张量(Tensor)可以理解为多维数组的扩展。在数学中,标量(0维)、向量(1维)、矩阵(2维)都可以视为张量的特例。例如:
- 标量:一个数字(如
3.14
),对应 0 维张量; - 向量:一维数组(如
[1, 2, 3]
),对应 1 维张量; - 矩阵:二维表格(如
[[1, 2], [3, 4]]
),对应 2 维张量; - 高维张量:三维及以上的数组(如图像的 RGB 通道),对应 3 维或更高维度的张量。
类比日常生活中的物品,张量就像一个“多层抽屉”:每个抽屉的层数代表维度,而每个格子中的数字则是数据元素。例如,一个 3×3×3 的立方体张量可以想象为三层 3×3 的棋盘,每一层存储不同的数据。
1.2 张量与 NumPy 数组的异同
PyTorch 张量的设计灵感部分来源于 NumPy 的 ndarray
,但两者存在关键差异:
- 运行效率:张量支持 GPU 加速,而 NumPy 仅限于 CPU;
- 自动求导:张量可以追踪梯度,便于反向传播,这是 NumPy 所不具备的;
- 动态性:PyTorch 的计算图是动态的,适合需要灵活调整模型结构的场景。
特性 | PyTorch 张量 | NumPy 数组 |
---|---|---|
运行设备 | 支持 CPU/GPU | 仅 CPU |
自动微分 | 支持梯度计算 | 不支持 |
动态计算图 | 动态构建(如 torchscript ) | 无计算图概念 |
二、创建与初始化张量
2.1 直接创建张量
通过 torch.tensor()
函数可以直接从 Python 的列表或元组生成张量:
import torch
tensor_2x2 = torch.tensor([[1.0, 2.0], [3.0, 4.0]])
print(tensor_2x2)
2.2 通过工厂函数创建
PyTorch 提供了多种工厂函数(Factory Functions)来快速生成特定类型的张量:
- 全零/全一:
torch.zeros()
、torch.ones()
- 随机值:
torch.rand()
(均匀分布)、torch.randn()
(正态分布) - 自定义形状:通过
size
参数定义维度
zeros_tensor = torch.zeros(3, 4)
print(zeros_tensor.shape) # 输出:torch.Size([3, 4])
normal_tensor = torch.randn(2, 2)
print(normal_tensor)
2.3 从 NumPy 数组转换
通过 torch.from_numpy()
可以将 NumPy 数组转换为张量,反之亦然:
import numpy as np
numpy_array = np.array([[5, 6], [7, 8]])
tensor_from_numpy = torch.from_numpy(numpy_array)
print(tensor_from_numpy.dtype) # 输出:torch.int32
2.4 特殊初始化技巧
- eye() 函数:生成对角线为 1 的单位矩阵:
identity_matrix = torch.eye(3) # 3x3 单位矩阵
- arange() 函数:类似 Python 的
range()
,但返回张量:sequence_tensor = torch.arange(0, 10, 2) # 输出:tensor([0, 2, 4, 6, 8])
三、张量的属性与操作
3.1 基本属性
张量的形状(shape)、数据类型(dtype)和设备(device)是其核心属性:
tensor = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32)
print("形状:", tensor.shape) # 输出:torch.Size([2, 2])
print("数据类型:", tensor.dtype) # 输出:torch.float32
print("设备:", tensor.device) # 默认输出:cpu
3.2 索引与切片
张量的索引规则与 NumPy 类似,支持多维切片:
tensor = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
second_row = tensor[1, :] # 输出:tensor([4, 5, 6])
submatrix = tensor[:2, :2] # 输出:tensor([[1, 2], [4, 5]])
3.3 数学运算与广播机制
3.3.1 基础数学运算
a = torch.tensor([[1, 2], [3, 4]])
b = torch.tensor([[5, 6], [7, 8]])
print(a + b) # 输出:tensor([[ 6, 8], [10, 12]])
print(torch.mm(a, b)) # 输出:tensor([[19, 22], [43, 50]])
3.3.2 广播(Broadcasting)
广播机制允许不同形状的张量进行运算。例如,当两个张量的维度不同时,PyTorch 会自动扩展较小的张量,使其与较大张量形状匹配。
a = torch.tensor([[1, 2], [3, 4]]) # 形状 (2, 2)
b = torch.tensor([5, 6]) # 形状 (2,)
result = a + b
print(result)
广播规则的核心是:张量的最后一个维度需匹配,或其中一方的维度为 1。
四、高级张量操作与应用
4.1 张量的变形与重塑
view()
和 reshape()
方法用于改变张量的形状,但需满足元素总数不变的条件:
original = torch.tensor([[1, 2, 3], [4, 5, 6]]) # 形状 (2, 3)
flattened = original.view(6) # 变为 1 维张量
reshaped = original.reshape(3, 2) # 变为 3x2 矩阵
4.2 张量的拼接与分割
- 拼接:通过
torch.cat()
或torch.stack()
沿指定维度合并张量:a = torch.tensor([[1, 2], [3, 4]]) b = torch.tensor([[5, 6], [7, 8]]) concatenated = torch.cat((a, b), dim=0) # 沿行拼接,结果形状 (4, 2)
- 分割:使用
torch.split()
将张量按指定维度拆分:tensor = torch.arange(8).view(2, 4) split_tensors = torch.split(tensor, 2, dim=1) # 沿列分割为两个 2x2 张量
4.3 自动求导与梯度计算
张量的 requires_grad
属性控制是否追踪梯度,这是实现反向传播的基础:
x = torch.tensor(2.0, requires_grad=True)
y = x**2 + 3*x
y.backward()
print(x.grad) # 输出:tensor(7.) (导数为 2x + 3 = 7)
五、实战案例:线性回归模型中的张量应用
5.1 案例背景
假设我们希望用 PyTorch 实现一个简单的线性回归模型,预测输入 x
对应的输出 y
。模型公式为:
[ y = w \cdot x + b ]
其中,权重 w
和偏置 b
需要通过训练数据优化。
5.2 数据准备与张量构建
X = torch.tensor([1.0, 2.0, 3.0, 4.0], dtype=torch.float32)
y = torch.tensor([2.0, 4.0, 6.0, 8.0], dtype=torch.float32) # 真实值为 y = 2x
w = torch.tensor(0.0, requires_grad=True)
b = torch.tensor(0.0, requires_grad=True)
5.3 模型训练与梯度更新
learning_rate = 0.01
epochs = 100
for epoch in range(epochs):
# 前向传播
y_pred = w * X + b
loss = ((y_pred - y)**2).mean() # 均方误差损失
# 反向传播
loss.backward()
# 手动更新参数
with torch.no_grad():
w -= learning_rate * w.grad
b -= learning_rate * b.grad
w.grad.zero_() # 清空梯度
b.grad.zero_()
print(f"训练后参数:w={w.item():.2f}, b={b.item():.2f}")
六、总结与进阶方向
通过本文,我们系统学习了 PyTorch 张量的核心概念、创建方法、操作技巧及实际应用。从基础的形状控制到高级的自动求导,张量的灵活性与高效性使其成为深度学习开发的基石。对于进一步学习,建议读者探索以下方向:
- GPU 加速:通过
.cuda()
方法将张量迁移至 GPU; - 自定义张量操作:使用
@torch.jit.script
优化计算流程; - 高维数据处理:掌握图像(3维)、时序数据(3维)等场景下的张量操作。
掌握张量的使用,不仅是 PyTorch 开发的起点,更是理解深度学习框架底层逻辑的关键。希望本文能为读者提供清晰的入门路径,并激发进一步探索的兴趣。