tf_utils.C
Go to the documentation of this file.
1 /*
2 Licensed under the MIT License <http://opensource.org/licenses/MIT>.
3 SPDX-License-Identifier: MIT
4 Copyright (c) 2018 - 2019 Daniil Goncharov <neargye@gmail.com>.
5 
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12 
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23 
24 This file is copied from TensorFlowFoam:
25 https://github.com/argonne-lcf/TensorFlowFoam
26 */
27 
28 #include "tf_utils.H"
29 
30 #include <algorithm>
31 #include <cstdlib>
32 #include <cstring>
33 #include <fstream>
34 #include <iostream>
35 
36 namespace tf_utils
37 {
38 
39 /*
40 // Tensorflow requirements
41 const char* TFDataTypeToString(TF_DataType data_type)
42 {
43  switch (data_type)
44  {
45  case TF_FLOAT:
46  return "TF_FLOAT";
47  case TF_DOUBLE:
48  return "TF_DOUBLE";
49  case TF_INT32:
50  return "TF_INT32";
51  case TF_UINT8:
52  return "TF_UINT8";
53  case TF_INT16:
54  return "TF_INT16";
55  case TF_INT8:
56  return "TF_INT8";
57  case TF_STRING:
58  return "TF_STRING";
59  case TF_COMPLEX64:
60  return "TF_COMPLEX64";
61  case TF_INT64:
62  return "TF_INT64";
63  case TF_BOOL:
64  return "TF_BOOL";
65  case TF_QINT8:
66  return "TF_QINT8";
67  case TF_QUINT8:
68  return "TF_QUINT8";
69  case TF_QINT32:
70  return "TF_QINT32";
71  case TF_BFLOAT16:
72  return "TF_BFLOAT16";
73  case TF_QINT16:
74  return "TF_QINT16";
75  case TF_QUINT16:
76  return "TF_QUINT16";
77  case TF_UINT16:
78  return "TF_UINT16";
79  case TF_COMPLEX128:
80  return "TF_COMPLEX128";
81  case TF_HALF:
82  return "TF_HALF";
83  case TF_RESOURCE:
84  return "TF_RESOURCE";
85  case TF_VARIANT:
86  return "TF_VARIANT";
87  case TF_UINT32:
88  return "TF_UINT32";
89  case TF_UINT64:
90  return "TF_UINT64";
91  default:
92  return "Unknown";
93  }
94 }
95 */
96 
97 static void DeallocateBuffer(void* data, size_t)
98 {
99  std::free(data);
100 }
101 
102 static TF_Buffer* ReadBufferFromFile(const char* file)
103 {
104  std::ifstream f(file, std::ios::binary);
105  if (f.fail() || !f.is_open())
106  {
107  return nullptr;
108  }
109 
110  f.seekg(0, std::ios::end);
111  const auto fsize = f.tellg();
112  f.seekg(0, std::ios::beg);
113 
114  if (fsize < 1)
115  {
116  f.close();
117  return nullptr;
118  }
119 
120  char* data = static_cast<char*>(std::malloc(fsize));
121  f.read(data, fsize);
122  f.close();
123 
124  TF_Buffer* buf = TF_NewBuffer();
125  buf->data = data;
126  buf->length = fsize;
127  buf->data_deallocator = DeallocateBuffer;
128 
129  return buf;
130 }
131 
132 TF_Graph* LoadGraph(const char* graphPath)
133 {
134  if (graphPath == nullptr)
135  {
136  return nullptr;
137  }
138 
139  TF_Buffer* buffer = ReadBufferFromFile(graphPath);
140  if (buffer == nullptr)
141  {
142  return nullptr;
143  }
144 
145  TF_Graph* graph = TF_NewGraph();
146  TF_Status* status = TF_NewStatus();
147  TF_ImportGraphDefOptions* opts = TF_NewImportGraphDefOptions();
148 
149  TF_GraphImportGraphDef(graph, buffer, opts, status);
150  TF_DeleteImportGraphDefOptions(opts);
151  TF_DeleteBuffer(buffer);
152 
153  if (TF_GetCode(status) != TF_OK)
154  {
155  TF_DeleteGraph(graph);
156  graph = nullptr;
157  }
158 
159  TF_DeleteStatus(status);
160 
161  return graph;
162 }
163 
164 /*
165 void DeleteGraph(TF_Graph* graph)
166 {
167  TF_DeleteGraph(graph);
168 }
169 */
170 
171 void DeleteSession(TF_Session* session)
172 {
173  TF_Status* status = TF_NewStatus();
174  TF_CloseSession(session, status);
175  if (TF_GetCode(status) != TF_OK)
176  {
177  TF_CloseSession(session, status);
178  }
179  TF_DeleteSession(session, status);
180  if (TF_GetCode(status) != TF_OK)
181  {
182  TF_DeleteSession(session, status);
183  }
184  TF_DeleteStatus(status);
185 }
186 
187 /*
188 TF_Session* CreateSession(TF_Graph* graph)
189 {
190  TF_Status* status = TF_NewStatus();
191  TF_SessionOptions* options = TF_NewSessionOptions();
192  TF_Session* session = TF_NewSession(graph, options, status);
193  TF_DeleteSessionOptions(options);
194 
195  if (TF_GetCode(status) != TF_OK)
196  {
197  DeleteSession(session);
198  TF_DeleteStatus(status);
199  return nullptr;
200  }
201  TF_DeleteStatus(status);
202 
203  return session;
204 }
205 
206 TF_Code RunSession(TF_Session* session,
207  const TF_Output* inputs,
208  TF_Tensor* const* input_tensors,
209  std::size_t ninputs,
210  const TF_Output* outputs,
211  TF_Tensor** output_tensors,
212  std::size_t noutputs)
213 {
214  if (session == nullptr || inputs == nullptr || input_tensors == nullptr || outputs == nullptr || output_tensors == nullptr)
215  {
216  return TF_INVALID_ARGUMENT;
217  }
218 
219  TF_Status* status = TF_NewStatus();
220  TF_SessionRun(session,
221  nullptr, // Run options.
222  inputs,
223  input_tensors,
224  static_cast<int>(ninputs), // Input tensors, input tensor values, number of inputs.
225  outputs,
226  output_tensors,
227  static_cast<int>(noutputs), // Output tensors, output tensor values, number of outputs.
228  nullptr,
229  0, // Target operations, number of targets.
230  nullptr, // Run metadata.
231  status // Output status.
232  );
233 
234  TF_Code code = TF_GetCode(status);
235  TF_DeleteStatus(status);
236  return code;
237 }
238 
239 TF_Code RunSession(TF_Session* session,
240  const std::vector<TF_Output>& inputs,
241  const std::vector<TF_Tensor*>& input_tensors,
242  const std::vector<TF_Output>& outputs,
243  std::vector<TF_Tensor*>& output_tensors)
244 {
245  return RunSession(session,
246  inputs.data(),
247  input_tensors.data(),
248  input_tensors.size(),
249  outputs.data(),
250  output_tensors.data(),
251  output_tensors.size());
252 }
253 */
254 
255 TF_Tensor* CreateTensor(TF_DataType data_type,
256  const std::int64_t* dims,
257  std::size_t num_dims,
258  const void* data,
259  std::size_t len)
260 {
261  if (dims == nullptr)
262  {
263  return nullptr;
264  }
265 
266  TF_Tensor* tensor = TF_AllocateTensor(data_type, dims, static_cast<int>(num_dims), len);
267  if (tensor == nullptr)
268  {
269  return nullptr;
270  }
271 
272  void* tensor_data = TF_TensorData(tensor);
273  if (tensor_data == nullptr)
274  {
275  TF_DeleteTensor(tensor);
276  return nullptr;
277  }
278 
279  if (data != nullptr)
280  {
281  std::memcpy(tensor_data, data, std::min(len, TF_TensorByteSize(tensor)));
282  }
283 
284  return tensor;
285 }
286 
287 /*
288 TF_Tensor* CreateEmptyTensor(TF_DataType data_type, const std::int64_t* dims, std::size_t num_dims)
289 {
290  return CreateTensor(data_type, dims, num_dims, nullptr, 0);
291 }
292 
293 TF_Tensor* CreateEmptyTensor(TF_DataType data_type, const std::vector<std::int64_t>& dims)
294 {
295  return CreateEmptyTensor(data_type, dims.data(), dims.size());
296 }
297 */
298 
299 void DeleteTensor(TF_Tensor* tensor)
300 {
301  if (tensor != nullptr)
302  {
303  TF_DeleteTensor(tensor);
304  }
305 }
306 
307 /*
308 void DeleteTensors(const std::vector<TF_Tensor*>& tensors)
309 {
310  for (auto t : tensors)
311  {
312  TF_DeleteTensor(t);
313  }
314 }
315 
316 void SetTensorsData(TF_Tensor* tensor, const void* data, std::size_t len)
317 {
318  void* tensor_data = TF_TensorData(tensor);
319  if (tensor_data != nullptr)
320  {
321  std::memcpy(tensor_data, data, std::min(len, TF_TensorByteSize(tensor)));
322  }
323 }
324 
325 // Some operations using tf_utils
326 void PrintInputs(TF_Graph*, TF_Operation* op)
327 {
328  const int num_inputs = TF_OperationNumInputs(op);
329 
330  for (int i = 0; i < num_inputs; ++i)
331  {
332  const TF_Input input = {op, i};
333  const TF_DataType type = TF_OperationInputType(input);
334  std::cout << "Input: " << i << " type: " << TFDataTypeToString(type) << std::endl;
335  }
336 }
337 
338 void PrintOutputs(TF_Graph* graph, TF_Operation* op)
339 {
340  const int num_outputs = TF_OperationNumOutputs(op);
341  TF_Status* status = TF_NewStatus();
342 
343  for (int i = 0; i < num_outputs; ++i)
344  {
345  const TF_Output output = {op, i};
346  const TF_DataType type = TF_OperationOutputType(output);
347  const int num_dims = TF_GraphGetTensorNumDims(graph, output, status);
348 
349  if (TF_GetCode(status) != TF_OK)
350  {
351  std::cout << "Can't get tensor dimensionality" << std::endl;
352  continue;
353  }
354 
355  std::cout << " dims: " << num_dims;
356 
357  if (num_dims <= 0)
358  {
359  std::cout << " []" << std::endl;
360  ;
361  continue;
362  }
363 
364  std::vector<std::int64_t> dims(num_dims);
365 
366  std::cout << "Output: " << i << " type: " << TFDataTypeToString(type);
367  TF_GraphGetTensorShape(graph, output, dims.data(), num_dims, status);
368 
369  if (TF_GetCode(status) != TF_OK)
370  {
371  std::cout << "Can't get get tensor shape" << std::endl;
372  continue;
373  }
374 
375  std::cout << " [";
376  for (int d = 0; d < num_dims; ++d)
377  {
378  std::cout << dims[d];
379  if (d < num_dims - 1)
380  {
381  std::cout << ", ";
382  }
383  }
384  std::cout << "]" << std::endl;
385  }
386 
387  TF_DeleteStatus(status);
388 }
389 
390 void PrintTensorInfo(TF_Graph* graph, const char* layer_name)
391 {
392  std::cout << "Tensor: " << layer_name;
393  TF_Operation* op = TF_GraphOperationByName(graph, layer_name);
394 
395  if (op == nullptr)
396  {
397  std::cout << "Could not get " << layer_name << std::endl;
398  return;
399  }
400 
401  const int num_inputs = TF_OperationNumInputs(op);
402  const int num_outputs = TF_OperationNumOutputs(op);
403  std::cout << " inputs: " << num_inputs << " outputs: " << num_outputs << std::endl;
404 
405  PrintInputs(graph, op);
406 
407  PrintOutputs(graph, op);
408 }
409 
410 void PrintOp(TF_Graph* graph)
411 {
412  TF_Operation* op;
413  std::size_t pos = 0;
414 
415  while ((op = TF_GraphNextOperation(graph, &pos)) != nullptr)
416  {
417  const char* name = TF_OperationName(op);
418  const char* type = TF_OperationOpType(op);
419  const char* device = TF_OperationDevice(op);
420 
421  const int num_outputs = TF_OperationNumOutputs(op);
422  const int num_inputs = TF_OperationNumInputs(op);
423 
424  std::cout << pos << ": " << name << " type: " << type << " device: " << device << " number inputs: " << num_inputs << " number outputs: " << num_outputs << std::endl;
425 
426  PrintInputs(graph, op);
427  PrintOutputs(graph, op);
428  std::cout << std::endl;
429  }
430 }
431 */
432 
433 } // namespace tf_utils
434 
435 #if defined(_MSC_VER)
436 #pragma warning(pop)
437 #endif
tf_utils::DeleteTensor
void DeleteTensor(TF_Tensor *tensor)
Definition: tf_utils.C:299
tf_utils
Definition: tf_utils.C:36
tf_utils::LoadGraph
TF_Graph * LoadGraph(const char *graphPath)
Definition: tf_utils.C:132
tf_utils.H
tf_utils::CreateTensor
TF_Tensor * CreateTensor(TF_DataType data_type, const std::int64_t *dims, std::size_t num_dims, const void *data, std::size_t len)
Definition: tf_utils.C:255
tf_utils::DeallocateBuffer
static void DeallocateBuffer(void *data, size_t)
Definition: tf_utils.C:97
tf_utils::ReadBufferFromFile
static TF_Buffer * ReadBufferFromFile(const char *file)
Definition: tf_utils.C:102
tf_utils::DeleteSession
void DeleteSession(TF_Session *session)
Definition: tf_utils.C:171