Skip to content

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

@BokiyCHU

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions