循环神经网络和LSTM模型

本文详细介绍了循环神经网络(RNN)的基本原理,指出RNN在处理序列问题时存在梯度消失和梯度爆炸的问题。为解决这些问题,文章引入了长短期记忆网络(LSTM)模型,通过门控机制来处理长期依赖问题,同时分析了LSTM的结构和计算过程。此外,还讨论了LSTM在文本分类和图像识别等任务中的应用以及与CNN的结合使用,如LSTM-CNN模型。最后,提到了CTC算法在手写体多字符识别中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(由于平台稿件格式问题,公式格式不能正确写上;如若读写困难可评论区留言获取完整电子版)

1.1 循环神经网络模型详解

1.1.1 循环神经网络的基本原理

在本书前面讨论过的模型中,无论是简单的逻辑回归,还是复杂的DNN、CNN等,都是在单个样本上进行分类的,也就是说,样本之间缺乏联系。例如,在使用CNN进行手写体字符识别时,仅有单个字符的图像输入,没有字符前后的内容。然而,在语音处理、自然语言处理等领域,样本之间的时序关系是非常重要的,类别之间在时序上有很强的关联性。

随着深度学习理论和工程的发展,越来越多的自然语言处理场景开始使用深度学习模型代替传统模型来处理日益复杂的业务需求。例如,快递公司在进行地址解析时,需要对字符串中的每个词是否为地址进行判断。为了简化任务,模型通常会假设已经完成分词,这样,分类任务就是输入一个词,返回的类别将是“地址”“非地址”两类,示例如下。

我 住 在 朝阳区 苹果 社区

分类器(Classifier,例如逻辑回归、SVM、DNN)需要完成的任务是计算以下式子。

classifier(我)=?

classifier(住)=?

classifier(在)=?

classifier(朝阳区)=?

classifier(苹果)=?

classifier(社区)=?

在上述式子中,每个词都对应于一个embedding,这一点和Word2vec无异。分类器有多种选型,这些选型可以是传统的逻辑回归、SVM,也可以是流行的DNN、CNN。每种选型都有配套的参数,通过标注数据学习模型的参数和词的embedding。

分类器学习完成后,我们就可以用它来计算输入样本属于各个类别的得分了。因为在绝大多数场景中,“朝阳区”都是作为地址出现的,所以,训练样本中的大多数“朝阳区”将被标注成地址,classifier(朝阳区)=“地址” 的可能性较大,即得分较高。同理,classifier(我)

=“非地址” 的得分较高。

问题貌似很简单。不过,难点来了——classifier(苹果) 会是什么样的结果呢?在大多数语料中,“苹果”都不太可能对应于地点,因此在这里有很大的可能将 classifier(苹果) 判断为“非地址”,而这个结果显然是错误的。在本例中,“苹果”应该是一个地名,就像北京的“苹果园”一样。

我们分析一下造成这个问题的原因。无论是逻辑回归还是DNN,在对一个词进行类别判断时,都只使用这个词本身的信息。但是,在很多场景中,只有词本身的信息是不够的,如果不对分类器输入新的信息,就很难通过调整模型参数来解决问题。

大多数人工智能工具都会借鉴人类的思考方式。我们先想想看人类是如何解决这个问题的——对,就是上下文。人类在阅读文本时,除了看当前词,还会看上下文,当一个词的前后两个词都是地址时,这个词就八九不离十是地址了。在这里,我们给上一时刻的输出结果乘以一个待学习参数 k,作为下一时刻的输入,公式如下。

y^' (t)=classifier(x(t),ky^' (t-1))

以上模型,如图13-1所示。

图13-1

为了形象地理解这个问题,我们假设分类模型是全连接神经网络,x(t) 为 t 时刻的词所对应的embedding。不考虑前一时刻的输出结果,公式如下。

y^' (t)=f(Ux(t)+u_0 )

U 和 u_0 都是待学习参数。f 为Sigmoid函数。该模型为逻辑回归。

当模型考虑上下文时,会将前一时刻的输出结果注入模型。因此,可以给以上模型添加一些东西,写成下式。

y^' (t)=f(Ux(t)+ky^' (t-1)+u_0 )

y^' (t-1) 为前一时刻的输出。k 为待学习参数,用于控制前一时刻的结果对当前时刻分类的影响。

