PyTorch学习(1):张量(Tensor)核心操作详解

PyTorch学习(1):张量(Tensor)核心操作详解

一、张量(Tensor)核心操作详解

张量是PyTorch的基础数据结构,类似于NumPy的ndarray,但支持GPU加速和自动微分。

1. 张量创建与基础属性
import torch# 创建张量
a = torch.tensor([1, 2, 3])  # 从列表中创建
print(a)
b = torch.zeros(2, 3)   # 2*3零矩阵
print(b)
c = torch.ones_like(b)   # 与b同形的全1矩阵
print(c)
d = torch.rand(3, 4)  # 3*4随机矩阵
print(d)
e = torch.arange(0, 10, 2)  # [0,2,4,6,8]
print(e)# 关键属性查看
print(f"形状: {d.shape}")  # torch.Size([3, 4])
print(f"数据类型:{d.dtype}")  # torch.float32
print(f"存储设备: {d.device}") # cpu 或 cuda:0

2. 张量运算与广播机制
x = torch.tensor([[1, 2], [3, 4]])
y = torch.tensor([[5], [6]])
print(x)
print(y)# 基本计算
add =x + y   # 广播加法:[[6,7], [9,10]]
mul =x * 2   # 标量乘法:[[2,4], [6,8]]
print(add)
print(mul)# 高级运算
sum_x =torch.sum(x,dim=0)  # 沿列求和:[4,6]
max_val,max_idx=torch.max(x,dim=1) # 每行最大值和索引
exp_x =torch.exp(x)  # 指数运算
print(sum_x)
print(max_val,max_idx)
print(exp_x)

3. 形状操作与内存管理
z = torch.arange(12)
print(z)# 形状变换(不复制数据)
z_view =z.view(3,4)  # 视图变形,3*4矩阵
print(z_view)
z_reshape = z.reshape(2,6)
print(z_reshape)# 内部复制
z_clone = z.clone()  # 显性复制数据
z_transpone =z_view.T # 转置(共享数据)
print(z_clone)
print(z_transpone)# 维度操作
print(f"原始形状:{z.shape}")
unsqueezed = z.unsqueeze(0) # 增加维度:形状从(12,)变成(1,12)
print(f"增加维度后的形状:{unsqueezed.shape}")
print(unsqueezed)squeezed = unsqueezed.squeeze(0) # 压缩维度:shape(12)
print(f"压缩维度后的形状:{squeezed.shape}")

4. 与NumPy互操作
import numpy as np# Tensor → NumPy
tensor = torch.rand(2,3)
print (tensor)
numpy_array = tensor.numpy() # 共享内存(CPU张量)
print (numpy_array)# NumPy → Tensor
np_arr = np.array([[1,2],[3,4]])
print (np_arr)
new_tensor = torch.from_numpy(np_arr)  # 共享内存
print (new_tensor)# 显式内存复制
safe_tensor = torch.tensor(np_arr)
print (safe_tensor)

5、检查设备

# 检测GPU可用性
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

二、动态计算图与自动微分(Autograd)

1. 计算图基本原理

PyTorch使用动态计算图,运算时实时构建计算图,示例1:

# 创建需要跟踪梯度的张量
x = torch.tensor(2.0,requires_grad=True)
print(x)# 定义一个简单的函数 y = x^2
y = x ** 2# 计算 y 关于 x 的梯度
y.backward()  # 执行反向传播# 查看梯度值 dy/dx = 2x = 2*2 = 4
print(x.grad)  # 输出: tensor(4.)

  1. torch.tensor(2.0)
    创建一个值为 2.0 的标量张量(即单元素张量),数据类型默认是torch.float32

  2. requires_grad=True
    这是一个关键参数,它告诉 PyTorch 需要跟踪这个张量的所有操作,以便之后进行自动求导。设置为True后,PyTorch 会构建一个计算图,记录所有依赖于x的操作,从而在需要时通过反向传播(backpropagation)自动计算梯度。

在这个例子中,由于xrequires_grad=True,PyTorch 记录了y = x²的计算过程,并在调用y.backward()时自动计算了梯度dy/dx,结果存储在x.grad中。

为什么需要这样做?

在深度学习中,梯度是优化模型参数的关键。例如,在神经网络训练时,我们需要计算损失函数对模型参数的梯度,以便使用梯度下降等优化算法更新参数。通过将requires_grad设置为True,PyTorch 会自动记录所有对该张量的操作,从而在调用backward()方法时计算梯度。

这种自动计算梯度的能力是深度学习框架(如 PyTorch、TensorFlow)的核心优势之一,它让我们无需手动推导复杂模型的导数公式,就能高效训练神经网络。

PyTorch使用动态计算图,运算时实时构建计算图,示例2:

# 创建需要跟踪梯度的张量
x = torch.tensor(2.0, requires_grad=True)
# 定义一个函数 y = x**3 + 2*x + 1
y = x**3 + 2*x + 1
# 再进行函数
z = torch.sin(y)z.backward()  # 反向传播自动计算梯度print(x.grad)  # dz/dx = dz/dy * dy/dx = cos(y)*(3x²+2)

2. 梯度计算模式

这是更灵活的显式梯度计算方式,适用于复杂场景

# 示例:计算偏导数
u = torch.tensor(1.0, requires_grad=True)
v = torch.tensor(2.0, requires_grad=True)
f = u**2 + 3*v# 计算梯度
grads = torch.autograd.grad(f, [u, v])  # (df/du, df/dv)
print(grads)  # (tensor(2.), tensor(3.))
  • requires_grad=True 告诉 PyTorch 跟踪这些张量的所有操作,以便后续计算梯度。
  • \(u = 1.0\) 和 \(v = 2.0\) 是初始值,用于计算梯度的具体数值。

定义了一个二元函数 \(f(u, v) = u^2 + 3v\)。在深度学习中,这类似一个损失函数,我们需要计算它对参数的梯度。


 

核心区别
操作用途结果存储适用场景
z.backward()计算 z 对所有 requires_grad=True 的叶子节点张量的梯度,并累积到 .grad 属性中。梯度存储在叶子节点的 .grad 属性中。标准的反向传播(如训练神经网络)。
torch.autograd.grad(f, [u, v])显式计算 f 对指定张量 [u, v] 的梯度,返回梯度张量组成的元组。梯度作为元组直接返回,不修改原有张量。需要自定义梯度计算路径(如多输出模型)
3. 梯度控制技巧
import torch
import torch.optim as optim# 初始化参数
x = torch.tensor(2.0, requires_grad=True)
w = torch.tensor(3.0, requires_grad=True)
b = torch.tensor(1.0, requires_grad=True)# 创建优化器
optimizer = optim.SGD([x, w, b], lr=0.01)# 1. 梯度累积清零
optimizer.zero_grad()  # 训练循环中必须的操作
print(f"初始梯度 x.grad: {x.grad}")  # 输出: None# 前向传播
y = x * w + b
loss = (y - 10)**2  # 假设目标值为10# 反向传播
loss.backward()
print(f"第一次反向传播后 x.grad: {x.grad}")  # 输出: tensor(12.)# 再次反向传播(梯度会累积)
loss.backward()
print(f"第二次反向传播后 x.grad: {x.grad}")  # 输出: tensor(24.)# 梯度清零
optimizer.zero_grad()
print(f"optimizer.zero_grad() 后 x.grad: {x.grad}")  # 输出: tensor(0.)# 2. 冻结梯度
with torch.no_grad():z = x * 2  # 不会追踪计算历史
print(f"z.requires_grad: {z.requires_grad}")  # 输出: False# 3. 分离计算图
a = x * w
detached = a.detach()  # 创建无梯度关联的副本
print(f"detached.requires_grad: {detached.requires_grad}")  # 输出: False# 4. 修改requires_grad
x.requires_grad_(False)  # 关闭梯度追踪
print(f"修改后 x.requires_grad: {x.requires_grad}")  # 输出: False# 验证修改后的效果
try:y = x ** 2y.backward()  # 会报错,因为x.requires_grad=False
except RuntimeError as e:print(f"错误: {e}")  # 输出: element 0 of tensors does not require grad and does not have a grad_fn
总结对比表

