Skip to content

[Bug] _get_and_fix_timestamp 中 min(start, last_end) 导致停顿信息丢失 #58

Description

@BokiyCHU

问题概述
当CTC/对齐模型给出带字间间隔的逐字时间戳时(例如句中停顿之后),_get_and_fix_timestamp的后处理会把下一个字的开始往回拉到上一字的结束,相当于在词级时间轴上抹掉了字间静音。结果是:停顿后的第一个字在输出里会显得偏早,与原始CTC时间戳以及听感上的起音不一致。

涉及代码
文件:fireredasr2s/fireredasr2/asr.py
分支:hyp["timestamp"] 存在时(非「按均分时长」的 fallback 分支)。

当前逻辑:
last_end = dur SHIFT = 0.06 for hyp_id, start, end in zip(hyp_ids, starts, ends): token = self.tokenizer.detokenize([hyp_id], "", False) start = min(max(0, start - SHIFT), last_end) end = min(max(0, end - SHIFT), dur) last_end = end timestamp.append([token.lower(), r3(start), r3(end)])

根因分析
在对齐时间戳整体前移 SHIFT 之后,用下面这行约束当前字的起点:
start = min(start - SHIFT, last_end)

其中 last_end 是上一个 token 修正后的结束时间

  • min(s, last_end) 的含义是:当前 start 不能晚于 last_end。
  • 当 CTC 正确地把下一字放在停顿之后(s > last_end)时,会被钳成 start = last_end,字间空白被吃掉。

示例
场景: 字 A 与字 B 之间有一段静音;CTC 给出的时间戳如下。

字 A:CTC start=1.0s,end=2.0s;减 SHIFT(0.06) 后约 start≈0.94s,end≈1.94s
静音:约 1.94s → 3.94s(字间空白)
字 B:CTC start=4.0s,end=5.0s;减 SHIFT 后约 s≈3.94s

当前逻辑

last_end ≈ 1.94(字 A 的 end)
start_B = min(3.94, 1.94) = 1.94
→ 字 B 的起点被钉在字 A 的结束处,约早 2 秒,字间静音在时间轴上消失

实际影响
转写结果中的词级 start/end(如 JSON 里的 words)在停顿后首字可能与 raw CTC 相差数百毫秒。
我们本地用「上一字结束与 raw CTC 一致、下一字 raw start 在停顿后」的样本验证过:后处理后的 start 会贴到上一字的 end,而不是 raw CTC(再减 SHIFT)的位置。

建议修复

last_end = 0.0
SHIFT = 0.06
for hyp_id, start, end in zip(hyp_ids, starts, ends):
    token = self.tokenizer.detokenize([hyp_id], "", False)
    s = max(0, start - SHIFT)
    e = max(0, end - SHIFT)
    # 单调:当前字起点不早于上一字结束;保留 CTC 给出的字间空白
    s = max(s, last_end)
    e = max(e, s)
    e = min(e, dur)
    start, end = s, e
    last_end = end
    timestamp.append([token.lower(), r3(start), r3(end)])

单调约束:s = max(s, last_end) → 当前字起点不早于上一字 end(可保留字间空白)
last_end 初值:0.0
区间:e = max(e, s),且 e = min(e, dur)

想向维护者确认

  • min(start, last_end) 当初是否另有设计意图(例如用另一种方式消除重叠)?还是应视为 bug?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions