第十四课.Transformer


谷歌的Transformer模型最早是用于机器翻译任务,当时达到了SOTA效果。Transformer改进了RNN最被人诟病的训练慢的缺点,利用self-attention机制实现快速并行。并且Transformer可以增加到非常深的深度,充分发掘DNN模型的特性,提升模型准确率;Transformer由论文 《Attention is All You Need》提出,现在被广泛应用于NLP的各个领域。目前在NLP各业务全面发展的模型如GPT,BERT等,都是基于Transformer模型

Seq2Seq的编码器-解码器架构与Attention机制

首先,关于Seq2Seq的Encoder-Decoder模型与Luong Attention机制原理及实现可回顾 第十二课Seq2Seq与Attention

Encoder-Decoder模型本质是两个循环神经网络(一般使用GRU)进行连接;假设现在有一个Seq元组:一句英文,一句中文,句子已经分词处理过,令 x x x表示英语的分词, y y y表示中文的分词,既有:
( x , y ) : [ x 1 , x 2 , x 3 ] ∣ [ y 1 , y 2 , y 3 , y 4 ] (x,y):[x_{1},x_{2},x_{3}]|[y_{1},y_{2},y_{3},y_{4}] (x,y):[x1,x2,x3][y1,y2,y3,y4]
按照Seq2Seq的一般处理格式,会构造 ( x 1 , x 2 , x 3 , y 1 ) (x_{1},x_{2},x_{3},y_{1}) (x1,x2,x3,y1)为输入数据, ( y 2 , y 3 , y 4 ) (y_{2},y_{3},y_{4}) (y2,y3,y4)为标签;

Encoder-Decoder的网络结构如下:
fig100
上述结构中,Encoder的初始输入 hidden state: h 0 h_{0} h0 可使用零向量,Decoder输出的预测结果为 ( y p 2 , y p 3 , y p 4 ) (yp_{2},yp_{3},yp_{4}) (yp2,yp3,yp4),对比标签数据 ( y 2 , y 3 , y 4 ) (y_{2},y_{3},y_{4}) (y2,y3,y4),机器翻译问题即转为普通的分类任务;Decoder其实是一个语言模型,利用当前中文分词,顺序预测后面的中文分词;

早期Attention机制通常有Bahdanau Attention与Luong Attention,两种注意力的理论相似,Luong Attention使用更加广泛。通常Attention会结合原始Encoder和原始Decoder的输出,重新整合得到新的输出:
fig200
网络的Encoder输出为序列 o s o_{s} os(每个元素是一个词向量),原始Decoder输出序列为 o c o_{c} oc,经过Luong Attention整合信息得到输出 y p yp yp

以机器翻译(英文到中文)为例,在原始的Encoder-Decoder模型里,英文句子的信息被压缩在Encoder的输出 hidden state 里,这不可避免的造成大量信息损失,对翻译中文不利,引入注意力后,给原始Decoder的某个输出词向量融合了其对应的重要英文分词信息,能提升翻译出该中文分词的准确性;

注意力机制的本质是更针对性实现特征提取,即加权平均,发展至今,注意力也有了不同的分类;

柔性注意力 Soft Attention

输入信息 X = [ x 1 , x 2 , . . . , x N ] X=[x_{1},x_{2},...,x_{N}] X=[x1,x2,...,xN],注意力计算过程如下:

  • 1.在输入信息上计算注意力分布;
  • 2.根据注意力分布计算输入信息的加权平均;

注意力分布
给定一个和任务相关的查询向量 q q q,用注意力变量 z ∈ [ 1 , N ] z\in [1,N] z[1,N] 表示被选择信息的索引位置,即 z = i z=i z=i 表示选择了第 i i i 个输入信息,其中查询向量 q q q 可以是动态生成的,也可以是可学习的参数;通常在Seq2Seq中,查询向量会使用当前模型的输出信息(比如Encoder-Decoder当前输出词对应的词向量);

