VAE模型(详细推导+实例代码)

news2024/11/17 4:41:52

文章目录

    • EM算法
      • 思路
      • E步
      • M步
      • 直观感觉
    • GMM模型
    • VAE
      • VAE思想
      • 从GMM到VAE
      • 公式推导
      • 重参数
      • VAE+神经网络
      • 另一个视角的VAE
        • 思想
        • 为什么引入encoder
        • 为什么要重参数
        • 噪声与重建
      • Discrete VAE

本文会从EM算法,GMM模型一步一步的的推导,在过渡到VAE模型,如果有熟悉的部分可以跳过。
Reference:

  1. [苏剑林] https://spaces.ac.cn/archives/5253
  2. Auto-Encoding Variational Bayes; arXiv:1312.6114 [stat.ML]
  3. 李宏毅 机器学习课程第六讲
  4. 机器学习白板推导 https://www.bilibili.com/video/BV1aE411o7qd/

EM算法

思路

首先回顾一下EM算法的过程:假设X是全体样本, θ \theta θ是全体参数。
那么MLE求解生成模型就是要求得一个 θ \theta θ,使得 P ( X ∣ θ ) P(X|\theta) P(Xθ)最大。(因为假设X是抽自于某个分布)
也就是如下式子:
θ ^ = arg max ⁡ θ P ( X ∣ θ ) \hat \theta = \argmax\limits_{\theta} P(X|\theta) θ^=θargmaxP(Xθ)
一般为了方便求解,会加上一个log。
θ ^ = arg max ⁡ θ l o g P ( X ∣ θ ) \hat \theta = \argmax\limits_{\theta} logP(X|\theta) θ^=θargmaxlogP(Xθ)
假设存在一个隐变量Z,这个隐变量可以生成X。
此时:

  1. X称之为观测数据
  2. Z称之为隐藏数据
  3. (X,Z)称之为完全数据

于是我们可以改写上面式子(以下均为恒等变换,不懂的可以从右向左推一遍)
l o g P ( X ∣ θ ) = l o g P ( X , Z ∣ θ ) − l o g P ( Z ∣ X , θ ) logP(X|\theta)=logP(X,Z|\theta)-logP(Z|X,\theta) logP(Xθ)=logP(X,Zθ)logP(ZX,θ)
l o g P ( X ∣ θ ) = l o g P ( X , Z ∣ θ ) Q ( Z ) − l o g P ( Z ∣ X , θ ) Q ( Z ) logP(X|\theta)=log\frac{P(X,Z|\theta)}{Q(Z)}-log\frac{P(Z|X,\theta)}{Q(Z)} logP(Xθ)=logQ(Z)P(X,Zθ)logQ(Z)P(ZX,θ)
然后两边同时乘以Q(Z)(这里表示这个隐变量Z的一个先验分布)再对Z积分,得到
左边 = ∫ z Q ( Z ) l o g P ( X ∣ θ ) d z = l o g P ( X ∣ θ ) 左边=\int_zQ(Z)logP(X|\theta)dz=logP(X|\theta) 左边=zQ(Z)logP(Xθ)dz=logP(Xθ)
右边 = ∫ z Q ( Z ) l o g [ P ( X , Z ∣ θ ) Q ( Z ) ] d z − ∫ z Q ( Z ) l o g [ P ( Z ∣ X , θ ) Q ( Z ) ] d z 右边=\int_zQ(Z)log[\frac{P(X,Z|\theta)}{Q(Z)}]dz-\int_zQ(Z)log[\frac{P(Z|X,\theta)}{Q(Z)}]dz 右边=zQ(Z)log[Q(Z)P(X,Zθ)]dzzQ(Z)log[Q(Z)P(ZX,θ)]dz

可以发现,右边的项是KL Divergence。也就是说:
− ∫ z Q ( Z ) l o g [ P ( Z ∣ X , θ ) Q ( Z ) ] d z = K L ( Q ( Z ) ∣ ∣ P ( Z ∣ X , θ ) ) ≥ 0 -\int_zQ(Z)log[\frac{P(Z|X,\theta)}{Q(Z)}]dz=KL(Q(Z)||P(Z|X, \theta)) \ge 0 zQ(Z)log[Q(Z)P(ZX,θ)]dz=KL(Q(Z)∣∣P(ZX,θ))0
我们记左边的项为ELBo,也就是一个下界
那么
l o g ( P ( X ∣ θ ) ) = E L B o + K L ≥ E L B o = ∫ z Q ( Z ) l o g [ P ( X , Z ∣ θ ) Q ( Z ) ] d z log(P(X|\theta))=ELBo+KL\ge ELBo=\int_zQ(Z)log[\frac{P(X,Z|\theta)}{Q(Z)}]dz log(P(Xθ))=ELBo+KLELBo=zQ(Z)log[Q(Z)P(X,Zθ)]dz
由于KL的非负性,所以上述等式成立,也就是说我们找到了 l o g ( P ( X ∣ θ ) ) log(P(X|\theta)) log(P(Xθ))的一个下界。我们只需要不断地优化提高这个下界,就可以使得其目标函数不断提高(其实这里还需要证明收敛性,不过略过)

E步

当我们固定 θ , X \theta, X θ,X时,左边( l o g ( P ( X ∣ θ ) ) log(P(X|\theta)) log(P(Xθ)))是不变的,而右边我们想要提高下界ELBo。就可以通过最小化KL。KL最小时就是两个分布完全一致,也就说是当:
Q ( Z ) = P ( Z ∣ X , θ ) Q(Z)=P(Z|X, \theta) Q(Z)=P(ZX,θ)
时,ELBo最大,此时我们得到了Z的先验分布就是 Q ( Z ) = P ( Z ∣ X , θ ) Q(Z)=P(Z|X, \theta) Q(Z)=P(ZX,θ)
注意,此时我们固定了 θ \theta θ,所以我们不妨记此时的 θ \theta θ θ ( t ) \theta^{(t)} θ(t)也就是当前t时刻的的值。
Q ( Z ) = P ( Z ∣ X , θ ( t ) ) Q(Z)=P(Z|X, \theta^{(t)}) Q(Z)=P(ZX,θ(t))

M步

