Skip to main content

ModelGraph

The ModelGraph class represents the network being processed by hls4ml. It manages layers as nodes in a directed graph and provides methods for compilation, prediction, and synthesis.
class ModelGraph:
    def __init__(self, config, inputs=None, outputs=None, initial_index=0)

Parameters

config
HLSConfig
required
Configuration object containing backend and conversion settings.
inputs
list
default:"None"
List of input variable names. If None, determined automatically.
outputs
list
default:"None"
List of output variable names. If None, determined automatically.
initial_index
int
default:"0"
Starting index for layer numbering.

Attributes

config
HLSConfig
The model configuration.
graph
OrderedDict
Dictionary mapping layer names to Layer objects.
inputs
list
List of input layer names.
outputs
list
List of output layer names.
output_vars
dict
Dictionary mapping output names to Variable objects.

Creating ModelGraph

from_layer_list

Create a ModelGraph from a list of layer dictionaries.
@classmethod
ModelGraph.from_layer_list(
    config_dict, 
    layer_list, 
    inputs=None, 
    outputs=None,
    initial_index=0
)
config_dict
dict
required
Configuration dictionary.
layer_list
list
required
List of layer dictionaries with ‘name’ and ‘class_name’ keys.
inputs
list
default:"None"
Input layer names.
outputs
list
default:"None"
Output layer names.
model
ModelGraph
The constructed ModelGraph instance.

Example

import hls4ml

layer_list = [
    {'name': 'input', 'class_name': 'InputLayer', 'input_shape': [10]},
    {'name': 'dense1', 'class_name': 'Dense', 'n_in': 10, 'n_out': 64},
    {'name': 'relu1', 'class_name': 'Activation', 'activation': 'relu'},
    {'name': 'output', 'class_name': 'Dense', 'n_in': 64, 'n_out': 1}
]

config = hls4ml.utils.config.create_config(
    output_dir='my-hls-test',
    project_name='myproject'
)

model = hls4ml.model.ModelGraph.from_layer_list(
    config,
    layer_list,
    inputs=['input'],
    outputs=['output']
)

Core Methods

write

Write the generated C++ project to disk.
model.write()
Generates HLS C++ code and writes to the output directory specified in config.

compile

Compile the generated project for simulation.
model.compile()
Writes the project to disk and compiles it into a shared library that can be used for predict().

Example

import hls4ml
import numpy as np

# Convert model
hls_model = hls4ml.converters.convert_from_keras_model(
    keras_model,
    output_dir='my-hls-test'
)

# Compile
hls_model.compile()

# Test
X_test = np.random.rand(100, 10)
y_pred = hls_model.predict(X_test)

predict

Run inference on the compiled model.
model.predict(x, *args, **kwargs)
x
numpy.ndarray | list
required
Input data. For single input models, provide a numpy array. For multi-input models, provide a list of arrays.
predictions
numpy.ndarray | list
Model predictions. Single array for single output, list of arrays for multiple outputs.

Example

import numpy as np

# Single input/output
X = np.random.rand(10, 784).astype(np.float32)
y_pred = hls_model.predict(X)

# Multiple inputs
X1 = np.random.rand(10, 32).astype(np.float32)
X2 = np.random.rand(10, 16).astype(np.float32)
y_pred = hls_model.predict([X1, X2])

# Multiple outputs
y_pred1, y_pred2 = hls_model.predict(X)

build

Synthesize the design with HLS tools.
model.build(
    reset=False,
    csim=True,
    synth=True,
    cosim=False,
    validation=False,
    export=False,
    vsynth=False
)
reset
bool
default:"False"
Reset/clean the project before building.
csim
bool
default:"True"
Run C simulation.
synth
bool
default:"True"
Run HLS synthesis.
cosim
bool
default:"False"
Run C/RTL co-simulation.
validation
bool
default:"False"
Run validation tests.
export
bool
default:"False"
Export IP.
vsynth
bool
default:"False"
Run Vivado synthesis (place and route).
report
dict
Synthesis report with resource usage and timing information.

Example

import hls4ml

# Convert model
hls_model = hls4ml.converters.convert_from_keras_model(
    keras_model,
    output_dir='my-hls-test'
)

# Run synthesis
report = hls_model.build(
    csim=True,
    synth=True,
    cosim=True,
    export=True
)

print(f"Latency: {report['LatencyBest']} - {report['LatencyWorst']} cycles")
print(f"Interval: {report['IntervalMin']} - {report['IntervalMax']} cycles")
print(f"LUTs: {report['LUT']}")
print(f"FFs: {report['FF']}")
print(f"DSPs: {report['DSP']}")
print(f"BRAMs: {report['BRAM_18K']}")

trace

Run inference with layer-by-layer tracing.
model.trace(x)
x
numpy.ndarray
required
Input data for tracing.
result
tuple
Returns (predictions, trace_output) where trace_output is a dict mapping layer names to their outputs.

Example

import numpy as np

X_test = np.random.rand(5, 10).astype(np.float32)
predictions, trace = hls_model.trace(X_test)

