BertTokenizer: `RemoveNonSpacingMarks = true` fails to strip accents from precomposed characters under invariant globalization
Maintainer antworten meist innerhalb von 1 Tag
Dieses Issue hat noch niemand übernommen.
Bewertung
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Anfängerfreundlichkeit
- 48/100
- Issue-Typ
- Bug
- Klarheit
- Größtenteils klar
- Aktivitätsstatus
- Aktiv
- Tech-Stack
- csharp
- Bereich
- machine-learning
Rechercherichtung
Start at BertTokenizer.Create and the RemoveNonSpacingMarks handling, then run the supplied reproduction once with ICU and once with InvariantGlobalization=true. The issue is done when precomposed accents are handled consistently across both modes, or creation fails clearly when decomposition is unavailable; add coverage for the reported inputs and configuration.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
BertOptions.RemoveNonSpacingMarks = true is the setting that makes BertTokenizer strip accents, as uncased BERT vocabularies expect: café becomes cafe. Accent stripping works by decomposing the text to Unicode Form D and dropping the non-spacing marks. Under globalization-invariant mode, string.Normalize returns its input unchanged — that is documented behaviour — so there are no marks to drop. Precomposed accented characters remain intact; for vocabularies such as all-MiniLM-L6-v2, this can cause affected words to miss their expected WordPiece decomposition and become [UNK].
Nothing signals this. BertTokenizer.Create succeeds, encoding succeeds, and for precomposed text the output is identical to having left the option off.
Invariant globalization is common in size-optimised .NET deployments. Microsoft's Alpine and Ubuntu Chiseled images ship without ICU (their extra variants add it), and the .NET 10 Native AOT templates enable it: dotnet new console --aot, dotnet new worker --aot and dotnet new webapiaot all set <InvariantGlobalization>true</InvariantGlobalization>. A service that tokenizes correctly in development can silently stop stripping accents when deployed in one of these configurations.
Reproduction
The reproduction below uses the vocab.txt from sentence-transformers/all-MiniLM-L6-v2.
using System.Text;
using Microsoft.ML.Tokenizers;
var vocabPath = args[0];
var vocab = File.ReadAllLines(vocabPath);
var tokenizer = BertTokenizer.Create(vocabPath, new BertOptions { RemoveNonSpacingMarks = true });
Console.WriteLine($"Normalize(FormD) of \"\\u00e9\": {"\u00e9".Normalize(NormalizationForm.FormD).Length} code unit(s)");
var ids = tokenizer.EncodeToIds("Café crème brûlée in São Paulo, naïve résumé");
Console.WriteLine(string.Join(' ', ids.Select(id => vocab[id])));
Run it once as built, and once in invariant mode:
dotnet run -- path/to/vocab.txt
dotnet run -p:InvariantGlobalization=true -- path/to/vocab.txt
Under ICU:
Normalize(FormD) of "\u00e9": 2 code unit(s)
[CLS] cafe cr ##eme br ##ule ##e in sao paulo , naive resume [SEP]
Under invariant globalization:
Normalize(FormD) of "\u00e9": 1 code unit(s)
[CLS] [UNK] [UNK] [UNK] in [UNK] paulo , [UNK] [UNK] [SEP]
The ICU output matches Hugging Face's BertTokenizer exactly. The invariant output is identical to running with RemoveNonSpacingMarks = false.
Only precomposed input is affected; input that is already decomposed is handled correctly because its combining marks are present to be dropped.
Expected behaviour
Either of these would remove the silent failure:
- Strip accents without relying on
string.Normalize, for example by carrying the decomposition data the option needs, so it behaves the same in every globalization mode; or - Fail loudly: throw from
BertTokenizer.CreatewhenRemoveNonSpacingMarks = trueand decomposition is unavailable, with a message naming the fix (<InvariantGlobalization>false</InvariantGlobalization>, or an ICU-carrying image such as a chiseled-extravariant).
The check for (2) is one line at construction: "\u00e9".Normalize(NormalizationForm.FormD).Length == 2.
Impact
In my test with all-MiniLM-L6-v2, mean pooling, and cosine similarity against the ICU tokenization, the embeddings of affected text diverge substantially:
| input | ICU | invariant |
|---|---|---|
Café crème brûlée in São Paulo, naïve résumé |
1.000000 | 0.333027 |
| a French sentence | 1.000000 | 0.545866 |
| a Spanish sentence | 1.000000 | 0.502484 |
| a German sentence | 1.000000 | 0.572320 |
accented capitals (ÉCOLE ÉLÉMENTAIRE) |
1.000000 | 0.089375 |
| plain ASCII | 1.000000 | 1.000000 |
Versions
- Microsoft.ML.Tokenizers 2.0.0 and 3.0.0-preview.26457.2, identical output
- .NET 10.0.12
Related
#7724 and #7725 report other BertTokenizer differences from Hugging Face's tokenizer. This one is independent of them: the output is correct under ICU and wrong only because of the globalization mode.
- Vorherrschende Sprache
- C#
- Sterne
- 9.4k
- Forks
- 2k
- Ø Merge
- 2 T. 18 Std.
- Gemergte PRs (30 T.)
- 64
Entwicklungsumgebung
- Kein Dockerfile und keine Docker-Compose-Datei
- Hat eine Pull-Request-Vorlage
- Beitragsleitfaden lesen
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus dotnet/machinelearning
-
area-Native untriaged
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 76/100
dotnet/machinelearning#7837 ·
Maintainer antworten meist innerhalb von 1 Tag
-
area-TensorFlow untriaged
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 62/100
dotnet/machinelearning#7836 ·
Maintainer antworten meist innerhalb von 1 Tag
-
ToArrowRecordBatches accumulates arrays from previous batches, producing invalid record batchesOffenarea-DataFrame bug untriaged
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 62/100
dotnet/machinelearning#7799 ·
Maintainer antworten meist innerhalb von 1 Tag
-
LlamaTokenizer encodes some runs of repeated characters differently from SentencePieceEvtl. vergeben @Laurianti hat das vor 42 Tagen übernommen. Offenarea-Tokenizers untriaged
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 88/100
dotnet/machinelearning#7751 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
BertTokenizer merges words separated only by `\n`, `\t` or `\r`Evtl. vergeben @Laurianti hat das vor 23 Tagen übernommen. Offenarea-Tokenizers green
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 85/100
dotnet/machinelearning#7724 · 3 Kommentare ·
Maintainer antworten meist innerhalb von 1 Tag
Alle Issues in dotnet/machinelearning
Ähnliche Issues
-
bug emitter:client:csharp
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 84/100
microsoft/typespec#12572 · 1 Kommentar · 1 Reaktion ·
Maintainer antworten meist innerhalb von 1 Tag
-
needs-area-label
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
Maintainer antworten meist innerhalb von 2 Tagen
-
AWS Lambda: KeyNotFoundException drops HTTP-triggered transactions when allowAllHeaders is disabledOffenbug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 70/100
newrelic/newrelic-dotnet-agent#3949 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
area-networking
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
dotnet/aspnetcore#70545 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 87/100
Maintainer antworten meist innerhalb von 1 Tag