FPGA视觉从入门到放弃——懒人的支持向量机

支持向量机曾是机器学习领域中的主流方法。针对小样本,现在用起来依然很方便。同时,该方面的工具和教程多得数不清。所以这里引用老师木的话就很合适:“经常,有些事还没做就已经知道它无意义,于是就没做;有些事做不做都知道无意义,还是蠢蠢欲动”。

本篇围绕“用现有的库把自己的代码工作量减到最小”为话题,以比大多教程尽量简单的支持向量机理论和实践为例,讲述软件与硬件(DSP或FPGA等)结合时的偷懒方法

1. 基本原理 5

(1) 超平面

假设数据集中有 l 个样本,每个样本包括属性向量和标签。所以,有样本{(X1,y1)...(Xi,yi),...(Xl,yl)} l 为样本的个数,yi{1,1}为标签,第 i 个样本Xi=[xi1,...,xin] n 为每个样本的属性数目。

超平面的方程为:

H=wTX+b=w0x0+w1x1+...+wnxn+b=0

其中, w n权重,b为偏置。

如果数据可分,则存在很多可分的超平面。贴着正负样本时的边缘超平面为 H=±1 ,中间超平面为 H=0 。最优的超平面会使边缘超平面和中间超平面之间的间隔最大。

(2) 优化

第i个样本的属性向量 Xi 距离超平面 H 的距离为:

d(Xi,H)=wTXi||w||

最大化间隔等价于优化问题:

minw,b12||w||2s.t.yi(wTXi+b)1,i=1,...,l

  • 超平面 H=±1 之间的距离为 2||w|| ,所以最大化间隔等价于最小化 ||w||22
  • yi=1 时, wTXi+b1 xi 位于 H=1 超平面的上侧;
  • yi=1 时, wTXi+b1 xi 位于 H=1 超平面的下侧。
(3) 二次规划函数
X = quadprog(H,f,A,c)

二次规划函数求解关于向量X的二次规划问题:

minX12XTHX+fXs.t.AXc

X仅表示二次规划要求解的项,与SVM中的样本数据没有关系。

(4) 编码优化问题

a. 目标函数

12wTw=12(wb)(I000)(wb)=12(w1w2...wnb)100000100000...000001000000w1w2...wnb

b. 约束条件

y1(wTx1+b)y2(wTx2+b)...yl(wTxl+b)=y10000y20000...0000ylx11x21...xl1............x1nx2n...xln1111w1...wnb1...11

2. 实现

(1) Matlab 2维版

这里把原优化问题作为二次规划问题求解。同理,也可以对它的对偶问题按二次规划问题求解。然而,该问题的规模正比于训练样本数,为避开高维数据计算的巨大开销,通常采用SMO方法[见 周志华, “机器学习”, pp. 124]。线性可分时,二次规划的解与工具箱的解 1相似。

clc;
clear;
close all;

%%

load fisheriris

X = meas(1:100,[2,3]);
group = species(1:100);
[groupIdx, groupStr] = grp2idx(group);

y = (groupIdx==1) * 2 - 1;

[l,n] = size(X);

H = eye(n + 1);
H(n + 1,n + 1) = 0;
f = zeros(n + 1,1);

Z = [X ones(l,1)];
A = -diag(y) * Z;
c = -1 * ones(l,1);

% 二次规划求解
w = quadprog(H,f,A,c);

% 调整横轴范围,便于与工具箱效果比较
X1 = [2:5];
w1 = w(1,1);
w2 = w(2,1);
b = w(3,1);

% 可分超平面:w1x1+w2x2+b=0 -> x2=-(w1*x1+b)/w2
Y1 = -(w1 * X1 + b) / w2;

XPos = X(find(y==1),:);
XNeg = X(find(y==-1),:);

% 超平面上界:w1x1+w2x2+b=1
YUP = (1 - w1 * X1 - b) / w2;
% 超平面上界:w1x1+w2x2+b=-1
YLOW = (-1 - w1 * X1 - b) / w2;

figure(1);
set(gcf,'Color',[1,1,1]);
subplot(1,2,1);
plot(XPos(:,1),XPos(:,2),'r+'); hold on;
plot(XNeg(:,1),XNeg(:,2),'g*'); hold on;
plot(X1,Y1,'k-'); hold on;
plot(X1,YUP,'m:'); hold on;
plot(X1,YLOW,'m:'); 
legend('setosa','versicolor','hyperplane','upper margin','lower margin');

% 调整纵轴范围,便于与工具箱效果比较
ylim([1,5.5]);

title('svm trained with quadratic programming');
xlabel('sepal length');
ylabel('sepal width');
grid on;

subplot(1,2,2);
svmStruct = svmtrain(X,group,'ShowPlot',true);
title('svm trained with matlab toolbox');
xlabel('sepal length');
ylabel('sepal width');
grid on;

这里写图片描述

注: 这里二次规划求解要求训练样本线性可分,否则找不到可行解。

(2) Matlab n维核函数版

工具箱自带预测器用到的参数 2有:

Alpha( α )——拉格朗日乘子
Beta( β )——线性预测器的系数
Bias( b )——偏置
KernelParameters.Scale(s)——缩放因子

