Text Classification
Transformers
Joblib
Safetensors
bert
sentiment-analysis
finance
macroeconomics
climate
esg
policy
ensemble
dictionary
finbert
Eval Results (legacy)
text-embeddings-inference
Instructions to use peyterho/macro-sentiment-finbert with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use peyterho/macro-sentiment-finbert with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="peyterho/macro-sentiment-finbert")# Load model directly from transformers import AutoTokenizer, AutoModelForSequenceClassification tokenizer = AutoTokenizer.from_pretrained("peyterho/macro-sentiment-finbert") model = AutoModelForSequenceClassification.from_pretrained("peyterho/macro-sentiment-finbert", device_map="auto") - Notebooks
- Google Colab
- Kaggle
Fine-tuned FinBERT on 20K macro sentiment dataset (2 epochs)
Browse files
README.md
CHANGED
|
@@ -1,252 +1,66 @@
|
|
| 1 |
---
|
| 2 |
library_name: transformers
|
| 3 |
-
|
| 4 |
tags:
|
| 5 |
-
-
|
| 6 |
-
- sentiment-analysis
|
| 7 |
-
- finance
|
| 8 |
-
- finbert
|
| 9 |
-
- roberta
|
| 10 |
-
- climate
|
| 11 |
-
- esg
|
| 12 |
-
- macroeconomics
|
| 13 |
-
- multilingual
|
| 14 |
-
datasets:
|
| 15 |
-
- nickmuchi/financial-classification
|
| 16 |
-
- zeroshot/twitter-financial-news-sentiment
|
| 17 |
-
- FinanceInc/auditor_sentiment
|
| 18 |
-
- pauri32/fiqa-2018
|
| 19 |
-
- climatebert/climate_sentiment
|
| 20 |
metrics:
|
| 21 |
- accuracy
|
| 22 |
-
- f1
|
| 23 |
-
language:
|
| 24 |
-
- en
|
| 25 |
-
- ar
|
| 26 |
-
- de
|
| 27 |
-
- es
|
| 28 |
-
- fr
|
| 29 |
-
- hi
|
| 30 |
-
- it
|
| 31 |
-
- pt
|
| 32 |
-
pipeline_tag: text-classification
|
| 33 |
model-index:
|
| 34 |
- name: macro-sentiment-finbert
|
| 35 |
-
results:
|
| 36 |
-
- task:
|
| 37 |
-
type: text-classification
|
| 38 |
-
name: Financial Sentiment Analysis
|
| 39 |
-
metrics:
|
| 40 |
-
- name: Accuracy (RoBERTa-Large)
|
| 41 |
-
type: accuracy
|
| 42 |
-
value: 0.913
|
| 43 |
-
- name: F1 Macro (RoBERTa-Large)
|
| 44 |
-
type: f1
|
| 45 |
-
value: 0.902
|
| 46 |
-
- name: Accuracy (FinBERT)
|
| 47 |
-
type: accuracy
|
| 48 |
-
value: 0.897
|
| 49 |
-
- name: F1 Macro (FinBERT)
|
| 50 |
-
type: f1
|
| 51 |
-
value: 0.881
|
| 52 |
---
|
| 53 |
|
| 54 |
-
|
|
|
|
| 55 |
|
| 56 |
-
|
| 57 |
|
| 58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
## The Simple Way (3 lines of Python)
|
| 63 |
-
|
| 64 |
-
```python
|
| 65 |
-
from transformers import pipeline
|
| 66 |
-
|
| 67 |
-
classifier = pipeline("text-classification", model="peyterho/finbert-macro-sentiment")
|
| 68 |
-
|
| 69 |
-
classifier("Tesla shares surged 15% after beating earnings expectations.")
|
| 70 |
-
# → [{'label': 'positive', 'score': 0.998}]
|
| 71 |
-
|
| 72 |
-
classifier("Markets crashed amid recession fears and massive layoffs.")
|
| 73 |
-
# → [{'label': 'negative', 'score': 0.997}]
|
| 74 |
-
```
|
| 75 |
-
|
| 76 |
-
### Which model should I pick?
|
| 77 |
-
|
| 78 |
-
| Model | Size | Speed | Accuracy | Best for |
|
| 79 |
-
|-------|------|-------|----------|----------|
|
| 80 |
-
| [`peyterho/finbert-macro-sentiment`](https://huggingface.co/peyterho/finbert-macro-sentiment) | 110M | Fast | 89.7% | General financial text — good default choice |
|
| 81 |
-
| [`peyterho/financial-roberta-large-macro-sentiment`](https://huggingface.co/peyterho/financial-roberta-large-macro-sentiment) | 355M | Slower | **91.3%** | When accuracy matters most |
|
| 82 |
-
| [`peyterho/climatebert-macro-sentiment`](https://huggingface.co/peyterho/climatebert-macro-sentiment) | 82M | Fastest | 88.9% | Climate/ESG text |
|
| 83 |
-
|
| 84 |
-
---
|
| 85 |
|
| 86 |
-
|
| 87 |
|
| 88 |
-
|
| 89 |
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
```python
|
| 93 |
-
from macro_sentiment import TransformerEnsemble
|
| 94 |
-
|
| 95 |
-
ensemble = TransformerEnsemble(device="cpu")
|
| 96 |
-
|
| 97 |
-
# German — auto-routed to multilingual head
|
| 98 |
-
result = ensemble.score_routed("EZB signalisiert Geduld bei Zinssenkungen.")
|
| 99 |
-
print(result["head_used"]) # "multilingual"
|
| 100 |
-
print(result["detected_language"]) # "de"
|
| 101 |
-
print(result["sentiment_score"]) # [-1, +1]
|
| 102 |
-
|
| 103 |
-
# French
|
| 104 |
-
result = ensemble.score_routed("La BCE maintient ses taux directeurs inchangés.")
|
| 105 |
-
print(result["head_used"]) # "multilingual"
|
| 106 |
-
|
| 107 |
-
# English — still routed to domain-specific heads as before
|
| 108 |
-
result = ensemble.score_routed("Fed raised rates by 75bps.")
|
| 109 |
-
print(result["head_used"]) # "policy" (RoBERTa-Large)
|
| 110 |
-
```
|
| 111 |
-
|
| 112 |
-
For better language detection accuracy, install `langdetect`:
|
| 113 |
-
```bash
|
| 114 |
-
pip install langdetect
|
| 115 |
-
```
|
| 116 |
-
|
| 117 |
-
To disable multilingual routing (v0.2.0 behavior):
|
| 118 |
-
```python
|
| 119 |
-
ensemble = TransformerEnsemble(multilingual_model=None)
|
| 120 |
-
```
|
| 121 |
-
|
| 122 |
-
---
|
| 123 |
|
| 124 |
-
##
|
| 125 |
|
| 126 |
-
|
| 127 |
|
| 128 |
-
|
| 129 |
-
python -m macro_sentiment.finetune \
|
| 130 |
-
--data my_labels.csv \
|
| 131 |
-
--text-column headline \
|
| 132 |
-
--label-column sentiment \
|
| 133 |
-
--base-model peyterho/finbert-macro-sentiment \
|
| 134 |
-
--output my-org/my-custom-model \
|
| 135 |
-
--push-to-hub
|
| 136 |
-
```
|
| 137 |
|
| 138 |
-
|
| 139 |
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 145 |
|
| 146 |
-
|
| 147 |
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
--lr Learning rate (default: 2e-5)
|
| 153 |
-
--batch-size Batch size (default: 32)
|
| 154 |
-
--max-length Max token length (default: 128)
|
| 155 |
-
--push-to-hub Push result to Hugging Face Hub
|
| 156 |
-
--output Local dir or Hub model ID
|
| 157 |
-
```
|
| 158 |
|
| 159 |
-
The script auto-detects label remapping from the model's config, applies class weighting for imbalanced data, and selects the best checkpoint by macro F1.
|
| 160 |
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
## The Full Pipeline
|
| 164 |
-
|
| 165 |
-
For hawkish/dovish stance, crisis detection, climate exposure, and uncertainty scoring:
|
| 166 |
-
|
| 167 |
-
```bash
|
| 168 |
-
pip install transformers torch pysentiment2 scikit-learn numpy datasets huggingface_hub
|
| 169 |
-
python -c "from huggingface_hub import snapshot_download; snapshot_download('peyterho/macro-sentiment-finbert', local_dir='macro-sentiment-finbert')"
|
| 170 |
-
cd macro-sentiment-finbert
|
| 171 |
-
```
|
| 172 |
-
|
| 173 |
-
```python
|
| 174 |
-
from macro_sentiment import MacroSentimentPipeline
|
| 175 |
-
|
| 176 |
-
pipe = MacroSentimentPipeline(device="cpu")
|
| 177 |
-
|
| 178 |
-
result = pipe("The Federal Reserve raised rates by 75bps citing persistent inflation.")
|
| 179 |
-
print(result.summary())
|
| 180 |
-
# → Sentiment: ... | Policy: Very Hawkish (+0.999) | Crisis: Normal | Domain: policy
|
| 181 |
-
|
| 182 |
-
result.macro_sentiment # -1.0 to +1.0
|
| 183 |
-
result.policy_stance # -1.0 (dovish) to +1.0 (hawkish)
|
| 184 |
-
result.crisis_signal # 0.0 (calm) to 1.0 (crisis)
|
| 185 |
-
result.uncertainty # 0.0 (certain) to 1.0 (uncertain)
|
| 186 |
-
result.climate_exposure # 0.0 to 1.0
|
| 187 |
-
```
|
| 188 |
-
|
| 189 |
-
---
|
| 190 |
-
|
| 191 |
-
## Accuracy
|
| 192 |
-
|
| 193 |
-
### In-domain (4,333 test samples from training datasets)
|
| 194 |
-
|
| 195 |
-
| Model | Accuracy | F1 Macro |
|
| 196 |
-
|-------|----------|----------|
|
| 197 |
-
| RoBERTa-Large (fine-tuned) | **91.3%** | **0.902** |
|
| 198 |
-
| FinBERT (fine-tuned) | 89.7% | 0.881 |
|
| 199 |
-
| ClimateBERT (fine-tuned) | 88.9% | 0.872 |
|
| 200 |
-
|
| 201 |
-
### Out-of-domain (datasets NOT in training)
|
| 202 |
-
|
| 203 |
-
| Model | Stock News (30K) | JB PhraseBank (785) |
|
| 204 |
-
|-------|------------------|---------------------|
|
| 205 |
-
| RoBERTa-Large | **72.1% acc / 0.727 F1** | **94.1% acc / 0.936 F1** |
|
| 206 |
-
| FinBERT | 67.8% / 0.677 | 92.4% / 0.913 |
|
| 207 |
-
| ClimateBERT | 64.7% / 0.644 | 92.5% / 0.921 |
|
| 208 |
-
|
| 209 |
-
The Stock News OOD dataset ([ic-fspml/stock_news_sentiment](https://huggingface.co/datasets/ic-fspml/stock_news_sentiment)) uses 5-class labels mapped to 3-class, with different annotation conventions — the 20pp accuracy drop is expected and honest. The JB PhraseBank OOD dataset ([Jean-Baptiste/financial_news_sentiment_mixte_with_phrasebank_75](https://huggingface.co/datasets/Jean-Baptiste/financial_news_sentiment_mixte_with_phrasebank_75)) is a similar domain and holds up well.
|
| 210 |
-
|
| 211 |
-
---
|
| 212 |
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
| `macro_sentiment` | -1 to +1 | Overall sentiment |
|
| 218 |
-
| `policy_stance` | -1 to +1 | Dovish ← 0 → Hawkish |
|
| 219 |
-
| `financial_sentiment` | -1 to +1 | Raw sentiment from active head |
|
| 220 |
-
| `climate_sentiment` | -1 to +1 | Climate risk ← 0 → opportunity |
|
| 221 |
-
| `crisis_signal` | 0 to 1 | Crisis intensity |
|
| 222 |
-
| `uncertainty` | 0 to 1 | Uncertainty level |
|
| 223 |
-
| `confidence` | 0 to 1 | Model confidence |
|
| 224 |
-
| `climate_exposure` | 0 to 1 | Climate topic density |
|
| 225 |
-
| `detected_domain` | text | policy / climate / financial_news / social |
|
| 226 |
-
| `head_used` | text | Which model was activated |
|
| 227 |
-
|
| 228 |
-
## File Structure
|
| 229 |
-
|
| 230 |
-
```
|
| 231 |
-
macro_sentiment/
|
| 232 |
-
├── __init__.py # Package entry point (v0.3.0)
|
| 233 |
-
├── dictionaries.py # Four financial dictionaries
|
| 234 |
-
├── transformers_ensemble.py # Four AI heads + language-aware router
|
| 235 |
-
├── pipeline.py # Full pipeline combining everything
|
| 236 |
-
├── finetune.py # Custom fine-tuning CLI
|
| 237 |
-
├── data_prep.py # Dataset loading
|
| 238 |
-
└── train_meta.py # Meta-classifier training
|
| 239 |
-
eval_results.json # In-domain metrics
|
| 240 |
-
eval_ood_results.json # Out-of-domain metrics
|
| 241 |
-
```
|
| 242 |
-
|
| 243 |
-
## References
|
| 244 |
-
|
| 245 |
-
- Araci (2019). [FinBERT](https://arxiv.org/abs/1908.10063)
|
| 246 |
-
- Loughran & McDonald (2011). *Journal of Finance*
|
| 247 |
-
- Henry (2008). *Journal of Business Communication*
|
| 248 |
-
- Sautner et al. (2023). *Review of Financial Studies*
|
| 249 |
-
- Barbieri et al. (2022). [XLM-T: Multilingual Language Models for Twitter](https://arxiv.org/abs/2104.12250)
|
| 250 |
-
|
| 251 |
-
## License
|
| 252 |
-
Apache 2.0
|
|
|
|
| 1 |
---
|
| 2 |
library_name: transformers
|
| 3 |
+
base_model: ProsusAI/finbert
|
| 4 |
tags:
|
| 5 |
+
- generated_from_trainer
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
metrics:
|
| 7 |
- accuracy
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
model-index:
|
| 9 |
- name: macro-sentiment-finbert
|
| 10 |
+
results: []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
---
|
| 12 |
|
| 13 |
+
<!-- This model card has been generated automatically according to the information the Trainer had access to. You
|
| 14 |
+
should probably proofread and complete it, then remove this comment. -->
|
| 15 |
|
| 16 |
+
# macro-sentiment-finbert
|
| 17 |
|
| 18 |
+
This model is a fine-tuned version of [ProsusAI/finbert](https://huggingface.co/ProsusAI/finbert) on the None dataset.
|
| 19 |
+
It achieves the following results on the evaluation set:
|
| 20 |
+
- Loss: 0.3450
|
| 21 |
+
- Accuracy: 0.8486
|
| 22 |
+
- F1 Macro: 0.8325
|
| 23 |
+
- F1 Weighted: 0.8515
|
| 24 |
|
| 25 |
+
## Model description
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
+
More information needed
|
| 28 |
|
| 29 |
+
## Intended uses & limitations
|
| 30 |
|
| 31 |
+
More information needed
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
|
| 33 |
+
## Training and evaluation data
|
| 34 |
|
| 35 |
+
More information needed
|
| 36 |
|
| 37 |
+
## Training procedure
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
|
| 39 |
+
### Training hyperparameters
|
| 40 |
|
| 41 |
+
The following hyperparameters were used during training:
|
| 42 |
+
- learning_rate: 2e-05
|
| 43 |
+
- train_batch_size: 16
|
| 44 |
+
- eval_batch_size: 32
|
| 45 |
+
- seed: 42
|
| 46 |
+
- gradient_accumulation_steps: 4
|
| 47 |
+
- total_train_batch_size: 64
|
| 48 |
+
- optimizer: Use OptimizerNames.ADAMW_TORCH_FUSED with betas=(0.9,0.999) and epsilon=1e-08 and optimizer_args=No additional optimizer arguments
|
| 49 |
+
- lr_scheduler_type: cosine
|
| 50 |
+
- lr_scheduler_warmup_steps: 31
|
| 51 |
+
- num_epochs: 2
|
| 52 |
|
| 53 |
+
### Training results
|
| 54 |
|
| 55 |
+
| Training Loss | Epoch | Step | Validation Loss | Accuracy | F1 Macro | F1 Weighted |
|
| 56 |
+
|:-------------:|:-----:|:----:|:---------------:|:--------:|:--------:|:-----------:|
|
| 57 |
+
| 1.6807 | 1.0 | 314 | 0.3761 | 0.8246 | 0.8058 | 0.8300 |
|
| 58 |
+
| 1.1679 | 2.0 | 628 | 0.3450 | 0.8486 | 0.8325 | 0.8515 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
|
|
|
|
| 60 |
|
| 61 |
+
### Framework versions
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
|
| 63 |
+
- Transformers 5.6.2
|
| 64 |
+
- Pytorch 2.11.0+cu130
|
| 65 |
+
- Datasets 4.8.4
|
| 66 |
+
- Tokenizers 0.22.2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|