在大多数时候,直接将前一时刻的输出作为当前时刻的一个输入,并不是特别合适的。尽管我们需要前一时刻的信息,但我们不希望完全使用前一时刻的输出。为了满足这个需求,要对分类模型进行改造。

首先,将分类器由逻辑回归改造成单层神经网络,公式如下。

h(t)=g(Ux(t)+u_0 )

y^' (t)=f(Vh(t)+v_0 )

因为网络是单层神经网络,梯度消失问题不明显,所以 g 一般使用输出信息更为丰富的Tanh作为激活函数。当预测目标为二分类时,f 为Sigmoid函数。当预测目标为多分类时,f 为Softmax函数。

接着,将中间层 h(t) 作为下一时刻 t+1 的另一个输入。h(t) 称为状态向量。因为状态向量存在于模型这个“黑盒”中,外界不知道它的存在,所以,状态向量是被隐藏的。

根据以上分析,对模型进行细微的改造,公式如下,结果如图13-2所示。

h(t)=f(Ux(t)+Wh(t-1)+u_0 )

y^' (t)=g(Vh(t)+v_0 )

图13-2

可以看出,h(t) 包含当前时刻的输入 x(t) 和过往时刻的信息 h(t-1)。在每个时刻,待学习参数 U、W、V、u_0、v_0 为同一套参数,即在所有时刻参数是共享的。参数共享的好处在于能够减少参数数量:如果每个时刻都对应于一套参数,那么随着序列的增长,参数数量将越来越多。在序列问题中,往往对绝对位置 t 不敏感,因此,共享参数也符合常见任务的特点。

状态 h(t) 所对应的激活函数 f 可以是ReLU、Sigmoid、Tanh等非线性函数,一般建议使用Tanh函数。Tanh函数的输出范围为 (-1,+1),能够提供的信息比Sigmoid函数、ReLU函数丰富(这些函数没有负输出)。当模型用在分类任务中时,激活函数 g 一般为Sigmoid函数(二分类)或Softmax函数(多分类)。

改造后的模型通常称为循环神经网络(Recurrent Neural Networks,RNN)。将循环神经网络的时序展开,如图13-3所示。

图13-3

由于RNN是一个变长序列,无法保证训练样本长度一致(地址长短不一),所以无法进行批标准化。在RNN中一般使用层标准化,即对 h(1),⋯,h(t) 分别进行标准化。

RNN在处理时序信号时展现了强大的能力,它会借鉴输入的上下文信息来完成分类任务,因此特别适合在语音处理、自然语言处理等场景中使用。

1.1.2 循环神经网络存在的一些问题

模型搭建完成,下一步就是参数学习了。待学习参数包括 U、W、V、u_0、v_0。考虑一个样本 i,当分类为二分类时,有

x_((i))=[x_((i) ) (0),x_((i) ) (1),⋯,x_((i)) (T)]

对应的类别为

y_((i))=[y_((i) ) (0),y_((i) ) (1),⋯,y_((i)) (T)]

损失函数为

Loss_((i))=∑_(t=0)^T▒〖Loss_((i) ) (t)〗=∑_(t=0)^T▒〖-y_((i) ) (t)logy_((i))^' (t)〗-(1-y_((i) ) (t))log(〖1-y〗_((i))^' (t))

其中

h_((i) ) (t)=f(Ux_((i) ) (t)+Wh_((i) ) (t-1)+u_0 )

y_((i))^' (t)=g(Vh_((i) ) (t)+v_0 )

依然使用梯度下降法学习各个参数,公式如下。

〖∂Loss〗_((i))/∂W=∑_(t=0)^T▒〖(∂Loss_((i) ) (t))/(∂y_((i))^' (t)) (∂y_((i))^' (t))/∂W〗

可以看出,y_((i))^' (t) 和 h_((i)) (t) 直接相关,前面的时刻 h_((i)) (t-1)、h_((i)) (t-2) 等都会通过 W 和

U 对 h_((i)) (t) 造成影响,所以,y_((i))^' (t) 与前面各时刻的 W 和 U 都有关(虽然各时刻的 W 和

U 都共享参数,但它们接收的输入都与当前状态有关,因此,对 y_((i))^' (t) 的影响是不同的),如

