不确定性引导的潜在扩散模型:实现忠实图像超分辨率
图像超分辨率(Super Resolution,SR)的目标是根据低分辨率图像重建高分辨率图像。过去几年,基于潜在扩散模型(Latent Diffusion Models, LDM)的超分方案受到大量关注:它能在保持整体结构的同时生成细腻纹理,效果远超早期基于插值和简单卷积网络的方法。但真正进入研究和工程落地时,一个绕不开的问题是“忠实性”(Faithfulness)。扩散模型的多模态生成特性决定了它很容易在信息不足的区域编造细节,结果图看着清晰,放大后却和真实场景对不上。Uncertainty-Guided Latent Diffusion Models for Faithful Super Resolution 这条研究线的核心思路,是在 LDM 生成链路中显式引入不确定性估计,让模型知道自己哪里不确定,再据此控制生成过程,从而在感知质量与保真度之间取得平衡。这篇文章会从问题动机讲起,逐步拆解潜在扩散模型的工作方式、不确定性如何参与引导、最小可运行实现,以及训练、评估和排错的完整路径。
1. 先理解“忠实超分”难在哪里
1.1 超分是典型的病态问题
低分辨率图像可以写成下面的简化模型:
LR = downsample(HR) + noise降采样过程会丢失高频信息。一个模糊的 3 像素边缘,可以对应真实世界中很多种清晰边缘;一片没有明显纹理的草地,理论上可以被复原成任意纹理图案。也就是说,给定一张低分辨率图像,可能存在无数张高分辨率图像与它兼容,超分本质上是一个病态问题。
这一点决定了后续所有方法都不可能“无损还原”原始高分辨率图像。无论使用卷积网络还是扩散模型,算法都必须依赖先验信息去填补缺失的高频细节。所谓“忠实”,并不是要求算法真的从低分辨率图像中还原出不可见的信息,而是要求算法生成的高频细节不能与低分辨率输入中已经存在的证据相矛盾。
1.2 感知质量与保真度之间存在经典权衡
超分方法大致分成两个阵营。
第一类是重建导向的方法,比如 SRCNN、EDSR、SwinIR。它们通常用 L1 或 L2 损失训练,追求低分辨率输入与预测结果之间的像素级一致。这类方法的 PSNR、SSIM 往往很高,但结果偏平滑,纹理细节弱,放大后经常出现“塑料感”。
第二类是生成导向的方法,比如基于 GAN 和基于扩散模型的方案。它们引入对抗损失或扩散先验,生成的图像纹理丰富、视觉自然,LPIPS 和 FID 更好,但代价是可能产生幻觉细节。模型会凭空画出不存在的纹理、字符或结构,图看着漂亮,却不一定符合真实场景。
这里面有一个被反复验证的规律:感知质量指标变好的同时,像素级保真度指标往往下降;反过来,像素级保真度提升时,感知质量又会妥协。这个“感知-失真权衡”是超分研究中最核心的矛盾之一,也是 Uncertainty-Guided LDM 这类方法要解决的根本问题。
1.3 扩散模型引入后的新矛盾
扩散模型通过逐步去噪的方式生成图像,天然支持从同一个低分辨率输入采样出多个合理的高分辨率结果。这种多模态生成能力对纹理合成非常有利,比如皮肤毛孔、树叶、布料纤维等难以从 LR 中推断的细节,扩散模型可以生成看起来很自然的版本。
但多模态也意味着不可控。如果没有额外机制约束,模型可能在某些区域采样出和输入完全不兼容的细节。文本类内容尤其明显:招牌上的一个字符,低分辨率下已经看不清结构,模型如果随意生成,很容易出现错字或形状怪异的字符。
因此,这类方法引入不确定性估计,核心动机是让模型显式判断:当前区域的信息足够吗?如果不确定,就不要强行走“高置信”生成路线,而应该用可控的采样策略处理这些区域。
2. 潜在扩散模型怎么做超分
2.1 扩散模型的两个过程
扩散模型包含前向过程和后向过程。
前向过程把一个干净图像逐步加噪,直到变成接近纯噪声的高斯分布:
q(x_t | x_0) = N(x_t; sqrt(alpha_t) * x_0, (1 - alpha_t) I)其中 alpha_t 是噪声调度系数,t 越大噪声越强。实际训练时不需要逐步模拟,可以直接通过重参数化从 x_0 一步采样到任意时刻的 x_t。
后向过程则由神经网络学习反向去噪:
p_theta(x_{t-1} | x_t, condition)模型在给定条件的前提下,预测噪声或预测原始图像,再从噪声中一步步恢复出目标图像。推理时可以使用 DDIM 等采样器减少步数,从 1000 步压缩到 20 到 50 步,代价是生成质量略有下降,但速度和显存占用更友好。
2.2 为什么要在潜在空间做扩散
像素空间的高分辨率图像张量非常大。一个 1024 分辨率的 RGB 图像,UNet 内部的中间特征动辄几个 GB 显存,训练成本极高。潜在扩散模型的思路是先训练一个自编码器,把图像压缩到低分辨率的潜在空间,再在潜在空间里做扩散生成,最后用解码器还原成图像。
潜在空间扩散的优势很直接:
- 计算量大幅下降,可以在更高分辨率上训练。
- 自编码器的先验已经压缩了大部分感知信息,扩散模型只需要学习潜在空间里的分布。
- 更容易复用预训练的自编码器和 UNet。
代价是潜在空间不是无损的。自编码器会丢弃一部分高频信息,这部分信息对忠实超分很关键。因此在这类方法里,自编码器的重构质量直接影响最终 SR 的保真度,不能只关心扩散部分。
| 对比项 | 像素空间扩散 | 潜在空间扩散 |
|---|---|---|
| 计算分辨率 | 必须与目标图像同尺度 | 可先压缩 4 到 16 倍 |
| 显存占用 | 高,训练大图困难 | 低,适合大图生成 |
| 细节保留 | 依赖 UNet 容量 | 依赖 VAE 解码器质量 |
| 条件注入 | 直接拼接到像素 | 在潜在空间做条件编码 |
| 训练成本 | 高 | 相对可控 |
2.3 超分条件是怎样注入模型的
在超分任务里,低分辨率图像就是条件。常见注入方式有三种。
第一种是通道拼接。把 LR 图像经过编码器得到潜在特征,再与带噪潜在变量在通道维度拼接,作为 UNet 的输入。这种方式最直接,SR 类 LDM 大多采用。
第二种是交叉注意力。把 LR 潜在特征作为注意力机制中的 Key 和 Value,带噪潜在变量作为 Query,让生成过程在每一步都能从条件中提取结构信息。
第三种是逐尺度注入。在 UNet 的不同分辨率层分别注入条件特征,帮助网络同时保留全局结构和局部细节。
这里容易踩一个坑:潜在空间的坐标比例必须对齐。如果 VAE 的下采样倍率是 8 倍,而你的超分倍率是 4 倍,那么 LR 图像要经过必要的缩放或填充,确保 LR 潜在特征与目标潜在特征的空间尺寸一致。否则条件与生成目标的位置错位,模型会学到错误的对应关系。
2.4 一条完整的 LDM 超分链路
可以用下面的流程表示输入到输出的完整过程:
LR image -> 预处理(resize / 归一化) -> VAE Encoder -> LR latent -> 与带噪 latent 拼接,作为 UNet 条件 -> 扩散 UNet 逐步去噪 -> 去噪后的 latent -> VAE Decoder -> HR 预测 -> 可选后处理(色彩校正、与 LR 对齐)训练时还需要额外加监督信号:一方面是比较模型输出与真实 HR 的重构损失,另一方面是比较降采样后的 SR 与 LR 的一致性损失。后者是“忠实”的直接体现,很多方案会把它写进总损失,防止模型偏离输入约束。
3. 不确定性引导:目标、来源与作用方式
3.1 不确定性在超分里代表什么
不确定性在这里是一张与生成结果同分辨率的置信度图,每个像素表示模型对该位置预测的把握程度。
低不确定性区域通常是平坦区域、边缘清晰的轮廓、明显可判别的结构。模型可以从 LR 输入中得到充分证据,生成结果应该紧贴条件。
高不确定性区域通常是纹理密集区、高频细节区、遮挡或模糊区域。LR 中没有足够证据,模型不知道真实纹理是什么形状,这时如果强行生成确定性的细节,就很容易产生幻觉。
不确定性引导的目标就是让模型在不同区域采用不同策略,而不是全图使用同一个生成强度。这比单纯提高模型容量更直接有效,因为它把“该不该生成细节”的问题显式建模出来。
3.2 偶然不确定性与认知不确定性
统计学习中,不确定性可以分成两类。
偶然不确定性(Aleatoric Uncertainty)来自数据本身的随机性和信息缺失。超分任务天然具有这类不确定性:降采样丢失的高频信息无法从同一张 LR 中恢复,无论模型多强都补不回来。这是超分不确定性的主要来源。
认知不确定性(Epistemic Uncertainty)来自模型自身能力的不足。训练数据不够、模型容量不够、优化不充分都会导致认知不确定性。这类不确定性可以通过增加数据、增大模型、改进训练缓解。
针对 SR 场景,不确定性模块主要建模偶然不确定性,但在小数据训练时,预测的不确定性图中也会混入认知不确定性。实际实现时不必强行区分,只要不确定性估计稳定、可解释,就能用于引导。
3.3 不确定性信息从哪里来
常见有三种估计方式。
第一种是多采样一致性。推理时对同一张 LR 采样多次,计算多个生成结果在每个像素上的方差。方差大的区域就是不确定区域。这种方式实现简单,不需要额外网络,但推理成本成倍增加。
第二种是方差头。在生成网络或一个轻量辅助网络中额外输出一个通道,预测每个像素的对数方差。训练时用高斯负对数似然监督,模型学到的方差图就代表不确定性。
第三种是 MC Dropout。推理时保留 dropout,多次前向得到预测分布,再用方差估计不确定性。
在 Uncertainty-Guided LDM 这类方法里,更常见的是让不确定性模块接收条件潜在特征和去噪时间步信息,输出一张逐像素不确定性图。这样不确定性估计与扩散过程共享语义信息,且不会显著增加推理负担。
3.4 不确定性如何引导生成过程
得到不确定性图之后,有几种典型的作用方式。
第一种是损失加权。在训练阶段,不确定性高的区域对应更高的对数方差,重构损失中的权重被压低,模型不会被迫在信息缺失区域硬拟合一个不存在的“正确答案”。这能避免训练过程因为无法恢复的高频细节而产生梯度震荡。
第二种是采样阶段引导。推理时,把不确定性图映射成条件指导强度。低不确定性区域使用更强的条件强度,严格跟随 LR 结构;高不确定性区域降低条件约束,让扩散先验生成合理纹理。可以理解成一个空间自适应的 CFG 开关。
第三种是时间步调度。对不确定性高的区域,允许模型在更长时间内保持噪声,晚一点才决定最终细节;对不确定性低的区域,则更快收敛到确定结构。
用实际例子说明:图像里的招牌文字属于高语义敏感区域,错一个字符都很明显。不确定性模块如果识别出这里信息不足,就应该让生成结果在字符结构上保持保守,必要时保留模糊但不会出错的结果;而一套石材纹理,即使具体纹路生成得和真实不同,人眼也很难察觉。不确定性引导的价值正在于区分这两种区域。
4. 实验环境与项目结构
4.1 环境要求
学习环境只需要跑通最小流程,重点是控制显存和依赖版本。生产环境还需要额外考虑推理速度、分布式训练、模型版本管理和灰度发布。
| 组件 | 学习环境建议 | 说明 |
|---|---|---|
| Python | 3.8 到 3.10 | 与 PyTorch 版本兼容即可 |
| PyTorch | 2.x | 推荐 2.0 以上,支持编译加速 |
| CUDA | 11.8 或 12.1 | 以显卡驱动和 PyTorch 官方说明为准 |
| GPU | 8GB 以上可做小图推理 | 训练完整模型建议 24GB 以上 |
| diffusers | 0.24 以上 | 方便复用预训练扩散模型 |
| opencv-python | 4.x | 图像读写和退化模拟 |
| tensorboard | 最新版 | 训练曲线和不确定性图可视化 |
注意:不同时间点的依赖版本差异较大。落地前先确认 PyTorch、diffusers 和 CUDA 的兼容关系,不要直接照抄网络上的安装命令。
4.2 安装依赖
以下命令创建一个干净环境并安装主要依赖:
python -m venv .venv source .venv/bin/activate pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 pip install diffusers datasets accelerate opencv-python tqdm tensorboard安装完成后可以用下面的命令检查基本环境是否可用:
python -c "import torch; print(torch.__version__); print(torch.cuda.is_available())"如果输出中torch.cuda.is_available()为 False,优先检查显卡驱动、CUDA 版本和 PyTorch 版本是否匹配,不要直接开始训练。
4.3 项目目录结构
一个便于扩展的最小工程结构可以参考:
udldm-sr/ ├── configs/ │ └── train.yaml ├── data/ │ ├── dataset.py │ └── degrade.py ├── models/ │ ├── vae_wrapper.py │ ├── diffusion_unet.py │ └── uncertainty_head.py ├── utils/ │ ├── metrics.py │ └── visualize.py ├── train.py └── infer.py实际项目可以按团队习惯调整,但建议把训练、推理、评测脚本分离,避免把大量逻辑堆在同一个文件里。
4.4 数据准备要点
训练数据需要 HR-LR 图像对。比较稳妥的做法是先从公开数据集 DIV2K、Flickr2K 等获取高分辨率图像,再通过同一套退化函数生成低分辨率图像,避免在不同环节多次缩放导致坐标漂移。
import cv2 import numpy as np def degrade_to_lr(hr, scale=4, noise_sigma=0.0): h, w = hr.shape[:2] lr_h, lr_w = h // scale, w // scale lr = cv2.resize(hr, (lr_w, lr_h), interpolation=cv2.INTER_CUBIC) if noise_sigma > 0: noise = np.random.normal(0, noise_sigma, lr.shape).astype(np.float32) lr = np.clip(lr + noise, 0, 255).astype(np.uint8) return lr数据增强建议使用随机翻转、旋转、裁剪,但颜色增强要谨慎,因为超分任务要求输入输出色彩一致。训练集和测试集要按同一退化函数生成,否则评估时 LR 一致性指标会失真。
5. 核心代码实现
5.1 轻量不确定性估计模块
不确定性模块不需要太复杂,通常是一个小卷积网络,输入条件潜在特征和时间步信息,输出单通道对数方差。
import torch import torch.nn as nn class UncertaintyHead(nn.Module): """从条件潜在特征预测逐像素对数方差。""" def __init__(self, in_channels: int, hidden_channels: int = 64): super().__init__() self.conv1 = nn.Conv2d(in_channels, hidden_channels, 3, padding=1) self.conv2 = nn.Conv2d(hidden_channels, hidden_channels, 3, padding=1) self.conv3 = nn.Conv2d(hidden_channels, 1, 3, padding=1) self.act = nn.SiLU() def forward(self, cond_latent: torch.Tensor) -> torch.Tensor: x = self.act(self.conv1(cond_latent)) x = self.act(self.conv2(x)) log_var = self.conv3(x) return log_var这里输出的是对数方差而不是方差,目的有两个:一是保证内部计算不出现负值约束问题,二是数值稳定性更好。初始化时可以让最后一层卷积的权重接近零,让初始对数方差接近 0,避免训练初期不确定性估计异常偏大或偏小。
5.2 不确定性加权的训练损失
训练时如果不做动作,模型会在信息缺失区域被重构损失强制拟合不存在的细节,导致梯度不稳定,也容易让模型输出模糊的平均结果。引入不确定性加权后,模型可以自主调节每个位置的损失权重。
def uncertainty_weighted_loss(pred, target, log_var, reduction="mean"): precision = torch.exp(-log_var) squared_error = (pred - target) ** 2 loss = precision * squared_error + log_var if reduction == "mean": return loss.mean() return loss这个公式来自高斯负对数似然。前半部分precision * squared_error让高置信区域贡献更大梯度,后半部分log_var防止模型把所有位置的方差都预测得非常大来逃避优化。两者必须同时存在,缺一不可。
如果发现训练初期不确定性图过于平滑或数值异常,可以给 log_var 加一个小的权重系数,比如先乘以 0.5,观察曲线后再调整。
5.3 推理时的不确定性引导采样
推理阶段把不确定性图转成空间自适应引导强度,再在去噪循环里使用。
def sample_with_uncertainty_guidance(unet, uncertainty_head, vae, lr_latent, steps=50): device = lr_latent.device batch_size, _, h, w = lr_latent.shape latent = torch.randn(batch_size, 4, h, w, device=device) # 预计算噪声调度 scheduler = DDIMScheduler(num_train_timesteps=1000) scheduler.set_timesteps(steps) cond_latent = lr_latent for t in scheduler.timesteps: log_var = uncertainty_head(cond_latent) uncertainty = torch.sigmoid(log_var) # 不确定性越高,引导强度越低,保留更多生成自由度 guidance_strength = 1.0 - uncertainty noise_pred = unet(latent, t, encoder_hidden_states=cond_latent).sample # 以空间自适应方式修正预测噪声 noise_pred = noise_pred * guidance_strength + noise_pred.detach() * (1 - guidance_strength) latent = scheduler.step(noise_pred, t, latent).prev_sample return vae.decode(latent).sample上面代码中的noise_pred修正方式是为了展示思路:真正实现时需要结合具体 UNet 的条件接口,决定是调整噪声预测,还是调整条件融合权重。比较稳妥的做法是先不加干预跑通基线,再逐步加入不确定性引导,逐项对比输出差异。
5.4 训练流程的组织
完整的训练通常分两阶段。
第一阶段是固定或微调 VAE。加载预训练自编码器,先验证它的重构质量。如果 VAE 对 HR 图像的重构已经出现明显细节丢失,后面的扩散阶段再强也补不回来。
第二阶段是联合训练扩散 UNet 和不确定性模块。扩散损失保持标准噪声预测损失,不确定性模块通过 5.2 节的损失参与训练。为了稳定训练,可以先用较小的不确定性权重跑几十轮,让 UNet 先学到基本的 SR 能力,再放开不确定性加权的强度。
6. 训练与推理的验证方法
6.1 训练过程看什么
训练不只是看 loss 下降。至少要看四类信息:
- 总 loss 和各分项 loss 曲线,确认扩散损失和不确定性损失都在正常范围。
- 每个验证周期保存一批 SR 样本,看纹理是否自然、是否有明显伪影。
- 把不确定性图可视化,叠加到样本上,判断不确定性高的区域是否集中在纹理和边缘区。
- 对同一张 LR 多次采样,观察结果多样性,确认不确定性图与采样差异有相关性。
如果不确定性图几乎全图均匀,说明模块没有学到有效信息,需要检查输入特征或者损失权重。如果不确定性图与明显错误区域完全无关,说明条件特征没有传递给不确定性模块。
6.2 自动化评估指标
不能只用一个指标判断好坏,尤其是在“忠实”这个模糊目标上。常用指标需要组合使用。
| 指标 | 衡量内容 | 局限性 |
|---|---|---|
| PSNR | 像素级误差 | 对模糊平滑的结果友好,不能衡量纹理 |
| SSIM | 结构相似度 | 受亮度、对比度影响,对局部错误不敏感 |
| LPIPS | 感知相似度 | 更接近人眼,但可能偏好纹理丰富甚至幻觉结果 |
| FID | 生成分布与真实分布的距离 | 需要大量样本,不反映单张图的忠实度 |
| LR 一致性 | 将 SR 降采样后与 LR 比较 | 能检测结构背离,但不能检测语义幻觉 |
LR 一致性是这里比较特别的一个指标。做法是把生成的 SR 用同一套退化函数降采样回 LR 尺寸,再计算与原始 LR 的 PSNR 或 SSIM。它能直接反映生成结果是否偏离输入证据。如果这个指标很差,说明条件注入或后处理出了问题。
6.3 定性检查清单
自动化指标之外,必须做人工观察。推荐按下面的清单检查:
- 字符和数字区域:是否存在错字、断笔、多余笔画。
- 人脸五官:五官是否变形,左右是否对称。
- 规则纹理:砖墙、织物、栅栏是否出现周期性错误。
- 平坦区域:是否被错误地生成了不存在的纹理。
- 图像边缘:边缘是否出现锯齿、振铃或双边扩散。
- 不确定区域:多次采样结果差异大的区域,人眼是否也觉得信息不明。
如果自动化指标好,但字符错误明显,说明模型只是在整体分布上接近真实图像,并没有做到逐区域的忠实。
7. 常见问题排错
7.1 问题现象与处理方案
| 问题现象 | 常见原因 | 检查方式 | 处理建议 |
|---|---|---|---|
| 训练时不确定性图趋于均匀 | 方差头初始值或损失权重不合适 | 打印 log_var 的分布和 loss 曲线 | 调整 log_var 初始权重,检查不确定性损失占比 |
| 生成结果与 LR 明显不一致 | 条件注入方式错误或条件权重过低 | 可视化条件 latent,做条件消融实验 | 改用通道拼接,或增大交叉注意力权重 |
| 输出出现棋盘格伪影 | VAE 解码器与扩散潜在分辨率不匹配 | 检查 latent 空间坐标和缩放比例 | 统一 resize 顺序,对齐下采样倍率 |
| 多次采样结果变化过大 | 条件约束过弱,或采样步数不足 | 对比不同 guidance 系数和 steps | 增大条件强度,把 DDIM 步数控制在 20 到 50 |
| 训练显存不足 | latent 分辨率过高或 batch 过大 | 运行 nvidia-smi 观察显存占用 | 降低 batch,开启 gradient checkpointing |
| 评估 PSNR 高但细节差 | 只优化重构损失,缺少感知约束 | 同时查看 LPIPS 和 LR 一致性 | 添加感知损失或对抗损失,结合不确定性加权 |
7.2 按链路排查的顺序
遇到问题不要先改模型结构,按下面顺序排查:
- 检查数据:HR 与 LR 是否严格对齐,退化函数是否一致。
- 检查预处理:训练、验证、推理三套流程中的 resize 和归一化是否一致。
- 检查潜在空间:LR latent 与目标 latent 的空间尺寸是否匹配。
- 检查前向输出:直接跑一个 batch,确认 UNet 的输入输出 shape 正确。
- 检查不确定性数值:log_var 是否在合理范围,sigmoid 后是否出现饱和。
- 检查采样输出:固定随机种子,对比某个中间时间步的噪声预测是否合理。
- 最后才是评测指标:先保证单张样本质量稳定,再谈批量指标对比。
这条链路覆盖了从数据到模型的绝大多数问题。实践中大量所谓“模型不收敛”,最后都定位在前三步的数据或预处理错误上。
8. 最佳实践与扩展方向
8.1 训练前检查清单
下面这份清单可以直接用于新实验启动前:
- 确认退化函数在训练、验证、测试中完全一致。
- 确认 LR 与 HR 的坐标对齐,没有二次缩放。
- 确认 VAE 重构质量满足要求,记录重构 PSNR 基线。
- 确认条件 latent 与目标 latent 的尺寸匹配。
- 确认不确定性模块的输入特征包含足够上下文,不止单像素信息。
- 确认损失函数中扩散损失、重构损失、不确定性损失的比例。
- 固定随机种子,跑一个过拟合小样本实验,确认模型能够学到基本映射。
- 在小规模验证集上先记录只重构不出纹理的基线指标。
8.2 生产落地建议
学习环境跑通后,部署到真实场景还需要补齐几块:
- 推理速度:把 DDIM 步数从 50 降到 20 步,开启 FP16 或 BF16,必要时使用模型量化和注意力切片。
- 稳定性:固定推理随机种子,或使用确定性采样,避免同一张图每次结果差异过大。
- 异常处理:面对真实低分辨率图像,先判断图像是否被其他退化污染,再决定使用哪种预处理。
- 监控:记录每张图的推理耗时、显存峰值、LR 一致性指标,超过阈值时告警。
- 配置外置:退化参数、采样步数、引导强度全部放进配置文件,不要在代码里硬编码。
8.3 可以继续探索的方向
不确定性引导不只适用于 LDM 超分。这个思路可以扩展到很多相邻任务:
- 视频超分:用时序不确定性约束相邻帧,避免闪烁。
- 真实世界超分:结合退化估计模块,让不确定性图同时反映模糊、噪声和压缩伪影。
- 医学影像和遥感影像:这类场景对幻觉容忍度极低,不确定性图可以直接作为风险提示。
- 可控生成:用户在生成前手动编辑不确定性图,指定哪些区域可以自由生成,哪些区域必须忠实。
- 下游任务联动:把不确定性图传给检测或识别模型,让它们知道输入图像中哪些区域不可信。
对新手来说,最值得做的一个实验是:在同一个数据集上,对比“有不确定性引导”和“没有不确定性引导”两个版本在字符类纹理和低频区域上的表现差异。只要能看到不确定性高的区域在引入引导后不再胡乱生成边缘和字形,就说明整个链路已经真正跑通了。
