CMSIS-DSP: Added an SVM example to show how to use it.

pull/19/head
Christophe Favergeon 6 years ago
parent 665ba5d4cb
commit 585137ad16

2
.gitignore vendored

@ -3,3 +3,5 @@ PythonWrapper/build/
PythonWrapper/cmsisdsp.cp36-win_amd64.pyd
PythonWrapper/rec_2.dat
Output.pickle
build_*/

@ -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(&params,
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(&params,
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(&params,
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()

@ -44,6 +44,9 @@
* @param[in] *pBuffer points to a buffer of length numberOfClasses
* @return The predicted class
*
* @par If the number of classes is big, MVE version will consume lot of
* stack since the log prior are computed on the stack.
*
*/
#if defined(ARM_MATH_MVEF) && !defined(ARM_MATH_AUTOVECTORIZE)
@ -359,7 +362,7 @@ uint32_t arm_gaussian_naive_bayes_predict_f32(const arm_gaussian_naive_bayes_ins
pIn = in;
tmp = logf(*pPrior);
tmp = 0.0;
acc1 = 0.0f;
acc2 = 0.0f;
for(nbDim = 0; nbDim < S->vectorDimension; nbDim++)

Loading…
Cancel
Save