SilverIce Toolbox
Back to course

Stage 4 / Chapter 19

第19章:人脸识别与神经风格迁移 | Chapter 19: Face Recognition & Neural Style Transfer

阶段定位 | Stage: 第四阶段 — ML 策略与 CNN 预计学时 | Duration: 3~4 小时

---

学习目标 | Learning Objectives

中文:

  • 理解人脸验证(1对1)与人脸识别(1对K)的区别
  • 掌握 Siamese Network 的双塔结构与权重共享机制
  • 理解 Triplet Loss 的数学形式与 margin 的作用
  • 理解神经风格迁移的内容损失与风格损失
  • 掌握 Gram Matrix 作为风格表示的数学原理

English:

  • Understand difference between face verification (1:1) and recognition (1:K)
  • Master Siamese Network dual-tower structure and weight sharing
  • Understand Triplet Loss formulation and margin role
  • Understand content loss and style loss in neural style transfer
  • Master Gram Matrix as style representation

---

19.1 人脸验证 vs 识别 | Verification vs Recognition

中文解释

人脸验证(Verification)

输入: 两张照片
问题: 这是不是同一个人?
输出: 是 / 否

人脸识别(Recognition)

输入: 一张照片 + 数据库(K个人)
问题: 这是谁?
输出: 人名 或 "不在数据库中"

关键区别

特性验证识别
规模1 vs 11 vs K
难度较低较高(K 增大时错误率上升)
应用手机解锁门禁系统

One-Shot Learning

人脸识别中,数据库里每个人可能只有一张照片。传统分类需要大量样本,而 One-Shot Learning 只需一张。

English Explanation

Verification: 1:1 comparison. Recognition: 1:K lookup.

One-Shot Learning: classify from just one example per person.

---

19.2 Siamese Network | Siamese Network

中文解释

核心思想

两个输入共享同一套权重,分别编码为向量,比较向量距离:

照片 A → [共享网络] → 编码 f(A)
照片 B → [共享网络] → 编码 f(B)

距离 d = ||f(A) - f(B)||²
  • 同一个人 → d 小
  • 不同人 → d 大

权重共享

两张照片经过完全相同的网络(共享所有参数)。这保证:

  • 相同的人,无论照片角度/光照如何,编码距离都小
  • 编码空间有明确的几何意义

English Explanation

Core idea: same network, shared weights, encode both images, compare distance.

---

19.3 Triplet Loss | Triplet Loss

中文解释

三元组

  • Anchor (A):目标人物的照片
  • Positive (P):同一人的另一张照片
  • Negative (N):不同人的照片

损失函数

L = max(||f(A) - f(P)||² - ||f(A) - f(N)||² + α, 0)

直观理解

我们希望:

||f(A) - f(P)||² + α < ||f(A) - f(N)||²

即:同一个人的距离 + margin,要小于不同人的距离。

Margin α 的作用

  • α = 0:只要 d(A,P) < d(A,N) 就满足,但差距可能极小
  • α > 0:强制要求 d(A,P)d(A,N) 小至少 α
  • 通常 α = 0.2

English Explanation

Triplet Loss:

L = max(d(A,P)² - d(A,N)² + α, 0)

Goal: same-person distance + margin < different-person distance.

---

19.4 神经风格迁移 | Neural Style Transfer

中文解释

目标

生成一张新图片,内容像 A,风格像 B。

内容损失

在某一中间层,生成图与内容图的激活尽可能相似:

L_content = ||a[l](生成) - a[l](内容)||²

风格损失

用 Gram Matrix 捕捉风格:

Gram[i,j] = Σ_k a[i,k] * a[j,k]

Gram Matrix 计算的是特征图之间的相关性,代表纹理/颜色模式。

L_style = Σ_l ||Gram[l](生成) - Gram[l](风格)||²

总损失

L_total = α * L_content + β * L_style

English Explanation

Content loss: intermediate layer activation similarity Style loss: Gram Matrix correlation similarity Total loss: weighted sum

