sora笔记(一):sora前世今生与技术梗概

:::info
💡 近日,OpenAI发布了视频生成模型Sora,最大的Sora模型能够生成一分钟的高保真视频。同时 OpenAI称,可扩展的视频生成模型,是构建物理世界通用模拟器的一条可能的路径。

**📃 **Sora能够生成横屏19201080视频,竖屏10801920视频,以及之间的所有内容。这使得Sora可 以兼容不同的视频播放设备,根据特定的纵横比来生成视频内容,这也会大大影响视频创作领域, 包括电影制作,电视内容,自媒体等。
:::
源地址为: Video generation models as world simulators

⛳️ ** 提示词:**一位时髦的女士穿行在东京的街头,街道充满了温暖的霓虹灯光和动感的城市标志。她穿着一 件黑色皮夹克,一条长红裙和黑色靴子,手拿一个黑色手提包。她戴着太阳镜和红色口红。她走路既自 信又随意。街道潮湿且能反射,创造出彩色灯光的镜面效果。许多行人来来往往。

演示效果如下:

title_0

当然,openai还展示了非常多的prompt,可以在Twitter或者上方链接中观看。

sora技术流程

根据魔搭社区所推测的sora技术架构图如下:

OpenAI训练了一个降低视觉数据维度的网络。这个网络接受原始视频作为输入,并输出在时间和空间上都被压缩的潜在表示。Sora在这个压缩的潜在空间上进行训练,并随后生成视频。同时还训练了一个相应的解码器模型,将生成的潜在表示映射回像素空间(源自Sora技术报告)。这部分内容为图中的红色部分。可见下图:
image.png

而其中的核心工作为将视觉数据转化为patches,patches是从大语言模型中获得的灵感,大语言模型范式的成功部分得益于使用优雅统一各种文本模态(代码、数学和各种自然语言)的token。大语言模型拥有文本token,而Sora拥有视觉分块(patches)。OpenAI在之前的Clip等工作中,充分实践了分块是视觉数据模型的一种有效表示(参考论文:An image is worth 16x16 words: Transformers for image recognition at scale.)这一技术路线。而视频压缩网络的工作就是将高维度的视频数据转换为patches,首先将视频压缩到一个低纬的latent space,然后分解为spacetime patches。

这个方法同样适用于图像(将图像作为单一帧视频处理),基于Patches的表示使得Sora能够训练具有不同分辨率,持续时间和纵横比的视频和图像,而在推理过程中,只需要在适当大小的grid中随机初始化patches即可控制视频生成的大小。

**技术难点:**视频压缩网络类比于latent diffusion model中的VAE,但是压缩率是多少,如何保证视频特征被更好地保留,还需要进一步的研究。

sora的前世今生

sora是一个diffusion模型,而扩散概念的提出是在2015年,并在2020年得到完善,提出了扩散模型DDPM,其是一种用于生成高质量图像的模型,其训练流程相对复杂但非常有效。以下是DDPM的训练流程和具体步骤:

  1. 定义可扩展步骤: DDPM使用马尔可夫链来定义可扩展的生成步骤。这意味着在每一步中,模型会逐渐生成图像的细节,使图像质量逐步提高。
  2. 改进Diffusion Models: DDPM对传统的diffusion模型进行了改进。传统的diffusion模型是通过对噪声进行预测来生成图像,而DDPM则更注重对噪声的预测,而不是直接生成图像,这有助于提高生成图像的质量和稳定性。
  3. 预测噪声而不是图片: 在DDPM中,模型的主要任务是预测噪声而不是直接生成图像。通过对噪声的预测,模型可以逐步生成图像的细节,从而得到高质量的图像输出。
  4. 使用Patch库: DDPM使用patch库将图像分割成小块,这有助于模型更好地处理图像的局部信息,并提高生成图像的质量。
  5. 向量操作: 模型使用ENOS库进行向量操作,以便更有效地处理图像数据,提高训练效率和生成图像的质量。

DDPM模型

整个过程的训练流程,即为:
image.png

