@@ -167,6 +167,25 @@ float get_scale(const Tensor& scale, size_t channel_ix) {
167167 }
168168}
169169
170+ /* *
171+ * Reads one per-channel zero point. `dequantize_per_channel` accepts both Int
172+ * and Long zero_point tensors, so the element width must be honoured here —
173+ * reading an Int tensor as int64 reinterprets pairs of channels as one value
174+ * and runs off the end of the buffer.
175+ */
176+ int64_t get_zero_point (const Tensor& zero_points, size_t channel_ix) {
177+ ET_CHECK_MSG (
178+ (zero_points.scalar_type () == ScalarType::Int) ||
179+ (zero_points.scalar_type () == ScalarType::Long),
180+ " zero_points.scalar_type() %" PRId8 " is not int or long type" ,
181+ static_cast <int8_t >(zero_points.scalar_type ()));
182+ if (zero_points.scalar_type () == ScalarType::Int) {
183+ return static_cast <int64_t >(
184+ zero_points.const_data_ptr <int32_t >()[channel_ix]);
185+ }
186+ return zero_points.const_data_ptr <int64_t >()[channel_ix];
187+ }
188+
170189bool can_use_optimized_dequantize_per_channel (
171190 const Tensor& in,
172191 const ScalarType in_dtype,
@@ -208,17 +227,15 @@ void dequantize_per_channel_optimized(
208227 }
209228 const int8_t * in_data = in.const_data_ptr <int8_t >();
210229 float * out_data = out.mutable_data_ptr <float >();
211- const int64_t * zero_points_data = nullptr ;
212- if (opt_zero_points.has_value ()) {
213- zero_points_data = opt_zero_points.value ().const_data_ptr <int64_t >();
214- }
230+ const Tensor* zero_points =
231+ opt_zero_points.has_value () ? &opt_zero_points.value () : nullptr ;
215232 const StridesType axis_stride = in.strides ()[axis];
216233 const StridesType outer_stride = in.size (axis) * axis_stride;
217234 apply_over_unpacked_dim (
218235 [in_data,
219236 out_data,
220237 &scales,
221- zero_points_data ,
238+ zero_points ,
222239 axis_stride,
223240 outer_stride,
224241 quant_min,
@@ -227,8 +244,8 @@ void dequantize_per_channel_optimized(
227244 const int8_t * in_data_local =
228245 in_data + outer_idx * outer_stride + unpacked_dim_idx * axis_stride;
229246 const double scale = get_scale (scales, unpacked_dim_idx);
230- const int64_t zero_point = zero_points_data != nullptr
231- ? zero_points_data[ unpacked_dim_idx]
247+ const int64_t zero_point = zero_points != nullptr
248+ ? get_zero_point (*zero_points, unpacked_dim_idx)
232249 : 0 ;
233250 float * out_data_local = out_data + outer_idx * outer_stride +
234251 unpacked_dim_idx * axis_stride;
@@ -422,12 +439,8 @@ Tensor& dequantize_per_channel_out(
422439 dims[i] = i + 1 ;
423440 }
424441 }
425- const int64_t * zero_point_data;
426- if (opt_zero_points.has_value ()) {
427- zero_point_data = opt_zero_points.value ().const_data_ptr <int64_t >();
428- } else {
429- zero_point_data = nullptr ;
430- }
442+ const Tensor* zero_point_tensor =
443+ opt_zero_points.has_value () ? &opt_zero_points.value () : nullptr ;
431444
432445 std::optional<executorch::aten::ArrayRef<int64_t >> optional_dim_list{
433446 executorch::aten::ArrayRef<int64_t >{dims, size_t (input.dim () - 1 )}};
@@ -449,14 +462,14 @@ Tensor& dequantize_per_channel_out(
449462 axis == 0 , " Axis must be 0 for a single dimensional tensors" ); \
450463 const std::optional<int64_t > dim; \
451464 apply_over_dim ( \
452- [input_data_ptr, out_data_ptr, zero_point_data , &scale]( \
465+ [input_data_ptr, out_data_ptr, zero_point_tensor , &scale]( \
453466 size_t numel, size_t stride, size_t base_ix) { \
454467 for (size_t i = 0 ; i < numel; i++) { \
455468 size_t current_ix = base_ix * stride + i; \
456469 float _scale = get_scale (scale, current_ix); \
457470 int64_t zero_point = 0 ; \
458- if (zero_point_data != nullptr ) { \
459- zero_point = zero_point_data[ current_ix]; \
471+ if (zero_point_tensor != nullptr ) { \
472+ zero_point = get_zero_point (*zero_point_tensor, current_ix); \
460473 } \
461474 out_data_ptr[current_ix] = \
462475 static_cast <CTYPE_OUT >( \
@@ -472,8 +485,8 @@ Tensor& dequantize_per_channel_out(
472485 for (size_t channel_ix = 0 ; channel_ix < input.size (axis); ++channel_ix) { \
473486 float _scale = get_scale (scale, channel_ix); \
474487 int64_t _zero_point = 0 ; \
475- if (zero_point_data != nullptr ) { \
476- _zero_point = zero_point_data[ channel_ix]; \
488+ if (zero_point_tensor != nullptr ) { \
489+ _zero_point = get_zero_point (*zero_point_tensor, channel_ix); \
477490 } \
478491 auto * out_data_ptr = out.mutable_data_ptr <CTYPE_OUT >(); \
479492 const auto * input_data_ptr = input.const_data_ptr <CTYPE_IN >(); \
0 commit comments