Реализация CNN с низкой точностью на данных MNIST

Вопрос или проблема

Я пытаюсь реализовать VGG11 (Модель A из Таблицы 1 из этой статьи) на наборе данных MINST, но я получаю примерно 10% точности на обучении и тестировании (это так же плохо, как случайное угадывание). Мне пришлось изменить размеры данных MINST с 28×28 на 32×32, чтобы соответствовать архитектуре CNN. Вот что я сделал:

from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Conv2D, MaxPooling2D, Flatten
from keras import optimizers, utils
from PIL import Image, ImageFilter
import numpy as np
import tensorflow as tf

# Предобработка

x_size = 6000 # Изменено для сокращения времени обучения 
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train_ = np.ndarray((x_size, 32, 32))
x_test_ = np.ndarray((x_test.shape[0], 32, 32))

# Изменение размера входных данных на 32x32
for i in [0, x_size-1]:
    im = Image.fromarray(x_train[i], mode=None)
    im = im.resize((32, 32))
    x_train_[i] = np.array(im)
for i in [0,x_test.shape[0]-1]:
    im = Image.fromarray(x_test[i], mode=None)
    im = im.resize((32, 32))
    x_test_[i] = np.array(im)

x_train_ = x_train_.reshape(x_train_.shape[0], 32, 32, 1)
x_test_ = x_test_.reshape(x_test_.shape[0], 32, 32, 1)

y_train = utils.to_categorical(y_train,10)
y_test = utils.to_categorical(y_test,10)
y_train_ = y_train[:x_size]


# Модель A (VGG11) из Таблицы 1: Конфигурации ConvNet из статьи arXiv:1409.1556v6

model = Sequential()
model.add(Conv2D(64, kernel_size=(3, 3), strides=(1, 1), activation='relu', padding='same', input_shape=(32, 32, 1), data_format="channels_last"))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2,2)))
model.add(Conv2D(128, kernel_size=(3, 3), strides=(1, 1), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2,2)))
model.add(Conv2D(256, kernel_size=(3, 3), strides=(1, 1), activation='relu', padding='same'))
model.add(Conv2D(256, kernel_size=(3, 3), strides=(1, 1), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2,2)))
model.add(Conv2D(512, kernel_size=(3, 3), strides=(1, 1), activation='relu', padding='same'))
model.add(Conv2D(512, kernel_size=(3, 3), strides=(1, 1), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2,2)))
model.add(Conv2D(512, kernel_size=(3, 3), strides=(1, 1), activation='relu', padding='same'))
model.add(Conv2D(512, kernel_size=(3, 3), strides=(1, 1), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2,2)))
model.add(Flatten())
model.add(Dense(4096, activation='relu'))
model.add(Dense(4096, activation='relu'))
model.add(Dense(1000, activation='relu'))
model.add(Dense(10, activation='softmax'))

# Компиляция модели

model.compile(loss="categorical_crossentropy", optimizer=optimizers.SGD(lr=0.001, momentum=0.9, nesterov=True, clipnorm=1.), metrics=['accuracy'])

# Обучение модели

model.fit(x_train_, y_train_, epochs=1, batch_size=32)

# Оценка модели

score = model.evaluate(x_train_, y_train_)
print('Потери на обучении после 1 эпохи:', score[0])
print('Точность на обучении после 1 эпохи:', score[1]) 

Я пытался нормализовать входные данные, изменять размеры обучения, увеличивать количество эпох, изменять размер плотных слоев/фильтров и изменять оптимизаторы (и скорость обучения). Точность на обучении настолько же низка, как из отчета об оценке, так и из отчета истории TensorFlow. Я ожидаю точность выше 95%. Где я ошибаюсь?

Попробуйте добавить регуляризацию dropout в сеть, чтобы избежать переобучения.
прочитайте документацию для получения дополнительной информации
https://keras.io/layers/core/

и попробуйте эти вещи тоже

поскольку цели являются целыми числами, лучше использовать sparse_categorical_crossentropy, чем categorical_crossentropy, и оптимизатор Adam

