};
/**
+ * @brief 2D Average Pooling
+ *
+ * @note Follows MaxPool2D (TODO: describe difference)
+ */
+struct AvgPool2D final : public FixedArityNode<1, Node>
+{
+public:
+ enum class Convention
+ {
+ Unknown,
+ // Use the number of elements in each receptive field as a divisor
+ Full,
+ // Use the number of valid (non-padding) elements in each receptive field as a divisor
+ Valid
+ };
+
+public:
+ Node *ifm(void) const { return at(0)->node(); }
+ void ifm(Node *node) { at(0)->node(node); }
+
+public:
+ Convention convention(void) const { return _convention; }
+ void convention(const Convention &convention) { _convention = convention; }
+
+public:
+ const Pad<2> *pad(void) const { return &_pad; }
+ Pad<2> *pad(void) { return &_pad; }
+
+public:
+ const Window<2> *window(void) const { return &_window; }
+ Window<2> *window(void) { return &_window; }
+
+public:
+ const Stride<2> *stride(void) const { return &_stride; }
+ Stride<2> *stride(void) { return &_stride; }
+
+private:
+ Convention _convention = Convention::Unknown;
+ Pad<2> _pad;
+ Window<2> _window;
+ Stride<2> _stride;
+};
+
+/**
* @brief Create a feature map from a tensor
*/
class FeatureEncode final : public FixedArityNode<1, Node>
ASSERT_EQ(maxpool_node.pad()->right(), r);
}
+TEST(AvgPool2DTest, constructor)
+{
+ loco::AvgPool2D avgpool_node;
+
+ ASSERT_EQ(avgpool_node.ifm(), nullptr);
+
+ ASSERT_EQ(avgpool_node.convention(), loco::AvgPool2D::Convention::Unknown);
+
+ ASSERT_EQ(avgpool_node.pad()->top(), 0);
+ ASSERT_EQ(avgpool_node.pad()->bottom(), 0);
+ ASSERT_EQ(avgpool_node.pad()->left(), 0);
+ ASSERT_EQ(avgpool_node.pad()->right(), 0);
+
+ ASSERT_EQ(avgpool_node.window()->vertical(), 1);
+ ASSERT_EQ(avgpool_node.window()->horizontal(), 1);
+
+ ASSERT_EQ(avgpool_node.stride()->vertical(), 1);
+ ASSERT_EQ(avgpool_node.stride()->horizontal(), 1);
+}
+
TEST(FeatureEncodeTest, constructor)
{
loco::FeatureEncode feature_encode;