吴恩达深度学习课程之第三门课 结构化机器学习项目 第二周:机器学习策略(2 2 )

本文参考黄海广主编针对吴恩达深度学习课程DeepLearning.ai 《深度学习课程 笔记 (V5.1 )》

第二周:机器学习策略(2 2 )

2.1 进行误差分析(Carrying out error analysis )

进行错误分析,应该找一组错误样本,可能在你的开发集里或者测试集里,观察错误标记的样本,看看假阳性(false positives)和假阴性(false negatives),统计属于不同错误类型的错误数量。在这个过程中,你可能会得到启发,归纳出新的错误类型,就像我们看到的那样。如果你过了一遍错误样本,发现有很多 Instagram 滤镜或Snapchat 滤镜,这些滤镜干扰了我的分类器,你就可以在途中新建一个错误类型。总之,通过统计不同错误标记类型占总数的百分比,可以帮你发现哪些问题需要优先解决,或者给你构思新优化方向的灵感。

2.2 清楚标注错误的数据(Cleaning up Incorrectly labeled data)

如果你发现你的数据有一些标记错误的样本,你该怎么办?

1. 首先,考虑训练集,事实证明,深度学习算法对于训练集中的随机错误是相当健壮的(robust)。只要你的标记出错的样本,只要这些错误样本离随机错误不太远,有时可能做标记的人没有注意或者不小心,按错键了,如果错误足够随机,那么放着这些错误不管可能也没问题,而不要花太多时间修复它们。
有时候修正这些错误是有价值的,有时候放着不管也可以,只要总数据集总足够大,实际错误率可能不会太高。
我这里先警告一下,深度学习算法对随机误差很健壮,但对系统性的错误就没那么健壮。所以比如说,如果做标记的人一直把白色的狗标记成猫,那就成问题了。因为你的分类器学习之后,会把所有白色的狗都分类为猫。但随机错误或近似随机错误,对于大多数深度学习算法来说不成问题。

如果这些标记错误严重影响了你在开发集上评估算法的能力,那么就应该去花时间修正错误的标签。但是,如果它们没有严重影响到你用开发集评估成本偏差的能力,那么可能就不应该花宝贵的时间去处理。

如果决定要去修正开发集数据,手动重新检查标签,并尝试修正一些标签,这里还有一些额外的方针和原则需要考虑。

1. 首先,不管用什么修正手段,都要同时作用到开发集和测试集上,开发和测试集必须来自相同的分布。这样能够更高效的在来自同一分布的开发集和测试集上迭代。

2. 其次,考虑同时检验算法判断正确和判断错误的样本,要检查算法出错的样本很容易,只需要看看那些样本是否需要修正,但还有可能有些样本算法判断正确,那些也需要修正。如果你只修正算法出错的样本,你对算法的偏差估计可能会变大,这会让你的算法有一点不公平的优势。

3. 最后,如果你进入到一个开发集和测试集去修正这里的部分标签,也可能不会去对训练集做同样的事情,修正训练集中的标签其实相对没那么重要,可以只修正开发集和测试集中的标签,因为它们通常比训练集小得多。

最后几个建议:
1. 首先,深度学习研究人员有时会喜欢这样说:“我只是把数据提供给算法,我训练过了,效果拔群”。这话说出了很多深度学习错误的真相,更多时候,我们把数据喂给算法,然后训练它,并减少人工干预,减少使用人类的见解。但在构造实际系统时,通常需要更多的人工错误分析,更多的人类见解来架构这些系统,尽管深度学习的研究人员不愿意承认这点。
2. 其次,亲自去看这些样本,亲自统计数据,可以帮找到需要优先处理的任务。在搭建机器学习系统的时候,确定应该优先尝试哪些想法,或者哪些方向。 

2.3 快速搭建你的第一个系统 ,并进行迭代(Build your first ystem quickly, then iterate )

