欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Up and Running with TensorFlow(第九章)

程序员文章站 2022-07-14 21:05:25
...

Tensorflow定义计算图,并且可以把计算图分成几块在不同GPU上运行。

Up and Running with TensorFlow(第九章)

并且支持分布式训练,把计算均摊在数百个服务器上来训练超大规模的神经网络。

 

Creating Your First Graph and Running It in a Session

实例上下面的代码不进行任何计算,它只是创建一个计算图。

import tensorflow as tf

reset_graph()

x = tf.Variable(3, name="x")
y = tf.Variable(4, name="y")
f = x*x*y + y + 2   ###<tf.Tensor 'add_1:0' shape=() dtype=int32>

要计算上面的代码,需要打开一个session,session是把上面这个操作放到devices中,例如CPU,GPU。最后需要sess.close释放资源。如下

sess = tf.Session()
sess.run(x.initializer)
sess.run(y.initializer)
result = sess.run(f)
print(result)

 

每次都需要sess.run()显然太麻烦,还有一种简单的方式。在with块中,session被当成默认的session.并且结束会自动释放资源。

with tf.Session() as sess:
    x.initializer.run()
    y.initializer.run()
    result = f.eval()

x.initializer.run() is equivalent to calling tf.get_default_session().run(x.initializer)

还有一种更简单的方式来初始化。

init = tf.global_variables_initializer()

with tf.Session() as sess:
    init.run()
    result = f.eval()

 

当使用InteractiveSession时,和常规的Session不同的是,会自动将InteractiveSession设置为默认的Session,不需要with框架,但是需要在最后关闭以释放资源。

sess = tf.InteractiveSession()
init.run()
result = f.eval()
print(result)
sess.close()

 

Managing Graphs

任何设置的节点都会自动添进默认的图表。

x1 = tf.Variable(1)
x1.graph is tf.get_default_graph()

 

Up and Running with TensorFlow(第九章)

有时候需要管理多个独立的图表,这时候需要创建一个新Graph并且临时得把这个图放入一个with块中,使得这个图为默认图。

graph = tf.Graph()
with graph.as_default():
    x2 = tf.Variable(2)

x2.graph is graph  ###true
x2.graph is tf.get_default_graph() ###Flase

 

在实验中,你有可能会运行同样得一条指令多次,这样会导致你的默认图中拥有很多重复的节点。    有两种方法应对这种情况:

  1. 重启spyder
  2. 使用如下指令
tf.reset_default_graph()

Lifecycle of a Node Value

当你评估一个节点时(一个节点代表一个数值),tensorflow会自动的确定此节点所依赖的所有节点,并且首先为这些节点评估。参考如下代码

w = tf.constant(3)
x = w + 2
y = x + 5
z = x * 3

with tf.Session() as sess:
    print(y.eval())  # 10
    print(z.eval())  # 15

 

首先这个代码评估y,它发现y依赖x,x依赖w,所以这个session首先evaluate,w,然后x,最后y。在评估z的时候还是会从头评估w和x,不会利用之前的结果,也就是说这行代码评估w,x两次。要想只评估一次,需要使用如下代码

with tf.Session() as sess:
    y_val, z_val = sess.run([y, z])
    print(y_val)  # 10
    print(z_val)  # 15

所有节点的值在图运行之间都会被丢弃,除了variable values,它的值是由Session提供。

多个Session之间不会共享状态,即使他们运行的是同一张图,每一个Session都会拥有每一个变量的副本。在分布式tensorflow中,变量的状态存储在服务器上(Server),而不是session中,因此可以共享变量。

 

Linear Regression with TensorFlow

以下代码相比于直接使用numpy的直接计算,tensorflow可以把以下代码放在GPU中运行。直接使用fetch_california_housing这个函数会出错,先把如下代码放入linux中运行,得到cal_housing_py3.pkz文件,放入data_home='H:\paper\DeepLearning\Tensorflow\hand on with tensorflow\california_housing'中,即可运行成功。这里把numpy转成tensorflow 的节点

import numpy as np
from sklearn.datasets import fetch_california_housing

reset_graph()

