notes for deep learning
Lecture 1
data:由样本(sample)和标签(label)组成
模型:判别式模型(classification)和生成式模型(generation)
深度学习的前提假设:神经网络可以近似地表示任何函数、一个优秀的算法可以自动生成相应的神经网络。
单层感知机可以对与或非门进行仿真,但仿真异或门需两层感知机。
多层感知机可以表达任意布尔函数,但是训练一个 \(3\) 层感知机是 NP-Complete 的。(MLP 能对任意函数进行很好的近似,但无法高效地找到最优解)
为什么使用感知机效果这么差?因为数据离散,所以无法很好地判断向哪个方向移动能让解变优,因而只能暴力搜索。改进方法:将激活函数改为连续函数(如 sigmoid)后做 backpropagation。
Lecture 2
梯度下降法:每次沿着梯度方向移动 \(\eta\),直到梯度足够小(可能找到局部最优解或鞍点,不一定能找到全局最优解)
\(\eta\) 被称为学习率(learning rate)
多分类问题:输出一个 \(C\) 个类之间的概率分布 \(\mathbb{P}(y=c|x)=f_c(x;\theta)\)。
softmax 函数:\(f(z)_c=\dfrac{e^{z_c}}{\sum\limits_{j=1}^Ce^{z_j}}\)(将参数转化为概率分布的通用方式)。
多分类问题的损失函数:negative log-likelihood loss,即输出得到正确的分类的概率的对数的相反数 \(-\ln f_{y_i}(x_i;W)\),也被称为 cross entropy loss。
- 为什么 NLL 损失也被称为 cross entropy loss?对于两个概率分布 \(p,q\),定义它们的交叉熵 \(CE(p,q)=-\sum\limits_{c}p(y=c)\log q(y=c)\),那么 \(-\ln f_{y_i}(x_i;W)\) 可以视作一个只有第 \(y_i\) 维是 \(1\) 的概率分布与 \(f_c(x_i,W)\) 的交叉熵。
计算损失函数对每个参数的导数:backpropagation。
MLP 前几层的神经元数量要尽量多(学习底层知识)。
深度越深越好,但过深的网络学习难度过大,也更难控制学习率。
sigmoid 激活函数的问题:梯度消失(当神经元的值特别小或特别大的时候,相应的梯度会特别接近 \(0\),做梯度下降的时候梯度容易消失)处理方法:1. 使用接近 \(0\) 的初始值 2. 使用 ReLU 函数作为激活函数。
正则化:为了控制参数的绝对值较小,可以在损失函数后添加额外项(如 \(\alpha|w|\) 或 \(\alpha|w|^2\)),也叫 weight decay。
卷积神经网络:处理局部信息(可用于图像识别、语音识别)
Distributed scanning:每一层扫描模式的一小部分,而不是只用一层就把所有的工作都搞定了,这样训练的参数个数更少。
CNN 中的一些术语:
- filter 一层 CNN 的 kernel 的大小
- stride 步长,可以减少 feature map
zero-padding:在原网络周围填上若干圈 \(0\),使得做完卷积之后输出网络的大小和原网络相同。
卷积神经网络中,即便模式只出现了一小变化,也会对 feature map 产生很大的影响(解决办法:将每个元素的值改为其一小邻域中所有元素的最大值,max-pooling,这样可以接受模式的小扰动)
max-pooling 会导致某些元素的梯度消失,因此有时也会用 average-pooling 代替 max-pooling。
pooling 本身也是一种卷积,因此也可以一路卷积到底(fully convolutional network)
Lecture 3
凸函数上的梯度下降
Descent Lemma:对于一个光滑的凸函数 \(f(x)\)(\(f(x)\) 为凸函数且 \(\forall x,y,|\nabla f(x)-\nabla f(y)|\le L|x-y|\)),都有 \(\forall x,y\),\(f(y)\le f(x)+\nabla f(x)^T(y-x)+\dfrac{L}{2}|x-y|^2\)。
如果已知 Lipschitz 常数 \(L\),则考虑令学习率 \(\eta=\dfrac{1}{L}\) 做梯度下降的过程,有
带入 Descent Lemma 有
将 \(k\) 个式子累加起来可以得到
这意味着如果最终 \(|\nabla f(X^k)|^2\le\epsilon\),则 \(k=O(\dfrac{1}{\epsilon})\)。
如何找到 Lipschitz 常数 \(L\)?一个实用的办法是初始设置一个较大的学习率 \(\eta\),一直减小学习率(乘以某个常数 \(\alpha\))直到模型在验证集上的表现更劣。
对于强凸函数(\(f(y)\ge f(x)+\nabla f(x)^T(y-x)+\dfrac{\mu}{2}|y-x|^2\)),对其做梯度下降可以实现更好的收敛速度:\(k=O(\log\dfrac{1}{\epsilon})\)。
Second-order optimization
考虑目标函数 \(f(\theta)\) 在 \(\theta\) 处的二阶泰勒展开:
通过最小化二阶近似,可以得到 Newton's method:
其收敛速度为局部二次收敛。
Second-order optimization 的缺点:
- 计算量太大,计算 Hessian 矩阵的逆要 \(O(n^3)\) 的时间。
- Hessian 可能不正定,迭代未必收敛。
回到一阶迭代上来,使用梯度下降算法时可能出现的一个问题是,如果我们对所有维度使用同一个学习率,可能会出现某些维度已经收敛,另一些维度还在震荡的情况,因此我们可以考虑使用 Heavy-ball method,以一个参数 \(\beta\) 累加过去梯度的信息
即
但很遗憾,该算法的收敛速度并没有保证。为了保证其收敛速度,我们有 Nesterov's accelerated gradient descent:
在光滑函数上,NAG 的收敛速度为 \(O(\dfrac{1}{\epsilon^2})\)。
Stochastic gradient descent:每次随机挑一个数据计算每个参数关于其的梯度。(其是关于梯度的 unbiased estimate,因为 \(\nabla L(\theta)=\mathbb{E}_j[\nabla L_j(\theta)]\),但是方差可能很大)
使用 stochastic gradient descent 需要一个随着时间不断减小的学习率(常用做法:\(\eta^k\propto\dfrac{1}{k}\))。为什么:即便站在最优点上,由于随机取样存在方差,使用常数作为学习率必定会导致迭代不收敛。
每次只取一个样本做梯度下降,方差过大应该怎么处理?考虑批量处理,设一个 batch size \(b\) 并随机采样 \(b\) 次,对这 \(b\) 个样本做梯度下降则是一个比较居中的做法,因为这样方差会乘以 \(\dfrac{1}{b}\)。(GD too expensive,SGD too noisy)
在深度学习和监督学习中,局部最优解和全局最优解差别不大,一般找到局部最优解即可结束梯度下降,只要逆不停在 saddle point 就行。
Adagrad 算法:\(g^k=\nabla_{\theta}f(\theta^k)\), \(G^k=G^{k-1}+|g^k|^2\), \(\theta^{k+1}=\theta^k-\dfrac{\eta}{\sqrt{G^k+\epsilon}}g^k\)
RMSProp 算法:\(g^k=\nabla_{\theta}f(\theta^k)\), \(G^k=\gamma G^{k-1}+(1-\gamma)|g^k|^2\), \(\theta^{k+1}=\theta^k-\dfrac{\eta}{\sqrt{G^k+\epsilon}}g^k\).
Adam 算法:\(g^k=\nabla_{\theta}f(\theta^k)\), \(M^k=\delta M^{k-1}+(1-\delta)g^k\), \(G^k=\gamma G^{k-1}+(1-\gamma)|g^k|^2\), \(\hat{M_k}=\dfrac{M^k}{1-\delta^k}\), \(\hat{G_k}=\dfrac{G^k}{1-\gamma^k}\), \(\theta^{k+1}=\theta^k-\dfrac{\eta}{\sqrt{\hat{G^k}+\epsilon}}\hat{M^k}\).
Data augmenting:对图像进行翻转/旋转/拉伸等变换,增加数据集大小,防止过拟合。
Dropout:每个神经元有 \(p\) 的概率停止工作。
Early stopping:使用验证集观察模型是否过拟合,如果发现过拟合就停止训练。
Gradient clipping:当梯度超过一定阈值时就将梯度设为该阈值。
初始化:常见的初始化方法有 Xavier initialization 和 Kaiming initialization。
归一化:对于 \(N\times H\times W\times C\) 的数据(\(N,H,W,C\) 分别表示 batch size,图像高度、图像宽度、通道数):
- BatchNorm:分成 \(C\) 组,每组 \(N\times H\times W\) 进行归一化。
- InstanceNorm:分成 \(N\times C\) 组,每组 \(H\times W\) 进行归一化。
- LayerNorm:分成 \(N\) 组,每组 \(H\times W\times C\) 进行归一化。
- GroupNorm:分成 \(N\times G\) 组,每组 \(H\times W\times (C/G)\) 进行归一化,其中 \(G\) 是超参数。
进行归一化的时候,首先计算组中所有数据的均值和方差 \(\mu,\sigma^2\),然后对每个数据 \(x_i\) 计算 \(\hat{x_i}=\dfrac{x_i-\mu}{\sqrt{\sigma^2+\epsilon}}\),然后令最终的 \(x'_i=\gamma\hat{x_i}+\beta\),其中 \(\gamma,\beta\) 为可学习的参数。
Lecture 4
生成式模型(generative model):给定 \(y\),求 \(P(X|y)\)。
Hopfield network:真“全连接”的神经网络,每个节点上有一个 \(y_i\),其中 \(y_i=\Theta(\sum\limits_{j\ne i}w_{j,i}y_j+b_i)\), \(\Theta(z)=\begin{cases}+1&(z>0)\\-1&(z\le 0)\end{cases}\),并且满足 \(w_{j,i}=w_{i,j}\)。
如何求最终的 \(y\)?考虑每次如果 \(y_i(\sum\limits_{j\ne i}w_{j,i}y_j+b_i)<0\),则令 \(y_i\leftarrow -y_i\)。这一操作可能会导致连锁反应,重复这一过程直到操作不了为止。这一过程是否会收敛呢?答案是肯定的。设 \(y_i^-\) 为反转前的 \(y_i\),\(y_i^+\) 为反转后的。如果 \(y_i^-(\sum\limits_{j\ne i}w_{j,i}y_j+b_i)\ge 0\) 无事发生,否则 \(y_i^+=-y_i^-\),\(y_i^+(\sum\limits_{j\ne i}w_{j,i}y_j+b_i)-y_i^-(\sum\limits_{j\ne i}w_{j,i}y_j+b_i)=2y_i^+(\sum\limits_{j\ne i}w_{j,i}y_j+b_i)>0\),也就是说,如果设 \(D=\sum\limits_{i<j}y_iw_{i,j}y_j+y_ib_i\),那么每次 flip 对 \(D\) 的改变量都是正数,因此 \(\{y_i\}\) 总会在有限步内收敛。令能量 \(E=-D\),则 \(E\) 严格降。
因此,在能量谷底附近进行 evolve,都会进入谷底,所以这个网络是有“记忆”的,只要谷底是我们需要的 pattern,那在谷底附近的小邻域内进行扰动依然能到达谷底。具有这一性质的神经网络可以用作图像生成。
Hebbian learning:设 \(y_i\) 为我们需要记住的 pattern,那我们令 \(w_{i,j}=y_iy_j\),这样 \(E=-\dfrac{1}{2}n(n-1)\) 达到全局最小值。推广到多个 pattern 的情况。假设 \(\{y^p\}\) 为我们要记住的 \(N_p\) 个 pattern,那令 \(w_{i,j}=\dfrac{1}{N_p}\sum\limits_{p}y_i^py_j^p\)。但如果记的 pattern 多了就可能导致最小值不是我们想要的 pattern 的情况。(事实上,\(n\) 个神经元大概可以最多记住 \(\dfrac{n}{4}\log n\) 张图,但是仍然存在不想要的最小值。)
事实上更好地方式是对我们要记住的 pattern 做机器学习。
即,最小化我们想要的 pattern 的能量值之和与我们不想要的 pattern 的能量值之和之差。
但后面那个式子里的 \(y\) 的数量太多了,没法直接算和。一个优化是随机找若干个初始值然后 evolve 找谷底,再对这些谷底求和。这个算法还可以进一步优化,因为谷底并非是一样重要的,从 desired pattern 出发达到的谷底对算法的训练效果最大,因此可以进一步改为将那些从 desired pattern 出发到达的谷底。但是如果你从 desired pattern 出发到达的谷底刚好是我们要的 desired pattern 呢?这样我们的算法又出问题了。不过我们思考一下,事实上我们并不是真的要让谷底变高,而是要让我们的 desired pattern 变成谷底,因此可以对算法进一步优化,我们不从 desired pattern 开始找谷底了,而是往旁边随机走几步,让旁边的位置的 energy 变大就行了。
这样我们就得到的最终的算法:
其中 \(y\) 是随机的 desired pattern,\(y'\) 是从某个随机的 desired pattern 旁边走几步得到的结果。
这样得到的网络最多能记住 \(O(n)\) 个 pattern,如何让网络能记住更多的 pattern 呢?
一个想法是建立一些 hidden neurons,将我们想要记住的 pattern 放进 visible neuron 里,但是直接做不太行,因为我们不知道 hidden neuron 应该怎么赋值。
一个改进是用热力学中的 Boltzmann distribution 来优化 Hopfield network,使其由确定性网络变为随机性网络。
对于一个状态,还是定义其能量
Boltzmann 概率分布:
其中 \(Z\) 是归一化常数。
怎么根据 Boltzmann 概率分布随机生成 \(y\) 呢?
- 首先随机生成一个 \(y\)。
- 枚举每个 \(y_i\),以 \(\dfrac{1}{1+\exp(-\sum\limits_{j\ne i}w_{i,j}y_j-2b_i)}\) 的概率将 \(y_i\) 设为 \(1\),\(1-\dfrac{1}{1+\exp(-\sum\limits_{j\ne i}w_{i,j}y_j-2b_i)}\) 将 \(y_i\) 设为 \(0\)。
- 最终 \(y\) 的概率分布将收敛于 Boltzmann 概率分布。
这一过程被称为 Gibbs sampling。
这一随机性的 Hopfield network 本质上就算一种 Boltzmann machine。更具体地,一个 Boltzmann machine 包含:
- 一个能量函数 \(E(y)=-\dfrac{1}{2}y^TWy\)。
- 概率分布 \(P(y)=\dfrac{1}{Z}\exp(-\dfrac{E(y)}{T})\),其中 \(T\) 为温度,\(Z\) 为归一化参数。
- 一个和 \(E\) 有关的参数 \(W\)。
不妨假设 \(T=1\)。那么对于一个固定的 pattern \(y\),有 \(P(y)=\dfrac{\exp(\frac{1}{2}y^TWy)}{\sum\limits_{y'}\exp(\frac{1}{2}y'^TWy')}\)。
给定一个 pattern 集合 \(P\),要最大化 \(P\) 中 pattern 出现的概率,就相当于最大化 log-likelihood,即
考虑其对 \(W_{i,j}\) 的导数:
其中 \(Z\) 为归一参数。第二项 \(y'\) 的数量是指数级的,因此需要根据 Gibb sampling 随机采样取平均值,然后跑梯度上升。
这样我们便可以扩展到有 hidden neuron 的情况。将原本 \(E(y)=\dfrac{1}{2}y^TWy\) 改为 \(E(v)=\sum\limits_{h}\dfrac{\exp(y^TWy)}{\sum\limits_{y'}\exp(y'^TWy')}\),我们可以得到新的 loss function:
两边都可以用 Gibb sampling 随机取样求梯度。
Boltzmann machine 有一个问题就是速度太慢了,一个优化是使用 Restricted Boltzmann machine。即,将原本的完全图变为 hidden neuron 和 visible neuron 的二分图,这样一来在 visible 给定以后 hidden 是独立的,反之亦然,因此可以并行采样。并且只需采样 \(3\) 次。
Restricted boltzman learning 还可以扩展到更深的版本,即有多层 hidden neuron,相邻层之间连边。
对于一些比较复杂的函数 \(p(x)\),如何采样?Importance sampling,即选择一个好的 proposal distribution \(q(x)\),以 \(q(x)\) 的分布采样,并以 \(\dfrac{p(x)}{q(x)}\) 为权重算带权和,要求是 \(p(x)\) 和 \(q(x)\) 的概率分布应该比较接近,否则采样的方差会很大。
Lecture 5
Latent variable model:先采样一隐变量 \(z\),再根据 \(z\) 和 \(x\) 的概率分布 \(p(x|z)\) 采样出 \(x\)。
例如我们要采样一包含 \(k\) 类高斯混合模型,那么我们可以先以 \(w_1,w_2,\cdots,w_k\) 为权重采样出一下标 \(z\),再从高斯分布 \(N(\mu_z,\Sigma_z)\) 中采样出 \(x\)。其中 \(w,\mu,\Sigma\) 均为待学习的参数。
那么怎么学 latent variable model 呢?设 \(\theta\) 为待学的参数,使用 log-likelihood 可得
后面这个 \(\log\sum\limits_{z}p(x,z;\theta)\) 不太好通过梯度直接算,怎么办呢?Evidence lower bound。即使用 importance sampling,选择一个比较好的 proposal distribution,这样 \(p(x;\theta)=\sum\limits_{z}q(z)\cdot\dfrac{p(x,z;\theta)}{q(z)}\)。因为 \(\log\) 是凸函数,所以 \(\log(\sum\limits_{z}q(z)\cdot\dfrac{p(x,z;\theta)}{q(z)})\ge\sum\limits_{z}q(z)\log(\dfrac{p(x,z;\theta)}{q(z)})\). 当 \(q(z)\leftarrow p(z|x;\theta)\) 等号成立,因此我们可以得到一个基于迭代的办法:先基于某个 \(q(z)\) 优化 \(p(x,z;\theta)\),然后设 \(q(z)=p(z|x;\theta)\)。(EM 算法)
但是问题又来了,怎么计算 \(p(z|x;\theta)\) 呢?首先我们需要知道怎么评估两个概率分布是否接近,即 KL divergence,\(\text{KL}(q\parallel p)=\sum\limits_{z}q(z)\log\dfrac{q(z)}{p(z)}\)。所以现在问题可以看作,给定一个分布 \(p\),希望找到一个参数 \(\phi\) 定义的分布 \(q\) 使得 \(\text{KL}(q\parallel p)\) 最小。而
我们惊奇地发现,减号后面的东西还是一个 evidence lower bound,也就是说,在两个步骤中我们需要最大化的目标函数都是 \(\sum\limits_{z}q(z;\phi)\log\dfrac{p(z,x)}{q(z,\phi)}\)。
这样我们可以看作是学一个联合分布 \(J(\theta,\phi;x)=\sum\limits_{z}q(z|x;\phi)\log\dfrac{p(z,x;\theta)}{q(z|x;\phi)}\)。
推导得到 \(J(\theta,\phi;x)=\mathbb{E}_{z\sim q(z|x;\phi)}[\log p(x|z;\theta)]-\text{KL}(q(z|x;\phi)\parallel p(z))\),其中前者被称为 reconstruction term,后者被称为 KL term。
如果我们令 \(p\) 和 \(q\) 都是高斯分布,那么我们就得到了 variational autoencoder。更具体地,在 VAE 中:
- \(q(z|x;\phi)\sim N(\mu(x;\phi),\text{diag}(\exp(\sigma(x;\phi))))\)
- 先验概率 \(p(z)\sim N(0,I)\)
- \(p(x|z;\theta)\sim N(f(z;\theta),I)\)。
- 最后图片生成则是按照先验概率 \(p(z)\) 采样得到 \(z\),然后按照 \(p(x|z;\theta)\) 生成 \(x\)。
我们的目标是希望数据集中的图片经过 VAE 以后能尽量接近原来的图片同时对应的 latent variable \(z\) 能够尽量接近其先验概率,即最大化 \(\sum\limits_{x\in D}J(\theta,\phi;x)\)。
那么我们该如何计算 \(J(\theta,\phi;x)\) 对 \(\theta\) 和 \(\phi\) 的梯度呢?
-
对于 KL term,由于两个高斯分布的 KL divergence 存在封闭形式,可以直接计算。
-
对于 reconstruction term,因为 \(p(x|z)=\dfrac{1}{\sqrt{2\pi}}\exp(-\dfrac{1}{2}|x-f(z;\theta)|^2)\),把跟 \(\phi,\theta\) 无关的项扔掉以后有 \(\mathbb{E}_{z\sim q(z|x;\phi)}[\log p(x|z;\theta)]\propto\mathbb{E}_{Z\sim q(z|x;\phi)}[(x-f(z;\theta))^2]\)。一个比较棘手的地方在于参数 \(\phi\) 作为采样的概率,这不好直接计算,但是对于高斯分布而言,若 \(X\sim N(0,1)\),\(\mu+\sigma X\sim N(\mu,\sigma^2)\),因此 \(\mathbb{E}_{z\sim q(z|x;\phi)}[\log p(x|z;\theta)]\propto\mathbb{E}_{\epsilon\sim N(0,I)}[(f(\mu(x;\phi)+\epsilon\sigma(x;\phi);\theta)-x)^2]\),这样其关于 \(\phi\) 的梯度就好算了,使用蒙特卡洛法随机采样即可。
VAE 通过平衡 reconstruction term 和 KL term 让模型学习到既能保持数据特征又不会坍缩到退化解的 latent variable,事实上我们也可以通过调整这两项之间的平衡得到 \(\beta\) VAE:\(J(\theta,\phi;x)=\mathbb{E}_{z\sim q(z|x;\phi)}[\log(x|z;\theta)]-\beta\cdot\text{KL}(q(z|x;\phi)\parallel p(z;\theta))\)
Lecture 6
Implicit generative model:随机生成 \(z\sim N(0,1)\),然后根据 \(x=G(z,\theta)\) 生成 \(x\)。我们希望 \(x\) 的采样与 \(p_{data}\) 尽可能接近,即 \(D(G(z;\theta),p_{data})\) 最大,其中 \(D\) 是某种距离标准。
怎么选择这个距离 \(D\) 呢?考虑将这个 \(D\) 也参数化为 \(D(x,\phi)\) 的形式且假设 \(D\) 关于 \(x\) 可微,这样我们的目标损失函数可以写成 \(L(\theta)=D(G(z;\theta),\phi)\)。而训练参数 \(\phi\) 的过程本质上是一个二分类问题,我们希望在 \(p_{data}\) 中的 \(D(x,\phi)\) 都接近 \(1\),不在 \(p_{data}\) 中的 \(D(x,\phi)\) 都尽量接近 \(0\)。positive sample 是容易的,如何生成 negative sample 呢?随机采样有点太弱了,因此我们还需要一个 negative sample generator。
一种方法是拿 \(G\) 自身本身当 negative sample generator,这样我们 \(D\) 的目标相当于是最小化 NLL,即 \(\phi^*=\max\limits_{\phi}\mathbb{E}_{x\sim p_{data}}[\log D(x,\phi)]+\mathbb{E}_{\hat{x}\sim g}[\log(1-D(\hat{x},\phi))]\),而 \(\theta^*=\max\limits_{\theta}D(G(z;\theta);\phi)=\min\limits_{\theta}1-D(G(z;\theta);\phi)\)。因此我们最终的损失函数可以写作 \(L(\theta,\phi)=\min\limits_{\theta}\max\limits_{\phi}\mathbb{E}_{x\sim p_{data}}[\log D(x;\phi)]+\mathbb{E}_{\hat{x}\sim G}[\log(1-D(\hat{x};\phi))]\)。
更进一步地,事实上我们发现当 \(G\) 固定的时候,最优的 \(D\) 应该满足 \(D^*=\dfrac{p_{data}(x)}{p_{data}(x)+p_G(x)}\),而如果把最优的 \(D^*\) 带入 \(L\) 的表达式,会发现最优的 \(G\) 相当于最小化 \(\text{KL}(p_{data}\parallel \dfrac{1}{2}(p_{data}+p_G))+\text{KL}(p_G\parallel\dfrac{1}{2}(p_{data}+p_G))-\log 4\),即 \(2\text{JSD}(p_{data}\parallel p_G)-\log 4\)。
- JSD(Jensen-Shannon Divergence)的定义:\(\text{JSD}(p\parallel q)=\dfrac{1}{2}(\text{KL}(p\parallel\dfrac{1}{2}(p+q))+\text{KL}(q\parallel\dfrac{1}{2}(p+q)))\)。其满足对称性,非负性,且 JSD 的平方根满足三角不等式。
还有一个问题就是如何去衡量一个 GAN 的表现。因为无法得出 \(p_{data}\),进而无法用 likelihood 的方式去衡量一个 GAN 的好坏。事实上有两种通过预训练的图像识别模型 Inception v3 来衡量的办法:
- IS:定义 \(p_f(y)=\mathbb{E}_{x\sim G}[f(y|x)]\),其中 \(f(y|x)\) 为 Inception v3 将图像 \(x\) 识别为每一个类型的概率分布,那么 \(IS=\exp(\mathbb{E}_{x\sim G}[\text{KL}(f(y|x)\parallel p_f(y))])\),IS 越高说明效果越好。这个 metric 无法解决模式坍缩问题,即哪怕生成器每种类型只能生成 \(p_{data}\) 中的一张图片仍可能获得很高的 IS 分数。
- FID:提取 \(p_G,p_{data}\) 的特征 \((\mu_G,\Sigma_G),(\mu_p,\Sigma_p)\),然后定义 \(FID=|\mu_G-\mu_p|^2+\text{tr}(\Sigma_p+\Sigma_G-2\sqrt{\Sigma_p\Sigma_G})\),FID 越低表明效果越好。
GAN 可能出现的问题:
- 模式坍缩:即前文中说的,哪怕生成器只会生成一小部分的图片仍可能骗过判别器。
- 训练不稳定性:判别器和生成器可能会在某个范围持续振动。
解决办法:
-
DCGAN:将 CNN 与 GAN 结合起来。使用 batch normalization 提高稳定性,使用 leaky ReLU 解决梯度消失的问题。
-
一些训练技巧:
- Feature matching:生成器不再直接最大化判别器的输出,而是匹配真实数据在判别器中间层的特征统计量。
- Minibatch Discrimination:解决模式坍塌,通过让判别器感知一个批次内样本的多样性,迫使生成器生成多样化的样本。
- Historical Averaging:在损失函数中添加一项 \(\lVert\theta-\dfrac{1}{T}\sum\limits_{i=1}^T\theta_i\rVert^2\),防止生成器和判别器的参数剧烈波动。
- One-sided Label Smoothing:将真实数据的标签从 \(1\) 降为 \(0.9\),从而缓解梯度消失问题。
-
WGAN:使用 Wasserstein distance 代替 JSD,即将损失函数变成
Lecture 7
正则化流(Normalizing Flow):从比较简单的分布(如标准高斯分布)出发生成一个随机变量 \(z_0\),然后每次作用一个可逆的非线性函数 \(f_i\),这样最终的变量 \(x=f_k(z_k)\) 存在 tractable density。
怎么训练 Normalizing Flow?还是 log-likelihood,\(\log(p(x))=\log(p(z_{k-1}))-\log|\det(\dfrac{\partial f_K}{\partial z_{k-1}})|=\log p(z_0)-\sum\limits_{i}\log|\det(\dfrac{\partial f_i}{\partial z_{k-1}})|\),但是有一个问题是计算行列式时间复杂度为 \(O(d^3)\),太慢了。因此我们希望设计的 \(f_i\) 的行列式需要比较好计算。于是就有了 NICE(Nonlinear Independent Components Estimation)。
在 NICE 中,我们令 \(z=f(x)\)(这与我们之前的推导存在差异,但为了与论文保持一致,在下文中我们默认采用这种方式)。在每一层中,我们将 \(x\) 划分为两个不相交的子集 \(x_{1:m}\) 和 \(x_{m+1:d}\),并且令 \(z_{1:m}=x_{1:m},z_{m+1:d}=x_{m+1:d}+\mu_{\theta}(x_{1:m})\),这样 \(x_{1:m}=z_{1:m},x_{m+1:d}=z_{m+1:d}-\mu_{\theta}(z_{1:m})\),每一层均可逆且 Jacobian 矩阵均为下三角矩阵,\(\det J=1\),并且 \(\mu_{\theta}\) 可以是任意函数(不一定可逆),可以使用神经网络训练,达到了我们想要的效果。有一个小问题是你直接这样进行 forward pass 的话最上端的若干位会一直保持不动,因此在每层做完以后需要加一个 coupling layer,即将每层的神经元随机打乱。
NICE 还有一个推广是 Real-NVP:还是一样将 \(x\) 划分为两个不相交的子集 \(x_{1:m}\) 和 \(x_{m+1:d}\),但是这里令 \(z_{1:m}=x_{1:m},z_{m+1:d}=(x_{m+1:d}+\mu_{\theta}(x_{1:m}))·\exp(-\alpha_{\theta}(x_{1:m}))\),此时 \(\det J=\prod\limits_{i=m+1}^d\exp(-\alpha_{\theta}(x_{1:m})_i)\)。
Score based model(diffusion model):给定一个清晰的图片样本,每次不断加噪声直至变成随机的噪声分布,再不断降噪还原回原本的复杂样本。
怎么很好地表示一个概率分布呢?score function,即 \(s(x)=\nabla_x\log(p(x))\)。这样我们就得到了 score-based function,即通过参数 \(\theta\) 来刻画这个 score function \(s_{\theta}(x)\),并且希望其与真实的 \(\nabla_x\log(p(x))\) 尽可能接近。这里距离函数可以使用 fisher divergence,即 \(\dfrac{1}{2}\mathbb{E}_{x\sim p_{data}}[\lVert \nabla_x\log p_{data}(x)-s_{\theta}(x)\rVert]^2\),经过数学推导,该式可改写为 \(\mathbb{E}_{x\sim p_{data}}[\dfrac{1}{2}\lVert s_{\theta}(x)\rVert^2+\text{tr}(\nabla_xs_{\theta}(x))]+\text{constant}\)(score matching),这样如果 \(s_{\theta}(x)\) 有比较好的数学表达式,使得 \(\text{tr}(\nabla_xs_{\theta}(x))]\) 及其关于 \(\theta\) 的偏导比较好计算,那么就可以 Monte Carlo 采样以后做梯度下降算出最优的 \(\theta\) 了。
上述做法由于涉及 Jacobian 矩阵,计算量很大,怎么办呢?考虑在原数据的基础上做一点小扰动得到 \(q_{\sigma}(\tilde{x})\) 然后用新得到的 \(q_{\theta}(\tilde{x})\) 训练 \(p_{data}\)。经过数学推导可得 \(\dfrac{1}{2}\mathbb{E}_{\tilde{x}\sim p_{data}}[\lVert s_{\theta}(\tilde{x})-\nabla_{\tilde{x}}\log q_{\sigma}(\tilde{x})\rVert^2]=\dfrac{1}{2}\mathbb{E}_{x\sim p_{data},\tilde{x}\sim q_{\sigma}(\tilde{x}|x)}[\lVert s_{\theta}(\tilde{x})-\nabla_{\tilde{x}}\log q_{\sigma}(\tilde{x}|x)\rVert^2]+\text{constant}\). 如果我们选择比较好计算的 \(q_{\sigma}(\tilde{x}|x)\),例如 \(q_{\sigma}(\tilde{x}|x)=N(\tilde{x}|x,\sigma^2I)\),这样 \(\nabla_{\tilde{x}}\log q_{\sigma}(\tilde{x}|x)=-\dfrac{\tilde{x}-x}{\sigma^2}\),带入损失函数的式子之后就可以做梯度下降训出 score function 了。如何选择扰动的尺度 \(\sigma\) 呢?显然 \(\sigma\) 不能太大,而如果 \(\sigma\) 太小则采样的方差会很大,因此 \(\sigma\) 的大小需要仔细调整。
这样可以训练得出 \(s(x)\),那么怎么根据 \(s(x)\) 得到最终的图片呢?Langevin 采样。首先先从 score function 采样得到 \(x^0\),然后每次令 \(z^t\leftarrow N(0,1),x^t\leftarrow x^{t-1}+\dfrac{\epsilon}{2}\nabla_x\log p(x^{t-1})+\sqrt{\epsilon}z^t\),这样令 \(\epsilon\to 0,T\to\infty\),就有 \(x^T\sim p(x)\)。
但是这个模型有一些问题:
- score function 有可能在高维空间中的很多地方都是不良定义的,而真实数据可能之聚集在某个低维度的子空间上。
- score function 在某些低概率的地方学得不准,这就导致如果从这些低概率的地方开始做 MCMC 可能无法收敛。
- score function 不太能反应生成的数据在不同点位上的权重。
怎么办呢?Gaussian perturbation,即在原数据上加一点点噪声。更具体地,我们先从一个噪声比较大的情况开始采样,每次以上一次采样的结果为初始值并在当前 noise scale 下做 MCMC,然后在对当前的样本做 noise annealing 得到小一点的 noise scale,如此迭代即可。这样对每种 noise scale 都要求一遍 score function,因此我们需要将 noise scale 作为 score function 的参数。
Lecture 8
到目前为止,我们接触的神经网络都是维数固定的,如果换成序列上的问题(例如检查一段语音里有没有 welcome
),应该怎么处理呢?
自回归模型(Autoregressive model):用于预测时间序列数据的未来值,基于过去的观测值。更具体地,我们希望找到比较好的条件概率 \(p(x_i|x_1,x_2,\cdots,x_{i-1})\),这样 \(p(x)=\prod\limits_{i}p(x_i|x_1,x_2,\cdots,x_{i-1})\).
Recurrent Neural Network:考虑在原序列基础上建立一个隐藏状态 \(h_t\),同时训两个神经网络 \(f_1,f_2\),\(f_1\) 能够通过 \(h_{t-1}\) 和输入 \(X_t\) 求出 \(h_t\),\(f_2\) 能够通过 \(h_t\) 求出输出 \(Y_t\),即 \(h_t=f_1(h_{t-1},X_t,\theta),Y_t=f_2(h_t,\theta)\)。
MLP 和 RNN 的差别:hidden state 在 RNN 中会随着 time step 的增加而自身迭代,而 MLP 不会(RNN 可以看作反复循环自身迭代的 MLP)
隐藏状态也可以有很多层,这样我们就得到了 Multi-layer RNN。
在标准的 RNN 中,\(Y_t\) 只取决于 \(X_1,X_2,\cdots,X_{t}\),如果我们希望 \(Y_t\) 依赖于整个 \(X\) 序列怎么办呢?Bidirectional RNN,搞两个 RNN,一个正向一个反向,这样我们令 \(Y_t=f_2(h_t^f,h_t^b,\theta)\) 再去训练就可以让 \(Y_t\) 依赖于整个序列了。
RNN 有什么问题呢?在 BPTT 中出现了矩阵的幂次,因此如果矩阵的特征值过大则梯度可能爆掉,如果特征值过小则梯度会消失。解决梯度太大的问题是容易的,gradient clipping 即可,即当梯度超过某个阈值时就将梯度设为这个阈值。
怎么解决梯度过小的问题呢?LSTM,即在 RNN 的基础上添加一个 memory cell \(c_t\),让 \(c_t\) 只会被部分更新。更具体地,我们建立 forget gate \(f_t\)(用于遗忘掉部分不重要的信息),input gate \(i_t\)(用于从输入中提取重要的信息),output gate(根据记忆算出下一个状态)\(o_t\),即 \(h_t=o_t\odot\tanh(c_t),c_t=f_t\odot c_{t-1}+i_t\odot\tilde{c_t},Y_t=g(h_t)\)。
词嵌入(word embedding):用多维空间中的向量来表示一个词的含义。
怎么学习词嵌入呢?CBOW。根据 distributional hypothesis,经常一起出现的词应该具有类似的词嵌入,这样我们就有了 Word2Vec 算法:给定 \(2k\) 个词 \(c_{-k},c_{-k+1},\cdots,c_{-1},c_1,c_2,\cdots,c_k\) 作为上下文和某个词 \(w\),考虑定义 \(P(w,c)=\prod\dfrac{1}{1+\exp(w^Tc_i)}\)。这样给若干段语料,将每段语料对应的 \((c,w)\) 加入 \(D^+\),同时再随机选一个词 \(w'\) 将 \((c,w')\) 加入 \(D^-\),这样使用梯度下降法最大化 \(\sum\limits_{(w,c)\in D^+}\log P(w,c)-\sum\limits_{(w,c)\in D^-}\log P(w,c)\) 就可以得到每个词的 word embedding 了。
还有一种方法是 Skip-gram。和 CBOW 相反,Skip-gram 是将中心词当作 context 去预测周围词的 embedding,即将每段语料的 \((w,c)\) 加入 \(D^+\),然后随机选择一些词 \(w'\) 将 \((w',c)\) 加入 \(D^-\),并最大化 \(\sum\limits_{(w,c)\in D^+}\log P(w,c)-\sum\limits_{(w',c)\in D^-}\log P(w,c)\),这种方法比较适合学习低频词的 embedding。
Beam search:进行 next-token prediction 的时候,保留概率最高的 \(k\) 个候选词。
Lecture 9
Seq2seq 模型:由两个 RNN 组成,\(f_{enc}\) 负责将输入 \(X\) 变换为隐藏状态 \(h\),\(f_{dec}\) 则将隐藏状态解码为输出 \(Y\)。可使用 BPTT 训练。
我们可以给 seq2seq 模型添加注意力机制,即我们在输出 \(Y_t\) 的时候,学一个注意力分布 \(P_{att}(X_i|h_{t-1})\) 表示你想要放多少注意力在输入 \(X_i\) 上,然后结合 \(f_{enc}\) 生成的 hidden state \(h_i^{enc}\) 算出注意力输出 \(h_{att}^{enc}\),最后根据 \(h_{t-1}\) 和 \(h_{att}^{enc}\) 生成 \(Y_t\)。
那么究竟什么是注意力机制呢?给定任意一个词嵌入组成的向量集 \(\{v_i\}\) 和一个询问 \(q\),注意力机制能够根据向量集中每个元素和 \(q\) 的相关程度生成一个分布 \(\alpha_i=\text{softmax}(f(v_i,q))\),然后根据 \(\alpha\) 计算注意力输出 \(\sum\alpha_i v_i\)。常用的 \(f\) 有乘法注意力 \(f(v_i,q)=q^TWv_i\) 和加法注意力 \(f(v_i,q)=u^T\tanh(W_1v_i+W_2q)\)。
自注意力机制(self-attention):对于序列中的每个元素,计算该元素与序列中所有其他元素的相关性,生成一个加权的表示,其中权重反映了元素间的相互关系。具体来说,首先输入序列会被映射到 query, key, value 三个向量,即 \(k_t=W^kX,v_t=W^vX,q_t=W^qX\),其次查询向量会和键值向量做点积并归一化得到注意力积分,即 \(\alpha_{t,j}=\text{softmax}(q_t^Tk_j)\),最后计算注意力输出 \(out_t=\sum\limits_{j}\alpha_{t,j}v_j\)。
朴素的 self-attention 存在如下问题:
- 序列顺序问题:自注意力机制本身是位置无关的。解决方案:计算中引入相对位置信息,即 \(\alpha_{t,j}=\text{softmax}(q_t^T(k_j+p_{i-j})),out_i=\sum\limits_{j}\alpha_{i,j}(v_j+p_{i-j})\)。
- 缺乏非线性:在自注意力层输出 \(out_i\) 后添加 MLP,通过激活函数引入非线性变换。
- 在自回归模型中,当前时刻的输出只能取决于过去时刻的输入,而朴素的 self-attention 机制违背了这一要求。解决方案:引入注意力掩码,在计算注意力权重时屏蔽未来位置的信息。
Multi-headed attention:将 \(q,k,v\) 的维度分成 \(h\) 部分,每一部分捕捉不同子空间的语义信息,然后合并。
cross-attention:decoder 从 encoder 的输出中提取信息。