MoCha——单调块注意力模型

转载MoCha——单调块注意力模型 - 以观其妙的文章 - 知乎

作者:恒毅,语音识别工作者,来自新东方AI研究院语音识别团队


1.首先,提出一个问题?

加了soft attention的seq2seq模型,在很多领域取得了广泛的应用,例如机器翻译、词性标注等NLP任务,因为它们都可以看成是序列到序列的问题。但是对于语音问题,这个模型存在很明显的弊端:

  • 时间复杂度很高: 因为对于soft attention的模型来说,decoder的每一个输出要计算encoder的每一个隐含状态的对应权重,所以时间复杂度为O(UT),其中U代表输出序列的长度,T代表输入序列的长度。对于语音任务来说,10ms的帧移就意味着1s的音频有100帧,随便读一段话可能就有成百上千帧的输入,这是非常耗时的。
  • 做不到online: 同样因为计算soft-attention需要考虑encoder每一个隐含状态,所以要等到输入全部输入之后才能计算,因而无法做到实时解码。

不过与机器翻译等任务不同,语音识别和语音生成的任务中输入和输出是单调对齐的,换句话说输入和输出享有通同一个自然的时间顺序,不涉及局部的颠倒。于是,Raffel等人在2017年的研究成果表明,对于这种单调对齐的seq2seq的问题,上述的两种弊端可以得到缓解。Raffel引入了一种叫hard monotonic attention的注意力机制,实现了线性时间复杂度和online解码。

然而与soft attention相比,hard monotonic attention也限制了模型的表达性,因为soft attention理论可以学习任意方式的对齐,而这是单调对齐做不到的。实验结果也表明使用单调对齐的hard monotonic attention模型表现落后于soft attention。

所以,MoCha就这样应运而生,它不是摩卡咖啡,而是Monotonic Chunk Attention。该机制保留了hard monotonic attention线性时间复杂度和实时解码的优势,同时也允许软对齐。它是如何做到的呢,简要来说,它先确定一个滑动窗口,也就是所谓的chunk,然后在这个窗口里的几个时间步上做soft attention。窗口的移动是单调的(只能沿着时间从左向右),而窗口什么时候该滑动、滑动多少,是由模型自己决定的,或者说是学习得到的。

在这里插入图片描述

上图是一个形象的展示,纵轴代表decoder输出序列的顺序,横轴代表encoder输出的隐含状态序列,颜色代表概率,每一横行概率相加应该是1。从图中我们可以看出soft attention可以实现任意的对齐;hard monotonic attention每一步决定向右移动几步,当然也可以不移动;而MoCha移动的是一个固定长度的窗口,窗口内部实现了软注意力。

MoCha的论文中还介绍了它的反向传播训练方式,该训练方式可以直接应用于现有的seq2seq模型。实验表明,MoCha使得单调注意力模型赶上了软注意力模型的性能,代价是参数量和计算成本的适度增加。

下面我们将详细介绍这一模型的模型结构以及训练过程。

2.然后,给出 MoCha 的方案

上一小节中谈到的三种模型,实际上是依次被提出的,hard monotonic attention的提出是为了解决soft attention存在的问题,但是牺牲了模型的准确度。MoCha的提出既保留了hard monotonic attention的优点,也弥补了它在准确度上的劣势。

所以我们这一小节,按照顺序,先来回顾一下soft attention,再来讲一下hard monotonic attention与soft attention的不同,最后再讲一下MoCha在前两者的基础上做了哪些改进。

2.1 Soft Attention

在这里插入图片描述

对于一个由RNN encoder和RNN deconder组成的seq2seq模型结构来说:

x = x 1 , x 2 , . . . , x T   h = h 1 , h 2 , . . . , h T   s = s 1 , s 2 , . . . , s U   y = y 1 , y 2 , . . . , y U   x={x_1,x_2,...,x_T} \ h={h_1,h_2,...,h_T} \ s={s_1,s_2,...,s_U} \ y={y_1,y_2,...,y_U} \ x=x1,x2,...,xT h=h1,h2,...,hT s=s1,s2,...,sU y=y1,y2,...,yU 

