00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "neuralnet.h"
00021 #include "matrixlinker.h"
00022 #include "biasedcluster.h"
00023 #include "backpropagationalgo.h"
00024
00025 namespace farsa {
00026
00027 BackPropagationAlgo::BackPropagationAlgo( NeuralNet *n_n, UpdatableList up_order, double l_r )
00028 : LearningAlgorithm(n_n), learn_rate(l_r), update_order(up_order) {
00029 useMomentum = false;
00030 momentumv = 0.0f;
00031 neuralNetChanged();
00032 }
00033
00034 BackPropagationAlgo::BackPropagationAlgo()
00035 : LearningAlgorithm(), learn_rate(0.0) {
00036 useMomentum = false;
00037 momentumv = 0.0f;
00038 neuralNetChanged();
00039 }
00040
00041 BackPropagationAlgo::~BackPropagationAlgo( ) {
00042
00043 }
00044
00045 void BackPropagationAlgo::neuralNetChanged() {
00046 NeuralNet* net = neuralNet();
00047 if ( !net ) return;
00048
00049 mapIndex.clear();
00050 cluster_deltas_vec.clear();
00051
00052 Cluster *cluster_temp;
00053
00054 ClusterList outs = net->outputClusters();
00055 for( int i=0; i<(int)outs.size(); i++ ) {
00056 addCluster( outs[i], true );
00057 }
00058
00059 for( int i=0; i<(int)update_order.size(); i++ ) {
00060 cluster_temp = dynamic_cast<Cluster*>(update_order[i]);
00061 if ( cluster_temp ) {
00062 addCluster( cluster_temp, false );
00063 continue;
00064 }
00065 MatrixLinker* linker_temp = dynamic_cast<MatrixLinker*>(update_order[i]);
00066 if ( linker_temp ) {
00067 addLinker( linker_temp );
00068 }
00069 }
00070 }
00071
00072 void BackPropagationAlgo::setUpdateOrder( const UpdatableList& update_order ) {
00073 this->update_order = update_order;
00074 this->neuralNetChanged();
00075 }
00076
00077 void BackPropagationAlgo::setTeachingInput( Cluster* output, const DoubleVector& ti ) {
00078 if ( mapIndex.count( output ) == 0 ) {
00079 return;
00080 }
00081 int index = mapIndex[ output ];
00082 subtract( cluster_deltas_vec[index].deltas_outputs, output->outputs(), ti );
00083 return;
00084 }
00085
00086 DoubleVector BackPropagationAlgo::getError( Cluster* cl ) {
00087 if ( mapIndex.count( cl ) == 0 ) {
00088 qWarning() << "Cluster not present in BackPropagationAlgo";
00089 return DoubleVector();
00090 }
00091 int index = mapIndex[ cl ];
00092 return cluster_deltas_vec[index].deltas_outputs;
00093 }
00094
00095 void BackPropagationAlgo::enableMomentum() {
00096 for ( int i=0; i<cluster_deltas_vec.size(); ++i ) {
00097 for ( int j=0; j<cluster_deltas_vec[i].incoming_linkers_vec.size(); ++j ) {
00098
00099 cluster_deltas_vec[i].incoming_last_outputs[j].zeroing();
00100 cluster_deltas_vec[i].last_deltas_inputs.zeroing();
00101 }
00102 }
00103 useMomentum = true;
00104 }
00105
00106 void BackPropagationAlgo::propagDeltas() {
00107 DoubleVector diff_vec;
00108 for( int i=0; i<(int)cluster_deltas_vec.size(); i++ ) {
00109 cluster_deltas_vec[i].incoming_linkers_vec;
00110
00111 cluster_deltas_vec[i].deltas_inputs.copyValues( cluster_deltas_vec[i].deltas_outputs );
00112 Cluster* cl = cluster_deltas_vec[i].cluster;
00113 OutputFunction* func = cl->outFunction();
00114 diff_vec.resize( cluster_deltas_vec[i].deltas_inputs.size() );
00115 if ( func->derivate( cl->inputs(), cl->outputs(), diff_vec ) ) {
00116 cluster_deltas_vec[i].deltas_inputs *= diff_vec;
00117 }
00118
00119 for( int k=0; k<cluster_deltas_vec[i].incoming_linkers_vec.size( ); ++k ) {
00120 MatrixLinker* link = dynamic_cast<MatrixLinker*>(cluster_deltas_vec[i].incoming_linkers_vec[k]);
00121 if ( mapIndex.count(link->from()) == 0 ) {
00122
00123 continue;
00124 }
00125 int from_index = mapIndex[ link->from() ];
00126 amul( cluster_deltas_vec[from_index].deltas_outputs, link->matrix(), cluster_deltas_vec[i].deltas_inputs );
00127 }
00128 }
00129 return;
00130 }
00131
00132 void BackPropagationAlgo::learn() {
00133
00134 for ( int i=0; i<cluster_deltas_vec.size(); ++i ) {
00135 if ( cluster_deltas_vec[i].isOutput ) continue;
00136 cluster_deltas_vec[i].deltas_outputs.zeroing();
00137 }
00138
00139 propagDeltas();
00140
00141 for ( int i=0; i<cluster_deltas_vec.size(); ++i ) {
00142 if ( cluster_deltas_vec[i].cluster != NULL) {
00143 DoubleVector minus_ones( cluster_deltas_vec[i].cluster->outputs().size( ), -1.0f );
00144 deltarule( cluster_deltas_vec[i].cluster->biases(), -learn_rate, minus_ones, cluster_deltas_vec[i].deltas_inputs );
00145 }
00146
00147 for ( int j=0; j<cluster_deltas_vec[i].incoming_linkers_vec.size(); ++j ) {
00148 if ( cluster_deltas_vec[i].incoming_linkers_vec[j] != NULL ) {
00149 deltarule(
00150 cluster_deltas_vec[i].incoming_linkers_vec[j]->matrix(),
00151 -learn_rate,
00152 cluster_deltas_vec[i].incoming_linkers_vec[j]->from()->outputs(),
00153 cluster_deltas_vec[i].deltas_inputs
00154 );
00155 if ( !useMomentum ) continue;
00156
00157 deltarule(
00158 cluster_deltas_vec[i].incoming_linkers_vec[j]->matrix(),
00159 -learn_rate*momentumv,
00160 cluster_deltas_vec[i].incoming_last_outputs[j],
00161 cluster_deltas_vec[i].last_deltas_inputs
00162 );
00163
00164 cluster_deltas_vec[i].incoming_last_outputs[j].copyValues( cluster_deltas_vec[i].incoming_linkers_vec[j]->from()->outputs() );
00165 cluster_deltas_vec[i].last_deltas_inputs.copyValues( cluster_deltas_vec[i].deltas_inputs );
00166 }
00167 }
00168 }
00169 return;
00170 }
00171
00172 void BackPropagationAlgo::learn( const Pattern& pat ) {
00173
00174 ClusterList clins = neuralNet()->inputClusters();
00175 for( int i=0; i<clins.size(); i++ ) {
00176 clins[i]->inputs().copyValues( pat.inputsOf( clins[i] ) );
00177 }
00178
00179 neuralNet()->step();
00180
00181 ClusterList clout = neuralNet()->outputClusters();
00182 for( int i=0; i<clout.size(); i++ ) {
00183 setTeachingInput( clout[i], pat.outputsOf( clout[i] ) );
00184 }
00185 learn();
00186 }
00187
00188 double BackPropagationAlgo::calculateMSE( const Pattern& pat ) {
00189
00190 ClusterList clins = neuralNet()->inputClusters();
00191 for( int i=0; i<clins.size(); i++ ) {
00192 clins[i]->inputs().copyValues( pat.inputsOf( clins[i] ) );
00193 }
00194
00195 neuralNet()->step();
00196
00197 ClusterList clout = neuralNet()->outputClusters();
00198 double mseacc = 0.0;
00199 int dim = (int)clout.size();
00200 for( int i=0; i<dim; i++ ) {
00201 mseacc += mse( clout[i]->outputs(), pat.outputsOf( clout[i] ) );
00202 }
00203 return mseacc/dim;
00204 }
00205
00206 void BackPropagationAlgo::addCluster( Cluster* cl, bool isOut ) {
00207 if( mapIndex.count( cl ) == 0 ) {
00208 cluster_deltas temp;
00209 int size = cl->numNeurons();
00210 temp.cluster = dynamic_cast<BiasedCluster*>(cl);
00211 temp.isOutput = isOut;
00212 temp.deltas_outputs.resize( size );
00213 temp.deltas_inputs.resize( size );
00214 temp.last_deltas_inputs.resize( size );
00215 cluster_deltas_vec.push_back( temp );
00216 mapIndex[cl] = cluster_deltas_vec.size()-1;
00217 }
00218 }
00219
00220 void BackPropagationAlgo::addLinker( Linker* link ) {
00221 if ( mapIndex.count( link->to() ) == 0 ) {
00222 cluster_deltas temp;
00223 int size = link->to()->numNeurons();
00224 temp.cluster = dynamic_cast<BiasedCluster*>(link->to());
00225 temp.isOutput = false;
00226 temp.deltas_outputs.resize( size );
00227 temp.deltas_inputs.resize( size );
00228 temp.last_deltas_inputs.resize( size );
00229 temp.incoming_linkers_vec.push_back( dynamic_cast<MatrixLinker*>(link) );
00230 temp.incoming_last_outputs.push_back( DoubleVector( link->from()->numNeurons() ) );
00231 cluster_deltas_vec.push_back( temp );
00232 mapIndex[temp.cluster] = cluster_deltas_vec.size()-1;
00233 }
00234 else {
00235 int tmp = mapIndex[link->to()];
00236 cluster_deltas_vec[ tmp ].incoming_linkers_vec.push_back( dynamic_cast<MatrixLinker*>(link) );
00237 cluster_deltas_vec[ tmp ].incoming_last_outputs.push_back( DoubleVector( link->from()->numNeurons() ) );
00238 }
00239 }
00240
00241 void BackPropagationAlgo::configure(ConfigurationParameters& params, QString prefix) {
00242 params.startRememberingGroupObjectAssociations();
00243 learn_rate = params.getValue( prefix + "rate" ).toDouble();
00244 momentumv = params.getValue( prefix + "momentum" ).toDouble();
00245 if ( momentumv == 0.0 ) {
00246 useMomentum = false;
00247 } else {
00248 useMomentum = true;
00249 }
00250 QString str = params.getValue( prefix + "order" );
00251 update_order.clear();
00252 if ( !str.isEmpty() ) {
00253 QStringList list = str.split(QRegExp("\\s+"), QString::SkipEmptyParts);
00254 foreach( QString upl, list ) {
00255 Updatable* up = params.getObjectFromGroup<Updatable>( upl, true );
00256 update_order << up;
00257 }
00258 }
00259 NeuralNet* net = params.getObjectFromParameter<NeuralNet>( prefix+"neuralnet", false, true );
00260 setNeuralNet( net );
00261 params.stopRememberingGroupObjectAssociations();
00262 }
00263
00264 void BackPropagationAlgo::save(ConfigurationParameters& params, QString prefix) {
00265 params.startObjectParameters(prefix, "BackPropagationAlgo", this);
00266 params.createParameter( prefix, "neuralnet", neuralNet() );
00267 params.createParameter( prefix, "rate", QString::number(learn_rate) );
00268 if ( useMomentum ) {
00269 params.createParameter( prefix, "momentum", QString::number(momentumv) );
00270 }
00271 QStringList list;
00272 foreach( Updatable* up, update_order ) {
00273 list << up->name();
00274 }
00275 params.createParameter( prefix, "order", list.join(" ") );
00276
00277 neuralNet()->save( params, neuralNet()->name() );
00278 }
00279
00280 void BackPropagationAlgo::describe( QString type ) {
00281 Descriptor d = addTypeDescription( type, "Backpropagation Learning Algorithm" );
00282 d.describeObject( "neuralnet" ).type( "NeuralNet" ).props( IsMandatory ).help( "The neural network to learn by backpropagation" );
00283 d.describeReal( "rate" ).limits( 0.0, 1.0 ).def( 0.2 ).help( "The learning rate" );
00284 d.describeReal( "momentum" ).limits( 0.0, 1.0 ).help( "The momentum rate; if zero momentum will be disabled" );
00285 }
00286
00287 }