def calc_local_params(self, Data, LP, **kwargs): ''' Calculate local parameters for each data item and each component. This is part of the E-step. Args ------- Data : bnpy data object with Data.nObs observations LP : local param dict with fields E_log_soft_ev : Data.nObs x K array E_log_soft_ev[n,k] = log p(data obs n | comp k) Returns ------- LP : local param dict with fields resp : Data.nObs x K array whose rows sum to one resp[n,k] = posterior responsibility that comp. k has for data n ''' lpr = LP['E_log_soft_ev'] lpr += self.Elogw # Calculate exp in numerically stable manner (first subtract the max) # perform this in-place so no new allocations occur NumericUtil.inplaceExpAndNormalizeRows(lpr) LP['resp'] = lpr assert np.allclose(lpr.sum(axis=1), 1) return LP
def calcLocalParams(Data, LP, Elogbeta=None, nnzPerRowLP=None, **kwargs): ''' Compute local parameters for each data item. Parameters ------- Data : bnpy.data.DataObj subclass LP : dict Local parameters as key-value string/array pairs * E_log_soft_ev : 2D array, N x K E_log_soft_ev[n,k] = log p(data obs n | comp k) Returns ------- LP : dict Local parameters, with updated fields * resp : 2D array, size N x K array Posterior responsibility each comp has for each item resp[n, k] = p(z[n] = k | x[n]) ''' lpr = LP['E_log_soft_ev'] lpr += Elogbeta K = LP['E_log_soft_ev'].shape[1] if nnzPerRowLP and (nnzPerRowLP > 0 and nnzPerRowLP < K): # SPARSE Assignments LP['spR'] = sparsifyLogResp(lpr, nnzPerRow=nnzPerRowLP) assert np.all(np.isfinite(LP['spR'].data)) LP['nnzPerRow'] = nnzPerRowLP else: # DENSE Assignments # Calculate exp in numerically stable manner (first subtract the max) # perform this in-place so no new allocations occur NumericUtil.inplaceExpAndNormalizeRows(lpr) LP['resp'] = lpr return LP
def calc_local_params(self, Data, LP, nnzPerRowLP=0, **kwargs): ''' Compute local parameters for each data item and component. Parameters ------- Data : bnpy.data.DataObj subclass LP : dict Local parameters as key-value string/array pairs * E_log_soft_ev : 2D array, N x K E_log_soft_ev[n,k] = log p(data obs n | comp k) Returns ------- LP : dict Local parameters, with updated fields * resp : 2D array, size N x K array Posterior responsibility each comp has for each item resp[n, k] = p(z[n] = k | x[n]) ''' lpr = LP['E_log_soft_ev'] K = lpr.shape[1] if self.inferType.count('EM') > 0: # Using point estimates, for EM algorithm lpr += np.log(self.w + 1e-100) if nnzPerRowLP and (nnzPerRowLP > 0 and nnzPerRowLP < K): # SPARSE Assignments LP['nnzPerRow'] = nnzPerRowLP LP['spR'] = sparsifyLogResp(lpr, nnzPerRow=nnzPerRowLP) assert np.all(np.isfinite(LP['spR'].data)) else: lprPerItem = logsumexp(lpr, axis=1) lpr -= lprPerItem[:, np.newaxis] np.exp(lpr, out=lpr) LP['resp'] = lpr LP['evidence'] = lprPerItem.sum() else: # Full Bayesian approach, for VB or GS algorithms lpr += self.Elogw if nnzPerRowLP and (nnzPerRowLP > 0 and nnzPerRowLP < K): # SPARSE Assignments LP['nnzPerRow'] = nnzPerRowLP LP['spR'] = sparsifyLogResp(lpr, nnzPerRow=nnzPerRowLP) assert np.all(np.isfinite(LP['spR'].data)) else: # DENSE Assignments # Calculate exp in numerically safe way, # in-place so no new allocations occur NumericUtil.inplaceExpAndNormalizeRows(lpr) LP['resp'] = lpr assert np.allclose(lpr.sum(axis=1), 1) return LP
def restrictedLocalStep_DPMixtureModel(Dslice=None, sumRespVec=None, LPkwargs=dict(), xObsModel=None, xPiVec=None, xInitSS=None, doBuildOnInit=False, nUpdateSteps=50, convThr=0.1, xPiPrior=1.0, logFunc=None, **kwargs): ''' Perform restricted local step on provided dataset. Returns ------- xLPslice : dict with updated local parameters Obeys restriction that sum(resp, axis=1) equals sumRespVec ''' if xInitSS is None: xWholeSS = None else: xWholeSS = xInitSS.copy() for step in range(nUpdateSteps): # Compute conditional likelihoods for every data atom xLPslice = xObsModel.calc_local_params(Dslice, **LPkwargs) assert 'E_log_soft_ev' in xLPslice xresp = xLPslice['E_log_soft_ev'] xresp += np.log(xPiVec)[np.newaxis, :] # Calculate exp in numerically stable manner (first subtract the max) # perform this in-place so no new allocations occur NumericUtil.inplaceExpAndNormalizeRows(xresp) # Enforce sum restriction xresp *= sumRespVec[:, np.newaxis] np.maximum(xresp, 1e-100, out=xresp) isLastStep = step == nUpdateSteps - 1 if not isLastStep: xSS = xObsModel.calcSummaryStats(Dslice, None, dict(resp=xresp)) # Increment if doBuildOnInit: xSS.setUIDs(xWholeSS.uids) xWholeSS += xSS else: xWholeSS = xSS # Global step xObsModel.update_global_params(xWholeSS) Nvec = xWholeSS.getCountVec() xPiVec = Nvec + xPiPrior # Decrement stats if doBuildOnInit: xWholeSS -= xSS # Assess early stopping if step > 0: thr = np.sum(np.abs(prevCountVec - xSS.getCountVec())) if thr < convThr: break prevCountVec = xSS.getCountVec() if logFunc: msg = "restrictedLocalStep_DPMixtureModel" msg += " stopped after %3d of %d iters. thr=%.4f" % (step, nUpdateSteps, thr) logFunc(msg) xLPslice['resp'] = xresp del xLPslice['E_log_soft_ev'] # delete since we did inplace ops on it return xLPslice