AIGC笔记--Stable Diffusion源码剖析之DDIM

1--前言

        以论文《High-Resolution Image Synthesis with Latent Diffusion Models》  开源的项目为例,剖析Stable Diffusion经典组成部分,巩固学习加深印象。

2--DDIM

一个可以debug的小demo:SD_DDIM

        以文生图为例,剖析SD中DDIM的核心组成模块。 本质上SD的DDIM遵循论文DENOISING DIFFUSION IMPLICIT MODELS的核心公式。

3--核心模块剖析

见SD_DDIM

4--完整代码

import torch
import pytorch_lightning as pl

import numpy as np
from tqdm import tqdm
from functools import partial

# From https://github.com/CompVis/latent-diffusion/blob/main/ldm/modules/diffusionmodules/util.py
def make_ddim_sampling_parameters(alphacums, ddim_timesteps, eta, verbose = True):
    # select alphas for computing the variance schedule
    alphas = alphacums[ddim_timesteps] # 由于alphacums来自DDPM,所以本质上还是调用了DDPM的alphas_cumprod,即[0.9983, 0.9804, ..., 0.0058]
    alphas_prev = np.asarray([alphacums[0]] + alphacums[ddim_timesteps[:-1]].tolist()) # 构成alphas_prev的方法是保留前49个alphas,同时在最前面添加DDPM的alphas_cumprod[0], 即[0.9991]

    # according the the formula provided in https://arxiv.org/abs/2010.02502 论文中的公式16
    sigmas = eta * np.sqrt((1 - alphas_prev) / (1 - alphas) * (1 - alphas / alphas_prev))
    if verbose:
        print(f'Selected alphas for ddim sampler: a_t: {alphas}; a_(t-1): {alphas_prev}')
        print(f'For the chosen value of eta, which is {eta}, '
              f'this results in the following sigma_t schedule for ddim sampler {sigmas}')
    return sigmas, alphas, alphas_prev

# From https://github.com/CompVis/latent-diffusion/blob/main/ldm/modules/diffusionmodules/util.py
# 获取 ddim 的timesteps
def make_ddim_timesteps(ddim_discr_method, num_ddim_timesteps, num_ddpm_timesteps, verbose = True):
    if ddim_discr_method == 'uniform':
        c = num_ddpm_timesteps // num_ddim_timesteps # 1000 // 50 = 20
        ddim_timesteps = np.asarray(list(range(0, num_ddpm_timesteps, c))) # 间隔c取样
    elif ddim_discr_method == 'quad':
        ddim_timesteps = ((np.linspace(0, np.sqrt(num_ddpm_timesteps * .8), num_ddim_timesteps)) ** 2).astype(int)
    else:
        raise NotImplementedError(f'There is no ddim discretization method called "{ddim_discr_method}"')

    # assert ddim_timesteps.shape[0] == num_ddim_timesteps
    # add one to get the final alpha values right (the ones from first scale to data during sampling)
    steps_out = ddim_timesteps + 1 # 每个数值加1
    if verbose:
        print(f'Selected timesteps for ddim sampler: {steps_out}')
    return steps_out # [1, 21, 41, ..., 981]

# From https://github.com/CompVis/latent-diffusion/blob/main/ldm/modules/diffusionmodules/util.py
def noise_like(shape, device, repeat = False):
    repeat_noise = lambda: torch.randn((1, *shape[1:]), device=device).repeat(shape[0], *((1,) * (len(shape) - 1)))
    noise = lambda: torch.randn(shape, device=device)
    return repeat_noise() if repeat else noise()

