Skip to content

Commit d47f8bf

Browse files
committed
Update default QAT recipe path to export in eval mode.
This change aligns the QuantizeStage with the recommended workflow described in https://github.com/pytorch/ao/blob/v0.18.0/torchao/quantization/pt2e/quantize_pt2e.py#L172-L184.
1 parent 20fe4d6 commit d47f8bf

2 files changed

Lines changed: 13 additions & 12 deletions

File tree

‎export/stages.py‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -598,10 +598,10 @@ def run(self, artifact: PipelineArtifact) -> None:
598598
{0: batch} if isinstance(t, torch.Tensor) else None for t in inputs
599599
)
600600

601-
# QAT requires the model to be in training mode at capture time so
602-
# that batch_norm and dropout decompose with training-mode semantics.
603-
if recipe.is_qat:
604-
model.train()
601+
# Export in eval mode for both PTQ and QAT. The torchao-recommended QAT workflow exports the model in eval
602+
# mode and calls model.train() only inside the train_fn, after prepare_qat_pt2e.
603+
# (see https://github.com/pytorch/ao/blob/v0.18.0/torchao/quantization/pt2e/quantize_pt2e.py#L172-L184)
604+
model.eval()
605605

606606
with torch.no_grad():
607607
for hook in self._pre_trace_hooks or []:

‎export/tests/test_export_stages.py‎

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -853,7 +853,7 @@ def test_run_qat_missing_train_fn_raises(self, mock_torch_export: Mock) -> None:
853853
@patch("executorch.export.stages.prepare_qat_pt2e")
854854
@patch("executorch.export.stages.ComposableQuantizer")
855855
@patch("torch.export.export")
856-
def test_run_qat_model_put_in_train_mode_before_export(
856+
def test_run_qat_model_put_in_eval_mode_before_export(
857857
self,
858858
mock_torch_export: Mock,
859859
mock_composable_quantizer: Mock,
@@ -863,8 +863,9 @@ def test_run_qat_model_put_in_train_mode_before_export(
863863
mock_move_to_eval: Mock,
864864
mock_allow_train_eval: Mock,
865865
) -> None:
866-
"""QAT: model.train() must be called before torch.export.export so that
867-
batch_norm and dropout decompose with training-mode semantics."""
866+
"""QAT: model.eval() is called before torch.export.export, following the
867+
torchao-recommended QAT workflow (torchao/quantization/pt2e/quantize_pt2e.py).
868+
model.train() is called only inside train_fn, after prepare_qat_pt2e."""
868869
mock_quantizer = self.create_dummy_quantizer()
869870
mock_recipe = Mock(spec=QuantizationRecipe)
870871
mock_recipe.quantizers = [mock_quantizer]
@@ -876,9 +877,9 @@ def test_run_qat_model_put_in_train_mode_before_export(
876877
mock_recipe.pre_convert_passes = None
877878
mock_recipe.post_convert_passes = None
878879

879-
# Start model in eval mode; the stage must switch it to train.
880-
self.model.eval()
881-
self.assertFalse(self.model.training)
880+
# Start model in train mode; the stage must switch it to eval.
881+
self.model.train()
882+
self.assertTrue(self.model.training)
882883

883884
training_at_export_time = []
884885

@@ -896,8 +897,8 @@ def capture_training_flag(model, *args, **kwargs):
896897
stage = QuantizeStage(mock_recipe)
897898
stage.run(PipelineArtifact(data=self.models_dict, context=self.context))
898899

899-
# The model must have been in training mode when export was called.
900-
self.assertEqual(training_at_export_time, [True])
900+
# The model must have been in eval mode when export was called.
901+
self.assertEqual(training_at_export_time, [False])
901902

902903
@patch("executorch.export.stages.move_exported_model_to_eval")
903904
@patch("executorch.export.stages.convert_pt2e")

0 commit comments

Comments
 (0)