TensorFlow
C++
Graph Loading
c_api.h
tensorflow.so

How to load a graph with tensorflow.so and c_api.h in c language?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

To load a TensorFlow graph from C through c_api.h, the normal workflow is to read a serialized GraphDef file into memory, import it into a TF_Graph, and then create a TF_Session for execution. The shared library tensorflow.so is just what you link against; the actual work happens through TensorFlow C API calls.

The Main TensorFlow C API Objects

A minimal graph-loading program usually needs these pieces:

  • 'TF_Buffer to hold the serialized graph bytes,'
  • 'TF_Graph to store the imported graph in memory,'
  • 'TF_Status to report errors,'
  • 'TF_Session to execute the graph,'
  • 'TF_ImportGraphDefOptions for graph import configuration.'

If you understand those objects, the loading sequence becomes much easier to follow.

Step 1: Read the Graph File Into a TF_Buffer

A frozen graph or other serialized GraphDef is just a byte file, often named model.pb. First read it into memory and wrap it in a TensorFlow buffer.

c
1#include <stdio.h>
2#include <stdlib.h>
3#include <tensorflow/c/c_api.h>
4
5TF_Buffer* ReadBufferFromFile(const char* file) {
6    FILE* f = fopen(file, "rb");
7    if (f == NULL) return NULL;
8
9    fseek(f, 0, SEEK_END);
10    long size = ftell(f);
11    fseek(f, 0, SEEK_SET);
12
13    void* data = malloc(size);
14    if (data == NULL) {
15        fclose(f);
16        return NULL;
17    }
18
19    fread(data, size, 1, f);
20    fclose(f);
21
22    TF_Buffer* buffer = TF_NewBuffer();
23    buffer->data = data;
24    buffer->length = size;
25    buffer->data_deallocator = free;
26    return buffer;
27}

This helper hands ownership of the allocated byte block to the TensorFlow buffer so it can be cleaned up later.

Step 2: Import the Graph Definition

Once the bytes are available, create a graph object and import the graph definition.

c
1TF_Status* status = TF_NewStatus();
2TF_Graph* graph = TF_NewGraph();
3TF_Buffer* graph_def = ReadBufferFromFile("model.pb");
4TF_ImportGraphDefOptions* import_opts = TF_NewImportGraphDefOptions();
5
6TF_GraphImportGraphDef(graph, graph_def, import_opts, status);
7
8if (TF_GetCode(status) != TF_OK) {
9    fprintf(stderr, "Import error: %s\n", TF_Message(status));
10    return 1;
11}

If status is not TF_OK, the graph was not imported successfully. That usually means the file is invalid, incompatible, or not actually a serialized graph definition.

Step 3: Create a Session

Importing the graph only loads it into memory. To execute operations, create a session.

c
1TF_SessionOptions* session_opts = TF_NewSessionOptions();
2TF_Session* session = TF_NewSession(graph, session_opts, status);
3
4if (TF_GetCode(status) != TF_OK) {
5    fprintf(stderr, "Session creation error: %s\n", TF_Message(status));
6    return 1;
7}

At this point, the graph is loaded and the runtime is ready to execute it.

A Minimal Complete Example

c
1#include <stdio.h>
2#include <stdlib.h>
3#include <tensorflow/c/c_api.h>
4
5TF_Buffer* ReadBufferFromFile(const char* file) {
6    FILE* f = fopen(file, "rb");
7    if (!f) return NULL;
8
9    fseek(f, 0, SEEK_END);
10    long size = ftell(f);
11    fseek(f, 0, SEEK_SET);
12
13    void* data = malloc(size);
14    if (!data) {
15        fclose(f);
16        return NULL;
17    }
18
19    fread(data, size, 1, f);
20    fclose(f);
21
22    TF_Buffer* buffer = TF_NewBuffer();
23    buffer->data = data;
24    buffer->length = size;
25    buffer->data_deallocator = free;
26    return buffer;
27}
28
29int main(void) {
30    TF_Status* status = TF_NewStatus();
31    TF_Graph* graph = TF_NewGraph();
32    TF_Buffer* graph_def = ReadBufferFromFile("model.pb");
33    TF_ImportGraphDefOptions* import_opts = TF_NewImportGraphDefOptions();
34
35    TF_GraphImportGraphDef(graph, graph_def, import_opts, status);
36    if (TF_GetCode(status) != TF_OK) {
37        fprintf(stderr, "Graph import failed: %s\n", TF_Message(status));
38        return 1;
39    }
40
41    TF_SessionOptions* session_opts = TF_NewSessionOptions();
42    TF_Session* session = TF_NewSession(graph, session_opts, status);
43    if (TF_GetCode(status) != TF_OK) {
44        fprintf(stderr, "Session creation failed: %s\n", TF_Message(status));
45        return 1;
46    }
47
48    printf("Graph loaded successfully.\n");
49
50    TF_CloseSession(session, status);
51    TF_DeleteSession(session, status);
52    TF_DeleteSessionOptions(session_opts);
53    TF_DeleteImportGraphDefOptions(import_opts);
54    TF_DeleteBuffer(graph_def);
55    TF_DeleteGraph(graph);
56    TF_DeleteStatus(status);
57    return 0;
58}

This only loads the graph and creates the session. Real inference still requires locating input and output operations and building tensors.

GraphDef Versus SavedModel

One important distinction is that this pattern is for importing a serialized graph definition, often a .pb file. If your model is packaged as a SavedModel directory, the loading API is different. In that case, you typically use the SavedModel-specific session-loading entry point rather than importing raw graph bytes yourself.

Common Pitfalls

A common mistake is assuming that linking tensorflow.so is the same thing as loading a model. It is not. The shared library only provides the API and runtime implementation.

Another issue is importing the graph successfully but never checking TF_Status. The C API does not hide failures for you.

Developers also frequently leak objects by forgetting that most TF_New* calls have matching TF_Delete* cleanup functions.

Summary

  • Link against tensorflow.so, but load the model through the TensorFlow C API.
  • Read the serialized graph file into a TF_Buffer.
  • Import it into a TF_Graph with TF_GraphImportGraphDef.
  • Create a TF_Session before attempting inference.
  • Check TF_Status after important calls and clean up all TensorFlow objects explicitly.

Course illustration
Course illustration

All Rights Reserved.