housing = fetch_california_housing(data_home='H:\paper\DeepLearning\Tensorflow\hand on with                 
                                   tensorflow\california_housing')####假如数据下载不成功则自
                                   行下载,然后添加
m, n = housing.data.shape
housing_data_plus_bias = np.c_[np.ones((m, 1)), housing.data]

X = tf.constant(housing_data_plus_bias, dtype=tf.float32, name="X")
y = tf.constant(housing.target.reshape(-1, 1), dtype=tf.float32, name="y")
XT = tf.transpose(X)
theta = tf.matmul(tf.matmul(tf.matrix_inverse(tf.matmul(XT, X)), XT), y)

with tf.Session() as sess:
    theta_value = theta.eval()

 使用numpy计算

X = housing_data_plus_bias
y = housing.target.reshape(-1, 1)
theta_numpy = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y)

print(theta_numpy)

使用sklearn进行计算

from sklearn.linear_model import LinearRegression
lin_reg = LinearRegression()
lin_reg.fit(housing.data, housing.target.reshape(-1, 1))

print(np.r_[lin_reg.intercept_.reshape(-1, 1), lin_reg.coef_.T])

 

 

Implementing Gradient Descent

Manually Computing the Gradients

  1. random_uniform() 函数在图中创建一个产生tensor的节点,给定Shape和值的范围,可以产生带有随机数的tensor。与numpy的rand()类似。
  2. assign()为variable赋上一个新值。下面例子中θ(next step) = θ –η∇θMSE(θ) 
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaled_housing_data = scaler.fit_transform(housing.data)
scaled_housing_data_plus_bias = np.c_[np.ones((m, 1)), scaled_housing_data]

​​​​

reset_graph()

n_epochs = 1000
learning_rate = 0.01

X = tf.constant(scaled_housing_data_plus_bias, dtype=tf.float32, name="X")
y = tf.constant(housing.target.reshape(-1, 1), dtype=tf.float32, name="y")
theta = tf.Variable(tf.random_uniform([n + 1, 1], -1.0, 1.0, seed=42), name="theta")
y_pred = tf.matmul(X, theta, name="predictions")
error = y_pred - y
mse = tf.reduce_mean(tf.square(error), name="mse")
gradients = 2/m * tf.matmul(tf.transpose(X), error)
training_op = tf.assign(theta, theta - learning_rate * gradients)

init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)

    for epoch in range(n_epochs):
        if epoch % 100 == 0:
            print("Epoch", epoch, "MSE =", mse.eval())
        sess.run(training_op)
    
    best_theta = theta.eval()

 

  1.  

Using autodiff

使用如下自动计算的梯度

gradients = tf.gradients(mse, [theta])[0]

The gradients() function takes an op (in this case mse) and a list of variables (in this
case just theta), and it creates a list of ops (one per variable) to compute the gradi‐
ents of the op with regards to each variable. 

Up and Running with TensorFlow(第九章)

a=tf.gradients(mse, [theta])[0] ,b=tf.gradients(mse, [theta])

代替上方手动计算的梯度

gradients = 2/m * tf.matmul(tf.transpose(X), error)

Using an Optimizer

事实上可以更加简单

把gradients = ...和 training_op = ... 替换成如下

optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
training_op = optimizer.minimize(mse)

完整代码如下 


n_epochs = 1000
learning_rate = 0.01

X = tf.constant(scaled_housing_data_plus_bias, dtype=tf.float32, name="X")
y = tf.constant(housing.target.reshape(-1, 1), dtype=tf.float32, name="y")
theta = tf.Variable(tf.random_uniform([n + 1, 1], -1.0, 1.0, seed=42), name="theta")
y_pred = tf.matmul(X, theta, name="predictions")
error = y_pred - y
mse = tf.reduce_mean(tf.square(error), name="mse")
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
training_op = optimizer.minimize(mse)
init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)

    for epoch in range(n_epochs):
        if epoch % 100 == 0:
            print("Epoch", epoch, "MSE =", mse.eval())
        sess.run(training_op)
    
    best_theta = theta.eval()

print("Best theta:")
print(best_theta)

