纯稀疏占用网络SparseOcc论文笔记

作者 | AIming  编辑 | 汽车人

原文链接:https://zhuanlan.zhihu.com/p/691549750

点击下方卡片,关注“自动驾驶之心”公众号

戳我-> 领取自动驾驶近15个方向学习路线

>>点击进入→自动驾驶之心占用网络技术交流群

本文只做学术分享,如有侵权,联系删文

Fully Sparse 3D Occupancy Prediction

arxiv:https://arxiv.org/abs/2312.17118v3

code:GitHub - MCG-NJU/SparseOcc: Fully Sparse 3D Occupancy Prediction

今天看到了arxiv版本更新到了V3,这应该是第一个做occupancy纯稀疏架构工作的paper,之前dense 的feature上做occupancy是比较容易的,大部分的方案也都是dense /semi-sparse(sparse-to-dense)的feature ,想做全稀疏的工作难度较高,作为第一篇值得精读,而且这个方案也算是重建了整个场景,目前看来感知和重建的方案在occ的发展上越来趋于一致

Abstract

以前的OCC方法通常构建密集的3D体积,忽略了场景的固有稀疏性(大部分为空气),计算成本较高。为了弥合差距,我们引入了一种新的完全稀疏占用网络,称为SparseOcc。SparseOcc 最初从视觉输入重建稀疏的 3D 表示,然后通过稀疏查询从 3D 稀疏表示预测语义/实例占用。掩码引导的稀疏采样旨在使稀疏查询能够以完全稀疏的方式与 2D 特征交互,从而规避昂贵的密集特征或全局注意力。此外,我们设计了一个深思熟虑的基于光线的评估指标,即RayIoU,以解决传统体素级mIoU标准中沿深度的不一致惩罚。SparseOcc 通过实现 34.0 的 RayIoU 来证明其有效性,同时保持 17.3 FPS 的实时推理速度,具有 7 个历史帧输入。通过将前面的更多帧合并到 15 帧,SparseOcc 不断提高其性能到 35.1 RayIoU,没有花里胡哨的东西。

Introduction

现有的方法通常构造密集的3D特征,存在计算开销巨大(A100上的2∼3FPS)。然而,密集表示对于占用预测不是必需的。图1(a)中的统计揭示了几何稀疏性,超过90%的体素是空的。这通过利用稀疏性在入住率预测加速方面显示出巨大的潜力。voxformer、TPVformer探索了 3D 场景的稀疏性,但它们仍然依赖于sparse-to-dense的模块进行密集预测。这启发我们寻求一个完全稀疏的占用网络,不需要任何密集的设计

a6e9082ac1287966cc74c848526cc41d.png

SparseOcc是第一个完全稀疏占用网络。如图1(b)所示,SparseOcc包括两个步骤。首先,它利用稀疏体素解码器以从粗到细的方式重建场景的稀疏几何形状。这仅对非自由区域进行建模,显着节省了计算成本。其次,我们设计了一个具有稀疏语义/实例查询的mask transformer来预测稀疏空间中片段的mask和label。mask transformer不仅提高了semantic occupancy的性能,而且为panoptic occupancy铺平了道路。设计了一种掩码引导的稀疏采样来实现mask transformer中的sparse cross-attention。

本文注意到常用的 mIoU指标的缺陷,并进一步设计 RayIoU 作为解决方案。考虑到未扫描体素的模糊标记,mIoU 标准是一个ill-posed公式(有些只是lidar点云稀疏没有扫描到,不代表真的没有占用)。以前的occ3d仅通过评估观察到的区域,也就是大家occ挑战赛常用的vismask来缓解这个问题,但会在深度的不一致惩罚中引发额外的问题。相反,RayIoU 同时解决了上述两个问题。它通过检索指定光线的深度和类别预测来评估预测的 3D 占用体积。具体来说,RayIoU 将查询光线(利用lidar线束生成的方法构造)投射到预测的 3D 体积中,并决定TP预测作为光线,其第一个被触及的占据体素网格的正确距离和类别。这制定了一个更加公平和合理的标准。

由于稀疏性设计,SparseOcc 在 Occ3D-nus [48] 上实现了 34.0 RayIoU,同时保持了 17.3 FPS(Tesla A100、PyTorch fp32 后端)的实时推理速度,具有 7 个历史帧输入。通过将更多的前一帧合并到 15 中,SparseOcc 不断提高其性能到 35.1 RayIoU。SparseOcc与以前的方法在性能和效率方面的比较如图1(c)所示。

不过flashocc的方法能在3090上达到200多FPS,sparseocc这个速度在A800上还是慢了一些,毕竟是第一篇,还会有优化空间

模型

9712a75b0d54ae3ef21f850abf1e0273.png
模型整体架构

SparseOcc 具有三个模块:

  1. 由backbone和 FPN 组成的图像编码器,用于从多视图图像中提取 2D 特征;

  2. Sparse Voxel Decoder(第 3.1 节)用于从图像特征中预测稀疏无类别的 3D occ结果;

  3. Mask transformer decoder (第 3.2 节)来区分稀疏 3D 空间中的语义和实例。

Sparse Voxel Decoder

b8d929677a2bb0496acf3d73dee7b2ed.png
Sparse Voxel Decoder结构

由于3D OCC GT是形状为W×H×D的密集3D体积(例如200×200×16),现有方法通常构建形状为W×H×D×C的密集3D特征,但该类方法计算消耗大。

在本文中,我们认为这种密集表示对于occupancy预测不是必需的。与我们的统计数据一样,我们发现场景中超过 90% 的体素是空气。这促使我们探索一种稀疏 3D 表示,它只对场景的占据区域进行建模,从而节省计算资源。

Sparse Voxel Decoder如图3所示。它遵循coarse-to-fine的结构,但只对占据区域进行建模。Decoder从一组均匀分布在 3D 空间中的粗体素查询开始(例如 25×25)。在每一层中,我们首先将每个体素上采样 2 倍,例如大小为 d 的体素将被上采样到 8 个大小为 d2 的体素。接下来,我们估计每个体素的占用分数并进行修剪以去除无用的体素网格。在这里有两种修剪方法:一种是基于阈值(例如,只保留score > 0.5);另一种是 top-k 选择。在本文实现中,只需保留具有 top-k 个占用分数的体素,以提高训练效率。k 是一个与数据集相关的参数,通过计算每个样本中不同分辨率的非自由体素的最大数量来获得。修剪后的体素tokens将作为下一层的输入。

在每一层中,我们使用类似 Transformer 的架构来处理体素查询。具体架构的来自SparseBEV,这是一种使用稀疏方案的检测方法。具体来说,在第 l 层,具有由 3D 位置和 C-dim 内容向量描述的 Kl-1 体素查询,我们首先使用自注意力来聚合这些查询体素的局部和全局特征。然后,线性层用于从相关内容向量为每个体素查询生成 3D 采样偏移量 {(Δxi, Δyi, Δzi)}。这些采样偏移量用于变换体素查询以获得全局坐标中的参考点。最后,我们将这些采样的参考点投影到多视图图像空间,通过自适应混合来整合图像特征

时序建模:以前的dense occupancy方法通常将历史BEV/3D特征warp到当前时间戳,并使用deformable attention或3D卷积来融合时间信息。然而,由于本文 3D 特征的稀疏性质,这种方法在我们的案例中并不直接适用。为了解决这个问题,我们利用上述全局采样参考点的灵活性,将它们扭曲到先前的时间戳来对历史多视图图像特征进行采样。然后,通过自适应混合堆叠和聚合采样的多帧特征。

监督:计算每一层的稀疏体素的损失。我们使用二元交叉熵 (BCE) 损失作为监督,因为我们正在重建与类别无关的稀疏占用空间(这个时候真值标签只有0/1)。只有保留的稀疏体素被监督,而在早期阶段修剪期间丢弃的区域被忽略。

由于严重的类不平衡(空气占据90%,稀有类别voxel数量极少),模型可以很容易地以大比例的类别为主,如地面(一般地面指标都很好,个人认为,occ任务上地面类别倒是不是特别重要),从而忽略场景中其他重要元素,如汽车、人等。因此,属于不同类别的体素被赋予不同的损失权重。例如,属于 c 类的体素被分配损失权重为:

dcc2bb9d30f5da3aff28985273696ed9.png
Mi是属于ground truth中的第i个类的体素数。Mc就是某个类别的体素个数

其实就是相当于类别越少,这个权重越大,看代码这部分逻辑是在batch内的真值上计算的,这样导致没有该类别的GT算出一个超大的权重,相当于0作为分子,感觉这里有点问题

