共计 2889 个字符,预计需要花费 8 分钟才能阅读完成。
背景介绍
自监督学习是近年来机器学习领域的重要方向,它通过从无标注数据中自动生成监督信号来训练模型。对比学习作为自监督学习的核心范式,其核心思想是拉近相似样本(正样本对)的表示距离,同时推开不相似样本(负样本对)的表示距离。

传统对比学习方法(如 SimCLR)依赖于大量负样本构建对比任务,但负样本的采集和存储会带来计算开销和内存压力。BYOL(Bootstrap Your Own Latent)的创新之处在于完全摒弃负样本,仅通过在线网络和目标网络的交互实现特征学习。
BYOL 创新点
BYOL 与 SimCLR 等传统方法的区别主要体现在三个方面:
- 无需负样本 :通过目标网络提供的稳定表征作为学习目标,避免负样本带来的计算负担
- 非对称结构 :在线网络包含预测头,目标网络通过 EMA(指数移动平均)更新
- 目标一致性 :目标网络参数缓慢更新,为在线网络提供一致的学习目标
其核心公式可表示为:
$$\mathcal{L}{\theta,\xi} = |q\theta(z_\theta) – z’\xi|_2^2$$
其中 $q\theta$ 是在线网络的预测头,$z_\theta$ 和 $z’_\xi$ 分别是在线网络和目标网络的输出。
核心组件
1. 双分支网络结构
- 在线网络 :包含编码器 $f_\theta$ 和预测头 $q_\theta$,通过梯度下降更新
- 目标网络 :结构同在线网络(不含预测头),参数 $\xi$ 通过 EMA 更新:
$$\xi \leftarrow \tau\xi + (1-\tau)\theta$$
典型 $\tau$ 值取 0.99-0.999
2. 数据增强策略
BYOL 对同一输入应用两种随机增强:
- 全局视图:包含颜色失真、高斯模糊等强增强
- 局部视图:随机裁剪等空间变换
3. 对称损失计算
对 batch 内每个样本计算两个方向的预测误差:
$$\mathcal{L} = \frac{1}{2N}\sum_{i=1}^N (|q(z_i)-z’_i|^2 + |q(z’_i)-z_i|^2)$$
PyTorch 实现
import torch
import torch.nn as nn
import torch.nn.functional as F
class MLPHead(nn.Module):
"""BYOL 的预测头"""
def __init__(self, dim_in, hidden_size=4096, dim_out=256):
super().__init__()
self.net = nn.Sequential(nn.Linear(dim_in, hidden_size),
nn.BatchNorm1d(hidden_size),
nn.ReLU(inplace=True),
nn.Linear(hidden_size, dim_out)
)
def forward(self, x):
return self.net(x)
class BYOL(nn.Module):
def __init__(self, backbone, hidden_size=4096, pred_dim=256, tau=0.996):
super().__init__()
self.tau = tau
self.online_encoder = backbone
self.target_encoder = backbone
# 初始化目标网络与在线网络参数一致
for param_o, param_t in zip(self.online_encoder.parameters(),
self.target_encoder.parameters()):
param_t.data.copy_(param_o.data)
param_t.requires_grad = False # 目标网络不更新梯度
# 预测头
self.online_predictor = MLPHead(dim_in=backbone.output_dim,
hidden_size=hidden_size,
dim_out=pred_dim)
@torch.no_grad()
def update_target(self):
"""EMA 更新目标网络"""
for param_o, param_t in zip(self.online_encoder.parameters(),
self.target_encoder.parameters()):
param_t.data = self.tau * param_t.data + (1 - self.tau) * param_o.data
def forward(self, view1, view2):
"""
输入:
view1, view2 - 同一图像的两个增强视图
返回:
loss - 对称损失值
"""
# 在线网络前向
z1_o = self.online_encoder(view1)
z2_o = self.online_encoder(view2)
p1_o = self.online_predictor(z1_o)
p2_o = self.online_predictor(z2_o)
# 目标网络前向 (不计算梯度)
with torch.no_grad():
z2_t = self.target_encoder(view2)
z1_t = self.target_encoder(view1)
# 对称损失
loss = 0.5 * (F.mse_loss(p1_o, z2_t.detach()) +
F.mse_loss(p2_o, z1_t.detach()))
# 更新目标网络
self.update_target()
return loss
训练技巧
- 学习率设置
- 基础学习率建议 3e-4,配合线性 warmup(前 10 个 epoch)
-
使用 AdamW 优化器,weight decay 设为 1e-6
-
Batch Size 选择
- 单卡 GPU 建议 256-512,多卡可适当增大
-
过小 batch size 可能导致学习不稳定
-
训练时长
- 小数据集(如 CIFAR)约 100-200epoch
-
ImageNet 等大数据集需要 300-500epoch
-
数据增强组合
- 必须包含随机裁剪 + 颜色扰动
- 可添加高斯模糊增强鲁棒性
避坑指南
模型坍塌(Collapse)
现象 :所有样本输出相同表示(损失趋近于 0 但无意义)
解决方案 :
– 确保使用 batch normalization(BN)
– 预测头使用固定维度的输出(如 256)
– 适当增大 batch size(至少 256)
训练不稳定
现象 :损失值剧烈波动
解决方法 :
– 降低基础学习率(尝试 1e- 4 到 3e-4)
– 增加 EMA 系数 $\tau$(接近 1 的值如 0.996)
– 检查数据增强是否过于激进
延伸思考
BYOL 在实际业务中的应用潜力:
- 医学影像分析
- 解决标注数据稀缺问题
-
通过无监督预训练提升下游任务性能
-
推荐系统
- 学习用户行为序列的通用表示
-
缓解冷启动问题
-
工业质检
- 利用正常样本学习特征空间
-
异常检测时通过距离阈值判断
-
多模态学习
- 扩展为跨模态对比框架
- 对齐视觉与文本特征空间
结语
BYOL 通过巧妙的网络设计和 EMA 机制,实现了无需负样本的高效对比学习。虽然训练过程需要更多 epoch 才能收敛,但节省了显存开销,更适合实际业务部署。建议初学者先从小型数据集(如 CIFAR-10)开始实验,逐步调整超参数,体会算法的工作原理。
