变分自编码器(VAE)的代码理解

来自我的个人网站: http://wangbch.com

variational_autoencoder.py

变分自编码器(VAE)
参考自:http://blog.csdn.net/jackytintin/article/details/53641885
- 自编码器(autoencoder) 是一种非监督式学习的神经网络模型,采用原始数据作为输入和输出,含有一个数量小于输入输出的隐藏层。
- 从输入到隐藏层,这一段神经元数量下降,被称为”encoder”,也可以称为模式识别模型或判别模型;而从隐藏层到输出,这一段神经元数量上升,被称为”decoder”,也称生成模型。因而编码器在一定程度上是类似于GAN的
- 由于隐藏层数量小于输入,所以会对数据进行压缩,之后输出神经元数量大于隐藏层,压缩后的隐藏层相互组合重现原始输出
- 它尝试使用一个函数,将输入逼近输出,经过训练之后,撤去输入层,仅凭隐藏层也可以实现重现输出
- 这样隐藏层就需要做到提取主要成分的任务。这样的功能实现了隐藏层对于数据特征的提取,类似于主成分分析(PCA)
- 稀疏自编码器(sparse autoencoder) 中的隐藏层数量会多于输入输出,此时需要抑制神经元。激活函数会使神经元处于抑制状态,这种抑制是稀疏性限制。比如采用sigmoid作为激活函数,就引入一个接近于0的稀疏性参数,这样会使得神经元的输出接近于0,从而在经过sigmoid函数之后会被抑制
- 需要注意的是,在编码器中使用的维度变换,可以为任意结构如MLP, CNN, RNN等
- 变分自编码器(VAE) 常常和GAN一同被提及,它们都属于生成模型,采用少量样本即可实现训练。步骤如下(结合后面的模型结构进行分析):
1. encoder或判别器将输入的n维数据转换为2个m维数据,其中第一个视作**m个高斯分布的均值,第二个视作**m个高斯分布方差的对数
2. 根据上述2个m维的数据,生成m维的服从高斯分布的随机数
3. 高斯分布先生成(None, m)的正态分布矩阵a,然后out = mean + exp(log_var/2) * a 输出encoder层的结果,注意是先生成N(0,1)再乘,而不是直接生成N(mean,log_var),这样只涉及线性操作
4. 模型结构如下:

layershapenotes
input(None, n)输入
encoder(None, ?)判别器,可采用MLP,CNN,RNN等
mean(None, m)均值,连接到hidden层
log_var(None, m)方差对数,和mean层并列,直接连接到hidden层
gaussian_out(None, m)生成高斯分布随机数
decoder(None, ?)生成器
output(None, n)恢复原始输出

- 变分自编码器的意义以及和GAN的简单对比: 变分自编码器将decoder训练过后,根据正态分布的随机数,即可生成原始图像。而训练出的encoder,也可以作为数据降维,高维数据可视化的手段。
- 与GAN的差异在于,VAE采用原始数据输入和输出,目的是训练encoder和decoder的能力,使其重现输入
- 而GAN的discriminator(和encoder类似)并不是抽取高维特征,而是直接辨别真假结果,但是训练时也会逐渐习得特征。GAN的generator(和decoder)类似,是从随机数中生成数据用于判别,并逐渐训练使其接近原始输入
- VAE和GAN是非常相似的,GAN的G-D模型,实际上可以理解为VAE的decoder,而GAN的D模型,也可理解为VAE的encoder
- VAE的输入经过encoder之后,会提取均值和对数方差,这就是对于不同特征的样本,生成了不同特征的随机数,之后用随机数做生成 ,就不依赖于特定输入输出,GAN也是采用随机数作为输入生成,但是GAN的随机数的特征是固定的,VAE的随机数的特征(均值和方差),会保留与输入的相关性。


variational_autoencoder.py对VAE的实现

  1. encoder:输入(batch_size, original_dim);用Dense将其转化为intermediate_dim数量的中间层,激活函数采用ReLU;z_mean和z_log_var均为shape:(batch_size, latent_dim)的矩阵。这个例子中并没有采用model.add的方式进行,而是利用<layer>(<parameter>)(<last_layer>)的方式连接,因为z_mean和z_log_var相互是并联在中间层上的,用sequence()无法实现
  2. 之后创建采样函数,输入z_mean和z_log_var,return一个方差为z_log_var/2,均值为z_mean的shape为(batch_size, latent_dim)的随机数矩阵。
  3. decoder:输入采样过后得到的随机数矩阵,将其转化为shape=(batch_size, intermediate_dim)的中间层,再转化为与输入相同shape的输出层decoded。
  4. 建立完成模型之后,建立一个继承自Layer的类,重写layer的call方法(每次调用),其中输入为原始数据以及最终生成的数据。loss由两部分组成,第一部分是z_mean和z_log_var,另一部分是输入和最终输出(decoded)的binary cross-entropy,这个继承至layer的类,将以模型的输入和输出作为参数,使模型增添loss函数用以训练

