Запуск простой регрессии в базе Tensorflow 2.0

1

Я изучаю Tensorflow 2.0, и я подумал, что было бы неплохо реализовать самую простую линейную регрессию в Tensorflow. К сожалению, я столкнулся с несколькими проблемами, и мне было интересно, сможет ли кто-нибудь здесь помочь.

Рассмотрим следующую настройку:

import tensorflow as tf # 2.0.0-alpha0
import numpy as np

x_data = np.random.randn(2000, 1)

w_real = [0.7] # coefficients
b_real = -0.2 # global bias
noise = np.random.randn(1, 2000) * 0.5 # level of noise
y_data = np.matmul(w_real, x_data.T) + b_real + noise

Теперь с определением модели:

# modelling this data with tensorflow (manually!)
class SimpleRegressionNN(tf.keras.Model):

    def __init__(self):
        super(SimpleRegressionNN, self).__init__()
        self.input_layer = tf.keras.layers.Input
        self.output_layer = tf.keras.layers.Dense(1)


    def call(self, data_input):
        model = self.input_layer(data_input)
        model = self.output_layer(model)
        # open question: how to account for the intercept/bias term?
        # Ideally, we'd want to generate preds as matmult(X,W) + b
        return model

nn_regressor = SimpleRegressionNN()

reg_loss = tf.keras.losses.MeanSquaredError()
reg_optimiser = tf.keras.optimizers.SGD(0.1)
metric_accuracy = tf.keras.metrics.mean_squared_error

# define forward step
@tf.function
def train_step(x_sample, y_sample):
  with tf.GradientTape() as tape:
    predictions = nn_regressor(x_sample)
    loss = reg_loss(y_sample, predictions)
    gradients = tape.gradient(loss, nn_regressor.trainable_variables) # had to indent this!
  reg_optimiser.apply_gradients(zip(gradients, nn_regressor.trainable_variables))  
  metric_accuracy(y_sample, predictions)

#%%
# run the model
for epoch in range(10):
    for x_point, y_point in zip(x_data.T[0], y_data[0]): # batch of 1
        train_step(x_sample=x_point, y_sample=y_point)
    print("MSE: {}".format(metric_accuracy.result()))

К сожалению, я получаю следующую ошибку:

TypeError: You are attempting to use Python control flow in a layer that was not declared to be dynamic. Pass 'dynamic=True' to the class constructor.
Encountered error:
"""
Tensor objects are only iterable when eager execution is enabled. To iterate over this tensor use tf.map_fn.
"""

Полный вывод ошибок здесь:


---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

/anaconda3/lib/python3.6/site-packages/tensorflow/python/keras/engine/base_layer.py in __call__(self, inputs, *args, **kwargs)
    611                                                       inputs)) as auto_updater:
--> 612                 outputs = self.call(inputs, *args, **kwargs)
    613                 auto_updater.set_outputs(outputs)

<ipython-input-5-8464ad8bcf07> in call(self, data_input)
      7     def call(self, data_input):
----> 8         model = self.input_layer(data_input)
      9         model = self.output_layer(model)

/anaconda3/lib/python3.6/site-packages/tensorflow/python/keras/engine/input_layer.py in Input(shape, batch_size, name, dtype, sparse, tensor, **kwargs)
    232       sparse=sparse,
--> 233       input_tensor=tensor)
    234   # Return tensor including '_keras_history'.

/anaconda3/lib/python3.6/site-packages/tensorflow/python/keras/engine/input_layer.py in __init__(self, input_shape, batch_size, dtype, input_tensor, sparse, name, **kwargs)
     93       if input_shape is not None:
---> 94         batch_input_shape = (batch_size,) + tuple(input_shape)
     95       else:

/anaconda3/lib/python3.6/site-packages/tensorflow/python/framework/ops.py in __iter__(self)
    448       raise TypeError(
--> 449           "Tensor objects are only iterable when eager execution is "
    450           "enabled. To iterate over this tensor use tf.map_fn.")

TypeError: Tensor objects are only iterable when eager execution is enabled. To iterate over this tensor use tf.map_fn.


During handling of the above exception, another exception occurred:

TypeError                                 Traceback (most recent call last)

<ipython-input-22-e1bde858b0fc> in <module>()
      3     #train_step(x_sample=x_data.T[0], y_sample=y_data[0])
      4     for x_point, y_point in zip(x_data.T[0], y_data[0]):
----> 5         train_step(x_sample=x_point, y_sample=y_point)
      6     print("MSE: {}".format(metric_accuracy.result()))
      7 

/anaconda3/lib/python3.6/site-packages/tensorflow/python/eager/def_function.py in __call__(self, *args, **kwds)
    416       # In this case we have not created variables on the first call. So we can
    417       # run the first trace but we should fail if variables are created.
