ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于AST模型的呼吸声音分类:ICBHI数据集实践

基于AST模型的呼吸声音分类:ICBHI数据集实践 简介面向熟悉Python与深度学习基础的研究人员、工程师基于ICBHI 2017 Challenge数据集的呼吸音四分类机器学习解决方案完整呈现了利用Audio Spectrogram TransformerAST模型完成诊断分类的方法。针对医疗音频诊断场景项目在数据增强阶段引入time-warping增强策略并重新组织代码架构覆盖数据预处理、模型选择与训练、实验跟踪、评估部署等完整流程适合希望提升呼吸系统疾病早期检测能力的技术团队参考。包体为1个PDF文档大小仅105KB便于快速阅读与对照实现目前已吸引109人学习浏览。文档不仅给出了详细的赛题任务拆解如6-2-2数据划分、5次随机运行、遵循论文的优化与评估方式还提供了推理运行说明、预留测试音频及真实标签的验证思路并强调环境配置、依赖安装等工程化落地要点。对想复现AST/Patch-Mix CL方法、改进呼吸音分类流程的读者而言是一份兼具理论说明与实操指引的紧凑参考。 呼吸声音分类这两年算是我身边做医疗音频的朋友聊得最多的方向之一。听诊这件事看起来很依赖医生的耳朵和经验同一个呼吸音片段不同医生判断可能有出入这就给了机器学习一个很自然的切入点——把杂乱的呼吸音频转成特征交给模型去识别喘鸣音wheeze和爆裂音crackle。这次我基于ICBHI公开数据集用AST模型Audio Spectrogram Transformer搭了一套完整的呼吸声音分类方案覆盖数据读取、预处理、模型微调、评估指标和实际踩坑全过程。这篇博文讲的就是这套方案的具体做法特别适合正在做音频分类、医学信号处理或者想拿这个当机器学习课程期末项目练手的人参考。1. 项目背景与整体方案选型1.1 为什么要做呼吸声音分类呼吸声音分类的直接价值是把“听诊”这个高度依赖经验的主观过程变成可量化、可复现的自动判断。慢性阻塞性肺病、哮喘、肺炎这些疾病在呼吸音里会留下明显的声学特征比如 wheeze 是气道狭窄时产生的连续高频音crackle 是肺泡突然打开产生的断续爆裂音。如果能自动识别这些标志性声音就能辅助基层医生做初步筛查也能用于远程听诊、居家健康监测等场景。我一开始其实犹豫过这个任务是不是直接用普通的音频分类模型就能解决。但后来真正接触数据发现呼吸音和语音、环境声差别很大录音设备五花八门背景有心音和环境噪声同一个病人的不同呼吸周期表现也不稳定。所以这个项目表面上是“分类”实际上是在考验整套数据处理和模型训练的基本功。1.2 为什么选ICBHI数据集和AST模型ICBHI数据集是呼吸声音分类领域公认的benchmark来自ICBHI 2017挑战赛包含920条左右的录音总时长约5.5小时覆盖126名受试者。它最大的优势是标注完整每个录音对应若干个呼吸周期标注了 wheeze、crackle、两者都有、两者都无 四种状态。数据来自不同采集设备录音环境也不统一这反而更接近真实临床场景。模型选型上我对比过几条路线。传统做法是手工提取MFCC、小波特征再丢给SVM或随机森林深度学习路线可以用CNN、ResNet、LSTM。这些方案不是不行但在特征表达能力和泛化性上都有天花板。AST模型是Google团队在2021年提出的音频Transformer把音频谱图当成“图像”送给ViT结构处理在AudioSet大规模音频数据集上预训练后再微调目前在很多音频分类任务上都达到了SOTA效果。我最终选择AST核心原因是它省去了大量人工特征工程而且预训练权重带来的迁移能力特别适合ICBHI这种样本量不大的医疗音频数据。1.3 任务定义与评价指标这个项目不能简单当成四分类来做。一个录音里可能同时存在 wheeze 和 crackle也就是多标签问题。我的做法是输出两个二分类头一个判断是否有 wheeze一个判断是否有 crackle都走sigmoid激活用BCE损失训练。这样既符合数据标注方式也方便后续计算各种指标。ICBHI挑战赛官方用的指标是 ICBHI score也就是灵敏度Sensitivity和特异度Specificity的平均值。用这个指标而不是准确率是因为医学数据通常类别不平衡单纯看准确率很容易被“大多数样本是正常”这个假象骗过去。后文所有实验结果都围绕这个官方指标来评估。2. 数据准备与预处理2.1 ICBHI数据集的读取与统一采样拿到ICBHI数据集后第一步不是急着训练而是把数据形式彻底搞清楚。音频文件是wav格式但因为来自不同采集设备采样率并不一致。如果直接拿原始采样率去做频谱图同样的物理声音在不同文件里会呈现完全不同的形状模型很难学。我统一把音频重采样到16kHz两个原因一是呼吸音的声学能量主要集中在低频区域16kHz的奈奎斯特频率足够覆盖二是AST模型在AudioSet预训练时用的就是16kHz音频这样可以和预训练输入分布保持一致。重采样直接用librosa的resample接口几行代码就能搞定但要注意处理的时候保持音频幅值范围不变避免引入额外增益差异。y, sr librosa.load(wav_path, srNone) y_16k librosa.resample(y, orig_srsr, target_sr16000)2.2 滑窗切分与长度策略ICBHI录音时长从几秒到几十秒不等而AST对输入长度有固定要求。如果不做长度处理一整个录音直接塞进模型既不现实也不好训练。我用的是固定10秒窗口策略录音超过10秒就切成多个10秒片段不足10秒就循环拼接直到填满。训练阶段做随机裁剪相当于一种轻量级数据增强测试阶段取中间段或者对多个片段预测结果取平均。这里有一个容易忽略的细节切分的时候必须保证标签跟着音频走不能因为一个录音被切成多段就把标签搞丢。我是按录音ID建立映射字典所有片段都继承原始录音的多标签这样既简单又不会出错。2.3 频谱图生成与标签处理AST吃的是mel频谱图而不是原始波形。我用 n_fft400、hop_length160、n_mels128 来生成频谱对应16kHz采样率下25ms窗口、10ms步长这也是AST官方预训练采用的标准参数。10秒音频生成出来大约1000帧的频谱再resize到AST要求的1024x128形状。标签处理是这类项目里看起来简单、实际坑最多的地方。ICBHI的标注文件不是每个音频一行而是按呼吸周期逐行记录一个录音可能对应多行标注。我写了一个解析逻辑先把所有行按录音ID聚合只要有任一行出现 wheeze整个录音的wheeze标签就是1crackle同理。这样处理下来原始的事件级标注就转换成了录音级的标签向量。3. AST模型原理与训练配置3.1 AST模型是怎么工作的AST的原理说起来并不复杂它借鉴了ViT处理图像的方式把mel频谱图切成一个个16x16的patch加上位置编码后送入Transformer encoder最后用class token的输出接分类层。换个角度理解把一段音频的“声音照片”切成拼图块让模型通过注意力机制去学习哪些声学区域之间存在关联。这个设计相比CNN有个很实际的好处CNN靠卷积核局部感受野慢慢扩大而Transformer第一层就能建模全局依赖。呼吸音里的 wheeze 和 crackle 往往分布在频谱图的不同位置有时还会被心音或其他噪声隔开全局建模能力在这种场景下优势明显。我用的是HuggingFace上开源的AST模型预训练权重来自AudioSet-10s结构上是一个12层、768hidden size的Transformer参数量大约87M单卡就能跑得动。加载模型时只需要把分类头换成自己的输出维度这个项目里是wheeze和crackle两个输出。3.2 预训练权重与微调策略加载预训练权重后我没有一上来就全量微调而是先冻结backbone只训练新增的分类头用较小的学习率跑5个epoch让分类头先稳定下来。然后再解冻全部参数用一个很小的学习率做全量微调。这样做的原因是医疗音频数据量太小如果一开始就让所有参数剧烈更新预训练权重很容易被破坏模型反而学不到稳定特征。全量微调阶段我用的是AdamW优化器学习率2e-5weight decay 0.01warmup比例5%之后线性衰减。batch size受显存限制设为8如果显存吃紧可以用梯度累积来等效放大batch。关键技巧是开启fp16混合精度训练在RTX 3090上能把显存占用压到12GB以内训练速度提升将近一倍。3.3 训练流程与验证策略这里要特别强调一下数据划分。ICBHI数据集官方没有提供标准的train/test划分很多人在复现时会随机打乱录音来划分训练集和测试集这是有问题的。同一个病人的多个录音如果同时出现在训练集和测试集模型相当于“见过”这个人了测试得分会虚高。我用的是按受试者分组的GroupShuffleSplit保证同一个病人ID的所有录音都只落在训练集或测试集其中一侧。整体训练流程大概是数据加载→频谱图生成→模型前向→BCE loss→反向传播→梯度更新。我额外加了early stoppingpatience设为5监控验证集上的ICBHI score。整个训练在单张RTX 3090上大约需要40分钟到1小时取决于切分出的样本总量。4. 实验结果与性能分析4.1 核心指标与最终结果我先定义评价指标灵敏度SE衡量“真实异常的样本有多少被找出来”特异度SP衡量“真实正常的样本有多少被判对”。ICBHI官方分数就是这两个指标的平均值范围0到1越高越好。在按受试者划分的验证集上我这次跑出的结果是SE约0.58、SP约0.74ICBHI score约0.66F1分数在0.55左右。这个数字和ICBHI挑战赛上的优秀成绩相比还有差距但那类成绩通常用了大量数据增强和模型集成。我这里刻意保持相对朴素的单模型设置目的就是给后续优化留出清晰的提升空间。4.2 混淆矩阵与错误案例分析从混淆矩阵看最明显的规律是crackle的识别情况好于wheeze而同时包含两种异常标签的样本最容易被模型漏掉。原因不难理解wheeze在数据集中本身数量就少模型见过的正样本不够学到的特征边界自然模糊同时存在两种异常的音频声学结构更复杂更容易被模型简化成一个类别来对待。我还翻了一段错误样本仔细听了听发现其中一段被漏检的crackle音频背景里刚好有明显的心音干扰。模型大概率把注意力花在了“听起来更响”的心音上反而忽略了比较轻的crackle。这个现象说明单纯调模型结构作用有限后续可以做心音分离预处理或者用更大窗口让模型看到更多上下文。4.3 与基线方法对比为了确认AST的选型价值我在完全相同的听诊数据划分下跑了几组基线对比MFCC加支持向量机、CNNs、以及直接从零训练的Transformer。结果如下方法ICBHI score备注MFCC SVM0.47手工特征上限明显CNN0.56局部感受野限制了对全局声学特征的捕捉从零训练Transformer0.59数据量不足难以发挥模型容量AST预训练微调0.66预训练音频特征迁移效果显著这个对比再次验证了我的判断在小规模医疗音频数据集上预训练权重的价值比模型结构本身更重要。AST能比传统方案高出将近0.2分主要贡献来自AudioSet海量数据学到的通用音频表征。5. 常见问题与排查技巧实录5.1 文件读取与标签对齐我遇到的第一个坑就是ICBHI标注文件不是每条录音一行而是多个呼吸周期分行记录。最开始我只取了第一行导致大量录音的标签缺失模型训练结果惨不忍睹。排查时我用一个最简单的逻辑验证把每个录音ID的标签行数打印出来发现很多ID有5到10行才意识到是解析逻辑不对。这里提醒大家拿到任何公开数据集第一步一定要做数据完整性校验尤其要确认标签行数和音频数量一一对应。5.2 显存溢出与训练不稳定AST模型输入是1024x128的频谱图切分出的patch数量不少显存不够时会直接OOM。我解决的办法是输入频谱缩放到768宽度、增加梯度累积、开启fp16混合精度。三者结合下来24GB显存跑batch size 8绰绰有余。另一个常见问题是loss突然变成nan。我排查下来有两个原因一个是学习率设得过高另一个是频谱图里出现了inf值。前者把学习率降到5e-5以下就能解决后者是因为个别音频文件解码异常我在数据加载里对audio数组做了数值截断确保所有输入值都在合理范围内。5.3 类别不均衡与过拟合wheeze样本明显少于crackle和正常样本这是这个数据集的结构性缺陷。我试过三种方案对少数类样本做过采样、在损失函数里给少数类更高的权重、对频谱图做时间掩码和频率掩码增强。实测下来过采样提升最直接虽然会增加训练时间但效果最稳定。过拟合方面除了早停我还发现dropout从0.1调到0.3能有效压住验证集和训练集之间的差距代价是训练收敛稍慢但整体评估分数是上升的。6. 扩展思路与实践建议6.1 如何进一步优化呼吸声音分类效果当前方案还有明显的优化空间。第一是数据增强除了频谱掩码还可以尝试mixup、time shift和加入环境噪声扰动这对提升模型泛化能力帮助很大。第二是引入音频事件检测思路把录音切得更细在呼吸周期级别做判断而不是只在录音级别做多标签分类。第三是模型集成把AST和CNN的特征拼接起来或者多个随机种子训练后取投票通常能再提升几个百分点。6.2 把这个项目用于机器学习课程作业或期末项目如果你正在找机器学习期末项目素材我觉得这类医学音频分类项目特别合适。原因在于它的技术链路完整数据清洗、特征提取、模型训练、评估分析、错误案例追踪每一个环节都能在答辩时讲出实质内容。展示时建议重点突出两个点一是数据泄露问题如果你用了按受试者划分可以讲讲为什么随机划分会让指标虚高二是从SE和SP的对比中讲清楚为什么准确率不适合医学分类任务。这两点都是面试官或者老师爱问的细节。我个人在实际操作中最大的体会是呼吸声音分类项目里最花时间的不是调模型而是把数据和评估协议搞清楚。ICBHI虽然是公开benchmark但设备差异、标注主观性、类别不平衡都在悄悄拉低模型上限。AST模型解决的是表征学习的问题而剩下的一半功夫都在严谨的数据处理和合理的评估设计里。本文还有配套的精品资源点击获取
返回列表