在创建了完整的VAE模型并增添loss函数之后,将喂入手写数据集用于训练(注意这里只会喂入image,没有任何label,因为是非监督的);训练完成之后将输入和z_mean连在一起构成新的模型,喂入手写数据集进行可视化;之后将(latent_dim, )作为输入节点,最终生成的图片作为输出节点,构建decoder模型,喂入随机数生成图片
1. 构建完整训练模型:首先将输入节点,即原始数据x,和输出节点,即生成的结果,一起作为参数传递到4.的layer中,用以定义损失函数。之后创建训练模型,将原始输入和损失函数作为节点连接(此时损失函数中就包含了运算图的信息)vae = Model(x, y),之后创建优化函数,喂入手写数字数据集进行训练
2. 构建encoder模型:用encoder = Model(x, z_mean)连接输入和z_mean输出节点,之后喂入手写数据进行预测,作图
3. 构建generator模型:采用generator = Model(decoder_input, _x_decoder_mean)


variational_autoencoder_deconv.py

这个例子将上个例子的全连接隐藏层变为了卷积和反卷积层,也是采用<layer>(<parameter>)(<last_layer>)的方式构建完整VAE网络以及encoder和decoder,具体完整VAE模型结构如下

layershape
input(None, 28, 28, 1)
conv2d(None, 28, 28, 1)
conv2d(None, 14, 14, 64)
conv2d(None, 14, 14, 64)
conv2d(None, 14, 14, 64)
flatten(None, 12544)
dense_out(None, 128)
以下z_mean和z_log_var是并列关系直接连接到dense_out
z_mean(None, 2)
z_log_var(None, 2)
dense_decoder_in(None, 128)
dense(None, 12544)
reshape(None, 14, 14, 64)
deconv2d(None, 14, 14, 64)
deconv2d(None, 14, 14, 64)
deconv2d(None, 29, 29, 64)
conv2d(None, 28, 28, 1)
自建层(None, 28, 28, 1)和(None, 28, 28, 1),求取loss

训练完成之后,用于特征提取的encoder的完整结构如下:

layershape
input(None, 28, 28, 1)
conv2d(None, 28, 28, 1)
conv2d(None, 14, 14, 64)
conv2d(None, 14, 14, 64)
conv2d(None, 14, 14, 64)
flatten(None, 12544)
dense(None, 128)
dense(None, 2)

decoder的结构如下:

layershape
input(None, 2)
dense(None, 128)
dense(None, 12544)
reshape(None, 14, 14, 64)
deconv2d(None, 14, 14, 64)
deconv2d(None, 14, 14, 64)
deconv2d(None, 29, 29, 64)
conv2d(None, 28, 28, 1)

完整的VAE模型相当于将encoder和decoder连接在一起,并增加loss函数用于训练

体会与心得

  • 神经网络中,每个参数都有自己的功能,虽然机器并不会知道这些功能是什么,但是人类创建的模型的逻辑结构,决定了某些参数最适合做什么功能,而机器为了去达到更小的损失,就会学着将这些参数按照人类的意志使用。比如自编码器,人类的意图是用一个同等的输入输出,加上一个更小的隐藏层,达到数据的特征提取压缩,以及解压和重现;但是在机器眼中,就只有较小的隐藏层,和同样大小的输入输出层。然而在训练过程中,为了降低损失,机器采用的最佳的方式,就是像人类希望地那样,将隐藏层作为特征提取,于是就学会了完成人类的意图
  • 在GAN中也是如此,真实数据代表1,虚假数据代表0,机器不懂这是为了区别真假,但是它会这样去做。之后尝试将随机数生成判别为1的图片,人类是为了生成以假乱真的图片,但是机器不了解这个目的,不过也是会按照人类的意志去做
  • 所以深度学习,就像是人类给机器构建了一个自然选择的环境,而机器就自我进化。但是与大自然不同,人类需要去制定一些规则,这些规则实际上是不必要的,但是为了更快收敛是需要的。比如,如果采用全连接而不是卷积处理图像数据,机器最终也会在权重上反映出来某些间隔数据点是具有相关性的,这些数据点也就是二维中间隔相近的点,但是为了快速收敛,人类用卷积给了机器一个思考方式
  • 另外一例是在LSTM中的“遗忘门”,没有人告诉机器这个东西是来控制遗忘的,但是这个值能够在某些情况下抑制特定的神经元,机器在逐渐优化的过程中,就会为了减少loss而逐渐意识到这个东西是用来干什么的。
  • 也就是说,人类构建的模型应当是十分优化的,基于目的的,机器能够通过减少loss来迎合这种人类的目的。不过有时候,当构建模型时,人类将模型放得很开,此时就会反而不理解到底机器做了什么,比如卷积网络,人类的目的就是提取特征,连接高阶特征,保留二维数据的空间关系,不像LSTM的遗忘门那样在设计时就有明确的功能,于是这样当机器训练学成之后,人类也都无法理解机器进行了怎样的提取

不过有时候我也这样想,当我们睁开眼睛,辨别物体的时候,是不是就像机器那样开始读取图像数据集,并训练成标签。而当我们闭上眼睛的时候,是不是就看到了那些训练好的卷积网络的隐藏层权重图像?而当我们做梦,是不是就相当于将训练好的标签经过decoder又返回变成图形?这样一想,突然感觉深度学习非常值得深入讨论,如何结合我们的大脑,构建强大的机器?
也许有一天,如果我们构建了一个和大脑完全相同的神经网络结构,加上传感器,也许就能够完完全全创造一个人类的复制品,但是,人类研究这样久之后得到的东西,自然界又是怎样发展而来,达到如此小的功耗的呢?

  • 9
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值