Skip to content

Commit

Permalink
Merge pull request #777 from roboflow/fix/issue_with_2_step_workflow_…
Browse files Browse the repository at this point in the history
…and_continue_if

Fixing the bug with two stage workflow and continue-if failing when nothing gets detected by primary model
  • Loading branch information
PawelPeczek-Roboflow authored Nov 6, 2024
2 parents 34171b9 + 0875487 commit ef8ea22
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -419,11 +419,11 @@ def get_compound_parameter_value(
result[nested_element.parameter_specification.nested_element_key] = (
non_compound_parameter_value
)
if non_compound_indices:
if non_compound_indices is not None:
batch_indices.append(non_compound_indices)
ensure_compound_input_indices_match(indices=batch_indices)
result_indices = None
if batch_indices:
if len(batch_indices) > 0:
result_indices = batch_indices[0]
return result, result_indices

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import numpy as np

from inference.core.env import WORKFLOWS_MAX_CONCURRENT_STEPS
from inference.core.managers.base import ModelManager
from inference.core.workflows.core_steps.common.entities import StepExecutionMode
from inference.core.workflows.execution_engine.core import ExecutionEngine

TWO_STAGE_WORKFLOW_WITH_FLOW_CONTROL = {
"version": "1.0",
"inputs": [{"type": "WorkflowImage", "name": "image"}],
"steps": [
{
"type": "roboflow_core/roboflow_object_detection_model@v1",
"name": "general_detection",
"image": "$inputs.image",
"model_id": "yolov8n-640",
"class_filter": ["dog"],
},
{
"type": "roboflow_core/dynamic_crop@v1",
"name": "cropping",
"image": "$inputs.image",
"predictions": "$steps.general_detection.predictions",
},
{
"type": "roboflow_core/roboflow_classification_model@v1",
"name": "breds_classification",
"image": "$steps.cropping.crops",
"model_id": "dog-breed-xpaq6/1",
},
{
"type": "roboflow_core/continue_if@v1",
"name": "continue_if",
"condition_statement": {
"type": "StatementGroup",
"statements": [
{
"type": "BinaryStatement",
"left_operand": {
"type": "DynamicOperand",
"operand_name": "predictions",
"operations": [
{
"type": "ClassificationPropertyExtract",
"property_name": "top_class_confidence",
}
],
},
"comparator": {"type": "(Number) >="},
"right_operand": {"type": "StaticOperand", "value": 0.35},
}
],
},
"evaluation_parameters": {
"predictions": "$steps.breds_classification.predictions"
},
"next_steps": ["$steps.property_definition"],
},
{
"type": "roboflow_core/property_definition@v1",
"name": "property_definition",
"operations": [
{"type": "ClassificationPropertyExtract", "property_name": "top_class"}
],
"data": "$steps.breds_classification.predictions",
},
],
"outputs": [
{
"type": "JsonField",
"name": "class_name",
"selector": "$steps.property_definition.output",
},
],
}


def test_two_stage_workflow_with_flow_control_when_there_is_nothing_predicted_from_first_stage_model(
model_manager: ModelManager,
crowd_image: np.ndarray,
roboflow_api_key: str,
) -> None:
# given
workflow_init_parameters = {
"workflows_core.model_manager": model_manager,
"workflows_core.api_key": roboflow_api_key,
"workflows_core.step_execution_mode": StepExecutionMode.LOCAL,
}
execution_engine = ExecutionEngine.init(
workflow_definition=TWO_STAGE_WORKFLOW_WITH_FLOW_CONTROL,
init_parameters=workflow_init_parameters,
max_concurrent_steps=WORKFLOWS_MAX_CONCURRENT_STEPS,
)

# when
result = execution_engine.run(
runtime_parameters={
"image": crowd_image,
}
)

assert isinstance(result, list), "Expected list to be delivered"
assert len(result) == 1, "Expected 1 element in the output for one input image"
assert set(result[0].keys()) == {
"class_name",
}, "Expected all declared outputs to be delivered"
assert (
len(result[0]["class_name"]) == 0
), "Expected no prediction from 2nd model, as no dogs detected"


def test_two_stage_workflow_with_flow_control_when_there_is_something_predicted_from_first_stage_model(
model_manager: ModelManager,
dogs_image: np.ndarray,
roboflow_api_key: str,
) -> None:
# given
workflow_init_parameters = {
"workflows_core.model_manager": model_manager,
"workflows_core.api_key": roboflow_api_key,
"workflows_core.step_execution_mode": StepExecutionMode.LOCAL,
}
execution_engine = ExecutionEngine.init(
workflow_definition=TWO_STAGE_WORKFLOW_WITH_FLOW_CONTROL,
init_parameters=workflow_init_parameters,
max_concurrent_steps=WORKFLOWS_MAX_CONCURRENT_STEPS,
)

# when
result = execution_engine.run(
runtime_parameters={
"image": dogs_image,
}
)

assert isinstance(result, list), "Expected list to be delivered"
assert len(result) == 1, "Expected 1 element in the output for one input image"
assert set(result[0].keys()) == {
"class_name",
}, "Expected all declared outputs to be delivered"
assert result[0]["class_name"] == [
"116.Parson_russell_terrier",
None,
], "Expected one crop to be passed by continue_if block and the other failed"
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ def test_keypoint_visualization_block_nocopy() -> None:
== start_image.__array_interface__["data"][0]
)


def test_keypoint_visualization_block_no_predictions() -> None:
# given
block = KeypointVisualizationBlockV1()
Expand All @@ -374,7 +375,7 @@ def test_keypoint_visualization_block_no_predictions() -> None:
predictions=empty_predictions,
copy_image=True,
annotator_type="edge",
color="#A351FB",
color="#A351FB",
text_color="black",
text_scale=0.5,
text_thickness=1,
Expand All @@ -389,7 +390,7 @@ def test_keypoint_visualization_block_no_predictions() -> None:

# dimensions of output match input
assert output.get("image").numpy_image.shape == (1000, 1000, 3)

# check if the image is unchanged since there were no predictions
assert np.array_equal(
output.get("image").numpy_image, np.zeros((1000, 1000, 3), dtype=np.uint8)
Expand Down

0 comments on commit ef8ea22

Please sign in to comment.