Обучение объектного детектора AI с помощью Label Studio и MMDetection
Меткировка и обучение требуют некоторой интеграции
Когда я обучал модель детектора объектов AI несколько лет назад - LabelImg был очень полезным инструментом, но экспорт из Label Studio в формат COCO не принимался фреймворком MMDetection..
Для этого требовались дополнительные инструменты и скрипты, чтобы всё заработало.
Перечислю здесь недостающие элементы и некоторые скрипты некоторые из которых я нашёл в интернете, а другие написал сам.
Основные шаги
Подготовка, обучение и использование AI включает в себя
- получение исходных данных (изображений для детекции объектов и классификации)
- аннотирование изображений и подготовка набора данных
- разработку новой модели или поиск подходящей существующей
- обучение модели, иногда с настройкой гиперпараметров
- использование модели для предсказания меток новых изображений (ингеринг)
Здесь я даю точные шаги, как аннотировать данные с помощью Label Studio (шаг 2) и обучить с помощью mmdetection и torchvision (шаг 4), а также касаюсь инференса (шаг 5)
Label Studio
У него есть некоторые открытые источники из программы LabelImg но сейчас он разрабатывается и поддерживается централизованно. И, конечно, есть корпоративная версия.
Все равно он доступен для саморазмещения, что очень приятно.
Настройка и запуск
Можно установить и запустить Label Studio несколькими способами, например, через пакет pip, или через контейнер docker compose. Здесь я использую одиночный docker-контейнер.
Подготовить исходную папку
mkdir ~/ls-data
sudo chown -R 1001:1001 ~/ls-data10
Настройка локального хранилища
mkdir ~/ai-local-store
mkdir ~/ai-local-labels
# настройка дополнительных разрешений
В ~/ai-local-store вы храните файлы изображений, ~/ai-local-labels - синхронизированные метки.
Запустить docker-контейнер
docker run -it -p 8080:8080 \
-e LABEL_STUDIO_HOST=http://your_ip_address:8080/ \
-e LABEL_STUDIO_LOCAL_FILES_SERVING_ENABLED=true \
-e LABEL_STUDIO_LOCAL_FILES_DOCUMENT_ROOT=/ai-local-store \
-e DATA_UPLOAD_MAX_NUMBER_FILES=10000000 \
-v /home/somename/ls-data:/label-studio/data \
-v /home/somename/ai-local-store:/ai-local-store \
-v /home/somename/ai-local-labels:/ai-local-labels \
heartexlabs/label-studio:latest \
label-studio \
--log-level DEBUG
LABEL_STUDIO_HOST - из-за перенаправлений веб-интерфейса LS. DATA_UPLOAD_MAX_NUMBER_FILES … Django ограничил количество загружаемых файлов до 100, что имело ужасные последствия для label studio, поэтому потребовалось указать это новое ограничение. Все остальные настройки хорошо документированы в документации Label Studio.
Импорт конфигурации. В настройках проекта в Облаке Хранения добавьте Источное Хранение типа Локальные Файлы, похожее на:
Не забудьте отметить “Рассматривать каждый объект ведра как исходный файл”, если вы планируете синхронизировать изображения (я думаю, да, вы это делаете), а не json. Если у вас уже есть некоторые метки для этих изображений в отдельном json - вы просто настраиваете это Облачное Хранение. Не нажимая Синхронизировать. А затем импортировать json.
Настройте то же самое для Целевого Облачного Хранения и ai-local-labels - если вы хотите синхронизировать их.
Импорт предварительно аннотированных данных в Label Studio
Люблю формат COCO json. Также Pascal VOC. Но они не совместимы напрямую с Label Studio, поэтому сначала нужно преобразовать в проприетарный формат LS.
Но сначала, возможно, потребуется отфильтровать набор данных. Возможно, вам нужны только некоторые метки, а не все. Мне нравится скрипт filter.py из coco-manager: https://github.com/immersive-limit/coco-manager/blob/master/filter.py
python filter.py --input_json instances_train2017.json --output_json filtered.json --categories person dog cat
Хорошо, теперь установите конвертер. Как рекомендует официальный сайт конвертера:
python -m venv env
source env/bin/activate
git clone https://github.com/heartexlabs/label-studio-converter.git
cd label-studio-converter
pip install -e .
Конвертировать из coco и установить правильную папку
label-studio-converter import coco -i your-input-file.json -o output.json
Импортировать output.json, нажав кнопку Импорт в Label Studio.
Аннотирование
Здесь выполняется много очень творческой работы.
Экспорт
После нажатия кнопки Экспорта в Label Studio и выбора формата COC, посмотрите внутрь этого файла и восхищайтесь именами изображений. Они будут выглядеть так, если вы импортировали метки заранее, не перезаписывая базовый путь изображения
"images": [
{
"width": 800,
"height": 600,
"id": 0,
"file_name": "\/data\/local-files\/?d=\/iteration1001\/123.jpg"
},
Или будут выглядеть так, если вы синхронизировали внешнее Облачное Хранение.
"images": [
{
"width": 800,
"height": 600,
"id": 0,
"file_name": "http:\/\/localhost:8080\/data\/local-files\/?d=iteration1001\/123.jpg"
},
Это не очень приятно. Мы хотим что-то вроде
"images": [
{
"width": 800,
"height": 600,
"id": 0,
"file_name": "iteration1001/123.jpg"
},
Чтобы исправить имена файлов я использовал прекрасные скрипты. Они перезаписывают файл result.json, поэтому, если вам нужен резервный копии заранее - позаботьтесь об этом сами:
sed -i -e 's/\\\/data\\\/local-files\\\/?d=\\\///g' ~/tmp/result.json
sed -i "s%http:\\\/\\\/localhost:8080\\\/data\\\/local-files\\\/?d=%%" ~/tmp/result.json
sed -i "s%http:\\\/\\\/your_ip_address:8080\\\/data\\\/local-files\\\/?d=%%" ~/tmp/result.json
Резервное копирование данных и БД Label Studio
Внимательно остановите контейнер Label Studio docker и затем выполните что-то вроде
cp ~/ls-data ~/all-my-backups
cp ~/ai-local-store ~/all-my-backups
cp ~/ai-local-labels ~/all-my-backups
Объединение
Иногда нужно объединить несколько наборов данных в один, особенно если вы запускаете несколько итераций.
Я использовал COCO-merger инструмент. После установки и запуска с параметром -h:
python tools/COCO_merger/merge.py -h
COCO Files Merge Usage
python -m COCO_merger.merge --src Json1.json Json2.json --out OUTPUT_JSON.json
Argument parser
usage: merge.py [-h] --src SRC SRC --out OUT
Merge two annotation files to one file
optional arguments:
-h, --help show this help message and exit
--src SRC SRC Path of two annotation files to merge
--out OUT Path of the output annotation file
Да, можно объединить только два файла. Поэтому, если у вас 10 итераций - нужно приложить дополнительные усилия. Тем не менее, я его люблю.
MMDetection
Разделение набора данных
Для разделения набора данных на обучение и тестирование я использовал инструмент COCOSplit.
git clone https://github.com/akarazniewicz/cocosplit.git
cd cocosplit
pip install -r requirements
Тут не так много:
$ python cocosplit.py -h
usage: cocosplit.py [-h] -s SPLIT [--having-annotations]
coco_annotations train test
Splits COCO annotations file into training and test sets.
positional arguments:
coco_annotations Path to COCO annotations file.
train Where to store COCO training annotations
test Where to store COCO test annotations
optional arguments:
-h, --help show this help message and exit
-s SPLIT A percentage of a split; a number in (0, 1)
--having-annotations Ignore all images without annotations. Keep only these
with at least one annotation
--multi-class Split a multi-class dataset while preserving class
distributions in train and test sets
Чтобы запустить разделение coco:
python cocosplit.py --having-annotations \
--multi-class \
-s 0.8 \
source_coco_annotations.json \
train.json \
test.json
Напомним, чтобы добавить свойства лицензий в начало файла json набора данных, где-то после первого “{”: Этот инструмент разделения действительно хочет это.
"licenses": [],
Настройка
Да, конфигурации моделей сложны.
Но mask-rcnn довольно быстр и имеет разумную скорость детекции. См. здесь для деталей конфигурации: https://mmdetection.readthedocs.io/en/latest/user_guides/train.html#train-with-customized-datasets
# Новая конфигурация наследует базовую конфигурацию, чтобы подчеркнуть необходимые изменения
_base_ = '/home/someusername/mmdetection/configs/mask_rcnn/mask-rcnn_r50-caffe_fpn_ms-poly-1x_coco.py'
# Нам также нужно изменить num_classes в голове, чтобы соответствовать аннотациям набора данных
model = dict(
roi_head=dict(
bbox_head=dict(num_classes=3),
mask_head=dict(num_classes=3)))
# Изменить настройки, связанные с набором данных
data_root = '/home/someusername/'
metainfo = {
'classes': ('MyClass1', 'AnotherClass2', 'AndTheLastOne3'),
'palette': [
(220, 20, 60),
(20, 60, 220),
(60, 220, 20),
]
}
train_dataloader = dict(
batch_size=1,
dataset=dict(
data_root=data_root,
metainfo=metainfo,
ann_file='train.json',
data_prefix=dict(img='')))
val_dataloader = dict(
dataset=dict(
data_root=data_root,
metainfo=metainfo,
ann_file='test.json',
data_prefix=dict(img='')))
test_dataloader = val_dataloader
# Изменить настройки, связанные с метриками
val_evaluator = dict(ann_file=data_root+'test.json')
test_evaluator = val_evaluator
# Мы можем использовать предварительно обученную модель Mask RCNN для получения более высокой производительности
load_from = 'https://download.openmmlab.com/mmdetection/v2.0/mask_rcnn/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco/mask_rcnn_r50_caffe_fpn_mstrain-poly_3x_coco_bbox_mAP-0.408__segm_mAP-0.37_20200504_163245-42aa3d00.pth'
# если вам нравятся длинные фильмы
# по умолчанию здесь, если я правильно помню, 12
train_cfg = dict(max_epochs=24)
Что-то, на что стоит посмотреть, если маски не нужны: https://mmdetection.readthedocs.io/en/latest/user_guides/single_stage_as_rpn.html
Обучение
Предположим, у вас есть ваша конфигурация модели в /home/someusername/myproject/models/configs/mask-rcnn_r50-caffe_fpn_ms-poly-1x_v1.0.py . Скрипт обучения - стандартный вызов инструмента mmdetection:
cd ~/mmdetection
python tools/train.py \
/home/someusername/myproject/models/configs/mask-rcnn_r50-caffe_fpn_ms-poly-1x_v1.0.py \
--work-dir /home/someusername/myproject/work-dirs/my-object-detector-v1.0-mask-rcnn_r50-caffe_fpn_ms-poly-1x
Инференс
Некоторые документы здесь: https://mmdetection.readthedocs.io/en/latest/user_guides/inference.html
from mmdet.apis import DetInferencer
inferencer = DetInferencer(
model='/home/someusername/myproject/models/configs/mask-rcnn_r50-caffe_fpn_ms-poly-1x_v1.0.py',
weights='/home/someusername/myproject/work-dirs/my-object-detector-v1.0-mask-rcnn_r50-caffe_fpn_ms-poly-1x/epoch_12.pth')
# запустить для одного файла:
# inferencer('demo/demo.jpg', out_dir='/home/someusername/myproject/test-output/1.0/', show=True)
# или для целой папки
inferencer('/home/someusername/myproject/test-images/', out_dir='/home/someusername/myproject/test-output/1.0/', no_save_pred=False)
Полезные ссылки
Надеюсь, это поможет вам как-то.
Другие полезные материалы см. на
- Сайте Label Studio: https://labelstud.io/
- Документация MMDetection: https://mmdetection.readthedocs.io/en/latest/get_started.html
- Справочник по Bash
- Обнаружение арматурных стержней бетонных конструкций с tensorflow
- Справочник по Python
- Справочник по Conda
- Flux текст в изображение
- Справочник по Ollama
- Справочник по Docker
- Слоистые лямбды с AWS SAM и Python
- Генерация PDF в Python - библиотеки и примеры"