Skip to content

Conversation

@huanmei9
Copy link
Contributor

@huanmei9 huanmei9 commented Aug 5, 2022

This PR is aim to change floating point multiplication of resize operator to integer division when method is nearest_neighbor and coordinate_transformation_mode is asymmetric.

Why this change?

When using create_prim_func to convert topi.upsampling into primfunc, tir analyzer cannot parse complex floating point operations in tir block body. In the following case, the dimensions of read buffer are inferred as 0 : 128. We expect to be tir.reads([x[i0_1, i1_1, i2_1/scale_h, i3_1/scale_w]])in line 18,so it can perform compute_at schedule on this prim_func.

scale_h = 2
scale_w = 2
x = te.placeholder([1, 128, 128, 128], "int8", "x")
y = topi.nn.upsampling(x, scale_h , scale_w)
func = te.create_prim_func([x, y])
print(func)
primfn(var_x: handle, var_resize: handle) -> ()
  attr = {"global_symbol": "main", "tir.noalias": True}
  buffers = {x: Buffer(x_1: Pointer(global int8), int8, [1, 128, 128, 128], []),
             resize: Buffer(resize_1: Pointer(global int8), int8, [1, 128, 256, 256], [])}
  buffer_map = {var_x: x, var_resize: resize} {
  block([], "root") {
    tir.reads([])
    tir.writes([])
    for (i0: int32, 0, 1) {
      for (i1: int32, 0, 128) {
        for (i2: int32, 0, 256) {
          for (i3: int32, 0, 256) {
            block([1, 128, 256, 256], "resize") as [i0_1, i1_1, i2_1, i3_1] {
              bind(i0_1, i0)
              bind(i1_1, i1)
              bind(i2_1, i2)
              bind(i3_1, i3)
              tir.reads([x[i0_1, i1_1, 0:128, 0:128]])
              tir.writes([resize[i0_1, i1_1, i2_1, i3_1]])
              resize[i0_1, i1_1, i2_1, i3_1] = cast(int8, cast(float32, x[i0_1, i1_1, max(min(cast(int32, @tir.floor(((0.5f32*cast(float32, i2_1)) + 1e-05f32), dtype=float32)), 127), 0), max(min(cast(int32, @tir.floor(((0.5f32*cast(float32, i3_1)) + 1e-05f32), dtype=float32)), 127), 0)]))
          }
        }
      }
    }
}

Why can it be changed?

This PR only modify float multiplication to integer division when method is nearest_neighbor and coordinate_transformation_mode is asymmetric(it's default setting for topi.upsampling op).

Go further, we expect to convert $\lfloor s * x + \epsilon_1 \rfloor$ to $x//a$, $s$ is scale, a float number, $x$ is input, $\epsilon_1$ is 1e-5 in resize op, $a$ is the reciprocal of $s$, an integer.

So, we can represent output as this:
$y = \lfloor s * x + \epsilon_1 \rfloor = \lfloor ( \frac{1}{a} + \epsilon_0 ) * x + \epsilon_1 \rfloor = \lfloor \frac{x}{a} + \epsilon_0 * x + \epsilon_1 \rfloor$, let $x = a * m + n$, where $m = x // a, n = x % a$ , then we can get $y = m + \lfloor \frac{n}{a} + \epsilon_0 * x + \epsilon_1 \rfloor$. In the case of upsampling op, $x$ and $a$ are always integers, so inequality $\frac{n}{a} \le \frac{a-1}{a}$ always holds. If $\epsilon_0 * x + \epsilon_1 < \frac{1}{a}$, we can get $0 < \frac{n}{a} + \epsilon_0 * x + \epsilon_1 < 1$,then $y = m + \lfloor \frac{n}{a} + \epsilon_0 * x + \epsilon_1 \rfloor = m = x // a$.

To sum up, when $\epsilon_0 * x + \epsilon_1 < \frac{1}{a}$, we can get $y = \lfloor s*x + \epsilon_1 \rfloor = x // a$.

In this PR, we assume $\epsilon_0 = \epsilon_1 = 1e-5$ and can_convert_multiply_to_intdivto check $\epsilon_0 * x + \epsilon_1 < \frac{1}{a}$.

@huanmei9 huanmei9 force-pushed the topi_change_mh branch 6 times, most recently from 94c3f08 to cb6a348 Compare August 8, 2022 09:02
@Hzfengsy Hzfengsy self-assigned this Aug 9, 2022
@Hzfengsy
Copy link
Member

Hzfengsy commented Aug 9, 2022

cc @masahi

Copy link
Member

@Hzfengsy Hzfengsy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall LGTM

@wrongtest-intellif wrongtest-intellif merged commit d8846ec into apache:main Aug 14, 2022
wrongtest-intellif pushed a commit that referenced this pull request Aug 30, 2022
#12315)

* [TOPI][OP]change float multiplication of resize op to integer division

* add unittest.

* 1. add docstring
2. rename param
xinetzone pushed a commit to daobook/tvm that referenced this pull request Nov 25, 2022
apache#12315)

* [TOPI][OP]change float multiplication of resize op to integer division

* add unittest.

* 1. add docstring
2. rename param
@huanmei9 huanmei9 deleted the topi_change_mh branch June 26, 2023 03:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants