――Es ist mühsam, jedes Mal denselben Trainingscode zu schreiben, wenn Sie etwas ausprobieren möchten, indem Sie nur den Code des Modells und des Datensatzes schnell schreiben. --Chainer hat ein praktisches Tool namens Trainer, aber es ist immer noch mühsam, Code zu schreiben, um jedes Mal eine ähnliche Erweiterung hinzuzufügen, um train.py zu erstellen. ――Es wäre schön, ein Befehlszeilentool zu haben, das wie gewohnt mit dem Lernen beginnt, wenn Sie eine YAML-Datei übergeben, in der die Lerneinstellungen, die Modelldatei, die Datensatzdatei usw. als Argument beschrieben werden. Ich habe es gemacht. ――Es handelt sich im Grunde genommen um ein komplettes Oleoresabo-Tool, daher wurde es nicht mit der Idee erstellt, überhaupt von Menschen verwendet zu werden, aber es wurde veröffentlicht, weil es eine große Sache war.
ChainerCMD
https://github.com/mitmul/chainercmd
$ pip install chainercmd
$ chainer init
Anschließend werden die folgenden vier Dateien erstellt.
Der Inhalt ist so.
config.yml
stop_trigger: [20, "epoch"]
# max_workspace_size: 8388608 # default: 8 * 1024 * 1024
dataset:
train:
file: dataset.py
name: MNIST
batchsize: 128
args:
split: train
ndim: 3
valid:
file: dataset.py
name: MNIST
batchsize: 64
args:
split: valid
ndim: 3
model:
file: model.py
name: LeNet5
args:
n_class: 10
loss:
module: chainer.links.model.classifier
# file: loss.py # If you use your own loss definition, remove "module" key above and use "file" key to specify the path to the file which describes the "name" class for a Loss link.
name: Classifier
optimizer:
method: MomentumSGD
args:
lr: 0.01
weight_decay: 0.0001
lr_drop_ratio: 0.1
lr_drop_triggers:
points: [10, 15]
unit: epoch
# You can ommit this part
# updater_creator:
# file: updater_creator.py
# name: MyUpdaterCreator
# args:
# print: True
trainer_extension:
- custom:
file: custom_extension.py
name: CustomExtension
args:
message: 'I am learning...'
- LogReport:
trigger: [1, "epoch"]
- dump_graph:
root_name: main/loss
out_name: cg.dot
- observe_lr:
trigger: [1, "epoch"]
- ParameterStatistics:
links:
- conv1
- conv2
- conv3
- fc4
- fc5
report_params: True
report_grads: True
prefix: null
trigger: [1, "epoch"]
- Evaluator:
module: chainer.training.extensions
name: Evaluator
trigger: [1, "epoch"]
prefix: val
# You can specify other evaluator like this:
# module: chainercv.extensions
# name: SemanticSegmentationEvaluator
# trigger: [1, "epoch"]
# prefix: val
- PlotReport:
y_keys:
- conv1/W/data/mean
- conv2/W/data/mean
- conv3/W/data/mean
- conv4/W/data/mean
- fc5/W/data/mean
- fc6/W/data/mean
x_key: epoch
file_name: parameter_mean.png
trigger: [1, "epoch"]
- PlotReport:
y_keys:
- conv1/W/data/std
- conv2/W/data/std
- conv3/W/data/std
- conv4/W/data/std
- fc5/W/data/std
- fc6/W/data/std
x_key: epoch
file_name: parameter_std.png
trigger: [1, "epoch"]
- PlotReport:
y_keys:
- main/loss
- val/main/loss
x_key: epoch
file_name: loss.png
trigger: [1, "epoch"]
- PlotReport:
y_keys:
- main/accuracy
- val/main/accuracy
x_key: epoch
file_name: accuracy.png
trigger: [1, "epoch"]
- PrintReport:
entries:
- epoch
- iteration
- main/loss
- main/accuracy
- val/main/loss
- val/main/accuracy
- elapsed_time
- lr
trigger: [1, "epoch"]
- ProgressBar:
update_interval: 10
trigger: [10, "iteration"]
- snapshot:
filename: trainer_{.updater.epoch}_epoch
trigger: [10, "epoch"]
custom_extension.py
import chainer
class CustomExtension(chainer.training.Extension):
def __init__(self, message):
self._message = message
def initialize(self, trainer):
self._message += ' and Trainer ID is: {}'.format(id(trainer))
def __call__(self, trainer):
pass
def serialize(self, serializer):
self._message = serializer('_message', self._message)
dataset.py
import chainer
class Dataset(chainer.dataset.DatasetMixin):
def __init__(self, split='train'):
super().__init__()
def __len__(self):
pass
def get_example(self, i):
pass
# You can delete this
class MNIST(chainer.dataset.DatasetMixin):
def __init__(self, split='train', ndim=3):
super().__init__()
train, valid = chainer.datasets.get_mnist(ndim=ndim)
self.d = train if split == 'train' else valid
def __len__(self):
return len(self.d)
def get_example(self, i):
return self.d[i]
loss.py
from chainer import link
from chainer import reporter
from chainer.functions.evaluation import accuracy
from chainer.functions.loss import softmax_cross_entropy
class MyLoss(link.Chain):
def __init__(self, predictor):
super().__init__()
self.lossfun = softmax_cross_entropy.softmax_cross_entropy
self.accfun = accuracy.accuracy
self.y = None
self.loss = None
self.accuracy = None
with self.init_scope():
self.predictor = predictor
def __call__(self, *args):
assert len(args) >= 2
x = args[:-1]
t = args[-1]
self.y = None
self.loss = None
self.accuracy = None
self.y = self.predictor(*x)
self.loss = self.lossfun(self.y, t)
reporter.report({'loss': self.loss}, self)
self.accuracy = self.accfun(self.y, t)
reporter.report({'accuracy': self.accuracy}, self)
return self.loss
model.py
import chainer
import chainer.functions as F
import chainer.links as L
class Model(chainer.Chain):
"""Model definition.
This is a template of model definition.
"""
def __init__(self, n_class):
super().__init__()
with self.init_scope():
pass
def __call__(self, x):
pass
# You can delete this! It's a sample model
class LeNet5(chainer.Chain):
def __init__(self, n_class):
super().__init__()
with self.init_scope():
self.conv1 = L.Convolution2D(None, 6, 5, 1)
self.conv2 = L.Convolution2D(6, 16, 5, 1)
self.conv3 = L.Convolution2D(16, 120, 4, 1)
self.fc4 = L.Linear(None, 84)
self.fc5 = L.Linear(84, n_class)
def __call__(self, x):
h = F.relu(self.conv1(x))
h = F.max_pooling_2d(h, 2, 2)
h = F.relu(self.conv2(h))
h = F.max_pooling_2d(h, 2, 2)
h = F.relu(self.conv3(h))
h = F.relu(self.fc4(h))
return self.fc5(h)
Bearbeiten Sie dies anschließend grundsätzlich für einzelne Aufgaben und wenn Sie fertig sind
$ chainer train config.yml --gpus 0
Anschließend beginnt das Lernen mit der Verwendung des Geräts mit der GPU-ID: 0. Wenn Sie mehrere GPUs verwenden möchten, geben Sie die IDs der zu verwendenden GPUs an, die durch Leerzeichen getrennt sind, z. B. "--gpus 0 1 2 3".
config.yml
Es ist eine Datei, die Lerneinstellungen beschreibt und welche Datei als Modelldatei verwendet werden soll.
dataset
dataset:
train:
file: dataset.py
name: MNIST
batchsize: 128
args:
split: train
ndim: 3
valid:
file: dataset.py
name: MNIST
batchsize: 64
args:
split: valid
ndim: 3
Dies ist die Einstellung des Trainingsdatensatzes und des Verifizierungsdatensatzes. Definieren Sie sie im Voraus in einer anderen Datei, geben Sie mit dem Schlüssel "file" den Pfad zu dieser Datei an und geben Sie mit "name" den Klassennamen der Dataset-Klasse in dieser Datei an. Der Wert von "args" muss ein Wörterbuch sein, das wie "** args" als Schlüsselwortargument an den Konstruktor der Dataset-Klasse übergeben wird. batchsize
ist die Größe des Mini-Batches, der aus jedem Datensatz erstellt wird.
model & loss
model:
file: model.py
name: LeNet5
args:
n_class: 10
Dies ist fast das gleiche: Erstellen eines Modells durch Instanziieren einer Klasse mit dem Namen "Name" in der Datei in dem durch "Datei" angegebenen Pfad. Wenn zu diesem Zeitpunkt args
vorhanden ist, übergeben Sie es als Schlüsselwortargument.
loss:
module: chainer.links
# file: loss.py # If you use your own loss definition, remove "module" key above and use "file" key to specify the path to the file which describes the "name" class for a Loss link.
name: Classifier
Der "Verlust" -Teil ist im Grunde der gleiche, und "Argumente" wird hier weggelassen. Wenn Sie jedoch ein Wörterbuch mit "Argumenten" als Schlüssel wie den "Modell" -Teil angeben, wird der Verlust berechnet. Es wird als Schlüsselwortargument an den Konstruktor der Klasse für übergeben. Für "Verlust" können Sie das Schlüsselmodul verwenden, so dass Sie auch "chainer.links.Classifier" usw. verwenden können, die von Chainer im Voraus vorbereitet wurden. module
und file
können nicht gleichzeitig verwendet werden.
optimizer
optimizer:
method: MomentumSGD
args:
lr: 0.01
weight_decay: 0.0001
lr_drop_ratio: 0.1
lr_drop_triggers:
points: [10, 15]
unit: epoch
Dies ist der Einstellungsteil von Optimizer. method
ist der Klassenname unter dem Chainer-Modul optimizers
. args
ist ein Schlüsselwortargument, das an seinen Konstruktor übergeben werden soll. Wenn der Schlüssel weight_decay
vorhanden ist, wird Weight Decay als Optimizer-Hook hinzugefügt. Wenn sowohl lr_drop_ratio
als auch lr_drop_triggers
vorhanden sind, wird die Lernrate mit dem ManualScheduleTrigger gesenkt. In dem an "lr_drop_triggers" übergebenen Wörterbuch ist "unit" die Einheit dieses Timings, wenn "points" die Lernrate um "lr_drop_ratio" verdoppelt ("epoch" oder "iteration" kann angegeben werden). Im Fall des obigen Beispiels beträgt die Lernrate von Momentum SGD für 10 Epochen das 0,1-fache und für 15 Epochen erneut das 0,1-fache.
updater
Updater kann angepasst werden, indem eine Funktion vorbereitet wird, die Iterator, Optimierer und Geräte verwendet, ein Updater-Objekt zurückgibt und es mit dem Schlüssel updater_creater in config.yml angibt.
Eine Wrapper-Klasse, die Dataset-Klassen, Modellklassen und Verluste berechnet, die mit einem normalen Chainer geschrieben wurden. Schreiben Sie für custom_extension.py
Ihre eigene Extension-Klasse, geben Sie sie in config.yml an und schreiben Sie sie neu, wenn Sie sie Trainer hinzufügen möchten.
Die von "chainer init" erstellte Datei enthält die Modelle und Datensätze, die erforderlich sind, um das MNIST-Beispiel von Anfang an auszuführen. Wenn "config.yml" unverändert bleibt, werden diese Modelldatensätze usw. Ist bereit, das MNIST-Beispiel mit auszuführen. Alles was Sie tun müssen, ist den Befehl chainer
zu drücken. Geben Sie im Unterbefehl train
an.
$ chainer train config.yml --gpus 0
Geben Sie den Pfad der Konfigurations-YAML-Datei an, die Sie neben dem Unterbefehl train
verwenden möchten. Der Dateiname muss nicht config.yml sein. Wenn Sie eine GPU verwenden möchten, geben Sie die Geräte-ID mit der Option "--gpus" an. Wenn mehr als eine angegeben wird, z. B. "--gpus 0 1 2 3", wird ParallelUpdater oder MultiprocessParallelUpdater (wenn NCCL aktiviert ist) automatisch ausgewählt und das Lernen wird auf mehreren GPUs durchgeführt.
Unter Ubuntu können Sie Fehler in PlotReport vermeiden, indem Sie "MPLBACKEND = Agg" und Umgebungsvariablen festlegen.
Das Ergebnis des tatsächlichen Drehens ist wie folgt. Ich habe vergeblich versucht, 4 GPUs zu verwenden.
$ MPLBACKEND=Agg chainer train config.yml --gpus 0 1 2 3
chainer version: 2.0.1
cuda: True, cudnn: True, nccl: True
result_dir: result/config_2017-07-18_23-26-41_0
train: 60000
valid: 10000
/home/shunta/.pyenv/versions/anaconda3-4.4.0/lib/python3.6/site-packages/chainer/training/updaters/multiprocess_parallel_updater.py:142: UserWarning: optimizer.lr is changed to 0.0025 by MultiprocessParallelUpdater for new batch size.
format(optimizer.lr))
epoch iteration main/loss validation/main/loss main/accuracy validation/main/accuracy elapsed_time lr
1 118 0.890775 0.234464 0.739672 0.928896 8.45449 0.0025
2 235 0.198075 0.141786 0.939503 0.957476 13.914 0.0025
3 352 0.128017 0.120378 0.960737 0.960839 19.1064 0.0025
4 469 0.100555 0.0979902 0.96895 0.969739 24.3107 0.0025
5 586 0.0865762 0.077968 0.971888 0.97587 29.2581 0.0025
6 704 0.0734014 0.0672336 0.976562 0.978837 34.3428 0.0025
7 821 0.0683174 0.0618281 0.977564 0.979826 39.1815 0.0025
8 938 0.0617364 0.0748559 0.980235 0.976958 44.0893 0.0025
9 1055 0.0573468 0.0596004 0.981904 0.980024 49.0457 0.0025
10 1172 0.0531992 0.0578394 0.98364 0.982694 54.3706 0.0025
11 1290 0.047489 0.0485524 0.986096 0.984573 59.3655 0.00025
12 1407 0.0417473 0.0482626 0.987513 0.984968 64.18 0.00025
13 1524 0.0406346 0.0473873 0.987914 0.984771 69.0114 0.00025
14 1641 0.0405981 0.0479212 0.987847 0.985265 74.0731 0.00025
15 1758 0.0394898 0.0478847 0.988114 0.986155 79.3369 0.00025
16 1875 0.0394069 0.0472816 0.988181 0.984968 84.2785 2.5e-05
17 1993 0.0389244 0.0471326 0.988546 0.985166 89.4715 2.5e-05
18 2110 0.0391655 0.046991 0.988181 0.985463 94.6602 2.5e-05
19 2227 0.0390729 0.0468674 0.988381 0.985364 99.7827 2.5e-05
20 2344 0.038587 0.0471131 0.988315 0.985166 104.962 2.5e-05
Da zwei plotReports in config.yml festgelegt wurden, geben Sie in config.yml im Ergebnisverzeichnis an (ein Verzeichnis mit einem Namen, der den Basisnamen der Konfigurationsdatei verkettet und das Datum / die Uhrzeit unter result erstellt). Bilder der Dateinamen (loss.png und Genauigkeit.png) werden erstellt.
Wenn das Lernen mit dem Befehl "chainer" gestartet wird, sind auch der Dateiname der automatisch angegebenen Konfigurationsdatei (wenn "config.yml" angegeben ist, der Teil von "config", der in die Erweiterung schaut) und die Startzeit enthalten. Infolgedessen wird automatisch ein Verzeichnis unter dem Verzeichnis "result" erstellt, das in der ausgeführten Hierarchie erstellt werden kann, und Modelldateien, Verlustdateien, Konfigurationsdateien usw. werden automatisch in dieses Verzeichnis kopiert. Dieses Verzeichnis ist in "out" des Trainers angegeben, daher werden dort auch Snapshots und Protokolldateien geschrieben.
Die Dinge, die mit einem solchen Tool gemacht werden können, sind sehr begrenzt, aber ich habe oft jedes Mal den gleichen train.py geschrieben, also habe ich versucht, ihn angemessen zu verallgemeinern. Wenn Sie jedoch NLP oder GAN ausführen, können Sie es nicht verwenden, da es streng ist, es sei denn, Sie können auch Updater angeben. Möglicherweise können Sie es für einfache Bilderkennungsaufgaben verwenden.
Recommended Posts