R の MXNet で iris を分類

MXNet で iris を分類」 と同様の処理を R言語で実装してみました。

ソースは http://github.com/fits/try_samples/tree/master/blog/20171212/

準備

今回は下記サイトの手順に従って MXNet R パッケージの CPU 版を Windows へインストールしました。

MXNet R パッケージの CPU 版を Windows へインストール
cran <- getOption("repos")
cran["dmlc"] <- "https://apache-mxnet.s3-accelerate.dualstack.amazonaws.com/R/CRAN/"
options(repos = cran)
install.packages("mxnet")

インストールした mxnet のバージョンが少し古いようですが(現時点の MXNet 最新バージョンは 1.0)、今回はこれを使います。

バージョン確認
> packageVersion('mxnet')
[1]0.10.1’

学習と評価

MXNet には、階層型ニューラルネットワークの学習処理を簡単に実行するための関数 mx.mlp が用意されているので、今回はこれを使います。

引数 備考
hidden_node 隠れ層のノード(ニューロン)数(デフォルトは 1)
out_node 出力ノード数(今回は分類数)
num.round 繰り返し回数(デフォルトは 10)
array.batch.size バッチサイズ(デフォルトは 128)
learning.rate 学習係数
activation 活性化関数(デフォルトは tanh

hidden_node にベクトル(例. c(6, 4))を設定すれば隠れ層が複数階層化されるようです。

iris のデータセットは R に用意されているものを使います。

mx.mlp の入力データには mx.io.DataIter か R の配列 / 行列を使う必要があるようなので(ラベルデータは配列のみ)、data.matrix で行列化しています。

ラベルデータとする iris の種別 iris$Species は因子型ですが、mxnet では因子型を扱えないようなので as.numeric で数値化しています。

ここで as.numeric の結果は 1 ~ 3 の数値になりますが、mxnet で 3種類の分類を行うには 0 ~ 2 でなければならないようなので -1 しています。

一方、predict の結果を max.col(t(<predictの結果>)) で処理すると 1 ~ 3 の数値になるため、評価用のラベルデータは -1 せずに正解率の算出に使っています。

また、array.layout = 'rowmajor' は Warning message 抑制のために設定しています。

iris_hnn.R
library(mxnet)

train_size = 0.7

n = nrow(iris)
# 1 ~ n から無作為に n * train_size 個を抽出
perm = sample(n, size = round(n * train_size))

# 学習用データ
train <- iris[perm, ]
# 評価用データ
test <-iris[-perm, ]

# 学習用入力データ
train.x <- data.matrix(train[1:4])
# 学習用ラベルデータ(0 ~ 2)
train.y <- as.numeric(train$Species) - 1

# 評価用入力データ
test.x <- data.matrix(test[1:4])
# 評価用ラベルデータ(1 ~ 3)
test.y <- as.numeric(test$Species)

mx.set.seed(0)

# 学習
model <- mx.mlp(train.x, train.y, 
                hidden_node = 5, 
                out_node = 3,
                num.round = 100,
                learning.rate = 0.1,
                array.batch.size = 10,
                activation = 'relu',
                array.layout = 'rowmajor',
                eval.metric = mx.metric.accuracy)

# 評価
pred <- predict(model, test.x, array.layout = 'rowmajor')

# 評価用データの分類結果(1 ~ 3)
pred.y <- max.col(t(pred))

# 評価データの正解率を算出
acc <- sum(pred.y == test.y) / length(pred.y)

print(acc)

実行結果は以下の通り。

実行結果
・・・
> model <- mx.mlp(train.x, train.y, 
+                 hidden_node = 5, 
+                 out_node = 3,
+                 num.round = 100,
+                 learning.rate = 0.1,
+                 array.batch.size = 10,
+                 activation = 'relu',
+                 array.layout = 'rowmajor',
+                 eval.metric = mx.metric.accuracy)
Start training with 1 devices
[1] Train-accuracy=0.32
[2] Train-accuracy=0.281818181818182
・・・
[99] Train-accuracy=0.954545454545455
[100] Train-accuracy=0.954545454545455
・・・
> print(acc)
[1] 0.9555556

備考

predict の実行結果は以下のような内容となっています。

> pred

            [,1]        [,2]        [,3]        [,4]
[1,] 0.968931615 0.968931615 0.968931615 0.968931615
[2,] 0.029328469 0.029328469 0.029328469 0.029328469
[3,] 0.001739914 0.001739914 0.001739914 0.001739914
            [,5]        [,6]        [,7]        [,8]
[1,] 0.968931615 0.968931615 0.968931615 0.968931615
[2,] 0.029328469 0.029328469 0.029328469 0.029328469
[3,] 0.001739914 0.001739914 0.001739914 0.001739914
・・・
            [,41]        [,42]        [,43]        [,44]
[1,] 1.762393e-08 7.670556e-06 5.799695e-06 9.349569e-12
[2,] 3.053433e-02 2.679898e-01 1.714197e-01 7.250102e-05
[3,] 9.694657e-01 7.320026e-01 8.285745e-01 9.999275e-01
            [,45]
[1,] 4.420018e-08
[2,] 8.569881e-03
[3,] 9.914301e-01

1 ~ 3 の中で最も数値の高いものが分類結果となりますので、上記t で転置して max.col すると以下のようになります。

> max.col(t(pred))

 [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 3 2 2 2 2 2
[30] 3 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3