Series · Transfer Learning · Chapter 1

迁移学习(一):基础与核心概念

迁移学习入门指南:为什么迁移有效、形式化定义、分类体系、负迁移,以及一个基于 MMD 域适应的完整特征迁移实现。

你刚刚花了两周时间,在一整柜 GPU 上训练出一个 ImageNet 分类器。周一早上,老板让你做一个胸片肺炎识别模型——而手里全部的标注数据只有 200 张。难道再排两周机器,从零再训一遍?

当然不会。你会把 ImageNet 模型已经学到的边缘、纹理和形状直接搬过来,换掉最后一层,在 X 光片上微调。两小时后,这个模型的表现远远超过任何用同样少量数据从头训练的版本。这就是迁移学习,也是大多数真实深度学习项目能在几天内交付而不是拖几个月的关键原因。

本文是整个系列的基石。在进入任何更专门的话题之前,你需要先把以下七件事弄清楚:

  1. 为什么从头训练往往不可行
  2. 域、任务、源域与目标域的形式化定义
  3. 三种分类体系——归纳、直推、无监督;
  4. 深度网络中哪些层可以迁移
  5. 负迁移:借来的知识反而拖后腿的情形;
  6. Ben-David 界MMD——如何判断迁移到底行不行;
  7. 一个完整、可跑的 MMD 特征对齐实现。

前置知识: 基本机器学习概念(损失函数、梯度下降、分类)以及能读懂 Python。


1. 为什么需要迁移学习

从头训练的困境

教科书式的监督学习流程默认了三件事,但它们在工业场景里几乎从来不成立:

  • 海量标注数据。 现代深度网络要泛化得好,往往需要上万到数百万条标注样本,真实业务团队鲜有这种规模。
  • 充裕的算力。 从随机初始化训练一个 ResNet-50 需要数百 GPU 小时,从零训练一个 Transformer 动辄上万 GPU 小时。
  • 知识无法复用。 即使是关系密切的任务——胸片 X 光与胸片 CT——也得各自从零开始。

而真实医学场景给你的是:罕见疾病只有几百个病例、标注必须由具备执业资格的医生完成、deadline 以"周"计。迁移学习给出的承诺很简单:拿一个在大规模通用数据上训练好的模型,低成本地适配到你的小数据任务上。

下面这张图直观展示了"小数据 + 分布偏移"到底长什么样:同样两类数据,目标域被旋转和平移过——这正是从 ImageNet 自然图迁到医学影像、或者在不同医院扫描仪之间迁移时常见的协变量偏移(covariate shift)的卡通版。

源域与目标域的分布偏移

直觉

人类一直在做知识迁移:

  • 会骑自行车的人,下午就能学会骑摩托车,不需要一年。
  • Python 程序员看到 Java,能立刻认出类、循环和异常机制。
  • 见过家猫的人,第一次看到狮子也会立刻判断为"某种猫科动物"。

深度网络具有同样的特性。视觉模型靠前的卷积层学到的是几乎"放之四海而皆准"的原始表示——有方向的边缘、色块、简单纹理,这些对几乎任何视觉任务都有用。靠后的层学到的是更专门的概念(毛皮花纹、眼睛形状),但在相关域之间也常常可以复用。迁移学习的工程纪律,就是把这种重叠最大化地利用起来。

一句话讲清核心思想

给定一个有大量标注数据的源域和一个几乎没有标注的目标域,迁移学习把源域的知识搬过来,让目标模型表现得比单独训练时更好。

唯一的硬性条件是:源域和目标域之间要有一定的相关性。它们不必共享同一特征空间、同一标签集,甚至不必同一模态——但共享得越多,可迁移的就越多。


2. 形式化定义

要把迁移学习讲精确,必须先把两个新手常常混淆的概念分开:说的是"输入长什么样";任务说的是"要预测什么"。Pan 和 Yang 在 2010 年的综述里把这条边界确立为整个领域的基石。

域是一个二元组 $\mathcal{D} = \{\mathcal{X}, P(X)\}$:$\mathcal{X}$ 是特征空间,$P(X)$ 是其上的边缘分布。

  • 源域: ImageNet 自然 RGB 图,$\mathcal{X} = \mathbb{R}^{224 \times 224 \times 3}$,$P_S(X)$ 体现自然场景的像素统计规律。
  • 目标域: 胸部 CT 切片,维度相同,但 $P_T(X)$ 的灰度直方图、结构先验和噪声特征都截然不同。

任务

任务是另一个二元组 $\mathcal{T} = \{\mathcal{Y}, f(\cdot)\}$:标签空间和我们想要学习的预测函数。在监督学习里,任务隐含地固定了条件分布 $P(Y \mid X)$。

  • 任务 1: ImageNet 1000 类分类,$|\mathcal{Y}| = 1000$。
  • 任务 2: 肺炎二分类,$|\mathcal{Y}| = 2$。

源域与目标域

源域目标域
$\mathcal{D}_S$,对应任务 $\mathcal{T}_S$$\mathcal{D}_T$,对应任务 $\mathcal{T}_T$
标注充足稀缺或缺失
分布$P_S(X), P_S(Y\|X)$$P_T(X), P_T(Y\|X)$

迁移学习并不要求源域和目标域完全相同——这正是它存在的意义。两者可以在以下任意维度上不同:特征空间($\mathcal{X}_S \neq \mathcal{X}_T$)、边缘分布($P_S(X) \neq P_T(X)$)、标签空间($\mathcal{Y}_S \neq \mathcal{Y}_T$)或条件分布($P_S(Y\mid X) \neq P_T(Y\mid X)$)。每种组合都对应一个不同的子问题。

形式化的目标

给定源域 $\mathcal{D}_S$ 及其任务 $\mathcal{T}_S$,目标域 $\mathcal{D}_T$ 及其任务 $\mathcal{T}_T$,迁移学习的目标是利用 $\mathcal{D}_S$ 与 $\mathcal{T}_S$ 的知识改进目标预测函数 $f_T(\cdot)$,其中 $\mathcal{D}_S \neq \mathcal{D}_T$ 或 $\mathcal{T}_S \neq \mathcal{T}_T$。

$$ \epsilon_T < \epsilon_0 $$

或者等价地:用更少的目标域标注,达到同样的精度。第二种说法在工业场景里通常更诚实——迁移学习很少能拉高一个已经饱和的模型,但它几乎总能在饱和点之前的任何工作点上大幅压低标注成本。


3. 迁移学习的分类体系

如果按"目标侧缺什么"来组织,原本看起来杂乱无章的方法立刻清晰起来——这就是下面这张三分类图。

迁移学习分类体系:归纳、直推、无监督

归纳迁移

  • 源任务与目标任务不同($\mathcal{T}_S \neq \mathcal{T}_T$)。
  • 目标域有少量标注
  • 方法:预训练-微调、多任务学习、自训练。
  • 经典案例:用 ImageNet 预训练 ResNet 的主干,换上新分类头去做胸部 X 光分类,仅靠几百张标注样本——这是几乎所有医学影像论文的标准流程。

直推迁移

  • 任务相同,域不同($\mathcal{T}_S = \mathcal{T}_T$,$\mathcal{D}_S \neq \mathcal{D}_T$)。
  • 目标域完全没有标注
  • 方法:域适应(特征对齐、对抗对齐)、样本重加权。
  • 经典案例:在 GTA5 游戏画面上训练的语义分割模型,部署到 Cityscapes 真实驾驶数据上,全程不引入新标注。自动驾驶的研究主战场之一。

无监督迁移

  • 两侧都没有标注。要迁移的是结构本身——表示、聚类、流形。
  • 方法:自监督预训练(MoCo、SimCLR、MAE)、深度聚类。
  • 经典案例:在通用语料上训练的 Word2Vec 或 BERT,作为特征提取器服务任意下游 NLP 任务。这也是当下基础模型流水线的起点。

实际工程中这三类常常融合在一起:典型的基础模型流程先做无监督预训练,再做归纳迁移到下游任务,如果部署环境与标注训练集还有差距,就再叠一层直推域适应。这套分类体系是一种词汇表,而不是非此即彼的硬划分。


4. 哪些层适合迁移

深度网络不是单一的知识块,而是一摞"专门程度"逐层递增的表示。Yosinski 等人 2014 年做了一个如今已经成为经典的实验:在 ImageNet 一半数据上训练一个 CNN,冻结前 $k$ 层,在另一半数据上重新训练剩余层,观察 $k$ 滑动时准确率的变化。结果如下,是关于迁移学习最有用的一个经验事实。

CNN 各层的特征可迁移性

这条曲线讲了三件事:

  1. 底层特征(conv1conv3)是通用的。 边缘和纹理在视觉任务之间几乎放之四海而皆准。冻结它们几乎不会损失性能,反而在小数据上比从头训练更好。
  2. 高层特征(conv5 及以后)是专门的。 为 ImageNet 物体类别量身打造的滤波器,并不天然契合你的目标类别。冻结它们会带来明显代价——橙色"冻结"曲线急速下滑。
  3. 微调能免费补回专门性。 蓝色"微调"曲线几乎一路保持高位:只要让高层适应目标分布,你就既保留了底层先验、又获得了目标特异性。这就是"低层冻结、高层微调"成为默认配方的原因。

这一张图能解释整个系列后续大部分实操建议:哪些层���结,哪一组学习率分块设置,以及为什么 LoRA 这类参数高效方法把改动集中在更深的层。


5. 负迁移

$$ \epsilon_T > \epsilon_0 $$

下图把这一规律可视化:随着源域-目标域散度增加,迁移曲线会跌穿"从头训练"基线。越过这个交叉点,你就是在花钱把错误的归纳偏置带进新任务。

负迁移:随域散度增长的正/负迁移区域

为什么会发生

  1. 输入分布差异过大。 自然图的纹理对手绘素描完全无用——高频统计特性截然不同。
  2. 任务之间冲突。 源任务损失的最优解可能离目标任务的最优解很远,梯度下降未必能跳出源域的"盆地"。
  3. 源域过拟合。 预训练模型可能记住了一些数据特有的噪声(例如 ImageNet 某些图角落里固定出现的水印),这种"知识"会主动误导目标预测。

如何避免

  • 先量一下。 用 MMD 或一个域分类器在原始或浅层特征上度量散度。如果偏差太大,要么少迁一些,要么换源数据集。
  • 选择性迁移。 冻结通用底层、重训专用高层。上节那张可迁移性曲线就是你的依据。
  • 正则化微调。 加一项把参数往预训练值拉的 $L_2$ 惩罚(如 L2-SP),约束你能漂移多远。
  • 集成兜底。 拿不准时,就把迁移模型与从头训练模型做个加权平均——大多数基准上都不会比两者中较差的一个更差。

那个交叉点不是理论玩具,而是每一位迁移学习实践者实际在走的工作曲线。你的任务是在上线之前就清楚自己站在交叉点的哪一侧。


6. 量化迁移可行性

下面两个工具,让你能够在训练之前就预判迁移有没有戏。

Ben-David 界

$$ \epsilon_T(h) \;\leq\; \epsilon_S(h) \;+\; \tfrac{1}{2}\, d_{\mathcal{H}\Delta\mathcal{H}}(\mathcal{D}_S, \mathcal{D}_T) \;+\; \lambda^{*}. $$

三项之间彼此独立,对应三个不同的着力点:

  • $\epsilon_S(h)$——源域错误率,靠更好的训练降低。
  • $d_{\mathcal{H}\Delta\mathcal{H}}$——源域与目标域的分布散度,靠域适应降低。
  • $\lambda^{*}$——理想联合错误率,即同一个最优假设在两个域上的最小误差和。这一项由问题本身决定:如果根本不存在一个能同时在两个域上做好的假设,再花哨的对齐方法也救不了你。

这个界的实践含义很直接:如果散度或者 $\lambda^{*}$ 任意一项过大,别折腾对齐了,换源数据集

最大均值差异(MMD)

$$ \mathrm{MMD}(\mathcal{D}_S, \mathcal{D}_T) \;=\; \big\lVert \mathbb{E}[\phi(X_S)] - \mathbb{E}[\phi(X_T)] \big\rVert_{\mathcal{H}}. $$$$ \mathcal{L} \;=\; \mathcal{L}_{\mathrm{task}} \;+\; \lambda \cdot \mathrm{MMD}^{2}. $$

最小化第二项的效果就是把源域与目标域的特征分布拉到一起,恰恰是 Ben-David 界叫你做的事。

预训练后的一个经验阈值:嵌入空间里的 MMD 低于 0.1 是强烈的正信号;超过 0.5 就基本是负迁移领地了。


