Repository navigation
dynamo: drop constant-folded weights before MIGraphX compiles (3x -> 2x peak memory) - #295
amarbarosys wants to merge 2 commits into
Conversation
Constant folding (pre_partition_pass) materializes GPU copies of the weights (e.g. transposed Linear weights) inside each partitioned subgraph. lower_subgraph copied them into the MIGraphX program as literals and then compiled while they were still referenced, so the device held the eager model, the folded copies and MIGraphX's upload at once, and the folded blocks stayed reserved by the caching allocator for the life of the process. Once the interpreter has run, every get_attr tensor of the subgraph is a literal in the program. Drop the interpreter and the subgraph's get_attr references, collect (the graph modules sit in reference cycles) and empty the cache before MGXModule compiles. The eager model's own parameters are untouched; the caller still holds them. 24x Linear(8192, 8192) fp16 (3072 MiB of weights), torch 2.13 + ROCm 7.2, RX 7900 XTX, device memory on top of the eager model, two runs each: peak during compile +6217 -> +3138..3162 MiB held after compile +6217 -> +3119..3145 MiB Output unchanged (max abs diff 0). tests/dynamo 355 passed, 10 skipped (354 on master plus the new regression test); tests/dynamo/models 4 passed on both; tests/dynamo/quantization 16 passed, 2 failed on both (test_quant_LLM, transformers DynamicCache pytree, pre-existing). Adds tests/dynamo/test_lower_subgraph_dynamo.py, which fails on master and passes with this change.
No reference cycle holds the folded weights: once the interpreter is deleted and the subgraph's get_attr attributes are removed, their refcount reaches zero. With the cyclic GC disabled and no gc.collect(), 0 of 4 folded tensors are alive when MGXModule compiles (master: 4 of 4, still referenced by the subgraph). On gfx1100, 24x Linear(8192) fp16, three alternated rounds, peak above the eager model: master +6213 / +6213 / +6213 MiB with gc.collect +3162 / +3141 / +3141 MiB without +3141 / +3162 / +3141 MiB After compile +3141 MiB in every PR run; output identical to eager. tests/dynamo/test_lower_subgraph_dynamo.py passes.
|
Dropped the Tests on the new head: |
|
There is a |
|
Thanks, I had missed it. I measured it on the same setup (24x Linear(8192) fp16, gfx1100, 3 alternated rounds): |
Great! Im glad that flag works identically. I would like to make deallocate default but some users have run into issues with specific models. Ideally we want to make it more robust for when weights are shared between different modules and other edge cases so that it can be on by default |
|
Makes sense, closing this since |
Free constant-folded weights before MIGraphX compiles
Problem
torch.compile(model, backend="migraphx")holds about 3x the model's weight size in device memory at its peak and 2x after compile, counting the eager model:pre_partition_passconstant-folds the weights into GPU copies (e.g. transposedLinearweights) inside each partitioned subgraph.lower_subgraphcopies them into the MIGraphX program as literals, then compiles while they are still referenced, so the eager model, the folded copies and MIGraphX's upload are resident at once.Stage trace, 24x
Linear(8192, 8192)fp16 (3072 MiB of weights), device memory in use:pre_partition_passMGXModulecompile startMGXModulecompile endFix
Once the interpreter has run, every
get_attrtensor of the subgraph is a literal in the program.lower_subgraphnow drops the interpreter and the subgraph'sget_attrreferences, callstorch.cuda.empty_cache(), then builds theMGXModule. The user's model parameters are untouched (the caller still holds them), so this is not the opt-indeallocatepath from #215, which moves them to host and doubles host RSS.Results
torch 2.13.0+rocm7.2, ROCm 7.2, RX 7900 XTX (gfx1100), Linux; device memory on top of the eager model, two runs each:
tests/dynamotest_reduce_ops_dimfailuretests/dynamo/models(wide_resnet50_2, vit_b_16)tests/dynamowall time (interleaved runs)tests/dynamo/quantization(torchao 0.18): 16 passed, 2 failed on both master and this branch. The 2 failures aretest_quant_LLM(distilgpt2), which hitstransformersDynamicCachenot being registered as a pytree during tracing, independent of this change.Probe script (
python mem_probe.py; peak/after numbers above)Samples used VRAM from amdgpu sysfs every 10 ms during compile. Rerun before opening this PR: master +6209 / +6265 MiB peak, this PR +3177 / +3179 MiB, max abs diff 0.
Test:
tests/dynamo/test_lower_subgraph_dynamo.pylowers a subgraph withget_attrweights and asserts the folded constants are gone from the GraphModule and the output matches eager. It fails on master and passes on this branch.Breaking changes: none. The
deallocateoption is unchanged.Related: #215, #218.