bpn1.h

説明を見る。
00001 // -*-c++-*-
00002 
00008 /*
00009  *Copyright:
00010 
00011  Copyright (C) Hidehisa AKIYAMA
00012 
00013  This code is free software; you can redistribute it and/or
00014  modify it under the terms of the GNU Lesser General Public
00015  License as published by the Free Software Foundation; either
00016  version 2.1 of the License, or (at your option) any later version.
00017 
00018  This library is distributed in the hope that it will be useful,
00019  but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00021  Lesser General Public License for more details.
00022 
00023  You should have received a copy of the GNU Lesser General Public
00024  License along with this library; if not, write to the Free Software
00025  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00026 
00027  *EndCopyright:
00028  */
00029 
00031 
00032 #ifndef RCSC_ANN_BPN1_H
00033 #define RCSC_ANN_BPN1_H
00034 
00035 #include <boost/array.hpp>
00036 
00037 #include <algorithm>
00038 #include <numeric> // inner_product
00039 #include <iostream>
00040 #include <cmath>
00041 
00042 namespace rcsc {
00043 
00045 
00050 struct SigmoidFunc {
00056     double operator()( const double & x ) const
00057       {
00058           return 1.0 / ( 1.0 + std::exp( - x ) );
00059       }
00060 
00066     double inverse( const double & y ) const
00067       {
00068           return - std::log( 1.0 / y - 1.0 );
00069       }
00070 
00076     double diffAtX( const double & x ) const
00077       {
00078           double s = this->operator()( x );
00079           return s * ( 1.0 - s );
00080       }
00081 
00087     double diffAtY( const double & y ) const
00088       {
00089           // return diffAtX( inverse( y ) );
00090           return y * ( 1.0 - y );
00091       }
00092 };
00093 
00095 
00100 struct LinearFunc {
00106     double operator()( const double & x ) const
00107       {
00108           return x;
00109       }
00110 
00116     double inverse( const double & y ) const
00117       {
00118           return y;
00119       }
00120 
00125     double diffAtX( const double & ) const
00126       {
00127           return 1.0;
00128       }
00129 
00134     double diffAtY( const double & ) const
00135       {
00136           return 1.0;
00137       }
00138 
00139 };
00140 
00142 
00150 template < std::size_t INPUT,
00151            std::size_t HIDDEN,
00152            std::size_t OUTPUT,
00153            typename FuncH = SigmoidFunc,
00154            typename FuncO = SigmoidFunc >
00155 class BPNetwork1 {
00156 public:
00157     typedef double value_type; 
00158 
00160     typedef boost::array< value_type, INPUT > input_array;
00162     typedef boost::array< value_type, OUTPUT > output_array;
00163 
00164 private:
00165 
00167     const value_type M_eta;
00169     const value_type M_alpha;
00170 
00172     boost::array< value_type, INPUT + 1 > M_weight_i_to_h[HIDDEN];
00174     boost::array< value_type, INPUT + 1 > M_delta_weight_i_to_h[HIDDEN];
00175 
00177     boost::array< value_type, HIDDEN + 1 > M_weight_h_to_o[OUTPUT];
00179     boost::array< value_type, HIDDEN + 1 > M_delta_weight_h_to_o[OUTPUT];
00180 
00185     mutable boost::array< value_type, HIDDEN + 1 > M_hidden_layer;
00186 
00187 public:
00193     BPNetwork1()
00194         : M_eta( 0.3 )
00195         , M_alpha( 0.9 )
00196       {
00197           init();
00198       }
00199 
00205     BPNetwork1( const value_type & eta,
00206                 const value_type & alpha )
00207         : M_eta( eta )
00208         , M_alpha( alpha )
00209       {
00210           init();
00211       }
00212 
00219     template < typename RNG >
00220     BPNetwork1( const value_type & eta,
00221                 const value_type & alpha,
00222                 RNG & rng )
00223         : M_eta( eta )
00224         , M_alpha( alpha )
00225       {
00226           init();
00227           randomize( rng );
00228       }
00229 
00233     void init()
00234       {
00235           M_hidden_layer.assign( 0 );
00236           M_hidden_layer.back() = 1;
00237           for ( std::size_t i = 0; i < HIDDEN; ++i )
00238           {
00239               M_weight_i_to_h[i].assign( 0 );
00240               M_delta_weight_i_to_h[i].assign( 0 );
00241           }
00242           for ( std::size_t i = 0; i < OUTPUT; ++i )
00243           {
00244               M_weight_h_to_o[i].assign( 0 );
00245               M_delta_weight_h_to_o[i].assign( 0 );
00246           }
00247       }
00248 
00253     template < typename RNG >
00254     void randomize( RNG & rng )
00255       {
00256           for ( std::size_t i = 0; i < HIDDEN; ++i )
00257           {
00258               std::generate( M_weight_i_to_h[i].begin(),
00259                              M_weight_i_to_h[i].end(),
00260                              rng );
00261           }
00262           for ( std::size_t i = 0; i < OUTPUT; ++i )
00263           {
00264               std::generate( M_weight_h_to_o[i].begin(),
00265                              M_weight_h_to_o[i].end(),
00266                              rng );
00267           }
00268       }
00269 
00275     void propagate( const input_array & input,
00276                     output_array & output ) const
00277       {
00278           // Input to Hidden
00279           FuncH func_h;
00280           for ( std::size_t i = 0; i < HIDDEN; ++i )
00281           {
00282               value_type sum = std::inner_product( input.begin(),
00283                                                    input.end(),
00284                                                    M_weight_i_to_h[i].begin(),
00285                                                    static_cast< value_type >( 0 ) );
00286               // add bias
00287               sum += M_weight_i_to_h[i].back();
00288               M_hidden_layer[i] = func_h( sum );
00289           }
00290           // Hidden to Output
00291           FuncO func_o;
00292           for ( std::size_t i = 0; i < OUTPUT; ++i )
00293           {
00294               value_type sum = std::inner_product( M_hidden_layer.begin(),
00295                                                    M_hidden_layer.end(),
00296                                                    M_weight_h_to_o[i].begin(),
00297                                                    static_cast< value_type >( 0 ) );
00298               // bias is already added
00299               output[i] = func_o( sum );
00300           }
00301       }
00302 
00308     value_type train( const input_array & input,
00309                       const output_array & teacher )
00310       {
00311           output_array output;
00312           propagate( input, output );
00313 
00314           // error value mulitiplied by differential
00315           output_array output_back;
00316 
00317           // caluculate output error back
00318           FuncO func_o;
00319           for ( std::size_t i = 0; i < OUTPUT; ++i )
00320           {
00321               value_type err = teacher[i] - output[i];
00322               output_back[i] = err * func_o.diffAtY( output[i] );
00323           }
00324 
00325           // caluculate hidden layer error back
00326           boost::array< value_type, HIDDEN > hidden_back;
00327           FuncH func_h;
00328           for ( std::size_t i = 0; i < HIDDEN; ++i )
00329           {
00330               value_type sum = 0;
00331               for ( std::size_t j = 0; j < OUTPUT; ++j )
00332               {
00333                   sum += output_back[j] * M_weight_h_to_o[j][i];
00334               }
00335               hidden_back[i] = sum * func_h.diffAtY( M_hidden_layer[i] );
00336           }
00337 
00338           // update weights hidden to out
00339           for ( std::size_t i = 0; i < OUTPUT; ++i )
00340           {
00341               for ( std::size_t j = 0; j < HIDDEN + 1; ++j )
00342               {
00343                   M_delta_weight_h_to_o[i][j]
00344                       = M_eta * M_hidden_layer[j] * output_back[i]
00345                       + M_alpha * M_delta_weight_h_to_o[i][j];
00346                   M_weight_h_to_o[i][j]
00347                       += M_delta_weight_h_to_o[i][j];
00348                   //+= M_epsilon * ( M_hidden_layer[i] * output_back[j] );
00349               }
00350           }
00351 
00352           // update weights input to hidden
00353           for ( std::size_t i = 0; i < HIDDEN; ++i )
00354           {
00355               for ( std::size_t j = 0; j < INPUT; ++j )
00356               {
00357                   M_delta_weight_i_to_h[i][j]
00358                       = M_eta * input[j] * hidden_back[i]
00359                       + M_alpha * M_delta_weight_i_to_h[i][j];
00360                   M_weight_i_to_h[i][j]
00361                       += M_delta_weight_i_to_h[i][j];
00362                   //+= M_epsilon * ( input[j] * hidden_back[i] );
00363               }
00364           }
00365           // update input layer bias
00366           for ( std::size_t i = 0; i < HIDDEN; ++i )
00367           {
00368               M_delta_weight_i_to_h[i][INPUT]
00369                   = M_eta * 1.0 * hidden_back[i]
00370                   + M_alpha * M_delta_weight_i_to_h[i][INPUT];
00371               M_weight_i_to_h[i][INPUT]
00372                   += M_delta_weight_i_to_h[i][INPUT];
00373               //+= M_epsilon * ( input[j] * hidden_back[i] );
00374           }
00375 
00376           // calcluate error after training
00377           value_type total_error = 0;
00378           propagate( input, output );
00379           for ( std::size_t i = 0; i < OUTPUT; ++i )
00380           {
00381               total_error += std::pow( teacher[i] - output[i], 2.0 );
00382           }
00383           //std::cout << "  error = " << total_error << std::endl;
00384           return total_error;
00385       }
00386 
00387 
00389     // stream I/O
00390 
00396     bool read( std::istream & is )
00397       {
00398           for ( std::size_t i = 0; i < HIDDEN; ++i )
00399           {
00400               for ( std::size_t j = 0; j < INPUT + 1; ++j )
00401               {
00402                   if ( ! is.good() ) return false;
00403                   is >> M_weight_i_to_h[i][j];
00404               }
00405           }
00406           for ( std::size_t i = 0; i < OUTPUT; ++i )
00407           {
00408               for ( std::size_t j = 0; j < HIDDEN + 1; ++ j )
00409               {
00410                   if ( ! is.good() ) return false;
00411                   is >> M_weight_h_to_o[i][j];
00412               }
00413           }
00414           return true;
00415       }
00416 
00422     std::ostream & print( std::ostream & os ) const
00423       {
00424           for ( std::size_t i = 0; i < HIDDEN; ++i )
00425           {
00426               std::copy( M_weight_i_to_h[i].begin(),
00427                          M_weight_i_to_h[i].end(),
00428                          std::ostream_iterator< value_type >( os, " " ) );
00429           }
00430           for ( std::size_t i = 0; i < OUTPUT; ++i )
00431           {
00432               std::copy( M_weight_h_to_o[i].begin(),
00433                          M_weight_h_to_o[i].end(),
00434                          std::ostream_iterator< value_type >( os, " " ) );
00435           }
00436           return os;
00437       }
00438 };
00439 
00440 }
00441 
00442 #endif

librcscに対してThu May 1 15:41:20 2008に生成されました。  doxygen 1.5.0