ARTICLE DETAIL

资讯详情

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

水下船舶声音分类:5通道特征与双分支网络压噪原理

水下船舶声音分类:5通道特征与双分支网络压噪原理 简介这份深度学习资源面向水下声学研究者和船舶识别相关工程师提供一套融合卷积操作与注意力机制的双分支网络分类方案。模型以5通道水下声学特征为输入覆盖低频段lf0/lf1、高频段hf、梅尔频谱mel与常数Q变换cq可有效区分不同水下航行器声音模式适用于海洋监测、资源勘探及军事防御等场景。资源包共8个文件包含4个Python脚本、说明txt、附赠docx、README及gitignore压缩包仅53KB便于快速下载与复现。脚本覆盖从特征转换到双分支注意力模型训练、EfficientNet训练等环节结构清晰。目前已吸引55人浏览学习。通过说明文档与附赠资料使用者可掌握数据处理、模型构建与训练调参的关键思路适合希望在水声信号处理中引入深度学习方法的入门至进阶研究者也可作为相关课程或课题的参考实现。1. 水下船舶声音分类5通道特征与双分支网络为什么能压住海上噪声水下船舶声音分类这个方向最容易被低估的是特征设计。我最早做被动声呐目标识别时直接拿Mel频谱图丢给CNN结果在低信噪比录音上完全翻车螺旋桨空化噪声把中高频段糊成一片模型学到的是环境噪声纹理而不是船的特征。后来换成这套思路——把声学信号拆成低频线谱特征lf0/lf1、高频调制谱特征hf、梅尔频谱Mel、常数Q变换CQT这5个通道再用融合卷积与注意力机制的双分支网络做分类效果才稳定下来。这套方案的适用场景很明确被动声呐目标识别、水下目标分类、海洋环境监测以及任何信噪比低、样本量不大但需要稳定判别的水声任务。下面从特征提取到网络落地按可复现的方式完整拆解。2. 5通道声学特征提取lf0、lf1、hf、Mel与CQT各自负责什么2.1 先看物理声源再看特征通道水下船声信号的频谱构成大致可以分为三类。第一类是螺旋桨低频线谱由轴频和叶频产生通常在几Hz到几百Hz不同船只的区别主要体现在这些离散谱线的位置和数量上。第二类是宽带噪声来自流体动力噪声和螺旋桨空化能量分布在中高频段上限经常超过20kHz。第三类是包络调制成分空化噪声强度随螺旋桨叶片转动周期性变化在包络上形成低频调制峰这个特征容易被人忽略但对船型识别非常关键。对应到5个通道上lf0和lf1负责低频线谱区一个贴近基频一个负责谐波延展hf负责高频空化区的包络调制谱Mel和CQT则把整段信号按两种不同频率分辨率映射成时频图给网络提供整体上下文。5个特征不是简单堆叠而是按物理来源分工再融合。在实际项目里这种设计在低信噪比数据上的表现比单独使用任何一种特征都要稳定。这里的实现前提是时间对齐。5个通道的帧长和帧移必须统一否则进网络时同一个时间点对应的是不同位置的信号网络再怎么调都学不到联合特征。建议把所有特征统一用hop_length512或1024来计算后续堆叠成多通道张量时才不会出现帧数对不上的问题。2.2 lf0与lf1低频子带统计特征提取方法低频段特征的常见做法是先STFT再按频率子带聚合而不是直接用原始谱线。原因在于水下实录数据的低频段经常被船舶自身辐射和海洋环境噪声污染子带统计能平滑掉一部分干扰。lf0和lf1的频段设置并不唯一我通常这样定lf0覆盖20-300Hz对应轴频和叶频主线谱lf1覆盖300-1500Hz对应线谱谐波拖尾。如果目标包含超低噪声的安静型船只lf0下边界要压到5Hz此时帧长必须同步加长否则FFT频率分辨率不够。import numpy as np import librosa def extract_lf_subband(y, sr, f_lo, f_hi, n_fft4096, hop1024, n_sub16): 提取低频子带统计特征, 用作 lf0/lf1 通道 y : 单通道时域波形, 浮点型 sr : 采样率, 常见 48k 或 96k f_lo/f_hi: 子带频率范围, 单位 Hz n_sub : 将频带内平均切分成几个子带 返回 (帧数, n_sub) 的对数能量矩阵 S np.abs(librosa.stft(y, n_fftn_fft, hop_lengthhop)) ** 2 freqs librosa.fft_frequencies(srsr, n_fftn_fft) band_idx np.where((freqs f_lo) (freqs f_hi))[0] if len(band_idx) n_sub: # 频带内bin不足时降级处理 n_sub max(1, len(band_idx)) S_band S[band_idx, :] # (频带bin数, 帧数) sub_bands np.array_split(S_band, n_sub, axis0) feat np.stack([np.mean(sb, axis0) for sb in sub_bands], axis0) return np.log(feat 1e-9).T参数上有几个点需要特别注意。n_fft4096在48k采样率下频率分辨率约11.7Hz如果目标船轴频低于10Hz这个分辨率不够需要把n_fft提到8192甚至更大。hop_length决定了时间帧数5个特征通道必须统一用同一个hop_length才能保证最终对齐。输出是(帧数, n_sub)结构lf0和lf1分别调用一次函数两者的n_sub可以设置成不同的值但在最终组成5通道输入时建议统一拉伸到相同维度。2.3 hf高频特征包络调制谱提取高频段直接用频谱图容易被环境噪声淹没多数项目的有效做法是先对高频段做带通滤波再提取Hilbert包络最后对包络做FFT得到调制谱。螺旋桨叶片通过频率会周期性地调制空化噪声强度因此包络谱上会在叶片通过频率及其谐波处出现明显峰值。这个特征在安静型船只识别上尤其好用因为它的物理来源非常特定。from scipy.signal import butter, lfilter, hilbert import numpy as np def extract_hf_modulation(y, sr, f_lo10000, f_hi24000, mod_lo2, mod_hi80, n_sub16): 提取高频段包络调制谱, 用作 hf 通道 f_lo/f_hi : 高频带通范围, 单位 Hz mod_lo/mod_hi: 调制频率分析范围, 单位 Hz 返回 (帧数, n_sub) 调制谱特征 nyq sr / 2.0 if f_hi nyq: # 防止截止频率超出奈奎斯特 f_hi nyq - 1 b, a butter(4, [f_lo / nyq, f_hi / nyq], btypeband) y_hf lfilter(b, a, y) env np.abs(hilbert(y_hf)) env env - env.mean() # 去掉直流分量再分析调制 mod_spec np.abs(np.fft.rfft(env, n8192)) mod_freqs np.fft.rfftfreq(8192, 1.0 / sr) mask (mod_freqs mod_lo) (mod_freqs mod_hi) if mask.sum() n_sub: n_sub max(1, int(mask.sum())) mod_band np.array_split(mod_spec[mask], n_sub) feat np.stack([np.mean(mb) for mb in mod_band], axis0) return np.log(feat 1e-9)注意调制频率通常在几Hz到几十Hz这个频段与lf0/lf1的线谱频段不重叠因此hf通道与低频特征不会冗余。实现时如果数据是短样本比如只有2秒一条调制频率最低只能分辨到0.5Hz勉强够用。样本最短建议10秒以上否则2Hz附近的调制峰根本看不见。这一点决定了数据切片的时长和普通语音分类里“2到3秒足够”完全不同。2.4 Mel与CQT两套时频网格互补组成5通道的后两路Mel频谱在低频段分辨率高、高频段粗符合人耳听觉特性CQT的带宽随中心频率等比变化在低频段频率分辨率高在高频段时间分辨率高正适合谐波结构明显的船舶线谱特征。两者都保留时频图结构但维度往往不同。常见做法是Mel取64或128个滤波器CQT取每八度24个bin。import librosa def extract_mel_cq(y, sr, fmin20, fmax20000, n_mels64, n_cq_bins96): 提取 Mel 和 CQT 两个通道 n_mels : mel滤波器组个数 n_cq_bins : 常数Q变换总bin数 统一使用 hop_length1024 与前面特征对齐 mel librosa.feature.melspectrogram( yy, srsr, n_fft2048, hop_length1024, fminfmin, fmaxfmax, n_melsn_mels ) mel_db librosa.power_to_db(mel) cqt np.abs(librosa.cqt( yy, srsr, hop_length1024, fminfmin, n_binsn_cq_bins, bins_per_octave24 )) cqt_db librosa.amplitude_to_db(cqt) return mel_db, cqt_db, mel.shape[1], cqt.shape[1]这里有一个容易忽略的细节librosa.stft的输出帧数与melspectrogram一致但librosa.cqt如果不指定分帧参数内部会做补零处理帧数可能和另外两个不一致。返回的mel.shape[1]和cqt.shape[1]就是为了检查这个最终统一取最短帧数或裁剪到相同帧数。组成5通道输入时把lf0、lf1、hf、mel、cq按通道维堆叠成形状(N, 5, T, F)其中F对mel和cq分别取64对lf0/lf1/hf的子带统计结果也统一成64维。网络第一层Conv2d的输入通道数就是5。实际堆叠代码可以这样写帧数裁剪逻辑放进Dataset里避免在特征提取阶段反复改全局变量def stack_features(lf0, lf1, hf, mel, cq, target_frames128): 将5个特征通道按时间帧对齐并裁剪到固定长度 min_frames min(lf0.shape[0], lf1.shape[0], hf.shape[0], mel.shape[1], cq.shape[1]) used min(min_frames, target_frames) lf0 lf0[:used] lf1 lf1[:used] hf hf[:used] mel mel[:, :used].T cq cq[:, :used].T return np.stack([lf0, lf1, hf, mel, cq], axis1) # (used, 5, 64)返回维度是(used, 5, 64)在PyTorch里再permute成(5, used, 64)作为Conv2d输入。注意mel和cq要转置成帧数在前、频带在后与lf0等保持一致的行是帧的约定。到这里5通道输入就完全确定了。3. 双分支网络卷积提取谱型注意力机制重标定有效频带3.1 为什么用双分支而不是一个共享主干如果5个通道直接拼在一起用一个CNN低频线谱和高频调制谱的数值尺度差异会让低频通道很快被高能量通道淹没。卷积核在局部区域做加权求和对数值范围大的通道天然更敏感而水下信号里高频宽带能量往往比低频线谱高很多。双分支的本意是分开处理两类不同物理特性的输入在各自的表示空间里先做归一化再在融合层合并。常见做法是把5个通道拆成两组。分支A拿lf0、lf1、CQT它们都是与线谱谐波相关的窄带信息分支B拿hf、Mel它们是宽带包络和整体时频分布。这里5个通道所以把CQT归到线谱分支、Mel归到宽带分支是常见选择。两个分支的结构可以相同也可以不同建议先做两个相同的卷积主干等基线稳定后再分别调整感受野不要一开始就设计不对称结构否则出了问题很难定位到具体分支。3.2 分支内部的卷积块小卷积核配合BN卷积部分用窄Conv2d就够。输入是(5, T, F)形状注意把通道维当成卷积的输入通道T和F当成长和宽。第一个卷积用3×3小核步长设为(1, 2)只在频率方向压缩时间方向保持分辨率这样后面的注意力模块能看到完整的时变过程。import torch.nn as nn class ConvBlock(nn.Module): 卷积块: Conv2d - BN - ReLU - 可选Dropout def __init__(self, in_ch, out_ch, kernel(3, 3), stride(1, 2)): super().__init__() self.conv nn.Conv2d(in_ch, out_ch, kernel_sizekernel, stridestride, padding(1, 1)) self.bn nn.BatchNorm2d(out_ch) self.act nn.ReLU(inplaceTrue) self.drop nn.Dropout2d(0.1) def forward(self, x): return self.drop(self.act(self.bn(self.conv(x))))stride设成(1, 2)而不是(2, 2)是因为水下信号的时间动态本来就不长时间方向再减半容易把短促的调制特征丢掉。kernel选择3×3两三个卷积块叠加后等效感受野接近7×7对频带局部结构已经足够。Dropout2d在训练阶段使用推理时自动关闭此处设0.1起步即可。3.3 注意力机制SE通道重标定放在哪里收益最大注意力机制在这个任务里承担的是通道重标定不是定位。SE模块通过全局平均池化把每个通道压成一个标量再过两个全连接层产生一组权重对原有特征通道重新加权。这样网络可以自动放大那些判别力强的频带抑制环境噪声主导的通道。class SEBlock(nn.Module): Squeeze-and-Excitation 通道注意力 def __init__(self, in_ch, reduction8): super().__init__() self.pool nn.AdaptiveAvgPool2d(1) self.fc nn.Sequential( nn.Linear(in_ch, in_ch // reduction), nn.ReLU(inplaceTrue), nn.Linear(in_ch // reduction, in_ch), nn.Sigmoid() ) def forward(self, x): b, c, _, _ x.size() w self.pool(x).view(b, c) w self.fc(w).view(b, c, 1, 1) return x * w放置位置上我实际试过两种。第一种每个卷积块之后都接SE第二种只在分支尾部、融合之前加一次SE。每个块都加会明显增加参数量收益在多数水声数据集上并不可观只在分支尾部加一次训练更稳显存占用也更温和。所以推荐先把SE放在每个分支最后。若分支内部通道数已经很少比如32到64reduction设8或16都行。如果训练出现震荡把reduction调大一些比如16因为SE第一层全连接会把通道压到1/16权重更新幅度更温和。SE之外CBAM还引入了空间注意力分支对时频图的空间位置做加权。船声分类里空间注意力通常作用于频率方向可以让网络学到“只有某几个低频离散频率带真正重要”。如果显存有余量可以在分支尾部同时挂SE和CBAM的空间注意力但要注意过拟合毕竟水下声学样本量通常不大。3.4 融合层与分类头拼接比相加更适合异源特征两个分支输出形状一般是(N, C1, H1, W1)和(N, C2, H2, W2)融合前要把空间尺寸统一。常见做法是各自做一次AdaptiveAvgPool2d把H和W压到1×1然后两个分支的特征在通道维拼接再用全连接层分类。class DualBranchNet(nn.Module): 双分支网络: 分支A接入lf0/lf1/CQT, 分支B接入hf/Mel x_a: (N, 3, T, F) x_b: (N, 2, T, F) def __init__(self, num_classes, in_ch1): super().__init__() # 分支A: 线谱相关通道 self.branch_a nn.Sequential( ConvBlock(in_ch, 32, stride(1, 2)), ConvBlock(32, 64, stride(1, 2)), ConvBlock(64, 128, stride(1, 2)), ) # 分支B: 宽带相关通道 self.branch_b nn.Sequential( ConvBlock(in_ch, 32, stride(1, 2)), ConvBlock(32, 64, stride(1, 2)), ConvBlock(64, 128, stride(1, 2)), ) self.se_a SEBlock(128) self.se_b SEBlock(128) self.fuse nn.Sequential( nn.Linear(256, 128), nn.ReLU(inplaceTrue), nn.Dropout(0.3), nn.Linear(128, num_classes) ) def forward(self, x_a, x_b): feat_a self.branch_a(x_a) feat_b self.branch_b(x_b) feat_a self.se_a(feat_a).mean(dim(2, 3)) feat_b self.se_b(feat_b).mean(dim(2, 3)) fused torch.cat([feat_a, feat_b], dim1) return self.fuse(fused)融合用拼接而不是相加这个选择很关键。两个分支的特征来自不同物理信号拼接让分类头自己学权重相加则强制两组特征在同一维度上做对应互相干扰。如果你实验中发现相加的效果更好大概率是数据分布太简单换到低信噪比测试集就会露馅。mean(dim(2,3))就是AdaptiveAvgPool2d的等价实现把每个分支的时频图压成一个128维向量。代码里in_ch1是为了演示简洁。实际实现时从5通道张量里切片给两个分支x_a feats[:, :3, :, :]x_b feats[:, 3:5, :, :]因此两个分支的输入通道数分别是3和2把in_ch改成对应数值即可。4. 数据切分与训练配置用特征缓存和L2正则跑出稳定模型4.1 按船切分数据避免同类样本泄漏音频分类任务里常见错误是随机切分train/val。水下船声数据往往是同一条船录了多段每段声音相近随机切分会让模型记住船的条件而不是船的类型测试成绩虚高部署到新船数据就崩。正确做法是按船ID分组同一艘船所有片段只能出现在训练集或测试集。如果数据没有船ID至少按录制航次切分避免同一个航次跨数据集。这一步同时决定了后续所有评估结论是否可信。4.2 离线特征缓存加速训练水下音频长特征提取耗时。推荐先把5通道特征离线算好存成npy文件训练时直接从文件读取而不是在DataLoader里重新算STFT和CQT。这样数据加载瓶颈完全消失还能避免每个epoch重复提取特征带来的额外开销。import os import numpy as np import torch from torch.utils.data import Dataset class ShipEchoDataset(Dataset): 读取离线缓存特征, 每个样本是 (T, 5, 64) 的npy文件 def __init__(self, file_list, labels, cache_dir, target_frames128): self.file_list file_list self.labels labels self.cache_dir cache_dir self.target_frames target_frames def __len__(self): return len(self.file_list) def __getitem__(self, idx): path os.path.join(self.cache_dir, self.file_list[idx] .npy) feat np.load(path).astype(np.float32) # 长度不够的样本用循环填充, 不用零填充 if feat.shape[0] self.target_frames: reps int(np.ceil(self.target_frames / feat.shape[0])) feat np.tile(feat, (reps, 1, 1)) feat feat[:self.target_frames] feat feat.transpose(1, 0, 2) # (5, T, F) label torch.tensor(self.labels[idx], dtypetorch.long) return torch.from_numpy(feat), label短样本用循环填充而不是零填充这个决定来源于实际踩坑。零填充会把一段能量为0的特征塞到尾部卷积会学到“末尾没信号”这种假规律推理时遇到正常长度音频反而分布偏移循环填充保持了信号连续性至少在语义上更接近真实声学信号。代价是样本拼接点可能有跳变但相比整段零填充要好得多。注意循环填充只适用于时间维度不要在频带上用频带之间没有周期性循环会破坏谱结构。4.3 训练循环与L2正则配置训练主体代码是标准流程但有两个细节值得单列weight decay就是L2正则直接作用在卷积核和全连接层参数上不要作用到BN的gamma和beta学习率调度用余弦退火比StepLR更稳水声数据集的验证集loss曲线本身就不平滑StepLR容易让模型卡在局部震荡点。import torch import torch.nn as nn from torch.optim.lr_scheduler import CosineAnnealingLR def train_one_epoch(model, loader, optimizer, criterion, device): model.train() total_loss 0.0 for feats, labels in loader: feats, labels feats.to(device), labels.to(device) # 切出双分支输入: 前3个通道给分支A, 后2个通道给分支B x_a feats[:, :3, :, :] x_b feats[:, 3:5, :, :] logits model(x_a, x_b) loss criterion(logits, labels) optimizer.zero_grad() loss.backward() optimizer.step() total_loss loss.item() * feats.size(0) return total_loss / len(loader.dataset) model DualBranchNet(num_classes5, in_ch1) # 按自己类别数改 optimizer torch.optim.AdamW( model.parameters(), lr1e-3, weight_decay1e-4 ) criterion nn.CrossEntropyLoss() scheduler CosineAnnealingLR(optimizer, T_max60) for epoch in range(60): loss train_one_epoch(model, train_loader, optimizer, criterion, device) scheduler.step() if epoch % 10 0: print(fepoch {epoch}, loss {loss:.4f})这里的weight_decay1e-4是相对保守的起步值。水下声学数据集通常只有几千条模型参数规模不大1e-3会让主干学不动1e-5又几乎不起作用。假如用了CBAM这类带空间注意力的模块建议把注意力部分全连接层的weight_decay单独设成1e-4主干沿用默认。做法是构造两个参数组传给optimizer一组带weight_decay一组不带调起来更细腻。4.4 超参表直接抄作业的起步配置参数建议值说明输入张量(N, 5, 128, 64)5通道、128帧、64频带采样率48kHz或96kHz统一降采样到48k更省内存每段样本时长10秒以上短于10s时hf调制谱分辨率不足批量大小32显存不够就16不要用8以下初始学习率1e-3AdamW配合CosineAnnealingLRweight_decay1e-4只对Conv/FC生效不作用到BN训练轮数60-100以验证集最优loss为准不硬跑满类别不均衡加权CrossEntropy权重按1/类别频率归一化批量大小低于8时BN统计量会很不稳定尤其输入特征里还包含大量恒定背景噪声时训练集和验证集的BN统计会明显偏移。如果显存实在不够用梯度累积两步再更新而不是把batch压到8以下。5. 水下声学分类避坑实录特征错位、分支失衡和评估幻觉5.1 训练loss下降但验证集频繁波动现象训练集准确率快速到95%验证集在70%和90%之间来回弹。原因最典型的是数据集按文件随机切分同一条船的多段录音同时出现在训练集和验证集验证集里出现“半熟脸”样本。另一个可能原因是CQT和Mel的帧数没对齐训练时模型见过很多短尾样本验证时遇到更长样本导致全局池化特征偏移。解决先按船ID做分组切分确保同船全部进同一侧再做一次特征帧数直方图确认训练集和验证集的样本时长分布一致。两个问题修完通常能消掉一半以上的验证集波动。5.2 低频通道能量为0模型根本没看到线谱现象训练结束后打印第一层卷积权重发现lf0通道对应的权重几乎全是0CAM可视化时低频区域也没有响应。原因特征提取时带通滤波上限设太低或者采样率设置错误。比如原数据是16kHz采样f_hi却设到20kHz整个频带为空。低频段能量本身很弱如果没做对数压缩直接输入浮点精度也会让低能量值被后续卷积忽略。解决在特征离线缓存阶段打印每个通道的均值和方差。均值低于0.1就需要检查滤波器参数低频通道先做log1p处理再对每个通道单独做min-max归一化到0到1之间。进入网络前各通道单独norm不要5个通道一起归一化否则会再次压低低频通道的存在感。5.3 双分支中宽带分支梯度远大于线谱分支现象训练日志里两个分支最后一个卷积层的梯度范数相差10倍以上融合层的参数几乎全由宽带分支主导。原因hf和Mel的能量范围大卷积输出特征尺度也大学习率对两个分支是同一个大尺度分支对应的梯度自然更大线谱分支被压制。解决在融合层之前对两个分支的输出各接一个LayerNorm把尺度拉齐。也可以在optimizer里给分支B单独设更小的学习率但麻烦效果也不如LayerNorm直接。两个方案都试过以后LayerNorm方案训练更稳我留在默认配置里。5.4 同一模型换到另一条船的数据就掉点现象在A船录制数据上训练准确率95%换到没见过的B船数据准确率掉到60%。原因特征归一化是在A船全局统计上做的。B船能量分布和调制频率范围不同归一化后特征被推离模型见过的分布。水下信道变化大船速、水深、海浪状态都会影响绝对能量。解决不要用全局固定min-max改在每条样本内部独立做通道归一化。这样模型学到的不是绝对能量而是相对谱形。另一个实用做法是在训练时对特征做随机增益扰动把5个通道统一乘一个0.8到1.2的随机系数模拟同一船在不同距离下收到信号的强弱变化能显著提升跨船泛化。5.5 准确率指标失真只看准确率会误判模型现象5类船里有一类占比极低模型全部输出到多数类准确率仍有90%但实际部署没有一点用。原因这是类别不均衡下的典型评估幻觉。准确率对多数类太友好少数类完全没被模型学到。解决改看加权F1和每类的Recall/Precision。如果少数类只有几十条样本直接用Focal Loss代替CrossEntropy更合适gamma设1到2alpha按类别频率反比设置。类别样本数不足时数据增强比调模型参数更有用其中对时间方向和频率方向做随机拉伸的增强方法对水声特征最稳定。6. 模型验证与上线前的压力测试CAM看注意力混淆矩阵查短板模型训练完不能只看测试集准确率就宣布完成。水下声学分类特别容易过拟合到数据集特有的噪声上验证需要分三步走。第一步是类激活映射CAM可视化。取训练好的模型最后一层卷积输出的特征图对类别概率求梯度或直接做加权求和叠加回原始时频图能看到模型到底在哪个频段做了判别。线谱分支的注意力应该稳定出现在低频几个离散频率带附近。如果可视化结果显示注意力散落在全频带说明模型没有学到有效的线谱结构只是记住了全局能量纹理。第二步是混淆矩阵逐类分析。把测试集预测结果画出来重点看哪两类最容易互相混淆。经常出问题的是同系列船上不同型号之间的线谱几乎一样只能靠高频包络调制峰值区分。如果hf通道对应类别的识别率低回查特征提取阶段调制谱是否被噪声污染必要时把调制分析范围从2-80Hz收窄到与实际船速匹配的区间。第三步是信噪比压力测试。把测试音频叠加不同程度的环境噪声从20dB SNR到0dB SNR逐级降下去看模型准确率曲线掉到什么位置开始崩。理想模型在10dB到5dB区间曲线平滑下降而不是断崖式垮掉。如果5dB就开始崩优先怀疑特征里环境噪声成分过多回到第二章把hf带通范围收紧或者训练时加随机噪声样本做增强。这个方法比单纯调模型参数有效得多。我自己的习惯是这三个步骤走完才允许模型出实验环境。水下声学数据集攒起来贵标注更贵一个能用但说不清在哪个频段做判别的模型部署之后出了问题连排查入口都没有。在这套5通道加双分支的方案里最有价值的不是最终准确率数字而是CAM可视化和SNR曲线这两样东西。它们是你项目验收时能拿得出手的说服证据也是模型后续迭代时唯一可靠的对照基准。希望帮到你。本文还有配套的精品资源点击获取
返回列表