Почему я получаю разные значения между функциями потерь и метриками в TensorFlow Keras? - PullRequest
0 голосов
/ 21 февраля 2019

В моей тренировке CNN с использованием TensorFlow я использую Keras.losses.poisson в качестве функции потери.Теперь мне нравится вычислять множество метрик наряду с этой функцией потерь, и я наблюдаю, что Keras.metrics.poisson дает разные результаты - хотя эти две функции одинаковы.

См. Здесь некоторые примеры выходных данных: loss иpoisson выходы имеют разные диапазоны, 0,5 против 0,12:

Epoch 1/20
Epoch 00001: val_loss improved from inf to 0.53228, saving model to P:\Data\xyz.h5
 - 8174s - loss: 0.5085 - binary_crossentropy: 0.1252 - poisson: 0.1271 - mean_squared_error: 1.2530e-04 - mean_absolute_error: 0.0035 - mean_absolute_percentage_error: 38671.1055 - val_loss: 0.5323 - val_binary_crossentropy: 0.1305 - val_poisson: 0.1331 - val_mean_squared_error: 5.8477e-05 - val_mean_absolute_error: 0.0035 - val_mean_absolute_percentage_error: 1617.8346

Epoch 2/20
Epoch 00002: val_loss improved from 0.53228 to 0.53218, saving model to P:\Data\xyz.h5
 - 8042s - loss: 0.5067 - binary_crossentropy: 0.1246 - poisson: 0.1267 - mean_squared_error: 1.0892e-05 - mean_absolute_error: 0.0017 - mean_absolute_percentage_error: 410.8044 - val_loss: 0.5322 - val_binary_crossentropy: 0.1304 - val_poisson: 0.1330 - val_mean_squared_error: 4.9087e-05 - val_mean_absolute_error: 0.0035 - val_mean_absolute_percentage_error: 545.5222

Epoch 3/20
Epoch 00003: val_loss improved from 0.53218 to 0.53199, saving model to P:\Data\xyz.h5
 - 8038s - loss: 0.5066 - binary_crossentropy: 0.1246 - poisson: 0.1266 - mean_squared_error: 6.6870e-06 - mean_absolute_error: 0.0013 - mean_absolute_percentage_error: 298.9844 - val_loss: 0.5320 - val_binary_crossentropy: 0.1304 - val_poisson: 0.1330 - val_mean_squared_error: 4.3858e-05 - val_mean_absolute_error: 0.0031 - val_mean_absolute_percentage_error: 452.3541

Я нашел похожие вопросы при наборе этого: Керас - Потери и метрики рассчитаны по-разному? Однако яя не использую регуляризацию.

Кроме того, я сталкивался с этим, который по крайней мере помог мне воспроизвести проблему: Та же функция в Keras Loss и Metric дает разные значения даже без регуляризации

from tensorflow import keras

layer = keras.layers.Input(shape=(1, 1, 1))
model = keras.models.Model(inputs=layer, outputs=layer)
model.compile(optimizer='adam', loss='poisson', metrics=['poisson'])
data = [[[[[1]]], [[[2]]], [[[3]]]]]
model.fit(x=data, y=data, batch_size=2, verbose=1)

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

  • проблема может быть воспроизведена с помощью многих функций потери (те, которые не начинаются с mean_),
  • проблемапропадает при замене tensorflow.keras на keras, а
  • tensorflow.keras , кажется, масштабирует метрики по размеру пакета, если размерность данных больше трех .По крайней мере, это моя скромная интерпретация.

Код:

import numpy as np
from tensorflow import keras
# import keras

nSamples = 98765
nBatch = 2345

metric = 'poisson'
# metric = 'squared_hinge'
# metric = 'logcosh'
# metric = 'cosine_proximity'
# metric = 'binary_crossentropy'

# example data: always the same samples
np.random.seed(0)
dataIn = np.random.rand(nSamples)
dataOut = np.random.rand(nSamples)

for dataDim in range(1, 10):
    # reshape samples into size (1,), ..., (1, 1, ...) according to dataDim
    dataIn = np.expand_dims(dataIn, axis=-1)
    dataOut = np.expand_dims(dataOut, axis=-1)

    # build a model that does absolutely nothing
    Layer = keras.layers.Input(shape=np.ones(dataDim))
    model = keras.models.Model(inputs=Layer, outputs=Layer)

    # compile, fit and observe loss ratio
    model.compile(optimizer='adam', loss=metric, metrics=[metric])
    history = model.fit(x=dataIn, y=dataOut, batch_size=nBatch, verbose=1)
    lossRatio = history.history['loss'][0] / history.history[metric][0]
    print(lossRatio)

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

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

  1. Если размер партии делитколичество образцов, взвешивание всех образцов одинаково, и потери просто компенсируются этим коэффициентом, равным размеру партии.
  2. Если размер партии не делит количество образцов, так как партии обычно перемешиваются,вес, и, следовательно, вычисленные потери меняются от одной эпохи к другой, несмотря на то, что ничего не изменилось.Это также относится к таким показателям, как MSE.

Следующий код подтверждает эти моменты:

import numpy as np
import tensorflow as tf
from tensorflow import keras

# metric = keras.metrics.poisson
# metricName = 'poisson'
metric = keras.metrics.mse
metricName = 'mean_squared_error'

nSamples = 3
nBatchSize = 2

