@@ -39,6 +39,9 @@ namespace Tensorflow | |||||
public Tensor sum(Tensor x, Axis? axis = null, string name = null) | public Tensor sum(Tensor x, Axis? axis = null, string name = null) | ||||
=> math_ops.reduce_sum(x, axis: axis, name: name); | => math_ops.reduce_sum(x, axis: axis, name: name); | ||||
public Tensor in_top_k(Tensor predictions, Tensor targets, int k, string name = "InTopK") | |||||
=> nn_ops.in_top_k(predictions, targets, k, name); | |||||
/// <summary> | /// <summary> | ||||
/// | /// | ||||
/// </summary> | /// </summary> | ||||
@@ -3,6 +3,7 @@ using System.Collections.Generic; | |||||
using System.Text; | using System.Text; | ||||
using Tensorflow.Keras.Layers; | using Tensorflow.Keras.Layers; | ||||
using Tensorflow.Keras.Losses; | using Tensorflow.Keras.Losses; | ||||
using Tensorflow.Keras.Metrics; | |||||
namespace Tensorflow.Keras | namespace Tensorflow.Keras | ||||
{ | { | ||||
@@ -10,6 +11,7 @@ namespace Tensorflow.Keras | |||||
{ | { | ||||
public ILayersApi layers { get; } | public ILayersApi layers { get; } | ||||
public ILossesApi losses { get; } | public ILossesApi losses { get; } | ||||
public IMetricsApi metrics { get; } | |||||
public IInitializersApi initializers { get; } | public IInitializersApi initializers { get; } | ||||
} | } | ||||
} | } |
@@ -0,0 +1,29 @@ | |||||
namespace Tensorflow.Keras.Metrics; | |||||
public interface IMetricsApi | |||||
{ | |||||
Tensor binary_accuracy(Tensor y_true, Tensor y_pred); | |||||
Tensor categorical_accuracy(Tensor y_true, Tensor y_pred); | |||||
Tensor mean_absolute_error(Tensor y_true, Tensor y_pred); | |||||
Tensor mean_absolute_percentage_error(Tensor y_true, Tensor y_pred); | |||||
/// <summary> | |||||
/// Calculates how often predictions matches integer labels. | |||||
/// </summary> | |||||
/// <param name="y_true">Integer ground truth values.</param> | |||||
/// <param name="y_pred">The prediction values.</param> | |||||
/// <returns>Sparse categorical accuracy values.</returns> | |||||
Tensor sparse_categorical_accuracy(Tensor y_true, Tensor y_pred); | |||||
/// <summary> | |||||
/// Computes how often targets are in the top `K` predictions. | |||||
/// </summary> | |||||
/// <param name="y_true"></param> | |||||
/// <param name="y_pred"></param> | |||||
/// <param name="k"></param> | |||||
/// <returns></returns> | |||||
Tensor top_k_categorical_accuracy(Tensor y_true, Tensor y_pred, int k = 5); | |||||
} |
@@ -240,16 +240,8 @@ namespace Tensorflow.Operations | |||||
/// <param name="name"></param> | /// <param name="name"></param> | ||||
/// <returns>A `Tensor` of type `bool`.</returns> | /// <returns>A `Tensor` of type `bool`.</returns> | ||||
public static Tensor in_top_kv2(Tensor predictions, Tensor targets, int k, string name = null) | public static Tensor in_top_kv2(Tensor predictions, Tensor targets, int k, string name = null) | ||||
{ | |||||
var _op = tf.OpDefLib._apply_op_helper("InTopKV2", name: name, args: new | |||||
{ | |||||
predictions, | |||||
targets, | |||||
k | |||||
}); | |||||
return _op.output; | |||||
} | |||||
=> tf.Context.ExecuteOp("InTopKV2", name, | |||||
new ExecuteOpArgs(predictions, targets, k)); | |||||
public static Tensor leaky_relu(Tensor features, float alpha = 0.2f, string name = null) | public static Tensor leaky_relu(Tensor features, float alpha = 0.2f, string name = null) | ||||
=> tf.Context.ExecuteOp("LeakyRelu", name, | => tf.Context.ExecuteOp("LeakyRelu", name, | ||||
@@ -121,6 +121,11 @@ namespace Tensorflow | |||||
if (dtype == TF_DataType.TF_INT32) | if (dtype == TF_DataType.TF_INT32) | ||||
values = long_values.Select(x => (int)Convert.ChangeType(x, new_system_dtype)).ToArray(); | values = long_values.Select(x => (int)Convert.ChangeType(x, new_system_dtype)).ToArray(); | ||||
} | } | ||||
else if (values is double[] double_values) | |||||
{ | |||||
if (dtype == TF_DataType.TF_FLOAT) | |||||
values = double_values.Select(x => (float)Convert.ChangeType(x, new_system_dtype)).ToArray(); | |||||
} | |||||
else | else | ||||
values = Convert.ChangeType(values, new_system_dtype); | values = Convert.ChangeType(values, new_system_dtype); | ||||
@@ -27,7 +27,7 @@ namespace Tensorflow.Keras | |||||
ThreadLocal<BackendImpl> _backend = new ThreadLocal<BackendImpl>(() => new BackendImpl()); | ThreadLocal<BackendImpl> _backend = new ThreadLocal<BackendImpl>(() => new BackendImpl()); | ||||
public BackendImpl backend => _backend.Value; | public BackendImpl backend => _backend.Value; | ||||
public OptimizerApi optimizers { get; } = new OptimizerApi(); | public OptimizerApi optimizers { get; } = new OptimizerApi(); | ||||
public MetricsApi metrics { get; } = new MetricsApi(); | |||||
public IMetricsApi metrics { get; } = new MetricsApi(); | |||||
public ModelsApi models { get; } = new ModelsApi(); | public ModelsApi models { get; } = new ModelsApi(); | ||||
public KerasUtils utils { get; } = new KerasUtils(); | public KerasUtils utils { get; } = new KerasUtils(); | ||||
@@ -2,7 +2,7 @@ | |||||
namespace Tensorflow.Keras.Metrics | namespace Tensorflow.Keras.Metrics | ||||
{ | { | ||||
public class MetricsApi | |||||
public class MetricsApi : IMetricsApi | |||||
{ | { | ||||
public Tensor binary_accuracy(Tensor y_true, Tensor y_pred) | public Tensor binary_accuracy(Tensor y_true, Tensor y_pred) | ||||
{ | { | ||||
@@ -53,5 +53,12 @@ namespace Tensorflow.Keras.Metrics | |||||
var diff = (y_true - y_pred) / math_ops.maximum(math_ops.abs(y_true), keras.backend.epsilon()); | var diff = (y_true - y_pred) / math_ops.maximum(math_ops.abs(y_true), keras.backend.epsilon()); | ||||
return 100f * keras.backend.mean(math_ops.abs(diff), axis: -1); | return 100f * keras.backend.mean(math_ops.abs(diff), axis: -1); | ||||
} | } | ||||
public Tensor top_k_categorical_accuracy(Tensor y_true, Tensor y_pred, int k = 5) | |||||
{ | |||||
return metrics_utils.sparse_top_k_categorical_matches( | |||||
tf.math.argmax(y_true, axis: -1), y_pred, k | |||||
); | |||||
} | |||||
} | } | ||||
} | } |
@@ -0,0 +1,39 @@ | |||||
using Tensorflow.NumPy; | |||||
namespace Tensorflow.Keras.Metrics; | |||||
public class metrics_utils | |||||
{ | |||||
public static Tensor sparse_top_k_categorical_matches(Tensor y_true, Tensor y_pred, int k = 5) | |||||
{ | |||||
var reshape_matches = false; | |||||
var y_true_rank = y_true.shape.ndim; | |||||
var y_pred_rank = y_pred.shape.ndim; | |||||
var y_true_org_shape = tf.shape(y_true); | |||||
if (y_pred_rank > 2) | |||||
{ | |||||
y_pred = tf.reshape(y_pred, (-1, y_pred.shape[-1])); | |||||
} | |||||
if (y_true_rank > 1) | |||||
{ | |||||
reshape_matches = true; | |||||
y_true = tf.reshape(y_true, new Shape(-1)); | |||||
} | |||||
var matches = tf.cast( | |||||
tf.math.in_top_k( | |||||
predictions: y_pred, targets: tf.cast(y_true, np.int32), k: k | |||||
), | |||||
dtype: keras.backend.floatx() | |||||
); | |||||
if (reshape_matches) | |||||
{ | |||||
return tf.reshape(matches, shape: y_true_org_shape); | |||||
} | |||||
return matches; | |||||
} | |||||
} |
@@ -0,0 +1,28 @@ | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Text; | |||||
using System.Threading.Tasks; | |||||
using Tensorflow; | |||||
using Tensorflow.NumPy; | |||||
using static Tensorflow.Binding; | |||||
using static Tensorflow.KerasApi; | |||||
namespace TensorFlowNET.Keras.UnitTest; | |||||
[TestClass] | |||||
public class MetricsTest : EagerModeTestBase | |||||
{ | |||||
/// <summary> | |||||
/// https://www.tensorflow.org/api_docs/python/tf/keras/metrics/top_k_categorical_accuracy | |||||
/// </summary> | |||||
[TestMethod] | |||||
public void top_k_categorical_accuracy() | |||||
{ | |||||
var y_true = np.array(new[,] { { 0, 0, 1 }, { 0, 1, 0 } }); | |||||
var y_pred = np.array(new[,] { { 0.1f, 0.9f, 0.8f }, { 0.05f, 0.95f, 0f } }); | |||||
var m = tf.keras.metrics.top_k_categorical_accuracy(y_true, y_pred, k: 3); | |||||
Assert.AreEqual(m.numpy(), new[] { 1f, 1f }); | |||||
} | |||||
} |