peyterho commited on
Commit
bd15ba9
Β·
verified Β·
1 Parent(s): 5fe8eb4

Add custom model_name support to all heads + update defaults to fine-tuned models

Browse files
macro_sentiment/transformers_ensemble.py CHANGED
@@ -2,12 +2,17 @@
2
  Multi-head transformer ensemble for macroeconomic sentiment.
3
 
4
  Domain-specific heads:
5
- 1. FinBERT (ProsusAI) β€” financial news sentiment
6
  2. Financial-RoBERTa-large β€” policy/formal text sentiment
7
  3. ClimateBERT β€” climate risk/opportunity
8
  4. Keyword-based Topic Router β€” routes to appropriate head
9
 
10
  All heads output standardized scores in [-1, +1].
 
 
 
 
 
11
  """
12
 
13
  import re
@@ -20,6 +25,18 @@ from transformers import (
20
  )
21
 
22
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  class SentimentHead:
24
  """Base class for a transformer sentiment scoring head."""
25
 
@@ -67,8 +84,14 @@ class SentimentHead:
67
 
68
 
69
  class FinBERTHead(SentimentHead):
70
- """FinBERT for financial news sentiment. Accepts custom model_name for fine-tuned variants."""
71
- def __init__(self, model_name="ProsusAI/finbert", device="cpu"):
 
 
 
 
 
 
72
  super().__init__(
73
  model_name=model_name,
74
  label_map={0: "positive", 1: "negative", 2: "neutral"},
@@ -78,19 +101,33 @@ class FinBERTHead(SentimentHead):
78
 
79
 
80
  class FinancialRoBERTaHead(SentimentHead):
81
- def __init__(self, device="cpu"):
 
 
 
 
 
 
 
82
  super().__init__(
83
- model_name="soleimanian/financial-roberta-large-sentiment",
84
- label_map={0: "positive", 1: "negative", 2: "neutral"},
85
  score_map={"positive": 1.0, "negative": -1.0, "neutral": 0.0},
86
  device=device, max_length=512,
87
  )
88
 
89
 
90
  class ClimateBERTHead(SentimentHead):
91
- def __init__(self, device="cpu"):
 
 
 
 
 
 
 
92
  super().__init__(
93
- model_name="climatebert/distilroberta-base-climate-sentiment",
94
  label_map={0: "risk", 1: "neutral", 2: "opportunity"},
95
  score_map={"risk": -1.0, "neutral": 0.0, "opportunity": 1.0},
96
  device=device, max_length=512,
@@ -169,13 +206,50 @@ class TopicRouter:
169
 
170
 
171
  class TransformerEnsemble:
172
- def __init__(self, device="cpu", use_router=True, finbert_model="ProsusAI/finbert"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  self.device = device
174
  self.use_router = use_router
175
  self.heads = {
176
  "finbert": FinBERTHead(model_name=finbert_model, device=device),
177
- "policy": FinancialRoBERTaHead(device),
178
- "climate": ClimateBERTHead(device),
179
  }
180
  self.router = TopicRouter(device) if use_router else None
181
 
 
2
  Multi-head transformer ensemble for macroeconomic sentiment.
3
 
4
  Domain-specific heads:
5
+ 1. FinBERT β€” financial news sentiment
6
  2. Financial-RoBERTa-large β€” policy/formal text sentiment
7
  3. ClimateBERT β€” climate risk/opportunity
8
  4. Keyword-based Topic Router β€” routes to appropriate head
9
 
10
  All heads output standardized scores in [-1, +1].
11
+
12
+ Fine-tuned models (v0.2.0):
13
+ - FinBERT: peyterho/finbert-macro-sentiment
14
+ - RoBERTa: peyterho/financial-roberta-large-macro-sentiment
15
+ - ClimateBERT: peyterho/climatebert-macro-sentiment
16
  """
17
 
18
  import re
 
25
  )
26
 
27
 
28
+ # ─── Default model names ─────────────────────────────────────────
29
+ # Fine-tuned on 20K combined financial sentiment corpus (v0.2.0)
30
+ DEFAULT_FINBERT = "peyterho/finbert-macro-sentiment"
31
+ DEFAULT_ROBERTA = "peyterho/financial-roberta-large-macro-sentiment"
32
+ DEFAULT_CLIMATEBERT = "peyterho/climatebert-macro-sentiment"
33
+
34
+ # Original off-the-shelf models (v0.1.0)
35
+ ORIGINAL_FINBERT = "ProsusAI/finbert"
36
+ ORIGINAL_ROBERTA = "soleimanian/financial-roberta-large-sentiment"
37
+ ORIGINAL_CLIMATEBERT = "climatebert/distilroberta-base-climate-sentiment"
38
+
39
+
40
  class SentimentHead:
41
  """Base class for a transformer sentiment scoring head."""
42
 
 
84
 
85
 
86
  class FinBERTHead(SentimentHead):
87
+ """FinBERT for financial news sentiment.
88
+
89
+ Args:
90
+ model_name: HF model ID. Default: fine-tuned 'peyterho/finbert-macro-sentiment'.
91
+ Use 'ProsusAI/finbert' for the original off-the-shelf model.
92
+ device: 'cpu' or 'cuda:0'.
93
+ """
94
+ def __init__(self, model_name=DEFAULT_FINBERT, device="cpu"):
95
  super().__init__(
96
  model_name=model_name,
97
  label_map={0: "positive", 1: "negative", 2: "neutral"},
 
101
 
102
 
103
  class FinancialRoBERTaHead(SentimentHead):
104
+ """Financial-RoBERTa-Large for policy/formal text sentiment.
105
+
106
+ Args:
107
+ model_name: HF model ID. Default: fine-tuned 'peyterho/financial-roberta-large-macro-sentiment'.
108
+ Use 'soleimanian/financial-roberta-large-sentiment' for the original.
109
+ device: 'cpu' or 'cuda:0'.
110
+ """
111
+ def __init__(self, model_name=DEFAULT_ROBERTA, device="cpu"):
112
  super().__init__(
113
+ model_name=model_name,
114
+ label_map={0: "negative", 1: "neutral", 2: "positive"},
115
  score_map={"positive": 1.0, "negative": -1.0, "neutral": 0.0},
116
  device=device, max_length=512,
117
  )
118
 
119
 
120
  class ClimateBERTHead(SentimentHead):
121
+ """ClimateBERT for climate risk/opportunity sentiment.
122
+
123
+ Args:
124
+ model_name: HF model ID. Default: fine-tuned 'peyterho/climatebert-macro-sentiment'.
125
+ Use 'climatebert/distilroberta-base-climate-sentiment' for the original.
126
+ device: 'cpu' or 'cuda:0'.
127
+ """
128
+ def __init__(self, model_name=DEFAULT_CLIMATEBERT, device="cpu"):
129
  super().__init__(
130
+ model_name=model_name,
131
  label_map={0: "risk", 1: "neutral", 2: "opportunity"},
132
  score_map={"risk": -1.0, "neutral": 0.0, "opportunity": 1.0},
133
  device=device, max_length=512,
 
206
 
207
 
208
  class TransformerEnsemble:
209
+ """Multi-head transformer ensemble with domain routing.
210
+
211
+ Args:
212
+ device: 'cpu' or 'cuda:0'.
213
+ use_router: Enable keyword-based topic routing.
214
+ finbert_model: HF model ID for the FinBERT head.
215
+ roberta_model: HF model ID for the Financial-RoBERTa head.
216
+ climatebert_model: HF model ID for the ClimateBERT head.
217
+
218
+ Default models are fine-tuned on 20K combined financial corpus.
219
+ Pass the ORIGINAL_* constants to use off-the-shelf models.
220
+
221
+ Examples:
222
+ # Use fine-tuned models (default, recommended)
223
+ ensemble = TransformerEnsemble(device="cpu")
224
+
225
+ # Use original off-the-shelf models
226
+ from macro_sentiment.transformers_ensemble import ORIGINAL_FINBERT, ORIGINAL_ROBERTA, ORIGINAL_CLIMATEBERT
227
+ ensemble = TransformerEnsemble(
228
+ finbert_model=ORIGINAL_FINBERT,
229
+ roberta_model=ORIGINAL_ROBERTA,
230
+ climatebert_model=ORIGINAL_CLIMATEBERT,
231
+ )
232
+
233
+ # Mix and match
234
+ ensemble = TransformerEnsemble(
235
+ finbert_model="peyterho/finbert-macro-sentiment",
236
+ roberta_model="soleimanian/financial-roberta-large-sentiment",
237
+ )
238
+ """
239
+ def __init__(
240
+ self,
241
+ device="cpu",
242
+ use_router=True,
243
+ finbert_model=DEFAULT_FINBERT,
244
+ roberta_model=DEFAULT_ROBERTA,
245
+ climatebert_model=DEFAULT_CLIMATEBERT,
246
+ ):
247
  self.device = device
248
  self.use_router = use_router
249
  self.heads = {
250
  "finbert": FinBERTHead(model_name=finbert_model, device=device),
251
+ "policy": FinancialRoBERTaHead(model_name=roberta_model, device=device),
252
+ "climate": ClimateBERTHead(model_name=climatebert_model, device=device),
253
  }
254
  self.router = TopicRouter(device) if use_router else None
255