TensorFlow 2.0中Lambda函数的组成

时间:2019-06-22 16:07:56

标签: python-3.x tensorflow tensorflow2.0

为了在TensorFlow 2.0中构建大型模型,我使用一种功能性方法并利用Python 3.6的functools模块。我通过显示特定自定义层的代码来说明问题。

import tensorflow as tf
import functools
from collections.abc import Iterable


# TODO Check for correctness of the model implementation
class Unit3D(tf.keras.layers.Layer):
    def __init__(self, output_channels,
                 kernel_shape=(1, 1, 1),
                 stride=(1, 1, 1),
                 activation_fn='relu',
                 use_batch_norm=True,
                 use_bias=False,
                 is_training=False,
                 name='unit_3d'):
        super(Unit3D, self).__init__(name=name)
        self._output_channels = output_channels
        self._kernel_shape = kernel_shape
        self._stride = stride
        self._activation = activation_fn
        self._use_batch_norm = use_batch_norm
        self._use_bias = use_bias
        self._is_training = is_training
        self._pipeline = []
        self._pipeline.append(tf.keras.layers.Conv3D(
            filters=self._output_channels,
            kernel_size=self._kernel_shape,
            strides=self._stride,
            padding='same',
            use_bias=self._use_bias,
            data_format='channels_first'
        )
        )
        if self._use_batch_norm:
            bn = tf.keras.layers.BatchNormalization(
                axis=1,
                fused=False,
            )
            bn = functools.partial(bn, training=self._is_training)
            self._pipeline.append(bn)

        if self._activation is not None:
            self._pipeline.append(tf.keras.layers.Activation(
                activation=self._activation
            )
            )

        print(isinstance(self._pipeline, Iterable))
        print(type(self._pipeline))
        self._pipeline = lambda x: functools.reduce(lambda f, g: g(f), self._pipeline, x)

    def call(self, input):
        return self._pipeline(input)

使用以下代码进行测试时,它返回错误

  

TypeError:reduce()arg 2必须支持迭代

该错误与self._pipeline方法中__init__中的函数组成有关。

import tensorflow as tf
from nets.i3d import Unit3D

model = Unit3D(output_channels=64, kernel_shape=[7,7,7],
               is_training=True)

input = tf.keras.backend.random_uniform(shape=(1,3,64,224,224),
                                        dtype=tf.float32)
output = model(input)

在TensorFlow 2.0中,在急切执行期间,所有列表都包装在称为<class 'tensorflow.python.training.tracking.data_structures.ListWrapper'>的数据结构中

事实证明,此数据结构是可迭代的。我使用collections.abc模块中的Iterable类对其进行了测试。

我无法用此代码理解该问题,并且不确定这是否是TensorFlow 2.0中的内部问题,还是我在这里遗漏的基本问题。

如果有帮助,我正在使用从2.0.0-beta1分支从源代码编译的tensorflow版本r2.0。相应的git哈希为8e423e3d56390671f0d954c90f4fd163ab02a9c1

1 个答案:

答案 0 :(得分:1)

我认为您的问题与Tensorflow无关。

在这一行:

self._pipeline = lambda x: functools.reduce(lambda f, g: g(f), self._pipeline, x)

您正在用函数覆盖先前在构造函数中创建的列表。因此,在实际执行lambda时(尤其是您传递来减少的lambda),它只是一个function

如果将外部lambda重构为用于调试目的的常规函数​​,这将变得更加明显:

    def debug_func(x):
        print(type(self._pipeline))  # prints <class 'function'>
        return functools.reduce(lambda f, g: g(f), self._pipeline, x)

    self._pipeline = debug_func  # Clearly, no longer a list

解决方案

我认为您的意思是将流水线函数保存在与_pipeline不同的字段中,例如:

    # ...
    self._pipeline_func = lambda x: functools.reduce(lambda f, g: g(f), self._pipeline, x)

def call(self, input):
    return self._pipeline_func(input)