参考:Probabilistic Diffusion Model概率扩散模型理论与完整PyTorch代码详细解读
由浅入深了解Diffusion Model
在上节我们了解了VAE的原理,总体来说可以分为两个过程,一个是使用 q ( z ∣ x ) q(z|x) q(z∣x)给Encoder进行前向学习的过程,另一个是使用 p ( x ∣ z ) p(x|z) p(x∣z)给Decoder进行逆向推理的过程。
多层VAE模型和单层VAE实际上是类似的,只不过在单层基础上,我们将其视为一个马尔科夫链,因此每一个概率只与前一个概率有关,
上面是我们利用詹森不等式得到的置信下界。
上面是概率的链式法则(马尔科夫链下的),我们把这个代入上面的最大似然,可以得到下界可以写为这种形式:
这就是多层VAE的目标函数。
之所以要先介绍VAE,是因为实际上多层VAE的过程和Diffusion Model很像。
Diffusion Model的原理是先对目标 x 0 x_0 x0逐步正向加噪得到最终的分布 x T x_T xT,然后再用逆向推理的过程逐步去噪,由 x T x_T xT得到 x 0 x_0 x0。
上图就是Diffusion Model的可视化过程,总的来说就是加噪的扩散过程(熵增过程) q ( x t ∣ x t − 1 ) q(x_t|x_{t-1}) q(xt∣xt−1),也就是上图第一行,我们可以看到随着加噪图像逐渐变得无序。
而对于一张给定的噪声图片 x T x_T xT,Diffusion Model在学习了去噪的逆向推理过程 p ( x t − 1 ∣ x t ) p(x_{t-1}|x_t) p(xt−1∣xt)后,就可以产生一个新的图片,也就是上图的第二行,(从T时刻到0时刻)可以看到我们生产了新的样本,它和原来我们用于加噪的训练图片大致是相似的。
第三行是漂移量,从中我们可以看到上一时刻和下一时刻的图像像素运动方向。
1.给定初始数据分布 x 0 ∼ q ( x ) x_0 \sim q(x) x0∼q(x),可以不断地向原始分布中添加高斯噪声(仿射变换),该噪声的标准差是以固定值 β t \beta_t βt确定的,均值(期望)以固定值 β t \beta_t βt和当前 t t t时刻的数据 x t x_t xt决定。这个过程是一个马尔科夫链。
2.随着 t t t的不断增大,最终的数据分布 x T x_T xT就变成了一个各向独立的高斯分布
关于 x t x_t xt服从的高斯分布的算法,其实就是我们上节讲过的重采样技巧,我们从正态分布中取样一个 z z z,然后计算 x = σ z + μ x=\sigma z+\mu x=σz+μ得到 x x x的采样值。利用重采样技巧对 x t − 1 x_{t-1} xt−1迭代就能求得 x t x_t xt的高斯分布。并且 q ( x t ∣ x 0 ) q(x_t|x_0) q(xt∣x0)满足马尔科夫链。
注意: β t ∈ ( 0 , 1 ) \beta_t \in (0,1) βt∈(0,1),并且随着时间推移会越来越大。
3.任意时刻的 q ( x t ) q(x_t) q(xt)推导也可以完全基于 x 0 x_0 x0和 β t \beta_t βt来计算,而不需要迭代,下面是计算过程:
这里我们需要用到参数重整化技巧,我们令 α t = 1 − β t , α ‾ t = ∏ t = 1 T α i \alpha_t=1-\beta_t,\overline \alpha_t=\displaystyle\prod^{T}_{t=1} \alpha_i αt=1−βt,αt=t=1∏Tαi,接下来将上式 q ( x t ∣ x t − 1 ) q(x_t|x_{t-1}) q(xt∣xt−1)代入重采样技巧 x t = σ z t − 1 + μ = β z t − 1 + 1 − β x t − 1 x_t=\sigma z_{t-1}+\mu=\sqrt{\beta}z_{t-1}+\sqrt{1-\beta}x_{t-1} xt=σzt−1+μ=βzt−1+1−βxt−1得到:
x t = α t x t − 1 + 1 − α t z t − 1 z t − 1 , z t − 2 均 . . . ∼ N ( 0 , I ) x_t=\sqrt{\alpha_t}x_{t-1}+\sqrt{1-\alpha_t}z_{t-1} ~~~~~z_{t-1},z_{t-2}均...\sim N(0,I) xt=αtxt−1+1−αtzt−1 zt−1,zt−2均...∼N(0,I)
我们将上式中的 x t − 1 x_{t-1} xt−1用关于 x t − 2 x_{t-2} xt−2的式子替换:
x t = α t ( α t − 1 x t − 2 + 1 − α t − 1 z t − 2 ) + 1 − α t z t − 1 = α t α t − 1 x t − 2 + α t − α t α t − 1 z t − 2 + 1 − α t z t − 1 x_t=\sqrt{\alpha_t}(\sqrt{\alpha_{t-1}}x_{t-2}+\sqrt{1-\alpha_{t-1}}z_{t-2})+\sqrt{1-\alpha_t}z_{t-1}\\ =\sqrt{\alpha_t \alpha_{t-1}}x_{t-2}+\sqrt{\alpha_t-\alpha_t\alpha_{t-1}}z_{t-2}+\sqrt{1-\alpha_t}z_{t-1} xt=αt(αt−1xt−2+1−αt−1zt−2)+1−αtzt−1=αtαt−1xt−2+αt−αtαt−1zt−2+1−αtzt−1
给出一个基本结论(独立分布可加性):两个正态分布 X ∼ N ( μ 1 , σ 1 2 ) 和 Y ∼ N ( μ 2 , σ 2 2 ) X \sim N(\mu_1,\sigma_1^2)和Y \sim N(\mu_2,\sigma_2^2) X∼N(μ1,σ12)和Y∼N(μ2,σ22)得到的叠加分布 a X + b Y aX+bY aX+bY的均值为 a μ 1 + b μ 2 a\mu_1+b\mu_2 aμ1+bμ2,方差为 a 2 σ 1 2 + b 2 σ 2 2 a^2\sigma_1^2+b^2\sigma_2^2 a2σ12+b2σ22,所以 α t − α t α t − 1 z t − 2 + 1 − α t z t − 1 \sqrt{\alpha_t-\alpha_t\alpha_{t-1}}z_{t-2}+\sqrt{1-\alpha_t}z_{t-1} αt−αtαt−1zt−2+1−αtzt−1由于 z ∼ N ( 0 , I ) z \sim N(0,I) z∼N(0,I),所以对应的叠加分布均值就是 μ = 0 + 0 = 0 \mu=0+0=0 μ=0+0=0,方差 σ 2 = a 2 + b 2 = α t − α t α t − 1 + 1 − α t = 1 − α t α t − 1 , \sigma^2=a^2+b^2=\alpha_t-\alpha_t\alpha_{t-1}+1-\alpha_t=1-\alpha_t\alpha_{t-1}, σ2=a2+b2=αt−αtαt−1+1−αt=1−αtαt−1,因此代入重采样公式即为 σ z + μ = 1 − α t α t − 1 z {\sigma}z+\mu=\sqrt{1-\alpha_t\alpha_{t-1}}z σz+μ=1−αtαt−1z
x t = α t α t − 1 x t − 2 + 1 − α t α t − 1 z ‾ t − 2 ( z ‾ t − 2 是混合高斯,但仍是标准正态分布 ) = . . . = α ‾ t x 0 + 1 − α ‾ t z x_t=\sqrt{\alpha_t \alpha_{t-1}}x_{t-2}+\sqrt{1-\alpha_t\alpha_{t-1}}\overline z_{t-2}~~(\overline z_{t-2}是混合高斯,但仍是标准正态分布)\\ =...\\ =\sqrt{\overline\alpha_t}x_0+\sqrt{1-\overline\alpha_t}z xt=αtαt−1xt−2+1−αtαt−1zt−2 (zt−2是混合高斯,但仍是标准正态分布)=...=αtx0+1−αtz
结论:
x t = α ‾ t x 0 + 1 − α ‾ t z ( 3 ) x_t=\sqrt{\overline\alpha_t}x_0+\sqrt{1-\overline\alpha_t}z~~~~~(3) xt=αtx0+1−αtz (3)
因此任意时刻的 q ( x t ) q(x_t) q(xt)都可以基于 x 0 x_0 x0和 β t \beta_t βt来计算而不需要迭代:
q ( x t ∣ x 0 ) = N ( x t ; α ‾ t x 0 , ( 1 − α ‾ t ) I ) q(x_t|x_0)=N(x_t;\sqrt{\overline\alpha_t}x_0,({1-\overline\alpha_t})I) q(xt∣x0)=N(xt;αtx0,(1−αt)I),这样我们就能以这个高斯分布采样出 x t x_t xt而不需要t次迭代了。
所以 α \alpha α更像是类似学习率的参数,因为 β \beta β会越来越大,所以 α \alpha α会越来越小,因此足够多的时刻之后 α → 0 , 1 − α → 1 \sqrt{\alpha} \to 0,\sqrt{1-\alpha} \to 1 α→0,1−α→1,因此当到达 t 时刻, q ( x t ∣ x 0 ) = N ( x t ; 0 , I ) q(x_t|x_0)=N(x_t;0,I) q(xt∣x0)=N(xt;0,I)会收敛于一个标准的正态分布,这样我们就能求出这个最大的时刻 t t t 了。从学习率上表现的性质就是如果用 x t x_t xt预测 x 0 x_0 x0,前面阶段的生成会很快显示出图像的底样,而越往后越慢,越是需要生成更多的细节。
(上图表示了 α ˉ t \bar \alpha_t αˉt和扩散步骤的关系)
从这里我们可以看到Diffusion Model 和VAE的一些区别,
首先在VAE中参数是通过前向逆向过程预测出来的,但diffusion里是给出一个固定参数后进行训练。
其次在VAE中采样的隐变量 z z z和 x x x是有一定关联的,而diffusion中的 x t x_t xt最终是一个标准正态分布,和 x x x无关了。
此外在VAE中 x x x和 z z z的维度不一定一样,而diffusion中 x 0 . . . . x t x_0....x_t x0....xt的维度始终是一样的。
如果说前向过程是一个加噪的过程,那么逆向过程就说去噪推断的过程,如果我们能够逐步得到逆转后的分布 q ( x t − 1 ∣ x t ) q(x_{t-1}|x_t) q(xt−1∣xt),就可以从标准正态分布 x t ∼ N ( 0 , I ) x_t \sim N(0,I) xt∼N(0,I)还原出原图分布 x 0 x_0 x0,文献1中证明了如果 q ( x t − 1 ∣ x t ) q(x_{t-1}|x_t) q(xt−1∣xt)满足高斯分布且 β t \beta_t βt足够小,那么 q ( x t − 1 ∣ x t ) q(x_{t-1}|x_t) q(xt−1∣xt)仍然是高斯分布,如果逐步地对 x t . . . x 0 x_t...x_0 xt...x0进行拟合来找到其服从的高斯分布参数,实在难以计算。所以我们需要构建一个参数分布来去做估计,逆向扩散过程仍然是一个马尔科夫链。
我们使用深度学习模型(参数为 θ \theta θ,目前主流是U-Net+attention的结构)去预测这样的一个逆向的分布 p θ p_\theta pθ。(类似VAE):
虽然我们无法得到逆转后的分布 q ( x t − 1 ∣ x t ) q(x_{t-1}|x_t) q(xt−1∣xt),但是如果我们知道 x 0 x_0 x0,可以通过以下的公式进行计算:
q ( x t − 1 ∣ x t , x 0 ) = N ( x t − 1 ; μ ~ ( x t , x 0 ) , β ~ t I ) ( 6 ) q(x_{t-1}|x_t,x_0)=N(x_{t-1};\tilde\mu(x_t,x_0),\tilde\beta_tI)~~~~(6) q(xt−1∣xt,x0)=N(xt−1;μ~(xt,x0),β~tI) (6)
推理如下:
我们用贝叶斯公式推理下(7-1):
q ( a ∣ b , c ) = q ( a , b , c ) q ( b , c ) q(a|b,c)=\frac{q(a,b,c)}{q(b,c)} q(a∣b,c)=q(b,c)q(a,b,c)
其中链式法则 q ( a , b , c ) = q ( b ∣ a , c ) q ( a ∣ c ) q ( c ) q(a,b,c)=q(b|a,c)q(a|c)q(c) q(a,b,c)=q(b∣a,c)q(a∣c)q(c), q ( b , c ) = q ( b ∣ c ) q ( c ) q(b,c)=q(b|c)q(c) q(b,c)=q(b∣c)q(c)
因此代入原式 = q ( b ∣ a , c ) q ( a ∣ c ) q ( c ) q ( b ∣ c ) q ( c ) = q ( b ∣ a , c ) q ( a ∣ c ) q ( b ∣ c ) =\frac{q(b|a,c)q(a|c)q(c)}{q(b|c)q(c)}=\frac{q(b|a,c)q(a|c)}{q(b|c)} =q(b∣c)q(c)q(b∣a,c)q(a∣c)q(c)=q(b∣c)q(b∣a,c)q(a∣c),由于是马尔科夫链,上式还等价于 q ( b ∣ c ) q ( a ∣ c ) q ( b ∣ c ) q(b|c)\frac{q(a|c)}{q(b|c)} q(b∣c)q(b∣c)q(a∣c)
我们可以看到在(7-1)式子中,我们使用贝叶斯公式,将这个逆向过程转化为了前向过程,(7-2)为其对应的高斯分布概率密度函数。我们将其展开得到式子(7-3),其中与 x t − 1 x_{t-1} xt−1无关的项例如只包含了 x t & x 0 x_t \& x_0 xt&x0的项都被归入了 C ( x t , x 0 ) C(x_t,x_0) C(xt,x0)
(高斯分布的概率密度函数是 f ( x ) = 1 2 π σ e − ( x − μ ) 2 2 σ 2 f(x)=\frac{1}{\sqrt{2\pi}\sigma}e^{-\frac{(x-\mu)^2}{2\sigma^2}} f(x)=2πσ1e−2σ2(x−μ)2)
我们之前说过 q ( x t − 1 ∣ x t ) q(x_{t-1}|x_t) q(xt−1∣xt)仍然是高斯分布,也就意味着上式可以被整理为高斯分布的式子,对应的一般高斯概率密度函数的指数部分为 e x p ( − ( x − μ ) 2 2 σ 2 ) = e x p ( − 1 2 ( 1 σ 2 x 2 − 2 μ σ 2 x + μ 2 σ 2 ) ) exp(-\frac{(x-\mu)^2}{2\sigma^2})=exp(-\frac{1}{2}(\frac{1}{\sigma^2}x^2-\frac{2\mu}{\sigma^2}x+\frac{\mu^2}{\sigma^2})) exp(−2σ2(x−μ)2)=exp(−21(σ21x2−σ22μx+σ2μ2)),和(7-3)整理出来的形式是对应的,因此:
用前向时讲到的 β \beta β代替方差 σ 2 \sigma^2 σ2,得到:
由于扩散过程讲过的推断3,我们得知任意时刻的 x t x_t xt可以由 x 0 x_0 x0和 β \beta β表示。因此:
x 0 = 1 α ˉ t ( x t − β t 1 − α ˉ t z ˉ t ) x_0=\frac{1}{\sqrt{\bar\alpha_t}}(x_t-\frac{\beta_t}{\sqrt{1-\bar\alpha_t}}\bar z_t)~~~ x0=αˉt1(xt−1−αˉtβtzˉt) ( x t x_t xt式子变形)
将其代入到(8-2)得到
其中的高斯分布 z ˉ t \bar z_t zˉt为深度模型所预测的噪声(用于去噪),可看做为 z θ ( x t , t ) , z_\theta(x_t,t), zθ(xt,t),得到:
我们经过了一连串的计算,先得到 q ( x t − 1 ∣ x t ) q(x_{t-1}|x_t) q(xt−1∣xt)的高斯分布概率密度函数,然后将其整理为高斯分布指数部分的一般形式,由此得到对应的均值和方差,其中方差 β \beta β是定值,而均值 μ \mu μ再表示为由 x t , t x_t,t xt,t为参数的函数形式
这样一来,DDPM的每一步的推断可以总结为:
1) 每个时间步通过 x t x_t xt和 t t t来预测高斯噪声 z θ ( x t , t ) z_\theta(x_t,t) zθ(xt,t),随后根据(9)得到均值 μ θ ( x t , t ) \mu_\theta(x_t,t) μθ(xt,t)
2) 得到方差 Σ θ ( x t , t ) \Sigma_\theta(x_t,t) Σθ(xt,t),DDPM中使用untrained Σ θ ( x t , t ) = β ~ t \Sigma_\theta(x_t,t)=\tilde \beta_t Σθ(xt,t)=β~t(也就是不训练方差作为固定参数),且认为 β ~ t = β t \tilde \beta_t=\beta_t β~t=βt和 β ~ t = 1 − α ˉ t − 1 1 − α ˉ t ⋅ β t \tilde \beta_t=\frac{1-\bar \alpha_{t-1}}{1-\bar \alpha_t} \cdot \beta_t β~t=1−αˉt1−αˉt−1⋅βt结果近似
3) 根据(5-2)得到 q ( x t − 1 ∣ x t ) q(x_{t-1}|x_t) q(xt−1∣xt),利用重参数技巧得到 x t − 1 x_{t-1} xt−1
重复上述步骤逐步去噪,直到计算出 x 0 x_0 x0,去噪过程完毕。
讲完了前向加噪的扩散过程和逆向去噪的推断过程(虽然文字上来看原理很简单,但是公式好繁杂)。现在我们讲讲如何训练diffusion model以得到靠谱的参数 μ θ ( x t , t ) 和 Σ θ ( x t , t ) \mu_\theta(x_t,t)和\Sigma_\theta(x_t,t) μθ(xt,t)和Σθ(xt,t),方法还是最大对数似然(此处用的最小化负对数似然)。
由于整个Diffusion模型和VAE很相似,训练过程也是,由于KL散度恒大于0,因此我们在负对数似然上加上一个KL散度就构成了它的上界(和VAE最大对数似然的时候正好相反,那时是减去一个KL散度是下界):
利用詹森不等式,我们就能得到(这块看的不太细,记住结论就好):
我们进一步对 L V L B L_{VLB} LVLB进行推导,可以得到熵与多个KL散度的累加2,其中分母是扩散过程,分子是逆扩散过程:
(上式【从 L V L B L_{VLB} LVLB开始为第一行】第四行到第五行又是应用了贝叶斯公式,先逆向马尔科夫链补上了一个 x 0 x_0 x0再应用了和之前前向中讲到的一模一样的贝叶斯公式)
第六行的第三项 ∑ t = 2 T l o g q ( x t ∣ x 0 ) q ( x t − 1 ∣ x 0 ) \sum^T_{t=2}log\frac{q(x_t|x_0)}{q(x_{t-1}|x_0)} ∑t=2Tlogq(xt−1∣x0)q(xt∣x0)可化简,最后与第四项以及第一项可合并,最终得到了第七行的式子
最后一行将其简化为了含有KL散度的式子,其中 L T L_T LT不含参(q分布不含参, x T x_T xT逆向过程最终为纯高斯噪声)相当于常量可以直接忽略, L t − 1 L_{t-1} Lt−1是逆扩散过程的KL散度,最后考虑的还是 L t − 1 和 L 0 L_{t-1}和L_0 Lt−1和L0。
并且由于 q 和 p θ q和p_{\theta} q和pθ其实都是高斯分布,并且 q q q是关于参数 β t \beta_t βt的高斯分布,且 β t \beta_t βt是untrained的固定参数(忘记的,点此回去), p θ p_{\theta} pθ的高斯分布均值是 μ θ \mu_{\theta} μθ,方差是 Σ θ \Sigma_\theta Σθ且 Σ θ \Sigma_\theta Σθ也是untrained的固定参数。因此可训练的参数 θ \theta θ只在 p θ p_\theta pθ中。
给出一个结论:对于两个高斯分布p,q而言,它们的KL散度可等价为
D K L ( p , q ) = l o g σ 2 σ 1 + σ 1 2 + ( μ 1 − μ 2 ) 2 2 σ 2 2 − 1 2 D_{KL}(p,q)=log\frac{\sigma_2}{\sigma_1}+\frac{\sigma_1^2+(\mu_1-\mu_2)^2}{2\sigma_2^2}-\frac{1}{2} DKL(p,q)=logσ1σ2+2σ22σ12+(μ1−μ2)2−21
让我们把 L t − 1 L_{t-1} Lt−1的式子用上式表示出来,得到:
(此处 L t − 1 L_{t-1} Lt−1应该是笔误,实为 L t L_t Lt, L V L B L_{VLB} LVLB给出的是 t = 2 t=2 t=2开始,在(14-3)中已经被改为 t = 1 t=1 t=1开始到 T − 1 T-1 T−1)
然后将 μ ~ t \tilde \mu_t μ~t用(8-2)替换, μ θ \mu_\theta μθ用(9)替换, x t x_t xt用(3)替换,得到:
从(16)可以看出,diffusion训练的核心就是取学习高斯噪声 z ˉ t , z θ \bar z_t,z_\theta zˉt,zθ之间的均方误差MSE。论文中作者说我们可以将(16)式子中前面的这个系数给直接丢掉,这样训练会更稳定。
最后论文给出的式子,我们将 z ˉ t \bar z_t zˉt替换为 ϵ \epsilon ϵ, z θ z_\theta zθ替换为 ϵ θ \epsilon_\theta ϵθ,DDPM将loss进一步简化为:
训练过程可以看做:
1)获取输入 x 0 x_0 x0,从1…T随机采样一个 t t t
2) 从标准高斯分布采样一个噪声 ϵ ∼ N ( 0 , I ) \epsilon \sim N(0,I) ϵ∼N(0,I)
3) 最小化loss函数
最后我们给出DDPM提供的训练/测试(采样)流程图
在训练过程中,我们要输入 x 0 x_0 x0进行随机采样时刻 t t t并采样噪声 ϵ \epsilon ϵ,然后对loss函数进行梯度下降直到拟合。而在测试采样过程中,我们则利用马尔科夫链逆向逐步去噪计算 x T x_T xT直到 x 0 x_0 x0作为最后的生成结果。
通过遵循反向扩散过程的马尔可夫链从DDPM生成样品非常慢,因为高质量生成需要的 T T T最多要走一千步或是几千步。“例如,从 DDPM 采样大小为 20 × 50 的 32k 图像大约需要 32 小时,但从 Nvidia 2080 Ti GPU 上的 GAN 采样不到一分钟。”
这就导致diffusion的前向过程非常缓慢。在denoising diffusion implicit model (DDIM)中提出了一种牺牲多样性来换取更快推断的手段。
一种简单的方法是运行一个跨步的采样,通过每隔 ⌈ T / S ⌉ \lceil T/S \rceil ⌈T/S⌉步进行采样更新,总共采样 S S S步,这样就能有效减少采样数量。
另一种方法是重写 q σ ( x t − 1 ∣ x t , x 0 ) q_\sigma(x_{t-1}|x_t,x_0) qσ(xt−1∣xt,x0)的标准差 σ t \sigma_t σt:
根据(3)我们可知:
最终得到的(18)将方差 σ t 2 \sigma_t^2 σt2迎入到了均值中,当 σ t 2 = β ~ t = 1 − α ˉ t − 1 1 − α ˉ t \sigma_t^2=\tilde \beta_t=\frac{1-\bar \alpha_{t-1}}{1-\bar \alpha_t} σt2=β~t=1−αˉt1−αˉt−1时,(18)等价于(6)。我们给定一个 η \eta η作为控制采样随机性的超参数 σ t 2 = η β ~ t \sigma_t^2=\eta \tilde \beta_t σt2=ηβ~t(作用类似于调整方差的大小),当 η = 1 \eta=1 η=1的时候就等价于DDPM,当 η = 0 \eta=0 η=0的时候是DDIM
(上图是不同设置的扩散模型在 CIFAR10 和 CelebA 数据集上的 FID 得分,包括了DDIM( η = 0 \eta=0 η=0)以及DDIM( σ ^ \hat \sigma σ^)( η = 1 \eta=1 η=1))
根据上表可知,数据量较小时DDIM的训练更快,而数据量较大时使用DDPM并采用更大的方差效果更好
与DDPM相比,DDIM能够:
1.使用更少的步骤生成更高质量的样本。
2.具有“一致性”属性,因为生成过程是确定性的,这意味着以同一潜在变量为条件的多个样本应该具有类似的高级特征。
3.由于一致性,DDIM 可以在潜在变量中执行语义上有意义的插值。
Feller, William. “On the theory of stochastic processes, with particular reference to applications.” Proceedings of the [First] Berkeley Symposium on Mathematical Statistics and Probability. University of California Press, 1949. ↩︎
Feller, William. “On the theory of stochastic processes, with particular reference to applications.” Proceedings of the [First] Berkeley Symposium on Mathematical Statistics and Probability. University of California Press, 1949. ↩︎