Dieser Artikel ist der 5. Tagesartikel von Furukawa Lab Advent_calendar.
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.
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.
Dieses Mal werde ich Chainer verwenden. Fügen wir dazu Chainer hinzu.
$ pip install chainer
$ pip install chainercv
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()
Ich konnte es gut erkennen!
Als nächstes habe ich ein Nodoguro-Bild eingefügt und es ausprobiert.
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.
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.
Ö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".
Dann können Sie eine solche Beschriftung hinzufügen.
Sie können auch zwei davon anhängen.
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
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)
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.
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.
Ich konnte es richtig erkennen! Sie können auch die durch "print (np.sum (labels [0] == 0))" erkannte Nummer drucken.
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.
Meistens habe ich auf diese Seite verwiesen. http://chocolate-ball.hatenablog.com/entry/2018/05/23/012449
Recommended Posts