optimizer.zero_grad()  # 训练循环中必须的操作
torch.no_grad() # 梯度清零
操作作用范围是否影响原张量是否释放内存典型场景
optimizer.zero_grad()优化器管理的所有参数是(梯度清零)每个训练迭代前
torch.no_grad()上下文内的所有计算推理阶段、无需梯度的计算
a.detach()单个张量否(创建新张量)截断梯度流、固定部分网络
x.requires_grad_(False)单个张量是(原地修改)冻结预训练模型参数
代码说明:
  1. 梯度累积清零

    • 两次调用 loss.backward() 会累积梯度
    • optimizer.zero_grad() 将梯度重置为零
  2. 冻结梯度

    • with torch.no_grad() 块内的计算不会追踪梯度
    • 输出张量 z 的 requires_grad 为 False
  3. 分离计算图

    • a.detach() 创建与计算图分离的新张量
    • 修改分离后的张量不会影响原梯度计算
  4. 修改 requires_grad

    • x.requires_grad_(False) 原地修改张量属性
    • 后续尝试对 x 进行反向传播会报错
注意事项:
  • 实际训练中,optimizer.zero_grad() 应在每个训练迭代开始时调用
  • torch.no_grad() 常用于推理阶段以提高性能
  • detach() 适用于需要固定部分网络参数的场景
  • 修改 requires_grad 是永久性的,需谨慎操作
4. 梯度检查(调试技巧)
import torch
def grad_check():x = torch.tensor(3.0, requires_grad=True)y = x ** 2# 理论梯度y.backward()analytic_grad = x.grad.item()# 数值梯度(修正:使用 x.item() 而非硬编码 3.0)eps = 1e-5y1 = (x.item() + eps) ** 2y2 = (x.item() - eps) ** 2numeric_grad = (y1 - y2) / (2 * eps)print(f"解析梯度: {analytic_grad:.6f}, 数值梯度: {numeric_grad:.6f}")assert abs(analytic_grad - numeric_grad) < 1e-6# 调用函数
grad_check()

这段代码实现了一个简单的 ** 梯度验证(Gradient Check)** 功能,用于验证 PyTorch 自动微分计算的梯度是否与数值计算的梯度一致。

1. 定义测试函数和输入
x = torch.tensor(3.0, requires_grad=True)
y = x ** 2
2. 计算解析梯度(Analytical Gradient)
y.backward()
analytic_grad = x.grad.item()

3. 计算数值梯度(Numerical Gradient)
eps = 1e-5
y1 = (x.item() + eps) ** 2
y2 = (x.item() - eps) ** 2
numeric_grad = (y1 - y2) / (2 * eps)

4. 验证结果

print(f"解析梯度: {analytic_grad:.6f}, 数值梯度: {numeric_grad:.6f}")
assert abs(analytic_grad - numeric_grad) < 1e-6

打印结果:解析梯度: 6.000000, 数值梯度: 6.000000

关键知识点

  1. 自动微分(Autograd): PyTorch 通过跟踪计算图自动计算梯度,无需手动推导公式。

  2. 数值微分: 数值方法是验证梯度计算正确性的重要工具,但计算效率低,仅用于测试。

  3. 梯度验证的重要性: 在实现复杂模型(如自定义层或损失函数)时,梯度验证能帮助发现反向传播中的错误。

潜在问题与改进

  1. 步长 \(\epsilon\) 的选择: 太小会导致数值误差(如浮点数舍入),太大会降低近似精度。

  2. 多维张量支持: 当前代码仅支持标量输入,扩展到多维张量需为每个元素计算数值梯度。

  3. 高阶导数验证: 对于二阶或更高阶导数,需使用更复杂的数值方法。

这个简单的验证函数是深度学习开发中的重要调试工具,特别是在实现自定义操作或优化算法时。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/82979.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker部署Spark大数据组件:配置log4j日志

