【Python】TensorFlowで回帰モデル

回帰問題で 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の話