@@ -22,6 +22,20 @@ public interface IMetricsApi | |||
/// <returns>Sparse categorical accuracy values.</returns> | |||
Tensor sparse_categorical_accuracy(Tensor y_true, Tensor y_pred); | |||
/// <summary> | |||
/// Computes the sparse categorical crossentropy loss. | |||
/// </summary> | |||
/// <param name="y_true"></param> | |||
/// <param name="y_pred"></param> | |||
/// <param name="from_logits"></param> | |||
/// <param name="ignore_class"></param> | |||
/// <param name="axis"></param> | |||
/// <returns></returns> | |||
Tensor sparse_categorical_crossentropy(Tensor y_true, Tensor y_pred, | |||
bool from_logits = false, | |||
int? ignore_class = null, | |||
Axis? axis = null); | |||
/// <summary> | |||
/// Computes how often targets are in the top `K` predictions. | |||
/// </summary> | |||
@@ -56,6 +70,16 @@ public interface IMetricsApi | |||
float label_smoothing = 0f, | |||
Axis? axis = null); | |||
/// <summary> | |||
/// Computes the crossentropy metric between the labels and predictions. | |||
/// </summary> | |||
/// <returns></returns> | |||
IMetricFunc SparseCategoricalCrossentropy(string name = "sparse_categorical_crossentropy", | |||
TF_DataType dtype = TF_DataType.TF_FLOAT, | |||
bool from_logits = false, | |||
int? ignore_class = null, | |||
Axis? axis = null); | |||
/// <summary> | |||
/// Computes the crossentropy metric between the labels and predictions. | |||
/// </summary> | |||
@@ -63,6 +87,13 @@ public interface IMetricsApi | |||
IMetricFunc CategoricalAccuracy(string name = "categorical_accuracy", | |||
TF_DataType dtype = TF_DataType.TF_FLOAT); | |||
/// <summary> | |||
/// Calculates how often predictions match integer labels. | |||
/// </summary> | |||
/// <returns></returns> | |||
IMetricFunc SparseCategoricalAccuracy(string name = "sparse_categorical_accuracy", | |||
TF_DataType dtype = TF_DataType.TF_FLOAT); | |||
/// <summary> | |||
/// Computes the cosine similarity between the labels and predictions. | |||
/// </summary> | |||
@@ -114,6 +145,15 @@ public interface IMetricsApi | |||
string name = "top_k_categorical_accuracy", | |||
TF_DataType dtype = TF_DataType.TF_FLOAT); | |||
/// <summary> | |||
/// Computes how often integer targets are in the top K predictions. | |||
/// </summary> | |||
/// <param name="k"></param> | |||
/// <returns></returns> | |||
IMetricFunc SparseTopKCategoricalAccuracy(int k = 5, | |||
string name = "sparse_top_k_categorical_accuracy", | |||
TF_DataType dtype = TF_DataType.TF_FLOAT); | |||
/// <summary> | |||
/// Computes the precision of the predictions with respect to the labels. | |||
/// </summary> | |||
@@ -276,6 +276,64 @@ namespace Tensorflow.Keras | |||
return -math_ops.reduce_sum(target * math_ops.log(output), new Axis(axis)); | |||
} | |||
public Tensor sparse_categorical_crossentropy(Tensor target, Tensor output, bool from_logits = false, int axis = -1, int? ignore_class = null) | |||
{ | |||
target = tf.cast(target, tf.int64); | |||
if (!from_logits) | |||
{ | |||
var epsilon_ = constant_op.constant(epsilon(), output.dtype.as_base_dtype()); | |||
output = tf.clip_by_value(output, epsilon_, 1 - epsilon_); | |||
output = tf.math.log(output); | |||
} | |||
var output_rank = output.shape.ndim; | |||
if (output_rank > -1) | |||
{ | |||
axis = Math.Abs(axis) % output_rank; | |||
if (axis != output_rank - 1) | |||
{ | |||
/*var permutation = list( | |||
itertools.chain( | |||
range(axis), range(axis + 1, output_rank), [axis] | |||
) | |||
); | |||
output = tf.transpose(output, perm: permutation);*/ | |||
throw new NotImplementedException(""); | |||
} | |||
} | |||
var output_shape = tf.shape(output); | |||
var target_rank = target.shape.ndim; | |||
var update_shape = target_rank > -1 && output_rank > -1 && target_rank != output_rank - 1; | |||
if (update_shape) | |||
{ | |||
/*var target = flatten(target); | |||
output = tf.reshape(output, [-1, output_shape[-1]]);*/ | |||
throw new NotImplementedException(""); | |||
} | |||
if (ignore_class.HasValue) | |||
{ | |||
throw new NotImplementedException(""); | |||
} | |||
var res = tf.nn.sparse_softmax_cross_entropy_with_logits(labels: target, logits: output); | |||
if (ignore_class.HasValue) | |||
{ | |||
throw new NotImplementedException(""); | |||
} | |||
if (update_shape && output_rank >= 3) | |||
{ | |||
// If our output includes timesteps or | |||
// spatial dimensions we need to reshape | |||
res = tf.reshape(res, output_shape[":-1"]); | |||
} | |||
return res; | |||
} | |||
public Tensor binary_crossentropy(Tensor target, Tensor output, bool from_logits = false) | |||
{ | |||
if (from_logits) | |||
@@ -27,6 +27,11 @@ | |||
return keras.backend.categorical_crossentropy(y_true, y_pred, from_logits: from_logits, axis: axis); | |||
} | |||
public Tensor sparse_categorical_crossentropy(Tensor y_true, Tensor y_pred, bool from_logits = false, int? ignore_class = null, Axis? axis = null) | |||
{ | |||
return keras.backend.sparse_categorical_crossentropy(y_true, y_pred, from_logits: from_logits, axis: axis ?? -1, ignore_class: ignore_class); | |||
} | |||
/// <summary> | |||
/// Calculates how often predictions matches integer labels. | |||
/// </summary> | |||
@@ -103,5 +108,14 @@ | |||
public IMetricFunc Recall(float thresholds = 0.5f, int top_k = 0, int class_id = 0, string name = "recall", TF_DataType dtype = TF_DataType.TF_FLOAT) | |||
=> new Recall(thresholds: thresholds, top_k: top_k, class_id: class_id, name: name, dtype: dtype); | |||
public IMetricFunc SparseCategoricalCrossentropy(string name = "sparse_categorical_crossentropy", TF_DataType dtype = TF_DataType.TF_FLOAT, bool from_logits = false, int? ignore_class = null, Axis? axis = null) | |||
=> new SparseCategoricalCrossentropy(name: name, dtype: dtype, from_logits: from_logits, ignore_class: ignore_class, axis: axis ?? -1); | |||
public IMetricFunc SparseTopKCategoricalAccuracy(int k = 5, string name = "sparse_top_k_categorical_accuracy", TF_DataType dtype = TF_DataType.TF_FLOAT) | |||
=> new SparseTopKCategoricalAccuracy(k: k, name: name, dtype: dtype); | |||
public IMetricFunc SparseCategoricalAccuracy(string name = "sparse_categorical_accuracy", TF_DataType dtype = TF_DataType.TF_FLOAT) | |||
=> new SparseCategoricalAccuracy(name: name, dtype: dtype); | |||
} | |||
} |
@@ -0,0 +1,11 @@ | |||
namespace Tensorflow.Keras.Metrics; | |||
public class SparseCategoricalAccuracy : MeanMetricWrapper | |||
{ | |||
public SparseCategoricalAccuracy(string name = "sparse_categorical_accuracy", TF_DataType dtype = TF_DataType.TF_FLOAT) | |||
: base((yt, yp) => metrics_utils.sparse_categorical_matches(yt, yp), | |||
name: name, | |||
dtype: dtype) | |||
{ | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
namespace Tensorflow.Keras.Metrics; | |||
public class SparseCategoricalCrossentropy : MeanMetricWrapper | |||
{ | |||
public SparseCategoricalCrossentropy(string name = "sparse_categorical_crossentropy", | |||
TF_DataType dtype = TF_DataType.TF_FLOAT, | |||
bool from_logits = false, | |||
int? ignore_class = null, | |||
Axis? axis = null) | |||
: base((yt, yp) => keras.metrics.sparse_categorical_crossentropy( | |||
yt, yp, from_logits: from_logits, ignore_class: ignore_class, axis: axis ?? -1), | |||
name: name, | |||
dtype: dtype) | |||
{ | |||
} | |||
} |
@@ -0,0 +1,11 @@ | |||
namespace Tensorflow.Keras.Metrics; | |||
public class SparseTopKCategoricalAccuracy : MeanMetricWrapper | |||
{ | |||
public SparseTopKCategoricalAccuracy(int k = 5, string name = "sparse_top_k_categorical_accuracy", TF_DataType dtype = TF_DataType.TF_FLOAT) | |||
: base((yt, yp) => metrics_utils.sparse_top_k_categorical_matches(yt, yp, k), | |||
name: name, | |||
dtype: dtype) | |||
{ | |||
} | |||
} |
@@ -73,7 +73,7 @@ public class metrics_utils | |||
y_true = tf.squeeze(y_true, new Shape(-1)); | |||
} | |||
y_pred = tf.math.argmax(y_pred, axis: -1); | |||
y_pred = tf.cast(y_pred, y_true.dtype); | |||
var matches = tf.cast( | |||
tf.equal(y_true, y_pred), | |||
dtype: keras.backend.floatx() | |||
@@ -74,6 +74,26 @@ public class MetricsTest : EagerModeTestBase | |||
Assert.AreEqual(r, 0.3f); | |||
} | |||
/// <summary> | |||
/// https://www.tensorflow.org/api_docs/python/tf/keras/metrics/SparseCategoricalAccuracy | |||
/// </summary> | |||
[TestMethod] | |||
public void SparseCategoricalAccuracy() | |||
{ | |||
var y_true = np.array(new[] { 2, 1 }); | |||
var y_pred = np.array(new[,] { { 0.1f, 0.6f, 0.3f }, { 0.05f, 0.95f, 0f } }); | |||
var m = tf.keras.metrics.SparseCategoricalAccuracy(); | |||
m.update_state(y_true, y_pred); | |||
var r = m.result().numpy(); | |||
Assert.AreEqual(r, 0.5f); | |||
m.reset_states(); | |||
var weights = np.array(new[] { 0.7f, 0.3f }); | |||
m.update_state(y_true, y_pred, sample_weight: weights); | |||
r = m.result().numpy(); | |||
Assert.AreEqual(r, 0.3f); | |||
} | |||
/// <summary> | |||
/// https://www.tensorflow.org/api_docs/python/tf/keras/metrics/CategoricalCrossentropy | |||
/// </summary> | |||
@@ -94,6 +114,20 @@ public class MetricsTest : EagerModeTestBase | |||
Assert.AreEqual(r, 1.6271976f); | |||
} | |||
/// <summary> | |||
/// https://www.tensorflow.org/api_docs/python/tf/keras/metrics/SparseCategoricalCrossentropy | |||
/// </summary> | |||
[TestMethod] | |||
public void SparseCategoricalCrossentropy() | |||
{ | |||
var y_true = np.array(new[] { 1, 2 }); | |||
var y_pred = np.array(new[,] { { 0.05f, 0.95f, 0f }, { 0.1f, 0.8f, 0.1f } }); | |||
var m = tf.keras.metrics.SparseCategoricalCrossentropy(); | |||
m.update_state(y_true, y_pred); | |||
var r = m.result().numpy(); | |||
Assert.AreEqual(r, 1.1769392f); | |||
} | |||
/// <summary> | |||
/// https://www.tensorflow.org/api_docs/python/tf/keras/metrics/CosineSimilarity | |||
/// </summary> | |||
@@ -207,6 +241,26 @@ public class MetricsTest : EagerModeTestBase | |||
Assert.AreEqual(r, 0.3f); | |||
} | |||
/// <summary> | |||
/// https://www.tensorflow.org/api_docs/python/tf/keras/metrics/SparseTopKCategoricalAccuracy | |||
/// </summary> | |||
[TestMethod] | |||
public void SparseTopKCategoricalAccuracy() | |||
{ | |||
var y_true = np.array(new[] { 2, 1 }); | |||
var y_pred = np.array(new[,] { { 0.1f, 0.9f, 0.8f }, { 0.05f, 0.95f, 0f } }); | |||
var m = tf.keras.metrics.SparseTopKCategoricalAccuracy(k: 1); | |||
m.update_state(y_true, y_pred); | |||
var r = m.result().numpy(); | |||
Assert.AreEqual(r, 0.5f); | |||
m.reset_states(); | |||
var weights = np.array(new[] { 0.7f, 0.3f }); | |||
m.update_state(y_true, y_pred, sample_weight: weights); | |||
r = m.result().numpy(); | |||
Assert.AreEqual(r, 0.3f); | |||
} | |||
/// <summary> | |||
/// https://www.tensorflow.org/api_docs/python/tf/keras/metrics/top_k_categorical_accuracy | |||
/// </summary> | |||