Большая разница между val-a cc и точностью предсказания в нейронной сети Keras - PullRequest
0 голосов
/ 30 марта 2020

У меня есть набор данных, который я использовал для создания модели NN в Керасе, я взял 2000 строк из этого набора данных, чтобы иметь их в качестве проверочных данных, эти 2000 строк должны быть добавлены в функцию .predict.

I написал код для Keras NN и пока он работает хорошо, но я заметил кое-что, что очень странно для меня. Это дает мне очень хорошую точность - более 83%, потери - около 0,12, но когда я хочу сделать прогноз с помощью невидимых данных (эти 2000 строк), он дает только правильный прогноз в среднем на 65%. Когда я добавляю слой Dropout, он только снижает точность.

Затем я добавил EarlyStopping, и это дало мне точность около 86%, потери - около 0,10, но все же, когда я делаю прогноз с невидимыми данными, я получить окончательную точность прогноза 67%.

Означает ли это, что модель сделала правильный прогноз в 87% ситуаций? Я собираюсь с логикой c, если я добавлю 100 выборок в мою функцию .predict, эта программа должна сделать хороший прогноз для 87/100 выборок или где-то в этом диапазоне (скажем, более 80)? Я попытался добавить 100, 500, 1000, 1500 и 2000 сэмплов в мою функцию .predict, и она всегда дает правильный прогноз в 65-68% выборок.

Почему это так, я делаю что-то не так? Я попытался поиграть с количеством слоев, количеством узлов, с разными функциями активации и с разными оптимизаторами, но результаты меняются только на 1-2%. Мой набор данных выглядит следующим образом:

DataFrame shape (59249, 33)
x_train shape (47399, 32)
y_train shape (47399,)
x_test shape (11850, 32)
y_test shape (11850,)
testing_features shape (1000, 32)

Это моя модель NN:

model = Sequential()
model.add(Dense(64, input_dim = x_train.shape[1], activation = 'relu')) # input layer requires input_dim param
model.add(Dropout(0.2))
model.add(Dense(32, activation = 'relu'))
model.add(Dropout(0.2))
model.add(Dense(16, activation = 'relu'))
model.add(Dense(1, activation='sigmoid')) # sigmoid instead of relu for final probability between 0 and 1

# compile the model, adam gradient descent (optimized)
model.compile(loss="binary_crossentropy", optimizer= "adam", metrics=['accuracy'])


# call the function to fit to the data training the network)
es = EarlyStopping(monitor='val_loss', min_delta=0.0, patience=1, verbose=0, mode='auto')
model.fit(x_train, y_train, epochs = 15, shuffle = True, batch_size=32, validation_data=(x_test, y_test), verbose=2, callbacks=[es])

scores = model.evaluate(x_test, y_test)
print(model.metrics_names[0], round(scores[0]*100,2), model.metrics_names[1], round(scores[1]*100,2))

Вот результаты:

Train on 47399 samples, validate on 11850 samples
Epoch 1/15
 - 25s - loss: 0.3648 - acc: 0.8451 - val_loss: 0.2825 - val_acc: 0.8756
Epoch 2/15
 - 9s - loss: 0.2949 - acc: 0.8689 - val_loss: 0.2566 - val_acc: 0.8797
Epoch 3/15
 - 9s - loss: 0.2741 - acc: 0.8773 - val_loss: 0.2468 - val_acc: 0.8849
Epoch 4/15
 - 9s - loss: 0.2626 - acc: 0.8816 - val_loss: 0.2416 - val_acc: 0.8845
Epoch 5/15
 - 10s - loss: 0.2566 - acc: 0.8827 - val_loss: 0.2401 - val_acc: 0.8867
Epoch 6/15
 - 8s - loss: 0.2503 - acc: 0.8858 - val_loss: 0.2364 - val_acc: 0.8893
Epoch 7/15
 - 9s - loss: 0.2480 - acc: 0.8873 - val_loss: 0.2321 - val_acc: 0.8895
Epoch 8/15
 - 9s - loss: 0.2450 - acc: 0.8886 - val_loss: 0.2357 - val_acc: 0.8888
11850/11850 [==============================] - 2s 173us/step
loss 23.57 acc 88.88

И это для прогноза:

#testing_features are 2000 rows that i extracted from dataset (these samples are not used in training, this is separate dataset thats imported)

prediction = model.predict(testing_features , batch_size=32)

res = []
for p in prediction:
    res.append(p[0].round(0))


# Accuracy with sklearn - also much lower 
acc_score = accuracy_score(testing_results, res)
print("Sklearn acc", acc_score)    

result_df = pd.DataFrame({"label":testing_results,
                          "prediction":res})


result_df["prediction"] = result_df["prediction"].astype(int)

s = 0
for x,y in zip(result_df["label"], result_df["prediction"]):
    if x == y:
        s+=1

print(s,"/",len(result_df))
acc = s*100/len(result_df)
print('TOTAL ACC:', round(acc,2))

Проблема в том ... теперь я получаю точность со склеарном 52% и my_acc 52%. Почему я получаю такую ​​низкую точность при проверке, когда говорится, что она намного больше?

Ответы [ 2 ]

1 голос
/ 30 марта 2020

Учебные данные, которые вы опубликовали, дают высокую точность проверки, поэтому я немного озадачен тем, откуда вы получаете эти 65%, но в целом, когда ваша модель работает намного лучше по данным обучения, чем по невидимым данным, это означает, что вы над фитингом . Это большая и повторяющаяся проблема в машинном обучении, и не существует способа предотвратить это, но есть пара вещей, которые вы можете попробовать:

  • регуляризация весов вашей сети, например использование l2 регуляризация
  • с использованием стохастий c методы регуляризации, такие как отсев во время тренировки
  • ранняя остановка
  • уменьшение сложности модели (но вы говорите, что вы Я уже пробовал это)
0 голосов
/ 01 апреля 2020

Я перечислю проблемы / рекомендации, которые я вижу в вашей модели.

  1. Что вы пытаетесь предсказать? Вы используете sigmoid функцию активации в последнем слое, которая выглядит как двоичная классификация, но в вашем loss режиме вы использовали mse, что кажется странным. Вы можете попробовать binary_crossentropy вместо mse функции потерь для вашей модели.
  2. Кажется, ваша модель страдает от переоснащения, поэтому вы можете увеличить вероятность. Dropout, а также добавьте новый Dropout между другими скрытыми слоями, или вы можете удалить один из скрытых слоев, потому что кажется, что ваша модель слишком сложна.
  3. Вы можете изменить свои нейронные числа в слоях, например, более узкие => 64 -> 32 -> 16 -> 1 или попробовать разные архитектуры NN.
  4. Попробуйте adam оптимизатор вместо sgd.
  5. Если у вас есть 57849 образец, вы можете использовать 47000 образцов при обучении + валидации, а остальные будут вашим тестовым набором.
  6. Не используйте одни и те же наборы для оценки и проверки. Сначала разделите ваши данные на поезд и тестовый набор. Затем, когда вы подгоняете свою модель, дайте validation_split_ratio, тогда она автоматически выдаст набор проверки из вашего тренировочного набора.
...