目标检测学习_P3

主要写写one-stage的网络模型,涉及到SSD,RetinaNet,YOLO.

YOLO

YOLO模型是构建快速实时物体探测器的第一次尝试。因为YOLO不经历区域建议步骤,并且只在有限数量的边界框上进行预测,所以它能够超快速地进行推理。

  1. 残差块

    首先,将图像划分为不同的网格。每个网格的尺寸为S x S。将输入图像转换为网格的过程如下图所示。每个网格单元将检测其中出现的对象。

  2. 边界框线性回归

边界框是高亮显示图像中具有某些属性(如宽度(bw)、高度(bh)和类别(如人、汽车、红绿灯等)的对象的轮廓,由字母C表示。边界框的中心(bx)。YOLO使用单边界框回归来预测对象的高度、宽度、中心和类别。

  1. IOU

    并集交集(IOU)是一种用于对象检测的工具,用于解释方框如何重叠。YOLO使用IOU完美地围绕对象的完美输出框。网格中的每个单元负责预测边界框及其置信度得分。如果预测的边界框与实际框相同,则IOU等于1。此技术可以消除与实际框不相等的边界框。

YOLOv2:YOLOv2于2017年发布,其架构对YOLO进行了几次迭代改进,包括BatchNorm、更高分辨率和锚盒。

YOLOv3:于2018年发布,YOLOv3在以前的模型的基础上,为边界框预测添加客观性分数,为主干层添加连接性,并在三个不同的级别进行预测,以提高对较小对象的性能。

YOLOv4:YOLOv4由Alexey Bochkovskiy于2020年4月发布,其中引入了改进的功能聚合、“免费包”(带增强)、漏洞激活等改进。

YOLOv5:由Glenn Jocher于2020年6月发布,YOLOv5与之前的所有版本不同,因为它是PyTorch实现,而不是原始暗网的分支。与YOLO v4一样,YOLO v5具有CSP脊椎和PA-NET颈部。主要改进包括马赛克数据扩展和自动学习边界框锚定。

PP-YOLO:百度基于YOLO v3于2020年8月发布。PP-YOLO的主要目标是实现一种具有相对平衡的效率和有效性的对象检测器,该检测器可以直接用于当前的应用场景,而不是设计新的检测模型。

Scaled YOLOv4:发布于2020年11月,作者:王、博奇科夫斯基和廖。该模型使用跨阶段部分网络来增加网络大小,同时保持YOLOv4的准确性和速度。

PP-YOLOv2:再次由百度团队撰写并于2021年4月发布,它对PP-YOLO进行了小修改,以获得更好的性能,包括添加错误激活功能和路径聚合网络。

流程:

  1. 预训练一个CNN用于图像分类任务
  2. 将输入图像分为SxS的块,如果一个物体的中心落入一个块cell中,该块“负责”检测该物体的存在.包括预测每个块预测碰撞盒的位置,置信度以及包含物体的概率
  3. 位置就是(x,y,w,h),x,y是相对于cell的offset,w,h被归一化
  4. 置信度是Pr(containing an object) x IoU(pred, truth); 其中Pr = 概率
  5. 如果一个cell包含物体,它会预测一个概率,表示这个物体属于每一类的概率Pr(the object belongs to the class C_i | containing an object),在该阶段模型仅预测每个cell的一组类概率,而与bbox无关
  6. 最终,一张图像包含SXSXB个bbox,每个bbox包含四个预测位置以及置信度和K个条件概率.所以预测的值shape是SXSX(5B+K)

imgNetwork Architecture

img

作为一个单级对象检测器,YOLO速度极快,但由于候选边界框的数量有限,它不善于识别形状不规则的对象或一组小对象。

损失函数

image-20231129233153863

损失由两部分组成,边界框偏移预测的定位损失和条件类概率的分类损失。这两部分都计算为误差平方和。

image-20231130101219411

img

YOLOV2改进

应用了多种修改以使YOLO预测更准确、更快,包括:

1.BatchNorm有助于:在所有卷积层上添加批次范数,从而显著提高收敛性。

2.图像分辨率很重要:用高分辨率图像微调基本模型可以提高检测性能。

3.卷积锚盒检测:YOLOv2不是在整个特征图上预测具有完全连接层的边界盒位置,而是使用卷积层来预测锚盒的位置,就像在更快的R-CNN中一样。空间位置的预测和类概率是解耦的。总体而言,这一变化导致mAP略有下降,但召回率有所上升。

4.框维度的K-均值聚类:与使用手工挑选的锚框大小的更快的R-CNN不同,YOLOv2对训练数据进行K-均值集群,以在锚框维度上找到良好的先验。距离度量是根据IoU分数设计的:

image-20231130103908962

通过聚类生成的锚框在固定数量的框的条件下提供更好的平均IoU。

5.直接位置预测:YOLOv2以一种不会与中心位置偏离太多的方式来制定边界框预测。如果盒子位置预测可以将盒子放置在图像的任何部分,就像在区域提案网络中一样,那么模型训练可能会变得不稳定。

img

6.添加细粒度特性:YOLOv2添加了一个直通层,将细粒度特性从早期层带到最后一个输出层。该穿透层的机制类似于ResNet中的身份映射,以从以前的层中提取更高维度的特征。这将使性能提高1%。

7.多尺度训练:为了训练模型对不同大小的输入图像具有鲁棒性,每10个批次随机采样一个新大小的输入维度。由于YOLOv2的conv层将输入维度下采样因子为32,因此新采样的大小是32的倍数。

8.轻量级基础模型:为了更快地进行预测,YOLOv2采用了轻量级基础模型DarkNet-19,该模型有19个conv层和5个最大池化层。关键是在3x3 conv层之间插入平均池和1x1 conv滤波器。

SSD

Single Shot Detector(SSD;Liu等人,2016)是首次尝试使用卷积神经网络的金字塔特征层次来有效检测各种大小的对象之一

img

该模型以图像作为输入,该图像通过具有不同大小滤波器(10x10、5x5和3x3)的多个卷积层。使用来自网络不同位置的卷积层的特征图来预测边界框。它们由具有3x3滤波器的特定卷积层处理,称为额外特征层,以产生一组类似于快速R-CNN的锚框的边界框。

与需要对象建议的方法相比,SSD 非常简单,因为它完全省去了建议生成和随后的像素或特征重采样阶段,并将所有计算封装在一个网络中。

img

此模型主要由基础网络组成,其后是几个多尺度特征块基本网络用于从输入图像中提取特征,因此它可以使用深度卷积神经网络

单发多框检测论文中选用了在分类层之前截断的VGG (Liu et al., 2016),现在也常用ResNet替代。 我们可以设计基础网络,使它输出的高和宽较大。 这样一来,基于该特征图生成的锚框数量较多,可以用来检测尺寸较小的目标。

接下来的每个多尺度特征块将上一层提供的特征图的高和宽缩小(如减半),并使特征图中每个单元在输入图像上的感受野变得更广阔。

通过深度神经网络分层表示图像的多尺度目标检测的设计。 由于接近顶部的多尺度特征图较小,但具有较大的感受野,它们适合检测较少但较大的物体。 简而言之,通过多尺度特征块,单发多框检测生成不同大小的锚框,并通过预测边界框的类别和偏移量来检测大小不同的目标,因此这是一个多尺度目标检测模型。

default box的生成

img

其中1表示对于k类bbox与gt-box是否match

损失函数

此外SSD使用了NMS和HHM优化训练过程.

NMS:非最大值抑制有助于避免重复检测同一实例。在我们为同一对象类别获得一组匹配的边界框之后:根据置信度得分对所有边界框进行排序。丢弃置信度分数较低的方框。当存在任何剩余的边界框时,重复以下操作:贪婪地选择得分最高的边界框。跳过具有高IoU(即大于0.5)的剩余框,使用之前选择的框

HNM:有些负类很容易被错误分类。我们可以在训练循环中明确地找到那些假阳性样本,并将它们包含在训练数据中,以改进分类器。

连结多尺度的预测

单发多框检测使用多尺度特征图来生成锚框并预测其类别和偏移量

在不同的尺度下,特征图的形状或以同一单元为中心的锚框的数量可能会有所不同。 因此,不同尺度下预测输出的形状可能会有所不同。

除了批量大小这一维度外,其他三个维度都具有不同的尺寸。 为了将这两个预测输出链接起来以提高计算效率,我们将把这些张量转换为更一致的格式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import torch
import torchvision
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2l


def cls_predictor(num_inputs, num_anchors, num_classes):
return nn.Conv2d(num_inputs, num_anchors * (num_classes + 1),
kernel_size=3, padding=1)
def forward(x, block):
return block(x)

Y1 = forward(torch.zeros((2, 8, 20, 20)), cls_predictor(8, 5, 10))
Y2 = forward(torch.zeros((2, 16, 10, 10)), cls_predictor(16, 3, 10))

def flatten_pred(pred):
return torch.flatten(pred.permute(0, 2, 3, 1), start_dim=1)

def concat_preds(preds):
return torch.cat([flatten_pred(p) for p in preds], dim=1)
concat_preds([Y1, Y2]).shape

高和宽减半块

1
2
3
4
5
6
7
8
9
10
def down_sample_blk(in_channels, out_channels):
blk = []
for _ in range(2):
blk.append(nn.Conv2d(in_channels, out_channels,
kernel_size=3, padding=1))
blk.append(nn.BatchNorm2d(out_channels))
blk.append(nn.ReLU())
in_channels = out_channels
blk.append(nn.MaxPool2d(2))
return nn.Sequential(*blk)

FPN

Feature Pyramid Networks for Object Detection

img

在看多尺度特征的时候注意到了这篇文章.提出了一个利用深度卷积神经网络固有的多尺度金字塔结构来以极小的计算量构建特征金字塔的网络结构

image-20231129231413439

img

  • 自下而上的路径是正常的前馈计算。
  • 自上而下的路径朝着相反的方向发展,通过横向连接将粗糙但语义更强的特征图添加回更大尺寸的先前金字塔级别。

首先,更高级别的特征在空间上更粗糙地上采样,使其大2倍。对于图像放大,本文使用了最近邻上采样。虽然有许多图像放大算法,例如使用deconv,但采用另一种图像缩放方法可能会也可能不会提高RetinaNet的性能

较大的特征图经过1x1 conv层以减小通道尺寸

最后,通过元素相加将这两个特征图合并。

根据消融研究,特征化图像金字塔设计的组件的重要性等级如下:1x1横向连接>跨多层检测对象>自上而下的富集>金字塔表示(与仅使用最底层相比)。

与SSD中一样,通过对每个合并的特征图进行预测,可以在所有金字塔级别中进行检测。因为预测共享相同的分类器和框回归器,所以它们都形成为具有相同的通道维度d=256。

img

OverFeat

[overfeat]

Overfeat是将目标检测、定位和分类任务集成到一个卷积神经网络中的先驱模型。主要思想是(i)以滑动窗口的方式在图像的多个尺度的区域上的不同位置进行图像分类,以及(ii)使用在相同卷积层上训练的回归器来预测边界框位置

(1)用一个共享的CNN(ConvNet)来同时处理图像分类,定位,检测三个任务,可以提升三个任务的表现。

(2)用CNN有效地实现了一个多尺度的,滑动窗口的方法,来处理任务。

(3)提出了一种方法,通过累积预测来求bounding boxes(而不是传统的非极大值抑制)

OverFeat——全卷积首次用于检测问题 (目标检测)(深度学习)(ICLR 2014)_overfeat是做什么的-CSDN博客

img

RetinaNet

Focal Loss for Dense Object Detection

在损失函数上进行改进.对象检测模型训练的一个问题是不包含对象的背景和包含感兴趣对象的前景之间的极端不平衡。焦点损失被设计为在硬的、容易被错误分类的例子(即具有噪声纹理或部分对象的背景)上分配更多的权重,并对容易被加权的例子(例如明显为空的背景)进行加权。

Abs

迄今为止,准确率最高的物体检测器都是基于 R-CNN 推广的两阶段方法,即对稀疏的候选物体位置集进行分类。相比之下,应用于对可能的物体位置进行规则、密集采样的单阶段检测器有可能更快、更简单,但迄今为止,其准确性仍落后于两阶段检测器。在本文中,我们将探讨出现这种情况的原因。

我们发现,dense detectors训练过程中遇到的前景-背景类别极度不平衡是主要原因。我们建议通过重塑标准交叉熵损失来解决这种类别不平衡问题,从而降低分类良好示例的损失权重。

Focal Loss

焦点损失(Focal Loss)的设计目的是解决在训练过程中前景类和背景类之间极度不平衡(例如 1:1000)的单阶段物体检测问题。我们从用于二元分类的交叉熵(CE)损失开始引入焦点损失

image-20231129231823763

在上述公式中,y∈{±1} 表示地面实况类别,p∈[0, 1]是模型对标签 y = 1 的类别的估计概率。

我们定义 p~t~

image-20231129231934979

重写 CE(p, y) = CE(p~t~) = - log(pt)。

我们建议在交叉熵损失中加入一个调制因子 (1 - p~t~)γ ,可调聚焦参数 γ ≥ 0。

image-20231129231711234

我们注意到焦点损失的两个特性。(1) 当一个例子被错误分类且 p~t~ 较小时,调制因子接近 1,损失不受影响。

img

BackBone

我们采用特征金字塔网络(FPN)作为 RetinaNet 的骨干网络。

简而言之,FPN 利用自上而下的路径和横向连接增强了标准卷积网络,因此该网络能从单一分辨率的输入图像中有效构建丰富的多尺度特征金字塔。金字塔的每一层都可用于检测不同尺度的物体。FPN 可以改进全卷积网络 (FCN) [23] 的多尺度预测,这体现在它对 RPN [28] 和 DeepMask 式提案 [24] 以及快速 R-CNN [10] 或 Mask R-CNN [14] 等两阶段检测器的增益上。继 Feature pyramid networks for object detection之后,我们在 ResNet 架构Deep residual learning for image recognition. 的基础上构建了 FPN。我们构建了一个 P3 到 P7 级的金字塔,其中 l 表示金字塔级别(Pl 的分辨率比输入低 2l)。与FPN 一样,所有金字塔层级都有 C = 256 个通道。虽然许多设计选择并不重要,但我们强调使用 FPN 主干网才是关键;使用仅来自最后 ResNet 层的特征进行的初步实验得出的 AP 值较低。

anchors

我们使用了与中 RPN 变体类似的平移不变锚点框。锚点在金字塔 P3 到 P7 层的面积分别为 32^2^ 到 512^2^。与文献一样,我们在每个金字塔层使用了三种纵横比的锚点{1:2, 1:1, 2:1}。为了获得比更密集的比例覆盖,我们在每个层级添加了尺寸为{2^0^, 2^1/3^, 2^2/3^}的锚点,这些锚点是原始的 3 种宽高比锚点的集合。这改进了我们的 AP 设置。每个级别总共有 A = 9 个锚点,相对于网络的输入图像,这些锚点覆盖了 32-813 个像素的范围。

YOLO v1~v9

总结一下YOLO的演变.

YOLO一开始,没有使用选择搜索和RPN生成region proposal,而是直接在图像上划分得到多个bbox.输出的结果包括位置和分类概率. 位置是相对于bbox的位移,w,h经过了归一化.

假设图片被均匀分为SxS个cell,每个cell中预测得到B个bbox,那么输出结果是SxSx(5B+K),K是预测的K类物体概率,5B包括4B(x,y,w,h)以及置信度Pr(containing an object) x IoU(pred, truth) 假设一个cell只包含一个物体.

img

YOLO2改进,使用了Batchnorm,使用高分辨率图像finetune,使用卷积而不是全连接替代header. 使用K聚集挑选anchor box的尺寸. 输出的位置也变成了直接的位置而不是便宜.多尺度训练和更细粒度的特征.

img

YOLO3在YOLO2上加了一堆tricks,包括使用logstic回归预测置信度,使用多个不同的logistic分类器对每类得到概率,在原本Darknet上加RestNet. 多尺度预测加跨层连接.

之后的YOLOv4并不是所谓官方的版本,在我看来还是网上加了一堆Tricks,

  1. 将CSP(Channel and Spatial Pyramid)结构融入Darknet53中,生成了新的主干网络CSPDarknet53

  2. 采用SPP(Spatial Pyramid Pooling)空间金字塔池化来扩大感受野

  3. 在Neck部分引入PAN结构,即FPN+PAN的形式

  4. 4.引入Mish激活函数

  5. 引入Mosaic数据增强

6.训练时采用CIOU_loss ,同时预测时采用DIOU_nms

image-20240502194822347

image-20240502194817818

这里也要提一句,目前深度学习貌似有进入到了大模型阶段,之前这种”小农”时代的往上加层数加残差魔改模型加点数的做法有点过时了,至少在学术界.而在工业界,其中的瓶颈貌似也不是模型的预测精度问题.

YOLOv5版本 UltralyticsLLC 公司推出的,是在YOLOv4的基础上做了少许的修补,由于改进比较小,譬如:

  1. 将v4版本骨干网络中的CSP(Channel and Spatial Pyramid)结构拓展到了NECK结构中。

  2. 增加了FOCUS操作,但是后续6.1版本中又剔除掉了该操作,使用一个6x6的卷积进行了替代。

  3. 使用SPPF结构代替了SPP。

YOLOv6是美团提出,1.骨干网Yo络由CSPDarknet换为了EfficientRep

2.Neck是基于Rep和PAN构建了Rep-PAN

3.检测头部分模仿YOLOX,进行了解耦操作,并进行了少许优化。

YOLOv7是YOLOv4团队的续作,主要是针对模型结构重参化和动态标签分配问题进行了优化。

YOLOv7检测算法的思路是与YOLOv4、v5类似。

主要改动:

1.提出了计划的模型结构重参化。

2.借鉴了YOLOv5、Scale YOLOv4、YOLOX,“拓展”和“复合缩放”方法,以便高效的利用参数和计算量。

3.提出了一种新的标签分配方法。
YOLOv8版本 UltralyticsLLC 公司推出的是,利用了与YOLOv5类似的代码,但采用了新的结构,其中使用相同的代码来支持分类、实例分割和对象检测等任务类型。模型仍然使用相同的YOLOv5 YAML格式初始化,数据集格式也保持不变。

YOLOv8目标检测算法相较于前几代YOLO系列算法具有如下的几点优势:

  • 更友好的安装/运行方式

  • 速度更快、准确率更高

  • 新的backbone,将YOLOv5中的C3更换为C2F
  • YOLO系列第一次尝试使用anchor-free

目前YOLOv9也出来了,通过引入“可编程梯度信息”(Programmable Gradient Information, PGI)和一种新的轻量级网络架构“通用高效层聚合网络”(Generalized Efficient Layer Aggregation Network, GELAN)来解决深层网络中的信息瓶颈问题。

image-20240502200729086

DETR

摘要

我们提出的新方法将目标检测视为一个直接的集合预测问题。我们的方法简化了检测流水线,有效地消除了对许多手工设计组件的需求,如非最大抑制程序或锚点生成,这些组件明确地编码了我们对任务的先验知识。

新框架被称为 DEtection TRansformer 或 DETR,其主要成分是基于集合的全局损失(通过两方匹配强制进行唯一预测)和transformers编码器-解码器架构。DETR 给定了一小组固定的已学对象查询,通过推理对象之间的关系和全局图像上下文,直接并行输出最终的预测结果。

引言

目标检测的目标是为每个感兴趣的物体预测一组边界框和类别标签。

现代检测器以一种间接的方式来解决这个集合预测任务,它们通过在大量候选区域、锚框或窗口中心上定义替代的回归和分类问题来实现这一目标。

image-20240505142247768

他们的性能在很大程度上受到后处理步骤的影响,这些步骤用于合并近似重复的预测,也受到锚框集合的设计和将目标框分配给锚框的启发式方法的影响.

为了简化这些流程管道,我们提出了一种直接的集合预测方法来绕过替代任务.这种端到端的理念已经在诸如机器翻译或语音识别等复杂结构预测任务中取得了重大进展,但在目标检测领域尚未得到应用:以前的尝试要么增加了其他形式的先验知识,要么在具有挑战性的基准测试中未能证明其比强基线算法的性能更加出色

image-20240505144614664

DETR 的整体架构非常简单,它包含三个主要组件:用于提取紧凑特征表示的 CNN 主干网、编码器-解码器转换器以及进行最终检测预测的简单前馈网络 (FFN)。

骨干网络: 利用传统CNN骨干处理图像得到CXHXW,C=2048,H, W = H0/32 , W0/32

Transformer encoder:1x1 卷积将高级激活图 f 的通道维度从 C 减小到更小的维度d.

编码器希望输入一个序列,因此我们将 z0 的空间维度折叠为一个维度,从而得到一个 d×HW 的特征图。每个编码器层都采用标准架构,由多头自注意模块和前馈网络(FFN)组成。由于变换器架构是permutation-invariant的,因此我们用固定位置编码对其进行补充,并将其添加到每个注意层的输入中

Transformer decoder:解码器遵循变换器的标准架构,利用多头自编码和编码器-解码器关注机制变换大小为 d 的 N 个嵌入式数据.

Prediction feed-forward networks (FFNs)最终预测结果由一个具有 ReLU 激活函数和隐藏维度 d 的 3 层感知器和一个线性投影层计算得出。

由于我们预测的是一组固定大小的 N 个边界框,而 N 通常远大于图像中感兴趣物体的实际数量,因此我们使用了一个额外的特殊类标签∅ 来表示在一个插槽中没有检测到任何物体。

Auxiliary decoding losses.发现在训练过程中在解码器中使用辅助损失]很有帮助,尤其是可以帮助模型输出每一类对象的正确数量。

