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.
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.
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.
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.
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. |
Anmerkungsergebnisse können in zwei Formaten gespeichert werden, Pascal VOC und YOLO. (Der Standardwert ist PascalVOC.)
Zur Vereinfachung der Verwaltung habe ich die XML-Datei des Anmerkungsergebnisses im selben Verzeichnis wie das Bild gespeichert. Dank dessen wurde das vorherige Anmerkungsergebnis automatisch geladen, sobald ich das Tool geschlossen und die Anmerkung neu gestartet habe.
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.
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
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 "
#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:
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.
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.
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.
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']
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.
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. ** **.
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')
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