Feeding Data to the Training Algorithm

使用Mini-batch Gradient Descent 时,需要在每次迭代的时候,用下一个mini-batch去替代X和y,为此,我们使用placeholder,placeholder不做任何计算,他们只输出你让他们输出的值。引入placeholder函数,指定了输出tensor的数据类型。也可以指定其shape,假如shape中存在None,那么代表着任意的尺寸。

reset_graph()

A = tf.placeholder(tf.float32, shape=(None, 3))
B = A + 5
with tf.Session() as sess:
    B_val_1 = B.eval(feed_dict={A: [[1, 2, 3]]})
    B_val_2 = B.eval(feed_dict={A: [[4, 5, 6], [7, 8, 9]]})

print(B_val_1)  ##[[6. 7. 8.]]

print(B_val_2)  ##[[ 9. 10. 11.]
                ##[12. 13. 14.]]

上面代码中,当评估B时,需要传出feed_dict参数来指定placeholder的值

按照上面房价预测的例子,只需要修改几行代码

n_epochs = 1000
learning_rate = 0.01
reset_graph()

X = tf.placeholder(tf.float32, shape=(None, n + 1), name="X")
y = tf.placeholder(tf.float32, shape=(None, 1), name="y")
theta = tf.Variable(tf.random_uniform([n + 1, 1], -1.0, 1.0, seed=42), name="theta")
y_pred = tf.matmul(X, theta, name="predictions")
error = y_pred - y
mse = tf.reduce_mean(tf.square(error), name="mse")
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
training_op = optimizer.minimize(mse)

init = tf.global_variables_initializer()
n_epochs = 10

batch_size = 100
n_batches = int(np.ceil(m / batch_size))

def fetch_batch(epoch, batch_index, batch_size):
    np.random.seed(epoch * n_batches + batch_index)  # not shown in the book###设置种子
    indices = np.random.randint(m, size=batch_size)  # not shown取值[0,m)
    X_batch = scaled_housing_data_plus_bias[indices] # not shown
    y_batch = housing.target.reshape(-1, 1)[indices] # not shown
    return X_batch, y_batch

with tf.Session() as sess:
    sess.run(init)

    for epoch in range(n_epochs):
        for batch_index in range(n_batches):
            X_batch, y_batch = fetch_batch(epoch, batch_index, batch_size)
            sess.run(training_op, feed_dict={X: X_batch, y: y_batch})

    best_theta = theta.eval()  ###输出最佳值

Saving and Restoring Models

通过在construction phase 中(构建图的过程)创建Saver 节点,即所有变量节点都被创建。然后在execution phase 中,每当你需要保存模型的时候就运行save() 方法,只需要传入会话以及路径。


在linux中使用如下代码,中间每100个epoch存一次,以防数据丢失。

n_epochs = 1000                                                                       # not shown in the book
learning_rate = 0.01                                                                  # not shown

X = tf.constant(scaled_housing_data_plus_bias, dtype=tf.float32, name="X")            # not shown
y = tf.constant(housing.target.reshape(-1, 1), dtype=tf.float32, name="y")            # not shown
theta = tf.Variable(tf.random_uniform([n + 1, 1], -1.0, 1.0, seed=42), name="theta")
y_pred = tf.matmul(X, theta, name="predictions")                                      # not shown
error = y_pred - y                                                                    # not shown
mse = tf.reduce_mean(tf.square(error), name="mse")                                    # not shown
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)            # not shown
training_op = optimizer.minimize(mse)                                                 # not shown

init = tf.global_variables_initializer()
saver = tf.train.Saver()    ####saver = tf.train.Saver({"weights": theta})

with tf.Session() as sess:
    sess.run(init)

    for epoch in range(n_epochs):
        if epoch % 100 == 0:
            print("Epoch", epoch, "MSE =", mse.eval())                                # not shown
            save_path = saver.save(sess, "/tmp/my_model.ckpt")
        sess.run(training_op)
    
    best_theta = theta.eval()
    save_path = saver.save(sess, "/tmp/my_model_final.ckpt")


with tf.Session() as sess:
    saver.restore(sess, "/tmp/my_model_final.ckpt")
    best_theta_restored = theta.eval() # not shown in the book

