Использование CNTK для генерации последовательности путем выборки на каждом этапе генерации

В модели seq2seq с кодером и декодером на каждом этапе генерации уровень softmax выводит распределение по всему словарю. В CNTK можно легко реализовать жадный декодер с помощью функции C.hardmax. Это выглядит так.

def create_model_greedy(s2smodel):
    # model used in (greedy) decoding (history is decoder's own output)
    @C.Function
    @C.layers.Signature(InputSequence[C.layers.Tensor[input_vocab_dim]])
    def model_greedy(input): # (input*) --> (word_sequence*)
        # Decoding is an unfold() operation starting from sentence_start.
        # We must transform s2smodel (history*, input* -> word_logp*) into a generator (history* -> output*)
        # which holds 'input' in its closure.
        unfold = C.layers.UnfoldFrom(lambda history: s2smodel(history, input) >> **C.hardmax**,
                                     # stop once sentence_end_index was max-scoring output
                                     until_predicate=lambda w: w[...,sentence_end_index],
                                     length_increase=length_increase)
        return unfold(initial_state=sentence_start, dynamic_axes_like=input)
    return model_greedy

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

Как я могу это сделать? Любая помощь приветствуется. Спасибо.


person meijiesky    schedule 14.08.2017    source источник


Ответы (2)


Вы можете просто добавить шум к выходам, прежде чем брать хардмакс. В частности, вы можете использовать C.random.gumbel или C.random.gumbel_like для выборки пропорционально exp(output). Это известно как трюк с гамбель-максом. Модуль cntk.random также содержит другие дистрибутивы, но если у вас есть вероятности журнала вы, скорее всего, захотите добавить шум гамбеля перед хардмаксом. Некоторый код:

@C.Function
def randomized_hardmax(x):
    noisy_x = x + C.random.gumbel_like(x)
    return C.hardmax(noisy_x)

Затем замените свой hardmax на randomized_hardmax.

person Nikos Karampatziakis    schedule 16.08.2017
comment
У меня нет 15 репутации в этой новой учетной записи ... Я сейчас в Китае и не могу войти в свою учетную запись Gmail или использовать учетную запись facebook. Я поддержу ваш ответ, как только вернусь в США. Еще раз спасибо. - person meijiesky; 18.08.2017

Большое спасибо Никосу Карампациакису.

Следующий код работает, если вы хотите иметь декодер стохастической выборки, который генерирует последовательность той же длины, что и ваша целевая последовательность.

@C.Function
def sampling(x):
    noisy_x = x + C.random.gumbel_like(x)
    return C.hardmax(noisy_x)

def create_model_sampling(s2smodel):
    @C.Function
    @C.layers.Signature(input=InputSequence[C.layers.Tensor[input_vocab_dim]],
                        labels=LabelSequence[C.layers.Tensor[label_vocab_dim]])
    def model_sampling(input, labels): # (input*) --> (word_sequence*)
        unfold = C.layers.UnfoldFrom(lambda history: s2smodel(history, input) >> sampling,
                                     length_increase=1)
        return unfold(initial_state=sentence_start, dynamic_axes_like=labels)
    return model_sampling
person meijiesky    schedule 17.08.2017