A White Paper on Neural Network Quantization

A White Paper on Neural Network Quantization

一、abstract

这篇文章《神经网络量化白皮书》主要讨论了神经网络量化在提高现代网络计算效率方面的重要作用,特别是对于具有严格功耗和计算限制的边缘设备。文章深入讨论了如何在保持低比特权重和激活的同时,减轻量化噪声对性能的影响的方法。首先,文章从硬件角度介绍了量化的基本概念,然后分别讨论了两种主要的量化方法:训练后量化(Post-Training Quantization, PTQ)和量化感知训练(Quantization-Aware Training, QAT)。PTQ方法无需重新训练或标记数据,是一种轻量级的量化方法。在大多数情况下,PTQ足以实现接近浮点精度的8位量化。而QAT则需要通过访问标记的训练数据进行微调,能够实现更低位宽的量化,且具有竞争力的结果。文章还基于现有文献和广泛的实验,为常见的深度学习模型和任务提供了经过测试的量化流程,以实现最先进的性能,并提出了一种调试工作流程来识别和解决量化新模型时遇到的常见问题。

**个人理解:**为了追求性能,神经网络模型的体量不断增大,这给在边缘设备上部署模型造成了困难。因此需要一些技术使得模型轻量化,加快模型的推理速度和功率消耗。模型量化就是一种非常有效的模型轻量化算法。它主要通过对模型内的权重和激活值参数进行类型转化(比如浮点型转低位整型,或者混合精度等)来加快模型推理速度。但是,这种粗略的量化方式会引入噪声使得模型精度有所下降。主流的模型量化算法主要分为PTQ和QAT两种。PTQ是在模型参数训练好之后进行精度转换,这种算法可以解决大多数问题。QAT是在训练过程中进行量化,步骤要繁琐一些,需要微调和标注数据,但是其精度要好于PTQ。

这里是引用

二、Introduction

这篇引言部分指出了深度学习作为一种通用工具在电子设备中注入智能的日益增长的需求,特别是对小型化、低延迟和高能效的神经网络解决方案的需求。如今,神经网络已被广泛应用于各种电子设备和服务中,包括智能手机、智能眼镜、家用电器、无人机、机器人以及自动驾驶汽车等。这些设备通常对神经网络的执行时间或长期性能的功耗有严格的要求。

文章强调了量化作为减少神经网络计算时间和能耗的有效方法。通过将权重和激活张量存储在比通常训练时使用的16或32位精度更低的位精度中,可以显著减少内存开销并降低矩阵乘法的计算成本。尽管神经网络对量化显示出了鲁棒性,即可以在保持相对较小的精度损失的情况下进行低位宽量化,但量化过程引入的噪声可能会降低网络的准确性。因此,尽管某些网络对这种噪声具有鲁棒性,其他网络则需要额外的工作来利用量化的好处。

文章介绍了神经网络量化的最新进展,从量化的基础介绍开始,讨论了硬件和实际考虑因素。然后,文章讨论了两种不同的神经网络量化方法:训练后量化(PTQ)和量化感知训练(QAT)。PTQ方法通过使用极少量或无需数据的方式对已训练的网络进行量化,这种方法简便易行,工程努力和计算成本低。与之相反,QAT依赖于在训练管道中模拟量化的神经网络重训练。尽管这需要更多的训练努力和可能的超参数调整,但通常比PTQ更能缩小到全精度准确性的差距。对于这两种方法,文章基于现有文献和广泛的实验,引入了标准化流程,实现了常见的计算机视觉和自然语言处理模型的最新性能,并提出了一种调试工作流程,以识别和解决量化新模型时遇到的常见问题。

三、Quantization fundamentals

在本节中,作者介绍了神经网络量化的基本原理以及运行量化网络的定点加速器。这一节从硬件背景开始,然后介绍标准量化方案及其属性。 稍后又讨论了与现代神经网络中常见的层相关的实际考虑因素及其对定点加速器的影响。

2.1 硬件背景(Hardware background)

