【AIGC】Diffusers:加载管道、模型和调度程序

前言

拥有一种使用扩散系统进行推理的简单方法对于🧨扩散器至关重要。扩散系统通常由多个组件组成,例如参数化模型、分词器和调度器,它们以复杂的方式进行交互。这就是为什么我们设计了 DiffusionPipeline,将整个扩散系统的复杂性包装成一个易于使用的 API,同时保持足够的灵活性以适应其他用例,例如将每个组件单独加载为构建块以组装您自己的扩散系统。

推理或训练所需的一切都可以通过该 from_pretrained() 方法访问。

 本指南将向您展示如何加载:

  • 来自中心和本地的管道
  • 将不同的组件放入管道中
  • 模型变体,例如不同的浮点类型或非指数平均平均 (EMA) 权重
  • 模型和调度程序

扩散管线 

 💡 如果您有兴趣更详细地了解 DiffusionPipeline 类的工作原理,请跳到DiffusionPipeline 说明部分。

DiffusionPipeline 类是从 Hub 加载最新趋势扩散模型的最简单、最通用的方法。DiffusionPipeline.from_pretrained() 方法自动从检查点检测正确的管道类,下载并缓存所有必需的配置和权重文件,并返回准备进行推理的管道实例。

from diffusers import DiffusionPipelinerepo_id = "runwayml/stable-diffusion-v1-5"
pipe = DiffusionPipeline.from_pretrained(repo_id, use_safetensors=True)

 还可以加载具有特定管道类的检查点。上面的示例加载了一个稳定扩散模型;若要获得相同的结果,请使用 StableDiffusionPipeline 类:

from diffusers import StableDiffusionPipelinerepo_id = "runwayml/stable-diffusion-v1-5"
pipe = StableDiffusionPipeline.from_pretrained(repo_id, use_safetensors=True)

 模型(如 CompVis/stable-diffusion-v1-4 或runwayml/stable-diffusion-v1-5 )也可以用于多个任务,例如文本到图像或图像到图像。若要区分要将模型用于的任务,必须直接使用其相应的特定于任务的管道类加载它:

from diffusers import StableDiffusionImg2ImgPipelinerepo_id = "runwayml/stable-diffusion-v1-5"
pipe = StableDiffusionImg2ImgPipeline.from_pretrained(repo_id)

 本地管道

 若要在本地加载扩散管道,请使用 git-lfs 手动将模型(在本例中为 runwayml/stable-diffusion-v1-5 )下载到本地磁盘。这会在磁盘上创建一个本地文件夹 ./stable-diffusion-v1-5 , :

git-lfs install
git clone https://huggingface.co/runwayml/stable-diffusion-v1-5

 然后将本地路径传递给 from_pretrained():

from diffusers import DiffusionPipelinerepo_id = "./stable-diffusion-v1-5"
stable_diffusion = DiffusionPipeline.from_pretrained(repo_id, use_safetensors=True)

 当 from_pretrained() 方法检测到本地路径时,它不会从 Hub 下载任何文件,但这也意味着它不会下载和缓存检查点的最新更改。

 在管道中交换组件

 您可以使用另一个兼容组件自定义任何管道的默认组件。定制很重要,因为:

  • 更改调度程序对于探索生成速度和质量之间的权衡非常重要。
  • 模型的不同组件通常是独立训练的,您可以将组件换成性能更好的组件。
  • 在微调过程中,通常只训练某些组件(如 UNet 或文本编码器)。

 若要找出哪些计划程序与自定义兼容,可以使用以下 compatibles 方法:

from diffusers import DiffusionPipelinerepo_id = "runwayml/stable-diffusion-v1-5"
stable_diffusion = DiffusionPipeline.from_pretrained(repo_id, use_safetensors=True)
stable_diffusion.scheduler.compatibles

让我们使用 SchedulerMixin.from_pretrained() 方法将默认的 PNDMScheduler 替换为性能更高的调度器 EulerDiscreteScheduler。从管道存储库的正确子文件夹加载调度程序配置需要该 subfolder="scheduler" 参数。

然后,您可以将新的 EulerDiscreteScheduler 实例传递给 DiffusionPipeline 中的 scheduler 参数:

from diffusers import DiffusionPipeline, EulerDiscreteSchedulerrepo_id = "runwayml/stable-diffusion-v1-5"
scheduler = EulerDiscreteScheduler.from_pretrained(repo_id, subfolder="scheduler")
stable_diffusion = DiffusionPipeline.from_pretrained(repo_id, scheduler=scheduler, use_safetensors=True)

