151 lines
5.5 KiB
Python
151 lines
5.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Export locally fine-tuned Hugging Face models to ONNX format for production inference"""
|
|
|
|
import os
|
|
from pathlib import Path
|
|
|
|
import torch
|
|
from optimum.onnxruntime import ORTModelForSequenceClassification
|
|
from transformers import AutoTokenizer, AutoConfig
|
|
|
|
# Local fine-tuned model paths
|
|
MODELS = {
|
|
"finbert": {
|
|
"local_path": "/mnt/dolphinng5_predict/sentiment_engine/models/finbert-crypto-sentiment",
|
|
"output_dir": "/mnt/dolphinng5_predict/sentiment_engine/models/onnx/finbert",
|
|
"labels": ["Bearish", "Bullish", "Neutral"],
|
|
"id2label": {0: "Bearish", 1: "Bullish", 2: "Neutral"},
|
|
},
|
|
"bert-base-event": {
|
|
"local_path": "/mnt/dolphinng5_predict/sentiment_engine/models/bert-crypto-events",
|
|
"output_dir": "/mnt/dolphinng5_predict/sentiment_engine/models/onnx/bert-base-event",
|
|
"labels": ["listing", "delisting", "hack", "regulatory", "governance",
|
|
"upgrade", "partnership", "earnings", "macro", "liquidation", "whale", "manipulation"],
|
|
"id2label": {i: l for i, l in enumerate([
|
|
"listing", "delisting", "hack", "regulatory", "governance",
|
|
"upgrade", "partnership", "earnings", "macro", "liquidation", "whale", "manipulation"
|
|
])},
|
|
},
|
|
"distilroberta-emotion": {
|
|
"local_path": "/mnt/dolphinng5_predict/sentiment_engine/models/distilroberta-crypto-emotion",
|
|
"output_dir": "/mnt/dolphinng5_predict/sentiment_engine/models/onnx/distilroberta-emotion",
|
|
"labels": ["joy", "fear", "anger", "greed", "sadness", "neutral"],
|
|
"id2label": {i: l for i, l in enumerate(["joy", "fear", "anger", "greed", "sadness", "neutral"])},
|
|
},
|
|
"minilm-l6-v2": {
|
|
"local_path": "/mnt/dolphinng5_predict/sentiment_engine/models/finbert-crypto-sentiment", # Use finbert tokenizer
|
|
"output_dir": "/mnt/dolphinng5_predict/sentiment_engine/models/onnx/minilm-l6-v2",
|
|
"labels": None,
|
|
"id2label": None,
|
|
},
|
|
}
|
|
|
|
def export_classification_model(model_key: str) -> None:
|
|
"""Export a local classification model to ONNX"""
|
|
config = MODELS[model_key]
|
|
local_path = config["local_path"]
|
|
output_dir = Path(config["output_dir"])
|
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
print(f"Exporting {model_key} from {local_path} to {output_dir}...")
|
|
|
|
# Load model config to check problem type
|
|
model_config = AutoConfig.from_pretrained(local_path)
|
|
is_multilabel = getattr(model_config, "problem_type", None) == "multi_label_classification"
|
|
|
|
print(f" Problem type: {getattr(model_config, 'problem_type', 'single_label')}")
|
|
print(f" Labels: {config['labels']}")
|
|
|
|
# Load model and export using optimum
|
|
model = ORTModelForSequenceClassification.from_pretrained(
|
|
local_path,
|
|
export=True,
|
|
)
|
|
model.save_pretrained(output_dir)
|
|
|
|
# Save tokenizer
|
|
tokenizer = AutoTokenizer.from_pretrained(local_path)
|
|
tokenizer.save_pretrained(output_dir)
|
|
|
|
# Save label mapping
|
|
import json
|
|
if config["labels"]:
|
|
with open(output_dir / "label_map.json", "w") as f:
|
|
json.dump({i: label for i, label in enumerate(config["labels"])}, f)
|
|
with open(output_dir / "id2label.json", "w") as f:
|
|
json.dump(config["id2label"], f)
|
|
|
|
print(f" Done: {model_key}")
|
|
|
|
def export_feature_extraction_model(model_key: str) -> None:
|
|
"""Export a feature extraction model to ONNX"""
|
|
config = MODELS[model_key]
|
|
local_path = config["local_path"]
|
|
output_dir = Path(config["output_dir"])
|
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
print(f"Exporting {model_key} (feature extraction) from {local_path} to {output_dir}...")
|
|
|
|
from transformers import AutoModel
|
|
|
|
# For sentence transformers / feature extraction
|
|
hf_model = AutoModel.from_pretrained(local_path)
|
|
hf_model.eval()
|
|
|
|
# Create dummy input
|
|
dummy_input = {
|
|
"input_ids": torch.ones(1, 128, dtype=torch.long),
|
|
"attention_mask": torch.ones(1, 128, dtype=torch.long),
|
|
}
|
|
|
|
# Export to ONNX
|
|
torch.onnx.export(
|
|
hf_model,
|
|
(dummy_input["input_ids"], dummy_input["attention_mask"]),
|
|
output_dir / "model.onnx",
|
|
input_names=["input_ids", "attention_mask"],
|
|
output_names=["last_hidden_state", "pooler_output"],
|
|
dynamic_axes={
|
|
"input_ids": {0: "batch", 1: "sequence"},
|
|
"attention_mask": {0: "batch", 1: "sequence"},
|
|
"last_hidden_state": {0: "batch", 1: "sequence"},
|
|
},
|
|
opset_version=14,
|
|
)
|
|
print(f" Exported feature extraction model")
|
|
|
|
# Save tokenizer
|
|
tokenizer = AutoTokenizer.from_pretrained(local_path)
|
|
tokenizer.save_pretrained(output_dir)
|
|
|
|
print(f" Done: {model_key}")
|
|
|
|
def main():
|
|
print("="*60)
|
|
print("EXPORTING FINE-TUNED MODELS TO ONNX")
|
|
print("="*60)
|
|
|
|
# Export classification models
|
|
for model_key in ["finbert", "bert-base-event", "distilroberta-emotion"]:
|
|
try:
|
|
export_classification_model(model_key)
|
|
except Exception as e:
|
|
print(f" ERROR exporting {model_key}: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
|
|
# Export feature extraction model (MiniLM)
|
|
try:
|
|
export_feature_extraction_model("minilm-l6-v2")
|
|
except Exception as e:
|
|
print(f" ERROR exporting minilm-l6-v2: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
|
|
print("\n" + "="*60)
|
|
print("ALL EXPORTS COMPLETE!")
|
|
print("="*60)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|