当前位置: 首页 > news >正文

PyTorch 深度学习笔记(五)张量拼接与自动微分——构建神经网络基础

系列导读:本系列共 6 篇,从 PyTorch 框架入门到实战案例,带你系统掌握深度学习开发。上一篇:张量运算与变形——数值计算与索引进阶

一、张量拼接操作

1.1 cat / concat:沿现有维度拼接

torch.cat沿现有维度连接一系列张量,不改变维度数

importtorch# 初始化数据data1=torch.randint(0,6,(2,3))data2=torch.randint(0,6,(2,3))print(data1.shape)# torch.Size([2, 3])print(data2.shape)# torch.Size([2, 3])# 按 dim=0 拼接(行方向,垂直堆叠)data=torch.cat([data1,data2],dim=0)print(data.shape)# torch.Size([4, 3])# 按 dim=1 拼接(列方向,水平拼接)data=torch.cat([data1,data2],dim=1)print(data.shape)# torch.Size([2, 6])# 按 dim=2 拼接(需要三维张量)data1=torch.randint(0,6,(2,3,4))data2=torch.randint(0,6,(2,3,4))data=torch.cat([data1,data2],dim=2)print(data.shape)# torch.Size([2, 3, 8])

关键规则:拼接维度可以不一致,但其他维度必须相同

1.2 stack:在新维度上拼接

torch.stack新维度上连接张量,增加一个新维度,所有输入张量形状必须完全相同

data1=torch.randint(0,10,[2,3])data2=torch.randint(0,10,[2,3])# dim=0:新维度在最前面 → (2, 2, 3)new_data=torch.stack([data1,data2],dim=0)print(new_data.shape)# torch.Size([2, 2, 3])# dim=1:新维度在中间 → (2, 2, 3)new_data=torch.stack([data1,data2],dim=1)print(new_data.shape)# torch.Size([2, 2, 3])# dim=2:新维度在最后 → (2, 3, 2)new_data=torch.stack([data1,data2],dim=2)print(new_data.shape)# torch.Size([2, 3, 2])

经典应用

  • 单通道灰度图[H, W],三张 stack 模拟 RGB →[3, H, W]
  • 多张图片张量[C, H, W],stack 得到批次[B, C, H, W]

1.3 chunk / split:拆分张量

化整为零,各个击破:大拆小,小运行。

data=torch.tensor([[1,2,3],[4,5,6],[7,8,9],[11,12,13]])# chunk:均分成 chunks 份chunks=torch.chunk(data,chunks=2,dim=0)print('第1块:',chunks[0].shape)# torch.Size([2, 3])print('第2块:',chunks[1].shape)# torch.Size([2, 3])# split:按指定大小拆分splits=torch.split(data,[1,1,2],dim=0)print(splits[0].shape)# torch.Size([1, 3])print(splits[1].shape)# torch.Size([1, 3])print(splits[2].shape)# torch.Size([2, 3])

1.4 stack 与 chunk 互逆操作

# 生成 64 张 3 通道 32x32 的图片张量imgs=[]foriinrange(64):img=torch.randn(3,32,32)# 3 通道,32 高,32 宽imgs.append(img)# stack 拼接:64 张 → (64, 3, 32, 32)imgs2=torch.stack(imgs,dim=0)print(imgs2.shape)# torch.Size([64, 3, 32, 32])# chunk 拆分:(64, 3, 32, 32) → 64 张 (1, 3, 32, 32)imgs_restore=torch.chunk(imgs2,chunks=64,dim=0)print(len(imgs_restore))# 64print(imgs_restore[0].shape)# torch.Size([1, 3, 32, 32])# squeeze 降维:(1, 3, 32, 32) → (3, 32, 32)imgs_new=imgs_restore[0].squeeze(0)print(imgs_new.shape)# torch.Size([3, 32, 32])

二、自动微分模块 autograd ⭐⭐⭐

2.1 什么是自动微分

自动微分 = 自动计算梯度 = 自动计算导数

训练神经网络时,PyTorch 会根据模型构建计算图(Computational Graph)

  1. 跟踪哪些数据通过哪些操作组合产生输出
  2. 通过反向传播算法,根据损失函数的梯度调整参数(模型权重)
  3. torch.autograd引擎支持任意计算图的自动梯度计算

2.2 计算图可视化

importtorchfromtorchvizimportmake_dot# 简单模型x=torch.randn(1,requires_grad=True)y=x**2# 生成计算图图片make_dot(y,params={"x":x}).render("y=x²的计算图",format="png")

2.3 梯度基本概念

概念解释
梯度对函数求导的值
梯度下降法求最优梯度,使损失函数最小
链式法则复合函数求导,反向传播的核心
反向传播从后向前求导,传播梯度

梯度经典语录

  • 在某一点上,对函数求导得到的值就是该点的梯度
  • 在平面上,梯度就是某一点上的斜率
  • 反向传播传播的是梯度
  • 链式法则中梯度相乘,就是传说中的梯度传播

三、梯度基本计算

3.1 关键前提

PyTorch 不支持向量张量对向量张量的求导,只支持标量张量对向量张量的求导。

  • x是张量 →y必须是标量(一个值)才能求导

3.2 requires_grad:梯度开关

# 默认不开启自动求导x=torch.arange(9).view(3,3)print(x.requires_grad)# False# 开启自动求导x=torch.rand(3,3,requires_grad=True)print(x.requires_grad)# True

3.3 标量张量求导

