diff --git a/.gitignore b/.gitignore index 552df484..f13295ba 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ PythonWrapper/build/ PythonWrapper/cmsisdsp.cp36-win_amd64.pyd PythonWrapper/rec_2.dat Output.pickle +build_*/ + diff --git a/Examples/ARM/arm_svm_example/CMakeLists.txt b/Examples/ARM/arm_svm_example/CMakeLists.txt new file mode 100755 index 00000000..81308c3c --- /dev/null +++ b/Examples/ARM/arm_svm_example/CMakeLists.txt @@ -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) + diff --git a/Examples/ARM/arm_svm_example/arm_svm_example_f32.c b/Examples/ARM/arm_svm_example/arm_svm_example_f32.c new file mode 100755 index 00000000..e3698f14 --- /dev/null +++ b/Examples/ARM/arm_svm_example/arm_svm_example_f32.c @@ -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 +#include +#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); + +} + + + diff --git a/Examples/ARM/arm_svm_example/train.py b/Examples/ARM/arm_svm_example/train.py new file mode 100755 index 00000000..49287bec --- /dev/null +++ b/Examples/ARM/arm_svm_example/train.py @@ -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() diff --git a/Source/BayesFunctions/arm_gaussian_naive_bayes_predict_f32.c b/Source/BayesFunctions/arm_gaussian_naive_bayes_predict_f32.c index 545f02f5..243a76e6 100755 --- a/Source/BayesFunctions/arm_gaussian_naive_bayes_predict_f32.c +++ b/Source/BayesFunctions/arm_gaussian_naive_bayes_predict_f32.c @@ -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++)