IDDPM原理和代码剖析

2023-11-06

前言

Improved Denoising Diffusion Probabilistic Models(IDDPM) 是上一篇 Denoising Diffusion Probabilistic Models(DDPM)的改进工作。
之前一些重要的公式已在上一篇博客 DDPM原理与代码剖析说过, 这里将不再赘述。本文主要将一些改进点和代码的解释。

本文参考视频 58、Improved Diffusion的PyTorch代码逐行深入讲解, up讲解得很清晰,推荐观看。

本文不断更新中ing…

DDIM针对采样进行了优化,利用respace技巧减少了采样步骤 DDIM原理及代码(Denoising diffusion implicit models)

复现这篇论文代码折腾了一下 Ubuntu 20.04下安装和配置MPI, 感谢这篇文章。
mpi4py这个库一直下不好原来是没有下mpicc。



代码

案例主要基于这份OpenAI官方代码 openai/improved-diffusion
该部分主要关注前向扩散,逆向扩散, 采样以及loss计算。至于模型用的是加了attention的unet,这里不展开。

主要集中于 improved_diffusion/gaussian_diffusion.py中的GaussianDiffusion类, 另外该部分只抽取核心部分代码,至于鲁棒性的,比如assert或者类型转换的代码将不包括,需要运行的请查看原仓库中的代码。

GaussianDiffusion

init

模型参数穿进来了betas, 其中betas是这么来的。原始的DDPM是采用Linear的方式,而IDDPM采用的是cosine的方式。

# gaussian_diffusion.py
def get_named_beta_schedule(schedule_name, num_diffusion_timesteps):
    """
    Get a pre-defined beta schedule for the given name.
    """
    if schedule_name == "linear":
        # Linear schedule from Ho et al, extended to work for any number of
        # diffusion steps.
        scale = 1000 / num_diffusion_timesteps
        beta_start = scale * 0.0001
        beta_end = scale * 0.02
        return np.linspace(
            beta_start, beta_end, num_diffusion_timesteps, dtype=np.float64
        )
    elif schedule_name == "cosine":
        return betas_for_alpha_bar(
            num_diffusion_timesteps,
            lambda t: math.cos((t + 0.008) / 1.008 * math.pi / 2) ** 2,
        )

alphas_cumprod 是 α ‾ t \overline{\alpha}_t αt, alphas_cumprod_prev 是 α ‾ t − 1 \overline{\alpha}_{t-1} αt1, alphas_cumprod_next 是 α ‾ t + 1 \overline{\alpha}_{t+1} αt+1

alphas = 1.0 - betas
alphas_cumprod = np.cumprod(alphas, axis=0)
alphas_cumprod_prev = np.append(1.0, self.alphas_cumprod[:-1])
alphas_cumprod_next = np.append(self.alphas_cumprod[1:], 0.0)

α ‾ t \sqrt{\overline{\alpha}_t} αt 为 sqrt_alphas_cumprod

sqrt_alphas_cumprod = np.sqrt(self.alphas_cumprod)

1 − α ‾ t \sqrt{1-\overline{\alpha}_t} 1αt 为 sqrt_one_minus_alphas_cumprod

sqrt_one_minus_alphas_cumprod = np.sqrt(1.0 - self.alphas_cumprod)

l o g ( 1 − α ‾ t ) log(1-\overline{\alpha}_t) log(1αt) 为 log_one_minus_alphas_cumprod。

log_one_minus_alphas_cumprod = np.log(1.0 - self.alphas_cumprod)

1 α ‾ t \frac{1}{\sqrt{\overline{\alpha}_t}} αt 1 为 sqrt_recip_alphas_cumprod

sqrt_recip_alphas_cumprod = np.sqrt(1.0 / self.alphas_cumprod)

1 α ‾ t − 1 \sqrt{\frac{1}{\overline{\alpha}_t}-1} αt11 为 sqrt_recipm1_alphas_cumprod

sqrt_recipm1_alphas_cumprod = np.sqrt(1.0 / self.alphas_cumprod - 1)

β ~ t = 1 − α ‾ t − 1 1 − α ‾ t β t \widetilde{\beta}_t = \frac{1-\overline{\alpha}_{t-1}}{1-\overline{\alpha}_t}\beta_t β t=1αt1αt1βt

# calculations for posterior q(x_{t-1} | x_t, x_0)
posterior_variance = (
   betas * (1.0 - self.alphas_cumprod_prev) / (1.0 - self.alphas_cumprod)
)

取一个log

# log calculation clipped because the posterior variance is 0 at the
# beginning of the diffusion chain.
posterior_log_variance_clipped = np.log(
   np.append(self.posterior_variance[1], self.posterior_variance[1:])
)

μ ~ ( X t , X 0 ) = α ‾ t − 1 1 − α ‾ t X 0 + α t ( 1 − α ‾ t − 1 ) 1 − α ‾ t X t \widetilde{\mu}(X_t, X_0) = \frac{\sqrt{\overline{\alpha}_{t-1}}}{1-\overline{\alpha}_t} X_0 + \frac{\sqrt{\alpha_t}(1-\overline{\alpha}_{t-1})}{1-\overline{\alpha}_{t}}X_t μ (Xt,X0)=1αtαt1 X0+1αtαt (1αt1)Xt, 其中 X 0 X_0 X0 前的系数对应 posterior_mean_coef1, X t X_t Xt 前的系数对应 posterior_mean_coef2。

posterior_mean_coef1 = (
    betas * np.sqrt(self.alphas_cumprod_prev) / (1.0 - self.alphas_cumprod)
)
posterior_mean_coef2 = (
   (1.0 - self.alphas_cumprod_prev)
   * np.sqrt(alphas)
   / (1.0 - self.alphas_cumprod)
)



q_mean_variance

传入 (x_start, t), 得到 均值和方差
q ( X t ∣ X 0 ) = N ( X t ; α ‾ t X 0 , ( 1 − α ‾ t ) I ) q(X_t|X_0) = N(X_t; \sqrt{\overline{\alpha}_t}X_0, (1-\overline{\alpha}_t)I) q(XtX0)=N(Xt;αt X0,(1αt)I)

mean = (
     _extract_into_tensor(self.sqrt_alphas_cumprod, t, x_start.shape) * x_start
)
variance = _extract_into_tensor(1.0 - self.alphas_cumprod, t, x_start.shape)
log_variance = _extract_into_tensor(
   self.log_one_minus_alphas_cumprod, t, x_start.shape
)

q_sample

重参数化获取加噪后的图片
X t = α ‾ t X 0 + 1 − α ‾ t   ϵ X_t = \sqrt{\overline{\alpha}_t}X_0+\sqrt{1-\overline{\alpha}_t}~\epsilon Xt=αt X0+1αt  ϵ

_extract_into_tensor(self.sqrt_alphas_cumprod, t, x_start.shape) * x_start
+ _extract_into_tensor(self.sqrt_one_minus_alphas_cumprod, t, x_start.shape)
* noise



q_posterior_mean_variance

后验的均值和分布
μ ~ ( X t , X 0 ) = α ‾ t − 1 1 − α ‾ t X 0 + α t ( 1 − α ‾ t − 1 ) 1 − α ‾ t X t \widetilde{\mu}(X_t, X_0) = \frac{\sqrt{\overline{\alpha}_{t-1}}}{1-\overline{\alpha}_t} X_0 + \frac{\sqrt{\alpha_t}(1-\overline{\alpha}_{t-1})}{1-\overline{\alpha}_{t}}X_t μ (Xt,X0)=1αtαt1 X0+1αtαt (1αt1)Xt

posterior_mean = (
            _extract_into_tensor(self.posterior_mean_coef1, t, x_t.shape) * x_start
            + _extract_into_tensor(self.posterior_mean_coef2, t, x_t.shape) * x_t
        )

β ~ t = 1 − α ‾ t − 1 1 − α ‾ t β t \widetilde{\beta}_t = \frac{1-\overline{\alpha}_{t-1}}{1-\overline{\alpha}_t} \beta_t β t=1αt1αt1βt, 这个之前 init 函数中已经算出来了,就不需要再计算了

posterior_variance = _extract_into_tensor(self.posterior_variance, t, x_t.shape)



p_mean_variance

这里传入的是 t t t 时刻的x, 要预测 t − 1 t-1 t1 时刻的 均值mean 和方差variance。
方差既可以学习,也可以固定值。
(1) 方差可学习, 及下面的条件

