运行 Tensorflow 2.0 代码会出现“ValueError:tf.function-decorated 函数试图在非首次调用时创建变量”。我做错了什么?

问题描述 投票:0回答:4

error_giving_notebook

非问题笔记本

可以看出,我在“error_giving_notebook”中使用了 tf.function 装饰器,它会抛出 ValueError,而同一笔记本除了删除 tf.function 装饰器之外没有任何更改,在“non_problematic_notebook”中运行顺利。可能是什么原因?

keras deep-learning keras-layer tensorflow2.0 tf.keras
4个回答
95
投票

当您尝试在 TF 2.0 中使用函数装饰器时,请在导入 TensorFlow 后使用以下行立即启用 run 函数:

tf.config.experimental_run_functions_eagerly(True)

由于上述内容已被弃用(不再是实验性的?),请使用以下内容:

tf.config.run_functions_eagerly(True)

如果您想了解更多信息,请参阅链接。


12
投票

这里的问题出在类 conv2d 的 call 方法的返回值上:

if self.bias:
  if self.pad == 'REFLECT':
    self.p = (self.filter_size - 1) // 2
    self.x = tf.pad(inputs, [[0, 0], [self.p, self.p], [self.p, self.p], [0, 0]], 'REFLECT')
    return Conv2D(filters=self.filter_num, kernel_size=(self.filter_size, self.filter_size), strides=(self.stride, self.stride),
                                  padding='VALID', use_bias=True, kernel_initializer=self.w, bias_initializer=self.b)(self.x)
  else:
    return Conv2D(filters=self.filter_num, kernel_size=(self.filter_size, self.filter_size), strides=(self.stride, self.stride),
                                  padding=self.pad, use_bias=True, kernel_initializer=self.w, bias_initializer=self.b)(inputs)
else:
   if self.pad == 'REFLECT':
      self.p = (self.filter_size - 1) // 2
      self.x = tf.pad(inputs, [[0, 0], [self.p, self.p], [self.p, self.p], [0, 0]], 'REFLECT')
      return Conv2D(filters=self.filter_num, kernel_size=(self.filter_size, self.filter_size), strides=(self.stride, self.stride),
                                  padding='VALID', use_bias=False, kernel_initializer=self.w)(self.x)
   else:
      return Conv2D(filters=self.filter_num, kernel_size=(self.filter_size, self.filter_size), strides=(self.stride, self.stride),
                                  padding=self.pad, use_bias=False, kernel_initializer=self.w)(inputs)

通过返回 Conv2D 对象,每次调用时都会创建 tf.Variable(权重、卷积层的偏差)

predictions = model(images)

在你的 tf 修饰的函数中。因此,例外。

解决此问题的一种可能方法是更改 conv2d 类中的构建和调用方法,如下所示:

def build(self, inputs):
  self.w = tf.random_normal_initializer(mean=0.0, stddev=1e-4)
  if self.bias:
    self.b = tf.constant_initializer(0.0)
  else:
    self.b = None

  self.conv_a = Conv2D(filters=self.filter_num, kernel_size=(self.filter_size, self.filter_size), strides=(self.stride, self.stride), padding='VALID', use_bias=True, kernel_initializer=self.w, bias_initializer=self.b)
  self.conv_b = Conv2D(filters=self.filter_num, kernel_size=(self.filter_size, self.filter_size), strides=(self.stride, self.stride), padding=self.pad, use_bias=True, kernel_initializer=self.w, bias_initializer=self.b)
  self.conv_c = Conv2D(filters=self.filter_num, kernel_size=(self.filter_size, self.filter_size), strides=(self.stride, self.stride), padding='VALID', use_bias=False, kernel_initializer=self.w)
  self.conv_d = Conv2D(filters=self.filter_num, kernel_size=(self.filter_size, self.filter_size), strides=(self.stride, self.stride),padding=self.pad, use_bias=False, kernel_initializer=self.w)  

def call(self, inputs):
  if self.bias:
    if self.pad == 'REFLECT':
      self.p = (self.filter_size - 1) // 2
      self.x = tf.pad(inputs, [[0, 0], [self.p, self.p], [self.p, self.p], [0, 0]], 'REFLECT')
      return self.conv_a(self.x)
    else:
      return self.conv_b(inputs)
  else:
     if self.pad == 'REFLECT':
        self.p = (self.filter_size - 1) // 2
        self.x = tf.pad(inputs, [[0, 0], [self.p, self.p], [self.p, self.p], [0, 0]], 'REFLECT')
        return self.conv_c(self.x)
     else:
        return self.conv_d(inputs)

为了更好地理解 AutoGraph 以及 @tf.function 的工作原理,我建议看一下 this


3
投票

当您尝试使用 TF 2.0 中的函数装饰器时,请在导入 TensorFlow 后使用以下行来立即启用 run 函数:

import tensorflow as tf
tf.config.run_functions_eagerly(True)

0
投票
tf.config.run_functions_eagerly(True)

为我工作

© www.soinside.com 2019 - 2024. All rights reserved.