Alpaxa FinBERT-Tone 7-Class (Custom Head)

Repo: MasSolutions/Alpaxa-FinBERT-Tone-7class
Base encoder: ProsusAI/finbert
Frozen sentiment head: yiyanghkust/finbert-tone
Task head: Custom 7-way classifier (Financial/Earnings, Operations/Business, Accidents/Safety, Labor/Layoffs, Legal/Regulatory, Fraud/Misconduct, Other/External)


πŸ“Š Test Results (n = 688)

Metric Score
Accuracy 0.846
F1-macro 0.681

Per-Class Performance

Class Precision Recall F1 Support
Financial/Earnings 0.809 0.885 0.845 148
Operations/Business 0.805 0.899 0.849 197
Accidents/Safety 0.333 0.200 0.250 5
Labor/Layoffs 0.909 0.870 0.889 23
Legal/Regulatory 0.875 0.875 0.875 56
Fraud/Misconduct 0.333 0.143 0.200 7
Other/External 0.914 0.806 0.857 252

πŸš€ Usage

import os, json, sys, importlib.util, torch
from typing import Dict, List
from huggingface_hub import hf_hub_download
from transformers import AutoTokenizer

REPO = "MasSolutions/Alpaxa-FinBERT-Tone-7class"

TOPIC_LABELS: List[str] = [
    "Financial/Earnings",   # 0
    "Operations/Business",  # 1
    "Accidents/Safety",     # 2
    "Labor/Layoffs",        # 3
    "Legal/Regulatory",     # 4
    "Fraud/Misconduct",     # 5
    "Other/External",       # 6
]
SENTIMENT_LABELS = ["Neutral", "Positive", "Negative"]

def sanitize_cfg(cfg: Dict) -> Dict:
    """Keep only keys accepted by the model constructor."""
    allowed = {
        "encoder_ckpt",
        "sentiment_ckpt",
        "num_labels",
        "use_mean_pool",
        "use_focal",
        "focal_gamma",
    }
    return {k: v for k, v in cfg.items() if k in allowed}

# 1) Download the modeling file and import it dynamically
model_py = hf_hub_download(REPO, "modeling_multi_head_finbert.py")
spec = importlib.util.spec_from_file_location("modeling_multi_head_finbert", model_py)
mod  = importlib.util.module_from_spec(spec)
sys.modules["modeling_multi_head_finbert"] = mod
spec.loader.exec_module(mod)

MultiHeadFinBERT = mod.MultiHeadFinBERT

# 2) Load config / weights / tokenizer
cfg_path   = hf_hub_download(REPO, "config.json")
state_path = None
try:
    state_path = hf_hub_download(REPO, "model.safetensors")
    use_safetensors = True
except Exception:
    state_path = hf_hub_download(REPO, "model_state.pth")
    use_safetensors = False

with open(cfg_path) as f:
    cfg_raw = json.load(f)
cfg = sanitize_cfg(cfg_raw)

tok = AutoTokenizer.from_pretrained(REPO)

# 3) Build and load model
model = MultiHeadFinBERT(**cfg)
if use_safetensors:
    from safetensors.torch import load_file as load_safetensors
    state = load_safetensors(state_path, device="cpu")
else:
    state = torch.load(state_path, map_location="cpu")
model.load_state_dict(state, strict=True)
model.eval()

# 4) Inference
texts = ["Delta flight crashed. 198 dead 2 missing."] # Test Headline 
batch = tok(texts, return_tensors="pt", truncation=True, max_length=128, padding=True)
batch.pop("token_type_ids", None)

with torch.no_grad():
    out = model(**batch)
topic_probs = out["logits"].softmax(-1)          # [B, 7]
senti_probs = out["sentiment_logits"].softmax(-1)  # [B, 3]

# 5) Pretty print with labels
for i, text in enumerate(texts):
    tp = topic_probs[i]
    sp = senti_probs[i]

    pred_topic_idx = int(tp.argmax().item())
    pred_senti_idx = int(sp.argmax().item())

    print(f"\nText: {text}")
    print(f"β†’ Topic: {TOPIC_LABELS[pred_topic_idx]}  (p={tp[pred_topic_idx]:.4f})")
    print(f"β†’ Sentiment: {SENTIMENT_LABELS[pred_senti_idx]}  "
          f"(neg={sp[0]:.3f}, neu={sp[1]:.3f}, pos={sp[2]:.3f})")

    # Top-3 topics
    topk = torch.topk(tp, k=min(3, tp.numel()))
    print("Top-3 topic probs:")
    for idx, prob in zip(topk.indices.tolist(), topk.values.tolist()):
        print(f"  {TOPIC_LABELS[idx]:<20} {prob:.4f}")
Downloads last month
5
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Model tree for MasSolutions/Alpaxa-FinBERT-Tone-7class

Base model

ProsusAI/finbert
Finetuned
(110)
this model