if self.model_var_type in [ModelVarType.LEARNED, ModelVarType.LEARNED_RANGE]:

需要在channel维度切分一下

model_output, model_var_values = th.split(model_output, C, dim=1)

这里也分两种情况,原始DDPM是直接预测方差

if self.model_var_type == ModelVarType.LEARNED:
	  model_log_variance = model_var_values
	  model_variance = th.exp(model_log_variance)

而improve-DDPM中是预测范围, 及预测下列式子的v。
Σ θ ( X t , t ) = e x p ( v l o g β t + ( 1 − v ) l o g β ~ t ) \Sigma_{\theta}(X_t, t)=exp(vlog\beta_t + (1-v)log \widetilde{\beta}_t) Σθ(Xt,t)=exp(vlogβt+(1v)logβ t)

因为 β ~ t = 1 − α ‾ t − 1 1 − α ‾ t β t \widetilde{\beta}_t = \frac{1-\overline{\alpha}_{t-1}}{1-\overline{\alpha}_t} \beta_t β t=1αt1αt1βt, 而 1 − α ‾ t − 1 < 1 − α ‾ t 1-\overline{\alpha}_{t-1} < 1-\overline{\alpha}_t 1αt1<1αt, 所以 β ~ t < β t \widetilde{\beta}_t < \beta_t β t<βt

故 max_log 就是 l o g β t log \beta_t logβt

max_log = _extract_into_tensor(np.log(self.betas), t, x.shape)

而 min_log 就是 l o g β ~ t log \widetilde{\beta}_t logβ t

min_log = _extract_into_tensor(
                    self.posterior_log_variance_clipped, t, x.shape)

将预测值 [-1, 1] 转化为 [0, 1]

# The model_var_values is [-1, 1] for [min_var, max_var].
frac = (model_var_values + 1) / 2

然后根据公式 Σ θ ( X t , t ) = e x p ( v l o g β t + ( 1 − v ) l o g β ~ t ) \Sigma_{\theta}(X_t, t)=exp(vlog\beta_t + (1-v)log \widetilde{\beta}_t) Σθ(Xt,t)=exp(vlogβt+(1v)logβ t)

model_log_variance = frac * max_log + (1 - frac) * min_log
model_variance = th.exp(model_log_variance)



(2) 方差不可学习
在DDPM中是用 β t \beta_t βt, 而在IDDPM中有两种方式 β t \beta_t βt or β ~ t \widetilde{\beta}_t β t
大的方差即 β t \beta_t βt,

ModelVarType.FIXED_LARGE: (
    # for fixedlarge, we set the initial (log-)variance like so
    # to get a better decoder log likelihood.
    np.append(self.posterior_variance[1], self.betas[1:]),
    np.log(np.append(self.posterior_variance[1], self.betas[1:])),
),

小的方差即 β ~ t \widetilde{\beta}_t β t

ModelVarType.FIXED_SMALL: (
    self.posterior_variance,
    self.posterior_log_variance_clipped,
),

注意上面计算的输出是列表,然后我们只需要取出第 t 时刻的

model_variance = _extract_into_tensor(model_variance, t, x.shape)
model_log_variance = _extract_into_tensor(model_log_variance, t, x.shape)

然后就是对均值的预测
(1) 预测 X t − 1 X_{t-1} Xt1 时刻的均值

if self.model_mean_type == ModelMeanType.PREVIOUS_X:

那么直接

model_mean = model_output

这里顺带还预测除了 X 0 X_0 X0, 在训练中不会用到,但在evaluation中会用到

pred_xstart = process_xstart(
    self._predict_xstart_from_xprev(x_t=x, t=t, xprev=model_output)
)



(2) 预测 X 0 X_0 X0

if self.model_mean_type == ModelMeanType.START_X:

经过一个后处理函数即可

pred_xstart = process_xstart(model_output)



(3) 预测 噪声

ModelMeanType.EPSILON
pred_xstart = process_xstart(
   self._predict_xstart_from_eps(x_t=x, t=t, eps=model_output)
)

