if len(normTypeArr ) == 3: # i.e. we've passed in gs_mean, gs_std, then replace... modFit[-2] = normTypeArr[1] modFit[-1] = normTypeArr[2] ignore, modResp, normTypeArr = mod_resp.SFMGiveBof(modFit, expData, normTypeArr) norm_type = normTypeArr[0] if norm_type == 1: gs_mean = normTypeArr[1] # guaranteed to exist after call to .SFMGiveBof, if norm_type == 1 gs_std = normTypeArr[2] # guaranteed to exist ... #modRespAll = mod_resp.SFMGiveBof(modParamsCurr, expData, normTypeArr)[1]; # NOTE: We're taking [1] (i.e. second) output of SFMGiveBof oriModResp, conModResp, sfmixModResp, allSfMix = organize_modResp( modResp, expData['sfm']['exp']['trial']) oriExpResp, conExpResp, sfmixExpResp, allSfMixExp = organize_modResp(expData['sfm']['exp']['trial']['spikeCount'], \ expData['sfm']['exp']['trial']) #pdb.set_trace(); # allSfMix is (nFam, nCon, nCond, nReps) where nCond is 11, # of SF centers and nReps is usually 10 modLow = np.nanmin(allSfMix, axis=3) modHigh = np.nanmax(allSfMix, axis=3) modAvg = np.nanmean(allSfMix, axis=3) modSponRate = modFit[6] findNan = np.isnan(allSfMixExp) nonNan = np.sum(findNan == False, axis=3) # how many valid trials are there for each fam x con x center combination? allExpSEM = np.nanstd(allSfMixExp, axis=3) / np.sqrt(nonNan) # SEM
def measure_chiSq(lossType, expInd=1, date='181121'): _, nDisps, _, nCons, nCells, dataLoc = hf.get_exp_params(expInd); if expInd == 1: # main V1 branch dataLoc = dataLoc + 'Structures/'; else: dataLoc = dataLoc + 'structures/'; dataList = hf.np_smart_load(str(dataLoc + 'dataList.npy')); # then the loss type if lossType == 1: lossSuf = '_sqrt.npy'; elif lossType == 2: lossSuf = '_poiss.npy'; elif lossType == 3: lossSuf = '_modPoiss.npy'; chi_wght = np.nan * np.zeros((nCells, )); chi_flat = np.nan * np.zeros((nCells, )); flat = hf.np_smart_load(dataLoc + 'fitList_%s_flat%s' % (date, lossSuf)); weight = hf.np_smart_load(dataLoc + 'fitList_%s_wght%s' % (date, lossSuf)); for i in range(nCells): print('cell %d' % i); S = hf.np_smart_load(str(dataLoc + dataList['unitName'][i] + '_sfm.npy')); # first, the data _, _, sfmixExpResp, allSfMixExp = hf.organize_modResp(S['sfm']['exp']['trial']['spikeCount'], S['sfm']['exp']['trial']) exp_responses = [sfmixExpResp, np.nanvar(allSfMixExp, axis=3)]; ## then, the model # flat normalization if i in flat: flat_params = flat[i]['params']; ignore, modResp = SFMGiveBof(flat_params, S, normType=1, lossType=lossType, expInd=expInd); _, _, sfmixModResp, allSfMixMod = hf.organize_modResp(modResp, S['sfm']['exp']['trial']) mod_responses = [sfmixModResp, np.nanvar(allSfMixMod)]; chi_flat[i] = hf.chiSq(exp_responses, mod_responses); print('chi: %.1f' % chi_flat[i]); # weighted normalization if i in weight: wght_params = weight[i]['params']; ignore, modResp = SFMGiveBof(wght_params, S, normType=2, lossType=lossType, expInd=expInd); _, _, sfmixModResp, allSfMixMod = hf.organize_modResp(modResp, S['sfm']['exp']['trial']) mod_responses = [sfmixModResp, np.nanvar(allSfMixMod)]; chi_wght[i] = hf.chiSq(exp_responses, mod_responses); print('\tchi: %.1f' % chi_wght[i]); n_flat_params = len(flat[0]['params']); n_wght_params = len(weight[0]['params']); chiNorm_flat = np.divide(chi_flat, n_flat_params); chiNorm_wght = np.divide(chi_flat, n_wght_params); chiAnalysis = dict(); chiAnalysis['flat_norm'] = chiNorm_flat; chiAnalysis['wght_norm'] = chiNorm_wght; chiAnalysis['flat'] = chi_flat; chiAnalysis['wght'] = chi_wght; np.save('chiAnalysis', chiAnalysis); return chiNorm_flat, chiNorm_wght, chi_flat, chi_wght;
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;
descrExpFit = descrExpFits[cellNum - 1]['params'] # nFam x nCon x nDescrParams descrModFit = descrModFits[cellNum - 1]['params'] # nFam x nCon x nDescrParams modResps = [ mod_resp.SFMGiveBof(fit, expData, normType=norm, lossType=lossType) for fit, norm in zip(modFits, normTypes) ] modResps = [x[1] for x in modResps] # 1st return output is NLL (don't care about that here) gs_mean = modFit_wg[8] gs_std = modFit_wg[9] # now organize the responses orgs = [ organize_modResp(mr, expData['sfm']['exp']['trial']) for mr in modResps ] oriModResps = [org[0] for org in orgs] conModResps = [org[1] for org in orgs] sfmixModResps = [org[2] for org in orgs] allSfMixs = [org[3] for org in orgs] # now organize the measured responses in the same way oriExpResp, conExpResp, sfmixExpResp, allSfMixExp = organize_modResp(expData['sfm']['exp']['trial']['spikeCount'], \ expData['sfm']['exp']['trial']) # allSfMix is (nFam, nCon, nCond, nReps) where nCond is 11, # of SF centers and nReps is usually 10 modLows = [np.nanmin(resp, axis=3) for resp in allSfMixs] modHighs = [np.nanmax(resp, axis=3) for resp in allSfMixs] modAvgs = [np.nanmean(resp, axis=3) for resp in allSfMixs] modSponRates = [fit[6] for fit in modFits]