Mask Transformer

这里倒不算是sparseocc第一个使用这种方法,之前论文occformer也采用了类似模块思想,但细节不太一样。

该部分源自Mask2Former,它使用 N 个稀疏语义/实例查询,由二进制mask query Qm ∈ [0, 1]N ×K 和content vector Qc ∈ RN ×C 解耦。掩码转换器包括三个步骤:多头自注意力(MHSA)、掩码引导的稀疏采样和自适应混合。MHSA 用于不同查询之间的交互作为常见的做法。Mask-guided稀疏采样和自适应混合负责查询和2D图像特征之间的交互。

Mask-guided sparse sampling:

一个简单基线是使用 Mask2Former 中的掩码交叉注意模块。但是,它关注key的所有位置,具有难以承受的计算。在这里,我们设计了一个简单的替代方案。我们首先在第 (l − 1) 个 Transformer 解码器层预测的掩码中随机选择一组 3D 点。然后,我们将这些 3D 点投影到多视图图像中,并通过双线性插值提取它们的特征。此外,稀疏采样机制通过简单地扭曲采样点(如稀疏体素解码器中所做的那样)来使时间建模更容易。

对于类别预测,应用了一个基于query embeddings Qc 的 sigmoid 激活的线性分类器。对于掩码预测,查询嵌入通过 MLP 转换为掩码嵌入。mask embeddings M ∈ R Q×C 具有与query embeddings Qc 相同的形状,并与稀疏体素嵌入 V ∈ R K×C 点积以产生掩码预测。因此,mask transformer的预测空间被限制在稀疏体素解码器的稀疏 3D 空间,而不是完整的 3D 场景(occformer是完整3D场景)。掩码预测将作为下一层的掩码查询 Qm。

Supervision:稀疏体素解码器的重建结果可能并不可靠,因为它可能会忽略或不准确检测某些元素(会漏一些前景voxel)。因此,监督mask transformer会带来一些挑战,因为它的预测被限制在这个不可靠的空间中。

在漏检占据区域的情况下,在预测的sparse occupancy不存在GT对应的预测,选择丢弃这些部分以防止混淆。

至于误检占据趋于,简单地将它们分类为一个额外的“"no object”类别。

遵循 MaskFormer,使用匈牙利匹配将基本事实与预测进行匹配。Focal loss Lf ocal 用于分类,而 DICE loss Ldice 和 BCE mask loss Lmask 的组合用于mask预测。Locc 是稀疏体素解码器的损失。因此,SparseOcc 的总损失由:

c847e152b293e35b76d165a56b5356b2.png

New metric:Ray-level mIoU

Occ3D 数据集及其提出的评估指标被广泛认可为该领域的基准。GT占用率由 LiDAR 测量重建,体素级别的平均 Intersection over Union (mIoU) 用于评估性能。然而,由于距离和遮挡等因素,累积的LiDAR点云不完善。LiDAR 未扫描的一些区域被标记为自由,导致实例碎片化(一些车的occ结果不全),如图 4(a) 所示。这引发了标签不一致的问题。以前解决评估问题的努力,例如 Occ3D,使用二进制vismask来指示在当前相机视图中是否观察到体素。然而,我们发现仅在观察到的体素位置计算 mIoU 仍然会造成歧义并且很容易被黑客攻击。如图 4 所示,RenderOcc [39] 生成了一个更厚的表面,射线状连续,这类方式是利用ray渲染,无法用于下游任务。然而,RenderOcc 的掩码 mIoU 远高于 BEVFormer 的预测,后者更稳定和干净。这表现了目前的评测指标还是不够合理

69f16ee1592fe1a006ba87a420b2b6ba.png

定性和定量结果之间的错位是由于vismask深度方向的不一致造成的。如图 5 所示,这个示例揭示了当前评估指标的几个问题:

677595cf6398c9b81a6b27f7df8f7d28.png

考虑一个场景,我们在前面有一个墙,地面真实距离为d,厚度为dv。当预测厚度为 dp >dv 时,如 RenderOcc 所示,mask mIoU 出现深度的不一致。如果我们预测的墙壁是 dv 比GT更远(总共 d + dv),那么它的 IoU 将为零,因为没有预测的体素与实际墙壁对齐。但是,如果我们预测的墙是 dv 更接近GT(总共 d - dv),我们仍然将达到 0.5 的 IoU,因为表面后面的所有体素都被填充。类似地,如果预测深度为 d − 2dv ,我们仍然有 1/3 的 IoU,依此类推。

