人工智能-深度学习案例:混合模型(神经网络VGG16+Kmeans+Meanshift+PCA等技术)实现苹果的分类
本次案例通过少样本的数据集,进行数据的增强完成数据集的准备。使用VGG16模型完成数据的特征提取。尝试使用Kmeans模型、MeanShift模型对数据进行分类。最后使用PCA降维处理减少执行时间,并保证了准确率。
一、任务说明:
根据original_data样本,建立模型,对test_data的图片进行普通/其他苹果的判断:
①:数据增强,扩充确认为普通苹果的样本数量
②:特征提取,使用VGG模型提取图像特征
③:Kmeans模型尝试普通、其他苹果聚类
④:MeanShift模型提升模型表现
⑤:数据降维PCA处理,提升模型表现
二、环境及数据集准备
环境要求
环境为本人所使用环境,版本差别不大应该也可完成本案例。
具体环境如下:
- Python3.10.7
- Anaconda3-2022.05
- Jupyter6.4.12
案例所需数据集
本案例所使用的数据集为本人自己制作,如需学习外使用请联系本人。
数据集链接:
https://pan.baidu.com/s/1_0StR87D5HwxxS9fcRRVHA?pwd=0806
提取码:0806
三、任务详细流程
说明:
类似这种苹果为本案例定义的普通苹果(现买现拍的)
类似这种苹果为本案例定义的其他苹果(网络途径获取)
①:数据增强
在实际生产生活中,大量数据集的收集会造成成本、时间等的耗费。因此,我们可以选取少量的数据,在对这些数据进行一些处理去生成更多的数据来达到训练模型的作用。
对于图片数据,我们可以对图片进行旋转、平移、拉伸等操作去生成大量数据集。
#一、数据增强
#由于数据集数据较少,需要进行数据增强
from keras.preprocessing.image import ImageDataGenerator
#图片被加强的文件路径
#另外需要在此文件夹original_data中创建一个子文件夹apple,并把正样本数据(待增强数据)复制到子文件夹中
#因为实际中,正样本数据应该占数据集的大多数
path='C:\\test\\original_data'
#图片加强后的文件路径
dst_path='C:\\test\\gen_data'
#图片增强方式的配置
datagen=ImageDataGenerator(rotation_range=10,width_shift_range=0.1,height_shift_range=0.02
,horizontal_flip=True,vertical_flip=True)
#设置路径及尺寸
#(224,224)是VGG16模型要求的
#batch_size=2:每批次生成两张图片
#save_prefix='gen':生成图片的前缀
gen=datagen.flow_from_directory(path,target_size=(224,224),batch_size=2
,save_to_dir=dst_path,save_prefix='gen'
,save_format='jpg')
for i in range(100):
gen.next()
②:特征提取
通过使用VGG16模型的特征提取功能来完成,本案例只使用VGG16模型的前部分,不使用VGG16的全连接层。
单张图片的特征提取
这里的train_dta文件夹是上述图片增强文件夹gen_data和初始文件夹(去掉子文件夹apple)original_data合并之后的文件夹。
#二、单张图片的展示及特征提取
#读取载入一张图片
from keras.preprocessing.image import load_img,img_to_array
img_path='C:\\test\\train_data\\1.jpg'
img=load_img(img_path,target_size=(224,224))
type(img)
#单张图片的展示
%matplotlib inline
from matplotlib import pyplot as plt
fig1=plt.figure(figsize=(5,5))
plt.imshow(img)
在进行特征提取前需要对图片数据做一些处理,也就是将图片数据转化为能够直接使用VGG16模型的形式。
#将图片信息转化为数组的形式
img=img_to_array(img)
type(img)
print(img.shape)
#数据的处理
#不加这两行,会挂掉内核,具体为啥不知道
import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
from keras.applications.vgg16 import VGG16
from keras.applications.vgg16 import preprocess_input
import numpy as np
#去掉VGG16模型中的全连接层,只保留其余层的系数,用于提取特征
model_vgg=VGG16(weights='imagenet',include_top=False)
#数据增加维度--表示第几张图片
x=np.expand_dims(img,axis=0)
#图片的预处理,使数据可以直接用于VGG16模型
x=preprocess_input(x)
print(x.shape)
#特征提取
features=model_vgg.predict(x)
print(features.shape)
至此单张图片的特征提取完毕、依据单张图片特征提取的流程,写出多张图片特征提取的方法。
多张图片的特征提取
这里暂时只提取训练数据集
#图片的批量处理
#加载图片名称
import os
folder='C:\\test\\train_data'
dirs=os.listdir(folder)
#名称合并---确保得到的文件都是.jpg结尾的
img_path=[]
for i in dirs:
if os.path.splitext(i)[1]=='.jpg':
img_path.append(i)
img_path=[folder+"//"+i for i in img_path]
print(img_path)
#定义一个单张图片特征提取的方法---为了下面多张图片特征提取时可以调用
def modelProcess(img_path,model):
#根据提供的路径加载数据,并固定格式大小
img=load_img(img_path,target_size=(224,224))
#将图片信息转化为数组的形式
img=img_to_array(img)
#增加维度---增加的维度表示为第几张图片
x=np.expand_dims(img,axis=0)
#图片的预处理,使数据可以直接用于VGG16模型
x=preprocess_input(x)
#特征提取
x_VGG=model.predict(x)
#摊开数据
x_VGG=x_VGG.reshape(1,7*7*512)
return x_VGG
#图片批处理
#暂时创建一个数值全为0,7*7*512列的数组
features_train=np.zeros([len(img_path),7*7*512])
for i in range(len(img_path)):
#调用上述方法,完成特征提取
feature_i=modelProcess(img_path[i],model_vgg)
print('preprocessed:',img_path[i])
features_train[i]=feature_i
print(features_train.shape)
③:KMeans模型尝试第一次分类
#定义x
x=features_train
#四、创建无监督的KMeans模型
from sklearn.cluster import KMeans
cnn_kmeans=KMeans(n_clusters=2,max_iter=2000)
cnn_kmeans.fit(x)
#预测结果
y_predict_kmeans=cnn_kmeans.predict(x)
print(y_predict_kmeans)
#统计每个类别的数量
from collections import Counter
print(Counter(y_predict_kmeans))
只看这种数字形式的预测结果,我们就能感觉到使用KMeans预测的训练数据集的结果不太好。我们再进行图片展示来观察一下。
#可视化结果
fig2=plt.figure(figsize=(10,40))
for i in range(46):
for j in range(5):
#读取数据
img=load_img(img_path[i*5+j])
plt.subplot(46,5,i*5+j+1)
plt.title('apple' if y_predict_kmeans[i*5+j]==normal_apple_id else 'others')
plt.imshow(img),plt.axis('off')
可视化之后发现训练数据集的预测结果不如人意,下面进行测试数据集的预测
#测试图片处理
#加载图片名称
import os
folder_test='C:\\test\\test_data'
dirs_test=os.listdir(folder_test)
#名称合并---确保得到的文件都是.jpg结尾的
img_path_test=[]
for i in dirs_test:
if os.path.splitext(i)[1]=='.jpg':
img_path_test.append(i)
img_path_test=[folder_test+"//"+i for i in img_path_test]
print(img_path_test)
#测试图片批处理
#暂时创建一个数值全为0,7*7*512列的数组
features_test=np.zeros([len(img_path_test),7*7*512])
for i in range(len(img_path_test)):
#调用上述方法,完成特征提取
feature_i=modelProcess(img_path_test[i],model_vgg)
print('preprocessed:',img_path_test[i])
features_test[i]=feature_i
x_test=features_test
#测试集的结果预测
y_predict_kmeans_test=cnn_kmeans.predict(x_test)
print(y_predict_kmeans_test)
#测试数据的可视化
#可视化结果
fig3=plt.figure(figsize=(10,10))
for i in range(3):
for j in range(4):
#读取数据
img=load_img(img_path_test[i*4+j])
plt.subplot(3,4,i*4+j+1)
plt.title('apple' if y_predict_kmeans[i*4+j]==normal_apple_id else 'others')
plt.imshow(img),plt.axis('off')
#可以看到,无论是训练数据,还是测试数据,结果都很糟糕
测试数据集的结果也很不妙,这时候,我们就要考虑使用别的算法完成任务。
分析本次案例的任务,主要是将苹果进行分类,即分成普通苹果和其它苹果。而KMeans算法的核心是以k个点为中心进行聚类,本实验为二分类,但数据集中的其它苹果的特征差异也很大,所以就会造成下图这种情况:
因此我们想到了另一种算法很适用于本案例——MeanShift
④:MeanShift尝试第二次分类
#换用Meanshift进行训练
from sklearn.cluster import MeanShift,estimate_bandwidth
#n_samples=140:表示每140个样本进行评估(可自行调节尝试)
#bw:区域大小
bw=estimate_bandwidth(x,n_samples=140)
print(bw)
#创建模型
cnn_ms=MeanShift(bandwidth=bw)
cnn_ms.fit(x)
#预测
y_predict_ms=cnn_ms.predict(x)
print(y_predict_ms)
在这里插入代码片
#预测结果统计
print(Counter(y_predict_ms))
眼前一亮,接着进行训练集预测结果可视化
#可视化结果
fig4=plt.figure(figsize=(10,40))
for i in range(46):
for j in range(5):
#读取数据
img=load_img(img_path[i*5+j])
plt.subplot(46,5,i*5+j+1)
plt.title('apple' if y_predict_ms[i*5+j]==normal_apple_id else 'others')
plt.imshow(img),plt.axis('off')
几乎全对,接着进行测试数据集的预测,判断是否过拟合。
#预测测试数据
y_predict_ms_test=cnn_ms.predict(x_test)
print(y_predict_ms_test)
#可视化测试数据
fig5=plt.figure(figsize=(10,10))
for i in range(3):
for j in range(4):
#读取数据
img=load_img(img_path_test[i*4+j])
plt.subplot(3,4,i*4+j+1)
plt.title('apple' if y_predict_ms_test[i*4+j]==normal_apple_id else 'others')
plt.imshow(img),plt.axis('off')
测试数据集的表现也很棒,这里要说明一下,准确率太高有一方面原因是数据集的原因,本次实验的普通苹果为同一个苹果(经费紧张)的不同角度拍摄所得,所以相似度极高。而普通苹果和其他苹果的特征形态差异较大,计算机学习起来会和容易分变成来。
除此之外,在上面的图片数据处理、特征提取等地方发现会耗费大量时间。这里的train_data有230张图片,大多数情况下的训练数据要远大于这些的,我们需要一种在保证准确率的情况下加快特征提取的方法。因此,我们想到了PCA降维处理。
⑤:PCA+MeanShift尝试第三次分类
#PCA降维处理
from sklearn.preprocessing import StandardScaler
#数据的标准化处理
stds=StandardScaler()
x_norm=stds.fit_transform(x)
#PCA处理---找出主成分
from sklearn.decomposition import PCA
#n_components=200:将数据降到多少维(可以自行尝试调节)
pca=PCA(n_components=200)
#x_pca:降维后的数据
x_pca=pca.fit_transform(x_norm)
#计算方差比例
#这里的方差越大数据越分散,选取的主成分越准确
var_ratio=pca.explained_variance_ratio_
print(np.sum(var_ratio))
print(x_pca.shape,x.shape)
#PCA+MeanShift
from sklearn.cluster import MeanShift,estimate_bandwidth
#n_samples=140:表示每140个样本进行评估(可自行调节尝试)
#bw:区域大小
bw=estimate_bandwidth(x_pca,n_samples=140)
print(bw)
#创建模型
cnn_pca_ms=MeanShift(bandwidth=bw)
cnn_pca_ms.fit(x_pca)
#预测
y_predict_pca_ms=cnn_pca_ms.predict(x_pca)
print(y_predict_pca_ms)
#预测结果统计
print(Counter(y_predict_pca_ms))
可以看到经过PCA降维处理后的训练数据的预测结果也是很好的,接着进行数据可视化。
normal_apple_id=0
#可视化结果
fig6=plt.figure(figsize=(10,40))
for i in range(46):
for j in range(5):
#读取数据
img=load_img(img_path[i*5+j])
plt.subplot(46,5,i*5+j+1)
plt.title('apple' if y_predict_pca_ms[i*5+j]==normal_apple_id else 'others')
plt.imshow(img),plt.axis('off')
接着进行测试数据集的预测。
#数据标准化处理
x_norm_test=stds.transform(x_test)
x_pca_test=pca.transform(x_norm_test)
y_predict_pca_ms_test=cnn_pca_ms.predict(x_pca_test)
print(y_predict_pca_ms_test)
测试数据集的可视化
#可视化测试数据
fig7=plt.figure(figsize=(10,10))
for i in range(3):
for j in range(4):
#读取数据
img=load_img(img_path_test[i*4+j])
plt.subplot(3,4,i*4+j+1)
plt.title('apple' if y_predict_pca_ms_test[i*4+j]==normal_apple_id else 'others')
plt.imshow(img),plt.axis('off')
效果很棒。
总结
本次案例通过少样本的数据集,进行数据的增强完成数据集的准备。使用VGG16模型完成数据的特征提取。尝试使用Kmeans模型、MeanShift模型对数据进行分类。最后使用PCA降维处理减少执行时间,并保证了准确率。
在生活工作中、我们可以去尝试很多模型、或者去调整模型参数去解决生活中的问题。
更多推荐
所有评论(0)