sklearn KMeans包结果无法复现

发布时间 2023-10-06 23:14:28作者: ykxhs

随机问题

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维度不会出现不一致情况。

Untitled

但是一旦我们将数据量提升至5000或者50000(对于一般数据来说不算多),就会发现每次聚类结果并不会一致。下面是5000

Untitled

对于仅仅需要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"))

结果:

Untitled