如果KernelParameters.Function为”Linear“,则输出为:

f(x)=(xs)β+b

更一般地,带核函数的预测输出可表示为:

f(x)=i=1mαiyiK(x,xi)+b

其中, yi 为第 i 个支持向量xi的标签, m 为训练得到的支持向量的总数,K(x,xi)为测试样本 x xi间的核函数输出。

clc;
clear;
close all;
%%

load fisheriris

X = meas(1:100,:);
group = species(1:100);
[groupIdx, groupStr] = grp2idx(group);

Y = (groupIdx==2) * 2 - 1;

XPos = X(find(Y==1),:);
XNeg = X(find(Y==-1),:);
%%

cv = cvpartition(Y,'k',10);
err = zeros(cv.NumTestSets,1);

for i = 1:cv.NumTestSets

    trainIdx = cv.training(i);
    testIdx = cv.test(i);
    Xtrain = X(trainIdx,:);
    Ytrain = Y(trainIdx);
    Xtest = X(testIdx,:);
    Ytest = Y(testIdx);

    %% SVM 训练
    clf = fitcsvm(Xtrain,Ytrain,'KernelFunction','polynomial','ClassNames',[-1,1]);
    [m,n] = size(clf.SupportVectors);

    %% SVM 验证

    % (0) 线性核 'linear'
    % Ypred = (Xtest / clf.KernelParameters.Scale) * clf.Beta + clf.Bias > 0;

    Ypred = zeros(length(Xtest),1);
    for j=1:m
        % (1) 线性核 'linear'
        % Kernel = Xtest * clf.SupportVectors(j,:)'; 
        % (2) 高斯核 'rbf'
        % Kernel = exp(-sum((Xtest - repmat(clf.SupportVectors(j,:),length(Xtest),1)).^2,2));
        % (3) 多项式核 'polynomial'
        Kernel = (1 + Xtest * clf.SupportVectors(j,:)').^clf.ModelParameters.KernelPolynomialOrder;

        Ypred = Ypred + clf.Alpha(j) * clf.SupportVectorLabels(j) * Kernel;
    end
    Ypred = (Ypred + clf.Bias > 0) * 2 - 1;    

    err(i) = sum(~strcmp(Ypred,Ytest));
end
cvError = sum(err)/sum(cv.TestSize)
%%

figure(1);
set(gcf,'Color',[1,1,1]);
%subplot(1,1,1);
plot(XPos(:,1),XPos(:,2),'ro'); hold on;
plot(XNeg(:,1),XNeg(:,2),'go'); hold on;
plot(Xtest(:,1),Xtest(:,2),'bo'); hold on;
plot(clf.SupportVectors(:,1),clf.SupportVectors(:,2),'k^'); hold on;

[l,n] = size(Xtest);

for i=1:l
    if Ypred(i)==1
        plot(Xtest(i,1),Xtest(i,2),'r*'); hold on;
    else
        plot(Xtest(i,1),Xtest(i,2),'g*'); hold on;        
    end
end

title('prediction with svm classifier');
xlabel('sepal length');
ylabel('sepal width');
grid on;

10折交叉验证 3后最后1折多项式核 4的预测结果如下图。其中三角形为支持向量,蓝色圆圈为验证样本,星型颜色和周围样本的颜色一致则分类正确。


(3) 转换

Matlab离线训练后得到分类器clf。线性核与高斯核预测时,保存支持向量即可;多项式核预测时,另外保存多项式的阶数。根据需要对预测部分转换成项目约束的语言即可。


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SmartFusion是一款集成了FPGA和ARM处理器的可编程逻辑器件。在使用SmartFusion进行FPGA到ARM的衔接过程中,首先我们可以通过MSS(Microcontroller Subsystem)模块的GPIO(General Purpose Input/Output)功能来实现点灯。 MSS是SmartFusion芯片中的一个微控制器子系统,它包含了ARM Cortex-M3处理器以及与之相关的外设。GPIO是MSS提供的一种功能,它允许我们通过配置相关引脚的输入输出状态来进行数字信号的输入输出。 在使用MSS_GPIO点灯的过程中,首先我们需要使用SmartFusion的设计工具进行硬件电路的设计。接着,我们需要在软件开发环境中编写ARM处理器的代码来控制MSS_GPIO。 在代码中,我们需要进行以下步骤来实现点灯功能: 1. 配置MSS_GPIO控制的引脚作为输出引脚。我们可以通过设置相应的寄存器来实现这一步骤。例如,我们可以将寄存器的特定位设置为1来将某个引脚设置为输出模式。 2. 设置输出引脚的电平状态。通过编写相应的代码,我们可以将输出引脚的电平配置为高电平或低电平。这将决定LED是否点亮。 3. 可以加入延时函数来控制点亮和熄灭的时间间隔,以及闪烁的频率。 以上就是使用SmartFusion的MSS_GPIO模块实现点灯的简要过程。通过编写ARM处理器的代码,配置相关的寄存器,我们可以通过控制MSS_GPIO模块的引脚状态来实现LED的点亮和熄灭。这个简单的示例展示了SmartFusion芯片中FPGA和ARM之间的协同工作能力,为我们实现更复杂的功能提供了基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值