(means1_N_D, stdevs1_N_D, means2_N_D, stdevs2_N_D)
return .5 * (
        np.square(stdevs1_N_D/stdevs2_N_D).sum(axis=1) +
        np.square((means2_N_D-means1_N_D)/stdevs2_N_D).sum(axis=1) +
        2.*(np.log(stdevs2_N_D).sum(axis=1) - np.log(stdevs1_N_D).sum(axis=1)) - D
    )
KL divergences between Gaussians with diagonal covariances
    Covariances matrices are specified with square roots of the diagonal (standard deviations)
KL divergences between Gaussians with diagonal covariances
    Covariances matrices are specified with square roots of the diagonal (standard deviations)
KL divergences between Gaussians with diagonal covariances Covariances matrices are specified with square roots of the diagonal ( standard deviations )
def gaussian_kl(means1_N_D, stdevs1_N_D, means2_N_D, stdevs2_N_D):
    '''
    KL divergences between Gaussians with diagonal covariances
    Covariances matrices are specified with square roots of the diagonal (standard deviations)
    '''
    assert means1_N_D.shape == stdevs1_N_D.shape == means2_N_D.shape == stdevs2_N_D.shape
    N, D = means1_N_D.shape

    return .5 * (
        np.square(stdevs1_N_D/stdevs2_N_D).sum(axis=1) +
        np.square((means2_N_D-means1_N_D)/stdevs2_N_D).sum(axis=1) +
        2.*(np.log(stdevs2_N_D).sum(axis=1) - np.log(stdevs1_N_D).sum(axis=1)) - D
    )
def gaussian_kl ( means1_N_D , stdevs1_N_D , means2_N_D , stdevs2_N_D ) : assert means1_N_D . shape == stdevs1_N_D . shape == means2_N_D . shape == stdevs2_N_D . shape N , D = means1_N_D . shape return .5 * ( np . square ( stdevs1_N_D / stdevs2_N_D ) . sum ( axis = 1 ) + np . square ( ( means2_N_D - means1_N_D ) / stdevs2_N_D ) . sum ( axis = 1 ) + 2. * ( np . log ( stdevs2_N_D ) . sum ( axis = 1 ) - np . log ( stdevs1_N_D ) . sum ( axis = 1 ) ) - D )