【DA-CLIP】encode_image图像编码过程和IRSDE对image_context,、degra_context的使用

 背景:

编码过程:

  with torch.no_grad(), torch.cuda.amp.autocast():
        # 这一行开始一个上下文管理器,用于关闭梯度计算(torch.no_grad()),这对于推理阶段是必要的,因为我们不需要计算反向传播。
        # torch.cuda.amp.autocast()用于自动将操作转换为半精度浮点数,这可以提高计算速度并减少内存使用
        image_context, degra_context = clip_model.encode_image(img4clip, control=True)
        # 这一行使用clip_model的encode_image方法来编码处理后的图像,生成图像的上下文信息。
        # control=True使用DA-CLIP的encode_image而非CLIP
        #
        image_context = image_context.float()
        # 这一行将图像上下文张量转换为浮点数类型。
        degra_context = degra_context.float()
        # 同上将degra_context张量转换为浮点数类型

根据 复原过程探究

【DA-CLIP】复原过程代码解读-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_60350022/article/details/137699012image_context,、degra_context被传入ConditionUnet的forward()计算noise张量再计算分数score

encode_image过程

已知clip_model是DaCLIP类实例,在open_clip/declip_model.py找到该方法定义

    def encode_image(self, image, control=False, normalize: bool = False):
        if control:
            degra_features, hiddens = self.visual_control(image, output_hiddens=True)
            image_features = self.clip.visual(image, control=hiddens)
            
            image_features = F.normalize(image_features, dim=-1) if normalize else image_features
            degra_features = F.normalize(degra_features, dim=-1) if normalize else degra_features
            return image_features, degra_features
        else:
            return self.clip.encode_image(image, normalize)
            # 相当于image_features = self.clip.visual(image, control=hiddens)
            # image_features = F.normalize(image_features, dim=-1) if normalize else image_features

DaCLIP类self.clip是clip实例,control为False,只返回一个image_feature没有degra_feature就是CLIP原始的图像编码过程。

    def encode_image(self, image, normalize: bool = False):
        features = self.visual(image)
        return F.normalize(features, dim=-1) if normalize else features

一、degra_features解析。

self.visual_control()

self.visual_control = copy.deepcopy(clip_model.visual)
self.visual_control.transformer = ControlTransformer(self.visual_control.transformer)

 visual_control方法是clip_model.visual方法的深拷贝,但是更换了transformer 

_build_vision_tower ()

clip_model.visual是_build_vision_tower方法的返回值,

这个函数通过不同的配置参数来决定使用哪种类型的模型,包括使用 timm 库中的模型、ModifiedResNet 或者 VisionTransformer。函数中使用了条件判断来根据不同的配置参数构建相应的视觉模型,并且对于不同的数据类型需求,选择了不同的归一化层。

 self.visual = _build_vision_tower(embed_dim, vision_cfg, quick_gelu, cast_dtype)

该方法接受 vision_cfg配置

class CLIPVisionCfg:
    # 定义Vision Transformer模型中的层数,可以是一个整数或者一个包含四个整数的元组,
    # 如果是元组,它代表了不同层的维度,通常用于构建具有不同宽度的模型。
    layers: Union[Tuple[int, int, int, int], int] = 12
    # 模型的宽度,即每个层中的通道数。
    width: int = 768
    # 头部的宽度,即在多头自注意力机制中每个头的维度。
    head_width: int = 64
    # 多层感知机(MLP)层的宽度与输入的宽度之比。
    mlp_ratio: float = 4.0
    # 图像分块的大小,即将输入图像划分为多少个小块(patches)。
    patch_size: int = 16
    # 输入图像的尺寸,可以是一个整数或者一个包含两个整数的元组。
    image_size: Union[Tuple[int, int], int] = 224

    # 层归一化(Layer Scale)的初始值。
    ls_init_value: Optional[float] = None
    # 在训练过程中要丢弃的补丁(patches)的比例。值为0表示不丢弃任何补丁,
    # 而0.5到0.75之间是推荐值,用于优化模型性能。
    patch_dropout: float = 0.
    # 是否在每个补丁上使用输入层归一化,即是否对每个补丁应用输入层的层归一化。
    input_patchnorm: bool = False
    # 是否在最后一个嵌入层使用全局平均池化(Global Average Pooling),而不是使用CLS标记。
    global_average_pool: bool = False
    # 是否在最后一个嵌入层使用注意力池化(Attentional Pooling)。
    attentional_pool: bool = False
    # 注意力池化器(Attentional Pooler)的查询数。
    n_queries: int = 256
    # 注意力池化器的头数。
    attn_pooler_heads: int = 8
    # 是否输出token,通常用于模型的最终输出。
    output_tokens: bool = False

    # Timm库中的有效模型名称,如果设置了这个值,将会覆盖layers、width和patch_size等配置。
    timm_model_name: str = None
    # 是否使用预训练权重(通常是在ImageNet数据集上预训练的)。
    timm_model_pretrained: bool = False
    # Timm模型的特征池化类型。
    timm_pool: str = 'avg'
    # Timm模型输出的线性投影类型。
    timm_proj: str = 'linear'
    # 是否启用最终投影的偏置项。
    timm_proj_bias: bool = False
    # 头部的dropout比率。
    timm_drop: float = 0.
    # Timm模型的路径丢弃比率,也称为随机深度(Stochastic Depth)。
    timm_drop_path: Optional[float] = None

