Учебное пособие по классификации изображений часов (классификация изображений часов по брендам)

Требуемые пакеты

pip install git+https://github.com/lanpa/tensorboard-pytorch
pip install tensorflow
pip install git+https://github.com/fastai/fastai.git
pip install google_images_download

Сбор данных с помощью googleimagesскачать

Классы, используемые для классификации, будут Audemars Piguet, Hamilton, Hublot, Jaeger Lecoultre, Omega, Patek Philippe, Rolex, Seiko, Sinn, Tag Heuer и Vacheron Constantin (не стесняйтесь добавлять столько классов/брендов, сколько хотите).

Чтобы получить обучающие образцы для каждого класса, мы будем использовать библиотеку загрузки googleimages здесь, которая собирает обучающие изображения из Google. Библиотека также позволяет пользователям указывать желаемый размер изображений и расширение файла, а также различные другие параметры, которые можно найти на странице github.

Чтобы скачать изображения, запустите команду шаблона

googleimagesdownload -k 'KEYWORD' -o 'OUTPUT DIRECTORY' -l <NUMBER OF IMAGES> --chromedriver 'PATH TO CHROMEDRIVER' --size SIZE

Замените KEYWORD на один из классов/брендов часов, OUTPUT DIRECTORY на каталог, в котором вы хотите сохранить изображения, ‹NUMBER OF IMAGES› на желаемое количество обучающих изображений (рекомендуется 1000), PATH TO CHROMEDRIVER на путь к исполняемый файл chromedriver (см. подробнее об установке chromedriver здесь) и SIZE с малым, средним или большим (рекомендуется большой, чтобы обеспечить лучшую точность классификации)

Пример:

googleimagesdownload -k "seiko" -o "C:\Users\Aidan\Documents\DL_Practice\DL Part 2 2018\data\watch_brands\images" -l 1000 --chromedriver "C:\\Users\\Aidan\\Downloads\\chromedriver.exe" --size large

Fast.ai

Импортировать необходимые пакеты

from fastai.imports import *
from fastai.conv_learner import *
from fastai.sgdr import *
from tensorboardX import SummaryWriter
torch.backends.cudnn.benchmark=True

torch.backends.cudnn.benchmark=True увеличивает производительность/скорость обучения

PATH = Path('data/watch_brands')
IMG_PATH = PATH/'images'
FILES_CSV = PATH/'files.csv'

Сохраните необходимые пути к каталогам, FILES_CSV — это путь к csv, который мы создадим, в котором будут храниться имена файлов и классы изображений.

sz=224; bs=64
arch=resnet50

Сохраняйте размер изображений как 224 (медленно обучайте модель на меньших изображениях до больших изображений, что называется прогрессивным изменением размера), а размер пакета должен быть настолько большим, насколько позволяет память графического процессора. Мы будем использовать архитектуру resnet50.

img_files = IMG_PATH.glob('**/**/*.*')
img_files = np.array([x for x in img_files])
np.random.shuffle(img_files)
img_clas = np.array([str(x).split('\\')[-2] for x in img_files])

Сохраните имена файлов изображений в виде массива numpy, перетасуйте расположение массива, а затем сохраните классы каждого изображения (имя каталога изображений)

with FILES_CSV.open('w') as f:
    for fn, c in zip(img_files, img_clas): f.write(f'{fn.relative_to(IMG_PATH)},{c}\n')

Создайте CSV-файл с именем файла, в котором первый столбец содержит путь к файлу относительно каталога изображений, а второй столбец содержит класс изображения.

val_idxs = get_cv_idxs(len(img_files))
aug_tfms = [RandomFlip(), RandomRotate(10), RandomLighting(0.05, 0.05)]
tfms = tfms_from_model(arch, sz, aug_tfms=aug_tfms)
md = ImageClassifierData.from_csv(PATH, 'images', FILES_CSV, bs=bs, tfms=tfms, val_idxs=val_idxs, test_name='test')

Создайте набор проверки, получив индексы для установки в качестве проверки (по умолчанию 20% всех изображений).

Создайте преобразования, создав массив желаемых преобразований fast.ai (RandomFlip, RandomRotate, RandomLighting) и передав его в функцию tfms_from_model, которая возвращает объект tfms (кортеж trn_tfm и val_tfm)

Создайте объект ModelData, используя имя файла csv, желаемый размер пакета, преобразования, индексы проверки и имя тестового каталога (если есть)

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

Создание модели учащегося и обучения с использованием циклических скоростей обучения, прогрессивного изменения размера и дифференциальных скоростей обучения

learner = ConvLearner.pretrained(arch, md, ps=[0.5, 0.5])
learner.metrics = [accuracy]

Установите показатели обучения для точности классификации

learner.lr_find(end_lr=100, wds=1e-5)
learner.sched.plot(n_skip=1)

Используйте lr_finder, чтобы определить оптимальную скорость обучения для обучения модели.

