- メインページ
- モジュール
- ネームスペース
- データ構造
- ファイル

- ファイル一覧
- グローバル

machine_learning.h
説明を見る。
1 //
2 // Copyright (c) 2003-2011, MIST Project, Nagoya University
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without modification,
6 // are permitted provided that the following conditions are met:
7 //
8 // 1. Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 //
11 // 2. Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
14 //
15 // 3. Neither the name of the Nagoya University nor the names of its contributors
16 // may be used to endorse or promote products derived from this software
17 // without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
20 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 //
28
42 #ifndef __INCLUDE_MACHINE_LEARNING__
43 #define __INCLUDE_MACHINE_LEARNING__
44
45
46 #ifndef __INCLUDE_MIST_H__
47 #include "mist.h"
48 #endif
49
50 #ifndef __INCLUDE_MIST_RANDOM__
51 #include "random.h"
52 #endif
53
54
55 #include <ctime>
56 #include <vector>
57 #include <map>
58 #include <algorithm>
59
60 #ifdef _OPENMP
61 #include <omp.h>
62 #endif
63
64
65 // mist名前空間の始まり
66 _MIST_BEGIN
67
68
69 #define __ASYMMETRIC_WEIGHTING__ 0
70 #define __ONE_PER_CLASS_CODE_WORD__ 0
71 #define __RANDOM_CODE_WORD__ 0
72 #define __DEBUG_OUTPUT_LEVEL__ 0
73 #define __NUMBER_OF_INNER_LOOPS__ 10
74
75
77 namespace machine_learning
78 {
79 typedef double feature_value_type;
80 typedef double feature_weight_type;
81
83 struct feature_one
84 {
85 typedef size_t size_type;
86 typedef ptrdiff_t difference_type;
87
88 feature_value_type value;
89 bool category;
90 feature_weight_type weight;
91
93 feature_one( ) : value( 0.0 ), category( true ), weight( 0.0 )
94 {
95 }
96
103 feature_one( feature_value_type val, bool cate, feature_weight_type wei ) : value( val ), category( cate ), weight( wei )
104 {
105 }
106
108 feature_one( const feature_one &f ): value( f.value ), category( f.category ), weight( f.weight )
109 {
110 }
111
113 feature_one &operator =( const feature_one &f )
114 {
115 if( &f != this )
116 {
117 value = f.value;
118 category = f.category;
119 weight = f.weight;
120 }
121
122 return( *this );
123 }
124
126 bool operator <( const feature_one &f ) const
127 {
128 return( value < f.value );
129 }
130 };
131
133 struct feature : public std::vector< feature_value_type >
134 {
135 typedef std::vector< feature_value_type > base;
136 typedef base::value_type value_type;
137 typedef base::size_type size_type;
138 typedef base::difference_type difference_type;
139
140 std::string category;
141 feature_weight_type weight;
142 bool valid;
143
145 feature( ) : base( ), category( "unknown" ), weight( 0.0 ), valid( true )
146 {
147 }
148
153 feature( size_type dimension ) : base( dimension ), category( "unknown" ), weight( 0.0 ), valid( true )
154 {
155 }
156
161 feature( const std::string &cate ) : base( ), category( cate ), weight( 0.0 ), valid( true )
162 {
163 }
164
170 feature( size_type dimension, const std::string &cate ) : base( dimension, 0.0 ), category( cate ), weight( 0.0 ), valid( true )
171 {
172 }
173
175 feature( const feature &f ): base( f ), category( f.category ), weight( f.weight ), valid( f.valid )
176 {
177 }
178
180 feature &operator =( const feature &f )
181 {
182 if( &f != this )
183 {
184 base::operator =( f );
185 category = f.category;
186 weight = f.weight;
187 valid = f.valid;
188 }
189
190 return( *this );
191 }
192 };
193
195 template < class KEY, class VALUE >
196 struct pair
197 {
198 KEY key;
199 VALUE value;
200
202 pair( ){ }
203
205 pair( const KEY &k, const VALUE &val ) : key( k ), value( val ){ }
206
208 bool operator <( const pair &f ) const
209 {
210 return( key < f.key );
211 }
212
214 static bool greater( const pair &f1, const pair &f2 )
215 {
216 return( f2 < f1 );
217 }
218 };
219
220
228
230 namespace adaboost
231 {
232 inline size_t __power_of_two__( size_t x )
233 {
234 size_t val = 1;
235 for( size_t i = 0 ; i < x ; i++ )
236 {
237 val *= 2;
238 }
239 return( val );
240 }
241
243 class threshold_classifier
244 {
245 public:
246 typedef feature feature_type;
247 typedef feature_type::value_type value_type;
248 typedef feature_type::size_type size_type;
249 typedef feature_type::difference_type difference_type;
250
251 private:
252 double sign_;
253 double threshold_;
254 size_type index_;
255
256 public:
258 threshold_classifier( ) : sign_( 1.0 ), threshold_( 0.0 ), index_( 0 )
259 {
260 }
261
263 threshold_classifier( const threshold_classifier& w ) : sign_( w.sign_ ), threshold_( w.threshold_ ), index_( w.index_ )
264 {
265 }
266
268 threshold_classifier& operator =( const threshold_classifier& other )
269 {
270 if( this != &other )
271 {
272 sign_ = other.sign_;
273 threshold_ = other.threshold_;
274 index_ = other.index_;
275 }
276
277 return( *this );
278 }
279
280 public:
286 template < template < typename, typename > class FEATURE_LIST, template < typename, typename > class CATEGORY_LIST, class Allocator1, class Allocator2 >
287 bool learn( const FEATURE_LIST< feature_type, Allocator1 > & features, const CATEGORY_LIST< bool, Allocator2 > &categories )
288 {
289 if( features.empty( ) )
290 {
291 return( false );
292 }
293
294 double _minimum_classification_error_ = 1.0e100;
295
296 // Positive と Negative それぞれの重みの合計を計算する
297 double overall_sum_of_positive_weights = 0.0;
298 double overall_sum_of_negative_weights = 0.0;
299 for( size_type i = 0 ; i < features.size( ) ; i++ )
300 {
301 const feature_type &f = features[ i ];
302 if( categories[ i ] )
303 {
304 overall_sum_of_positive_weights += f.weight;
305 }
306 else
307 {
308 overall_sum_of_negative_weights += f.weight;
309 }
310 }
311
312 if( overall_sum_of_positive_weights == 0.0 || overall_sum_of_negative_weights == 0.0 )
313 {
314 return( false );
315 }
316
317 double max_sigma = -1.0;
318 int nfeatures = static_cast< int >( features[ 0 ].size( ) );
319
320 // 特徴量のリストを作成する
321 #pragma omp parallel for firstprivate( nfeatures ) schedule( guided )
322 for( int index = 0 ; index < nfeatures ; index++ )
323 {
324 std::vector< feature_one > flist;
325 flist.reserve( features.size( ) );
326 for( size_type i = 0 ; i < features.size( ) ; i++ )
327 {
328 const feature_type &f = features[ i ];
329 if( f.valid )
330 {
331 flist.push_back( feature_one( f[ index ], categories[ i ], f.weight ) );
332 }
333 }
334
335 // 特徴量をソートする
336 std::sort( flist.begin( ), flist.end( ) );
337
338 // 各しきい値での重み付き誤差を計算し，誤差最小のしきい値を求める
339 double min_error = 1.0e100, sgn = 1.0, th = 0.0;
340 double sum_of_positive_weights = 0.0;
341 double sum_of_negative_weights = 0.0;
342
343 for( size_type i = 0 ; i < flist.size( ) ; i++ )
344 {
345 const feature_one &f = flist[ i ];
346 if( f.category )
347 {
348 sum_of_positive_weights += f.weight;
349 }
350 else
351 {
352 sum_of_negative_weights += f.weight;
353 }
354
355 double e1 = sum_of_positive_weights + overall_sum_of_negative_weights - sum_of_negative_weights;
356 double e2 = sum_of_negative_weights + overall_sum_of_positive_weights - sum_of_positive_weights;
357 double error = e1 < e2 ? e1 : e2;
358
359 if( error <= min_error )
360 {
361 min_error = error;
362 th = f.value;
363 sgn = e1 < e2 ? -1.0 : 1.0;
364
365 if( 0 < i && i < flist.size( ) - 2 )
366 {
367 double v1 = std::abs( flist[ i - 1 ].value - flist[ i + 0 ].value );
368 double v2 = std::abs( flist[ i + 1 ].value - flist[ i + 2 ].value );
369 if( std::abs( v1 + v2 ) > 0 )
370 {
371 double t1 = flist[ i + 0 ].value;
372 double t2 = flist[ i + 1 ].value;
373 th = ( t1 * v1 + t2 * v2 ) / ( v1 + v2 );
374 }
375 }
376 else if( i < flist.size( ) - 1 )
377 {
378 th = ( th + flist[ i + 1 ].value ) * 0.5;
379 }
380 }
381 }
382
383 double e = 0.0;
384 for( size_t i = 0 ; i < features.size( ) ; i++ )
385 {
386 const feature_type &f = features[ i ];
387 if( f.valid )
388 {
389 if( evaluate( f, index, sgn, th ) != categories[ i ] )
390 {
391 e += f.weight;
392 }
393 }
394 }
395
396 double sigma = 0.0;
397 {
398 double M1 = 0.0;
399 double M2 = 0.0;
400 double S1 = 0.0;
401 double S2 = 0.0;
402
403 for( size_type i = 0 ; i < flist.size( ) ; i++ )
404 {
405 const feature_type &f = features[ i ];
406 if( categories[ i ] )
407 {
408 M1 += f.weight * f[ index ];
409 }
410 else
411 {
412 M2 += f.weight * f[ index ];
413 }
414 }
415
416 M1 /= overall_sum_of_positive_weights;
417 M2 /= overall_sum_of_negative_weights;
418
419 for( size_type i = 0 ; i < features.size( ) ; i++ )
420 {
421 const feature_type &f = features[ i ];
422 if( categories[ i ] )
423 {
424 S1 += f.weight * ( f[ index ] - M1 ) * ( f[ index ] - M1 );
425 }
426 else
427 {
428 S2 += f.weight * ( f[ index ] - M2 ) * ( f[ index ] - M2 );
429 }
430 }
431
432 S1 /= overall_sum_of_positive_weights;
433 S2 /= overall_sum_of_negative_weights;
434 double V1 = overall_sum_of_positive_weights * overall_sum_of_negative_weights * ( M1 - M2 ) * ( M1 - M2 );
435 double V2 = ( overall_sum_of_positive_weights + overall_sum_of_negative_weights ) * ( overall_sum_of_positive_weights * S1 + overall_sum_of_negative_weights * S2 );
436 sigma = V1 / ( 1.0 + V2 );
437 }
438
439 #pragma omp critical
440 {
441 if( _minimum_classification_error_ > e )
442 {
443 _minimum_classification_error_ = e;
444 index_ = index;
445 sign_ = sgn;
446 threshold_ = th;
447 max_sigma = sigma;
448 }
449 else if( _minimum_classification_error_ == e && sigma > max_sigma )
450 {
451 _minimum_classification_error_ = e;
452 index_ = index;
453 sign_ = sgn;
454 threshold_ = th;
455 max_sigma = sigma;
456 }
457 }
458 }
459
460 return( true );
461 }
462
463 public:
468 template < class FEATURE >
469 bool operator ()( const FEATURE &f ) const
470 {
471 return( evaluate( f ) );
472 }
473
478 template < class FEATURE >
479 bool evaluate( const FEATURE &f ) const
480 {
481 return( evaluate( f, index_, sign_, threshold_ ) );
482 }
483
485 template < class FEATURE >
486 bool evaluate( const FEATURE &f, size_type indx, double sgn, double th ) const
487 {
488 return( sgn * f[ indx ] <= sgn * th );
489 }
490
492 const std::string serialize( ) const
493 {
494 char buff[ 1024 ];
495 sprintf( buff, "%ld,%f,%f", index_, sign_, threshold_ );
496 return( buff );
497 }
498
500 void deserialize( const std::string &data )
501 {
502 sscanf( data.c_str( ), "%ld,%lf,%lf", &index_, &sign_, &threshold_ );
503 }
504 };
505
507 class mahalanobis_classifier
508 {
509 public:
510 typedef feature feature_type;
511 typedef feature_type::value_type value_type;
512 typedef feature_type::size_type size_type;
513 typedef feature_type::difference_type difference_type;
514
515 private:
516 double ave_[ 2 ];
517 double sig_[ 2 ];
518 size_type index_;
519
520 public:
522 mahalanobis_classifier( ) : index_( 0 )
523 {
524 ave_[ 0 ] = ave_[ 1 ] = 0.0;
525 sig_[ 0 ] = sig_[ 1 ] = 1.0;
526 }
527
529 mahalanobis_classifier( const mahalanobis_classifier& w ) : index_( w.index_ )
530 {
531 memcpy( ave_, w.ave_, sizeof( double ) * 2 );
532 memcpy( sig_, w.sig_, sizeof( double ) * 2 );
533 }
534
536 mahalanobis_classifier& operator =( const mahalanobis_classifier& other )
537 {
538 if( this != &other )
539 {
540 memcpy( ave_, other.ave_, sizeof( double ) * 2 );
541 memcpy( sig_, other.sig_, sizeof( double ) * 2 );
542 index_ = other.index_;
543 }
544
545 return( *this );
546 }
547
548 public:
554 template < template < typename, typename > class FEATURE_LIST, template < typename, typename > class CATEGORY_LIST, class Allocator1, class Allocator2 >
555 bool learn( const FEATURE_LIST< feature_type, Allocator1 > & features, const CATEGORY_LIST< bool, Allocator2 > &categories )
556 {
557 if( features.empty( ) )
558 {
559 return( false );
560 }
561
562 double _minimum_classification_error_ = 1.0e100;
563
564 // Positive と Negative それぞれの重みの合計を計算する
565 double overall_sum_of_positive_weights = 0.0;
566 double overall_sum_of_negative_weights = 0.0;
567 for( size_type i = 0 ; i < features.size( ) ; i++ )
568 {
569 const feature_type &f = features[ i ];
570 if( categories[ i ] )
571 {
572 overall_sum_of_positive_weights += f.weight;
573 }
574 else
575 {
576 overall_sum_of_negative_weights += f.weight;
577 }
578 }
579
580 double max_sigma = -1.0;
581 int nfeatures = static_cast< int >( features[ 0 ].size( ) );
582
583 // 特徴量のリストを作成する
584 #pragma omp parallel for firstprivate( nfeatures ) schedule( guided )
585 for( int index = 0 ; index < nfeatures ; index++ )
586 {
587 double ave[ 2 ] = { 0.0, 0.0 };
588 double sig[ 2 ] = { 0.0, 0.0 };
589
590 for( size_type i = 0 ; i < features.size( ) ; i++ )
591 {
592 const feature_type &f = features[ i ];
593 if( categories[ i ] )
594 {
595 ave[ 0 ] += f.weight * f[ index ];
596 }
597 else
598 {
599 ave[ 1 ] += f.weight * f[ index ];
600 }
601 }
602
603 ave[ 0 ] /= overall_sum_of_positive_weights;
604 ave[ 1 ] /= overall_sum_of_negative_weights;
605
606 for( size_type i = 0 ; i < features.size( ) ; i++ )
607 {
608 const feature_type &f = features[ i ];
609 if( categories[ i ] )
610 {
611 sig[ 0 ] += f.weight * ( f[ index ] - ave[ 0 ] ) * ( f[ index ] - ave[ 0 ] );
612 }
613 else
614 {
615 sig[ 1 ] += f.weight * ( f[ index ] - ave[ 1 ] ) * ( f[ index ] - ave[ 1 ] );
616 }
617 }
618
619 sig[ 0 ] /= overall_sum_of_positive_weights;
620 sig[ 1 ] /= overall_sum_of_negative_weights;
621
622 double e = 0.0;
623 for( size_t i = 0 ; i < features.size( ) ; i++ )
624 {
625 const feature_type &f = features[ i ];
626 if( f.valid )
627 {
628 if( evaluate( f, index, ave, sig ) != categories[ i ] )
629 {
630 e += f.weight;
631 }
632 }
633 }
634
635 double sigma = 0.0;
636 {
637 double V1 = overall_sum_of_positive_weights * overall_sum_of_negative_weights * ( ave[ 0 ] - ave[ 1 ] ) * ( ave[ 0 ] - ave[ 1 ] );
638 double V2 = ( overall_sum_of_positive_weights + overall_sum_of_negative_weights ) * ( overall_sum_of_positive_weights * sig[ 0 ] + overall_sum_of_negative_weights * sig[ 1 ] );
639 sigma = V1 / V2;
640 }
641
642 #pragma omp critical
643 {
644 if( _minimum_classification_error_ >= e && sigma > max_sigma )
645 {
646 _minimum_classification_error_ = e;
647 index_ = index;
648 memcpy( ave_, ave, sizeof( double ) * 2 );
649 memcpy( sig_, sig, sizeof( double ) * 2 );
650 }
651 }
652 }
653
654 return( true );
655 }
656
657 public:
662 template < class FEATURE >
663 bool operator ()( const FEATURE &f ) const
664 {
665 return( evaluate( f ) );
666 }
667
672 template < class FEATURE >
673 bool evaluate( const FEATURE &f ) const
674 {
675 return( evaluate( f, index_, ave_, sig_ ) );
676 }
677
679 template < class FEATURE >
680 bool evaluate( const FEATURE &f, size_type indx, const double ave[ 2 ], const double sig[ 2 ] ) const
681 {
682 double v0 = f[ indx ] - ave[ 0 ];
683 double v1 = f[ indx ] - ave[ 1 ];
684 return( v0 * v0 * sig[ 1 ] <= v1 * v1 * sig[ 0 ] );
685 }
686
688 const std::string serialize( ) const
689 {
690 char buff[ 1024 ];
691 sprintf( buff, "%ld,%f,%f,%f,%f", index_, ave_[ 0 ], ave_[ 1 ], sig_[ 0 ], sig_[ 1 ] );
692 return( buff );
693 }
694
696 void deserialize( const std::string &data )
697 {
698 sscanf( data.c_str( ), "%ld,%lf,%lf,%lf,%lf", &index_, &ave_[ 0 ], &ave_[ 1 ], &sig_[ 0 ], &sig_[ 1 ] );
699 }
700 };
701
703 class confidence_rating_classifier
704 {
705 public:
706 typedef feature feature_type;
707 typedef feature_type::value_type value_type;
708 typedef feature_type::size_type size_type;
709 typedef feature_type::difference_type difference_type;
710
711 _MIST_CONST( size_type, __number_of_bins__, 100 );
712
713 private:
714 double hist1_[ __number_of_bins__ ];
715 double hist2_[ __number_of_bins__ ];
716 double min_;
717 double max_;
718 size_type index_;
719
720 public:
722 confidence_rating_classifier( ) : min_( 0 ), max_( 0 ), index_( 0 )
723 {
724 memset( hist1_, 0, sizeof( double ) * __number_of_bins__ );
725 memset( hist2_, 0, sizeof( double ) * __number_of_bins__ );
726 }
727
729 confidence_rating_classifier( const confidence_rating_classifier& w ) : min_( w.min_ ), max_( w.max_ ), index_( w.index_ )
730 {
731 memcpy( hist1_, w.hist1_, sizeof( double ) * __number_of_bins__ );
732 memcpy( hist2_, w.hist2_, sizeof( double ) * __number_of_bins__ );
733 }
734
736 confidence_rating_classifier& operator =( const confidence_rating_classifier& other )
737 {
738 if( this != &other )
739 {
740 memcpy( hist1_, other.hist1_, sizeof( double ) * __number_of_bins__ );
741 memcpy( hist2_, other.hist2_, sizeof( double ) * __number_of_bins__ );
742 index_ = other.index_;
743 min_ = other.min_;
744 max_ = other.max_;
745 }
746
747 return( *this );
748 }
749
750 public:
756 template < template < typename, typename > class FEATURE_LIST, template < typename, typename > class CATEGORY_LIST, class Allocator1, class Allocator2 >
757 bool learn( const FEATURE_LIST< feature_type, Allocator1 > & features, const CATEGORY_LIST< bool, Allocator2 > &categories )
758 {
759 if( features.empty( ) )
760 {
761 return( false );
762 }
763
764 double _minimum_classification_error_ = 1.0e100;
765 int nfeatures = static_cast< int >( features[ 0 ].size( ) );
766
767 // 特徴量のリストを作成する
768 #pragma omp parallel for firstprivate( nfeatures ) schedule( guided )
769 for( int index = 0 ; index < nfeatures ; index++ )
770 {
771 double min = features[ 0 ][ index ];
772 double max = min;
773
774 for( size_type i = 0 ; i < features.size( ) ; i++ )
775 {
776 const feature_type &f = features[ i ];
777 if( min > f[ index ] )
778 {
779 min = f[ index ];
780 }
781 else if( max < f[ index ] )
782 {
783 max = f[ index ];
784 }
785 }
786
787 double hist1[ __number_of_bins__ ];
788 double hist2[ __number_of_bins__ ];
789 for( size_type i = 0 ; i < __number_of_bins__ ; i++ )
790 {
791 hist1[ i ] = hist2[ i ] = 0.0;
792 }
793
794 for( size_type i = 0 ; i < features.size( ) ; i++ )
795 {
796 const feature_type &f = features[ i ];
797 int bin = ( int )( ( f[ index ] - min ) * __number_of_bins__ / ( max - min + 1 ) + 0.5 );
798 if( bin < 0 )
799 {
800 bin = 0;
801 }
802 else if( bin >= __number_of_bins__ )
803 {
804 bin = __number_of_bins__ - 1;
805 }
806
807 if( categories[ i ] )
808 {
809 hist1[ bin ] += f.weight;
810 }
811 else
812 {
813 hist2[ bin ] += f.weight;
814 }
815 }
816
817 double e = 0.0;
818 for( size_t i = 0 ; i < features.size( ) ; i++ )
819 {
820 const feature_type &f = features[ i ];
821 if( f.valid )
822 {
823 if( evaluate( f, index, hist1, hist2, min, max ) != categories[ i ] )
824 {
825 e += f.weight;
826 }
827 }
828 }
829
830 #pragma omp critical
831 {
832 if( _minimum_classification_error_ >= e )
833 {
834 _minimum_classification_error_ = e;
835 index_ = index;
836 min_ = min;
837 max_ = max;
838 memcpy( hist1_, hist1, sizeof( double ) * __number_of_bins__ );
839 memcpy( hist2_, hist2, sizeof( double ) * __number_of_bins__ );
840 }
841 }
842 }
843
844 return( true );
845 }
846
847 public:
852 template < class FEATURE >
853 bool operator ()( const FEATURE &f ) const
854 {
855 return( evaluate( f ) );
856 }
857
862 template < class FEATURE >
863 bool evaluate( const FEATURE &f ) const
864 {
865 return( evaluate( f, index_, hist1_, hist2_, min_, max_ ) );
866 }
867
869 template < class FEATURE >
870 bool evaluate( const FEATURE &f, size_type indx, const double hist1[ ], const double hist2[ ], double min, double max ) const
871 {
872 int bin = ( int )( ( f[ indx ] - min ) * __number_of_bins__ / ( max - min + 1 ) + 0.5 );
873 if( bin < 0 )
874 {
875 bin = 0;
876 }
877 else if( bin >= __number_of_bins__ )
878 {
879 bin = __number_of_bins__ - 1;
880 }
881 return( hist1[ bin ] <= hist2[ bin ] );
882 }
883
885 const std::string serialize( ) const
886 {
887 //char buff[ 1024 ];
888 //sprintf( buff, "%d,%f,%f,%f,%f", index_, ave_[ 0 ], ave_[ 1 ], sig_[ 0 ], sig_[ 1 ] );
889 //return( buff );
890 return( "" );
891 }
892
894 void deserialize( const std::string & /* data */ )
895 {
896 //sscanf( data.c_str( ), "%d,%lf,%lf,%lf,%lf", &index_, &ave_[ 0 ], &ave_[ 1 ], &sig_[ 0 ], &sig_[ 1 ] );
897 }
898 };
899
901 template < typename __WEAK_CLASSIFIER__ = threshold_classifier >
902 class classifier
903 {
904 public:
905 typedef __WEAK_CLASSIFIER__ weak_classifier_type;
906 typedef feature feature_type;
907 typedef feature_type::value_type value_type;
908 typedef feature_type::size_type size_type;
909 typedef feature_type::difference_type difference_type;
910
911 private:
912 std::vector< std::string > categories_;
913 std::vector< weak_classifier_type > weak_classifiers_;
914 std::vector< std::vector< bool > > code_word_;
915 std::vector< double > alpha_;
916 std::vector< double > beta_;
917
918 public:
920 classifier( )
921 {
922 }
923
925 classifier( const classifier &cls ) : categories_( cls.categories_ ), weak_classifiers_( cls.weak_classifiers_ ), code_word_( cls.code_word_ ), alpha_( cls.alpha_ ), beta_( cls.beta_ )
926 {
927 }
928
930 classifier& operator =( const classifier& other )
931 {
932 if( this != &other )
933 {
934 categories_ = other.categories_;
935 weak_classifiers_ = other.weak_classifiers_;
936 code_word_ = other.code_word_;
937 alpha_ = other.alpha_;
938 beta_ = other.beta_;
939 }
940
941 return( *this );
942 }
943
944 public:
946 const std::vector< weak_classifier_type > &weak_classifiers( ) const
947 {
948 return( weak_classifiers_ );
949 }
950
952 std::vector< weak_classifier_type > &weak_classifiers( )
953 {
954 return( weak_classifiers_ );
955 }
956
958 const std::vector< std::string > &categories( ) const
959 {
960 return( categories_ );
961 }
962
964 std::vector< std::string > &categories( )
965 {
966 return( categories_ );
967 }
968
970 const std::vector< std::vector< bool > > &code_word( ) const
971 {
972 return( code_word_ );
973 }
974
976 std::vector< std::vector< bool > > &code_word( )
977 {
978 return( code_word_ );
979 }
980
982 const std::vector< double > &alpha( ) const
983 {
984 return( alpha_ );
985 }
986
988 std::vector< double > &alpha( )
989 {
990 return( alpha_ );
991 }
992
994 const std::vector< double > &beta( ) const
995 {
996 return( beta_ );
997 }
998
1000 std::vector< double > &beta( )
1001 {
1002 return( beta_ );
1003 }
1004
1005 public:
1013 template < template < typename, typename > class FEATURE_LIST, class Allocator >
1014 bool learn( FEATURE_LIST< feature_type, Allocator > & features, size_type number_of_iterations )
1015 {
1016 if( features.empty( ) )
1017 {
1018 std::cerr << "特徴データが指定されていません．" << std::endl;
1019 return( false );
1020 }
1021 else if( number_of_iterations == 0 )
1022 {
1023 // 少なくとも1回は実行する
1024 number_of_iterations++;
1025 }
1026
1027 // 強識別器を初期化する
1028 weak_classifiers_.clear( );
1029 categories_.clear( );
1030 code_word_.clear( );
1031 alpha_.clear( );
1032 beta_.clear( );
1033
1034
1035 // カテゴリの数を数える
1036 std::map< std::string, size_type > category_map;
1037 for( size_type i = 0 ; i < features.size( ) ; i++ )
1038 {
1039 category_map[ features[ i ].category ] = 0;
1040 }
1041
1042 // カテゴリの数を確定する
1043 categories_.reserve( category_map.size( ) );
1044
1045 // カテゴリのリストを登録する
1046 std::map< std::string, size_type >::iterator ite = category_map.begin( );
1047 for( ; ite != category_map.end( ) ; ++ite )
1048 {
1049 ite->second = categories_.size( );
1050 categories_.push_back( ite->first );
1051 }
1052
1053 // 重みを初期化する
1054 mist::matrix< double > D( features.size( ), categories_.size( ) );
1055 for( size_type i = 0 ; i < features.size( ) ; i++ )
1056 {
1057 const feature_type &f = features[ i ];
1058 size_type category_index = category_map[ f.category ];
1059 for( size_type l = 0 ; l < categories_.size( ) ; l++ )
1060 {
1061 if( l != category_index )
1062 {
1063 D( i, l ) = 1.0 / static_cast< double >( features.size( ) * ( categories_.size( ) - 1 ) );
1064 }
1065 else
1066 {
1067 D( i, l ) = 0.0;
1068 }
1069 }
1070 }
1071
1072 std::vector< size_type > fcatemap( features.size( ) );
1073 std::vector< bool > fcategories( features.size( ) );
1074 std::vector< double > rpweight( categories_.size( ) );
1075 for( size_type i = 0 ; i < fcatemap.size( ) ; i++ )
1076 {
1077 fcatemap[ i ] = static_cast< typename std::vector< size_type >::value_type >( category_map[ features[ i ].category ] );
1078 }
1079
1080 #if defined( __ONE_PER_CLASS_CODE_WORD__ ) && __ONE_PER_CLASS_CODE_WORD__ == 1
1081 // 各クラス単位で code word を作る
1082 size_type nhypothesis = categories_.size( );
1083 #elif defined( __RANDOM_CODE_WORD__ ) && __RANDOM_CODE_WORD__ == 1
1084 uniform::random rnd( std::clock( ) );
1085 // code word を ECC ベースで作る
1086 size_type nhypothesis = categories_.size( );
1087 #else
1088 // code word を ECC ベースで作る
1089 size_type nhypothesis = 0;
1090 #endif
1091
1092 // AdaBoost により強識別器を学習する
1093 for( size_type t = 0 ; t < number_of_iterations ; t++ )
1094 {
1095 // カラーリングを決定する
1096 code_word_.push_back( std::vector< bool >( categories_.size( ) ) );
1097 std::vector< bool > &myu = code_word_.back( );
1098
1099 #if defined( __ONE_PER_CLASS_CODE_WORD__ ) && __ONE_PER_CLASS_CODE_WORD__ == 1
1100 myu[ t % nhypothesis ] = true;
1101 #elif defined( __RANDOM_CODE_WORD__ ) && __RANDOM_CODE_WORD__ == 1
1102 {
1103 std::vector< pair< double, size_type > > list( nhypothesis );
1104 for( size_type i = 0 ; i < list.size( ) ; i++ )
1105 {
1106 list[ i ].key = rnd.real1( );
1107 list[ i ].value = i;
1108 }
1109 std::sort( list.begin( ), list.end( ) );
1110 for( size_type i = 0 ; i < list.size( ) ; i++ )
1111 {
1112 myu[ list[ i ].value ] = i < list.size( ) / 2;
1113 }
1114 }
1115 #else
1116 if( categories_.size( ) == 2 )
1117 {
1118 myu[ 0 ] = ( t % 2 ) == 0;
1119 myu[ 1 ] = !myu[ 0 ];
1120 }
1121 else
1122 {
1123 myu[ 0 ] = true;
1124 size_type val = nhypothesis++;
1125 bool flag = true;
1126 for( size_type r = categories_.size( ) - 1 ; r > 0 ; r-- )
1127 {
1128 bool b = ( val & 1 ) != 0;
1129 flag = flag && b;
1130 myu[ r ] = b;
1131 val >>= 1;
1132 }
1133
1134 if( flag )
1135 {
1136 val = nhypothesis++;
1137 for( size_type r = categories_.size( ) - 1 ; r > 0 ; r-- )
1138 {
1139 myu[ r ] = ( val & 1 ) != 0;
1140 val >>= 1;
1141 }
1142 }
1143 }
1144 #endif
1145
1146 #if defined( __DEBUG_OUTPUT_LEVEL__ ) && __DEBUG_OUTPUT_LEVEL__ >= 3
1147 // 弱識別器の学習用カテゴリデータを作る
1148 for( size_type i = 0 ; i < fcategories.size( ) ; i++ )
1149 {
1150 std::cout << myu[ fcatemap[ i ] ];
1151 }
1152 std::cout << std::endl;
1153 #endif
1154
1155 // 学習に使う弱識別器を用意する
1156 weak_classifiers_.push_back( weak_classifier_type( ) );
1157 weak_classifier_type &weak = weak_classifiers_.back( );
1158
1159 for( size_type m = 0 ; m < __NUMBER_OF_INNER_LOOPS__ ; m++ )
1160 {
1161 // 弱識別器の学習用カテゴリデータを作る
1162 for( size_type i = 0 ; i < fcategories.size( ) ; i++ )
1163 {
1164 fcategories[ i ] = myu[ fcatemap[ i ] ];
1165 }
1166
1167 // 重みを正規化する
1168 double Ut = 0.0;
1169 for( size_type i = 0 ; i < features.size( ) ; i++ )
1170 {
1171 const feature_type &f = features[ i ];
1172 if( f.valid )
1173 {
1174 bool myuY = fcategories[ i ];
1175 for( size_type l = 0 ; l < categories_.size( ) ; l++ )
1176 {
1177 if( myuY != myu[ l ] )
1178 {
1179 Ut += D( i, l );
1180 }
1181 }
1182 }
1183 }
1184
1185 for( size_type i = 0 ; i < D.rows( ) ; i++ )
1186 {
1187 feature_type &f = features[ i ];
1188 if( f.valid )
1189 {
1190 bool myuY = fcategories[ i ];
1191 double sum = 0.0;
1192 for( size_type l = 0 ; l < categories_.size( ) ; l++ )
1193 {
1194 if( myuY != myu[ l ] )
1195 {
1196 sum += D( i, l );
1197 }
1198 }
1199
1200 f.weight = static_cast< feature_value_type >( sum / Ut );
1201 }
1202 }
1203
1204 // 弱識別器を学習する
1205 weak.learn( features, fcategories );
1206 //std::cout << "しきい値: " << weak.threshold( ) << ", 符号: " << ( weak.sign( ) < 0.0 ? "-" : "+" ) << ", 番号: " << weak.index( ) << std::endl;
1207
1208 if( m < __NUMBER_OF_INNER_LOOPS__ - 1 )
1209 {
1210 for( size_type i = 0 ; i < rpweight.size( ) ; i++ )
1211 {
1212 rpweight[ i ] = 0.0;
1213 }
1214
1215 for( size_type i = 0 ; i < features.size( ) ; i++ )
1216 {
1217 feature_type &f = features[ i ];
1218 if( f.valid )
1219 {
1220 double val = weak( f ) ? 1.0 : -1.0;
1221
1222 double tmp = 0.0;
1223 for( size_type l = 0 ; l < D.cols( ) ; l++ )
1224 {
1225 tmp += D( i, l ) * val;
1226 }
1227
1228 rpweight[ fcatemap[ i ] ] += tmp;
1229
1230 for( size_type l = 0 ; l < D.cols( ) ; l++ )
1231 {
1232 rpweight[ l ] -= D( i, l ) * val;
1233 }
1234 }
1235 }
1236
1237 std::vector< bool > tmyu( myu );
1238 bool isChanged = false;
1239 for( size_type i = 0 ; i < rpweight.size( ) ; i++ )
1240 {
1241 bool nmyu = rpweight[ i ] >= 0.0;
1242 isChanged = isChanged || nmyu != tmyu[ i ];
1243 tmyu[ i ] = nmyu;
1244 }
1245
1246 if( !isChanged )
1247 {
1248 // 前回とまったく同じなので終了する
1249 break;
1250 }
1251
1252 // すべて同じコードワードになっていないかをチェックする
1253 {
1254 size_type idx = 1;
1255 for( ; idx < tmyu.size( ) ; idx++ )
1256 {
1257 if( tmyu[ 0 ] != tmyu[ idx ] )
1258 {
1259 break;
1260 }
1261 }
1262
1263 if( idx < tmyu.size( ) )
1264 {
1265 myu = tmyu;
1266 }
1267 else
1268 {
1269 break;
1270 }
1271 }
1272 }
1273 }
1274
1275
1276 #if defined( __DEBUG_OUTPUT_LEVEL__ ) && __DEBUG_OUTPUT_LEVEL__ >= 3
1277 // 学習した弱識別器の分類結果を表示する
1278 for( size_type i = 0 ; i < features.size( ) ; i++ )
1279 {
1280 const feature_type &f = features[ i ];
1281 if( f.valid )
1282 {
1283 std::cout << weak.evaluate( f );
1284 }
1285 }
1286 std::cout << std::endl;
1287 #endif
1288
1289 #if defined( __ASYMMETRIC_WEIGHTING__ ) && __ASYMMETRIC_WEIGHTING__ == 1
1290 // 重みの更新を非対称に行う
1291 const double eps = 1.0e-16;
1292 double h1u1 = eps;
1293 double h1u0 = eps;
1294 double h0u0 = eps;
1295 double h0u1 = eps;
1296
1297 for( size_type i = 0 ; i < features.size( ) ; i++ )
1298 {
1299 const feature_type &f = features[ i ];
1300 if( f.valid )
1301 {
1302 bool uY = fcategories[ i ];
1303 bool hX = weak( f );
1304 if( hX && uY )
1305 {
1306 h1u1 += f.weight;
1307 }
1308 else if( hX && !uY )
1309 {
1310 h1u0 += f.weight;
1311 }
1312 else if( !hX && !uY )
1313 {
1314 h0u0 += f.weight;
1315 }
1316 else
1317 {
1318 h0u1 += f.weight;
1319 }
1320 }
1321 }
1322
1323 double alpha = 0.5 * std::log( h1u1 / h1u0 );
1324 double beta = -0.5 * std::log( h0u0 / h0u1 );
1325 #else
1326 // 重みの更新を対称にする
1327 const double eps = 1.0e-16;
1328 double positives = eps;
1329 double negatives = eps;
1330
1331 for( size_type i = 0 ; i < features.size( ) ; i++ )
1332 {
1333 const feature_type &f = features[ i ];
1334 if( f.valid )
1335 {
1336 bool uY = fcategories[ i ];
1337 bool hX = weak( f );
1338 if( hX == uY )
1339 {
1340 positives += f.weight;
1341 }
1342 else
1343 {
1344 negatives += f.weight;
1345 }
1346 }
1347 }
1348
1349 double alpha = 0.5 * std::log( positives / negatives );
1350 double beta = -alpha;
1351 #endif
1352
1353 alpha_.push_back( alpha );
1354 beta_.push_back( beta );
1355
1356 double Zt = 0.0;
1357 for( size_type i = 0 ; i < features.size( ) ; i++ )
1358 {
1359 const feature_type &f = features[ i ];
1360 if( f.valid )
1361 {
1362 bool myuY = fcategories[ i ];
1363 for( size_type l = 0 ; l < categories_.size( ) ; l++ )
1364 {
1365 double v = ( myu[ l ] - myuY ) * 0.5;
1366 if( weak( f ) )
1367 {
1368 v *= alpha;
1369 }
1370 else
1371 {
1372 v *= beta;
1373 }
1374
1375 D( i, l ) *= std::exp( v );
1376 Zt += D( i, l );
1377 }
1378 }
1379 }
1380
1381 for( size_type i = 0 ; i < D.size( ) ; i++ )
1382 {
1383 D[ i ] /= Zt;
1384 }
1385
1386 if( ( ( t + 1 ) % 5 ) == 0 )
1387 {
1388 double __classification_error__ = error_rate( features );
1389
1390 #if defined( __DEBUG_OUTPUT_LEVEL__ ) && __DEBUG_OUTPUT_LEVEL__ >= 1
1391 // 1ループ終了
1392 std::cout << "識別器の学習ループ " << t + 1 << " / " << number_of_iterations << " が終了しました。";
1393 std::cout << "分類誤差: " << __classification_error__ << std::endl;
1394 #endif
1395
1396 if( __classification_error__ == 0.0 )
1397 {
1398 // 分類器の性能に変化が無かった，もしくは，すべて分類できたので終了する
1399 break;
1400 }
1401 }
1402 }
1403
1404 return( true );
1405 }
1406
1407 public:
1414 template < class FEATURE >
1415 const std::string operator ()( const FEATURE &f ) const
1416 {
1417 return( evaluate( f ) );
1418 }
1419
1426 template < class FEATURE >
1427 const std::string evaluate( const FEATURE &f ) const
1428 {
1429 #if 1
1430 std::vector< double > values( categories_.size( ), 0.0 );
1431 for( size_type t = 0 ; t < weak_classifiers_.size( ) ; t++ )
1432 {
1433 const std::vector< bool > &code = code_word_[ t ];
1434 double weight = weak_classifiers_[ t ]( f ) ? alpha_[ t ] : beta_[ t ];
1435
1436 for( size_type l = 0 ; l < categories_.size( ) ; l++ )
1437 {
1438 values[ l ] += code[ l ] * weight;
1439 }
1440 }
1441
1442 size_type category = 0;
1443 for( size_type l = 1 ; l < categories_.size( ) ; l++ )
1444 {
1445 if( values[ category ] < values[ l ] )
1446 {
1447 category = l;
1448 }
1449 }
1450 #else
1451 double max = 0.0;
1452 size_type category = 0;
1453 for( size_type l = 0 ; l < categories_.size( ) ; l++ )
1454 {
1455 double sum = 0.0;
1456 for( size_type t = 0 ; t < weak_classifiers_.size( ) ; t++ )
1457 {
1458 double val = code_word_[ t ][ l ];
1459 if( weak_classifiers_[ t ]( f ) )
1460 {
1461 val *= alpha_[ t ];
1462 }
1463 else
1464 {
1465 val *= beta_[ t ];
1466 }
1467
1468 sum += val;
1469 }
1470
1471 if( sum > max )
1472 {
1473 max = sum;
1474 category = l;
1475 }
1476 }
1477 #endif
1478
1479 return( categories_[ category ] );
1480 }
1481
1487 template < class FEATURE >
1488 void compute_category_ranks( const FEATURE &f, std::vector< pair< double, std::string > > &ranks ) const
1489 {
1490 std::vector< double > values( categories_.size( ), 0.0 );
1491 for( size_type t = 0 ; t < weak_classifiers_.size( ) ; t++ )
1492 {
1493 const std::vector< bool > &code = code_word_[ t ];
1494 double weight = weak_classifiers_[ t ]( f ) ? alpha_[ t ] : beta_[ t ];
1495
1496 for( size_type l = 0 ; l < categories_.size( ) ; l++ )
1497 {
1498 values[ l ] += code[ l ] * weight;
1499 }
1500 }
1501
1502 ranks.clear( );
1503 ranks.reserve( values.size( ) );
1504
1505 for( size_type l = 0 ; l < values.size( ) ; l++ )
1506 {
1507 ranks.push_back( pair< double, std::string >( values[ l ], categories_[ l ] ) );
1508 }
1509
1510 std::sort( ranks.begin( ), ranks.end( ), pair< double, std::string >::greater );
1511 }
1512
1519 template < template < typename, typename > class FEATURE_LIST, class Allocator >
1520 double error_rate( const FEATURE_LIST< feature_type, Allocator > & features ) const
1521 {
1522 if( features.empty( ) )
1523 {
1524 return( 0.0 );
1525 }
1526
1527 size_type error = 0;
1528 int nfeatures = static_cast< int >( features.size( ) );
1529
1530 #pragma omp parallel for firstprivate( nfeatures ) reduction( +: error ) schedule( guided )
1531 for( int i = 0 ; i < nfeatures ; i++ )
1532 {
1533 const feature_type &f = features[ i ];
1534 if( f.valid )
1535 {
1536 std::string ret = evaluate( f );
1537 #if defined( __DEBUG_OUTPUT_LEVEL__ ) && __DEBUG_OUTPUT_LEVEL__ >= 3
1538 std::cout << ret;
1539 #endif
1540 if( f.category != ret )
1541 {
1542 error++;
1543 }
1544 }
1545 }
1546
1547 #if defined( __DEBUG_OUTPUT_LEVEL__ ) && __DEBUG_OUTPUT_LEVEL__ >= 3
1548 std::cout << std::endl;
1549 #endif
1550
1551 return( static_cast< double >( error ) / static_cast< double >( nfeatures ) );
1552 }
1553
1554 public:
1555 static const char *get_value( const char *s, const char *e, std::string &val )
1556 {
1557 // 先頭の空白（改行やタブを含む）を飛ばす
1558 while( s < e )
1559 {
1560 if( s[ 0 ] == '\r' )
1561 {
1562 if( s + 1 != e && s[ 1 ] == '\n' )
1563 {
1564 s = s + 2;
1565 }
1566 else
1567 {
1568 s++;
1569 }
1570 }
1571 else if( s[ 0 ] == '\n' )
1572 {
1573 s++;
1574 }
1575 else if( s[ 0 ] == ' ' || s[ 0 ] == '\t' )
1576 {
1577 s++;
1578 }
1579 else
1580 {
1581 break;
1582 }
1583 }
1584
1585 const char *sp = s;
1586 const char *ep = sp;
1587
1588 // 次にコンマが来る前まで進める
1589 while( s < e )
1590 {
1591 if( s[ 0 ] == '\r' )
1592 {
1593 if( s + 1 != e && s[ 1 ] == '\n' )
1594 {
1595 s = s + 2;
1596 }
1597 else
1598 {
1599 s++;
1600 }
1601 break;
1602 }
1603 else if( s[ 0 ] == '\n' )
1604 {
1605 s++;
1606 break;
1607 }
1608 else if( s[ 0 ] == ',' )
1609 {
1610 s++;
1611 break;
1612 }
1613
1614 ep++;
1615 s++;
1616 }
1617
1618 if( sp < ep )
1619 {
1620 val = std::string( sp, ep );
1621 }
1622
1623 return( s > e ? e : s );
1624 }
1625
1626 public:
1635 bool save( const std::string &filename ) const
1636 {
1637 FILE *fp = fopen( filename.c_str( ), "wt" );
1638
1639 if( fp == NULL )
1640 {
1641 return( false );
1642 }
1643
1644 // クラス数等の基本情報を書き込む
1645 fprintf( fp, "Category = %ld\n", categories_.size( ) );
1646 fprintf( fp, "Stage = %ld\n", weak_classifiers_.size( ) );
1647
1648 // クラス名を列挙する
1649 for( size_type i = 0 ; i < categories_.size( ) ; i++ )
1650 {
1651 fprintf( fp, "Class[%ld] : %s\n", i + 1, categories_[ i ].c_str( ) );
1652 }
1653
1654 // Code Word を列挙する
1655 for( size_type i = 0 ; i < code_word_.size( ) ; i++ )
1656 {
1657 const std::vector< bool > &code = code_word_[ i ];
1658 fprintf( fp, "%d", code[ 0 ] ? 1: 0 );
1659 for( size_type l = 1 ; l < code.size( ) ; l++ )
1660 {
1661 fprintf( fp, ",%d", code[ l ] ? 1: 0 );
1662 }
1663 fprintf( fp, "\n" );
1664 }
1665
1666 // 弱識別器と Alpha と Beta を列挙する
1667 for( size_type i = 0 ; i < weak_classifiers_.size( ) ; i++ )
1668 {
1669 const weak_classifier_type &weak = weak_classifiers_[ i ];
1670 fprintf( fp, "%s\n", weak.serialize( ).c_str( ) );
1671 fprintf( fp, "%f,%f\n", alpha_[ i ], beta_[ i ] );
1672 }
1673
1674 fclose( fp );
1675
1676 return( true );
1677 }
1678
1687 bool load( const std::string &filename )
1688 {
1689 FILE *fp = fopen( filename.c_str( ), "rt" );
1690
1691 if( fp == NULL )
1692 {
1693 return( false );
1694 }
1695
1696 int numClasses = 0, numStages = 0, dmy;
1697 char line[ 4096 ], buff[ 4096 ];
1698
1699 // クラス数等の基本情報を書き込む
1700 if( fgets( line, 4096, fp ) != NULL )
1701 {
1702 sscanf( line, "Category = %d", &numClasses );
1703 }
1704 if( fgets( line, 4096, fp ) != NULL )
1705 {
1706 sscanf( line, "Stage = %d", &numStages );
1707 }
1708
1709 // 強識別器を初期化する
1710 weak_classifiers_.resize( numStages );
1711 alpha_.resize( numStages );
1712 beta_.resize( numStages );
1713 code_word_.resize( numStages );
1714 categories_.resize( numClasses );
1715
1716 // クラス名を読み込む
1717 for( size_type i = 0 ; i < categories_.size( ) ; i++ )
1718 {
1719 if( fgets( line, 4096, fp ) != NULL )
1720 {
1721 memset( buff, '\0', 4096 );
1722 sscanf( line, "Class[%d] : %s", &dmy, buff );
1723 categories_[ i ] = buff;
1724 }
1725 }
1726
1727 // Code Word を読み込む
1728 for( size_type i = 0 ; i < code_word_.size( ) ; i++ )
1729 {
1730 std::vector< bool > &code = code_word_[ i ];
1731 code.resize( numClasses );
1732
1733 if( fgets( line, 4096, fp ) == NULL )
1734 {
1735 break;
1736 }
1737
1738 const char *p = line, *ep = line + 4096;
1739
1740 for( size_type l = 0 ; l < code.size( ) ; l++ )
1741 {
1742 std::string val;
1743 p = get_value( p, ep, val );
1744 code[ l ] = val == "1" ? true : false;
1745 }
1746 }
1747
1748 // 弱識別器と Alpha と Beta を列挙する
1749 for( size_type i = 0 ; i < weak_classifiers_.size( ) ; i++ )
1750 {
1751 if( fgets( line, 4096, fp ) != NULL )
1752 {
1753 weak_classifiers_[ i ].deserialize( line );
1754 }
1755
1756 if( fgets( line, 4096, fp ) != NULL )
1757 {
1758 double alpha, beta;
1759 sscanf( line, "%lf,%lf", &alpha, &beta );
1760 alpha_[ i ] = alpha;
1761 beta_[ i ] = beta;
1762 }
1763 }
1764
1765 fclose( fp );
1766
1767 return( true );
1768 }
1769 };
1770 }
1771
1772
1774 // 機械学習グループの終わり
1775 }
1776
1777
1778 // mist名前空間の終わり
1779 _MIST_END
1780
1781
1782
1783 #endif // __INCLUDE_MACHINE_LEARNING__
1784