赞
踩
2018年我写过一篇博客,叫:《一文读懂目标检测:R-CNN、Fast R-CNN、Faster R-CNN、YOLO、SSD》,该文相当于梳理了2019年之前CV领域的典型视觉模型,比如
随着2019 CenterNet的发布,特别是2020发布的DETR(End-to-End Object Detection with Transformers)之后,自此CV迎来了生成式下的多模态时代(本文介绍其中有下划线的部分,其他部分下一篇介绍)
1月 | 3月 | 4月 | 5月 | 6月 | 8月 | 9月 | 10月 | 11月 | |
2020 | DETR | DDPM | DDIM VisionTransf.. | ||||||
2021 | CLIP DALL·E | SwinTransf.. | MAE SwinTransf..V2 | ||||||
2022 | BLIP | DALL·E 2 | StableDiffusion BEiT-3 Midjourney V3 | ||||||
2023 | BLIP2 | VisualChatGPT GPT4 Midjourney V5 | SAM(Segment Anything Model) | DALLE3 |
但看这些模型接二连三的横空出世,都不用说最后爆火的GPT4,便可知不少CV同学被卷的不行
说到GPT4,便不得不提ChatGPT,实在是太火了,改变了很多行业,使得国内外绝大部分公司的产品、服务都值得用LLM全部升级一遍(比如微软的365 Copilot、阿里所有产品、金山WPS等等)
而GPT4相比GPT3.5或GPT3最本质的改进就是增加了多模态的能力,使得ChatGPT很快就能支持图片的输入形式,从而达到图生文和文生图的效果,而AI绘画随着去年stable diffusion和Midjourney的推出,使得文生图火爆异常,各种游戏的角色设计、网上店铺的商品/页面设计都用上了AI绘画这样的工具,更有不少朋友利用AI绘画取得了不少的创收,省时省力还能赚钱,真香
但面对这么香的技术,其背后的一系列原理到底是什么呢,本文特从头开始,不只是简单的讲一下扩散模型的原理,而是在反复研读相关论文之后,准备把20年起相关的CV多模态模型全部梳理一遍,从VE、VAE、DDPM到ViT/Swin transformer、CLIP/BLIP,再到stable diffusion/Midjourney、GPT4,当然,实际写的时候,会分成两篇甚至多篇文章,比如
就当2020年之后的CV视觉发展史了,且过程中会尽可能写透彻每一个模型的原理,举两个例子
自编码器(Autoencoder,简称AE)是一种无监督学习的神经网络,用于学习输入数据的压缩表示。具体而言,可以将其分为两个部分:编码器和解码器
编码器:编码器是一个神经网络,负责将输入数据(如图像、文本等)压缩为一个低维表示,且表示为
解码器:解码器是另一个神经网络,负责将编码器生成的低维表示恢复为原始数据,且表示为
从而最终完成这么一个过程:,而其训练目标即是最小化输入数据与解码器重建数据之间的差异,所以自编码器常用的一个损失函数为
这个自编码的意义在于
对于第二点,理论上可以这么做,但问题在于
有问题自然便得探索对应的解决方案,而VAE(自变分编码器,Variational Autoencoders)则是在AE的基础上,显性的对的分布进行建模(比如符合某种常见的概率分布),使得自编码器成为一个合格的生成模型
VAE和GAN一样,都是从隐变量生成目标数据, 具体如下图所示(本1.2节的部分图来自苏剑林):
而VAE和GAN都希望这组生成数据的分布和目标分布尽量接近,看似美好,但有两个问题
实际是怎么做的呢?如苏剑林所说,与自动编码器由编码器与解码器两部分构成相似,VAE利用两个神经网络建立两个概率密度分布模型:
仔细理解的时候有没有发现一个问题?为什么在文章最开头,我们强调了没法直接比较 与 的分布,而在这里,我们认为可以直接比较这俩?注意,这里的 是专属于或针对于的隐变量,那么和 本身就有对应关系,因此右边的蓝色方框内的“生成器”,是一一对应的生成。
另外,大家可以看到,均值和方差的计算本质上都是encoder。也就是说,VAE其实利用了两个encoder去分别学习均值和方差
这里还有一个非常重要的问题,如苏剑林所说,由于我们通过最小化来训练右边的生成器,最终模型会逐渐使得 和趋于一致。但是注意,因为 是重新随机采样过的,而不是直接通过均值和方差encoder学出来的,这个生成器的输入 是有噪声的
现在我们来回顾一下VAE到底做了啥。VAE在AE的基础上
这样一来,当decoder训练的不好的时候,整个体系就可以降低噪声;当decoder逐渐拟合的时候,就会增加噪声
VQ即Vector Quantised,它编码出的向量是离散的,也就是把VAE做量化,所以VQ-VAE最后得到的编码向量的每个元素都是一个整数
此时这个量化特征就非常可控了,因为它们永远都是从codebook里面来的,而非随机生成,这样优化起来相对容易,如下图所示
VQ-VAE也可以用来做CV领域的自监督学习,比如BEIT就是把DALL·E训练好的codebook拿来用。将图片经过上面同样的过程quantise成的特征图作为ground truth,自监督模型来训练一个网络
后续还有VL-BEIT (vision language BEIT)的工作,也是类似的思路,只不过是用一个Transformer编码器来做多模态的任务
// 待更
在写本部分之前,我反复看了网上很多阐述DDPM的文章,实话说,一开始看到那种一上来就一堆公式的,起初基本看不下去,虽然后来慢慢的都看得下去了,但如果对于一个初次接触DDPM的初学者来说,一上来就一堆公式确实容易把人绕晕,但如果没有公式,则又没法透彻理解背后的算法步骤
两相权衡,本文将侧重算法每一步的剖析,而公式更多为解释算法原理而服务,说白了,侧重原理 其次公式,毕竟原理透彻了,公式也就自然而然的能推出来了
言归正传,咱们先来了解下扩散模型的极简发展史
2015年,斯坦福大学的一博士后Sohl-Dickstein通过此篇论文《Deep Unsupervised Learning using Nonequilibrium Thermodynamics》提出扩散模型的概念
简单来讲,扩散模型的灵感来自非平衡热力学,通过定义了一个扩散步骤的马尔可夫链,以缓慢地将「符合高斯分布的随机噪声」添加到数据中,然后反转扩散过程以从噪声中构建所需的数据样本
随后,2019年,斯坦福一在读博士宋飏和其导师通过此文《Generative Modeling by Estimating Gradients of the Data Distribution》提出了一种新方法来构建生成模型:即不需要估计数据的概率分布(数据概率的分布类似高维曲面),相反,它估计的是分布的梯度(分布的梯度可以看成是高维曲面的斜率)
「顺带说一下,后来宋飏等人推出了扩散模型的改进,即DALLE 3的解码器之一致性模型Consistency Models(详见:AI绘画神器DALLE 3的解码器:一步生成的扩散模型之Consistency Models)」
再之后,2020年6月,UC Berkeley的Jonathan Ho等人意识到宋飏的工作可以改进 Sohl-Dickstein的扩散模型,很快,便通过论文《Denoising Diffusion Probabilistic Models》正式提出对于普通扩散模型的改进版:DDPM(全称即论文名称:Denoising Diffusion Probabilistic Models)
DDPM主要有两个贡献
为方便大家更好的理解本文,特地解释下什么叫U-Net网络(对应论文为:U-Net: Convolutional Networks for Biomedical Image Segmentation)
在目前绝大部分的图像或视频扩散方法中,主导的骨干网络一般是由一系列卷积和自注意力层构成的 U-Net 架构
它总共有23个卷积层的网络,由一个收缩路径(左侧)和一个扩张路径(右侧)组成
- 收缩路径遵循卷积网络的典型架构。 它由两个3x3卷积(无填充卷积)的重复结构组成,每个卷积后面跟着ReLU和一个2x2最大池化操作,步长为2,用于下采样,在每个下采样步骤中,我们将特征通道的数量加倍
- 扩张路径中的每个步骤都包括特征图的上采样,然后是一个2x2卷积(“上卷积”),将特征通道数量减半,与收缩路径中相应裁剪的特征图进行连接(a concatenation with the correspondingly cropped feature map from the contracting path),以及两个3x3卷积,每个卷积后面跟着一个ReLU。由于每次卷积都会丢失边界像素(the loss of border pixels in every convolution),所以裁剪是必要的
- 在最后一层,使用1x1卷积将每个64个分量的特征向量映射到所需的类别数
人们之所以偏好 U-Net,是因为 Transformer 中全注意力机制的内存需求会随输入序列长度而二次方增长,而在处理视频这样的高维信号时,这样的增长模式会让计算成本变得非常高
当然,在此文《视频生成的原理解析:从Gen2、Emu Video到PixelDance、SVD、Pika 1.0、W.A.L.T》的第六部分你会看到,已有最新的研究把Transformer用做扩散模型的骨干网络
DDPM也有些类似VAE,也可以将其当做一个encoder-decoder的结构,但是有几点区别:
DDPM使得扩散模型可以在真实数据集上work得很好之后,一下子吸引了很多人的兴趣。因为DDPM在数学上简洁美观,无论正向还是逆向,都是高斯分布,可以做很多推理证明,而且还有很多不错的性质,2021年2月,OpenAI的Alex Nichol和Prafulla Dhariwal推出了 improved DDPM「其对应论文为:《Improved Denoising Diffusion Probabilistic Models》」
improved DDPM相比DDPM做了几点改动:
上面第三点对OpenAI来说,无疑是个好消息。所以improved DDPM的二作和三作马上着手研究,发布了《Diffusion Models Beat GANs on Image Synthesis》这篇论文,比之前的improved DDPM又做了一些改进:
当然,除了最简单最原始的classifier guidance之外,还有很多其它的引导方式
CLIP guidance:将简单的分类器换成CLIP之后,文本和图像就联系起来了。此时不光可以利用这个梯度引导模型采用和生成,而且可以利用文本指导其采样和生成
image侧引导:除了利用图像重建进行像素级别的引导,还可以做图像特征和风格层面的引导,只需要一个gram matrix就行
text 侧:可以用训练好的NLP大模型做引导
以上所有引导方式,都是下面目标函数里的,即模型的输入不光是和time embedding,还有condition,加了condition之后,可以让模型的生成又快又好p(xt−1∣xt)=‖z−fθ(xt,t,y)‖
且值得一提的是,额外引入一个网络来指导,推理的时候比较复杂 (扩散模型需要反复迭代,每次迭代都需要额外算一个分数),所以引出了后续2022年7月的一个工作:classifier free guidance
2021年年底,此篇论文《High-Resolution Image Synthesis with Latent Diffusion Models》提出了潜在扩散模型,也是后续奠定stable diffusion的核心论文(关于SD详见本系列的另一篇文章《AI绘画原理解析:从CLIP到DALLE1/2、DALLE 3、Stable Diffusion》)
为何要弄这么个隐空间或潜在空间呢?
原因很简单,为了使扩散模型在有限的计算资源上训练,并且保留它们的质量和灵活性,故首先训练了一个强大的预训练自编码器,这个自编码器所学习到的是一个潜在的空间,这个潜在的空间要比像素空间要小的多(可以简单粗暴的理解为就是一个被压缩或被降维的空间),把扩散模型在这个潜在的空间去训练,大大的降低了对算力的要求,这也是Stable Diffusion比原装Diffusion速度快的原因
所谓classifier free guidance的方式(对应论文为《Jonathan Ho and Tim Salimans. Classifier-free diffusion guidance》),只是改变了模型输入的内容,除了 conditional输入外(随机高斯噪声输入加引导信息),还有 unconditional 的采样输入,两种输入都会被送到同一个 diffusion model,从而让其能够具有无条件和有条件生成的能力
总之,扩散模型本来训练就很贵了,classifier free guidance这种方式在训练时需要生成两个输出,所以训练更贵了。但是这个方法确实效果好,所以在GLIDE 、DALL·E2和Imagen里都用了,而且都提到这是一个很重要的技巧,用了这么多技巧之后,GLIDE终于是一个很好的文生图模型了,只用了35亿参数,生成效果和分数比120亿参数的DALL·E还要好
2021年,OpenAI一看GLIDE这个方向靠谱,就马上跟进,不再考虑DALL·E的VQ-VAE路线了,而是将GLIDE改为层级式生成(56→256→1024)并加入prior网络等等,于是
回到DDPM,每一个噪声都是在前一时刻增加噪声而来的,从最开始的x0
所以DDPM为了从随机噪声中直接生成图片,首先需要训练一个噪声估计模型,然后将输入的随机噪声还原成图片,相当于就两个关键,一个是训练过程,一个是推理过程
前向过程(forward process)也称为扩散过程(diffusion process),简单理解就是对原始图片x0
在从到的过程中,其对应的分布q(xt|xt−1)
q(xt|xt−1)=N(xt;ut=√1−βtxt−1,βtI)
对于这个公式,解释下3点
正态分布的概率密度函数具有以下形式:
f(x)=1σ√2πe−(x−μ)22σ2
顺带帮你再回顾下:正态分布有两个参数:均值μ和方差。其中,μ是分布的均值,决定了分布的中心位置,σ是标准差,决定了分布的宽度
接下来,如果我们定义 αt=1−βt, 且{αt}Tt=1『被称为Noise schedule,通常是一些列很小的值』,以及 ϵt−1∼N(0,1)是高斯噪声(即满足正太分布),便可以得到的采样值
xt=√αtxt−1+√1−αtϵt−1
把上述公式迭代变换下,可以直接得出 x0 到 的公式,如下:
xt=√ˉαtx0+√1−ˉαtϵ0
其中 ¯αt=∏ti=1αi,ϵ∼N(0,1) 也是一个高斯噪声
换言之,所以 在 x0条件下的分布就是均值为 √¯αtx0 , 方差为 1−¯αt的正态分布 (下式的意义在于,只需要给出x0,便可以计算出任意时刻t的)
q(xt∣x0)=N(xt;√ˉαtx0,(1−ˉαt)I)
考虑到可能会有读者对这个x0 到 的一步到位感到困惑,而一般的同类文章不会展开的特别细,故本文细致展开下(能拆10步则10步,确保阅读无障碍)
- 首先通过xt=√αtxt−1+√1−αtϵt−1可知,xt−1=√αt−1xt−2+√1−αt−1ϵt−2,把这个代入到的表达式后,再展开即可得
xt=√αtxt−1+√1−αtϵ∗t−1=√αt(√αt−1xt−2+√1−αt−1ϵ∗t−2)+√1−αtϵ∗t−1=√αtαt−1xt−2+√αt−αtαt−1ϵ∗t−2+√1−αtϵ∗t−1- 考虑到两个独立正态分布的随机变量之和是正态的,其均值是两个均值之和,其方差是两个方差之和(即标准差的平方是标准差的平方)「比如两个方差不同的高斯分布N(0,σ21I)和N(0,σ22I)相加等于一个新的高斯分布N(0,(σ21+σ22)I)」,然后再通过重参数技巧可得
xt=√αtαt−1xt−2+√√αt−αtαt−12+√1−αt2ϵt−2=√αtαt−1xt−2+√αt−αtαt−1+1−αtϵt−2=√αtαt−1xt−2+√1−αtαt−1ϵt−2=…
对此,本文参考文献中的这篇《Understanding Diffusion Models: A Unified Perspective》也解释了这几个步骤- 最后定义一个累积混合系数, ¯αt=∏ti=1αi,即√¯αt=√αt√αt−1⋯√α1,可得
xt=√∏ti=1αix0+√1−∏ti=1αiϵ0=√ˉαtx0+√1−ˉαtϵ0∼N(xt;√ˉαtx0,(1−ˉαt)I)
逆向过程就是通过估测噪声,多次迭代逐渐将被破坏的 恢复成 x0,如下图
更具体而言,正向扩散和逆扩散过程都是马尔可夫,唯一的区别就是正向扩散里每一个条件概率的高斯分布的均值和方差都是已经确定的(依赖于 βt 和 x0),而逆扩散过程里面的均值和方差需要通过网络学出来,怎么个学法呢?
理论上没问题,但是实际效果很差,为什么呢?如果直接用 xθ(xt,t),那么中间的x2,x3,…,xT−1都没用了,整个 DDPM 就退化成了 VAE 的结构,但是
VAE 的生成模型和后验都是自己学习出来的,二者双向奔赴共同优化去寻找最优解
而 DDPM 的后验是人为指定的(即x0=1/√ˉαt(xt−√1−ˉαtϵ0)),并且由于 ˉαt→0,q(xt|x0)基本上就是一个标准正态分布,磨灭掉了几乎所有的输入信息,全靠生成模型这一边去恢复,难度未免过大..
那样,我们便可以使用「参数为 θ 的U-Net+attention 结构pθ」去预测这样的一个逆向的分布(类似VAE):
pθ(X0:T)=p(xt)∏Tt=1pθ(xt−1∣xt)
pθ(xt−1∣xt)=N(xt−1;μθ(xt,t),Σθ(xt,t))
不过在DDPM的论文中,作者把条件概率 pθ(xt−1|xt) 的方差直接取了βt,而不是上面说的需要网络去估计的 Σθ(xt,t),所以说实际上只有均值需要网络去估计
然现在的问题是,我们无法直接去推断 q(xt−1|xt),即q(xt−1|xt) is unknown
所以,接下来的问题 自然而然 就转换成了我们希望求解q(xt−1∣xt),因为我们已知前向过程q(xt∣xt−1),所以自然想到使用贝叶斯公式:
q(xt−1∣xt)=q(xt∣xt−1)q(xt−1)q(xt)
可惜 q(xt)和 q(xt−1)是未知的,事情到这里似乎走入了僵局,好在我们发现q(xt|x0)和 q(xt−1|x0)是已知的,这样一变换,下述等式右边的三项就都可知了
q(xt−1∣xt)=q(xt∣xt−1)q(xt−1|x0)q(xt|x0)
相当于如果给上式加上 x0 为条件,则立马柳暗花明,而一旦知道了 x0,q(xt−1|xt,x0),便可以直接写出q(xt−1∣xt,x0)=N(xt−1;˜μ(xt,x0),˜βtI)
接下来,我们便好好推导下
解释下上面7.1~7.5这5个步骤的推导
7.1依据的是
P(A|B)=P(AB)P(B)- 7.2中,分母部分依据的是
P(AB)=P(A)P(B|A)
分子部分依据的是
P(ABC)=P(A)P(B|A)P(C|AB)
注,此处的A B与上面7.1的A B非同一个具体的指向,只是公式层面的原有表达- 7.3依据的是分子分母同时除以q(x0)
- 至于7.3到7.4
=q(xt∣xt−1,x0)q(xt−1∣x0)q(xt∣x0)7.3∝exp(−12((xt−√αtxt−1)2βt+(xt−1−√ˉαt−1x0)21−ˉat−1−(xt−√ˉαtx0)21−ˉat))7.4
依据的是
ρ(x)=1√2πσe−12(x−μσ)2
且由前向扩散过程的特性『别忘了2.2.1节中,有 q(xt∣x0)=N(xt;√ˉαtx0,(1−ˉαt)I)』,可知
q(xt∣xt−1,x0)=q(xt∣xt−1)=N(xt;√1−βtxt−1,βtI)
q(xt−1∣x0)=N(xt−1;√ˉαt−1x0,(1−ˉαt−1)I)
q(xt∣x0)=N(xt;√ˉαtx0,(1−ˉαt)I)- 最后,再解释下怎么从7.4到的7.5
=q(xt∣xt−1,x0)q(xt−1∣x0)q(xt∣x0)7.3∝exp(−12((xt−√αtxt−1)2βt+(xt−1−√ˉαt−1x0)21−ˉat−1−(xt−√ˉαtx0)21−ˉat))=exp(−12((αtβt+11−ˉαt−1)x2t−1⏟xt−1−(2√αtβtxt+2√ˉat−11−ˉαt−1x0)xt−1⏟xt−1+C(xt,x0)⏟))⋅7.5
先举一个最简单的例子,比如对于 12(Ax2+Bx+C),稍加转化下即是12A(x+B2A)2+C,而这个
A则对应于7.5中的αtβt+11−ˉαt−1
B则对应于7.5中的−(2√αtβtxt+2√ˉat−11−ˉαt−1x0)
且其均值为−B2A,方差为1A,从而有
μt(xt,x0)=−B2A
=(√αtβtxt+√ˉαt−11−ˉαt−1x0)/(αtβt+11−ˉαt−1)=(√αtβtxt+√ˉαt−11−ˉαt−1x0)1−ˉαt−11−ˉαt⋅βt=√αt(1−ˉαt−1)1−ˉαtxt+√ˉαt−1βt1−ˉαtx0
~βt=1A=1/(αtβt+11−ˉαt−1)=1/(αt−ˉαt+βtβt(1−ˉαt−1))=1−ˉαt−11−ˉαt⋅βt
好,接下来关键来了
根据xt=√ˉαtx0+√1−ˉαtϵ0,可知x0=1√ˉαt(xt−√1−ˉαtϵ0),代入上面μt(xt,x0)的表达式 可得
μ(xt,x0)=1√αt(xt−1−αt√1−ˉαtϵ0)
大部分文章对上面这个的推导都是一步到位的,但本文为细致起见,故还是一步步来推导下
- 首先直接把x0=1√ˉαt(xt−√1−ˉαtϵ0)和βt=1−αt代入进去,可得
μ(xt,x0)=√αt(1−ˉαt−1)xt+√ˉαt−1(1−αt)x01−ˉαt=√αt(1−ˉαt−1)xt+√ˉαt−1(1−αt)xt−√1−ˉαtϵ0√ˉαt1−ˉαt
- 接下来,我们可以进一步观察到 分子中的后半部分有√ˉαt−1(1−αt)xt−√1−ˉαtϵ0√ˉαt这一项,怎么进一步化简呢?
接下来非常关键(截止23年5月份之前,暂时没看到有其他中英文资料解释了这个细节)
好在之前有定义:¯αt=∏ti=1αi,即√¯αt=√αt√αt−1⋯√α1,从而有√¯αt=√αt√¯αt−1所以我们可以针对这一项√ˉαt−1(1−αt)xt−√1−ˉαtϵ0√ˉαt的分子分母同时除以√¯αt−1,得到
μt(xt,x0)=√αt(1−ˉαt−1)xt+(1−αt)xt−√1−ˉαtϵ0√αt1−ˉαt之后的推导就比较简单了
以下分别对上面的三行公式做解释说明:
接着把上阶段2得到的式子的分子拆成三项,且三项中最后两项的分子分母同时乘以√αt
然后再把上一步骤中分子三项中的前两项通过提取出从而实现合并
前两项合并之后,再对前两项中第一项的分子分母同时乘以√αt,然后对第三项的分子分母同时除以√1−αt,即可得1−αt√1−ˉαt√αtϵ0,原因很简单,因为:1−¯αt=(√1−¯αt)2接下来,针对上面阶段3得到的式子的前两项再做合并,合并中用到了一个细节,即αtׯαt−1=¯αt,原因也同样很简单,根据上面阶段2出现的这个式子√¯αt=√αt√¯αt−1而来,再之后就更eazy 便不再赘述了
总之,从最终得到的结果可以看出,在给定 x0 的条件下,后验条件高斯分布的均值只和超参数αt、、ϵ0有关,即
μ(xt,x0)=1√αt(xt−1−αt√1−ˉαtϵ0)
方差只与超参数α有关,即
~βt=1A=1/(αtβt+11−ˉαt−1)=1/(αt−ˉαt+βtβt(1−ˉαt−1))=1−ˉαt−11−ˉαt⋅βt
从而通过以上的方差和均值,我们就得到了q(xt−1|xt,x0)的解析形式
继续下文之前,先总结一下
生成模型的本质是根据给定的样本(训练数据)生成新样本
- 具体而言,给定一批训练数据,假设其服从某种复杂的真实分布p(x),则给定的训练数据可视为从该真实分布中采样的观测样本
- 如果能从这些观测样本中估计出训练数据的真实分布,相当于就可以从该分布(估计出的接近真实分布的分布)中不断的采样出新的样本了,故说白了,生产模型的目标就是估计训练数据的真实分布,并假定其真实分布为q(x)
- 从而问题自然而然就变成了尽可能缩小估计的分布q(x)与真实分布p(x)之间的差距
接下来介绍这个模型要怎么优化,即网络该怎么训练:去估计分布q(xt−1∣xt)的条件概率pθ(xt−1|xt)的均值uθ(xt,t) 和方差Σθ(xt,t)
与之前介绍的VAE相比,扩散模型的隐变量是和原始数据是同维度的,而且encoder(即扩散/加噪过程)是固定的
既然扩散模型是隐变量模型,那么我们可以基于变分推断来得到variational lower bound(VLB,又称ELBO)作为最大化优化目标,当然实际训练时一般对VLB取负,即我们要最小化目标分布的负对数似然:
−logpθ(x0)≤−logpθ(x0)+DKL(q(x1:T∣x0)‖pθ(x1:T∣x0))=−logpθ(x0)+Ex1:T∼q(x1:T∣x0)[logq(x1:T∣x0)pθ(x0:T)/pθ(x0)]=−logpθ(x0)+Eq[logq(x1:T∣x0)pθ(x0:T)+logpθ(x0)]=Eq[logq(x1:T∣x0)pθ(x0:T)]
考虑到本文的定位起见,逐一解释下上面推导的每一行
第一行:由 KL 散度的非负性质(KL 散度始终大于等于零),我们得到如下不等式:−logpθ(x0)≤−logpθ(x0)+DKL(q(x1:T∣x0)‖pθ(x1:T∣x0))
第二行:将 KL 散度的定义代入上式可得
其中 E 表示期望,即对分布 q(x1:T|x0) 中的所有可能值求期望
第三行:对上式进行简化,将−logpθ(x0)项移到期望内部
其中 Eq表示对分布 q(x1:T|x0) 中的所有可能值求期望
第四行:−logpθ(x0) 和 +logpθ(x0) 相互抵消可得
令
Let LVLB=Eq(x0:T)[logq(x1:T∣x0)pθ(x0:T)]≥−Eq(x0)logpθ(x0)
所以 LVLB就是我们的上界,我们要最小化它,接着进行变形
老规矩,上面整个推导总计九行,下面逐行解释下上面推导的每一行(纵使其他所有文章都不解释,本文也要给你解释的明明白白)
第一行,直接给出了 LVLB 的定义,即计算概率分布 q 和pθ之间的对数比值的期望(注意,这是咱们的目标)
LVLB=Eq(x0:T)[logq(x1:T∣x0)pθ(x0:T)]
考虑到七月SD课的一学员对第一步有疑问,再多解释一下
在第1步中,公式的意思是对于所有可能的的x0,x1,…,xT路径,我们要计算中括号内部表达式的期望值这里是一个联合分布,表示所有xt(t=0,1,...,T)一起的分布,而期望是在这个分布下计算的
这意味着我们在所有这个分布支持的路径上平均这个中括号里的量
所以,如果x0,x1,…,xT都服从分布q,那么我们确实是在对中括号里的式子求整体期望第二行,将条件概率 q(x1:T∣x0) 和联合概率 pθ(x0:T) 展开为一系列条件概率的乘积
q(x1:T∣x0)=∏Tt=1q(xt∣xt−1)
考虑到pθ(x0:T)实际上就是pθ(x1:T∣x0),所以有
pθ(x0:T)=pθ(x0)∏Tt=1pθ(xt|x0:t−1)=pθ(xT)∏Tt=1pθ(xt−1∣xt)然后把上述结果分别分别代入q(x1:T∣x0)和 pθ(x0:T),即可得到第二行的结果
Eq[log∏Tt=1q(xt∣xt−1)pθ(xT)∏Tt=1pθ(xt−1∣xt)]
第三行,将乘积转换为求和,并将pθ(xT)项移到前面
Eq[−logpθ(xT)+∑Tt=1logq(xt∣xt−1)pθ(xt−1∣xt)]
第四行,调整求和的范围,使其从2开始,从而达到将 t=1 的项分离出来的目的
Eq[−logpθ(xT)+∑Tt=2logq(xt∣xt−1)pθ(xt−1∣xt)+logq(x1∣x0)pθ(x0∣x1)]
第五行,将 t 项的对数比值分解为两个对数比值的和,其中一个涉及xt−1和 xt,另一个涉及xt和 x0,相当于补了个x0
Eq[−logpθ(xT)+∑Tt=2log(q(xt−1∣xt,x0)pθ(xt−1∣xt)⋅q(xt∣x0)q(xt−1∣x0))+logq(x1∣x0)pθ(x0∣x1)]
这里得着重解释下
把第四行的第二项的分子和分母都乘以q(xt−1|x0),即得
logq(xt∣xt−1)pθ(xt−1∣xt)=log(q(xt−1∣xt,x0)pθ(xt−1∣xt)⋅q(xt∣x0)q(xt−1∣x0))这里面的关键是,即同时乘以q(xt−1|x0)后,怎么就得到上式了呢,分母部分一目了然,直接乘上的q(xt−1|x0),但分子部分呢,明明应该是q(xt|xt−1)q(xt−1|x0),则就变成了这个呢:q(xt−1|xt,x0)q(xt|x0)?好问题! 原因在于这两个式子是等价的,即(定义为等式1)
q(xt|xt−1)q(xt−1|x0)=q(xt−1|xt,x0)q(xt|x0)
为何等价呢,或者说上面这个等式1是怎么来的?其实也简单,因有
p(A, B, C) = p(A|B, C) p(B, C) = p(A|B, C) p(B|C) p(C)
p(A, B, C) = p(B|A, C) p(A, C) = p(B|A, C) p(A|C) p(C)
故有『下面五个等式先后依据:马尔科夫假设倒推、条件概率定义、分母中联合概率定义、分子中联合概率定义、分子分母同时约掉q(x0)』
q(xt∣xt−1)=q(xt∣xt−1,x0)=q(xt,xt−1,x0)q(xt−1,x0)=q(xt−1∣xt,x0)q(xt∣x0)q(x0)q(xt−1,x0)=q(xt−1∣xt,x0)q(xt∣x0)q(x0)q(xt−1∣x0)q(x0)=q(xt−1∣xt,x0)q(xt∣x0)q(xt−1∣x0)
第六行,将第五行的中间项一分为二,即拆分为两个求和项
Eq[−logpθ(xT)+∑Tt=2logq(xt−1∣xt,x0)pθ(xt−1∣xt)+∑Tt=2logq(xt∣x0)q(xt−1∣x0)+logq(x1∣x0)pθ(x0∣x1)]
第七行,将第五行中间部分得到的两个求和项的第二个求和项的最后一项t=T分离出来,说白了,将第二个求和项的范围调整为从1到T−1,啥意思呢
首先,第五行中间部分的两个求和项可以表示为∑Tt=2logq(xt−1∣xt,x0)pθ(xt−1∣xt)+∑Tt=2logq(xt∣x0)q(xt−1∣x0)=∑Tt=2[logq(xt−1∣xt,x0)pθ(xt−1∣xt)+logq(xt∣x0)q(xt−1∣x0)]
接下来,关键的一步在于,上面中括号里的第二个求和项在求和过程中相邻两项会相互抵消 「依据:logaM/N=logaM−logaN」
具体地,当t=k时的q(xk∣x0)会和当t=k+1时的q(xk∣x0)相互抵消,这样的抵消会发生在每一对相邻的项上,从2到T−1,最后,只剩下t=T和t=2时的两项,即logq(xT∣x0)q(x1∣x0)
从而得到最终整个第7行所示的结果,如下Eq[−logpθ(xT)+∑Tt=2logq(xt−1∣xt,x0)pθ(xt−1∣xt)+logq(xT∣x0)q(x1∣x0)+logq(x1∣x0)pθ(x0∣x1)]
第八行,上一行第7行总共4个带log的项,把最后两个log项拆开成4个式子,抵消两个,还分别剩一个logq(xT|x0)、一个−logpθ(x0|x1),然后logq(xT|x0)与最初4项中的第1项−logpθ(xT)合并,即可得到整个第八行的结果
Eq[logq(xT∣x0)pθ(xT)+∑Tt=2logq(xt−1∣xt,x0)pθ(xt−1∣xt)−logpθ(x0∣x1)]
第九行,将最后一项中的负号移到对数里面,并将整个表达式重写为一系列 KL 散度项的和,这些项分别为 LT、Lt−1 和 L0
Eq[DKL(q(xT∣x0)‖pθ(xT))⏟LT+∑Tt=2DKL(q(xt−1∣xt,x0)‖pθ(xt−1∣xt))⏟Lt−1−logpθ(x0∣x1)⏟L0]
考虑到七月SD课的一学员对这一步有疑问,再多解释一下
对于第9步,KL散度是一种衡量两个概率分布p和q之间差异的方法,这里的公式是在计算q和p之间的KL散度的期望值
尽管KL散度自己就是一个期望值的形式,但这里的Eq指的是在分布q下对KL散度本身求期望
这意味着你不仅计算了q和p之间的差异,而且你要考虑所有q分布可能产生的不同序列x0,x1,…,xT,对这些序列的KL散度进行平均最后得到的表达式表示了最初我们想求解的LVLB最终是一系列 KL 散度项之和,我们可以利用这个结果进行参数优化,使得两个概率分布之间的差异最小
对于上面公式最后第九行得到的结果
Lt=Eq[‖˜μt(xt,x0)−μθ(xt,t)‖2]
这里的 Eq是在分布 q 下的期望,当我们~μt的表达式代入后,得到:
Lt=Eq[‖1√αt(xt−βt√1−ˉαtϵ)−μθ(xt,t)‖2]
在这个式子中,ϵ 是一个服从标准正态分布的随机变量,而则取决于x0和ϵ。因此,这个期望 Eq实际上是在 x0和ϵ 的联合分布下的期望(在 x0和ϵ 的所有可能值上取平均),于是我们得到:
Lt=Ex0,ϵ[‖1√αt(xt(x0,ϵ)−βt√1−ˉαtϵ)−μθ(xt(x0,ϵ),t)‖2]
Ex0,ϵ 代表就是在 x0和ϵ 的联合分布下的期望,ϵ 依然是从标准正态分布中采样的噪声 ”
由上可知,DDPM的关键是训练 ϵθ(xt,t)模型,使其预测的 ˆϵ与真实用于破坏的ϵ 相近,用L2距离刻画相近程度就好,总之,我们的Loss就是如下公式『相当于训练时,网络输入为 (由 x0 和噪声 ϵ 线性组合而成) 和时刻t ,输出要尽可能的拟合输入的噪声 ϵ (通过L2 loss约束)』
下图可以总结噪声估计模型的训练过程 (依然是经典的那一套:对比预测噪声predicted noise与真实噪声true noise ε之间的差距 建loss 反向传播,训练好之后,好预测噪声,毕竟模糊的图片减掉噪声 不就得到清晰的图片了么)
而整个训练过程可如下图描述
DDPM论文中对应的伪代码为
通过上文2.2节的最后,我们得知
从最终得到的结果可以看出,在给定 x0 的条件下
后验条件高斯分布的均值只和超参数αt、、ϵ0有关,即
μ(xt,x0)=1√αt(xt−1−αt√1−ˉαtϵ0)
方差只与超参数α有关,即
~βt=1A=1/(αtβt+11−ˉαt−1)=1/(αt−ˉαt+βtβt(1−ˉαt−1))=1−ˉαt−11−ˉαt⋅βt
从而通过以上的方差和均值,我们就得到了q(xt−1|xt,x0)的解析形式
通过2.2节的最后,我们估计到了噪声估测模型 ϵθ(xt,t) ,接下来要生成模型就很简单了。从N(0,1)中随机生成一个噪声作为XT,然后再用该模型逐步从估测噪声,并用去噪公式逐渐恢复到 x0 即可,见如下伪代码
用通俗的语言来说,如何去噪生成清晰图片呢?如上述第4行代码所述,比较模糊的图片 减掉噪声估计器预测出来的噪声 (只是实际操作时,减掉的是与一个常数1−αt√1−ˉαt相乘之后的噪声),得到的结果乘以1/√at之后,最后再加上一个带σt的
换言之,推理时,我们从各项独立的高斯分布 开始,一共 T 步,每一步其实都是用了一次reparameterization trick
每一步具体来说,我们有了 , 想要得到 ,因为我们之前逆扩散过程建模有:
pθ(xt−1∣xt)=N(xt−1;μθ(xt,t),Σ2θ(xt,t))
=N(xt−1;1√αt(xt−βt√1−ˉαtϵθ(xt,t)),βt)
所以由reparameterization trick我们有:
每一轮都这样迭代,最终就得到了生成的图片,如下图所示
注,本小节的内容主要参考科技猛兽此文的相关部分
一般目标检测的任务是预测一系列的Bounding Box的坐标以及Label,而大多数检测器的具体做法是
把问题构建成为一个分类和回归问题来间接地完成这个任务,但最后都会生成很多个预测框(确定框的坐标及框内是什么物体),从而不可避免的出现很多冗余的框,而要去除这些冗余的框,则都需要做一个NMS(non-maximum suppersion,非极大值抑制)的后处理(使得最后调参不易、部署不易),所以如果要是有一个端对端的模型,不需要做NMS之类的后处理 也不需要太多先验知识则该有多好
而通过论文《End-to-End Object Detection with Transformers》提出的DETR则满足了大家这个期待,其取代了现在的模型需要手工设计的工作,效果不错且可扩展性强(在DETR上加个专用的分割头便可以做全景分割),其解决的方法是把检测问题看做是一个集合预测的问题(即set prediction problem,说白了,各种预测框本质就是一个集合),其基本流程如下图所示
更细致的讲,DETR整体结构可以分为四个部分:backbone,encoder,decoder和FFN,如下图所示
对于前两部分而言
一开始的backbone面对的是 ximg∈B×3×H0×W0维的图像,首先把它转换为f∈RB×C×H×W维的feature map(一般来说,通道数或256,,)
然后由于encoder的输入是f∈RB×C×H×W维的feature map,故正式输入encoder之前还需要依次进行以下过程(图源:科技猛兽):
对于上节第三步的位置编码,再好好解释说明下
首先,通过此文《从零实现Transformer的简易版与强大版:从300多行到3000多行》的1.1.2节可知,原始transformer中的Positional Encoding的表达式为:
其中, 就是这个 维的feature map的第一维,表示token在sequence中的位置,sequence的长度是,例如第一个token 的 ,第二个token的
,或者准确意义上是和表示了Positional Encoding的维度, 的取值范围是:,所以当 为1时,对应的Positional Encoding可以写成(注意到):
其次,DETR与原版transformer中的位置编码有两点不同
所以,了解了DETR的位置编码之后,你应该明白了其实input embedding和位置编码维度其实是一样的,从而也就可以直接相加,使得Encoder最终输出的是维的编码矩阵Embedding,按照原版Transformer的做法,把这个东西给Decoder
通过上节最后的对比图,可知DETR的Decoder和原版Transformer的decoder也是不太一样的
至于DETR的Decoder主要有两个输入:
每个Decoder的输出维度为,送入后面的前馈网络
到这里你会发现:Object queries充当的其实是位置编码的作用,只不过它是可以学习的位置编码,所以,我们对Encoder和Decoder的每个self-attention的Query和Key的位置编码做个归纳,如下图所示,Value没有位置编码
得到了Decoder的输出以后,如前文所述,应该是输出维度为的张量。接下来要送入2个前馈网络FFN得到class和Bounding Box(如再度引用的下图所示),它们会得到 个预测目标 包含类别和Bounding Box(当然这个100肯定是大于图中的目标总数的,如果不够100,则采用背景填充
所以,DETR输出张量的维度为,和『对应COCO数据集来说: , 4 指的是每个预测目标归一化的,归一化就是除以图片宽高进行归一化』,对于这两个维度
但是读者可能会有疑问:预测框和真值是怎么一一对应的?换句话说:你怎么知道第47个预测框对应图片里的狗,第88个预测框对应图片里的车?..
继DETR、DDPM之后,Google的Alexey Dosovitskiy等人于2020年10月发布的这篇论文《An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale》提出的ViT彻底引燃了多模态的火热,更是直接挑战了此前CNN在视觉领域长达近10年的绝对统治地位「如果忘了CNN长啥样的,请回顾此文《CNN笔记:通俗理解卷积神经网络》」
这个工作是怎么一步步出来的呢?自从Google在2017年发布的transformer在NLP领域大杀四方的时候,就一直不断有人想把如此强大且充满魔力的transformer用到CV领域中,但前路曲折啊
下面,我们来仔细探究下ViT到底是怎么做的
简单而言,Vision Transformer(ViT)的模型框架由三个模块组成:
16*16 | 16*16 | 16*16 | 16*16 | 16*16 | 16*16 | 16*16 | 16*16 | 16*16 | 16*16 | 16*16 | 16*16 | 16*16 | 16*16 |
16*16 | |||||||||||||
16*16 | |||||||||||||
16*16 | |||||||||||||
... |
至于在代码实现中,可通过一个卷积层来实现,卷积核大小为16,步长为16,输入维度是3,通过对整个图片进行卷积操作:[224, 224, 3] -> [14, 14, 768],然后把H以及W两个维度展平即可[14, 14, 768] -> [196, 768]
Conv2d(in_c, embed_dim, kernel_size=patch_size, stride=patch_size)
接下来,为了做最后的分类,故在所有tokens的前面加一个可以通过学习得到的 [class] token作为这些patchs的全局输出,相当于BERT中的分类字符CLS (这里的加是concat拼接),得益于self-attention机制,所有token两两之间都会做交互,故这个[class] token也会有与其他所有token交互的信息再通过小绿豆根据ViT的源码画的这个图总结一下
此外,上述这三个阶段的过程最终可以用如下4个公式表达
对于公式(1),表示图片patch,总共N个patch,则表示patch embedding,表示class embedding,因为需要用它做最后的输出/分类
对于公式(2),则表示多头注意力的结果(先Norm再multi-head attention,得到的结果再与做残差连接)
对于公式(3),表示最终整个transformer decoder的输出(先做Norm再做MLP,得到的结果再与做残差连接)
值得一提的是,由于ViT不像CNN那样对图像有比较多的先验知识,即没有用太多的归纳偏置
所以在中小型的数据集上训练的结果不如CNN也是可以理解的。既如此,transformer的全局建模能力比较强,而CNN又不用那么多的训练数据,那是否可以把这个模型的优势给结合起来呢?比如做一个混合网络,前头是CNN,后头是transformer呢,答案是:也是可以的! 但这是不是就类似上文介绍过的DETR呢?读者可以继续深入思考下。
// 待更
swin transformer作为多尺度的ViT更加适合处理视觉问题,且证明transformer不但能在ViT所证明的分类任务上取得很好的效果,在检测、分割上也能取得很好的效果,而在结构上,swin transformer主要做了以下两点改进
接下来,我们看下swin transformer中移动窗口的设计,图中灰色的小patch就是4✖️4的大小,然后最左侧的4个红色小窗口中均默认有7✖️7=49个小patch(当然,示意图中只展示了16个小patch),如果做接下来几个操作
则成为图中右侧所示的大窗口layer 1+1,从而使得之前互相独立不重叠的4个小窗口在经过这一系列shift操作之后,彼此之间可以进行互动做自注意力的计算了
貌似还是有点抽象是不?没事,我画个图 就一目了然了
如下所示,在右侧加粗的4个新的小窗口内部,每个小窗口都有其他小窗口的信息了(每个小窗口都由之前的单一颜色的patch组成,变成了由4种不同的颜色patch组成,相当于具备了全局的注意力,够直观吧?!)
以下是整个swin transformer模型的总览图
从左至右走一遍整个过程则是
整个前向传播过程走完了之后,可能有读者问,swin transformer如何做分类呢?它为了和CNN保持一致,没有像ViT在输入序列上加一个用于最后分类的CLS token,而是在得到最后的特征图之后,用了一个golbal average polling(即全局池化)的操作,直接把[7,7,768]中的7✖️1取平均并拉直成1,使得最终的维度变成[1,768]
//待更新..
知乎上关于扩散模型的几篇文章:全网最简单的扩散模型DDPM教程、Diffusion扩散模型大白话讲解、扩散生成模型: 唯美联姻物理概念与机器学习
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。