在E步中找到了Q的分布后,我们需要寻找在当前Q下能够让 l o g P ( X ∣ θ ) logP(X|\theta) logP(Xθ)尽可能大的 θ \theta θ
也就是说我们要最大化ELBo:
θ ^ = arg max ⁡ θ ∫ z Q ( Z ) l o g [ P ( X , Z ∣ θ ) Q ( Z ) ] d z \hat\theta=\argmax\limits_{\theta} \int_zQ(Z)log[\frac{P(X,Z|\theta)}{Q(Z)}]dz θ^=θargmaxzQ(Z)log[Q(Z)P(X,Zθ)]dz
我们替换ELBo的Q(Z)为M步得到的值,于是得到下面的式子:
θ ^ ( t + 1 ) = arg max ⁡ θ ∫ z P ( Z ∣ X , θ ( t ) ) l o g [ P ( X , Z ∣ θ ) P ( Z ∣ X , θ ( t ) ) ] d z \hat\theta^{(t+1)}=\argmax\limits_{\theta}\int_zP(Z|X, \theta^{(t)})log[\frac{P(X,Z|\theta)}{P(Z|X, \theta^{(t)})}] dz θ^(t+1)=θargmaxzP(ZX,θ(t))log[P(ZX,θ(t))P(X,Zθ)]dz
我们把log中的除法拆成加法:
θ ^ ( t + 1 ) = arg max ⁡ θ ∫ z P ( Z ∣ X , θ ( t ) ) l o g [ P ( X , Z ∣ θ ) ] − P ( Z ∣ X , θ ( t ) ) l o g [ P ( Z ∣ X , θ ( t ) ) ] d z \hat\theta^{(t+1)}=\argmax\limits_{\theta}\int_zP(Z|X, \theta^{(t)})log[P(X,Z|\theta)] -P(Z|X, \theta^{(t)})log[P(Z|X, \theta^{(t)})] dz θ^(t+1)=θargmaxzP(ZX,θ(t))log[P(X,Zθ)]P(ZX,θ(t))log[P(ZX,θ(t))]dz
可以发现,后面的 − P ( Z ∣ X , θ ( t ) ) l o g [ P ( Z ∣ X , θ ( t ) ) -P(Z|X, \theta^{(t)})log[P(Z|X, \theta^{(t)}) P(ZX,θ(t))log[P(ZX,θ(t)) θ \theta θ无关,所以可以舍弃。于是我们得到了M步的目标:
θ ^ ( t + 1 ) = arg max ⁡ θ ∫ z P ( Z ∣ X , θ ( t ) ) l o g [ P ( X , Z ∣ θ ) ] d z \hat\theta^{(t+1)}=\argmax\limits_{\theta}\int_zP(Z|X, \theta^{(t)})log[P(X,Z|\theta)] dz θ^(t+1)=θargmaxzP(ZX,θ(t))log[P(X,Zθ)]dz
我们可以进一步改写上面的式子为期望的形式:
θ ^ ( t + 1 ) = E Z ∣ X , θ ( t ) [ l o g [ P ( X , Z ∣ θ ) ] ] \hat\theta^{(t+1)}=E_{Z|X,\theta^{(t)}}[log[P(X,Z|\theta)]] θ^(t+1)=EZX,θ(t)[log[P(X,Zθ)]]

至此,期望最大化算法(EM)算法推导结束(除了收敛性证明)

直观感觉

直观的来看EM算法的两步可以归为如下步骤:

  1. 固定 θ \theta θ,然后寻找Z的先验P(Z),使得ELBo尽可能的大
  2. 解除 θ \theta θ的固定,然后在E步找到的P(Z)的前提下,最大化ELBo提升下界

GMM模型

高斯混合模型是一种生成模型,它假定存在着一个隐变量Z,Z是一个离散的概率分布,有K个取值,如下:
Z = 1 , 2.. , k P ( Z = i ) = p i ( i ∈ { 1 , 2.. , k } ) ∑ i p i = 1 Z=1,2..,k\\P(Z=i)=p_i(i \in \{1,2..,k\})\\\sum_ip_i=1 Z=1,2..,kP(Z=i)=pi(i{1,2..,k})ipi=1
然后,我们所要建模 P ( X ∣ θ ) P(X|\theta) P(Xθ)由k个高斯分布乘以对应的z的概率值构成,也就是:
P ( X ∣ θ ) = ∑ i = 1 k p i N ( X ∣ Σ i , μ i ) P(X|\theta)=\sum_{i=1}^k p_iN(X|\Sigma_i, \mu_i) P(Xθ)=i=1kpiN(XΣi,μi)
也就是说,有K个高斯分布组成了要建模的分布,这K个高斯分布的线性组合就是我们要求的分布。
其中:
θ = { Σ 1 , Σ 2 . . . Σ k , μ 1 , μ 2 . . . , μ k , p 1 , p 2 . . . p k } \theta=\{\Sigma_1,\Sigma_2...\Sigma_k, \mu_1, \mu_2..., \mu_k, p_1,p_2...p_k\} θ={Σ1,Σ2...Σk,μ1,μ2...,μk,p1,p2...pk}

GMM模型显然是一个含有隐变量的模型,二期我们可以直接通过EM算法来进行求解,但这里主要是为了讲解VAE。所以不写如何求解GMM了。

VAE

VAE思想

VAE的假设很简单:

  1. 存在着隐随机变量Z,该变量有一个先验分布 P θ ( Z ) P_\theta(Z) Pθ(Z)
  2. 从先验分布 P θ ( Z ) P_\theta(Z) Pθ(Z)中抽取样本z
  3. 由样本z得到条件分布 P θ ( X ∣ Z = z ) P_\theta(X|Z=z) Pθ(XZ=z),然后抽样得到X

在这里插入图片描述
如上图所示,隐变量Z决定了X的生成 ( 先忽略参数 ϕ ) (先忽略参数\phi) (先忽略参数ϕ)
以上就是VAE假设的样本生成过程。

从GMM到VAE

可以看到和GMM非常相似,但是这里VAE与GMM有所不同,因为VAE假设的Z是高维,连续的,这就带来了几个问题:
P θ ( X ) = ∫ z P θ ( Z ) P θ ( X ∣ Z ) d z P_\theta(X)=\int_z P_\theta(Z)P_\theta(X|Z) dz Pθ(X)=zPθ(Z)Pθ(XZ)dz
上述式子是我们熟悉的概率乘条件概率的式子,相当于GMM中的高斯分布线性组合。不过这里显然是无穷个高斯分布(因为积分是连续的)。

但是比较尴尬的问题出现了,这个积分是高维的,我们无法对其求解(也就是说是intractable的)。也就是说我们求解得到 P ( X ) P(X) P(X)

那么用EM算法是否可以呢?这里也很难,因为EM算法的E步骤需要令:
Q θ ( Z ) = P θ ( Z ∣ X ) Q_\theta(Z)=P_\theta(Z|X) Qθ(Z)=Pθ(ZX)
P θ ( Z ∣ X ) P_\theta(Z|X) Pθ(ZX)而想要求这个分布也是intractable(因为需要用到 P ( X ) P(X) P(X)),所以我们无法直接求出。

于是我们改其道而行,我们另外找一个分布 q θ ( Z ∣ X ) q_\theta(Z|X) qθ(ZX)我们让这个分布无限的去逼近 P θ ( Z ∣ X ) P_\theta(Z|X) Pθ(ZX),也就是说两者的KL散度最小。

公式推导

我们重回到EM算法的最开始步骤,我们将第i个样本P(x^{(i)})拆解为KL和ELBo
l o g P ( x ( i ) ) = E L B o + K L ≥ E L B o logP(x^{(i)})=ELBo+KL \ge ELBo logP(x(i))=ELBo+KLELBo
注意,KL的公式如下:
K L ( q ( z ) ∣ P ( z ∣ x ( i ) , θ ) ) KL(q(z)|P(z|x^{(i)},\theta)) KL(q(z)P(zx(i),θ))
我们把 q ( z ) q(z) q(z)替换为 Q ϕ ( z ∣ x ( i ) ) Q_\phi(z|x^{(i)}) Qϕ(zx(i)),于是就可以发现,其实我们就是在逼近这两者的分布。
于是我们得到了:
l o g P ( x ( i ) ) ≥ E L B o = E Q ϕ ( z ∣ x ( i ) ) [ l o g P θ ( x ( i ) , z ) − l o g Q ϕ ( z ∣ x ( i ) ) ] logP(x^{(i)})\ge ELBo = E_{Q_\phi(z|x^{(i)})}[logP_\theta(x^{(i)},z)-logQ_\phi(z|x^{(i)})] logP(x(i))ELBo=EQϕ(zx(i))[logPθ(x(i),z)logQϕ(zx(i))]
这是一个下界,显然如同EM一样,我们只需要提高这个下界就可以不断地扩大 l o g P ( x ( i ) ) logP(x^{(i)}) logP(x(i))还能同时把 Q ϕ ( z ∣ x ( i ) ) Q_\phi(z|x^{(i)}) Qϕ(zx(i))给解出来。

我们进一步的进行变形(一下X可以看做是 x ( i ) x^{(i)} x(i)):
E Q ϕ ( Z ∣ X ) [ l o g P θ ( X , Z ) − l o g Q ϕ ( Z ∣ X ) ] = E Q ϕ ( Z ∣ X ) [ l o g P θ ( X ∣ Z ) + l o g P θ ( Z ) − l o g Q ϕ ( Z ∣ X ) ] = E Q ϕ ( Z ∣ X ) [ l o g P θ ( X ∣ Z ) + l o g P θ ( Z ) Q ϕ ( Z ∣ X ) ] = E Q ϕ ( Z ∣ X ) [ l o g P θ ( X ∣ Z ) ] − K L ( Q ϕ ( Z ∣ X ) ∣ ∣ P θ ( Z ) ) E_{Q_\phi(Z|X)}[logP_\theta(X,Z)-logQ_\phi(Z|X)]=\\E_{Q_\phi(Z|X)}[logP_\theta(X|Z) + logP_\theta(Z)-logQ_\phi(Z|X)]=\\E_{Q_\phi(Z|X)}[logP_\theta(X|Z) + log\frac{P_\theta(Z)}{Q_\phi(Z|X)}]=\\E_{Q_\phi(Z|X)}[logP_\theta(X|Z)] -KL(Q_\phi(Z|X)||P_\theta(Z)) EQϕ(ZX)[logPθ(X,Z)logQϕ(ZX)]=EQϕ(ZX)[logPθ(XZ)+logPθ(Z)logQϕ(ZX)]=EQϕ(ZX)[logPθ(XZ)+logQϕ(ZX)Pθ(Z)]=EQϕ(ZX)[logPθ(XZ)]KL(Qϕ(ZX)∣∣Pθ(Z))
于是我们得到了最终的形式:
l o g P ( x ( i ) ) ≥ E Q ϕ ( z ∣ x ) [ l o g P θ ( x ( i ) ∣ z ) ] − K L ( Q ϕ ( z ∣ x ( i ) ) ∣ ∣ P θ ( z ) ) logP(x^{(i)})\ge E_{Q_\phi(z|x)}[logP_\theta(x^{(i)}|z)] -KL(Q_\phi(z|x^{(i)})||P_\theta(z)) logP(x(i))EQϕ(zx)[logPθ(x(i)z)]KL(Qϕ(zx(i))∣∣Pθ(z))
从上面我们可以看出一些有意思的事,我们期望最大化ELBo,也就是说我们要最小化 K L ( Q ϕ ( z ∣ x ( i ) ) ∣ ∣ P θ ( z ) ) KL(Q_\phi(z|x^{(i)})||P_\theta(z)) KL(Qϕ(zx(i))∣∣Pθ(z))

就是说让这两个分布尽可能的接近,也就是说这里其实 Q ϕ ( z ∣ x ( i ) ) Q_\phi(z|x^{(i)}) Qϕ(zx(i))近似了 P θ ( z ) P_\theta(z) Pθ(z)
这里可以看做一定encode的能力,给定数据X,然后生成隐变量的值Z。
然后另一部分可以看做要最大化给定Z时,还原出X的期望。也就是Decode的过程。

至此从优化的目标函数上来看,我们已经找到了Encoder和Decoder的两个相关优化目标。
到这里,为了优化这个目标,我们可以使用梯度上升的的方式,也就是对 ϕ \phi ϕ进行求导,然后再用蒙特卡洛采样得到梯度的近似值。

我们记
L ( θ , ϕ ; x ( i ) ) = E L B o = E Q ϕ ( z ∣ x ( i ) ) [ l o g P θ ( x ( i ) , z ) − l o g Q ϕ ( z ∣ x ( i ) ) ] L(\theta, \phi; x^{(i)})=ELBo=E_{Q_\phi(z|x^{(i)})}[logP_\theta(x^{(i)},z)-logQ_\phi(z|x^{(i)})] L(θ,ϕ;x(i))=ELBo=EQϕ(zx(i))[logPθ(x(i),z)logQϕ(zx(i))]
我们令 f ( z ) = l o g P θ ( x ( i ) , z ) − l o g Q ϕ ( z ∣ x ( i ) ) f(z)=logP_\theta(x^{(i)},z)-logQ_\phi(z|x^{(i)}) f(z)=logPθ(x(i),z)logQϕ(zx(i))
那么我们要求的梯度就是(以下 Q ϕ ( z ∣ x ( i ) ) Q_\phi(z|x^{(i)}) Qϕ(zx(i))记做 Q ϕ Q_\phi Qϕ)
∇ ϕ E Q ϕ [ f ( z ) ] = ∇ ϕ ∫ z Q ϕ f ( z ) d z = ∫ z ∇ ϕ Q ϕ f ( z ) d z = ∫ z f ( z ) Q ϕ ∇ Q ϕ l o g ( Q ϕ ) d z = E Q ϕ [ f ( z ) ∇ Q ϕ l o g ( Q ϕ ) ] \nabla_\phi E_{Q_\phi}[f(z)]=\nabla_\phi\int_zQ_\phi f(z) dz=\int_z\nabla_\phi Q_\phi f(z) dz \\=\int_zf(z)Q_\phi \nabla_{Q_\phi}log(Q_{\phi}) dz=E_{Q_\phi}[f(z)\nabla_{Q_\phi} log(Q_{\phi})] ϕEQϕ[f(z)]=ϕzQϕf(z)dz=zϕQϕf(z)dz=zf(z)QϕQϕlog(Qϕ)dz=EQϕ[f(z)Qϕlog(Qϕ)]
这里其实利用到了一个很有趣的性质 f ′ ( x ) = f ( x ) ∗ ( l o g f ( x ) ) ′ f'(x)=f(x)*(logf(x))' f(x)=f(x)(logf(x))于是把原本求的积分内的梯度再次变回了一个期望的形式。
而这个期望就可以使用蒙特卡洛的方式进行近似逼近了。

但是此时存在着一个问题
在这里插入图片描述
如图是VAE原论文中的蒙特卡洛近似后的结果,也就是用随机采样的得到的样本的计算后的均值近似原本的均值,这里存在着一个 z ( l ) z^{(l)} z(l),是从 Q ϕ ( z ∣ x ( i ) ) Q_{\phi}(z|x^{(i)}) Qϕ(zx(i))中抽样的,这个log就会造成很大的方差(因为越靠近0,就越陡峭)。

蒙特卡洛估计本身就是近似,方差又打再加上随机梯度下降的不确定性。所以导致很难进行优化。于是就引入了重参数技巧.

重参数

之所以出现了log,是因为对原本作为期望的分布 Q ϕ ( z ∣ x ( i ) ) Q_{\phi}(z|x^{(i)}) Qϕ(zx(i))进行了求导。于是坐着引入了一个新的变量 ϵ \epsilon ϵ,这个变量来与z产生关系:
z ~ ∼ g ϕ ( ϵ , x ( i ) ) ϵ ∼ p ( ϵ ) \tilde z\sim g_\phi(\epsilon,x^{(i)}) \\ \epsilon \sim p(\epsilon) z~gϕ(ϵ,x(i))ϵp(ϵ)
可以注意到:
∫ Q ϕ ( z ∣ x ) f ( z ) d z = ∫ p ( ϵ ) f ( z ) d ϵ = ∫ p ( ϵ ) f ( g ϕ ( ϵ , x ( i ) ) ) d ϵ \int Q_\phi (z|x) f(z) dz=\int p(\epsilon) f(z) d\epsilon=\int p(\epsilon) f(g_\phi(\epsilon,x^{(i)})) d\epsilon Qϕ(zx)f(z)dz=p(ϵ)f(z)dϵ=p(ϵ)f(gϕ(ϵ,x(i)))dϵ

此时我们就可以直接的估计出 E Q ϕ [ f ( z ) ] E_{Q_\phi}[f(z)] EQϕ[f(z)]
于是我们就得到:
E Q ϕ [ f ( z ) ] = E p ( ϵ ) [ f ( g ϕ ( ϵ , x ( i ) ) ) ] E_{Q_\phi}[f(z)]=E_{p(\epsilon)}[f(g_\phi(\epsilon,x^{(i)}))] EQϕ[f(z)]=Ep(ϵ)[f(gϕ(ϵ,x(i)))]
于是我们得到了一个估计值:
E p ( ϵ ) [ f ( g ϕ ( ϵ , x ( i ) ) ) ] ≈ 1 L ∑ i = 1 L f ( g ϕ ( ϵ ( i ) , x ( i ) ) ) 其中 ϵ i 采样于 p ( ϵ ) E_{p(\epsilon)}[f(g_\phi(\epsilon,x^{(i)}))]\approx \frac{1}{L}\sum_{i=1}^Lf(g_\phi(\epsilon^{(i)},x^{(i)}))\\其中\epsilon_i 采样于p(\epsilon) Ep(ϵ)[f(gϕ(ϵ,x(i)))]L1i=1Lf(gϕ(ϵ(i),x(i)))其中ϵi采样于p(ϵ)
然后我们重写L的式子:
L ( θ , ϕ ; x ( i ) ) = E L B o = E p ( ϵ ) [ l o g P θ ( x ( i ) , z ) − l o g Q ϕ ( z ∣ x ( i ) ) ] L(\theta, \phi; x^{(i)})=ELBo=E_{p(\epsilon)}[logP_\theta(x^{(i)},z)-logQ_\phi(z|x^{(i)})] L(θ,ϕ;x(i))=ELBo=Ep(ϵ)[logPθ(x(i),z)logQϕ(zx(i))]
= 1 L ∑ l = 1 L l o g P θ ( x ( i ) , g ϕ ( ϵ ( l ) , x ( i ) ) ) − l o g Q ϕ ( g ϕ ( ϵ ( l ) , x ( i ) ) ∣ x ( i ) ) 其中 ϵ i 采样于 p ( ϵ ) = \frac{1}{L}\sum_{l=1}^L logP_\theta(x^{(i)},g_\phi(\epsilon^{(l)},x^{(i)})) - logQ_\phi(g_\phi(\epsilon^{(l)},x^{(i)})|x^{(i)})\\其中\epsilon_i 采样于p(\epsilon) =L1l=1LlogPθ(x(i),gϕ(ϵ(l),x(i)))logQϕ(gϕ(ϵ(l),x(i))x(i))其中ϵi采样于p(ϵ)

由于KL散度经常可以直接被计算出来,所以我们也可以写成如下的式子:
= − K L ( Q ϕ ( z ∣ x ( i ) ) ∣ ∣ P θ ( z ) ) + 1 L ∑ l = 1 L l o g P θ ( x ( i ) ∣ g ϕ ( ϵ ( l ) , x ( i ) ) ) 其中 ϵ i 采样于 p ( ϵ ) = -KL(Q_\phi(z|x^{(i)})||P_\theta(z))+\frac{1}{L}\sum_{l=1}^L logP_\theta(x^{(i)}|g_\phi(\epsilon^{(l)},x^{(i)}))\\其中\epsilon_i 采样于p(\epsilon) =KL(Qϕ(zx(i))∣∣Pθ(z))+L1l=1LlogPθ(x(i)gϕ(ϵ(l),x(i)))其中ϵi采样于p(ϵ)
此时上述的式子就是近似可微的了,这个结果可以直接通过SGD求解。

VAE+神经网络

我们来举一个VAE+神经网络的例子,我们具体化上述抽象的分布和函数:

  1. g ϕ ( x ( i ) , ϵ ( l ) ) = μ ( i ) + σ ( i ) ⊙ ϵ ( l ) g_\phi(x^{(i)}, \epsilon^{(l)})=\mu^{(i)} + \sigma^{(i)}\odot \epsilon^{(l)} gϕ(x(i),ϵ(l))=μ(i)+σ(i)ϵ(l)
  2. ϵ ∼ N ( 0 , I ) \epsilon\sim N(0,I) ϵN(0,I)
  3. z ∼ N ( 0 , I ) z\sim N(0,I) zN(0,I)
  4. Q ϕ ( z ∣ x ( i ) ) = N ( Z ; μ ( i ) , σ 2 ( i ) I ) Q_\phi(z|x^{(i)})=N(Z;\mu^{(i)}, \sigma^{2(i)}I) Qϕ(zx(i))=N(Z;μ(i),σ2(i)I)
    上述的 μ ( i ) \mu^{(i)} μ(i) σ 2 ( i ) \sigma^{2(i)} σ2(i)都是由x得到的,也就是说我们需要训练一个encoder,来输入x获得上述两个部分:
    e n c o d e r ( x ( i ) ) = ( μ ( i ) , σ 2 ( i ) ) encoder(x^{(i)})=(\mu^{(i)}, \sigma^{2(i)}) encoder(x(i))=(μ(i),σ2(i))
    其中这个encoder就是一个神经网络。
    然后我们用另一个神经网络来拟合概率分布 p θ ( x ∣ z ) p_{\theta}(x|z) pθ(xz)
    于是就有了decoder。
    接下来我么们来计算损失函数:
    L ( θ , ϕ ; x ( i ) ) = − K L ( Q ϕ ( z ∣ x ( i ) ) ∣ ∣ P θ ( z ) ) + 1 L ∑ l = 1 L l o g P θ ( x ( i ) ∣ g ϕ ( ϵ ( l ) , x ( i ) ) ) 其中 ϵ i 采样于 p ( ϵ ) L(\theta, \phi; x^{(i)})= -KL(Q_\phi(z|x^{(i)})||P_\theta(z))+\frac{1}{L}\sum_{l=1}^L logP_\theta(x^{(i)}|g_\phi(\epsilon^{(l)},x^{(i)}))\\其中\epsilon_i 采样于p(\epsilon) L(θ,ϕ;x(i))=KL(Qϕ(zx(i))∣∣Pθ(z))+L1l=1LlogPθ(x(i)gϕ(ϵ(l),x(i)))其中ϵi采样于p(ϵ)

第二项变成:
1 L ∑ l = 1 L l o g P θ ( x ( i ) , g ϕ ( ϵ ( l ) , x ( i ) ) ) = 1 L ∑ l = 1 L l o g P θ ( x ( i ) ∣ μ ( i ) + σ ( i ) ⊙ ϵ ( l ) ) \frac{1}{L}\sum_{l=1}^L logP_\theta(x^{(i)},g_\phi(\epsilon^{(l)},x^{(i)}))=\frac{1}{L}\sum_{l=1}^L logP_\theta(x^{(i)}|\mu^{(i)} + \sigma^{(i)}\odot \epsilon^{(l)}) L1l=1LlogPθ(x(i),gϕ(ϵ(l),x(i)))=L1l=1LlogPθ(x(i)μ(i)+σ(i)ϵ(l))

而第一项KL散度通过积分可以得到:
(这里的具体推导可以看下面另一个视角的VAE那里)
在这里插入图片描述
其中J是 σ \sigma σ的维度。

然后就是decoder损失函数的选择:
如果是二值数据,那么此时可以使用n重伯努利分布:
P θ ( x ∣ z ) = ∏ k = 1 D p ( z ) k x k ( 1 − p ( z ) k ) ( 1 − x k ) P_\theta(x|z)=\prod\limits_{k=1}^D p(z)_k^{x_k}(1-p(z)_k)^{(1-x_k)} Pθ(xz)=k=1Dp(z)kxk(1p(z)k)(1xk)
− l o g P θ ( x ∣ z ) = ∑ k = 1 D − x k l o g p ( z ) k − ( 1 − x k ) l o g ( 1 − p ( z ) k ) -logP_\theta(x|z)=\sum\limits_{k=1}^D -x_klogp(z)_k-(1-x_k)log(1-p(z)_k) logPθ(xz)=k=1Dxklogp(z)k(1xk)log(1p(z)k)
可以看到这其实就是cross entropy。也就是交叉熵作为损失函数。

如果是一般的数据可以使用正态分布作为损失函数:
我们固定正态分布的sigma,就得到:
P θ ( x ∣ z ) = 1 C 1 e x p − C 2 ∣ ∣ x − μ ( z ) ∣ ∣ 2 P_\theta(x|z)=\frac{1}{C_1}exp^{-C_2||x-\mu(z)||^2} Pθ(xz)=C11expC2∣∣xμ(z)2
当方差固定时,正态分布的一些参数可以用两个常数 C 1 , C 2 C_1,C_2 C1,C2代替,如上图。然后取对数
− l o g P θ ( x ∣ z ) = − l o g ( 1 C 1 ) + C 2 ∣ ∣ x − μ ( z ) ∣ ∣ 2 ≈ ∣ ∣ x − μ ( z ) ∣ ∣ 2 -logP_\theta(x|z)=-log(\frac{1}{C_1}) + C_2||x-\mu(z)||^2 \approx||x-\mu(z)||^2 logPθ(xz)=log(C11)+C2∣∣xμ(z)2∣∣xμ(z)2
也就是说是MSE损失函数,其中 μ ( z ) \mu(z) μ(z)可以看作是decoder的输出。

然后是采样,由于有多个epoch,所以每次采样一个就够了。
接下来上代码:
我们用交叉熵做损失函数,同时使用Minist作为数据集训练

from torch import nn
import torch

class VAE(nn.Module):
    def __init__(self, image_size=28, z_dim=100) -> None:
        super().__init__()

        self.encoder = nn.Sequential( #由若干卷积和一个全连接构成encoder
            nn.Conv2d(in_channels=1, out_channels=20, kernel_size=3),
            nn.ReLU(),
            nn.Conv2d(in_channels=20, out_channels=20, kernel_size=3),
            nn.ReLU(),
            nn.Flatten(start_dim=1),
            nn.Linear(in_features=11520, out_features=800),
            nn.ReLU()
        )
        self.sigma = nn.Linear(800, z_dim)
        self.mu = nn.Linear(800, z_dim)
        self.sigmoid = nn.Sigmoid()

        self.decoder = nn.Sequential( # 两个全连接构成decoder
            nn.Linear(in_features=z_dim, out_features=2000),
            nn.ReLU(),
            nn.Linear(in_features=2000, out_features=image_size * image_size)
        )

    def reparameterize(self, sigma, mu): # 冲参数计算,计算z
        sigma = torch.exp(sigma / 2) # 这里sigma可能非正,所以加了exp,然后开根号
        eps = torch.rand_like(sigma) # 抽样得到epsilon
        return mu + eps * sigma

    def encode(self, x):
        hidden = self.encoder(x)
        sigma, mu = self.sigma(hidden), self.mu(hidden)
        return sigma, mu
    
    def decode(self, z):
        return self.decoder(z)
    
    def forward(self, x):
        sigma, mu = self.encode(x)
        z = self.reparameterize(sigma, mu)
        return sigma, mu, self.sigmoid(self.decode(z)) # 这里的sigmoid是为了计算交叉熵损失
    

def loss_function(sigma, mu, x, reconstruct):
    BCE_loss = nn.BCELoss(reduction='sum')
    kl_divergece = -0.5 * torch.sum(1 + sigma - torch.exp(sigma) - mu ** 2) # 这里的sigma本来应该是正的,所以用exp来代替了
    x = torch.flatten(x, start_dim=1)
    cross = BCE_loss(reconstruct, x) # 交叉熵部分
    return kl_divergece + cross

下面是训练的部分

from model import VAE, loss_function
import torch
import torchvision
from torch.utils.data import DataLoader
from torchvision.utils import save_image

if __name__ == '__main__':
    BATCH_SIZE = 150
    LR = 0.001
    EPOCH = 100

    model = VAE().cuda()
    optim = torch.optim.Adam(lr=LR, params=model.parameters())
    data = torchvision.datasets.MNIST('./data', train=True, transform=torchvision.transforms.ToTensor(), download=True)
    dataloader = DataLoader(dataset=data, batch_size=BATCH_SIZE, shuffle=True)

    for epoch in range(EPOCH):
        for i, (imgs, labels) in enumerate(dataloader):
            imgs = imgs.cuda()
            sigma, mu, recon = model(imgs)

            loss = loss_function(sigma, mu, imgs, recon)

            optim.zero_grad()
            loss.backward()
            optim.step()
            if i % 50 == 0:
                print('loss', loss.item())
                fake_images = recon.view(-1, 1, 28, 28)[:5]
                x_concat = torch.cat([imgs.view(-1, 1, 28, 28)[:5, :], fake_images], dim=3)
                save_image(x_concat, 'generate_images/generate_images-{}-{}.png'.format(epoch + 1, i))
        torch.save(model.state_dict(), './model.pkl')

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
图中是数字对,每一对左边是原图,右边是VAE重建后的图片。
到此,VAE结束

另一个视角的VAE

思想

上述是从贝叶斯视角来看VAE的,全部都是公式,非常的不直接,让扔一头雾水,下来来从更intuitive的角度来看VAE:
先来看,高斯混合模型,相当于是把若干个高斯模型迭代并分别乘以一个离散的概率分布的概率作为权重:
在这里插入图片描述
其中P(m)就是这个概率,也是上面所说的隐变量z。
然后直观地来看,我们把这个高斯混合模型给一般化,把P(m)编程高维分布,也变成连续的分布,就得到了VAE:
在这里插入图片描述
如图,此时的z就是个标准的高维的正态分布。

其中我们有一项 P ( x ∣ z ) P(x|z) P(xz)这个我们用神经网络去模拟:
在这里插入图片描述
输入一个z,输出均值和方差,他们都是z的函数。
理论上来说到这里看似很完美了,P(z)是标准正态分布是已知的,而且 P ( x ∣ z ) P(x|z) P(xz)可以通过神经网络训练得来。似乎所有问题都解决了。

为什么引入encoder

但是问题在于这没法实现,首先,我们的目标是最大化似然函数 P ( X ∣ θ ) P(X|\theta) P(Xθ),然后似然可以被拆做:
P θ ( X ) = ∫ z P θ ( Z ) P θ ( X ∣ Z ) d z P_\theta(X)=\int_z P_\theta(Z)P_\theta(X|Z) dz Pθ(X)=zPθ(Z)Pθ(XZ)dz
这个积分是无法积出来的,因为后项 P θ ( X ∣ Z ) P_\theta(X|Z) Pθ(XZ)是个神经网络。这样我们得不到损失函数。

另一个问题在于,P(z)与x是没有对应关系的,同一个P(z)抽出来的样本,可以对应相同的x。这可能会造成一系列麻烦:
于是VAE引入了另一个分布 Q ( z ∣ x ) Q(z|x) Q(zx)来取代原来的 P ( z ) P(z) P(z),这样解决了z没有指向性的问题。当然这个 Q ( z ∣ x ) Q(z|x) Q(zx)也是正态分布,我们也用一个神经网络去模拟:
在这里插入图片描述
输入一个x,同样的输出两个参数作为输出结果。

这样似乎我们的问题就解决了,但仍然存在问题:
在这里插入图片描述
如上图(来自于苏剑林的博客),是我们的步骤,这里有一个大问题那就是我们希望采样得到的z是的不确定性是由神经网络自己生成的(也就是方差sigma)。

也就是说神经网络完全可以偷懒,让这个方差直接为0,然后我们希望引入的采样的随机性就没了。于是我们引入了正则项,来要求 Q ( z ∣ x ) Q(z|x) Q(zx)朝着标准正态分布的方向逼近,也就是我们之前假设的先验分布P(z):
下面 z k z_k zk表示z的第k个纬度, x ( i ) x^{(i)} x(i)表示第i个样本

也就是 min ⁡ K L ( N ( μ ( x ( i ) ) , σ ( x ( i ) ) ) ∣ ∣ N ( 0 , I ) ) = ∫ z N ( μ ( x ( i ) ) , σ ( x ( i ) ) ) l n N ( μ ( x ( i ) ) , σ ( x ( i ) ) ) N ( 0 , I ) d z \min KL(N(\mu(x^{(i)}), \sigma(x^{(i)}))||N(0,I))=\int_zN(\mu(x^{(i)}), \sigma(x^{(i)}))ln\frac{N(\mu(x^{(i)}), \sigma(x^{(i)}))}{N(0,I)}dz minKL(N(μ(x(i)),σ(x(i)))∣∣N(0,I))=zN(μ(x(i)),σ(x(i)))lnN(0,I)N(μ(x(i)),σ(x(i)))dz
我们假设各个分量之间是独立的,于是我们只用计算出第k维度即可
∫ − ∞ + ∞ 1 2 π σ k 2 ( x ( i ) ) e − ( z k − μ k ( x ( i ) ) ) 2 2 σ k ( x ( i ) ) 2 l n 1 2 π σ k 2 ( x ( i ) ) e − ( z k − μ k ( x ( i ) ) ) 2 2 σ k ( x ( i ) ) 2 1 2 π e − z k 2 2 d z k \int_{-\infin} ^{+\infin} \frac{1}{\sqrt{2\pi \sigma^2_k(x^{(i)})}}e^{-\frac{(z_k - \mu_k(x^{(i)}))^2}{2\sigma_k(x^{(i)})^2}} ln\frac{\frac{1}{\sqrt{2\pi \sigma^2_k(x^{(i)})}}e^{-\frac{(z_k - \mu_k(x^{(i)}))^2}{2\sigma_k(x^{(i)})^2}}}{\frac{1}{\sqrt{2\pi }}e^{-\frac{z_k^2}{2}}}dz_k +2πσk2(x(i)) 1e2σk(x(i))2(zkμk(x(i)))2ln2π 1e2zk22πσk2(x(i)) 1e2σk(x(i))2(zkμk(x(i)))2dzk
我们把后项进行化简:
= 1 2 ∫ − ∞ + ∞ 1 2 π σ k 2 ( x ( i ) ) e − ( z k − μ k ( x ( i ) ) ) 2 2 σ k ( x ( i ) ) 2 ( − l n σ k 2 ( x ( i ) ) ) + z k 2 − ( z k − μ k ( x ( i ) ) ) 2 σ k ( x ( i ) ) 2 ) d z k =\frac{1}{2}\int_{-\infin} ^{+\infin} \frac{1}{\sqrt{2\pi \sigma^2_k(x^{(i)})}}e^{-\frac{(z_k - \mu_k(x^{(i)}))^2}{2\sigma_k(x^{(i)})^2}}(-ln\sigma^2_k(x^{(i)}))+z_k^2 -\frac{(z_k - \mu_k(x^{(i)}))^2}{\sigma_k(x^{(i)})^2})dz_k =21+2πσk2(x(i)) 1e2σk(x(i))2(zkμk(x(i)))2(lnσk2(x(i)))+zk2σk(x(i))2(zkμk(x(i)))2)dzk
可以看到后面有三项需要分别和第一项相乘然后积分:
首先是:
− 1 2 ∫ − ∞ + ∞ 1 2 π σ k 2 ( x ( i ) ) e − ( z k − μ k ( x ( i ) ) ) 2 2 σ k ( x ( i ) ) 2 l n σ k 2 ( x ( i ) ) ) d z k = − 1 2 l n σ k 2 ( x ( i ) ) -\frac{1}{2}\int_{-\infin} ^{+\infin} \frac{1}{\sqrt{2\pi \sigma^2_k(x^{(i)})}}e^{-\frac{(z_k - \mu_k(x^{(i)}))^2}{2\sigma_k(x^{(i)})^2}}ln\sigma^2_k(x^{(i)}))dz_k =-\frac{1}{2}ln\sigma^2_k(x^{(i)}) 21+2πσk2(x(i)) 1e2σk(x(i))2(zkμk(x(i)))2lnσk2(x(i)))dzk=21lnσk2(x(i))
因为上述的积分就是个概率分布的积分,最后结果为1, − 1 2 l n σ k 2 ( x ( i ) ) -\frac{1}{2}ln\sigma^2_k(x^{(i)}) 21lnσk2(x(i))与x无关
1 2 ∫ − ∞ + ∞ 1 2 π σ k 2 ( x ( i ) ) e − ( z k − μ k ( x ( i ) ) ) 2 2 σ k ( x ( i ) ) 2 z k 2 d z k \frac{1}{2}\int_{-\infin} ^{+\infin} \frac{1}{\sqrt{2\pi \sigma^2_k(x^{(i)})}}e^{-\frac{(z_k - \mu_k(x^{(i)}))^2}{2\sigma_k(x^{(i)})^2}}z_k^2 dz_k 21+2πσk2(x(i)) 1e2σk(x(i))2(zkμk(x(i)))2zk2dzk
这就是二阶中心距:
μ ( x ( i ) ) 2 + σ ( x ( i ) ) 2 \mu(x^{(i)})^2+\sigma(x^{(i)})^2 μ(x(i))2+σ(x(i))2
最后一项,展开之后得到:
( z k − μ k ( x ( i ) ) ) 2 σ k ( x ( i ) ) 2 = ( z k 2 − 2 z k μ k ( x ( i ) ) + μ k ( x ( i ) ) ) σ k ( x ( i ) ) 2 \frac{(z_k - \mu_k(x^{(i)}))^2}{\sigma_k(x^{(i)})^2}=\frac{(z_k^2 -2z_k\mu_k(x^{(i)}) + \mu_k(x^{(i)}))}{\sigma_k(x^{(i)})^2} σk(x(i))2(zkμk(x(i)))2=σk(x(i))2(zk22zkμk(x(i))+μk(x(i)))
中间和前面相乘后积分直接为0,前面和后面也可以用二阶中心距和概率分布的定义直接计算
最后得到结果为-1
于是
∫ − ∞ + ∞ 1 2 π σ k 2 ( x ( i ) ) e − ( z k − μ k ( x ( i ) ) ) 2 2 σ k ( x ( i ) ) 2 l n 1 2 π σ k 2 ( x ( i ) ) e − ( z k − μ k ( x ( i ) ) ) 2 2 σ k ( x ( i ) ) 2 1 2 π e − z k 2 2 d z k = 1 2 ( − l n σ k 2 ( x ( i ) ) + μ ( x ( i ) ) 2 + σ ( x ( i ) ) 2 − 1 ) \int_{-\infin} ^{+\infin} \frac{1}{\sqrt{2\pi \sigma^2_k(x^{(i)})}}e^{-\frac{(z_k - \mu_k(x^{(i)}))^2}{2\sigma_k(x^{(i)})^2}} ln\frac{\frac{1}{\sqrt{2\pi \sigma^2_k(x^{(i)})}}e^{-\frac{(z_k - \mu_k(x^{(i)}))^2}{2\sigma_k(x^{(i)})^2}}}{\frac{1}{\sqrt{2\pi }}e^{-\frac{z_k^2}{2}}}dz_k=\frac{1}{2}(-ln\sigma^2_k(x^{(i)})+\mu(x^{(i)})^2+\sigma(x^{(i)})^2-1) +2πσk2(x(i)) 1e2σk(x(i))2(zkμk(x(i)))2ln2π 1e2zk22πσk2(x(i)) 1e2σk(x(i))2(zkμk(x(i)))2dzk=21(lnσk2(x(i))+μ(x(i))2+σ(x(i))21)
在这里插入图片描述

为什么要重参数

然后是采样操作,实际上采样操作是不可行的,因为采样出来的值没法后续用X来进行优化(因为前半部分的encoder只有一个KL损失在约束,不受到后面的decoder的梯度传播)

所以必须要引入一个新变量来把采样过程的随机性独立出来,这就是重参数技巧
P ( z ∣ x ) = 1 σ ( x ( i ) ) 2 π e − ( x − μ ( x ( i ) ) ) 2 2 σ ( x ( i ) ) 2 ∼ N ( μ ( x ( i ) ) , σ ( x ( i ) ) 2 ) P(z|x)=\frac{1}{\sigma(x^{(i)})\sqrt{2\pi}}e^{-\frac{(x-\mu(x^{(i)}))^2}{2\sigma(x^{(i)})^2}}\sim N(\mu(x^{(i)}), \sigma(x^{(i)})^2) P(zx)=σ(x(i))2π 1e2σ(x(i))2(xμ(x(i)))2N(μ(x(i)),σ(x(i))2)
我们引入另一个标准正态分布
ϵ ∼ N ( 0 , I ) \epsilon \sim N(0,I) ϵN(0,I)
可知
ϵ ∗ μ ( x ( i ) ) + σ ( x ( i ) ) ∼ N ( μ ( x ( i ) ) , σ ( x ( i ) ) 2 ) \epsilon * \mu(x^{(i)}) + \sigma(x^{(i)}) \sim N(\mu(x^{(i)}), \sigma(x^{(i)})^2) ϵμ(x(i))+σ(x(i))N(μ(x(i)),σ(x(i))2)
也就是说我们可以用这个 ϵ \epsilon ϵ对一个与神经网络无关的标准正态分布采样,然后通过如下公式在转换为z
ϵ ∗ μ ( x ( i ) ) + σ ( x ( i ) ) = z \epsilon * \mu(x^{(i)}) + \sigma(x^{(i)}) =z ϵμ(x(i))+σ(x(i))=z
这就是重参数技巧的实质。

