草庐IT

Auto-encoder(自编码器)的原理及最新的技术应用(李宏毅视频课整理和总结)

Y_蒋林志 2023-06-24 原文

文章目录


0 前言

本节学习的是Auto-encoder,这是一种无监督的学习算法,主要用于数据的降维或者特征的抽取。自编码器是一种特殊的神经网络架构,其的输入和输出是架构是相同的,先获取输入数据的低维度表达,然后在神经网络的后段重构回高维的数据表达,在此基础还有诸多应用。本文由整理李宏毅老师视频课笔记和个人理解所得,详细讲述了Auto-encoder的原理及最新的技术。我会及时回复评论区的问题,如果觉得本文有帮助欢迎点赞 😃。

1 Auto-encoder

Auto-encoder是一个基本的生成模型,更重要的是它提供了一种encoder-decoder的框架思想,广泛的应用在了许多模型架构中。简单来说,Auto-encoder可以看作是如下的结构:

  1. Encoder(编码器):它可以把原先的图像压缩成更低维度的向量。
  2. Decoder(解码器):它可以把压缩后的向量还原成图像,通常它们使用的都是神经网络。

Encoder接收一张图像(或是其他类型的数据)(hidden layer)输出一个低维的vector,它也可称为Embedding或者code,然后将vector输入到Decoder中就可以得到重建后的图像,希望它和输入图像越接近越好,即最小化重建误差(reconstruction error)。Auto-encoder本质上就是一个自我压缩和解压的过程。具体如下图:

第一个流程图:假设输入是一张图片,有784个像素,输入一种network的Encoder(编码器)后,输出一组远小于784的code vector,认为这是一种紧凑的表示。
第二个流程图:输入是一组code vector,经过network的Decoder(解码器)之后可以输出原始图片。

两者单独来看都是无监督学习,不能独立训练,因为不知道输出是什么。所以将两者结合起来训练。

1.1 PCA

先回顾PCA的概念。PCA输入是 x x x,乘上W的权值矩阵,可以得到component c c c,然后再乘上 W T W^T WT ,可以得到 x ^ \hat{x} x^。目标函数即使得 x x x x ^ \hat{x} x^的差值最小:Minimize ( x − x ^ ) 2 (x-\hat{x})^{2} (xx^)2

将PCA类比为network的话,就可以分为input layer,hidden layer和output layer,hidden layer又称Bottleneck(瓶颈) layer。因为hidden layer的通常维数比output和input要小很多,所以整体看来hidden layer形如瓶颈一般。 Hidden layer 的输出就可以等同于Auto-encoder的code vector。

1.2 Deep Auto-encoder

但是PCA只有一个hidden layer,如果我们将hidden layer增加,就变成了Deep Auto-encoder。目标函数也是:Minimize ( x − x ^ ) 2 (x-\hat{x})^{2} (xx^)2,训练方法和训练一般的神经网络一样。

将中间最窄的hidden layer作为bottleneck layer,其输出就是code。bottleneck layer之前的部分认为是encoder,之后的部分认为是decoder。

可认为 W 1 W_1 W1 W 1 T W_1^T W1T互为转置的关系,参数的值是相同的,但是实际上这种对称是没有必要的。直接训练就可以了。

对比使用PCA和Deep Auto-encoder的结果,可以发现后者的结果要好很多:

为了可视化,将bottleneck layer的输出降到2维后拿出来显示,不同颜色代表不同的数字。PCA就比较混杂,而Deep Auto-encoder分得比较开。

2 Some Applications

2.1 Text Retrieval(文字检索)

一般的文字搜索的方法是Vector Space Model,把每一篇文章表示为空间中的一个点,将输入的查询词汇也变成空间中的一个点,计算输出的查询词汇和文章在空间的距离,比如内积和cosine similarity,用距离来retrieve。

这个模型的核心是将一个document表示成一个vector,假设我们有一个 bag of word,假设所有的词汇有十万个,那么这个document的维度就是十万维。涉及到某个词汇,对应的维度就置为1。但是这样的模型无法知道具体的语义,对它来说每一个词汇都是独立的,忽略了相关性。

可以使用Auto-encoder来表示这种相关性。

