1. 项目背景与个人分工

本项目是“诈骗克星——基于大模型智能体的 AI 反诈骗检测系统”。

我的分工:音频伪造检测工具开发,基于 Wav2Vec2-Base 识别语音真假(bonafide/spoof),并最终封装为可被后端和大模型调用的接口服务。

2. 本次成果

下载预训练模型 facebook/wav2vec2-base

下载并校验 ASVspoof2019 LA 数据集

编写数据检查脚本,验证协议与音频文件对应关系

完成最小训练脚本

3. 环境与资源准备

3.1 模型下载

通过cursor推荐代码将Wav2Vec2-Base 下载到本地目录:pretrained/wav2vec2-base

下载后包含 config.json、pytorch_model.bin 等文件,说明模型资源完整。

3.2 数据集准备

从官方网站下载ASVspoof2019_LA数据集,目录如下:

                          

4. 数据检测脚本与验证结果

我用cursor帮我编写了 check_asvspoof_data.py,主要做三件事:

(1)解析协议文件中的 utt_id + label

(2)检查协议样本是否都能在对应 flac 目录找到音频

(3)抽样检查是否存在空文件

运行结果:

train 协议条目:25380,缺失文件:0

dev 协议条目:24844,缺失文件:0

eval 协议条目:71237,缺失文件:0

抽样空文件:0

PS D:\项目实训> python check_asvspoof_data.py --data_dir data --sample_size 20
data_dir: D:\项目实训\data
cm_protocol_dir: D:\项目实训\data\ASVspoof2019_LA_cm_protocols

=== ASVspoof2019.LA.cm.dev.trl.txt ===
parsed entries: 24844
bad lines: 0
label distribution: {'bonafide': 2548, 'spoof': 22296}
audio root: data\ASVspoof2019_LA_dev\flac
missing files: 0
sample size check: 20, zero-size files in sample: 0

=== ASVspoof2019.LA.cm.eval.trl.txt ===
parsed entries: 71237
bad lines: 0
label distribution: {'spoof': 63882, 'bonafide': 7355}
audio root: data\ASVspoof2019_LA_eval\flac
missing files: 0
sample size check: 20, zero-size files in sample: 0

=== ASVspoof2019.LA.cm.train.trn.txt ===
parsed entries: 25380
bad lines: 0
label distribution: {'bonafide': 2580, 'spoof': 22800}
audio root: data\ASVspoof2019_LA_train\flac
missing files: 0
sample size check: 20, zero-size files in sample: 0

数据完整性和标签可用性通过,可以进入训练阶段。

5. 最小训练脚本说明

我用cursor帮我编写了 train_wav2vec2_minimal.py,关键设计如下:

从 CM protocol 读取标签:bonafide -> 0(真人语音)、spoof -> 1(伪造、合成音频)

使用 Wav2Vec2ForSequenceClassification 进行二分类微调

截断音频时长(默认 4 秒)降低训练开销

先使用小样本验证训练链路

关键代码:

音频标准化:同一输入波形格式

def load_audio(path: Path, target_sr: int = 16000) -> np.ndarray:
    wav, sr = sf.read(path)
    if wav.ndim > 1:
        wav = wav.mean(axis=1)
    wav = wav.astype(np.float32)

    if sr != target_sr:
        duration = len(wav) / sr
        target_len = int(duration * target_sr)
        if target_len > 1:
            x_old = np.linspace(0, 1, num=len(wav), endpoint=False)
            x_new = np.linspace(0, 1, num=target_len, endpoint=False)
            wav = np.interp(x_new, x_old, wav).astype(np.float32)
    return wav

自定义数据集(读取音频并返回训练项)

class ASVspoofDataset(Dataset):
    def __init__(
        self,
        pairs: List[Tuple[str, int]],
        audio_root: Path,
        max_seconds: float = 4.0,
        sample_rate: int = 16000,
    ):
        self.pairs = pairs
        self.audio_root = audio_root
        self.max_len = int(max_seconds * sample_rate)
        self.sample_rate = sample_rate

    def __len__(self):
        return len(self.pairs)

    def __getitem__(self, idx):
        utt_id, label = self.pairs[idx]
        audio_path = self.audio_root / f"{utt_id}.flac"
        wav = load_audio(audio_path, target_sr=self.sample_rate)

        if len(wav) > self.max_len:
            wav = wav[: self.max_len]

        return {
            "input_values": wav,
            "labels": label,
        }

动态补齐:把边长音频组装为同一batch

class DataCollatorCTCWithPadding:
    def __init__(self, processor: Wav2Vec2Processor):
        self.processor = processor

    def __call__(self, features):
        input_values = [f["input_values"] for f in features]
        labels = torch.tensor([f["labels"] for f in features], dtype=torch.long)
        batch = self.processor(
            input_values,
            sampling_rate=16000,
            return_tensors="pt",
            padding=True,
        )
        batch["labels"] = labels
        return batch
训练流程:

解析参数->固定随机种子->加载train/dev协议 -> 加载预训练 Wav2Vec2ForSequenceClassification

->创建 TrainingArguments(学习率、warmup等)->trainer.train() 训练->trainer.evaluate() 评估

->保存 best 模型到 outputs/.../best

输出指标:

全局 accuracy、loss、f1(默认为以spoof为正类的f1)

以 spoof 为正类:precision/recall/f1

以 bonafide 为正类:precision/recall/f1

混淆矩阵:TP/TN/FP/FN

计算逻辑:

tp:预测为spoof且真实为spoof

fp:预测为spoof但真实为bonafide

fn:预测为bonafide但真实为spoof

tn:  预测为bonafide且真实为bonafide

以spoof为正类为例:

precision=tp/(tp+fp)

recall=tp/(tp+fn)

f1=2⋅precision⋅recall/(precision+recall)​

6. 最小闭环训练结果(小样本)

实验配置:train:64、dev:16、epoch:1、batch_size:2

输出结果核心:eval_accuracy = 0.8125、eval_f1 = 0.8966

模型成功保存到:outputs/wav2vec2-minimal/best

训练链路已跑通(数据加载、前向反向、验证、保存模型均正常)。

由于样本规模较小,当前指标不用于最终性能结论,后续需扩大样本并做稳定评估。

final eval metrics: {'eval_loss': 0.5625872611999512, 'eval_accuracy': 0.8125, 'eval_f1': 0.8965517235814506, 'eval_precision_spoof': 0.8124999999492187, 'eval_recall_spoof': 0.9999999999230769, 'eval_f1_spoof': 0.8965517235814506, 'eval_precision_bonafide': 0.0, 'eval_recall_bonafide': 0.0, 'eval_f1_bonafide': 0.0, 'eval_cm_tp': 13, 'eval_cm_tn': 0, 'eval_cm_fp': 3, 'eval_cm_fn': 0, 'eval_pred_spoof_count': 16, 'eval_pred_bonafide_count': 0, 'eval_true_spoof_count': 13, 'eval_true_bonafide_count': 3, 'eval_runtime': 4.1105, 'eval_samples_per_second': 3.892, 'eval_steps_per_second': 1.946, 'epoch': 1.0}

7. 小结

我已完成音频检测方向的基础工程搭建与最小训练闭环,实现了从“资源准备”到“模型可训练可保存”的完整链路。后续将从“能跑”进入“跑得准、跑得稳、可服务化”的阶段。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