论文翻译:Attention is all you need

Attention is all you need

摘要

主要的序列转换模型基于复杂的递归或卷积神经网络,包括编码器和解码器。性能最好的模型还通过注意力机制连接编码器和解码器。我们提出了一种新的简单的网络体系结构Transformer,它完全基于注意力机制,完全不需要重复和卷积。在两个机器翻译任务上的实验表明,这些模型在质量上更优越,同时更具并行性,需要的训练时间明显减少。我们的模型在2014年WMT英德翻译任务中达到28.4 BLEU,比现有的最佳结果(包括集成部分)提高了2个BLEU以上。在WMT 2014英法翻译任务中,我们的模型在8个GPU上训练3.5天后,建立了一个新的单模型最新的BLEU分数41.8,这是文献中最好模型的训练成本的一小部分。我们通过将其成功地应用于大量和有限训练数据的英语选区分析中,表明Transformer对其他任务具有很好的通用性。


1. 介绍

递归神经网络,特别是长短期记忆[13]和门控递归神经网络[7],已经被牢固地确立为序列建模和转换问题(例如语言建模和机器翻译)中的最先进的方法[35,2,5]。此后,人们一直在努力扩大循环语言模型和编码器-解码器体系结构的界限[38、24、15]。

递归模型通常沿输入和输出序列的符号位置因数计算。将位置与计算时间中的步骤对齐,它们根据前一隐藏状态 h t − 1 h_{t-1} ht1和位置 t t t的输入来生成隐藏状态 h t h_t ht的序列。由于内存限制限制了示例之间的批处理,因此这种固有的顺序性妨碍了训练示例中的并行化,而在更长的序列长度中,并行化变得至关重要。最近的工作已经通过因数分解技巧[21]和条件计算[32]在计算效率方面取得了显著的改进,同时也提高了针对后者的模型性能。然而,顺序计算的基本约束仍然存在。

在各种任务中,注意力机制已经成为引人注目的序列建模和转换模型的组成部分,允许对依赖项(相关性)进行建模,而不考虑它们在输入或输出序列中的距离[2,19]。但是,在少数情况下[27],在所有情况下,此类注意力机制都与循环网络结合使用。

在这项工作中,我们提出了 Transformer,一个避免循环的模型架构,而是完全依赖于一个注意力机制来绘制输入和输出之间的全局依赖性。Transformer允许更多的并行化,并且可以在8个P100 gpu上进行最少12个小时的训练,从而在翻译质量方面达到新的水平。


2. 背景

减少顺序计算的目标也构成了扩展神经GPU[16]、ByteNet[18]和ConvS2S[9]的基础,它们都使用卷积神经网络作为基本构件,并行计算所有输入和输出位置的隐藏表示。
在这些模型中,将两个任意输入或输出位置的信号关联起来所需的操作数量在位置之间的距离中增长,对于ConvS2S是线性增长,对于ByteNet是对数增长。这使得学习相距较远的位置之间的依赖关系变得更加困难[12]。在Transformer中,这可以减少到恒定的操作次数,尽管会因平均注意力加权位置而导致有效分辨率降低的代价,这是我们用3.2中所述的多头注意力抵消的效果。

自我注意,有时被称为内部注意,是一种将单个序列的不同位置联系起来以计算该序列的表示的注意机制。自我注意已经被成功地用于各种任务,包括阅读理解、抽象总结、文本蕴涵和学习任务无关的句子表征[4,27,28,22]。端到端记忆网络基于一种递归注意机制,而不是按顺序排列的递归,在简单语言问题回答和语言建模任务[34]中表现良好。

然而,就我们所知,Transformer是第一个完全依赖于自注意来计算其输入和输出表示的转换模型,而不使用顺序排列的RNNs或卷积。在接下来的部分中,我们将描述Transformer,激发self-attention,并讨论它相对于[17,18]和[9]等模型的优点。


3. 模型结构

