张量是PyTorch中的核心数据抽象PyTorch中的张量就是元素为同一种数据类型的多维矩阵与NumPy数组类似。PyTorch中张量以类的形式封装起来对张量的一些运算、处理的方法数值计算、矩阵操作、自动求导被封装在类中。数据类型张量中默认的数据类型是float32(torch.FloatTensor)API1. 基本创建方式代码贴合代码解释补充要点torch.tensor([1,2,3], requires_gradTrue, dtypetorch.float)基于列表[1,2,3]创建张量开启梯度追踪指定数据类型为浮点型。推荐优先使用。支持自定义requires_grad、dtype自动推断数据类型可接收列表、numpy 数组。torch.Tensor([1,2])构造函数创建张量传入列表[1,2]默认生成浮点张量。大写 Tensor 是类构造器无法直接设置 requires_grad旧写法不推荐用于创建张量。torch.IntTensor([1,2])创建整型张量数据来源于列表[1,2]。固定数据类型为 int32不能直接配置梯度参数。torch.FloatTensor([1.,2.])创建浮点型张量数据来源于列表[1.,2.]。固定数据类型为 float32不能直接配置梯度参数。2. 线性序列张量代码贴合代码解释补充要点torch.arange(0, 10, 2)生成起始值 0、终止值 10左闭右开不包含 10、步长为 2 的序列张量结果[0,2,4,6,8]默认生成整型张量控制步长无法直接指定元素总个数torch.linspace(0, 1, 5)生成起始值 0、终止值 1包含两端、一共 5 个均匀分布数值的序列张量结果[0.0, 0.25, 0.5, 0.75, 1.0]默认浮点张量控制元素总数自动计算间隔大小3. 随机张量代码贴合代码解释补充要点torch.rand(2, 3)生成形状为[2,3]的张量数值服从均匀分布取值区间[0,1)。浮点型随机数常用于权重初始化、简单随机采样。torch.randn(4)生成形状为[4]的一维张量数值服从标准正态分布均值 0方差 1。深度学习最常用的初始化方式可生成正负随机值。torch.randint(0, 10, (2, 2))生成形状为[2,2]的整型张量随机整数区间[0,10)左闭右开。专门生成随机整数适合随机索引、离散采样场景。随机种子代码贴合代码解释补充要点torch.manual_seed(42)设置 CPU 随机数种子为 42固定随机生成序列保证每次运行随机结果保持一致实现实验可复现。只作用于 CPU若使用 GPU 还需要额外设置 cuda 种子种子数字 42 无特殊含义仅约定俗成。torch.initial_seed()获取当前 CPU 上正在使用的随机种子数值。可用于查看当前种子、保存种子方便后续复现实验。4. 固定值张量代码贴合代码解释补充要点torch.zeros((2, 3))创建形状为[2,3]的张量所有元素填充数值 0。需要手动指定尺寸默认浮点型。torch.zeros_like(data)参照张量data创建同形状、同数据类型的张量所有元素填充数值 0。自动继承data的 shape 与 dtype无需手动填写维度。torch.ones(4)创建形状为[4]的一维张量所有元素填充数值 1。手动定义目标形状。torch.ones_like(data)参照张量data创建同形状、同数据类型的张量所有元素填充数值 1。常用于生成和 data 规格一致的掩码矩阵。torch.full((2, 3), fill_value5)创建形状为[2,3]的张量全部元素统一填充数值 5。手动指定形状与填充值。torch.full_like(data, fill_value-2)参照张量data创建同形状、同数据类型的张量全部元素统一填充数值 - 2。填充值自由自定义通用性最强。5. 指定元素类型张量所有类型转换操作不会原地修改原张量需要接收返回值代码贴合代码解释补充要点data.type(torch.FloatTensor)将张量data转换为 FloatTensor 类型返回转换后的新张量。通过传入字符串形式指定目标张量类型属于旧版 API 写法推荐使用.to()或者.float()这类简写接口。data.half()将张量data转换为半精度浮点float16张量返回新张量。常用于混合精度训练减小显存占用。data.float()将张量data转换为单精度浮点float32张量返回新张量。深度学习最常用默认浮点类型。data.double()将张量data转换为双精度浮点float64张量返回新张量。精度高、占用显存大一般很少使用。data.int()将张量data转换为32 位整型int32张量返回新张量。用于普通整数标签、索引。data.long()将张量data转换为64 位长整型int64张量返回新张量。分类任务标签、索引取值必须使用 long 类型。6. 张量的类型转换代码贴合代码解释补充要点tensor.numpy().copy()先将 tensor 转为 numpy 数组再执行 copy () 生成独立副本。原 tensor 与 numpy 数组不再共享内存。不带 copy 时tensor.numpy()与张量共享内存带梯度张量直接调用.numpy()会报错需要先.detach()。torch.from_numpy(arr).copy()由 numpy 数组arr创建张量并且复制数据新张量和原 numpy 数组解除内存共享。torch.from_numpy(arr)默认共享内存加上.copy()切断共享一方修改不会影响另一方。torch.tensor(arr)接收 numpy 数组arr创建全新张量默认自动拷贝数据不与原数组共享内存。对比 from_numpy天生复制不存在共享内存问题。scalar.item()从标量张量 scalar 中取出普通 Python 数值int/float。仅能用于只有单个元素的标量张量常用于取出 loss 数值打印。7. 张量的数值运算7.1 基本运算代码贴合代码解释补充要点a.add(b)张量a与张量b逐元素相加返回新张量不修改原始 a。等价运算符a b。支持广播机制。a.add_(b)原地逐元素相加计算结果直接覆盖存入a修改原张量。带下划线_代表原地操作训练时尽量避免对需要求导的张量使用原地运算易引发梯度报错。a.sub(b)张量a与张量b逐元素相减返回新张量。等价运算符a - b。支持广播机制。a.sub_(b)原地逐元素相减直接覆盖修改张量a。原地操作。a.mul(b)张量a与张量b逐元素相乘哈达玛积返回新张量。等价运算符a * b。⚠️ 不是矩阵乘法矩阵乘法使用matmul/。a.mul_(b)原地逐元素相乘直接覆盖修改张量a。原地操作。a.div(b)张量a与张量b逐元素相除返回新张量。等价运算符a / b。除数不能包含 0否则产生 inf。a.div_(b)原地逐元素相除直接覆盖修改张量a。原地操作。a.neg()将张量a所有元素取相反数返回新张量不修改原张量。等价-a。逐元素符号翻转。a.neg_()原地对张量a所有元素取相反数直接修改自身。原地操作。7.2 点乘运算要求两个张量维度一致对应元素直接相乘或其他运算代码贴合代码解释补充要点t1.mul(t2)对t1与t2执行逐元素相乘哈达玛积返回新张量不修改原始t1。等价运算符t1 * t2要求两个张量形状满足广播规则不是矩阵乘法。t1.mul_(t2)带下划线代表原地操作将t1与t2逐元素相乘结果直接覆盖保存到t1自身无返回值。原地运算会直接修改原张量若t1开启requires_gradTrue尽量避免使用原地操作容易引发自动微分报错。7.3 矩阵乘法运算要求第一个矩阵 shape: (n, m)第二个矩阵 shape: (m, p), 两个矩阵点积运算 shape 为: (n, p)。代码贴合代码解释补充要点t1.matmul(t2)执行张量矩阵乘法将张量t1与t2做矩阵相乘运算。等价于t1 t2遵循矩阵乘法规则t1最后一维大小 t2倒数第二维大小支持高维张量批量矩阵乘法。8. 张量的运算函数代码贴合代码解释补充要点data.mean(dim0)在第 0 维按列求平均值压缩第 0 维。dim 指定要压缩、归约的维度输出维度减少一维。data.mean(dim1)在第 1 维按行求平均值压缩第 1 维。若需要保留被压缩的维度可添加参数keepdimTrue。data.mean()不指定维度对张量全部元素求全局平均值输出标量张量。等价于把所有元素摊平后求均值。data.sum(dim1)在第 1 维上求和压缩第 1 维。深度学习常用于损失求和、特征聚合。data.min(dim1)在第 1 维求取最小值返回(最小值张量最小值索引张量)。返回两个值和 mean/sum 行为不同。data.max(dim1)在第 1 维求取最大值返回(最大值张量最大值索引张量)。常用于分类任务获取预测类别。data.pow(2)逐元素进行幂运算data.pow(2)等价于data**2data.sqrt()逐元素计算平方根等价于 .pow (0.5) 或 data ** 0.5。输入负数会产生 nan。data.exp()逐元素计算自然指数 ex。激活函数、概率转换常用。data.log()逐元素计算自然对数 ln(x)。输入必须大于 0负数值会产生 nan。9. 张量的索引操作索引取出的数据如果是切片 / 基础下标和原张量共享内存原地修改会互相影响。9.1 简单行列索引data[行索引, 列索引]代码data 为张量解释data[0]选取第 0 行取出一整行数据data[:, 0]选取全部行、第 0 列取出一整列数据9.2 列表索引代码data 为张量解释data[[0, 1], [1, 2]]多维配对索引。行索引列表[0,1]与列索引列表[1,2]一一对应依次取出坐标(0,1)、(1,2)两个元素。data[[[0],[1]], [1, 2]]广播机制下的多维索引。行维度[[0],[1]]、列维度[1,2]广播配对取出坐标(0,1),(0,2),(1,1),(1,2)最终结果形状为[2,2]。9.3 范围索引代码data 为张量解释data[:3, :2]范围切片索引选取前 3 行0、1、2 行、前 2 列0、1 列左闭右开区间data[2:, :2]范围切片索引选取第 2 行及之后所有行、前 2 列0、1 列9.4 布尔索引代码data 为张量解释data[data[:, 2] 5]布尔索引先取出全部行第 2 列构成一维张量筛选其中数值大于 5 对应的整行数据。data[:, data[1] 5]布尔索引先取出第 1 行构成一维张量筛选其中数值大于 5 对应的整列数据。9.5 多维索引​​​代码data 为三维张量解释data[0, :, :]选取第 0 维度下标为 0 的全部数据取出第 0 个切片data[:, 0, :]选取全部第 0 维度、第 1 维度下标为 0 的全部数据取出每个切片的第 0 行data[:, :, 0]选取全部第 0 维度、全部第 1 维度、第 2 维度下标为 0 的数据取出每个切片的第 0 列10. 张量的形状操作张量形状操作是指对张量的维度进行变换的一系列操作。张量的形状则描述了每个维度上的元素数量。代码data 为张量解释补充要点data.shape获取当前张量各个维度的尺寸大小等价data.size()data.shape[0]读取第 0 维长度data.reshape(1, 6)将张量重塑为[1,6]的二维形状元素总数量不变可使用-1自动计算维度不强制要求张量内存连续data.unsqueeze(0)在第 0 维插入一个长度为 1 的新维度实现升维unsqueeze(-1)代表在最后一维新增维度data.squeeze()自动移除张量中所有长度等于 1的维度若传入维度编号则只移除指定维度上 size1 的轴不会删除长度大于 1 的维度data.transpose(0, -1)交换第 0 维和最后一维两个维度的位置仅支持两个维度互换适合二维转置仅允许传入两个维度参数data.permute(2, 0, 1)把原维度顺序(0,1,2)重排为(2,0,1)一次性完成多维度调换支持任意多个维度重排常用于[B,C,H,W]通道变换data.view(3, 2)将张量重塑为[3,2]形状元素总数保持不变要求张量内存连续非连续张量直接调用会报错支持-1推导维度data.contiguous()复制数据生成一份内存连续排布的新张量transpose、permute 操作后张量常不连续view 前常用data.is_contiguous()检测张量在内存中是否连续存储返回True/False用来判断是否需要调用 contiguous11. 张量的拼接操作代码贴合代码解释补充要点torch.cat([data1, data2], dim1)将张量data1、data2沿着第 1 维拼接不新增维度只扩展该维度长度。参与拼接的张量除 dim 指定维度外其余维度尺寸必须完全一致torch.stack([data1, data2], dim1)将张量data1、data2沿着第 1 维堆叠会新增一个维度把两个张量嵌入新维度中。参与堆叠的所有张量形状必须完全相同12. 自动微分模块自动微分自动求导梯度。梯度 函数求导对函数求导得到的值就是梯度在数值上的理解梯度就是上山下山最快的方向在方向上理解)在平面内梯度就是某一点上的斜率反向传播传播的是梯度反向传播利用链式法则不断的从后向前求导求出来的值就是梯度所以大家都经常说反向传播传播的是梯度链式法则中梯度相乘就是传说中的梯度传播梯度下降法是一种求最优梯度值的方法使得损失函数的值最小训练神经网络时最常用的算法就是反向传播。在该算法中参数模型权重会根据损失函数关于对应参数的梯度进行调整。为了计算这些梯度PyTorch内置了名为 torch.autograd 的微分模块。它支持任意计算图的自动梯度计算代码贴合代码解释补充要点loss.sum().backward()先对 loss 张量求和转为标量再启动反向传播自动计算计算图中所有可求导参数的梯度并存入.gradbackward () 只能对标量直接调用多维损失需要先聚合为标量w.grad读取标量张量w反向传播后计算得到的梯度张量未执行反向传播时为 None梯度会累加多次 backward 不清除会叠加结果w.grad.zero_()原地清零参数w已存储的梯度避免多次迭代梯度持续累积带下划线_代表原地操作训练循环每轮一般都需要执行data.requires_grad布尔属性查看张量data是否开启梯度追踪、参与构建计算图True参与求导False不计算梯度节省显存data.detach().numpy()detach()切断张量与计算图的梯度关联再转为 numpy 数组脱离梯度图后才能顺利转 numpy直接对带梯度张量调用.numpy()会报错必须先 detach模拟权重更新过程 循环更新梯度模拟梯度下降过程 import torch # 1. 准备w w torch.tensor(10, requires_gradTrue, dtypetorch.float) # 2. 准备loss loss w ** 2 40 # 3. 梯度下降循环100次求最优解 print(f初始权重为{w}, 权重更新公式w w - 0.01 * w.grad, 初始梯度无, 初始loss为{loss}\n) for i in range(100): # 3.1 正向计算前向转播 loss w ** 2 40 # 3.2 梯度清零否则会累加 # 第1次的时候w.grad None所以会报错 if w.grad is not None: w.grad.zero_() # 3.3 反向传播 loss.sum().backward() # 3.4 更新权重 w.data w.data - 0.01 * w.grad # 3.5 打印结果 print(f第{i 1}次迭代权重为{w:.2f}, 梯度为{w.grad:.2f}, loss为{loss:.2f}) # 4. 输出结果 print(f\n最终结果 权重为{w}, loss为{loss})