安全检查器

 像 Stable Diffusion 这样的扩散模型可能会产生有害内容,这就是为什么 🧨 Diffusers 有一个安全检查器来检查生成的输出是否符合已知的硬编码 NSFW 内容。如果您出于任何原因想要禁用安全检查器,请传递 None safety_checker 参数:

from diffusers import DiffusionPipelinerepo_id = "runwayml/stable-diffusion-v1-5"
stable_diffusion = DiffusionPipeline.from_pretrained(repo_id, safety_checker=None, use_safetensors=True)
"""
You have disabled the safety checker for <class 'diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion.StableDiffusionPipeline'> by passing `safety_checker=None`. Ensure that you abide by the conditions of the Stable Diffusion license and do not expose unfiltered results in services or applications open to the public. Both the diffusers team and Hugging Face strongly recommend keeping the safety filter enabled in all public-facing circumstances, disabling it only for use cases that involve analyzing network behavior or auditing its results. For more information, please have a look at https://github.com/huggingface/diffusers/pull/254 .
"""

 跨管道重用组件

您还可以在多个管道中重复使用相同的组件,以避免两次将权重加载到 RAM 中。使用 components 方法保存组件: 

from diffusers import StableDiffusionPipeline, StableDiffusionImg2ImgPipelinemodel_id = "runwayml/stable-diffusion-v1-5"
stable_diffusion_txt2img = StableDiffusionPipeline.from_pretrained(model_id, use_safetensors=True)components = stable_diffusion_txt2img.components

 然后,您可以将其 components 传递到另一个管道,而无需将权重重新加载到 RAM 中:

stable_diffusion_img2img = StableDiffusionImg2ImgPipeline(**components)

如果希望更灵活地重用或禁用哪些组件,还可以将组件单独传递到管道。例如,若要在图像到图像管道中重用文本到图像管道中的相同组件,但安全检查器和特征提取器除外:

from diffusers import StableDiffusionPipeline, StableDiffusionImg2ImgPipelinemodel_id = "runwayml/stable-diffusion-v1-5"
stable_diffusion_txt2img = StableDiffusionPipeline.from_pretrained(model_id, use_safetensors=True)
stable_diffusion_img2img = StableDiffusionImg2ImgPipeline(vae=stable_diffusion_txt2img.vae,text_encoder=stable_diffusion_txt2img.text_encoder,tokenizer=stable_diffusion_txt2img.tokenizer,unet=stable_diffusion_txt2img.unet,scheduler=stable_diffusion_txt2img.scheduler,safety_checker=None,feature_extractor=None,requires_safety_checker=False,
)

模型权重变体

 以不同的浮点类型存储,以实现较低的精度和较低的存储,例如 torch.float16 ,因为它只需要一半的带宽和存储即可下载。如果您正在继续训练或使用 CPU,则无法使用此变体。

非指数平均 (EMA) 权重,不应用于推理。您应该使用它们来继续微调模型。 

 💡 当检查点具有相同的模型结构,但它们是在不同的数据集上训练的,并且使用不同的训练设置时,它们应该存储在单独的存储库中,而不是变体(例如, stable-diffusion-v1-4 和 stable-diffusion-v1-5 )。

 否则,变体与原模型相同。它们具有完全相同的序列化格式(如 Safetensors)、模型结构和具有相同张量形状的权重。

checkpoint type 检查点类型weight name 重量名称argument for loading weights
加载砝码的参数
original 源语言diffusion_pytorch_model.bin
floating point 浮点diffusion_pytorch_model.fp16.binvarianttorch_dtype
non-EMA 非 EMAdiffusion_pytorch_model.non_ema.binvariant

 对于加载变体,有两个重要的参数需要了解:

 

  • torch_dtype 定义加载的检查点的浮点精度。例如,如果要通过加载 fp16 变体来节省带宽,则应指定 torch_dtype=torch.float16 将权重转换为 fp16 。否则, fp16 权重将转换为默认 fp32 精度。您也可以在不定义 variant 参数的情况下加载原始检查点,并将其转换为 fp16 with torch_dtype=torch.float16 .在这种情况下,将首先下载默认 fp32 权重,然后在加载后将其 fp16 转换为默认权重。

  • variant 定义应从存储库加载哪些文件。例如,如果要从存储库加载 non_ema 变体,则应指定 variant="non_ema" 下载 non_ema diffusers/stable-diffusion-variants 文件。

