1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
5 #include <vpu/frontend/frontend.hpp>
9 #include <unordered_set>
15 #include <vpu/utils/numeric.hpp>
21 class EltwiseStage final : public StageNode {
23 StagePtr cloneImpl() const override {
24 return std::make_shared<EltwiseStage>(*this);
27 DataMap<float> propagateScaleFactorsImpl(
28 const DataMap<float>& inputScales,
29 ScalePropagationStep step) override {
30 IE_ASSERT(_inputEdges.size() == 2);
31 IE_ASSERT(_outputEdges.size() == 1);
33 auto output = _outputEdges[0]->output();
37 if (_type != StageType::Prod &&
38 step == ScalePropagationStep::Propagate) {
39 // Keep the largest input scale factor.
40 auto maxScale = std::numeric_limits<float>::lowest();
41 for (const auto& inEdge : _inputEdges) {
42 maxScale = std::max(maxScale, inputScales.at(inEdge->input()));
45 for (const auto& inEdge : _inputEdges) {
46 auto curScale = inputScales.at(inEdge->input());
48 if (!isFloatEqual(curScale, maxScale)) {
49 out[inEdge->input()] = maxScale / curScale;
53 out[output] = maxScale;
55 // Eltwise can only propagate scaling for Sum and Max cases.
56 for (const auto& inEdge : _inputEdges) {
57 out[inEdge->input()] = 1.0f;
66 DataMap<DimsOrder> propagateDataOrderImpl() const override {
67 IE_ASSERT(_inputEdges.size() == 2);
68 IE_ASSERT(_outputEdges.size() == 1);
70 auto input0 = _inputEdges[0]->input();
71 auto input1 = _inputEdges[1]->input();
72 auto output = _outputEdges[0]->output();
74 auto in0Desc = input0->desc();
75 auto in1Desc = input1->desc();
76 auto outDesc = output->desc();
78 auto finalOrder = in0Desc.numDims() >= in1Desc.numDims() ? in0Desc.dimsOrder() : in1Desc.dimsOrder();
79 auto secondOrder = in0Desc.numDims() >= in1Desc.numDims() ? in1Desc.dimsOrder() : in0Desc.dimsOrder();
80 if (secondOrder.numDims() >= 3) {
81 if (secondOrder.dimInd(Dim::C) == 1 /*HCW*/) {
82 finalOrder = secondOrder;
83 } else if (secondOrder.dimInd(Dim::C) == 2 /*CHW*/ && finalOrder.dimInd(Dim::C) != 1 /*HCW*/) {
84 finalOrder = secondOrder;
87 if (outDesc.numDims() > finalOrder.numDims())
88 finalOrder = outDesc.dimsOrder();
90 DataMap<DimsOrder> out;
92 out[input0] = finalOrder.numDims() == in0Desc.numDims() ? finalOrder : in0Desc.dimsOrder();
93 out[input1] = finalOrder.numDims() == in1Desc.numDims() ? finalOrder : in1Desc.dimsOrder();
94 out[output] = finalOrder;
99 DataMap<StridesRequirement> getDataStridesRequirementsImpl() const override {
100 return DataMap<StridesRequirement>();
103 void finalizeDataLayoutImpl() override {
106 DataMap<BatchSupport> getBatchSupportInfoImpl() const override {
107 return DataMap<BatchSupport>();
110 StageSHAVEsRequirements getSHAVEsRequirementsImpl() const override {
111 return StageSHAVEsRequirements::CanBeLimited;
114 void finalCheckImpl() const override {
117 void serializeParamsImpl(BlobSerializer& serializer) const override {
118 auto coeff1 = attrs().getOrDefault<float>("coeff1", 1.0f);
119 auto coeff2 = attrs().getOrDefault<float>("coeff2", 1.0f);
121 serializer.append(static_cast<float>(coeff1));
122 serializer.append(static_cast<float>(coeff2));
125 void serializeDataImpl(BlobSerializer& serializer) const override {
126 IE_ASSERT(_inputEdges.size() == 2);
127 IE_ASSERT(_outputEdges.size() == 1);
128 IE_ASSERT(_tempBufferEdges.empty());
130 auto input0 = _inputEdges[0]->input();
131 auto input1 = _inputEdges[1]->input();
132 auto output = _outputEdges[0]->output();
134 input0->serializeNewBuffer(serializer, output->desc().dimsOrder());
135 output->serializeNewBuffer(serializer);
136 input1->serializeNewBuffer(serializer, output->desc().dimsOrder());
142 void FrontEnd::parseEltwise(
143 const Model::Ptr& model,
144 const ie::CNNLayerPtr& _layer,
145 const DataVector& inputs,
146 const DataVector& outputs) {
147 IE_ASSERT(inputs.size() >= 2);
148 IE_ASSERT(outputs.size() == 1);
150 auto layer = std::dynamic_pointer_cast<ie::EltwiseLayer>(_layer);
151 IE_ASSERT(layer != nullptr);
153 auto stageType = StageType::None;
154 auto subCoefficient = 1.0f;
155 switch (layer->_operation) {
156 case ie::EltwiseLayer::eOperation::Sum:
157 stageType = StageType::Sum;
159 case ie::EltwiseLayer::eOperation::Prod:
160 stageType = StageType::Prod;
162 case ie::EltwiseLayer::eOperation::Max:
163 stageType = StageType::Max;
165 case ie::EltwiseLayer::eOperation::Sub:
166 if (inputs.size() > 2) {
167 VPU_THROW_EXCEPTION << "Eltwise operation: " << layer->_operation << " with multiple inputs is not supported";
169 stageType = StageType::Sum;
170 subCoefficient = -1.f;
173 VPU_THROW_EXCEPTION << "Eltwise operation" << layer->_operation << " is not supported";
176 if (stageType != StageType::Sum && !layer->coeff.empty()) {
177 VPU_THROW_EXCEPTION << layer->name << " coefficients only supported for Sum/Sub operations.";
180 auto output = outputs[0];
182 auto tempOutput = output;
183 if (inputs.size() > 2) {
184 tempOutput = model->duplicateData(
186 formatString("@temp@1/%d", inputs.size() - 2));
189 DataVector tempInputs(2);
190 tempInputs[0] = inputs[0];
191 tempInputs[1] = inputs[1];
193 auto stage = model->addNewStage<EltwiseStage>(
200 if (layer->coeff.size() > 0) {
201 stage->attrs().set<float>("coeff1", layer->coeff[0]);
203 if (layer->coeff.size() > 1 || subCoefficient != 1.0f) {
204 stage->attrs().set<float>("coeff2", subCoefficient * (layer->coeff.size() > 1 ? layer->coeff[1] : 1.0f));
207 tempInputs[0] = tempOutput;
208 for (int ind = 2; ind < inputs.size(); ++ind) {
209 tempInputs[1] = inputs[ind];
211 if (ind + 1 == inputs.size()) {
214 tempOutput = model->duplicateData(
216 formatString("@temp@%d/%d", ind, inputs.size() - 2));
219 stage = model->addNewStage<EltwiseStage>(
220 layer->name + "@" + std::to_string(ind - 1),
226 if (layer->coeff.size() > ind) {
227 stage->attrs().set<float>("coeff2", layer->coeff[ind]);
230 tempInputs[0] = tempOutput;
234 Stage StageBuilder::addSumStage(
235 const Model::Ptr& model,
236 const std::string& name,
237 const ie::CNNLayerPtr& layer,
240 const Data& output) {
241 return model->addNewStage<EltwiseStage>(