#include //#include #include #include "Nnet.h" #include "CRBEDctFeat.h" #include "BlockArray.h" namespace TNet { void Network::Feedforward(const Matrix& in, Matrix& out, size_t start_frm_ext, size_t end_frm_ext) { //empty network: copy input to output if(mNnet.size() == 0) { if(out.Rows() != in.Rows() || out.Cols() != in.Cols()) { out.Init(in.Rows(),in.Cols()); } out.Copy(in); return; } //short input: propagate in one block if(in.Rows() < 5000) { Propagate(in,out); } else {//long input: propagate per parts //initialize out.Init(in.Rows(),GetNOutputs()); Matrix tmp_in, tmp_out; int done=0, block=1024; //propagate first part tmp_in.Init(block+end_frm_ext,in.Cols()); tmp_in.Copy(in.Range(0,block+end_frm_ext,0,in.Cols())); Propagate(tmp_in,tmp_out); out.Range(0,block,0,tmp_out.Cols()).Copy( tmp_out.Range(0,block,0,tmp_out.Cols()) ); done += block; //propagate middle parts while((done+2*block) < in.Rows()) { tmp_in.Init(block+start_frm_ext+end_frm_ext,in.Cols()); tmp_in.Copy(in.Range(done-start_frm_ext, block+start_frm_ext+end_frm_ext, 0,in.Cols())); Propagate(tmp_in,tmp_out); out.Range(done,block,0,tmp_out.Cols()).Copy( tmp_out.Range(start_frm_ext,block,0,tmp_out.Cols()) ); done += block; } //propagate last part tmp_in.Init(in.Rows()-done+start_frm_ext,in.Cols()); tmp_in.Copy(in.Range(done-start_frm_ext,in.Rows()-done+start_frm_ext,0,in.Cols())); Propagate(tmp_in,tmp_out); out.Range(done,out.Rows()-done,0,out.Cols()).Copy( tmp_out.Range(start_frm_ext,tmp_out.Rows()-start_frm_ext,0,tmp_out.Cols()) ); done += tmp_out.Rows()-start_frm_ext; assert(done == out.Rows()); } } void Network::Propagate(const Matrix& in, Matrix& out) { //empty network: copy input to output if(mNnet.size() == 0) { if(out.Rows() != in.Rows() || out.Cols() != in.Cols()) { out.Init(in.Rows(),in.Cols()); } out.Copy(in); return; } //this will keep pointer to matrix 'in', for backprop mNnet.front()->SetInput(in); //propagate LayeredType::iterator it; for(it=mNnet.begin(); it!=mNnet.end(); ++it) { (*it)->Propagate(); } //copy the output matrix const Matrix& mat = mNnet.back()->GetOutput(); if(out.Rows() != mat.Rows() || out.Cols() != mat.Cols()) { out.Init(mat.Rows(),mat.Cols()); } out.Copy(mat); } void Network::Backpropagate(const Matrix& globerr) { //pass matrix to last component mNnet.back()->SetErrorInput(globerr); // back-propagation : reversed order, LayeredType::reverse_iterator it; for(it=mNnet.rbegin(); it!=mNnet.rend(); ++it) { //first component does not backpropagate error (no predecessors) if(*it != mNnet.front()) { (*it)->Backpropagate(); } //compute gradient if updatable component if((*it)->IsUpdatable()) { UpdatableComponent& comp = dynamic_cast(**it); comp.Gradient(); //compute gradient } } } void Network::AccuGradient(const Network& src, int thr, int thrN) { LayeredType::iterator it; LayeredType::const_iterator it2; for(it=mNnet.begin(), it2=src.mNnet.begin(); it!=mNnet.end(); ++it,++it2) { if((*it)->IsUpdatable()) { UpdatableComponent& comp = dynamic_cast(**it); const UpdatableComponent& comp2 = dynamic_cast(**it2); comp.AccuGradient(comp2,thr,thrN); } } } void Network::Update(int thr, int thrN) { LayeredType::iterator it; for(it=mNnet.begin(); it!=mNnet.end(); ++it) { if((*it)->IsUpdatable()) { UpdatableComponent& comp = dynamic_cast(**it); comp.Update(thr,thrN); } } } Network* Network::Clone() { Network* net = new Network; LayeredType::iterator it; for(it = mNnet.begin(); it != mNnet.end(); ++it) { //clone net->mNnet.push_back((*it)->Clone()); //connect network if(net->mNnet.size() > 1) { Component* last = *(net->mNnet.end()-1); Component* prev = *(net->mNnet.end()-2); last->SetInput(prev->GetOutput()); prev->SetErrorInput(last->GetErrorOutput()); } } //copy the learning rate //net->SetLearnRate(GetLearnRate()); return net; } void Network::ReadNetwork(const char* pSrc) { std::ifstream in(pSrc); if(!in.good()) { Error(std::string("Error, cannot read model: ")+pSrc); } ReadNetwork(in); in.close(); } void Network::ReadNetwork(std::istream& rIn) { //get the network elements from a factory Component *pComp; while(NULL != (pComp = ComponentFactory(rIn))) mNnet.push_back(pComp); } void Network::WriteNetwork(const char* pDst) { std::ofstream out(pDst); if(!out.good()) { Error(std::string("Error, cannot write model: ")+pDst); } WriteNetwork(out); out.close(); } void Network::WriteNetwork(std::ostream& rOut) { //dump all the componetns LayeredType::iterator it; for(it=mNnet.begin(); it!=mNnet.end(); ++it) { ComponentDumper(rOut, **it); } } Component* Network:: ComponentFactory(std::istream& rIn) { rIn >> std::ws; if(rIn.eof()) return NULL; Component* pRet=NULL; Component* pPred=NULL; std::string componentTag; size_t nInputs, nOutputs; rIn >> std::ws; rIn >> componentTag; if(componentTag == "") return NULL; //nothing left in the file //make it lowercase std::transform(componentTag.begin(), componentTag.end(), componentTag.begin(), tolower); //the 'endblock' tag terminates the network if(componentTag == "") return NULL; if(componentTag[0] != '<' || componentTag[componentTag.size()-1] != '>') { Error(std::string("Invalid component tag:")+componentTag); } rIn >> std::ws; rIn >> nOutputs; rIn >> std::ws; rIn >> nInputs; assert(nInputs > 0 && nOutputs > 0); //make coupling with predecessor if(mNnet.size() == 0) { pPred = NULL; } else { pPred = mNnet.back(); } //array with list of component tags static const std::string TAGS[] = { "", "", "", "", "", "", "", "", "", "", "", "", "", }; static const int n_tags = sizeof(TAGS) / sizeof(TAGS[0]); int i = 0; for(i=0; iReadFromStream(rIn); //return return pRet; } void Network:: ComponentDumper(std::ostream& rOut, Component& rComp) { //use tags of all the components; or the identification codes //array with list of component tags static const Component::ComponentType TYPES[] = { Component::BIASED_LINEARITY, Component::SHARED_LINEARITY, Component::SIGMOID, Component::SOFTMAX, Component::BLOCK_SOFTMAX, Component::EXPAND, Component::COPY, Component::TRANSPOSE, Component::BLOCK_LINEARITY, Component::BIAS, Component::WINDOW, Component::LOG, Component::BLOCK_ARRAY, }; static const std::string TAGS[] = { "", "", "", "", "", "", "", "", "", "", "", "", "", }; static const int MAX = sizeof TYPES / sizeof TYPES[0]; int i; for(i=0; i