Skip to content

Commit 8141f8c

Browse files
committed
Keras step_function doesn't return accuracy SciSharp#630
1 parent ba49010 commit 8141f8c

14 files changed

Lines changed: 222 additions & 21 deletions

File tree

src/TensorFlowNET.Core/Binding.Util.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ public static void Update<T>(this IList<T> list, T element)
4949
public static void add<T>(this IList<T> list, T element)
5050
=> list.Add(element);
5151

52+
public static void add<T>(this IList<T> list, IEnumerable<T> elements)
53+
{
54+
foreach (var ele in elements)
55+
list.Add(ele);
56+
}
57+
5258
public static void append<T>(this IList<T> list, T element)
5359
=> list.Insert(list.Count, element);
5460

src/TensorFlowNET.Core/Keras/Engine/LossesContainer.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,13 @@ public class LossesContainer : Container
1111
Mean _loss_metric;
1212
bool _built;
1313
Tensor[] _per_output_metrics;
14-
List<Tensor> loss_metric_values;
1514

1615
public LossesContainer(ILossFunc losses, string[] output_names = null)
1716
: base(output_names)
1817
{
1918
_user_losses = losses;
2019
_losses = losses;
2120
_loss_metric = new Mean(name: "loss");
22-
loss_metric_values = new List<Tensor>();
2321
_built = false;
2422
}
2523

@@ -37,6 +35,7 @@ public Tensor Call(Tensor y_true, Tensor y_pred)
3735
var batch_dim = array_ops.shape(y_true)[0];
3836

3937
var loss_values = new List<Tensor>();
38+
var loss_metric_values = new List<Tensor>();
4039

