diff --git a/src/TensorFlowNET.Console/MemoryLeakTesting.cs b/src/TensorFlowNET.Console/MemoryLeakTesting.cs
deleted file mode 100644
index 6b1e07f2..00000000
--- a/src/TensorFlowNET.Console/MemoryLeakTesting.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using static Tensorflow.Binding;
-
-namespace Tensorflow
-{
- class MemoryLeakTesting
- {
- public void WarmUp()
- {
- print(tf.VERSION);
- }
-
- ///
- ///
- ///
- public void TensorCreation()
- {
- int total = 1 * 1000 * 1000;
- for (int i = 0; i < total; i++)
- {
- /*var const1 = new Tensor(new float[,]
- {
- { 3.0f, 1.0f },
- { 1.0f, 2.0f }
- });
- const1.Dispose();*/
-
- var tensor = new EagerTensorV2(new float[,]
- {
- { 3.0f, 1.0f },
- { 1.0f, 2.0f }
- });
-
- tensor.Dispose();
- }
-
- GC.Collect();
- }
- }
-}
diff --git a/src/TensorFlowNET.Console/MemoryMonitor.cs b/src/TensorFlowNET.Console/MemoryMonitor.cs
new file mode 100644
index 00000000..86130583
--- /dev/null
+++ b/src/TensorFlowNET.Console/MemoryMonitor.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+using static Tensorflow.Binding;
+
+namespace Tensorflow
+{
+ public class MemoryMonitor
+ {
+ public void WarmUp()
+ {
+ print(tf.VERSION);
+ }
+
+ public void Execute(int epoch, int iterate, Action process)
+ {
+ /*GC.Collect();
+ GC.WaitForPendingFinalizers();
+ GC.Collect();*/
+
+ print($"{process.Method.Name} started...");
+ for (int i = 0; i < epoch; i++)
+ {
+ var initialMemory = Process.GetCurrentProcess().PrivateMemorySize64;// GC.GetTotalMemory(true);
+ process(iterate);
+ var finalMemory = Process.GetCurrentProcess().PrivateMemorySize64; //GC.GetTotalMemory(true);
+ print($"Epoch {i}: {Format(finalMemory - initialMemory)}.");
+ }
+
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ GC.Collect();
+
+ print($"Total {process.Method.Name} usage {Format(Process.GetCurrentProcess().PrivateMemorySize64)}");
+ }
+
+ private string Format(long usage)
+ {
+ if (usage < 0)
+ return $"-{Format(0 - usage)}";
+
+ if (usage <= 1024 && usage >= 0)
+ return $"{usage} Bytes";
+ else if (usage > 1024 && usage <= 1024 * 1024)
+ return $"{usage / 1024} KB";
+ else
+ return $"{usage / 1024 / 1024} MB";
+ }
+ }
+}
diff --git a/src/TensorFlowNET.Console/MemoryTestingCases.cs b/src/TensorFlowNET.Console/MemoryTestingCases.cs
new file mode 100644
index 00000000..f9356955
--- /dev/null
+++ b/src/TensorFlowNET.Console/MemoryTestingCases.cs
@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using static Tensorflow.Binding;
+
+namespace Tensorflow
+{
+ class MemoryTestingCases
+ {
+ ///
+ ///
+ ///
+ public Action Constant
+ => (iterate) =>
+ {
+ for (int i = 0; i < iterate; i++)
+ {
+ var tensor = tf.constant(3112.0f);
+ }
+ };
+ public Action Variable
+ => (iterate) =>
+ {
+ for (int i = 0; i < iterate; i++)
+ {
+ var tensor = tf.Variable(3112.0f);
+ }
+ };
+
+ public Action MathAdd
+ => (iterate) =>
+ {
+ var x = tf.constant(3112.0f);
+ var y = tf.constant(3112.0f);
+
+ for (int i = 0; i < iterate; i++)
+ {
+ var z = x + y;
+ }
+ };
+
+ public Action Gradient
+ => (iterate) =>
+ {
+ for(int i = 0; i< iterate; i++)
+ {
+ var w = tf.constant(3112.0f);
+ using var tape = tf.GradientTape();
+ tape.watch(w);
+ var loss = w * w;
+ var grad = tape.gradient(loss, w);
+ }
+ };
+ }
+}
diff --git a/src/TensorFlowNET.Console/Program.cs b/src/TensorFlowNET.Console/Program.cs
index 86ed503b..8cfd9200 100644
--- a/src/TensorFlowNET.Console/Program.cs
+++ b/src/TensorFlowNET.Console/Program.cs
@@ -7,11 +7,24 @@ namespace Tensorflow
static void Main(string[] args)
{
// boot .net core 10.5M.
- var memoryTest = new MemoryLeakTesting();
+ var mm = new MemoryMonitor();
// warm up tensorflow.net 28.5M.
- memoryTest.WarmUp();
- // 1 million float tensor 34.5M.
- memoryTest.TensorCreation();
+ mm.WarmUp();
+ var cases = new MemoryTestingCases();
+
+ int batchSize = 1000;
+
+ // 1 million float tensor 58.5M.
+ // mm.Execute(10, 100 * batchSize, cases.Constant);
+
+ // 100K float variable 80.5M.
+ //mm.Execute(10, 10 * batchSize, cases.Variable);
+
+ // 1 million math add 36.5M.
+ // mm.Execute(10, 100 * batchSize, cases.MathAdd);
+
+ // 100K gradient 211M.
+ mm.Execute(100, 1 * batchSize, cases.Gradient);
Console.WriteLine("Finished.");
Console.ReadLine();
diff --git a/src/TensorFlowNET.Core/APIs/c_api.cs b/src/TensorFlowNET.Core/APIs/c_api.cs
index d3dc15ed..c1575fb4 100644
--- a/src/TensorFlowNET.Core/APIs/c_api.cs
+++ b/src/TensorFlowNET.Core/APIs/c_api.cs
@@ -43,7 +43,7 @@ namespace Tensorflow
///
public partial class c_api
{
- public const string TensorFlowLibName = "tensorflow";
+ public const string TensorFlowLibName = @"D:\SciSharp\tensorflow-google\bazel-bin\tensorflow\tensorflow.dll";
public static string StringPiece(IntPtr handle)
{
diff --git a/src/TensorFlowNET.Core/Eager/EagerOperation.cs b/src/TensorFlowNET.Core/Eager/EagerOperation.cs
index dfc5df78..39038608 100644
--- a/src/TensorFlowNET.Core/Eager/EagerOperation.cs
+++ b/src/TensorFlowNET.Core/Eager/EagerOperation.cs
@@ -7,8 +7,10 @@ namespace Tensorflow.Eager
public class EagerOperation : Operation
{
public int NumInputs;
+ public IntPtr[] InputHandles { get; set; }
public Tensor[] Inputs { get; set; }
public int NumOutputs;
+ public IntPtr[] OutputHandles { get; set; }
public Tensor[] Outputs { get; set; }
public int[] SkipInputIndices { get; set; }
diff --git a/src/TensorFlowNET.Core/Eager/EagerTensor.Creation.cs b/src/TensorFlowNET.Core/Eager/EagerTensor.Creation.cs
index fb63e6d8..20edaf3a 100644
--- a/src/TensorFlowNET.Core/Eager/EagerTensor.Creation.cs
+++ b/src/TensorFlowNET.Core/Eager/EagerTensor.Creation.cs
@@ -2,47 +2,66 @@
using System;
using System.Collections.Generic;
using System.Text;
-using static Tensorflow.Binding;
+using Tensorflow.Gradients;
namespace Tensorflow.Eager
{
public partial class EagerTensor : Tensor
{
- public EagerTensor(IntPtr handle) : base(handle)
+ public EagerTensor() : base(IntPtr.Zero)
{
- EagerTensorHandle = handle;
- tfe_tensor_handle = c_api.EagerTensor_Handle(handle);
- _handle = c_api.TFE_TensorHandleResolve(tfe_tensor_handle, status);
- }
-
- /*public EagerTensor(int value, string device_name) : base(value)
- {
- tfe_tensor_handle = c_api.TFE_NewTensorHandle(_handle, status);
- EagerTensorHandle = c_api.TFE_EagerTensorFromHandle(tf.context, tfe_tensor_handle);
+ EagerTensorHandle = c_api.TFE_NewEagerTensor();
+ // _id = c_api.TFE_EagerTensorId(EagerTensorHandle);
+ // print($"new EagerTensorHandle {EagerTensorHandle.ToString("x16")} {Id}");
}
- public EagerTensor(long value, string device_name) : base(value)
+ public EagerTensor(IntPtr handle) : base(IntPtr.Zero)
{
- tfe_tensor_handle = c_api.TFE_NewTensorHandle(_handle, status);
- EagerTensorHandle = c_api.TFE_EagerTensorFromHandle(tf.context, tfe_tensor_handle);
+ EagerTensorHandle = handle;
+ Resolve();
+ // print($"new EagerTensorHandle {EagerTensorHandle.ToString("x16")} {Id}");
}
- public EagerTensor(float value, string device_name) : base(value)
- {
- tfe_tensor_handle = c_api.TFE_NewTensorHandle(_handle, status);
- EagerTensorHandle = c_api.TFE_EagerTensorFromHandle(tf.context, tfe_tensor_handle);
- }*/
-
public EagerTensor(string value, string device_name) : base(value)
{
+ EagerTensorHandle = c_api.TFE_NewEagerTensor();
tfe_tensor_handle = c_api.TFE_NewTensorHandle(_handle, status);
- EagerTensorHandle = c_api.TFE_EagerTensorFromHandle(tf.context, tfe_tensor_handle);
+ c_api.TFE_SetEagerTensorHandle(EagerTensorHandle, tfe_tensor_handle);
+ Resolve();
+ // print($"new EagerTensorHandle {EagerTensorHandle.ToString("x16")} {Id}");
}
public EagerTensor(NDArray value, string device_name) : base(value)
{
+ EagerTensorHandle = c_api.TFE_NewEagerTensor();
tfe_tensor_handle = c_api.TFE_NewTensorHandle(_handle, status);
- EagerTensorHandle = c_api.TFE_EagerTensorFromHandle(tf.context, tfe_tensor_handle);
+ c_api.TFE_SetEagerTensorHandle(EagerTensorHandle, tfe_tensor_handle);
+ Resolve();
+ // print($"new EagerTensorHandle {EagerTensorHandle.ToString("x16")} {Id}");
+ }
+
+ public EagerTensor Resolve()
+ {
+ if (tfe_tensor_handle == IntPtr.Zero)
+ tfe_tensor_handle = c_api.TFE_EagerTensorHandle(EagerTensorHandle);
+
+ if (_handle == IntPtr.Zero)
+ _handle = c_api.TFE_TensorHandleResolve(tfe_tensor_handle, status);
+
+ _id = c_api.TFE_EagerTensorId(EagerTensorHandle);
+
+ GarbageCollector.Increase(_handle, GCItemType.TensorHandle);
+ GarbageCollector.Increase(tfe_tensor_handle, GCItemType.LocalTensorHandle);
+ GarbageCollector.Increase(EagerTensorHandle, GCItemType.EagerTensorHandle);
+
+ return this;
+ }
+
+ protected override void DisposeUnmanagedResources(IntPtr handle)
+ {
+ GarbageCollector.Decrease(_handle);
+ GarbageCollector.Decrease(tfe_tensor_handle);
+ GarbageCollector.Decrease(EagerTensorHandle);
}
}
}
diff --git a/src/TensorFlowNET.Core/Eager/EagerTensor.cs b/src/TensorFlowNET.Core/Eager/EagerTensor.cs
index 13d89f73..7a88a602 100644
--- a/src/TensorFlowNET.Core/Eager/EagerTensor.cs
+++ b/src/TensorFlowNET.Core/Eager/EagerTensor.cs
@@ -13,6 +13,25 @@ namespace Tensorflow.Eager
public IntPtr EagerTensorHandle { get; set; }
public override string Device => c_api.StringPiece(c_api.TFE_TensorHandleDeviceName(tfe_tensor_handle, status));
+ public override int rank => c_api.TFE_TensorHandleNumDims(tfe_tensor_handle, status);
+
+ public static int GetRank(IntPtr handle)
+ {
+ var tfe_tensor_handle = c_api.TFE_EagerTensorHandle(handle);
+ using var status = new Status();
+ return c_api.TFE_TensorHandleNumDims(tfe_tensor_handle, status);
+ }
+
+ public static int[] GetDims(IntPtr handle)
+ {
+ var tfe_tensor_handle = c_api.TFE_EagerTensorHandle(handle);
+ using var status = new Status();
+ var dims = new int[c_api.TFE_TensorHandleNumDims(tfe_tensor_handle, status)];
+ for (int i = 0; i < dims.Length; i++)
+ dims[i] = c_api.TFE_TensorHandleDim(tfe_tensor_handle, i, status);
+ return dims;
+ }
+
public override string ToString()
{
switch (rank)
diff --git a/src/TensorFlowNET.Core/Eager/Execute.cs b/src/TensorFlowNET.Core/Eager/Execute.cs
index 7cb8ebbb..91db9ca6 100644
--- a/src/TensorFlowNET.Core/Eager/Execute.cs
+++ b/src/TensorFlowNET.Core/Eager/Execute.cs
@@ -33,18 +33,17 @@ namespace Tensorflow.Eager
{
ctx.ensure_initialized();
- using var status = new Status();
-
- BindingArray results = c_api.TFE_QuickExecute(ctx,
+ var results = Enumerable.Range(0, num_outputs).Select(x => new EagerTensor()).ToArray();
+ Status status = c_api.TFE_QuickExecute(ctx,
ctx.device_name,
op_name,
inputs.Select(x => x.EagerTensorHandle).ToArray(),
inputs.Length,
op => wrap_tfe_src.SetOpAttrs(op, attrs),
- status);
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return results.Data().Select(x => new EagerTensor(x)).ToArray();
+ return results.Select(x => x.Resolve()).ToArray();
}
public (TF_DataType, EagerTensor[]) args_to_matching_eager(Context ctx, TF_DataType default_dtype = TF_DataType.DtInvalid, object[] args = null)
diff --git a/src/TensorFlowNET.Core/Eager/c_api.eager.cs b/src/TensorFlowNET.Core/Eager/c_api.eager.cs
index 6b33dfa0..b175e3e2 100644
--- a/src/TensorFlowNET.Core/Eager/c_api.eager.cs
+++ b/src/TensorFlowNET.Core/Eager/c_api.eager.cs
@@ -11,18 +11,28 @@ namespace Tensorflow
public static extern void TFE_RegisterGradientFunction(gradient_function_callback gradientFunctionCallback,
delete_backward_function_callback deleteBackwardFunctionCallback);
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// previous node ouput
+ ///
+ ///
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr gradient_function_callback(string op_name,
- BindingArray op_inputs,
- BindingArray op_outputs,
+ IntPtr op_inputs,
+ IntPtr op_outputs,
int num_attrs,
- BindingArray output_grads,
- BindingArray skip_input_indices);
+ IntPtr output_grads,
+ IntPtr skip_input_indices);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void delete_backward_function_callback(string op_name,
- BindingArray op_inputs,
- BindingArray op_outputs);
+ IntPtr op_inputs,
+ IntPtr op_outputs);
[DllImport(TensorFlowLibName)]
public static extern IntPtr TFE_WrapGradientResult(IntPtr[] gradients, int num_gradients);
@@ -32,7 +42,7 @@ namespace Tensorflow
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr VSpace_callback_Ones(long[] shape, int dims, TF_DataType dtype);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate IntPtr VSpace_callback_AggregateGrads(BindingArray gradients);
+ public delegate IntPtr VSpace_callback_AggregateGrads(TF_BindingArray gradients);
[DllImport(TensorFlowLibName)]
public static extern void TFE_RegisterVSpace(IntPtr vspace);
@@ -217,10 +227,16 @@ namespace Tensorflow
public static extern TFE_TensorHandle TFE_NewTensorHandle(IntPtr t, IntPtr status);
[DllImport(TensorFlowLibName)]
- public static extern IntPtr EagerTensor_Handle(IntPtr t);
+ public static extern IntPtr TFE_EagerTensorHandle(IntPtr t);
[DllImport(TensorFlowLibName)]
- public static extern IntPtr TFE_EagerTensorFromHandle(IntPtr ctx, IntPtr h);
+ public static extern int TFE_EagerTensorId(IntPtr t);
+
+ [DllImport(TensorFlowLibName)]
+ public static extern IntPtr TFE_NewEagerTensor();
+
+ [DllImport(TensorFlowLibName)]
+ public static extern void TFE_SetEagerTensorHandle(IntPtr tensor, IntPtr handle);
///
/// Sets the default execution mode (sync/async). Note that this can be
@@ -260,6 +276,9 @@ namespace Tensorflow
[DllImport(TensorFlowLibName)]
public static extern int TFE_TensorHandleNumDims(IntPtr h, IntPtr status);
+ [DllImport(TensorFlowLibName)]
+ public static extern int TFE_TensorHandleDim(IntPtr h, int dim, IntPtr status);
+
///
/// Returns the device of the operation that produced `h`. If `h` was produced by
/// a copy, returns the destination device of the copy. Note that the returned
@@ -304,7 +323,13 @@ namespace Tensorflow
/// TFE_TensorHandle*
[DllImport(TensorFlowLibName)]
public static extern void TFE_DeleteEagerTensor(IntPtr h);
-
+
+ [DllImport(TensorFlowLibName)]
+ public static extern void TF_DeleteBindingArray(IntPtr h);
+
+ [DllImport(TensorFlowLibName)]
+ public static extern void TFE_DeleteBindingTensorArray(IntPtr h);
+
///
/// Creates a new eager Executor. Nodes in one executor are guaranteed to be
/// executed in sequence. Assigning nodes to different executors allows executing
@@ -372,10 +397,11 @@ namespace Tensorflow
string device_name,
string op_name,
string name,
- IntPtr[] args,
+ IntPtr[] inputs,
int input_size,
TFE_FastPathExecute_SetOpAttrs set_op_attrs,
- IntPtr status);
+ IntPtr[] outputs,
+ int output_size);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void TFE_FastPathExecute_SetOpAttrs(IntPtr op);
@@ -386,13 +412,8 @@ namespace Tensorflow
IntPtr[] inputs,
int input_size,
TFE_FastPathExecute_SetOpAttrs set_op_attrs,
- IntPtr status);
-
- [DllImport(TensorFlowLibName)]
- public static extern IntPtr TFE_QuickExecute1(
- string op_name,
- int input_size,
- IntPtr status);
+ IntPtr[] outputs,
+ int output_size);
[DllImport(TensorFlowLibName)]
public static extern IntPtr TFE_TapeSetNew(bool persistent, bool watch_accessed_variables);
@@ -415,7 +436,7 @@ namespace Tensorflow
[DllImport(TensorFlowLibName)]
public static extern IntPtr TFE_TapeGradient(IntPtr tape,
IntPtr[] target, int target_size,
- IntPtr[] sources, int source_size,
- IntPtr status);
+ IntPtr[] sources, int source_size,
+ IntPtr[] outputs, int output_size);
}
}
diff --git a/src/TensorFlowNET.Core/Gradients/GradientTape.cs b/src/TensorFlowNET.Core/Gradients/GradientTape.cs
index c4cf0cce..ef1ea9fa 100644
--- a/src/TensorFlowNET.Core/Gradients/GradientTape.cs
+++ b/src/TensorFlowNET.Core/Gradients/GradientTape.cs
@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Runtime.InteropServices;
using System.Text;
using Tensorflow.Eager;
using static Tensorflow.Binding;
@@ -21,7 +22,8 @@ namespace Tensorflow.Gradients
///
public class GradientTape : IDisposable
{
- bool _recording;
+ static bool _recording;
+ public static bool Recording => _recording;
bool _persistent;
bool _watch_accessed_variables;
ResourceVariable[] _watched_variables;
@@ -76,13 +78,13 @@ namespace Tensorflow.Gradients
_pop_tape();
}
- using var status = new Status();
- var et = c_api.TFE_TapeGradient(_tape,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_TapeGradient(_tape,
new [] { (target as EagerTensor).EagerTensorHandle }, 1,
new [] { (source as EagerTensor).EagerTensorHandle }, 1,
- status);
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(et);
+ return results[0];
}
public unsafe (Tensor, Tensor) gradient(Tensor target, (ResourceVariable, ResourceVariable) sources)
@@ -93,8 +95,8 @@ namespace Tensorflow.Gradients
_pop_tape();
}
- using var status = new Status();
- BindingArray result_handle = c_api.TFE_TapeGradient(_tape,
+ var results = new[] { new EagerTensor(), new EagerTensor() };
+ Status status = c_api.TFE_TapeGradient(_tape,
new IntPtr[]
{
target as EagerTensor
@@ -104,12 +106,9 @@ namespace Tensorflow.Gradients
(sources.Item1.Handle as EagerTensor).EagerTensorHandle,
(sources.Item2.Handle as EagerTensor).EagerTensorHandle
}, 2,
- status);
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- var results = result_handle.Data().Select(x => new EagerTensor(x)).ToArray();
-
-
if (!_persistent)
{
// Keep track of watched variables before setting tape to None
diff --git a/src/TensorFlowNET.Core/Gradients/RegisterGradientEager.cs b/src/TensorFlowNET.Core/Gradients/RegisterGradientEager.cs
new file mode 100644
index 00000000..0c621750
--- /dev/null
+++ b/src/TensorFlowNET.Core/Gradients/RegisterGradientEager.cs
@@ -0,0 +1,30 @@
+/*****************************************************************************
+ Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+******************************************************************************/
+
+using System;
+
+namespace Tensorflow.Gradients
+{
+ public class RegisterGradientEager : Attribute
+ {
+ public string Name { get; set; }
+
+ public RegisterGradientEager(string name)
+ {
+ Name = name;
+ }
+ }
+}
diff --git a/src/TensorFlowNET.Core/Gradients/Tape.cs b/src/TensorFlowNET.Core/Gradients/Tape.cs
index de5548e8..9a52d743 100644
--- a/src/TensorFlowNET.Core/Gradients/Tape.cs
+++ b/src/TensorFlowNET.Core/Gradients/Tape.cs
@@ -34,7 +34,7 @@ namespace Tensorflow.Gradients
public unsafe ResourceVariable[] watched_variables()
{
BindingArray result = c_api.TFE_TapeWatchedVariables(_handle);
- var variables = result.Data().Select(x =>
+ var variables = result.Data.Select(x =>
{
var tensor = c_api.ResourceVariable_Handle(x);
return new ResourceVariable(x, tensor);
diff --git a/src/TensorFlowNET.Core/Gradients/math_grad_eager.cs b/src/TensorFlowNET.Core/Gradients/math_grad_eager.cs
new file mode 100644
index 00000000..2e5b65a9
--- /dev/null
+++ b/src/TensorFlowNET.Core/Gradients/math_grad_eager.cs
@@ -0,0 +1,74 @@
+/*****************************************************************************
+ Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+******************************************************************************/
+
+using NumSharp;
+using System;
+using System.Linq;
+using Tensorflow.Eager;
+using Tensorflow.Operations;
+using static Tensorflow.Binding;
+
+namespace Tensorflow.Gradients
+{
+ ///
+ /// Gradients for operators defined in math_ops.py.
+ ///
+ [RegisterGradientEager("math_grad")]
+ public class math_grad_eager
+ {
+ [RegisterGradientEager("Mul")]
+ public static EagerTensor[] _MulGrad(EagerOperation op, IntPtr[] grads)
+ {
+ var x = op.InputHandles[0];
+ var y = op.InputHandles[1];
+ var grad = grads[0];
+
+ if (op.SkipInputIndices.Contains(1) &&
+ EagerTensor.GetRank(grad) == 0)
+ {
+ return new EagerTensor[]
+ {
+ null,//gen_math_ops.mul(grad, math_ops.conj(y)),
+ null
+ };
+ }
+
+ if (_ShapesFullySpecifiedAndEqual(x, y, grad))
+ {
+ return new EagerTensor[]
+ {
+ gen_math_ops.mul(grad, y),
+ gen_math_ops.mul(grad, x)
+ };
+ }
+
+ throw new NotImplementedException("");
+ }
+
+ public static bool _ShapesFullySpecifiedAndEqual(IntPtr x, IntPtr y, IntPtr grad)
+ {
+ var x_shape = EagerTensor.GetDims(x);
+ var y_shape = EagerTensor.GetDims(y);
+
+ var grad_shape = EagerTensor.GetDims(grad);
+ return x_shape != null &&
+ y_shape != null &&
+ Enumerable.SequenceEqual(x_shape, y_shape) &&
+ Enumerable.SequenceEqual(y_shape, grad_shape) &&
+ !x_shape.Contains(-1);
+ }
+ }
+}
diff --git a/src/TensorFlowNET.Core/Gradients/ops.gradient_function_mapping_eager.cs b/src/TensorFlowNET.Core/Gradients/ops.gradient_function_mapping_eager.cs
new file mode 100644
index 00000000..432113e0
--- /dev/null
+++ b/src/TensorFlowNET.Core/Gradients/ops.gradient_function_mapping_eager.cs
@@ -0,0 +1,101 @@
+/*****************************************************************************
+ Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using Tensorflow.Eager;
+using Tensorflow.Gradients;
+
+namespace Tensorflow
+{
+ public partial class ops
+ {
+ public static Dictionary> gradientFunctionsEager = null;
+
+ public static void RegisterFromAssemblyEager()
+ {
+ if (gradientFunctionsEager == null)
+ {
+ gradientFunctionsEager = new Dictionary>();
+
+ var gradGroups = Assembly.GetExecutingAssembly()
+ .GetTypes()
+ .Where(x => x.GetCustomAttribute() != null)
+ .ToArray();
+
+ foreach (var g in gradGroups)
+ {
+ var methods = g.GetMethods()
+ .Where(x => x.GetCustomAttribute() != null)
+ .ToArray();
+
+ foreach (var m in methods)
+ {
+ RegisterGradientFunctionEager(m.GetCustomAttribute().Name,
+ (oper, out_grads) =>
+ g.InvokeMember(m.Name,
+ BindingFlags.InvokeMethod,
+ null,
+ null,
+ args: new object[] { oper, out_grads }) as EagerTensor[]
+ );
+ }
+
+ // REGISTER_NO_GRADIENT_OP
+ methods = g.GetMethods()
+ .Where(x => x.GetCustomAttribute() != null)
+ .ToArray();
+
+ foreach (var m in methods)
+ RegisterNoGradientFunctionEager(m.GetCustomAttribute().Name);
+ }
+ }
+ }
+
+ ///
+ /// Regiter new gradient function
+ ///
+ /// operation type
+ /// function delegate
+ public static void RegisterGradientFunctionEager(string name, Func func)
+ {
+ RegisterFromAssemblyEager();
+
+ gradientFunctionsEager[name] = func;
+ }
+
+ public static void RegisterNoGradientFunctionEager(string name)
+ {
+ RegisterFromAssemblyEager();
+
+ gradientFunctionsEager[name] = null;
+ }
+
+ public static Func get_gradient_function_eager(EagerOperation op)
+ {
+ if (op.inputs == null) return null;
+
+ RegisterFromAssemblyEager();
+
+ if (!gradientFunctionsEager.ContainsKey(op.type))
+ throw new LookupError($"can't get graident function through get_gradient_function {op.type}");
+
+ return gradientFunctionsEager[op.type];
+ }
+ }
+}
diff --git a/src/TensorFlowNET.Core/Operations/NnOps/gen_nn_ops.cs b/src/TensorFlowNET.Core/Operations/NnOps/gen_nn_ops.cs
index 9cada111..b7c3b392 100644
--- a/src/TensorFlowNET.Core/Operations/NnOps/gen_nn_ops.cs
+++ b/src/TensorFlowNET.Core/Operations/NnOps/gen_nn_ops.cs
@@ -15,6 +15,7 @@
******************************************************************************/
using System;
+using System.Linq;
using Tensorflow.Eager;
using static Tensorflow.Binding;
@@ -467,14 +468,15 @@ namespace Tensorflow.Operations
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Relu", name, new IntPtr[]
{
features as EagerTensor,
- }, 1, null, status);
+ }, 1, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Relu", name: name, args: new { features });
@@ -485,14 +487,15 @@ namespace Tensorflow.Operations
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Tanh", name, new IntPtr[]
{
x as EagerTensor,
- }, 1, null, status);
+ }, 1, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Tanh", name: name, args: new { x });
diff --git a/src/TensorFlowNET.Core/Operations/gen_array_ops.cs b/src/TensorFlowNET.Core/Operations/gen_array_ops.cs
index e85c743a..8fcc31e6 100644
--- a/src/TensorFlowNET.Core/Operations/gen_array_ops.cs
+++ b/src/TensorFlowNET.Core/Operations/gen_array_ops.cs
@@ -54,15 +54,16 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"ConcatV2", name, new IntPtr[]
{
values as EagerTensor,
axis as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("ConcatV2", name: name, args: new { values, axis });
@@ -161,14 +162,14 @@ namespace Tensorflow
{
if(tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Pack", name,
values.Select(x => (x as EagerTensor).EagerTensorHandle).ToArray(), values.Length,
op => wrap_tfe_src.SetOpAttrs(op, "axis", axis),
- status);
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Pack", name: name, args: new { values, axis });
@@ -229,14 +230,15 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Identity", name, new IntPtr[]
{
input as EagerTensor
- }, 1, null, status);
+ }, 1, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Identity", name, new { input });
@@ -276,15 +278,16 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Fill", name, new IntPtr[]
{
dims as EagerTensor,
value as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Fill", name, new { dims, value });
@@ -302,15 +305,16 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor(), new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"BroadcastGradientArgs", name, new IntPtr[]
{
s0 as EagerTensor,
s1 as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return (new EagerTensor(results[0]), new EagerTensor(results[1]));
+ return (results[0], results[1]);
}
var _op = _op_def_lib._apply_op_helper("BroadcastGradientArgs", name, new { s0, s1 });
@@ -328,15 +332,16 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Reshape", name, new IntPtr[]
{
tensor as EagerTensor,
shape as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Reshape", name, new { tensor, shape });
@@ -416,16 +421,16 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Shape", name, new IntPtr[]
{
input as EagerTensor,
}, 1,
op => wrap_tfe_src.SetOpAttrs(op, "out_type", out_type),
- status);
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Shape", name, new { input, out_type });
@@ -475,15 +480,16 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Tile", name, new IntPtr[]
{
input as EagerTensor,
multiples as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Tile", name, new { input, multiples });
@@ -519,8 +525,8 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"StridedSlice", name, new IntPtr[]
{
input as EagerTensor,
@@ -533,10 +539,10 @@ namespace Tensorflow
"end_mask", end_mask,
"ellipsis_mask", ellipsis_mask,
"new_axis_mask", new_axis_mask,
- "shrink_axis_mask", shrink_axis_mask),
- status);
+ "shrink_axis_mask", shrink_axis_mask),
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("StridedSlice", name, new
diff --git a/src/TensorFlowNET.Core/Operations/gen_math_ops.cs b/src/TensorFlowNET.Core/Operations/gen_math_ops.cs
index 8f9e6d88..9df1986b 100644
--- a/src/TensorFlowNET.Core/Operations/gen_math_ops.cs
+++ b/src/TensorFlowNET.Core/Operations/gen_math_ops.cs
@@ -16,12 +16,13 @@
using System;
using System.Linq;
+using System.Runtime.InteropServices;
using Tensorflow.Eager;
using static Tensorflow.Binding;
namespace Tensorflow
{
- public static class gen_math_ops
+ public static partial class gen_math_ops
{
public static OpDefLibrary _op_def_lib = new OpDefLibrary();
public static Execute _execute = new Execute();
@@ -43,14 +44,14 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"AddN", name,
inputs.Select(x => (x as EagerTensor).EagerTensorHandle).ToArray(), inputs.Length,
null,
- status);
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("AddN", name, args: new { inputs });
@@ -58,6 +59,18 @@ namespace Tensorflow
return _op.outputs[0];
}
+ public static EagerTensor add_n(IntPtr[] inputs, string name = null)
+ {
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ "AddN", name,
+ inputs, inputs.Length,
+ null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
+ status.Check(true);
+ return results[0].Resolve();
+ }
+
///
/// Returns the index with the largest value across dimensions of a tensor.
///
@@ -131,8 +144,8 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Mean", name,
new IntPtr[]
{
@@ -140,9 +153,9 @@ namespace Tensorflow
axis as EagerTensor
}, 2,
op => wrap_tfe_src.SetOpAttrs(op, "keep_dims", keep_dims),
- status);
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0];
}
var _op = _op_def_lib._apply_op_helper("Mean", name, args: new { input, reduction_indices = axis, keep_dims = keep_dims });
@@ -178,17 +191,17 @@ namespace Tensorflow
{
try
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Prod", name, new IntPtr[]
{
input as EagerTensor,
axis as EagerTensor
}, 2,
- op => wrap_tfe_src.SetOpAttrs(op, "keep_dims", keep_dims),
- status);
+ op => wrap_tfe_src.SetOpAttrs(op, "keep_dims", keep_dims),
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
catch (Exception)
{
@@ -228,15 +241,16 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Add", name, new IntPtr[]
{
x as EagerTensor,
y as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Add", name, args: new { x, y });
@@ -248,15 +262,16 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Add", name, new IntPtr[]
{
x as EagerTensor,
y as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Add", name, args: new { x, y });
@@ -269,15 +284,16 @@ namespace Tensorflow
// forward_compatible(2019, 6, 25):
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"AddV2", name, new IntPtr[]
{
x as EagerTensor,
y as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("AddV2", name, args: new { x, y });
@@ -303,14 +319,15 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Sin", name, new IntPtr[]
{
x as EagerTensor,
- }, 1, null, status);
+ }, 1, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Sin", name, args: new { x });
@@ -336,14 +353,15 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Sigmoid", name, new IntPtr[]
{
x as EagerTensor,
- }, 1, null, status);
+ }, 1, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var op = _op_def_lib._apply_op_helper("Sigmoid", name: name, new { x });
@@ -428,14 +446,15 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Tan", name, new IntPtr[]
{
x as EagerTensor,
- }, 1, null, status);
+ }, 1, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Tan", name, args: new { x });
@@ -510,15 +529,16 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Less", name, new IntPtr[]
{
x as EagerTensor,
y as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Less", name: name, args: new { x, y });
@@ -586,14 +606,15 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Square", name, new IntPtr[]
{
x as EagerTensor,
- }, 1, null, status);
+ }, 1, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Square", name, args: new { x });
@@ -651,14 +672,14 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Cast", name,
new IntPtr[] { x as EagerTensor }, 1,
op => wrap_tfe_src.SetOpAttrs(op, "DstT", DstT, "Truncate", Truncate),
- status);
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Cast", name, args: new { x, DstT, Truncate });
@@ -670,14 +691,15 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Neg", name, new IntPtr[]
{
x as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Neg", name, args: new { x });
@@ -689,14 +711,15 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Sqrt", name, new IntPtr[]
{
x as EagerTensor,
- }, 1, null, status);
+ }, 1, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Sqrt", name, args: new { x });
@@ -708,15 +731,16 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Sub", name, new IntPtr[]
{
x as EagerTensor,
y as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Sub", name, args: new { x, y });
@@ -728,15 +752,16 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Sub", name, new IntPtr[]
{
x as EagerTensor,
y as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Sub", name, args: new { x, y });
@@ -755,15 +780,16 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Equal", name, new IntPtr[]
{
x as EagerTensor,
y as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Equal", name, args: new { x, y });
@@ -783,15 +809,16 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"NotEqual", name, new IntPtr[]
{
x as EagerTensor,
y as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("NotEqual", name, args: new { x, y });
@@ -803,15 +830,16 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Atan2", name, new IntPtr[]
{
y as EagerTensor,
x as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Atan2", name, args: new { y, x });
@@ -822,15 +850,16 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Mul", name, new IntPtr[]
{
x as EagerTensor,
y as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Mul", name, args: new { x, y });
@@ -842,15 +871,16 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Mul", name, new IntPtr[]
{
x as EagerTensor,
y as EagerTensor,
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Mul", name, args: new { x, y });
@@ -869,15 +899,16 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"RealDiv", name, new IntPtr[]
{
x as EagerTensor,
y as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("RealDiv", name, args: new { x, y });
@@ -896,15 +927,16 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"FloorMod", name, new IntPtr[]
{
x as EagerTensor,
y as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("FloorMod", name, args: new { x, y });
@@ -916,15 +948,16 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"FloorDiv", name, new IntPtr[]
{
x as EagerTensor,
y as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("FloorDiv", name, args: new { x, y });
@@ -945,8 +978,8 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"MatMul", name,
new IntPtr[]
{
@@ -955,10 +988,10 @@ namespace Tensorflow
}, 2,
op => wrap_tfe_src.SetOpAttrs(op,
"transpose_a", transpose_a,
- "transpose_b", transpose_b),
- status);
+ "transpose_b", transpose_b),
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("MatMul", name, args: new { a, b, transpose_a, transpose_b });
@@ -1054,15 +1087,16 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Pow", name, new IntPtr[]
{
x as EagerTensor,
y as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Pow", name, args: new { x, y });
@@ -1074,8 +1108,8 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Sum", name,
new IntPtr[]
{
@@ -1083,9 +1117,9 @@ namespace Tensorflow
axis as EagerTensor
}, 2,
op => wrap_tfe_src.SetOpAttrs(op, "keep_dims", keep_dims),
- status);
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Sum", name, args: new { input, reduction_indices = axis, keep_dims });
@@ -1128,16 +1162,17 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"Range", name, new IntPtr[]
{
start as EagerTensor,
limit as EagerTensor,
delta as EagerTensor
- }, 3, null, status);
+ }, 3, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("Range", name, new { start, limit, delta });
diff --git a/src/TensorFlowNET.Core/Operations/gen_math_ops.eager.cs b/src/TensorFlowNET.Core/Operations/gen_math_ops.eager.cs
new file mode 100644
index 00000000..80655943
--- /dev/null
+++ b/src/TensorFlowNET.Core/Operations/gen_math_ops.eager.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Tensorflow.Eager;
+using static Tensorflow.Binding;
+
+namespace Tensorflow
+{
+ public static partial class gen_math_ops
+ {
+ public static EagerTensor mul(IntPtr x, IntPtr y, string name = null)
+ {
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ "Mul", name, new IntPtr[]
+ {
+ x,
+ y,
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
+ status.Check(true);
+ return results[0].Resolve();
+ }
+ }
+}
diff --git a/src/TensorFlowNET.Core/Operations/gen_random_ops.cs b/src/TensorFlowNET.Core/Operations/gen_random_ops.cs
index 65824da3..bf474814 100644
--- a/src/TensorFlowNET.Core/Operations/gen_random_ops.cs
+++ b/src/TensorFlowNET.Core/Operations/gen_random_ops.cs
@@ -14,6 +14,7 @@
limitations under the License.
******************************************************************************/
using System;
+using System.Linq;
using Tensorflow.Eager;
using static Tensorflow.Binding;
@@ -41,8 +42,8 @@ namespace Tensorflow
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"RandomStandardNormal", name, new IntPtr[]
{
shape as EagerTensor,
@@ -50,10 +51,10 @@ namespace Tensorflow
op => wrap_tfe_src.SetOpAttrs(op,
"seed", seed,
"seed2", seed2,
- "dtype", dtype),
- status);
+ "dtype", dtype),
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("RandomStandardNormal",
diff --git a/src/TensorFlowNET.Core/Operations/gen_resource_variable_ops.cs b/src/TensorFlowNET.Core/Operations/gen_resource_variable_ops.cs
index 1307f81f..37e78188 100644
--- a/src/TensorFlowNET.Core/Operations/gen_resource_variable_ops.cs
+++ b/src/TensorFlowNET.Core/Operations/gen_resource_variable_ops.cs
@@ -29,16 +29,17 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"AssignSubVariableOp", name,
new IntPtr[]
{
resource as EagerTensor,
value as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return results[0];
+ return results[0].Resolve();
}
return null;
@@ -55,16 +56,17 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"AssignAddVariableOp", name,
new IntPtr[]
{
resource as EagerTensor,
value as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return results[0];
+ return results[0].Resolve();
}
return null;
@@ -74,14 +76,15 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- var results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new EagerTensor[0];
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"AssignVariableOp", name,
new IntPtr[]
{
resource as EagerTensor,
value as EagerTensor
- }, 2, null, status);
+ }, 2, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
return null;
}
@@ -95,13 +98,14 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"VarIsInitializedOp", name,
new IntPtr[] { resource as EagerTensor },
- 1, null, status);
+ 1, null,
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("VarIsInitializedOp", name, new { resource });
@@ -123,17 +127,17 @@ namespace Tensorflow
{
if(tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"VarHandleOp", name, null, 0,
op => wrap_tfe_src.SetOpAttrs(op,
"container", container,
"shared_name", shared_name,
"dtype", dtype,
- "shape", shape.dims),
- status);
+ "shape", shape.dims),
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("VarHandleOp", name, new {
@@ -157,14 +161,14 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"ReadVariableOp", name,
new IntPtr[] { resource as EagerTensor }, 1,
op => wrap_tfe_src.SetOpAttrs(op, "dtype", dtype),
- status);
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return new EagerTensor(results[0]);
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("ReadVariableOp", name, new
diff --git a/src/TensorFlowNET.Core/Status/Status.cs b/src/TensorFlowNET.Core/Status/Status.cs
index 90597195..68f86c4e 100644
--- a/src/TensorFlowNET.Core/Status/Status.cs
+++ b/src/TensorFlowNET.Core/Status/Status.cs
@@ -42,6 +42,11 @@ namespace Tensorflow
_handle = TF_NewStatus();
}
+ public Status(IntPtr handle)
+ {
+ _handle = handle;
+ }
+
public void SetStatus(TF_Code code, string msg)
{
TF_SetStatus(_handle, code, msg);
@@ -69,6 +74,9 @@ namespace Tensorflow
public static implicit operator IntPtr(Status status)
=> status._handle;
+ public static implicit operator Status(IntPtr handle)
+ => new Status(handle);
+
protected override void DisposeUnmanagedResources(IntPtr handle)
=> TF_DeleteStatus(handle);
diff --git a/src/TensorFlowNET.Core/System/GCItemCounter.cs b/src/TensorFlowNET.Core/System/GCItemCounter.cs
new file mode 100644
index 00000000..8eecde03
--- /dev/null
+++ b/src/TensorFlowNET.Core/System/GCItemCounter.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tensorflow
+{
+ public class GCItemCounter
+ {
+ public GCItemType ItemType { get; set; }
+ public int RefCounter { get; set; }
+ public DateTime LastUpdateTime { get; set; }
+ public IntPtr Handle { get; set; }
+
+ public override string ToString()
+ => $"{ItemType} {RefCounter} {LastUpdateTime}";
+ }
+}
diff --git a/src/TensorFlowNET.Core/System/GCItemType.cs b/src/TensorFlowNET.Core/System/GCItemType.cs
new file mode 100644
index 00000000..ed6b0b2a
--- /dev/null
+++ b/src/TensorFlowNET.Core/System/GCItemType.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tensorflow
+{
+ public enum GCItemType
+ {
+ TensorHandle = 0,
+ LocalTensorHandle = 1,
+ EagerTensorHandle = 2
+ }
+}
diff --git a/src/TensorFlowNET.Core/System/GarbageCollector.cs b/src/TensorFlowNET.Core/System/GarbageCollector.cs
new file mode 100644
index 00000000..b7ea74d0
--- /dev/null
+++ b/src/TensorFlowNET.Core/System/GarbageCollector.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Timers;
+
+namespace Tensorflow
+{
+ public class GarbageCollector
+ {
+ static Dictionary container = new Dictionary();
+ static Timer timer = null;
+ static object locker = new object();
+
+ public static void Increase(IntPtr handle, GCItemType type)
+ {
+ if(timer == null)
+ {
+ timer = new Timer(300);
+ // Hook up the Elapsed event for the timer.
+ timer.Elapsed += OnTimedEvent;
+ timer.AutoReset = true;
+ timer.Enabled = true;
+ }
+
+ if (container.ContainsKey(handle))
+ {
+ container[handle].RefCounter++;
+ container[handle].LastUpdateTime = DateTime.Now;
+ }
+ else
+ {
+ lock (locker)
+ {
+ container[handle] = new GCItemCounter
+ {
+ ItemType = type,
+ RefCounter = 1,
+ Handle = handle,
+ LastUpdateTime = DateTime.Now
+ };
+ }
+ }
+ }
+
+ public static void Decrease(IntPtr handle)
+ {
+ lock (locker)
+ {
+ if (container.ContainsKey(handle))
+ container[handle].RefCounter--;
+ }
+ }
+
+ private static void OnTimedEvent(object source, ElapsedEventArgs e)
+ {
+ timer.Stop();
+
+ // dispose before 1 sec
+ lock (locker)
+ {
+ var items = container.Values
+ .Where(x => x.RefCounter <= 0 && (DateTime.Now - x.LastUpdateTime).Milliseconds > 300)
+ .ToArray();
+
+ foreach (var item in items)
+ {
+ item.RefCounter = 0;
+ container.Remove(item.Handle);
+ switch (item.ItemType)
+ {
+ case GCItemType.TensorHandle:
+ c_api.TF_DeleteTensor(item.Handle);
+ break;
+ case GCItemType.LocalTensorHandle:
+ c_api.TFE_DeleteTensorHandle(item.Handle);
+ break;
+ case GCItemType.EagerTensorHandle:
+ c_api.TFE_DeleteEagerTensor(item.Handle);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ timer.Start();
+ }
+ }
+}
diff --git a/src/TensorFlowNET.Core/TensorFlow.Binding.csproj b/src/TensorFlowNET.Core/TensorFlow.Binding.csproj
index ae6548a9..e462fded 100644
--- a/src/TensorFlowNET.Core/TensorFlow.Binding.csproj
+++ b/src/TensorFlowNET.Core/TensorFlow.Binding.csproj
@@ -62,6 +62,7 @@ Please be patient, we're working hard on missing functions, providing full tenso
+
True
diff --git a/src/TensorFlowNET.Core/Tensors/EagerTensorV2.cs b/src/TensorFlowNET.Core/Tensors/EagerTensorV2.cs
index 83d23255..9f1d1929 100644
--- a/src/TensorFlowNET.Core/Tensors/EagerTensorV2.cs
+++ b/src/TensorFlowNET.Core/Tensors/EagerTensorV2.cs
@@ -21,7 +21,7 @@ namespace Tensorflow
public EagerTensorV2(IntPtr handle)
{
EagerTensorHandle = handle;
- tfe_tensor_handle = c_api.EagerTensor_Handle(handle);
+ tfe_tensor_handle = c_api.TFE_EagerTensorHandle(handle);
_handle = c_api.TFE_TensorHandleResolve(tfe_tensor_handle, status);
}
@@ -43,7 +43,7 @@ namespace Tensorflow
}, IntPtr.Zero);
tfe_tensor_handle = c_api.TFE_NewTensorHandle(_handle, status);
- EagerTensorHandle = c_api.TFE_EagerTensorFromHandle(tf.context, tfe_tensor_handle);
+ EagerTensorHandle = c_api.TFE_NewEagerTensor();
}
/*public unsafe EagerTensorV2(float[,] value)
diff --git a/src/TensorFlowNET.Core/Tensors/TF_BindingArray.cs b/src/TensorFlowNET.Core/Tensors/TF_BindingArray.cs
new file mode 100644
index 00000000..2999dc86
--- /dev/null
+++ b/src/TensorFlowNET.Core/Tensors/TF_BindingArray.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Tensorflow
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TF_BindingArray
+ {
+ public IntPtr array;
+ public int length;
+
+ public static implicit operator TF_BindingArray(IntPtr handle)
+ => handle == IntPtr.Zero ? default : Marshal.PtrToStructure(handle);
+
+ public unsafe IntPtr this[int index]
+ => array == IntPtr.Zero ? IntPtr.Zero : *((IntPtr*)array + index);
+
+ public unsafe IntPtr[] Data
+ {
+ get
+ {
+ var results = new IntPtr[length];
+ for (int i = 0; i < length; i++)
+ results[i] = array == IntPtr.Zero ? IntPtr.Zero : *((IntPtr*)array + i);
+ return results;
+ }
+ }
+ }
+}
diff --git a/src/TensorFlowNET.Core/Tensors/Tensor.cs b/src/TensorFlowNET.Core/Tensors/Tensor.cs
index c11e2e6c..89fb00d1 100644
--- a/src/TensorFlowNET.Core/Tensors/Tensor.cs
+++ b/src/TensorFlowNET.Core/Tensors/Tensor.cs
@@ -171,7 +171,7 @@ namespace Tensorflow
/// n n-Tensor (you get the idea)
///
/// https://www.tensorflow.org/api_docs/python/tf/rank
- public int rank
+ public virtual int rank
{
get
{
diff --git a/src/TensorFlowNET.Core/Training/gen_training_ops.py.cs b/src/TensorFlowNET.Core/Training/gen_training_ops.py.cs
index 40ba3584..e9d4e854 100644
--- a/src/TensorFlowNET.Core/Training/gen_training_ops.py.cs
+++ b/src/TensorFlowNET.Core/Training/gen_training_ops.py.cs
@@ -15,6 +15,7 @@
******************************************************************************/
using System;
+using System.Linq;
using Tensorflow.Eager;
using static Tensorflow.Binding;
@@ -64,18 +65,18 @@ namespace Tensorflow
{
if (tf.context.executing_eagerly())
{
- using var status = new Status();
- BindingArray results = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
+ var results = new[] { new EagerTensor() };
+ Status status = c_api.TFE_FastPathExecute(tf.context, tf.context.device_name,
"ResourceApplyGradientDescent", name, new IntPtr[]
{
var,
alpha,
delta
}, 3,
- op => wrap_tfe_src.SetOpAttrs(op, "use_locking", use_locking),
- status);
+ op => wrap_tfe_src.SetOpAttrs(op, "use_locking", use_locking),
+ results.Select(x => x.EagerTensorHandle).ToArray(), results.Length);
status.Check(true);
- return results[0];
+ return results[0].Resolve();
}
var _op = _op_def_lib._apply_op_helper("ResourceApplyGradientDescent", name, new
diff --git a/src/TensorFlowNET.Core/Util/BindingArray.cs b/src/TensorFlowNET.Core/Util/BindingArray.cs
index 984e6642..788d389d 100644
--- a/src/TensorFlowNET.Core/Util/BindingArray.cs
+++ b/src/TensorFlowNET.Core/Util/BindingArray.cs
@@ -19,24 +19,32 @@ using System.Runtime.InteropServices;
namespace Tensorflow
{
- [StructLayout(LayoutKind.Sequential)]
- public struct BindingArray
+ public class BindingArray : DisposableObject
{
- public IntPtr array;
- public int length;
+ TF_BindingArray data;
+ public IntPtr Address => data.array;
+ public int Length => data.length;
+
+ public BindingArray(IntPtr handle) : base(handle)
+ {
+ if (_handle != IntPtr.Zero)
+ data = Marshal.PtrToStructure(_handle);
+ else
+ data = default;
+ }
public static implicit operator BindingArray(IntPtr handle)
- => handle == IntPtr.Zero ? default : Marshal.PtrToStructure(handle);
+ => new BindingArray(handle);
public unsafe IntPtr this[int index]
- => array == IntPtr.Zero ? IntPtr.Zero : * ((IntPtr*)array + index);
+ => data[index];
+
+ public unsafe IntPtr[] Data
+ => data.Data;
- public unsafe IntPtr[] Data()
+ protected override void DisposeUnmanagedResources(IntPtr handle)
{
- var results = new IntPtr[length];
- for (int i = 0; i < length; i++)
- results[i] = array == IntPtr.Zero ? IntPtr.Zero : * ((IntPtr*)array + i);
- return results;
+ c_api.TF_DeleteBindingArray(_handle);
}
}
}
diff --git a/src/TensorFlowNET.Core/Util/BindingTensorArray.cs b/src/TensorFlowNET.Core/Util/BindingTensorArray.cs
new file mode 100644
index 00000000..c3862d97
--- /dev/null
+++ b/src/TensorFlowNET.Core/Util/BindingTensorArray.cs
@@ -0,0 +1,50 @@
+/*****************************************************************************
+ Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+******************************************************************************/
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Tensorflow
+{
+ public class BindingTensorArray : DisposableObject
+ {
+ TF_BindingArray data;
+ public IntPtr Address => data.array;
+ public int Length => data.length;
+
+ public BindingTensorArray(IntPtr handle) : base(handle)
+ {
+ if (_handle != IntPtr.Zero)
+ data = Marshal.PtrToStructure(_handle);
+ else
+ data = default;
+ }
+
+ public static implicit operator BindingTensorArray(IntPtr handle)
+ => new BindingTensorArray(handle);
+
+ public unsafe IntPtr this[int index]
+ => data[index];
+
+ public unsafe IntPtr[] Data
+ => data.Data;
+
+ protected override void DisposeUnmanagedResources(IntPtr handle)
+ {
+ c_api.TFE_DeleteBindingTensorArray(_handle);
+ }
+ }
+}
diff --git a/src/TensorFlowNET.Core/tensorflow.cs b/src/TensorFlowNET.Core/tensorflow.cs
index 942388aa..1acf07ba 100644
--- a/src/TensorFlowNET.Core/tensorflow.cs
+++ b/src/TensorFlowNET.Core/tensorflow.cs
@@ -14,11 +14,14 @@
limitations under the License.
******************************************************************************/
+using NumSharp.Utilities;
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using Tensorflow.Eager;
+using static Tensorflow.Binding;
namespace Tensorflow
{
@@ -38,7 +41,6 @@ namespace Tensorflow
public Context context = new Context(new ContextOptions(), new Status());
-
public tensorflow()
{
_constructThreadingObjects();
@@ -53,20 +55,20 @@ namespace Tensorflow
return ones.EagerTensorHandle;
}, (gradients) =>
{
- var input_grads = gradients.Data().Select(x => new EagerTensor(x)).ToArray();
+ var input_grads = gradients.Data.Select(x => new EagerTensor(x)).ToArray();
var add_n = gen_math_ops.add_n(input_grads) as EagerTensor;
return add_n.EagerTensorHandle;
});
ops.RegisterFromAssembly();
+ // ops.RegisterFromAssemblyEager();
+
c_api.TFE_RegisterGradientFunction((op_name, op_inputs, op_outputs, num_attrs, output_grads, skip_input_indices) =>
{
- var input_tensors = op_inputs.Data().Select(x => new EagerTensor(x)).ToArray();
- var output_tensors = op_outputs.Data().Select(x => new EagerTensor(x)).ToArray();
- var output_grad_tensors = output_grads.Data().Select(x => new EagerTensor(x)).ToArray();
- var skip_input_indices_param = new int[skip_input_indices.length];
- for (int i = 0; i < skip_input_indices.length; i++)
- skip_input_indices_param[i] = *((int*)skip_input_indices.array + i);
+ var input_tensors = new BindingTensorArray(op_inputs).Data.Select(x => new EagerTensor(x)).ToArray();
+ var output_tensors = new BindingTensorArray(op_outputs).Data.Select(x => new EagerTensor(x)).ToArray();
+ var output_grad_tensors = new BindingTensorArray(output_grads).Data.Select(x => new EagerTensor(x)).ToArray();
+ var skip_input_indices_param = new BindingArray(skip_input_indices).Data.Select(x => *(int*)x).ToArray();
var gradients = ops.gradientFunctions[op_name](new EagerOperation
{
diff --git a/test/TensorFlowNET.UnitTest/NativeAPI/Eager/GradientEagerTest.cs b/test/TensorFlowNET.UnitTest/NativeAPI/Eager/GradientEagerTest.cs
index a46ab669..edd1a438 100644
--- a/test/TensorFlowNET.UnitTest/NativeAPI/Eager/GradientEagerTest.cs
+++ b/test/TensorFlowNET.UnitTest/NativeAPI/Eager/GradientEagerTest.cs
@@ -10,7 +10,6 @@ namespace TensorFlowNET.UnitTest.Gradient
[TestClass]
public class GradientEagerTest : PythonTest
{
- [Ignore]
[TestMethod]
public void ConstantSq()
{