news 2026/10/23 8:08:43

四川方言诈骗电话音频分类实战:从特征工程到半监督调参全记录

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
四川方言诈骗电话音频分类实战:从特征工程到半监督调参全记录

1. 赛题解读:这场比赛到底在做什么

先说结论:这个比赛的训练目标,是让模型在给定的一段电话录音里判断“这通电话是不是诈骗电话”。听起来像常规的二分类,但加上“四川”两个字之后,难度直接翻了一倍——语料里大量出现西南官话的口音、俚语和表达习惯,普通话模型经常一上来就翻车。

我这次是solo参赛,没有队友,从初赛到复赛全程一个人扛。最后复赛拿到rank 13,不算顶尖,但作为一个独立完成的方案,我对这个成绩还算满意。这篇帖子就把整个思路、踩坑、调参过程完整梳理一遍,给后面想打类似比赛的朋友一个参考。

先还原一下赛题的核心约束。

复赛阶段提供的训练数据由两部分组成:一部分是标注好的录音片段,另一部分是大量未标注的通话数据。每个样本本质上是一段电话录音,格式一般是wav或者mp3,采样率常见为16k或8k,时长从十几秒到两三分钟不等。分类目标只有两类:正常通话和诈骗通话。

表面上是音频二分类,实际上有几层隐藏难点。

第一,录音质量参差不齐。电话信道的带宽本身就窄,再加上背景噪声、混响、音量忽大忽小,模型在特征层面必须足够鲁棒。

第二,诈骗话术极其狡猾。很多诈骗电话不会一上来就提钱,而是先寒暄、套近乎、冒充熟人,甚至故意用方言拉近距离。这意味着模型不能只靠某几个敏感词判断,而是要捕捉整个对话的语调和节奏异常。

第三,方言问题。四川口音里平翘舌不分、韵母发音靠前、语速偏快,如果直接拿普通话训练的语音模型来做特征提取,经常会把“四”识别成“十”,把“啥子”听成“傻子”。这一块如果不做针对性处理,baseline基本就是原地踏步。

复赛的评测指标我记得是一个综合得分,既看AUC又看F1,还带了一点对误报率的惩罚。也就是说,光把诈骗电话召回做高不行,还得控制正常通话被误杀的比例。这个指标设置让很多人栽了跟头——有人把阈值调得很激进,结果正常通话误杀一堆,得分反而掉下去。

说回我自己的策略。solo参赛最大的问题是资源有限。别人一个团队可以同时跑十几个实验,我手上就一两张卡,时间也就那么多。所以我的打法从一开始就比较明确:不做花哨的东西,把数据吃透,把baseline做稳,再在细节上一点点抠分数。

2. 数据是小头还是大头?预处理与方言关卡

2.1 先把音频切成能喂进模型的样子

所有语音任务的起点都是特征提取。我直接使用了80维Fbank特征,帧长25ms,帧移10ms,采样率统一到16kHz。为什么要用Fbank而不是MFCC?因为对深度学习模型来说,Fbank保留的信息更完整,MFCC的DCT变换反而会丢掉一些对噪声鲁棒的细节。特别是在电话信道这种低带宽场景下,高频细节本来就不多,能留的信息尽量全留下。

特征提取这块用现成的torchaudio或者librosa都行,但有几个细节需要注意。

一是预加重。电话语音的高频能量衰减明显,预加重滤波器能补回来一部分,默认系数0.97就能用。二是归一化。每条样本自己的能量差异很大,有的离麦克风近,有的远,如果不做per-sample的均值方差归一化,模型很容易被音量带偏。

音频切分上我踩过一个坑。一开始我把整段录音直接扔进模型,padding到固定长度。问题在于,一通正常电话可能聊三分钟,其中诈骗相关的内容只出现在中间某一小段,前面的寒暄全是无效信息。全序列建模不仅慢,而且关键信息被大量无关内容稀释了。后来改成先做VAD(语音活动检测),把静音和过长的停顿切掉,再按滑窗切成3到5秒的片段,每个片段单独判断,最后通过投票决策整通录音的标签。这一改,线上分数直接涨了一个档次。

2.2 四川方言:不是加个词表就能解决的事

这是整个比赛里最让我头疼的部分。

最开始我想得比较简单:方言嘛,多做点数据增强,加些噪声、加些速度扰动,让模型见过足够多样本就完事了。但跑了一轮之后发现完全不是这么回事。

普通话模型和四川话模型的差距不在声学特征上,而在音素映射上。举个具体例子:“你咋个搞的嘛”这句话,普通话模型会把“咋个”拆成zǎ和gè两个音,但四川话里“咋个”经常连读成一个接近zái的音节。特征提取出来之后,普通话模型对应的序列和四川话实际发音的序列根本对不齐,后面的时序模型无论怎么学都抓不住规律。

那怎么办?我试了几种方案,说下有效和无效的。

方案一:直接用方言语音识别模型来做预训练特征提取器。这个思路理论上最对口,但实际效果一般。原因有两个:一是现成的四川方言识别模型本身就不多,质量也参差不齐;二是ASR任务的特征和分类任务的特征侧重点不同,识别模型关注的是音素序列的准确对齐,而诈骗电话分类更关注语气、节奏、情绪这类超音段特征。硬套反而丢失了重要信息。

方案二:在数据层面做方言增强。具体做法是找一些四川方言的影视剧音频、语音合成材料,混入训练集做多任务训练。这个有效,但我当时手头可用的方言数据不算多,扩充了一部分之后收益就饱和了。

方案三:把方言问题转成语速和语调问题。我分析了一下数据,发现四川方言诈骗电话有一个很明显的特征:语速比正常通话快,而且句尾经常有上扬的语调变化。于是我在特征层面加了两个辅助特征:一个是局部帧能量变化率,用来捕捉语速突变;一个是基频F0的统计量,用来刻画语调起伏。

这里说一下我理解的原理:诈骗电话多数是照着脚本念的,人在念脚本时语速会不由自主地加快,特别是在报出银行卡号、验证码这些关键数字时,音节的边界会变得模糊。这个特征在普通话里也有,但四川话语速本身就快,反而更容易暴露这种“念稿感”。加了这两个辅助特征后,模型对正常寒暄和念稿式诈骗的区分度明显变好。

2.3 数据增强:别把增强做成自残

数据增强这块,很多人一上来就上全套:加噪、变速、变调、SpecAugment、Mixup全部拉满。我的建议是:先保守,再激进,并且每一步都要用线下验证集确认没有把验证集和训练集搞混。

我最终使用的增强组合是这样:

  • 速度扰动:0.9到1.1倍速随机缩放。这个对语速敏感的模型很有帮助,但注意不要调得过大,不然方言发音会被扭曲得不成样子。
  • 音量扰动:0.8到1.2倍随机缩放。模拟不同人说话时离麦距离的差异。
  • 加背景噪声:混入一些电话录音里的常见底噪、环境音,信噪比控制在10dB到20dB之间。我用的噪声数据是从比赛的未标注数据里自己切出来的静音段,这个很关键——用城市白噪声或者咖啡馆噪声去混电信电话录音,效果很差,因为频段对不上。
  • SpecAugment:在Fbank特征的时间轴和频率轴上随机遮盖。这个是我的主力增强,每次训练都能稳定带来提升,但遮盖的宽幅不能太大。频率遮盖上限设在15个bin左右,时间遮盖上限设在20帧左右,大了会把关键信息整个盖掉。
  • Mixup:这个我用得比较谨慎。在音频分类里Mixup对二分类的收益不如多分类明显,而且如果混合的是正常电话和诈骗电话,模型学到的东西会变得很模糊。我只在训练后期对难样本做Mixup,效果还行。

还要提一个我初期犯过的错误:做增强的时候没有检查和验证集的数据是否有泄漏。有一次我把同一个emo的静音段噪声切出来混入训练集,结果验证集里也有类似的底噪,线上分数好看,线下却拉了胯。后来我重新整理了数据划分,保证验证集完全来自不同通话录音,数据增强带来的收益才真正反映到线上。

3. 模型与训练:我的炼丹配方

3.1 模型选型:从轻到重,最后停在哪个结构上

这个赛题我用过三种主干网络做对比。

第一个是纯CNN结构,类似音频分类里常见的vgg-ish堆叠。优点是训练快、不容易过拟合,复赛初期我用它做整个流程的调试,跑通之后再换更强的模型。

第二个是CNN+双向GRU的时序结构。在CNN提取局部声学特征之后,用双向GRU建模时序依赖。诈骗电话里的核心特征往往在数秒内连续出现,比如诈骗分子急促地报出一串数字、反复强调“不要挂电话”,这些在时间维度上是连续的。GRU能比纯CNN更好地捕捉这种依赖关系。这个结构最终成为我的主力方案。

第三个是直接用预训练语音模型做特征抽取,后面接分类头。我把wav2vec2之类的中文预训练模型用在特征提取上,冻结底层,只训练分类头。这个方案效果并不如预期,原因有两点:一是预训练模型本身是在通用语音上训练的,对电话信道和四川方言的适配不够;二是参数量大,小数据量下直接训练容易过拟合,冻结训练又发挥不出预训练的优势。

我的一句话总结:这类中低资源音频分类比赛,CNN+时序结构比预训练大模型更稳,性价比更高。

3.2 训练细节:batch size、学习率和损失函数

训练配置这里我记录一下自己的最终参数,供参考。使用单卡训练,batch size设置成32,音频长度统一切成5秒,特征维度80,模型输出两个类别。优化器用AdamW,初始学习率3e-4,后面配合warmup和余弦退火做衰减。

关于batch size我再多说一句。语音模型对batch size挺敏感的,batch太小,BN层统计不稳定,容易训练震荡;batch太大,显存吃不消,而且单样本梯度更新次数变少。我在16和64之间都试过,32最合适。

损失函数我用的不是普通交叉熵,而是加了标签平滑的交叉熵,标签平滑系数0.1。为什么要平滑?因为诈骗电话数据里有一批样本本身就标得模棱两可——有的明明在聊家常,后面突然提到转账;有的语气听着像推销,但实际上是诈骗。这种标签噪声会让模型过度自信,平滑一下反而能提升泛化能力。

还有一个重要细节:类别不均衡。诈骗电话在真实场景里肯定是少数类,复赛给的数据也一样。我抽样看了一下训练集,诈骗样本占比大约只有三成左右。这个比例还不算极端,不需要过采样太多,但训练时候我用了带有权重的基础损失函数,给诈骗类一个1.5左右的加权,让模型不至于完全偏向多数类。

3.3 调参笔记:几条我反复验证过的经验

  1. warmup步数不要贪多。总训练步数大概6000步左右,warmup只设了300步。对于这种小数据量的场景,warmup太长会让模型迟迟进不了稳态。

  2. 学习率是最重要的超参。3e-4这个值我在这个模型上验证过是甜点。调成1e-3会震荡,降到1e-4收敛太慢。如果你复现这个方案,建议先用2e-4到5e-4的区间做一次粗网格搜索,找到大概甜点后再微调。

  3. Early stopping要多看几个指标。我同时监控线下AUC和验证集F1。有时候AUC还在涨,但F1已经开始掉了,说明模型在往错误方向走了。两个指标一起看能更早发现问题。

  4. 不要迷信大模型。很多人一看线上分数不高,第一反应是换更大的模型。其实先检查数据和训练配置才是正路。我试过把一个小的学生模型换成两倍大的教师模型,结果线上只涨了0.002,后来我把同样的精力花在半监督数据上,涨了0.01以上。性价比完全不一样。

4. 成绩提升关键:半监督与后处理

4.1 半监督:把未标注数据用起来

复赛给了一大批未标注通话录音,这部分数据如果只用无监督预训练损失来学表示,收益不明显。我选择的是比较成熟的伪标签方案。

流程是这样的:先用全部有标注数据训练一个教师模型,然后用这个模型给未标注数据打分,把预测置信度高于0.9的样本挑出来,直接当作伪标签塞进训练集,和学生模型一起重新训练。学生模型跑完之后,再挑出它高置信度的样本回填给教师模型,这样迭代两轮。

这里面的关键在阈值选择上。阈值太高,选出来的样本太少,对训练集扩充帮助不大;阈值太低,噪声伪标签会把模型带偏。我用线下验证集做了阈值扫描,最后锁定在0.88这个位置上。在0.88的阈值下,大概能筛出一万多条可靠样本,将近原始训练集的一倍。

还有一个重要的技巧:伪标签样本在训练时的损失权重不要和真实标注一样大。我给伪标签样本设置了0.5的权重。这样即使有少量错标数据,对模型的冲击也不会太大。从实验结果看,两轮迭代之后,线上得分涨了约0.01,这个涨幅在复赛阶段是决定性的。

4.2 TTA:测试时增强,老实但是有用

TTA这个概念不新鲜,但很多人做TTA就是简单地做几次变速叠加,实际上精髓在于怎么组织增强方式和聚合策略。

我在推理阶段用了三种增强:速度扰动、音量扰动和SpecAugment的确定性版本。每种增强做5次,一共15次推理,最后用概率平均的方式聚合。

为什么不用投票而用概率平均?因为投票会把概率信息离散化,丢失置信度区分度。比如一条样本15次预测里有8次是诈骗、7次是正常,投票结果是诈骗,但如果那8次的平均概率只有0.51,这个结果的置信度就非常低。平均概率能保留更多信息,下游阈值调整的空间也更大。

TTA在最终得分上贡献不大,大概0.003左右,但在复赛这种分毫必争的阶段,能拿的分都要拿。

4.3 阈值选择:误杀和漏杀的平衡艺术

比赛到了最后阶段,拼的往往不是模型,而是后处理。

模型输出的是诈骗概率p。理论上,p大于0.5判为诈骗,小于0.5判为正常。但在复赛指标下,阈值不能简单取0.5。我系统扫了一遍0.3到0.7之间的阈值,发现在0.45附近时综合得分最高。

这个结果是有道理的:竞赛指标对漏判的惩罚比对误判更敏感,所以最优阈值会偏向0.5以下,也就是更激进地把样本判成诈骗。但不要因为这一点就把阈值推得特别低,我试过0.3,误杀率显著攀升,综合得分反而下降。阈值扫描虽然简单,却是整个比赛中投入产出比非常高的一件事。

4.4 分段投票策略的进一步优化

前面提到整通录音切成片段投票,这里有个可以优化的细节:不是所有片段对最终决策的权重都一样。

有些片段有明显的念稿特征,比如连续出现数字串、语速突然加快,而有些片段就是普通的点头应答。如果能识别出这些关键片段并给予更高权重,投票结果会更准。

我用了一个简单方案:用模型的片段预测概率做加权。预测概率越接近0.5的片段,说明模型判断越模糊,这类片段权重越低;概率越接近0或1的片段,说明模型越有把握,权重越高。具体公式是,每个片段的权重取1减去两倍的概率熵归一化值。最后整通录音的诈骗概率是各片段概率的加权平均。

这个做法的收益不算大,但思路值得借鉴:后处理不是死的,把语义重要性信息加进去,往往比堆模型参数更快。

5. 排坑实录与经验总结

5.1 数据泄漏:最隐蔽的坑

比赛过程中我经历了一次线下验证分数和线上分数严重不一致的情况,排查了三天,最后定位到数据泄漏。

问题出在我切分验证集的方式上。我一开始是直接按文件随机切分,也就是说同一条录音里可能既有训练片段又有验证片段。但根据竞赛的要求,同一个原始录音的所有片段应该要么在训练集,要么在验证集,不能两边都有。因为同一通电话里前后的背景噪声、信道响应是一样的,模型只要记住了某个片段的底噪特征,就能“认”出同录音的其他片段。

解决方式很简单:按通话录音ID分组切分,确保验证集里出现的录音ID完全不在训练集中出现。改完这一点后,线下分数和线上的相关性显著提升。这个坑对做音频任务的人来说特别典型,我在心里记下了:凡是按片段切数据,必须优先确认录音级别的隔离。

5.2 峰值显存爆炸:怎么在有限的卡上跑更大的模型

solo参赛的人经常会遇到这个情况:模型调参调到差不多了,想试着扩大输入分辨率或者增大模型容量,结果模型一加载,显存直接爆掉。

我当时的做法是梯度累积变体:把batch size从32降到16,然后累积2个step再更新一次梯度,等效batch size不变,峰值显存却能降下来。这个属于常规操作,不过实际执行时还要注意BN层的统计量同步问题。如果用了SyncBN,梯度累积会引入额外误差;我最终用的是普通的BN,在累积模式下表现更稳定。

另一个技巧是fp16混合精度。把模型和中间激活值切到半精度之后,显存占用降到原来的六成左右,而且AUC基本不掉。有些人对fp16有偏见,觉得会损失精度,但实际上对音频分类任务,动态loss scaling做得好,fp16完全能打。

5.3 过拟合信号:训练损失降了,验证却纹丝不动

