Skip to content
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

[Relay] softmax, max_pool2d, conv2d, fix 4D memory connections (WIP) #289

Merged
merged 96 commits into from
Dec 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
b624a6d
Use dahlia.
cgyurgyik Nov 5, 2020
9819202
cleanup.
cgyurgyik Nov 5, 2020
9e83fa1
Add temporary file use.
cgyurgyik Nov 5, 2020
1afa5a1
Now only need changes in two places when adding a Dahlia function.
cgyurgyik Nov 5, 2020
18a8361
Assume Dahlia is on path.
cgyurgyik Nov 5, 2020
3ae22ee
Add DAHLIA_EXEC environment variable.
cgyurgyik Nov 5, 2020
dc96f85
cleanup.
cgyurgyik Nov 5, 2020
c8088eb
Cleanup.
cgyurgyik Nov 6, 2020
7d75370
Add incorrect batch_matmul.
cgyurgyik Nov 6, 2020
d73ace8
[Relay] Add actual expect for matrix multiply.
cgyurgyik Nov 6, 2020
57f85be
Add succinct example.
cgyurgyik Nov 7, 2020
16b2c6a
Merge branch 'master' into relay
cgyurgyik Nov 10, 2020
d87b5f3
[relay] Add more functions, cleanup.
cgyurgyik Nov 12, 2020
bd7afa3
Merge branch 'master' into relay
cgyurgyik Nov 12, 2020
8980ed9
[relay] Clarify comment.
cgyurgyik Nov 12, 2020
9b08d29
Rename to batch_flatten.
cgyurgyik Nov 15, 2020
806e93d
Fix batch_flatten, add test for 1d tensor binary ops
cgyurgyik Nov 15, 2020
425a87c
[relay] add binary ops for 3d tensors.
cgyurgyik Nov 15, 2020
a24a4db
Add additional assert statement.
cgyurgyik Nov 15, 2020
eb0a9d7
Merge branch 'master' into relay
cgyurgyik Nov 20, 2020
46dc536
Add 4d tensor ops.
cgyurgyik Nov 20, 2020
696204f
Merge branch 'master' into relay
cgyurgyik Nov 20, 2020
40db68f
Remove comma.
cgyurgyik Nov 20, 2020
63535b2
Add negative, non-working expand_dims.
cgyurgyik Nov 21, 2020
8614cc6
Fix dahlia name.
cgyurgyik Nov 21, 2020
6657d2f
Add axis=1.
cgyurgyik Nov 21, 2020
b4a373a
Add does not work.
cgyurgyik Nov 21, 2020
21a4921
Add transforms.
cgyurgyik Nov 21, 2020
40b9392
Add attributes, bias_add along different axis.
cgyurgyik Nov 21, 2020
3555c62
Add bias add.
cgyurgyik Nov 21, 2020
a959fa5
Fix name ordering for visit let.
cgyurgyik Nov 21, 2020
2c8b72e
Cleanup!
cgyurgyik Nov 21, 2020
77f01c4
More cleanup.
cgyurgyik Nov 21, 2020
e5aa60d
Add element-wise with a single value.
cgyurgyik Nov 21, 2020
5a31731
Revert add.
cgyurgyik Nov 21, 2020
6a9f170
Fix PP for D4.
cgyurgyik Nov 22, 2020
655a439
Fix 4d case.
cgyurgyik Nov 22, 2020
caf0112
Remove extra comma.
cgyurgyik Nov 22, 2020
f049645
Simplify expr.
cgyurgyik Nov 22, 2020
318b6f5
Change to dahlia_name.
cgyurgyik Nov 22, 2020
6305a0f
Clean up PP.
cgyurgyik Nov 22, 2020
a99384f
Place mapping outside of function call.
cgyurgyik Nov 22, 2020
3dd6a44
Add support for dense operator.
cgyurgyik Nov 22, 2020
c51c41a
Implement broadcasting.
cgyurgyik Nov 23, 2020
96654d4
Rename mapping.
cgyurgyik Nov 23, 2020
a8a9039
Fix spacing.
cgyurgyik Nov 23, 2020
52d0b90
Fix dahlia naming.
cgyurgyik Nov 23, 2020
0ff11ec
Cleanup.
cgyurgyik Nov 23, 2020
09a2019
CLeanup.
cgyurgyik Nov 23, 2020
9c41278
Add todo for supporting axis=-1.
cgyurgyik Nov 23, 2020
98589f2
Begin generalizing functions for any tensor size.
cgyurgyik Nov 24, 2020
1b18673
Fix comment.
cgyurgyik Nov 24, 2020
01bfe74
Generalize functions.
cgyurgyik Nov 24, 2020
9f3a756
Fix batch_matmul.
cgyurgyik Nov 24, 2020
05a3935
Add mlp_net (incomplete example).
cgyurgyik Nov 24, 2020
fe78aee
Add mem_d4 to remove externals pass
cgyurgyik Nov 27, 2020
e9b3db3
Add ,
cgyurgyik Nov 27, 2020
ac80b3f
Merge branch 'master' into relay
cgyurgyik Nov 27, 2020
2ebe1ec
Use op instead of +
cgyurgyik Nov 27, 2020
e46b499
tMerge branch 'relay' of https://github.com/cucapra/futil into relay
cgyurgyik Nov 27, 2020
62a20de
Add fixed_p_std_gt.
cgyurgyik Nov 27, 2020
4482dd5
Float mlp_net
cgyurgyik Nov 27, 2020
6d94e56
Merge branch 'master' of https://github.com/cucapra/futil into relay
cgyurgyik Nov 27, 2020
ea17024
Merge branch 'master' into relay
cgyurgyik Nov 27, 2020
1658e77
Merge branch 'relay' of https://github.com/cucapra/futil into relay
cgyurgyik Nov 27, 2020
822f1f3
Add element-wise sqrt.
cgyurgyik Nov 27, 2020
89b1283
Merge branch 'master' into relay
cgyurgyik Dec 1, 2020
1d2a675
Merge branch 'master' into relay
cgyurgyik Dec 2, 2020
52b33ef
Merge branch 'master' of https://github.com/cucapra/futil into relay
cgyurgyik Dec 2, 2020
87dfc03
Initial.
cgyurgyik Dec 2, 2020
4935912
Add stdlib
cgyurgyik Dec 2, 2020
01a87fe
Merge branch 'master' into relay
cgyurgyik Dec 2, 2020
1bcfefe
Softmax for integer type fixed.
cgyurgyik Dec 2, 2020
78d7168
Remove unnecessary else.
cgyurgyik Dec 2, 2020
75c1499
Add working max_pool2d.
cgyurgyik Dec 3, 2020
d63fd81
Add expected output.
cgyurgyik Dec 3, 2020
82363ad
Remove ellipsis
cgyurgyik Dec 3, 2020
83a0cc5
Cleanup, add externalize registry to fud.
cgyurgyik Dec 3, 2020
fd3f133
Initial conv2d commit.
cgyurgyik Dec 4, 2020
2bc240e
Update conv2d expect.
cgyurgyik Dec 4, 2020
839a40e
Singular.
cgyurgyik Dec 4, 2020
3dc4b29
conv2d.
cgyurgyik Dec 5, 2020
86ed13d
Merge branch 'master' into relay
cgyurgyik Dec 5, 2020
13ec4ff
Remove mlp from test suite.
cgyurgyik Dec 5, 2020
781c51a
Merge branch 'relay' of https://github.com/cucapra/futil into relay
cgyurgyik Dec 5, 2020
89cda69
Cleanup.
cgyurgyik Dec 8, 2020
c818bd8
Merge branch 'master' into relay
cgyurgyik Dec 8, 2020
cc13e7c
Continued modular efforts.
cgyurgyik Dec 9, 2020
cd92fd3
Merge branch 'master' into relay
cgyurgyik Dec 11, 2020
06dff4f
Fix fud externalize stage.
cgyurgyik Dec 11, 2020
d632e4d
Merge branch 'master' into relay
cgyurgyik Dec 12, 2020
ea981d1
Merge branch 'master' into relay
cgyurgyik Dec 15, 2020
f2290cb
Remove primitive library changes.
cgyurgyik Dec 20, 2020
a25b30d
Merge branch 'master' into relay
cgyurgyik Dec 20, 2020
c3018f5
Mark softmax as unimplemented.
cgyurgyik Dec 20, 2020
c43ed4a
Merge branch 'master' into relay
cgyurgyik Dec 20, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 35 additions & 73 deletions frontends/relay-futil/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,7 @@
from pretty_print import *
from utilities import *
from futil_ast import *
from dahlia_functions import *

