【目标检测】8、CenterNet:Objects as points

论文:Objects as Points

代码:https://github.com/xingyizhou/CenterNet

发布时间:2019.4.16

出处:UT Austin,UC Berkeley

摘要

目标检测常用的方法是将对象标识为图像中轴向对齐的框,大多数的较好的检测方法稠密的列举了目标可能出现的位置,并对每个位置进行分类,这是浪费、低效的,且需要很多额外的后处理。

本文提出了一种不同的方法,我们将目标建模为一个点——b-box的中心点。

本文检测方法使用关键点估计来寻找中心点,并回归框的其他特性,如尺度、3D 位置、方向、姿态等。

本文的基于中心点的方法——CenterNet,是一个端到端可微、简单、快速且准确度较高的方法。

CenterNet 在 MS COCO 数据集上达到了最好的速度和精度的平衡,AP 为28.1%时达到142FPS,AP为37.4%时达到52FPS,多尺度测试时AP 为45.1%时达到1.4FPS。

同时,我们使用了相同的方法在 KITTI 中来估计3D b-box。

在这里插入图片描述

1. 引言

本文提出了简单且高效的目标检测方法,我们使用b-box的单个中心点来表示目标(图2),之后可以从中心位置的图像特征来回归得到目标大小、维度、3d 扩展、方向和姿态等。

基于此,我们的目标检测问题就变成了一个标准的关键点估计问题。

我们将图像输入全卷积网络,得到热力图,热力图的峰值对应目标的中心。

每个峰值上的图像特征可以预测目标框的宽和高,网络使用稠密的有监督学习进行训练,推理阶段是一个单一的前向传播网络,没有NMS的后处理。

在这里插入图片描述
本文方法可以通过预测每个中心点的额外的输出,来扩展到其他应用方面,如3D目标检测和多人姿态估计。

对于3D 目标检测,我们回归目标的绝对深度、3D b-box 维度、目标方向。

对于人类姿态估计,我们将关节点(2D joint)位置作为中心点的偏移量,直接在中心点位置回归出这些偏移量的值。

本文简单的方法使得具有较快的速度,如图1,实验在三个网络上进行:

  • Resnet-18 with up-convolutional layers : 28.1% coco and 142 FPS
  • DLA-34 : 37.4% COCOAP and 52 FPS
  • Hourglass-104 : 45.1% COCOAP and 1.4 FPS

2. 相关工作

本文的方法接近于 anchor-based 单阶段方法,中心点可以被看成一个形状未知的anchor(如图3),但也有很多不同。
在这里插入图片描述

  • CenterNet 仅仅在一个位置上放置一个点,没有框重叠的情况,无需使用阈值对前景和背景进行分类。
  • 我们只有一个正的“anchor”,所以不需要 NMS 处理,在关键点热力图中抽取局部峰值即可。
  • CenterNet 的输出分辨率相比其他网络的输出分辨率较大(输出步长为4,其他网络为16),故不需要多尺度的anchors。

利用关键点进行目标检测:

本文不是第一个使用关键点进行目标检测的方法,CornerNet 使用两个关键点来检测边界框。ExtremNet 检测所有目标的左、右、上、下和中心点。

这些方法同样能够建立鲁棒性的关键点估计网络,但是,他们在关键点检测之后需要组合的步骤,会显著的降低网络速度。

CenterNet 网络仅仅抽取目标的中心点,无需进行关键点组合的后处理。

单目3D目标检测:

3D 边界框估计在自动驾驶领域有很重要的作用[17]。

  • Deep3Dbox[38] 使用 slow-RCNN[19] 类型的网络框架,首先检测 2D 目标[46] ,之后将所有目标输入 3D 估计网络。
  • 3D RCNN 给 Faster R-CNN 添加了另外的 head,之后做 3D 投影。
  • Deep Manta 使用从多个任务中训练得到的从粗尺度到细尺度的 Faster R-CNN。
  • 本文方法类似于 Deep3Dbox [38] 或 3DRCNN [29] 的单阶段版本,但更加简洁。

3. 准备阶段

