Repository navigation
Fix MDP partitioning for scoped ONNX aliases #1430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6bc1e38
2fb4bfd
30d0c30
37b20b0
ff19cf7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,6 +29,8 @@ | |
| from QEfficient.compile.mdp_generator import ( | ||
| _get_layer_num_from_inputs, | ||
| _layer_partition_bounds, | ||
| generate_disagg_mdp_intersection_config, | ||
| precheck_and_autofix_mdp_partition_order, | ||
| ) | ||
| from QEfficient.transformers.models.modeling_auto import QEFFAutoModelForCausalLM | ||
|
|
||
|
|
@@ -789,6 +791,161 @@ def test_mdp_disagg_json_is_created(self, compile_workspace): | |
| disagg_files = list(compile_dir.glob("mdp_disagg_4d_2p.json")) | ||
| assert len(disagg_files) == 1, "Expected exactly one mdp_disagg_4d_2p.json in compile_dir" | ||
|
|
||
| def test_intersection_repairs_scoped_alias_to_compiler_partition(self, tmp_path: Path): | ||
| """Intersection moves an unscoped alias to the compiler-assigned partition.""" | ||
| onnx_path = tmp_path / "scoped_alias.onnx" | ||
| model = helper.make_model( | ||
| helper.make_graph( | ||
| [ | ||
| helper.make_node( | ||
| "Identity", | ||
| inputs=["input"], | ||
| outputs=["hidden0"], | ||
| name="/language_model/layers.0/hidden", | ||
| ), | ||
| helper.make_node( | ||
| "Identity", | ||
| inputs=["input"], | ||
| outputs=["scoped_hidden"], | ||
| name="/language_model/Gather_5", | ||
| ), | ||
| helper.make_node( | ||
| "Identity", | ||
| inputs=["input"], | ||
| outputs=["hidden1"], | ||
| name="/language_model/layers.1/hidden", | ||
| ), | ||
| helper.make_node( | ||
| "Identity", | ||
| inputs=["input"], | ||
| outputs=["output"], | ||
| name="/Gather_5", | ||
| ), | ||
| ], | ||
| name="scoped_alias_graph", | ||
| inputs=[helper.make_tensor_value_info("input", TensorProto.FLOAT, [1])], | ||
| outputs=[helper.make_tensor_value_info("output", TensorProto.FLOAT, [1])], | ||
| ), | ||
| opset_imports=[helper.make_opsetid("", 17)], | ||
| ) | ||
| onnx.save(model, onnx_path) | ||
|
|
||
| compiler_dump_path = tmp_path / "compiler_dump.json" | ||
| compiler_dump_path.write_text( | ||
| json.dumps( | ||
| { | ||
| "partitions": [ | ||
| { | ||
| "nodeList": [ | ||
| "/language_model/layers.0/hidden", | ||
| "/Gather_5", | ||
| ] | ||
| }, | ||
| {"nodeList": ["/language_model/layers.1/hidden"]}, | ||
| ] | ||
| } | ||
| ) | ||
| ) | ||
|
|
||
| mdp_json = generate_disagg_mdp_intersection_config( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please extend this regression to run precheck_and_autofix_mdp_partition_order() after generate_disagg_mdp_intersection_config() and assert /Gather_5 is still retained. The production path runs this precheck after the scoped-alias repair, so the current test may pass even if the precheck later removes /Gather_5 before the final MDP JSON is written. |
||
| onnx_path=str(onnx_path), | ||
| compiler_dump_path=str(compiler_dump_path), | ||
| num_devices=2, | ||
| num_partitions=2, | ||
| num_layers=2, | ||
| ) | ||
|
|
||
| precheck_removed = precheck_and_autofix_mdp_partition_order( | ||
| onnx_path=str(onnx_path), | ||
| mdp_json=mdp_json, | ||
| ) | ||
|
|
||
| assert precheck_removed == 0 | ||
| assert "/Gather_5" in mdp_json["partitions"][0]["nodeList"] | ||
| assert mdp_json["partitions"][0]["nodeList"] == [ | ||
| "/language_model/layers.0/hidden", | ||
| "/Gather_5", | ||
| ] | ||
| assert mdp_json["partitions"][1]["nodeList"] == ["/language_model/layers.1/hidden"] | ||
|
|
||
| def test_intersection_skips_alias_move_that_follows_consumer(self, tmp_path: Path): | ||
| """Intersection keeps a producer in place when relocation would reverse its dependency.""" | ||
| onnx_path = tmp_path / "scoped_alias_dependency.onnx" | ||
| model = helper.make_model( | ||
| helper.make_graph( | ||
| [ | ||
| helper.make_node( | ||
| "Identity", | ||
| inputs=["input"], | ||
| outputs=["hidden0"], | ||
| name="/language_model/layers.0/hidden", | ||
| ), | ||
| helper.make_node( | ||
| "Identity", | ||
| inputs=["input"], | ||
| outputs=["scoped_alias"], | ||
| name="/language_model/Gather_9", | ||
| ), | ||
| helper.make_node( | ||
| "Identity", | ||
| inputs=["input"], | ||
| outputs=["producer_output"], | ||
| name="/Gather_9", | ||
| ), | ||
| helper.make_node( | ||
| "Identity", | ||
| inputs=["producer_output"], | ||
| outputs=["consumer_output"], | ||
| name="/language_model/Gather_11", | ||
| ), | ||
| helper.make_node( | ||
| "Identity", | ||
| inputs=["input"], | ||
| outputs=["hidden1"], | ||
| name="/language_model/layers.1/hidden", | ||
| ), | ||
| ], | ||
| name="scoped_alias_dependency_graph", | ||
| inputs=[helper.make_tensor_value_info("input", TensorProto.FLOAT, [1])], | ||
| outputs=[helper.make_tensor_value_info("consumer_output", TensorProto.FLOAT, [1])], | ||
| ), | ||
| opset_imports=[helper.make_opsetid("", 17)], | ||
| ) | ||
| onnx.save(model, onnx_path) | ||
|
|
||
| compiler_dump_path = tmp_path / "compiler_dump.json" | ||
| compiler_dump_path.write_text( | ||
| json.dumps( | ||
| { | ||
| "partitions": [ | ||
| { | ||
| "nodeList": [ | ||
| "/language_model/layers.0/hidden", | ||
| "/language_model/Gather_11", | ||
| ] | ||
| }, | ||
| {"nodeList": ["/Gather_9", "/language_model/layers.1/hidden"]}, | ||
| ] | ||
| } | ||
| ) | ||
| ) | ||
|
|
||
| mdp_json = generate_disagg_mdp_intersection_config( | ||
| onnx_path=str(onnx_path), | ||
| compiler_dump_path=str(compiler_dump_path), | ||
| num_devices=2, | ||
| num_partitions=2, | ||
| num_layers=2, | ||
| ) | ||
|
|
||
| precheck_removed = precheck_and_autofix_mdp_partition_order( | ||
| onnx_path=str(onnx_path), | ||
| mdp_json=mdp_json, | ||
| ) | ||
|
|
||
| assert precheck_removed == 0 | ||
| assert "/Gather_9" in mdp_json["partitions"][0]["nodeList"] | ||
|
|
||
| def test_mdp_disagg_json_has_two_partitions(self, compile_workspace): | ||
| """mdp_disagg_4d_2p.json contains exactly two partitions.""" | ||
| compile_dir, _, _ = self._run_mdp_compile(compile_workspace) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.