model.cpp (4539B)
1 #include <ctime> 2 #include <cstddef> 3 #include <string> 4 #include <stdexcept> 5 6 #include <boost/version.hpp> 7 #include <boost/shared_ptr.hpp> 8 #include <boost/make_shared.hpp> 9 #include <boost/random/linear_congruential.hpp> 10 #include <nmlp/Criterion.h> 11 #include <nmlp/Matrix.h> 12 #include <nmlp/Tensor.h> 13 14 #include "data_set.hpp" 15 #include "factory.hpp" 16 #include "model.hpp" 17 #include "view.hpp" 18 19 #if BOOST_VERSION < 104700 20 #define uniform_int_distribution uniform_int 21 #include <boost/random/uniform_int.hpp> 22 #else 23 #include <boost/random/uniform_int_distribution.hpp> 24 #endif 25 26 bool Model::add_view(boost::shared_ptr<View> v){ 27 if(views.count(v->kind)) 28 return false; 29 if(!views.empty() && views.begin()->second->concept_dimension!=v->concept_dimension) 30 throw std::runtime_error("Trying to aggregate views of different concept space dimensions in a single model."); 31 views.insert(std::make_pair(v->kind, v)); 32 return true; 33 } 34 35 void Model::stochastic_learn(Data_set const &data_set, std::size_t number_of_step, float gradient_step, std::string const &criterion){ 36 static boost::minstd_rand gen(std::time(0)); 37 boost::uniform_int_distribution<> view_dist(0, data_set.number_of_views()-1); 38 boost::uniform_int_distribution<> data_dist(0, data_set.size()-1); 39 40 std::vector<boost::shared_ptr<View> > view_vector(data_set.number_of_views()); 41 for(std::size_t i=0; i<data_set.number_of_views(); ++i){ 42 std::string kind=data_set.kind(i); 43 std::map<std::string, boost::shared_ptr<View> >::iterator it=views.find(kind); 44 if(it==views.end()) 45 throw std::runtime_error("Training a model with an unknown view."); 46 view_vector[i]=it->second; 47 } 48 49 std::vector<boost::shared_ptr<Criterion> > criteria(data_set.number_of_views()); 50 for(std::size_t i=0; i<data_set.number_of_views(); ++i) 51 criteria[i]=criterion_factory(criterion, view_vector[i]->view_dimension); 52 53 boost::shared_ptr<Tensor> input=boost::make_shared<Tensor>(1), output=boost::make_shared<Tensor>(1); 54 /// @todo Optimise 55 for(std::size_t step=0; step<number_of_step*data_set.size(); ++step){ 56 std::size_t element=data_dist(gen); 57 std::size_t from_id=view_dist(gen), to_id=view_dist(gen); 58 59 boost::shared_ptr<View> from=view_vector[from_id], to=view_vector[to_id]; 60 input->setMatrix(0, data_set.get(element, from_id)); 61 output->setMatrix(0, data_set.get(element, to_id)); 62 63 SequentialModule trainer; 64 trainer.addModule(from->encoder); 65 trainer.addModule(to->decoder); 66 trainer.init_gradient(); 67 trainer.forward(input); 68 criteria[to_id]->backward(trainer.getOutput(), output); 69 trainer.backward(input, criteria[to_id]->getDelta()); 70 trainer.updateParameters(gradient_step); 71 } 72 } 73 74 double Model::error(Data_set const &data_set, std::string const &criterion, std::size_t from_view, std::size_t to_view) const { 75 // nmlp is const-inconsistent 76 Model *ncthis=const_cast<Model*>(this); 77 78 std::vector<boost::shared_ptr<View> > view_vector(data_set.number_of_views()); 79 for(std::size_t i=0; i<data_set.number_of_views(); ++i){ 80 std::string kind=data_set.kind(i); 81 std::map<std::string, boost::shared_ptr<View> >::const_iterator it=views.find(kind); 82 if(it==views.end()) 83 throw std::runtime_error("Training a model with an unknown view."); 84 view_vector[i]=it->second; 85 } 86 87 std::vector<boost::shared_ptr<Criterion> > criteria(data_set.number_of_views()); 88 for(std::size_t i=0; i<data_set.number_of_views(); ++i) 89 criteria[i]=criterion_factory(criterion, view_vector[i]->view_dimension); 90 91 std::map<std::string, boost::shared_ptr<View> >::const_iterator it; 92 it=views.find(data_set.kind(from_view)); 93 if(it==views.end()) 94 throw std::runtime_error("Testing a model with an unknown view."); 95 boost::shared_ptr<View> from=it->second; 96 it=views.find(data_set.kind(to_view)); 97 if(it==views.end()) 98 throw std::runtime_error("Testing a model with an unknown view."); 99 boost::shared_ptr<View> to=it->second; 100 101 boost::shared_ptr<Tensor> input=boost::make_shared<Tensor>(data_set.get(from_view)); 102 boost::shared_ptr<Tensor> output=boost::make_shared<Tensor>(data_set.get(to_view)); 103 boost::shared_ptr<Criterion> criter=criterion_factory(criterion, to->view_dimension); 104 105 SequentialModule tester; 106 tester.addModule(from->encoder); 107 tester.addModule(to->decoder); 108 tester.init_gradient(); 109 tester.forward(input); 110 criter->computeValue(tester.getOutput(), output); 111 boost::shared_ptr<Tensor> diff=criter->getValue(); 112 113 float err=0; 114 for(int i=0; i<diff->getMatrix(0)->getNumberOfRows(); ++i) 115 err+=diff->getMatrix(0)->getValue(i,0); 116 err/=diff->getMatrix(0)->getNumberOfRows(); 117 118 return err; 119 } 120