@Deprecated
让我们拥抱tensorflow2.0吧
0. 概述
TensorFlow提供了实现机器学习算法的一套API。当然也提供了一套预定义库实现了常见机器学习算法。由于是开源项目,所有这些算法都可以自行改进。TensorFlow可以很轻松地扩展到集群。
1. 安装
CPU版本
pip install tensorflow
GPU版本
根据https://www.tensorflow.org/install/gpu的版本要求分别安装CUDA和cuDNN
如果要用最新版本的CUDA,参考这篇文章
对应tensorflow版本在这
pip install tensorflow-gpu
2. 样例
实现两个向量相加
import tensorflow as tf
a = tf.constant([1,2], name="a")
b = tf.constant([2,3], name="b")
result = a + b # 这个代码实际上并不执行任何计算,它只是创建一个计算图
print(result)
# Tensor("add_3:0", shape=(2,), dtype=int32)
sess = tf.Session()
print(sess.run(result))
# [3 5]
sess.close()
# 会话负责处理在 CPU 和 GPU 上的操作并运行它们
'''
为了避免每次重复的close session,更好的写法如下:
'''
with tf.Session() as sess
sess.run(result)
3.基本概念
Tensor:张量、多维数组。Flow:流,张量之间通过计算互相转换的过程。
TensorFlow程序一般分为两个步骤,首先定义计算图,然后进行计算。在机器学习中,这个步骤相当于先构建模型的计算图,然后进行训练。
计算图
TensorFlow通过计算图的形式来表述系统。计算图上的每个节点都是计算,节点之间的边表示计算之间的依赖关系。
可视化
TensorBoard是TensorFlow的可视化工具。
在代码中加入:writer = tf.summary.FileWriter("tfgraph", tf.get_default_graph()) # 将计算图写入日志,用于可视化 writer.close()
命令行运行:
tensorboard --logdir="tfgraph"
会启动一个服务,默认端口6006,通过浏览器访问查看可视化结果
默认图
创建的任何节点都会自动添加到默认图中
a.graph is tf.get_default_graph()
# True
#a.graph 即获取张量所属的计算图
重置默认图
tf.reset_default_grapgh()
添加图
g = tf.Graph()
with g.as_default():
x = tf.Variable(2)
x.graph is tf.get_default_graph()
# False
with g.device('/gpu:0'): # 指定运行的设备
result = a*a
with tf.Session(graph=g) as sess:
# do the calculation here
张量
张量是TensorFlow管理数据的形式,可以理解成一个多维数组,0阶的表示的是标量,1阶表示一个一维数组,其中保存的并不是运算的结果,而是如何得到结果的运算过程,一个引用。
a = tf.constant([1,2], name="a")
b = tf.constant([2,3], name="b")
res = a+b
print(res)
# Tensor("add:0", shape=(2,), dtype=int32)
可以看到res是一个张量,张量的结构有三部分组成
- 名字:张量的唯一标识符,同时以node:src_output的形式告诉了我们这个张量的结果是如何计算出来的,add:0表示该张量的结果是add节点的第0个输出。
- 维度:维度信息 shape=(2,)表示一维数组,且长度为2。
- 类型:每个张量都有唯一的类型,当类型不匹配时会报错。在定义变量的时候可以指定类型:a = tf.constant([1,2], name="a", dtype=float32)。
基本操作:get_shape()
,reshape()
,rank
,dtype
,cast
TensorFlow基本类型
-
tf.constant
常量 -
tf.variable
计算图中需要调整地变量。生命周期:从调用initializer
到session结束。每个session都持有了所有变量的副本。但是在分布式环境中,变量存储在服务器中,所有session共享。 -
tf.placeholder
存放数据
Session 会话
session负责执行定义好的计算,拥有并管理运行时的所有资源,需要通过关闭会话来释放资源。当会话被指定后,可以通过tf.Tensor.eval()来获取张量的取值。
a = tf.constant([1,2], name="a")
b = tf.constant([2,3], name="b")
res = a+b
with tf.Session() as sess:
print(sess.run(res))
print(res.eval(session=sess))
# [3, 5]
# 两种表达方式等价
tf.InteractiveSession()是一种交互式的session方式,它让自己成为了默认的session,也就是说用户在不需要指明用哪个session运行的情况下,就可以运行起来,这就是默认的好处。这样的话就是run()和eval()函数可以不指明session。
ConfigProto
ConfigProto用于配置会话。
config = tf.ConfigProto(allow_soft_placement=True, allow_soft_placement=True)
config.gpu_options.per_process_gpu_memory_fraction = 0.4 #占用40%显存
sess = tf.Session(config=config)
- 设置tf.ConfigProto()中参数log_device_placement = True ,可以获取到 operations 和 Tensor 被指派到哪个设备(几号CPU或几号GPU)上运行,会在终端打印出各项操作是在哪个设备上运行的
- 在tf中,通过命令 "with tf.device('/cpu:0'):",允许手动设置操作运行的设备。如果手动设置的设备不存在或者不可用,就会导致tf程序等待或异常,为了防止这种情况,可以设置tf.ConfigProto()中参数allow_soft_placement=True,允许tf自动选择一个存在并且可用的设备来运行操作。
4. 简单神经网络可视化
TensorFlow Playground是一个简单神经网络训练过程可视化工具。
- 边的黄色越深表示负的绝对值越大
- 边的蓝色越深表示正的绝对值越大
- 节点的颜色代表了这个节点的区分平面
5. 完整神经网络样例程序
import tensorflow as tf
from numpy.random import RandomState
'''
1. 定义神经网络的参数,输入和输出节点。
'''
batch_size = 8
learning_rate = 0.001
# tf.Variable用于保存和更新神经网络中的参数
w1= tf.Variable(tf.random_normal([2, 3], stddev=1, seed=1)) # tf.random_normal生成正态分布的随机数
w2= tf.Variable(tf.random_normal([3, 1], stddev=1, seed=1))
x = tf.placeholder(tf.float32, shape=(None, 2), name="x-input")
y_= tf.placeholder(tf.float32, shape=(None, 1), name='y-input')
# 如果每次迭代中选取的数据都要用常量来表示,那么计算图将会太大。因为每生成一个常量,都会在计算图中增加一个节点。
# TensorFlow提供了placeholder机制用于提供输入数据。
'''
2. 定义前向传播过程,损失函数及反向传播算法。
'''
a = tf.matmul(x, w1) # tf.matmul 矩阵乘法
y = tf.matmul(a, w2)
y = tf.sigmoid(y) # 激活函数的一种 sigmoid: y = 1/(1 + exp (-x))。
cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0))
+ (1 - y_) * tf.log(tf.clip_by_value(1 - y, 1e-10, 1.0)))
# reduce_mean求平均值
train_step = tf.train.AdamOptimizer(learning_rate).minimize(cross_entropy)
# 定义了反向传播算法,常用的还有GradientDescentOptimizer, MomentumOptimizer
'''
3. 生成模拟数据集。
'''
rdm = RandomState(1)
X = rdm.rand(128,2)
Y = [[int(x1+x2 < 1)] for (x1, x2) in X]
'''
4. 创建一个会话来运行TensorFlow程序。
'''
with tf.Session() as sess:
init_op = tf.global_variables_initializer()
sess.run(init_op)
# 输出目前(未经训练)的参数取值。
print(sess.run(w1))
print(sess.run(w2))
print("\n")
# 训练模型。
STEPS = 5000
for i in range(STEPS):
start = (i*batch_size) % 128
end = (i*batch_size) % 128 + batch_size
sess.run([train_step, y, y_], feed_dict={x: X[start:end], y_: Y[start:end]})
if i % 1000 == 0:
total_cross_entropy = sess.run(cross_entropy, feed_dict={x: X, y_: Y})
print("After %d training step(s), cross entropy on all data is %g" % (i, total_cross_entropy))
# 输出训练后的参数取值。
print("\n")
print(sess.run(w1))
print(sess.run(w2))
'''
[[-0.8113182 1.4845988 0.06532937]
[-2.4427042 0.0992484 0.5912243 ]]
[[-0.8113182 ]
[ 1.4845988 ]
[ 0.06532937]]
After 0 training step(s), cross entropy on all data is 1.89805
After 1000 training step(s), cross entropy on all data is 0.655075
After 2000 training step(s), cross entropy on all data is 0.626172
After 3000 training step(s), cross entropy on all data is 0.615096
After 4000 training step(s), cross entropy on all data is 0.610309
[[ 0.02476983 0.56948674 1.6921941 ]
[-2.1977348 -0.23668921 1.1143895 ]]
[[-0.45544702]
[ 0.49110925]
[-0.98110336]]
'''
6. TensorFlow实战之线性回归
用到的房价数据集,可以参考这篇简书
也可以直接用代码中的方法housing = fetch_california_housing()
正态方程解
根据这篇简书,线性回归的正态方程解为
用TensorFlow实现求解:
import numpy as np
from sklearn.datasets import fetch_california_housing
import tensorflow as tf
tf.reset_default_graph()
housing = fetch_california_housing()
m, n = housing.data.shape
# 向所有训练实例添加一个额外的偏置输入特征( x0 = 1 )
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()
theta_value
'''
array([[-3.7185181e+01],
[ 4.3633747e-01],
[ 9.3952334e-03],
[-1.0711310e-01],
[ 6.4479220e-01],
[-4.0338000e-06],
[-3.7813708e-03],
[-4.2348403e-01],
[-4.3721911e-01]], dtype=float32)
'''
print(housing.DESCR)
'''
.. _california_housing_dataset:
California Housing dataset
--------------------------
**Data Set Characteristics:**
:Number of Instances: 20640
:Number of Attributes: 8 numeric, predictive attributes and the target
:Attribute Information:
- MedInc median income in block
- HouseAge median house age in block
- AveRooms average number of rooms
- AveBedrms average number of bedrooms
- Population block population
- AveOccup average house occupancy
- Latitude house block latitude
- Longitude house block longitude
:Missing Attribute Values: None
'''
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)
Scikit-Learn实现
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])
梯度下降
首先归一化特征向量
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]
手动计算梯度
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()
'''
Epoch 0 MSE = 9.161542
Epoch 100 MSE = 0.7145004
Epoch 200 MSE = 0.56670487
Epoch 300 MSE = 0.5555718
Epoch 400 MSE = 0.5488112
Epoch 500 MSE = 0.5436363
Epoch 600 MSE = 0.5396291
Epoch 700 MSE = 0.5365092
Epoch 800 MSE = 0.53406775
Epoch 900 MSE = 0.5321473
'''
best_theta
'''
array([[ 2.0685523 ],
[ 0.8874027 ],
[ 0.14401656],
[-0.34770882],
[ 0.36178368],
[ 0.00393811],
[-0.04269556],
[-0.6614529 ],
[-0.6375279 ]], dtype=float32)
'''
利用tf.gradients
自动计算梯度
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")
'''
tensorflow计算梯度使用的是反向模式 reverse-mode autodiff
gradients()函数使用一个 op(在这种情况下是MSE)和一个变量列表(在这种情况下只 是 theta),
它创建一个ops列表(每个变量一个)来计算op的梯度变量。
因此,梯度节 点将计算 MSE相对于theta的梯度向量
'''
gradients = tf.gradients(mse, [theta])[0]
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()
print("Best theta:")
print(best_theta)
'''
Epoch 0 MSE = 9.161542
Epoch 100 MSE = 0.71450037
Epoch 200 MSE = 0.56670487
Epoch 300 MSE = 0.5555718
Epoch 400 MSE = 0.54881126
Epoch 500 MSE = 0.5436363
Epoch 600 MSE = 0.53962916
Epoch 700 MSE = 0.5365092
Epoch 800 MSE = 0.53406775
Epoch 900 MSE = 0.5321473
Best theta:
[[ 2.0685523 ]
[ 0.8874027 ]
[ 0.14401656]
[-0.3477088 ]
[ 0.36178365]
[ 0.00393811]
[-0.04269556]
[-0.66145283]
[-0.6375278 ]]
'''
TensorFlow梯度优化器
tf.train.GradientDescentOptimizer
tf.train.MomentumOptimizer
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")
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
# optimizer = tf.train.MomentumOptimizer(learning_rate=learning_rate, momentum=0.9)
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)
'''
Epoch 0 MSE = 9.161542
Epoch 100 MSE = 0.7145004
Epoch 200 MSE = 0.56670487
Epoch 300 MSE = 0.5555718
Epoch 400 MSE = 0.54881126
Epoch 500 MSE = 0.5436363
Epoch 600 MSE = 0.53962916
Epoch 700 MSE = 0.5365092
Epoch 800 MSE = 0.53406775
Epoch 900 MSE = 0.5321473
Best theta:
[[ 2.0685523 ]
[ 0.8874027 ]
[ 0.14401656]
[-0.3477088 ]
[ 0.36178365]
[ 0.00393811]
[-0.04269556]
[-0.66145283]
[-0.6375278 ]]
'''
将数据提供给训练算法
tf.placeholder
本身不执行任何计算,只是输出数据,通常用于存放训练数据。下面实现以下小批量梯度下降。
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)
indices = np.random.randint(m, size=batch_size)
X_batch = scaled_housing_data_plus_bias[indices]
y_batch = housing.target.reshape(-1, 1)[indices]
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()
best_theta
'''
array([[ 2.0703337 ],
[ 0.8637145 ],
[ 0.12255152],
[-0.31211877],
[ 0.38510376],
[ 0.00434168],
[-0.0123295 ],
[-0.83376896],
[-0.8030471 ]], dtype=float32)
'''
保存和恢复模型
在构造阶段结束(创建所有变量节点之后)创建一个保存节点tf.train.Saver()
,在执行阶段调用它的 save()
方法
saver = tf.train.Saver()
with tf.Session() as sess:
sess.run(init)
for epoch in range(n_epochs):
if epoch % 100 == 0:
print("Epoch", epoch, "MSE =", mse.eval())
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")
在执行阶段的开始调用store()
方法恢复数据
with tf.Session() as sess:
saver.restore(sess, "tmp/my_model_final.ckpt")
best_theta_restored = theta.eval()
save()
方法可以只保存想要的数据,下面这个例子保存了theta,并且键值为weights
saver = tf.train.Saver({"weights": theta})
保存器Saver
默认会把计算图的结构保存在另外一个.meta
文件中,可以通过tf.train.import_meta_graph()
恢复计算图
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")
使用 TensorBoard 展现计算图和训练曲线
除了上文可视化中提到的本地启动TensorBoard服务之外,也可以在jupyterlab中使用一个在线的TensorBoard服务,方法如下:
from tensorflow_graph_in_jupyter import show_graph
show_graph(tf.get_default_graph())
每次运行程序时都需要使用不同的日志目录,否则
TensorBoard 将会合并来自不同运行的统计信息,这将会混乱可视化。 最简单的解决方案是在日志目录名称中包含时间戳。
reset_graph()
from datetime import datetime
now = datetime.utcnow().strftime("%Y%m%d%H%M%S")
root_logdir = "tf_logs"
logdir = "{}/run-{}/".format(root_logdir, now)
接下来,在构建阶段结束时添加以下代码:
mse_summary = tf.summary.scalar('MSE', mse)
file_writer = tf.summary.FileWriter(logdir, tf.get_default_graph())
第一行创建一个节点,这个节点将求出 MSE 值并将其写入summary
中
完整代码:
import numpy as np
from sklearn.datasets import fetch_california_housing
import tensorflow as tf
from sklearn.preprocessing import StandardScaler
housing = fetch_california_housing()
m, n = housing.data.shape
print("数据集:{}行,{}列".format(m, n))
housing_data_plus_bias = np.c_[np.ones((m, 1)), housing.data]
scaler = StandardScaler()
scaled_housing_data = scaler.fit_transform(housing.data)
scaled_housing_data_plus_bias = np.c_[np.ones((m, 1)), scaled_housing_data]
from datetime import datetime
now = datetime.utcnow().strftime("%Y%m%d%H%M%S")
root_logdir = r"D://tf_logs"
logdir = "{}/run-{}/".format(root_logdir, now)
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())
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)
indices = np.random.randint(m, size=batch_size)
X_batch = scaled_housing_data_plus_bias[indices]
y_batch = housing.target.reshape(-1, 1)[indices]
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)
if batch_index % 10 == 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()
file_writer.close()
print(best_theta)
名称作用域 name scope
当处理更复杂的模型(如神经网络)时,该图可以很容易地与数千个节点混淆。 为了避免这种情况,可以创建名称作用域来对相关节点进行分组。
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)
'''
a
a_1
param/a
param_1/a
'''
模块性
一段重复的代码如下:
n_features = 3
X = tf.placeholder(tf.float32, shape=(None, n_features), name="X")
w1 = tf.Variable(tf.random_normal((n_features, 1)), name="weights1")
w2 = tf.Variable(tf.random_normal((n_features, 1)), name="weights2")
b1 = tf.Variable(0.0, name="bias1")
b2 = tf.Variable(0.0, name="bias2")
z1 = tf.add(tf.matmul(X, w1), b1, name="z1")
z2 = tf.add(tf.matmul(X, w2), b2, name="z2")
relu1 = tf.maximum(z1, 0., name="relu1")
relu2 = tf.maximum(z2, 0., name="relu2")
output = tf.add(relu1, relu2, name="output")
用一个函数来构建ReLUs,add_n()
创建一个计算张量列表之和的操作。
def relu(X):
w_shape = (int(X.get_shape()[1]), 1)
w = tf.Variable(tf.random_normal(w_shape), name="weights")
b = tf.Variable(0.0, name="bias")
z = tf.add(tf.matmul(X, w), b, name="z")
return tf.maximum(z, 0., name="relu")
n_features = 3
X = tf.placeholder(tf.float32, shape=(None, n_features), name="X")
relus = [relu(X) for i in range(5)]
output = tf.add_n(relus, name="output")
创建节点时,TensorFlow 将检查其名称是否已存在,如果它已经存在,则会附加一个下划线,后跟一个索引,以使该名称是唯一的。 因此,第一个 ReLU 包含名为 weights , bias , z 和 relu 的节点(加上其他默认名称的更多节点,如 MatMul ); 第二个 ReLU 包含名为 weights_1 , bias_1 等节点的节点; 第三个 ReLU 包含名为weights_2 , bias_2 的节点,依此类推。
利用name scope可以让计算图更清晰
reset_graph()
def relu(X):
with tf.name_scope("relu"):
w_shape = (int(X.get_shape()[1]), 1)
w = tf.Variable(tf.random_normal(w_shape), name="weights")
b = tf.Variable(0.0, name="bias")
z = tf.add(tf.matmul(X, w), b, name="z")
return tf.maximum(z, 0., name="max")
共享变量
使用get_variable()
函数,如果它还不存在,则创建共享变量,如果已经存在,则复用它。
以下代码将创建一个名为 relu/threshold 的变量
with tf.variable_scope("relu"):
threshold = tf.get_variable("threshold", shape=(), initializer=tf.constant_initializer(0.0))
如果变量已经通过较早的 get_variable()
调用创建,则此代码将引发异常。 这种行为可以防止错误地复用变量。如果要复用变量,则需要通过将variable_scope
的复用属性设置为True
with tf.variable_scope("relu", reuse=True):
threshold = tf.get_variable("threshold")