LoginSignup
22
36

More than 5 years have passed since last update.

Tensorflowでブロック崩し

Last updated at Posted at 2017-01-28

概要

機械学習のモデルをゲームに組み込むと、結果をグラフィカルにみることができて楽しい。そこで、Tensorflowでモデルを作成してゲームに組み込む。具体的には、Tensorflowで人の手によるプレイデータを用いてモデルを作成してブロック崩しをさせる。
洗練されたモデルなどにはこだわらず、てきとーなものをてきとーに作る。
Tensorflowでの基本的なモデル作成は以下の記事で
適当にTensorflowを理解して、モデルを作ってみる(Tensorflow入門)
使用するブロック崩しは以下のリンク先のもの
ブロック崩し

動機

機械学習モデルに色々プレイさせる記事はよく見るが、実際に時間をかけずに適当に試してみたい。
精度や美しさを気にせずに、動く実感を得られるように動かすのが目的。

前提

今回使用するブロック崩しの概要は以下のようである。

* パドルを動かしてボールを弾いて行く
* マウスのx座標でパドルの座標を決定

つまり、ボールのy座標とパドルのy座標が一致する時に、それぞれのx座標が一致してさえいればボールを弾くことは可能となる。
そういう意味で、オートブロック崩しの作成は相当優しい。

データ作成

実際のプレイから、データを作成する。今回はてきとーに進めていくのが目的なので、説明変数と被説明変数のセットを細かくは考えない。
まずは、実際にプレイをするときに、画面の更新タイミングに合わせてパドルの座標とボールの座標を書き出し、各フレームに置けるボールのx座標、y座標を説明変数、パドルの位置を被説明変数とするデータを作成する。
これは、Ballクラスのmove関数、Paddleクラスのupdate関数内にそれぞれの座標を書き出す(保存する)処理を書いておけば良い。

モデルの作成

model.py
# ライブラリインポート
import tensorflow as tf
import pandas as pd

# データ読み込み
data_x = pd.read_csv('/somewhere/ball_movement_x.csv', header=None)
data_y = pd.read_csv('/somewhere/ball_movement_y.csv', header=None)
movement = pd.read_csv('/somewhere/mouse_movement.csv', header=None)

data = pd.DataFrame({'x_data': data_x.ix[:, 0],
                     'y_data': data_y.ix[:, 0]
                     })
teacher = pd.DataFrame({'teacher':movement.ix[:, 0]})

# モデル作成
# プレースホルダー設定
X = tf.placeholder(tf.float32, shape = [None, 2])
Y = tf.placeholder(tf.float32, shape = [None, 1])

# 変数設定
W = tf.Variable(tf.zeros([2,1]))

B = tf.Variable(tf.zeros([1]))

y_hypo = tf.matmul(X, W) + B

# 損失関数
cost = tf.reduce_mean(tf.square(y_hypo - Y))

# 勾配降下
train_step = tf.train.GradientDescentOptimizer(0.000001).minimize(cost)


with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for i in range(1000):
        sess.run(train_step, feed_dict={X:data, Y:teacher})
    parameter_W = sess.run(W)
    parameter_B = sess.run(B)

順に見ていく

model.py
# モデル作成
# プレースホルダー設定
X = tf.placeholder(tf.float32, shape = [None, 2])
Y = tf.placeholder(tf.float32, shape = [None, 1])

# 変数設定
W = tf.Variable(tf.zeros([2,1]))
B = tf.Variable(tf.zeros([1]))

y_hypo = tf.matmul(X, W) + B

プレースホルダーには学習フェーズで、実データが代入され、変数がパラメーターとして学習の中で決められる。
y_hypoはデータとパラメーターによってパドルの座標を予測するためのモデルとなる。

optimize.py
# 損失関数
cost = tf.reduce_mean(tf.square(y_hypo - Y))

# 勾配降下
train_step = tf.train.GradientDescentOptimizer(0.000001).minimize(cost)


with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for i in range(1000):
        sess.run(train_step, feed_dict={X:data, Y:teacher})
    parameter_W = sess.run(W)
    parameter_B = sess.run(B)

実際に学習を行い、パラメーターを探索させる。
parameter_Wとparameter_Bが求めたパラメーターとなり、Xを入力データ(ボールのx座標とy座標)とし、tf.matmul(X, parameter_W) + parameter_Bの値がパドルの予測座標となる。

実行

main関数のwhile内でボールの座標を取得し、それを上のモデルに入れ、その予測値をパドルの座標にする。
情報のアップデートが行われる度に予測が行われているので非常に重たいが、とりあえず以下のように動作。

ezgif.com-resize.gif

感想

今回の目的はてきとーにゲームにモデルを組み込んで動作させることだったが、それはうまくいった。
実際には、どのようなデータを使用するかや、どのようにより洗練された動きをさせるかなどを気にしながら進めることになる。
例えば、今回のブロック崩しの場合は、一定のところまでブロックがなくなると、パドルとボールの動きが定まってしまい、ブロックのない空間をずっと行き来するようになった。加えて、フレームの更新の度に予測を行うのは非効率で、ボールの動きも非常に遅くなった。

22
36
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
36