在给定输入信息 X X X 和查询向量 q q q 后,选择第 i i i 个输入信息的概率:
a i = P ( z = i ∣ X , q ) = s o f t m a x ( s c o r e ( x i , q ) ) = e x p ( s c o r e ( x i , q ) ) ∑ j = 1 N e x p ( s c o r e ( x j , q ) ) a_{i}=P(z=i|X,q)=softmax(score(x_{i},q))=\frac{exp(score(x_{i},q))}{\sum_{j=1}^{N}exp(score(x_{j},q))} ai=P(z=iX,q)=softmax(score(xi,q))=j=1Nexp(score(xj,q))exp(score(xi,q))
其中, a i a_{i} ai 称为注意力分布,反映提取信息 x i x_{i} xi 的程度, s c o r e ( x i , q ) score(x_{i},q) score(xi,q) 为注意力打分函数;

打分函数有不同的形式:

  • 加性模型
    s c o r e ( x i , q ) = v T t a n h ( W x i + U q ) score(x_{i},q)=v^{T}tanh(Wx_{i}+Uq) score(xi,q)=vTtanh(Wxi+Uq)
  • 点积模型(常用)
    s c o r e ( x i , q ) = x i T q score(x_{i},q)=x_{i}^{T}q score(xi,q)=xiTq
  • 缩放点积模型(常用)
    s c o r e ( x i , q ) = x i T q d score(x_{i},q)=\frac{x_{i}^{T}q}{\sqrt{d}} score(xi,q)=d xiTq
  • 双线性模型
    s c o r e ( x i , q ) = x i T W q score(x_{i},q)=x_{i}^{T}Wq score(xi,q)=xiTWq

其中, [ W , U , v ] [W,U,v] [W,U,v]为待学习参数, d d d 为输入信息的维度。点积模型的计算效率更高,当输入信息 x i x_{i} xi 的维度维度 d d d 较大,可以通过缩放点积平衡数值。注意力分布可解释为在给定查询向量下,第 i i i 个信息的受关注程度;

加权平均
基于注意力分布和输入信息,得到:
a t t n ( X , q ) = ∑ i = 1 N a i x i attn(X,q)=\sum_{i=1}^{N}a_{i}x_{i} attn(X,q)=i=1Naixi
即:
fig2
在软注意力中,输入信息一方面要用于计算注意力,另一方面是被注意力提取的对象,这对输入信息来说,负担过重。因此,提出了键值对注意力;

键值对注意力 Key-Value Pair Attention

输入信息为:
( K , V ) = [ ( k 1 , v 1 ) , ( k 2 , v 2 ) , . . . , ( k N , v N ) ] (K,V)=[(k_{1},v_{1}),(k_{2},v_{2}),...,(k_{N},v_{N})] (K,V)=[(k1,v1),(k2,v2),...,(kN,vN)]
其中,键用于计算注意力分布 a i a_{i} ai,值用来计算聚合信息,通常值 V V V 即为输入信息 X X X K K K 对应的信息不固定,只要是和 V V V 有关系的对象均可以做为 K K K
给定查询向量 q q q ,注意力分布为:
a i = e x p ( s c o r e ( k i , q ) ) ∑ j = 1 N e x p ( s c o r e ( k j , q ) ) a_{i}=\frac{exp(score(k_{i},q))}{\sum_{j=1}^{N}exp(score(k_{j},q))} ai=j=1Nexp(score(kj,q))exp(score(ki,q))
加权平均:
a t t n ( ( K , V ) , q ) = ∑ i = 1 N a i v i attn((K,V),q)=\sum_{i=1}^{N}a_{i}v_{i} attn((K,V),q)=i=1Naivi
K = V K=V K=V 时,键值对注意力就是柔性注意力;

自注意力 Self-Attention

在键值对注意力中,有两个量 ( K , q ) (K,q) (K,q)比较模糊,没有一个统一的标准,于是提出自注意力机制,输入序列为:
X = [ x 1 , x 2 , . . . , x N ] ∈ R d 1 × N X=[x_{1},x_{2},...,x_{N}]\in R^{d_{1}\times N} X=[x1,x2,...,xN]Rd1×N
输出序列为:
H = [ h 1 , h 2 , . . . , h N ] ∈ R d 2 × N H=[h_{1},h_{2},...,h_{N}]\in R^{d_{2}\times N} H=[h1,h2,...,hN]Rd2×N
通过线性变换得到向量序列:
Q = W Q X ∈ R d 3 × N Q=W_{Q}X\in R^{d_{3}\times N} Q=WQXRd3×N
K = W K X ∈ R d 3 × N K=W_{K}X\in R^{d_{3}\times N} K=WKXRd3×N
V = W V X ∈ R d 2 × N V=W_{V}X\in R^{d_{2}\times N} V=WVXRd2×N
其中, [ Q , K , V ] [Q,K,V] [Q,K,V] 分别为查询向量,键向量,值向量; [ W Q , W K , W V ] [W_{Q},W_{K},W_{V}] [WQ,WK,WV]为待学习参数;

