МИНОБРНАУКИ РОССИИ
САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ
ЭЛЕКТРОТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ
«ЛЭТИ» ИМ. В.И. УЛЬЯНОВА (ЛЕНИНА)
Кафедра вычислительной техники
Отчёт по проекту
по дисциплине «Нейронные сети»
Тема: Разработка модели нейронной сети для классификации изображений
Студенты гр. |
|
Преподаватель |
Викснин И.И. |
СОДЕРЖАНИЕ
Введение 3
Введение 3
Постановка задачи 3
Постановка задачи 3
Сбор данных 3
Сбор данных 3
План работы 3
План работы 3
Добавление аугментированных фотографий 4
Добавление аугментированных фотографий 4
Подготовка данных 8
Подготовка данных 8
Создание новой папочной структуры 11
Создание новой папочной структуры 11
Демонстрация работы архитектуры 14
Демонстрация работы архитектуры 14
Обучение с помощью CNN 18
Обучение с помощью CNN 18
Принципы предыдущих архитектур 28
Принципы предыдущих архитектур 28
Вывод 33
Вывод 33
Введение
Постановка задачи
Целями разработки проекта являются: получение навыков работы со свёрточными нейронными сетями (CNN), получение опыта при подготовки датасета к обучению, создание и анализ архитектур для нейронных сетей на Python.
Сбор данных
Набор данных представлен 7000 изображениями автомобилей на 197 классов по марке, году выпуска и модели. Для получения адекватных результатов будет применена аугментация данных (библиотеки Torch.Transforms и/или Albumentations). После добавления аугментированных изображений файлов стало в 2 раза больше (14000).
План работы
Аугментация данных;
Создание новой папочной структуры;
Распаковка и определение меток класса;
Разработка архитектур и обучение.
Добавление аугментированных фотографий
Для того, чтобы модель обучалась не только на легкоразличимых фотографиях, но и на тех экземплярах, что приближены к снимкам, совершаемым в реальной жизни (с различным уровнем освещённости, с различным размером попадаемого в кадр объекта, с различным уровнем качества, то есть с возможной размытостью, с различным углом поворота относительно снимаемого объекта) производится аугментация данных фотографий.
Мы будем использовать следующие методы аугментации данных:
Resize – Выбор случайного обреза 224x224;
Random Rotation – Случайный поворот на небольшой угол в 10*;
Random Flip – Рандомное отражение по горизонтиали;
Gauss Blur – Применение Гауссовского размытия;
Мы производим удаление старых аугментированных фотографий, если они есть, то есть подготавливаем датасет к загрузке новых аугментированных фотографий, чтобы не было ошибок и коллизий:
# Удаление всех аугментированных фотографий
dir_name = DATASET_PATH + "/dataset"
all_files = os.listdir(dir_name)
print(len(all_files))
# + обновите файл csv
for file in all_files:
if "aug" in file:
os.remove(os.path.join(dir_name, file))
Создаём новые аугментированные фотографии и добавляем их в датасет, а также трансформируем тензоры фотографий в формат 224x224 для новых аугментированных изображений:
all_files = os.listdir(dir_name)
print(len(all_files))
import os
import sys
import PIL
from PIL import Image
from imgaug import augmenters as iaa
import imageio.v2 as imageio
# Определение преобразований
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.RandomHorizontalFlip(), # Случайное отражение по горизонтали
transforms.RandomRotation(10), # Случайный поворот на 10 градусов
#transforms.ColorJitter(brightness=0.1, contrast=0.1, saturation=0.1, hue=0.1),
transforms.GaussianBlur(kernel_size=(7, 13), sigma=(0.1, 1.0)), # blur images with a sigma of 0.1 to 1.0
transforms.ToTensor(), # Преобразование в тензор
# transforms.RandomResizedCrop(224), # Случайный обрез на размер 224x224
transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]) # Нормализация
])
def augmentation(pilimg):
return transforms.ToPILImage()(transform(pilimg))
csv_file = pd.read_csv(DATASET_PATH+"/train.csv")
print("Before: ", len(csv_file))
dest_dir = DATASET_PATH + "/dataset"
print("Проверка! Файлов в датасете (до обработки):", end = " ")
all_files = os.listdir(dest_dir)
print(len(all_files))
suffix = "_aug1."
# files = ["/content/drive/MyDrive/Colab Notebooks/dataset/dataset/00001.jpg"]
files = [os.path.join(path, name) for path, subdirs, files in os.walk(dest_dir) for name in files]
files.sort()
# print(dest_dir, files)
gi, N = 0, len(files)
for file_i in files:
if "_aug" not in file_i:
file_i_rel = os.path.relpath(file_i, dest_dir)
file_i_out = os.path.join(dest_dir, file_i_rel)
file_parts = file_i_out.split(".")
imagepil = PIL.Image.open(file_i)
imagepil = imagepil.convert('RGB')
imagepil.load()
imagepil = augmentation(imagepil)
new_filename = file_parts[0]+suffix+file_parts[1]
imagepil.save(new_filename)
new_classs = csv_file[csv_file.image == file_i_rel].Class.item()
new_row = pd.Series({'image': os.path.relpath(new_filename, dest_dir),
'Class': new_classs})
csv_file = csv_file.append(new_row, ignore_index=True)
# csv_file = pd.concat([csv_file, new_row])
gi+=1
if gi % 1000 == 0:
print("Прошло файлов: " + str(gi))
# Как отсортировать строки по имени в csv?
csv_file = csv_file.sort_values(by=["image"])
print("After: ", len(csv_file))
csv_file.to_csv(DATASET_PATH+"/train.csv", index=False)
print("Проверка! Файлов в датасете (после обработки):", end = " ")
all_files = os.listdir(dest_dir)
print(len(all_files))
Подготовка данных
Произведём импорт необходимых библиотек, монтирование диска, с которого будем считывать фотографии, а также определив их по классам, указанным в файле “train.csv”. Затем трансформируем новые аугментированные фотографии в определённый заранее формат – 224x224 пикселя для корректной работы модели, чтобы она читала и загружала в тензоры один формат для всех данных.
Мы не будем менять формат фотографий, то есть не будем конвертировать имеющиеся фотографии в формат 224x224 пикселя, мы будем сразу сжимать их при загрузке в тензор.
Производим импорт необходимых библиотек и монтирование диска:
import torch
import torchvision
# dataset preparation
import torchvision.transforms as transforms
# NN
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import models as torch_models
# Utils
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# Other
import os
import zipfile
import requests
import hashlib
import random
import time
import datetime
import PIL
from PIL import Image
np.random.seed(5051)
device = "cuda" if torch.cuda.is_available() else "cpu"
#DATASET_PATH = "/content/drive/MyDrive/dataset"
DATASET_PATH = "/content/drive/MyDrive/Colab Notebooks/dataset"
from google.colab import drive
drive.mount('/content/drive/')
Читаем csv-файл, который содержит метки класса:
csv_file = pd.read_csv(DATASET_PATH+"/train.csv")
print(csv_file)
print(len(csv_file))
# classes = list(set(csv_file["Class"]))
files_cars = list(csv_file["image"])
# print(classes)
print(files_cars)
Создание новой папочной структуры
На основе ImageFolder мы строили тестовую и обучающие выборки для аугментированных фотографий. Изначально на основе оригинала создавалась аугментированная фотография, из которых рандомно делались различные выборки, а метки классов назначались из csv-файла. В ImageFolder изначально имелась структура данных, где каждая папка – это “train” или “test” выборка, в которой были папки с соответствующими классами.
Код структуры:
NEW_DATASET_PATH = "/content/drive/MyDrive/Colab Notebooks/new_dataset"
train_dir = NEW_DATASET_PATH + "/train"
test_dir = NEW_DATASET_PATH + "/test"
import shutil
# Заблокировать на случай, если уже создана папочная структура
os.mkdir(NEW_DATASET_PATH)
os.mkdir(train_dir)
os.mkdir(test_dir)
classes = set(list(csv_file["Class"]))
for classs in classes:
os.mkdir(os.path.join(train_dir, str(classs)))
os.mkdir(os.path.join(test_dir, str(classs)))
# ------------------------------------------------------------
all_files = os.listdir(DATASET_PATH+"/dataset")
random.shuffle(all_files)
# Разделяем тренировочную и тестовую выборки в соответствие 90 на 10
length = len(all_files)
bound = int(length*0.9)
train_files = all_files[0:bound]
test_files = all_files[bound:length]
def generate_new_folder(files, dir):
for file in files:
classs = str(csv_file[csv_file.image == file].Class.item())
src_file = os.path.join(DATASET_PATH+"/dataset", file)
dest_file = os.path.join(dir, classs, file)
try:
shutil.copyfile(src_file, dest_file)
except FileNotFoundError:
print("No such file or directory: ", src_file)
# раскидывает файлы по папочкам
generate_new_folder(train_files, train_dir)
generate_new_folder(test_files, test_dir)