[PYTHON] Ich habe versucht, meinen eigenen Datensatz mit Chainer Trainer zu lernen

Chainer1.11.0 wurde veröffentlicht, und es scheint, dass eine Funktion zum Abstrahieren der Lernschleife namens Trainer hinzugefügt wurde. Versuchen wir also, mit unserem eigenen Gesichtsbilddatensatz für AV-Schauspielerinnen zu lernen.

Informationen zum Extrahieren und Erweitern von Gesichtsbildern finden Sie unter Veröffentlichen des Know-hows zum Erstellen eines ähnlichen Bildsuchdienstes für AV-Schauspielerinnen durch intensives Lernen mit Qiita --chainer. Bitte. Im Originalartikel wird es in das Numpy-Format konvertiert, diesmal jedoch nicht in das Numpy-Format, da das Bild während des Lernens direkt aus dem Verzeichnis gelesen wird.

Es wird davon ausgegangen, dass das hier verwendete Gesichtsbild 1000 Bilder für jede Schauspielerin enthält, auf eine Größe von 64 x 64 verkleinert und in die folgenden Verzeichnisse unterteilt ist.

./root
    |
    |--- /actress1
    |        |--- image1.jpg
    |        |--- image2.jpg
    |        |--- image3.jpg
    |
    |--- /actress2
    |        .
    |        .
    |--- /actress3
    .
    .
    .

Separate Daten für Training und Validierung

Zunächst werden die Gesichtsbilddaten in Training und Verifikation unterteilt. Es ist möglich zu lernen, während die Daten zum Lernen und zur Verifizierung geteilt werden, wenn die Daten zum Zeitpunkt des Lernens gelesen werden. Es ist jedoch schwierig zu verstehen, welche Daten zum Lernen verwendet werden und welche Daten zur Verifizierung verwendet werden, sodass sie im Voraus aufgeteilt werden Ich werde das machen.

#!/usr/bin/env python
#-*- coding:utf-8 -*-

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

import argparse
import glob
import logging
import os
import random
import shutil

def separate_train_val(args):
    if not os.path.exists(args.output_dir):
        os.mkdir(args.output_dir)

    if not os.path.exists(os.path.join(args.output_dir, 'train')):
        os.mkdir(os.path.join(args.output_dir, 'train'))

    if not os.path.exists(os.path.join(args.output_dir, 'val')):
        os.mkdir(os.path.join(args.output_dir, 'val'))

    directories = os.listdir(args.root)

    for dir_index, dir_name in enumerate(directories):
        files = glob.glob(os.path.join(args.root, dir_name, '*.jpg'))
        random.shuffle(files)
        if len(files) == 0: continue

        for file_index, file_path in enumerate(files):
            if file_index % args.val_freq != 0:
                target_dir = os.path.join(args.output_dir, 'train', dir_name)
                if not os.path.exists(target_dir):
                    os.mkdir(target_dir)
                shutil.copy(file_path, target_dir)
                logging.info('Copied {} => {}'.format(file_path, target_dir))
            else:
                target_dir = os.path.join(args.output_dir, 'val', dir_name)
                if not os.path.exists(target_dir):
                    os.mkdir(target_dir)
                shutil.copy(file_path, target_dir)
                logging.info('Copied {} => {}'.format(file_path, target_dir))

if __name__ == '__main__':
    logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')

    parser = argparse.ArgumentParser(description='converter')
    parser.add_argument('--root', default='.')
    parser.add_argument('--output_dir', default='.')
    parser.add_argument('--val_freq', type=int, default=10)
    args = parser.parse_args()

    separate_train_val(args)

Das geteilte Verzeichnis hat die folgende Struktur.

./train_val_root
    |
    |--- /train
    |       |--- actress1
    |       |       |--- image1.jpg
    |       |       |--- image2.jpg
    |       |       |--- image3.jpg
    |       |・
    |       |・
    |       |--- actress2
    |       |・
    |     |・
    |
    |--- /val
    |       |--- actress1
    |       |
    |       |--- actress2
    .
    .

