Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Relay/Topi][Op] Added native DepthToSpace and SpaceToDepth Operators #4566

Merged
merged 11 commits into from
Dec 24, 2019
Prev Previous commit
Next Next commit
Added depth_to_space relay attributes.
  • Loading branch information
jwfromm committed Dec 22, 2019
commit f317f0d3d695107be117d4f587796654f8422c81
8 changes: 6 additions & 2 deletions include/tvm/relay/attrs/nn.h
Original file line number Diff line number Diff line change
Expand Up @@ -823,10 +823,14 @@ struct DeformableConv2DAttrs : public tvm::AttrsNode<DeformableConv2DAttrs> {

/*! \brief Attributes used in subpixel operators */
struct SubPixelAttrs : public tvm::AttrsNode<SubPixelAttrs> {
std::string data_layout;
int block_size;
std::string layout;

TVM_DECLARE_ATTRS(SubPixelAttrs, "relay.attrs.SubPixelAttrs") {
TVM_ATTR_FIELD(data_layout)
TVM_ATTR_FIELD(block_size)
.describe("The size of subpixel blocks to compose or decompose.")
.set_default(1);
TVM_ATTR_FIELD(layout)
.set_default("NCHW")
.describe(
"Dimension ordering of input data. Can be 'NCHW', 'NHWC', etc."
Expand Down
59 changes: 59 additions & 0 deletions src/relay/op/nn/nn.cc
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,65 @@ Accept logits.
.set_support_level(10)
.add_type_rel("CrossEntropy", CrossEntropyRel);

// Depth to space and space to depth
TVM_REGISTER_NODE_TYPE(SubPixelAttrs);

bool DepthToSpaceRel(const Array<Type>& types, int num_inputs, const Attrs& attrs,
const TypeReporter& reporter) {
CHECK_EQ(types.size(), 2);
const auto* data = types[0].as<TensorTypeNode>();
if (data == nullptr) return false;

static const Layout kNCHW("NCHW");

const SubPixelAttrs* param = attrs.as<SubPixelAttrs>();
CHECK(param != nullptr);
const int block_size = param->block_size;
const Layout in_layout(param->layout);
auto layout_converter = BijectiveLayoutNode::make(in_layout, kNCHW);
CHECK(layout_converter.defined())
<< "DepthToSpace only support input layouts that are convertible from NCHW."
<< " But got " << in_layout;

auto oshape = layout_converter.ForwardShape(data->shape);
oshape.Set(1, indexdiv(data->shape[1], (block_size * block_size)));
oshape.Set(2, data->shape[2] * block_size);
oshape.Set(3, data->shape[3] * block_size);

// Assign output type
reporter->Assign(types[1],
TensorTypeNode::make(layout_converter.BackwardShape(oshape), data->dtype));

return true;
}

// Positional relay function to create DepthToSpace opeator
// used by frontend FFI
Expr MakeDepthToSpace(Expr data, int block_size, std::string layout) {
auto attrs = make_node<SubPixelAttrs>();
attrs->block_size = block_size;
attrs->layout = std::move(layout);
static const Op& op = Op::Get("nn.depth_to_space");
return CallNode::make(op, {data}, Attrs(attrs), {});
}

TVM_REGISTER_API("relay.op.nn._make.depth_to_space").set_body_typed(MakeDepthToSpace);

RELAY_REGISTER_OP("nn.depth_to_space")
.describe(R"code(Rearrange input channels into spatial pixels.

- **data**: data is a 4D array of shape
(batch, in_channels, in_height, in_width) for NCHW

- **out**: Output is a 4D array of shape
(batch, in_channels / block_size * block_size, in_height * block_size, in_width * block_size) for NCHW.

)code" TVM_ADD_FILELINE)
.set_attrs_type<SubPixelAttrs>()
.set_num_inputs(1)
.add_argument("data", "Tensor", "The input tensor")
.add_type_rel("DepthToSpace", DepthToSpaceRel)
.set_attr<TOpPattern>("TOpPattern", kInjective);

} // namespace relay
} // namespace tvm