7. 整合起来:标准配方

预训练主干 + 新任务头

能解决大多数生产问题的"九成方案"也是最朴素的:

预训练主干 + 任务专用新头

拿一个在大规模通用数据上训练好的卷积或 Transformer 主干,丢掉原本的分类头,按你目标标签数量装上一个新头,然后微调。你可以逐层决定是冻结(便宜、保守)还是放开(贵、表达力强)。绝大多数中等预算下的最优策略是:先冻结主干训几个 epoch,再用极小学习率全网放开微调

为什么在小数据下尤其有效

下图的"数据效率曲线"是迁移学习最有说服力的商业论据。10 个标注时,从头训练几乎跟瞎猜差不多,迁移已经能给你一个可用模型;100 个标注时,差距巨大;到一万个标注时,两条曲线收敛——这正好说明了,为什么迁移最值钱的是那些标不起一万条样本的团队

数据效率:目标域准确率 vs. 标注量

这张图可以当合同读:每一条水平切片告诉你迁移能省多少标注,每一条垂直切片告诉你迁移能多拿多少分。两种视角等价,而且都是经常以"数量级"为单位的差距。

无监督场景:域适应

当目标域一个标注都没有时,无法以传统意义上的微调。主流做法(系列第三篇会展开讲)是学一个共享编码器,把源域和目标域特征拉到同一子空间,再在(有标注的)源域侧训练分类器,并把它直接用到(已经对齐的)目标域上。

域适应问题设定:共享编码器

训练目标正是上一节写出的那个损失:源域分类损失 + 把源/目标特征拉到一起的 MMD 惩罚。下一节会展示,整套东西用 PyTorch 写不到 100 行。


迁移学习与相关概念

迁移学习与若干相邻领域接壤,词汇要分清楚:

维度迁移学习多任务学习
目标优化目标域性能同时优化所有任务
训练方式顺序(先源域后目标域)并行(同时训练)
数据假设域可以不同假设任务相关
典型套路预训练-微调共享编码器 + 多个任务头
维度迁移学习元学习
目标迁移具体知识学习"如何学习"新任务
训练数据单个或少数源域大量、多样的任务
适应方式通常需要微调快速小样本更新
维度迁移学习域泛化
测试期信息可访问目标域数据目标域未知
方法域适应学习域不变特征

把这几条边界搞清楚,你才知道该去翻哪些论文、跑哪些 benchmark、用哪些工具。


完整实现:基于 MMD 的特征迁移

下面是本文一直在描述的工作流的一个自包含示例。我们模拟一个 2D 域偏移,比较三种策略:在目标上从头训练、直接把源域模型拿来用、用 MMD 正确地做对齐。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
"""
特征迁移与域适应示例
方法:特征提取 + MMD 对齐 + 微调
"""

import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
from sklearn.metrics import accuracy_score
from sklearn.svm import SVC

np.random.seed(42)
torch.manual_seed(42)


# --- 数据生成:模拟域偏移 ---------------------------------------------------

