Слой потерь среднеквадратичной ошибки Кераса

В настоящее время я реализую настраиваемый уровень потерь и в процессе я наткнулся на реализацию среднеквадратичной ошибки в файле objects.py [1]. Я знаю, что мне что-то не хватает в моем понимании этого расчета потерь, потому что я всегда думал, что среднее значение было сделано отдельно по выборкам для каждого вывода в каждой мини-партии (ось 0 тензора), но похоже, что среднее значение на самом деле выполняется по последней оси, что в одном векторе, означало бы, что это выполняется по выходам. Я обнаружил это случайно, когда работал над своим настраиваемым слоем потерь, потому что он требует дисконтирования потери некоторых выходных данных, если тренировочный выход в определенном месте имеет определенное значение. В любом случае, я неверно понимаю среднеквадратичную ошибку? Почему Керас использовал последнюю ось и, таким образом, превращал выходной вектор 1xn в выходной вектор 1x1?

Спасибо.

[1] https://github.com/fchollet/keras/blob/master/keras/objectives.py#L7


person Corey J. Nolet    schedule 17.01.2017    source источник
comment
Как вы думаете, что означает K.mean? :)   -  person Dr. Snoopy    schedule 18.01.2017
comment
Извините - я скорректировал свой вопрос. Я имел в виду, что я не видел, где происходит возведение в квадрат, а не среднее значение.   -  person Corey J. Nolet    schedule 18.01.2017
comment
Это будет K.square   -  person Dr. Snoopy    schedule 18.01.2017
comment
Вы прочитали весь мой вопрос?   -  person Corey J. Nolet    schedule 18.01.2017
comment
Да, но в любом случае здесь есть несколько вопросов, я просто указал на один.   -  person Dr. Snoopy    schedule 18.01.2017
comment
Я не спрашиваю, как вычислить квадрат, я спрашиваю, почему функция MSE по умолчанию, которая предоставляется в структуре, не вычисляет возведение в квадрат, когда она называется среднеквадратической ошибкой. Я не вижу места в вычислении, где возведение в квадрат сделано. Я знаю, как вычислить квадрат, я хочу знать, почему автор этого кода не сделал этого.   -  person Corey J. Nolet    schedule 18.01.2017


Ответы (3)


Рассматриваемый код потери MSE следующий:

def mean_squared_error(y_true, y_pred):
    return K.mean(K.square(y_pred - y_true), axis=-1)

Здесь сначала вычитаются y_pred и y_true, затем этот результат передается в K.square, которая, как и ожидалось, возвращает квадрат своего параметра, а затем этот результат передается в K.mean, которая вычисляет среднее значение.

Итак, код явно делает то, что должен делать. О том, почему используется последняя ось, это не имеет ничего общего с классами, это просто соглашение. Обратите внимание, что в общем случае в определении MSE нет классов.

person Dr. Snoopy    schedule 17.01.2017
comment
Ах, вы правы, что я пропустил K.square в коде. Вупс. Я нахожусь в частной сети, и, к сожалению, я не могу скопировать / вставить код, и мне приходится его вручную замораживать. В данном случае я неправильно его заклинил. Таким образом, вы правы относительно последнего вопроса, который я задал в конце. - person Corey J. Nolet; 18.01.2017
comment
Кстати, спасибо за ответ! Однако ось на самом деле является причиной моего вопроса. На самом деле для меня очень важно, что они используют axis = -1 вместо axis = 0, и причина этого в том, что они определяют тензоры, которые проходят через сеть. Они заставляют вас использовать размер пакета в качестве первого измерения тензора, а для одного набора значений в векторе в качестве выходных данных заставляют это быть последним измерением. Это означает, что они несут убытки по всем этим выходам, а не по каждому отдельному результату. - person Corey J. Nolet; 18.01.2017
comment
Я знаю, что сделал не так при копировании. Я случайно скопировал mean_absolute_error вместо mean_squared. Эта часть исправлена, но проблема с осью все еще меня беспокоит. - person Corey J. Nolet; 18.01.2017
comment
Что ты имеешь в виду? @Cor - person Nima Mousavi; 04.02.2018
comment
Что ты имеешь в виду? @ CoreyJ.Нолет абсолютно прав. Среднее значение следует взять по партиям. Почему ось = -1? - person Nima Mousavi; 04.02.2018

