【问题标题】:Working with multiple graphs in TensorFlow在 TensorFlow 中处理多个图
【发布时间】:2016-03-12 07:50:29
【问题描述】:

有人可以向我解释name_scope 在 TensorFlow 中的工作原理吗?

假设我有以下代码:

import tensorflow as tf

g1 = tf.Graph()
with g1.as_default() as g:
    with g.name_scope( "g1" ) as scope:
        matrix1 = tf.constant([[3., 3.]])
        matrix2 = tf.constant([[2.],[2.]])
        product = tf.matmul(matrix1, matrix2)

tf.reset_default_graph()

g2 = tf.Graph()
with g2.as_default() as g:
    with g.name_scope( "g2" ) as scope:
        matrix1 = tf.constant([[4., 4.]])
        matrix2 = tf.constant([[5.],[5.]])
        product = tf.matmul(matrix1, matrix2)

tf.reset_default_graph()

with tf.Session( graph = g1 ) as sess:
    result = sess.run( product )
    print( result )

当我运行此代码时,我收到以下错误消息:

Tensor Tensor("g2/MatMul:0", shape=(1, 1), dtype=float32) is not an element of this graph.

我同意“g2/MatMul”不是图形g1 的元素,但是为什么当会话图形设置为g1 时选择“g2/MatMul”?为什么不选择“g1/MatMul”?


编辑

以下代码似乎有效:

import tensorflow as tf

g1 = tf.Graph()
with g1.as_default() as g:
    with g.name_scope( "g1" ) as g1_scope:
        matrix1 = tf.constant([[3., 3.]])
        matrix2 = tf.constant([[2.],[2.]])
        product = tf.matmul( matrix1, matrix2, name = "product")

tf.reset_default_graph()

g2 = tf.Graph()
with g2.as_default() as g:
    with g.name_scope( "g2" ) as g2_scope:
        matrix1 = tf.constant([[4., 4.]])
        matrix2 = tf.constant([[5.],[5.]])
        product = tf.matmul( matrix1, matrix2, name = "product" )

tf.reset_default_graph()

use_g1 = False

if ( use_g1 ):
    g = g1
    scope = g1_scope
else:
    g = g2
    scope = g2_scope

with tf.Session( graph = g ) as sess:
    tf.initialize_all_variables()
    result = sess.run( sess.graph.get_tensor_by_name( scope + "product:0" ) )
    print( result )

通过拨动开关use_g1,图表g1g2 将在会话中运行。这是名称范围的工作方式吗?

【问题讨论】:

  • 切换图和会话的开销有多严重?如果我希望它们相互进行顺序游戏,使用这种方法在 2 个图之间不断交换是否可行?
  • 这是一个 Python 问题,而不是 Tensorflow。您的“g1”图仍然存在,但由于您将其指向“g2”,因此您失去了对它的引用。用两个列表替换图表可能会更清楚。

标签: tensorflow


【解决方案1】:

您的product 是一个全局变量,您已将其设置为指向“g2/MatMul”。

特别是

试试

print product

你会看到

Tensor("g2/MatMul:0", shape=(1, 1), dtype=float32)

因此系统采用"g2/MatMul:0",因为那是张量的名称,并尝试在图形g1 中找到它,因为那是您为会话设置的图形。顺便说一句,你可以看到图中的所有节点print [n.name for n in g1.as_graph_def().node]

通常,使用多个图表很少有用。你不能合并它们,也不能在它们之间传递张量。我建议只是做

tf.reset_default_graph()
a = tf.Constant(2)
sess = tf.InteractiveSession()
....

这样您将拥有一个默认图表和一个默认会话,并且在大多数情况下您可以省略指定图表或会话。如果您需要明确引用它们,可以从 tf.get_default_graph()tf.get_default_session() 获取它们

【讨论】:

  • 我同意,您始终可以坚持使用默认图,但由于开发人员明确构建了一个包含多个图的 API,问题是如何使用它。根据您的说法,每个图中的所有变量都需要唯一的全局名称。如果是这样的话,不清楚他们为什么引入“名称范围”的概念或应该如何使用它。
  • name_scope("g2")g2/ 添加到在该范围内创建的所有张量名称之前,因此您的“范围切换”无效,因为张量已经创建
  • 没有关于如何在 TensorFlow 中使用多个图的文档吗?
  • 在一个过程中使用多个图通常是一个可怕的错误
  • 因此,如果我想运行随机搜索以在不同运行之间选择不同的超参数,如果没有多个张量流图,如何做到这一点?
