Add MocapNET

This commit is contained in:
Justin John
2023-12-15 04:22:41 +05:30
parent 8434144ded
commit 65e8934d5e
336 changed files with 100584 additions and 0 deletions
@@ -0,0 +1,20 @@
import tensorflow as tf
gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.5)
#config = tf.ConfigProto(gpu_options=gpu_options)
config = tf.ConfigProto(
device_count={'CPU' : 1, 'GPU' : 0},
allow_soft_placement=True,
log_device_placement=False
);
serialized = config.SerializeToString()
c = list(map(hex, serialized))
print("uint8_t config[] = {")
print(c)
print("};")
print("TF_SetConfig(opts, (void*)config, ",len(serialized),", status);};")
#['0x32', '0x9', '0x9', '0x0', '0x0', '0x0', '0x0', '0x0', '0x0', '0xe0', '0x3f']
@@ -0,0 +1,462 @@
/** @file tensorflow.cpp
* @brief This is a Tensorflow C-API wrapper.. Since Tensorflow is pretty volatile this whole file is kind of
* half-finished and will probably have to change to reflect changes to the tensorflow project. This code needs a serious cleanup when the Tensorflow C API is
* completely stable.
* If you are not familiar with Tensorflow for C check https://github.com/iwatake2222/CNN_NumberDetector/tree/master/03_Tensorflow_C
* @bug Tensorflow and the TF_GraphGetTensorShape ( https://github.com/tensorflow/tensorflow/blob/master/tensorflow/c/c_api.h#L239 ) returns -1,-1 as the dimensions of some tensors. In order to work around this the expected dimensions are given as variables
* from the MocapNET client applications
* @author Ammar Qammaz (AmmarkoV)
*/
#include "tensorflow.hpp"
#include "tf_utils.hpp"
#include <stdio.h>
#include <vector>
#include <iostream>
#include <cstdint> // include this header for uint64_t
/*
std::vector<int> get_tensor_shape(tensorflow::Tensor& tensor)
{
std::vector<int> shape;
int num_dimensions = tensor.shape().dims()
for(int ii_dim=0; ii_dim<num_dimensions; ii_dim++) {
shape.push_back(tensor.shape().dim_size(ii_dim));
}
return shape;
}*/
#define NORMAL "\033[0m"
#define BLACK "\033[30m" /* Black */
#define RED "\033[31m" /* Red */
#define GREEN "\033[32m" /* Green */
#define YELLOW "\033[33m" /* Yellow */
#include <sys/time.h>
#include <unistd.h>
#include <time.h>
unsigned long tickBaseTF = 0;
unsigned long GetTickCountMicroseconds()
{
struct timespec ts;
if ( clock_gettime(CLOCK_MONOTONIC,&ts) != 0)
{
return 0;
}
if (tickBaseTF==0)
{
tickBaseTF = ts.tv_sec*1000000 + ts.tv_nsec/1000;
return 0;
}
return ( ts.tv_sec*1000000 + ts.tv_nsec/1000 ) - tickBaseTF;
}
unsigned long GetTickCountMilliseconds()
{
return (unsigned long) GetTickCountMicroseconds()/1000;
}
int checkAndDeallocate(TF_Status * s,const char * label)
{
if (TF_GetCode(s) != TF_OK)
{
fprintf(stderr,RED "Error %s \n" NORMAL,label );
TF_DeleteStatus(s);
return 0;
}
return 1;
}
void listNodes(const char * label , TF_Graph* graph)
{
size_t pos = 0;
TF_Operation* oper;
std::cout << "Nodes list : \n";
while ((oper = TF_GraphNextOperation(graph, &pos)) != nullptr)
{
std::cout << label<<" - "<<TF_OperationName(oper)<<" "<< std::endl;
}
}
char tfGraphExists(const char * filename)
{
FILE *fp = fopen(filename,"r");
if( fp ) { /* exists */ fclose(fp); return 1; }
return 0;
}
int loadTensorflowInstance(
struct TensorflowInstance * net,
const char * filename,
const char * inputTensor,
const char * outputTensor,
unsigned int forceCPU
)
{
if (!tfGraphExists(filename))
{
std::cout << "Graph "<<filename<<" could not be found "<< std::endl;
return 0;
}
if (net==0)
{
std::cout << "TensorflowInstance structure not allocated "<< std::endl;
return 0;
}
net->outputTensor=nullptr;
//--------------------------------------------------------------------------------------------------------------
net->graph = tf_utils::LoadGraph(filename);
if (net->graph == nullptr)
{
fprintf(stderr,RED "Can't load graph %s \n" NORMAL,filename);
return 0;
}
//tf_utils::PrintOp(net->graph);
//--------------------------------------------------------------------------------------------------------------
net->input_operation = {TF_GraphOperationByName(net->graph, inputTensor), 0};
if (net->input_operation.oper == nullptr)
{
listNodes(filename,net->graph);
fprintf(stderr,RED "Can't init input for %s \n" NORMAL,filename);
return 0;
}
std::cout << " Input Tensor for " <<filename << std::endl;
tf_utils::PrintTensorInfo(net->graph,inputTensor,0,0);
net->output_operation = {TF_GraphOperationByName(net->graph, outputTensor), 0};
if (net->output_operation.oper == nullptr)
{
listNodes(filename,net->graph);
fprintf(stderr,RED "Can't init output for %s \n" NORMAL,filename);
return 0;
}
std::cout << " Output Tensor for " <<filename << std::endl;
tf_utils::PrintTensorInfo(net->graph,outputTensor,0,0);
//--------------------------------------------------------------------------------------------------------------
snprintf(net->modelPath,1024,"%s",filename);
snprintf(net->inputLayerName,512,"%s",inputTensor);
snprintf(net->outputLayerName,512,"%s",outputTensor);
//--------------------------------------------------------------------------------------------------------------
net->status = TF_NewStatus();
net->options = TF_NewSessionOptions();
if (forceCPU)
{
//How do you end up with this byte array you might ask ?
uint8_t config[] = { 0xa,0x7,0xa,0x3,0x43,0x50,0x55,0x10,0x1,0xa,0x7,0xa,0x3,0x47,0x50,0x55,0x10,0x0,0x38,0x1};
//Good Question, you use the python code and extract the configuration bytes and copy paste them here..
//https://github.com/FORTH-ModelBasedTracker/MocapNET/blob/master/src/Tensorflow/createTensorflowConfigurationForC.py
/*net->session = tf.ConfigProto(
device_count={'CPU' : 1, 'GPU' : 0},
allow_soft_placement=True,
log_device_placement=False
);*/
TF_SetConfig(net->options, (void*)config, 20 , net->status);
}
net->session = TF_NewSession(net->graph,net->options,net->status);
TF_DeleteSessionOptions(net->options);
if (TF_GetCode(net->status) != TF_OK)
{
TF_DeleteStatus(net->status);
return 0;
}
//--------------------------------------------------------------------------------------------------------------
return 1;
}
int unloadTensorflow(struct TensorflowInstance * net)
{
//------------------------------------
TF_CloseSession(net->session, net->status);
if (TF_GetCode(net->status) != TF_OK)
{
std::cout << "Error closing all session";
TF_DeleteStatus(net->status);
return 0;
}
TF_DeleteSession(net->session, net->status);
if (TF_GetCode(net->status) != TF_OK)
{
std::cout << "Error delete session";
TF_DeleteStatus(net->status);
return 0;
}
tf_utils::DeleteGraph(net->graph);
tf_utils::DeleteTensor(net->inputTensor);
tf_utils::DeleteTensor(net->outputTensor);
//------------------------------------
TF_DeleteStatus(net->status);
return 1;
}
std::vector<float> predictTensorflow(struct TensorflowInstance * net,std::vector<float> input)
{
const int printInput=0;
const int printOutput=0;
std::vector<float> result;
result.clear();
TF_Tensor* output_tensor = nullptr;
unsigned int inputSize=input.size();
std::vector<std::int64_t> input_dims = {1,inputSize};
std::vector<float> input_vals = input;
//----------------------------------------
if (printInput)
{
//----------------------------------------
std::cout << "Input vals: ";
for (int i=0; i<inputSize; i++)
{
std::cout << input_vals[i] << ", ";
}
std::cout << std::endl;
} //----------------------------------------
//----------------------------------------
TF_Tensor* input_tensor = tf_utils::CreateTensor(
TF_FLOAT,
input_dims.data(), input_dims.size(),
input_vals.data(), input_vals.size() * sizeof(float)
);
TF_SessionRun( net->session,
nullptr, // Run options.
&net->input_operation, &input_tensor, 1, // Input tensors, input tensor values, number of inputs.
&net->output_operation, &output_tensor, 1, // Output tensors, output tensor values, number of outputs.
nullptr, 0, // Target operations, number of targets.
nullptr, // Run metadata.
net->status // Output status.
);
if (!checkAndDeallocate(net->status,"at predictTensorflow while running session"))
{
fprintf(stderr,RED "Possibly a wrong number of arguments given ( %lu )\n" NORMAL,input.size());
return result;
}
const auto data = static_cast<float*>(TF_TensorData(output_tensor));
int64_t outputSizeA[4];
TF_GraphGetTensorShape(
net->graph,
net->output_operation,
outputSizeA, 2,
net->status
);
if (!checkAndDeallocate(net->status,"TF_GraphGetTensorShape"))
{
return result;
}
int outputSize = outputSizeA[1];
//----------------------------------------
if (printOutput)
{
//----------------------------------------
std::cout << "Output vals "<<outputSize<<" : ";
for (int i=0; i<outputSize; i++)
{
std::cout << data[i] << ", ";
}
std::cout << std::endl;
} //----------------------------------------
//----------------------------------------
for (int i=0; i<outputSize; i++)
{
result.push_back((float) data[i]);
}
tf_utils::DeleteTensor(input_tensor);
tf_utils::DeleteTensor(output_tensor);
return result;
}
std::vector<std::vector<float> > predictTensorflowOnArrayOfHeatmaps(
struct TensorflowInstance * net,
unsigned int width ,
unsigned int height ,
float * data,
unsigned int heatmapWidth,
unsigned int heatmapHeight,
unsigned int numberOfOutputTensors
)
{
std::vector<std::vector<float> > matrix; //This function output
TF_Tensor* output_tensor = nullptr;
std::vector<std::int64_t> input_dims = {1,height,width,3};
TF_Tensor* input_tensor = tf_utils::CreateTensor(
TF_FLOAT,
input_dims.data(), 4,
data , width * height * 3 * sizeof(float)
);
TF_SessionRun( net->session,
nullptr, // Run options.
&net->input_operation, &input_tensor, 1, // Input tensors, input tensor values, number of inputs.
&net->output_operation, &output_tensor, 1, // Output tensors, output tensor values, number of outputs.
nullptr, 0, // Target operations, number of targets.
nullptr, // Run metadata.
net->status // Output status.
);
if (TF_GetCode(net->status) != TF_OK)
{
fprintf(stderr,RED "predictTensorflowOnArrayOfHeatmaps: Error running session %u ( %s ) \n" NORMAL, TF_GetCode(net->status),TF_Message(net->status));
TF_DeleteStatus(net->status);
tf_utils::DeleteTensor(input_tensor);
return matrix;
}
if (output_tensor==nullptr)
{
fprintf(stderr,RED "Error retrieving output..\n" NORMAL);
TF_DeleteStatus(net->status);
tf_utils::DeleteTensor(input_tensor);
return matrix;
}
/*
TF_Output outputO = TF_Output{net->operation, 0};
TF_Status* s = TF_NewStatus();
//TF_Output feed_out_0 = TF_Output{output_tensor, 0};
int num_dims;
// Fetch the shape, it should be completely unknown.
num_dims = TF_GraphGetTensorNumDims(net->graph,outputO, s);
fprintf(stderr,"Number of dimensions is %u \n",num_dims);
*/
//===============================================================================
int64_t outputSizeA[32]= {0};
TF_GraphGetTensorShape(
net->graph,
net->output_operation,
outputSizeA, numberOfOutputTensors,
net->status
);
if (TF_GetCode(net->status) != TF_OK)
{
fprintf(stderr,RED "Error TF_GraphGetTensorShape for output, numberOfOutputTensors is probably wrong..! \n" NORMAL);
TF_DeleteStatus(net->status);
tf_utils::DeleteTensor(input_tensor);
return matrix;
}
//===============================================================================
//std::cout << "OutputA vals "<<outputSizeA[0]<<","<<outputSizeA[1]<<","<<outputSizeA[2]<<","<<outputSizeA[3]<<"\n";
//This is -1 -1 -1 19 and so we need the values and we get them as input
if ( (outputSizeA[1]==-1) && (outputSizeA[2]==-1) )
{
//std::cout<<"tensorflow not reporting correct output size..\n";
}
/*
* Attempting to retreive the correct shape ..
//===============================================================================
TF_Operation *operation = TF_GraphOperationByName(net->graph, net->outputLayerName);
TF_Output operation_out = {operation, 0};
int64_t outputSizeB[32];
TF_OperationGetAttrShape(
operation,
"shape",
outputSizeB, 4,
net->status
);
std::cout << "OutputB "<<net->outputLayerName<<" vals "<<outputSizeB[0]<<", cols = "<<outputSizeB[1]<<", rows = "<<outputSizeB[2]<<", hm = "<<outputSizeB[3]<<"\n";
//===============================================================================
*/
// const int num_outputs = TF_OperationNumOutputs(operation);
// std::cout << "TF_OperationNumOutputs "<<num_outputs<<"\n";
//Retreive output..
float * out_p = static_cast<float*>(TF_TensorData(output_tensor));
if (out_p!=nullptr)
{
//Rows and columns should be automatically extracted,however
//tensorflow and TF_GraphGetTensorShape returns -1,-1 as their dimensions
//https://github.com/tensorflow/tensorflow/blob/master/tensorflow/c/c_api.h#L239
unsigned int rows = heatmapWidth; //outputSizeA[numberOfOutputTensors-3];
unsigned int cols = heatmapHeight; //outputSizeA[numberOfOutputTensors-2];
unsigned int hm = outputSizeA[numberOfOutputTensors-1];
//For each of the output heatmaps
for(int i=0; i<hm; ++i)
{
std::vector<float> heatmap(rows*cols);
//For each of the rows of a particular heatmap
for(int r=0; r<rows; ++r)
{
//For each of the cols of a particular heatmap
for(int c=0; c<cols; ++c)
{
int pos = (r*cols+c) * hm + i;
heatmap[r*cols+c] = out_p[pos];
}
}
//Retreive the values in our matrix
matrix.push_back(heatmap);
}
} //We have output..
tf_utils::DeleteTensor(input_tensor);
tf_utils::DeleteTensor(output_tensor);
return matrix;
}
@@ -0,0 +1,119 @@
#pragma once
/** @file tensorflow.hpp
* @brief The main wrapper around the tensorflow C API
*
*
* @author Ammar Qammaz (AmmarkoV)
* @bug The tensorflow C-API is volatile and subject to change
*/
#include <tensorflow/c/c_api.h> // TensorFlow C API header
#include <vector>
/**
* @brief A structure that holds all of the relevant information for a tensorflow instance
*
* This is used to simplify context switching and reduce the complexity of the library
*
*/
struct TensorflowInstance
{
char modelPath[1024];
char inputLayerName[512];
char outputLayerName[512];
TF_Graph* graph;
TF_Session* session;
TF_Operation* operation;
TF_Tensor* inputTensor;
TF_Tensor* outputTensor;
TF_Output input_operation;
TF_Output output_operation;
TF_Status* status;
TF_SessionOptions* options;
};
/**
* @brief Get the number of Ticks in Microseconds, to be used as a performance counter
* @ingroup tensorflow
* @retval The number of microseconds since system boot
*/
unsigned long GetTickCountMicroseconds();
/**
* @brief Get the number of Ticks in Milliseconds, to be used as a performance counter
* @ingroup tensorflow
* @retval The number of milliseconds since system boot
*/
unsigned long GetTickCountMilliseconds();
/**
* @brief List nodes of the TF_Graph by printing them in stdout
* @ingroup tensorflow
* @param Label of printed output
* @param Pointer to TF_Graph struct
* @retval No return value
*/
void listNodes(const char * label , TF_Graph* graph);
/**
* @brief Load a tensorflow instance from a .pb file
* @ingroup tensorflow
* @param Pointer to a struct TensorflowInstance that will hold the tensorflow instance on load.
* @param Path to .pb file
* @param Name of input tensor, i.e. input_1
* @param Name of output tensor, i.e. output_1
* @retval 1 = Success loading the file , 0 = Failure
*/
int loadTensorflowInstance(
struct TensorflowInstance * net,
const char * filename,
const char * inputTensor,
const char * outputTensor,
unsigned int forceCPU
);
/**
* @brief Evaluate an input vector through the neural network and return an output vector
* @ingroup tensorflow
* @param Pointer to a struct TensorflowInstance that holds a loaded tensorflow instance.
* @param Input vector of floats
* @retval Output vector of floats, Empty vector in case of failure
*/
std::vector<float> predictTensorflow(struct TensorflowInstance * net,std::vector<float> input);
/**
* @brief Evaluate an input image through a network that outputs a vector of heatmaps
* @ingroup tensorflow
* @param Pointer to a struct TensorflowInstance that holds a loaded tensorflow instance.
* @param Width of input image
* @param Height of input image
* @param Pixels of input image
* @retval Output vector of vectors of floats, That correspond to the heatmaps
* @bug TF_GraphGetTensorShape returns -1 for some networks.
*/
std::vector<std::vector<float> > predictTensorflowOnArrayOfHeatmaps(
struct TensorflowInstance * net,
unsigned int width ,
unsigned int height ,
float * data,
unsigned int heatmapWidth,
unsigned int heatmapHeight,
unsigned int numberOfOutputTensors
);
/**
* @brief Clean tensorflow instance from memory and deallocate it
* @ingroup tensorflow
* @param Pointer to a struct TensorflowInstance that holds a loaded tensorflow instance.
* @retval 1 = Success saving the file , 0 = Failure
*/
int unloadTensorflow(struct TensorflowInstance * net);
@@ -0,0 +1,505 @@
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT
// Copyright (c) 2018 - 2019 Daniil Goncharov <neargye@gmail.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "tf_utils.hpp"
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <fstream>
namespace tf_utils
{
namespace
{
static void DeallocateBuffer(void* data, size_t)
{
std::free(data);
}
static TF_Buffer* ReadBufferFromFile(const char* file)
{
std::ifstream f(file, std::ios::binary);
if (f.fail() || !f.is_open())
{
return nullptr;
}
f.seekg(0, std::ios::end);
const auto fsize = f.tellg();
f.seekg(0, std::ios::beg);
if (fsize < 1)
{
f.close();
return nullptr;
}
char* data = static_cast<char*>(std::malloc(fsize));
f.read(data, fsize);
f.close();
TF_Buffer* buf = TF_NewBuffer();
buf->data = data;
buf->length = fsize;
buf->data_deallocator = DeallocateBuffer;
return buf;
}
} // namespace tf_utils::
TF_Graph* LoadGraph(const char* graphPath)
{
fprintf(stderr,"LoadGraph %s using TensorFlow Version: %s\n",graphPath,TF_Version());
if (graphPath == nullptr)
{
fprintf(stderr,"Cannot load graph with null path..\n");
return nullptr;
}
TF_Buffer* buffer = ReadBufferFromFile(graphPath);
if (buffer == nullptr)
{
fprintf(stderr,"Cannot read buffer from file %s ..\n",graphPath);
return nullptr;
}
TF_Graph* graph = TF_NewGraph();
TF_Status* status = TF_NewStatus();
TF_ImportGraphDefOptions* opts = TF_NewImportGraphDefOptions();
TF_GraphImportGraphDef(graph, buffer, opts, status);
TF_DeleteImportGraphDefOptions(opts);
TF_DeleteBuffer(buffer);
if (TF_GetCode(status) != TF_OK)
{
fprintf(stderr,"Error importing graph definition.. (%u)\n",TF_GetCode(status));
switch (TF_GetCode(status))
{
case TF_INVALID_ARGUMENT :
fprintf(stderr,"Invalid Argument in graph..\n");
break;
};
TF_DeleteGraph(graph);
graph = nullptr;
}
TF_DeleteStatus(status);
return graph;
}
void DeleteGraph(TF_Graph* graph)
{
TF_DeleteGraph(graph);
}
TF_Session* CreateSession(TF_Graph* graph)
{
TF_Status* status = TF_NewStatus();
TF_SessionOptions* options = TF_NewSessionOptions();
TF_Session* session = TF_NewSession(graph, options, status);
TF_DeleteSessionOptions(options);
if (TF_GetCode(status) != TF_OK)
{
DeleteSession(session);
TF_DeleteStatus(status);
return nullptr;
}
TF_DeleteStatus(status);
return session;
}
void DeleteSession(TF_Session* session)
{
TF_Status* status = TF_NewStatus();
TF_CloseSession(session, status);
if (TF_GetCode(status) != TF_OK)
{
TF_CloseSession(session, status);
}
TF_DeleteSession(session, status);
if (TF_GetCode(status) != TF_OK)
{
TF_DeleteSession(session, status);
}
TF_DeleteStatus(status);
}
TF_Code RunSession(TF_Session* session,
const TF_Output* inputs, TF_Tensor* const* input_tensors, std::size_t ninputs,
const TF_Output* outputs, TF_Tensor** output_tensors, std::size_t noutputs)
{
if (session == nullptr ||
inputs == nullptr || input_tensors == nullptr ||
outputs == nullptr || output_tensors == nullptr)
{
return TF_INVALID_ARGUMENT;
}
TF_Status* status = TF_NewStatus();
TF_SessionRun(session,
nullptr, // Run options.
inputs, input_tensors, static_cast<int>(ninputs), // Input tensors, input tensor values, number of inputs.
outputs, output_tensors, static_cast<int>(noutputs), // Output tensors, output tensor values, number of outputs.
nullptr, 0, // Target operations, number of targets.
nullptr, // Run metadata.
status // Output status.
);
TF_Code code = TF_GetCode(status);
TF_DeleteStatus(status);
return code;
}
TF_Code RunSession(TF_Session* session,
const std::vector<TF_Output>& inputs, const std::vector<TF_Tensor*>& input_tensors,
const std::vector<TF_Output>& outputs, std::vector<TF_Tensor*>& output_tensors)
{
return RunSession(session,
inputs.data(), input_tensors.data(), input_tensors.size(),
outputs.data(), output_tensors.data(), output_tensors.size());
}
TF_Tensor* CreateTensor(TF_DataType data_type,
const std::int64_t* dims, std::size_t num_dims,
const void* data, std::size_t len)
{
if (dims == nullptr)
{
return nullptr;
}
TF_Tensor* tensor = TF_AllocateTensor(data_type, dims, static_cast<int>(num_dims), len);
if (tensor == nullptr)
{
return nullptr;
}
void* tensor_data = TF_TensorData(tensor);
if (tensor_data == nullptr)
{
TF_DeleteTensor(tensor);
return nullptr;
}
if (data != nullptr)
{
std::memcpy(tensor_data, data, std::min(len, TF_TensorByteSize(tensor)));
}
return tensor;
}
TF_Tensor* CreateEmptyTensor(TF_DataType data_type, const std::int64_t* dims, std::size_t num_dims)
{
return CreateTensor(data_type, dims, num_dims, nullptr, 0);
}
TF_Tensor* CreateEmptyTensor(TF_DataType data_type, const std::vector<std::int64_t>& dims)
{
return CreateEmptyTensor(data_type, dims.data(), dims.size());
}
void DeleteTensor(TF_Tensor* tensor)
{
if (tensor != nullptr)
{
TF_DeleteTensor(tensor);
}
}
void DeleteTensors(const std::vector<TF_Tensor*>& tensors)
{
for (auto t : tensors)
{
TF_DeleteTensor(t);
}
}
void SetTensorsData(TF_Tensor* tensor, const void* data, std::size_t len)
{
void* tensor_data = TF_TensorData(tensor);
if (tensor_data != nullptr)
{
std::memcpy(tensor_data, data, std::min(len, TF_TensorByteSize(tensor)));
}
}
const char* TFDataTypeToString(TF_DataType data_type)
{
switch (data_type)
{
case TF_FLOAT:
return "TF_FLOAT";
case TF_DOUBLE:
return "TF_DOUBLE";
case TF_INT32:
return "TF_INT32";
case TF_UINT8:
return "TF_UINT8";
case TF_INT16:
return "TF_INT16";
case TF_INT8:
return "TF_INT8";
case TF_STRING:
return "TF_STRING";
case TF_COMPLEX64:
return "TF_COMPLEX64";
case TF_INT64:
return "TF_INT64";
case TF_BOOL:
return "TF_BOOL";
case TF_QINT8:
return "TF_QINT8";
case TF_QUINT8:
return "TF_QUINT8";
case TF_QINT32:
return "TF_QINT32";
case TF_BFLOAT16:
return "TF_BFLOAT16";
case TF_QINT16:
return "TF_QINT16";
case TF_QUINT16:
return "TF_QUINT16";
case TF_UINT16:
return "TF_UINT16";
case TF_COMPLEX128:
return "TF_COMPLEX128";
case TF_HALF:
return "TF_HALF";
case TF_RESOURCE:
return "TF_RESOURCE";
case TF_VARIANT:
return "TF_VARIANT";
case TF_UINT32:
return "TF_UINT32";
case TF_UINT64:
return "TF_UINT64";
default:
return "Unknown";
}
}
void PrintInputs(TF_Graph*, TF_Operation* op)
{
const int num_inputs = TF_OperationNumInputs(op);
for (int i = 0; i < num_inputs; ++i)
{
const TF_Input input = {op, i};
const TF_DataType type = TF_OperationInputType(input);
std::cout << "Input: " << i << " type: " << TFDataTypeToString(type) << std::endl;
}
}
void PrintOutputs(TF_Graph* graph, TF_Operation* op)
{
const int num_outputs = TF_OperationNumOutputs(op);
TF_Status* status = TF_NewStatus();
for (int i = 0; i < num_outputs; ++i)
{
const TF_Output output = {op, i};
const TF_DataType type = TF_OperationOutputType(output);
const int num_dims = TF_GraphGetTensorNumDims(graph, output, status);
if (TF_GetCode(status) != TF_OK)
{
std::cout << "Can't get tensor dimensionality" << std::endl;
continue;
}
std::cout << " dims: " << num_dims<<"\n";
if (num_dims <= 0)
{
std::cout << " []" << std::endl;;
continue;
}
std::vector<std::int64_t> dims(num_dims);
std::cout << "Output: " << i << " type: " << TFDataTypeToString(type);
TF_GraphGetTensorShape(graph, output, dims.data(), num_dims, status);
if (TF_GetCode(status) != TF_OK)
{
std::cout << "Can't get get tensor shape" << std::endl;
continue;
}
std::cout << " [";
for (int d = 0; d < num_dims; ++d)
{
std::cout << dims[d];
if (d < num_dims - 1)
{
std::cout << ", ";
}
}
std::cout << "]" << std::endl;
}
TF_DeleteStatus(status);
}
void PrintTensorInfo(TF_Graph* graph, const char* layer_name,int printInputs,int printOutputs)
{
//std::cout << "PrintTensorInfo\n";
std::cout << "Tensor: " << layer_name;
TF_Operation* op = TF_GraphOperationByName(graph, layer_name);
if (op == nullptr)
{
std::cout << "Could not get " << layer_name << std::endl;
return;
}
const int num_inputs = TF_OperationNumInputs(op);
const int num_outputs = TF_OperationNumOutputs(op);
std::cout << " inputs: " << num_inputs << "\n outputs: " << num_outputs << std::endl;
if (printInputs)
{
PrintInputs(graph, op);
}
if (printOutputs)
{
PrintOutputs(graph, op);
}
}
void PrintOpInputs(TF_Graph*, TF_Operation* op)
{
const int num_inputs = TF_OperationNumInputs(op);
std::cout << "Number inputs: " << num_inputs << std::endl;
for (int i = 0; i < num_inputs; ++i)
{
const TF_Input input = {op, i};
const TF_DataType type = TF_OperationInputType(input);
std::cout << std::to_string(i) << " type : " << TFDataTypeToString(type) << std::endl;
}
}
void PrintOpOutputs(TF_Graph* graph, TF_Operation* op)
{
TF_Status* status = TF_NewStatus();
const int num_outputs = TF_OperationNumOutputs(op);
std::cout << "Number outputs: " << num_outputs << std::endl;
for (int i = 0; i < num_outputs; ++i)
{
const TF_Output output = {op, i};
const TF_DataType type = TF_OperationOutputType(output);
std::cout << std::to_string(i) << " type : " << TFDataTypeToString(type);
const int num_dims = TF_GraphGetTensorNumDims(graph, output, status);
if (TF_GetCode(status) != TF_OK)
{
std::cout << "Can't get tensor dimensionality" << std::endl;
continue;
}
std::cout << " dims: " << num_dims;
if (num_dims <= 0)
{
std::cout << " []" << std::endl;;
continue;
}
std::vector<std::int64_t> dims(num_dims);
TF_GraphGetTensorShape(graph, output, dims.data(), num_dims, status);
if (TF_GetCode(status) != TF_OK)
{
std::cout << "Can't get get tensor shape" << std::endl;
continue;
}
std::cout << " [";
for (int j = 0; j < num_dims; ++j)
{
std::cout << dims[j];
if (j < num_dims - 1)
{
std::cout << ",";
}
}
std::cout << "]" << std::endl;
}
TF_DeleteStatus(status);
}
void PrintOp(TF_Graph* graph)
{
TF_Operation* op;
std::size_t pos = 0;
while ((op = TF_GraphNextOperation(graph, &pos)) != nullptr)
{
const char* name = TF_OperationName(op);
const char* type = TF_OperationOpType(op);
const char* device = TF_OperationDevice(op);
const int num_outputs = TF_OperationNumOutputs(op);
const int num_inputs = TF_OperationNumInputs(op);
std::cout << pos << ": " << name << " type: " << type << " device: " << device << " number inputs: " << num_inputs << " number outputs: " << num_outputs << std::endl;
PrintOpInputs(graph, op);
PrintOpOutputs(graph, op);
std::cout << std::endl;
}
}
int listNodesMN(const char * label , TF_Graph* graph)
{
size_t pos = 0;
TF_Operation* oper;
fprintf(stdout, "Nodes list : \n");
while ((oper = TF_GraphNextOperation(graph, &pos)) != nullptr)
{
fprintf(stderr," %s - %s \n",label,TF_OperationName(oper));
}
return 1;
}
} // namespace tf_utils
@@ -0,0 +1,113 @@
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT
// Copyright (c) 2018 - 2019 Daniil Goncharov <neargye@gmail.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#pragma once
#if defined(_MSC_VER)
# if !defined(COMPILER_MSVC)
# define COMPILER_MSVC // Set MSVC visibility of exported symbols in the shared library.
# endif
# pragma warning(push)
# pragma warning(disable : 4190)
#endif
#include <tensorflow/c/c_api.h> // TensorFlow C API header
#include <cstddef>
#include <cstdint>
#include <vector>
namespace tf_utils {
TF_Graph* LoadGraph(const char* graphPath);
void DeleteGraph(TF_Graph* graph);
TF_Session* CreateSession(TF_Graph* graph);
void DeleteSession(TF_Session* session);
TF_Code RunSession(TF_Session* session,
const TF_Output* inputs, TF_Tensor* const* input_tensors, std::size_t ninputs,
const TF_Output* outputs, TF_Tensor** output_tensors, std::size_t noutputs);
TF_Code RunSession(TF_Session* session,
const std::vector<TF_Output>& inputs, const std::vector<TF_Tensor*>& input_tensors,
const std::vector<TF_Output>& outputs, std::vector<TF_Tensor*>& output_tensors);
TF_Tensor* CreateTensor(TF_DataType data_type,
const std::int64_t* dims, std::size_t num_dims,
const void* data, std::size_t len);
template <typename T>
TF_Tensor* CreateTensor(TF_DataType data_type, const std::vector<std::int64_t>& dims, const std::vector<T>& data) {
return CreateTensor(data_type,
dims.data(), dims.size(),
data.data(), data.size() * sizeof(T));
}
TF_Tensor* CreateEmptyTensor(TF_DataType data_type, const std::int64_t* dims, std::size_t num_dims);
TF_Tensor* CreateEmptyTensor(TF_DataType data_type, const std::vector<std::int64_t>& dims);
void DeleteTensor(TF_Tensor* tensor);
void DeleteTensors(const std::vector<TF_Tensor*>& tensors);
void SetTensorsData(TF_Tensor* tensor, const void* data, std::size_t len);
void PrintTensorInfo(TF_Graph* graph, const char* layer_name,int printInputs,int printOutputs);
void PrintOp(TF_Graph* graph);
int listNodesMN(const char * label , TF_Graph* graph);
template <typename T>
void SetTensorsData(TF_Tensor* tensor, const std::vector<T>& data) {
SetTensorsData(tensor, data.data(), data.size() * sizeof(T));
}
template <typename T>
std::vector<T> GetTensorsData(const TF_Tensor* tensor) {
auto data = static_cast<T*>(TF_TensorData(tensor));
if (data == nullptr) {
return {};
}
return {data, data + (TF_TensorByteSize(tensor) / TF_DataTypeSize(TF_TensorType(tensor)))};
}
template <typename T>
std::vector<std::vector<T> > GetTensorsData(const std::vector<TF_Tensor*>& tensors) {
std::vector<std::vector<T> > data;
data.reserve(tensors.size());
for (const auto t : tensors) {
data.push_back(GetTensorsData<T>(t));
}
return data;
}
} // namespace tf_utils
#if defined(_MSC_VER)
# pragma warning(pop)
#endif