SVM支持向量机理解_KKT条件_拉格朗日对偶_SMO算法代码

news2024/10/3 4:33:21

目录

一、支持向量机基本型(线性可分)

1.1 问题描述

1.2 参考资料

二、KKT条件

2.1 KKT条件的几个部分

2.1.1 原始条件

2.1.2 梯度条件

2.1.3 松弛互补条件

2.1.4 KKT条件小结

2.2 参考资料

三、对偶形式

3.1 由原始问题到对偶问题

3.2 对偶问题的具体形式

3.3 为什么可以将求解极小极打问题转化为求解极大极小问题?(具体证明我也没看)

3.4 参考资料

四、对偶问题的求解

4.1 SMO算法理论推导(仅考虑线性可分时)

4.2 SMO算法代码实现

4.3 编写程序的过程中的一点点收获

4.3.1 关于选点与优化结果

4.3.2 不同的选点方式带来的损失值变化的不同

4.4 参考资料

五、线性不可分情形

六、核函数


一、支持向量机基本型(线性可分)

1.1 问题描述

        在PLA感知机算法中我们求取超平面是保证所有目标分类正确即可,但是我们为了增加我们学习到的算法的鲁棒性,泛化能力更强,我们可以使超平面到样本的间隔距离最大,这里我们定义间隔为“样本到超平面的最近距离”,也就是说我们的超平面就是对应间隔最大的平面。下面我们用数学语言来描述。

        假设样本集eq?%5Cleft%20%5C%7B%20x_%7B1%7D%2Cy_%7B1%7D%20%5Cright%20%5C%7D%2C%5Cleft%20%5C%7B%20x_%7B2%7D%2Cy_%7B2%7D%20%5Cright%20%5C%7D%2C...%2C%5Cleft%20%5C%7B%20x_%7Bn%7D%2Cy_%7Bn%7D%20%5Cright%20%5C%7D%2Cx_%7Bi%7D%5Cin%20R%5E%7Bn%7D%2C%20y_%7Bi%7D%5Cin%20%5Cleft%20%5C%7B%20+1%2C%20-1%20%5Cright%20%5C%7D,设超平面为eq?wx+b%3D0,点到超平面的距离eq?d%3D%5Cfrac%7B%28wx_%7Bi%7D+b%29y_%7Bi%7D%7D%7B%5Cleft%20%5C%7C%20w%20%5Cright%20%5C%7C%7D    eq?i%3D1%2C2%2C3%2C...%2Cn,最小间隔则为eq?d%5E%7B*%7D%3D%5Cunderset%7Bi%7D%7Bmin%7D%5Cfrac%7B%28wx_%7Bi%7D+b%29y_%7Bi%7D%7D%7B%5Cleft%20%5C%7C%20w%20%5Cright%20%5C%7C%7D,当eq?d%5E%7B*%7D达到最大时的eq?w%2Cb就对应我们的超平面。即:

eq?w%2Cb%20%3D%20arg%5Cunderset%7Bw%2C%20b%7D%7Bmax%7D%5Cunderset%7Bi%7D%7Bmin%7D%5Cfrac%7B%28wx_%7Bi%7D+b%29y_%7Bi%7D%7D%7B%5Cleft%20%5C%7C%20w%20%5Cright%20%5C%7C%7D

现在的问题转变成了优化问题。

8c2ccda4db644fedb2d84df791e0c80a.png

对于这样确定的eq?w%2Cb,必然存在eq?%5Cvarepsiloneq?%5Cvarepsilon%20%3D%20%5Cunderset%7Bi%7D%7Bmin%7D%28wx_%7Bi%7D+b%29y_%7Bi%7D,即:

eq?%28wx_%7Bi%7D+b%29y_%7Bi%7D%5Cgeqslant%20%5Cvarepsilon%2C%5Cvarepsilon%20%3E0

eq?w进行缩放是不影响超平面的,所以可以必然存在这样的eq?w%2Cb,使得:

eq?%28wx_%7Bi%7D+b%29y_%7Bi%7D%5Cgeqslant%201     //这个式子隐含了eq?%5Cvarepsilon%20%3E0这个条件了

所以:

eq?d%5E%7B*%7D%3D%5Cunderset%7Bw%2Cb%7D%7Bmax%7D%5Cfrac%7B1%7D%7B%5Cleft%20%5C%7C%20w%20%5Cright%20%5C%7C%7D

要使eq?d%5E%7B*%7D达到最大,则使eq?%5Cleft%20%5C%7C%20w%20%5Cright%20%5C%7C最小即可。所以上述优化问题可以写成下列形式:

eq?%5Cunderset%7Bw%2Cb%7D%7Bmin%7D%5Cfrac%7B1%7D%7B2%7D%5Cleft%20%5C%7C%20w%20%5Cright%20%5C%7C%5E%7B2%7D

eq?s.t.   eq?%28wx_%7Bi%7D%20+%20b%29y_%7Bi%7D%5Cgeqslant%201   eq?i%3D1%2C2%2C...%2Cn

1.2 参考资料

        以上就是支持向量机的基本型。详细内容可参见李航《机器学习方法》第七章支持向量机。网上其他参考资料可参见:

文档资料:

机器学习:支持向量机(SVM)_燕双嘤的博客-CSDN博客_支持向量机

支持向量机通俗导论(理解SVM的三层境界)_v_JULY_v的博客-CSDN博客_支持向量机

视频资料:

推导SVM基本形式_哔哩哔哩_bilibili

【数之道25】机器学习必经之路-SVM支持向量机的数学精华_哔哩哔哩_bilibili

1. 支持向量机(线性模型)问题_哔哩哔哩_bilibili

svm原理推导:1-支持向量机要解决的问题_哔哩哔哩_bilibili

二、KKT条件

        我把KKT条件放到第二节来讲,我觉得更加符合我们的思维方式,在第一节中我们给出了SVM的基本型,那么接下来我们来试图求解这个优化问题,由此引出KKT条件,很多写法将KKT条件直接上来就构建拉格朗日辅助函数,然后就给读者说就是这么回事,这种逻辑其实不合理,应当直接从梯度角度来讲这个事情。

2.1 KKT条件的几个部分

上述优化问题:

eq?%5Cunderset%7Bw%2Cb%7D%7Bmin%7D%5Cfrac%7B1%7D%7B2%7D%5Cleft%20%5C%7C%20w%20%5Cright%20%5C%7C%5E%7B2%7D

eq?s.t.   eq?%28wx_%7Bi%7D%20+%20b%29y_%7Bi%7D%5Cgeqslant%201   eq?i%3D1%2C2%2C...%2Cn

2.1.1 原始条件

            eq?%28wx_%7Bi%7D%20+%20b%29y_%7Bi%7D%5Cgeqslant%201   eq?i%3D1%2C2%2C...%2Cn

2.1.2 梯度条件

        在求解带不等式约束的优化问题时,考虑两种情况一种是不等式约束有效,一种是不等式约束无效。我们把要优化的函数称为目标函数(这个地方只考虑凸函数的情况)。

        (1)当约束条件无效时,目标函数最优值为其梯度为0时的值。

        (2)当约束条件有效时(目标函数不在约束范围内),那么目标函数取得最优值是应当与约束条件“相切”,也就是梯度方向成平行关系,具体可分为以下4种情况,我们假设目标函数为eq?f%28x%29,约束函数为eq?g%28x%29

        1. eq?minf%28x%29   eq?s.t.   eq?g%28x%29%5Cleqslant%200

83af67e0171c4cacaf7a1a4fb7155d53.png

                 此时有:eq?%5Cbigtriangledown%20f%28x%29%20%3D%20%5Calpha%20%5Cbigtriangledown%20g%28x%29  eq?%5Calpha%20%3C0

        2. eq?minf%28x%29  eq?s.t.  eq?g%28x%29%5Cgeqslant%200

c27963064dea4240b0e57ad8624caf9e.png

                  此时有:eq?%5Cbigtriangledown%20f%28x%29%20%3D%20%5Calpha%20%5Cbigtriangledown%20g%28x%29  eq?%5Calpha%20%3E0

        3. eq?maxf%28x%29  eq?s.t.  eq?g%28x%29%5Cleqslant%200

 8d5e21316c7e413eb24a53452270f461.png

                    此时有:eq?%5Cbigtriangledown%20f%28x%29%20%3D%20%5Calpha%20%5Cbigtriangledown%20g%28x%29  eq?%5Calpha%20%3E0

        4. eq?maxf%28x%29  eq?s.t.  eq?g%28x%29%5Cgeqslant%200

d876439c81964533911df9d1bd909e4b.png

                  此时有:eq?%5Cbigtriangledown%20f%28x%29%20%3D%20%5Calpha%20%5Cbigtriangledown%20g%28x%29  eq?%5Calpha%20%3C0

        注意eq?g%28x%29的梯度方向与eq?g%28x%29具体函数相关,这里为了举例方便仅画出示意图默认了梯度方向。

         在SVM基本型的优化问题中,其情形属于第二种情况,即: eq?%5Cbigtriangledown%20f%28x%29%20%3D%20%5Calpha%20%5Cbigtriangledown%20g%28x%29  eq?%5Calpha%20%3E0

综上两种情况可知:

 eq?%5Cbigtriangledown%20f%28x%29%20%3D%200或  eq?%5Cbigtriangledown%20f%28x%29%20%3D%20%5Calpha%20%5Cbigtriangledown%20g%28x%29  eq?%5Calpha%20%3E0

由于原优化问题是多约束条件,我们画出示意图如下:

5acc01877b474d05b9cca7e4e5dadc12.png

此时有:

eq?%5Cbigtriangledown%20f%28x%29%20%3D%20%5Calpha_%7B1%7D%20%5Cbigtriangledown%20g_%7B1%7D%28x%29+%5Calpha_%7B2%7D%20%5Cbigtriangledown%20g_%7B2%7D%28x%29      eq?%5Calpha%20_%7B1%7D%3E0%2C%5Calpha%20_%7B2%7D%3E0

