sklearn KMeans包结果无法复现
随机问题
numpy等随机数
使用numpy等随机数时,一定要注意随机函数会首到上次随机结果的影响。e.g.
# 如果代码如下:
import numpy as np
np.random.seed(20) # 为numpy设置随机种子
for i in range(10):
x = np.random.random()
print(x)
会发现每次随机的结果不一致,这是由于第二次随机时会收到第一次影响。
如果我们需要for里面的每次随机一致需要将种子设置放在for里面,e.g
import numpy as np
for i in range(10):
np.random.seed(20) # 为numpy设置随机种子
x = np.random.random()
print(x)
sklearn KMeans包结果无法复现问题
今天写代码有个问题困扰了我很久,今天分享出来,以及解决办法。其中出现问题代码片段简单化如下:
import os
import random
import numpy as np
import torch
# from kmeans_pytorch import kmeans
from sklearn.cluster import KMeans
def setup_seed(seed):
random.seed(seed)
np.random.seed(seed) # 为numpy设置随机种子
torch.manual_seed(seed) # 为CPU设置随机种子
torch.cuda.manual_seed(seed) # 为当前GPU设置随机种子
setup_seed(20)
center = []
pred = []
data = np.random.random([500,512])
for i in range(10):
print("k-means++: {}".format(i))
k = KMeans(n_clusters=10,n_init=10,init='k-means++',random_state=0)
k.fit_predict(data)
center.append(k.cluster_centers_)
pred.append(k.labels_)
for i in range(9):
print("-------------------center------------")
print(str(center[i] == center[i+1]).count("False"))
print("-------------------pred------------")
print(str(pred[i] == pred[i+1]).count("False"))
代码大概意思就是使用kmeans将数据重复聚类10次,并统计查看每次聚类结果中的聚类中心和聚类标签是否一致。这种需求是一般是为了实验的可复现。
当我们的数据量较小时,如上500个样本,每个512维度不会出现不一致情况。
但是一旦我们将数据量提升至5000或者50000(对于一般数据来说不算多),就会发现每次聚类结果并不会一致。下面是5000
对于仅仅需要label的算法而言,影响不大。但是像DEC(深度嵌入聚类)需要使用kmeans算法初始化质心而言就会使得每次算法结果不一致,使得参数无从下手调整。
问题:经过多次实验,初步认为是由于kmeans精度所导致的,每次Debug时,前几位数每次都是一致的,但是随着epoch的增加后面8,9位小数点的累加就会导致结果偏差。
解决:1. 可以使用np.round()限制小数点位数。2. 使用pytorch-kmeans(推荐)
不过其中需要注意:他聚类的是tensor,其次正如开始所述的随机问题,为了保证每次结果的一致我们需要每次for设定一次种子让pytorch-kmeans的质心每次随机初始化都一致。
import os
import random
import numpy as np
import torch
from kmeans_pytorch import kmeans
# from sklearn.cluster import KMeans
def setup_seed(seed):
random.seed(seed)
np.random.seed(seed) # 为numpy设置随机种子
torch.manual_seed(seed) # 为CPU设置随机种子
torch.cuda.manual_seed(seed) # 为当前GPU设置随机种子
setup_seed(20)
center = []
pred = []
data = torch.from_numpy(np.random.random([5000,512]))
for i in range(10):
print("k-means++: {}".format(i))
np.random.seed(20) # 为numpy设置随机种子
cluster_ids_x, cluster_centers = kmeans(X=data, num_clusters=10, distance='euclidean', device=torch.device("cuda:0"))
center.append(cluster_centers)
pred.append(cluster_ids_x)
for i in range(9):
print("-------------------center------------")
print(str(center[i] == center[i+1]).count("False"))
print("-------------------pred------------")
print(str(pred[i] == pred[i+1]).count("False"))
结果: