渋谷駅前で働くデータサイエンティストのブログ

元祖「六本木で働くデータサイエンティスト」です / 道玄坂→銀座→東京→六本木→渋谷駅前

H2OのRパッケージ{h2o}でお手軽にDeep Learningを実践してみる(4):隠れ層の特徴表現を抽出してみたがよく分からなかった話

そういえばMNISTコンペが気が付いたらまた1年延長されたみたいですが。



これ以上順位上げるのは面倒で仕方ないのでほっといて、もうちょっと自分の勉強しようかと思います。今気になってるのが、隠れ層における特徴量の表現状態。どちらかというとConvNetの利点として紹介されることが多いのですが、Deep Belief Networkたる{h2o}にもh2o.deepfeaturesという関数があってやはり隠れ層における表現を抽出してくることができます。


で、その関数の概要をヘルプで見るとこんなことが書いてあります。

Feature Generation via H2O Deep Learning Model

Description

Extract the non-linear features from a H2O dataset using a H2O deep learning model.

Usage

h2o.deepfeatures(data, model, key = "", layer = -1)

Arguments

data
An H2OParsedData object.

model
An H2ODeepLearningModel object that represents the deeplearning model to be used for feature extraction.

key
(Optional) The unique hex key assigned to the resulting dataset. If none is given, a key will automatically be generated.

layer
(Optional) Index of the hidden layer to extract. If none is given, the last hidden layer is chosen.)

Value

Returns an H2OParsedData object with as many features as the number of units in the hidden layer of specified index. If the model is supervised, and the data object has a column of the same name as the response with which the model was trained, then the response column will be prepended to the output frame.

See Also

H2OParsedData, H2ODeepLearningModel, h2o.deeplearning

Examples
library(h2o)
localH2O = h2o.init()
prosPath = system.file("extdata", "prostate.csv", package = "h2o")
prostate.hex = h2o.importFile(localH2O, path = prosPath)
prostate.dl = h2o.deeplearning(x = 3:9, y = 2, data = prostate.hex, hidden = c(100, 200),
                               epochs = 5)
prostate.deepfeatures_layer1 = h2o.deepfeatures(prostate.hex, prostate.dl, layer = 1)
prostate.deepfeatures_layer2 = h2o.deepfeatures(prostate.hex, prostate.dl, layer = 2)
head(prostate.deepfeatures_layer1)
head(prostate.deepfeatures_layer2)


ちなみに同一H2Oインスタンスから生成されたparsed data / model同士でないとh2o.deepfeatures関数自体が走らないので要注意*1。その都度フレッシュなh2o.deeplearning関数が推定したモデルを使って、特徴量を抽出する必要があります。


で、使い方を調べようと思ったんですがH2O World Trainingを見ても特に記述がない。。。orz


http://learn.h2o.ai/content/hands-on_training/deep_learning.html


ということで、適当に触ってみます。まずはフレッシュなh2o.deeplearning推定モデルを作ります。train.csvはKaggle MNISTコンペのデータとして、以下のように手早くモデルを推定します。

> library(h2o)
> localH2O <- h2o.init(ip = "localhost", port = 54321, startH2O = TRUE, nthreads=7)
> trData<-h2o.importFile(localH2O,path="data/train_noheader.csv")
> res.dl <- h2o.deeplearning(x = 2:785, y = 1, data = trData, activation = "RectifierWithDropout", hidden=c(1024,1024,2048),epochs = 10, adaptive_rate = FALSE, rate=0.01, rate_annealing = 1.0e-6, rate_decay = 1.0, momentum_start = 0.5,momentum_ramp = 42000*0.6, momentum_stable = 0.99, input_dropout_ratio = 0.2, l1 = 1.0e-5,l2 = 0.0,max_w2 = 15.0, initial_weight_distribution = "Normal",initial_weight_scale = 0.01,nesterov_accelerated_gradient = T, loss = "CrossEntropy", fast_mode = T, diagnostics = T, ignore_const_cols = T, force_load_balance = T, autoencoder = F)
> res_layer1<-h2o.deepfeatures(trData,res.dl,layer=1)
> res_layer2<-h2o.deepfeatures(trData,res.dl,layer=2)
> res_layer3<-h2o.deepfeatures(trData,res.dl,layer=3)


epochs = 10なのでかなり粗いモデルですが、それでも正答率は0.97014と言うほど悪くもないです*2。で、deepfeaturesを描画してみたらどうなるんでしょうか? Web上には↓↓こんな例があるようですが。。。



これに従ってちょろちょろimage関数を使って描画してみたらこんなのできました。

> train<-read.delim('train.csv',header=T,sep=',')
> idx<-which(as.matrix(res_layer1$label)[1:100]==4) # 「4」を例にとる
> par(mfrow=c(5,4))
> for (i in 1:5){
+ image(t(apply(matrix(as.vector(as.matrix(train[idx[i],-1])),ncol=28,nrow=28,byrow=T),2,rev)),col=grey(seq(0,1,length.out=256)))
+ image(t(apply(matrix(as.vector(as.matrix(res_layer1[idx[i],-1])),ncol=32,nrow=32,byrow=T),2,rev)),col=grey(seq(0,1,length.out=256)))
+ image(t(apply(matrix(as.vector(as.matrix(res_layer2[idx[i],-1])),ncol=32,nrow=32,byrow=T),2,rev)),col=grey(seq(0,1,length.out=256)))
+ image(t(apply(matrix(as.vector(as.matrix(res_layer3[idx[i],-1])),ncol=64,nrow=32,byrow=T),2,rev)),col=grey(seq(0,1,length.out=256)))
+ }

f:id:TJO:20150121165347p:plain

訳分からんorz これ、よくよく考えたら「分類モデル側のカラムの並びが学習データ側のカラムの並びと一致するとは限らない」ので、本当は並べ替えなきゃいけないんですよね。。。同様に「3」「9」でやってみるとこうなります。

f:id:TJO:20150121165456p:plain

f:id:TJO:20150121165503p:plain

やっぱり見ていてもよく分からないorz 教えて、えらい人!

*1:そもそも同一H2Oインスタンスでないとただのsummary関数を走らせることすらできない

*2:Kaggleコンペサイトのleaderboard、いつの間にかクリーニングされてたことに気付いた