降到2维后做可视化,右上的每个点表示一个document,可以发现同一类的document都分散在一起。如果用刚刚的LSA模型,如右下,就得不到类似的结果。

2.2 Similar Image Search(相似图片搜索)

可以用在图片的搜索上面,用图片来寻找类似的图片。如果使用欧式距离在像素密度空间去搜索的话,结果如下,效果不是很好。

Auto-encoder的方法就是将图片变成一个code,在code空间去做搜索。变成code之后再通过一个decoder,reconstruct回来可以得到下图的结果:

如果在code上做搜索的话,可以得到以下结果,至少都是人脸。

2.3 Pre-training(预训练)

在训练DNN的时候希望能选择好的初始值,这类方法称为Pre-training。可以用Auto-encoder来做Pre-training,假设目标是一个如下的network:

开始使用Auto-encoder对第一个hidden layer进行训练:

但是有个问题,就是这里的hidden layer是1000维,code比两边都大,可能什么都learn不到,直接把参数复制一遍就可以一模一样了。所以要加一个很强的regularization 来约束,比如使得这1000维是稀疏(sparse)的,某几个维度才有值,这样才能learn下去。

现在将学好的第一层的 W 1 W^1 W1固定下来,再学习第二层hidden layer:

同理得到其他的W:

已经得到很好的W了,最后使用BP(back propagation)算法fine-tune微调一下即可。不过现在训练的技术进步,Pre-training用的不多了,但是如果你unlabeled data很多,labeled data1很少,那么可以使用这个方法。

3 De-noising Auto-encoder(加噪的自编码器)

这是一种改进的Auto-encoder算法:训练的时候,在x输入前加入噪声。这样做的结果会使得学习的模型有更好的鲁棒性。

还有很多线性的降维法:

深度信念网络:

4 Auto-encoder for CNN

一般图像处理会使用CNN,如果将Auto-encoder的思想用在CNN上,那么encoder和decoder的卷积、池化和反卷积、池化将是一一对应的,如下图所示:

但是反卷积和反池化到底是什么呢?

4.1 Unpooling(反池化)

首先看反池化的部分。池化的意思原本是对特征进行提取,比如是在22的矩阵中选取一个作为特征,那么此时使用一个Max location的层来记录筛选特征的位置,在后面进行反池化(unpooling)的时候就依据Max location的位置reconstruction这些特征。原本1414的数据,经过unpooling之后就会变成28*28的数据。具体过程如下图所示:

上述只是一种方式,也有不管位置信息,直接将特征复制4份的做法。

4.2 Deconvolution(反卷积)

那对于反卷积来说,本质上就是做卷积。我们知道卷积的本质就是相乘相加,再移位后继续重复。用一维的卷积举例,输入5个点,卷积核为红色蓝色绿色的3个weight,最后相加得到3个值。而Deconvolution 的就是反过来,因为刚才是三个点乘上3个weight,相加后变成1个值,这里Deconvolution就需要从1个值乘3个weight变成3个值,其他点操作一样,产生在相同位置的值可以相加。最后初始的3个点就变成了5个点。这件事其实等价于padding后的convolution,在3个点周围补上4个零,仍然使用3个weight,最后得到的结果是一模一样的。不同之处在于,卷积核即weight的顺序是相反的:

4.3 Generate Image

Decoder还有一个特别的用法,因为已经训练好了整个模型,将Decoder抽出来,随机丢入一个二维的code,希望可以输出一张图。李宏毅老师将图片通过hidden layer 投影到2维上,然后再通过Decoder解成图片。2维是可以画图的,分布如下图所示,按照一定步长取红色方框中的code输入到decoder中,可以解出如下图片:

加上L1的正则项后,数据分布向0靠拢。重新选取数据得到以下结果,可以观察到这两个维度其实是有一定物理意义的,反映了图片的变化规律:

我们知道一般的Auto-encoder的目标函数是最小化重构误差(上文),但是除此之外还有别的方法。

5 More Than Minimizing Reconstruction Error(其他计算Error的方法)

5.1 Representative Embedding

先思考对Auto-encoder的目标来说什么样的embedding(嵌入,这里可以理解为低维表示)是好的呢?希望这个embedding可以代表原来的object。比如出现这个embedding就会联想到这个object。比如出现一个耳机,就会想到“三玖”(动漫人物):

