(一)选题背景:
自古以来花便是人们生活中常见的点缀物,也是人们诸多情绪的寄托品,有许多诗人文豪托物言志写下了许多的传世佳作,探望病人时人们会送百合、康乃馨以示祝福,送出玫瑰表达自己的爱慕之情。时至今日花朵也发展出了许多的衍生物,如花语、插花技艺等。但是花朵种类繁多,一个人不可能认识所有种类的花。计算机技术发展至今日,AI技术也有了极大的进步,可以为人们的日常提供诸多便利,通过机器学习不断训练AI建立起AI对于花朵的识别能力即可帮助人们对花朵进行识别.
(二)机器学习设计案例设计方案:
从网络上获取数据集
使用工具:pycharm
给数据集中的文件打上标签,对数据进行预处理,
利用keras,构建网络,训练模型,导入图片测试模型
数据集来源:kaggle,网址:https://tianchi.aliyun.com/
(三)机器学习的实现步骤:
1.获取数据集
2.对数据集重命名
import os #导入模块 filename = 'D:\\python\\python Save\\期末\\python\\flower\\train\\dandelion' #文件地址 list_path = os.listdir(filename) #读取文件夹里面的名字 count = 1 for index in list_path: path = filename + '\\' + index # 原本文件名 new_path = filename + '\\' + f'dandelion{count}' print(new_path) os.rename(path, new_path) count += 1 print('修改完成')
重命名前:
重命名后:
3.查看各数据数量
import os train_path="flower/train/" print('train:') print(' daisy images:', len(os.listdir(train_path+"daisy"))) #菊花花数据集图片数量 print(' dandelion images:', len(os.listdir(train_path+"dandelion"))) #蒲公英数据集图片数量 print(' roses images:', len(os.listdir(train_path+"roses"))) #玫瑰花数据集图片数量 print(' tulips images:', len(os.listdir(train_path+"tulips"))) #郁金香数据集图片数量 print(' sunflowers images:', len(os.listdir(train_path+"sunflowers"))) #太阳花数据集图片数量 valid_path="flower/val/" print('val') print(' daisy images:', len(os.listdir(valid_path+"daisy"))) #菊花花数据集图片数量 print(' dandelion images:', len(os.listdir(valid_path+"dandelion"))) #蒲公英数据集图片数量 print(' roses images:', len(os.listdir(valid_path+"roses"))) #玫瑰花数据集图片数量 print(' tulips images:', len(os.listdir(valid_path+"tulips"))) #郁金香数据集图片数量 print(' sunflowers images:', len(os.listdir(valid_path+"sunflowers"))) #太阳花数据集图片数量
4.导入所需各类库
from keras import layers from keras import models from keras.models import load_model import warnings from keras import optimizers from keras.preprocessing.image import ImageDataGenerator warnings.filterwarnings("ignore") 图片数量
5.搭建神经网络
model = models.Sequential() #第一个卷积层作为输入层,32个3*3卷积核,输入形状input_shape = (150,150,3) # 输出图片尺寸:150-3+1=148*148,参数数量:32*3*3*3+32=896 model.add(layers.Conv2D(32,(3,3),activation = 'relu',input_shape = (150,150,3))) model.add(layers.MaxPooling2D((2,2)))# 输出图片尺寸:148/2=74*74 #输出图片尺寸:74-3+1=72*72,参数数量:64*3*3*32+64=18496 model.add(layers.Conv2D(64,(3,3),activation = 'relu')) model.add(layers.MaxPooling2D((2,2)))# 输出图片尺寸:72/2=36*36 # 输出图片尺寸:36-3+1=34*34,参数数量:128*3*3*64+128=73856 model.add(layers.Conv2D(128,(3,3),activation = 'relu')) model.add(layers.MaxPooling2D((2,2)))# 输出图片尺寸:34/2=17*17 model.add(layers.Conv2D(128,(3,3),activation = 'relu')) model.add(layers.MaxPooling2D((2,2))) model.add(layers.Flatten()) model.add(layers.Dense(512,activation = 'relu')) model.add(layers.Dense(5,activation = 'softmax'))#sigmoid分类,输出是二元类别,softmax输出多元类别
6.编译模型
# 编译模型 # RMSprop 优化器。因为网络最后一层是单一sigmoid单元, # 所以使用二元交叉熵作为损失函数 model.compile(loss='binary_crossentropy', optimizer=optimizers.RMSprop(lr=1e-4), metrics=['acc']) #归一化 train_datagen = ImageDataGenerator(rescale = 1./255) val_datagen = ImageDataGenerator(rescale = 1./255) train_dir = 'flower/train' #指向训练集图片目录路径 #图像处理 train_generator = train_datagen.flow_from_directory( train_dir, target_size = (150,150),# 输入训练图像尺寸 batch_size = 20, class_mode = 'categorical') # validation_dir = 'flower/val' #指向验证集图片目录路径 validation_generator = val_datagen.flow_from_directory( validation_dir, target_size = (150,150), batch_size = 20, class_mode = 'categorical') for data_batch,labels_batch in train_generator: print('data batch shape:',data_batch.shape) print('data batch shape:',labels_batch.shape) break #生成器不会停止,会循环生成这些批量,所以我们就循环生成一次批量 history = model.fit(train_generator,validation_data=validation_generator,epochs=30) #保存训练模型 model.save('flower/flowermodel.h5')
7.可视化特征图
#读取.h5文件 model=load_model('flower/flowermodel.h5') #从测试集中读取一条样本 img_path = "flower/test/flower1.jpg" img = image_utils.load_img(img_path, target_size=(150,150)) img_tensor = image_utils.img_to_array(img) img_tensor = np.expand_dims(img_tensor, axis=0) img_tensor /= 255. print(img_tensor.shape)
#显示样本 plt.imshow(img_tensor[0]) plt.show()
#建立模型,输入为原图像,输出为原模型的前8层的激活输出的特征图 layer_outputs = [layer.output for layer in model.layers[:8]] activation_model = models.Model(inputs=model.input, outputs=layer_outputs) #获得改样本的特征图 activations = activation_model.predict(img_tensor) #显示第一层激活输出特的第一个滤波器的特征图 first_layer_activation = activations[0] plt.matshow(first_layer_activation[0,:,:,1], cmap="viridis")
#存储层的名称 layer_names = [] for layer in model.layers[:4]: layer_names.append(layer.name) # 每行显示16个特征图 images_pre_row = 16 #每行显示的特征图数 # 循环8次显示8层的全部特征图 for layer_name, layer_activation in zip(layer_names, activations): n_features = layer_activation.shape[-1] #保存当前层的特征图个数 size = layer_activation.shape[1] #保存当前层特征图的宽高 n_col = n_features // images_pre_row #计算当前层显示多少行 #生成显示图像的矩阵 display_grid = np.zeros((size*n_col, images_pre_row*size)) #遍历将每个特张图的数据写入到显示图像的矩阵中 for col in range(n_col): for row in range(images_pre_row): #保存该张特征图的矩阵(size,size,1) channel_image = layer_activation[0,:,:,col*images_pre_row+row] #为使图像显示更鲜明,作一些特征处理 channel_image -= channel_image.mean() channel_image /= channel_image.std() channel_image *= 64 channel_image += 128 #把该特征图矩阵中不在0-255的元素值修改至0-255 channel_image = np.clip(channel_image, 0, 255).astype("uint8") #该特征图矩阵填充至显示图像的矩阵中 display_grid[col*size:(col+1)*size, row*size:(row+1)*size] = channel_image scale = 1./size #设置该层显示图像的宽高 plt.figure(figsize=(scale*display_grid.shape[1],scale*display_grid.shape[0])) plt.title(layer_name) plt.grid(False) #显示图像 plt.imshow(display_grid, aspect="auto", cmap="viridis")
8.准备数张图片
9.自定义图片处理
import os import matplotlib.pyplot as plt from PIL import Image import os.path def convertjpg(jpgfile, outdir, width=150, height=150): # 将图片缩小到(150,150)的大小 img = Image.open(jpgfile) try: new_img = img.resize((width, height), Image.BILINEAR) new_img.save(os.path.join(outdir, os.path.basename(jpgfile))) except Exception as e: print(e) jpgfile1 = 'flower/test/flower1.jpg' # 读取原图像 jpgfile2 = 'flower/test/flower2.jpg' # 读取原图像 jpgfile3 = 'flower/test/flower3.jpg' # 读取原图像 jpgfile4 = 'flower/test/flower4.jpg' # 读取原图像 jpgfile5 = 'flower/test/flower5.jpg' # 读取原图像 convertjpg(jpgfile1, "flower/newtest/") # 图像大小改变到(150,150) convertjpg(jpgfile2, "flower/newtest/") # 图像大小改变到(150,150) convertjpg(jpgfile3, "flower/newtest/") # 图像大小改变到(150,150) convertjpg(jpgfile4, "flower/newtest/") # 图像大小改变到(150,150) convertjpg(jpgfile5, "flower/newtest/") # 图像大小改变到(150,150) img_scale = plt.imread('flower/newtest/flower2.jpg') plt.imshow(img_scale) # 显示改变图像大小后的图片确实变到了(150,150)大小 plt.show()
10.测试
import numpy as np import os import matplotlib.pyplot as plt from keras.preprocessing.image import ImageDataGenerator from keras.preprocessing import image from keras.models import load_model from keras.utils import image_utils, load_img, img_to_array from PIL import Image model=load_model('flower/flowermodel.h5') img='flower/newtest/flower1.jpg' img_scale = plt.imread(img) plt.imshow(img_scale) plt.show() img_scale = img_scale.reshape(1,150,150,3).astype('float32') img_scale = img_scale/255 #归一化到0-1之间 result = model.predict(img_scale) #取图片信息 print(result) dict={'0':'菊花','1':'蒲公英','2':'玫瑰','3':'向日葵','4':'郁金香'} for i in range(5): if result[0][i]>0.5: print( '这是:'+ dict[str(i)])
2.
img='flower/newtest/flower2.jpg' img_scale = plt.imread(img) plt.imshow(img_scale) plt.show() img_scale = img_scale.reshape(1,150,150,3).astype('float32') img_scale = img_scale/255 #归一化到0-1之间 result = model.predict(img_scale) #取图片信息 print(result) dict={'0':'菊花','1':'蒲公英','2':'玫瑰','3':'向日葵','4':'郁金香'} for i in range(5): if result[0][i]>0.5: print( '这是:'+ dict[str(i)])
3. img='flower/newtest/flower3.jpg' img_scale = plt.imread(img) plt.imshow(img_scale) plt.show() img_scale = img_scale.reshape(1,150,150,3).astype('float32') img_scale = img_scale/255 #归一化到0-1之间 result = model.predict(img_scale) #取图片信息 print(result) dict={'0':'菊花','1':'蒲公英','2':'玫瑰','3':'向日葵','4':'郁金香'} for i in range(5): if result[0][i]>0.5: print( '这是:'+ dict[str(i)])
4. img='flower/newtest/flower4.jpg' img_scale = plt.imread(img) plt.imshow(img_scale) plt.show() img_scale = img_scale.reshape(1,150,150,3).astype('float32') img_scale = img_scale/255 #归一化到0-1之间 result = model.predict(img_scale) #取图片信息 print(result) dict={'0':'菊花','1':'蒲公英','2':'玫瑰','3':'向日葵','4':'郁金香'} for i in range(5): if result[0][i]>0.5: print( '这是:'+ dict[str(i)])
5. img='flower/newtest/flower5.jpg' img_scale = plt.imread(img) plt.imshow(img_scale) plt.show() img_scale = img_scale.reshape(1,150,150,3).astype('float32') img_scale = img_scale/255 #归一化到0-1之间 result = model.predict(img_scale) #取图片信息 print(result) dict={'0':'菊花','1':'蒲公英','2':'玫瑰','3':'向日葵','4':'郁金香'} for i in range(5): if result[0][i]>0.5: print( '这是:'+ dict[str(i)])
11.完整代码 import os import numpy as np import pandas as pd import tensorflow as tf import matplotlib.pyplot as plt from keras import layers from keras import models from keras.models import load_model import warnings from keras import optimizers from keras.preprocessing.image import ImageDataGenerator from keras.preprocessing import image from keras.utils import image_utils filename = 'D:\\python\\python Save\\期末\\python\\flower\\val\\sunflowers' #文件地址 list_path = os.listdir(filename) #读取文件夹里面的名字 count = 1 for index in list_path: path = filename + '\\' + index # 原本文件名 new_path = filename + '\\' + f'sunflowers{count}'+'.jpg' print(new_path) os.rename(path, new_path) count += 1 print('修改完成') train_path="flower/train/" print('train:') print(' daisy images:', len(os.listdir(train_path+"daisy"))) #菊花花数据集图片数量 print(' dandelion images:', len(os.listdir(train_path+"dandelion"))) #蒲公英数据集图片数量 print(' roses images:', len(os.listdir(train_path+"roses"))) #玫瑰花数据集图片数量 print(' tulips images:', len(os.listdir(train_path+"tulips"))) #郁金香数据集图片数量 print(' sunflowers images:', len(os.listdir(train_path+"sunflowers"))) #太阳花数据集图片数量 valid_path="flower/val/" print('val') print(' daisy images:', len(os.listdir(valid_path+"daisy"))) #菊花花数据集图片数量 print(' dandelion images:', len(os.listdir(valid_path+"dandelion"))) #蒲公英数据集图片数量 print(' roses images:', len(os.listdir(valid_path+"roses"))) #玫瑰花数据集图片数量 print(' tulips images:', len(os.listdir(valid_path+"tulips"))) #郁金香数据集图片数量 print(' sunflowers images:', len(os.listdir(valid_path+"sunflowers"))) #太阳花数据集图片数量 model = models.Sequential() #第一个卷积层作为输入层,32个3*3卷积核,输入形状input_shape = (150,150,3) # 输出图片尺寸:150-3+1=148*148,参数数量:32*3*3*3+32=896 model.add(layers.Conv2D(32,(3,3),activation = 'relu',input_shape = (150,150,3))) model.add(layers.MaxPooling2D((2,2)))# 输出图片尺寸:148/2=74*74 #输出图片尺寸:74-3+1=72*72,参数数量:64*3*3*32+64=18496 model.add(layers.Conv2D(64,(3,3),activation = 'relu')) model.add(layers.MaxPooling2D((2,2)))# 输出图片尺寸:72/2=36*36 # 输出图片尺寸:36-3+1=34*34,参数数量:128*3*3*64+128=73856 model.add(layers.Conv2D(128,(3,3),activation = 'relu')) model.add(layers.MaxPooling2D((2,2)))# 输出图片尺寸:34/2=17*17 model.add(layers.Conv2D(128,(3,3),activation = 'relu')) model.add(layers.MaxPooling2D((2,2))) model.add(layers.Flatten()) model.add(layers.Dense(512,activation = 'relu')) model.add(layers.Dense(5,activation = 'softmax'))#sigmoid分类,输出是二元类别,softmax输出多元类别 # 编译模型 # RMSprop 优化器。因为网络最后一层是单一sigmoid单元, # 所以使用二元交叉熵作为损失函数 model.compile(loss='binary_crossentropy', optimizer=optimizers.RMSprop(lr=1e-4), metrics=['acc']) #归一化 train_datagen = ImageDataGenerator(rescale = 1./255) val_datagen = ImageDataGenerator(rescale = 1./255) train_dir = 'flower/train' #指向训练集图片目录路径 #图像处理 train_generator = train_datagen.flow_from_directory( train_dir, target_size = (150,150),# 输入训练图像尺寸 batch_size = 20, class_mode = 'categorical') # validation_dir = 'flower/val' #指向验证集图片目录路径 validation_generator = val_datagen.flow_from_directory( validation_dir, target_size = (150,150), batch_size = 20, class_mode = 'categorical') for data_batch,labels_batch in train_generator: print('data batch shape:',data_batch.shape) print('data batch shape:',labels_batch.shape) break #生成器不会停止,会循环生成这些批量,所以我们就循环生成一次批量 history = model.fit(train_generator,validation_data=validation_generator,epochs=30) #保存训练模型 model.save('flower/flowermodel.h5')
accuracy =history.history['acc'] loss = history.history['loss'] val_loss = history.history['val_loss'] val_accuracy = history.history['val_acc'] plt.figure(figsize=(17, 7)) plt.subplot(2, 2, 1) plt.plot(range(30), accuracy,'bo', label='Training Accuracy') plt.plot(range(30), val_accuracy, label='Validation Accuracy') plt.legend(loc='lower right') plt.title('Accuracy : Training vs. Validation ') plt.subplot(2, 2, 2) plt.plot(range(30), loss,'bo' ,label='Training Loss') plt.plot(range(30), val_loss, label='Validation Loss') plt.title('Loss : Training vs. Validation ') plt.legend(loc='upper right') plt.show()
accuracy =history.history['acc'] loss = history.history['loss'] val_loss = history.history['val_loss'] val_accuracy = history.history['val_acc'] plt.figure(figsize=(17, 7)) plt.subplot(2, 2, 1) plt.plot(range(30), accuracy,'bo', label='Training Accuracy') plt.plot(range(30), val_accuracy, label='Validation Accuracy') plt.legend(loc='lower right') plt.title('Accuracy : Training vs. Validation ') plt.subplot(2, 2, 2) plt.plot(range(30), loss,'bo' ,label='Training Loss') plt.plot(range(30), val_loss, label='Validation Loss') plt.title('Loss : Training vs. Validation ') plt.legend(loc='upper right') plt.show() warnings.filterwarnings("ignore") #读取.h5文件 model=load_model('flower/flowermodel.h5') #从测试集中读取一条样本 img_path = "flower/test/flower1.jpg" img = image_utils.load_img(img_path, target_size=(150,150)) img_tensor = image_utils.img_to_array(img) img_tensor = np.expand_dims(img_tensor, axis=0) img_tensor /= 255. print(img_tensor.shape) #显示样本 plt.imshow(img_tensor[0]) layer_outputs = [layer.output for layer in model.layers[:8]] activation_model = models.Model(inputs=model.input, outputs=layer_outputs) #获得改样本的特征图 activations = activation_model.predict(img_tensor) #显示第一层激活输出特的第一个滤波器的特征图 first_layer_activation = activations[0] plt.matshow(first_layer_activation[0,:,:,1], cmap="viridis") # 存储层的名称 layer_names = [] for layer in model.layers[:4]: layer_names.append(layer.name) # 每行显示16个特征图 images_pre_row = 16 # 每行显示的特征图数 # 循环8次显示8层的全部特征图 for layer_name, layer_activation in zip(layer_names, activations): n_features = layer_activation.shape[-1] # 保存当前层的特征图个数 size = layer_activation.shape[1] # 保存当前层特征图的宽高 n_col = n_features // images_pre_row # 计算当前层显示多少行 # 生成显示图像的矩阵 display_grid = np.zeros((size * n_col, images_pre_row * size)) # 遍历将每个特张图的数据写入到显示图像的矩阵中 for col in range(n_col): for row in range(images_pre_row): # 保存该张特征图的矩阵(size,size,1) channel_image = layer_activation[0, :, :, col * images_pre_row + row] # 为使图像显示更鲜明,作一些特征处理 channel_image -= channel_image.mean() channel_image /= channel_image.std() channel_image *= 64 channel_image += 128 # 把该特征图矩阵中不在0-255的元素值修改至0-255 channel_image = np.clip(channel_image, 0, 255).astype("uint8") # 该特征图矩阵填充至显示图像的矩阵中 display_grid[col * size:(col + 1) * size, row * size:(row + 1) * size] = channel_image scale = 1. / size # 设置该层显示图像的宽高 plt.figure(figsize=(scale * display_grid.shape[1], scale * display_grid.shape[0])) plt.title(layer_name) plt.grid(False) # 显示图像 plt.imshow(display_grid, aspect="auto", cmap="viridis") import os import matplotlib.pyplot as plt from PIL import Image import os.path def convertjpg(jpgfile, outdir, width=150, height=150): # 将图片缩小到(150,150)的大小 img = Image.open(jpgfile) try: new_img = img.resize((width, height), Image.BILINEAR) new_img.save(os.path.join(outdir, os.path.basename(jpgfile))) except Exception as e: print(e) jpgfile1 = 'flower/test/flower1.jpg' # 读取原图像 jpgfile2 = 'flower/test/flower2.jpg' # 读取原图像 jpgfile3 = 'flower/test/flower3.jpg' # 读取原图像 jpgfile4 = 'flower/test/flower4.jpg' # 读取原图像 jpgfile5 = 'flower/test/flower5.jpg' # 读取原图像 convertjpg(jpgfile1, "flower/newtest/") # 图像大小改变到(150,150) convertjpg(jpgfile2, "flower/newtest/") # 图像大小改变到(150,150) convertjpg(jpgfile3, "flower/newtest/") # 图像大小改变到(150,150) convertjpg(jpgfile4, "flower/newtest/") # 图像大小改变到(150,150) convertjpg(jpgfile5, "flower/newtest/") # 图像大小改变到(150,150) img_scale = plt.imread('flower/newtest/flower2.jpg') plt.imshow(img_scale) # 显示改变图像大小后的图片确实变到了(150,150)大小 img='flower/newtest/flower1.jpg' img_scale = plt.imread(img) plt.imshow(img_scale) plt.show() img_scale = img_scale.reshape(1,150,150,3).astype('float32') img_scale = img_scale/255 #归一化到0-1之间 result = model.predict(img_scale) #取图片信息 print(result) dict={'0':'菊花','1':'蒲公英','2':'玫瑰','3':'向日葵','4':'郁金香'} for i in range(5): if result[0][i]>0.5: print( '这是:'+ dict[str(i)])
(四)总结:
本次课程设计内容为机器学习,之所以选择此课题,是因为刚刚学完了猫狗图片识别,对机器学习印象更加深刻。本次课程设计主要参考了课程猫狗识别,手写数字识别和老师给的参考资料森林火灾图片识别,主要涉及到了机器学习的二分类和多分类的区别。
问题主要在于代码:model.add(layers.Dense(5,activation = 'softmax'))中的“activation=’softmax‘”的值的选择上。当”activation“的值为softmax时,分类器此时为多个分类。当”activation“的值为sigmoid时分类器此时为二分类。多分类与二分类所产生的结果时大为不同的,在初次别写代码时,由于没有选对值导致模型编译时丢失率极大,成功率也非常低。
其次在编写图像预处理代码过程中,参考猫狗识别代码将"class_mode"的值写成了"binary"也导致了程序运行时报错。如果是二分类应写为:class_model=“binary”,如果是多分类应写为class_model=“categorical”,查阅了相关资料了解后更改class_model的值代码果然运行成功。
标签:150,plt,机器,img,scale,path,model,识别,种类 From: https://www.cnblogs.com/wydks/p/17002489.html