返回列表

1st place solution

374. Deepfake Detection Challenge | deepfake-detection-challenge

开始: 2019-12-11 结束: 2020-04-23 AI安全与对抗 数据算法赛
第一名解决方案

保持简单

像许多其他参赛者一样,我使用了逐帧分类的方法。我尝试了很多其他复杂的方法,但最终发现只使用分类器效果更好。

数据准备

  • 使用 MTCNN 提取边界框和关键点,并将其保存为 json 格式
  • 提取原始尺寸的人脸裁剪,并将其保存为 png 格式
  • 通过真实和伪造图像的差异提取 SSIM 掩码,并将其保存为 png 格式

人脸检测器

我使用了简单的 MTCNN 检测器。人脸检测器的输入尺寸是根据每个视频的分辨率计算的。

  • 对于宽边小于 300 像素的视频,进行 2 倍放大
  • 对于宽边在 300 到 1000 像素之间的视频,不进行缩放
  • 对于宽边大于 1000 像素的视频,进行 0.5 倍缩放
  • 对于宽边大于 1900 像素的视频,进行 0.33 倍缩放

输入尺寸

当我发现 EfficientNets 的性能明显优于其他编码器时,我在解决方案中只使用了它们。因为我从 B4 开始尝试,所以我决定使用该网络的“原生”尺寸(380x380)。由于内存限制,即使对于 B7 编码器,我也没有增加输入尺寸。

边距

在生成训练用的裁剪图像时,我在每边添加了人脸裁剪尺寸 30% 的边距,并且在比赛期间只使用了这一设置。

编码器

开始时我尝试了多种 EfficientNets 变体:

  • 单独 B3 (300x300) - 公开榜单 0.29
  • 单独 B4 (380x380) - 公开榜单 0.27
  • 单独 B5 (380x380) - 公开榜单 0.25
  • 单独 B6 (380x380) - 公开榜单 0.27(令人惊讶的是,它比 B5 差,而且直到比赛最后一周我才尝试 B7)
  • 单独 B7 (380x380) - 公开榜单 0.24

最终我提交了两个结果:

  • 15xB5(不同种子),使用针对公开榜单过拟合的启发式方法,并使用标准增强进行训练 - 私有榜单第 10 名
  • 7xB7(不同种子),使用更保守的平均启发式方法,并使用硬核增强进行训练 - 私有榜单第 3 名

预测平均

每个视频我使用了 32 帧。对于每个模型的输出,我没有使用简单的平均,而是使用了以下启发式方法,这在公开榜单上效果很好(单独 B5 从 0.25 提升到 0.22)。

def confident_strategy(pred, t=0.87):
    pred = np.array(pred)
    size = len(pred)
    fakes = np.count_nonzero(pred > t)
    if fakes > size // 3 and fakes > 11:
        return np.mean(pred[pred > t])
    elif np.count_nonzero(pred < 0.2) > 0.6 * size:
        return np.mean(pred[pred < 0.2])
    else:
        return np.mean(pred)

也就是说,如果通过了某些阈值,我只使用置信度高的预测进行平均。虽然这在公开榜单上效果很好,但为了保险起见,对于第二次提交(私有榜单第 3 名),我对真实视频使用了更保守的阈值。

验证策略

起初我使用 0-2 文件夹作为留出集。但公开测试集中的 400 个视频与公开榜单有更多的相关性,所以我转而采用这种方法。

我跟踪了两个对数损失指标(基于每个视频的平均概率):

  • 真实视频的 logloss
  • 伪造视频的 logloss

从验证结果来看,伪造视频的 logloss 远低于真实视频。也就是说,伪造视频太容易被识别了。这并不令人鼓舞。我猜公开榜单也有这个特点,因为我的验证结果与公开榜单有很强的相关性。私有榜单情况并非如此,因为它包含新的/不同的 FaceSwap 方法。

数据增强