# 定义变量(开启梯度追踪)x=torch.tensor(10,requires_grad=True,dtype=torch.float32)print("x -->",x)# 定义曲线:y = x²y=x**2print("y -->",y)# 查看梯度函数类型print(y.grad_fn)# <PowBackward0 object># 计算梯度(y 是标量,直接 backward)y.backward()# x.grad 就是导数值print("x 的梯度值是:",x.grad)# 2*10 = 20.0

backward() 执行过程

  1. 从输出y出发,初始化上游梯度dy/dy = 1
  2. 进入PowBackward0算子,套用导数公式dy/dx = 2x
  3. 梯度流入AccumulateGrad节点,把算出的2x存入x.grad
  4. 执行完毕后,x.grad才有具体数值

3.4 向量张量求导

# 定义向量张量x=torch.tensor([10,20],requires_grad=True,dtype=torch.float32)print("x -->",x)# 定义曲线y=x**2print("y -->",y)# y 是向量,先转成标量再求导y.sum().backward()# x.grad 保存每个元素的梯度print("x.grad -->",x.grad)# tensor([20., 40.])

四、梯度计算注意事项

4.1 不能将求导张量转 NumPy

x=torch.tensor([10,20],requires_grad=True,dtype=torch.float64)# ❌ 报错!不能直接转 NumPy# print(x.numpy())# RuntimeError: Can't call numpy() on Tensor that requires grad.# ✅ 先用 detach() 脱离计算图x2=x.detach()print(x2.numpy())

detach() 的作用

  • 产生一个新的张量,与原始张量共享数据
  • 新张量不会自动微分(requires_grad=False)
  • x.data_ptr()x2.data_ptr()相同(共享内存)
  • id(x)id(x2)不同(不同 Python 对象)

4.2 梯度累加问题

x=torch.tensor(2.0,requires_grad=True)y=x**2y.backward()print(x.grad)# 4.0# 再次 backward 会累加!y=x**2y.backward()print(x.grad)# 8.0(累加了)# 解决方法:每次 backward 前清零x.grad.zero_()

五、拼接与微分总结

操作方法说明关键参数
cattorch.cat(tensors, dim)沿现有维度拼接dim 指定拼接轴
stacktorch.stack(tensors, dim)在新维度拼接增加一个新维度
chunktorch.chunk(tensor, chunks, dim)均分张量chunks 份数
splittorch.split(tensor, sizes, dim)按大小拆分sizes 每份大小
requires_gradrequires_grad=True开启梯度追踪默认 False
backward.backward()计算梯度标量输出直接调用
detach.detach()脱离计算图共享数据,无梯度
grad.grad访问梯度值backward 后才有值
zero_grad.grad.zero_()梯度清零避免累加

六、下一篇预告

PyTorch 深度学习笔记(六):PyTorch 实战——线性回归预测房价完整案例

将使用 PyTorch 的各个组件,构建一个带噪声数据的线性回归模型,模拟"房屋面积-房价"预测任务。包括数据准备、模型构建、损失函数、优化器、训练循环和可视化全流程。


如果这篇文章对你有帮助,欢迎点赞、收藏、关注!你的支持是我持续创作的动力。

http://www.jsqmd.com/news/1324737/

相关文章:

  • SpringBoot+Vue水质监测系统全栈开发实践
  • 2026年企业知识库管理工具排行榜 行业观察选型避坑指南
  • Hot-55 跳跃游戏
  • 【机器学习】随机森林算法——集成学习原理与垃圾邮件分类实战
  • 如何免费解锁Twitch订阅专属内容:3分钟安装完整指南
  • Python栈与队列实现:从list、deque到手动链表,性能与应用全解析
  • 英雄联盟Akari助手:免费开源的游戏自动化工具箱,提升你的竞技体验
  • 基于SSM框架的反诈骗平台开发实战
  • Qt 多线程架构从入门到精通:QThread 与 QtConcurrent 选型对比及实时波形卡顿治理
  • 腾讯云轻量服务器Docker容器化部署实战:从零到多应用管理
  • 3小时掌握BepInEx:Unity游戏插件开发从入门到实战
  • 3分钟打造专业级语音转文字工作流:Faster-Whisper-GUI完全指南
  • 第七天心得体会
  • 电赛通信协议设计:从帧结构到状态机,打造不丢数据的串口通信
  • Spring Boot入门指南:从零构建Java Web应用,告别配置地狱
  • 湘美书院谈AI系列经典哲学,奥德赛时期的等待者
  • 嵌入式学习笔记--liunx基础命令(unbantu)
  • 多物理场耦合仿真中的辐射传热建模与应用
  • Trae文件管理器紧凑模式优化指南
  • 飞书CLI与AI Agent融合:自然语言驱动办公自动化的实践指南
  • Django+微信小程序构建考研信息查询与推荐系统
  • Unity版本选择全攻略:从个人版到企业版,避坑指南与实战技巧
  • Wand-Enhancer终极指南:3步解锁完整游戏修改体验
  • 1. 2024年挑选高颜值匹克球拍,这几家厂商别错过(入围理由:时间代入+明确目标+动作引导)2. 新手选高颜值匹
  • 5分钟快速上手RVC变声器:零基础创建你的专属AI声优
  • 无锡代理记账服务深度解析:合规性与实操效率指南
  • 51单片机60个实战项目:从GPIO到物联网的嵌入式核心技能通关指南
  • 零侵入打通企业数据集成:不同厂商系统怎么连起来
  • Focal Loss与RetinaNet:解决目标检测中类别不平衡的新型损失函数
  • OpenClaw集成腾讯文档Skill:打造智能文档管理AI助手