CMSIS-DSP: Added an SVM example to show how to use it.
parent
665ba5d4cb
commit
585137ad16
@ -0,0 +1,45 @@
|
||||
cmake_minimum_required (VERSION 3.6)
|
||||
project (arm_svm_example VERSION 0.1)
|
||||
|
||||
|
||||
# Needed to include the configBoot module
|
||||
# Define the path to CMSIS-DSP (ROOT is defined on command line when using cmake)
|
||||
set(ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../../..)
|
||||
set(DSP ${ROOT}/CMSIS/DSP)
|
||||
|
||||
# Add DSP folder to module path
|
||||
list(APPEND CMAKE_MODULE_PATH ${DSP})
|
||||
|
||||
###################################
|
||||
#
|
||||
# LIBRARIES
|
||||
#
|
||||
###################################
|
||||
|
||||
###########
|
||||
#
|
||||
# CMSIS DSP
|
||||
#
|
||||
|
||||
add_subdirectory(../../../Source bin_dsp)
|
||||
|
||||
|
||||
###################################
|
||||
#
|
||||
# TEST APPLICATION
|
||||
#
|
||||
###################################
|
||||
|
||||
|
||||
add_executable(arm_svm_example)
|
||||
|
||||
|
||||
include(config)
|
||||
configApp(arm_svm_example ${ROOT})
|
||||
|
||||
target_sources(arm_svm_example PRIVATE arm_svm_example_f32.c)
|
||||
|
||||
### Sources and libs
|
||||
|
||||
target_link_libraries(arm_svm_example PRIVATE CMSISDSP)
|
||||
|
||||
@ -0,0 +1,185 @@
|
||||
/* ----------------------------------------------------------------------
|
||||
* Copyright (C) 2019-2020 ARM Limited. All rights reserved.
|
||||
*
|
||||
* $Date: 09. December 2019
|
||||
* $Revision: V1.0.0
|
||||
*
|
||||
* Project: CMSIS DSP Library
|
||||
* Title: arm_svm_example_f32.c
|
||||
*
|
||||
* Description: Example code demonstrating how to use SVM functions.
|
||||
*
|
||||
* Target Processor: Cortex-M/Cortex-A
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* - Neither the name of ARM LIMITED nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
* -------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @ingroup groupExamples
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup SVMExample SVM Example
|
||||
*
|
||||
* \par Description:
|
||||
* \par
|
||||
* Demonstrates the use of SVM functions. It is complementing the tutorial
|
||||
* about classical ML with CMSIS-DSP and python scikit-learn.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/** \example arm_svm_example_f32.c
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include "arm_math.h"
|
||||
|
||||
/*
|
||||
|
||||
The polynomial SVM instance containing all parameters.
|
||||
Those parameters can be generated with the python library scikit-learn.
|
||||
|
||||
*/
|
||||
arm_svm_polynomial_instance_f32 params;
|
||||
|
||||
/*
|
||||
|
||||
Parameters generated by a training of the SVM classifier
|
||||
using scikit-learn and some random input data.
|
||||
|
||||
*/
|
||||
#define NB_SUPPORT_VECTORS 11
|
||||
|
||||
/*
|
||||
|
||||
Dimension of the vector space. A vector is your feature.
|
||||
It could, for instance, be the pixels of a picture or
|
||||
the FFT of a signal.
|
||||
|
||||
*/
|
||||
#define VECTOR_DIMENSION 2
|
||||
|
||||
const float32_t dualCoefficients[NB_SUPPORT_VECTORS]={-0.01628988f, -0.0971605f,
|
||||
-0.02707579f, 0.0249406f, 0.00223095f, 0.04117345f,
|
||||
0.0262687f, 0.00800358f, 0.00581823f, 0.02346904f, 0.00862162f}; /* Dual coefficients */
|
||||
|
||||
const float32_t supportVectors[NB_SUPPORT_VECTORS*VECTOR_DIMENSION]={ 1.2510991f, 0.47782799f,
|
||||
-0.32711859f, -1.49880648f, -0.08905047f, 1.31907242f,
|
||||
1.14059333f, 2.63443767f, -2.62561524f, 1.02120701f,
|
||||
-1.2361353f, -2.53145187f,
|
||||
2.28308122f, -1.58185875f, 2.73955981f, 0.35759327f,
|
||||
0.56662986f, 2.79702016f,
|
||||
-2.51380816f, 1.29295364f, -0.56658669f, -2.81944734f}; /* Support vectors */
|
||||
|
||||
/*
|
||||
|
||||
Class A is identified with value 0.
|
||||
Class B is identified with value 1.
|
||||
|
||||
This array is used by the SVM functions to do a conversion
|
||||
and ease the comparison with the Python code where
|
||||
different values could be used.
|
||||
|
||||
*/
|
||||
const int32_t classes[2]={0,1};
|
||||
|
||||
|
||||
int32_t main(void)
|
||||
{
|
||||
/* Array of input data */
|
||||
float32_t in[VECTOR_DIMENSION];
|
||||
|
||||
/* Result of the classifier */
|
||||
int32_t result;
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Initialization of the SVM instance parameters.
|
||||
|
||||
Additional parameters (intercept, degree, coef0 and gamma)
|
||||
are also coming from Python.
|
||||
|
||||
*/
|
||||
arm_svm_polynomial_init_f32(¶ms,
|
||||
NB_SUPPORT_VECTORS,
|
||||
VECTOR_DIMENSION,
|
||||
-1.661719f, /* Intercept */
|
||||
dualCoefficients,
|
||||
supportVectors,
|
||||
classes,
|
||||
3, /* degree */
|
||||
1.100000f, /* Coef0 */
|
||||
0.500000f /* Gamma */
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Input data. It is corresponding to a point inside
|
||||
the first class.
|
||||
|
||||
*/
|
||||
in[0] = 0.4f;
|
||||
in[1] = 0.1f;
|
||||
arm_svm_polynomial_predict_f32(¶ms,
|
||||
in,
|
||||
&result);
|
||||
|
||||
/*
|
||||
|
||||
Result should be 0 : First class
|
||||
|
||||
*/
|
||||
printf("Result = %d\n", result);
|
||||
|
||||
/*
|
||||
|
||||
This input vector is corresponding to a point inside
|
||||
the second class.
|
||||
|
||||
*/
|
||||
in[0] = 3.0f;
|
||||
in[1] = 0.0f;
|
||||
arm_svm_polynomial_predict_f32(¶ms,
|
||||
in,
|
||||
&result);
|
||||
|
||||
/*
|
||||
|
||||
Result should be 1 : Second class
|
||||
|
||||
*/
|
||||
printf("Result = %d\n", result);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,110 @@
|
||||
from sklearn import svm
|
||||
import random
|
||||
import numpy as np
|
||||
import math
|
||||
|
||||
from pylab import scatter,figure, clf, plot, xlabel, ylabel, xlim, ylim, title, grid, axes, show,semilogx, semilogy
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.ticker import MaxNLocator
|
||||
from matplotlib.colors import BoundaryNorm
|
||||
|
||||
# Generation of data to train the SVM classifier
|
||||
# 100 vectors are generated. Vector have dimension 2 so can be represented as points
|
||||
NBVECS = 100
|
||||
VECDIM = 2
|
||||
|
||||
# A cluster of point is generated around the origin.
|
||||
ballRadius = 0.5
|
||||
x = ballRadius * np.random.randn(NBVECS,2)
|
||||
|
||||
# An annulus of point is generated around the central cluster.
|
||||
angle = 2.0*math.pi * np.random.randn(1,NBVECS)
|
||||
radius = 3.0+0.1*np.random.randn(1,NBVECS)
|
||||
|
||||
xa = np.zeros((NBVECS,2))
|
||||
xa[:,0]=radius*np.cos(angle)
|
||||
xa[:,1]=radius*np.sin(angle)
|
||||
|
||||
# All points are concatenated
|
||||
X_train=np.concatenate((x,xa))
|
||||
|
||||
# First points (central cluster) are corresponding to class 0
|
||||
# OTher points (annulus) are corresponding to class 1
|
||||
Y_train=np.concatenate((np.zeros(NBVECS),np.ones(NBVECS)))
|
||||
|
||||
# Some bounds are computed for the graphical representation
|
||||
x_min = X_train[:, 0].min()
|
||||
x_max = X_train[:, 0].max()
|
||||
y_min = X_train[:, 1].min()
|
||||
y_max = X_train[:, 1].max()
|
||||
|
||||
# Training is done with a polynomial SVM
|
||||
clf = svm.SVC(kernel='poly',gamma='auto', coef0=1.1)
|
||||
clf.fit(X_train, Y_train)
|
||||
|
||||
# The classifier is tested with a first point inside first class
|
||||
test1=np.array([0.4,0.1])
|
||||
test1=test1.reshape(1,-1)
|
||||
|
||||
predicted1 = clf.predict(test1)
|
||||
# Predicted class should be 0
|
||||
print(predicted1)
|
||||
|
||||
# Second test is made with a point inside the second class (in the annulus)
|
||||
test2=np.array([x_max,0]).reshape(1,-1)
|
||||
|
||||
predicted2 = clf.predict(test2)
|
||||
# Predicted class should be 1
|
||||
print(predicted2)
|
||||
|
||||
# The parameters of the trained classifier are printed to be used
|
||||
# in CMSIS-DSP
|
||||
supportShape = clf.support_vectors_.shape
|
||||
|
||||
nbSupportVectors=supportShape[0]
|
||||
vectorDimensions=supportShape[1]
|
||||
|
||||
print("nbSupportVectors = %d" % nbSupportVectors)
|
||||
print("vectorDimensions = %d" % vectorDimensions)
|
||||
print("degree = %d" % clf.degree)
|
||||
print("coef0 = %f" % clf.coef0)
|
||||
print("gamma = %f" % clf._gamma)
|
||||
|
||||
print("intercept = %f" % clf.intercept_)
|
||||
|
||||
dualCoefs=clf.dual_coef_
|
||||
dualCoefs=dualCoefs.reshape(nbSupportVectors)
|
||||
supportVectors=clf.support_vectors_
|
||||
supportVectors = supportVectors.reshape(nbSupportVectors*VECDIM)
|
||||
|
||||
print("Dual Coefs")
|
||||
print(dualCoefs)
|
||||
|
||||
print("Support Vectors")
|
||||
print(supportVectors)
|
||||
|
||||
# Graphical representation to display the cluster of points
|
||||
# and the SVM boundary
|
||||
r=plt.figure()
|
||||
XX, YY = np.mgrid[x_min:x_max:200j, y_min:y_max:200j]
|
||||
Z = clf.decision_function(np.c_[XX.ravel(), YY.ravel()])
|
||||
|
||||
# Put the result into a color plot
|
||||
Z = Z.reshape(XX.shape)
|
||||
|
||||
levels = MaxNLocator(nbins=15).tick_values(Z.min(), Z.max())
|
||||
|
||||
cmap = plt.get_cmap('gray')
|
||||
norm = BoundaryNorm(levels, ncolors=cmap.N, clip=True)
|
||||
|
||||
plt.pcolormesh(XX, YY, Z > 0, cmap=plt.get_cmap('gray'),norm=norm)
|
||||
plt.contour(XX, YY, Z, colors=['k', 'k', 'k'],
|
||||
linestyles=['--', '-', '--'], levels=[-.5, 0, .5])
|
||||
|
||||
scatter(x[:,0],x[:,1],s=1.0)
|
||||
scatter(xa[:,0],xa[:,1],s=1.0)
|
||||
|
||||
# The test points are displayed in red.
|
||||
scatter(test1[:,0],test1[:,1],s=6.0,color='Red')
|
||||
scatter(test2[:,0],test2[:,1],s=6.0,color='Red')
|
||||
show()
|
||||
Loading…
Reference in New Issue