【扩散模型】DDIM从原理到实战

news2024/12/23 9:19:57

DDIM从原理到实战

  • 1. DDIM简介
  • 2. 实战DDIM
    • 2.1 载入一个预训练过的pipeline
    • 2.2 DDIM采样
    • 2.3 反转(invert)
  • 3. 组合封装
  • 参考资料

DDPM过程的一个问题是在训练后生成图像的速度。当然,我们可能能够生成令人惊叹的图像,但生成一张图像需要1000次模型传递。在GPU上使图像通过模型1000次可能需要几秒钟,但在CPU上需要更长的时间。我们需要一种方法来加快生成过程。

1. DDIM简介

DDIM论文介绍了一种在图像质量几乎没有tradeoff的情况下加快图像生成的方法。它通过将扩散过程重新定义为非马尔可夫过程来做到这一点。
DDIM
左图是原始的DDPM论文,它需要从时间 T T T到时间 T − 1 T-1 T1所有过去的去噪步骤来获得时间T的下一个去噪图像。DDPM被建模为马尔可夫链,这意味着在生成 T T T之前的整个链之前,不能生成时间 T T T的图像。

DDIM论文提出了一种使过程非马尔可夫的方法(如右图所示),允许跳过去噪过程中的步骤,而不需要在当前状态之前访问所有过去的状态。DDIM最好的部分是,它们可以在训练模型后应用,因此DDPM模型可以很容易地转换为DDIM,而无需重新训练新模型

首先,重新定义了single step的逆向扩散过程:
the reverse diffusion process for a single step
注:DDIM论文使用的是不带bar的alphas,但论文中的alphas值是DDPM论文中使用的alphas bar(cumulative alpha)值。这有点令人困惑,所以我将用alpha bars替换它们的alphas,以保持符号的一致性。

首先,这个reformalization相当于DDPM论文中的formalization,但仅当方差等于 β ~ t \tilde{\beta}_t β~t时。
Variance
作者没有明确指出他们的sigma公式只是 β ~ t \tilde{\beta}_t β~t, 但只要有一点代数,你就会发现情况确实如此。

σ = θ \sigma=\theta σ=θ,得到DDIM:
DDIM 去噪公式
请注意,数据中没有添加noise。这就是DDIM的诀窍。当 σ = ⊙ \sigma=\odot σ=时,去噪过程变得完全确定,唯一的噪声是 x 0 x_0 x0处的原始噪声,因为在去噪过程中没有添加新的噪声。

由于逆向过程中没有噪声,因此该过程是确定性的,并且我们不再需要使用马尔可夫链,因为马尔可夫链用于概率过程。我们可以使用非马尔可夫过程,它允许我们跳过步骤
Graphical model for accelerated generation
非马尔可夫正向和逆向过程

在上图中,我们从步骤 x 3 x_3 x3跳到 x 1 x_1 x1,跳过 x 2 x_2 x2。作者将新的扩散过程建模为子序列 τ \tau τ,是原始扩散序列的子集。例如,我可以在扩散过程中每隔一个扩散步骤进行采样,得到 τ = [ 0 , 2 , 4 , … , T − 2 , T ] \tau=[0,2,4,…,T-2,T] τ=[024T2T]的子序列。

最后,作者使用以下公式将模型的扩散模型方差确定为DDIM和DDPM之间的插值:
DDIM variance
η = ⊙ \eta =\odot η=时,由于没有噪声,扩散模型是DDIM,当 η = 1 \eta =1 η=1时,扩散模型为原始DDPM。0和1之间的任何 η \eta η都是DDIM和DDPM之间的插值。

当所采取的步骤数小于原始 T T T步骤时,DDIM的性能比DDPM好得多。下表显示了从0到1的 η \eta η插值以及10、20、50、100和1000个生成步骤的DDPM和DDIM FID分数(对多样性和图像质量进行评分)。请注意,原始模型是在 T = 1000 T=1000 T=1000步上训练的。
DDIM result
DDIM在不同的数据集上产生不同的 η \eta η值和不同的步长。

