AutoEncoder: 稀疏自动编码器 Sparse_AutoEncoder
本文为系列文章AutoEncoder第三篇.AutoEncoder对几种主要的自动编码器进行介绍,并使用PyTorch进行实践,相关完整代码将同步到Github
本系列主要为记录自身学习历程,并分享给有需要的人.水平所限,错误难免,欢迎批评指正,不吝赐教.
本文及本系列将不定期更新.
AutoEncoder:
- 自动编码器 AE
- 堆叠自动编码器 Stacked AutoEncoder
- 稀疏自动编码器 Sparse AutoEncoder
- 降噪自动编码器 Denoising AutoEncoder
- 变分自动编码器 Variational AutoEncoder
- CAE
本文主要包含一下内容:
稀疏自动编码器的基本概念,原理,并使用MNIST数据集进行实现
写在前面:推荐一篇斯坦福Andrew Ng的CS294A Lecture notes, 对神经网络,SAE以及KL等都有很好的讲解,本文很多内容来源于此.
1. 基本概念
稀疏自动编码器(SAE)其实就是在普通autoencoder的基础上增加了稀疏的约束,使得神经网络在隐藏层神经元较多的情况下依然能够提取样本的特征和结构.
且该稀疏性penalty是用来惩罚隐藏层激活输出值的,而不是输出层的输出.
关于稀疏的解释:
当神经元的的输出接近激活函数上限时(例如对于Sigmoid为1)称该神经元状态为激活,反之当神经元的输出接近激活函数的下限时称该神经元的状态为抑制,那么当某个约束或规则使得神经网络中大部分的神经元的状态为抑制时,称该约束为`稀疏性限制`.2. 原理
惩罚项其实有很多种选择, 常见的L1/L2正则化也是其中之一.
本处我们将使用KL散度进行隐藏层激活值的惩罚, 以使得隐藏层神经元输出的平均值接近0(本文未加说明则以Sigmoid函数为例),从而是的大多数神经元处于抑制状态.
关于KL散度的直观理解可以参考这里, 以及这里
增加一小节内容,对KL散度进行简单理解:
KL散度即 相对熵=交叉熵 - 信息熵
交叉熵使我们老朋友了,关于相对熵/交叉熵/信息熵的理解可以参考这里
对于二项分布,可以得到KL散度的公式为:
增加了KL散度后的损失函数为:
其中KL散度项为:
上式中,
对于第i个神经元,如果我们的batch_size=N,那么第i个神经元将会经过N次激活,输出N个激活值,
其中
为KL散度的*权重*,通过
注意:这里所有的稀疏限制都是加在<隐藏层>上的, 因此需要获得隐藏层的输出来计算KL
由此,我们可以结合PyTorch实现KL散度的计算:
# 计算p和q之间的KL散度
# p为期望激活值扩充为hidden_size的tensor
# q为隐藏层结点激活后的输出值
def KL_divergence(p, q):
"""
Calculate the KL-divergence of (p,q)
:param p:
:param q:
:return:
"""
q = torch.nn.functional.softmax(q, dim=0) # 首先要用softmax对隐藏层结点输出进行归一化处理
q = torch.sum(q, dim=0)/batch_size # dim:缩减的维度,q的第一维是batch维,即大小为batch_size大小,此处是将第j个神经元在batch_size个输入下所有的输出取平均
s1 = torch.sum(p*torch.log(p/q))
s2 = torch.sum((1-p)*torch.log((1-p)/(1-q)))
return s1+s2训练逻辑:
for epoch in range(num_epochs):
for batch_index, (train_data, train_label) in enumerate(train_loader):
if torch.cuda.is_available():
train_data = train_data.cuda()
train_label = train_label.cuda()
input_data = train_data.view(train_data.size(0), -1)
encoder_out, decoder_out = autoEncoder(input_data)
loss = Loss(decoder_out, input_data)
# 计算并增加KL散度到loss
_kl = KL_devergence(tho_tensor, encoder_out)
loss += _beta * _kl
Optimizer.zero_grad()
loss.backward()
Optimizer.step()于是我们又可以快乐的训练了.
完整代码请参考Github