建议: 快速建立第一个系统,然后迭代。

  • 不过如果这个应用程序领域有很多经验,这个建议适用程度要低一些。
  • 还有一种情况适应程度更低,当这个领域有很多可以借鉴的学术文献,处理的问题和你要解决的几乎完全相同,所以,比如说,人脸识别就有很多学术文献,如果你尝试搭建一个人脸识别设备,那么可以从现有大量学术文献为基础出发,一开始就搭建比较复杂的系统。
  • 但如果你第一次处理某个新问题,那真的不鼓励想太多,或者把第一个系统弄得太复杂。建议构建一些快速而粗糙的实现,然后用来帮你找到改善系统要优先处理的方向

2.4 在不同的划分上进行训练并测试(Training and testing on different distributions ) 

现在你有两个数据来源:

1. 一个是你真正关心的数据分布,来自应用上传的数据,这些照片一般更业余,取景不太好,有些甚至很模糊,因为它们都是业余用户拍的。例如收集到 10,000 张用户上传的照片。

2. 另一个数据来源就是你可以用爬虫程序挖掘网页直接下载,就这个样本而言,可以下载很多取景专业、高分辨率、拍摄专业的猫图片。例如从互联网上下载了超过 20 万张猫图。

一、一种做法是将来源不同的两组数据合并在一起,这样你就有 21 万张照片,然后随机分配到训练、开发和测试集中。这么设立你的数据集有一些好处,也有坏处。假设已经确定开发集和测试集各包含 2500 个样本,所以你的训练集有 205000 个样本。

好处在于,训练集、开发集和测试集都来自同一分布,这样更好管理。

坏处在于,这坏处还不小,就是如果你观察开发集,看看这样本中很多图片都来自网页下载的图片,那并不是你真正关心的数据分布,你真正要处理的是来自手机的图片。

要记住,设立开发集的目的是告诉团队去瞄准的目标,而大部分精力都用在优化来自网页下载的图片,这其实不是想要的。所以不建议使用第一个选项,因为这样设立开发集就是告诉你的团队,针对不同于你实际关心的数据分布去优化,所以不要这么做。

二、训练集,比如说还是 205,000 张图片,训练集是来自网页下载的 200,000 张图片,然后如果需要的话,再加上 5000 张来自手机上传的图片。然后对于开发集测试集这数据集的大小是按比例画的你的开发集和测试集都是手机图。而训练集包含了来自网页的 20 万张图片,还有 5000 张来自应用的图片,开发集就是 2500 张来自应用的图片,测试集也是 2500 张来自应用的图片。

这样将数据分成训练集、开发集和测试集的好处在于,现在瞄准的目标就是想要处理的目标,开发集包含的数据全部来自手机上传,这是你真正关心的图片分布。我们试试搭建一个学习系统,让系统在处理手机上传图片分布时效果良好。

缺点在于,当然了,现在你的训练集分布和你的开发集、测试集分布并不一样。但事实证明,这样把数据分成训练、开发和测试集,在长期能给你带来更好的系统性能。

 2.5 不匹配数据划分的偏差和方差(Bias and Variance with mismatched data distributions)

估计学习算法的偏差和方差真的可以帮你确定接下来应该优先做的方向,但是,当训练集来自和开发集、测试集不同分布时,分析偏差和方差的方式可能不一样,我们来看为什么。

假设已经设立过这样的训练集、开发集和测试集了,并且开发集和测试集来自相同的分布,但训练集来自不同的分布

需要随机打散训练集,然后分出一部分训练集作为训练-开发集(training-dev),就像开发集和测试集来自同一分布,训练集、训练-开发集也来自同一分布。

但不同的地方是,现在你只在训练集训练你的神经网络,你不会让神经网络在训练-开发集上跑后向传播。为了进行误差分析,你应该做的是看看分类器在训练集上的误差,训练-开发集上的误差,还有开发集上的误差。

一、比如说这个样本中,训练误差是 1%,我们说训练-开发集上的误差是 9%,然后开发集误差是 10%

你就可以从这里得到结论,当你从训练数据变到训练-开发集数据时,错误率真的上升了很多。而训练数据和训练-开发数据的差异在于,你的神经网络能看到第一部分数据并直接在上面做了训练,但没有在训练-开发集上直接训练,这就告诉你,算法存在方差问题(方差过拟合,泛化能力),因为训练-开发集的错误率是在和训练集来自同一分布的数据中测得的。

