当前位置:首页 » 操作系统 » 优化算法ppt

优化算法ppt

发布时间: 2023-04-15 11:06:06

‘壹’ XGBoost与GBDT(一)-几种最优化方法对比

发现了作者的一个ppt GBDT算法原理与系统设计简介 ,从头复习了一波相关的内容,写两篇记录下来.
从根本上来说, GBDT 与XGBoost最大的区别在于二者用的优化方法不一样,所以从先从最优化方法开始复习.

最优化问题通常分为两个大类:

在机器学习中,典型的做法就是选择一个合适的模型 ,对该模型的损失函数 ,通过最优化的方法最小化损失函数,从而求解模型的参数.
最常见的几种优化方法包括[2]:

可以看出,虽然牛顿法收敛速度较快,但是每次迭代过程,计算海塞矩阵的逆过程相当繁琐,特别是当该矩阵维度较大时.因此就有了逆牛顿法,他使用正定矩阵来近似求海塞矩阵的逆.
拟牛顿法和梯度下降法一样只要求每一步迭代时知道目标函数的梯度,另外,因为拟牛顿法不需要二阶导数的信息,所以有时比牛顿法更为有效。常用的拟牛顿法有DFP算法和BFGS算法.此处不再赘述.
下面补充拟牛顿法的思路(摘自[3]):

共轭梯度法是一种用于解决无约束凸二次规划问题的方法.

启发式方法指人在解决问题时所采取的一种根据经验规则进行发现的方法。其特点是在解决问题时,利用过去的经验,选择已经行之有效的方法,而不是系统地、以确定的步骤去寻求答案。启发式优化方法种类繁多,包括经典的模拟退火方法、遗传算法、蚁群算法以及粒子群算法等等。

上面前三种算法,解决的问题都仅限于无约束的凸优化, 而拉格朗日乘数法则解决含有约束条件的优化问题,例如svm算法的解法推导.约束优化问题的一般形式是:

这个问题可以转化成函数 的无条件极值问题.
对于约束条件为不等式的问题,有科学家拓展了拉格朗日乘数法.增加了kkt条件以求解.没学过最优化,这块就没法细谈了.有机会一定要补上.

[1]Poll的笔记.常见的几种最优化方法[EB/OL]. https://www.cnblogs.com/maybe2030/p/4751804.html,2015-08-23 .
[2]超神冉.最优化算法——常见优化算法分类及总结[EB/OL]. https://blog.csdn.net/qq997843911/article/details/83445318,2018-10-27 .
[3]李航.统计学习方法[M].清华大学出版社:北京,2012:220.
[4]Ja1r0.共轭梯度法[EB/OL]. https://zhuanlan.hu.com/p/28623599,2018-05-28 .

‘贰’ 优化算法总结

本文介绍一下机器学习和深度学习中常用的优化算法和优化器以及一些其他我知道的优化算法,部分算法我也没有搞懂,就先记录下来以后慢慢研究吧.*_*.

1.梯度下降算法(Gradient Descent)

梯度下降法可以参考我另一篇文章 机器学习-线性回归 里的讲解,这里就不在重复叙述.这里需要强调一下,深度学习里常用的SGD,翻译过来是随机梯度下降,但是实质是mini-batch梯度下降(mini-batch-gd),或者说是两者的结合更准确一些.

SGD的优点是,算法简单,计算量小,在函数为凸函数时可以找到全局最优解.所以是最常用的优化算法.缺点是如果函数不是凸函数的话,很容易进入到局部最优解而无法跳出来.同时SGD在选择学习率上也是比较困难的.

2.牛顿法

牛顿法和拟牛顿法都是求解无约束最优化问题的常用方法,其中牛顿法是迭代算法,每一步需要求解目标函数的海森矩阵的逆矩阵,计算比较复杂.

牛顿法在求解方程根的思想:在二维情况下,迭代的寻找某一点x,寻找方法是随机一个初始点x_0,目标函数在该点x_0的切线与x坐标轴的交点就是下一个x点,也就是x_1.不断迭代寻找x.其中切线的斜率为目标函数在点x_0的导数(梯度),切必过点(x_0,f(x_0)).所以迭代的方程式如图1,为了求该方程的极值点,还需要令其导数等于0,也就是又求了一次导数,所以需要用到f(x)的二阶导数.

在最优化的问题中,牛顿法提供了一种求解的办法. 假设任务是优化一个目标函数f, 求函数ff的极大极小问题, 可以转化为求解函数f导数等于0的问题, 这样求可以把优化问题看成方程求解问题(f的导数等于0). 剩下的问题就和牛顿法求解方程根的思想很相似了.

目标函数的泰勒展开式:

化简后:

这样就得到了与图1相似的公式,这里是二维的,在多维空间上,求二阶导数就是求海森矩阵,因为是分母,所以还需要求海森矩阵的逆矩阵.

牛顿法和SGD的区别:

牛顿法是二阶求导,SGD是一阶求导,所以牛顿法要收敛的更快一些.SGD只考虑当前情况下梯度下降最快的方向,而牛顿法不仅考虑当前梯度下降最快,还有考虑下一步下降最快的方向.

牛顿法的优点是二阶求导下降速度快,但是因为是迭代算法,每一步都需要求解海森矩阵的逆矩阵,所以计算复杂.

3.拟牛顿法(没搞懂,待定)

考虑到牛顿法计算海森矩阵比较麻烦,所以它使用正定矩阵来代替海森矩阵的逆矩阵,从而简化了计算过程.

常用的拟牛顿法有DFP算法和BFGS算法.

4.共轭梯度法(Conjugate Gradient)

共轭梯度法是介于最速下降法与牛顿法之间的一个方法,它仅需利用一阶导数信息,但克服了最速下降法收敛慢的缺点,又避免了牛顿法计算海森矩阵并求逆的缺点.共轭梯度法不仅是解决大型线性方程组最有用的方法之一,也是解大型非线性最优化最有效的算法之一.

5.拉格朗日法

参考SVM里的讲解 机器学习-SVM

6.动量优化法(Momentum)

动量优化法主要是在SGD的基础上,加入了历史的梯度更新信息或者说是加入了速度更新.SGD虽然是很流行的优化算法,但是其学习过程很慢,因为总是以同样的步长沿着梯度下降的方向.所以动量是为了加速学习的方法.

其中第一行的减号部分是计算当前的梯度,第一行是根据梯度更新速度v,而α是新引进的参数,在实践中,α的一般取值为 0.5,0.9 和 0.99.和学习率 一样,α 也会随着时间不断调整.一般初始值是一个较小的值,随后会慢慢变大.