from diffusers import DiffusionPipeline
import torch# load fp16 variant
stable_diffusion = DiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5", variant="fp16", torch_dtype=torch.float16, use_safetensors=True
)
# load non_ema variant
stable_diffusion = DiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5", variant="non_ema", use_safetensors=True
)

若要将存储在不同浮点类型中的检查点保存为非 EMA 变体,请使用 DiffusionPipeline.save_pretrained() 方法并指定 variant 参数。您应该尝试将变体保存到与原始检查点相同的文件夹中,以便您可以从同一文件夹加载两者:

from diffusers import DiffusionPipeline# save as fp16 variant
stable_diffusion.save_pretrained("runwayml/stable-diffusion-v1-5", variant="fp16")
# save as non-ema variant
stable_diffusion.save_pretrained("runwayml/stable-diffusion-v1-5", variant="non_ema")

如果不将变体保存到现有文件夹,则必须指定参数, variant 否则它将抛出一个 Exception ,因为它找不到原始检查点:

# 👎 this won't work
stable_diffusion = DiffusionPipeline.from_pretrained("./stable-diffusion-v1-5", torch_dtype=torch.float16, use_safetensors=True
)
# 👍 this works
stable_diffusion = DiffusionPipeline.from_pretrained("./stable-diffusion-v1-5", variant="fp16", torch_dtype=torch.float16, use_safetensors=True
)

模型

 模型从 ModelMixin.from_pretrained() 方法加载,该方法下载并缓存最新版本的模型权重和配置。如果本地缓存中有最新的文件,则 from_pretrained() 会重用缓存中的文件,而不是重新下载它们。

 可以从带有参数的 subfolder 子文件夹加载模型。例如,模型权重 runwayml/stable-diffusion-v1-5 存储在 unet 子文件夹中:

from diffusers import UNet2DConditionModelrepo_id = "runwayml/stable-diffusion-v1-5"
model = UNet2DConditionModel.from_pretrained(repo_id, subfolder="unet", use_safetensors=True)

或者直接从存储库的目录

from diffusers import UNet2DModelrepo_id = "google/ddpm-cifar10-32"
model = UNet2DModel.from_pretrained(repo_id, use_safetensors=True)

您还可以通过在 ModelMixin.from_pretrained() 和 ModelMixin.save_pretrained() 中指定 variant 参数来加载和保存模型变体:

from diffusers import UNet2DConditionModelmodel = UNet2DConditionModel.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="unet", variant="non_ema", use_safetensors=True
)
model.save_pretrained("./local-unet", variant="non_ema")

 调度程序

调度器是从 SchedulerMixin.from_pretrained() 方法加载的,与模型不同,调度器没有参数化或训练;它们由配置文件定义。 

加载调度程序不会消耗任何大量内存,并且相同的配置文件可用于各种不同的调度程序。例如,以下调度程序与 StableDiffusionPipeline 兼容,这意味着您可以在以下任何类中加载相同的调度程序配置文件: 

from diffusers import StableDiffusionPipeline
from diffusers import (DDPMScheduler,DDIMScheduler,PNDMScheduler,LMSDiscreteScheduler,EulerAncestralDiscreteScheduler,EulerDiscreteScheduler,DPMSolverMultistepScheduler,
)repo_id = "runwayml/stable-diffusion-v1-5"ddpm = DDPMScheduler.from_pretrained(repo_id, subfolder="scheduler")
ddim = DDIMScheduler.from_pretrained(repo_id, subfolder="scheduler")
pndm = PNDMScheduler.from_pretrained(repo_id, subfolder="scheduler")
lms = LMSDiscreteScheduler.from_pretrained(repo_id, subfolder="scheduler")
euler_anc = EulerAncestralDiscreteScheduler.from_pretrained(repo_id, subfolder="scheduler")
euler = EulerDiscreteScheduler.from_pretrained(repo_id, subfolder="scheduler")
dpm = DPMSolverMultistepScheduler.from_pretrained(repo_id, subfolder="scheduler")# replace `dpm` with any of `ddpm`, `ddim`, `pndm`, `lms`, `euler_anc`, `euler`
pipeline = StableDiffusionPipeline.from_pretrained(repo_id, scheduler=dpm, use_safetensors=True)

