【问题标题】:For loop in tensorflow/ kerastensorflow/keras中的for循环
【发布时间】:2020-07-11 13:12:37
【问题描述】:

我正在尝试在模型定义中使用 for 循环(并尝试在 keras 中重新创建 TabNet)。

class TabNet(keras.Model):
    def __init__(self, input_dim, output_dim, steps, n_d, n_a, gamma=1.3):
        super().__init__()
        self.n_d, self.n_a, self.steps = n_d, n_a, steps
        self.shared = SharedBlock(n_d+n_a)
        self.first_block = SharedBlock(n_a)
        self.decision_blocks = [DecisionBlock(n_d+n_a)] * steps
        self.prior_scale = Prior(input_dim, gamma)
        self.bn = layers.BatchNormalization()
        self.attention = [AttentiveTransformer(input_dim)] * steps
        self.final = layers.Dense(output_dim)
        self.eps = 1e-8

    @tf.function
    def call(self, x):
        self.prior_scale.reset()
        final_out = 0
        M_loss = 0

        x = self.bn(x)
        attention = self.first_block(self.shared(x))
        for i in range(self.steps):
            mask = self.attention[i](attention, self.prior_scale.P)
            M_loss += tf.reduce_sum(mask * tf.math.log(mask + self.eps), axis=-1) / self.steps

            prior = self.prior_scale(mask)
            out = self.decision_blocks[i](self.shared(x * prior))
            attention, output = out[:,:self.n_a], out[:,self.n_a:]
            final_out += tf.nn.relu(output)

        return self.final(final_out), M_loss

如果您不知道这些单独的块是什么,只需假设它们是线性层。如果你想看看它们到底是什么,我有 a colab notebook 的完整代码。

但是,我无法训练它,因为我收到了错误 iterating over tf.Tensor is not allowed: AutoGraph did not convert this function. Try decorating it directly with @tf.function.。我已经装饰了它,但仍然没有帮助。

我相当确定当我执行model.fit(train_x, train_y) 时,是 for 循环导致了我的错误。希望有任何关于如何以 tensorflow 方式实现上述 for 循环的想法。 tf.while_loop 是我到目前为止所看到的所有内容,与我想做的相比,给出的示例相当简单。

