TSNE的实现总体上并不复杂,麻烦的是其超高的浮点运算和大型矩阵的操控,在上一篇Largevis的算法中,TangJian大神很明显用的是MATLAB,我这里贴出Python版本的代码,和大家一起学习。
代码分为几个模块
1、计算高维空间分布P
2、计算低维空间分布Q
3、计算梯度
4、主函数,进行迭代
1、计算高维空间分布P
def cal_matrix_P(X,neighbors):
entropy=numpy.log(neighbors)
n1,n2=X.shape
D=numpy.square(metrics.pairwise_distances(X))
D_sort=numpy.argsort(D,axis=1)
P=numpy.zeros((n1,n1))
for i in xrange(n1):
Di=D[i,D_sort[i,1:]]
P[i,D_sort[i,1:]]=cal_p(Di,entropy=entropy)
P=(P+numpy.transpose(P))/(2*n1)
P=numpy.maximum(P,1e-100)
return P
neighbors为邻域点个数,P是逐行计算,最后在计算平均,使其成为对称矩阵的,每一行的计算都需要找到一个合适beta,使得这一行的分布熵小于等于log(neighbors),我这里偷了个懒,没有找邻域点,而是对数据进行了排序,选取排序前面k个作为邻域点,在解决大规模问题时,有兴趣的可以自行改进。
def cal_p(D,entropy,K=50):
beta=1.0
H=cal_entropy(D,beta)
error=H-entropy
k=0
betamin=-numpy.inf
betamax=numpy.inf
while numpy.abs(error)>1e-4 and k<=K:
if error > 0:
betamin=copy.deepcopy(beta)
if betamax==numpy.inf:
beta=beta*2
else:
beta=(beta+betamax)/2
else:
betamax=copy.deepcopy(beta)
if betamin==-numpy.inf:
beta=beta/2
else:
beta=(beta+betamin)/2
H=cal_entropy(D,beta)
error=H-entropy
k+=1
P=numpy.exp(-D*beta)
P=P/numpy.sum(P)
return P