DiffusionPipeline 解释

 作为类方法,DiffusionPipeline.from_pretrained() 负责两件事:

  • 下载推理所需的最新版本的文件夹结构并对其进行缓存。如果本地缓存中提供了最新的文件夹结构,则 DiffusionPipeline.from_pretrained() 会重用缓存,并且不会重新下载文件。
  • 将缓存的权重加载到正确的管道类(从文件中 model_index.json 检索),并返回该类的实例。

 管道的基础文件夹结构与其类实例直接对应。例如,StableDiffusionPipeline 对应于 runwayml/stable-diffusion-v1-5 中的文件夹结构。

from diffusers import DiffusionPipelinerepo_id = "runwayml/stable-diffusion-v1-5"
pipeline = DiffusionPipeline.from_pretrained(repo_id, use_safetensors=True)
print(pipeline)

 你将看到 pipeline 是 StableDiffusionPipeline 的一个实例,它由七个组件组成:

 

  • "feature_extractor" :来自 Transformer 的 🤗 CLIPImageProcessor。
  • "safety_checker" :用于筛选有害内容的组件。
  • "scheduler" :PNDMScheduler 的实例。
  • "text_encoder" :来自 Transformer 的 🤗 CLIPTextModel。
  • "tokenizer" :来自Transformer的 🤗 CLIPTokenizer。
  • "unet" :UNet2DConditionModel 的实例。
  • "vae" :AutoencoderKL 的实例。
StableDiffusionPipeline {"feature_extractor": ["transformers","CLIPImageProcessor"],"safety_checker": ["stable_diffusion","StableDiffusionSafetyChecker"],"scheduler": ["diffusers","PNDMScheduler"],"text_encoder": ["transformers","CLIPTextModel"],"tokenizer": ["transformers","CLIPTokenizer"],"unet": ["diffusers","UNet2DConditionModel"],"vae": ["diffusers","AutoencoderKL"]
}

将管道实例的组件与文件夹结构进行比较,你将看到存储库中的每个组件都有一个单独的 runwayml/stable-diffusion-v1-5 文件夹:

.
├── feature_extractor
│   └── preprocessor_config.json
├── model_index.json
├── safety_checker
│   ├── config.json
|   ├── model.fp16.safetensors
│   ├── model.safetensors
│   ├── pytorch_model.bin
|   └── pytorch_model.fp16.bin
├── scheduler
│   └── scheduler_config.json
├── text_encoder
│   ├── config.json
|   ├── model.fp16.safetensors
│   ├── model.safetensors
│   |── pytorch_model.bin
|   └── pytorch_model.fp16.bin
├── tokenizer
│   ├── merges.txt
│   ├── special_tokens_map.json
│   ├── tokenizer_config.json
│   └── vocab.json
├── unet
│   ├── config.json
│   ├── diffusion_pytorch_model.bin
|   |── diffusion_pytorch_model.fp16.bin
│   |── diffusion_pytorch_model.f16.safetensors
│   |── diffusion_pytorch_model.non_ema.bin
│   |── diffusion_pytorch_model.non_ema.safetensors
│   └── diffusion_pytorch_model.safetensors
|── vae
.   ├── config.json
.   ├── diffusion_pytorch_model.bin├── diffusion_pytorch_model.fp16.bin├── diffusion_pytorch_model.fp16.safetensors└── diffusion_pytorch_model.safetensors

您可以将管道的每个组件作为属性进行访问,以查看其配置:

pipeline.tokenizer
CLIPTokenizer(name_or_path="/root/.cache/huggingface/hub/models--runwayml--stable-diffusion-v1-5/snapshots/39593d5650112b4cc580433f6b0435385882d819/tokenizer",vocab_size=49408,model_max_length=77,is_fast=False,padding_side="right",truncation_side="right",special_tokens={"bos_token": AddedToken("<|startoftext|>", rstrip=False, lstrip=False, single_word=False, normalized=True),"eos_token": AddedToken("<|endoftext|>", rstrip=False, lstrip=False, single_word=False, normalized=True),"unk_token": AddedToken("<|endoftext|>", rstrip=False, lstrip=False, single_word=False, normalized=True),"pad_token": "<|endoftext|>",},clean_up_tokenization_spaces=True
)