在深入了解技术细节之前,我们首先探讨量化的硬件背景以及它如何使设备上的推理变得高效。图1提供了一个示意性概览,展示了在神经网络(NN)加速器中如何计算矩阵-向量乘法,y = Wx + b。 这是神经网络中更大的矩阵-矩阵乘法和卷积的基本构建块。这种硬件块旨在通过尽可能并行地执行多个计算来提高NN推理的效率。这个NN加速器的两个基本组件是处理元素Cn,m和累加器An。我们在图1中的玩具示例有16个排列成正方形网格的处理元素和4个累加器。计算开始时,首先用偏置值bn加载累加器。然后,我们将权重值Wn,m和输入值xm加载到数组中,并在各自的处理元素Cn,m = Wn,m xm中计算它们的乘积,在单个周期内完成。它们的结果随后被加到累加器中:
在这里插入图片描述

上述操作也被称为乘累加(MAC)操作。这个步骤对于更大的矩阵-向量乘法会重复多次。一旦所有周期完成,累加器中的值随后被移回内存,以便在下一个神经网络层中使用。神经网络通常使用FP32权重和激活进行训练。如果我们要在FP32中执行推理,处理元素和累加器将不得不支持浮点逻辑,并且我们需要将32位数据从内存传输到处理单元。MAC操作和数据传输消耗了神经网络推理期间大部分的能量。因此,通过对这些量使用较低位的定点或量化表示,可以获得显著的好处。低位定点表示法,如INT8,不仅减少了数据传输量,也减小了MAC操作的大小和能耗(Horowitz, 2014)。这是因为数字算术的成本通常与使用的位数线性到二次方地增长,而且定点加法比浮点加法更高效(Horowitz, 2014)。
图1. 神经网络加速器硬件中的矩阵-向量相乘运算的机制图
图1. 神经网络加速器硬件中的矩阵-向量相乘运算的机制图
为了从浮点运算转移到高效的定点运算,我们需要一个将浮点向量转换为整数的方案。一个浮点向量x可以近似表示为一个标量乘以一个整数值向量:
在这里插入图片描述
其中 s x s_x sx是浮点数比例因子, x int x_{\text{int}} xint是整数向量,例如INT8。我们将这个量化后的向量表示为 x ^ \hat{x} x^。通过量化权重和激活,我们可以写出累加方程的量化版本:
在这里插入图片描述
这里, A ^ n \hat{A}_n A^n是量化后的累加结果, b ^ n \hat{b}_n b^n是量化后的偏置值, W ^ n , m \hat{W}_{n,m} W^n,m是量化后的权重,而 x ^ m \hat{x}_m x^m是量化后的输入值。
通过这种方式,原始的浮点运算被转换为基于整数的运算,这在定点硬件上更加高地执行。这种转换减少了计算复杂性,并可能减少了内存占用和能耗,使得神经网络在资源受限的设备上运行成为可能。

请注意,我们对权重使用了单独的比例因子 s w s_w sw,对激活使用了 s x s_x sx。这提供了灵活性并减少了量化误差(更多细节见2.2节)。由于每个比例因子应用于整个张量,这个方案允许我们在方程中将比例因子从求和中分离出来,并以定点格式执行MAC(乘累加)操作。我们有意忽略了偏置的量化,因为偏置通常以更高的位宽(32位)存储,其比例因子依赖于权重和激活的比例因子(Jacob et al., 2018)。

图2展示了当我们引入量化时,神经网络加速器如何变化。在我们的示例中,我们使用了INT8算术运算,但为了这次讨论,这可以是任何量化格式。保持累加器更高的位宽,通常是32位宽,是很重要的。否则,随着更多的乘积在计算过程中被累加,我们有可能因为溢出而遭受损失。

存储在32位累加器中的激活需要在它们可以被下一层使用之前写入内存。为了减少数据传输和降低下一层操作的复杂度,这些激活被重新量化回INT8。这需要一个重新量化步骤,如图2所示。

在这里插入图片描述
 图2. 用于量化推理的神经网络加速器中的矩阵乘法逻辑示意图。

2.2 均匀仿射量化

在本节中,作者定义了他们将在论文中使用的量化方案。 这种方案称为均匀量化,它是最常用的量化方案,因为它允许有效地实现定点算术。
  均匀仿射量化,也称为非对称量化,由三个量化参数定义:。比例因子 s、零点 z 和位宽 b

  • 比例因子和零点用于将浮点值映射到整数网格,其大小取决于位宽。
  • 比例因子通常用浮点数表示,并且指定量化器的步长。
  • 零点 z 是一个整数,可确保对实零进行无误差量化。这对于确保零填充或 ReLU 等常见操作不会引起量化误差很重要。

