基于Hierarchical softmax的word2vec模型

word2vec有两个重要的模型:CBOW模型和Skip-gram模型。如下图所示:

在这里插入图片描述
这两个模型都包括输入层,投影层,输出层,如上右图CBOW模型时在已知当前词 w t w_t wt的上下文 w t − 2 , w t − 1 , w t + 1 , w t + 2 w_{t-2},w_{t-1},w_{t+1},w_{t+2} wt2,wt1,wt+1,wt+2的前提下预测当前词 w t w_t wt。而Skip-gram模型是在已知 w t w_t wt的前提下,预测其上下文 w t − 2 , w t − 1 , w t + 1 , w t + 2 w_{t-2},w_{t-1},w_{t+1},w_{t+2} wt2,wt1,wt+1,wt+2

在神经网络语言模型中,目标函数通常取对数似然函数:
L = ∑ w ∈ C log ⁡ p ( w ∣ c o n t e x t ( w ) ) \mathcal L = \sum_{w \in C} \log p(w|context(w)) L=wClogp(wcontext(w))
CBOW模型的目标函数也是上式。其中的关键是条件概率函数 log ⁡ p ( w ∣ c o n t e x t ( w ) ) \log p(w|context(w)) logp(wcontext(w))的构造。

而Skip-gram模型的优化目标则是:
L = ∑ w ∈ C log ⁡ p ( c o n t e x t ( w ) ∣ w ) \mathcal L = \sum_{w \in C} \log p(context(w)|w) L=wClogp(context(w)w)

CBOW模型

基本结构

CBOW模型的网络结构包括三层:输入层,投影层,输出层。

在这里插入图片描述

(1)输入层:包含 c o m t e x t ( w ) comtext(w) comtext(w)中的 2 c 2c 2c个词向量 v ( c o n t e x t ( w ) 1 ) , v ( c o n t e x t ( w ) 2 ) , … , v ( c o n t e x t ( w ) 2 c ) ∈ R m \mathbf v(context(w)_1),\mathbf v(context(w)_2),\ldots,\mathbf v(context(w)_{2c}) \in \mathbf R^m v(context(w)1),v(context(w)2),,v(context(w)2c)Rm ,每个词向量的长度是 m m m

(2)投影层:将输入层的 2 c 2c 2c个词向量累加求和,即 x w = ∑ i = 1 2 c v ( c o n t e x t ( w ) i ) \mathbf x_w = \sum_{i=1}^{2c}\mathbf v(context(w)_i) xw=i=12cv(context(w)i)

(3)输出层:输出层对应一颗二叉树,这是一颗Huffman树,其叶子结点是语料库中的所有词,叶子个数N=|D|,分别对应词典D中的词。以各词在语料中出现的次数作为权值构建出来的Huffman树。(构建过程可参考:Huffman编码 )

CBOW模型与神经网络语言模型对比,主要有三个不同 :

(1)(从输入层到投影层的操作)前者是通过拼接,后者通过累加求和.

(2)(隐藏层)前者有隐藏层,后者无隐藏层.

(3)(输出层)前者是线性结构,后者是树形结构.

神经网络语言模型中大部分计算集中在隐藏层和输出层之间的矩阵向量运算,以及输出层上的softmax归一化运算,CBOW模型对这些计算复杂度高的地方有针对性地进行了改变,首先,去掉了隐藏层,其次,输出层改用了Huffman树,从而为利用Hierarchical softmax技术奠定了基础。

梯度计算

假设2014 年世界杯期间,从新浪微博中抓取了若干条与足球相关的微博,经统计,“我”、“喜欢”、“观看”、“巴西”、“足球”、“世界杯”这六个词出现的次数分别为15, 8, 6, 5,3, 1。用这些语料构建Huffman树,并将其作为CBOW模型的输出层。如下图所示:

在这里插入图片描述

针对上图,规定:

p w p^w pw 表示从根结点出发到达 w w w对应叶子结点的路径,

l w l^w lw 表示这个路径中包含结点的个数,

p l w p_{l}^w plw 表示路径 p w p^w pw中的第 l l l个结点,

d j w d_j^w djw 表示路径 p w p^w pw中第 j j j个结点对应的编码(0或1),

