Skip to content

Commit 6caa479

Browse files
aki916fFKKimura
andauthored
Refactoring: quantization progress logs with ETA (#15)
* refactoring : QuantizationProgressTracker * update CHANGELOG.md --------- Co-authored-by: FKKimura <50981196+FKKimura@users.noreply.github.com>
1 parent 77da402 commit 6caa479

7 files changed

Lines changed: 42 additions & 46 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
# Change log
22

3-
## [v1.1.1] 2026-05-07
3+
## [v1.1.1] 2026-05-19
44

5-
## Bug Fixes
5+
### New Feature: Quantization progress logging
6+
7+
- Added `QuantizationProgressTracker` (`onecomp/utils/quantization_progress.py`) that emits a single `[progress]` INFO line per completed step with done/total, percentage, elapsed time, and a linear ETA estimate; supports an optional `thread_safe=True` mode for multi-GPU quantization
8+
- Added `report_progress: bool = True` flag to `Runner.__init__` (`onecomp/runner.py`) and to the underlying entry points `run_chunked_quantization` (`onecomp/runner_methods/chunked_quantization.py`), `run_multi_gpu_quantization` / `run_quantization_phase` (`onecomp/runner_methods/multi_gpu_quantization.py`), `run_quantize_with_qep` (`onecomp/qep/_quantize_with_qep.py`), and `run_quantize_with_qep_arch` (`onecomp/qep/_quantize_with_qep_arch.py`) so long quantization runs (calibration, chunked, multi-GPU, QEP) report progress by default; pass `report_progress=False` for quiet runs
9+
10+
### Bug Fixes
611

712
- Raise a clear error when ``Runner`` is configured with ``qep=True`` and a quantizer that does not support QEP (currently `JointQ`). Previously the run failed deep inside `quantize_with_qep` / `adjust_weight` with a confusing low-level error. `Runner.check()` now reports e.g. "Quantizer 'JointQ' (or one of its candidate quantizers) does not support QEP (Quantization Error Propagation). Set qep=False, or use a QEP-compatible quantizer (e.g., GPTQ, DBF, AutoBitQuantizer with QEP-compatible candidates)." Implementation: added `flag_qep_supported` (default `True`) on `Quantizer`, set to `False` on `JointQ`, and propagated via `AutoBitQuantizer._sync_flags` (only `True` when *all* candidate quantizers support QEP).
813

9-
## Tests
14+
### Tests
1015

1116
- Added `tests/onecomp/test_runner_check.py` covering the new `qep=True` validation path: JointQ + qep=True raises a clear `ValueError`, while JointQ + qep=False and GPTQ + qep=True both pass `Runner.check()`.
1217

18+
### New Contributors
19+
20+
- [@sotanengel](https://github.com/sotanengel) made their first contribution in [#13](https://github.com/FujitsuResearch/OneCompression/pull/13)
21+
1322
## [v1.1.0] 2026-04-16
1423

1524
### Gemma 3 / Gemma 4 & VLM Support

onecomp/qep/_quantize_with_qep.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from onecomp.qep._qep_config import QEPConfig
2828
from onecomp.quantizer._quantizer import Quantizer
2929
from onecomp.utils import capture_input_activations
30+
from onecomp.utils.quantization_progress import QuantizationProgressTracker
3031

3132
logger = getLogger(__name__)
3233

@@ -37,7 +38,7 @@ def run_quantize_with_qep(
3738
qep_config: QEPConfig,
3839
calibration_config: CalibrationConfig,
3940
*,
40-
quantization_progress: bool = True,
41+
report_progress: bool = True,
4142
):
4243
"""Run quantization with Quantization Error Propagation (QEP).
4344
@@ -53,7 +54,7 @@ def run_quantize_with_qep(
5354
qep_config (QEPConfig): Configuration for QEP
5455
(percdamp, perccorr, exclude_layer_keywords).
5556
calibration_config (CalibrationConfig): Calibration parameters.
56-
quantization_progress (bool): When True, log ``[progress]`` with ETA per layer.
57+
report_progress (bool): When True, log ``[progress]`` with ETA per layer.
5758
5859
"""
5960
model = model_config.load_model()
@@ -84,10 +85,7 @@ def run_quantize_with_qep(
8485
logger.info("Quantizing the model using %s", quantizer.name)
8586

8687
progress = None
87-
if quantization_progress:
88-
# pylint: disable-next=import-outside-toplevel
89-
from onecomp.utils.quantization_progress import QuantizationProgressTracker
90-
88+
if report_progress:
9189
progress = QuantizationProgressTracker(
9290
logger,
9391
len(quantizer.module_to_name),

onecomp/qep/_quantize_with_qep_arch.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
move_kwargs_to_device,
3434
expand_kwargs_batch,
3535
)
36+
from onecomp.utils.quantization_progress import QuantizationProgressTracker
3637

3738
logger = getLogger(__name__)
3839

@@ -263,7 +264,7 @@ def run_quantize_with_qep_arch(
263264
qep_config: QEPConfig,
264265
calibration_config: CalibrationConfig,
265266
*,
266-
quantization_progress: bool = True,
267+
report_progress: bool = True,
267268
):
268269
"""Run architecture-aware quantization with QEP.
269270
@@ -280,7 +281,7 @@ def run_quantize_with_qep_arch(
280281
qep_config (QEPConfig): Configuration for QEP
281282
(percdamp, perccorr, exclude_layer_keywords).
282283
calibration_config (CalibrationConfig): Calibration parameters.
283-
quantization_progress (bool): When True, log ``[progress]`` with ETA per target layer.
284+
report_progress (bool): When True, log ``[progress]`` with ETA per target layer.
284285
285286
"""
286287

@@ -321,10 +322,7 @@ def run_quantize_with_qep_arch(
321322
}
322323

323324
progress = None
324-
if quantization_progress:
325-
# pylint: disable-next=import-outside-toplevel
326-
from onecomp.utils.quantization_progress import QuantizationProgressTracker
327-
325+
if report_progress:
328326
progress = QuantizationProgressTracker(
329327
logger,
330328
len(remaining_targets),

onecomp/runner.py

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from .quantizer.autobit import AutoBitQuantizer
2929
from .utils import calculate_accuracy as calc_accuracy
3030
from .utils import calculate_perplexity as calc_perplexity
31+
from .utils.quantization_progress import QuantizationProgressTracker
3132
from .log import setup_logger
3233

3334

@@ -86,7 +87,7 @@ def __init__(
8687
multi_gpu=False,
8788
gpu_ids=None,
8889
post_processes=None,
89-
quantization_progress=True,
90+
report_progress=True,
9091
):
9192
"""__init__ method
9293
@@ -131,7 +132,7 @@ def __init__(
131132
a quantized model on CPU (built via
132133
``create_quantized_model``) and may modify it in-place.
133134
Processes are executed in order. Default is None.
134-
quantization_progress (bool):
135+
report_progress (bool):
135136
When ``True`` (default), emit ``[progress]`` log lines with
136137
completed steps, elapsed time, and a linear ETA estimate
137138
during long quantization (calibration, chunked, multi-GPU,
@@ -221,7 +222,7 @@ def __init__(
221222
self.lpcd_config = None
222223
if lpcd:
223224
self.lpcd_config = lpcd_config if lpcd_config is not None else LPCDConfig()
224-
self.quantization_progress = quantization_progress
225+
self.report_progress = report_progress
225226

226227
def check(self):
227228
"""Check the settings
@@ -602,10 +603,7 @@ def quantize_with_calibration(self):
602603
# Register hooks to all linear layers
603604
handles = []
604605
progress = None
605-
if self.quantization_progress:
606-
# pylint: disable-next=import-outside-toplevel
607-
from .utils.quantization_progress import QuantizationProgressTracker
608-
606+
if self.report_progress:
609607
progress = QuantizationProgressTracker(
610608
logger,
611609
len(self.quantizer.module_to_name),
@@ -664,7 +662,7 @@ def quantize_with_calibration_chunked(self):
664662
model_config=self.model_config,
665663
quantizers=self.quantizers if self.quantizers is not None else [self.quantizer],
666664
calibration_config=self.calibration_config,
667-
quantization_progress=self.quantization_progress,
665+
report_progress=self.report_progress,
668666
)
669667

670668
def quantize_with_calibration_on_multi_gpu(self):
@@ -693,7 +691,7 @@ def quantize_with_calibration_on_multi_gpu(self):
693691
quantizer=self.quantizer,
694692
calibration_config=self.calibration_config,
695693
gpu_ids=self.gpu_ids,
696-
quantization_progress=self.quantization_progress,
694+
report_progress=self.report_progress,
697695
)
698696

699697
# Store results in quantizer.results
@@ -721,10 +719,7 @@ def quantize_without_calibration(self):
721719
self.quantizer.name,
722720
)
723721
progress = None
724-
if self.quantization_progress:
725-
# pylint: disable-next=import-outside-toplevel
726-
from .utils.quantization_progress import QuantizationProgressTracker
727-
722+
if self.report_progress:
728723
progress = QuantizationProgressTracker(
729724
logger,
730725
len(self.quantizer.module_to_name),
@@ -754,7 +749,7 @@ def quantize_with_qep(self):
754749
quantizer=self.quantizer,
755750
qep_config=self.qep_config,
756751
calibration_config=self.calibration_config,
757-
quantization_progress=self.quantization_progress,
752+
report_progress=self.report_progress,
758753
)
759754

760755
if self.qep_config.general:

onecomp/runner_methods/chunked_quantization.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from onecomp.calibration import CalibrationConfig, prepare_calibration_dataset
3535
from onecomp.model_config import ModelConfig
3636
from onecomp.quantizer._quantizer import Quantizer, QuantizationResult
37+
from onecomp.utils.quantization_progress import QuantizationProgressTracker
3738

3839
logger = getLogger(__name__)
3940

@@ -48,7 +49,7 @@ def run_chunked_quantization(
4849
quantizers: List[Quantizer],
4950
calibration_config: CalibrationConfig,
5051
*,
51-
quantization_progress: bool = True,
52+
report_progress: bool = True,
5253
):
5354
"""Run quantization for large-scale calibration data.
5455
@@ -61,7 +62,7 @@ def run_chunked_quantization(
6162
quantizers (list[Quantizer]): List of quantizers. Each quantizer must have
6263
flag_hessian=True or flag_xtx=True.
6364
calibration_config (CalibrationConfig): Calibration parameters.
64-
quantization_progress (bool): When True, log ``[progress]`` lines with ETA
65+
report_progress (bool): When True, log ``[progress]`` lines with ETA
6566
for X^T X chunks and per-layer quantization.
6667
6768
Note:
@@ -120,10 +121,7 @@ def run_chunked_quantization(
120121

121122
num_groups = (len(all_layers) + num_layers_per_group - 1) // num_layers_per_group
122123
layer_progress = None
123-
if quantization_progress:
124-
# pylint: disable-next=import-outside-toplevel
125-
from onecomp.utils.quantization_progress import QuantizationProgressTracker
126-
124+
if report_progress:
127125
layer_progress = QuantizationProgressTracker(
128126
logger,
129127
len(all_layers) * len(quantizers),
@@ -145,7 +143,7 @@ def run_chunked_quantization(
145143
)
146144

147145
chunk_progress = None
148-
if quantization_progress:
146+
if report_progress:
149147
num_chunks = (total_samples + calibration_batch_size - 1) // calibration_batch_size
150148
chunk_progress = QuantizationProgressTracker(
151149
logger,

onecomp/runner_methods/multi_gpu_quantization.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from onecomp.calibration import CalibrationConfig
2424
from onecomp.quantizer._quantizer import QuantizationResult
2525
from onecomp.utils import check_activations
26+
from onecomp.utils.quantization_progress import QuantizationProgressTracker
2627

2728
logger = getLogger(__name__)
2829

@@ -178,7 +179,7 @@ def run_quantization_phase(
178179
quantizer,
179180
gpu_ids: List[int],
180181
*,
181-
quantization_progress: bool = True,
182+
report_progress: bool = True,
182183
) -> Dict[str, Dict]:
183184
"""Phase 2: Parallel quantization using multiple threads.
184185
@@ -196,10 +197,7 @@ def run_quantization_phase(
196197
start_time = time.time()
197198

198199
progress = None
199-
if quantization_progress:
200-
# pylint: disable-next=import-outside-toplevel
201-
from onecomp.utils.quantization_progress import QuantizationProgressTracker
202-
200+
if report_progress:
203201
progress = QuantizationProgressTracker(
204202
logger,
205203
len(layer_names),
@@ -359,7 +357,7 @@ def run_multi_gpu_quantization(
359357
calibration_config: CalibrationConfig,
360358
gpu_ids: Optional[List[int]] = None,
361359
*,
362-
quantization_progress: bool = True,
360+
report_progress: bool = True,
363361
) -> Dict[str, Any]:
364362
"""Main entry point for multi-GPU quantization.
365363
@@ -368,7 +366,7 @@ def run_multi_gpu_quantization(
368366
quantizer: Quantizer instance.
369367
calibration_config (CalibrationConfig): Calibration parameters.
370368
gpu_ids: List of GPU IDs to use (all GPUs if None).
371-
quantization_progress: When True, log ``[progress]`` with ETA per completed layer.
369+
report_progress: When True, log ``[progress]`` with ETA per completed layer.
372370
373371
Returns:
374372
Dict containing "results" with quantization results for each layer
@@ -394,7 +392,7 @@ def run_multi_gpu_quantization(
394392
layer_names=capture_result["layer_names"],
395393
quantizer=quantizer,
396394
gpu_ids=gpu_ids,
397-
quantization_progress=quantization_progress,
395+
report_progress=report_progress,
398396
)
399397

400398
total_elapsed = time.time() - total_start

onecomp/utils/quantization_progress.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,11 @@ def _step_complete_unlocked(self, detail: Optional[str]) -> None:
6868
done = min(self._done, self._total)
6969
elapsed = now - self._start
7070

71-
if done < self._total and done > 0:
71+
if done < self._total:
7272
eta_sec = (elapsed / done) * (self._total - done)
7373
eta_str = _format_duration(eta_sec)
7474
else:
75-
eta_str = "unknown" if done == 0 else "0s"
75+
eta_str = "0s"
7676

7777
pct = 100.0 * done / self._total
7878
suffix = f" ({detail})" if detail else ""

0 commit comments

Comments
 (0)