如何使用Python3对比原始音频与对抗样本提取扰动生成perturbation.wav
嘿,这个需求其实很好实现——对抗样本里的扰动本质上就是带扰动音频与原始音频的差值,直接用Python做减法就行!下面给你两种实用的实现方式,你可以根据自己的环境选:
方法一:用Python标准库
wave(无需额外安装) 如果不想装第三方库,用Python自带的wave模块就能搞定,核心思路是把音频帧转换成数值数组,做差值后再写回文件:
import wave import numpy as np def extract_perturbation(original_path, attacked_path, output_path): # 打开两个音频文件 with wave.open(original_path, 'rb') as orig_wav, wave.open(attacked_path, 'rb') as att_wav: # 先检查两个音频的参数必须完全一致(采样率、位深、声道数、长度) assert orig_wav.getparams() == att_wav.getparams(), \ "Error: 两个音频的参数(采样率、位深、声道数等)必须完全匹配才能提取扰动!" # 读取所有音频帧 orig_frames = orig_wav.readframes(-1) att_frames = att_wav.readframes(-1) # 根据位深选择对应的数据类型 sample_width = orig_wav.getsampwidth() if sample_width == 1: dtype = np.uint8 offset = 128 # 8位音频是无符号,要转成有符号计算 elif sample_width == 2: dtype = np.int16 offset = 0 elif sample_width == 4: dtype = np.int32 offset = 0 else: raise ValueError(f"不支持的音频位深:{sample_width}字节") # 把字节数据转成数值数组 orig_data = np.frombuffer(orig_frames, dtype=dtype) - offset att_data = np.frombuffer(att_frames, dtype=dtype) - offset # 计算扰动:带扰动音频 - 原始音频 perturbation_data = att_data - orig_data # 转换回原始位深的字节格式 perturbation_data += offset perturbation_frames = perturbation_data.astype(dtype).tobytes() # 写入输出文件 with wave.open(output_path, 'wb') as out_wav: out_wav.setparams(orig_wav.getparams()) out_wav.writeframes(perturbation_frames) # 调用函数,替换成你的文件路径 extract_perturbation("original.wav", "attacked.wav", "perturbation.wav")
注意事项:
- 对抗样本攻击生成的
attacked.wav通常和original.wav参数完全一致,所以断言一般不会触发,但如果不一致,你需要先把两个音频转成相同参数(比如用FFmpeg转码)。 - 8位音频是无符号类型,所以要减去128转成有符号数再计算,避免溢出。
方法二:用
librosa(更简洁,适合复杂场景) 如果你经常处理音频,librosa会让代码更简洁,它会自动处理位深、声道等细节,不过需要先安装依赖:
pip install librosa soundfile
实现代码:
import librosa import soundfile as sf def extract_perturbation_librosa(original_path, attacked_path, output_path): # 读取音频,sr=None表示保留原始采样率 orig_data, sr = librosa.load(original_path, sr=None, mono=False) att_data, _ = librosa.load(attacked_path, sr=sr, mono=False) # 检查音频形状是否一致 assert orig_data.shape == att_data.shape, \ "Error: 两个音频的声道数和长度必须一致!" # 直接计算扰动 perturbation_data = att_data - orig_data # 写入输出文件:注意librosa返回的是(声道数, 采样点数),soundfile需要转成(采样点数, 声道数) sf.write(output_path, perturbation_data.T, sr) # 调用函数 extract_perturbation_librosa("original.wav", "attacked.wav", "perturbation.wav")
额外提示:
- 提取出来的扰动音频大概率是人类几乎听不到的噪音,这是正常的——对抗扰动本来就是精心设计的、不影响听觉但能误导模型的微小信号。
- 如果需要调整扰动的音量,可以给
perturbation_data乘以一个系数(比如perturbation_data * 10),但注意不要超出音频的数值范围(浮点型是[-1,1])。
内容的提问来源于stack exchange,提问作者Alexis
相关产品推荐
相关产品推荐

