KL-расхождение двух ОММ

У меня есть два GMM, которые я использовал для размещения двух разных наборов данных в одном и том же пространстве, и я хотел бы рассчитать KL-расхождение между ними.

В настоящее время я использую GMM, определенные в sklearn (http://scikit-learn.org/stable/modules/generated/sklearn.mixture.GMM.html) и реализацию KL-расхождения SciPy (http://docs.scipy.org/doc/scipy-dev/reference/generated/scipy.stats.entropy.html)

Как мне это сделать? Хочу ли я просто создать множество случайных точек, получить их вероятности для каждой из двух моделей (назовем их P и Q), а затем использовать эти вероятности в качестве входных данных? Или есть более канонический способ сделать это в среде SciPy/SKLearn?


person Andrew Latham    schedule 27.09.2014    source источник
comment
Закрытой формы не существует. Взгляните на эту статью, чтобы получить приблизительное представление об этом. scholar.google.co.kr/   -  person emeth    schedule 28.09.2014


Ответы (1)


Не существует закрытой формы расхождения KL между GMM. Однако вы можете легко сделать Монте-Карло. Напомним, что KL(p||q) = \int p(x) log(p(x) / q(x)) dx = E_p[ log(p(x) / q(x)). Так:

def gmm_kl(gmm_p, gmm_q, n_samples=10**5):
    X = gmm_p.sample(n_samples)
    log_p_X, _ = gmm_p.score_samples(X)
    log_q_X, _ = gmm_q.score_samples(X)
    return log_p_X.mean() - log_q_X.mean()

(mean(log(p(x) / q(x))) = mean(log(p(x)) - log(q(x))) = mean(log(p(x))) - mean(log(q(x))) несколько дешевле в вычислительном отношении.)

Вы не хотите использовать scipy.stats.entropy; это для дискретных дистрибутивов.

Если вместо этого вам нужна симметричная и сглаженная дивергенция Дженсена-Шеннона KL(p||(p+q)/2) + KL(q||(p+q)/2), она очень похожа:

def gmm_js(gmm_p, gmm_q, n_samples=10**5):
    X = gmm_p.sample(n_samples)
    log_p_X, _ = gmm_p.score_samples(X)
    log_q_X, _ = gmm_q.score_samples(X)
    log_mix_X = np.logaddexp(log_p_X, log_q_X)

    Y = gmm_q.sample(n_samples)
    log_p_Y, _ = gmm_p.score_samples(Y)
    log_q_Y, _ = gmm_q.score_samples(Y)
    log_mix_Y = np.logaddexp(log_p_Y, log_q_Y)

    return (log_p_X.mean() - (log_mix_X.mean() - np.log(2))
            + log_q_Y.mean() - (log_mix_Y.mean() - np.log(2))) / 2

(log_mix_X/log_mix_Y на самом деле являются логарифмом удвоенных плотностей смеси; выведение этого из средней операции экономит несколько провалов.)

person Danica    schedule 27.09.2014
comment
Привет, Дугал, я пытаюсь использовать функцию gym_js, которую вы определили, чтобы выяснить надежность моей модели, но не уверен, что здесь делает n_samples и как интерпретировать возвращаемое значение? Если я использую весь набор данных, который у меня есть, чтобы создать модели gmm_p и gmm_q с одинаковым количеством кластеров и передать их в эту функцию, могу ли я подтвердить надежность моей модели на основе метрики js здесь? Спасибо. - person Mojgan Mazouchi; 18.06.2019
comment
Я пришел сюда, чтобы посмотреть, смогу ли я рассчитать расхождение js между двумя дистрибутивами, и похоже, что смогу (код, адаптированный из этого ответа, лежит здесь в качестве ответа: stats.stackexchange.com/questions/345915/) - person Holi; 27.07.2019