# Mapping from Relay binary calls to the respective Dahlia operator.
BuiltInBinaryOps = {'add': '+', 'divide': '/', 'multiply': '*', 'subtract': '-'}

# Mapping from Relay function names to their respective Dahlia lowering.
RelayFunctionCalls = {'nn.dense': dense, 'nn.batch_flatten': batch_flatten, 'nn.batch_matmul': batch_matmul,
'nn.bias_add': bias_add, 'nn.relu': relu, 'negative': negative, 'expand_dims': expand_dims,
'sqrt': sqrt}

# Mapping between primitive type and associated Dahlia name extension.
# E.g. A 2D memory primitive named `A` will be lowered to `A0_0`.
DahliaNameExtension = {PrimitiveType.Memory1D: '0', PrimitiveType.Memory2D: '0_0',
PrimitiveType.Memory3D: '0_0_0', PrimitiveType.Memory4D: '0_0_0_0'}
from dahlia_lowering import *


class Relay2Futil(ExprFunctor):
Expand All @@ -30,115 +17,92 @@ def __init__(self):
super(Relay2Futil, self).__init__()
self.id_dictionary = defaultdict(int)
self.relay_id_dictionary = defaultdict(int)
self.dahlia_components = []
self.main = FComponent(name="main", cells=[], wires=[])
self.main = FComponent(name="main")

