FEATURED · 精选文章

PyTorch核心数据结构Tensor详解:创建、属性与GPU加速实战

发布时间 / 2026/8/29 3:29:41
来源 / 创域科博编辑部
栏目 / 资讯中心
PyTorch核心数据结构Tensor详解:创建、属性与GPU加速实战 这次我们来看 PyTorch 教程的第 1 课Tensor。为什么第一课要讲 Tensor因为无论你之后是做图像分类、目标检测、自然语言处理还是加载别人训练好的模型输入和输出都绕不开 Tensor。理解 Tensor 的创建、属性和基本操作等于先拿到了解锁 PyTorch 的钥匙。这一课我会直接带你过一遍 Tensor 的核心内容包括Tensor 怎么创建、有哪些属性、支持什么运算、怎么在 CPU 和 GPU 之间切换以及常见报错怎么处理。课程最后会补充环境安装和性能观察的实操经验。如果你是第一次接触 PyTorch先把这一课看完再往后走会顺很多。先说结论Tensor 入门不难但它和 Python 自带的数据结构不太一样最大的区别是支持 GPU 加速、自动求导和批量维度计算。后面写模型时你会频繁看到shape、dtype、device这三个属性所以要尽早形成肌肉记忆。下面从核心能力速览开始。1. 核心能力速览能力项说明项目类型深度学习开源框架 PyTorch 的核心数据结构核心对象Tensor张量主要功能数据创建、属性查看、形状变换、数学运算、GPU 加速、自动求导基础推荐硬件有 NVIDIA GPU 可体验 CUDA 加速无 GPU 也能用 CPU 完成本课全部内容显存占用取决于 Tensor 维度、数据精度和 batch 大小需按实际测试观察支持平台Windows、Linux、macOS启动方式Python 脚本、Jupyter Notebook、交互式解释器均可是否支持 API以 Python API 为主不是网络服务是否支持批量任务支持Tensor 天然带有 batch 维度可批量计算适合场景深度学习入门、模型开发、论文复现、算法验证从材料看PyTorch 是目前深度学习领域使用非常广泛的框架之一TensorFlow 和 PyTorch 的对比也是社区热门话题。无论选择哪个框架理解张量运算都是基本功。PyTorch 的 Tensor 设计得足够贴近 NumPy所以很多做数据分析的人第一次迁移也不会太难受。2. 适用场景与使用边界2.1 适合哪些读者这一课适合四类读者。第一类是刚入门深度学习的学生或开发者需要从底层数据结构认识 PyTorch。第二类是已经会 NumPy 但没接触过 PyTorch 的人可以借助 Tensor 和 NumPy 的相似性快速迁移。第三类是要复现论文代码的人读模型源码时经常看到shape、view、permute这类操作不理解 Tensor 就很容易卡住。第四类是准备把自己的算法封装成服务或批量处理工具的工程开发者先搞清楚 Tensor 的创建和转换后面写部署脚本会更稳。2.2 不适合哪些场景如果你只是做简单表格数据处理、画几张图、跑一次线性回归用 Pandas 和 NumPy 已经够了不一定需要引入 PyTorch。如果你是做 Web 后端开发只想调用别人训练好的模型接口也不需要从 Tensor 底层学起直接使用部署框架反而更快。Tensor 是深度学习的基础组件但不是数据处理工具链的全部。2.3 使用边界与合规提醒Tensor 本身不涉及版权和隐私问题但它承载的数据可能涉及。训练图像模型、语音模型或文本模型时训练数据的来源必须合法人脸、声音、个人信息要获得明确授权。如果后续用 PyTorch 做模型发布或商用还要注意模型权重文件的许可协议以及训练数据是否包含受版权保护的素材。这个习惯要从第一课就开始养成。3. 环境准备与前置条件3.1 硬件与系统要求Tensor 这一课对硬件要求很低CPU 就能完整跑通。系统方面Windows、Linux、macOS 都可以。如果你有 NVIDIA 显卡可以装 CUDA 版 PyTorch体验 GPU 加速如果没有显卡装 CPU 版即可不影响本课任何示例。AMD 显卡用户可以关注官方 ROCm 支持情况但更稳妥的方案是先用 CPU 版本完成学习。3.2 Python 版本与虚拟环境建议使用 Python 3.9 到 3.12 范围内的稳定版本。PyTorch 支持多个 Python 版本但过老的版本容易踩依赖坑。强烈建议创建独立的虚拟环境避免多个项目之间包版本冲突。如果你使用 Anaconda可以这样创建环境conda create -n pytorch-lesson python3.11 conda activate pytorch-lesson如果你不想用 Anaconda也可以直接用 Python 自带的venvpython -m venv pytorch-lesson # Windows pytorch-lesson\Scripts\activate # Linux/macOS source pytorch-lesson/bin/activate3.3 安装 PyTorch安装 PyTorch 最常用的方式是 pip 或 conda。CPU 版直接安装最简单pip install torch如果要安装 CUDA 版建议先打开 PyTorch 官网的 Get Started 页面选择自己的操作系统、包管理工具和 CUDA 版本复制对应的安装命令。不同 CUDA 版本对应不同的编译产物装错可能出现 GPU 不可用的情况。国内网络环境下pip 下载慢是常见问题。可以临时指定镜像源下载速度会明显提升pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple需要注意PyTorch 官方源和 pip 默认源的文件差异直接用镜像源安装 CPU 版本一般没问题。安装完成后不要急着写模型先验证环境。3.4 校验安装结果安装完成后在 Python 环境里执行下面的代码确认 PyTorch 能正常导入import torch print(torch.__version__) print(torch.cuda.is_available())如果torch.__version__能正常输出说明安装成功。torch.cuda.is_available()在 CPU 版上会返回False这是正常的不代表安装失败。如果返回True说明当前环境能使用 GPU 加速。这里还要提醒一个新版变化从 PyTorch 2.6 开始torch.load的weights_only参数默认值发生了变化。加载模型权重文件时建议显式确认参数避免反序列化带来的兼容性和安全问题。4. Tensor 创建从零开始造一个张量4.1 从 Python 列表创建创建 Tensor 最简单的方式是直接用torch.tensor()传入 Python 列表import torch a torch.tensor([1, 2, 3]) print(a) # tensor([1, 2, 3])如果想创建二维张量就传嵌套列表b torch.tensor([[1, 2], [3, 4]]) print(b) print(b.shape) # torch.Size([2, 2])这里有一个非常容易踩的坑torch.tensor()和torch.Tensor()不一样。torch.tensor()会根据输入数据推断数据类型torch.Tensor()也可以创建张量但它默认使用torch.float32而且传列表和传整数时的行为有差异。建议初学者统一使用torch.tensor()语义更清晰。# 不推荐在最开始阶段混用 c torch.Tensor([1, 2, 3]) print(c.dtype) # torch.float324.2 与 NumPy 互相转换Tensor 和 NumPy 的互转很常用转换代码也很短import numpy as np arr np.array([[1, 2], [3, 4]]) tensor_from_np torch.from_numpy(arr) print(tensor_from_np) back_to_np tensor_from_np.numpy() print(back_to_np)需要注意torch.from_numpy()转换出的 Tensor 在 CPU 上和原始 NumPy 数组共享内存。也就是说修改其中一方另一方也会跟着变。这在某些场景下是优点在另一些场景下会带来隐蔽的 bug。如果不希望共享内存可以使用tensor.clone()或np.array()复制一份。4.3 常用初始化方法实际写模型时很少会手写列表初始化更多是用现成的初始化函数。下面这些方法必须掌握# 全 0形状 (3, 4) zeros torch.zeros(3, 4) # 全 1形状 (2, 3) ones torch.ones(2, 3) # 单位矩阵3 行 3 列 eye torch.eye(3) # 均匀分布随机数范围 [0, 1) rand torch.rand(2, 2) # 标准正态分布随机数 randn torch.randn(2, 2) # 指定范围的连续整数类似 range arange torch.arange(0, 10, step2) # 等差序列 linspace torch.linspace(0, 1, steps5) # 指定值填充 full torch.full((2, 2), 7) # 未初始化的内存空间 empty torch.empty(2, 2)torch.empty()是最容易让新手困惑的函数它不会把内存清零输出值是未定义的。平时不建议用除非你确定后续会覆盖所有元素。torch.arange()的结束位置不包含在结果里写torch.arange(0, 10, step2)得到的是[0, 2, 4, 6, 8]。4.4 指定 dtype、device 与 requires_grad创建 Tensor 时可以直接指定数据类型、设备以及是否需要梯度x torch.tensor( [1.5, 2.5], dtypetorch.float32, devicecpu, requires_gradTrue ) print(x.dtype) print(x.device) print(x.requires_grad)requires_gradTrue表示这个张量会参与自动求导是 PyTorch 相比 NumPy 最大的优势。普通的 NumPy 数组无法自动计算梯度而 Tensor 加上requires_grad之后就能构建计算图反向传播时自动求出梯度。这一课先记住这个参数具体求导逻辑会在后面的 autograd 课程里展开。创建零张量时也可以指定参数比如z torch.zeros(2, 2, dtypetorch.float64)dtype的选择直接影响精度和显存占用。float32是深度学习默认精度float64更精确但更占内存float16和bfloat16在训练时可以降低显存占用但需要留意数值稳定性。5. Tensor 属性与形状操作5.1 查看核心属性拿到一个 Tensor第一件事是搞清楚它的形状、维度、数据类型和设备。以下几个属性必须刻进记忆x torch.randn(4, 8, 16) print(x.shape) # torch.Size([4, 8, 16]) print(x.size()) # 和 shape 一样 print(x.ndim) # 3 print(x.dtype) # torch.float32 print(x.device) # cpu 或 cuda:0 print(x.requires_grad) # Falseshape和size()在多数情况下可以互换但size(i)可以单独取第 i 维的大小这个在写代码时很常用print(x.size(0)) # 4 print(x.size(1)) # 85.2 索引与切片Tensor 的索引和 Python 列表非常像支持冒号切片x torch.arange(12).reshape(3, 4) print(x) # tensor([[ 0, 1, 2, 3], # [ 4, 5, 6, 7], # [ 8, 9, 10, 11]]) # 取第一行 print(x[0]) # tensor([0, 1, 2, 3]) # 取第一行第二列 print(x[0, 1]) # tensor(1) # 取所有行的第一列 print(x[:, 1]) # tensor([1, 5, 9]) # 取前两行 print(x[:2])和 NumPy 一样切片返回的张量在多数情况下共享底层内存修改切片会影响原张量。如果你不希望影响原数据使用x[1:3].clone()。5.3 形状变换 view / reshape形状变换是模型代码里出现频率最高的操作之一。view()和reshape()都能改变形状x torch.arange(12) y x.view(3, 4) z x.reshape(2, 6) print(y.shape) print(z.shape)两者有一个重要区别view()要求张量在内存中是连续存放的否则可能报错。reshape()更智能当无法直接复用内存时会自动复制数据适用范围更广。从工程角度如果你不确定张量是否连续优先使用reshape()如果在意性能且确定连续使用view()更稳妥。view()里还有一个常用写法是-1表示该维度自动推导x torch.arange(12) y x.view(3, -1) print(y.shape) # torch.Size([3, 4])5.4 维度调整 squeeze / unsqueeze / permute / transpose这四个函数是新手最容易晕的操作但它们在图像和文本模型里无处不在。x torch.randn(1, 3, 1, 28, 28) # 去掉长度为 1 的维度 squeeze_x x.squeeze() print(squeeze_x.shape) # torch.Size([3, 28, 28]) # 只去掉指定位置的长度为 1 的维度 squeeze_0 x.squeeze(0) print(squeeze_0.shape) # torch.Size([3, 1, 28, 28]) # 增加一个维度 unsqueeze_x x.unsqueeze(0) print(unsqueeze_x.shape) # torch.Size([1, 1, 3, 1, 28, 28])squeeze()去掉所有长度为 1 的维度unsqueeze()在指定位置增加一个维度。这两个操作常用于拼接数据和调整 batch 维度。permute()和transpose()用于交换维度顺序x torch.randn(4, 3, 32, 32) # 模拟 batch4, channel3, height32, width32 # 将维度顺序调整为 [batch, height, width, channel] y x.permute(0, 2, 3, 1) print(y.shape) # torch.Size([4, 32, 32, 3]) # 交换两个维度 z x.transpose(1, 3) print(z.shape) # torch.Size([4, 32, 32, 3])transpose()只能交换指定的两个维度permute()可以任意重排所有维度。两者之后得到的新张量可能是非连续的如果后续要接view()建议先执行contiguous()y x.permute(0, 2, 3, 1).contiguous() print(y.is_contiguous()) # True6. Tensor 基本运算6.1 算术运算与逐元素计算Tensor 支持常见的算术运算符包括、-、*、/、//、%、**。这些都是逐元素计算a torch.tensor([1.0, 2.0, 3.0]) b torch.tensor([4.0, 5.0, 6.0]) print(a b) print(a * b) print(a / b) print(a ** 2) # tensor([ 1., 4., 9.])这些运算在底层会调用对应的 PyTorch 函数比如torch.add()、torch.mul()。函数式写法在某些场景下更明确c torch.add(a, b) d torch.mul(a, b)6.2 矩阵乘法逐元素乘法和矩阵乘法是两回事。矩阵乘法使用运算符或torch.matmul()A torch.randn(2, 3) B torch.randn(3, 4) C A B print(C.shape) # torch.Size([2, 4]) D torch.matmul(A, B) print(D.shape) # torch.Size([2, 4])torch.matmul()还支持更复杂的批量矩阵乘法。简单理解两个张量的最后两个维度构成矩阵乘法前面的维度作为 batch 维度参与广播。这是深度学习中批量计算的核心基础。6.3 拼接与分割拼接和分割在模型代码中也很常见。torch.cat()沿着已有维度拼接torch.stack()创建新维度后堆叠x torch.randn(2, 3) y torch.randn(2, 3) # 沿着第 0 维拼接结果形状 (4, 3) cat0 torch.cat([x, y], dim0) print(cat0.shape) # 沿着第 1 维拼接结果形状 (2, 6) cat1 torch.cat([x, y], dim1) print(cat1.shape) # 新建一个维度堆叠结果形状 (2, 2, 3) stack torch.stack([x, y], dim0) print(stack.shape)分割使用torch.chunk()或torch.split()x torch.randn(6, 4) # 分成 3 份每份形状 (2, 4) chunks torch.chunk(x, chunks3, dim0) print(len(chunks)) # 按照指定大小分割 splits torch.split(x, [1, 2, 3], dim0) for s in splits: print(s.shape)6.4 归约操作对张量求总和、均值、最大值是模型训练中非常常见的操作。归约操作默认会作用于整个张量也可以通过dim指定维度x torch.arange(6, dtypetorch.float32).reshape(2, 3) print(x) # tensor([[0., 1., 2.], # [3., 4., 5.]]) print(x.sum()) # tensor(15.) print(x.mean(dim0)) # tensor([1.5, 2.5, 3.5]) print(x.max(dim1)) # torch.return_types.max(valuestensor([2., 5.]), indicestensor([2, 2]))指定dim后被归约的那个维度会消失。做损失函数时最常见的写法是loss.mean()也就是把 batch 内的所有样本损失取平均。6.5 广播机制PyTorch 的广播机制继承自 NumPy。当两个张量形状不完全一致时只要满足规则会先自动扩展再计算a torch.randn(2, 3) b torch.randn(3) # b 会被广播成 (2, 3)然后逐元素相加 c a b广播规则可以简单理解成从后往前对齐维度如果某个维度相等、是 1或者缺失就能广播。我们经常用这个特性来做归一化操作比如把张量每一列减去均值。但广播也可能产生隐性 bug尤其是当两个张量形状刚好匹配、但语义上不对应时。建议每次写复杂运算前先打印一下广播后的形状。7. CPU 与 GPU 切换、资源占用与性能观察7.1 检测 CUDA 是否可用Tensor 在 CPU 和 GPU 上的行为几乎一致区别在于计算设备。使用 GPU 前先检测环境import torch if torch.cuda.is_available(): print(CUDA available:, torch.cuda.get_device_name(0)) else: print(CUDA not available, running on CPU)在 macOS 上新版 PyTorch 也可以使用 Apple 芯片的 MPS 后端if torch.backends.mps.is_available(): print(MPS available)7.2 张量迁移张量可以直接在 CPU 和 GPU 之间迁移最常用的方式是to()device torch.device(cuda if torch.cuda.is_available() else cpu) x torch.randn(3, 3) x x.to(device) print(x.device)也可以使用cpu()和cuda()x_cpu x.cpu() x_gpu x.cuda(0)实际写训练脚本时推荐统一使用device变量避免硬编码cuda。遇到多个 GPU 时可以通过cuda:0、cuda:1指定设备。GPU 计算和 CPU 计算最大的不同在于GPU 显存是独立于系统内存的。一个 Tensor 在 CPU 上占用多少内存迁移到 GPU 后会在显存里重新分配。如果模型、输入、梯度加在一起超过显存容量就会触发CUDA out of memory错误。7.3 张量运算性能观察这一课不涉及大模型性能压力很小但你应该建立“观察资源占用”的习惯。开启一个 GPU 环境后在另一个终端里运行nvidia-smi这个命令会显示 GPU 利用率、显存占用和运行进程。当 PyTorch 程序执行时显存占用会明显上升。影响显存和性能的主要因素有三个Tensor 的维度、数据精度dtype、批量大小batch。同样的数据量float32比float64省一半空间float16又比float32省一半空间。批量越大虽然计算效率更高但显存占用也线性上涨。初学者第一次跑模型时如果内存不足优先减少 batch size而不是换机器。7.4 显存释放与计算图控制在 Python 中del删除对象后相关对象的引用计数会下降。但显存的释放时机并不完全由 Python 控制因为 PyTorch 的显存分配器会缓存已释放的显存。手动释放显存可以这样del x torch.cuda.empty_cache()torch.cuda.empty_cache()会把缓存的显存返还给 PyTorch 的显存池但不一定会立刻返还给操作系统。更关键的做法是不要长期持有不再需要的大张量以及善用with torch.no_grad():关闭计算图保存。训练时带有requires_gradTrue的张量会保存计算图。如果只做推理不更新梯度可以这样with torch.no_grad(): y model(x)no_grad块内不会保存反向传播所需的中间结果能明显降低显存占用。8. 常见问题与排查方法问题现象可能原因排查方式解决方案pip 安装 PyTorch 太慢或超时网络环境不稳定观察下载进度和超时位置使用国内镜像源如清华、阿里云镜像import torch 成功但 CUDA 不可用安装了 CPU 版 Torch或 CUDA 驱动版本不匹配运行torch.cuda.is_available()和nvidia-smi按官网命令重新安装匹配 CUDA 版本的 PyTorchnvidia-smi 能显示显卡但 is_available 仍为 False驱动版本过低或 PyTorch 版本不支持当前 CUDA检查nvidia-smi顶部驱动版本升级驱动或选择对应 CUDA 版本的 PyTorch显存不足报错batch size 过大、分辨率过高、缓存未释放查看nvidia-smi的显存占用调小 batch size、降低精度、用del和empty_cache()释放view()报错提示 not contiguous张量经过了 transpose 或 permute打印is_contiguous()检查使用contiguous()或改用reshape()两个张量运算时报 shape mismatch维度不匹配或广播规则不满足打印两个张量的 shape调整维度使用unsqueeze、permute或reshapetorch.load()加载权重报错或安全提示PyTorch 2.6 后weights_only默认值变化查看版本更新说明和报错信息显式添加weights_onlyTrue或按需要调整加载方式在同一个表达式里混用了 CPU 和 GPU 张量一个张量调用过.to(device)另一个没有分别打印.device统一迁移到同一个设备conda 环境内 import torch 报错不同环境依赖混用或安装不完整pip list查看包列表新建干净虚拟环境后重新安装8.1 安装类问题安装类问题的核心是先确定版本组合。PyTorch 版本、CUDA 版本、显卡驱动版本三者需要匹配。官方安装命令已经帮用户默认匹配所以最好不要手动混合不同源的包。Windows 用户如果遇到 DLL 加载失败优先检查是否缺少 Visual C 运行库。8.2 设备类问题CPU 和 GPU 混用是新手最常遇到的问题。出现Expected all tensors to be on the same device这类报错时不用慌定位方法很简单把参与运算的每个张量都打印一下.device然后把所有需要计算的张量统一迁移到同一个设备。好的代码习惯是不要硬编码cuda而是定义device torch.device(cuda if torch.cuda.is_available() else cpu)。8.3 形状类问题形状错误本质上是数学维度没对齐。PyTorch 的报错信息相对友好会直接告诉你期望的维度和实际收到的维度。排查方法是用.shape打印每一步的中间结果逐步缩小问题范围。不要一次写一大段运算代码建议每步都打印验证。9. 最佳实践与学习建议9.1 从最小案例开始学习 Tensor 时不要一开始就模拟很复杂的图像或文本数据。先用torch.randn造几个小张量练习形状变换、拼接和矩阵乘法。把前面章节的代码完整跑一遍再尝试改维度。第一次接触permute时建议在纸上画出维度变化再和打印结果对照。9.2 固定随机种子PyTorch 里的随机函数很多torch.rand、torch.randn、以及后续的torch.manual_seed都会影响实验复现。在脚本开头加上import torch torch.manual_seed(42)如果涉及 CUDA再补充一句torch.cuda.manual_seed_all(42)固定种子后同一份代码多次运行会得到相同结果这对调试和复现非常重要。9.3 保持代码模块化不要把 Tensor 的操作全部堆在一个文件里。建议把数据创建、模型结构、训练逻辑分开。目录结构可以像这样pytorch-lesson/ ├── data/ ├── models/ ├── utils/ ├── train.py └── config.py其中config.py统一管理学习率、batch size、epoch 数和设备信息。这个习惯会让后续调试省很多时间。9.4 关注自动求导和数据加载Tensor 是 PyTorch 的地基但真正跑训练还需要两个核心组件自动求导autograd和数据加载DataLoader。学完 Tensor 后下一步建议按这个顺序走先看requires_grad和backward()是怎么工作的再学习Dataset和DataLoader如何把数据组织成 batch最后看nn.Module如何搭建神经网络。这一课里关于device、dtype、shape的理解会在后面每个阶段都用上。9.5 建立自己的速查手册Tensor 方法很多一次性记不住很正常。建议把自己本课涉及的代码按“创建、属性、形状、运算、设备迁移、性能观察”分门别类整理成一个速查脚本。每次遇到view和permute记不清时直接跑一遍自己的速查脚本。这个脚本会随着课程推进越来越有价值。9.6 合规与工程化提醒PyTorch 本身是开源工具但用它处理真实数据时要确认数据来源合法尤其是图像、人脸、声音等敏感数据。商用前检查模型权重的许可协议。训练脚本里建议加入日志记录把每次训练的配置、数据版本、模型版本都保存下来。批量任务规模变大后要关注显存释放和进程管理避免长时间运行导致资源泄漏。10. 总结与下一步Tensor 这一课看起来内容多但核心可以压缩成三句话Tensor 是 PyTorch 的基本数据结构创建时注意dtype、device、requires_grad运算前先用shape确认维度再用to(device)统一设备。最值得马上验证的是把第 4 章到第 6 章的代码逐段跑通。不要只看不写很多形状变换的报错只有亲手遇到才会有印象。最容易踩的坑是view和permute的连续性问题以及 CPU 张量和 GPU 张量混用。遇到这类报错先把每个张量的.device和.shape打出来问题通常立刻清楚。下一步的方向已经很明确先学autograd理解requires_gradTrue之后梯度是怎么算出来的再学DataLoader把数据组织成批量输入然后就可以进入线性回归、多层感知机这些真正意义上的训练代码了。建议先把这一课收藏后面写模型遇到 Tensor 方法记不住时回来查速查表作用比再看一遍视频更大。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