# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. import numpy as np import tvm import tvm.testing from tvm import relax from tvm.relax.transform import ToMixedPrecision from tvm.script.parser import ir as I from tvm.script.parser import relax as R from tvm.script.parser import tirx as T def _assert_test(input, expected=None, expected2=None): if expected: mod = ToMixedPrecision()(input) tvm.ir.assert_structural_equal(mod, expected) if expected2: mod = ToMixedPrecision(out_dtype="float16")(input) tvm.ir.assert_structural_equal(mod, expected2) def test_conv2d(): @I.ir_module(s_tir=True) class Input: @R.function def main( x: R.Tensor((2, 3, 28, 28), "float32"), w: R.Tensor((4, 3, 3, 3), "float32") ) -> R.Tensor(None, "float32", ndim=4): with R.dataflow(): gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32") R.output(gv) return gv @I.ir_module(s_tir=True) class Expected: @R.function def main( x: R.Tensor((2, 3, 28, 28), dtype="float32"), w: R.Tensor((4, 3, 3, 3), dtype="float32") ) -> R.Tensor((2, 4, 26, 26), dtype="float32"): with R.dataflow(): lv: R.Tensor((2, 3, 28, 28), dtype="float16") = R.astype(x, dtype="float16") lv1: R.Tensor((4, 3, 3, 3), dtype="float16") = R.astype(w, dtype="float16") gv: R.Tensor((2, 4, 26, 26), dtype="float32") = R.nn.conv2d( lv, lv1, strides=[1, 1], padding=[0, 0, 0, 0], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float32", ) R.output(gv) return gv @I.ir_module(s_tir=True) class Expected2: @R.function def main( x: R.Tensor((2, 3, 28, 28), dtype="float32"), w: R.Tensor((4, 3, 3, 3), dtype="float32") ) -> R.Tensor((2, 4, 26, 26), dtype="float32"): with R.dataflow(): lv: R.Tensor((2, 3, 28, 28), dtype="float16") = R.astype(x, dtype="float16") lv1: R.Tensor((4, 3, 3, 3), dtype="float16") = R.astype(w, dtype="float16") lv2: R.Tensor((2, 4, 26, 26), dtype="float16") = R.nn.conv2d( lv, lv1, strides=[1, 1], padding=[0, 0, 0, 0], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float16", ) gv: R.Tensor((2, 4, 26, 26), dtype="float32") = R.astype(lv2, dtype="float32") R.output(gv) return gv _assert_test(Input, Expected, Expected2) def test_conv2d_relu(): @I.ir_module(s_tir=True) class Input: @R.function def main( x: R.Tensor((2, 3, 28, 28), "float32"), w: R.Tensor((4, 3, 3, 3), "float32") ) -> R.Tensor(None, "float32", ndim=4): with R.dataflow(): lv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32") gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.relu(lv) R.output(gv) return gv @I.ir_module(s_tir=True) class Expected: @R.function def main( x: R.Tensor((2, 3, 28, 28), dtype="float32"), w: R.Tensor((4, 3, 3, 3), dtype="float32") ) -> R.Tensor((2, 4, 26, 26), dtype="float32"): with R.dataflow(): lv: R.Tensor((2, 3, 28, 28), dtype="float16") = R.astype(x, dtype="float16") lv1: R.Tensor((4, 3, 3, 3), dtype="float16") = R.astype(w, dtype="float16") lv2: R.Tensor((2, 4, 26, 26), dtype="float32") = R.nn.conv2d( lv, lv1, strides=[1, 1], padding=[0, 0, 0, 0], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float32", ) lv_1: R.Tensor((2, 4, 26, 26), dtype="float16") = R.astype(lv2, dtype="float16") lv3: R.Tensor((2, 4, 26, 26), dtype="float16") = R.nn.relu(lv_1) gv: R.Tensor((2, 4, 26, 26), dtype="float32") = R.astype(lv3, dtype="float32") R.output(gv) return gv @I.ir_module(s_tir=True) class Expected2: @R.function def main( x: R.Tensor((2, 3, 28, 28), dtype="float32"), w: R.Tensor((4, 3, 3, 3), dtype="float32") ) -> R.Tensor((2, 4, 26, 26), dtype="float32"): with R.dataflow(): lv: R.Tensor((2, 3, 28, 28), dtype="float16") = R.astype(x, dtype="float16") lv1: R.Tensor((4, 3, 3, 3), dtype="float16") = R.astype(w, dtype="float16") lv_1: R.Tensor((2, 4, 26, 26), dtype="float16") = R.nn.conv2d( lv, lv1, strides=[1, 1], padding=[0, 0, 0, 0], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float16", ) lv2: R.Tensor((2, 4, 26, 26), dtype="float16") = R.nn.relu(lv_1) gv: R.Tensor((2, 4, 26, 26), dtype="float32") = R.astype(lv2, dtype="float32") R.output(gv) return gv _assert_test(Input, Expected, Expected2) def test_unknown_dtype_is_not_rewritten(): @I.ir_module(s_tir=True) class Input: @R.function def main(x: R.Tensor((2, 3), dtype=None)) -> R.Tensor((2, 3), dtype=None): with R.dataflow(): gv: R.Tensor((2, 3), dtype=None) = R.nn.relu(x) R.output(gv) return gv mod = ToMixedPrecision()(Input) tvm.ir.assert_structural_equal(mod, Input) def test_relu_conv2d_relu(): @I.ir_module(s_tir=True) class Input: @R.function def main( x: R.Tensor((2, 3, 28, 28), "float32"), w: R.Tensor((4, 3, 3, 3), "float32") ) -> R.Tensor(None, "float32", ndim=4): with R.dataflow(): x0: R.Tensor((2, 3, 28, 28), "float32") = R.nn.relu(x) gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x0, w, out_dtype="float32") gv2: R.Tensor((2, 4, 26, 26), "float32") = R.nn.relu(gv) R.output(gv2) return gv2 @I.ir_module(s_tir=True) class Expected: @R.function def main( x: R.Tensor((2, 3, 28, 28), dtype="float32"), w: R.Tensor((4, 3, 3, 3), dtype="float32") ) -> R.Tensor((2, 4, 26, 26), dtype="float32"): with R.dataflow(): lv: R.Tensor((4, 3, 3, 3), dtype="float16") = R.astype(w, dtype="float16") x0: R.Tensor((2, 3, 28, 28), dtype="float32") = R.nn.relu(x) lv1: R.Tensor((2, 3, 28, 28), dtype="float16") = R.astype(x0, dtype="float16") lv2: R.Tensor((2, 4, 26, 26), dtype="float32") = R.nn.conv2d( lv1, lv, strides=[1, 1], padding=[0, 0, 0, 0], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float32", ) gv: R.Tensor((2, 4, 26, 26), dtype="float16") = R.astype(lv2, dtype="float16") lv3: R.Tensor((2, 4, 26, 26), dtype="float16") = R.nn.relu(gv) gv2: R.Tensor((2, 4, 26, 26), dtype="float32") = R.astype(lv3, dtype="float32") R.output(gv2) return gv2 @I.ir_module(s_tir=True) class Expected2: @R.function def main( x: R.Tensor((2, 3, 28, 28), dtype="float32"), w: R.Tensor((4, 3, 3, 3), dtype="float32") ) -> R.Tensor((2, 4, 26, 26), dtype="float32"): with R.dataflow(): lv: R.Tensor((4, 3, 3, 3), dtype="float16") = R.astype(w, dtype="float16") x0: R.Tensor((2, 3, 28, 28), dtype="float32") = R.nn.relu(x) lv1: R.Tensor((2, 3, 28, 28), dtype="float16") = R.astype(x0, dtype="float16") gv: R.Tensor((2, 4, 26, 26), dtype="float16") = R.nn.conv2d( lv1, lv, strides=[1, 1], padding=[0, 0, 0, 0], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float16", ) lv2: R.Tensor((2, 4, 26, 26), dtype="float16") = R.nn.relu(gv) gv2: R.Tensor((2, 4, 26, 26), dtype="float32") = R.astype(lv2, dtype="float32") R.output(gv2) return gv2 _assert_test(Input, Expected, Expected2) def test_conv2d_relu_conv2d(): @I.ir_module(s_tir=True) class Input: @R.function def main( x: R.Tensor((2, 3, 28, 28), "float32"), w: R.Tensor((4, 3, 3, 3), "float32"), w2: R.Tensor((4, 4, 3, 3), "float32"), ) -> R.Tensor(None, "float32", ndim=4): with R.dataflow(): gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32") gv2: R.Tensor((2, 4, 26, 26), "float32") = R.nn.relu(gv) gv3: R.Tensor((2, 4, 24, 24), "float32") = R.nn.conv2d(gv2, w2, out_dtype="float32") R.output(gv3) return gv3 @I.ir_module(s_tir=True) class Expected: @R.function def main( x: R.Tensor((2, 3, 28, 28), dtype="float32"), w: R.Tensor((4, 3, 3, 3), dtype="float32"), w2: R.Tensor((4, 4, 3, 3), dtype="float32"), ) -> R.Tensor((2, 4, 24, 24), dtype="float32"): with R.dataflow(): lv: R.Tensor((2, 3, 28, 28), dtype="float16") = R.astype(x, dtype="float16") lv1: R.Tensor((4, 3, 3, 3), dtype="float16") = R.astype(w, dtype="float16") lv2: R.Tensor((4, 4, 3, 3), dtype="float16") = R.astype(w2, dtype="float16") lv3: R.Tensor((2, 4, 26, 26), dtype="float32") = R.nn.conv2d( lv, lv1, strides=[1, 1], padding=[0, 0, 0, 0], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float32", ) gv: R.Tensor((2, 4, 26, 26), dtype="float16") = R.astype(lv3, dtype="float16") gv2: R.Tensor((2, 4, 26, 26), dtype="float16") = R.nn.relu(gv) gv3: R.Tensor((2, 4, 24, 24), dtype="float32") = R.nn.conv2d( gv2, lv2, strides=[1, 1], padding=[0, 0, 0, 0], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float32", ) R.output(gv3) return gv3 @I.ir_module(s_tir=True) class Expected2: @R.function def main( x: R.Tensor((2, 3, 28, 28), dtype="float32"), w: R.Tensor((4, 3, 3, 3), dtype="float32"), w2: R.Tensor((4, 4, 3, 3), dtype="float32"), ) -> R.Tensor((2, 4, 24, 24), dtype="float32"): with R.dataflow(): lv: R.Tensor((2, 3, 28, 28), dtype="float16") = R.astype(x, dtype="float16") lv1: R.Tensor((4, 3, 3, 3), dtype="float16") = R.astype(w, dtype="float16") lv2: R.Tensor((4, 4, 3, 3), dtype="float16") = R.astype(w2, dtype="float16") gv: R.Tensor((2, 4, 26, 26), dtype="float16") = R.nn.conv2d( lv, lv1, strides=[1, 1], padding=[0, 0, 0, 0], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float16", ) gv2: R.Tensor((2, 4, 26, 26), dtype="float16") = R.nn.relu(gv) lv3: R.Tensor((2, 4, 24, 24), dtype="float16") = R.nn.conv2d( gv2, lv2, strides=[1, 1], padding=[0, 0, 0, 0], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float16", ) gv3: R.Tensor((2, 4, 24, 24), dtype="float32") = R.astype(lv3, dtype="float32") R.output(gv3) return gv3 _assert_test(Input, Expected, Expected2) def test_gemm_add_silu(): @I.ir_module(s_tir=True) class Input: @R.function def main( x: R.Tensor((2, 320), "float32"), w1: R.Tensor((320, 1280), "float32"), w2: R.Tensor((2, 1280), "float32"), ) -> R.Tensor(None, "float32", ndim=2): with R.dataflow(): gv0: R.Tensor((2, 1280), "float32") = R.matmul(x, w1, out_dtype="float32") gv1: R.Tensor((2, 1280), "float32") = R.add(gv0, w2) gv2: R.Tensor((2, 1280), "float32") = R.nn.silu(gv1) R.output(gv2) return gv2 @I.ir_module(s_tir=True) class Expected: @R.function def main( x: R.Tensor((2, 320), dtype="float32"), w1: R.Tensor((320, 1280), dtype="float32"), w2: R.Tensor((2, 1280), dtype="float32"), ) -> R.Tensor((2, 1280), dtype="float32"): with R.dataflow(): lv: R.Tensor((2, 320), dtype="float16") = R.astype(x, dtype="float16") lv1: R.Tensor((320, 1280), dtype="float16") = R.astype(w1, dtype="float16") lv2: R.Tensor((2, 1280), dtype="float32") = R.matmul(lv, lv1, out_dtype="float32") gv0: R.Tensor((2, 1280), dtype="float16") = R.astype(lv2, dtype="float16") lv3: R.Tensor((2, 1280), dtype="float32") = R.astype(gv0, dtype="float32") gv1: R.Tensor((2, 1280), dtype="float32") = R.add(lv3, w2) gv2: R.Tensor((2, 1280), dtype="float32") = R.nn.silu(gv1) R.output(gv2) return gv2 @I.ir_module(s_tir=True) class Expected2: @R.function def main( x: R.Tensor((2, 320), dtype="float32"), w1: R.Tensor((320, 1280), dtype="float32"), w2: R.Tensor((2, 1280), dtype="float32"), ) -> R.Tensor((2, 1280), dtype="float32"): with R.dataflow(): lv: R.Tensor((2, 320), dtype="float16") = R.astype(x, dtype="float16") lv1: R.Tensor((320, 1280), dtype="float16") = R.astype(w1, dtype="float16") gv0: R.Tensor((2, 1280), dtype="float16") = R.matmul(lv, lv1, out_dtype="float16") lv2: R.Tensor((2, 1280), dtype="float32") = R.astype(gv0, dtype="float32") gv1: R.Tensor((2, 1280), dtype="float32") = R.add(lv2, w2) gv2: R.Tensor((2, 1280), dtype="float32") = R.nn.silu(gv1) R.output(gv2) return gv2 _assert_test(Input, Expected, Expected2) def test_tuple(): @I.ir_module(s_tir=True) class Input: @R.function def main( x: R.Tensor((2, 3, 28, 28), "float32"), w: R.Tensor((4, 3, 3, 3), "float32"), w_2: R.Tensor((4, 4, 3, 3), "float32"), ) -> R.Tensor(None, "float32", ndim=4): with R.dataflow(): gv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32") gv2: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32") gv3 = (gv, gv2) gv4 = (gv3, gv2) gv5 = gv4[0] gv6 = gv5[0] gv7 = R.nn.conv2d(gv6, w_2, out_dtype="float32") R.output(gv7) return gv7 @I.ir_module(s_tir=True) class Expected: @R.function def main( x: R.Tensor((2, 3, 28, 28), dtype="float32"), w: R.Tensor((4, 3, 3, 3), dtype="float32"), w_2: R.Tensor((4, 4, 3, 3), dtype="float32"), ) -> R.Tensor((2, 4, 24, 24), dtype="float32"): with R.dataflow(): lv: R.Tensor((2, 3, 28, 28), dtype="float16") = R.astype(x, dtype="float16") lv1: R.Tensor((4, 3, 3, 3), dtype="float16") = R.astype(w, dtype="float16") lv2: R.Tensor((4, 4, 3, 3), dtype="float16") = R.astype(w_2, dtype="float16") lv3: R.Tensor((2, 4, 26, 26), dtype="float32") = R.nn.conv2d( lv, lv1, strides=[1, 1], padding=[0, 0, 0, 0], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float32", ) gv: R.Tensor((2, 4, 26, 26), dtype="float16") = R.astype(lv3, dtype="float16") lv4: R.Tensor((2, 4, 26, 26), dtype="float32") = R.nn.conv2d( lv, lv1, strides=[1, 1], padding=[0, 0, 0, 0], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float32", ) gv2: R.Tensor((2, 4, 26, 26), dtype="float16") = R.astype(lv4, dtype="float16") gv3: R.Tuple( R.Tensor((2, 4, 26, 26), dtype="float16"), R.Tensor((2, 4, 26, 26), dtype="float16"), ) = (gv, gv2) gv4: R.Tuple( R.Tuple( R.Tensor((2, 4, 26, 26), dtype="float16"), R.Tensor((2, 4, 26, 26), dtype="float16"), ), R.Tensor((2, 4, 26, 26), dtype="float16"), ) = (gv3, gv2) gv5: R.Tuple( R.Tensor((2, 4, 26, 26), dtype="float16"), R.Tensor((2, 4, 26, 26), dtype="float16"), ) = gv4[0] gv6: R.Tensor((2, 4, 26, 26), dtype="float16") = gv5[0] gv7: R.Tensor((2, 4, 24, 24), dtype="float32") = R.nn.conv2d( gv6, lv2, strides=[1, 1], padding=[0, 0, 0, 0], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float32", ) R.output(gv7) return gv7 @I.ir_module(s_tir=True) class Expected2: @R.function def main( x: R.Tensor((2, 3, 28, 28), dtype="float32"), w: R.Tensor((4, 3, 3, 3), dtype="float32"), w_2: R.Tensor((4, 4, 3, 3), dtype="float32"), ) -> R.Tensor((2, 4, 24, 24), dtype="float32"): with R.dataflow(): lv: R.Tensor((2, 3, 28, 28), dtype="float16") = R.astype(x, dtype="float16") lv1: R.Tensor((4, 3, 3, 3), dtype="float16") = R.astype(w, dtype="float16") lv2: R.Tensor((4, 4, 3, 3), dtype="float16") = R.astype(w_2, dtype="float16") gv: R.Tensor((2, 4, 26, 26), dtype="float16") = R.nn.conv2d( lv, lv1, strides=[1, 1], padding=[0, 0, 0, 0], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float16", ) gv2: R.Tensor((2, 4, 26, 26), dtype="float16") = R.nn.conv2d( lv, lv1, strides=[1, 1], padding=[0, 0, 0, 0], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float16", ) gv3: R.Tuple( R.Tensor((2, 4, 26, 26), dtype="float16"), R.Tensor((2, 4, 26, 26), dtype="float16"), ) = (gv, gv2) gv4: R.Tuple( R.Tuple( R.Tensor((2, 4, 26, 26), dtype="float16"), R.Tensor((2, 4, 26, 26), dtype="float16"), ), R.Tensor((2, 4, 26, 26), dtype="float16"), ) = (gv3, gv2) gv5: R.Tuple( R.Tensor((2, 4, 26, 26), dtype="float16"), R.Tensor((2, 4, 26, 26), dtype="float16"), ) = gv4[0] gv6: R.Tensor((2, 4, 26, 26), dtype="float16") = gv5[0] lv3: R.Tensor((2, 4, 24, 24), dtype="float16") = R.nn.conv2d( gv6, lv2, strides=[1, 1], padding=[0, 0, 0, 0], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float16", ) gv7: R.Tensor((2, 4, 24, 24), dtype="float32") = R.astype(lv3, dtype="float32") R.output(gv7) return gv7 _assert_test(Input, Expected, Expected2) def test_concat_matmul(): @I.ir_module(s_tir=True) class Input: @R.function def main( lv10: R.Tensor((2, 160), "float32"), lv12: R.Tensor((2, 160), "float32"), w: R.Tensor((320, 1280), "float32"), ) -> R.Tensor(None, "float32", ndim=2): with R.dataflow(): lv13: R.Tensor((2, 320), "float32") = R.concat((lv10, lv12), axis=-1) lv14: R.Tensor((2, 1280), "float32") = R.matmul(lv13, w, out_dtype="float32") R.output(lv14) return lv14 @I.ir_module(s_tir=True) class Expected: @R.function def main( lv10: R.Tensor((2, 160), dtype="float32"), lv12: R.Tensor((2, 160), dtype="float32"), w: R.Tensor((320, 1280), dtype="float32"), ) -> R.Tensor((2, 1280), dtype="float32"): with R.dataflow(): lv: R.Tensor((320, 1280), dtype="float16") = R.astype(w, dtype="float16") lv13: R.Tensor((2, 320), dtype="float32") = R.concat((lv10, lv12), axis=-1) lv1: R.Tensor((2, 320), dtype="float16") = R.astype(lv13, dtype="float16") lv14: R.Tensor((2, 1280), dtype="float32") = R.matmul(lv1, lv, out_dtype="float32") R.output(lv14) return lv14 @I.ir_module(s_tir=True) class Expected2: @R.function def main( lv10: R.Tensor((2, 160), dtype="float32"), lv12: R.Tensor((2, 160), dtype="float32"), w: R.Tensor((320, 1280), dtype="float32"), ) -> R.Tensor((2, 1280), dtype="float32"): with R.dataflow(): lv: R.Tensor((320, 1280), dtype="float16") = R.astype(w, dtype="float16") lv13: R.Tensor((2, 320), dtype="float32") = R.concat((lv10, lv12), axis=-1) lv1: R.Tensor((2, 320), dtype="float16") = R.astype(lv13, dtype="float16") lv2: R.Tensor((2, 1280), dtype="float16") = R.matmul(lv1, lv, out_dtype="float16") lv14: R.Tensor((2, 1280), dtype="float32") = R.astype(lv2, dtype="float32") R.output(lv14) return lv14 _assert_test(Input, Expected, Expected2) def test_conv2d_softmax(): @I.ir_module(s_tir=True) class Input: @R.function def main( x: R.Tensor((2, 3, 28, 28), "float32"), w: R.Tensor((3, 3, 3, 3), "float32") ) -> R.Tensor(None, "float32", ndim=4): with R.dataflow(): gv: R.Tensor((2, 3, 28, 28), "float32") = R.nn.conv2d(x, w, padding=(1, 1)) gv1: R.Tensor((2, 3, 28, 28), "float32") = R.nn.softmax(x, axis=1) gv2 = R.add(gv, gv1) R.output(gv2) return gv2 @I.ir_module(s_tir=True) class Expected: @R.function def main( x: R.Tensor((2, 3, 28, 28), dtype="float32"), w: R.Tensor((3, 3, 3, 3), dtype="float32") ) -> R.Tensor((2, 3, 28, 28), dtype="float32"): with R.dataflow(): lv: R.Tensor((3, 3, 3, 3), dtype="float16") = R.astype(w, dtype="float16") lv1: R.Tensor((2, 3, 28, 28), dtype="float16") = R.astype(x, dtype="float16") lv2: R.Tensor((2, 3, 28, 28), dtype="float32") = R.nn.conv2d( lv1, lv, strides=[1, 1], padding=[1, 1, 1, 1], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float32", ) gv: R.Tensor((2, 3, 28, 28), dtype="float16") = R.astype(lv2, dtype="float16") gv1: R.Tensor((2, 3, 28, 28), dtype="float32") = R.nn.softmax(x, axis=1) lv3: R.Tensor((2, 3, 28, 28), dtype="float32") = R.astype(gv, dtype="float32") gv2: R.Tensor((2, 3, 28, 28), dtype="float32") = R.add(lv3, gv1) R.output(gv2) return gv2 @I.ir_module(s_tir=True) class Expected2: @R.function def main( x: R.Tensor((2, 3, 28, 28), dtype="float32"), w: R.Tensor((3, 3, 3, 3), dtype="float32") ) -> R.Tensor((2, 3, 28, 28), dtype="float32"): with R.dataflow(): lv: R.Tensor((3, 3, 3, 3), dtype="float16") = R.astype(w, dtype="float16") lv1: R.Tensor((2, 3, 28, 28), dtype="float16") = R.astype(x, dtype="float16") gv: R.Tensor((2, 3, 28, 28), dtype="float16") = R.nn.conv2d( lv1, lv, strides=[1, 1], padding=[1, 1, 1, 1], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float16", ) gv1: R.Tensor((2, 3, 28, 28), dtype="float32") = R.nn.softmax(x, axis=1) lv2: R.Tensor((2, 3, 28, 28), dtype="float32") = R.astype(gv, dtype="float32") gv2: R.Tensor((2, 3, 28, 28), dtype="float32") = R.add(lv2, gv1) R.output(gv2) return gv2 _assert_test(Input, Expected, Expected2) def test_conv2d_bias_conv2d(): @tvm.script.ir_module class Input: @R.function def main( z: R.Tensor((1, 4, 64, 64), dtype="float32"), w0: R.Tensor((512, 4, 3, 3), dtype="float16"), w1: R.Tensor((512,), dtype="float16"), w2: R.Tensor((4, 4, 1, 1), dtype="float16"), w3: R.Tensor((4,), dtype="float16"), ) -> R.Tensor((1, 512, 64, 64), dtype="float32"): # block 0 with R.dataflow(): lv: R.Tensor((512, 4, 3, 3), dtype="float32") = R.wrap_param(w0, dtype="float32") lv1: R.Tensor((512,), dtype="float32") = R.wrap_param(w1, dtype="float32") lv140: R.Tensor((4, 4, 1, 1), dtype="float32") = R.wrap_param(w2, dtype="float32") lv141: R.Tensor((4,), dtype="float32") = R.wrap_param(w3, dtype="float32") lv142: R.Tensor((1, 4, 64, 64), dtype="float32") = R.nn.conv2d( z, lv140, strides=[1, 1], padding=[0, 0, 0, 0], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float32", ) lv143: R.Tensor((1, 4, 1, 1), dtype="float32") = R.reshape(lv141, (1, 4, 1, 1)) lv144: R.Tensor((1, 4, 64, 64), dtype="float32") = R.add(lv142, lv143) lv145: R.Tensor((1, 512, 64, 64), dtype="float32") = R.nn.conv2d( lv144, lv, strides=[1, 1], padding=[1, 1, 1, 1], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float32", ) lv146: R.Tensor((1, 512, 1, 1), dtype="float32") = R.reshape(lv1, (1, 512, 1, 1)) lv147: R.Tensor((1, 512, 64, 64), dtype="float32") = R.add(lv145, lv146) gv: R.Tensor((1, 512, 64, 64), dtype="float32") = lv147 R.output(gv) return gv @I.ir_module(s_tir=True) class Expected: @R.function def main( z: R.Tensor((1, 4, 64, 64), dtype="float32"), w0: R.Tensor((512, 4, 3, 3), dtype="float16"), w1: R.Tensor((512,), dtype="float16"), w2: R.Tensor((4, 4, 1, 1), dtype="float16"), w3: R.Tensor((4,), dtype="float16"), ) -> R.Tensor((1, 512, 64, 64), dtype="float32"): # block 0 with R.dataflow(): lv: R.Tensor((1, 4, 64, 64), dtype="float16") = R.astype(z, dtype="float16") lv_1: R.Tensor((512, 4, 3, 3), dtype="float16") = w0 lv1: R.Tensor((512,), dtype="float16") = w1 lv140: R.Tensor((4, 4, 1, 1), dtype="float16") = w2 lv141: R.Tensor((4,), dtype="float16") = w3 lv1_1: R.Tensor((1, 4, 64, 64), dtype="float32") = R.nn.conv2d( lv, lv140, strides=[1, 1], padding=[0, 0, 0, 0], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float32", ) lv142: R.Tensor((1, 4, 64, 64), dtype="float16") = R.astype(lv1_1, dtype="float16") lv143: R.Tensor((1, 4, 1, 1), dtype="float16") = R.reshape(lv141, (1, 4, 1, 1)) lv144: R.Tensor((1, 4, 64, 64), dtype="float16") = R.add(lv142, lv143) lv2: R.Tensor((1, 512, 64, 64), dtype="float32") = R.nn.conv2d( lv144, lv_1, strides=[1, 1], padding=[1, 1, 1, 1], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float32", ) lv145: R.Tensor((1, 512, 64, 64), dtype="float16") = R.astype(lv2, dtype="float16") lv146: R.Tensor((1, 512, 1, 1), dtype="float16") = R.reshape(lv1, (1, 512, 1, 1)) lv147: R.Tensor((1, 512, 64, 64), dtype="float16") = R.add(lv145, lv146) gv: R.Tensor((1, 512, 64, 64), dtype="float32") = R.astype(lv147, dtype="float32") R.output(gv) return gv @I.ir_module(s_tir=True) class Expected2: @R.function def main( z: R.Tensor((1, 4, 64, 64), dtype="float32"), w0: R.Tensor((512, 4, 3, 3), dtype="float16"), w1: R.Tensor((512,), dtype="float16"), w2: R.Tensor((4, 4, 1, 1), dtype="float16"), w3: R.Tensor((4,), dtype="float16"), ) -> R.Tensor((1, 512, 64, 64), dtype="float32"): with R.dataflow(): lv: R.Tensor((1, 4, 64, 64), dtype="float16") = R.astype(z, dtype="float16") lv_1: R.Tensor((512, 4, 3, 3), dtype="float16") = w0 lv1: R.Tensor((512,), dtype="float16") = w1 lv140: R.Tensor((4, 4, 1, 1), dtype="float16") = w2 lv141: R.Tensor((4,), dtype="float16") = w3 lv142: R.Tensor((1, 4, 64, 64), dtype="float16") = R.nn.conv2d( lv, lv140, strides=[1, 1], padding=[0, 0, 0, 0], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float16", ) lv143: R.Tensor((1, 4, 1, 1), dtype="float16") = R.reshape( lv141, R.shape([1, 4, 1, 1]) ) lv144: R.Tensor((1, 4, 64, 64), dtype="float16") = R.add(lv142, lv143) lv145: R.Tensor((1, 512, 64, 64), dtype="float16") = R.nn.conv2d( lv144, lv_1, strides=[1, 1], padding=[1, 1, 1, 1], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float16", ) lv146: R.Tensor((1, 512, 1, 1), dtype="float16") = R.reshape( lv1, R.shape([1, 512, 1, 1]) ) lv147: R.Tensor((1, 512, 64, 64), dtype="float16") = R.add(lv145, lv146) gv: R.Tensor((1, 512, 64, 64), dtype="float32") = R.astype(lv147, dtype="float32") R.output(gv) return gv binding = { "w0": np.random.uniform(size=(512, 4, 3, 3)).astype("float16"), "w1": np.random.uniform(size=(512,)).astype("float16"), "w2": np.random.uniform(size=(4, 4, 1, 1)).astype("float16"), "w3": np.random.uniform(size=(4,)).astype("float16"), } binding = {k: tvm.runtime.tensor(v) for k, v in binding.items()} Input = relax.transform.BindParams("main", binding)(Input) Expected = relax.transform.BindParams("main", binding)(Expected) Expected2 = relax.transform.BindParams("main", binding)(Expected2) _assert_test(Input, Expected, Expected2) def test_tuple_get(): @tvm.script.ir_module class Module: @R.function def main( x: R.Tensor((1, 4, 64, 64), dtype="float32"), w: R.Tensor((512, 4, 3, 3), dtype="float32"), bias: R.Tensor((512, 1, 1), dtype="float32"), ) -> R.Tensor((1, 256, 64, 64), dtype="float32"): with R.dataflow(): conv = R.nn.conv2d( x, w, strides=[1, 1], padding=[0, 0, 1, 1], ) bias_out = R.add(conv, bias) split = R.split(bias_out, indices_or_sections=2, axis=1) out = R.add(split[0], split[1]) R.output(out) return out @tvm.script.ir_module class Expected: @R.function def main( x: R.Tensor((1, 4, 64, 64), dtype="float32"), w: R.Tensor((512, 4, 3, 3), dtype="float32"), bias: R.Tensor((512, 1, 1), dtype="float32"), ): with R.dataflow(): lv = R.astype(x, dtype="float16") lv1 = R.astype(w, dtype="float16") conv = R.nn.conv2d( lv, lv1, strides=[1, 1], padding=[0, 0, 1, 1], out_dtype="float16", ) lv2 = R.astype(conv, dtype="float32") bias_out = R.add(lv2, bias) split = R.split(bias_out, indices_or_sections=2, axis=1) lv3 = split[0] lv4 = split[1] out = R.add(lv3, lv4) R.output(out) return out _assert_test(Module, expected2=Expected) def test_conv2d_bias_fp32(): @tvm.script.ir_module class Input: @R.function def main( x: R.Tensor((1, 4, 64, 64), dtype="float32"), w: R.Tensor((512, 4, 3, 3), dtype="float32"), bias: R.Tensor((512,), dtype="float32"), ) -> R.Tensor((1, 512, 64, 64), dtype="float32"): # block 0 with R.dataflow(): lv142: R.Tensor((1, 512, 62, 62), dtype="float32") = R.nn.conv2d( x, w, strides=[1, 1], padding=[0, 0, 0, 0], out_dtype="float32", ) lv143: R.Tensor((1, 512, 1, 1), dtype="float32") = R.reshape(bias, (1, 512, 1, 1)) lv144: R.Tensor((1, 512, 62, 62), dtype="float32") = R.add(lv142, lv143) R.output(lv144) return lv144 @tvm.script.ir_module class Expected: @R.function def main( x: R.Tensor((1, 4, 64, 64), dtype="float32"), w: R.Tensor((512, 4, 3, 3), dtype="float32"), bias: R.Tensor((512,), dtype="float32"), ) -> R.Tensor((1, 512, 62, 62), dtype="float32"): with R.dataflow(): lv: R.Tensor((1, 4, 64, 64), dtype="float16") = R.astype(x, dtype="float16") lv1: R.Tensor((512, 4, 3, 3), dtype="float16") = R.astype(w, dtype="float16") lv142: R.Tensor((1, 512, 62, 62), dtype="float16") = R.nn.conv2d( lv, lv1, strides=[1, 1], padding=[0, 0, 0, 0], out_dtype="float16", ) lv2: R.Tensor((512,), dtype="float16") = R.astype(bias, dtype="float16") lv143: R.Tensor((1, 512, 1, 1), dtype="float16") = R.reshape( lv2, R.shape([1, 512, 1, 1]) ) lv3: R.Tensor((1, 512, 62, 62), dtype="float16") = R.add(lv142, lv143) lv144: R.Tensor((1, 512, 62, 62), dtype="float32") = R.astype(lv3, dtype="float32") R.output(lv144) return lv144 @tvm.script.ir_module class Expected_no_bias_cast: @R.function def main( x: R.Tensor((1, 4, 64, 64), dtype="float32"), w: R.Tensor((512, 4, 3, 3), dtype="float32"), bias: R.Tensor((512,), dtype="float32"), ) -> R.Tensor((1, 512, 62, 62), dtype="float32"): with R.dataflow(): lv: R.Tensor((1, 4, 64, 64), dtype="float16") = R.astype(x, dtype="float16") lv1: R.Tensor((512, 4, 3, 3), dtype="float16") = R.astype(w, dtype="float16") lv142: R.Tensor((1, 512, 62, 62), dtype="float16") = R.nn.conv2d( lv, lv1, strides=[1, 1], padding=[0, 0, 0, 0], out_dtype="float16", ) lv143: R.Tensor((1, 512, 1, 1), dtype="float32") = R.reshape( bias, R.shape([1, 512, 1, 1]) ) lv2: R.Tensor((1, 512, 62, 62), dtype="float32") = R.astype(lv142, dtype="float32") lv144: R.Tensor((1, 512, 62, 62), dtype="float32") = R.add(lv2, lv143) R.output(lv144) return lv144 binding_np = { "w": np.random.uniform(size=(512, 4, 3, 3)).astype("float32"), "bias": np.random.uniform(size=(512,)).astype("float32"), } binding = {k: tvm.runtime.tensor(v) for k, v in binding_np.items()} Input_bound = relax.transform.BindParams("main", binding)(Input) Expected = relax.transform.BindParams("main", binding)(Expected) _assert_test(Input_bound, expected2=Expected) binding_np["bias"][0] = 70000 # Out of fp16 range binding = {k: tvm.runtime.tensor(v) for k, v in binding_np.items()} Input_bound = relax.transform.BindParams("main", binding)(Input) Expected_no_bias_cast = relax.transform.BindParams("main", binding)(Expected_no_bias_cast) _assert_test(Input_bound, expected2=Expected_no_bias_cast) def test_convert_sig(): @tvm.script.ir_module class Input: @R.function def main( x: R.Tensor((1, 4, 64, 64), dtype="float32"), w: R.Tensor((512, 4, 3, 3), dtype="float32"), bias: R.Tensor((512,), dtype="float32"), ) -> R.Tensor((1, 512, 64, 64), dtype="float32"): # block 0 with R.dataflow(): lv142: R.Tensor((1, 512, 62, 62), dtype="float32") = R.nn.conv2d( x, w, strides=[1, 1], padding=[0, 0, 0, 0], out_dtype="float32", ) lv143: R.Tensor((1, 512, 1, 1), dtype="float32") = R.reshape(bias, (1, 512, 1, 1)) lv144: R.Tensor((1, 512, 62, 62), dtype="float32") = R.add(lv142, lv143) R.output(lv144) return lv144 @tvm.script.ir_module class Expected: @R.function def main( x: R.Tensor((1, 4, 64, 64), dtype="float32"), w: R.Tensor((512, 4, 3, 3), dtype="float16"), bias: R.Tensor((512,), dtype="float16"), ) -> R.Tensor((1, 512, 62, 62), dtype="float32"): with R.dataflow(): lv = R.astype(x, dtype="float16") lv142 = R.nn.conv2d( lv, w, strides=[1, 1], padding=[0, 0, 0, 0], out_dtype="float16" ) lv143 = R.reshape(bias, R.shape([1, 512, 1, 1])) lv1 = R.add(lv142, lv143) lv144 = R.astype(lv1, dtype="float32") R.output(lv144) return lv144 mod = ToMixedPrecision(out_dtype="float16", fp16_input_names=["w", "bias"])(Input) tvm.ir.assert_structural_equal(mod, Expected) def test_call_tir_with_float16_args(): @I.ir_module(s_tir=True) class Before: @R.function def main(A: R.Tensor([64], "float16")): cls = Before with R.dataflow(): B = R.call_tir(cls.tir_identity, [A], out_ty=R.Tensor([64], "float16")) C = R.call_tir(cls.tir_identity, [B], out_ty=R.Tensor([64], "float16")) R.output(C) return C @T.prim_func(s_tir=True) def tir_identity( Input: T.Buffer(64, "float16"), Output: T.Buffer(64, "float16"), ): for i in range(64): with T.sblock("copy"): vi = T.axis.remap("S", [i]) Output[vi] = Input[vi] Expected = Before After = ToMixedPrecision()(Before) tvm.ir.assert_structural_equal(Expected, After) def test_dynamic_strided_slice(): @I.ir_module(s_tir=True) class Input: @R.function def main( x: R.Tensor((2, 3, 28, 28), "float32"), w: R.Tensor((4, 3, 3, 3), "float32"), begin: R.Tensor((4,), "int64"), end: R.Tensor((4,), "int64"), strides: R.Tensor((4,), "int64"), ) -> R.Tensor(None, "float32", ndim=4): with R.dataflow(): lv: R.Tensor((2, 4, 26, 26), "float32") = R.nn.conv2d(x, w, out_dtype="float32") gv = R.dynamic_strided_slice(lv, begin, end, strides) R.output(gv) return gv @I.ir_module(s_tir=True) class Expected: @R.function def main( x: R.Tensor((2, 3, 28, 28), dtype="float32"), w: R.Tensor((4, 3, 3, 3), dtype="float32"), begin: R.Tensor((4,), dtype="int64"), end: R.Tensor((4,), dtype="int64"), strides: R.Tensor((4,), dtype="int64"), ) -> R.Tensor(None, dtype="float32", ndim=4): with R.dataflow(): lv: R.Tensor((2, 3, 28, 28), dtype="float16") = R.astype(x, dtype="float16") lv1: R.Tensor((4, 3, 3, 3), dtype="float16") = R.astype(w, dtype="float16") lv2: R.Tensor((2, 4, 26, 26), dtype="float32") = R.nn.conv2d( lv, lv1, strides=[1, 1], padding=[0, 0, 0, 0], dilation=[1, 1], groups=1, data_layout="NCHW", kernel_layout="OIHW", out_layout="NCHW", out_dtype="float32", ) lv3: R.Tensor((2, 4, 26, 26), dtype="float16") = R.astype(lv2, dtype="float16") lv4: R.Tensor((2, 4, 26, 26), dtype="float32") = R.astype(lv3, dtype="float32") gv: R.Tensor(None, dtype="float32", ndim=4) = R.dynamic_strided_slice( lv4, begin, end, strides ) R.output(gv) return gv _assert_test(Input, Expected) if __name__ == "__main__": tvm.testing.main()