1 // Copyright (C) 2012 Davis E. King (davis@dlib.net) 2 // License: Boost Software License See LICENSE.txt for the full license. 3 #ifndef DLIB_ACTIVE_LEARnING_Hh_ 4 #define DLIB_ACTIVE_LEARnING_Hh_ 5 6 #include "active_learning_abstract.h" 7 8 #include "svm_c_linear_dcd_trainer.h" 9 #include <vector> 10 11 namespace dlib 12 { 13 14 enum active_learning_mode 15 { 16 max_min_margin, 17 ratio_margin 18 }; 19 20 // ---------------------------------------------------------------------------------------- 21 22 template < 23 typename kernel_type, 24 typename in_sample_vector_type, 25 typename in_scalar_vector_type, 26 typename in_sample_vector_type2 27 > impl_rank_unlabeled_training_samples(const svm_c_linear_dcd_trainer<kernel_type> & trainer,const in_sample_vector_type & samples,const in_scalar_vector_type & labels,const in_sample_vector_type2 & unlabeled_samples,const active_learning_mode mode)28 std::vector<unsigned long> impl_rank_unlabeled_training_samples ( 29 const svm_c_linear_dcd_trainer<kernel_type>& trainer, 30 const in_sample_vector_type& samples, 31 const in_scalar_vector_type& labels, 32 const in_sample_vector_type2& unlabeled_samples, 33 const active_learning_mode mode 34 ) 35 { 36 DLIB_ASSERT(is_vector(unlabeled_samples) && 37 (samples.size() == 0 || is_learning_problem(samples, labels)) , 38 "\t std::vector<unsigned long> rank_unlabeled_training_samples()" 39 << "\n\t Invalid inputs were given to this function" 40 << "\n\t is_vector(unlabeled_samples): " << is_vector(unlabeled_samples) 41 << "\n\t is_learning_problem(samples, labels): " << is_learning_problem(samples, labels) 42 << "\n\t samples.size(): " << samples.size() 43 << "\n\t labels.size(): " << labels.size() 44 ); 45 46 // If there aren't any training samples then all unlabeled_samples are equally good. 47 // So just report an arbitrary ordering. 48 if (samples.size() == 0 || unlabeled_samples.size() == 0) 49 { 50 std::vector<unsigned long> ret(unlabeled_samples.size()); 51 for (unsigned long i = 0; i < ret.size(); ++i) 52 ret[i] = i; 53 54 return ret; 55 } 56 57 // We are going to score each unlabeled sample and put the score and index into 58 // results. Then at the end of this function we just sort it and return the indices. 59 std::vector<std::pair<double, unsigned long> > results; 60 results.resize(unlabeled_samples.size()); 61 62 // make sure we use this trainer's ability to warm start itself since that will make 63 // this whole function run a lot faster. But first, we need to find out what the state 64 // we will be warm starting from is. 65 typedef typename svm_c_linear_dcd_trainer<kernel_type>::optimizer_state optimizer_state; 66 optimizer_state state; 67 trainer.train(samples, labels, state); // call train() just to get state 68 69 decision_function<kernel_type> df; 70 71 std::vector<typename kernel_type::sample_type> temp_samples; 72 std::vector<typename kernel_type::scalar_type> temp_labels; 73 temp_samples.reserve(samples.size()+1); 74 temp_labels.reserve(labels.size()+1); 75 temp_samples.assign(samples.begin(), samples.end()); 76 temp_labels.assign(labels.begin(), labels.end()); 77 temp_samples.resize(temp_samples.size()+1); 78 temp_labels.resize(temp_labels.size()+1); 79 80 81 for (long i = 0; i < unlabeled_samples.size(); ++i) 82 { 83 temp_samples.back() = unlabeled_samples(i); 84 // figure out the margin for each possible labeling of this sample. 85 86 optimizer_state temp(state); 87 temp_labels.back() = +1; 88 df = trainer.train(temp_samples, temp_labels, temp); 89 const double margin_p = temp_labels.back()*df(temp_samples.back()); 90 91 temp = state; 92 temp_labels.back() = -1; 93 df = trainer.train(temp_samples, temp_labels, temp); 94 const double margin_n = temp_labels.back()*df(temp_samples.back()); 95 96 if (mode == max_min_margin) 97 { 98 // The score for this sample is its min possible margin over possible labels. 99 // Therefore, this score measures how much flexibility we have to label this 100 // sample however we want. The intuition being that the most useful points to 101 // label are the ones that are still free to obtain either label. 102 results[i] = std::make_pair(std::min(margin_p, margin_n), i); 103 } 104 else 105 { 106 // In this case, the score for the sample is a ratio that tells how close the 107 // two margin values are to each other. The closer they are the better. So in 108 // this case we are saying we are looking for samples that have the same 109 // preference for either class label. 110 if (std::abs(margin_p) >= std::abs(margin_n)) 111 { 112 if (margin_p != 0) 113 results[i] = std::make_pair(margin_n/margin_p, i); 114 else // if both are == 0 then say 0/0 == 1 115 results[i] = std::make_pair(1, i); 116 } 117 else 118 { 119 results[i] = std::make_pair(margin_p/margin_n, i); 120 } 121 } 122 } 123 124 // sort the results so the highest scoring samples come first. 125 std::sort(results.rbegin(), results.rend()); 126 127 // transfer results into a vector with just sample indices so we can return it. 128 std::vector<unsigned long> ret(results.size()); 129 for (unsigned long i = 0; i < ret.size(); ++i) 130 ret[i] = results[i].second; 131 return ret; 132 } 133 134 // ---------------------------------------------------------------------------------------- 135 136 template < 137 typename kernel_type, 138 typename in_sample_vector_type, 139 typename in_scalar_vector_type, 140 typename in_sample_vector_type2 141 > 142 std::vector<unsigned long> rank_unlabeled_training_samples ( 143 const svm_c_linear_dcd_trainer<kernel_type>& trainer, 144 const in_sample_vector_type& samples, 145 const in_scalar_vector_type& labels, 146 const in_sample_vector_type2& unlabeled_samples, 147 const active_learning_mode mode = max_min_margin 148 ) 149 { 150 return impl_rank_unlabeled_training_samples(trainer, 151 mat(samples), 152 mat(labels), 153 mat(unlabeled_samples), 154 mode); 155 } 156 157 // ---------------------------------------------------------------------------------------- 158 159 } 160 161 #endif // DLIB_ACTIVE_LEARnING_Hh_ 162 163