噪声与重建

VAE的KL损失及部分实际上是一个正则化部分,它让模型尽可能的保持一定的噪声。而VAE的重建损失(Reconstruct Loss)则是尽可能的去在有噪声的情况下回复原图。这实际上是一个对抗的过程。
在这里插入图片描述
从另一个角度来看,VAE其实也是在希望模型能够不在一个点上学到会付出这个输出,而是在一个范围之类(噪声的影响范围)之内恢复出一个数据
在这里插入图片描述

Discrete VAE

以后再写吧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1084144.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

博华网龙设备命令执行漏洞复现 [附POC]

文章目录 博华网龙设备命令执行漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 博华网龙设备命令执行漏洞复现 [附POC] 0x01 前言 免责声明:请勿利用文章内的相关技术从事非法测试&…

【Vue】之Vuex的入门使用,取值,修改值,同异步请求处理---保姆级别教学

一,Vuex入门 1.1 什么是Vuex Vuex是一个专门为Vue.js应用程序开发的状态管理库。它用于管理应用程序中的共享状态,它采用集中式存储管理应用的所有组件的状态,使得状态的管理变得简单和可预测 官方解释:Vuex 是一个专为 Vue.js 应…

Python数据分析实战-实现Kruskal-Wallis H检验(附源码和实现效果)

