变量的作用域:
with块里的变量,块外也能用。
name_scope和variable_scope
import tensorflow as tf def my_func(x): w1 = tf.Variable(tf.random_normal([1]))[0] b1 = tf.Variable(tf.random_normal([1]))[0] r1 = w1 * x + b1 w2 = tf.Variable(tf.random_normal([1]))[0] b2 = tf.Variable(tf.random_normal([1]))[0] r2 = w2 * r1 + b2 return r1, w1, b1, r2, w2, b2 # 下面两行代码还是属于图的构建 x = tf.constant(3, dtype=tf.float32) r = my_func(x) with tf.Session(config=tf.ConfigProto(log_device_placement=True, allow_soft_placement=True)) as sess: # 初始化 tf.global_variables_initializer().run() # 执行结果 print(sess.run(r)) |
改进:
# -*- coding: utf-8 -*- """ Created on Sun Feb 24 17:35:18 2019 @author: oucbu """ import tensorflow as tf # 方式二 def my_func(x): w = tf.get_variable(name='w', shape=[1], initializer=tf.random_normal_initializer())[0] b = tf.get_variable(name='b', shape=[1], initializer=tf.random_normal_initializer())[0] r = w * x + b return r, w, b def func(x): #第一处复用my_func中的w,b,定义作用域 with tf.variable_scope('op1', reuse=tf.AUTO_REUSE):#变量(w,b)作用域 r1 = my_func(x) with tf.variable_scope('op2', reuse=tf.AUTO_REUSE): r2 = my_func(r1[0]) return r1, r2 # 下面两行代码还是属于图的构建 x1 = tf.constant(3, dtype=tf.float32, name='x1') x2 = tf.constant(4, dtype=tf.float32, name='x2') #第二处复用fun中的op1,op2,定义作用域 with tf.variable_scope('func1'): r1 = func(x1) with tf.variable_scope('func2'): r2 = func(x2) with tf.Session(config=tf.ConfigProto(log_device_placement=True, allow_soft_placement=True)) as sess: # 初始化 tf.global_variables_initializer().run() # 执行结果 print(sess.run([r1, r2])) |
tf.variable_score参数如果给定的是一个已经存在的作用域对象的时候,那么构
建变量的时候表示直接跳过当前作用域前缀,直接成为一个完全不同与现在的作
用域(直接创建给定作用域下的变量)。但是构建操作的时候,还是和嵌套的方式一样,直接添加子作用域。
import tensorflow as tf with tf.Session(config=tf.ConfigProto(log_device_placement=True, allow_soft_placement=True)) as sess: with tf.variable_scope('foo', initializer=tf.constant_initializer(4.0)) as foo: v = tf.get_variable("v", [1]) w = tf.get_variable("w", [1], initializer=tf.constant_initializer(3.0)) with tf.variable_scope('bar'): l = tf.get_variable("l", [1])
with tf.variable_scope(foo):#这个时候,不是子作用域,而是foo作用域 h = tf.get_variable('h', [1]) g = v + w + l + h
with tf.variable_scope('abc'): a = tf.get_variable('a', [1], initializer=tf.constant_initializer(5.0)) b = a + g
sess.run(tf.global_variables_initializer()) print("v-{},{}".format(v.name, v.eval())) print("w-{},{}".format(w.name, w.eval())) print("l-{},{}".format(l.name, l.eval())) print("h-{},{}".format(h.name, h.eval())) print("g-{},{}".format(g.name, g.eval())) print("a-{},{}".format(a.name, a.eval())) print("b-{},{}".format(b.name, b.eval())) v-foo/v:0,[4.] w-foo/w:0,[3.] l-foo/bar/l:0,[4.] h-foo/h:0,[4.] g-foo/bar/foo/add_2:0,[15.] a-abc/a:0,[5.] b-abc/add:0,[20.] |
同时,TensorFlow中的name_score和variable_score是两个不同的东西,name_score的主要作用是为op_name前加前缀,variable_score是为get_variable创建的变量的名字加前缀。简单来讲:使用tf.Variable创建的变量受name_score和variable_score的的效果,会给变量添加前缀,但是使用tf.get_variable创建变量只受variable_score的效果。
name_score的主要作用就是:Tensorflow中常常会有数以千计的节点,在可视化的过程中很难一下子展示出来,因此用name_scope为变量划分范围,在可视化中,这表示在计算图中的一个层级。name_scope会影响op_name,不会影响用get_variable()创建的变量,而会影响通过Variable()创建的变量。
注意:variable_score内部会创建一个同名的name_score
tf.variable_score参数中,可以给定当前作用域中默认的初始化器initializer,
并且子作用域会直接继承父作用域的相关参数(是否重用、默认初始化器等)
TensorBoard通过读取TensorFlow的事件文件来运行,TensorFlow的事件文件
包括了在TensorFlow运行中涉及到的主要数据,比如:scalar、image、audio、
histogram和graph等。
通过tf.summary相关API,将数据添加summary中,然后在Session中执行这些
操作得到一个序列化Summary protobuf对象,然后使用FileWriter对象将汇总
的序列数据写入到磁盘,然后使用tensorboard命令进行图标展示,默认访问端口是:6006
TensorBoard中支持结构视图和设备视图
TensorBoard显示的时候,必须给定对应的数据聚合文件路径信息(参数:--logdir)。
python -m tensorflow.tensorboard --logdir
python -m tensorflow.tensorboard --logdir C:\workspace\python\logs
tensorboard --logdir C:\workspace\python\logs
Fatal error in launcher: Unable to create process using \Scripts\tensorboard.exe" --logdir C:\workspace\python\result'
http://localhost XXX
import tensorflow as tf # # 可视化 with tf.variable_scope("foo"): with tf.device("/cpu:0"): x_init1 = tf.get_variable('init_x', [10], tf.float32, initializer=tf.random_normal_initializer())[0] x = tf.Variable(initial_value=x_init1, name='x') y = tf.placeholder(dtype=tf.float32, name='y') z = x + y
# update x assign_op = tf.assign(x, x + 1) with tf.control_dependencies([assign_op]): with tf.device('/gpu:0'): out = x * y
with tf.device('/cpu:0'): with tf.variable_scope("bar"): a = tf.constant(3.0) + 4.0 w = z * a
# 开始记录信息(需要展示的信息的输出) tf.summary.scalar('scalar_init_x', x_init1) tf.summary.scalar(name='scalar_x', tensor=x) tf.summary.scalar('scalar_y', y) tf.summary.scalar('scalar_z', z) tf.summary.scalar('scala_w', w) tf.summary.scalar('scala_out', out)
with tf.Session(config=tf.ConfigProto(log_device_placement=True, allow_soft_placement=True)) as sess: # merge all summary merged_summary = tf.summary.merge_all() # 得到输出到文件的对象 writer = tf.summary.FileWriter('./result', sess.graph)
# 初始化 sess.run(tf.global_variables_initializer()) # print for i in range(1, 5): summary, r_out, r_x, r_w = sess.run([merged_summary, out, x, w], feed_dict={y: i}) writer.add_summary(summary, i) print("{},{},{}".format(r_out, r_x, r_w))
# 关闭操作 writer.close() |
tensorboard很好,但是不能用,待解决?
tensorflow的线程和队列
在TensorFlow进行异步计算的时候,队列是一种强大的机制。和TensorFlow中
的其它组件一样,队列就是TensorFlow图中的节点。这是一种有状态的节点,
和变量一样。其它节点可以修改它的内容,比如:将新元素添加到队列后端,也可以把队列前端的元素删除。
TensorFlow常见队列:FIFOQueue:先进先出队列;RandomShuffleQueue:随机混淆队列
队列使用的常见结构:
多个线程准备训练数据,并将这些数据推入队列中一个训练线程执行一个训练操作,此操作会从队列中移除最小批次的数据(mini batches)
TensorFlow的Session对象是支持多线程的,因此多个线程可以比较方便的使用同一个Session并且并行的执行操作。但是,在Python程序实现这样的并行运算并不容易,所有线程必须被同步的终止,异常必须被正确的捕获并报告,会话终止的时候,队列必须对正确的关闭。
针对这个问题,TensorFlow提供了两个类来帮助多线程的实现:tf.Coordinator和tf.QueueRunner。
Coordinator类可以用来停止多个工作线程并且向那个在等待所有工作线程终止的线程发送异常报告
QueueRunner类用来协调多个工作线程同时将多个张量推入一个队列中
# 模型保存 v1 = tf.Variable(tf.constant(3.0), name='v1') v2 = tf.Variable(tf.constant(4.0), name='v2') result = v1 + v2
saver = tf.train.Saver() with tf.Session() as sess: sess.run(tf.global_variables_initializer()) sess.run(result) # 模型保存到model文件夹下,文件前缀为:model.ckpt saver.save(sess, './model/model.ckpt')
# 模型的提取(完整提取:需要完整恢复保存之前的数据格式) v1 = tf.Variable(tf.constant(1.0), name='v1') v2 = tf.Variable(tf.constant(4.0), name='v2') result = v1 + v2
saver = tf.train.Saver() with tf.Session() as sess: # 会从对应的文件夹中加载变量、图等相关信息 saver.restore(sess, './model/model.ckpt') print(sess.run([result])) |
# 直接加载图,不需要定义变量了 saver = tf.train.import_meta_graph('./model/model.ckpt.meta')
with tf.Session() as sess: saver.restore(sess, './model/model.ckpt') print(sess.run(tf.get_default_graph().get_tensor_by_name("add:0"))) |
# 模型的提取(给定映射关系) a = tf.Variable(tf.constant(1.0), name='a') b = tf.Variable(tf.constant(2.0), name='b') result = a + b
saver = tf.train.Saver({"v1": a, "v2": b}) with tf.Session() as sess: # 会从对应的文件夹中加载变量、图等相关信息 saver.restore(sess, './model/model.ckpt') print(sess.run([result])) |
构建服务之后,使用:
import tensorflow as tf import numpy as np # 1. 构建图 with tf.device('/job:ps/task:0'): # 2. 构造数据 x = tf.constant(np.random.rand(100).astype(np.float32)) # 3. 使用另外一个机器 with tf.device('/job:work/task:1'): y = x * 0.1 + 0.3 # 4. 运行 with tf.Session(target='grpc://127.0.0.1:33335', config=tf.ConfigProto(log_device_placement=True, allow_soft_placement=True)) as sess: print(sess.run(y)) |
TensorFlow中主要包含两个方面,第一:对不同数据大小进行计算的任务(work作业),第二:用于不停更新共享参数的任务(ps作业)。这样任务都可以运行不同在机器上,在TensorFlow中,主要实现方式如下:
图内的拷贝(In-Graph Replication)
图间的拷贝(Between-Graph Replication)
异步训练(Asynchronous Training)
同步训练(Synchronous Training)
回顾激活函数、梯度下降方法。
# -- encoding:utf-8 -- """ Create by ibf on 2018/5/6 """
import numpy as np import tensorflow as tf
# TODO: 大家自己画一下图代码实现 # 1. 构造一个数据 np.random.seed(28) N = 100 x = np.linspace(0, 6, N) + np.random.normal(loc=0.0, scale=2, size=N) y = 14 * x - 7 + np.random.normal(loc=0.0, scale=5.0, size=N) # 将x和y设置成为矩阵 x.shape = -1, 1#行不确定,1列 y.shape = -1, 1
# 2. 模型构建 # 定义一个变量w和变量b # random_uniform:(random意思:随机产生数据, uniform:均匀分布的意思) ==> 意思:产生一个服从均匀分布的随机数列 # shape: 产生多少数据/产生的数据格式是什么; minval:均匀分布中的可能出现的最小值,maxval: 均匀分布中可能出现的最大值 w = tf.Variable(initial_value=tf.random_uniform(shape=[1], minval=-1.0, maxval=1.0), name='w') b = tf.Variable(initial_value=tf.zeros([1]), name='b') # 构建一个预测值 y_hat = w * x + b
# 构建一个损失函数 # 以MSE作为损失函数(预测值和实际值之间的平方和) loss = tf.reduce_mean(tf.square(y_hat - y), name='loss')
# 以随机梯度下降的方式优化损失函数 optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.05) # 在优化的过程中,是让那个函数最小化 train = optimizer.minimize(loss, name='train')
# 全局变量更新 init_op = tf.global_variables_initializer()
# 运行 def print_info(r_w, r_b, r_loss): print("w={},b={},loss={}".format(r_w, r_b, r_loss))
with tf.Session() as sess: # 初始化 sess.run(init_op)
# 输出初始化的w、b、loss #r_w, r_b, r_loss = sess.run([w, b, loss]) #print_info(r_w, r_b, r_loss)
# 进行训练(n次) for step in range(100): # 模型训练 sess.run(train) # 输出训练后的w、b、loss r_w, r_b, r_loss = sess.run([w, b, loss]) print_info(r_w, r_b, r_loss) |
分布式,between-graph 异步 |
import numpy as np import tensorflow as tf
np.random.seed(28)
# TODO: 将这个代码整理成为单机运行的
# 1. 配置服务器相关信息 # 因为tensorflow底层代码中,默认就是使用ps和work分别表示两类不同的工作节点 # ps:变量/张量的初始化、存储相关节点 # work: 变量/张量的计算/运算的相关节点 ps_hosts = ['127.0.0.1:33331', '127.0.0.1:33332'] work_hosts = ['127.0.0.1:33333', '127.0.0.1:33334', '127.0.0.1:33335'] cluster = tf.train.ClusterSpec({'ps': ps_hosts, 'work': work_hosts})
# 2. 定义一些运行参数(在运行该python文件的时候就可以指定这些参数了) tf.app.flags.DEFINE_integer('task_index', default=0, help="Index of task within the job") FLAGS = tf.app.flags.FLAGS
# 3. 构建运行方法 def main(_): # 图的构建 with tf.device( tf.train.replica_device_setter(worker_device='/job:work/task:%d' % FLAGS.task_index, cluster=cluster)): # 构建一个样本的占位符信息 x_data = tf.placeholder(tf.float32, [10])#批量梯度下降 y_data = tf.placeholder(tf.float32, [10])
# 定义一个变量w和变量b # random_uniform:(random意思:随机产生数据, uniform:均匀分布的意思) ==> 意思:产生一个服从均匀分布的随机数列 # shape: 产生多少数据/产生的数据格式是什么; minval:均匀分布中的可能出现的最小值,maxval: 均匀分布中可能出现的最大值 w = tf.Variable(initial_value=tf.random_uniform(shape=[1], minval=-1.0, maxval=1.0), name='w') b = tf.Variable(initial_value=tf.zeros([1]), name='b') # 构建一个预测值 y_hat = w * x_data + b
# 构建一个损失函数 # 以MSE作为损失函数(预测值和实际值之间的平方和) loss = tf.reduce_mean(tf.square(y_hat - y_data), name='loss')
global_step = tf.Variable(0, name='global_step', trainable=False) # 以随机梯度下降的方式优化损失函数 optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.05) # 在优化的过程中,是让那个函数最小化 train = optimizer.minimize(loss, name='train', global_step=global_step)
# 图的运行 hooks = [tf.train.StopAtStepHook(last_step=10000000)] with tf.train.MonitoredTrainingSession( master='grpc://' + work_hosts[FLAGS.task_index], is_chief=(FLAGS.task_index == 0), # 是否进行变量的初始化,设置为true,表示进行初始化 checkpoint_dir='./tmp', save_checkpoint_secs=None, hooks=hooks # 给定的条件 ) as mon_sess: while not mon_sess.should_stop(): N = 10 train_x = np.linspace(0, 6, N) + np.random.normal(loc=0.0, scale=2, size=N) train_y = 14 * train_x - 7 + np.random.normal(loc=0.0, scale=5.0, size=N) _, step, loss_v, w_v, b_v = mon_sess.run([train, global_step, loss, w, b], feed_dict={x_data: train_x, y_data: train_y}) if step % 100 == 0: print('Step:{}, loss:{}, w:{}, b:{}'.format(step, loss_v, w_v, b_v))
if __name__ == '__main__': tf.app.run() |
python test5.py --task_index 0 另一个shell python test5.py --task_index 1 |
常见API,不同版本tf,API稍有不同
https://github.com/tensorflow/docs/blob/r1.4/site/en/api_docs/api_docs/python/tf/FixedLenFeature.md
https://tensorflow.google.cn/api_docs/cc