FZGPUModules 2.0
GPU-accelerated modular compression pipelines
Loading...
Searching...
No Matches
quantizer.h
Go to the documentation of this file.
1#pragma once
2
8#include "stage/stage.h"
9#include "fzm_format.h"
10#include "fused/lorenzo_quant/lorenzo_quant.h" // for ErrorBoundMode
11#include "backend/types.h"
12#include <array>
13#include <cmath>
14#include <cstdint>
15#include <memory>
16#include <cstring>
17#include <limits>
18
19namespace fz {
20
32 float value_base;
33 uint32_t quant_radius;
34 uint32_t num_elements;
35 uint32_t outlier_count;
38 uint8_t eb_mode;
39 uint8_t zigzag_codes;
42 uint8_t linear_mode;
43 uint8_t dither;
44 uint8_t _pad[5];
45 uint64_t dither_seed;
47 uint32_t _pad2;
55
57 : abs_error_bound(0.0f), user_error_bound(0.0f), value_base(0.0f),
59 input_type(DataType::FLOAT32), code_type(DataType::UINT16),
60 eb_mode(0), zigzag_codes(0),
61 outlier_threshold(std::numeric_limits<float>::infinity()),
63 dither_strength(1.0f), _pad2(0),
65};
66static_assert(sizeof(QuantizerConfig) <= FZM_STAGE_CONFIG_SIZE,
67 "QuantizerConfig must fit in FZM_STAGE_CONFIG_SIZE");
68
128template<typename TInput = float, typename TCode = uint16_t>
129class QuantizerStage : public Stage {
130public:
132 struct Config {
133 float error_bound = 1e-4f;
134 int quant_radius = 32768;
135 float outlier_capacity = 0.05f;
141 bool zigzag_codes = false;
143 float outlier_threshold = std::numeric_limits<float>::infinity();
147 bool inplace_outliers = false;
154 bool linear_mode = false;
164 bool dither = false;
167 uint64_t dither_seed = 0;
174 float dither_strength = 1.0f;
175
176 Config() = default;
177 Config(TInput eb, ErrorBoundMode mode = ErrorBoundMode::ABS,
178 int radius = 32768, float outlier_cap = 0.05f)
179 : error_bound(static_cast<float>(eb)), quant_radius(radius),
180 outlier_capacity(outlier_cap), eb_mode(mode) {}
181 };
182
183 explicit QuantizerStage(const Config& config = Config());
184 ~QuantizerStage() override;
185
187 fz::stream_t stream,
188 MemoryPool* pool,
189 const std::vector<void*>& inputs,
190 const std::vector<void*>& outputs,
191 const std::vector<size_t>& sizes
192 ) override;
193
194 void postStreamSync(fz::stream_t stream) override;
195
200 void onFinalize(size_t estimated_inlen, MemoryPool* pool) override;
201
202 size_t estimateDeviceFootprintBytes(size_t /*estimated_inlen*/) const override {
203 return (isLinearMode() || isInplaceMode()) ? 0 : sizeof(uint32_t);
204 }
205
206 std::string getName() const override { return "Quantizer"; }
207
208 size_t getNumInputs() const override {
209 if (!is_inverse_) return 1;
210 return (isLinearMode() || isInplaceMode()) ? 1 : 3;
211 }
212 size_t getNumOutputs() const override {
213 if (is_inverse_) return 1;
214 return (isLinearMode() || isInplaceMode()) ? 1 : 3;
215 }
216
217 std::vector<std::string> getOutputNames() const override {
218 if (is_inverse_) return {"reconstructed"};
219 if (isLinearMode() || isInplaceMode()) return {"codes"};
220 return {"codes", "outlier_vals", "outlier_idxs"};
221 }
222
223 std::vector<size_t> estimateOutputSizes(
224 const std::vector<size_t>& input_sizes
225 ) const override;
226
227 std::unordered_map<std::string, size_t> getActualOutputSizesByName() const override {
228 auto names = getOutputNames();
229 std::unordered_map<std::string, size_t> result;
230 for (size_t i = 0; i < names.size() && i < actual_output_sizes_.size(); i++)
231 result[names[i]] = actual_output_sizes_[i];
232 return result;
233 }
234 size_t getActualOutputSize(int index) const override {
235 return (index >= 0 && index < static_cast<int>(actual_output_sizes_.size()))
236 ? actual_output_sizes_[index] : 0;
237 }
238
239 void setInverse(bool inverse) override { is_inverse_ = inverse; }
240 bool isInverse() const override { return is_inverse_; }
241
246 void setDims(const std::array<size_t, 3>& dims) override { dims_ = dims; }
247
248 uint16_t getStageTypeId() const override {
249 return static_cast<uint16_t>(StageType::QUANTIZER);
250 }
251
252 uint8_t getOutputDataType(size_t output_index) const override {
253 if (is_inverse_) return static_cast<uint8_t>(getInputDataType());
254 // Linear mode: codes hold two's-complement signed q — declare the signed type
255 // so the DAG connects cleanly to LorenzoStage<intN>.
256 if (isLinearMode()) return static_cast<uint8_t>(signedOf(getCodeDataType()));
257 if (isInplaceMode()) return static_cast<uint8_t>(getCodeDataType()); // only codes
258 switch (output_index) {
259 case 0: return static_cast<uint8_t>(getCodeDataType());
260 case 1: return static_cast<uint8_t>(getInputDataType());
261 case 2: return static_cast<uint8_t>(DataType::UINT32);
262 default: return static_cast<uint8_t>(DataType::UINT8);
263 }
264 }
265
266 uint8_t getInputDataType(size_t /*input_index*/) const override {
267 return static_cast<uint8_t>(getInputDataType());
268 }
269
270 size_t serializeHeader(size_t output_index, uint8_t* buf, size_t max_size) const override;
271 size_t getMaxHeaderSize(size_t) const override { return sizeof(QuantizerConfig); }
272 void deserializeHeader(const uint8_t* buf, size_t size) override;
273
274 void saveState() override {
275 saved_config_ = config_;
276 saved_num_elements_ = num_elements_;
277 saved_actual_outlier_count_ = actual_outlier_count_;
278 saved_computed_abs_eb_ = computed_abs_eb_;
279 saved_computed_value_base_ = computed_value_base_;
280 saved_actual_output_sizes_ = actual_output_sizes_;
281 }
282
283 void restoreState() override {
284 config_ = saved_config_;
285 num_elements_ = saved_num_elements_;
286 actual_outlier_count_ = saved_actual_outlier_count_;
287 computed_abs_eb_ = saved_computed_abs_eb_;
288 computed_value_base_ = saved_computed_value_base_;
289 actual_output_sizes_ = saved_actual_output_sizes_;
290 }
291
292 void setErrorBound(TInput eb) { config_.error_bound = static_cast<float>(eb); }
293 void setQuantRadius(int r) { config_.quant_radius = r; }
294 void setOutlierCapacity(float c) { config_.outlier_capacity = c; }
295 void setErrorBoundMode(ErrorBoundMode m) { config_.eb_mode = m; }
296 void setValueBase(float vb) { config_.precomputed_value_base = vb; }
297 void setZigzagCodes(bool enable) { config_.zigzag_codes = enable; }
299 void setOutlierThreshold(float t) { config_.outlier_threshold = t; }
301 void setInplaceOutliers(bool enable) { config_.inplace_outliers = enable; }
303 void setLinearMode(bool enable) { config_.linear_mode = enable; }
306 void setDither(bool enable) { config_.dither = enable; }
308 void setDitherSeed(uint64_t seed) { config_.dither_seed = seed; }
310 void setDitherStrength(float strength) { config_.dither_strength = strength; }
311
312 TInput getErrorBound() const { return static_cast<TInput>(config_.error_bound); }
313 int getQuantRadius() const { return config_.quant_radius; }
314 ErrorBoundMode getErrorBoundMode() const { return config_.eb_mode; }
315 float getValueBase() const { return config_.precomputed_value_base; }
316 float getOutlierCapacity() const { return config_.outlier_capacity; }
317 bool getZigzagCodes() const { return config_.zigzag_codes; }
318 float getOutlierThreshold() const { return config_.outlier_threshold; }
319 bool getInplaceOutliers() const { return config_.inplace_outliers; }
320 bool getLinearMode() const { return config_.linear_mode; }
321 bool getDither() const { return config_.dither; }
322 uint64_t getDitherSeed() const { return config_.dither_seed; }
323 float getDitherStrength() const { return config_.dither_strength; }
324
325private:
326 Config config_;
327 Config saved_config_;
328 std::array<size_t, 3> dims_ = {0, 1, 1};
329 std::vector<size_t> actual_output_sizes_;
330 std::vector<size_t> saved_actual_output_sizes_;
331 size_t num_elements_ = 0;
332 size_t saved_num_elements_ = 0;
333 uint32_t actual_outlier_count_= 0;
334 uint32_t saved_actual_outlier_count_ = 0;
335 bool is_inverse_ = false;
336 TInput computed_abs_eb_ = static_cast<TInput>(1e-4);
337 TInput saved_computed_abs_eb_ = static_cast<TInput>(1e-4);
338 TInput computed_value_base_ = static_cast<TInput>(0);
339 TInput saved_computed_value_base_ = static_cast<TInput>(0);
347 uint32_t* d_outlier_count_scratch_ = nullptr;
350 MemoryPool* persistent_pool_ = nullptr;
355 std::weak_ptr<const void> persistent_pool_alive_;
356
357
361 void initOutlierCountScratch(MemoryPool* pool);
362
363 bool isInplaceMode() const {
364 return config_.inplace_outliers
365 && config_.eb_mode != ErrorBoundMode::REL;
366 }
367
368 bool isLinearMode() const { return config_.linear_mode; }
369
372 static DataType signedOf(DataType d) {
373 switch (d) {
374 case DataType::UINT8: return DataType::INT8;
375 case DataType::UINT16: return DataType::INT16;
376 case DataType::UINT32: return DataType::INT32;
377 default: return d;
378 }
379 }
380
381 DataType getInputDataType() const {
382 if (std::is_same<TInput, float>::value) return DataType::FLOAT32;
383 if (std::is_same<TInput, double>::value) return DataType::FLOAT64;
384 return DataType::FLOAT32;
385 }
386 DataType getCodeDataType() const {
387 if (std::is_same<TCode, uint8_t>::value) return DataType::UINT8;
388 if (std::is_same<TCode, uint16_t>::value) return DataType::UINT16;
389 if (std::is_same<TCode, uint32_t>::value) return DataType::UINT32;
390 return DataType::UINT16;
391 }
392 size_t getMaxOutlierCount(size_t n) const {
393 return static_cast<size_t>(std::ceil(n * config_.outlier_capacity));
394 }
395};
396
397extern template class QuantizerStage<float, uint16_t>;
398extern template class QuantizerStage<float, uint32_t>;
399extern template class QuantizerStage<double, uint16_t>;
400extern template class QuantizerStage<double, uint32_t>;
401
402} // namespace fz
Definition mempool.h:82
Definition quantizer.h:129
void setDither(bool enable)
Definition quantizer.h:306
void saveState() override
Definition quantizer.h:274
uint8_t getInputDataType(size_t) const override
Definition quantizer.h:266
uint8_t getOutputDataType(size_t output_index) const override
Definition quantizer.h:252
void setInplaceOutliers(bool enable)
ABS/NOA: encode outliers in-place (raw float bits in codes array; no scatter buffers).
Definition quantizer.h:301
std::vector< std::string > getOutputNames() const override
Definition quantizer.h:217
void setInverse(bool inverse) override
Definition quantizer.h:239
void deserializeHeader(const uint8_t *buf, size_t size) override
size_t estimateDeviceFootprintBytes(size_t) const override
Definition quantizer.h:202
void setDims(const std::array< size_t, 3 > &dims) override
Definition quantizer.h:246
void setOutlierThreshold(float t)
ABS/NOA: |x| >= threshold → lossless outlier regardless of bin (LC reference parameter).
Definition quantizer.h:299
void onFinalize(size_t estimated_inlen, MemoryPool *pool) override
void setDitherSeed(uint64_t seed)
Seed for the deterministic per-element dither offset (see Config::dither_seed).
Definition quantizer.h:308
std::string getName() const override
Definition quantizer.h:206
size_t serializeHeader(size_t output_index, uint8_t *buf, size_t max_size) const override
uint16_t getStageTypeId() const override
Definition quantizer.h:248
std::unordered_map< std::string, size_t > getActualOutputSizesByName() const override
Definition quantizer.h:227
void setDitherStrength(float strength)
Dither offset amplitude as a fraction of abs_eb, in (0,1]; see Config::dither_strength.
Definition quantizer.h:310
std::vector< size_t > estimateOutputSizes(const std::vector< size_t > &input_sizes) const override
void execute(fz::stream_t stream, MemoryPool *pool, const std::vector< void * > &inputs, const std::vector< void * > &outputs, const std::vector< size_t > &sizes) override
size_t getMaxHeaderSize(size_t) const override
Definition quantizer.h:271
void setLinearMode(bool enable)
ABS/NOA: linear / no-outlier mode (cuSZp-style signed codes; see Config::linear_mode).
Definition quantizer.h:303
size_t getActualOutputSize(int index) const override
Definition quantizer.h:234
void postStreamSync(fz::stream_t stream) override
Definition stage.h:30
FZM binary file format definitions — structs, enums, and helpers.
Fused Lorenzo predictor and quantizer stage.
Definition algorithms.h:48
ErrorBoundMode
Definition lorenzo_quant.h:40
@ ABS
Absolute error bound.
@ REL
Exact per-element point-wise relative bound (QuantizerStage only).
constexpr size_t FZM_STAGE_CONFIG_SIZE
Per-stage serialized config slot (bytes)
Definition fzm_format.h:65
DataType
Element data type identifiers used in buffer and stage descriptors.
Definition fzm_format.h:117
Base class interface for all compression stages.
Definition quantizer.h:26
uint8_t inplace_outliers
1 if outliers are encoded in-place in the codes array.
Definition quantizer.h:41
double abs_error_bound_f64
Definition quantizer.h:53
uint8_t _pad[5]
Alignment padding (dither_seed needs 8-byte alignment) — must be zero.
Definition quantizer.h:44
uint32_t _pad2
Definition quantizer.h:47
uint8_t linear_mode
1 if linear/no-outlier mode (signed codes, no outlier ports).
Definition quantizer.h:42
uint8_t eb_mode
ErrorBoundMode cast to uint8_t.
Definition quantizer.h:38
uint64_t dither_seed
Deterministic per-element dither seed; meaningful only when dither.
Definition quantizer.h:45
uint32_t outlier_count
Actual number of outliers.
Definition quantizer.h:35
DataType code_type
Quantization code type (1B).
Definition quantizer.h:37
uint8_t zigzag_codes
1 if ABS/NOA codes are zigzag-encoded.
Definition quantizer.h:39
uint32_t num_elements
Total element count.
Definition quantizer.h:34
double value_base_f64
Full-precision value_base; 0 in pre-2026-08-07 headers.
Definition quantizer.h:54
uint32_t quant_radius
Quantization radius.
Definition quantizer.h:33
float user_error_bound
Definition quantizer.h:30
DataType input_type
Original input type (1B).
Definition quantizer.h:36
float abs_error_bound
Absolute EB after mode conversion (0 for REL).
Definition quantizer.h:29
float dither_strength
Dither offset amplitude as a fraction of abs_eb, in (0,1]; meaningful only when dither.
Definition quantizer.h:46
float outlier_threshold
ABS/NOA: |x| >= threshold → forced outlier (inf = disabled).
Definition quantizer.h:40
uint8_t dither
1 if "_R"-style dithered reconstruction is enabled (LC QUANT_*_R).
Definition quantizer.h:43
float value_base
value_range (NOA); 0 for ABS/REL.
Definition quantizer.h:32
Definition quantizer.h:132
float outlier_threshold
ABS/NOA: |x| >= threshold → lossless outlier (LC reference threshold). Default: ∞.
Definition quantizer.h:143
bool dither
Definition quantizer.h:164
float outlier_capacity
Fraction of input size reserved for outliers.
Definition quantizer.h:135
bool zigzag_codes
Definition quantizer.h:141
uint64_t dither_seed
Definition quantizer.h:167
float precomputed_value_base
Pre-computed value_base > 0 to skip the NOA data scan; 0 = auto.
Definition quantizer.h:138
bool inplace_outliers
Definition quantizer.h:147
int quant_radius
Quantization radius.
Definition quantizer.h:134
bool linear_mode
Definition quantizer.h:154
float error_bound
Error bound (interpretation set by eb_mode).
Definition quantizer.h:133
float dither_strength
Definition quantizer.h:174
Backend-neutral GPU type aliases.