ひゃまだのblog

ひゃまだ(id:hymd3a)の趣味のブログ

Tensorflow で回帰分析

(2018-02-19 初稿 - 2021-05-21 転記・修正)

はじめに

Raspberry Pi 3(以下、ラズパイ)を購入してから、python や tensorflow を使って、ディープラーニングのことを学んでいる。
ちなみに、筆者は、ディープラーニングのことも、pythonのことも、まったくの素人なので、以下の記述は参考までに。

なお、tensorflowのラズパイへのインストールは以下のページを参照のこと。

さて、tensorflowをgoogleから頂いて来て、MNIST dataでmnist_softmax.pyを実行して、文字認識のテストをしたまでは良かったが、実際何をやっているのか筆者にはまったく理解できなかった。とほほ。(^_^;)

まずは、理解しやすい内容を実行しようと思い、回帰分析を実行してみた。

このページでは、tensorflowを用いた回帰分析について記述する。

なお、このページを記述するにあたり、以下のサイトを参照させていただいた。多謝

1次回帰

まずは、上記サイトの1次回帰のスクリプトを実行してみる。

# coding:utf-8

import tensorflow as tf

# y = 2x + 1
input_x = [[0.],[1.]]
input_y = [[1.],[3.]]

x = tf.placeholder("float", [None, 1])
y_ = tf.placeholder("float", [None, 1])

a = tf.Variable([1.], name="slope")        # 初期値 a = 1
b = tf.Variable([0.], name="y-intercept")  # 初期値 b = 0
y = tf.multiply(a,x) + b

init = tf.global_variables_initializer()

# 誤差関数
loss = tf.reduce_sum(tf.square(y_ - y))

# トレーニング方法は、勾配降下法を選択
train_step = tf.train.GradientDescentOptimizer(0.03).minimize(loss)

with tf.Session() as sess:
        sess.run(init)
        print("初期状態")
        print('誤差' + str(sess.run(loss, feed_dict={x: input_x, y_: input_y})))
        print("slope: %f, y-intercept: %f" % (sess.run(a), sess.run(b)))

        for step in range(200):
            sess.run(train_step, feed_dict={x: input_x, y_: input_y})
            if (step+1) % 20 == 0:
                print('\nStep: %s' % (step+1))
                print('誤差' + str(sess.run(loss, feed_dict={x: input_x, y_: input_y})))
                print("slope: %f, y-intercept: %f" % (sess.run(a), sess.run(b)))

実行結果は以下のとおり。

(tflow) $ python 1kaiki.py 
初期状態
誤差5.0
slope: 1.000000, y-intercept: 0.000000

Step: 20
誤差0.02128378
slope: 1.802436, y-intercept: 1.069051

(中略)

Step: 200
誤差3.7843301e-06
slope: 1.997323, y-intercept: 1.001655

正解は、y=2x+1 の式だが、200回のステップで、正解の値までかなり近づくことがわかった。

2次回帰

1次回帰については、なんとかできるようになったので、2次回帰に挑戦してみる。前回のリストから、値の部分と、計算式の部分が異なるだけ。

【List 2-1】

# coding:utf-8

import tensorflow as tf

input_x = [[-1.],[0.],[2]]
input_y = [[3.],[1.],[9]]

x = tf.placeholder("float", [None, 1])
y_ = tf.placeholder("float", [None, 1])

a = tf.Variable([1.], name="slope")
b = tf.Variable([0.], name="y-intercept")
y = tf.multiply(a,x**2) + b                       # y = 2 x^2 + 1

init = tf.global_variables_initializer()

# 誤差関数
loss = tf.reduce_sum(tf.square(y_ - y))

# トレーニング方法は、勾配降下法を選択
train_step = tf.train.GradientDescentOptimizer(0.03).minimize(loss)

with tf.Session() as sess:
        sess.run(init)
        print("初期状態")
        print('誤差' + str(sess.run(loss, feed_dict={x: input_x, y_: input_y})))
        print("slope: %f, y-intercept: %f" % (sess.run(a), sess.run(b)))

        for step in range(200):
            sess.run(train_step, feed_dict={x: input_x, y_: input_y})
            if (step+1) % 20 == 0:
                print('\nStep: %s' % (step+1))
                print('誤差' + str(sess.run(loss, feed_dict={x: input_x, y_: input_y})))
                print("slope: %f, y-intercept: %f" % (sess.run(a), sess.run(b)))

