[PYTHON] Rares sont ceux qui ont tiré NODOGURO tournant et ont essayé de compter le nodoguro automatiquement

Cet article est l'article du 5ème jour de Furukawa Lab Advent_calendar.

introduction

Divers frameworks tels que PyTorch, Chainer, Keras et TensorFlow sont apparus, et il est dit que tout le monde peut facilement utiliser le Deep Learning. Pour ceux qui utilisent réellement le Deep Learning, il peut sembler facile de simplement le déplacer. Cependant, c'est plus difficile pour les personnes qui n'utilisent pas beaucoup Python que le Deep Learning. À mon avis, courir Deep Learning est comme faire du vélo. Les gens qui peuvent faire du vélo disent une fois "C'est facile de faire du vélo" ou "Vous pouvez faire du vélo de la même manière, n'est-ce pas?", Mais de ceux qui n'ont jamais roulé ou qui ne peuvent pas rouler J'ai envie de "de quoi tu parles?"

De plus, lorsque vous utilisez Deep Learning, je pense que la compétence requise diffère en fonction de ce que vous voulez faire, comme le montre la figure ci-dessous, ce qui est l'une des raisons pour lesquelles on soulève l'obstacle à l'utilisation de Deep. スライド1.png

Dans cet article, je vais vous expliquer le chemin de la 2ème étape que j'ai réellement fait pour vous aider à faire du vélo appelé Deep Learning.

Pour le moment, essayez la reconnaissance d'objets avec Deep

Préparation

Cette fois, j'utiliserai Chainer. Ajoutons Chainer pour cela.

$ pip install chainer
$ pip install chainercv

Courir

Cela fonctionne comme suit.

python


import matplotlib.pyplot as plt
import numpy as np

from PIL import Image
from chainercv.visualizations import vis_bbox
from chainercv.datasets import voc_bbox_label_names
from chainercv.links import FasterRCNNVGG16

#Étiquette à utiliser (cette fois, celle par défaut)
label_names = voc_bbox_label_names

#Lecture des données "'./fish/test.Faites de "jpeg" votre fichier image préféré
test_data = Image.open('./fish/test.jpg')
test_data = np.asarray(test_data).transpose(2, 0, 1).astype(np.float32)

#Construction du modèle, pour le moment, utilisez voc07 formé
model_frcnn = FasterRCNNVGG16(n_fg_class=len(voc_bbox_label_names), pretrained_model='voc07')

#Prévoir
bboxes, labels, scores = model_frcnn.predict([test_data])
predict_result = [test_data, bboxes[0], labels[0], scores[0]]

#Dessiner le résultat
res = predict_result
fig = plt.figure(figsize=(6, 6))
ax = fig.subplots(1, 1)
line = 0.0
vis_bbox(res[0], res[1][res[3]>line], res[2][res[3]>line], res[3][res[3]>line], label_names=label_names, ax=ax)
plt.show()

résultat

J'ai pu bien le reconnaître! image.png

Ensuite, j'ai mis une image nodoguro et l'ai essayé. image.png

Bien sûr, si vous conservez la valeur par défaut, il n'y aura pas d'étiquette Nodoguro et cela ne fonctionnera pas. Je fais donc du Fine Turn pour en faire un classificateur spécialisé Nodoguro. Je vais sauter l'explication détaillée du tournage fin, mais le fait est que le modèle entraîné est en outre entraîné.

Préparation des données

Étant donné que des données d'apprentissage sont nécessaires pour un apprentissage supplémentaire, créons des données d'apprentissage. Je recommande celui qui s'appelle labelImg. Comment le mettre et comment l'utiliser est écrit dans le README du site github, donc je n'expliquerai qu'un flux simple et simple pour le moment. Tout d'abord, ajoutez celui dont vous avez besoin pour exécuter labelImg.

$ brew install qt  # Install qt-5.x.x by Homebrew
$ brew install libxml2
$ pip3 install pyqt5 lxml # Install qt and lxml by pip
$ make qt5py3

Je le ferai. Je ne pense pas qu'il y ait quoi que ce soit à faire attention, mais c'est un endroit où opérer dans le répertoire cloné. J'obtiens une erreur comme "Aucun fichier ou répertoire de ce type"

$ python3 labelImg.py

Lorsque vous exécutez labelImg.py, l'écran suivant apparaît.

image.png

Ouvrez l'image avec ouvrir et entrez "nodoguro" dans l'étiquette à droite Vous pouvez sélectionner la plage en appuyant sur la touche w, donc sélectionnez Nodoguro. image.png

Ensuite, vous pouvez ajouter une étiquette comme celle-ci. image.png

Vous pouvez également en attacher deux comme ça. image.png

Enfin, appuyez sur le bouton Enregistrer pour créer un fichier xml. Ce fichier contient des informations sur l'emplacement de l'étiquette ou de la bordure. Les noms Falui doivent être numérotés comme ʻimage_1.jpg, ʻimage_2.jpg. Après cela, créez un fichier avec le nom d'étiquette nommé classes.txt écrit dans une puce.

python


nodoguro
iwashi
cat

C'est la fin de la création des données de formation! Les points à prendre en compte sont «de rendre la taille d'image uniforme» et «de créer deux étiquettes ou plus». S'il n'y avait qu'un seul type d'étiquette, cela ne fonctionnait pas lors de l'apprentissage.

NODOGURO turning Maintenant que nous avons les données d'entraînement, formons-les. J'ai utilisé Imagenet pour le modèle formé. Cette fois, nous apprendrons en plus 7 images.

La structure du répertoire ressemble à ce qui suit.

sample/
 ├ fish/
 │ ├ res_images/
 │ │  ├ images.npy
 │ │  ├ bounding_box_data.npy
 │ │  └ object_ids.npy
 │ ├ classes.txt
 │ ├ image_1.jpg
 │ ├ image_1.xml 
 │ ├    ...
 │ ├ image_7.xml
 │ └ test.jpg
 ├ out/
 ├ learn.py
 ├ predict.py
 └ xml2numpyarray.py

Mise en forme des données

C'était pratique de le faire sous la forme de numpyarray avant l'entraînement cette fois, donc je l'ai converti en utilisant le code suivant. Si une erreur d'importation se produit, veuillez utiliser pip.

python


import matplotlib.pyplot as plt
import numpy as np
import glob
import os
import cv2
from PIL import Image
import xmltodict

# Global Variables

classes_file = 'fish/classes.txt'
data_dir = 'fish'

classes = list()
with open(classes_file) as fd:
    for one_line in fd.readlines():
        cl = one_line.split('\n')[0]
        classes.append(cl)
print(classes)

def getBBoxData(anno_file, classes, data_dir):
    with open(anno_file) as fd:
        pars = xmltodict.parse(fd.read())
    ann_data = pars['annotation']

    print(ann_data['filename'])
    # read image
    img = Image.open(os.path.join(data_dir, ann_data['filename']))
    img_arr = np.asarray(img).transpose(2, 0, 1).astype(np.float32)
    bbox_list = list()
    obj_names = list()
    for obj in ann_data['object']:
        bbox_list.append([obj['bndbox']['ymin'], obj['bndbox']['xmin'], obj['bndbox']['ymax'], obj['bndbox']['xmax']])
        obj_names.append(obj['name'])
    bboxs = np.array(bbox_list, dtype=np.float32)
    obj_names = np.array(obj_names)
    obj_ids = np.array(list(map(lambda x:classes.index(x), obj_names)), dtype=np.int32)
    return {'img':img, 'img_arr':img_arr, 'bboxs':bboxs, 'obj_names':obj_names, 'obj_ids':obj_ids}

def getBBoxDataSet(data_dir, classes):
    anno_files = glob.glob(os.path.join(data_dir, '*.xml'))
    img_list = list()
    bboxs = list()
    obj_ids = list()
    # imgs = np.zeros([4, 3, 189, 267])
    # num = 0
    for ann_file in anno_files:
        ret = getBBoxData(anno_file=ann_file, classes=classes, data_dir=data_dir)
        print(ret['img_arr'].shape)
        img_list.append(ret['img_arr'])
        # imgs[num] = ret['img_arr']
        bboxs.append(ret['bboxs'])
        obj_ids.append(ret['obj_ids'])

    imgs = np.array(img_list)
    return (imgs, bboxs, obj_ids)

imgs, bboxs, obj_ids = getBBoxDataSet(data_dir=data_dir, classes=classes)

np.save(os.path.join(data_dir, 'images.npy'), imgs)
np.save(os.path.join(data_dir, 'bounding_box_data.npy'), bboxs)
np.save(os.path.join(data_dir, 'object_ids.npy'), obj_ids)

Apprentissage

Exécutez avec le code suivant

python


import os
import numpy as np
import chainer
import random
from chainercv.chainer_experimental.datasets.sliceable import TupleDataset
from chainercv.links import FasterRCNNVGG16
from chainercv.links.model.faster_rcnn import FasterRCNNTrainChain
from chainer.datasets import TransformDataset
from chainercv import transforms
from chainer import training
from chainer.training import extensions

HOME = './'

data_dir = os.path.join(HOME, './fish/res_images')
file_img_set = os.path.join(data_dir, 'images.npy')
file_bbox_set = os.path.join(data_dir, 'bounding_box_data.npy')
file_object_ids = os.path.join(data_dir, 'object_ids.npy')
file_classes = os.path.join(data_dir, 'classes.txt')

#Charger le jeu de données
imgs = np.load(file_img_set)
bboxs = np.load(file_bbox_set, allow_pickle=True)
objectIDs = np.load(file_object_ids, allow_pickle=True)

#Lire les informations d'étiquette
classes = list()
with open(file_classes) as fd:
    for one_line in fd.readlines():
        cl = one_line.split('\n')[0]
        classes.append(cl)

dataset = TupleDataset(('img', imgs), ('bbox', bboxs), ('label', objectIDs))

N = len(dataset)
N_train = (int)(N*0.9)
N_test = N - N_train
print('total:{}, train:{}, test:{}'.format(N, N_train, N_test))

#Construction de réseau
faster_rcnn = FasterRCNNVGG16(n_fg_class=len(classes), pretrained_model='imagenet')
faster_rcnn.use_preset('evaluate')
model = FasterRCNNTrainChain(faster_rcnn)

#Paramètres GPU(Non utilisé cette fois)
gpu_id = -1
# chainer.cuda.get_device_from_id(gpu_id).use()
# model.to_gpu()

#Définir comment optimiser
optimizer = chainer.optimizers.MomentumSGD(lr=0.001, momentum=0.9)
optimizer.setup(model)
optimizer.add_hook(chainer.optimizer_hooks.WeightDecay(rate=0.0005))


#Préparation des données
class Transform(object):

    def __init__(self, faster_rcnn):
        self.faster_rcnn = faster_rcnn

    def __call__(self, in_data):
        img, bbox, label = in_data
        _, H, W = img.shape
        img = self.faster_rcnn.prepare(img)
        _, o_H, o_W = img.shape
        scale = o_H / H
        bbox = transforms.resize_bbox(bbox, (H, W), (o_H, o_W))

        # horizontally flip
        img, params = transforms.random_flip(
            img, x_random=True, return_param=True)
        bbox = transforms.flip_bbox(
            bbox, (o_H, o_W), x_flip=params['x_flip'])

        return img, bbox, label, scale

idxs = list(np.arange(N))
random.shuffle(idxs)
train_idxs = idxs[:N_train]
test_idxs = idxs[N_train:]

#Divers paramètres d'apprentissage
train_data = TransformDataset(dataset[train_idxs], Transform(faster_rcnn))
train_iter = chainer.iterators.SerialIterator(train_data, batch_size=1)
test_iter = chainer.iterators.SerialIterator(dataset[test_idxs], batch_size=1, repeat=False, shuffle=False)

updater = chainer.training.updaters.StandardUpdater(train_iter, optimizer, device=gpu_id)

n_epoch = 20
out_dir = './out'
trainer = training.Trainer(updater, (n_epoch, 'epoch'), out=out_dir)

step_size = 100
trainer.extend(extensions.snapshot_object(model.faster_rcnn, 'snapshot_model.npz'), trigger=(n_epoch, 'epoch'))
trainer.extend(extensions.ExponentialShift('lr', 0.1), trigger=(step_size, 'iteration'))

log_interval = 1, 'epoch'
plot_interval = 1, 'epoch'
print_interval = 1, 'epoch'

trainer.extend(chainer.training.extensions.observe_lr(), trigger=log_interval)
trainer.extend(extensions.LogReport(trigger=log_interval))
trainer.extend(extensions.PrintReport(['iteration', 'epoch', 'elapsed_time', 'lr', 'main/loss', 'main/roi_loc_loss', 'main/roi_cls_loss', 'main/rpn_loc_loss', 'main/rpn_cls_loss', 'validation/main/map', ]), trigger=print_interval)
trainer.extend(extensions.PlotReport(['main/loss'], file_name='loss.png', trigger=plot_interval), trigger=plot_interval)
trainer.extend(extensions.dump_graph('main/loss'))

#Apprentissage
trainer.run()