其中 h h h为encoder的隐含状态, s s s为decoder的隐含状态,T为输入序列的长度(在语音识别任务中就是帧数),U为输出序列的长度(在语音识别任务中是token的个数)。 h j = E n c o d e r R N N ( x j , h j − 1 )   s i = D e c o d e r R N N ( y i − 1 , s i − 1 , c i )   y i = O u t p u t ( s i , c i ) h_j=EncoderRNN(x_j,h_{j-1})\ s_i=DecoderRNN(y_{i-1},s_{i-1},c_i)\ y_i=Output(s_i,c_i) hj=EncoderRNN(xj,hj1) si=DecoderRNN(yi1,si1,ci) yi=Output(si,ci) Attention可以就将其看做是一系列操作,经过这一系列操作之后Encoder的T个隐含状态 h h h就变成了U个context向量 c c c。这个 c c c就是将输入信息传给decoder的唯一通道。对于不同的attention实际上就是不同的操作,但是最终的效果就是将 h h h变成 c c c

对于soft attention来说,对应的操作如下所示: e i , j = E n e r g y ( h j , s i − 1 ) = v ⊤ t a n h ( W h h j + W s s i − 1 + b )   α i , j = exp ⁡ ( e i , j ) ∑ k = 1 T exp ⁡ ( e i , k )   c i = ∑ j = 1 T α i , j h j e_{i,j}=Energy(h_j,s_{i-1})=v^\top tanh(W_hh_j+W_ss_{i-1}+b)\ \alpha_{i,j}=\frac{\exp(e_{i,j})}{\sum_{k=1}^T{\exp(e_{i,k})}}\ c_i=\sum_{j=1}^T{\alpha_{i,j}h_j} ei,j=Energy(hj,si1)=vtanh(Whhj+Wssi1+b) αi,j=k=1Texp(ei,k)exp(ei,j) ci=j=1Tαi,jhj 计算第 i i i个时间步的 c i c_i ci时候,首先对前一个时间步的 s i − 1 s_{i-1} si1计算和每一个 h h h的energy,然后经过softmax后得到当前时间步的输出对于每一个 h h h的权重系数 α \alpha α,然后加权相加,得到当前时间步的 c i c_i ci,这样decoder依次得到每一个 c i c_i ci,再结合前一步的隐含状态 s i − 1 s_{i-1} si1以及前一步的输出 y i − 1 y_{i-1} yi1就可以得到当前时间步的输出 y i y_i yi。因为计算每一个 c i c_i ci的时候要考虑每一个 h h h,所以soft attention的时空复杂度是 O ( T U ) O(TU) O(TU)

而且soft attention部分的计算无非是矩阵的乘法、加法、tanh激活函数,这些操作都是可以求导的,也就支持了反向传播。所以引入soft attention机制并不需要额外做什么事情便可以直接训练。

2.2 Hard Monotonic Attention

在hard monotonic attention中,我们依然来看一下,U个context向量 c c c是如何由T个隐含状态 h h h得到。首先对于decoder的第 i i i的时间步的输出来说,这种注意力机制从第 i − 1 i-1 i1的时间步对齐的 h h h开始依次遍历每一个 h h h,而不是像soft attention一样从头开始。假设decoder第 i − 1 i-1 i1个时间步对齐的 h h h的索引是 t i − 1 t_{i-1} ti1,也就是说 c i − 1 c_{i-1} ci1对应 h t i − 1 h_{t_{i-1}} hti1,那么计算 c i c_i ci的时候,我们对于所有的 j = t i − 1 , t i − 1 + 1 , . . . j=t_{i-1},t_{i-1}+1,... j=ti1,ti1+1,...依次计算 e i , j e_{i,j} ei,j,然后再通过一个sigmoid激活函数,计算出一个 p i , j p_{i,j} pi,j,它可以理解成“ c i c_i ci选择第 h j h_j hj的概率”。这样,由这个 p i , j p_{i,j} pi,j就可以得到一个伯努利随机变量,对个随机变量来采样得到 z i , j z_{i,j} zi,j用来表征“对齐到这一帧\跳过这一帧”, z i , j z_{i,j} zi,j为1就表示对齐到这一帧,为0就表示跳过这一帧。 z i , j z_{i,j} zi,j一直为0就一直向后寻找,直到 z i , j z_{i,j} zi,j为1时, c i = h j c_i=h_j ci=hj

e i , j = M o n o t o n i c E n e r g y ( s i − 1 , h j )   p i , j = σ ( e i , j )   z i , j ∼ B e r n u o l l i ( p i , j ) e_{i,j}=MonotonicEnergy(s_{i-1},h_j)\ p_{i,j}=\sigma(e_{i,j})\ z_{i,j}\sim Bernuolli(p_{i,j}) ei,j=MonotonicEnergy(si1,hj) pi,j=σ(ei,j) zi,jBernuolli(pi,j)

对于解码而言,从T个 h h h中得到U个 c c c的方式就是根据上述的这个模型输出0或1,来选择出一部分 h h h作为 c c c。这个算法在解码的时候是没有任何问题的,但是因为这个的选择的操作并不能求导,所以就没有办法通过反向传播去训练。

为了解决训练的问题,在论文中,作者提出了一个方法,可以支持训练。推导比较繁琐,但是实际并不难,我们一起来看一下。

首先,为了attention的计算能够求导,我们依然想办法让每一个 c c c都由 h h h加权求和得到,即:

c i = ∑ j = 1 T α i , j h j c_i=\sum_{j=1}^T{\alpha_{i,j}h_j} ci=j=1Tαi,jhj

那么,这里的 α i , j \alpha_{i,j} αi,j如何设计呢,作者的思路是,将 α i , j \alpha_{i,j} αi,j理解成对于整个序列 c i c_i ci对齐到 h j h_j hj的概率。 c i c_i ci对齐到 h j h_j hj的概率可以分为两部分,一部分是 c i − 1 c_{i-1} ci1也对齐到了 h j h_j hj的概率 α i − 1 , j \alpha_{i-1,j} αi1,j乘上 p i , j p_{i,j} pi,j,另一部分是 c i − 1 c_{i-1} ci1对齐到了 h k ( k < j ) h_k(k<j) hkk<j然后从 k k k j − 1 j-1 j1帧都输出0的概率,即:

α i , j = p i , j ∑ k = 1 j ( α i − 1 , k ∏ l = k j − 1 ( 1 − p i , l ) )   = p i , j ( ∑ k = 1 j − 1 ( α i − 1 , k ∏ l = k j − 1 ( 1 − p i , l ) ) + α i − 1 , j )   = p i , j ( ( 1 − p i , j − 1 ) ∑ k = 1 j − 1 ( α i − 1 , k ∏ l = k j − 2 ( 1 − p i , l ) ) + α i − 1 , j )   = p i , j ( ( 1 − p i , j − 1 ) α i , j − 1 p i , j − 1 + α i − 1 , j )   \begin{align} \alpha_{i,j}&=p_{i,j}\sum_{k=1}^{j}\left(\alpha_{i-1,k}\prod_{l=k}^{j-1}{(1-p_{i,l})}\right)\ &=p_{i,j}\left(\sum_{k=1}^{j-1}\left(\alpha_{i-1,k}\prod_{l=k}^{j-1}{(1-p_{i,l})}\right)+\alpha_{i-1,j}\right)\ &=p_{i,j}\left((1-p_{i,j-1})\sum_{k=1}^{j-1}\left(\alpha_{i-1,k}\prod_{l=k}^{j-2}{(1-p_{i,l})}\right)+\alpha_{i-1,j}\right)\ &=p_{i,j}\left((1-p_{i,j-1})\frac{\alpha_{i,j-1}}{p_{i,j-1}}+\alpha_{i-1,j}\right)\ \end{align} αi,j=pi,jk=1j(αi1,kl=kj1(1pi,l)) =pi,j(k=1j1(αi1,kl=kj1(1pi,l))+αi1,j) =pi,j((1pi,j1)k=1j1(αi1,kl=kj2(1pi,l))+αi1,j) =pi,j((1pi,j1)pi,j1αi,j1+αi1,j) 

