[PYTHON] Nur wenige schossen NODOGURO und versuchten, den Nodoguro automatisch zu zählen

Dieser Artikel ist der 5. Tagesartikel von Furukawa Lab Advent_calendar.

Einführung

Verschiedene Frameworks wie PyTorch, Chainer, Keras und TensorFlow sind erschienen, und es wird gesagt, dass jeder Deep Learning problemlos verwenden kann. Für diejenigen, die tatsächlich Deep Learning verwenden, scheint es einfach zu sein, es einfach zu verschieben. Es ist jedoch schwieriger für Leute, die Python nicht viel verwenden als Deep Learning. Deep Learning ist meiner Meinung nach wie Fahrradfahren. Leute, die einmal Fahrrad fahren können, sagen "Es ist einfach, Fahrrad zu fahren" oder "Sie können andere Fahrräder auf die gleiche Weise fahren, oder?", Aber von denen, die noch nie gefahren sind oder die nicht fahren können Ich fühle mich wie "wovon redest du?"

Darüber hinaus denke ich, dass bei Verwendung von Deep Learning die erforderlichen Fähigkeiten unterschiedlich sind, je nachdem, wie viel Sie tun möchten, wie in der folgenden Abbildung gezeigt. Dies ist einer der Gründe, die Hürde für die Verwendung von Deep zu erhöhen. スライド1.png

In diesem Artikel werde ich den Weg des 2. Schritts erklären, den ich tatsächlich getan habe, um Ihnen beim Fahrradfahren mit dem Namen Deep Learning zu helfen.

Versuchen Sie vorerst die Objekterkennung mit Deep

Vorbereitung

Dieses Mal werde ich Chainer verwenden. Fügen wir dazu Chainer hinzu.

$ pip install chainer
$ pip install chainercv

Lauf

Es funktioniert wie folgt.

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

#Zu verwendendes Etikett (diesmal das Standardetikett)
label_names = voc_bbox_label_names

#Daten lesen "'./fish/test.Machen Sie "jpeg" zu Ihrer Lieblingsbilddatei
test_data = Image.open('./fish/test.jpg')
test_data = np.asarray(test_data).transpose(2, 0, 1).astype(np.float32)

#Für den Modellbau wird vorerst geschultes Voc07 verwendet
model_frcnn = FasterRCNNVGG16(n_fg_class=len(voc_bbox_label_names), pretrained_model='voc07')

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

#Das Ergebnis zeichnen
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()

Ergebnis

Ich konnte es gut erkennen! image.png

Als nächstes habe ich ein Nodoguro-Bild eingefügt und es ausprobiert. image.png

Wenn Sie die Standardeinstellung beibehalten, gibt es natürlich kein Nodoguro-Label und es funktioniert nicht. Also mache ich Feindrehen, um es zu einem Nodoguro-Spezialklassifikator zu machen. Ich werde die detaillierte Erklärung des Feindrehens überspringen, aber der Punkt ist, dass das trainierte Modell zusätzlich trainiert wird.

Datenaufbereitung

Da für zusätzliches Lernen Lerndaten erforderlich sind, erstellen wir Lerndaten. Ich empfehle das mit dem Namen labelImg. Wie man es einfügt und wie man es benutzt, steht in der README-Datei der Github-Site, daher werde ich vorerst nur einen einfachen und einfachen Ablauf erläutern. Fügen Sie zunächst diejenige hinzu, die Sie zum Ausführen von labelImg benötigen.

$ 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

Ich werde das machen. Ich glaube nicht, dass es etwas gibt, bei dem man vorsichtig sein muss, aber es ist ein Ort, an dem man im geklonten Verzeichnis arbeiten kann. Ich erhalte eine Fehlermeldung wie "Keine solche Datei oder kein solches Verzeichnis"

$ python3 labelImg.py

Wenn Sie labelImg.py ausführen, wird der folgende Bildschirm angezeigt.

image.png

