}
std::vector<Operation*> ONNXOpCreator::convertPool(InputOps& inputs, ONNXOpCode op_code,
- const onnx::NodeProto& onnx_node) {
- auto* kshape = findAttribute(onnx_node, "kernel_shape");
- assert(kshape && kshape->ints_size());
- auto* strides = findAttribute(onnx_node, "strides");
- assert(strides && strides->ints_size());
- Shape onnx_kernel_shape = ShapeHelper::createShape(kshape->ints(), kshape->ints_size());
- Shape onnx_strides_shape = ShapeHelper::createShape(strides->ints(), strides->ints_size());
-
+ const onnx::NodeProto& onnx_node) {
ops::PoolOp::BorderType border_type;
ops::PoolOp::PoolingType pool_type;
+ std::vector<Operation*> result;
+ std::vector<int32_t> padding_before{0, 0};
+ std::vector<int32_t> padding_after{0, 0};
+
switch (op_code) {
+ case ONNXOpCode::opGlobalAveragePool:
+ // GlobalAveragePool is equivalent to AveragePool with kernel size equal
+ // to the spatial dimension of input tensor
+ return createOp<ops::PoolOp>(inputs[0]->getOutput(0),
+ ops::PoolOp::PoolingType::AVG,
+ inputs[0]->getOutputShape(0), // kernel_shape
+ Shape({1, 1}), // strides_shape
+ padding_before, padding_after,// no padding
+ ops::PoolOp::BorderType::ZEROFILLED,
+ ops::PoolOp::RoundMode::floor);
case ONNXOpCode::opAveragePool:
border_type = ops::PoolOp::BorderType::ZEROFILLED;
pool_type = ops::PoolOp::PoolingType::AVG;
default:
assert(false);
}
- // FIXME: it's a hack to be compatible with current implementation of PoolOp - we expect
- // 3 dims for 2D picture
- Shape window_shape{onnx_kernel_shape.dim(0), onnx_kernel_shape.dim(1)};
- // FIXME: it's another hack identical to the above one
- Shape strides_shape{onnx_strides_shape.dim(0), onnx_strides_shape.dim(1)};
- std::vector<int32_t> padding_before{0, 0};
- std::vector<int32_t> padding_after{0, 0};
- // TODO: ONNX has more parameters for pooling. We should use them.
- auto pooling = createOp<ops::PoolOp>(inputs[0]->getOutput(0), pool_type, window_shape,
- strides_shape, padding_before, padding_after, border_type);
- return pooling;
+ // Proceed with Average or Max Pool
+ auto* kshape = findAttribute(onnx_node, "kernel_shape");
+ assert(kshape && kshape->ints_size());
+ auto* strides = findAttribute(onnx_node, "strides");
+ assert(strides && strides->ints_size());
+ auto* pads = findAttribute(onnx_node, "pads");
+
+ Shape kernel_shape = ShapeHelper::createShape(kshape->ints(), kshape->ints_size());
+ Shape strides_shape = ShapeHelper::createShape(strides->ints(), strides->ints_size());
+
+ if (pads) {
+ assert(pads->ints_size() >= 2);
+ padding_before[0] = pads->ints(0);
+ padding_before[1] = pads->ints(1);
+ // TODO: ONNX padding could be for the beginning and ending along each axis that's why we
+ // should select the interesting ones.
+ if (pads->ints_size() == 4) {
+ padding_after[0] = pads->ints(2);
+ padding_after[1] = pads->ints(3);
+ }
+
+ }
+ result = createOp<ops::PoolOp>(inputs[0]->getOutput(0), pool_type, kernel_shape, strides_shape,
+ padding_before, padding_after, border_type,
+ ops::PoolOp::RoundMode::floor);
+ return result;
}
std::vector<Operation*> ONNXOpCreator::convertSoftmax(InputOps& inputs,