nnlayer.cpp

Go to the documentation of this file.
00001 
00005 #include <assert.h>
00006 #include <algorithm>
00007 #include <numeric>
00008 #include "random.h"
00009 #include "quickfun.h"
00010 #include "nnlayer.h"
00011 
00012 REGISTER_CREATOR(lemga::NNLayer);
00013 
00014 namespace lemga {
00015 
00016 NNLayer::NNLayer (UINT n_in, UINT n_unit)
00017     : LearnModel(n_in, n_unit), w_min(-1), w_max(1),
00018       w(n_unit*(n_in+1)), dw(n_unit*(n_in+1)), sig_der(n_unit)
00019 {
00020     quick_tanh_setup();
00021 }
00022 
00023 bool NNLayer::serialize (std::ostream& os, ver_list& vl) const {
00024     SERIALIZE_PARENT(LearnModel, os, vl, 1);
00025     if (!(os << w_min << ' ' << w_max << '\n')) return false;
00026     WVEC::const_iterator pw = w.begin();
00027     for (UINT i = 0; i < _n_out; ++i) {
00028         for (UINT j = 0; j <= _n_in; ++j, ++pw)
00029             if (!(os << *pw << ' ')) return false;
00030         os << '\n';
00031     }
00032     return true;
00033 }
00034 
00035 bool NNLayer::unserialize (std::istream& is, ver_list& vl, const id_t& d) {
00036     if (d != id() && d != empty_id) return false;
00037     UNSERIALIZE_PARENT(LearnModel, is, vl, 1, v);
00038 
00039     if (v == 0) // Take care of _n_in and _n_out
00040         if (!(is >> _n_in >> _n_out)) return false;
00041     if (!(is >> w_min >> w_max) || w_min >= w_max) return false;
00042 
00043     const UINT n_weights = _n_out * (_n_in+1);
00044     w.resize(n_weights);
00045     dw = WVEC(n_weights, 0);
00046     sig_der = DVEC(_n_out);
00047 
00048     for (UINT i = 0; i < n_weights; ++i)
00049         if (!(is >> w[i])) return false;
00050     return true;
00051 }
00052 
00053 void NNLayer::set_weight (const WVEC& wgt) {
00054     assert(wgt.size() == _n_out * (_n_in+1));
00055     w = wgt;
00056 }
00057 
00058 void NNLayer::clear_gradient () {
00059     std::fill(dw.begin(), dw.end(), 0);
00060 }
00061 
00062 void NNLayer::initialize () {
00063     for (WVEC::iterator pw = w.begin(); pw != w.end(); ++pw)
00064         *pw = w_min + randu() * (w_max-w_min);
00065     clear_gradient();
00066 }
00067 
00068 REAL NNLayer::sigmoid (REAL x) const {
00069     stored_sigmoid = quick_tanh(x);
00070     return stored_sigmoid;
00071 }
00072 
00073 REAL NNLayer::sigmoid_deriv (REAL x) const {
00074     assert(stored_sigmoid == quick_tanh(x));
00075     return (1 - stored_sigmoid*stored_sigmoid);
00076 }
00077 
00078 void NNLayer::feed_forward (const Input& x, Output& y) const {
00079     assert(x.size() == n_input());
00080     assert(y.size() == n_output());
00081 
00082     WVEC::const_iterator pw = w.begin();
00083     for (UINT i = 0; i < _n_out; ++i) {
00084         const REAL th = *pw;
00085         const REAL s = std::inner_product(x.begin(), x.end(), ++pw, th);
00086         pw += _n_in;
00087 
00088         y[i] = sigmoid(s);
00089         sig_der[i] = sigmoid_deriv(s);
00090     }
00091 }
00092 
00093 void NNLayer::back_propagate (const Input& x, const DVEC& dy, DVEC& dx) {
00094     assert(x.size() == n_input());
00095     assert(dy.size() == n_output());
00096     assert(dx.size() == n_input());
00097 
00098     std::fill(dx.begin(), dx.end(), 0);
00099 
00100     WVEC::const_iterator pw = w.begin();
00101     DVEC::iterator pdw = dw.begin();
00102     for (UINT i = 0; i < _n_out; ++i) {
00103         const REAL delta = dy[i] * sig_der[i];
00104         *pdw += delta; ++pdw; ++pw;
00105 
00106         DVEC::iterator pdx = dx.begin();
00107         Input::const_iterator px = x.begin();
00108         for (UINT j = _n_in; j; --j) {
00109             *pdw++ += delta * (*px++);
00110             *pdx++ += delta * (*pw++);
00111         }
00112     }
00113 }
00114 
00115 } // namespace lemga

Generated on Mon Jan 9 23:43:24 2006 for LEMGA by  doxygen 1.4.6