实现功能 当需要比较多个(大于两个)独立样本之间的差异时,可以使用非参数的Kruskal-Wallis H检验。Kruskal-Wallis H检验是一种非参数的方差分析方法,用于检验多个独立样本是否来自于相同的总体分布。 在Python中,你…

英国生物技术公司【AstronauTx】完成4800万英镑A轮融资

来源:猛兽财经 作者:猛兽财经 猛兽财经获悉,总部位于英国伦敦的生物技术公司【AstronauTx】今日宣布已完成4800万英镑A轮融资 。 本轮融资由诺华风险基金领投,布兰登资本(Brandon Capital)、MPM Capital、…

产品经理视角 | API接口知识小结

应用程序接口API(Application Programming Interface),是提供特定业务输出能力、连接不同系统的一种约定。这里包括外部系统与提供服务的系统(中后台系统)或后台不同系统之间的交互点。包括外部接口、内部接口&#xf…

下一代Docker来了,会让部署更加丝滑吗?

下一代Docker来了,会让部署更加丝滑吗? 目录 一、Docker是什么? 二、Docker 的几个名词概念 2.1、镜像(Image) 2.2、容器 (Container) 2.3、仓库 (Repository) 三、容器和虚拟机比较 四、Docker 运行环境 五、…

因子分析(SPSS和Python)

