Прогнозы tf.keras плохие, а оценки хорошие - PullRequest
1 голос
/ 01 апреля 2019

Я программирую модель в tf.keras, и запускаю model.evaluate () на тренировочном наборе, как правило, дает точность ~ 96%.Моя оценка на тестовом наборе обычно близка, около 93%.Однако, когда я прогнозирую вручную, модель обычно неточна.Это мой код:

import tensorflow as tf
from tensorflow.keras import layers
import numpy as np
import pandas as pd

!git clone https://github.com/DanorRon/data
%cd data
!ls

batch_size = 100
epochs = 15
alpha = 0.001
lambda_ = 0.001
h1 = 50

train = pd.read_csv('/content/data/mnist_train.csv.zip')
test = pd.read_csv('/content/data/mnist_test.csv.zip')

train = train.loc['1':'5000', :]
test = test.loc['1':'2000', :]

train = train.sample(frac=1).reset_index(drop=True)
test = test.sample(frac=1).reset_index(drop=True)

x_train = train.loc[:, '1x1':'28x28']
y_train = train.loc[:, 'label']

x_test = test.loc[:, '1x1':'28x28']
y_test = test.loc[:, 'label']

x_train = x_train.values
y_train = y_train.values

x_test = x_test.values
y_test = y_test.values

nb_classes = 10
targets = y_train.reshape(-1)
y_train_onehot = np.eye(nb_classes)[targets]

nb_classes = 10
targets = y_test.reshape(-1)
y_test_onehot = np.eye(nb_classes)[targets]

model = tf.keras.Sequential()
model.add(layers.Dense(784, input_shape=(784,), kernel_initializer='random_uniform', bias_initializer='zeros'))
model.add(layers.Dense(h1, activation='relu', kernel_regularizer=tf.keras.regularizers.l2(lambda_), kernel_initializer='random_uniform', bias_initializer='zeros'))
model.add(layers.Dense(10, activation='softmax', kernel_regularizer=tf.keras.regularizers.l2(lambda_), kernel_initializer='random_uniform', bias_initializer='zeros'))

model.compile(optimizer='SGD',
             loss = 'mse',
             metrics = ['categorical_accuracy'])

model.fit(x_train, y_train_onehot, epochs=epochs, batch_size=batch_size)

model.evaluate(x_test, y_test_onehot, batch_size=batch_size)

prediction = model.predict_classes(x_test)
print(prediction)

print(y_test[1:])

Я слышал, что большую часть времени, когда люди сталкиваются с этой проблемой, это просто проблема с вводом данных.Но я не вижу здесь никакой проблемы с этим, поскольку он почти всегда предсказывает неверно (примерно столько, сколько вы ожидаете, если он будет случайным).Как мне решить эту проблему?

Редактировать: Вот конкретные результаты:

Последний шаг обучения:

Epoch 15/15
49999/49999 [==============================] - 3s 70us/sample - loss: 0.0309 - categorical_accuracy: 0.9615

Результат оценки:

2000/2000 [==============================] - 0s 54us/sample - loss: 0.0352 - categorical_accuracy: 0.9310
[0.03524150168523192, 0.931]

Вывод из model.predict_classes:

[9 9 0 ... 5 0 5]

Вывод из печати (y_test):

[9 0 0 7 6 8 5 1 3 2 4 1 4 5 8 4 9 2 4]

1 Ответ

1 голос
/ 01 апреля 2019

Во-первых, ваша функция потерь неверна: вы находитесь в настройке классификации нескольких классов и используете функцию потерь, подходящую для регрессии, а не классификации (MSE).

Измените компиляцию нашей моделипо:

model.compile(loss='categorical_crossentropy',
              optimizer='SGD',
              metrics=['accuracy'])

См. пример Keras MNIST MLP для подтверждения и собственный ответ в Какая функция определяет точность в Keras, когда потеря представляет собой среднеквадратическую ошибку (MSE)? для более подробной информации (хотя здесь у вас фактически есть обратная проблема, то есть потеря регрессии в настройке классификации).

