#include #include #include #include #include #include #include #include #include #include #include using N=knp::neuron_traits::neuron_parameters; using P=knp::core::Population; using R=knp::core::Projection; namespace fs=std::filesystem; templatestd::vector read(std::ifstream&f,size_t n){std::vectora(n);f.read(reinterpret_cast(a.data()),n*sizeof(T));if(!f)throw std::runtime_error("Truncated model/data");return a;} void progress(const fs::path&dir,int cur,int total,bool done=false,bool failed=false){std::ofstream f(dir/"progress.json.tmp");f<<"{\"current\":"<64||total<1||first<0)throw std::runtime_error("Invalid range"); std::vectorids(total);std::iota(ids.begin(),ids.end(),first);if(std::string(argv[7])!="-"){std::ifstream f(argv[7]);for(auto&i:ids)if(!(f>>i))throw std::runtime_error("Missing id");} std::ifstream mf(root/"model.bin",std::ios::binary);auto hdr=read(mf,8);int pix=hdr[0],hidden=hdr[1],classes=hdr[2],groups=hdr[3],active=hdr[4],hthr=hdr[5],othr=hdr[6],clock=hdr[7],outs=2*groups*classes; if(pix!=784||hidden!=256||classes!=10||groups!=8||clock>255)throw std::runtime_error("Unsupported model dimensions"); auto w1=read(mf,pix*hidden),b1=read(mf,hidden),w2=read(mf,hidden*classes),b2=read(mf,classes); std::ifstream imf(root/"images.bin",std::ios::binary),lf(root/"labels.bin",std::ios::binary);auto labels=read(lf,70000);std::vectorimages(total*pix); for(int i=0;i=70000)throw std::runtime_error("image id out of bounds");imf.seekg(size_t(ids[i])*pix);imf.read(reinterpret_cast(images.data()+i*pix),pix);if(!imf)throw std::runtime_error("Truncated pixels");} auto make=[&](int thr){N n;n.activation_threshold_=thr;n.negative_activation_threshold_=0;n.is_diff_=true;n.is_reset_=false;n.saturate_=true;n.potential_leak_=0;return n;}; P hp([&](size_t){return make(hthr);},hidden*reps),op([&](size_t){return make(othr);},outs*reps);auto huid=hp.get_uid(),ouid=op.get_uid(); int hs=pix+clock+128,os=clock+128;std::vectorhin,oin,mid;hin.reserve(reps*(pix*hidden+128*hidden));oin.reserve(reps*128*outs);mid.reserve(reps*hidden*classes); auto add=[](auto&v,int pre,int post,int weight,bool inhibitory=false){if(!weight)return;if(std::abs(weight)>255)throw std::runtime_error("Weight outside native range");if(inhibitory)weight=-std::abs(weight);v.push_back(R::Synapse{{float(weight),1,knp::synapse_traits::OutputType::EXCITATORY},size_t(pre),size_t(post)});}; for(int r=0;r0?1:-1); for(int c=0;c<128;c++)add(hin,r*hs+pix+clock+c,r*hidden+h,255,true); for(int k=0;k=0?0:groups*classes)+(h/32)*classes+k;add(mid,r*hidden+h,r*outs+o,std::abs(w));} } for(int k=0;k=0?0:groups*classes)+k,1); for(int o=0;ohused(reps*hs),oused(reps*os);for(auto &z:hin)hused[std::get<1>(z)]=true;for(auto &z:oin)oused[std::get<1>(z)]=true; auto projection=[](knp::core::UID pre,knp::core::UID post,auto&vec){return R(pre,post,[&vec](size_t i)->std::optional{return vec[i];},vec.size());}; auto ih=projection(knp::core::UID{false},huid,hin),io=projection(knp::core::UID{false},ouid,oin),ho=projection(huid,ouid,mid);auto ihid=ih.get_uid(),ioid=io.get_uid(); knp::framework::Network net;net.add_population(std::move(hp));net.add_population(std::move(op));net.add_projection(std::move(ih));net.add_projection(std::move(io));net.add_projection(std::move(ho));knp::framework::Model model(std::move(net));knp::core::UID inch,incout,outch,outh;model.add_input_channel(inch,ihid);model.add_input_channel(incout,ioid);model.add_output_channel(outch,ouid);model.add_output_channel(outh,huid); std::shared_ptrbackend;knp::framework::BackendLoader loader; if(mode=="gm"){auto gm=knp::backends::altai::AltAIBackend::create();auto dev=gm->get_devices();bool selected=false;for(auto&d:dev)if(dynamic_cast(d.get())){std::cout<<"DEVICE "<get_name()<select_device(std::move(d));selected=true;break;}if(!selected)throw std::runtime_error("No official GoldenModel");backend=gm;} else backend=loader.load(mode=="cuda"?"/home/user/KNP/build/bin/libknp-altai-cuda-backend.so":"/home/user/KNP/build/bin/libknp-cpu-single-threaded-backend.so"); std::ofstream result(out/"predictions.csv"),hcfile(out/"hidden_counts.bin",std::ios::binary),ocfile(out/"output_counts.bin",std::ios::binary);if(!result||!hcfile||!ocfile)throw std::runtime_error("Cannot open outputs");result<<"row,image_id,label,prediction\n"; std::vectorhc(reps*hidden),oc(reps*outs);std::vectorraster(reps*pix);int batch=0,phase=0,tick=0,quiet=0;size_t last=size_t(-1);bool done=false;int correct=0;knp::framework::ModelExecutor*ep=nullptr; auto update=[&](size_t step){ if(last==step)return;last=step;bool any=false; if(step&&ep){for(auto&m:ep->get_loader().get_output_channel(outch).read_some_from_buffer(step-1,step-1))for(auto i:m.neuron_indexes_){if(i>=oc.size())throw std::runtime_error("Output index overflow");if(phase<=2){++oc[i];any=true;}} for(auto&m:ep->get_loader().get_output_channel(outh).read_some_from_buffer(step-1,step-1))for(auto i:m.neuron_indexes_)if(phase<=2){if(i>=hc.size())throw std::runtime_error("Hidden index overflow");++hc[i];} } if(step==0)return; if(phase==0){if(++tick>=active){phase=1;tick=0;}} else if(phase==1){phase=2;tick=0;quiet=0;} else if(phase==2){++tick;quiet=any?0:quiet+1;if(tick>10000)throw std::runtime_error("Output failed to drain");if(tick>=3&&quiet>=2){ int n=std::min(reps,total-batch);for(int r=0;rbs){bs=score;best=k;}} int ix=batch+r;result<(hc.data()),n*hidden*sizeof(int32_t));ocfile.write(reinterpret_cast(oc.data()),n*outs*sizeof(int32_t));result.flush();completed=batch+n;progress(out,completed,total);std::cout<<"BATCH "<=3){batch+=reps;if(batch>=total){done=true;return;}std::fill(hc.begin(),hc.end(),0);std::fill(oc.begin(),oc.end(),0);std::fill(raster.begin(),raster.end(),0);phase=0;tick=0;}} }; auto hidden_input=[&](size_t step){update(step);knp::core::messaging::SpikeData data;if(done)return data;int n=std::min(reps,total-batch);for(int r=0;r=255){v-=255;if(hused[r*hs+p])data.push_back(r*hs+p);}}for(int c=0;c(std::chrono::steady_clock::now()-start).count();std::ofstream summary(out/"summary.json");summary<<"{\"backend\":\""<