TensorFlow精进之路(九):TensorFlow编程基础

1、概述


卷积部分的知识点在博客:TensorFlow精进之路(三):两层卷积神经网络模型将MNIST未识别对的图片筛选出来已经写过,所以不再赘述。这一节简单聊聊tensorflow的编程基础。

2、会话Session


Tensorflow有“图”和“会话”的概念,“图”定义一个计算任务,计算则是在“会话”中完成。从一个“Hello world”理解这个概念吧。比如在python中,想打印“Hello world”,代码如下:

str = 'Hello world!'
print(str)


运行结果:

Hello world!

Tensorflow定义常量的函数是tf.constant()

我模仿上面的代码如下:

import tensorflow as tf
a = tf.constant('hello world!')
print(a)


运行结果:

Tensor("Const:0", shape=(), dtype=string)

意不意外,惊不惊喜?

将上面的代码改成下面的代码,

 

import tensorflow as tf
a = tf.constant('hello world!')
sess = tf.Session()
print(sess.run(a))
sess.close()


运行结果:

hello world!

这才是正确的操作姿势。图只是定义了应该怎么做,而会话Session才是真正的执行。但是一般不会像上面那种写法,而是使用with语法,如下:

a = tf.constant('hello world!')
with tf.Session() as sess:
    print(sess.run(a))


这样做的好处是如果忘记手动关闭会话,或者程序崩溃时,会自动关闭会话。

那我们上面打印的Tensor("Const:0", shape=(), dtype=string)是什么鬼?

为了弄清这个东西,我们再写个小demo,如下

import tensorflow as tf
b = tf.constant([[1, 1, 1], [2, 2, 2]], name='wei')
c = tf.constant([[3, 3, 3], [4, 4, 4]], name='fang')
d = b + c
 
print(b)
print(c)
print(d)


运行结果:

Tensor("wei:0", shape=(2, 3), dtype=int32)

Tensor("fang:0", shape=(2, 3), dtype=int32)

Tensor("add:0", shape=(2, 3), dtype=int32)

可以看到,第一个参数其实就是这个常量的名字,如果不设置名字的话,会默认给它一个名字,而第二个参数就是它的形状,第三个参数就是类型。

这小节只需要记住,图只是定义操作,计算在会话中进行就好了。

3、占位符placeholder


placeholder是用来保存数据的,在session运行阶段,通过feed_dict的字典结构给placeholder喂数据。占位符在tensorflow中非常常见的,可以看看前面的MNIST例子,我们在这里也写个demo,

import tensorflow as tf
 
a = tf.placeholder(tf.float32, [2])
b = tf.placeholder(tf.float32, [2])
c = tf.add(a, b)
 
with tf.Session() as sess:
    print(sess.run(c, feed_dict={a:[1.0, 2.0], b:[3.0, 4.0]}))


运行结果:

[4. 6.]

4、指定GPU运算


如果想指定用第一个GPU运算,只要将其放在with tf.device('/gpu:0'):里即可,还是用上面的例子,代码如下:

import tensorflow as tf
 
a = tf.placeholder(tf.float32, [2])
b = tf.placeholder(tf.float32, [2])
c = tf.add(a, b)
 
config = tf.ConfigProto(log_device_placement=True)
with tf.Session(config=config) as sess:
    with tf.device('/gpu:0'):
        print(sess.run(c, feed_dict={a:[1.0, 2.0], b:[3.0, 4.0]}))


运行结果:

Device mapping:

/job:localhost/replica:0/task:0/device:GPU:0 -> device: 0, name: GeForce GTX 950, pci bus id: 0000:01:00.0, compute capability: 5.2

Add: (Add): /job:localhost/replica:0/task:0/device:GPU:0

Placeholder_1: (Placeholder): /job:localhost/replica:0/task:0/device:GPU:0

Placeholder: (Placeholder): /job:localhost/replica:0/task:0/device:GPU:0

[4. 6.]

5、保存和加载模型


如果花了几天辛辛苦苦训练了一个模型,却没有保存训练结果,相当于杨白劳,所以要会保存模型的训练结果,以及使用训练结果。我们前面训练的MNIST和CIFAR10都有这方面的操作的,可以回去看看。

5.1、保存模型

5.1.1、tf.train.Saver

我们定义一个变量a,初始化为32,然后将它保存,代码如下:

import tensorflow as tf
a = tf.Variable(32, tf.float32, name='Nini')
saver = tf.train.Saver()
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print(sess.run(a))
    saver.save(sess, 'wilf/wilf.cpkt')


运行结果:

32

看看wilf目录,生成了四个文件,

这里面怎么存数据呢?我们把它打印出来看看,代码如下:

 

from tensorflow.python.tools.inspect_checkpoint import print_tensors_in_checkpoint_file
print_tensors_in_checkpoint_file('wilf/wilf.cpkt', None, True)


运行结果:

tensor_name:  nini

32

5.1.2、tf.train.MonitoredTrainingSession

我们在分析官方CIFAR10的代码时,还遇到了一个自动保存训练结果的方法,tf.train.MonitoredTrainingSession,这里就不说了,可以去看前面的例子。

 