考虑一个场景,我们在前面有一个墙,地面真实距离为d,厚度为dv。当预测厚度为 dp >dv 时,如 RenderOcc 所示,mask mIoU 出现深度的不一致。如果我们预测的墙壁是 dv 比GT更远(总共 d + dv),那么它的 IoU 将为零,因为没有预测的体素与实际墙壁对齐。但是,如果我们预测的墙是 dv 更接近

  1. 如果模型填充表面后面的所有区域,则不一致地惩罚深度预测。该模型可以通过填充表面后面的所有区域并预测更接近的深度来获得更高的 IoU。这种厚表面问题在使用可见掩码或 2D 监督的模型中很常见。

  2. 如果预测的占用是一个薄的表面,惩罚过于严格,因为一个体素的偏差将导致IoU为零。

  3. vismask只考虑当前时刻的可见区域,从而将占用减少到具有类别的深度估计任务,而忽略了在可见区域之外完成场景的关键能力。(从最新的趋势来看vismask的依赖变得逐渐减少了,毕竟推理的时候不使用会变很差)

Mean IoU by Ray Casting

为了解决上述问题,提出了一个新的评估指标:Ray-level mIoU(简称RayIoU)。在RayIoU中,集合的元素现在是查询射线,而不是体素。我们通过将查询光线投影到预测的 3D 占用体积来模拟 LiDAR射线。对于每个查询射线,计算它在相交任何表面并检索相应类标签之前传播的距离。然后,我们将相同的过程应用于GT,以获得GT深度和类别标签。如果光线与GT中存在的任何体素不相交,它将被排除在评估过程之外

如图6(a)所示,真实数据集中的原始激光雷达射线往往从近到远不平衡。因此,我们对 LiDAR 射线重新采样以平衡不同距离的分布,如图 6(b) 所示。对于近距离,我们修改了LiDAR射线通道,以在投影到地平面时实现等距离间距。在远距离,我们增加了角分辨率通道,以确保在不同范围内更均匀的数据密度。此外,查询射线可以起源于ego路径当前、过去或未来时刻的激光雷达位置。如图6所示,时序堆叠更好地评估场景完成性能,同时确保任务保持良好。

6fff06a3b419766ccb202f5fafc173b6.png
RayIoU的覆盖区域。(a)不同距离的原始激光雷达射线样本不平衡。(b)对射线重新采样,以平衡RayIoU中距离的权重。(c)为了研究场景完成的性能,我们建议通过在访问的路点上投射光线来评估可见区域在宽时间跨度内的占用率

如果类标签重合,并且地面真实深度和预测深度之间的L1误差小于某个阈值(例如,2m),则查询射线被分类为真阳性(TP)。设C是类的数量

3a9cfe903d03a161c93343335cc309e5.png

RayIoU解决了上述三个问题:

  1. 由于查询射线只计算它接触第一个体素的距离,因此模型不能通过填充表面后面的区域来获得更高的IoU。

  2. RayIoU通过距离阈值确定TP,减轻体素级mIoU过于苛刻的性质

  3. 查询射线可以起源于场景中的任何位置,从而考虑模型的场景补全能力和防止occupancy衰减成深度估计。

Experiments

在Occ3D-nus上进行,使用提出的RayIoU来评估语义分割性能。查询光线来自ego路径的 8 个 LiDAR 位置。计算三个距离阈值下的RayIoU: 1,2和4米。最终的排名指标在这些距离阈值上取平均值

FPS 是在 Tesla A100 GPU 上使用 PyTorch fp32 (1个batch size)测量的。

8431620b5047d3035572a741d6b1c2f9.png

rayiou上是高了一些,但是速度其实并没有比16帧的fb-occ这类方案快多少,理论上纯稀疏方案会减少很多计算量,但是目前看来计算量还有待进一步减少

Ablations

使用 SparseOcc 的单帧版本作为基线做ablation