np.allclose(best_theta, best_theta_restored) ###true

当用作存储模型的时候,下面用作取出模型的with块需要注释。当为了取出模型的时候,上面用作训练的with块需要被注释。

 

中间可以每100个epoch保存一次模型。即:还是要写construction phase ,也需要在最后添加Saver,然而在with中,不需要sess.run(init),只需要取出模型就可以了。

 

Saver默认是存储或者取回所有的变量,以及变量的名字。假如需要更多控制,可以指定哪些变量需要存储或取回,以及他们使用什么名字。以下代码以名字‘weights’存储或者取回theta。在构建阶段添加

saver = tf.train.Saver({"weights": theta})

.meta文件中存储着图的结构。

直接从空的图表中恢复存储的图

reset_graph()
# notice that we start with an empty graph.

saver = tf.train.import_meta_graph("/tmp/my_model_final.ckpt.meta")  # this loads the graph structure
theta = tf.get_default_graph().get_tensor_by_name("theta:0") # not shown in the book  ##取出一个tensor theta这个ops的第一个输出tensor

with tf.Session() as sess:
    saver.restore(sess, "/tmp/my_model_final.ckpt")  # this restores the graph's state
    best_theta_restored = theta.eval() # not shown in the book

np.allclose(best_theta, best_theta_restored)  ###true

需要有取出tensor以便下面使用帮助你恢复一个模型。

 

 

Visualizing the Graph and Training Curves Using TensorBoard

第一步对你的程序进行微调,把图的定义和训练统计(例如MSE(training error))放入一个Log文件夹,tensorboard会从这个文件夹导入它。你每次需要使用不同的log文件夹,否则tensorboard会把不同的次运行的结果结合起来,造成结果混乱。为解决这个问题,可以加入时间戳。(UTC时间是


0时区的区时,即0度经线的地方时,比北京时间(东八区的区时,即东经120度的地方时)晚8小时),即加8小时=北京时间。0时区的区时,即0度经线的地方时,比北京时间(东八区的区时,即东经120度的地方时)晚8小时),即加8小时=北京时间。
reset_graph()

from datetime import datetime

now = datetime.utcnow().strftime("%Y%m%d%H%M%S")
print (now)
root_logdir = "tf_logs"
logdir = "{}/run-{}/".format(root_logdir, now)
print (logdir)


Up and Running with TensorFlow(第九章)

 

n_epochs = 1000
learning_rate = 0.01

X = tf.placeholder(tf.float32, shape=(None, n + 1), name="X")
y = tf.placeholder(tf.float32, shape=(None, 1), name="y")
theta = tf.Variable(tf.random_uniform([n + 1, 1], -1.0, 1.0, seed=42), name="theta")
y_pred = tf.matmul(X, theta, name="predictions")
error = y_pred - y
mse = tf.reduce_mean(tf.square(error), name="mse")
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
training_op = optimizer.minimize(mse)

init = tf.global_variables_initializer()
mse_summary = tf.summary.scalar('MSE', mse)
file_writer = tf.summary.FileWriter(logdir, tf.get_default_graph())

在以上代码中,第一行在图中创建一个节点,用来评估mse的值,这时候只是创建一个节点,如下。

Up and Running with TensorFlow(第九章)Up and Running with TensorFlow(第九章)

第二行创建一个FileWriter,用来把summaries写入 log 目录下的logfiles中。第一个参数是log目录的地址,第二个参数是你想要可视化的图。最后FileWriter把图的定义写入events文件。

Up and Running with TensorFlow(第九章)

 

随后你需要在训练时刻,每10个batch就评估mse_summary节点。summary_str是一个summary,你可以把这个summary写入event文件,使用file_writer。   

with tf.Session() as sess:                                                        # not shown in the book
    sess.run(init)                                                                # not shown

    for epoch in range(n_epochs):                                                 # not shown
        for batch_index in range(n_batches):
            X_batch, y_batch = fetch_batch(epoch, batch_index, batch_size)
            if batch_index % 100 == 0:
                summary_str = mse_summary.eval(feed_dict={X: X_batch, y: y_batch})
                step = epoch * n_batches + batch_index
                file_writer.add_summary(summary_str, step)
            sess.run(training_op, feed_dict={X: X_batch, y: y_batch})

    best_theta = theta.eval()  

