TensorFlow入门教程

简介

  深度学习的框架有很多:TensorFlow、Caffe、Theano、Torch...TensorFlow作为谷歌重要的开源项目,有非常火热的开源的开源社区推动着开源项目的发展,它能让项目有旺盛的生命力并在生命周期中不断涌现新的功能并以较快的迭代来更新Bug修复。Keras是在TensorFlow基础上构建的高层API,Keras在TensorFlow中。

  Tensorflow中实现代码可能跟我们python程序有那么一点不一样,因为tensorflow有他自己的框架和体系,会用自己更加适配的方式来表达描述过程。

基本用法

tensorflow的程序通常被组织成两个相互独立的阶段,一个构建计算图(tf.Graph)的阶段,一个运行计算图(tf.Session)的阶段

构建计算图阶段:由张量操作,张量Tensor主要保存了3个属性: 名字(name)、维度(shape)、类型(type);操作OP,图中的节点。

运行计算图阶段:使用会话执行构建好的图中的操作

  TensorFlow图描述了计算的过程。为了进行计算, 图必须在会话里被启动会话将图的OP分发到诸如CPU或GPU之类的设备上, 同时提供执行OP的方法。这些方法执行后, 将产生的tensor返回。

复制代码
import tensorflow as tf

# 构建加法 计算图
a = tf.constant(2.0, dtype=tf.float32)
b = tf.constant(3.0)
c = tf.add(a, b)
print("a", a)        # a Tensor("Const:0", shape=(), dtype=float32)
print("b", b)        # b Tensor("Const_1:0", shape=(), dtype=float32)
print("c", c)        # c Tensor("add:0", shape=(), dtype=int32)

# 开启会话,在会话中运行计算图
with tf.Session() as sess:
    c_t = sess.run(c)   # 把run之后的结果保存在c_t中
    print(sess.run(b))        # 3.0
    print("在会话中run后的加法结果", c_t)     # 5
复制代码

以上的图中,有是三个节点,两个constant节点,一个add节点,为了得到加法结果,再次强调我们必须在会话中run这个图

计算图(graph)

图中包含了操作(tf.Operation)和数据(tf.Tensor)

默认图

通常TensorFlow会默认帮我们创建一张图,

查看默认图有两种方法:

1、default_g = tf.get_default_graph()  # 创建一个默认图的实例,绑定在default_g

2、op、sess都有graph属性,默认在一张图中

a.graph    # <tensorflow.python.framework.ops.Graph object at 0x000001E3D5D12940>

sess.graph  # <tensorflow.python.framework.ops.Graph object at 0x000001E3D5D12940>

创建图

new_g = tf.Graph()    创建一张新的图的实例,绑定在new_g

如果要在这张图上定义数据和操作,可以使用new_g.as_default(),上下文管连器

要在tf.session(graph=new_g)选择自定义的图

复制代码
# 自定义图
new_g = tf.Graph()
# 在自己的图中定义数据和操作
with new_g.as_default():
    a_new = tf.constant([[20]])

# 开启new_g的会话
with tf.Session(graph=new_g) as new_sess:
    a_new_value = new_sess.run(a_new)
    print("新的图的a的值", a_new_value)
复制代码

会话(Session)

要评估张量,需要实例化一个tf.Session()对象,在会话中,调用 run 方法来运行图节点以及查看张量,

sess.run(a) 和Tensor.eval(a) 返回与张量内容相同的numpy 数组

Tensor.eval方法和sess.run()仅在tf.Session处于活跃时才起作用。

with tf.Session() as sess:  # 启动默认图
    print(a.eval())  # 3
    print(sess.run(a))  # 3

会话有两种开启的方式

1、tf.Session()

2、tf.InteractiveSession(),用于在交互模式中打开会话,ipython,shell,jupyter Notebook。

Session在使用完后需要释放资源,除了使用sess.close()外,一般使用“with代码块”来自动关闭。

 

tf.Session(graph=None, config=None)

graph=new_graph  # new_graph是自定义创建的新的图的对象实例

config:清晰地显示操作运行在哪些设备上  如果想要知道设备信息,把config设置成config = tf.ConfigProto(allow_soft_placement=True, log_device_placement=True)

会话的run()

run(fetches, feed_dict=None, options=None, run_metadata=None)

fetches:单一的operation,或者元组operation、列表operation

a = tf.constant(2.)
b = tf.constant(3.)
c = a+b

sess = tf.Session()
s = sess.run(c)
print(s)
print(c.eval(session=sess))
View Code

