Vous pouvez télécharger le modèle EfficientDet entraîné avec l'ensemble de données créé à l'aide de la méthode indiquée dans cet article à partir du référentiel Github (https://github.com/kosuke1701/pretrained-efficdet-character-head).
Nous avons également préparé une Démo dans laquelle vous pouvez essayer le modèle formé avec Google colaboratory, alors jouez avec.
Je voulais détecter le visage dans l'illustration pour améliorer la précision de l 'Outil de classification automatique des illustrations de caractères que j'ai récemment développé.
Dans la détection de visage de l'animation, Efforts utilisant OpenCV et Efforts utilisant YOLO / items / 054ee8266d5b9e0c704e) a été publié sous forme d'article. Cependant, la précision du modèle OpenCV semble être limitée, et l'article YOLO ne semble pas publier le modèle entraîné (je suis désolé s'il est publié).
Alors cette fois, j'ai décidé d'apprendre le modèle de détection d'objets par moi-même. Cependant, il n'y a pas d'ensemble de données, donc cette fois je vais commencer par les annotations moi-même.
La détection d'objets étant un domaine de recherche relativement important, il semble que de nombreux outils d'annotation soient ouverts au public.
Cette fois, en me référant à l 'article de comparaison de ces outils, j'ai utilisé LabelImg. Annoté.
La préparation de l'annotation est très simple, après avoir préparé l'environnement nécessaire, préparez le fichier de définition de classe classes.txt
à annoter, et mettez les images à annoter dans un répertoire (par exemple, ʻimage_dir`). Il suffit de laisser.
Le fichier de définition de classe est aussi simple que d'écrire le nom de la classe sur chaque ligne. Par exemple, dans ce cas, nous voulons juste détecter le "visage", donc ce sera comme suit.
classes.txt
face
Pour démarrer l'outil d'annotation:
python labelImg.py image_dir classes.txt
L'interface graphique de l'outil est extrêmement intuitive, il suffit d'appuyer sur la touche w
pour commencer à créer une Bouding Box puis de cliquer sur les points qui correspondent aux deux extrémités de la diagonale.
Cet outil dispose d'une variété de raccourcis utiles, mais ceux que j'ai utilisés le plus souvent étaient:
Clé | une fonction |
---|---|
w | Commencez à créer une nouvelle boîte englobante. |
d | Passez à l'image suivante. |
a | Passez à l'image précédente. |
Ctrl+S | Enregistrez le résultat de l'annotation. |
Les résultats d'annotation peuvent être enregistrés dans deux formats, Pascal VOC et YOLO. (La valeur par défaut est PascalVOC.)
Pour faciliter la gestion, j'ai enregistré le fichier xml du résultat de l'annotation dans le même répertoire que l'image. Grâce à cela, une fois que j'ai fermé l'outil et redémarré l'annotation, le résultat de l'annotation précédent était automatiquement chargé.
Dans une récente recherche sur la détection d'objets, l'ensemble de données COCO 2017 est souvent utilisé comme référence, et il semble que de nombreuses implémentations publiques d'articles entrent également dans ce format.
Donc, cette fois, j'ai écrit le code de prétraitement pour convertir le résultat de l'annotation avec LabelImg au format COCO. Le code de prétraitement est disponible sur Github.
En créant ce code de prétraitement, j'ai fait référence à cet article pour le format spécifique. Veuillez vous référer à ceux qui sont intéressés par des formats plus détaillés.
La structure de fichier du jeu de données final est la suivante. Remplacez project_name
par le nom de votre choix.
project_name
+- train
| +- <Image de formation>
+- val
| +- <Image d'évaluation>
+- annotations
+- instances_train.json
+- instances_val.json
Exécutez la commande suivante pour exécuter le code de prétraitement. Dans ce qui suit, on suppose que le fichier XML du résultat de l'annotation par LabelImg est enregistré sous le répertoire tel que `
#Données d'entraînement
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> ...
#Données d'évaluation (il suffit de changer train en val)
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'> ...
Les hypothèses suivantes sont supposées:
Il existe plusieurs référentiels qui publient des implémentations d'EfficientDet. À la suite de diverses enquêtes zylo117 / Yet-Another-EfficientDet-Pytorch semblait être facile à utiliser, donc cette fois nous l'utiliserons pour apprendre le modèle.
Pour vous entraîner avec votre propre jeu de données, vous devez (1) télécharger des paramètres pré-entraînés et (2) créer un fichier de définition pour votre propre jeu de données, en plus de préparer l'environnement.
Pour les paramètres pré-entraînés de EfficientDet, téléchargez «efficientdet-d * .pth» depuis Github Repository Je vais.
«d0» et «d7» correspondent (probablement) aux paramètres liés à la taille du modèle décrit dans Article, et plus le nombre est petit, plus le poids est léger. Au lieu de cela, il semble être un modèle avec une faible précision.
Cette fois, j'ai téléchargé ʻefficace det-d0.pth` pour le moment.
Il semble que vous deviez créer un fichier yml avec des paramètres dans le répertoire projects
pour apprendre avec votre propre jeu de données.
Les éléments qui doivent être modifiés par rapport aux paramètres de l'ensemble de données COCO sont le nom de l'ensemble de données nom_projet
, la liste des noms de classe à détecter ʻobj_list et le nombre de GPU à utiliser
num_gpus`. Faisons le.
Pour ʻanchors_scales et ʻanchors_ratios
, je n'ai pas encore compris les algorithmes détaillés de détection d'objets et d'EfficientDet, donc je les ai laissés comme ensemble de données COCO cette fois.
Dans mon cas, le fichier de définition ressemble à ceci:
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']
Pour effectuer la formation, procédez comme suit: Les hyper paramètres, etc. ne sont pas particulièrement mis à la terre, ils sont donc à titre indicatif uniquement.
python train.py -c 0 -p project_name \
--batch_size 8 --lr 1e-5 --num_epochs 100 \
--load_weights efficientdet-d0.pth \
--data_path <Répertoire de l'ensemble de données créé avec un projet de code de prétraitement_Répertoire avec nom>
Les nombres spécifiés par l'option «-c» correspondent aux «d0» et «d7» mentionnés ci-dessus. Par conséquent, ce nombre et le nombre de «d *» du paramètre pré-entraîné spécifié par «--load_weights» doivent correspondre.
Avec le GTX1070, il a fallu environ 1 heure pour connaître 900 données d'entraînement et 100 époques.
Exécutez ʻefficdet_test.py` pour appliquer réellement le modèle entraîné à l'image et voir quelles seront les performances. Cependant, puisque le nom de l'image d'entrée, etc. est solide dans ce code, si vous le modifiez comme suit
python efficientdet_test.py <d*Numéro correspondant à> <modèle.nom de fichier pth> <Nom de l'image>
Vous pouvez visualiser le résultat réel de la détection avec. ** Appuyez sur n'importe quelle touche pour fermer la fenêtre de l'image affichée. Il peut se figer lorsqu'il est effacé avec le bouton x. ** **
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')
Cette fois, j'ai parcouru tout, de l'annotation du jeu de données de détection d'objets à l'apprentissage du modèle. Je n'ai encore annoté qu'environ 1000 feuilles, mais il semble que je puisse apprendre à un niveau pratique que je ne le pensais quand j'ai vu les performances du modèle du résultat de la formation. J'ai été sauvé parce que l'apprentissage lui-même était étonnamment facile, environ une heure (même si je n'ai pas pu converger correctement).
À l'avenir, je voudrais augmenter le nombre d'annotations pour améliorer la précision de l'outil de classification des illustrations, qui est l'objectif initial.
Recommended Posts