Classx-GAN
1. GAN基本理论
神经网络世界中,根据目标不同,可以分为两大类:
判别网络(discriminative learning):得到数据到label的映射模型,比如分类和回归模型。该部分通过反向传播技术,已经达到很好的效果;
生成模型(Generative learning):学习出给定数据集的样本分布,生成相似的新样本。
两种类别并非完全独立,比如,近几年来,学术界常常使用分类模型解决非监督问题,RNN解决的问题是利用之前词语预测下一个词语,该问题也可以看作是一个生成模型,只不过分类模型中,是使用一个词语预测后面一个词语,而生成模型中,是将上述过程批量化,输入一个词语序列,生成另一个词语序列。
2014年,GAN横空出世,全称为Generative Adversarial Networks–生成对抗网络。我们可以使用分类模型来得到生成模型。GAN模型的基本理念为:一个好的生成器其生成的数据,分类器无法将其与真实数据区分。因此,我们构建以下GAN生成器:
关注的要点:
1)GAN的网络结构由两部分组成:生成器(Generator)和分类器(Discrimitor)。
2)网络输入为:噪声noise
z
z
z和真实数据Data
x
x
x。
3)生成器依靠
z
z
z生成fake数据
G
(
z
)
G(z)
G(z),与
x
x
x共同送入分类器中,最终得到判断该数据为真or假。
4)上述过程成为一个针对生成器和分类器的博弈过程,生成器要生成可以以假乱真的数据,分类器练就火眼金睛可以愈发区分真假数据。
5)生成器可为任意种类:深度神经网络、游戏虚拟引擎、声音处理器…
根据以上分析,自然而然,loss函数必须能够体现上述博弈过程:
分类器:
分类器模型
D
(
x
)
D(x)
D(x)的目标即为输出二值分类结果:隐层输出通过sigmoid函数,再使用交叉熵损失函数:
生成器:
生成器模型
G
(
z
)
G(z)
G(z),依靠一组随机噪声输入
z
z
z,该模型目标为
D
(
G
(
z
)
)
→
1
D(G(z))\rightarrow1
D(G(z))→1,因此损失函数为交叉熵(下式中,
y
=
0
y=0
y=0):
若分类器训练得很好,使得
D
(
G
(
z
)
)
→
0
D(G(z))\rightarrow0
D(G(z))→0,则上式中生成器的loss变为常数0不变化,所以我们对该loss做以下改进:
此时,当
D
(
G
(
z
)
)
→
0
D(G(z))\rightarrow0
D(G(z))→0,loss函数还是能够有一个较大的数值,以保证导数不为0。
至此,生成器
G
G
G和分类器
D
D
D通过以下loss和模型结构,形成博弈局面:
2. GAN应用实例
todo
Classx-DCGAN
上节中,我们使用了一个线性函数作为生成器,3层线性函数+激活函数作为分类器,进行一个高斯分布的函数数据输入的GAN模型训练。
本节中,我们使用DCGAN(Deep Convolutional Generative Adversarial Networks)进行图像生成。
具体操作
a) 下载Pokemon Dataset
使用ToTensor指令,将图像全部转变为tensor变量,需要注意的是:该指令将值域映射为[0,1],而我们的生成器产生的输出值域为[-1,1],因此我们将数据归一化到以0.5为均值,0.5为标准差的范围中。
b) 生成器 (
G
G
G)
G
G
G将
d
d
d维向量,映射为
64
∗
64
64*64
64∗64的RGB图像。基本构成为:转置卷积层+BN+ReLU。
在操作中,我们使用全卷积网络(使用转置卷积层)将输入图像放大。
c)分类器
分类器是一个常见的图像分类模型,值得注意的是:该分类器使用了leaky ReLU函数作为激活层:
使用leaky ReLU函数的原因是,由于原始函数在小于0时候全0,因此梯度消失,leakyReLU则不会出现该问题。
d)训练
对于分类器和生成器使用相同的学习率,且随着训练的增加,学习率逐渐减少。
Classx-样式迁移
直白来说,我们想要构建一张图像
c
c
c,它有图像
a
a
a的内容,使用图像
b
b
b的风格,这样的例子,就是样式迁移(style transfer)。
以下图为例:
网络结构如下图所示:
具体操作如下所示:
1)初始化合成图像,例如将其初始化成内容图像,该合成图像是样式迁移过程中唯一需要更新的变量,即样式迁移所需迭代的模型参数;
2)我们选择一个预训练的卷积神经网络来抽取图像的特征,其中的模型参数在训练中无须更新。深度卷积神经网络凭借多个层逐级抽取图像的特征。我们可以选择其中某些层的输出作为内容特征或样式特征。
3)接下来,我们通过正向传播(实线箭头方向)计算样式迁移的损失函数,并通过反向传播(虚线箭头方向)迭代模型参数,即不断更新合成图像。
样式迁移常用的损失函数由3部分组成:1)内容损失(content loss)使合成图像与内容图像在内容特征上接近;2)样式损失(style loss)令合成图像与样式图像在样式特征上接近;3)而总变差损失(total variation loss)则有助于减少合成图像中的噪点。最后,当模型训练结束时,我们输出样式迁移的模型参数,即得到最终的合成图像。
具体操作
1)读取数据
读取内容图像和样式图像,两者大小可以不一致。
2)预处理和后处理图像
预处理函数preprocess对输入图像在RGB三个通道分别做标准化,并将结果变换成卷积神经网络接受的输入格式。
后处理函数postprocess则将输出图像中的像素值还原回标准化之前的值。
3)抽取特征
我们使用基于ImageNet数据集预训练的VGG-19模型来抽取图像特征 [1]。
我们可以选择VGG网络中某些层的输出。一般来说,越靠近input的输出越容易抽取图像的细节信息(样式信息);反之越靠近output则越容易抽取图像的全局信息(内容信息)。
抽取特征所用的网络:VGG从input到最后一个样式/内容层中的所有层。
4)定义损失函数
由内容损失、样式损失和总变差损失3部分组成。
内容损失:使用平方误差函数,衡量在内容层feature map上的差异loss;
样式损失:使用Gram matrix衡量特征相关性,表征在样式层feature map上的差异loss;
总变差损失:对于合成图像的高频噪点,即有特别亮或者特别暗的颗粒像素。一种常用的降噪方法是总变差降噪(total variation denoising),即使得每个pixel亮度值尽量平滑:
损失函数则定义为上述三个loss的加权值。
5)创建和初始化合成图像
在样式迁移中,合成图像是唯一需要更新的变量。我们可以定义一个简单的模型GeneratedImage,并将合成图像视为模型参数。模型的前向计算只需返回模型参数即可。
6)训练
训练中,不断抽取合成图像的内容特征和样式特征,计算损失函数。
Classx-图像增广(数据增强)
数据增强,随机改变训练样本可以降低模型对某些属性的依赖,从而提高模型的泛化能力,是一种通过对训练图像做一系列随机改变,来产生相似但又不同的训练样本,从而扩大训练数据集的规模的方法。
数据增强包括以下几种(torchvision.transforms):
翻转(RandomHorizontalFlip()…)、裁剪(RandomResizedCrop())、变化颜色(ColorJitter)、叠加多个图像
Classx-模型微调
模型的训练不从头开始,而是基于某些已经训练比较好的大型模型,使得自己的模型可以快速得到比较好的效果。
比如我们可以使用分类1000类目标的训练好的分类网络,使用微调,得到分类桌子的分类模型。
微调方法一般如上图所示,包括以下几个步骤:
1)下载源数据集(如ImageNet)的训练好的神经网络模型,即源模型。
2)创建一个新的神经网络模型,即目标模型,该模型复制了源模型上除了输出层外的所有模型设计及其参数。
我们假设这些模型参数包含了源数据集上学习到的知识,且这些知识同样适用于目标数据集。我们还假设源模型的输出层跟源数据集的标签紧密相关,因此在目标模型中不予采用。
3)为目标模型添加一个输出大小为目标数据集类别个数的输出层,并随机初始化该层的模型参数。
4)在目标数据集(如椅子数据集)上训练目标模型。我们将从头训练输出层,而其余层的参数都是基于源模型的参数微调得到的。
Classx-目标检测和边界框
本节包括很多代码知识。
1. 锚框
目标检测算法通常会在输入图像中采样大量的区域,然后判断这些区域中是否包含我们感兴趣的目标,并调整区域边缘从而更准确地预测目标的真实边界框(ground-truth bounding box)。
不同的模型使用的区域采样方法可能不同。这里我们介绍其中的一种方法:它以每个像素为中心生成多个大小和宽高比(aspect ratio)不同的边界框。这些边界框被称为锚框(anchor box)。我们将在后面基于锚框实践目标检测。
2.锚框具体操作
输入图像为
h
∗
w
h*w
h∗w,产生一组
n
n
n个大小值
s
∈
(
0
,
1
]
s \in (0,1]
s∈(0,1],一组
m
m
m个宽高比
r
>
0
r>0
r>0,则对于任意一个中心点pixel,其锚框为高
h
=
s
/
r
h=\sqrt{s/r}
h=s/r,宽为
w
=
s
r
w=\sqrt{sr}
w=sr。
若
n
n
n个大小值与
m
m
m个宽高比组合,对于所有像素,将有
m
∗
n
∗
w
∗
h
m*n*w*h
m∗n∗w∗h个锚框,计算量巨大,重复很多,我们可以选择我们感兴趣的锚框进行生成计算,比如:
生成
(
n
+
m
−
1
)
∗
w
h
(n+m-1)*wh
(n+m−1)∗wh个锚框。
还有一种能有效减少锚框数量的方式是在多尺度目标检测时候,一种简单方法是在输入图像中均匀采样一小部分像素,并以采样像素为中心生成锚框,此外,在不同尺度下,我们可以生成不同数量和不同大小的锚框,基于一个基本假设:较小目标比较大目标在图像上出现位置的可能性更多,因此,当使用较小锚框来检测较小目标时,我们可以采样较多的区域;而当使用较大锚框来检测较大目标时,我们可以采样较少的区域。
3.衡量方式
衡量一个锚框与gt值之间的差距,使用二维图像上的交并比(IoU)评价相似度:
IoU的值域在0和1之间:0表示两个边界框无重合像素,1表示两个边界框相等。
4.锚框比较操作
有了loss函数,我们可以使用所有锚框与所有gt框进行比较,找到最大含有目标的估计结果。
锚框信息:a. 锚框位置大小;b. 锚框所含目标类别,简称类别;c. 实边界框相对锚框的偏移量,简称偏移量(offset)。
在目标检测时,我们首先生成多个锚框,然后为每个锚框预测类别以及偏移量,接着根据预测的偏移量调整锚框位置从而得到预测边界框,最后筛选需要输出的预测边界框。
问题为:多个锚框,多个目标,如何高效地找到每个目标的最大可能锚框?我们有以下操作:
- 构造 n a ∗ n b n_a*n_{b} na∗nb的矩阵 X X X, X X X的行代表候选锚框 A i A_{i} Ai,列代表真实边界框 B j B_{j} Bj, X i j X_{ij} Xij数值为 A i A_{i} Ai和 B j B_{j} Bj的交并比(IoU)。
- 对于 X X X,首先找到所有元素中最大值 X i 1 j 1 X_{i_{1}j_{1}} Xi1j1,则候选锚框 A i 1 A_{i_1} Ai1分配给 B j 1 B_{j_1} Bj1。
- 分配一组 A i 1 → B j 1 A_{i_1}\rightarrow B_{j_1} Ai1→Bj1后,将 X i 1 X_{i_1} Xi1行和 X j 1 X_{j_1} Xj1列全部删除(即 X i 1 j 1 X_{i_{1}j_{1}} Xi1j1所在行列全部清除)。
- 在新的 X X X上找到最大值 X i 2 j 2 X_{i_{2}j_{2}} Xi2j2,匹配 A i 2 → B j 2 A_{i_2}\rightarrow B_{j_2} Ai2→Bj2,清楚 X i 2 j 2 X_{i_{2}j_{2}} Xi2j2所在行列。重复2-3步骤。
- 上述操作重复至全部
n
b
n_{b}
nb个真值框已经找到配对锚框,在剩余的
n
a
−
n
b
n_{a}-n_{b}
na−nb个锚框中遍历,取每个剩余锚框
B
i
B_i
Bi所在
X
X
X行,找到最大IoU的列
B
j
B_j
Bj,若该IoU大于设定阈值,则匹配
A
i
→
B
j
A_{i}\rightarrow B_{j}
Ai→Bj
6.全部配对完毕后,计算锚框的类别和偏移量。
类别:对于锚框 A i A_{i} Ai: A i → B j A_{i}\rightarrow B_{j} Ai→Bj,类别为 B j B_{j} Bj。没有被分配的锚框设置为背景类。所有目标类锚框为正类锚框,所有背景锚框被称为负类锚框。
偏移量:锚框 A i A_{i} Ai和gt框 B j B_{j} Bj的中心点分别为 ( x a , y a ) (x_a,y_a) (xa,ya)和 ( x b , y b ) (x_b,y_b) (xb,yb),高宽为 h a ∗ w a h_{a}*w_{a} ha∗wa和 h b ∗ w b h_{b}*w_{b} hb∗wb,锚框 A i A_{i} Ai的偏移量可以标注为:
其中,前两项为两个中心点之间的偏移量(按锚框尺寸归一化),后两项为两个尺寸的偏移量。
7.在实际操作中,我们也常常使用mask将负类过滤掉。
5. 特殊操作:非极大值抑制(non-maximum suppression,NMS)
对于这样一种问题:同一个目标上可能会输出较多相似的预测边界框。
移除相似的预测边界框的操作,称为非极大值抑制(non-maximum suppression,NMS)。
该方法操作如下:
1)取所有匹配上
B
B
B类的候选锚框,按照置信度从大到小排列;
2)取置信度最高的候选锚框为基准,遍历其余所有锚框,计算基准锚框与其余锚框的IoU;
3)IoU大于设定阈值(超参数)的候选锚框,被认为是相似锚框,删除;
4)在剩余列表中,找最大置信度锚框作为基准锚框,重复2-3步骤,直至得到所需个数的锚框。