机器学习之旅---SVM分类器

article/2025/10/6 11:50:23

本次内容主要讲解什么是支持向量,SVM分类是如何推导的,最小序列SMO算法部分推导。

最后给出线性和非线性2分类问题的smo算法matlab实现代码。


一、什么是支持向量机(Support Vector Machine)

本节内容部分翻译Opencv教程:

http://docs.opencv.org/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.html#introductiontosvms

 

SVM是一个由分类超平面定义的判别分类器。也就是说给定一组带标签的训练样本,算法将会输出一个最优超平面对新样本(测试样本)进行分类。

什么样的超平面才是最优的?我们考虑如下场景:对于一个由二维坐标点构成的线性可分集合,如何找到一条直线将两类坐标分隔开?


      上图中,你可以看到存在多条直线将两类坐标分开。它们中有没有最好的?我们可以直观地定义如下规则:如果一条分割的直线离坐标点太近,那它就不是最佳的。因为它会对噪声敏感,不能正确的推广。因此,我们的目标是找到一条分割线,它要离所有的样本点都尽可能的远。

       SVM算法就是找一个超平面,并且它到离他最近的训练样本的距离要最大。即最优分割超平面最大化训练样本边界。


原谅哥的翻译水平,看着自己也别扭,重新整理下:

对线性可分集,总能找到使样本正确划分的分界面,而且有无穷多个,哪个是最优? 必须寻找一种最优的分界准则,是两类模式分开的间隔最大。


在介绍如何推到之前,了解一个定义:

分隔超平面:上述将数据集分割开来的直线叫做分隔超平面。

超平面:如果数据集是N维的,那么就需要N-1维的某对象来对数据进行分割。该对象叫做超平面,也就是分类的决策边界。

间隔

一个点到分割面的距离,称为点相对于分割面的距离。

数据集中所有的点到分割面的最小间隔的2倍,称为分类器或数据集的间隔。

最大间隔:SVM分类器是要找最大的数据集间隔。

支持向量:离分割超平面最近的那些点。


SVM算法其实就是最大化支持向量到分割面的距离。另外,目前上面讲的都是针对线性可分的数据集。非线性的数据集,需要核函数转换空间,才具有非线性数据处理能力。

最优分类超平面只由少数支持向量决定,问题具有稀疏性。

 

二、推导

下面讲解下SVM的数学原理,其实就是复述我之前写过的东西。

http://blog.csdn.net/jinshengtao/article/details/17636953





(这里yi(wTx+b)称为点到分割面的函数间隔。yi(wTx+b)/|w|称为点到分割面的几何间隔)


            现在的目标就是找出分类器定义中的w和b。为此,我们必须找到具有最小间隔的数据点,而这些数据点也就是前面提到的支持向量。一旦找到具有最小间隔的数据点,我们就需要对该间隔最大化。这就可以写作:


          直接求解上面的公式很难。并且到目前为止,我们知道所有数都不那么干净,不能100%线性可分。我们可以通过引入松弛变量,来允许有些数据点可以处于分割面的错误的一侧。如下面几幅图所示:



 εi是松弛变量,常数C代表惩罚系数,即如果某个x是属于某一类,但是它偏离了该类,跑到边界上后者其他类的地方去了,C越大表明越不想放弃这个点,边界就会缩小,错分点更少,但是过拟合情况会比较严重。


为此,我们引入拉格朗日乘子,用条件极值求解最优分界面,构造拉格朗日函数,也是之前公式(3)的对偶形式:



也就是说,只要求的拉格朗日乘子ai,我们就能得到分类边界。


