Как се играе с Quidditch с помощта на TensorFlow Object Detection API

TensorFlow по-добър търсещ ли е от Хари?

Дълбокото обучение никога не престава да ме учудва. Той оказа дълбоко влияние върху няколко области, като победи показателите отляво и отдясно.

Класификацията на изображенията с помощта на конволюционни невронни мрежи (CNN) е сравнително лесна днес, особено с появата на мощни предни опаковки като Keras с TensorFlow заден край. Но какво ще стане, ако искате да идентифицирате повече от един обект в изображение?

Този проблем се нарича „локализация и откриване на обекти“. Много по-труден е от обикновената класификация. Всъщност до 2015 г. локализацията на изображения с помощта на CNN е била много бавна и неефективна. Вижте тази публикация в блога от Dhruv, за да прочетете историята на откриването на обекти в Deep Learning, ако се интересувате.

Източник: CS231n Лекция 8 (2016)

Звучи яко. Но трудно ли е да се кодира?

Не се притеснявайте, API на TensorFlow за откриване на обекти идва на помощ! Те са направили по-голямата част от тежкото повдигане за вас. Всичко, което трябва да направите, е да подготвите набора от данни и да зададете някои конфигурации. Можете да обучите вашия модел и да го използвате след това за извод.

TensorFlow също така осигурява предварително обучени модели, обучени на наборите данни MS COCO, Kitti или на Open Data. Можете да ги използвате като такива, ако просто искате да го използвате за стандартно откриване на обекти. Недостатъкът е, че те са предварително дефинирани. Той може само да предвиди класовете, определени от наборите от данни.

API за откриване на обекти на TensorFlow на работа

Но какво ще стане, ако искате да откриете нещо, което не е в списъка с възможни класове? Това е целта на тази публикация в блога. Ще ви насоча чрез създаването на собствена персонализирана програма за откриване на обекти, използвайки забавен пример на Куидич от вселената на Хари Потър! (За всички, които сте фенове на Междузвездни войни, ето подобна публикация в блога, която може да ви хареса).

Приготвяме се да започнем

Започнете с клонирането на моето хранилище GitHub, намерено тук. Това ще бъде вашата основна директория. Всички файлове, посочени в тази публикация в блога, са достъпни в хранилището.

Освен това можете да клонирате репо модели на TensorFlow. Ако изберете последната, ви трябват само папките с име „тънък“ и „обект_откриване“, така че не се колебайте да премахнете останалите. Не преименувайте нищо в тези папки (освен ако не сте сигурни, че няма да се обърка с кода).

Зависимостите

Ако приемем, че имате инсталиран TensorFlow, може да се наложи да инсталирате още няколко зависимости, което можете да направите, като изпълните следното в основната директория:

pip install -r изисквания.txt

API използва Protobufs за конфигуриране и обучение на параметри на модела. Трябва да съставим библиотеките на Protobuf, преди да ги използваме. Първо, трябва да инсталирате компилатора Protobuf с помощта на командата по-долу:

sudo apt-get install protobuf-компилатор

Сега можете да компилирате Protobuf библиотеките, като използвате следната команда:

protoc object_detection / protos / *. proto --python_out =.

Трябва да добавите пътя на основната си директория, както и тънката си директория към вашата променлива на пътя на Python. Обърнете внимание, че трябва да изпълните тази стъпка всеки път, когато отворите нов терминал. Можете да направите това, като изпълните командата по-долу. Като алтернатива можете да го добавите във файла ~ / .bashrc, за да автоматизирате процеса.

износ PYTHONPATH = $ PYTHONPATH: `pwd`:` pwd` / тънък

Подготовка на входовете

Мотивът ми беше доста прям. Исках да създам Quidditch Seeker, използвайки TensorFlow. По-конкретно, исках да напиша програма за локализиране на доносника при всеки кадър.

Но тогава реших да увелича колове. Какво ще кажете да опитате да идентифицирате всички подвижни части, използвани в Quidditch?

Куидичът има три (уникални) движещи се обекта. Два Bludgers, един Quaffle и един доносник.

Започваме с подготовката на файла label_map.pbtxt. Това ще съдържа всички целеви имена на етикета, както и идентификационен номер за всеки етикет. Обърнете внимание, че идентификационният номер на етикета трябва да започва от 1. Ето съдържанието на файла, който използвах за моя проект.

вещ {
 id: 1
 име: „доносник“
}
вещ {
 id: 2
 име: „треска“
}
вещ {
 id: 3
 име: „bludger“
}

Сега е време за събиране на набора от данни.

Fun! Или скучно, в зависимост от вашия вкус, но все пак това е обичайна задача.

