#include "mir/ops/ConcatOp.h"
#include "mir/ops/ConstantOp.h"
#include "mir/ops/Conv2DOp.h"
+#include "mir/ops/DepthwiseConv2DOp.h"
#include "mir/ops/MulOp.h"
#include "mir/ops/PoolOp.h"
#include "mir/ops/ReluOp.h"
return decode_node;
}
+loco::DepthwiseFilterEncode *createHWCMDepthwiseFilterEncode(loco::Graph *graph)
+{
+ auto filter_enc = graph->nodes()->create<loco::DepthwiseFilterEncode>();
+ auto enc = stdex::make_unique<loco::PermutingEncoder<loco::Domain::DepthwiseFilter>>();
+ // mir using filter convention as TF
+ // In TensorFlow, dwconv2d filter is a 4-D tensor of following shape:
+ // [filter_height, filter_width, in_channels, channel_multiplier]
+ enc->perm()->axis(loco::DepthwiseFilterAxis::Height) = 0;
+ enc->perm()->axis(loco::DepthwiseFilterAxis::Width) = 1;
+ enc->perm()->axis(loco::DepthwiseFilterAxis::Depth) = 2;
+ enc->perm()->axis(loco::DepthwiseFilterAxis::Multiplier) = 3;
+
+ filter_enc->encoder(std::move(enc));
+ return filter_enc;
+}
+
loco::DataType convertDataType(mir::DataType data_type)
{
switch (data_type)
_mir2loco_map.emplace(&op, decode_node);
}
+void Transformer::visit(mir::ops::DepthwiseConv2DOp &op)
+{
+ auto input = op.getInput(0)->getProducer()->getNode();
+ auto kernel = op.getInput(1)->getProducer()->getNode();
+ // Get ConstantOp
+ auto const_node = _mir2loco_map.at(kernel);
+
+ auto filter_enc = createHWCMDepthwiseFilterEncode(_loco_graph.get());
+ // Set filter input
+ filter_enc->input(const_node);
+ // Setting up DepthwiseConv2D
+
+ // FeatureEncode
+ auto feature_enc = createNHWCFeatureEncode(_loco_graph.get());
+ // Set Input
+ auto loco_it = _mir2loco_map.find(input);
+ assert(loco_it != _mir2loco_map.end()); // can't find the input
+ feature_enc->input(loco_it->second);
+ // DepthwiseConv2D
+ auto dw_conv2d_node = _loco_graph->nodes()->create<loco::DepthwiseConv2D>();
+ setupStride(op.getStrides(), dw_conv2d_node->stride());
+ setupPad(op.getPaddingBefore(), op.getPaddingAfter(), dw_conv2d_node->pad());
+ // Set Input
+ dw_conv2d_node->ifm(feature_enc);
+ dw_conv2d_node->ker(filter_enc);
+ // FeatureDecode
+ auto feature_dec = createNHWCFeatureDecode(_loco_graph.get());
+ // Set Input
+ feature_dec->input(dw_conv2d_node);
+ // Not set Shape
+ // Add to map
+ _mir2loco_map.emplace(&op, feature_dec);
+}
+
void Transformer::visit(mir::ops::InputOp &op)
{
auto pull_node = _loco_graph->nodes()->create<loco::Pull>();
#include "mir/ops/ConcatOp.h"
#include "mir/ops/ConstantOp.h"
#include "mir/ops/Conv2DOp.h"
+#include "mir/ops/DepthwiseConv2DOp.h"
#include "mir/ops/MulOp.h"
#include "mir/ops/PoolOp.h"
#include "mir/ops/ReluOp.h"
ASSERT_EQ(pull2_node->dim(2), 7);
ASSERT_EQ(pull2_node->dim(3), 3);
}
+
+TEST_F(TestTransformer_mir2loco, DepthwiseConv2D_Test)
+{
+ mir::Graph mir_graph;
+
+ mir::Shape input_shape = mir::Shape({7, 7, 9, 1});
+ auto *input = mir_graph.create<mir::ops::InputOp>("input", input_shape);
+ mir::Shape shape = mir::Shape({2, 3, 1, 1});
+ const float data[] = {5.9, 6.7, 5.32, 54.11231, 43.2444, 3.409};
+ auto mir_tensor = mir::TensorVariant(mir::DataType::FLOAT32, shape, (const void *)data);
+ auto *constant = mir_graph.create<mir::ops::ConstantOp>("constant", mir_tensor);
+ auto *conv = mir_graph.create<mir::ops::DepthwiseConv2DOp>(
+ "dwconv", input->getOutput(0), constant->getOutput(0), mir::Shape{2, 3},
+ std::vector<int32_t>{5, 9}, std::vector<int32_t>{7, 4});
+ auto *output = mir_graph.create<mir::ops::OutputOp>("output", conv->getOutput(0));
+
+ mir2loco::Transformer transformer;
+ auto loco_graph = transformer.transform(&mir_graph);
+
+ // Pull
+ auto inputs = loco_graph->inputs();
+ loco::Pull *pull_node = inputs->at(0)->node();
+ ASSERT_NE(pull_node, nullptr);
+ // FeatureEncode
+ auto pull_uses = loco::succs(pull_node);
+ ASSERT_EQ(pull_uses.size(), 1);
+ loco::FeatureEncode *encode_node = dynamic_cast<loco::FeatureEncode *>(*pull_uses.begin());
+ ASSERT_NE(encode_node, nullptr);
+ ASSERT_EQ(encode_node->input(), pull_node);
+ // DepthwiseConv2D
+ auto encode_uses = loco::succs(encode_node);
+ ASSERT_EQ(encode_uses.size(), 1);
+ loco::DepthwiseConv2D *dw_conv_node = dynamic_cast<loco::DepthwiseConv2D *>(*encode_uses.begin());
+ ASSERT_NE(dw_conv_node, nullptr);
+ loco::DepthwiseFilterEncode *filter_node =
+ dynamic_cast<loco::DepthwiseFilterEncode *>(dw_conv_node->ker());
+ ASSERT_NE(filter_node, nullptr);
+ ASSERT_EQ(dw_conv_node->ifm(), encode_node);
+ // Check params
+ ASSERT_EQ(dw_conv_node->pad()->left(), 5);
+ ASSERT_EQ(dw_conv_node->pad()->top(), 9);
+ ASSERT_EQ(dw_conv_node->pad()->right(), 7);
+ ASSERT_EQ(dw_conv_node->pad()->bottom(), 4);
+ ASSERT_EQ(dw_conv_node->stride()->horizontal(), 2);
+ ASSERT_EQ(dw_conv_node->stride()->vertical(), 3);
+ // ConstGen
+ loco::ConstGen *const_node = dynamic_cast<loco::ConstGen *>(filter_node->input());
+ ASSERT_NE(const_node, nullptr);
+ // FeatureDecode
+ auto dw_conv_uses = loco::succs(dw_conv_node);
+ ASSERT_EQ(dw_conv_uses.size(), 1);
+ loco::FeatureDecode *decode_node = dynamic_cast<loco::FeatureDecode *>(*dw_conv_uses.begin());
+ ASSERT_NE(decode_node, nullptr);
+ ASSERT_EQ(decode_node->input(), dw_conv_node);
+ // Push
+ auto decode_uses = loco::succs(decode_node);
+ ASSERT_EQ(decode_uses.size(), 1);
+ loco::Push *push_node = dynamic_cast<loco::Push *>(*decode_uses.begin());
+ ASSERT_NE(push_node, nullptr);
+ ASSERT_EQ(push_node->from(), decode_node);
+}