Код, который вы опубликовали, касается моделей с несколькими выходами, где каждый выход может иметь свои собственные потери и веса. Следовательно, значения потерь разных выходных слоев суммируются вместе. Тем не менее, отдельные потери усредняются по партии , как вы можете видеть в файле loss.py . Например, это код, связанный с двоичной кросс-энтропийной потерей:
def binary_crossentropy(y_true, y_pred):
return K.mean(K.binary_crossentropy(y_true, y_pred), axis=-1)
Обновление: Сразу после добавления второй части этого ответа (т.е. функций потерь) в качестве ОП я был озадачен axis=-1
в определении функции потерь, и я подумал про себя что это должно быть axis=0
, чтобы указать среднее значение по партии ?! Затем я понял, что все K.mean()
, используемые в определении функции потерь, существуют для случая выходного слоя, состоящего из нескольких единиц. Так, где потеря усреднена по партии? Я проверил код, чтобы найти ответ: чтобы получить значение потерь для определенной функции потерь, функция называется , принимая в качестве входных данных истинные и предсказанные метки, а также веса выборки и маску:
weighted_loss = weighted_losses[i]
# ...
output_loss = weighted_loss(y_true, y_pred, sample_weight, mask)
что это за функция weighted_losses[i]
? Как вы можете заметить, это элемент списка (дополненных) функций потерь :
weighted_losses = [
weighted_masked_objective(fn) for fn in loss_functions]
fn
на самом деле является одной из функций потерь, определенных в файле loss.py , или это может быть пользовательская пользовательская функция потерь. А теперь, что это за функция weighted_masked_objective
? Он был определен в training_utils.py файле:
def weighted_masked_objective(fn):
"""Adds support for masking and sample-weighting to an objective function.
It transforms an objective function `fn(y_true, y_pred)`
into a sample-weighted, cost-masked objective function
`fn(y_true, y_pred, weights, mask)`.
# Arguments
fn: The objective function to wrap,
with signature `fn(y_true, y_pred)`.
# Returns
A function with signature `fn(y_true, y_pred, weights, mask)`.
"""
if fn is None:
return None
def weighted(y_true, y_pred, weights, mask=None):
"""Wrapper function.
# Arguments
y_true: `y_true` argument of `fn`.
y_pred: `y_pred` argument of `fn`.
weights: Weights tensor.
mask: Mask tensor.
# Returns
Scalar tensor.
"""
# score_array has ndim >= 2
score_array = fn(y_true, y_pred)
if mask is not None:
# Cast the mask to floatX to avoid float64 upcasting in Theano
mask = K.cast(mask, K.floatx())
# mask should have the same shape as score_array
score_array *= mask
# the loss per batch should be proportional
# to the number of unmasked samples.
score_array /= K.mean(mask)
# apply sample weighting
if weights is not None:
# reduce score_array to same ndim as weight array
ndim = K.ndim(score_array)
weight_ndim = K.ndim(weights)
score_array = K.mean(score_array,
axis=list(range(weight_ndim, ndim)))
score_array *= weights
score_array /= K.mean(K.cast(K.not_equal(weights, 0), K.floatx()))
return K.mean(score_array)
return weighted
Как видите, сначала потери на выборку вычисляются в строке score_array = fn(y_true, y_pred)
, а затем в конце возвращается среднее значение потерь, то есть return K.mean(score_array)
. Таким образом, это подтверждает, что заявленные потери являются средними потерями на образец в каждой партии.
Обратите внимание, что K.mean()
, в случае использования Tensorflow в качестве бэкэнда, вызывает функцию tf.reduce_mean()
. Теперь, когда K.mean()
вызывается без аргумента axis
(значение по умолчанию axis
аргумент будет None
), как это вызывается в функции weighted_masked_objective
, соответствующий вызов tf.reduce_mean()
вычисляет среднее значение по всем осям и возвращает одно значение . Поэтому, независимо от формы выходного слоя и используемой функции потерь, Keras использует и сообщает только одно значение потерь (и так должно быть, потому что алгоритмы оптимизации должны минимизировать скалярное значение, а не вектор или тензор) .