所以你知道,尽管你的神经网络在训练集中表现良好,但无法泛化到来自相同分布的训练-开发集里,它无法很好地泛化推广到来自同一分布,但以前没见过的数据中,所以在这个样本中我们确实有一个方差问题。

二、一个不同的样本,假设训练误差为 1%,训练-开发误差为 1.5%,但当你开始处理开发集时,错误率上升到 10%。

现在你的方差问题就很小了,因为当你从见过的训练数据转到训练-开发集数据,神经网络还没有看到的数据,错误率只上升了一点点。但当你转到开发集时,错误率就大大上升了,所以这是数据不匹配的问题。因为你的学习算法没有直接在训练-开发集或者开发集训练过,但是这两个数据集来自不同的分布。但不管算法在学习什么,它在训练-开发集上做的很好,但开发集上做的不好,所以总之你的算法擅长处理和你关心的数据不同的分布,我们称之为数据不匹配的问题

三、最后一个例子,如果你的训练集错误率是 10%,你的训练-开发错误率是 11%,开发错误率是 20%,那么这其实有两个问题。

第一,可避免偏差相当高,因为你在训练集上都没有做得很好,而人类能做到接近 0%错误率,但你的算法在训练集上错误率为 10%。这里方差似乎很小,但数据不匹配问题很大。所以对于这个样本,我说,如果你有很大的偏差或者可避免偏差问题,还有数据不匹配问题。

小小结:在搭建神经网络的时候,最初数据集来源多种,网络和实际应用拍摄,划分数据集是个问题,可以通过尝试来判断,需要通过模型表现,比如错误率和人类水平来分析方差与偏差问题,进而采取相应手段改建网络。

要看的关键数据是人类水平错误率,你的训练集错误率,训练-开发集错误率,所以这分布和训练集一样,但你没有直
接在上面训练。根据这些错误率之间差距有多大,你可以大概知道,可避免偏差、方差数据不匹配问题各自有多大。

所以我们讲了如何使用来自和开发集、测试集不同分布的训练数据,这可以给你提供更多训练数据,因此有助于提高你的学习算法的性能,但是,潜在问题就不只是偏差和方差问题,这样做会引入第三个潜在问题,数据不匹配。如果你做了错误分析,并发现数据不匹配是大量错误的来源,那么你怎么解决这个问题呢?但结果很不幸,并没有特别系统的方法去解决数据不匹配问题,但可以做一些尝试。

2.6 定位数据不匹配(Addressing data mismatch )

如果训练集来自和开发测试集不同的分布,如果错误分析显示你有一个数据不匹配的问题该怎么办?

这个问题没有完全系统的解决方案,但可以看看一些可以尝试的事情。如果我发现有严重的数据不匹配问题,亲自做错误分析,尝试了解训练集和开发测试集的具体差异。技术上,为了避免对测试集过拟合,要做错误分析,应该人工去看开发集而不是测试集。

一个具体的例子,如果正在开发一个语音激活的后视镜应用,如果是语音的话,可能要听一下来自开发集的样本,尝试弄清楚开发集和训练集到底有什么不同。比如说可能会发现很多开发集样本噪音很多,有很多汽车噪音,这是开发集和训练集差异之一。也许还会发现其他错误。

当了解开发集误差的性质时,你就知道,开发集有可能跟训练集不同或者更难识别,那么可以尝试把训练数据变得更像开发集一点,或者,你也可以收集更多类似你的开发集和测试集的数据。所以,比如说,如果你发现车辆背景噪音是主要的错误来源,那么你可以模拟车辆噪声数据

可以合成。
所以假设你录制了大量清晰的音频,不带车辆背景噪音的音频,“The quick brown fox jumps over the lazy dog”(音频播放),所以,这可能是你的训练集里的一段音频,顺便说一下,这个句子在 AI 测试中经常使用,因为这个短句包含了从 a 到 z 所有字母,所以你会经常见到这个句子。但是,有了这个“the quick brown fox jumps over the lazy dog”这段录音之后,你也可以收集一段这样的汽车噪音,(播放汽车噪音音频)这就是汽车内部的背景噪音,如果你一言不发开车的话,就是这种声音。如果你把两个音频片段放到一起,你就可以合成出"the quick brown fox jumps over the lazy dog"(带有汽车噪声),在汽车背景噪音中的效果,听起来像这样,所以这是一个相对简单的音频合成例子

