///////////////////////////////////////////////////////////////////////////// // // GEM - Graphics Environment for Multimedia // // pix_linNN // // Implementation file // // Copyright (c) 2004 Georg Holzmann // (and of course lot's of other developers for PD and GEM) // // For information on usage and redistribution, and for a DISCLAIMER OF ALL // WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution. // ///////////////////////////////////////////////////////////////////////////// #include "pix_linNN.h" CPPEXTERN_NEW_WITH_TWO_ARGS(pix_linNN, t_floatarg, A_DEFFLOAT, t_floatarg, A_DEFFLOAT) //---------------------------------------------------------- /* Constructor */ pix_linNN::pix_linNN(t_floatarg arg0=64, t_floatarg arg1=1) : m_data_(NULL), m_xsize_(0), m_ysize_(0), m_csize_(0), train_on_(false), net_(NULL) { // init args ????????????????????????????????? neuron_nr_=2048; //static_cast((arg0<0)?2:arg0); precision_=2; //static_cast((arg1<1)?1:arg1); //post("arg0: %d, arg1: %d",arg0,arg1); // generate the in- and outlet: out0_ = outlet_new(this->x_obj, &s_signal); inlet_new(this->x_obj, &this->x_obj->ob_pd, &s_signal, &s_signal); // set random seed: srand( (unsigned)time(NULL) ); // creates the nets net_ = new LinNeuralNet[neuron_nr_](3); if(!net_) { post("pix_linNN~: no memory for neural nets!"); return; } for(int i=0; ineuron_nr_) { post("pix_linNN~: neurons and buffersize are different! You MUST have the same neuron nr as the buffersize !!!"); post("neurons: %d, buffersize: %d", x->neuron_nr_, blocksize); return (w+5); } // some needed data long int pix_size = x->m_xsize_ * x->m_ysize_; int pix_blocksize = (blocksizem_xsize_ / nr; // x size of a slice in pixels float y_slice = x->m_ysize_ / nr; // x size of a slice in pixels int x_slice_int = static_cast( x_slice ); int y_slice_int = static_cast( y_slice ); // the number of slices on one axis (is the float nr // from above rounded up) int slice_nr = static_cast(nr) + 1; if (x->m_data_) { switch(x->m_format_) { case GL_RGBA: for(int n=0; n( (n % slice_nr) * x_slice ); int lu_pix_y = static_cast( static_cast(n / slice_nr) * y_slice ); //post("lu_pix: %d, %d", lu_pix_x, lu_pix_y); // now sum up all the pixels of one slice and then divide through the // number of pixels unsigned long int temp_data[3] = { 0, 0, 0 }; // the storage to sum the pixels t_float average_pix[3] = { 0, 0, 0 }; // the average of the pixels // only for optimization: int helper1 = x->m_xsize_ * x->m_csize_; int add_count = 0; for(int i=0; iprecision_) { for(int j=0; jprecision_) { // the way to access the pixels: (C=chRed, chBlue, ...) //data[Y * xsize * csize + X * csize + C] //post("current pixel: %d %d", // ((lu_pix_x+i)%x->m_xsize), ((lu_pix_y+j)%x->m_ysize) ); temp_data[0] += x->m_data_[ (lu_pix_y+j) * helper1 + (lu_pix_x+i) * x->m_csize_ + chRed ]; temp_data[1] += x->m_data_[ ((lu_pix_y+j)) * helper1 + ((lu_pix_x+i)) * x->m_csize_ + chGreen ]; temp_data[2] += x->m_data_[ ((lu_pix_y+j)%x->m_ysize_) * helper1 + ((lu_pix_x+i)%x->m_xsize_) * x->m_csize_ + chBlue ]; add_count++; } } average_pix[0] = temp_data[0] / add_count; average_pix[1] = temp_data[1] / add_count; average_pix[2] = temp_data[2] / add_count; // the calculation of the network: *out_signal = x->net_[n].calculateNet(average_pix); //post("%d: RGBav: %f %f %f, out_signal: %f", //n,average_pix[0],average_pix[1],average_pix[2],*out_signal); // learning: if(x->train_on_) x->net_[n].trainNet(average_pix, *out_signal, *in_signal); out_signal++; in_signal++; } break; default: post("RGB only for now"); } } else { pix_blocksize=blocksize; while (pix_blocksize--) *out_signal++=0; } x->train_on_=false; return (w+5); } //---------------------------------------------------------- /* DSP-Message */ void pix_linNN::dspMess(void *data, t_signal** sp) { dsp_add(perform, 4, data, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n); } //---------------------------------------------------------- /* saves the contents of the current net to file * (it saves the neuron_nr_, learning rate * IW-matrix and b1-vector of the net) */ void pix_linNN::saveNet(string filename) { // open and check outfile ofstream outfile; outfile.open(filename.c_str()); if(!outfile) { post("pix_linNN~: failed to open output-file!"); return; } // write XML-header outfile << "" << endl; // start-tag outfile << "" << endl; // neuron_nr_(=size) and learning rate outfile << "\t " << neuron_nr_ << " " << endl; outfile << "\t " << net_[0].getLearningRate() << " " << endl; // now the IW-matrix of the neural net outfile << "\t" << endl; for(int i=0; i" << endl; // and the b1-vector outfile << "\t" << endl << "\t\t"; for(int i=0; i" << endl; // end-tag outfile << "" << endl; outfile.close(); post("pix_linNN~: saved to output-file %s", filename.c_str()); return; } //---------------------------------------------------------- /* loads the parameters of the net from file * (it loads the neuron_nr_, learning rate * IW-matrix and b1-vector of the net) */ void pix_linNN::loadNet(string filename) { // temp variables float IW[3]; float b1, learnrate; ifstream infile; infile.open(filename.c_str()); if(!infile) { post("pix_linNN~: cannot open input-file!"); return; } post("pix_linNN~: loading input-file %s",filename.c_str()); int state = 0, IWcount = 0, b1count = 0; bool tag=false; string line, temp; while (getline(infile, line)) { istringstream instream(line); instream >> temp; // specify the tags //post("input: %s",temp.c_str()); if( temp == "" ) {state=1; } if( temp == "" ) {state=2; } if( temp == "" ) {state=3; } if( temp == "" ) {state=4; } if( !strncmp(temp.c_str(),"> temp; // if theres a tag, stream it bool go_on=false; while(!go_on) { // end of a line if(instream.eof() || !state) { go_on=true; break; } // if(state == 1) { instream >> neuron_nr_; if(!net_) { // creates new nets net_ = new LinNeuralNet[neuron_nr_](3); if(!net_) { post("pix_linNN~: no memory for neural nets!"); break; } } for(int i=0; i if(state == 2) { instream >> learnrate; for(int i=0; i if(state == 3) { instream >> IW[0]; instream >> IW[1]; instream >> IW[2]; if(IWcount if(state == 4) { for(int i=0; i> b1; net_[b1count++].setb1(b1); } go_on = false; break; } //else: go_on=false; break; } } infile.close(); return; } //---------------------------------------------------------- /* setup callback */ void pix_linNN::obj_setupCallback(t_class *classPtr) { class_addcreator((t_newmethod)_classpix_linNN, gensym("pix_linNN~"), A_NULL); class_addmethod(classPtr, (t_method)pix_linNN::setNeurons, gensym("neurons"), A_FLOAT, A_NULL); class_addmethod(classPtr, (t_method)pix_linNN::getNeurons, gensym("getneurons"), A_NULL); class_addmethod(classPtr, (t_method)pix_linNN::setPrecision, gensym("precision"), A_FLOAT, A_NULL); class_addmethod(classPtr, (t_method)pix_linNN::getPrecision, gensym("getprecision"), A_NULL); class_addmethod(classPtr, (t_method)pix_linNN::setTrainOn, gensym("train"), A_NULL); class_addmethod(classPtr, (t_method)pix_linNN::setLearnrate, gensym("learnrate"), A_FLOAT, A_NULL); class_addmethod(classPtr, (t_method)pix_linNN::getLearnrate, gensym("getlearnrate"), A_NULL); class_addmethod(classPtr, (t_method)pix_linNN::saveToFile, gensym("save"), A_SYMBOL, A_NULL); class_addmethod(classPtr, (t_method)pix_linNN::loadFromFile, gensym("load"), A_SYMBOL, A_NULL); class_addmethod(classPtr, (t_method)pix_linNN::dspMessCallback, gensym("dsp"), A_NULL); class_addmethod(classPtr, nullfn, gensym("signal"), A_NULL); } //---------------------------------------------------------- /* DSP callback */ void pix_linNN::dspMessCallback(void *data, t_signal** sp) { GetMyClass(data)->dspMess(data, sp); } //---------------------------------------------------------- /* sets the precision */ void pix_linNN::setPrecision(void *data, t_floatarg precision) { GetMyClass(data)->precision_ = (precision<1) ? 1 : static_cast(precision); } void pix_linNN::getPrecision(void *data) { post("pix_linNN~: precision: %d",GetMyClass(data)->precision_); } //---------------------------------------------------------- /* method to train the network */ void pix_linNN::setTrainOn(void *data) { GetMyClass(data)->train_on_ = true; } //---------------------------------------------------------- /* changes the number of neurons * (which should be the same as the audio buffer) * ATTENTION: a new IW-matrix and b1-vector will be initialized */ void pix_linNN::setNeurons(void *data, t_floatarg neurons) { GetMyClass(data)->neuron_nr_ = (neurons<1) ? 1 : static_cast(neurons); if(GetMyClass(data)->net_) delete[] GetMyClass(data)->net_; // creates the nets GetMyClass(data)->net_ = new LinNeuralNet[GetMyClass(data)->neuron_nr_](3); if(!GetMyClass(data)->net_) { post("pix_linNN~: no memory for neural nets!"); return; } for(int i=0; ineuron_nr_; i++) { if( !GetMyClass(data)->net_[i].createNeurons() ) { post("pix_linNN~: error in creating the net!"); return; } if( !GetMyClass(data)->net_[i].initNetworkRand(-1,1) ) { post("pix_linNN~: error in initializing the net!"); return; } } } void pix_linNN::getNeurons(void *data) { post("pix_linNN~: nr of neurons: %d (MUST be the same as buffersize!)", GetMyClass(data)->neuron_nr_); } //---------------------------------------------------------- /* sets the learnrate of the net */ void pix_linNN::setLearnrate(void *data, t_floatarg learn_rate) { for(int i=0; ineuron_nr_; i++) GetMyClass(data)->net_[i].setLearningRate(learn_rate); } void pix_linNN::getLearnrate(void *data) { post("pix_linNN~: learning rate: %f",GetMyClass(data)->net_[0].getLearningRate()); } //---------------------------------------------------------- /* FileIO-stuff */ void pix_linNN::saveToFile(void *data, t_symbol *filename) { GetMyClass(data)->saveNet(filename->s_name); } void pix_linNN::loadFromFile(void *data, t_symbol *filename) { GetMyClass(data)->loadNet(filename->s_name); }