【word2vec】篇二:基于Hierarchical Softmax的 CBOW 模型和 Skip-gram 模型
文章目录
- CBOW 模型
- 基本结构
- 目标函数
- 梯度计算
- Skip-gram 模型
- 基本结构
- 梯度计算
- 优缺点分析
系列文章:
- 【word2vec】篇一:理解词向量、CBOW与Skip-Gram等知识
- 【word2vec】篇二:基于Hierarchical Softmax的 CBOW 模型和 Skip-gram 模型
- 【word2vec】篇三:基于Negative Sampling 的 CBOW 模型和 Skip-gram 模型
本篇是介绍基于Hierarchical Softmax的 CBOW 模型和 Skip-gram 模型。
CBOW 模型
基本结构
CBOW 模型是在已知当前词wtw_twt的上下文wt−2,wt−1,wt+1,wt+2w_{t-2},w_{t-1},w_{t+1},w_{t+2}wt−2,wt−1,wt+1,wt+2的前提下预测当前词wtw_twt。后面我们用comtext(w)comtext(w)comtext(w)来表示词w的上下文中的词,通常,我们取词 w 前后 2c 个单词来组成comtext(w)comtext(w)comtext(w)。下图给出了 CBOW 模型的网络结构:
它包括三层:输入层,投影层,输出层。
(1)输入层:包含comtext(w)comtext(w)comtext(w)中的2c2c2c个词向量v(context(w)1),v(context(w)2),…,v(context(w)2c)∈Rm\mathbf v(context(w)_1),\mathbf v(context(w)_2),\ldots,\mathbf v(context(w)_{2c}) \in \mathbf R^mv(context(w)1),v(context(w)2),…,v(context(w)2c)∈Rm ,每个词向量的长度是mmm。
(2)投影层:将输入层的2c2c2c个词向量累加求和,即xw=∑i=12cv(context(w)i)\mathbf x_w = \sum_{i=1}^{2c}\mathbf v(context(w)_i)xw=∑i=12cv(context(w)i) 。
(3)输出层:输出层是用哈夫曼算法以各词在语料中出现的次数作为权值生成的一颗二叉树,其叶子结点是语料库中的所有词,叶子个数N=|D|,分别对应词典D中的词。
神经网络语言模型(NNLM)中大部分计算集中在隐藏层和输出层之间的矩阵向量运算,以及输出层上的softmax归一化运算,CBOW模型对此进行了改进。与传统的神经网络语言模型相比:
- NNLM则是简单的将输入的向量进行拼接,而CBOW 模型将上下文的词累加求和作为输入。
- NNLM是线性结构,而CBOW 是树形结构。
- NNLM具有隐藏层,而CBOW没有隐藏层。
目标函数
假设对于给定的文本,“我”、“喜欢”、“观看”、“巴西”、“足球”、“世界杯”这六个词出现的次数分别为15, 8, 6, 5,3, 1。于是可以用这些语料构建霍夫曼树,并将其作为CBOW模型的输出层。如下图所示:
注意:与常规的霍夫曼树不同,左子树用1编码,右子树用0编码。
接下来,我们用 pwp^wpw 表示从根结点出发到达www对应叶子结点的路径,lwl^wlw 表示这个路径中包含结点的个数,plwp_{l}^wplw 表示路径 pwp^wpw中的第lll个结点,djwd_j^wdjw 表示路径pwp^wpw中第jjj个结点对应的编码(0或1),θjw\theta^w_jθjw 表示路径pwp^wpw中第jjj个非叶子结点对应向量。
我们的目标是利用输入向量XwX_wXw 和霍夫曼树来定义函数p(w∣context(w))p(w|context(w))p(w∣context(w))。
以图中的词w="足球"w="足球"w="足球"为例,从霍夫曼树的根结点出发到“足球”,中间经历了4个分支,每一次分支,都可以看成进行了一次二分类。那么从二分类的角度来看,对于每个非叶子结点,就需要为其左右孩子指定类别。我们规定:编码为1的结点定义为负类,编码为0的结点定义为正类。也就是说,将一个结点进行二分类,分到左边是负类,分到右边是正类。所以有:
Label(piw)=1−diw,i=1,2,…,lwLabel(p_i^w) = 1- d_i^w, \quad i=1,2,\ldots,l^w Label(piw)=1−diw,i=1,2,…,lw
我们用逻辑斯蒂回归进行二分类,一个结点被分为正类的概率是:
σ(xwTθ)=11+e−xwTθ\sigma(\mathbf x_w^T\theta) = \frac{1}{1+e^{-\mathbf x_w^T\theta}} σ(xwTθ)=1+e−xwTθ1
被分成负类的概率为:
1−σ(xwTθ)1-\sigma(\mathbf x_w^T\theta) 1−σ(xwTθ)
这里的θ\thetaθ就是非叶子节点对应的向量,是个待定参数。
所以,从霍夫曼树的根结点出发到“足球”,中间经历了4个二分类,每个分类的结果如下:
第一次:p(d2w∣xw,θ1w)=1−σ(xwTθ1w)p(d_2^w|\mathbf x_w,\theta_1^w) = 1- \sigma(\mathbf x_w^T\theta_1^w)p(d2w∣xw,θ1w)=1−σ(xwTθ1w)
第二次:p(d3w∣xw,θ2w)=σ(xwTθ2w)p(d_3^w|\mathbf x_w,\theta_2^w) = \sigma(\mathbf x_w^T\theta_2^w)p(d3w∣xw,θ2w)=σ(xwTθ2w)
第三次:p(d4w∣xw,θ3w)=σ(xwTθ3w)p(d_4^w|\mathbf x_w,\theta_3^w) = \sigma(\mathbf x_w^T\theta_3^w)p(d4w∣xw,θ3w)=σ(xwTθ3w)
第四次:p(d5w∣xw,θ4w)=1−σ(xwTθ4w)p(d_5^w|\mathbf x_w,\theta_4^w) = 1- \sigma(\mathbf x_w^T\theta_4^w)p(d5w∣xw,θ4w)=1−σ(xwTθ4w)
这四个概率的乘积就是p(足球∣context(足球))p(足球|context(足球))p(足球∣context(足球)),即:
p(足球∣context(足球))=∏j=25p(djw∣xw,θj−1w)p(足球|context(足球)) = \prod_{j=2}^5 p(d_j^w|\mathbf x_w,\theta_{j-1}^w) p(足球∣context(足球))=j=2∏5p(djw∣xw,θj−1w)
总结:对于词典D中的任意词w, 霍夫曼树中必存在一条从根结点到词w对应结点的路径pwp^wpw (且这条路径是唯一的)。路径pwp^wpw上存在lw−1l^w -1lw−1个分支,将每个分支看做一次二分类,每一次分类就产生一个概率, 将这些概率乘起来,就是所需的p(w∣Context(w))p(w|Context(w))p(w∣Context(w))。
所以条件概率的定义如下:
p(w∣context(w))=∏j=2lwp(djw∣xw,θj−1w)p(w|context(w)) = \prod_{j=2}^{l^w} p(d_j^w|\mathbf x_w,\theta_{j-1}^w) p(w∣context(w))=j=2∏lwp(djw∣xw,θj−1w)
其中:
p(djw∣xw,θj−1w)={σ(xwTθj−1w)djw=01−σ(xwTθj−1w)djw=1p(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(djw∣xw,θj−1w)={σ(xwTθj−1w)djw=01−σ(xwTθj−1w)djw=1
于是整体表达式如下:
p(djw∣xw,θj−1w)=[σ(xwTθj−1w)]1−djw⋅[1−σ(xwTθj−1w)]djwp(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(djw∣xw,θj−1w)=[σ(xwTθj−1w)]1−djw⋅[1−σ(xwTθj−1w)]djw
所以我们的优化目标是:
L=∑w∈Clog∏j=2lw{[σ(xwTθj−1w)]1−djw⋅[1−σ(xwTθj−1w)]djw}=∑w∈C∑j=2lw{(1−djw)log[σ(xwTθj−1w)]+djwlog[1−σ(xwTθj−1w)]}=∑w∈C∑j=2lwL(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=w∈C∑logj=2∏lw{[σ(xwTθj−1w)]1−djw⋅[1−σ(xwTθj−1w)]djw}=w∈C∑j=2∑lw{(1−djw)log[σ(xwTθj−1w)]+djwlog[1−σ(xwTθj−1w)]}=w∈C∑j=2∑lwL(w,j)
其中:L(w,j)=(1−djw)log[σ(xwTθj−1w)]+djwlog[1−σ(xwTθj−1w)]\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)=(1−djw)log[σ(xwTθj−1w)]+djwlog[1−σ(xwTθj−1w)]
这就是CBOW的目标函数。
梯度计算
采用随机梯度上升法将这个函数最大化。
注:随机梯度上升法:随机取一个样本(context(w),w)(context(w),w)(context(w),w),对目标函数中的所有的参数行一次更新。
(1)更新θj−1w\theta_{j-1}^wθj−1w
因为:
∂L(w,j)∂θj−1w=∂{(1−djw)log[σ(xwTθj−1w)]+djwlog[1−σ(xwTθj−1w)]}∂θj−1w=(1−djw)[1−σ(xwTθj−1w)]xw−djwσ(xwTθj−1w)xw={(1−djw)[1−σ(xwTθj−1w)]−djwσ(xwTθj−1w)}xw=[1−djw−σ(xwTθj−1w)]xw\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} ∂θj−1w∂L(w,j)=∂θj−1w∂{(1−djw)log[σ(xwTθj−1w)]+djwlog[1−σ(xwTθj−1w)]}=(1−djw)[1−σ(xwTθj−1w)]xw−djwσ(xwTθj−1w)xw={(1−djw)[1−σ(xwTθj−1w)]−djwσ(xwTθj−1w)}xw=[1−djw−σ(xwTθj−1w)]xw
所以 θj−1w\theta_{j-1}^wθj−1w更新公式为:
θj−1w:=θj−1w+η[1−djw−σ(xwTθj−1w)]xw\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 θj−1w:=θj−1w+η[1−djw−σ(xwTθj−1w)]xw
其中η\etaη为学习率。
(2)更新xw\mathbf x_wxw
因为L(w,j)\mathcal L(w,j)L(w,j) 关于变量xw\mathbf x_wxw和θj−1w\theta_{j-1}^wθj−1w是对称的。所以:
∂L(w,j)∂xw=[1−djw−σ(xwTθj−1w)]θj−1w\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} ∂xw∂L(w,j)=[1−djw−σ(xwTθj−1w)]θj−1w
这里存在一个问题:我们的最终目的是要求词典D中每个词的词向量,而这里的 xw\mathbf x_wxw 表示的是context(w)context(w)context(w)中各词词向量的累加。那么,如何利用∂L(w,j)∂xw\frac{\partial \mathcal L(w,j)}{\partial \mathbf x_w}∂xw∂L(w,j)来对v(w),w∈D\mathbf v(w),w \in Dv(w),w∈D 进行更新呢? word2vec中的做法很简单, 直接取
v(w):=v(w)+η∑j=2lw∂L(w,j)∂xw,w∈context(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=2∑lw∂xw∂L(w,j),w∈context(w)
注:既然xw\mathbf x_wxw 本身就是context(w)context(w)context(w)中各个词向量的累加,求完梯度后也应该将其贡献到每个分量上。
下面是CBOW模型中采用的随机梯度上升法伪代码:
Skip-gram 模型
基本结构
Skip-gram 模型的结构也是三层,下面以样本(w,context(w))(w,context(w))(w,context(w))为例说明。如下图所示:
(1)输入层:只包含当前样本中心词www词向量v(w)∈Rm\mathbf v(w) \in \mathbf R^mv(w)∈Rm ,每个词向量的长度是mmm。
(2)投影层:恒等投影,即和输入层一样,保留是为了与CBOW对比。
(3)输出层:与CBOW类似。
对于Skip-gram模型,已知的是当前词www,需要对其上下文context(w)context(w)context(w)中的词进行预测,所以:
p(context(w)∣w)=∏u∈context(w)p(u∣w)p(context(w)|w) = \prod_{u \in context(w)} p(u|w) p(context(w)∣w)=u∈context(w)∏p(u∣w)
类似于CBOW,所以:
p(u∣w)=∏j=2lup(dju∣v(w),θj−1u)p(u|w) = \prod_{j=2}^{l^u}p(d_j^u|\mathbf v(w),\theta_{j-1}^u) p(u∣w)=j=2∏lup(dju∣v(w),θj−1u)
其中:
p(dju∣v(w),θj−1u)=[σ(v(w)Tθj−1u)]1−dju⋅[1−σ(v(w)Tθj−1u)]djup(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(dju∣v(w),θj−1u)=[σ(v(w)Tθj−1u)]1−dju⋅[1−σ(v(w)Tθj−1u)]dju
所以我们的优化目标是:
L=∑w∈Clog∏u∈context(w)∏j=2lu{[σ(v(w)Tθj−1u)]1−dju⋅[1−σ(v(w)Tθj−1u)]dju}=∑w∈C∑u∈context(w)∑j=2lu{(1−dju)log[σ(v(w)Tθj−1u)]+djulog[1−σ(v(w)Tθj−1u)]}=∑w∈C∑u∈context(w)∑j=2luL(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=w∈C∑logu∈context(w)∏j=2∏lu{[σ(v(w)Tθj−1u)]1−dju⋅[1−σ(v(w)Tθj−1u)]dju}=w∈C∑u∈context(w)∑j=2∑lu{(1−dju)log[σ(v(w)Tθj−1u)]+djulog[1−σ(v(w)Tθj−1u)]}=w∈C∑u∈context(w)∑j=2∑lu L(w,u,j)
采用随机梯度上升法将这个函数最大化。
梯度计算
(1)更新θj−1u\theta_{j-1}^uθj−1u
因为:
∂L(w,u,j)∂θj−1u=∂{[σ(v(w)Tθj−1u)]1−dju⋅[1−σ(v(w)Tθj−1u)]dju}∂θj−1u=(1−dju)[1−σ(v(w)Tθj−1u)]v(w)−djuσ(v(w)Tθj−1u)v(w)={(1−dju)[1−σ(v(w)Tθj−1u)]−djuσ(v(w)Tθj−1u)}v(w)=[1−dju−σ(v(w)Tθj−1u)]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} ∂θj−1u∂L(w,u,j)=∂θj−1u∂{[σ(v(w)Tθj−1u)]1−dju⋅[1−σ(v(w)Tθj−1u)]dju}=(1−dju)[1−σ(v(w)Tθj−1u)]v(w)−djuσ(v(w)Tθj−1u)v(w)={(1−dju)[1−σ(v(w)Tθj−1u)]−djuσ(v(w)Tθj−1u)}v(w)=[1−dju−σ(v(w)Tθj−1u)]v(w)
所以 θj−1w\theta_{j-1}^wθj−1w更新公式为:
θj−1u:=θj−1u+η[1−dju−σ(v(w)Tθj−1u)]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) θj−1u:=θj−1u+η[1−dju−σ(v(w)Tθj−1u)]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−1w\theta_{j-1}^wθj−1w是对称的。所以:
∂L(w,u,j)∂v(w)=[1−dju−σ(v(w)Tθj−1u)]θj−1u\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)=[1−dju−σ(v(w)Tθj−1u)]θj−1u
所以,v(w)\mathbf v(w)v(w)更新公式为:
v(w):=v(w)+η∑u∈context(w)∑j=2lw∂L(w,u,j)∂v(w),w∈context(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)+ηu∈context(w)∑j=2∑lw∂v(w)∂L(w,u,j),w∈context(w)
具体伪代码如下:
与 CBOW 相比,最大的区别是多个了外层循环。
优缺点分析
使用霍夫曼树来代替传统的神经网络,避免了从隐藏层到输出的softmax层这里的计算,也避免计算所有词的softmax概率。
但是如果我们的训练样本里的中心词www是一个很生僻的词,那么就得在霍夫曼树中辛苦的向下走很久了。解决这个问题则是采用基于Negative Sampling的模型。
参考文章:
word2vec 中的数学原理详解
基于Hierarchical Softmax的word2vec模型
【word2vec】篇二:基于Hierarchical Softmax的 CBOW 模型和 Skip-gram 模型相关推荐
- 【word2vec】篇三:基于Negative Sampling 的 CBOW 模型和 Skip-gram 模型
系列文章: [word2vec]篇一:理解词向量.CBOW与Skip-Gram等知识 [word2vec]篇二:基于Hierarchical Softmax的 CBOW 模型和 Skip-gram 模 ...
- 基于JVM原理、JMM模型和CPU缓存模型深入理解Java并发编程
许多以Java多线程开发为主题的技术书籍,都会把对Java虚拟机和Java内存模型的讲解,作为讲授Java并发编程开发的主要内容,有的还深入到计算机系统的内存.CPU.缓存等予以说明.实际上,在实际的 ...
- word2vec原理(二):基于Hierarchical Softmax的模型
在word2vec原理(一) CBOW与Skip-Gram模型基础中,说到了使用神经网络的方法来得到词向量语言模型的原理和一些问题,现在开始关注word2vec的语言模型如何改进传统的神经网络的方法. ...
- word2vec 中的数学原理具体解释(四)基于 Hierarchical Softmax 的模型
word2vec 是 Google 于 2013 年开源推出的一个用于获取 word vector 的工具包,它简单.高效,因此引起了非常多人的关注.因为 word2vec 的作者 Tomas Mik ...
- 学习笔记(02):自然语言处理Word2Vec视频学习教程-Hierarchical Softmax
立即学习:https://edu.csdn.net/course/play/5226/94796?utm_source=blogtoedu 分层softmax, Cbrow 根据上下文预测当前词语的出 ...
- Word2vec之CBOW模型和Skip-gram模型形象解释
Word2vec中两个重要模型是:CBOW和Skip-gram模型 首先Wordvec的目标是:将一个词表示成一个向量 这里首先说下我对CBOW模型的理解 这是主要是举个例子简化下 首先说下CBOW的 ...
- NLP | Word2Vec之基于Negative Sampling的 CBOW 和 skip-gram 模型
前面介绍了基于Hierarchical Softmax的 skip-gram 和 CBOW 模型,虽然我们使用霍夫曼树代替传统的神经网络,可以提高模型训练的效率.但是如果我们的训练样本里的中心词www ...
- word2vec原理及其Hierarchical Softmax优化
文章目录 一.什么是word2vec? 1.1 词嵌入(word embedding)介绍 1.2 word2vec概述 二.CBOW模型 2.1 Context滑动窗口 2.2 模型结构 三.Hie ...
- 【基于WPF+OneNote+Oracle的中文图片识别系统阶段总结】之篇二:基于OneNote难点突破和批量识别...
篇一:WPF常用知识以及本项目设计总结:http://www.cnblogs.com/baiboy/p/wpf.html 篇二:基于OneNote难点突破和批量识别:http://www.cnblog ...
最新文章
- Android测试分析3
- easyui-window窗口不遮挡_眼睛是心灵的窗口、佩戴舒适又时尚的米家防蓝光护目镜 Pro...
- Drools学习 入门实例
- python 各个模块的简单介绍 转载
- mac 下安装pip
- OpenGL ES Emulator再次横向比较
- java jdk1 5手机版,java jdk1.7|java7_绿茶手机网
- 微信小程序sass不编译怎么办_不吹牛,四款免费实用的微信小程序,打开立即使用!...
- XCode出现Could not locate device support files的解决办法
- OLS最小二乘法和2SLS两阶段…
- Path 贝塞尔曲线 练习 Demo
- UIPATH Timeout reached
- 模数转换器matlab仿真,基于MATLAB的1.5位/级10位流水线结构模数转换器系统仿真(图)...
- [转]对Android开发者有益的40条优化建议
- stimulsoft mysql_StimulSoft——将炫酷的报表写入你的应用程序
- Win10-1809 离线安装 .net framework 3.5
- js终止程序执行的方法
- 摆脱处男_是时候摆脱我们的密码了
- 【编程杂谈】【书单】-陈皓大佬推荐书单
- vs2010 玩转金山界面库 (2) 应用基础