VAE变分自编码器原理推导+Python代码实现

1、前言

变分自编码器是近些年较火的一个生成模型,我个人认为其本质上仍然是一个概率图模型,只是在此基础上引入了神经网络。本文将就变分自编码器(VAE)进行简单的原理讲解和数学推导。

2、引入

2.1、高斯混合模型

生成模型,可以简单的理解为生成数据 ( 不止,但我们暂且就这么理解它 ) \boxed{(不止,但我们暂且就这么理解它)} (不止,但我们暂且就这么理解它)。假如现在我们有样本数据,而我们发现这些样本符合正态分布且样本具有充分的代表性,因此我们计算出样本的均值和方差,就能得到样本的概率分布。然后从正态分布中抽样,就能得到样本。 这种生成样本的过程就是生成过程 \boxed{\mathbf{这种生成样本的过程就是生成过程}} 这种生成样本的过程就是生成过程

可是,假如我们的数据长这样

VAE变分自编码器原理推导+Python代码实现_第1张图片

很显然,它的数据是由两个不同的正态分布构成。我们可以计算出这些样本的概率分布。但是一种更为常见的方法就是将其当作是两个正态分布。我们引入一个隐变量z。

假设 z 的取值为 0 , 1 \boxed{\mathbf{假设z的取值为0,1}} 假设z的取值为01,如果z为0,我们就从蓝色的概率分布中抽样;否则为1,则从橙色的概率分布中抽样。这就是生成过程。

但是这个隐变量z是什么?它其实就是隐藏特征 训练数据 x 的抽象出来的特征 \boxed{\mathbf{训练数据x的抽象出来的特征}} 训练数据x的抽象出来的特征,比如,如果x偏小,我们则认为它数据蓝色正太分布,否则为橙色。这个 “偏小” \boxed{“偏小”} 偏小就是特征,我们把它的取值为0,1(0代表偏小,1代表偏大)。

那这种模型我们如何取训练它呢?如何去找出这个z呢? 一种很直观的方法就是重构代价最小 \boxed{\mathbf{一种很直观的方法就是重构代价最小}} 一种很直观的方法就是重构代价最小,我们希望,给一个训练数据x,由x去预测隐变量z,再由隐变量z预测回x,得到的误差最小。比如假如我们是蓝色正态分布,去提取特征z,得到的z再返回来预测x,结果得到的却是橙色的正态分布,这是不可取的。其模型图如下

在这里插入图片描述

这个模型被称为GMM高斯混合模型

2.2、变分自编码器(VAE)

那它和VAE有什么关联呢?其实VAE的模型图跟这个原理差不多。只是有些许改变, 隐变量 z 的维度是连续且高维的,不再是简单的离散分布 \boxed{\mathbf{隐变量z的维度是连续且高维的,不再是简单的离散分布}} 隐变量z的维度是连续且高维的,不再是简单的离散分布,因为假如我们生成的是图片,我们需要提取出来的特征明显是要很多的,传统的GMM无法做到。

