―― Il est difficile d'écrire le même code d'entraînement chaque fois que vous voulez essayer quelque chose en écrivant rapidement uniquement le code du modèle et l'ensemble de données. --Chainer a un outil pratique appelé Trainer, mais il est toujours difficile d'écrire du code pour ajouter une extension similaire à chaque fois pour créer train.py. ――Si vous passez un fichier YAML qui décrit les paramètres d'apprentissage, le fichier modèle, le fichier d'ensemble de données, etc. comme argument, ce serait facile s'il y avait un outil de ligne de commande qui commencerait à apprendre comme d'habitude. Je l'ai fait. Il s'agit essentiellement d'un outil oléorésabo complet, donc il n'a pas du tout été conçu avec l'idée d'être utilisé par les gens, mais il a été publié parce que c'était un gros problème.
ChainerCMD
https://github.com/mitmul/chainercmd
$ pip install chainercmd
$ chainer init
Ensuite, les quatre fichiers suivants seront créés.
Le contenu est comme ça.
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)
Après cela, modifiez-le pour les tâches individuelles et lorsque vous avez terminé
$ chainer train config.yml --gpus 0
Ensuite, l'apprentissage commencera à utiliser l'appareil avec l'ID GPU: 0. Si vous souhaitez utiliser plusieurs GPU, spécifiez les ID des GPU que vous souhaitez utiliser, séparés par des espaces, tels que «--gpus 0 1 2 3».
config.yml
Il s'agit d'un fichier qui décrit les paramètres d'apprentissage et le fichier à utiliser comme fichier modèle.
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
Il s'agit du réglage de l'ensemble de données d'entraînement et de l'ensemble de données de vérification. Définissez-les dans un autre fichier à l'avance, utilisez la clé file
pour spécifier le chemin d'accès à ce fichier et utilisez nom
pour spécifier le nom de classe de la classe de l'ensemble de données dans ce fichier. La valeur de ʻargsdoit être un dictionnaire, qui est passé comme argument de mot-clé au constructeur de la classe d'ensemble de données, tout comme
** args.
batchsize` est la taille du mini-lot créé à partir de chaque ensemble de données.
model & loss
model:
file: model.py
name: LeNet5
args:
n_class: 10
C'est presque la même chose, créer un modèle en instanciant une classe nommée name
dans le fichier dans le chemin spécifié par file
. S'il y a des «arguments» à ce moment-là, passez-le comme argument de mot-clé.
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
La partie loss
est fondamentalement la même, et ʻargs est omis ici, mais si vous spécifiez un dictionnaire avec ʻargs
comme clé comme la partie model
, il calculera la perte. Il est passé comme argument de mot-clé au constructeur de la classe pour. Pour loss
, vous pouvez utiliser le module de clé afin que vous puissiez également utiliser
chainer.links.Classifieretc. préparé par Chainer à l'avance.
module et
file` ne peuvent pas être utilisés en même temps.
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
Il s'agit de la partie paramétrage de l'Optimizer. method
sera le nom de la classe sous le module ʻoptimizers de Chainer. ʻArgs
est un argument mot-clé à transmettre à son constructeur. Si la clé weight_decay
est présente, la décroissance de poids est ajoutée en tant que crochet de l'optimiseur. Si les deux lr_drop_ratio
et lr_drop_triggers
sont présents, le taux d'apprentissage est supprimé en utilisant le ManualScheduleTrigger. Dans le dictionnaire passé à lr_drop_triggers
, quand points
double le taux d'apprentissage de lr_drop_ratio
, et ʻunit est l'unité de ce timing ("epoch
ou ʻitération` peut être spécifié). Dans le cas de l'exemple ci-dessus, le taux d'apprentissage de Momentum SGD est de 0,1 fois pour 10 époques et de 0,1 fois pour 15 époques à nouveau.
updater
Updater peut être personnalisé en préparant une fonction qui prend l'itérateur, l'optimiseur et les périphériques et renvoie un objet Updater, et en le spécifiant avec la clé updater_creater dans config.yml.
Une classe wrapper qui calcule les classes d'ensemble de données, les classes de modèle et les pertes écrites à l'aide de Chainer ordinaire. Pour custom_extension.py
, écrivez votre propre classe d'extension, spécifiez-la à partir de config.yml, et réécrivez-la lorsque vous voulez l'ajouter à Trainer.
Le fichier créé par chainer init
contient les modèles et les ensembles de données nécessaires pour exécuter l'exemple MNIST depuis le début, et si config.yml
est laissé tel quel, ces ensembles de données de modèle, etc. Est prêt à exécuter l'exemple MNIST en utilisant. Donc, tout ce que vous avez à faire est d'appuyer sur la commande chainer
. Spécifiez train
dans la sous-commande.
$ chainer train config.yml --gpus 0
Spécifiez le chemin du fichier de configuration YAML que vous souhaitez utiliser à côté de la sous-commande train
. Il n'est pas nécessaire que le nom de fichier soit config.yml. Si vous souhaitez utiliser le GPU, spécifiez l'ID de l'appareil avec l'option --gpus
. Si plus d'un est spécifié, tel que --gpus 0 1 2 3
, ParallelUpdater ou MultiprocessParallelUpdater (si NCCL est activé) sera automatiquement sélectionné et l'apprentissage sera effectué sur plusieurs GPU.
Lorsque vous faites sur Ubuntu Vous pouvez éviter les erreurs autour de PlotReport en définissant MPLBACKEND = Agg
et les variables d'environnement.
Le résultat du tournage est le suivant. J'ai essayé d'utiliser 4 GPU en vain.
$ 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
Puisque deux PlotReports ont été définis dans config.yml, spécifiez dans config.yml dans le répertoire de résultats (un répertoire avec un nom qui concatène le nom de base du fichier de configuration et la date / heure est créée sous result). Des images des noms de fichiers (loss.png et precision.png) sont créées.
Lorsque l'apprentissage est démarré avec la commande chainer
, le nom de fichier du fichier de configuration spécifié automatiquement (lorsque config.yml
est spécifié, la partie de config
regardant dans l'extension) et l'heure de début sont également inclus. En conséquence, un répertoire est automatiquement créé sous le répertoire result
qui peut être créé dans la hiérarchie exécutée, et les fichiers de modèle, les fichiers de perte, les fichiers de configuration, etc. y sont automatiquement copiés. Ce répertoire est spécifié dans ʻout` de Trainer, donc des instantanés et des fichiers journaux y sont également écrits.
Les choses qui peuvent être faites avec un tel outil sont très limitées, mais j'ai souvent écrit le même train.py à chaque fois, j'ai donc essayé de le généraliser de manière appropriée. Cependant, si vous utilisez NLP ou GAN, vous ne pouvez pas l'utiliser car il est strict à moins que vous ne puissiez également spécifier Updater. Vous pourrez peut-être l'utiliser pour des tâches simples de reconnaissance d'image.
Recommended Posts