Преглед изворни кода

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

Christophe Favergeon пре 6 година
родитељ
комит
9dc97a95f3

+ 2 - 0
CMSIS/DSP/.gitignore

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

+ 45 - 0
CMSIS/DSP/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)
+

+ 185 - 0
CMSIS/DSP/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 <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);
+
+}
+
+
+

+ 110 - 0
CMSIS/DSP/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()

+ 4 - 1
CMSIS/DSP/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++)