Browse Source

add a GarbageCollector to address cross-runtime GC issue.

tags/v0.20
Oceania2018 5 years ago
parent
commit
4a74d8d044
34 changed files with 960 additions and 324 deletions
  1. +0
    -42
      src/TensorFlowNET.Console/MemoryLeakTesting.cs
  2. +51
    -0
      src/TensorFlowNET.Console/MemoryMonitor.cs
  3. +55
    -0
      src/TensorFlowNET.Console/MemoryTestingCases.cs
  4. +17
    -4
      src/TensorFlowNET.Console/Program.cs
  5. +1
    -1
      src/TensorFlowNET.Core/APIs/c_api.cs
  6. +2
    -0
      src/TensorFlowNET.Core/Eager/EagerOperation.cs
  7. +41
    -22
      src/TensorFlowNET.Core/Eager/EagerTensor.Creation.cs
  8. +19
    -0
      src/TensorFlowNET.Core/Eager/EagerTensor.cs
  9. +4
    -5
      src/TensorFlowNET.Core/Eager/Execute.cs
  10. +42
    -21
      src/TensorFlowNET.Core/Eager/c_api.eager.cs
  11. +10
    -11
      src/TensorFlowNET.Core/Gradients/GradientTape.cs
  12. +30
    -0
      src/TensorFlowNET.Core/Gradients/RegisterGradientEager.cs
  13. +1
    -1
      src/TensorFlowNET.Core/Gradients/Tape.cs
  14. +74
    -0
      src/TensorFlowNET.Core/Gradients/math_grad_eager.cs
  15. +101
    -0
      src/TensorFlowNET.Core/Gradients/ops.gradient_function_mapping_eager.cs
  16. +11
    -8
      src/TensorFlowNET.Core/Operations/NnOps/gen_nn_ops.cs
  17. +43
    -37
      src/TensorFlowNET.Core/Operations/gen_array_ops.cs
  18. +150
    -115
      src/TensorFlowNET.Core/Operations/gen_math_ops.cs
  19. +26
    -0
      src/TensorFlowNET.Core/Operations/gen_math_ops.eager.cs
  20. +6
    -5
      src/TensorFlowNET.Core/Operations/gen_random_ops.cs
  21. +28
    -24
      src/TensorFlowNET.Core/Operations/gen_resource_variable_ops.cs
  22. +8
    -0
      src/TensorFlowNET.Core/Status/Status.cs
  23. +17
    -0
      src/TensorFlowNET.Core/System/GCItemCounter.cs
  24. +13
    -0
      src/TensorFlowNET.Core/System/GCItemType.cs
  25. +90
    -0
      src/TensorFlowNET.Core/System/GarbageCollector.cs
  26. +1
    -0
      src/TensorFlowNET.Core/TensorFlow.Binding.csproj
  27. +2
    -2
      src/TensorFlowNET.Core/Tensors/EagerTensorV2.cs
  28. +31
    -0
      src/TensorFlowNET.Core/Tensors/TF_BindingArray.cs
  29. +1
    -1
      src/TensorFlowNET.Core/Tensors/Tensor.cs
  30. +6
    -5
      src/TensorFlowNET.Core/Training/gen_training_ops.py.cs
  31. +19
    -11
      src/TensorFlowNET.Core/Util/BindingArray.cs
  32. +50
    -0
      src/TensorFlowNET.Core/Util/BindingTensorArray.cs
  33. +10
    -8
      src/TensorFlowNET.Core/tensorflow.cs
  34. +0
    -1
      test/TensorFlowNET.UnitTest/NativeAPI/Eager/GradientEagerTest.cs

+ 0
- 42
src/TensorFlowNET.Console/MemoryLeakTesting.cs View File

@@ -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);
}

/// <summary>
///
/// </summary>
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();
}
}
}

+ 51
- 0
src/TensorFlowNET.Console/MemoryMonitor.cs View File

@@ -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<int> 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";
}
}
}

+ 55
- 0
src/TensorFlowNET.Console/MemoryTestingCases.cs View File

@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Text;
using static Tensorflow.Binding;

