热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

jupyternotebookpytorch_PyTorch和优化器

这段话来自非洲经济女学家DambisaMoyo的《DeadAid》❝种一棵树最好的时间是十年前,其次是现在。--DambisaMoyo❞❝只要你心里有信念࿰

这段话来自 非洲经济女学家 Dambisa Moyo 的《Dead Aid》

种一棵树最好的时间是十年前,其次是现在。-- Dambisa Moyo

只要你心里有信念,没有时间的差距,什么时候开始都可以。

温馨提示:代码可能一行过长,可以左右滑动查看。

这篇文章的主要内容会围绕着如何使用 「PyTorch」 的优化器来展开。同样地,在这一篇文章中优化的函数还是一个简单的一元二次函数。

在我的 「机器学习」 系列文章中,还有两篇文章是和本篇文章相关的。在这两篇文章中着重的是介绍了其中一种 「优化器」 :「梯度下降法」。(其实就是一种优化函数的方法,只不过被大家称为 「优化器」)

「梯度下降法」 这篇文章主要详细地阐述了它的数学原理,随后使用一个简单的代码模拟了这个过程。

【链接】Gradient-Descent (梯度下降,优化函数大法)

【链接】PyTorch 和 自动求导

「PyTorch 和 自动求导」 这篇文章主要详细地阐述了怎样使用「PyTorch」 的 API(Application Interface)完成自动求导这个动作,毕竟求导是一件非常累人的事情。但是这篇文章并没有告诉大家怎样完成各个 「权重」 的自动更新,而仅仅是求出了每个 「权重」 变量的导数而已。

那么,在这一篇文章就算是作为上边提到的第二篇文章的一个补充:使用 「PyTorch」 完成 「自动更新权重」 这个动作。

1 什么是优化器?

在上边已经提到过了,简单来说,优化损失函数的方法就是优化器。而在这篇文章主要介绍 「梯度下降法」 这种优化器。其实,其他还有一些 「优化器」,基本上也都是在梯度下降法的基础上改进的。而且,值得一提的是:在 PyTorch 中优化器的接口形式都是一样的,会使用梯度下降法的 API (Application Interface)后,其他的也就会了。

2 目标函数

我们就使用一个一元二次函数作为我们优化的 「目标函数」 好啦。我就随便地写一个吧,就用它了!

从这个式子就可以看出,当 且 的时候 达到最小值。

3 优化目标函数

需要注意的是:我的代码都是在 Jupyter-Notebook 中运行的,所以我直接运行一个 Cell 的时候能输出当前代码的运行结果。

「加载模块」

首先,我加载了需要使用的模块,并且把刚才我 「随便写的」 那个目标函数的图像画了出来。好!下边儿就是这个过程的代码了!当然,还有图像也放了出来。

import torch
import numpy as np
import matplotlib.pyplot as plt

plot_x = np.linspace(-5, 7, 100)
plot_y = (plot_x - 1)**2 + 2

plt.plot(plot_x, plot_y)
plt.show()

待会,我们初始化的位置大概就是红色箭头指向的这个地方了,这里是 这个点的位置。

c707960ac465c3e8ba38441ed0135bd1.png
目标函数

「初始化 x 和 目标函数」

接下来,初始化一个 x,它是一个 torch.tensor 类型,待会我们每一次迭代的过程中更新的对象就是 x,并且最终 x 的值将会是最小值点的横坐标。x 是一个一维的向量,并且这个向量只有一个元素,初始值为 。因为要对 x 求导的,所以它应该是一个浮点类型的并且 「requires_grad=True」

在这里我还会定义一个函数 f,这个函数输入的值是目标函数的自变量,返回值就是目标函数的值。

def f(x):
    return torch.square(x-1)+2

x = torch.tensor([6], 
    dtype=torch.float32, 
    requires_grad=True)

好啦,让我们来看看,执行了上边的代码后,x 的具体状况。

43baad4dae6381221ebbbaa81d77d976.png
x 的状况

「给定学习率和迭代次数」

在这儿,我初始化两个变量,其中 「lr」 代表学习率,其实就是 「learning_rate」 。另外的 「iter」 代表迭代次数。另外还有两个列表,「all_x」 用来存储每一次 x 更新后的值,「all_loss」 用来存储每一次迭代后的损失的值。通过记录这些值,最后我们就可以可视化出来算法运行过程中的情况了。

lr = 0.05
iter = 1000

