何となくTFのお作法が分かってきたのでどんどん先に行きます。そう言えばただの備忘録なので何一つ出典とか参考文献とか書いてませんが、このシリーズでやっていることの理論的基礎は深層学習青本がほぼ全てカバーしています。
- 作者: 岡谷貴之
- 出版社/メーカー: 講談社
- 発売日: 2015/04/08
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (13件) を見る
というか、僕はこれ以上の理論的な知識を持ち合わせません。。。閑話休題、今度は3層NNで誤差逆伝播をやってみようと思います。と言っても、下のコードを見ての通りで非常に簡単です。
TensorFlowでやってみる
今回はUCI ML repositoryのWine Qualityデータセットの赤ワインの方を、適当にtrain / testに分けたやつを使います。いつも通りGitHubに置いてあります。
本来なら順序ロジットでモデリングするべきなんですが、面倒なのでただの名義尺度化させて多項分類になるようにしています。そしてコードを見れば分かりますが、TFだと逆伝播なんてわざわざ意識しなくてもグラフ構造に応じて勝手にオプティマイザの方で逆伝播しちゃうんですよね。。。あまり醍醐味がないようで。
import tensorflow as tf import numpy as np import pandas as pd from sklearn.preprocessing import StandardScaler from sklearn.metrics import confusion_matrix from sklearn.metrics import accuracy_score d_train = pd.read_csv("wine_red_train.csv", sep=',') d_test = pd.read_csv("wine_red_test.csv", sep=',') train_X = d_train.iloc[:, 0:11] train_Y = d_train[[11]] test_X = d_test.iloc[:, 0:11] test_Y = d_test[[11]] scaler = StandardScaler() train_X.iloc[:, 0:11] = scaler.fit_transform(train_X) test_X.iloc[:, 0:11] = scaler.fit_transform(test_X) x = tf.placeholder(tf.float32, [None, 11]) W1 = tf.Variable(tf.random_normal([11,9], mean=0.0, stddev=0.5)) b1 = tf.Variable(tf.random_normal([9], mean=0.0, stddev=0.1)) y1 = tf.matmul(x, W1) + b1 tf.get_variable_scope().reuse_variables() W2 = tf.Variable(tf.random_normal([9,6], mean=0.0, stddev=0.5)) b2 = tf.Variable(tf.random_normal([6], mean=0.0, stddev=0.1)) y2 = tf.nn.softmax(tf.matmul(y1, W2) + b2) tf.get_variable_scope().reuse_variables() y = tf.placeholder(tf.int64, [None, 1]) y_ = tf.one_hot(indices = y, depth = 6) # tf.train.exponential_decayでmomentumっぽいことができるらしい global_step = tf.Variable(0, trainable=False) starter_learning_rate = 0.0001 learning_rate = tf.train.exponential_decay(starter_learning_rate, global_step, 10000, 0.9, staircase=True) tf.get_variable_scope().reuse_variables() cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels = y_, logits = y2)) optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost) sess = tf.Session() init = tf.initialize_all_variables() sess.run(init) num_epochs = 500 for i in range(num_epochs): sess.run(optimizer, feed_dict = {x:train_X, y:train_Y}) pred = sess.run(y2, feed_dict = {x: test_X}) pred = pred.round(0) pred_d = tf.argmax(pred,1) print confusion_matrix(test_Y-3, sess.run(pred_d)), accuracy_score(test_Y-3, sess.run(pred_d)) [[ 0 0 1 0 0 0] [ 2 1 1 1 0 0] [15 7 15 12 0 19] [20 1 9 22 1 11] [ 7 1 3 6 2 1] [ 2 0 0 0 0 0]] 0.25
全然ダメじゃんorz ACC 0.25という惨憺たる有様になりました。
Rでやってみる
一応、{nnet}パッケージでそれっぽいことをやることができます。
> d_train <- read.csv('wine_red_train.csv') > d_test <- read.csv('wine_red_test.csv') > d_train$quality <- as.factor(d_train$quality) > library(nnet) > d_train.nnet <- nnet(quality~., d_train, size=9, decay=1e-7, maxit=500) # weights: 168 initial value 2319.968381 iter 10 value 1671.868126 iter 20 value 1600.442989 iter 30 value 1495.903826 iter 40 value 1391.839381 iter 50 value 1359.748150 iter 60 value 1350.807539 iter 70 value 1347.931243 iter 80 value 1347.464786 iter 90 value 1346.661153 iter 100 value 1346.511094 iter 110 value 1346.359111 iter 120 value 1346.158824 iter 130 value 1345.423738 iter 140 value 1345.298538 iter 150 value 1345.281488 iter 160 value 1345.151790 iter 170 value 1344.751637 iter 180 value 1344.743908 iter 190 value 1344.737232 iter 200 value 1344.735879 iter 210 value 1344.731908 final value 1344.731263 converged > table(d_test$quality, predict(d_train.nnet, newdata=d_test[,-12], type='class')) 5 6 7 3 1 0 0 4 3 2 0 5 50 18 0 6 21 39 4 7 1 13 6 8 0 2 0 > (50+39+6)/nrow(d_test) [1] 0.59375
RでやってもACC 0.59ぐらいとか結構ダメな感じですねorz 何か納得がいかないので、{randomForest}でやり直してみました。
> library(randomForest) > tuneRF(d_train[,-12], d_train[,12], doBest=T) mtry = 3 OOB error = 31.55% Searching left ... mtry = 2 OOB error = 30.44% 0.03524229 0.05 Searching right ... mtry = 6 OOB error = 32.38% -0.02643172 0.05 Call: randomForest(x = x, y = y, mtry = res[which.min(res[, 2]), 1]) Type of random forest: classification Number of trees: 500 No. of variables tried at each split: 2 OOB estimate of error rate: 29.67% Confusion matrix: 3 4 5 6 7 8 class.error 3 0 1 7 1 0 0 1.0000000 4 1 0 28 18 1 0 1.0000000 5 0 1 500 109 3 0 0.1843393 6 0 1 122 421 30 0 0.2665505 7 0 0 7 83 89 0 0.5027933 8 0 0 0 10 4 2 0.8750000 > d_train.rf <- randomForest(quality~., d_train, mtry=2) > table(d_test$quality, predict(d_train.rf, newdata=d_test[,-12])) 3 4 5 6 7 8 3 0 0 1 0 0 0 4 0 0 4 1 0 0 5 0 0 55 13 0 0 6 0 0 13 48 3 0 7 0 0 2 5 13 0 8 0 0 0 0 2 0 > (55+48+13)/nrow(d_test) [1] 0.725
ACC 0.725ということで、前にやった時と似たような結果になりました。
ということでせめてこれぐらいのACCは出したいものですが。。。どなたか詳しい方ご教授くださいm(_ _)m
追記1
いつもながら@stakemuraさんからAzure NotebookにTFコードを載せたもの*1を頂戴したんですが、何故かL2正則化項がきちんと走らず。。。
どうも僕の手元の環境では頂戴したコード通りに書くと、最後のトレーニングのところでテンソル形状が合わずにエラーになるようです(with句を外して分かった)。とりあえず最後の.round(0)は確かにtf.argmaxするなら要らないはずということで、そこを削除した上で幾つか学習パラメータを変更してやり直してみました。
import tensorflow as tf import numpy as np import pandas as pd from sklearn.preprocessing import StandardScaler from sklearn.metrics import confusion_matrix from sklearn.metrics import accuracy_score d_train = pd.read_csv("wine_red_train.csv", sep=',') d_test = pd.read_csv("wine_red_test.csv", sep=',') train_X = d_train.iloc[:, 0:11] train_Y = d_train[[11]] - 3 test_X = d_test.iloc[:, 0:11] test_Y = d_test[[11]] - 3 # ここで先にラベルを-3しておく scaler = StandardScaler() train_X.iloc[:, 0:11] = scaler.fit_transform(train_X) test_X.iloc[:, 0:11] = scaler.fit_transform(test_X) x = tf.placeholder(tf.float32, [None, 11]) W1 = tf.Variable(tf.random_normal([11,9], mean=0.0, stddev=0.5)) b1 = tf.Variable(tf.random_normal([9], mean=0.0, stddev=0.1)) y1 = tf.matmul(x, W1) + b1 tf.get_variable_scope().reuse_variables() W2 = tf.Variable(tf.random_normal([9,6], mean=0.0, stddev=0.5)) b2 = tf.Variable(tf.random_normal([6], mean=0.0, stddev=0.1)) y2 = tf.nn.softmax(tf.matmul(y1, W2) + b2) tf.get_variable_scope().reuse_variables() y = tf.placeholder(tf.int64, [None, 1]) y_ = tf.one_hot(indices = y, depth = 6) global_step = tf.Variable(0, trainable=False) starter_learning_rate = 0.3 learning_rate = tf.train.exponential_decay(starter_learning_rate, global_step, 1000, 0.95, staircase=True) tf.get_variable_scope().reuse_variables() cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels = y_, logits = y2)) optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost) sess = tf.Session() init = tf.initialize_all_variables() sess.run(init) num_epochs = 1000 for i in range(num_epochs): sess.run(optimizer, feed_dict = {x:train_X, y:train_Y}) pred = sess.run(y2, feed_dict = {x: test_X}) # pred = pred.round(0) # これが不要 pred_d = tf.argmax(pred,1) print confusion_matrix(test_Y, sess.run(pred_d)), accuracy_score(test_Y, sess.run(pred_d)) [[ 0 0 1 0 0 0] [ 0 0 4 1 0 0] [ 0 0 48 20 0 0] [ 0 0 14 48 2 0] [ 0 0 1 16 3 0] [ 0 0 0 2 0 0]] 0.61875
初期値次第な気もしますがACC 0.62近くまではいくことが分かりました。
*1:これは自分の中では複数のツボにハマってるんですが笑