6_1 持久化模型与再次加载_探讨(1)_三种持久化模型加载方式以及import_meta_graph方式加载持久化模型会存在的变量管理命名混淆的问题

笔者提交到gitHub上的问题描述地址是:https://github.com/tensorflow/tensorflow/issues/20140

三种持久化模型加载方式的一个小结论

加载持久化模型的三种方式:

第一,saver.restore:属于当前代码计算图已经定义,我需要将持久化模型中变量的值加载到当前代码计算图中的变量中去。所以,两者只能是持久化模型中的变量是当前代码计算图中变量集合的一个子集,必须是一种严格包含的关系。(当然,可以在初始化Saver的时候指定加载哪些变量)

第二,import_meta_graph则完全不允许当前代码计算图已经定义的变量节点和要加载的持久化模型中的节点存在冲突,因为它价值的是整个图。不是单纯将变量的值进行加载。

第三,使用pb文件的方式,即使持久化模型中的变量节点和当前代码计算图中定义的变量节点发生冲突,也是毛事没有,没有任何关系。因为pb文件的方式加载进来的计算图,

会全部加上import/前缀。也就是说,从命名空间上就隔开了这种冲突。

上述三点是很重要的结论,自己调试和观察的。

所以,使用别人的模型,最好的方式就是用pb文件。因为不会有冲突的可能!但是,有一个弊端就是,import命名空间下的变量不能参与到当前的训练!!!记住,不能参与训练!

问题描述(英文版):

write the code below, and save it to a ,ckpt as a model

import tensorflow as tf`
v1 = tf.Variable(tf.constant(1.0, shape=[]), name = "v1")
v2 = tf.Variable(tf.constant(2.0, shape=[]), name = "v2")
v3 = tf.Variable(tf.constant(3.0, shape=[]), name = "v3")
result=v1+v2
result2= result + v3 init_op = tf.global_variables_initializer()
saver = tf.train.Saver() with tf.Session() as sess:
sess.run(init_op)
writer = tf.summary.FileWriter('./graphs/const_add', sess.graph)
saver.save(sess, "Saved_model/model.ckpt")`

then in another .py, we restore the model from the model.ckpt file

import tensorflow as tf
saver = tf.train.import_meta_graph("Saved_model/model.ckpt.meta")
with tf.Session() as sess:
saver.restore(sess, "Saved_model/model.ckpt")
print (sess.run(tf.get_default_graph().get_tensor_by_name("add:0")))
#sess.run(tf.assign(v1,[10])) #直接这样使用v1,会提示v1没有定义 #with tf.variable_scope("",reuse=tf.AUTO_REUSE):
with tf.variable_scope("",reuse=False):
v1=tf.get_variable(name="v1",shape=[1])
print(v1.name)
sess.run(tf.assign(v1,[10]))
"""④输出所有可训练的变量名称,也就是神经网络的参数"""
trainable_variables=tf.trainable_variables()
variable_list_name = [c.name for c in tf.trainable_variables()]
variable_list = sess.run(variable_list_name)
for k,v in zip(variable_list_name,variable_list):
print("variable name:",k)
print("shape:",v.shape)
#print(v)
"""④输出所有可训练的变量名称,也就是神经网络的参数"""
print (sess.run(tf.get_default_graph().get_tensor_by_name("v1:0")))
print (sess.run(tf.get_default_graph().get_tensor_by_name("add:0")))
print (sess.run(tf.get_default_graph().get_tensor_by_name("add_1:0")))
print (sess.run(tf.get_default_graph().get_tensor_by_name("v1_1:0")))

the results will be as below:
6_1 持久化模型与再次加载_探讨(1)_三种持久化模型加载方式以及import_meta_graph方式加载持久化模型会存在的变量管理命名混淆的问题
we will find that:
if we restore some variables from the already existed model file ""Saved_model/model.ckpt.meta")",
such as v1,v2,v3 in this example.
it will influence the process of calling get_variable. Because of these two causes as below:

  1. the variables restored from the model file such as v1,v2 and v3 will not exist in the scope of get_variable, it means you can only use
with tf.variable_scope("",reuse=False):
v1=tf.get_variable(name="v1",shape=[1])

and create a new variable. you can not reuse the restored variable v1 from the model file unless you define a v1 , before you restore from the model file. like below

v1=tf.get_variable(name="v1",shape=[1])
saver = tf.train.Saver()
with tf.Session() as sess:
saver.restore(sess, "Saved_model/model.ckpt")
print (sess.run(result))

that is , you can not reuse the restored variable v1 which is from restoring the model file unless you define it befor you restore.
2. although tensorflow doesnot allow reusing the restored variable v1 which is from restoring the model file if you don't define v1 before you restore the model file.
But if you call get_varialbe after you restore the model file, it will create a variable whose name is "v1_1" but not as name='v1' which you specify.
in my opinion, it should be corrected because it is so confusing. how to correct it?
i think get_variable should also reuse the variables which is loaded by restoring some model file.
the last sentence is what i finally want to say.
My english is to bad, you can run the code i offer and will find what i want to convey.
Thanks.

总结

假定一个持久化模型中存在一个V1命名的变量,此时如果使用import_meta_graph方式加载持久化模型。

  • 首先,使用import_meta_graph要加载的持久化模型中的变量命名不能与当前代码默认计算图中的变量命名发生冲突
  • 其次,如果此时希望通过利用tf.get_variable的方式,来建立python变量与计算图变量节点之间的关系,即:
    with tf.variable_scope("",reuse=False):
v1=tf.get_variable(name="v1",shape=[1])
print(v1.name)

是不可能做到的。而且你只能用reuse=False,就好像:加载持久化模型以后,计算图中没有V1变量节点一样。

同时,你使用v1=tf.get_variable(name="v1",shape=[1])方式,会在当前代码的计算图中生成一个新的变量节点V1_1,并非加载的持久化模型中的变量节点V1。此时,就会出现函数功能失效。也就是,你希望调用get_variable函数使得:python的变量v1和计算图中的变量节点v1是绑定的,但是情况并非如此,绑定的是变量节点v1_1。

所以访问计算图中的V1节点,就只能使用tf.get_default_graph().get_tensor_by_name("v1:0")的方式。

很多人可能并不理解这个:0,这是一个operation的输出。也就是说变量节点的输出只有一个,所以用0表示引用计算图中这个变量节点的输出tensor。

事实上,可以自定义tensorflow中的operation,也就是我可以输出多个tensor。那个时候:0,:1就可以用起来了。

总的来说,笔者将此问题提交到gitHub,目前仍然处于欢迎讨论状态。即tensorflow的开发人员需要更多tensorflow使用者的意见,来回答:有没有必要对这个问题进行修复。

上一篇:剑指offer-面试题.二叉树的镜像


下一篇:WPF把CheckBox的文字放到左边,开关在右边