[PYTHON] Jusqu'à ce que vous annotiez votre propre jeu de données et détectiez un objet avec EfficientDet ~ Détection de visage de personnage ~

Qu'est-ce que tu as fait

démo

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.

Arrière-plan (sauter OK)

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.

Préparation des données

Annotation

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é.

Comment utiliser Label Img

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.

Raccourci

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.

Supplément

Prétraitement des données (conversion au format COCO)

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.

Structure hiérarchique de l'ensemble de données

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

Exemple d'exécution de code de prétraitement

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 ` ''. (Plusieurs sélections peuvent être effectuées pour ce répertoire, séparées par des espaces.)

#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:

Apprentissage efficaceDet

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.

Préparation

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.

Paramètres pré-entraînés

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.

Fichier de définition du jeu de données

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']

Apprentissage

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.

Évaluation

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. ** **

Exemple de correction de code d'évaluation

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')

finalement

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

Jusqu'à ce que vous annotiez votre propre jeu de données et détectiez un objet avec EfficientDet ~ Détection de visage de personnage ~
Jusqu'à ce que vous puissiez installer votre propre bibliothèque Python avec pip
Jusqu'à ce que vous hébergiez vous-même votre propre interprète
Entraînez UGATIT avec votre propre jeu de données
Créons un modèle de reconnaissance d'image avec vos propres données et jouons!
Hello World et détection de visage avec opencv-python 4.2
Jusqu'à ce que vous installiez votre propre bibliothèque Python
Jusqu'à ce que vous créiez une clé USB de démarrage Ubuntu sur votre Macbook et installiez Ubuntu sur votre Thinkpad
Essayez de détecter un objet avec RaspberryPi ~ Partie 1: Comparaison de la vitesse de détection ~
Essayez de monter votre visage avec le test AB
Développez et gonflez votre propre ensemble de données Deep Learning
J'ai essayé de détecter un objet avec M2Det!