配音

Course 4:人脸识别与神经风格迁移

课程简介

Siamese 网络、Triplet Loss、神经风格迁移原理。

🎬 本课程视频:Deep Learning Specialization — 深度学习专项课程


一、人脸识别

人脸识别分为两种场景:
1. 人脸验证(Face Verification):1:1 匹配,判断两张人脸是否是同一个人
2. 人脸识别(Face Recognition):1:K 匹配,判断一张人脸是K个人中的哪一个

验证比识别简单,因为识别需要在更大的候选集中查找。

1.1 One-Shot学习

人脸识别面临的特殊挑战是One-Shot学习——每个目标只有一张参考照片,无法为每个人训练一个多类别分类器(因为新用户加入时需要不断重新训练)。

解决方案:学习一个相似度函数 $d(img1, img2)$,输出两张人脸的差异度。如果 $d < \tau$ 判定为同一人。

1.2 Siamese网络

Siamese网络由两个共享权重的相同网络组成,将输入图像映射到嵌入向量 $f(x)$:

$$|f(x^{(i)}) - f(x^{(j)})|^2$$

同一人的两张照片嵌入距离小,不同人的距离大。

1.3 Triplet Loss

Triplet Loss是训练Siamese网络的标准损失函数:

$$\mathcal{L} = \max\left(|f(A) - f(P)|^2 - |f(A) - f(N)|^2 + \alpha, 0\right)$$

其中 A=Anchor(锚点),P=Positive(同一人),N=Negative(不同人),$\alpha$ 是边距(margin)。

Loss的含义:锚点与正样本的距离加上边距要小于锚点与负样本的距离。

$$|f(A) - f(P)|^2 + \alpha \leq |f(A) - f(N)|^2$$

三元组选择技巧:选择困难的三元组(正样本不太像、负样本比较像)可以加速训练。如果随机选择,大多数三元组已经满足条件,loss为0。

FaceNet使用Triplet Loss在大规模人脸数据集上训练,在LFW数据集上达到99.63%的准确率。

1.4 人脸验证与二分类

另一种训练方法是将人脸验证视为二分类问题:输入两张人脸的嵌入向量,输出是否同一人。

$$y = \sigma\left(\sum_{k=1}^{K} w_k |f(x^{(i)})_k - f(x^{(j)})_k| + b\right)$$

这种方法在部署时更简单——只需预先计算所有用户的嵌入向量存到数据库,新用户注册时计算嵌入并查找最近邻。

1.5 人脸识别的挑战

  1. 光照变化:不同光照条件下同一人脸差异可能很大
  2. 姿态变化:正面和侧面人脸差异大
  3. 遮挡:眼镜、口罩、围巾
  4. 年龄变化:随着年龄增长人脸变化
  5. 化妆和整容

二、神经风格迁移

2.1 问题定义

神经风格迁移(Neural Style Transfer)将一张图片的内容与另一张图片的风格结合,生成新的图像。

输入:内容图像 $C$ 和风格图像 $S$
输出:生成图像 $G$

2.2 成本函数

总成本函数由内容成本和风格成本两部分组成:

$$J(G) = \alpha J_{\text{content}}(C, G) + \beta J_{\text{style}}(S, G)$$

$\alpha$ 和 $\beta$ 控制内容和风格的权重。

2.3 内容成本

使用预训练的CNN(如VGG-16)提取特征:

$$J_{\text{content}}(C, G) = \frac{1}{2}|a^{l} - a^{l}|^2$$

层 $l$ 的选择很重要:浅层保留更多细节,深层保留更多语义内容。

2.4 风格成本

风格被定义为特征图中通道间的相关性,使用Gram矩阵表示:

$$G^{l}{kk'} = \sum{i}\sum_{j} A^{l}{ijk} \cdot A^{l}{ijk'}$$

Gram矩阵的第 $(k, k')$ 个元素表示第 $k$ 个特征图与第 $k'$ 个特征图之间的相关性。

风格成本:

$$J_{\text{style}}(S, G) = \frac{1}{4n_C^2 n_H^2 n_W^2} |G^{l} - G^{l}|_F^2$$

实践中会在多个层上计算风格成本,以捕获不同尺度的风格信息。

2.5 实现流程

# 神经风格迁移简化实现
def neural_style_transfer(content_img, style_img, num_iterations=1000):
    # 加载预训练VGG模型
    model = load_pretrained_vgg()

    # 初始化生成图像为内容图像的拷贝
    generated = content_img.copy()
    generated = tf.Variable(generated)

    optimizer = tf.optimizers.Adam(learning_rate=10.0)

    for i in range(num_iterations):
        with tf.GradientTape() as tape:
            # 提取各层特征
            content_features = model(content_img)
            style_features = model(style_img)
            gen_features = model(generated)

            # 计算内容成本
            J_content = compute_content_cost(content_features, gen_features)
            # 计算风格成本
            J_style = compute_style_cost(style_features, gen_features)
            # 总成本
            J_total = alpha * J_content + beta * J_style

        # 更新生成图像的像素值
        grads = tape.gradient(J_total, generated)
        optimizer.apply_gradients([(grads, generated)])

    return generated

注意:风格迁移优化的是生成图像的像素值,而不是网络参数。

2.6 1D和3D卷积推广

卷积不仅适用于2D图像:
- 1D卷积:时间序列、音频、文本($n_H \times n_C$ 的1D特征图)
- 3D卷积:视频、医学CT扫描($n_H \times n_W \times n_T \times n_C$)

延伸阅读