Tensorflow 使用tf.cond()为我的图形提供训练和验证

Tensorflow 使用tf.cond()为我的图形提供训练和验证,tensorflow,tensorflow-gpu,Tensorflow,Tensorflow Gpu,在我的TensorFlow代码中,我希望我的网络从两个阶段区域对象之一获取输入,具体取决于我是想进行培训还是测试。 我编写的图形构造代码的一部分如下所示: with tf.device("/gpu:0"): for i in range(numgpus): with tf.variable_scope(tf.get_variable_scope(), reuse=i>0) as vscope: with tf.device('/g

在我的TensorFlow代码中,我希望我的网络从两个
阶段区域
对象之一获取输入,具体取决于我是想进行培训还是测试。 我编写的图形构造代码的一部分如下所示:

with tf.device("/gpu:0"):
      for i in range(numgpus):
          with tf.variable_scope(tf.get_variable_scope(), reuse=i>0) as vscope:
              with tf.device('/gpu:{}'.format(i)):
                  with tf.name_scope('GPU-Tower-{}'.format(i)) as scope:
                      phase = tf.get_variable("phase", [], initializer=tf.zeros_initializer(),dtype=tf.uint8, trainable=False)
                      phaseassigntest = phase.assign(1)
                      phaseassigntrain = phase.assign(0)
                      phasetest = tf.equal(phase, 0)
                      is_training = tf.cond(phasetest, lambda: tf.constant(True), lambda: tf.constant(False))

                      trainstagingarea = tf.contrib.staging.StagingArea([tf.float32, tf.int32], shapes=[[trainbatchsize, 3, 221, 221], [trainbatchsize]], capacity=20)
                      putoptrain = trainstagingarea.put(train_iterator.get_next())
                      trainputop.append(putoptrain)
                      getoptrain = trainstagingarea.get()
                      traingetop.append(getoptrain)
                      trainclearop = trainstagingarea.clear()
                      trainstageclear.append(trainclearop)
                      trainsizeop = trainstagingarea.size()
                      trainstagesize.append(trainsizeop)

                      valstagingarea = tf.contrib.staging.StagingArea([tf.float32, tf.int32], shapes=[[valbatchsize, 3, 221, 221], [valbatchsize]], capacity=20)
                      putopval = valstagingarea.put(val_iterator.get_next())
                      valputop.append(putopval)
                      getopval = valstagingarea.get()
                      valgetop.append(getopval)
                      valclearop = valstagingarea.clear()
                      valstageclear.append(valclearop)
                      valsizeop = valstagingarea.size()
                      valstagesize.append(valsizeop)


                      #elem = valgetop[i]
                      elem = tf.cond(is_training,lambda: traingetop[i],lambda: valgetop[i])

                      img = elem[0]
                      label = elem[1]
                      labelonehot = tf.one_hot(label, depth=numclasses)
                      net, networksummaries =  overfeataccurate(img,numclasses=numclasses, phase=is_training)
我使用了
tf.cond
来确保网络由两个
stagingara
对象之一供电。一个用于培训,另一个用于验证。 现在,当我尝试执行下面的图时,我没有得到任何结果,事实上代码只是挂起,我必须终止进程

with tf.Session(graph=g,config=config) as sess:
    sess.run(init_op)
    sess.run(tf.local_variables_initializer())
    sess.run(val_initialize)
    for i in range(20):
        sess.run(valputop)
        print(sess.run(valstagesize))
    writer = tf.summary.FileWriter('.', graph=tf.get_default_graph())
    epoch = 0
    iter = 0
    print("Performing Validation")
    sess.run(phaseassigntest)
    saver = tf.train.Saver()
    while(epoch<10):
        time_init = time.time()
        while True:
            try:
                [val_accu, _, summaries] = sess.run([towervalidation, towervalidationupdateop,validation_summary_op])
                print(val_accu)
将tf.Session(graph=g,config=config)作为sess:
sess.run(初始化操作)
sess.run(tf.local\u variables\u initializer())
sess.run(val\u初始化)
对于范围(20)内的i:
sess.run(瓦尔普托普)
打印(sess.run(valstagesize))
writer=tf.summary.FileWriter('.',graph=tf.get\u default\u graph())
历元=0
iter=0
打印(“执行验证”)
测试运行(阶段信号测试)
saver=tf.train.saver()
当(我)解决我们的问题时
你认为tf.cond的作用是什么
根据该标志,执行将traingetop[i]或valgetop[i]放入
elem
tensor所需的操作

tf.cond实际上做什么 执行同时获取traingetop[i]和valgetop[i]所需的操作,然后将其中一个传递到
元素
张量中

所以 它永远挂起的原因是因为它正在等待一个元素添加到您的训练暂存区(以便它可以获取该元素并将其丢弃)。您没有意识到这是它正在做的事情,这实际上是非常违反直觉的。文档对如何处理这一点非常不清楚


推荐的解决方案(通过Tensorflow文档) 如果您确实需要队列位于同一个图表中,那么您需要制作整个图表的两个副本,一个由培训暂存区提供,另一个由验证暂存区提供。然后您只需在
sess中使用相关的张量。运行
调用。我建议创建一个接受队列输出的函数或者,并返回一个
model\u输出
tensor。现在您有了一个
train\u time\u输出
tensor和一个
validation\u time\u输出
tensor,您可以选择要在
sess中执行哪一个。运行

警告 你需要确保你实际上没有创建新的变量来配合这些新的操作。要做到这一点,请查看上的最新文档。看起来他们已经从v0.12简化了它,本质上可以归结为使用
tf.get_variable
而不是
tf.variable
来创建变量阿贝尔斯


我最喜欢的工作 虽然这是推荐的解决方案(AFAIK),但我对此非常不满意;您在图形上创建了一整套恰好使用相同权重的操作。通过滥用训练时间和测试/验证时间之间的分离,似乎存在很大的程序员错误的可能性(导致模型在这些时候的行为出人意料地不同)。更糟糕的是,它不能解决
tf.cond
要求两个分支的输入值的问题,它只是迫使您复制整个图形,这并不总是可能的

我不想让我的队列像那样出现在图中,而是把模型当作一个函数,可以作为一个例子,而不必关心它来自哪里。也就是说,我会用一个
tf.placeholder
作为输入实例化模型,在执行时我会使用
feed\u dict
来实际提供值像这样的

#主训练回路内
如果列车运行时间:
示例=sess.run(traingettop)
其他:
示例=sess.run(valgettop)
result=sess.run(model_输出,{input_占位符:example})
需要注意的是,您可以使用feed_dict为模型中任何位置的任何张量提供任何值。因此,您可以更改任何模型定义,因为
tf.cond
始终需要输入,例如:

a=tf.常数(某些值)
b=tf.placeholder(tf.float32)
flag=tf.placeholder(tf.bool,[])
其中一个=tf.cond(标志a、b)
模型输出=构建图(其中一个)
进入一个不符合以下条件的定义:

a=tf.常数(某些值)
模型输出=构建图(a)
请记住,您始终可以在执行时覆盖
a
的内容:

#在主训练循环中,
sess.run(train_op,{a:some_other_value})
这实质上是将条件语句推送到本地python中。在代码中,您可能会得到如下结果:

如果条件满足:
sess.run(train_op,{a:some_other_value})
其他:
列车运行(列车运行)
性能问题 如果您在一台机器上使用tensorflow,那么这个解决方案实际上没有性能成本,因为放入
示例
python变量的numpy数组实际上仍然存储在GPU上


如果您以分布式方式使用tensorflow,那么这个解决方案会降低您的性能;它需要将示例从任何机器上发送到主机,以便主机可以将其发送回去。

这是一个很好的解决方案,但我不知道如何在tensorflow基准测试中实现它:我简单地看了一下,第#1206行似乎是他们实际运行模型的那一行。假设您能够运行它,那么您只需要将其更改为
results=sess.run(fetches,{tensor\u to\u overwrite:numpy\u array\u with\u the\u values})
。如果您需要一个关于是执行该操作还是执行默认操作的条件,请在该行之前在python中执行该操作。