def calcHrespFromLP(LP=None, resp=None): if LP is not None and 'spR' in LP: nnzPerRow = LP['nnzPerRow'] if nnzPerRow > 1: # Handles multiply by -1 already Hresp = calcSparseRlogR(**LP) assert np.all(np.isfinite(Hresp)) else: Hresp = 0.0 else: if LP is not None and 'resp' in LP: resp = LP['resp'] Hresp = -1 * NumericUtil.calcRlogR(resp) return Hresp
def L_entropy(Data=None, LP=None, resp=None, returnVector=0): """ Calculate entropy of soft assignments term in ELBO objective. Returns ------- L_entropy : scalar float """ spR = None if LP is not None: if 'resp' in LP: resp = LP['resp'] elif 'spR' in LP: spR = LP['spR'] N, K = LP['spR'].shape else: raise ValueError("LP dict missing resp or spR") if resp is not None: N, K = LP['resp'].shape if hasattr(Data, 'word_count') and N == Data.word_count.size: if resp is not None: Hvec = -1 * NumericUtil.calcRlogRdotv(resp, Data.word_count) elif spR is not None: Hvec = calcSparseRlogRdotv(v=Data.word_count, **LP) else: raise ValueError("Missing resp assignments!") else: if resp is not None: Hvec = -1 * NumericUtil.calcRlogR(resp) elif 'spR' in LP: assert 'nnzPerRow' in LP Hvec = calcSparseRlogR(**LP) else: raise ValueError("Missing resp assignments!") assert Hvec.size == K assert Hvec.min() >= -1e-6 if returnVector: return Hvec return Hvec.sum()
def calcELBO_NonlinearTerms(Data=None, SS=None, LP=None, todict=0, rho=None, Ebeta=None, alpha=None, resp=None, nDoc=None, DocTopicCount=None, theta=None, thetaRem=None, ElogPi=None, ElogPiRem=None, sumLogPi=None, sumLogPiRem=None, sumLogPiRemVec=None, Hresp=None, slackTheta=None, slackThetaRem=None, gammalnTheta=None, gammalnSumTheta=None, gammalnThetaRem=None, thetaEmptyComp=None, ElogPiEmptyComp=None, ElogPiOrigComp=None, gammalnThetaOrigComp=None, slackThetaOrigComp=None, returnMemoizedDict=0, **kwargs): """ Calculate ELBO objective terms non-linear in suff stats. """ if resp is not None: N, K = resp.shape elif LP is not None: if 'resp' in LP: N, K = LP['resp'].shape else: N, K = LP['spR'].shape if Ebeta is None: Ebeta = rho2beta(rho, returnSize='K+1') if LP is not None: DocTopicCount = LP['DocTopicCount'] nDoc = DocTopicCount.shape[0] theta = LP['theta'] thetaRem = LP['thetaRem'] ElogPi = LP['ElogPi'] ElogPiRem = LP['ElogPiRem'] sumLogPi = np.sum(ElogPi, axis=0) sumLogPiRem = np.sum(ElogPiRem) if 'thetaEmptyComp' in LP: thetaEmptyComp = LP['thetaEmptyComp'] ElogPiEmptyComp = LP['ElogPiEmptyComp'] ElogPiOrigComp = LP['ElogPiOrigComp'] gammalnThetaOrigComp = LP['gammalnThetaOrigComp'] slackThetaOrigComp = LP['slackThetaOrigComp'] HrespOrigComp = LP['HrespOrigComp'] elif SS is not None: sumLogPi = SS.sumLogPi nDoc = SS.nDoc if hasattr(SS, 'sumLogPiRemVec'): sumLogPiRemVec = SS.sumLogPiRemVec else: sumLogPiRem = SS.sumLogPiRem if DocTopicCount is not None and theta is None: theta = DocTopicCount + alpha * Ebeta[:-1] thetaRem = alpha * Ebeta[-1] if theta is not None and ElogPi is None: digammasumtheta = digamma(theta.sum(axis=1) + thetaRem) ElogPi = digamma(theta) - digammasumtheta[:, np.newaxis] ElogPiRem = digamma(thetaRem) - digammasumtheta[:, np.newaxis] if sumLogPi is None and ElogPi is not None: sumLogPi = np.sum(ElogPi, axis=0) sumLogPiRem = np.sum(ElogPiRem) if Hresp is None: if SS is not None and SS.hasELBOTerm('Hresp'): Hresp = SS.getELBOTerm('Hresp') else: if hasattr(Data, 'word_count') and N == Data.word_count.size: if resp is not None: Hresp = -1 * NumericUtil.calcRlogRdotv( resp, Data.word_count) elif 'resp' in LP: Hresp = -1 * NumericUtil.calcRlogRdotv( LP['resp'], Data.word_count) elif 'spR' in LP: Hresp = calcSparseRlogRdotv( v=Data.word_count, **LP) else: raise ValueError("Missing resp assignments!") else: if resp is not None: Hresp = -1 * NumericUtil.calcRlogR(resp) elif 'resp' in LP: Hresp = -1 * NumericUtil.calcRlogR(LP['resp']) elif 'spR' in LP: assert 'nnzPerRow' in LP Hresp = calcSparseRlogR(**LP) else: raise ValueError("Missing resp assignments!") if slackTheta is None: if SS is not None and SS.hasELBOTerm('slackTheta'): slackTheta = SS.getELBOTerm('slackTheta') slackThetaRem = SS.getELBOTerm('slackThetaRem') else: slackTheta = DocTopicCount - theta slackTheta *= ElogPi slackTheta = np.sum(slackTheta, axis=0) slackThetaRem = -1 * np.sum(thetaRem * ElogPiRem) if gammalnTheta is None: if SS is not None and SS.hasELBOTerm('gammalnTheta'): gammalnSumTheta = SS.getELBOTerm('gammalnSumTheta') gammalnTheta = SS.getELBOTerm('gammalnTheta') gammalnThetaRem = SS.getELBOTerm('gammalnThetaRem') else: sumTheta = np.sum(theta, axis=1) + thetaRem gammalnSumTheta = np.sum(gammaln(sumTheta)) gammalnTheta = np.sum(gammaln(theta), axis=0) gammalnThetaRem = theta.shape[0] * gammaln(thetaRem) if thetaEmptyComp is not None: gammalnThetaEmptyComp = nDoc * gammaln(thetaEmptyComp) - \ gammalnThetaOrigComp slackThetaEmptyComp = -np.sum(thetaEmptyComp * ElogPiEmptyComp) - \ slackThetaOrigComp if returnMemoizedDict: Mdict = dict(Hresp=Hresp, slackTheta=slackTheta, slackThetaRem=slackThetaRem, gammalnTheta=gammalnTheta, gammalnThetaRem=gammalnThetaRem, gammalnSumTheta=gammalnSumTheta) if thetaEmptyComp is not None: Mdict['HrespEmptyComp'] = -1 * HrespOrigComp Mdict['gammalnThetaEmptyComp'] = gammalnThetaEmptyComp Mdict['slackThetaEmptyComp'] = slackThetaEmptyComp return Mdict # First, compute all local-only terms Lentropy = np.sum(Hresp) Lslack = slackTheta.sum() + slackThetaRem LcDtheta = -1 * (gammalnSumTheta - gammalnTheta.sum() - gammalnThetaRem) # For stochastic (soVB), we need to scale up these terms # Only used when --doMemoELBO is set to 0 (not recommended) if SS is not None and SS.hasAmpFactor(): Lentropy *= SS.ampF Lslack *= SS.ampF LcDtheta *= SS.ampF # Next, compute the slack term alphaEbeta = alpha * Ebeta Lslack_alphaEbeta = np.sum(alphaEbeta[:-1] * sumLogPi) if sumLogPiRemVec is not None: Ebeta_gt = 1 - np.cumsum(Ebeta[:-1]) Lslack_alphaEbeta += alpha * np.inner(Ebeta_gt, sumLogPiRemVec) else: Lslack_alphaEbeta += alphaEbeta[-1] * sumLogPiRem Lslack += Lslack_alphaEbeta if todict: return dict( Lslack=Lslack, Lentropy=Lentropy, LcDtheta=LcDtheta, Lslack_alphaEbeta=Lslack_alphaEbeta) return LcDtheta + Lslack + Lentropy