
简介这份资源是面向MATLAB初学者与音频识别方向学习者的BP神经网络猪咳嗽声识别项目源码包可用于理解如何将机器学习分类方法落地到畜牧业动物健康监测场景。包内共13个文件以12个wav音频样本和1个m脚本为主压缩包约306KB音频文件覆盖猪咳嗽、哼哼、咆哮、尖叫、打呼噜等类别用于训练与测试主程序脚本承担网络构建、训练、测试与结果分析等核心流程。项目围绕音频预处理、分帧、去噪与特征提取展开输入可采用声谱图、MFCC或短时能量与过零率等特征隐藏层学习复杂模式输出层对应不同声音类别并涉及训练函数选择、迭代次数与学习率设置及交叉验证评估。目前已有330人学习适合希望快速复现声音分类实验、掌握MATLAB神经网络工具箱用法并积累特征工程与模型调参经验的读者参考。1. 从一段猪舍录音说起BP神经网络猪咳嗽声识别到底在做什么猪舍里此起彼伏的咳嗽声靠人耳去分辨哪头猪病了几乎是不可能完成的任务。一个存栏几千头的育肥场饲养员每天巡栏两三次等发现明显呼吸道症状时往往已经有一批猪进入感染中期用药成本上去了料肉比也垮了。BP神经网络猪咳嗽声识别要解决的就是把「听咳嗽」这件事从人耳搬到算法上用麦克风阵列或录音笔采集猪舍音频切出疑似咳嗽的片段提取特征后送进BP神经网络做二分类或多分类判断这段声音是不是猪咳嗽、属于哪种咳嗽。它适合两类人一类是想把声音监测接入现有养殖管理系统的工程师另一类是手里有音频数据、想跑通一个完整识别链路的学生或算法初学者。整条链路不复杂但每一步都有坑下面按「数据怎么来、特征怎么提、网络怎么搭、结果怎么验」的顺序讲透。2. 音频采集与标注猪咳嗽声识别的数据地基怎么打2.1 猪舍录音的采集方案与设备选型猪咳嗽声识别第一个翻车点往往不在模型而在数据。猪舍环境噪声极大风机低频轰鸣、猪只走动撞击栏位、饲喂器落料、人员走动信噪比经常低到让人怀疑录音设备坏了。常见做法是用指向性麦克风或小型麦克风阵列采样率至少 16 kHz位深 16 bit单声道即可。如果做定点监测麦克风吊装在栏位上方 1.5 到 2 米避开风机正对方向如果做移动巡检手持录音笔要加防风毛套否则风噪会直接淹没咳嗽声。采集时长上建议每个栏舍连续录 30 分钟以上覆盖早中晚三个时段因为猪的咳嗽在清晨和夜间更频繁。录音文件按「栏舍编号_日期_时段」命名方便后续追溯。这里有个血泪经验不要用手机自带录音 App 直接录很多手机会自动做降噪和增益把咳嗽声的高频细节抹掉后面特征提取时你会后悔没有原始波形。提示采集前先用一段已知咳嗽样本试录回放确认能听清咳嗽的爆发段再开始批量录。2.2 咳嗽声片段切分与人工标注流程整段录音不能直接喂给网络需要先切分成短片段。猪咳嗽声通常持续 0.3 到 0.8 秒能量集中在中高频。切分可以用短时能量加过零率做初筛先算帧能量超过自适应阈值的段标记为候选再合并相邻候选帧得到候选片段。候选片段导出后必须人工听辨标注标成「咳嗽」和「非咳嗽」两类非咳嗽里要包含风机噪声、猪叫、撞击声等负样本。标注工具用 Audacity 或 Praat 都行导出时统一成 WAV、16 kHz、单声道。每个类别建议至少 500 条片段正负样本比例控制在 1:1 到 1:2 之间。如果正样本太少可以用数据增强加轻微高斯噪声、做时间平移、调整音量但不要做大幅变速否则咳嗽的时频结构会变形。import librosa import numpy as np import os def split_cough_segments(wav_path, out_dir, frame_len400, hop200, energy_th0.02): # 读取音频统一采样率 y, sr librosa.load(wav_path, sr16000, monoTrue) # 分帧计算短时能量 frames librosa.util.frame(y, frame_lengthframe_len, hop_lengthhop) energy np.sum(frames ** 2, axis0) energy energy / (np.max(energy) 1e-8) # 能量超过阈值的帧标记为候选 candidates energy energy_th segments [] start None for i, flag in enumerate(candidates): if flag and start is None: start i elif not flag and start is not None: s start * hop e i * hop frame_len if 0.2 * sr (e - s) 1.2 * sr: # 限制片段长度 segments.append((s, e)) start None # 导出候选片段 os.makedirs(out_dir, exist_okTrue) for idx, (s, e) in enumerate(segments): seg y[s:e] librosa.output.write_wav(os.path.join(out_dir, fseg_{idx}.wav), seg, sr) return len(segments) if __name__ __main__: n split_cough_segments(pig_house_01.wav, candidates) print(导出候选片段数, n)这段代码的逻辑是先统一采样率到 16 kHz再分帧算短时能量能量归一化后用阈值筛出候选帧合并成片段并限制长度在 0.2 到 1.2 秒之间。参数frame_len400对应 25 ms 窗hop200对应 50% 重叠energy_th0.02是经验阈值实际要根据录音增益调整。导出后的片段还需要人工听辨把真正的咳嗽挑出来。3. 特征提取MFCC、梅尔频谱和时域特征怎么选3.1 MFCC 与梅尔频谱的提取步骤BP 神经网络不能直接吃原始波形需要把音频转成固定维度的特征向量。最常用的是 MFCC梅尔频率倒谱系数它模拟人耳对频率的非线性感知对咳嗽这种中高频爆发声比较敏感。提取流程是预加重、分帧、加汉明窗、FFT、梅尔滤波器组、取对数、DCT最后取前 13 维再加上一阶差分和二阶差分凑成 39 维。梅尔频谱则是省去 DCT 这一步直接取对数梅尔谱维度通常取 64 或 128适合后面接卷积结构但纯 BP 网络用 MFCC 更省参数。import librosa import numpy as np def extract_mfcc(wav_path, n_mfcc13): y, sr librosa.load(wav_path, sr16000, monoTrue) # 预加重增强高频 y np.append(y[0], y[1:] - 0.97 * y[:-1]) # 提取 MFCC mfcc librosa.feature.mfcc(yy, srsr, n_mfccn_mfcc, n_fft400, hop_length200) # 一阶差分和二阶差分 delta librosa.feature.delta(mfcc) delta2 librosa.feature.delta(mfcc, order2) # 拼接后对时间轴取均值和标准差得到固定维度 feat np.concatenate([mfcc, delta, delta2], axis0) feat np.concatenate([np.mean(feat, axis1), np.std(feat, axis1)]) return feat # 维度 39*2 78 if __name__ __main__: f extract_mfcc(seg_0.wav) print(特征维度, f.shape)这里的关键参数是n_mfcc13加上差分后每个系数有 3 个版本再对时间轴做均值和标准差池化得到 78 维固定向量。池化是为了让不同时长的片段都能送进全连接网络。如果你发现咳嗽和非咳嗽在均值上区分度不够可以改用最大值池化或分位数池化保留爆发段的峰值信息。3.2 时域特征与特征融合的取舍除了 MFCC还可以加时域特征短时能量、过零率、谱质心、谱带宽、谱滚降。这些特征计算快对冲击性噪声敏感。常见做法是把 MFCC 的 78 维和 5 个时域特征拼成 83 维送进 BP 网络。但特征不是越多越好维度太高而样本少时网络容易过拟合。我一般会先单独用 MFCC 跑一版再逐步加特征看验证集准确率有没有提升没有提升就砍掉。注意所有特征在送入网络前必须做标准化按训练集的均值和标准差做 Z-score验证集和测试集用同一套参数否则会出现数据泄露。4. BP 网络搭建结构、激活函数和训练参数怎么定4.1 网络结构设计与 bp 神经网络结构图对应关系标题里热搜词有「bp神经网络结构图」说明很多人关心网络到底几层、每层多少节点。猪咳嗽声识别这种任务输入是 78 到 83 维特征输出是二分类结构不需要太深。我一般用三层输入层、一个隐藏层、输出层。隐藏层节点数按经验公式sqrt(输入维数 输出维数) 5估算78 维输入二分类大概在 15 到 25 之间实际取 20 比较稳。激活函数隐藏层用 ReLU输出层用 Sigmoid二分类或 Softmax多分类。损失函数用交叉熵优化器用 Adam学习率 0.001批量大小 32训练 100 到 200 轮配合早停。import torch import torch.nn as nn class CoughBPNet(nn.Module): def __init__(self, input_dim78, hidden_dim20, num_classes2): super().__init__() self.net nn.Sequential( nn.Linear(input_dim, hidden_dim), nn.ReLU(), nn.Dropout(0.3), # 防止过拟合 nn.Linear(hidden_dim, num_classes) ) def forward(self, x): return self.net(x) def train_one_epoch(model, loader, optimizer, criterion, device): model.train() total_loss 0 for x, y in loader: x, y x.to(device), y.to(device) optimizer.zero_grad() logits model(x) loss criterion(logits, y) loss.backward() optimizer.step() total_loss loss.item() return total_loss / len(loader) if __name__ __main__: model CoughBPNet() print(model)这段代码定义了一个带 Dropout 的三层 BP 网络。input_dim78对应 MFCC 加差分的池化特征hidden_dim20是隐藏层节点数Dropout(0.3)在训练时随机丢弃 30% 神经元降低过拟合。训练循环里先清零梯度再前向、算损失、反向、更新。如果你用 Softmax 多分类损失函数换成nn.CrossEntropyLoss它内部已经包含 Softmax不要再手动加。4.2 训练参数调优与早停策略学习率是最关键的参数。0.001 是 Adam 的常用起点如果损失震荡降到 0.0005如果下降太慢升到 0.002 试试。批量大小 32 在样本量几百到几千时比较合适太小梯度噪声大太大收敛慢。早停的判据是验证集损失连续 10 轮不下降就停同时保存验证集损失最低的模型权重。这里有个玄学现象有时候验证集准确率还在涨但损失已经开始升说明模型在过拟合这时候要以损失为准早停。提示训练前把数据按 7:1.5:1.5 切成训练、验证、测试切分时按片段随机打乱不要按录音文件切否则同一头猪的相似片段会同时出现在训练和测试里准确率虚高。5. 避坑与排查猪咳嗽声识别落地时最容易翻车的 5 个地方5.1 现象验证集准确率 99%现场部署后惨不忍睹原因数据泄露。同一段录音切出来的片段被随机分到了训练集和测试集片段之间高度相似模型只是记住了这段录音的噪声底没有学到咳嗽的本质特征。解决按原始录音文件划分数据集训练集和测试集来自不同栏舍、不同日期再做交叉验证。5.2 现象模型把风机噪声也判成咳嗽原因负样本里风机噪声太少或者风机噪声和咳嗽在 MFCC 上区分度不够。解决增加风机噪声负样本同时加入谱质心和谱滚降特征风机噪声能量集中在低频咳嗽在中高频这两个特征能拉开差距。5.3 现象训练损失不下降一直卡在 0.69 左右原因特征没有标准化或者标签编码错了。解决检查输入特征是否做了 Z-score检查标签是不是 0 和 1 而不是 1 和 2。另外如果输入特征全是正数且量纲差异大网络很难收敛。5.4 现象模型在测试集上表现好但换一个猪舍就崩原因过拟合到特定猪舍的声学环境。解决做数据增强时加入不同信噪比的噪声训练时用 Dropout 和权重衰减测试时至少在两个不同猪舍的数据上验证。5.5 现象推理速度太慢达不到实时监测要求原因特征提取用了太长的窗和太高的重叠或者网络隐藏层节点太多。解决特征提取用 25 ms 窗、10 ms hop网络隐藏层降到 15 以内推理时用 ONNX 或 TorchScript 导出批量推理。6. 进阶技巧用交叉验证和混淆矩阵把模型可信度摸清楚6.1 五折交叉验证的落地写法单次划分的测试结果波动很大尤其是样本量只有几百条时。我一般用五折交叉验证把数据按录音文件分成五份每次取四份训练、一份验证循环五次取平均准确率和标准差。这样能看出模型在不同数据子集上的稳定性。如果五折的标准差超过 5 个百分点说明数据分布不均匀需要检查是不是某些栏舍的样本太少。from sklearn.model_selection import KFold import numpy as np def cross_validate(features, labels, model_fn, n_splits5): kf KFold(n_splitsn_splits, shuffleTrue, random_state42) accs [] for train_idx, val_idx in kf.split(features): X_train, X_val features[train_idx], features[val_idx] y_train, y_val labels[train_idx], labels[val_idx] model model_fn() # 这里省略训练循环实际调用训练函数 acc 0.0 # 替换为真实验证准确率 accs.append(acc) return np.mean(accs), np.std(accs)这段代码展示了五折交叉验证的骨架KFold的shuffleTrue保证每折数据随机random_state固定后结果可复现。实际使用时把训练循环填进去记录每折的验证准确率最后看均值和标准差。6.2 混淆矩阵告诉你模型到底错在哪准确率只给一个总数混淆矩阵能看出模型是把咳嗽漏判了还是把噪声误判了。猪咳嗽识别里漏判假阴性比误判假阳性更严重因为漏掉一头病猪可能导致整栏感染。所以看混淆矩阵时重点看假阴性有多少。如果假阴性高可以调低分类阈值比如从 0.5 降到 0.3牺牲一点精确率换召回率。指标含义猪咳嗽识别中的取舍准确率正确分类比例整体参考样本不均衡时失真精确率判为咳嗽中真正咳嗽的比例误报多时看这个召回率真正咳嗽中被判出来的比例漏报多时看这个优先保证F1 值精确率和召回率的调和平均综合权衡我自己的习惯是每次训练完先打印混淆矩阵再算召回率如果召回率低于 0.9不管准确率多高都不上线。现场部署时把模型输出概率和一段时间的滑动平均结合连续多个片段都判为咳嗽才报警能进一步压误报。这套流程跑下来猪咳嗽声识别从数据到部署的链路就闭环了。希望帮到你。本文还有配套的精品资源点击获取