namespace Tensorflow
{
class MemoryTestingCases
{
/// <summary>
///
/// </summary>
public Action<int> Constant
=> (iterate) =>
{
for (int i = 0; i < iterate; i++)
{
var tensor = tf.constant(3112.0f);
}
};
public Action<int> Variable
=> (iterate) =>
{
for (int i = 0; i < iterate; i++)
{
var tensor = tf.Variable(3112.0f);
}
};

public Action<int> 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<int> 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);
}
};
}
}

+ 17
- 4
src/TensorFlowNET.Console/Program.cs View File

@@ -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();


+ 1
- 1
src/TensorFlowNET.Core/APIs/c_api.cs View File

@@ -43,7 +43,7 @@ namespace Tensorflow
/// </summary>
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)
{


+ 2
- 0
src/TensorFlowNET.Core/Eager/EagerOperation.cs View File

@@ -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; }



+ 41
- 22
src/TensorFlowNET.Core/Eager/EagerTensor.Creation.cs View File

@@ -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);
}
}
}

+ 19
- 0
src/TensorFlowNET.Core/Eager/EagerTensor.cs View File

@@ -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)


+ 4
- 5
src/TensorFlowNET.Core/Eager/Execute.cs View File

@@ -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)


+ 42
- 21
src/TensorFlowNET.Core/Eager/c_api.eager.cs View File

@@ -11,18 +11,28 @@ namespace Tensorflow
public static extern void TFE_RegisterGradientFunction(gradient_function_callback gradientFunctionCallback,
delete_backward_function_callback deleteBackwardFunctionCallback);

/// <summary>
///
/// </summary>
/// <param name="op_name"></param>
/// <param name="op_inputs"></param>
/// <param name="op_outputs"></param>
/// <param name="num_attrs"></param>
/// <param name="output_grads">previous node ouput</param>
/// <param name="skip_input_indices"></param>
/// <returns></returns>
[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);

/// <summary>
/// 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);

/// <summary>
/// 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
/// <param name="h">TFE_TensorHandle*</param>
[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);

/// <summary>
/// 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);
}
}

+ 10
- 11
src/TensorFlowNET.Core/Gradients/GradientTape.cs View File

@@ -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
/// </summary>
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


+ 30
- 0
src/TensorFlowNET.Core/Gradients/RegisterGradientEager.cs View File

@@ -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;
}
}
}

+ 1
- 1
src/TensorFlowNET.Core/Gradients/Tape.cs View File

@@ -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);


+ 74
- 0
src/TensorFlowNET.Core/Gradients/math_grad_eager.cs View File

@@ -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
{
/// <summary>
/// Gradients for operators defined in math_ops.py.
/// </summary>
[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);
}
}
}

+ 101
- 0
src/TensorFlowNET.Core/Gradients/ops.gradient_function_mapping_eager.cs View File

@@ -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<string, Func<EagerOperation, IntPtr[], EagerTensor[]>> gradientFunctionsEager = null;

public static void RegisterFromAssemblyEager()
{
if (gradientFunctionsEager == null)
{
gradientFunctionsEager = new Dictionary<string, Func<EagerOperation, IntPtr[], EagerTensor[]>>();

var gradGroups = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(x => x.GetCustomAttribute<RegisterGradientEager>() != null)
.ToArray();

foreach (var g in gradGroups)
{
var methods = g.GetMethods()
.Where(x => x.GetCustomAttribute<RegisterGradientEager>() != null)
.ToArray();

foreach (var m in methods)
{
RegisterGradientFunctionEager(m.GetCustomAttribute<RegisterGradientEager>().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<RegisterNoGradient>() != null)
.ToArray();

foreach (var m in methods)
RegisterNoGradientFunctionEager(m.GetCustomAttribute<RegisterNoGradient>().Name);
}
}
}

/// <summary>
/// Regiter new gradient function
/// </summary>
/// <param name="name">operation type</param>
/// <param name="func">function delegate</param>
public static void RegisterGradientFunctionEager(string name, Func<EagerOperation, IntPtr[], EagerTensor[]> func)
{
RegisterFromAssemblyEager();

gradientFunctionsEager[name] = func;
}

public static void RegisterNoGradientFunctionEager(string name)
{
RegisterFromAssemblyEager();

gradientFunctionsEager[name] = null;
}

public static Func<EagerOperation, IntPtr[], EagerTensor[]> 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];
}
}
}

+ 11
- 8
src/TensorFlowNET.Core/Operations/NnOps/gen_nn_ops.cs View File

@@ -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 });


+ 43
- 37
src/TensorFlowNET.Core/Operations/gen_array_ops.cs View File

@@ -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


+ 150
- 115
src/TensorFlowNET.Core/Operations/gen_math_ops.cs View File

@@ -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();
}

/// <summary>
/// Returns the index with the largest value across dimensions of a tensor.
/// </summary>
@@ -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 });


+ 26
- 0
src/TensorFlowNET.Core/Operations/gen_math_ops.eager.cs View File

@@ -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();
}
}
}

+ 6
- 5
src/TensorFlowNET.Core/Operations/gen_random_ops.cs View File

@@ -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",


+ 28
- 24
src/TensorFlowNET.Core/Operations/gen_resource_variable_ops.cs View File

@@ -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


+ 8
- 0
src/TensorFlowNET.Core/Status/Status.cs View File

@@ -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);



+ 17
- 0
src/TensorFlowNET.Core/System/GCItemCounter.cs View File

@@ -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}";
}
}

+ 13
- 0
src/TensorFlowNET.Core/System/GCItemType.cs View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Tensorflow
{
public enum GCItemType
{
TensorHandle = 0,
LocalTensorHandle = 1,
EagerTensorHandle = 2
}
}

+ 90
- 0
src/TensorFlowNET.Core/System/GarbageCollector.cs View File

@@ -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<IntPtr, GCItemCounter> container = new Dictionary<IntPtr, GCItemCounter>();
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();
}
}
}

+ 1
- 0
src/TensorFlowNET.Core/TensorFlow.Binding.csproj View File

@@ -62,6 +62,7 @@ Please be patient, we're working hard on missing functions, providing full tenso
<None Remove="Distribute\**" />
<None Remove="Models\**" />
<None Remove="runtimes\**" />
<Compile Remove="Util\BindingArray2.cs" />
<None Include="..\..\LICENSE">
<Pack>True</Pack>
<PackagePath></PackagePath>


+ 2
- 2
src/TensorFlowNET.Core/Tensors/EagerTensorV2.cs View File

@@ -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)


+ 31
- 0
src/TensorFlowNET.Core/Tensors/TF_BindingArray.cs View File

@@ -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<TF_BindingArray>(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;
}
}
}
}

+ 1
- 1
src/TensorFlowNET.Core/Tensors/Tensor.cs View File

@@ -171,7 +171,7 @@ namespace Tensorflow
/// n n-Tensor (you get the idea)
/// </summary>
/// <remarks>https://www.tensorflow.org/api_docs/python/tf/rank</remarks>
public int rank
public virtual int rank
{
get
{


+ 6
- 5
src/TensorFlowNET.Core/Training/gen_training_ops.py.cs View File

@@ -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


+ 19
- 11
src/TensorFlowNET.Core/Util/BindingArray.cs View File

@@ -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<TF_BindingArray>(_handle);
else
data = default;
}

public static implicit operator BindingArray(IntPtr handle)
=> handle == IntPtr.Zero ? default : Marshal.PtrToStructure<BindingArray>(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);
}
}
}

+ 50
- 0
src/TensorFlowNET.Core/Util/BindingTensorArray.cs View File

@@ -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<TF_BindingArray>(_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);
}
}
}

+ 10
- 8
src/TensorFlowNET.Core/tensorflow.cs View File

@@ -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
{


+ 0
- 1
test/TensorFlowNET.UnitTest/NativeAPI/Eager/GradientEagerTest.cs View File

@@ -10,7 +10,6 @@ namespace TensorFlowNET.UnitTest.Gradient
[TestClass]
public class GradientEagerTest : PythonTest
{
[Ignore]
[TestMethod]
public void ConstantSq()
{


Loading…
Cancel
Save