> For the complete documentation index, see [llms.txt](https://deeplearning4j.konduit.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://deeplearning4j.konduit.ai/en-1.0.0-rewrite/model-import/overview-5.md).

# TensorFlow

### TensorFlow Direct Inference

The `nd4j-tensorflow` module runs TensorFlow frozen graphs natively using JavaCPP TF bindings. There is no conversion to a SameDiff graph; the TF runtime executes the graph directly. This is appropriate when you have a stable frozen graph and want low-overhead inference without the SameDiff import layer.

For models that need graph inspection or further training in Java, use [SameDiff TF import](https://github.com/KonduitAI/deeplearning4j-docs/blob/en-1.0.0-rewrite/docs/m2.1/model-import/samediff-import/tensorflow/README.md) instead.

***

### When to Use TF Direct vs SameDiff Import

| Requirement                            | TF Direct     | SameDiff TF Import |
| -------------------------------------- | ------------- | ------------------ |
| Pure inference, stable frozen graph    | Yes           | Yes                |
| Graph inspection in Java               | No            | Yes                |
| Further training in Java               | No            | Yes                |
| Dependency on TF native libraries      | Yes (JavaCPP) | No                 |
| Access TF-specific ops not in SameDiff | Yes           | No                 |

***

### Maven Dependency

```xml
<dependency>
    <groupId>org.nd4j</groupId>
    <artifactId>nd4j-tensorflow</artifactId>
    <version>${dl4j.version}</version>
</dependency>
```

The module bundles TensorFlow native libraries via JavaCPP presets for Linux x86\_64, Windows x86\_64, and macOS.

***

### Preparing the Model

TF direct inference requires a frozen graph (a protobuf where all `Variable` ops have been converted to constants). See [TensorFlow Import — Preparing Your Model](https://github.com/KonduitAI/deeplearning4j-docs/blob/en-1.0.0-rewrite/docs/m2.1/model-import/samediff-import/tensorflow/README.md#preparing-your-tensorflow-model) for Python export instructions.

***

### Running Inference

Use `TensorFlowRunner` to load and execute a frozen graph:

```java
import org.nd4j.tensorflow.conversion.graphrunner.GraphRunner;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

// Specify input names and output names
List<String> inputNames  = Arrays.asList("input_1");
List<String> outputNames = Arrays.asList("output/Softmax");

// Build the runner
GraphRunner runner = GraphRunner.builder()
        .graphPath("frozen_model.pb")
        .inputNames(inputNames)
        .outputNames(outputNames)
        .build();

// Prepare inputs
INDArray input = Nd4j.rand(1, 224, 224, 3).castTo(org.nd4j.linalg.api.buffer.DataType.FLOAT);
Map<String, INDArray> inputs = new LinkedHashMap<>();
inputs.put("input_1", input);

// Run
Map<String, INDArray> outputs = runner.run(inputs);
INDArray predictions = outputs.get("output/Softmax");
System.out.println("Shape: " + Arrays.toString(predictions.shape()));

runner.close();
```

***

### GraphRunner Builder Options

```java
GraphRunner runner = GraphRunner.builder()
        .graphPath("frozen_model.pb")      // path to frozen .pb file
        .inputNames(inputNames)             // list of placeholder node names
        .outputNames(outputNames)           // list of output node names to fetch
        .build();
```

`GraphRunner` is `AutoCloseable`:

```java
try (GraphRunner runner = GraphRunner.builder()
        .graphPath("frozen_model.pb")
        .inputNames(inputNames)
        .outputNames(outputNames)
        .build()) {

    Map<String, INDArray> result = runner.run(inputs);
}
```

***

### Data Format Notes

TensorFlow defaults to NHWC (channels-last) data format for images: `[batch, height, width, channels]`. This differs from ND4J's default NCHW. Construct your input `INDArray` in NHWC order for TF models that were not explicitly configured for NCHW.

```java
// NHWC: batch=1, height=224, width=224, channels=3
INDArray nhwcInput = Nd4j.rand(1, 224, 224, 3);
```

If your model uses `data_format='channels_first'` (NCHW), adjust accordingly:

```java
// NCHW: batch=1, channels=3, height=224, width=224
INDArray nchwInput = Nd4j.rand(1, 3, 224, 224);
```

***

### Getting Node Names

To find placeholder and output node names in a frozen graph:

```python
import tensorflow as tf

graph_def = tf.compat.v1.GraphDef()
with open('frozen_model.pb', 'rb') as f:
    graph_def.ParseFromString(f.read())

# Print all node names and types
for node in graph_def.node:
    print(f"{node.op:30s}  {node.name}")
```

***

### Complete Example

```java
import org.nd4j.tensorflow.conversion.graphrunner.GraphRunner;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;

public class TfDirectInferenceExample {

    public static void main(String[] args) throws Exception {
        String modelPath   = "frozen_model.pb";
        String inputName   = "input_1";
        String outputName  = "predictions/Softmax";

        try (GraphRunner runner = GraphRunner.builder()
                .graphPath(modelPath)
                .inputNames(Arrays.asList(inputName))
                .outputNames(Arrays.asList(outputName))
                .build()) {

            // NHWC image: batch=1, H=224, W=224, C=3
            INDArray image = Nd4j.rand(1, 224, 224, 3)
                    .castTo(org.nd4j.linalg.api.buffer.DataType.FLOAT);

            Map<String, INDArray> inputs = new LinkedHashMap<>();
            inputs.put(inputName, image);

            Map<String, INDArray> outputs = runner.run(inputs);
            INDArray softmax = outputs.get(outputName);

            int topClass = softmax.argMax(1).getInt(0);
            System.out.println("Predicted class: " + topClass);
        }
    }
}
```

***

### Troubleshooting

**Native library load failure**: the TF JavaCPP preset must match your platform. Verify that the artifact downloaded native libraries for your OS. On Linux, `LD_LIBRARY_PATH` may need to include the directory containing `libtensorflow.so`.

**Node name not found**: node names in TF frozen graphs are case-sensitive and include the full path (e.g., `conv1/Relu` not just `Relu`). Use the Python node listing snippet to find exact names.

**Variable op in graph**: `GraphRunner` requires a fully frozen graph. Variables that were not converted to constants cause runtime errors. Re-run the Python freezing step.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://deeplearning4j.konduit.ai/en-1.0.0-rewrite/model-import/overview-5.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
