@@ -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(); | |||
} | |||
} | |||
} |
@@ -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"; | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
}; | |||
} | |||
} |
@@ -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(); | |||
@@ -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) | |||
{ | |||
@@ -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; } | |||
@@ -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); | |||
} | |||
} | |||
} |
@@ -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) | |||
@@ -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) | |||
@@ -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); | |||
} | |||
} |
@@ -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 | |||
@@ -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; | |||
} | |||
} | |||
} |
@@ -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); | |||
@@ -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); | |||
} | |||
} | |||
} |
@@ -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]; | |||
} | |||
} | |||
} |
@@ -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 }); | |||
@@ -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 | |||
@@ -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 }); | |||
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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", | |||
@@ -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 | |||
@@ -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); | |||
@@ -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}"; | |||
} | |||
} |
@@ -0,0 +1,13 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace Tensorflow | |||
{ | |||
public enum GCItemType | |||
{ | |||
TensorHandle = 0, | |||
LocalTensorHandle = 1, | |||
EagerTensorHandle = 2 | |||
} | |||
} |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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> | |||
@@ -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) | |||
@@ -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; | |||
} | |||
} | |||
} | |||
} |
@@ -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 | |||
{ | |||
@@ -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,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); | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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 | |||
{ | |||
@@ -10,7 +10,6 @@ namespace TensorFlowNET.UnitTest.Gradient | |||
[TestClass] | |||
public class GradientEagerTest : PythonTest | |||
{ | |||
[Ignore] | |||
[TestMethod] | |||
public void ConstantSq() | |||
{ | |||