大多数竞争性神经序列转换模型都具有编码器-解码器结构[5,2,35]。这里,编码器将符号表示 ( x 1 , . . . , x n ) (x_1,...,x_n) (x1,...,xn)的输入序列映射到连续表示序列 z = ( z 1 , . . . , z n ) z=(z_1, ..., z_n) z=(z1,...,zn)。在给定 z \mathbf{z} z的情况下,解码器一次一个元素地生成输出序列的符号 ( y 1 , . . . , y m ) (y_1,... ,y_m) (y1,...,ym)。在每一步,模型都是自回归的[10],在生成下一步时使用先前生成的符号作为附加输入。

Transformer遵循这个整体架构,对编码器和解码器使用堆叠的自关注层和逐点的完全连接层,分别显示在图1的左半部分和右半部分。

图1

3.1 编码器和解码器堆栈

编码器: 编码器由 N = 6 N=6 N=6个相同的堆叠组成。每层都有两个子层。第一个是多头自我注意机制,第二个是简单的位置全连接前馈网络。我们在每两个子层周围使用一个残余连接[11],然后使用层标准化[1]。也就是说,每个子层的输出是 LayerNorm( x + Sublayer ( x ) ) \text{LayerNorm(}x+\text{Sublayer}(x)\text{)} LayerNorm(x+Sublayer(x)),其中 Sublayer ( x ) \text{Sublayer}(x) Sublayer(x)是子层本身实现的功能。为了便于这些残余连接,模型中的所有子层以及嵌入层产生维度 d m o d e l = 512 d_{model}=512 dmodel=512的输出。

解码器: 解码器还由 N = 6 N=6 N=6个相同的层堆叠而成。除了每个编码层中的两个子层之外,解码器还插入第三个子层,该第三子层对编码器堆栈的输出执行多头关注。与编码器类似,我们在每个子层周围使用残差连接,然后进行层归一化。我们还修改了解码器堆栈中的自我注意子层,以防止位置对后续位置的注意。这种掩蔽,与属于嵌入偏移一个位置的事实相结合,确保了位置 i i i的预测只能依赖于小于 i i i的位置的已知输出。

3.2 注意力

注意函数可以描述为将query和一组key-value对映射到输出,其中,query、keys、values都是向量。输出被计算为value的加权和,其中分配给每个value的权重是由query与相应的key的兼容性函数计算的。

图2

3.2.1 Scaled Dot-Product Attention

我们将一种特别的注意机制称为“Scaled Dot-Product Attention”(图2)。输入包括queries和keys的维度 d k d_k dk,以及values的维度 d v d_v dv。我们用所有keys计算query的点积,然后将每个点积除以 d k \sqrt{d_k} dk ,然后应用softmax函数来获得values的权重。

在实践中,我们同时计算一组queries的注意力函数,并将其打包成一个矩阵 Q Q Q。键和值也被打包到矩阵 K K K V V V中。我们计算输出矩阵为:

Attention ( Q ,    K ,    V ) = s o f t m a x ( Q K T d k ) V \text{Attention}(Q,\;K,\;V)=softmax(\frac{QK^T}{\sqrt{d_k}})V Attention(Q,K,V)=softmax(dk QKT)V(1)

两个最常用的注意函数是加性注意[2]和点积(乘性)注意。除了比例因子 1 d k \frac{1}{\sqrt{d_k}} dk 1外,点积注意与我们的算法相同。加性注意使用带有单隐层的前馈网络计算兼容性函数。虽然两者在理论复杂性上相似,但点积注意在实践中要快得多,空间效率更高,因为它可以使用高度优化的矩阵乘法代码来实现。

而对于较小的 d k d_k dk值,这两种机制的表现相似,对于较大的 d k d_k dk值,加性注意由于点积注意,而无需缩放[3]。为了抵消这种影响,我们将点积缩放 1 d k \frac{1}{\sqrt{d_k}} dk 1

3.2.2 Multi-Head Attention

我们发现利用学习到的不同的线性投影将queries,keys和values分别线性投影到 d k ,    d k ,    d v d_k, \; d_k, \;d_v dk,dk,dv维度 h h h次是有益的,而不是用 d m o d e l d_{model} dmodel维的queries,key,values执行单一的注意函数。然后,在query,key和value的每个投影版本上,我们并行执行注意函数,从而产生 d v d_v dv维输出的value。这些被连接起来并再次投影,产生最终的值,如图2所示。