FID分数越低越好。尽管DDPM在最初的1000个步骤中表现最好,但在生成具有更少生成步骤的图像时,DDIM紧随其后。在使用DDIM时,基本上需要在图像质量和生成时间之间进行权衡,而原始DDPM没有提供这种权衡。现在我们可以用更少的步骤生成高质量的图像!

2. 实战DDIM

安装依赖库:

!pip install -Uq transformers diffusers accelerate

加载依赖包:

import torch
import requests
import torch.nn as nn
import torch.nn.functional as F
from PIL import Image
from io import BytesIO
from tqdm.auto import tqdm
from matplotlib import pyplot as plt
from torchvision import transforms as tfms
from diffusers import StableDiffusionPipeline, DDIMScheduler

# 判断当前GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)

定义图像加载函数:

def load_image(url, size=None):
  response = requests.get(url,timeout=1)
  img = Image.open(BytesIO(response.content)).convert('RGB')
  if size is not None:
    img = img.resize(size)
  return img

2.1 载入一个预训练过的pipeline

使用StableDiffusionPipeline加载预训练模型并配置DDIM调度器,而后对预训练模型进行一次采样。

pipe = StableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5").to(device)
# 配置DDIM调度器
pipe.scheduler = DDIMScheduler.from_config(pipe.scheduler.config)
# 采样一次,保证代码正常
prompt = 'Beautiful DSLR Photograph of a penguin on the beach, golden hour'
negative_prompt = 'blurry, ugly, stock photo'

im = pipe(prompt, negative_prompt=negative_prompt).images[0]
im.resize((256, 256))  # 调整至有利于查看的尺寸

采样结果:
采样结果

2.2 DDIM采样

在给定时刻 t t t,带有噪声的图像 x t x_t xt是通过对原始图像 x 0 x_0 x0加上高斯噪声 ϵ \epsilon ϵ得到的。DDIM论文给出了 x t x_t xt的定义式: x t = α t x 0 + 1 − α t ϵ x_t=\sqrt{\alpha_t}x_0+\sqrt{1-\alpha_t}ϵ xt=αt x0+1αt ϵ
其中 ϵ ϵ ϵ是方差归一化后的高斯噪声, α t \alpha_t αt在DDPM论文中被称为 α ˉ \bar{\alpha} αˉ,并被用于定义噪声调度器。在扩散模型中, α \alpha α被计算并排序存储在scheduler.alphas_cumprod中。

# 选择使用Diffusers中的alphas_cumprod函数来得到alphas
timesteps = pipe.scheduler.timesteps.cpu()
alphas = pipe.scheduler.alphas_cumprod[timesteps]
plt.plot(timesteps, alphas, label='alpha_t');
plt.legend();

噪声曲线
从中可以看出,噪声曲线(在时间步0)是从一幅无噪的干净图像开始的,此时 α t = 1 \alpha_t=1 αt=1。在到达更高的时间步后,便得到一幅几乎全是噪声的图像, α t \alpha_t αt也几乎下降到0。

为了计算采样轨迹中下一个时刻的值 x t − 1 x_{t-1} xt1(因为是从后向前移动的),我们

  • 首先需要得到预测噪声 ϵ θ ( x t ) ϵ_θ(x_t) ϵθ(xt)(这是模型的输出),
  • 然后用它预测不带噪声的图像 x 0 x_0 x0
  • 接下来,朝着“反转”的方向移动一步。
  • 最后,可以加上一些带有 σ t σ_t σt系数的额外噪声

