1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
5 #include <vpu/pass_manager.hpp>
16 #include <unordered_map>
19 #include <vpu/stub_stage.hpp>
20 #include <vpu/sw/utility.hpp>
21 #include <vpu/compile_env.hpp>
27 using ReplicatedDataMap = std::unordered_map<int, Data>;
29 class UpsamplingStage final : public StageNode {
31 StagePtr cloneImpl() const override {
32 return std::make_shared<UpsamplingStage>(*this);
35 DataMap<float> propagateScaleFactorsImpl(
36 const DataMap<float>&,
37 ScalePropagationStep) override {
38 VPU_THROW_EXCEPTION << "Must never be called";
41 DataMap<DimsOrder> propagateDataOrderImpl() const override {
42 IE_ASSERT(_inputEdges.size() == 1);
43 IE_ASSERT(_outputEdges.size() == 1);
45 auto input = _inputEdges[0]->input();
46 auto output = _outputEdges[0]->output();
48 DataMap<DimsOrder> out;
50 out[input] = DimsOrder::NCHW;
51 out[output] = DimsOrder::NCHW;
56 DataMap<StridesRequirement> getDataStridesRequirementsImpl() const override {
57 IE_ASSERT(_inputEdges.size() == 1);
58 IE_ASSERT(_outputEdges.size() == 1);
60 auto output = _outputEdges[0]->output();
62 DataMap<StridesRequirement> out;
64 out[output] = StridesRequirement().add(1, DimStride::Aligned);
69 void finalizeDataLayoutImpl() override {
72 DataMap<BatchSupport> getBatchSupportInfoImpl() const override {
73 IE_ASSERT(_inputEdges.size() == 1);
74 IE_ASSERT(_outputEdges.size() == 1);
76 auto input = _inputEdges[0]->input();
77 auto output = _outputEdges[0]->output();
79 DataMap<BatchSupport> out;
81 out[input] = BatchSupport::Split;
82 out[output] = BatchSupport::Split;
87 StageSHAVEsRequirements getSHAVEsRequirementsImpl() const override {
88 return StageSHAVEsRequirements::TwoOrOne;
91 void finalCheckImpl() const override {
94 void serializeParamsImpl(BlobSerializer& serializer) const override {
95 auto scaleX = attrs().get<int>("upsampling_factorx_x");
96 auto scaleY = attrs().get<int>("upsampling_factorx_y");
97 auto scaleZ = attrs().get<int>("upsampling_factorx_z");
98 auto pad_l_x = attrs().get<int>("pad_l_x");
99 auto pad_r_x = attrs().get<int>("pad_r_x");
100 auto pad_l_y = attrs().get<int>("pad_l_y");
101 auto pad_r_y = attrs().get<int>("pad_r_y");
102 auto pad_l_z = attrs().get<int>("pad_l_z");
103 auto pad_r_z = attrs().get<int>("pad_r_z");
105 serializer.append(static_cast<int32_t>(scaleX));
106 serializer.append(static_cast<int32_t>(scaleY));
107 serializer.append(static_cast<int32_t>(scaleZ));
108 serializer.append(static_cast<int32_t>(pad_l_x));
109 serializer.append(static_cast<int32_t>(pad_r_x));
110 serializer.append(static_cast<int32_t>(pad_l_y));
111 serializer.append(static_cast<int32_t>(pad_r_y));
112 serializer.append(static_cast<int32_t>(pad_l_z));
113 serializer.append(static_cast<int32_t>(pad_r_z));
116 void serializeDataImpl(BlobSerializer& serializer) const override {
117 IE_ASSERT(_inputEdges.size() == 1);
118 IE_ASSERT(_outputEdges.size() == 1);
119 IE_ASSERT(_tempBufferEdges.empty());
121 auto input = _inputEdges[0]->input();
122 auto output = _outputEdges[0]->output();
124 input->serializeNewBuffer(serializer);
125 output->serializeNewBuffer(serializer);
130 class DeconvolutionToConvolutionContent final : public CalculatedDataContent {
132 DeconvolutionToConvolutionContent(
133 const DataContent::Ptr& origContent,
134 int kernelSizeX, int kernelSizeY) :
135 CalculatedDataContent({origContent}),
136 _kerneSizeX(kernelSizeX), _kernelSizeY(kernelSizeY) {
139 void fillTempBuf(const SmallVector<DataContent::Ptr, 2>& baseContents, void* tempBuf) const {
140 VPU_PROFILE(DeconvolutionToConvolutionContent);
142 IE_ASSERT(baseContents.size() == 1);
143 IE_ASSERT(_desc.type() == DataType::FP16);
145 deconv_to_conv(baseContents[0]->get<fp16_t>(), static_cast<fp16_t*>(tempBuf), _desc);
154 class PassImpl final : public Pass {
156 explicit PassImpl(const StageBuilder::Ptr& stageBuilder) : _stageBuilder(stageBuilder) {}
158 void run(const Model::Ptr& model) override;
161 StageBuilder::Ptr _stageBuilder;
164 void PassImpl::run(const Model::Ptr& model) {
165 VPU_PROFILE(replaceDeconvByConv);
167 auto stages = model->getStages();
168 for (const auto& stage : stages) {
169 if (stage->type() != StageType::StubDeconv) {
173 auto kernelSizeX = stage->attrs().get<int>("kernelSizeX");
174 auto kernelSizeY = stage->attrs().get<int>("kernelSizeY");
175 auto kernelStrideX = stage->attrs().get<int>("kernelStrideX");
176 auto kernelStrideY = stage->attrs().get<int>("kernelStrideY");
177 auto groupSize = stage->attrs().get<int>("groupSize");
179 auto padLeft = stage->attrs().get<int>("padLeft");
180 auto padRight = stage->attrs().get<int>("padRight");
181 auto padTop = stage->attrs().get<int>("padTop");
182 auto padBottom = stage->attrs().get<int>("padBottom");
183 auto deconvScale = stage->attrs().getOrDefault<float>("scaleFactor", 1.0);
185 /* Upsampling layer does not support negative paddings */
186 if ((kernelSizeX - 1 - padLeft < 0) || (kernelSizeX - 1 - padRight < 0) ||
187 (kernelSizeY - 1 - padTop < 0) || (kernelSizeY - 1 - padBottom < 0)) {
191 if (groupSize != 1) {
195 if ((padTop != padBottom) || (padLeft != padRight)) {
199 if (kernelSizeX > 15 || kernelSizeY > 15) {
203 auto input = stage->input(0);
204 auto weights = stage->input(1);
205 auto biases = stage->input(2);
206 auto output = stage->output(0);
207 const auto& env = CompileEnv::get();
209 if (env.netConfig.hwDisabled(stage->origLayer()->name)) {
213 if (output->desc().numDims() < 4) {
217 // problem with Deconv/CommonSingleLayerTest
218 auto origOutputX = kernelStrideX * (input->desc().dim(Dim::W) - 1) + kernelSizeX - padLeft - padRight;
219 auto origOutputY = kernelStrideY * (input->desc().dim(Dim::H) - 1) + kernelSizeY - padTop - padBottom;
221 if ((origOutputX != output->desc().dim(Dim::W)) || (origOutputY != output->desc().dim(Dim::H))) {
225 model->disconnectStageDatas(stage);
227 DataDesc newDesc({1, 1, output->desc().dim(Dim::C), output->desc().dim(Dim::N)});
228 newDesc.setDim(Dim::N, 1);
229 newDesc.setDim(Dim::C, input->desc().dim(Dim::C));
230 newDesc.setDim(Dim::H, (input->desc().dim(Dim::H) - 1) * kernelStrideY + 1 + (kernelSizeY - 1) * 2 - padTop - padBottom);
231 newDesc.setDim(Dim::W, (input->desc().dim(Dim::W) - 1) * kernelStrideX + 1 + (kernelSizeX - 1) * 2 - padLeft - padRight);
233 auto newOutput = model->duplicateData(output, "@upsampleData", newDesc);
234 auto newWeights = model->duplicateData(weights, "@upsampleData", weights->desc(),
235 std::make_shared<DeconvolutionToConvolutionContent>(weights->content(), kernelSizeX, kernelSizeY));
237 auto upsampleStage = model->addNewStage<UpsamplingStage>(
238 stage->origLayerName() + "@Upsample",
239 StageType::Upsampling,
244 upsampleStage->attrs().set<int>("upsampling_factorx_x", kernelStrideX);
245 upsampleStage->attrs().set<int>("upsampling_factorx_y", kernelStrideY);
246 upsampleStage->attrs().set<int>("upsampling_factorx_z", 1);
247 upsampleStage->attrs().set<int>("pad_l_x", (kernelSizeX - 1) - padLeft);
248 upsampleStage->attrs().set<int>("pad_r_x", (kernelSizeX - 1) - padRight);
249 upsampleStage->attrs().set<int>("pad_l_y", (kernelSizeY - 1) - padTop);
250 upsampleStage->attrs().set<int>("pad_r_y", (kernelSizeY - 1) - padBottom);
251 upsampleStage->attrs().set<int>("pad_l_z", 0);
252 upsampleStage->attrs().set<int>("pad_r_z", 0);
254 auto newStage = model->addNewStage<StubStage>(
255 stage->origLayerName() + "@UpsampleConv",
258 {newOutput, newWeights, biases},
261 newStage->attrs().set<int>("kernelSizeX", kernelSizeX);
262 newStage->attrs().set<int>("kernelSizeY", kernelSizeY);
263 newStage->attrs().set<int>("kernelStrideX", 1);
264 newStage->attrs().set<int>("kernelStrideY", 1);
265 newStage->attrs().set<int>("padLeft", 0);
266 newStage->attrs().set<int>("padRight", 0);
267 newStage->attrs().set<int>("padTop", 0);
268 newStage->attrs().set<int>("padBottom", 0);
269 newStage->attrs().set<int>("dilationX", 1);
270 newStage->attrs().set<int>("dilationY", 1);
271 newStage->attrs().set<int>("groupSize", 1);
272 newStage->attrs().set<bool>("tryHW", true);
273 newStage->attrs().set<float>("scaleFactor", deconvScale);
275 model->removeStage(stage);
281 Pass::Ptr PassManager::replaceDeconvByConv() {
282 return std::make_shared<PassImpl>(_stageBuilder);