令 q i , j = α i , j p i , j  带入上式得  q i , j = ( 1 − p i , j − 1 ) q i , j − 1 + α i − 1 , j   q i , j ∏ k = 1 j ( 1 − p i , k − 1 ) − ( 1 − p i , j − 1 ) q i , j − 1 ∏ k = 1 j ( 1 − p i , k − 1 ) = α i − 1 , j ∏ k = 1 j ( 1 − p i , k − 1 )   q i , j ∏ k = 1 j ( 1 − p i , k − 1 ) − q i , j − 1 ∏ k = 1 j − 1 ( 1 − p i , k − 1 ) = α i − 1 , j ∏ k = 1 j ( 1 − p i , k − 1 )   ∑ l = 1 j ( q i , l ∏ k = 1 l ( 1 − p i , k − 1 ) − q i , l − 1 ∏ k = 1 l − 1 ( 1 − p i , k − 1 ) ) = ∑ l = 1 j α i − 1 , l ∏ k = 1 l ( 1 − p i , k − 1 )   q i , j ∏ k = 1 j ( 1 − p i , k − 1 ) − q i , 0 = ∑ l = 1 j α i − 1 , l ∏ k = 1 l ( 1 − p i , k − 1 )   q i , j = ( ∏ k = 1 j ( 1 − p i , k − 1 ) ) ( ∑ l = 1 j α i − 1 , l ∏ k = 1 l ( 1 − p i , k − 1 ) )  所以  q i = c u m p r o d ( 1 − p i ) c u m s u m ( α i − 1 c u m p r o d ( 1 − p i ) ) 令 q_{i,j}=\frac{\alpha_{i,j}}{p_{i,j}}\ 带入上式得\ \begin{align} q_{i,j}&=(1-p_{i,j-1})q_{i,j-1}+\alpha_{i-1,j}\ \frac{q_{i,j}}{\prod_{k=1}^j(1-p_{i,k-1})}-\frac{(1-p_{i,j-1})q_{i,j-1}}{\prod_{k=1}^j(1-p_{i,k-1})}&=\frac{\alpha_{i-1,j}}{\prod_{k=1}^j(1-p_{i,k-1})}\ \frac{q_{i,j}}{\prod_{k=1}^j(1-p_{i,k-1})}-\frac{q_{i,j-1}}{\prod_{k=1}^{j-1}(1-p_{i,k-1})}&=\frac{\alpha_{i-1,j}}{\prod_{k=1}^j(1-p_{i,k-1})}\ \sum_{l=1}^j\left(\frac{q_{i,l}}{\prod_{k=1}^l(1-p_{i,k-1})} - \frac{q_{i,l-1}}{\prod_{k=1}^{l-1}(1-p_{i,k-1})} \right)&= \sum_{l=1}^j\frac{\alpha_{i-1,l}}{\prod_{k=1}^l(1-p_{i,k-1})}\ \frac{q_{i,j}}{\prod_{k=1}^j(1-p_{i,k-1})}-q_{i,0} &= \sum_{l=1}^j\frac{\alpha_{i-1,l}}{\prod_{k=1}^l(1-p_{i,k-1})}\ q_{i,j}&=\left(\prod_{k=1}^j(1-p_{i,k-1})\right)\left(\sum_{l=1}^j\frac{\alpha_{i-1,l}}{\prod_{k=1}^l(1-p_{i,k-1})}\right)\ 所以\ q_i&=cumprod(1-p_i)cumsum\left(\frac{\alpha_{i-1}}{cumprod(1-p_i)}\right) \end{align} qi,j=pi,jαi,j 带入上式得 qi,j=(1pi,j1)qi,j1+αi1,j k=1j(1pi,k1)qi,jk=1j(1pi,k1)(1pi,j1)qi,j1=k=1j(1pi,k1)αi1,j k=1j(1pi,k1)qi,jk=1j1(1pi,k1)qi,j1=k=1j(1pi,k1)αi1,j l=1j(k=1l(1pi,k1)qi,lk=1l1(1pi,k1)qi,l1)=l=1jk=1l(1pi,k1)αi1,l k=1j(1pi,k1)qi,jqi,0=l=1jk=1l(1pi,k1)αi1,l qi,j=(k=1j(1pi,k1))(l=1jk=1l(1pi,k1)αi1,l) 所以 qi=cumprod(1pi)cumsum(cumprod(1pi)αi1)

其中cumprod和cumsum是连乘和累加的意思,只不过是对向量操作,例如对于 x = [ x 1 , x 2 , x 3 , . . . x n ] x=[x_1,x_2,x_3,...x_n] x=[x1,x2,x3,...xn] c u m p r o d ( x ) = [ 1 , x 1 , x 1 x 2 , . . . , ∏ i = 1 n − 1 x i ] cumprod(x)=[1,x_1,x_1x_2,...,\prod_{i=1}^{n-1}x_i] cumprod(x)=[1,x1,x1x2,...,i=1n1xi] c u m s u m ( x ) = [ x 1 , x 1 + x 2 , . . . , ∑ i = 1 n x i ] cumsum(x)=[x_1,x_1+x_2,...,\sum_{i=1}^nx_i] cumsum(x)=[x1,x1+x2,...,i=1nxi]。对于这两个操作,早在1980年就提出了并行计算的高速算法,计算量是可以接受的。

现在我们就有了一个可以求导的过程,对于每个 h j h_j hj,依次计算每一个 p i , j p_{i,j} pi,j,然后依次计算 q i q_i qi,再通过 q i q_i qi计算 α i \alpha_i αi,这样把 α i \alpha_i αi当做权重乘上 h h h加权相加得到了 c i c_i ci。整个过程无论是 p i , j p_{i,j} pi,j的计算还是累加连乘等操作都是可以求导的,这样就能够训练了。

你可能会疑惑,这样时间复杂度不依然是 O ( T U ) O(TU) O(TU)吗,因为对于每一个 c i c_i ci还是要依次计算每一个 h j h_j hj。实际上在训练的时候确实是这样的,但是在解码的时候还是按照0,1采样的方式去决定每一个 c i c_i ci取哪一个 h j h_j hj,也就是说该模型在训练和解码的时候采用了不同的计算公式。作者为了弥补训练和推理时的差异,在经过计算 p i , j p_{i,j} pi,j的sigmoid函数之前加入了一个0均值1方差的高斯噪声来让训练出来的 p i , j p_{i,j} pi,j变得sharp,也就是概率要么接近0,要么接近1。在推理的时候并没有这个高斯噪声, p i , j > 0.5 p_{i,j}>0.5 pi,j>0.5就输出1, p i , j < 0.5 p_{i,j}<0.5 pi,j<0.5就输出0,这样推理的时候就可以得到确定的结果。

另外,作者对attention的计算也做了改进:

e i , j = M o n o t o n i c E n e r g y ( s i − 1 , h j ) = g v ⊤ ∣ ∣ v ∣ ∣ t a n h ( W s i − 1 + V h j + b ) + r e_{i,j}=MonotonicEnergy(s_{i-1},h_j)=g\frac{v^\top}{||v||}tanh(Ws_{i-1}+Vh_j+b)+r ei,j=MonotonicEnergy(si1,hj)=g∣∣v∣∣vtanh(Wsi1+Vhj+b)+r

g g g r r r都是可训练的参数,

在soft attention中, e i , j e_{i,j} ei,j计算出来是会送到softmax中去,softmax只关心相对大小,所以 e i , j e_{i,j} ei,j如果整体的数值有偏移的话,分子分母是会抵消掉的。monotonic attention做不到这一点,因为它的 e i , j e_{i,j} ei,j是会送到sigmoid函数中,所以为了防止输入sigmoid前的数值偏移影响结果,加了可训练的参数 r r r来调整。而且, q i , j = ( 1 − p i , j − 1 ) q i , j − 1 + α i − 1 , j q_{i,j}=(1-p_{i,j-1})q_{i,j-1}+\alpha_{i-1,j} qi,j=(1pi,j1)qi,j1+αi1,j在连乘的时候随着 i i i的增大,会出现指数衰减的情况,加了 r r r之后,r可以为负值,这样经过sigmoid之后的概率值就趋近于0, ( 1 − p i , j − 1 ) → 1 (1-p_{i,j-1})\to1 (1pi,j1)1,解决了 q i , j q_{i,j} qi,j会变得很小的问题,也使得概率更加的sharp。而比上 ∣ ∣ v ∣ ∣ ||v|| ∣∣v∣∣在乘上 g g g是为了消除 v v v的scale的影响。

2.3 Monotonic Chunkwise Attention

接下来我们再来看一下Monotonic Chunkwise Attention,也就是MoCha。依然还是推理和训练分别介绍,首先是推理。

在这里插入图片描述