图13-4所示。

图13-4

我们先分析一下 (∂y_((i))^' (t))/∂W。

为了推导方便,可以进行简化。在激活区,Tanh 函数接近线性变化,因此有

h_((i)) (t)=Tanh(Ux_((i) ) (t)+Wh_((i)) (t-1)+u_0 )≈Ux_((i) ) (t)+Wh_((i)) (t-1)+u_0

(∂y_((i))^' (t))/∂W 要考虑前面各时刻的情况,即

(∂y_((i))^' (t))/∂W=∑_(j=1)^t▒(∂y_((i))^' (t))/(∂h_((i)) (j) ) (h_((i)) (j-1))^T=∑_(j=1)^t▒〖((∂h_((i)) (t))/〖∂(h_((i)) (j))〗^T )^T (∂y_((i))^' (t))/(∂h_((i)) (t) )〗 (h_((i)) (j-1))^T

在上式中,当 j=t-τ 时(前 τ 时刻),(∂h_((i)) (t))/〖∂(h_((i)) (t-τ))〗^T 应该如何求解?因为

h_((i)) (t)≈Ux_((i) ) (t)+Wh_((i)) (t-1)+u_0

(∂h_((i)) (t))/〖∂(h_((i)) (t-1))〗^T =W

使用链式法则,可以得到

(∂h_((i)) (t))/〖∂(h_((i)) (t-τ))〗^T =(∂h_((i)) (t))/〖∂(h_((i)) (t-1))〗^T (∂h_((i)) (t-1))/〖∂(h_((i)) (t-2))〗^T ⋯(∂h_((i)) (t-τ+1))/〖∂(h_((i)) (t-τ))〗^T =W^τ

所以

(∂y_((i))^' (t))/(∂h_((i)) (t-τ) )=((∂h_((i)) (t))/〖∂(h_((i)) (t-τ))〗^T )^T (∂y_((i))^' (t))/(∂h_((i)) (t) )=W^τ (∂y_((i))^' (t))/(∂h_((i)) (t) )

在线性代数中,有一个有趣的结论:

W=P^(-1) ΣP

其中,P 为矩阵的特征向量组成的特征矩阵,P^(-1) P=E,E 为单位矩阵,Σ 为对角线矩阵,对角线元素为 W 所对应的特征值,即

Σ=[■(λ_1&⋯&0@⋮&⋱&⋮@0&⋯&λ_m )]

那么

W^τ=P^(-1) ΣP〖×P〗^(-1) ΣP×⋯×P^(-1) ΣP=P^(-1) Σ^τ P

Σ^τ=[■(λ_1^τ&⋯&0@⋮&⋱&⋮@0&⋯&λ_m^τ )]

(∂y_((i))^' (t))/(∂h_((i)) (t-τ) )=P^(-1) [■(λ_1^τ&⋯&0@⋮&⋱&⋮@0&⋯&λ_m^τ )]P (∂y_((i))^' (t))/(∂h_((i)) (t) )

当矩阵 W 的特征值 λ_k>1 时,λ_k^τ 将是一个特别大的值,且 τ 的值越大(距离 t 时刻

越远),此现象越严重。这将导致 (∂y_((i))^' (t))/(∂h_((i)) (t-τ) ) 是一个非常大的值,显然不利于训练——这就是

梯度爆炸。

当矩阵 W 的特征值 λ_k<1 时,经过若干连乘,λ_k^τ 将是一个趋近于0的值,且 τ 的值

越大(距离 t 时刻越远),此现象越严重。这将导致 (∂y_((i))^' (t))/(∂h_((i)) (t-τ) )≈0,几乎学不到东西——这

就是梯度消失。

只有特征值刚好等于1才能避免上述两个问题,但这几乎不可能实现。

可以看出,当时序过长时,梯度很容易出现要么过大、要么过小的两种极端情况,不利于学到合适的参数。

更复杂的情况是,因为各 λ_k(1 ≤ k ≤ m)是相互独立的,所以会出现 λ_1>1、λ_2<1 的情况,此时,W 将在不同的方向(特征向量的方向)上分别出现梯度消失和梯度爆炸,使问题变得复杂。

如果DNN过深,也会出现梯度消失和梯度爆炸,这主要是激活函数选取不当所致。尽管计算梯度时也涉及多层 W 连乘,但DNN各层使用的 W 是相互独立的,有些层的特征值大,有些层的特征值小,可以抵消。因此,只要激活函数选择得当,那么,即使DNN中存在梯度消失或梯度爆炸的情况,其影响也不如RNN中严重。CNN中也存在参数共享的情况(不同的位置对应于相同的卷积核参数),但共享是在同一层进行的,不涉及自连乘,所以影响也不如RNN中严重。

从前向传播的角度看:λ_k 过小(梯度消失)意味着从当前时刻起对未来的影响力越来越弱;λ_k 过大(梯度爆炸)表示当前时刻的信息会随时间的推移而增强,但新时刻的信息所起的作用将会减弱。这两种情况都是极端的,不利于模型的训练和预测。

1.2 LSTM模型详解

根据13.1节的分析不难看出,RNN不适合处理过长的序列,主要原因如下。

h(t) 会被 Wh(t-1) 影响,求 (∂h_((i)) (t))/〖∂(h_((i)) (t-τ))〗^T 时必然会出现 W 的自连乘,导致梯度消失

或梯度爆炸。

在RNN中,h(t) 首先作为当前状态的输出,它保存了 t 时刻之前的信息。如果在实际业务中,t 时刻之前的信息只影响当前(t 时刻)的输出,则对未来(t+1、t+2 等)时刻不会有影响。但 h(t) 会将它放入未来时刻,这相当于为未来时刻带去噪声。

在 t=1 时刻,输入的信息对 t=10 时刻的分类是非常重要的,但因为它们距离较远(从 h(1) 到 h(10),x(1) 的信息在 h(10) 中已经被中间的多个 W 和 x(2)~x(9) 稀释),所以 x(1) 很难在 h(10) 中得到体现(长距离依赖问题)。

为了解决上述问题,我们引入一个新的状态 c(t) 来专门存储历史信息,h(t) 则用于当前时刻的输出,公式如下。

c(t)=c(t-1)+Tanh⁡(W_C [■(x(t)@h(t-1) )]+b_C )

h(t)=Tanh(c(t))

y^' (t)=g(Vh(t)+v_0 )

c(t) 在 t 时刻通过 Tanh(W_C [■(x(t)@h(t-1) )]+b_C ) 增加当前时刻的输入 x(t) 和上一时刻

的输出 h(t-1) 所提供的信息。

c(t) 用于保存序列的历史信息。可以看出,(∂c(t))/(∂〖c(t-1)〗^T )=I,所以有 (∂c(t))/(∂〖c(t-τ)〗^T )=I,而这与

W_C 无关,从而解决了梯度消失和梯度爆炸问题。

c(t) 通过Tanh函数进行非线性变换,将 h(t) 作为输出。

尽管旧的问题得到了解决,但引入了新的问题。例如,每经历一个时刻,c(t)=c(t-1)+Tanh(W_C [■(x(t)@h(t-1) )]+b_C ) 都会“吃”掉一点新信息 Tanh(W_C [■(x(t)@h(t-1) )]+b_C ),最终

c(t) 的值会非常大,导致 h(t)=Tanh(c(t)) 所对应的Tanh函数达到饱和,而Tanh函数达到饱和的结果是 h(t) 几乎不再变化,其后果是后面的输入 x(t) 几乎不会对 h(t) 产生影响。因此,要给 c(t)“减肥”——给它乘以一个遗忘因子 〖gate〗_forget。这就好比人不可能记得之前发生的所有事情,总会忘掉一些,腾出一部分大脑“空间”,才能记住后面发生的事情。公式如下。

c(t)=〖gate〗_forget.*c(t-1)+Tanh(W_C [■(x(t)@h(t-1) )]+b_C )

其中,〖gate〗_forget 是一个向量,该向量中元素的取值范围为 (0,1)(为0意味着完全忘记过去

的状态,为1意味着对过去的所有状态铭记于心);.* 是指Pointwise卷积操作,表示两个向量按位相乘。

还有改进的空间吗?人类在面对新事物的时候,一般也无法全部记住,而是有选择地记住一部分(将与任务无关的信息丢弃),这样做的好处是能够克服一部分噪声。因此,可以通过给新的信息添加一个门 〖gate〗_in 进行过滤,将模型公式调整如下。

c(t)=〖gate〗_forget.*c(t-1)+〖gate〗_in.*Tanh(W_C [■(x(t)@h(t-1) )]+b_C )

另外,尽管当前模型的输出 h(t)=Tanh(c(t)) 完全由 c(t) 决定,但当前时刻的分类任务并不需要所有的 c(t)。c(t) 的一部分是与当前分类有关的信息,另一部分是与当前时刻分类无关的、只用于传递至未来时刻的状态的信息。因此,也可以通过一个门对隐藏的状态进行过滤,将过滤结果作为输出,公式如下。

h(t)=〖gate〗_out.*Tanh(c(t))

我们引入了三个门(〖gate〗_forget、〖gate〗_in、〖gate〗_out)对信息进行过滤。这三个门都是向量,

向量元素的取值范围都是 (0,1)。那么,具体的数值是多少呢?我们知道,忘记多少、记住多少、对外保留多少都与前一时刻的输出状态 h(t-1) 和当前的输入 x(t) 有关,因此,将这三个门参数化,公式如下。

〖gate〗_forget=σ(W_forget [■(x(t)@h(t-1) )]+b_f )

〖gate〗_in=σ(W_in [■(x(t)@h(t-1) )]+b_in )

〖gate〗_out=σ(W_out [■(x(t)@h(t-1) )]+b_out )

在这里,σ 为Sigmoid函数,值域为 (0,1),用于对信息进行过滤。这三个门的参数也是通过

梯度下降法学习得到的,其过滤强度由 h(t-1)、x(t) 和待学习参数 W_forget 、W_in 、W_out 、b_f 、b_in 、b_out 决定。

大功告成。这就是LSTM(Long Short-Term Memory),它的结构如图13-5所示。

图13-5

整理一下上面的分析内容,LSTM的计算公式如下。

c(t)=〖gate〗_forget.*c(t-1)+〖gate〗_in.*Tanh(W_C [■(x(t)@h(t-1) )]+b_C )

h(t)=〖gate〗_out.*Tanh(c(t))

〖 y〗^' (t)=g(Vh(t)+v_0 )

〖gate〗_forget=σ(W_forget [■(x(t)@h(t-1) )]+b_f )

〖 gate〗_in=σ(W_in [■(x(t)@h(t-1) )]+b_in )

〖gate〗_out=σ(W_out [■(x(t)@h(t-1) )]+b_out )

作为总结,我们复习一下时序神经网络的演化过程,如图13-6所示。

图13-6

LSTM在语音识别、自然语言处理等时序信号场景中有广泛的应用。例如,在中文拼音输入法中,输入是拼音序列,预测结果是相应的汉字,模型如图13-7所示。

图13-7

LSTM可仅以最后一个时刻的输出作为全局特征,从而完成文本分类等任务,如图13-8所示。

图13-8

在机器翻译领域,LSTM也有着广泛的应用。例如,汉译英模型可以使用两个不同的LSTM序列,其中:LSTM1称为编码器(Encoder),它将中文句子编码,并将最后一个状态的输出交给LSTM2作为第一个状态 h(0);LSTM2称为解码器(Decoder),它将前一时刻的预测结果作为后一时刻的输入放入模型,在预测出“<End>”时结束翻译,不再进行解码。LSTM机器翻译模型,如图13-9所示。

图13-9

在一些场景中,不仅前一时刻的信息会传递给后面的时刻,后面时刻的信息也有可能影响前面的分类结果。LSTM可以双向扩展,得到BI-LSTM,其模型如图13-10所示。

图13-10

在这里,两个方向采用不同的LSTM(LSTM1和LSTM2),在输出时将二者的输出向量串联起来。

LSTM除了本章所讲的标准形式,还有GRU等变种,但万变不离其宗,基本原理仍然如本章所述。LSTM的变种只是对门进行了一些改造,本书不再赘述,感兴趣的读者可以自行查阅相关资料。

1.3 LSTM模型的改进和应用

CNN和LSTM都可用于文本分类任务,那么,它们之间有什么区别呢?

CNN在进行1维卷积时,重点捕捉局部特征。例如,在情感分类场景中,对每句话的情感进行“正面”或“负面”的二分类,“不喜欢”这个词组,在以下三句话中都能被CNN捕捉到。

我 不 喜欢 这些 饭菜

我 非常 不 喜欢 这个 人

我 看过 这部 电影,但是 不 喜欢 它 的 结局

显然,如果将CNN作为分类器,那么“不喜欢”这种局部特征会提高分类结果为“负面”的概率。

LSTM在分类时侧重于提取整体特征(特别是当语义集中在句尾时),示例如下。

我 不 喜欢 这家 餐厅 的 位置,但是 满意 它 的 菜

这句话表达的是“正面”的情感,语义集中在句尾。

LSTM具备全局特征提取能力,可以很好地把全局语义提取出来。但是,如果使用CNN对上面这句话进行分类,那么局部信息“不喜欢”会使分类器产生误判。

通过上面的分析可以总结出LSTM和CNN在分类任务上的优缺点。

LSTM:强调全局信息,对局部信息的提取能力较弱。

CNN:能有效地提取局部特征,但“大局观”不足。

鉴于二者各自的特点,目前工业界常常将二者组合使用,其模型称为LSTM-CNN,结构如图13-11所示。

图13-11

该模型先将字符输入LSTM模型,使字符获得一个全局特征,再使用CNN提取局部特征,最后进行分类。

LSTM和CNN还有很多组合方式,近些年也产生了丰硕的研究成果,感兴趣的读者可自行查阅相关资料。

1.4 CTC算法

除了在语音、文字这类天然具有时序特点的场景中可以使用LSTM模型,在图像分类任务中也可以使用LSTM模型。将图像的宽作为时间,将图像的高作为向量,将图像作为时序特征,输入LSTM模型,然后将LSTM最后一个节点的输出作为图像特征输入Softmax函数或Sigmoid函数并进行分类,模型结构如图13-12所示。

图13-12

在图像识别任务中,LSTM和CNN哪个效果更好呢?没有“免费的午餐”——LSTM擅长处理时域信号,因此手写文字识别这种有明显时序特征的数据比较适合用LSTM来处理,而其代价是对空域信号的处理效果不好;CNN刚好弥补了这一点,在静态图像识别任务中大放异彩。

在图像识别领域,有一类任务是手写体多字符识别。输入图像如图13-13所示,任务是准确识别图像中的三个字母。

图13-13

这种分类任务与单字符任务相比,有以下特点。

输入图像和识别类别都是变长的,即待识别的字符的个数不固定(但类别总数固定)。

输入图像和输入类别没有严格对齐,即每个字符占据的空间不固定。

可以对输入图像进行切分,使一个字符对应于一个字母,然后进行分类,逐个突破。然而,切分任务未必能达到100% 的准确率,切分错误将直接导致后续的识别错误。况且,多个手写体字符经常“粘”在一起,很难切分。因此,我们需要通过一种端到端的方法进行手写体多字符的识别,这时CTC(Connectionist Temporal Classification)就派上了用场。将图像输入LSTM模型,使每个时刻的输出对应于一个分类。特别地,CTC增加了一个类别 ε 来表示空白。

CTC的模型结构,如图13-14所示。

图13-14

模型的预测队列不能作为最终的输出,因为有些字符被重复预测了。因此,需要对队列进行合并。合并的原则如下。

由于 ε 表示该处图像不属于任何字符,故可以舍弃,即将“εffooxxε”变成“ffooxx”。

将相邻的相同预测结果合并,例如将“fffoxx”合并成“fox”。

而对于单词“hello”中的两个“l”,将不进行合并。此时,需要用“ε”将它们分开,即“lεl”的识别结果是“ll”。


(由于平台稿件格式问题,公式格式不能正确写上;如若读写困难可评论区留言获取完整电子版)

对机器学习感兴趣的读者可以去主页关注我;本人著有《速通深度学习》以及《速通机器学习数学基础》二书,想要完整版电子档可以后台私信我;实体版已出版在JD上有售,有兴趣的同学可以自行搜索了解

想一起学习机器学习的话也可以,本人所做机器学习0基础教程已有60余章还未公开;想了解的话也可以评论区留言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值