huanmei9 opened a new pull request, #12315:
URL: https://github.com/apache/tvm/pull/12315

   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.
   
   ```python
   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)
   ```
   
   ```Python
   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_multiple2div`to check $\epsilon_0 * x + \epsilon_1 < \frac{1}{a}$.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to