I ∈ R W × H × 3 I\in R^{W\times H \times 3} IRW×H×3 是大小为 W 和 H 的三维输入图像
我们的目标是产生一个关键点的热力图 Y ^ ∈ [ 0 , 1 ] W R × H R × C \hat{Y}\in[0,1]^{\frac{W}{R}\times\frac{H}{R}\times C} Y^[0,1]RW×RH×C,其中,R 是输出的特征图的步长,C 是关键点类型个数。

关键点类型的个数:

  • 人体姿态估计中,C=18
  • 目标检测中,C=80

输出步长:本文使用 R=4,输出的步长对输出的估计用 R 进行下采样

预测结果:

  • 当预测 Y ^ x , y , c = 1 \hat{Y}_{x,y,c}=1 Y^x,y,c=1 时,表示检测到的是关键点
  • 当预测 Y ^ x , y , c = 0 \hat{Y}_{x,y,c}=0 Y^x,y,c=0 时,表示检测到的是背景

本文使用多个不同的全卷积编码解码网络来估计 Y ^ \hat{Y} Y^

  • 堆叠沙漏网络
  • up-convolutional residual networks, ResNet
  • deep layer aggregation(DLA)

关键点预测网络的训练:

对类别 c 中的每个真实关键点 p ∈ R 2 p \in R^2 pR2,计算一个低分辨率(原图下采样4倍后的)的对应点 p ˇ = ⌊ p R ⌋ \check{p}=\lfloor \frac{p}{R} \rfloor pˇ=Rp

之后将所有真实关键点使用高斯核 Y x y c = e x p ( − ( x − p ˇ x ) 2 + ( y − p ˇ y ) 2 2 σ p 2 ) Y_{xyc}=exp(-\frac{(x-\check{p}_x)^2+(y-\check{p}_y)^2}{2\sigma_p^2}) Yxyc=exp(2σp2(xpˇx)2+(ypˇy)2) 投射到热力图上,其中 σ p \sigma_p σp 为与目标大小相关的标准差。

如果同一类别的两个高斯分布重合了,我们使用逐个像素点取最大值的方法来处理。

训练的目标函数是一个像素级逻辑回归的focal loss:
在这里插入图片描述
在这里插入图片描述
其中:

  • α \alpha α β \beta β 分别为focal loss 的超参数,分别设置为2和4。
  • N N N 是图像中的关键点个数,使用其进行归一化相当于将所有正例 focal loss 规范化为1。
  • otherwise 情况其实表示 Y x y z Y_{xyz} Yxyz 为负样本,也就是其值为 (0,1) 之间,左右两边不包含,也就是高斯分布上的值。

该 Focal loss 函数是针对 CenterNet 修正而来的损失函数,和 Focal Loss类似,对于easy example的中心点,适当减少其训练比重也就是loss值.

( 1 − Y ^ x y z ) α (1-\hat{Y}_{xyz})^{\alpha} (1Y^xyz)α ( Y ^ x y z ) α (\hat{Y}_{xyz})^{\alpha} (Y^xyz)α 的作用:

  • 限制 easy example 导致的梯度更新被易区分的点所主导的问题

  • Y x y z = 1 Y_{xyz}=1 Yxyz=1 的时候, 假如 Y ^ x y z \hat{Y}_{xyz} Y^xyz 接近1的话,说明这个是一个比较容易检测出来的点,那么 ( 1 − Y ^ x y z ) α (1-\hat{Y}_{xyz})^{\alpha} (1Y^xyz)α 就相应比较低了。

  • Y x y z = 1 Y_{xyz}=1 Yxyz=1 的时候,而 Y ^ x y z \hat{Y}_{xyz} Y^xyz 接近0的时候,说明这个中心点还没有学习到,所以要加大其训练的比重,因此 ( 1 − Y ^ x y z ) α (1-\hat{Y}_{xyz})^{\alpha} (1Y^xyz)α 就会很大, α \alpha α是超参数,这里取2。

  • Y x y z = 0 Y_{xyz}=0 Yxyz=0 的时候,预测的 Y ^ x y z \hat{Y}_{xyz} Y^xyz 理论上也要接近于0,但如果其预测的值 Y ^ x y z \hat{Y}_{xyz} Y^xyz 接近于1的话, ( Y ^ x y z ) α (\hat{Y}_{xyz})^{\alpha} (Y^xyz)α 的值就会比较大,加大损失,即增加这个未被正确预测的样本的损失。