这里涉及一点对抗生成网络的概念,即使用一个二分类的判别器对结果进行判别,如果觉得输入和输出是一对就是yes,反之就是no。通过使得判别器的损失最小来训练这个网络:

具体是首先通过训练判别器 L D ∗ = min ⁡ ϕ L D L_{D}^{*}=\min _{\phi} L_{D} LD=minϕLD 最小化损失函数 L D L_D LD,然后再训练encoder的 θ ∗ = arg ⁡ min ⁡ θ L D ∗ = arg ⁡ min ⁡ θ min ⁡ ϕ L D \begin{aligned} \theta^{*} &=\arg \min _{\theta} L_{D}^{*} =\arg \min _{\theta} \min _{\phi} L_{D} \end{aligned} θ=argθminLD=argθminϕminLD。训练最好的encoder和最好的discriminator:

可以将这个过程类比如下:

5.2 Sequential Data

也可以用于训练有顺序的数据:

6 More Interpretable Embedding(更易解释)

让encoder的output,即code,更容易被解释。

6.1 Feature Disentangle(特征解析)

比如一段声音信号里面除了语义本身,还包含了说话人的语音语调和环境噪声等信息。那么code vector中也含有以上所有信息,但是我们不知道各个维度的具体含义。所以期望Encoder能指出维度和各类信息的对应关系。

具体做法如下,假设只有说话人和内容两种信息,一种是将vector进行划分,另外一种是直接就训练两个encoder处理不同的信息:

可以将声音和语义分开:

然后将不同的声音和语义组合,得到完全不同的语音输出,可以做成一个变声器:

变声器的应用:

引入对抗训练的概念,也就是在训练中加入了Discriminator。目的是训练让前面的维度是语义,后面的维度代表男声还是女声。先训练一个语者的Classifier,可以分辨男声女声,但是encoder需要训练来骗过classifier,让这个classifier不能区分男声还是女声,正确率越低越好。这样就使得语者的信息从前部分的维度剔除了出来,只剩下内容的信息,语者信息都在了后部分的维度中:

或者直接修改encoder的架构可以区分语者和语义信息。假设有一种特殊的layer,instance normalization,可以抹除语者的信息:

6.2 Discrete Representation(离散的表示)

6.2.1 Base Method

我们之前讲的code都说是一个连续的vector,如果Encoder能够输出离散的向量,那么更有利于我们解读code的信息,比如可以用一些聚类的方法将向量分成一些簇。可以将code直接变成One-hot或者Binary的形式,取最大值或者设置阈值即可实现,这样看维度信息就可以直接完成分类了。但是老师认为binary更好,因为可表示的信息更大,而one-hot过于稀疏。

6.2.2 Vector Quantized Variational Auto-encoder (向量量化变异的自编码器)

设置一个codebook,里面是一排向量,这个也是需要学习的。Encoder输出原始向量vector,这是连续的。接下来用这个vector去计算和codebook里面的向量的相似度,相似度最高的vector3作为decoder的输入。这样可以固定向量的类别,相当于做了离散化。离散化之后信息 更易分类:

有一些trick来让你训练这些没办法微分的部分,一般是用强化学习直接做。

6.2.3 Sequence as Embedding

可以让embedding不再是向量而是句子。比如一个 seq2seq2seq auto-encoder 模型,使用这些sequence 作为code来还原文章。期待这些code可以就是原来那篇文章的摘要或者精简版本,但是实际上由于encoder和decoder的存在,这些code会参杂一些“暗号”,虽然是文字的组合,但没有实际含义。如果要让这些code有实际含义,将会用到GAN的概念,就是预先训练一个可以识别人类是否能读懂的句子的discriminator,然后去训练这些code,使得code具有可读性:

一些实验的例子:

有关Auto-encoder(自编码器)的原理及最新的技术应用(李宏毅视频课整理和总结)的更多相关文章

  1. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  2. ruby - 用逗号、双引号和编码解析 csv - 2

    我正在使用ruby​​1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\

  3. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  4. 动漫制作技巧如何制作动漫视频 - 2

    动漫制作技巧是很多新人想了解的问题,今天小编就来解答与大家分享一下动漫制作流程,为了帮助有兴趣的同学理解,大多数人会选择动漫培训机构,那么今天小编就带大家来看看动漫制作要掌握哪些技巧?一、动漫作品首先完成草图设计和原型制作。设计草图要有目的、有对象、有步骤、要形象、要简单、符合实际。设计图要一致性,以保证制作的顺利进行。二、原型制作是根据设计图纸和制作材料,可以是手绘也可以是3d软件创建。在此步骤中,要注意的问题是色彩和平面布局。三、动漫制作制作完成后,加工成型。完成不同的表现形式后,就要对设计稿进行加工处理,使加工的难易度降低,并得到一些基本准确的概念,以便于后续的大样、准确的尺寸制定。四、

  5. python ffmpeg 使用 pyav 转换 一组图像 到 视频 - 2

    2022/8/4更新支持加入水印水印必须包含透明图像,并且水印图像大小要等于原图像的大小pythonconvert_image_to_video.py-f30-mwatermark.pngim_dirout.mkv2022/6/21更新让命令行参数更加易用新的命令行使用方法pythonconvert_image_to_video.py-f30im_dirout.mkvFFMPEG命令行转换一组JPG图像到视频时,是将这组图像视为MJPG流。我需要转换一组PNG图像到视频,FFMPEG就不认了。pyav内置了ffmpeg库,不需要系统带有ffmpeg工具因此我使用ffmpeg的python包装p

  6. TimeSformer:抛弃CNN的Transformer视频理解框架 - 2

    Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图

  7. ruby-on-rails - 有没有一种工具可以在编码时自动保存对文件的增量更改? - 2

    我最喜欢的Google文档功能之一是它会在我工作时不断自动保存我的文档版本。这意味着即使我在进行关键更改之前忘记在某个点进行保存,也很有可能会自动创建一个保存点。至少,我可以将文档恢复到错误更改之前的状态,并从该点继续工作。对于在MacOS(或UNIX)上运行的Ruby编码器,是否有具有等效功能的工具?例如,一个工具会每隔几分钟自动将Gitcheckin我的本地存储库以获取我正在处理的文件。也许我有点偏执,但这点小保险可以让我在日常工作中安心。 最佳答案 虚拟机有些人可能讨厌我对此的回应,但我在编码时经常使用VIM,它具有自动保存功

  8. ruby - 未定义的方法 auto_upgrade!将 Sinatra/DataMapper 应用程序推送到 Heroku 时 - 2

    有谁知道在Heroku的Bamboo堆栈上启动并运行使用DataMapper的Sinatra应用程序所需的魔法咒语?Bamboo堆栈不包含任何预安装的系统gem,无论我尝试使用何种gem组合,我都会不断收到此错误:undefinedmethod`auto_upgrade!'forDataMapper:Module(NoMethodError)这是我的.gems文件中的内容:sinatrapgdatamapperdo_postgresdm-postgres-adapter这些是我将应用程序推送到Heroku时安装的依赖项:----->Herokureceivingpush----->Si

  9. c - Ruby - 源代码 - 编码风格 - 2

    查看Ruby代码,它具有以下proc_arity:staticVALUEproc_arity(VALUEself){intarity=rb_proc_arity(self);returnINT2FIX(arity);}更多的是C编码风格问题,但为什么staticVALUE在单独的一行而不是像这样的:staticVALUEproc_arity(VALUEself) 最佳答案 它来自UNIX世界,因为它有助于轻松grep函数的定义:$grep-n'^proc_arity'*.c或使用vim:/^proc_arity

  10. ruby - 如何以编程方式删除实例上的 "singleton information"以使其编码(marshal)? - 2

    我创建了一个由于“在运行时执行的单例元类定义”而无法编码的对象(这段代码的描述是否正确?)。这是通过以下代码执行的:#defineclassXthatmyusesingletonclassmetaprogrammingfeatures#throughcallofmethod:break_marshalling!classXdefbreak_marshalling!meta_class=class我该怎么做才能使对象编码正确?是否可以从对象instance_of_x的classX中“移除”单例组件?我真的需要一个建议,因为我们的一些对象需要通过Marshal.dump序列化机制进行缓存。

随机推荐