# Inspect layer outputs
for layer_name, output in trace.items():
    print(f"{layer_name}: shape={output.shape}, mean={np.mean(output):.4f}")

Graph Manipulation

make_node

Create a new node (layer) for the graph.
model.make_node(
    kind, 
    name, 
    attributes, 
    inputs, 
    outputs=None,
    initialize=True
)
kind
str | type
required
Layer type (class name or class).
name
str
required
Unique name for the layer.
attributes
dict
required
Layer attributes and configuration.
inputs
list
required
List of input variable names.
outputs
list
default:"None"
List of output variable names. Defaults to [name].
initialize
bool
default:"True"
Call the layer’s initialize() method.
node
Layer
The created layer node.

Example

# Create a Dense layer node
node = model.make_node(
    kind='Dense',
    name='new_dense',
    attributes={
        'n_in': 64,
        'n_out': 32,
        'weight_data': weights,
        'bias_data': bias
    },
    inputs=['prev_layer'],
    outputs=['new_dense']
)

insert_node

Insert a node into the graph.
model.insert_node(node, before=None, input_idx=0)
node
Layer
required
Node to insert (created with make_node).
before
Layer
default:"None"
Insert before this node. If None, inserts after the node’s input.
input_idx
int
default:"0"
Input index for multi-input nodes.

remove_node

Remove a node from the graph.
model.remove_node(node)
node
Layer
required
Node to remove.
Automatically connects the previous node to the next node.

replace_node

Replace a node with another.
model.replace_node(old_node, new_node)
old_node
Layer
required
Node to replace.
new_node
Layer
required
Replacement node.

Example: Adding Quantization

# Get a layer
dense_layer = model.graph['dense_1']

# Create quantization node
quant_attrs = {
    'n_in': dense_layer.get_attr('n_out'),
    'precision': 'ap_fixed<8,4>'
}

quant_node = model.make_node(
    kind='ApplyAlpha',
    name='quant_dense_1',
    attributes=quant_attrs,
    inputs=dense_layer.outputs,
    outputs=['quant_dense_1']
)

# Insert after dense layer
model.insert_node(quant_node)

Layer Access

get_layers

Get all layers in the model.
model.get_layers()
layers
ValuesView
View of all Layer objects in the graph.

Example

for layer in model.get_layers():
    print(f"{layer.name}: {layer.class_name}")
    if hasattr(layer, 'weights'):
        for weight in layer.get_weights():
            print(f"  {weight.name}: {weight.shape}")

get_input_variables

Get input variables of the model.
model.get_input_variables()
variables
list
List of input Variable objects.

get_output_variables

Get output variables of the model.
model.get_output_variables()
variables
list
List of output Variable objects.

get_weight_variables

Get all weight variables in the model.
model.get_weight_variables()
variables
list
List of all weight Variable objects.

Example

# Print input/output info
for var in model.get_input_variables():
    print(f"Input: {var.name}, shape: {var.shape}, type: {var.type.precision}")

for var in model.get_output_variables():
    print(f"Output: {var.name}, shape: {var.shape}, type: {var.type.precision}")

# Count total parameters
total_params = sum(var.data_length for var in model.get_weight_variables())
print(f"Total parameters: {total_params}")

Optimization

apply_flow

Apply an optimization flow (collection of optimizer passes).
model.apply_flow(flow, reapply='single')
flow
str
required
Name of the flow to apply.
reapply
str
default:"single"
Reapplication strategy:
  • 'all': Reapply flow and all requirements
  • 'single': Apply flow, skip applied requirements
  • 'none': Skip if already applied

Example

import hls4ml

# Get model
hls_model = hls4ml.converters.convert_from_keras_model(keras_model)

# Apply optimization flow
hls_model.apply_flow('vivado:optimize')

# Apply custom optimization
hls_model.apply_flow('quantization')

Serialization

save

Save the ModelGraph to a file.
model.save(file_path)
file_path
str
required
Path to save the model (.fml format).

Example

# Save model
hls_model.save('my_model.fml')

# Load model
import hls4ml
loaded_model = hls4ml.converters.load_saved_model('my_model.fml')

# Use loaded model
loaded_model.compile()
predictions = loaded_model.predict(test_data)

HLSConfig

Configuration object managing model settings.
class HLSConfig:
    def __init__(self, config)

Methods

get_precision

Get precision for a layer and variable.
config.get_precision(layer, var='default')
result
tuple
Returns (precision, type_name) tuple.

get_reuse_factor

Get reuse factor for a layer.
config.get_reuse_factor(layer)
rf
int
The reuse factor.

get_strategy

Get implementation strategy for a layer.
config.get_strategy(layer)
strategy
str
Strategy: 'latency' or 'resource'.

Example

for layer in model.get_layers():
    rf = model.config.get_reuse_factor(layer)
    strategy = model.config.get_strategy(layer)
    precision, type_name = model.config.get_precision(layer)
    
    print(f"{layer.name}:")
    print(f"  ReuseFactor: {rf}")
    print(f"  Strategy: {strategy}")
    print(f"  Precision: {precision}")

See Also