feed_dict:参数允许调用者覆盖图中张量的值,运行时赋值。

    与tf.placeholder()配合使用,则会检测值的形状是否与占位符匹配。

我们可以通过sess.run取回多个tensor

input1 = tf.constant(3.0)
input2 = tf.constant(2.0)
input3 = tf.constant(5.0)
intermed = tf.add(input2, input3)
mul = tf.mul(input1, intermed)

with tf.Session():
  result = sess.run([mul, intermed])
  print result

# 输出:
# [array([ 21.], dtype=float32), array([ 7.], dtype=float32)]
View Code

feed操作

使用 tf.placeholder() 为这些操作创建占位符,run时候通过feed_dict指定参数替换占位符。

复制代码
a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
c = tf.add(a,b)

with tf.Session() as sess:
    re = sess.run(c, feed_dict={a:1, b:2.5})
    print(re)        # 3.5
    print(sess.run(c, feed_dict={a:[1., 3.], b:[2., 3.]}))    # [3. 6.]
复制代码

Tensor 张量

张量Tensor有3个属性: 名字(name)、维度(shape)、类型(type);

0 阶张量

一个数字的大小

mammal = tf.Variable("Elephant", tf.string)
ignition = tf.Variable(451, tf.int16)
floating = tf.Variable(3.14159265359, tf.float64)
its_complicated = tf.Variable(12.3 - 4.85j, tf.complex64)

1 阶张量

mystr = tf.Variable(["Hello"], tf.string)
cool_numbers  = tf.Variable([3.14159, 2.71828], tf.float32)
first_primes = tf.Variable([2, 3, 5, 7, 11], tf.int32)
its_very_complicated = tf.Variable([12.3 - 4.85j, 7.5 - 6.23j], tf.complex64)

2 阶张量

mymat = tf.Variable([[7],[11]], tf.int16)
myxor = tf.Variable([[False, True],[True, False]], tf.bool)
linear = tf.Variable([[4], [9], [16], [25]], tf.int32)
squarish = tf.Variable([ [4, 9], [16, 25] ], tf.int32)
rank = tf.rank(squarish_squares)

在图像处理的过程中,会使用许多4阶张量,维度对应批次大小、图像宽度、图像高度和颜色通道。

my_image = tf.zeros([10, 299, 299, 3])  # batch x height x width x color

改变形状:tf.reshape(x, shape)

three = tf.ones([3, 4, 5])
matrix = tf.reshape(three, [6, 10])  #重塑成 6*10 
matrixB = tf.reshape(matrix, [3, -1])  # 重塑成 3x20 

切片索引的时候[3, -1]列表示重塑成3行任意列。

constant 常量 Tensor

生成0的张量函数  tf.zeros(shape=[2,2], dtypt=tf.float32, namhanghe=None)  

生成1的张量函数  tf.ones(shape=[2,2], dtypt=tf.float32, namhanghe=None)

生成都是value值的dims形状的张量  tf.fill(dims, value, name=None)

import tensorflow as tf
t1 = tf.fill([2,3], 3)
sess = tf.Session()
print(sess.run(t1))

# [[3 3 3]
#  [3 3 3]]
View Code

生成常数   tf.constant(value, dtype=None, Shape=None, name="Const")

numpy数据转换为tensorflow数据:data_tensor= tf.convert_to_tensor(data_numpy)

tensorflow数据转换为numpy数据:data_numpy = data_tesor.eval()在会话中运行

random 随机 Tensor

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)

  shape表示生成张量的维度,mean是均值,stddev是标准差。这个函数产生截断的正太分布,就是说产生正太分布的值与均值的差值大于两倍的标准差,那就重新生成。和一般的正太分布的产生随机数据比起来,这个函数产生的随机数与均值的差距不会超过两倍的标准差,但是一般的别的函数是可能的。

tf.random_uniform(shape, minval=0, maxval=None, dtype=tf.float32, seed=None, name=None)

  从均匀分布中返回随机值,shape形状、minval最小值、maxval最大值
tf.random_shuffle(value, seed=None, name=None)

  沿着要被洗牌的张量的第一个维度,随机打乱。value要洗牌的张量

initialize 初始化Tensor

tf.constant_initializer(value=0, dtype=tf.float32)

  也可以简写为tf.Constant(),初始化为常数,这个非常有用,通常偏置项就是用它初始化的。

  由它衍生出的两个初始化方法:

  1. tf.zeros_initializer(shape, dtype=tf.float32, partition_info=None)
  2. tf.ones_initializer(dtype=tf.float32, partition_info=None)
  3. tf.constant_initializer(0),tf.Constant(0)