def id(self, name):
"""
Provides a unique identification for a given name.
For example, if 'a' is seen three times, it will produce: 'a0', 'a1', 'a2'.
"""
id_number = self.id_dictionary[name]
id_number = str(self.id_dictionary[name])
self.id_dictionary[name] += 1
return name + str(id_number)
return ''.join((name, id_number))

def relay_id(self, name):
"""
Relay does not explicitly differentiate a variable name if it is used twice. For example,
%x = foo(%y);
%x1 = bar(%x); // Here, at this level, the name_hint associated with `x1` is still 'x'.

To avoid this, we provide Relay with its own identification dictionary. If 'x' is seen
three times, it will produce: 'x', 'x1', x2'.
To avoid this, we provide Relay with its own identification dictionary.
If 'x' is seen three times, it will produce: 'x', 'x1', x2'.
"""
id_number = self.relay_id_dictionary[name]
self.relay_id_dictionary[name] += 1
if id_number == 0: return name
return name + str(id_number)
return ''.join((name, str(id_number)))

def dahlia_name(self, name, type):
"""
Dahlia uses the following naming scheme for an arbitrary variable 'X':
Memory1D: 'X0', 'X1', 'X2', ...
Memory2D: 'X0_0', 'X1_0', 'X2_0', ...
Memory3D: 'X0_0_0', 'X1_0_0', 'X2_0_0', ...
Dahlia uses the following naming scheme for arbitrary variables `X`, `Y`:
Memory1D: `X0`, `Y0`
Memory2D: `X0_0`, `Y0_0`
Memory3D: `X0_0_0`, `Y0_0_0`
"""
assert type in DahliaNameExtension, f'{name} with {type} is not supported yet.'
return name + DahliaNameExtension[type]
return ''.join((name, DahliaNameExtension[type]))

def get_dahlia_declaration(self, function_name, cells, args, attrs):
"""
Returns the corresponding name, Dahlia function type, and op (if it is a binary op, otherwise None).
If the function type isn't supported, fails with an assertion.
"""
input_type = cells[0].primitive.type
function = name = op = None
if function_name in BuiltInBinaryOps:
op = BuiltInBinaryOps[function_name]
function, name = broadcast, function_name
elif function_name in RelayFunctionCalls:
function = RelayFunctionCalls[function_name]
name = function.__name__
else:
assert False, f'{function_name} with type {input_type} is not supported.'
return DahliaDeclaration(component_name=self.relay_id(name), decl_name=self.id(name),
op=op, inputs=args, attributes=attrs, function=function)