7.Nesterov加速梯度(NAG, Nesterov accelerated gradient)

NAG是在动量优化算法的基础上又进行了改进.根据下图可以看出,Nesterov 动量和标准动量之间的区别体现在梯度计算上, Nesterov 动量中,梯度计算在施加当前速度之后.因此,Nesterov 动量可以解释为往标准动量方法中添加了一个校正因子

8.AdaGrad算法

AdaGrad算法,自适应优化算法的一种,独立地适应所有模型参数的学习率,缩放每个参数反比于其所有梯度历史平均值总和的平方根.具有代价函数最大梯度的参数相应地有个快速下降的学习率,而具有小梯度的参数在学习率上有相对较小的下降.通俗一点的讲,就是根据实际情况更改学习率,比如模型快要收敛的时候,学习率步长就会小一点,防止跳出最优解.

其中g是梯度,第一行的分母是计算累计梯度的平方根, 是为了防止分母为0加上的极小常数项,α是学习率.

Adagrad的主要优点是不需要人为的调节学习率,它可以自动调节.但是依然需要设置一个初始的全局学习率.缺点是随着迭代次数增多,学习率会越来越小,最终会趋近于0.

9.RMSProp算法

RMSProp修改 AdaGrad 以在非凸设定下效果更好,改变梯度积累为指数加权的移动平均.AdaGrad旨在应用于凸问题时快速收敛.

10.AdaDelta算法

11.Adam算法

Adam是Momentum和RMSprop的结合体,也就是带动量的自适应优化算法.

12.Nadam算法

13.模拟退火算法

14.蚁群算法

15.遗传算法

动量是为了加快学习速度,而自适应是为了加快收敛速度,注意学习速度快不一定收敛速度就快,比如步长大学习速度快,但是很容易跳出极值点,在极值点附近波动,很难达到收敛.

未完待定....

参考:

《统计学习方法》  李航    着

《深度学习》  花书

‘叁’ 优化算法笔记(二)优化算法的分类

(以下描述,均不是学术用语,仅供大家快乐的阅读)

在分类之前,我们先列举一下常见的优化算法(不然我们拿什么分类呢?)。
1遗传算法Genetic algorithm
2粒子群优化算法Particle Swarm Optimization
3差分进化算法Differential Evolution
4人工蜂群算法Artificial Bee Colony
5蚁群算法Ant Colony Optimization
6人工鱼群算法Artificial Fish Swarm Algorithm
7杜鹃搜索算法Cuckoo Search
8萤火虫算法Firefly Algorithm
9灰狼算法Grey Wolf Optimizer
10鲸鱼算法Whale Optimization Algorithm
11群搜索算法Group search optimizer
12混合蛙跳算法Shuffled Frog Leaping Algorithm
13烟花算法fireworks algorithm
14菌群优化算法Bacterial Foraging Optimization
以上优化算法是我所接触过的算法,没接触过的算法不能随便下结论,知之为知之,不知为不知。其实到目前为止优化算法可能已经有几百种了,我们不可能也不需要全面的了解所有的算法,而且优化算法之间也有较大的共性,深入研究几个之后再看其他优化算法上手速度会灰常的快。
优化算法从提出到现在不过50-60年(遗传算法1975年提出),虽种类繁多但大多较为相似,不过这也很正常,比较香蕉和人的基因相似度也有50%-60%。当然算法之间的相似度要比香蕉和人的相似度更大,毕竟人家都是优化算法,有着相同的目标,只是实现方式不同。就像条条大路通罗马,我们可以走去,可以坐汽车去,可以坐火车去,也可以坐飞机去,不管使用何种方式,我们都在去往罗马的路上,也不会说坐飞机去要比走去更好,交通工具只是一个工具,最终的方案还是要看我们的选择。

上面列举了一些常见的算法,即使你一个都没见过也没关系,后面会对它们进行详细的介绍,但是对后面的分类可能会有些许影响,不过问题不大,就先当总结看了。
再对优化算法分类之前,先介绍一下算法的模型,在笔记(一)中绘制了优化算法的流程,不过那是个较为简单的模型,此处的模型会更加复杂。上面说了优化算法有较大的相似性,这些相似性主要体现在算法的运行流程中。
优化算法的求解过程可以看做是一个群体的生存过程。

有一群原始人,他们要在野外中寻找食物,一个原始人是这个群体中的最小单元,他们的最终目标是寻找这个环境中最容易获取食物的位置,即最易存活下来的位置。每个原始人都去独自寻找食物,他们每个人每天获取食物的策略只有采集果实、制作陷阱或者守株待兔,即在一天之中他们不会改变他们的位置。在下一天他们会根据自己的策略变更自己的位置。到了某一天他们又聚在了一起,选择了他们到过的最容易获取食物的位置定居。
一群原始人=优化算法中的种群、群体;
一个原始人=优化算法中的个体;
一个原始人的位置=优化算法中个体的位置、基因等属性;
原始人变更位置=优化算法中总群的更新操作;
该位置获取食物的难易程度=优化算法中的适应度函数;
一天=优化算法中的一个迭代;
这群原始人最终的定居位置=优化算法所得的解。
优化算法的流程图如下:

对优化算法分类得有个标准,按照不同的标准分类也会得到不一样的结果。首先说一下我所使用的分类标准(动态更新,有了新的感悟再加):

按由来分类比较好理解,就是该算法受何种现象启发而发明,本质是对现象分类。

可以看出算法根据由来可以大致分为有人类的理论创造而来,向生物学习而来,受物理现象启发。其中向生物学习而来的算法最多,其他类别由于举例有偏差,不是很准确,而且物理现象也经过人类总结,有些与人类现象相交叉,但仍将其独立出来。
类别分好了,那么为什么要这么分类呢?

当然是因为要凑字数啦,啊呸,当然是为了更好的理解学习这些算法的原理及特点。
向动物生存学习而来的算法一定是一种行之有效的方法,能够保证算法的效率和准确性,因为,如果使用该策略的动物无法存活到我们可以对其进行研究,我们也无法得知其生存策略。(而这也是一种幸存者偏差,我们只能看到行之有效的策略,但并不是我们没看到的策略都是垃圾,毕竟也发生过小行星撞地球这种小概率毁灭性事件。讲个冷笑话开cou心一shu下:一只小恐龙对他的小伙伴说,好开心,我最喜欢的那颗星星越来越亮了(完)。)但是由于生物的局限性,人们所创造出的算法也会有局限性:我们所熟知的生物都生存在三维空间,在这些环境中,影响生物生存的条件比较有限,反应到算法中就是这些算法在解决较低维度的问题时效果很好,当遇到超高维(维度>500)问题时,结果可能不容乐观,没做过实验,我也不敢乱说。

按更新过程分类相对复杂一点,主要是根据优化算法流程中更新位置操作的方式来进行分类。更新位置的操作按我的理解可大致分为两类:1.跟随最优解;2.不跟随最优解。
还是上面原始人的例子,每天他有一次去往其他位置狩猎的机会,他们采用何种方式来决定今天自己应该去哪里呢?
如果他们的策略是“跟随最优解”,那么他们选取位置的方式就是按一定的策略向群体已知的最佳狩猎位置(历史最佳)或者是当前群体中的最佳狩猎位置(今天最佳)靠近,至于是直线跑过去还是蛇皮走位绕过去,这个要看他们群体的策略。当然,他们的目的不是在最佳狩猎位置集合,他们的目的是在过去的途中看是否能发现更加好的狩猎位置,去往已经到过的狩猎地点再次狩猎是没有意义的,因为每个位置获取食物的难易程度是固定的。有了目标,大家都会朝着目标前进,总有一日,大家会在谋个位置附近相聚,相聚虽好但不利于后续的觅食容易陷入局部最优。
什么是局部最优呢?假设在当前环境中有一“桃花源”,拥有上帝视角的我们知道这个地方就是最适合原始人们生存的,但是此地入口隐蔽“山有小口,仿佛若有光”、“初极狭,才通人。”,是一个难以发现的地方。如果没有任何一个原始人到达了这里,大家向着已知的最优位置靠近时,也难以发现这个“桃源之地”,而当大家越聚越拢之后,“桃源”被发现的可能性越来越低。虽然原始人们得到了他们的解,但这并不是我们所求的“桃源”,他们聚集之后失去了寻求“桃源”的可能,这群原始人便陷入了局部最优。

如果他们的策略是“不跟随最优解”,那么他们的策略是什么呢?我也不知道,这个应该他们自己决定。毕竟“是什么”比“不是什么”的范围要小的多。总之不跟随最优解时,算法会有自己特定的步骤来更新个体的位置,有可能是随机在自己附近找,也有可能是随机向别人学习。不跟随最优解时,原始人们应该不会快速聚集到某一处,这样一来他们的选择更具多样性。
按照更新过程对上面的算法分类结果如下

可以看出上面不跟随最优解的算法只有遗传算法和差分进化算法,他们的更新策略是与进化和基因的重组有关。因此这些不跟随最优解的算法,他们大多依据进化理论更新位置(基因)我把他们叫做进化算法,而那些跟随群体最优解的算法,他们则大多依赖群体的配合协作,我把这些算法叫做群智能算法。

目前我只总结了这两种,分类方法,如果你有更加优秀的分类方法,我们可以交流一下:

目录
上一篇 优化算法笔记(一)优化算法的介绍
下一篇 优化算法笔记(三)粒子群算法(1)

‘肆’ 优化算法有哪些

你好,优化算法有很多,关键是针对不同的优化问题,例如可行解变量的取值(连续还是离散)、目标函数和约束条件的复杂程度(线性还是非线性)等,应用不同的算法。
对于连续和线性等较简单的问题,可以选择一些经典算法,例如梯度、Hessian
矩阵、拉格朗日乘数、单纯形法、梯度下降法等;而对于更复杂的问题,则可考虑用一些智能优化算法,例如你所提到的遗传算法和蚁群算法,此外还包括模拟退火、禁忌搜索、粒子群算法等。
这是我对优化算法的初步认识,供你参考。有兴趣的话,可以看一下维基网络。

‘伍’ 优化方法总结

神经网络模型中有多种优化算法,优化算法的作用用来优化更新参数。
对于优化算法而言,主要的框架如下。
参数: 目标函数: 学习率 。
对于每个epoch t:
step1: 计算当前梯度
step2: 计算动量。
     一阶动量:
     二阶动量:
step3: 计算当前时刻下降梯度
step4: 更新参数亩返皮
对于不同的优化算法而言,区别主要在于第一步和第二步。对于梯度的计算,一阶动量的计算,和二阶动量的计算存在差别。
三、四步的计算更新,各个算法之间都是相同的。

最常见的SGD
直接没有step2,没有引入动量。

在实际的实现中,可能会对学习率 进行改变,会使用衰减学习率。
SGD的缺点是 1 收敛速度慢,2 有可能会困在局部最优解。

也就是SGD+ Momentum。这里引入了一阶动量。
从直观理解就是加入了一个惯性,在坡度比较陡的地方,会有较大的惯性,这是下降的多。坡度平缓的地方,惯性较小,下降的会比较慢。
修改SGD中的一阶动量为

等式右边有两部分,加号左边的部分为之前积累的下降方向,加号右边为当前的梯度。两者的权重用参数来控制。
越大,说明下降的方向越依赖于以往的惯性。可以减少方向的突变。

NAG是:Nesterov Accelerated Gradient
这里是针对SGD会陷在局部最优附近的缺点进行改进。
在前面针对收敛慢改,引进一阶动量后,这里着眼于step1里的梯度计算。通常 会设的比较大,这就说明下降方向主要由历史方向积累决定,那么在step1里,不看当前的梯度,而是看下一步时刻的梯度。直观理解为多看一步,计算下一步的梯度。
用下一个点的梯度下降方向,与历史累积动量结合,计算step2里的一阶动量。
计算公式如下

前面的优化算法主要着眼于一阶迅差动量的设计,从AdaGrad开始,将引入二阶动量。参数的二阶动量在这里表示为当前维度上,历史积累的全部的梯度的平方和。
将step3里的公式修改一下顺序,那前面的部分可以看成学习率。这里的分母是二阶动量。这里的学习率(包含二阶动量)会随着二阶动量的积累而逐渐变化,这就是‘自适应学习’。

宏观来分析,这里参数更新时,希望从少更新的维度多学习,经常更新的参世团数那里少学习一点。对于频繁更新的的参数,二阶动量迅速积累,会使的学习率降低,那么在同一次更新中,模型会学到比较少的内容。而不频繁更新的参数,学习率会比较大,每次更新时学到的东西比较多。
Ada算法的缺点也很明显,二阶动量是历史梯度的积累,是个单调递增的值,当分母越来越大时,整个的学习率会趋于0,会提前停止学习。

为了改进AdaGrad中的二阶动量会不断增加的缺点,这里提出了一个时间窗口。计算二阶动量的时候只计算这个时间窗口内的动量。避免了二阶动量的持续积累。
二阶动量的计算公式如下

SGD-M 引入了一阶动量,AdaG 引入了二阶动量。
二者结合就是Adam,同时考虑一阶动量和二阶动量。
二者的计算公式如下:

回头看最初的优化框架,已经分别在一阶动量和二阶动量做了研究。还剩下当前的梯度可以进行尝试。参考前面的NAG,Nadam就是Adam+Nesterov。
在Adam的基础上保持其他计算公式不变,更改当前梯度的计算公式为

从前面的介绍可以看出,Adam系列的算法表面上更优秀,针对原本的SGD的缺点做了各种改变。但是对于Adam算法,目前也存在着缺点。
其中一个很严重的问题是Adam算法有可能不收敛。因为二阶动量取决于一段时间内的梯度的积累。这段时间内的数据如果有异常,会导致这个二阶动量极不稳定。在学习的后期,学习率有可能不断震荡,导致整个模型无法收敛。
同时因为动量的引入,在学习的后期,存在可能使一步过大,错过最优解。
综上所述,虽然Adam看着很完美,但在实际应用中还是存在着缺点。所以到底是各种优化器要如何选择,还是要取决于具体的情况和个人的调参经验。

后续会逐渐更新个人的调参经验。

[1] 一个框架看懂优化算法之异同 SGD/AdaGrad/Adam
[2] Adam的两宗罪
[3] 如何理解随机梯度下降(Stochastic gradient descent,SGD)?

‘陆’ 优化算法笔记(一)优化算法的介绍

(以下描述,均不是学术用语,仅供大家快乐的阅读)

        我们常见常用的算法有排序算法,字符串遍历算法,寻路算法等。这些算法都是为了解决特定的问题而被提出。

        算法本质是一种按照固定步骤执行的过程。

        优化算法也是这样一种过程,是一种根据概率按照固定步骤寻求问题的最优解的过程。与常见的排序算法、寻路算法不同的是,优化算法不具备等幂性,是一种 概率算法 。算法不断的 迭代 执行同一步骤直到结束,其流程如下图。

        等幂性即 对于同样的输入,输出是相同的 。

        比如图1,对于给定的鱼和给定的熊掌,我们在相同的条件下一定可以知道它们谁更重,当然,相同的条件是指鱼和熊掌处于相同的重力作用下,且不用考虑水分流失的影响。在这些给定的条件下,我们(无论是谁)都将得出相同的结论,鱼更重或者熊掌更重。我们可以认为,秤是一个等幂性的算法(工具)。

        现在把问题变一变,问鱼与熊掌你更爱哪个,那么现在,这个问题,每个人的答案可能不会一样,鱼与熊掌各有所爱。说明喜爱这个算法不是一个等幂性算法。当然你可能会问,哪个更重,和更喜欢哪个这两个问题一个是客观问题,一个是主观问题,主观问题没有确切的答案的。当我们处理主观问题时,也会将其转换成客观问题,比如给喜欢鱼和喜欢熊掌的程度打个分,再去寻求答案,毕竟计算机没有感情,只认0和1(量子计算机我不认识你)。

        说完了等幂性,再来说什么是概率算法。简单来说就是看脸、看人品、看运气的算法。

        有一场考试,考试的内容全部取自课本,同时老师根据自己的经验给同学们划了重点,但是因为试卷并不是该老师所出,也会有考试内容不在重点之内,老师估计试卷中至少80%内容都在重点中。学霸和学渣参加了考试,学霸为了考满分所以无视重点,学渣为了pass,因此只看了重点。这样做的结果一定是score(学霸)>=score(学渣)。

        当重点跟上图一样的时候,所有的内容都是重点的时候,学霸和学渣的学习策略变成了相同的策略,则score(学霸)=score(学渣)。但同时,学渣也要付出跟学霸相同的努力去学习这些内容,学渣心里苦啊。

        当课本如下图时

        学霸?学霸人呢,哪去了快来学习啊,不是说学习一时爽,一直学习一直爽吗,快来啊,还等什么。

        这时,如果重点内容远少于书本内容时,学渣的学习策略有了优势——花费的时间和精力较少。但是同时,学渣的分数也是一个未知数,可能得到80分也可能拿到100分,分数完全取决于重点内容与题目的契合度,契合度越高,分数越高。对学渣来说,自己具体能考多少分无法由自己决定,但是好在能够知道大概的分数范围。

        学霸的学习策略是一种遍历性算法,他会遍历、通读全部内容,以保证满分。

        学渣的学习策略则是一种概率算法,他只会遍历、学习重点内容,但至于这些重点是不是真重点他也不知道。

        与遍历算法相比,概率算法的结果具有不确定性,可能很好,也可能很差,但是会消耗更少的资源,比如时间(人生),空间(记忆)。概率算法的最大优点就是 花费较少的代价来获取最高的收益 ,在现实中体现于节省时间,使用很少的时间得到一个不与最优解相差较多的结果。

        “庄子:吾生也有涯,而知也无涯;以有涯随无涯,殆矣。”的意思是:人生是有限的,但知识是无限的(没有边界的),用有限的人生追求无限的知识,是必然失败的。

        生活中概率算法(思想)的应用其实比较广泛,只是我们很少去注意罢了。关于概率算法还衍生出了一些有趣的理论,比如墨菲定律和幸存者偏差,此处不再详述。

        上面说到,优化算法就是不停的执行同样的策略、步骤直到结束。为什么要这样呢?因为优化算法是一种概率算法,执行一次操作就得到最优结果几乎是不可能的,重复多次取得最优的概率也会增大。

        栗子又来了,要从1-10这10个数中取出一个大于9的数,只取1次,达到要求的概率为10%,取2次,达到要求的概率为19%。

        可以看出取到第10次时,达到要求的概率几乎65%,取到100次时,达到要求的概率能接近100%。优化算法就是这样简单粗暴的来求解问题的吗?非也,这并不是一个恰当的例子,因为每次取数的操作之间是相互独立的,第2次取数的结果不受第1次取数结果的影响,假设前99次都没达到要求,那么再取一次达到要求的概率跟取一次达到要求的概率相同。

        优化算法中,后一次的计算会依赖前一次的结果,以保证后一次的结果不会差于前一次的结果。这就不得不谈到马尔可夫链了。

        由铁组成的链叫做铁链,同理可得,马尔可夫链就是马尔可夫组成的链。

        言归正传, 马尔可夫链(Markov Chain, MC) ,描述的是 状态转移的过程中,当前状态转移的概率只取决于上一步的状态,与其他步的状态无关 。简单来说就是当前的结果只受上一步的结果的影响。每当我看到马尔可夫链时,我都会陷入沉思,生活中、或者历史中有太多太多与马尔可夫链相似的东西。西欧封建等级制度中“附庸的附庸不是我的附庸”与“昨天的努力决定今天的生活,今天的努力决定明天的生活”,你的下一份工作的工资大多由你当前的工资决定,这些都与马尔可夫链有异曲同工之处。

        还是从1-10这10个数中取出一个大于9的数的这个例子。基于马尔可夫链的概率算法在取数时需要使当前取的数不小于上一次取的数。比如上次取到了3,那么下次只能在3-10这几个数中取,这样一来,达到目标的概率应该会显着提升。还是用数据说话。

        取1次达到要求的概率仍然是

        取2次内达到要求的概率为

        取3次内达到要求的概率为

        取4次内……太麻烦了算了不算了

        可以看出基于马尔可夫链来取数时,3次内能达到要求的概率与不用马尔可夫链时取6次的概率相当。说明基于马尔可夫链的概率算法求解效率明显高于随机概率算法。那为什么不将所有的算法都基于马尔可夫链呢?原因一,其实现方式不是那么简单,例子中我们规定了取数的规则是复合马尔可夫链的,而在其他问题中我们需要建立适当的复合马尔科夫链的模型才能使用。原因二,并不是所有的问题都符合马尔科夫链条件,比如原子内电子出现的位置,女朋友为什么会生(lou)气,彩票号码的规律等,建立模型必须与问题有相似之处才能较好的解决问题。

        介绍完了优化算法,再来讨论讨论优化算法的使用场景。

        前面说了优化算法是一种概率算法,无法保证一定能得到最优解,故如果要求结果必须是确定、稳定的值,则无法使用优化算法求解。

        例1,求城市a与城市b间的最短路线。如果结果用来修建高速、高铁,那么其结果必定是唯一确定的值,因为修路寸土寸金,必须选取最优解使花费最少。但如果结果是用来赶路,那么即使没有选到最优的路线,我们可能也不会有太大的损失。

        例2,求城市a与城市b间的最短路线,即使有两条路径,路径1和路径2,它们从a到b的距离相同,我们也可以得出这两条路径均为满足条件的解。现在将问题改一下,求城市a到城市b耗时最少的线路。现在我们无法马上得出确切的答案,因为最短的线路可能并不是最快的路线,还需要考虑到天气,交通路况等因素,该问题的结果是一个动态的结果,不同的时间不同的天气我们很可能得出不同的结果。

        现实生产、生活中,也有不少的场景使用的优化算法。例如我们的使用的美图软件,停车场车牌识别,人脸识别等,其底层参数可能使用了优化算法来加速参数计算,其参数的细微差别对结果的影响不太大,需要较快的得出误差范围内的参数即可;电商的推荐系统等也使用了优化算法来加速参数的训练和收敛,我们会发现每次刷新时,推给我们的商品都有几个会发生变化,而且随着我们对商品的浏览,系统推给我们的商品也会发生变化,其结果是动态变化的;打车软件的订单系统,会根据司机和客人的位置,区域等来派发司机给客人,不同的区域,不同的路况,派发的司机也是动态变化的。

        综上我们可以大致总结一下推荐、不推荐使用优化算法的场景的特点。

        前面说过,优化算法处理的问题都是客观的问题,如果遇到主观的问题,比如“我孰与城北徐公美”,我们需要将这个问题进行量化而转换成客观的问题,如身高——“修八尺有余”,“外貌——形貌昳丽”,自信度——“明日徐公来,孰视之,自以为不如;窥镜而自视,又弗如远甚”,转化成客观问题后我们可以得到各个解的分数,通过比较分数,我们就能知道如何取舍如何优化。这个转化过程叫做问题的建模过程,建立的问题模型实际上是一个函数,这个函数对优化算法来说是一个黑盒函数,即不需要知道其内部实现只需要给出输入,得到输出。

        在优化算法中这个黑盒函数叫做 适应度函数 , 优化算法的求解过程就是寻找适应度函数最优解的过程 ,使用优化算法时我们最大的挑战就是如何将抽象的问题建立成具体的模型,一旦合适的模型建立完成,我们就可以愉快的使用优化算法来求解问题啦。(“合适”二字谈何容易)

        优化算法的大致介绍到此结束,后面我们会依次介绍常见、经典的优化算法,并探究其参数对算法性能的影响。

