admin管理员组

文章数量:1630195

文章目录

  • 一、Basic Idea of Auto Encoder
    • 1.1 Auto Encoder 结构
    • 1.2 Auto Encoder 降维
    • 1.3 Why Auto Encoder
    • 1.4 De-Noising Auto Encoder
  • 二、Feature Disentanglement 特征解耦
    • 2.1 特征解耦介绍
    • 2.2 特征解耦的应用
      • 2.2.1 Voice Conversion 语者转换
  • 三、Discrete Representation 离散表示
  • 四、Generator 生成器
  • 五、Compression 压缩
  • 六、Anomaly Detection 异常检测
    • 6.1 Anomaly Detection 介绍
    • 6.2 Anomaly Detection 例子
      • 6.2.1 辛普森家庭人物分类
      • 6.2.2 异常检测系统的评估
      • 6.2.3 Without Label 例子
  • 七、自编码器PyTorch实战
    • 7.1 MNIST手写数据集的Auto Encoder


一、Basic Idea of Auto Encoder

1.1 Auto Encoder 结构

左边是编码器,将高维度图像数据转化为低维度向量。
右边是解码器,将低维度向量,解码还原为高维度图片。
这就是自编码器的大概结构

1.2 Auto Encoder 降维

根据编码器的特性,我们可以用它对数据进行降维。(类似的降维技术有PCA主成分分析、t-SNE)

1.3 Why Auto Encoder

假设一个场景:图中的老头和年轻人正在切磋,老头的武器是他的胡须,他的胡须很长,通过甩动他的胡须可以攻击很大范围内的敌人;年轻人的武器是一把剑,理论上老头更占优势,但是年轻人凭借智慧最终战胜了老头(故事改编于神雕侠侣)

年轻人的秘诀是:老头的胡须很长,但胡须是由头操控的,胡须的攻击范围很大,但是头的移动范围很小,所以可以直接攻击其头部,导致其需要不断躲闪,无法专心控制胡须,从而轻易将其击败

从这个故事中,我们可以猜测。虽然一张图片上的像素点很多,但是其真正有用的信息是有限的,我们相信图片是可以缩小为低维数据而只损失很小信息的。Auto Encoder的创建者应该也是秉持了这个信念。

1.4 De-Noising Auto Encoder

在原图的基础上加入一些噪声,将加了噪声的图片作为Auto Encoder的输入进行训练,Loss定义为Decoder输出和原图的相差度
此时,Auto Encoder模型不止要学会怎么降维和还原,还要学会怎么把噪声去掉。

二、Feature Disentanglement 特征解耦

2.1 特征解耦介绍

在自编码器中,如果我们输入一张图片,它会将图片降维成一个低维向量,而这个低维向量里就包含了图片的重要信息(可能是图片的颜色、图片的类型等等)

Feature Disentanglement 特征解耦的目的是:从Encoder压缩得到的低维向量中,得到哪些数据对应什么特征信息。例如,100维的向量,我们通过特征解耦得出前50维代表图片的颜色,后50维代表图片的类型。

2.2 特征解耦的应用

2.2.1 Voice Conversion 语者转换

柯南的变身器就是用到了语者转换技术

在传统监督学习的思想中,如果我们需要将A的声音转化为B的声音,我们需要让A念一个句子,然后B也跟着念同样的句子(作为Label),构成一个带标签的训练数据。

但是,这样显然是很麻烦的,在实际中,我们不可能让A和B一直念同样的句子来构造完备的数据集。


而使用Auto Encoder的技术就可以解决这个问题,只要我们有A和B的声音,不管A和B念了什么,我们都可以进行训练。

我们可以将A和B分别传入Encoder,得到两个降维的特征向量,然后通过特征解耦技术,我们可以直到两个向量中哪些维度代表声音的内容,哪些维度代表声音的音色。

然后我们只需要将两个特征向量的代表声音音色的部分互换,就可以达到变音的效果。

三、Discrete Representation 离散表示

将离散的特征向量转化为Binary二值的特征向量,可能会有利于我们对特征向量的解释。
将离散的特征向量转化为One-Hot编码类型的特征向量,有希望实现没有标签的无监督学习,类似聚类(中间的One-Hot特征向量就是学习出来的标签),自动实现无标签分类,即聚类

假设我们有5个已知向量(相当于我们的字典),我们可以把降维后的特征向量对字典里的5个向量做相似度计算,取出字典中和降维后的特征向量最相似的向量作为Decoder的输入,然后去训练,这样,我们就可以自定义字典集合,实现离散的固定种类数的特征向量表示了。

中间的特征向量一定是向量吗?不可以是文字吗?

更疯狂的想法是,将文章作为输入,得到降维后的数据还是文字,且通过降维后的文字可以还原文章的内容,那么说明降维后的文字大概率是文章中的精华。那我们是不是可以将其当作文章的摘要?(这样就可以制作自动提取文章摘要的模型了)


不过,实际实现起来会发现行不通,你会发现Encoder和Deocoder在训练中会发明出他们之间才能看懂的密文,根本不是人能看懂的。

解决的方法是,将密文传入另外一个模型进行训练,该模型的输入标签是人为写的摘要,损失定义为人写的摘要和密文之间的相差程度,这样就可以在训练过程中,让密文尽可能变成人能看得懂的文字。

四、Generator 生成器

显而易见,我们只需要给Decoder固定格式的一个向量,它就能够还原一张图片。即作为图片生成器(输入关键词,自动生成图片)

