File size: 12,800 Bytes
129f065
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d6a74c2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129f065
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
---
language:
- en
- zh
- ja
- es
- de
- fr
- ar
license: apache-2.0
library_name: transformers
pipeline_tag: text-classification
base_model: jhu-clsp/mmBERT-base
datasets:
- Kenpache/financial-sentiment-eval-7lang
metrics:
- accuracy
- f1
tags:
- finance
- financial-sentiment
- sentiment-analysis
- multilingual
- financial-news
- fintech
- trading
- market-sentiment
- text-classification
- modernbert
- mmbert
- cross-lingual
---

# Financial Sentiment, 7 Languages

**Sentiment of financial news, in seven languages, from one model.** Feed it a headline
or a sentence in English, Chinese, Japanese, Spanish, German, French or Arabic — get
back `negative`, `neutral` or `positive`.

```python
from transformers import pipeline

clf = pipeline("text-classification", model="Kenpache/finbert-multilingual-v2")

clf("The company reported record quarterly earnings, driven by strong demand.")
# [{'label': 'positive', 'score': 0.9456}]

clf("Die Aktie verlor nach der Gewinnwarnung deutlich an Wert.")
# [{'label': 'negative', 'score': 0.9324}]

clf("该公司宣布大规模裁员计划,股价应声下跌。")
# [{'label': 'negative', 'score': 0.9406}]
```

| | |
|---|---|
| **Task** | Financial sentiment, 3 classes (negative / neutral / positive) |
| **Languages** | **7** — en · zh · ja · es · de · fr · ar |
| **Accuracy** | **87.2%** |
| **Parameters** | 307M (fp32, 1.2 GB) |
| **Backbone** | [`jhu-clsp/mmBERT-base`](https://huggingface.co/jhu-clsp/mmBERT-base) (ModernBERT) |

One model covers all seven languages — no per-language checkpoints, no translation step,
no language ID in front of it. Mixed-language pipelines just work.

**Larger sibling:**
[`Kenpache/finbert-multilingual-v2-large`](https://huggingface.co/Kenpache/finbert-multilingual-v2-large)
— 560M parameters, 88.9% on the same evaluation set. Take that one for accuracy, this
one for footprint.

---

## Accuracy

Measured on a held-out test set of **4,993 financial news sentences** across the seven
languages, published as
[`Kenpache/financial-sentiment-eval-7lang`](https://huggingface.co/datasets/Kenpache/financial-sentiment-eval-7lang).

| Metric | Score |
|---|---|
| **Accuracy** | **0.8724** |
| **F1 (weighted)** | **0.8724** |

### Per language

This is the table to read before adopting the model — it tells you whether *your*
language is covered properly, not just the average.

| Language | | Items | Accuracy |
|---|---|---:|---:|
| Spanish | `es` | 905 | **0.8950** |
| Chinese | `zh` | 1,023 | **0.8935** |
| German | `de` | 650 | 0.8785 |
| Arabic | `ar` | 73 | 0.8767 |
| Japanese | `ja` | 1,063 | 0.8702 |
| English | `en` | 780 | 0.8410 |
| French | `fr` | 499 | 0.8337 |

**The spread between the best and worst language is 6 points**, and English is not at the
top — Spanish and Chinese are. That matters more than it looks: most "multilingual"
financial models are English models with a multilingual tokenizer, and they collapse on
CJK and right-to-left text. This one holds its level across scripts — Latin, Chinese,
Japanese and Arabic alike.

Arabic is measured on 73 items, so treat its number as indicative rather than precise.

### Reproducing these numbers

The evaluation set is public, and so is the protocol — `max_length=192`, fp32, raw text
with no normalisation:

```python
import pandas as pd, torch
from datasets import load_dataset
from transformers import AutoModelForSequenceClassification, AutoTokenizer

ds = load_dataset("Kenpache/financial-sentiment-eval-7lang", split="test").to_pandas()

REPO = "Kenpache/finbert-multilingual-v2"
tok = AutoTokenizer.from_pretrained(REPO)
model = AutoModelForSequenceClassification.from_pretrained(REPO).eval()

preds = []
with torch.no_grad():
    for i in range(0, len(ds), 64):
        enc = tok(ds.sentence[i:i + 64].tolist(), return_tensors="pt",
                  padding=True, truncation=True, max_length=192)
        preds += [model.config.id2label[j].lower()
                  for j in model(**enc).logits.argmax(-1).tolist()]

print((pd.Series(preds) == ds.label).mean())   # 0.8724
```

### Per class

| Class | Precision | Recall | F1 | Support |
|---|---:|---:|---:|---:|
| negative | 0.8658 | 0.8913 | 0.8784 | 1,260 |
| neutral | 0.8683 | 0.8587 | 0.8635 | 2,158 |
| positive | 0.8835 | 0.8762 | 0.8798 | 1,575 |

No class collapse: the three F1 scores sit within 1.6 points of each other, and `neutral`
— the majority class, and the usual dumping ground for models that learned to hedge — has
the *lowest* F1 of the three rather than the highest.

**Polarity errors are rare.** Across all 4,993 items, `negative` is called `positive` 19
times and `positive` is called `negative` 32 times — **51 cases, 1.0% of the set**.
Practically all remaining error sits on the boundary with `neutral`. The model may fail to
register a weak signal; it very seldom reverses one.

### Comparison on the English subset

Both models were run on the **English portion — 780 items — of
[`Kenpache/financial-sentiment-eval-7lang`](https://huggingface.co/datasets/Kenpache/financial-sentiment-eval-7lang)**,
under one identical protocol: `max_length=192`, fp32, raw text, argmax over the three
classes, no tuning or threshold fitting for either model.

| Model | Accuracy | F1 (weighted) |
|---|---:|---:|
| **This model** | **0.8410** | **0.8410** |
| [`ProsusAI/finbert`](https://huggingface.co/ProsusAI/finbert) | 0.7218 | 0.7224 |

Two things belong next to those numbers. `ProsusAI/finbert` is an English-only model, so
the comparison is confined to the English subset — which is, as the table above shows,
this model's weakest language of the seven. And it was trained under a different
annotation convention: most of its errors on this set are neutral items assigned a
direction, so part of the gap reflects differing label conventions rather than capability.

**These figures describe behaviour on this evaluation set only, under the protocol stated
above. They are not a general claim about either model.**

### Cross-benchmark check: Financial PhraseBank

A model tends to look good on the benchmark its own authors picked, so here is the mirror
image of the table above — the same two models on
[Financial PhraseBank](https://huggingface.co/datasets/takala/financial_phrasebank)
(Malo et al., 2014), the long-standing English benchmark in this field, all **4,846
sentences**, under the identical protocol.

| Model | Accuracy | F1 (weighted) |
|---|---:|---:|
| [`ProsusAI/finbert`](https://huggingface.co/ProsusAI/finbert) | **0.8896** | 0.8908 |
| **This model** | 0.8291 | 0.8287 |

Read that gap with one fact next to it: `ProsusAI/finbert` was **fine-tuned on Financial
PhraseBank** — its model card states that "Financial PhraseBank by Malo et al. (2014) is
used for fine-tuning". This model has never seen the corpus. All 4,846 sentences were
checked against this model's training, validation and test data after normalising case
and punctuation; the overlap is zero.

So neither benchmark is neutral ground. The first favours this model, the second favours
`ProsusAI/finbert`. Together they bracket the answer:

| Model | English subset, our set | Financial PhraseBank | Shift |
|---|---:|---:|---:|
| **This model** | 0.8410 | 0.8291 | **−1.2** |
| [`ProsusAI/finbert`](https://huggingface.co/ProsusAI/finbert) | 0.7218 | 0.8896 | **+16.8** |

This model gives up a little over a point when moved onto a foreign benchmark. The
English-only model moves by nearly seventeen between the two.

**Polarity holds.** On its own evaluation set this model reverses polarity on 1.0% of
items; on Financial PhraseBank — a corpus a decade older, in a different register, under a
different annotation convention — the rate is **1.1%** (53 of 4,846). The core judgement
of direction does not degrade off home ground.

**94% of the remaining error sits on the boundary with `neutral`**, which is where the two
conventions genuinely disagree rather than where the model fails. Financial PhraseBank
labels a signed contract or a reported sales increase as `positive`; this model treats a
bare corporate fact as `neutral` unless the text carries an evaluative charge. Neither
reading is wrong — they are two conventions, and each model follows the one it was built
for.

**These figures describe behaviour on these two evaluation sets only. They are not a
general claim about either model.**

---

## Usage

```bash
pip install transformers torch
```

### Pipeline

```python
from transformers import pipeline

clf = pipeline("text-classification", model="Kenpache/finbert-multilingual-v2")

clf("Les bénéfices du groupe ont augmenté de 15% au premier trimestre.")
# [{'label': 'positive', 'score': 0.9423}]
```

Batch a whole list in one call:

```python
texts = ["株価は決算発表後に急落した。",
         "La compañía anunció un despido masivo y sus acciones se desplomaron.",
         "Quarterly revenue beat analyst expectations by a wide margin."]

clf(texts, batch_size=32)
# [{'label': 'negative', 'score': 0.9275},
#  {'label': 'negative', 'score': 0.9355},
#  {'label': 'positive', 'score': 0.9391}]
```

Add `top_k=None` to get the full probability distribution over all three classes instead
of the winner only — useful when you want to threshold on confidence rather than take
the argmax.

### Direct loading

```python
import torch
from transformers import AutoModelForSequenceClassification, AutoTokenizer

REPO = "Kenpache/finbert-multilingual-v2"
tokenizer = AutoTokenizer.from_pretrained(REPO)
model = AutoModelForSequenceClassification.from_pretrained(REPO).eval()

text = "Der Umsatz blieb im Vergleich zum Vorjahr unverändert."
enc = tokenizer(text, return_tensors="pt", truncation=True, max_length=192)

with torch.no_grad():
    probs = torch.softmax(model(**enc).logits, dim=-1)[0]

for i, p in enumerate(probs):
    print(f"{model.config.id2label[i]:8} {p:.4f}")

# negative 0.0391
# neutral  0.9087
# positive 0.0522
```

### On GPU

```python
clf = pipeline("text-classification", model=REPO, device=0)          # CUDA
clf = pipeline("text-classification", model=REPO, device="mps")      # Apple Silicon
```

CUDA, Apple Silicon and plain CPU all work — at 307M parameters this is a small model by
current standards, and it runs comfortably on a laptop.

**Use `max_length=192`** to reproduce the numbers above. The backbone supports up to
8,192 tokens, so longer inputs are technically fine, but the reported accuracy is
measured at 192 — enough for headlines and single sentences, which is what this model is
for.

---

## Limitations

1. **Sentence-level, not document-level.** The model is built for headlines and single
   sentences. Feeding a full article gives you one label for the whole thing, which is
   rarely what you want — split it first.
2. **Financial sentiment is not general sentiment.** "Shares fell 3% on the news" is
   negative in a market sense with no emotional language at all. On product reviews or
   social media this model is the wrong tool.
3. **`neutral` is a convention, not a fact.** The boundary between neutral and mildly
   positive/negative is where human annotators disagree most, and the model inherits that
   ambiguity. If a decision hinges on that boundary, use the probabilities and a
   threshold instead of the argmax.
4. **Arabic coverage is thin** in evaluation (73 items). The other six languages are
   measured on 499–1,063 items each.
5. **Seven languages, not 1,811.** The backbone is pretrained on far more, but this
   classifier was tuned for these seven. Other languages will produce output, but it is
   untested.
6. **Not investment advice.** The output is a sentiment label on a text, not a signal to
   trade on.

---

## Intended use

Good fits:

- tagging multilingual financial news feeds in real time
- market-sentiment dashboards and indices across regions
- pre-screening research corpora before human analysis
- backtesting sentiment-based features on multilingual sources

Poor fits: general-purpose sentiment, long documents, languages outside the seven,
anything where the neutral boundary carries legal or financial weight on its own.

---

## Files

| File | What it is |
|---|---|
| `model.safetensors` | weights, fp32, 1.2 GB |
| `config.json` | ModernBERT config with `id2label` (`negative` / `neutral` / `positive`) |
| `tokenizer.json`, `tokenizer_config.json` | tokenizer |

## License

Apache 2.0.

Built on [`jhu-clsp/mmBERT-base`](https://huggingface.co/jhu-clsp/mmBERT-base), which is
MIT-licensed; that attribution is preserved here.

## Citation

```bibtex
@misc{finbert_multilingual_v2,
  title  = {Financial Sentiment, 7 Languages},
  author = {Kenpache},
  year   = {2026},
  url    = {https://huggingface.co/Kenpache/finbert-multilingual-v2}
}
```