- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我通过子类 keras.model 创建了一个 keras 模型。我还使用了自定义损失(焦点损失)、自定义指标(keras.metrics 的子类)和学习率衰减。我已经训练了模型并使用 tf.keras.callbacks.ModelCheckpoint(model_path) 保存它。
当我尝试加载模型时,出现错误:ValueError: 目前无法恢复类型 _tf_keras_metric 的自定义对象。保存时请确保该层实现了 get_config 和 from_config 。另外,调用load_model()时请使用custom_objects arg
在深入了解错误后,我开始了解如何传递 custom_objects。然而,在阅读了相关内容并尝试了一些事情之后,我仍然无法加载模型。有人可以让我知道正确的做法吗?我的代码如下:
def get_metrics():
train_accuracy = tf.keras.metrics.CategoricalAccuracy(name="train_accuracy")
val_accuracy = tf.keras.metrics.CategoricalAccuracy(name="val_accuracy")
confusion_matrix = ConfusionMatrixMetric(20)
return confusion_matrix, train_accuracy, val_accuracy
def loss_fn(labels, logits):
epsilon = 1e-9
model_out = tf.nn.softmax(logits, axis=-1) + epsilon
ce = - (tf.math.log(model_out) * labels)
weight = labels * tf.math.pow(1 - model_out, gamma)
fl = alpha * weight * ce
loss = tf.reduce_max(fl, axis=-1)
return loss
def get_optimizer(steps_per_epoch, finetune=False):
lr = 0.001
if finetune:
lr = 0.00001
lr_fn = tf.keras.optimizers.schedules.PiecewiseConstantDecay(
[steps_per_epoch * 10], [lr, lr / 10], name=None
)
opt_op = tf.keras.optimizers.Adam(learning_rate=lr_fn)
return opt_op
class MyModel(keras.Model):
def compile(self, optimizer, loss_fn, metric_fn):
super(MyModel, self).compile()
self.optimizer = optimizer
self.loss_fn = loss_fn
self.confusion_matrix, self.train_accuracy, self.val_accuracy = metric_fn()
def train_step(self, train_data):
X, y = train_data
with tf.GradientTape() as tape:
logits = self(X, training=True)
loss = self.loss_fn(y, logits)
# Compute gradients
trainable_vars = self.trainable_variables
gradients = tape.gradient(loss, trainable_vars)
# Update weights
self.optimizer.apply_gradients(zip(gradients, trainable_vars))
# compute metrics keeping an moving average
y_pred = tf.nn.softmax(y, axis=-1)
self.train_accuracy.update_state(y, y_pred )
self.confusion_matrix.update_state(y, y_pred)
update_dict = {"train_accuracy": self.train_accuracy.result()}
if 'confusion_matrix_metric' in self.metrics_names:
self.metrics[0].add_results(update_dict)
return update_dict
class ConfusionMatrixMetric(tf.keras.metrics.Metric):
def __init__(self, num_classes, **kwargs):
super(ConfusionMatrixMetric, self).__init__(name='confusion_matrix_metric', **kwargs) # handles base args (e.g., dtype)
self.num_classes = num_classes
self.total_cm = self.add_weight("total", shape=(num_classes, num_classes), initializer="zeros")
def reset_states(self):
for s in self.variables:
s.assign(tf.zeros(shape=s.shape))
def update_state(self, y_true, y_pred, sample_weight=None):
self.total_cm.assign_add(self.confusion_matrix(y_true, y_pred))
return self.total_cm
def result(self):
return self.process_confusion_matrix()
def confusion_matrix(self, y_true, y_pred):
y_pred = tf.math.argmax(y_pred, 1)
cm = tf.math.confusion_matrix(y_true, y_pred, dtype=tf.float32, num_classes=self.num_classes)
return cm
def process_confusion_matrix(self):
cm = self.total_cm
diag_part = tf.linalg.diag_part(cm)
# accuracy = tf.math.reduce_sum(diag_part) / (tf.math.reduce_sum(cm) + tf.constant(1e-15))
precision = diag_part / (tf.math.reduce_sum(cm, 0) + tf.constant(1e-15))
recall = diag_part / (tf.math.reduce_sum(cm, 1) + tf.constant(1e-15))
f1 = 2 * precision * recall / (precision + recall + tf.constant(1e-15))
return f1
def add_results(self, output):
results = self.result()
for i in range(self.num_classes):
output['F1_{}'.format(i)] = results[i]
if __name__ == "__main__":
model_path = 'model/my_custom_model/'
create_folder(model_path)
callbacks = [tf.keras.callbacks.ModelCheckpoint(model_path)]
# train
model = MyModel(inputs, outputs)
model.summary()
opt_op = get_optimizer(100)
model.compile(optimizer=opt_op,
loss_fn=loss_fn,
metric_fn=get_metrics)
model.fit(train_data_gen(),
epochs=10,
callbacks=callbacks)
tf.keras.models.load_model(model_path)
抱歉代码太长。但只是想确保我所做的一切都是正确且可以理解的。
最佳答案
正如您的错误注释所示,如果您想子类化、使用和加载自定义指标,则应该实现 get_config
方法。
您已经正确构建了度量子类tf.Keras.metrics.Metric
,您只需要添加get_config
并用它获取您的参数(从什么我明白了,你只有 num_classes
):
def get_config(self):
base_config = super().get_config()
return {**base_config, "num_classes": self.num_classes}
此外,加载时,您还必须加载自定义指标:
tf.keras.models.load_model(model_path, custom_objects={"ConfusionMatrixMetric": ConfusionMatrixMetric )
但请注意以下几点(来自书籍 Hands-On Machine Learning with Scikit-Learn and TensorFlow by Aurélien Géron, 2nd Edition ):
The Keras API currently only specifies how to use subclassing to define layers models, callbacks and regularizers. If you build other components (such as losses, metrics, initializers, or constraints). using subclassing, they may not be portable to other Keras implementations. It is likely that the Keras API will be updated to specify subclassing for all these components as well.
关于python - 使用 custom_metrics 和自定义损失加载 keras 模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64797096/
我想在 Datadog 中创建一个图表来显示每个用户的空闲连接。 以下示例:http://www.miketheman.net/tag/postgres/我将 postgres.yaml 配置更改为:
我通过子类 keras.model 创建了一个 keras 模型。我还使用了自定义损失(焦点损失)、自定义指标(keras.metrics 的子类)和学习率衰减。我已经训练了模型并使用 tf.kera
我通过子类 keras.model 创建了一个 keras 模型。我还使用了自定义损失(焦点损失)、自定义指标(keras.metrics 的子类)和学习率衰减。我已经训练了模型并使用 tf.kera
我是一名优秀的程序员,十分优秀!