@@ -24,6 +24,8 @@ namespace Tensorflow | |||||
public Tensor argmax(Tensor input, Axis axis = null, string name = null, int? dimension = null, TF_DataType output_type = TF_DataType.TF_INT64) | public Tensor argmax(Tensor input, Axis axis = null, string name = null, int? dimension = null, TF_DataType output_type = TF_DataType.TF_INT64) | ||||
=> gen_math_ops.arg_max(input, axis, name: name, output_type: output_type); | => gen_math_ops.arg_max(input, axis, name: name, output_type: output_type); | ||||
public Tensor count_nonzero(Tensor input, Axis? axis = null, bool? keepdims = null, TF_DataType dtype = TF_DataType.TF_INT64, string name = null) | |||||
=> math_ops.count_nonzero_v2(input, axis: axis, keepdims: keepdims ?? false, dtype: dtype); | |||||
public Tensor log(Tensor x, string name = null) | public Tensor log(Tensor x, string name = null) | ||||
=> gen_math_ops.log(x, name); | => gen_math_ops.log(x, name); | ||||
@@ -91,7 +91,20 @@ public interface IMetricsApi | |||||
float? threshold = null, | float? threshold = null, | ||||
string name = "fbeta_score", | string name = "fbeta_score", | ||||
TF_DataType dtype = TF_DataType.TF_FLOAT); | TF_DataType dtype = TF_DataType.TF_FLOAT); | ||||
/// <summary> | |||||
/// Computes hamming loss. | |||||
/// </summary> | |||||
/// <param name="mode">multiclass or multilabel</param> | |||||
/// <param name="threshold"></param> | |||||
/// <param name="name"></param> | |||||
/// <param name="dtype"></param> | |||||
/// <returns></returns> | |||||
IMetricFunc HammingLoss(string mode, | |||||
float? threshold = null, | |||||
string name = "hamming_loss", | |||||
TF_DataType dtype = TF_DataType.TF_FLOAT); | |||||
/// <summary> | /// <summary> | ||||
/// Computes how often targets are in the top K predictions. | /// Computes how often targets are in the top K predictions. | ||||
/// </summary> | /// </summary> | ||||
@@ -821,6 +821,18 @@ namespace Tensorflow | |||||
.SetAttributes(new { adj_x, adj_y })); | .SetAttributes(new { adj_x, adj_y })); | ||||
}); | }); | ||||
public static Tensor count_nonzero_v2(Tensor input, | |||||
Axis? axis, | |||||
bool keepdims = false, | |||||
string name = null, | |||||
TF_DataType dtype = TF_DataType.TF_INT64) | |||||
=> tf_with(ops.name_scope(name, "count_nonzero", input), scope => | |||||
{ | |||||
name = scope; | |||||
var zero = array_ops.zeros(Shape.Scalar, dtype: input.dtype); | |||||
return reduce_sum(cast(gen_math_ops.not_equal(input, zero), dtype), axis: axis, keepdims: keepdims); | |||||
}); | |||||
public static Tensor bincount(Tensor arr, Tensor weights = null, | public static Tensor bincount(Tensor arr, Tensor weights = null, | ||||
Tensor minlength = null, | Tensor minlength = null, | ||||
Tensor maxlength = null, | Tensor maxlength = null, | ||||
@@ -109,7 +109,7 @@ https://tensorflownet.readthedocs.io</Description> | |||||
<ItemGroup> | <ItemGroup> | ||||
<PackageReference Include="MethodBoundaryAspect.Fody" Version="2.0.148" /> | <PackageReference Include="MethodBoundaryAspect.Fody" Version="2.0.148" /> | ||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" /> | <PackageReference Include="Newtonsoft.Json" Version="13.0.2" /> | ||||
<PackageReference Include="Protobuf.Text" Version="0.6.0" /> | |||||
<PackageReference Include="Protobuf.Text" Version="0.6.1" /> | |||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> | <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> | ||||
</ItemGroup> | </ItemGroup> | ||||
</Project> | </Project> |
@@ -0,0 +1,15 @@ | |||||
namespace Tensorflow.Keras.Metrics; | |||||
public class HammingLoss : MeanMetricWrapper | |||||
{ | |||||
public HammingLoss(string mode, | |||||
NDArray threshold = null, | |||||
string name = "hamming_loss", | |||||
TF_DataType dtype = TF_DataType.TF_FLOAT) | |||||
: base((yt, yp) => metrics_utils.hamming_loss_fn(yt, yp, threshold, mode), | |||||
name: name, | |||||
dtype: dtype) | |||||
{ | |||||
_dtype = dtype; | |||||
} | |||||
} |
@@ -92,6 +92,9 @@ | |||||
public IMetricFunc FBetaScore(int num_classes, string? average = null, float beta = 0.1F, float? threshold = null, string name = "fbeta_score", TF_DataType dtype = TF_DataType.TF_FLOAT) | public IMetricFunc FBetaScore(int num_classes, string? average = null, float beta = 0.1F, float? threshold = null, string name = "fbeta_score", TF_DataType dtype = TF_DataType.TF_FLOAT) | ||||
=> new FBetaScore(num_classes, average: average,beta: beta, threshold: threshold, name: name, dtype: dtype); | => new FBetaScore(num_classes, average: average,beta: beta, threshold: threshold, name: name, dtype: dtype); | ||||
public IMetricFunc HammingLoss(string mode, float? threshold = null, string name = "hamming_loss", TF_DataType dtype = TF_DataType.TF_FLOAT) | |||||
=> new HammingLoss(mode, threshold: threshold, name: name, dtype: dtype); | |||||
public IMetricFunc TopKCategoricalAccuracy(int k = 5, string name = "top_k_categorical_accuracy", TF_DataType dtype = TF_DataType.TF_FLOAT) | public IMetricFunc TopKCategoricalAccuracy(int k = 5, string name = "top_k_categorical_accuracy", TF_DataType dtype = TF_DataType.TF_FLOAT) | ||||
=> new TopKCategoricalAccuracy(k: k, name: name, dtype: dtype); | => new TopKCategoricalAccuracy(k: k, name: name, dtype: dtype); | ||||
@@ -24,6 +24,36 @@ public class metrics_utils | |||||
return tf.reduce_sum(y_true * y_pred, axis: axis ?? -1); | return tf.reduce_sum(y_true * y_pred, axis: axis ?? -1); | ||||
} | } | ||||
public static Tensor hamming_loss_fn(Tensor y_true, Tensor y_pred, Tensor threshold, string mode) | |||||
{ | |||||
if (threshold == null) | |||||
{ | |||||
threshold = tf.reduce_max(y_pred, axis: -1, keepdims: true); | |||||
// make sure [0, 0, 0] doesn't become [1, 1, 1] | |||||
// Use abs(x) > eps, instead of x != 0 to check for zero | |||||
y_pred = tf.logical_and(y_pred >= threshold, tf.abs(y_pred) > 1e-12); | |||||
} | |||||
else | |||||
{ | |||||
y_pred = y_pred > threshold; | |||||
} | |||||
y_true = tf.cast(y_true, tf.int32); | |||||
y_pred = tf.cast(y_pred, tf.int32); | |||||
if (mode == "multiclass") | |||||
{ | |||||
var nonzero = tf.cast(tf.math.count_nonzero(y_true * y_pred, axis: -1), tf.float32); | |||||
return 1.0 - nonzero; | |||||
} | |||||
else | |||||
{ | |||||
var nonzero = tf.cast(tf.math.count_nonzero(y_true - y_pred, axis: -1), tf.float32); | |||||
return nonzero / y_true.shape[-1]; | |||||
} | |||||
} | |||||
/// <summary> | /// <summary> | ||||
/// Creates float Tensor, 1.0 for label-prediction match, 0.0 for mismatch. | /// Creates float Tensor, 1.0 for label-prediction match, 0.0 for mismatch. | ||||
/// </summary> | /// </summary> | ||||
@@ -142,6 +142,51 @@ public class MetricsTest : EagerModeTestBase | |||||
Assert.AreEqual(r, new[] { 0.3846154f, 0.90909094f, 0.8333334f }); | Assert.AreEqual(r, new[] { 0.3846154f, 0.90909094f, 0.8333334f }); | ||||
} | } | ||||
/// <summary> | |||||
/// https://www.tensorflow.org/addons/api_docs/python/tfa/metrics/HammingLoss | |||||
/// </summary> | |||||
[TestMethod] | |||||
public void HammingLoss() | |||||
{ | |||||
// multi-class hamming loss | |||||
var y_true = np.array(new[,] | |||||
{ | |||||
{ 1, 0, 0, 0 }, | |||||
{ 0, 0, 1, 0 }, | |||||
{ 0, 0, 0, 1 }, | |||||
{ 0, 1, 0, 0 } | |||||
}); | |||||
var y_pred = np.array(new[,] | |||||
{ | |||||
{ 0.8f, 0.1f, 0.1f, 0.0f }, | |||||
{ 0.2f, 0.0f, 0.8f, 0.0f }, | |||||
{ 0.05f, 0.05f, 0.1f, 0.8f }, | |||||
{ 1.0f, 0.0f, 0.0f, 0.0f } | |||||
}); | |||||
var m = tf.keras.metrics.HammingLoss(mode: "multiclass", threshold: 0.6f); | |||||
m.update_state(y_true, y_pred); | |||||
var r = m.result().numpy(); | |||||
Assert.AreEqual(r, 0.25f); | |||||
// multi-label hamming loss | |||||
y_true = np.array(new[,] | |||||
{ | |||||
{ 1, 0, 1, 0 }, | |||||
{ 0, 1, 0, 1 }, | |||||
{ 0, 0, 0, 1 } | |||||
}); | |||||
y_pred = np.array(new[,] | |||||
{ | |||||
{ 0.82f, 0.5f, 0.9f, 0.0f }, | |||||
{ 0f, 1f, 0.4f, 0.98f }, | |||||
{ 0.89f, 0.79f, 0f, 0.3f } | |||||
}); | |||||
m = tf.keras.metrics.HammingLoss(mode: "multilabel", threshold: 0.8f); | |||||
m.update_state(y_true, y_pred); | |||||
r = m.result().numpy(); | |||||
Assert.AreEqual(r, 0.16666667f); | |||||
} | |||||
/// <summary> | /// <summary> | ||||
/// https://www.tensorflow.org/api_docs/python/tf/keras/metrics/TopKCategoricalAccuracy | /// https://www.tensorflow.org/api_docs/python/tf/keras/metrics/TopKCategoricalAccuracy | ||||
/// </summary> | /// </summary> | ||||