4140
/*if (_losses.Reduction == ReductionV2.SUM_OVER_BATCH_SIZE
4241
|| _losses.Reduction == ReductionV2.AUTO)
@@ -69,5 +68,16 @@ void _create_metrics()
6968
{
7069
// _per_output_metrics = _output_names.Select(x => null);
7170
}
71+
72+
public IEnumerable<Metric> metrics
73+
{
74+
get
75+
{
76+
if (!_built)
77+
return new List<Metric>();
78+
79+
return new[] { _loss_metric };
80+
}
81+
}
7282
}
7383
}
Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,81 @@
1-
namespace Tensorflow.Keras.Engine
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Tensorflow.Keras.Metrics;
5+
using static Tensorflow.Binding;
6+
7+
namespace Tensorflow.Keras.Engine
28
{
39
public class MetricsContainer : Container
410
{
511
string[] _user_metrics;
6-
string[] _metrics;
12+
string[] _metric_names;
13+
Metric[] _metrics;
14+
List<Metric> _metrics_in_order;
715

816
public MetricsContainer(string[] metrics, string[] output_names = null)
917
: base(output_names)
1018
{
1119
_user_metrics = metrics;
12-
_metrics = metrics;
20+
_metric_names = metrics;
1321
_built = false;
1422
}
1523

1624
public void update_state(Tensor y_true, Tensor y_pred, Tensor sample_weight = null)
1725
{
1826
if (!_built)
19-
Build();
27+
Build(y_true, y_pred);
28+
29+
foreach (var metric_obj in _metrics_in_order)
30+
metric_obj.update_state(y_true, y_pred);
31+
}
2032

33+
void Build(Tensor y_true, Tensor y_pred)
34+
{
35+
_metrics = _get_metric_objects(_metric_names, y_true, y_pred);
36+
_set_metric_names();
37+
_create_ordered_metrics();
2138
_built = true;
2239
}
2340

24-
void Build()
41+
void _set_metric_names()
42+
{
43+
44+
}
45+
46+
void _create_ordered_metrics()
47+
{
48+
_metrics_in_order = new List<Metric>();
49+
foreach (var m in _metrics)
50+
_metrics_in_order.append(m);
51+
}
52+
53+
Metric[] _get_metric_objects(string[] metrics, Tensor y_t, Tensor y_p)
54+
{
55+
return metrics.Select(x => _get_metric_object(x, y_t, y_p)).ToArray();
56+
}
57+
58+
Metric _get_metric_object(string metric, Tensor y_t, Tensor y_p)
59+
{
60+
Func<Tensor, Tensor, Tensor> metric_obj = null;
61+
if (metric == "accuracy" || metric == "acc")
62+
{
63+
metric_obj = tf.keras.metrics.sparse_categorical_accuracy;
64+
return new MeanMetricWrapper(metric_obj, metric);
65+
}
66+
67+
throw new NotImplementedException("");
68+
}
69+
70+
public IEnumerable<Metric> metrics
2571
{
72+
get
73+
{
74+
if (!_built)
75+
return new List<Metric>();
2676

77+
return _metrics_in_order;
78+
}
2779
}
2880
}
2981
}

src/TensorFlowNET.Core/Keras/Engine/Model.Fit.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using NumSharp;
22
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
35
using Tensorflow.Keras.ArgsDefinition;
46
using Tensorflow.Keras.Engine.DataAdapters;
57

@@ -51,17 +53,24 @@ public void fit(NDArray x, NDArray y,
5153

5254
stop_training = false;
5355
_train_counter.assign(0);
54-
56+
bool first_step = true;
5557
foreach (var (epoch, iterator) in data_handler.enumerate_epochs())
5658
{
5759
// reset_metrics();
5860
// callbacks.on_epoch_begin(epoch)
5961
// data_handler.catch_stop_iteration();
62+
IEnumerable<(string, Tensor)> results = null;
6063
foreach (var step in data_handler.steps())
6164
{
6265
// callbacks.on_train_batch_begin(step)
63-
step_function(iterator);
66+
results = step_function(iterator);
67+
if (first_step)
68+
{
69+
Console.WriteLine($"epoch: {epoch}, " + string.Join(", ", results.Select(x => $"{x.Item1}: {(float)x.Item2}")));
70+
first_step = false;
71+
}
6472
}
73+
Console.WriteLine($"epoch: {epoch + 1}, " + string.Join(", ", results.Select(x => $"{x.Item1}: {(float)x.Item2}")));
6574
}
6675
}
6776
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.Collections.Generic;
2+
using Tensorflow.Keras.Metrics;
3+
using static Tensorflow.Binding;
4+
5+
namespace Tensorflow.Keras.Engine
6+
{
7+
public partial class Model
8+
{
9+
public IEnumerable<Metric> metrics
10+
{
11+
get
12+
{
13+
var _metrics = new List<Metric>();
14+
if (_is_compiled)
15+
{
16+
if (compiled_loss != null)
17+
_metrics.add(compiled_loss.metrics);
18+
if (compiled_metrics != null)
19+
_metrics.add(compiled_metrics.metrics);
20+
}
21+
22+
foreach(var layer in _flatten_layers())
23+
{
24+
// _metrics.extend(layer.metrics);
25+
}
26+
27+
return _metrics;
28+
}
29+
}
30+
}
31+
}

src/TensorFlowNET.Core/Keras/Engine/Model.Train.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,20 @@ namespace Tensorflow.Keras.Engine
88
{
99
public partial class Model
1010
{
11-
Tensor step_function(OwnedIterator iterator)
11+
IEnumerable<(string, Tensor)> step_function(OwnedIterator iterator)
1212
{
1313
var data = iterator.next();
1414
var outputs = train_step(data[0], data[1]);
1515
tf_with(ops.control_dependencies(new object[0]), ctl => _train_counter.assign_add(1));
16-
return null;
16+
return outputs;
1717
}
1818

1919
/// <summary>
2020
/// The logic for one training step.
2121
/// </summary>
2222
/// <param name="data"></param>
2323
/// <returns></returns>
24-
IEnumerable<(string, Tensor)> train_step(Tensor x, Tensor y)
24+
List<(string, Tensor)> train_step(Tensor x, Tensor y)
2525
{
2626
(x, y) = data_handler.DataAdapter.Expand1d(x, y);
2727
using var tape = tf.GradientTape();
@@ -36,7 +36,8 @@ Tensor step_function(OwnedIterator iterator)
3636
// such as loss scaling and gradient clipping.
3737
_minimize(tape, optimizer, loss, trainable_variables);
3838
compiled_metrics.update_state(y, y_pred);
39-
return new[] { ("loss", loss) };
39+
40+
return metrics.Select(x => (x.Name, x.result())).ToList();
4041
}
4142

4243
void _minimize(GradientTape tape, OptimizerV2 optimizer, Tensor loss, List<IVariableV1> trainable_variables)

src/TensorFlowNET.Core/Keras/KerasApi.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Tensorflow.Keras.Engine;
66
using Tensorflow.Keras.Layers;
77
using Tensorflow.Keras.Losses;
8+
using Tensorflow.Keras.Metrics;
89
using Tensorflow.Keras.Optimizers;
910

1011
namespace Tensorflow
@@ -20,6 +21,7 @@ public class KerasApi
2021
public Preprocessing preprocessing { get; } = new Preprocessing();
2122
public BackendImpl backend { get; } = new BackendImpl();
2223
public OptimizerApi optimizers { get; } = new OptimizerApi();
24+
public MetricsApi metrics { get; } = new MetricsApi();
2325

2426
public Sequential Sequential(List<Layer> layers = null,
2527
string name = null)

src/TensorFlowNET.Core/Keras/Metrics/Mean.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
/// </summary>
66
public class Mean : Reduce
77
{
8-
public Mean(string name = "mean", TF_DataType dtype = TF_DataType.DtInvalid)
8+
public Mean(string name = "mean", TF_DataType dtype = TF_DataType.TF_FLOAT)
99
: base(Reduction.WEIGHTED_MEAN, name, dtype: dtype)
1010
{
1111

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Tensorflow.Keras.Metrics
6+
{
7+
public class MeanMetricWrapper : Mean
8+
{
9+
string name;
10+
Func<Tensor, Tensor, Tensor> _fn = null;
11+
12+
public MeanMetricWrapper(Func<Tensor, Tensor, Tensor> fn, string name, TF_DataType dtype = TF_DataType.TF_FLOAT)
13+
: base(name: name, dtype: dtype)
14+
{
15+
_fn = fn;
16+
}
17+
18+
public override Tensor update_state(Tensor y_true, Tensor y_pred, Tensor sample_weight = null)
19+
{
20+
y_true = math_ops.cast(y_true, _dtype);
21+
y_pred = math_ops.cast(y_pred, _dtype);
22+
23+
var matches = _fn(y_true, y_pred);
24+
return update_state(matches, sample_weight: sample_weight);
25+
}
26+
}
27+
}

src/TensorFlowNET.Core/Keras/Metrics/Metric.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ namespace Tensorflow.Keras.Metrics
1010
/// </summary>
1111
public class Metric : Layer
1212
{
13+
protected IVariableV1 total;
14+
protected IVariableV1 count;
15+
protected string _reduction;
16+
protected TF_DataType _dtype;
17+
1318
public Metric(string name = null, TF_DataType dtype = TF_DataType.DtInvalid)
1419
: base(new LayerArgs
1520
{
@@ -44,5 +49,14 @@ protected override IVariableV1 add_weight(string name,
4449
aggregation: aggregation);
4550
});
4651
}
52+
53+
public virtual Tensor update_state(Tensor y_true, Tensor y_pred, Tensor sample_weight = null)
54+
=> throw new NotImplementedException("");
55+
56+
public virtual Tensor result()
57+
=> throw new NotImplementedException("");
58+
59+
public override string ToString()
60+
=> $"{name} {(float)total.numpy()}/{(float)count.numpy()}";
4761
}
4862
}

0 commit comments

Comments
 (0)