预测输出向量:
h ^ i = a t t n ( ( K , V ) , q i ) = ∑ j = 1 N a i , j v j = ∑ j = 1 N s o f t m a x ( s c o r e ( k j , q i ) ) v j \widehat{h}_{i}=attn((K,V),q_{i})=\sum_{j=1}^{N}a_{i,j}v_{j}=\sum_{j=1}^{N}softmax(score(k_{j},q_{i}))v_{j} h i=attn((K,V),qi)=j=1Nai,jvj=j=1Nsoftmax(score(kj,qi))vj
当使用缩放点积打分时,输出向量序列为:
H d 2 × N = W V X s o f t m a x ( K T Q d 3 , a x i s = − 1 ) H_{d_{2}\times N}=W_{V}Xsoftmax(\frac{K^{T}Q}{\sqrt{d_{3}}},axis=-1) Hd2×N=WVXsoftmax(d3 KTQ,axis=1)


pytorch 中softmax函数举例:

import torch
import torch.nn as nn

mat=torch.randn(2,2)
print(mat,mat.size())
softmax=nn.Softmax(dim=1)
output=softmax(mat)
print(output,output.size())

"""
tensor([[ 0.0081,  0.1971],
        [-0.2666, -1.0529]]) torch.Size([2, 2])
tensor([[0.4529, 0.5471],
        [0.6870, 0.3130]]) torch.Size([2, 2])
"""

axis=-1dim=-1,即在最后一维上操作,在(2,2)的张量上,体现为沿着列轴计算softmax:
0.4529 = e x p ( 0.0081 ) e x p ( 0.0081 ) + e x p ( 0.1971 ) 0.4529=\frac{exp(0.0081)}{exp(0.0081)+exp(0.1971)} 0.4529=exp(0.0081)+exp(0.1971)exp(0.0081)


多头注意力 Multi-Head Attention

多头注意力起源于自注意力,多头注意力为:
a t t n ( X ) = a t t n ( ( K 1 , V 1 ) , Q 1 ) ⊕ a t t n ( ( K 2 , V 2 ) , Q 2 ) ⊕ . . . ⊕ a t t n ( ( K h , V h ) , Q h ) attn(X)=attn((K_{1},V_{1}),Q_{1})\oplus attn((K_{2},V_{2}),Q_{2})\oplus ...\oplus attn((K_{h},V_{h}),Q_{h}) attn(X)=attn((K1,V1),Q1)attn((K2,V2),Q2)...attn((Kh,Vh),Qh)
其中的 ⊕ \oplus 表示张量拼接,多头注意力相当于给出了注意力层的多个"表示空间",即融合了不同角度的自注意力信息;

Transformer通用特征提取器

Transformer是一种架构,目的是用于实现一种通用的特征提取器。模型架构如下:
fig1
模型有两个输入,一个输出,左部被称为编码器,右部被称为解码器。左边的输入为源序列,右边输入为目标序列,目标序列是一个固定长度的输入序列;

图中的 N × N\times N× 表示网络的堆叠,图中的灰色部分表示一层单元(比如左边的Encoder单元和右边的Decoder单元),加深网络可以通过重复堆叠单元实现。

输入,目标,输出序列