Erstellen Sie einen Datensatz, um Daten aus einem Verzeichnis zu lesen

Definiert eine Klasse, die chainer.dataset.DatasetMixin erbt und Daten aus dem angegebenen Verzeichnis liest. Wir haben eine Methode (create_label_file) definiert, die die zur Erkennung verwendeten Klassen (Zahlen von 0 bis 9) und label (Verzeichnisnamen) ausgibt. Dies ist jedoch unangenehm und sollte nicht nachgeahmt werden.

class DatasetFromDirectory(chainer.dataset.DatasetMixin):

    def __init__(self, root='.', label_out='', dtype=np.float32, label_dtype=np.int32):
        directories = os.listdir(root)
        label_table = []
        pairs = [] # tuple (filepath, label) list
        for dir_index, dir_name in enumerate(directories):
            label_table.append((dir_index, dir_name))
            file_paths = glob.glob(os.path.join(root, dir_name, '*.jpg'))
            for file_path in file_paths:
                pairs.append((file_path, dir_index))

        self._pairs = pairs
        self._root = root
        self._label_out = label_out
        self._label_table = label_table
        self._dtype = dtype
        self._label_dtype = label_dtype

        if label_out != '':
            self.create_label_file()

    def __len__(self):
        return len(self._pairs)

    def get_example(self, i):
        path, int_label = self._pairs[i]
        with Image.open(path) as f:
            image = np.asarray(f, dtype=self._dtype)
        image = image.transpose(2, 0, 1)
        label = np.array(int_label, dtype=self._label_dtype)
        return image, label

    def create_label_file(self):
        with open(self._label_out, "w") as f:
            for (label_index, label_name) in self._label_table:
                f.write('{},{}\n'.format(label_index, label_name))

