[读书笔记] 从问题和公式角度理解 Diffusion Model

[小全读书笔记] 从问题和公式角度理解 Diffusion Model

此读书笔记本意是想理解文章 Denoising Diffusion Probabilistic Models (DDPM),但确实因为里边提到的公式对于跨领域读者有点晦涩难懂,但写者又希望能稍微从公式角度去理解其背后原理,写者进一步借助文章Understanding Diffusion Models: A Unified Perspective进行理解,因此本文主要记录了在阅读和理解后一篇文章的心路历程。

本文会省略掉一些关于模型背景等方面的介绍,而主要集中于理解背后公式的出发点和直观解释。

1. Diffusion Model的结构

图源自于DDPM
Diffusion Model的目标是学习一套模型,能将噪声 x T x_T xT还原成原始图片 x 0 x_0 x0的一套模型,而整个模型的结构包含了两部分:

  • 前向过程:加噪,模型由原始图片逐步变化变成完全的噪声
  • 后向过程:去噪,模型由噪声还原成原始图片

为了方便理解,“前向过程”都会表达成“加噪过程”,“后向过程”都会表达成“去噪过程”

1.1 定义与限制

同时,对模型加之以下定义和限制:

  1. 前向和后向过程均建模成马尔可夫链
    马尔科夫链背后的含义是:任何 t + 1 t+1 t+1时刻的状态只与 t t t时刻的状态有关,而与其他时刻无关,这蕴含着形如这的联合概率可展开成 P ( x t + 2 , x t + 1 ∣ x t ) = P ( x t + 2 ∣ x t + 1 ) P ( x t + 1 ∣ x t ) P(x_{t+2},x_{t+1}|x_t) = P(x_{t+2}|x_{t+1}) P(x_{t+1}|x_t) P(xt+2,xt+1xt)=P(xt+2xt+1)P(xt+1xt) 。这里的推导可以通过联合概率公式展开 P ( y , x ) = P ( y ∣ x ) ∗ P ( x ) P(y,x) = P(y|x) * P(x) P(y,x)=P(yx)P(x)
  2. 加噪过程是无参数的,而去噪过程是有参数的
    在Diffusion Model里,加噪过程的encoder被认为是已知的无需参数优化的,是一个以前一时刻的隐变量为中心的高斯模型,记为 q ( x t ∣ x t − 1 ) q(x_t|x_{t-1}) q(xtxt1),而去噪过程的decoder则是需要学习的模型,记为 p θ ( x t − 1 ∣ x t ) p_\theta(x_{t-1}|x_t) pθ(xt1xt)
  3. 最终时刻隐变量 x T ∼ N ( 0 , 1 ) x_T\sim N(0,1) xTN(0,1)
  4. 模型所有时刻的隐变量维度与原始图片相同

这些定义与限制对于理解后续的公式非常重要,本人最开始并没有去真正理解这些,导致了最开始理解DDPM以及相关博客地公式都非常困难。当后来我以这些定义和限制为始,并对原文进行阅读时,公式的理解就顺畅许多。Understanding Diffusion Models: A Unified Perspective非常值得阅读。

1.2 定义与限制的数学体现

p ( x 0 : T ) = p ( x 0 , x 1 , . . . , x T ) = p ( x T ) ∏ t = 1 T p θ ( x t − 1 ∣ x t ) (1) p(x_{0:T}) = p(x_0, x_1, ..., x_T) = p(x_T) \prod_{t=1}^Tp_\theta(x_{t-1}|x_t) \tag{1} p(x0:T)=p(x0,x1,...,xT)=p(xT)t=1Tpθ(xt1xt)(1)
q ( x t ∣ x t − 1 ) = N ( x t ; α t x t − 1 , ( 1 − α t ) I ) (2) q(x_t|x_{t-1}) = N(x_t;\sqrt{\alpha_t}x_{t-1}, (1-\alpha_t)\Iota)\tag{2} q(xtxt1)=N(xt;αt xt1,(1αt)I)(2)
p ( x T ) = N ( x T ; 0 , I ) (3) p(x_T) = N(x_T;0, \Iota) \tag{3} p(xT)=N(xT;0,I)(3)
公式1 是用了马尔可夫链的性质,其中提到的 p ( x 0 : T ) {p(x_{0:T})} p(x0:T)将会用于后续的求目标函数,公式二则是一个模型选择的问题(为什么模型的均值和方差要采取这种形式?)。