综上所述,代入原式子,即:

eq?w%20%3D%200eq?%5Cleft%5C%7B%5Cbegin%7Bmatrix%7D%20w%20%3D%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7Dx_%7Bi%7D%5C%5C%20%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7D%3D0%5C%5C%20%5Calpha%20_%7Bi%7D%3E0%5Cend%7Bmatrix%7D%5Cright.

为了将两种情况综合到一起,我们引入了互补松弛条件。

2.1.3 松弛互补条件

        我们把约束条件有效和约束条件无效两种情况综合打一起,实际上对于第二种情况,当约束条件无效时eq?g_%7Bi%7D%28x%29%5Cneq%200,可令对应的乘子eq?%5Calpha%20_%7Bi%7D=0,此时第二种情况也就变成了第一种情况,当约束条件有效时则约束条件eq?g_%7Bi%7D%28x%29=0,所有始终有:

eq?%5Calpha%20_%7Bi%7D*g_%7Bi%7D%28x%29%3D0

我们称之为互补松弛条件。对于原始问题来讲,互补松弛条件就是:

eq?%5Calpha%20_%7Bi%7D*%5B%28wx_%7Bi%7D+b%29y_%7Bi%7D-1%5D%3D0       eq?i%3D1%2C2%2C...%2Cn

2.1.4 KKT条件小结

        综上所述我们引出了KKT条件,对于凸优化问题因为只存在唯一解KKT条件等价于原始优化问题,解KKT条件就是解原始优化问题,原始优化问题的解一定满足KKT条件。

eq?%28wx_%7Bi%7D%20+%20b%29y_%7Bi%7D%5Cgeqslant%201   eq?i%3D1%2C2%2C...%2Cn

eq?%5Cleft%5C%7B%5Cbegin%7Bmatrix%7D%20w%20%3D%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7Dx_%7Bi%7D%5C%5C%20%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7D%3D0%5C%5C%20%5Calpha%20_%7Bi%7D%5Cgeqslant%200%5Cend%7Bmatrix%7D%5Cright.

eq?%5Calpha%20_%7Bi%7D*%5B%28wx_%7Bi%7D+b%29y_%7Bi%7D-1%5D%3D0   eq?i%3D1%2C2%2C...%2Cn

        上述就是我们所说的KKT条件,KKT条件主要用来求解,但是实际上我们发现KKT条件中的参数还是很多,求解并不容易,为此我们又引入了拉格朗日对偶性,降低要求解的维度。

2.2 参考资料

文档资料:

Qoo-凸二次规划与KTT条件-支持向量机SVM(二) - 知乎

KKT条件,原来如此简单 | 理论+算例实践 - 知乎

Karush-Kuhn-Tucker (KKT)条件 - 知乎

视频资料:

“拉格朗日对偶问题”如何直观理解?“KKT条件” “Slater条件” “凸优化”打包理解_哔哩哔哩_bilibili

拉格朗日对偶性_哔哩哔哩_bilibili

三、对偶形式

3.1 由原始问题到对偶问题

        上面我们已经说到,原问题转化为对偶问题主要原因是对偶问题会好计算一些,对偶问题其实就是拉格朗日极大极小和极小极大问题。我们的原始问题是不等式约束问题,现在我们要将不等式约束问题转化为极大极小或者极小极大问题。我们这里写出原问题:

eq?%5Cunderset%7Bw%2Cb%7D%7Bmin%7D%5Cfrac%7B1%7D%7B2%7D%5Cleft%20%5C%7C%20w%20%5Cright%20%5C%7C%5E%7B2%7D

eq?s.t.   eq?%28wx_%7Bi%7D%20+%20b%29y_%7Bi%7D%5Cgeqslant%201   eq?i%3D1%2C2%2C...%2Cn

        首先构建拉格朗日辅助函数,注意该辅助函数约束条件部分前的符号是减号,不明白的话可以倒回去看梯度条件,就明白这个地方为什么是减号了。

eq?L%28w%2Cb%2C%5Calpha%20%29%20%3D%20%5Cfrac%7B1%7D%7B2%7D%5Cleft%20%5C%7C%20w%20%5Cright%20%5C%7C%5E%7B2%7D-%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7D%5B%28wx_%7Bi%7D%20+%20b%29y_%7Bi%7D%20-%201%5D         eq?%5Calpha%20_%7Bi%7D%5Cgeqslant%200

eq?%5Cunderset%7B%5Calpha_%7Bi%7D%3A%5Calpha_%7Bi%7D%20%5Cgeqslant%200%20%7D%7Bmax%7DL%28w%2Cb%2C%5Calpha%20%29的值,考虑以下两种情况:

        (1)eq?w%2Cb不满足原约束条件,即存在某个eq?x_%7Bi%7D使得:eq?wx_%7Bi%7D+b%20-%201%3C%200,要想值最大则有满足条件的部分eq?%5Calpha%20_%7Bi%7D%3D0,不满足的部分eq?%5Calpha%20_%7Bi%7D%20%3D%20+%5Cinfty,那么有:

eq?%5Cunderset%7B%5Calpha_%7Bi%7D%3A%5Calpha_%7Bi%7D%20%5Cgeqslant%200%20%7D%7Bmax%7DL%28w%2Cb%2C%5Calpha%20%29%20%3D+%5Cinfty

        (2)eq?w%2Cb满足原约束条件,则当eq?%5Calpha%20_%7Bi%7D%3D0时,值取到最大,即:

eq?%5Cunderset%7B%5Calpha_%7Bi%7D%3A%5Calpha_%7Bi%7D%20%5Cgeqslant%200%20%7D%7Bmax%7DL%28w%2Cb%2C%5Calpha%20%29%20%3D%5Cfrac%7B1%7D%7B2%7D%5Cleft%20%5C%7C%20w%20%5Cright%20%5C%7C%5E%7B2%7D

         综上所述:

6d9c876b543b41a1991821a282f8aa88.png

        这里的eq?w%2Cb是无约束的,可以取任意值,实际上就是当取到最优值的时候,对应的eq?w%2Cb必然满足原约束条件,所以可以不管约束条件只管放心大胆的去求极值就行。综上所述,可得极小极大问题eq?%5Cunderset%7Bw%2Cb%7D%7Bmin%7D%5Cunderset%7B%5Calpha_%7Bi%7D%3A%5Calpha_%7Bi%7D%20%5Cgeqslant%200%20%7D%7Bmax%7DL%28w%2Cb%2C%5Calpha%20%29等同于下:

eq?%5Cunderset%7Bw%2Cb%7D%7Bmin%7D%5Cunderset%7B%5Calpha_%7Bi%7D%3A%5Calpha_%7Bi%7D%20%5Cgeqslant%200%20%7D%7Bmax%7DL%28w%2Cb%2C%5Calpha%20%29%20%3D%20%5Cfrac%7B1%7D%7B2%7D%5Cleft%20%5C%7C%20w%20%5Cright%20%5C%7C%5E%7B2%7D

该极小极大问题的解与原始问题的解是一致的。到此为止我们完成了将原始问题转化为拉格朗日极小极大问题。我们顺理成章的可以引出他的对偶问题,极大极小问题:

eq?%5Cunderset%7B%5Calpha_%7Bi%7D%3A%5Calpha_%7Bi%7D%20%5Cgeqslant%200%20%7D%7Bmax%7D%5Cunderset%7Bw%2Cb%7D%7Bmin%7DL%28w%2Cb%2C%5Calpha%20%29

3.2 对偶问题的具体形式

        对于eq?%5Cunderset%7B%5Calpha_%7Bi%7D%3A%5Calpha_%7Bi%7D%20%5Cgeqslant%200%20%7D%7Bmax%7D%5Cunderset%7Bw%2Cb%7D%7Bmin%7DL%28w%2Cb%2C%5Calpha%20%29我们可以先求eq?%5Cunderset%7Bw%2Cb%7D%7Bmin%7DL%28w%2Cb%2C%5Calpha%20%29,该拉格朗日辅助函数可以看出也是一个凸函数,或者说是凹函数(凸函数就是极小值点在最下面,凹函数就是极大值点在最上面,凸的“拱”往下,凹的“拱”往上,这个地方不要太过纠结,毕竟加个负号就相互转换了)。另外,实际上对偶问题一定是一个凹函数,因为对偶函数是一族关于拉格朗日乘子(对应这里就是eq?%5Calpha)的仿射函数的逐点下确界,所以即使原问题不是凸的,对偶问题也是凹的,他的最优值只有一个,即梯度为0的点。因此可以得到条件如下:

eq?%5Cbigtriangledown%20_%7Bw%7DL%28w%2Cb%2C%5Calpha%20%29%20%3D%20w%20-%20%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dx_%7Bi%7Dy_%7Bi%7D%20%3D%200

eq?%5Cbigtriangledown%20_%7Bb%7DL%28w%2Cb%2C%5Calpha%20%29%20%3D%20-%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7D%3D0

        将该结论代入拉格朗日辅助函数可得:

eq?%5Cunderset%7Bw%2Cb%7D%7Bmin%7DL%28w%2Cb%2C%5Calpha%20%29%3D-%5Cfrac%7B1%7D%7B2%7D%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Csum_%7Bj%3D1%7D%5E%7Bn%7D%5Calpha_%7Bi%7D%20%5Calpha%20_%7Bj%7Dy_%7Bi%7Dy_%7Bj%7Dx_%7Bi%7Dx_%7Bj%7D+%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7D

        所以对偶问题可以转变为:

eq?%5Cunderset%7B%5Calpha_%7Bi%7D%3A%5Calpha_%7Bi%7D%20%5Cgeqslant%200%20%7D%7Bmax%7D-%5Cfrac%7B1%7D%7B2%7D%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Csum_%7Bj%3D1%7D%5E%7Bn%7D%5Calpha_%7Bi%7D%20%5Calpha%20_%7Bj%7Dy_%7Bi%7Dy_%7Bj%7Dx_%7Bi%7Dx_%7Bj%7D+%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7D