一旦三个量化参数定义好之后,便可以执行量化参数操作,从一个真实值的向量x开始,首先按照下边的公式将一个原始的权重或激活值向量x映射到无符号的整型网格中{0, . . . , 2 b − 1 2^b - 1 2b1},其中b是位宽。
在这里插入图片描述
在这里插入图片描述

表示的是四舍五入。clamping函数被定义如下:
在这里插入图片描述
为了从量化后的数据中恢复出真实的数据x,我们需要反量化操作:
在这里插入图片描述
将量化步骤和反量化步骤进行总结,可以得到最终的通用的量化函数。

在这里插入图片描述
在这里插入图片描述

对称的均匀量化
对称量化是不对称情况的简化版本。 对称量化器将零点限制为 0。这减少了在不对称量化中的累加操作期间处理零点偏移的计算开销。 但是偏移量的缺乏限制了整数域和浮点域之间的映射。 因此,有符号或无符号整数网格的选择很重要:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
无符号型的对称量化很适合单尾分布 (单尾( o n e − t a i l e d )分布的数据指的是数据分布呈现出在一个方向上有明显偏倚的趋势,这意味着数据的大部分值集中在分布的一侧。在统计学中,这种分布常见于某些特定的测试或实验结果,其中结果主要偏向于分布的一个方向。) {\tiny (单尾(one-tailed)分布的数据指的是数据分布呈现出在一个方向上有明显偏倚的趋势,这意味着数据的大部分值集中在分布的一侧。在统计学中,这种分布常见于某些特定的测试或实验结果,其中结果主要偏向于分布的一个方向。)} (单尾(onetailed)分布的数据指的是数据分布呈现出在一个方向上有明显偏倚的趋势,这意味着数据的大部分值集中在分布的一侧。在统计学中,这种分布常见于某些特定的测试或实验结果,其中结果主要偏向于分布的一个方向。)
的数据,比如RELU的激活值。而有符号型的对称量化适合用于关于零大致对称的数据。

均匀量化的三种形式(非对称均匀量化,有符号型对称量化,无符号型对称量化)如图3所示。
在这里插入图片描述
图3. 位宽为 8 的不同均匀量化网格的直观解释。s 是比例因子,z 是零点。 浮点网格为黑色,整数量化网格为蓝色。

2的幂次方
2的幂次方量化是对称量化的一种特殊情况,其中比例因子 s s s 被限制为2的幂次方,即 s = 2 − k s = 2^{-k} s=2k。这种方式在硬件上可以表现得很高效,因为这样的缩放相当于简单的位移操作。然而,这种比例因子的有限表达能力会使舍入误差和裁剪误差之间的权衡变得复杂。

量化粒度
到目前为止,我们已经为每个张量定义了一组量化参数(量化器),一个用于权重,一个用于激活。这称为 per-tensor 量化。我们还可以为张量的各个维度(例如,权重张量的输出通道)定义单独的量化器,从而增加量化粒度。在神经网络量化中, per-tensor 量化是最常见的粒度选择,因为它的硬件实现更简单:图2中所有累加器都使用相同的比例因子 S w , S x S_w, S_x Sw,Sx。但是,我们可以使用更精细的粒度来进一步提高性能。例如,对于权重张量,我们可以为每个输出通道指定不同的量化器。这称为per-channel量化。

还有一些其他的工作不止于为每个输出通道指定不同的量化器,而是为每组权重或激活应用单独的量化器。但是,增加组的粒度通常会以一些额外开销为代价来提高准确性。开销与处理具有不同比例因子的值之和的累加器相关。大多数现有的定点加速器目前不支持这种逻辑,因此,我们不会在这项工作中考虑它们。然而,随着该领域研究的增长,预计未来会有更多对这些方法的硬件支持。

2.3 量化模拟