5.2、加载模型

将上面的代码稍加修改,为了看到效果,我们将a的初始化值改为12,如下:

import tensorflow as tf
 
a = tf.Variable(12, tf.float32, name='Nini')
saver = tf.train.Saver()
with tf.Session() as sess:
    saver.restore(sess, 'wilf/wilf.cpkt')
    print(sess.run(a))


运行结果:

32

6、变量


6.1、tf.Variable上面的例子其实已经使用过tf.Variable创建变量,我想强调的是,使用变量之前,一定要先使用

sess.run(tf.global_variables_initializer())对变量进行初始化,否则会出错,代码如下:

import tensorflow as tf
a = tf.Variable(32, tf.float32, name='Nini')
with tf.Session() as sess:
    # sess.run(tf.global_variables_initializer())
    print(sess.run(a))


运行结果:

tensorflow.python.framework.errors_impl.FailedPreconditionError: Attempting to use uninitialized value weifang

 [[Node: _retval_weifang_0_0 = _Retval[T=DT_INT32, index=0, _device="/job:localhost/replica:0/task:0/device:CPU:0"](weifang)]]

6.2、修改变量

既然说道变量,那怎么修改变量里的值呢?不可能直接用a = 11吧?Tensorflow提供了tf.assign()函数来修改变量,代码如下:

import tensorflow as tf
 
a = tf.Variable(32, tf.float32, name='Nini')
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print("before:", sess.run(a))
    print("after:", sess.run(tf.assign(a, 11)))


运行结果:

('before:', 32)

('after:', 11)

6.3、tf.get_variable

tf.get_variable也是定义变量的,比如:

var1 = tf.get_variable('wei', [1], dtype=tf.float32)

那么它跟tf.Variable有什么不同呢?我们写个demo,通过tf.Variable和tf.get_variable分别定义两个名字一样的变量:

import tensorflow as tf
 
var1 = tf.Variable(1, name='NI')
print(var1.name)
var2 = tf.Variable(2, name='NI')
print(var2.name)
 
var3 = tf.get_variable('ni', [1], dtype=tf.float32)
print(var3.name)
var4 = tf.get_variable('ni', [1], dtype=tf.float32)
print(var4.name)


运行结果:

NI:0

NI_1:0

ni:0

ValueError: Variable fang already exists, disallowed. Did you mean to set reuse=True or reuse=tf.AUTO_REUSE in VarScope? Originally defined at

可以看到,运行到var4的时候程序崩了,说明tf.Variable可以定义两个重名的变量,如果重名,会自动在名字后加上”_N”N是数字,而tf.get_variable不行。而且tf.get_variable定义的时候必须设置名字。那有什么方法用tf.get_variable设置两个名字一样的变量呢?这就要指定变量的作用域了。

6.4、tf.variable_scope

tf.variable_scope函数可以指定作用域,代码如下:

import tensorflow as tf
 
with tf.variable_scope("scope1"):
    var1 = tf.get_variable("ni", [1], dtype=tf.float32)
 
with tf.variable_scope('scope2'):
    var2 = tf.get_variable("ni", [1], dtype=tf.float32)
 
print(var1.name)
print(var2.name)


运行结果:

scope1/wei:0

scope2/wei:0

作用域还可以嵌套使用,将上面例子’scope2’作用域往后缩进试试,代码如下:

import tensorflow as tf
 
with tf.variable_scope("scope1"):
    var1 = tf.get_variable("Ni", [1], dtype=tf.float32)
 
    with tf.variable_scope('scope2'):
        var2 = tf.get_variable("Ni", [1], dtype=tf.float32)
 
print(var1.name)
print(var2.name)


运行结果:

scope1/wei:0

scope1/scope2/wei:0

6.5、共享变量

说了这么多,这个get_variable到底有什么用呢?答案是共享变量。在某些情况下,一个模型可能需要其他模型创建的变量,这时候就用到共享变量了。

Tf.variable_scope有一个reuse=True的属性,表示,如果已经定义过该变量,就不再创建,而是在图中找到这个变量直接使用。实例代码如下:

import tensorflow as tf
 
with tf.variable_scope('scope1'):
    var1 = tf.get_variable('Ni', [1], initializer=tf.constant_initializer(123))
    with tf.variable_scope('scope2'):
        var2 = tf.get_variable('ni', [1], initializer=tf.constant_initializer(234))
 
with tf.variable_scope('scope1', reuse=True):
    var3 = tf.get_variable('Ni', [1], initializer=tf.constant_initializer(888))
    with tf.variable_scope('scope2', reuse=True):
        var4 = tf.get_variable('ni', [1], initializer=tf.constant_initializer(999))
 
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print(sess.run(var1))
    print(sess.run(var2))
    print(sess.run(var3))
    print(sess.run(var4))


运行结果:

[123.]

[234.]

[123.]

[234.]

可以看到,虽然var3和var4初始化变量值为888和999,但是输出的结果依然是var1和var2的初始值,说明并没有重新创建,也可以打印它名字来看,其实是一样的。一定要加上reuse=True属性!

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值