# From https://github.com/CompVis/latent-diffusion/blob/main/ldm/modules/diffusionmodules/util.py
def make_beta_schedule(schedule, n_timestep, linear_start = 1e-4, linear_end = 2e-2, cosine_s = 8e-3):
    if schedule == "linear":
        betas = (
                torch.linspace(linear_start ** 0.5, linear_end ** 0.5, n_timestep, dtype = torch.float64) ** 2
        )

    elif schedule == "cosine":
        timesteps = (
                torch.arange(n_timestep + 1, dtype=torch.float64) / n_timestep + cosine_s
        )
        alphas = timesteps / (1 + cosine_s) * np.pi / 2
        alphas = torch.cos(alphas).pow(2)
        alphas = alphas / alphas[0]
        betas = 1 - alphas[1:] / alphas[:-1]
        betas = np.clip(betas, a_min=0, a_max=0.999)

    elif schedule == "sqrt_linear":
        betas = torch.linspace(linear_start, linear_end, n_timestep, dtype = torch.float64)
    elif schedule == "sqrt":
        betas = torch.linspace(linear_start, linear_end, n_timestep, dtype = torch.float64) ** 0.5
    else:
        raise ValueError(f"schedule '{schedule}' unknown.")
    return betas.numpy()

# origin from https://github.com/CompVis/latent-diffusion/blob/main/ldm/models/diffusion/ddpm.py, modified by ljf
class DDPM(pl.LightningModule):
    def __init__(self, given_betas = None, beta_schedule = "linear", timesteps = 1000, linear_start = 0.00085, linear_end = 0.012, cosine_s = 8e-3):
        super().__init__()
        self.v_posterior = 0.0
        self.parameterization = "eps"
        self.register_schedule(given_betas = given_betas, beta_schedule = beta_schedule, timesteps = timesteps,
                        linear_start = linear_start, linear_end = linear_end, cosine_s = cosine_s)

    def register_schedule(self, given_betas=None, beta_schedule="linear", timesteps=1000,
                          linear_start=1e-4, linear_end=2e-2, cosine_s=8e-3):

        betas = make_beta_schedule(beta_schedule, timesteps, linear_start=linear_start, linear_end=linear_end,
                                    cosine_s=cosine_s) # 计算 betas [0.00085, 0.0008547, ..., 0.012] # total 1000
        alphas = 1. - betas # 根据betas计算alphas [0.99915, 0.9991453, ..., 0.988] # total 1000
        alphas_cumprod = np.cumprod(alphas, axis=0) # 计算alphas_cumprod [0.99915, 0.99915*0.9991453, ..., ..*0.988] # 与本身及前面的数进行相乘
        alphas_cumprod_prev = np.append(1., alphas_cumprod[:-1]) # 计算alphas_cumprod_prev [1, 0.99915, 0.99915*0.9991453, ...] # 保留前999位

        timesteps, = betas.shape
        self.num_timesteps = int(timesteps)
        self.linear_start = linear_start
        self.linear_end = linear_end
        assert alphas_cumprod.shape[0] == self.num_timesteps, 'alphas have to be defined for each timestep'

        to_torch = partial(torch.tensor, dtype=torch.float32)

        self.register_buffer('betas', to_torch(betas))
        self.register_buffer('alphas_cumprod', to_torch(alphas_cumprod))
        self.register_buffer('alphas_cumprod_prev', to_torch(alphas_cumprod_prev))

        # calculations for diffusion q(x_t | x_{t-1}) and others
        self.register_buffer('sqrt_alphas_cumprod', to_torch(np.sqrt(alphas_cumprod)))
        self.register_buffer('sqrt_one_minus_alphas_cumprod', to_torch(np.sqrt(1. - alphas_cumprod)))
        self.register_buffer('log_one_minus_alphas_cumprod', to_torch(np.log(1. - alphas_cumprod)))
        self.register_buffer('sqrt_recip_alphas_cumprod', to_torch(np.sqrt(1. / alphas_cumprod)))
        self.register_buffer('sqrt_recipm1_alphas_cumprod', to_torch(np.sqrt(1. / alphas_cumprod - 1)))

        # calculations for posterior q(x_{t-1} | x_t, x_0)
        posterior_variance = (1 - self.v_posterior) * betas * (1. - alphas_cumprod_prev) / (
                    1. - alphas_cumprod) + self.v_posterior * betas
        # above: equal to 1. / (1. / (1. - alpha_cumprod_tm1) + alpha_t / beta_t)
        self.register_buffer('posterior_variance', to_torch(posterior_variance))
        # below: log calculation clipped because the posterior variance is 0 at the beginning of the diffusion chain
        self.register_buffer('posterior_log_variance_clipped', to_torch(np.log(np.maximum(posterior_variance, 1e-20))))
        self.register_buffer('posterior_mean_coef1', to_torch(
            betas * np.sqrt(alphas_cumprod_prev) / (1. - alphas_cumprod)))
        self.register_buffer('posterior_mean_coef2', to_torch(
            (1. - alphas_cumprod_prev) * np.sqrt(alphas) / (1. - alphas_cumprod)))

        if self.parameterization == "eps":
            lvlb_weights = self.betas ** 2 / (
                        2 * self.posterior_variance * to_torch(alphas) * (1 - self.alphas_cumprod))
        elif self.parameterization == "x0":
            lvlb_weights = 0.5 * np.sqrt(torch.Tensor(alphas_cumprod)) / (2. * 1 - torch.Tensor(alphas_cumprod))
        else:
            raise NotImplementedError("mu not supported")
        # TODO how to choose this term
        lvlb_weights[0] = lvlb_weights[1]
        self.register_buffer('lvlb_weights', lvlb_weights, persistent=False)
        assert not torch.isnan(self.lvlb_weights).all()

    # 模拟 UNet 预测
    def apply_model(self, x_noisy, t, cond, return_ids=False):
        return torch.rand(x_noisy.shape) # 随机返回一个latent 预测