Up and Running with TensorFlow(第九章)

此图是根据mini_batch画出,可以看出与上面的tensorboard相比,多了SCALARS这一个。graphs与上面保持不变。

Up and Running with TensorFlow(第九章)

 

最后使用以下指令关闭

file_writer.close()

上面的代码会创建log目录并且把events文件写入这个目录,包括图的定义以及MSE的值。使用如下代码来展现tf_logs/run*下的内容。run*意思:前面三个字符为run。

加入跑了两次以上代码,则能看到

Up and Running with TensorFlow(第九章)

每一个节点都有很多边(连接到其他节点),为了减少不必要的混乱,把这些节点放到旁边的辅助区(右击),

打开tensorboard在tf_logs所在目录下,使用,注意不能使用ctrl+c退出,直接如下打开

Up and Running with TensorFlow(第九章)

source activate py36
tensorboard --logdir tf_logs/

 

Name Scopes

当使用神经网络时,节点之间的关系会变得复杂。可以使用名字空间(name scopes)来把相关的节点聚集起来。

使用losss名字来规定名字空间。

with tf.name_scope("losss") as scope:
    error = y_pred - y
    mse = tf.reduce_mean(tf.square(error), name="msee")

所有在with块下面的op操作,都会被加一个前缀losss/

print(error.op.name)   ##losss/sub
print(mse.op.name)     ##losss/msee

在tensorboard中会把error和mse放在loss的名字空间当中。如下图,error,和mse被包在losss(loss的别名)中。

Up and Running with TensorFlow(第九章)

Up and Running with TensorFlow(第九章)

Up and Running with TensorFlow(第九章)

reset_graph()

a1 = tf.Variable(0, name="a")      # name == "a"
a2 = tf.Variable(0, name="a")      # name == "a_1"

with tf.name_scope("param"):       # name == "param"
    a3 = tf.Variable(0, name="a")  # name == "param/a"

with tf.name_scope("param"):       # name == "param_1"
    a4 = tf.Variable(0, name="a")  # name == "param_1/a"

for node in (a1, a2, a3, a4):
    print(node.op.name)

Up and Running with TensorFlow(第九章)

Modularity

写代码没有模块性容易出错,例如下面这样。

reset_graph()

n_features = 3
X = tf.placeholder(tf.float32, shape=(None, n_features), name="XX")

w1 = tf.Variable(tf.random_normal((n_features, 1)), name="weights11")
w2 = tf.Variable(tf.random_normal((n_features, 1)), name="weights22")
b1 = tf.Variable(0.0, name="bias11")
b2 = tf.Variable(0.0, name="bias22")

z1 = tf.add(tf.matmul(X, w1), b1, name="z11")
z2 = tf.add(tf.matmul(X, w2), b2, name="z22")

relu1 = tf.maximum(z1, 0., name="relu11")
relu2 = tf.maximum(z1, 0., name="relu22")  # Oops, cut&paste error! Did you spot it?

output = tf.add(relu1, relu2, name="output")

可以使用函数来使得代码更加简洁。

reset_graph()

def relu(X):
    w_shape = (int(X.get_shape()[1]), 1)
    w = tf.Variable(tf.random_normal(w_shape), name="weightss")
    b = tf.Variable(0.0, name="biass")
    z = tf.add(tf.matmul(X, w), b, name="zz")
    return tf.maximum(z, 0., name="reluu")

n_features = 3
X = tf.placeholder(tf.float32, shape=(None, n_features), name="XX")
relus = [relu(X) for i in range(5)]
output = tf.add_n(relus, name="outputt")
file_writer = tf.summary.FileWriter("logs/relu11", tf.get_default_graph())

 

当你创建一个节点时,tensorboard会检查它是否已经存在,存在的话会给这个节点加一个下划线,后面跟一个索引,来使得这个节点不重复。使用上述代码创建的tensorboard如下