为了测试神经网络在量化设备上的运行情况,我们经常在用于训练神经网络的相同通用硬件上模拟量化行为。这就叫做 quantization simulation (量化模拟)。 我们旨在使用浮点型的硬件估计定点运算。相比较于在真正的量化硬件或者使用量化过的核跑实验,模拟量化更好实现。这允许用户高效地测试不同的量化策略,并且对于QAT还可以使能GPU加速。在这一节,作者首先解释了量化模拟步骤的基本原理,然后讨论能够帮助减少模拟量化核在真实设备上运行之间的差异的技术。

之前,我们了解了在定点运算型的设备上,矩阵-向量相乘是怎么计算的。在图4a中,作者将这种运算过程推广到卷积层,而且还包括一个激活函数以使其更真实。在设备上推理期间,硬件的所有输入(偏差、权重和输入激活)都是定点格式。 然而,当我们使用常见的深度学习框架和通用硬件模拟量化时,这些量是浮点数。 这就是我们在计算图中引入量化模块以诱导量化效果的原因。
在这里插入图片描述
图4. 卷积层量化前向传递的示意图:a) 计算实际设备上量化推理的图。 b) 模拟通用浮点硬件的量化推理。

图 4b 显示了如何在深度学习框架中对相同的卷积层进行建模。在权重和卷积之间添加量化块以模拟权重量化,并在激活函数之后添加以模拟激活量化。 偏差通常不会被量化,因为它以更高的精度存储。在前边的小节中,作者更详细地讨论了何时将量化模块置于非线性之后是合适的。 量化模块实现前边列出的的量化函数,每个量化模块由一组量化参数(比例因子、零点、位宽)定义。量化模块的输入和输出都是浮点格式,但输出位于量化网格上。

Batch normalization folding

批量标准化(Batch Normalization,简称BN)是现代卷积网络中的一个标准组件,由Ioffe和Szegedy在2015年提出。批量标准化的主要作用是在线性层输出的数据上进行标准化处理,然后再进行缩放和偏移操作(参见公式9)。对于设备上的推理,这些操作可以通过一个称为批量标准化折叠(Batch Normalization Folding)的步骤被整合到前一个或下一个线性层中,这一概念分别由Krishnamoorthi在2018年和Jacob等人在2018年提出。这样做可以从网络中完全移除批量标准化操作,因为这些计算被吸收到相邻的线性层中。除了减少额外的缩放和偏移操作带来的计算开销外,这还避免了额外的数据移动和层输出的量化。更正式地,推理时的批量标准化可以定义为输出x的仿射映射:

BatchNorm ( x ) = γ ( x − μ σ 2 + ϵ ) + β \text{BatchNorm}(x) = \gamma \left( \frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}} \right) + \beta BatchNorm(x)=γ(σ2+ϵ xμ)+β
在这里插入图片描述

其中,

这种方式使得批量标准化的操作通过修改权重和偏置来实现,从而在执行推理时简化了计算过程。

通过上述变换,就将批量归一化层和线性层融合在了一起

Activation function fusing

虽然像Swish这样的新型激活函数在使用浮点数模型时可以提高准确性,但这些优势在量化后可能会消失。此外,在固定点硬件上部署这些函数可能效率较低,影响这类平台上量化模型的实际性能和效率。

在图2中介绍的简单量化加速器中,我们看到激活的反量化发生在计算矩阵乘法或卷积输出值之后。然而,实际上我们经常在线性运算之后直接出现非线性(图4中的情况)。因为将线性层的激活写入内存,然后将它们重新加载到计算核心应用非线性运算会很浪费资源。出于这个原因,许多硬件解决方案都带有一个硬件单元,在重新量化步骤之前应用非线性。 如果是这种情况,我们只需要模拟在非线性之后发生的重新量化。 例如 ReLU 非线性很容易由重新量化块建模,因为您可以设置它的最小可表示值激活量化为 0。

其他更复杂的激活函数,例如 sigmoid 或 Swish,需要更专门的支持。如果这种支持不可用,我们需要在图中的非线性前后添加一个量化步骤。这会对量化模型的准确性产生很大影响 尽管像 Swish 函数这样的新激活可以提高浮点精度,但这些激活在量化后可能会消失,或者在定点硬件上部署的效率可能较低。

