int GradientCheckConn::calc_dW() { assert(plasticityFlag); int status; //for(int arborId=0;arborId<numberOfAxonalArborLists();arborId++) { // status = initialize_dW(arborId); // if (status==PV_BREAK) { break; } // assert(status == PV_SUCCESS); //} for(int arborId=0;arborId<numberOfAxonalArborLists();arborId++) { status = update_dW(arborId); if (status==PV_BREAK) { break; } assert(status == PV_SUCCESS); } for(int arborId=0;arborId<numberOfAxonalArborLists();arborId++) { status = reduce_dW(arborId); if (status==PV_BREAK) { break; } assert(status == PV_SUCCESS); } for(int arborId=0;arborId<numberOfAxonalArborLists();arborId++) { status = normalize_dW(arborId); if (status==PV_BREAK) { break; } assert(status == PV_SUCCESS); } return PV_SUCCESS; }
int MomentumConn::calc_dW() { assert(plasticityFlag); int status; if(timeBatchIdx >= timeBatchPeriod){ timeBatchIdx = 0; } else{ timeBatchIdx++; } //Clear at time 0, update at time timeBatchPeriod - 1 bool need_update_w = false; bool need_clear_dw = false; if(timeBatchIdx == 0){ need_clear_dw = true; } if(timeBatchIdx == timeBatchPeriod - 1){ need_update_w = true; } for(int arborId=0;arborId<numberOfAxonalArborLists();arborId++) { //Clear every batch period if(need_clear_dw){ status = initialize_dW(arborId); if (status==PV_BREAK) { break; } assert(status == PV_SUCCESS); } } for(int arborId=0;arborId<numberOfAxonalArborLists();arborId++) { //Sum up parts every timestep status = update_dW(arborId); if (status==PV_BREAK) { break; } assert(status == PV_SUCCESS); } for(int arborId=0;arborId<numberOfAxonalArborLists();arborId++) { //Reduce only when we need to update if(need_update_w){ status = reduce_dW(arborId); if (status==PV_BREAK) { break; } assert(status == PV_SUCCESS); } } for(int arborId=0;arborId<numberOfAxonalArborLists();arborId++) { //Normalize only when reduced if(need_update_w){ status = normalize_dW(arborId); if (status==PV_BREAK) { break; } assert(status == PV_SUCCESS); } } return PV_SUCCESS; }
int MomentumConn::allocateDataStructures(){ HyPerConn::allocateDataStructures(); if (!plasticityFlag) return PV_SUCCESS; int sx = nfp; int sy = sx * nxp; int sp = sy * nyp; int nPatches = getNumDataPatches(); const int numAxons = numberOfAxonalArborLists(); //Allocate dw buffer for previous dw prev_dwDataStart = (pvwdata_t **) calloc(numAxons, sizeof(pvwdata_t *)); if( prev_dwDataStart == NULL ) { createArborsOutOfMemory(); assert(false); } prev_dwDataStart[0] = (pvwdata_t*) calloc(numAxons * nxp * nyp * nfp * nPatches, sizeof(pvwdata_t)); assert(prev_dwDataStart[0] != NULL); for (int arborId = 0; arborId < numAxons; arborId++) { prev_dwDataStart[arborId] = (prev_dwDataStart[0] + sp * nPatches * arborId); assert(prev_dwDataStart[arborId] != NULL); } // loop over arbors assert(clones.size() == 0); return PV_SUCCESS; }
int MomentumConn::updateWeights(int arborId){ if(timeBatchIdx != timeBatchPeriod - 1){ return PV_SUCCESS; } //Add momentum right before updateWeights for(int kArbor = 0; kArbor < this->numberOfAxonalArborLists(); kArbor++){ applyMomentum(arborId); } //Saved to prevweights assert(prev_dwDataStart); std::memcpy(*prev_dwDataStart, *get_dwDataStart(), sizeof(pvwdata_t) * numberOfAxonalArborLists() * nxp * nyp * nfp * getNumDataPatches()); // add dw to w for(int kArbor = 0; kArbor < this->numberOfAxonalArborLists(); kArbor++){ pvwdata_t * w_data_start = get_wDataStart(kArbor); for( long int k=0; k<patchStartIndex(getNumDataPatches()); k++ ) { w_data_start[k] += get_dwDataStart(kArbor)[k]; } } return PV_BREAK; }
int MomentumConn::checkpointRead(const char * cpDir, double * timeptr) { HyPerConn::checkpointRead(cpDir, timeptr); if (!plasticityFlag) return PV_SUCCESS; clearWeights(prev_dwDataStart, getNumDataPatches(), nxp, nyp, nfp); char * path = parent->pathInCheckpoint(cpDir, getName(), "_prev_dW.pvp"); PVPatch *** patches_arg = sharedWeights ? NULL : get_wPatches(); double filetime=0.0; int status = PV::readWeights(patches_arg, prev_dwDataStart, numberOfAxonalArborLists(), getNumDataPatches(), nxp, nyp, nfp, path, parent->icCommunicator(), &filetime, pre->getLayerLoc()); if (parent->columnId()==0 && timeptr && *timeptr != filetime) { fprintf(stderr, "Warning: \"%s\" checkpoint has timestamp %g instead of the expected value %g.\n", path, filetime, *timeptr); } free(path); return status; }
/** * First function to be executed * Updates the postsynaptic trace and calls the updateWeights function */ int STDP3Conn::updateState(double time, double dt) { update_timer->start(); int status=0; if (stdpFlag) { //const int axonId = 0; // assume only one for now for(int axonId = 0; axonId<numberOfAxonalArborLists(); axonId++) { status=updateWeights(axonId); } } update_timer->stop(); //const int axonId = 0; // assume only one for now //return updateWeights(axonId); return status; }
int VaryingHyPerConn::allocateDataStructures() { HyPerConn::allocateDataStructures(); // initialize all dW's to one. int syPatch = yPatchStride(); for(int kAxon = 0; kAxon < numberOfAxonalArborLists(); kAxon++){ for(int kPatch = 0; kPatch < getNumDataPatches(); kPatch++){ PVPatch * W = getWeights(kPatch, kAxon); int nkPatch = fPatchSize() * W->nx; float * dWdata = get_dwData(kAxon, kPatch); for(int kyPatch = 0; kyPatch < W->ny; kyPatch++){ for(int kPatch = 0; kPatch < nkPatch; kPatch++){ dWdata[kPatch] = 1.0f; } dWdata += syPatch; } } } return PV_SUCCESS; }
int MomentumConn::allocateDataStructures(){ int status = HyPerConn::allocateDataStructures(); if (status==PV_POSTPONE) { return status; } if (!plasticityFlag) return status; int sx = nfp; int sy = sx * nxp; int sp = sy * nyp; int nPatches = getNumDataPatches(); const int numAxons = numberOfAxonalArborLists(); //Allocate dw buffer for previous dw prev_dwDataStart = (pvwdata_t **) pvCalloc(numAxons, sizeof(pvwdata_t *)); prev_dwDataStart[0] = (pvwdata_t*) pvCalloc(numAxons * nxp * nyp * nfp * nPatches, sizeof(pvwdata_t)); for (int arborId = 0; arborId < numAxons; arborId++) { prev_dwDataStart[arborId] = (prev_dwDataStart[0] + sp * nPatches * arborId); assert(prev_dwDataStart[arborId] != NULL); } // loop over arbors //assert(clones.size() == 0); return PV_SUCCESS; }
int LCALIFLateralKernelConn::allocateDataStructures() { int status = HyPerConn::allocateDataStructures(); // Neurons don't inhibit themselves, only their neighbors; set self-interaction weights to mmzero. assert(nxp % 2 == 1 && nyp % 2 == 1 && getNumDataPatches()==nfp); for (int k=0; k<getNumDataPatches(); k++) { int n = kIndex((nxp-1)/2, (nyp-1)/2, k, nxp, nyp, nfp); get_wDataHead(0, k)[n] = 0.0f; } integratedSpikeCountCube = pvcube_new(pre->getLayerLoc(), pre->getNumExtended()); integratedSpikeCount = integratedSpikeCountCube->data; for (int k=0; k<pre->getNumExtended(); k++) { integratedSpikeCount[k] = integrationTimeConstant*getTargetRateKHz(); // Spike counts initialized to equilibrium value } mpi_datatype = Communicator::newDatatypes(pre->getLayerLoc()); if (mpi_datatype==NULL) { fprintf(stderr, "LCALIFLateralKernelConn \"%s\" error creating mpi_datatype\n", name); abort(); } // Compute the number of times each patch contributes to dw, for proper averaging. int num_arbors = numberOfAxonalArborLists(); interiorCounts = (float **) calloc(num_arbors, sizeof(float *)); if (interiorCounts==NULL) { fprintf(stderr, "LCALIFLateralKernelConn::initialize \"%s\" error: unable to allocate memory for interiorCounts pointer\n", name); } interiorCounts[0] = (float *) calloc(getNumDataPatches()*nxp*nyp*nfp, sizeof(float)); if (interiorCounts[0]==NULL) { fprintf(stderr, "LCALIFLateralKernelConn::initialize \"%s\" error: unable to allocate memory for interiorCounts\n", name); } for (int arbor=1; arbor<num_arbors; arbor++) { interiorCounts[arbor] = interiorCounts[0]+arbor*getNumDataPatches()*nxp*nyp*nfp; } const PVLayerLoc * preloc = pre->getLayerLoc(); int nxpre = preloc->nx; int nypre = preloc->ny; int nfpre = preloc->nf; int nExt = pre->getNumExtended(); int sya = getPostExtStrides()->sy; int nxglob = preloc->nxGlobal; int nyglob = preloc->nyGlobal; int kx0 = preloc->kx0; int ky0 = preloc->ky0; for (int arbor=0; arbor<numberOfAxonalArborLists(); arbor++) { for(int kExt=0; kExt<nExt;kExt++) { int xglob = kxPos(kExt, nxpre + preloc->halo.lt + preloc->halo.rt, nypre + preloc->halo.dn + preloc->halo.up, nfpre) + kx0 - preloc->halo.lt; int yglob = kyPos(kExt, nypre + preloc->halo.lt + preloc->halo.rt, nypre + preloc->halo.dn + preloc->halo.up, nfpre) + ky0 - preloc->halo.up; if (xglob < 0 || xglob >= nxglob || yglob < 0 || yglob >= nyglob) { continue; } PVPatch * weights = getWeights(kExt,arbor); int offset = (int) getAPostOffset(kExt, arbor); int ny = weights->ny; int nk = weights->nx * nfp; int interiorCountOffset = get_wData(arbor, kExt)-get_wDataStart(arbor); int lineoffsetw = 0; int lineoffseta = 0; for( int y=0; y<ny; y++ ) { for( int k=0; k<nk; k++ ) { int postactindex = offset+lineoffseta+k; if (postactindex != kExt) { // Neurons don't inhibit themselves interiorCounts[arbor][interiorCountOffset + lineoffsetw + k]++; } } lineoffsetw += syp; lineoffseta += sya; } } } int bufsize = numberOfAxonalArborLists() * getNumDataPatches() * nxp * nyp * nfp; // TODO-CER-2014.3.26 - Ensure that reduction is done when not using MPI #ifdef PV_USE_MPI MPI_Allreduce(MPI_IN_PLACE, interiorCounts[0], bufsize, MPI_FLOAT, MPI_SUM, parent->icCommunicator()->communicator()); #endif return status; }
//Connections update first int GradientCheckConn::updateState(double time, double dt){ int status = PV_SUCCESS; int weightIdx = parent->getCurrentStep() - parent->getInitialStep() - 2; std::cout << "weightIdx " << weightIdx << "\n"; int numPatch = nxp * nyp * nfp; int numData = getNumDataPatches(); int arborIdx = weightIdx / (numPatch * numData); int dataIdx = (weightIdx / numPatch) % numData; int patchIdx = weightIdx % numPatch; if(firstRun){ initialize_dW(0); firstRun = false; return PV_SUCCESS; } //Grab cost from previous timestep if(secondRun){ //First run does regular updateState to calculate dw buffer for(int arborId=0;arborId<numberOfAxonalArborLists();arborId++) { status = calc_dW(); // Calculate changes in weights if (status==PV_BREAK) { break; } assert(status == PV_SUCCESS); } //for (int arborID = 0; arborID < numberOfAxonalArborLists(); arborID++) { // if(sharedWeights){ // status = reduceKernels(arborID); // combine partial changes in each column // if (status == PV_BREAK) { // break; // } // assert(status == PV_SUCCESS); // } //} //No update weights origCost = getCost(); secondRun = false; } //Does not update after first run //Check if we are in bounds for non-shared weights if(!sharedWeights){ PVPatch* weights = getWeights(dataIdx, arborIdx); //Calculate x and y of patchIdx and compare it to offset int xPatchIdx = kxPos(patchIdx, nxp, nyp, nfp); int yPatchIdx = kyPos(patchIdx, nxp, nyp, nfp); int xOffsetIdx = kxPos(weights->offset, nxp, nyp, nfp); int yOffsetIdx = kyPos(weights->offset, nxp, nyp, nfp); //If index is oob, skip if(xPatchIdx < xOffsetIdx || xPatchIdx >= xOffsetIdx + weights->nx || yPatchIdx < yOffsetIdx || yPatchIdx >= yOffsetIdx + weights->ny){ return PV_SUCCESS; } } //Calculate difference in numerical method and backprop method if(prevIdx != -1){ currCost = getCost(); //Check for accuracy float numGradient = (currCost - origCost)/epsilon; float backpropGradient = get_dwDataStart()[0][prevIdx] / dWMax; std::cout << "Numerical gradient: " << numGradient << " Backprop gradient: " << backpropGradient << "\n"; //if(fabs(numGradient + backpropGradient) >= .1){ // std::cout << "Numerical gradient: " << numGradient << " Backprop gradient: " << backpropGradient << "\n"; // exit(-1); //} } //Restore weight if(prevIdx != -1){ std::cout << "Restoring weight " << prevIdx << " to " << prevWeightVal << "\n"; get_wDataStart()[0][prevIdx] = prevWeightVal; } //Set next weight if not the end if(weightIdx < numberOfAxonalArborLists() * numData * numPatch){ prevWeightVal = get_wDataStart()[0][weightIdx]; prevIdx = weightIdx; get_wDataStart()[0][weightIdx] += epsilon; std::cout << "Setting weight " << weightIdx << " to " << prevWeightVal + epsilon << "\n"; } else{ std::cout << "END\n"; } return status; }
/** * STDP online implementation * (see more at: Pfister et al. 2008) * */ int STDP3Conn::updateWeights(int axonId) { // Steps: // 1. Update post_tr // 2. Update pre_tr // 3. Update w_ij const float dt = parent->getDeltaTime(); const float decayLTP = exp(-dt / tauLTP); const float decayLTD = exp(-dt / tauLTD); const float decayY = exp(-dt / tauY); const int nkpre = pre->getNumExtended(); assert(nkpre == getNumWeightPatches()); const pvdata_t * preLayerData = pre->getLayerData(); const pvdata_t * aPost = post->getLayerData(); pvdata_t aPre; //PVPatch * w; pvdata_t * post_tr_m; pvdata_t * post2_tr_m; pvdata_t * pre_tr_m; // Presynaptic trace matrix pvwdata_t * W; int nk, ny; const int nkPost = post_tr->numItems; post_tr_m = post_tr->data; // Postsynaptic trace matrix post2_tr_m = post2_tr->data; // Postsynaptic trace matrix // 1. Updates the postsynaptic traces for (int kPost = 0; kPost < nkPost; kPost++) { //post_tr_m[kPost] = (decayLTD * post_tr_m[kPost] + aPost[kPost]) > 1? 1 : (decayLTD * post_tr_m[kPost] + aPost[kPost]); post_tr_m[kPost] = decayLTD * post_tr_m[kPost] + aPost[kPost]; post2_tr_m[kPost] = decayY * post2_tr_m[kPost] + aPost[kPost]; } // this stride is in extended space for post-synaptic activity and STDP decrement variable const int postStrideY = post->getLayerLoc()->nf * (post->getLayerLoc()->nx + post->getLayerLoc()->halo.lt + post->getLayerLoc()->halo.rt); //FIXME: In the first iteration post is -70!! for (int kPre = 0; kPre < nkpre; kPre++) { aPre = preLayerData[kPre]; PVPatch * w = getWeights(kPre, axonId); //Get weights in form of a patch (nx,ny,nf), TODO: what's the role of the offset? size_t postOffset = getAPostOffset(kPre, axonId); //Gets start index for postsynaptic vectors given presynaptic neuron kPre aPost = &post->getLayerData()[postOffset]; //Gets postsynaptic activity post_tr_m = &(post_tr->data[postOffset]); // STDP decrement variable post2_tr_m = &(post_tr->data[postOffset]); // STDP y decrement variable //pre_tr_m = get_dwData(axonId, kPre); // STDP increment variable pre_tr_m = &(pre_tr->data[kPre]); W = get_wData(axonId, kPre); // w->data; nk = nfp * w->nx; // one line in x at a time ny = w->ny; // 2. Updates the presynaptic trace //pre_tr_m[0] = (decayLTP * pre_tr_m[0] + aPre) > 1? 1 : (decayLTP * pre_tr_m[0] + aPre); pre_tr_m[0] = decayLTP * pre_tr_m[0] + aPre; //3. Update weights for (int y = 0; y < ny; y++) { for (int k = 0; k < nk; k++) { // The next statement allows some synapses to "die". if (W[k] < WEIGHT_MIN_VALUE) continue; W[k] += dWMax * (-ampLTD*aPre * post_tr_m[k] + ampLTP * aPost[k] * (pre_tr_m[0]*post2_tr_m[k])); W[k] = W[k] < wMin ? wMin : W[k]; W[k] = W[k] > wMax ? wMax : W[k]; } // advance pointers in y W += syp; //FIXME: W += nk //pre_tr_m += syp; //FIXME: pre_tr_m += syp; // postActivity and post trace are extended layer aPost += postStrideY; //TODO: is this really in the extended space? post_tr_m += postStrideY; post2_tr_m += postStrideY; } } if(synscalingFlag){ //int kxPre, kyPre, kPre; const int numPostPatch = nxpPost * nypPost * nfpPost; // Post-synaptic weights are never shrunken float sumW = 0; //int kxPost, kyPost, kfPost; const int xScale = post->getXScale() - pre->getXScale(); const int yScale = post->getYScale() - pre->getYScale(); const double powXScale = pow(2.0f, (double) xScale); const double powYScale = pow(2.0f, (double) yScale); nxpPost = (int) (nxp * powXScale); nypPost = (int) (nyp * powYScale); nfpPost = pre->clayer->loc.nf; for(int axonID=0;axonID<numberOfAxonalArborLists();axonID++) { // loop through post-synaptic neurons (non-extended indices) for (int kPost = 0; kPost < post_tr->numItems; kPost++) { pvwdata_t ** postData = wPostDataStartp[axonID] + numPostPatch*kPost + 0; for (int kp = 0; kp < numPostPatch; kp++) { sumW += *(postData[kp]); } for (int kp = 0; kp < numPostPatch; kp++) { *(postData[kp]) = ((*postData[kp])/sumW)*synscaling_v; } //printf("%f ",sumW); sumW = 0; } //printf("\n"); } } return 0; }