RでMXNet(1)

ついにフレームワークに手を出した。
数ある中で「MXNet」を選択。(なんとなくRから使いやすそうなので)

WindowsのCPU用のインストールは非常に簡単。
Rのコマンドラインに以下を入力。

install.packages("drat")
drat::addRepo("dmlc")
install.packages("mxnet")

Rの「mxnet」パッケージがインストールされると同時に「MXNet」そのものがインストールされる。
そのためパッケージを読み込むだけですぐに使用できる。

library(mxnet)


(2017年7月4日追記)
上記でだめならこちらを試してみて下さい。

cran <- getOption("repos")
cran["dmlc"] <- "https://s3-us-west-2.amazonaws.com/apache-mxnet/R/CRAN/"
options(repos = cran)
install.packages("mxnet")

(ここまで)


(2017年7月17日追記)
GPU版はこちらを参照。
(ここまで)


「MNISTやってみました」という記事はネット上にあふれているが、詳細な日本語マニュアルは少ない。
実際、自分がいろいろやってみてわかったことを記述。

#訓練データの読み込み
x_train <- readRDS("x_train") / 255
t_train <- apply(readRDS("t_train"), 1, which.max) - 1

#テストデータの読み込み
x_test <- readRDS("x_test")
t_test <- apply(readRDS("t_test"), 1, which.max) - 1
  • 一般的にはone-hot表現は使わないらしい

簡単な2層ニューラルネットワークを作ってみた。

#2層NN
data <- mx.symbol.Variable("data")
fc1 <- mx.symbol.FullyConnected(data, name = "fc1", num_hidden = 100)
act1 <- mx.symbol.Activation(fc1, name = "relu1", act_type = "relu")
fc2 <- mx.symbol.FullyConnected(act1, name = "fc2", num_hidden = 10)
softmax <- mx.symbol.SoftmaxOutput(fc2, name = "sm")

#実行
mx.set.seed(200)
model <- mx.model.FeedForward.create(
    softmax, X = x_train,
    y = t_train,
    ctx = mx.cpu(),
    num.round = 15,
    array.batch.size = 100,
    learning.rate = 0.1, momentum = 0,
    eval.metric = mx.metric.accuracy,
    eval.data = list(data = x_test, label = t_test),
    initializer = mx.init.normal(0.01),
    array.layout = "rowmajor")
  • どうやらnum.roundはエポック数を指している
  • デフォルトの最適化はSGDであるが、厳密にはSGD with Momentumを指す

(momentum=0を指定するとsimple SGDになると思う)

  • 行列の行数=標本数の場合に、array.layout="rowmajor"

結果1

Start training with 1 devices
[1] Train-accuracy=0.809048414023373
[1] Validation-accuracy=0.9045
[2] Train-accuracy=0.915516666666667
[2] Validation-accuracy=0.9206
[3] Train-accuracy=0.932616666666668
[3] Validation-accuracy=0.9339
[4] Train-accuracy=0.943583333333335
[4] Validation-accuracy=0.9447
[5] Train-accuracy=0.951783333333336
[5] Validation-accuracy=0.9514
[6] Train-accuracy=0.957883333333338
[6] Validation-accuracy=0.9564
[7] Train-accuracy=0.962600000000005
[7] Validation-accuracy=0.9596
[8] Train-accuracy=0.966416666666673
[8] Validation-accuracy=0.9631
[9] Train-accuracy=0.969200000000007
[9] Validation-accuracy=0.9649
[10] Train-accuracy=0.971900000000006
[10] Validation-accuracy=0.966499999999999
[11] Train-accuracy=0.974400000000006
[11] Validation-accuracy=0.9679
[12] Train-accuracy=0.976300000000007
[12] Validation-accuracy=0.969299999999999
[13] Train-accuracy=0.97808333333334
[13] Validation-accuracy=0.97
[14] Train-accuracy=0.979600000000006
[14] Validation-accuracy=0.970699999999999
[15] Train-accuracy=0.980766666666673
[15] Validation-accuracy=0.9715
  • 1epoch毎に結果が出力される(Train-accuracy)
  • eval.dataを指定しておけばその結果(Validation-accuracy)も1epoch毎に返してくれる

実行&結果2

出力が必要なければ記録することも可能

#結果を保存するためのクラス
logger <- mx.metric.logger$new()

mx.set.seed(200)

model <- mx.model.FeedForward.create(
    softmax, X = x_train,
    y = t_train,
    ctx = mx.cpu(),
    num.round = 15,
    array.batch.size = 100,
    learning.rate = 0.1, momentum = 0,
    eval.metric = mx.metric.accuracy,
    eval.data = list(data=x_test,label=t_test),
    initializer = mx.init.normal(0.01),
    array.layout = "rowmajor",
    verbose = F,
    epoch.end.callback = mx.callback.log.train.metric(15,logger))
> logger
Reference class object of class "mx.metric.logger"
Field "train":
 [1] 0.8090484 0.9155167 0.9326167 0.9435833 0.9517833 0.9578833 0.9626000
 [8] 0.9664167 0.9692000 0.9719000 0.9744000 0.9763000 0.9780833 0.9796000
[15] 0.9807667
Field "eval":
 [1] 0.9045 0.9206 0.9339 0.9447 0.9514 0.9564 0.9596 0.9631 0.9649 0.9665
[11] 0.9679 0.9693 0.9700 0.9707 0.9715
  • mx.callback.log.train.metricで指定した数字はよく理解できない

(数字が変わっても結果は変わらない印象)

  • 学習後の重みとバイアスはmodel$arg.paramsから取り出せる
> is.list(model$arg.params)
[1] TRUE
> names(model$arg.params)
[1] "fc1_weight" "fc1_bias"   "fc2_weight" "fc2_bias"