Sparse voxel decoder vs. dense voxel decoder 在表2。将稀疏体素解码器与密集体素解码器进行比较。在这里,我们实现了两个基线,它们都输出一个形状为 200×200×16×C 的密集特征图。第一个基线是一个从粗到细的架构,没有修剪空体素。在这个基线中,我们将自注意力替换为 3D 卷积,并使用 3D 反卷积对预测进行上采样。其他基线是一种patch-based的架构,通过将 3D 空间划分为少量补丁作为 PETRv2 [34] 用于 BEV 分割。我们使用25×25×2=1250个查询,每个查询对应一个形状8×8的特定补丁。一堆反卷积层用于将粗查询提升到全分辨率的3D体积。

01df0b87472bc69b3c1e347f66ff07c5.png

稀疏体素解码器以 K × C 的形状生成稀疏的 3D 特征(其中 K = 32000 ≪ 200×200×16),在不影响性能的情况下实现了快近 4 倍的推理速度。

Mask Transformer

36eb2687f7ece58b48c6484386e42e75.png

消融Mask Transformer的有效性。第一行是每个体素基线,它使用一堆 MLP 直接从稀疏体素解码器预测语义。引入原始密集交叉注意的Mask Transformer(因为它是MaskFormer和Mask3D的常见做法),性能提升1.7 RayIoU,但不可避免地减慢推理速度。为了加快密集的交叉注意力管道,我们采用了一种稀疏采样机制,减少了 50% 的推理时间。然后,通过预测掩码引导进一步采样稀疏3D点,最终得到24 FPS的29.2 RayIoU。综合看下来mask-guided设计是十分必要的

稀疏体素够预测整个场景吗?

在这项研究中,我们深入研究了体素稀疏性对最终性能的影响。为了研究这一点,我们系统地消融了图 8 (a) 中 k 的值。

58a0ba46f6135404361281d20f2cdecc.png
当 k 设置为 32000(5% 稀疏度)时,最佳性能发生。(b) 性能继续随着帧数的增加而增加,但在 12 帧后开始饱和。

k只是密集体素总数的 5%(200×200×16 = 640000)。进一步增加 k 不会产生任何性能改进;相反,它会引入噪声。因此,我们的研究结果表明 5% 的稀疏级别就足够了,额外的稀疏性将适得其反。这个应该是rayiou指标造成的现象,感觉miou的话,应该会涨。时序上12帧就饱和了

Panoptic occupancy。展示了SparseOcc可以很容易地扩展到泛视占用预测,这是一个从全景分割派生的任务,它不仅将图像分割成语义上有意义的区域,而且可以检测和区分单个实例。与全景分割相比,全景占用预测要求模型是几何感知来构建用于分割的 3D 场景。通过在掩码转换器中引入实例查询。在图9中,可视化了SparseOcc的全景占用结果。

2118492eb77cd5d5a65d0fb1eee1f056.png

通过去除路面来增强稀疏性。大多数无非占用数据与背景几何有关。实际应用时,占用率可以有效地替换为高清地图(HD Map)或online mapping。这种替换不仅简化了稀疏性,而且丰富了道路的语义和结构理解。我们构建了实验来研究在 SparseOcc 中去除路面的效果。表7可以看出去除背景query数量降低了,对比原来性能也没有变化,但是这里对比原来的FPS没有变化,比较意外,感觉不正常。不过纯稀疏的架构确实可以通过这种操作减少计算量

5e920115e23fab0380adffdc333453ba.png

Miou对比

之前大家一直都是miou的指标对比,其实也可以发现整体场景的miou而言,sparseocc性能也能达到30,这个是16帧的结果,对比没有使用vismask比fb-occ性能(作者自己实现的fb-occ变体)还强,虽然速度确实还不够理想,

264ed7b45fd6047c3a51e3baf89250eb.png f83bd707bdae5c34e893fd12b35738ad.png
在rayiou的指标下,使用vismask反而还会掉点

在训练期间使用可见掩码可以提高大多数前景类的性能,例如公共汽车、自行车和卡车。然而,它对可驾驶表面、地形和人行道等背景类产生负面影响。

这一观察引发了进一步的问题:为什么背景类的性能下降。为了解决这个问题,我们在图 10 中提供了 FB-Occ 中预测可驾驶表面的深度误差和高度图的可视化比较,无论是否在训练期间使用可见掩码。该图表明,使用可见掩码进行训练会导致更厚、更高的地面表示,从而导致远处区域的深度误差很大。相反,没有可见掩码训练的模型以更高的精度预测深度