到这里,我们是对diffusion model只是进行了一个定义和限制,以及这种定义之下隐含的数学体现。非常明确的一点是,我们需要对模型的参数部分,也就是后向过程进行参数求解,后续章节则为了参数求解涉及了一套美妙的数学解释。

因为这套数学解释非常复杂,写者在阅读时有两个非常naive的问题:

  1. 既然加噪过程 q ( x t ∣ x t − 1 ) q(x_t|x_{t-1}) q(xtxt1)时已知的,去噪过程本质就是加噪过程的逆分布,不能从数学公式直接推导吗,非得参数化求解?
    答案是No,加噪过程的逆运算 q ( x t − 1 ∣ x t ) = q ( x t ∣ x t − 1 ) q ( x t − 1 ) q ( x t ) q(x_{t-1}|x_t) = \frac{q(x_t|x_{t-1}) q(x_{t-1})}{q(x_t)} q(xt1xt)=q(xt)q(xtxt1)q(xt1),确实有一部分已知,但公式中的 q ( x t − 1 ) , q ( x t ) q(x_{t-1}), q(x_t) q(xt1),q(xt)的分布是完全未知且难以建模的,他们也不能先入为主的认为是 N ( 0 , 1 ) N(0, 1) N(0,1),设想 x 1 x_1 x1,这是原始图片加噪一次的结果,其不可能是正态分布,也不可能被简单的建模,其建模的难度等同于 p ( x 0 ) p(x_0) p(x0)
  2. 既然公式推导不了,为啥不考虑一些简单的损失函数,如对输入图片 x 0 ′ x'_0 x0和groundtruth图片 x 0 x_0 x0做MSE?
    我们可以把diffusion model简化来思考这个问题。假设T=1,这个模型本质就是一个variational auto encoder。若只做MSE,不对中间隐变量 x 1 x_1 x1做任何的regularization,则这个模型进一步退化成auto encoder,模型生成的效果必然很差。auto encoder为什么差,可参照这篇文章的分析。

问题1的思考也给我带来了一些新的insight。加噪过程的逆分布是我们无法得到或者intractable的,diffusion model的目标其实就是利用参数化的去噪过程去学习和逼近我们设想中的加噪过程的逆分布,即 p θ ( x t − 1 ∣ x t ) p_\theta(x_{t-1}|x_t) pθ(xt1xt)的理想目标就是 q ( x t ∣ x t − 1 ) q(x_t|x_{t-1}) q(xtxt1)的逆分布。

2. Diffusion Model的模型训练

我们已经有了模型的定义,并且对模型已经参数化了,下一步则是需要进行模型训练,这便需要我们提供一个目标函数,也就是所有隐变量的联合密度函数的对数(取对数只是为了方便计算,应该分布往往都是以指数形式存在,如正态分布)。
l o g ( p ( X ) ) = l o g ( p ( x 0 : T ) ) log(p(X)) = log(p(x_{0:T})) log(p(X))=log(p(x0:T))

Diffusion Model希望最大化概率该密度函数。

在经典的深度学习领域,如分类、检测、分割等,模型的训练往往是需要一个groundtruth的,而目标函数的定义往往衡量的是模型输出与ground truth的差距(如CE、MSE),从而让模型参数朝着减少差距的方向进行参数优化。Diffusion Model的目标函数则无须ground truth,其从统计学的角度建模了随机变量的似然函数,并从最大化似然函数为目标进行求解,3.1小节对最大似然函数进行了补充。

由于 l o g p ( X ) logp(X) logp(X)形式并不能用于求解,需要进行进一步推导,得到易于求解的形式。推导过程我将其分成了几步。

2.1 似然函数转换成ELBO

ELBO貌似是变分推断中常用的一种求解方式,但读者并未完全理解其background以及意义,后续将补充这一相关读书笔记。先留个坑。

