在这个例子中,使用了大量的人脸图像数据集来学习一组20x20大小的图像块,这些图像块构成了人脸。从编程的角度来看,这非常有趣,因为它展示了如何使用scikit-learn的在线API来分块处理非常大的数据集。做法是一次加载一张图像,并从这张图像中随机提取50个图像块。一旦累积了500个这样的图像块(使用10张图像),就运行在线KMeans对象MiniBatchKMeans的partial_fit方法。
MiniBatchKMeans的verbose设置使能够看到在连续调用partial_fit时,一些聚类被重新分配。这是因为它们所代表的图像块数量变得太低,选择一个新的随机聚类是更好的选择。
from sklearn import datasets
faces = datasets.fetch_olivetti_faces()
首先导入必要的库,然后初始化一个MiniBatchKMeans对象,设置聚类数量为81,并设置随机状态和verbose参数。接着,定义了图像块的大小,并初始化了一个空的缓冲区。记录了开始时间,并开始了在线学习过程,循环遍历整个数据集6次。
import time
import numpy as np
from sklearn.cluster import MiniBatchKMeans
from sklearn.feature_extraction.image import extract_patches_2d
print("开始学习图像字典...")
rng = np.random.RandomState(0)
kmeans = MiniBatchKMeans(n_clusters=81, random_state=rng, verbose=True, n_init=3)
patch_size = (20, 20)
buffer = []
t0 = time.time()
# 在线学习部分:循环遍历整个数据集6次
index = 0
for _ in range(6):
for img in faces.images:
data = extract_patches_2d(img, patch_size, max_patches=50, random_state=rng)
data = np.reshape(data, (len(data), -1))
buffer.append(data)
index += 1
if index % 10 == 0:
data = np.concatenate(buffer, axis=0)
data -= np.mean(data, axis=0)
data /= np.std(data, axis=0)
kmeans.partial_fit(data)
buffer = []
if index % 100 == 0:
print("Partial fit of %4i out of %i" % (index, 6*len(faces.images)))
dt = time.time() - t0
print("完成时间:%.2f s." % dt)
在学习过程中,可以看到一些聚类中心被重新分配,这是因为它们所代表的图像块数量变得太低。最终,完成了学习过程,并输出了总的运行时间。
最后,使用matplotlib库来绘制学习到的图像块。创建了一个图形,并为每个聚类中心绘制了一个子图。每个子图显示了一个图像块,并设置了灰度颜色映射和最近邻插值。还设置了标题和子图的调整参数,以确保图形的布局合理。
import matplotlib.pyplot as plt
plt.figure(figsize=(4.2, 4))
for i, patch in enumerate(kmeans.cluster_centers_):
plt.subplot(9, 9, i + 1)
plt.imshow(patch.reshape(patch_size), cmap=plt.cm.gray, interpolation="nearest")
plt.xticks(())
plt.yticks(())
plt.suptitle("人脸图像块\n训练时间 %.1f s 在 %d 个图像块上" % (dt, 8*len(faces.images)), fontsize=16)
plt.subplots_adjust(0.08, 0.02, 0.92, 0.85, 0.08, 0.23)
plt.show()