Up and Running with TensorFlow(第九章)

 

最好使用名字空间,这样tensorboard会显示的更加简洁。

reset_graph()

def relu(X):
    with tf.name_scope("relu"):
        w_shape = (int(X.get_shape()[1]), 1)                          # not shown in the book
        w = tf.Variable(tf.random_normal(w_shape), name="weightss")    # not shown
        b = tf.Variable(0.0, name="biass")                             # not shown
        z = tf.add(tf.matmul(X, w), b, name="zz")                      # not shown
        return tf.maximum(z, 0., name="maxx")   

n_features = 3
X = tf.placeholder(tf.float32, shape=(None, n_features), name="XX")
relus = [relu(X) for i in range(5)]
output = tf.add_n(relus, name="outputt")

file_writer = tf.summary.FileWriter("logs/relu22", tf.get_default_graph())
file_writer.close()

Up and Running with TensorFlow(第九章)

可以看出在函数开头加上名字空间relu,会把函数中的内容放入relu内部

Up and Running with TensorFlow(第九章)

Sharing Variables

假如你想在你的图之间的各个组件之间共享变量,最简单的方法就是先创建它,然后把这个共享变量传入需要它的函数。

reset_graph()

def relu(X, threshold):
    with tf.name_scope("relu"):
        w_shape = (int(X.get_shape()[1]), 1)                        # not shown in the book
        w = tf.Variable(tf.random_normal(w_shape), name="weights")  # not shown
        b = tf.Variable(0.0, name="bias")                           # not shown
        z = tf.add(tf.matmul(X, w), b, name="z")                    # not shown
        return tf.maximum(z, threshold, name="max")

threshold = tf.Variable(0.0, name="threshold")
X = tf.placeholder(tf.float32, shape=(None, n_features), name="X")
relus = [relu(X, threshold) for i in range(5)]
output = tf.add_n(relus, name="output")

在tensorflow中还有一种更加简单的方式来创建共享变量,即使用get_variable() 函数来创建先前没有的变量,或者使用这个函数来重新使用共享变量。创建/重用操作受当前的variable_scope() 控制。例如如下代码

reset_graph()

with tf.variable_scope("relu"):
    threshold = tf.get_variable("threshold", shape=(),
                                initializer=tf.constant_initializer(0.0))

此代码创建了一个变量,名为relu/threshold,因为此是一个标量,所以shape为(),假如这个变量被之前的get_variable()创建,那么会报错。假如你想重用此变量,那么需要使得变量范围中reuse=True.这时候不需要初始化了。

with tf.variable_scope("relu", reuse=True):
    threshold = tf.get_variable("threshold")

上面代码会取回"relu/threshold" 变量。假如变量不存在或者不是由get_variable创建的,那么会报错。

reuse=True这个属性可以放在with块中,如下。

with tf.variable_scope("relu") as scope:
    scope.reuse_variables()
    threshold = tf.get_variable("threshold")

一旦reuse被设为True,那么在with块中就无法设置为False。假如你在此块中设置了其他的variable scopes ,那么他们的reuse也为True。最后,只有使用get_variable创建的变量才能使用reuse。

使用以下代码进行relu的多threshold设置 

reset_graph()

def relu(X):
    with tf.variable_scope("relu", reuse=True):
        threshold = tf.get_variable("threshold")
        w_shape = int(X.get_shape()[1]), 1                          # not shown
        w = tf.Variable(tf.random_normal(w_shape), name="weights")  # not shown
        b = tf.Variable(0.0, name="bias")                           # not shown
        z = tf.add(tf.matmul(X, w), b, name="z")                    # not shown
        return tf.maximum(z, threshold, name="max")

X = tf.placeholder(tf.float32, shape=(None, n_features), name="X")
with tf.variable_scope("relu"):
    threshold = tf.get_variable("threshold", shape=(),
                                initializer=tf.constant_initializer(0.0))
relus = [relu(X) for relu_index in range(5)]
output = tf.add_n(relus, name="output")

