[PYTHON] J'ai réécrit le code MNIST de Chainer avec PyTorch + Ignite

TL;DR L'impression de réécrire le code MNIST de Chainer dans PyTorch était presque la même. La différence était la couche au-dessus de Updater dans Chainer et la couche Ignite dans PyTorch. De plus, si vous utilisez [chainer-pytorch-migration] 3, vous pouvez utiliser les extensions utilisées dans Chainer dans Ignite, et vous pouvez utiliser PyTorch + Ignite tout comme Chainer. Je pense que ceux qui ont utilisé Chainer pourront s'habituer naturellement à PyTorch + Ignite.

Développement de chaînes arrêté par PFN et PyTorch adopté

Comme décrit ici [\ [1 ]] 1, il a été annoncé que PFN mettra fin au développement de Chainer et passera à PyTorch.

Preferred Networks Co., Ltd. (Siège social: Chiyoda-ku, Tokyo, Président: Toru Nishikawa, Preferred Networks, ci-après PFN) a développé un cadre d'apprentissage en profondeur, qui est la technologie de base pour la recherche et le développement, à partir de son Chainer ™ développé en interne. Migrez vers PyTorch de manière séquentielle. Dans le même temps, nous collaborerons avec Facebook, qui développe PyTorch, et la communauté des développeurs de PyTorch, et participerons au développement de PyTorch. De plus, Chainer passera à la phase de maintenance avec la dernière version v7, qui est une mise à jour majeure de la version publiée aujourd'hui. Pour les utilisateurs de Chainer, nous fournissons de la documentation et des bibliothèques pour vous aider à migrer vers PyTorch.

Ce n'est pas que vous ne pouvez pas utiliser Chainer tout de suite, mais les utilisateurs de Chainer sont progressivement obligés de passer à d'autres frameworks.

Prise en charge de la migration de Chainer vers PyTorch avec PFN

Je pense que de nombreux utilisateurs ont été déroutés par l'annonce soudaine de la fin du développement de Chainer, mais PFN prend également en charge la transition vers PyTorch en prévision de cette situation [Document \ [2 ]] 2 et [Bibliothèque \ [ 3 ]] 3 est fourni.

En regardant le document ci-dessus, la correspondance entre Chainer et PyTorch + Ignite est la suivante.

スクリーンショット 2019-12-17 15.32.28.png cited from [2]

Ce que vous pouvez voir ci-dessus

--PyTorch prend en charge le rôle de Chainer jusqu'à Optimizer --Ignite prend en charge le rôle de Updater / Trainer of Chainer.

Donc, si vous voulez écrire les étapes d'apprentissage vous-même, vous ne pouvez écrire qu'avec PyTorch, mais si vous voulez que les étapes d'apprentissage soient gérées par le framework comme Trainer of Chainer, vous devez utiliser PyTorch + Ignite.

Je suis immédiatement passé de Chainer à PyTorch + Ignite

Code à migrer

Il y a un cahier pour la formation et l'inférence MNIST en utilisant Chainer's Trainer sur le lien ci-dessous.

Cette fois, je voudrais réécrire le code ci-dessus en utilisant PyTorch + Ignite.

Comment migrer chaque étape

Lecture d'une partie de l'échantillon de données

from chainer.datasets import mnist

train, test = mnist.get_mnist()

from torchvision.datasets import MNIST
from torchvision.transforms import ToTensor

data_transform = ToTensor()

train = MNIST(download=True, root=".", transform=data_transform, train=True)
test = MNIST(download=False, root=".", transform=data_transform, train=False)

Iterator -> DataLoader

from chainer import iterators

batchsize = 128

train_iter = iterators.SerialIterator(train, batchsize)
test_iter = iterators.SerialIterator(test, batchsize, False, False)

from torch.utils.data import DataLoader

batch_size = 128

train_loader = DataLoader(train, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test, batch_size=batch_size, shuffle=False)

Préparation du modèle


import chainer
import chainer.links as L
import chainer.functions as F

class MLP(chainer.Chain):

    def __init__(self, n_mid_units=100, n_out=10):
        super(MLP, self).__init__()
        with self.init_scope():
            self.l1=L.Linear(None, n_mid_units)
            self.l2=L.Linear(None, n_mid_units)
            self.l3=L.Linear(None, n_out)


    def forward(self, x):
        h1 = F.relu(self.l1(x))
        h2 = F.relu(self.l2(h1))
        return self.l3(h2)

gpu_id = 0  # Set to -1 if you don't have a GPU

model = L.Classifier(model)
if gpu_id >= 0:
    model.to_gpu(gpu_id)

from torch import nn
import torch.nn.functional as F
import torch

class MLP(nn.Module):

    def __init__(self, n_mid_units=100, n_out=10):
        super(MLP, self).__init__()
        self.l1 = nn.Linear(784, n_mid_units)
        self.l2 = nn.Linear(n_mid_units, n_mid_units)
        self.l3 = nn.Linear(n_mid_units, n_out)

    def forward(self, x):
        x = torch.flatten(x, start_dim=1)
        h1 = F.relu(self.l1(x))
        h2 = F.relu(self.l2(h1))
        h3 = self.l3(h2)
        return F.log_softmax(h3, dim=1)

device = 'cuda:0'

model = MLP()

Préparation à l'optimiseur

from chainer import optimizers

lr = 0.01

optimizer = optimizers.SGD(lr=lr)
optimizer.setup(model)

from torch import optim

lr = 0.01