有一段时间训练集损失降得很漂亮,验证集AUC却始终在0.83附近徘徊。我意识到这是过拟合的典型信号。

排查之后发现两个问题。一是模型复杂度偏高,CNN的通道数堆得太多,而训练集本身只有几千条有效样本。二是正则化强度不够,Dropout设得太低,而且没有用权重衰减。后来我把主干网络的通道数减了三分之一,Dropout从0.1提到0.3,权重衰减从0提到1e-4,验证AUC立刻松动,最后稳定爬到了0.87附近。

这里我要说一个个人体会:很多人打比赛遇到验证集不涨,第一反应就是换模型、换损失函数,其实先回头检查正则化强度和训练配置的性价比更高。模型过拟合的表现往往不是验证损失不降,而是训练和验证的差距在拉大。把握住这个信号,及时收手,比继续调模型架构有用得多。

5.4 时间管理:solo玩家最大的敌人

最后聊一点非技术层面的东西。

solo参赛,最大的敌人不是模型效果,而是时间不够。同台竞赛的一些团队分工明确:一个人管数据处理,一个人管模型训练,一个人管论文复现,一个人管后处理。我只有一个人,这意味着任何一个环节卡壳,整个流程都会停滞。

我的做法是给每个阶段设置硬性截止时间:初赛阶段前三天必须跑通baseline,中间一周做数据增强和模型对比,最后两天集中做后处理和伪标签。每天固定时间只做一件事,不交叉。比如上午只看训练日志和调参,下午才跑实验和记录结果,晚上做数据分析。

还有一个心态问题:复赛排名靠前的方案往往不是最复杂的,而是踩坑最少、迭代最稳的。单人参赛尤其容易陷入“看到别人都在卷,自己也赶鸭子上架”的焦虑。说实话rank 13这个名次离颁奖台还有距离,但这个方案里每一个模块我都清楚地知道它为什么有效、为什么没用,这种掌控感比名次本身更重要。

如果下次再打类似的比赛,我会在数据层面投入更多时间,尤其是方言语义层面的知识,比如把方言里特殊的语气词、强调格式、惯用表达做成知识特征注入模型,这应该比堆模型参数更有效。希望这篇记录能帮到准备参加同类型比赛的朋友,少走一些我走过的弯路。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/23 8:08:42

企业软件合规管理:终端软件资产审计与风险管控实战指南

很多企业在做数据安全、终端安全建设时,容易把重心放在文件加密、上网审计上,忽略了企业软件合规管理带来的版权与安全双重风险。终端上员工私自安装盗版软件、破解工具、外挂、未经审批的开源工具、远程控制程序,一方面会带来软件版权侵权索…

作者头像 李华
网站建设 2026/10/23 2:35:56

Python读取Excel并写入zip:多sheet批量处理与避坑实战

简介:这份资源面向需要处理表格数据的Python学习者与开发者,聚焦Excel文件的读取与写入这一常见任务,帮助解决数据分析、数据清洗和自动化报告中的表格操作问题。压缩包共4个文件,全部为py脚本,整体约6KB,涵…

作者头像 李华
网站建设 2026/10/23 3:02:43

OpenJDK 8u292 Windows x64 绿色版部署指南:环境变量与避坑手册

简介:OpenJDK 8u292-b10 是基于 Java 8 的开源开发工具包,面向 64 位 Windows 系统,为需要构建、运行 Java 应用的开发者提供完整环境,尤其适合软件开发、服务端部署或学习使用。压缩包采用 zip 格式,整体大小 109.15M…

作者头像 李华
网站建设 2026/10/17 10:26:12

R语言数据处理实战:tidyverse增改选排完全指南

R语言学习笔记又更新了。上一篇我们把R的基本数据结构过了一遍,从向量、列表到数据框,终于把“装数据的容器”搞明白了。这一篇笔记的主题,是数据分析里每天都要反复做的基础动作:数据处理中的变量和观测的增改选排。说白了&#…

作者头像 李华
网站建设 2026/10/18 2:04:00

Python爬虫抓取网页数据实战:从能跑到跑得稳的工程化指南

简介:这份资源面向Python爬虫初学者与需要快速上手Scrapy框架的开发者,围绕BBS网站数据抓取这一典型场景,提供了一套可直接参考的实战代码。包内共14个文件,以6个py源码与6个pyc编译文件为主,另含1个docx说明文档和1个…

作者头像 李华