-
Notifications
You must be signed in to change notification settings - Fork 22.6k
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
suggest constraints to specify for export based on generated shape guards #98463
Conversation
…ards The design of export API expects constraints to be specified on dynamic dimensions, while assuming all other dimensions are static by default. However a user who wishes to export a model may not be fully familiar with the code to plan what to specify. This diff provides support for discovering constraints to specify. The basic idea is to take the set of generated shape guards and convert them into appropriate constraints. However, we usually generate a LOT of shape guards, and there is often a LOT of redundancy in them. Thus, we also need to simplify the guards so that our suggested constraints are concise yet capture the information content in the guards. The algorithm for simplification uses `sympy` under the hood, but very surgically to avoid any risk of blowing up. See comments inline for a full description. Briefly, 1. We consider only univariate inequalities, and among them, solve for equalities first. 2. We substitute these exact solutions to convert multivariate inequalities progressively into univariate. 3. Remaining univariate inequalities are solved using `sympy.solvers.inequalities.reduce_inequalities`. 4. As pre-processing, we also eliminate all `//` and `%` operations to generate a set of linear congruence guards, and solve these using `sympy.ntheory.modular.solve_congruence`. The results are quite dramatic. For example, an internal model produced several hundreds of guards with `dynamic_shapes=True`, which were pretty much inscrutable for humans. The summary contains around 30 dimensions that were specialized and 3 constraints on dynamic dimensions. The output format looks like this: ``` The following dimensions have been specialized and CANNOT be dynamic. NOTE: Specializations will happen by default with `assume_static_by_default=True`. L['foo']['bar'].size()[0] == 4 ... L['baz']['qux'].size()[3] == 96 The following dimensions CAN be dynamic. You can use the following code to specify the constraints they must satisfy: constraints=[ dynamic_dim(L['blah']['bleh'], 1) == dynamic_dim(L['blah']['bloh'], 1), ..., 2 <= dynamic_dim(L['blah']['bloh'], 1), ] ``` Differential Revision: [D44731747](https://our.internmc.facebook.com/intern/diff/D44731747/) [ghstack-poisoned]
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/98463
Note: Links to docs will display an error until the docs builds have been completed. ❗ 1 Active SEVsThere are 1 currently active SEVs. If your PR is affected, please view them below: ❌ 2 FailuresAs of commit 8b02491: NEW FAILURES - The following jobs have failed:
This comment was automatically generated by Dr. CI and updates every 15 minutes. |
…ards The design of export API expects constraints to be specified on dynamic dimensions, while assuming all other dimensions are static by default. However a user who wishes to export a model may not be fully familiar with the code to plan what to specify. This diff provides support for discovering constraints to specify. The basic idea is to take the set of generated shape guards and convert them into appropriate constraints. However, we usually generate a LOT of shape guards, and there is often a LOT of redundancy in them. Thus, we also need to simplify the guards so that our suggested constraints are concise yet capture the information content in the guards. The algorithm for simplification uses `sympy` under the hood, but very surgically to avoid any risk of blowing up. See comments inline for a full description. Briefly, 1. We consider only univariate inequalities, and among them, solve for equalities first. 2. We substitute these exact solutions to convert multivariate inequalities progressively into univariate. 3. Remaining univariate inequalities are solved using `sympy.solvers.inequalities.reduce_inequalities`. 4. As pre-processing, we also eliminate all `//` and `%` operations to generate a set of linear congruence guards, and solve these using `sympy.ntheory.modular.solve_congruence`. The results are quite dramatic. For example, an internal model produced several hundreds of guards with `dynamic_shapes=True`, which were pretty much inscrutable for humans. The summary contains around 30 dimensions that were specialized and 3 constraints on dynamic dimensions. The output format looks like this: ``` The following dimensions have been specialized and CANNOT be dynamic. NOTE: Specializations will happen by default with `assume_static_by_default=True`. L['foo']['bar'].size()[0] == 4 ... L['baz']['qux'].size()[3] == 96 The following dimensions CAN be dynamic. You can use the following code to specify the constraints they must satisfy: constraints=[ dynamic_dim(L['blah']['bleh'], 1) == dynamic_dim(L['blah']['bloh'], 1), ..., 2 <= dynamic_dim(L['blah']['bloh'], 1), ] ``` Differential Revision: [D44731747](https://our.internmc.facebook.com/intern/diff/D44731747/) ghstack-source-id: 185227035 Pull Request resolved: #98463
expr = LoggingShapeGuardPrinter(self.var_to_sources).doprint(expr) | ||
log.warning(f"Adding shape guard {expr} at \n{user_stack}") | ||
tc = TracingContext.get() | ||
if tc is not None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait why this change? TC should never be None here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cut. I remember running into a problem here, maybe in some other context...
if torch._dynamo.config.dynamic_shapes and torch._dynamo.config.summarize_dim_constraints: | ||
dim_constraints.solve() | ||
log.warning(f"Summary of dimension constraints:{dim_constraints.prettify_results()}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No dynamo config notions in this file please. We already have dynamo source notions here in some places and it kills me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would you suggest I do this, then, assuming I do want to gate it with a flag?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, the other way we've been doing it is passing these in inside __init__
. BTW there's no point in testing dynamic_shapes
, you'll never hit ShapeEnv without it True.
def is_dim(src): | ||
return isinstance(src, TensorPropertySource) and src.prop is TensorProperty.SIZE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This leaks some specific tensor notions here - maybe there's a better way to do it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Elsewhere in the same file we specifically have this pattern (e.g., see track_symint
). I don't see an abstraction here that's leaking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure why SIZE should be treated specially here but not the other sizevars.
@@ -1811,6 +2088,8 @@ def hint(): | |||
# if we have an input (2, 3), we must show s0*2 == 2 and s1 == 3. | |||
# This does a lot of work: it covers duck sizing and equality guards. | |||
exprs = [] | |||
dim_constraints = DimConstraints(symbol_to_source, self.var_to_val) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This work is unused if summarize_dim_constraints is False, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. I thought about hiding it but it's not anything heavy that we don't do already (e.g., we're not calling any solvers when initializing).
@@ -118,6 +118,10 @@ | |||
# Show a warning for every specialization | |||
print_specializations = False | |||
|
|||
# Simplify guards, summarizing static and dynamic constraints on dimensions. | |||
# NOTE: This only has an effect when dynamic_shapes=True. | |||
summarize_dim_constraints = False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this gated, btw? If it's generally good and able, we should include it unequivocally, right? Or what is the tradeoff space for enabling this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to leave this gated for export only, at least until we have been using it for a while. This is mainly because I have only tested this in the wild on export use cases, and I don't know (a) what performance bar we need to meet for eager (b) what corner cases we could be missing that could blow up these solvers, which we haven't used before.
# Our inequality solver can handle / but not %. So we need to transform them away. | ||
# We do so by using the values of variables as hints to evaluate %. | ||
# For soundness we record additional congruence guards and solve them separately. | ||
self._var_to_val = var_to_val |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
copy to not accidentally mess with this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're evidently not messing with it. Read-only for substitutions.
self._static_results = set() | ||
self._dynamic_results = set() | ||
|
||
self._dcp = DynamicDimConstraintPrinter(symbol_to_source) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
copy symbol_to_source to not accidentally mess with this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're not messing with it.
congruence = (base - mod_reduced) % divisor | ||
if congruence != 0: | ||
self._congruences[s].add(congruence) | ||
return (base - mod_reduced) / divisor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unprotected divide by 0? or do you trust upstream?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trust upstream.
if expr.free_symbols: | ||
# these will resolve to either specializations or dynamic equality constraints | ||
self._symbolic_equivalences.append((source, expr)) | ||
else: | ||
# specialization, right here | ||
self._static_results.add(f"{source.name()} == {expr}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, why only here? It seems like every expr should be checked for this, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you elaborate? We have an assertion in add()
, we don't expect non-true non-false exprs with no free symbols.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests, way more docs please, have a few sus spots to check out, otherwise seems like a great direction
…ed shape guards" The design of export API expects constraints to be specified on dynamic dimensions, while assuming all other dimensions are static by default. However a user who wishes to export a model may not be fully familiar with the code to plan what to specify. This diff provides support for discovering constraints to specify. The basic idea is to take the set of generated shape guards and convert them into appropriate constraints. However, we usually generate a LOT of shape guards, and there is often a LOT of redundancy in them. Thus, we also need to simplify the guards so that our suggested constraints are concise yet capture the information content in the guards. The algorithm for simplification uses `sympy` under the hood, but very surgically to avoid any risk of blowing up. See comments inline for a full description. Briefly, 1. We consider only univariate inequalities, and among them, solve for equalities first. 2. We substitute these exact solutions to convert multivariate inequalities progressively into univariate. 3. Remaining univariate inequalities are solved using `sympy.solvers.inequalities.reduce_inequalities`. 4. As pre-processing, we also eliminate all `//` and `%` operations to generate a set of linear congruence guards, and solve these using `sympy.ntheory.modular.solve_congruence`. The results are quite dramatic. For example, an internal model produced several hundreds of guards with `dynamic_shapes=True`, which were pretty much inscrutable for humans. The summary contains around 30 dimensions that were specialized and 3 constraints on dynamic dimensions. The output format looks like this: ``` The following dimensions have been specialized and CANNOT be dynamic. NOTE: Specializations will happen by default with `assume_static_by_default=True`. L['foo']['bar'].size()[0] == 4 ... L['baz']['qux'].size()[3] == 96 The following dimensions CAN be dynamic. You can use the following code to specify the constraints they must satisfy: constraints=[ dynamic_dim(L['blah']['bleh'], 1) == dynamic_dim(L['blah']['bloh'], 1), ..., 2 <= dynamic_dim(L['blah']['bloh'], 1), ] ``` Differential Revision: [D44731747](https://our.internmc.facebook.com/intern/diff/D44731747/) cc soumith voznesenskym penguinwu anijain2305 EikanWang jgong5 Guobing-Chen XiaobingSuper zhuhaozhe blzheng Xia-Weiwen wenzhe-nrv jiayisunx desertfire [ghstack-poisoned]
…ards Pull Request resolved: #98463 The design of export API expects constraints to be specified on dynamic dimensions, while assuming all other dimensions are static by default. However a user who wishes to export a model may not be fully familiar with the code to plan what to specify. This diff provides support for discovering constraints to specify. The basic idea is to take the set of generated shape guards and convert them into appropriate constraints. However, we usually generate a LOT of shape guards, and there is often a LOT of redundancy in them. Thus, we also need to simplify the guards so that our suggested constraints are concise yet capture the information content in the guards. The algorithm for simplification uses `sympy` under the hood, but very surgically to avoid any risk of blowing up. See comments inline for a full description. Briefly, 1. We consider only univariate inequalities, and among them, solve for equalities first. 2. We substitute these exact solutions to convert multivariate inequalities progressively into univariate. 3. Remaining univariate inequalities are solved using `sympy.solvers.inequalities.reduce_inequalities`. 4. As pre-processing, we also eliminate all `//` and `%` operations to generate a set of linear congruence guards, and solve these using `sympy.ntheory.modular.solve_congruence`. The results are quite dramatic. For example, an internal model produced several hundreds of guards with `dynamic_shapes=True`, which were pretty much inscrutable for humans. The summary contains around 30 dimensions that were specialized and 3 constraints on dynamic dimensions. The output format looks like this: ``` The following dimensions have been specialized and CANNOT be dynamic. NOTE: Specializations will happen by default with `assume_static_by_default=True`. L['foo']['bar'].size()[0] == 4 ... L['baz']['qux'].size()[3] == 96 The following dimensions CAN be dynamic. You can use the following code to specify the constraints they must satisfy: constraints=[ dynamic_dim(L['blah']['bleh'], 1) == dynamic_dim(L['blah']['bloh'], 1), ..., 2 <= dynamic_dim(L['blah']['bloh'], 1), ] ``` ghstack-source-id: 185398866 Differential Revision: [D44731747](https://our.internmc.facebook.com/intern/diff/D44731747/)
…ed shape guards" The design of export API expects constraints to be specified on dynamic dimensions, while assuming all other dimensions are static by default. However a user who wishes to export a model may not be fully familiar with the code to plan what to specify. This diff provides support for discovering constraints to specify. The basic idea is to take the set of generated shape guards and convert them into appropriate constraints. However, we usually generate a LOT of shape guards, and there is often a LOT of redundancy in them. Thus, we also need to simplify the guards so that our suggested constraints are concise yet capture the information content in the guards. The algorithm for simplification uses `sympy` under the hood, but very surgically to avoid any risk of blowing up. See comments inline for a full description. Briefly, 1. We consider only univariate inequalities, and among them, solve for equalities first. 2. We substitute these exact solutions to convert multivariate inequalities progressively into univariate. 3. Remaining univariate inequalities are solved using `sympy.solvers.inequalities.reduce_inequalities`. 4. As pre-processing, we also eliminate all `//` and `%` operations to generate a set of linear congruence guards, and solve these using `sympy.ntheory.modular.solve_congruence`. The results are quite dramatic. For example, an internal model produced several hundreds of guards with `dynamic_shapes=True`, which were pretty much inscrutable for humans. The summary contains around 30 dimensions that were specialized and 3 constraints on dynamic dimensions. The output format looks like this: ``` The following dimensions have been specialized and CANNOT be dynamic. NOTE: Specializations will happen by default with `assume_static_by_default=True`. L['foo']['bar'].size()[0] == 4 ... L['baz']['qux'].size()[3] == 96 The following dimensions CAN be dynamic. You can use the following code to specify the constraints they must satisfy: constraints=[ dynamic_dim(L['blah']['bleh'], 1) == dynamic_dim(L['blah']['bloh'], 1), ..., 2 <= dynamic_dim(L['blah']['bloh'], 1), ] ``` Differential Revision: [D44731747](https://our.internmc.facebook.com/intern/diff/D44731747/) cc soumith voznesenskym penguinwu anijain2305 EikanWang jgong5 Guobing-Chen XiaobingSuper zhuhaozhe blzheng Xia-Weiwen wenzhe-nrv jiayisunx desertfire [ghstack-poisoned]
…ards Pull Request resolved: #98463 The design of export API expects constraints to be specified on dynamic dimensions, while assuming all other dimensions are static by default. However a user who wishes to export a model may not be fully familiar with the code to plan what to specify. This diff provides support for discovering constraints to specify. The basic idea is to take the set of generated shape guards and convert them into appropriate constraints. However, we usually generate a LOT of shape guards, and there is often a LOT of redundancy in them. Thus, we also need to simplify the guards so that our suggested constraints are concise yet capture the information content in the guards. The algorithm for simplification uses `sympy` under the hood, but very surgically to avoid any risk of blowing up. See comments inline for a full description. Briefly, 1. We consider only univariate inequalities, and among them, solve for equalities first. 2. We substitute these exact solutions to convert multivariate inequalities progressively into univariate. 3. Remaining univariate inequalities are solved using `sympy.solvers.inequalities.reduce_inequalities`. 4. As pre-processing, we also eliminate all `//` and `%` operations to generate a set of linear congruence guards, and solve these using `sympy.ntheory.modular.solve_congruence`. The results are quite dramatic. For example, an internal model produced several hundreds of guards with `dynamic_shapes=True`, which were pretty much inscrutable for humans. The summary contains around 30 dimensions that were specialized and 3 constraints on dynamic dimensions. The output format looks like this: ``` The following dimensions have been specialized and CANNOT be dynamic. NOTE: Specializations will happen by default with `assume_static_by_default=True`. L['foo']['bar'].size()[0] == 4 ... L['baz']['qux'].size()[3] == 96 The following dimensions CAN be dynamic. You can use the following code to specify the constraints they must satisfy: constraints=[ dynamic_dim(L['blah']['bleh'], 1) == dynamic_dim(L['blah']['bloh'], 1), ..., 2 <= dynamic_dim(L['blah']['bloh'], 1), ] ``` ghstack-source-id: 185432080 Differential Revision: [D44731747](https://our.internmc.facebook.com/intern/diff/D44731747/)
…ed shape guards" The design of export API expects constraints to be specified on dynamic dimensions, while assuming all other dimensions are static by default. However a user who wishes to export a model may not be fully familiar with the code to plan what to specify. This diff provides support for discovering constraints to specify. The basic idea is to take the set of generated shape guards and convert them into appropriate constraints. However, we usually generate a LOT of shape guards, and there is often a LOT of redundancy in them. Thus, we also need to simplify the guards so that our suggested constraints are concise yet capture the information content in the guards. The algorithm for simplification uses `sympy` under the hood, but very surgically to avoid any risk of blowing up. See comments inline for a full description. Briefly, 1. We consider only univariate inequalities, and among them, solve for equalities first. 2. We substitute these exact solutions to convert multivariate inequalities progressively into univariate. 3. Remaining univariate inequalities are solved using `sympy.solvers.inequalities.reduce_inequalities`. 4. As pre-processing, we also eliminate all `//` and `%` operations to generate a set of linear congruence guards, and solve these using `sympy.ntheory.modular.solve_congruence`. The results are quite dramatic. For example, an internal model produced several hundreds of guards with `dynamic_shapes=True`, which were pretty much inscrutable for humans. The summary contains around 30 dimensions that were specialized and 3 constraints on dynamic dimensions. The output format looks like this: ``` The following dimensions have been specialized and CANNOT be dynamic. NOTE: Specializations will happen by default with `assume_static_by_default=True`. L['foo']['bar'].size()[0] == 4 ... L['baz']['qux'].size()[3] == 96 The following dimensions CAN be dynamic. You can use the following code to specify the constraints they must satisfy: constraints=[ dynamic_dim(L['blah']['bleh'], 1) == dynamic_dim(L['blah']['bloh'], 1), ..., 2 <= dynamic_dim(L['blah']['bloh'], 1), ] ``` Differential Revision: [D44731747](https://our.internmc.facebook.com/intern/diff/D44731747/) cc soumith voznesenskym penguinwu anijain2305 EikanWang jgong5 Guobing-Chen XiaobingSuper zhuhaozhe blzheng Xia-Weiwen wenzhe-nrv jiayisunx desertfire [ghstack-poisoned]
…ed shape guards" The design of export API expects constraints to be specified on dynamic dimensions, while assuming all other dimensions are static by default. However a user who wishes to export a model may not be fully familiar with the code to plan what to specify. This diff provides support for discovering constraints to specify. The basic idea is to take the set of generated shape guards and convert them into appropriate constraints. However, we usually generate a LOT of shape guards, and there is often a LOT of redundancy in them. Thus, we also need to simplify the guards so that our suggested constraints are concise yet capture the information content in the guards. The algorithm for simplification uses `sympy` under the hood, but very surgically to avoid any risk of blowing up. See comments inline for a full description. Briefly, 1. We consider only univariate inequalities, and among them, solve for equalities first. 2. We substitute these exact solutions to convert multivariate inequalities progressively into univariate. 3. Remaining univariate inequalities are solved using `sympy.solvers.inequalities.reduce_inequalities`. 4. As pre-processing, we also eliminate all `//` and `%` operations to generate a set of linear congruence guards, and solve these using `sympy.ntheory.modular.solve_congruence`. The results are quite dramatic. For example, an internal model produced several hundreds of guards with `dynamic_shapes=True`, which were pretty much inscrutable for humans. The summary contains around 30 dimensions that were specialized and 3 constraints on dynamic dimensions. The output format looks like this: ``` The following dimensions have been specialized and CANNOT be dynamic. NOTE: Specializations will happen by default with `assume_static_by_default=True`. L['foo']['bar'].size()[0] == 4 ... L['baz']['qux'].size()[3] == 96 The following dimensions CAN be dynamic. You can use the following code to specify the constraints they must satisfy: constraints=[ dynamic_dim(L['blah']['bleh'], 1) == dynamic_dim(L['blah']['bloh'], 1), ..., 2 <= dynamic_dim(L['blah']['bloh'], 1), ] ``` Differential Revision: [D44731747](https://our.internmc.facebook.com/intern/diff/D44731747/) cc soumith voznesenskym penguinwu anijain2305 EikanWang jgong5 Guobing-Chen XiaobingSuper zhuhaozhe blzheng Xia-Weiwen wenzhe-nrv jiayisunx desertfire [ghstack-poisoned]
Merge failedReason: 3 jobs have failed, first few of them are: trunk / macos-12-py3-arm64 / test (default, 1, 3, macos-m1-12), trunk / macos-12-py3-arm64 / test (default, 2, 3, macos-m1-12), trunk / macos-12-py3-arm64 / test (default, 3, 3, macos-m1-12) Details for Dev Infra teamRaised by workflow job |
…ed shape guards" The design of export API expects constraints to be specified on dynamic dimensions, while assuming all other dimensions are static by default. However a user who wishes to export a model may not be fully familiar with the code to plan what to specify. This diff provides support for discovering constraints to specify. The basic idea is to take the set of generated shape guards and convert them into appropriate constraints. However, we usually generate a LOT of shape guards, and there is often a LOT of redundancy in them. Thus, we also need to simplify the guards so that our suggested constraints are concise yet capture the information content in the guards. The algorithm for simplification uses `sympy` under the hood, but very surgically to avoid any risk of blowing up. See comments inline for a full description. Briefly, 1. We consider only univariate inequalities, and among them, solve for equalities first. 2. We substitute these exact solutions to convert multivariate inequalities progressively into univariate. 3. Remaining univariate inequalities are solved using `sympy.solvers.inequalities.reduce_inequalities`. 4. As pre-processing, we also eliminate all `//` and `%` operations to generate a set of linear congruence guards, and solve these using `sympy.ntheory.modular.solve_congruence`. The results are quite dramatic. For example, an internal model produced several hundreds of guards with `dynamic_shapes=True`, which were pretty much inscrutable for humans. The summary contains around 30 dimensions that were specialized and 3 constraints on dynamic dimensions. The output format looks like this: ``` The following dimensions have been specialized and CANNOT be dynamic. NOTE: Specializations will happen by default with `assume_static_by_default=True`. L['foo']['bar'].size()[0] == 4 ... L['baz']['qux'].size()[3] == 96 The following dimensions CAN be dynamic. You can use the following code to specify the constraints they must satisfy: constraints=[ dynamic_dim(L['blah']['bleh'], 1) == dynamic_dim(L['blah']['bloh'], 1), ..., 2 <= dynamic_dim(L['blah']['bloh'], 1), ] ``` Differential Revision: [D44731747](https://our.internmc.facebook.com/intern/diff/D44731747/) cc soumith voznesenskym penguinwu anijain2305 EikanWang jgong5 Guobing-Chen XiaobingSuper zhuhaozhe blzheng Xia-Weiwen wenzhe-nrv jiayisunx desertfire [ghstack-poisoned]
…ards Pull Request resolved: #98463 The design of export API expects constraints to be specified on dynamic dimensions, while assuming all other dimensions are static by default. However a user who wishes to export a model may not be fully familiar with the code to plan what to specify. This diff provides support for discovering constraints to specify. The basic idea is to take the set of generated shape guards and convert them into appropriate constraints. However, we usually generate a LOT of shape guards, and there is often a LOT of redundancy in them. Thus, we also need to simplify the guards so that our suggested constraints are concise yet capture the information content in the guards. The algorithm for simplification uses `sympy` under the hood, but very surgically to avoid any risk of blowing up. See comments inline for a full description. Briefly, 1. We consider only univariate inequalities, and among them, solve for equalities first. 2. We substitute these exact solutions to convert multivariate inequalities progressively into univariate. 3. Remaining univariate inequalities are solved using `sympy.solvers.inequalities.reduce_inequalities`. 4. As pre-processing, we also eliminate all `//` and `%` operations to generate a set of linear congruence guards, and solve these using `sympy.ntheory.modular.solve_congruence`. The results are quite dramatic. For example, an internal model produced several hundreds of guards with `dynamic_shapes=True`, which were pretty much inscrutable for humans. The summary contains around 30 dimensions that were specialized and 3 constraints on dynamic dimensions. The output format looks like this: ``` The following dimensions have been specialized and CANNOT be dynamic. NOTE: Specializations will happen by default with `assume_static_by_default=True`. L['foo']['bar'].size()[0] == 4 ... L['baz']['qux'].size()[3] == 96 The following dimensions CAN be dynamic. You can use the following code to specify the constraints they must satisfy: constraints=[ dynamic_dim(L['blah']['bleh'], 1) == dynamic_dim(L['blah']['bloh'], 1), ..., 2 <= dynamic_dim(L['blah']['bloh'], 1), ] ``` ghstack-source-id: 186338578 Differential Revision: [D44731747](https://our.internmc.facebook.com/intern/diff/D44731747/)
@pytorchbot merge |
Merge startedYour change will be merged once all checks pass (ETA 0-4 Hours). Learn more about merging in the wiki. Questions? Feedback? Please reach out to the PyTorch DevX Team |
Merge failedReason: 2 jobs have failed, first few of them are: inductor / cuda11.8-py3.10-gcc7-sm86 / test (inductor_torchbench, 1, 1, linux.g5.4xlarge.nvidia.gpu), inductor / cuda11.8-py3.10-gcc7-sm86 / test (inductor_torchbench_dynamic, 1, 1, linux.g5.4xlarge.nvidia.gpu) Details for Dev Infra teamRaised by workflow job |
…ed shape guards" The design of export API expects constraints to be specified on dynamic dimensions, while assuming all other dimensions are static by default. However a user who wishes to export a model may not be fully familiar with the code to plan what to specify. This diff provides support for discovering constraints to specify. The basic idea is to take the set of generated shape guards and convert them into appropriate constraints. However, we usually generate a LOT of shape guards, and there is often a LOT of redundancy in them. Thus, we also need to simplify the guards so that our suggested constraints are concise yet capture the information content in the guards. The algorithm for simplification uses `sympy` under the hood, but very surgically to avoid any risk of blowing up. See comments inline for a full description. Briefly, 1. We consider only univariate inequalities, and among them, solve for equalities first. 2. We substitute these exact solutions to convert multivariate inequalities progressively into univariate. 3. Remaining univariate inequalities are solved using `sympy.solvers.inequalities.reduce_inequalities`. 4. As pre-processing, we also eliminate all `//` and `%` operations to generate a set of linear congruence guards, and solve these using `sympy.ntheory.modular.solve_congruence`. The results are quite dramatic. For example, an internal model produced several hundreds of guards with `dynamic_shapes=True`, which were pretty much inscrutable for humans. The summary contains around 30 dimensions that were specialized and 3 constraints on dynamic dimensions. The output format looks like this: ``` The following dimensions have been specialized and CANNOT be dynamic. NOTE: Specializations will happen by default with `assume_static_by_default=True`. L['foo']['bar'].size()[0] == 4 ... L['baz']['qux'].size()[3] == 96 The following dimensions CAN be dynamic. You can use the following code to specify the constraints they must satisfy: constraints=[ dynamic_dim(L['blah']['bleh'], 1) == dynamic_dim(L['blah']['bloh'], 1), ..., 2 <= dynamic_dim(L['blah']['bloh'], 1), ] ``` Differential Revision: [D44731747](https://our.internmc.facebook.com/intern/diff/D44731747/) cc soumith voznesenskym penguinwu anijain2305 EikanWang jgong5 Guobing-Chen XiaobingSuper zhuhaozhe blzheng Xia-Weiwen wenzhe-nrv jiayisunx desertfire [ghstack-poisoned]
…ards Pull Request resolved: #98463 The design of export API expects constraints to be specified on dynamic dimensions, while assuming all other dimensions are static by default. However a user who wishes to export a model may not be fully familiar with the code to plan what to specify. This diff provides support for discovering constraints to specify. The basic idea is to take the set of generated shape guards and convert them into appropriate constraints. However, we usually generate a LOT of shape guards, and there is often a LOT of redundancy in them. Thus, we also need to simplify the guards so that our suggested constraints are concise yet capture the information content in the guards. The algorithm for simplification uses `sympy` under the hood, but very surgically to avoid any risk of blowing up. See comments inline for a full description. Briefly, 1. We consider only univariate inequalities, and among them, solve for equalities first. 2. We substitute these exact solutions to convert multivariate inequalities progressively into univariate. 3. Remaining univariate inequalities are solved using `sympy.solvers.inequalities.reduce_inequalities`. 4. As pre-processing, we also eliminate all `//` and `%` operations to generate a set of linear congruence guards, and solve these using `sympy.ntheory.modular.solve_congruence`. The results are quite dramatic. For example, an internal model produced several hundreds of guards with `dynamic_shapes=True`, which were pretty much inscrutable for humans. The summary contains around 30 dimensions that were specialized and 3 constraints on dynamic dimensions. The output format looks like this: ``` The following dimensions have been specialized and CANNOT be dynamic. NOTE: Specializations will happen by default with `assume_static_by_default=True`. L['foo']['bar'].size()[0] == 4 ... L['baz']['qux'].size()[3] == 96 The following dimensions CAN be dynamic. You can use the following code to specify the constraints they must satisfy: constraints=[ dynamic_dim(L['blah']['bleh'], 1) == dynamic_dim(L['blah']['bloh'], 1), ..., 2 <= dynamic_dim(L['blah']['bloh'], 1), ] ``` ghstack-source-id: 186396325 Differential Revision: [D44731747](https://our.internmc.facebook.com/intern/diff/D44731747/)
@pytorchbot merge |
Merge startedYour change will be merged once all checks pass (ETA 0-4 Hours). Learn more about merging in the wiki. Questions? Feedback? Please reach out to the PyTorch DevX Team |
Merge failedReason: 1 mandatory check(s) failed. The first few are: Dig deeper by viewing the failures on hud |
…ed shape guards" The design of export API expects constraints to be specified on dynamic dimensions, while assuming all other dimensions are static by default. However a user who wishes to export a model may not be fully familiar with the code to plan what to specify. This diff provides support for discovering constraints to specify. The basic idea is to take the set of generated shape guards and convert them into appropriate constraints. However, we usually generate a LOT of shape guards, and there is often a LOT of redundancy in them. Thus, we also need to simplify the guards so that our suggested constraints are concise yet capture the information content in the guards. The algorithm for simplification uses `sympy` under the hood, but very surgically to avoid any risk of blowing up. See comments inline for a full description. Briefly, 1. We consider only univariate inequalities, and among them, solve for equalities first. 2. We substitute these exact solutions to convert multivariate inequalities progressively into univariate. 3. Remaining univariate inequalities are solved using `sympy.solvers.inequalities.reduce_inequalities`. 4. As pre-processing, we also eliminate all `//` and `%` operations to generate a set of linear congruence guards, and solve these using `sympy.ntheory.modular.solve_congruence`. The results are quite dramatic. For example, an internal model produced several hundreds of guards with `dynamic_shapes=True`, which were pretty much inscrutable for humans. The summary contains around 30 dimensions that were specialized and 3 constraints on dynamic dimensions. The output format looks like this: ``` The following dimensions have been specialized and CANNOT be dynamic. NOTE: Specializations will happen by default with `assume_static_by_default=True`. L['foo']['bar'].size()[0] == 4 ... L['baz']['qux'].size()[3] == 96 The following dimensions CAN be dynamic. You can use the following code to specify the constraints they must satisfy: constraints=[ dynamic_dim(L['blah']['bleh'], 1) == dynamic_dim(L['blah']['bloh'], 1), ..., 2 <= dynamic_dim(L['blah']['bloh'], 1), ] ``` Differential Revision: [D44731747](https://our.internmc.facebook.com/intern/diff/D44731747/) cc soumith voznesenskym penguinwu anijain2305 EikanWang jgong5 Guobing-Chen XiaobingSuper zhuhaozhe blzheng Xia-Weiwen wenzhe-nrv jiayisunx desertfire [ghstack-poisoned]
…ards Pull Request resolved: #98463 The design of export API expects constraints to be specified on dynamic dimensions, while assuming all other dimensions are static by default. However a user who wishes to export a model may not be fully familiar with the code to plan what to specify. This diff provides support for discovering constraints to specify. The basic idea is to take the set of generated shape guards and convert them into appropriate constraints. However, we usually generate a LOT of shape guards, and there is often a LOT of redundancy in them. Thus, we also need to simplify the guards so that our suggested constraints are concise yet capture the information content in the guards. The algorithm for simplification uses `sympy` under the hood, but very surgically to avoid any risk of blowing up. See comments inline for a full description. Briefly, 1. We consider only univariate inequalities, and among them, solve for equalities first. 2. We substitute these exact solutions to convert multivariate inequalities progressively into univariate. 3. Remaining univariate inequalities are solved using `sympy.solvers.inequalities.reduce_inequalities`. 4. As pre-processing, we also eliminate all `//` and `%` operations to generate a set of linear congruence guards, and solve these using `sympy.ntheory.modular.solve_congruence`. The results are quite dramatic. For example, an internal model produced several hundreds of guards with `dynamic_shapes=True`, which were pretty much inscrutable for humans. The summary contains around 30 dimensions that were specialized and 3 constraints on dynamic dimensions. The output format looks like this: ``` The following dimensions have been specialized and CANNOT be dynamic. NOTE: Specializations will happen by default with `assume_static_by_default=True`. L['foo']['bar'].size()[0] == 4 ... L['baz']['qux'].size()[3] == 96 The following dimensions CAN be dynamic. You can use the following code to specify the constraints they must satisfy: constraints=[ dynamic_dim(L['blah']['bleh'], 1) == dynamic_dim(L['blah']['bloh'], 1), ..., 2 <= dynamic_dim(L['blah']['bloh'], 1), ] ``` ghstack-source-id: 186430118 Differential Revision: [D44731747](https://our.internmc.facebook.com/intern/diff/D44731747/)
@pytorchbot merge |
Merge startedYour change will be merged once all checks pass (ETA 0-4 Hours). Learn more about merging in the wiki. Questions? Feedback? Please reach out to the PyTorch DevX Team |
Merge failedReason: 1 jobs have failed, first few of them are: trunk / macos-12-py3-arm64 / test (default, 1, 3, macos-m1-12) Details for Dev Infra teamRaised by workflow job |
…ed shape guards" The design of export API expects constraints to be specified on dynamic dimensions, while assuming all other dimensions are static by default. However a user who wishes to export a model may not be fully familiar with the code to plan what to specify. This diff provides support for discovering constraints to specify. The basic idea is to take the set of generated shape guards and convert them into appropriate constraints. However, we usually generate a LOT of shape guards, and there is often a LOT of redundancy in them. Thus, we also need to simplify the guards so that our suggested constraints are concise yet capture the information content in the guards. The algorithm for simplification uses `sympy` under the hood, but very surgically to avoid any risk of blowing up. See comments inline for a full description. Briefly, 1. We consider only univariate inequalities, and among them, solve for equalities first. 2. We substitute these exact solutions to convert multivariate inequalities progressively into univariate. 3. Remaining univariate inequalities are solved using `sympy.solvers.inequalities.reduce_inequalities`. 4. As pre-processing, we also eliminate all `//` and `%` operations to generate a set of linear congruence guards, and solve these using `sympy.ntheory.modular.solve_congruence`. The results are quite dramatic. For example, an internal model produced several hundreds of guards with `dynamic_shapes=True`, which were pretty much inscrutable for humans. The summary contains around 30 dimensions that were specialized and 3 constraints on dynamic dimensions. The output format looks like this: ``` The following dimensions have been specialized and CANNOT be dynamic. NOTE: Specializations will happen by default with `assume_static_by_default=True`. L['foo']['bar'].size()[0] == 4 ... L['baz']['qux'].size()[3] == 96 The following dimensions CAN be dynamic. You can use the following code to specify the constraints they must satisfy: constraints=[ dynamic_dim(L['blah']['bleh'], 1) == dynamic_dim(L['blah']['bloh'], 1), ..., 2 <= dynamic_dim(L['blah']['bloh'], 1), ] ``` Differential Revision: [D44731747](https://our.internmc.facebook.com/intern/diff/D44731747/) cc soumith voznesenskym penguinwu anijain2305 EikanWang jgong5 Guobing-Chen XiaobingSuper zhuhaozhe blzheng Xia-Weiwen wenzhe-nrv jiayisunx desertfire [ghstack-poisoned]
…ed shape guards" The design of export API expects constraints to be specified on dynamic dimensions, while assuming all other dimensions are static by default. However a user who wishes to export a model may not be fully familiar with the code to plan what to specify. This diff provides support for discovering constraints to specify. The basic idea is to take the set of generated shape guards and convert them into appropriate constraints. However, we usually generate a LOT of shape guards, and there is often a LOT of redundancy in them. Thus, we also need to simplify the guards so that our suggested constraints are concise yet capture the information content in the guards. The algorithm for simplification uses `sympy` under the hood, but very surgically to avoid any risk of blowing up. See comments inline for a full description. Briefly, 1. We consider only univariate inequalities, and among them, solve for equalities first. 2. We substitute these exact solutions to convert multivariate inequalities progressively into univariate. 3. Remaining univariate inequalities are solved using `sympy.solvers.inequalities.reduce_inequalities`. 4. As pre-processing, we also eliminate all `//` and `%` operations to generate a set of linear congruence guards, and solve these using `sympy.ntheory.modular.solve_congruence`. The results are quite dramatic. For example, an internal model produced several hundreds of guards with `dynamic_shapes=True`, which were pretty much inscrutable for humans. The summary contains around 30 dimensions that were specialized and 3 constraints on dynamic dimensions. The output format looks like this: ``` The following dimensions have been specialized and CANNOT be dynamic. NOTE: Specializations will happen by default with `assume_static_by_default=True`. L['foo']['bar'].size()[0] == 4 ... L['baz']['qux'].size()[3] == 96 The following dimensions CAN be dynamic. You can use the following code to specify the constraints they must satisfy: constraints=[ dynamic_dim(L['blah']['bleh'], 1) == dynamic_dim(L['blah']['bloh'], 1), ..., 2 <= dynamic_dim(L['blah']['bloh'], 1), ] ``` Differential Revision: [D44731747](https://our.internmc.facebook.com/intern/diff/D44731747/) cc soumith voznesenskym penguinwu anijain2305 EikanWang jgong5 Guobing-Chen XiaobingSuper zhuhaozhe blzheng Xia-Weiwen wenzhe-nrv jiayisunx desertfire [ghstack-poisoned]
…ards Pull Request resolved: #98463 The design of export API expects constraints to be specified on dynamic dimensions, while assuming all other dimensions are static by default. However a user who wishes to export a model may not be fully familiar with the code to plan what to specify. This diff provides support for discovering constraints to specify. The basic idea is to take the set of generated shape guards and convert them into appropriate constraints. However, we usually generate a LOT of shape guards, and there is often a LOT of redundancy in them. Thus, we also need to simplify the guards so that our suggested constraints are concise yet capture the information content in the guards. The algorithm for simplification uses `sympy` under the hood, but very surgically to avoid any risk of blowing up. See comments inline for a full description. Briefly, 1. We consider only univariate inequalities, and among them, solve for equalities first. 2. We substitute these exact solutions to convert multivariate inequalities progressively into univariate. 3. Remaining univariate inequalities are solved using `sympy.solvers.inequalities.reduce_inequalities`. 4. As pre-processing, we also eliminate all `//` and `%` operations to generate a set of linear congruence guards, and solve these using `sympy.ntheory.modular.solve_congruence`. The results are quite dramatic. For example, an internal model produced several hundreds of guards with `dynamic_shapes=True`, which were pretty much inscrutable for humans. The summary contains around 30 dimensions that were specialized and 3 constraints on dynamic dimensions. The output format looks like this: ``` The following dimensions have been specialized and CANNOT be dynamic. NOTE: Specializations will happen by default with `assume_static_by_default=True`. L['foo']['bar'].size()[0] == 4 ... L['baz']['qux'].size()[3] == 96 The following dimensions CAN be dynamic. You can use the following code to specify the constraints they must satisfy: constraints=[ dynamic_dim(L['blah']['bleh'], 1) == dynamic_dim(L['blah']['bloh'], 1), ..., 2 <= dynamic_dim(L['blah']['bloh'], 1), ] ``` ghstack-source-id: 186564283 Differential Revision: [D44731747](https://our.internmc.facebook.com/intern/diff/D44731747/)
@pytorchbot merge -f "unrelated ci failures (doctr)" |
Merge startedYour change will be merged immediately since you used the force (-f) flag, bypassing any CI checks (ETA: 1-5 minutes). Learn more about merging in the wiki. Questions? Feedback? Please reach out to the PyTorch DevX Team |
Stack from ghstack (oldest at bottom):
The design of export API expects constraints to be specified on dynamic dimensions, while assuming all other dimensions are static by default. However a user who wishes to export a model may not be fully familiar with the code to plan what to specify.
This diff provides support for discovering constraints to specify. The basic idea is to take the set of generated shape guards and convert them into appropriate constraints. However, we usually generate a LOT of shape guards, and there is often a LOT of redundancy in them. Thus, we also need to simplify the guards so that our suggested constraints are concise yet capture the information content in the guards.
The algorithm for simplification uses
sympy
under the hood, but very surgically to avoid any risk of blowing up. See comments inline for a full description. Briefly,sympy.solvers.inequalities.reduce_inequalities
.//
and%
operations to generate a set of linear congruence guards, and solve these usingsympy.ntheory.modular.solve_congruence
.The results are quite dramatic. For example, an internal model produced several hundreds of guards with
dynamic_shapes=True
, which were pretty much inscrutable for humans. The summary contains around 30 dimensions that were specialized and 3 constraints on dynamic dimensions. The output format looks like this:Differential Revision: D44731747
cc @soumith @voznesenskym @penguinwu @anijain2305 @EikanWang @jgong5 @Guobing-Chen @XiaobingSuper @zhuhaozhe @blzheng @Xia-Weiwen @wenzhe-nrv @jiayisunx @desertfire