[PYTHON] Bis Sie Ihren eigenen Datensatz mit Anmerkungen versehen und ein Objekt mit EfficientDet ~ Zeichengesichtserkennung ~ erkennen

Was hast du getan

Demo

Sie können das trainierte EfficientDet-Modell mit dem Datensatz, der mit der in diesem Artikel angegebenen Methode erstellt wurde, aus dem Github-Repository (https://github.com/kosuke1701/pretrained-efficientdet-character-head) herunterladen.

Wir haben auch eine [Demo] vorbereitet (https://colab.research.google.com/drive/1zabpphmfq2P5kTBV7WiZOz-VOYJLx89S?usp=sharing), in der Sie das trainierte Modell mit Google Colaboratory ausprobieren können. Spielen Sie also bitte damit.

Hintergrund (OK überspringen)

Ich wollte das Gesicht in der Abbildung erkennen, um die Genauigkeit des kürzlich entwickelten Tools zur automatischen Klassifizierung von Zeichenillustrationen zu verbessern.

Bei der Gesichtserkennung von Animationen Bemühungen mit OpenCV und Bemühungen mit YOLO / items / 054ee8266d5b9e0c704e) wurde als Artikel veröffentlicht. Die Genauigkeit des OpenCV-Modells scheint jedoch begrenzt zu sein, und der YOLO-Artikel scheint das trainierte Modell nicht zu veröffentlichen (es tut mir leid, wenn es veröffentlicht wird).

Deshalb habe ich mich dieses Mal entschlossen, das Objekterkennungsmodell selbst zu lernen. Da jedoch kein Datensatz vorhanden ist, beginne ich dieses Mal selbst mit Anmerkungen.

Datenaufbereitung

Anmerkung

Da die Objekterkennung ein relativ wichtiges Forschungsfeld ist, scheinen viele Werkzeuge für Anmerkungen für die Öffentlichkeit zugänglich zu sein.

Diesmal unter Bezugnahme auf den Vergleichsartikel dieser Tools unter Verwendung von LabelImg Kommentiert.

Verwendung von Label Img

Die Vorbereitung für die Annotation ist sehr einfach. Nachdem Sie die erforderliche Umgebung vorbereitet haben, bereiten Sie die zu kommentierende Klassendefinitionsdatei classes.txt vor und legen Sie die zu annotierenden Bilder in einem Verzeichnis ab (z. B. image_dir). Lass es einfach.

Die Klassendefinitionsdatei ist so einfach wie das Schreiben des Klassennamens in jede Zeile. In diesem Fall möchten wir beispielsweise nur das "Gesicht" erkennen, also wie folgt.

classes.txt


face

So starten Sie das Anmerkungswerkzeug:

python labelImg.py image_dir classes.txt

Die Benutzeroberfläche des Tools ist äußerst intuitiv. Drücken Sie einfach die Taste "w", um eine Bouding Box zu erstellen, und klicken Sie dann auf die Punkte, die beiden Enden der Diagonale entsprechen.

Abkürzung

Dieses Tool verfügt über eine Reihe nützlicher Verknüpfungen, die ich jedoch am häufigsten verwendet habe:

Schlüssel Funktion
w Erstellen Sie eine neue Begrenzungsbox.
d Fahren Sie mit dem nächsten Bild fort.
a Zum vorherigen Bild wechseln.
Ctrl+S Speichern Sie das Anmerkungsergebnis.

Ergänzung

Datenvorverarbeitung (Konvertierung in das COCO-Format)

In der jüngsten Objekterkennungsforschung wird der COCO 2017-Datensatz häufig als Benchmark verwendet, und es scheint, dass viele öffentliche Implementierungen von Papieren auch dieses Format eingeben.

Also habe ich dieses Mal den Vorverarbeitungscode geschrieben, um das Ergebnis der Annotation mit LabelImg in das COCO-Format zu konvertieren. Der Vorverarbeitungscode ist auf [Github] verfügbar (https://github.com/kosuke1701/labelimg-coco-preprocess).

Bei der Erstellung dieses Vorverarbeitungscodes habe ich für das jeweilige Format auf diesen Artikel verwiesen. Bitte wenden Sie sich an diejenigen, die an detaillierteren Formaten interessiert sind.

Hierarchische Struktur des Datensatzes

Die Dateistruktur des endgültigen Datensatzes ist wie folgt. Ersetzen Sie "Projektname" durch einen beliebigen Namen.

project_name
+- train
|  +- <Trainingsbild>
+- val
|  +- <Bewertungsbild>
+- annotations
   +- instances_train.json
   +- instances_val.json

Beispiel für die Vorverarbeitung von Code

Führen Sie den folgenden Befehl aus, um den Vorverarbeitungscode auszuführen. Im Folgenden wird davon ausgegangen, dass die XML-Datei des Anmerkungsergebnisses von LabelImg in einem Verzeichnis wie "" gespeichert ist. (Für dieses Verzeichnis können mehrere Auswahlen getroffen werden, die durch Leerzeichen getrennt sind.)

#Trainingsdaten
python convert_to_coco.py \
    --image-root-dir project_name/train \
    --annotation-fn project_name/annotations/instances_train.json \
    --copy-images --same-dir \
    --annotation-dir <DIR1> <DIR2> ...

#Bewertungsdaten (einfach Zug in Wert ändern)
python convert_to_coco.py \
    --image-root-dir project_name/val \
    --annotation-fn project_name/annotations/instances_val.json \
    --copy-images --same-dir \
    --annotation-dir <DIR1'> <DIR2'> ...

Als Annahmen wird Folgendes angenommen:

Effizientes Lernen

Es gibt mehrere Repositorys, die Implementierungen von EfficientDet veröffentlichen. Als Ergebnis verschiedener Untersuchungen zylo117 / Noch-ein-effizienter-Tet-Pytorch schien einfach zu bedienen zu sein, daher werden wir es dieses Mal verwenden, um das Modell zu lernen.

Vorbereitung

Um mit Ihrem eigenen Datensatz zu trainieren, müssen Sie (1) vorab trainierte Parameter herunterladen und (2) zusätzlich zur Vorbereitung der Umgebung eine Definitionsdatei für Ihren eigenen Datensatz erstellen.

Vorab trainierte Parameter

Laden Sie für vorab trainierte Parameter von EfficientDet 'Efficientdet-d * .pth' von [Github Repository] herunter (https://github.com/zylo117/Yet-Another-EfficientDet-Pytorch#pretrained-weights-and-benchmark). Ich werde.

d0 und d7 entsprechen (wahrscheinlich) den Einstellungen in Bezug auf die Größe des in Artikel beschriebenen Modells. Je kleiner die Zahl, desto leichter das Gewicht. Stattdessen scheint es sich um ein Modell mit geringer Genauigkeit zu handeln.

Dieses Mal habe ich vorerst effizientdet-d0.pth heruntergeladen.

Datensatzdefinitionsdatei

Es scheint, dass Sie eine XML-Datei mit Einstellungen im Verzeichnis "Projekte" erstellen müssen, um mit Ihrem eigenen Datensatz zu lernen.

Die Elemente, die in den COCO-Dataset-Einstellungen geändert werden müssen, sind der Dataset-Name "Projektname", die Liste der zu erkennenden Klassennamen "obj_list" und die Anzahl der zu verwendenden GPUs "num_gpus". Machen wir das.

Für anchorors_scales und anchorors_ratios habe ich die detaillierten Algorithmen der Objekterkennung und EfficientDet noch nicht verstanden, daher habe ich sie diesmal als COCO-Datensatz belassen.

In meinem Fall sieht die Definitionsdatei folgendermaßen aus:

projects/coco_pixiv.yml


project_name: coco_pixiv  # also the folder name of the dataset that under data_path folder
train_set: train
val_set: val
num_gpus: 1

# mean and std in RGB order, actually this part should remain unchanged as long as your dataset is similar to coco.
mean: [0.485, 0.456, 0.406]
std: [0.229, 0.224, 0.225]

# this is coco anchors, change it if necessary
anchors_scales: '[2 ** 0, 2 ** (1.0 / 3.0), 2 ** (2.0 / 3.0)]'
anchors_ratios: '[(1.0, 1.0), (1.4, 0.7), (0.7, 1.4)]'

# must match your dataset's category_id.
# category_id is one_indexed
obj_list: ['face']

Lernen

Gehen Sie wie folgt vor, um das Training durchzuführen: Hyperparameter usw. sind nicht besonders geerdet, daher dienen sie nur als Referenz.

python train.py -c 0 -p project_name \
    --batch_size 8 --lr 1e-5 --num_epochs 100 \
    --load_weights efficientdet-d0.pth \
    --data_path <Datensatzverzeichnis, das mit dem Vorverarbeitungscode-Projekt erstellt wurde_Verzeichnis mit Namen>

Die Option "-c" gibt den numerischen Wert an, der dem oben genannten "d0" oder "d7" entspricht. Daher müssen diese Anzahl und die Anzahl von "d *" des durch "--load_weights" angegebenen vorab trainierten Parameters übereinstimmen.

Mit der GTX1070 dauerte es ungefähr 1 Stunde, um ungefähr 900 Trainingsdaten und 100 Epochen zu lernen.

Auswertung

Führen Sie effizientdet_test.py aus, um das trainierte Modell tatsächlich auf das Bild anzuwenden und zu sehen, wie gut es funktioniert. Da der Name des Eingabebildes usw. in diesem Code jedoch fest ist, ändern Sie ihn wie folgt

python efficientdet_test.py <d*Nummer entsprechend> <Modell-.p-ter Dateiname> <Bildname>

Sie können das tatsächliche Erkennungsergebnis mit visualisieren. ** Drücken Sie eine beliebige Taste, um das Fenster des angezeigten Bildes zu schließen. Es kann einfrieren, wenn es mit der x-Taste gelöscht wird. ** **.

Beispiel für eine Korrektur des Auswertungscodes

efficientdet_test.py



# Author: Zylo117

"""
Simple Inference Script of EfficientDet-Pytorch
"""
import sys
import time
import torch
from torch.backends import cudnn
from matplotlib import colors

from backbone import EfficientDetBackbone
import cv2
import numpy as np

from efficientdet.utils import BBoxTransform, ClipBoxes
from utils.utils import preprocess, invert_affine, postprocess, STANDARD_COLORS, standard_to_bgr, get_index_label, plot_one_box

compound_coef = int(sys.argv[1])
force_input_size = None  # set None to use default size
img_path = sys.argv[3]

# replace this part with your project's anchor config
anchor_ratios = [(1.0, 1.0), (1.4, 0.7), (0.7, 1.4)]
anchor_scales = [2 ** 0, 2 ** (1.0 / 3.0), 2 ** (2.0 / 3.0)]

threshold = 0.2
iou_threshold = 0.2

use_cuda = True
use_float16 = False
cudnn.fastest = True
cudnn.benchmark = True

obj_list = ['face']


color_list = standard_to_bgr(STANDARD_COLORS)
# tf bilinear interpolation is different from any other's, just make do
input_sizes = [512, 640, 768, 896, 1024, 1280, 1280, 1536]
input_size = input_sizes[compound_coef] if force_input_size is None else force_input_size
ori_imgs, framed_imgs, framed_metas = preprocess(img_path, max_size=input_size)

if use_cuda:
    x = torch.stack([torch.from_numpy(fi).cuda() for fi in framed_imgs], 0)
else:
    x = torch.stack([torch.from_numpy(fi) for fi in framed_imgs], 0)

x = x.to(torch.float32 if not use_float16 else torch.float16).permute(0, 3, 1, 2)

model = EfficientDetBackbone(compound_coef=compound_coef, num_classes=len(obj_list),
                             ratios=anchor_ratios, scales=anchor_scales)
model.load_state_dict(torch.load(sys.argv[2]))
model.requires_grad_(False)
model.eval()

if use_cuda:
    model = model.cuda()
if use_float16:
    model = model.half()

with torch.no_grad():
    features, regression, classification, anchors = model(x)

    regressBoxes = BBoxTransform()
    clipBoxes = ClipBoxes()

    out = postprocess(x,
                      anchors, regression, classification,
                      regressBoxes, clipBoxes,
                      threshold, iou_threshold)

def display(preds, imgs, imshow=True, imwrite=False):
    for i in range(len(imgs)):
        if len(preds[i]['rois']) == 0:
            continue

        for j in range(len(preds[i]['rois'])):
            x1, y1, x2, y2 = preds[i]['rois'][j].astype(np.int)
            obj = obj_list[preds[i]['class_ids'][j]]
            score = float(preds[i]['scores'][j])
            plot_one_box(imgs[i], [x1, y1, x2, y2], label=obj,score=score,color=color_list[get_index_label(obj, obj_list)])


        if imshow:
            cv2.imshow('img', imgs[i])
            cv2.waitKey(0)

        if imwrite:
            cv2.imwrite(f'test/img_inferred_d{compound_coef}_this_repo_{i}.jpg', imgs[i])


out = invert_affine(framed_metas, out)
display(out, ori_imgs, imshow=True, imwrite=True)

print('running speed test...')
with torch.no_grad():
    print('test1: model inferring and postprocessing')
    print('inferring image for 10 times...')
    t1 = time.time()
    for _ in range(10):
        _, regression, classification, anchors = model(x)

        out = postprocess(x,
                          anchors, regression, classification,
                          regressBoxes, clipBoxes,
                          threshold, iou_threshold)
        out = invert_affine(framed_metas, out)

    t2 = time.time()
    tact_time = (t2 - t1) / 10
    print(f'{tact_time} seconds, {1 / tact_time} FPS, @batch_size 1')

Schließlich

Dieses Mal ging ich alles durch, von der Annotation des Objekterkennungsdatensatzes bis zum Erlernen des Modells. Ich habe bisher nur ungefähr 1000 Blätter kommentiert, aber es scheint, dass ich auf einem praktischen Niveau lernen kann, als ich dachte, als ich die Leistung des Modells des Trainingsergebnisses sah. Das Lernen selbst (obwohl ich nicht richtig konvergieren konnte) dauerte ungefähr eine Stunde, was überraschend einfach war, also wurde ich gerettet.

In Zukunft möchte ich die Anzahl der Anmerkungen erhöhen, um die Genauigkeit des Illustrationsklassifizierungswerkzeugs zu verbessern, das der ursprüngliche Zweck ist.

Recommended Posts

Bis Sie Ihren eigenen Datensatz mit Anmerkungen versehen und ein Objekt mit EfficientDet ~ Zeichengesichtserkennung ~ erkennen
Bis Sie Ihre eigene Python-Bibliothek mit pip installieren können
Bis Sie Ihren eigenen Dolmetscher selbst hosten
Trainiere UGATIT mit deinem eigenen Datensatz
Lassen Sie uns ein Bilderkennungsmodell mit Ihren eigenen Daten erstellen und spielen!
Hallo Welt- und Gesichtserkennung mit opencv-python 4.2
Bis Sie Ihre eigene Python-Bibliothek installieren
Bis Sie ein Ubuntu-Boot-USB auf Ihrem Macbook erstellen und Ubuntu auf Ihrem Thinkpad installieren
Versuchen Sie, ein Objekt mit RaspberryPi zu erkennen ~ Teil 1: Vergleich der Erkennungsgeschwindigkeit ~
Versuchen Sie, Ihr Gesicht mit dem AB-Test zu montieren
Erweitern und erweitern Sie Ihren eigenen Deep Learning-Datensatz
Ich habe versucht, ein Objekt mit M2Det zu erkennen!