μ ~ ( X t , X 0 ) = α ‾ t − 1 1 − α ‾ t X 0 + α t ( 1 − α ‾ t − 1 ) 1 − α ‾ t X t \widetilde{\mu}(X_t, X_0) = \frac{\sqrt{\overline{\alpha}_{t-1}}}{1-\overline{\alpha}_t} X_0 + \frac{\sqrt{\alpha_t}(1-\overline{\alpha}_{t-1})}{1-\overline{\alpha}_{t}}X_t μ (Xt,X0)=1αtαt1 X0+1αtαt (1αt1)Xt

model_mean, _, _ = self.q_posterior_mean_variance(
   x_start=pred_xstart, x_t=x, t=t
)



_predict_xstart_from_xprev

利用该公式计算 X 0 X_0 X0: μ ~ ( X t , X 0 ) = α ‾ t − 1 1 − α ‾ t X 0 + α t ( 1 − α ‾ t − 1 ) 1 − α ‾ t X t \widetilde{\mu}(X_t, X_0) = \frac{\sqrt{\overline{\alpha}_{t-1}}}{1-\overline{\alpha}_t} X_0 + \frac{\sqrt{\alpha_t}(1-\overline{\alpha}_{t-1})}{1-\overline{\alpha}_{t}}X_t μ (Xt,X0)=1αtαt1 X0+1αtαt (1αt1)Xt

return (  # (xprev - coef2*x_t) / coef1
    _extract_into_tensor(1.0 / self.posterior_mean_coef1, t, x_t.shape) * xprev 
    - _extract_into_tensor(
       self.posterior_mean_coef2 / self.posterior_mean_coef1, t, x_t.shape
    )
    * x_t
)



_predict_xstart_from_eps

X 0 = 1 α t ( X t − β t 1 − α ‾ t ϵ ) X_0 = \frac{1}{\sqrt{\alpha_t}}(X_t-\frac{\beta_t}{\sqrt{1-\overline{\alpha}_t}}\epsilon) X0=αt 1(Xt1αt βtϵ)
将上述公式化简
X 0 = 1 α ‾ t X t − 1 α ‾ t − 1   ϵ X_0 = \frac{1}{\sqrt{\overline{\alpha}_t}}X_t - \sqrt{\frac{1}{\overline{\alpha}_t}-1}~\epsilon X0=αt 1Xtαt11  ϵ

_extract_into_tensor(self.sqrt_recip_alphas_cumprod, t, x_t.shape) * x_t
- _extract_into_tensor(self.sqrt_recipm1_alphas_cumprod, t, x_t.shape) * eps



p_sample

基于 X t X_t Xt 采样出 X t − 1 X_{t-1} Xt1
out是 { “mean”: model_mean, “variance”: model_variance, “log_variance”: model_log_variance, “pred_xstart”: pred_xstart}

# 得到 X[t-1]的均值、方差、对数方差、X[0]的预测值
out = self.p_mean_variance(
          model,
          x,
          t,
          clip_denoised=clip_denoised,
          denoised_fn=denoised_fn,
          model_kwargs=model_kwargs,
      )

重参数化采样

noise = th.randn_like(x)
sample = out["mean"] + nonzero_mask * th.exp(0.5 * out["log_variance"]) * noise

p_sample_loop 和 p_sample_loop_progressive 函数迭代调用这个函数。



p_sample_loop_progressive

X 0 X_0 X0

if noise is not None:
   img = noise
else:
   img = th.randn(*shape, device=device)

T, T-1, …, 0

indices = list(range(self.num_timesteps))[::-1]

不断的采样

for i in indices:
    t = th.tensor([i] * shape[0], device=device)
    with th.no_grad():
        out = self.p_sample(
                model,
                img,
                t,
                clip_denoised=clip_denoised,
                denoised_fn=denoised_fn,
                model_kwargs=model_kwargs,
             )
        yield out
        img = out["sample"]



_vb_terms_bpd

vb 变分下界, bpd 是 bit per dimension

算出 q 分布真实的均值和方差

true_mean, _, true_log_variance_clipped = self.q_posterior_mean_variance(
     x_start=x_start, x_t=x_t, t=t
)

算出 p 分布的模型预测的均值和方差

out = self.p_mean_variance(
           model, x_t, t, clip_denoised=clip_denoised, model_kwargs=model_kwargs
)

