机器学习-常见蔬菜种类识别
机器学习—蔬菜种类图片识别
一、选题的背景
随着科技的进步,机器学习已经深入到各个领域,其中包括农业。蔬菜分类是农业中一个重要的环节,它涉及到蔬菜的种植、销售和质量控制等方面。传统的蔬菜分类方法通常依赖于人工目视检查,这种方法不仅效率低下,而且容易受到人为因素和主观性的影响。在机器学习发展迅速的今天,我们是可以用机器学习技术进行蔬菜分类的,通过机器学习技术,我们可以训练模型对蔬菜进行自动分类。实现快速、准确的分类效果。以提高分类的准确性和效率,降低人工成本和误差率。
二、机器学习案例设计方案
1.数据来源
本选题的数据集来源于:https://www.kaggle.com/datasets/misrakahmed/vegetable-image-dataset/data 该数据集是常见的15种蔬菜:豆子、苦瓜、冬瓜、茄子、西兰花、卷心菜、辣椒、胡萝卜、花椰菜、黄瓜、木瓜、土豆、南瓜、萝卜和番茄。共使用了来自15个类别的21000张图像,其中每个类别包含1400张大小为224×224、*.jpg格式的图像。数据集70%用于训练,15%用于验证,15%用于测试。
2.机器学习案例的设计步骤
构建网络结构:该网络结构由Conv2D层(使用ReLU激活)和MaxPooling2D层交替堆叠构成。这样的可以增大网络容量,也可以进一步减少特征图的尺寸,使其在连接Flatten层时尺寸不会太大。
使用交叉熵损失函数:使用RMSprop优化器,在网络最后一层使用多分类交叉熵作为损失函数。
数据预处理:读取图像文件、解码、数据归一化。
训练模型:使用fit方法训练模型。
绘制损失曲线和精度曲线。
将数据输入网络进行训练以及测试-验证网络模型。
三、机器学习的实现
引用函数
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
import glob as gb
from tensorflow import keras
from keras.models import Sequential
from keras.layers import Conv2D,MaxPooling2D,Flatten,Dense,Dropout
from tensorflow.keras.utils import to_categorical
from keras.preprocessing import image
from keras.preprocessing.image import ImageDataGenerator
import os, shutil
import warnings
warnings.filterwarnings('ignore')
让下列程序检查部分分组的(测试/训练)中包含多少张图片。
import os
#定义 train_path,valid_path,test_path 路径
train_path = 'C:/Users/Administrator/Desktop/Vegetable Images/train/'
valid_path = 'C:/Users/Administrator/Desktop/Vegetable Images/validation/'
test_path = 'C:/Users/Administrator/Desktop/Vegetable Images/test/'
#检查分组训练集中含有的图像数量
print('total trainning Bean images: ',len(os.listdir(train_path+"Bean")))
print('total trainning Bitter_Gourd images: ',len(os.listdir(train_path+"Bitter_Gourd")))
print('total trainning Bitter_Gourd images: ',len(os.listdir(train_path+"Bitter_Gourd")))
print('total trainning Brinjal images: ',len(os.listdir(train_path+"Brinjal")))
print('total trainning Broccoli images: ',len(os.listdir(train_path+"Broccoli")))
#检查分组验证集集中含有的图像数量
print('total validation Bean images: ',len(os.listdir(valid_path+"Bean")))
print('total validation Bitter_Gourd images: ',len(os.listdir(valid_path+"Bitter_Gourd")))
print('total validation Bitter_Gourd images: ',len(os.listdir(valid_path+"Bitter_Gourd")))
print('total validation Brinjal images: ',len(os.listdir(valid_path+"Brinjal")))
print('total validation Broccoli images: ',len(os.listdir(valid_path+"Broccoli")))

从文件夹中读取训练集中各种蔬菜图片,并展示。
image_categories = os.listdir('C:/Users/Administrator/Desktop/Vegetable Images/train')
def plot_images(image_categories):
# 使用matplotlib库创建一个新的图形,并设置其大小为12x12。
plt.figure(figsize=(12, 12))
for i, photo in enumerate(image_categories):
#遍历获取每个文件夹的索引i和名称photo
image_path = train_path + '/' + photo
images_in_folder = os.listdir(image_path)
first_image_of_folder = images_in_folder[i]
# 从当前文件夹的所有文件中选择第一个文件
first_image_path = image_path + '/' + first_image_of_folder
img = image.load_img(first_image_path)
#将加载的图片转换为数组格式,并将其除以255进行归一化。
img_arr = image.img_to_array(img)/255
# Create Subplot and plot the images
plt.subplot(4, 4, i+1)
plt.imshow(img_arr)
plt.title(photo)
plt.axis('off')
plt.show()
plot_images(image_categories)