tf.truncated_normal_initializer(mean=0.0, stddev=1.0, seed=None, dtype=tf.float32)

  也可简写为tf.TruncatedNormal(),生成截断正态分布的随机数,这个初始化方法好像在tf中用得比较多。
tf.random_normal_initializer(mean=0.0, stddev=1.0, seed=None, dtype=tf.float32)

  用正态分布产生张量的初始化器,mean均值、stddev方差、seed随机种子、dtype数据类型。

tf.random_uniform_initializer(minval=0, maxval=None, seed=None, dtype=tf.float32)

  初始化均匀分布的随机Tensor,参数分别用于指定minval最小值、maxval最大值、seed随机数种子、dtype类型。

tf.cast(x, dtype, name=None)  # 把张量x,变成任何的dtype

变量

变量也是张量的一种

创建变量 variable;get_variable

tensorflow中创建变量的函数有tf.get_variabletf.Variable

tf.get_variable(name, validate_shape=True, dtype=None, initializer=None, trainable=True, collections=None, caching_device=None, regularizer=None, partitioner=None, custom_getter=None, shape=None)

  • name:      变量名(必须设置)
  • initializer:   初始化的值
  • trainable:   是否能被训练
  • shape:      形状

例如:创建一个名为“my_variable”的变量,shape为[1,2,3]的三维张量。默认情况下dtype=tf.float32

my_int_variable = tf.get_variable("my_int_variable", shape=[1, 2, 3], dtype=tf.int32, initializer=tf.zeros_initializer)

我们还可以将Tensor变量作为初始化对象,但此时我们不能初始化形状,而需要使用初始化张量的形状

other_variable = tf.get_variable("other_variable", dtype=tf.int32,
  initializer=tf.constant([23, 42]))

使用tf.Varizble 创建变量

tf.Variable(name=None, validate_shape=True, dtype=None, initial_value=None, trainable=True, collections=None, caching_device=None, variable_def=None, expected_shape=None, import_scope=None)

  • dtype:      数据类型
  • initial_value:  初始化的值
  • trainable:    是否能被训练
v = tf.get_variable("v", shape=(), initializer=tf.zeros_initializer())
w = v + 1   # 这样一来w也是tf.Tensor

我们可以使用assign、assign_add方法为变量tf.Variable赋值

import tensorflow as tf
# 创建一个变量, 初始化为标量 0.
state = tf.Variable(0, name="counter")
one = tf.constant(1)
v = tf.get_variable("v", shape=(), initializer=tf.zeros_initializer())

assignment = v.assign_add(1)    # 变量加1
new_value = tf.add(state, one)  # new_value = state + 1
update = tf.assign(state, new_value)    # state = new_value 只是在描绘图,并不会真正的执行

# 启动图后, 变量必须先经过'初始化'(init)
init = tf.global_variables_initializer()

# 启动图, 运行 op
with tf.Session() as sess:
  sess.run(init)    # 运行 'init' 
  print(sess.run(state))    # 打印'state'的初始值 0
  print(sess.run(assignment))    # assignment.eval()
  # 运行 op, 更新 'state', 并打印 'state'
  for _ in range(3):
    sess.run(update)
    print(sess.run(state))

# 0
# 1
# 2
# 3
View Code

区别1、使用tf.Variable时候,如果检测到命名冲突,系统会自己处理。使用tf.get_variable()时,系统不会处理相同变量名的冲突,而会报错。

tf.Variable()    创建变量

w_1 = tf.Variable(3, name="w_1")
w_2 = tf.Variable(1, name="w_1")
print(w_1.name)     # w_1:0
print(w_2.name)     # w_1:0

tf.get_variable()  创建变量

w_1 = tf.get_variable(name="w_1", initializer=1)
w_2 = tf.get_variable(name="w_1", initializer=2)

# ValueError: Variable w_1 already exists, disallowed. Did you mean to set reuse=True in VarScope?

区别2、tf.Variable()每次都在创建新对象,所以reuse=True和它没有什么关系,对于get_vatiable(),如果是一个已经创建的变量对象,就把那个对象返回,如果是之前没有创建的变量对象的话,就创建一个新的。

复制代码
with tf.variable_scope("scope1"):
    w1 = tf.get_variable("w1", shape=[])
    w2 = tf.Variable(0.0, name="w2")
with tf.variable_scope("scope1", reuse=True):
    w1_p = tf.get_variable("w1", shape=[])
    w2_p = tf.Variable(1.0, name="w2")

print(w1 is w1_p)   # True  w1和w1_p 指向同一个对象
print(w2 is w2_p)   # False w2和w2_p 指向不同对象
复制代码

代码中创建了变量的,“变量”必须经过初始化,然后在会话中运行下面一段进行初始化,一次性初始化所有变量,初始化后,才能调用与显示。

复制代码
a = tf.Variable(initial_value=50)
b = tf.Variable(initial_value=50)
c = tf.add(a, b)

init = tf.global_variables_initializer()    # 初始化变量

with tf.Session() as sess:      # 开启会话
    sess.run(init)      # 允许初始化
    a_value, b_value, c_value = sess.run([a,b,c])
    print("a_value",a_value)
    print("b_value", b_value)
    print("c_value", c_value)
复制代码

tf.global_variables_initializer不会指定变量的初始化顺序,因此如果变量的初始值取决另一个变量的值,那么很有可能出现错误,所以我们最好使用variable.initialized_value(),而非veriable,也就是在创建变量的时候给变量初始化。

v = tf.get_variable("v", shape=(), initializer=tf.zeros_initializer())
w = tf.get_variable("w", initializer=v.initialized_value() + 1)

当然我们也可以自行初始化变量

session.run(my_variable.initializer)
my_variable.initializer.run()

tf.add_to_collection:把变量放入一个集合,把很多变量变成一个列表

tf.get_collection:从一个列表中取出全部变量,是一个列表

tf.add_n:把一个列表的东西都依次加起来

复制代码
import tensorflow as tf
 
v1 = tf.get_variable(name='v1', shape=[1], initializer=tf.constant_initializer(0))
tf.add_to_collection('loss', v1)
v2 = tf.get_variable(name='v2', shape=[1], initializer=tf.constant_initializer(2))
tf.add_to_collection('loss', v2)

init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)
    print(tf.get_collection("loss"))
    # [<tf.Variable 'v1:0' shape=(1,) dtype=float32_ref>, 
    # <tf.Variable 'v2:0' shape=(1,) dtype=float32_ref>]
    print(sess.run(tf.add_n(tf.get_collection("loss"))))    # [2.]
复制代码

变量命名空间 variable_scope;tf.name_scope

tensorflow中创建变量命名空间域的函数有   tf.name_scope;tf.variable_scope

使用tf.variable_scope()修改变量的命名空间,使得代码的结构更加清晰,还能够使得TensorBoard更加整洁。同时给变量取名name也可以使得TensorBoard更加整洁。

首先看看比较简单的tf.name_scope("scope_name")

tf.name_scope主要结合tf.Variable()来使用,它的主要目的是为了方便管理参数命名。

复制代码
import tensorflow as tf

with tf.name_scope('conv1'):
    weights1 = tf.Variable([1.0, 2.0], name='weights')
    bias1 = tf.Variable([0.3], name='bias')

# 下面是在另外一个命名空间来定义变量的
with tf.name_scope('conv2'):
    weights2 = tf.Variable([4.0, 2.0], name='weights')
    bias2 = tf.Variable([0.33], name='bias')

# 所以,实际上weights1 和 weights2 这两个引用名指向了不同的空间,不会冲突
print(weights1.name)        # conv1/weights:0
print(weights2.name)        # conv2/weights:0

# 这时候如果再次执行上面的代码,就会再生成其他命名空间
with tf.name_scope('conv1'):
    weights1 = tf.Variable([1.0, 2.0], name='weights')
    bias1 = tf.Variable([0.3], name='bias')

with tf.name_scope('conv2'):
    weights2 = tf.Variable([4.0, 2.0], name='weights')
    bias2 = tf.Variable([0.33], name='bias')

print(weights1.name)        # conv1_1/weights:0
print(weights2.name)        # conv2_1/weights:0
复制代码

我们再来看看tf.variable_scope("scope_name")

tf.variable_scope()主要结合tf.get_variable()来使用,实现 变量共享。

复制代码
with tf.variable_scope('v_scope'):
    Weights1 = tf.get_variable('Weights', shape=[2,3])
    bias1 = tf.get_variable('bias', shape=[3])

# 下面来共享上面已经定义好的变量
# 在下面的 scope 中的get_variable()变量必须经过get_variable()定义过了,才能设置 reuse=True,否则会报错reuse=True,否则会报错
with tf.variable_scope('v_scope', reuse=True):
    Weights2 = tf.get_variable('Weights')

