R h2o をつかってみるだけ

h2o(H2O のR用インターフェース)をつかってみる
※ つかってみるだけであって、以下のような状況に最適なツールだといっているわけではない
※ そもそも画像認識の知識がない

環境準備
  • パッケージ h2o をインストールする(予め JDK をインストールしておく)
    今回は Version 3.6.0.8 を入れたので、同じ版であれば以下のコードで動作する(はず)
    版が違うと引数ラベルが違うこともあるようなので注意
データ準備
  • 学習用、テスト用データを用意する(画像:全てガールズ&パンツァー公式サイトより)
    顔範囲の認識は今回は手動でいい加減に行う
    f:id:cookie-box:20160116155708p:plain:w300
  • GIMPでリサイズ(今回は 90×90 ピクセル)し、RAWデータとしてエクスポートする
  • bincsvでRAWデータをCSVに書き出す(10進数にする)
    • このツールでは出力にシングルクオテーションが混じるようなので置換で取り除いておく
学習
  • R で各CSVを読み込んでグレースケール化し 8100 次元のベクトルにする(参考文献1)
    • 事前知識としてグレースケールの手書き数字の分類を知っているくらいでカラー画像の取り扱いを知らないため
    • グレースケール化せずにRGBの3倍の長さのベクトルにしてみても結果に大して変わりはなかった
  • h2o.deeplearning に学習用データを渡し分類器を学習させ、テスト用データの判定をみる(参考文献2)
結果

テストデータf:id:cookie-box:20160116162318p:plain:w55f:id:cookie-box:20160116162324p:plain:w55f:id:cookie-box:20160116162332p:plain:w55f:id:cookie-box:20160116162343p:plain:w55f:id:cookie-box:20160116162352p:plain:w55
正解anzumahomihosaoriyukari
分類器による判定anzumahoyukarisaoriyukari
活性化関数、隠れ層のサイズ、イテレーション回数を変更してもみほがみほと判定されなかった
設定によっても正誤は変わるが、下のコードで多少試した範囲では、全員合うケース、みほが正しく判定されるケースはなかった
この少なすぎるデータ数でどうもこうもないけどみほのテストデータの何かが他のキャラっぽいのか
確率分布がどの活性化関数にしてもほぼ 1 or 0 だった

結果(参考)

アイマスの雪歩(画像:アイドルマスター公式サイトより)

テストデータf:id:cookie-box:20160116172315p:plain:w55
分類器による判定miho
みほと判定される
みほのテストデータがみほと判定されていないのに

コード
library("h2o", lib.loc="C:/banana/libs") # 普通のインストールが上手くいかなかったので .zip からここにインストール

GetVectorFromCsv <- function(csv.path) {
  # bincsv の出力ファイルに # が含まれるのでコメント文字を何か別の文字に回避
  x <- read.table(csv.path, header=T, skip=1, sep=",", comment.char="%")
  # h03, h07, h0B, h0F 列は透明度なので使用しない
  vec.r <- as.vector(t(x[,c("h00", "h04", "h08", "h0C")]))
  vec.g <- as.vector(t(x[,c("h01", "h05", "h09", "h0D")]))
  vec.b <- as.vector(t(x[,c("h02", "h06", "h0A", "h0E")]))
  vec <- 2.0 * vec.r + 4.0 * vec.g + vec.b # グレースケール化 (NTSC 参考文献参照)
  # vec <- c(vec.r, vec.g, vec.b) # グレースケール化せずRGBのベクトルを全て使用
  return(vec)
}

# データ読み込み
data <- NULL
characters <- c("anzu", "maho", "miho", "saori", "yukari")
for (character in characters) {
  for (i.img in 1:4) {
    csv.path <- paste0("img/", character, i.img, ".csv")
    vec <- GetVectorFromCsv(csv.path)
    data <- rbind(data, vec)
  }
}
data <- as.data.frame(data)
dim.input <- ncol(data)
data$label <- rep(characters, each=4)

# 学習用データとテスト用データにふり分け
test.index <- seq(4, 20, by=4)
train.data <- data[-test.index,]
test.data  <- data[test.index,]

# テスト用データにゆきぽを追加する場合
vec <- GetVectorFromCsv("img/yukiho.csv")
test.data[nrow(test.data)+1,] <- c(vec, "yukiho")

# 学習(ほとんど参考文献と同じ)
write.csv(train.data, file="train.csv", row.names=FALSE, quote=FALSE)
write.csv(test.data,  file="test.csv", row.names=FALSE, quote=FALSE)

localH2O <- h2o.init(ip="localhost", port=54321, startH2O=TRUE, nthreads=-1)

train.data <-  h2o.importFile(path="train.csv")
test.data  <-  h2o.importFile(path="test.csv")

result <- h2o.deeplearning(x=1:dim.input,
                           y=dim.input + 1,
                           training_frame=train.data,
                           activation="Tanh",  # "Maxout" "RectifierWithDropout" # 適当
                           hidden=c(100, 100), # 適当
                           epochs=200)         # 適当
predict <- h2o.predict(object=result, newdata=test.data[,-(dim.input + 1)])
predict <- as.data.frame(predict)