расчет потерь по разным размерам партии в кера - PullRequest
0 голосов
/ 04 сентября 2018

Я знаю, что теоретически потеря сети за один пакет - это просто сумма всех индивидуальных потерь. Это отражено в коде Keras для расчета общего убытка. Нелишне:

            for i in range(len(self.outputs)):
            if i in skip_target_indices:
                continue
            y_true = self.targets[i]
            y_pred = self.outputs[i]
            weighted_loss = weighted_losses[i]
            sample_weight = sample_weights[i]
            mask = masks[i]
            loss_weight = loss_weights_list[i]
            with K.name_scope(self.output_names[i] + '_loss'):
                output_loss = weighted_loss(y_true, y_pred,
                                            sample_weight, mask)
            if len(self.outputs) > 1:
                self.metrics_tensors.append(output_loss)
                self.metrics_names.append(self.output_names[i] + '_loss')
            if total_loss is None:
                total_loss = loss_weight * output_loss
            else:
                total_loss += loss_weight * output_loss

Однако я заметил, что когда я тренирую сеть с batch_size=32 и batch_size=64, значение потерь для каждой эпохи все равно оказывается более или менее одинаковым только с разницей ~0.05%. Однако точность для обеих сетей оставалась одинаковой. Таким образом, размер пакета не оказал слишком большого влияния на сеть.

Мой вопрос: когда я удваиваю размер партии, предполагая, что потеря действительно суммируется, разве потеря не должна быть вдвое больше, чем она была ранее, или, по крайней мере, больше? Оправдание о том, что сеть, вероятно, научилась лучше с большим размером пакета, сводится на нет тем фактом, что точность осталась прежней.

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

1 Ответ

0 голосов
/ 04 сентября 2018

Код, который вы опубликовали, касается моделей с несколькими выходами, где каждый выход может иметь свои собственные потери и веса. Следовательно, значения потерь разных выходных слоев суммируются вместе. Тем не менее, отдельные потери усредняются по партии , как вы можете видеть в файле 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 использует и сообщает только одно значение потерь (и так должно быть, потому что алгоритмы оптимизации должны минимизировать скалярное значение, а не вектор или тензор) .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...