计算两个高斯分布的KL散度。
L t − 1 = D K L ( q ( X t − 1 ∣ X t , X 0 )   ∣ ∣   p θ ( X t − 1 ∣ X t ) ) L_{t-1} = D_{KL}(q(X_{t-1}|X_t, X_0)~||~ p_\theta (X_{t-1}|X_t)) Lt1=DKL(q(Xt1Xt,X0) ∣∣ pθ(Xt1Xt))

kl = normal_kl( true_mean, true_log_variance_clipped, 
                out["mean"], out["log_variance"])
kl = mean_flat(kl) / np.log(2.0)



L 0 = − l o g p θ ( X 0 ∣ X 1 ) L_0=-log p_{\theta}(X_0|X_1) L0=logpθ(X0X1)
用一个累计函数的差分模拟一个离散分布

decoder_nll = -discretized_gaussian_log_likelihood(
    x_start, means=out["mean"], log_scales=0.5 * out["log_variance"]
)
decoder_nll = mean_flat(decoder_nll) / np.log(2.0)

合并一下, 囊括所有时刻的KL散度

output = th.where((t == 0), decoder_nll, kl)



discretized_gaussian_log_likelihood

improved_diffusion/losses.py

def discretized_gaussian_log_likelihood(x, *, means, log_scales):
    """
    Compute the log-likelihood of a Gaussian distribution discretizing to a
    given image.

    :param x: the target images. It is assumed that this was uint8 values,
              rescaled to the range [-1, 1].
    :param means: the Gaussian mean Tensor.
    :param log_scales: the Gaussian log stddev Tensor.
    :return: a tensor like x of log probabilities (in nats).
    """
    assert x.shape == means.shape == log_scales.shape
    centered_x = x - means
    inv_stdv = th.exp(-log_scales)
    plus_in = inv_stdv * (centered_x + 1.0 / 255.0)
    cdf_plus = approx_standard_normal_cdf(plus_in)
    min_in = inv_stdv * (centered_x - 1.0 / 255.0)
    cdf_min = approx_standard_normal_cdf(min_in)
    log_cdf_plus = th.log(cdf_plus.clamp(min=1e-12))
    log_one_minus_cdf_min = th.log((1.0 - cdf_min).clamp(min=1e-12))
    cdf_delta = cdf_plus - cdf_min
    log_probs = th.where(
        x < -0.999,
        log_cdf_plus,
        th.where(x > 0.999, log_one_minus_cdf_min, th.log(cdf_delta.clamp(min=1e-12))),
    )
    assert log_probs.shape == x.shape
    return log_probs



training_losses

如果losstype是KL的话

if self.loss_type == LossType.KL or self.loss_type == LossType.RESCALED_KL:

调用之前的 vb_terms 函数

terms["loss"] = self._vb_terms_bpd(
                model=model,
                x_start=x_start,
                x_t=x_t,
                t=t,
                clip_denoised=False,
                model_kwargs=model_kwargs,
            )["output"]



至于MSE loss则根据模型预测类型不同加以不同的判断

elif self.loss_type == LossType.MSE or self.loss_type == LossType.RESCALED_MSE:

(1) 如果模型预测的是方差

if self.model_var_type in [
    ModelVarType.LEARNED,
    ModelVarType.LEARNED_RANGE,
]:

拆分开,model_output 和 model_var_values

B, C = x_t.shape[:2]
assert model_output.shape == (B, C * 2, *x_t.shape[2:])
model_output, model_var_values = th.split(model_output, C, dim=1)
frozen_out = th.cat([model_output.detach(), model_var_values], dim=1)
terms["vb"] = self._vb_terms_bpd(
	model=lambda *args, r=frozen_out: r,
	x_start=x_start,
	x_t=x_t,
	t=t,
	clip_denoised=False,
)["output"]

这里由于model已经预测过一回了,就不用再让模型预测一回,所以传入的model直接就是一个恒等返回。这里 frozen_out 是让方差的学习不影响均值的优化。

model=lambda *args, r=frozen_out: r

这里 lambda相当于一个匿名函数

def fun(*args, r=frozen_out):
	return r

如果rescale的话,

if self.loss_type == LossType.RESCALED_MSE:
    # Divide by 1000 for equivalence with initial implementation.
    # Without a factor of 1/1000, the VB term hurts the MSE term.
    terms["vb"] *= self.num_timesteps / 1000.0

接下来就看目标预测的是哪种了
可以是 X t − 1 X_{t-1} Xt1 时刻的均值和方差, X 0 X_0 X0, 也可以是噪声

target = {
            ModelMeanType.PREVIOUS_X: self.q_posterior_mean_variance(
                x_start=x_start, x_t=x_t, t=t
            )[0],
            ModelMeanType.START_X: x_start,
            ModelMeanType.EPSILON: noise,
          }[self.model_mean_type]

然后就算个MSEloss即可

terms["mse"] = mean_flat((target - model_output) ** 2)

再把loss合起来

if "vb" in terms:
    terms["loss"] = terms["mse"] + terms["vb"]
else:
    terms["loss"] = terms["mse"]

总之,当方差可学习的话,就会有 vb 这一项损失。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

IDDPM原理和代码剖析 的相关文章

  • 使用plsql访问远程数据库

    1 plsql输入ip端口数据库实例名直接登录 Username 用户名 如 scott Password 用户对应密码 如 tiger Database 数据库位置 语法为 ip 端口号 数据库实例名 如 192 168 1 156 15
  • Nand Flash的同步、异步、ONFI、Toggle

    1 SDR和DDR SDR Single Data Rate 写读数据使用上升沿或下降沿来触发 因为只用上升沿或下降沿 对信号准确性要求较低 DDR Double Data Rate 写数据时通过MCU来控制DQS信号跳变沿来触发 即上升沿
  • android fragment 重复创建的问题

    解决fragment重复创建目前用到有两个方法 1 fragment同viewpager一起使用 vp setOffscreenPageLimit 3 设置缓存页面的个数 2 fragment单独使用 在onCreateView 方法中加入
  • 用C语言写UTF-8编码的文件

    原文地址 http blog csdn net zaffix article details 7217701 为实现用C语言写UTF 8编码的文件 测试了以下两种情况 第一种情况 为 fopen 指定一个编码 然后写入 wchar t 字符
  • Flink笔记14:Flink之window起始点的确定与watermark使用详解

    1 window起始时间的确定 在TimeWindow java中有如下方法来确定window的起始时间 public static long getWindowStartWithOffset long timestamp long off
  • win32 API函数大全

    1 API之网络函数 WNetAddConnection 创建同一个网络资源的永久性连接 WNetAddConnection2 创建同一个网络资源的连接 WNetAddConnection3 创建同一个网络资源的连接 WNetCancelC
  • Python网络爬虫之数美滑块的加密及轨迹之动态js参数分析

    前言 数美滑块的加密及轨迹等应该是入门级别的吧 用他们的教程和话来说 就一个des 然后识别缺口位置可以用cv2或者ddddoc 轨迹 也可以随便模拟一个 这些简单的教程 在csdn已经有一大把可以搜到的 但是却很少人告诉你 它的js好像是

