[文献阅读] DCEC - Deep Clustering with Convolutional Autoencoders
**文献信息:**Deep Clustering with Convolutional Autoencoders ICONIP17-DCEC.pdf
发表于ICONIP2017 。这篇文章的方法和DEPICT很像,而且两者都发表于2017年,虽然DEPICT的正确率更高,但是DCEC重点在证明了CAE在图像聚类任务中优于全连接SAE。在研究历史有一定地位并且引用数也很高,因此还是值得一读。
摘要
针对于DEC不能很好地保留学习到的特征空间中数据生成分布的局部结构的问题。
为了解决这个问题,该论文基于DEC,使用卷积自编码器结构CAE代替了SAE。并且保留了解码器,同时最小化重构损失和聚类损失,以端到端方式学习嵌入式特征。值得一提的是,聚类损失乘上了一个系数(0<γ<1),更好的阻止了DEC严重的特征空间被聚类损失扭曲从而使正确率下降的问题。
在基准数据集上的实验经验验证了卷积自编码器在特征学习方面的能力和局部结构保存的有效性,图像数据上正确率比DEC更高。
Abstract
This week’s report examines DCEC (Deep Clustering with Convolutional Autoencoders), a clustering model presented at ICONIP 2017. DCEC builds on the DEC framework but replaces the fully connected autoencoder (SAE) with a convolutional autoencoder (CAE) to better capture local structures in image data. The model combines reconstruction and clustering losses in an end-to-end training process, using a joint loss function to prevent distortion of the feature space caused by clustering loss alone. The report details the CAE architecture, the joint loss formulation, and the training procedure, including pretraining and iterative updates of the target distribution. Experimental results on benchmark datasets demonstrate DCEC’s effectiveness in image clustering, achieving higher accuracy than DEC. The summary highlights DCEC’s contributions to the field of deep clustering and suggests potential improvements to the loss function for further enhancing clustering performance.
DCEC
CAE
DCEC使用的自编码器架构如图,提出了一种新的卷积自动编码器(CAE),不需要繁琐的分层预训练,如图1所示。
首先,将一些卷积层叠加在输入图像上,以提取分层特征。然后将最后一个卷积层中的所有单元平铺形成一个向量,接下来是一个只有10个单元的完全连接层,称为嵌入层。这样,输入的2D图像就被转换成10维特征空间。为了以无监督的方式训练它,我们使用一个全连接层和一些卷积转置层将嵌入的特征转换回原始图像。
DCEC在卷积过程并没有使用maxpooling等池化操作,而是用stride=2的步长来代替这一点。
另一个因素是我们在编码器中使用了带有stride的卷积层,而不是卷积层后面跟着池化层,在解码器中使用了带有stride的卷积转置层。因为带stride的卷积(转置)层允许网络从数据中学习空间子采样(上采样),从而获得更高的变换能力。
通过最小化重构误差来更新编码器 h = F ω ( x ) h =F_ω(x) h=Fω(x)和解码器 x 0 = G ω 0 ( h ) x^0=G_{ω0}(h) x0=Gω0(h)的参数:
潜在维度h低于输入数据x。学习这种不完全表示迫使自动编码器捕捉数据的最显著特征。因此,我们强制嵌入空间的维度等于数据集簇的数量。这样,即使没有任何像Dropout或Batch Normalization这样的正则化,也可以以端到端方式直接训练网络。学习到的紧凑表示被证明对聚类任务是有效的。
虽然这段解释比较奇怪,并没解释为什么不使用Dropout或Batch Normalization。不过DEC也没有这样做,整篇文章并没有过多的改动DEC原有的结构。
联合损失
通过联合损失使得DCEC能实现端到端训练,这也是与DEC不同的一点。
因为仅使用面向聚类的损失可能会扭曲DEC中的嵌入特征空间。为此,我们将自编码器的重构损失加入到目标中,并与聚类损失同步优化。自编码器将保留数据生成分布的局部结构,避免特征空间的破坏。
聚类层将输入图像 x i x_i xi的每个嵌入点zi映射成一个软标签。然后将聚类损失 L c L_c Lc定义为软标签分布与预定义目标分布之间的Kullback-Leibler散度(KL散度)。利用CAE学习嵌入特征,聚类损失引导嵌入特征容易形成聚类。
DCEC的目标函数是
其中Lr和Lc分别是重构损失和聚类损失,γ> 0是控制嵌入空间扭曲程度的系数。
当γ= 1且Lr≡0时,化简为DEC聚类阶段的的目标。
当γ= 0时,可以控制模型进行预训练。
聚类层和损失直接从DEC借用。
聚类层将聚类中心
{
μ
j
}
1
K
\{μ_j\}^K_1
{μj}1K作为可训练的权重,通过t-分布将每个嵌入点
z
i
z_i
zi映射到软标签
q
i
q_i
qi
聚类损失定义为
其中P为目标分布,定义为
在联合训练阶段文中将γ设置为0.1。
目标分布的更新
目标分布P是从真实分布Q中得到的,但是真实分布Q每个batch都在更新。DCEC这点也与DEC不同。
更新目标分布。目标分布P作为ground truth软标签,但也依赖于预测的软标签。因此,为了避免不稳定,不应该在每次迭代时只使用一批数据来更新P。在实践中,我们在每T次迭代中使用所有嵌入点来更新目标分布。
训练过程
- 预训练不含聚类loss的CAE网络,每个输入会得到一个10D的embedding z i z_i zi。这一步设置γ=0。
- 对所有 z i z_i zi应用k-means得到10个初始化聚类中心 μ j μ_j μj。,然后就可以计算出用作聚类损失的的真实分布 q i q_i qi,然后使用 q i q_i qi算出目标分布 p i p_i pi。
- 联合训练,设置γ=0.1,开始训练重构损失和聚类损失,网络权重可以通过BP更新,聚类中心也可以通过 ∂ L c ∂ μ j = ∂ L c ∂ q ∂ q ∂ μ \frac{\partial L_c}{\partial \mu_j} = \frac{\partial L_c}{\partial q} \frac{\partial q}{\partial \mu} ∂μj∂Lc=∂q∂Lc∂μ∂q更新。
- 如果目标分布的两次连续更新之间的标签分配变化小于阈值δ,则训练过程终止。
结果
IDEC的聚类性能优于DEC, DEC-conv和DCEC的聚类性能也优于DEC。虽然DCEC并没有以更高的准确率作为目标,也没有花较多的功夫在参数设置上,但是依旧证明了其在图像聚类上的有效性。
实验
原项目使用Keras,这里我使用DEC的pytorch一个项目修改而来 https://github.com/xiaopeng-liao/DEC_pytorch
主要修改了网络结构和联合聚类训练过程时的损失函数。
网络结构:
class DEC_Conv_AE(nn.Module):
def __init__(self, num_classes, num_features):
super(DEC_Conv_AE, self).__init__()
self.num_features = num_features
# Encoder
self.encoder = nn.Sequential(
nn.Conv2d(1, 16, kernel_size=3, stride=1, padding=1), # 16x28x28
nn.ReLU(),
nn.MaxPool2d(2, stride=2), # 16x14x14
nn.Conv2d(16, 32, 3, stride=1, padding=1), # 32x14x14
nn.ReLU(),
nn.MaxPool2d(2, stride=2), # 32x7x7
nn.Conv2d(32, 64, 3, stride=1, padding=1), # 64x7x7
nn.ReLU(),
nn.Conv2d(64, num_features, 3, stride=1, padding=1), # num_featuresx7x7
nn.AdaptiveAvgPool2d((1,1)), # num_featuresx1x1
nn.Flatten()
)
# Decoder
self.decoder = nn.Sequential(
nn.Linear(num_features, 64*7*7),
nn.Unflatten(1, (64,7,7)), # 64x7x7
nn.ConvTranspose2d(64, 32, 3, stride=2, padding=1, output_padding=1), # 32x14x14
nn.ReLU(),
nn.ConvTranspose2d(32, 16, 3, stride=2, padding=1, output_padding=1), # 16x28x28
nn.ReLU(),
nn.ConvTranspose2d(16, 1, 3, stride=1, padding=1), # 1x28x28
nn.Sigmoid()
)
self.dropout = nn.Dropout(p=0.1)
self.alpha = 1.0
self.clusterCenter = nn.Parameter(torch.zeros(num_classes, num_features))
self.pretrainMode = True
# 初始化權重
for m in self.modules():
if isinstance(m, (nn.Conv2d, nn.ConvTranspose2d, nn.Linear)):
nn.init.xavier_uniform_(m.weight)
def setPretrain(self, mode):
self.pretrainMode = mode
def updateClusterCenter(self, cc):
self.clusterCenter.data = torch.from_numpy(cc).cuda()
def getTDistribution(self, x, clusterCenter):
xe = torch.unsqueeze(x, 1) - clusterCenter.unsqueeze(0)
q = 1.0 / (1.0 + (torch.sum(torch.mul(xe, xe), dim=2) / self.alpha))
q = q ** ((self.alpha + 1.0) / 2.0)
q = (q.t() / torch.sum(q, dim=1)).t()
return q
def forward(self, x):
# 輸入形狀保持 (batch, 1, 28, 28)
x = self.dropout(x)
# 編碼器
x_ae = self.encoder(x) # 輸出形狀 (batch, num_features)
if not self.pretrainMode:
# 計算聚類分佈
q = self.getTDistribution(x_ae, self.clusterCenter)
# 解碼器
x_de = self.decoder(x_ae) # 輸出形狀 (batch, 1, 28, 28)
if self.pretrainMode:
return x_ae, x_de
else:
return x_ae, q, x_de
联合训练时的损失函数
model.train()
#now we start training with acquired cluster center
feature_pred, q, x_de = model(x)
#get target distribution
p = self.target_distribution(q)
#print('q',q,'p',p)
# loss = self.kld(q,p).mean() # KLd
loss1 = F.mse_loss(x_de,x,reduction='mean')
loss2 = self.kld(q,p).mean()
loss = loss1 + 0.1*loss2
loss.backward()
optimizer.step()
在MNIST上的结果
总结
DCEC在DEC的基础上使用卷积自编码器CAE代替了SAE,在预训练之后,联合重构损失和聚类损失,从而缓解了DEC严重的聚类空间扭曲特征空间的问题,并且不使用逐层预训练,实现了端到端训练。DCEC证明了CAE在图像聚类任务中优于全连接SAE,并且补齐了自编码器聚类研究的历史。未来可以对损失函数进一步优化,就像DEPICT做的那样,以获取更高的正确率。