回帰問題で TensorFlow を使いたかったので自分用にメモを残しておきます。
ちなみに 分類問題での TensorFlow の使い方は, 公式のtutorials が充実しています。
環境構築
環境は OSX 10.11.3, CPU 1.3 GHz Intel Core i5, メモリ 4 GB DDR3 で, tensorflow をインストールする。
$ sudo pip install --upgrade virtualenv
$ virtualenv --system-site-packages ~/tensorflow
$ source ~/tensorflow/bin/activate
$ pip install --upgrade tensorflow
# $ pip install --upgrade tensorflow-gpu
TensorFlow
改めて書く必要はないかもしれないが, TensorFlowは多次元配列 [1] を扱うデータフロー演算のFW。
TensorFlowの Graph を構築する際, 下記のように分類してデザインすると見通しがよくなるとの事 [2] なので, 今回はそれに従う。
- inference : 予測モデルを記述する
- loss : 予測モデルの結果と正解から誤差を計算する損失関数を記述する
- training : 損失関数で得た誤差を用いて学習を行うための Optimizer の指定や学習率を記述する
Linear regression
2つのデータセットを例に, TensorFlowで線形回帰モデルを作る。
artificial-data
イントロダクションとしての線形回帰 [3] を参考に, 人工データ (synthetic data) に対して線形モデルを作ってみる。
生成するデータは下記で, 真のパラメータは回帰係数を 2, 切片を 3 とする。
train_x = np.linspace(-1, 1, N)
err = np.random.randn(*train_x.shape) * 0.5
train_y = 2 * train_x + 3 + err
Graph部分は下記。
# 推論
def inference(w, b):
lm = x * w + b
return lm
# 損失関数
def loss(lm, y):
return tf.reduce_mean(tf.square(lm - y))
# 学習
def training(loss, rate):
return tf.train.AdagradOptimizer(rate).minimize(loss)
tf.Session() as sess で記述した処理の管理を行い, sess.run()で実際に実行する。step=1000 の結果が下記。
step : 0, w : [ 0.97288424], b: [ 0.99864316]
step : 100, w : [ 1.95609689], b: [ 3.03214002]
step : 200, w : [ 1.95609689], b: [ 3.03214002]
step : 300, w : [ 1.95609689], b: [ 3.03214002]
step : 400, w : [ 1.95609689], b: [ 3.03214002]
step : 500, w : [ 1.95609689], b: [ 3.03214002]
step : 600, w : [ 1.95609689], b: [ 3.03214002]
step : 700, w : [ 1.95609689], b: [ 3.03214002]
step : 800, w : [ 1.95609689], b: [ 3.03214002]
step : 900, w : [ 1.95609689], b: [ 3.03214002]
step : 1000, w : [ 1.95609689], b: [ 3.03214002]
airquality
続いて, 回帰問題で取り上げられることのある airquality データセットで, Ozone を目的変数とした線形モデルをTensorFlowで作る。
Ozone Solar.R Wind Temp Month Day
1 41 190 7.4 67 5 1
2 36 118 8.0 72 5 2
3 12 149 12.6 74 5 3
4 18 313 11.5 62 5 4
7 23 299 8.6 65 5 7
8 19 99 13.8 59 5 8
Graph部分は下記。
# 推論
def inference(w, b):
lm = tf.matmul(x, w) + b
return lm
# 損失関数
def loss(lm, y):
return tf.reduce_mean(tf.square(lm - y))
# 学習
def training(loss, rate):
return tf.train.AdagradOptimizer(rate).minimize(loss)
step=30000 の時のパラメータは下記となった。
step : 30000, loss : 417.871124268, cor : 0.787142288512, w : [[ 0.05068821]
[-3.86576462]
[ 1.62008727]
[-3.28687215]
[ 0.21118863]], b: [-34.3141861]
R の stats::lm で同様のモデルを作りパラメータを比較してみると, 切片以外はそこそこ近い。
d <- airquality
model <- lm(Ozone ~ ., data=d)
summary(model)
# Coefficients:
# Estimate Std. Error t value Pr(>|t|)
# (Intercept) -64.11632 23.48249 -2.730 0.00742 **
# Solar.R 0.05027 0.02342 2.147 0.03411 *
# Wind -3.31844 0.64451 -5.149 1.23e-06 ***
# Temp 1.89579 0.27389 6.922 3.66e-10 ***
# Month -3.03996 1.51346 -2.009 0.04714 *
# Day 0.27388 0.22967 1.192 0.23576
# ---
# Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
#
# Residual standard error: 20.86 on 105 degrees of freedom
# (42 observations deleted due to missingness)
# Multiple R-squared: 0.6249, Adjusted R-squared: 0.6071
# F-statistic: 34.99 on 5 and 105 DF, p-value: < 2.2e-16
Logistic regression
MNIST データセットを使ったロジスティック回帰の例。
# 推論
def inference(x, w):
return tf.matmul(x, w)
# 損失関数
def loss(model, y):
return tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(model, y))
# 学習
def training(loss, rate):
return tf.train.GradientDescentOptimizer(rate).minimize(loss)
テスト時の予測用に predict_op を追加した。
model = inference(x, w)
loss_value = loss(model, y)
train_op = training(loss_value, 0.03)
predict_op = tf.argmax(model, 1)
結果が下記。
step : 0, test prob : 0.8749
step : 1, test prob : 0.8882
step : 2, test prob : 0.8958
step : 3, test prob : 0.9001
step : 4, test prob : 0.9037
step : 5, test prob : 0.9068
step : 6, test prob : 0.9084
step : 7, test prob : 0.9104
step : 8, test prob : 0.9108
step : 9, test prob : 0.9117
NN regression
最後に Diabetes データセットを使った NN (Neural Network) による回帰の例。
# 推論
def inference(x, p_keep_in, p_keep_hidden):
n = [128, 256, 1]
with tf.name_scope('l1') as scope:
w_l1 = tf.Variable(tf.truncated_normal(
[10, n[0]], stddev=0.33), name="w_l1")
b_l1 = tf.Variable(tf.constant(
1.0, shape=[n[0]]), name="b_l1")
h_l1 = tf.nn.relu(tf.matmul(x, w_l1) + b_l1)
h_l1 = tf.nn.dropout(h_l1, p_keep_in)
with tf.name_scope('l2') as scope:
w_l2 = tf.Variable(tf.truncated_normal(
[n[0], n[1]], stddev=0.33), name="w_l2")
b_l2 = tf.Variable(tf.constant(
1.0, shape=[n[1]]), name="b_l2")
h_l2 = tf.nn.relu(tf.matmul(h_l1, w_l2) + b_l2)
h_l2 = tf.nn.dropout(h_l2, p_keep_in)
with tf.name_scope('l3') as scope:
w_l3 = tf.Variable(tf.truncated_normal(
[n[1], n[2]], stddev=0.33), name="w_l3")
b_l3 = tf.Variable(tf.constant(
1.0, shape=[n[2]]), name="b_l3")
output = tf.nn.relu(tf.matmul(h_l2, w_l3) + b_l3)
output = tf.nn.dropout(output, p_keep_hidden)
return output
# 損失関数
def loss(model, y):
return tf.reduce_mean(tf.square(model - y), name="loss")
# 学習
def training(loss, rate):
return tf.train.RMSPropOptimizer(rate, 0.9).minimize(loss)
BATCH_SIZE=10 step=300 で, テストデータに対する相関が 0.727 となった。
Code は GitHub に置いた。
[1] 1次元配列がベクトル, 2次元配列が行列, 多次元配列がテンソル。テンソルを扱うデータフロー演算のためのFWだからテンソルフローぽい。
[2] TensorFlow Mechanics 101
[3] 初めてのTensorFlow - イントロダクションとしての線形回帰
[4] TensorFlowでアニメゆるゆりの制作会社を識別する
[5] TensorFlow研究会が開催されました!!
[6] TensorFlow White Paperを読む
[7] Distributed TensorFlowの話