θ j w \theta^w_j θjw 表示路径 p w p^w pw中第 j j j个结点对应向量(可以理解图中每一条边的都有一个权值向量)。

我们的目标是利用输入向量 X w X_w Xw 和Huffman树来定义函数 p ( w ∣ c o n t e x t ( w ) ) p(w|context(w)) p(wcontext(w))

以图中的词 w = " 足 球 " w="足球" w=""为例,从Huffman树的根结点出发到“足球”,中间经历了4个分支,每一次分支,都可以看成进行了一次二分类。那么从二分类的角度来看,对于每个非叶子结点,就需要为其左右孩子指定类别。我们规定:编码为1的结点定义为负类,编码为0的结点定义为正类。也就是说,将一个结点进行二分类,分到左边是负类,分到右边是正类。所以有:
L a b e l ( p i w ) = 1 − d i w , i = 1 , 2 , … , l w Label(p_i^w) = 1- d_i^w, \quad i=1,2,\ldots,l^w Label(piw)=1diw,i=1,2,,lw
我们用逻辑斯蒂回归进行二分类,一个结点被分为正类的概率是:
σ ( x w T θ ) = 1 1 + e − x w T θ \sigma(\mathbf x_w^T\theta) = \frac{1}{1+e^{-\mathbf x_w^T\theta}} σ(xwTθ)=1+exwTθ1
被分成负类的概率为:
1 − σ ( x w T θ ) 1-\sigma(\mathbf x_w^T\theta) 1σ(xwTθ)
这里的 θ \theta θ指图中每一条边的都有一个权值向量。是个待定参数。

所以,从Huffman树的根结点出发到“足球”,中间经历了4个二分类,每个分类的结果如下:

第一次: p ( d 2 w ∣ x w , θ 1 w ) = 1 − σ ( x w T θ 1 w ) p(d_2^w|\mathbf x_w,\theta_1^w) = 1- \sigma(\mathbf x_w^T\theta_1^w) p(d2wxw,θ1w)=1σ(xwTθ1w)

第二次: p ( d 3 w ∣ x w , θ 2 w ) = σ ( x w T θ 2 w ) p(d_3^w|\mathbf x_w,\theta_2^w) = \sigma(\mathbf x_w^T\theta_2^w) p(d3wxw,θ2w)=σ(xwTθ2w)

第三次: p ( d 4 w ∣ x w , θ 3 w ) = σ ( x w T θ 3 w ) p(d_4^w|\mathbf x_w,\theta_3^w) = \sigma(\mathbf x_w^T\theta_3^w) p(d4wxw,θ3w)=σ(xwTθ3w)

第四次: p ( d 5 w ∣ x w , θ 4 w ) = 1 − σ ( x w T θ 4 w ) p(d_5^w|\mathbf x_w,\theta_4^w) = 1- \sigma(\mathbf x_w^T\theta_4^w) p(d5wxw,θ4w)=1σ(xwTθ4w)

这四个概率的乘积就是 p ( 足 球 ∣ c o n t e x t ( 足 球 ) ) p(足球|context(足球)) p(context()),即:
p ( 足 球 ∣ c o n t e x t ( 足 球 ) ) = ∏ j = 2 5 p ( d j w ∣ x w , θ j − 1 w ) p(足球|context(足球)) = \prod_{j=2}^5 p(d_j^w|\mathbf x_w,\theta_{j-1}^w) p(context())=j=25p(djwxw,θj1w)
总结:对于词典D中的任意词w, Huffman树中必存在一条从根结点到词w对应结点的路径 p w p^w pw (且这条路径是唯一的)。路径 p w p^w pw上存在 l w − 1 l^w -1 lw1个分支,将每个分支看做一次二分类,每一次分类就产生一个概率, 将这些概率乘起来,就是所需的 p ( w ∣ C o n t e x t ( w ) ) p(w|Context(w)) p(wContext(w))