下面是_build_vision_tower 定义,在判断中

timm_model_name初始为None

vision_cfg.layers为12(int)

以上判断不满足,所以进入else。根据cfg配置VisionTransformer

visual = VisionTransformer()

# build_vision_tower,它接受以下参数:
# embed_dim: 整数,表示嵌入维度。
# vision_cfg: CLIPVisionCfg 类型,包含了配置视觉模型所需的参数。
# quick_gelu: 布尔值,可选参数,默认为 False。用于指定是否使用 QuickGELU 激活层。
# cast_dtype: 可选参数,默认为 None,表示在 PyTorch 中的类型转换。

def _build_vision_tower(
        embed_dim: int,
        vision_cfg: CLIPVisionCfg,
        quick_gelu: bool = False,
        cast_dtype: Optional[torch.dtype] = None
):
    # 如果传入的 vision_cfg 是一个字典,将其转换为 CLIPVisionCfg 类的实例。
    if isinstance(vision_cfg, dict):
        vision_cfg = CLIPVisionCfg(**vision_cfg)

    # 根据 quick_gelu 参数的值选择使用 QuickGELU 还是原生的 nn.GELU 激活层。
    # QuickGELU 在 OpenAI 的模型中预训练使用,但在 PyTorch 1.10 及更高版本中,原生的 GELU 更快且更节省内存。
    # 注意:无论 quick_gelu 标志如何,timm 模型始终使用原生 GELU。
    act_layer = QuickGELU if quick_gelu else nn.GELU

    # 如果 vision_cfg 中包含了 timm_model_name,表示使用 timm 库中的模型。
    if vision_cfg.timm_model_name:
        visual = TimmModel(
            vision_cfg.timm_model_name,  # 使用指定的 timm 模型名称。
            pretrained=vision_cfg.timm_model_pretrained,  # 是否使用预训练权重。
            pool=vision_cfg.timm_pool,  # 指定池化层的类型。
            proj=vision_cfg.timm_proj,  # 投影层的输出维度。
            proj_bias=vision_cfg.timm_proj_bias,  # 投影层是否包含偏置项。
            drop=vision_cfg.timm_drop,  # 指定 dropout 比率。
            drop_path=vision_cfg.timm_drop_path,  # 指定 drop path 正则化的比率。
            patch_drop=vision_cfg.patch_dropout if vision_cfg.patch_dropout > 0 else None,  # 指定 patch dropout 比率。
            embed_dim=embed_dim,  # 嵌入维度。
            image_size=vision_cfg.image_size,  # 输入图像的尺寸。
        )
    # 如果 vision_cfg 中包含了 layers,且类型为元组或列表。
    elif isinstance(vision_cfg.layers, (tuple, list)):
        # 计算视觉头的数量。
        vision_heads = vision_cfg.width * 32 // vision_cfg.head_width
        # 使用 ModifiedResNet 构建视觉模型。
        visual = ModifiedResNet(
            layers=vision_cfg.layers,  # 指定 ResNet 的层数。
            output_dim=embed_dim,  # 输出维度。
            heads=vision_heads,  # 视觉头的数量。
            image_size=vision_cfg.image_size,  # 输入图像的尺寸。
            width=vision_cfg.width,  # 模型的宽度。
        )
    # 如果以上条件都不满足,则使用 VisionTransformer 构建视觉模型。
    else:
        # 计算视觉头的数量。
        vision_heads = vision_cfg.width // vision_cfg.head_width
        # 根据 cast_dtype 的值选择使用不同的 LayerNorm 层。
        norm_layer = LayerNormFp32 if cast_dtype in (torch.float16, torch.bfloat16) else LayerNorm
        # 使用 VisionTransformer 构建视觉模型。
        visual = VisionTransformer(
            image_size=vision_cfg.image_size,  # 输入图像的尺寸。
            patch_size=vision_cfg.patch_size,  # 补丁的大小。
            width=vision_cfg.width,  # 模型的宽度。
            layers=vision_cfg.layers,  # 指定 Transformer 的层数。
            heads=vision_heads,  # 视觉头的数量。
            mlp_ratio=vision_cfg.mlp_ratio,  # MLP 的比例。
            ls_init_value=vision_cfg.ls_init_value,  # 层归一化初始化值。
            patch_dropout=vision_cfg.patch_dropout,  # 指定补丁 dropout 比率。
            input_patchnorm=vision_cfg.input_patchnorm,  # 是否使用输入补丁归一化。
            global_average_pool=vision_cfg.global_average_pool,  # 是否使用全局平均池化。
            attentional_pool=vision_cfg.attentional_pool,  # 是否使用注意力池化。
            n_queries=vision_cfg.n_queries,  # 查询的数量。
            attn_pooler_heads=vision_cfg.attn_pooler_heads,  # 注意力池化头的数量。
            output_tokens=vision_cfg.output_tokens,  # 输出的 token 数量。
            output_dim=embed_dim,  # 输出维度。
            act_layer=act_layer,  # 激活层。
            norm_layer=norm_layer,  # 归一化层。
        )

    # 返回构建好的视觉模型实例。
    return visual

 配置好VisionTransformer之后更换transformer,

 self.visual_control深拷贝clip_model.visual,self.visual_control.transformer就是ViT的transformer,

  self.transformer = Transformer(
            width,
            layers,
            heads,
            mlp_ratio,
            ls_init_value=ls_init_value,
            act_layer=act_layer,
            norm_layer=norm_layer
        )

ControlTransformer()

使用自定义的ControlTransformer,其构造函数中接受一个 transformer 参数,该参数是 Transformer 类的一个实例。ControlTransformer 类的主要目的是通过添加额外的控制机制来增强原始 Transformer 模型的功能。这种控制机制通过一个 control 张量实现,该张量可以在模型的前向传播过程中与每个残差块的输出相加,从而对模型的输出进行调节。

import torch
import torch.nn as nn
from typing import Optional, Callable

# 假设 LayerNorm 和 ResidualAttentionBlock 已经在其他地方定义
# LayerNorm = ... 
# ResidualAttentionBlock = ...

class ControlTransformer(nn.Module):
    def __init__(self, transformer: nn.Module):
        """
        初始化 ControlTransformer 实例。
        
        :param transformer: 一个 nn.Module 类型的实例,它应该是一个 Transformer 模型。
                              ControlTransformer 将使用这个模型的层数和宽度,并添加控制机制。
        """
        super().__init__()  # 调用父类的构造函数
        self.transformer = transformer  # 保存传入的 Transformer 实例
        self.layers = transformer.layers  # 获取 Transformer 的层数
        self.width = transformer.width  # 获取 Transformer 的宽度(即特征维度)

        # 创建一个 ModuleList,其中包含与 Transformer 层数相同数量的零模块
        # 每个零模块都是一个线性层,用于生成全零的向量
        self.zero_modules = nn.ModuleList([
            self.zero_module(nn.Linear(self.width, self.width, 1))
            for _ in range(self.layers)]).cuda()  # 将零模块移动到 GPU 上(如果可用)

        # 保存 Transformer 实例的梯度检查点(grad checkpointing)设置
        self.grad_checkpointing = transformer.grad_checkpointing

    # 定义一个辅助函数,用于将模块的参数归零
    def zero_module(self, module: nn.Module) -> nn.Module:
        """
        将传入模块的参数归零并返回该模块。
        
        :param module: 一个 nn.Module 类型的实例,其参数将被归零。
        :return: 传入的模块,其参数已被归零。
        """
        for p in module.parameters():
            p.detach().zero_()  # 归零参数
        return module  # 返回修改后的模块

    def forward(self, x: torch.Tensor, attn_mask: Optional[torch.Tensor] = None, 
                output_hiddens: Optional[bool] = False, 
                control: Optional[torch.Tensor] = None) -> Optional[torch.Tensor]:
        """
        前向传播函数。
        
        :param x: 输入张量。
        :param attn_mask: 可选的注意力掩码张量。
        :param output_hiddens: 可选的布尔值,指示是否输出每层的隐藏状态。
        :param control: 可选的控制张量,用于调节模型的输出。
        :return: 如果 output_hiddens 为 True,则返回输入 x 和每层的隐藏状态(hiddens);
                 否则只返回输入 x。
        """
        if output_hiddens:
            hiddens = []  # 如果需要输出隐藏状态,则初始化一个列表来存储它们

        # 遍历 Transformer 的每一层和对应的零模块
        for z, r in zip(self.zero_modules, self.transformer.resblocks):
            # 如果启用了梯度检查点,则使用 checkpoint 装饰器来保存和恢复梯度
            if self.grad_checkpointing and not torch.jit.is_scripting():
               
                x = checkpoint(r, x, None, None, attn_mask)
            else:
                # 否则,直接调用残差块的前向传播方法
                x = r(x, attn_mask=attn_mask)
            
            # 应用零模块生成零向量
            zx = z(x)

            # 如果需要输出隐藏状态,则将其添加到列表中
            if output_hiddens:
                hiddens.append(zx)

            # 如果提供了控制张量,则将其添加到当前层的输出中
            if control is not None:
                x += control.pop()

        # 根据 output_hiddens 的值返回相应的结果
        return (x, hiddens) if output_hiddens else x

