This repository has been archived by the owner on Nov 17, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6.8k
[MXNET-891] Support tuple of scales in upsample operator #14042
Closed
Closed
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
097c10d
Accept tuple of int as scale
vandanavk 42c25bc
Nearest neighbor working
vandanavk 6d1cce4
ONNX import/export: Upsample
vandanavk 6728347
Fix ONNX import of upsample, enable test
vandanavk f1e4973
Support multi-batch input
vandanavk f22eecb
Fix warnings, nearest neighbor
vandanavk 9fb8d1c
Revert arg changes
vandanavk 0a9dc2d
Revert bilinear test comment
vandanavk cbfea16
Fix lint error
vandanavk b2a6219
Add output in test
vandanavk 44b315e
Uncomment shape checks
vandanavk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -48,16 +48,18 @@ enum UpSamplingMultiInputMode {kConcat, kSum}; | |
} // namespace up_enum | ||
|
||
struct UpSamplingParam : public dmlc::Parameter<UpSamplingParam> { | ||
int scale; | ||
TShape scale; | ||
int num_filter; | ||
int sample_type; | ||
int num_args; | ||
int multi_input_mode; | ||
uint64_t workspace; | ||
DMLC_DECLARE_PARAMETER(UpSamplingParam) { | ||
DMLC_DECLARE_FIELD(scale) | ||
.set_range(1, 1000) | ||
.describe("Up sampling scale"); | ||
.set_default(TShape()) | ||
.describe("Up sampling scale. Integer or tuple of integers. " | ||
"Different scale per dimension is allowed only for " | ||
"nearest neighbor upsampling."); | ||
DMLC_DECLARE_FIELD(num_filter) | ||
.describe("Input filter. Only used by bilinear sample_type.") | ||
.set_default(0); | ||
|
@@ -82,6 +84,57 @@ struct UpSamplingParam : public dmlc::Parameter<UpSamplingParam> { | |
} | ||
}; // struct UpSamplingParam | ||
|
||
template<typename xpu, typename DTyp, typename AccReal> | ||
void SpatialUpSamplingNearestUpdateOutput(mshadow::Stream<cpu> *s, | ||
const std::vector<TBlob> &in_data, | ||
std::vector<TBlob> *out_data) { | ||
Tensor<xpu, 4, DTyp> itensor = in_data[0].get<xpu, 4, DTyp>(s); | ||
Tensor<xpu, 4, DTyp> otensor = (*out_data)[0].get<xpu, 4, DTyp>(s); | ||
|
||
int outputHeight = otensor.size(2); | ||
int outputWidth = otensor.size(3); | ||
int inputHeight = itensor.size(2); | ||
int inputWidth = itensor.size(3); | ||
|
||
int dW = outputWidth / inputWidth; | ||
int dH = outputHeight / inputHeight; | ||
int idim = itensor.shape_.kDimension; | ||
|
||
// dims | ||
int osz0 = otensor.size(0); | ||
int osz1 = otensor.size(1); | ||
int osz2 = otensor.size(2); | ||
int osz3 = 1; | ||
if (idim > 3) { | ||
osz3 = otensor.size(3); | ||
} | ||
|
||
// perform the upsampling | ||
int i0, i1, i2, i3; | ||
int iout[4]; // Output indices | ||
int iin[4]; // Input indices | ||
|
||
for (i0 = 0; i0 < osz0; i0++) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can this nested for loop be vectorized? |
||
iout[0] = i0; | ||
iin[0] = i0; | ||
for (i1 = 0; i1 < osz1; i1++) { | ||
iout[1] = i1; | ||
iin[1] = i1; | ||
for (i2 = 0; i2 < osz2; i2++) { | ||
iout[2] = i2; | ||
iin[2] = i2; | ||
int in_y = i2 / dH; | ||
for (i3 = 0; i3 < osz3; i3++) { | ||
iout[3] = i3; | ||
iin[3] = i3; | ||
int in_x = i3 / dW; | ||
otensor[i0][i1][i2][i3] = itensor[i0][i1][in_y][in_x]; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
template<typename xpu, typename DType> | ||
void UpSamplingForward(const OpContext &ctx, const UpSamplingParam ¶m, | ||
const std::vector<TBlob> &in_data, | ||
|
@@ -96,26 +149,37 @@ void UpSamplingForward(const OpContext &ctx, const UpSamplingParam ¶m, | |
} | ||
Stream<xpu> *s = ctx.get_stream<xpu>(); | ||
Tensor<xpu, 4, DType> out = out_data[up_enum::kOut].get<xpu, 4, DType>(s); | ||
std::vector<TBlob> outdata = out_data; | ||
if (param.num_args > 1) { | ||
int begin = 0; | ||
for (int i = 0; i < param.num_args; ++i) { | ||
Tensor<xpu, 4, DType> data = in_data[i].get<xpu, 4, DType>(s); | ||
int end = begin + data.size(1); | ||
int scale = out_data[up_enum::kOut].size(2)/in_data[i].size(2); | ||
if (param.multi_input_mode == up_enum::kSum) { | ||
if (i == 0) { | ||
Assign(out, req[up_enum::kOut], upsampling_nearest(data, scale)); | ||
MSHADOW_REAL_TYPE_SWITCH_EX(in_data[0].type_flag_, DTyp, AccReal, { | ||
SpatialUpSamplingNearestUpdateOutput<xpu, DTyp, AccReal>(s, in_data, &outdata); | ||
out = out_data[up_enum::kOut].get<xpu, 4, DType>(s); | ||
}); | ||
} else { | ||
out += upsampling_nearest(data, scale); | ||
MSHADOW_REAL_TYPE_SWITCH_EX(in_data[0].type_flag_, DTyp, AccReal, { | ||
SpatialUpSamplingNearestUpdateOutput<xpu, DTyp, AccReal>(s, in_data, &outdata); | ||
out += out_data[up_enum::kOut].get<xpu, 4, DType>(s); | ||
}); | ||
} | ||
} else { | ||
Assign(slice<1>(out, begin, end), req[up_enum::kOut], upsampling_nearest(data, scale)); | ||
MSHADOW_REAL_TYPE_SWITCH_EX(in_data[0].type_flag_, DTyp, AccReal, { | ||
SpatialUpSamplingNearestUpdateOutput<xpu, DTyp, AccReal>(s, in_data, &outdata); | ||
slice<1>(out, begin, end) = out_data[up_enum::kOut].get<xpu, 4, DType>(s); | ||
}); | ||
} | ||
begin = end; | ||
} | ||
} else { | ||
Tensor<xpu, 4, DType> data = in_data[up_enum::kData].get<xpu, 4, DType>(s); | ||
Assign(out, req[up_enum::kOut], upsampling_nearest(data, param.scale)); | ||
MSHADOW_REAL_TYPE_SWITCH_EX(in_data[0].type_flag_, DTyp, AccReal, { | ||
SpatialUpSamplingNearestUpdateOutput<xpu, DTyp, AccReal>(s, in_data, &outdata); | ||
out = out_data[up_enum::kOut].get<xpu, 4, DType>(s); | ||
}); | ||
} | ||
} | ||
|
||
|
@@ -134,44 +198,71 @@ void UpSamplingBackward(const OpContext &ctx, const UpSamplingParam ¶m, | |
Tensor<xpu, 4, DType> input_grad = in_grad[i].get<xpu, 4, DType>(s); | ||
mshadow::Shape<2> in_shape = Shape2(input_grad.shape_[2], input_grad.shape_[3]); | ||
int end = begin + input_grad.size(1); | ||
int scale = grad.size(2)/in_shape[0]; | ||
int scale_h = grad.size(2)/in_shape[0]; | ||
int scale_w = grad.size(3)/in_shape[1]; | ||
if (param.multi_input_mode == up_enum::kSum) { | ||
Assign(input_grad, req[i], | ||
pool<mshadow::red::sum>(grad, | ||
in_shape, | ||
scale, | ||
scale, | ||
scale, | ||
scale)); | ||
scale_h, | ||
scale_w, | ||
scale_h, | ||
scale_w)); | ||
} else { | ||
Assign(input_grad, req[i], | ||
pool<mshadow::red::sum>(slice<1>(grad, begin, end), | ||
in_shape, | ||
scale, | ||
scale, | ||
scale, | ||
scale)); | ||
scale_h, | ||
scale_w, | ||
scale_h, | ||
scale_w)); | ||
} | ||
begin = end; | ||
} | ||
} else { | ||
Tensor<xpu, 4, DType> input_grad = in_grad[up_enum::kData].get<xpu, 4, DType>(s); | ||
mshadow::Shape<2> in_shape = Shape2(input_grad.shape_[2], input_grad.shape_[3]); | ||
int scale_h = 1; | ||
int scale_w = 1; | ||
if (param.scale.ndim() == 1) { | ||
scale_h = param.scale[0]; | ||
scale_w = param.scale[0]; | ||
} else if (param.scale.ndim() == 2) { | ||
scale_h = param.scale[0]; | ||
scale_w = param.scale[1]; | ||
} else if (param.scale.ndim() == 4) { | ||
scale_h = param.scale[2]; | ||
scale_w = param.scale[3]; | ||
} | ||
Assign(input_grad, req[up_enum::kData], | ||
pool<mshadow::red::sum>(grad, | ||
in_shape, | ||
param.scale, | ||
param.scale, | ||
param.scale, | ||
param.scale)); | ||
scale_h, | ||
scale_w, | ||
scale_h, | ||
scale_w)); | ||
} | ||
} | ||
|
||
static inline DeconvolutionParam GetDeconvolutionParam(const UpSamplingParam& param) { | ||
DeconvolutionParam p = DeconvolutionParam(); | ||
int kernel = 2 * param.scale - param.scale % 2; | ||
int stride = param.scale; | ||
int pad = static_cast<int>(ceil((param.scale - 1) / 2.)); | ||
int scale_h = 1; | ||
int scale_w = 1; | ||
if (param.scale.ndim() == 1) { | ||
scale_h = param.scale[0]; | ||
scale_w = param.scale[0]; | ||
} else if (param.scale.ndim() == 2) { | ||
scale_h = param.scale[0]; | ||
scale_w = param.scale[1]; | ||
} else if (param.scale.ndim() == 4) { | ||
scale_h = param.scale[2]; | ||
scale_w = param.scale[3]; | ||
} | ||
CHECK_EQ(scale_h, scale_w) << | ||
"UpSamplingBilinear: Scale should be the same along all dimensions for bilinear upsampling"; | ||
int kernel = static_cast<int>(2.0 * scale_h - ::fmod(scale_h, 2)); | ||
int stride = scale_h; | ||
int pad = static_cast<int>(ceil((scale_h - 1) / 2.)); | ||
p.workspace = param.workspace; | ||
p.num_group = param.num_filter; | ||
p.num_filter = param.num_filter; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about using index_t as datatype for all of them
Since for large operator support it was found to be useful -#13418
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I'll make this change