print(Weights1.name)    # v_scope/Weights:0
print(Weights2.name)    # v_scope/Weights:0
复制代码

  我们可以看到这两个变量命名空间名都是 v_scope,reuse=True只是让后一个v_scope重用上一个v_scope的所有变量。在后一个v_scope中定义的变量,必须是已经在上一个v_scope中经过get_variable定义过的,否则会报错。tf.Variable()每次都在创建新对象,而tf.get_variable()如果变量存在,则使用以前创建的变量,如果不存在,则新创建一个变量

从输出我们可以看出来,这两个引用名称指向的是同一个内存对象

  共享变量有两种方法

# 方法一
with tf.variable_scope("name") as scope:
    scope.reuse_variables()
# 方法二
with tf.variable_scope("name", reuse=True):
    scope.reuse_variables()
View Code

我们同时使用Variable和get_variable看看输出结果:

复制代码
with tf.variable_scope('v_scope') as scope1:
    Weights1 = tf.get_variable('Weights', shape=[2,3])
    bias1 = tf.Variable([0.52], name='bias')

# 下面来共享上面已经定义好的变量
with tf.variable_scope('v_scope', reuse=True) as scope2:
    Weights2 = tf.get_variable('Weights')
    bias2 = tf.Variable([0.52], name='bias')

print(Weights1.name)        # v_scope/Weights:0
print(Weights2.name)        # v_scope/Weights:0
print(bias1.name)           # v_scope/bias:0
print(bias2.name)           # v_scope_1/bias:0
复制代码

如果reuse=True的scope中的变量没有经过get_variable定义,则会报错。

复制代码
with tf.variable_scope('v_scope') as scope1:
    Weights1 = tf.get_variable('Weights', shape=[2,3])
    bias1 = tf.Variable([0.52], name='bias')        # bias1 的定义方式是使用Variable

print(Weights1.name)        # v_scope/Weights:0
print(bias1.name)           # v_scope/bias:0

# 下面来共享上面已经定义好的变量
# 在下面的 scope 中的get_variable()变量必须经过get_variable()定义过了,才能设置 reuse=True,否则会报错
with tf.variable_scope('v_scope', reuse=True) as scope2:
    Weights2 = tf.get_variable('Weights')
    bias2 = tf.get_variable('bias', [1])  # ‘bias

print(Weights2.name)
print(bias2.name)

# Variable v_scope/bias does not exist, or was not created with tf.get_variable()
复制代码

总结:如果我们使用tf.variable_scope定义变量命名空间,尽量使用tf.get_variable创建变量

TensorFlow里面的变量OP

常见的tensorflow的OP

类型

实例

标量运算

add、sub、mul、div、exp、log、greater、less、equal

向量运算

concat、slice、splot、constant、rank、spape、shuffle、

矩阵运算

matmul、matrixinverse、matrixdateminant

带状态的运算

Variable、assgin、assginadd

神经元组件

softmax、sigmoid、relu、convolution、max_pool

存储、恢复

Save、Restroe

队列与同步运算

Equeue、Dequeue、MutexAxquire、MutexRelease

控制流

Merge、Switch、Enter、Leave、Nextiteration

 

用tensorflow做一个简单的线性回归

import tensorflow as tf

# .rand生成一个[0~1]之间2行100列的数组
# .randn生成服从正态分布的数组
x_data = tf.random_normal(shape=[100,1])
y_data = tf.matmul(x_data, [[0.4]]) + 5

# 构造一个线性模型
b = tf.Variable(initial_value=tf.random_normal(shape=[1, 1]))
W = tf.Variable(initial_value=tf.random_normal(shape=[1, 1]))
y = tf.matmul(x_data, W) + b

# 最小化方差
loss = tf.reduce_mean(tf.square(y - y_data))
# 设置学习率0.5的梯度下降算法,求最小值
optimizer = tf.train.GradientDescentOptimizer(0.01).minimize(loss)
init = tf.global_variables_initializer()    # 初始化变量

# 开启会话
with tf.Session() as sess:
    sess.run(init)
    print("训练前的w: %f 和b:%f" % (W.eval(), b.eval()))
    for i in range(0, 1000):
        sess.run(optimizer)
        if i % 20 == 0:     # 每20次打印一次
            print("第 %d 次训练前的w: %f 和b:%f 损失值%f" % (i, W.eval(), b.eval(), loss.eval()))
View Code

TensorBoard:可视化学习

TensorFlow是tensorflow的可视化工具,实现程序可视化的过程

1、数据序列化-events文件

在会话中写入事件文件,然后在path路径创建一个even文件

tf.summary.FileWriter("path", graph=sess.graph)

  • path  事件文件的写入地址
  • graph 选择描绘的计算图,graph=sess.graph 或者 graph=tf.get_default_graph() 选择的都是默认图
