Skip to content

Commit 7d0f38a

Browse files
committed
Update document
1 parent 87f667c commit 7d0f38a

10 files changed

Lines changed: 181 additions & 22 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,4 @@ Star me or raise issue on [Github](https://github.com/SciSharp/TensorFlow.NET) f
6161

6262
Scan QR code to join TIM group:
6363

64-
![SciSharp STACK](docs/TIM.png)
64+
![SciSharp STACK](docs/TIM.jpg)

docs/TIM.jpg

64.9 KB
Loading

docs/TIM.png

-14.8 KB
Binary file not shown.

docs/source/ImageRecognition.md

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff 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).

docs/source/Table of Contents.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,31 @@
1414

1515
##### 2. Hello World
1616

17+
18+
1719
## Part II. Tensorflow.NET in Depth
1820

21+
##### 1. Control Dependency ......................................................................................................
22+
23+
##### 2. Graph ....................................
24+
25+
##### 3. Session ............................
26+
27+
28+
1929
## Part III. Dealing with Human Language
2030

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+

docs/source/index.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,5 @@ Welcome to TensorFlow.NET's documentation!
2727
ControlDependency
2828
Gradient
2929
Train
30-
EagerMode
30+
EagerMode
31+
ImageRecognition

src/TensorFlowNET.Core/Graphs/Graph.Import.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,13 @@ public Status Import(string file_path)
3434
c_api.TF_GraphImportGraphDef(_handle, graph_def, opts, Status);
3535
return Status;
3636
}
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+
}
3745
}
3846
}

src/TensorFlowNET.Core/Sessions/BaseSession.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ private NDArray _run(object fetches, FeedItem[] feed_dict = null)
7070
case float floatVal:
7171
feed_dict_tensor[subfeed_t] = (NDArray)floatVal;
7272
break;
73+
case double doubleVal:
74+
feed_dict_tensor[subfeed_t] = (NDArray)doubleVal;
75+
break;
7376
case int intVal:
7477
feed_dict_tensor[subfeed_t] = (NDArray)intVal;
7578
break;
@@ -80,6 +83,7 @@ private NDArray _run(object fetches, FeedItem[] feed_dict = null)
8083
feed_dict_tensor[subfeed_t] = (NDArray)bytes;
8184
break;
8285
default:
86+
Console.WriteLine($"can't handle data type of subfeed_val");
8387
throw new NotImplementedException("_run subfeed");
8488
}
8589
feed_map[subfeed_t.name] = (subfeed_t, subfeed_val);

src/TensorFlowNET.Core/TensorFlowNET.Core.csproj

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@
1717
<Description>Google's TensorFlow binding in .NET Standard.
1818
Docs: https://tensorflownet.readthedocs.io</Description>
1919
<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.
2322
</PackageReleaseNotes>
2423
<LangVersion>7.2</LangVersion>
2524
<FileVersion>0.3.0.0</FileVersion>

test/TensorFlowNET.Examples/LabelImage.cs renamed to test/TensorFlowNET.Examples/InceptionArchGoogLeNet.cs

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@
1414
namespace TensorFlowNET.Examples
1515
{
1616
/// <summary>
17+
/// Inception Architecture for Computer Vision
1718
/// Port from tensorflow\examples\label_image\label_image.py
1819
/// </summary>
19-
public class LabelImage : Python, IExample
20+
public class InceptionArchGoogLeNet : Python, IExample
2021
{
2122
string dir = "label_image_data";
2223
string pbFile = "inception_v3_2016_08_28_frozen.pb";
@@ -33,15 +34,15 @@ public void Run()
3334
{
3435
PrepareData();
3536

36-
var labels = LoadLabels(Path.Join(dir, labelFile));
37+
var labels = File.ReadAllLines(Path.Join(dir, labelFile));
3738

3839
var nd = ReadTensorFromImageFile(Path.Join(dir, picFile),
3940
input_height: input_height,
4041
input_width: input_width,
4142
input_mean: input_mean,
4243
input_std: input_std);
4344

44-
var graph = LoadGraph(Path.Join(dir, pbFile));
45+
var graph = Graph.ImportFromPB(Path.Join(dir, pbFile));
4546
var input_operation = graph.get_operation_by_name(input_name);
4647
var output_operation = graph.get_operation_by_name(output_name);
4748

@@ -61,19 +62,6 @@ public void Run()
6162
Console.WriteLine($"{picFile}: {idx} {labels[(int)idx]}, {results[(int)idx]}");
6263
}
6364

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-
7765
private NDArray ReadTensorFromImageFile(string file_name,
7866
int input_height = 299,
7967
int input_width = 299,
@@ -97,7 +85,6 @@ private NDArray ReadTensorFromImageFile(string file_name,
9785

9886
private void PrepareData()
9987
{
100-
10188
Directory.CreateDirectory(dir);
10289

10390
// get model file

0 commit comments

Comments
 (0)