【机器学习】集成学习(理论)

这篇具有很好参考价值的文章主要介绍了【机器学习】集成学习(理论)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

集成学习(理论)




一、何为集成学习


集成学习(Ensemble Learning),通过构建并结合多个学习器来完成学习任务。一般结构是:先产生一组“个体学习器”,再用某种策略将它们结合起来。结合策略主要有平均法、投票法和学习法等。因此,有时也称集成学习为多学习器系统(multiclassifier system)、基于委员会的学习(committee-based learning)。

【机器学习】集成学习(理论)

集成学习主要用来提高模型(分类,预测,函数估计等)的性能,或用来降低模型选择不当的可能性(如用于减小方差的 Bagging 算法、降低偏差的 Boosting 算法或改进预测的 Stacking 算法等。

集成学习有许多集成模型,如自助聚合、随机森林、提升法、 堆叠法以及许多其它模型。集成方法的思想正是通过上述模型来将不同个体学习器(也称“基学习器”或“弱学习器”)的偏置或方差结合起来,从而创建一个更强的学习器(或集成模型),以获得更好的性能。

下面介绍三种旨在组合弱学习器的元算法:

  • 自助聚合(Bagging):该方法通常考虑的是同质弱学习器。其相互独立地并行训练这些弱学习器,并按照某种确定性的平均过程将它们组合起来。
  • 提升法(Boosting):该方法通常考虑的也是同质弱学习器。它以一种高度自适应的方法顺序地学习这些弱学习器(每个基础模型都依赖于前面的模型,即串行训练),并按照某种确定性策略将它们组合起来(尝试在每次分类中都将上一次分错的数据权重提高一点再进行分类,来获得一个强分类器)。
  • 堆叠法(stacking):该方法通常考虑的是异质弱学习器。通过并行地训练这些弱学习器,然后再构建一个元模型来组合不同弱模型的预测结果,并输出最终预测结果。

粗略来看,Bagging 的重点在于获得一个方差比其组成部分更小的集成模型,而 Boosting 和 Stacking 则注重生成偏置比其组成部分更低的强模型(方差也随之减小)。




二、集成学习最简单的模型:投票策略


测试时,对待测样本分别选取不同分类器进行,然后再汇总各分类器的结果进行汇总。汇总策略主要有平均法、投票法和学习法等。这里说一下投票法的两种方式:

  1. 硬投票:在所有分类器预测的结果里,选择出现频次最高的(少数服从多数)。采取这样的投票策略时,下图展示的集成学习模型则认为待预测样本应被归类为 1 类(3 > 1);
  2. 软投票:将所有分类器预测的结果进行加权平均,然后再选择可能性最大的(这就要求各分类器能得到概率值)。采取这样的投票策略时,下图展示的集成学习模型则认为待预测样本应被归类为 2 类。

【机器学习】集成学习(理论)




三、弱学习器的组合算法:自助聚合(Bagging模型)


并行化方法的最大特点是可以单独且同时训练不同学习器。最著名的方法是自助聚合(Bagging,全称是 Bootstrap Aggregation),它的目标是生成比单个模型更棒的集成模型。其实现思路是:并行训练多个弱学习器 f i ( x ) f_i(x) fi(x) ,并取平均值作为最终的预测结果。即: f ( x ) = 1 M ∑ m = 1 M f m ( x ) f(x)=\frac1M\sum_{m=1}^Mf_m(x) f(x)=M1m=1Mfm(x)(从该式可以看出,最终的预测结果将更加平滑,方差会大幅降低)。

对于每个弱学习器,我们自然希望他它们能在某个方面取得较好的拟合效果(或者说,每个学习器都尽量对不一样的数据进行拟合,否则大家都训练统一的数据将毫无意义)。这样一来,在最终集成时就能汇总大家的长处,来共同组成一个在各方面都不错的集成模型。于是,我们需要设计一种方法,使得一份数据集能够被合理地划分为不同训练集。自助法显然是一个不错的方案。

1、数据划分方法:自助法(Bootstrap Method)


自助法:从给定训练集中有放回地进行均匀抽样。

假设给定的数据集包含 n 个样本,接下来对该数据集进行有放回地抽样 k 次,这将产生含 k 个样本的训练集。由于采样时对每个样本都有放回,则用这样的方式得到的训练集很可能会包含一些重复样本(即某些样本在该训练集中出现多次)。

【机器学习】集成学习(理论)

在某些假设条件下,这些样本具有非常好的统计特性:在一级近似中,它们可以被视为“直接从真实的底层(并且往往是未知的)数据分布中抽取出,并且彼此之间相互独立”。因此,它们被认为是真实数据分布的代表性和独立样本。为了使这种近似成立,需要最大限度地满足以下两点:

  1. 初始数据集的大小 n 应该足够大,以服从底层分布的大部分复杂性。这样,从数据集中抽样就是从真实分布中抽样的良好近似(代表性)。
  2. 与自助样本的大小 k 相比,数据集的规模 n 要足够大,这样样本之间就不会有太大的相关性(独立性)。

2、Bagging 策略


在对数据进行合理划分后,就能对其分别构建弱学习器,并在最后进行汇总。这个步骤可归结如下:

  1. 首先对训练数据集进行多次采样,保证每次得到的采样数据都是不同的;
  2. 分别训练多个同质的模型,例如树模型;
  3. 预测时需得到所有模型的预测结果再进行集成。

【机器学习】集成学习(理论)


3、Bagging 模型的典型用例:随机森林(Random Forest)


Bagging 模型最典型的例子就是随机森林(Random Forest)。
随机是指数据采样随机,特征选择随机;森林则是指,一片森林由多棵决策树构成。

【机器学习】集成学习(理论)

随机森林的优势在于:

  1. 能处理高纬度的数据(不用专门做特征选择);
  2. 训练后得到的模型能反映出哪些特征比较重要;
  3. 并行算法,执行速度较快;
  4. 具有可解释性,且便于进行可视化展示(实战部分会证明这一点)。



四、弱学习器的组合算法:提升法(Boosting模型)


顺序化方法的主要思路是对模型进行迭代拟合,即每次构建模型时都依赖于其在前一步所构建的模型。对于采取顺序化方法组合的弱模型而言,彼此之间不再独立,而是存在一种后者依赖于前者的关系。在顺序化方法中,提升法(Boosting) 是最著名的一种,由它生成的集成模型通常比组成该模型的弱学习器偏置更小。通俗地说就是,提升法认为:每加入一个新的弱学习器就一定要带来正收益,使得最终的集成模型更强。

Boosting 和 Bagging 的工作思路相同:构建一系列模型,将它们聚合起来得到一个性能更好的强学习器。然而,与重点在于减小方差的 Bagging 不同,Boosting 着眼于以一种适应性很强的方式顺序拟合多个弱学习器:序列中每个模型在拟合的过程中,会更加重视那些 “序列之前的模型处理很糟糕的观测数据” 。直观地说,每个模型都把注意力集中在目前最难拟合的观测数据上。这样一来,在该过程的最后,就能获得一个具有较低偏置的强学习器(显然,方差也会降低)。

【机器学习】集成学习(理论)

和 Bagging 一样,Boosting 也可以用于回归和分类问题。由于其重点在于减小偏置,所以用 Boosting 基础模型的通常是那些低方差高偏置的模型。例如,如果想要使用树作为基础模型,我们将主要选择只有少许几层的较浅决策树。而选择低方差高偏置模型作为 Boosting 弱学习器的另一个重要原因是:这些模型拟合的计算开销较低(参数化时自由度较低)。实际上,由于拟合不同模型的计算无法并行处理(与 Bagging 最大的不同之处),因此顺序拟合若干复杂模型会导致计算开销变得非常高。

一旦选定了弱学习器,我们仍需要定义它们的拟合方式和聚合方式。这便引出两个重要的 Boosting 算法:自适应提升(Adaboost)和梯度提升(Gradient Boosting)。简单说来,这两种元算法在顺序化的过程中创建和聚合弱学习器的方式存在差异:

  • 自适应提升算法:会更新附加给每个训练数据集中观测数据的权重;
  • 梯度提升算法:会更新每个训练数据集中观测数据的值。

产生以上差异的主要原因是:两种算法解决优化问题(寻找最佳模型——弱学习器的加权和)的方式不同。


1、自适应提升(Adaboost)

自适应提升(Adaboost)算法的核心思想是:上一次分类错误的数据,接下来需要重点关注(就像上学时,我们的错题本)。因此,Adaboost 通过在训练样本数据时,不断修正对这些数据的权重,以此达到“对症下药”的目的,从而提高最终集成模型的分类效果。

【机器学习】集成学习(理论)

在自适应提升算法中,我们将集成模型定义为 L 个弱学习器的加权和:

s L ( ⋅ ) = ∑ l = 1 L c l × w l ( ⋅ ) s_L(·)=\sum_{l=1}^Lc_l×w_l(·) sL()=l=1Lcl×wl()

其中 c l c_l cl 为权重系数(可理解为弱学习器的地位评估), w l w_l wl 为弱学习器的拟合参数(可理解为弱学习器)。于是,求解集成模型就变为使上式参数最佳的一个优化问题(找到给出最佳整体加法模型的所有系数和弱学习器)。在一步之内“寻找使上式最优的参数”,这无疑是一个非常困难的优化问题。但是,我们可以采取更易于处理的迭代优化方式。也就是说,可以顺序地将弱学习器逐个添加到当前集成模型中,并在每次迭代时寻找可能的最佳组合(系数、弱学习器)。此时,可将某次迭代时的 s l ( ⋅ ) s_l(·) sl() 定义为:

s l ( ⋅ ) = s l − 1 ( ⋅ ) + c l × w l ( ⋅ ) s_l(·)=s_{l-1}(·)+c_l×w_l(·) sl()=sl1()+cl×wl()

其中, c l c_l cl w l w_l wl 是被挑选出来使得 s l ( ⋅ ) s_l(·) sl() 最适合的参数,因此这是对 s l − 1 ( ⋅ ) s_{l-1}(·) sl1() 的最佳可能改进。我们可以进一步将其表示为:

( c l , w l ( ⋅ ) ) = a r g c , w ( ⋅ ) m i n { E ( s l − 1 ( ⋅ ) + c l × w ( ⋅ ) ) } = a r g c , w ( ⋅ ) m i n ( ∑ l = 1 n e ( y l , s l − 1 ( x n ) + c l × w ( x n ) ) ) \left(c_l,w_l\left(·\right)\right) = arg_{c,w(·)}min\{E\left(s_{l-1}(·)+c_l×w(·)\right)\}= arg_{c,w(·)}min\left(\sum_{l=1}^ne\left(y_l,s_{l-1}(x_n)+c_l×w(x_n)\right)\right) (cl,wl())=argc,w()min{E(sl1()+cl×w())}=argc,w()min(l=1ne(yl,sl1(xn)+cl×w(xn)))

其中, E ( ⋅ ) E(·) E() 是给定模型的拟合误差, e ( ⋅ ) e(·) e() 是损失(误差)函数。因此,我们并没有在求和过程中对全部(L个)模型进行全局优化,而是通过局部优化来将近似最优系数以及弱学习器逐个添加到强模型中。


特别的是,在考虑二分类问题时,可将 Adaboost 算法写入以下过程:

  1. 更新数据集中观测数据的权重,并以此训练新的弱学习器(该学习器将重点关注当前集成模型误分类的观测数据);
  2. 根据一个表示该弱模型性能的更新系数,将弱学习器添加到加权和中(显然,弱学习器的性能越好,其对强学习器的贡献就越大,则对应的更新系数也越大)。

基于此,假设面对具有 n 个观测数据的数据集,则在给定一组弱模型的情况下用 Adaboost 算法求解时,其过程如下:

  1. 算法开始,置所有观测数据相同权重 1 n \frac1n n1
  2. 重复以下步骤 L 次(定义了 L 个弱学习器):
    ① 基于当前观测数据的权重拟合可能的最佳弱模型;
    ② 计算更新系数的值(更修系数是弱学习器的某种量化评估指标,表示其相对集成模型来说,该弱学习器的分量如何);
    ③ 添加新的弱学习器及其更新系数的乘积,并由该乘积来更新强学习器接下来要学习的观测数据的权重,该权重表示了在下一轮迭代中会重点关注哪些观测数据(在当前集成模型中,预测错误的观测数据其权重将增加,而预测正确的观测数据其权重则减小)。

重复以上步骤,就能顺序地构建出 L 个模型,并将它们聚合成一个简单的线性组合,最后再由表示每个学习器性能的系数加权。注意,初始 Adaboost 算法有一些变体,比如 LogitBoost(分类)或 L2Boost(回归),它们的差异主要取决于损失函数的选择。


2、梯度提升(Gradient Boosting)

梯度提升(Gradient Boosting)是一种常用于回归和分类问题的集成学习算法,主要以弱预测模型(通常是决策树)集合的形式产生预测模型。聚合算法汇聚不同弱学习器的结果,然后采取均值或投票方式产生最终结果,而梯度提升则是把所有学习器的结果累加起来得出最终结论。梯度提升的核心在于,每一个学习器学习的目标是之前所有学习器结论之和的残差。比如,小明的真实贷款额度为 1000,第一个学习器预测出是 950,差了 50,即残差为 50;那么在第二个学习器里,就需要把小明的贷款额度设为 50 去学习,如果第二个学习器在测试时真的能把小明的贷款额度预测为 50,则累加两个学习器的结果就是小明的真实贷款额度;如果第二个学习器的预测结果是 45,则仍然存在 5 的残差,那第三个学习器里小明的贷款额度就变成 5,继续学习……这就是梯度提升的算法流程。

【机器学习】集成学习(理论)

提升算法的主要思想是每步产生一个弱学习器,并不断把弱学习器加权累加到总模型当中,其基本公式如下:

F L ( x ) = ∑ i = 1 L c i w i ( x ) F_L(x)=\sum_{i=1}^Lc_iw_i(x) FL(x)=i=1Lciwi(x)

其中,𝐿 为弱学习器的个数, c i c_i ci 是系数, w ( ⋅ ) w_(·) w() 是弱学习器, F L F_L FL 是最终的集成模型。我们的目的是得到一个优秀的集成模型,使损失函数尽可能小,即:

argmin F m ∑ i = 1 n e ( y i , F L ( x i ) ) = argmin c L ∑ i = 1 n e ( y i , F L − 1 ( x i ) + c L w L ( x i ) ) \text{argmin}_{F_m}\sum_{i=1}^ne(y_i,F_L(x_i))=\text{argmin}_{c_L}\sum_{i=1}^ne(y_i,F_{L-1}(x_i)+c_Lw_L(x_i)) argminFmi=1ne(yi,FL(xi))=argmincLi=1ne(yi,FL1(xi)+cLwL(xi))

由于 F L ( x ) F_L(x) FL(x) 是由多个弱学习器加权组成,所以不可能同时求解。为此,梯度提升使用了一种贪心算法。在刚开始时,模型 F L ( x ) F_L(x) FL(x) 为一个常函数,然后每次只求解一个基学习器及其系数,从而一步一步地来提升 F L ( x ) F_L(x) FL(x) 的性能。这一点和梯度下降法及其相似,Gradient Boosting 就是每次让 w L ( x i ) w_L(x_i) wL(xi) 等于损失函数的负梯度,从而最快地最小化损失函数。所以, w L ( x i ) w_L(x_i) wL(xi) 可以写成下式:

w L ( x i ) = γ ∂ L ( y i , F L − 1 ( x i ) ) ∂ F L − 1 ( x i ) w_L(x_i)=\gamma\frac{∂L(y_i,F_{L-1}(x_i))}{∂F_{L-1}(x_i)} wL(xi)=γFL1(xi)L(yi,FL1(xi))

上式中 γ \gamma γ 为步长,包含了负梯度的负号。公式右边除 γ \gamma γ 以外的部分通常称为伪残差(也可以称为梯度),即: R i L = ∂ L ( y i , F L − 1 ( x i ) ) ∂ F L − 1 ( x i ) R_{iL}=\frac{∂L(y_i,F_{L-1}(x_i))}{∂F_{L-1}(x_i)} RiL=FL1(xi)L(yi,FL1(xi))。根据该式,由于 F L ( x ) F_L(x) FL(x) 的上一步模型已知,那对于每个训练样本,我们总可以求出它的伪残差 R i L R_{iL} RiL 。这样,只要假设一种弱学习器,我们就可以根据训练样本的 x 和 y 值(用弱学习器进行拟合)来训练得到当前的弱学习器 w L w_L wL 。最后将训练完的弱学习器带入 argmin F m ∑ i = 1 n e ( y i , F L ( x i ) ) \text{argmin}_{F_m}\sum_{i=1}^ne(y_i,F_L(x_i)) argminFmi=1ne(yi,FL(xi)) 中,使得损失函数最小,即可求出对应的 c L c_L cL




五、弱学习器的组合算法:堆叠法(Stacking模型)

堆叠法 Stacking 与 Bagging 和 Boosting 主要存在两方面的差异。首先,堆叠法通常考虑的是异质弱学习器(不同的学习算法被组合在一起),而 Bagging 和 Boosting 主要考虑的是同质弱学习器。其次,Stacking 堆叠法学习用元模型组合基础模型,而 Bagging 和 Boosting 则根据确定性算法组合弱学习器。

【机器学习】集成学习(理论)

因此,为了构建 Stacking 模型,我们需要定义两个东西:想要拟合的 L 个学习器(基础模型)以及组合它们的元模型。例如,对于分类问题,我们可以选择 KNN 分类器、Logistic 回归和 SVM 作为弱学习器,并以神经网络作为元模型。此时,神经网络将会把三个弱学习器的输出作为输入,并返回基于该输入的最终预测。若我们想要拟合由 L 个弱学习器组成的 Stacking 集成模型,需要遵循以下步骤:

  1. 将训练数据分为两组;
  2. 选择 L 个弱学习器,并用它们拟合第一组数据(完成对这 L 个学习器的构建);
  3. 用 L 个学习器中的每个学习器对第二组数据观测数据进行预测;
  4. 将 3 中得到的预测结果作为输入,以构建组合前面 L 个弱学习器的元模型。

在上面的步骤中,我们将数据集一分为二以分别训练,是因为训练基础模型与训练元模型这两个过程是不相关的。此时如果用整个数据集一次性构建集成模型,则会使得想要拟合的 L 个学习器与组合它们的元模型存在相关性,这显然是不合理的(会出现过拟合现象)。因此,必须将数据集一分为二,前后训练。

但是,将数据集分为两部分的一个明显缺点是:数据利用率太低,且存在“模型竞争”现象(用一部分数据训练基础模型,剩余数据训练元模型时,若前者的数据规模更大,则势必导致后者的训练效果较差,反之亦然)。为了克服这一缺陷,可以使用“k-折交叉训练方法”(类似于 k-折交叉验证的做法,不知道什么是 k-折交叉验证,的请 点击此处 花2分钟自行学习)。这样,所有观测数据均能用于训练基础模型和元模型:对于任意观测数据,弱学习器的预测都是通过在 k-1折数据上训练后而得。换句话说,它会在 k-1折数据上进行训练,从而对剩下的一折数据进行预测。迭代地重复这个过程,就可以得到对任何一折观测数据的预测结果。这样一来,我们就可以为数据集中的每个观测数据生成相关的预测,然后使用所有这些预测结果训练元模型。

注:由于深度学习模型一般需要较长的训练周期,因此,如果硬件设备不允许建议选取留出法,如果需要追求精度则可以使用交叉验证方法。




六、实战部分

本文主要介绍了集成学习的三种弱学习器组合元算法:自助聚合、提升法和堆叠法,重点讲解了各算法的性能侧重点和彼此的典型用例。这一部分内容最好结合着代码进行实验,以探寻各算法的优劣和实现细则。下面附上实战链接:【机器学习】集成学习(实战)。文章来源地址https://www.toymoban.com/news/detail-437054.html


END


到了这里,关于【机器学习】集成学习(理论)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【机器学习】决策树(理论)

    决策树(Decision Tree)是一种分类和回归方法,是基于各种情况发生的所需条件构成决策树,以实现期望最大化的一种图解法。由于这种决策分支画成图形很像一棵树的枝干,故称决策树。它的运行机制非常通俗易懂,因此被誉为机器学习中,最“友好”的算法。下面通过一个

    2024年02月04日
    浏览(50)
  • 【Python机器学习】深度学习——一些理论知识

            深度学习在很多机器学习应用中都有巨大的潜力,但深度学习算法往往经过精确调整,只适用于特定的使用场景。先学习一些简单的方法,比如用于分类和回归的多层感知机(MLP),它可以作为研究更复杂的深度学习方法的起点。MPL也被称为(普通)前馈神经网络,

    2024年01月16日
    浏览(48)
  • 图机器学习【从理论到实战】

    传统神经网络 以往:随着机器学习、深度学习的发展,语音、图像、自然语言处理逐渐取得了很大的突破,然而语音、图像、文本都是很简单的序列或者网格数据,是很结构化的数据,深度学习很善于处理该种类型的数据。 图神经网络 现实世界:并不是所有的事物都可以表

    2024年02月09日
    浏览(40)
  • 【概率论理论】协方差,协方差矩阵理论(机器学习)

      在许多算法中需要求出两个分量间相互关系的信息。协方差就是描述这种相互关联程度的一个特征数。   设 ( X , Y ) (X,Y) ( X , Y ) 是一个二维随机变量,若 E [ ( X − E ( X ) ) ( Y − E ( Y ) ) ] E[(X-E(X))(Y-E(Y))] E [ ( X − E ( X ) ) ( Y − E ( Y ) ) ] 存在,则称此数学期望为 X X X 与

    2024年02月14日
    浏览(46)
  • 机器学习理论知识部分——朴素贝叶斯

    机器学习以及matlab和数据分析 机器学习聚类算法——BIRCH算法、DBSCAN算法、OPTICS算法_ 机器学习——随机森林算法、极端随机树和单颗决策树分类器对手写数字数据进行对比分析_极端随机森林算法 文章目录 问题一、朴素贝叶斯是基于特征独立性假设的概率模型吗? 问题二、

    2024年02月11日
    浏览(51)
  • 【Python机器学习】理论知识:决策树

    决策树是广泛用于分类和回归任务的模型,本质上是从一层层if/else问题中进行学习,并得出结论。这些问题类似于“是不是”中可能问到的问题。 决策树的每个结点代表一个问题或一个包含答案的终结点(叶结点)。树的边奖问题的答案与将问的下一个问题连接起来。 用机

    2024年02月01日
    浏览(87)
  • 【机器学习】 贝叶斯理论的变分推理

    许志永         贝叶斯原理,站在概率角度上似乎容易解释,但站在函数立场上就不那么容易了;然而,在高端数学模型中,必须要在函数和集合立场上有一套完整的概念,其迭代和运算才能有坚定的理论基础。          贝叶斯定理看起来天真地简单。但是,分母是在

    2024年02月13日
    浏览(48)
  • 机器学习-学习率:从理论到实战,探索学习率的调整策略

    本文全面深入地探讨了机器学习和深度学习中的学习率概念,以及其在模型训练和优化中的关键作用。文章从学习率的基础理论出发,详细介绍了多种高级调整策略,并通过Python和PyTorch代码示例提供了实战经验。 关注TechLead,分享AI全维度知识。作者拥有10+年互联网服务架构

    2024年02月05日
    浏览(48)
  • 机器学习理论笔记(二):数据集划分以及模型选择

    欢迎来到蓝色是天的机器学习笔记专栏!在上一篇文章《机器学习理论笔记(一):初识机器学习》中,我们初步了解了机器学习,并探讨了其定义、分类以及基本术语。作为继续学习机器学习的进一步之旅,今天我们将进一步讨论机器学习中的一些重要概念和技巧。 在本文

    2024年02月11日
    浏览(36)
  • 机器学习理论基础—支持向量机的推导(一)

    SVM:从几何角度,对于线性可分数据集,支持向量机就是找距离正负样本都最远的超平面,相比于感知机,其解是唯一的,且不偏不倚,泛化性能更好。 超平面 n维空间的超平面(wT X+ b= 0,其中w,x ∈ R) 超平面方程不唯— 法向量w和位移项b确定一个唯一超平面 法向量w垂直于

    2024年04月28日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包