我正在学习Tensorflow 2.0,并且我认为实现最基本的简单线性回归是一个好主意。不幸的是,我遇到了几个问题,我想知道这里是否有人可以帮助我。
考虑以下设置:
import tensorflow as tf # 2.0.0-alpha0import numpy as npx_data = np.random.randn(2000, 1)w_real = [0.7] # coefficientsb_real = -0.2 # global biasnoise = np.random.randn(1, 2000) * 0.5 # level of noisey_data = np.matmul(w_real, x_data.T) + b_real + noise
现在继续进行模型定义:
# 使用tensorflow手动建模这些数据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) # 开放问题:如何考虑截距/偏置项? # 理想情况下,我们希望生成的预测值为matmult(X,W) + b return modelnn_regressor = SimpleRegressionNN()reg_loss = tf.keras.losses.MeanSquaredError()reg_optimiser = tf.keras.optimizers.SGD(0.1)metric_accuracy = tf.keras.metrics.mean_squared_error# 定义前向步骤@tf.functiondef 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) # 需要缩进这行! reg_optimiser.apply_gradients(zip(gradients, nn_regressor.trainable_variables)) metric_accuracy(y_sample, predictions)#%%# 运行模型for epoch in range(10): for x_point, y_point in zip(x_data.T[0], y_data[0]): # 批量大小为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's 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默认设置为启用急切执行模式!
除了这个问题之外,我还有一些额外的问题:
- 在这里考虑截距项的最佳方法是什么?
- 这种方法是否合理,或者我在这里做了一些奇怪的事情?(忽略批量大小和没有验证数据的事实,这只是一个玩具示例)
非常感谢!
回答:
我有以下几点评论:
- 在你的
SimpleRegression
模型中不需要Input
层。另外,不要在call()
方法中将层的张量输出命名为”model
“。这真的很容易混淆。 - 你没有向
train_step
函数传递正确的形状。它期望接收(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-alpha0import numpy as npx_data = np.random.randn(5, 2)w_real = 0.7 # coefficientsb_real = -0.2 # global biasnoise = np.random.randn(5, 2) * 0.01 # level of noisey_data = w_real * x_data + b_real + noiseclass 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 resultreg_loss = tf.keras.losses.MeanSquaredError()reg_optimiser = tf.keras.optimizers.SGD(0.1)nn_regressor = SimpleRegressionNN()@tf.functiondef 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) # 需要缩进这行! reg_optimiser.apply_gradients(zip(gradients, nn_regressor.trainable_variables)) return lossfor x_point, y_point in zip(x_data, y_data): # 批量大小为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()))