但是通过人工数据合成,你可以快速制造更多的训练数据,就像真的在车里录的那样,那就不需要花时间实际出去收集数据,比如说在实际行驶中的车子,录下上万小时的音频。所以,如果错误分析显示你应该尝试让你的数据听起来更像在车里录的,那么人工合成那种音频,然后喂给你的机器学习算法,这样做是合理的。

过拟合问题:现在我们要提醒一下,人工数据合成有一个潜在问题,比如说,你在安静的背景里录得10,000 小时音频数据,然后,比如说,你只录了一小时车辆背景噪音,那么,你可以这么做,将这 1 小时汽车噪音回放 10,000 次,并叠加到在安静的背景下录得的 10,000 小时数据。如果你这么做了,人听起来这个音频没什么问题。但是有一个风险,有可能你的学习算法对这1 小时汽车噪音过拟合。特别是,如果这组汽车里录的音频可能是你可以想象的所有汽车噪音背景的集合,如果你只录了一小时汽车噪音,那你可能只模拟了全部数据空间的一小部分,你可能只从汽车噪音的很小的子集来合成数据。

总而言之,如果认为存在数据不匹配问题,我建议你做错误分析,或者看看训练集,或者看看开发集,试图找出,试图了解这两个数据分布到底有什么不同,然后看看是否有办法收集更多看起来像开发集的数据作训练。
我们谈到其中一种办法是人工数据合成,人工数据合成确实有效。在语音识别中。我已经看到人工数据合成显著提升了已经非常好的语音识别系统的表现,所以这是可行的。但当你使用人工数据合成时,一定要谨慎,要记住你有可能从所有可能性的空间只选了很小一部分去模拟数据。 

2.7 迁移学习(Transfer learning )

深度学习中,最强大的理念之一就是,有的时候神经网络可以从一个任务中习得知识,并将这些知识应用到另一个独立的任务中。所以例如,也许你已经训练好一个神经网络,能够识别像猫这样的对象,然后使用那些知识,或者部分习得的知识去帮助您更好地阅读 x 射线扫描图,这就是所谓的迁移学习

把图像识别中学到的知识应用或迁移到放射科诊断上来,为什么这样做有效果呢?有很多低层次特征,比如说边缘检测、曲线检测、阳性对象检测(positiveobjects),从非常大的图像识别数据库中习得这些能力可能有助于你的学习算法在放射科诊断中做得更好,算法学到了很多结构信息,图像形状的信息,其中一些知识可能会很有用,所以学会了图像识别,它就可能学到足够多的信息,可以了解不同图像的组成部分是怎样的,学到线条、点、曲线这些知识,也许对象的一小部分,这些知识有可能帮助你的放射科诊断网络学习更快一些,或者需要更少的学习数据。(修改后面部分网络)

 那么迁移学习什么时候是有意义的呢?

迁移学习起作用的场合是,在迁移来源问题中你有很多数据,但迁移目标问题你没有那么多数据。例如,假设图像识别任务中你有 1 百万个样本,所以这里数据相当多。可以学习低层次特征,可以在神经网络的前面几层学到如何识别很多有用的特征。但是对于放射科任务,也许你只有一百个样本,所以你的放射学诊断问题数据很少,也许只有 100 次X射线扫描,所以你从图像识别训练中学到的很多知识可以迁移,并且真正帮你加强放射科识别任务的性能,即使你的放射科数据很少。

总结一下,迁移学习最有用的场合是,如果你尝试优化任务 B 的性能,通常这个任务数据相对较少,例如,在放射科中你知道很难收集很多𝑌射线扫描图来搭建一个性能良好的放射科诊断系统,所以在这种情况下,你可能会找一个相关但不同的任务,如图像识别,其中你可能用 1 百万张图片训练过了,并从中学到很多低层次特征,所以那也许能帮助网络在任务𝐶在放射科任务上做得更好,尽管任务B没有这么多数据。它确实可以显著提高你的学习任务的性能,但有时候也见过有些场合使用迁移学习时,任务A实际上数据量比任务B要少,这种情况下增益可能不多。

