| @@ -1,7 +1,7 @@ | |||||
| | | ||||
| Microsoft Visual Studio Solution File, Format Version 12.00 | 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 | MinimumVisualStudioVersion = 10.0.40219.1 | ||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TensorFlowNET.UnitTest", "test\TensorFlowNET.UnitTest\TensorFlowNET.UnitTest.csproj", "{029A8CF1-CF95-4DCB-98AA-9D3D96A83B3E}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TensorFlowNET.UnitTest", "test\TensorFlowNET.UnitTest\TensorFlowNET.UnitTest.csproj", "{029A8CF1-CF95-4DCB-98AA-9D3D96A83B3E}" | ||||
| EndProject | EndProject | ||||
| @@ -11,7 +11,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TensorFlowNET.Core", "src\T | |||||
| EndProject | EndProject | ||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Keras.Core", "src\KerasNET.Core\Keras.Core.csproj", "{902E188F-A953-43B4-9991-72BAB1697BC3}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Keras.Core", "src\KerasNET.Core\Keras.Core.csproj", "{902E188F-A953-43B4-9991-72BAB1697BC3}" | ||||
| EndProject | 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 | EndProject | ||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Keras.UnitTest", "test\KerasNET.Test\Keras.UnitTest.csproj", "{A5839A45-A117-4BEA-898B-DE1ED6E0D58F}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Keras.UnitTest", "test\KerasNET.Test\Keras.UnitTest.csproj", "{A5839A45-A117-4BEA-898B-DE1ED6E0D58F}" | ||||
| EndProject | EndProject | ||||
| @@ -99,6 +99,9 @@ namespace Tensorflow | |||||
| feed_dict_tensor[subfeed_t] = (NDArray)val; | feed_dict_tensor[subfeed_t] = (NDArray)val; | ||||
| break; | break; | ||||
| case byte[] val: | case byte[] val: | ||||
| feed_dict_tensor[subfeed_t] = np.array(val); | |||||
| break; | |||||
| case char[] val: | |||||
| feed_dict_tensor[subfeed_t] = (NDArray)val; | feed_dict_tensor[subfeed_t] = (NDArray)val; | ||||
| break; | break; | ||||
| case bool val: | case bool val: | ||||
| @@ -130,7 +133,7 @@ namespace Tensorflow | |||||
| // We only want to really perform the run if fetches or targets are provided, | // 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. | // 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); | return fetch_handler.build_results(this, results); | ||||
| } | } | ||||
| @@ -161,7 +164,7 @@ namespace Tensorflow | |||||
| case Tensor t1: | case Tensor t1: | ||||
| return new KeyValuePair<TF_Output, Tensor>(tensor._as_tf_output(), t1); | return new KeyValuePair<TF_Output, Tensor>(tensor._as_tf_output(), t1); | ||||
| case NDArray nd: | case NDArray nd: | ||||
| return new KeyValuePair<TF_Output, Tensor>(tensor._as_tf_output(), new Tensor(nd)); | |||||
| return new KeyValuePair<TF_Output, Tensor>(tensor._as_tf_output(), new Tensor(nd, tensor.dtype)); | |||||
| case int intVal: | case int intVal: | ||||
| return new KeyValuePair<TF_Output, Tensor>(tensor._as_tf_output(), new Tensor(intVal)); | return new KeyValuePair<TF_Output, Tensor>(tensor._as_tf_output(), new Tensor(intVal)); | ||||
| case float floatVal: | case float floatVal: | ||||
| @@ -20,9 +20,9 @@ namespace Tensorflow | |||||
| _handle = handle; | _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) | public unsafe Tensor(byte[] buffer) | ||||
| @@ -38,8 +38,14 @@ namespace Tensorflow | |||||
| status.Check(true); | 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<byte>()); | |||||
| } | |||||
| IntPtr dotHandle = IntPtr.Zero; | IntPtr dotHandle = IntPtr.Zero; | ||||
| ulong size = 0; | ulong size = 0; | ||||
| @@ -73,23 +79,6 @@ namespace Tensorflow | |||||
| break; | break; | ||||
| case "Byte": | case "Byte": | ||||
| Marshal.Copy(nd1.Data<byte>(), 0, dotHandle, nd.size); | Marshal.Copy(nd1.Data<byte>(), 0, dotHandle, nd.size); | ||||
| /*var bb = nd.Data<byte>(); | |||||
| 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; | break; | ||||
| //case "String": | //case "String": | ||||
| /*string ss = nd.Data<string>()[0]; | /*string ss = nd.Data<string>()[0]; | ||||
| @@ -187,6 +187,8 @@ namespace Tensorflow | |||||
| { | { | ||||
| switch (type.Name) | switch (type.Name) | ||||
| { | { | ||||
| case "Char": | |||||
| return TF_DataType.TF_UINT8; | |||||
| case "Int16": | case "Int16": | ||||
| return TF_DataType.TF_INT16; | return TF_DataType.TF_INT16; | ||||
| case "Int32": | case "Int32": | ||||
| @@ -8,6 +8,7 @@ namespace Tensorflow | |||||
| { | { | ||||
| public static partial class tf | 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 int16 = TF_DataType.TF_INT16; | ||||
| public static TF_DataType int32 = TF_DataType.TF_INT32; | public static TF_DataType int32 = TF_DataType.TF_INT32; | ||||
| public static TF_DataType float16 = TF_DataType.TF_HALF; | public static TF_DataType float16 = TF_DataType.TF_HALF; | ||||
| @@ -1,4 +1,5 @@ | |||||
| using System; | |||||
| using NumSharp; | |||||
| using System; | |||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Diagnostics; | using System.Diagnostics; | ||||
| using System.IO; | using System.IO; | ||||
| @@ -105,7 +106,83 @@ namespace TensorFlowNET.Examples.ImageProcess | |||||
| Tensor bottleneck_tensor, string module_name) | Tensor bottleneck_tensor, string module_name) | ||||
| { | { | ||||
| var label_lists = image_lists[label_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<string, Dictionary<string, string[]>> 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); | |||||
| } | |||||
| /// <summary> | |||||
| /// Runs inference on an image to extract the 'bottleneck' summary layer. | |||||
| /// </summary> | |||||
| /// <param name="sess">Current active TensorFlow Session.</param> | |||||
| /// <param name="image_path">Path of raw JPEG data.</param> | |||||
| /// <param name="image_data_tensor">Input data layer in the graph.</param> | |||||
| /// <param name="decoded_image_tensor">Output of initial image resizing and preprocessing.</param> | |||||
| /// <param name="resized_input_tensor">The input node of the recognition graph.</param> | |||||
| /// <param name="bottleneck_tensor">Layer before the final softmax.</param> | |||||
| /// <returns></returns> | |||||
| 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<string, Dictionary<string, string[]>> 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<string, Dictionary<string, string[]>> 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() | public void PrepareData() | ||||