( 1 − Y x y z ) β (1-Y_{xyz})^{\beta} (1Yxyz)β 的作用:

  • 该项是为了平衡正负样本(弱化了实际中心点周围的其他负样本的损失比重,加强了远离实际中心点周围的负样本的损失比重,因为实际的物体只有一个中心点,其余都是负样本,但负样本相较于中心点来说显得有很多很多)
  • 该项和预测的结果没有关系,只和距离中心点的远近有关系,距离中心点越近,真值 Y x y z Y_{xyz} Yxyz 越接近于1,而 ( 1 − Y x y z ) β (1-Y_{xyz})^{\beta} (1Yxyz)β 会越小,即离中心越近的点的损失会变小,会更加注重离中心较远的点的情况。
  • Y x y z Y_{xyz} Yxyz 是高斯核生成的中心点,且中心点上 Y x y z = 1 Y_{xyz}=1 Yxyz=1, 对于中心点周围的点,离中心点越远,则其值会慢慢下降为0。当越接近于中心点时, Y x y z Y_{xyz} Yxyz 会越大,则 ( 1 − Y x y z ) β (1-Y_{xyz})^{\beta} (1Yxyz)β 的值会越小,反之该值会越大。
  • 即对离中心点越近的点,假设 Y x y z Y_{xyz} Yxyz 的值为0.9(otherwise情况),但预测得到其为接近于1,那显然是不对的,应该预测为0才对。此时 ( Y ^ x y z ) α (\hat{Y}_{xyz})^{\alpha} (Y^xyz)α 的值很大,loss会变大,但因为其离中心很近,预测的结果接近于1也情有可原,所以用 ( 1 − Y x y z ) β (1-Y_{xyz})^{\beta} (1Yxyz)β 来使得loss减小一些。
  • 对于离中心点越远的点,假设 Y x y z Y_{xyz} Yxyz 的值为0.1(otherwise情况),但预测得到其为接近于1,那显然是不对的,要用 ( Y ^ x y z ) α (\hat{Y}_{xyz})^{\alpha} (Y^xyz)α 来惩罚,如果预测的接近于0,那么差不多了, ( Y ^ x y z ) α (\hat{Y}_{xyz})^{\alpha} (Y^xyz)α 值就会很小。而 ( 1 − Y x y z ) β (1-Y_{xyz})^{\beta} (1Yxyz)β 的值会较大,也就是使得离中心点较远的点的损失比重较大,越近的点的损失比重越小,相当于弱化了实际中心点周围的其他负样本的损失比重,加强了远离实际中心点周围的负样本的损失比重。

为了弥补输出步长所造成的离散化损失,我们对每个中心点都额外的预测了 local offset O ^ ∈ R W R × H R × 2 \hat{O}\in R^{\frac{W}{R}\times\frac{H}{R}\times 2} O^RRW×RH×2

所有的类别都共享相同的预测 offset,该offset是用L1 loss训练的:
在这里插入图片描述
仅仅在关键点位置 p ˇ \check{p} pˇ 上实行有监督行为,其他位置被忽略。

4. objects as points 目标即点

( x 1 ( k ) , y 1 ( k ) , x 2 ( k ) , y 2 ( k ) ) (x_1^{(k)},y_1^{(k)},x_2^{(k)},y_2^{(k)}) (x1(k),y1(k),x2(k),y2(k)) 表示有 c k c_k ck个类别的目标 k k k 的b-box,其中心点在 p k = ( x 1 ( k ) + x 2 ( k ) 2 , y 1 ( k ) + y 2 ( k ) 2 ) p_k=(\frac{x_1^{(k)}+x_2^{(k)}}{2},\frac{y_1^{(k)}+y_2^{(k)}}{2}) pk=(2x1(k)+x2(k),2y1(k)+y2(k))

我们使用关键点估计 Y ^ \hat{Y} Y^ 来预测所有中心点,另外,对每个目标 k 都回归其目标大小 s k = ( x 2 ( k ) − x 1 ( k ) , y 2 ( k ) − y 1 ( k ) ) s_k=(x_2^{(k)}-x_1^{(k)}, y_2^{(k)}-y_1^{(k)}) sk=(x2(k)x1(k),y2(k)y1(k))

