卷积神经网络(CNN)

卷积层

提取图像中的局部特征,其原理是通过许多的卷积核 (filter, kernel) 在图片上进行滑动提取特征。

卷积核

  • 特性:权值共享(一个卷积核滑动提取图像的某一个特征,进而带来平移不变性)、局部连接(感知图像的局部信息)
  • 参数:核大小 Kernel Size、步长 Stride、卷积核数量(通道) Channel、边界填充 Padding
  • 输出大小计算公式:$ H_{out} = \frac{H_{in} - K + 2P}{S} + 1 $,$ W_{out} = \frac{W_{in} - K + 2P}{S} + 1 $

注:卷积核通常设定为奇数的原因?(保证padding时候,图像的两边依然相对称),3×3 的卷积核是最优选择。

感受野

  • 概念:输出特征图上的像素点对于原图的映射区域的大小

1 × 1 卷积

作用:
(1)实现信息的跨通道交互和整合;
(2)对卷积核通道数进行降维或升维,减小参数量。

K × K 卷积

⼤多数情况下,通过 堆叠较⼩的卷积核 ⽐直接采⽤ 单个更⼤的卷积核 会更加有效。**
如:两层 3×3 卷积会比一层 5×5 卷积有效(深度更大),且 参数量更小($3\times3\times2<5\times5$)

3 × 3 卷积的实现

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
import numpy as np 

def Conv2d(img, in_channels, out_channels, kernels, bias=False, stride=1, padding=0):
N, C, H, W = img.shape
kh, kw = kernels.shape
assert C == in_channels

if padding:
img = np.pad(img, ((0, 0),(0, 0),(padding, padding),(padding, padding)), 'constant')

out_h = (H + 2*padding - kh) // stride + 1
out_w = (W + 2*padding - kw) // stride + 1

outputs = np.zeros([N, out_channels, out_h, out_w])

for n in range(N):
for c in range(out_channels):
for i in range(in_channels):
for h in range(out_h):
for w in range(out_w):
for x in range(kh):
for y in range(kw):
outputs[n][c][h][w] += img[n][i][h*stride+x][w*stride+y] * kernels[x][y]
return outputs

img = np.random.random(size=(1, 3, 32, 32))
kernel = np.random.random(size=(3, 3))
outputs = Conv2d(img, in_channels=3, out_channels=3, kernels=kernel, bias=False, stride=1, padding=1)
print(img, kernel, outputs)

分组卷积

深度可分离卷积

可变形卷积

转置卷积

棋盘效应

产生原因:卷积计算后差异被放大所导致的明暗相间的网格状。

stride=2, kernel size=2
stride=2, kernel size=3
stride=2, kernel size=4

解决办法:(推荐使用第二种)
(1)设置的 kernel size 能够被 stride 整除;(无法从根本上解决问题)
(2)采用双线性插值+卷积,即先利用双线性插值上采样,以减小插值的像素和原输入像素值的大小差异,再进行卷积可以避免棋盘效应的产生。

池化层

主要用来缩小特征图的大小,减少计算量和参数量(降维)、减少过拟合问题、缓解卷积层对位置的敏感度。

上采样

反卷积(转置卷积)

插值法(双线性插值)

反池化(Unpooling / Unsampling)

全连接层

全连接层中的每个神经元与其前一层的所有神经元进行中全连接,全连接层可以整合卷积层或者池化层中具有类别区分性的局部信息

FC、MLP 和 DNN

MLP (多层感知机)至少两层 全连接层(FC)堆叠得到的模型,能够解决单层感知机无法解决的 非线性问题
DNN(深度神经网络):网络深度较大的 MLP

Dropout

Dropout 被大量利用于全连接网络,而由于卷积自身的稀疏化以及稀疏化的 ReLU 函数(置零特性)的大量使用等原因,Dropout 策略也逐渐被淘汰。

  • 训练过程中 Dropout 函数的 re-scale

dropout 在训练过程中以一定概率 p 使神经元 失活,则为了保证随机失活后被保留的神经元的期望保持不变,则需要对神经元的数值进行 re-scale,不妨设输入序列为 $X=[1, 1, 1, 1, 1]$,设以失活概率 p=0.2 对该序列进行 mask 后的序列为 $X’=[1, 0, 1, 1, 1]$,易知 $E(X)=1, E(X’)=0.8$,因此为了 保证期望不变,需要对 $X’$ 的数值进行 $\frac{1}{1-p}$ 倍的放大(re-scale),本例中 $E(\frac{X’}{0.8})=1$。

归一化层

将输入的特征图 $x \in \mathbb{R}^{N \times C \times H \times W}$ 比喻成一摞书,这摞书总共有 $N$ 本,每本有 $C$ 页,每页有 $H$ 行,每行有 $W$ 个字符;
(1)BN 是在 batch 上,对 N、H、W 做归一化,而保留通道 C 的维度。BN 对较小的 batch size 效果不好。**BN 适用于固定深度的前向神经网络**,如 CNN,不适用于 RNN
注:BN 相当于把这些书按页码一一对应地加起来,再除以每个页码下的字符总数:$N×H×W$;
(2)LN 在通道方向上,对 C、H、W 归一化,主要 RNNTransformer 效果明显
注:LN 相当于把每一本书的所有字加起来,再除以这本书的字符总数:$C×H×W$;
(3)IN 在图像像素上,对 H、W 做归一化,用在 风格化迁移
注:IN 相当于把一页书中所有字加起来,再除以该页的总字数:$H×W$;
(4)GNchannel 分组,然后再做归一化;
注:GN 相当于把一本 $C$ 页的书平均分成 $G$ 份,每份成为有 $C/G$ 页的小册子,对每个小册子做 Norm

Batch Normalization

  • 算法步骤

(0)给定 1 个 $batch=m$ 的 输入 $X=[x^{(1)},x^{(2)},…,x^{(m)}]$,在神经网络某一层对应的中间隐藏值为 $Z=[z^{(1)},z^{(2)},…,z^{(m)}]$;

(1)计算均值: $\mu = \frac{1}{m}\sum_{i=1}^{m}z^{(i)}$

(2)计算方差: $\sigma^{2}=\frac{1}{m}\sum_{i=1}^{m}(z^{(i)}-\mu)^2$

(3)归一化: $z_{norm}^{(i)}=\frac{z^{(i)}-\mu}{\sqrt{\sigma^2 + \epsilon}}$ ,其中 $\epsilon$ 是为了防止除 0

(4)缩放和平移: $\tilde{z}^{(i)}=\gamma z_{norm}^{(i)}+\beta$ ,其中 $\gamma$ 和 $\beta$ 是要训练的超参数。

  • Why BN works?

BN 的作用
(1)加速训练,可以使用更大的学习率;
(2)解决 梯度消失和梯度爆炸
(3)有 轻微的正则化作用(相当于给隐藏层加入噪声),神经网络无需再使用 dropoutL2 正则。

有效的原因?(说法有很多种,以下为个人见解)
(1)加速训练:归一化使得每层输入的特征都处于同一分布或尺度,这种情况下的数据拟合更高效;(理论解释:对特征进⾏了归⼀化,其对应的等⾼线会显得很圆(下右图),在梯度下降进⾏求解时能较快的收敛。)
(2)梯度问题:数据归一化到区间 [-1,1] 内,能够有效避免梯度弥散,且减少了链式求导法则带来的梯度依赖;
(3)正则化:每次使用的是当前 batch 的均值和方差而不是整个数据集的均值和方差,引入了些微噪声。因此,Batch size 越大,正则化效果越弱。

  • Python实现
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
class MyBN:
def __init__(self, momentum, eps, num_features):
"""
初始化参数值
:param momentum: 追踪样本整体均值和方差的动量
:param eps: 防止数值计算错误
:param num_features: 特征数量
"""

