Skip to content
This repository was archived by the owner on Nov 17, 2023. It is now read-only.

Commit bd6405b

Browse files
authored
Add quantized batch norm operator fused with ReLU (#21137)
* Delete fuse_norm_relu flag * Refactor BN operator * Add quantized bn relu * Fix error * Small fix * Fix issues after rebase * Change output size
1 parent f803641 commit bd6405b

5 files changed

Lines changed: 172 additions & 3 deletions

File tree

python/mxnet/amp/lists/symbol_bf16.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@
209209
'_contrib_quantize_asym',
210210
'_contrib_quantized_act',
211211
'_contrib_quantized_batch_norm',
212+
'_contrib_quantized_batch_norm_relu',
212213
'_contrib_quantized_concat',
213214
'_contrib_quantized_conv',
214215
'_contrib_quantized_elemwise_add',

python/mxnet/amp/lists/symbol_fp16.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
'_contrib_intgemm_prepare_weight',
5353
'_contrib_intgemm_take_weight',
5454
'_contrib_quantized_batch_norm',
55+
'_contrib_quantized_batch_norm_relu',
5556
'_contrib_quantized_elemwise_mul',
5657
'_contrib_quantized_embedding',
5758
'_contrib_mrcnn_mask_target',

src/operator/quantization/dnnl/dnnl_quantized_batch_norm.cc

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
/*!
2121
* \file dnnl_quantized_batch_norm.cc
22-
* \brief
2322
* \author Yixin Bao
2423
*/
2524

@@ -30,6 +29,7 @@
3029
namespace mxnet {
3130
namespace op {
3231

32+
template <bool fuse_relu>
3333
static void DNNLQuantizedBatchNormForward(const nnvm::NodeAttrs& attrs,
3434
const OpContext& ctx,
3535
const std::vector<NDArray>& in_data,
@@ -83,7 +83,7 @@ static void DNNLQuantizedBatchNormForward(const nnvm::NodeAttrs& attrs,
8383

8484
dnnl::normalization_flags flags =
8585
dnnl::normalization_flags::use_global_stats | dnnl::normalization_flags::use_scale_shift;
86-
auto& fwd = DNNLBNForward::GetCached(param, ctx, data_mem, false, flags);
86+
auto& fwd = DNNLBNForward::GetCached(param, ctx, data_mem, fuse_relu, flags);
8787
const dnnl::memory& weight_mem = fwd.GetWeight();
8888
CHECK_EQ(weight_mem.get_desc().get_size(), channel_count * sizeof(float) * 2);
8989
float* weight_buf = reinterpret_cast<float*>(weight_mem.get_data_handle());
@@ -132,6 +132,14 @@ inline static bool QuantizedBatchNormStorageType(const nnvm::NodeAttrs& attrs,
132132
DispatchMode* dispatch_mode,
133133
std::vector<int>* in_attrs,
134134
std::vector<int>* out_attrs) {
135+
return DNNLStorageType(attrs, dev_mask, true, dispatch_mode, in_attrs, out_attrs);
136+
}
137+
138+
inline static bool QuantizedBatchNormWithReLUStorageType(const nnvm::NodeAttrs& attrs,
139+
const int dev_mask,
140+
DispatchMode* dispatch_mode,
141+
std::vector<int>* in_attrs,
142+
std::vector<int>* out_attrs) {
135143
bool dispatched = false;
136144
if (!dispatched) {
137145
dispatched = DNNLStorageType(attrs, dev_mask, true, dispatch_mode, in_attrs, out_attrs);
@@ -141,7 +149,16 @@ inline static bool QuantizedBatchNormStorageType(const nnvm::NodeAttrs& attrs,
141149

142150
NNVM_REGISTER_OP(_contrib_quantized_batch_norm)
143151
.set_attr<FInferStorageType>("FInferStorageType", QuantizedBatchNormStorageType)
144-
.set_attr<FComputeEx>("FComputeEx<cpu>", DNNLQuantizedBatchNormForward)
152+
.set_attr<FComputeEx>("FComputeEx<cpu>", DNNLQuantizedBatchNormForward</*fuse_relu*/ false>)
153+
.set_attr<FResourceRequest>("FResourceRequest",
154+
[](const NodeAttrs& n) {
155+
return std::vector<ResourceRequest>{ResourceRequest::kTempSpace};
156+
})
157+
.set_attr<bool>("TIsDNNL", true);
158+
159+
NNVM_REGISTER_OP(_contrib_quantized_batch_norm_relu)
160+
.set_attr<FInferStorageType>("FInferStorageType", QuantizedBatchNormWithReLUStorageType)
161+
.set_attr<FComputeEx>("FComputeEx<cpu>", DNNLQuantizedBatchNormForward</*fuse_relu*/ true>)
145162
.set_attr<FResourceRequest>("FResourceRequest",
146163
[](const NodeAttrs& n) {
147164
return std::vector<ResourceRequest>{ResourceRequest::kTempSpace};
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
/*!
21+
* \file quantized_batch_norm_relu.cc
22+
* \author Hanna Jarlaczyńska, hanna.jarlaczynska@intel.com
23+
*/
24+
#include <mxnet/op_attr_types.h>
25+
#include "operator/nn/batch_norm-inl.h"
26+
#if MXNET_USE_ONEDNN == 1
27+
#include "operator/nn/dnnl/dnnl_batch_norm-inl.h"
28+
#endif
29+
30+
namespace mxnet {
31+
namespace op {
32+
33+
bool QuantizedBatchNormWithReLUShape(const nnvm::NodeAttrs& attrs,
34+
mxnet::ShapeVector* in_shape,
35+
mxnet::ShapeVector* out_shape) {
36+
const BatchNormParam& param = nnvm::get<BatchNormParam>(attrs.parsed);
37+
using namespace mshadow;
38+
CHECK_EQ(in_shape->size(), 7U)
39+
<< "Input:[data, gamma, beta, moving_mean, moving_var, min_data, max_data]";
40+
CHECK_EQ(out_shape->size(), 3U);
41+
42+
const mxnet::TShape& dshape = in_shape->at(batchnorm::kData);
43+
if (!mxnet::ndim_is_known(dshape)) {
44+
return false;
45+
}
46+
const int channelAxis = batchnorm::GetRealAxis(dshape, param.axis);
47+
CHECK(channelAxis >= 0 && channelAxis < dshape.ndim())
48+
<< "Channel axis out of range: " << param.axis;
49+
const int channelCount = dshape[channelAxis];
50+
51+
SHAPE_ASSIGN_CHECK(*in_shape, 1, mxnet::TShape(Shape1(channelCount))) // gamma,beta
52+
SHAPE_ASSIGN_CHECK(*in_shape, 2, mxnet::TShape(Shape1(channelCount)))
53+
SHAPE_ASSIGN_CHECK(*in_shape, 3, mxnet::TShape(Shape1(channelCount))); // moving_mean, moving_var
54+
SHAPE_ASSIGN_CHECK(*in_shape, 4, mxnet::TShape(Shape1(channelCount)))
55+
SHAPE_ASSIGN_CHECK(*in_shape, 5, mxnet::TShape(1, 1)); // min_data, max_data
56+
SHAPE_ASSIGN_CHECK(*in_shape, 6, mxnet::TShape(1, 1));
57+
58+
SHAPE_ASSIGN_CHECK(*out_shape, 0, dshape);
59+
SHAPE_ASSIGN_CHECK(*out_shape, 1, mxnet::TShape(1, 1)); // min_output, max_output
60+
SHAPE_ASSIGN_CHECK(*out_shape, 2, mxnet::TShape(1, 1));
61+
return true;
62+
}
63+
64+
bool QuantizedBatchNormWithReLUType(const nnvm::NodeAttrs& attrs,
65+
std::vector<int>* in_type,
66+
std::vector<int>* out_type) {
67+
using namespace mshadow;
68+
CHECK_EQ(in_type->size(), 7U);
69+
CHECK_EQ(out_type->size(), 3U);
70+
71+
#if MXNET_USE_ONEDNN == 1
72+
CHECK(in_type->at(0) == mshadow::kInt8 || in_type->at(0) == mshadow::kUint8)
73+
<< "QuantizedBatchNorm with oneDNN backend only supports int8/uint8 input, while "
74+
<< in_type->at(0) << " is given.";
75+
#else
76+
TYPE_ASSIGN_CHECK(*in_type, 0, mshadow::kInt8);
77+
#endif
78+
for (size_t i = 1; i < 7; ++i) {
79+
TYPE_ASSIGN_CHECK(*in_type, i, mshadow::kFloat32);
80+
}
81+
82+
TYPE_ASSIGN_CHECK(*out_type, 0, mshadow::kInt8);
83+
TYPE_ASSIGN_CHECK(*out_type, 1, mshadow::kFloat32);
84+
TYPE_ASSIGN_CHECK(*out_type, 2, mshadow::kFloat32);
85+
86+
return true;
87+
}
88+
89+
NNVM_REGISTER_OP(_contrib_quantized_batch_norm_relu)
90+
.describe(R"code(BatchNorm with ReLU operator for input and output data type of int8.
91+
The input and output data comes with min and max thresholds for quantizing
92+
the float32 data into int8.
93+
94+
.. Note::
95+
This operator only supports forward propogation. DO NOT use it in training.
96+
)code" ADD_FILELINE)
97+
.set_num_inputs(7)
98+
.set_num_outputs(3)
99+
.set_attr_parser(ParamParser<BatchNormParam>)
100+
.set_attr<nnvm::FListInputNames>(
101+
"FListInputNames",
102+
[](const NodeAttrs& attrs) {
103+
return std::vector<std::string>{
104+
"data", "gamma", "beta", "moving_mean", "moving_var", "min_data", "max_data"};
105+
})
106+
.set_attr<nnvm::FListOutputNames>(
107+
"FListOutputNames",
108+
[](const NodeAttrs& attrs) {
109+
return std::vector<std::string>{"output", "min_output", "max_output"};
110+
})
111+
.set_attr<nnvm::FMutateInputs>("FMutateInputs",
112+
[](const nnvm::NodeAttrs& attrs) {
113+
return std::vector<uint32_t>{3, 4};
114+
})
115+
.set_attr<mxnet::FInferShape>("FInferShape", QuantizedBatchNormWithReLUShape)
116+
.set_attr<nnvm::FInferType>("FInferType", QuantizedBatchNormWithReLUType)
117+
.set_attr<FNeedRequantize>("FNeedRequantize", [](const NodeAttrs& attrs) { return false; })
118+
.set_attr<FNeedCalibrateInput>("FNeedCalibrateOutput",
119+
[](const NodeAttrs& attrs) { return std::vector<int>{0}; })
120+
.add_argument("data", "NDArray-or-Symbol", "Input data.")
121+
.add_argument("gamma", "NDArray-or-Symbol", "gamma.")
122+
.add_argument("beta", "NDArray-or-Symbol", "beta.")
123+
.add_argument("moving_mean", "NDArray-or-Symbol", "moving_mean.")
124+
.add_argument("moving_var", "NDArray-or-Symbol", "moving_var.")
125+
.add_argument("min_data", "NDArray-or-Symbol", "Minimum value of data.")
126+
.add_argument("max_data", "NDArray-or-Symbol", "Maximum value of data.")
127+
.add_arguments(BatchNormParam::__FIELDS__());
128+
129+
NNVM_REGISTER_OP(_sg_onednn_batch_norm)
130+
.set_attr<FQuantizedOp>("FQuantizedOp",
131+
[](const NodeAttrs& attrs) {
132+
nnvm::ObjectPtr node = nnvm::Node::Create();
133+
node->attrs.op = Op::Get("_contrib_quantized_batch_norm_relu");
134+
node->attrs.name = "quantized_" + attrs.name;
135+
node->attrs.dict = attrs.dict;
136+
if (node->op()->attr_parser != nullptr) {
137+
node->op()->attr_parser(&(node->attrs));
138+
}
139+
return node;
140+
})
141+
.set_attr<FAvoidQuantizeInput>("FAvoidQuantizeInput",
142+
[](const NodeAttrs& attrs,
143+
const size_t index,
144+
const std::string quantize_granularity) {
145+
return (index != 0);
146+
});
147+
148+
} // namespace op
149+
} // namespace mxnet

src/operator/subgraph/dnnl/dnnl_subgraph_property.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ MXNET_REGISTER_SUBGRAPH_PROPERTY(ONEDNN_QUANTIZE, SgDNNLIdentityProperty);
5858
MXNET_REGISTER_SUBGRAPH_PROPERTY(ONEDNN_QUANTIZE, SgDNNLConvProperty).set_attr("quantize", true);
5959
MXNET_REGISTER_SUBGRAPH_PROPERTY(ONEDNN_QUANTIZE, SgDNNLFCProperty).set_attr("quantize", true);
6060
MXNET_REGISTER_SUBGRAPH_PROPERTY(ONEDNN_QUANTIZE, SgDNNLTransformerQKSplitProperty);
61+
MXNET_REGISTER_SUBGRAPH_PROPERTY(ONEDNN_QUANTIZE, SgDNNLBNReLUProperty);
6162
MXNET_REGISTER_SUBGRAPH_PROPERTY(ONEDNN_QUANTIZE, SgDNNLTransformerQKProperty);
6263
MXNET_REGISTER_SUBGRAPH_PROPERTY(ONEDNN_QUANTIZE, SgDNNLTransformerValAttProperty);
6364
MXNET_REGISTER_SUBGRAPH_PROPERTY(ONEDNN_QUANTIZE, SgDNNLBatchDotProperty)

0 commit comments

Comments
 (0)