一、源数据 二、SPSS因子分析 2.1.导入数据 2.2.标准化处理 由于指标的量纲不同(单位不一致),因此,需要对数据进行标准化处理 2.3.因子分析 点击“确定”后,再回到“总方差解释”表格,以“旋转载荷平方和…

Java 基于SpringBoot的某家乡美食系统

1 简介 《Java 基于SpringBoot的某家乡美食系统》该项目含有源码、文档等资料、配套开发软件、软件安装教程等。系统功能完整,适合作为毕业设计、课程设计、数据库大作业学习使用。 功能介绍 这个项目是基于 SpringBoot和 Vue 开发的地方美食系统,包括…

STM32F4X I2C LM75

STM32F4X I2C LM75 I2C协议讲解I2C接线I2C协议波形I2C起始信号I2C停止信号I2C应答信号I2C寻址I2C地址格式 I2C数据传输 LM75ALM75A介绍LM75A引脚说明LM75A地址LM75A寄存器LM75A I2C协议写配置寄存器读配置寄存器写Tos和Thyst寄存器读Tos Thyst Temp寄存器LM75A温度计算 LM75A例…

帆软报表之填报报表

1、配置数据源 URL填充格式:jdbc:mysql://127.0.0.1:3306/yq_iwater_ads 2、新建普通报表,配置数据库查询 3、编辑单元格 3.1、插入公式 ‘每月营业厅情况统计\n’ replace($month_id,‘-’,‘年’)‘月’ 3.2、插入数据列 3.3、关联数据列 3.4、隐藏不…

