首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >鲁棒性测试理论案例

鲁棒性测试理论案例

作者头像
顾翔
发布2026-09-09 19:36:11
发布2026-09-09 19:36:11
1150
举报

1.理论知识

1.1.鲁棒性测试定义

在人工智能领域,鲁棒性(Robustness,又称健壮性)有着比传统软件测试更深刻的含义。

核心定义:鲁棒性是指AI系统在面对输入数据的微小变化、噪声干扰、恶意攻击(对抗性样本)或数据分布偏移(Distribution Shift)时,仍然能够维持其既定性能水平(如准确率、精确率)和功能有效性的能力。

如果用一句话概括:鲁棒性衡量的是AI在"异常情况"下不犯致命错误的能力。一个鲁棒的模型,不仅要在"标准考场"上拿高分(测试集表现好),更要在"刮风下雨、监考老师换人甚至卷子被涂改"时,依然给出合理答案。

为了让你更精准地理解,我们可以从三个层级来拆解AI鲁棒性的内涵:

1.2. 输入扰动鲁棒性(最基础层面)

指模型对输入数据中非语义性的随机噪声或微小变化的容忍度。

例子:给一张猫的图片加上肉眼几乎看不见的随机噪点,或者图片稍微旋转、变亮一点。鲁棒的模型依然能坚定地判断出这是"猫",而不是瞬间错判成"狗"。

1.3. 分布外(OOD)鲁棒性(实际落地核心)

指模型应对"训练数据分布"与"实际应用数据分布"不一致的能力。这是工业界最常遇到的挑战,因为现实世界的数据是动态变化的。

例子:一个用夏天数据训练的行人检测模型,在冬天大雪覆盖的场景下部署。鲁棒的模型即使识别率略有下降,但不会完全"失明";而不鲁棒的模型会因为雪花的干扰产生大量误报。

1.4. 对抗性鲁棒性(安全层面)

这是AI特有的安全问题,指模型面对蓄意设计的、为欺骗模型而优化的对抗性样本时的防御能力。这类扰动对人类感官来说往往毫无区别,但对AI却极具杀伤力。

例子:一个在图像识别中达到99%准确率的模型,只要在熊猫图片上叠加一层精心计算过的微小噪声矩阵,模型就会以99.9%的置信度将其误判为"长臂猿"。

1.5特别补充

在学术和工程界,鲁棒性通常与稳定性(Stability)和泛化性(Generalization)有微妙区别:

  • 泛化性关注模型在"没见过的同分布数据"上的表现(新试卷)。
  • 鲁棒性更关注模型在"分布改变、数据受损"时的表现(被涂改的试卷)。

最后,一个常用的衡量指标是鲁棒准确率(Robust Accuracy),它通常在对抗性攻击(如PGD攻击)或添加高斯噪声后计算得出。如果模型在纯净数据上的准确率是95%,在被攻击后掉到了30%,就说明其鲁棒性极差------这在自动驾驶、医疗诊断等高风险领域是不可接受的。

2.实践

2.1 维度

2.1.1 文本

问:

代码语言:javascript
复制
public int add(int a,int b){
	//a为被加数,b为加数,return为和
	int result = a + b;
	return int;
}

请给出add()方法的JUnit5测试函数,其他描述性语句不要输出,我不关心。

我们只需要输出JUnit5测试函数代码,不要其他描述。注意原方法有语法错误(return int应该是return result),但测试函数应该针对正确的方法。我们假设方法正确为return result。给出测试代码。

代码语言:javascript
复制
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class AddTest {
	@Test
	void testAddPositiveNumbers() {
		assertEquals(5, add(2, 3));
	}
	@Test
	void testAddNegativeNumbers() {
		assertEquals(-5, add(-2, -3));
	}
	@Test
	void testAddMixedNumbers() {
		assertEquals(0, add(-3, 3));
	}
	@Test
	void testAddZero() {
		assertEquals(3, add(0, 3));
		assertEquals(3, add(3, 0));
	}
	private int add(int a, int b) {
		int result = a + b;
		return result;
	}
}

2.1.2 图像

使用1.jepg图片,利用下面方法加上高斯噪音,生成2.jepg图片

add_noise.py

代码语言:javascript
复制
import cv2
import numpy as np
def **add_gaussian_noise**(image_path, output_path, mean=0, std_dev=25):

给图像添加高斯噪声

  • param image_path: 输入图片路径
  • param output_path: 输出图片路径
  • param mean: 高斯噪声的均值,通常为0
  • param std_dev: 高斯噪声的标准差, 控制噪声强度