图来源于原论文
最后一步用到了Jensen不等式。

对数函数与期望的转换是信息论里常用的应用Jensen不等式的例子。另外,一元函数是否为凸函数可以判断其二阶导是否恒>0,因此 l o g ( x ) log(x) log(x)是满足这一性质的。

2.2 拆解ELBO

图来自原论文图来自原论文
到这里,优化ELBO需要优化三项:

  • E q ( x 1 ∣ x 0 ) [ l o g p θ ( x 0 ∣ x 1 ) ] E_{q(x_1|x_0)}[logp_\theta(x_0|x_1)] Eq(x1x0)[logpθ(x0x1)]: 最大化这一项表示去噪过程的最后一步需要最大成都还原原始图片
  • D K L ( q ( x T ∣ x 0 ) ∣ ∣ p ( x T ) ) D_{KL}(q(x_T|x_0)||p(x_T)) DKL(q(xTx0)∣∣p(xT)): 这一项对参数 θ \theta θ而言是恒定值,可以忽略
  • ∑ t = 2 T E q ( x t ∣ x 0 ) [ D K L ( q ( x t − 1 ∣ x t , x 0 ) ∣ ∣ p θ ( x t − 1 ∣ x t ) ) ) ] \sum_{t=2}^{T}E_{q(x_t|x_0)}[D_{KL}(q(x_{t-1}|x_t,x_0)||p_\theta(x_{t-1}|x_t)))] t=2TEq(xtx0)[DKL(q(xt1xt,x0)∣∣pθ(xt1xt)))]: 这一项是表示去噪过程的每一步的分布 p θ ( x t − 1 ∣ x t ) ) p_\theta(x_{t-1}|x_t)) pθ(xt1xt))需要最大化地拟合分布 q ( x t − 1 ∣ x t , x 0 ) q(x_{t-1}|x_t,x_0) q(xt1xt,x0)

到这里,一系列推导给出了一个比较直观地理解:我们原本希望 p θ ( x t − 1 ∣ x t ) ) p_\theta(x_{t-1}|x_t)) pθ(xt1xt))希望逼近 q ( x t ∣ x t − 1 ) q(x_{t}|x_{t-1}) q(xtxt1)的逆分布 q ( x t − 1 ∣ x t ) q(x_{t-1}|x_t) q(xt1xt),而逆分布是intractable的(如1.2小节提到)。通过ELBO以及一些列推导,我们转换成了 q ( x t − 1 ∣ x t , x 0 ) q(x_{t-1}|x_t,x_0) q(xt1xt,x0),而该分布是有可能tractable的,也就是其形式是可知的。一旦知道其形式,就能得到参数优化的求解公式

2.3 求解关键: q ( x t − 1 ∣ x t , x 0 ) q(x_{t-1}|x_t,x_0) q(xt1xt,x0)的显示表达

首先,应用贝叶斯公式:
q ( x t − 1 ∣ x t , x 0 ) = q ( x t ∣ x t − 1 , x 0 ) ∗ q ( x t − 1 ∣ , x 0 ) q ( x t ∣ x 0 ) = q ( x t ∣ x t − 1 ) ∗ q ( x t − 1 ∣ , x 0 ) q ( x t ∣ x 0 ) q(x_{t-1}|x_t,x_0) = \frac{q(x_{t}|x_{t-1},x_0) * q(x_{t-1}|,x_0)}{q(x_{t}|x_0)}= \frac{q(x_{t}|x_{t-1}) * q(x_{t-1}|,x_0)}{q(x_{t}|x_0)} q(xt1xt,x0)=q(xtx0)q(xtxt1,x0)q(xt1,x0)=q(xtx0)q(xtxt1)q(xt1,x0)

