sigma[[x for x in range(len(sfRel)) if sfRel[x] > 1]] = sigHigh # - now, compute the responses (automatically normalized, since max gaussian value is 1...) s = [ np.exp(-np.divide(np.square(np.log(x)), 2 * np.square(y))) for x, y in zip(sfRel, sigma) ] sfExcCurr = s sfExc.append(sfExcCurr) inhSfTuning = hf.getSuppressiveSFtuning() # Compute weights for suppressive signals nInhChan = expData['sfm']['mod']['normalization']['pref']['sf'] nTrials = inhSfTuning.shape[0] inhWeight = hf.genNormWeights(expData, nInhChan, gs_mean, gs_std, nTrials, expInd) inhWeight = inhWeight[:, :, 0] # genNormWeights gives us weights as nTr x nFilters x nFrames - we have only one "frame" here, and all are the same # first, tuned norm: sfNormTune = np.sum(-.5 * (inhWeight * np.square(inhSfTuning)), 1) sfNormTune = sfNormTune / np.amax(np.abs(sfNormTune)) # then, untuned norm: inhAsym = 0 inhWeight = [] for iP in range(len(nInhChan)): inhWeight = np.append( inhWeight, 1 + inhAsym * (np.log(expData['sfm']['mod']['normalization']['pref']['sf'][iP]) - np.mean( np.log(expData['sfm']['mod']['normalization']['pref']['sf'][iP]))) )
measured_resps = hf.organize_resp( data['spikeCount'], cellStruct, expInd)[2] # 3rd output is organized sfMix resp. measured_byDisp = shapeByDisp(measured_resps) nDisps = len(measured_byDisp) ## get the final filter tunings omega = np.logspace(-2, 2, 1000) # where are we evaluating? # first, normalization inhSfTuning = hf.getSuppressiveSFtuning(sfs=omega) nInhChan = cellStruct['sfm']['mod']['normalization']['pref']['sf'] nTrials = inhSfTuning.shape[0] if fitType == 2: gs_mean, gs_std = [finalParams[normMu], finalParams[normStd]] inhWeight = hf.genNormWeights(cellStruct, nInhChan, gs_mean, gs_std, nTrials, expInd) inhWeight = inhWeight[:, :, 0] # genNormWeights gives us weights as nTr x nFilters x nFrames - we have only one "frame" here, and all are the same # first, tuned norm: sfNorm = np.sum(-.5 * (inhWeight * np.square(inhSfTuning)), 1) sfNorm = sfNorm / np.amax(np.abs(sfNorm)) # update function to be used below updateInhWeight = lambda mn, std: hf.genNormWeights( cellStruct, nInhChan, mn, std, nTrials, expInd)[:, :, 0] else: # then, untuned norm: inhAsym = 0 inhWeight = [] for iP in range(len(nInhChan)): inhWeight = np.append( inhWeight, 1 + inhAsym *
# plot model details - exc/suppressive components prefSf = modFit[0] dOrder = modFit[1] omega = np.logspace(-2, 2, 1000) sfRel = omega / prefSf s = np.power(omega, dOrder) * np.exp(-dOrder / 2 * np.square(sfRel)) sMax = np.power(prefSf, dOrder) * np.exp(-dOrder / 2) sfExc = s / sMax inhSfTuning = getSuppressiveSFtuning() # Compute weights for suppressive signals nInhChan = expData['sfm']['mod']['normalization']['pref']['sf'] if norm_type == 1: nTrials = inhSfTuning.shape[0] inhWeight = genNormWeights(expData, nInhChan, gs_mean, gs_std, nTrials) inhWeight = inhWeight[:, :, 0] # genNormWeights gives us weights as nTr x nFilters x nFrames - we have only one "frame" here, and all are the same else: if modFit[8]: # i.e. if this parameter exists... inhAsym = modFit[8] else: inhAsym = 0 inhWeight = [] for iP in range(len(nInhChan)): inhWeight = np.append( inhWeight, 1 + inhAsym * (np.log(expData['sfm']['mod']['normalization']['pref']['sf'][iP]) - np.mean( np.log(expData['sfm']['mod']['normalization']['pref']['sf']
# if modParamsCurr doesn't have inhAsym parameter, add it! if norm_type == 2: unweighted = 1 _, _, _, normRespSimple, _ = mod_resp.SFMsimulate( modParamsCurr, cellStruct, disp + 1, conLevels[conLvl], sfCenters[sfCent], unweighted, normType=norm_type, expInd=expInd) nTrials = normRespSimple.shape[0] nInhChan = cellStruct['sfm']['mod']['normalization'][ 'pref']['sf'] inhWeightMat = hf.genNormWeights(cellStruct, nInhChan, gs_mean, gs_std, nTrials) normResp = np.sqrt( (inhWeightMat * normRespSimple).sum(1)).transpose() norm_sim[disp, conLvl, sfCent] = np.mean(normResp) # take mean of the returned simulations (10 repetitions per stim. condition) else: # norm_type == 1 or 3: _, _, _, _, normResp = mod_resp.SFMsimulate( modParamsCurr, cellStruct, disp + 1, conLevels[conLvl], sfCenters[sfCent], normType=norm_type, expInd=expInd) norm_sim[disp, conLvl, sfCent] = np.mean(normResp) # take mean of the returned simulations (10 repetitions per stim. condition)
def SFMsimulate(params, structureSFM, stimFamily, con, sf_c, unweighted = 0, normType=1): # Currently, will get slightly different stimuli for excitatory and inhibitory/normalization pools # But differences are just in phase/TF, but for TF, drawn from same distribution, anyway... # 4/27/18: if unweighted = 1, then do the calculation/return normResp with weights applied; otherwise, just return the unweighted filter responses # 00 = preferred spatial frequency (cycles per degree) # 01 = derivative order in space # 02 = normalization constant (log10 basis) # 03 = response exponent # 04 = response scalar # 05 = early additive noise # 06 = late additive noise # 07 = variance of response gain # if fitType == 1 # 08 = asymmetry ("historically", bounded [-0.35, 0.35]) # if fitType == 2 # 08 = mean of normalization weights gaussian # 09 = std of ... # if fitType == 3 # 08 = offset of c50 tuning filter (filter bounded between [sigOffset, 1] # 09/10 = standard deviations to the left and right of the peak of the c50 filter # 11 = peak (in sf cpd) of c50 filter #print('simulate!'); T = structureSFM['sfm']; # Get parameter values # Excitatory channel pref = {'sf': params[0]}; dord = {'sp': params[1], 'ti': 0.25}; # deriv order in temporal domain = 0.25 ensures broad tuning for temporal frequency excChannel = {'pref': pref, 'dord': dord}; # Other (nonlinear) model components sigma = pow(10, params[2]); # normalization constant # respExp = 2; # response exponent respExp = params[3]; # response exponent scale = params[4]; # response scalar # Noise parameters noiseEarly = params[5]; # early additive noise noiseLate = params[6]; # late additive noise varGain = params[7]; # multiplicative noise ### Normalization parameters normParams = getNormParams(params, normType); if normType == 1: inhAsym = normParams; elif normType == 2: gs_mean = normParams[0]; gs_std = normParams[1]; elif normType == 3: # sigma calculation offset_sigma = normParams[0]; # c50 filter will range between [v_sigOffset, 1] stdLeft = normParams[1]; # std of the gaussian to the left of the peak stdRight = normParams[2]; # '' to the right '' sfPeak = normParams[3]; # where is the gaussian peak? else: inhAsym = normParams; # Get stimulus structure ready... stimParams = dict(); stimParams['stimFamily'] = stimFamily; stimParams['conLevel'] = con; stimParams['sf_c'] = sf_c; stimParams['repeats'] = 1; # defaults to 10 anyway, in makeStimulus.py # Compute weights for suppressive signals nInhChan = T['mod']['normalization']['pref']['sf']; nTrials = stimParams['repeats']; inhWeight = []; nFrames = 120; # always if normType == 3: filter = setSigmaFilter(sfPeak, stdLeft, stdRight); scale_sigma = -(1-offset_sigma); evalSfs = structureSFM['sfm']['exp']['trial']['sf'][0]; # the center SF of all stimuli sigmaFilt = evalSigmaFilter(filter, scale_sigma, offset_sigma, evalSfs); else: sigmaFilt = numpy.square(sigma); # i.e. normalization constant squared if normType == 2: inhWeightMat = genNormWeights(structureSFM, nInhChan, gs_mean, gs_std, nTrials); else: # normType == 1 or anything else, we just go with for iP in range(len(nInhChan)): inhWeight = numpy.append(inhWeight, 1 + inhAsym*(numpy.log(T['mod']['normalization']['pref']['sf'][iP]) \ - numpy.mean(numpy.log(T['mod']['normalization']['pref']['sf'][iP])))); # assumption (made by Robbe) - only two normalization pools inhWeightT1 = numpy.reshape(inhWeight, (1, len(inhWeight))); inhWeightT2 = repmat(inhWeightT1, nTrials, 1); inhWeightT3 = numpy.reshape(inhWeightT2, (nTrials, len(inhWeight), 1)); inhWeightMat = numpy.tile(inhWeightT3, (1,1,nFrames)); # Evaluate sfmix experiment T = structureSFM['sfm']; # [iR] # Get simple cell response for excitatory channel E = SFMSimpleResp(structureSFM, excChannel, stimParams); # Extract simple cell response (half-rectified linear filtering) Lexc = E['simpleResp']; # Get inhibitory response (pooled responses of complex cells tuned to wide range of spatial frequencies, square root to bring everything in linear contrast scale again) normResp = GetNormResp(structureSFM, [], stimParams); if unweighted == 1: return [], [], Lexc, normResp['normResp'], []; Linh = numpy.sqrt((inhWeightMat*normResp['normResp']).sum(1)).transpose(); # Compute full model response (the normalization signal is the same as the subtractive suppressive signal) numerator = noiseEarly + Lexc; # taking square root of denominator (after summing squares...) to bring in line with computation in Carandini, Heeger, Movshon, '97 denominator = pow(sigmaFilt + pow(Linh, 2), 0.5); # squaring Linh - edit 7/17 ratio = pow(numpy.maximum(0, numerator/denominator), respExp); meanRate = ratio.mean(0); respModel = noiseLate + scale*meanRate; # respModel[iR] return respModel, Linh, Lexc, normResp['normResp'], denominator;
def SFMGiveBof(params, structureSFM, normType=1, lossType=1, trialSubset=None, maskOri=True, maskIn=None): # Computes the negative log likelihood for the LN-LN model # Optional arguments: //note: true means include in mask, false means exclude # trialSubset - pass in the trials you want to evaluate (ignores all other masks) # maskOri - in the optimization, we don't include the orientation tuning curve - skip that in the evaluation of loss, too # maskIn - pass in a mask (overwrite maskOri and trialSubset, i.e. highest presedence) # MASK IGNORED FOR NOW (12.02.18) # Returns NLL ###, respModel # 00 = preferred spatial frequency (cycles per degree) # 01 = derivative order in space # 02 = normalization constant (log10 basis) # 03 = response exponent # 04 = response scalar # 05 = early additive noise # 06 = late additive noise # 07 = variance of response gain # if fitType == 1 # 08 = asymmetry ("historically", bounded [-0.35, 0.35]) # if fitType == 2 # 08 = mean of normalization weights gaussian # 09 = std of ... # if fitType == 3 # 08 = offset of c50 tuning filter (filter bounded between [sigOffset, 1] # 09/10 = standard deviations to the left and right of the peak of the c50 filter # 11 = peak (in sf cpd) of c50 filter T = structureSFM['sfm']; # Get parameter values # Excitatory channel pref = {'sf': params[0]}; dord = {'sp': params[1], 'ti': 0.25}; # deriv order in temporal domain = 0.25 ensures broad tuning for temporal frequency excChannel = {'pref': pref, 'dord': dord}; # Inhibitory channel # nothing in this current iteration - 7/7/17 # Other (nonlinear) model components sigma = pow(10, params[2]); # normalization constant # respExp = 2; # response exponent respExp = params[3]; # response exponent scale = params[4]; # response scalar # Noise parameters noiseEarly = params[5]; # early additive noise noiseLate = params[6]; # late additive noise varGain = params[7]; # multiplicative noise ### Normalization parameters normParams = getNormParams(params, normType); if normType == 1: inhAsym = normParams; elif normType == 2: gs_mean = normParams[0]; gs_std = normParams[1]; elif normType == 3: # sigma calculation offset_sigma = normParams[0]; # c50 filter will range between [v_sigOffset, 1] stdLeft = normParams[1]; # std of the gaussian to the left of the peak stdRight = normParams[2]; # '' to the right '' sfPeak = normParams[3]; # where is the gaussian peak? else: inhAsym = normParams; # Evaluate prior on response exponent -- corresponds loosely to the measurements in Priebe et al. (2004) priorExp = lognorm.pdf(respExp, 0.3, 0, numpy.exp(1.15)); # matlab: lognpdf(respExp, 1.15, 0.3); NLLExp = 0; #-numpy.log(priorExp); # Compute weights for suppressive signals nInhChan = T['mod']['normalization']['pref']['sf']; nTrials = len(T['exp']['trial']['num']); inhWeight = []; nFrames = 120; # always if normType == 3: filter = setSigmaFilter(sfPeak, stdLeft, stdRight); scale_sigma = -(1-offset_sigma); evalSfs = structureSFM['sfm']['exp']['trial']['sf'][0]; # the center SF of all stimuli sigmaFilt = evalSigmaFilter(filter, scale_sigma, offset_sigma, evalSfs); else: sigmaFilt = numpy.square(sigma); # i.e. square the normalization constant if normType == 2: inhWeightMat = genNormWeights(structureSFM, nInhChan, gs_mean, gs_std, nTrials); else: # normType == 1 or anything else, for iP in range(len(nInhChan)): inhWeight = numpy.append(inhWeight, 1 + inhAsym*(numpy.log(T['mod']['normalization']['pref']['sf'][iP]) \ - numpy.mean(numpy.log(T['mod']['normalization']['pref']['sf'][iP])))); # assumption by creation (made by Robbe) - only two normalization pools inhWeightT1 = numpy.reshape(inhWeight, (1, len(inhWeight))); inhWeightT2 = repmat(inhWeightT1, nTrials, 1); inhWeightT3 = numpy.reshape(inhWeightT2, (nTrials, len(inhWeight), 1)); inhWeightMat = numpy.tile(inhWeightT3, (1,1,nFrames)); # Evaluate sfmix experiment for iR in range(1): #range(len(structureSFM['sfm'])): # why 1 for now? We don't have S.sfm as array (just one) T = structureSFM['sfm']; # [iR] # Get simple cell response for excitatory channel E = SFMSimpleResp(structureSFM, excChannel); # Extract simple cell response (half-rectified linear filtering) Lexc = E['simpleResp']; # Get inhibitory response (pooled responses of complex cells tuned to wide range of spatial frequencies, square root to bring everything in linear contrast scale again) Linh = numpy.sqrt((inhWeightMat*T['mod']['normalization']['normResp']).sum(1)).transpose(); # Compute full model response (the normalization signal is the same as the subtractive suppressive signal) numerator = noiseEarly + Lexc; denominator = pow(sigmaFilt + pow(Linh, 2), 0.5); # square Linh added 7/24 - was mistakenly not fixed earlier ratio = pow(numpy.maximum(0, numerator/denominator), respExp); meanRate = ratio.mean(0); respModel = noiseLate + scale*meanRate; # respModel[iR] rateModel = T['exp']['trial']['duration'] * respModel; # and get the spike count spikeCount = T['exp']['trial']['spikeCount']; if lossType == 1: # alternative loss function: just (sqrt(modResp) - sqrt(neurResp))^2 lsq = numpy.square(numpy.add(numpy.sqrt(rateModel), -numpy.sqrt(spikeCount))); NLL = numpy.mean(lsq); elif lossType == 2: poiss_llh = numpy.log(poisson.pmf(spikeCount, rateModel)); NLL = numpy.mean(-poiss_llh); elif lossType == 3: # Get predicted spike count distributions mu = numpy.maximum(.01, rateModel); # The predicted mean spike count; respModel[iR] var = mu + (varGain*pow(mu,2)); # The corresponding variance of the spike count r = pow(mu,2)/(var - mu); # The parameters r and p of the negative binomial distribution p = r/(r + mu); llh = nbinom.pmf(spikeCount, r, p); # Likelihood for each pass under doubly stochastic model NLL = numpy.mean(-numpy.log(llh)); # The negative log-likelihood of the whole data-set; [iR] elif lossType == 4: #chi squared if trialSubset is not None: warnings.warn('This loss type (chi squared) is not currently equipped to handle hold out subsets'); expByCond, expAll = organize_modResp(spikeCount, structureSFM); exp_responses = [expByCond.flatten(), numpy.nanvar(expAll, axis=3).flatten()]; modByCond, modAll = organize_modResp(rateModel, structureSFM); mod_responses = [modByCond.flatten(), numpy.nanvar(modAll, axis=3).flatten()]; NLL = chiSq(exp_responses, mod_responses); return NLL, respModel;
def SFMGiveBof(params, structureSFM, normType): # Computes the negative log likelihood for the LN-LN model # Returns NLL ###, respModel, E # 00 = preferred spatial frequency (cycles per degree) # 01 = derivative order in space # 02 = normalization constant (log10 basis) # 03 = response exponent # 04 = response scalar # 05 = early additive noise # 06 = late additive noise # 07 = variance of response gain # if fitType == 1 # currently, no 08; alternatively, 08 = asymmetry (typically bounded [-0.35, 0.35]) # if fitType == 2 # 08 = mean of normalization weights gaussian # 09 = std of ... # if fitType == 3 # 08 = offset of c50 tuning filter (filter bounded between [sigOffset, 1] # 09/10 = standard deviations to the left and right of the peak of the c50 filter # 11 = peak (in sf cpd) of c50 filter print('ha!') T = structureSFM['sfm'] # Get parameter values # Excitatory channel pref = { 'sf': params[0] } dord = { 'sp': params[1], 'ti': 0.25 } # deriv order in temporal domain = 0.25 ensures broad tuning for temporal frequency excChannel = { 'pref': pref, 'dord': dord } # Inhibitory channel # nothing in this current iteration - 7/7/17 # Other (nonlinear) model components sigma = pow(10, params[2]) # normalization constant # respExp = 2; # response exponent respExp = params[3] # response exponent scale = params[4] # response scalar # Noise parameters noiseEarly = params[5] # early additive noise noiseLate = params[6] # late additive noise varGain = params[7] # multiplicative noise ### Normalization parameters normParams = getNormParams(params, normType) if normType == 1: # flat inhAsym = normParams elif normType == 2: # gaussian weighting gs_mean = normParams[0] gs_std = normParams[1] elif normType == 3: # two-halved gaussian for c50 # sigma calculation offset_sigma = normParams[0] # c50 filter will range between [v_sigOffset, 1] stdLeft = normParams[1] # std of the gaussian to the left of the peak stdRight = normParams[2] # '' to the right '' sfPeak = normParams[3] # where is the gaussian peak? else: inhAsym = normParams # Evaluate prior on response exponent -- corresponds loosely to the measurements in Priebe et al. (2004) priorExp = lognorm.pdf(respExp, 0.3, 0, numpy.exp(1.15)) # matlab: lognpdf(respExp, 1.15, 0.3); NLLExp = 0 #-numpy.log(priorExp); # Compute weights for suppressive signals nInhChan = T['mod']['normalization']['pref']['sf'] nTrials = len(T['exp']['trial']['num']) inhWeight = [] nFrames = 120 # always if normType == 3: filter = setSigmaFilter(sfPeak, stdLeft, stdRight) scale_sigma = -(1 - offset_sigma) evalSfs = structureSFM['sfm']['exp']['trial']['sf'][0] # the center SF of all stimuli sigmaFilt = evalSigmaFilter(filter, scale_sigma, offset_sigma, evalSfs) else: sigmaFilt = numpy.square(sigma) # i.e. square the normalization constant if normType == 2: inhWeightMat = genNormWeights(structureSFM, nInhChan, gs_mean, gs_std, nTrials) else: # normType == 1 or anything else, for iP in range(len(nInhChan)): inhWeight = numpy.append(inhWeight, 1 + inhAsym*(numpy.log(T['mod']['normalization']['pref']['sf'][iP]) \ - numpy.mean(numpy.log(T['mod']['normalization']['pref']['sf'][iP])))) # assumption (made by Robbe) - only two normalization pools inhWeightT1 = numpy.reshape(inhWeight, (1, len(inhWeight))) inhWeightT2 = repmat(inhWeightT1, nTrials, 1) inhWeightT3 = numpy.reshape(inhWeightT2, (nTrials, len(inhWeight), 1)) inhWeightMat = numpy.tile(inhWeightT3, (1, 1, nFrames)) # Evaluate sfmix experiment for iR in range( 1 ): #range(len(structureSFM['sfm'])): # why 1 for now? We don't have S.sfm as array (just one) T = structureSFM['sfm'] # [iR] # Get simple cell response for excitatory channel E = SFMSimpleResp(structureSFM, excChannel) # Extract simple cell response (half-rectified linear filtering) Lexc = E['simpleResp'] # Get inhibitory response (pooled responses of complex cells tuned to wide range of spatial frequencies, square root to bring everything in linear contrast scale again) Linh = numpy.sqrt( (inhWeightMat * T['mod']['normalization']['normResp']).sum(1)).transpose() # Compute full model response (the normalization signal is the same as the subtractive suppressive signal) numerator = noiseEarly + Lexc denominator = pow(sigmaFilt + pow(Linh, 2), 0.5) # square Linh added 7/24 - was mistakenly not fixed earlier # denominator = pow(pow(sigma, 2) + pow(Linh, 2), 0.5); # square Linh added 7/24 - was mistakenly not fixed earlier ratio = pow(numpy.maximum(0, numerator / denominator), respExp) meanRate = ratio.mean(0) respModel = noiseLate + scale * meanRate # respModel[iR] # Get predicted spike count distributions mu = numpy.maximum(.01, T['exp']['trial']['duration'] * respModel) # The predicted mean spike count; respModel[iR] var = mu + (varGain * pow(mu, 2)) # The corresponding variance of the spike count r = pow(mu, 2) / (var - mu) # The parameters r and p of the negative binomial distribution p = r / (r + mu) # Evaluate the model lsq = numpy.square( numpy.sqrt(respModel) - numpy.sqrt(T['exp']['trial']['spikeCount'])) NLL = numpy.mean(lsq) # was 1*lsq #llh = nbinom.pmf(T['exp']['trial']['spikeCount'], r, p); # Likelihood for each pass under doubly stochastic model #NLLtempSFM = numpy.mean(-numpy.log(llh)); # The negative log-likelihood of the whole data-set; [iR] # Combine data and prior #NLL = NLLtempSFM + NLLExp; # sum over NLLtempSFM if you allow it to be d>1 return NLL, respModel
aRatio) filt = (filtTemp - filtTemp[0, 0]) / np.amax(np.abs(filtTemp - filtTemp[0, 0])) # get model details - exc/suppressive components omega = np.logspace(-2, 2, 1000) sfRel = omega / prefSf s = np.power(omega, dOrder) * np.exp(-dOrder / 2 * np.square(sfRel)) sMax = np.power(prefSf, dOrder) * np.exp(-dOrder / 2) sfExc = s / sMax inhSfTuning = helper_fcns.getSuppressiveSFtuning() nInhChan = cellStruct['sfm']['mod']['normalization']['pref']['sf'] if norm_type == 1: nTrials = inhSfTuning.shape[0] inhWeight = helper_fcns.genNormWeights(cellStruct, nInhChan, gs_mean, gs_std, nTrials) inhWeight = inhWeight[:, :, 0] # genNormWeights gives us weights as nTr x nFilters x nFrames - we have only one "frame" here, and all are the same else: if modFit[8]: # i.e. if this parameter exists... inhAsym = modFit[8] else: inhAsym = 0 inhWeight = [] for iP in range(len(nInhChan)): inhWeight = np.append( inhWeight, 1 + inhAsym * (np.log(cellStruct['sfm']['mod']['normalization']['pref']['sf'] [iP]) - np.mean( np.log(cellStruct['sfm']['mod']['normalization']