# Origin from https://github.com/CompVis/latent-diffusion/blob/main/ldm/models/diffusion/ddim.py, modified by ljf
class DDIMSampler(object):
    def __init__(self, model, schedule = "linear", **kwargs):
        super().__init__()
        self.model = model # DDPM的model
        self.ddpm_num_timesteps = model.num_timesteps
        self.schedule = schedule

    def register_buffer(self, name, attr):
        if type(attr) == torch.Tensor:
            if attr.device != torch.device("cuda"):
                attr = attr.to(torch.device("cuda"))
        setattr(self, name, attr)

    def make_schedule(self, ddim_num_steps, ddim_discretize = "uniform", ddim_eta = 0., verbose = True):
        # 获取ddim的timesteps [1, 21, 41, ..., 981]
        self.ddim_timesteps = make_ddim_timesteps(ddim_discr_method = ddim_discretize, num_ddim_timesteps = ddim_num_steps,
                                                  num_ddpm_timesteps = self.ddpm_num_timesteps, verbose = verbose)
        
        alphas_cumprod = self.model.alphas_cumprod # 使用ddpm的alphas_cumprod
        assert alphas_cumprod.shape[0] == self.ddpm_num_timesteps, 'alphas have to be defined for each timestep'
        to_torch = lambda x: x.clone().detach().to(torch.float32).to(self.model.device) # lambda表达式,对每一个输入实现相同的操作

        self.register_buffer('betas', to_torch(self.model.betas)) # 使用ddpm的betas
        self.register_buffer('alphas_cumprod', to_torch(alphas_cumprod)) # 使用ddpm的alphas_cumprod
        self.register_buffer('alphas_cumprod_prev', to_torch(self.model.alphas_cumprod_prev)) #使用ddpm的alphas_cumprod_prev

        # calculations for diffusion q(x_t | x_{t-1}) and others
        self.register_buffer('sqrt_alphas_cumprod', to_torch(np.sqrt(alphas_cumprod.cpu())))
        self.register_buffer('sqrt_one_minus_alphas_cumprod', to_torch(np.sqrt(1. - alphas_cumprod.cpu())))
        self.register_buffer('log_one_minus_alphas_cumprod', to_torch(np.log(1. - alphas_cumprod.cpu())))
        self.register_buffer('sqrt_recip_alphas_cumprod', to_torch(np.sqrt(1. / alphas_cumprod.cpu())))
        self.register_buffer('sqrt_recipm1_alphas_cumprod', to_torch(np.sqrt(1. / alphas_cumprod.cpu() - 1)))

        # ddim sampling parameters
        ddim_sigmas, ddim_alphas, ddim_alphas_prev = make_ddim_sampling_parameters(alphacums = alphas_cumprod.cpu(),
                                                                                   ddim_timesteps = self.ddim_timesteps,
                                                                                   eta = ddim_eta,verbose = verbose)
        self.register_buffer('ddim_sigmas', ddim_sigmas)
        self.register_buffer('ddim_alphas', ddim_alphas)
        self.register_buffer('ddim_alphas_prev', ddim_alphas_prev)
        self.register_buffer('ddim_sqrt_one_minus_alphas', np.sqrt(1. - ddim_alphas))
        sigmas_for_original_sampling_steps = ddim_eta * torch.sqrt(
            (1 - self.alphas_cumprod_prev) / (1 - self.alphas_cumprod) * (
                        1 - self.alphas_cumprod / self.alphas_cumprod_prev))
        self.register_buffer('ddim_sigmas_for_original_num_steps', sigmas_for_original_sampling_steps)

    @torch.no_grad()
    def sample(self, S, batch_size, shape, conditioning = None, callback = None,
               img_callback = None, quantize_x0 = False, eta = 0., mask = None, x0 = None,
               temperature = 1., noise_dropout = 0., score_corrector = None, corrector_kwargs = None,
               verbose = True, x_T = None, log_every_t = 100, unconditional_guidance_scale = 1.,
               unconditional_conditioning = None
    ):
        self.make_schedule(ddim_num_steps = S, ddim_eta = eta, verbose = verbose) # 注册各个参数
        # sampling
        C, H, W = shape # [4, 64, 64]
        size = (batch_size, C, H, W) # [3, 4, 64, 64]
        print(f'Data shape for DDIM sampling is {size}, eta {eta}')

        samples, intermediates = self.ddim_sampling(conditioning, size,
                                                    callback = callback,
                                                    img_callback = img_callback,
                                                    quantize_denoised = quantize_x0,
                                                    mask = mask, x0 = x0,
                                                    ddim_use_original_steps = False,
                                                    noise_dropout = noise_dropout,
                                                    temperature = temperature,
                                                    score_corrector = score_corrector,
                                                    corrector_kwargs = corrector_kwargs,
                                                    x_T = x_T,
                                                    log_every_t = log_every_t,
                                                    unconditional_guidance_scale = unconditional_guidance_scale,
                                                    unconditional_conditioning = unconditional_conditioning,
        )
        return samples, intermediates

    @torch.no_grad()
    def ddim_sampling(self, cond, shape,
                      x_T = None, ddim_use_original_steps = False,
                      callback = None, timesteps = None, quantize_denoised = False,
                      mask = None, x0 = None, img_callback = None, log_every_t = 100,
                      temperature = 1., noise_dropout = 0., score_corrector = None, corrector_kwargs = None,
                      unconditional_guidance_scale = 1., unconditional_conditioning = None):
        device = self.model.betas.device
        b = shape[0] # batchsize
        if x_T is None:
            img = torch.randn(shape, device=device)
        else:
            img = x_T

        timesteps = self.ddim_timesteps
        intermediates = {'x_inter': [img], 'pred_x0': [img]}
        time_range = np.flip(timesteps) 
        total_steps = timesteps.shape[0] # 50
        print(f"Running DDIM Sampling with {total_steps} timesteps")

        iterator = tqdm(time_range, desc='DDIM Sampler', total=total_steps)

        for i, step in enumerate(iterator): # 981, 961, ..., 1
            index = total_steps - i - 1 
            ts = torch.full((b,), step, device=device, dtype=torch.long) # [981, 981, 981], [961, 961, 961], ...
            outs = self.p_sample_ddim(img, cond, ts, index=index, use_original_steps=ddim_use_original_steps,
                                      quantize_denoised=quantize_denoised, temperature=temperature,
                                      noise_dropout=noise_dropout, score_corrector=score_corrector,
                                      corrector_kwargs=corrector_kwargs,
                                      unconditional_guidance_scale=unconditional_guidance_scale,
                                      unconditional_conditioning=unconditional_conditioning)
            img, pred_x0 = outs # 更新img
            if callback: callback(i)
            if img_callback: img_callback(pred_x0, i)

            if index % log_every_t == 0 or index == total_steps - 1:
                intermediates['x_inter'].append(img)
                intermediates['pred_x0'].append(pred_x0)

        return img, intermediates

    @torch.no_grad()
    def p_sample_ddim(self, x, c, t, index, repeat_noise=False, use_original_steps=False, quantize_denoised=False,
                      temperature=1., noise_dropout=0., score_corrector=None, corrector_kwargs=None,
                      unconditional_guidance_scale=1., unconditional_conditioning=None):
        b, *_, device = *x.shape, x.device

        if unconditional_conditioning is None or unconditional_guidance_scale == 1.:
            e_t = self.model.apply_model(x, t, c)
        else:
            x_in = torch.cat([x] * 2) # [3, 4, 64, 64] -> [6, 4, 64, 64]
            t_in = torch.cat([t] * 2) # [3] -> [6]
            c_in = torch.cat([unconditional_conditioning, c]) # [3, 77, 768] -> [6, 77, 768]
            e_t_uncond, e_t = self.model.apply_model(x_in, t_in, c_in).chunk(2) # using Unet
            e_t = e_t_uncond + unconditional_guidance_scale * (e_t - e_t_uncond) # free guidance

        # 使用ddpm的参数或者make_ddim_sampling_parameters()函数生成的参数,这里默认使用了后者
        alphas = self.model.alphas_cumprod if use_original_steps else self.ddim_alphas
        alphas_prev = self.model.alphas_cumprod_prev if use_original_steps else self.ddim_alphas_prev
        sqrt_one_minus_alphas = self.model.sqrt_one_minus_alphas_cumprod if use_original_steps else self.ddim_sqrt_one_minus_alphas
        sigmas = self.model.ddim_sigmas_for_original_num_steps if use_original_steps else self.ddim_sigmas

        # select parameters corresponding to the currently considered timestep
        a_t = torch.full((b, 1, 1, 1), alphas[index], device = device)
        a_prev = torch.full((b, 1, 1, 1), alphas_prev[index], device = device)
        sigma_t = torch.full((b, 1, 1, 1), sigmas[index], device = device)
        sqrt_one_minus_at = torch.full((b, 1, 1, 1), sqrt_one_minus_alphas[index], device = device)

        # current prediction for x_0
        pred_x0 = (x - sqrt_one_minus_at * e_t) / a_t.sqrt() # 论文https://arxiv.org/pdf/2010.02502中公式(12)的第一项

        # direction pointing to x_t
        dir_xt = (1. - a_prev - sigma_t**2).sqrt() * e_t # 论文https://arxiv.org/pdf/2010.02502中公式(12)的第二项 
        noise = sigma_t * noise_like(x.shape, device, repeat_noise) * temperature # 论文https://arxiv.org/pdf/2010.02502中公式(12)的第三项 # 由于输入的eta为0,因此sigma_t为0,因此本式的结果为0

        if noise_dropout > 0.:
            noise = torch.nn.functional.dropout(noise, p=noise_dropout)
        x_prev = a_prev.sqrt() * pred_x0 + dir_xt + noise # 构成论文https://arxiv.org/pdf/2010.02502中的公式(12),即根据x_t得到x_(t-1)
        return x_prev, pred_x0 
    
