PyTorch 张量(Tensor)(手把手讲解)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

截止目前, 星球 内专栏累计输出 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 张量的核心概念、创建方法、操作技巧及实际应用。从基础的形状控制到高级的自动求导,张量的灵活性与高效性使其成为深度学习开发的基石。对于进一步学习,建议读者探索以下方向:

  1. GPU 加速:通过 .cuda() 方法将张量迁移至 GPU;
  2. 自定义张量操作:使用 @torch.jit.script 优化计算流程;
  3. 高维数据处理:掌握图像(3维)、时序数据(3维)等场景下的张量操作。

掌握张量的使用,不仅是 PyTorch 开发的起点,更是理解深度学习框架底层逻辑的关键。希望本文能为读者提供清晰的入门路径,并激发进一步探索的兴趣。

最新发布