-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
[FRONTEND] A Python hybrid frontend #1251
Conversation
@tqchen @merrymercy @kevinthesun @xqdan @ZihengJiang |
docs/dev/hybrid_script.md
Outdated
a = numpy.random.rand(100) | ||
b = numpy.random.rand(99) | ||
c = numpy.zeros((100, 99)) | ||
outer_product(a, b) |
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.
should be outer_product(a, b, c)
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.
Other parts look good to me
@were please comment when the PR is ready to be reviewed. We shouldn't put TODO in the docs, but you can put a note saying that the feature is yet to be supported. We will need a tutorial in tutorials/language/hybrid_script.py |
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.
a few typos
docs/dev/hybrid_script.md
Outdated
|
||
### Loops | ||
|
||
In HalideIR, loops have in total 4 types: `serail`, `unrolled`, `parallel`, and `vectorized`. |
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.
serail should be serial
docs/dev/hybrid_script.md
Outdated
for j in range(5): | ||
sum += a[i, j] #do something with sum | ||
b[i] = sum #you can still use sum in this level | ||
#you can NEVER use some here, even though it is allowed in conventional Python |
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.
Is that some, or should it be sum?
general progress tracked in #1213 |
stmt = schedule.ScheduleOps(sch, bounds) | ||
stmt = ir_pass.InjectPrefetch(stmt) | ||
else: | ||
#So far there is no op for hybrid script, so a plain ir body is given |
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.
check if sch is stmt, if not raise error
python/tvm/hybrid/_internal.py
Outdated
from ..tensor import Tensor | ||
|
||
# Useful constants | ||
NOP = _make.Evaluate(_api.const(0, dtype='int32')) |
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.
try not to construct IR object in global, since we sometimes will have runtime only object and we need to support non-dependency when we only import but did not use hybrid.
Construct a Constant class single and overload property to do it lazily when any of them is requested
python/tvm/hybrid/_internal.py
Outdated
NUMPY_ARG_TYPES = (float, int, long, numpy.float32, numpy.int32, numpy.ndarray) | ||
|
||
def _is_tvm_arg_types(args): | ||
"""Determine a list of element is either a list of tvm arguments of a list of numpy arguments. |
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.
when possible, document the arg types
python/tvm/hybrid/_internal.py
Outdated
|
||
TVM_ARG_TYPES = (_expr.Var, Tensor) | ||
if sys.version_info[0] == 3: | ||
NUMPY_ARG_TYPES = (float, int, numpy.float32, numpy.int32, numpy.ndarray) |
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 should go to _ffi.base
python/tvm/hybrid/_intrin.py
Outdated
@@ -0,0 +1,69 @@ | |||
"""Intrinsics of Python-Halide DSL for Python runtime""" |
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.
Intrinsics of TVM Hybrid script
python/tvm/hybrid/parser.py
Outdated
Returns | ||
------- | ||
func_name: str | ||
The name of the function to be lowered; if not provided, |
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.
indent the description
python/tvm/hybrid/parser.py
Outdated
|
||
def parse_python(src, args): | ||
""" The helper function of calling the AST visitor""" | ||
root = ast.parse(src) |
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.
seems most of this can be merged into parser construction
python/tvm/hybrid/parser.py
Outdated
|
||
#pylint: disable=missing-docstring, invalid-name | ||
#pylint: disable=consider-merging-isinstance, no-else-return | ||
#pylint: disable=inconsistent-return-statements |
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.
check inconsistent-return-statements
python/tvm/hybrid/var_decl.py
Outdated
from ._intrin import HYBRID_GLOBALS | ||
|
||
class PyVariableUsage(ast.NodeVisitor): | ||
"""The vistor class to determine the declaration, r/w status, and last use of each variable""" |
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.
document arguments
@@ -0,0 +1,68 @@ | |||
"""Determines the declaration, r/w status, and last use of each variable""" |
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.
import absolute import
docs/dev/hybrid_script.rst
Outdated
@@ -0,0 +1,66 @@ | |||
Hybrid Frontend Developer Guide | |||
------------------------------- |
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.
Let us start from first level title =======
docs/langref/hybrid_script.rst
Outdated
@@ -0,0 +1,169 @@ | |||
Hybrid Frontend Language Reference | |||
---------------------------------- |
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.
first level title is =====
, second level title is -------
, third level title is ~~~~~
@Laurawly please also take a look |
docs/dev/hybrid_script.rst
Outdated
If you are a developer: | ||
|
||
1. who is trying writing some preliminary patterns that have not been supported by TVM yet, | ||
maybe ``lang_ref/hybrid_script.rst`` is a better place for you. |
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.
use ref feature of rst
docs/langref/hybrid_script.rst
Outdated
|
||
In HalideIR, loops have in total 4 types: ``serial``, ``unrolled``, ``parallel``, and ``vectorized``. | ||
|
||
Here we use ``range``, ``serial``, ``unroll``, ``parallel``, and ``vectorize``, |
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.
remove serial
docs/langref/hybrid_script.rst
Outdated
|
||
**NOTE**: In HalideIR those are enums, they are in passive form. | ||
Here we use active form to annotate loops, because they are ready to run. | ||
|
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.
since this is useer facing doc, no need to refer back to HalideIR, instead, directly say the loop_type corresponds to range. Use note block construction of rst .
docs/langref/hybrid_script.rst
Outdated
All the mutatable variables will be lowered to an array with size 1. | ||
It regards the first store of a variable as its declaration. | ||
|
||
**NOTE**: Unlike conventional Python, in hybrid script, the declared variable |
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.
use note block rst
docs/dev/hybrid_script.rst
Outdated
If you are a developer: | ||
|
||
1. who is trying writing some preliminary patterns that have not been supported by TVM yet, | ||
maybe `language ref <../langref/hybrid_script.rst>`_ is a better place for you. |
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.
Use ref. see http://www.sphinx-doc.org/en/stable/markup/inline.html cross reference arbitrary locations
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 is a ref to a file instead of an anchor. Can I still use label to do it? I suppose label is only for intra file instead of inter.
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.
label works for inter file
@@ -0,0 +1,170 @@ | |||
Hybrid Frontend Language Reference |
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.
Hybrid Script Language Reference
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.
since this is the first level, change to ======
python/tvm/hybrid/_intrin.py
Outdated
|
||
|
||
def allocate(shape, dtype=None): | ||
"""Allocate a buffer with given shape""" |
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.
document all the arguments, see https://docs.tvm.ai/contribute/document.html#document-python
python/tvm/hybrid/_intrin.py
Outdated
|
||
|
||
def popcount(x): | ||
"""Software emulated popcount function which counts 1's in a number's binary representation.""" |
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.
python/tvm/hybrid/_intrin.py
Outdated
return cnt | ||
|
||
|
||
def sigmoid(x): |
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.
python/tvm/hybrid/_util.py
Outdated
@@ -0,0 +1,73 @@ | |||
"""Internal utilities for parsing Python subset to HalideIR""" |
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.
consider just make it util.py
python/tvm/hybrid/_util.py
Outdated
|
||
|
||
# Useful constants. In avoid of runtime dependences, we use function calls to return them. | ||
def make_nop(): |
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.
document functions
python/tvm/hybrid/api.py
Outdated
------- | ||
(halide_ir, parser) : (Stmt, PyAST2HalideIR) | ||
The result Halide IR and the parser class instance. | ||
TODO: Later we deprecate this return value, use a dedicated OP node type instead |
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.
parse should always return Stmt only
python/tvm/hybrid/parser.py
Outdated
@@ -0,0 +1,342 @@ | |||
"""Compiling a TVM Hybrid Script Python to HalideIR""" |
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.
Hybrid Script Parser
return res | ||
|
||
|
||
def parse_python(src, args): |
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.
is this function necessary? Can we just do and inline it into parse?
HybridParser parser(src, args)
return parser.parse(root)
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 just want to make the code style uniform, each IR pass has its own helper function. Just like that is in Halide style.
@@ -0,0 +1,10 @@ | |||
"""Hybrid Programming APIs of TVM Python Package. | |||
|
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.
need to add hybrid.rst to the python API, see example here
https://github.com/dmlc/tvm/blob/master/docs/api/python/index.rst
https://github.com/dmlc/tvm/blob/master/docs/api/python/intrin.rst
@were Could there be more gpu testings regarding vthread injection and usage of shared / warp memory? |
Thanks! This is merged. Please followup with PRs on gpu support |
Hybrid Frontend Developer Guide
This hybrid frontend is aimed at:
Features
Software emulation
This feature supports both software emulation and compilation of the code.
To define a function, you need to use
tvm.hybrid.script
decorator to indicate this is a hybrid function:This decorator will help you to import key words required spontaneously when software emulation.
Every element in the argument list is either a python variable or
numpy
tensor.Backend Compilation
The current parse interface looks like:
TODO: If we pass these tvm tensors to this function, it returns a op node:
Scheduling
Under construction, not truly supported yet.
Follow up the example above, you can use some tvm like interfaces to manipulate the structure of IR:
split
,reorder
, and loop_annotation will be supported!Attributes
So far, ONLY tensors'
shape
attribute is supported!Loops
In HalideIR, loops have in total 4 types:
serail
,unrolled
,parallel
, andvectorized
.Here we use
range
,serial
,unroll
,parallel
, andvectorize
, these 5 keywords to annotate the types of for loops.NOTE: In HalideIR those are enums, they are in passive form. Here we use active form to annotate loops, because they are ready to run.
NOTE: Unlike what that is in HalideIR, in
loop_type(a, b)
,a
is the starting point andb
is the trip count of iterations. Hereloop_type(a, b)
indicates[a, b)
.Variables
Because there is no variables in
HalideIR
, all the mutatable variables will be lowered to an array with size 1.It takes the first store of a variable as its declaration.
NOTE: Unlike conventional Python, the declared array can only be used in the scope level it is declared.
Conditional Statement and Expression
However, NO
True
andFalse
keyword supported yet.Math intrinsics
So far, these math intrinsics,
log
,exp
,sigmoid
,tanh
,power
, andpopcount
, are supported. No import is required, just use it!Array allocation
TODO: Use a function call
allocation(shape, type, share/local)
to declare an array buffer. The basic usage is roughly the same as variablesThread bind
You can also do loop-thread bind by writing code like this:
Appendix
Keywords
for
,in
,if
,else
serial
,range
,unroll
,parallel
,vectorize
,bind
log
,exp
,sigmoid
,tanh
,power
,popcount