【问题讨论】:

    标签: tensorflow keras


    【解决方案1】:

    这是我的提议……

    我不知道你的网络到底在做什么,但我可以看到你想要产生 2 个输出并将它们组合到你的损失中。您的输出之一也是网络内部某些隐藏操作的结果(M_loss)。

    因此,如果您想返回 2 个输出,则在 keras 中需要 2 个目标才能进行匹配。在我下面提供的代码中,第一个目标是真实标签,另一个是假输出(一个零数组)。

    如前所述,您尝试将组合损失构建为sparse_entropy(y_true, y_pred) - reg_sparse * M_loss。为了实现这一点,我将损失分成两部分(每个输出一个):稀疏部分和 M_loss 部分。稀疏损失只是 keras 的 SparseCategoricalCrossentropy(from_logits=True),而对于 M_loss,我按照您的代码编写了这个函数

    def m_loss(y_true, y_pred):
      m = tf.reduce_mean(y_pred, keepdims=True)
      return m
    

    m_loss 仅使用“y_pred”,它们是您网络的隐藏部分。在这种情况下, y_true 与所需的操作无关。这就是我们在拟合时传递一个零数组的原因。

    此时,我们必须将两个损失结合起来,这在 keras 中是可能的

    reg_sparse = 0.1
    
    model.compile('Adam', loss=[sce, m_loss], loss_weights=[1,-reg_sparse])
    model.fit(train_x, [train_y, np.zeros(train_y.shape[0])], epochs=3)
    

    在这种情况下,最终的损失是1*sce + (-reg_sparse)*m_loss组合的结果

    这是完整的运行代码:https://colab.research.google.com/drive/152q1rmqTJ0dWLbFN8PqzCBhWkVKirkU5?usp=sharing

    我还在 TabNet 中做了一些小改动,例如 final_out 和 M_loss 的创建方式

    【讨论】:

      【解决方案2】:

      不,实际上这不是for 循环的问题。我检查了您的代码,问题是您忘记在您的 SharedBlockDecisionBlockPrior 中调用超类构造函数。

      例如,您的代码应如下所示。

      class SharedBlock(layers.Layer):
          def __init__(self, units, mult=tf.sqrt(0.5)):
              super().__init__()
              self.layer1 = FCBlock(units)
              self.layer2 = FCBlock(units)
              self.mult = mult
      

      进行这些更改后,您将不会再看到该错误,但会出现其他问题。

      TypeError: in user code:
      
          /usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/training.py:1147 predict_function  *
              outputs = self.distribute_strategy.run(
          <ipython-input-46-f609cb1acdfa>:15 call  *
              self.prior_scale.reset()
      
          TypeError: tf__reset() missing 1 required positional argument: 'len_x'
      

      要解决此问题,您需要在 class Prior(layers.Layer): 类中进行以下更改。

      def reset(self, len_x=1.0):
              self.P = 1.0
      

      然后你会遇到另一个问题。

      AttributeError:在用户代码中:

      /usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/training.py:1147 predict_function  *
          outputs = self.distribute_strategy.run(
      <ipython-input-46-f609cb1acdfa>:26 call  *
          out = self.decision[i](self.shared(x * prior))
      
      AttributeError: 'TabNet' object has no attribute 'decision'
      

      对于这个问题,我将要求打开另一个问题,因为我认为您的主要问题已经解决。

      更新:

      您可以查看此答案的评论部分,该问题已提供解决方案AttributeError: 'TabNet' object has no attribute 'decision'

      更新:21/07

      我不得不再次让您失望,问题不在于 for 循环。

      如果您仔细查看错误日志,您会发现问题是由full_loss 函数引起的。

      <ipython-input-10-07e59f23d230>:7 full_loss  *
              logits, M_loss = y_pred
          /usr/local/lib/python3.6/dist-packages/tensorflow/python/framework/ops.py:561 __iter__
              self._disallow_iteration()
          /usr/local/lib/python3.6/dist-packages/tensorflow/python/framework/ops.py:554 _disallow_iteration
              self._disallow_when_autograph_enabled("iterating over `tf.Tensor`")
          /usr/local/lib/python3.6/dist-packages/tensorflow/python/framework/ops.py:532 _disallow_when_autograph_enabled
              " decorating it directly with @tf.function.".format(task))
      
          OperatorNotAllowedInGraphError: iterating over `tf.Tensor` is not allowed: AutoGraph did not convert this function. Try decorating it directly with @tf.function.
      

      确切的问题是由以下语句引起的。

      logits, M_loss = y_pred
      

      如果您使用以下不使用损失函数的代码,您将看到不同的结果。

      model.compile('Adam', loss='sparse_categorical_crossentropy')
      model.fit(train_x, train_y, batch_size=1)
      
      Received a label value of 1 which is outside the valid range of [0, 1).  Label values: 1
           [[node sparse_categorical_crossentropy_1/SparseSoftmaxCrossEntropyWithLogits/SparseSoftmaxCrossEntropyWithLogits (defined at <ipython-input-26-d39f533b7a69>:2) ]] [Op:__inference_train_function_18003]
      

      我不完全理解模型代码,model.summary() 对您的情况没有太大帮助。你的最后一层有问题,至少错误信息表明你没有足够的神经元(每个类1个)。

      我建议研究最后一层和损失函数。

      为什么我确定这不是由于for 循环是因为即使您评论for 循环您仍然会收到相同的错误。

      我希望我能进一步帮助你,我花了几个小时才弄明白。

      【讨论】:

      • 这是 self.decision_blocks 而不是 self.decision。 n_a 和 n_d 会引发相同的错误,可以使用 self.n_a 和 self.n_d 调用它们来解决。修复此问题后,它可以正常工作
      • 感谢你们花时间浏览我的代码(尤其是我的错误)。真的很感激!
      • 我已经修复了您提到的错误。现在错误又回到了 for 循环。如果您对如何解决这个问题有任何想法,很想听听。
      猜你喜欢
      • 2018-07-15
      • 1970-01-01
      • 1970-01-01
      • 2019-11-03
      • 2016-09-05
      • 2011-10-18
      • 2020-06-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多