Tensorflow 和 Keras:为精度构建自定义指标
Tensorflow & Keras: Building Custom Metric for Precision
我对指标进行了子分类 class 以创建自定义精度指标。一切看起来都很好;我的意思是没有 运行 时间错误。但是我怀疑当我看到输出中记录的精度分数时有问题,它总是在每个纪元结束时显示相同的分数,例如纪元 0.1000 或 0.9000
这是我的代码:
(X_train_10, y_train_10), (X_test_10, y_test_10) = keras.datasets.cifar10.load_data()
X_train_10 = X_train_10 / 255.
X_test_10 = X_test_10 / 255.
class PrecisionMetric(keras.metrics.Metric):
def __init__(self, name = 'precision', **kwargs):
super(PrecisionMetric, self).__init__(**kwargs)
self.tp = self.add_weight('tp', initializer = 'zeros')
self.fp = self.add_weight('fp', initializer = 'zeros')
def update_state(self, y_true, y_pred):
y_true = tf.cast(y_true, tf.bool)
y_pred = tf.cast(y_pred, tf.bool)
true_p = tf.logical_and(tf.equal(y_true, True), tf.equal(y_pred, True))
false_p = tf.logical_and(tf.equal(y_true, False), tf.equal(y_pred, True))
self.tp.assign_add(tf.reduce_sum(tf.cast(true_p, self.dtype)))
self.fp.assign_add(tf.reduce_sum(tf.cast(false_p, self.dtype)))
def reset_states(self):
self.tp.assign(0)
self.fp.assign(0)
def result(self):
return self.tp / (self.tp + self.fp)
keras.backend.clear_session()
model = keras.models.Sequential()
model.add(keras.layers.Flatten(input_shape = np.array(X_train_10.shape[1: ])))
for _ in range(2):
model.add(keras.layers.Dense(50, activation = 'elu', kernel_initializer = 'he_normal'))
model.add(keras.layers.Dense(1, activation = 'sigmoid'))
loss = keras.losses.binary_crossentropy
optimizer = keras.optimizers.SGD()
model.compile(loss = loss, optimizer = optimizer, metrics = [PrecisionMetric()])
# To make it binary classification
y_train_5 = (y_train_10 == 5)
y_test_5 = (y_test_10 == 5)
history = model.fit(X_train_10, y_train_5, epochs = 5)
运行ning 5 纪元后的输出:
Epoch 1/5
1563/1563 [==============================] - 5s 4ms/step - loss: 0.2921 - precision_metric: 0.1000
Epoch 2/5
1563/1563 [==============================] - 4s 2ms/step - loss: 0.2744 - precision_metric: 0.1000
Epoch 3/5
1563/1563 [==============================] - 3s 2ms/step - loss: 0.2682 - precision_metric: 0.1000
Epoch 4/5
1563/1563 [==============================] - 3s 2ms/step - loss: 0.2651 - precision_metric: 0.1000
Epoch 5/5
1563/1563 [==============================] - 4s 3ms/step - loss: 0.2629 - precision_metric: 0.1000
注意:即使尝试使用更多的 epoch,例如 100,仍然输出完全相同的精度,而损失保持 shrinking/getting-smaller。
编辑
您的实施有误。您不应该将 y_pred
转换为 bool。这些是 sigmoid 的输出。你应该做
y_pred = tf.math.greater(y_pred, 0.5)
当你的问题是二进制的(你从 sigmoid 得到输出)。并使其适应多class class化。
请在result
中检查你是否不是通过以下方式除0/0:
def result(self):
res = self.tp / (self.tp + self.fp)
if tf.math.is_nan(res):
return 0.0
else:
return res
对于第一个错误的回答,我深表歉意,尽管我希望它能起到一定的教育作用。
我对指标进行了子分类 class 以创建自定义精度指标。一切看起来都很好;我的意思是没有 运行 时间错误。但是我怀疑当我看到输出中记录的精度分数时有问题,它总是在每个纪元结束时显示相同的分数,例如纪元 0.1000 或 0.9000
这是我的代码:
(X_train_10, y_train_10), (X_test_10, y_test_10) = keras.datasets.cifar10.load_data()
X_train_10 = X_train_10 / 255.
X_test_10 = X_test_10 / 255.
class PrecisionMetric(keras.metrics.Metric):
def __init__(self, name = 'precision', **kwargs):
super(PrecisionMetric, self).__init__(**kwargs)
self.tp = self.add_weight('tp', initializer = 'zeros')
self.fp = self.add_weight('fp', initializer = 'zeros')
def update_state(self, y_true, y_pred):
y_true = tf.cast(y_true, tf.bool)
y_pred = tf.cast(y_pred, tf.bool)
true_p = tf.logical_and(tf.equal(y_true, True), tf.equal(y_pred, True))
false_p = tf.logical_and(tf.equal(y_true, False), tf.equal(y_pred, True))
self.tp.assign_add(tf.reduce_sum(tf.cast(true_p, self.dtype)))
self.fp.assign_add(tf.reduce_sum(tf.cast(false_p, self.dtype)))
def reset_states(self):
self.tp.assign(0)
self.fp.assign(0)
def result(self):
return self.tp / (self.tp + self.fp)
keras.backend.clear_session()
model = keras.models.Sequential()
model.add(keras.layers.Flatten(input_shape = np.array(X_train_10.shape[1: ])))
for _ in range(2):
model.add(keras.layers.Dense(50, activation = 'elu', kernel_initializer = 'he_normal'))
model.add(keras.layers.Dense(1, activation = 'sigmoid'))
loss = keras.losses.binary_crossentropy
optimizer = keras.optimizers.SGD()
model.compile(loss = loss, optimizer = optimizer, metrics = [PrecisionMetric()])
# To make it binary classification
y_train_5 = (y_train_10 == 5)
y_test_5 = (y_test_10 == 5)
history = model.fit(X_train_10, y_train_5, epochs = 5)
运行ning 5 纪元后的输出:
Epoch 1/5
1563/1563 [==============================] - 5s 4ms/step - loss: 0.2921 - precision_metric: 0.1000
Epoch 2/5
1563/1563 [==============================] - 4s 2ms/step - loss: 0.2744 - precision_metric: 0.1000
Epoch 3/5
1563/1563 [==============================] - 3s 2ms/step - loss: 0.2682 - precision_metric: 0.1000
Epoch 4/5
1563/1563 [==============================] - 3s 2ms/step - loss: 0.2651 - precision_metric: 0.1000
Epoch 5/5
1563/1563 [==============================] - 4s 3ms/step - loss: 0.2629 - precision_metric: 0.1000
注意:即使尝试使用更多的 epoch,例如 100,仍然输出完全相同的精度,而损失保持 shrinking/getting-smaller。
编辑
您的实施有误。您不应该将 y_pred
转换为 bool。这些是 sigmoid 的输出。你应该做
y_pred = tf.math.greater(y_pred, 0.5)
当你的问题是二进制的(你从 sigmoid 得到输出)。并使其适应多class class化。
请在result
中检查你是否不是通过以下方式除0/0:
def result(self):
res = self.tp / (self.tp + self.fp)
if tf.math.is_nan(res):
return 0.0
else:
return res
对于第一个错误的回答,我深表歉意,尽管我希望它能起到一定的教育作用。