输入序列, i q ∈ R S o u r c e V o c a b S i z e i_{q}\in R^{SourceVocabSize} iqRSourceVocabSize反映了该词在词汇表中的序号(one-hot编码)
i n p u t s = [ i 1 , i 2 , . . . , i N ] inputs=[i_{1},i_{2},...,i_{N}] inputs=[i1,i2,...,iN]
目标序列, t q ∈ R T a r g e t V o c a b S i z e t_{q}\in R^{TargetVocabSize} tqRTargetVocabSize反映了该词在词汇表中的序号(one-hot编码)
t a r g e t s = [ t 1 , t 2 , . . . , t M ] targets=[t_{1},t_{2},...,t_{M}] targets=[t1,t2,...,tM]
其中还有
o u t p u t s p r o b a b i l i t i e s = T r a n s f o r m e r ( i n p u t s , t a r g e t s ) = ( o 1 , o 2 , . . . , o M ) outputs_{probabilities}=Transformer(inputs,targets)=(o_{1},o_{2},...,o_{M}) outputsprobabilities=Transformer(inputs,targets)=(o1,o2,...,oM)
o u t p u t s p r o b a b i l i t i e s outputs_{probabilities} outputsprobabilities为预测结果, o q ∈ R T a r g e t V o c a b S i z e o_{q}\in R^{TargetVocabSize} oqRTargetVocabSize反映了词汇表中词的概率;

词嵌入与位置信息融合

输入序列词嵌入为:
E m b e d d i n g ( i n p u t s ) ∈ R N , d m o d e l Embedding(inputs)\in R^{N,d_{model}} Embedding(inputs)RN,dmodel
其中, N N N为输入序列长度, d m o d e l d_{model} dmodel为词嵌入维度,输入序列位置编码为:
P o s E n c ( p o s t i o n i n p u t s ) ∈ R N , d m o d e l PosEnc(postion_{inputs})\in R^{N,d_{model}} PosEnc(postioninputs)RN,dmodel
其中, p o s t i o n i n p u t s = ( 1 , 2 , . . . , p , . . . , N ) postion_{inputs}=(1,2,...,p,...,N) postioninputs=(1,2,...,p,...,N) 为各个字符在句子中对应的位置序号;

位置编码计算为:
P o s E n c ( p o s , 2 i ) = s i n ( p o s 1000 0 2 i / d m o d e l ) , P o s E n c ( p o s , 2 i + 1 ) = c o s ( p o s 1000 0 2 i / d m o d e l ) PosEnc(pos,2i)=sin(\frac{pos}{10000^{2i/d_{model}}}),PosEnc(pos,2i+1)=cos(\frac{pos}{10000^{2i/d_{model}}}) PosEnc(pos,2i)=sin(100002i/dmodelpos),PosEnc(pos,2i+1)=cos(100002i/dmodelpos)
其中, p o s ∈ p o s t i o n i n p u t s pos\in postion_{inputs} pospostioninputs i ∈ ( 0 , 1 , . . . , d m o d e l / 2 ) i\in (0,1,...,d_{model}/2) i(0,1,...,dmodel/2)


融合位置信息的目的:注意力机制没有考虑单词的位置信息,而是单纯的加权平均,所以在Transformer中添加了位置信息


将词嵌入与位置信息融合:
E m b e d d i n g ( i n p u t s ) + P o s E n c ( p o s t i o n i n p u t s ) Embedding(inputs)+PosEnc(postion_{inputs}) Embedding(inputs)+PosEnc(postioninputs)
同样的,目标序列也进行对应的融合:
E m b e d d i n g ( t a r g e t s ) + P o s E n c ( p o s t i o n t a r g e t s ) Embedding(targets)+PosEnc(postion_{targets}) Embedding(targets)+PosEnc(postiontargets)

编码器

