MXNet Average Pool count_include_pad is not the same as TVM


#1

We could see MXNet source code: https://github.com/apache/incubator-mxnet/blob/master/src/operator/nn/pool.h#L468-L478

int hstart = ph * stride_h - pad_h;
int wstart = pw * stride_w - pad_w;
int hend = std::min(hstart + kernel_h, height + pad_h);
int wend = std::min(wstart + kernel_w, width + pad_w);
int pool_size = (get_avg ? (hend - hstart) * (wend - wstart) : 1);
hstart = std::max(hstart, 0);
wstart = std::max(wstart, 0);
hend = std::min(hend, height);
wend = std::min(wend, width);
if (get_avg && !count_include_pad) {
       pool_size = (hend - hstart) * (wend - wstart);
}

If we are AvgPool, count_include_pad will not affect pool_size.
MXNet Doc said: https://mxnet.incubator.apache.org/api/python/symbol/symbol.html#mxnet.symbol.Pooling
count_include_pad is true to be default. So, our TVM MXNet frontend set count_include_pad be true default.

Here is our pool impl:

   return tvm::compute(out_shape,
    [&](const Array<Var>& output) {
      if (count_include_pad) {
        return tavg(output, kernel_height * kernel_width);
      } else {
        Expr h_start = output[height_axis] * stride_height - pad_top;
        Expr w_start = output[width_axis] * stride_width - pad_left;
        Expr h_end = ir::Min::make(h_start + kernel_height, height);
        Expr w_end = ir::Min::make(w_start + kernel_width, width);
        h_start = ir::Max::make(h_start, make_const(Int(32), 0));
        w_start = ir::Max::make(w_start, make_const(Int(32), 0));
        Expr divide_factor = ir::Max::make((h_end - h_start) * (w_end - w_start),
                                           make_const(Int(32), 1));
        return tavg(output, divide_factor);
      }
    }, "tensor", "pool_avg");

In fact, when count_include_pad is false, which is MXNet’s computation in fact.

I have tested, I find when count_include_pad be false in MXNet frontend, we have more accuracy result compared with MXNet.

How we handle this situation?

@tqchen @yzhliu @eqy @junrushao1994