Spaces:
Sleeping
Sleeping
| """ | |
| backend/src/models/onnx_export.py | |
| Converts the trained PyTorch Wav2Vec2 model to an optimized ONNX format, | |
| and performs dynamic INT8 quantization for low-latency production execution. | |
| """ | |
| import torch | |
| import logging | |
| from pathlib import Path | |
| from transformers import Wav2Vec2ForSequenceClassification | |
| from onnxruntime.quantization import quantize_dynamic, QuantType | |
| from src.models.config import CHECKPOINT_DIR, OPTIMIZED_DIR, MODEL_NAME, NUM_LABELS | |
| logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") | |
| logger = logging.getLogger(__name__) | |
| def export_and_quantize(): | |
| hf_model_path = CHECKPOINT_DIR / "hf_model" | |
| if not hf_model_path.exists(): | |
| logger.error(f"Fine-tuned HuggingFace model missing at {hf_model_path}. Train the model first!") | |
| return | |
| logger.info(f"Loading fine-tuned model from {hf_model_path} for ONNX export...") | |
| model = Wav2Vec2ForSequenceClassification.from_pretrained(hf_model_path) | |
| model.eval() | |
| # Define paths | |
| onnx_path = OPTIMIZED_DIR / "model.onnx" | |
| quant_path = OPTIMIZED_DIR / "model_quantized.onnx" | |
| # 1. Export to ONNX | |
| logger.info("Exporting model to ONNX...") | |
| # Dummy input: batch_size=1, audio_length = 3 seconds (3 * 16000 = 48000 samples) | |
| dummy_input = torch.randn(1, 48000) | |
| # Export with dynamic axes for input sequence length and batch size | |
| torch.onnx.export( | |
| model, | |
| dummy_input, | |
| str(onnx_path), | |
| input_names=["input_values"], | |
| output_names=["logits"], | |
| dynamic_axes={ | |
| "input_values": {0: "batch_size", 1: "sequence_length"}, | |
| "logits": {0: "batch_size"} | |
| }, | |
| opset_version=14, | |
| do_constant_folding=True | |
| ) | |
| logger.info(f"Base ONNX model successfully saved to {onnx_path}") | |
| # 2. INT8 Dynamic Quantization | |
| logger.info("Quantizing ONNX model to INT8...") | |
| try: | |
| quantize_dynamic( | |
| model_input=str(onnx_path), | |
| model_output=str(quant_path), | |
| weight_type=QuantType.QUInt8 | |
| ) | |
| logger.info(f"Quantized INT8 ONNX model successfully saved to {quant_path}") | |
| except Exception as e: | |
| logger.warning(f"ONNX Quantization failed due to shape inference constraints: {str(e)}") | |
| logger.info("Falling back to unquantized base ONNX model for production execution...") | |
| import shutil | |
| shutil.copy(onnx_path, quant_path) | |
| logger.info(f"Base ONNX model copied to {quant_path} successfully.") | |
| if __name__ == "__main__": | |
| export_and_quantize() | |