all_x = []
all_loss = []

「初始化 优化器」

我们只需要这样的一行代码就完成了优化器的初始化,其中的 SGD 代表的就是 「梯度下降法」。可以注意到,SGD() 这个对象的第一个参数是一个列表,这个列表中需要放入我们需要在每一次迭代过程中更新的变量,另外第二个参数是 lr,这就是告诉它我们使用的学习率的大小。


optimizer = torch.optim.SGD([x], lr=lr)

「开始优化」

for i in range(iter):
    loss = f(x)

    all_x.append(x.item())
    all_loss.append(loss.item())

    # 第 1 行
    optimizer.zero_grad()
    # 第 2 行
    loss.backward()
    # 第 3 行
    optimizer.step()

上边就是我们具体的优化过程的代码了。这将会迭代 「1000」 (iter 等于 1000) 次。用之前定义好的 f() 函数计算出损失的值 loss,这个过程就已经自动构成了 「计算图」。随后我们把当前的 x 的值放进 「all_x」 中,把当前的损失值放进 「all_loss」 中。使用 「item()」 方法会返回这个 「tensor」 中存储的值。

最重要的代码就是紧接着的下边的三行了,在代码中我用注释标注了这三行代码。

先来看,第 1 行:这个操作就和我们对需要求导的 「torch.tensor」 类型的变量的 「grad」 属性使用 「zero_()」 方法是一样的效果。这个操作会把优化器的第 1 个参数中所有的变量的梯度值归零,第 1 个参数就是刚才我们传入的列表(list),只不过我们这里的情况比较简单,在列表(list)中只有一个变量,当然,你可以传入很多个。

再来看,第 2 行:这个操作时作用在 「loss」 上的,因此会对 「loss」 相关的所有需要求导的变量进行求导操作。

最后,第 3 行:相信你已经知道了,我们只求完导数还不行,注意到,当前这个操作时作用在 「optimizer」 上的,所以,它会把那些我们放进列表(list)中的变量进行更新,这一步其实就是完成了下边儿这个非常眼熟的数学表达式所完成的工作。(数学表达式中的 代表学习率)

注意这个数学表达式,虽然我使用了偏微分符号,由于我们这里只有一个自变量,其实是和使用微分符号 表达的意思是一样的。

第 3 行就是完成了使用 「自己」 减去 「学习率」 乘以 「目标函数对自己的导数」 然后用得到的这个值去更新 「自己」 的这样一个过程。

「绘制 x 的轨迹」

通过下边的代码,就绘制出了所有 x 在更新过程中的路径,最终 x 在最小值点的附近停了下来。

plot_x = np.linspace(-5, 7, 100)
plot_y = (plot_x - 1)**2 + 2

plt.plot(plot_x, plot_y)

x_scatter = np.array(all_x)
y_scatter = np.array((x_scatter-1)**2 + 2)

plt.scatter(x_scatter, y_scatter, color='red')
plt.show()

e759c62de8378af7278cc656980b97e0.png
x 的轨迹

「如何绘制 loss 损失变化图」

绘制 loss 的图:我会生成从 「0」 开始一直到 「999」「1000」 个数字,这代表了每一次的迭代,这 「1000」 个数字用于图像的 「横坐标」,而它对应的 「纵坐标」 就是这每一次迭代过程中计算出的损失值的大小。

「绘制损失 loss 的变化」

loss_x = np.array(range(iter))
loss_y = np.array(all_loss)

plt.plot(loss_x, loss_y)
plt.show()

第 1 个 loss 轨迹图:

958af4b22eb46d55d2cc5d1971ad2359.png
第 1 个 loss 轨迹图

通过第 1 个 loss 轨迹图,我们会发现,损失值一下子就变得很小了,在后面很长的一段迭代过程中几乎都是没有什么变化的。因为横坐标的尺度太大了,我们几乎看不出来损失的变化过程是怎样的,所以我绘制第 2 个 loss 损失变化的图,在第 2 个图中,我将只绘制前 「50」 次迭代过程中 「loss」 的变化。

loss_x = np.array(range(iter))
loss_y = np.array(all_loss)

plt.plot(loss_x[:50], loss_y[:50])
plt.show()

第 2 个 loss 轨迹图:

3d697aca651f56e008e4e4393f20b62a.png
第 2 个 loss 轨迹图

「看看 x 最终的样子」

