BertTokenizer: `RemoveNonSpacingMarks = true` fails to strip accents from precomposed characters under invariant globalization
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 48/100
- Tipo di issue
- Bug
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Attiva
- Stack tecnologico
- csharp
- Ambito
- machine-learning
Direzione di ricerca
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.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
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.
- Lingua principale
- C#
- Stelle
- 9.4k
- Fork
- 2k
- Merge medio
- 2g 18h
- PR unite (30g)
- 64
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di dotnet/machinelearning
-
area-Native untriaged
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
dotnet/machinelearning#7837 ·
I maintainer di solito rispondono entro 1 giorno
-
area-TensorFlow untriaged
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
dotnet/machinelearning#7836 ·
I maintainer di solito rispondono entro 1 giorno
-
ToArrowRecordBatches accumulates arrays from previous batches, producing invalid record batchesApertaarea-DataFrame bug untriaged
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
dotnet/machinelearning#7799 ·
I maintainer di solito rispondono entro 1 giorno
-
LlamaTokenizer encodes some runs of repeated characters differently from SentencePieceForse già presa @Laurianti l’ha presa 42 giorni fa. Apertaarea-Tokenizers untriaged
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
dotnet/machinelearning#7751 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
BertTokenizer merges words separated only by `\n`, `\t` or `\r`Forse già presa @Laurianti l’ha presa 23 giorni fa. Apertaarea-Tokenizers green
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
dotnet/machinelearning#7724 · 3 commenti ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di dotnet/machinelearning
Issue simili
-
bug emitter:client:csharp
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
microsoft/typespec#12572 · 1 commento · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno
-
needs-area-label
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 2 giorni
-
AWS Lambda: KeyNotFoundException drops HTTP-triggered transactions when allowAllHeaders is disabledApertabug
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
newrelic/newrelic-dotnet-agent#3949 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
area-networking
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
dotnet/aspnetcore#70545 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 87/100
I maintainer di solito rispondono entro 1 giorno