本では Ubuntu Linux と MacOS のインストール方法が述べられているが、 自分は Windows を使うので conda 上の 「Deep Learning のための python + Visualization 環境」 のやり方でインストールした deep-graph または gpu-graph 環境を用いた。
公式の情報はこちら。
import tensorflow as tf
deep_learning = tf.constant("Deep Learning")
session = tf.Session()
r1 = session.run(deep_learning)
print(r1)
a = tf.constant(2)
b = tf.constant(3)
multiply = tf.multiply(a, b)
r2 = session.run(multiply)
print(r2)
TensorFlow の Variable とは、テンソルをメモリ上に格納したバッファのようなもの。 通常のテンソルは、グラフが実行されるときにインスタンス化され、実行が終わると直ちに破棄される。 Variable はテンソルであるが、複数回のグラフの実行にまたがってメモリ上に存在することができる。
tf.Variable を呼び出すと、次の3つの操作が計算グラフに追加される。
Variable を利用する際には tf.assign メソッドが実行されている必要がある。
# shape=[300, 200]
# the standard deviation of the normal distribution = 0.5
# trainable (default)
weights = tf.Variable(
tf.random_normal([300, 200], stddev=0.5),
name="weights"
)
# not trainable
weights = tf.Variable(
tf.random_normal([300, 200], stddev=0.5),
name="weights",
trainable=False
)
# How to initialize Variable
shape = [300, 200]
tf.zeros(shape, dtype=tf.float32, name=None)
tf.ones(shape, dtype=tf.float32, name=None)
tf.random_normal(
shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None
)
tf.truncated_normal(
shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None
)
tf.random_uniform(
shape, minval=0, maxval=None, dtype=tf.float32, seed=None, name=None
)
カテゴリー | 例 |
---|---|
要素ごとの算術演算 | Add, Sub, Mul, Div, Exp, Log, Greater, Less, Equal, ... |
配列の操作 | Concat, Slice, Split, Constant, Rank, Shape, Shuffle, ... |
行列の操作 | MatMul, MatrixInverse, MatrixDeterminant, ... |
内部状態を持った操作 | Variable, Assign, AssignAdd, ... |
NNのlayer | SoftMax, Sigmoid, ReLU, Convolution2D, MaxPool, ... |
チェックポイント | Save, Restore |
キューと同期 | Enqueue, Dequeue, MutexAcquire, MutexRelease, ... |
制御フロー | Merge, Switch, Enter, Leave, NextIteration |
Variable は一度しか初期化されない。それに対して、グラフの実行のたびに値が設定されるのが PlaceHolder である。Session.run(), Tensor.eval(), Operation.run() のオプションの feed_dict で値を与える。
x = tf.placeholder(tf.float32, name="x", shape=[None, 784])
W = tf.Variable(tf.random_uniform([784, 10], -1, 1), name="W")
multiply = tf.matmul(x, W)
session は初期状態の計算グラフを作成する役割を果たす。
# session.py
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("data", one_hot=True)
minibatch_x, minibatch_y = mnist.train.next_batch(32)
x = tf.placeholder(tf.float32, name="x", shape=[None, 784])
W = tf.Variable(tf.random_uniform([784, 10], -1, 1), name="W")
b = tf.Variable(tf.zeros([10]), name="biases")
output = tf.matmul(x, W) + b
init_op = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init_op)
feed_dict = {x : minibatch_x}
sess.run(output, feed_dict=feed_dict)
# scope1.py
import tensorflow as tf
def my_network(input):
W_1 = tf.Variable(tf.random_uniform([784, 100], -1, 1), name="W_1")
b_1 = tf.Variable(tf.zeros([100]), name="biases_1")
output_1 = tf.matmul(input, W_1) + b_1
W_2 = tf.Variable(tf.random_uniform([100, 50], -1, 1), name="W_2")
b_2 = tf.Variable(tf.zeros([50]), name="biases_2")
output_2 = tf.matmul(output_1, W_2) + b_2
W_3 = tf.Variable(tf.random_uniform([50, 10], -1, 1),name="W_3")
b_3 = tf.Variable(tf.zeros([10]), name="biases_3")
output_3 = tf.matmul(output_2, W_3) + b_3
# printing names
print("Printing names of weight parameters")
print(W_1.name, W_2.name, W_3.name)
print("Printing names of bias parameters")
print(b_1.name, b_2.name, b_3.name)
return output_3
i_1 = tf.placeholder(tf.float32, [1000, 784], name="i_1")
my_network(i_1)
i_2 = tf.placeholder(tf.float32, [1000, 784], name="i_2")
my_network(i_2)
scope1.py では、 my_network() を呼び出すたびに、異なる変数が用意されてしまうことがわかる。 たとえば "W_1" という変数は、最初の呼び出しでは W_1_1:0 , 2番目の呼び出しでは W_1_2:0 という別の変数になっていることがわかる。
以下に示す scope2.py では、関数を呼び出す度に同じ変数が使われる。
https://www.tensorflow.org/api_docs/python/tf/get_variable
https://www.tensorflow.org/api_docs/python/tf/variable_scope
# scope2.py
import tensorflow as tf
def layer(input, weight_shape, bias_shape):
weight_init = tf.random_uniform_initializer(minval=-1, maxval=1)
bias_init = tf.constant_initializer(value=0)
W = tf.get_variable("W", weight_shape, initializer=weight_init)
b = tf.get_variable("b", bias_shape, initializer=bias_init)
return tf.matmul(input, W) + b
def my_network(input):
with tf.variable_scope("layer_1"):
output_1 = layer(input, [784, 100], [100])
with tf.variable_scope("layer_2"):
output_2 = layer(output_1, [100, 50], [50])
with tf.variable_scope("layer_3"):
output_3 = layer(output_2, [50, 10], [10])
return output_3
i_1 = tf.placeholder(tf.float32, [1000, 784], name="i_1")
my_network(i_1)
i_2 = tf.placeholder(tf.float32, [1000, 784], name="i_2")
# my_network(i_2)
# ValueError: Over-sharing: Variable layer_1/W already exists...
tf.variable_scope() を宣言することで、Variableの名前は "layer_1/W" のように、名前空間がついたものになる。
tf.get_variable() は Variable が既にインスタンス化されているかどうかをチェックする。 デフォルトでは共有は無効化されているので、2度インスタンス化しようとするとエラーとなる。 共有を有効化するには、scope.reuse_variables() を呼び出す。
with tf.variable_scope("shared_variables") as scope:
i_1 = tf.placeholder(tf.float32, [1000, 784], name="i_1")
my_network(i_1)
scope.reuse_variables()
i_2 = tf.placeholder(tf.float32, [1000, 784], name="i_2")
my_network(i_2)
with tf.device() を用いて特定のデバイスを選択できる。 指定されたデバイスが利用できない場合はエラーとなる。 使えるデバイスを使って計算を進める場合は Session のオプションとして allow_soft_placement フラグを指定する。
値 | 説明 |
---|---|
cpu:0 | CPU を表す |
gpu:0 | 1つ目の GPU を表す |
gpu:1 | 2つ目の GPU を表す |
import tensorflow as tf
with tf.device("/gpu:2"):
a = tf.constant([1.0, 2.0, 3.0, 4.0], shape=[2, 2], name="a")
b = tf.constant([1.0, 2.0], shape=[2, 1], name="b")
c = tf.matmul(a, b)
sess = tf.Session(
config=tf.ConfigProto(
allow_soft_placement=True,
log_device_placement=True
)
)
ans = sess.run(c)
print(ans)
プログラムでは、 $$ \begin{pmatrix} 1 & 2 \\ 3 & 4 \\ \end{pmatrix} \begin{pmatrix} 1 \\ 2 \\ \end{pmatrix} = \begin{pmatrix} 1 \times 1 + 2 \times 2 \\ 3 \times 1 + 4 \times 2 \\ \end{pmatrix} = \begin{pmatrix} 1 \times 1 + 2 \times 2 \\ 3 \times 1 + 4 \times 2 \\ \end{pmatrix} = \begin{pmatrix} 5 \\ 11 \end{pmatrix} $$ を計算している。
# device.py
c = []
for d in ["/gpu:0", "/gpu:1"]:
with tf.device(d):
a = tf.constant([1.0, 2.0, 3.0, 4.0], shape=[2, 2], name="a")
b = tf.constant([1.0, 2.0], shape=[2, 1], name="b")
c.append(tf.matmul(a, b))
with tf.device("/cpu:0"):
sum = tf.add_n(c)
sess = tf.Session(
config=tf.ConfigProto(
allow_soft_placement=True,
log_device_placement=True
)
)
ans = sess.run(sum)
print(ans)
上の例では、同じ計算をしてできた行列 $ \begin{pmatrix} 5 \\ 11 \\ \end{pmatrix} $ を リストに append して $ c = \begin{pmatrix} \begin{pmatrix} 5 \\ 11 \\ \end{pmatrix} & \begin{pmatrix} 5 \\ 11 \\ \end{pmatrix} \end{pmatrix} $ となり、tf.add_n(c) を呼び出すので各要素が加算されて $ \begin{pmatrix} 10 \\ 22 \end{pmatrix} $ となる。
ロジスティック回帰 (logistic regression) は、入力をクラス分け (classify) する仕組みで、各クラスに属する確率が求まる。
$$ P(y=i|x) = softmax_i (Wx+b) = \frac{e^{W_i x + b_i}}{\sum_{j} e^{W_j x + b_j}} $$まず、隠れ層 (hidden layer) を持たないニューラルネットワークを考える。 (だんだん改良していく)
https://www.tensorflow.org/api_docs/python/tf/math/reduce_sum
https://www.tensorflow.org/api_docs/python/tf/nn/softmax
https://www.tensorflow.org/api_docs/python/tf/math/reduce_mean
https://www.tensorflow.org/api_docs/python/tf/train/GradientDescentOptimizer
https://www.tensorflow.org/api_docs/python/tf/summary
https://www.tensorflow.org/api_docs/python/tf/summary/histogram
https://www.tensorflow.org/api_docs/python/tf/train
# logistic_regression.py
import tensorflow as tf
import time, shutil, os
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("data", one_hot=True)
# Parameters
learning_rate = 0.01
training_epochs = 100
batch_size = 100
display_step = 1
def inference(x):
init = tf.constant_initializer(value=0)
W = tf.get_variable("W", [784, 10], initializer=init)
b = tf.get_variable("b", [10], initializer=init)
output = tf.nn.softmax(tf.matmul(x, W) + b)
tf.summary.histogram("weights", W)
tf.summary.histogram("biases", b)
tf.summary.histogram("output", output)
return output
def loss(output, y):
dot_product = y * tf.log(output)
# Reduction along axis 0 collapses each column into a single
# value, whereas reduction along axis 1 collapses each row
# into a single value. In general, reduction along axis i
# collapses the ith dimension of a tensor to size 1.
xentropy = -tf.reduce_sum(dot_product, axis=1)
loss = tf.reduce_mean(xentropy)
return loss
def training(cost, global_step):
tf.summary.scalar("cost", cost)
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
train_op = optimizer.minimize(cost, global_step=global_step)
return train_op
def evaluate(output, y):
correct_prediction = tf.equal(tf.argmax(output, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
tf.summary.scalar("validation error", (1.0 - accuracy))
return accuracy
if __name__ == "__main__":
# Remove old summaries and checkpoints
if os.path.exists("logistic_logs"):
shutil.rmtree("logistic_logs")
with tf.Graph().as_default():
x = tf.placeholder("float", [None, 784]) # mnist data image of shape 28*28=784
y = tf.placeholder("float", [None, 10]) # 0-9 digits recognition => 10 classes
output = inference(x)
cost = loss(output, y)
global_step = tf.Variable(0, name="global_step", trainable=False)
train_op = training(cost, global_step)
eval_op = evaluate(output, y)
summary_op = tf.summary.merge_all()
saver = tf.train.Saver()
sess = tf.Session()
summary_writer = tf.summary.FileWriter(
"logistic_logs",
graph_def=sess.graph_def
)
init_op = tf.global_variables_initializer()
sess.run(init_op)
# Training cycle
for epoch in range(training_epochs):
avg_cost = 0.
total_batch = int(mnist.train.num_examples/batch_size)
# Loop over all batches
for i in range(total_batch):
minibatch_x, minibatch_y = mnist.train.next_batch(batch_size)
# Fit training using batch data
sess.run(train_op, feed_dict={x: minibatch_x, y: minibatch_y})
# Compute average loss
avg_cost += sess.run(
cost, feed_dict={x: minibatch_x, y: minibatch_y}
) / total_batch
# Display logs per epoch step
if epoch % display_step == 0:
print("Epoch: {:04d} cost: {:.9f}".format(epoch+1, avg_cost))
accuracy = sess.run(eval_op, feed_dict={x: mnist.validation.images, y: mnist.validation.labels})
print("Validation Error: {}".format(1 - accuracy))
summary_str = sess.run(summary_op, feed_dict={x: minibatch_x, y: minibatch_y})
summary_writer.add_summary(summary_str, sess.run(global_step))
saver.save(sess, os.path.join("logistic_logs", "model-checkpoint"), global_step=global_step)
print("Optimization Finished!")
accuracy = sess.run(eval_op, feed_dict={x: mnist.test.images, y: mnist.test.labels})
print("Test Accuracy: {}".format(accuracy))
https://www.tensorflow.org/guide/graph_viz
(base) c:\Users\nitta> g: (base) g:\> cd マイドライブ\deeplearning\book3\ch03 (base) g:\マイドライブ\deeplearning\book3\ch03> conda activate gpu-graph (gpu-graph) g:\マイドライブ\deeplearning\book3\ch03> tensorboard --logdir logistic_logs logistic_logs
256 子の ReLU ニューロンからなる隠れ層を2つ持つモデルを考える。
ReLU ニューロンについては、 [He 2015] で述べられているように、ネットワーク内での重みの分散を $\frac{2}{n_{in}}$ にする。
softmax の計算を inference の中ではなく、損失の算出時に行うことに変更する。
以上の変更により、性能がかなり改善されることがわかる。
# multilayer_perceptron.py
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
import time, shutil, os
mnist = input_data.read_data_sets("data", one_hot=True)
# Architecture
n_hidden_1 = 256
n_hidden_2 = 256
# Parameters
learning_rate = 0.01
training_epochs = 300
batch_size = 100
display_step = 1
def layer(input, weight_shape, bias_shape):
weight_init = tf.random_normal_initializer(stddev=(2.0/weight_shape[0])**0.5)
bias_init = tf.constant_initializer(value=0)
W = tf.get_variable("W", weight_shape, initializer=weight_init)
b = tf.get_variable("b", bias_shape, initializer=bias_init)
return tf.nn.relu(tf.matmul(input, W) + b)
def inference(x):
with tf.variable_scope("hidden_1"):
hidden_1 = layer(x, [784, n_hidden_1], [n_hidden_1])
with tf.variable_scope("hidden_2"):
hidden_2 = layer(hidden_1, [n_hidden_1, n_hidden_2], [n_hidden_2])
with tf.variable_scope("output"):
output = layer(hidden_2, [n_hidden_2, 10], [10])
return output
def loss(output, y):
xentropy = tf.nn.softmax_cross_entropy_with_logits(logits=output, labels=y)
loss = tf.reduce_mean(xentropy)
return loss
def training(cost, global_step):
tf.summary.scalar("cost", cost)
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
train_op = optimizer.minimize(cost, global_step=global_step)
return train_op
def evaluate(output, y):
correct_prediction = tf.equal(tf.argmax(output, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
tf.summary.scalar("validation", accuracy)
return accuracy
if __name__ == "__main__":
# Remove old summaries and checkpoints
if os.path.exists("mlp_logs"):
shutil.rmtree("mlp_logs")
with tf.Graph().as_default():
with tf.variable_scope("mlp_model"):
x = tf.placeholder("float", [None, 784]) # mnist data image of shape 28*28=784
y = tf.placeholder("float", [None, 10]) # 0-9 digits recognition => 10 classes
output = inference(x)
cost = loss(output, y)
global_step = tf.Variable(0, name="global_step", trainable=False)
train_op = training(cost, global_step)
eval_op = evaluate(output, y)
summary_op = tf.summary.merge_all()
saver = tf.train.Saver()
sess = tf.Session()
summary_writer = tf.summary.FileWriter(
"mlp_logs",
graph_def=sess.graph_def
)
init_op = tf.global_variables_initializer()
sess.run(init_op)
# Training cycle
for epoch in range(training_epochs):
avg_cost = 0.
total_batch = int(mnist.train.num_examples/batch_size)
# Loop over all batches
for i in range(total_batch):
minibatch_x, minibatch_y = mnist.train.next_batch(batch_size)
# Fit training using batch data
sess.run(train_op, feed_dict={x: minibatch_x, y: minibatch_y})
# Compute average loss
avg_cost += sess.run(cost, feed_dict={x: minibatch_x, y: minibatch_y})/total_batch
# Display logs per epoch step
if epoch % display_step == 0:
print("Epoch: {:04d} cost: {:.9f}".format(epoch+1, avg_cost))
accuracy = sess.run(eval_op, feed_dict={x: mnist.validation.images, y: mnist.validation.labels})
print("Validation Error: {}".format(1 - accuracy))
summary_str = sess.run(summary_op, feed_dict={x: minibatch_x, y: minibatch_y})
summary_writer.add_summary(summary_str, sess.run(global_step))
saver.save(sess, os.path.join("mlp_logs", "model-checkpoint"), global_step=global_step)
print("Optimization Finished!")
accuracy = sess.run(eval_op, feed_dict={x: mnist.test.images, y: mnist.test.labels})
print("Test Accuracy: {}".format(accuracy))