如何正确使用TensorFlow的tf.case api?

时间:2018-03-23 19:02:36

标签: tensorflow

我想设计一个跟随函数,用于将任何1D/2D/3D矩阵扩展为4D矩阵。

import tensorflow as tf

def inputs_2_4D(inputs):
    _ranks = tf.rank(inputs)
    return tf.case({tf.equal(_ranks, 3): lambda: tf.expand_dims(inputs, 3),
                    tf.equal(_ranks, 2): lambda: tf.expand_dims(tf.expand_dims(inputs, 0), 3),
                    tf.equal(_ranks, 1): lambda: tf.expand_dims(tf.expand_dims(tf.expand_dims(inputs, 0), 0), 3)},
                    default=lambda: tf.identity(inputs))

def run():
    with tf.Session() as sess:
       mat_1d = tf.constant([1, 1])
       mat_2d = tf.constant([[1, 1]])
       mat_3d = tf.constant([[[1, 1]]])
       mat_4d = tf.constant([[[[1, 1]]]])

       result = inputs_2_4D(mat_1d)
       print(result.eval())

然而,该功能无法正常运行。只有在4-Dmat_3d张量传递到矩阵时,它才能执行输出mat-4d矩阵。如果将1D2D矩阵传递给函数,则会出现一些错误信息。

mat_3dmat_4d传递到inputs_2_4D()时,可以将它们扩展为4D矩阵或原始矩阵:

     mat_3d -----> [[[[1]
                      [1]]]]
     mat_4d -----> [[[[1 1]]]]

mat_1dmat_2d矩阵传递到inputs_2_4D时,错误信息:

ValueError: dim 3 not in the interval [-2, 1]. for 'case/cond/ExpandDims' (op: 'ExpandDims') with input shapes: [2], [] and with computed input tensors: input[1] = <3>.

之前我测试过另一个类似的功能。该功能可以正常运行。

import tensorflow as tf

def test_2_4D(inputs):
    _ranks = tf.rank(inputs)
     return tf.case({tf.equal(_ranks, 3): lambda: tf.constant(3),
                     tf.equal(_ranks, 2): lambda: tf.constant(2),
                     tf.equal(_ranks, 1): lambda: tf.constant(1)},
                     default=lambda: tf.identity(inputs))

def run():
    with tf.Session() as sess:
      mat_1d = tf.constant([1, 1])
      mat_2d = tf.constant([[1, 1]])
      mat_3d = tf.constant([[[1, 1]]])
      mat_4d = tf.constant([[[[1, 1]]]])

      result = test_2_4D(mat_3d)
      print(result.eval())

当传递所有矩阵时,此函数可以正确输出相应的结果。

test_2_4D()结果:

    mat_1d -----> 1
    mat_2d -----> 2
    mat_3d -----> 3
    mat_4d -----> [[[[1 1]]]]

我不知道为什么在执行每个分支的inputs_2_4D()时找不到tf.equal()中的正确分支。我觉得如果输入矩阵是"mat_1d""mat_2d".,函数中的第1和第2个分支似乎仍然有效。因此,程序将崩溃。请帮我分析一下这个问题!

2 个答案:

答案 0 :(得分:0)

我解决了问题所在。结果是评估所有条件/函数对。这可以通过赋予操作不同的名称来揭示。问题是,如果你的输入是排名2,Tensorflow似乎仍在评估tf.equal(_ranks, 3): lambda: tf.expand_dims(inputs, 3)。这会导致崩溃,因为它无法扩展dim 3以获得rank-2张量(允许的最大值为2)。

这实际上是有道理的,因为tf.case你基本上都在说&#34;我不知道哪些情况在运行时会是真的,所以检查哪一个是合适的并执行相应的功能&#34;。但是,这意味着Tensorflow需要为所有可能的情况准备执行路径,在这种情况下会导致无效的计算(尝试扩展无效的维度)。

在这一点上,了解一下你的问题会更好,也就是说你为什么需要这个功能。如果您有不同的输入并且您只想将它​​们全部带到4D,但每个输入始终具有相同的维度,请考虑使用Python if语句。例如:

inputs3d = tf.constant([[[1,1]]])  # this is always 3D
inputs2d = tf.constant([[1,1]])  # this is alwayas 2D
...

def inputs_2_4D(inputs):
    _rank = len(inputs.shape.as_list())
    if _rank == 3:
        return tf.expand_dims(inputs, 3)
    elif _rank == 2:
        return tf.expand_dims(tf.expand_dims(inputs, 0), 3)
    ...

这将检查构建图形时的输入排名(不是在运行时,如tf.case),并且实际上只准备那些适合给定的expand_dims操作输入

但是,如果您有一个inputs张量,并且在程序的不同时间可能会有不同的等级,则需要使用不同的解决方案。请告诉我们您要解决的问题!

答案 1 :(得分:0)

我通过2种方式实现了我想要的功能。现在,我提供我的代码分享。

基于tf.cond的第一种方法:

def inputs_2_4D(inputs):
    _rank1d = tf.rank(inputs)
    def _1d_2_2d(): return tf.expand_dims(inputs, 0)
    def _greater_than_1d(): return tf.identity(inputs)
    _tmp_2d = tf.cond(_rank1d < 2, _1d_2_2d, _greater_than_1d)

    _rank2d = tf.rank(_tmp_2d)
    def _2d_2_3d(): return tf.expand_dims(_tmp_2d, 0)
    def _greater_than_2d(): return tf.identity(_tmp_2d)
    _tmp_3d = tf.cond(_rank2d < 3, _2d_2_3d, _greater_than_2d)

    _rank3d = tf.rank(_tmp_3d)
    def _3d_2_4d(): return tf.expand_dims(_tmp_3d, 3)
    def _greater_than_3d(): return tf.identity(_tmp_3d)

    return (tf.cond(_rank3d < 4, _3d_2_4d, _greater_than_3d))

基于tf.case tf.cond的第二种方法:

def inputs_2_4D_1(inputs):
    _rank = tf.rank(inputs)
    def _assign_original(): return tf.identity(inputs)
    def _dummy(): return tf.expand_dims(inputs, 0)

    _1d = tf.cond(tf.equal(_rank, 1), _assign_original, _dummy)
    _2d = tf.cond(tf.equal(_rank, 2), _assign_original, _dummy)
    _3d = tf.cond(tf.equal(_rank, 3), _assign_original, _dummy)

    def _1d_2_4d(): return tf.expand_dims(tf.expand_dims(tf.expand_dims(_1d, 0), 0), 3)
    def _2d_2_4d(): return tf.expand_dims(tf.expand_dims(_2d, 0), 3)
    def _3d_2_4d(): return tf.expand_dims(_3d, 3)

    return (tf.case({tf.equal(_rank, 1): _1d_2_4d,
                     tf.equal(_rank, 2): _2d_2_4d,
                     tf.equal(_rank, 3): _3d_2_4d},
                     default=_assign_original))

我认为第二种方法的效率应该低于第一种方法,因为在将_dummy()分配到inputs时,函数_1d总是浪费2次操作,{ {1}},_2d