self.running_mean = 0
self.running_var = 1

self.momentum = momentum

self.eps = eps
self.beta = np.zeros(shape=(num_features, ))
self.gamma = np.ones(shape=(num_features, ))

def batch_norm(self, x):
x_mean = x.mean(axis=0)
x_var = x.var(axis=0)

self.running_mean = (1-self.momentum)*x_mean + self._momentum*self.running_mean
self.running_var = (1-self.momentum)*x_var + self._momentum*self.running_var

x_hat = (x-x_mean) / np.sqrt(x_var+self.eps)
y = self.gamma*x_hat + self.beta

return y

Layer Normalization

RNNs 网络中,不同的 mini-batch 可能具有 不同的输入序列长度(深度),计算统计信息比较困难,而且测试序列长度不能大于最大训练序列长度;

  • 算法步骤

(0)对于前向神经网络的第 $l$ 个隐藏层(等价于 RNNs 中 $x^{l}$ 时刻对应的隐藏层),令 $a^{l}$ 表示输入向量(前层网络输出加权后的向量),$H$ 表示隐藏单元数量;

(1)计算均值:$\mu^{l}=\frac{1}{H}\sum_{i=1}^{H}a_{i}^{l}$,在 通道维度 上求每一个 token 的均值(方差同理);

(2)计算方差:$\sigma^{l}=\sqrt{\frac{1}{H}\sum_{i=1}^{H}(a_{i}^{l}-\mu^{l})^{2}}$;

(3)归一化:$z_{norm}^{l}=\frac{z^{l}-\mu^{l}}{\sqrt{(\sigma^{l})^{2} + \epsilon}}$;

(4)缩放和平移:$\tilde{z}^{l}=\gamma z_{norm}^{l}+\beta$。

LN 的优势::无需批训练,适用于 batch size1 的数据输入

一个很好的解释:
深度学习里的正则化方法就是 “通过把一部分不重要的复杂信息损失掉,以此来降低拟合难度以及过拟合的风险,从而加速了模型的收敛”
Normalization 目的就是让分布稳定下来(降低各维度数据的方差)。
&nbsp;
不同正则化方法的区别只是操作的信息维度不同,即选择损失信息的维度不同。
CV 场景中,各个 Channel 维度中的信息原封不动,因为数据在不同 channel 中的信息很重要,如果
channle 维度进行归一化将会损失不同 channel 的差异信息。

NLP 中不同 batch 样本的信息关联性不大,而且由于不同的句子长度不同,强行归一化会损失不同样本间的差异信息,所以就没在 batch 维度进行归一化,而是选择 Layer Normalization,只考虑的句子内部维度的归一化。 可以认为 NLP 应用场景中一个样本内部维度间是有关联的,所以在信息归一化时,对样本内部差异信息进行一些损失,反而能降低方差。
&nbsp;
总结:选择什么样的归一化方式,取决于你关注数据的哪部分信息。如果某个维度信息的差异性很重要,需要被拟合,那就别在那个维度进行归一化。

激活函数

激活函数和归一化的顺序问题?
若激活函数为 ReLU,则必须将 BN 置于激活前,否则经过 ReLU 后的失活神经元会造成归一化的偏移和抖动。若激活函数为 Sigmoid 或 tanh,则顺序根据实验效果而定。

Sigmoid

$$f(x)=\frac{1}{1+e^{-x}}$$

劣势:(1)梯度弥散(消失或爆炸);(2)求导耗时;(3)不关于原点对称;(4)收敛速度慢;

激活函数关于原点对称的重要性:
Sigmoid 的非原点对称的特点导致所有参数的梯度方向都是同向的;而深度学习模型的参数在更新时,不一定都朝着同一(正向/反向)梯度方向更新,因此 sigmoid 这一特点使得模型收敛速度减慢了;