每个管道都需要一个 model_index.json 文件,该文件告诉 DiffusionPipeline:

  • 要从 _class_name 哪个管道类加载
  • 哪个版本的🧨扩散器用于创建模型 _diffusers_version
{"_class_name": "StableDiffusionPipeline","_diffusers_version": "0.6.0","feature_extractor": ["transformers","CLIPImageProcessor"],"safety_checker": ["stable_diffusion","StableDiffusionSafetyChecker"],"scheduler": ["diffusers","PNDMScheduler"],"text_encoder": ["transformers","CLIPTextModel"],"tokenizer": ["transformers","CLIPTokenizer"],"unet": ["diffusers","UNet2DConditionModel"],"vae": ["diffusers","AutoencoderKL"]
}

参考链接:

 https://huggingface.co/docs/diffusers/using-diffusers/loading

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

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

相关文章

检测头篇 | 原创自研 | YOLOv8 更换 SEResNeXtBottleneck 头 | 附详细结构图

左图:ResNet 的一个模块。右图:复杂度大致相同的 ResNeXt 模块,基数(cardinality)为32。图中的一层表示为(输入通道数,滤波器大小,输出通道数)。 1. 思路 ResNeXt是微软研究院在2017年发表的成果。它的设计灵感来自于经典的ResNet模型,但ResNeXt有个特别之处:它采用…

HiveSQL题——用户连续登陆

目录 一、连续登陆 1.1 连续登陆3天以上的用户 0 问题描述 1 数据准备 2 数据分析 3 小结 1.2 每个用户历史至今连续登录的最大天数 0 问题描述 1 数据准备 2 数据分析 3 小结 1.3 每个用户连续登录的最大天数(间断也算) 0 问题描述 1 数据准备 2 数据分析 3 小…

qt信号与槽机制及使用demo

要在 Qt 中将 rclcomm 类与 MainWindow 连接&#xff0c;并使用 rcl->pose_uids 中的项更新 comboBox_model&#xff0c;您可以按照以下步骤操作&#xff1a; 信号与槽机制&#xff1a;Qt 使用信号和槽机制来处理事件和对象间通信。您可以在 rclcomm 类中定义一个信号&#…

MySQL-窗口函数 简单易懂

窗口函数 考查知识点&#xff1a; • 如何用窗口函数解决排名问题、Top N问题、前百分之N问题、累计问题、每组内比较问题、连续问题。 什么是窗口函数 窗口函数也叫作OLAP&#xff08;Online Analytical Processing&#xff0c;联机分析处理&#xff09;函数&#xff0c;可…

Python入门知识点分享——(十七)正则表达式和re模块

不好意思鸽了这么久&#xff0c;这几天备赛美赛没有太多时间写博客。好了闲话少叙&#xff0c;这次为大家带来的是正则表达式的相关介绍。正则表达式又叫做规则表达式,英文全称Regular Expression。是一种对字符串操作的逻辑公式&#xff0c;就是用事先定义好的一些特定字符、及…

RK3568平台 of 操作函数获取属性

一.of 操作函数获取属性 of_find_property 函数&#xff0c;用于在设备树中查找节点 下具有指定名称的属性。 struct property *of_find_property(const struct device_node *np, const char *name, int*lenp)np: 要查找的节点。 name: 要查找的属性的属性名。 lenp: 一个指…

Android 基础技术——列表卡顿问题如何分析解决

笔者希望做一个系列&#xff0c;整理 Android 基础技术&#xff0c;本章是关于列表卡顿问题如何分析解决 onBindViewHolder 优化 是否有耗时操作、重复创建对象、设置监听器、findViewByID、局部的动画对象等操作 是否存在内存泄漏 发生内存泄露&#xff0c;会导致一些不再使用…

游戏开发丨基于Tkinter的扫雷小游戏

文章目录 写在前面扫雷小游戏需求分析程序设计程序分析运行结果系列文章写在后面 写在前面 本期内容 基于tkinter的扫雷小游戏 所需环境 pythonpycharm或anaconda 下载地址 https://download.csdn.net/download/m0_68111267/88790713 扫雷小游戏 扫雷是一款广为人知的单…

RabbitMQ“延时队列“

1.RabbitMQ"延时队列" 延迟队列存储的对象是对应的延迟消息&#xff0c;所谓“延迟消息”是指当消息被发送以后&#xff0c;并不想让消费者立刻拿到消息&#xff0c;而是等待特定时间后&#xff0c;消费者才能拿到这个消息进行消费 注意RabbitMQ并没有延时队列慨念,…

【ArcGIS微课1000例】0097:栅格重采样(以数字高程模型dem为例)