随机推荐

  • CMake 命令

    1 Usage cmake options
  • MAC安装渗透测试靶机

    1 mac 安装docker 直接到docker官网下载docker dmg 下载前先要注册docker 下载后直接安装就可以了 docker version 就能看见安装的版本 我的版本17 03 1 ce 2 下载docker镜像ima
  • 了解l电源纹波PSRR----转摘

    PSRR 就是 Power Supply Rejection Ratio 的缩写 中文含意为 电源纹波抑制比 也就是说 PSRR 表示把输入与电源视为两个独立的信号源时 所得到的两个电压增益的比值 基本计算公式为 PSRR 20log Ri
  • 【C语言】-- 整型数据的存储

    目录 1 数据类型的分类 2 基本类型 2 1 基本类型大小 2 2 整型家族 2 3 数据的存储形式 2 4 整形数据的存储方式 1 数据类型的分类 在C语言中有如下类型 2 基本类型 2 1 基本类型大小 一个变量的创建是要在内存中开辟
  • node の SQLite

    node操作SQLite 之前在做electron桌面制作番茄钟应用时曾经想过用数据库存储数据 一开始打算mongodb 但是发现不能实现无服务器 那么只能使用SQLite了 介绍 SQLite 是一个软件库 实现了自给自足的 无服务器的
  • android 前端常用布局文件升级总结(一)

    问题一 android support design widget CoordinatorLayout 报红 不显示页面 解决方法 把xml布局文件里面的 android support design widget CoordinatorL
  • SpringBoot + Prometheus + Grafana 打造可视化监控

    SpringBoot Prometheus Grafana 打造可视化监控 文章目录 SpringBoot Prometheus Grafana 打造可视化监控 常见的监控组件搭配 安装Prometheus 安装Grafana 搭建Spri
  • [正能量系列]失业的程序员(一)

    注 本文原型为作者的好友 全文不完全代表作者本人的意图 不小心 我失业了 原因是前几天和我的部门经理拍了桌子 我的组员去内蒙古出差 项目没有中标 年后 长得很像猪刚烈的部门经理发飙了 要辞退我的组员 我纳闷了 我的组员是技术支持 要退也应该
  • Proxmox VE虚拟化从入门到应用实战-服务器管理篇(网络配置2

    Proxmox VE虚拟化从入门到应用实战 服务器管理篇 网络配置2 一 Linux多网口绑定 多网口绑定 也称为网卡组或链路聚合 是一种将多个网卡绑定单个网络设备的技术 利用该技术可以实现某个或多个目标 例如提高网络链容错能力 增加网络通
  • 哈希算法总结

    目录 1 Hash是什么 它的作用 2 Hash算法有什么特点 2 1 Hash在管理数据结构中的应用 2 1 Hash在在密码学中的应用 3 Hash算法是如何实现的 4 Hash有哪些流行的算法 5 那么 何谓Hash算法的 碰撞 5
  • Markdown文件关机没保存,怎么恢复

    1 2 点开找到你想恢复的时间段的文件
  • JS date格式化

    Date prototype Format function fmt author meizz use strict jshint var o M this getMonth 1 月份 d this getDate 日 h this get
  • Qt Creator中,include路径包含过程(或如何找到对应的头文件)

    Qt Creator中 include路径包含过程 或如何找到对应的头文件 利用Qt Creator开发程序时 需要包含利用 include来添加头文件 大家都知道 include lt gt 用于包含标准库头文件 路径在安装软件的incl
  • centos7环境下mysql8的tar包的安装及配置

    内网环境下安装及配置 并将数据保存指向某个文件夹 因为博主这里的数据文件夹是有硬盘挂靠的 centos 7 aliyun CentOS 7 x86 64 DVD 1810 mysql mysql 8 0 17 linux glibc2 12
  • 【题解】闯关游戏

    题目描述 艾伦正在闯关 游戏有N个关卡 按照必须完成的顺序编号为1到N 每个关卡可以用两个参数来描述 prob i 和value i 这些参数的含义如下 每当艾伦尝试闯第i关时 他要么顺利通过 要么 挂掉 他完成该关卡的概率总是prob i
  • Red5应用开发(二)直播串流与录制

    环境 操作系统 win10 1803 Eclipse版本 4 7 3a Oxygen J2EE版本 Red5 Server版本 1 0 8 Release 环境搭建参考前一篇文章 Red5应用开发 一 开发环境搭建 后续不再涉及red5 f
  • 职场加班

    总是听到形形色色的职场加班过劳死的故事 甚至有人写了一篇文章 别让老板杀了你 职场果真那么恐怖吗 其实公司怎么想那是公司的事情 公司有权想着把你干掉 把你榨干 因为这样对于公司最有利 但是 问题在于我们自己怎么想呢 在我看来 在这个社会上混
  • python 泛型函数--singledispatch的使用

    functools singledispatch 将一个函数转变为单一分派的泛型函数 用 singledispatch装饰一个函数 将定义一个泛型函数 注意 我们创建的函数获得分派的依据是第一个参数的类型 from functools im
  • SSM框架整合方案(Spring+SpringMVC+Mybatis)

    一 将application进行纵向切分 每一个配置文件只配置与之相关的Bean 除此之外 项目中通常还有log4j properties SqlMapConfig xml db properties文件 二 各文件配置方案详解 1 日志组
  • IDDPM原理和代码剖析

    前言 Improved Denoising Diffusion Probabilistic Models IDDPM 是上一篇 Denoising Diffusion Probabilistic Models DDPM 的改进工作 之前一些