From bd04f5bad240ba7e4e0d7aadb543091ff6f2e290 Mon Sep 17 00:00:00 2001 From: Oceania2018 Date: Sat, 18 May 2019 22:33:27 -0500 Subject: [PATCH] run_bottleneck_on_image.resized_input_values --- TensorFlow.NET.sln | 6 +- .../Sessions/BaseSession.cs | 7 +- .../Tensors/Tensor.Creation.cs | 29 +++---- src/TensorFlowNET.Core/Tensors/Tensor.cs | 2 + src/TensorFlowNET.Core/tf.cs | 1 + .../ImageProcess/RetrainImageClassifier.cs | 81 ++++++++++++++++++- 6 files changed, 99 insertions(+), 27 deletions(-) diff --git a/TensorFlow.NET.sln b/TensorFlow.NET.sln index 12b93519..7982345e 100644 --- a/TensorFlow.NET.sln +++ b/TensorFlow.NET.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.168 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28803.452 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TensorFlowNET.UnitTest", "test\TensorFlowNET.UnitTest\TensorFlowNET.UnitTest.csproj", "{029A8CF1-CF95-4DCB-98AA-9D3D96A83B3E}" EndProject @@ -11,7 +11,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TensorFlowNET.Core", "src\T EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Keras.Core", "src\KerasNET.Core\Keras.Core.csproj", "{902E188F-A953-43B4-9991-72BAB1697BC3}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Keras.Example", "test\KerasNET.Example\Keras.Example.csproj", "{17E1AC16-9E0E-4545-905A-E92C6300C7AF}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Keras.Example", "test\KerasNET.Example\Keras.Example.csproj", "{17E1AC16-9E0E-4545-905A-E92C6300C7AF}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Keras.UnitTest", "test\KerasNET.Test\Keras.UnitTest.csproj", "{A5839A45-A117-4BEA-898B-DE1ED6E0D58F}" EndProject diff --git a/src/TensorFlowNET.Core/Sessions/BaseSession.cs b/src/TensorFlowNET.Core/Sessions/BaseSession.cs index 4e67c7ae..771b0d7d 100644 --- a/src/TensorFlowNET.Core/Sessions/BaseSession.cs +++ b/src/TensorFlowNET.Core/Sessions/BaseSession.cs @@ -99,6 +99,9 @@ namespace Tensorflow feed_dict_tensor[subfeed_t] = (NDArray)val; break; case byte[] val: + feed_dict_tensor[subfeed_t] = np.array(val); + break; + case char[] val: feed_dict_tensor[subfeed_t] = (NDArray)val; break; case bool val: @@ -130,7 +133,7 @@ namespace Tensorflow // We only want to really perform the run if fetches or targets are provided, // or if the call is a partial run that specifies feeds. - var results = _do_run(final_targets.Select(x => (Operation)(object)x).ToList(), final_fetches, feed_dict_tensor); + var results = _do_run(final_targets.Select(x => (Operation)x).ToList(), final_fetches, feed_dict_tensor); return fetch_handler.build_results(this, results); } @@ -161,7 +164,7 @@ namespace Tensorflow case Tensor t1: return new KeyValuePair(tensor._as_tf_output(), t1); case NDArray nd: - return new KeyValuePair(tensor._as_tf_output(), new Tensor(nd)); + return new KeyValuePair(tensor._as_tf_output(), new Tensor(nd, tensor.dtype)); case int intVal: return new KeyValuePair(tensor._as_tf_output(), new Tensor(intVal)); case float floatVal: diff --git a/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs b/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs index 6ba5d3ca..eff138b5 100644 --- a/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs +++ b/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs @@ -20,9 +20,9 @@ namespace Tensorflow _handle = handle; } - public Tensor(NDArray nd) + public Tensor(NDArray nd, TF_DataType? tensorDType = null) { - _handle = Allocate(nd); + _handle = Allocate(nd, tensorDType: tensorDType); } public unsafe Tensor(byte[] buffer) @@ -38,8 +38,14 @@ namespace Tensorflow status.Check(true); } - private IntPtr Allocate(NDArray nd) + private IntPtr Allocate(NDArray nd, TF_DataType? tensorDType = null) { + if (tensorDType == TF_DataType.TF_STRING && + nd.dtype.Name == "Byte") + { + return new Tensor(nd.Data()); + } + IntPtr dotHandle = IntPtr.Zero; ulong size = 0; @@ -73,23 +79,6 @@ namespace Tensorflow break; case "Byte": Marshal.Copy(nd1.Data(), 0, dotHandle, nd.size); - /*var bb = nd.Data(); - var bytes = Marshal.AllocHGlobal(bb.Length); - Marshal.Copy(bb, 0, bytes, bb.Length); - ulong bytes_len = c_api.TF_StringEncodedSize((ulong)bb.Length); - var dataTypeByte = ToTFDataType(nd.dtype); - // shape - var dims2 = nd.shape.Select(x => (long)x).ToArray(); - - var tfHandle2 = c_api.TF_AllocateTensor(dataTypeByte, - dims2, - nd.ndim, - bytes_len + sizeof(Int64)); - - dotHandle = c_api.TF_TensorData(tfHandle2); - Marshal.WriteInt64(dotHandle, 0); - c_api.TF_StringEncode(bytes, (ulong)bb.Length, dotHandle + sizeof(Int64), bytes_len, status); - return tfHandle2;*/ break; //case "String": /*string ss = nd.Data()[0]; diff --git a/src/TensorFlowNET.Core/Tensors/Tensor.cs b/src/TensorFlowNET.Core/Tensors/Tensor.cs index 34b98b35..e5b9e786 100644 --- a/src/TensorFlowNET.Core/Tensors/Tensor.cs +++ b/src/TensorFlowNET.Core/Tensors/Tensor.cs @@ -187,6 +187,8 @@ namespace Tensorflow { switch (type.Name) { + case "Char": + return TF_DataType.TF_UINT8; case "Int16": return TF_DataType.TF_INT16; case "Int32": diff --git a/src/TensorFlowNET.Core/tf.cs b/src/TensorFlowNET.Core/tf.cs index 65551e7b..b4b97c90 100644 --- a/src/TensorFlowNET.Core/tf.cs +++ b/src/TensorFlowNET.Core/tf.cs @@ -8,6 +8,7 @@ namespace Tensorflow { public static partial class tf { + public static TF_DataType bytes = TF_DataType.TF_STRING; public static TF_DataType int16 = TF_DataType.TF_INT16; public static TF_DataType int32 = TF_DataType.TF_INT32; public static TF_DataType float16 = TF_DataType.TF_HALF; diff --git a/test/TensorFlowNET.Examples/ImageProcess/RetrainImageClassifier.cs b/test/TensorFlowNET.Examples/ImageProcess/RetrainImageClassifier.cs index 94c76754..f9a5bef9 100644 --- a/test/TensorFlowNET.Examples/ImageProcess/RetrainImageClassifier.cs +++ b/test/TensorFlowNET.Examples/ImageProcess/RetrainImageClassifier.cs @@ -1,4 +1,5 @@ -using System; +using NumSharp; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -105,7 +106,83 @@ namespace TensorFlowNET.Examples.ImageProcess Tensor bottleneck_tensor, string module_name) { var label_lists = image_lists[label_name]; - var sub_dir_path = Path.Join(image_dir, label_name); + var sub_dir_path = Path.Join(bottleneck_dir, label_name); + Directory.CreateDirectory(sub_dir_path); + string bottleneck_path = get_bottleneck_path(image_lists, label_name, index, + bottleneck_dir, category, module_name); + + if (!File.Exists(bottleneck_path)) + create_bottleneck_file(bottleneck_path, image_lists, label_name, index, + image_dir, category, sess, jpeg_data_tensor, + decoded_image_tensor, resized_input_tensor, + bottleneck_tensor); + } + + private void create_bottleneck_file(string bottleneck_path, Dictionary> image_lists, + string label_name, int index, string image_dir, string category, Session sess, + Tensor jpeg_data_tensor, Tensor decoded_image_tensor, Tensor resized_input_tensor, Tensor bottleneck_tensor) + { + // Create a single bottleneck file. + print("Creating bottleneck at " + bottleneck_path); + var image_path = get_image_path(image_lists, label_name, index, image_dir, category); + if (!File.Exists(image_path)) + print($"File does not exist {image_path}"); + + var image_data = File.ReadAllBytes(image_path); + var bottleneck_values = run_bottleneck_on_image( + sess, image_data, jpeg_data_tensor, decoded_image_tensor, + resized_input_tensor, bottleneck_tensor); + } + + /// + /// Runs inference on an image to extract the 'bottleneck' summary layer. + /// + /// Current active TensorFlow Session. + /// Path of raw JPEG data. + /// Input data layer in the graph. + /// Output of initial image resizing and preprocessing. + /// The input node of the recognition graph. + /// Layer before the final softmax. + /// + private NDArray run_bottleneck_on_image(Session sess, byte[] image_data, Tensor image_data_tensor, + Tensor decoded_image_tensor, Tensor resized_input_tensor, Tensor bottleneck_tensor) + { + // First decode the JPEG image, resize it, and rescale the pixel values. + var resized_input_values = sess.run(decoded_image_tensor, new FeedItem(image_data_tensor, image_data)); + // Then run it through the recognition network. + var bottleneck_values = sess.run(bottleneck_tensor, new FeedItem(resized_input_tensor, resized_input_values)); + bottleneck_values = np.squeeze(bottleneck_values); + return bottleneck_values; + } + + private string get_bottleneck_path(Dictionary> image_lists, string label_name, int index, + string bottleneck_dir, string category, string module_name) + { + module_name = (module_name.Replace("://", "~") // URL scheme. + .Replace('/', '~') // URL and Unix paths. + .Replace(':', '~').Replace('\\', '~')); // Windows paths. + return get_image_path(image_lists, label_name, index, bottleneck_dir, + category) + "_" + module_name + ".txt"; + } + + private string get_image_path(Dictionary> image_lists, string label_name, + int index, string image_dir, string category) + { + if (!image_lists.ContainsKey(label_name)) + print($"Label does not exist {label_name}"); + + var label_lists = image_lists[label_name]; + if (!label_lists.ContainsKey(category)) + print($"Category does not exist {category}"); + var category_list = label_lists[category]; + if (category_list.Length == 0) + print($"Label {label_name} has no images in the category {category}."); + + var mod_index = index % len(category_list); + var base_name = category_list[mod_index].Split(Path.DirectorySeparatorChar).Last(); + var sub_dir = label_name; + var full_path = Path.Join(image_dir, sub_dir, base_name); + return full_path; } public void PrepareData()