@@ -18,6 +18,7 @@ namespace Tensorflow.Keras.Engine.DataAdapters | |||
public int Inferredsteps => _inferred_steps; | |||
int _current_step; | |||
int _step_increment; | |||
public int StepIncrement => _step_increment; | |||
bool _insufficient_data; | |||
int _steps_per_execution_value; | |||
int _initial_epoch => args.InitialEpoch; | |||
@@ -73,7 +74,7 @@ namespace Tensorflow.Keras.Engine.DataAdapters | |||
_dataset = _adapter.GetDataset(); | |||
_inferred_steps = _infer_steps(args.StepsPerEpoch, _dataset); | |||
_current_step = 0; | |||
_step_increment = args.StepsPerExecution.numpy() - 1; | |||
_step_increment = _steps_per_execution_value - 1; | |||
_insufficient_data = false; | |||
} | |||
@@ -14,6 +14,7 @@ namespace Tensorflow.Keras.Engine.DataAdapters | |||
int _batch_size; | |||
int num_samples; | |||
int num_full_batches; | |||
int _partial_batch_size; | |||
public TensorLikeDataAdapter(DataAdapterArgs args) | |||
{ | |||
@@ -22,9 +23,9 @@ namespace Tensorflow.Keras.Engine.DataAdapters | |||
num_samples = args.X.shape[0]; | |||
var batch_size = args.BatchSize == -1 ? 32 : args.BatchSize; | |||
_batch_size = batch_size; | |||
_size = Convert.ToInt32(Math.Floor(num_samples / (batch_size + 0f))); | |||
_size = num_samples < batch_size ? num_samples % batch_size : num_samples / batch_size; | |||
num_full_batches = num_samples / batch_size; | |||
var _partial_batch_size = num_samples % batch_size; | |||
_partial_batch_size = num_samples % batch_size; | |||
var indices_dataset = tf.data.Dataset.range(1); | |||
indices_dataset = indices_dataset.repeat(args.Epochs); | |||
@@ -57,6 +58,15 @@ namespace Tensorflow.Keras.Engine.DataAdapters | |||
var first_k_indices = array_ops.slice(indices, new int[] { 0 }, new int[] { num_in_full_batch }); | |||
first_k_indices = array_ops.reshape(first_k_indices, new int[] { num_full_batches, _batch_size }); | |||
var flat_dataset = tf.data.Dataset.from_tensor_slices(first_k_indices); | |||
if (_partial_batch_size > 0) | |||
{ | |||
var array = array_ops.slice(indices, | |||
new[] { constant_op.constant(num_in_full_batch)}, | |||
new[] { constant_op.constant(_partial_batch_size)}); | |||
var index_remainder = tf.data.Dataset.from_tensor(array); | |||
flat_dataset = flat_dataset.concatenate(index_remainder); | |||
} | |||
return flat_dataset; | |||
} | |||
@@ -340,7 +340,7 @@ namespace Tensorflow.Keras.Engine | |||
tf.Logger.Debug($"Depth {depth}: {node.Layer}: {node.Layer.Name}"); | |||
var outputs = node.Layer.Apply(layer_inputs, is_training: training); | |||
foreach (var output in outputs.Where(x => x != null)) | |||
tf.Logger.Debug($"Depth {depth}: {node.Layer}: {node.Layer.Name} {output.TensorShape}"); | |||
tf.Logger.Information($"Depth {depth}: {node.Layer}: {node.Layer.Name} {output.TensorShape}"); | |||
// Update tensor_dict for next input | |||
foreach (var (x_id, y) in zip(node.FlatOutputIds, outputs)) | |||
tensor_dict[x_id] = new Queue<Tensor>(Enumerable.Range(0, tensor_usage_count[x_id]).Select(x => y)); | |||
@@ -95,7 +95,7 @@ namespace Tensorflow.Keras.Engine | |||
foreach (var step in data_handler.steps()) | |||
{ | |||
// callbacks.on_train_batch_begin(step) | |||
var results = step_function(iterator); | |||
var results = train_step_function(iterator); | |||
var result_pairs = string.Join(", ", results.Select(x => $"{x.Item1}: {(float)x.Item2:F6}")); | |||
Console.WriteLine($"Epoch: {epoch + 1:D3}/{epochs:D3}, Step: {step + 1:D4}/{data_handler.Inferredsteps:D4}, {result_pairs}"); | |||
} | |||
@@ -1,7 +1,10 @@ | |||
using NumSharp; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using Tensorflow.Keras.ArgsDefinition; | |||
using Tensorflow.Keras.Engine.DataAdapters; | |||
using static Tensorflow.Binding; | |||
namespace Tensorflow.Keras.Engine | |||
{ | |||
@@ -21,7 +24,7 @@ namespace Tensorflow.Keras.Engine | |||
/// <param name="workers"></param> | |||
/// <param name="use_multiprocessing"></param> | |||
/// <returns></returns> | |||
public Tensor predict(Tensor x, | |||
public Tensors predict(Tensor x, | |||
int batch_size = -1, | |||
int verbose = 0, | |||
int steps = -1, | |||
@@ -43,7 +46,35 @@ namespace Tensorflow.Keras.Engine | |||
StepsPerExecution = _steps_per_execution | |||
}); | |||
throw new NotImplementedException(""); | |||
Tensors outputs = null; | |||
_predict_counter.assign(0); | |||
// callbacks.on_predict_begin() | |||
foreach (var (epoch, iterator) in data_handler.enumerate_epochs()) | |||
{ | |||
foreach(var step in data_handler.steps()) | |||
{ | |||
// callbacks.on_predict_batch_begin(step) | |||
var batch_outputs = run_predict_step(iterator); | |||
outputs = batch_outputs; | |||
var end_step = step + data_handler.StepIncrement; | |||
// callbacks.on_predict_batch_end(end_step, {'outputs': batch_outputs}) | |||
} | |||
} | |||
// callbacks.on_predict_end() | |||
return outputs; | |||
} | |||
Tensors run_predict_step(OwnedIterator iterator) | |||
{ | |||
var data = iterator.next(); | |||
var outputs = predict_step(data[0]); | |||
tf_with(ops.control_dependencies(new object[0]), ctl => _predict_counter.assign_add(1)); | |||
return outputs; | |||
} | |||
Tensors predict_step(Tensor data) | |||
{ | |||
return Apply(data, is_training: false); | |||
} | |||
} | |||
} |
@@ -8,7 +8,7 @@ namespace Tensorflow.Keras.Engine | |||
{ | |||
public partial class Model | |||
{ | |||
IEnumerable<(string, Tensor)> step_function(OwnedIterator iterator) | |||
IEnumerable<(string, Tensor)> train_step_function(OwnedIterator iterator) | |||
{ | |||
var data = iterator.next(); | |||
var outputs = train_step(data[0], data[1]); | |||
@@ -45,5 +45,11 @@ namespace Tensorflow.Keras.Layers | |||
{ | |||
TargetShape = target_shape | |||
}); | |||
public Reshape Reshape(object[] target_shape) | |||
=> new Reshape(new ReshapeArgs | |||
{ | |||
TargetShapeObjects = target_shape | |||
}); | |||
} | |||
} |
@@ -142,9 +142,6 @@ namespace Tensorflow.Keras.Layers | |||
if (use_fused_avg_updates) | |||
exponential_avg_factor = 1.0f - momentum; | |||
var beta = this.beta; | |||
var gamma = this.gamma; | |||
Func<Tensor[]> _fused_batch_norm_training = () => | |||
{ | |||
return tf.nn.fused_batch_norm( | |||
@@ -21,11 +21,15 @@ namespace Tensorflow.Keras.Layers | |||
protected override Tensors Call(Tensors inputs, Tensor state = null, bool is_training = false) | |||
{ | |||
var shape_tensor = array_ops.shape(inputs); | |||
var shape = new List<int> { inputs.shape[0] }; | |||
shape.AddRange(args.TargetShape.dims); | |||
var shapes = new List<object>(); | |||
shapes.Add(array_ops.shape(inputs)[0]); | |||
if (args.TargetShapeObjects != null) | |||
shapes.AddRange(args.TargetShapeObjects); | |||
if (args.TargetShape != null) | |||
args.TargetShape.dims.ToList().ForEach(x => shapes.Add(x)); | |||
var shape = ops.convert_to_tensor(shapes); | |||
var result = array_ops.reshape(inputs, shape.ToArray()); | |||
var result = array_ops.reshape(inputs, shape); | |||
if (!tf.Context.executing_eagerly()) | |||
result.set_shape(ComputeOutputShape(inputs.shape)); | |||
return result; | |||
@@ -33,14 +37,16 @@ namespace Tensorflow.Keras.Layers | |||
public override TensorShape ComputeOutputShape(TensorShape input_shape) | |||
{ | |||
if (input_shape.dims[0] == -1) | |||
if (input_shape.dims[1..].Contains(-1)) | |||
{ | |||
throw new NotImplementedException(""); | |||
} | |||
else | |||
{ | |||
input_shape = input_shape.dims[0]; | |||
var output_shape = input_shape.concatenate(args.TargetShape.dims); | |||
return output_shape; | |||
} | |||
else | |||
throw new NotImplementedException(""); | |||
} | |||
} | |||
} |
@@ -6,7 +6,7 @@ | |||
<LangVersion>8.0</LangVersion> | |||
<RootNamespace>Tensorflow.Keras</RootNamespace> | |||
<Platforms>AnyCPU;x64</Platforms> | |||
<Version>0.3.0</Version> | |||
<Version>0.4.0</Version> | |||
<Authors>Haiping Chen</Authors> | |||
<Product>Keras for .NET</Product> | |||
<Copyright>Apache 2.0, Haiping Chen 2020</Copyright> | |||
@@ -20,7 +20,8 @@ | |||
* Support Conv2D functional API. | |||
* Support BatchNormalization layer. | |||
* Building keras model in subclass, functional and sequential api | |||
* Implemented backward_function.</PackageReleaseNotes> | |||
* Implemented backward_function. | |||
* Support model.load_weights.</PackageReleaseNotes> | |||
<Description>Keras for .NET | |||
Keras is an API designed for human beings, not machines. Keras follows best practices for reducing cognitive load: it offers consistent & simple APIs, it minimizes the number of user actions required for common use cases, and it provides clear & actionable error messages.</Description> | |||
@@ -31,8 +32,8 @@ Keras is an API designed for human beings, not machines. Keras follows best prac | |||
<RepositoryType>Git</RepositoryType> | |||
<SignAssembly>true</SignAssembly> | |||
<AssemblyOriginatorKeyFile>Open.snk</AssemblyOriginatorKeyFile> | |||
<AssemblyVersion>0.3.0.0</AssemblyVersion> | |||
<FileVersion>0.3.0.0</FileVersion> | |||
<AssemblyVersion>0.4.0.0</AssemblyVersion> | |||
<FileVersion>0.4.0.0</FileVersion> | |||
<PackageLicenseFile>LICENSE</PackageLicenseFile> | |||
</PropertyGroup> | |||
@@ -48,7 +49,6 @@ Keras is an API designed for human beings, not machines. Keras follows best prac | |||
<ItemGroup> | |||
<PackageReference Include="MethodBoundaryAspect.Fody" Version="2.0.138" /> | |||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> | |||
<PackageReference Include="NumSharp.Lite" Version="0.1.10" /> | |||
<PackageReference Include="SciSharp.Keras.HDF5" Version="1.1.10.500" /> | |||
<PackageReference Include="SharpZipLib" Version="1.3.1" /> | |||
</ItemGroup> | |||