/
githubmirror
/
incubator-mxnet
Обзор
Документация
Войти
/
githubmirror
/
incubator-mxnet
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/operator/nn/upsampling.cc
251 строка
10 KB
Zhenghui Jin
[v2.0][LICENSE] Port #20493 (#20608)
28 сен 2021, 03:10
Не верифицирован
28 сен 2021, 03:10
a720b15
Код
Авторство
О чём код?
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /*! * \file upsampling_nearest.cc * \brief * \author Bing Xu, Da Zheng */ #include "./upsampling-inl.h" #include <nnvm/op_attr_types.h> #include "./deconvolution-inl.h" namespace mxnet { namespace op { static bool UpSamplingShape(const nnvm::NodeAttrs& attrs, mxnet::ShapeVector* in_shape, mxnet::ShapeVector* out_shape) { const UpSamplingParam& param_ = nnvm::get<UpSamplingParam>(attrs.parsed); CHECK_GE(in_shape->size(), 1U); const mxnet::TShape& dshape = (*in_shape)[0]; mxnet::TShape oshape = dshape; if (param_.sample_type == up_enum::kNearest) { CHECK_EQ(in_shape->size(), static_cast<size_t>(param_.num_args)); oshape[1] = 0; for (auto& shape : *in_shape) { CHECK_EQ(shape.ndim(), 4U) << "UpSamplingNearest: Input data should be 4D in (batch, channel, y, x)"; int oh = dshape[2] * param_.scale, ow = dshape[3] * param_.scale; CHECK_EQ(oh % shape[2], 0U) << "UpSamplingNearest: input height of " << shape[2] << "does not divide output height of " << oh; CHECK_EQ(ow % shape[3], 0U) << "UpSamplingNearest: input width of " << shape[3] << "does not divide output width of " << ow; if (param_.multi_input_mode == up_enum::kSum) { CHECK(oshape[1] == 0 || oshape[1] == shape[1]) << "Number of channels must be the same when multi_input_mode==sum"; oshape[1] = shape[1]; } else { oshape[1] += shape[1]; } } } else { CHECK_EQ(in_shape->size(), 2U) << "Input:[data, weight]"; CHECK_EQ(dshape.ndim(), 4U) << "UpSamplingBilinear: Input data should be 4D in (batch, channel, y, x)"; if (!shape_is_known(dshape)) return false; int kernel = 2 * param_.scale - param_.scale % 2; SHAPE_ASSIGN_CHECK(*in_shape, up_enum::kWeight, mshadow::Shape4(dshape[1], 1, kernel, kernel)); oshape = dshape; } oshape[2] = dshape[2] * param_.scale; oshape[3] = dshape[3] * param_.scale; out_shape->clear(); out_shape->push_back(oshape); return true; } static inline std::vector<std::string> ListArguments(const UpSamplingParam& param) { if (param.sample_type == up_enum::kNearest) { std::vector<std::string> ret; ret.reserve(param.num_args); for (int i = 0; i < param.num_args; ++i) { ret.push_back(std::string("arg") + std::to_string(i)); } return ret; } else { return {"data", "weight"}; } } static bool UpSamplingType(const nnvm::NodeAttrs& attrs, std::vector<int>* in_type, std::vector<int>* out_type) { const UpSamplingParam& param = nnvm::get<UpSamplingParam>(attrs.parsed); CHECK_GE(in_type->size(), 1U); int dtype = (*in_type)[0]; CHECK_NE(dtype, -1) << "First input must have specified type"; for (size_t i = 0; i < in_type->size(); ++i) { if ((*in_type)[i] == -1) { (*in_type)[i] = dtype; } else { UNIFORM_TYPE_CHECK((*in_type)[i], dtype, ListArguments(param)[i]); } } out_type->clear(); out_type->push_back(dtype); return true; } struct UpSamplingGrad { const char* op_name; std::vector<nnvm::NodeEntry> operator()(const nnvm::ObjectPtr& n, const std::vector<nnvm::NodeEntry>& ograds) const { const UpSamplingParam& param_ = nnvm::get<UpSamplingParam>(n->attrs.parsed); std::vector<nnvm::NodeEntry> heads(ograds.begin(), ograds.end()); if (param_.sample_type != up_enum::kNearest) { heads.push_back(n->inputs[up_enum::kData]); heads.push_back(n->inputs[up_enum::kWeight]); } return MakeGradNode(op_name, n, heads, n->attrs.dict); } }; DMLC_REGISTER_PARAMETER(UpSamplingParam); NNVM_REGISTER_OP(UpSampling) .describe(R"code(Upsamples the given input data. Two algorithms (``sample_type``) are available for upsampling: - Nearest Neighbor - Bilinear **Nearest Neighbor Upsampling** Input data is expected to be NCHW. Example:: x = [[[[1. 1. 1.] [1. 1. 1.] [1. 1. 1.]]]] UpSampling(x, scale=2, sample_type='nearest') = [[[[1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1.] [1. 1. 1. 1. 1. 1.]]]] **Bilinear Upsampling** Uses `deconvolution` algorithm under the hood. You need provide both input data and the kernel. Input data is expected to be NCHW. `num_filter` is expected to be same as the number of channels. Example:: x = [[[[1. 1. 1.] [1. 1. 1.] [1. 1. 1.]]]] w = [[[[1. 1. 1. 1.] [1. 1. 1. 1.] [1. 1. 1. 1.] [1. 1. 1. 1.]]]] UpSampling(x, w, scale=2, sample_type='bilinear', num_filter=1) = [[[[1. 2. 2. 2. 2. 1.] [2. 4. 4. 4. 4. 2.] [2. 4. 4. 4. 4. 2.] [2. 4. 4. 4. 4. 2.] [2. 4. 4. 4. 4. 2.] [1. 2. 2. 2. 2. 1.]]]] )code" ADD_FILELINE) .set_num_inputs([](const NodeAttrs& attrs) { const UpSamplingParam& params = nnvm::get<UpSamplingParam>(attrs.parsed); return params.sample_type == up_enum::kNearest ? params.num_args : 2; }) .set_num_outputs(1) .set_attr_parser(ParamParser<UpSamplingParam>) .set_attr<nnvm::FListInputNames>("FListInputNames", [](const NodeAttrs& attrs) { return ListArguments( nnvm::get<UpSamplingParam>(attrs.parsed)); }) .set_attr<nnvm::FListOutputNames>("FListOutputNames", [](const NodeAttrs& attrs) { return std::vector<std::string>{"output"}; }) .set_attr<mxnet::FInferShape>("FInferShape", UpSamplingShape) .set_attr<nnvm::FInferType>("FInferType", UpSamplingType) .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& n) { const UpSamplingParam& param = nnvm::get<UpSamplingParam>(n.parsed); if (param.sample_type == up_enum::kNearest) { return std::vector<ResourceRequest>(); } else { return std::vector<ResourceRequest>{ ResourceRequest::kTempSpace}; } }) .set_attr<THasDeterministicOutput>("THasDeterministicOutput", true) .set_attr<FCompute>("FCompute<cpu>", UpSamplingCompute<cpu>) .set_attr<nnvm::FGradient>("FGradient", UpSamplingGrad{"_backward_UpSampling"}) .set_attr<std::string>("key_var_num_args", "num_args") .add_argument("data", "NDArray-or-Symbol[]", "Array of tensors to upsample. " "For bilinear upsampling, there should be 2 inputs - 1 data and 1 weight.") .add_arguments(UpSamplingParam::__FIELDS__()) .set_attr<nnvm::FSetInputVarAttrOnCompose>( "FSetInputVarAttrOnCompose", [](const nnvm::NodeAttrs& attrs, nnvm::ObjectPtr var, const int index) { if (var->attrs.dict.find("__init__") != var->attrs.dict.end()) return; if (index == 1) { var->attrs.dict["__init__"] = "[\"bilinear\", {}]"; } }); NNVM_REGISTER_OP(_backward_UpSampling) .set_num_inputs([](const NodeAttrs& attrs) { const UpSamplingParam& param_ = nnvm::get<UpSamplingParam>(attrs.parsed); if (param_.sample_type != up_enum::kNearest) { return 3; } else { return 1; } }) .set_num_outputs([](const NodeAttrs& attrs) { const UpSamplingParam& params = nnvm::get<UpSamplingParam>(attrs.parsed); return params.sample_type == up_enum::kNearest ? params.num_args : 2; }) .set_attr<nnvm::TIsBackward>("TIsBackward", true) .set_attr<FResourceRequest>("FResourceRequest", [](const NodeAttrs& n) { const UpSamplingParam& param = nnvm::get<UpSamplingParam>(n.parsed); if (param.sample_type == up_enum::kNearest) { return std::vector<ResourceRequest>(); } else { return std::vector<ResourceRequest>{ ResourceRequest::kTempSpace}; } }) .set_attr_parser(ParamParser<UpSamplingParam>) .set_attr<FCompute>("FCompute<cpu>", UpSamplingGradCompute<cpu>); } // namespace op } // namespace mxnet