其它的网络层的量化
在神经网络中使用了许多其他类型的层,这些层的建模方式在很大程度上取决于特定的硬件实现。有时,模拟量化与目标性能之间的不匹配是由于层没有被正确量化。在这里,我们提供一些关于如何为一些常用层模拟量化的指导:

  • 最大池化(Max pooling):激活量化不是必需的,因为输入和输出值位于同一量化网格上。
  • 平均池化(Average pooling):整数的平均值不一定是整数。因此,平均池化后需要一个量化步骤。然而,我们对输入和输出使用相同的量化器,因为量化范围不会显著改变。
  • 逐元素加法(Element-wise addition):尽管这种操作很简单,但很难准确模拟。在加法过程中,两个输入的量化范围必须完全匹配。如果这些范围不匹配,需要额外的注意以确保加法按预期工作。虽然没有单一公认的解决方案,但增加一个重量化步骤可以粗略模拟增加的噪声。另一种方法是通过绑定输入的量化网格来优化网络。这可以避免重量化步骤,但可能需要微调。
  • 连接(Concatenation):被连接的两个分支通常不共享相同的量化参数。这意味着它们的量化网格可能不重叠,使得重量化步骤变得必要。与逐元素加法一样,通过为被连接的分支优化网络以拥有共享的量化参数是可能的。

总的来说,对于不同的层以及它们在特定硬件上的实现,模拟量化需要特定的考虑和策略。这些策略旨在在保持模型性能的同时,减少量化引入的误差和损失。

2.4 部分的注意事项(Practical considerations)

在对多层神经网络进行量化时,我们面临着大量的量化选择空间,包括量化方案、粒度和位宽。 在本节中,作者探讨了一些有助于减少搜索空间的实际考虑因素

请注意,在本白皮书中,作者仅考虑同质位宽。这意味着为权重或激活选择的位宽在所有层中保持不变。因为硬件更普遍地支持同构位宽,但最近的一些工作也探索了异构位宽或混合精度的实现。
对称与非对称量化的比较 (Symmetric vs. asymmetric quantization)
对于每一个权重或者激活量化,我们都需要选择一个量化的方案。一方面,由于非对称量化有一个额外的偏移参数,所以其更富有表现力,但是使用非对称的量化可能会带来额外的计算开销。要了解为什么会出现这种情况,请考虑当权重不对称时会发生什么。

下边分别是当前层量化后的权重和上一层的量化后的激活值。如下所示,它们要进行相乘得到当前层的计算结果。 
在这里插入图片描述
如果两个操作都是对称格式,第一项就是我们将拥有的(因为没有零点和偏置)。第三项和第四项仅取决于预先知道的比例、偏移量和重量值。因此,这两项可以预先计算并添加到层的偏置项中,几乎不需要任何成本 然而,第二项取决于输入数据 x。这意味着对于每批数据,我们需要在推理期间计算一个附加项。这可能会导致延迟和功率的显着开销,因为它相当于添加一个额外的通道。出于这个原因,使用非对称激活量化和对称权重量化是一种常见的方法,可以避免额外的数据相关项。
·······

因此,使用非对称激活量化和对称权重量化是一种常见的方法,从而避免了附加的数据依赖项。

每个张量和每个通道的量化
在2.23节,我们讨论了不同水平的粒度量化。在一段时间里面,每个张量的参数和激活的量化是一个标准,因为它被固定点的加速器所支持。然而,每通道的权重的量化也能提升准确率,特别是当权重的分布在不同通道之间变化显著时。回顾方程(3)中被量化的MAC操作,我们可以看到,每通道权重量化可以在加速器中通过应用一个单独的每通道权重尺度因子来实现,而不需要重新缩放。每个通道的激活量化很难实现,因为我们不能将比例因子从求和中考虑出来,因此,需要为每个输入通道重新缩放累加器。尽管每个通道的权重量化越来越普遍,但并不是所有的商业硬件都支持它。因此,需要考虑是否能够在你的目标设备上进行实现。

四、后训练量化(post-training quantization)