复制代码
import tensorflow as tf 

a = tf.constant(20, name="a")
b = tf.constant(30, name="b")
c = a + b

with tf.Session() as sess:
    c = sess.run(c)
    writer = tf.summary.FileWriter("./", sess.graph)  # 写入事件文件
    writer.close()  # 写完之后最后要记得关闭
复制代码

2、启动TensorBoard

在cmd中或者Git Bash中运行 tensorboard --logdir="path"

然后在谷歌浏览器中 localhost:6006 就可以看到图了

我们来看一个更复杂的TensorBoard图,代码如下

# 实现一个线性回归
import tensorflow as tf

# 准备数据
X = tf.random_normal(shape=[100, 1])
y_true = tf.matmul(X, [[0.8]]) + 0.7

# 构建线性模型的tensor变量Weight, bias
Weight = tf.Variable(initial_value=tf.random_normal(shape=[1, 1]))
bias = tf.Variable(initial_value=tf.random_normal(shape=[1, 1]))
y_predict = tf.matmul(X, Weight) + bias

# 构建损失方程,优化器及训练模型操作train
loss = tf.reduce_mean(tf.square(y_predict - y_true))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.5)
train = optimizer.minimize(loss)

init = tf.initialize_all_variables()     # 构建变量初始化操作init

with tf.Session() as sess:
    sess.run(init)
    writer = tf.summary.FileWriter("./", sess.graph)

    for step in range(1000):
        sess.run(train)
        if step % 20 == 0:     # 每20次打印一次
            print(step, sess.run(Weight), sess.run(bias))

    writer.close()
View Code

3、增加变量显示功能

目的:在TensorBoard中观察模型参数、损失值等变量的变化

步骤:

1、收集变量

  tf.summary.scalar(name="", tensor)  # 收集对于对于损失函数和准确率等单值变量,tensor为要收集的tnesor对象

  tf.summary.histogram(name="", tensor)    # 收集高维度的变量

  tf.summaty.image(name="", tensor)      # 收集输入的图片张量

2、合并变量并写入事件文件

  1、合并变量:merged = tf.summary.merge_all() 

  2、在会话中创建事件文件:event_file = tf.summary.FileWriter("./", sess.graph) # 创建事件文件

  3、在会话中运行合并操作:summary = sess.run(merged)      # 每次迭代都需要运行

  4、将每次迭代后的变量写入事件文件:event_file.add_summary(summary, step)    # step表示第几次运行

  5、最后记得关闭事件文件:event_file.close()

# 实现一个线性回归
import tensorflow as tf

# 准备数据
X = tf.random_normal(shape=[100, 1])
y_true = tf.matmul(X, [[0.8]]) + 0.7

# 构建线性模型的tensor变量Weight, bias
Weight = tf.Variable(initial_value=tf.random_normal(shape=[1, 1]))
bias = tf.Variable(initial_value=tf.random_normal(shape=[1, 1]))
y_predict = tf.matmul(X, Weight) + bias

# 构建损失方程,优化器及训练模型操作train
loss = tf.reduce_mean(tf.square(y_predict - y_true))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
train = optimizer.minimize(loss)

# 收集变量
tf.summary.scalar("error", loss)            # 收集标量
tf.summary.histogram("Weight", Weight)      # 收集高维变量
tf.summary.histogram("bias", bias)
merged = tf.summary.merge_all()             # 合并变量

init = tf.initialize_all_variables()        # 变量初始化操作

with tf.Session() as sess:
    sess.run(init)
    event_file = tf.summary.FileWriter("./", sess.graph)     # 创建事件文件

    for step in range(100):
        sess.run(train)
        if step % 20 == 0:     # 每20次打印一次
            print(step, sess.run(Weight), sess.run(bias))

        summary = sess.run(merged)                  # 运行合并变量操作
        event_file.add_summary(summary, step)       # 将每次迭代后的变量写入事件文件
    event_file.close()
View Code

菜单栏多了 scalars(标量)、distributions(分布图)、histogram(直方图)

我们先来看看scalars

我们再来看看 distributions和histogram

                    

我们可以看到,我们所看到的grapth图结构是比较乱的,我们添加变量命名空间让图结构显示的更整齐。

  

模型的保存与加载

模型保存

saver = tf.train.Saver(var_list=None, max_to_keep=5)   保存和加载模型(保存文件格式:checkpoint文件)

  • var_list:指定要保存的变量,可以作为一个dict或列表传递,如果为None,就是保存所有变量。
  • max_to_keep:保留检查点文件的数量,创建新文件时会删除旧的文件