​​​​​​​首先定义relu函数,然后创建relu/threshold variable ,通过引用relu()函数创建5个ReLu,relu()函数会重用relu/threshold variable 。图的定义如下threshold同时传入给relu_1,2,3,4,5.

Up and Running with TensorFlow(第九章)

这个方法是把threshold的定义放在函数外面。还有一种放里面,一旦relu()函数被调用,那么在其内部创建threshold 变量,然后在后续调用中,重用此变量。需要注意,在第一次调用的时候需要把reuse设置为False(首先是创建),后面在设置为True。

 

reset_graph()

def relu(X):
    threshold = tf.get_variable("threshold", shape=(),
                                initializer=tf.constant_initializer(0.0))
    w_shape = (int(X.get_shape()[1]), 1)                        # not shown in the book
    w = tf.Variable(tf.random_normal(w_shape), name="weights")  # not shown
    b = tf.Variable(0.0, name="bias")                           # not shown
    z = tf.add(tf.matmul(X, w), b, name="z")                    # not shown
    return tf.maximum(z, threshold, name="max")

X = tf.placeholder(tf.float32, shape=(None, n_features), name="X")
relus = []
for relu_index in range(5):
    with tf.variable_scope("relu", reuse=(relu_index >= 1)) as scope:
        relus.append(relu(X))
output = tf.add_n(relus, name="output")

 

图的定义如下。relu有一个箭头直接出来output,还有4个箭头指向relu_1,2,3,4

Up and Running with TensorFlow(第九章)

 

Extra material

以下代码

reset_graph()

with tf.variable_scope("my_scope"):
    x0 = tf.get_variable("x", shape=(), initializer=tf.constant_initializer(0.))
    x1 = tf.Variable(0., name="x")
    x2 = tf.Variable(0., name="x")

with tf.variable_scope("my_scope", reuse=True):
    x3 = tf.get_variable("x")
    x4 = tf.Variable(0., name="x")

with tf.variable_scope("", default_name="", reuse=True):
    x5 = tf.get_variable("my_scope/x")

print("x0:", x0.op.name)
print("x1:", x1.op.name)
print("x2:", x2.op.name)
print("x3:", x3.op.name)
print("x4:", x4.op.name)
print("x5:", x5.op.name)
print(x0 is x3 and x3 is x5)

Up and Running with TensorFlow(第九章) 

​​​​​​​对于非共享变量来说,name scope只是一个前缀,tensorflow会让前缀变得独一无二,所以才有了x4的my_scope_1/x,以及x1,x2.

 

 

Exercises

  1. a_val = a.eval(session=sess) 和a_val =sess.run(a) 效果相同
  2. a_val, b_val = a.eval(session=sess), b.eval(session=sess)###1
    a_val, b_val = sess.run([a, b])##2
    效果不同,1运行两次图,#只运行一次。
  3. 在local TensorFlow 中,sessions管理变量,假如创建一个包含有变量w的图,打开两个threads,并且在每个thread中打开session,同时使用同一张图,那么每一个session都会拥有一个变量w的拷贝。分布式tensorflow中,变量的值存在由cluster管理的container中,假如session连接到相同的cluster中,那么session可以共享变量w。
  4. 变量通过调用initializer开始它的生命周期,当session结束时,结束它的生命周期。
  5. 变量是一个op,用来存住一个值,当run的时候,会返回这个值。但是在run之前,需要initialize它。placeholder只拥有他所表示的tensor的shape和type,并没有值。必须通过feed_dict给placeholder传入值。原始问题为How can you set a variable to any value you want (during the execution phase)?当execution phase 时,需要设置variable的值,需要这么做。通过tf.assign()函数创建一个赋值节点,传入variable和placeholder,作为参数。如下
    x = tf.Variable(tf.random_uniform(shape=(), minval=0.0, maxval=1.0))
    x_new_val = tf.placeholder(shape=(), dtype=tf.float32)
    x_assign = tf.assign(x, x_new_val)
    with tf.Session():
        x.initializer.run() # random number is sampled *now*
        print(x.eval()) # 0.646157 (some random number)
        x_assign.eval(feed_dict={x_new_val: 5.0})
        print(x.eval()) # 5.0

     

​​​​​​​