2016
(虽然算是比较老的论文了,但是本来一方面我就只是拿来用到一个小环节中,这这里纠结太久了,另一方面也是在paperwithcode上看了一圈的代码,到这终于能运行出来东西了😭)
摘要
本文提出了“对抗性自编码器”(AAE),这是一种概率自编码器,使用生成对抗性网络(GAN),通过将自动编码器的隐藏编码向量的聚合后验与任意先验分布相匹配来进行变分推理(变分?那和变分自编码器VAE有啥关系吗?整的我还是分不清AE和VAE的区别)
。与先验聚合后验匹配确保从先验空间的任何部分生成会产生有意义的样本。因此,对抗性自编码器的解码器学习了一个深度生成模型,它映射了在数据分布之前所施加的模型。我们展示了如何将对抗性自动编码器在半监督分类、图像分离风格和内容、无监督聚类(你最好是真的无监督聚类哦,刚看到一堆半监督咱心都凉了凎)
、降维和数据可视化等应用中使用。
在MNIST、街景屋数和多伦多人脸数据集上进行了实验,结果表明,对抗性自动编码器在生成建模和半监督分类任务中取得了具有竞争力的结果。
6 无监督聚类与对抗性的自编码器
体系结构与图8相似,不同的是删除了半监督分类阶段,因此不再在任何标记的小批量上训练网络。另一个区别是,推理网络q(y|x)预测了一个onehot向量,其维数是希望将数据聚类成的类别的数量(那就是人为规定k值呗)
。图9显示了当集群数量为16个时,AAE在MNIST上的无监督聚类性能。每一行对应一个集群。每一行中的第一幅图像显示了集群头,它们是通过将样式变量固定为零并将标签变量设置为16个单热向量中的一个而生成的数字。每一行的其余图像都是随机测试图像,它们根据q(y|x)被分类为相应的类别。
+-----------------+-------+
| Parameter | Value |
+=================+=======+
| B1 | 0.500 |adam的第一次梯度冲量衰减率
+-----------------+-------+
| B2 | 0.999 |
+-----------------+-------+
| Batch size | 64 |
+-----------------+-------+
| Channels | 1 |
+-----------------+-------+
| Img size | 32 |
+-----------------+-------+
| Latent dim | 10 |编码维度,也就是认为定的簇数k
+-----------------+-------+
| Lr | 0.000 |
+-----------------+-------+
| N cpu | 8 |
+-----------------+-------+
| N epochs | 200 |
+-----------------+-------+
| Sample interval | 400 |图像采样间隔
+-----------------+-------+
其实这代码里dataloader调用了现成的mnist数据结构,不过在每轮训练时通过for i, (imgs, _) in enumerate(dataloader)跳开标签信息
从而有[64, 1, 32, 32]的输入
定义对抗标签
valid = Variable(Tensor(imgs.shape[0], 1).fill_(1.0), requires_grad=False)
#[64, 1] 全1
fake = Variable(Tensor(imgs.shape[0], 1).fill_(0.0), requires_grad=False)
#[64, 1] 全0
Encoder(
#先把img view成[64, 1024]的img_flat
(model): Sequential(
(0): Linear(in_features=1024, out_features=512, bias=True)
(1): LeakyReLU(negative_slope=0.2, inplace=True)
(2): Linear(in_features=512, out_features=512, bias=True)
(3): BatchNorm1d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(4): LeakyReLU(negative_slope=0.2, inplace=True)
)
#得到[64,512]的x
(mu): Linear(in_features=512, out_features=10, bias=True)
(logvar): Linear(in_features=512, out_features=10, bias=True)
#分别得到[64,10]的mu和logvar
#调用reparameterization计算z
)
reparameterization:
先算
s
t
d
=
e
l
o
g
v
a
r
2
std=e^{\frac{logvar}{2}}
std=e2logvar(表示标准差?mu表示均值期望?)
在标正分布里随机造一个[64,10]的sampled_z
然后反归一化出z
Decoder(
(model): Sequential(
(0): Linear(in_features=10, out_features=512, bias=True)
(1): LeakyReLU(negative_slope=0.2, inplace=True)
(2): Linear(in_features=512, out_features=512, bias=True)
(3): BatchNorm1d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(4): LeakyReLU(negative_slope=0.2, inplace=True)
(5): Linear(in_features=512, out_features=1024, bias=True)
(6): Tanh()
)
#得到[64, 1024]
#再view成[64, 1, 32, 32]
)
有重构损失
g
l
o
s
s
=
0.001
×
B
C
E
L
o
s
s
(
d
i
s
c
r
i
m
i
n
a
t
o
r
(
e
n
c
o
d
e
d
)
,
v
a
l
i
d
)
+
0.999
×
L
1
L
o
s
s
(
d
e
c
o
d
e
d
,
r
e
a
l
i
m
g
s
)
g_loss = 0.001×BCELoss(discriminator(encoded), valid) + 0.999×L1Loss(decoded, real_imgs)
gloss=0.001×BCELoss(discriminator(encoded),valid)+0.999×L1Loss(decoded,realimgs)
Discriminator(
(model): Sequential(
(0): Linear(in_features=10, out_features=512, bias=True)
(1): LeakyReLU(negative_slope=0.2, inplace=True)
(2): Linear(in_features=512, out_features=256, bias=True)
(3): LeakyReLU(negative_slope=0.2, inplace=True)
(4): Linear(in_features=256, out_features=1, bias=True)
(5): Sigmoid()
)
#得到[64,1]
)
构造判别标签
在标正分布里随机造一个[64,10]的z作为标签
real_loss = adversarial_loss(discriminator(z), valid)
fake_loss = adversarial_loss(discriminator(encoded_imgs.detach()), fake)
d_loss = 0.5 * (real_loss + fake_loss)
Adam (
Parameter Group 0
amsgrad: False
betas: (0.5, 0.999)
eps: 1e-08
lr: 0.0002
weight_decay: 0
)
(不太懂GAN,没明白这样怎么聚了类,但没有用到类别标签应该是可以用的吧)