上一篇《Docker部署Spark大数据组件》中&#xff0c;日志是输出到console的&#xff0c;如果有将日志输出到文件的需要&#xff0c;需要进一步配置。 配置将日志同时输出到console和file 1、停止spark集群 docker-compose down -v 2、使用自带log4j日志配置模板配置 cp -f …

Nginx Lua模块(OpenResty)实战:动态化、智能化你的Nginx,实现复杂Web逻辑 (2025)

更多服务器知识&#xff0c;尽在hostol.com 嘿&#xff0c;各位Nginx的“铁杆粉丝”和“配置大师”们&#xff01;咱们都知道&#xff0c;Nginx以其超凡的性能、稳定性和丰富的模块化功能&#xff0c;在Web服务器、反向代理、负载均衡等领域独步青云&#xff0c;简直是服务器软…

一、CentOS7通过kubeadm安装K8S 1.20.1版本

一、准备机器 所有节点执行 准备3台虚拟机&#xff08;2核4G&#xff0c;CentOS 7&#xff09;&#xff0c;配置如下&#xff1a; hostnamectl set-hostname k8s-master # 在Master节点执行 hostnamectl set-hostname k8s-node1 # Worker1节点执行 hostnamectl set-hostna…

AgenticSeek,开源本地通用AI Agent,自主执行任务

AgenticSeek是一款完全本地化的开源AI助手&#xff0c;作为Manus的开源替代品&#xff0c;专为保护用户隐私而设计。它能够在本地设备上执行多种任务&#xff0c;包括网页浏览、代码编写和复杂项目的规划&#xff0c;确保所有操作和数据均在用户的设备上完成。 AgenticSeek是什…

C 语言学习笔记(指针6)

内容提要 内存操作 内存操作的函数 内存操作 我们对于内存操作需要依赖于string.h头文件中相关的库函数。 内存的库函数 内存填充 头文件&#xff1a;#include <string.h>函数原型 void* memset(void* s, int c, size_t)函数功能&#xff1a;将内存块s的前n个字节…

Grafana-Gauge仪表盘

仪表盘是一种单值可视化。 可让您快速直观地查看某个值落在定义的或计算出的最小和最大范围内的位置。 通过重复选项&#xff0c;您可以显示多个仪表盘&#xff0c;每个对应不同的序列、列或行。 支持的数据格式 单值 数据集中只有一个值&#xff0c;会生成一个显示数值的…

解决Vue项目依赖错误:使用electron-vite重建

文章目录 开端解决方案&#xff1a;使用 electron-vite Vue 重建项目1. 环境准备2. 创建新项目3. 安装依赖并启动项目 开端 在开发过程中&#xff0c;我遇到了一个令人头疼的错误提示&#xff1a; 0:0 error Parsing error: Cannot find module vue/cli-plugin-babel/preset…

WPF prism

Prism Prism.Dryloc 包 安装 Nuget 包 - Prism.DryIoc 1. 修改 App.xaml 修改 App.xaml 文件&#xff0c;添加 prism 命名空间, 继承由 Application → PrismApplication&#xff0c;删除默认启动 url, StartupUri“MainWindow.xaml” <dryioc:PrismApplicationx:Class…

循序渐进PersistentVolumes与PersistentVolumeClaim

文章目录 静态配置&#xff08;Static Provisioning&#xff09;&#xff1a;Persistent volume(PV)Local 示例&#xff1a;NFS 示例&#xff1a;检查pvPV 的常见状态说明Persistent volume claim(PVC)1. local PVC示例:2.NFS PVC示例:3. 检查PVC: 挂载静态供应卷验证静态供应卷…

【连接器专题】SD卡座规格书审查需要审哪些方面?

在审查SD卡座规格书时,我们需要考虑哪些方面? 首先在拿到一份SD卡座的详细规格书时,一般供应商给到的规格书中包括了一些基础信息、产品图纸信息、技术参数信息,同时有些供应商会给出产品可靠性测试报告。因此我们会从这几个要素去看规格书。 基础信息 基础信息一般会给变更…

投稿 IEEE Transactions on Knowledge and Data Engineering 注意事项