s.t.      eq?-%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7D%3D0

         进一步写成如下形式:

eq?%5Cunderset%7B%5Calpha%7D%7Bmin%7D%5Cfrac%7B1%7D%7B2%7D%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Csum_%7Bj%3D1%7D%5E%7Bn%7D%5Calpha_%7Bi%7D%20%5Calpha%20_%7Bj%7Dy_%7Bi%7Dy_%7Bj%7Dx_%7Bi%7Dx_%7Bj%7D-%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7D

s.t.    eq?%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7D%3D0

                             eq?%5Calpha%20_%7Bi%7D%5Cgeqslant%200    eq?i%3D1%2C2%2C3%2C...%2Cn

这就是对偶问题的具体形式了。

3.3 为什么可以将求解极小极打问题转化为求解极大极小问题?(具体证明我也没看)

        这个地方我只能给出个定理李航《机器学习方法》附录C里面这么说的,对偶问题是强对偶的情况下(目标函数是凸函数,约束集是凸集或者说这里的约束条件全是仿射函数,满足Slater条件),原问题的解eq?w%5E%7B*%7D%2Cb%5E%7B*%7D,与对偶问题的解eq?%5Calpha%20%5E%7B*%7D,这一对解能够满足KKT条件。前面我们已经说了,对于凸优化问题KKT条件解是唯一的,也就是说我们通过eq?%5Calpha%20%5E%7B*%7D和KKT条件求得的eq?w%2Cb,必然就是eq?w%5E%7B*%7D%2Cb%5E%7B*%7D也就是原问题的解。

3.4 参考资料

文档资料:

李航《机器学习方法》第七章、附录C

王书宁《凸优化》第五章

拉格朗日对偶问题_VelvetQuilt的博客-CSDN博客

机器学习中的数学——拉格朗日乘子法(二):不等式约束与KKT条件_von Neumann的博客-CSDN博客_拉格朗日乘子法 不等式约束

视频资料:

【数之道25】机器学习必经之路-SVM支持向量机的数学精华_哔哩哔哩_bilibili

拉格朗日对偶性_哔哩哔哩_bilibili

“拉格朗日对偶问题”如何直观理解?“KKT条件” “Slater条件” “凸优化”打包理解_哔哩哔哩_bilibili

四、对偶问题的求解

4.1 SMO算法理论推导(仅考虑线性可分时)

        (这个地方我先只考虑可分的情形,到不可分情形时我们再逐步深入。)

        经过上文的探讨,我们得到了SVM优化问题的对偶问题,如下:

eq?%5Cunderset%7B%5Calpha%7D%7Bmin%7D%5Cfrac%7B1%7D%7B2%7D%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Csum_%7Bj%3D1%7D%5E%7Bn%7D%5Calpha_%7Bi%7D%20%5Calpha%20_%7Bj%7Dy_%7Bi%7Dy_%7Bj%7Dx_%7Bi%7Dx_%7Bj%7D-%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7D

s.t.    eq?%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7D%3D0

                             eq?%5Calpha%20_%7Bi%7D%5Cgeqslant%200    eq?i%3D1%2C2%2C3%2C...%2Cn

        该对偶问题也是凸优化问题,针对该类问题我们可以使用梯度下降的方式求解,但是上述优化问题由于有约束条件eq?%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7D%3D0的存在,我们在使用梯度下降计算最优解时,不能够单变量下降,应当多个变量组合下降,保证满足约束条件。我们不在这里对使用梯度下降做过多探讨,针对SVM学术界已经提出了更高效的计算方法,即序列最小最优化算法(SMO)该算法于1998年由Platt提出,其论文见参考资料。

        SMO算法思想就是选取两个变量eq?%5Calpha%20_%7Bi%7Deq?%5Calpha%20_%7Bj%7D作为优化对象,其他eq?%5Calpha当做已知量。为啥不是选一个变量来优化?由约束条件决定的没办法单独对一个变量做优化。或者为啥不是选三个变量来优化?选三个就不叫“最小序列”优化算法了,主要是3个变量计算起来也不简单。将eq?%5Calpha%20_%7Bi%7Deq?%5Calpha%20_%7Bj%7D单独拎出来,所以有以下式子(为方便书写,我们假设eq?ieq?j就是1、2,1、2也具有一般性并不会影响结果,eq?X_%7Bij%7D表示eq?x_%7Bi%7D%5Ccdot%20x_%7Bj%7D点积):

        原问题的对偶问题实际上是一个二次规划问题,这个二次规划问题为什么能够分解为二次规划子问题来求解,以及关于为什么每次优化两个值eq?%5Calpha%20_%7Bi%7D%2C%5Calpha%20_%7Bj%7D,能够使原目标函数值减少,并且最终收敛的理论保证作者在原论文中提到过。感兴趣的请自行查看原文,部分原文内容如下:

a8a701789d614e9ca85bdcc346013360.png

        实际对应的理论是在Osuna, E的论文《An improved training algorithm for support vector machines》中提到的。

        我们把eq?%5Calpha%20_%7B1%7D%2C%5Calpha%20_%7B2%7D单独提出来得下式:

eq?%5Cunderset%7B%5Calpha%20_%7B1%7D%2C%5Calpha%20_%7B2%7D%7D%7Bmin%7DL%28%5Calpha%20_%7B1%7D%2C%5Calpha%20_%7B2%7D%29%3D%5Cfrac%7B1%7D%7B2%7D%5Calpha%20_%7B1%7D%5E%7B2%7DX_%7B11%7D+%5Cfrac%7B1%7D%7B2%7D%5Calpha%20_%7B2%7D%5E%7B2%7DX_%7B22%7D+%5Calpha_%7B1%7D%5Calpha_%7B2%7D%20y_%7B1%7Dy_%7B2%7DX_%7B12%7D-%28%5Calpha%20_%7B1%7D+%5Calpha%20_%7B2%7D%29+y_%7B1%7D%5Calpha%20_%7B1%7D%5Csum_%7Bi%3D3%7D%5E%7Bn%7Dy_%7Bi%7D%5Calpha%20_%7Bi%7DX_%7Bi1%7D+y_%7B2%7D%5Calpha%20_%7B2%7D%5Csum_%7Bi%3D3%7D%5E%7Bn%7Dy_%7Bi%7D%5Calpha%20_%7Bi%7DX_%7Bi2%7D

s.t.  eq?%5Calpha%20_%7B1%7Dy_%7B1%7D+%5Calpha%20_%7B2%7Dy_%7B2%7D%20%3D%20-%5Csum_%7Bi%3D3%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7D%20%3D%20%5Cvarepsilon        //  eq?%5Cvarepsilon为某一确定值

eq?%5Calpha%20_%7B1%7D%5Cgeqslant%200,eq?%5Calpha%20_%7B2%7D%5Cgeqslant%200

        有上述可知:

eq?%5Calpha_%7B1%7D%20%3D%20y_%7B1%7D%28%5Cvarepsilon%20-%5Calpha%20_%7B2%7Dy_%7B2%7D%29

        代入要优化的目标函数,可得:

eq?L%28%5Calpha%20_%7B2%7D%29%20%3D%5Cfrac%7B1%7D%7B2%7D%28%5Cvarepsilon%20-%5Calpha%20_%7B2%7Dy_%7B2%7D%29%5E2X_%7B11%7D+%5Cfrac%7B1%7D%7B2%7D%5Calpha%20%5E2X_%7B22%7D+%28%5Cvarepsilon%20-%5Calpha%20_%7B2%7Dy_%7B2%7D%29%5Calpha%20_%7B2%7Dy_%7B2%7DX_%7B12%7D-y_%7B1%7D%28%5Cvarepsilon%20-%5Calpha_%7B2%7Dy_%7B2%7D%29-%5Calpha_%7B2%7D+%28%5Cvarepsilon%20-%5Calpha%20_%7B2%7Dy_%7B2%7D%29%5Csum_%7Bi%3D3%7D%5E%7Bn%7Dy_%7Bi%7D%5Calpha%20_%7Bi%7DX_%7Bi1%7D+%5Calpha%20_%7B2%7Dy_%7B2%7D%5Csum_%7Bi%3D3%7D%5E%7Bn%7Dy_%7Bi%7D%5Calpha%20_%7Bi%7DX_%7Bi2%7D

        要想使得eq?L%28%5Calpha_%7B2%7D%29值最小,也就是其梯度等于0时为最小值,我们对eq?L%28%5Calpha_%7B2%7D%29求梯度,如下:

eq?%5Cbigtriangledown_%7B%5Calpha%20_%7B2%7D%7D%20L%28%5Calpha%20_%7B2%7D%29%3D%5Calpha%20_%7B2%7D%28X_%7B11%7D-2X_%7B12%7D+X_%7B22%7D%29-%5Cvarepsilon%20y_%7B2%7DX_%7B11%7D+%5Cvarepsilon%20y_%7B2%7DX_%7B12%7D+y_%7B1%7Dy_%7B2%7D-1-y_%7B2%7D%5Csum_%7Bi%3D3%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7DX_%7Bi1%7D+y_%7B2%7D%5Csum_%7Bi%3D3%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7DX_%7Bi2%7D%3D0

        得:

eq?%5Calpha%20_%7B2%7D%28X_%7B11%7D-2X_%7B12%7D+X_%7B22%7D%29%3D%5Cvarepsilon%20y_%7B2%7DX_%7B11%7D-%5Cvarepsilon%20y_%7B2%7DX_%7B12%7D-y_%7B1%7Dy_%7B2%7D+1+y_%7B2%7D%5Csum_%7Bi%3D3%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7DX_%7Bi1%7D-y_%7B2%7D%5Csum_%7Bi%3D3%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7DX_%7Bi2%7D

        又:eq?%5Cvarepsilon%20%3D%20%5Calpha%20_%7B1%7Dy_%7B1%7D+%5Calpha%20_%7B2%7Dy_%7B2%7D,和上式放到一起可以得含两个变量的方程组:

eq?%5Cleft%5C%7B%5Cbegin%7Bmatrix%7D%5Calpha%20_%7B2%7D%28X_%7B11%7D-2X_%7B12%7D+X_%7B22%7D%29%3D%5Cvarepsilon%20y_%7B2%7DX_%7B11%7D-%5Cvarepsilon%20y_%7B2%7DX_%7B12%7D-y_%7B1%7Dy_%7B2%7D+1+y_%7B2%7D%5Csum_%7Bi%3D3%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7DX_%7Bi1%7D-y_%7B2%7D%5Csum_%7Bi%3D3%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7DX_%7Bi2%7D%5C%5C%20%5Calpha%20_%7B1%7Dy_%7B1%7D+%5Calpha%20_%7B2%7Dy_%7B2%7D%3D%5Cvarepsilon%20%5Cend%7Bmatrix%7D%5Cright.

        这样我们就把求解二次规划子问题的解,变成了求解方程组。这个方程组看起来也不好求,但是我们有方法。求解线性方程组我们可以使用迭代法,只要在当前方程形式下解是逐步收敛的,那么就可以使用这种方法。相关知识请参考李庆扬《数值分析》第五版第6章——解线性方程组的迭代法。我们对eq?%5Calpha%20_%7B1%7Deq?%5Calpha%20_%7B2%7D赋满足条件(也就是前面说的对偶问题里面的两个约束,eq?%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7D%3D0eq?%5Calpha%20_%7Bi%7D%5Cgeqslant%200    eq?i%3D1%2C2%2C3%2C...%2Cn)的初值,这里我们可以赋初值eq?%5Calpha%20%3D0。迭代方程如下:

eq?%5Cleft%5C%7B%5Cbegin%7Bmatrix%7D%5Calpha%20_%7B2%7D%5E%7Bn+1%7D%28X_%7B11%7D-2X_%7B12%7D+X_%7B22%7D%29%3D%5Cvarepsilon%20y_%7B2%7DX_%7B11%7D-%5Cvarepsilon%20y_%7B2%7DX_%7B12%7D-y_%7B1%7Dy_%7B2%7D+1+y_%7B2%7D%5Csum_%7Bi%3D3%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7DX_%7Bi1%7D-y_%7B2%7D%5Csum_%7Bi%3D3%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7DX_%7Bi2%7D%5C%5C%20%5Calpha%20_%7B1%7D%5E%7Bn%7Dy_%7B1%7D+%5Calpha%20_%7B2%7D%5E%7Bn%7Dy_%7B2%7D%3D%5Cvarepsilon%20%5Cend%7Bmatrix%7D%5Cright.

        eq?%5Calpha%20_%7B2%7D%5E%7Bn%7D表示上一次结果,eq?%5Calpha%20_%7B2%7D%5E%7Bn+1%7D表示下一次结果。

        那么新的问题来了,我们该怎么去选取eq?%5Calpha%20_%7B1%7Deq?%5Calpha%20_%7B2%7D来进行迭代,前面说了eq?%5Calpha%20_%7B1%7Deq?%5Calpha%20_%7B2%7D是泛指,可能是eq?%5Calpha%20_%7B3%7Deq?%5Calpha%20_%7B4%7Deq?%5Calpha%20_%7B5%7D等。我们接下来对上述方程进行变形,然后告诉你该怎么去选(这个地方要是去遍历所有组合是不是也能求得解呢?我理解应该也是可以的就是效率低了点,后面实验一下)。

        设:eq?f%28x%29%20%3D%20wx%5E%7BT%7D+b

        根据KKT条件(前面说了对偶问题的解和原问题的解,放到一起满足KKT条件),eq?w%20%3D%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7Dx_%7Bi%7D,所以eq?f%28x%29%20%3D%20%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7Dx_%7Bi%7Dx%5E%7BT%7D+b

        所以:

eq?%5Cleft%5C%7B%5Cbegin%7Bmatrix%7D%20f%28x_%7B1%7D%29%3D%5Calpha%20_%7B1%7Dy_%7B1%7DX_%7B11%7D+%5Calpha%20_%7B2%7Dy_%7B2%7DX_%7B21%7D+%20%5Csum_%7Bi%3D3%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7DX_%7Bi1%7D+b%5C%5C%20f%28x_%7B2%7D%29%3D%5Calpha%20_%7B1%7Dy_%7B1%7DX_%7B12%7D+%5Calpha%20_%7B2%7Dy_%7B2%7DX_%7B22%7D+%20%5Csum_%7Bi%3D3%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7DX_%7Bi2%7D+b%20%5Cend%7Bmatrix%7D%5Cright.

eq?%5CRightarrow%20%5Cleft%5C%7B%5Cbegin%7Bmatrix%7D%20%5Csum_%7Bi%3D3%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7DX_%7Bi1%7D%3D%20f%28x_%7B1%7D%29-%5Calpha%20_%7B1%7Dy_%7B1%7DX_%7B11%7D-%5Calpha%20_%7B2%7Dy_%7B2%7DX_%7B21%7D-b%5C%5C%20%5Csum_%7Bi%3D3%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7DX_%7Bi2%7D%3Df%28x_%7B2%7D%29-%5Calpha%20_%7B1%7Dy_%7B1%7DX_%7B12%7D-%5Calpha%20_%7B2%7Dy_%7B2%7DX_%7B22%7D-b%20%5Cend%7Bmatrix%7D%5Cright.

        将上式代入迭代方程(这里是代入迭代方程的前一步,即eq?%5Calpha%20_%7B1%7D%5E%7Bn%7Deq?%5Calpha%20_%7B2%7D%5E%7Bn%7D)化简后可得:

eq?%5Calpha%20_%7B2%7D%5E%7Bn+1%7D%3D%5Calpha%20_%7B2%7D%5E%7Bn%7D+%5Cfrac%7By_%7B2%7D%5Cleft%20%5B%20f%28x_%7B1%7D%29-y_%7B1%7D-%28f%28x_%7B2%7D%29-y_%7B2%7D%29%20%5Cright%20%5D%7D%7BX_%7B11%7D-2X_%7B12%7D+X_%7B22%7D%7D

        接下来我们再把前面的KKT条件放这里,并进行新的分析:

      

eq?%28wx_%7Bi%7D%20+%20b%29y_%7Bi%7D%5Cgeqslant%201   eq?i%3D1%2C2%2C...%2Cn

eq?%5Cleft%5C%7B%5Cbegin%7Bmatrix%7D%20w%20%3D%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7Dx_%7Bi%7D%5C%5C%20%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7D%3D0%5C%5C%20%5Calpha%20_%7Bi%7D%5Cgeqslant%200%5Cend%7Bmatrix%7D%5Cright.

eq?%5Calpha%20_%7Bi%7D*%5B%28wx_%7Bi%7D+b%29y_%7Bi%7D-1%5D%3D0   eq?i%3D1%2C2%2C...%2Cn

        我们要注意我们通过迭代去求得的eq?%5Calpha(注意这里的eq?%5Calpha是(eq?%5Calpha%20_%7B1%7D%2C%5Calpha%20_%7B2%7D%2C...%2C%5Calpha%20_%7Bn%7D)向量),什么时候就是我们想要的eq?%5Calpha呢?意思就是什么时候得到的eq?%5Calpha就是是目标函数取得最优值的eq?%5Calpha。回忆前面的内容,满足KKT条件的eq?%5Calpha就是最优的eq?%5Calpha。那么我们就知道该如何去选取eq?%5Calpha%20_%7B1%7D%5E%7Bn%7Deq?%5Calpha%20_%7B2%7D%5E%7Bn%7D,选取违背KKT条件的,又根据Osuna, E的理论对含有违背KKT条件的QP子问题进行优化,一定能够使原问题得到下降,在没有达到最优前那么一定会有对应的eq?%5Calpha%20_%7Bi%7D对应的样本违背KKT条件。

        接下来如何快速的选取对应违背KKT条件的eq?%5Calpha%20_%7Bi%7D呢?再次回到KKT条件。我们以eq?%5Calpha%20_%7Bi%7D为关注点,来分情况判断。

eq?%5Calpha%20_%7Bi%7D%5Cleft%5C%7B%5Cbegin%7Bmatrix%7D%20%3D0%5Cquad%28wx_%7Bi%7D+b%29y_%7Bi%7D%3E1%5C%5C%20%3E0%20%5Cquad%28wx_%7Bi%7D+b%29y_%7Bi%7D%3D1%5Cend%7Bmatrix%7D%5Cright.

        对于无效的约束条件,其对应的拉格朗日乘子eq?%5Calpha%20_%7Bi%7D为0,当约束条件有效时,其对应的拉格朗日乘子eq?%5Calpha%20_%7Bi%7D大于0。eq?%28wx_%7Bi%7D+b%29y_%7Bi%7D代表的就是软间隔距离。利用上式我们可以简化KKT条件的判断。另外由于对偶问题实际上是一个凸优化问题,要想使优化值下降的足够多,那么我们就要想使eq?%5Calpha%20_%7Bi%7D%5E%7Bn%7Deq?%5Calpha%20_%7Bi%7D%5E%7Bn+1%7D之间变化足够大。结合前面的迭代式:

eq?%5Calpha%20_%7B2%7D%5E%7Bn+1%7D%3D%5Calpha%20_%7B2%7D%5E%7Bn%7D+%5Cfrac%7By_%7B2%7D%5Cleft%20%5B%20f%28x_%7B1%7D%29-y_%7B1%7D-%28f%28x_%7B2%7D%29-y_%7B2%7D%29%20%5Cright%20%5D%7D%7BX_%7B11%7D-2X_%7B12%7D+X_%7B22%7D%7D