训练后量化(PTQ)算法采用一个预先训练好的FP32网络,并将其直接转换为一个定点网络,而不需要原始的训练管道。这些方法方法不需要数据或者可能需要一个小的校准数据集(这通常是很好获得的)。此外,几乎没有超参数调优,这使得它们可以通过单个API调用作为黑盒方法,以计算效率高的方式量化预先训练过的神经网络。这使得神经网络设计者不必成为量化方面的专家,从而允许神经网络量化的更广泛的应用。PTQ过程中的一个基本步骤是为每个量化器找到良好的量化范围。
们在第2.2节中简要讨论了量化范围的选择如何影响量化误差。在本节中,我们首先讨论在实践中用于寻找良好的量化参数的各种常用方法。.然后,我们探讨在PTQ中观察到的常见问题,并介绍最成功的技术来克服它们。使用这些技术,我们提出了一个标准的训练后量化管道,我们发现它在大多数常见的场景中工作得最好,最后,我们引入了一组调试步骤来提高量化模型的性能。

3.1 量化范围的设置

量化范围设置是指确定量化网格的剪切阈值的方法, q m i n q_{min} qmin q m a x q_{max} qmax(见公式7)。范围设置的关键权衡是在剪切和舍入误差之间,在第2.2节中描述,以及它们对被配置的每个量化器的最终任务损失的影响。这里描述的每一种方法都提供了两个量之间不同的权衡。这里描述的每一种方法都提供了两个量之间不同的权衡。这是因为在PTQ中,我们的目标是不需要端到端训练的快速计算方法。权重通常可以被量化,而不需要任何校准数据。然而,确定激活量化的参数通常需要几批校准数据。

为了覆盖张量的整个动态范围,我们可以定义如下的量化参数:
在这里插入图片描述
其中,V表示要被量化的张量。这将导致没有剪切错误。然而,这种方法对离群值很敏感,因为较强的离群值可能会导致过多的舍入误差。
均方误差(MSE)缓解大离群值问题的一种方法是使用基于MSE的范围设置。在范围设置的方法中。我们发现 q m i n q_{min} qmin q m a x q_{max} qmax,他们在原始和量化张量之间去最小化MSE。
在这里插入图片描述

六 Summary and Conclusions

这段内容概述了深度学习在各种机器学习应用中的重要性,特别是在需要快速且高效的神经网络推断的场景中。随着深度学习在日常生活中的应用越来越广泛,比如智能手机、家用电器、无人机、机器人以及自动驾驶汽车,对于快速且省电的神经网络推理的需求也在增加。神经网络量化是减少神经网络在推理过程中的能耗和延迟要求的最有效方法之一。

量化技术允许我们从浮点表示转移到固定点格式,结合使用高效的固定点运算的专用硬件,有潜力实现显著的功耗降低和推理加速。然而,要利用这些节能优势,我们需要健壮的量化方法,这些方法能在减少权重和激活的位宽度的同时,保持高准确率。为此,文中考虑了两大类量化算法:训练后量化(Post-Training Quantization, PTQ)和量化感知训练(Quantization-Aware Training, QAT)。

训练后量化技术将预训练的FP32网络转换为固定点网络,无需原始训练流程。这使它们成为一种轻量级的、一键式的量化方法,工程努力和计算成本都很低。文中描述了PTQ的一系列最新进展,并介绍了一个导致广泛模型和机器学习任务接近浮点精度结果的PTQ流程。特别是,使用所提出的流程,我们可以仅在浮点精度1%的范围内实现权重和激活的8位量化。此外,还展示了许多网络甚至可以量化到4位权重,只有很小的性能下降。此外,还介绍了一个调试工作流程,有效识别和解决量化新网络时可能出现的问题。

量化感知训练在训练过程中通过模拟量化操作来模拟量化噪声。与PTQ相比,这种训练程序能够找到更好的解决方案,同时使激活量化更加有效和激进。类似于PTQ,我们介绍了一个使用该领域最新算法的标准训练流程。我们还特别注意到在QAT中的批量归一化折叠,展示了简单的静态折叠比其他更计算密集的方法表现更好。我们演示了,使用我们的QAT流程,我们可以实现权重的4位量化,对于某些模型甚至可以实现4位激活,与浮点相比只有很小的精度下降。

在PTQ和QAT之间的选择取决于应用的准确率和功耗要求。这两种方法都是任何模型效率工具包的重要组成部分,我们希望我们提出的流程能帮助工程师们用更少的时间和努力部署高性能的量化模型。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值