Repository navigation
word_timestamps: punctuation inside a word starts a new "word" (3.5% -> 3, .5, %; "안녕"이라고 -> "안녕, "이라고)
#2875
Replies: 1 comment
|
Nice, precise report. As far as I can see, the split comes from (A side note: Workaround without patching Whisper. Your own detection rule (a word that does not start with a space continues the previous one) works as a post-processing step: def merge_inword_punctuation(segments):
"""Re-join pieces of one space-delimited word that word_timestamps split at ASCII punctuation."""
for seg in segments:
merged = []
for w in seg.get("words", []):
if merged and not w["word"].startswith(" "):
prev = merged[-1]
prev["word"] += w["word"]
prev["end"] = w["end"]
prev["probability"] = min(prev["probability"], w["probability"])
else:
merged.append(dict(w))
seg["words"] = merged
return segments
result["segments"] = merge_inword_punctuation(result["segments"])On your examples this gives Possible fix upstream: start a new word on punctuation only when the punctuation token itself begins with a space, i.e. drop the bare |
Uh oh!
There was an error while loading. Please reload this page.
With
word_timestamps=True, an ASCII punctuation character that sits inside a space-delimited word splits that word, and the punctuation ends up at the start of the second half. Decimals, thousands separators, times and domain names are affected in every language that goes throughsplit_tokens_on_spaces. Korean is hit harder, because particles attach directly after a closing quote or bracket ("안녕"이라고,'서울'에서,(주)한국으로), so the closing quote is moved onto the particle.Checked on
mainat 8609812 (Python 3.11, torch 2.14.1+cpu, tiktoken 0.14.0).1. Real audio,
tiny, CPUAudio: EN-UK inflation rate increases to 4%.ogg (Wikinews audio, CC BY 2.5, 3 min; only the first 60 s are used).
Output:
17.5%is three words (17,.5,%),3.7%.is two (3,.7%.), andwikinews.org,iswikinews+.org,.2. No model: tokenizer +
merge_punctuations+WriteSRTThe split depends only on the text tokens, so it can be shown without audio. The Korean lines below are the tokenizer applied to text I typed, not model output.
Output:
The same sentence with a curly closing quote (
”) gives one word“안녕”이라고; with an ASCII"it gives"안녕and"이라고, and the second subtitle starts with the closing quote.Expected
A word is what stands between two spaces:
3.5%,$1,234.50,10:30,example.com.,"안녕"이라고. Or, if punctuation is meant to separate words, at least not.5/"이라고with the separator glued to the front of what follows.Where it comes from
Tokenizer.split_tokens_on_spaces,whisper/tokenizer.pylines 317-325:3|..words[-1], which is now the punctuation (line 324):.+5=.5.merge_punctuations(whisper/timing.pyline 268) only moves a word that is entirely inappend_punctuations;.5and"이라고are not, so they stay. Settingprepend_punctuations=""/append_punctuations=""does not help, because the gluing happens in step 2.string.punctuationis ASCII only and the test is a substring test, which explains the inconsistencies above:”is not in it, so the curly quote does not split; the single token%.is not a substring of it, so4%.stays one word while4+%becomes two.Question / proposal
Is the
.5/"이라고form intended? If not, would you accept rejoining a punctuation "word" with the word before it when the next subword has no leading space? Locally this is 10 lines in theelse:branch:With it the script in section 2 prints
and the existing test suite still passes (
pytest -k 'not test_transcribe or test_transcribe[tiny] or test_transcribe[tiny.en]' -m 'not requires_cuda': 20 passed). Punctuation at the end of a word is untouched, so a trailing%is still its own word unless it is added toappend_punctuations; I left that alone because it is a separate decision. Token order and the token-to-word mapping are unchanged, only the grouping differs. I can open a PR with the change and a test if that is the direction you prefer.Related work
I did not find an earlier report of this. Closest items: #869 (introduced word timestamps and
split_tokens_on_spaces; the review discussed attaching punctuation to adjacent words, not punctuation inside a word), #973 (exposedprepend_punctuations/append_punctuations), #1089 (replacement-character handling insplit_tokens_on_unicode, different function and input), discussion #1243 (suggests emptyprepend_punctuations/append_punctuationsto get punctuation as separate words; that does not change the result here), open PRs #2863, #2847 and #2793 (subtitle writer inwhisper/utils.py, not the word split). Searched discussions, PRs and issues for:split_tokens_on_spaces,split_to_word_tokens,string.punctuation,merge_punctuations,prepend_punctuations,append_punctuations, "word timestamps" combined with decimal / number / comma / percent / dollar / quote / apostrophe / parenthesis / hyphen / URL / punctuation / Korean.All reactions