Давайте подробно рассмотрим этапы вычисления потерь в Keras, чтобы показать, что axis=-1 во всех вычислениях потерь верны:

  • Итак, мы выбираем убыток в loss.py что мы перейдем к compile методу нашей модели.

  • В compile вычисляются общие потери. Это происходит в несколько этапов: Первый шаг создает список потерь, по одному для каждого выхода модели.

  • Этот первый шаг вызывает _weighted_masked_objective, который в соответствии с документами «Добавляет поддержку маскирования и взвешивания выборки для целевой функции»
  • По сути, _weighted_masked_objective возвращает новые целевые функции, которые учитывают параметры weights и mask, которые пользователь предоставит при использовании метода fit.

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

def _weighted_masked_objective(fn):
    def weighted(y_true, y_pred, weights, mask=None):
          score_array = fn(y_true, y_pred) # Compute loss as in losses.py
          return K.mean(score_array) # Average over all axis

class Model(Container):
    def compile(self, optimizer, loss, metrics=None, loss_weights=None,
                sample_weight_mode=None, weighted_metrics=None,
                target_tensors=None, **kwargs):
        weighted_losses = [_weighted_masked_objective(fn) for fn in loss_functions]

Итак, в конце потеря действительно усредняется по каждому измерению, и использование axis=-1 - просто элегантный способ включить маскировку и взвешивание потерь в другой точке кода.

NB: Я не объяснил другие шаги, потому что они не помогают ответить на вопрос.

person mpariente    schedule 11.02.2018

Я считаю, что после некоторых разговоров с коллегами я понимаю эту ситуацию и могу найти правильное решение проблемы. Хотя я знал, что Theano предоставлял тензорные функции с отложенным вычислением, которые запускали матричные операции на GPU, я не понимал, что функции потерь Кераса на самом деле написаны таким образом, что скомпилированный граф выполнения theano достаточно умен, чтобы кэшировать определенные значений для правильного обратного распространения значений потерь обратно по сети. Из-за типа сети, которую я создаю, я погрузился в написание моей собственной функции потерь, не полностью понимая, как Theano на самом деле обрабатывает потерю после того, как она была рассчитана функцией.

Насколько я могу судить, мое беспокойство было правильным, что использование Керасом последней оси является проблемой. В моем случае у меня есть полностью сверточная глубокая нейронная сеть, и входными данными для функции потерь являются (x, 7, 16, 16), где x - размер мини-пакета. Обычно нейронные сети выводят матрицу, в которой первое измерение - это размер мини-пакета, а второе (обычно последнее) измерение - это фактический размер выходного вектора. Из-за этого использование последней оси в выходном тензоре для получения фактической «средней» части среднеквадратичной ошибки некорректно. Вместо этого ось должна быть 1 (в случае индексации с нуля), потому что это 7 фактических выходных функций регрессии, которые необходимо дифференцировать для обратного распространения.

Изначально я знал, что ось = -1 может быть неправильной, и причина, по которой я разместил этот вопрос, заключалась в том, что я не мог полностью объяснить, почему. Прошло много времени с тех пор, как мне пришлось погрузиться в математику, лежащую в основе нейронных сетей, но когда я наконец это сделал, я смог устранить пробелы (Я думаю). Я отправляю этот ответ здесь для будущих людей, которые могут столкнуться с той же проблемой или пробелом в понимании тензорной структуры Теано.

person Corey J. Nolet    schedule 18.01.2017