History

added KNN.weigh()

Ge Wang committed 3 years ago

Commit 11b3b3c1 parent 7cda3b24 files · +114 −16Browse files

Unified · Split

4 files
  1. examples/ai/knn/knn-search.ck +4 −0
  2. examples/ai/knn/knn2-classify.ck +5 −1
  3. examples/ai/knn/knn2-search.ck +4 −0
  4. src/core/ulib_ai.cpp +101 −15
examples/ai/knn/knn-search.ck+4−0
@@ -22,6 +22,10 @@ KNN knn; · 21 unmodified lines
2222 [2.0, 2.0]] @=> float features[][];
2323 // train the model
2424 knn.train( features );
25+// optional: weigh feature dimensions
26+[1.0, 1.0] @=> float weights[];
27+// optional: set the weights across dimensions
28+knn.weigh( weights );
2529
2630 // provide a test query
2731 [0.5, 0.5] @=> float q[];
examples/ai/knn/knn2-classify.ck+5−1
@@ -30,8 +30,12 @@ KNN2 knn; · 29 unmodified lines
3030 labels.size() => int NUM_LABELS;
3131 // train the model
3232 knn.train( features, labels );
33+// optional: weigh the feature dimensions
34+[1.0, 1.0] @=> float weights[];
35+// optional: set the weights across feature dimensions
36+knn.weigh( weights );
3337
34−// provide an unlabled test query
38+// provide an unlabeled test query
3539 [0.5, 0.5] @=> float q[];
3640
3741 // predict with new query and k=1
examples/ai/knn/knn2-search.ck+4−0
@@ -30,6 +30,10 @@ KNN2 knn; · 29 unmodified lines
3030 labels.size() => int NUM_LABELS;
3131 // train the model
3232 knn.train( features, labels );
33+// optional: weigh the feature dimensions
34+[1.0, 1.0] @=> float weights[];
35+// optional: set the weights across feature dimensions
36+knn.weigh( weights );
3337
3438 // provide an unlabled test query
3539 [0.5, 0.5] @=> float q[];
src/core/ulib_ai.cpp+101−15
@@ -59,6 +59,7 @@ CK_DLL_CTOR( KNN_ctor ); · 58 unmodified lines
5959 CK_DLL_DTOR( KNN_dtor );
6060 CK_DLL_MFUN( KNN_train );
6161 CK_DLL_MFUN( KNN_search );
62+CK_DLL_MFUN( KNN_weigh );
6263 // 1.4.2.1 (yikai) added KNN2
6364 CK_DLL_CTOR( KNN2_ctor );
6465 CK_DLL_DTOR( KNN2_dtor );
@@ -67,6 +68,7 @@ CK_DLL_MFUN( KNN2_predict ); · 2 unmodified lines
6768 CK_DLL_MFUN( KNN2_search );
6869 CK_DLL_MFUN( KNN2_search2 );
6970 CK_DLL_MFUN( KNN2_search3 );
71+CK_DLL_MFUN( KNN2_weigh );
7072 // offset
7173 static t_CKUINT KNN_offset_data = 0;
7274 static t_CKUINT KNN2_offset_data = 0;
@@ -133,7 +135,7 @@ DLL_QUERY libai_query( Chuck_DL_Query * QUERY ) · 60 unmodified lines
133135 return FALSE;
134136
135137 // data offset
136− SVM_offset_data = type_engine_import_mvar( env, "float", "@SVM_data", FALSE );
138+ SVM_offset_data = type_engine_import_mvar( env, "int", "@SVM_data", FALSE );
137139 if( SVM_offset_data == CK_INVALID_OFFSET ) goto error;
138140
139141 // train
@@ -166,7 +168,7 @@ DLL_QUERY libai_query( Chuck_DL_Query * QUERY ) · 26 unmodified lines
166168 return FALSE;
167169
168170 // data offset
169− KNN_offset_data = type_engine_import_mvar( env, "float", "@KNN_data", FALSE );
171+ KNN_offset_data = type_engine_import_mvar( env, "int", "@KNN_data", FALSE );
170172 if( KNN_offset_data == CK_INVALID_OFFSET ) goto error;
171173
172174 // train
@@ -183,6 +185,12 @@ DLL_QUERY libai_query( Chuck_DL_Query * QUERY ) · 10 unmodified lines
183185 func->doc = "Search for the 'k' nearest neighbors of 'query' and return their respective indices.";
184186 if( !type_engine_import_mfun( env, func ) ) goto error;
185187
188+ // weigh
189+ func = make_new_mfun( "void", "weigh", KNN_weigh );
190+ func->add_arg( "float[]", "weights" );
191+ func->doc = "Set the weights for each dimension of the input vectors.";
192+ if( !type_engine_import_mfun( env, func ) ) goto error;
193+
186194 // end the class import
187195 type_engine_import_class_end( env );
188196
@@ -199,7 +207,7 @@ DLL_QUERY libai_query( Chuck_DL_Query * QUERY ) · 10 unmodified lines
199207 return FALSE;
200208
201209 // data offset
202− KNN_offset_data = type_engine_import_mvar( env, "float", "@KNN2_data", FALSE );
210+ KNN_offset_data = type_engine_import_mvar( env, "int", "@KNN2_data", FALSE );
203211 if( KNN_offset_data == CK_INVALID_OFFSET ) goto error;
204212
205213 // train
@@ -247,6 +255,12 @@ DLL_QUERY libai_query( Chuck_DL_Query * QUERY ) · 41 unmodified lines
247255 "Search for the 'k' nearest neighbors of 'query' and return their labels, indices, and feature vectors.";
248256 if( !type_engine_import_mfun( env, func ) ) goto error;
249257
258+ // weigh
259+ func = make_new_mfun( "void", "weigh", KNN2_weigh );
260+ func->add_arg( "float[]", "weights" );
261+ func->doc = "Set the weights for each dimension of the input vectors.";
262+ if( !type_engine_import_mfun( env, func ) ) goto error;
263+
250264 // end the class import
251265 type_engine_import_class_end( env );
252266
@@ -262,7 +276,7 @@ DLL_QUERY libai_query( Chuck_DL_Query * QUERY ) · 9 unmodified lines
262276 return FALSE;
263277
264278 // data offset
265− HMM_offset_data = type_engine_import_mvar( env, "float", "@HMM_data", FALSE );
279+ HMM_offset_data = type_engine_import_mvar( env, "int", "@HMM_data", FALSE );
266280 if( HMM_offset_data == CK_INVALID_OFFSET ) goto error;
267281
268282 // init
@@ -310,7 +324,7 @@ DLL_QUERY libai_query( Chuck_DL_Query * QUERY ) · 41 unmodified lines
310324 return FALSE;
311325
312326 // data offset
313− Word2Vec_offset_data = type_engine_import_mvar( env, "float", "@Word2Vec_data", FALSE );
327+ Word2Vec_offset_data = type_engine_import_mvar( env, "int", "@Word2Vec_data", FALSE );
314328 if( Word2Vec_offset_data == CK_INVALID_OFFSET ) goto error;
315329
316330 // load
@@ -393,7 +407,7 @@ DLL_QUERY libai_query( Chuck_DL_Query * QUERY ) · 76 unmodified lines
393407 return FALSE;
394408
395409 // data offset
396− PCA_offset_data = type_engine_import_mvar( env, "float", "@PCA_data", FALSE );
410+ PCA_offset_data = type_engine_import_mvar( env, "int", "@PCA_data", FALSE );
397411 if( PCA_offset_data == CK_INVALID_OFFSET ) goto error;
398412
399413 // transform
@@ -401,7 +415,8 @@ DLL_QUERY libai_query( Chuck_DL_Query * QUERY ) · 1 unmodified line
401415 func->add_arg( "float[][]", "input" );
402416 func->add_arg( "int", "D" );
403417 func->add_arg( "float[][]", "output" );
404− func->doc = "dimension-reduce 'input' (NxM) to 'output' (NxD) as the projection of the input data onto its first 'D' principle components";
418+ func->doc =
419+ "dimension-reduce 'input' (NxM) to 'output' (NxD) as the projection of the input data onto its first 'D' principle components";
405420 if( !type_engine_import_sfun( env, func ) ) goto error;
406421
407422 // end the class import
@@ -673,27 +688,37 @@ public: · 265 unmodified lines
673688 // constructor
674689 KNN_Object()
675690 {
676− X = new ChaiMatrixFast<t_CKFLOAT>();
677− Y = new ChaiVectorFast<t_CKUINT>();
691+ X = NULL;
692+ Y = NULL;
693+ weights = NULL;
678694 }
679695
680696 // destructor
681697 ~KNN_Object()
698+ {
699+ clear();
700+ }
701+
702+ // clear
703+ void clear()
682704 {
683705 SAFE_DELETE( X );
684706 SAFE_DELETE( Y );
707+ SAFE_DELETE( weights );
685708 }
686709
687710 // train
688711 t_CKINT train( Chuck_Array4 & x_ )
689712 {
713+ clear();
690714 // init
691715 t_CKINT n_sample = x_.size();
692716 t_CKUINT v;
693717 x_.get( 0, &v );
694718 Chuck_Array8 * x_i = (Chuck_Array8 *)v;
695719 t_CKINT x_dim = x_i->size();
696− X->allocate( n_sample, x_dim );
720+ X = new ChaiMatrixFast<t_CKFLOAT>( n_sample, x_dim );
721+ weights = new ChaiVectorFast<t_CKFLOAT>( x_dim );
697722 // copy
698723 for( t_CKINT i = 0; i < n_sample; i++ )
699724 {
@@ -704,20 +729,27 @@ public: · 4 unmodified lines
704729 x_i->get( j, &X->v( i, j ) );
705730 }
706731 }
732+ // init weights
733+ for( t_CKINT i = 0; i < x_dim; i++ )
734+ {
735+ weights->v( i ) = 1.0;
736+ }
707737 return 0;
708738 }
709739
710740 // train
711741 t_CKINT train( Chuck_Array4 & x_, Chuck_Array4 & y_ )
712742 {
743+ clear();
713744 // init
714745 t_CKINT n_sample = x_.size();
715746 t_CKUINT v;
716747 x_.get( 0, &v );
717748 Chuck_Array8 * x_i = (Chuck_Array8 *)v;
718749 t_CKUINT x_dim = x_i->size();
719− X->allocate( n_sample, x_dim );
720− Y->allocate( n_sample );
750+ X = new ChaiMatrixFast<t_CKFLOAT>( n_sample, x_dim );
751+ Y = new ChaiVectorFast<t_CKUINT>( n_sample );
752+ weights = new ChaiVectorFast<t_CKFLOAT>( x_dim );
721753 // copy
722754 for( t_CKINT i = 0; i < n_sample; i++ )
723755 {
@@ -729,6 +761,11 @@ public: · 5 unmodified lines
729761 }
730762 y_.get( i, &Y->v( i ) );
731763 }
764+ // init weights
765+ for( t_CKINT i = 0; i < x_dim; i++ )
766+ {
767+ weights->v( i ) = 1.0;
768+ }
732769 return 0;
733770 }
734771
@@ -760,7 +797,7 @@ public: · 25 unmodified lines
760797 {
761798 // extra check in case query less than training dimensions
762799 diff = ( j < query.size() ? query[j] : 0.0 ) - X->v( i, j );
763− distance += diff * diff;
800+ distance += diff * diff * weights->v( j );
764801 }
765802 // check
766803 for( t_CKINT j = 0; j < k; j++ )
@@ -891,9 +928,32 @@ public: · 124 unmodified lines
891928 }
892929 }
893930
931+ // weigh
932+ void weigh( const vector<t_CKFLOAT> & weights_ )
933+ {
934+ // sanity check
935+ if( X == NULL )
936+ {
937+ EM_error3( "KNN: cannot weigh without training data" );
938+ return;
939+ }
940+ if( weights_.size() != X->yDim() )
941+ {
942+ EM_error3( "KNN: invalid 'weights' vector provided: %d (expecting %d)",
943+ weights_.size(), X->yDim() );
944+ return;
945+ }
946+ // copy
947+ for( t_CKINT i = 0; i < weights_.size(); i++ )
948+ {
949+ weights->v( i ) = weights_[i];
950+ }
951+ }
952+
894953 private:
895954 ChaiMatrixFast<t_CKFLOAT> * X;
896955 ChaiVectorFast<t_CKUINT> * Y;
956+ ChaiVectorFast<t_CKFLOAT> * weights;
897957 };
898958
899959
@@ -953,6 +1013,16 @@ CK_DLL_MFUN( KNN_search ) · 53 unmodified lines
9531013 knn->search0( query->m_vector, k, *indices );
9541014 }
9551015
1016+CK_DLL_MFUN( KNN_weigh )
1017+{
1018+ // get object
1019+ KNN_Object * knn = (KNN_Object *)OBJ_MEMBER_UINT( SELF, KNN_offset_data );
1020+ // get args
1021+ Chuck_Array8 * weights = (Chuck_Array8 *)GET_NEXT_OBJECT( ARGS );
1022+ // weigh
1023+ knn->weigh( weights->m_vector );
1024+}
1025+
9561026
9571027
9581028
@@ -1074,6 +1144,16 @@ CK_DLL_MFUN( KNN2_search3 ) · 115 unmodified lines
10741144 knn->search3( query->m_vector, k, *labels, *indices, *features );
10751145 }
10761146
1147+CK_DLL_MFUN( KNN2_weigh )
1148+{
1149+ // get object
1150+ KNN_Object * knn = (KNN_Object *)OBJ_MEMBER_UINT( SELF, KNN2_offset_data );
1151+ // get args
1152+ Chuck_Array8 * weights = (Chuck_Array8 *)GET_NEXT_OBJECT( ARGS );
1153+ // weigh
1154+ knn->weigh( weights->m_vector );
1155+}
1156+
10771157 //-----------------------------------------------------------------------------
10781158 // name: struct HMM_Object
10791159 // desc: hidden markov model implementation | added 1.4.2.0 (yikai)
@@ -2065,7 +2145,10 @@ public: · 985 unmodified lines
20652145 { }
20662146
20672147 /* Reduce a real, symmetric matrix to a symmetric, tridiag. matrix. */
2068− static void tred2( ChaiMatrixFast<t_CKFLOAT> & a, t_CKINT m, ChaiVectorFast<t_CKFLOAT> & d, ChaiVectorFast<t_CKFLOAT> & e )
2148+ static void tred2( ChaiMatrixFast<t_CKFLOAT> & a,
2149+ t_CKINT m,
2150+ ChaiVectorFast<t_CKFLOAT> & d,
2151+ ChaiVectorFast<t_CKFLOAT> & e )
20692152 /* Householder reductiom of matrix a to tridiagomal form.
20702153 Algorithm: Martim et al., Num. Math. 11, 181-195, 1968.
20712154 Ref: Smith et al., Matrix Eigemsystem Routimes -- EISPACK Guide
@@ -2153,7 +2236,10 @@ public: · 81 unmodified lines
21532236 }
21542237
21552238 /* Tridiagonal QL algorithm -- Implicit */
2156− static void tqli( ChaiVectorFast<t_CKFLOAT> & d, ChaiVectorFast<t_CKFLOAT> & e, t_CKINT m, ChaiMatrixFast<t_CKFLOAT> & z )
2239+ static void tqli( ChaiVectorFast<t_CKFLOAT> & d,
2240+ ChaiVectorFast<t_CKFLOAT> & e,
2241+ t_CKINT m,
2242+ ChaiMatrixFast<t_CKFLOAT> & z )
21572243 /*
21582244 Source code adapted from F. Murtagh, Munich, 6 June 1989
21592245 http://astro.u-strasbg.fr/~fmurtagh/mda-sw/pca.c

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t