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;
Exemple #4
0
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]