mirror of
https://github.com/storytold/storyteller-ml.git
synced 2026-10-16 00:13:07 +00:00
Add MocapNET
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user