也就是eq?%5Cfrac%7By_%7B2%7D%5Cleft%20%5B%20f%28x_%7B1%7D%29-y_%7B1%7D-%28f%28x_%7B2%7D%29-y_%7B2%7D%29%20%5Cright%20%5D%7D%7BX_%7B11%7D-2X_%7B12%7D+X_%7B22%7D%7D,变化足够大。在SMO原论文中,这个地方分母是核函数,由于核函数计算比较困难,原论文实际上忽略了分母,只考虑分子的变化足够大,即eq?f%28x_%7B1%7D%29-y_%7B1%7D-%28f%28x_%7B2%7D%29-y_%7B2%7D%29变化足够大,这个就实际上可能会导致优化值降低的不够。那么现在我们就可以在外层循环中先找到一个违背KKT条件的eq?%5Calpha%20_%7B1%7D%5E%7Bn%7D以及其对应的样本(这个地方说是违背越严重的点带来的优化越多,怎么判断严重程度呢?就是用到上面说的简化版的判断是否违背KKT的式子,比如说eq?%5Calpha%20_%7Bi%7D%3D0时,那么eq?%28wx_%7Bi%7D+b%29y_%7Bi%7D-1值越大则说明违背越严重),然后在内层循环中找到一个与eq?%5Calpha%20_%7B1%7D%5E%7Bn%7D能够产生足够大差的eq?%5Calpha%20_%7B2%7D%5E%7Bn%7D以及其对应的样本。接下来我们再考虑一个问题。

eq?%5Calpha%20_%7B2%7D%5E%7Bn+1%7D%3D%5Calpha%20_%7B2%7D%5E%7Bn%7D+%5Cfrac%7By_%7B2%7D%5Cleft%20%5B%20f%28x_%7B1%7D%29-y_%7B1%7D-%28f%28x_%7B2%7D%29-y_%7B2%7D%29%20%5Cright%20%5D%7D%7BX_%7B11%7D-2X_%7B12%7D+X_%7B22%7D%7D

        这个求解实际上对于eq?%5Calpha%20_%7Bi%7D是一个无约束求解,但实际上在KKT条件中,eq?%5Calpha%20_%7Bi%7D%5Cgeqslant%200。因此我们需要对求得的eq?%5Calpha%20_%7Bi%7D进行裁剪。注意要保证eq?%5Calpha%20_%7B1%7D%5E%7Bn+1%7Deq?%5Calpha%20_%7B2%7D%5E%7Bn+1%7D同时满足条件。通过上述迭代式我们求得了eq?%5Calpha%20_%7B2%7D%5E%7Bn+1%7D,我们怎么求eq?%5Calpha%20_%7B1%7D%5E%7Bn+1%7D呢?

又有:eq?%5Calpha%20_%7B1%7D%5E%7Bn%7Dy_%7B1%7D+%5Calpha%20_%7B2%7D%5E%7Bn%7Dy_%7B2%7D%3D%5Calpha%20_%7B1%7D%5E%7Bn+1%7Dy_%7B1%7D+%5Calpha%20_%7B2%7D%5E%7Bn+1%7Dy_%7B2%7D

所以:eq?%5Calpha%20_%7B1%7D%5E%7Bn+1%7D%3D%5Calpha%20_%7B1%7D%5E%7Bn%7D+y_%7B1%7Dy_%7B2%7D%28%5Calpha%20_%7B2%7D%5E%7Bn%7D-%5Calpha%20_%7B2%7D%5E%7Bn+1%7D%29

考虑:eq?%5Calpha%20_%7B1%7D%5Cgeqslant%200eq?%5Calpha%20_%7B2%7D%5Cgeqslant%200

得:eq?%5Cleft%5C%7B%5Cbegin%7Bmatrix%7D%200%5Cleqslant%5Calpha%20_%7B2%7D%5E%7Bn+1%7D%5Cleqslant%20%5Calpha%20_%7B2%7D%5E%7Bn%7D+%5Calpha%20_%7B1%7D%5E%7Bn%7D%5Cquad%20y_%7B1%7D%3Dy_%7B2%7D%5C%5C%20max%5Cleft%20%5C%7B%200%2C%5Calpha%20_%7B2%7D%5E%7Bn%7D-%5Calpha%20_%7B1%7D%5E%7Bn%7D%20%5Cright%20%5C%7D%5Cleqslant%5Calpha%20_%7B2%7D%5E%7Bn+1%7D%20%5Cquad%20y_%7B1%7D%5Cneq%20y_%7B2%7D%5Cend%7Bmatrix%7D%5Cright.

接下来更新阈值b,我们分情况讨论:

        ①当eq?%5Calpha%20_%7B2%7D%5E%7Bn+1%7D%5Cneq%200eq?%5Calpha%20_%7B1%7D%5E%7Bn+1%7D%3D%200时,则eq?%28wx_%7B2%7D+b%29y_%7B2%7D%3D1

        ②当eq?%5Calpha%20_%7B2%7D%5E%7Bn+1%7D%3D%200eq?%5Calpha%20_%7B1%7D%5E%7Bn+1%7D%5Cneq%200时,则eq?%28wx_%7B1%7D+b%29y_%7B1%7D%3D1

        ③当eq?%5Calpha%20_%7B2%7D%5E%7Bn+1%7D%5Cneq%200eq?%5Calpha%20_%7B1%7D%5E%7Bn+1%7D%5Cneq%200时,则eq?%5Cleft%5C%7B%5Cbegin%7Bmatrix%7D%20%28wx_%7B1%7D+b_%7B1%7D%29y_%7B1%7D%3D1%5C%5C%20%28wx_%7B2%7D+b_%7B2%7D%29y_%7B2%7D%3D1%20%5Cend%7Bmatrix%7D%5Cright.,此时eq?b_%7B1%7D%3Db_%7B2%7D

        ③当eq?%5Calpha%20_%7B2%7D%5E%7Bn+1%7D%3D%200eq?%5Calpha%20_%7B1%7D%5E%7Bn+1%7D%3D%200时,则eq?%5Cleft%5C%7B%5Cbegin%7Bmatrix%7D%20%28wx_%7B2%7D+b%29y_%7B2%7D%3E%201%5C%5C%20%28wx_%7B1%7D+b%29y_%7B1%7D%3E%201%20%5Cend%7Bmatrix%7D%5Cright.,即软间隔均大于1。这种情况又要细分讨论。(实际上通过后面的实验我发现,在优化后eq?%5Calpha%20_%7B2%7D%5E%7Bn+1%7Deq?%5Calpha%20_%7B1%7D%5E%7Bn+1%7D其中至少一个会变成支撑向量,所有根本不会出现两者都等于0的情况,所以下面的讨论可以忽略掉,我会在文章结尾部分贴出选点以及每次迭代的优化效果,你就会发现必然会有至少一个优化变量变成了支撑向量)

        (1)当eq?y_%7B1%7D%5Cneq%20y_%7B2%7D时,我们可以得到:eq?-1-wx_%7B1%7D%3Eb%3E1-wx_%7B2%7Deq?-1-wx_%7B2%7D%3Eb%3E1-wx_%7B1%7D,总之获得的是一个区间。这个区间范围内的值都可以取,都可以使KKT条件成立;

        (2)当eq?y_%7B1%7D%3D%20y_%7B2%7D时,我们可以得到:eq?b%3Emax%5Cleft%20%5C%7B1-wx_%7B2%7D%2C1-wx_%7B1%7D%20%5Cright%20%5C%7Deq?b%3Cmin%5Cleft%20%5C%7B-1-wx_%7B2%7D%2C-1-wx_%7B1%7D%20%5Cright%20%5C%7D,这种情况在原论文中实际上被忽略掉了,但是按照前面选取eq?%5Calpha%20_%7B1%7D%5E%7Bn%7Deq?%5Calpha%20_%7B2%7D%5E%7Bn%7D的策略来讲这种情况实际上是不会出现的,因为要使eq?f%28x_%7B1%7D%29-y_%7B1%7D-%28f%28x_%7B2%7D%29-y_%7B2%7D%29变化足够大,那么eq?y_%7B1%7D一定不等于eq?y_%7B2%7D。假设遇到了这种情况,一定要更新b的话,可以让eq?b%3Dmax%5Cleft%20%5C%7B1-wx_%7B2%7D%2C1-wx_%7B1%7D%20%5Cright%20%5C%7Deq?y_%7B1%7D%2Cy_%7B2%7D%3E0eq?b%3Dmin%5Cleft%20%5C%7B-1-wx_%7B2%7D%2C-1-wx_%7B1%7D%20%5Cright%20%5C%7D,eq?y_%7B1%7D%2Cy_%7B2%7D%3C0(这个时候其实就是原文中说的eq?L%3DH时候,这个时候作者直接return 0了放弃本次优化了,实际上也是这么个情况,没有限制到b的范围,和我最初随机给的b实际上没什么本质区别,因为我最初给的b必然能够使至少一个样本满足KKT条件,而现在这个优化后也就使至少两个样本满足KKT条件,没太大意义);

74af7205f3f94db6b7f55e2720a45c68.png

        为了方便理解我画个图来表示上面说的eq?y_%7B1%7D%3D%20y_%7B2%7D的情况优化前和优化后的区别。

9798fed978d94820b3d20c4ec2d4071e.png0d60dad48aec42f897cd2be567d4b833.png

         左侧就是我随便初始化了一个超平面,右侧两个绿色圈出来的样本就是我们选的同号的样本,然后为了让这两个样本满足KKT条件,我们计算出了右侧这个新的超平面。但是我们看结果,新的超平面对于原来有什么大的优化吗?没有。所以这种情况实际上是没什么意义的,上图只是一个示意,想表达的意思就是这种优化和之前的随机初始化没什么区别,运气好你能优化,运气不好越来越差,而且这种情况是不可能出现的,所以作者也直接放弃了这种情况下的优化。所以就得两个异号的样本来做优化才是有意义的,最后优化的超平面会在两个异号的样本之间。

        为了方便计算,我们令eq?E_%7Bi%7D%3D%20f%28x_%7Bi%7D%29-y_%7Bi%7D,并将每个样本的eq?E_%7Bi%7D保存在一个列表中。那么计算eq?%5Calpha%20_%7B2%7D%5E%7Bn+1%7D的迭代式可以写成:

eq?%5Calpha%20_%7B2%7D%5E%7Bn+1%7D%3D%5Calpha%20_%7B2%7D%5E%7Bn%7D+%5Cfrac%7By_%7B2%7D%5Cleft%20%5B%20E_%7B1%7D-E_%7B2%7D%5Cright%20%5D%7D%7BX_%7B11%7D-2X_%7B12%7D+X_%7B22%7D%7D

对b的更新:

eq?%5Cleft%5C%7B%5Cbegin%7Bmatrix%7D%20%5Calpha%20_%7B1%7D%5E%7Bn+1%7Dy_%7B1%7DX_%7B12%7D+%5Calpha%20_%7B2%7D%5E%7Bn+1%7Dy_%7B2%7DX_%7B22%7D+%5Csum_%7Bi%3D3%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7DX_%7Bi2%7D+b_%7B2%7D%5E%7Bn+1%7D%3Dy_%7B2%7D%5C%5C%20E_%7B2%7D%5E%7Bn%7D%3D%5Csum_%7Bi%3D3%7D%5E%7Bn%7D%5Calpha%20_%7Bi%7Dy_%7Bi%7DX_%7Bi2%7D+%5Calpha%20_%7B1%7D%5E%7Bn%7Dy_%7B1%7DX_%7B12%7D+%5Calpha%20_%7B2%7D%5E%7Bn%7Dy_%7B2%7DX_%7B22%7D+b_%7B2%7D%5E%7Bn%7D-y_%7B2%7D%20%5Cend%7Bmatrix%7D%5Cright.

两式联立可得:

eq?b_%7B2%7D%5E%7Bn+1%7D%3D-E_%7B2%7D%5E%7Bn%7D-y_%7B1%7DX_%7B12%7D%28%5Calpha%20_%7B1%7D%5E%7Bn+1%7D-%5Calpha%20_%7B1%7D%5E%7Bn%7D%29-y_%7B2%7DX_%7B22%7D%28%5Calpha%20_%7B2%7D%5E%7Bn+1%7D-%5Calpha%20_%7B2%7D%5E%7Bn%7D%29+b%5E%7Bn%7D

同理:

eq?b_%7B1%7D%5E%7Bn+1%7D%3D-E_%7B1%7D%5E%7Bn%7D-y_%7B1%7DX_%7B11%7D%28%5Calpha%20_%7B1%7D%5E%7Bn+1%7D-%5Calpha%20_%7B1%7D%5E%7Bn%7D%29-y_%7B2%7DX_%7B21%7D%28%5Calpha%20_%7B2%7D%5E%7Bn+1%7D-%5Calpha%20_%7B2%7D%5E%7Bn%7D%29+b%5E%7Bn%7D

eq?E_%7Bi%7D的更新:

eq?E_%7Bi%7D%5E%7Bn+1%7D%20%3D%20%5Csum_%7Bi%3D1%7D%5E%7Bn%7Dy_%7Bj%7D%5Calpha%20_%7Bj%7DX_%7Bij%7D+b%5E%7Bn+1%7D-y_%7Bi%7D

在一定精度条件下满足KKT,则停止算法,否则进行循环。算法流程图如下:

90979864e683427796ee5d39417f59af.jpeg

至此我们完成了线性可分情况下的支持向量机的整个流程推导计算流程,有什么问题欢迎交流。

4.2 SMO算法代码实现

        在实际代码实现的过程中,为了方便计算。我们把KKT的条件判断可以改一下,原KKT条件的判断如下:

eq?%5Calpha%20_%7Bi%7D%5Cleft%5C%7B%5Cbegin%7Bmatrix%7D%20%3D0%5Cquad%28wx_%7Bi%7D+b%29y_%7Bi%7D%3E1%5C%5C%20%3E0%20%5Cquad%28wx_%7Bi%7D+b%29y_%7Bi%7D%3D1%5Cend%7Bmatrix%7D%5Cright.

因为eq?f%28x_%7Bi%7D%29%20%3D%20wx_%7Bi%7D%5E%7BT%7D+beq?E_%7Bi%7D%3D%20f%28x_%7Bi%7D%29-y_%7Bi%7D,所以eq?%28wx_%7Bi%7D+b%29y_%7Bi%7D%3Df%28x_%7Bi%7D%29y_%7Bi%7D%3DE_%7Bi%7Dy_%7Bi%7D+1

改后如下:

eq?%5Calpha%20_%7Bi%7D%5Cleft%5C%7B%5Cbegin%7Bmatrix%7D%20%3D0%5Cquad%20E_%7Bi%7Dy_%7Bi%7D%3E0%5C%5C%20%3E0%20%5Cquad%20E_%7Bi%7Dy_%7Bi%7D%3D0%5Cend%7Bmatrix%7D%5Cright.

        详细代码如下(作者时间有限,代码可能比较粗糙还请见谅,下面的代码可直接运行出结果),先贴运行结果如下,这是15个样本的列子:

86cd4e08a4ce4f6687774c6792ab4a8c.png

# 作者: wxj233
# 开发时间: 2023/6/12 8:28


import numpy as np
import matplotlib.pyplot as plt


