1.前言
GAN项目被我搁置一旁很久了,最近想回顾一下写过的程序,看看能不能发现一些错误或是从中得到一些新的灵感和启发。
2.程序回顾
废话不多说,直接上代码,我只挑一些比较重要的进行分析。
TensorFlow-gpu版本:1.12.0
(1)sys.path
Python在看一个模块是否存在时首先会看看自身内核中的模块,如果不存在,则就要到sys.path
中去找,print(sys.path)
输出的是所有路径,如果你是自定义的模块,就要通过sys.path.append
加入模块所在的目录即可,否则import的时候会报错。
(2)tf.set_random_seed(seed)
如果在一个tf.Graph
中加入tf.set_random_seed(seed)
会让使用tf的变量(tf.constant
和tf.Variable()
的初始化每次运行的时候都是相同的值),举个例子吧:
import tensorflow as tf
graph1 = tf.Graph() # 创建一个新的计算图
with graph1.as_default():
tf.set_random_seed(10) # 这个随机种子将决定整个graph1下的所有变量的取值
a = tf.random_normal([5])
with tf.Session() as sess1:
print(sess1.run(a))
print(sess1.run(a))
with tf.Session() as sess2:
print(sess2.run(a))
print(sess2.run(a))
结论:在同一个graph1下的不同会话的输出值是相同的。
注意:如果存在with, tf.set_random_seed(10)
(计算图级)必须放放在with中,否则将没有作用,因为不是全局设置的语句!或者在变量中去定义seed:a = tf.random_normal([5], seed=1)
也就是设置操作级的随机数。
下面,我再举例说明.as_default()
的用法:
import tensorflow as tf
a = tf.constant(1.0) # 常数
print(a.graph)
graph1 = tf.Graph() # 创建一个新的计算图
print(a.graph is tf.get_default_graph()) # 输出True,说明创建a的时候就已经创建了一个graph了
print(a.graph is graph1) # 输出False
with graph1.as_default() as graph: # 一共有两个图了,指定graph1为默认的图
print(a.graph is graph1) # 输出False,因为图不一样
b = tf.Variable(tf.constant(2.0)) # 变量
print(b.graph is graph1) # 输出True,因为图一样
init = tf.global_variables_initializer() # 因为有Variable
with tf.Session().as_default() as sess: # .as_default()保证了当前会话在with结束后不关闭
sess.run(init) # 必须单独写
print(sess.run([b])) # run是有顺序的
# sess.close() # 加上这句,即使有.as_default(),后面也会报错的
print(b.eval(session=sess)) # 必须要指定sess
结论:
① Variable的init必须是单独的
② run可以多个变量一起,必须用[]或者()
③ eval一次只能对一个变量进行输出
④ 在一个session下要run两个变量,如果两个变量是在不同的graph中,则会报错
例如:print(sess.run([b,a]))
⑤ 当一个变量被创建的时候,就会生成一个默认的图,一个线程中可以画很多图,但是默认的图只有一个
(3)tf.variable_scope(name)
与tf.name_scope(name)
tf.variable_scope(name)
域下的变量可以使用tf.get_variable()
来定义,也可以用tf.Variable()
来定义;而tf.name_scope(name)
仅能用tf.Variable()
来定义,具体操作见下:
>>> with tf.variable_scope('vars'):
... var1 = tf.get_variable(name='var1', shape=[1, 2])
...
>>> var1.name
'vars/var1:0'
# 下面如果要再在vars域下面声明一个名叫var1的变量是会报错误的,如果是要做变量共享,则可以继续这样做:
>>> with tf.variable_scope('vars', reuse=True):
... var2 = tf.get_variable(name='var1', shape=[1, 2])
...
>>> var2.name
'vars/var1:0'
# 从上面可以看出,变量的生成只与name有关,需要注意的是当变量name相同时,你的shape也要一致;name_scope是不能使用reuse的,但是允许在同一个域下使用相同name的变量,因为会自动为这些变量增加序号哦:
>>> with tf.name_scope('vars'):
... var1 = tf.Variable(1, name='var1')
...
>>> var1.name
'vars_5/var1:0'
>>> with tf.name_scope('vars'):
... var2 = tf.Variable(1, name='var1')
...
>>> var2.name
'vars_6/var1:0'
(4)tf.contrib.layers.batch_norm()
和tf.nn.dropout()
批归一化在算法层面有两点需要注意:
① 训练阶段只有两个可训练的参数,β和γ,用于缩放,然后就是两个不可训练的参数,滑动平均值和方差
② 测试阶段,一般使用保存好的滑动平均值和方差即可
在实际使用批归一化的时候,却没那么简单
,对于不同的深度学习框架,配置方式和难易程度差别很大,这里就只介绍TensorFlow下的实现方式:
第一步:搭建批归一化层,其中最重要的就是is_training参数,True为训练过程,False为测试过程,当然,你可以将这个层封装为一个可以直接调用的函数,也就是放在def __call__(self, x):
下
tf.contrib.layers.batch_norm(x, decay=self.momentum, updates_collections=None, is_training=self.trainable, epsilon=self.epsilon, scale=True, scope=self.name)
第二步,在优化器层上封装如下语句,这个是tf.contrib.layers.batch_norm
硬性规定的,目的就是前面提到的批归一化参数变量
update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
with tf.control_dependencies(update_ops):
d_optim = tf.train.AdamOptimizer().minimize(loss, var_list=var)
对于dropout
,这个与批归一化类似,在训练阶段需要设置keep_prob为0.5或者其他的<1.0
的数,在测试阶段一般是不使用dropout的,因为这个是随机的过程,你不能也无法取模拟训练的过程,所以设置为1.0
需要注意的一点:在TensorFlow中只能自己通过sess.run()
去设置keep_prob和is_training
================= To be continued =================