输出最后一次迭代后 x 的值,可以发现,它已经收敛到了最小值的位置。

a6acf10207fd647637e197e330889192.png
x 的最终结果

推荐阅读:【链接】

PyTorch 和 自动求导

Gradient-Descent (梯度下降,优化函数大法)

Logistic-Regression(逻辑斯蒂回归)

Logistic-Regression(损失函数梯度推导)

机器学习基础(4)-主成分分析法PCA(下)

机器学习基础(4)-主成分分析法PCA(上)

3fae4a5cb57fb141699a246fcdc7ca2b.png
酷酷的算法

如果喜欢我的文章,点个 「在看」 吧。谢谢你的支持。




推荐阅读
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了logistic回归(线性和非线性)相关的知识,包括线性logistic回归的代码和数据集的分布情况。希望对你有一定的参考价值。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文介绍了机器学习手册中关于日期和时区操作的重要性以及其在实际应用中的作用。文章以一个故事为背景,描述了学童们面对老先生的教导时的反应,以及上官如在这个过程中的表现。同时,文章也提到了顾慎为对上官如的恨意以及他们之间的矛盾源于早年的结局。最后,文章强调了日期和时区操作在机器学习中的重要性,并指出了其在实际应用中的作用和意义。 ... [详细]
  • 从零基础到精通的前台学习路线
    随着互联网的发展,前台开发工程师成为市场上非常抢手的人才。本文介绍了从零基础到精通前台开发的学习路线,包括学习HTML、CSS、JavaScript等基础知识和常用工具的使用。通过循序渐进的学习,可以掌握前台开发的基本技能,并有能力找到一份月薪8000以上的工作。 ... [详细]
  • 十大经典排序算法动图演示+Python实现
    本文介绍了十大经典排序算法的原理、演示和Python实现。排序算法分为内部排序和外部排序,常见的内部排序算法有插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。文章还解释了时间复杂度和稳定性的概念,并提供了相关的名词解释。 ... [详细]
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
  • 本文介绍了贝叶斯垃圾邮件分类的机器学习代码,代码来源于https://www.cnblogs.com/huangyc/p/10327209.html,并对代码进行了简介。朴素贝叶斯分类器训练函数包括求p(Ci)和基于词汇表的p(w|Ci)。 ... [详细]
  • 前言:拿到一个案例,去分析:它该是做分类还是做回归,哪部分该做分类,哪部分该做回归,哪部分该做优化,它们的目标值分别是什么。再挑影响因素,哪些和分类有关的影响因素,哪些和回归有关的 ... [详细]
  • cs231n Lecture 3 线性分类笔记(一)
    内容列表线性分类器简介线性评分函数阐明线性分类器损失函数多类SVMSoftmax分类器SVM和Softmax的比较基于Web的可交互线性分类器原型小结注:中文翻译 ... [详细]
  • 在本教程中,我们将看到如何使用FLASK制作第一个用于机器学习模型的RESTAPI。我们将从创建机器学习模型开始。然后,我们将看到使用Flask创建AP ... [详细]
  • 【论文】ICLR 2020 九篇满分论文!!!
    点击上方,选择星标或置顶,每天给你送干货!阅读大概需要11分钟跟随小博主,每天进步一丢丢来自:深度学习技术前沿 ... [详细]
  • Android系统移植与调试之如何修改Android设备状态条上音量加减键在横竖屏切换的时候的显示于隐藏
    本文介绍了如何修改Android设备状态条上音量加减键在横竖屏切换时的显示与隐藏。通过修改系统文件system_bar.xml实现了该功能,并分享了解决思路和经验。 ... [详细]
  • 背景应用安全领域,各类攻击长久以来都危害着互联网上的应用,在web应用安全风险中,各类注入、跨站等攻击仍然占据着较前的位置。WAF(Web应用防火墙)正是为防御和阻断这类攻击而存在 ... [详细]
  • 建立分类感知器二元模型对样本数据进行分类
    本文介绍了建立分类感知器二元模型对样本数据进行分类的方法。通过建立线性模型,使用最小二乘、Logistic回归等方法进行建模,考虑到可能性的大小等因素。通过极大似然估计求得分类器的参数,使用牛顿-拉菲森迭代方法求解方程组。同时介绍了梯度上升算法和牛顿迭代的收敛速度比较。最后给出了公式法和logistic regression的实现示例。 ... [详细]
author-avatar
桑正青0V1
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有