Поезд Keras и значения метрик валидации различаются даже при использовании одних и тех же данных (логистическая регрессия) - PullRequest
0 голосов
/ 12 ноября 2018

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

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

Вот мой код:

Генерирует несколько случайных данных с двумя классами:

N = 100
x = np.concatenate([np.random.randn(N//2, 1), np.random.randn(N//2, 1)+2])
y = np.concatenate([np.zeros(N//2), np.ones(N//2)])

И построение графика распределения данных двух классов (одна особенность x):

data = pd.DataFrame({'x': x.ravel(), 'y': y})
sns.violinplot(x='x', y='y', inner='point', data=data, orient='h')
pyplot.tight_layout(0)
pyplot.show()

enter image description here

Сборка и установка модели keras:

model = tf.keras.Sequential([tf.keras.layers.Dense(1, activation='sigmoid', input_dim=1)])
model.compile(optimizer=tf.keras.optimizers.SGD(2), loss='binary_crossentropy', metrics=['accuracy'])
model.fit(x, y, epochs=10, validation_data=(x, y), batch_size=N)

Обратите внимание, что я указал данные x и цели y как для обучения, так и для validation_data. Кроме того, размер batch_size равен общему размеру batch_size=N.

Результаты обучения:

100/100 [==============================] - 1s 5ms/step - loss: 1.4500 - acc: 0.2300 - val_loss: 0.5439 - val_acc: 0.7200
Epoch 2/10
100/100 [==============================] - 0s 18us/step - loss: 0.5439 - acc: 0.7200 - val_loss: 0.4408 - val_acc: 0.8000
Epoch 3/10
100/100 [==============================] - 0s 16us/step - loss: 0.4408 - acc: 0.8000 - val_loss: 0.3922 - val_acc: 0.8300
Epoch 4/10
100/100 [==============================] - 0s 16us/step - loss: 0.3922 - acc: 0.8300 - val_loss: 0.3659 - val_acc: 0.8400
Epoch 5/10
100/100 [==============================] - 0s 17us/step - loss: 0.3659 - acc: 0.8400 - val_loss: 0.3483 - val_acc: 0.8500
Epoch 6/10
100/100 [==============================] - 0s 16us/step - loss: 0.3483 - acc: 0.8500 - val_loss: 0.3356 - val_acc: 0.8600
Epoch 7/10
100/100 [==============================] - 0s 17us/step - loss: 0.3356 - acc: 0.8600 - val_loss: 0.3260 - val_acc: 0.8600
Epoch 8/10
100/100 [==============================] - 0s 18us/step - loss: 0.3260 - acc: 0.8600 - val_loss: 0.3186 - val_acc: 0.8600
Epoch 9/10
100/100 [==============================] - 0s 18us/step - loss: 0.3186 - acc: 0.8600 - val_loss: 0.3127 - val_acc: 0.8700
Epoch 10/10
100/100 [==============================] - 0s 23us/step - loss: 0.3127 - acc: 0.8700 - val_loss: 0.3079 - val_acc: 0.8800

Результаты показывают, что val_loss и убыток не совпадают в конце каждой эпохи, а также acc и val_acc не совсем то же самое. Однако, исходя из этой настройки, можно ожидать, что они будут такими же.

Я просматривал код в keras, особенно эту часть: https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/keras/engine/training.py#L1364

и до сих пор все, что я могу сказать, это различие из-за некоторых других вычислений через граф вычислений.

Кто-нибудь знает, почему будет такая разница?

1 Ответ

0 голосов
/ 12 ноября 2018

Таким образом, после более тщательного изучения результатов значения loss и acc на этапе обучения вычисляются ДО того, как текущая партия используется для обновления модели.

Таким образом, в случае одной партии на эпоху, поезда acc и loss оцениваются при подаче партии, затем параметры модели обновляются на основе предоставленного оптимизатора. После завершения шага поезда мы рассчитываем потери и точность, вводя данные проверки, которые теперь оцениваются с использованием новой обновленной модели.

Это видно из вывода результатов обучения, где точность и потеря проверки в эпоху 1 равны точности поезда и потерям в эпоху 2 и т. Д ...

Быстрая проверка с использованием тензорного потока подтвердила, что значения выбираются до обновления переменных:

import tensorflow as tf
import numpy as np
np.random.seed(1)

x = tf.placeholder(dtype=tf.float32, shape=(None, 1), name="x")
y = tf.placeholder(dtype=tf.float32, shape=(None), name="y")

W = tf.get_variable(name="W", shape=(1, 1), dtype=tf.float32, initializer=tf.constant_initializer(0))
b = tf.get_variable(name="b", shape=1, dtype=tf.float32, initializer=tf.constant_initializer(0))
z = tf.matmul(x, W) + b

error = tf.square(z - y)
obj = tf.reduce_mean(error, name="obj")

opt = tf.train.MomentumOptimizer(learning_rate=0.025, momentum=0.9)
grads = opt.compute_gradients(obj)
train_step = opt.apply_gradients(grads)

N = 100
x_np = np.random.randn(N).reshape(-1, 1)
y_np = 2*x_np + 3 + np.random.randn(N)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for i in range(2):
        res = sess.run([obj, W, b, train_step], feed_dict={x: x_np, y: y_np})
        print('MSE: {}, W: {}, b: {}'.format(res[0], res[1][0, 0], res[2][0]))

Выход:

MSE: 14.721437454223633, W: 0.0, b: 0.0
MSE: 13.372591018676758, W: 0.08826743811368942, b: 0.1636980175971985

Поскольку параметры W и b были инициализированы равными 0, ясно, что извлеченные значения по-прежнему равны 0, даже если сеанс был запущен с запросом обновления градиента ...

...