更改 Keras 模型变量
Change Keras Model variable
我想逐渐增加 Keras 模型中用于计算损失的系数。变量值基于当前纪元。但是,当我想设置值时,出现以下错误:
float object has no attribute dtype
我的代码:
def warm_up(epoch, logs):
new_value= tf.keras.backend.variable(np.array(1.0, dtype=np.float32), dtype=tf.float32)
tf.keras.backend.set_value(model.variable1, new_value)
callback = tf.keras.callbacks.LambdaCallback(on_epoch_begin=warm_up)
model.fit(..., callbacks = [callback])
如何在训练期间更改自定义 Keras 模型中的变量?我正在使用 Tensorflow 2.2。
回溯:
\Anaconda3\lib\site-packages\tensorflow\python\keras\engine\training.py in _method_wrapper(self, *args, **kwargs)
64 def _method_wrapper(self, *args, **kwargs):
65 if not self._in_multi_worker_mode(): # pylint: disable=protected-access
---> 66 return method(self, *args, **kwargs)
67
68 # Running inside `run_distribute_coordinator` already.
~\Anaconda3\lib\site-packages\tensorflow\python\keras\engine\training.py in fit(self, x, y, batch_size, epochs, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_epoch, steps_per_epoch, validation_steps, validation_batch_size, validation_freq, max_queue_size, workers, use_multiprocessing)
836 for epoch, iterator in data_handler.enumerate_epochs():
837 self.reset_metrics()
--> 838 callbacks.on_epoch_begin(epoch)
839 with data_handler.catch_stop_iteration():
840 for step in data_handler.steps():
~\Anaconda3\lib\site-packages\tensorflow\python\keras\callbacks.py in on_epoch_begin(self, epoch, logs)
347 logs = self._process_logs(logs)
348 for callback in self.callbacks:
--> 349 callback.on_epoch_begin(epoch, logs)
350 self._reset_batch_timing()
351
c:\Users\..\training.py in warm_up(epoch, logs)
379 def warm_up(epoch, logs):
380 test = tf.keras.backend.variable(np.array(1.0, dtype=np.float32), dtype=tf.float32)
--> 381 tf.keras.backend.set_value(model.variable1, test)
382
383
~\Anaconda3\lib\site-packages\tensorflow\python\keras\backend.py in set_value(x, value)
3349 (of the same shape).
3350 """
-> 3351 value = np.asarray(value, dtype=dtype(x))
3352 if ops.executing_eagerly_outside_functions():
3353 x.assign(value)
~\Anaconda3\lib\site-packages\tensorflow\python\keras\backend.py in dtype(x)
1266
1267 """
-> 1268 return x.dtype.base_dtype.name
1269
1270
AttributeError: 'float' object has no attribute 'dtype'
编辑:我将代码更改为以下内容:
class LossCallback(tf.keras.callbacks.Callback):
def __init__(self):
super(LossCallback, self).__init__()
self.model.beta_x = tf.Variable(1.0, trainable=False, name='weight1', dtype=tf.float32)
def on_epoch_begin(self, epoch, logs=None):
tf.keras.backend.set_value(self.model.beta_x, tf.constant(0.5) * epoch)
def on_epoch_end(self, epoch, logs=None):
logs = logs or {}
logs['beta_x'] = tf.keras.backend.get_value(self.model.beta_x)
我仍然在 on_epoch_begin
中遇到错误:'NoneType' object has no attribute 'beta_x'
。
避免直接编辑变量。
您必须像这样访问 keras 变量
import tensorflow as tf
from tensorflow import keras
import numpy as np
def warm_up(epoch, logs):
val = keras.backend.get_value(model.optimizer.lr)
val *= 1.1
tf.keras.backend.set_value(model.optimizer.lr, val)
callback = tf.keras.callbacks.LambdaCallback(on_epoch_begin=warm_up)
model = tf.keras.models.Sequential([
keras.layers.Dense(10, 'relu'),
keras.layers.Dense(1, 'sigmoid')
])
model.compile(loss='binary_crossentropy')
X_train = tf.random.uniform((10,10))
y_train = tf.ones((10,))
model.fit(X_train, y_train,
callbacks = [callback])
请注意我是如何获取当前值的 val = keras.backend.get_value(model.optimizer.lr)
。这是在运行时获取正确值的正确方法。
另外,不要在循环内使用或声明新变量。您可能可以通过阅读和更改旧版本获得 new_value
。
此外,请避免在回调中使用除 tensorflow 之外的任何其他库,尤其是当您的回调将经常被调用时。不要使用 numpy,使用 tensorflow。几乎总是有一个 tensorflow optaion 可以满足您的需求。
编辑:
如果你有一些自定义值要更新,你可以使用这样的模式:
class LossCallback(tf.keras.callbacks.Callback):
def __init__(self):
super(LossCallback, self).__init__()
self.someValue = tf.Variable(1.0, trainable=False, name='weight1', dtype=tf.float32)
def on_epoch_end(self, epoch, logs=None):
tf.keras.backend.set_value(self.model.loss.someValue, self.someValue * epoch)
或者您仍然可以尝试使用 lambda 回调。
从回调中,您可以访问模型的任何变量。像这样self.model.someVariable
。您还可以访问在模型的自定义 __init__
函数中定义的任何自定义变量,如下所示:
#in model's custom __init__
def __init__(self, someArgs):
...
self.someArg = someArgs
...
#in callback's "on_epoch_..." method
...
keras.backend.set_value(self.model.someArg, 42)
...
请注意,您不能在回调的 __init__
函数中使用 self.model
,因为当回调的 __init__
为模型时,模型仍未初始化打电话。
这有帮助吗?
编辑 2:
当我首先初始化我的模型并将其作为额外参数添加到它起作用的回调方法时。所以解决方法如下:
class LossCallback(tf.keras.callbacks.Callback):
def __init__(self, model):
super(LossCallback, self).__init__()
model.beta_x = tf.Variable(1.0, trainable=False, name='weight1', dtype=tf.float32)
def on_epoch_begin(self, epoch, logs=None):
tf.keras.backend.set_value(self.model.beta_x, tf.constant(0.5) * epoch)
def on_epoch_end(self, epoch, logs=None):
logs = logs or {}
logs['beta_x'] = tf.keras.backend.get_value(self.model.beta_x)
model = create_model() # initialize custom keras model
callback = LossCallback(model)
model.fit(..., callbacks=[callback])
感谢@tornikeo 的大力帮助!
我想逐渐增加 Keras 模型中用于计算损失的系数。变量值基于当前纪元。但是,当我想设置值时,出现以下错误:
float object has no attribute dtype
我的代码:
def warm_up(epoch, logs):
new_value= tf.keras.backend.variable(np.array(1.0, dtype=np.float32), dtype=tf.float32)
tf.keras.backend.set_value(model.variable1, new_value)
callback = tf.keras.callbacks.LambdaCallback(on_epoch_begin=warm_up)
model.fit(..., callbacks = [callback])
如何在训练期间更改自定义 Keras 模型中的变量?我正在使用 Tensorflow 2.2。
回溯:
\Anaconda3\lib\site-packages\tensorflow\python\keras\engine\training.py in _method_wrapper(self, *args, **kwargs)
64 def _method_wrapper(self, *args, **kwargs):
65 if not self._in_multi_worker_mode(): # pylint: disable=protected-access
---> 66 return method(self, *args, **kwargs)
67
68 # Running inside `run_distribute_coordinator` already.
~\Anaconda3\lib\site-packages\tensorflow\python\keras\engine\training.py in fit(self, x, y, batch_size, epochs, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_epoch, steps_per_epoch, validation_steps, validation_batch_size, validation_freq, max_queue_size, workers, use_multiprocessing)
836 for epoch, iterator in data_handler.enumerate_epochs():
837 self.reset_metrics()
--> 838 callbacks.on_epoch_begin(epoch)
839 with data_handler.catch_stop_iteration():
840 for step in data_handler.steps():
~\Anaconda3\lib\site-packages\tensorflow\python\keras\callbacks.py in on_epoch_begin(self, epoch, logs)
347 logs = self._process_logs(logs)
348 for callback in self.callbacks:
--> 349 callback.on_epoch_begin(epoch, logs)
350 self._reset_batch_timing()
351
c:\Users\..\training.py in warm_up(epoch, logs)
379 def warm_up(epoch, logs):
380 test = tf.keras.backend.variable(np.array(1.0, dtype=np.float32), dtype=tf.float32)
--> 381 tf.keras.backend.set_value(model.variable1, test)
382
383
~\Anaconda3\lib\site-packages\tensorflow\python\keras\backend.py in set_value(x, value)
3349 (of the same shape).
3350 """
-> 3351 value = np.asarray(value, dtype=dtype(x))
3352 if ops.executing_eagerly_outside_functions():
3353 x.assign(value)
~\Anaconda3\lib\site-packages\tensorflow\python\keras\backend.py in dtype(x)
1266
1267 """
-> 1268 return x.dtype.base_dtype.name
1269
1270
AttributeError: 'float' object has no attribute 'dtype'
编辑:我将代码更改为以下内容:
class LossCallback(tf.keras.callbacks.Callback):
def __init__(self):
super(LossCallback, self).__init__()
self.model.beta_x = tf.Variable(1.0, trainable=False, name='weight1', dtype=tf.float32)
def on_epoch_begin(self, epoch, logs=None):
tf.keras.backend.set_value(self.model.beta_x, tf.constant(0.5) * epoch)
def on_epoch_end(self, epoch, logs=None):
logs = logs or {}
logs['beta_x'] = tf.keras.backend.get_value(self.model.beta_x)
我仍然在 on_epoch_begin
中遇到错误:'NoneType' object has no attribute 'beta_x'
。
避免直接编辑变量。 您必须像这样访问 keras 变量
import tensorflow as tf
from tensorflow import keras
import numpy as np
def warm_up(epoch, logs):
val = keras.backend.get_value(model.optimizer.lr)
val *= 1.1
tf.keras.backend.set_value(model.optimizer.lr, val)
callback = tf.keras.callbacks.LambdaCallback(on_epoch_begin=warm_up)
model = tf.keras.models.Sequential([
keras.layers.Dense(10, 'relu'),
keras.layers.Dense(1, 'sigmoid')
])
model.compile(loss='binary_crossentropy')
X_train = tf.random.uniform((10,10))
y_train = tf.ones((10,))
model.fit(X_train, y_train,
callbacks = [callback])
请注意我是如何获取当前值的 val = keras.backend.get_value(model.optimizer.lr)
。这是在运行时获取正确值的正确方法。
另外,不要在循环内使用或声明新变量。您可能可以通过阅读和更改旧版本获得 new_value
。
此外,请避免在回调中使用除 tensorflow 之外的任何其他库,尤其是当您的回调将经常被调用时。不要使用 numpy,使用 tensorflow。几乎总是有一个 tensorflow optaion 可以满足您的需求。
编辑: 如果你有一些自定义值要更新,你可以使用这样的模式:
class LossCallback(tf.keras.callbacks.Callback):
def __init__(self):
super(LossCallback, self).__init__()
self.someValue = tf.Variable(1.0, trainable=False, name='weight1', dtype=tf.float32)
def on_epoch_end(self, epoch, logs=None):
tf.keras.backend.set_value(self.model.loss.someValue, self.someValue * epoch)
或者您仍然可以尝试使用 lambda 回调。
从回调中,您可以访问模型的任何变量。像这样self.model.someVariable
。您还可以访问在模型的自定义 __init__
函数中定义的任何自定义变量,如下所示:
#in model's custom __init__
def __init__(self, someArgs):
...
self.someArg = someArgs
...
#in callback's "on_epoch_..." method
...
keras.backend.set_value(self.model.someArg, 42)
...
请注意,您不能在回调的 __init__
函数中使用 self.model
,因为当回调的 __init__
为模型时,模型仍未初始化打电话。
这有帮助吗?
编辑 2: 当我首先初始化我的模型并将其作为额外参数添加到它起作用的回调方法时。所以解决方法如下:
class LossCallback(tf.keras.callbacks.Callback):
def __init__(self, model):
super(LossCallback, self).__init__()
model.beta_x = tf.Variable(1.0, trainable=False, name='weight1', dtype=tf.float32)
def on_epoch_begin(self, epoch, logs=None):
tf.keras.backend.set_value(self.model.beta_x, tf.constant(0.5) * epoch)
def on_epoch_end(self, epoch, logs=None):
logs = logs or {}
logs['beta_x'] = tf.keras.backend.get_value(self.model.beta_x)
model = create_model() # initialize custom keras model
callback = LossCallback(model)
model.fit(..., callbacks=[callback])
感谢@tornikeo 的大力帮助!