Runtime parameters on exported pipelines
Exported .denkflow files from the Vision AI Hub can embed constant topic values — for example bounding-box filter thresholds (/iou_threshold, /score_threshold) or resize dimensions (/image_size).
If you need different values on each pipeline run without re-exporting the graph, treat those constants as runtime parameters: discover them with get_constant_values() on an uninitialized pipeline, release the baked-in values with remove_constant_value() before initialization, then publish your own tensors before every run().
When to use this
- Tune detection sensitivity per image, product line, or station
- A/B test threshold combinations in production
- Drive resize or filter settings from external configuration
This example builds on Basic object detection and assumes a typical object-detection export with a bounding-box filter node.
Workflow
- Discover — load the export and call
get_constant_values()beforeinitialize(). You get each topic name and its default value as a NumPy array (Python) or a raw buffer withDenkflowArrayDataType,DenkflowTensorType, and shape (C). - Release constants — call
remove_constant_value(topic)for each runtime parameter you intend to override. - Initialize once — call
initialize()and set up receivers. - Publish per run — before every
run(), publish your parameter values, then publish the image input.
get_topics() vs get_constant_values()Use get_constant_values() to discover exported constant names and default values before initialization. Use get_topics() after initialization to wire external inputs and outputs — it is not the right API for runtime-parameter discovery.
Discover constant topics and defaults
- Python
- C / C++
from denkflow import Pipeline
pipeline = Pipeline.from_denkflow("model.denkflow", pat="YOUR-PAT")
defaults = pipeline.get_constant_values()
for topic, array in defaults.items():
print(topic, array.dtype, array.shape, array)
runtime_parameter_topics = list(defaults.keys())
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "denkflow.h"
static void handle_error(enum DenkflowResult code, const char* fn) {
if (code != DenkflowResult_Ok) {
char* buf = (char*)malloc(DENKFLOW_ERROR_BUFFER_SIZE);
denkflow_get_last_error(buf);
printf("%s failed: %s\n", fn, buf);
free(buf);
exit(EXIT_FAILURE);
}
}
static size_t element_count(const DenkflowConstantValue* c) {
size_t count = 1;
for (size_t d = 0; d < c->shape_length; ++d) {
count *= c->shape[d];
}
return count;
}
int main(void) {
DenkflowPipeline* pipeline = NULL;
DenkflowHubLicenseSource* license = NULL;
DenkflowConstantValueArray* constants = NULL;
handle_error(denkflow_hub_license_source_from_pat(&license, "YOUR-PAT", NULL, NULL),
"denkflow_hub_license_source_from_pat");
handle_error(denkflow_pipeline_from_denkflow(&pipeline, "model.denkflow", (void*)license),
"denkflow_pipeline_from_denkflow");
handle_error(denkflow_pipeline_get_constant_values(&constants, pipeline),
"denkflow_pipeline_get_constant_values");
for (size_t i = 0; i < constants->constant_values_length; ++i) {
DenkflowConstantValue* c = &constants->constant_values[i];
printf("Runtime parameter: %s (tensor_type=%d, data_type=%d, shape_length=%zu)\n",
c->topic_name, (int)c->tensor_type, (int)c->data_type, c->shape_length);
if (c->data_type == DenkflowArrayDataType_Float32 && element_count(c) == 1) {
float default_value = *((const float*)c->data);
printf(" default float32 scalar: %f\n", default_value);
}
}
denkflow_constant_value_array_free(&constants);
denkflow_free_object((void**)&pipeline);
denkflow_free_object((void**)&license);
return 0;
}
Typical object-detection exports expose /iou_threshold and /score_threshold as runtime parameters. Topic names vary by export — always call get_constant_values() on your .denkflow file.
Override parameters on each run
Remove the constants you want to control, initialize once, then publish new values before every run().
- Python
- C / C++
import numpy as np
from denkflow import Pipeline, ImageTensor, BaseTensor
pat = "YOUR-PAT"
denkflow_path = "path/to/model/file.denkflow"
image_path = "path/to/an/image.jpg"
input_topic = "/image"
output_topic = "bounding_box_filter_node/filtered_bounding_boxes"
pipeline = Pipeline.from_denkflow(denkflow_path, pat=pat)
defaults = pipeline.get_constant_values()
for topic in defaults:
pipeline.remove_constant_value(topic)
pipeline.initialize()
receiver = pipeline.subscribe(output_topic)
for iou, score in [(0.7, 0.5), (0.5, 0.3)]:
pipeline.publish_tensor(
"/iou_threshold",
BaseTensor.from_numpy(np.array([iou], dtype=np.float32)),
)
pipeline.publish_tensor(
"/score_threshold",
BaseTensor.from_numpy(np.array([score], dtype=np.float32)),
)
pipeline.publish_image_tensor(input_topic, ImageTensor.from_file(image_path))
pipeline.run()
results = receiver.receive_bounding_box_tensor().to_objects(score)
print(f"IoU={iou}, score={score}: {len(results)} detections")
for box in results:
print(f" {box.class_label.name}: {box.confidence:.2f}")
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "denkflow.h"
static void handle_error(enum DenkflowResult code, const char* fn) {
printf("%s: %d", fn, (int)code);
if (code != DenkflowResult_Ok) {
char* buf = (char*)malloc(DENKFLOW_ERROR_BUFFER_SIZE);
denkflow_get_last_error(buf);
printf(" (%s)\n", buf);
free(buf);
exit(EXIT_FAILURE);
}
printf("\n");
}
static void publish_threshold(DenkflowInitializedPipeline* initialized,
const char* topic, float value) {
DenkflowBaseTensor* tensor = NULL;
float data[1] = { value };
size_t shape[1] = { 1 };
handle_error(denkflow_base_tensor_from_buffer(
&tensor, data, DenkflowArrayDataType_Float32, shape, 1),
"denkflow_base_tensor_from_buffer");
handle_error(denkflow_initialized_pipeline_publish_tensor(
initialized, topic, (void**)&tensor),
"denkflow_initialized_pipeline_publish_tensor");
}
int main(void) {
DenkflowPipeline* pipeline = NULL;
DenkflowInitializedPipeline* initialized = NULL;
DenkflowHubLicenseSource* license = NULL;
DenkflowConstantValueArray* constants = NULL;
DenkflowImageTensor* image = NULL;
DenkflowReceiverTensor* receiver = NULL;
DenkflowBoundingBoxTensor* bbox_tensor = NULL;
DenkflowBoundingBoxResults* results = NULL;
const char* denkflow_path = "path/to/model/file.denkflow";
const char* image_path = "path/to/an/image.jpg";
const char* input_topic = "/image";
const char* output_topic = "bounding_box_filter_node/filtered_bounding_boxes";
struct { float iou; float score; } runs[] = { {0.7f, 0.5f}, {0.5f, 0.3f} };
handle_error(denkflow_hub_license_source_from_pat(&license, "YOUR-PAT", NULL, NULL),
"denkflow_hub_license_source_from_pat");
handle_error(denkflow_pipeline_from_denkflow(&pipeline, denkflow_path, (void*)license),
"denkflow_pipeline_from_denkflow");
handle_error(denkflow_pipeline_get_constant_values(&constants, pipeline),
"denkflow_pipeline_get_constant_values");
for (size_t i = 0; i < constants->constant_values_length; ++i) {
handle_error(
denkflow_pipeline_remove_constant_value(pipeline, constants->constant_values[i].topic_name),
"denkflow_pipeline_remove_constant_value");
}
denkflow_constant_value_array_free(&constants);
handle_error(denkflow_initialize_pipeline(&initialized, &pipeline),
"denkflow_initialize_pipeline");
handle_error(denkflow_initialized_pipeline_subscribe(&receiver, initialized, output_topic),
"denkflow_initialized_pipeline_subscribe");
for (size_t r = 0; r < sizeof(runs) / sizeof(runs[0]); ++r) {
publish_threshold(initialized, "/iou_threshold", runs[r].iou);
publish_threshold(initialized, "/score_threshold", runs[r].score);
handle_error(denkflow_image_tensor_from_file(&image, image_path),
"denkflow_image_tensor_from_file");
handle_error(denkflow_initialized_pipeline_publish_tensor(
initialized, input_topic, (void **)&image),
"denkflow_initialized_pipeline_publish_tensor");
handle_error(denkflow_initialized_pipeline_run(initialized, 8000),
"denkflow_initialized_pipeline_run");
handle_error(denkflow_receiver_receive_bounding_box_tensor(&bbox_tensor, receiver),
"denkflow_receiver_receive_bounding_box_tensor");
handle_error(denkflow_bounding_box_tensor_to_objects(&results, bbox_tensor, runs[r].score),
"denkflow_bounding_box_tensor_to_objects");
printf("IoU=%.1f, score=%.1f: %zu detections\n",
runs[r].iou, runs[r].score, results->bounding_boxes_length);
denkflow_free_object((void**)&bbox_tensor);
denkflow_free_object((void**)&results);
}
denkflow_free_object((void**)&receiver);
denkflow_free_object((void**)&initialized);
denkflow_free_object((void**)&license);
return 0;
}
Tips and pitfalls
get_constant_values()must be called beforeinitialize()— same timing asset_constant_valueandremove_constant_value.remove_constant_valueonly works on topics that have a constant — useget_constant_values()to confirm which topics are set before removing.- C: cast
datausingdata_type— eachDenkflowConstantValueincludes aDenkflowArrayDataTypeenum. Match the enum when castingdata(for exampleDenkflowArrayDataType_Float32→(const float*)c->data). Element count is the product ofshape[]. Free the result withdenkflow_constant_value_array_free(&constants). - Use
publish_tensorfor all runtime inputs in C — build a typed tensor (denkflow_base_tensor_from_bufferfor numeric values,denkflow_image_tensor_from_filefor images), then calldenkflow_initialized_pipeline_publish_tensorwith a(void**)cast. Python still has separatepublish_image_tensorandpublish_tensormethods. - Constants you do not remove keep their exported defaults — only remove topics you intend to supply yourself each run.
- See also — Core concepts: constant topic values for the underlying topic naming rules.