所以条件概率的定义如下:
p ( w ∣ c o n t e x t ( w ) ) = ∏ j = 2 l w p ( d j w ∣ x w , θ j − 1 w ) p(w|context(w)) = \prod_{j=2}^{l^w} p(d_j^w|\mathbf x_w,\theta_{j-1}^w) p(wcontext(w))=j=2lwp(djwxw,θj1w)
其中:
p ( d j w ∣ x w , θ j − 1 w ) = { σ ( x w T θ j − 1 w ) d j w = 0 1 − σ ( x w T θ j − 1 w ) d j w = 1 p(d_j^w|\mathbf x_w,\theta_{j-1}^w) = \begin{cases} \sigma(\mathbf x_w^T\theta_{j-1}^w) \qquad d_j^w=0 \\ 1-\sigma(\mathbf x_w^T\theta_{j-1}^w) \quad d_j^w=1 \end{cases} p(djwxw,θj1w)={σ(xwTθj1w)djw=01σ(xwTθj1w)djw=1
写成总体表达式如下:
p ( d j w ∣ x w , θ j − 1 w ) = [ σ ( x w T θ j − 1 w ) ] 1 − d j w ⋅ [ 1 − σ ( x w T θ j − 1 w ) ] d j w p(d_j^w|\mathbf x_w,\theta_{j-1}^w) = [\sigma(\mathbf x_w^T\theta_{j-1}^w)]^{1-d_j^w}\cdot[1-\sigma(\mathbf x_w^T\theta_{j-1}^w)]^{d_j^w} p(djwxw,θj1w)=[σ(xwTθj1w)]1djw[1σ(xwTθj1w)]djw
所以我们的优化目标是:
L = ∑ w ∈ C l o g ∏ j = 2 l w { [ σ ( x w T θ j − 1 w ) ] 1 − d j w ⋅ [ 1 − σ ( x w T θ j − 1 w ) ] d j w } = ∑ w ∈ C ∑ j = 2 l w { ( 1 − d j w ) log ⁡ [ σ ( x w T θ j − 1 w ) ] + d j w log ⁡ [ 1 − σ ( x w T θ j − 1 w ) ] } = ∑ w ∈ C ∑ j = 2 l w L ( w , j ) \begin{aligned} \mathcal L &= \sum_{w \in C} log\prod_{j=2}^{l^w}\{ [\sigma(\mathbf x_w^T\theta_{j-1}^w)]^{1-d_j^w}\cdot[1-\sigma(\mathbf x_w^T\theta_{j-1}^w)]^{d_j^w}\} \\ &= \sum_{w \in C} \sum_{j=2}^{l^w}\{ ({1-d_j^w})\log[\sigma(\mathbf x_w^T\theta_{j-1}^w)]+d_j^w\log[1-\sigma(\mathbf x_w^T\theta_{j-1}^w)]\} \\ &= \sum_{w \in C} \sum_{j=2}^{l^w} \mathcal L(w,j) \end{aligned} L=wClogj=2lw{[σ(xwTθj1w)]1djw[1σ(xwTθj1w)]djw}=wCj=2lw{(1djw)log[σ(xwTθj1w)]+djwlog[1σ(xwTθj1w)]}=wCj=2lwL(w,j)
其中: L ( w , j ) = ( 1 − d j w ) log ⁡ [ σ ( x w T θ j − 1 w ) ] + d j w log ⁡ [ 1 − σ ( x w T θ j − 1 w ) ] \mathcal L(w,j) = ({1-d_j^w})\log[\sigma(\mathbf x_w^T\theta_{j-1}^w)]+d_j^w\log[1-\sigma(\mathbf x_w^T\theta_{j-1}^w)] L(w,j)=(1djw)log[σ(xwTθj1w)]+djwlog[1σ(xwTθj1w)]

这就是CBOW的目标函数。采用随机梯度上升法将这个函数最大化。

注:随机梯度上升法:随机取一个样本 ( c o n t e x t ( w ) , w ) (context(w),w) (context(w),w),对目标函数中的所有的参数行一次更新。

(1)更新 θ j − 1 w \theta_{j-1}^w θj1w

因为:
∂ L ( w , j ) ∂ θ j − 1 w = ∂ { ( 1 − d j w ) log ⁡ [ σ ( x w T θ j − 1 w ) ] + d j w log ⁡ [ 1 − σ ( x w T θ j − 1 w ) ] } ∂ θ j − 1 w = ( 1 − d j w ) [ 1 − σ ( x w T θ j − 1 w ) ] x w − d j w σ ( x w T θ j − 1 w ) x w = { ( 1 − d j w ) [ 1 − σ ( x w T θ j − 1 w ) ] − d j w σ ( x w T θ j − 1 w ) } x w = [ 1 − d j w − σ ( x w T θ j − 1 w ) ] x w \begin{aligned} \frac{\partial \mathcal L(w,j)}{\partial \theta_{j-1}^w} &= \frac{\partial \{ ({1-d_j^w})\log[\sigma(\mathbf x_w^T\theta_{j-1}^w)]+d_j^w\log[1-\sigma(\mathbf x_w^T\theta_{j-1}^w)]\} }{\partial \theta_{j-1}^w} \\ &= ({1-d_j^w})[1-\sigma(\mathbf x_w^T\theta_{j-1}^w)]\mathbf x_w - d_j^w\sigma(\mathbf x_w^T\theta_{j-1}^w) \mathbf x_w \\ &=\{(1-d_j^w)[1-\sigma(\mathbf x_w^T\theta_{j-1}^w)] - d_j^w\sigma(\mathbf x_w^T\theta_{j-1}^w) \}\mathbf x_w \\ & = [1-d_j^w-\sigma(\mathbf x_w^T\theta_{j-1}^w)]\mathbf x_w \end{aligned} θj1wL(w,j)=θj1w{(1djw)log[σ(xwTθj1w)]+djwlog[1σ(xwTθj1w)]}=(1djw)[1σ(xwTθj1w)]xwdjwσ(xwTθj1w)xw={(1djw)[1σ(xwTθj1w)]djwσ(xwTθj1w)}xw=[1djwσ(xwTθj1w)]xw
所以 θ j − 1 w \theta_{j-1}^w θj1w更新公式为:
θ j − 1 w : = θ j − 1 w + η [ 1 − d j w − σ ( x w T θ j − 1 w ) ] x w \theta_{j-1}^w:=\theta_{j-1}^w + \eta [1-d_j^w-\sigma(\mathbf x_w^T\theta_{j-1}^w)]\mathbf x_w θj1w:=θj1w+η[1djwσ(xwTθj1w)]xw
其中 η \eta η为学习率。

(2)更新 x w \mathbf x_w xw

因为 L ( w , j ) \mathcal L(w,j) L(w,j) 关于变量 x w \mathbf x_w xw θ j − 1 w \theta_{j-1}^w θj1w是对称的。所以:
∂ L ( w , j ) ∂ x w = [ 1 − d j w − σ ( x w T θ j − 1 w ) ] θ j − 1 w \begin{aligned} \frac{\partial \mathcal L(w,j)}{\partial \mathbf x_w} = [1-d_j^w-\sigma(\mathbf x_w^T\theta_{j-1}^w)]\theta_{j-1}^w \end{aligned} xwL(w,j)=[1djwσ(xwTθj1w)]θj1w
这里存在一个问题:我们的最终目的是要求词典D中每个词的词向量,而这里的 x w \mathbf x_w xw 表示的是 c o n t e x t ( w ) context(w) context(w)中各词词向量的累加。那么,如何利用 ∂ L ( w , j ) ∂ x w \frac{\partial \mathcal L(w,j)}{\partial \mathbf x_w} xwL(w,j)来对 v ( w ) , w ∈ D \mathbf v(w),w \in D v(w),wD 进行更新呢? word2vec中的做法很简单, 直接取
v ( w ) : = v ( w ) + η ∑ j = 2 l w ∂ L ( w , j ) ∂ x w , w ∈ c o n t e x t ( w ) \mathbf v(w) := \mathbf v(w) + \eta \sum_{j=2}^{l^w} \frac{\partial \mathcal L(w,j)}{\partial \mathbf x_w},\quad w \in context(w) v(w):=v(w)+ηj=2lwxwL(w,j),wcontext(w)
注:既然 x w \mathbf x_w xw 本身就是 c o n t e x t ( w ) context(w) context(w)中各个词向量的累加,求完梯度后也应该将其贡献到每个分量上。

下面是CBOW模型中采用的随机梯度上升法伪代码:

在这里插入图片描述

Skip-gram模型

基本结构

Skip-gram母模型的结构也是三层,下面以样本 ( w , c o n t e x t ( w ) ) (w,context(w)) (w,context(w))为例说明。如下图所示:

在这里插入图片描述

(1)输入层:只包含当前样本中心词 w w w词向量 v ( w ) ∈ R m \mathbf v(w) \in \mathbf R^m v(w)Rm ,每个词向量的长度是 m m m

(2)投影层:恒等投影,保留是为了与CBOW对比。

(3)输出层:与CBOW类似。

对于Skip-gram模型,已知的是当前词 w w w,需要对其上下文 c o n t e x t ( w ) context(w) context(w)中的词进行预测,所以:
p ( c o n t e x t ( w ) ∣ w ) = ∏ u ∈ c o n t e x t ( w ) p ( u ∣ w ) p(context(w)|w) = \prod_{u \in context(w)} p(u|w) p(context(w)w)=ucontext(w)p(uw)
类似于CBOW,所以:
p ( u ∣ w ) = ∏ j = 2 l u p ( d j u ∣ v ( w ) , θ j − 1 u ) p(u|w) = \prod_{j=2}^{l^u}p(d_j^u|\mathbf v(w),\theta_{j-1}^u) p(uw)=j=2lup(djuv(w),θj1u)
其中:
p ( d j u ∣ v ( w ) , θ j − 1 u ) = [ σ ( v ( w ) T θ j − 1 u ) ] 1 − d j u ⋅ [ 1 − σ ( v ( w ) T θ j − 1 u ) ] d j u p(d_j^u|\mathbf v(w),\theta_{j-1}^u) = [\sigma(\mathbf v(w)^T\theta_{j-1}^u)]^{1-d_j^u}\cdot[1-\sigma(\mathbf v(w)^T\theta_{j-1}^u)]^{d_j^u} p(djuv(w),θj1u)=[σ(v(w)Tθj1u)]1dju[1σ(v(w)Tθj1u)]dju

所以我们的优化目标是:
L = ∑ w ∈ C log ⁡ ∏ u ∈ c o n t e x t ( w ) ∏ j = 2 l u { [ σ ( v ( w ) T θ j − 1 u ) ] 1 − d j u ⋅ [ 1 − σ ( v ( w ) T θ j − 1 u ) ] d j u } = ∑ w ∈ C ∑ u ∈ c o n t e x t ( w ) ∑ j = 2 l u { ( 1 − d j u ) log ⁡ [ σ ( v ( w ) T θ j − 1 u ) ] + d j u l o g [ 1 − σ ( v ( w ) T θ j − 1 u ) ] } = ∑ w ∈ C ∑ u ∈ c o n t e x t ( w ) ∑ j = 2 l u   L ( w , u , j ) \begin{aligned} \mathcal L &= \sum_{w \in C} \log \prod_{u \in context(w)} \prod_{j=2}^{l^u} \{ [\sigma(\mathbf v(w)^T\theta_{j-1}^u)]^{1-d_j^u}\cdot[1-\sigma(\mathbf v(w)^T\theta_{j-1}^u)]^{d_j^u}\} \\ &= \sum_{w \in C} \sum_{u \in context(w)} \sum_{j=2}^{l^u} \{ (1-d_j^u) \log [\sigma(\mathbf v(w)^T\theta_{j-1}^u)]+d_j^ulog[1-\sigma(\mathbf v(w)^T\theta_{j-1}^u)] \}\\ &= \sum_{w \in C} \sum_{u \in context(w)} \sum_{j=2}^{l^u} \mathcal L(w,u,j) \end{aligned} L=wClogucontext(w)j=2lu{[σ(v(w)Tθj1u)]1dju[1σ(v(w)Tθj1u)]dju}=wCucontext(w)j=2lu{(1dju)log[σ(v(w)Tθj1u)]+djulog[1σ(v(w)Tθj1u)]}=wCucontext(w)j=2lu L(w,u,j)
采用随机梯度上升法将这个函数最大化。

梯度更新

(1)更新 θ j − 1 u \theta_{j-1}^u θj1u

因为:
∂ L ( w , u , j ) ∂ θ j − 1 u = ∂ { [ σ ( v ( w ) T θ j − 1 u ) ] 1 − d j u ⋅ [ 1 − σ ( v ( w ) T θ j − 1 u ) ] d j u } ∂ θ j − 1 u = ( 1 − d j u ) [ 1 − σ ( v ( w ) T θ j − 1 u ) ] v ( w ) − d j u σ ( v ( w ) T θ j − 1 u ) v ( w ) = { ( 1 − d j u ) [ 1 − σ ( v ( w ) T θ j − 1 u ) ] − d j u σ ( v ( w ) T θ j − 1 u ) } v ( w ) = [ 1 − d j u − σ ( v ( w ) T θ j − 1 u ) ] v ( w ) \begin{aligned}\frac{\partial \mathcal L(w,u,j)}{\partial \theta_{j-1}^u} &= \frac{\partial \{ [\sigma(\mathbf v(w)^T\theta_{j-1}^u)]^{1-d_j^u}\cdot[1-\sigma(\mathbf v(w)^T\theta_{j-1}^u)]^{d_j^u}\} }{\partial \theta_{j-1}^u} \\ &= ({1-d_j^u})[1-\sigma(\mathbf v(w)^T\theta_{j-1}^u)]\mathbf v(w) - d_j^u\sigma(\mathbf v(w)^T\theta_{j-1}^u) \mathbf v(w)\\ &=\{(1-d_j^u)[1-\sigma(\mathbf v(w)^T\theta_{j-1}^u)] - d_j^u\sigma(\mathbf v(w)^T\theta_{j-1}^u) \}\mathbf v(w) \\& = [1-d_j^u-\sigma(\mathbf v(w)^T\theta_{j-1}^u)]\mathbf v(w) \end{aligned} θj1uL(w,u,j)=θj1u{[σ(v(w)Tθj1u)]1dju[1σ(v(w)Tθj1u)]dju}=(1dju)[1σ(v(w)Tθj1u)]v(w)djuσ(v(w)Tθj1u)v(w)={(1dju)[1σ(v(w)Tθj1u)]djuσ(v(w)Tθj1u)}v(w)=[1djuσ(v(w)Tθj1u)]v(w)
所以 θ j − 1 w \theta_{j-1}^w θj1w更新公式为:
θ j − 1 u : = θ j − 1 u + η [ 1 − d j u − σ ( v ( w ) T θ j − 1 u ) ] v ( w ) \theta_{j-1}^u:=\theta_{j-1}^u + \eta [1-d_j^u-\sigma(\mathbf v(w)^T\theta_{j-1}^u)]\mathbf v(w) θj1u:=θj1u+η[1djuσ(v(w)Tθj1u)]v(w)
其中 η \eta η为学习率。

(2)更新 v ( w ) \mathbf v(w) v(w)

因为 L ( w , u , j ) \mathcal L(w,u,j) L(w,u,j) 关于变量 v ( w ) \mathbf v(w) v(w) θ j − 1 w \theta_{j-1}^w θj1w是对称的。所以:
∂ L ( w , u , j ) ∂ v ( w ) = [ 1 − d j u − σ ( v ( w ) T θ j − 1 u ) ] θ j − 1 u \begin{aligned}\frac{\partial \mathcal L(w,u,j)}{\partial \mathbf v(w)} = [1-d_j^u-\sigma(\mathbf v(w)^T\theta_{j-1}^u)]\theta_{j-1}^u \end{aligned} v(w)L(w,u,j)=[1djuσ(v(w)Tθj1u)]θj1u
所以, v ( w ) \mathbf v(w) v(w)更新公式为:
v ( w ) : = v ( w ) + η ∑ u ∈ c o n t e x t ( w ) ∑ j = 2 l w ∂ L ( w , u , j ) ∂ v ( w ) , w ∈ c o n t e x t ( w ) \mathbf v(w) := \mathbf v(w) + \eta \sum_{u \in context(w)} \sum_{j=2}^{l^w} \frac{\partial \mathcal L(w,u,j)}{\partial \mathbf v(w)},\quad w \in context(w) v(w):=v(w)+ηucontext(w)j=2lwv(w)L(w,u,j),wcontext(w)
具体伪代码如下:

在这里插入图片描述

优缺点

使用霍夫曼树来代替传统的神经网络,避免了从隐藏层到输出的softmax层这里的计算。也避免计算所有词的softmax概率。但是如果我们的训练样本里的中心词 w w w是一个很生僻的词,那么就得在霍夫曼树中辛苦的向下走很久了。解决这个问题则是采用基于Negative Sampling的模型。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值