搭建网络
#搭建网络
from keras import layers
from keras import models
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(1,activation = 'softmax'))
model.summary()

# 编译模型
# RMSprop 优化器。因为网络最后一层是softmax单元,
# 所以使用多分类交叉熵作为损失函数
from tensorflow import optimizers
model.compile(loss='categorical_crossentropy',
optimizer=optimizers.RMSprop(learning_rate=1e-4),
metrics=['accuracy'])
from keras.preprocessing.image import ImageDataGenerator
# 归一化
train_datagen = ImageDataGenerator(rescale=1./255)
val_datagen = ImageDataGenerator(rescale=1./255)
test_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
train_path,
target_size=(150, 150), # 输入训练图像尺寸
batch_size=20,
class_mode='categorical' # 多分类模式
)
validation_generator = val_datagen.flow_from_directory(
val_path,
target_size=(150, 150),
batch_size=20,
class_mode='categorical'
)
test_generator = test_datagen.flow_from_directory(
test_path,
target_size=(150, 150),
batch_size=32,
class_mode='categorical'
)
class_map = dict([(v, k) for k, v in train_generator.class_indices.items()])
print(class_map)
for data_batch, labels_batch in train_generator:
print('data batch shape:', data_batch.shape)
print('labels batch shape:', labels_batch.shape) # 更正了这里的打印语句
break # 生成器会循环生成批次,所以我们只循环一次来查看批次形状

训练模型
#训练模型轮次
history = model.fit(
train_generator,
steps_per_epoch = 100,
epochs = 10,
validation_data = validation_generator,
validation_steps = 50)

# 绘制损失曲线
plt.plot(history.history['loss'], label='Training Loss')
plt.plot(history.history['val_loss'], label='Validation Loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.title('Training and Validation Loss')
plt.legend()
plt.show()
# 绘制精度曲线
plt.plot(history.history['accuracy'], label='Training Accuracy')
plt.plot(history.history['val_accuracy'], label='Validation Accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.title('Training and Validation Accuracy')
plt.legend()
plt.show()

从训练的模型可以看出训练精度随时间线性的增加,感觉产生了一定的拟合。这是十次训练模型
为了尽可能的消除拟合我选择在模型中增加Dropout层并且将训练的轮次提升至一百次。
#在模型中添加Droup
from tensorflow import optimizers
from keras.preprocessing.image import ImageDataGenerator
from keras import layers
from keras import models
#添加后将模型训练提升到一百次
#定义一个包含Droupout的新卷积神经网络
model = models.Sequential()
#定义四层卷积和池化层
# 输出图片尺寸: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.Dropout(0.5))#增加Dropout正则化
model.add(layers.Dense(512,activation = 'relu'))
model.add(layers.Dense(1,activation = 'softmax'))
model.summary()
model.compile(loss='categorical_crossentropy',
optimizer=optimizers.RMSprop(learning_rate=1e-4),
metrics=['accuracy'])
#归一化
train_datagen = ImageDataGenerator(rescale = 1./255)
test_datagen = ImageDataGenerator(rescale = 1./255)
val_datagen = ImageDataGenerator(rescale = 1.0/255.0)
train_generator = train_datagen.flow_from_directory(
train_path,
target_size = (150,150),# 输入训练图像尺寸
batch_size = 20,
class_mode = 'categorical') #
validation_generator = test_datagen.flow_from_directory(
val_path,
target_size = (150,150),
batch_size = 20,
class_mode = 'categorical')
test_generator = train_datagen.flow_from_directory(
test_path,
target_size=(150, 150),
batch_size=32,
class_mode='categorical')
class_map = dict([(v, k) for k, v in train_generator.class_indices.items()])
print(class_map)
for data_batch,labels_batch in train_generator:
print('data batch shape:',data_batch.shape)
print('data batch shape:',labels_batch.shape)
break #生成器不会停止,会循环生成这些批量,所以我们就循环生成一次批量
modelone = model.fit(
train_generator,
steps_per_epoch = 100,
epochs = 100,
validation_data = validation_generator,
validation_steps = 50)
# 绘制损失曲线
plt.plot(modelone.history['loss'], label='Training Loss')
plt.plot(modelone.history['val_loss'], label='Validation Loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.title('Training and Validation Loss')
plt.legend()
plt.show()
# 绘制精度曲线
plt.plot(modelone.history['accuracy'], label='Training Accuracy')
plt.plot(modelone.history['val_accuracy'], label='Validation Accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.title('Training and Validation Accuracy')
plt.legend()
plt.show()
模型的最后一轮输出以及性能曲线

由模型输出的曲线可以看出,模型泛化的准确率上升并稳定在最大值左右。
四、总结
本次课程设计中是对常见的15物种蔬菜进行机器学习,是进行对常见的蔬菜进行分类从训练得到的精度曲线和损失曲线进行分析得出在多次的训练可以提高机器学习模型的泛化能力。通过本次课程设计,我将全面了解蔬菜分类的整个流程,并掌握相关的机器学习算法和Python编程技术。在此次学习中图像分类的流程也有了一定的了解,从收集数据、对数据进行预处理、自己构建网络模型、训练网络到最后的预测结果,加深了对图像分类过程的理解。希望在以后的学习中,可以学习更多深度学习的方法和应用。
五、全部代码
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
import glob as gb
from tensorflow import keras
from keras.models import Sequential
from keras.layers import Conv2D,MaxPooling2D,Flatten,Dense,Dropout
from tensorflow.keras.utils import to_categorical
from keras.preprocessing import image
from keras.preprocessing.image import ImageDataGenerator
import os, shutil
import warnings
warnings.filterwarnings('ignore')
import os
#定义 train_path,valid_path,test_path 路径
train_path = 'C:/Users/Administrator/Desktop/Vegetable Images/train/'
valid_path = 'C:/Users/Administrator/Desktop/Vegetable Images/validation/'
test_path = 'C:/Users/Administrator/Desktop/Vegetable Images/test/'
#检查分组训练集中含有的图像数量
print('total trainning Bean images: ',len(os.listdir(train_path+"Bean")))
print('total trainning Bitter_Gourd images: ',len(os.listdir(train_path+"Bitter_Gourd")))
print('total trainning Bitter_Gourd images: ',len(os.listdir(train_path+"Bitter_Gourd")))
print('total trainning Brinjal images: ',len(os.listdir(train_path+"Brinjal")))
print('total trainning Broccoli images: ',len(os.listdir(train_path+"Broccoli")))
#检查分组验证集集中含有的图像数量
print('total validation Bean images: ',len(os.listdir(valid_path+"Bean")))
print('total validation Bitter_Gourd images: ',len(os.listdir(valid_path+"Bitter_Gourd")))
print('total validation Bitter_Gourd images: ',len(os.listdir(valid_path+"Bitter_Gourd")))
print('total validation Brinjal images: ',len(os.listdir(valid_path+"Brinjal")))
print('total validation Broccoli images: ',len(os.listdir(valid_path+"Broccoli")))
image_categories = os.listdir('C:/Users/Administrator/Desktop/Vegetable Images/train')
def plot_images(image_categories):
# 使用matplotlib库创建一个新的图形,并设置其大小为12x12。
plt.figure(figsize=(12, 12))
for i, photo in enumerate(image_categories):
#遍历获取每个文件夹的索引i和名称photo
image_path = train_path + '/' + photo
images_in_folder = os.listdir(image_path)
first_image_of_folder = images_in_folder[i]
# 从当前文件夹的所有文件中选择第一个文件
first_image_path = image_path + '/' + first_image_of_folder
img = image.load_img(first_image_path)
#将加载的图片转换为数组格式,并将其除以255进行归一化。
img_arr = image.img_to_array(img)/255
# Create Subplot and plot the images
plt.subplot(4, 4, i+1)
plt.imshow(img_arr)
plt.title(photo)
plt.axis('off')
plt.show()
plot_images(image_categories)
#搭建网络
from keras import layers
from keras import models
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(1,activation = 'softmax'))
model.summary()
# 编译模型
# RMSprop 优化器。因为网络最后一层是softmax单元,
# 所以使用多分类交叉熵作为损失函数
from tensorflow import optimizers
model.compile(loss='categorical_crossentropy',
optimizer=optimizers.RMSprop(learning_rate=1e-4),
metrics=['accuracy'])
from keras.preprocessing.image import ImageDataGenerator
# 归一化
train_datagen = ImageDataGenerator(rescale=1./255)
val_datagen = ImageDataGenerator(rescale=1./255)
test_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
train_path,
target_size=(150, 150), # 输入训练图像尺寸
batch_size=20,
class_mode='categorical' # 多分类模式
)
validation_generator = val_datagen.flow_from_directory(
val_path,
target_size=(150, 150),
batch_size=20,
class_mode='categorical'
)
test_generator = test_datagen.flow_from_directory(
test_path,
target_size=(150, 150),
batch_size=32,
class_mode='categorical'
)
class_map = dict([(v, k) for k, v in train_generator.class_indices.items()])
print(class_map)
for data_batch, labels_batch in train_generator:
print('data batch shape:', data_batch.shape)
print('labels batch shape:', labels_batch.shape) # 更正了这里的打印语句
break # 生成器会循环生成批次,所以我们只循环一次来查看批次形状
#训练模型轮次
history = model.fit(
train_generator,
steps_per_epoch = 100,
epochs = 10,
validation_data = validation_generator,
validation_steps = 50)
validation_steps = 50)
# 绘制损失曲线
plt.plot(history.history['loss'], label='Training Loss')
plt.plot(history.history['val_loss'], label='Validation Loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.title('Training and Validation Loss')
plt.legend()
plt.show()
# 绘制精度曲线
plt.plot(history.history['accuracy'], label='Training Accuracy')
plt.plot(history.history['val_accuracy'], label='Validation Accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.title('Training and Validation Accuracy')
plt.legend()
plt.show()
#在模型中添加Droup
from tensorflow import optimizers
from keras.preprocessing.image import ImageDataGenerator
from keras import layers
from keras import models
#添加后将模型训练提升到一百次
#定义一个包含Droupout的新卷积神经网络
model = models.Sequential()
#定义四层卷积和池化层
# 输出图片尺寸: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.Dropout(0.5))#增加Dropout正则化
model.add(layers.Dense(512,activation = 'relu'))
model.add(layers.Dense(1,activation = 'softmax'))
model.summary()
model.compile(loss='categorical_crossentropy',
optimizer=optimizers.RMSprop(learning_rate=1e-4),
metrics=['accuracy'])
#归一化
train_datagen = ImageDataGenerator(rescale = 1./255)
test_datagen = ImageDataGenerator(rescale = 1./255)
val_datagen = ImageDataGenerator(rescale = 1.0/255.0)
train_generator = train_datagen.flow_from_directory(
train_path,
target_size = (150,150),# 输入训练图像尺寸
batch_size = 20,
class_mode = 'categorical') #
validation_generator = test_datagen.flow_from_directory(
val_path,
target_size = (150,150),
batch_size = 20,
class_mode = 'categorical')
test_generator = train_datagen.flow_from_directory(
test_path,
target_size=(150, 150),
batch_size=32,
class_mode='categorical')
class_map = dict([(v, k) for k, v in train_generator.class_indices.items()])
print(class_map)
for data_batch,labels_batch in train_generator:
print('data batch shape:',data_batch.shape)
print('data batch shape:',labels_batch.shape)
break #生成器不会停止,会循环生成这些批量,所以我们就循环生成一次批量
modelone = model.fit(
train_generator,
steps_per_epoch = 100,
epochs = 100,
validation_data = validation_generator,
validation_steps = 50)
# 绘制损失曲线
plt.plot(modelone.history['loss'], label='Training Loss')
plt.plot(modelone.history['val_loss'], label='Validation Loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.title('Training and Validation Loss')
plt.legend()
plt.show()
# 绘制精度曲线
plt.plot(modelone.history['accuracy'], label='Training Accuracy')
plt.plot(modelone.history['val_accuracy'], label='Validation Accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.title('Training and Validation Accuracy')
plt.legend()
plt.show()

浙公网安备 33010602011771号