Събрах набора от данни, като взех проба от всички кадри от видеоклип на Хари Потър, използвайки малък кодов фрагмент, който написах, използвайки OpenCV рамката. След като това беше направено, използвах друг фрагмент на код, за да извадя на случаен принцип 300 изображения от набора от данни. Кодовите фрагменти са достъпни в utils.py в моето репо за GitHub, ако искате да направите същото.

Правилно ме чухте. Само 300 изображения. Да, данните ми не бяха огромни Това е главно защото не мога да си позволя да коментирам много изображения. Ако искате, можете да изберете платени услуги като Amazon Mechanical Turk, за да коментирате снимките си.

анотации

Всяка задача за локализиране на изображения изисква основни пояснения за истината. Използваните тук пояснения са XML файлове с 4 координати, представящи местоположението на ограничаващото поле около обекта и неговия етикет. Използваме формат Pascal VOC. Примерно пояснение ще изглежда така:

<Анотация>
  <Име> 182.jpg 
  <Размер>
    <Ширина> 1280 
    <Височина> 586 
    <Дълбочина> 3 
  
  <Сегментирани> 0 
  <Обект>
    <Име> bludger 
    
       581 
       106 
       618 
       142 
    
  
  <Обект>
    <Име> quaffle 
    
       127 
       406 
       239 
       526 
    
  

Може би си мислите: „Наистина ли трябва да преживея болката от ръчно въвеждане на пояснения в XML файлове?“ Абсолютно не! Има инструменти, които ви позволяват да използвате графичен интерфейс, за да рисувате полета върху обекти и да ги пояснявате. Fun! LabelImg е отличен инструмент за потребители на Linux / Windows. Като алтернатива RectLabel е добър избор за потребителите на Mac.

Няколко бележки под линия, преди да започнете да събирате данните си:

  • Не преименувайте файлове с изображения, след като ги поясните. Кодът се опитва да потърси изображение с помощта на името на файла, посочено във вашия XML файл (Кой LabelImg автоматично попълва името на файла с изображение). Освен това, уверете се, че вашето изображение и XML файловете имат едно и също име.
  • Уверете се, че преоразмерите изображенията до желания размер, преди да започнете да ги коментирате. Ако направите това по-късно, поясненията няма да имат смисъл и ще трябва да мащабите стойностите на поясненията в XML.
  • LabelImg може да изведе някои допълнителни елементи към XML файла (като , , ). Не е необходимо да ги премахвате, тъй като те няма да пречат на кода.

В случай, че объркате нещо, файлът utils.py има някои полезни функции, които могат да ви помогнат. Ако просто искате да дадете снимка на Quidditch, можете да изтеглите моята база данни с пояснения вместо това. И двете са достъпни в моето хранилище на GitHub.

И накрая, създайте текстов файл, наречен trainval. Той трябва да съдържа имената на всички ваши изображения / XML файлове. Например, ако имате img1.jpg, img2.jpg и img1.xml, img2.xml във вашия набор от данни, файлът trainval.txt трябва да изглежда така:

img1
img2

Разделете вашия набор от данни в две папки, а именно изображения и пояснения. Поставете label_map.pbtxt и trainval.txt в папката с пояснения. Създайте папка с име xmls в папката с пояснения и поставете всичките си XML в нея. Йерархията на вашата директория трябва да изглежда така:

-base_directory
| -снимка
| -annotations
|| -xmls
|| -label_map.pbtxt
|| -trainval.txt

API приема входове във файловия формат на TFRecords. Не се притеснявайте, лесно можете да конвертирате текущия си набор от данни в необходимия формат с помощта на малка полезна функция. Използвайте файла create_tf_record.py, предоставен в моето репо за преобразуване на вашия набор от данни в TFRecords. Трябва да изпълните следната команда в основната си директория:

python create_tf_record.py \
    --data_dir = `pwd` \
    --output_dir = `pwd`

Ще намерите два файла, train.record и val.record, след като програмата завърши изпълнението. Стандартният разделен набор от данни е 70% за обучение и 30% за валидиране. Можете да промените разделената част във функцията main () на файла, ако е необходимо.

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

Това бе доста дълъг процес за приготвяне на нещата. Краят е почти близо. Трябва да изберем модел за локализация, за да обучим. Проблемът е, че има толкова много възможности за избор. Всяка от тях се различава по отношение на скоростта или точността. Трябва да изберете правилния модел за правилната работа. Ако искате да научите повече за компромиса, този документ е добър прочит.

Накратко, SSD дисковете са бързи, но може да не успеят да открият по-малки обекти с прилична точност, докато по-бързите RCNN са сравнително по-бавни и по-големи, но имат по-добра точност.