def visit_var(self, var):
def visit_var(self, var) -> FCell:
name = self.relay_id(var.name_hint)
# Do not add duplicate primitives to main.
if self.main.contains_primitive(name): return cell
if name in self.main.cells: return cell
data, type, data_type = get_memory_parameters(var.type_annotation)
dahlia_name = self.dahlia_name(name, type)
return FCell(dahlia_name=dahlia_name,
return FCell(dahlia_name=self.dahlia_name(name, type),
primitive=FPrimitive(name=name, data=data, data_type=data_type, type=type))

def visit_let(self, let):
values, output = self.visit(let.value), self.visit(let.var)
if isinstance(values, list):
for value in values:
if not value.is_dahlia_declaration(): continue
value.dahlia_declaration.output = output
value.dahlia_declaration.invoke()
for value in flatten(values):
if value.is_relay_function(): value.relay_function.output = output
return [self.visit(let.body), values]

def visit_constant(self, const):
def visit_constant(self, const) -> FCell:
# Note: We're currently treating constants defined in a `let` statement in Relay IR as 1D Memory.
type, shape = const.data.dtype, const.data.shape
name, data = self.id("const"), [get_bitwidth(type), int(const.data.asnumpy())]
data_type = get_memory_parameters(type)
return FCell(primitive=FPrimitive(name=name, data=data, data_type=data_type, type=PrimitiveType.Constant))
# type, shape = const.data.dtype, const.data.shape
pass

def visit_call(self, call):
def visit_call(self, call) -> List[FCell]:
attributes = call.attrs
cells, args = [], []
for arg in call.args:
argument = self.visit(arg)
cells.append(argument)
args.append(argument)
cells.append(FCell(dahlia_declaration=self.get_dahlia_declaration(call.op.name, cells, args, call.attrs)))
# We are representing all function calls in Relay IR at the Dahlia level, which will then be lowered to FuTIL.
# Note, the Relay function's output is not defined until the `let` statement is visited.
function, name, op = GetRelayFunctionCall(call.op.name)
component_name = self.id(name)
relay_function_call = RelayFunctionCall(component_name=component_name, name=f'comp_{component_name}',
op=op, inputs=args, attributes=call.attrs, lowering_function=function)
cells.append(FCell(relay_function=relay_function_call))
return cells

def visit_function(self, function):
body = self.visit(function.body)
for cell in flatten(body):
self.main.add_cell(cell)
if not cell.is_dahlia_declaration(): continue
self.dahlia_components.append(cell.dahlia_declaration.program)
for cell in flatten(body): self.main.add_cell(cell)
build_main_controls(self.main)
return pp_component(self.main)
return pp_lowered_relay_function(self.main)


def relay_transforms(expr: Function) -> Function:
"""https://tvm.apache.org/docs/api/python/relay/transform.html"""
transform = tvm.transform.Sequential([
transforms = tvm.transform.Sequential([
relay.transform.SimplifyExpr(),
relay.transform.SimplifyInference(),
relay.transform.InferType()
relay.transform.InferType(),
])
mod = ir.IRModule.from_expr(expr)
mod['main'] = expr
mod = transform(mod)
mod = transforms(mod)
return mod['main']


Expand All @@ -147,11 +111,9 @@ def lower_to_futil(program) -> str:
program = relay_transforms(program)
visitor = Relay2Futil()

PREAMBLE = """import "primitives/std.lib";"""
PREAMBLE = """import "primitives/std.lib";\n"""
MAIN = visitor.visit(program)
DAHLIA_COMPONENTS = '\n'.join(visitor.dahlia_components)
NEWL = '\n\n'
return f'{PREAMBLE}{NEWL}{DAHLIA_COMPONENTS}{NEWL}{MAIN}'
return '\n'.join((PREAMBLE, MAIN))


if __name__ == '__main__':
Expand Down
Loading