其中,figure 2所提到的work主要分为两个step(加噪&去噪):

  1. 首先是Diffuison(前向扩散) : 简单来说就是对原始图片 x 0 x_{0} x0进行加噪操作为: q ( x t ∣ x t − 1 ) = N ( x t ; 1 − β x t − 1 , β t I ) q\left(x_{t} \mid x_{t-1}\right)=N\left(x_{t} ; \sqrt{1-\beta} x_{t-1}, \beta_{t} I\right) q(xtxt1)=N(xt;1β xt1,βtI) 文章中主要就是逐渐将高斯噪声加到img中,最后得到纯噪声: q ( x t ∣ x 0 ) = N ( x t ; α ˉ t x 0 , ( 1 − α ˉ t ) I ) q\left(\mathbf{x}_{t} \mid \mathbf{x}_{0}\right)=\mathcal{N}\left(\mathbf{x}_{t} ; \sqrt{\bar{\alpha}_{t}} \mathbf{x}_{0},\left(1-\bar{\alpha}_{t}\right) \mathbf{I}\right) q(xtx0)=N(xt;αˉt x0,(1αˉt)I)
  2. p θ p_{\theta} pθ反向去噪扩散: p θ ( x t − 1 ∣ x t ) = N ( X t − 1 ; μ θ ( x t , t ) , ∑ θ ( x t , t ) ) p_{\theta}\left(x_{t-1} \mid x_{t}\right)=N\left(X_{t-1} ; \mu_{\theta}\left(x_{t}, t\right), \sum_{\theta}\left(x_{t}, t\right)\right) pθ(xt1xt)=N(Xt1;μθ(xt,t),θ(xt,t)),即神经网络从纯噪声 Xt (T=1000 In raw paper) 开始对图像进行去噪,公式为:

μ θ ( x t , t ) = 1 α t ( x t − β t 1 − σ t ϵ θ ( x t , t ) ) \mu_{\theta}\left(\mathbf{x}_{t}, t\right)=\frac{1}{\sqrt{\alpha_{t}}}\left(\mathbf{x}_{t}-\frac{\beta_{t}}{\sqrt{1-\sigma_{t}}} \epsilon_{\theta}\left(\mathbf{x}_{t}, t\right)\right) μθ(xt,t)=αt 1(xt1σt βtϵθ(xt,t))

training

training实作上就是使用真实高斯噪声 μ t ( x t , x 0 ) \mu_{t}\left(x_{t}, x_{0}\right) μt(xt,x0) 和预测高斯噪声 μ θ ( x t , t ) \mu_{\theta}\left(x_{t}, t\right) μθ(xt,t) M S E MSE MSE优化
image.png

  • 随机抽样 x 0 ∼ q ( x 0 ) x_{0} \sim q\left(x_{0}\right) x0q(x0)
  • 采样 t ∼ Uniform ⁡ ( 1 , … , T ) t \sim \operatorname{Uniform}(1, \ldots, T) tUniform(1,,T)
  • 随机采样噪声 ϵ ∼ N ( 0 , I ) \epsilon \sim N(0, I) ϵN(0,I)
  • train神经网络(U-net) based on Loss
  • 目标函数 L t = ∥ ϵ − ϵ θ ( x t , t ) ∥ 2 = ∥ ϵ − ϵ θ ( α ˉ t x 0 + ( 1 − α ˉ t ) ϵ , t ) ∥ 2 L_{t}=\left\|\epsilon-\epsilon_{\theta}\left(\mathbf{x}_{t}, t\right)\right\|^{2}=\left\|\epsilon-\epsilon_{\theta}\left(\sqrt{\bar{\alpha}_{t}} \mathbf{x}_{0}+\sqrt{\left(1-\bar{\alpha}_{t}\right)} \epsilon, t\right)\right\|^{2} Lt=ϵϵθ(xt,t)2= ϵϵθ(αˉt x0+(1αˉt) ϵ,t) 2

需要理解的是生成模型使用U-net结构,在DDPM中需要生成器预测噪声的分布,但是此处我们可以把噪声看成数据的增广,因此我们需要一个具有强大能力的生成网络,而使用Unet相当于把模型结构规定,结构如下图:
image.png

以上即为DDPM的一个训练过程,这里列举前向扩散过程的code解析,即将噪声逐步添加到img中,正向过程的方差在本文中采用线性计划,将方差设为常数,定义beta schedule,之后为上述步骤描述,详细代码为:

timesteps = 200# define beta schedule
betas = linear_beta_schedule(timesteps=timesteps)# define alphas 
alphas = 1. - betas
alphas_cumprod = torch.cumprod(alphas, axis=0)
alphas_cumprod_prev = F.pad(alphas_cumprod[:-1], (1, 0), value=1.0)
sqrt_recip_alphas = torch.sqrt(1.0 / alphas)# calculations for diffusion q(x_t | x_{t-1}) and others
sqrt_alphas_cumprod = torch.sqrt(alphas_cumprod)
sqrt_one_minus_alphas_cumprod = torch.sqrt(1. - alphas_cumprod)# calculations for posterior q(x_{t-1} | x_t, x_0)
posterior_variance = betas * (1. - alphas_cumprod_prev) / (1. - alphas_cumprod)def extract(a, t, x_shape):batch_size = t.shape[0]out = a.gather(-1, t.cpu())return out.reshape(batch_size, *((1,) * (len(x_shape) - 1))).to(t.device)# forward diffusion (using the nice property)
def q_sample(x_start, t, noise=None):if noise is None:noise = torch.randn_like(x_start)sqrt_alphas_cumprod_t = extract(sqrt_alphas_cumprod, t, x_start.shape)sqrt_one_minus_alphas_cumprod_t = extract(sqrt_one_minus_alphas_cumprod, t, x_start.shape)return sqrt_alphas_cumprod_t * x_start + sqrt_one_minus_alphas_cumprod_t * noise

sampling

  • 利用 diffusion model生成新图像,从高斯分布 x T ∼ N ( 0 , I ) x_{T} \sim N(0, I) xTN(0,I) 采样纯噪声
  • 利用神经网络进行去噪(条件概率 p θ ( x t − 1 , x t ) p_{\theta}\left(x_{t-1}, x_{t}\right) pθ(xt1,xt)
  • 插入重参数化过的均值,逐步推导出去噪程度略低的图像 x t − 1 x_{t-1} xt1

image.png

下面的代码实现里这一过程(Simple Version | different from raw code):

@torch.no_grad()
def p_sample(model, x, t, t_index):betas_t = extract(betas, t, x.shape)sqrt_one_minus_alphas_cumprod_t = extract(sqrt_one_minus_alphas_cumprod, t, x.shape)sqrt_recip_alphas_t = extract(sqrt_recip_alphas, t, x.shape)# Equation 11 in the paper# Use our model (noise predictor) to predict the meanmodel_mean = sqrt_recip_alphas_t * (x - betas_t * model(x, t) / sqrt_one_minus_alphas_cumprod_t)if t_index == 0:return model_meanelse:posterior_variance_t = extract(posterior_variance, t, x.shape)noise = torch.randn_like(x)# Algorithm 2 line 4:return model_mean + torch.sqrt(posterior_variance_t) * noise # Algorithm 2 (including returning all images)
@torch.no_grad()
def p_sample_loop(model, shape):device = next(model.parameters()).deviceb = shape[0]# start from pure noise (for each example in the batch)img = torch.randn(shape, device=device)imgs = []for i in tqdm(reversed(range(0, timesteps)), desc='sampling loop time step', total=timesteps):img = p_sample(model, img, torch.full((b,), i, device=device, dtype=torch.long), i)imgs.append(img.cpu().numpy())return imgs@torch.no_grad()
def sample(model, image_size, batch_size=16, channels=3):return p_sample_loop(model, shape=(batch_size, channels, image_size, image_size))

那我们可以用一张比较形象的图进行总结,为:
image.png

sora模块拆解

根据上述DDPM模型中的介绍,可以将sora拆解为三个部分,为Visusal encoder、Diffusion TransformerTransformer Decoder下面就对其分别阐述。

Visusal encoder

Sora 之所以显得如此强大,在于以前的文本转视频方法需要训练时使用的所有图片和视频都要有相同的大小,这就需要大量的预处理工作来裁剪视频至适当的大小。而由于 Sora 是基于“Patch”而非视频的全帧进行训练的,它可以处理任何大小的视频或图片,无需进行裁剪。这就让 OpenAI 能够在大量的图像和视频数据上训练 Sora。因此,可以有更多的数据用于训练,得到的输出质量也会更高。例如,将视频预处理至新的长宽比通常会导致视频的原始构图丢失。一个在宽屏中心呈现人物的视频,裁剪后可能只能部分展示该人物。因为 Sora 能接收任何视频作为训练输入,所以其输出不会受到训练输入构图不良的影响。

输入的视频可以看成是NxHxW的若干帧图像, 通过Encoder被切分成spatial tempral patch,这些patch最终会被flatten成一维向量,送入diffusion model。其中,这里的patch的定义可以类比Vision Transformer中的patch,列举一个简单例子,可以定义一个patch类,最后展示为分割后的结果,代码为:

class Patches(L.Layer):def __init__(self, patch_size=PATCH_SIZE, **kwargs):super().__init__(**kwargs)self.patch_size = patch_sizeself.resize = L.Reshape((-1, patch_size * patch_size * 3))def call(self, images):patches = tf.image.extract_patches(images=images,sizes=[1, self.patch_size, self.patch_size, 1],strides=[1, self.patch_size, self.patch_size, 1],rates=[1, 1, 1, 1],padding="VALID",)patches = self.resize(patches)return patchesdef show_patched_image(self, images, patches):idx = np.random.choice(patches.shape[0])print(f"Index selected: {idx}.")plt.figure(figsize=(4, 4))plt.imshow(keras.utils.array_to_img(images[idx]))plt.suptitle('Original Image')plt.axis("off")plt.show()n = int(np.sqrt(patches.shape[1]))plt.figure(figsize=(4, 4))plt.suptitle('Patches')for i, patch in enumerate(patches[idx]):ax = plt.subplot(n, n, i + 1)patch_img = tf.reshape(patch, (self.patch_size, self.patch_size, 3))plt.imshow(keras.utils.img_to_array(patch_img))plt.axis("off")plt.show()return idxdef reconstruct_from_patch(self, patch):num_patches = patch.shape[0]n = int(np.sqrt(num_patches))patch = tf.reshape(patch, (num_patches, self.patch_size, self.patch_size, 3))rows = tf.split(patch, n, axis=0)rows = [tf.concat(tf.unstack(x), axis=1) for x in rows]reconstructed = tf.concat(rows, axis=0)return reconstructedimage_batch = next(iter(train_ds))augmentation_model = get_train_augmentation_model()
augmented_images = augmentation_model(image_batch)patch_layer = Patches()
patches = patch_layer(images=augmented_images)
random_index = patch_layer.show_patched_image(images=augmented_images, patches=patches)

而该方案来自于Vision Transformer论文,也是由此,让图像进入了transformer时代。下面为Vit的架构图:
image.png

  1. 只使用transformer的编码器部分,但区别在于如何将图像输入网络
  2. 将图像分解成固定大小的patches。可以是16x16或32x32,或者更大,但更多的patches意味着随着patches本身变得更小,训练这些网络变得更简单。
  3. 将patches展开(压平,即将二维转化为一维向量)并发送到网络中进行进一步处理。
  4. 与神经网络不同,这里的模型对样本在序列中的位置一无所知,这里的每个样本都是来自输入图像的一个patches。因此,图像被连同positional embedding vector一起提供到encoder中。这里需要注意的一点是位置嵌入也是可学习的,所以实际上不需要将硬编码的向量 w.r.t 提供给它们的位置。
  5. 在开始时还有一个特殊的标记,就像 BERT 一样。
  6. 将一维(压平)的patches组成一个大矢量,并得到乘以一个embedding矩阵,这也是可学习的,创建embedding patches。将这些与位置向量相结合,输入到transformer中。
  7. 前馈神经网络MLP Header,并获取到分类输出。

以上为图像级别的Vit构造,Sora的Encoder根据openai的资料来看可能是一个Video transformer,但是作为视频来讲,不同的分辨率输入在训练时候带来的是大量的计算负载不均衡,一个最简单的做法就是直接padding到固定大小这种做大会引入大量不必要的计算量。 从技术报告给出的参考文献来看,openAI最有可能是使用了 Google 的 Patch n’ Pack (NaViT)即多个patches打包成一个单一序列以实现可变分辨率技术降低计算量,支持动态分辨率视频作为输入。

此外NaViT还有一个对视频处理特别关键的优势。它可以根据图像相似度,丢掉雷同的图像块,实现更快的训练。而在视频里,本来帧与帧之间就有大量雷同的图像信息。因此,这样一个技术也可以帮助Sora在训练视频时丢弃掉大量雷同的内容,从而大幅降低训练视频的成本。

那么如何视频数据进行采样呢?有两种方式:

第一种,如下图所示,将输入视频划分为token的直接方法是从输入视频剪辑中均匀采样 n t n_t nt个帧,使用与ViT 相同的方法独立地嵌入每个2D帧(embed each 2D frame independently using the same method as ViT),并将所有这些token连接在一起。

具体地说,如果从每个帧中提取 n h ⋅ n w n_{h} \cdot n_{w} nhnw个非重叠图像块(就像 ViT 一样),那么总共将有 n t ⋅ n h ⋅ n w n_{t} \cdot n_{h} \cdot n_{w} ntnhnw 个token通过transformer编码器进行传递,这个过程可以被看作是简单地构建一个大的2D图像,以便按照ViT的方式进行tokenised:

第二种则是把输入的视频划分成若干个tuplet(类似不重叠的带空间-时间维度的立方体),每个tuplet会变成一个token(因这个tublelt的维度就是: t ∗ h ∗ w t * h * w thw 包含了时间、宽、高),经过spatial temperal attention进行空间和时间建模获得有效的视频表征token。

总结以上两种方法为,第一种是时空联合建模,通过spatial-tempral attention直接建模,这种方式在大数据量情况下效果最好,但是对于小的数据集,factorised方法将时间和空间解耦建模,相当于减少模型参数,会更容易训练和效果更好。基于openai大力出奇迹的惯性,我们推测他们采用了大量的数据,采用了时空联合建模的方式,进行了video encoder的训练。

Diffusion Transformer

Sora的主要作者是Peebles William,他在ICCV上发表了一篇DiT的工作,DiT = [VAE编码器 + ViT + DDPM + VAE解码器],但把DPPM中的卷积U-Net架构换成了transformer。这篇工作是通过结合diffusion model和transformer,从而达到可以scale up model来提升图像生成质量的效果,这篇文章是在technical report的reference中给出,直观来讲把图像的scaling技术运用到视频场景也非常直观,可以确定是Sora的技术之一。下图也是openai用以展示训练算力scale up后视频生成质量有所提升。

下图展示了Dit的主要原理,输入是一张256x256x3的图片,对图片做切patch后经过投影得到每个patch的token,得到32x32x4的latent(在推理时输入直接是32x32x4的噪声),结合当前的step t, 输入label y作为输入, 经过N个Dit Block通过mlp进行输出,得到输出的噪声以及对应的协方差矩阵,经过T个step采样,得到32x32x4的降噪后的latent。

Peebles, William, and Saining Xie. “Scalable diffusion models with transformers.” Proceedings of the IEEE/CVF International Conference on Computer Vision. 2023

还存在的技术难点

  1. 训练数据很重要,具体怎么构建?Transformer Scale up到多大?
  2. 是从头训练到收敛的trick嘛?
  3. 如何实现Long Context(长达1分钟的视频)的支持,这里猜测是切断+性能优化?
  4. 如何保证视频中实体的高质量和一致性?

reference

  1. https://datawhaler.feishu.cn/wiki/LxSCw0EyRidru1kFkttc1jNQnnh
  2. 最强文生视频模型 SORA 技术路线解读
  3. Denoising Diffusion Probabilistic Models(DDPM)

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode --- 长度最小的子数组(滑动窗口)

前言 滑动窗口算法是一种用于解决数组或者列表中子数组或者字串问题的方法,通常用于在给定数据上执行连续区间的操作,算法基本思想是维护一个固定大小或不定大小的窗口,通过移动窗口的起始位置和结束位置来遍历整个数据。在每个窗口位置&…

多态——细致讲解

🔶多态基础概念  🔶概念   🔱多态性   🔱多态——重新(覆盖)  🔶示例   🔶基本使用方法   🔶特例    🔱协变    🔱析构函数重写  🔱多态原理…

LaTeX-设置表格大小

文章目录 LaTeX-设置表格大小1.创建表格2.设置表格的宽度2.1控制表格每一列的宽度2.2控制整个表格的宽度 3.设置表格的外观4.LaTeX绘制三线表 LaTeX-设置表格大小 本文介绍了LaTeX如何设置表格的大小、改变表格的外观以及如何绘制三线表。 1.创建表格 在LaTeX中创建表很耗时…

算法修炼-动态规划之路径问题(1)

62. 不同路径 - 力扣(LeetCode) 思路:选定一个网格为终点,走到这个网格的所有走法就是这个网格的上面一个网格的所有走法加上这个网格左边一个网格的所有走法,然后做好初始化工作就行。 class Solution { public:int…

扼杀网络中的环路:STP、RSTP、MSTP

目录 前言: 一、STP(Spanning Tree Protocol) 1.1 STP功能 1.2 STP应用 二、RSTP(Rapid Spanning Tree Protocol) 2.1 RSTP功能 2.2 RSTP应用 三、MSTP(Multiple Spanning Tree Protocol&#xff0…

【中英对照】【自译】【精华】麻省理工学院MIT技术双月刊(Bimonthly MIT Technology Review)2024年3/4月刊内容概览

一、说明 Notation 仅供学习、参考,请勿用于商业行为。 二、本期封面、封底 Covers 本期杂志购于新加坡樟宜机场Changi Airport Singapore,售价为20.50新元。 本期仍然关注伦敦的AI大会。(笔者十分想去,在伦敦和MIT校园均设有会…

SpringBoot整合rabbitmq-扇形交换机队列(三)

说明:本文章主要是Fanout 扇形交换机的使用,它路由键的概念,绑定了页无用,这个交换机在接收到消息后,会直接转发到绑定到它上面的所有队列。 大白话:广播模式,交换机会把消息发给绑定它的所有队…

进程间的通信 -- 共享内存

一 共享内存的概念 1. 1 共享内存的原理 之前我们学过管道通信,分为匿名管道和命名管道,匿名管道通过父子进程的属性继承原理来完成父子进程看到同一份资源的目的,而命名管道则是通过路径与文件名来唯一标识管道文件,来让不同的进…

【系统分析师】-需求工程

一、需求工程 需求工程分为需求开发和需求管理。 需求开发:需求获取,需求分析,需求定义、需求验证。 需求管理:变更控制、版本控制、需求跟踪,需求状态跟踪。(对需求基线的管理) 1.1需求获取…

02-设计概述

上一篇:01-导言 本章重点讨论 JNI 中的主要设计问题。本节中的大多数设计问题都与本地方法有关。调用 API 的设计将在第 5 章:调用 API 中介绍。 2.1 JNI 接口函数和指针 本地代码通过调用 JNI 函数来访问 Java 虚拟机功能。JNI 函数可通过接口指针使用…

如何实现桌面美化

一.隐藏桌面图标 1. 在商店里下载TranslucentTB 二.设置底层图标 1.下载Nexus 打开官网: Winstep Nexus Dock and Nexus Ultimate - The Advanced Docking System for Windows 三.设置插件 1.打开致美化官网 致美化 - 最专业的视觉美化交流平台 (zhutix.com) 2.注…

MySQL进阶:全局锁、表级锁、行级锁总结

👨‍🎓作者简介:一位大四、研0学生,正在努力准备大四暑假的实习 🌌上期文章:MySQL进阶:MySQL事务、并发事务问题及隔离级别 📚订阅专栏:MySQL进阶 希望文章对你们有所帮助…