【解决方案2】:

这确实是个死灵,但它仍然是与此相关的问题的热门搜索结果,我认为它可能有助于做出非常明确的事情,之前的答案(正确)顺便指出:

Q 的变量product 是一个python 变量。因此,它指向一个对象:定义后,它指向在 name_scope 'g1' 中定义的 matmul tf.Operationtf.Tensor 输出。它稍后被重新定义为指向不同的对象,即“g2”的tf.Tensor 输出。这个python变量从来没有听说过tf.name_scopes,也不在乎。

就是为什么您需要通过 tensorflow 对象的名称属性进行查找的原因......通过使用 name_scopes,这些属性是唯一且可访问的。或者生成不同的 Python 变量(根据 Python 范围规则是唯一且可访问的),以指向您要引用的每个 tf.Tensor 对象。

不知道这是否对其他人有帮助,但如果我忘记了,我会为此感谢过去的自己。

【讨论】:

    【解决方案3】:

    我在处理 IPython 笔记本上的多个图表时遇到了类似的困难。我的目的是将每个图形及其会话封装在一个函数中。我意识到这更像是一种 hack,我对命名空间一无所知,我知道 OP 想要一些类似的东西。也许它会帮助我不知道的人,你也可以在计算之间传递结果。

    import tensorflow as tf
    
    def Graph1():
        g1 = tf.Graph()
        with g1.as_default() as g:
            matrix1 = tf.constant([[3., 3.]])
            matrix2 = tf.constant([[2.],[2.]])
            product = tf.matmul( matrix1, matrix2, name = "product")
    
        with tf.Session( graph = g ) as sess:
            tf.initialize_all_variables().run()
            return product
    
    
    def Graph2(incoming):
        i = incoming
        g2 = tf.Graph()
        with g2.as_default() as g:
            matrix1 = tf.constant([[4., 4.]])
            matrix2 = tf.constant([[5.],[5.]])
            product = tf.matmul( matrix1, matrix2, name = "product" )
    
        with tf.Session( graph = g ) as sess:
            tf.initialize_all_variables().run()
            print product
            print i
    
    print Graph1()
    
    Graph2(Graph1())
    

    【讨论】:

      【解决方案4】:

      您的问题是您正在调用最新的变量product,它指向在 g2 上创建的张量 - 您在第二个作用域中覆盖了它。只需重新标记所有变量,就可以了。工作代码如下。

      import tensorflow as tf
      
      g1 = tf.Graph() with g1.as_default() as g:
          with g.name_scope( "g1" ) as scope:
              matrix11 = tf.constant([[3., 3.]])
              matrix21 = tf.constant([[2.],[2.]])
              product1 = tf.matmul(matrix11, matrix21)
      
      tf.reset_default_graph()
      
      g2 = tf.Graph() with g2.as_default() as g:
          with g.name_scope( "g2" ) as scope:
              matrix12 = tf.constant([[4., 4.]])
              matrix22 = tf.constant([[5.],[5.]])
              product2 = tf.matmul(matrix12, matrix22)
      
      tf.reset_default_graph()
      
      with tf.Session( graph = g1 ) as sess:
          result = sess.run( product1 )
          print( result )
      

      【讨论】:

      • 但是直觉上好像变量虽然同名,但是属于不同的name_scopes,应该不会混淆吧?
      • 但是g.name_scope 是 GPU 的范围,而不是 python 代码。 With tf.Graph 不会像在函数或方法内部那样创建 Pythonic 局部范围 - 相反,它会向 GPU 指示应如何标记变量。而局部变量product 是指向GPU 上的图形计算的指针。如果这些代码段是不同的函数,那么您可以保持相同的名称。
      【解决方案5】:

      您有 3 个图表,而不是 2 个图表(g1 或 g2)。

      你可以通过 id() 看到 3 个图表

      ...
      
      print 'g1           ', id(g1)
      print 'g2           ', id(g2)
      print 'current graph', id ( tf.get_default_graph() )
      
      with tf.Session( graph = g1 ) as sess:
          result = sess.run( product )
          print( result )
      

      使用“with g1.as_default():”会犯同样的错误

      ...
      
      with g1.as_default() :
          with tf.Session( graph = g1 ) as sess:
              result = sess.run( product )
              print( result )
      

      因为,你有两个 'product' ,而不是一个。

      g1 = tf.Graph()
      with g1.as_default() as g:
          ...
          print 'g1 product', id ( product )
      
      ...
      
      g2 = tf.Graph()
      with g2.as_default() as g:
          ...
          print 'g2 product', id ( product )
      
      with tf.Session( graph = g1 ) as sess:
          print 'last product', id(product)
          ...
      

      最后一个产品 == g2 产品

      ...
          product = tf.matmul(matrix1, matrix2, name='g1_product')
      ...
      with g1.as_default() as g:
          with tf.Session() as sess:
              product = g.get_tensor_by_name(  "g1_product:0" )
              result = sess.run( product )
              print( result )
      

      以上代码工作。

      但是,两个同名的变量(产品)

      用类封装好不好?

      【讨论】:

        【解决方案6】:

        我已经写了两个 sn-ps 来做你想做的事情。

        第一个在图表之间切换并且不使用 name_scope。第二个对两个操作都使用 default_graph 并使用 name_scope 在它们之间切换...

        import tensorflow as tf
        
        g1 = tf.Graph()
        with g1.as_default() as g:
          matrix1 = tf.constant([[3., 3.]])
          matrix2 = tf.constant([[2.],[2.]])
          tf.matmul(matrix1, matrix2, name="productX")
        
        g2 = tf.Graph()
        with g2.as_default() as g:
          matrix1 = tf.constant([[4., 4.]])
          matrix2 = tf.constant([[5.],[5.]])
          tf.matmul(matrix1, matrix2, name="productX")
        
        product_op = g1.get_tensor_by_name(  "productX:0" )
        with tf.Session( graph = g1 ) as sess:
            result = sess.run( product_op )
            print( result )
        
        product_op = g2.get_tensor_by_name(  "productX:0" )
        with tf.Session( graph = g2 ) as sess:
          result = sess.run( product_op )
          print( result )
        

        注意 A)我已经取消了默认图形的重置(从不使用默认图形)并且 B)我已经摆脱了“产品”变量并为操作命名,而不是

        重要的切换代码是……

        product_op = g2.get_tensor_by_name(  "productX:0" )
        

        这里我们使用两个图的变量名来区分两个产品操作。

        请注意您必须在变量名末尾加上烦人的 ':0'。

        现在使用 name_scope...

        import tensorflow as tf
        
        g = tf.get_default_graph()
        
        matrix1 = tf.constant([[3., 3.]])
        matrix2 = tf.constant([[2.],[2.]])
        with g.name_scope("prodA"):
          tf.matmul(matrix1, matrix2, name="productX")
        
        matrix1 = tf.constant([[4., 4.]])
        matrix2 = tf.constant([[5.],[5.]])
        with g.name_scope("prodB"):
          tf.matmul(matrix1, matrix2, name="productX")
        
        with tf.Session() as sess:
        
          product_op = g.get_tensor_by_name(  "prodA/productX:0" )
          result = sess.run( product_op )
          print( result )
        
          product_op = g.get_tensor_by_name(  "prodB/productX:0" )
          result = sess.run( product_op )
          print( result )
        

        现在切换的代码行是这样的……

        product_op = g.get_tensor_by_name(  "prodB/productX:0" )
        

        注意 A) 图表或会话之间没有切换。 B) name_scope 给你一种目录结构,看起来名字层次结构。

        graph vs name_scope 切换的优缺点是什么?如果有人为此写博客,我会读的!

        不过,我认为图表和会话之间的切换不会很快。

        【讨论】:

        • 不要在回答中留下一些问题。请编辑它。
        猜你喜欢
        • 1970-01-01
        • 2018-08-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-19
        • 1970-01-01
        相关资源
        最近更新 更多