在 opencv_contrib 中复现 "Deep Neural Networks are Easily Fooled":基于 Caffe 与 Sferes 的深度网络愚弄图像生成实验指南
在 opencv_contrib 中复现 "Deep Neural Networks are Easily Fooled":基于 Caffe 与 Sferes 的深度网络愚弄图像生成实验指南
本指南围绕 opencv_contrib 仓库中的 dnns_easily_fooled 模块,系统讲解如何复现 CVPR 2015 论文《Deep Neural Networks are Easily Fooled: High Confidence Predictions for Unrecognizable Images》中的"愚弄图像"(fooling images)实验。你将掌握两条核心生成路线(进化算法与梯度上升)的依赖环境、下载安装脚本、MNIST/ImageNet 实验的运行方式、网络结构配置文件,以及常见的调参与排障手段,最终能够在本地或集群上独立生成让深度网络以高置信度误判的不可识别图像。
模块定位与论文背景
dnns_easily_fooled 是 opencv_contrib 中一个特殊用途的模块:它并非常规的 OpenCV 图像处理贡献模块,而是一套独立的学术复现代码库,用于重现 2015 年 CVPR 论文中展示的"愚弄图像"。其核心发现是:深度神经网络会对人类完全无法识别(甚至看起来就是随机噪声)的图像,给出极高的类别置信度预测。该论文由 Nguyen A、Yosinski J 与 Clune J 合作完成,对应引用格式如下:
@inproceedings{nguyen2015deep,
title={Deep Neural Networks are Easily Fooled: High Confidence Predictions for Unrecognizable Images},
author={Nguyen, Anh and Yosinski, Jason and Clune, Jeff},
booktitle={Computer Vision and Pattern Recognition (CVPR), 2015 IEEE Conference on},
year={2015},
organization={IEEE}
}
模块的说明文档即 modules/dnns_easily_fooled/README.md,其中明确要求:若在学术论文中使用本软件,请引用上述文献。从仓库结构看,本模块没有 CMakeLists.txt,不参与 OpenCV 的常规构建流程,也不属于"构建 OpenCV + extra modules"时的编译单元;它的运行依赖两套外部下载的补丁框架(Caffe 与 Sferes),本质上是一个独立的可执行实验工程。
两种愚弄图像生成方法
论文复现代码提供了两条相互独立的技术路线,分别对应论文中的不同图组:
| 方法 | 核心思想 | 对应论文图 | 所需框架 |
|---|---|---|---|
| 进化算法(EA)+ MAP-Elites | 通过进化搜索在高维图像空间中寻找让网络输出高置信度的"不可识别"图像 | 图 4、5(MNIST)、图 8(ImageNet) | Caffe + Sferes |
| 梯度上升(Gradient Ascent) | 从噪声或真实图像出发,沿分类器输出概率的梯度方向迭代修改像素 | 图 13、S3、S4、S5、S6、S7 | Caffe(ascent 分支) |
两种方法共用 Caffe 作为深度网络推理后端,但需要不同版本的 Caffe 补丁:EA 实验使用 download_caffe_evolutionary_algorithm.sh 下载的版本,梯度上升实验使用 download_caffe_gradient_ascent.sh 下载的版本。README 特别强调:这两套框架都是作者打了补丁的定制版本,加入了论文复现所需的额外工作,与它们各自的 master 分支并不相同,不能直接替换。
环境与依赖要求
README 明确列出了两套软件包的运行环境。需要特别说明的是,这些版本号(CUDA 6.0、Boost 1.52、g++ 4.6/4.9、OpenCV 2.4.10)来自 2015 年前后的实验环境,属于历史性约束;在当代系统上复现时,你需要自行完成新旧工具链的兼容适配,仓库本身并未提供现代环境的替代方案。
Caffe(EA 与梯度上升共用基础)
- 官网渠道:Caffe(Berkeley Vision 项目)官方发布版
- 本模块为其编译安装的配套库版本:CUDA 6.0、Boost 1.52、g++ 4.6
- 通过仓库内的下载脚本获取与实验匹配的正确 Caffe 版本:
- download_caffe_evolutionary_algorithm.sh——EA 实验专用版本
- download_caffe_gradient_ascent.sh——梯度上升实验专用版本
Sferes 2(EA 实验专用)
- Sferes 是一个 C++ 进化算法框架(Sferes 2 是其第二代实现)
- 本模块为其编译安装的配套库版本:OpenCV 2.4.10、Boost 1.52、g++ 4.9(要求支持 C++11 标准的编译器)
- 通过 download_sferes.sh 下载正确版本
下载与安装:三个脚本的用途
仓库根目录下提供了三个一键下载脚本,它们都以 wget 拉取 Evolving-AI-Lab/fooling 仓库对应分支的 zip 包,解压后将所需的 caffe 或 sferes 目录移动到当前目录,并清理临时文件。
download_caffe_evolutionary_algorithm.sh 与 download_sferes.sh 均下载 master.zip,分别把其中的 caffe/ 与 sferes/ 目录就地展开;download_caffe_gradient_ascent.sh 则下载 ascent.zip(fooling 仓库的 ascent 分支),把其中的 caffe/ 目录展开。三个脚本的执行逻辑一致,以 EA 版 Caffe 脚本为例:
# 若当前目录已存在 ./caffe,脚本会拒绝执行并要求手动移除后重跑
wget <fooling 仓库 master.zip>
unzip master.zip
mv ./fooling-master/caffe ./
# 清理临时文件
也就是说,运行顺序大致为:先执行对应脚本下载 Caffe/Sferes,再按照 Installation_Guide.pdf 完成框架编译与配置。安装指南以 PDF 形式随仓库分发,建议完整阅读后再开始编译,其中包含两套框架的详细构建步骤。
运行实验:MNIST 与 ImageNet
MNIST 快速实验(论文图 4、5)
MNIST 实验是快速验证整条链路的最佳入口。README 给出的量化预期是:在一台 4 核本地机器上,运行 200 代(generations)大约只需要 5 分钟甚至更短。这对于首次接触该代码库的开发者非常友好,可以在投入集群资源之前先验证环境与代码是否就绪。
MNIST 实验的主程序为 sferes/exp/images/dl_map_elites_images_mnist.cpp(位于脚本下载得到的 Sferes 目录中),其关键配置点包括:
- 进化代数:默认按 200 代配置即可完成快速验证;
- 评估方式:通过注释/取消注释对应代码行(README 指出约在第 190–191 行)在
eval::Eval(单核本地模式)与eval::Mpi(集群分布式模式)之间切换,详见下文"MPI 与非 MPI 模式"; - 网络与数据:MNIST 实验使用本仓库 modules/dnns_easily_fooled/model/lenet/ 下的 LeNet 预训练模型与 MNIST 均值文件。
ImageNet 大规模实验(论文图 8)
ImageNet 实验的规模要求则完全不同。README 给出的数据是:约 4 天 × 128 核的集群算力,运行 5000 代,最终产出 1000 张愚弄图像。这意味着:
- 该实验必须在集群环境(MPI)下运行,单机无法在合理时间内完成;
- 你需要准备 AlexNet 等 ImageNet 预训练模型(README 指明 AlexNet 模型可从 Caffe Model Zoo 获取);
- 实验输出规模较大,需要规划磁盘与结果管理策略。
ImageNet 实验对应程序为 sferes/exp/images/dl_map_elites_images.cpp。
配置一个快速测试实验
README 还给出了一个"快速测试进化框架"的实践指引:为了在投入大规模运行前验证框架本身工作正常,可以先将实验配置缩减到极小规模(例如降低进化代数、缩小种群),跑通 MNIST 这类轻量任务。这与上文 MNIST 实验"约 5 分钟跑 200 代"的定位相互印证——先用小任务验证框架可用,再扩展到 ImageNet 规模。
梯度上升实验复现(论文图 13、S3–S7)
梯度上升实验与 EA 实验相互独立,复现步骤如下:
- 使用 download_caffe_gradient_ascent.sh 下载对应的 Caffe 版本(
ascent分支补丁); - 按照该分支
caffe/ascent目录下的文档完成编译与运行配置; - 该路线不依赖 Sferes,仅依赖 Caffe 前向/反向传播完成像素迭代优化。
梯度上升的思路与进化算法截然不同:它从一个初始图像出发,计算分类器对目标类别的置信度关于输入像素的梯度,沿梯度上升方向反复微调图像,直到网络以高置信度输出目标类别。由于该方法天然可解释、计算路径清晰,适合作为理解"愚弄图像"机理的入门实验。
预训练模型与网络结构配置
仓库 modules/dnns_easily_fooled/model/ 目录下随附了实验所需的模型文件与网络定义,分为 MNIST 与 ImageNet 两套。
LeNet(MNIST)
modules/dnns_easily_fooled/model/lenet/ 目录包含:
lenet_image_memory_data.prototxt:LeNet 网络结构定义(IMAGE_DATA 数据层);lenet_iter_10000:训练 10000 次迭代后的预训练权重(caffemodel 格式,无扩展名),README 明确指出 LeNet 模型可直接在本模块中获取;mnist_mean.binaryproto:MNIST 数据集均值文件;mnist_image_list.txt:图像列表示例,内容形如<mnist_sample_image.png 路径> 0,即一张标签为 0 的 MNIST 样本;mnist_sample_image.png:28×28 的 MNIST 样例图像。
网络结构(lenet_image_memory_data.prototxt)为经典 LeNet-5 变体:data 层以 IMAGE_DATA 类型读取单张 28×28 灰度图,scale: 0.00390625(即 1/256,将 0–255 像素归一化到 0–1);随后依次为 conv1(20 个 5×5 卷积核)、pool1(2×2 最大池化)、conv2(50 个 5×5 卷积核)、pool2(2×2 最大池化)、ip1(500 维全连接 + ReLU)、ip2(10 维全连接,对应 10 个数字类别)与 prob(Softmax 输出概率)。
需要注意:prototxt 中的 source 与 mean_file 指向的是作者原机器上的绝对路径(如 /project/EvolvingAI/anguyen8/model/...)。实际运行前,必须把这两处路径改为你本地 model/lenet 目录的实际位置,这也是 MNIST 快速实验最容易踩到的配置点。
CaffeNet(ImageNet)
modules/dnns_easily_fooled/model/imagenet_deploy_image_memory_data.prototxt 定义了 ImageNet 实验所用的 CaffeNet(AlexNet 的 Caffe 实现)结构:
data层:IMAGE_DATA类型,batch_size: 10,crop_size: 227,输入 256×256 彩色图(images_in_color: true),mirror: false;- 卷积主干:
conv1(96 个 11×11 卷积核、步长 4)+ ReLU + 3×3 最大池化 + LRN;conv2(256 个 5×5 卷积核、分组 2、pad 2)+ 池化 + LRN;conv3(384 个 3×3);conv4(384 个 3×3);conv5(256 个 3×3)+ 池化; - 分类头:
fc6(4096 维,带 ReLU 与 0.5 比率 Dropout)、fc7(4096 维,带 ReLU 与 Dropout)、fc8(1000 维,对应 ImageNet 1000 类)与probSoftmax。
modules/dnns_easily_fooled/model/image_list.txt 给出了该数据层的图像列表格式示例:<hen_256.png 绝对路径> 1,其中 hen_256.png(256×256)是仓库中随附的示例输入图(一只母鸡的常规照片,用作 ImageNet 实验的输入样本),标签为 1。同样地,image_data_param.source 与 mean_file 中的绝对路径需要在本地环境中改写;AlexNet 预训练权重按 README 指引从 Caffe Model Zoo 获取。
调参与监控
动态库查找问题
若 Sferes(Waf 构建系统)找不到 CUDA 与 Caffe 的动态库,README 给出了两种解决办法:
- 在
exp/images对应的 wscript 中为obj.libpath添加路径,使其能找到libcudart与libcaffe; - 或者直接使用 Linux 环境变量
LD_LIBRARY_PATH指定动态库搜索路径。
监控实验进度
进化算法的运行时间较长(尤其 ImageNet 实验动辄数天),README 指出代码内置了每运行 N 代打印一次结果(适应度 fitness + 图像) 的开关,可通过调整 dump_period 设置来控制输出频率。该参数位于下载得到的 Sferes 代码中 sferes/exp/images/dl_map_elites_images.cpp(README 标注约在第 159 行)。合理设置 dump_period 既能及时观察进化进程,又不会因频繁落盘拖慢运行速度。
MPI 与非 MPI 模式
README 明确回答了"没有 MPI 如何在本地运行"的问题:在 sferes/exp/images/dl_map_elites_images_mnist.cpp(约第 190–191 行)中,通过注释/取消注释一行即可切换:
eval::Eval:单核评估,适用于本地快速验证(对应 MNIST 5 分钟实验);eval::Mpi:分布式评估,适用于集群上的 ImageNet 大规模实验。
两种模式共用同一份实验代码,仅评估后端不同,这为"本地调通 → 集群全量运行"的工作流提供了极大便利。
结语与进一步阅读
dnns_easily_fooled 模块完整承载了 CVPR 2015 论文的复现代码:进化算法路线(Caffe + Sferes + MAP-Elites)与梯度上升路线(Caffe ascent 分支)双线并行,MNIST 快速实验与 ImageNet 集群实验覆盖了从本地验证到大规模复现的完整谱系。仓库随附的 README、安装指南 PDF、三个下载脚本与 model 目录 构成了可闭环的复现环境。论文的更多背景信息可参见作者团队主页(www.evolvingai.org/fooling),该研究对深度网络可解释性与鲁棒性研究具有里程碑意义——它直观地证明了"高置信度 ≠ 正确理解",这一结论至今仍是对抗样本与模型安全研究的重要出发点。