Casing and inverse text normalization: two decisions that leak into your labels
Whether the transcript says 1200 or twelve hundred, and whether it says White House or white house, is a labeling decision that changes what a model learns.
Two post-processing steps are usually mentioned together and usually specified separately: casing, which restores capital letters, and inverse text normalization, which turns the spoken form of a number, date, or amount into its written form. Both look cosmetic. Both change what a model learns when the decision is made at the label level rather than at the output level.
The decision has a direct consequence: it determines whether the recognizer is asked to transcribe what was said, or to transcribe it and then quietly edit it.
Spoken form and written form are different products
Spoken form is what a verbatim transcript contains: "twelve hundred" rather than 1200, "nineteen eighty four" rather than 1984, "doctor smith" rather than "Dr Smith". It is faithful to the audio, it is what a transcriber working under a verbatim convention produces, and it can be converted to written form later by a deterministic normalizer. Written form is what a reader or a downstream language model wants.
The training consequence is the part that gets missed. If the labels are spoken form, the model learns to output the words that were said. If the labels are written form, the model is being asked to perform the normalization implicitly, as part of recognition, and it will do it inconsistently. The same phrase comes out as 1200 in one utterance and "twelve hundred" in the next, depending on the context and the speaker. That inconsistency is worse than either convention applied consistently, because no downstream module can be built on top of it.
The pattern most production pipelines settle on is to keep the recognizer on spoken form and put a rule-based or grammar-based normalizer after it. The model job stays well defined, the normalization becomes auditable and testable on its own, and the output convention can change without retraining the acoustic model.
The ambiguities that make normalization hard
Every item below is a rule, every rule needs a test case, and the order the rules are applied in is where the bugs live. A grammar-based normalizer is a priority-ordered set of these rules, and writing that priority order down is the actual work. Two rules that are individually correct still produce wrong output if the wrong one runs first, and the failure looks like a data problem rather than a rule problem.
- Ratios and scores. "four to one" is a ratio in one context and a scoreline in another, and writing it as 4:1 is wrong in at least one of them.
- Years and quantities. "nineteen eighty four" is usually a year, but it can also be a quantity, and a rule that always reads it as a year will corrupt the cases where it is not.
- Identifiers spoken digit by digit. Phone numbers, account numbers, and part numbers are said one digit at a time and must not be grouped, summed, or formatted by a generic number rule. "one oh five" is a room number, a time, or the number 105, and only the context decides.
- Ranges. "twenty to thirty" is a range and "twenty two" is a number. A rule that catches the second before the first turns a range into a corrupted number.
- Ordinals, decimals, and currency. "third" becomes 3rd and "point five" becomes 0.5, but "fifty bucks" is not a currency code at all, and a rule that treats it as one produces an amount with a currency the speaker never said.
- Spelled letters. "A B C one two three" is an identifier. A number rule applied to the digits inside it destroys the identifier, and this is one of the most common regressions when a new rule is added.
Casing is mechanical until it is not
Capitalizing the first word of a sentence is mechanical once the sentence boundaries are known, which makes it a downstream consumer of the punctuation model. The hard part is everything else, and the failures are not random: "the white house said" and "the White House said" are different claims, "us" and "US" are different words, and "polish" and "Polish" are a verb and a nationality. A casing model trained on general text gets most of these right and fails on exactly the entities a domain cares about - product names, statutes, instrument names, tickers.
Two workable responses. Maintain a proper-noun list per domain and apply it after the model, accepting that the list needs an owner. Or leave the output lowercase and let the consumer handle it, which is a defensible product decision as long as it is made deliberately. What does not work is a model trained on text whose casing convention is mixed, because the model learns the mixture.
The properties worth testing, and what to ask for
- Idempotence. Running the normalizer over already-normalized text must change nothing. The classic bug is a number rule that reads 1200 and rewrites it as words, or a date rule that reformats a date it already formatted.
- Round trip where the rules claim coverage. Number to words to number should return the original for the cases the grammar handles. Where it does not, the rule is less general than its author believed.
- No silent failure. A rule that does not match should leave the text untouched and be counted, so the coverage of the module is measurable rather than assumed.
- An ambiguity set. A few hundred curated cases covering the list above, scored as sentence-level exact match and re-run on every rule change.
- A label consistency check. Sample the training transcripts, run the normalizer over the labels, and count how many change. If a meaningful share changes, the label set is not in the target convention and the model is learning a mixture.
What this means for transcripts you buy
Ask which convention the transcripts use, and ask for the normalizer that produced them rather than only the output. A supplier that cannot say whether the labels contain 1200 or "twelve hundred" has not made the decision, and the corpus will contain both.
If the convention is spoken form, spot-check the categories that are easy to get wrong: times, dates, amounts, ranges, and identifiers. And keep the two layers separate in the deliverable - verbatim transcripts plus the normalizer, rather than normalized transcripts alone - because a normalizer can be re-run on verbatim text, and verbatim text cannot be recovered from normalized output.