Кроме того, неясно, нормализован ли используемый вами вариант MNIST;если нет, вам следует нормализовать их самостоятельно:

x_train = x_train.values/255
x_test = x_test.values/255

Также не ясно, почему вы запрашиваете слой в 784 единицы, поскольку на самом деле это второй слой вашего NN (первый неявно задается аргументом input_shape - см. входной слой последовательной модели Keras * (1019 *), и, конечно, ему не нужно содержать одну единицу для каждой из ваших 784 входных функций.

ОБНОВЛЕНИЕ (после комментариев):

Но почему MSE не имеет смысла для классификации?

Это теоретическая проблема, не совсем подходящая для SO;грубо говоря, по той же причине, по которой мы не используем линейную регрессию для классификации - мы используем логистическую регрессию, фактическая разница между этими двумя подходами является именно функцией потерь.Эндрю Нг, в своем популярном курсе машинного обучения в Coursera, хорошо объясняет это - см. Его Лекция 6.1 - Логистическая регрессия |Классификация на Youtube (объяснение начинается в ~ 3:00), а также раздел 4.2. Почему не линейная регрессия [для классификации]? из (настоятельно рекомендуется и свободно доступного) учебника AnВведение в статистическое обучение Хасти, Тибширани и его коллег.

И MSE дает высокую точность, так почему же это не имеет значения?

В наше время,почти что-нибудь , которое вы бросаете в MNIST, будет "работать", что, конечно, ни делает это правильным, ни хорошим подходом для более требовательных наборов данных ...

ОБНОВЛЕНИЕ 2 :

всякий раз, когда я бегу с кроссентропией, точность просто колеблется на уровне ~ 10%

Извините, не могу воспроизвести поведение ... Принимая MLP * MNIST Kerasпример с упрощенной версией вашей модели, а именно:

model = Sequential()
model.add(Dense(784, activation='linear', input_shape=(784,)))
model.add(Dense(50, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))

model.compile(loss='categorical_crossentropy',
              optimizer=SGD(),
              metrics=['accuracy'])

, мы легко получаем точность ~ 92% только после 5 эпох:

history = model.fit(x_train, y_train,
                    batch_size=128,
                    epochs=5,
                    verbose=1,
                    validation_data=(x_test, y_test))

Train on 60000 samples, validate on 10000 samples
Epoch 1/10
60000/60000 [==============================] - 4s - loss: 0.8974 - acc: 0.7801 - val_loss: 0.4650 - val_acc: 0.8823
Epoch 2/10
60000/60000 [==============================] - 4s - loss: 0.4236 - acc: 0.8868 - val_loss: 0.3582 - val_acc: 0.9034
Epoch 3/10
60000/60000 [==============================] - 4s - loss: 0.3572 - acc: 0.9009 - val_loss: 0.3228 - val_acc: 0.9099
Epoch 4/10
60000/60000 [==============================] - 4s - loss: 0.3263 - acc: 0.9082 - val_loss: 0.3024 - val_acc: 0.9156
Epoch 5/10
60000/60000 [==============================] - 4s - loss: 0.3061 - acc: 0.9132 - val_loss: 0.2845 - val_acc: 0.9196

Обратите внимание на activation='linear' первого плотного слоя, что эквивалентно без указания чего-либо , как в вашем случае (как я уже сказал, практически все, что вы бросаете в MNIST, будет "работать") ...

Последний совет: попробуйте изменить модель следующим образом:

model = tf.keras.Sequential()
model.add(layers.Dense(784, activation = 'relu',input_shape=(784,)))
model.add(layers.Dense(h1, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))

, чтобы использовать лучший (и по умолчанию ) 'glorot_uniform' инициализатор, и удалить аргументы kernel_regularizer (они могутбыть причиной любой проблемы - всегда начать просто!) ...

...