主流Text2Image技术学习

DDPM原理

DDPM(Denoising Diffusion Probabilistic Models)是一种生成模型,它通过模拟数据的扩散过程来生成新的数据样本。

DDPM通过一个随时间增加噪声的扩散过程和一个逐步去除噪声的生成过程来模拟数据分布。其核心在于训练一个去噪声模型,该模型学习如何从加噪声的数据中恢复原始数据。

这个过程分为两个主要部分:

  • 一个是扩散过程,它逐步将数据加噪声,直到数据完全转化为噪声;
  • 另一个是去噪声过程,它逐步从噪声中恢复出数据。

DDPM模型的训练目标是学习如何有效地进行去噪声,以便能够从随机噪声中生成高质量的数据样本。

扩散过程

贝叶斯公式

在这里插入图片描述

马尔可夫过程

扩散过程可以被视为一系列的马尔可夫链步骤,每一步都向数据中添加一定量的高斯噪声。

给定一个初始数据样本 x 0 x_0 x0,扩散过程可以表示为:

x t = α t x t − 1 + 1 − α t ϵ t x_t = \sqrt{\alpha_t} x_{t-1} + \sqrt{1 - \alpha_t} \epsilon_t xt=αt xt1+1αt ϵt

  • x t x_t xt:表示在时间步骤 t t t的数据。
  • x t − 1 x_{t-1} xt1:表示在时间步骤 t − 1 t-1 t1的数据。
  • ϵ t \epsilon_t ϵt是从标准正态分布 N ( 0 , I ) N(0, I) N(0,I)中采样的噪声
  • α t \alpha_t αt是一个介于0和1之间的预先定义的系数,用于控制噪声的加入程度 α t \alpha_t αt随时间递减,表示噪声量的增加。这个过程逐渐增加数据中的噪声,直到数据完全转化为噪声。

去噪声过程

去噪声过程的目标是学习一个模型,该模型能够预测给定带噪声数据 x t x_t xt时的原始数据 x 0 x_0 x0

这个过程可以被视为扩散过程的逆过程,目标是从简单的噪声分布中重建出原始数据,通过训练一个神经网络 ϵ θ \epsilon_\theta ϵθ来预测给定噪声数据 x t x_t xt时的噪声 ϵ \epsilon ϵ来实现。

在这个过程的开始,我们从标准正态分布中采样一个点 x T x_T xT 作为起点,即:

x T ∼ N ( 0 , I ) x_T \sim \mathcal{N}(0, \mathbf{I}) xTN(0,I)

这里的 N ( 0 , I ) \mathcal{N}(0, \mathbf{I}) N(0,I)表示均值为0,协方差矩阵为单位矩阵 I \mathbf{I} I的多维正态分布。这个采样点 x T x_T xT 将作为去噪过程的输入,通过模型逐步去除噪声,最终生成数据 x 0 x_0 x0

逆扩散迭代公式可以表示为:

x t − 1 = 1 α t ( x t − 1 − α t 1 − α ˉ t ϵ θ ( x t , t ) ) x_{t-1} = \frac{1}{\sqrt{\alpha_t}} (x_t - \frac{1-\alpha_t}{\sqrt{1-\bar{\alpha}_t}} \epsilon_\theta(x_t, t)) xt1=αt 1(xt1αˉt 1αtϵθ(xt,t))

其中:

  • x t − 1 x_{t-1} xt1:是我们希望恢复的,在时间步骤 t − 1 t-1 t1的去噪后的数据。
  • x t x_t xt:是当前步骤中的含噪数据。
  • α t \alpha_t αt:同上,控制每一步加入噪声的量。
  • α ˉ t \bar{\alpha}_t αˉt:是直到时间步骤 t t t的所有 α \alpha α值的累乘,表示到目前为止整体噪声量的累积。
  • ϵ θ ( x t , t ) \epsilon_\theta(x_t, t) ϵθ(xt,t):是神经网络预测的噪声,这个网络试图从噪声数据 x t x_t xt中恢复出原始的噪声 ϵ \epsilon ϵ

数据从 N ( 0 , 1 ) \mathcal{N}(0,1) N(0,1)的高斯分布中采样获得" 指的是初始化去噪过程的步骤,即从一个多维标准正态分布中采样一个起始点。

多维标准正态分布的概率密度函数(PDF)为:
p ( x ) = 1 ( 2 π ) d / 2 exp ⁡ ( − 1 2 x T x ) p(x) = \frac{1}{(2\pi)^{d/2}} \exp\left(-\frac{1}{2} x^T x\right) p(x)=(2π)d/21exp(21xTx)

其中, x x x 是一个 d d d维向量, d d d 是数据的维度, x T x^T xT x x x 的转置。

  • 这个分布有一个中心在原点,协方差矩阵为单位矩阵,意味着各个维度上的随机变量是独立且同分布的。

通过从这个分布中采样,我们可以得到一个随机向量 x T x_T xT,它的每个分量都是独立的标准正态分布变量。这个向量 x T x_T xT 是去噪过程的输入,模型将从这个噪声分布中逐步重建出原始数据。

训练目标

DDPM的训练目标是最小化去噪声过程中的预测噪声的误差,模型被训练来预测在每一步扩散过程中加入的噪声 ϵ t \epsilon_t ϵt,而不是直接预测原始数据 x 0 x_0 x0

这可以通过最小化以下损失函数来实现:

L = E t , x 0 , ϵ t [ ∣ ϵ t − ϵ θ ( x t , t ) ∣ 2 2 ] L = \mathbb{E}_{t, x_0, \epsilon_t}\left[ | \epsilon_t - \epsilon_\theta(x_t, t) |_2^2 \right] L=Et,x0,ϵt[ϵtϵθ(xt,t)22]

其中, ϵ θ ( x t , t ) \epsilon_\theta(x_t, t) ϵθ(xt,t)是模型对加入的噪声的预测, ϵ t \epsilon_t ϵt是实际加入的噪声, θ \theta θ表示模型参数。

模型推导

  1. 初始化:从训练数据中选择一个样本 x 0 x_0 x0作为扩散过程的起点。
  2. 扩散过程:通过上述扩散公式,逐步加入噪声,直到数据完全转化为噪声。
  3. 去噪声过程:使用模型 ϵ θ ( x t , t ) \epsilon_\theta(x_t, t) ϵθ(xt,t)来预测每一步中加入的噪声,并逐步从噪声数据中恢复出原始数据。
  4. 训练:通过最小化损失函数 L L L来训练模型,使其能够准确预测每一步中加入的噪声。
  5. DDPM通过这种方式训练生成模型,使其能够从纯噪声中生成高质量的数据样本。这个过程的关键在于,通过逐步加入和去除噪声,模型学习到了数据的内在结构和分布,从而能够生成新的、逼真的数据样本。

DDIM

DDIM的核心思想

DDIM的核心思想是改进生成过程,使其在每一步都显式地依赖于原始数据 x 0 x_0 x0,而非完全依赖于模型的去噪能力。这种方法允许模型在较少的步骤中更快地生成数据,因为它直接利用了关于原始数据的信息。

DDIM的去噪声过程

假设我们有一个噪声级别为 t t t的数据 x t x_t xt,DDIM的目标是计算一个更少噪声的版本 x t − 1 x_{t-1} xt1

与DDPM不同,DDIM使用一个确定性的映射而非条件高斯分布

这个映射可以表示为:

x t − 1 = α t − 1 ∗ x t − 1 − α t ϵ θ ( x t , t ) α t + 1 − α t − 1 ∗ ϵ θ ( x t , t ) x_{t-1} = \sqrt{\alpha_{t-1}} * {\frac{x_t - \sqrt{1-\alpha_t} \epsilon_\theta(x_t, t)}{\sqrt{\alpha_t}}} + \sqrt{1-\alpha_{t-1}} * \epsilon_\theta(x_t, t) xt1=αt1 αt xt1αt ϵθ(xt,t)+1αt1 ϵθ(xt,t)

其中, α t \alpha_t αt是预定义的噪声水平系数, ϵ θ ( x t , t ) \epsilon_\theta(x_t, t) ϵθ(xt,t)是模型预测的噪声,与DDPM中的相同。

逐项解释这个公式中的每个部分:

  • x t − 1 x_{t-1} xt1:这是我们希望计算的目标,即在时间步 t − 1 t-1 t1的数据。这个数据应该比 x t x_t xt有更少的噪声,我们通过应用确定性映射来计算它。

  • x t x_t xt:这是当前步骤中的数据,它包含了噪声级别为 t t t的信息。

  • α t \alpha_t αt α t − 1 \alpha_{t-1} αt1:这些是预定义的系数,它们与每一步中加入或去除的噪声量有关。这些系数帮助我们控制数据中噪声的量。在扩散过程中, α t \alpha_t αt是逐渐减小的,表示数据中噪声的增加。

  • 1 − α t \sqrt{1-\alpha_t} 1αt 1 − α t − 1 \sqrt{1-\alpha_{t-1}} 1αt1 :这些根号项代表噪声的标准差。它们说明了在每一步中,噪声是如何影响数据的。

  • ϵ θ ( x t , t ) \epsilon_\theta(x_t, t) ϵθ(xt,t):这是模型预测的噪声,即去噪声模型试图从 x t x_t xt中恢复出的噪声。这个预测用于帮助我们在去噪声过程中更准确地恢复出原始数据

这个公式的核心在于两个主要部分:

  • 去除噪声:首先,我们从当前的数据 x t x_t xt中去除预测的噪声 ϵ θ ( x t , t ) \epsilon_\theta(x_t, t) ϵθ(xt,t),这是通过 x t − 1 − α t ϵ θ ( x t , t ) α t \frac{x_t - \sqrt{1-\alpha_t} \epsilon_\theta(x_t, t)}{\sqrt{\alpha_t}} αt xt1αt ϵθ(xt,t)这部分实现的。这一步的目的是尽可能地恢复出在没有噪声 t t t的情况下的数据。

  • 添加适量噪声:然后,我们添加适当量的噪声以达到 t − 1 t-1 t1时刻的噪声水平,这是通过 1 − α t − 1 ϵ θ ( x t , t ) \sqrt{1-\alpha_{t-1}} \epsilon_\theta(x_t, t) 1αt1 ϵθ(xt,t)这部分实现的。这一步确保了我们不是简单地去除所有噪声,而是逐步接近原始数据的过程。

推导过程

  1. 从噪声中恢复:这一步是基于DDPM的去噪声模型,模型预测给定噪声数据 x t x_t xt时的噪声 ϵ \epsilon ϵ

  2. 确定性映射:与DDPM使用的随机过程不同,DDIM采用了一个确定性的映射来计算下一步的数据 x t − 1 x_{t-1} xt1。这种方法减少了生成过程中的随机性,允许更快地收敛。

算法优势

  • 效率:由于DDIM在每一步都直接利用了关于原始数据的信息,它可以在较少的步骤中生成数据,从而提高了效率。
  • 稳定性:确定性的映射减少了生成过程中的随机性,使得生成的数据更加稳定和一致。

Score-based

Score-based生成模型,也称为Score Matching模型,是一种基于能量的生成模型,它通过学习数据分布的梯度场(即分数函数)来生成新的样本。这个模型的核心是估计概率分布的分数,即概率密度函数对数据的梯度。以下是Score-based模型的基本推导。

假设我们有一个数据集 { x i } \{x_i\} {xi},数据点 x i x_i xi 从一个未知的数据生成分布 p data ( x ) p_{\text{data}}(x) pdata(x) 中采样得到。我们的目标是学习一个模型分布 p model ( x ; θ ) p_{\text{model}}(x; \theta) pmodel(x;θ),使其尽可能接近真实的数据分布 p data ( x ) p_{\text{data}}(x) pdata(x),其中 θ \theta θ 是模型参数。

在Score-based模型中,我们不直接学习 p model ( x ; θ ) p_{\text{model}}(x; \theta) pmodel(x;θ),而是学习数据分布的分数函数 s ( x ; θ ) s(x; \theta) s(x;θ),其中 s ( x ; θ ) = ∇ x log ⁡ p model ( x ; θ ) s(x; \theta) = \nabla_x \log p_{\text{model}}(x; \theta) s(x;θ)=xlogpmodel(x;θ)

Fisher得分匹配

为了学习分数函数,我们可以使用Fisher得分匹配(Fisher Score Matching)。其目标是最小化模型分数和数据分数之间的平方误差:

J ( θ ) = 1 2 E x ∼ p data ( x ) [ ∥ s ( x ; θ ) − ∇ x log ⁡ p data ( x ) ∥ 2 ] J(\theta) = \frac{1}{2} \mathbb{E}_{x \sim p_{\text{data}}(x)} \left[ \left\| s(x; \theta) - \nabla_x \log p_{\text{data}}(x) \right\|^2 \right] J(θ)=21Expdata(x)[s(x;θ)xlogpdata(x)2]

然而, ∇ x log ⁡ p data ( x ) \nabla_x \log p_{\text{data}}(x) xlogpdata(x) 通常是未知的,所以我们不能直接优化这个目标函数。一个解决方案是使用分数函数的定义和积分的链式法则来重写目标函数,得到一个只依赖于模型分数的目标函数:

J ( θ ) = 1 2 E x ∼ p data ( x ) [ ∥ s ( x ; θ ) ∥ 2 ] − E x ∼ p data ( x ) [ div   s ( x ; θ ) ] + const J(\theta) = \frac{1}{2} \mathbb{E}_{x \sim p_{\text{data}}(x)} \left[ \left\| s(x; \theta) \right\|^2 \right] - \mathbb{E}_{x \sim p_{\text{data}}(x)} \left[ \text{div} \, s(x; \theta) \right] + \text{const} J(θ)=21Expdata(x)[s(x;θ)2]Expdata(x)[divs(x;θ)]+const

其中 div   s ( x ; θ ) \text{div} \, s(x; \theta) divs(x;θ) 是分数函数的散度,也被称为Stein’s Unbiased Risk Estimator (SURE)。

优化

在实践中,我们通常使用一个参数化的模型(如神经网络)来表示分数函数 s ( x ; θ ) s(x; \theta) s(x;θ),并使用随机梯度下降(SGD)或其变体来最小化目标函数 J ( θ ) J(\theta) J(θ)

生成样本

一旦我们学习到了分数函数 s ( x ; θ ) s(x; \theta) s(x;θ),就可以使用Langevin动力学来生成新的样本。从一个随机初始化的点 x 0 x_0 x0 开始,我们可以迭代地应用以下更新规则:

x t + 1 = x t + ϵ 2 2 s ( x t ; θ ) + ϵ z t , z t ∼ N ( 0 , I ) x_{t+1} = x_t + \frac{\epsilon^2}{2} s(x_t; \theta) + \epsilon z_t, \quad z_t \sim \mathcal{N}(0, I) xt+1=xt+2ϵ2s(xt;θ)+ϵzt,ztN(0,I)

其中 ϵ \epsilon ϵ 是一个小的步长, z t z_t zt 是从标准正态分布中采样的噪声。

通过这个迭代过程,我们可以从噪声中生成出符合数据分布的样本。

请注意,这里的推导是非常高层次的概述,具体实现中会有更复杂的细节,比如如何选择合适的学习率、如何确保数值稳定性、如何处理高维数据等。此外,实际应用中还会涉及到更高级的技术,如变分下界的优化、随机微分方程的应用等。

CLIP

预训练任务:即预测哪个文本描述对应当前图像
代码流程:
在这里插入图片描述
Given a batch of N (image, text) pairs, CLIP is trained to predict which of the N × N possible (image, text) pairings across a batch actually occurred.

  • 学习联合表征向量:CLIP learns a multi-modal embedding space by jointly training an image encoder and text encoder

  • N个真实的pair:to maximize the cosine similarity of the image and text embeddings of the N real pairs in the batch

  • N 2 − N N^2 − N N2N to minimizie the cosine similarity of the embeddings of the N 2 − N N^2 − N N2N incorrect pairings.

  • InfoNCE 对比损失:We optimize a symmetric cross entropy loss over these similarity scores

在这里插入图片描述

CLIP的改动:

  • CLIP去掉了ConVIRT中text transformation(指均匀从text中采样句子),因为CLIP数据集中有很多只出现过一次的(image,text);
  • CLIP的image transformation只用了resize和squared crop;
  • CLIP loss中的temperature参数τ是可学的

LLaVA

架构

在这里插入图片描述

  • 输入的图片使用CLIP预训练的ViT编码,然后通过一个线性层W(可训练的)映射到语言空间(变成token和文本的token进行拼接)
  • 和minigpt4的区别是不需要复杂的Q-Former结构,但是需要微调语言模型,minigpt不需要训练语言模型。

训练:

训练过程主要分为两轮:

(1)Pre-training for Feature Alignment,frozen视觉vit和语言llm模型,从CC3M数据中过滤了595K图像-文本对,Xinstruct是单轮训练,只训练Project W权重

(2)Fine-tuning End-to-End,只frozen视觉的vit权重,更新Project和LLM大语言模型的权重。分成2个任务:

  • 多模态chatbot:
    用158K的数据训练(其中58K对话数据、23K详细描述、77K复杂推理),分成3种问答形式(Conversion,Detailed description,Complex reasoning),其中Conversion采用多轮对话形式,其他采用单轮。

  • Science QA:采用单轮问答形式训练。
    在这里插入图片描述

  • 输入模版,只在response上计算loss
    在这里插入图片描述

GLIDE

  • 代码开源

两种不同的引导策略:CLIP Guide和Classifier-Free Guide。

  • 实验发现,Classifier-Free Guide在人类评估者眼中无论是在照片真实感还是标题相似性方面都更受青睐,并且能够产生逼真的样本。

Classifier-Free Guide策略的优点是不需要单独训练一个分类器,仅需将类别标签替换为一个空标签,并将标签预测概率的梯度替换为基于文本标签与空标签之间条件分布的差异
在这里插入图片描述
CLIP Guide 则是通过对无条件扩散模型预测的噪声应用梯度修正来实现:
在这里插入图片描述

代码

  • https://github.com/openai/glide-text2im/blob/main/glide_text2im/xf.py

  • token embedding:Transformer + 一个全连接层进行编码

  • postion embedding:可学习的,直接和token embedding相加

  • timestep embedding:再和加完postion后的token emb相加,由残差块和注意力块组成

  • 上采样是插值,下采样是卷积

  • 注意力层的qkv空间位置编码

Unet

  • Unet结构(都带上timestep embedding):
    • 每层input_block:残差块+注意力块,最后一个是残差块+下采样块
    • 每层middle_block:残差块+注意力块 + 残差块
    • 每层output_block:残差块+注意力块,最后一个是残差块+上采样块
 def forward(self, x, timesteps, y=None):
        """
        Apply the model to an input batch.

        :param x: an [N x C x ...] Tensor of inputs.
        :param timesteps: a 1-D batch of timesteps.
        :param y: an [N] Tensor of labels, if class-conditional.
        :return: an [N x C x ...] Tensor of outputs.
        """
        assert (y is not None) == (
            self.num_classes is not None
        ), "must specify y if and only if the model is class-conditional"

        hs = []
        emb = self.time_embed(timestep_embedding(timesteps, self.model_channels))

        if self.num_classes is not None:
            assert y.shape == (x.shape[0],)
            emb = emb + self.label_emb(y)# time emb + label emb

        h = x.type(self.dtype)
        for module in self.input_blocks:
            h = module(h, emb)
            hs.append(h)
        h = self.middle_block(h, emb)
        for module in self.output_blocks:
            h = th.cat([h, hs.pop()], dim=1)
            h = module(h, emb)
        h = h.type(x.dtype)
        return self.out(h)

timestep embedding


def timestep_embedding(timesteps, dim, max_period=10000):
    """
    Create sinusoidal timestep embeddings.

    :param timesteps: a 1-D Tensor of N indices, one per batch element.
                      These may be fractional.
    :param dim: the dimension of the output.
    :param max_period: controls the minimum frequency of the embeddings.
    :return: an [N x dim] Tensor of positional embeddings.
    """
    half = dim // 2
    freqs = th.exp(
        -math.log(max_period) * th.arange(start=0, end=half, dtype=th.float32) / half
    ).to(device=timesteps.device)
    args = timesteps[:, None].float() * freqs[None]
    embedding = th.cat([th.cos(args), th.sin(args)], dim=-1)
    if dim % 2:
        embedding = th.cat([embedding, th.zeros_like(embedding[:, :1])], dim=-1)
    return embedding


class TimestepEmbedSequential(nn.Sequential, TimestepBlock):
    """
    A sequential module that passes timestep embeddings to the children that
    support it as an extra input.
    为了每一步都带上time embedding
    """

    def forward(self, x, emb, encoder_out=None):
        for layer in self:
            if isinstance(layer, TimestepBlock):
                x = layer(x, emb)
            elif isinstance(layer, AttentionBlock):
                x = layer(x, encoder_out)
            else:
                x = layer(x)
        return x

MultiheadAttention代码

class MultiheadAttention(nn.Module):
    def __init__(self, n_ctx, width, heads):
        super().__init__()
        self.n_ctx = n_ctx
        self.width = width
        self.heads = heads
        self.c_qkv = nn.Linear(width, width * 3)
        self.c_proj = nn.Linear(width, width)
        self.attention = QKVMultiheadAttention(heads, n_ctx)

    def forward(self, x):
        x = self.c_qkv(x)
        x = self.attention(x)
        x = self.c_proj(x)
        return x
        
class QKVMultiheadAttention(nn.Module):
    def __init__(self, n_heads: int, n_ctx: int):
        super().__init__()
        self.n_heads = n_heads
        self.n_ctx = n_ctx

    def forward(self, qkv):
        bs, n_ctx, width = qkv.shape
        attn_ch = width // self.n_heads // 3
        scale = 1 / math.sqrt(math.sqrt(attn_ch))
        qkv = qkv.view(bs, n_ctx, self.n_heads, -1)
        q, k, v = th.split(qkv, attn_ch, dim=-1)
        weight = th.einsum(
            "bthc,bshc->bhts", q * scale, k * scale
        )  # More stable with f16 than dividing afterwards
        wdtype = weight.dtype
        weight = th.softmax(weight.float(), dim=-1).type(wdtype)
        return th.einsum("bhts,bshc->bthc", weight, v).reshape(bs, n_ctx, -1)

MLP和Res


class ResidualAttentionBlock(nn.Module):
    def __init__(
        self,
        n_ctx: int,
        width: int,
        heads: int,
    ):
        super().__init__()

        self.attn = MultiheadAttention(
            n_ctx,
            width,
            heads,
        )
        self.ln_1 = LayerNorm(width)
        self.mlp = MLP(width)
        self.ln_2 = LayerNorm(width)

    def forward(self, x: th.Tensor):
        x = x + self.attn(self.ln_1(x))
        x = x + self.mlp(self.ln_2(x))
        return x
        
 class MLP(nn.Module):
    def __init__(self, width):
        super().__init__()
        self.width = width
        self.c_fc = nn.Linear(width, width * 4)
        self.c_proj = nn.Linear(width * 4, width)
        self.gelu = nn.GELU()

    def forward(self, x):
        return self.c_proj(self.gelu(self.c_fc(x)))

class Transformer(nn.Module):
    def __init__(
        self,
        n_ctx: int,
        width: int,
        layers: int,
        heads: int,
    ):
        super().__init__()
        self.n_ctx = n_ctx
        self.width = width
        self.layers = layers
        self.resblocks = nn.ModuleList(
            [
                ResidualAttentionBlock(
                    n_ctx,
                    width,
                    heads,
                )
                for _ in range(layers)
            ]
        )

    def forward(self, x: th.Tensor):
        for block in self.resblocks:
            x = block(x)
        return x

超分代码

class SuperResText2ImUNet(Text2ImUNet):
    """
    A text2im model that performs super-resolution.
    Expects an extra kwarg `low_res` to condition on a low-resolution image.
    """

    def __init__(self, *args, **kwargs):
        if "in_channels" in kwargs:
            kwargs = dict(kwargs)
            kwargs["in_channels"] = kwargs["in_channels"] * 2
        else:
            # Curse you, Python. Or really, just curse positional arguments :|.
            args = list(args)
            args[1] = args[1] * 2
        super().__init__(*args, **kwargs)
"""
def forward(self, x, timesteps, low_res=None, **kwargs):

x 是输入的高分辨率特征,timesteps 是时间步参数,low_res 是可选的低分辨率图像。

代码将低分辨率图像 low_res 上采样到与 x 相同的高度和宽度。
上采样使用双线性插值方法(mode="bilinear"),并且 align_corners=False 指定了插值的一种特定方式。

通过 th.cat([x, upsampled], dim=1),将上采样后的低分辨率图像与输入特征 x 在通道维度上(dim=1)拼接。

最后,使用 super().forward(x, timesteps, **kwargs) 调用父类的 forward 方法,并将拼接后的特征图传递进去,完成前向传播。

总的来说,这个类的目的是结合低分辨率图像和其他可能的输入特征(如文本描述),通过超分辨率模型生成高分辨率的图像。这个过程通常用于图像生成任务,其中文本描述帮助模型理解要生成的图像内容,而低分辨率图像提供了一个粗略的视觉基础。

"""
    def forward(self, x, timesteps, low_res=None, **kwargs):
        _, _, new_height, new_width = x.shape
        upsampled = F.interpolate(
            low_res, (new_height, new_width), mode="bilinear", align_corners=False
        )
        x = th.cat([x, upsampled], dim=1)
        return super().forward(x, timesteps, **kwargs)

图像修复

"""
执行修复操作:

使用 inpaint_mask 乘以 inpaint_image 来应用掩码,只保留需要修复的区域的图像信息。
其他区域(掩码值为0的区域)将被置为0。

使用 th.cat([x, inpaint_image * inpaint_mask, inpaint_mask], dim=1) 将输入图像 x、处理后的待修复图像区域(inpaint_image * inpaint_mask)、以及掩码 inpaint_mask 在通道维度上(dim=1)拼接起来。这一步骤将原始图像、修复内容和修复区域的信息合并,为模型提供了完整的上下文信息。
"""
def forward(self, x, timesteps, inpaint_image=None, inpaint_mask=None, **kwargs):
        if inpaint_image is None:
            inpaint_image = th.zeros_like(x)
        if inpaint_mask is None:
            inpaint_mask = th.zeros_like(x[:, :1])
        return super().forward(
            th.cat([x, inpaint_image * inpaint_mask, inpaint_mask], dim=1),
            timesteps,
            **kwargs,
        )
    def forward(
        self,
        x,
        timesteps,
        inpaint_image=None,
        inpaint_mask=None,
        low_res=None,
        **kwargs,
    ):
        if inpaint_image is None:
            inpaint_image = th.zeros_like(x)
        if inpaint_mask is None:
            inpaint_mask = th.zeros_like(x[:, :1])
        _, _, new_height, new_width = x.shape
        upsampled = F.interpolate(
            low_res, (new_height, new_width), mode="bilinear", align_corners=False
        )
        return super().forward(
            th.cat([x, inpaint_image * inpaint_mask, inpaint_mask, upsampled], dim=1),
            timesteps,
            **kwargs,
        )

DALL-E

  • 阶段1:先训练一个离散变分自编码器(dVAE),将每张256×256的RGB图像压缩成32×32网格的图像标记,每个标记可以取8192个可能的值。这样做将tranformer的上下文大小减少了192倍,而视觉生成质量没有大幅下降。

  • 阶段2:将多达256个BPE编码的文本标记与1024个图像标记(32×32)连接起来,然后训练一个自回归tranformer来模拟文本和图像标记的联合分布。

在这里插入图片描述

  1. 文本编码:DALL·E首先利用其BPE编码器将输入的文本描述转换成一组嵌入向量。

  2. 自回归生成:然后,这些嵌入向量被送入Transformer模型,在自回归的方式下生成图像标记,之后通过离散变分自编码器(dVAE)的解码器解码,生成对应的图像。

  3. 后处理:最终,通过预先训练好的CLIP模型计算文本描述与生成图像之间的匹配得分,并保留那些匹配得分较高的图像。

  4. BPE(Byte Pair Encoding)编码器是一种通过迭代合并频繁出现的字符或字符序列来构建词汇表的方法,这种方法可以有效地处理词汇表外的单词,以及应对语言中的形态变化。

DALL-E 2

  • https://zhuanlan.zhihu.com/p/526438544

整体架构

对比学习模型,如CLIP,能够学习到鲁棒的、富含语义和风格的图像表示。为了将这些强有力的图像表示应用于图像生成中,作者提出了一个两阶段模型DALL-E 2:

  • 第一阶段:一个先验模型,它可以根据文本标题生成CLIP图像嵌入。以文本为输入,经过CLIP模型,得到图像表示,以此作为先验知识。
  • 第二阶段:解码器,它依赖于图像嵌入来生成图像。基于第一阶段的图像表示,经过解码器,生成符合文本描述的图像内容。

在这里插入图片描述

  • 具体训练过程:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 论文整体原图,需要分步骤解读

在这里插入图片描述

先验知识

尽管解码器可以将CLIP图像嵌入 z i z_i zi转换回图像x,但我们仍需要一个先验模型,它能够根据文本描述 y y y生成 z i z_i zi,这样才能实现从文本描述生成图像的功能

两种策略:

  • 为了改善采样质量,对 AR and diffusion的先验知识同时随机drop掉10%的文本控制信息

(1)自回归模型先验:将CLIP图像向量 z i z_i zi转换为一个离散code序列,然后以文本 y y y作为条件约束 ,进行预测。

  • 为了更有效地从自回归先验中训练和采样,对应用主成分分析PCA进行降维处理。
  • 为什么能进行降维呢?
    作者发现,当使用SAM训练CLIP时,CLIP表示空间的秩急剧下降且验证指标稍有提升。相比原来的1024维,仅保留319个主成分,就能保存将近所有的信息。
  • 将文本caption的自回归先验知识和CLIP文本向量进行编码作为Prefix,进而达到约束自回归先验的目的。
  • 以文本向量 z i z_i zi和图像向量 z t z_t zt的点积约束模型,在更高的点积条件下训练模型,因为较高的文本与图像点积意味着标题更能准确地描述图像。在实际应用中,我们发现从分布的点积前一半(top half)对点积进行采样是有帮助的。

(2)扩散模型先验:使用高斯扩散模型直接建模连续向量 z i z_i zi

使用 the encoded text, the CLIP text embedding, an embedding for the diffusion timestep,the noised CLIP image embedding, and a final embedding 来预测 the unnoised CLIP image embedding

  • 没有使用文本和图像的点积,采样生成两个图像向量 z i z_i zi选择与文本向量 z i z_i zi点积更高的那个图像 z i z_i zi
  • 预测中使用均方误差作为损失函数

Decoder

使用约束信息作为指导能极大地提升采样质量。

  • 因而,作者使用classifier-free guidance,通过对10%的时间序列随机设置CLIP向量为0或是可学习的向量为0,以及随机失活50%的文本信息

为了生成高分辨率图像,作者训练了两个扩散上采样模块:

  • 一个用于将64x64分辨率上采样到256x256
  • 另一个进一步将256x256分辨率上采样到1024x1024

为了提升上采样模块的鲁棒性,在训练时,分别使用高斯模糊、BSR弱化等处理手段。

text2img

尽管我们训练了一个先验模型来从标题生成CLIP图像嵌入,但这个先验模型对于标题到图像的生成并不是绝对必要的。

  1. 我们的解码器可以同时基于CLIP图像嵌入和标题进行条件化,但在训练过程中,CLIP图像嵌入有5%的时间会被丢弃,以实现无分类器引导。
  2. 在采样时,我们可以仅基于标题进行条件化,尽管这种方式的性能不如完全以此方式训练的模型(三种里面效果最差)
  3. 另一种可能是将CLIP文本嵌入作为图像嵌入输入给解码器
  4. 另一种方法是将解码器训练为基于CLIP文本嵌入[9]而不是CLIP图像嵌入进行条件化(尽管我们会失去第4节提到的能力)

我们训练了两个模型:

  • 一个基于CLIP文本嵌入的小型解码器
  • 一个小型非CLIP堆栈(扩散先验和解码器)效果好

DALL-E 3

DALL-E 3的这篇技术报告重点是放在了如何通过合成图像的文本描述(caption)来提升模型的prompt following能力,即生成的图像和输入的text prompt的一致性)

  • text2img模型的问题:模型无法生成文本所描述的图像

这个问题主要还是由于训练数据集的图像caption不够准确

  • 一方面,图像常规的文本描述往往过于简单(比如COCO数据集),它们大部分只描述图像中的主体而忽略图像中其它的很多信息,比如背景,物体的位置和数量,图像中的文字等。
  • 一方面,图文pair数据质量不够高。目前训练文生图的图像文本对数据集(比如LAION数据集)都是从网页上爬取的,图像的文本描述其实就是alt-text,但是这种文本描述很多是一些不太相关的东西,比如广告

Openai的解决方案:训练一个image captioner(CoCa)来合成图像的caption

在这里插入图片描述

  • 其中一点是合成caption对文生图模型性能的影响
  • 另外一点是探讨训练过程中合成caption和原始caption的最佳混合比例
    • 只用原始caption
    • 5%的原始caption+95%的合成短caption
    • 5%的原始caption+95%的合成长caption

如何评估?
验证模型的prompt following能力,所以采用了CLIP score来评价模型,这里的CLIP score是基于CLIP ViT-B/32来计算生成图像的image embedding和text prompt对应的text embedding的余弦相似度

结论

  1. 长caption > 短caption > 原始caption
  2. 混合比例为95%为最佳
  3. 由于采用长captin训练的latent diffusion模型,在实际用户输入中大多是短caption,所以使用GPT4将短caption改写成长caption
  4. DALL-E 3的模型应该类似于SDXL,采用递进式的训练策略(256 -> 512 -> 1024),而且最后也是采用了多尺度训练策略来使模型能够输出各种长宽比的图像
  5. DALL-E 3额外训练了一个latent decoder(替换原始的VAE decoder)来提升图像的细节,特别是文字和人脸方面,这个应该是为了解决VAE所产生的图像畸变。这个pixel level扩散模型的condition是VAE的latent

存在的问题

  • 模型在空间位置关系上还是会比较容易出错,当prompt包含一些位置关系描述如"to the left of",模型生成的图像并不一定会符合这样的位置关系,这主要是因为合成的caption在这方面也并不可靠
  • 文字生成能力有限。出现多词或者少词的情况,一个可能的原因T5-XXL的tokenizer并不是字符级
  • 合成的caption会幻想图像中的重要细节,比如给一幅植物的绘图,image captioner可能会虚构出一个植物并体现在合成的caption上。

Coca

CoCa在解码器层的前半部分省略了跨注意力机制,以编码单模态文本表示,并将剩余的解码器层级联起来,这些层跨关注图像编码器以生成多模态图像-文本表示。

我们在单模态图像和文本嵌入之间应用对比损失,同时在多模态解码器输出上应用字幕损失,后者预测文本标记自回归地生成。通过共享相同的计算图,这两个训练目标可以高效地计算,开销最小。

  • CoCa从头开始端到端预训练,既使用了网络规模的替代文本数据,也使用了标注图像,将所有标签简单地视为文本,无缝地统一了表示学习的自然语言监督。

在这里插入图片描述

  • 单模态图像和文本嵌入之间使用对比损失
  • 在多模态解码器输出上使用text caption 交叉熵损失

Stable Diffusion

Stable Diffusion是一种基于扩散模型的生成模型,它能够生成高质量的图像,并且支持条件生成,比如根据文本描述生成图像。Stable Diffusion结合了扩散模型和变分自编码器(Variational Autoencoder, VAE)的特点,通过一个精心设计的反向过程生成数据。以下是Stable Diffusion的主要原理和组成部分:

原理概述

  1. 扩散过程:Stable Diffusion的基础是扩散模型,这种模型通过逐步添加噪声将数据(如图像)转换成无结构的噪声。具体来说,这个过程通过多个步骤逐渐增加噪声,每一步都基于高斯分布添加噪声,直到数据完全转变为噪声。

  2. 变分自编码器(VAE):Stable Diffusion使用VAE来学习数据的压缩表示,这有助于提高模型的效率和生成质量。在扩散过程的开始,使用VAE编码的图像而不是原图,这样可以减少扩散模型需要处理的数据复杂度。

  3. 去噪过程:与扩散过程相反,去噪过程从噪声中恢复出原始数据。这一过程是通过训练一个神经网络(通常是一个Transformer模型)来完成的,该网络学习如何在每一步中预测并去除噪声,最终恢复出接近原始数据的图像。

  4. 文本到图像生成:Stable Diffusion通过将文本嵌入作为条件信息输入到去噪过程中,实现了根据文本描述生成图像的功能。这通过使用预训练的文本嵌入模型(如CLIP)来实现,它能够将文本描述转换成与图像内容相关联的嵌入向量。

关键技术和特点

  • CLIP引导:Stable Diffusion使用OpenAI开发的CLIP模型来理解文本和图像之间的关系,这使得它能够根据文本提示生成与之高度相关的图像。

  • 去噪预测网络:该网络是Stable Diffusion的核心,负责在去噪过程中预测每一步应该去除多少噪声,以逐步恢复出清晰的图像。

  • 高效性和灵活性:Stable Diffusion设计用于高效生成高质量的图像,同时支持多种生成任务,包括条件生成(如文本到图像)、图像到图像转换、图像编辑等。

Diffusion Guidance

Diffusion Model (例如,DDPM)的主要任务是无条件生成图像。如果想控制生成的图像内容就需要conditional diffusion model。

Conditional diffusion model 将额外的条件信息(例如,类别信息,文本)作为模型的输入来学习。那么目前就有两种对diffusion model进行引导的方法。Classifier Guidance 和 Classifier-free guidance。

DDPM + Classifier Guidance

Classifier Guidance核心思路:

  • 在diffusion model逆向过程的每一步,用另外一个分类网络对生成的图片进行分类。
  • 再基于分类分数和目标类别之间的交叉熵损失计算梯度,用该梯度引导下一步的生成采样。
    在这里插入图片描述

在这里插入图片描述

  • s是分类器的缩放因子,变化的部分就是加上的这个分类器梯度
    在这里插入图片描述
  • 改变的是采样的分布
    在这里插入图片描述

DDPM + Classifier (CLIP) Guidance

上面的Classifier Guidance针对的是类别条件,那把分类器替换成CLIP就可以做文本引导的diffusion model。

  • 用类别分类器引导:将diffusion model逆过程每一步产生的输入到分类器中得到预测类别的概率与groundturth的类别做交叉熵,再得到梯度信息。

  • 用CLIP引导:将diffusion model逆过程每一步产生的输入到CLIP的image encoder中,将文本条件输入到CLIP的text encoder中计算两者的相似度,再得到梯度信息。

DDIM + Classifier Guidance

在这里插入图片描述

在这里插入图片描述

Classifier-Free Diffusion Guidance

Classifier Guidance 使用显式的分类器引导条件生成有几个问题:

  • 一是需要额外训练一个噪声版本的图像分类器。
  • 二是该分类器的质量会影响按类别生成的效果。
  • 三是通过梯度更新图像会导致对抗攻击效应,生成图像可能会通过人眼不可察觉的细节欺骗分类器,实际上并没有按条件生成。

在这里插入图片描述
Classifier-Free Guidance的核心是通过一个隐式分类器来替代显示分类器,而无需直接计算显式分类器及其梯度。

根据贝叶斯公式,分类器的梯度可以用条件生成概率和无条件生成概率表示
在这里插入图片描述
训练时,Classifier-Free Guidance需要训练两个模型:

  • 一个是无条件生成模型,另一个是条件生成模型。但这两个模型可以用同一个模型表示,训练时只需要以一定概率将条件置空即可。

详细公式

  • 苏神文章:https://kexue.fm/archives/9257/comment-page-1

基本原理
在CFG中,模型被训练来理解如何在给定特定条件(如文本描述)时生成数据,同时也学习如何在没有任何条件的情况下生成数据。

  • 生成时,通过调整条件生成和无条件生成之间的平衡,可以引导模型偏向于生成满足特定条件的数据,而无需外部分类器。

公式推导
假设我们有一个条件 ©(例如文本描述),我们想要生成满足这个条件的数据 (x)。

  • 我们首先有一个条件生成的概率分布 p ( x ∣ c ) p(x|c) p(xc),表示在给定条件 © 下生成数据 (x) 的概率。
  • 同时,我们也有一个无条件生成的概率分布 p ( x ) p(x) p(x),表示在没有任何条件的情况下生成数据 (x) 的概率。

在CFG中,生成过程是通过调整这两种分布之间的平衡来进行的。具体来说,我们通过引入一个超参数 (w) 来调整这两种模式的权重,生成的新分布可以表示为:

p cfg ( x ∣ c ) ∝ p ( x ∣ c ) ∗ w ⋅ p ( x ) ∗ ( 1 − w ) p_{\text{cfg}}(x|c) \propto p(x|c) * w \cdot p(x)*{(1-w)} pcfg(xc)p(xc)wp(x)(1w)

其中,(w) 是一个大于1的权重,用于控制条件生成和无条件生成之间的平衡。当 (w=1) 时,CFG退化为纯条件生成;随着 (w) 增大,生成过程更加关注于满足条件 ©。

在实践中,我们通常不直接计算上述公式,而是通过调整生成过程中的梯度来实现。给定一个目标(如最小化与目标分布的KL散度),我们可以调整反向过程中的梯度更新步骤,使得在每一步的更新中,生成的数据既考虑到满足条件 © 的需求,也保留了一定程度的随机性(无条件生成的特性)。

Transformer扩散模型 - DiT

  • DiT详解
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    (1)In-context conditioning
    (2)Cross-attention block
    (3)Adaptive layer norm (adaLN) block
    (4)AdaLN-Zero block
    (5)DiT scaling

AdaLN

LN的目的是减少训练过程中的内部协变量偏移,通过规范化每个样本在网络层内的激活值来加速训练并提高模型的稳定性。

下面是Layer Normalization的基本数学公式:

给定一个小批量的数据,其中包含(N)个样本,每个样本具有(M)个特征(对于一个给定的层)。对于该层的每个样本 x i x_i xi(其中 i = 1 , 2 , . . . , N i = 1, 2, ..., N i=1,2,...,N),Layer Normalization首先计算该样本的均值 μ i \mu_i μi和方差 σ i 2 \sigma_i^2 σi2

μ i = 1 M ∑ j = 1 M x i j \mu_i = \frac{1}{M} \sum_{j=1}^{M} x_{ij} μi=M1j=1Mxij

σ i 2 = 1 M ∑ j = 1 M ( x i j − μ i ) 2 \sigma_i^2 = \frac{1}{M} \sum_{j=1}^{M} (x_{ij} - \mu_i)^2 σi2=M1j=1M(xijμi)2

其中, x i j x_{ij} xij是第 i i i个样本的第 j j j个特征。

接着,对每个样本的每个特征进行规范化:

x ^ i j = x i j − μ i σ i 2 + ϵ \hat{x}_{ij} = \frac{x_{ij} - \mu_i}{\sqrt{\sigma_i^2 + \epsilon}} x^ij=σi2+ϵ xijμi

这里, ϵ \epsilon ϵ是一个很小的数值,例如 1 0 − 5 10^{-5} 105,用来保证分母不为零,增加数值稳定性。

最后,引入了两个可学习的参数,缩放因子 γ \gamma γ和偏移量 β \beta β(这两个参数的维度与每个样本的特征数相同),用于对规范化后的数据进行线性变换:

y i j = γ x ^ i j + β y_{ij} = \gamma \hat{x}_{ij} + \beta yij=γx^ij+β

最终得到的 y i j y_{ij} yij是Layer Normalization的输出,用于下一层的输入。

  • Scale(缩放因子)

定义:在Layer Normalization之后应用的乘法因子,用于调整规范化后的数据的尺度。这使得网络可以学习到在规范化过程中最优的数据分布尺度。
目的:缩放因子允许模型恢复那些对于完成特定任务可能是有益的、在规范化过程中被标准化的特征的重要性。

  • Shift(偏移量)

定义:在Layer Normalization之后应用的加法项,用于调整规范化后的数据的中心位置。这使得网络可以学习到在规范化过程中最优的数据分布中心。
目的:偏移量允许模型调整数据分布的中心位置,保留或恢复对于完成特定任务可能是有益的特征。
总结来说,Layer Normalization通过计算每个样本的均值和方差,并对每个样本的特征进行规范化,然后通过引入可学习的缩放因子和偏移量进行线性变换,以此来优化训练过程和模型性能。

PixArt

任务分解

PIXART-α将复杂的文本到图像生成任务分解为三个子任务:

(1)Pixel dependency learning

为了生成高质量图像,本文首先在ImageNet上预训练类引导生成模型,这一过程不仅成本低廉,而且能够有效地理解图像内部的像素级依赖性。因为类引导生成模型的架构与文本到图像生成模型架构有兼容性,这种预训练的初始化方式大大提高了训练的效率。

(2)Text-image alignment learning

为了实现文本与图像之间的精确对齐,本文构建了一个包含高概念密度的精确文本-图像对数据集,利用这个数据集,每次训练迭代时能够处理更多的名词,并且相较于以往的数据集,所遇到的歧义显著减少,极大地提高了模型在文本描述与图像对齐方面的训练效率。

(3)High-resolution and aesthetic image generation

为了生成高审美质量的图片,本文使用高质量的审美数据对模型进行微调。因为前两个阶段建立了强大先验知识,这个阶段的收敛速度显著加快。

模型架构

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

降低Attention计算复杂度

  • Blog
  • mamba:空间状态机

图像生成评估指标

Inception Score (IS)

在这里插入图片描述
然而,Inception Score 并不是完美的指标,它不能很好地捕捉到模式崩溃(mode collapse)的问题,即模型可能只生成少数几类图像但仍然获得高IS值。此外,IS依赖于预训练的Inception模型,这意味着它在某种程度上受限于Inception模型的性能和它在特定数据集上的训练情况。

Fréchet Inception Distance (FID)

在这里插入图片描述

Clip Score

在这里插入图片描述

R- Precision

在这里插入图片描述

面试问题

diffusion的采样方式有哪些?
确定性采样(DDIM),随机采样,条件采样

Pixel Diffusion有哪些?

lora推理过程有额外的计算吗?

在推理过程中,LoRA 的确会引入额外的计算步骤,因为它需要计算低秩矩阵与原始权重的组合。具体来说,LoRA 在预训练模型的权重矩阵 ( W ) 上应用两个较小的矩阵 ( A ) 和 ( B ) 的乘积,得到一个低秩矩阵 Δ W = A × B \Delta W = A \times B ΔW=A×B,然后将这个低秩矩阵添加到原始的权重矩阵 ( W ) 上,得到适应了新任务的权重矩阵 W + Δ W W + \Delta W W+ΔW

stable diffusion不稳定的情况和原因?

  • 文本描述的模糊性:如果提供给模型的文本描述过于模糊或含糊不清,模型可能难以理解预期的输出,从而生成与预期差异较大的图像。例如,一个模糊的描述如“一个美丽的场景”可能导致模型生成一系列非常不同的图像,因为“美丽”是一个主观且模糊的概念。
  • 模型训练数据的局限性:Stable Diffusion模型的表现在很大程度上取决于其训练数据。如果模型在训练过程中没有接触到足够多样化的数据,或者特定主题的数据较少,那么在生成这些主题的图像时可能会表现不佳。
  • 复杂或特定领域的文本描述:对于一些特定领域或非常复杂的文本描述,模型可能难以准确理解并生成匹配的图像。这是因为模型的文本理解能力受到其训练数据和内部表征的限制。
  • 超参数设置不当:Stable Diffusion模型的性能也受到超参数设置的影响,包括采样步骤数、温度参数等。不适当的超参数设置可能导致生成过程不稳定,比如生成模糊的图像或细节丢失。
  • 引导过程的挑战:在使用Stable Diffusion进行图像编辑或利用特定的引导技术(如CLIP引导)时,不恰当的引导或编辑策略可能导致生成结果与预期不符。

文本如何控制图像生成的?

文本没有权重是如何控制的?

Clip如何训练,如何推理的?

代码

  • condition/uncondition的代码实现:https://github.com/Allenem/DDPM/blob/main/ddpm_conditional.py

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Steam新人下载安装教程分享 迅游一键下载安装steam

Steam平台是Valve公司聘请的BitTorrent协议(BT下载)发明者Bram Cohen亲自开发设计。国内玩家对于Valve公司的游戏不会陌生,该公司发行的游戏有半条命系列、反恐精英系列、求生之路系列、传送门系列、军团要塞2、Dota2。Steam平台的客户端新增…

使用docker安装redis

使用docker安装redis ①拉取镜像 docker pull redis:6.2.6② 创建容器 docker run -d --name forum-redis --restartalways -p 6379:6379 redis:6.2.6 redis-server --requirepass "dong97"③链接测试 打开Redis Desktop Manager,输入host、port、pas…

开源版本管理系统的搭建一:SVN服务端安装

作者:私语茶馆 1.Windows搭建SVN版本管理系统 点评:SVN本身非常简洁易用,VisualSVN文档支撑非常好,客户端TortoiseSVN非常专业。5星好评。 1.1.SVN概要和组成 背景介绍 Svn是一个开源版本管理系统,由CollabNet公司…

Java Map集合(二)

1. HashMap原理 1.1 HashMap的容量 HashMap中使用数组作为存储元素的桶,对应的内部属性为table,如下图所示。HashMap的内部数组不是在创建HashMap对象时初始化,而是在首次存入元素时进行初始化,以减少对内存的占用。 从源码注释中…

【STM32+HAL】三轴按键PS2摇杆

一、准备工作: 有关CUBEMX的初始化配置,参见我的另一篇blog:【STM32HAL】CUBEMX初始化配置 有关定时器触发ADC模式配置,详见【STM32HAL】ADC采集波形实现 二、所用工具: 1、芯片: STM32F407VET6 2、CUBE…

小蓝本--因式分解(习题1)讲解

这几天要备战期中,下一期可能要等暑假了...... 小升初的压力真是紧扣于头啊,为了分到一个好班,拼了! 对了,下一期可能在寒假更,见谅! 1分解因式: 公因式: 答案&#xff…

发动机台架测试起动电源为发动机台架测试提供方便操作

发动机台架测试启动电源通常是指为发动机试验设备提供电力的装置,它可能包括交流电源、直流电源或专用的启动发电机。在进行发动机性能测试时,需要稳定的电力供应来驱动各种测试设备,如振动台、数据采集系统等。具体到电源类型常见的有市电、…

QT:label标签/进度条的使用

文章目录 设置不同格式的文本显示图片文本对齐/自动换行/缩进/边距LCDNumber倒计时 ProgressBar进度条 设置不同格式的文本 在文本格式中,存在富文本,makedown格式的文本,还有纯文本,下面就依据这三个进行举例 #include "w…

# 从浅入深 学习 SpringCloud 微服务架构(七)Hystrix(1)

从浅入深 学习 SpringCloud 微服务架构(七)Hystrix(1) 一、Hystrix:基于 RestTemplate 的熔断配置 1、Hystrix 介绍: 1)Hystrix 是由 Netflix 开源的一个延迟和容错库, 用于隔离访…

nginx--配置文件

组成 主配置文件:nginx.conf 子配置文件:include conf.d/*.conf 协议相关的配置文件:fastcgi uwsgi scgi等 mime.types:⽀持的mime类型,MIME(Multipurpose Internet Mail Extensions)多用途互联⽹网邮件扩展类型&…

渲染 函数

DOM树 什么是渲染函数 在多数情况下,Vue推荐使用模板template来创建HTML。 然而在一些应用场景中,需要使用JavaScript创建HTML。 这时可以用渲染函数,它比模板更方便。 render函数的主要神秘地方就是Vue的h函数。 h()函数 h()函数是一个用于…

学习Rust的第26天:Rust中的cp

在本文中复刻了 cp 实用程序的功能,我想默认使其递归,因为每次我想复制时都输入 -R 文件夹都会觉得有点重复,本文代码将与前文代码保持相似,我们只会更改程序的核心功能和一些变量名称以匹配用例 Pseudo Code 伪代码 function cop…

C#实战—代码实现收发文件智能化

在信息化的今天,收发电子文档几乎是每个朋友都要经历的事情。比如班级学委和班长需要收发作业,企业管理者需要收发工作文件。但是!!! 每到要交结果时,往往会发现总会有一些人没有即使交上,50个…

基于Springboot的校园食堂订餐系统(有报告)。Javaee项目,springboot项目。

演示视频: 基于Springboot的校园食堂订餐系统(有报告)。Javaee项目,springboot项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构…

区域文本提示的实时文本到图像生成;通过一致性自注意力机制的视频生成工具保持视频的一致性;专门为雪佛兰汽车设计的客服聊天机器人

✨ 1: StreamMultiDiffusion StreamMultiDiffusion是首个基于区域文本提示的实时文本到图像生成框架,实现了高速且互动的图像生成。 StreamMultiDiffusion 旨在结合加速推理技术和基于区域的文本提示控制,以克服之前解决方案中存在的速度慢和用户交互性…

从零开始学AI绘画,万字Stable Diffusion终极教程(一)

【第1期】SD入门 2022年8月,一款叫Stable Diffusion的AI绘画软件开源发布,从此开启了AIGC在图像上的爆火发展时期 率先学会SD的人,已经挖掘出了越来越多AI绘画有趣的玩法 从开始的AI美女、线稿上色、真人漫改、头像壁纸 到后来的AI创意字、AI…

望仙谷听谿涛

望仙谿涛 近来不知为何,染上喝咖啡的恶习,称为“恶”,是因为要花钱,而且非得是那种口感好的。 网络流行“人生无解,来杯拿铁”。 大抵是因为咖啡再苦,也比不过生活吧,至少咖啡可以加糖&#xff…

机器学习批量服务模式优化指南

原文地址:optimizing-machine-learning-a-practitioners-guide-to-effective-batch-serving-patterns 2024 年 4 月 15 日 简介 在机器学习和数据分析中,模型服务模式的战略实施对于在生产环境中部署和操作人工智能模型起着至关重要的作用。其中&…

STM32——WWDG(窗口看门狗)

技术笔记! 1.WWDG(窗口看门狗)简介 本质:能产生系统复位信号和提前唤醒中断的计数器。 特性: 递减的计数器; 当递减计数器值从 0x40减到0x3F时复位(即T6位跳变到0); …

HTML_CSS学习:CSS盒子模型

一、CSS中常用的长度单位 相关代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>CSS中常用的长度单位</title><style>html{font-size: 40px;}#d1{/*第一种长度单位&…
最新文章