Как исправить переобучение сверточной нейронной сети(keras)?
Начал изучать машинное обучение и уже подошёл к практике
Решил сделать нейросеть, которая разпознает числа на циферблате калькулятора
Но результат плохой
Я три дня пытался настроить её, искал материал, который мог бы помочь, или примеры, но сеть постоянно переобучается
Минимальное значение, которое я нашёл при разхождении между обучающей выборкой и тестовой, это примерно ±1.3
Мне кажется, что я что-то принципиально делаю не так, но не хватает опыта, чтобы понять, что именно
Поэтому хочу понять, есть ли явные ошибки при проектировании сети
Мои действия:
Подготовка данных:
1) Скачал примерно 150 изображений калькуляторов
2) Обрезал циферблаты
3) С помощью библиотеки Pillow привёл их к размеру 300x100 пикселей (растягивание/сжатие)
4) Составил матрицу пикселей для каждого изображения размером 300x100x3 (где 3 - это цветовые каналы RGB)
5) Загрузил всё это в базу данных PostgreSQL и добавил для каждого изображения правильный ответ в нужном формате
Формат вывода, аналогичный учебному примеру, я выбрал softmax
Однако, поскольку у меня много чисел и могут быть десятичные дроби, я использую следующий формат
На выходе я получаю матрицу размером (11, 10), где столбец 0 это позиция точки, а столбцы с 1 по 10 это числа от 0 до 9.
Используя функцию np.argmax, я определяю номер строки, соответствующей распознанному числу
Пример для числа 2.2
[ [0, 1, 0, 0, 0, 0, 0, 0, 0, 0] - точка на 1-й позиции с конца [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] - 10-е число 0 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] - 9-е число 0 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] - 8-е число 0 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] - 7-е число 0 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] - 6-е число 0 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] - 5-е число 0 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] - 4-е число 0 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] - 3-е число 0 [0, 0, 1, 0, 0, 0, 0, 0, 0, 0] - 2-е число 2 [0, 0, 1, 0, 0, 0, 0, 0, 0, 0] - 1-е число 2 ] |
[ [0, 1, 0, 0, 0, 0, 0, 0, 0, 0] - точка на 1-й позиции с конца [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] - 10-е число 0 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] - 9-е число 0 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] - 8-е число 0 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] - 7-е число 0 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] - 6-е число 0 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] - 5-е число 0 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] - 4-е число 0 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] - 3-е число 0 [0, 0, 1, 0, 0, 0, 0, 0, 0, 0] - 2-е число 2 [0, 0, 1, 0, 0, 0, 0, 0, 0, 0] - 1-е число 2 ]
Код нейронной сети
model = keras.Sequential( [ Conv2D(filters=5, kernel_size=5, activation='relu', input_shape=(300, 100, 3)), Conv2D(filters=5, kernel_size=5, activation='relu'), MaxPooling2D(pool_size=2), Conv2D(filters=5, kernel_size=5, activation='relu'), Conv2D(filters=5, kernel_size=5, activation='relu'), Conv2D(filters=5, kernel_size=5, activation='relu'), MaxPooling2D(pool_size=2), Conv2D(filters=5, kernel_size=5, activation='relu'), Conv2D(filters=5, kernel_size=5, activation='relu'), Conv2D(filters=5, kernel_size=5, activation='relu'), MaxPooling2D(pool_size=2), Flatten(), Dense(units=60, activation="relu"), Dense(units=60, activation="relu"), Dense(units=110), Reshape((11, 10)), Activation('softmax') ] ) model.compile( optimizer=keras.optimizers.Adam(learning_rate=0.0001), loss="categorical_crossentropy", metrics=["accuracy"], ) his = model.fit( trainings_input, trainings_exit, batch_size=32, epochs=200, validation_split=0.2, ) model.evaluate(trainings_input, trainings_exit) |
model = keras.Sequential( [ Conv2D(filters=5, kernel_size=5, activation='relu', input_shape=(300, 100, 3)), Conv2D(filters=5, kernel_size=5, activation='relu'), MaxPooling2D(pool_size=2), Conv2D(filters=5, kernel_size=5, activation='relu'), Conv2D(filters=5, kernel_size=5, activation='relu'), Conv2D(filters=5, kernel_size=5, activation='relu'), MaxPooling2D(pool_size=2), Conv2D(filters=5, kernel_size=5, activation='relu'), Conv2D(filters=5, kernel_size=5, activation='relu'), Conv2D(filters=5, kernel_size=5, activation='relu'), MaxPooling2D(pool_size=2), Flatten(), Dense(units=60, activation="relu"), Dense(units=60, activation="relu"), Dense(units=110), Reshape((11, 10)), Activation('softmax') ] ) model.compile( optimizer=keras.optimizers.Adam(learning_rate=0.0001), loss="categorical_crossentropy", metrics=["accuracy"], ) his = model.fit( trainings_input, trainings_exit, batch_size=32, epochs=200, validation_split=0.2, ) model.evaluate(trainings_input, trainings_exit)
Сеть, кажется, что-то распознает
Например, количество цифр и позицию точки она распознает в целом верно (тестировалась на наборе валидации, который не участвовал в обучении)
Однако ни разу не распознала цифру верно
Очень редко она была максимально близка, но мне кажется, что это случайность
Вот график расхождения для 200 эпох.
plt.plot(his.history['loss']) plt.plot(his.history['val_loss']) plt.savefig('training_validation_correlation.png') |
plt.plot(his.history['loss']) plt.plot(his.history['val_loss']) plt.savefig('training_validation_correlation.png')
Дополнительно:
150 изображений для обучения нейронки? Маловато будет. Вот и результат никакой. Классический для изучения нейронок набор данных MNIST содержит 60к картинок. На практике данных нужно как можно больше - миллионы и миллиарды, сколько бюджет и ресурсы позволяют, к тому же их дополнительно искажают по-всякому на каждой эпохе случайным образом.
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос

Для исправления переобучения сверточной нейронной сети в Keras можно применить несколько методов. Вот некоторые из них:
1. Уменьшить сложность модели: Попробуйте уменьшить количество слоев или нейронов в каждом слое сети. Это может помочь предотвратить переобучение.
model = Sequential() model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3))) model.add(MaxPooling2D((2, 2))) model.add(Flatten()) model.add(Dense(64, activation='relu')) model.add(Dense(10, activation='softmax'))
2. Добавить регуляризацию: Используйте методы регуляризации, такие как L1 или L2 регуляризация, чтобы уменьшить переобучение. Например, добавьте параметр kernel_regularizer к слоям Dense или Conv2D.
from keras import regularizers model.add(Dense(64, activation='relu', kernel_regularizer=regularizers.l2(0.01)))
3. Использовать Dropout: Добавьте слои Dropout после сверточных слоев или полносвязных слоев, чтобы случайным образом "выключать" нейроны во время обучения.
model.add(Dropout(0.5))
4. Использовать аугментацию данных: Добавьте аугментацию данных в процесс обучения, чтобы увеличить разнообразие обучающего набора данных и предотвратить переобучение.
from keras.preprocessing.image import ImageDataGenerator datagen = ImageDataGenerator(rotation_range=40, width_shift_range=0.2, height_shift_range=0.2, shear_range=0.2, zoom_range=0.2, horizontal_flip=True, fill_mode='nearest')
5. Использовать раннюю остановку: Добавьте обратный вызов EarlyStopping, чтобы остановить обучение, когда ошибка на валидационном наборе данных перестанет уменьшаться.
from keras.callbacks import EarlyStopping early_stopping = EarlyStopping(monitor='val_loss', patience=3)
Применение этих методов поможет улучшить производительность сверточной нейронной сети в Keras и предотвратить переобучение.