forked from migueldeicaza/TensorFlowSharp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProgram.cs
More file actions
234 lines (199 loc) · 7.69 KB
/
Copy pathProgram.cs
File metadata and controls
234 lines (199 loc) · 7.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
// An example for using the TensorFlow C# API for image recognition
// using a pre-trained inception model (http://arxiv.org/abs/1512.00567).
//
// Sample usage: <program> -dir=/tmp/modeldir imagefile
//
// The pre-trained model takes input in the form of a 4-dimensional
// tensor with shape [ BATCH_SIZE, IMAGE_HEIGHT, IMAGE_WIDTH, 3 ],
// where:
// - BATCH_SIZE allows for inference of multiple images in one pass through the graph
// - IMAGE_HEIGHT is the height of the images on which the model was trained
// - IMAGE_WIDTH is the width of the images on which the model was trained
// - 3 is the (R, G, B) values of the pixel colors represented as a float.
//
// And produces as output a vector with shape [ NUM_LABELS ].
// output[i] is the probability that the input image was recognized as
// having the i-th label.
//
// A separate file contains a list of string labels corresponding to the
// integer indices of the output.
//
// This example:
// - Loads the serialized representation of the pre-trained model into a Graph
// - Creates a Session to execute operations on the Graph
// - Converts an image file to a Tensor to provide as input to a Session run
// - Executes the Session and prints out the label with the highest probability
//
// To convert an image file to a Tensor suitable for input to the Inception model,
// this example:
// - Constructs another TensorFlow graph to normalize the image into a
// form suitable for the model (for example, resizing the image)
// - Creates an executes a Session to obtain a Tensor in this normalized form.
using System;
using TensorFlow;
using Mono.Options;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Collections.Generic;
namespace ExampleInceptionInference
{
class MainClass
{
static void Error (string msg)
{
Console.WriteLine ("Error: {0}", msg);
Environment.Exit (1);
}
static void Help ()
{
options.WriteOptionDescriptions (Console.Out);
}
static bool jagged = true;
static OptionSet options = new OptionSet ()
{
{ "m|dir=", "Specifies the directory where the model and labels are stored", v => dir = v },
{ "h|help", v => Help () },
{ "amulti", "Use multi-dimensional arrays instead of jagged arrays", v => jagged = false }
};
static string dir, modelFile, labelsFile;
public static void Main (string [] args)
{
var files = options.Parse (args);
if (dir == null) {
dir = "/tmp";
//Error ("Must specify a directory with -m to store the training data");
}
//if (files == null || files.Count == 0)
// Error ("No files were specified");
if (files.Count == 0)
files = new List<string> () { "/tmp/demo.jpg" };
ModelFiles (dir);
// Construct an in-memory graph from the serialized form.
var graph = new TFGraph ();
// Load the serialized GraphDef from a file.
var model = File.ReadAllBytes (modelFile);
graph.Import (model, "");
using (var session = new TFSession (graph)) {
var labels = File.ReadAllLines (labelsFile);
foreach (var file in files) {
// Run inference on the image files
// For multiple images, session.Run() can be called in a loop (and
// concurrently). Alternatively, images can be batched since the model
// accepts batches of image data as input.
var tensor = CreateTensorFromImageFile (file);
var runner = session.GetRunner ();
runner.AddInput (graph ["input"] [0], tensor).Fetch (graph ["output"] [0]);
var output = runner.Run ();
// output[0].Value() is a vector containing probabilities of
// labels for each image in the "batch". The batch size was 1.
// Find the most probably label index.
var result = output [0];
var rshape = result.Shape;
if (result.NumDims != 2 || rshape [0] != 1) {
var shape = "";
foreach (var d in rshape) {
shape += $"{d} ";
}
shape = shape.Trim ();
Console.WriteLine ($"Error: expected to produce a [1 N] shaped tensor where N is the number of labels, instead it produced one with shape [{shape}]");
Environment.Exit (1);
}
// You can get the data in two ways, as a multi-dimensional array, or arrays of arrays,
// code can be nicer to read with one or the other, pick it based on how you want to process
// it
bool jagged = true;
var bestIdx = 0;
float p = 0, best = 0;
if (jagged) {
var probabilities = ((float [] [])result.GetValue (jagged: true)) [0];
for (int i = 0; i < probabilities.Length; i++) {
if (probabilities [i] > best) {
bestIdx = i;
best = probabilities [i];
}
}
} else {
var val = (float [,])result.GetValue (jagged: false);
// Result is [1,N], flatten array
for (int i = 0; i < val.GetLength (1); i++) {
if (val [0, i] > best) {
bestIdx = i;
best = val [0, i];
}
}
}
Console.WriteLine ($"{file} best match: [{bestIdx}] {best * 100.0}% {labels [bestIdx]}");
}
}
}
// Convert the image in filename to a Tensor suitable as input to the Inception model.
static TFTensor CreateTensorFromImageFile (string file)
{
var contents = File.ReadAllBytes (file);
// DecodeJpeg uses a scalar String-valued tensor as input.
var tensor = TFTensor.CreateString (contents);
TFGraph graph;
TFOutput input, output;
// Construct a graph to normalize the image
ConstructGraphToNormalizeImage (out graph, out input, out output);
// Execute that graph to normalize this one image
using (var session = new TFSession (graph)) {
var normalized = session.Run (
inputs: new [] { input },
inputValues: new [] { tensor },
outputs: new [] { output });
return normalized [0];
}
}
// The inception model takes as input the image described by a Tensor in a very
// specific normalized format (a particular image size, shape of the input tensor,
// normalized pixel values etc.).
//
// This function constructs a graph of TensorFlow operations which takes as
// input a JPEG-encoded string and returns a tensor suitable as input to the
// inception model.
static void ConstructGraphToNormalizeImage (out TFGraph graph, out TFOutput input, out TFOutput output)
{
// Some constants specific to the pre-trained model at:
// https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip
//
// - The model was trained after with images scaled to 224x224 pixels.
// - The colors, represented as R, G, B in 1-byte each were converted to
// float using (value - Mean)/Scale.
const int W = 224;
const int H = 224;
const float Mean = 117;
const float Scale = 1;
graph = new TFGraph ();
input = graph.Placeholder (TFDataType.String);
output = graph.Div (
x: graph.Sub (
x: graph.ResizeBilinear (
images: graph.ExpandDims (
input: graph.Cast (
graph.DecodeJpeg (contents: input, channels: 3), DstT: TFDataType.Float),
dim: graph.Const (0, "make_batch")),
size: graph.Const (new int [] { W, H }, "size")),
y: graph.Const (Mean, "mean")),
y: graph.Const (Scale, "scale"));
}
//
// Downloads the inception graph and labels
//
static void ModelFiles (string dir)
{
string url = "https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip";
modelFile = Path.Combine (dir, "tensorflow_inception_graph.pb");
labelsFile = Path.Combine (dir, "imagenet_comp_graph_label_strings.txt");
var zipfile = Path.Combine (dir, "inception5h.zip");
if (File.Exists (modelFile) && File.Exists (labelsFile))
return;
Directory.CreateDirectory (dir);
var wc = new WebClient ();
wc.DownloadFile (url, zipfile);
ZipFile.ExtractToDirectory (zipfile, dir);
File.Delete (zipfile);
}
}
}