q ( x t ∣ x t − 1 ) q(x_t|x_{t-1}) q(xtxt1)的分布密度函数是已知的,上述问题的关键就转换成了求 q ( x t ∣ x 0 ) q(x_t|x_0) q(xtx0)的显示表达。这里需要用到一个重参技巧(reparameterization trick:

x t ∼ q ( x t ∣ x t − 1 ) = N ( x t ; α t x t − 1 , ( 1 − α t ) I ) x_t \sim q(x_t|x_{t-1}) = N(x_t;\sqrt{\alpha_t}x_{t-1}, (1-\alpha_t)\Iota) xtq(xtxt1)=N(xt;αt xt1,(1αt)I),转换为
x t = α t x t − 1 + 1 − α t ϵ , ϵ ∼ N ( 0 , I ) x_t = \sqrt{\alpha_t}x_{t-1} + \sqrt{1-\alpha_t}\epsilon, \epsilon \sim N(0, \Iota) xt=αt xt1+1αt ϵ,ϵN(0,I)
以此类推,就比较容易得到下列事实:
x t ∼ q ( x t ∣ x 0 ) = N ( α ˉ t x 0 , ( 1 − α ˉ t ) I ) x_t \sim q(x_t|x_0) = N(\sqrt{\bar{\alpha}_t}x_0,(1-\bar\alpha_t)\Iota) xtq(xtx0)=N(αˉt x0,(1αˉt)I)

图来自于原论文
因此, q ( x t − 1 ∣ x t , x 0 ) q(x_{t-1}|x_t,x_0) q(xt1xt,x0)的形式也比较容易得到,这里也不展开了。

综上,Diffusion Model的最大似然函数的优化目标可以显示地表达出来,结合我们训练数据即可得到我们的最优参数。

一个非常有趣的感悟是:也许一开始有人会想到 q ( x t − 1 ∣ x t ) q(x_{t-1}|x_t) q(xt1xt)是intractable,而 q ( x t − 1 ∣ x t , x 0 ) q(x_{t-1}|x_t,x_0) q(xt1xt,x0)可以借助贝叶斯公式变成tractable。直接用 q ( x t − 1 ∣ x t , x 0 ) q(x_{t-1}|x_t,x_0) q(xt1xt,x0)近似 q ( x t − 1 ∣ x t ) q(x_{t-1}|x_t) q(xt1xt)求解,即可免去了上述一系列的ELBO及其后续的推导。这种近似虽然直觉上很好理解并觉得合理,但却缺乏数学支持而显得非常无力并难以信服。数学推导尽管痛苦,但却从理论上保证了可行性,这回答了一个非常本质的问题:以这个目标函数训练为什么能work。人们常说,人是无法赚到认知以外的钱的。而数学原理的保障给我们提供了认知,让我们能赚到这里面的钱:那就是确保模型训练的有效性,这莫不是是数学之美的一个体现。

3. 附录

3.1 最大化似然函数

这里举个最大化似然函数求解的例子。假设已知随机变量 x ∼ N ( θ , σ 2 ) x \sim N(\theta, \sigma^2) xN(θ,σ2),现在有俩抽样样本,值分别1,2。则似然函数刻画的是出现这俩样本的概率
P ( x 1 = 1 , x 2 = 2 ) = P ( x 1 = 1 ) ∗ P ( x 2 = 2 ) = 1 2 π σ e x p ( − ( 1 − μ ) 2 2 σ 2 ) ∗ 1 2 π σ e x p ( − ( 2 − μ ) 2 2 σ 2 ) \begin{aligned} P(x_1 = 1, x_2 = 2) & = P(x_1 = 1) * P(x_2 = 2) \\ & = \frac{1}{\sqrt{2\pi}\sigma}exp(-\frac{(1-\mu)^2}{2\sigma^2}) * \frac{1}{\sqrt{2\pi}\sigma}exp(-\frac{(2-\mu)^2}{2\sigma^2}) \\ \end{aligned} P(x1=1,x2=2)=P(x1=1)P(x2=2)=2π σ1exp(2σ2(1μ)2)2π σ1exp(2σ2(2μ)2)
取对数后则为
l o g ( P ( x 1 = 1 , x 2 = 2 ) ) = − l o g ( 2 π ) − 2 l o g ( σ ) − 1 2 σ 2 ( ( 1 − μ ) 2 + ( 2 − μ ) 2 ) \begin{aligned} log(P(x_1 = 1, x_2 = 2)) & = -log(2\pi) - 2log(\sigma) - \frac{1}{2\sigma^2}((1-\mu)^2 + (2-\mu)^2) \end{aligned} log(P(x1=1,x2=2))=log(2π)2log(σ)2σ21((1μ)2+(2μ)2)

然后通过求导求最大值的方式得到 μ = μ ∗ , σ = σ ∗ \mu=\mu^*,\sigma = \sigma* μ=μ,σ=σ

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

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

相关文章

【c语言】函数的数据传递原理 | 数组传入函数方法

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ…

ChatGPT实现语义分析情感分类

语义分析情感分类 我们从开源社区找到了中科院谭松波博士整理的携程网酒店评论数据集(https://raw.githubusercontent.com/SophonPlus/ChineseNlpCorpus/master/datasets/ChnSentiCorp_htl_all/ChnSentiCorp_htl_all.csv)。一共七千余条数据&#xff0c;包括 label 和 review …

5G基站外市电改造建设方案 (ppt可编辑)

本资料来源公开网络&#xff0c;仅供个人学习&#xff0c;请勿商用&#xff0c;如有侵权请联系删除 外市电定义及分类 定义&#xff1a;由供电部门提供的专用高压电源或非专用高压电源或低压电源均称为市电。分类&#xff1a; &#xff08;1&#xff09;按电压等级分类 ①提供…

Linux Shell 实现一键部署http+用户名密码登录

Apache 前言 Apache(音译为阿帕奇)是世界使用排名第一的Web服务器软件。它可以运行在几乎所有广泛使用的计算机平台上&#xff0c;由于其跨平台和安全性被广泛使用&#xff0c;是最流行的Web服务器端软件之一。它快速、可靠并且可通过简单的API扩充&#xff0c;将Perl/Python等…

西交大-一百本书-解决不能粘贴的限制

快毕业了&#xff0c;要填四个一百&#xff0c;其他三个都几分钟就填完了。只有读一百本书要写读书笔记且不能粘贴&#xff0c;防谁呢真是的。发现一种解决不能粘贴限制的方法。顺道附上利用ChatGpt快速生成书评的方法。 四个一百网址 一、 解除粘贴限制 以edge浏览器为例 登…

Redis基础知识概述

Redis基础知识概述 文章目录 Redis基础知识概述一、Redis简介二、NoSQL技术三、Redis的高并发和快速原因四、Redis为什么是单线程的 五、单线程的优劣势1、优势2、劣势 六、Redis高并发总结七、在java中使用Redis1、添加Jedis依赖 八、Redis在Java Web中的应用1、存储缓存用的数…

C++的异常

文章目录 1. C语言传统的处理错误的方式2. C异常概念3. 异常的使用3.1 异常的抛出和匹配原则 4. C标准库的异常体系5. 自定义异常体系6. 异常的重新抛出7. 函数调用链中异常栈展开匹配原则8. 异常安全9. 异常规范10. 异常的优缺点 1. C语言传统的处理错误的方式 传统的错误处理…

【LPC55s69】使用FAL分区管理与easyflash变量管理

文章目录 1.FAL组件1.1什么是FAL1.2 使用ENV配置FAL1.3 FAL SFUD 移植1.4 FAL SFUD 测试用例1.5 测试结果 2.DFS文件系统2.1 什么是DFS2.2 DFS架构2.3 使用ENV配置DFS2.4 DFS挂载到FAL分区测试2.5 测试结果 3.Easyflash移植到FAL分区3.1 简述EasyFlash3.2EasyFlash软件包使用3.…

windows 文件夹目录过长超过长度259字符 文件打不开

当路径超过260个字符时&#xff0c;Windows操作系统就无法处理文件或文件夹&#xff0c;并且无法打开或重命名。这是因为Windows系统使用的文件系统&#xff0c;即FAT和NTFS文件系统&#xff0c;都有最大路径限制。NTFS文件系统最大长度限制为32767个字符&#xff0c;但操作系统…

凝心聚力,携“源”出海:开源社顾问委员会2023年第一季度会议圆满举办!

2023 年 3 月 25 日&#xff0c;开源社顾问委员会&#xff08;以下简称"顾问委员会"&#xff09;第一季度会议在北京圆满召开。这是顾问委员会自 2018 年成立以来的第 17 次全体委员会议。 为增进顾问委员会成员交流&#xff0c;加强开源社社区建设&#xff0c;实现开…

ansible自动运维——ansible使用临时命令通过模块来执行任务

大家好&#xff0c;这里是天亮之前ict&#xff0c;本人网络工程大三在读小学生&#xff0c;拥有锐捷的ie和红帽的ce认证。每天更新一个linux进阶的小知识&#xff0c;希望能提高自己的技术的同时&#xff0c;也可以帮助到大家 另外其它专栏请关注&#xff1a; 锐捷数通实验&…

制冷暖通工业互联网平台建设

制冷暖通工业互联网平台建设需要遵循一定的流程&#xff0c;具体步骤如下&#xff1a; 需求分析&#xff1a;了解客户需求&#xff0c;包括业务流程、系统功能、界面设计等方面。 系统设计&#xff1a;基于需求分析&#xff0c;进行系统设计&#xff0c;包括系统结构、数据库设…

jekyll+GithubPage搭建一个免费的个人网站

文章目录 Jekyll环境搭建windows安装RUBY、gem、Jekyll用Jekyll搭建本地博客 用jekyll模板搭建githubpage Jekyll环境搭建 windows安装RUBY、gem、Jekyll 安装ruby RUBY安装包下载地址&#xff1a;https://rubyinstaller.org/downloads/&#xff0c;一路默认选项next即可。 最…

LightGBM

LightGBM LightGBM是XGBoost的优化。 提出算法的原因&#xff1a; GBDT在每一次迭代的时候&#xff0c;都需要遍历整个训练数据多次。如果把整个训练数据装进内存则会限制训练数据的大小&#xff1b;如果不装进内存&#xff0c;反复地读写训练数据又会消耗非常大的时间。尤其面…

python 第一章——简介与环境搭建

文章目录 前言一、什么是编程语言二、下载python解释器三、安装pycharm 前言 本系列教程目录可点击这里查看&#xff1a;python教程目录 python在当今世界的流行度应该已经不用我多说了&#xff0c;这可以从TIOBE的榜单中可窥一二 作为一门面向编程新人的语言&#xff0c;它…

matlab数据归一化与反归一化处理

假如数据实际取值范围为 X i ∈ [ − π π ] , i 1 , 2 , 3 X_i \in [-\pi \ \ \pi], i1,2,3 Xi​∈[−π π],i1,2,3&#xff0c;变量服从正态分布 示例如下&#xff1a; %% 数据归一化处理及其概率密度函数 clear clc Mu [0 0 0]; % 均值 Sigma [1 1 1]; % 标准差 C…

水羊转债,超达转债,晓鸣转债上市价格预测

水羊转债 基本信息 转债名称&#xff1a;水羊转债&#xff0c;评级&#xff1a;A&#xff0c;发行规模&#xff1a;6.94987亿元。 正股名称&#xff1a;水羊股份&#xff0c;今日收盘价&#xff1a;13.94元&#xff0c;转股价格&#xff1a;13.71元。 当前转股价值 转债面值 /…

【Leetcode每日一刷】动态规划:509. 斐波那契数、322. 零钱兑换、300. 最长递增子序列

博主简介&#xff1a;努力学习的22级计科生博主主页&#xff1a; 是瑶瑶子啦所属专栏: LeetCode每日一题–进击大厂 前言&#xff1a;动规五部曲 以下是《代码随想录》作者总结的动规五部曲 确定dp数组&#xff08;dp table&#xff09;以及下标的含义确定递推公式&#xff0…

ChatGPT写小论文

ChatGPT写小论文 只是个人对写小论文心得?从知乎,知网自己总结的,有问题,可以留个言我改一下 文章目录 ChatGPT写小论文-1.写论文模仿实战(狗头)0.论文组成1.好论文前提:2.标题3.摘要4.关键词5.概述6.实验数据、公式或者设计7.结论&#xff0c;思考8.参考文献 0.模仿1.喂大纲…

【轴承故障检测】滚动轴承中进行基于振动的故障诊断研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…
最新文章