这就是迁移学习,你从一个任务中学习,然后尝试迁移到另一个不同任务中。

从多个任务中学习还有另外一个版本,就是所谓的多任务学习,当你尝试从多个任务中并行学习,而不是串行学习,在训练了一个任务之后试图迁移到另一个任务。

2.8 多任务学习(Multi-task learning )

迁移学习中,你的步骤是串行的,你从任务 A 里学习只是然后迁移到任务 B。

多任务学习中,你是同时开始学习的,试图让单个神经网络同时做几件事情,然后希望这里每个任务都能帮到其他所有任务。

一个例子,假设你在研发无人驾驶车辆,那么你的无人驾驶车可能需要同时检测不同的物体,比如检测行人、车辆、停车标志,还有交通灯各种其他东西。比如在左边这个例子中,图像里有个停车标志,然后图像中有辆车,但没有行人,也没有交通灯。

 

那么你现在可以做的是训练一个神经网络,来预测这些𝑧值,你就得到这样的神经网络,输入𝑦

整个训练集的平均损失和之前分类猫的例子主要区别在于,现在你要对J = 1到4求和,这与 softmax 回归的主要区别在于,与 softmax 回归不同,softmax 将单个标签分配给单个样本。 

事实证明,多任务学习也可以处理图像只有部分物体被标记的情况。所以第一个训练样本,我们说有人,给数据贴标签的人告诉你里面有一个行人,没有车,但他们没有标记是否有停车标志,或者是否有交通灯。也许第二个例子中,有行人,有车。但是,当标记人看着那张图片时,他们没有加标签,没有标记是否有停车标志,是否有交通灯等等。也许有些样本都有标记,但也许有些样本他们只标记了有没有车,然后还有一些是问号。

即使是这样的数据集,你也可以在上面训练算法,同时做四个任务,即使一些图像只有一小部分标签,其他是问号或者不管是什么。然后你训练算法的方式,即使这里有些标签是问号,或者没有标记,这就是对j从 1 到 4 求和,你就只对带 0 和 1 标签的 j 值求和,所以当有问号的时候,你就在求和时忽略那个项,这样只对有标签的值求和,于是你就能利用这样的数据集。 

 那么多任务学习什么时候有意义呢?当三件事为真时,它就是有意义的。

第一,如果你训练的一组任务,可以共用低层次特征。对于无人驾驶的例子,同时识别交通灯、汽车和行人是有道理的,这些物体有相似的特征,也许能帮你识别停车标志,因为这些都是道路上的特征。

第二,这个准则没有那么绝对,所以不一定是对的。

最后多任务学习往往在以下场合更有意义,当你可以训练一个足够大的神经网络,同时做好所有的工作,所以多任务学习的替代方法是为每个任务训练一个单独的神经网络。所以不是训练单个神经网络同时处理行人、汽车、停车标志和交通灯检测。你可以训练一个用于行人检测的神经网络,一个用于汽车检测的神经网络,一个用于停车标志检测的神经网络和一个用于交通信号灯检测的神经网络。

在实践中,多任务学习的使用频率要低于迁移学习

很多迁移学习的应用,你需要解决一个问题,但你的训练数据很少,所以你需要找一个数据很多的相关问题来预先学习,并将知识迁移到这个新问题上。

但多任务学习比较少见,就是你需要同时处理很多任务,都要做好,你可以同时训练所有这些任务,也许计算机视觉是一个例子。在物体检测中,我们看到更多使用多任务学习的应用,其中一个神经网络尝试检测一大堆物体,比分别训练不同的神经网络检测物体更好。但我说,平均来说,目前迁移学习使用频率更高,比多任务学习频率要高,但两者都可以成为你的强力工具。

2.9 什么是端到端的深度学习?(What is end-to-end deep learning? ) 

深度学习中最令人振奋的最新动态之一就是端到端深度学习的兴起,那么端到端学习到底是什么呢?简而言之,以前有一些数据处理系统或者学习系统,它们需要多个阶段的处理。那么端到端深度学习就是忽略所有这些不同的阶段,用单个神经网络代替它。