API за откриване на обекти на TensorFlow ни предостави куп предварително обучени модели. Силно се препоръчва да се инициира обучение с помощта на предварително обучен модел. Това може значително да намали времето за тренировки.

Редица модели, предварително обучени на MS COCO Dataset

Изтеглете един от тези модели и извлечете съдържанието в основната си директория. Тъй като бях по-фокусиран върху точността, но и исках разумно време за изпълнение, избрах ResNet-50 версията на по-бързия RCNN модел. След извличане ще получите модела контролни точки, замразена графика на извода и файл pipeline.config.

Остава едно последно нещо! Трябва да дефинирате „тренировъчната работа“ във файла pipeline.config. Поставете файла в основната директория. Това, което наистина има значение, е последните няколко реда на файла - трябва само да зададете подчертаните стойности на съответните си файлови места.

gradient_clipping_by_norm: 10.0
  fine_tune_checkpoint: "model.ckpt"
  from_detection_checkpoint: вярно
  брой стъпки: 200000
}
train_input_reader {
  label_map_path: "пояснения / label_map.pbtxt"
  tf_record_input_reader {
    input_path: "train.record"
  }
}
eval_config {
  брой_примери: 8000
  max_evals: 10
  use_moving_aasures: невярно
}
eval_input_reader {
  label_map_path: "пояснения / label_map.pbtxt"
  разбъркване: невярно
  num_epochs: 1
  num_readers: 1
  tf_record_input_reader {
    input_path: "val.record"
  }
}

Ако имате опит в настройката на най-добрите хипер параметри за вашия модел, можете да го направите. Създателите са дали няколко доста кратки насоки тук.

Всички сте готови да обучите модела си сега! Изпълнете командата по-долу, за да започнете тренировъчната работа.

python object_detection / train.py \
--logtostderr \
--pipeline_config_path = pipeline.config \
--train_dir = влак

Моят лаптоп GPU не можеше да се справи с размера на модела (Nvidia 950M, 2GB), така че трябваше да го пусна на процесора. Отне около 7–13 секунди на стъпка на устройството ми. След около 10 000 мъчителни стъпки, моделът постигна доста добра точност. Спрях да тренирам, след като достигна 20 000 стъпки, единствено защото вече отне два дни.

Можете да възобновите обучението от контролна точка, като промените атрибута „fine_tune_checkpoint“ от model.ckpt в model.ckpt-xxxx, където xxxx представлява глобалния номер на стъпка на запазената контролна точка.

Експортиране на модела за извод

Какъв е смисълът от обучението на модела, ако не можете да го използвате за откриване на обекти? API за спасяване отново! Но има уловка. Техният модул за извеждане изисква модел на замразена графика като вход. Не се притеснявайте обаче: използвайки следната команда, можете да експортирате обучения си модел в замразен графичен модел.

python object_detection / export_inference_graph.py \
--input_type = image_tensor \
--pipeline_config_path = pipeline.config \
--trained_checkpoint_prefix = влак / модел.ckpt-xxxxx \
--output_directory = изход

Neat! Ще получите файл, нареченrozen_inference_graph.pb, заедно с куп файлове за контролни точки.

Можете да намерите файл с име inference.py в моето репо за GitHub. Можете да го използвате за тестване или стартиране на вашия модул за откриване на обекти. Кодът е доста обяснителен и е подобен на демонстрацията на обект за откриване, представена от създателите. Можете да го изпълните, като въведете следната команда:

python object_detection / inference.py \
--input_dir = {PATH} \
--output_dir = {PATH} \
--label_map = {PATH} \
--frozen_graph = {PATH} \
--num_output_classes = {NUM}

Заменете маркираните знаци {PATH} с името на файла или пътя на съответния файл / директория. Заменете {NUM} с броя обекти, които сте дефинирали за вашия модел да открие (в моя случай 3).

Резултати

Вижте тези видеоклипове, за да видите сами представянето му! Първият видеоклип демонстрира способността на модела да различава и трите обекта, докато вторият видео се отличава с умението си като търсач.

Доста впечатляващо бих казал! Той има проблем с разграничаването на главите от обектите на Quidditch. Но като се има предвид големината на нашия набор от данни, производителността е доста добра.

Тренирането му прекалено дълго време доведе до огромно пренасочване (вече не беше инвариантно по размер), въпреки че намали някои грешки. Можете да преодолеете това, като разполагате с по-голям набор от данни.

Благодаря ви, че прочетохте тази статия! Натиснете този бутон, ако сте го направили! Надявам се, че ви помогна да създадете своя собствена програма за разпознаване на обекти. Ако имате някакви въпроси, можете да ме изпратите на LinkedIn или да ми изпратите имейл (bharathrajn98@gmail.com).