| @@ -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 | |||
| @@ -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<TF_Output, Tensor>(tensor._as_tf_output(), t1); | |||
| 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: | |||
| return new KeyValuePair<TF_Output, Tensor>(tensor._as_tf_output(), new Tensor(intVal)); | |||
| case float floatVal: | |||
| @@ -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<byte>()); | |||
| } | |||
| IntPtr dotHandle = IntPtr.Zero; | |||
| ulong size = 0; | |||
| @@ -73,23 +79,6 @@ namespace Tensorflow | |||
| break; | |||
| case "Byte": | |||
| 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; | |||
| //case "String": | |||
| /*string ss = nd.Data<string>()[0]; | |||
| @@ -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": | |||
| @@ -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; | |||
| @@ -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<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() | |||