def generate_source_domain(n_samples=1000):
    """源域:两个分得很开的高斯簇。"""
    X0 = np.random.randn(n_samples // 2, 2) * 0.5 + np.array([-2, -2])
    X1 = np.random.randn(n_samples // 2, 2) * 0.5 + np.array([2, 2])
    X = np.vstack([X0, X1])
    y = np.hstack([np.zeros(n_samples // 2), np.ones(n_samples // 2)])
    return X, y


def generate_target_domain(n_samples=200):
    """目标域:旋转 45 度并平移(协变量偏移)。"""
    theta = np.pi / 4
    rotation = np.array([[np.cos(theta), -np.sin(theta)],
                         [np.sin(theta),  np.cos(theta)]])
    X0 = (np.random.randn(n_samples // 2, 2) * 0.6 + np.array([-1, -1])) @ rotation.T
    X1 = (np.random.randn(n_samples // 2, 2) * 0.6 + np.array([ 1,  1])) @ rotation.T
    X = np.vstack([X0, X1])
    y = np.hstack([np.zeros(n_samples // 2), np.ones(n_samples // 2)])
    return X, y


X_source,        y_source        = generate_source_domain(1000)
X_target_train,  y_target_train  = generate_target_domain(50)   # 少量标注
X_target_test,   y_target_test   = generate_target_domain(200)  # 留出测试

print(f"源域: {X_source.shape}  |  目标训练: {X_target_train.shape}  "
      f"|  目标测试: {X_target_test.shape}")


# --- 方法 1:仅在少量目标样本上从头训练 -----------------------------------

clf_scratch = SVC(kernel="rbf", gamma="auto").fit(X_target_train, y_target_train)
acc_scratch = accuracy_score(y_target_test, clf_scratch.predict(X_target_test))
print(f"[从头训练]   准确率: {acc_scratch:.4f}")


# --- 方法 2:在源域训练,直接套用到目标域(无适应) -----------------------

clf_direct = SVC(kernel="rbf", gamma="auto").fit(X_source, y_source)
acc_direct = accuracy_score(y_target_test, clf_direct.predict(X_target_test))
print(f"[直接迁移]   准确率: {acc_direct:.4f}")


# --- 方法 3:特征迁移 + MMD 对齐 + 微调 -----------------------------------

class FeatureExtractor(nn.Module):
    def __init__(self, input_dim=2, hidden_dim=32, output_dim=16):
        super().__init__()
        self.encoder = nn.Sequential(
            nn.Linear(input_dim, hidden_dim), nn.ReLU(),
            nn.Linear(hidden_dim, output_dim), nn.ReLU(),
        )

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


class Classifier(nn.Module):
    def __init__(self, input_dim=16, num_classes=2):
        super().__init__()
        self.fc = nn.Linear(input_dim, num_classes)

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


def compute_mmd(x_source, x_target, gamma=1.0):
    """两个 batch 之间的 RBF 核 MMD(有偏估计,SGD 下足够用)。"""
    xx = torch.sum(x_source ** 2, dim=1, keepdim=True)
    yy = torch.sum(x_target ** 2, dim=1, keepdim=True)
    K_ss = torch.exp(-gamma * (xx + xx.t() - 2 * x_source @ x_source.t()))
    K_tt = torch.exp(-gamma * (yy + yy.t() - 2 * x_target @ x_target.t()))
    K_st = torch.exp(-gamma * (xx + yy.t() - 2 * x_source @ x_target.t()))
    n_s, n_t = x_source.size(0), x_target.size(0)
    return K_ss.sum() / n_s ** 2 + K_tt.sum() / n_t ** 2 - 2 * K_st.sum() / (n_s * n_t)


def train_with_mmd(X_source, y_source, X_target_unlabeled,
                   X_target_labeled, y_target_labeled,
                   epochs=100, lambda_mmd=0.5):
    """两阶段训练:源域分类 + MMD 对齐,然后在目标域上微调。"""
    X_s   = torch.FloatTensor(X_source)
    y_s   = torch.LongTensor(y_source.astype(int))
    X_t_u = torch.FloatTensor(X_target_unlabeled)
    X_t_l = torch.FloatTensor(X_target_labeled)
    y_t_l = torch.LongTensor(y_target_labeled.astype(int))

    feat = FeatureExtractor()
    clf  = Classifier()
    optimizer = optim.Adam(list(feat.parameters()) + list(clf.parameters()), lr=1e-3)
    criterion = nn.CrossEntropyLoss()

    loader = DataLoader(TensorDataset(X_s, y_s), batch_size=32, shuffle=True)

    # 阶段 1:源域分类 + 在无标注目标上做 MMD 对齐
    for _ in range(epochs):
        for X_batch, y_batch in loader:
            optimizer.zero_grad()
            loss_cls = criterion(clf(feat(X_batch)), y_batch)
            loss_mmd = compute_mmd(feat(X_batch), feat(X_t_u))
            (loss_cls + lambda_mmd * loss_mmd).backward()
            optimizer.step()

    # 阶段 2:在少量标注目标样本上做轻量微调
    for _ in range(50):
        optimizer.zero_grad()
        criterion(clf(feat(X_t_l)), y_t_l).backward()
        optimizer.step()

    return feat, clf


feat, clf_mmd = train_with_mmd(
    X_source, y_source,
    X_target_unlabeled=X_target_test,
    X_target_labeled=X_target_train,
    y_target_labeled=y_target_train,
)

feat.eval(); clf_mmd.eval()
with torch.no_grad():
    preds = torch.argmax(clf_mmd(feat(torch.FloatTensor(X_target_test))), dim=1).numpy()

acc_transfer = accuracy_score(y_target_test, preds)
print(f"[特征 + MMD] 准确率: {acc_transfer:.4f}")
print(f"\n相比从头训练提升: "
      f"{(acc_transfer - acc_scratch) / acc_scratch * 100:.1f}%")

各部分的作用

组件功能
generate_source/target_domain制造一个可控的协变量偏移(旋转 + 平移)
compute_mmd两个嵌入 batch 之间的 RBF 核 MMD
阶段 1 训练在源域分类的同时,把目标域嵌入往源域拉
阶段 2 微调用 50 个标注样本做轻量适配

两个值得理解的旋钮。 lambda_mmd=0.5 控制对齐力度——太小则等于忽略目标域,太大则会破坏源域分类精度。100/50 epoch 的划分把大部分预算留给对齐,再用一个小阶段做精化。

把上面的合成 2D 数据替换成任何真实数据对(Office-31、DomainNet、VisDA),代码结构都不需要改动——这正是这个练习的意义所在。


常见问题

迁移学习一定比从头训练好吗?

不一定。效果取决于域相关性、目标数据量和任务相似度。诚实的经验法则:当目标数据不到从头训练所需量的约 10% 时,优先考虑迁移;超过这个阈值后,收益迅速变小,工程开销可能就划不来了。

怎么挑一个合适的源域?

挑一个大、多样、同模态的。视觉默认 ImageNet;NLP 默认一个强预训练 Transformer(BERT、GPT、Llama)。挑完之后,用 t-SNE 在浅层特征上看看重叠度,并算一下 MMD:低于 0.1 是绿灯,高于 0.5 是红灯。

哪些层应该冻结?

入门做法:先冻结网络底部 30%–50%,微调剩余层。NLP 更常见的是全网微调,但学习率比预训练时小一个数量级。极端小数据(< 100 条)时只训最后 1–2 层,不然必过拟合。

怎么检测负迁移?

永远跑一个从头训练基线。 如果迁移模型不如基线,或者微调时验证损失不降反升,或者预训练后嵌入空间 MMD 仍在 0.5 以上,你就遇到负迁移了。补救按代价从低到高:减少迁移层数 → 换源数据集 → 上对抗域适应(系列第三篇会讲)。


小结

我们覆盖了任何迁移学习项目都需要的七块拼图:

  • 动机——数据稀缺、算力昂贵、知识复用的普适价值。
  • 形式化定义——域 vs 任务、源域 vs 目标域,以及它们之间的四种差异。
  • 分类体系——归纳、直推、无监督;同一套词汇,三种问题形态。
  • 逐层可迁移性——底层通用、高层专门;冻底层、调高层。
  • 负迁移——成因、检测、控伤。
  • 理论——Ben-David 分解,加 MMD 这个实用的散度估计器。
  • 配方与代码——预训练主干 + 新头,外加一个完整可跑的 MMD 对齐实现。

迁移学习不是魔法。它是有纪律地利用真实数据集间共享结构的工程。用得好,是现代深度学习工具箱里杠杆最大的方法之一;用得糙,则会悄无声息地让模型变差。这个系列接下来要讲的,就是怎么把它用得好


参考文献

  1. Pan, S. J., & Yang, Q. (2010). A survey on transfer learning. IEEE TKDE, 22(10), 1345-1359.
  2. Weiss, K., Khoshgoftaar, T. M., & Wang, D. (2016). A survey of transfer learning. Journal of Big Data, 3(1), 1-40.
  3. Yosinski, J., Clune, J., Bengio, Y., & Lipson, H. (2014). How transferable are features in deep neural networks? NeurIPS.
  4. Rosenstein, M. T. et al. (2005). To transfer or not to transfer. NeurIPS Workshop on Transfer Learning.
  5. Ben-David, S. et al. (2010). A theory of learning from different domains. Machine Learning, 79(1), 151-175.
  6. Gretton, A. et al. (2012). A kernel two-sample test. JMLR, 13, 723-773.

系列导航

部分主题
1基础与核心概念(本文)
2预训练与微调
3域适应
4小样本学习
5知识蒸馏
6多任务学习

Liked this piece?

Follow on GitHub for the next one — usually one a week.

GitHub