编码器的计算为:
e 0 = E m b e d d i n g ( i n p u t s ) + P o s E n c ( p o s t i o n i n p u t s ) e_{0}=Embedding(inputs)+PosEnc(postion_{inputs}) e0=Embedding(inputs)+PosEnc(postioninputs)
e l = E n c o d e r L a y e r ( e l − 1 ) , l ∈ [ 1 , n ] e_{l}=EncoderLayer(e_{l-1}),l\in [1,n] el=EncoderLayer(el1),l[1,n]
其中, e 0 ∈ R N , d m o d e l e_{0}\in R^{N,d_{model}} e0RN,dmodel为编码器输入, n n n为编码器层数, e l e_{l} el为第 l l l层编码器的输出;
编码器 E n c o d e r L a y e r EncoderLayer EncoderLayer
e m i d = L a y e r N o r m ( e i n + M u l t i H e a d A t t e n t i o n ( e i n ) ) e_{mid}=LayerNorm(e_{in}+MultiHeadAttention(e_{in})) emid=LayerNorm(ein+MultiHeadAttention(ein))
e o u t = L a y e r N o r m ( e m i d + F F N ( e m i d ) ) e_{out}=LayerNorm(e_{mid}+FFN(e_{mid})) eout=LayerNorm(emid+FFN(emid))
其中, e i n ∈ R N , d m o d e l e_{in}\in R^{N,d_{model}} einRN,dmodel为编码器层输入, e o u t ∈ R N , d m o d e l e_{out}\in R^{N,d_{model}} eoutRN,dmodel为编码器层输出, M u l t i H e a d A t t e n t i o n MultiHeadAttention MultiHeadAttention为多头注意力机制, F F N FFN FFN为前馈神经网络, L a y e r N o r m LayerNorm LayerNorm为层归一化;


图中的多头注意力机制输入有三条支路,代表了三个待学习参数 [ W Q , W K , W V ] [W_{Q},W_{K},W_{V}] [WQ,WK,WV]


关于Transformer的缩放点积和多头注意力机制:
fig3
注意左图的 [ Q , K , V ] [Q,K,V] [Q,K,V]是右图 [ Q , K , V ] [Q,K,V] [Q,K,V]经过线性变换得到的;

输入向量序列 e i n = [ e i n 1 , e i n 2 , . . . , e i n N ] ∈ R N , d m o d e l e_{in}=[e_{in1},e_{in2},...,e_{inN}]\in R^{N,d_{model}} ein=[ein1,ein2,...,einN]RN,dmodel,分别得到查询向量序列 Q = e i n Q=e_{in} Q=ein,键向量序列 K = e i n K=e_{in} K=ein,值向量序列 V = e i n V=e_{in} V=ein

使用缩放点积打分的多头注意力机制:
M u l t i H e a d A t t e n t i o n ( e i n ) = C o n c a t ( h e a d 1 , . . . , h e a d h ) W O MultiHeadAttention(e_{in})=Concat(head_{1},...,head_{h})W_{O} MultiHeadAttention(ein)=Concat(head1,...,headh)WO
其中,多头输出:
h e a d i = A t t e n t i o n ( Q W Q , i , K W K , i , V W V , i ) = s o f t m a x ( Q W Q , i ( K W K , i ) T d K ) V W V , i head_{i}=Attention(QW_{Q,i},KW_{K,i},VW_{V,i})=softmax(\frac{QW_{Q,i}(KW_{K,i})^{T}}{\sqrt{d_{K}}})VW_{V,i} headi=Attention(QWQ,i,KWK,i,VWV,i)=softmax(dK QWQ,i(KWK,i)T)VWV,i
可学习的参数为:
[ W Q , i ∈ R d m o d e l , d K , W K , i ∈ R d m o d e l , d K , W V , i ∈ R d m o d e l , d V , W O ∈ R h ⋅ d V , d m o d e l ] [W_{Q,i}\in R^{d_{model},d_{K}},W_{K,i}\in R^{d_{model},d_{K}},W_{V,i}\in R^{d_{model},d_{V}},W_{O}\in R^{h\cdot d_{V},d_{model}}] [WQ,iRdmodel,dK,WK,iRdmodel,dK,WV,iRdmodel,dV,WORhdV,dmodel]


Mask操作可以省略,Mask操作是为了保留非填充(pad)的词


前馈神经网络为全连接网络,两层网络如下:
F F N ( e m i d ) = R e L U ( e m i d W 1 + b 1 ) W 2 + b 2 FFN(e_{mid})=ReLU(e_{mid}W_{1}+b_{1})W_{2}+b_{2} FFN(emid)=ReLU(emidW1+b1)W2+b2

解码器