五、Compression 压缩

通过Encoder的降维功能可以实现数据的压缩(但这是一种失真的压缩技术,会丢失一些信息)

六、Anomaly Detection 异常检测

6.1 Anomaly Detection 介绍

给定一个数据集,再给定一个新数据,Anomaly Detector可以检测出新数据是否与数据集中的数据比较相似,如果不是,则判定其为异常数据

如下所示:

  1. 如果数据集中都是雷丘,给定皮卡丘就会判定为异常数据
  2. 如果数据集中都是皮卡丘,给定雷丘就会判定为异常数据

    其他应用:

    怎么判断异常呢?

可以将正常的数据集传入AutoEncoder进行训练,然后将新数据(要判断的数据)传入,通过新数据和还原数据的差别程度(Loss)来判断,如果Loss很大,说明AutoEncoder大概率没有见过这个新数据,即可以判断新数据为异常数据。

6.2 Anomaly Detection 例子

6.2.1 辛普森家庭人物分类


我们希望训练出来的模型,在接受一个图片后不止输出其所属类别,而且还输出它对自己决策的“信心程度”,这样就可以通过信心程度的大小,判断输入图片是否为异常图片(信心程度小于设定阈值,就判定为异常数据)

如下图所示,第一张图的最大信心程度是0.97,说明不是异常数据。
第二张图的信心程度都比较平均,最大也只有0.26,说明很可能为异常数据

6.2.2 异常检测系统的评估

在传统二分类问题上,我们常常用正确率来衡量二分类模型的好坏,但在异常检测任务中,使用正确率往往是不靠谱的,这是因为异常数据的数量往往比正常数据的数量少得多,这会导致即使模型“一视同仁”地将所有数据认定为正常数据,也可以得到很高的正确率。如下图所示,所有异常图片都被认为是正常的图片,但正确率依然大于95%,所以异常检测任务中,不能仅仅采用正确率来衡量异常检测系统的好坏。

可以使用AUC衡量异常检测系统的好坏

AUC(Area Under Curve)被定义为ROC曲线下与坐标轴围成的面积,显然这个面积的数值不会大于1。又由于ROC曲线一般都处于y=x这条直线的上方,所以AUC的取值范围在0.5和1之间。AUC越接近1.0,检测方法真实性越高;等于0.5时,则真实性最低,无应用价值。

6.2.3 Without Label 例子

下图是一个可以数万人同时玩的游戏,可以看到图的右边有很多不同的玩家在按不同的按钮。

对此,我们相信大部分玩家都是想让游戏通关的,而少部分玩家可能由于是小白或由于其不想让大家通关所以其按的按钮对通过没有帮助,甚至阻挠通关。

我们的目标是检测出这一些阻挠通关的玩家(侦测出异常玩家)。

七、自编码器PyTorch实战

7.1 MNIST手写数据集的Auto Encoder

import torch
from torch.utils.data import DataLoader
from torchvision import transforms, datasets
from torch import nn, optim


class AutoEncoder(nn.Module):
    def __init__(self):
        super(AutoEncoder, self).__init__()

        # encoder [b,784] => [b,64]
        self.encoder = nn.Sequential(
            nn.Linear(784, 256),
            nn.ReLU(),
            nn.Linear(256, 128),
            nn.ReLU(),
            nn.Linear(128, 64),
            nn.ReLU(),
        )

        # decoder [b,64] => [b,784]
        self.decoder = nn.Sequential(
            nn.Linear(64, 128),
            nn.ReLU(),
            nn.Linear(128, 256),
            nn.ReLU(),
            nn.Linear(256, 784),
            nn.Sigmoid(),
        )

    def forward(self, x):
        batch_size = x.size(0)
        # 展平
        x = x.view(batch_size, 784)
        # encoder
        x = self.encoder(x)
        # decoder
        x = self.decoder(x)
        # reshape
        x = x.view(batch_size, 1, 28, 28)
        # 返回
        return x


def main():
    # 构建训练集
    mnist_train = datasets.MNIST('mnist', train=True, transform=transforms.Compose([transforms.ToTensor()]),
                                 download=True)
    mnist_train = DataLoader(mnist_train, batch_size=64, shuffle=True)

    # 构建测试集
    mnist_test = datasets.MNIST('mnist', train=False, transform=transforms.Compose([transforms.ToTensor()]),
                                download=True)
    mnist_test = DataLoader(mnist_test, batch_size=64, shuffle=False)

    print(len(mnist_train))

    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

    model = AutoEncoder().to(device)
    optimizer = optim.Adam(model.parameters(), lr=0.001)
    criterion = nn.MSELoss()

    # 迭代训练
    for epoch in range(1001):
        for batch_idx, (x, _) in enumerate(mnist_train):
            # [b,1,28,28]
            x = x.to(device)
            # forward
            x_hat = model(x)
            loss = criterion(x_hat, x)
            # 标准三步
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
        if epoch % 20 == 0:
            print("loss:", loss.item())


if __name__ == '__main__':
    main()

输出:

938
loss: 0.021354397758841515
loss: 0.007018874865025282
loss: 0.00483087869361043
loss: 0.005021111574023962
loss: 0.0037358475383371115
loss: 0.0038538670632988214
loss: 0.003534478833898902
loss: 0.003522576065734029
loss: 0.003523445688188076
loss: 0.003590955398976803
迭代太慢了,我就没有迭代完了,大家可以跑着试一下,我就不跑了。。。

本文标签: 深度编码器实战课程笔记