if __name__ == "__main__":

    model = DDPM() # 初始化DDPM model
    sampler = DDIMSampler(model)

    # 模拟FrozenCLIPEmbedder的输出
    batchsize = 3
    c = torch.rand(batchsize, 77, 768) # 模拟有prompt时的embedding
    uc = torch.rand(batchsize, 77, 768) # 模拟无prompt时的embedding

    # 使用ddim进行去噪
    shape = [4, 64, 64]
    scale = 7.5 # unconditional guidance scale: eps = eps(x, empty) + scale * (eps(x, cond) - eps(x, empty))
    ddim_eta = 0.0 # ddim eta (eta=0.0 corresponds to deterministic sampling
    samples_ddim, _ = sampler.sample(S = 50, # 采样50步
                                    conditioning = c, # 条件embedding
                                    batch_size = batchsize,
                                    shape = shape,
                                    verbose = False,
                                    unconditional_guidance_scale = scale,
                                    unconditional_conditioning = uc, # 无条件embedding
                                    eta = ddim_eta,
                                    x_T = None)
    
    assert samples_ddim.shape[0] == batchsize
    assert list(samples_ddim[0].shape) == shape
    print("samples_ddim.shape: ", samples_ddim.shape)
    assert samples_ddim.shape[0] == batchsize
    assert list(samples_ddim.shape[1:]) == shape
    print("All Done!")

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

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

