PyTorch基础学习03_数学运算自动微分

news/2024/11/28 10:49:59/

目录

一、数学运算

1、基本操作

2、三角函数

3、统计学函数

二、保存和加载

三、并行化

四、自动微分

1、相关概念

2、计算梯度

1.标量梯度计算

2.向量梯度计算

3.多标量梯度计算

4.多向量梯度计算

5.矩阵梯度计算

3、梯度上下文控制

1、梯度控制

2、梯度更新

3、叶子节点


导入torch库:

import torch

一、数学运算

1、基本操作

  • floor: 向下取整;

  • ceil:向上取整;

  • round:四舍五入;

  • trunc:裁剪,只保留整数部分;

  • frac:只保留小数部分;

  • fix:向零方向舍入;

  • %:取余;

  • abs:取绝对值。

data = torch.tensor([[1, 2, -3.5],  # 1[4, 5, 6],  # 2[10.5, 18.6, 19.6],  # 3[11.05, 19.3, 20.6],  # 4]
)
print(data)
# 向下取整(往小取 返回不大于每个元素的最大整数)
x1 = torch.floor(data)
print(x1)
# 向上取整(往大取 返回不小于每个元素的最小整数)
x2 = torch.ceil(data)
print(x2)
# 四舍五入 与python round()一致 四舍六入五看齐(看个位奇偶,奇进偶舍)
x3 = torch.round(data)
print(x3)
# 截断,只保留整数部分
x4 = torch.trunc(data)
print(x4)
# 截断,只保留小数部分
x5 = torch.frac(data)
print(x5)
# 向零方向舍入(舍入到最接近零的整数)
x6 = torch.fix(data)
print(x6)
# 取余
x7 = torch.fmod(data, 2)
print(x7)
# 绝对值
x8 = torch.abs(data)
print(x8)

2、三角函数

  • torch.cos(input,out=None)

  • torch.cosh(input,out=None) # 双曲余弦函数

  • torch.sin(input,out=None)

  • torch.sinh(input,out=None) # 双曲正弦函数

  • torch.tan(input,out=None)

  • torch.tanh(input,out=None) # 双曲正切函数

# torch.set_printoptions(sci_mode=False)print(torch.pi) # 圆周率
deg = torch.pi/180
data = torch.tensor([0,90*deg,45*deg])
x1 = torch.sin(data)
print(x1)
x2 = torch.cos(data)
print(x2)
x3 = torch.sinh(data)
print(x3)
x4 = torch.cosh(data)
print(x4)
x5 = torch.tan(data)
print(x5)
x6 = torch.tanh(data)
print(x6)

3、统计学函数

  1. torch.mean(): 计算张量的平均值。

  2. torch.sum(): 计算张量的元素之和。

  3. torch.std(): 计算张量的标准差。

  4. torch.var(): 计算张量的方差。

  5. torch.median(): 计算张量的中位数。

  6. torch.max(): 计算张量的最大值。

  7. torch.min(): 计算张量的最小值。

  8. torch.mode():  计算张量众数

  9. torch.sort(): 对张量进行排序。 返回排序后的张量values和索引indices

  10. torch.topk(): 返回张量中的前 k 个最大值或最小值。

  11. torch.histc(): 计算张量的直方图。

  12. torch.unique(): 返回张量中的唯一值。

  13. torch.bincount(): 计算张量中每个元素的出现次数。

torch.manual_seed(66)
x = torch.tensor([1,2,2,3,3,3,4,4,5]).type(torch.float32)
print(x)
# 平均值
x1 = x.mean()
print(x1)
# 求和
x2 = x.sum()
print(x2)
# 标准差
x3 = x.std()
print(x3)
# 方差
x4 = x.var()
print(x4)
# 中位数
x5 = x.median()
print(x5)
# 最大值
x6 = x.max()
print(x6)
# 最小值
x7 = x.min()
print(x7)
# 众数
x8 = torch.mode(x)
print(x8)
# 排序 返回排序后的张量values和索引indices
x9 = torch.sort(x)
print(x9)x = torch.tensor([1,2,2,3,3,3,4,4,5,2,3,4,6]).type(torch.float32)
print(torch.topk(x,3)) # 返回前3个最大值
print(torch.histc(x,bins=10, min=2,max=4)) # 区间[min,max]分成bins份 表示各个区间的元素计数
print(torch.unique(x)) # 返回分类的数据集中的数据类型x = torch.tensor([1,2,2,3,3,3,4,4,5,2,3,4,6])
print(torch.bincount(x)) # 返回张量中每个元素的出现次数

二、保存和加载

# 保存
x = torch.tensor([1,2,3])
torch.save(x,'./data/tensor01.pth')device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 加载
y = torch.load('./data/tensor01.pth',map_location=device)
print(y)
print(y.device)

三、并行化

在 PyTorch 中,可以查看和设置用于 CPU 运算的线程数。PyTorch 使用多线程来加速 CPU 运算,但有时可能需要调整线程数来优化性能。

# torch.get_num_threads() 来查看当前 PyTorch 使用的线程数
def test01():count = torch.get_num_threads()print(count)# torch.set_num_threads() 设置 PyTorch 使用的线程数
def test02():torch.set_num_threads(4)count = torch.get_num_threads()print(count)if __name__ == '__main__':test01()test02()

 设置线程数时,确保考虑到你的 CPU 核心数和其他进程的资源需求,以获得最佳性能。

注意事项

  • 线程数设置过高可能会导致线程竞争,反而降低性能;

  • 线程数设置过低可能会导致计算资源未得到充分利用;

  • 当使用 GPU 进行计算时,线程数设置对性能影响较小,因为 GPU 计算并不依赖于 CPU 线程数。

四、自动微分

自动微分模块torch.autograd负责自动计算张量操作的梯度,具有自动求导功能。自动微分模块是构成神经网络训练的必要模块,可以实现网络权重参数的更新,使得反向传播算法的实现变得简单而高效。

1、相关概念

  1. 张量

    Torch中的对象都为张量,属性requires_grad决定是否对其进行梯度计算。默认是 False,如需计算梯度则设置为True。

  2. 计算图

    torch.autograd通过创建一个动态计算图来跟踪张量的操作,每个张量是计算图中的一个节点,节点之间的操作构成图的边。

  3. 反向传播

    使用tensor.backward()方法执行反向传播,从而计算张量的梯度。这个过程会自动计算每个张量对损失函数的梯度。

  4. 梯度

    计算得到的梯度通过tensor.grad访问,这些梯度用于优化模型参数,以最小化损失函数。

2、计算梯度

使用tensor.backward()方法执行反向传播,以计算张量的梯度。

1.标量梯度计算
# 创建张量:要计算梯度则必须为浮点类型
x = torch.tensor(3, require_grad=True, dtype=torch.float64)
# 定义函数
y = x**2 + 2*x - 5
# 计算梯度,也就是反向传播
y.backward() # # 梯度计算 1.y函数对x求导函数 y'=2*x+2 2.代入x的当前值 x=3 3.求出导数值 y'=2*3+2
# 读取梯度值
print(x.grad) # tensor(8.)
2.向量梯度计算
# 向量梯度计算
x = torch.tensor([1,2,3],requires_grad=True,dtype=torch.float64)
y = x**2 + 2*x - 5
print(y) # tensor([-2.,  3., 10.], dtype=torch.float64, grad_fn=<SubBackward0>)y = y.sum() # y必须是一个标量才能用这个标量对x求导 设置一个复合函数y.backward() # y'=2x+2
print(x.grad) # tensor([4., 6., 8.], dtype=torch.float64)
3.多标量梯度计算
# 多标量的梯度计算
x1 = torch.tensor(1,requires_grad=True,dtype=torch.float64)
x2 = torch.tensor(2,requires_grad=True,dtype=torch.float64)
y = x1**2 + 3*x2 - 5y.backward() # 偏导数print(x1.grad)
print(x2.grad)
4.多向量梯度计算
# 多向量的梯度计算
x1 = torch.tensor([1,2,3],requires_grad=True,dtype=torch.float64)
x2 = torch.tensor([4,5,6],requires_grad=True,dtype=torch.float64)
y = x1**2 + 3*x2 - 5y = y.sum()y.backward() # 偏导数
print(x1.grad) # 2*x1 tensor(2., dtype=torch.float64)
print(x2.grad) # 3 tensor(3., dtype=torch.float64)
5.矩阵梯度计算
# 矩阵梯度计算
x = torch.tensor([[1,2],[3,4]],requires_grad=True,dtype=torch.float64)
y = x**2 + 2*x - 5y = y.sum()y.backward()
print(x.grad)

3、梯度上下文控制

梯度计算的上下文控制和设置对于管理计算图、内存消耗、以及计算效率至关重要。

1、梯度控制

梯度计算是有性能开销的,有些时候只是简单的运算,此时并不需要梯度。

# 正常情况下
def test01():x = torch.tensor(10.5, requires_grad=True)print(x.requires_grad)  # True# 默认y的requires_grad=Truey = x**2 + 2 * x + 3print(y.requires_grad)  # Truedef test02():x = torch.tensor(5, requires_grad=True,dtype=torch.float64)# 关闭y的梯度计算 使用with进行上下文管理with torch.no_grad():y = x**2 + 2*x - 5print(y.requires_grad) # False# 使用装饰器
@torch.no_grad()
def test03():x = torch.tensor([1,2,3], requires_grad=True,dtype=torch.float64)y = x**2 + 2*x - 5y = y.sum()print(y.requires_grad) # False# 自己创建装饰器
def my_no_grad(func):def wrapper(): with torch.no_grad():re = func()return rereturn wrapper@my_no_grad
def test04():x = torch.tensor([1,2,3], requires_grad=True,dtype=torch.float64)y = x**2 + 2*x - 5y = y.sum()print(y.requires_grad) # False# 全局设置关闭梯度计算
def test05():x = torch.tensor([1,2,3], requires_grad=True,dtype=torch.float64)torch.set_grad_enabled(False)y = x**2 + 2*x - 5y = y.sum()y.backward()print(x.requires_grad)print(y.requires_grad)print(x.grad)# 累计梯度
def test06():x = torch.tensor(1, requires_grad=True,dtype=torch.float64)y = x**2 + 2*x - 5y.backward()print(x.grad)y = 2*x**2 + 7y.backward()print(x.grad)# 累计梯度02
def test07():x = torch.tensor(4, requires_grad=True,dtype=torch.float64)for _ in range(4):y = x**2 + 2*x - 5y.backward()print(x.grad)# 梯度清零
def test08():x = torch.tensor(4, requires_grad=True,dtype=torch.float64)y = x**2 + 2*x - 5y.backward() # 2*x + 2print(x.grad)z = 3*x**2 + 7*x# 清零x.grad.zero_() # 不清零则为 10+31=41z.backward() # 清零后为 6*4+7=31print(x.grad)# 综合梯度清零操作for _ in range(3):y = x**2 + 2 * x + 7z = y.mean()# 反向传播之前先对梯度进行清零if x.grad is not None:x.grad.zero_()z.backward()print(x.grad)if __name__ == '__main__':test01()test02()test03()test04()test05()test06()test07()test08()
2、梯度更新

大多数情况下是不需要梯度累加的,反向传播之前可以先用 .zero_() 对梯度进行清零。

更新梯度时,注意更新的数据应是data,直接改变原tensor会导致其变成新的数据。

# 标量训练
def test01():# 生成初始化ww = torch.tensor(25., requires_grad=True)# 训练参数lr = 0.01epoch = 5for i in range(epoch):# 生成损失函数loss = 3*w**2 + 2*w - 5# 梯度清零if w.grad is not None: w.grad.zero_()# 反向传播 求当前w的导数值:梯度值,斜率loss.backward()# 当前斜率print(w.grad)# 更新梯度# w的tensor不能修改 避免w变成新的数据 应修改w.dataw.data = w.data - lr*w.grad.dataprint(w)# 访问训练后的w的值print(w.data)# 向量训练
def test02():# 生成初始化ww = torch.tensor([10,20,30], requires_grad=True,dtype=torch.float64)# 训练参数lr = 0.01epoch = 5for i in range(epoch):# 生成损失函数loss = 3*w**2 + 2*w - 5loss = loss.sum() # 设置一个复合函数# 梯度清零if w.grad is not None: w.grad.zero_()# 反向传播 求当前w的导数值:梯度值,斜率loss.backward()# 当前斜率print(w.grad)# 更新梯度# w的tensor不能修改 避免w变成新的数据 应修改w.dataw.data = w.data - lr*w.grad.dataprint(w)# 访问训练后的w的值print(w.data)# 保存训练好的权重数据torch.save(w.data,'./data/weight.pth')# 加载训练好的权重数据
def detect():w = torch.load('./data/weight.pth',map_location='cuda')# 使用wprint(w)if __name__ == '__main__':# test01()test02()detect()
3、叶子节点

当想使用不含求导功能的tensor时,可以使用detach()创建张量,该张量是作为叶子结点存在的,并且该张量和原张量共享数据,只是该张量不需要计算梯度。

原因:可以求导的张量不能直接当作普通的tensor使用,如转换为numpy数组操作: .numpy()

# detach()产生的张量是作为叶子结点存在的,并且该张量和原张量共享数据,只是该张量不需要计算梯度。
def test01():x = torch.tensor([1, 2, 3], requires_grad=True,dtype=torch.float32)# x1 = x.numpy() # 报错 如果x是一个可以求导的张量,那么它就不能直接当作普通的tensor使用def test02():x = torch.tensor([1, 2, 3], requires_grad=True,dtype=torch.float32)x2 = x.detach() # 创建一个叶子结点,并且和x共享数据,但是不需要计算梯度print(x) # tensor([1., 2., 3.], requires_grad=True)print(x2) # tensor([1., 2., 3.])print(id(x),id(x2)) # 两个对象print(id(x.data),id(x2.data)) # 数据共享x2[0] = 5print(x,x2)if __name__ == '__main__':test02()


http://www.ppmy.cn/news/1550598.html

相关文章

echarts使用示例

柱状图折线图 折柱混合&#xff1a;https://echarts.apache.org/examples/zh/editor.html?cmix-line-bar option {title:{show: true},tooltip: {trigger: axis,axisPointer: {type: cross,crossStyle: {color: #999}}},toolbox: {feature: {dataView: { show: true, readOnl…

Ubuntu20.04运行DM-VIO

目录 环境配置非ROS环境运行编译运行结果图 ROS环境参考 环境配置 Ubuntu20.04 将项目中Cmakelists.txt中C 和 opencv版本修改下 C 使用 14 opencv使用4 非ROS环境运行 编译 按照官网即可 cd dm-vio mkdir build cd build cmake .. make -j运行 DM-VIO给的命令是 bin/d…

在 JavaScript 中,将一个十进制字符串转为二进制的方法

在 JavaScript 中&#xff0c;可以使用以下几种方法将一个十进制字符串转为二进制&#xff1a; 方法一&#xff1a;使用 parseInt() 和 toString() 首先&#xff0c;使用 parseInt() 函数将十进制字符串转换为十进制整数。 parseInt() 函数会解析传入的字符串&#xff0c;并根…

firewalld防火墙阻止docker容器间通信的排查思路及解决方案

摘要 现有两个docker容器nginx、openjdk分别部署前后端服务&#xff0c;假设默认防火墙为firewalld&#xff0c;发现在默认配置下&#xff0c;本地直接curl后台服务器能正确响应&#xff0c;nginx的代理的请求proxy_pass无法得到后台服务器的响应&#xff0c;只得到502 BadGat…

[产品管理-156]:《领先的密码-BLM方法论全面解读与应用指南》- 全书概述

目录 前言&#xff1a; 一、BLM方法论概述 二、BLM方法论的核心要素 三、BLM方法论的应用指南 四、BLM方法论的实际应用案例 五、总结 前言&#xff1a; “领先的密码&#xff1a;BLM方法论全面解读与应用指南”这一主题涉及对Business Leadership Model&#xff08;业务…

DataWhale—PumpkinBook(TASK06神经网络)

课程开源地址及相关视频链接&#xff1a;&#xff08;当然这里也希望大家支持一下正版西瓜书和南瓜书图书&#xff0c;支持文睿、秦州等等致力于开源生态建设的大佬✿✿ヽ(▽)ノ✿&#xff09; Datawhale-学用 AI,从此开始 【吃瓜教程】《机器学习公式详解》&#xff08;南瓜…

探索 Python 任务自动化的新境界:Invoke 库揭秘

文章目录 探索 Python 任务自动化的新境界&#xff1a;Invoke 库揭秘背景&#xff1a;为何选择 Invoke&#xff1f;什么是 Invoke&#xff1f;如何安装 Invoke&#xff1f;5个简单的库函数使用方法1. 定义任务2. 带参数的任务3. 运行 Shell 命令4. 任务参数化5. 列出任务 场景应…

【竞技宝】LOL-传奇杯:KB3-1击败M3

北京时间2024年11月27日,英雄联盟第二届传奇杯正在如火如荼的进行之中。昨天首场比赛迎来胜者组首轮KB(leyan队)对阵M3(icon队)。本场比赛M3以出色的表现拿下首局之后被KB打出完美运营连追两局,最后一局更是在大优势的情况下接连出现失误被KB翻盘,最终KB3-1击败M3。以下是本场比…