| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 87f667c commit 7d0f38a
10 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -61,4 +61,4 @@ Star me or raise issue on [Github](https://github.com/SciSharp/TensorFlow.NET) f | |||
| 61 | 61 | ||
| 62 | 62 | Scan QR code to join TIM group: | |
| 63 | 63 | ||
| 64 | -  | ||
| 64 | +  | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,136 @@ | |||
| 1 | + # Chapter. Image Recognition | ||
| 2 | + | ||
| 3 | + An example for using the [TensorFlow.NET](https://github.com/SciSharp/TensorFlow.NET) and [NumSharp](https://github.com/SciSharp/NumSharp) for image recognition, it will use a pre-trained inception model to predict a image which outputs the categories sorted by probability. The original paper is [here](https://arxiv.org/pdf/1512.00567.pdf). The Inception architecture of GoogLeNet was designed to perform well even under strict constraints on memory and computational budget. The computational cost of Inception is also much lower than other performing successors. This has made it feasible to utilize Inception networks in big-data scenarios, where huge amount of data needed to be processed at reasonable cost or scenarios where memory or computational capacity is inherently limited, for example in mobile vision settings. | ||
| 4 | + | ||
| 5 | + The GoogLeNet architecture conforms to below design principles: | ||
| 6 | + | ||
| 7 | + * Avoid representational bottlenecks, especially early in the network. | ||
| 8 | + * Higher dimensional representations are easier to process locally within a network. | ||
| 9 | + * Spatial aggregation can be done over lower dimensional embeddings without much or any loss in representational power. | ||
| 10 | + * Balance the width and depth of the network. | ||
| 11 | + | ||
| 12 | + #### Let's get started with real code. | ||
| 13 | + | ||
| 14 | + ##### 1. Prepare data | ||
| 15 | + | ||
| 16 | + This example will download the dataset and uncompress it automatically. Some external paths are omitted, please refer to the source code for the real path. | ||
| 17 | + | ||
| 18 | + ```csharp | ||
| 19 | + private void PrepareData() | ||
| 20 | + { | ||
| 21 | + Directory.CreateDirectory(dir); | ||
| 22 | + | ||
| 23 | + // get model file | ||
| 24 | + string url = "models/inception_v3_2016_08_28_frozen.pb.tar.gz"; | ||
| 25 | + | ||
| 26 | + string zipFile = Path.Join(dir, $"{pbFile}.tar.gz"); | ||
| 27 | + Utility.Web.Download(url, zipFile); | ||
| 28 | + | ||
| 29 | + Utility.Compress.ExtractTGZ(zipFile, dir); | ||
| 30 | + | ||
| 31 | + // download sample picture | ||
| 32 | + string pic = "grace_hopper.jpg"; | ||
| 33 | + Utility.Web.Download($"data/{pic}", Path.Join(dir, pic)); | ||
| 34 | + } | ||
| 35 | + ``` | ||
| 36 | + | ||
| 37 | + ##### 2. Load image file and normalize | ||
| 38 | + | ||
| 39 | + We need to load a sample image to test our pre-trained inception model. Convert it into tensor and normalized the input image. The pre-trained model takes input in the form of a 4-dimensional tensor with shape [BATCH_SIZE, INPUT_HEIGHT, INPUT_WEIGHT, 3] where: | ||
| 40 | + | ||
| 41 | + - BATCH_SIZE allows for inference of multiple images in one pass through the graph | ||
| 42 | + - INPUT_HEIGHT is the height of the images on which the model was trained | ||
| 43 | + - INPUT_WEIGHT is the width of the images on which the model was trained | ||
| 44 | + - 3 is the (R, G, B) values of the pixel colors represented as a float. | ||
| 45 | + | ||
| 46 | + ```csharp | ||
| 47 | + private NDArray ReadTensorFromImageFile(string file_name, | ||
| 48 | + int input_height = 299, | ||
| 49 | + int input_width = 299, | ||
| 50 | + int input_mean = 0, | ||
| 51 | + int input_std = 255) | ||
| 52 | + { | ||
| 53 | + return with<Graph, NDArray>(tf.Graph().as_default(), graph => | ||
| 54 | + { | ||
| 55 | + var file_reader = tf.read_file(file_name, "file_reader"); | ||
| 56 | + var image_reader = tf.image.decode_jpeg(file_reader, channels: 3, name: "jpeg_reader"); | ||
| 57 | + var caster = tf.cast(image_reader, tf.float32); | ||
| 58 | + var dims_expander = tf.expand_dims(caster, 0); | ||
| 59 | + var resize = tf.constant(new int[] { input_height, input_width }); | ||
| 60 | + var bilinear = tf.image.resize_bilinear(dims_expander, resize); | ||
| 61 | + var sub = tf.subtract(bilinear, new float[] { input_mean }); | ||
| 62 | + var normalized = tf.divide(sub, new float[] { input_std }); | ||
| 63 | + | ||
| 64 | + return with<Session, NDArray>(tf.Session(graph), sess => sess.run(normalized)); | ||
| 65 | + }); | ||
| 66 | + } | ||
| 67 | + ``` | ||
| 68 | + | ||
| 69 | + ##### 3. Load pre-trained model and predict | ||
| 70 | + | ||
| 71 | + Load the pre-trained inception model which is saved as Google's protobuf file format. Construct a new graph then set input and output operations in a new session. After run the session, you will get a numpy-like ndarray which is provided by NumSharp. With NumSharp, you can easily perform various operations on multiple dimensional arrays in the .NET environment. | ||
| 72 | + | ||
| 73 | + ```csharp | ||
| 74 | + public void Run() | ||
| 75 | + { | ||
| 76 | + PrepareData(); | ||
| 77 | + | ||
| 78 | + var labels = File.ReadAllLines(Path.Join(dir, labelFile)); | ||
| 79 | + | ||
| 80 | + var nd = ReadTensorFromImageFile(Path.Join(dir, picFile), | ||
| 81 | + input_height: input_height, | ||
| 82 | + input_width: input_width, | ||
| 83 | + input_mean: input_mean, | ||
| 84 | + input_std: input_std); | ||
| 85 | + | ||
| 86 | + var graph = Graph.ImportFromPB(Path.Join(dir, pbFile)); | ||
| 87 | + var input_operation = graph.get_operation_by_name(input_name); | ||
| 88 | + var output_operation = graph.get_operation_by_name(output_name); | ||
| 89 | + | ||
| 90 | + var results = with<Session, NDArray>(tf.Session(graph), | ||
| 91 | + sess => sess.run(output_operation.outputs[0], | ||
| 92 | + new FeedItem(input_operation.outputs[0], nd))); | ||
| 93 | + | ||
| 94 | + results = np.squeeze(results); | ||
| 95 | + | ||
| 96 | + var argsort = results.argsort<float>(); | ||
| 97 | + var top_k = argsort.Data<float>() | ||
| 98 | + .Skip(results.size - 5) | ||
| 99 | + .Reverse() | ||
| 100 | + .ToArray(); | ||
| 101 | + | ||
| 102 | + foreach (float idx in top_k) | ||
| 103 | + Console.WriteLine($"{picFile}: {idx} {labels[(int)idx]}, {results[(int)idx]}"); | ||
| 104 | + } | ||
| 105 | + ``` | ||
| 106 | + | ||
| 107 | + ##### 4. Print the result | ||
| 108 | + | ||
| 109 | + The best probability is `military uniform` which is 0.8343058. It's the correct classification. | ||
| 110 | + | ||
| 111 | + ```powershell | ||
| 112 | + 2/18/2019 3:56:18 AM Starting InceptionArchGoogLeNet | ||
| 113 | + label_image_data\inception_v3_2016_08_28_frozen.pb.tar.gz already exists. | ||
| 114 | + label_image_data\grace_hopper.jpg already exists. | ||
| 115 | + 2019-02-19 21:56:18.684463: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 | ||
| 116 | + create_op: Const 'file_reader/filename', inputs: empty, control_inputs: empty, outputs: file_reader/filename:0 | ||
| 117 | + create_op: ReadFile 'file_reader', inputs: file_reader/filename:0, control_inputs: empty, outputs: file_reader:0 | ||
| 118 | + create_op: DecodeJpeg 'jpeg_reader', inputs: file_reader:0, control_inputs: empty, outputs: jpeg_reader:0 | ||
| 119 | + create_op: Cast 'Cast/Cast', inputs: jpeg_reader:0, control_inputs: empty, outputs: Cast/Cast:0 | ||
| 120 | + create_op: Const 'ExpandDims/dim', inputs: empty, control_inputs: empty, outputs: ExpandDims/dim:0 | ||
| 121 | + create_op: ExpandDims 'ExpandDims', inputs: Cast/Cast:0, ExpandDims/dim:0, control_inputs: empty, outputs: ExpandDims:0 | ||
| 122 | + create_op: Const 'Const', inputs: empty, control_inputs: empty, outputs: Const:0 | ||
| 123 | + create_op: ResizeBilinear 'ResizeBilinear', inputs: ExpandDims:0, Const:0, control_inputs: empty, outputs: ResizeBilinear:0 | ||
| 124 | + create_op: Const 'y', inputs: empty, control_inputs: empty, outputs: y:0 | ||
| 125 | + create_op: Sub 'Sub', inputs: ResizeBilinear:0, y:0, control_inputs: empty, outputs: Sub:0 | ||
| 126 | + create_op: Const 'y_1', inputs: empty, control_inputs: empty, outputs: y_1:0 | ||
| 127 | + create_op: RealDiv 'truediv', inputs: Sub:0, y_1:0, control_inputs: empty, outputs: truediv:0 | ||
| 128 | + grace_hopper.jpg: 653 military uniform, 0.8343058 | ||
| 129 | + grace_hopper.jpg: 668 mortarboard, 0.02186947 | ||
| 130 | + grace_hopper.jpg: 401 academic gown, 0.01035806 | ||
| 131 | + grace_hopper.jpg: 716 pickelhaube, 0.008008132 | ||
| 132 | + grace_hopper.jpg: 466 bulletproof vest, 0.005350832 | ||
| 133 | + 2/18/2019 3:56:25 AM Completed InceptionArchGoogLeNet | ||
| 134 | + ``` | ||
| 135 | + | ||
| 136 | + You can find the full source code from [github](https://github.com/SciSharp/TensorFlow.NET/tree/master/test/TensorFlowNET.Examples). | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -14,7 +14,31 @@ | |||
| 14 | 14 | ||
| 15 | 15 | ##### 2. Hello World | |
| 16 | 16 | ||
| 17 | + | ||
| 18 | + | ||
| 17 | 19 | ## Part II. Tensorflow.NET in Depth | |
| 18 | 20 | ||
| 21 | + ##### 1. Control Dependency ...................................................................................................... | ||
| 22 | + | ||
| 23 | + ##### 2. Graph .................................... | ||
| 24 | + | ||
| 25 | + ##### 3. Session ............................ | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 19 | 29 | ## Part III. Dealing with Human Language | |
| 20 | 30 | ||
| 31 | + ##### 1. Text Classification ............................................................................................ | ||
| 32 | + | ||
| 33 | + ##### 2. Named Entity Recognition .............................................................................. | ||
| 34 | + | ||
| 35 | + ##### 3. Sentiment Analyze ........................................................................................... | ||
| 36 | + | ||
| 37 | + ##### 4. Sentence Dependency ........................................................................ | ||
| 38 | + | ||
| 39 | + | ||
| 40 | + | ||
| 41 | + ## Part IV. Image Recognition | ||
| 42 | + | ||
| 43 | + ##### 1. Inception Model ................................................................................................................. 100 | ||
| 44 | + | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -27,4 +27,5 @@ Welcome to TensorFlow.NET's documentation! | |||
| 27 | 27 | ControlDependency | |
| 28 | 28 | Gradient | |
| 29 | 29 | Train | |
| 30 | - EagerMode | ||
| 30 | + EagerMode | ||
| 31 | + ImageRecognition | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -34,5 +34,13 @@ public Status Import(string file_path) | |||
| 34 | 34 | c_api.TF_GraphImportGraphDef(_handle, graph_def, opts, Status); | |
| 35 | 35 | return Status; | |
| 36 | 36 | } | |
| 37 | + | ||
| 38 | + public static Graph ImportFromPB(string file_path) | ||
| 39 | + { | ||
| 40 | + var graph = tf.Graph().as_default(); | ||
| 41 | + var graph_def = GraphDef.Parser.ParseFrom(File.ReadAllBytes(file_path)); | ||
| 42 | + importer.import_graph_def(graph_def); | ||
| 43 | + return graph; | ||
| 44 | + } | ||
| 37 | 45 | } | |
| 38 | 46 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -70,6 +70,9 @@ private NDArray _run(object fetches, FeedItem[] feed_dict = null) | |||
| 70 | 70 | case float floatVal: | |
| 71 | 71 | feed_dict_tensor[subfeed_t] = (NDArray)floatVal; | |
| 72 | 72 | break; | |
| 73 | + case double doubleVal: | ||
| 74 | + feed_dict_tensor[subfeed_t] = (NDArray)doubleVal; | ||
| 75 | + break; | ||
| 73 | 76 | case int intVal: | |
| 74 | 77 | feed_dict_tensor[subfeed_t] = (NDArray)intVal; | |
| 75 | 78 | break; | |
@@ -80,6 +83,7 @@ private NDArray _run(object fetches, FeedItem[] feed_dict = null) | |||
| 80 | 83 | feed_dict_tensor[subfeed_t] = (NDArray)bytes; | |
| 81 | 84 | break; | |
| 82 | 85 | default: | |
| 86 | + Console.WriteLine($"can't handle data type of subfeed_val"); | ||
| 83 | 87 | throw new NotImplementedException("_run subfeed"); | |
| 84 | 88 | } | |
| 85 | 89 | feed_map[subfeed_t.name] = (subfeed_t, subfeed_val); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -17,9 +17,8 @@ | |||
| 17 | 17 | <Description>Google's TensorFlow binding in .NET Standard. | |
| 18 | 18 | Docs: https://tensorflownet.readthedocs.io</Description> | |
| 19 | 19 | <AssemblyVersion>0.3.0.0</AssemblyVersion> | |
| 20 | - <PackageReleaseNotes>Added a bunch of APIs. | ||
| 21 | - Fixed String tensor creation bug. | ||
| 22 | - Upgraded to TensorFlow 1.13 RC-1. | ||
| 20 | + <PackageReleaseNotes>Added image prediction example. | ||
| 21 | + Upgraded to TensorFlow 1.13 RC2. | ||
| 23 | 22 | </PackageReleaseNotes> | |
| 24 | 23 | <LangVersion>7.2</LangVersion> | |
| 25 | 24 | <FileVersion>0.3.0.0</FileVersion> | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -14,9 +14,10 @@ | |||
| 14 | 14 | namespace TensorFlowNET.Examples | |
| 15 | 15 | { | |
| 16 | 16 | /// <summary> | |
| 17 | + /// Inception Architecture for Computer Vision | ||
| 17 | 18 | /// Port from tensorflow\examples\label_image\label_image.py | |
| 18 | 19 | /// </summary> | |
| 19 | - public class LabelImage : Python, IExample | ||
| 20 | + public class InceptionArchGoogLeNet : Python, IExample | ||
| 20 | 21 | { | |
| 21 | 22 | string dir = "label_image_data"; | |
| 22 | 23 | string pbFile = "inception_v3_2016_08_28_frozen.pb"; | |
@@ -33,15 +34,15 @@ public void Run() | |||
| 33 | 34 | { | |
| 34 | 35 | PrepareData(); | |
| 35 | 36 | ||
| 36 | - var labels = LoadLabels(Path.Join(dir, labelFile)); | ||
| 37 | + var labels = File.ReadAllLines(Path.Join(dir, labelFile)); | ||
| 37 | 38 | ||
| 38 | 39 | var nd = ReadTensorFromImageFile(Path.Join(dir, picFile), | |
| 39 | 40 | input_height: input_height, | |
| 40 | 41 | input_width: input_width, | |
| 41 | 42 | input_mean: input_mean, | |
| 42 | 43 | input_std: input_std); | |
| 43 | 44 | ||
| 44 | - var graph = LoadGraph(Path.Join(dir, pbFile)); | ||
| 45 | + var graph = Graph.ImportFromPB(Path.Join(dir, pbFile)); | ||
| 45 | 46 | var input_operation = graph.get_operation_by_name(input_name); | |
| 46 | 47 | var output_operation = graph.get_operation_by_name(output_name); | |
| 47 | 48 | ||
@@ -61,19 +62,6 @@ public void Run() | |||
| 61 | 62 | Console.WriteLine($"{picFile}: {idx} {labels[(int)idx]}, {results[(int)idx]}"); | |
| 62 | 63 | } | |
| 63 | 64 | ||
| 64 | - private string[] LoadLabels(string file) | ||
| 65 | - { | ||
| 66 | - return File.ReadAllLines(file); | ||
| 67 | - } | ||
| 68 | - | ||
| 69 | - private Graph LoadGraph(string modelFile) | ||
| 70 | - { | ||
| 71 | - var graph = tf.Graph().as_default(); | ||
| 72 | - var graph_def = GraphDef.Parser.ParseFrom(File.ReadAllBytes(modelFile)); | ||
| 73 | - tf.import_graph_def(graph_def); | ||
| 74 | - return graph; | ||
| 75 | - } | ||
| 76 | - | ||
| 77 | 65 | private NDArray ReadTensorFromImageFile(string file_name, | |
| 78 | 66 | int input_height = 299, | |
| 79 | 67 | int input_width = 299, | |
@@ -97,7 +85,6 @@ private NDArray ReadTensorFromImageFile(string file_name, | |||
| 97 | 85 | ||
| 98 | 86 | private void PrepareData() | |
| 99 | 87 | { | |
| 100 | - | ||
| 101 | 88 | Directory.CreateDirectory(dir); | |
| 102 | 89 | ||
| 103 | 90 | // get model file | |
| Back | FazBrowse Home | New Git URL |
0 commit comments