相关文章

Java的基础语法

叠甲:以下文章主要是依靠我的实际编码学习中总结出来的经验之谈,求逻辑自洽,不能百分百保证正确,有错误、未定义、不合适的内容请尽情指出! 文章目录 1.第一份程序1.1.代码编写1.2.代码运行1.2.1.命令行编译1.2.2.IEDA…

Science Advances|用于肌电检测的柔性微针电极阵列(健康监测/柔性传感/柔性电子)

2024年5月1日,美国南加州大学Hangbo Zhao课题组在《Science Advances》上发布了一篇题为“Highly stretchable and customizable microneedle electrode arrays for intramuscular electromyography”的论文。论文内容如下: 一、 摘要 可伸缩的三维穿透式微电极阵列在多个领…

Linux环境安装Maven

1.下载安装包 访问Maven官网下载地址:Maven – Download Apache Maven进行下载对应的安装包。 本文档使用的是apache-maven-3.9.8-bin.tar.gz 2.将下载好的安装包上传到环境上,本处是在/usr目录下新建了一个Maven的目录,如下: …

在线白板工具大揭秘:为何它成为远程团队的必备神器?

一直觉得白板是个很好的工具,不管是学习还是工作,它都能够帮助我们更好地整理思路。 作为一名经常需要远程协作和创意脑暴的职场人,显然传统普通的白板工具已经不够用了。 在这个数字化时代,我们更需要一个电子白板,一…