我们在每个解码器层后添加预测 FFN 和Hungarian损失。所有预测 FFN 都共享参数。我们使用额外的共享层规范来规范不同解码器层的预测 FFNs 输入。

Deformable-DETR

最近有人提出了 DETR 方法,该方法无需在物体检测中使用许多手工设计的组件,而且性能良好。然而,由于transformer注意模块在处理图像特征图时的局限性,它存在收敛速度慢和特征空间分辨率有限的问题。为了缓解这些问题,我们提出了可变形 DETR,其注意力模块只关注参考点周围的一小部分关键采样点。可变形 DETR 比 DETR 性能更好(尤其是在处理小物体时),训练历时减少了 10 倍。在 COCO 基准上进行的大量实验证明了我们方法的有效性。

image-20240505153729910

尽管 DETR 的设计很有趣,性能也不错,但它也有自己的问题:(1) 与现有的物体检测器相比,它需要更长的训练历时才能收敛。.(2) DETR 检测小物体的性能相对较低。现代物体检测器通常利用多尺度特征,从高分辨率特征图中检测小物体。同时,高分辨率特征图会导致 DETR 的复杂性。

上述问题主要归咎于 Transformer 组件在处理图像特征图时的缺陷。在初始化时,注意力模块会对特征图中的所有像素施加几乎一致的注意力权重。需要经过长时间的训练才能学会将注意力权重集中在稀疏的有意义的位置上。另一方面,Transformer 编码器中的注意力权重计算是像素数的二次计算。因此,处理高分辨率特征图的计算和内存复杂度非常高。

