声纹仅留 CAM++(用户拍板:eres2net 系识别效果太差整体退役):speakerModels 单条;initFastSpeakerModel 删除;单模型单空间——fastReady=false 时全部 fast 路径自动回落准确注册表(0.5/0.42 更严),滚动/快检/权威判定共用 CAM++;deferredNaming 镜像计算门控跳过;代价=每次滚动检查换 CAM++ 推理(检查线程串行,1s 节拍下可承受);设备 eres2net 两文件已无引用可删

This commit is contained in:
liwenhao2 2026-09-16 17:08:58 +08:00
parent dea9622245
commit 12f008a4c1
2 changed files with 12 additions and 30 deletions

View File

@ -159,12 +159,11 @@ class MainActivity : AppCompatActivity() {
// Embedding model candidates, tried in order. Place one in the external // Embedding model candidates, tried in order. Place one in the external
// models dir (preferred) or at the ROOT of assets/. Download: // models dir (preferred) or at the ROOT of assets/. Download:
// https://github.com/k2-fsa/sherpa-onnx/releases/tag/speaker-recongition-models // https://github.com/k2-fsa/sherpa-onnx/releases/tag/speaker-recongition-models
// 仅 CAM++(2026-09-16 用户拍板:eres2net 系识别效果太差,整体退役)。
// 单模型单空间:滚动/快检/权威判定共用 CAM++;fastReady()=false 时所有
// fast 路径自动回落准确注册表(阈值 0.5/0.42,更严更稳)
private val speakerModels = listOf( private val speakerModels = listOf(
// 主选:CAM++ 7.1M,中英训练,3D-Speaker 榜单 EER 优于 eres2net 系,
// v1.13 声纹提取器架构无关(读 ONNX 元数据),换文件即生效
"3dspeaker_speech_campplus_sv_zh_en_16k-common_advanced.onnx", "3dspeaker_speech_campplus_sv_zh_en_16k-common_advanced.onnx",
"3dspeaker_speech_eres2netv2_sv_zh-cn_16k-common.onnx", // accurate fallback
"3dspeaker_speech_eres2net_base_sv_zh-cn_3dspeaker_16k.onnx", // smaller/faster
) )
private var activeSpeakerModel: String? = null private var activeSpeakerModel: String? = null
private val speakerThreshold = 0.5f private val speakerThreshold = 0.5f
@ -464,9 +463,6 @@ class MainActivity : AppCompatActivity() {
initOfflineRecognizer() initOfflineRecognizer()
setStatus(getString(R.string.loading_speaker)) setStatus(getString(R.string.loading_speaker))
initSpeakerIdentification() initSpeakerIdentification()
if (speakersEnabled) {
initFastSpeakerModel()
}
runOnUiThread { runOnUiThread {
modelsLoaded = true modelsLoaded = true
if (!historyMode) recordButton.isEnabled = true if (!historyMode) recordButton.isEnabled = true
@ -1232,23 +1228,6 @@ class MainActivity : AppCompatActivity() {
activeSpeakerModel = null activeSpeakerModel = null
} }
// E:轻量声纹模型(eres2net base,列表末位)专供滚动换人检测,推理快 ~4 倍。
// 找不到该文件(或准确模型本来就是 base)时跳过,滚动检测自动回退准确模型。
// 注:换 CAM++ 主选后 fast 空间暂仍用 base(独立 registry 镜像,互不污染);
// CAM++ 足够小,后续想让它兼职 fast 只需把末位换成同文件。
private fun initFastSpeakerModel() {
val fastName = speakerModels.last()
if (activeSpeakerModel == fastName) return // 准确模型已是 base
try {
SpeakerRecognition.initFastExtractor(
null, speakerModelFile(fastName).absolutePath
)
Log.i(TAG, "fast speaker model ready: $fastName")
} catch (t: Throwable) {
Log.i(TAG, "fast model '$fastName' not found, rolling falls back to v2")
}
}
// 点击行首说话人标签(ClickableSpan)→ 命名或改名。 // 点击行首说话人标签(ClickableSpan)→ 命名或改名。
// internalKey:该行的内部声纹键("S0"/真名);null=归属未定,提示稍后再命名。 // internalKey:该行的内部声纹键("S0"/真名);null=归属未定,提示稍后再命名。
private fun showNameSpeakerDialog(internalKey: String?) { private fun showNameSpeakerDialog(internalKey: String?) {
@ -1860,9 +1839,11 @@ class MainActivity : AppCompatActivity() {
uiHandler.post { adoptSwitchLabel(serial, name) } uiHandler.post { adoptSwitchLabel(serial, name) }
} }
name == null || score < verdictFallbackMin -> { name == null || score < verdictFallbackMin -> {
// 确认无人:发新号 + 双空间注册(纯净素材) // 确认无人:发新号注册(纯净素材);fastReady=false(单 CAM++)时
val fastEmb = SpeakerRecognition.computeEmbeddingFast( // 镜像无意义,跳过额外计算
samples, sampleRateInHz) val fastEmb = if (SpeakerRecognition.fastReady()) {
SpeakerRecognition.computeEmbeddingFast(samples, sampleRateInHz)
} else null
val label = SpeakerRecognition.nextAutoLabel().also { val label = SpeakerRecognition.nextAutoLabel().also {
SpeakerRecognition.registry.addAuto(it, acc) SpeakerRecognition.registry.addAuto(it, acc)
if (fastEmb != null) { if (fastEmb != null) {

View File

@ -221,9 +221,10 @@ class SpeakerRegistry {
// Singleton holder shared by the UI thread, recording thread and the rolling // Singleton holder shared by the UI thread, recording thread and the rolling
// speaker-check thread. // speaker-check thread.
// //
// 双模型方案(E):准确模型(eres2netv2)负责 endpoint 权威判定与注册; // 单模型方案(2026-09-16 用户拍板):仅 CAM++;eres2net 系整体退役。
// 轻量模型(eres2net base,可选)只负责滚动换人检测(推理快 ~4 倍)。 // fastReady()=false 时:computeEmbeddingFast 回落 CAM++,滚动检索直接走
// ⚠ 两个模型的 embedding 不互通:各自配一份 registry,注册时双写镜像。 // 准确注册表(speakerThreshold 0.5 / verdictFallbackMin 0.42)。镜像注册
// 机制保留但不再有调用者(fastEmb 门控后恒 null)。
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
object SpeakerRecognition { object SpeakerRecognition {
@Volatile private var _extractor: SpeakerEmbeddingExtractor? = null @Volatile private var _extractor: SpeakerEmbeddingExtractor? = null