Öffnen Sie das Bild mit open und geben Sie "nodoguro" in das Etikett rechts ein Sie können den Bereich auswählen, indem Sie die Taste "w" drücken. Wählen Sie also "Nodoguro". image.png

Dann können Sie eine solche Beschriftung hinzufügen. image.png

Sie können auch zwei davon anhängen. image.png

Klicken Sie abschließend auf die Schaltfläche Speichern, um eine XML-Datei zu erstellen. Diese Datei enthält Informationen darüber, wo sich die Beschriftung oder der Rand befindet. Bitte nummerieren Sie die Falui-Namen als "image_1.jpg ", "image_2.jpg ". Erstellen Sie anschließend eine Datei mit dem Namen "classes.txt" in einem Aufzählungszeichen.

python


nodoguro
iwashi
cat

Dies ist das Ende der Erstellung von Trainingsdaten! Die Punkte, die zu beachten sind, sind "die Bildgröße einheitlich machen" und "zwei oder mehr Beschriftungen machen". Wenn es nur eine Art von Etikett gab, funktionierte es beim Lernen nicht.

NODOGURO turning Nachdem wir die Trainingsdaten haben, trainieren wir sie tatsächlich. Ich habe Imagenet für das trainierte Modell verwendet. Dieses Mal lernen wir zusätzlich 7 Bilder.

Die Verzeichnisstruktur sieht wie folgt aus.

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

Datenformung

Es war praktisch, es vor dem Training in Form eines Numpyarrays zu erstellen, daher habe ich es mit dem folgenden Code konvertiert. Wenn ein Importfehler auftritt, verwenden Sie bitte 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)

Lernen

Führen Sie den folgenden Code aus

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

#Datensatz laden
imgs = np.load(file_img_set)
bboxs = np.load(file_bbox_set, allow_pickle=True)
objectIDs = np.load(file_object_ids, allow_pickle=True)

#Etiketteninformationen lesen
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))

#Netzwerkaufbau
faster_rcnn = FasterRCNNVGG16(n_fg_class=len(classes), pretrained_model='imagenet')
faster_rcnn.use_preset('evaluate')
model = FasterRCNNTrainChain(faster_rcnn)

#GPU-Einstellungen(Diesmal nicht verwendet)
gpu_id = -1
# chainer.cuda.get_device_from_id(gpu_id).use()
# model.to_gpu()

#Legen Sie fest, wie optimiert werden soll
optimizer = chainer.optimizers.MomentumSGD(lr=0.001, momentum=0.9)
optimizer.setup(model)
optimizer.add_hook(chainer.optimizer_hooks.WeightDecay(rate=0.0005))


#Vorbereitung der Daten
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:]

#Verschiedene Einstellungen zum Lernen
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'))

#Lernen
trainer.run()

Als hier einzustellender Parameter ・ Bei GPU (GPU wird diesmal nicht verwendet)

python


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

・ Am Ort des Optimierers

python


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

・ Anzahl der Lernvorgänge

python


n_epoch = 20
step_size = 100

Wird sein. Es gibt viele andere Dinge wie "batch_size" und wie viele Testdaten zu erstellen sind ("N_train = (int) (N * 0.9)" N_test = N - N_train "), aber vorerst die obigen drei Es geht um.

Das trainierte Netzwerk wird übrigens in einer Datei namens "out / snapshot_model.npz" gespeichert.

Prognose

Ich habe Nodoguro tatsächlich erkannt. Es werden nur diejenigen mit einem Score von 0,9 oder höher anerkannt.

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

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

#Testdaten lesen
test_data = Image.open('./fish/test.jpg')
test_data = np.asarray(test_data).transpose(2, 0, 1).astype(np.float32)

#Laden Sie das trainierte Modell
pretrain_model = 'out/snapshot_model.npz'

#Netzwerkaufbau
model_frcnn = FasterRCNNVGG16(n_fg_class=len(classes), pretrained_model=pretrain_model)

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

#Punktzahl ist 0.Schwellenwerteinstellung, um Personen unter 9 Jahren nicht zu erkennen
line = 0.9

#Zeichnung
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()

Das Ergebnis ist hier.

image.png

Ich konnte es richtig erkennen! Sie können auch die durch "print (np.sum (labels [0] == 0))" erkannte Nummer drucken.

schließlich

Dieses Mal habe ich versucht, mich mit Aiya fein zu drehen, um Kehlhaine zu erkennen. Es war ziemlich einfach, als ich fertig war. Als nächstes müssen Sie nur das Nodoguro in Ihr Lieblingsbild ändern, damit es relativ einfach zu implementieren ist. Um jedoch eine hochgenaue Erkennung und Zählung zu realisieren, ist es zunächst schwierig, die Netzwerkstruktur und die Problemeinstellungen zu überdenken, z. B. was mit dem überlappenden Teil und was mit der Drehung zu tun ist. Es ist schwierig, es auf die Forschungs- oder Produktebene zu bringen, aber ich denke, dass Sie durch diese Implementierung verstehen können, dass es relativ einfach ist, "vorerst mit Deep zu spielen". Überlegen.

Referenzseite

Meistens habe ich auf diese Seite verwiesen. http://chocolate-ball.hatenablog.com/entry/2018/05/23/012449

Recommended Posts

Nur wenige schossen NODOGURO und versuchten, den Nodoguro automatisch zu zählen
Ich habe versucht, mit VOICEROID2 2 automatisch zu lesen und zu speichern
Ich habe versucht, mit VOICEROID2 automatisch zu lesen und zu speichern
Ich habe die Körner gezählt
Ich habe versucht, zum Zeitpunkt der Bereitstellung mit Fabric und ChatWork Api automatisch in ChatWork zu posten
Ich habe versucht, die Zeit und die Zeit der C-Sprache zu veranschaulichen
Ich habe versucht, den Chi-Quadrat-Test in Python und Java zu programmieren.
Ich habe versucht, die Uhrzeit und das heutige Wetter anzuzeigen
Ich habe versucht, die Unterschiede zwischen Java und Python aufzuzählen
Ich habe den Chat von YouTube Live angezeigt und versucht zu spielen
Ich habe die Changefinder-Bibliothek ausprobiert!
Ich möchte automatisch hochwertige Teile aus den von mir aufgenommenen Videos finden
Ich habe versucht, Sphinx-Dokumente an BitBucket zu senden und sie automatisch auf dem Webserver wiederzugeben
Ich habe das TensorFlow-Tutorial als erstes ausprobiert
Ich habe die Naro-Roman-API 2 ausprobiert
Ich habe das 2. TensorFlow-Tutorial ausprobiert
Ich habe die neuartige API von Naruro ausprobiert
Ich habe versucht, den Ball zu bewegen
Ich habe versucht, die checkio-API zu verwenden
Ich habe versucht, den Abschnitt zu schätzen.
Ich versuchte zusammenzufassen, bis ich die Bank verließ und Ingenieur wurde
Ich habe versucht, das Bild durch Klicken mit der rechten und linken Maustaste in den angegebenen Ordner zu verschieben
Ich habe versucht, die Altersgruppe und die Ratenverteilung von Atcoder zu visualisieren
Ich versuchte, Trauer und Freude über das Problem der stabilen Ehe auszudrücken.
Ich habe versucht, den Winkel von Sin und Cos mit Chainer zu lernen
Ich habe versucht, die Beschleunigung von Python durch Cython zu verifizieren und zu analysieren
Ich habe versucht, das RSS des Top-Songs des iTunes Store automatisch abzurufen
Ich habe das VGG16-Modell mit Keras implementiert und versucht, CIFAR10 zu identifizieren
Ich habe versucht, die Netzwerkbandbreite und -verzögerung mit dem Befehl tc zu steuern