我们来看一些例子,以语音识别为例,你的目标是输入𝑦,比如说一段音频,然后把它映射到一个输出𝑧,就是这段音频的听写文本。所以传统上,语音识别需要很多阶段的处理。
首先你会提取一些特征,一些手工设计的音频特征,也许你听过 MFCC,这种算法是用来从音频中提取一组特定的人工设计的特征。在提取出一些低层次特征之后,你可以应用机器学习算法在音频片段中找到音位,所以音位是声音的基本单位,比如说“Cat”这个词是三个音节构成的,Cu-、Ah-和 Tu-,算法就把这三个音位提取出来,然后你将音位串在一起构成独
立的词,然后你将词串起来构成音频片段的听写文本。

和这种有很多阶段的流水线相比,端到端深度学习做的是,你训练一个巨大的神经网络,输入就是一段音频,输出直接是听写文本。端到端深度学习就只需要把训练集拿过来,直接学到了x和y之间的函数映射,直接绕过了其中很多步骤。

事实证明,端到端深度学习的挑战之一是,你可能需要大量数据才能让系统表现良好,比如,你只有 3000 小时数据去训练你的语音识别系统,那么传统的流水线效果真的很好。但当你拥有非常大的数据集时,比如 10,000 小时数据或者 100,000 小时数据,这样端到端方法突然开始很厉害了。所以当你的数据集较小的时候,传统流水线方法其实效果也不错,通常做得更好。你需要大数据集才能让端到端方法真正发出耀眼光芒。如果你的数据量适中,那么也可以用中间件方法,你可能输入还是音频,然后绕过特征提取,直接尝试从神经网络输出音位,然后也可以在其他阶段用,所以这是往端到端学习迈出的一小步,但还没有到那里。

 我们再来看几个例子,比如机器翻译。传统上,机器翻译系统也有一个很复杂的流水线,比如英语机翻得到文本,然后做文本分析,基本上要从文本中提取一些特征之类的,经过很多步骤,你最后会将英文文本翻译成法文。因为对于机器翻译来说的确有很多(英文,法文)的数据对,端到端深度学习在机器翻译领域非常好用,那是因为在今天可以收集x − y对的大数据集,就是英文句子和对应的法语翻译。所以在这个例子中,端到端深度学习效果很好。 

2.10 是否要使用端到端的深度学习?(Whether to use end-to-end learning? ) 

端到端深度学习的一些优缺点,这样你就可以根据一些准则,判断你的应用程序是否有希望使用端到端方法。

这里是应用端到端学习的一些好处,首先端到端学习真的只是让数据说话。所以如果你有足够多的(x,y)数据,那么不管从 x 到 y 最适合的函数映射是什么,如果你训练一个足够大的神经网络,希望这个神经网络能自己搞清楚,而使用纯机器学习方法,直接从x到y输入。

端到端深度学习的第二个好处就是这样,所需手工设计的组件更少,所以这也许能够简化你的设计工作流程,你不需要花太多时间去手工设计功能,手工设计这些中间表示方式。

 

 那么缺点呢?这里有一些缺点,首先,它可能需要大量的数据。要直接学到这个x到y的映射,你可能需要大量(x,y)数据。这就是为什么我们称之为端到端学习,因为你直接学习出从系统的一端到系统的另一端。

另一个缺点是,它排除了可能有用的手工设计组件。机器学习研究人员一般都很鄙视手工设计的东西,但如果你没有很多数据,你的学习算法就没办法从很小的训练集数据中获得洞察力。所以手工设计组件在这种情况,可能是把人类知识直接注入算法的途径,这总不是一件坏事。我觉得学习算法有两个主要的知识来源,一个是数据,另一个是你手工设计的任何东西,可能是组件,功能,或者其他东西。所以当你有大量数据时,手工设计的东西就不太重要了,但是当你没有太多的数据时,构造一个精心设计的系统,实际上可以将人类对这个问题的很多认识直接注入到问题里,进入算法里应该挺有帮助的。

如果你在构建一个新的机器学习系统,而你在尝试决定是否使用端到端深度学习,我认为关键的问题是,你有足够的数据能够直接学到从x映射到y足够复杂的函数吗? 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Clark-dj

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

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

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

打赏作者

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

抵扣说明:

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

余额充值