En tant que paramètre à définir ici ・ Sur gpu (gpu n'est pas utilisé cette fois)

python


# chainer.cuda.get_device_from_id(gpu_id).use()
# model.to_gpu()

・ À la place de l'optimiseur

python


optimizer = chainer.optimizers.MomentumSGD(lr=0.001, momentum=0.9)
optimizer.setup(model)
optimizer.add_hook(chainer.optimizer_hooks.WeightDecay(rate=0.0005))

・ Nombre d'apprentissage

python


n_epoch = 20
step_size = 100

Sera. Il y a beaucoup d'autres choses telles que batch_size et le nombre de données de test à faire ( N_train = (int) (N * 0.9) `` N_test = N --N_train), mais pour le moment, les trois C'est à propos de.

À propos, le réseau formé est enregistré dans un fichier appelé ʻout / snapshot_model.npz`.

Prévoir

J'ai en fait reconnu Nodoguro. Seuls ceux avec un score de 0,9 ou plus sont reconnus.

python


import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
from chainercv.visualizations import vis_bbox
from chainercv.links import FasterRCNNVGG16

#Lecture d'étiquettes
classes = list()
with open('./fish/classes.txt') as fd:
    for one_line in fd.readlines():
        cl = one_line.split('\n')[0]
        classes.append(cl)

#Lire les données de test
test_data = Image.open('./fish/test.jpg')
test_data = np.asarray(test_data).transpose(2, 0, 1).astype(np.float32)

#Charger le modèle entraîné
pretrain_model = 'out/snapshot_model.npz'

#Construction de réseau
model_frcnn = FasterRCNNVGG16(n_fg_class=len(classes), pretrained_model=pretrain_model)

#Prévoir
bboxes, labels, scores = model_frcnn.predict([test_data])
predict_result = [test_data, bboxes[0], labels[0], scores[0]]

#Le score est de 0.Réglage du seuil pour ne pas reconnaître les moins de 9 ans
line = 0.9

#dessin
res = predict_result
fig = plt.figure(figsize=(6, 6))
ax = fig.subplots(1, 1)
vis_bbox(res[0], res[1][res[3]>line], res[2][res[3]>line], res[3][res[3]>line], label_names=classes, ax=ax)
plt.show()

Le résultat est là.

image.png

J'ai pu le reconnaître correctement! Vous pouvez également imprimer le numéro reconnu par print (np.sum (labels [0] == 0)).

à la fin

Cette fois, j'ai essayé de tourner avec Aiya pour détecter les bosquets à gorge. C'était assez facile quand j'ai fini. Ensuite, il vous suffit de changer le nodoguro en votre image préférée, c'est donc relativement facile à mettre en œuvre. Cependant, afin de réaliser réellement une détection et un comptage très précis, il est difficile de retravailler la structure du réseau et les paramètres du problème en premier lieu, comme quoi faire avec des pièces qui se chevauchent et que faire avec la rotation. Il est difficile de l'amener au niveau de la recherche ou au niveau du produit, mais je pense qu'à travers cette implémentation, vous pouvez comprendre qu'il est relativement facile de "jouer avec Deep pour le moment". pense.

Site de référence

La plupart du temps, je me suis référé à ce site. http://chocolate-ball.hatenablog.com/entry/2018/05/23/012449

Recommended Posts

Rares sont ceux qui ont tiré NODOGURO tournant et ont essayé de compter le nodoguro automatiquement
J'ai essayé de lire et d'enregistrer automatiquement avec VOICEROID2 2
J'ai essayé de lire et d'enregistrer automatiquement avec VOICEROID2
J'ai compté les grains
J'ai essayé de publier automatiquement sur ChatWork au moment du déploiement avec Fabric et ChatWork Api
J'ai essayé d'illustrer le temps et le temps du langage C
J'ai essayé de programmer le test du chi carré en Python et Java.
J'ai essayé d'afficher l'heure et la météo d'aujourd'hui w
J'ai essayé d'énumérer les différences entre java et python
J'ai affiché le chat de YouTube Live et essayé de jouer
J'ai essayé la bibliothèque changefinder!
Je veux trouver automatiquement des pièces de haute qualité à partir des vidéos que j'ai tournées
J'ai essayé de pousser les documents Sphinx vers BitBucket et de les refléter automatiquement sur le serveur Web
J'ai essayé le tutoriel TensorFlow 1er
J'ai essayé le roman Naro API 2
J'ai essayé le tutoriel TensorFlow 2ème
J'ai essayé l'API du roman Naruro
J'ai essayé de déplacer le ballon
J'ai essayé d'utiliser l'API checkio
J'ai essayé d'estimer la section.
J'ai essayé de résumer jusqu'à ce que je quitte la banque et devienne ingénieur
J'ai essayé de déplacer l'image vers le dossier spécifié en faisant un clic droit et un clic gauche
J'ai essayé de visualiser la tranche d'âge et la distribution des taux d'Atcoder
J'ai essayé d'exprimer de la tristesse et de la joie face au problème du mariage stable.
J'ai essayé d'apprendre l'angle du péché et du cos avec le chainer
J'ai essayé de vérifier et d'analyser l'accélération de Python par Cython
J'ai essayé d'obtenir automatiquement le RSS de la chanson la plus populaire de l'iTunes Store
J'ai implémenté le modèle VGG16 avec Keras et essayé d'identifier CIFAR10
J'ai essayé de contrôler la bande passante et le délai du réseau avec la commande tc