Wenn Sie sich [Offizielles Imagenet-Beispiel] ansehen (https://github.com/pfnet/chainer/blob/master/examples/imagenet/train_imagenet.py), können Sie die Daten während des Trainings basierend auf der erstellten Datensatzklasse verarbeiten. Du kannst auch. Wenn Sie das Bild während des Trainings zufällig ein wenig drehen oder ein wenig verschieben, ist es weniger wahrscheinlich, dass Sie aus genau denselben Daten lernen, sodass eine Verbesserung der Generalisierungsleistung erwartet werden kann.

Lernen Sie Ihren eigenen Datensatz mit Trainer

Sie lernen den Datensatz kennen, den Sie tatsächlich vorbereitet haben. Durch die Implementierung mit Chainer Trainer kann die Implementierung mit etwa der Hälfte des ursprünglichen Codes durchgeführt werden.

class CNN(chainer.Chain):
    """
    CNN (CCPCCPCP)
    """
    def __init__(self, n_classes):
        super(CNN, self).__init__(
            conv1_1=L.Convolution2D(3, 32, 3, pad=1),
            bn1_1=L.BatchNormalization(32),
            conv1_2=L.Convolution2D(32, 32, 3, pad=1),
            bn1_2=L.BatchNormalization(32),

            conv2_1=L.Convolution2D(32, 64, 3, pad=1),
            bn2_1=L.BatchNormalization(64),
            conv2_2=L.Convolution2D(64, 64, 3, pad=1),
            bn2_2=L.BatchNormalization(64),

            conv3_1=L.Convolution2D(64, 128, 3, pad=1),
            bn3_1=L.BatchNormalization(128),

            fc4=L.Linear(8192, 1024),
            fc5=L.Linear(1024, n_classes),
        )
        self.train = True

    def __call__(self, x, t):
        h = F.relu(self.bn1_1(self.conv1_1(x), test=not self.train))
        h = F.relu(self.bn1_2(self.conv1_2(h), test=not self.train))
        h = F.max_pooling_2d(h, 2, 2)

        h = F.relu(self.bn2_1(self.conv2_1(h), test=not self.train))
        h = F.relu(self.bn2_2(self.conv2_2(h), test=not self.train))
        h = F.max_pooling_2d(h, 2, 2)

        h = F.relu(self.bn3_1(self.conv3_1(h), test=not self.train))
        h = F.max_pooling_2d(h, 2, 2)

        h = F.dropout(F.relu(self.fc4(h)), ratio=0.3, train=self.train)
        h = self.fc5(h)

        loss = F.softmax_cross_entropy(h, t)
        chainer.report({'loss': loss, 'accuracy': F.accuracy(h, t)}, self)
        return loss
model = CNN(10)
optimizer = chainer.optimizers.Adam()
optimizer.setup(model)

mean = np.load(args.mean)
train_data = datasets.DatasetFromDirectory(args.train_root, label_out=label_file)
val_data = datasets.DatasetFromDirectory(args.val_root)

train_iter = chainer.iterators.SerialIterator(train_data, args.batch_size)
val_iter = chainer.iterators.SerialIterator(val_data, args.batch_size, repeat=False, shuffle=False)

# Set up a trainer
updater = training.StandardUpdater(train_iter, optimizer, device=args.gpu)
trainer = training.Trainer(updater, (args.n_epoch, 'epoch'), out=args.output_dir)

snapshot_interval = (args.snapshot_interval, 'iteration')

# Copy the chain with shared parameters to flip 'train' flag only in test
eval_model = model.copy()
eval_model.train = False

trainer.extend(extensions.Evaluator(val_iter, eval_model, device=args.gpu))
trainer.extend(extensions.dump_graph('main/loss'))
trainer.extend(extensions.snapshot(), trigger=snapshot_interval)
trainer.extend(extensions.snapshot_object(
    model, 'model_iter_{.updater.iteration}'), trigger=snapshot_interval)
trainer.extend(extensions.snapshot_object(
    optimizer, 'optimizer_iter_{.updater.iteration}'), trigger=snapshot_interval)
trainer.extend(extensions.LogReport())
trainer.extend(extensions.PrintReport(
    ['epoch', 'main/loss', 'validation/main/loss',
     'main/accuracy', 'validation/main/accuracy']))
trainer.extend(extensions.ProgressBar(update_interval=10))

if args.resume:
    if not os.path.exists(args.resume):
        raise IOError('Resume file is not exists.')
    logging.info('Load optimizer state from {}'.format(args.resume))
    chainer.serializers.load_npz(args.resume, trainer)

trainer.run()

# Save the trained model
chainer.serializers.save_npz(os.path.join(args.output_dir, 'model_final'), model)
chainer.serializers.save_npz(os.path.join(args.output_dir, 'optimizer_final'), optimizer)

print()
logging.info('Saved the model and the optimizer')
logging.info('Training is finished!')

Da das von extensions.snapshot () gespeicherte Objekt für den Trainer bestimmt ist, müssen model und optimizer gespeichert werden, damit sie geladen werden können, wenn sie tatsächlich von extensions.snapshot_object () separat vorhergesagt werden.

Zusammenfassung

Ich habe versucht, meinen eigenen Datensatz mit Chainer Trainer zu lernen. Wie erwartet ist der Eindruck, Trainer zu verwenden, dass es in der Nähe von Keras liegt. Als ich zum ersten Mal versuchte, Chainer zu verwenden, erinnere ich mich, dass das Lesen jedes Mini-Batches viel Zeit in Anspruch nahm. Daher hielt ich Trainer, der solche Teile abstrahiert, für eine leicht verständliche Implementierung.

In Keras können Sie jedoch flow_from_directory der ImageDataGenerator-Klasse verwenden, um Daten aus dem Verzeichnis zu lesen, ohne die Dataset-Klasse zu implementieren, sodass das Erstellen einfacher ist. kann auch tun.

Last but not least erstelle ich eine Website, die mit CNN nach ähnlichen Bildern von AV-Schauspielerinnen sucht. Schauen Sie also bitte nach, wenn Sie möchten.

Babelink - Ähnlicher AV-Schauspielerin-Suchdienst

Recommended Posts

Ich habe versucht, meinen eigenen Datensatz mit Chainer Trainer zu lernen
[Ich habe versucht, Pythonista 3 zu verwenden] Importieren meines eigenen Moduls
Ich habe versucht, mit PyBrain verstärkt zu lernen
Ich habe versucht, mit Theano tief zu lernen
[Kaggle] Ich habe versucht, Ensemble mit LightGBM zu lernen
Ich habe versucht, parametrisiert zu verwenden
Ich habe versucht, Argparse zu verwenden
Ich habe versucht, Mimesis zu verwenden
Ich habe versucht, anytree zu verwenden
Ich habe versucht, aiomysql zu verwenden
Ich habe versucht, Summpy zu verwenden
Ich habe versucht, Coturn zu verwenden
Ich habe versucht, Pipenv zu verwenden
Ich habe versucht, Matplotlib zu verwenden
Ich habe versucht, "Anvil" zu verwenden.
Ich habe versucht, Hubot zu verwenden
Ich habe versucht, ESPCN zu verwenden
Ich habe versucht, openpyxl zu verwenden
Ich habe versucht, tief zu lernen
Ich habe versucht, Ipython zu verwenden
Ich habe versucht, PyCaret zu verwenden
Ich habe versucht, Cron zu verwenden
Ich habe versucht, ngrok zu verwenden
Ich habe versucht, face_recognition zu verwenden
Ich habe versucht, Jupyter zu verwenden
Ich habe versucht, doctest zu verwenden
Ich habe versucht, Folium zu verwenden
Ich habe versucht, jinja2 zu verwenden
Ich habe versucht, Folium zu verwenden
Ich habe versucht, das Zeitfenster zu verwenden
Ich habe versucht, meinen eigenen Quellcode mit Chainer v2 alpha kompatibel zu machen
Ich habe versucht, die Sündenfunktion mit Chainer zu approximieren
Ich habe versucht, das Bild mithilfe von maschinellem Lernen zu komprimieren
[Ich habe versucht, Pythonista 3 zu verwenden] Einführung
Ich habe versucht, easydict (Memo) zu verwenden.
Ich habe versucht, das Gesicht mit Face ++ zu erkennen
Ich habe versucht, BigQuery ML zu verwenden
Ich habe meine eigene Sprache gemacht. (1)
Ich habe versucht, Amazon Glacier zu verwenden
Ich habe versucht, Git Inspector zu verwenden
Ich habe meine eigene Sprache gemacht (2)
Ich habe meine eigene AML gemacht
Ich habe versucht, Magenta / TensorFlow zu verwenden
Ich habe versucht, AWS Chalice zu verwenden
Ich habe versucht, Slack Emojinator zu verwenden
Ich habe versucht, ein Deep-Learning-Modell von TensorFlow mit TensorFlow Serving zu hosten
Ich habe versucht, Tensorboard zu verwenden, ein Visualisierungstool für maschinelles Lernen
Ich habe versucht, ListNet of Rank Learning mit Chainer zu implementieren
[TF] Ich habe versucht, das Lernergebnis mit Tensorboard zu visualisieren
Ich habe versucht, die Sündenfunktion mit Chainer zu approximieren (Re-Challenge)
Ich habe versucht, Rotrics Dex Arm # 2 zu verwenden
Ich habe maschinelles Lernen mit liblinear versucht
Ich habe meine eigene Python-Bibliothek erstellt
Ich habe versucht, Pytorchs Datensatz zu erklären
Ich habe versucht, meinen Lieblingssänger (SHISHAMO) mit der Spotify-API zu analysieren
Ich habe versucht, Thonny (Python / IDE) zu verwenden.
Stärkung des Lernens 8 Versuchen Sie, die Chainer-Benutzeroberfläche zu verwenden