Выполнение кода Tensorflow 2.0 дает сообщение «ValueError: функция, украшенная tf.function, пыталась создать переменные не при первом вызове». Что я делаю неправильно?

error_giving_notebook

non_problematic_notebook

Как видно, я использовал декоратор tf.function в error_giving_notebook, и он выдает ошибку ValueError, в то время как тот же блокнот без каких-либо изменений, за исключением удаления декоратора tf.function, плавно работает в non_problematic_notebook. В чем может быть причина?


person Gaurav Singh    schedule 12.10.2019    source источник
comment
Если кажется, что вы вызываете функции более одного раза, и функции пытаются создать новые переменные, в то время как они должны создавать новые переменные только при первом вызове? --- Кстати, я никогда не использовал @tf.function для обучающих циклов, есть ли особая причина, по которой вы хотите его использовать?   -  person Daniel Möller    schedule 12.10.2019
comment
tensorflow.org/tutorials/customization/performance#variables --- I ' я не уверен, что создает новую переменную в вашем коде внутри этих функций, но, возможно, это делает градиентная лента ...   -  person Daniel Möller    schedule 12.10.2019
comment
Поразмыслив, я считаю, что графическая версия обучения должна использовать tf.gradients вместо градиентной ленты. Но для tf.gradients, чтобы работать, вся модель от начала до конца тоже должна быть графиком. (Что в вашем случае кажется нормальным). Теперь, если ваш код - это только то, что находится в записной книжке, вы действительно можете подумать об использовании model.fit() с обратным вызовом вместо настраиваемого цикла обучения.   -  person Daniel Möller    schedule 12.10.2019


Ответы (2)


Проблема здесь в возвращаемых значениях метода вызова класса conv2d:

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 (s) создаются (веса, смещение слоя conv) каждый раз, когда вы вызываете

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, я предлагаю взглянуть на это

person user9342787    schedule 23.10.2019

Поскольку вы пытаетесь использовать декоратор функций в TF 2.0, пожалуйста, сразу же включите функцию запуска, используя строку ниже после импорта TensorFlow:

tf.config.experimental_run_functions_eagerly(True)

Поскольку указанное выше устарело (больше не является экспериментальным?), Используйте вместо этого следующее:

tf.config.run_functions_eagerly(True)

Если вы хотите узнать больше, перейдите по этой ссылке.

person Apoorv Mishra    schedule 06.12.2019
comment
На самом деле я использовал общий слой, который вызывал ошибку. Это спасло меня от безумия спасибо! - person Lamberto Basti; 12.11.2020
comment
Эта ошибка может произойти при использовании Keras. Чтобы использовать это решение, просто выполните import tensorflow as tf, затем tf.config... - person YScharf; 05.04.2021