- Исходный датасет c www.kaggle.com
- Бинарная классификация по изображениям (TensorFlow documentation)
- Облачная платформа, на которой проводил обучение нейросетей (Google Colaboratory)
- Обработка загружаемых файлов (Flask documentation)
- Оформление и стили с помощью MaterializeCSS (MaterializeCSS documentation)
Основной функционал проекта заключается в возможности получать информацию об объекте путем вывода того, кто изображен на картинке на страницу браузера. Загружаем выбранную нами картинку с изображением объекта (Кошки или Собаки) в поле
<input type="file" name="inputfile">
Отправляем на сервер загруженное изображение
<input type="submit">
Данные приходят в POST запросе. Сохраняем файлы для последующей обработки с помощью нейросети в директорию UPLOAD_FOLDER
, а ALLOWED_EXTENSION
- набор допустимых расширений.
Проверка загрженной картинки на соответствие расширению .jpg
осуществялется с помощью регулярных выражений
answer_request = str(request.files)
mask = re.compile('.jpg') #
answer_result = mask.findall(answer_request) # True or False
В случае ошибки при загрузке, я не обрабатываю ее конструкцией, вида:
try:
do smth1
except SomethingError as ex:
do smth2
А перенапрявляю пользователя на страницу со вспомогательной информацией, чтобы он успешно загрузил файл. Перейдя по предложенной сылке, вы попадете на стартовую страницу и сможете попытаться загрузить файл снова.
Push to load correct 'name'.jpg file
Важно отметить, что метод def allowed_file(filename)
вернет True or False
в зависимости от удовлетворения условю ALLOWED_EXTENSION
, в котором перечислены разрешенные расширения для файла.
Сохранение файлов, которые прошли проверку происходит в директорию, прописанную в конфиг объекта app.config['UPLOAD_FOLDER'] = 'saveimages'
, также существует ограничение на максимальный размер, для картинки app.config['MAX_CONTENT_LENGTH']
.
- Слой свертки, размер ядра 3х3, количество карт признаков - 32 шт., функция активации ReLU
- Слой подвыборки, выбор максимального значения из квадрата 2х2
- Слой свертки, размер ядра 3х3, количество карт признаков - 32 шт., функция активации ReLU
- Слой подвыборки, выбор максимального значения из квадрата 2х2
- Слой свертки, размер ядра 3х3, количество карт признаков - 64 шт., функция активации ReLU
- Слой подвыборки, выбор максимального значения из квадрата 2х2
- Слой преобразования из двумерного в одномерное представление
- Полносвязный слой, 64 нейрона, функция активации ReLU
- Слой Dropout
- Выходной слой, 1 нейрон, функция активации sigmoid
Слои с 1 по 6 - для выделения важных признаков, а 7 - 10 для классификации
model = Sequential()
model.add(Conv2D(32, (3, 3), input_shape=input_shape))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation('sigmoid'))
Обучение модели проводилось с использованием генераторов, о чем подробно можно посмотреть в binary.ipynb
Качество работы нейронной сети binary.h5
:
>>>scores = model.evaluate_generator(test_generator, nb_test_samples // batch_size)
>>>print("Точность на тестовых данных: {} %".format(scores[1]*100))
Точность на тестовых данных: 83.52000117301941 %
При реализации дянной нейронной сети, я использовал подход Transfer leaning
, когда берется пердварительно обученная нейронная сеть и дообучается под конкретную задачу
В моем случае, я взял нейронную сеть VGG16
, и модифицировал под задачу бинарной классификации. Для этого к сверточной части сети VGG16
была добавлена (точнее заменена) часть отвечающая за классификацию чтобы на выходе получить информацию не о 1000 объектах, как в сети VGG16, а только о 2-х - Кошка и Собака.
Для этого, в параметре include_top=False
, я установил значение False, чтобы загрузить только ту часть сети VGG16, которая отвечает за выделение характерных признаков в изображении.
Таким образом обучается только новая часть сети, отвечающая за классификацию:
model.add(Flatten())
model.add(Dense(256))
model.add(Activation('relu'))
model.add(Dropout(0.5))
# Выходной слой с 1-им нейроном
model.add(Dense(1))
model.add(Activation('sigmoid'))
model.summary()
Качество работы нейронной сети transferlearning.h5
:
>>>scores = model.evaluate_generator(test_generator, nb_test_samples // batch_size)
>>>print("Точность на тестовых данных: {} %".format(scores[1]*100))
Точность на тестовых данных: 91.33333563804626 %
P.s. При тестировании данной модели с Web частью, совместно работающей системы получить не получилось, возможно проблемы в том, каким образом сохраняется обученная модель на диск и впоследствии загружается для использования в Web приложение.