多头注意力使模型可以共同关注来自不同位置的不同表示子空间的信息。在单一注意力的情况下,平均会抑制这一点。

MultiHead ( Q , K , V ) = Concat ( head 1 , . . . , head h ) W O where    head i = Attention ( Q W i Q , K W i K , V W i V ) \text{MultiHead}(Q, K, V)=\text{Concat}(\text{head}_1,...,\text{head}_h)W^O \\ \text{where} \;\text{head}_i = \text{Attention}(QW_i^Q,KW_i^K,VW_i^V) MultiHead(Q,K,V)=Concat(head1,...,headh)WOwhereheadi=Attention(QWiQ,KWiK,VWiV)

其中,投影是参数矩阵 W i Q ∈ R d m o d e l × d k , W i K ∈ R d m o d e l × d k , W i V ∈ R d m o d e l × d v , W O ∈ R h d v × d m o d e l W_i^Q\in \mathbb{R}^{d_{model}\times{d_k}},W_i^K\in \mathbb{R}^{d_{model}\times{d_k}},W_i^V\in \mathbb{R}^{d_{model}\times{d_v}}, W^O\in \mathbb{R}^{hd_v\times d_{model}} WiQRdmodel×dk,WiKRdmodel×dk,WiVRdmodel×dv,WORhdv×dmodel

在这项工作中,我们使用 h = 8 h=8 h=8个平行注意层或头。对于其中的每一个,我们使用 d k = d v = d m o d e l / h = 64 d_k = d_v = d_{model}/h = 64 dk=dv=dmodel/h=64。由于降低了每个头部的维度,所以总的计算量与全维的单头注意机制相似。

3.2.3 注意力在我们模型中的应用

Transformer以三种不同方式使用多头注意力:

  • 在“encoder-decoder attention”层中,query来自先前的解码器层,而存储的key和value来自解码器的输出。这允许解码器中的每个位置都关注输入序列中的所有位置。这模仿了序列到序列模型(如[38,2,9])中典型的编码器-解码器注意机制。这模仿了序列到序列模型

  • encoder包含自注意层。在自注意层,所有的key,value,query都来自同一个位置,在本例中是编码器中上一层的输出。编码器的每个位置都可以关注编码器上一层中的所有位置。

  • 类似地,解码器中的自注意层允许解码器中的每个位置关注解码器中的所有位置,直到并包括该位置。我们需要防止信息在解码器中向左流动,以保留自回归特效。我们通过屏蔽(设置为 − ∞ -\infty )Softmax输入中对应于非法连接的所有value。参见图2。

基于位置的前馈网络

除了注意子层,编码器和解码器中的每一层都包含一个完全连接的前馈网络,该网络分别且相同地应用于每个位置。这由两个线性变换组成,两个线性变换之间具有ReLU激活。

FFN ( x ) = max ( 0 , x W 1 + b 1 ) W 2 + b 2 \text{FFN}(x)=\text{max}(0,xW_1 + b_1)W_2+b_2 FFN(x)=max(0,xW1+b1)W2+b2(2)

虽然线性变换在不同位置上相同,但是它们使用不同的参数。另一种描述方式是内核大小为1的两个卷积。输入和输出的维度 d m o d e l = 512 d_{model}=512 dmodel=512,内层维度 d f f = 2048 d_{ff}=2048 dff=2048

3.4 Embeddings and Softmax

与其他序列转换模型相似,我们使用了学习嵌入将输入标记和输出标记转换为维度 d m o d e l d_{model} dmodel的向量。我们还使用常用的学习线性边和和softmax函数将解码器输出转换为预测的下一个标记概率。在我们的模型中,我们在两个嵌入层和Softmax前的线性变换之间共享想的权重矩阵,类似于[30]。在嵌入层中,我们将这些权重乘以 d m o d e l \sqrt{d_{model}} dmodel

3.5 位置编码

由于我们的模型不包含递归和卷积,为了使模型利用序列的顺序,我们必须注入一些关于序列中标记的相对或绝对位置的信息。为此,我们将“positional encodings”添加到编码器和解码器堆栈底部的输入嵌入中。位置编码具有嵌入相同的维度 d m o d e l d_{model} dmodel,从而可以将两者相加。位置编码有很多选择,有学习的和固定的[9]。