ViT的 Transformer

class Transformer(nn.Module):
    def __init__(  # 构造函数定义了如何初始化 Transformer 模型
            self,
            width: int,          # 模型的宽度,即特征维度
            layers: int,         # Transformer 块的层数
            heads: int,          # 多头注意力中头的数量
            mlp_ratio: float = 4.0,  # MLP层的宽度与输入宽度的比率
            ls_init_value: float = None,  # 层归一化(LayerScale)的初始值
            act_layer: Callable = nn.GELU,  # 激活层的类型
            norm_layer: Callable = LayerNorm,  # 归一化层的类型
    ):
        super().__init__()  # 调用父类的构造函数
        self.width = width  # 保存模型宽度
        self.layers = layers  # 保存层数
        self.grad_checkpointing = False  # 默认不启用梯度检查点

        # 创建一个 ModuleList,存储所有的残差注意力块
        self.resblocks = nn.ModuleList([
            ResidualAttentionBlock(  # 为每个层创建一个残差注意力块
                width, heads, mlp_ratio, ls_init_value=ls_init_value, act_layer=act_layer, norm_layer=norm_layer
            ) for _ in range(layers)
        )

    def get_cast_dtype(self) -> torch.dtype:  # 获取用于类型转换的原始数据类型
        # 假设 ResidualAttentionBlock 和其 MLP 层已经在其他地方定义
        # 这里只是一个示例,实际的实现可能需要访问具体的 MLP 层和其属性
        if hasattr(self.resblocks[0].mlp.c_fc, 'int8_original_dtype'):
            return self.resblocks[0].mlp.c_fc.int8_original_dtype
        return self.resblocks[0].mlp.c_fc.weight.dtype

    def forward(self,  # 前向传播函数
            x: torch.Tensor,  # 输入张量
            attn_mask: Optional[torch.Tensor] = None,  # 可选的注意力掩码
            output_hiddens: Optional[bool] = False,  # 可选的标志,指示是否输出隐藏状态
    ):
        if output_hiddens:
            hiddens = []  # 如果需要输出隐藏状态,则初始化一个列表来存储它们

        for r in self.resblocks:  # 遍历所有的残差注意力块
            if self.grad_checkpointing and not torch.jit.is_scripting():
                # 使用梯度检查点来节省内存
                x = checkpoint(r, x, None, None, attn_mask)
            else:
                x = r(x, attn_mask=attn_mask)  # 调用残差注意力块的前向传播方法

            if output_hiddens:
                hiddens.append(x)  # 如果需要,保存当前层的输出

        return (x, hiddens) if output_hiddens else x  # 根据需要返回最终输出和/或隐藏状态
  1. 控制机制: ControlTransformer 引入了控制机制,它通过一个额外的 control 参数来调节模型的输出。这是 ControlTransformer 独有的特性,而原始的 Transformer 没有这个功能。

  2. 零模块(Zero Modules): ControlTransformer 创建了一个 zero_modulesModuleList,其中包含零初始化的线性层。这些零模块用于生成全零的向量,这些向量可以在前向传播中与残差块的输出相加。原始的 Transformer 没有这个列表和这些零模块。

  3. 梯度检查点(Grad Checkpointing): 虽然两个类都有关于梯度检查点的代码,但 ControlTransformer 在其构造函数中直接从传入的 transformer 参数中继承了这个设置。这意味着 ControlTransformer 可以利用原始 Transformer 的梯度检查点配置。

  4. 前向传播方法(Forward Method): 两个类的 forward 方法在结构上相似,但 ControlTransformer 在处理每层的输出时会考虑 control 参数,并将其与输出相加。

  5. 类之间的关系: ControlTransformer 继承自 nn.Module 并接受一个 transformer 参数,这个参数应该是 Transformer 类的一个实例。这样,ControlTransformer 可以在原始 Transformer 的基础上添加额外的功能。

 

小结 

 self.visual_control()应该是VisionTransformer,Transformer更换了ControlTransformer

 degra_features, hiddens = self.visual_control(image, output_hiddens=True)就是执行VisionTransformer的forward()

def forward(self, x: torch.Tensor, output_hiddens: bool = False, control: Optional[torch.Tensor] = None):
    """
    前向传播函数,定义了 Vision Transformer 模型如何处理输入数据 x 并生成输出。

    :param x: 输入的张量,代表一批图像。
    :param output_hiddens: 布尔值,指示是否输出每层的隐藏状态。
    :param control: 可选的控制张量,用于调节模型的输出。
    :return: 根据模型配置返回不同的输出,可能是池化后的输出、隐藏状态或注意力池化的 token。
    """

    # 如果启用了输入补丁归一化(input patch normalization),则对输入图像的每个补丁进行处理
    if self.input_patchnorm:
        # 使用 einops 库对输入图像进行分块(patchification)
        x = x.reshape(...)  # 重新排列和重塑张量以匹配补丁嵌入的格式
        x = self.patchnorm_pre_ln(x)  # 应用第一个 LayerNorm
        x = self.conv1(x)  # 应用卷积层以生成补丁嵌入
    else:
        # 如果没有启用输入补丁归一化,直接应用卷积层
        x = self.conv1(x)
        # 重塑和排列张量以准备嵌入和嵌入位置
        x = x.reshape(...)  # 重塑张量以匹配补丁嵌入的格式
        x = x.permute(...)  # 排列张量维度以匹配所需的格式

    # 将类嵌入(class embeddings)添加到输入补丁,并与位置嵌入(positional embeddings)相加
    x = torch.cat([self.class_embedding, x], dim=1)

    # 应用补丁dropout(如果dropout比例不为0)
    x = self.patch_dropout(x)

    # 应用预Transformer层的LayerNorm
    x = self.ln_pre(x)

    # 调整张量维度顺序以适应Transformer的输入要求(从 NLD 到 LND)
    x = x.permute(1, 0, 2)

    # 通过Transformer层进行前向传播,并可选择性地输出隐藏状态
    x = self.transformer(x, output_hiddens=output_hiddens, control=control)
    if output_hiddens:
        x, hiddens = x  # 如果需要,解包Transformer的输出以获取隐藏状态

    # 再次调整张量维度顺序(从 LND 回到 NLD)
    x = x.permute(1, 0, 2)

    # 如果模型包含注意力池化器,则应用它并获取池化后的输出和token
    if self.attn_pool is not None:
        x = self.attn_pool(x)
        x = self.ln_post(x)
        pooled, tokens = self._global_pool(x)
    else:
        # 否则,直接应用全局池化并获取池化后的输出
        pooled, tokens = self._global_pool(x)
        pooled = self.ln_post(pooled)

    # 如果存在输出投影层,则应用它
    if self.proj is not None:
        pooled = pooled @ self.proj

    # 如果模型配置为输出token,则返回它们
    if self.output_tokens:
        return pooled, tokens

    # 如果需要输出隐藏状态,则返回它们
    if output_hiddens:
        return pooled, hiddens
    
    # 否则,只返回池化后的输出
    return pooled

返回的是一个包含两个元素的元组,其中第一个元素是 pooled(经过处理的特征表示),第二个元素是 hiddens(每个Transformer层的输出) 

猪脑过载了有机会再探究为什么叫degradation_feature

二、image_features = self.clip.visual(image, control=hiddens)

 这个相比上面的理解就简单了,

self.clip.visual就是VisionTransformer,

image_features = self.clip.visual(image, control=hiddens)同样执行VisionTransformer的forward

代码还是上面那段。

control的输入是刚刚生成degra_features的返回值hiddens

三、image_features = F.normalize(image_features, dim=-1) if normalize else image_features

【Pytorch】F.normalize计算理解-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/lj2048/article/details/118115681默认normalize为False,暂时不去理解这里

score计算过程

预处理

image_context = image_context.float()
# 这一行将图像上下文张量转换为浮点数类型。
degra_context = degra_context.float()
# 同上将degra_context张量转换为浮点数类型

noise? 

 noise = self.model(x, self.mu, t * scale, **kwargs) 

 ConditionalUNet的forward 接收输入张量 xt、条件张量 cond、时间参数 time,以及可选的文本和图像上下文。通过一系列卷积、注意力机制和上/下采样操作,模型提取和融合特征,最终生成输出张量。输出张量经过裁剪,确保其尺寸与输入图像的尺寸一致。

def forward(self, xt, cond, time, text_context=None, image_context=None):
    # 检查输入的时间参数是否为整数或浮点数,如果是,则将其转换为一个单元素张量,并移动到xt所在的设备
    if isinstance(time, int) or isinstance(time, float):
        time = torch.tensor([time]).to(xt.device)
    
    # X=noisy_tensor-LQ_tensor就是文章第一步添加的随机噪声,与LQ_tensor拼接,增加通道维度
    x = xt - cond
    x = torch.cat([x, cond], dim=1)

    # 获取输入张量的空间维度H和W
    H, W = x.shape[2:]
    # 检查并调整输入张量x的空间尺寸以匹配原始图像的尺寸
    x = self.check_image_size(x, H, W)

    # 应用初始卷积层
    x = self.init_conv(x)
    # 克隆x,用于后续操作
    x_ = x.clone()

    # 通过时间MLP处理时间参数
    t = self.time_mlp(time) 
    # 如果上下文维度大于0,并且使用degra上下文,且文本上下文不为空
    if self.context_dim > 0:
        if self.use_degra_context and text_context is not None:
            # 计算文本上下文的嵌入,将其与提示向量结合,并进行处理
            prompt_embedding = torch.softmax(self.text_mlp(text_context), dim=1) * self.prompt
            prompt_embedding = self.prompt_mlp(prompt_embedding)
            # 将处理后的文本上下文嵌入加到时间参数t上
            t = t + prompt_embedding

        # 如果使用图像上下文,且图像上下文不为空
        if self.use_image_context and image_context is not None:
            # 为图像上下文增加一个通道维度
            image_context = image_context.unsqueeze(1)

    # 存储下采样过程中的特征图
    h = []
    # 遍历下采样模块列表
    for b1, b2, attn, downsample in self.downs:
        # 应用第一个残差块和时间参数t
        x = b1(x, t)
        # 存储特征图
        h.append(x)

        # 应用第二个残差块和时间参数t
        x = b2(x, t)
        # 应用注意力机制,如果提供了图像上下文,则使用它
        x = attn(x, context=image_context)
        # 存储特征图
        h.append(x)

        # 应用下采样操作
        x = downsample(x)

    # 应用中间块1和时间参数t
    x = self.mid_block1(x, t)
    # 如果使用图像上下文,则应用注意力机制
    x = self.mid_attn(x, context=image_context) if self.use_image_context else x
    # 应用中间块2和时间参数t
    x = self.mid_block2(x, t)

    # 遍历上采样模块列表
    for b1, b2, attn, upsample in self.ups:
        # 从历史特征图中弹出并拼接特征,与当前特征图拼接
        x = torch.cat([x, h.pop()], dim=1)
        # 应用第一个残差块和时间参数t
        x = b1(x, t)
        
        # 再次从历史特征图中弹出并拼接特征,与当前特征图拼接
        x = torch.cat([x, h.pop()], dim=1)
        # 应用第二个残差块和时间参数t
        x = b2(x, t)

        # 应用注意力机制,如果提供了图像上下文,则使用它
        x = attn(x, context=image_context)
        # 应用上采样操作
        x = upsample(x)

    # 将原始输入xt与当前特征图x拼接,增加通道维度
    x = torch.cat([x, x_], dim=1)

    # 应用最终的残差块和时间参数t
    x = self.final_res_block(x, t)
    # 应用最终的卷积层
    x = self.final_conv(x)

    # 裁剪输出张量x,使其空间尺寸与原始输入图像的尺寸相匹配
    x = x[..., :H, :W].contiguous()
    
    # 返回处理后的输出张量x
    return x

 根据返回的noise计算score

    def get_score_from_noise(self, noise, t):
        return -noise / self.sigma_bar(t)
    def sigma_bar(self, t):
        return self.sigma_bars[t]
      sigma_bars = get_sigma_bars(thetas_cumsum)
thetas_cumsum = get_thetas_cumsum(thetas) - thetas[0] # for that thetas[0] is not 0
def get_sigma_bars(thetas_cumsum):
    return torch.sqrt(max_sigma**2 * (1 - torch.exp(-2 * thetas_cumsum * self.dt)))

 以上完成score计算

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

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

相关文章

NVM的安装与配置

目录 一、简介二、下载2.1、windows环境下载地址2.2、安装 三、配置3.1、查看可安装版本3.2、安装版本3.3、使用和切换版本3.4、模块配置 四、其他4.1、全局安装pnpm4.2、常用nvm命令 一、简介 NVM,全称为Node Version Manager,是一个流行的命令行工具&a…

【OpenHarmony】TDD-FUZZ环境配置

零、参考 1、AttributeError: ‘ElementTree‘ object has no attribute ‘getiterator‘:https://blog.csdn.net/suhao0911/article/details/110950742 一、创建工作目录 1、新建工作目录如:D:\0000_TDD_FUZZ\0000_ohos_tdd_fuzz。 2、gitee上下载 t…

简历上写熟悉Linux下常用命令?直接寄

大家写简历技术栈时,都觉得越多越好,其中一条,熟悉Linux下常用命令?其实开发中Linux不是必备考点,除了运维,真正用的多的仅仅cd ls mkdir等,但当面试官问到上面命令时,是不是就傻眼了…

three.js(1):three.js简介

1 什么是three.js three.js,一个WebGL引擎,基于JavaScript,可直接运行GPU驱动游戏与图形驱动应用于浏览器。其库提供的特性与API以绘制3D场景于浏览器。 2 下载地址 three.js下载地址:https://github.com/mrdoob/three.js 3 目录介绍 下载…

vue3 uniapp微信登录

根据最新的微信小程序官方的规定,uniapp中的uni.getUserInfo方法不再返回用户头像和昵称、以及手机号 首先,需获取appID,appSecret,如下图 先调用uni.getUserInfo方法获取code,然后调用后台的api,传入code&…

微信登录功能-保姆级教学

目录 一、使用组件 二、登录功能 2.1 步骤 2.2 首先找到网页权限 复制demo 代码 这里我们需要修改两个参数 三、前端代码 3.1 api 里weiXinApi.ts 3.2 api里的 index.ts 3.3 pinia.ts 3.4 My.vue 四、后端代码 4.1 WeiXinController 4.2 Access_Token.Java 4.3 We…

vue列表列表过滤

对已知的列表进行数据过滤(根据输入框里面的内容进行数据过滤) 编写案例 通过案例来演示说明 效果就是这样的 输入框是模糊查询 想要实现功能,其实就两大步,1获取输入框内容 2根据输入内容进行数据过滤 绑定收集数据 我们可以使用v-model去双向绑定 …

车机系统与 Android 的关系概述

前言:搞懂 Android 系统和汽车到底有什么关系。 文章目录 一、基本概念1、Android Auto1)是什么2)功能 2、Google Assistant3、Android Automotive1、Android Auto 和 Android Automotive 的区别 4、App1)App 的开发2)…

