Короче говоря, вам нужно:
- Активации ReLU
- Упрощенная модель
- Мормализация данных
- Больше эпох
Подробно:
Первая проблема заключается в том, что в настоящее время мы никогда не используем activation='tanh'
для промежуточных сетевых уровней. В таких задачах мы практически всегда используем activation='relu'
.
Вторая проблема заключается в том, что вы создали довольно большую модель Keras, и вполне возможно, что в вашем тренировочном наборе всего 100 образцов радужной оболочки. у вас слишком мало данных для эффективного обучения такой большой модели. Попробуйте значительно уменьшить как количество слоев, так и количество узлов на слой. Начало проще .
Большие нейронные сети действительно процветают, когда у нас есть лотов данных, но в случае небольших наборов данных, таких как здесь, их выразительность и гибкость могут стать вместо этого, по сравнению с более простыми алгоритмами, такими как RF или k-nn.
Третья проблема заключается в том, что, в отличие от моделей на основе деревьев, таких как случайные леса, нейронные сети обычно требуют нормализации данных, которые не делай Правда в том, что knn также требует нормализованных данных, но здесь, поскольку все функции диафрагмы находятся в одном масштабе, это не влияет отрицательно на производительность в этом особом случае.
И последнее, но не менее важное: вы, кажется, запускаете модель Keras только для одной эпохи (значение по умолчанию, если вы ничего не указали в model.fit
); это несколько эквивалентно созданию случайного леса с одним деревом (что, кстати, все еще намного лучше, чем с одним деревом решений ).
В целом, со следующими изменениями в Ваш код:
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)
model = Sequential()
model.add(Dense(150, activation='relu', input_shape = ((df.shape[1]-1),)))
model.add(Dense(150, activation='relu'))
model.add(Dense(y.shape[1], activation='softmax'))
model.fit(X_train, y_train, epochs=100)
и все остальное, как есть, мы получаем:
score, acc = model.evaluate(X_test, y_test, verbose=0)
acc
# 0.9333333373069763
Мы можем сделать лучше: использовать немного больше данных тренировки и расслаивать их, т. е.
X_train, X_test, y_train, y_test = train_test_split(X, y,
test_size = 0.20, # a few more samples for training
stratify=y)
И с теми же эпохами модели и обучения вы можете получить совершенную точность 1,0 в тестовом наборе:
score, acc = model.evaluate(X_test, y_test, verbose=0)
acc
# 1.0
(детали могут отличаться из-за некоторой случайности, налагаемой по умолчанию в таких экспериментах).