在这项工作中,我们使用不同频率的正弦和余弦函数:

P E ( p o s , 2 i ) = s i n ( p o s / 1000 0 2 i / d m o d e l ) P E ( p o s , 2 i + 1 ) = c o s ( p o s / 1000 0 2 i / d m o d e l ) PE(pos,2i)=sin(pos/10000^{2i/d_{model}}) \\ PE(pos,2i+1)=cos(pos/10000^{2i/d_{model}}) PE(pos,2i)=sin(pos/100002i/dmodel)PE(pos,2i+1)=cos(pos/100002i/dmodel)

其中 p o s pos pos是位置, i i i是维度。也就是说,位置编码的每个维度对应于一个正弦。波长形成从2π到10000·2π的几何级数。我们选择这个函数是我们假设它将允许模型很容易地学习通过相对位置参加,因为对于任何固定的偏移量 k k k P E p o s + k PE_{pos+k} PEpos+k可以表示为 P E p o s PE_{pos} PEpos的线性函数。

我们还试验了使用习得的位置嵌入[9],发现两个版本产生的结果几乎相同(参见表3,第(E)行)。我们选择正弦曲线版本是因为它可以使模型外推到比训练过程中遇到的序列更长的序列长度。


4. Why Self-Attention

在本节中,我们将自注意层的各个方面与通常用于将一个可变长度的符号表示序列 x 1 , . . . , x n x_1,...,x_n x1,...,xn映射到另一个等长序列 ( z 1 , . . . , z n ) (z_1,...,z_n) (z1,...,zn)的递归和卷积层进行比较,其中 x i , z i ∈ R d x_i,z_i\in \mathbb{R}^d xi,ziRd,例如典型的序列转换解码器或解码器中的隐藏层。为了激发我们的自我注意力,我们考虑了三个愿望。

一个是每层的总计算复杂度。 另一个是可以并行化的计算量,以所需的最少顺序操作数衡量。

第三个是网络中远程依赖之间的路径长度。在许多序列转换任务中,学习长距离依赖关系是一个关键的挑战。影响学习这种依赖关系的能力的一个关键因素是网络中向前和向后信号必须经过的路径的长度。输入和输出序列中位置的任意组合之间的这些路径越短,学习远程依赖关系就越容易[12]。 因此,我们还比较了由不同层类型组成的网络中任意两个输入和输出位置之间的最大路径长度。

如表1所示,自我注意层使用恒定数量的顺序执行的操作连接所有位置,而循环层需要 O ( n ) O(n) O(n)个顺序操作。

表1

就计算复杂度而言,当序列长度 n n n小于表示维数 d d d时,自注意层比递归层块,这是机器翻译中最先进的模型使用句子表示的最常见情况,例如词段(word-piece)[38]和字节对(byte-pair)[31]表示形式。为了提高涉及非常长序列的任务的计算性能,可以将自我注意力限制为仅考虑输入序列中以各个输出位置为中心的大小为r的邻域。这会将最大路径长度增加到 O ( n / r ) O(n/r) O(n/r)。我们计划在今后的工作中进一步研究这一方法。

具有核宽度 k < n k<n k<n的单个卷积层不连接所有的输入和输出位置对。这样做在连续核的情况下需要 O ( n / k ) O(n/k) O(n/k)卷积层的堆栈,或者在扩张卷积的情况下需要 O ( l o g k ( n ) ) O(log_k(n)) O(logk(n))的堆栈,从而增加网络中任意两个位置之间的最长路径的长度。卷积层通常比递归层昂贵 k k k倍。然而,可分离卷积[6]将复杂度大大降低到 O ( k ⋅ n ⋅ d + n ⋅ d 2 ) O(k\cdot n\cdot d + n \cdot d^2) O(knd+nd2)。然而,即使在 k = n k=n k=n的情况下,可分离卷积的复杂度也等于自注意层和逐点前馈层的组合,也就是我们在模型中采用的方法。

作为附带的好处,自注意机制可以产生更多可解释的模型。我们检查了我们的模型中的注意力分布,并在附录中给出并讨论了实例。个体注意力头不仅清楚地学会执行不同的任务,而且许多人似乎表现出与句子的句法和语义结构相关的行为。