和hard monotonic attention类似,MoCha只是将对到固定的一帧改为对齐到一个滑动窗口。推理时的步骤如上图所示:首先给decoder输入一个开始信号,在输出第i个输出 y i y_i yi时,先从 y i − 1 y_{i-1} yi1对齐到的滑动窗口的位置开始遍历每一个 h j h_j hj计算一个概率 p i , j p_{i,j} pi,j

e i , j = M o n o t o n i c E n e r g y ( s i − 1 , h j )   p i , j = σ ( e i , j )   e_{i,j}=MonotonicEnergy(s_{i-1},h_j)\ p_{i,j}=\sigma(e_{i,j})\ ei,j=MonotonicEnergy(si1,hj) pi,j=σ(ei,j) 

如果这个概率大于0.5就意味着将长度为 w w w的滑动窗口放到这一帧(这一帧作为滑动窗口的最后一帧)。然后对在滑动窗口内的 w w w帧计算soft attention:

u i , k = C h u n k E n e r g y ( s i − 1 , h k )   c i = ∑ k = j − w + 1 j exp ⁡ ( u i , k ) ∑ l = j − w + 1 j exp ⁡ ( u i , l ) h k u_{i,k}=ChunkEnergy(s_{i-1},h_k)\ c_i=\sum_{k=j-w+1}^j\frac{\exp(u_{i,k})}{\sum_{l=j-w+1}^j\exp(u_{i,l})}h_k ui,k=ChunkEnergy(si1,hk) ci=k=jw+1jl=jw+1jexp(ui,l)exp(ui,k)hk

这样就得到了 c i c_i ci,如果遍历到最后一帧模型一直没有输出大于0.5的概率,那么 c i c_i ci就取零向量。最终依然按照同样的方式,将 c i c_i ci送入decoder计算输出 y i y_i yi

s i = D e c o d e r R N N ( y i − 1 , s i − 1 , c i )   y i = O u t p u t ( s i , c i ) s_i=DecoderRNN(y_{i-1},s_{i-1},c_i)\ y_i=Output(s_i,c_i) si=DecoderRNN(yi1,si1,ci) yi=Output(si,ci)

接下来说一下训练过程,MoCha训练的时候同样无法反向传播,所以依然仿照hard monotonic 的方式,先计算 α i , j \alpha_{i,j} αi,j,这里的 α i , j \alpha_{i,j} αi,j理解为 c i c_i ci对应的滑动窗口的位置在第 j j j帧的概率。但是不同的是, c i c_i ci对于 h j h_j hj的权重系数并不只是 α i , j \alpha_{i,j} αi,j,因为 c i c_i ci的滑动窗口包含 h j h_j hj的情况有 w w w种( h j h_j hj作为滑动窗口中的第1,2,3…w帧),要把这些情况都考虑进去,而且在每一种情况中, h j h_j hj c i c_i ci的贡献是softmax算出来的相应的权重,所以要把这个权重也乘上。

β i , j = ∑ k = 1 j + w − 1 ( α i , k exp ⁡ ( u i , j ) ∑ l = k − w + 1 k exp ⁡ ( u i , l ) )   c i = ∑ j = 1 T β i , j h j \beta_{i,j}=\sum_{k=1}^{j+w-1}\left(\alpha_{i,k}\frac{\exp(u_{i,j})}{\sum_{l=k-w+1}^{k}\exp(u_{i,l})}\right)\ c_i=\sum_{j=1}^T\beta_{i,j}h_j βi,j=k=1j+w1(αi,kl=kw+1kexp(ui,l)exp(ui,j)) ci=j=1Tβi,jhj

这里的 β \beta β看起来计算量很大,不过幸运的是,计算这种嵌套累加也有并行的高效算法,这里就不做展开了。其他训练的操作和hard monotonic attention相同。

草草结尾,希望批评指正!

参考文献:

Chiu C C, Raffel C. Monotonic chunkwise attention[J]. arXiv preprint arXiv:1712.05382, 2017.
Liu B, Cao S, Sun S, et al. Multi-head monotonic chunkwise attention for online speech recognition[J]. arXiv preprint arXiv:2005.00205, 2020.
Kim K, Lee K, Gowda D, et al. Attention based on-device streaming speech recognition with large speech corpus[C]//2019 IEEE Automatic Speech Recognition and Understanding Workshop (ASRU). IEEE, 2019: 956-963.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值