d 0 = E m b e d d i n g ( t a r g e t s ) + P o s E n c ( p o s t i o n t a r g e t s ) d_{0}=Embedding(targets)+PosEnc(postion_{targets}) d0=Embedding(targets)+PosEnc(postiontargets)
d l = D e c o d e r L a y e r ( d l − 1 ) , l ∈ [ 1 , n ] d_{l}=DecoderLayer(d_{l-1}),l\in [1,n] dl=DecoderLayer(dl1),l[1,n]
o u t p u t s p r o b a b i l i t i e s = s o f t m a x ( d n W ) outputs_{probabilities}=softmax(d_{n}W) outputsprobabilities=softmax(dnW)
其中, d 0 ∈ R M , d m o d e l d_{0}\in R^{M,d_{model}} d0RM,dmodel为解码器的输入, d l ∈ R M , d m o d e l d_{l}\in R^{M,d_{model}} dlRM,dmodel为解码器第 l l l层的输出, W ∈ R d m o d e l , T a r g e t V o c a b S i z e W\in R^{d_{model},TargetVocabSize} WRdmodel,TargetVocabSize

解码器层 D e c o d e r L a y e r DecoderLayer DecoderLayer
d m i d 1 = L a y e r N o r m ( d i n + M a s k e d M u l t i H e a d A t t e n t i o n ( d i n ) ) d_{mid1}=LayerNorm(d_{in}+MaskedMultiHeadAttention(d_{in})) dmid1=LayerNorm(din+MaskedMultiHeadAttention(din))
d m i d 2 = L a y e r N o r m ( d m i d 1 + M u l t i H e a d A t t e n t i o n ( d m i d 1 , e o u t ) ) d_{mid2}=LayerNorm(d_{mid1}+MultiHeadAttention(d_{mid1},e_{out})) dmid2=LayerNorm(dmid1+MultiHeadAttention(dmid1,eout))
d o u t = L a y e r N o r m ( d m i d 2 + F F N ( d m i d 2 ) ) d_{out}=LayerNorm(d_{mid2}+FFN(d_{mid2})) dout=LayerNorm(dmid2+FFN(dmid2))
其中, d i n ∈ R M , d m o d e l d_{in}\in R^{M,d_{model}} dinRM,dmodel为解码器输入, d o u t ∈ R M , d m o d e l d_{out}\in R^{M,d_{model}} doutRM,dmodel为解码器输出;

由于解码器的目标序列是逐步向后移动的固定长度输入,在预测当前序列时,使用 M a s k e d M u l t i H e a d A t t e n t i o n MaskedMultiHeadAttention MaskedMultiHeadAttention可以遮挡住当前输入中文数据内,目标序列以外的信息,确保当前计算所输入的目标序列是我们确实需要的信息。


M a s k e d M u l t i H e a d A t t e n t i o n MaskedMultiHeadAttention MaskedMultiHeadAttention用于训练,因为训练是已知中文序列的,而翻译只有英文序列,所以不需要mask操作,使用中文逐个作为输入序列依次翻译即可;


训练与翻译

假设有一个英文与中文元组:

"""
(['BOS', 'why', 'me', 'EOS'],
 ['BOS', '为', '什', '么', '是', '我', 'EOS'])
"""

对于Encoder-Decoder,或结合Luong Attention的Encoder-Decoder,都有训练格式如下:

  • 英文部分的输入为:BOS why me EOS
  • 中文部分的输入为:BOS 为 什 么 是 我
  • 标签为:为 什 么 是 我 EOS

翻译时:

  • 英文序列作为输入;
  • 模型固定为逐次调用以输出 max seq len 个词向量;
  • 将标志符号BOS作为中文的第一个分词,结合英文输入,得到第一个输出词向量,再将该词向量作为新的中文输入词向量,因此,可以依次得到一组输出词向量(一共 max seq len 个),每个词向量经过全连接映射得到one-hot编码,即得到输出的中文分词列表;
  • 顺着列表检查分词,如果出现标志符号EOS就截取前面的分词组成中文结果。

对于Transformer,如果设置目标序列长度固定为3,则输入的中文序列与对应标签依次为:

  • 输入中文BOS 为 什,标签为 什 么
  • 输入中文为 什 么,标签什 么 是
  • 输入中文什 么 是,标签么 是 我
  • 输入中文么 是 我,标签是 我 EOS

通常,每次设置目标序列长度为中文序列长度减1,该情况下的训练格式与Encoder-Decoder相同,mask操作只需遮挡中文序列最后一个元素EOS即可;

Transformer的翻译过程与Encoder-Decoder一致

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值