哈夫曼树Huffman tree
一句话解释,哈夫曼树将一个softmax的多分类问题转换成了多个logistic的二分类问题
以连续词袋模型(CBOW)为例,输入多个词向量,输出层则输出最可能的w,最简的实现自然是softmax,但为了计算难度,使用哈夫曼树简化计算
p
w
p^w
pw为从根节点到词汇w 叶子节点对应的路径
d
j
w
{d_j^w}
djw表示
p
w
p^w
pw中第j个节点对应的编码,而
θ
1
w
\theta^w_1
θ1w表示路径
p
w
p^w
pw中的参数向量
根据上述定义,我们可以写出基于Hierarchical Softmax优化的连续词袋模型(CBOW)的条件概率:
p ( w ∣ context ( w ) ) = ∏ j = 1 I w p ( d j w ∣ x w ; θ j − 1 w )
其中,每一项都是一个Logistic回归
后半部分略去,有想法在写
负采样优化每次采样一小部分,更新一个训练样本的一小部分权重
Logistic回归
用sigmoid函数模拟阶跃函数,sigmoid函数即:
σ
=
1
1
+
e
−
z
=
1
1
+
e
−
w
T
x
\sigma =\frac{1}{1+e^{-z}}=\frac{1}{1+e^{-w^T x}}
σ=1+e−z1=1+e−wTx1
定义对数几率为
l
n
y
1
−
y
=
w
T
x
ln\frac{y}{1-y}=w^T x
ln1−yy=wTx
显然,y可视为正例的概率,1-y为负例的概率则
p
(
y
=
1
)
=
e
w
T
x
1
+
e
w
T
x
=
1
1
+
e
−
w
T
x
=
σ
p(y=1)=\frac{e^{w^T x}}{1+e^{w^T x}}=\frac{1}{1+e^{-w^T x}}=\sigma
p(y=1)=1+ewTxewTx=1+e−wTx1=σ
则
p
(
y
=
0
)
=
1
−
σ
p(y=0)=1-\sigma
p(y=0)=1−σ
用梯度上升算法进行Logistic回归
w
=
w
+
∇
f
(
w
)
w=w+\nabla{f(w)}
w=w+∇f(w)
对应代码如下
import math
import numpy as np
data = [] # 特征数据
labels = [] # 目标数据
def sigmoid(x):
sig = 1/(1+math.exp(-x))
return sig
def grad_ascent():
datamat = np.mat(data)
labelsmat = np.mat(labels).transpose()
m, n = np.shape(datamat)
weights = np.ones(n, 1) # 初始化weight
alpha = 0.001
iters = 500
for i in range(iters):
h = sigmoid(datamat * weights)
error = labelsmat - h
weights = weights + alpha * datamat.transpose() * error
return weights
关于
w
=
w
+
∇
f
(
w
)
w=w+\nabla{f(w)}
w=w+∇f(w)与weights = weights + alpha * datamat.transpose() * error等价的证明
∇
f
(
w
)
=
∂
e
r
r
o
r
∂
w
=
−
∂
D
∗
w
∂
w
⋅
∂
σ
(
D
∗
w
)
∂
(
D
∗
w
)
=
−
D
T
σ
(
D
∗
w
)
[
1
−
σ
(
D
∗
w
)
]
\nabla{f(w)}=\frac{\partial error}{\partial w}=-\frac{\partial D*w}{\partial w}\cdot \frac{\partial \sigma( D*w)}{\partial (D*w)}=-D^T\sigma(D*w)[1 - \sigma(D*w)]
∇f(w)=∂w∂error=−∂w∂D∗w⋅∂(D∗w)∂σ(D∗w)=−DTσ(D∗w)[1−σ(D∗w)]
略去高阶项,加入常数项得:
∇
f
(
w
)
=
−
D
T
σ
(
D
∗
w
)
=
D
T
(
e
r
r
o
r
−
l
a
b
e
l
s
)
\nabla{f(w)}=-D^T\sigma(D*w)=D^T(error-labels)
∇f(w)=−DTσ(D∗w)=DT(error−labels)即
∇
f
(
w
)
=
D
T
e
r
r
o
r
\nabla{f(w)}=D^Terror
∇f(w)=DTerror
改进的随机梯度上升算法:
# 改进的随机梯度上升算法
def stocGradAscent1(dataMatrix, classLabels, numIter=150): # dataMatIn数据集、classLabels数据标签、numIter迭代次数
m, n = shape(dataMatrix) # 获取数据集矩阵的大小,m为行数,n为列数
weights = ones(n) # 所以初始化为1
for j in range(numIter):
dataIndex = list(range(m)) # 创建数据下标列表
for i in range(m):
alpha = 4 / (1.0 + j + i) + 0.0001 # apha目标移动的步长,每次迭代调整
randIndex = int(random.uniform(0, len(dataIndex))) # 随机选取更新样本
h = sigmoid(sum(dataMatrix[randIndex] * weights)) # 矩阵相乘,计算sigmoid函数
error = classLabels[randIndex] - h # 计算误差
weights = weights + alpha * error * dataMatrix[randIndex] # 矩阵相乘,更新权重
del (dataIndex[randIndex]) # 删除已使用过的样本
return weights