为了限制计算量,我们对所有目标类别都使用单个尺度的预测 S ^ ∈ R W R × H R × 2 \hat{S}\in R^{\frac{W}{R}\times\frac{H}{R}\times 2} S^RRW×RH×2

我们对中心点使用和(2)相同的 L1 loss :
在这里插入图片描述
我们没有规范化尺度,且直接使用原始的像素坐标,直接使用常量 λ s i z e \lambda_{size} λsize 来平衡 loss:
在这里插入图片描述
设定:

  • λ s i z e = 0.1 \lambda_{size}=0.1 λsize=0.1 λ o f f = 1 \lambda_{off}=1 λoff=1
  • 使用一个整体的网络来预测关键点 Y ^ \hat{Y} Y^、偏移 O ^ \hat{O} O^、尺寸 S ^ \hat{S} S^
  • 该网络在每个位置一共预测 C + 4 C+4 C+4 个输出(C:C个热力图,每个代表一个类别,4:2个 wh,2个 offset)
  • 所有的输出共享相同的全卷积backbone网络
  • 从backbone输出的特征要分别经过 3x3 卷积、Relu、1x1卷积过程
  • 图4展示了网络的输出
  • 图5是补充细节在这里插入图片描述
    在这里插入图片描述

从点到b-box:

推理阶段,首先给每个类别独立抽取热力图的峰值,检测所有其值大于或等于其相邻8个邻域的响应,保留前100个峰值。

P ^ c \hat{P}_c P^c 表示类别 c c c 中,检测到的 n n n 个中心点 P ^ = ( x ^ i , y ^ i ) i = 1 n \hat{P}={(\hat{x}_i, \hat{y}_i)}_{i=1}^n P^=(x^i,y^i)i=1n

每个关键点是由整数坐标 ( x i , y i ) (x_i,y_i) (xi,yi) 给出的,我们将关键点值 Y ^ x i y i c \hat{Y}_{x_iy_ic} Y^xiyic 作为检测置信度的衡量,并且在位置上产生一个b-box:

在这里插入图片描述
其中:

  • ( δ x ^ i , δ y ^ i ) = O ^ x ^ i , y ^ i (\delta \hat{x}_i, \delta \hat{y}_i) = \hat{O}_{\hat{x}_i, \hat{y}_i} (δx^i,δy^i)=O^x^i,y^i 是预测的偏移
  • ( w ^ i , h ^ i ) = S ^ x ^ i , y ^ i (\hat{w}_i,\hat{h}_i)=\hat{S}_{\hat{x}_i,\hat{y}_i} (w^i,h^i)=S^x^i,y^i 是预测大小
  • 所有的输出都是直接从关键点预测的结果得到的,没有使用 IoU 或 NMS 等后处理
  • 峰值关键点提取是一种有效的NMS替代方法,可以在设备上使用3×3 max池操作高效地实现。

4.1 3D检测

3D 检测是估计一个三维的b-box,并且每个关键点都需要额外的参数:深度、3D 维度、方向。

我们给其添加一些额外的输出来预测这些值。

  • 深度:

    深度(depth) d 是一个单独的,但是深度难以直接回归,我们使用[13]中的输出变换,且 d = 1 / δ ( d ^ ) − 1 d=1/\delta(\hat{d})-1 d=1/δ(d^)1,其中 δ \delta δ 是sigmoid函数。我们将深度的计算单独输出一个通道 D ^ ∈ [ 0 , 1 ] W R × H R \hat{D}\in [0,1]^{\frac{W}{R}\times \frac{H}{R}} D^[0,1]RW×RH

    不同于之前的形式,在输出层使用反向sigmoid变换,变换之后使用 L1 loss 来训练深度估计的网络。

  • 3D dimensions

    目标的3D dimensions 是三个标量,我们直接使用分离的head F ^ ∈ R W R × H R × 3 \hat{F}\in R^{\frac{W}{R}\times \frac{H}{R}\times 3} F^RRW×RH×3 和 L1 loss 来回归其绝对值,

  • 方向

    方向是一个默认的单个标量,但也较难回归。我们使用 [38] 中的方法,将方向表示成两个 bins,且用 in-bins 回归。详细来说就是使用 8 个标量scalars 来编码,每个bin有4个标量,每个bin中,两个标量被用来进行 softmax 分离,其余两个被用来会个每个bin中的角度。详见附录。

