FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

MNISTによるChainerのファーストインプレッション

f:id:msyksphinz:20160520003556j:plain

Chainerのインストール環境が整ったので、まずはChainerのチュートリアルを実行した。

msyksphinz.hatenablog.com

ニューラルネットワークチュートリアルといえばやっぱりMNISTだ。TensorFlowでもMNISTは最初に実行するチュートリアルになっている。

qiita.com

上記の解説記事に書いてあるように、まずはtrain_mnist.pyを実行して動作を観察する。

引数の処理

parser = argparse.ArgumentParser(description='Chainer example: MNIST')
parser.add_argument('--initmodel', '-m', default='',
                    help='Initialize the model from given file')
parser.add_argument('--resume', '-r', default='',
                    help='Resume the optimization from snapshot')
parser.add_argument('--net', '-n', choices=('simple', 'parallel'),
                    default='simple', help='Network type')
parser.add_argument('--gpu', '-g', default=-1, type=int,
                    help='GPU ID (negative value indicates CPU)')
parser.add_argument('--epoch', '-e', default=20, type=int,
                    help='number of epochs to learn')
parser.add_argument('--unit', '-u', default=1000, type=int,
                    help='number of units')
parser.add_argument('--batchsize', '-b', type=int, default=100,
                    help='learning minibatch size')
  • initmodel: 初期モデルをロードする。指定した場合は、以下でロードされる。
if args.initmodel:
    print('Load model from', args.initmodel)
    serializers.load_npz(args.initmodel, model)
  • resume: optimizerをロードする。すでに学習済みのモデルをロードすることになる?
if args.resume:
    print('Load optimizer state from', args.resume)
    serializers.load_npz(args.resume, optimizer)
  • net : ネットワークの並列処理の可否を指定する?GPU指定があるときはどちらも有効化する。MnistMLP()を呼び出すか、MnistMLPParallel()を呼び出すかの違いになっているようだ。
if args.net == 'simple':
    model = L.Classifier(net.MnistMLP(784, n_units, 10))
    if args.gpu >= 0:
        cuda.get_device(args.gpu).use()
        model.to_gpu()
    xp = np if args.gpu < 0 else cuda.cupy
elif args.net == 'parallel':
    cuda.check_cuda_available()
    model = L.Classifier(net.MnistMLPParallel(784, n_units, 10))
    xp = cuda.cupy
  • gpu : GPUを有効化する

  • epoch : epoch(データの学習回数)を指定する

n_epoch = args.epoch
  • unit : データの更新単位を指定する。
n_units = args.unit

これ、最終的にどこに効くかというと、

if args.net == 'simple':
    model = L.Classifier(net.MnistMLP(784, n_units, 10))
    if args.gpu >= 0:
        cuda.get_device(args.gpu).use()
        model.to_gpu()
    xp = np if args.gpu < 0 else cuda.cupy
elif args.net == 'parallel':
    cuda.check_cuda_available()
    model = L.Classifier(net.MnistMLPParallel(784, n_units, 10))
    xp = cuda.cupy

の部分になるのだが、n_unitsにより中間レイヤの数が決まるように見える。

  • batchsize : バッチサイズを指定する。

Learning Loopの詳細

詳しくはソースコードを見るのが一番良いのだが、概略を示すと以下のようになる。

# Setup optimizer
optimizer = optimizers.Adam()   # Adam : SGDの更新式: [https://ja.scribd.com/doc/260859670/30minutes-Adam]
optimizer.setup(model)

# Learning loop
for epoch in six.moves.range(1, n_epoch + 1):   # n_epoch回数分学習を繰替えす
    # x, t変数作成 先に定義した x_train, y_train から切り出す。
    for i in six.moves.range(0, N, batchsize):  # バッチサイズのステップで、Nまで繰替えす
        optimizer.update(model, x, t)           # モデルを更新
        # 必要に応じてグラフ描画
        # 精度の計算

実行結果

仮想マシン上で実行しているのだが結構な時間がかかる。数時間がかかっているだろうか。

$ time python ./train_mnist.py
GPU: -1
# unit: 1000
# Minibatch-size: 100
# epoch: 20
Network type: simple

load MNIST dataset
epoch 1
graph generated
train mean loss=0.19138759135, accuracy=0.942583334881, throughput=156.836722845 images/sec
test  mean loss=0.101782948093, accuracy=0.967800005674
epoch 2
train mean loss=0.073480642344, accuracy=0.977633343637, throughput=171.438272947 images/sec
test  mean loss=0.0949596984277, accuracy=0.970700005293
epoch 3

...