我需要编写一个度量标准,以使我能够针对极端不平衡的多类分类问题对某些模型进行评分。
为此,我为tensorflow.keras
编写了自己的自定义指标:
import tensorflow as tf
import tensorflow.keras.backend as K
weight_vector = [class_weights[i] for i in range(n_classes)]
# adapted from https://www.kaggle.com/guglielmocamporese/macro-f1-score-keras
def weighted_macro_f1_score(y_true, y_pred):
y_true = tf.reshape(y_true, shape=(-1,n_classes))
y_pred = tf.reshape(y_pred, shape=(-1,n_classes))
y_pred = tf.argmax(y_pred, axis=-1)
y_pred = tf.one_hot(y_pred, depth=n_classes)
aux = np.array(weight_vector, dtype=np.float32)
weights = np.vstack([aux]*y_true.shape[0])
tp = K.sum(K.cast(y_true*y_pred*weights, 'float'))
fp = K.sum(K.cast((1-y_true)*y_pred*weights, 'float'))
fn = K.sum(K.cast(y_true*(1-y_pred)*weights, 'float'))
p = tp / (tp + fp + K.epsilon())
#print(f"p = {p}")
r = tp / (tp + fn + K.epsilon())
#print(f"r = {r}")
f1 = 2*p*r / (p+r+K.epsilon())
f1 = tf.where(tf.is_nan(f1), tf.zeros_like(f1), f1)
return K.mean(f1)
当我在渴望模式下的一些numpy数组上对其进行测试时,我得到了预期的结果。
但是,当我尝试将其输入到model.fit时,出现此错误:
model.compile(
optimizer='adam',
loss='categorical_crossentropy',
metrics=metrics,
sample_weight_mode="temporal")
history = model.fit(X, Y, epochs=20, sample_weight=sample_weight)
错误:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-12-6dbe62cf6d4e> in <module>()
3 loss='categorical_crossentropy',
4 metrics=metrics,
----> 5 sample_weight_mode="temporal")
6
7 history = model.fit(X, Y, epochs=20, sample_weight=sample_weight)
10 frames
/usr/local/lib/python3.6/dist-packages/tensorflow/python/training/checkpointable/base.py in _method_wrapper(self, *args, **kwargs)
440 self._setattr_tracking = False # pylint: disable=protected-access
441 try:
--> 442 method(self, *args, **kwargs)
443 finally:
444 self._setattr_tracking = previous_value # pylint: disable=protected-access
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/training.py in compile(self, optimizer, loss, metrics, loss_weights, sample_weight_mode, weighted_metrics, target_tensors, distribute, **kwargs)
497 targets=self.targets,
498 skip_target_indices=skip_target_indices,
--> 499 sample_weights=self.sample_weights)
500
501 # Prepare gradient updates and state updates.
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/training.py in _handle_metrics(self, outputs, skip_target_indices, targets, sample_weights, masks, return_stateful_result)
1842 output,
1843 output_mask,
-> 1844 return_stateful_result=return_stateful_result))
1845 metric_results.extend(
1846 self._handle_per_output_metrics(
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/training.py in _handle_per_output_metrics(self, metrics_dict, y_true, y_pred, mask, weights, return_stateful_result)
1798 # In graph mode, we build the sub-graph for both the stateful and the
1799 # stateless fns.
-> 1800 stateful_metric_result = _call_stateful_fn(stateful_fn)
1801 metric_result = _call_stateless_fn(metric_fn)
1802 _track_metric_tensors(metric_name, metric_result,
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/training.py in _call_stateful_fn(fn)
1771 def _call_stateful_fn(fn):
1772 return training_utils.call_metric_function(
-> 1773 fn, y_true, y_pred, weights=weights, mask=mask)
1774
1775 def _call_stateless_fn(fn):
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/training_utils.py in call_metric_function(metric_fn, y_true, y_pred, weights, mask)
850 """Invokes metric function and returns the metric result tensor."""
851 if mask is None:
--> 852 return metric_fn(y_true, y_pred, sample_weight=weights)
853
854 mask = math_ops.cast(mask, y_pred.dtype)
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/metrics.py in __call__(self, *args, **kwargs)
436 The metric value tensor.
437 """
--> 438 update_op = self.update_state(*args, **kwargs)
439 with ops.control_dependencies([update_op]):
440 result_t = self.result()
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/metrics.py in decorated(metric_obj, *args, **kwargs)
96 """Decorated function with `add_update()`."""
97
---> 98 update_op = update_state_fn(*args, **kwargs)
99 if update_op is not None: # update_op will be None in eager execution.
100 metric_obj.add_update(update_op, inputs=True)
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/metrics.py in update_state(self, y_true, y_pred, sample_weight)
647 y_pred, y_true, sample_weight)
648
--> 649 matches = self._fn(y_true, y_pred, **self._fn_kwargs)
650 return super(MeanMetricWrapper, self).update_state(
651 matches, sample_weight=sample_weight)
<ipython-input-11-030fcade0122> in weighted_macro_f1_score(y_true, y_pred)
8
9 aux = np.array(weight_vector, dtype=np.float32)
---> 10 weights = np.vstack([aux]*y_true.shape[0])
11
12 tp = K.sum(K.cast(y_true*y_pred*weights, 'float'))
/usr/local/lib/python3.6/dist-packages/tensorflow/python/framework/tensor_shape.py in __rmul__(self, other)
408 A Dimension whose value is the product of `self` and `other`.
409 """
--> 410 return self * other
411
412 def __floordiv__(self, other):
TypeError: __index__ returned non-int (type NoneType)
我对这个结果感到困惑。当我尝试不修改体重平衡的度量标准时,它工作正常,但现在却不起作用。
这是怎么回事?我该如何解决?