Изучение дискретных параметров HMM в PyMC

Я пытаюсь узнать параметры простого дискретного HMM, используя PyMC. Я моделирую дождливо-солнечную модель со страницы Wiki на HMM. Модель выглядит следующим образом:

Я использую следующие приоры.

theta_start_state ~ beta(20,10)
theta_transition_rainy ~beta(8,2)
theta_transition_sunny ~beta(2,8)
theta_emission_rainy ~ Dirichlet(3,4,3)
theta_emission_sunny ~ Dirichlet(10,6,4)

Первоначально я использую эту настройку для создания тренировочного набора следующим образом.

## Some not so informative priors!
# Prior on start state
theta_start_state = pm.Beta('theta_start_state',12,8)

# Prior on transition from rainy
theta_transition_rainy = pm.Beta('transition_rainy',8,2)

# Prior on transition from sunny
theta_transition_sunny = pm.Beta('transition_sunny',2,8)

# Prior on emission from rainy
theta_emission_rainy = pm.Dirichlet('emission_rainy',[3,4,3])

# Prior on emission from sunny
theta_emission_sunny = pm.Dirichlet('emission_sunny',[10,6,4])

# Start state
x_train_0 = pm.Categorical('x_0',[theta_start_state, 1-theta_start_state])

N = 100

# Create a train set for hidden states
x_train = np.empty(N, dtype=object)

# Creating a train set of observations
y_train = np.empty(N, dtype=object)

x_train[0] = x_train_0

for i in xrange(1, N):
    if x_train[i-1].value==0:
        x_train[i] = pm.Categorical('x_train_%d'%i,[theta_transition_rainy, 1- theta_transition_rainy])
    else:
        x_train[i] = pm.Categorical('x_train_%d'%i,[theta_transition_sunny, 1- theta_transition_sunny])


for i in xrange(0,N):
    if x_train[i].value == 0:
        # Rain
        y_train[i] = pm.Categorical('y_train_%d' %i, theta_emission_rainy)
    else:
        y_train[i] = pm.Categorical('y_train_%d' %i, theta_emission_sunny)

Однако я не могу понять, как узнать эти параметры с помощью PyMC. Я начал следующим образом.

@pm.observed
def y(x=x_train, value =y_train):    
    N = len(x)    
    out = np.empty(N, dtype=object)
    for i in xrange(0,N):
        if x[i].value == 0:
            # Rain
            out[i] = pm.Categorical('y_%d' %i, theta_emission_rainy)
        else:
            out[i] = pm.Categorical('y_%d' %i, theta_emission_sunny)
    return out

Полный блокнот, содержащий этот код, можно найти здесь.

Кроме того: суть, содержащая код HMM для гауссова, действительно трудно понять! (не задокументировано)

Обновлять

Основываясь на приведенных ниже ответах, я попытался изменить свой код следующим образом:

@pm.stochastic(observed=True)
def y(value=y_train, hidden_states = x_train):
    def logp(value, hidden_states):
        logprob = 0 
        for i in xrange(0,len(hidden_states)):
            if hidden_states[i].value == 0:
                # Rain
                logprob = logprob + pm.categorical_like(value[i], theta_emission_rainy)
            else:
                # Sunny
                logprob = logprob + pm.categorical_like(value[i], theta_emission_sunny)
        return logprob 

Следующим шагом будет создание модели, а затем запуск алгоритма MCMC. Однако приведенный выше отредактированный код также не будет работать. Это дает ZeroProbability error.

Я не уверен, правильно ли я интерпретировал ответы.


person Nipun Batra    schedule 04.05.2014    source источник
comment
Как вы сделали графическое отображение модели?   -  person ColinMac    schedule 05.01.2019


Ответы (2)


Просто некоторые мысли по этому поводу:

  • Солнечно и Дождливо — взаимоисключающие и исчерпывающие скрытые состояния. Почему бы вам не закодировать их как единую категориальную переменную погоды, которая может принимать одно из двух значений (кодирование для солнечного или дождливого)?
  • В вашей функции правдоподобия вы, кажется, наблюдаете Дождливое/Солнечное время. Как я вижу это на графике вашей модели, это скрытые, а не наблюдаемые переменные (это будут «прогулка», «магазин» и «уборка»)

В вашей функции правдоподобия вам необходимо суммировать (для всех временных шагов t) логарифмическую вероятность наблюдаемых значений (ходьбы, магазина и уборки соответственно) с учетом текущих (выборочных) значений дождя/ солнечно (т. е. Погода) в то же время шаг t.

Обучение

Если вы хотите изучить параметры модели, вы можете подумать о переходе на PyMC3, который лучше подходит для автоматического вычисления градиентов для вашей функции logp. Но в этом случае (поскольку вы выбрали сопряженные априоры) в этом нет необходимости. Если вы не знаете, что такое сопряженные приоры, или вам нужен обзор, спросите в Википедии Список сопряженных приоров, там есть отличная статья на эту тему.

В зависимости от того, что вы хотите сделать, у вас есть несколько вариантов. Если вы хотите получить выборку из апостериорного распределения всех параметров, просто укажите свою модель MCMC, как вы это сделали, и нажмите кнопку вывода, после этого просто постройте и суммируйте маргинальные распределения интересующих вас параметров, и все готово. .

Если вы заинтересованы не в маргинальных апостериорных распределениях, а скорее в поиске параметров совместного MAP, вы можете рассмотреть возможность использования обучения максимизации ожидания (EM) или имитации отжига. Оба должны работать достаточно хорошо в рамках MCMC Framework.

Для EM Learning просто повторяйте эти шаги до конвергенции:

  • E (Ожидаемый) шаг: запустите цепочку MCMC на некоторое время и соберите образцы
  • Шаг M (Максимизация): обновите гиперпараметры для ваших бета-приоритетов и априорных значений Дирихле, как если бы эти выборки были реальными наблюдениями. Посмотрите бета-версии и дистрибутивы Дирихле, если вы не знаете, как это сделать.

Я бы использовал небольшой коэффициент скорости обучения, чтобы вы не попали в первый локальный оптимум (теперь мы приближаемся к моделируемому отжигу): вместо обработки N выборок, сгенерированных вами из цепочки MCMC, как реальных наблюдений, обрабатывайте их как K наблюдений. (для значения K ‹‹ N) путем масштабирования обновлений гиперпараметров на коэффициент скорости обучения K/N.

person Kai Londenberg    schedule 06.05.2014
comment
Я бы сказал, что солнце и дождь не являются несовместимыми друг с другом — я знаю, что это немного преувеличено, но это правда. - person Nick Dickinson-Wilde; 07.05.2014
comment
Спасибо. Я обновил свой ответ на основе вашего предложения, и у меня все еще возникают проблемы. - person Nipun Batra; 07.05.2014

Первое, что мне приходит в голову, — это возвращаемое значение вашей вероятности. PyMC ожидает скалярное возвращаемое значение, а не список/массив. Вам нужно суммировать массив перед его возвратом.

Кроме того, когда вы используете Дирихле в качестве априора для категориального, PyMC обнаруживает это и заполняет последнюю вероятность. Вот как я бы закодировал ваши циклы x_train/y_train:

p = []
for i in xrange(1, N):
    # This will return the first variable if prev=0, and the second otherwise
    p.append(pm.Lambda('p_%i' % i, lambda prev=x_train[i-1]: (theta_transition_rainy, theta_transition_sunny)[bool(prev)]))
    x_train[i] = pm.Categorical('x_train_%i' % i, p[-1])

Итак, вы берете соответствующие вероятности с помощью лямбды и используете ее в качестве аргумента для категориального.

person Chris Fonnesbeck    schedule 06.05.2014
comment
Спасибо за ответ Крис. Моя главная проблема заключается в том, как подходить к изучению параметров HMM, когда задана последовательность наблюдений «y», а также априорные значения. - person Nipun Batra; 06.05.2014
comment
Используя цикл x_train, как вы предложили, я получаю следующую ошибку ZeroProbability: Stochastic x_train_47's value is outside its support, or it forbids its parents' current values. Этого не происходит, если я использую цикл, как в моем вопросе. - person Nipun Batra; 07.05.2014
comment
Я обновил свой вопрос, пытаясь добавить термин logp. Все равно заканчиваются ошибками. - person Nipun Batra; 07.05.2014
comment
Ошибки ZeroProbability указывают на то, что значение, которым вы инициализируете стохастические параметры, выходит за пределы указанной поддержки этой переменной. - person Chris Fonnesbeck; 10.05.2014
comment
Как можно иметь дело с тем же. Я получил ту же ошибку, когда попытался запустить ваш код HMM по существу без каких-либо изменений! - person Nipun Batra; 14.05.2014