tanh

$$f(x)=\frac{e^{x}-e^{-x}}{e^{x}+e^{-x}}$$

优势:(1)关于原点对称;(2)收敛速度比 sigmoid 更快;
劣势:(1)梯度弥散(消失或爆炸);

为什么 tanh 比 sigmoid 收敛快?
tanh 激活函数关于原点对称,训练过程中梯度可以朝着两个方向呈现 zigzag 形式的更新,更容易达到最优值。

ReLU

$$f(x)=\begin{cases} x, x>0, \\ 0, x<0 \end{cases}$$

优势:(1)求导运算量小;(2)有效避免梯度消失;(3)置零能够缓解过拟合。
劣势:(1)神经元死亡且不会复活;


循环神经网络(RNN)

RNNCNN 中的梯度问题,为什么 RNN 更容易梯度消失或爆炸?
(1)**RNN:长时间序列的传播过程会用到前一时刻的信息,导致 n相同的 雅可比矩阵 W 连续相乘;(解决方法:梯度截断
(2)
CNN:每层的参数矩阵** W 不同;(解决方法:激活函数,正则化等

LSTM

三个门
(1)遗忘门(Forget:最左侧 Sigmoid,选择保留(遗忘)旧的信息
(3)输入门(Input:中间的 Sigmoid + tanh,选择保留(遗忘)新的信息
(3)输出门(Output:最右侧 Sigmoid + tanh选择输出内容。

LSTM 如何解决梯度问题?
当前的 cell informaton 是通过 input gate 控制之后叠加的,RNN 是叠乘。

为什么既存在tanh和sigmoid,而不统一采用一样的?
sigmoid 用于门控处理(一般不可替换),tanh 用于状态输出(可替换)

GRU

进一步解决长期记忆反向传播中的梯度等问题

两个门
(1)更新门(Update:两个 Sigmoid合并了 LSTM 中的输入门和遗忘门,分别选择保留(遗忘)新/旧的信息;
(2)重置门(Reset:一个 tanh,选择输出内容。


生成模型

根据真实分布 p-data(x) 的训练数据,通过训练学习得到近似于真实的分布 p-model(x) 的新样本数据。

生成模型与判别模型

Pixel RNN / CNN

从左上角开始定义 之前的像素,生成图像 x条件概率分布 为:
$$p(x)=\prod_{i=1}^{n}p(x_{i}|x_{1},…,x_{i-1})$$
:对于 Pixel RNN 而言,公式中的每一项的输出概率 $p(x_{i})$ 都依赖于之前所有概率 $p(x_{1}),…,p(x_{i-1})$;
Pixel CNN 在训练时可以 并行计算 公式中的每一项,然后进行参数更新,因此 训练速度远快于 Pixel RNN

训练方式
(1)前向传播:根据上面的公式求出似然
Pixel RNN 需要 从左上到右下串行 走一遍,而 Pixel CNN 并行计算所有像素点);
(2)最大化似然 以对参数 做一轮更新
测试方式
Pixel RNNPixel CNN 都要 从左上角开始逐个像素点地生成图片

Pixel RNN / CNN 的优劣势:
优势:是一种 可优化的显式密度模型,可以通过似然评估生成质量;
劣势:由于需要逐像素点生成图像,实际应用中的 速度很慢

变分自编码器(VAE)

待补充……

生成对抗网络(GAN)

核心思路

GAN 中我们定义了两个网络:生成器判别器
生成器:利用随机噪声 $z$ 生成尽可能真的样本 以骗过判别器。
判别器:辨别区分 生成器生成的假样本训练集中抽出来的真样本

对抗形式:
$$\min_{\theta_{g}}\max_{\theta_{d}}[\mathbb{E}_{x \sim p_{data}} \log D_{\theta_{d}}(x) + \mathbb{E}_{z \sim p_{z}} \log (1-D_{\theta_{d}}(G_{\theta_{g}}(z)))]$$
其中第一项为输入真实数据 $x \sim p_{data}$,第二项为输入生成数据 $G_{\theta_{g}}(z)$,优化过程:
对判别器网络训练 K 次,使目标函数在判别器参数 $\theta_{d}$ 下最大化,
(1)使得 $D_{\theta_{d}}(x)$ 接近 1,即将真实样本 $x$ 判定为真;
(2)使得 $D_{\theta_{d}}(G_{\theta_{g}}(z))$ 接近 0,即将生成样本 $G_{\theta_{g}}(z)$ 判定为假;
对生成器网络训练 1 次,使目标函数在生成器参数 $\theta_{g}$ 下最小化,
(3)使得 $D_{\theta_{d}}(G_{\theta_{g}}(z))$ 接近 1,即骗过判别器将生成样本 $G_{\theta_{g}}(z)$ 判定为真;

生成分布和真实分布之间的差异衡量
(1)KL 散度:
$$KL(P(x)||Q(x)) = \sum_{x \in X}[P(x) \log\frac{P(x)}{Q(x)}]=\mathbb{E}_{x \sim P(x)}[\log\frac{P(x)}{Q(x)}],$$
然而,KL 散度具有不对称性,即 $KL(P||Q) \neq KL(Q||P)$
(2)JS 散度:
$$JS(P(x)||Q(x)) = \frac{1}{2}KL(P(x)||\frac{P(x)+Q(x)}{2}) + \frac{1}{2}KL(Q(x)||\frac{P(x)+Q(x)}{2}),$$
JS 散度则具有对称性,即 $JS(P||Q) = JS(Q||P)$,且值域范围为 $[0, 1]$

原始 GAN 存在的问题

(1)梯度消失
判别器网络的训练令其过于强大,导致生成分布和真实分布不重叠或者重叠较小,

当两个分布没有重叠部分时,此时的 JS 散度为
$$JS(P_{data}(x)||P_{g}(x))=\frac{1}{2}\mathbb{E}_{x \sim P_{data}(x)}[\log\frac{2P_{data}(x)}{P_{data}(x)+P_{g}(x)}] + \frac{1}{2}\mathbb{E}_{x \sim P_{g}(x)}[\log\frac{2P_{g}(x)}{P_{data}(x)+P_{g}(x)}],$$
不妨设 $P_{data}(x)=0, P_{g}(x)\neq0$ 或 $P_{data}(x)\neq0, P_{g}(x)=0$,则 $JS(P_{data}(x)||P_{g}(x))=\log2$,此时生成器的 梯度消失,无法更新。

当两个分布有重叠部分时,有文献指出,两个分布在高维空间是很难相交的,即使相交,其相交部分其实是高维空间中的一个低维流形,可以忽略不计,则此时的 JS 散度依然为常数,生成器依然 梯度消失,无法更新。

(2)模式崩塌(Mode Collapse)
崩塌的概念是针对 生成判别对抗模式 而言的,是指 GAN 生成了与真实样本相同的样本,但 生成样本不具多样性(或说存在大量重复的样本),但在这种情况下 判别器却认为生成器的性能优越

如左下图中的绿色样本,右下图中的重复样本。

Wasserstein GAN(W-GAN)

引入了 Wasserstein 距离(也称 Earth-Mover (EM) 距离),无论两个分布多远,都有梯度,相对 KL 散度与 JS 散度具有优越的平滑特性,理论上可以解决 真实分布和生成分布不重叠或重叠部分可忽略时 出现的梯度消失问题

将两个分布 $p$ 和 $q$ 看成两堆土,如下图所示,希望把其中的一堆土移成另一堆土的位置和形状,有很多种可能的方案。推土代价被定义为移动土的量乘以土移动的距离,在所有的方案中,存在一种推土代价最小的方案,这个代价就称为两个分布的 Wasserstein 距离。

Wasserstein 距离的形式化的表达式如下:$$W(p,q)=\inf\limits_{\gamma\sim\prod(p,q)}E_{x,y\sim\gamma}[||x-y||]$$其中, $\prod(p,q)$ 表示​分布 $p$ 和 $q$ 组合起来的所有可能的联合分布的集合。

对于每一个可能的联合分布 $\gamma$,可以从中采样一对样本​ $x$ 和​​​ $y$,$(x,y)\sim\gamma$,并计算出这对样本的距离 $||x-y||$,计算该联合分布 $\gamma$ 下,样本对距离的期望值 $E_{x,y\sim\gamma}[||x-y||]$。

用推土的方式理解就是,$E_{x,y\sim\gamma}[||x-y||]$ 是在 $\gamma$ 路径规划下,把 $p$ 移动成​ $q$ 的消耗,而 Wasserstein 距离就是在“最优路径规划”下的最小消耗,也即所有可能的联合分布中能够对这个期望值取到的下界

CycleGAN

待补充……


Transformer

Transformer(Encoder(左),Decoder(右))
Multi-head Self-attention

Encoder

EncoderN=6 个相同的 layers 组成, 每个 layers 的结构:
(1)多头注意力层(Multi-head attention layer);
(2)前馈层(Feed Forward Layer);
每个 sub-layer 都加了残差连接和归一化。

Positional Embedding

Multi-head Attention

多头注意力计算过程

Head 数等于 4 为例

计算步骤

(1)求出 $Q, K, V$

这里是求 MultiHead 的 $Q,K,V$,所以 Shape 为 (batch, head数, 词数,d_model/head数)

  • 首先,通过定义的 $W^q,W^k,W^v$ 求出 SelfAttention 的 $Q,K,V$,此时 $Q,K,V$ 的 Shape 为 (batch, 词数, d_model),对应代码为 linear(x)
  • 分成多头,即将 Shape 由 (batch, 词数, d_model) 变为 (batch, 词数, head数,d_model/head数)。对应代码为 view(nbatches, -1, self.h, self.d_k)
  • 最终交换 “词数” 和 “head数” 这两个维度,将 head数 放在前面,最终 shape 变为 (batch, head数, 词数,d_model/head数)。对应代码为 transpose(1, 2)

(2)通过 attention 函数计算出 Attention 结果

$$Attention(Q,K,V)=softmax(\frac{QK^{T}}{\sqrt{d_{k}}})V$$

这里 xshape 为 (batch, head数, 词数,d_model/head数),self.attnshape 为 (batch, head数, 词数,词数)

(重点)注:self-attention 为什么要除以 $\sqrt{d_{k}}$参考
目的:使得 attention 的结果处于一个合适的区间(数值不大不小),结果中个别数值偏大或整体偏小都会导致梯度消失(解释如下),同时也起到归一化的作用;
解释:个别数值偏大 会导致数据数量级差距过大,softmax 会将概率分布(p=1)全部分配给最大值的标签,导致其他类别对应的偏导向量值为 $0$;
整体数值偏小
则会导致梯度过小,会导致在前馈或反馈的过程中梯度消失。
解决方案:attention 的结果进行 scale,缩小数据范围,扩大数据差异;
数学证明:假设 $Q, K$ 均服从期望为 $0$,方差为 $1$ 的概率分布,则 $$E(Q)=E(K)=E(QK)=0, D(Q)=D(K)=1,$$可得
$$D(QK)=D(\sum_{i=0}^{d_{k}}q_{i}k_{i})=d_{k}\times1=d_{k},$$由 $D(\frac{X}{a})=\frac{D(X)}{a^{2}}$ 可得$$D(\frac{QK}{\sqrt{q_{k}}})=\frac{d_{k}}{(\sqrt{d^{k}})^{2}}=1$$

(3)合并多个 head 的结果

即将 xshape 由 (batch, head数, 词数,d_model/head数),再变为 (batch, 词数,d_model)

  • 首先,交换 “head数”和“词数”,这两个维度,结果为(batch, 词数, head数, d_model/head数),对应代码为:x.transpose(1, 2).contiguous()
  • 然后将 “head数” 和 “d_model/head数” 这两个维度合并,结果为(batch, 词数,d_model)。
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
# 按注意力公式计算结果
def attention(query, key, value):
d_k = query.size(-1)
scores = torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(d_k)
p_attn = scores.softmax(dim=-1)
return torch.matmul(p_attn, value)


class MultiHeadedAttention(nn.Module):

def __init__(self, h, d_model):
super(MultiHeadedAttention, self).__init__()
assert d_model % h == 0

self.d_k = d_model // h
self.h = h

self.linears = [
nn.Linear(d_model, d_model),
nn.Linear(d_model, d_model),
nn.Linear(d_model, d_model),
nn.Linear(d_model, d_model),
]

def forward(self, x):
nbatches = x.size(0)

query, key, value = [
linear(x).view(nbatches, -1, self.h, self.d_k).transpose(1, 2)
for linear, x in zip(self.linears, (x, x, x))
]

x = attention(query, key, value)

x = (x.transpose(1, 2).contiguous().view(nbatches, -1, self.h * self.d_k))

return self.linears[-1](x)


# 定义8个head,词向量维度为512的多头注意力层
model = MultiHeadedAttention(8, 512)

# 传入一个batch_size为2, 7个单词,每个单词为512维度
x = torch.rand(2, 7, 512)
print(model(x).size())

Layer Normalization

见 1.4.2。

Feed Forward

前馈全连接层的作用:
考虑注意力机制可能对复杂过程的拟合程度不够,通过增加两层网络来增强模型的能力。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class PositionwiseFeedForward(nn.Module):
def __init__(self, d_model, d_ff, dropout=0.1):
super(PositionwiseFeedForward, self).__init__()

self.w1 = nn.Linear(d_model, d_ff)
self.w2 = nn.Linear(d_ff, d_model)
self.dropout = nn.Dropout(p=dropout)

def forward(self, x):
x = self.w1(x)
x = F.relu(x)
x = self.dropout(x)
x = self.w2(x)
return x

Decoder

DncoderN=6 个相同的 layers 组成, 每个 layers 的结构:
(1)带mask的多头注意力层
(2)多头注意力层(Multi-head attention layer);
(3)前馈层(Feed Forward Layer);
每个 sub-layer 都加了残差连接和归一化。

Masked Multi-head Attention

MultiHead-Attention和Masked-Attention的机制和原理


数据处理

数据增强

类别不平衡问题

分类任务中不同类别的训练样例数⽬差别很⼤的情况。

解决方案:
(1)扩大数据集;
(2)采样策略:对大类数据欠采样或对小类数据过采样;
(3)训练策略:代价加权,新的评价指标或算法;
(4)问题转化:子问题划分或将问题转换成小类样本检测问题(如异常点检测、变化趋势检测等)。


优化方法

各种优化器的计算公式(GD,SGD,batch GD,SGD+momentum,NAG,AdaGrad,RMSProp,Adam)
待补充……


损失函数

Mean Square Error(均方误差,MSE)

$$\mathcal{L}_{MSE}=\frac{1}{n}\sum_{i=1}^{n}(p_{i}-y_{i})^{2}$$
## Root Mean Square Error(均方根误差,RMSE)
$$\mathcal{L}_{RMSE}=\sqrt{\frac{1}{n}\sum_{i=1}^{n}(p_{i}-y_{i})^{2}}$$
## Mean Absolute Error(平均绝对误差,MAE)
$$\mathcal{L}_{MAE}=\frac{1}{n}\sum_{i=1}^{n}|p_{i}-y_{i}|$$
## Cross Entropy(交叉熵,CE)
$$\mathcal{L}_{CE}=-\frac{1}{n}\sum_{i=1}^{n}y_{i}\log(p_{i})$$
Weighted Cross Entropy(带权交叉熵,WCE)
$$\mathcal{L}_{WCE}=-\frac{1}{n}\sum_{i=1}^{n}w_{i}y_{i}\log(p_{i})$$
Binary Cross Entropy(二类交叉熵,BCE)
$$\mathcal{L}_{BCE}=-\frac{1}{n}\sum_{i=1}^{n}(y_{i}\log(p_{i})+(1-y_{i})\log(1-p_{i}))$$
## Dice Loss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class SoftDiceLoss(nn.Module):
def __init__(self, weight=None, size_average=True):
super(SoftDiceLoss, self).__init__()

def forward(self, logits, targets):
num = targets.size(0)
// 为了防止除0的发生
smooth = 1

probs = F.sigmoid(logits)
m1 = probs.view(num, -1)
m2 = targets.view(num, -1)
intersection = (m1 * m2)

score = 2. * (intersection.sum(1) + smooth) / (m1.sum(1) + m2.sum(1) + smooth)
score = 1 - score.sum() / num
return score

## IOU Loss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#PyTorch
class IoULoss(nn.Module):
def __init__(self, weight=None, size_average=True):
super(IoULoss, self).__init__()

def forward(self, inputs, targets, smooth=1):
inputs = F.sigmoid(inputs)

inputs = inputs.view(-1)
targets = targets.view(-1)

intersection = (inputs * targets).sum()
total = (inputs + targets).sum()
union = total - intersection

IoU = (intersection + smooth)/(union + smooth)

return 1 - IoU

## Focal Loss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#PyTorch
ALPHA = 0.8
GAMMA = 2

class FocalLoss(nn.Module):
def __init__(self, weight=None, size_average=True):
super(FocalLoss, self).__init__()

def forward(self, inputs, targets, alpha=ALPHA, gamma=GAMMA, smooth=1):
inputs = F.sigmoid(inputs)

inputs = inputs.view(-1)
targets = targets.view(-1)

BCE = F.binary_cross_entropy(inputs, targets, reduction='mean')
BCE_EXP = torch.exp(-BCE)
focal_loss = alpha * (1-BCE_EXP)**gamma * BCE

return focal_loss

其他

目标检测

深度学习与计算机视觉教程(12) | 目标检测 (两阶段, R-CNN系列)
深度学习与计算机视觉教程(13) | 目标检测 (SSD, YOLO系列)

传统检测方法

三个步骤:
(1)滑动窗口选择候选区域;
(2)提取候选区域的视觉特征;
(3)分类器识别;
可以视为 穷举法

深度学习方法

两阶段和一阶段的区别:
(1)两阶段:生成一系列候选框,再通过 CNN 分类;(R-CNN、Fast R-CNN、Faster R-CNN 等)
(2)一阶段:直接将目标框的定位问题转化为回归问题;(YOLO、SSD 等)
注:两阶段方法精度更高,一阶段方法速度更快

R-CNN 系列

R-CNN

R-CNNRegion with CNN features) 尝试将爆火的 CNNAlexNet)应用到目标检测的特征提取过程中

Insights:
(1)用 CNN 做特征提取;
(2)迁移学习的策略应对检测数据量少的问题,也就是预训练

检测方案:
(1)直接回归锚框坐标;
(2)滑动窗口;
(3)候选框策略。(RCNN

Fast R-CNN

Faster R-CNN

YOLO 系列

YOLO V1(Paper

YOLO V2(Paper

YOLO V3(Paper

YOLO V4(Paper

YOLO V5

待补充……

无监督学习

  • 聚类
  • 主成分分析(PCA)

半监督学习

待补充……

自监督学习

自监督中的崩溃解问题的理解