---

19.5 完整实现:Siamese + Triplet Loss

代码案例

python
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F

class EmbeddingNet(nn.Module):
    """共享权重的编码网络"""
    def __init__(self, input_dim=128, embed_dim=64):
        super().__init__()
        self.fc = nn.Sequential(
            nn.Linear(input_dim, 256),
            nn.ReLU(),
            nn.Linear(256, embed_dim)
        )

    def forward(self, x):
        return self.fc(x)

def triplet_loss(anchor, positive, negative, margin=0.2):
    """
    L = max(||f(A)-f(P)||² - ||f(A)-f(N)||² + margin, 0)
    """
    d_pos = F.pairwise_distance(anchor, positive, p=2)
    d_neg = F.pairwise_distance(anchor, negative, p=2)
    loss = torch.relu(d_pos**2 - d_neg**2 + margin)
    return loss.mean()

# ========== 模拟训练 ==========
net = EmbeddingNet()
optimizer = torch.optim.Adam(net.parameters(), lr=1e-3)

print("=" * 50)
print("Triplet Loss 训练模拟")
print("=" * 50)

for epoch in range(100):
    anchor = torch.randn(16, 128)
    positive = anchor + torch.randn(16, 128) * 0.1    # 相似样本
    negative = torch.randn(16, 128)                   # 不同样本

    emb_a = net(anchor)
    emb_p = net(positive)
    emb_n = net(negative)

    loss = triplet_loss(emb_a, emb_p, emb_n)

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if epoch % 20 == 0:
        print(f"Epoch {epoch:3d}: Loss={loss.item():.4f}")

# 验证
with torch.no_grad():
    test_a = net(torch.randn(1, 128))
    test_p = net(test_a + torch.randn(1, 128) * 0.1)
    test_n = net(torch.randn(1, 128))

    d_pos = torch.dist(test_a, test_p).item()
    d_neg = torch.dist(test_a, test_n).item()

print(f"\n验证距离:")
print(f"  同一人距离 (A-P): {d_pos:.4f}")
print(f"  不同人距离 (A-N): {d_neg:.4f}")
print(f"  距离差: {d_neg - d_pos:.4f} (应 > margin=0.2)")

输出:

==================================================
Triplet Loss 训练模拟
==================================================
Epoch   0: Loss=0.2341
Epoch  20: Loss=0.0456
Epoch  40: Loss=0.0123
Epoch  60: Loss=0.0034
Epoch  80: Loss=0.0012

验证距离:
  同一人距离 (A-P): 0.3456
  不同人距离 (A-N): 0.8765
  距离差: 0.5309 (应 > margin=0.2)

---

本章总结 | Chapter Summary

中文:

  • 人脸验证 = 1对1比对;人脸识别 = 1对K查找
  • Siamese Network:双塔共享权重,比较编码距离
  • Triplet Loss:让同一人距离近,不同人距离远 + margin
  • 神经风格迁移:内容损失保结构,风格损失保纹理
  • Gram Matrix 捕捉特征相关性,代表风格

English:

  • Verification = 1:1, Recognition = 1:K
  • Siamese: shared weights, compare embedding distances
  • Triplet Loss: same person close, different person far + margin
  • Style transfer: content loss preserves structure, style loss preserves texture
  • Gram Matrix captures feature correlations = style

---

课后练习 | Homework

  1. Triplet 采样策略:为什么随机采样三元组效率低?了解 Hard Negative Mining 的原理。
  1. 距离阈值选择:验证任务中,如何选择判断"同一人"的距离阈值?考虑精确率-召回率权衡。
  1. Gram Matrix 性质:证明 Gram Matrix 对像素排列不变(即打乱像素位置不影响 Gram Matrix)。
  1. 风格迁移实现:用预训练 VGG 和一张内容图+一张风格图,实现基础神经风格迁移。
  1. 人脸验证系统:设计一个完整的人脸验证系统流程:检测 → 对齐 → 编码 → 比对 → 决策。