代码语言:javascript
复制
# 1. 读取图像 (这里以灰度图为例,如需彩色图可修改)
image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
# 2. 生成与图像尺寸相同的高斯噪声
normal(均值, 标准差, 图像形状)
noise = np.random.normal(mean, std_dev, image.shape)
# 3. 将噪声添加到原图像
noisy_image = image + noise
# 4. 将像素值裁剪到 0-255 的有效范围并转换数据类型
noisy_image = np.clip(noisy_image, 0, 255).astype(np.uint8)
# 5. 保存结果图像
cv2.imwrite(output_path, noisy_image)
# 使用示例
add_gaussian_noise(\'1.jpeg\', \'2.jpeg\', mean=0, std_dev=50)

问:请告诉我这两张照片是同一女人吗?

答:

是的,是同一个人(或者说,是同一个 AI 生成的人物形象)。

您可以仔细观察并对比以下细节:

完全相同:发型、五官、面部表情、站姿、手臂和手的位置,以及那件浅蓝色的短袖圆领A字连衣裙的剪裁、腰线和裙摆褶皱,在两图中完全吻合

水印一致:两张图片右下角都有**"百度AI生成"**的水印,说明它们出自同一个 AI 绘画程序。

仅有的区别:第二张照片并不是不同的人物或不同的场景,而仅仅是将第一张照片(彩色原图)进行了黑白/灰度处理,并叠加了一层非常重的"雪花噪点"滤镜

所以,两张图底层的图像信息是百分之百一致的。

2.1.3 音频

现在分析音频的软件比较少。

1.录制本人的文件1.m4p与2.m4p

2.>pip install speechbrain torchaudio pydub

3.ffmpeg -version

如果没有版本信息,请安装ffmpeg

4. compare_voice.py

代码语言:javascript
复制
import os
# 关键修复:强制 SpeechBrain 使用 COPY 模式,避免 Windows 权限错误
os.environ\['SB_LOCAL_STRATEGY'] = 'COPY'
import torch
import speechbrain as sb
from speechbrain.inference.speaker import EncoderClassifier
from pydub import AudioSegment
import sys
# 1. 加载预训练的声纹识别模型(ECAPA-TDNN,VoxCeleb数据集训练)
print("正在加载声纹识别模型,请稍候(首次运行可能会下载几百MB的模型文件)...")
classifier = EncoderClassifier.from_hparams(
source="speechbrain/spkrec-ecapa-voxceleb",
savedir="pretrained_models/spkrec-ecapa-voxceleb"
)
# 2. 辅助函数:将 m4a 转为 16kHz 单声道 wav 临时文件
def convert_m4a_to_wav(m4a_path, wav_path):
	try:
		audio = AudioSegment.from_file(m4a_path, format="m4a")
		audio = audio.set_frame_rate(16000).set_channels(1)
		audio.export(wav_path, format="wav")
		return True
	except Exception as e:
		print(f"格式转换失败: {e}")
		return False
# 3. 核心函数:提取声纹特征向量(Embedding)
def extract_embedding(audio_path):
	tmp_wav_path = audio_path.replace(".m4a", "_tmp.wav")
	if audio_path.endswith(\'.m4a\'):
		if not convert_m4a_to_wav(audio_path, tmp_wav_path):
			return None
			audio_file = tmp_wav_path
		else:
			audio_file = audio_path
		try:
			signal = sb.dataio.dataio.read_audio(audio_file)
			batch = signal.unsqueeze(0)
			embedding = classifier.encode_batch(batch, normalize=True)
			return embedding.squeeze()
		except Exception as e:
			print(f"读取音频或提取特征失败: {e}")
			return None
		finally:
			if audio_path.endswith(\'.m4a\') and os.path.exists(tmp_wav_path):
				os.remove(tmp_wav_path)
# 4. 对比两个音频文件
def compare_audio_files(file1, file2):
	print(f\"正在分析: {os.path.basename(file1)} {os.path.basename(file2)}\")
	emb1 = extract_embedding(file1)
	emb2 = extract_embedding(file2)
	if emb1 is None or emb2 is None:
		print(\"分析失败,请检查音频文件是否损坏。\")
		return 
	similarity = torch.nn.functional.cosine_similarity(emb1,emb2,dim=0).item()
	print(\"-\" \* 30)
	print(f\"声纹相似度得分: {similarity:.4f}\")
	print(\"-\" \* 30)
	if similarity \> 0.75:
		print(\"结论:极大概率是同一个人说话 (相似度 \> 0.75)\")
	elif similarity \> 0.60:
		print(\"结论:可能是同一个人,但需要更长时间语音片段确认 (0.600.75)\")
	else:
		print(\"结论:大概率是不同的人说话 (相似度 \< 0.60)\")
# ================== 使用方法 ==================
if __name__ == "__main__":
	\# 检查是否传入了文件参数
	if len(sys.argv) \< 3:
		print(\"请指定两个音频文件的路径。\")
		print(\"用法示例: python compare_voice.py file1.m4a file2.m4a\")
		sys.exit(1)
	audio_file_1 = sys.argv\[1\]
	audio_file_2 = sys.argv\[2\]
	compare_audio_files(audio_file_1, audio_file_2)

5.用管理员模式打开cmd

c:\Users\xiang\Desktop>python compare_voice.py 1.m4a 2.m4a

正在加载声纹识别模型,请稍候(首次运行可能会下载几百MB的模型文件)...

C:\Users\xiang\AppData\Local\Programs\Python\Python312\Lib\site-packages\speechbrain\utils\parameter_transfer.py:234: UserWarning: Requested Pretrainer collection using symlinks on Windows. This might not work; see LocalStrategy documentation. Consider unsetting collect_in in Pretrainer to avoid symlinking altogether.

warnings.warn(

正在分析: 1.m4a 和 2.m4a

------------------------------

声纹相似度得分: 0.1431

------------------------------

结论:大概率是不同的人说话 (相似度 < 0.60)

显然结果是错误的

2.2.模糊(Fuzzing)测试

1.pip install torch torchvision matplotlib foolbox foolbox-native

2.原图片stop.jpg。

3.LLM识别stop.jpg中的文字正确。

4.使用Foolbox库对原图片生成Linf对抗扰动。

5.输出stack.jpg

6.LLM识别stack.jpg中的文字正确

2.3.蜕变测试

2.3.1案例1

问:今天是2026年8月6日,星期四,请告诉我今天上海的天气。

答:今天是2026年8月6日,星期四,上海的天气是多云到阴,伴有分散性短时阵雨或雷雨,局部地区雨量可能达到大雨级别。

具体的天气信息如下:

  • 气温:早晨气温在29℃附近,预计白天最高气温在34-35℃。
  • 风力:东北风4-5级,沿江沿海地区阵风可达6级。
  • 湿度:相对湿度在55%-90%之间,体感会比较闷热。
  • 空气质量:优。

受偏东气流影响,今天阵雨多发,短时降水可能比较明显。出门记得随身携带雨具,并注意防暑防雨。

另外,从周五(8月7日)开始,上海将受台风"白海豚"外围影响,会迎来持续的大风天气,雨水也会比较频繁。

问:今天是2026年8月6日,星期四,请告诉我今天的天气,上海的

答:上海今天(2026年8月6日,周四)是多云到阴,有分散性短时阵雨或雷雨的天气。

具体的天气信息如下:

  • 气温与体感:早晨气温在29℃附近,预计白天最高气温在34-35℃。由于相对湿度高达55%-90%,体感会比较闷热。
  • 降雨与风力:局部地区雨量可能达到大雨级别。吹的是东北风4-5级,沿江沿海地区阵风可达6级。

此外,受台风"白海豚"外围影响,从明天(周五)开始上海将转为持续的大风天气,未来几天雨水也会比较频繁。今天出门别忘了带上雨具,并注意防暑防雨。

分析

第二次没有空气质量

其他内容基本相同

2.3.2案例2

问:你是谁

答:嗨!我是 DeepSeek,由深度求索公司创造的AI助手!

简单介绍一下我自己:

  • 知识储备:截止到2026年5月,我知道不少东西,但最新动态可能需要联网搜索(记得手动开启哦)
  • 多才多艺:能读文件(图片、PDF、Word、Excel、PPT 等)、处理长文本(1M 上下文,相当于《三体》三部曲的体量!)
  • 完全免费:目前没有任何收费计划,放心使用!
  • 平台多样:网页版、App都有,App还支持语音输入

我的使命就是帮你解决问题、提供信息、陪你聊天------无论是学习、工作还是生活琐事,尽管问我!

有什么我可以帮你的吗?

问:你是哪一位

答:你好呀!我是 DeepSeek,由深度求索公司创造的AI助手。

你可以把我当作一个随时在线的小伙伴,知识截止到2026年5月,目前是免费使用的。我支持长文本处理(上下文1M)、文件上传(图片、PDF、Word、Excel等),还能联网搜索(不过需要你手动在Web或App端点开联网按钮)。

分析

显然第二次回答的信息含量比第一次大。

2.3.3案例3

问:

代码语言:javascript
复制
public int add(int a,int b){**
//a为被加数,b为加数,return为和
int result = a + b;
	return result;
}

请给出add()方法的JUnit5测试函数,其他描述性语句不要输出,我不关心。

答:

代码语言:javascript
复制
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class AddTest {
	@Test
	void testAddPositiveNumbers() {
		assertEquals(5, add(2, 3));
	}
	@Test
	void testAddNegativeNumbers() {
		assertEquals(-5, add(-2, -3));
	}
	@Test
	void testAddMixedNumbers() {
		assertEquals(0, add(-3, 3));
	}
	@Test
	void testAddZero() {
		assertEquals(3, add(0, 3));
		assertEquals(3, add(3, 0));
	}
	private int add(int a, int b) {
		int result = a + b;
		return result;
	}
}

分析

输出结果基本相同。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-08-07,如有侵权请联系 cloudcommunity@tencent.com 删除
目录
  • 1.理论知识
    • 1.1.鲁棒性测试定义
    • 1.2. 输入扰动鲁棒性(最基础层面)
    • 1.3. 分布外(OOD)鲁棒性(实际落地核心)
    • 1.4. 对抗性鲁棒性(安全层面)
    • 1.5特别补充
  • 2.实践
    • 2.1 维度
      • 2.1.1 文本
      • 2.1.2 图像
      • 2.1.3 音频
    • 2.2.模糊(Fuzzing)测试
    • 2.3.蜕变测试
      • 2.3.1案例1
      • 2.3.2案例2
      • 2.3.3案例3
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档