——2019.06.20

[目录]

[下一篇 优化算法笔记(二)优化算法的分类]

‘柒’ 常用优化器算法归纳介绍

优化器是神经网络训练过程中,进行梯度下降以寻找最优解的优化方法。不同方法通过不同方式(如附加动量项,学习率自适应变化等)侧重于解决不同的问题,但最终大都是为了加快训练速度。

这里就介绍几种常见的优化器,包括其原理、数学公式、核心思想及其性能;

核心思想: 即针对每次输入的训练数据,计算输出预测与真值的Loss的梯度;

从表达式来看,网络中参数的更新,是不断向着最小化Loss函数的方向移动的:

优点:
简单易懂,即对于相应的最优解(这里认为是Loss的最小函数),每次变量更新都是沿着局部梯度下降最快的方向,从而最小化损失函数。

缺点:

不同于标准梯度下降法(Gradient Descent)一次计算所有数据样本的Loss并计算相应的梯度,批量梯度下降法(BGD, Batch Gradient Descent)每次只取一个小批次的数据及其真实标签进行训练,称这个批次为mini-batch;

优点:

缺点:
随机梯度下降法的 batch size 选择不当可能导致模型难以收敛;由于这种方法是在一次更新中,就对整个数据集计算梯度,所以计算起来非常慢,遇到很大量的数据集也会非常棘手,而且不能投入新数据实时更新模型。

我们会事先定义一个迭代次数 epoch,首先计算梯度向量 params_grad,然后沿着梯度的方向更新参数 params,learning rate 决定了我们每一步迈多大。

Batch gradient descent 对于凸函数可以收敛到全局极小值,对于非凸函数可以收敛到局部极小值。

和 BGD 的一次用所有数据计算梯度相比,SGD 每次更新时对每个样本进行梯度更新,对于很大的数据集来说,可能会有相似的样本,这样 BGD 在计算梯度时会出现冗余,而 SGD 一次只进行一次更新,就没有冗余,而且比较快,并且可以新增样本。

即训练时,每次只从一批训练样本中随机选取一个样本进行梯度下降;对随机梯度下降来说,只需要一次关注一个训练样本,一点点把参数朝着全局最小值的方向进行修改了。

整体数据集是个循环,其中对每个样本进行一次参数更新

缺点:

梯度下降速度比较慢,而且每次梯度更新时往往只专注与局部最优点,而不会恰好指向全局最优点;

单样本梯度更新时会引入许多噪声(跟训练目标无关的特征也会被归为该样本分类的特征);

SGD 因为更新比较频繁,会造成 cost function 有严重的震荡。

BGD 可以收敛到局部极小值,当然 SGD 的震荡可能会跳到更好的局部极小值处。

当我们稍微减小 learning rate,SGD 和 BGD 的收敛性是一样的。

优点:

当处理大量数据时,比如SSD或者faster-rcnn等目标检测模型,每个样本都有大量候选框参与训练,这时使用随机梯度下降法能够加快梯度的计算。

随机梯度下降是通过每个样本来迭代更新一次,如果样本量很大的情况,那么可能只用其中部分的样本,就已经将 迭代到最优解了,对比上面的批量梯度下降,迭代一次需要用到十几万训练样本,一次迭代不可能最优,如果迭代10次的话就需要遍历训练样本10次。缺点是SGD的噪音较BGD要多,使得SGD并不是每次迭代都向着整体最优化方向。所以虽然训练速度快,但是准确度下降,并不是全局最优。虽然包含一定的随机性,但是从期望上来看,它是等于正确的导数的。

梯度更新规则:

MBGD 每一次利用一小批样本,即 n 个样本进行计算,这样它可以降低参数更新时的方差,收敛更稳定,另一方面可以充分地利用深度学习库中高度优化的矩阵操作来进行更有效的梯度计算。

和 SGD 的区别是每一次循环不是作用于每个样本,而是具有 n 个样本的批次。

超参数设定值: n 一般取值在 50~256

缺点:(两大缺点)

鞍点就是:一个光滑函数的鞍点邻域的曲线,曲面,或超曲面,都位于这点的切线的不同边。例如这个二维图形,像个马鞍:在x-轴方向往上曲,在y-轴方向往下曲,鞍点就是(0,0)。

为了应对上面的两点挑战就有了下面这些算法

核心思想:

不使用动量优化时,每次训练的梯度下降方向,都是按照当前批次训练数据计算的,可能并不能代表整个数据集,并且会有许多噪声,下降曲线波动较大:

添加动量项之后,能够有效减小波动,从而加快训练速度:

当我们将一个小球从山上滚下来时,没有阻力的话,它的动量会越来越大,但是如果遇到了阻力,速度就会变小。
加入的这一项,可以使得梯度方向不变的维度上速度变快,梯度方向有所改变的维度上的更新速度变慢,这样就可以加快收敛并减小震荡。

优点:

通过动量更新,参数向量会在有持续梯度的方向上增加速度;
使梯度下降时的折返情况减轻,从而加快训练速度;

缺点:

如果数据集分类复杂,会导致 和 时刻梯度 向量方向相差较大;在进行向量求和时,得到的 会非常小,反而使训练速度大大下降甚至模型难以收敛。

这种情况相当于小球从山上滚下来时是在盲目地沿着坡滚,如果它能具备一些先知,例如快要上坡时,就知道需要减速了的话,适应性会更好。

目前为止,我们可以做到,在更新梯度时顺应 loss function 的梯度来调整速度,并且对 SGD 进行加速。

核心思想:

自适应学习率优化算法针对于机器学习模型的学习率,采用不同的策略来调整训练过程中的学习率,从而大大提高训练速度。

这个算法就可以对低频的参数做较大的更新,对高频的做较小的更新,也因此,对于稀疏的数据它的表现很好,很好地提高了 SGD 的鲁棒性,例如识别 Youtube 视频里面的猫,训练 GloVe word embeddings,因为它们都是需要在低频的特征上有更大的更新。

Adagrad 的优点是减少了学习率的手动调节

式中, 表示第 个分类, 表示第 迭代同时也表示分类 累计出现的次数。 表示初始的学习率取值(一般为0.01)

AdaGrad的核心思想: 缩放每个参数反比于其所有梯度历史平均值总和的平方根。具有代价函数最大梯度的参数相应地有较大的学习率,而具有小梯度的参数又较小的学习率。

缺点:

它的缺点是分母会不断积累,这样学习率就会收缩并最终会变得非常小。

这个算法是对 Adagrad 的改进,

和 Adagrad 相比,就是分母的 换成了过去的梯度平方的衰减平均值,指数衰减平均值

这个分母相当于梯度的均方根 root mean squared (RMS),在数据统计分析中,将所有值平方求和,求其均值,再开平方,就得到均方根值 ,所以可以用 RMS 简写:

其中 的计算公式如下, 时刻的依赖于前一时刻的平均和当前的梯度:

梯度更新规则:

此外,还将学习率 换成了 RMS[Δθ],这样的话,我们甚至都不需要提前设定学习率了:

超参数设定值: 一般设定为 0.9

RMSprop 是 Geoff Hinton 提出的一种自适应学习率方法。

RMSprop 和 Adadelta 都是为了解决 Adagrad 学习率急剧下降问题的,

梯度更新规则:

RMSprop 与 Adadelta 的第一种形式相同:(使用的是指数加权平均,旨在消除梯度下降中的摆动,与Momentum的效果一样,某一维度的导数比较大,则指数加权平均就大,某一维度的导数比较小,则其指数加权平均就小,这样就保证了各维度导数都在一个量级,进而减少了摆动。允许使用一个更大的学习率η)

超参数设定值:

Hinton 建议设定 为 0.9, 学习率 为 0.001。

这个算法是另一种计算每个参数的自适应学习率的方法。相当于 RMSprop + Momentum

除了像 Adadelta 和 RMSprop 一样存储了过去梯度的平方 vt 的指数衰减平均值 ,也像 momentum 一样保持了过去梯度 mt 的指数衰减平均值:

如果 和 被初始化为 0 向量,那它们就会向 0 偏置,所以做了偏差校正,通过计算偏差校正后的 和 来抵消这些偏差:

梯度更新规则:

超参数设定值:
建议

示例一

示例二

示例三