【VS2019】x64 Native Tools Command Prompt for Vs 2019使用conda命令进入环境

【VS2019】x64 Native Tools Command Prompt for Vs 2019使用conda命令进入环境 安装完VS2019后,打开终端x64 Native Tools Command Prompt for Vs 2019,直接运行conda会出现‘conda’ 不是内部或外部命令,也不是可运行的程序 原因分析&am…

Kafka 架构深入介绍 及搭建Filebeat+Kafka+ELK

目录 一 架构深入介绍 (一)Kafka 工作流程及文件存储机制 (二)数据可靠性保证 (三)数据一致性问题 (四)故障问题 (五)ack 应答机制 二 实…

YOLOv1精读笔记

YOLO系列 摘要1. 将目标检测视为一个回归问题2. 定位准确率不如 SOTA,但背景错误率更低3. 泛化能力强 1.引言1.1 YOLO 速度很快1.2 全局推理 2. Unified Detection2.1 网络设计2.2 训练YOLOv1模型损失函数的选择和其潜在的问题YOLOv1模型如何改进其损失函数来更好地…

深入理解信号上升沿与带宽的关系

信号的上升时间,对于理解信号完整性问题至关重要,高速pcb设计中的绝大多数问题都和它有关,很多信号完整性问题都是由信号上升时间短引起的,你必须对他足够重视。 信号上升时间并不是信号从低电平上升到高电平所经历的时间&#xf…