5. 实施细节

使用 Resnet-18,Resnet-101,DLA-34 和 Hourglass-104 backbone分别实验

对Resnet 和 DLA-34都使用可变性卷积进行了修正,Hourglass-104使用原来的网络。

Training:

我们训练的输入分辨率是512×512。这使得所有模型的输出分辨率为128×128。我们使用随机翻转、随机缩放(介于0.6到1.3之间)、裁剪和颜色抖动作为数据增强,并使用Adam[28]优化总体目标。当裁剪或缩放改变三维测量值时,我们不使用增强来训练三维估计分支。对于残差网络和DLA-34,我们对140个阶段进行了批量大小为128(8gpu)和学习率为5e-4的训练,在90和120个阶段的学习率分别下降了10倍(见[55])。对于沙漏-104,我们遵循ExtremeNet[61],使用批量大小29(在5gpu上,主GPU批量大小4)和学习率2.5e-4,50个阶段的学习率在40个阶段下降了10倍。为了进行检测,我们对ExtremeNet[61]中的沙漏-104进行微调,以节省计算量。使用ImageNet pretrain初始化Resnet101和DLA-34的下采样层,随机初始化上采样层。

7. 总结

CenterNet的优点如下:

  • 设计模型的结构比较简单,一般人也可以轻松看明白,不仅对于two-stage,对于one-stage的目标检测算法来说该网络的模型设计也是优雅简单的。

  • 该模型的思想不仅可以用于目标检测,还可以用于3D检测和人体姿态识别,虽然论文中没有是深入探讨这个,但是可以说明这个网络的设计还是很好的,我们可以借助这个框架去做一些其他的任务。

  • 虽然目前尚未尝试轻量级的模型,但是可以猜到这个模型对于嵌入式端这种算力比较小的平台还是很有优势的。

CenterNet的缺点也是有的:

  • 在实际训练中,如果在图像中,同一个类别中的某些物体的GT中心点,在下采样时会挤到一块,也就是两个物体在GT中的中心点重叠了,CenterNet对于这种情况也是无能为力的,也就是将这两个物体的当成一个物体来训练(因为只有一个中心点)。同理,在预测过程中,如果两个同类的物体在下采样后的中心点也重叠了,那么CenterNet也是只能检测出一个中心点,不过CenterNet对于这种情况的处理要比faster-rcnn强一些的,具体指标可以查看论文相关部分。

  • 有一个需要注意的点,CenterNet在训练过程中,如果同一个类的不同物体的高斯分布点互相有重叠,那么则在重叠的范围内选取较大的高斯点。

8. 代码

代码已开源:https://github.com/xingyizhou/CenterNet

把需要的模型和数据下载,安装,之后运行。

8.1 训练

所有的训练脚本都在 :https://github.com/xingyizhou/CenterNet/tree/master/experiments

本文的训练都是在 8 个GPU 上进行的,可以依据该论文来将学习率和 batch size 调整。

例如,在 2 个 gpu 上训练 coco 数据集:

python main.py ctdet --exp_id coco_dla --batch_size 32 --master_batch 15 --lr 1.25e-4 --gpus 0,1
  • batch_size 为32时,默认学习率为 1.25e-4(2 gpus),pytorch 通常会将总的batch_size 分配个每个 gpu 来进行训练
  • --master batch 允许给最好的 GPU 使用不同的batch_size。
  • 如果训练提前终止了,可以使用 --resume 来中段训练,也可以在 exp_id 中找到最后的那个模型
  • hourglass 模型是从 extremenet 模型微调而来的,需要先下载该extremenet 模型。
cd src
# train
python main.py ctdet --exp_id coco_hg --arch hourglass --batch_size 24 --master_batch 4 --lr 2.5e-4 --load_model ../models/ExtremeNet_500000.pth --gpus 0,1,2,3,4
# test
python test.py ctdet --exp_id coco_hg --arch hourglass --keep_res --resume
# flip test
python test.py ctdet --exp_id coco_hg --arch hourglass --keep_res --resume --flip_test 
# multi scale test
python test.py ctdet --exp_id coco_hg --arch hourglass --keep_res --resume --flip_test --test_scales 0.5,0.75,1,1.25,1.5
cd ..

