В моей тренировке 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)
Я считаю, что это поведение по крайней мере противоречиво.Должен ли я считать это ошибкой или функцией?
Обновление : После дальнейшего изучения я обнаружил, что значения метрик, которые считаются правильными, вычисляются, а значения потерь - нет;на самом деле потери представляют собой взвешенные суммы потерь выборки, где взвешиванием каждой выборки является размер партии, в которой находится выборка. Это имеет два значения:
- Если размер партии делитколичество образцов, взвешивание всех образцов одинаково, и потери просто компенсируются этим коэффициентом, равным размеру партии.
- Если размер партии не делит количество образцов, так как партии обычно перемешиваются,вес, и, следовательно, вычисленные потери меняются от одной эпохи к другой, несмотря на то, что ничего не изменилось.Это также относится к таким показателям, как 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)
Я начинаю считать, что это должно быть ошибкой, а сообщил об этом здесь .