dataIn = np.random.rand(nSamples, 1, 1, 1)
dataOut = np.random.rand(nSamples, 1, 1, 1)

tf.InteractiveSession()
layer = keras.layers.Input(shape=(1, 1, 1))
model = keras.models.Model(inputs=layer, outputs=layer)
model.compile(optimizer='adam', loss=metric, metrics=[metric])

h = model.fit(x=dataIn, y=dataOut, batch_size=nBatchSize, verbose=1, epochs=10)

for (historyMetric, historyLoss) in zip(h.history[metricName], h.history['loss']):

    # the metric value is correct and can be reproduced in a number of ways

    kerasMetricOfData = metric(dataOut, dataIn).eval()
    averageMetric = np.mean(kerasMetricOfData)
    assert np.isclose(historyMetric, averageMetric), "..."

    flattenedMetric = metric(dataOut.flatten(), dataIn.flatten()).eval()
    assert np.isclose(historyMetric, flattenedMetric), "..."

    if metric == keras.metrics.poisson:
        numpyMetric = np.mean(dataIn - np.log(dataIn) * dataOut)
        assert np.isclose(historyMetric, numpyMetric), "..."

    # the loss value is incorrect by at least a scaling factor (~ batch size).
    # also varies *randomly* if the batch size does not divide the # of samples:

    if nSamples == 3:
        incorrectLoss = np.array([
            np.mean(kerasMetricOfData.flatten() * [1, nBatchSize, nBatchSize]),
            np.mean(kerasMetricOfData.flatten() * [nBatchSize, 1, nBatchSize]),
            np.mean(kerasMetricOfData.flatten() * [nBatchSize, nBatchSize, 1]),
        ])
    elif nSamples == 4:
        incorrectLoss = np.mean(kerasMetricOfData) * nBatchSize
    assert np.any(np.isclose(historyLoss, incorrectLoss)), "..."

Он выводит:

Epoch 1/10

2/3 [===================>..........] - ETA: 0s - loss: 0.0044 - mean_squared_error: 0.0022
3/3 [==============================] - 0s 5ms/sample - loss: 0.0099 - mean_squared_error: 0.0084
Epoch 2/10

2/3 [===================>..........] - ETA: 0s - loss: 0.0238 - mean_squared_error: 0.0119
3/3 [==============================] - 0s 2ms/sample - loss: 0.0163 - mean_squared_error: 0.0084
Epoch 3/10

2/3 [===================>..........] - ETA: 0s - loss: 0.0238 - mean_squared_error: 0.0119
3/3 [==============================] - 0s 2ms/sample - loss: 0.0163 - mean_squared_error: 0.0084
Epoch 4/10

2/3 [===================>..........] - ETA: 0s - loss: 0.0238 - mean_squared_error: 0.0119
3/3 [==============================] - 0s 2ms/sample - loss: 0.0163 - mean_squared_error: 0.0084
Epoch 5/10

2/3 [===================>..........] - ETA: 0s - loss: 0.0238 - mean_squared_error: 0.0119
3/3 [==============================] - 0s 2ms/sample - loss: 0.0163 - mean_squared_error: 0.0084
Epoch 6/10

2/3 [===================>..........] - ETA: 0s - loss: 0.0222 - mean_squared_error: 0.0111
3/3 [==============================] - 0s 2ms/sample - loss: 0.0158 - mean_squared_error: 0.0084
Epoch 7/10

2/3 [===================>..........] - ETA: 0s - loss: 0.0222 - mean_squared_error: 0.0111
3/3 [==============================] - 0s 2ms/sample - loss: 0.0158 - mean_squared_error: 0.0084
Epoch 8/10

2/3 [===================>..........] - ETA: 0s - loss: 0.0238 - mean_squared_error: 0.0119
3/3 [==============================] - 0s 2ms/sample - loss: 0.0163 - mean_squared_error: 0.0084
Epoch 9/10

2/3 [===================>..........] - ETA: 0s - loss: 0.0222 - mean_squared_error: 0.0111
3/3 [==============================] - 0s 2ms/sample - loss: 0.0158 - mean_squared_error: 0.0084
Epoch 10/10

2/3 [===================>..........] - ETA: 0s - loss: 0.0044 - mean_squared_error: 0.0022
3/3 [==============================] - 0s 2ms/sample - loss: 0.0099 - mean_squared_error: 0.0084

Обновление : Наконец, кажется, есть разница между использованием keras.metrics.mse и 'mse', как показано в этом примере:

import numpy as np
from tensorflow import keras

# these three reproduce the issue:
# metric = keras.metrics.poisson
# metric = 'poisson'
# metric = keras.metrics.mse

# this one does not:
metric = 'mse'

nSamples = 3
nBatchSize = 2

dataIn = np.random.rand(nSamples, 1, 1, 1)
dataOut = np.random.rand(nSamples, 1, 1, 1)

layer = keras.layers.Input(shape=(1, 1, 1))
model = keras.models.Model(inputs=layer, outputs=layer)
model.compile(optimizer='adam', loss=metric, metrics=[metric])
model.fit(x=dataIn, y=dataOut, batch_size=2, verbose=1, epochs=10)

Я начинаю считать, что это должно быть ошибкой, а сообщил об этом здесь .

1 Ответ

0 голосов
/ 25 мая 2019

Это было подтверждено как ошибка и исправлено.Для получения дополнительной информации см. https://github.com/tensorflow/tensorflow/issues/25970.

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