COCO 上进行目标检测训练的细节:
在这里插入图片描述

  • 所有的模型都在 coco train 2017 上训练,在 coco val 2017 上评估
  • 测试时间和 AP 指标都是从 没有数据增强/ 水平增强(flip)/多尺度增强(0.5, 0.75, 1, 1.25, 1.5)
  • coco test-dev 上的结果可以在论文中找到,或给 test.py 增加 --trainval
  • exdet 是 ExtremeNet 的实现
  • 对于 DLA 和 ResNet,1x 表示训练迭代 140 个 epoch,在 90 次和 120 次的时候学习率分别下降 10倍;2x 表示训练迭代 230 个 epoch,在 180 次和 210 次的时候学习率分别下降 10倍;
  • Hourglass 网络训练的方式是和 Extreme 网络相同的,训练迭代 50 个epoch(当 batch_size 为24时,大约 25w 次 iteration),且在第 40 个epoch 时,学习率下降。
  • 测试时间包括网络前向传播时间、编码时间和NMS时间(EXtremeNet 中才有)。

batch_size、iteration、epoch 的区别:

  • batchsize:中文翻译为批大小(批尺寸)。在深度学习中,一般采用SGD训练,即每次训练在训练集中取batchsize个样本训练;

  • iteration:中文翻译为迭代,1个iteration等于使用batchsize个样本训练一次;一个迭代 = 一个正向通过+一个反向通过

  • epoch:迭代次数,1个epoch等于使用训练集中的全部样本训练一次;一个epoch = 所有训练样本的一个正向传递和一个反向传递

  • 举个例子,训练集有1000个样本,batchsize=10,那么:训练完整个样本集需要:100次iteration,1次epoch。

KITTI 上进行 3D 目标检测的细节:

  • 3 dop 划分方法源于 3DOP,suborn 划分方法源于 subCNN
  • 测试中没有使用任何数据增强
  • 总共训练 70 个epochs,分别在 45 次和 60 次的时候学习率下降

ddd_3dop.sh:

cd src
# train
python main.py ddd --exp_id 3dop --dataset kitti --kitti_split 3dop --batch_size 16 --master_batch 7 --num_epochs 70 --lr_step 45,60 --gpus 0,1
# test
python test.py ddd --exp_id 3dop --dataset kitti --kitti_split 3dop --resume
cd ..

在这里插入图片描述
ddd_sub.sh:

cd src
# train
python main.py ddd --exp_id sub --dataset kitti --kitti_split subcnn --batch_size 16 --master_batch 7 --num_epochs 70 --lr_step 45,60 --gpus 0,1
# test
python test.py ddd --exp_id sub --dataset kitti --kitti_split subcnn --resume
cd ..

在这里插入图片描述

8.2 测试

例如:

1、使用 DLA 作为backbone,来评估 COCO 数据集上的效果:

python test.py ctdet --exp_id coco_dla --keep_res --load_model ../models/ctdet_coco_dla_2x.pth

如果所有的安装正确,那么会获得AP=37.4的结果

  • --keep_res:使用原始分辨率的图像,如果没有设定这项的话,将会把图像resize为 512x512 大小
  • --flip_test --test_scales 0.5,0.75,1,1.25,1.5:分别实现 flip_test 和 muiti-scale test

2、使用 hourglass 作为backbone,来评估 COCO 数据集上的效果:

python test.py ctdet --exp_id coco_hg --arch hourglass --fix_res --load_model ../models/ctdet_coco_hg.pth

3、测试 KITTI 的效果::

首先编码工具:

cd CenterNet_ROOT/src/tools/kitti_eval
g++ -o evaluate_object_3d_offline evaluate_object_3d_offline.cpp -O3

之后运行:

python test.py ddd --exp_id 3dop --dataset kitti --kitti_split 3dop --load_model ../models/ddd_3dop.th
  • ddd 是3D 的模型
  • --exp_id 3dop:使用 3dop 数据划分,也可以使用 --kitti_split subcnn 来划分
  • 6
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呆呆的猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值