model.compile(loss="sparse_categorical_crossentropy", optimizer=optimizers.Adam(lr=0.001), metrics=['accuracy'])

и попробуйте использовать sigmoid активационную функцию для выходного слоя

model.add(Dense(10, activation='sigmoid'))

На сколько вы увеличили количество эпох? Вы пытаетесь переобучить VGG11 с нуля, и у нее более 30 миллионов параметров, что предполагает длительное время обучения. Вы пытаетесь использовать трансферное обучение, беря предобученные веса и зафиксировав все слои, кроме последнего, для решения вашей классификационной задачи? В этом случае вы правы, ожидая точность более 95% после нескольких эпох.

Я не знаю, где найти предобученную VGG11 для TensorFlow, но здесь есть версия для PyTorch.

Ответ или решение

Обработка данных и реализация свёрточных нейронных сетей (CNN) — это важные аспекты в области машинного обучения и компьютерного зрения. В вашем случае, внедрение архитектуры VGG11 на данных MNIST привело к низкому уровню точности (около 10%), что указывает на ряд возможных ошибок и недоработок. Давайте рассмотрим наиболее вероятные причины низкой точности и возможные улучшения.

1. Проблемы с предобработкой данных

А) Размер и формат данных:
Вы сделали изменения в размере входных изображений, увеличив их с 28×28 до 32×32. Однако возможно, изображения были не только масштабированы, но и потеряли резкость. Вам нужно убедиться, что используемый режим ‘L’ в PIL для черно-белых изображений соответствует формату, ожидаемому CNN. Кроме того, важно нормализовать данные, чтобы значения падали в диапазон [0, 1]. Маловероятно, что модель может обучаться эффективно на необработанных данных.

x_train_ = x_train_.astype('float32') / 255.0
x_test_ = x_test_.astype('float32') / 255.0

Б) Целевые метки:
Использование sparse_categorical_crossentropy может быть предпочтительнее, если метки представлены в виде целых чисел. Это упростит задачу компиляции модели.

2. Архитектура модели

А) Размерность выходного слоя:
Если ваша окончательная цель — классификация 10 классов, необходимо убедиться, что выходной слой имеет 10 нейронов с активацией softmax. Функция активации sigmoid не подходит для многоклассовой классификации в вашем случае.

model.add(Dense(10, activation='softmax'))

Б) Сложность модели:
VGG11 — это глубокая архитектура с миллионами параметров, что делает ее сложно обучаемой на небольших наборах данных. Попробуйте уменьшить количество слоев или использовать менее сложные модели, такие как LeNet, которые более оптимальны для данных MNIST.

3. Изменения в процессе обучения

А) Оптимизатор:
Попробуйте использовать Adam вместо SGD. Эта оптимизация предлагает адаптивное управление скоростью обучения и может ускорить процесс сходимости.

model.compile(loss="sparse_categorical_crossentropy", optimizer=optimizers.Adam(lr=0.001), metrics=['accuracy'])

Б) Увеличение эпох:
Обучение VGG11 требует большого количества эпох. Убедитесь, что вы пробовали больше одного цикла, например, 10 или 20, чтобы модель могла собрать информацию о данных и обучиться на них.

4. Регуляризация

Поскольку у вас есть возможность переобучения из-за высокой сложности модели, добавление слоев Dropout может помочь в этом:

from keras.layers import Dropout

# Пример: добавление слоя Dropout
model.add(Dropout(0.5))

5. Использование предобученных моделей

Изучение методов передачи обучения может сильно помочь: замените все, кроме верхних слоев, используя предобученные веса VGG11. В этом случае вы сможете добиться высоких показателей точности гораздо быстрее. Возможно, вам будет нужно настроить библиотеку TensorFlow для поддержки предобученных моделей.

Заключение

В решении проблемы низкой точности стоит проверить предобработку данных, структуру модели, иаргументы, настроить процесс обучения и использовать подходы к регуляризации. Попробуйте также различные комбинации этих улучшений. Вы сможете добиться более высокой точности модели на данных MNIST и перейти к более сложным архитектурным вариантам в будущем.

Оцените материал
Добавить комментарий

Капча загружается...