Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Xiaomi
Mace
提交
6c65796f
Mace
项目概览
Xiaomi
/
Mace
通知
106
Star
40
Fork
27
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
Mace
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
6c65796f
编写于
9月 18, 2018
作者:
李
李寅
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Support quantize-weights only
上级
ec2a70ce
变更
12
隐藏空白更改
内联
并排
Showing
12 changed file
with
224 addition
and
171 deletion
+224
-171
mace/core/tensor.h
mace/core/tensor.h
+2
-1
mace/core/workspace.cc
mace/core/workspace.cc
+30
-5
mace/kernels/gemmlowp_util.h
mace/kernels/gemmlowp_util.h
+4
-4
mace/kernels/quantize.h
mace/kernels/quantize.h
+1
-144
mace/ops/conv_2d_test.cc
mace/ops/conv_2d_test.cc
+1
-1
mace/ops/depthwise_conv2d_test.cc
mace/ops/depthwise_conv2d_test.cc
+1
-1
mace/ops/fully_connected_test.cc
mace/ops/fully_connected_test.cc
+1
-1
mace/proto/mace.proto
mace/proto/mace.proto
+1
-0
mace/python/tools/converter_tool/transformer.py
mace/python/tools/converter_tool/transformer.py
+1
-3
mace/python/tools/tensor_source.jinja2
mace/python/tools/tensor_source.jinja2
+1
-0
mace/utils/BUILD
mace/utils/BUILD
+12
-11
mace/utils/quantize.h
mace/utils/quantize.h
+169
-0
未找到文件。
mace/core/tensor.h
浏览文件 @
6c65796f
...
...
@@ -142,7 +142,8 @@ class Tensor {
buffer_
=
&
buffer_slice_
;
}
Tensor
()
:
Tensor
(
GetCPUAllocator
(),
DT_FLOAT
)
{}
explicit
Tensor
(
bool
is_weight
=
false
)
:
Tensor
(
GetCPUAllocator
(),
DT_FLOAT
,
is_weight
)
{}
~
Tensor
()
{
if
(
is_buffer_owner_
&&
buffer_
!=
nullptr
)
{
...
...
mace/core/workspace.cc
浏览文件 @
6c65796f
...
...
@@ -14,13 +14,12 @@
#include "mace/core/workspace.h"
#include <memory>
#include <string>
#include <vector>
#include <unordered_set>
#include <utility>
#include "mace/core/arg_helper.h"
#include "mace/utils/quantize.h"
#ifdef MACE_ENABLE_OPENCL
#include "mace/core/runtime/opencl/opencl_runtime.h"
#endif
...
...
@@ -34,6 +33,15 @@ bool ShouldPreallocateMemoryForOp(const OperatorDef &op) {
};
return
reuse_buffer_ops
.
find
(
op
.
type
())
==
reuse_buffer_ops
.
end
();
}
bool
HasQuantizeOp
(
const
NetDef
&
net_def
)
{
for
(
auto
&
op
:
net_def
.
op
())
{
if
(
op
.
type
()
==
"Quantize"
)
{
return
true
;
}
}
return
false
;
}
}
// namespace
Workspace
::
Workspace
()
:
...
...
@@ -146,6 +154,7 @@ MaceStatus Workspace::LoadModelTensor(const NetDef &net_def,
0
,
model_data_size
);
tensor_buffer_
->
UnMap
();
}
bool
has_quantize_op
=
HasQuantizeOp
(
net_def
);
for
(
auto
&
const_tensor
:
net_def
.
tensors
())
{
MACE_LATENCY_LOGGER
(
2
,
"Load tensor "
,
const_tensor
.
name
());
VLOG
(
3
)
<<
"Tensor name: "
<<
const_tensor
.
name
()
...
...
@@ -163,11 +172,27 @@ MaceStatus Workspace::LoadModelTensor(const NetDef &net_def,
const_tensor
.
data_size
()
*
GetEnumTypeSize
(
const_tensor
.
data_type
())),
const_tensor
.
data_type
(),
true
));
tensor
->
Reshape
(
dims
);
tensor
->
SetScale
(
const_tensor
.
scale
());
tensor
->
SetZeroPoint
(
const_tensor
.
zero_point
());
tensor_map_
[
const_tensor
.
name
()]
=
std
::
move
(
tensor
);
// Only weights are quantized
if
(
const_tensor
.
quantized
()
&&
!
has_quantize_op
)
{
std
::
unique_ptr
<
Tensor
>
dequantized_tensor
(
new
Tensor
(
true
));
dequantized_tensor
->
Resize
(
dims
);
Tensor
::
MappingGuard
quantize_guard
(
tensor
.
get
());
Tensor
::
MappingGuard
dequantize_guard
(
dequantized_tensor
.
get
());
auto
quantized_data
=
tensor
->
data
<
uint8_t
>
();
auto
dequantized_data
=
dequantized_tensor
->
mutable_data
<
float
>
();
Dequantize
(
quantized_data
,
tensor
->
size
(),
tensor
->
scale
(),
tensor
->
zero_point
(),
dequantized_data
);
tensor_map_
[
const_tensor
.
name
()]
=
std
::
move
(
dequantized_tensor
);
}
else
{
tensor_map_
[
const_tensor
.
name
()]
=
std
::
move
(
tensor
);
}
}
fused_buffer_
=
true
;
}
...
...
mace/kernels/gemmlowp_util.h
浏览文件 @
6c65796f
...
...
@@ -44,8 +44,8 @@ struct GemmlowpOutputPipeline {
bias_addition_stage
.
bias_vector
=
bias_vector
;
int32_t
quantized_multiplier
;
int32_t
right_shift
;
kernels
::
GetOutputMultiplierAndShift
(
lhs_scale
,
rhs_scale
,
output_scale
,
&
quantized_multiplier
,
&
right_shift
);
GetOutputMultiplierAndShift
(
lhs_scale
,
rhs_scale
,
output_scale
,
&
quantized_multiplier
,
&
right_shift
);
gemmlowp
::
OutputStageQuantizeDownInt32ToUint8ScaleByFixedPoint
quantize_down_stage
;
quantize_down_stage
.
result_offset_after_shift
=
output_zero_point
;
...
...
@@ -62,8 +62,8 @@ struct GemmlowpOutputPipeline {
const
int32_t
output_zero_point
)
{
int32_t
quantized_multiplier
;
int32_t
right_shift
;
kernels
::
GetOutputMultiplierAndShift
(
lhs_scale
,
rhs_scale
,
output_scale
,
&
quantized_multiplier
,
&
right_shift
);
GetOutputMultiplierAndShift
(
lhs_scale
,
rhs_scale
,
output_scale
,
&
quantized_multiplier
,
&
right_shift
);
gemmlowp
::
OutputStageQuantizeDownInt32ToUint8ScaleByFixedPoint
quantize_down_stage
;
quantize_down_stage
.
result_offset_after_shift
=
output_zero_point
;
...
...
mace/kernels/quantize.h
浏览文件 @
6c65796f
...
...
@@ -23,154 +23,11 @@
#include "mace/core/future.h"
#include "mace/core/tensor.h"
#include "mace/kernels/kernel.h"
#include "mace/utils/quantize.h"
namespace
mace
{
namespace
kernels
{
template
<
typename
T
>
inline
void
AdjustRange
(
const
float
in_min_data
,
const
float
in_max_data
,
const
bool
non_zero
,
float
*
scale
,
int32_t
*
zero_point
)
{
// re-range to make range include zero float and
// make zero float as integer u8
const
T
quantized_min
=
std
::
numeric_limits
<
T
>::
lowest
();
const
T
quantized_max
=
std
::
numeric_limits
<
T
>::
max
();
if
(
quantized_min
<
0
)
{
MACE_ASSERT
(
!
non_zero
,
"Cannot nudge to non_zero quantize value."
);
}
float
out_max
=
std
::
max
(
0.
f
,
in_max_data
);
float
out_min
=
std
::
min
(
0.
f
,
in_min_data
);
// make in_min_data quantize as greater than 1
if
(
non_zero
)
{
out_min
=
std
::
min
(
out_min
,
in_min_data
-
(
out_max
-
in_min_data
)
/
(
quantized_max
-
quantized_min
-
1
));
}
*
scale
=
(
out_max
-
out_min
)
/
(
quantized_max
-
quantized_min
);
const
float
kEps
=
1e-6
;
if
(
out_min
<
-
kEps
&&
out_max
>
kEps
)
{
float
quantized_zero
=
-
out_min
/
*
scale
;
int32_t
quantized_zero_near_int
=
static_cast
<
int32_t
>
(
roundf
(
quantized_zero
));
*
zero_point
=
quantized_zero_near_int
;
if
(
fabs
(
quantized_zero
-
quantized_zero_near_int
)
>
kEps
)
{
if
(
quantized_zero
<
quantized_zero_near_int
||
non_zero
)
{
// keep out_max fixed, and move out_min
*
zero_point
=
static_cast
<
int32_t
>
(
std
::
ceil
(
quantized_zero
));
*
scale
=
out_max
/
(
quantized_max
-
*
zero_point
);
}
else
{
// keep out_min fixed, and move out_max
*
scale
=
out_min
/
(
quantized_min
-
*
zero_point
);
}
}
}
else
if
(
out_min
>
-
kEps
)
{
*
zero_point
=
quantized_min
;
}
else
{
*
zero_point
=
quantized_max
;
}
}
template
<
typename
T
>
inline
T
Saturate
(
float
value
)
{
int
rounded_value
=
static_cast
<
int
>
(
value
);
if
(
rounded_value
<=
std
::
numeric_limits
<
T
>::
lowest
())
{
return
std
::
numeric_limits
<
T
>::
lowest
();
}
else
if
(
rounded_value
>=
std
::
numeric_limits
<
T
>::
max
())
{
return
std
::
numeric_limits
<
T
>::
max
();
}
else
{
return
static_cast
<
T
>
(
rounded_value
);
}
}
inline
void
FindMinMax
(
const
float
*
input
,
const
index_t
size
,
float
*
min_val
,
float
*
max_val
)
{
float
max_v
=
std
::
numeric_limits
<
float
>::
lowest
();
float
min_v
=
std
::
numeric_limits
<
float
>::
max
();
for
(
index_t
i
=
0
;
i
<
size
;
++
i
)
{
max_v
=
std
::
max
(
max_v
,
input
[
i
]);
min_v
=
std
::
min
(
min_v
,
input
[
i
]);
}
*
min_val
=
min_v
;
*
max_val
=
max_v
;
}
template
<
typename
T
>
inline
void
QuantizeWithScaleAndZeropoint
(
const
float
*
input
,
const
index_t
size
,
float
scale
,
int32_t
zero_point
,
T
*
output
)
{
float
recip_scale
=
1
/
scale
;
#pragma omp parallel for
for
(
int
i
=
0
;
i
<
size
;
++
i
)
{
output
[
i
]
=
Saturate
<
T
>
(
roundf
(
zero_point
+
recip_scale
*
input
[
i
]));
}
}
template
<
typename
T
>
inline
void
Quantize
(
const
float
*
input
,
const
index_t
size
,
bool
non_zero
,
T
*
output
,
float
*
scale
,
int32_t
*
zero_point
)
{
float
in_min_data
;
float
in_max_data
;
FindMinMax
(
input
,
size
,
&
in_min_data
,
&
in_max_data
);
AdjustRange
<
T
>
(
in_min_data
,
in_max_data
,
non_zero
,
scale
,
zero_point
);
QuantizeWithScaleAndZeropoint
(
input
,
size
,
*
scale
,
*
zero_point
,
output
);
}
template
<
typename
T
>
inline
void
Dequantize
(
const
T
*
input
,
const
index_t
size
,
const
float
scale
,
const
int32_t
zero_point
,
float
*
output
)
{
#pragma omp parallel for
for
(
int
i
=
0
;
i
<
size
;
++
i
)
{
output
[
i
]
=
scale
*
(
input
[
i
]
-
zero_point
);
}
}
inline
void
QuantizeMultiplier
(
double
multiplier
,
int32_t
*
output_multiplier
,
int32_t
*
shift
)
{
if
(
multiplier
==
0.
f
)
{
*
output_multiplier
=
0
;
*
shift
=
0
;
return
;
}
const
double
q
=
std
::
frexp
(
multiplier
,
shift
);
auto
qint
=
static_cast
<
int64_t
>
(
roundl
(
q
*
(
1ll
<<
31
)));
if
(
qint
==
(
1ll
<<
31
))
{
qint
/=
2
;
++*
shift
;
}
*
output_multiplier
=
static_cast
<
int32_t
>
(
qint
);
MACE_CHECK
(
*
output_multiplier
<=
std
::
numeric_limits
<
int32_t
>::
max
());
}
inline
void
GetOutputMultiplierAndShift
(
const
float
lhs_scale
,
const
float
rhs_scale
,
const
float
output_scale
,
int32_t
*
quantized_multiplier
,
int
*
right_shift
)
{
float
real_multiplier
=
lhs_scale
*
rhs_scale
/
output_scale
;
MACE_CHECK
(
real_multiplier
>
0.
f
&&
real_multiplier
<
1.
f
,
real_multiplier
);
int
exponent
;
QuantizeMultiplier
(
real_multiplier
,
quantized_multiplier
,
&
exponent
);
*
right_shift
=
-
exponent
;
MACE_CHECK
(
*
right_shift
>=
0
);
}
template
<
DeviceType
D
,
typename
T
>
struct
QuantizeFunctor
;
...
...
mace/ops/conv_2d_test.cc
浏览文件 @
6c65796f
...
...
@@ -1174,7 +1174,7 @@ void TestQuant(const index_t batch,
Tensor
*
bias
=
net
.
GetTensor
(
"Bias"
);
auto
bias_data
=
bias
->
data
<
float
>
();
std
::
vector
<
int32_t
>
q_bias
(
bias
->
size
());
kernels
::
QuantizeWithScaleAndZeropoint
(
QuantizeWithScaleAndZeropoint
(
bias_data
,
bias
->
size
(),
q_input
->
scale
()
*
q_filter
->
scale
(),
0
,
q_bias
.
data
());
net
.
AddInputFromArray
<
DeviceType
::
CPU
,
int32_t
>
(
"QuantizedBias"
,
...
...
mace/ops/depthwise_conv2d_test.cc
浏览文件 @
6c65796f
...
...
@@ -459,7 +459,7 @@ void TestQuant(const index_t batch,
Tensor
*
bias
=
net
.
GetTensor
(
"Bias"
);
auto
bias_data
=
bias
->
data
<
float
>
();
std
::
vector
<
int32_t
>
q_bias
(
bias
->
size
());
kernels
::
QuantizeWithScaleAndZeropoint
(
QuantizeWithScaleAndZeropoint
(
bias_data
,
bias
->
size
(),
q_input
->
scale
()
*
q_filter
->
scale
(),
0
,
q_bias
.
data
());
net
.
AddInputFromArray
<
DeviceType
::
CPU
,
int32_t
>
(
...
...
mace/ops/fully_connected_test.cc
浏览文件 @
6c65796f
...
...
@@ -277,7 +277,7 @@ void QuantRandom(const index_t batch,
Tensor
*
bias
=
net
.
GetTensor
(
"Bias"
);
auto
bias_data
=
bias
->
data
<
float
>
();
std
::
vector
<
int32_t
>
q_bias
(
bias
->
size
());
kernels
::
QuantizeWithScaleAndZeropoint
(
QuantizeWithScaleAndZeropoint
(
bias_data
,
bias
->
size
(),
q_input
->
scale
()
*
q_weight
->
scale
(),
0
,
q_bias
.
data
());
net
.
AddInputFromArray
<
DeviceType
::
CPU
,
int32_t
>
(
"QuantizedBias"
,
...
...
mace/proto/mace.proto
浏览文件 @
6c65796f
...
...
@@ -36,6 +36,7 @@ message ConstTensor {
optional
int64
data_size
=
7
;
optional
float
scale
=
8
;
optional
int32
zero_point
=
9
;
optional
bool
quantized
=
10
[
default
=
false
];
optional
uint32
node_id
=
100
;
}
...
...
mace/python/tools/converter_tool/transformer.py
浏览文件 @
6c65796f
...
...
@@ -1667,9 +1667,6 @@ class Transformer(base_converter.ConverterInterface):
def
quantize_tensor
(
self
,
tensor
):
"""Assume biasadd has been already folded with convolution and fc"""
if
not
self
.
_option
.
quantize
:
return
False
if
tensor
.
data_type
==
mace_pb2
.
DT_FLOAT
:
ops
=
self
.
_consumers
.
get
(
tensor
.
name
,
None
)
if
len
(
ops
)
==
1
and
ops
[
0
].
type
in
[
MaceOp
.
Conv2D
.
name
,
...
...
@@ -1697,6 +1694,7 @@ class Transformer(base_converter.ConverterInterface):
tensor
.
int32_data
.
extend
(
quantized_tensor
.
data
)
tensor
.
scale
=
quantized_tensor
.
scale
tensor
.
zero_point
=
quantized_tensor
.
zero
tensor
.
quantized
=
True
self
.
_quantized_tensor
.
update
([
tensor
.
name
])
return
False
...
...
mace/python/tools/tensor_source.jinja2
浏览文件 @
6c65796f
...
...
@@ -34,6 +34,7 @@ void CreateTensor{{tensor_info.id}}(mace::ConstTensor *const_tensor) {
const_tensor->set_node_id({{ tensor.node_id }});
const_tensor->set_scale({{ tensor.scale }});
const_tensor->set_zero_point({{ tensor.zero_point }});
const_tensor->set_quantized({{ tensor.quantized | lower}});
}
} // namespace {{tag}}
...
...
mace/utils/BUILD
浏览文件 @
6c65796f
...
...
@@ -15,20 +15,17 @@ cc_library(
"logging.cc"
,
"string_util.cc"
,
],
hdrs
=
[
"env_time.h"
,
"logging.h"
,
"memory_logging.h"
,
"rwlock.h"
,
"string_util.h"
,
"timer.h"
,
"tuner.h"
,
"utils.h"
,
hdrs
=
glob
([
"*.h"
,
]),
copts
=
[
"-Werror"
,
"-Wextra"
,
"-Wno-missing-field-initializers"
,
],
linkopts
=
if_android
([
"-llog"
,
]),
copts
=
[
"-Werror"
,
"-Wextra"
,
"-Wno-missing-field-initializers"
],
deps
=
[
"//mace/public"
,
],
...
...
@@ -40,7 +37,11 @@ cc_test(
srcs
=
[
"tuner_test.cc"
,
],
copts
=
[
"-Werror"
,
"-Wextra"
,
"-Wno-missing-field-initializers"
],
copts
=
[
"-Werror"
,
"-Wextra"
,
"-Wno-missing-field-initializers"
,
],
linkopts
=
[
"-ldl"
]
+
if_android
([
"-pie"
,
"-lm"
,
# Required by unordered_map
...
...
mace/utils/quantize.h
0 → 100644
浏览文件 @
6c65796f
// Copyright 2018 Xiaomi, Inc. All rights reserved.
//
// Licensed 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.
#ifndef MACE_UTILS_QUANTIZE_H_
#define MACE_UTILS_QUANTIZE_H_
#include <limits>
#include <algorithm>
namespace
mace
{
template
<
typename
T
>
inline
void
AdjustRange
(
const
float
in_min_data
,
const
float
in_max_data
,
const
bool
non_zero
,
float
*
scale
,
int32_t
*
zero_point
)
{
// re-range to make range include zero float and
// make zero float as integer u8
const
T
quantized_min
=
std
::
numeric_limits
<
T
>::
lowest
();
const
T
quantized_max
=
std
::
numeric_limits
<
T
>::
max
();
if
(
quantized_min
<
0
)
{
MACE_ASSERT
(
!
non_zero
,
"Cannot nudge to non_zero quantize value."
);
}
float
out_max
=
std
::
max
(
0.
f
,
in_max_data
);
float
out_min
=
std
::
min
(
0.
f
,
in_min_data
);
// make in_min_data quantize as greater than 1
if
(
non_zero
)
{
out_min
=
std
::
min
(
out_min
,
in_min_data
-
(
out_max
-
in_min_data
)
/
(
quantized_max
-
quantized_min
-
1
));
}
*
scale
=
(
out_max
-
out_min
)
/
(
quantized_max
-
quantized_min
);
const
float
kEps
=
1e-6
;
if
(
out_min
<
-
kEps
&&
out_max
>
kEps
)
{
float
quantized_zero
=
-
out_min
/
*
scale
;
int32_t
quantized_zero_near_int
=
static_cast
<
int32_t
>
(
roundf
(
quantized_zero
));
*
zero_point
=
quantized_zero_near_int
;
if
(
fabs
(
quantized_zero
-
quantized_zero_near_int
)
>
kEps
)
{
if
(
quantized_zero
<
quantized_zero_near_int
||
non_zero
)
{
// keep out_max fixed, and move out_min
*
zero_point
=
static_cast
<
int32_t
>
(
std
::
ceil
(
quantized_zero
));
*
scale
=
out_max
/
(
quantized_max
-
*
zero_point
);
}
else
{
// keep out_min fixed, and move out_max
*
scale
=
out_min
/
(
quantized_min
-
*
zero_point
);
}
}
}
else
if
(
out_min
>
-
kEps
)
{
*
zero_point
=
quantized_min
;
}
else
{
*
zero_point
=
quantized_max
;
}
}
template
<
typename
T
>
inline
T
Saturate
(
float
value
)
{
int
rounded_value
=
static_cast
<
int
>
(
value
);
if
(
rounded_value
<=
std
::
numeric_limits
<
T
>::
lowest
())
{
return
std
::
numeric_limits
<
T
>::
lowest
();
}
else
if
(
rounded_value
>=
std
::
numeric_limits
<
T
>::
max
())
{
return
std
::
numeric_limits
<
T
>::
max
();
}
else
{
return
static_cast
<
T
>
(
rounded_value
);
}
}
inline
void
FindMinMax
(
const
float
*
input
,
const
index_t
size
,
float
*
min_val
,
float
*
max_val
)
{
float
max_v
=
std
::
numeric_limits
<
float
>::
lowest
();
float
min_v
=
std
::
numeric_limits
<
float
>::
max
();
for
(
index_t
i
=
0
;
i
<
size
;
++
i
)
{
max_v
=
std
::
max
(
max_v
,
input
[
i
]);
min_v
=
std
::
min
(
min_v
,
input
[
i
]);
}
*
min_val
=
min_v
;
*
max_val
=
max_v
;
}
template
<
typename
T
>
inline
void
QuantizeWithScaleAndZeropoint
(
const
float
*
input
,
const
index_t
size
,
float
scale
,
int32_t
zero_point
,
T
*
output
)
{
float
recip_scale
=
1
/
scale
;
#pragma omp parallel for
for
(
int
i
=
0
;
i
<
size
;
++
i
)
{
output
[
i
]
=
Saturate
<
T
>
(
roundf
(
zero_point
+
recip_scale
*
input
[
i
]));
}
}
template
<
typename
T
>
inline
void
Quantize
(
const
float
*
input
,
const
index_t
size
,
bool
non_zero
,
T
*
output
,
float
*
scale
,
int32_t
*
zero_point
)
{
float
in_min_data
;
float
in_max_data
;
FindMinMax
(
input
,
size
,
&
in_min_data
,
&
in_max_data
);
AdjustRange
<
T
>
(
in_min_data
,
in_max_data
,
non_zero
,
scale
,
zero_point
);
QuantizeWithScaleAndZeropoint
(
input
,
size
,
*
scale
,
*
zero_point
,
output
);
}
template
<
typename
T
>
inline
void
Dequantize
(
const
T
*
input
,
const
index_t
size
,
const
float
scale
,
const
int32_t
zero_point
,
float
*
output
)
{
#pragma omp parallel for
for
(
int
i
=
0
;
i
<
size
;
++
i
)
{
output
[
i
]
=
scale
*
(
input
[
i
]
-
zero_point
);
}
}
inline
void
QuantizeMultiplier
(
double
multiplier
,
int32_t
*
output_multiplier
,
int32_t
*
shift
)
{
if
(
multiplier
==
0.
f
)
{
*
output_multiplier
=
0
;
*
shift
=
0
;
return
;
}
const
double
q
=
std
::
frexp
(
multiplier
,
shift
);
auto
qint
=
static_cast
<
int64_t
>
(
roundl
(
q
*
(
1ll
<<
31
)));
if
(
qint
==
(
1ll
<<
31
))
{
qint
/=
2
;
++*
shift
;
}
*
output_multiplier
=
static_cast
<
int32_t
>
(
qint
);
MACE_CHECK
(
*
output_multiplier
<=
std
::
numeric_limits
<
int32_t
>::
max
());
}
inline
void
GetOutputMultiplierAndShift
(
const
float
lhs_scale
,
const
float
rhs_scale
,
const
float
output_scale
,
int32_t
*
quantized_multiplier
,
int
*
right_shift
)
{
float
real_multiplier
=
lhs_scale
*
rhs_scale
/
output_scale
;
MACE_CHECK
(
real_multiplier
>
0.
f
&&
real_multiplier
<
1.
f
,
real_multiplier
);
int
exponent
;
QuantizeMultiplier
(
real_multiplier
,
quantized_multiplier
,
&
exponent
);
*
right_shift
=
-
exponent
;
MACE_CHECK
(
*
right_shift
>=
0
);
}
}
// namespace mace
#endif // MACE_UTILS_QUANTIZE_H_
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录