
很多初学者学 PyTorch 的第一周通常是这样度过的先看几段教学视频再复制一份别人写好的模型代码好不容易跑通 MNIST然后一到自己改模型、写数据预处理、调维度就开始疯狂报错。错误信息五花八门但总结起来往往只有一个核心问题——没搞懂 Tensor。Tensor 这个词听起来很像「数组」但它背后牵扯到的 shape、dtype、device、自动求导、内存共享任何一个概念不清楚都会在后续写训练循环、跑 GPU 推理时反复被坑。这篇文章是 2026 最新 PyTorch 教程的第 1 课目标很明确不铺开讲太多只把 Tensor 这一块真正讲透。读完你可以做到三件事用多种方式创建 Tensor看懂 Tensor 的核心属性和内存行为熟练完成维度变换、拼接、归约等基本操作。文中所有代码都基于 PyTorch 2.x 的稳定接口你手上如果是近期安装的新版本也可以直接运行。1. 这篇文章真正要解决的问题先泼一盆冷水如果你打算跳过 Tensor直接去啃 Transformer、YOLO 或者 LSTM 的源码后面大概率会卡在某一行的view、permute或者contiguous上然后回头补课。与其这样不如一开始就把这块地基打牢。具体来说这节教程要解决三个层面的问题。第一创建层面的困惑。很多新手分不清torch.tensor()和torch.Tensor()有什么区别不知道什么时候该用torch.zeros什么时候该用torch.full更不知道从 NumPy 转过来的数组到底是共享内存还是拷贝了一份。这些问题不搞清楚代码偶尔能跑但换一个场景就出错。第二属性层面的盲区。Tensor 不只是有数值还有shape、dtype、device、requires_grad这些关键属性。其中任何一个不匹配都会让你的训练代码直接崩溃。比如最常见的Expected all tensors to be on the same device本质就是device属性没有统一。第三操作层面的混乱。矩阵乘法用*还是view和reshape能不能混用cat和stack区别在哪这些都是新手高频问题也会在这篇文章里逐一说明。所以这篇文章适合三类读者刚开始学 PyTorch 的纯新手会写 Python 但没接触过深度学习的转行开发者以及已经能跑通示例代码、但想系统整理一遍 Tensor 用法的进阶学习者。2. 什么是 Tensor先建立一个正确的直觉Tensor 最朴素的解释是「一个多维数组容器」。0 维是一个标量1 维是一条向量2 维是矩阵3 维通常代表一批向量或者单个序列4 维则常见于批量图像数据。例如一批 64 张、大小 224x224 的 RGB 彩色图片在 PyTorch 中的表示方式通常是[64, 3, 224, 224]这就是一个 4 维 Tensor。但 Tensor 和普通数组最重要的区别并不仅仅是「维度更多」而是它天生为深度学习设计具备三个关键能力能力说明对应的开发场景设备无关数据可以放在 CPU也可以放在 GPU模型训练时把数据搬到显卡自动求导记录计算图自动计算梯度反向传播更新模型参数生态集成与nn.Module、DataLoader等模块无缝配合构建网络、批量加载数据这引出一个很多人忽略的判断PyTorch 之所以在教学和科研中越来越流行除了 API 设计贴近 Python 直觉之外更关键的是它把「数据表示」「计算设备」「自动微分」这三件事整合在一个对象里。你不需要手动管理 GPU 内存也不需要自己实现反向传播前提是你要理解 Tensor 在这些环节里扮演的角色。2.1 从 NumPy 到 Tensor差别不是换个名字用 NumPy 写过机器学习代码的读者可能会觉得 Tensor 和ndarray差不多。确实二者在索引、切片、广播等操作上非常接近但 PyTorch Tensor 增加了两个 NumPy 没有的核心能力GPU 加速和自动求导。如果说 NumPy 是「面向科学计算的数组」那 Tensor 就是「面向深度学习训练与推理的数组」。它保留了数组的灵活性额外加上了device和requires_grad这两个属性让数据可以在 GPU 上计算并且自动被计算图追踪。这意味着你在写训练代码时只需要把数据包装成 TensorPyTorch 会自动记录每个操作反向传播时调用loss.backward()就能得到梯度。理解这一点是整个深度学习框架的核心心智模型。3. 环境准备版本选择与常见安装问题先说结论Tensor 核心 API 非常稳定不建议为了追求新版本反复折腾环境。标题里写「2026 最新」指的并不是某个特定的新 API而是这套教程面向当前主流的学习起点以 PyTorch 2.x 为基础编写。3.1 Python 环境与 PyTorch 安装建议使用 Python 3.9 及以上的版本。如果从零开始推荐用 Anaconda 创建独立虚拟环境避免把系统 Python 环境搞乱。# 创建虚拟环境建议按 Python 3.10 或 3.11 创建 conda create -n pytorch_lesson python3.10 -y conda activate pytorch_lesson接下来安装 PyTorch。CPU 版本可以直接用 pip 安装GPU 版本需要先确认本机显卡和驱动情况。最稳妥的方式是打开 PyTorch 官网的安装页选择你的操作系统、包管理方式和 CUDA 版本复制对应的命令。一个常见的通用命令是pip install torch torchvision torchaudio如果下载速度较慢可以临时指定国内镜像源pip install torch torchvision torchaudio -i https://pypi.tuna.tsinghua.edu.cn/simple这里有一个容易踩坑的地方不要凭印象选择 CUDA 版本。安装 GPU 版之前先运行nvidia-smi查看显卡驱动支持的 CUDA 版本再选择不超过这个版本的 PyTorch 构建。如果驱动不支持即使装上也会在运行时提示 CUDA 不可用最后只能退回 CPU 模式。AMD 显卡用户更要注意PyTorch 的 GPU 支持主要面向 NVIDIA CUDAAMD 显卡的方案需要查看官方是否提供对应的 ROCm 构建以及是否支持你的具体型号。入门阶段如果不想在环境上花费太多时间先用 CPU 版本跑通学习流程反而是更高效的选择。3.2 验证环境是否可用安装完成后可以运行下面这段小代码确认 PyTorch 是否正常import torch print(PyTorch 版本:, torch.__version__) print(CUDA 是否可用:, torch.cuda.is_available())预期输出中的torch.__version__会显示版本号。torch.cuda.is_available()若为True说明 GPU 环境可用如果为False则说明当前是 CPU 版本或者驱动/CUDA 配置不匹配。这个结果决定了后面示例代码在什么设备上运行。4. 创建 Tensor 的常用方式Tensor 的创建方式非常多样很多教程会一口气列十几种 API但对你来说更重要的是知道每种方式适合什么场景。这里按用途分类讲解。4.1 从列表或 NumPy 数组创建最直接的方式是从 Python 列表创建import torch # 从列表创建一维 Tensor a torch.tensor([1, 2, 3]) print(a) # 从嵌套列表创建二维 Tensor b torch.tensor([[1, 2], [3, 4]]) print(b) # 创建标量0 维 Tensor c torch.tensor(3.14) print(c, c.shape)这里需要特别注意大小写问题。torch.tensor()是小写函数负责把现有数据包装成 Tensor。而torch.Tensor()是类构造器它默认创建的是空的或未初始化的 FloatTensor并不推荐直接用它来转换数据。新手最常见的错误之一就是用torch.Tensor([1, 2, 3])这种写法它通常也能运行但语义并不清晰默认的 dtype 也容易产生误解。从 NumPy 数组转换时有两个常见选择import numpy as np arr np.array([1, 2, 3]) # 方式一torch.from_numpy与 NumPy 数组共享内存 t1 torch.from_numpy(arr) # 方式二torch.tensor默认拷贝数据 t2 torch.tensor(arr)torch.from_numpy()不会复制数据修改 Tensor 会同步修改原 NumPy 数组。这个特性在节省内存时很有用但如果你想保留原始数据就需要用torch.tensor()做一次拷贝。实际项目中取舍标准很简单数据要不要被后续操作改变。4.2 用固定值或模板创建深度学习中经常需要初始化全零向量、全一矩阵或单位矩阵# 全零张量 z torch.zeros(3, 4) # 全一张量 o torch.ones(2, 3) # 单位矩阵 e torch.eye(3) # 填充固定值 f torch.full((2, 2), 7.0) print(zeros:, z.shape) print(ones:, o.shape) print(eye:\n, e) print(full:\n, f)这段代码中torch.zeros(3, 4)创建了一个 3 行 4 列、全部为 0 的二维 Tensortorch.full((2, 2), 7.0)创建一个 2x2 且所有元素都是 7.0 的 Tensor。torch.eye(3)常用于构造单位矩阵在实现某些线性变换时非常方便。另外一个实用的系列是zeros_like和ones_like它们会保持与输入 Tensor 相同的形状。当你想快速生成一份和某个特征张量形状一致、但值不同的数据时比手动传 shape 更不容易出错。4.3 按序列创建生成等差数列或线性等分向量在构造时间步、坐标轴数据时很常用# 从 0 到 9步长为 1 ar torch.arange(0, 10, 1) # 从 0 到 1均匀分成 5 个点 lin torch.linspace(0, 1, steps5) print(arange:, ar) print(linspace:, lin)torch.arange的语义和 Python 内置的range类似结束位置不包含torch.linspace则会在指定区间内生成包含两端点的steps个等距数值。如果要生成整数序列作为索引优先用arange如果要生成用于归一化坐标的浮点数序列优先用linspace。4.4 随机创建模型参数的初始化、数据增强、随机采样都离不开随机 Tensor# 均匀分布 [0, 1) r torch.rand(3, 3) # 标准正态分布 rn torch.randn(3, 3) # 随机整数 ri torch.randint(0, 10, (3, 3)) print(rand:\n, r) print(randn:\n, rn) print(randint:\n, ri)这里容易误解的是torch.rand和torch.randn的区别。torch.rand生成的是 0 到 1 之间的均匀分布随机数适合做 dropout 掩码或归一化数据torch.randn生成的是均值为 0、方差为 1 的标准正态分布随机数更接近神经网络权重的常见初始化分布。两者虽然只差一个字母但用途完全不同。5. Tensor 的核心属性创建出 Tensor 之后下一步是学会读懂它。调试模型时最重要的能力就是快速判断一个 Tensor 的shape、dtype、device和requires_grad。5.1 关键属性一览import torch x torch.randn(2, 3, 4) print(shape:, x.shape) print(size():, x.size()) print(维度数:, x.dim(), x.ndim) print(元素总数:, x.numel()) print(数据类型:, x.dtype) print(所在设备:, x.device) print(是否需要梯度:, x.requires_grad)这里需要特别澄清几个容易混淆的概念。第一shape和size()完全等价返回的都是torch.Size对象表示各维度大小。numel()返回元素总数也就是各个维度大小的乘积。第二dtype决定了每个元素占多少内存、怎么解释。浮点张量常用torch.float32默认情况下torch.randn创建的是torch.float32张量整数张量默认是torch.int64。深度学习中如果不做特殊处理一般建议统一使用torch.float32避免 CPU 和 GPU 之间因为类型不一致产生转换报错。第三device表示数据存放在 CPU 还是 GPU。CPU 上的 Tensor 和 GPU 上的 Tensor 不能直接参与同一个运算这是新手最常见的报错来源之一。第四requires_grad表示该 Tensor 是否被计算图追踪。默认是False但如果你给一个 Tensor 设置requires_gradTrue之后所有对这个 Tensor 的操作都会被记录下来用于后续自动求导。模型权重默认就是需要梯度的而输入数据和标签通常不需要。5.2 从 0 维到高维的理解在 PyTorch 中0维 Tensor 是一个标量但它和 Python 里的普通数字不同它本身仍然是 Tensor 对象。实际取值时需要调用.item()s torch.tensor(3.14) print(0维 Tensor:, s) print(shape:, s.shape) print(取 Python 数值:, s.item())这个细节在写损失函数时很常见。比如loss本身通常是一个 0 维 Tensor如果直接拿到 Python 里做比较需要loss.item()或float(loss)。如果不取出来它一直保留在计算图中可能导致显存累积。5.3 Tensor 属性汇总属性作用典型示例shape/size()描述各维度大小torch.Size([2, 3, 4])dim()/ndim返回维度数量2 维 Tensor 返回 2dtype元素数据类型torch.float32device数据所在设备cuda:0或cpurequires_grad是否被自动求导追踪True/Falsenumel()元素总数24item()0 维 Tensor 转 Python 数值3.14在实际调试中你最该养成的习惯是每创建一个 Tensor先明确它的shape、dtype、device三个属性。这三个维度匹配了大概率不会出现底层报错。6. Tensor 的基本操作Tensor 操作通常可以分成几个大类算术运算、矩阵乘法、维度变换、拼接拆分、归约统计。下面重点讲最容易出错的部分。6.1 算术运算与广播机制加减乘除和 Python 数值运算看起来一致但注意在深度学习中大多数同名运算符都是逐元素操作a torch.tensor([1, 2, 3]) b torch.tensor([4, 5, 6]) print(加法:, a b) print(逐元素乘法:, a * b) print(幂运算:, a ** 2)a * b的结果是[4, 10, 18]这是逐元素相乘不是矩阵乘法。这一点新手经常混。广播机制是指两个形状不完全相同的 Tensor 在运算时PyTorch 会自动扩展维度。例如a torch.tensor([[1, 2, 3], [4, 5, 6]]) # shape [2, 3] b torch.tensor([10, 20, 30]) # shape [3] print(a b)这里b会广播成[[10, 20, 30], [10, 20, 30]]然后与a相加。广播能让代码更简洁但也让维度错误变得更加隐蔽。当报错信息提示The size of tensor a (3) must match the size of tensor b (4)时往往就是两个张量的形状没有对齐。6.2 矩阵乘法*不等于矩阵乘法在 PyTorch 中有三种常见写法x y、torch.matmul(x, y)、torch.mm(x, y)。其中是 Python 3.5 引入的运算符推荐使用可读性最好。x torch.randn(2, 3) y torch.randn(3, 4) # 矩阵乘法结果是 [2, 4] z x y print(矩阵乘法结果 shape:, z.shape)如果这里误写成x * y就会触发形状不匹配的报错因为逐元素乘法要求两个张量形状一致或可广播。实际项目中写矩阵乘法时可以先在注释里标明预期输出形状这样排错会更快。6.3 维度变换view、reshape、permute、squeeze、unsqueeze维度变换是 Tensor 操作中坑最多的地方。view和reshape都可以改变形状。区别在于view要求 Tensor 在内存中是连续的如果之前做过转置等操作view可能报错reshape更灵活会自动处理不连续的情况。实际开发中如果拿不准优先用reshape。x torch.randn(2, 3, 4) # reshape 成新形状 y x.reshape(6, 4) print(reshape 后:, y.shape) # 增加一个维度 z x.unsqueeze(0) print(unsqueeze 后:, z.shape) # [1, 2, 3, 4] # 减少一个维度 w x.squeeze(0) print(squeeze 后:, w.shape)squeeze和unsqueeze是一对相反操作。unsqueeze(0)在开头增加一个大小为 1 的维度常用于给单个样本添加 batch 维度squeeze(0)则移除大小为 1 的维度。permute用于多维张量的维度重排。假设你有个形状为[batch, channels, height, width]的图像张量想转换成[batch, height, width, channels]只用permute即可img torch.randn(4, 3, 224, 224) img_permuted img.permute(0, 2, 3, 1) print(permute 后:, img_permuted.shape) # [4, 224, 224, 3]注意permute会返回一个新的视图但底层数据在内存中可能变得不连续。如果之后要调用view要先做contiguous()。6.4 拼接与拆分cat 和 stack 的区别cat和stack长得像但行为完全不同。torch.cat在已有维度上拼接要求除了拼接维度外其他维度完全一致。torch.stack则会创建新维度把多个张量堆叠起来。a torch.tensor([1, 2, 3]) b torch.tensor([4, 5, 6]) # cat拼接后 shape 为 [6] c torch.cat([a, b]) print(cat:, c, c.shape) # stack新增维度后 shape 为 [2, 3] s torch.stack([a, b]) print(stack:\n, s, s.shape)实际应用场景中cat常用于合并多个 batch 的特征stack常用于把多个独立的向量组合成一个小 batch。两者的选择标准很简单你要扩展现有维度还是新增一个维度。6.5 归约与统计sum、mean、max、argmax训练过程中最常做的事情是对 Tensor 做归约统计x torch.randn(3, 4) print(所有元素求和:, x.sum()) print(所有元素均值:, x.mean()) print(按第 0 维求和:, x.sum(dim0)) print(按第 1 维求最大值:, x.max(dim1))这里要注意dim参数的语义。dim0表示沿第 0 维归约也就是把每一列的元素合并dim1表示沿第 1 维归约也就是针对每一行操作。max(dim1)返回的结果不是一个 Tensor而是一个包含values和indices的对象分别表示最大值和最大值所在的索引位置。想取索引做进一步计算时可以直接取.indices。6.6 与 NumPy 互转Tensor 和 NumPy 数组互转在数据预处理阶段非常频繁import numpy as np t torch.arange(5) arr t.numpy() print(Tensor 转 NumPy:, arr, type(arr)) arr2 np.array([1, 2, 3]) t2 torch.from_numpy(arr2) print(NumPy 转 Tensor:, t2, type(t2))需要注意在 CPU 上创建的 Tensor 转 NumPy 是共享内存的改动一方会同步影响另一方。但是 GPU 上的 Tensor 不能直接.numpy()必须先调用.cpu()把数据搬到 CPU再进行转换。7. 运行结果与效果验证学习 Tensor 操作最有效的方式不是看而是跑。建议打开 Jupyter Notebook 或 VS Code新建一个.py文件把前面所有代码复制进去逐段运行然后观察输出。下面这段代码可以当作一个综合验证脚本建议自己手动写一遍不要直接复制import torch x torch.randn(2, 3) print(初始 shape:, x.shape) print(所需设备:, x.device) print(数据类型:, x.dtype) y x.reshape(3, 2) print(reshape 后 shape:, y.shape) z x x.T print(矩阵乘法结果 shape:, z.shape) # 判断是否可训练 linear_input x.unsqueeze(0) print(添加 batch 维度后:, linear_input.shape)运行成功的标准有三个第一所有print语句正常输出第二每个 Tensor 的shape都符合你在注释里的预期第三没有出现 dtype 或 device 相关的报错。如果运行失败第一步不要乱猜先看报错信息中的最后一行把其中的 shape、dtype、device 关键词提取出来再和当前代码中涉及的所有 Tensor 比对。大多数情况下问题就出在这三个属性中的某一个不匹配。8. 常见问题与排查思路下面这张表整理了 PyTorch Tensor 初学者最容易遇到的几类问题以及对应的排查路径问题现象可能原因排查方式解决方案矩阵相乘报size mismatch两个 Tensor 的形状不满足矩阵乘法规则打印两个 Tensor 的 shape确认内维度相等检查是否需要转置或用reshape调整形状运算时报same device错误一个 Tensor 在 GPU另一个在 CPU分别打印.device属性统一调用.to(device)不要手动混合设备报dtype mismatch浮点型和整型 Tensor 直接参与运算打印.dtype属性统一转换为torch.float32view报view size is not compatible原始 Tensor 内存不连续检查是否刚执行过permute或transpose先调用.contiguous()再用view或者直接改用reshape下载安装很慢网络到默认 PyPI 源不稳定查看 pip 下载日志使用国内镜像源或下载离线 wheel 包CPU 环境下 GPU 代码报错未安装 GPU 版 PyTorch或 CUDA 驱动不匹配运行torch.cuda.is_available()根据nvidia-smi选择匹配的 CUDA 版本重新安装这里特别想强调第一行的问题。很多新手看到size mismatch就去改模型的层结构但真正原因可能只是两个 Tensor 在拼接时维度没有对齐。排查这类问题时先打印 shape不要只看报错信息的中段。9. 最佳实践与工程建议Tensor 操作本身不难难的是在真实项目里写出稳定、可维护的代码。下面这些建议来自实际工程中比较常见的经验建议收藏。第一统一设备管理。不要在代码里硬编码cuda或cpu而是定义一个变量device torch.device(cuda if torch.cuda.is_available() else cpu)之后所有 Tensor 和模型都通过.to(device)转移。这样换机器、换 GPU 环境时不需要改业务代码。第二统一 dtype。深度学习模型默认浮点类型是torch.float32。如果你的数据是torch.float64可能在 GPU 上报不支持或者训练速度突然变慢。创建 Tensor 时如果涉及浮点数据建议显式指定x torch.tensor([1.0, 2.0, 3.0], dtypetorch.float32, devicedevice)第三固定随机种子。需要复现实验结果时这是必须做的torch.manual_seed(42)如果使用 GPU后续配合torch.cuda.manual_seed_all(42)可以让多次运行的初始化结果保持一致。第四推理阶段关闭梯度追踪。如果只是做预测和评估不要在需要反向传播的路径之外构建多余的计算图with torch.no_grad(): output model(input_tensor)这样能节省大量显存和计算时间。当你只是验证一个 Tensor 中间结果时也可以用.detach()把它从计算图中分离出来。第五不要在训练循环里频繁执行 GPU 到 CPU 的同步比如每次迭代都调用.item()或.tolist()。这些操作会阻塞流水线显著拖慢训练速度。合理的做法是累积到一定步数再统一打印或保存。第六注意 PyTorch 版本变化。比如 PyTorch 2.6 起torch.load的weights_only参数默认值发生了变化加载模型时建议显式传入避免出现安全隐患或兼容问题。Tensor 核心 API 虽然稳定但涉及模型加载、序列化时还是要在升级版本后跑一遍回归验证。10. 总结与下一步学习方向这一课的核心内容可以浓缩成一张心智地图Tensor 是数据的容器先搞清楚它的shape、dtype、device三个属性再掌握创建、变换、归约、拼接这四类基本操作。只要这张地图在脑子里后面读 PyTorch 源码时会轻松很多。建议你先打开 Jupyter Notebook把上文所有代码亲手敲一遍特别是view、permute、squeeze、unsqueeze这几个维度变换操作多打几遍print(tensor.shape)观察变化直到不用看文档也能判断输出形状为止。下一课开始我们会进入自动求导和nn.Module理解 PyTorch 是如何把 Tensor 操作组合成可训练模型的。在那之前请把本课的创建和操作练习到足够熟练。如果文章里有哪段代码运行报错先把报错信息里的属性关键词抄下来对照第 8 节的排查表通常就能定位问题。