计算机如何存储浮点数

浮点数组成 在计算机中浮点数通常由三部分组成:符号位、指数位、尾数位。IEEE-754中32位浮点数如下: 上图32bit浮点数包含1bit的符号位,8比特的指数位和23bit的尾数位。对于一个常规浮点数,我们来看看它是如何存储和计算的。这里…

FPGA的理解,个人的见解,不一定对

类似于面包板上搭建电路,但是使用的是逻辑单元模块;如加法器,减法器,寄存器等 没有模拟电路的电容,电阻;但是逻辑单元的底层实现,使用MOS管等电路实现电路的开关;从而表示0&#xf…

1002-15SF 同轴连接器

型号简介 1002-15SF是Southwest Microwave的29.2 mm (V) DC 至 67 GHz 连接器。该连接器用于连接电缆和设备的组件,它可以提供电气连接和机械支撑。广泛应用于通信、电子、航空航天、军事等领域。 型号特点 电缆的中心导体插入连接器后部的母插座内置应力释放装置可…

SpringMVC系列十三: SpringMVC执行流程 - 源码分析

源码分析 执行流程图实验设计前端控制器分发请求处理器映射器处理器适配器调用目标方法调用视图解析器渲染视图作业布置 执行流程图 实验设计 1.新建com.zzw.web.debug.HelloHandler Controller public class HelloHandler {//编写方法, 响应请求, 返回ModelAndViewRequestMa…

GD 32点亮流水灯

1. 0 软件架构设置 2.0 API 接口以及数据结构定义 3.0 程序代码实现 程序项目的结构如下所示: 第一步:编写LED驱动,初始化驱动程序 创建结构体:第一个参数表示GPIO使能,第二个参数表示单片机的IO口,第三个…

html+css+js贪吃蛇游戏

贪吃蛇游戏&#x1f579;四个按钮控制方向&#x1f3ae; 源代码在图片后面 点赞❤️关注&#x1f64f;收藏⭐️ 互粉必回&#x1f64f;&#x1f64f;&#x1f60d;&#x1f60d;&#x1f60d; 源代码&#x1f4df; <!DOCTYPE html> <html lang"en"&…

idea删除分支并同步到gitLab以及gitLab上的分支删除

目录 idea删除分支并同步到gitLab 方法一&#xff08;推荐&#xff09; 方法二&#xff08;命令行&#xff09; gitLab上的分支删除 前言-与正文无关 ​ 生活远不止眼前的苦劳与奔波&#xff0c;它还充满了无数值得我们去体验和珍惜的美好事物。在这个快节奏的世界中&…

Tell Me Why:利用大型语言模型进行可解释的公共健康事实核查

Tell Me Why: Explainable Public Health Fact-Checking with Large Language Models 论文地址:https://arxiv.org/abs/2405.09454https://arxiv.org/abs/2405.09454 1.概述 最近的COVID-19大流行突显了公共健康领域事实核查的关键需求。在信息通过社交媒体平台迅速传播的时…

GPU 张量核心(Tensor Core)技术解读

一文理解 GPU 张量核心&#xff08;Tensor Core&#xff09; 引言 最新一代Nvidia GPU搭载Tensor Core技术&#xff0c;本指南深度解读其卓越性能&#xff0c;为您带来极致体验。 Nvidia最新GPU微架构中的核心技术——Tensor Core&#xff0c;自Volta起每代均获突破&#xf…

【漏洞复现】Emlog Pro 2.3.4——任意用户登入、会话持久化(CVE-2024-5044)

声明&#xff1a;本文档或演示材料仅供教育和教学目的使用&#xff0c;任何个人或组织使用本文档中的信息进行非法活动&#xff0c;均与本文档的作者或发布者无关。 文章目录 漏洞描述漏洞复现 漏洞描述 漏洞编号&#xff1a;CVE-2024-5044 漏洞成因&#xff1a; 在Emlog Pro …

加密与安全_ 解读非对称密钥解决密钥配送问题的四个方案

文章目录 Pre对称密钥的死穴 - 经典的密钥配送问题什么是非对称密钥非对称密钥解决密钥配送问题的四个方案共享密钥密钥分配中心&#xff08;KDC&#xff09;Diffie-Hellman 密钥交换体系公钥密码体系RSA算法 Pre 对称密钥的死穴 - 经典的密钥配送问题 假设 Alice 和 Bob 两个人…

阻塞赋值与非阻塞赋值

文章目录 一、何为“阻塞”&#xff1f;二、阻塞赋值与非阻塞赋值1. 阻塞式赋值“”2.非阻塞式赋值“<” 三、什么时候用阻塞赋值或非阻塞赋值&#xff1f; 一、何为“阻塞”&#xff1f; 所谓“阻塞”&#xff0c;可以理解为阻止顺序语句块中其他语句的执行。例如&#xf…

ASP.NET Core----基础学习04----Model模型的创建 服务的注入

文章目录 1. 创建Models文件夹&#xff0c;3个文件的内容如下&#xff1a;&#xff08;1&#xff09;模型的创建&#xff08;2&#xff09;服务的注入 1. 创建Models文件夹&#xff0c;3个文件的内容如下&#xff1a; &#xff08;1&#xff09;模型的创建 模型的基础类Student…

阿里云 Ubuntu 开启允许 ssh 密码方式登录

以前用的 centos&#xff0c;重置系统为 ubuntu 后在ssh 远程连接时遇到了点问题&#xff1a; 在阿里云控制台重置实例密码后无法使用密码进行 SSH 连接登录 原因&#xff1a;阿里云 Ubuntu 默认禁用密码登录方式 解决办法&#xff1a; 先使用其他用户登录到服务器 这里进来…

Java中多线程经典案例

案例一单例模式 只有一个对象,只实例化一个对象 饿汉模式 在程序开始初期的实例化一个对象 static成员初始化时机是在类加载的时候,static修饰的instance只有唯一一个,初始化也是只执行一次,static修饰的是类属性,就是在类对象上的,每个类对象在JVM中只有一份,里面的静态成员…

下载安装JavaFX及解决报错:缺少 JavaFX 运行时组件, 需要使用该组件来运行此应用程序|Eclipse

目录 1.下载并解压 2.Eclipse配置 3.报错问题 解决方法1&#xff1a;将javaSE更改到9以下 解决方法2&#xff1a; 使用module-info.java配置解决 1.下载并解压 JavaFX下载地址&#xff1a;JavaFX - Gluon 选择合适自己电脑配置的sdk版本下载 打不开网页的参考这个博客&…