--> 418       results = self._stateful_fn(*args, **kwds)
    419       if self._created_variables:
    420         raise ValueError("Creating variables on a non-first call to a function"

/anaconda3/lib/python3.6/site-packages/tensorflow/python/eager/function.py in __call__(self, *args, **kwargs)
   1285   def __call__(self, *args, **kwargs):
   1286     """Calls a graph function specialized to the inputs."""
-> 1287     graph_function, args, kwargs = self._maybe_define_function(args, kwargs)
   1288     return graph_function._filtered_call(args, kwargs)  # pylint: disable=protected-access
   1289 

/anaconda3/lib/python3.6/site-packages/tensorflow/python/eager/function.py in _maybe_define_function(self, args, kwargs)
   1609           relaxed_arg_shapes)
   1610       graph_function = self._create_graph_function(
-> 1611           args, kwargs, override_flat_arg_shapes=relaxed_arg_shapes)
   1612       self._function_cache.arg_relaxed[rank_only_cache_key] = graph_function
   1613 

/anaconda3/lib/python3.6/site-packages/tensorflow/python/eager/function.py in _create_graph_function(self, args, kwargs, override_flat_arg_shapes)
   1510             arg_names=arg_names,
   1511             override_flat_arg_shapes=override_flat_arg_shapes,
-> 1512             capture_by_value=self._capture_by_value),
   1513         self._function_attributes)
   1514 

/anaconda3/lib/python3.6/site-packages/tensorflow/python/framework/func_graph.py in func_graph_from_py_func(name, python_func, args, kwargs, signature, func_graph, autograph, autograph_options, add_control_dependencies, arg_names, op_return_value, collections, capture_by_value, override_flat_arg_shapes)
    692                                           converted_func)
    693 
--> 694       func_outputs = python_func(*func_args, **func_kwargs)
    695 
    696       # invariant: 'func_outputs' contains only Tensors, IndexedSlices,

/anaconda3/lib/python3.6/site-packages/tensorflow/python/eager/def_function.py in wrapped_fn(*args, **kwds)
    315         # __wrapped__ allows AutoGraph to swap in a converted function. We give
    316         # the function a weak reference to itself to avoid a reference cycle.
--> 317         return weak_wrapped_fn().__wrapped__(*args, **kwds)
    318     weak_wrapped_fn = weakref.ref(wrapped_fn)
    319 

/anaconda3/lib/python3.6/site-packages/tensorflow/python/framework/func_graph.py in wrapper(*args, **kwargs)
    684                   optional_features=autograph_options,
    685                   force_conversion=True,
--> 686               ), args, kwargs)
    687 
    688         # Wrapping around a decorator allows checks like tf_inspect.getargspec

/anaconda3/lib/python3.6/site-packages/tensorflow/python/autograph/impl/api.py in converted_call(f, owner, options, args, kwargs)
    390     return _call_unconverted(f, args, kwargs)
    391 
--> 392   result = converted_f(*effective_args, **kwargs)
    393 
    394   # The converted function closure is simply inserted into the function's

/var/folders/8_/pl9fgq297ld3b7kgy5tmvf700000gn/T/tmpluzodr7d.py in tf__train_step(x_sample, y_sample)
      2 def tf__train_step(x_sample, y_sample):
      3   with tf.GradientTape() as tape:
----> 4     predictions = ag__.converted_call(nn_regressor, None, ag__.ConversionOptions(recursive=True, verbose=0, strip_decorators=(tf.function, defun, ag__.convert, ag__.do_not_convert, ag__.converted_call), force_conversion=False, optional_features=(), internal_convert_user_code=True), (x_sample,), {})
      5     loss = ag__.converted_call(reg_loss, None, ag__.ConversionOptions(recursive=True, verbose=0, strip_decorators=(tf.function, defun_1, ag__.convert, ag__.do_not_convert, ag__.converted_call), force_conversion=False, optional_features=(), internal_convert_user_code=True), (y_sample, predictions), {})
      6     gradients = ag__.converted_call('gradient', tape, ag__.ConversionOptions(recursive=True, verbose=0, strip_decorators=(tf.function, defun_2, ag__.convert, ag__.do_not_convert, ag__.converted_call), force_conversion=False, optional_features=(), internal_convert_user_code=True), (loss, nn_regressor.trainable_variables), {})

/anaconda3/lib/python3.6/site-packages/tensorflow/python/autograph/impl/api.py in converted_call(f, owner, options, args, kwargs)
    265 
    266   if not options.force_conversion and conversion.is_whitelisted_for_graph(f):
--> 267     return _call_unconverted(f, args, kwargs)
    268 
    269   # internal_convert_user_code is for example turned off when issuing a dynamic

/anaconda3/lib/python3.6/site-packages/tensorflow/python/autograph/impl/api.py in _call_unconverted(f, args, kwargs)
    186     return f.__self__.call(args, kwargs)
    187 
--> 188   return f(*args, **kwargs)
    189 
    190 

