-
Notifications
You must be signed in to change notification settings - Fork 4
[ingress][torch-mlir][RFC] Initial version of fx-importer script using torch-mlir #4
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
base: main
Are you sure you want to change the base?
Conversation
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.
Thanks @dchigarev for making progress on PyTorch ingress!
In general it all seems to make sense to me! My comments are on relatively small matters.
Having said that, I would say the majority of the PR is on enabling the cmdline interface, which I expect to also be the most contentious. Personally, I am not a fan of such interfaces and prefer the scripting approach. If other people are in favour though, I am not opposed for the code to be included.
Do you happen to have examples of similar cmdline interfaces being used for enabling PyTorch lowerings in other projects?
@rolfmorel thanks for your time and feedback! No, I haven't seen such cmdline approach anywhere (I wasn't looking to deep though). On the surface of IREE's and Blade's documentation I could only found the user-script approach. So even if they have a cmdline option, they don't seem to promote it very well. |
This is great, thank you so much for working on this 🙏🏻 I have a few high-level suggestions. Keep this PR simple and restrict to the required minimum. The cmdline interface looks complex and is merely a "wrapper" for the script logic. We can't avoid having a script, but we can avoid the cmdline interface. And, with a complex cmdline interface like this, I would wrap it into yet another script. My suggestion - drop the interface for now. This will allow us to focus on the core logic instead. Consistent filenames and hyphenation.
Use doctoring consistently. Lets use (function + module) docstrings consistently (instead of mixing docstring and plain Python comments starting with Do we need all the Bash scripts? There's seems to be a fair bit of duplication, e.g. Naming.
IIUC, While Final thoughts. Really fantastic to see this, just a bit concerned that this PR is trying to achieve too many things in one go. I recommend trimming it - I'd much rather focus on the core part and also make sure that we establish a consistent way of naming, structuring and implementing things. I've some other, more specific comments inline. Thanks again for working on this! 🙏🏻 |
|
||
|
||
def generate_mlir(model, sample_args, sample_kwargs=None, dialect="linalg"): | ||
# Convert the Torch model to MLIR |
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 we use docstrings consistently throughout this project?
@@ -0,0 +1,16 @@ | |||
#!/usr/bin/env bash | |||
|
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.
DOCUMENTME - what is the purpose of this script and how do I use it?
Building wrapper scripts around torch-mlir is not scalable at all. torch-mlir is not a library to build things with, not a tool to build scripts around. The proper way of doing this is shipping fx_importer as part of bindings: #3 (ready for review) and then building export over it and ship it as part of the python package. I'm going to send a pr on building an aot export for torch and onnx around that today to give an idea of how it should be done. |
Given the distinct though all ingress-related PRs currently up, I thought that delineating their separate purposes might be helpful:
Regarding the interaction between the importer script and the scripts that deal with input sources: My feeling is that providing a little python package that can be used as a utility by the separate input-processing scripts might be most helpful.
As the PyTorch and torch-mlir libs need to live in the same process anyway, I do not see much benefit coming from trying to separate out the importer/converter code to a script that actually runs in a separate process from the code that deals with the input sources. |
…rch-mlir Signed-off-by: dchigarev <[email protected]>
Signed-off-by: dchigarev <[email protected]>
Signed-off-by: dchigarev <[email protected]>
Signed-off-by: dchigarev <[email protected]>
a08bcc5
to
b984314
Compare
I've updated the PR following your suggestions. Lighthouse now has a p.s. |
Signed-off-by: dchigarev <[email protected]>
Signed-off-by: dchigarev <[email protected]>
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.
Many thanks for the revision (and the commitment to the PR)! It is looking good!
Have left a number of minor comments. I will soon try to rebase #5 on this branch and confirm that that works as expected. Happy to approve once both are sorted 👍
ir_context : ir.Context, optional | ||
An optional MLIR context to use for parsing the module. | ||
If not provided, the module is returned as a string. |
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.
Just to leave a note: this is somewhat surprising to me, though as I don't currently have a better suggestion to expose the same functionality (i.e. returning before conversion to environment's mlir) I am okay with it.
Signed-off-by: dchigarev <[email protected]>
Signed-off-by: dchigarev <[email protected]>
Signed-off-by: dchigarev <[email protected]>
The PR modifies `pyproject.toml` to make the content of `python/lighthouse` to be installable via `uv pip install .` For now the package is empty, but after #4 is merged users would be able to access ingress helper functions as part of the package: ```python from lighthouse.ingress.torch import import_from_file ... ``` * install lighthouse on 'uv sync' Signed-off-by: dchigarev <[email protected]> * use dynamic version in pyproject.toml Signed-off-by: dchigarev <[email protected]> --------- Signed-off-by: dchigarev <[email protected]>
Signed-off-by: dchigarev <[email protected]>
Signed-off-by: dchigarev <[email protected]>
inputs_args_fn = getattr(module, inputs_args_fn_name, None) | ||
if inputs_args_fn is None: | ||
raise ValueError(f"Inputs args function '{inputs_args_fn_name}' not found in {filepath}") | ||
model_init_args = maybe_load_and_run_callable( |
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 believe the following works and would mean a bit less abstraction:
try:
model_init_args = init_args_fn_name and getattr(module, init_args_fn_name)() or tuple()
except AttributeError:
raise ValueError(f"Init args function '{init_args_fn_name}' not found in {filepath}")
I know not everyone will find using the boolean operators in this way intuitive though (and technically it's not completely right, in the sense that returned falsity values will get replaced by tuple()
). Nonetheless thought to suggest 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.
Thanks @dchigarev ! That's it for my comments. IMO this is looking great.
Am approving now, though with the caveat that I will still rebase #5 on this branch before we merge this PR (to check that the API works there as expected). Will report back on that by EOD tomorrow at the latest.
@banach-space, would you like to give this a final pass before it goes in?
Signed-off-by: dchigarev <[email protected]>
Can confirm that this is working as expected for #5: https://github.com/llvm/lighthouse/pull/5/files/0912de15b458a78a88f111045fe0e54618ae83a1..63b82406443cdd449bbb1100a1639853b7417160 Barring one or two outstanding comments, this is go to IMO 👍 |
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.
Thanks for the updates and for pushing on this 🙏🏻
Approving as is - looks very clean and clear. I have some suggestions for minor improvements, but this is already great, so feel free to ignore.
If folks agree with my suggestions but have no bandwidth for PRs, I can upload something myself. Thanks!
# Step 4: Apply some MLIR passes using a PassManager | ||
pm = passmanager.PassManager(context=ir_context) | ||
pm.add("linalg-specialize-generic-ops") | ||
pm.add("one-shot-bufferize") |
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 do we bufferize? Bufferization is quite an involved transformation and IMHO, we should only do the bare minimum here. Specifically, these are two orthogonal things to me:
- importing a PyTorch model into MLIR,
- running transformations on MLIR.
WDYT? Thinking in terms of "separation of concerns".
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.
+1 to removing bufferization specifically. It can have many flavors and generally we want to stay at tensor longer.
OTOH, it's just an arbitrary example so, it's fine. Alternatively, an extra comment spelling out the message or motivation here could help to clarify intent.
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.
Right, I also think that applying bufferization in an ingress-example could be too much :)
But do you think we should remove the PassManager
case from the ingress-examples completely? I also believe that ingress and running a pipeline are two separate things, we could leave a hint to the users though in form of an in-code comment on what to do next with an imported mlir module, e.g.
....
# Step 4: output the imported MLIR module
print("\n\nModule dump after running the pipeline:")
mlir_module_ir.dump()
# You can alternatively write the MLIR module to a file:
# with open("output.mlir", "w") as f:
# f.write(str(mlir_module_ir))
#
# Or apply some MLIR passes using a PassManager:
# pm = passmanager.PassManager(context=ir_context)
# pm.add("linalg-specialize-generic-ops")
# pm.add(...)
# pm.run(mlir_module_ir.operation)
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.
It'd make sense to completely skip these parts and focus only on ingress.
We can make other examples that focus on lowering later.
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 agree, let's remove it completely
Example demonstrating how to load an already instantiated PyTorch model | ||
to MLIR using Lighthouse. |
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.
The difference between this file and 01-dummy-mlir-from-model.py is "instantiation" (here the model is "already instantiated"). But what does "model instantiation" mean? Genuine question - I think that it would be good to capture this somewhere :)
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.
by "instantiation" I meant an instantiation (creation) of the model's class :)
changed to "model initialization", means the same but sound simplier
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 think that "model" is just a bit too overloaded term and that's a potential source of confusion (I remember getting quite confused first time I played with PyTorch).
[nit] Could you specify that you mean the PyTorch "model" (class)?
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.
Tried to make the docstring clearer on what pytorch model means
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.
Great work 😎
print(f"entry-point name: {func_op.name}") | ||
print(f"entry-point type: {func_op.type}") | ||
|
||
# Step 4: Apply some MLIR passes using a PassManager |
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.
Going to category could be a more useful or more broadly applicable default but TBD
# Step 4: Apply some MLIR passes using a PassManager | ||
pm = passmanager.PassManager(context=ir_context) | ||
pm.add("linalg-specialize-generic-ops") | ||
pm.add("one-shot-bufferize") |
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.
+1 to removing bufferization specifically. It can have many flavors and generally we want to stay at tensor longer.
OTOH, it's just an arbitrary example so, it's fine. Alternatively, an extra comment spelling out the message or motivation here could help to clarify intent.
Signed-off-by: dchigarev <[email protected]>
Signed-off-by: dchigarev <[email protected]>
Signed-off-by: dchigarev <[email protected]>
Signed-off-by: dchigarev <[email protected]>
The PR adds two utility functions as part of lighthouse's python package to convert torch models to a mlir module using
torch_mlir
.A user can import one of the functions (
import_from_model
orimport_from_file
) and get amlir.ir.Module
that they can use to run passes on or simply write its content into a file.some use cases
1. Import from an instance of a model:
2. Import from a file where a torch model is defined:
Imagine we want to import a model from
KernelBench
. They ship models as python files where models and their arguments are uniformly defined.The utility functions use
torch_mlir
andmlir
installed in the python env following #6 (and not from lighthouses bindings as suggested in #3).