Repository navigation
Expand file tree
/
Copy pathquantized-fp16.cpp
More file actions
112 lines (96 loc) · 4.61 KB
/
Copy pathquantized-fp16.cpp
File metadata and controls
112 lines (96 loc) · 4.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/*
* Copyright (c) 2019, 2024, 2025-2026 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#if defined(__aarch64__) && (defined(FP16_KERNELS) || defined(ARM_COMPUTE_ENABLE_FP16))
#include "arm_gemm/arm_gemm.hpp"
#include "arm_common/internal/utils.hpp"
#include "arm_common/internal/quantized.hpp"
#include <arm_neon.h>
namespace arm_gemm {
// FP16 dequantize
template<>
void dequantize_block_32<__fp16>(const DequantizeFloat &qp, unsigned int width, unsigned int height,
const int32_t * in_ptr, unsigned int in_stride, __fp16 *out_ptr, unsigned int out_stride,
const __fp16 * bias_ptr, bool not_first_pass, const Activation &act,
const int32_t * /*col_bias*/, const int32_t * /*row_sum*/, int32_t /*k_total*/)
{
const float32x4_t vscale = vdupq_n_f32(qp.scale);
float maxval = std::numeric_limits<float>::infinity();
float minval = -std::numeric_limits<float>::infinity();
switch(act.type) {
default:
case Activation::Type::None:
break;
case Activation::Type::BoundedReLU:
maxval = static_cast<float>(act.param1);
/* fall through */
case Activation::Type::ReLU:
minval = 0;
break;
}
const float16x8_t vmin = vdupq_n_f16(static_cast<__fp16>(minval));
const float16x8_t vmax = vdupq_n_f16(static_cast<__fp16>(maxval));
for(unsigned int row=0; row<height; row++) {
unsigned int col=0;
if (width >= 8) {
for(; col <= (width-8); col+=8) {
const int32x4_t vin0 = vld1q_s32(in_ptr + col + (row * in_stride));
const int32x4_t vin1 = vld1q_s32(in_ptr + col + 4 + (row * in_stride));
float32x4_t vdeq0 = vmulq_f32(vcvtq_f32_s32(vin0), vscale);
float32x4_t vdeq1 = vmulq_f32(vcvtq_f32_s32(vin1), vscale);
if(bias_ptr) {
const float16x8_t bin = vld1q_f16(bias_ptr + col);
const float32x4_t bin0 = vcvt_f32_f16(vget_low_f16(bin));
const float32x4_t bin1 = vcvt_f32_f16(vget_high_f16(bin));
vdeq0 = vaddq_f32(vdeq0, bin0);
vdeq1 = vaddq_f32(vdeq1, bin1);
}
if(not_first_pass) {
const float16x8_t in = vld1q_f16(out_ptr + col + (row * out_stride));
const float32x4_t in0 = vcvt_f32_f16(vget_low_f16(in));
const float32x4_t in1 = vcvt_f32_f16(vget_high_f16(in));
vdeq0 = vaddq_f32(vdeq0, in0);
vdeq1 = vaddq_f32(vdeq1, in1);
}
float16x8_t vdeq16 = vcombine_f16(vcvt_f16_f32(vdeq0), vcvt_f16_f32(vdeq1));
vdeq16 = vminq_f16(vmaxq_f16(vdeq16, vmin), vmax);
vst1q_f16(out_ptr + col + (row * out_stride), vdeq16);
}
}
// left-over elements
for(; col < width; ++col) {
const int32_t val = *(in_ptr + (row * in_stride) + col);
float res = static_cast<float>(val * qp.scale);
if(bias_ptr) {
res += static_cast<float>(*(bias_ptr + col));
}
if(not_first_pass) {
res += *(out_ptr + (row * out_stride) + col);
}
res = std::min(std::max(res, minval), maxval);
*(out_ptr + (row * out_stride) + col) = static_cast<__fp16>(res);
}
}
}
} // namespace arm_gemm
#endif // defined(__aarch64__) && (defined(FP16_KERNELS) || defined(ARM_COMPUTE_ENABLE_FP16))