今回は、Tensor(テンソル)を利用できるように宣言して、初期化したり、値を変更したりする3つの方法、定数と変数とプレースホルダーを整理してみます。
Tensor(テンソル)については、前回の記事で整理していますので、初回の方はこちらを先に読んでから、すすめることをおすすめします。
Tensor(テンソル)はとても汎用的なので、それをスカラ型として使うのか、一次配列として使うのか、それとも行列として使うのか・・など、どのデータ型として使っているのかまで意識しておかないといけません。
その辺も意識して整理しようと思います。
定数
Tensor(テンソル)を初期化する際に、初期化でセットする値と、ShapeとTypeを指定すれば良いみたいです。
ShapeとTypeを指定する初期化の例です。値1.5で初期化します。
import tensorflow as tf
# Rank:0 スカラー型定数の初期化(無指定)
c01 = tf.constant(1.5)
# Rank:1 配列型定数の初期化
c02 = tf.constant(1.5,shape=[10],dtype=tf.float32)
# Rank:2 行列型定数の初期化
c03 = tf.constant(1.5,shape=[5,10],dtype=tf.float32)
# Rank:3 3D定数の初期化
c04 = tf.constant(1.5,shape=[3,5,10],dtype=tf.float32)
初期化したあとで表示させてみた結果です。
Rank:0 スカラの定数
Rank:1 配列の定数
Rank:2 行列の定数
Rank:3 3Dの定数
Shapeを指定しないで、ダイレクトに任意の値を指定する初期化ももちろんできます。
このケースだと、自動的に与えた初期値と同じshapeになります。
その例です。
import tensorflow as tf
# Rank:1 配列
c02a = tf.constant([1.5,2.0])# Rank:2 行列
c03a = tf.constant([[1.5,2.0],[2.5,3.0]])
初期化後に表示させてみた結果です。
Rank:1配列です。
Rank:2行列です。
あと、ランダムな値を自動生成して初期化する方法もあります。これは行列の場合だけ例でやってみます。
c03r = tf.random_uniform(shape=[5,10],minval=-2.0,maxval=2.0,dtype=tf.float32)
これで、-2.0 から 2.0の区間で、一様分布の乱数を生成して、行列データを初期化してくれます。
ただ、このケースは、tf.constant()と組み合わせて書くと、「TypeError: List of Tensors when single Tensor expected」がでて、動きませんでした。
そう書いたサンプルもネットにはあったので、環境のせいかもしれないですが、とりあえず、tf.constantをはずして書いてます。
まあ、定数については、この位のやり方を理解しとけば、いいかなと思ってます。
変数
変数を使うには、3つのお約束事があります。
- variable() で変数を宣言・初期化する。
- assign() で変数の値を変更する。
- 変数を使う前に必ずglobal_variables_initializer() を実行する。
補足すると、3番目の「global_variables_initializer()」は、Session(セッション)毎に実行する必要があります。
これを実行した後でないと、変数を使って何かしようとするとエラーになってしまいます。
これは、たぶん実際にやってみた方が、言葉よりだいぶわかりやすいので、そうしてみます。
import tensorflow as tf
# Rank:0 スカラー型定数を、0で初期化する
c01 = tf.Variable(0,dtype=tf.float32)# 値を1.5に変更する
c01a = tf.assign(c01,1.5)
# Rank:1 配列を、すべて0で初期化する
c02 = tf.Variable(tf.zeros([10],dtype=tf.float32))# 指定の値に配列の中身を書き換える
c02a = tf.assign(c02,[1.0,1.5,2.0,2.5,3.0,1.0,1.5,2.0,2.5,3.0])
# Rank:2 行列を、すべて0で初期化する
c03 = tf.Variable(tf.zeros([5,10],dtype=tf.float32))# 行列をすべて、1で書き換える
c03a = tf.assign(c03,tf.ones([5,10],dtype=tf.float32))
# Rank:3 3D構造を、すべて0で初期化する
c04 = tf.Variable(tf.zeros([3,5,10],dtype=tf.float32))with tf.Session() as s:
# 変数を利用可能なように領域を初期化する
s.run(tf.global_variables_initializer())
print(s.run(c01))
print("\n")#以下同じようにprintが続くので引用省略
Rank:0 スカラの初期化時と変更後です。
Rank:1 配列の初期化時と変更後です。
Rank:2 行列の初期化時と変更後です。
変数はこんなもんで。
プレースホルダー
定数と変数だけだと、スカラ型はともかく、配列とか行列とかの大きさがわからない場合には使えないことはすぐわかります。
宣言して初期化するときに、サイズをきっちり指定しないとエラーになりますからね。
ところが、プログラムでは例えばデータベースやファイルからデータを読み込んだ時みたいに、データが何件あるのか事前には予測できないし、条件によって異なるというケースが普通に登場します。
これをどうするのか?ってやつですね。
tensorflowでは、それを、とりあえず空のTensor(テンソル)だけ用意しておいて、実行時に値をセットする方法で対応するみたいです。
それが、プレースホルダーです。
プレースホルダーを使うときの約束事です。
- placeholder() で宣言をする。初期化の必要はない。
- 動的にサイズが変わる部分は、Noneで指定する。
- 値は実行時に、feed_dict={ホルダ名:値}の形で与える。
試しにやってみます。
import tensorflow as tf
# shapeを指定しないプレースホルダ宣言
c01 = tf.placeholder(dtype=tf.float32)
# 配列で大きさは動的に決まるプレースホルダ宣言
c02 = tf.placeholder(dtype=tf.float32,shape=[None])
# 行列で大きさが動的に決まるプレースホルダの宣言
c03 = tf.placeholder(dtype=tf.float32,shape=[None,2])
# ここからは実行部です
with tf.Session() as s:# 単一の値だけを与える場合
print(s.run(c01,feed_dict={c01:1.0}))
# 配列の値を与える場合
print(s.run(c02,feed_dict={c02:[1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0]}))
# 行列の値を与える場合
print(s.run(c03,feed_dict={c03:[[1.0,1.0],[2.0,3.0],[4.0,5.0],[6.0,7.0],[8.0,9.0]]}))
結果はこんな感じです。
上記例では、配列、行列とshapeを指定してplaceholder(プレースホルダー)を宣言しました。
でも、実は、placeholderは、デフォルトで「shape=None」になっていて、サイズだけでなく、shapeそのものも動的に決まるみたいになってます。
そのため、最後の行列の値を実行時に与えるパターンでも、shape=Noneのデフォルトでいけたりもします。
サンプルとしてはこんな感じです。
c01 = tf.placeholder(dtype=tf.float32)
with tf.Session() as s:
print(s.run(c01,feed_dict={c01:[[1.0,1.0],[2.0,3.0],[4.0,5.0],[6.0,7.0],[8.0,9.0]]}))
結果は同じです。
とりあえず、定数・変数・プレースホルダの整理はこんなものかな。
2017/12/09追記
いちおう、tensorflow v1.4で動作確認してます。
2017/02/12追記
tensorflow v1.5で動作確認してます。
tensorflowの入門の入門カテゴリの記事一覧はこちらです。