#Sélection de la méthode d'optimisation
optimizer = optim.SGD(model.parameters(), lr=lr)

Updater -> Ignite

from chainer import training

updater = training.StandardUpdater(train_iter, optimizer, device=gpu_id)

from ignite.engine import create_supervised_trainer

trainer = create_supervised_trainer(model, optimizer, F.nll_loss, device=device)

Ajout d'extension

from chainer.training import extensions

trainer = training.Trainer(
    updater, (max_epoch, 'epoch'), out='mnist_result'
)

trainer.extend(extensions.LogReport())
.
.
.
trainer.extend(extensions.Evaluator(test_iter, model, device=gpu_id))

from ignite.engine import create_supervised_evaluator
from ignite.metrics import Accuracy, Loss
from ignite.engine import Events

evaluator = create_supervised_evaluator(
    model,
    metrics={
      'accuracy': Accuracy(),
      'nll': Loss(F.nll_loss),
    },
    device=device,
)

training_history = {'accuracy':[],'loss':[]}
validation_history = {'accuracy':[],'loss':[]}

@trainer.on(Events.EPOCH_COMPLETED)
def log_training_results(engine):
    evaluator.run(train_loader)
    metrics = evaluator.state.metrics
    avg_accuracy = metrics['accuracy']
    avg_nll = metrics['nll']
    training_history['accuracy'].append(avg_accuracy)
    training_history['loss'].append(avg_nll)
    print(
        "Training Results - Epoch: {}  Avg accuracy: {:.2f} Avg loss: {:.2f}"
        .format(engine.state.epoch, avg_accuracy, avg_nll)
    )

@trainer.on(Events.EPOCH_COMPLETED)
def log_validation_results(engine):
    evaluator.run(test_loader)
    metrics = evaluator.state.metrics
    avg_accuracy = metrics['accuracy']
    avg_nll = metrics['nll']
    validation_history['accuracy'].append(avg_accuracy)
    validation_history['loss'].append(avg_nll)
    print(
        "Validation Results - Epoch: {}  Avg accuracy: {:.2f} Avg loss: {:.2f}"
        .format(engine.state.epoch, avg_accuracy, avg_nll))

# Create snapshot
from ignite.handlers import ModelCheckpoint

checkpointer = ModelCheckpoint(
    './models',
    'MNIST',
    save_interval=1,
    n_saved=2, 
    create_dir=True, 
    save_as_state_dict=True,
    require_empty=False,
)
trainer.add_event_handler(Events.EPOCH_COMPLETED, checkpointer, {'MNIST': model})

Exécution de la formation

trainer.run()

max_epochs = 10
trainer.run(train_loader, max_epochs=max_epochs)

Code post-migration

Vous trouverez ci-dessous un bloc-notes qui migre et s'exécute sur Colaboratory. En plus du code expliqué ci-dessus, ce qui suit est également inclus, alors essayez de l'exécuter à portée de main si vous le souhaitez.

https://drive.google.com/open?id=1NqHYJjFz-dl1tWP8kMO0y0kCZ9-ZWLxi

prime

En fait, si vous utilisez [chainer-pytorch-migration] 3, vous pouvez utiliser les extensions utilisées dans Chainer dans Ignite! Si vous manquez les extensions Chainer, essayez d'utiliser chainer-pytorch-migration.

import chainer_pytorch_migration as cpm
import chainer_pytorch_migration.ignite
from chainer.training import extensions

optimizer.target = model
trainer.out = 'result'

cpm.ignite.add_trainer_extension(trainer, optimizer, extensions.LogReport())
cpm.ignite.add_trainer_extension(trainer, optimizer, extensions.ExponentialShift('lr', 0.9, 1.0, 0.1))
cpm.ignite.add_trainer_extension(trainer, optimizer, extensions.PrintReport(
    ['epoch', 'iteration', 'loss', 'lr']))

max_epochs = 10
trainer.run(train_loader, max_epochs=max_epochs)

Reference

Recommended Posts

J'ai réécrit le code MNIST de Chainer avec PyTorch + Ignite
J'ai créé Word2Vec avec Pytorch
J'ai essayé de classer MNIST par GNN (avec PyTorch géométrique)
J'ai essayé d'implémenter Attention Seq2Seq avec PyTorch
J'ai essayé d'implémenter DeepPose avec PyTorch
J'ai essayé d'implémenter la régularisation Shake-Shake (ShakeNet) avec PyTorch
[Introduction à Pytorch] J'ai joué avec sinGAN ♬
J'ai essayé d'implémenter DeepPose avec PyTorch PartⅡ
J'ai essayé d'implémenter CVAE avec PyTorch
J'ai essayé d'implémenter la lecture de Dataset avec PyTorch
J'ai essayé de déplacer GAN (mnist) avec keras
J'ai essayé Flask avec des conteneurs distants de VS Code
Jouez avec PyTorch
Validation croisée avec PyTorch
À partir de PyTorch
Code pour TensorFlow MNIST débutant / expert avec commentaires japonais
J'ai essayé de déplacer Faster R-CNN rapidement avec pytorch
Entraînez les données MNIST avec PyTorch en utilisant un réseau neuronal
J'ai essayé d'implémenter et d'apprendre DCGAN avec PyTorch
[Introduction à Pytorch] J'ai essayé de catégoriser Cifar10 avec VGG16 ♬
J'ai essayé d'implémenter SSD avec PyTorch maintenant (Dataset)
J'ai eu une erreur lors de l'utilisation de Tensorboard avec Pytorch