【java学习】面向对象特征之一:封装和隐藏(23)

文章目录 信息的封装和隐藏 信息的封装和隐藏 Java 中通过将数据声明为私有的 (private) 变量, 再提供 公共的( public )方法 :getXxx() 和 setXxx() 实现对该属性的操作,以实现下述目的: 隐藏一个类中不需…

LeetCode【100】单词拆分

题目&#xff1a; 代码&#xff1a; public boolean wordBreak(String s, List<String> wordDict) {Set<String> dictSet new HashSet<>(wordDict);boolean[] dp new boolean[s.length() 1]; // dp问题均是&#xff0c;先构造dp数组&#xff0c;大小为…

vue实现搜索文字高亮功能

在前端开发中&#xff0c;要实现文字搜索高亮效果&#xff0c;你可以使用JavaScript来搜索文本并通过CSS或其他方式对匹配的文本进行高亮处理。以下是一种常见的方法&#xff1a; 实现步骤&#xff1a; 1、 获取用户输入的搜索词。 2、创建一个正则表达式&#xff0c;以全局&am…

分享一下微信付费文章功能怎么做

微信付费文章功能是一种基于微信公众号的文章付费阅读模式&#xff0c;它可以帮助公众号运营者实现文章内容的变现&#xff0c;提高文章的阅读量和收益。本文将介绍微信付费文章功能的制作流程、功能特点、使用流程和推广策略&#xff0c;帮助读者了解如何制作一个高效的微信付…