上面情况都可以看出,Adagrad, Adadelta, RMSprop 几乎很快就找到了正确的方向并前进,收敛速度也相当快,而其它方法要么很慢,要么走了很多弯路才找到。

由图可知自适应学习率方法即 Adagrad, Adadelta, RMSprop, Adam 在这种情景下会更合适而且收敛性更好。

如果数据是稀疏的,就用自适用方法,即 Adagrad, Adadelta, RMSprop, Adam。

RMSprop, Adadelta, Adam 在很多情况下的效果是相似的。

Adam 就是在 RMSprop 的基础上加了 bias-correction 和 momentum,

随着梯度变的稀疏,Adam 比 RMSprop 效果会好。

整体来讲,Adam 是最好的选择。

很多论文里都会用 SGD,没有 momentum 等。SGD 虽然能达到极小值,但是比其它算法用的时间长,而且可能会被困在鞍点。

如果需要更快的收敛,或者是训练更深更复杂的神经网络,需要用一种自适应的算法。

各种优化器Optimizer原理:从SGD到AdamOptimizer

深度学习——优化器算法Optimizer详解(BGD、SGD、MBGD、Momentum、NAG、Adagrad、Adadelta、RMSprop、Adam)

‘捌’ 优化算法是什么

智能优化算法是一种启发式优化算法,包括遗传算法、蚁群算法、禁忌搜索算法、模拟退火算法、粒子群算法等。·智能优化算法一般是针对具体问题设计相关的算法,理论要求弱,技术性强。一般,我们会把智能算法与最优化算法进行比较,相比之下,智能算法速度快,应用性强。

群体智能优化算法是一类基于概率的随机搜索进化算法,各个算法之间存在结构、研究内容、计算方法等具有较大的相似性。

各个群体智能算法之间最大不同在于算法更新规则上,有基于模拟群居生物运动长更新的(如PSO,AFSA与SFLA),也有根据某种算法机理设置更新规则(如ACO)。

(8)优化算法ppt扩展阅读:

优化算法有很多,关键是针对不同的优化问题,例如可行解变量的取值(连续还是离散)、目标函数和约束条件的复杂程度(线性还是非线性)等,应用不同的算法。 对于连续和线性等较简单的问题,可以选择一些经典算法,例如梯度、Hessian 矩阵、拉格朗日乘数、单纯形法、梯度下降法等;而对于更复杂的问题,则可考虑用一些智能优化算法。

‘玖’ 优化算法

  SGD算法中的一个关键参数是学习率。之前,我们介绍的SGD使用固定的学习率。在实践中,有必要随着时间的推移逐渐降低学习率,因此我们将第 k 步迭代的学习率记作 ϵ k 。
  这是因为SGD中梯度估计引入的噪声源(m 个训练样本的随机采样)并不会在极小点处消失。相比之下,当我们使用批量梯度下降到达极小点时,整个代价函数的真实梯度会变得很小,之后为 0,因此批量梯度下降可以使用固定的学习率。保证SGD收敛的一个充分条件是

  若 ϵ 0 太大,学习曲线将会剧烈振荡,代价函数值通常会明显增加。温和的振荡是良好的,容易在训练随机代价函数(例如使用Dropout的代价函数)时出现。如果学习率太小,那么学习过程会很缓慢。如果初始学习率太低,那么学习可能会卡在一个相当高的代价值。通常,就总训练时间和最终代价值而言,最优初始学习率会高于大约迭代 100 次左右后达到最佳效果的学习率。因此,通常最好是检测最早的几轮迭代,选择一个比在效果上表现最佳的学习率更大的学习率,但又不能太大导致严重的震荡。

  虽然随机梯度下降仍然是非常受欢迎的优化方法,但其学习过程有时会很慢。动量方法 (Polyak, 1964) 旨在加速学习,特别是处理高曲率、小但一致的梯度,或是带噪声的梯度。动量算法积累了之前梯度指数级衰减的移动平均,并且继续沿该方向移动。动量的效果如图8.5所示

  受 Nesterov 加速梯度算法 (Nesterov, 1983, 2004) 启发,提出了动量算法的一个变种。这种情况的更新规则如下:

  其中参数 α 和 ϵ 发挥了和标准动量方法中类似的作用。Nesterov 动量和标准动量之间的区别体现在梯度计算上。Nesterov 动量中,梯度计算在施加当前速度之后。因此,Nesterov 动量可以解释为往标准动量方法中添加了一个校正因子。完整的Nesterov动量算法如算法3.2所示

  初始点能够决定算法是否收敛,有些初始点十分不稳定,使得该算法会遭遇数值困难,并完全失败。当学习收敛时,初始点可以决定学习收敛得多快,以及是否收敛到一个代价高或低的点。此外,差不多代价的点可以具有区别极大的泛化误差,初始点也可以影响泛化。
  也许完全确知的唯一特性是初始参数需要在不同单元间 ‘‘破坏对称性’’。如果具有相同激活函数的两个隐藏单元连接到相同的输入,那么这些单元必须具有不同的初始参数。如果它们具有相同的初始参数,然后应用到确定性损失和模型的确定性学习算法将一直以相同的方式更新这两个单元。即使模型或训练算法能够使用随机性为不同的单元计算不同的更新(例如使用Dropout的训练),通常来说,最好还是初始化每个单元使其和其他单元计算不同的函数。这或许有助于确保没有输入模式
丢失在前向传播的零空间中,没有梯度模式丢失在反向传播的零空间中。每个单元计算不同函数的目标促使了参数的随机初始化。我们可以明确地搜索一大组彼此互不相同的基函数,但这经常会导致明显的计算代价。例如,如果我们有和输出一样多的输入,我们可以使用 Gram-Schmidt 正交化于初始的权重矩阵,保证每个单元计算彼此非常不同的函数。在高维空间上使用高熵分布来随机初始化,计算代价小并且不太可能分配单元计算彼此相同的函数。
  通常情况下,我们可以为每个单元的偏置设置启发式挑选的常数,仅随机初始化权重。额外的参数(例如用于编码预测条件方差的参数)通常和偏置一样设置为启发式选择的常数。
  我们几乎总是初始化模型的权重为高斯或均匀分布中随机抽取的值。高斯或均匀分布的选择似乎不会有很大的差别,但也没有被详尽地研究。然而,初始分布的大小确实对优化过程的结果和网络泛化能力都有很大的影响。
  更大的初始权重具有更强的破坏对称性的作用,有助于避免冗余的单元。它们也有助于避免在每层线性成分的前向或反向传播中丢失信号——矩阵中更大的值在矩阵乘法中有更大的输出。如果初始权重太大,那么会在前向传播或反向传播中产生爆炸的值。在循环网络中,很大的权重也可能导致混沌(chaos)(对于输入中很小的扰动非常敏感,导致确定性前向传播过程表现随机)。在一定程度上,梯度爆炸问题可以通过梯度截断来缓解(执行梯度下降步骤之前设置梯度的阈值)。较大的权