五、Jenkins、Docker、SpringClound持续集成

Jenkins、Docker、SpringClound持续集成 一、部署介绍1.部署图2.微服务项目结构3.项目启动顺序 二、微服务项目在Windows运行1.配置java、maven环境2.初始化数据库表/数据2.1 tensquare_gathering服务表2.2 tensquare_gathering服务表 3.启动微服务4.微服务接口测试4.1 获取用户…

陇剑杯 ios 流量分析

陇剑杯 ios 流量分析 ios 一位ios的安全研究员在家中使用手机联网被黑,不仅被窃密还丢失比特币若干,根据流量分析完成ios1-8 ios 1 ios-1:黑客所控制的C&C服务器IP是_____________。 什么是C&C服务器? C&C(Com…

回溯算法中常见的使用方法逻辑整理

回溯算法 常见的使用方法逻辑整理 1. 回溯算法 特点 回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。回溯法是一种选优搜索法&#xff0…

乐写9612手写板实测故障

闲鱼上淘了二手的 ①需要驱动很强的usb口,老usb口会不识别,尤其是笔记本容易不识别,非常容易出现下面这种问题: ②需要microsoft2013以上的,兼容性做的比较差 ③由于可视化,导致数据线容易烧,…

stm32报错问题集锦

PS:本文负责记录本人日常遇到的报错问题,以及问题描述、原因以及解决办法等,解决办法百分百亲测有效。本篇会不定期更新,更新频率就看遇到的问题多不多了 更换工程芯片型号 问题描述 例程最开始用的芯片型号是STM32F103VE&#…

CentOS 7安装Nginx

说明:本文介绍如何在CentOS 7操作系统中安装Nginx 下载安装 首先,去官网上下载Nginx压缩包,官网地址:https://nginx.org/en/download.html,我这里下载稳定版1.24.0; 上传到云服务器上,解压&am…

数据可视化基础与应用-04-seaborn库人口普查分析--如何做人口年龄层结构金字塔

总结 本系列是数据可视化基础与应用的第04篇seaborn,是seaborn从入门到精通系列第3篇。本系列主要介绍基于seaborn实现数据可视化。 参考 参考:我分享了一个项目给你《seaborn篇人口普查分析–如何做人口年龄层结构金字塔》,快来看看吧 数据集地址 h…

【题目】【信息安全管理与评估】2022年国赛高职组“信息安全管理与评估”赛项样题5

【题目】【信息安全管理与评估】2022年国赛高职组“信息安全管理与评估”赛项样题5 第一阶段竞赛项目试题 本文件为信息安全管理与评估项目竞赛-第一阶段试题,第一阶段内容包括:网络平台搭建与设备安全防护。 本次比赛时间为180分钟。 介绍 竞赛阶段…