嵌入式C语言自我修养《内存堆栈管理》学习笔记

目录 一、Linux环境下的内存管理 二、栈的管理 三、堆内存管理 四、mmap映射区 五、内存泄漏与防范 六、常见的内存错误及检测 C程序中定义的函数、全局变量、静态变量经过编译链接后&#xff0c;分别以section的形式存储在可执行文件的代码段、数据段和BSS段中。当程序运…

vue 本地上传Excel文件并读取内容

陌路遇见&#xff0c;陌路告别&#xff0c;陌路问好&#xff0c;九月再见&#xff0c;十月重现! 首先我来讲解一下我的思路&#xff1a; 首先&#xff0c;在模板部分&#xff0c;我们有以下元素&#xff1a; <input type“file” change“handleFileUpload” accept“.xlsx…

哈希应用之布隆过滤器

文章目录 1.介绍1.1百度搜索1.2知乎好文1.3自身理解 2.模拟实现2.1文档阅读2.2代码剖析 3.误判率的研究4.布隆过滤器的应用4.1如何找到两个分别有100亿个字符串的文件的交集[只有1G内存].分别给出精确算法和近似算法4.2如何扩展BloomFilter使得它支持删除元素的操作 5.整体代码…

第十章 字符串和日期

1.字符串 1.1.String 1.1.1.String特性 代表字符串。Java 程序中的所有字符串字面值&#xff08;如 "abc" &#xff09;都作为此类的实例实现&#xff1b;String是一个final类&#xff0c;代表不可变的字符序列,不可被继承&#xff1b;字符串是常量&#xff0c;用&…

高级网络调试技巧:使用Charles Proxy捕获和修改HTTP/HTTPS请求

今天我将与大家分享一种强大的网络调试技巧&#xff0c;那就是使用Charles Proxy来捕获和修改HTTP/HTTPS请求。如果您是一位开发人员或者网络调试爱好者&#xff0c;那么这个工具肯定对您有着很大的帮助。接下来&#xff0c;让我们一起来学习如何使用Charles Proxy进行高级网络…

1200*C1. k-LCM (easy version)(找规律)

Problem - 1497C1 - Codeforces 解析&#xff1a; 找规律即可&#xff0c;分为偶数的一半是偶数、偶数的一半是奇数、奇数三种情况 分别为 &#xff08;n/2&#xff0c;n/4&#xff0c;n/4&#xff09;&#xff08;n/2-1&#xff0c;n/2-1&#xff0c;2&#xff09;&#xff08…