class SMO:
    def __init__(self, X, t):
        """
        初始化
        :param X: 样本,X每一行为一个样本,列为样本维度。列如:
        [[1,2,3],
        [4,5,6]]
        就是一个两个样本,每个样本有三个维度的数据集。
        :param t: 样本标签,为一维数组,长度应当和样本数量一致。
        :return:
        """
        assert X.shape[0] == t.size, "样本维度与标签维度不一致"
        self.X = X
        self.t = t
        self.a = np.zeros_like(t)  # 初始化α为0,因为没有α这个字母,所以用a代替
        self.b = 0  # 初始化b为0
        self.E = -t
        self.d = 1e-3  # KKT条件的精度范围,因为没有ε,就用字母d代替
        self.w = np.zeros(X.shape[1])

        self.error = np.zeros_like(t)  # 用于记录违背KKT条件的情况

    def KKT_error(self):
        """
        计算精度范围内的KKT的违背情况,没有违背则对应的值为0
        :return:
        """
        for i in range(self.a.size):
            if (self.a[i] == 0 and self.E[i] * self.t[i] > 0) or \
                    (self.a[i] > 0 and np.abs(self.E[i] * self.t[i]) < self.d):  # 精度范围内满足KKT条件
                self.error[i] = 0
            else:
                self.error[i] = self.E[i] * self.t[i]

        return self.error

    def cal_b(self, i_a1, i_a2, a1_new, a2_new, E, a, b):
        """
        计算新的b值
        :param i_a1: 第一个优化值的索引
        :param i_a2: 第二个优化值的索引
        :param a1_new: 第一个拉格朗日乘子的新值
        :param a2_new: 第二个拉格朗日乘子的新值
        :param E: 列表E
        :param a: α列表
        :param b: 阈值
        :return: 新的b
        """
        b1 = -E[i_a1] - self.t[i_a1] * np.dot(self.X[i_a1], self.X[i_a1])*(a1_new - a[i_a1]) \
             - self.t[i_a2] * np.dot(self.X[i_a2], self.X[i_a1])*(a2_new - a[i_a2]) + b
        b2 = -E[i_a2] - self.t[i_a1] * np.dot(self.X[i_a1], self.X[i_a2])*(a1_new - a[i_a1]) \
             - self.t[i_a2] * np.dot(self.X[i_a2], self.X[i_a2])*(a2_new - a[i_a2]) + b
        if a1_new > 0:
            b = b1
            return b
        if a2_new > 0:
            b = b2
            return b
        return (b1 + b2) / 2

    def cal_Ei(self, i_a1, i_a2, a, b):
        """
        计算E1和E2
        :param i_a1: 第一个优化值的索引
        :param i_a2: 第二个优化值的索引
        :param a: α列表
        :param b: 阈值
        :return: E1, E2
        """
        a = a.reshape(-1, 1)
        t = self.t.reshape(-1, 1)
        E1 = np.dot(self.X[i_a1], np.sum(self.X * a * t, axis=0)) + b - t[i_a1]
        E2 = np.dot(self.X[i_a2], np.sum(self.X * a * t, axis=0)) + b - t[i_a2]
        return E1, E2

    def update_w(self):
        """
        更新w
        :return:
        """
        a = self.a.reshape(-1, 1)
        t = self.t.reshape(-1, 1)
        self.w = np.sum(self.X * a * t, axis=0)

    def update_E(self):
        """
        更新列表E
        :return:
        """
        self.update_w()
        self.E = np.dot(self.X, self.w) + self.b - self.t

    def calculate_loss(self, i_a1, i_a2):
        """
        计算拉格朗日乘子对应的损失值,同时会顺带一起返回新的a, b, E, w
        :param i_a1: 第一个优化值的索引
        :param i_a2: 第二个优化值的索引
        :return: loss, a, b, E, w
        """
        b = self.b
        a = np.copy(self.a)
        E = np.copy(self.E)
        t = self.t

        e = np.dot(self.X[i_a1], self.X[i_a1]) + np.dot(self.X[i_a2], self.X[i_a2]) - 2*np.dot(self.X[i_a1], self.X[i_a2])
        while True:
            a2_new = a[i_a2] + t[i_a2] * (E[i_a1] - E[i_a2]) / e

            if t[i_a1] == t[i_a2]:  # 裁剪
                if a2_new < 0 or a2_new > a[i_a1] + a[i_a2]:  # 碰到边界,说明被裁剪了,计算可以停止了。
                    a2_new = np.median(np.array([0, a2_new, a[i_a1] + a[i_a2]]))
                    a1_new = a[i_a1] + t[i_a1] * t[i_a2] * (a[i_a2] - a2_new)
                    b = self.cal_b(i_a1, i_a2, a1_new, a2_new, E, a, b)  # 更新b
                    a[i_a1] = a1_new
                    a[i_a2] = a2_new
                    E[i_a1], E[i_a2] = self.cal_Ei(i_a1, i_a2, a, b)  # 更新E1,E2
                    break
            else:
                if a2_new < 0 or a2_new < a[i_a2] - a[i_a1]:  # 碰到边界,说明被裁剪了,计算可以停止了。
                    a2_new = np.max(np.array([0, a[i_a2] - a[i_a1], a2_new]))
                    a1_new = a[i_a1] + t[i_a1] * t[i_a2] * (a[i_a2] - a2_new)
                    b = self.cal_b(i_a1, i_a2, a1_new, a2_new, E, a, b)  # 更新b
                    a[i_a1] = a1_new
                    a[i_a2] = a2_new
                    E[i_a1], E[i_a2] = self.cal_Ei(i_a1, i_a2, a, b)  # 更新E1,E2
                    break

            if np.abs(a2_new - a[i_a2]) < 1e-5:  # 满足计算精度也可以停止计算了
                a1_new = a[i_a1] + t[i_a1] * t[i_a2] * (a[i_a2] - a2_new)
                b = self.cal_b(i_a1, i_a2, a1_new, a2_new, E, a, b)  # 更新b
                a[i_a1] = a1_new
                a[i_a2] = a2_new
                E[i_a1], E[i_a2] = self.cal_Ei(i_a1, i_a2, a, b)  # 更新E1,E2
                break

            a1_new = a[i_a1] + t[i_a1] * t[i_a2]*(a[i_a2] - a2_new)
            b = self.cal_b(i_a1, i_a2, a1_new, a2_new, E, a, b)  # 更新b
            a[i_a1] = a1_new
            a[i_a2] = a2_new
            E[i_a1], E[i_a2] = self.cal_Ei(i_a1, i_a2, a, b)  # 更新E1,E2

        a1 = a.reshape(-1, 1)
        t1 = t.reshape(-1, 1)
        w = np.sum(self.X * a1 * t1, axis=0)
        loss = 1/2*np.dot(w, w)-np.sum(a1)
        return a, b, E, w, loss


    def plotW(self, *point):
        """
        绘图
        :param point: 选择的点
        :return:
        """
        fig, ax = plt.subplots()  # 绘图
        # 绘制样本点
        samples_x_r = []
        samples_y_r = []
        samples_x_b = []
        samples_y_b = []
        for i in range(self.t.size):
            if self.t[i] == 1:
                samples_x_r.append(self.X[i, 0])
                samples_y_r.append(self.X[i, 1])
            elif self.t[i] == -1:
                samples_x_b.append(self.X[i, 0])
                samples_y_b.append(self.X[i, 1])
        ax.scatter(samples_x_r, samples_y_r, color="r", label="red")
        ax.scatter(samples_x_b, samples_y_b, color="b", label="blue")
        if len(point) == 2:
            i_a1 = point[0]
            i_a2 = point[1]
            ax.scatter(X[i_a1, 0], X[i_a1, 1], color="g", alpha=1, marker="*", label="point1")
            ax.scatter(X[i_a2, 0], X[i_a2, 1], color="y", alpha=1, marker="*", label="point2")

        x = np.arange(-10, 10, 0.01)  # 规定点间隔,依据间隔来画图
        y = (-self.w[0] * x - self.b) / self.w[1]
        ax.plot(x, y, label="wx+b=0")
        y1 = (1-self.w[0] * x - self.b) / self.w[1]
        ax.plot(x, y1, label="wx+b=1")
        y2 = (-1 - self.w[0] * x - self.b) / self.w[1]
        ax.plot(x, y2, label="wx+b=-1")

        ax.set_title("SVM-SMO")
        ax.legend(loc='upper left', bbox_to_anchor=(0.5, 1))  # 图列左上方位置相对于坐标的位置
        ax.set_xlabel('x')
        ax.set_ylabel('y')
        plt.show()

    def getI_a1(self, i_a2):
        """
        按照与E[i_a2]违背程度排序,越违背的排越前面
        :param i_a2: 第一个选点
        :return: 第二个选点的一个列表(这个列表按违背程度排序)
        """
        NKKT_list = []  # 不满足KKT条件的索引列表
        KKT_list = []  # 满足KKT条件的索引列表
        list = []
        if self.a[i_a2] == 0:
            if self.t[i_a2] == -1:
                E = self.E
                min_max_list = np.argsort(E)  # 从小到大排序,选出(E1 - E2)差值最大的点,就是E2尽可能的小
                for i in range(E.size):
                    if min_max_list[i] != i_a2:  # 确保i_a1 != i_a2
                        list.append(min_max_list[i])
                        if self.error[min_max_list[i]] != 0:
                            NKKT_list.append(min_max_list[i])
                        else:
                            KKT_list.append(min_max_list[i])
                NKKT_list.extend(KKT_list)
                return NKKT_list, list
            else:
                E = self.E
                min_max_list = np.argsort(E)  # 从小到大排序,选出(E1 - E2)差值最小的点,就是E2尽可能的大
                for i in range(E.size):
                    if min_max_list[-(i+1)] != i_a2:  # 确保i_a1 != i_a2
                        list.append(min_max_list[-(i+1)])
                        if self.error[min_max_list[-(i+1)]] != 0:
                            NKKT_list.append(min_max_list[-(i+1)])
                        else:
                            KKT_list.append(min_max_list[-(i+1)])
                NKKT_list.extend(KKT_list)
                return NKKT_list, list
        else:
            if self.E[i_a2] > 0:
                E = self.E
                min_max_list = np.argsort(E)  # 从小到大排序,选出(E1 - E2)差值最大的点,就是E2尽可能的小
                for i in range(E.size):
                    if min_max_list[i] != i_a2:  # 确保i_a1 != i_a2
                        list.append(min_max_list[i])
                        if self.error[min_max_list[i]] != 0:
                            NKKT_list.append(min_max_list[i])
                        else:
                            KKT_list.append(min_max_list[i])
                NKKT_list.extend(KKT_list)
                return NKKT_list, list
            else:
                E = self.E
                min_max_list = np.argsort(E)  # 从小到大排序,选出(E1 - E2)差值最小的点,就是E2尽可能的大
                for i in range(E.size):
                    if min_max_list[-(i+1)] != i_a2:  # 确保i_a1 != i_a2
                        list.append(min_max_list[-(i+1)])
                        if self.error[min_max_list[-(i+1)]] != 0:
                            NKKT_list.append(min_max_list[-(i+1)])
                        else:
                            KKT_list.append(min_max_list[-(i+1)])
                NKKT_list.extend(KKT_list)
                return NKKT_list, list

    def loss(self):
        """
        计算当前损失值
        :return:
        """
        return 1/2*np.dot(self.w, self.w)-np.sum(self.a)

    def train(self):
        """
        训练函数
        :return:
        """
        self.update_E()  # 更新列表E,计算一次w
        self.KKT_error()
        last_loss = self.loss()

        loss_y = [last_loss]
        while np.max(np.abs(self.error)) > 0:  # 如果所有点都满足KKT条件了(即误差全部为0),那么说明达到最优训练结束,循环停止。
            issatloss = False  # 是否还能够产生足够的下降
            min_max_sort = np.argsort(np.abs(self.error))
            isValid = False
            for s in range(1, min_max_sort.size+1):
                if isValid:
                    break
                i_a2 = min_max_sort[-s]
                if self.error[i_a2] == 0:  # 说明已经无法满足下降了,因为前面违背KKT条件的点都已经试过了
                    break
                NKKT_list, list = self.getI_a1(i_a2)
                # for i_a1 in NKKT_list:
                for i_a1 in list:
                    a, b, E, w, loss = self.calculate_loss(i_a1, i_a2)
                    if -(loss - last_loss) > 1e-4:
                        # self.plotW(i_a1, i_a2)
                        self.a = a
                        self.b = b
                        self.E = E
                        self.w = w
                        last_loss = loss
                        loss_y.append(last_loss)
                        isValid = True
                        issatloss = True
                        # self.plotW(i_a1, i_a2)
                        break

            if not issatloss:
                print("无法产生足够的下降")
                break
            self.update_E()  # 更新列表E
            self.KKT_error()  # 重新计算KKT的违背情况

        # np.save("NKKT_loss", np.array(loss_y))
        # np.save("list_loss", np.array(loss_y))
        print("α", self.a)
        print("error", np.abs(self.error))
        print(self.loss())
        self.plotW()


if __name__ == '__main__':
    np.random.seed(1)
    X = np.random.rand(15, 2) * 20 - 10  # 产生随机样本
    t = np.sign(X.sum(axis=1))  # 为样本打标记

    smo = SMO(X, t)
    smo.train()

4.3 编写程序的过程中的一点点收获

4.3.1 关于选点与优化结果

        下面我用几幅图来表名选点及其优化效果(左侧为在当前情况下的选点,右侧为优化后的结果):

a7d22b8b0a4f47b28459cb290dc35407.pngaedb28930e9f4db3ad4f65a3d21baf97.png

 06677237184145d3928964abe2e9efd9.pngb2a7fb5e4c3349ddb83e7f12ae3da09a.png

 d4200f57b8b744478121149460978e49.png587820db562e4348899c5e69ef3e62c0.png

 4a0531c23eb642a482a560eefa5422e9.pngbf558db49b294348ad467ec66d9cf31f.png

84a04be74b2f40c79e6eeb0fccd69c2b.pngfe6c9896e8e54b2d96f62d74d197656e.png

 b90d090e9caa4db9982e15e0454d40d8.pngccd317c0f8104bb590249af4cd1e51dd.png

        从结果可以看出,如果选择的两个优化点不是同一类,则在优化后这两个点都会变成支撑向量,如果两个点是同一类,则其中至少一个(这一个是靠近另一个分类的)会变成支撑向量。

