Tensorflow 自定义训练步骤失败 "Unexpected result of train_function"
Tensorflow custom training step fails with "Unexpected result of train_function"
我已根据 here 中描述的过程对 tensorflow.keras.models.Model
class 进行了子class 编写并编写了自定义 train_step
。该模型将两个二维数组作为输入(它是一个多输入模型)并产生一个浮点值作为输出。
我正在使用以下方法将 TFRecord 数据集传递给模型,其中 parse_element_func
returns 一个包含 4 个项目的元组:(二维数组、二维数组、浮点数、浮点数)。第一项和第二项是输入数据,第三项是目标值,最后一项是自定义损失函数中使用的数字,因训练示例而异。这些项目中的每一项都在训练期间扩展了 1 个维度,因为它们是批处理的。
train_dataset = tf.data.TFRecordDataset(records_train).map(parse_element_func).batch(batch_size).prefetch(tf.data.AUTOTUNE)
class 看起来像这样:
import tensorflow.keras.backend as K
from tensorflow.keras.metrics import Mean
from tensorflow.keras.models import Model
loss_tracker = Mean(name="loss")
custom_metric_tracker = Mean(name="custom_metric")
magic_number = 4
class CustomModel(Model):
def __init__(self, *args, clip_global_norm: float = 1.0, **kwargs):
super(CustomModel, self).__init__(*args, **kwargs)
self.clip_global_norm = clip_global_norm
def train_step(self, data):
# unpack data
x_input_1, x_input_2, y_true, loss_modifier = data
with tf.GradientTape() as tape:
# predict
y_pred = self((x_input_1, x_input_2), training=True)
# calculate loss
weights = K.pow(K.square(loss_modifier + magic_number), -1)
squared_error = K.square(y_pred - y_true)
loss = K.mean(weights * squared_error, axis=0)
# calculate custom metric
num = K.sum(K.square(y_pred - y_true), axis=0)
denom = K.sum(y_true - K.mean(y_true), axis=0)
custom_metric_value = 1 - num / (denom + 0.000001) # to prevent being 0
trainable_vars = self.trainable_variables
gradients = tape.gradient(loss, trainable_vars)
gradients, _ = tf.clip_by_global_norm(gradients, clip_norm=self.clip_global_norm)
self.optimizer.apply_gradients(zip(gradients, trainable_vars))
loss_tracker.update_state(loss)
custom_metric_tracker.update_state(custom_metric_value)
return {"loss": loss_tracker.result(), "custom_metric": custom_metric_tracker.result()}
模型构建和编译都很好,我已经使用 plot_model
检查了所有形状是否正确。当我测试加载数据时,一切都以正确的形状和值存在。无论如何,我得到相同的 ValueError:
ValueError: Unexpected result of `train_function` (Empty logs).
这是我收到的唯一消息。除了与训练功能有关外,它没有告诉我任何错误,并且它发生在 model.fit
期间。当我调用它时,它在我的脚本中看起来像这样:
train_dataset = tf.data.TFRecordDataset(records_train).map(parse_element_func).batch(batch_size).prefetch(tf.data.AUTOTUNE)
val_dataset = tf.data.TFRecordDataset(records_val).map(parse_element_func).batch(batch_size).prefetch(tf.data.AUTOTUNE)
model = build_model_func(**model_build_params)
model.compile(optimizer="adam")
history = model.fit(
train_dataset,
batch_size=batch_size,
epochs=epochs,
validation_data=val_dataset,
)
我是否运行热切与否并没有什么不同。我想也许我的数据集传递一个包含 4 个值的元组可能是问题所在,但据我所知,通过文档它应该没问题,甚至我修改了 TFRecord 数据集元素解析器以仅提供输入和输出而不提供其他值(所以 2 个值而不是 4 个),我仍然得到同样的错误。
我在这上面花了好几个小时,只是不知道为什么会出现这个错误,也不知道这个函数或我的过程有什么问题。谁能帮忙弄清楚如何解决这个错误?
我终于弄明白了,同时根据 M.Innat 的建议创建了可重现的代码。错误消息让我相信它与自定义训练功能有关,但实际上与 TFRecordDataset 有关。
事实证明,在脚本中的某个时刻,records_train
原本有一个 tfrecord 文件名列表,变成了一个空列表。所以基本上没有数据传递给 model.fit
.
作为参考,这是产生错误的代码行:
history = model.fit(
train_dataset,
batch_size=batch_size,
epochs=epochs,
validation_data=val_dataset,
)
但错误的实际来源是这一行,其中 records_train = []
:
train_dataset = tf.data.TFRecordDataset(records_train).map(parse_element_func).batch(batch_size).prefetch(tf.data.AUTOTUNE)
这是错误信息:
ValueError: Unexpected result of `train_function` (Empty logs).
一个非常无用的错误消息,但也许这个 post 会对以后的人有所帮助。
我已根据 here 中描述的过程对 tensorflow.keras.models.Model
class 进行了子class 编写并编写了自定义 train_step
。该模型将两个二维数组作为输入(它是一个多输入模型)并产生一个浮点值作为输出。
我正在使用以下方法将 TFRecord 数据集传递给模型,其中 parse_element_func
returns 一个包含 4 个项目的元组:(二维数组、二维数组、浮点数、浮点数)。第一项和第二项是输入数据,第三项是目标值,最后一项是自定义损失函数中使用的数字,因训练示例而异。这些项目中的每一项都在训练期间扩展了 1 个维度,因为它们是批处理的。
train_dataset = tf.data.TFRecordDataset(records_train).map(parse_element_func).batch(batch_size).prefetch(tf.data.AUTOTUNE)
class 看起来像这样:
import tensorflow.keras.backend as K
from tensorflow.keras.metrics import Mean
from tensorflow.keras.models import Model
loss_tracker = Mean(name="loss")
custom_metric_tracker = Mean(name="custom_metric")
magic_number = 4
class CustomModel(Model):
def __init__(self, *args, clip_global_norm: float = 1.0, **kwargs):
super(CustomModel, self).__init__(*args, **kwargs)
self.clip_global_norm = clip_global_norm
def train_step(self, data):
# unpack data
x_input_1, x_input_2, y_true, loss_modifier = data
with tf.GradientTape() as tape:
# predict
y_pred = self((x_input_1, x_input_2), training=True)
# calculate loss
weights = K.pow(K.square(loss_modifier + magic_number), -1)
squared_error = K.square(y_pred - y_true)
loss = K.mean(weights * squared_error, axis=0)
# calculate custom metric
num = K.sum(K.square(y_pred - y_true), axis=0)
denom = K.sum(y_true - K.mean(y_true), axis=0)
custom_metric_value = 1 - num / (denom + 0.000001) # to prevent being 0
trainable_vars = self.trainable_variables
gradients = tape.gradient(loss, trainable_vars)
gradients, _ = tf.clip_by_global_norm(gradients, clip_norm=self.clip_global_norm)
self.optimizer.apply_gradients(zip(gradients, trainable_vars))
loss_tracker.update_state(loss)
custom_metric_tracker.update_state(custom_metric_value)
return {"loss": loss_tracker.result(), "custom_metric": custom_metric_tracker.result()}
模型构建和编译都很好,我已经使用 plot_model
检查了所有形状是否正确。当我测试加载数据时,一切都以正确的形状和值存在。无论如何,我得到相同的 ValueError:
ValueError: Unexpected result of `train_function` (Empty logs).
这是我收到的唯一消息。除了与训练功能有关外,它没有告诉我任何错误,并且它发生在 model.fit
期间。当我调用它时,它在我的脚本中看起来像这样:
train_dataset = tf.data.TFRecordDataset(records_train).map(parse_element_func).batch(batch_size).prefetch(tf.data.AUTOTUNE)
val_dataset = tf.data.TFRecordDataset(records_val).map(parse_element_func).batch(batch_size).prefetch(tf.data.AUTOTUNE)
model = build_model_func(**model_build_params)
model.compile(optimizer="adam")
history = model.fit(
train_dataset,
batch_size=batch_size,
epochs=epochs,
validation_data=val_dataset,
)
我是否运行热切与否并没有什么不同。我想也许我的数据集传递一个包含 4 个值的元组可能是问题所在,但据我所知,通过文档它应该没问题,甚至我修改了 TFRecord 数据集元素解析器以仅提供输入和输出而不提供其他值(所以 2 个值而不是 4 个),我仍然得到同样的错误。
我在这上面花了好几个小时,只是不知道为什么会出现这个错误,也不知道这个函数或我的过程有什么问题。谁能帮忙弄清楚如何解决这个错误?
我终于弄明白了,同时根据 M.Innat 的建议创建了可重现的代码。错误消息让我相信它与自定义训练功能有关,但实际上与 TFRecordDataset 有关。
事实证明,在脚本中的某个时刻,records_train
原本有一个 tfrecord 文件名列表,变成了一个空列表。所以基本上没有数据传递给 model.fit
.
作为参考,这是产生错误的代码行:
history = model.fit(
train_dataset,
batch_size=batch_size,
epochs=epochs,
validation_data=val_dataset,
)
但错误的实际来源是这一行,其中 records_train = []
:
train_dataset = tf.data.TFRecordDataset(records_train).map(parse_element_func).batch(batch_size).prefetch(tf.data.AUTOTUNE)
这是错误信息:
ValueError: Unexpected result of `train_function` (Empty logs).
一个非常无用的错误消息,但也许这个 post 会对以后的人有所帮助。