Модели Seq2Seq и функции потерь (в керасах)

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

Например :

For given vector :
[2, #start token
3,
123,
1548, #end token
1548,
1548,
1548,
1548,
1548,
1548]

The model predict :
[1548, 
1548,
1548,
1548,
1548,
1548,
1548,
1548,
1548,
1548]

я пытался использовать обратный вызов SaveModel от keras, который отслеживает «потери», но он все еще дает тот же результат.

поэтому я понимаю, что, возможно, мне следует использовать свою собственную функцию потерь.

простая функция потерь, которую предоставляет keras:

def mean_absolute_error(y_true, y_pred):
    return K.mean(K.abs(y_pred - y_true), axis=-1)

и y_true, и y_pred являются объектами тензорного потока (мы получаем только указатель на реальный массив), поэтому ... для создания некоторой логики нам нужно получить массив из графического процессора или загрузить свой собственный массив в графический процессор.

моя разыскиваемая функция потери

def mean_absolute_error(y_true, y_pred):
    sum = 0
    for y , _y in zip(y_true , y_pred):
         if (y == _y) and (y == self.startToken or y == self.endToken):
              continue
         else:
              sum += abs(y - _y)
    return sum

я пытался использовать y_true.eval(), который должен передать массив как объект numpy в процессор (невозможно оценить тензор с помощью eval(): сеанс по умолчанию не зарегистрирован)

и мне не удалось найти, как загрузить свой собственный массив в tensorflow.

если у вас есть решение или какое-либо предложение, я буду более чем рад услышать об этом.

Спасибо..

(не столь важно, но...)

Модель основана на: https://blog.keras.io/a-ten-minute-introduction-to-sequence-to-sequence-learning-in-keras.html , но с одним горячим (двумя тусклыми [Matrix] ) выход.


person Ori Yampolsky    schedule 25.03.2018    source источник
comment
В предоставленной вами ссылке они перестают прогнозировать после того, как увидят конечный токен; в частности, в функции decode_sequence: # Exit condition: either hit max length or find stop character. Они также предварительно заполняют выходной массив модели начальным символом: # Populate the first character of target sequence with the start character. Мне интересно, используете ли вы функцию, аналогичную их функции decode_sequence?   -  person vasilyrud    schedule 26.03.2018
comment
нет, это можно сделать намного проще с помощью: model.predict([x,x])   -  person Ori Yampolsky    schedule 26.03.2018
comment
Хотя это может быть причиной проблемы. Попробуйте точно следовать их функции decode_sequence и сначала посмотрите, сработает ли это. Возможно, это единственный способ предсказать последовательную последовательность в Керасе.   -  person vasilyrud    schedule 26.03.2018
comment
я уже проверил это..то же самое..   -  person Ori Yampolsky    schedule 27.03.2018


Ответы (1)


Использование K.eval или if в функциях потерь не является хорошей идеей. Вся идея тензоров заключается в том, что у них есть внутреннее соединение, управляемое tensorflow/keras, с помощью которого можно вычислять градиенты и другие вещи.

Использование eval и работа со значениями numpy разорвут эту связь и испортят модель. Используйте eval только для просмотра результатов, а не для создания функций.

Использование ifs не будет работать, потому что значения тензора недоступны. Но есть функции keras, такие как K.switch, K.greater, K.less и т. д., все они перечислены в бэкенд-документации. .

Вы можете воссоздать свою функцию, используя эти функции.

Но, честно говоря, я думаю, что вместо этого вам следует использовать маскировку или взвешивание классов.

Маскировка (решение 1)

Если вы используете встраивание слоев, вы можете намеренно зарезервировать нулевые значения после окончания.

Затем вы можете использовать mask_zero=True во встраиваемых слоях и иметь входные данные, подобные этому:

[2, #start token
3,
123,
1548, #end token
0, #nothing, value to be masked
0,
0,
0,
0,
0]

Другой вариант — не иметь конечного токена и использовать вместо него ноль.

Взвешивание классов (решение 2)

Поскольку это, скорее всего, происходит из-за того, что у вас гораздо больше конечных токенов, чем чего-либо еще в желаемых выходных данных, вы можете уменьшить релевантность конечных токенов.

Подсчитайте вхождения каждого класса в ваших выходных данных и рассчитайте соотношение для конечных токенов. Пример:

  • Вычислить среднее значение вхождений всех других классов
  • Подсчитайте вхождения конечного токена
  • ratio = other_classes_mean / end_token_occurences

Затем в методе fit используйте:

class_weight = {0:1, 1:1, 2:1, ...., 1548:ratio, 1549:1,1550:1,...}

Легко выполнимо с:

class_weight = {i:1. for i in range(totalTokens)}
class_weight[1548] = ratio
model.fit(...,...,....., class_weight = class_weight,...)

(Убедитесь, что в этом случае у вас есть 0 как возможный класс, или сдвиньте индексы на 1)

Аналогичная функция потерь (решение 3)

Обратите внимание, что y_pred никогда не будет равно y_true.

  • y_pred является переменным, непрерывным и дифференцируемым
  • y_true является точным и постоянным

Для сравнения следует взять argmax, который очень похож (если не совсем) на индекс класса.

def mean_absolute_error(y_true, y_pred):

    #for comparing, let's take exact values
    y_true_max = K.argmax(y_true)
    y_pred_max = K.argmax(y_pred)

    #compare with a proper tensor function
    equal_mask = K.equal(y_true_max,y_pred_max)
    is_start = K.equal(y_true_max, self.startTokenAsIndex)
    is_end = K.equal(y_true_max, self.endTokenAsIndex)

    #cast to float for multiplying and summing
    equal_mask = K.cast(equal_mask, K.floatx()) 
    is_start = K.cast(is_start, K.floatx())
    is_end = K.cast(is_end, K.floatx())
        #these are tensors with 0 (false) and 1 (true) as float
    
    #entire condition as you wanted
    condition = (is_start + is_end) * equal_mask
        # sum = or ||| multiply = and
        # we don't have to worry about the sum resulting in 2
            # because you will never have startToken == endToken

    #reverse condition:
    condition = 1 - condition

    #result
    return condition * K.mean(K.abs(y_pred - y_true), axis=-1)
person Daniel Möller    schedule 02.04.2018
comment
вау, чувак, ты потрясающий .. я никогда не знал о вариантах веса. и я хотел иметь некоторую опору на стороне сервера Keras, так что вы мне очень помогаете... спасибо. - person Ori Yampolsky; 03.04.2018