三、序列最小化方法SMO

    C-SVM是一个凸二次规划问题,SMO算法能快速解决SVM的二次规划问题,把它分解成一些子问题来解决。在每一步中,SMO算法仅选择两个拉格朗日乘子进行优化,然后再更新SVM以反应新的优化值。

   对于C-SVM目标函数和优化过程中必须遵循的约束条件如下:



     我们需要一种算法来求解最优化问题。(在以前的实现,我用了matlab提供的求条件极值的函数,http://blog.csdn.net/jinshengtao/article/details/17675653)。

现在打算自己用smo算法实现,下面就重点讲下smo算法。

       C-SVM的KTT条件为:

(KTT条件是指在满足一些有规则的条件下, 一个非线性规划(Nonlinear Programming)问题能有最优化解法的一个必要和充分条件.即最优解都需要满足KTT条件)。现在这里对于C-SVM的KTT条件为:


其中,b*由上面的公式计算得到。

SMO算法包括两个步骤:一是用分析的方法解一个简单的优化问题;二是选择待优化的拉格朗日乘子的策略。

(1)   简单的优化问题----两个拉格朗日乘子优化问题的解

    为了求解只有两个乘子的优化问题【因为(x i,y i)都已知】,SMO方法首先计算它的约束,然后再解带有约束的最小化问题。对于两个乘子,其二维约束很容易表达:边界约束使得乘子在方框内,而线性等式约束使得乘子在对角线上,这里y i∈{1,-1},



    现在,在一条线段上求目标函数的极值,相当于一个一维的极值问题。我们可以把a1用a2表示,对a2求无条件极值,如果目标函数是严格凹的,最小值就一定在这一极值点(极值点在区间内)或在区间端点(极值点在区间外)。a2确定下来后,a1也确定了。因此,我们要先找到a2的优化区间,再在这个区间中对a2求最小值。

根据上面两幅图可以知道,a2优化区间:

当y1和y2异号时:LH的计算是由a2-a1正负未知所导致的】


当y1和y2同号时:





(b)当L的二阶导数为0,即训练样本中出现相同的特征时,我们计算目标函数是单调的。最小值在线段两个端点上的取值,我们将a2=L和a2=H分别代入目标函数,这样拉格朗日乘子就修正到目标函数较小的端点上,比较ΨL和ΨH就可以求得Ψ的最小值。最终得到a2的值,接着一串值都解出来了。


至于偏置值b,每一步都要更新,因为前面的KKT条件指出了ai和yiui关系,而ui和b有关,在每一步计算出ai后,根据KKT条件来调整b,分如下几种情况


(2)   选择策略----选取两个拉格朗日乘子的启发规则

事实上即使我们不采用任何找点法,只是按顺序抽取ai,aj的所有组合进行优化,目标函数也会不断下降。直到任一对ai,aj都不能继续优化,目标函数就会收敛到极小值。我们采取某种找点方法只是为了使算法收敛得更快。

这种试探法先选择最有可能需要优化的a2,再针对这样的a2选择最有可能取得较大修正步长的a1。这样,我们在程序中使用两个层次的循环:

外层循环首先遍历所有样本查找违反KTT规则的乘子进行优化,当完成一次遍历后外层循环再遍历那些非边界乘子的样本(0<a<C),挑选那些违反KTT条件的样本进行优化。外层循环重复执行,直到所有的非边界样本在一定范围内均满足KKT条件。

    在选定第一个拉格朗日乘子ai后,内层循环会通过最大化步长的方式来挑选第二个拉格朗日乘子,即最大化|Ei-Ej|,当Ei为正时最小化Ej,当为负Ei时最大化Ej.

下面给出matlab代码实现 :

1.线性可分简单smo

function [b,alphas] = smoSimple(data, class, C, toler, maxIter)
b = 0;
[m,n] = size(data);
alphas = zeros(m,1);
iter=0;
while (iter < maxIter)alphasChanges = 0;for k=1:1:mfxk = (alphas .* class)' * data * data(k,:)' + b;   % f = wx+bek = fxk - class(k);if (((ek*class(k) < -toler) && (alphas(k) < C)) || ((ek*class(k) > toler) && (alphas(k) > 0)))j = selectJrand(k,m);fxj = (alphas .* class)' * data * data(j,:)' + b;   % f = wx+bej = fxj - class(j);temp_k = alphas(k);temp_j = alphas(j);if(class(k) ~= class(j))L = max(0, alphas(j) - alphas(k));H = min(C, C + alphas(j) - alphas(k));elseL = max(0, alphas(k) + alphas(j) - C);H = min(C, alphas(k) + alphas(j));endif L == Hcontinue;endeta = 2.0 * data(k,:) * data(j,:)' - data(k,:) * data(k,:)' - data(j,:) * data(j,:)';if eta >= 0continue;endalphas(j) = alphas(j) - class(j) * (ek - ej) / eta;alphas(j) = clipalpha(alphas(j), H, L);if(abs(alphas(j) - temp_j) < 0.00001)continue;endalphas(k) = alphas(k) + class(k) * class(j) * (temp_j - alphas(j));b1 = b - ek - class(k) * (alphas(k) - temp_k) * data(k,:) * data(k,:)' - class(j) * (alphas(j) - temp_j) * data(k,:) * data(j,:)';b2 = b - ej - class(k) * (alphas(k) - temp_k) * data(k,:) * data(j,:)' - class(j) * (alphas(j) - temp_j) * data(j,:) * data(j,:)'; if (alphas(k) > 0 && alphas(k) < C)b = b1;elseif(alphas(j) > 0 && alphas(j) < C)b = b2;elseb = (b1 + b2)/2;endalphasChanges = alphasChanges + 1;end endif alphasChanges == 0iter = iter + 1;elseiter = 0;end
end
endfunction index = selectJrand(k,m)index = k;while(index == k)index = randi([1,m],1,1);  end
endfunction res = clipalpha(a, H, L)if a > Ha = H;endif a < La = L;endres = a;
end

clc;
clear;load Data[r,c] = size(Data);
Test = Data(:,1:2);
Label = Data(:,3);[b, alphas] = smoSimple(Test, Label, 0.6, 0.001, 40);%%画图
figure(1)
axis([-2 12 -8 6])
for k = 1:1:rhold onif Data(k,3) == 1plot(Data(k,1),Data(k,2),'r+');elseplot(Data(k,1),Data(k,2),'b*');end
end%画支持向量及分割面
%result=[];
for k=1:1:rif alphas(k)~= 0hold on%result =[result;alphas(k)];QX = plot(Data(k,1:1),Data(k,2:2),'Ok','MarkerSize',12);set(QX,'LineWidth',2.0);end
end
W=(alphas.*Label)'*Data(:,1:2);
y=(-W(1).* Data(:,1:1)-b) ./W(2);
plot(Data(:,1:1),y);

结果:


上述代码运行事件较长,此处仅是100个点的小规模数据集,对于更大的数据集收敛时间更长。


2.完整的smo算法

function [b, res_alphas] = smoP(data, class, C, toler, maxIter)[m,n] = size(data);iter = 0;entireSet = 1;alphaPairsChanged = 0;oS = init(data,class,C,toler,m);while(((iter<maxIter)&&(alphaPairsChanged > 0)) || (entireSet == 1))alphaPairsChanged = 0;if entireSet == 1for k = 1:1:m[ret, oS] = innerL(k, oS);alphaPairsChanged = alphaPairsChanged + ret;enditer = iter + 1;elsenonBoundIs = [];for k = 1:1:mif ((oS.alphas(k) < C) && (oS.alphas(k) > 0))nonBoundIs = [nonBoundIs k];endend[r,c] = size(nonBoundIs);for k = 1:1:cindex = nonBoundIs(k);[ret, oS] = innerL(index, oS);alphaPairsChanged = alphaPairsChanged + ret;enditer = iter + 1;endif entireSet == 1entireSet = 0;elseif alphaPairsChanged == 0entireSet = 1;endendb = oS.b;res_alphas = oS.alphas;
endfunction oS = init(data,class,C,toler,m)alphas = zeros(m,1);eCache = zeros(m,2);b = 0;oS.data = data;oS.class = class;oS.C = C;oS.toler = toler;oS.m = m;oS.alphas = alphas;oS.b = b;oS.eCache = eCache;endfunction [ret,oS] = innerL(k, oS)Ei = calcEk(oS, k);if(((oS.class(k)*Ei < -oS.toler) && (oS.alphas(k) < oS.C)) || ((oS.class(k)*Ei > oS.toler) && (oS.alphas(k) > 0)))[j, Ej] = selectJ(k, oS, Ei);temp_k = oS.alphas(k);temp_j = oS.alphas(j);if oS.class(k) ~= oS.class(j)L = max(0, oS.alphas(j) - oS.alphas(k));H = min(oS.C, oS.C +oS.alphas(j) - oS.alphas(k));elseL = max(0, oS.alphas(j) + oS.alphas(k) - oS.C);H = min(oS.C, oS.alphas(j) + oS.alphas(k));endif L == Hret = 0;return;endeta = 2.0 * oS.data(k,:) * oS.data(j,:)' - oS.data(k,:) * oS.data(k,:)' - oS.data(j,:) * oS.data(j,:)';if eta >=0 ret = 0;return;endoS.alphas(j) = oS.alphas(j) - oS.class(j) * (Ei - Ej) / eta;oS.alphas(j) = clipalpha(oS.alphas(j), H, L);%update EkEt = calcEk(oS, j);oS.eCache(j,:) = [1 Et];if(abs(oS.alphas(j) - temp_j) < 0.00001)ret = 0;return;endoS.alphas(k) =   oS.alphas(k) + oS.class(j)*oS.class(k)*(temp_j - oS.alphas(j));Et = calcEk(oS, k);oS.eCache(k,:) = [1 Et];b1 = oS.b - Ei - oS.class(k) * (oS.alphas(k) - temp_k) * oS.data(k,:) * oS.data(k,:)' - oS.class(j) * (oS.alphas(j) - temp_j) * oS.data(k,:) * oS.data(j,:)';b2 = oS.b - Ej - oS.class(k) * (oS.alphas(k) - temp_k) * oS.data(k,:) * oS.data(j,:)' - oS.class(j) * (oS.alphas(j) - temp_j) * oS.data(j,:) * oS.data(j,:)'; if (oS.alphas(k)>0) && (oS.alphas(k)<oS.C)oS.b = b1;elseif(oS.alphas(j)>0) && (oS.alphas(j)<oS.C)oS.b = b2;elseoS.b = (b1+b2)/2.0;endret = 1;return;elseret = 0;return;end
endfunction Ek = calcEk(oS, k)fXk = (oS.alphas .* oS.class)' * oS.data * oS.data(k,:)' + oS.b;Ek = fXk - oS.class(k);
endfunction [j, Ej] = selectJ(k, oS, Ei)maxK = -1;maxDeltaE = 0; Ej = 0;oS.eCache(k,:) =[1 Ei];validEcacheList = [];for l = 1:1:oS.mif oS.eCache(l,1:1) ~= 0validEcacheList = [validEcacheList l];endend[r, c] = size(validEcacheList);if c > 1for l=1:1:cindex = validEcacheList(l)if index == kcontinue;endEk = calcEk(oS,index);deltaE = abs(Ei - Ek);if(deltaE > maxDeltaE)maxK = index;maxDeltaE = deltaE;Ej = Ek;endendj = maxK;elsej = selectJrand(k, oS.m);Ej = calcEk(oS, j);end
endfunction index = selectJrand(k,m)index = k;while(index == k)index = randi([1,m],1,1);  end
endfunction res = clipalpha(a, H, L)if a > Ha = H;endif a < La = L;endres = a;
end

clc;
clear;load Data[r,c] = size(Data);
Test = Data(:,1:2);
Label = Data(:,3);[b, alphas] = smoP(Test, Label, 0.6, 0.001, 40);%%画图
figure(1)
axis([-2 12 -8 6])
for k = 1:1:rhold onif Data(k,3) == 1plot(Data(k,1),Data(k,2),'r+');elseplot(Data(k,1),Data(k,2),'b*');end
end%画支持向量及分割面
%result=[];
for k=1:1:rif alphas(k)~= 0hold on%result =[result;alphas(k)];QX = plot(Data(k,1:1),Data(k,2:2),'Ok','MarkerSize',12);set(QX,'LineWidth',2.0);end
end
W=(alphas.*Label)'*Data(:,1:2);
y=(-W(1).* Data(:,1:1)-b) ./W(2);
plot(Data(:,1:1),y);

运行结果:


与第一个代码唯一的不同就是选择alphas的方式。第一个代码覆盖了所有数据集。常数C=0.6,一方面要保证所有样例的间隔不小于1.0,另一方面又要使得分类间隔尽可能大,并且要在 这两方面平衡。如果C很大,那么分类器将力图通过分割超平面对所有的样例都正确分类。小圆点标注的是支持向量。如果数据集非线性可分,支持向量 会在超平面附近聚集成团


四、非线性可分问题


对于上图,在二维平面中很难用直线分割,但是这里明显存在着两类数据。接下来,我们就使用一种称为核函数的工具将数据转化成易于分类器理解的形式。

1.      利用核函数将数据映射到高维空间

对于上图而言,如果只在x和y构成的坐标系中插入直线进行分类的话,我们不会得到理想的结果。我们可以对数据进行转换从而得到某些新的变量来表示数据。在这种情况下,我们就更容易得到大于零或小于零的测试结果。数学家们将数据从一个特征空间转换到另一特征空间的过程称为特征空间映射,通常我们将低维特征空间映射到高维特征空间。下面举个例子来形象地理解核函数:


我们把横轴上端点a和b之间红色部分里的所有点定为正类,两边的黑色部分里的点定为负类。试问能找到一个线性函数把两类正确分开么?不能,因为二维空间里的线性函数就是指直线,显然找不到符合条件的直线。但我们可以找到一条曲线,例如下面这一条


    显然通过点在这条曲线的上方还是下方就可以判断点所属的类别(你在横轴上随便找一点,算算这一点的函数值,会发现负类的点函数值一定比0大,而正类的一定比0小)。这条曲线就是我们熟知的二次曲线。

上述过程即完成了一维空间向二维空间的映射。

对于SVM分类问题,所有的运算都可以写成内积形式(点积),我们把内积运算替换成核函数,即可完成特征映射。核函数主要有:

l  多项式核

l  傅立叶核

l  B样条核

l  Sigmod核

l  高斯径向基核

核函数并不仅仅应用于支持向量机,很多其他机器学习算法也要用到。下面就介绍高斯径向基核函数。

径向基函数是一种采用向量作为自变量的函数,能够基于向量距离输出一个标量,具体数学公式:



     其中,σ是用户定义的用于确定到达率或者说是函数值跌落到0的速度参数。这个高斯核函数将数据从其特征空间映射到更高维的空间,具体说来这里是映射到一个无穷维的空间。我们不用确切地理解数据是如何表现的。

【这里扯一下我的同学,他的论文《基于矩阵运算的单隐层Madaline网络批量学习》,人家提出数据往低维空间映射,比较神奇哈】

最终的分类平面:(推导参考:http://blog.csdn.net/wangran51/article/details/7354915http://blog.csdn.net/wangran51/article/details/7354915)


代码:

function [b, res_alphas] = rbf_smoP(data, class, C, toler, maxIter, k1)[m,n] = size(data);iter = 0;entireSet = 1;alphaPairsChanged = 0;oS = init(data, class, C, toler, m, k1);while(((iter<maxIter)&&(alphaPairsChanged > 0)) || (entireSet == 1))alphaPairsChanged = 0;if entireSet == 1for k = 1:1:m[ret, oS] = innerL(k, oS);alphaPairsChanged = alphaPairsChanged + ret;enditer = iter + 1;elsenonBoundIs = [];for k = 1:1:mif ((oS.alphas(k) < C) && (oS.alphas(k) > 0))nonBoundIs = [nonBoundIs k];endend[r,c] = size(nonBoundIs);for k = 1:1:cindex = nonBoundIs(k);[ret, oS] = innerL(index, oS);alphaPairsChanged = alphaPairsChanged + ret;enditer = iter + 1;endif entireSet == 1entireSet = 0;elseif alphaPairsChanged == 0entireSet = 1;endendb = oS.b;res_alphas = oS.alphas;
endfunction K = kernelTrans(X, A, k1)[m, n] = size(X);K = zeros(m,1);for j = 1:1:mdeltaRow = X(j,:) - A;K(j) = deltaRow * deltaRow';endK = exp(K./(-2*k1));
endfunction oS = init(data,class,C,toler,m,k1)alphas = zeros(m,1);eCache = zeros(m,2);b = 0;oS.data = data;oS.class = class;oS.C = C;oS.toler = toler;oS.m = m;oS.alphas = alphas;oS.b = b;oS.eCache = eCache;oS.K = zeros(m,m);for j = 1:1:moS.K(:,j) = kernelTrans(oS.data,oS.data(j,:),k1);end
endfunction [ret,oS] = innerL(k, oS)Ei = calcEk(oS, k);if(((oS.class(k)*Ei < -oS.toler) && (oS.alphas(k) < oS.C)) || ((oS.class(k)*Ei > oS.toler) && (oS.alphas(k) > 0)))[j, Ej] = selectJ(k, oS, Ei);temp_k = oS.alphas(k);temp_j = oS.alphas(j);if oS.class(k) ~= oS.class(j)L = max(0, oS.alphas(j) - oS.alphas(k));H = min(oS.C, oS.C +oS.alphas(j) - oS.alphas(k));elseL = max(0, oS.alphas(j) + oS.alphas(k) - oS.C);H = min(oS.C, oS.alphas(j) + oS.alphas(k));endif L == Hret = 0;return;endeta = 2.0 * oS.K(k,j) - oS.K(k,k) - oS.K(j,j);if eta >=0 ret = 0;return;endoS.alphas(j) = oS.alphas(j) - oS.class(j) * (Ei - Ej) / eta;oS.alphas(j) = clipalpha(oS.alphas(j), H, L);%update EkEt = calcEk(oS, j);oS.eCache(j,:) = [1 Et];if(abs(oS.alphas(j) - temp_j) < 0.00001)ret = 0;return;endoS.alphas(k) =   oS.alphas(k) + oS.class(j)*oS.class(k)*(temp_j - oS.alphas(j));Et = calcEk(oS, k);oS.eCache(k,:) = [1 Et];b1 = oS.b - Ei - oS.class(k) * (oS.alphas(k) - temp_k) * oS.K(k,k) - oS.class(j) * (oS.alphas(j) - temp_j) * oS.K(k,j);b2 = oS.b - Ej - oS.class(k) * (oS.alphas(k) - temp_k) * oS.K(k,j) - oS.class(j) * (oS.alphas(j) - temp_j) * oS.K(j,j); if (oS.alphas(k)>0) && (oS.alphas(k)<oS.C)oS.b = b1;elseif(oS.alphas(j)>0) && (oS.alphas(j)<oS.C)oS.b = b2;elseoS.b = (b1+b2)/2.0;endret = 1;return;elseret = 0;return;end
endfunction Ek = calcEk(oS, k)fXk = (oS.alphas .* oS.class)' * oS.K(:,k) + oS.b;Ek = fXk - oS.class(k);
endfunction [j, Ej] = selectJ(k, oS, Ei)maxK = -1;maxDeltaE = 0; Ej = 0;oS.eCache(k,:) =[1 Ei];validEcacheList = [];for l = 1:1:oS.mif oS.eCache(l,1:1) ~= 0validEcacheList = [validEcacheList l];endend[r, c] = size(validEcacheList);if c > 1for l=1:1:cindex = validEcacheList(l);if index == kcontinue;endEk = calcEk(oS,index);deltaE = abs(Ei - Ek);if(deltaE > maxDeltaE)maxK = index;maxDeltaE = deltaE;Ej = Ek;endendj = maxK;elsej = selectJrand(k, oS.m);Ej = calcEk(oS, j);end
endfunction index = selectJrand(k,m)index = k;while(index == k)index = randi([1,m],1,1);  end
endfunction res = clipalpha(a, H, L)if a > Ha = H;endif a < La = L;endres = a;
end

clc;
clear;load NData
load NTestData = ndata;
Data_Test = ntest;
[r,c] = size(Data);
Test = Data(:,1:2);
Label = Data(:,3);[b, alphas] = rbf_smoP(Test, Label, 200, 0.0001, 1000,1.3);%%画图
figure(1)
axis([-1.5 1.5 -1.5 1.5])
for k = 1:1:rhold onif Data(k,3) == 1plot(Data(k,1),Data(k,2),'r+');elseplot(Data(k,1),Data(k,2),'b*');end
end
%%画支持向量
support_vector = [];
lable_sv = [];
alphas_sv = [];
for k=1:1:rif alphas(k)~= 0hold onsupport_vector = [support_vector; Test(k,1:2)];lable_sv = [lable_sv Label(k)];alphas_sv = [alphas_sv alphas(k)];%result =[result;alphas(k)];QX = plot(Data(k,1:1),Data(k,2:2),'Ok','MarkerSize',12);set(QX,'LineWidth',2.0);end
end
%%预测
temp = lable_sv .* alphas_sv;
[m, n] = size(Data_Test);
errorCount = 0;
for k = 1:1:mvalue = kernelTrans(support_vector, Data_Test(k,1:2),1.3);predict = temp * value + b;if predict > 0predict = 1;elsepredict = -1;endif predict ~= Data_Test(k,3:3)errorCount = errorCount + 1;end
end
errorCount

运行结果:


支持向量围绕超平面成团了。。。


预测结果,错分类2,效果不错。

代码地址:

http://download.csdn.net/detail/jinshengtao/8134089


唉,这篇博文写了将近一个月,断断续续的,自己写到最后都不知道写的什么了,尤其smo推导那块,乱七八糟,大家可以参考网上其他的优秀文章。

华为比较辛苦,搞适配单板,bcm sdk啥的一点意思都没有,明年打算辞职咯










http://chatgpt.dhexx.cn/article/A2nQPegk.shtml

相关文章

人工智能学习笔记 实验五 python 实现 SVM 分类器的设计与应用

学习来源 【机器学习】基于SVM人脸识别算法的一些对比探究&#xff08;先降维好还是先标准化好等对比分析&#xff09;_○( &#xff3e;皿&#xff3e;)っHiahiahia…的博客-CSDN博客 实验原理 有关svm原理 请移步该篇通俗易懂的博客 机器学习算法&#xff08;一&#xff0…

Matlab-SVM分类器

支持向量机&#xff08;Support Vector Machine&#xff0c;SVM)&#xff0c;可以完成对数据的分类&#xff0c;包括线性可分情况和线性不可分情况。 1、线性可分 首先&#xff0c;对于SVM来说&#xff0c;它用于二分类问题&#xff0c;也就是通过寻找一个分类线(二维是直线&…

UGUI——RectTransform详解

什么是RectTransform 创建一个UGUI控件时&#xff0c;查看其Inspector面板&#xff0c;原先熟悉的Transform已经被替换成RectTransform&#xff0c;面板也与原先的Transform的面板相去甚远。 先看看Unity官方对RectTransform的描述&#xff1a; Position, size, anchor and pi…

【Unity3D】UGUI之Button

1 Button属性面板 在 Hierarchy 窗口右键&#xff0c;选择 UI 列表里的 Button 控件&#xff0c;即可创建 Button 控件&#xff0c;选中创建的 Button 控件&#xff0c;按键盘【T】键&#xff0c;可以调整 Button 控件的大小和位置。创建 Button 控件时&#xff0c;系统会自动给…

UGUI基础

UGUI基础 ##1、UGUI概述 1.1、Unity界面发展史 【老版本界面onGUI】>【GUI插件NGUI】>【新版本界面UGUI】 1.2、UGUI特点 新的UI系统是从Unity4.6开始被集成到Unity编译器中的。Unity官方给这个新的UI系统赋予的标签是&#xff1a;灵活&#xff0c;快速和可视化。 对…

【Unity基础】ugui的案例篇(个人学习)

文章目录 前言案例1、点击游戏物体改变一次颜色&#xff0c;被UI遮挡的情况下点击无效1.动态图演示2.实现方式I.实现方案1 通过射线检测实现 3.源码演示Lua部分代码CSharp部分代码 案例2、圆形图片的制作1.图演示2.实现方式I.实现方案1 使用Mask组件实现II.实现方案2 通过重写G…

Unity UGUI源码解析

前言 这篇文章想写的目的也是因为我面试遇到了面试官问我关于UGUI原理性的问题&#xff0c;虽然我看过&#xff0c;但是并没有整理出完整的知识框架&#xff0c;导致描述的时候可能自己都是不清不楚的。自己说不清楚的东西&#xff0c;别人就等于你不会。每当学完一个东西的时…

UGUI基础学习

目录 TEXT IMAGE ROWIMAGE TEXT fontsize:字体 color&#xff1a;字体颜色 ;inespacing:字行间隔 代码展示&#xff1a; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI;public class TEXTtest : MonoBehaviour {p…

UGUI源码解析——总览

一&#xff1a;图像相关 ——UIBehaviour&#xff1a;UI组件的基类&#xff0c;继承MonoBehaviourUGUI源码解析——UIBehaviour——CanvasUpdateRegistry&#xff1a;图像、布局重建注册器UGUI源码解析——CanvasUpdateRegistry——ICanvasElement&#xff1a;图像、布局重建接…

UGUI 全方位了解

随着 unity3d 4.6 ~ 5.x 新 UI 系统终于与大家见面了。这篇文章将不会介绍如何使用按钮、滚动条之类的UI控件&#xff0c;这些内容可以参考 Unity Manual&#xff1b;这篇文章的重点是&#xff0c;如何理解 UI 系统的设计&#xff0c;以便更好的在实际中使用它。 RectTransfor…

UI框架(UGUI)

整个游戏的工程源码下载链接&#xff1a;点击打开链接 可以参考的写的Demo和本文章来学习 毕竟有些细节问题在文章中不能一一说到 工具&#xff1a;VS2010、Unity5.2.3f 先介绍整个Demo的主面板 其中任务、技能、符文等等都是按钮&#xff0c;点击按钮会生成相应面板 【Pro…

UGUI相关使用

UGUI 文章目录 UGUI1.六大基础组件概述1.1 Canvas组件1.2 CanvasScaler组件1.3 Graphic Raycaster组件1.4 Event System组件1.5 Standalone Input Module组件1.6 RectTransform组件 2.三大基础控件概述2.1 图像控件Image2.2 文本控件Text2.3 RawImage原始图像组件 3.七大组合控…

Unity UGUI系统

UI系统对比 对 UI 系统的选择取决于是为 Unity 编辑器开发 UI&#xff0c;还是为游戏或应用程序开发运行时 UI。 UI 的类型UI 工具包Unity UI(uGUI)IMGUI注意事项运行时&#xff08;调试&#xff09;✔ *✔✔这指用于调试用途的临时运行时 UI。运行时&#xff08;游戏内&…

UGUI 详解

1.RectTransform RectTransform组件 继承自Transform组件&#xff0c;是2D界面中元素的Transform。 对比Transform增加了新的属性分别是&#xff1a;Anchor&#xff08;锚点&#xff09;和 Pivot&#xff08;轴心点&#xff09;。 属性&#xff1a; localPosition&#xff1a;图…

UGUI学习笔记(八)UGUI不规则响应区域

一、Unity自带的点击策略 在上一篇文章中我们了解到&#xff0c;UI的默认响应区域是UI元素所在的矩形框线内的区域。这也就意味着&#xff0c;当UI的图形为不规则形状时&#xff0c;点击图形的外部也可能会触发事件。 但其实Unity自带了一种不规则区域点击策略。要想使用它&…

[Unity UGUI图集系统]浅谈UGUI图集使用

**写在前面&#xff0c;下面是自己做Demo的时候一些记录吧&#xff0c;参考了很多网上分享的资源 一、打图集 1.准备好素材&#xff08;建议最好是根据图集名称按文件夹分开&#xff09; 2、创建一个SpriteAtlas 3、将素材添加到图集中 4、生成图集 到此&#xff0c;我们的图…

Ngui和Ugui的区别

NGUI的元素更新&#xff1a; UIPanel.LateUpdate采用轮询的方式&#xff0c;每帧都会执行&#xff0c;并且每帧都会有UIPanel.UpdateWidgets这个函数的调用&#xff0c;做的事情就是对这些UI元素的位置、缩放等信息的获取&#xff0c;也就是即使没有变化的UI元素&#xff0c;也…

Unity—UGUI

每日一句&#xff1a;读数、学习 去更远的地方&#xff0c;才能摆脱那些你不屑一顾的圈子 目录 InputFiled输入框 例&#xff1a;用户名和密码 Toggle组件 案例&#xff1a;冷却效果 InputFiled输入框 Text Component 输入文本组件 Text输入内容 Character Limit 输入字符…

【Unity3D】UGUI概述

1 UGUI 与 GUI 区别 GUI控件 在编译时不能可视化&#xff0c;并且界面不太美观&#xff0c;在实际应用中使用的较少。UGUI 在编译时可视化&#xff0c;界面美观&#xff0c;实际应用较广泛。 2 Canvas 渲染模式&#xff08;Render Mode&#xff09; Screen Space - Overlay&a…

怎样使用UGUI

什么是 UGUI UGUI 是 Unity 自带的一套 GUI 系统&#xff0c;含有基本的一些 UI 控件。 UGUI 控件有哪些&#xff1f; 我们常用的有 Canvas&#xff0c;Text&#xff0c;Image&#xff0c;Button&#xff0c;Toggle&#xff0c;Slider&#xff0c;Scroll Bar&#xff0c;Scroll…