重也会产生使得激活函数饱和的值,导致饱和单元的梯度完全丢失。这些竞争因素决定了权重的理想初始大小。
  也有助于避免在每层线性成分的前向或反向传播中丢失信号——矩阵中更大的值在矩阵乘法中有更大的输出。如果初始权重太大,那么会在前向传播或反向传播中产生爆炸的值。在循环网络中,很大的权重也可能导致混沌(chaos)(对于输入中很小的扰动非常敏感,导致确定性前向传播过程表现随机)。在一定程度上,梯度爆炸问题可以通过梯度截断来缓解(执行梯度下降步骤之前设置梯度的阈值)。较大的权重也会产生使得激活函数饱和的值,导致饱和单元的梯度完全丢失。这些竞争因素决定了权重的理想初始大小。
  有些启发式方法可用于选择权重的初始大小。一种初始化 m 个输入和 n 输出的全连接层的权重的启发式方法是从分布 U(−1/√ m ,
1/√ m ) 中采样权重,而 Glorot and Bengio 建议使用标准初始化

  后一种启发式方法初始化所有的层,折衷于使其具有相同激活方差和使其具有相同梯度方差之间。这假设网络是不含非线性的链式矩阵乘法,据此推导得出。现实的神经网络显然会违反这个假设,但很多设计于线性模型的策略在其非线性对应中的效果也不错。
  数值范围准则的一个缺点是,设置所有的初始权重具有相同的标准差,例如1/√ m ,会使得层很大时每个单一权重会变得极其小。Martens (2010) 提出了一种被称为稀疏初始化(sparse initialization)的替代方案,每个单元初始化为恰好有 k 个非零权重。这个想法保持该单元输入的总数量独立于输入数目 m,而不使单一权重元素的大小随 m 缩小。稀疏初始化有助于实现单元之间在初始化时更具多样性。但是,获得较大取值的权重也同时被加了很强的先验。因为梯度下降需要很长时间缩小 ‘‘不正确’’ 的大值,这个初始化方案可能会导致某些单元出问题,例如maxout单元有几个过滤器,互相之间必须仔细调整。

  Delta-bar-delta 算法 (Jacobs, 1988) 是一个早期的在训练时适应模型参数各自学习率的启发式方法。该方法基于一个很简单的想法,如果损失对于某个给定模型参数的偏导保持相同的符号,那么学习率应该增加。如果对于该参数的偏导变化了符号,那么学习率应减小。当然,这种方法只能应用于全批量优化中。

  AdaGrad 算法,如算法8.4所示,独立地适应所有模型参数的学习率,缩放每个参数反比于其所有梯度历史平方值总和的平方根 (Duchi et al., 2011)。具有损失最大偏导的参数相应地有一个快速下降的学习率,而具有小偏导的参数在学习率上有相对较小的下降。净效果是在参数空间中更为平缓的倾斜方向会取得更大的进步。

  在凸优化背景中,AdaGrad 算法具有一些令人满意的理论性质。然而,经验上已经发现,对于训练深度神经网络模型而言,从训练开始时积累梯度平方会导致有效学习率过早和过量的减小。AdaGrad在某些深度学习模型上效果不错,但不是全部。

  RMSProp 算法 (Hinton, 2012) 修改 AdaGrad 以在非凸设定下效果更好,改变梯度积累为指数加权的移动平均。AdaGrad旨在应用于凸问题时快速收敛。当应用于非凸函数训练神经网络时,学习轨迹可能穿过了很多不同的结构,最终到达一个局部是凸碗的区域。AdaGrad 根据平方梯度的整个历史收缩学习率,可能使得学习率在达到这样的凸结构前就变得太小了。RMSProp 使用指数衰减平均以丢弃遥远过去的历史,使其能够在找到凸碗状结构后快速收敛,它就像一个初始化于该碗状结构的 AdaGrad 算法实例。
  RMSProp 的标准形式如算法8.5所示,结合 Nesterov 动量的形式如算法8.6所示。相比于 AdaGrad,使用移动平均引入了一个新的超参数ρ,用来控制移动平均的长度范围。经验上,RMSProp 已被证明是一种有效且实用的深度神经网络优化算法。目前它是深度学习从业者经常采用的优化方法之一。

  Adam (Kingma and Ba, 2014) 是另一种学习率自适应的优化算法,最好被看作结合 RMSProp 和具有一些重要区别的动量的变种。首先,在 Adam 中,动量直接并入了梯度一阶矩(指数加权)的估计。将动量加入 RMSProp 最直观的方法是将动量应用于缩放后的梯度。结合缩放的动量使用没有明确的理论动机。其次,Adam 包括偏置修正,修正从原点初始化的一阶矩(动量项)和(非中心的)二阶矩的估计(算法8.7)。RMSProp 也采用了(非中心的)二阶矩估计,然而缺失了修正因子。因此,不像 Adam,RMSProp 二阶矩估计可能在训练初期有很高的偏置。Adam 通常被认为对超参数的选择相当鲁棒,尽管学习率有时需要从建议的默认修改。

  目前,最流行并且使用很高的优化算法包括 SGD、具动量的 SGD、RMSProp、具动量的 RMSProp、AdaDelta 和 Adam。

热点内容
内置存储卡可以拆吗 发布:2025-05-18 04:16:35 浏览:334
编译原理课时设置 发布:2025-05-18 04:13:28 浏览:377
linux中进入ip地址服务器 发布:2025-05-18 04:11:21 浏览:611
java用什么软件写 发布:2025-05-18 03:56:19 浏览:31
linux配置vim编译c 发布:2025-05-18 03:55:07 浏览:107
砸百鬼脚本 发布:2025-05-18 03:53:34 浏览:942
安卓手机如何拍视频和苹果一样 发布:2025-05-18 03:40:47 浏览:739
为什么安卓手机连不上苹果7热点 发布:2025-05-18 03:40:13 浏览:802
网卡访问 发布:2025-05-18 03:35:04 浏览:510
接收和发送服务器地址 发布:2025-05-18 03:33:48 浏览:371