saver.save(sess, save_path="./liner.ckpt", global_step=step)  保存模型

  • sess:会话名字
  • save_path:设定权重参数保存的路径和文件名;
  • global_step=step:将训练的次数作为后缀加入到模型名字中。

一次 saver.save() 后可以在文件夹中看到新增的四个文件,

checkpoint       记录最新的模型

***.meta        存储网络结构

***.data/***.index   存储训练好的参数

复制代码
import tensorflow as tf

v1 = tf.get_variable("v1", shape=[3], initializer=tf.zeros_initializer)
v2 = tf.get_variable("v2", shape=[5], initializer=tf.zeros_initializer)
inc_v1 = v1.assign(v1+1)        # v1变量+1
dec_v2 = v2.assign(v2-1)        # v2变量-1

init = tf.global_variables_initializer()
saver = tf.train.Saver()        # 创建Saver对象

with tf.Session() as sess:
    sess.run(init)
    inc_v1.op.run()
    dec_v2.op.run()
    for epoch in range(300):
        if epoch % 10 ==0:
            # 在会话中保存模型
            save_path = saver.save(sess, "./model/model.ckpt", global_step=epoch)
    print("Model saved in path: %s" % save_path)
复制代码

下图是训练过程中生成的几个模型文件列表

模型加载

加载模型:saver.restore(sess, "./liner.ckpt")

获取最新的模型:checkpoint = tf.train.latest_checkpoint("./model/")

复制代码
import tensorflow as tf
import os

v1 = tf.get_variable("v1", shape=[3])
v2 = tf.get_variable("v2", shape=[5])
tf.add_to_collection("variable", v1)
tf.add_to_collection("variable", v2)

def load_model(sess, ckpt):
    # ckpt是模型路径
    if os.path.isdir(ckpt):
        # 获取最新的模型
        checkpoint = tf.train.latest_checkpoint(ckpt)  # ./model/model.ckpt-290
    else:
        checkpoint = ckpt
    print(checkpoint)
    meta = checkpoint + '.meta'  # './model/model.ckpt-290.meta'
    
    saver = tf.train.import_meta_graph(meta)  # 加载graph图结构
    saver.restore(sess, checkpoint)  # 加载模型参数


with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    model_dir = "./model/"
    load_model(sess, model_dir)
    # 从变量集和名为"variable"的集和中取出变量
    a, b = tf.get_collection('variable')   
    print(a,b)

    print("模型恢复....")
    print("v1 : %s" % v1.eval())
    print("v2 : %s" % v2.eval())
复制代码

 

sv = tf.train.Supervisor(logdir="./my_dir", init_op=init)

一般我们在训练模型之前,都会检查本地是否有之前已经训练好并保存了的模型,所以会做一次if判断,但是Supervisor可以节省这一步,sv = tf.train.Supervisor(logdir=log_path, init_op=init)会判断模型是否存在.如果存在,会自动读取模型.不用显式地调用restore,具体如下

复制代码
log_path = "./Source/model/supervisor"
log_name = "linear.ckpt"

saver = tf.train.Saver()            # 创建saver
init = tf.global_variables_initializer()

sess = tf.Session()
sess.run(init)

if len(os.listdir(log_path)) != 0:  # 如果已经有模型,则直接读取
    saver.restore(sess, os.path.join(log_path, log_name))
for step in range(201):
    sess.run(train)
    if step % 20 == 0:
        print(step, sess.run(W), sess.run(b))
saver.save(sess, os.path.join(log_path, log_name))
复制代码

用Supervisor

复制代码
log_path = "./Source/model/supervisor"
log_name = "linear.ckpt"

init = tf.global_variables_initializer()

sv = tf.train.Supervisor(logdir=log_path, init_op=init)  # logdir用来保存checkpoint和summary
saver = sv.saver                  # 创建saver
sess = sv.managed_session()        # 会自动去logdir中去找checkpoint,如果没有的话,自动执行初始化

for i in range(201):
    sess.run(train)
    if i % 20 == 0:
        print(i, sess.run(W), sess.run(b))
saver.save(sess, os.path.join(log_path, log_name))
复制代码

通过checkpoint找到模型文件名

tf.train.get_checkpoint_state(checkpoint_dir,latest_filename=None)

参数:

  • checkpoint_dir:checkpoint文件的路径
  • latest_filename:指定checkpoint的名字

返回的是CheckpointState proto对象,CheckpointState proto对象有两个可用属性。

  • model_checkpoint_path:最新的chechpoint路径
  • all_model_checkpoint_paths:文件中所有的checkpoints路径列表
复制代码
ckpt = tf.train.get_checkpoint_state('./model/')
if ckpt and ckpt.model_checkpoint_path:
    print(ckpt.model_checkpoint_path)
    # ./model/model.ckpt-1000(1000是训练步数)
    print(ckpt.all_model_checkpoint_paths)
    # ['./model/model.ckpt-500', './model/model.ckpt-1000']
复制代码

 

global_step = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]

得到了global_step之后,就可以恢复模型,继续在原来的模型基础上,训练后面的步骤了。

命令行参数的使用

tensorflow支持程序从命令行接受参数,即使用tf.app.flag,tf.app.flag可以定义各种参数类型

tf.app.flag.DEFINE_integer(参数名, 默认值, 参数说明文档 字符串)

整形参数   tf.app.flag.DEFINE_integer(flag_name, default, docstring)

字符串参数  tf.app.flag.DEFINE_string(flag_name, default, docstring)

布尔值参数  tf.app.flag.DEFINE_boolean(flag_name, default, docstring)

浮点值参数  tf.app.flag.DEFINE_float(flag_name, default, docstring)

...

2、tf.app.flags,flags有一个FLAGS标志,可以调用到我们前面具体定义的参数名flag_name。

复制代码
import tensorflow as tf 

# 定义命令行参数
tf.app.flags.DEFINE_integer("step", 100, "训练模型的步数")
tf.app.flags.DEFINE_string("model_dir", "Unknown", "模型保存的路径")

FLAGS = tf.app.flags.FLAGS                  # 简化变量名

print("step:", FLAGS.step)                  # step: 100
print("model_dir:", FLAGS.model_dir)        # model_dir: Unknown
复制代码

tf.app.run()可以自动运行脚本中的main(argv)函数,如果脚本没有main(argv)函数,会报错。

  main函数中的argv参数打印出来是脚本的地址

复制代码
import tensorflow as tf 

def main(argv):
    print(argv)     # ['C:\\Users\\Never\\Desktop\\temp\\temp.py']

tf.app.run()        # 自动调用脚本中的main(argv)函数
复制代码

关于多个GPU的分类使用

TensorFlow一般你不需要显式指定使用CPU还是GPU,TensorFlow能自动检测。如果检测到 GPU,TensorFlow会尽可能地利用找到的第一个GPU来执行操作。

如果你的电脑有两个GPU,tensorflow默认是不会使用的,为了让 TensorFlow 使用这些 GPU, 你必须将 op 明确指派给它们执行. with.Device 语句用来指派特定的 CPU 或 GPU 执行操作:

with tf.Session() as sess:
  with tf.device("/gpu:1"):
    matrix1 = tf.constant([[3., 3.]])
    matrix2 = tf.constant([[2.],[2.]])
    product = tf.matmul(matrix1, matrix2)
    ...
View Code

关于IPython的tensorflow的使用

为了便于使用诸如IPython之类的Python交互环境,比如jupyter notebook。可以使用InteractiveSession代替Session 类,使用Tensor.eval()Operation.run()方法代替Session.run()。这样可以避免使用一个变量来持有会话。

# 进入一个交互式 TensorFlow 会话.
import tensorflow as tf
sess = tf.InteractiveSession()

x = tf.Variable([1.0, 2.0])
a = tf.constant([3.0, 3.0])

# 使用初始化器 initializer op 的 run() 方法初始化 'x'
x.initializer.run()

# 增加一个减法 sub op, 从 'x' 减去 'a'. 运行减法 op, 输出结果
sub = tf.subtract(x, a)
print(sub.eval())    # [-2. -1.]
View Code

运行tensorflow的时候,会出现红色警告I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2

如果不想看到这个,在脚本开始的时候,

import os
os.environ["TF_CPP_MIN_LOG_LEVEL"]= "2"
# 或者
import os
os.environ["KERAS_BACKEND"] = "tensorflow"

 

参考文献:

tensorflow中文社区

【tensorflow】tf.train.get_checkpoint_state

TensorFlow中numpy与tensor数据相互转化

 

作者:凌逆战
欢迎任何形式的转载,但请务必注明出处。
限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。
本文章不做任何商业用途,仅作为自学所用,文章后面会有参考链接,我可能会复制原作者的话,如果介意,我会修改或者删除。

 

 

 

出处:https://www.cnblogs.com/LXP-Never/p/10008693.html

posted on 2020-04-13 12:33  jack_Meng  阅读(2169)  评论(0编辑  收藏  举报

导航