可变形 DETR,它缓解了 DETR 收敛慢和复杂度高的问题。它结合了可变形卷积的稀疏空间采样和变形器的关系建模能力。

image-20240505153747011

给定一个输入特征图$ x∈R^{C×H×W}$ ,让 q 标示一个具有内容特征 $z{q}$ 和二维参考点 $p{q}$ 的查询元素.m 表示注意力头,k 表示采样键,K 是总采样键数.

∆p${mqk}$ 和 A${mqk}$ 分别表示第 m 个注意头中第 k 个采样点的采样偏移和注意权重

我们用提出的多尺度可变形注意力模块取代了 DETR 中处理特征图的 Transformer 注意力模块。编码器的输入和输出都是分辨率相同的多尺度特征图。在编码器中,我们从 ResNet中 C3 到 C5 阶段(通过 1 × 1 卷积转换)的输出特征图中提取多尺度特征图 {xl}$^{L-1}_{l=1}$ (L = 4),其中 Cl 的分辨率比输入图像低 2^l^。

解码器中有交叉注意模块和自我注意模块。这两种注意模块的查询元素都是对象查询。在交叉注意模块中,对象查询从特征图中提取特征,而关键元素则来自编码器输出的特征图。在自我关注模块中,对象查询相互影响,其中的关键要素是对象查询。

由于我们提出的可变形注意力模块旨在处理卷积特征图这一关键要素,因此我们只将每个交叉注意力模块替换为多尺度可变形注意力模块,而自注意力模块则保持不变。

参考资料

  1. 2402.13616 (arxiv.org)
  2. A Comprehensive Review of YOLO: From YOLOv1 and Beyond (arxiv.org)
-------------本文结束感谢您的阅读-------------
感谢阅读.

欢迎关注我的其它发布渠道