投稿 IEEE Transactions on Knowledge and Data Engineering 注意事项 要IEEE overleaf 模板私信,我直接给我自己论文,便于编辑 已经投稿完成了,有一些小坑 准备工作 注册IEEE账户:若没有IEEE账户,需前往IEEE官网注册。注册成功后,可用于登录投稿系统。现在新的系统,…

JS入门——三种输入方式

JS入门——三种输入方式 一、方式一&#xff1a;直接在警告框弹出(window可以省略) <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><body><script><!-- 方式一直接在警告框弹…

WordPress免费网站模板下载

大背景图免费wordpress建站模板 这个wordpress模板设计以简约和专业为主题&#xff0c;旨在为用户提供清晰、直观的浏览体验。以下是对其风格、布局和设计理念的详细介绍&#xff1a; 风格 简约现代&#xff1a;整体设计采用简约风格&#xff0c;使用了大量的白色和灰色调&am…

AUTOSAR CP全新系统化培训上线!从底层到应用,三步阶梯,五大学习维度构建完整知识体系

AUTOSAR组织 AUTOSAR官方全新推出「AUTOSAR CP全栈赋能计划」&#xff0c;从架构全景到模块细节&#xff0c;自底向上、由浅入深&#xff0c;覆盖MCAL至SWC全层级&#xff0c;融合通信、诊断、安全等六大核心Feature&#xff0c;带您穿透复杂理论&#xff0c;直击AUTOSAR开发本…

Java网络编程与Socket安全权限详解

Socket安全权限控制 Java通过java.net.SocketPermission类实现对网络套接字访问的细粒度控制。该权限管理机制通常在Java策略文件中配置,其标准授权语法格式如下: grant {permission java.net.SocketPermission"target", "actions"; };目标主机与端口规…

基于本地化大模型的智能编程助手全栈实践:从模型部署到IDE深度集成学习心得

近年来&#xff0c;随着ChatGPT、Copilot等AI编程工具的爆发式增长&#xff0c;开发者生产力获得了前所未有的提升。然而&#xff0c;云服务的延迟、隐私顾虑及API调用成本促使我探索一种更自主可控的方案&#xff1a;基于开源大模型构建本地化智能编程助手。本文将分享我构建本…

视频监控汇聚平台EasyCVR安防小知识:如何通过视频融合平台解决信息孤岛问题?

一、项目背景与需求分析​ 随着数字化技术发展与网络带宽升级&#xff0c;视频技术应用场景不断拓展&#xff0c;视频监控、记录仪等多样化产品构建起庞大体系。但这些独立系统彼此割裂&#xff0c;形成信息孤岛。 在系统集成项目中&#xff0c;视频系统深度融合已成必然趋势…

如何在 Windows 和 Mac 上擦拭和清洁希捷外置硬盘

希捷外置硬盘广泛用于存储目的&#xff0c;但有时您可能出于多种目的需要擦除或清洁希捷外置硬盘&#xff0c;例如转售、重复使用、捐赠等。为了释放硬盘上的存储空间或确保没有人可以从硬盘中恢复您的信息&#xff0c;擦除硬盘是必要的步骤。无论您使用的是 Windows 还是 Mac&…

SAP saml2 元数据 HTTP 错误

使⽤事务 SAML2 或 SAML2_IDP 在 ABAP 系统中配置 SAML 2.0 时&#xff0c; Web 页⾯返回 403 已禁⽌、 404 未找到 或 500 服务器内部错误。 在事务 SAML2 中下载元数据时&#xff0c; ⽹页返回 403 已禁⽌、 404 未找到或 500 服务器内部错误。 在事务 SAML2_IDP 中下载…

powershell 中 invoke-expression 报错解决

打开powershell就出现这个报错&#xff1a; 网上搜了也没有很好的解决办法&#xff0c;抱着一点点期待&#xff0c;问了豆包 根据豆包的指示&#xff0c;在终端执行以下 几个命令&#xff0c;报错解决了&#xff08;开心万岁&#xff09; # 移除多余的引号和空路径 $pathArra…