I'm trying to load and run a TensorFlow graph using the C API (I need to build outside of the TensorFlow project, and preferably without Bazel, so can't use C++).
The graph is a 3-layer LSTM-RNN which classifies feature vectors of 3 elements into one of 9 classes. The graph is built and trained in Python, and I've tested it in both Python and C++.
So far, I've got the graph loading, however I'm having trouble running the session once the graph is loaded. I've done a fair bit of digging around, but I've only found one example using the C API (here), and that doesn't include running the graph.
I've managed to put together the following, but it produces a segmentation fault (I can successfully run the code if I comment out the TF_SessionRun() call, but I get the seg fault when TF_SessionRun() is included). Here's the code:
#include "tensorflow/c/c_api.h"
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <assert.h>
#include <vector>
#include <algorithm>
#include <iterator>
TF_Buffer* read_file(const char* file);
void free_buffer(void* data, size_t length) {
free(data);
}
static void Deallocator(void* data, size_t length, void* arg) {
free(data);
}
int main() {
// Use read_file to get graph_def as TF_Buffer*
TF_Buffer* graph_def = read_file("tensorflow_model/constant_graph_weights.pb");
TF_Graph* graph = TF_NewGraph();
// Import graph_def into graph
TF_Status* status = TF_NewStatus();
TF_ImportGraphDefOptions* graph_opts = TF_NewImportGraphDefOptions();
TF_GraphImportGraphDef(graph, graph_def, graph_opts, status);
if (TF_GetCode(status) != TF_OK) {
fprintf(stderr, "ERROR: Unable to import graph %s", TF_Message(status));
return 1;
}
else {
fprintf(stdout, "Successfully imported graph\n");
}
// Configure input & provide dummy values
const int num_bytes = 3 * sizeof(float);
const int num_bytes_out = 9 * sizeof(int);
int64_t dims[] = {3};
int64_t out_dims[] = {9};
float values[3] = {-1.04585315e+03, 1.25702492e+02, 1.11165466e+02};
// Setup graph inputs
std::vector<TF_Tensor*> input_values;
TF_Operation* input_op = TF_GraphOperationByName(graph, "lstm_1_input");
TF_Output inputs = {input_op, 0};
TF_Tensor* input = TF_NewTensor(TF_FLOAT, dims, 1, &values, num_bytes, &Deallocator, 0);
input_values.push_back(input);
// Setup graph outputs
TF_Operation* output_op = TF_GraphOperationByName(graph, "output_node0");
TF_Output outputs = {output_op, 0};
std::vector<TF_Tensor*> output_values(9, nullptr);
// Run graph
fprintf(stdout, "Running session...\n");
TF_SessionOptions* sess_opts = TF_NewSessionOptions();
TF_Session* session = TF_NewSession(graph, sess_opts, status);
assert(TF_GetCode(status) == TF_OK);
TF_SessionRun(session, nullptr,
&inputs, &input_values[0], 3,
&outputs, &output_values[0], 9,
nullptr, 0, nullptr, status);
fprintf(stdout, "Successfully run session\n");
TF_CloseSession(session, status);
TF_DeleteSession(session, status);
TF_DeleteSessionOptions(sess_opts);
TF_DeleteImportGraphDefOptions(graph_opts);
TF_DeleteGraph(graph);
TF_DeleteStatus(status);
return 0;
}
TF_Buffer* read_file(const char* file) {
FILE *f = fopen(file, "rb");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
void* data = malloc(fsize);
fread(data, fsize, 1, f);
fclose(f);
TF_Buffer* buf = TF_NewBuffer();
buf->data = data;
buf->length = fsize;
buf->data_deallocator = free_buffer;
return buf;
}
I'm not sure exactly where I'm going wrong with TF_SessionRun, so any help would be greatly appreciated!
Update: I've set a break point at the TF_SessionRun call in gdb, and as I step through it, I first get:
Thread 1 received signal SIGSEGV, Segmentation fault.
0x0000000100097650 in ?? ()
followed by:
"Cannot find bounds of current function"
I initially thought this was as the TensorFlow library wasn't compiled with debug symbols, but have since compiled it with debug symbols and get the same output in gdb.
Since my original post I found a TensorFlow C example here (however the author points out that it's untested). As such, I've since re-written my code according to their example, and have double checked everything with TensorFlow's c_api.h header file. I'm also now calling the C API from a C++ file (as that's what's done in the above example). Despite all this, I'm still getting the same output from gdb.
Update 2: To ensure that my graph is loading properly, I've used some of the TF_Operation functions in the C API (TF_GraphNextOperation() and TF_OperationName()) to check the graph operations, and have compared these with the operations when loading the graph in Python. The output looks correct, and I can retrieve properties from the operations (e.g. using TF_OperationNumOutputs()), so it appears the graph is definitely loading correctly.
Advice from someone with experience using TensorFlow's C API would be greatly appreciated.