5. 训练

本节描述我们的模型的训练机制。

5.1 训练数据和批处理

我们在标准的WMT 2014英语-德语数据集上进行了训练,该数据集由大约450万个句子对组成。句子使用字节对编码[3],它具有大约37000个标记的共享源目标词汇表。对于英语-法语,我们使用了大得多的WMT2014年英法数据集,包括3600万个句子和拆分成32000个词条的词汇表[38]。句子对按近似序列长度成批排列在一起。每个训练批次包含一组句子对,其中包含大约25000个源标记和25000个目标标记。

5.2 硬件和时间表

我们在一台配备8个NVIDIA P100 GPU的机器上训练我们的模型。对于使用本文所述的超参数的基本模型,每个训练步骤大约需要0.4秒。 我们对基本模型进行了总共100,000步或12个小时的训练。 对于我们的大型模型(如表3的底行所述),步长为1.0秒。 大型模型接受了300,000步(3.5天)的训练。

5.3 优化器

我们使用Adam优化器,其中 β 1 = 0.9 , β 2 = 0.98 , ϵ = 1 0 − 9 \beta_1=0.9,\beta_2=0.98,\epsilon=10^{-9} β1=0.9,β2=0.98,ϵ=109。我们在训练过程中根据公式改变学习率。

l r a t e = d m o d e l − 0.5 ⋅ m i n ( s t e p n u m − 0.5 , s t e p n u m ⋅ w a r m u p s t e p s − 1.5 ) lrate=d_{model}^{-0.5}\cdot min(step_num^{-0.5},step_num\cdot warmup_steps^{-1.5}) lrate=dmodel0.5min(stepnum0.5,stepnumwarmupsteps1.5)(3)

这对应于线性增加第一个 w a r m u p s t e p s warmup_steps warmupsteps训练步骤的学习速率,此后将其与步数的平方根的倒数成比例地降低。我们使用 w a r m u p s t e p s = 4000 warmup_steps=4000 warmupsteps=4000

5.4 正则化

我们在训练期间采用了三种类型的正规化:

Residual Dropout 我们将Dropout[33]应用于每个子层的输出,然后将其添加到子层输入并进行规格化(normalized)。此外,我们对编码器和解码器堆栈中的嵌入和位置编码的总和应用了dropout。对于基本模型,我们使用 P d r o p P_{drop} Pdrop的比率。

Label Smoothing 在训练过程中,我们采用值 ϵ l s = 0.1 \epsilon_{ls}=0.1 ϵls=0.1的标签平滑处理。随着模型变得更加不确定,这会减轻困惑(perplexity),但会提高准确性和BLEU得分。


6. 结果

6.1 机器翻译

在WMT 2014英德翻译任务中,big transformer模型(表2中的transformer(big))比之前报告的最佳模型(包括集成)的表现超过2.0 BLEU,新的最新BLEU分数为28.4。

表2

表3的底部列出了该模型的配置。

表3
训练时间为3.5天,使用8个P100 gpu。甚至我们的基础模型也超过了所有以前发布的模型和集成,而训练成本只是任何竞争模型的一小部分。

在2014年的WMT英法翻译任务中,我们的大模型获得了41.0的BLEU评分,超过了之前发布的所有单个模型,花费不到之前最先进模型的1/4的训练成本。接受英法双语培训的Transformer (big)模型使用的dropout率 P d r o p = 0.1 P_{drop}= 0.1 Pdrop=0.1,而不是0.3。

对于基本模型,我们使用通过平均最近5个检查点(以10分钟为间隔编写)获得的单个模型。对于大型模型,我们平均了最后20个检查点。我们使用beam search,beam大小为4,长度惩罚 α = 0.6 \alpha=0.6 α=0.6[38]。这些超参数是在开发集上进行实验后选择的。我们在推断过程中将最大输出长度设置为输入长度+50,但在可能的情况下提前终止[38]。

表2总结了我们的结果,并将我们的翻译质量和训练成本与文献中的其他模型体系结构进行了比较。我们通过乘以训练时间、使用的GPU数量和每个GPU的持续单精度浮点容量的估计值来估计用于训练模型的浮点运算的数量。