/anaconda3/lib/python3.6/site-packages/tensorflow/python/keras/engine/base_layer.py in __call__(self, inputs, *args, **kwargs)
    623                                   'dynamic. Pass 'dynamic=True' to the class '
    624                                   'constructor.\nEncountered error:\n"""\n' +
--> 625                                   exception_str + '\n"""')
    626               raise
    627           else:

TypeError: You are attempting to use Python control flow in a layer that was not declared to be dynamic. Pass 'dynamic=True' to the class constructor.
Encountered error:
"""
Tensor objects are only iterable when eager execution is enabled. To iterate over this tensor use tf.map_fn.
"""

Проблема в том, что 2.0 по умолчанию настроен на активное выполнение!

В дополнение к этой проблеме у меня есть несколько дополнительных вопросов:

  1. Каков наилучший способ учета перехвата здесь?
  2. Является ли общий подход разумным или я делаю что-то странное здесь? (игнорируя размер пакета и тот факт, что мне нужно проверить данные, это всего лишь игрушечный пример)

Большое спасибо!

  • 0
    (1) tf.keras.layers.Dense() добавляет перехват по умолчанию. Какова точная линия ошибок?
  • 0
    Спасибо за ваш быстрый ответ. Боюсь, найти источник ошибки не так просто. Я включил весь вывод ошибок, надеюсь, это поможет. Я только что попытался запустить функцию train_step сам по себе, и она выдала мне ту же ошибку, что я могу сузить.
Теги:
tensorflow
machine-learning
deep-learning
regression

1 ответ

1
Лучший ответ

У меня есть следующие замечания:

  • Вам не нужен Input слой в вашей модели SimpleRegression. Кроме того, не вызывайте тензорный выход слоя по имени " model " (как вы делаете в методе call()). Это действительно сбивает с толку.
  • Вы не передаете правильные формы в функцию train_step. (n_samples, input_dim) получение (n_samples, input_dim) во время передачи (input_dim ,).
  • Помните, что в tensorflow первым измерением тензора всегда является размер партии (то есть количество выборок). Используйте это всегда так, без транспонирования.
  • Почему вы называете metric_accuracy = tf.keras.metrics.mean_squared_error точность? У вас есть проблема регрессии, нет такой вещи, как точность в регрессии. Кроме того, почему вы определяете дважды и вычисляете дважды mse?
  • Если вы конвертируете свои данные с помощью tf.convert_to_tensor() выполнение будет быстрее.
  • Функция train_step() выполняет прямые и обратные проходы, а не только прямой проход.
  • Используйте небольшие наборы данных для примеров игрушек (2-10 примеров, а не 2000), особенно если вы не знаете, работает ли ваш код!
  • Ваша функция train_step() ничего не возвращает, как вы ожидаете вывести значение потери mse.

Это исправленная версия вашего кода:

import tensorflow as tf # 2.0.0-alpha0
import numpy as np

x_data = np.random.randn(5, 2)

w_real = 0.7 # coefficients
b_real = -0.2 # global bias
noise = np.random.randn(5, 2) * 0.01 # level of noise
y_data = w_real * x_data + b_real + noise

class SimpleRegressionNN(tf.keras.Model):

    def __init__(self):
        super(SimpleRegressionNN, self).__init__()

        self.output_layer = tf.keras.layers.Dense(1, input_shape=(2, ))

    def call(self, data_input):
        result = self.output_layer(data_input)
        return result

reg_loss = tf.keras.losses.MeanSquaredError()
reg_optimiser = tf.keras.optimizers.SGD(0.1)

nn_regressor = SimpleRegressionNN()

@tf.function
def train_step(x_sample, y_sample):
    with tf.GradientTape() as tape:
        predictions = nn_regressor(x_sample)
        loss = reg_loss(y_sample, predictions)
    gradients = tape.gradient(loss, nn_regressor.trainable_variables) # had to indent this!
    reg_optimiser.apply_gradients(zip(gradients, nn_regressor.trainable_variables))  

    return loss

for x_point, y_point in zip(x_data, y_data): # batch of 1
    x_point, y_point = tf.convert_to_tensor([x_point]), tf.convert_to_tensor([y_point])
    mse = train_step(x_sample=x_point, y_sample=y_point)
    print("MSE: {}".format(mse.numpy()))
  • 0
    Влад, спасибо большое! Я следил за несколькими примерами, которые я мог найти в Интернете (но в TF 2.0 почти ничего не было), поэтому в моем коде было несколько странностей. Ваш пример имеет смысл, еще раз спасибо!
  • 1
    Рад, что это помогло. Я исправил небольшую неточность в моем коде. Лучше вычислять и применять градиенты вне контекста GradientTape (если вы не собираетесь вычислять вторые производные). Это не ошибка, но если вы сделаете это в контексте GradientTape он запишет эти операции в буфер, который добавляет ненужные накладные расходы.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню