diff --git a/README.md b/README.md index 8130fbd7..15f72bf5 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![Badge](https://img.shields.io/badge/link-996.icu-red.svg)](https://996.icu/#/en_US) [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/javiercp/BinderTF.NET/master?urlpath=lab) -*master branch is based on tensorflow 2.1 now, v0.15-tensorflow1.15 is from tensorflow1.15.* +*master branch is based on tensorflow 2.2 now, v0.15-tensorflow1.15 is from tensorflow1.15.* TF.NET is a member project of [SciSharp STACK](https://github.com/SciSharp). @@ -28,7 +28,7 @@ In comparison to other projects, like for instance TensorFlowSharp which only pr ### How to use -| TensorFlow | tf 1.13 | tf 1.14 | tf 1.15 | tf 2.0 | +| TensorFlow | tf 1.13 | tf 1.14 | tf 1.15 | tf 2.2 | | ----------- | ------- | ------- | ------- | ------ | | tf.net 0.20 | | | x | x | | tf.net 0.15 | | x | x | | diff --git a/docs/assets/tf2.jpg b/docs/assets/tf2.jpg new file mode 100644 index 00000000..c4ebd31e Binary files /dev/null and b/docs/assets/tf2.jpg differ diff --git a/docs/assets/tf2.psd b/docs/assets/tf2.psd new file mode 100644 index 00000000..1cde3023 Binary files /dev/null and b/docs/assets/tf2.psd differ diff --git a/src/TensorFlowNET.Core/Eager/EagerTensor.cs b/src/TensorFlowNET.Core/Eager/EagerTensor.cs index 85cc731e..d7474e7d 100644 --- a/src/TensorFlowNET.Core/Eager/EagerTensor.cs +++ b/src/TensorFlowNET.Core/Eager/EagerTensor.cs @@ -13,31 +13,37 @@ namespace Tensorflow.Eager { tfe_tensor_handle = handle; _handle = c_api.TFE_TensorHandleResolve(handle, status); + _id = ops.uid(); } public EagerTensor(string value, string device_name) : base(value) { tfe_tensor_handle = c_api.TFE_NewTensorHandle(_handle, status); + _id = ops.uid(); } public EagerTensor(int value, string device_name) : base(value) { tfe_tensor_handle = c_api.TFE_NewTensorHandle(_handle, status); + _id = ops.uid(); } public EagerTensor(float[] value, string device_name) : base(value) { tfe_tensor_handle = c_api.TFE_NewTensorHandle(_handle, status); + _id = ops.uid(); } public EagerTensor(double[] value, string device_name) : base(value) { tfe_tensor_handle = c_api.TFE_NewTensorHandle(_handle, status); + _id = ops.uid(); } public EagerTensor(NDArray value, string device_name) : base(value) { tfe_tensor_handle = c_api.TFE_NewTensorHandle(_handle, status); + _id = ops.uid(); } public override string ToString() diff --git a/src/TensorFlowNET.Core/Eager/c_api.eager.cs b/src/TensorFlowNET.Core/Eager/c_api.eager.cs index bb75f153..4d9c2f32 100644 --- a/src/TensorFlowNET.Core/Eager/c_api.eager.cs +++ b/src/TensorFlowNET.Core/Eager/c_api.eager.cs @@ -102,14 +102,20 @@ namespace Tensorflow public static extern TFE_Op TFE_NewOp(IntPtr ctx, string op_or_function_name, IntPtr status); /// - /// + /// Resets `op_to_reset` with `op_or_function_name` and `raw_device_name`. This + /// is for performance optimization by reusing an exiting unused op rather than + /// creating a new op every time. If `raw_device_name` is `NULL` or empty, it + /// does not set the device name. If it's not `NULL`, then it attempts to parse + /// and set the device name. It's effectively `TFE_OpSetDevice`, but it is faster + /// than separately calling it because if the existing op has the same + /// `raw_device_name`, it skips parsing and just leave as it is. /// - /// TFE_Context* + /// TFE_Op* /// const char* + /// const char* /// TF_Status* - /// TFE_Op* [DllImport(TensorFlowLibName)] - public static extern void TFE_OpReset(IntPtr ctx, string op_or_function_name, IntPtr status, IntPtr op_to_reset); + public static extern void TFE_OpReset(IntPtr op_to_reset, string op_or_function_name, string raw_device_name, IntPtr status); /// /// @@ -304,5 +310,17 @@ namespace Tensorflow /// TFE_Executor* [DllImport(TensorFlowLibName)] public static extern TFE_Executor TFE_ContextGetExecutorForThread(IntPtr ctx); + + [DllImport(TensorFlowLibName)] + public static extern void TFE_Test(); + + [DllImport(TensorFlowLibName)] + public static extern IntPtr TFE_TapeSetNew(bool persistent, bool watch_accessed_variables); + + [DllImport(TensorFlowLibName)] + public static extern void TFE_TapeWatch(IntPtr tape, IntPtr tensor, int tensor_id); + + [DllImport(TensorFlowLibName)] + public static extern void TFE_TapeGradient(IntPtr tape, long[] targetTensorIds, IntPtr[] target, long[] sourcesTensorIds, IntPtr status); } } diff --git a/src/TensorFlowNET.Core/Eager/wrap_tfe_src..cs b/src/TensorFlowNET.Core/Eager/wrap_tfe_src..cs new file mode 100644 index 00000000..fd5810ee --- /dev/null +++ b/src/TensorFlowNET.Core/Eager/wrap_tfe_src..cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System.Linq; +using System; +using static Tensorflow.OpDef.Types; + +namespace Tensorflow.Eager +{ + /// + /// python\eager\pywrap_tfe_src.cc + /// + public partial class wrap_tfe_src + { + + } +} diff --git a/src/TensorFlowNET.Core/Eager/wrap_tfe_src.TFE_FastPathExecute.cs b/src/TensorFlowNET.Core/Eager/wrap_tfe_src.TFE_FastPathExecute.cs index 01302805..b9aaeab2 100644 --- a/src/TensorFlowNET.Core/Eager/wrap_tfe_src.TFE_FastPathExecute.cs +++ b/src/TensorFlowNET.Core/Eager/wrap_tfe_src.TFE_FastPathExecute.cs @@ -110,7 +110,7 @@ namespace Tensorflow.Eager var maybe_op = ReleaseThreadLocalOp(); if (maybe_op != IntPtr.Zero) { - c_api.TFE_OpReset(ctx, op_or_function_name, status, maybe_op); + c_api.TFE_OpReset(maybe_op, op_or_function_name, ctx.device_name, status); } else { diff --git a/src/TensorFlowNET.Core/Gradients/GradientActor.cs b/src/TensorFlowNET.Core/Gradients/GradientActor.cs index 7bc8ccde..f650aa9e 100644 --- a/src/TensorFlowNET.Core/Gradients/GradientActor.cs +++ b/src/TensorFlowNET.Core/Gradients/GradientActor.cs @@ -23,7 +23,6 @@ namespace Tensorflow.Gradients bool _watch_accessed_variables; bool _created_eagerly; Tape _tape; - int tape_nesting_id_counter = 0; public GradientActor(bool persistent = false, bool watch_accessed_variables = true) @@ -41,18 +40,28 @@ namespace Tensorflow.Gradients "re-enter an already-active tape."); if (_tape == null) - { - _tape = new Tape(); - _tape.tape = new GradientTape(_persistent, _watch_accessed_variables); - _tape.nesting_id = tape_nesting_id_counter++; - } + _tape = new Tape(_persistent, _watch_accessed_variables); + else + throw new NotImplementedException(""); _recording = true; } + /// + /// Marks this tensor to be watched by the given tape. + /// + /// public void watch(Tensor x) { + _tape.watch(x); + } + public Tensor gradient(Tensor target, Tensor sources) + { + c_api.TFE_Test(); + //using (var status = new Status()) + //c_api.TFE_TapeGradient(_tape, new long[] { target.Id }, status); + return null; } public void Dispose() diff --git a/src/TensorFlowNET.Core/Gradients/Tape.cs b/src/TensorFlowNET.Core/Gradients/Tape.cs index 852bdf28..a61898fe 100644 --- a/src/TensorFlowNET.Core/Gradients/Tape.cs +++ b/src/TensorFlowNET.Core/Gradients/Tape.cs @@ -4,11 +4,21 @@ using System.Text; namespace Tensorflow.Gradients { - public class Tape + public class Tape : DisposableObject { public GradientTape tape { get; set; } public int nesting_id { get; set; } + public Tape(bool persistent, bool watch_accessed_variables) + { + _handle = c_api.TFE_TapeSetNew(persistent, watch_accessed_variables); + } + + public void watch(Tensor x) + { + c_api.TFE_TapeWatch(_handle, x, x.Id); + } + public static bool IsDtypeTrainable(DataType dtype) { switch (dtype) @@ -26,5 +36,12 @@ namespace Tensorflow.Gradients return false; } } + + protected override void DisposeUnmanagedResources(IntPtr handle) + { + } + + public static implicit operator IntPtr(Tape tape) + => tape._handle; } } diff --git a/src/TensorFlowNET.Core/Tensors/Tensor.cs b/src/TensorFlowNET.Core/Tensors/Tensor.cs index 24af4ec9..c9703699 100644 --- a/src/TensorFlowNET.Core/Tensors/Tensor.cs +++ b/src/TensorFlowNET.Core/Tensors/Tensor.cs @@ -39,7 +39,7 @@ namespace Tensorflow IPackable, ICanBeFlattened { - private readonly int _id; + protected int _id; private readonly Operation _op; private readonly int _value_index; private TF_Output? _tf_output; diff --git a/src/TensorFlowNET.Core/Variables/ResourceVariable.Operators.cs b/src/TensorFlowNET.Core/Variables/ResourceVariable.Operators.cs index eddb97ea..d6eafbc1 100644 --- a/src/TensorFlowNET.Core/Variables/ResourceVariable.Operators.cs +++ b/src/TensorFlowNET.Core/Variables/ResourceVariable.Operators.cs @@ -30,6 +30,8 @@ namespace Tensorflow public static Tensor operator -(ResourceVariable x, double y) => op_helper("sub", x, y); public static Tensor operator -(ResourceVariable x, Tensor y) => op_helper("sub", x, y); + public static Tensor operator *(ResourceVariable x, ResourceVariable y) => gen_math_ops.mul(x, y); + public static Tensor operator <(ResourceVariable x, Tensor y) => gen_math_ops.less(x.value(), y); public static Tensor operator >(ResourceVariable x, Tensor y) => gen_math_ops.greater(x.value(), y); diff --git a/tensorflowlib/README.md b/tensorflowlib/README.md index fdc6953f..33f36a22 100644 --- a/tensorflowlib/README.md +++ b/tensorflowlib/README.md @@ -44,7 +44,9 @@ We can't found official prebuild binaries for each platform since tensorflow 2.0 https://www.tensorflow.org/install/source_windows -Download [Bazel 0.29.1](https://github.com/bazelbuild/bazel/releases/tag/0.29.1) to build tensorflow2.x. We build customized binary to export c_api from this [fork](https://github.com/SciSharp/tensorflow). +Download [Bazel 2.0.0](https://github.com/bazelbuild/bazel/releases/tag/2.0.0) to build tensorflow2.x. We build customized binary to export c_api from this [fork](https://github.com/SciSharp/tensorflow). + +Set ENV `BAZEL_VC=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC`. `pacman -S git patch unzip` diff --git a/test/TensorFlowNET.UnitTest/Tensorflow.UnitTest.csproj b/test/TensorFlowNET.UnitTest/Tensorflow.UnitTest.csproj index d269bcdc..0211b584 100644 --- a/test/TensorFlowNET.UnitTest/Tensorflow.UnitTest.csproj +++ b/test/TensorFlowNET.UnitTest/Tensorflow.UnitTest.csproj @@ -29,7 +29,7 @@ - +