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?