Contents 1. 最邻近法(Nearest Neighbor)2. 双线性内插法(Bilinear Interpolation)3. 三次卷积法(Cubic Convolution)4. ArcGIS重采样工具(Resample)5. 注意事项栅格/影像数据进行配准或纠正、投影等几何变换后,像元中心位置通常会发生变化,其在输入栅格中的位置不一…

OpenCV-29 自适应阈值二值化

一、引入 在前面的部分我们使用的是全局阈值&#xff0c;整幅图像采用同一个数作为阈值。当时这种方法并不适应于所有情况。尤其是当同一幅图像上的不同部分具有不同的亮度时。这种情况下我们需要采用自适应阈值。此时的阈值时根据图像上的每一个小区域计算与其对应的阈值。因此…

com.spring4all:swagger-spring-boot-starter:1.7.1.RELEASE导致,项目启动出错

Springboot 启动出错如下&#xff1a; Exception in thread "main" java.lang.NoSuchMethodError: org.springframework.util.Assert.isInstanceOf(Ljava/lang/Class;Ljava/lang/Object;Ljava/util/function/Supplier;)Vat org.springframework.boot.logging.logbac…

【幻兽帕鲁】开服务器,高性能高带宽(100mbps),免费!!!【学生党强推】

【幻兽帕鲁】开服务器&#xff0c;高性能高带宽&#xff08;100mbps&#xff09;&#xff0c;免费&#xff01;&#xff01;&#xff01;【学生党强推】 教程相关视频地址&#xff1a;https://www.bilibili.com/video/BV16e411Y7Fd/ 目前幻兽帕鲁开服务器有以下几套比较性价比的…

Python编程技巧 – 函数参数

Python编程技巧 – 函数参数 Python Programming Skills - Functional Parameters 1. 函数的定义 函数有简明扼要的定义。 函数是一个代码块&#xff0c;仅在调用时运行。可以将数据&#xff08;称为参数&#xff09;传递到函数中。函数可以返回数据作为结果。 2. 函数的结…

【Vue】为什么Vue3使用Proxy代替defineProperty?

先来看看 Vue2 中 defineProperty 来操作数据&#xff1a; const obj {a: 1,b: 2,c: {a: 1,b: 2} } function _isObject(v) {return typeof v object && v ! null; } function observe(object) {for (let key in object) {let v object[key];if (_isObject(v)) {ob…

研发日记,Matlab/Simulink避坑指南(九)——可变数组应用Bug

文章目录 前言 背景介绍 问题描述 分析排查 解决方案 总结归纳 前言 见《研发日记&#xff0c;Matlab/Simulink避坑指南(四)——transpose()转置函数Bug》 见《研发日记&#xff0c;Matlab/Simulink避坑指南(五)——CAN解包 DLC Bug》 见《研发日记&#xff0c;Matlab/Si…

Hive之set参数大全-19

指定用于计算列的唯一值数&#xff08;NDV&#xff0c;即基数&#xff09;的算法 在 Hive 中&#xff0c;hive.stats.ndv.algo 是一个配置参数&#xff0c;用于指定用于计算列的唯一值数&#xff08;NDV&#xff0c;即基数&#xff09;的算法。以下是有关该参数的一些解释&…

计算机网络之ARP协议

ARP&#xff08;地址解析协议&#xff0c;Address Resolution Protocol&#xff09;是一种用于在网络中解析或确定目标主机的物理地址&#xff08;如以太网MAC地址&#xff09;的网络协议。ARP主要用于IPv4网络&#xff0c;它使得设备能夠在知道目标设备的IP地址的情况下找到其…

qemu + vscode图形化调试linux kernel

一、背景 使用命令行连接gdb 在调试时&#xff0c;虽然可以通过tui enable 显示源码&#xff0c;但还是存在设置断点麻烦&#xff08;需要对着源码设置&#xff09;&#xff0c;terminal显示代码不方便&#xff0c;不利于我们学习&#xff1b;另外在gdb 下p命令显示结构体内容…

重构改善既有代码的设计-学习(六):处理继承关系

1、函数上移&#xff08;Pull Up Method&#xff09; 无论何时&#xff0c;只要系统内出现重复&#xff0c;你就会面临“修改其中一个却未能修改另一个”的风险。通常&#xff0c;找出重复也有一定的难度。 所以&#xff0c;某个函数在各个子类中的函数体都相同&#xff08;它们…