在VAE中, q ( z ∣ x ) q(z|x) q(zx) (也就是用样本 x 预测变量 z ) \boxed{(也就是用样本x预测变量z)} (也就是用样本x预测变量z,其服从高斯分布,接下来,我们来看模型图

VAE变分自编码器原理推导+Python代码实现_第2张图片

也就是将训练样本x给神经网络,让神经网络计算出均值和协方差矩阵 μ , log ⁡ σ 2 \mu,\log \sigma^2 μ,logσ2 取 log ⁡ 的原因是传统的神经网络输出值总是有正有负 \boxed{\mathbf{取\log的原因是传统的神经网络输出值总是有正有负}} log的原因是传统的神经网络输出值总是有正有负。有了这两个值就可以在对应的高斯分布中采样,得到隐变量z。再让z经过神经网络重构回样本,得到新样本。这就是整个VAE的大致过程了。

再次强调 训练过程我们希望每次重构的时候,新样本和训练样本尽可能的相似 \boxed{\mathbf{训练过程我们希望每次重构的时候,新样本和训练样本尽可能的相似}} 训练过程我们希望每次重构的时候,新样本和训练样本尽可能的相似

如果我们这样直接去训练的化,可以吗?可以!但是会有个问题,神经网络会趋向于将协方差变0,而让概率分布 q ( z ∣ x ) q(z|x) q(zx)将不再具备随机性,概率分布空间会坍缩成一个点,每次采样都是均值,这种情况我们俗称过拟合。

为什么协方差会变成0?因为采样具有随机性,也就是存在噪声,噪声是肯定会增加重构的误差的。神经网络为了让误差最小,是肯定让这个随机性越小越好,因为只有这样,才能重构误差最小

但是我们肯定是希望有随机性的,为什么?因为有随机性,我们才可以生成不同的样本啊!

所以,对于概率分布 q ( z ∣ x ) q(z|x) q(zx),我们不希望它的协方差为0,所以我们需要对其进行约束。在论文中,它对其进行约束,要求它尽量的往 N ( 0 , I ) N(0,I) N(0,I)靠近( 其实与先验分布 P ( z ) 有关,后续数学推导中可见 , 假设 P ( z ) ∼ N ( z ∣ 0 , I ) \boxed{其实与先验分布P(z)有关,后续数学推导中可见,假设P(z)\sim N(z|0,I)} 其实与先验分布P(z)有关,后续数学推导中可见,假设P(z)N(z∣0,I)

所以,有KL散度去衡量两个概率分布的相似性
min ⁡ K L ( P ( z ∣ x ) ∣ ∣ P ( z ) ) \min KL\left(P(z|x)||P(z)\right) minKL(P(zx)∣∣P(z))
KL散度是大于等于0的值,越小则证明越相似
K L ( q ( x ) ∣ ∣ p ( x ) ) = ∫ x q ( x ) log ⁡ q ( x ) p ( x ) d x KL(q(x)||p(x))=\int_x q(x)\log\frac{q(x)}{p(x)}dx KL(q(x)∣∣p(x))=xq(x)logp(x)q(x)dx
所以,我们就是两个优化目标
①最小化重构代价 ②最小化上述的 K L 散度 \boxed{\mathbf{①最小化重构代价}}\\ \boxed{\mathbf{②最小化上述的KL散度}} 最小化重构代价最小化上述的KL散度
依照这两个条件,建立目标函数,直接梯度下降 ( 其实还需要重参数化,后面会讲到 ) \boxed{\mathbf{(其实还需要重参数化,后面会讲到)}} (其实还需要重参数化,后面会讲到),刷刷刷地往下降,最终收敛。

下面,我们就对其进行简单的数学推导,并以此推导出目标函数

3、原理推导

3.1、引入目标函数

以VAE的简略图为例

在这里插入图片描述

定义隐变量先验分布 P ( z ) ∼ N ( 0 , I ) P(z) \sim N(0,I) P(z)N(0,I)。很自然的想法,我们直接对x求log极大似然,假设我们有N的样本,记作X。设所需求解的参数为 θ \theta θ,第 i i i个样本记为 x i x^{i} xi,某个样本的第 j j j个维度记作 x j x_j xj
log ⁡ P ( X ) = log ⁡ ∏ i = 1 N P ( x i ) = ∑ i = 1 N log ⁡ P ( x i ) \begin{aligned} \log P(X)=&\log\prod\limits_{i=1}^N P(x^i) \\=&\sum\limits_{i=1}^N\log P(x_i) \end{aligned} logP(X)==logi=1NP(xi)i=1NlogP(xi)
现在,我们先单独看看里面某一个样本的似然,某个样本记为 x x x
log ⁡ P ( x ) = log ⁡ P ( x , z ) P ( z ∣ x ) = log ⁡ P ( x , z ) − log ⁡ P ( z ∣ x ) \begin{aligned} \log P(x)=&\log\frac{P(x,z)}{P(z|x)} \\=&\log P(x,z) -\log P(z|x) \end{aligned} logP(x)==logP(zx)P(x,z)logP(x,z)logP(zx)
等式左右分别对 q ( z ∣ x ) q(z|x) q(zx)求积分
左边: ∫ z log ⁡ P ( x ) q ( z ∣ x ) d z = log ⁡ P ( x ) ∫ z q ( z ∣ x ) d z = log ⁡ P ( x ) \begin{aligned} &\mathbf{左边:}\int_z \log P(x)q(z|x)dz=\log P(x)\int_z q(z|x)dz=\log P(x) \\ \end{aligned} 左边:zlogP(x)q(zx)dz=logP(x)zq(zx)dz=logP(x)
所以
log ⁡ P ( x ) = ∫ z ( log ⁡ P ( x , z ) − log ⁡ P ( z ∣ x ) ) q ( z ∣ x ) d z = ∫ z ( log ⁡ P ( x , z ) q ( z ∣ x ) − log ⁡ P ( z ∣ x ) q ( z ∣ x ) ) q ( z ∣ x ) d z = ∫ z log ⁡ P ( x , z ) q ( z ∣ x ) q ( z ∣ x ) d z − log ⁡ P ( z ∣ x ) q ( z ∣ x ) q ( z ∣ x ) d z = ∫ z log ⁡ P ( x , z ) q ( z ∣ x ) q ( z ∣ x ) d z ⏟ ① − K L ( q ( z ∣ x ) ∣ ∣ P ( z ∣ x ) ) ⏟ ② \begin{align} \log P(x)=&\int_z (\log P(x,z)-\log P(z|x))q(z|x)dz\tag{a} \\=&\int_z (\log \frac{P(x,z)}{q(z|x)}-\log \frac{P(z|x)}{q(z|x)})q(z|x)dz\tag{b} \\=&\int_{z}\log\frac{P(x,z)}{q(z|x)}q(z|x)dz-\log \frac{P(z|x)}{q(z|x)}q(z|x)dz\nonumber \\=&\underbrace{\int_{z}\log\frac{P(x,z)}{q(z|x)}q(z|x)dz}_{①}-\underbrace{KL(q(z|x)||P(z|x))}_{②}\nonumber \end{align} logP(x)====z(logP(x,z)logP(zx))q(zx)dzz(logq(zx)P(x,z)logq(zx)P(zx))q(zx)dzzlogq(zx)P(x,z)q(zx)dzlogq(zx)P(zx)q(zx)dz zlogq(zx)P(x,z)q(zx)dz KL(q(zx)∣∣P(zx))(a)(b)
(式a)到(式b)用到了 log ⁡ \log log的性质。

对于里面的第②项,因为KL是大于等于0的。在给定x的情况下, log ⁡ P ( x ) \log P(x) logP(x)的值是确定的,所以 log ⁡ P ( x ) \log P(x) logP(x)的最大值,其实就等价于最大化第①项(最小化第②项),即
max ⁡ ∫ z log ⁡ P ( x , z ) q ( z ∣ x ) q ( z ∣ x ) d z ↔ min ⁡ K L ( q ( z ∣ x ) ∣ ∣ P ( z ∣ x ) ) \max \int_{z}\log\frac{P(x,z)}{q(z|x)}q(z|x)dz \leftrightarrow \min KL(q(z|x)||P(z|x)) maxzlogq(zx)P(x,z)q(zx)dzminKL(q(zx)∣∣P(zx))
好,现在我们只需要最大化
max ⁡ ∫ z log ⁡ P ( x , z ) q ( z ∣ x ) q ( z ∣ x ) d z = max ⁡ ∫ z log ⁡ P ( x ∣ z ) P ( z ) q ( z ∣ x ) q ( z ∣ x ) d z = max ⁡ ∫ z ( log ⁡ P ( z ) q ( z ∣ x ) + log ⁡ P ( x ∣ z ) ) q ( z ∣ x ) d z = max ⁡ ∫ z log ⁡ P ( x ∣ z ) q ( z ∣ x ) d z − ∫ log ⁡ q ( z ∣ x ) P ( z ) q ( z ∣ x ) d z = max ⁡ ( E q ( z ∣ x ) [ log ⁡ P ( x ∣ z ) ] ⏟ ① − K L ( q ( z ∣ x ) ∣ ∣ P ( z ) ) ⏟ ② ) \begin{aligned} &\max \int_{z}\log\frac{P(x,z)}{q(z|x)}q(z|x)dz \\=&\max \int_z\log \frac{P(x|z)P(z)}{q(z|x)}q(z|x)dz \\=&\max \int_z \left(\log \frac{P(z)}{q(z|x)}+\log P(x|z)\right)q(z|x)dz \\=&\max \int_z\log P(x|z)q(z|x)dz-\int \log \frac{q(z|x)}{P(z)}q(z|x)dz \\=&\max \left(\underbrace{\mathbb{E}_{q(z|x)}\left[\log P(x|z)\right]}_{①} -\underbrace{KL(q(z|x)||P(z))}_{②}\right) \end{aligned} ====maxzlogq(zx)P(x,z)q(zx)dzmaxzlogq(zx)P(xz)P(z)q(zx)dzmaxz(logq(zx)P(z)+logP(xz))q(zx)dzmaxzlogP(xz)q(zx)dzlogP(z)q(zx)q(zx)dzmax( Eq(zx)[logP(xz)] KL(q(zx)∣∣P(z)))

发现了吗,最大化里面的第一项就期望,不就是从 q ( z ∣ x ) q(z|x) q(zx)采样z,再让 log ⁡ P ( x ∣ z ) \log P(x|z) logP(xz)概率最大。这不就是重构代价最小吗;而对于第二项,最大化 − K L -KL KL散度,就相当于最小化 K L KL KL散度。这和我们上面提到的两个优化目标是一样的。

3.2、细化目标函数

既然得到了目标函数,那么我们就对 log ⁡ P ( x ∣ z ) \log P(x|z) logP(xz)似然和KL散度都求出具体的表达。

先来看 K L 散度 \boxed{先来看KL散度} 先来看KL散度

前面我们提到, q ( z ∣ x ) q(z|x) q(zx)需要逼近 P ( z ) P(z) P(z),而 P ( z ) ∼ N ( 0 , I ) P(z) \sim N(0,I) P(z)N(0,I)的多维高斯分布,并且各个维度之间相互独立,所以 q ( z ∣ x ) q(z|x) q(zx)也是如此设定。那么最小化其KL散度,只需要对每一个维度求KL最小即可,单独看某一个维度(为了表达的简洁,正态分布中不再写出随机变量,里面的z都表示和 z j z_j zj是同一个东西,懒得改了,知道就行)
min ⁡ K L ( q ( z j ∣ x ) ∣ ∣ P ( z j ) ) = min ⁡ ∫ q ( z j ∣ x ) log ⁡ q ( z j ∣ x ) P ( z j ) d z = min ⁡ ∫ N ( μ , σ 2 ) log ⁡ N ( μ , σ 2 ) N ( 0 , 1 ) d z = min ⁡ ∫ z N ( μ , σ 2 ) log ⁡ 1 2 π σ exp ⁡ { − ( z − μ ) 2 2 σ 2 } 1 2 π exp ⁡ { − z 2 2 } d z = min ⁡ 1 2 ∫ z N ( μ , σ 2 ) ( z 2 − log ⁡ σ 2 − ( z − μ ) 2 σ 2 ) d z \begin{aligned} &\min KL(q(z_j|x)||P(z_j)) \\=&\min \int q(z_j|x) \log\frac{q(z_j|x)}{P(z_j)}dz \\=&\min \int N(\mu,\sigma^2)\log \frac{N(\mu,\sigma^2)}{N(0,1)}dz \\=&\min \int_z N(\mu,\sigma^2) \log \frac{\frac{1}{\sqrt{2\pi}\sigma}\exp\{-\frac{(z-\mu)^2}{2\sigma^2}\}}{\frac{1}{\sqrt{2\pi}}\exp \{-\frac{z^2}{2}\}}dz \\=&\min \frac{1}{2}\int_z N(\mu,\sigma^2)\left(z^2-\log \sigma^2-\frac{(z-\mu)^2}{\sigma^2}\right)dz \end{aligned} ====minKL(q(zjx)∣∣P(zj))minq(zjx)logP(zj)q(zjx)dzminN(μ,σ2)logN(0,1)N(μ,σ2)dzminzN(μ,σ2)log2π 1exp{2z2}2π σ1exp{2σ2(zμ)2}dzmin21zN(μ,σ2)(z2logσ2σ2(zμ)2)dz
可以分为三部分
①: ∫ z N ( μ , σ 2 ) z 2 d z = E [ z 2 ] = D ( z ) + E [ z ] 2 = σ 2 + μ 2 ②: ∫ z N ( μ , σ 2 ) log ⁡ σ 2 d z = log ⁡ σ 2 ∫ z N ( μ , σ 2 ) d z = log ⁡ σ 2 ③: ∫ z N ( μ , σ 2 ) ( z − μ ) 2 σ 2 d z = 1 σ 2 ∫ z N ( μ , σ 2 ) ( z − μ ) 2 d z = 1 σ 2 E [ ( z − μ ) 2 ] = 1 \begin{align} ①:&\int_z N(\mu,\sigma^2)z^2 dz=\mathbb{E}[z^2]=D(z)+\mathbb{E}[z]^2=\sigma^2+\mu^2\tag{A}\\ ②:&\int_z N(\mu,\sigma^2)\log \sigma^2 dz = \log\sigma^2\int_zN(\mu,\sigma^2)dz=\log \sigma^2\tag{B} \\ ③:&\int_z N(\mu,\sigma^2)\frac{(z-\mu)^2}{\sigma^2}dz=\frac{1}{\sigma^2}\int_z N(\mu,\sigma^2)(z-\mu)^2dz=\frac{1}{\sigma^2}\mathbb{E}[(z-\mu)^2]=1\tag{C} \end{align} zN(μ,σ2)z2dz=E[z2]=D(z)+E[z]2=σ2+μ2zN(μ,σ2)logσ2dz=logσ2zN(μ,σ2)dz=logσ2zN(μ,σ2)σ2(zμ)2dz=σ21zN(μ,σ2)(zμ)2dz=σ21E[(zμ)2]=1(A)(B)(C)
对于(式 A ),里面用到了方差的计算公式 D ( z ) = E ( z 2 ) − E ( z ) 2 \boxed{\mathbf{对于(式A),里面用到了方差的计算公式D(z)=E(z^2)-E(z)^2}} 对于(式A),里面用到了方差的计算公式D(z)=E(z2)E(z)2

对于(式 B ) , 是因为 N ( μ , σ 2 ) 积分为 1 \boxed{\mathbf{对于(式B),是因为N(\mu,\sigma^2)积分为1}} 对于(式B,是因为N(μ,σ2)积分为1

对于(式 C ) \boxed{\mathbf{对于(式C)}} 对于(式C
1 σ 2 E [ ( z − μ ) 2 ] = 1 σ 2 E [ z 2 − 2 μ z + μ 2 ] = 1 σ 2 ( E ( z 2 ) − 2 μ E ( z ) + μ 2 ) = 1 σ 2 ( σ 2 + μ 2 − 2 μ 2 + μ 2 ) = 1 \begin{aligned} &\frac{1}{\sigma^2}\mathbb{E}[(z-\mu)^2]\\ \\=&\frac{1}{\sigma^2}\mathbb{E}[z^2-2\mu z +\mu^2] \\=&\frac{1}{\sigma^2}\left(\mathbb{E}(z^2)-2\mu\mathbb{E}(z)+\mu^2\right) \\=&\frac{1}{\sigma^2}\left(\sigma^2+\mu^2-2\mu^2+\mu^2\right) \\=1 \end{aligned} ====1σ21E[(zμ)2]σ21E[z22μz+μ2]σ21(E(z2)2μE(z)+μ2)σ21(σ2+μ22μ2+μ2)
如果你熟悉高斯分布的高阶矩的话,式A和式C完全就是二阶原点矩和中心距,是直接可以的得出答案的。

所以对于所有维度的 K L 散度 , 有 ( 假设隐变量有 J 维 ) \boxed{\mathbf{所以对于所有维度的KL散度,有(假设隐变量有J维)}} 所以对于所有维度的KL散度,(假设隐变量有J)
min ⁡ 1 2 ∑ j = 1 J ( σ j 2 + μ j 2 − log ⁡ σ j 2 − 1 ) \min \frac{1}{2}\sum\limits_{j=1}^J(\sigma^2_j+\mu^2_j-\log \sigma^2_j -1 ) min21j=1J(σj2+μj2logσj21)

再来看 log ⁡ P ( x ∣ z ) 极大似然,即 max ⁡ E q ( z ∣ x ) [ log ⁡ P ( x ∣ z ) ] \boxed{\mathbf{再来看\log P(x|z)极大似然,即\max \mathbb{E}_{q(z|x)}[\log P(x|z)]}} 再来看logP(x∣z)极大似然,即maxEq(z∣x)[logP(x∣z)]

值得注意的是,我看很多文章中都说此处就直接采用均方差来计算。这种说法是不准确的,在论文中提到 P ( x ∣ z ) P(x|z) P(xz)是服从一个概率分布的,而不是无端的就计算其差值。它不像是GAN一样,对于其隐藏在内部的概率分布不作约束,VAE是仍然对 P ( x ∣ z ) P(x|z) P(xz)进行约束。

VAE变分自编码器原理推导+Python代码实现_第3张图片

“ log ⁡ p θ ( x ( i ) ∣ z ( i , l ) ) 是伯努利或高斯 M L P ,这取决于我们建模的数据类型” \boxed{“\log p θ (x^{(i)} |z^{(i,l)} )是伯努利或高斯MLP,这取决于我们建模的数据类型”} log(x(i)z(i,l))是伯努利或高斯MLP,这取决于我们建模的数据类型

当然了,其实我们也可以不对其概率分布进行约束,归根究底,其让然是最小重构代价,那么我们的目标函数如果可以充分表达出“最小重构代价”,那么是什么又有何关系呢?

在论文中,其假设 P ( x ∣ z ) ∼ N ( μ , σ 2 I ) P(x|z) \sim N(\mu,\sigma^2 I) P(xz)N(μ,σ2I),其中 μ \mu μ σ 2 \sigma^2 σ2都是需要使用神经网络去逼近。

但是,一般地,我们假设 P ( x ∣ z ) ∼ ( f ( z ) , c I ) P(x|z) \sim (f(z),cI) P(xz)(f(z),cI),也就是其均值用神经网络去逼近,对于其协方差矩阵,我们设定为常数c和 I I I相乘,所以依然是各个维度之间相互独立。我们来看看它的极大似然估计得什么(假设采样n个样本)

max ⁡ E q ( z ∣ x ) [ log ⁡ P ( x ∣ z ) ] = max ⁡ 1 n ∑ i = 1 n log ⁡ P ( x i ∣ z i ) = max ⁡ 1 n ∑ i = 1 n log ⁡ 1 2 π D / 2 ∣ c I ∣ 1 / 2 exp ⁡ { − 1 2 ( x − f ( z i ) ) ( c I ) − 1 ( x − f ( z i ) ) T } = max ⁡ 1 n ∑ i = 1 n log ⁡ 1 2 π D / 2 ∣ c I ∣ 1 / 2 − 1 2 ( x − f ( z i ) ) ( c I ) − 1 ( x − f ( z i ) ) T = min ⁡ 1 n ∑ i = 1 n ( x − f ( z i ) ) ( x − f ( z i ) ) T 2 c = min ⁡ 1 n ∑ i = 1 n ∣ ∣ x − f ( z i ) ∣ ∣ 2 c \begin{aligned} \max \mathbb{E}_{q(z|x)}[\log P(x|z)]=&\max\frac{1}{n}\sum\limits_{i=1}^n\log P(x^i|z^i) \\=&\max\frac{1}{n}\sum\limits_{i=1}^n\log \frac{1}{{2\pi }^{D/2}|cI|^{1/2}}\exp\left\{-\frac{1}{2}(x-f(z^i))(cI)^{-1}(x-f(z^i))^T\right\} \\=&\max\frac{1}{n}\sum\limits_{i=1}^n\log \frac{1}{{2\pi }^{D/2}|cI|^{1/2}}-\frac{1}{2}(x-f(z^i))(cI)^{-1}(x-f(z^i))^T \\=&\min \frac{1}{n}\sum\limits_{i=1}^n\frac{(x-f(z^i))(x-f(z^i))^T}{2c} \\=&\min \frac{1}{n}\sum\limits_{i=1}^n\frac{||x-f(z^i)||}{2c} \end{aligned} maxEq(zx)[logP(xz)]=====maxn1i=1nlogP(xizi)maxn1i=1nlog2πD/2cI1/21exp{21(xf(zi))(cI)1(xf(zi))T}maxn1i=1nlog2πD/2cI1/2121(xf(zi))(cI)1(xf(zi))Tminn1i=1n2c(xf(zi))(xf(zi))Tminn1i=1n2c∣∣xf(zi)∣∣
看出来了吧,如果让 2 c 2 = 1 2c^2=1 2c2=1,那么它就是一个均方差了。所以归根究底,c就像是神经网络的一个惩罚系数一样。

综合得到最终目标函数表达式 \boxed{\mathbf{综合得到最终目标函数表达式}} 综合得到最终目标函数表达式
min ⁡ ( 1 2 ∑ j = 1 J ( σ j 2 + μ j 2 − log ⁡ σ j 2 − 1 ) + 1 n ∑ i = 1 n ∣ ∣ x − f ( z i ) ∣ ∣ 2 c ) \min \left(\frac{1}{2}\sum\limits_{j=1}^J(\sigma^2_j+\mu^2_j-\log \sigma^2_j -1 )+\frac{1}{n}\sum\limits_{i=1}^n\frac{||x-f(z^i)||}{2c}\right) min(21j=1J(σj2+μj2logσj21)+n1i=1n2c∣∣xf(zi)∣∣)

3.3、重参数化技巧

有了目标函数,理论上我们直接梯度下降就可以了。然而,别忘了,我们是从 q ( z ∣ x ) q(z|x) q(zx)中采样出z来。可是我们却是用的神经网络去计算的均值和方差,得到的高斯分布再去采样,这种情况是不可导的。中间都已经出现了一个断层了。神经网络是一层套一层的计算。而采样计算了一层之后,从这一层中去采样新的值,再计算下一层。因此,采样本身是不可导的。

所以要引入重参数化技巧,即假定 q ( z ∣ x ) ∼ N ( μ , σ 2 ) q(z|x) \sim N(\mu,\sigma^2) q(zx)N(μ,σ2)。那么可以构造一个概率分布 p ( ϵ ) ∼ N ( 0 , 1 ) p(\epsilon) \sim N(0,1) p(ϵ)N(0,1)。有
z = μ + ϵ σ z=\mu +\epsilon\sigma z=μ+ϵσ
我们从 P ( ϵ ) P(\epsilon) P(ϵ)采样,然后利用上述公式,就相当于得到了从 q ( z ∣ x ) q(z|x) q(zx)采样的采样值。

证明 \boxed{\mathbf{证明}} 证明
E ( z ) = E ( μ ) + E ( ϵ ) σ = μ V a r ( z ) = E [ ( z − μ ) 2 ] = E [ ( ϵ σ ) 2 ] = σ 2 \begin{aligned} \mathbb{E}(z)=&\mathbb{E}(\mu)+\mathbb{E}(\epsilon)\sigma=\mu\\ Var(z)=&\mathbb{E}[(z-\mu)^2]=\mathbb{E}[(\epsilon\sigma)^2]=\sigma^2 \end{aligned} E(z)=Var(z)=E(μ)+E(ϵ)σ=μE[(zμ)2]=E[(ϵσ)2]=σ2

4、代码实现

VAE变分自编码器原理推导+Python代码实现_第4张图片

效果一般,不晓得论文里面用了什么手段,效果看起来比这个好。(这个结果甚至还是我加了一层隐藏层的)

import torch
from torch.utils.data import DataLoader
from torchvision.datasets import MNIST
from torchvision.transforms import transforms
from  torch import nn
from tqdm import tqdm
import matplotlib.pyplot as plt
class VAE(nn.Module):
    def __init__(self,input_dim,hidden_dim,gaussian_dim):
        super().__init__()
        #编码器
        #隐藏层
        self.fc1=nn.Sequential(
            nn.Linear(in_features=input_dim,out_features=hidden_dim),
            nn.Tanh(),
            nn.Linear(in_features=hidden_dim, out_features=256),
            nn.Tanh(),
        )
        #μ和logσ^2
        self.mu=nn.Linear(in_features=256,out_features=gaussian_dim)
        self.log_sigma=nn.Linear(in_features=256,out_features=gaussian_dim)



        #解码(重构)
        self.fc2=nn.Sequential(
            nn.Linear(in_features=gaussian_dim,out_features=256),
            nn.Tanh(),
            nn.Linear(in_features=256, out_features=512),
            nn.Tanh(),
            nn.Linear(in_features=512,out_features=input_dim),
            nn.Sigmoid() #图片被转为为0,1的值了,故用此函数
        )
    def forward(self,x):
        #隐藏层
        h=self.fc1(x)

        #计算期望和log方差
        mu=self.mu(h)
        log_sigma=self.log_sigma(h)

        #重参数化
        h_sample=self.reparameterization(mu,log_sigma)

        #重构
        reconsitution=self.fc2(h_sample)

        return reconsitution,mu,log_sigma

    def reparameterization(self,mu,log_sigma):
        #重参数化
        sigma=torch.exp(log_sigma*0.5) #计算σ
        e=torch.randn_like(input=sigma,device=device)

        result=mu+e*sigma #依据重参数化技巧可得

        return result
    def predict(self,new_x): #预测
        reconsitution=self.fc2(new_x)

        return reconsitution
def train():

    transformer = transforms.Compose([
        transforms.ToTensor(),
    ]) #归一化
    data = MNIST("./data", transform=transformer,download=True) #载入数据

    dataloader = DataLoader(data, batch_size=128, shuffle=True) #写入加载器

    model = VAE(784, 512, 20).to(device) #初始化模型

    optimer = torch.optim.Adam(model.parameters(), lr=1e-3) #初始化优化器

    loss_fn = nn.MSELoss(reduction="sum") #均方差损失
    epochs = 100 #训练100轮

    for epoch in torch.arange(epochs):
        all_loss = 0
        dataloader_len = len(dataloader.dataset)

        for data in tqdm(dataloader, desc="第{}轮梯度下降".format(epoch)):
            sample, label = data
            sample = sample.to(device)
            sample = sample.reshape(-1, 784) #重塑
            result, mu, log_sigma = model(sample) #预测

            loss_likelihood = loss_fn(sample, result) #计算似然损失

            #计算KL损失
            loss_KL = torch.pow(mu, 2) + torch.exp(log_sigma) - log_sigma - 1

            #总损失
            loss = loss_likelihood + 0.5 * torch.sum(loss_KL)

            #梯度归0并反向传播和更新
            optimer.zero_grad()

            loss.backward()

            optimer.step()
            with torch.no_grad():
                all_loss += loss.item()
        print("函数损失为:{}".format(all_loss / dataloader_len))
        torch.save(model, "./model/VAE.pth")
if __name__ == '__main__':
    #是否有闲置GPU
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    #训练
    train()

    #载入模型,预测
    model=torch.load("./model/VAE (1).pth",map_location="cpu")
    #预测20个样本
    x=torch.randn(size=(20,20))
    result=model.predict(x).detach().numpy()
    result=result.reshape(-1,28,28)
    #绘图
    for i in range(20):
        plt.subplot(4,5,i+1)
        plt.imshow(result[i])
        plt.gray()
    plt.show()

VAE有很多的变种优化,感兴趣的读者自行查阅。

5、结束

以上,就是VAE的原理和推导过程了。能力有限,过程并不严谨,如有问题,还望指出。阿里嘎多

VAE变分自编码器原理推导+Python代码实现_第5张图片

你可能感兴趣的:(机器学习,人工智能,笔记,python,机器学习,开发语言,深度学习)