311a6b1fed6396cb4cca8c538b344ecf.png
“FB w/mask”倾向于预测更高和更厚的路面,导致沿射线的深度误差显著。相比之下,“FB wo/mask”预测一个既准确又一致的路面

vismask结论:在训练期间使用vismask通过解决未扫描体素的模糊标记问题有利于前景类occ预测。然而,它损害了深度估计的准确性,因为模型倾向于预测更厚和更紧密的表面。

本文还支持全景占用预测,但个人感觉occ是否需要实例信息感觉并不是一个关键的问题,而且实例信息额外依赖的标注,通过本文的方案感觉会引入额外的误差。

总结

这是第一个纯稀疏占用网络,不依赖于密集的 3D 特征,也不依赖于稀疏到密集和全局的注意力操作。

还创建了RayIoU,这是一种用于occupancy评估的射线级度量,消除了先前度量miou的一些问题。

最后也给出了关于vismask使用与否的结论。论文值得一读。也开源了代码,后续有机会可以精度下,继续分享。

如果有不正确的地方,欢迎指正~后续检查周更一篇occ相关paper,希望大家多多关注

投稿作者为『自动驾驶之心知识星球』特邀嘉宾,欢迎加入交流!

① 全网独家视频课程

BEV感知、毫米波雷达视觉融合多传感器标定多传感器融合多模态3D目标检测车道线检测轨迹预测在线高精地图世界模型点云3D目标检测目标跟踪Occupancy、cuda与TensorRT模型部署大模型与自动驾驶Nerf语义分割自动驾驶仿真、传感器部署、决策规划、轨迹预测等多个方向学习视频(扫码即可学习

d3208811e504eadaeed7099a65c3dbad.png

网页端官网:www.zdjszx.com

② 国内首个自动驾驶学习社区

国内最大最专业,近3000人的交流社区,已得到大多数自动驾驶公司的认可!涉及30+自动驾驶技术栈学习路线,从0到一带你入门自动驾驶感知2D/3D检测、语义分割、车道线、BEV感知、Occupancy、多传感器融合、多传感器标定、目标跟踪)、自动驾驶定位建图SLAM、高精地图、局部在线地图)、自动驾驶规划控制/轨迹预测等领域技术方案大模型、端到端等,更有行业动态和岗位发布!欢迎扫描下方二维码,加入自动驾驶之心知识星球,这是一个真正有干货的地方,与领域大佬交流入门、学习、工作、跳槽上的各类难题,日常分享论文+代码+视频

b03abf67921ab13e3154bbac17c996e4.png

③【自动驾驶之心】技术交流群

自动驾驶之心是首个自动驾驶开发者社区,聚焦感知、定位、融合、规控、标定、端到端、仿真、产品经理、自动驾驶开发、自动标注与数据闭环多个方向,目前近60+技术交流群,欢迎加入!

自动驾驶感知:目标检测、语义分割、BEV感知、毫米波雷达视觉融合、激光视觉融合、车道线检测、目标跟踪、Occupancy、深度估计、transformer、大模型、在线地图、点云处理、模型部署、CUDA加速等技术交流群;

多传感器标定:相机在线/离线标定、Lidar-Camera标定、Camera-Radar标定、Camera-IMU标定、多传感器时空同步等技术交流群;

多传感器融合:多传感器后融合技术交流群;

规划控制与预测:规划控制、轨迹预测、避障等技术交流群;

定位建图:视觉SLAM、激光SLAM、多传感器融合SLAM等技术交流群;

三维视觉:三维重建、NeRF、3D Gaussian Splatting技术交流群;

自动驾驶仿真:Carla仿真、Autoware仿真等技术交流群;

自动驾驶开发:自动驾驶开发、ROS等技术交流群;

其它方向:自动标注与数据闭环、产品经理、硬件选型、求职面试、自动驾驶测试等技术交流群;

扫码添加汽车人助理微信邀请入群,备注:学校/公司+方向+昵称(快速入群方式)

ba29ce9f09f24aa7cd9107e43d5a7c1b.jpeg

④【自动驾驶之心】平台矩阵,欢迎联系我们!

0ce47c659e2dc2b517cf51ad4d05d9fd.jpeg

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值