Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
48
Help us understand the problem. What is going on with this article?
@nyancook

サルでもわかるtensorflow:基本的な変数の扱い方

More than 1 year has passed since last update.

ディープラーニングのフレームワークの中で、世界で一番使われているtensorflowの使い方を調べてみました。

見ているだけで基本的な使い方が頭に入ってくるものを目指して、できるだけ細かく(冗長に?)コードを書いているので、初めてtensorflowを使う人向けになればいいな、と願っております。

動機

今まで機会があるごとにchainerやkerasを触ってきたのですが、

kerasに頼らずtensorflow使いたい...!

ということでネット上の転がってる記事を参考に勉強を始めました。


ちなみにtensorflowを使おうと思ったきっかけは主に2つです。

・遺伝アルゴリズムを使ってネットワークを進化させてみたい!(とある教授の実験を再現したい)
日本語記事の豊富なchainerばっかり使ってると「いかにも日本人らしい」ってなりそう...

tensorflowのとっつきにくさ

まずtensorflowがとっかかりづらい(実は嬉しさでもある)のは、

計算グラフ(フロー)を作成 → 計算を実行

という手順を踏まないといけない部分です。
普通のpythonコードだと

a = 10
b = a + 10
c = b + 10

の各行を実行すると、
aに値が入る → bに値が入る → cに値が入る
ってなりますよね。

じゃあtensorflowだとどうなの、について見ていきましょう。

基本的な計算

まずインポートは以下のように。


import numpy as np
import tensorflow as tf

定数

以下を実行してみてください。

const = tf.constant(10)  # 定数を定義

with tf.Session() as sess:
    result_const = sess.run(const)
    print(result_const)  # 10がプリントされる

定数を定義している箇所は

const = tf.constant(10)

ですが、ここではまだ
「constに定数オブジェクトを割り当てる」
という「グラフ」を定義しただけなので、constに10という値は代入されません。

sess.run(const)

で初めて値の代入・計算が実行されます。
返り値はconstの値です。

今の例だとやっていることが単純すぎて逆によくわからないかもしれないので、足し算をしてみましょう。

const_1 = tf.constant(10)
const_2 = tf.constant(30)
added = const_1 + const_2

with tf.Session() as sess:
    result = sess.run(added)
    print(result)  # 10+30の結果である40がプリントされる

最初の3行で
(const_1, const_2) → added
という計算グラフを作成しています。

そして、

sess.run(added)

の返り値は"added"の値そのものになります。

注目すべきは、

sess.run(added)

を実行すると、addedに繋がるまでの2つの計算グラフ、すなわち
「const_1に値を代入」「const_2に値を代入」の両方が自動で実行されることです。
つまり、以下のような書き方をする必要はないということです。


const_1 = tf.constant(10)
const_2 = tf.constant(30)

with tf.Session() as sess:
    result_const_1 = sess.run(const_1)
    result_const_2 = sess.run(const_2)
    result = result_const_1 + result_const_2
    print(result)

ただし、const_1とconst_2の値を別の計算グラフで計算したい時には、上のような書き方をする必要があるでしょう。

変数

変数は"tf.Variable( )"で定義しますが、定数の時と同じように実行すると怒られます。
これ、知らないとちょっと焦ります


val = tf.Variable(10)  # 変数を定義

with tf.Session() as sess:
    result = sess.run(val)
    print(result)

tf.Variable( )を使う場合は、初期化してあげる必要があるそうです。

val = tf.Variable(10)  # 変数を定義

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())  # ここが必要!
    result = sess.run(val)
    print(result)

プレースホルダー

「実行するまで値がわからない」変数を扱う時の格納庫的な役割をしてくれます。
tf.constantやtf.Variableと違って、データの型を指定する必要があります。


holder = tf.placeholder(dtype=tf.float32)  # 今はまだ値がわからない
const = tf.constant(10, dtype=tf.float32)
added = holder + const

with tf.Session() as sess:
    the_value = 40  # この時点で初めて値がわかった!
    result = sess.run(added, feed_dict={holder:the_value})  # holderにthe_valueの値を代入してaddedを計算
    print(result)

"sess.run( )"時に辞書の形で実際の値を代入してあげます。

注意点

今まで触れませんでしたが、同じデータ型同士でないと計算ができないので、今のように型を明示的に書くことを心がける必要がありそうです。

代入

pythonでの

var = 100

def main():
    return var + 1

for i in range(3):
    var = main()
    print(var)

のように、変数の値をどんどんアップデートする処理をtensorflowで実現したいのですが、Sessionの中で

tf_variable = 101  # tf_variable : tf.Variableオブジェクト

のように値を代入することはできません。
値の代入には


tf.assign("アップデートする変数", "代入する値")

を使います。

var = tf.Variable(100, dtype=tf.int32)  # この変数をアップデートしていく

holder = tf.placeholder(dtype=tf.int32)  # アップデートする値を代入する用
update = tf.assign(var, holder)  # 値をアップデートする処理

def main():
    return var + 1

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())  # 変数を初期化
    for i in range(3):
        result = sess.run(main())  # 1を加えた値を取得
        sess.run(update, feed_dict={holder:result})  # update関数を使って、varの値をresultの値にアップデート
        print(result)  # 101 102 103 の順番でプリントされる

以上を踏まえて

一般的な書き方?

普通は関数などを定義してコードをわかりやすくするので、足し算なら以下のような書き方になるのではないでしょうか。

def main():
    x = tf.constant(10)
    y = tf.constant(30)
    return x + y

with tf.Session() as sess:
    result = sess.run(main())
    print(result)  # 40

はたまた

def add():
    x = tf.constant(10)
    y = tf.constant(30)
    return x + y

z = add() + tf.constant(100)


with tf.Session() as sess:
    result = sess.run(z)
    print(result)  # 140

最後のコードの計算グラフをtensorboardを使って可視化するとこうなりました。

スクリーンショット 2018-05-26 2.25.02.png

ちゃんと1つの計算グラフになっていますね!


ただし、気をつけなければいけないのは、以下を実行すると怒られることです。

def main():
    val_1 = tf.Variable(10, dtype=tf.float32)
    val_2 = tf.Variable(20, dtype=tf.float32)
    return val_1 * val_2

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())  # 変数を初期化
    result = sess.run(main())  # ここで怒られる!

何が問題かというと、main( )を定義しただけではval_1, val_2が定義されたことにならないので、変数を初期化してるつもりができていないことです。

なので、変数はできるだけ関数の外で定義してあげると混乱しにくいと思います。

配列

numpyの配列と同じように計算できます。


def mul(x, y):
    return x * y

val_1 = tf.Variable([10, 20], dtype=tf.float32)
val_2 = tf.Variable([30, 40], dtype=tf.float32)

result = mul(val_1, val_2)


with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())  # 変数を初期化
    result = sess.run(result)
    print(result)  # [ 300.  800.]

最後に

とりあえず今回は以上で。
次は全結合層をメインにしたネットワーク作って、遺伝アルゴリズムで進化させてみたいと思います。

誤差逆伝播使わないとtensorflowが泣く?
そんなことは知ったこっちゃありません。

48
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
nyancook

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
48
Help us understand the problem. What is going on with this article?