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)
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 }