6.2 模型变量

为了评估Transformer不同组件的重要性,我们以不同的方式改变了基本模型,并在newstest2013开发集上测量了英译德性能的变化。如上一节所述,我们使用了波束搜索,但是没有检查点平均。 我们在表3中列出了这些结果。

在表3中的行(A)中,我们改变了注意头的数量以及注意key和value的大小,使计算量保持不变,如3.2.2节中所述。尽管单头注意比最佳设置差0.9 BLEU,但过多的头也会降低质量。

在表3行(B)中,我们观察到降低注意力的key的大小 d k d_{k} dk会降低模型质量。这表明,确定兼容性是不容易的,一个比点积更复杂的兼容性函数可能是有益的。我们在©和(D)行中进一步观察到,正如预期的那样,越大的模型越好,并且dropout对于避免过拟合非常有帮助。在第(E)行中,我们用习得的位置嵌入[9]代替正弦位置编码,并观察到与基本模型几乎相同的结果。

6.3 英语选区分析

为了评估Transformer是否可以推广到其他任务,我们进行了英语选民分析的实验。这项任务提出了一些具体的挑战:输出受到强大的结构约束,并且比输入要长得多。此外,RNN序列到序列模型还不能在小数据区域中获得最先进的结果[37]。

我们在《华尔街日报》(Wall Street Journal)的Penn Treebank[25]部分训练了一个 d m o d e l = 1024 d_{model}=1024 dmodel=1024的4层Transformer,大约4万个训练句子。我们还在半监督环境下对其进行了训练,使用了来自大约1700万个句子的较大的高置信度和Berkley Parser语料库[37]。对于WSJ Only设置,我们使用了16K个标记的词汇表;对于半监督设置,我们使用了32K个标记的词汇表。

我们仅进行了少量实验来选择第22节开发集上的dropout,注意力和残差(第5.4节),学习率和波束大小,所有其他参数在英语到德语基础翻译模型中均保持不变。在推断过程中,我们将最大输出长度增加到输入长度+300。对于“华尔街日报”和半监督设置,我们都使用了束大小为21且 α = 0.3 \alpha=0.3 α=0.3的设置。

我们在表4中的结果显示,尽管缺乏特定于任务的调优,但我们的模型执行得出奇地好,产生的结果比之前报道的所有模型都要好,除了递归神经网络语法[8]。

表4

与RNN序列到序列模型[37]相比,即使只在40K句子的WSJ训练集上进行训练,Transformer的性能也要优于BerkeleyParser[29]。


7. 总结

在这项工作中,我们提出了第一个完全基于注意的序列转换模型Transformer,用多头自我注意取代了编解码器结构中最常用的递归层。

对于转换任务,Transformer的训练速度比基于递归或卷积层的架构要快得多。在2014年WMT英法翻译任务和2014年WMT英法翻译任务中,我们都达到了一个新的水平。在前一个任务中,我们的最佳模型甚至优于所有先前报告的集成。

我们对基于注意力的模型的未来感到兴奋,并计划将其应用于其他任务。 我们计划将“Transformer”扩展到涉及文本以外的涉及输入和输出方式的问题,并研究局部受限的注意机制,以有效处理大型输入和输出,例如图像,音频和视频。 使世代相继减少是我们的另一个研究目标。

我们用来训练和评估模型的代码位于:https://github.com/tensorflow/tensor2tensor


注意力可视化

图3

在第5层(共6层)中的编码器自我注意中遵循长距离依赖关系的注意机制的示例。许多注意力集中在动词“make”的遥远依赖关系上,完成了短语“make……more difficult”。注意这里只显示了“make”这个词。不同的颜色代表不同的头。最好用彩色观看。

图4

两个注意头,也在第5层或第6层,显然涉及回指消解。上图:5号头全神贯注。下图:将注意力从“it”这个词中分离出来,表示注意头5和6。请注意,这个词的关注度非常高。

图5

许多注意头表现出的行为似乎与句子的结构有关。我们在上面给出了两个这样的例子,分别来自编码器第6层的第5层自我注意的两个不同的头。这两个头清楚地学会了执行不同的任务。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值