一、数据集和模型文件准备
1.1 数据集下载
使用kaggle猫狗大战的test中的前100张图像作为数据集1:dogs-vs-cats
使用100张红外船舶图像作为数据集2:
1.2 模型文件下载(可忽略)
通过使用更大、更复杂的模型,可以获得更高的准确率,预训练模型是一个很好的选择,我们可以直接使用预训练模型来完成分类任务,因为预训练模型通常已经在大型的数据集上进行过训练,通常用于完成大型的图像分类任务。
tf.keras.applications中有一些预定义好的经典卷积神经网络结构(Application应用):
我们可以直接调用这些经典的卷积神经网络结构(甚至载入预训练的参数),而无需手动来构建网络结构。
例如,本文将要用到的模型是由谷歌开发的 MobileNetV2 网络结构,该模型已经在 ImageNet 数据集上进行过预训练,共含有 1.4M 张图像,而且学习了常见的 1000 种物体的基本特征,因此,该模型具有强大的特征提取能力。
model = tf.keras.applications.MobileNetV2()
当执行以上代码时,TensorFlow会自动从网络上下载 MobileNetV2 网络结构,运行代码后需要等待一会会儿~~。MobileNetV2模型的速度很快,而且耗费资源也不是很多。
二、K-means聚类实现数据集的聚类
2.1 K-means的原理和算法
详细原理:【机器学习】K-means(非常详细)
定义
聚类是一个将数据集中在某些方面相似的数据成员进行分类组织的过程,聚类就是一种发现这种内在结构的技术,聚类技术经常被称为无监督学习。
k均值聚类是最著名的划分聚类算法,由于简洁和效率使得他成为所有聚类算法中最广泛使用的。给定一个数据点集合和需要的聚类数目k,k由用户指定,k均值算法根据某个距离函数反复把数据分入k个聚类中。
算法
先随机选取K个对象作为初始的聚类中心。然后计算每个对象与各个种子聚类中心之间的距离,把每个对象分配给距离它最近的聚类中心。聚类中心以及分配给它们的对象就代表一个聚类。一旦全部对象都被分配了,每个聚类的聚类中心会根据聚类中现有的对象被重新计算。这个过程将不断重复直到满足某个终止条件。终止条件可以是以下任何一个:
- 没有(或最小数目)对象被重新分配给不同的聚类。
- 没有(或最小数目)聚类中心再发生变化。
- 误差平方和局部最小。
2.2 K-means中K值的最合适取值
学习总结:K-Means算法之K值的选择
2.2.1 肘部法
2.2.1.1 手肘法的核心思想
随着聚类数 k k k的增大,样本划分会更加精细,每个簇的聚合程度会逐渐提高,那么误差平方和SSE自然会逐渐变小。并且,当k小于最佳聚类数时,由于k的增大会大幅增加每个簇的聚合程度,故SSE的下降幅度会很大;而当k到达最佳聚类数时,再增加k所得到的聚合程度回报会迅速变小,所以SSE的下降幅度会骤减;然后随着k值的继续增大而趋于平缓,也就是说SSE和k的关系图是一个手肘的形状,而这个肘部对应的k值就是数据的最佳聚类数。这也是该方法被称为手肘法的原因。
由下图,y轴为SSE(Sum of the Squared Errors-误差平方和),x轴为k的取值。随着x的增加,SSE会随之降低,当下降幅度明显趋向于缓慢的时候,取该值为K的值。
- 对于n个点的数据集,迭代计算k from 1 to n,每次聚类完成后计算每个点到其所属的簇中心的距离的平方和;
- 平方和是会逐渐变小的,直到k时平方和为0,因为每个点都是它所在的簇中心本身。
- 在这个平方和变化过程中,会出现一个拐点也即“肘”点,下降率突然变缓时即认为是佳的k值。
2.2.1.2 SSE
手肘法的评价K值好坏的标准是SSE。
S S E = ∑ p ∈ C i ∣ p − m i ∣ 2 SSE=\sum_{p∈C_i}|p-m_i|^2 SSE=p∈Ci∑∣p−mi∣2
其中 C i C_i Ci代表第 i i i个簇, p p p是簇 C i C_i Ci里的样本点, m i m_i mi是簇的质心。
2.2.1.3 应用
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
import matplotlib.pyplot as plt
# 生成数据
X, y = make_blobs(n_samples=300, centers=5, n_features=5, random_state=0)
start_k=2
end_k=20
SSE = []
model = [] #保存每次的模型
kt=[]
for i in range(start_k, end_k):
kMeans = KMeans(n_clusters=i)
kMeans.fit(X)
SSE.append(kMeans.inertia_) # 保存每一个k值的SSE值
print('{} Means SSE loss = {}'.format(i, kMeans.inertia_))
model.append(kMeans)
kt.append(i)
plt.plot(kt, SSE)
plt.ylabel('Means SSE loss')
plt.ylabel('SSE ')
plt.show()
# 求二阶导数,通过sse方法计算最佳k值
kl=[]
SSE_d1 = [] #sse的一阶导数
SSE_d2 = [] #sse的二阶导数
SSE_length = len(SSE)
for i in range(1, SSE_length):
SSE_d1.append((SSE[i - 1] - SSE[i]) / 2)
for i in range(1, len(SSE_d1) - 1):
SSE_d2.append((SSE_d1[i - 1] - SSE_d1[i]) / 2)
kl.append(i)
best_model = model[SSE_d2.index(max(SSE_d2)) + 2]
print(best_model)
2.2.2 轮廓法
2.2.2.1 概述
通过聚类后的结果label来计算的一种评价指标。内部有效性指标呢设计的时候从三个方面来看聚类的有效性:
- 度量各个聚类的分离程度,理论上,类分离程度越大,结果越好。
- 度量每个类内的内在紧致性,紧致性越大,聚类效果越好。
- 度量各个类表示的复杂度,在可行的类表示中选择简单的。
在聚类问题中,Silhouette分析用来研究聚类结果的类间距离。Silhouette数值度量在相同类中的点,与不同类中的点相比的紧密程度。Silhouette图可视化这一测度,这样就提供了一种评价类个数的方法。使用Silhouette分析选择一个类个数参数n_clusters的最优值。
Silhouette 遵循类紧致性。Silhouette值用来描述一个目标对于目标所在簇与其他簇之间的相似性。其范围是从-1~+1,这个值越大表明目标与自己所在簇之间的匹配关系度越高,与其他簇的匹配关系度越低。如果这个值越高,那么聚类结果越好,如果是很小或是负值,那么可能是分簇太多或是太少造成的。Silhouette是通过一些距离矩阵来计算的。
2.2.2.2 Silhouette的定义
-
簇内不相似度
假设数据集我们已经通过聚类算法分成了很多类。对