Skip to content

Commit b42339d

Browse files
autodiff : Added optimization for quantize / dequantize
Added python script to convert a pytorch model to autodiff C++ version (Only support the operators in autodiff)
1 parent f6fbd11 commit b42339d

15 files changed

Lines changed: 1750 additions & 72 deletions

File tree

dsppp/Include/dsppp/Helium/basic.hpp

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,191 @@
1818
*/
1919

2020
#if defined(ARM_MATH_MVEI) || defined(ARM_MATH_MVEF)
21+
22+
template<typename DST,typename SRC,
23+
typename std::enable_if<has_vector_inst<DST>() &&
24+
has_vector_inst<SRC>() &&
25+
vector_idx_pair<DST,SRC>() &&
26+
has_predicate<DST>(),bool>::type = true>
27+
inline void _round_to_nearest(DST& destination, const SRC& source,
28+
const vector_length_t length,
29+
const Helium* = nullptr)
30+
{
31+
using T = typename traits<DST>::Scalar;
32+
constexpr int lanes = vector_traits<T>::nb_lanes;
33+
for (index_t i = 0; i < length; i += lanes)
34+
{
35+
auto value = source.vector_op_tail(i, length - i);
36+
if constexpr (std::is_same<T, float>::value)
37+
value = vrndnq_f32(value);
38+
#if defined(ARM_FLOAT16_SUPPORTED)
39+
else if constexpr (std::is_same<T, float16_t>::value)
40+
value = vrndnq_f16(value);
41+
#endif
42+
destination.vector_store_tail(i, length - i, value);
43+
}
44+
}
45+
46+
template<typename DST,typename SRC,
47+
typename std::enable_if<has_vector_inst<DST>() &&
48+
has_vector_inst<SRC>() &&
49+
vector_idx_pair<DST,SRC>() &&
50+
has_predicate<DST>(),bool>::type = true>
51+
inline void _round_to_nearest_clipped(
52+
DST& destination, const SRC& source,
53+
typename traits<DST>::Scalar offset,
54+
typename traits<DST>::Scalar minimum,
55+
typename traits<DST>::Scalar maximum,
56+
const vector_length_t length, const Helium* = nullptr)
57+
{
58+
using T = typename traits<DST>::Scalar;
59+
constexpr int lanes = vector_traits<T>::nb_lanes;
60+
const auto minimum_vector = inner::vconst(minimum);
61+
const auto maximum_vector = inner::vconst(maximum);
62+
for (index_t i = 0; i < length; i += lanes)
63+
{
64+
auto value = source.vector_op_tail(i, length - i);
65+
if constexpr (std::is_same<T, float>::value)
66+
value = vrndnq_f32(value);
67+
#if defined(ARM_FLOAT16_SUPPORTED)
68+
else if constexpr (std::is_same<T, float16_t>::value)
69+
value = vrndnq_f16(value);
70+
#endif
71+
value = inner::vadd(value, offset);
72+
value = vmaxnmq(value, minimum_vector);
73+
value = vminnmq(value, maximum_vector);
74+
destination.vector_store_tail(i, length - i, value);
75+
}
76+
}
77+
78+
template<typename DST,typename SRC,
79+
typename std::enable_if<has_vector_inst<DST>() &&
80+
has_vector_inst<SRC>() &&
81+
vector_idx_pair<DST,SRC>() &&
82+
has_predicate<DST>(),bool>::type = true>
83+
inline void _round_scaled_to_nearest_clipped(
84+
DST& destination, const SRC& source, float multiplier,
85+
typename traits<DST>::Scalar offset,
86+
typename traits<DST>::Scalar minimum,
87+
typename traits<DST>::Scalar maximum,
88+
const vector_length_t length, const Helium* = nullptr)
89+
{
90+
using T = typename traits<DST>::Scalar;
91+
constexpr int lanes = vector_traits<T>::nb_lanes;
92+
for (index_t i = 0; i < length; i += lanes)
93+
{
94+
auto value = source.vector_op_tail(i, length - i);
95+
if constexpr (std::is_same<T, float>::value)
96+
{
97+
value = vrndnq_f32(vmulq_n_f32(value, multiplier));
98+
value = vaddq_n_f32(value, offset);
99+
value = vmaxnmq(value, inner::vconst(minimum));
100+
value = vminnmq(value, inner::vconst(maximum));
101+
}
102+
#if defined(ARM_FLOAT16_SUPPORTED)
103+
else if constexpr (std::is_same<T, float16_t>::value)
104+
{
105+
auto bottom = vrndnq_f32(
106+
vmulq_n_f32(vcvtbq_f32_f16(value), multiplier));
107+
auto top = vrndnq_f32(
108+
vmulq_n_f32(vcvttq_f32_f16(value), multiplier));
109+
const float offset_f32 = static_cast<float>(offset);
110+
const auto minimum_f32 = vdupq_n_f32(static_cast<float>(minimum));
111+
const auto maximum_f32 = vdupq_n_f32(static_cast<float>(maximum));
112+
bottom = vmaxnmq(vaddq_n_f32(bottom, offset_f32), minimum_f32);
113+
top = vmaxnmq(vaddq_n_f32(top, offset_f32), minimum_f32);
114+
bottom = vminnmq(bottom, maximum_f32);
115+
top = vminnmq(top, maximum_f32);
116+
value = vcvtbq_f16_f32(value, bottom);
117+
value = vcvttq_f16_f32(value, top);
118+
}
119+
#endif
120+
destination.vector_store_tail(i, length - i, value);
121+
}
122+
}
123+
124+
template<typename MASK>
125+
inline mve_pred16_t _nearest_even_range_predicate(
126+
const MASK& mask, index_t i, vector_length_t remaining,
127+
const Helium* = nullptr)
128+
{
129+
using T = typename MASK::Scalar;
130+
const mve_pred16_t tail = inner::vctpq<T>::mk(remaining);
131+
auto value = mask.values().vector_op_tail(i, remaining);
132+
if constexpr (std::is_same<T, float>::value)
133+
{
134+
value = vrndnq_f32(vmulq_n_f32(value, mask.multiplier()));
135+
value = inner::vadd(value, mask.offset(), tail);
136+
}
137+
#if defined(ARM_FLOAT16_SUPPORTED)
138+
else if constexpr (std::is_same<T, float16_t>::value)
139+
{
140+
auto bottom = vrndnq_f32(
141+
vmulq_n_f32(vcvtbq_f32_f16(value), mask.multiplier()));
142+
auto top = vrndnq_f32(
143+
vmulq_n_f32(vcvttq_f32_f16(value), mask.multiplier()));
144+
const float offset = static_cast<float>(mask.offset());
145+
bottom = vaddq_n_f32(bottom, offset);
146+
top = vaddq_n_f32(top, offset);
147+
value = vcvtbq_f16_f32(value, bottom);
148+
value = vcvttq_f16_f32(value, top);
149+
}
150+
#endif
151+
mve_pred16_t selected = vcmpgeq_m(value, mask.minimum(), tail);
152+
return vcmpleq_m(value, mask.maximum(), selected);
153+
}
154+
155+
template<typename DST,typename SRC,typename MASK,
156+
typename std::enable_if<has_vector_inst<DST>() &&
157+
has_vector_inst<SRC>() &&
158+
vector_idx_pair<DST,SRC>() &&
159+
has_predicate<DST>(),bool>::type = true>
160+
inline void _masked_scale_add(DST& destination, const SRC& source,
161+
const MASK& mask,
162+
typename traits<DST>::Scalar scale,
163+
const vector_length_t length,
164+
const Helium* architecture = nullptr)
165+
{
166+
using T = typename traits<DST>::Scalar;
167+
constexpr int lanes = vector_traits<T>::nb_lanes;
168+
for (index_t i = 0; i < length; i += lanes)
169+
{
170+
const mve_pred16_t selected =
171+
_nearest_even_range_predicate(mask, i, length - i, architecture);
172+
auto destination_value = destination.vector_op_tail(i, length - i);
173+
destination_value = vfmaq_m(
174+
destination_value, source.vector_op_tail(i, length - i),
175+
scale, selected);
176+
destination.vector_store_tail(i, length - i, destination_value);
177+
}
178+
}
179+
180+
template<typename A,typename B,typename MASK,
181+
typename std::enable_if<has_vector_inst<A>() &&
182+
has_vector_inst<B>() &&
183+
vector_idx_pair<A,B>() &&
184+
has_predicate<A>(),bool>::type = true>
185+
inline auto _masked_dot_sum(const A& a, const B& b, const MASK& mask,
186+
const vector_length_t length,
187+
const Helium* architecture = nullptr)
188+
{
189+
using T = typename traits<A>::Scalar;
190+
using Vector = typename vector_traits<T>::vector;
191+
constexpr int lanes = vector_traits<T>::nb_lanes;
192+
Vector dot = vector_traits<T>::temp_acc_zero();
193+
Vector sum = vector_traits<T>::temp_acc_zero();
194+
for (index_t i = 0; i < length; i += lanes)
195+
{
196+
const mve_pred16_t selected =
197+
_nearest_even_range_predicate(mask, i, length - i, architecture);
198+
const auto first = a.vector_op_tail(i, length - i);
199+
dot = inner::vmacc(dot, first, b.vector_op_tail(i, length - i),
200+
selected);
201+
sum = vaddq_m(sum, sum, first, selected);
202+
}
203+
return MaskedDotSum<T>{inner::vreduce(dot), inner::vreduce(sum)};
204+
}
205+
21206
/**
22207
* @brief Fill evaluator for Helium
23208
*

dsppp/Include/dsppp/Scalar/basic.hpp

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,96 @@
1212

1313
#define SCALAR_UNROLL 2
1414

15+
template<typename DST,typename SRC>
16+
inline void _round_to_nearest(DST& destination, const SRC& source,
17+
const vector_length_t length,
18+
const Scalar* = nullptr)
19+
{
20+
using T = typename traits<DST>::Scalar;
21+
for (index_t i = 0; i < length; ++i)
22+
destination[i] = static_cast<T>(
23+
std::nearbyint(static_cast<float>(source[i])));
24+
}
25+
26+
template<typename DST,typename SRC>
27+
inline void _round_to_nearest_clipped(
28+
DST& destination, const SRC& source,
29+
typename traits<DST>::Scalar offset,
30+
typename traits<DST>::Scalar minimum,
31+
typename traits<DST>::Scalar maximum,
32+
const vector_length_t length, const Scalar* = nullptr)
33+
{
34+
using T = typename traits<DST>::Scalar;
35+
for (index_t i = 0; i < length; ++i)
36+
{
37+
float value = std::nearbyint(static_cast<float>(source[i])) +
38+
static_cast<float>(offset);
39+
if (value < static_cast<float>(minimum))
40+
value = static_cast<float>(minimum);
41+
if (value > static_cast<float>(maximum))
42+
value = static_cast<float>(maximum);
43+
destination[i] = static_cast<T>(value);
44+
}
45+
}
46+
47+
template<typename DST,typename SRC>
48+
inline void _round_scaled_to_nearest_clipped(
49+
DST& destination, const SRC& source, float multiplier,
50+
typename traits<DST>::Scalar offset,
51+
typename traits<DST>::Scalar minimum,
52+
typename traits<DST>::Scalar maximum,
53+
const vector_length_t length, const Scalar* = nullptr)
54+
{
55+
using T = typename traits<DST>::Scalar;
56+
for (index_t i = 0; i < length; ++i)
57+
{
58+
float value = std::nearbyint(
59+
static_cast<float>(source[i]) * multiplier) +
60+
static_cast<float>(offset);
61+
if (value < static_cast<float>(minimum))
62+
value = static_cast<float>(minimum);
63+
if (value > static_cast<float>(maximum))
64+
value = static_cast<float>(maximum);
65+
destination[i] = static_cast<T>(value);
66+
}
67+
}
68+
69+
template<typename MASK>
70+
inline bool _nearest_even_range_predicate(
71+
const MASK& mask, index_t i, vector_length_t,
72+
const Scalar* = nullptr)
73+
{
74+
return mask[i];
75+
}
76+
77+
template<typename DST,typename SRC,typename MASK>
78+
inline void _masked_scale_add(DST& destination, const SRC& source,
79+
const MASK& mask,
80+
typename traits<DST>::Scalar scale,
81+
const vector_length_t length,
82+
const Scalar* architecture = nullptr)
83+
{
84+
for (index_t i = 0; i < length; ++i)
85+
if (_nearest_even_range_predicate(mask, i, 1, architecture))
86+
destination[i] += source[i] * scale;
87+
}
88+
89+
template<typename A,typename B,typename MASK>
90+
inline auto _masked_dot_sum(const A& a, const B& b, const MASK& mask,
91+
const vector_length_t length,
92+
const Scalar* architecture = nullptr)
93+
{
94+
using T = typename traits<A>::Scalar;
95+
MaskedDotSum<T> result{T{}, T{}};
96+
for (index_t i = 0; i < length; ++i)
97+
if (_nearest_even_range_predicate(mask, i, 1, architecture))
98+
{
99+
result.dot += a[i] * b[i];
100+
result.sum += a[i];
101+
}
102+
return result;
103+
}
104+
15105
/**
16106
* @brief Fill evaluator for scalar architecture
17107
*

0 commit comments

Comments
 (0)