在DDIM论文原文中与上述操作相关的内容是:
Denoising Diffusion Implicit Models
翻译如下:
根据公式(10)中的 p θ ( x 1 : T ) p_{\theta}(x_{1:T}) pθ(x1:T),可以通过公式(12)从 x t x_t xt推导出 x t − 1 x_{t-1} xt1,其中 ϵ t ∼ N ( 0 , I ) \epsilon _t\sim \mathcal{N}(0,\mathrm{I} ) ϵtN(0,I)是独立于 x t x_t xt的标准高斯噪声,并且定义 α 0 = 1 \alpha _0=1 α0=1,使用不同的 α \alpha α值会导致不同的生成流程,因为同时使用了相同的模型 ϵ θ \epsilon _\theta ϵθ,所以不需要重新训练模型。对于所有时刻 t t t,当 θ t = ( 1 − α t − 1 ) / ( 1 − α t ) 1 − α t / α t − 1 \theta_t=\sqrt{(1-\alpha _{t-1})/(1-\alpha _t)}\sqrt{1-\alpha _t/\alpha _{t-1}} θt=(1αt1)/(1αt) 1αt/αt1 时,前向过程将变成马尔可夫过程,生成过程变为DDPM

另一个特殊情况是,即对于几乎所有时刻(t=1除外)的 σ t = 0 \sigma_t=0 σt=0,前向过程在给定 x t − 1 x_{t-1} xt1 x 0 x_0 x0的情况下变得更加确定;在生成过程中,随机噪声 ϵ t \epsilon_t ϵt前面的系数变为0。得到的模型变成隐式概率模型(Mohamed & Lakshminarayanan, 2016),其中的样本是根据固定的过程从隐变量生成的(从 x r x_r xr x 0 x_0 x0)。将这个模型命名为“去噪扩散隐式模型”(Denoising Diffusion Implicit Model, DDIM),因为它是一个使用DDPM目标进行训练的隐式概率模型(尽管前向过程不再是扩散过程)。

因此接下来的示例不需要再额外添加噪声,即可实现完全确定的DDIM采样:

# 采样噪声(标准DDIM采样)
@torch.no_grad()
def sample(
    prompt, 
    start_step=0, 
    start_latents=None, 
    guidance_scale=3.5, 
    num_inference_steps=30, 
    num_images_per_prompt=1, 
    do_classifier_free_guidance=True,
    negative_prompt='',
    device=device
    ):
  # 对文本提示语进行编码
  text_embeddings = pipe._encode_prompt(prompt, device, num_images_per_prompt, do_classifier_free_guidance, negative_prompt)
  # 设置推理的步数
  pipe.scheduler.set_timesteps(num_inference_steps, device=device)
  # 创建随机起点
  if start_latents is None:
    start_latents = torch.randn(1, 4, 64, 64, device=device)
    start_latents *= pipe.scheduler.init_noise_sigma
  
  latents = start_latents.clone()
  for i in tqdm(range(start_step, num_inference_steps)):
    t = pipe.scheduler.timesteps[i]
  
    # 如果正在进行CFG,则对隐层进行扩展
    latent_model_input = torch.cat([latents] * 2) if do_classifier_free_guidance else latents
    latent_model_input = pipe.scheduler.scale_model_input(latent_model_input, t)

    # 预测噪声
    noise_pred = pipe.unet(latent_model_input, t, encoder_hidden_states=text_embeddings).sample

    # 进行引导
    if do_classifier_free_guidance:
      noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)
      noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)
    
    # 使用调度器更新步骤
    # Normally we'd rely on the scheduler to handle the update step:
    # latents = pipe.scheduler.step(noise_pred, t, latents).prev_sample

    # 现在不用调度器,而是自行实现
    prev_t = max(1, t.item()-(1000//num_inference_steps)) # t-1
    alpha_t = pipe.scheduler.alphas_cumprod[t.item()]
    alpha_t_prev = pipe.scheduler.alphas_cumprod[prev_t]
    predicted_x0 = (latents - (1-alpha_t).sqrt()*noise_pred) / alpha_t.sqrt()
    direction_pointing_to_xt = (1-alpha_t_prev).sqrt()*noise_pred
    latents = alpha_t_prev.sqrt()*predicted_x0 + direction_pointing_to_xt
  # 后处理
  images = pipe.decode_latents(latents)
  images = pipe.numpy_to_pil(images)

  return images

生成一张图片:

prompt = 'Watercolor painting of a beach sunset'
sample(prompt, negative_prompt=negative_prompt, num_inference_steps=50)[0].resize((256, 256))

采样函数的测试效果

2.3 反转(invert)

反转的目标是“颠倒”采样的过程。 最终想得到“带噪”的隐式表示,如果将其用作正常采样过程的起点,那么生成的将是原始图像
图片示例:

input_image = load_image('https://images.pexels.com/photos/8306128/pexels-photo-8306128.jpeg', size=(512, 512))
input_image

示例图片
使用一个包含无分类器引导的文本提示语来进行反转操作。
输入图片
定义invert()函数:

# 定义invert函数
@torch.no_grad()
def invert(
    start_latents, 
    prompt, 
    guidance_scale=3.5, 
    num_inference_steps=80,
    num_images_per_prompt=1,
    do_classifier_free_guidance=True,
    negative_prompt='',
    device=device):
  # 对提示文本进行编码
  text_embeddings = pipe._encode_prompt(prompt, device, num_images_per_prompt, do_classifier_free_guidance, negative_prompt)
  # 指定起点
  latents = start_latents.clone()
  # 用一个列表保存反转的隐层
  intermediate_latents = []
  # 设置推理的步数
  pipe.scheduler.set_timesteps(num_inference_steps, device=device)
  # 反转的时间步
  timesteps = reversed(pipe.scheduler.timesteps)

  for i in tqdm(range(1, num_inference_steps), total=num_inference_steps-1):
    # 跳过最后一次迭代
    if i >= num_inference_steps - 1: continue
    t = timesteps[i]
    # 如果正在进行CFG,则对隐层进行扩展
    latent_model_input = torch.cat([latents] * 2) if do_classifier_free_guidance else latents
    latent_model_input = pipe.scheduler.scale_model_input(latent_model_input, t)
    # 预测残留的噪声
    noise_pred = pipe.unet(latent_model_input, t, encoder_hidden_states=text_embeddings).sample
    # 引导
    if do_classifier_free_guidance:
      noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)
      noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)
    current_t = max(0, t.item() - (1000//num_inference_steps)) # t
    next_t = t # min(999, t.item() + (1000//num_inference_steps)) # t+1
    alpha_t = pipe.scheduler.alphas_cumprod[current_t]
    alpha_t_next = pipe.scheduler.alphas_cumprod[next_t]

    # 反转的更新步(重新排列更新步,利用当前隐层得到新的隐层)
    latents = (latents - (1-alpha_t).sqrt() * noise_pred) * (alpha_t_next.sqrt() / alpha_t.sqrt()) + (1-alpha_t_next).sqrt() * noise_pred
    # 保存隐层
    intermediate_latents.append(latents)
  return torch.cat(intermediate_latents)

invert函数与上文中的sample函数非常相似,但是在时间步上是朝着相反的方向移动的:从t=0开始,向噪声更多的方向移动,而不是在更新隐式层的过程中那样噪声越来越少。可以利用预测的噪声来撤回一步更新操作,并从t移动到t+1。

将invert函数应用于示例图片,得到在反转的过程中的一系列隐式表达:

inverted_latents = invert(l, input_image_prompt,num_inference_steps=50)
inverted_latents.shape  # torch.Size([48, 4, 64, 64])

最终的隐式表达:

# 解码反转的最后一个隐层
with torch.no_grad():
    im = pipe.decode_latents(inverted_latents[-1].unsqueeze(0))
pipe.numpy_to_pil(im)[0]

反转过程中最后一层的隐式表达
将其作为起点噪声,通过常规调用方法call,将反转隐式地传递给pipeline

# 可以通过常规调用方法,将反转隐层传递给管线
pipe(input_image_prompt, latents=inverted_latents[-1][None], num_inference_steps=50, guidance_scale=3.5).images[0]

call方法的生成图
显然,这并不是最初的那张照片。这是因为DDIM反转需要一个重要的假设——在时刻 t 预测的噪声与在时刻 t+1 预测的噪声相同,但这个假设在反转50步或者100步时是不成立的

当然,既可以使用更多的时间步来得到更准确的反转,也可以采取“作弊”的方式,直接从相应反转过程50步中的第20步的隐式表达开始,代码如下:

# 从第20步的隐式表示开始,得到的结果距离最初的图片很近了!
start_step=20
sample(input_image_prompt, start_latents=inverted_latents[-(start_step+1)][None], 
       start_step=start_step, num_inference_steps=50)[0]

测试图
显然,得到的结果与最初的图片很接近。

但是,为什么要这么做呢?因为现在想用一个新的文件提示语来生成图片。想要得到一张除了与提示语相关以外,其他内容都与原始图片大致相同的图片。例如:把小狗换成小猫

# 把小狗换成小猫,从第10步的隐式表示开始
start_step=10
new_prompt = input_image_prompt.replace('puppy', 'cat')
sample(new_prompt, start_latents=inverted_latents[-(start_step+1)][None], 
       start_step=start_step, num_inference_steps=50)[0]

将小狗替换为小猫
还有一个问题是,为什么不直接使用Img2Img管线呢?或者是为什么要做反转?为什么不直接对输入图像添加噪声,然后用新的文本提示语直接“去噪”呢?当然可以,但是这会导致图片变化非常大或者图片没什么变化。如下所示:

start_step=10
num_inference_steps=50
pipe.scheduler.set_timesteps(num_inference_steps)
noisy_1 = pipe.scheduler.add_noise(l, torch.randn_like(l), pipe.scheduler.timesteps[start_step])
sample(new_prompt, start_latents=noisy_1, start_step=start_step, num_inference_steps=num_inference_steps)[0]

测试图
这时的草地发生了明显的变化。

3. 组合封装

将所有代码封装到一个函数中,输入一张图片和两个文本提示语,得到一张通过反转得到的修改后的图片

def edit(input_image, input_image_prompt, edit_prompt, num_steps=100, start_step=30, guidance_scale=3.5):
  with torch.no_grad(): 
    latent = pipe.vae.encode(tfms.functional.to_tensor(input_image).unsqueeze(0).to(device)*2-1)
  l = 0.18215 * latent.latent_dist.sample()
  inverted_latents = invert(l, input_image_prompt,num_inference_steps=num_steps)
  final_im = sample(edit_prompt, start_latents=inverted_latents[-(start_step+1)][None], 
                    start_step=start_step, 
                    num_inference_steps=num_steps, 
                    guidance_scale=guidance_scale)[0]
  return final_im

示例1:

edit(input_image, 'A puppy on the grass', 'an old grey dog on the grass', num_steps=50, start_step=10)

修改后的图片:An old grey dog
示例2:

face = load_image('https://images.pexels.com/photos/1493111/pexels-photo-1493111.jpeg', size=(512, 512))
face

原始图片
给原始图片增加一幅眼镜:

edit(face, 'A photograph of a face', 'A photograph of a face with sunglasses', num_steps=250, start_step=30, guidance_scale=3.5)

示例2: with sunglasses
更多的迭代能够得到更好的表现,可以多试几次。

edit(face, 'A photograph of a face', 'Acrylic palette knife painting of a face, colorfull', num_steps=250, start_step=65, guidance_scale=5.5)

示例2:Acrylic palette knife painting of a face, colorfull
推荐阅读:Null-text Inversion for Editing Real Images using Guided Diffusion Models——一个基于DDIM来优化空文本(无条件文本提示语)的反转过程。

参考资料

  1. Diffusion Models — DDPMs, DDIMs, and Classifier Free Guidance
  2. Denoising Diffusion Implicit Models
  3. Null-text Inversion:基于Null Prompt Finetuning的图像编辑技术

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【算法】NOIP2003神经网络

题目描述 人工神经网络(Artificial Neural Network)是一种新兴的具有自我学习能力的计算系统,在模式识别、函数逼近及贷款风险评估等诸多领域有广泛的应用。对神经网络的研究一直是当今的热门方向,兰兰同学在自学了一本神经网络的…

pycharm安装PyQt5及其工具

PyCharm安装PyQt5及其工具(Qt Designer、PyUIC、PyRcc)详细教程_pycharm pyqt5-CSDN博客 上面是原文链接,根据原文链接,我重新记录一下。IDE:pycharm 2023.2.5 一共需要安装5个。 在PyCharm中如何完整优雅地安装配置…

ESP32-Web-Server编程- JS 基础 3

ESP32-Web-Server编程- JS 基础 3 概述 本示例演示通过 button 控件的 onclick 内联属性,实现在网页上点击按钮,切换 LED 灯图标的转变。 示例解析 前端设计 前端代码建立了一个 id 为 “imageLamp” 的图片对象。并建立两个按钮,设计两…

【WP】Geek Challenge 2023 web 部分wp

EzHttp http协议基础题 unsign 简单反序列化题 n00b_Upload 很简单的文件上传&#xff0c;上传1.php&#xff0c;抓包&#xff0c;发现php内容被过滤了&#xff0c;改为<? eval($_POST[‘a’]);?>&#xff0c;上传成功&#xff0c;命令执行读取就好了 easy_php …

企业软件手机app定制开发趋势|小程序网站搭建

企业软件手机app定制开发趋势|小程序网站搭建 随着移动互联网的快速发展和企业数字化转型的加速&#xff0c;企业软件手机App定制开发正成为一个新的趋势。这种趋势主要是由于企业对于手机App的需求增长以及现有的通用应用不能满足企业特定需求的情况下而产生的。 1.企业软件手…

ensp 启动设备时报40错误,然后一直没有去管,再次进去就好了,我知道是配置虚拟机的时候修改了一些设置:

第一个阶段&#xff1a; 那时我是重置电脑之后就安装了ensp所以没有出现什么问题&#xff0c;&#xff08;那时没有导入ce6800和12800还有防火墙6000&#xff09; 第二个阶段&#xff1a; 因为有华为相关的实验要做&#xff0c;所以心血来潮打开了ensp&#xff08;路由器之前…

Maven Helper插件——实现一键Maven依赖冲突问题

总结/朱季谦 业余在一个SpringBoot项目集成Swagger2时&#xff0c;启动过程一直出现以下报错信息—— An attempt was made to call a method that does not exist. The attempt was made from the following location: ​ springfox.documentation.schema.DefaultModelDepe…

Redis面试题:分片集群相关问题

目录 面试官&#xff1a;redis的分片集群有什么作用 面试官&#xff1a;Redis分片集群中数据是怎么存储和读取的&#xff1f; 面试官&#xff1a;redis的分片集群有什么作用 候选人&#xff1a;分片集群主要解决的是&#xff0c;海量数据存储的问题&#xff0c;集群中有多个m…

Selenium 学习(0.16)——软件测试之测试用例设计方法——白盒测试——逻辑覆盖法(语句覆盖和判定覆盖)

写在前面 今天回来有点晚&#xff0c;因为上午给小伙伴们开了个小会&#xff0c;随便说了些什么&#xff0c;结果小伙伴们下班就没急着走&#xff0c;弄点我还有点不好意思提前走了&#xff0c;就略留了一会。其实也没说什么&#xff0c;就是强调工作要抓点紧&#xff0c;8小时…

FLASK博客系列7——我要插入数据库

我们来继续上次的内容&#xff0c;实现将数据插入数据库。 我们先更改下models.py&#xff0c;由于上次笔误&#xff0c;把外键关联写错了。在这里给大家说声抱歉。不过竟然没有小伙伴发现。 models.py from app import dbclass User(db.Model): # 表名将会是 user&#xff0…

GPIO的使用--操作PE02 PE03 PE04实现开关控制灯泡亮灭

效果&#xff1a; 开关控制灯的亮灭 目录 1.找到引脚组别(DEFG) led灯硬件结构 开关硬件结构 2.时钟使能 3.GPIO时钟控制 4.控制实现思路 5. 完整代码 6.视频演示 1.找到引脚组别(DEFG) 开关的引脚组别--E&#xff1b;LED灯的引脚组别--F led灯硬件结构 开关硬件结构…

SpringBoot整合Sharding-Jdbc实现分库分表和分布式全局id

SpringBoot整合Sharding-Jdbc Sharding-Jdbc sharding-jdbc是客户端代理的数据库中间件&#xff1b;它和MyCat最大的不同是sharding-jdbc支持库内分表。 整合 数据库环境 在两台不同的主机上分别都创建了sharding_order数据库&#xff0c;库中都有t_order_1和t_order_2两张…

移动安全威胁:今天和明天的危险

随着技术的发展&#xff0c;个人和公司的设备、数据和隐私所面临的威胁也在发生变化。在本文中&#xff0c;我们将仔细研究当今移动设备安全面临的主要威胁&#xff0c;并共同探讨不久的将来的前景。 但首先让我们从基础开始&#xff1a;如何对移动设备发起攻击&#xff1f; …

血的教训--redis被入侵之漏洞利用复现--总览

血的教训–redis被入侵之漏洞利用复现–总览 相信大家对于自己的服务器被入侵&#xff0c;还是比较憎恨的&#xff0c;我的就被攻击了一次&#xff0c;总结经验&#xff0c;自己也是整理了这一个系列&#xff0c;从最基础到最后面的自己总结被攻破的步骤&#xff0c;非常清晰的…

Jboss启动报错Unrecognized VM option PermSize=128m

1.问题现象 JBoss启动提示创建JAVA虚拟机失败&#xff0c;异常信息如下 异常截图 异常日志 .JBoss Bootstrap Environment .JBOSS_HOME: E:\Jboss\jboss-4.0.2_BR_5.4.4.21\bin\\.. .JAVA: C:\Java\jdk1.6.0_38\bin\java .JAVA_OPTS: -Xms64m -Xmx1024m -Dprogram.namerun.ba…

STK Components 二次开发- StarLink

1.星链数据下载 CelesTrak: Current GP Element Sets 下载二根数就可以。 2.处理数据 下载下来的数据是这样&#xff0c;要将字符串转为 二根数对象 TwoLineElementSet tle new TwoLineElementSet(tleString); Sgp4Propagator propagator new Sgp4Propagator(tle); 3.批量…

红米手机如何远程控制荣耀手机?

很多人都知道&#xff0c;华为体系有【畅联】&#xff0c;与华为手机或平板“畅连”通话时&#xff0c;可共享屏幕给对方&#xff0c;一边聊天一边演示&#xff0c;还可在屏幕上涂鸦帮助理解。同样&#xff0c;小米体系有【小米通话】&#xff0c;它的远程协助功能可以帮助朋友…

C语言--每日选择题--Day27

第一题 1. 对于代码段&#xff0c;问下面不可以表示a[1]地址的是&#xff08;&#xff09; int a[10]; A&#xff1a;&a[0] 1 B&#xff1a;a sizeof(int) C&#xff1a;(int*)&a 1 D&#xff1a;(int*)((char*)&a sizeof(int)) 答案及解析 A A&#xff1a;取到…

【索引优化与查询优化】

文章目录 1. 索引失效的案例1.1 最左优先1.2 主键插入顺序1.3 计算、函数、类型转换(自动或手动)导致索引失效1.4 范围条件右边的列索引失效1.5 非 条件索引失效1.6 like以通配符%开头索引失效1.7 OR 前后存在非索引的列&#xff0c;索引失效 2. 关联查询优化 1. 索引失效的案例…

Locust单机多核压测,以及主从节点的数据通信处理!

一、背景 这还是2个月前做的一次接口性能测试&#xff0c;关于locust脚本的单机多核运行&#xff0c;以及主从节点之间的数据通信。 先简单交代下背景&#xff0c;在APP上线之前&#xff0c;需要对登录接口进行性能测试。经过评估&#xff0c;我还是优先选择了locust来进行脚…