Skip to content

Commit c67ceca

Browse files
committed
[Fix][Relax] Require matching bias output width when fusing parallel matmul biases
1 parent 04603e6 commit c67ceca

2 files changed

Lines changed: 43 additions & 0 deletions

File tree

src/relax/transform/combine_parallel_matmul.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,18 @@ ffi::TypedFunction<ffi::Map<Var, Expr>(ffi::Map<DFPattern, Var>, ffi::Map<Var, E
234234
if (!shapes_compatible_excluding_trailing_axes(bias_shapes, 1)) {
235235
continue;
236236
}
237+
arith::Analyzer ana;
238+
bool bias_widths_match = true;
239+
for (size_t i = 0; i < splits.size(); ++i) {
240+
const auto& shape = bias_shapes[i];
241+
if (!ana->CanProve(shape[shape.size() - 1] == splits[i].split_size)) {
242+
bias_widths_match = false;
243+
break;
244+
}
245+
}
246+
if (!bias_widths_match) {
247+
continue;
248+
}
237249
}
238250

239251
auto concat_rhs = concat(Tuple(rhs), rhs_dim - 1);

tests/python/relax/test_transform_combine_parallel_matmul.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,37 @@ def expected(
779779
tvm.ir.assert_structural_equal(after, expected)
780780

781781

782+
def test_skip_bias_fusion_when_bias_relies_on_its_own_broadcast():
783+
"""Do not fuse biases whose last dimension only matches via broadcast
784+
785+
Biases can agree with each other on every non-concat axis and still be
786+
unsafe to fuse if a bias's own last dimension doesn't equal its
787+
branch's actual output width and it was only valid by broadcasting
788+
against that branch's own matmul.
789+
"""
790+
791+
@R.function(private=True)
792+
def before(
793+
x: R.Tensor((2, 3), "float32"),
794+
w0: R.Tensor((3, 4), "float32"),
795+
w1: R.Tensor((3, 5), "float32"),
796+
b0: R.Tensor((2, 1), "float32"),
797+
b1: R.Tensor((2, 1), "float32"),
798+
):
799+
with R.dataflow():
800+
lv0 = R.matmul(x, w0)
801+
lv1 = R.matmul(x, w1)
802+
y0 = R.add(lv0, b0)
803+
y1 = R.add(lv1, b1)
804+
out = (y0, y1)
805+
R.output(out)
806+
return out
807+
808+
after = CombineParallelMatmul()(tvm.IRModule.from_expr(before))["main"]
809+
810+
tvm.ir.assert_structural_equal(after, before)
811+
812+
782813
@pytest.mark.parametrize("float32_branch", [0, 1])
783814
def test_skip_matmuls_with_different_output_dtypes(float32_branch):
784815
if float32_branch == 0:

0 commit comments

Comments
 (0)