4.3.2 不同的选点方式带来的损失值变化的不同

        我在选择第二个点的时候用了两种方式,第一种就是按照eq?E_%7B1%7D-E_%7B2%7D差足够大来选的,我给这种选点方式取名“list_loss”,第二种是优先选在满足违背KKT条件的然后选eq?E_%7B1%7D-E_%7B2%7D差足够大的,我给这种方式取名"NKKT_loss",两种选点方式下的loss值变化如下图(这是20个样本的列子)。

5737f1448bca4370906882809c825dda.png

         从上图可知list_loss的下降速度显然更快,400多次迭代就可得到解,而NKKT_loss需要700次的迭代才能达到同样的效果,这个内容不重要啊,这是我自己随便尝试的,为了加深理解而已。

4.4 参考资料

文档资料:

Sequential Minimal Optimization : A Fast Algorithm for Training Support Vector Machines-学术范

Fast Training of Support Vector Machines Using Sequential Minimal Optimization - 百度学术

[1]Osuna, E.;Freund, R.;Institute of Electric and Electronic Engineer.An improved training algorithm for support vector machines[A].Neural Networks for Signal Processing VII. Proceedings of the 1997 IEEE Signal Processing Society Workshop[C],1997

李庆扬《数值分析》第五版第6章——解线性方程组的迭代法

支持向量机原理详解(六): 序列最小最优化(SMO)算法(Part I) - 知乎

支持向量机原理详解(七): 序列最小最优化(SMO)算法(Part II) - 知乎

五、线性不可分情形

        作者最近没时间写,空了再说。

六、核函数

        作者最近没时间写,空了再说。

        以上内容花费了我将近一个月时间来理解吸收,作者也是一点点的理解,有不足之处敬请批评指正。

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

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

相关文章

ubuntu双系统安装

1. 下载系统 国内镜像 http://mirrors.ustc.edu.cn/ubuntu-releases/2. U盘启动盘 Rufus 软件 制作U盘启动盘 Rufus 链接 https://rufus.en.softonic.com/3. 磁盘中准备一定未分配磁盘 我准备了100G 4. BIOS启动项选择为usb启动&#xff08;每个品牌进BIOS不同&#xff0…

win下 Nginx.conf 路径配置注意事项(win)

win下 Nginx.conf 路径配置注意事项 文章目录 可使用win绝对路径路径不能包含中文路径不能包含空格路径中的"\n"会被识别成换行贴一段正确配置的Nginx.conf代码 可使用win绝对路径 网上有种说法是win下Nginx不能设置绝对路径&#xff0c;但我在Nginx-1.24.0下是设置…

在Windows11中安装WSL2(Ubuntu20.04)并配置Anaconda环境

在Windows11中安装WSL2(Ubuntu20.04)并配置Anaconda环境 文章目录 在Windows11中安装WSL2(Ubuntu20.04)并配置Anaconda环境说在前面1. 检查开启CPU虚拟化和虚拟机平台2. 安装Ubuntu20.043. Vscode连接WSL2(Ubuntu20.04)4. Anaconda开发环境的搭建5. Vscode 访问 notebook结尾 说…

高效视觉识别的动态感知器

文章目录 Dynamic Perceiver for Efficient Visual Recognition摘要本文方法实验结果 Dynamic Perceiver for Efficient Visual Recognition 摘要 Early exiting已成为提高深度网络推理效率的一种很有前途的方法。通过构建具有多个分类器(出口)的模型&#xff0c;可以在较早的…

佩戴舒适的蓝牙耳机有哪些?公认佩戴舒适性不错的蓝牙耳机推荐

​都2023年了&#xff0c;不会还有人没有一款蓝牙耳机吧&#xff1f;随着蓝牙耳机的增长&#xff0c;越来越多人不知道如何挑选蓝牙耳机了&#xff0c;蓝牙耳机除了音质表现要好之外&#xff0c;还有就是佩戴舒适性不能差&#xff0c;防水性能要有&#xff0c;接下来&#xff0…

WPF 的几种模板概念

WPF中有三大模板ControlTemplate,ItemsPanelTemplate,DataTemplate.其中ControlTemplate和ItemsPanelTemplate是控件模板,DataTemplate是数据模板,他们都派生自FrameworkTemplate抽象类。 看看如下继承图: ControlTemplate <Style TargetType="Button">&…

MiniGPT-4 模型学习与实战

1 前言 MiniGPT-4 是一个冻结的视觉编码器(Q-Former&ViT)与一个冻结的 文本生成大模型&#xff08;Vicuna&#xff0c;江湖人称&#xff1a;小羊驼&#xff09; 进行对齐造出来的。 MiniGPT-4 具有许多类似于 GPT-4 的能力, 图像描述生成、从手写草稿创建网站等MiniGPT-4…

bitbucket 配置 SSH keys

目录 问题 配置方法 生成SSH key 添加SSH key至SSH Agent 添加公钥至Bitbucket 执行Git clone 问题 拉取bitbucket上的代码需要配置SSH key Configure SSH and two-step verification | Bitbucket Cloud | Atlassian Support 以Linux为例&#xff1a; Set up persona…

WebSocket 的介绍及基本使用

websocket 什么是 websocket ? https://websocket.org/ 是一种网络通信协议&#xff0c;和 HTTP 协议 一样。 为什么需要websocket ? 因为 HTTP 协议有一个缺陷&#xff1a;通信只能由客户端发起。 了解 websocket api含义 基于原生的 websocket 完成服务端和客户端的通…

使用指针突破类的private限制

使用指针突破类的private限制 继承的内存模型使用指针再子类中访问父类的私有变量 继承的内存模型 创建派生类对象时只会申请一次内存&#xff0c;派生类对象包含了基类对象的内存空间&#xff0c;this指针相同的。创建派生类对象时&#xff0c;先初始化基类对象&#xff0c;再…

Oracle数据库安全评估工具(DBSAT)

目录&#xff1a; 工具概述&#xff1a;先决条件&#xff1a;一、支持的操作系统及DB版本&#xff1a;1.支持的操作系统2.支持的数据库版本 二、评估工具的前提条件&#xff1a;1.所需安装包及工具2.Collector的先决条件3.Reporter的先决条件4.Discoverer的先决条件 工具下载&a…

23vue3铺垫知识——ES6模块化与异步编程高级用法

文章目录 一、ES6模块化1、回顾:nodejs中如何实现模块化2、前端模块化规范的分类3、什么是ES6模块化规范4、在nodeis中体验ES6模块化5、ES6模块化的基本语法5.1 默认导出与默认导入5.2 按需导出与按需导入5.3直接导入并执行模块中的代码 二、Promise1、回调地狱1.1 如何解决回调…

iptables 限制转发

概述 可以通过设置内核参数来启动或停止内核的转发 sysctl -w net.ipv4.ip_forward1当开启了Linux内核转发 cat /proc/sys/net/ipv4/ip_forward开启内核转发后&#xff0c;当Linux主机收到不属于自己IP的数据包时&#xff0c;将会根据主机上配置的路由表进行转发&#xff0c…

kubernetes的二进制安装

二进制搭建 Kubernetes v1.20 k8s集群master01&#xff1a;192.168.232.37 kube-apiserver kube-controller-manager kube-scheduler etcd k8s集群master02&#xff1a;192.168.232.7 k8s集群node01&#xff1a;192.168.232.47 kubelet kube-proxy docker k8s集群node…

Android jar包的生成与使用

前言 Android中常见的第三方库有&#xff1a; *.so&#xff0c;*.jar&#xff0c;*.aar&#xff0c;今天给大家分享一下jar文件&#xff0c;在Android应用程序开发中&#xff0c;我们需要使用一些Java库&#xff0c;可能这个库是自己封装好的或者第三方的库&#xff0c;我们每…

收入指引令人失望,股票回购不积极,满帮(YMM)面临监管风险

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 收入指引令人失望 上个月末&#xff0c;满帮&#xff08;YMM&#xff09;公布了2023年第一季度的财务业绩&#xff0c;同时还公布了2023年第二季度的管理指引。 满帮预计其2023年第二季度的收入将在19.10亿元至20.10亿元之…

【SwinFusion:通用网络框架 :Swin Transformer】

SwinFusion: Cross-domain Long-range Learning for General Image Fusion via Swin Transformer &#xff08;SwinFusion&#xff1a;基于Swin Transformer的跨域远程学习通用图像融合&#xff09; 提出了一种基于跨域远程学习和Swin Transformer的通用图像融合框架SwinFusi…

粮油质量追溯系统源码,MES生产加工管理系统

粮油生产质量追溯系统&#xff0c;实现一物一码&#xff0c;全程追溯&#xff0c;正向追踪&#xff0c;逆向溯源。 技术架构&#xff1a;spring bootmybatiseasyuimysql 。 粮油生产质量追溯系统实现种植主体、种植基地、生产计划、压榨、精炼、包装、销售、物料管理、检验检测…

AI绘画:Roop插件的使用详解!

roop插件有哪些特性&#xff0c;如果安装&#xff0c;已经在上一篇讲的非常详细了。不知道你们装得怎么样了&#xff1f; 今天&#xff0c;来详细的说一说roop插件的使用。 首先呢启动我们的Stable-Diffusion-WebUI&#xff0c;然后确保插件已经启用&#xff01; 选择好模型&a…

【Spring Boot 初识丨七 丨外部化配置(一)】属性详解

上一篇讲了 Spring Boot 的依赖注入 本篇来讲一讲Spring Boot 外部化配置 Spring Boot 初识&#xff1a; 【Spring Boot 初识丨一】入门实战 【Spring Boot 初识丨二】maven 【Spring Boot 初识丨三】starter 【Spring Boot 初识丨四】主应用类 【Spring Boot 初识丨五】beans …