実行結果は以下のとおり。

(tflow) @ ~/tflow$ python 2kaiki_list2-1.py 
初期状態
誤差30.0
slope: 1.000000, y-intercept: 0.000000

Step: 20
誤差0.017613236
slope: 2.034258, y-intercept: 0.893097

(中略)

Step: 160
誤差1.1404211e-12
slope: 2.000000, y-intercept: 1.000000

なんと、160ステップでほぼ正解に辿りついた。

もう少し実用的な回帰分析ができないと、tensorflowを使う意味がないね。

そこで、ネットで検索して、年と総農家個数の表を見つけたので、以下のとおりデータファイルを作成した。 毎回、データを打ち込むのって大変だからね。

# test data 年(年-1900/10)と総農家戸数(1/1000)
6.0,2.078
6.5,1.219
7.0,0.831
7.5,0.616
8.0,0.623
8.5,0.626
9.0,0.498
9.5,0.473

注意点としては、あまり大きな数字だと、nanとエラーが出るので、年については (年 - 1900)/10、総農家戸数は1/1000に値を小さくしている。

さっそく、データファイルから読み込むスクリプトを作成。

【List 2-2】

# coding:utf-8

import tensorflow as tf
import sys

args = sys.argv               # コマンドライン引数を取得

if len(args) == 1:            # 引数がなかったら
    fname = "./data.csv"      # data.csv を読む
else:                         # 引数があったら
    fname = args[1]           # ファイルを指定

input_x = []
input_y = []

f = open(fname)
for line in f.readlines():
    if line[0] == '#':         # データファイルのコメントスキップ
        continue
    line = line.split(',')     # カンマで分けて読み込む
    input_x.append([float(line[0])])
    input_y.append([float(line[1])])

x = tf.placeholder("float", [None, 1])
y_ = tf.placeholder("float", [None, 1])

a = tf.Variable([1.], name="slope")
b = tf.Variable([0.], name="y-intercept")
y = tf.multiply(a,1/tf.sqrt(x)) + b     # y = a / sqrt(x) + b に近い

init = tf.global_variables_initializer()

# 誤差関数
loss = tf.reduce_sum(tf.square(y_ - y))

# トレーニング方法は、勾配降下法を選択
train_step = tf.train.GradientDescentOptimizer(0.03).minimize(loss)

with tf.Session() as sess:
        sess.run(init)
        print("初期状態")
        print('誤差' + str(sess.run(loss, feed_dict={x: input_x, y_: input_y})))
        print("slope: %f, y-intercept: %f" % (sess.run(a), sess.run(b)))

        for step in range(400):
            sess.run(train_step, feed_dict={x: input_x, y_: input_y})
            if (step+1) % 20 == 0:
                print('\nStep: %s' % (step+1))
                print('誤差' + str(sess.run(loss, feed_dict={x: input_x, y_: input_y})))
                print("slope: %f, y-intercept: %f" % (sess.run(a), sess.run(b)))

実行結果は以下のとおり。

(tflow) @ ~/tflow$ python 2kaiki_list2-2.py 
初期状態
誤差3.94166
slope: 1.000000, y-intercept: 0.000000

Step: 20
誤差1.8281436
slope: 1.259537, y-intercept: 0.417840

(中略)
Step: 400
誤差1.5395262
slope: 2.963965, y-intercept: -0.199980

400ステップで、誤差は大分小さくなったが、y = a / sqrt(x) + b の式に適合しているかは、検定しないとわからないが、近いような気もする。(^_^;)

おわりに

今回は、2次回帰までのスクリプトを作ったが、本来ならばディープラーニングで、入力した式も自ら推定しながら解析して欲しいよね。
自ら解析しながら、式を作っていく方法については、以下に示すので参考に。^^;

また、何かわかったら、追記するね。

関連ページ