class TensorboardLogger(Callback):
    def __init__(self, model, md, log_name, metrics_names=[], path=None, histogram_freq=100):
        super().__init__()
        self.model = model
        self.md = md
        self.metrics_names = ["validation_loss"]
        self.metrics_names += metrics_names
        self.histogram_freq = histogram_freq
        
        path = path or os.path.join(md.path, "logs")
        self.log_dir = os.path.join(path, log_name)
        
    def on_train_begin(self):
        self.iteration = 0
        self.epoch = 0
        self.writer = SummaryWriter(log_dir=self.log_dir)
    def on_batch_begin(self): pass
    def on_phase_begin(self): pass
    def on_epoch_end(self, metrics):
        self.epoch += 1
        
        for val, name in zip(metrics, self.metrics_names):
            self.writer.add_scalar(name, val, self.iteration) 
                
    def on_phase_end(self): pass
    def on_batch_end(self, loss):
        self.iteration += 1
        self.writer.add_scalar("loss", loss, self.iteration)
        
        if self.iteration%self.histogram_freq==0:
            for name, param in self.model.model.named_parameters():
                self.writer.add_histogram(name, param, self.iteration)
    def on_train_end(self):
        try:
            with warnings.catch_warnings():
                warnings.simplefilter("ignore")
                dummy_input = tuple(next(iter(self.md.trn_dl))[:-1])
                self.writer.add_graph(self.model, dummy_input)
        except Exception as e:
            print("Unable to create graph.")
            print(e)
        self.writer.close()

Создайте пользовательский обратный вызов TensorboardLogger, чтобы обеспечить производительность / статистику обучения с использованием tensorboard (полученный пользовательский класс здесь)

lr=3e-3; wd=1e-5
tb_logger = TensorboardLogger(learner.model, md, 'watch classification test', ['accuracy'])
learner.fit(lr, 1, cycle_len=5, wds=wd, use_clr=(20, 10), callbacks=[tb_logger], best_save_name='bestbest')

Установите скорость обучения на значение, немного меньшее минимального значения на графике, и установите скорость снижения веса либо на 1e-6, либо на 1e-5 (соответственно отрегулируйте уменьшение веса, большее уменьшение веса -> больше регуляризации)

Создайте обратный вызов регистратора tensorboard и обучите учащегося. Чтобы просмотреть производительность на tensorboard, выполните команду: tensorboard -logdir='путь к каталогу журналов'

Функция fit принимает несколько обязательных параметров:
1. скорость обучения: установите скорость обучения на 3e-3 на основе lr_finder
2. количество циклов: установите на 1
3. длина цикла: установите значение 5 (определяет количество эпох/количество итераций по всему обучающему набору, обычно определяемое на основе параметров CLR)
4. снижение веса (необязательно): установите значение 1e-5, помогает с регуляризацией (наказывает большие веса)
5. обратные вызовы (необязательно): список обратных вызовов, которые выполняются в конце каждого пакета или эпохи
6. use_clr (циклическая скорость обучения): принимает кортеж, содержащий 2 значения (количество чтобы разделить скорость обучения на, чтобы получить минимальную скорость и количество итераций для увеличения и уменьшения скорости обучения)
7. best_save_name (необязательно): сохранить модель с наилучшей производительностью, основанную на потерях/точности проверки.

Например, установка значения use_clr (20, 10) подразумевает, что минимальная скорость обучения будет 3e-3/20, и что обучение начнется с минимальной скорости обучения и постепенно будет увеличиваться и достигать максимальной скорости обучения (3e-3) за 1 /10 от общего числа итераций. После этого скорость обучения начнет постепенно снижаться и достигнет минимальной скорости обучения (3e-3/20) после 9/10 от общего числа итераций.

learner.unfreeze()
lr=3e-3; wd=1e-5
lrs=np.array([lr/100, lr/10, lr])
learner.fit(lrs/20, 1, cycle_len=10, wds=wd, use_clr=(32, 10), callbacks=[tb_logger], best_save_name='bestbest')

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

learner.fit(lrs/200, 1, cycle_len=30, wds=wd, use_clr=(32, 10), callbacks=[tb_logger], best_save_name='bestbest')
learner.save('4')

Наконец, тренируйтесь с длиной цикла 30 и пониженной скоростью обучения, чтобы гарантировать, что модель больше не может быть улучшена. Затем измените размер и пакетные параметры объекта ModelData и перезапустите весь процесс, но на этот раз с изображениями большего размера.

После повторения этого процесса до размера изображения 1024 модель должна иметь точность около 88%.

epoch      trn_loss   val_loss   accuracy                                                                              
    0      0.62359    0.410226   0.862729  
    1      0.670505   0.41044    0.872306                                                                              
    2      0.703594   0.418569   0.868316                                                                              
    3      0.540351   0.418307   0.876297                                                                              
    4      0.586124   0.425277   0.858739                                                                              
    5      0.6451     0.433394   0.865124                                                                              
    6      0.513875   0.418064   0.865124                                                                              
    7      0.560347   0.417235   0.86672                                                                               
    8      0.569284   0.42699    0.865922                                                                              
    9      0.540357   0.406808   0.869912                                                                              
    10     0.585541   0.424397   0.871508                                                                              
    11     0.629697   0.403836   0.873105                                                                              
    12     0.578186   0.399353   0.869912                                                                              
    13     0.580718   0.393956   0.871508                                                                              
    14     0.520731   0.446471   0.857941                                                                              
    15     0.598394   0.41884    0.860335                                                                              
    16     0.611838   0.393764   0.873105                                                                              
    17     0.553723   0.41744    0.865922                                                                              
    18     0.612677   0.411182   0.869114                                                                              
    19     0.6611     0.410436   0.865124                                                                              
    20     0.542844   0.390165   0.876297                                                                              
    21     0.659803   0.398199   0.874701                                                                              
    22     0.563547   0.403286   0.865922                                                                              
    23     0.623685   0.386968   0.87071                                                                               
    24     0.599079   0.414476   0.865922                                                                              
    25     0.521744   0.396762   0.877095                                                                              
    26     0.681244   0.413879   0.868316                                                                              
    27     0.525194   0.397991   0.875499                                                                              
    28     0.627125   0.391735   0.877893                                                                              
    29     0.439041   0.391175   0.879489