🤵‍♂️ 个人主页:@艾派森的个人主页

✍🏻作者简介:Python学习者
🐋 希望大家多多支持,我们一起进步!😄
如果文章对你有帮助的话,
欢迎评论 💬点赞👍🏻 收藏 📂加关注+


目录

1.项目背景

2.数据集介绍

3.技术工具

4.实验过程

4.1导入数据

4.2数据预处理

4.3特征工程 

4.4构建模型

4.5模型评估

4.6模型保存

文末推荐

源代码


1.项目背景

        玉米作为全球范围内重要的粮食作物之一,其产量和品质对于全球粮食安全和经济发展具有重要影响。然而,玉米在生长过程中常常受到各种病害的侵袭,这些病害不仅影响玉米的产量和品质,还可能对农民的经济收益造成巨大损失。因此,快速、准确地识别玉米病害,对于指导农民科学防治、保障玉米产量具有重要意义。

        传统的玉米病害识别方法主要依赖于农学家的经验判断和田间观察,这种方法不仅耗时耗力,而且识别准确率和效率较低。近年来,随着计算机视觉和人工智能技术的快速发展,深度学习算法在图像识别领域取得了显著成果。其中,卷积神经网络(CNN)作为一种典型的深度学习模型,以其强大的特征提取和分类能力,在图像识别领域得到了广泛应用。

        在农业领域,基于CNN的农作物病害识别模型也逐渐受到关注。该模型通过训练大量的病害图像数据,能够自动学习并提取病害图像中的特征信息,进而实现对病害的准确分类和识别。与传统的病害识别方法相比,基于CNN的病害识别模型具有更高的识别准确率和效率,能够实现对玉米病害的快速、准确识别。

        然而,目前基于CNN的玉米植物叶病分类识别模型的研究相对较少,且面临着一些挑战。首先,玉米病害种类繁多,不同病害的表型症状可能存在相似性,增加了识别难度。其次,玉米病害图像数据的获取和标注需要大量的人力和时间成本,限制了模型训练的数据规模。此外,玉米生长环境的复杂性和多样性也对模型的泛化能力提出了更高要求。

        因此,开展基于卷积神经网络(CNN)的玉米植物叶病分类识别模型的研究具有重要的理论意义和实践价值。该研究不仅能够为玉米病害的快速、准确识别提供新的技术手段,还能够为玉米病害的科学防治提供有力支持,有助于保障玉米产量和品质的稳定提升。

2.数据集介绍

关于数据集

数据集来源于Kaggle,用于玉米或玉米植物叶病分类的数据集

数据集说明:

  • 0:Common Rust(常见锈病 - 1306 张图片
  • 1:Gray Leaf Spot(灰叶斑 - 574 张图片
  • 2:Blight(枯萎病 -1146 张图片
  • 3:Healthy(健康 - 1162 张图片

3.技术工具

Python版本:3.9

代码编辑器:jupyter notebook

4.实验过程

4.1导入数据

导入第三方库并定义一些函数用于查看图像

import os
import cv2
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')

# 定义加载和调整图像大小的函数
def load_and_resize_image(file_path, target_shape=(128, 128)):
    image = cv2.imread(file_path)
    resized_image = cv2.resize(image, target_shape)
    return resized_image

# 定义函数加载每个图像类(目标)存储在单独的目录
# 每个类目录包含各自的图像
def load_image_class_by_directory(image_dir):
    # 加载和调整图像大小
    image_files = os.listdir(image_dir)
    images = []
    for file in image_files:
        if file.endswith('.jpg') or file.endswith('.JPG'):  # 假设图像是jpg或jpg格式
            image_path = os.path.join(image_dir, file)
            resized_image = load_and_resize_image(image_path)
            images.append(resized_image)

    print(f"Num of images: {len(images)}")        
    print(f"Single image shape before flattening: {images[0].shape}")
    return images

# 显示一些图像
def display_images(images, num_images_to_display = 6):
    fig, axes = plt.subplots(1, num_images_to_display, figsize=(20, 5))
    for i in range(num_images_to_display):
        # 在颜色转换之前,将图像转换为支持的深度(例如,CV_8U)
        image = images[i].astype(np.uint8)
        axes[i].imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))  # 将BGR转换为RGB以使用matplotlib显示
        axes[i].axis('off')
    plt.show()

查看Blight(枯萎病

# 定义包含图像的目录
image_dir = "./data/Blight"
images_Blight = load_image_class_by_directory(image_dir)
display_images(images_Blight)

查看Common Rust(常见锈病

# 定义包含图像的目录
image_dir = "./data/Common_Rust"
images_Common_Rust = load_image_class_by_directory(image_dir)
display_images(images_Common_Rust)

查看Gray Leaf Spot(灰叶斑

# 定义包含图像的目录
image_dir = "./data/Gray_Leaf_Spot"
images_Gray_Leaf_Spot = load_image_class_by_directory(image_dir)
display_images(images_Gray_Leaf_Spot)

查看Healthy(健康

# 定义包含图像的目录
image_dir = "./data/Healthy"
images_Healthy = load_image_class_by_directory(image_dir)
display_images(images_Healthy)

4.2数据预处理

定义数据类别标签

# 定义类标签
classes = {'Blight': 0, 'Common_Rust': 1, 'Gray_Leaf_Spot': 2, 'Healthy': 3} 
inverted_classes = {0: 'Blight', 1: 'Common_Rust', 2: 'Gray_Leaf_Spot', 3: 'Healthy'}
images_lst_lst = [images_Blight, images_Common_Rust, images_Gray_Leaf_Spot, images_Healthy]

# 字典来存储图像样本的数量
classes_dict = {}
for i, images in enumerate(images_lst_lst):
    classes_dict.update({inverted_classes[i]: len(images)})
    print(f'Disease: {inverted_classes[i]} --- Images: {len(images)}')

plt.bar(*zip(*classes_dict.items()))
plt.show()

存在一种类别不平衡,Gray_Leaf_Spot的案例较少。这可能会影响模型识别类的能力,或者至少会影响高置信度的识别能力。

分配类标签

选择要设置为测试集的图像数量。算法不应该看到这些数据,因为它将用于以后的评估。

为每个图像添加一个类标签。这是通过首先将图像从2D扁平化到1D,然后将类别编号附加到其上(例如Blight为0等)来完成的。

# 函数将RGB值从2D平铺到1D,返回numpy数组
def flatten_images(images):
    data_flattened = []
    for image in images:
        flattened_image = image.reshape(-1)  # 将图像平面化
        data_flattened.append(flattened_image)
            
    print(f"Num of images: {len(data_flattened)}")
    print(f"Single image shape after flattening: {data_flattened[0].shape}")
    
    # 将数据转换为numpy数组以供进一步处理
    data_flattened = np.array(data_flattened)
    return data_flattened

# 分配类标签的函数:返回一个numpy数组
def assign_image_class_label(images, class_label = int):
    data_labeled = []
    # 将图像平面化
    data_flattened = flatten_images(images)    
    for image in data_flattened:
        # 分配类标签
        data_labeled.append(np.concatenate([image, [class_label]]))
    
    print(f"Num of images: {len(data_labeled)}")
    print(f"Single data shape with label: {data_labeled[0].shape} --- Class label: {class_label}\n")
    
    # 将数据转换为numpy数组以供进一步处理
    data_labeled = np.array(data_labeled)
    return data_labeled

# 定义一个函数将数组横向连接到pandas数据框中
def concat_arrays_to_dataframe(arrays = []):
    # 垂直地组合成单个数据框架
    dataset = np.concatenate(arrays, axis = 0)
    # 像素列数,不包括最后一个标签列
    num_pix = dataset.shape[1] - 1
    # 修改列名
    col_lst = [f"pixel{col}" for col in range(num_pix)]
    # 追加最后一列的名称作为标签
    col_lst.append("label")
    # 转换为数据框架并添加列名
    df_dataset = pd.DataFrame(dataset, columns = col_lst)
    
    return df_dataset

# 将图像文件分割为训练-测试集。
def split_train_test_files(images_lst_lst = [], num_test_set = int):
    train_images_lst_lst = []
    test_images_lst_lst = []
    for images in images_lst_lst:
        train_set = images[num_test_set:]
        test_set = images[:num_test_set]
        train_images_lst_lst.append(train_set)
        test_images_lst_lst.append(test_set)
        
    return train_images_lst_lst, test_images_lst_lst
# 每个类预留作为测试集的图像数量
num_test_set = 20
# 将图像文件分割为训练-测试集。
train_images, test_images = split_train_test_files(images_lst_lst, num_test_set)
images_lst_array = []
# 遍历类,类索引i将表示类名/标签
for i, images in enumerate(train_images):
    # 为每个图像分配标签
    labeled = assign_image_class_label(images, i)
    images_lst_array.append(labeled)

 将数组连接到dataframe 

# 将数组连接到dataframe
df_images = concat_arrays_to_dataframe(images_lst_array)
df_images.head()

4.3特征工程 

准备建模数据

from sklearn.model_selection import train_test_split
# 准备建模数据X和y
X_images = df_images.drop("label", axis = 1)
y_images = df_images["label"]
# 拆分数据集
X_train, X_val, y_train, y_val = train_test_split(X_images, y_images, test_size = 0.25, random_state = 2, shuffle=True)
print("Shape of train X:", X_train.shape)
print("Shape of train Y:", y_train.shape)
print("Shape of val X:", X_val.shape)
print("Shape of val Y:", y_val.shape)

在缩放前显示一些图像

# 在缩放前显示一些图像
X_train_RGB = np.array(X_train).reshape(-1, 128, 128, 3)
display_images(X_train_RGB)

# 在缩放前显示一些图像
X_val_RGB = np.array(X_val).reshape(-1, 128, 128, 3)
display_images(X_val_RGB)

标准化数据集

from sklearn.preprocessing import MinMaxScaler
# 像素取值范围为0 ~ 255。MinMaxScaler使它从0到1,这降低了所选ML算法的激活函数的幅度敏感性。
scaler = MinMaxScaler(feature_range = (0, 1))
# 转换为numpy数组以在拟合之前删除特征名称
scaler = scaler.fit(np.array(X_train))
X_train_np = scaler.transform(np.array(X_train))
X_val_np = scaler.transform(np.array(X_val))
# 重塑为RGB格式
X_train_RGB = np.array(X_train_np).reshape(-1, 128, 128, 3)
X_val_RGB = np.array(X_val_np).reshape(-1, 128, 128, 3)
# 重塑的目标
y_train = y_train.values.reshape(len(y_train), 1)
y_val = y_val.values.reshape(len(y_val), 1)
print("Shape of train X:", X_train_RGB.shape)
print("Shape of train Y:", y_train.shape)
print("Shape of val X:", X_val_RGB.shape)
print("Shape of val Y:", y_val.shape)

4.4构建模型

导入第三方库

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout, Input
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# 为了避免过度拟合
from tensorflow.keras.callbacks import EarlyStopping 
# 目标变量需要one-hot编码,以确保每个示例的实际类的概率为1.0,其他类的概率为0.0。使用Keras的to_categorical()函数来实现这一点。
from tensorflow.keras.utils import to_categorical
# 绘制神经网络精度实况图
from livelossplot import PlotLossesKeras
# 单个图像的形状
input_shape = X_train_RGB[0].shape
num_train_images = len(X_train_RGB)
# 要预测的类的数量
num_classes = 4
print(f'Single image shape: {input_shape}')
print(f'Number of train images: {num_train_images}')

接下来是模型体系结构及其组件

# 初始化sequential模型
model = Sequential() 
# 添加具有指定输入形状的输入图层
model.add(Input(shape=input_shape))
# 添加一个卷积层,128个大小为3x3的过滤器,使用ReLU激活函数
model.add(Conv2D(128, (3, 3), activation="relu"))
# 添加一个滤镜大小为2x2的最大池化层
model.add(MaxPooling2D((2, 2)))
# 添加dropout正则化来随机省略神经元
model.add(Dropout(0.5))
# 使用ReLU激活函数,添加另一个带有64个大小为3x3的过滤器的卷积层
model.add(Conv2D(64, (3, 3), activation="relu"))          
# 添加另一个最大池层,滤镜大小为2x2
model.add(MaxPooling2D((2, 2)))
# 添加dropout正则化来随机省略神经元
model.add(Dropout(0.5))
# 将前面的层的输出拉平
model.add(Flatten())
# 增加256个神经元的密集层和ReLU激活函数
model.add(Dense(256, activation="relu"))
# 添加dropout正则化来随机省略神经元
model.add(Dropout(0.5))
# 添加一个带有类数量和softmax激活函数的密集输出层
model.add(Dense(num_classes, activation="softmax"))
# 用分类交叉熵损失和随机梯度下降优化器编译模型
opt = SGD(learning_rate=0.0001, momentum=0.9)
model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"])
# 显示模型体系结构的摘要
model.summary()

初始化参数并训练模型 

# 初始化图像增强
train_datagen = ImageDataGenerator(rotation_range = 10,  # rotation
                                   width_shift_range = 0.1,  # horizontal shift
                                   height_shift_range = 0.1,
                                   zoom_range = 0.1) # zoom
# 初始化正则化参数-如果没有进一步的改进,训练停止前需要等待多少epoch
monitor_val_loss = EarlyStopping(monitor = "val_loss", 
                                 min_delta = 1e-3, 
                                 patience = 20, # 再等5个epoch
                                 verbose = 1, 
                                 mode = "auto", 
                                 restore_best_weights = True)
# 初始化epochs、batch_size参数
epochs = 100
batch_size = 64
# 使用flow方法动态增强图像。
training_data = train_datagen.flow(X_train_RGB, to_categorical(y_train), batch_size = batch_size)
# 模型评价
validation_data = (X_val_RGB, to_categorical(y_val))
# 模型训练
history = model.fit(training_data,
                    epochs = epochs,
                    steps_per_epoch = num_train_images // batch_size, # 每个epoch的迭代次数
                    batch_size = batch_size,
                    validation_data = validation_data, 
                    callbacks = [PlotLossesKeras(), monitor_val_loss], 
                    verbose = 1
                   )

4.5模型评估

# 函数用于缩放和重塑每个类的图像
def scale_and_reshape_images(flattened_images_lst = []):
    images_scaled_RGB_lst = []
    for images in flattened_images_lst:
        # 使用与train和val集合相同的缩放器缩放图像
        images_scaled = scaler.transform(images)
        # 重塑为RGB格式
        images_scaled_RGB = np.array(images_scaled).reshape(-1, 128, 128, 3)
        images_scaled_RGB_lst.append(images_scaled_RGB)
    return images_scaled_RGB_lst

# 显示单个图像
def display_image(image_single):
    image_flat = image_single.reshape(1, -1) # 
    image_inv = scaler.inverse_transform(image_flat) 
    image_reshaped = image_inv.reshape(128, 128, 3)
    image = image_reshaped.astype(np.uint8)
    plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) 
    plt.show()

# 解释模型预测:返回预测的类和以%为单位的置信水平
def interpret_model_prediction(predictions):
    # 将推断转换为列表和
    pred_lst = predictions[0,:].tolist()
    # 获取最大值
    max_proba = max(pred_lst)
    # 获取max_probability的索引位置
    pred_idx = pred_lst.index(max_proba)
    return pred_idx, max_proba

# 定义函数来进行推断/预测。
# 接受实际值(String)和图像索引(从0到n的int,其中n是num_test_set)
def make_predictions(scaled_RGB_lst, image_class = '', image_idx = int):
    # 从定义的类字典中获取类的数值
    class_val = classes[image_class]
    # 获取单个图像
    image_single = scaled_RGB_lst[class_val][image_idx]
    # 对一张图像进行预测。必须重新塑造
    pred = model.predict(image_single.reshape(1, 128, 128, 3))
    # 解释模型预测
    pred_class, confidence = interpret_model_prediction(pred)
    # 展示图片
    display_image(image_single)
    print(f"Actual: {image_class}")
    print(f"Predicted: {list(classes.keys())[pred_class]}")
    print(f'Confidence: {round(confidence, 4)}')
# 将图像平面化
images_lst_array = []
for images in test_images:
    # 函数返回两个值
    flattened = flatten_images(images) # Num_test_set是预留作为测试集的图像数量
    images_lst_array.append(flattened)

# 对每个类的图像进行归一化和重塑
images_scaled_RGB_lst = scale_and_reshape_images(images_lst_array)
# 上面定义的类字典中的键
class_keys = list(classes.keys())
# 来自测试集的图像索引
image_idx = 2
for key in class_keys:
    make_predictions(images_scaled_RGB_lst, key, image_idx)

4.6模型保存

# 保存模型
model.save("disease_detector_model.keras")

文末推荐

《GPTs与GPT Store应用开发详解》

内容简介       

  1. 本书详细介绍了如何根据个人需求和应用场景创建定制化GPTs,为各个行业的创新者开辟了新的可能性,助力了各种新应用和服务的诞生。本书从理论到实战,由浅入深,对创建定制化GPTs的方法与技术进行了全方位的介绍,为希望深入了解并应用这一前沿技术的专业人士、开发者和爱好者提供了全面的学习指导。从而根据自己的需求定制和优化GPTs。
  2. 本书分四篇,共13章,包括ChatGPT介绍、定制化GPTs基础知识、GPTs使用场景介绍、GPTs创建步骤、使用GPTs的高级定制、使用Zapier完成自动作业、搭建LOGO制作助手GPT、搭建数学学习助手GPT、搭建邮件助手GPT、搭建插图助手GPT、搭建足球比赛查询GPT、GPT Store介绍、GPT Store上架实战。
  3. 本书内容详尽,原理论述简单明了,案例丰富,内容由浅入深,具有很强的可读性。它既适合初次接触AI技术的普通读者阅读,也适合有一定经验的AI从业者借鉴。此外,本书也适合那些需要了解最新ChatGPT技术的开发人员阅读。

京东购买链接:https://item.jd.com/14833204.html

当当购买链接:http://product.dangdang.com/29802146.html

 《ChatGPT 4 应用详解:AI文案+AI绘画+AI视频+GPTs》

内容简介        

12 大专题讲解 +31 个温馨提示+ 70 多个效果文件 +208 页 PPT 教学课件+ 210 多分钟教学视频+280 多张精美插图,随书还提供了 200 多个提示词等资源,帮助读者从入门到精通 ChatGPT 4 的全部应用。全书共分为 5 篇,具体内容如下:

AI 提示篇介绍了 ChatGPT 4 的基本操作,以及优化 AI 提示让回答更加精准等内容。

AI 文案篇介绍了 ChatGPT 4 生成优质文案的方法,以及电商、新媒体等常见案例。

AI 绘画篇介绍了 Dall·E 3 的使用技巧,以及绘画指令和艺术、海报等 AI 绘画案例。

AI 视频篇介绍了运用 CapCut VideoGPT 与 Visla Video Maker 生成 AI 视频的操作方法。

GPTs 篇介绍了使用 GPTs 实现高效化学习和提高工作效率的方法,如用 Diagrams: Show Me 绘制图表、用 Wolfram 处理专业性问题、用 Doc Maker 生成高质量文档、用 PDF Ai PDF 快速分析文档。

本书适合想要了解 ChatGPT 4 和 GPTs 的读者,包括 AI 文案创作者、AI 绘画爱好者等,以及相关行业从业者,包括文案工作者、营销人员、自媒体人、视频剪辑师、插画设计师、包装设计师、电商美工人员、插图师、影视制作人员等阅读,也可作为相关培训机构、职业院校的参考教材。

京东购买链接:https://item.jd.com/14308053.html

当当购买链接:http://product.dangdang.com/29795683.html

源代码

import os
import cv2
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')

# 定义加载和调整图像大小的函数
def load_and_resize_image(file_path, target_shape=(128, 128)):
    image = cv2.imread(file_path)
    resized_image = cv2.resize(image, target_shape)
    return resized_image

# 定义函数加载每个图像类(目标)存储在单独的目录
# 每个类目录包含各自的图像
def load_image_class_by_directory(image_dir):
    # 加载和调整图像大小
    image_files = os.listdir(image_dir)
    images = []
    for file in image_files:
        if file.endswith('.jpg') or file.endswith('.JPG'):  # 假设图像是jpg或jpg格式
            image_path = os.path.join(image_dir, file)
            resized_image = load_and_resize_image(image_path)
            images.append(resized_image)

    print(f"Num of images: {len(images)}")        
    print(f"Single image shape before flattening: {images[0].shape}")
    return images

# 显示一些图像
def display_images(images, num_images_to_display = 6):
    fig, axes = plt.subplots(1, num_images_to_display, figsize=(20, 5))
    for i in range(num_images_to_display):
        # 在颜色转换之前,将图像转换为支持的深度(例如,CV_8U)
        image = images[i].astype(np.uint8)
        axes[i].imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))  # 将BGR转换为RGB以使用matplotlib显示
        axes[i].axis('off')
    plt.show()
# 定义包含图像的目录
image_dir = "./data/Blight"
images_Blight = load_image_class_by_directory(image_dir)
display_images(images_Blight)
# 定义包含图像的目录
image_dir = "./data/Common_Rust"
images_Common_Rust = load_image_class_by_directory(image_dir)
display_images(images_Common_Rust)
# 定义包含图像的目录
image_dir = "./data/Gray_Leaf_Spot"
images_Gray_Leaf_Spot = load_image_class_by_directory(image_dir)
display_images(images_Gray_Leaf_Spot)
# 定义包含图像的目录
image_dir = "./data/Healthy"
images_Healthy = load_image_class_by_directory(image_dir)
display_images(images_Healthy)
检查样品
# 定义类标签
classes = {'Blight': 0, 'Common_Rust': 1, 'Gray_Leaf_Spot': 2, 'Healthy': 3} 
inverted_classes = {0: 'Blight', 1: 'Common_Rust', 2: 'Gray_Leaf_Spot', 3: 'Healthy'}
images_lst_lst = [images_Blight, images_Common_Rust, images_Gray_Leaf_Spot, images_Healthy]

# 字典来存储图像样本的数量
classes_dict = {}
for i, images in enumerate(images_lst_lst):
    classes_dict.update({inverted_classes[i]: len(images)})
    print(f'Disease: {inverted_classes[i]} --- Images: {len(images)}')
plt.bar(*zip(*classes_dict.items()))
plt.show()
存在一种类别不平衡,Gray_Leaf_Spot的案例较少。这可能会影响模型识别类的能力,或者至少会影响高置信度的识别能力。
分配类标签
选择要设置为测试集的图像数量。算法不应该看到这些数据,因为它将用于以后的评估。
为每个图像添加一个类标签。这是通过首先将图像从2D扁平化到1D,然后将类别编号附加到其上(例如Blight为0等)来完成的。
# 函数将RGB值从2D平铺到1D,返回numpy数组
def flatten_images(images):
    data_flattened = []
    for image in images:
        flattened_image = image.reshape(-1)  # 将图像平面化
        data_flattened.append(flattened_image)
            
    print(f"Num of images: {len(data_flattened)}")
    print(f"Single image shape after flattening: {data_flattened[0].shape}")
    
    # 将数据转换为numpy数组以供进一步处理
    data_flattened = np.array(data_flattened)
    return data_flattened

# 分配类标签的函数:返回一个numpy数组
def assign_image_class_label(images, class_label = int):
    data_labeled = []
    # 将图像平面化
    data_flattened = flatten_images(images)    
    for image in data_flattened:
        # 分配类标签
        data_labeled.append(np.concatenate([image, [class_label]]))
    
    print(f"Num of images: {len(data_labeled)}")
    print(f"Single data shape with label: {data_labeled[0].shape} --- Class label: {class_label}\n")
    
    # 将数据转换为numpy数组以供进一步处理
    data_labeled = np.array(data_labeled)
    return data_labeled

# 定义一个函数将数组横向连接到pandas数据框中
def concat_arrays_to_dataframe(arrays = []):
    # 垂直地组合成单个数据框架
    dataset = np.concatenate(arrays, axis = 0)
    # 像素列数,不包括最后一个标签列
    num_pix = dataset.shape[1] - 1
    # 修改列名
    col_lst = [f"pixel{col}" for col in range(num_pix)]
    # 追加最后一列的名称作为标签
    col_lst.append("label")
    # 转换为数据框架并添加列名
    df_dataset = pd.DataFrame(dataset, columns = col_lst)
    
    return df_dataset

# 将图像文件分割为训练-测试集。
def split_train_test_files(images_lst_lst = [], num_test_set = int):
    train_images_lst_lst = []
    test_images_lst_lst = []
    for images in images_lst_lst:
        train_set = images[num_test_set:]
        test_set = images[:num_test_set]
        train_images_lst_lst.append(train_set)
        test_images_lst_lst.append(test_set)
        
    return train_images_lst_lst, test_images_lst_lst
# 每个类预留作为测试集的图像数量
num_test_set = 20
# 将图像文件分割为训练-测试集。
train_images, test_images = split_train_test_files(images_lst_lst, num_test_set)
images_lst_array = []
# 遍历类,类索引i将表示类名/标签
for i, images in enumerate(train_images):
    # 为每个图像分配标签
    labeled = assign_image_class_label(images, i)
    images_lst_array.append(labeled)
# 将数组连接到dataframe
df_images = concat_arrays_to_dataframe(images_lst_array)
df_images.head()
from sklearn.model_selection import train_test_split
# 准备建模数据X和y
X_images = df_images.drop("label", axis = 1)
y_images = df_images["label"]
# 拆分数据集
X_train, X_val, y_train, y_val = train_test_split(X_images, y_images, test_size = 0.25, random_state = 2, shuffle=True)
print("Shape of train X:", X_train.shape)
print("Shape of train Y:", y_train.shape)
print("Shape of val X:", X_val.shape)
print("Shape of val Y:", y_val.shape)
# 在缩放前显示一些图像
X_train_RGB = np.array(X_train).reshape(-1, 128, 128, 3)
display_images(X_train_RGB)
# 在缩放前显示一些图像
X_val_RGB = np.array(X_val).reshape(-1, 128, 128, 3)
display_images(X_val_RGB)
标准化数据集
from sklearn.preprocessing import MinMaxScaler
# 像素取值范围为0 ~ 255。MinMaxScaler使它从0到1,这降低了所选ML算法的激活函数的幅度敏感性。
scaler = MinMaxScaler(feature_range = (0, 1))
# 转换为numpy数组以在拟合之前删除特征名称
scaler = scaler.fit(np.array(X_train))
X_train_np = scaler.transform(np.array(X_train))
X_val_np = scaler.transform(np.array(X_val))
# 重塑为RGB格式
X_train_RGB = np.array(X_train_np).reshape(-1, 128, 128, 3)
X_val_RGB = np.array(X_val_np).reshape(-1, 128, 128, 3)
# 重塑的目标
y_train = y_train.values.reshape(len(y_train), 1)
y_val = y_val.values.reshape(len(y_val), 1)
print("Shape of train X:", X_train_RGB.shape)
print("Shape of train Y:", y_train.shape)
print("Shape of val X:", X_val_RGB.shape)
print("Shape of val Y:", y_val.shape)
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout, Input
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# 为了避免过度拟合
from tensorflow.keras.callbacks import EarlyStopping 
# 目标变量需要one-hot编码,以确保每个示例的实际类的概率为1.0,其他类的概率为0.0。使用Keras的to_categorical()函数来实现这一点。
from tensorflow.keras.utils import to_categorical
# 绘制神经网络精度实况图
from livelossplot import PlotLossesKeras
# 单个图像的形状
input_shape = X_train_RGB[0].shape
num_train_images = len(X_train_RGB)
# 要预测的类的数量
num_classes = 4
print(f'Single image shape: {input_shape}')
print(f'Number of train images: {num_train_images}')
接下来是模型体系结构及其组件
# 初始化sequential模型
model = Sequential() 
# 添加具有指定输入形状的输入图层
model.add(Input(shape=input_shape))
# 添加一个卷积层,128个大小为3x3的过滤器,使用ReLU激活函数
model.add(Conv2D(128, (3, 3), activation="relu"))
# 添加一个滤镜大小为2x2的最大池化层
model.add(MaxPooling2D((2, 2)))
# 添加dropout正则化来随机省略神经元
model.add(Dropout(0.5))
# 使用ReLU激活函数,添加另一个带有64个大小为3x3的过滤器的卷积层
model.add(Conv2D(64, (3, 3), activation="relu"))          
# 添加另一个最大池层,滤镜大小为2x2
model.add(MaxPooling2D((2, 2)))
# 添加dropout正则化来随机省略神经元
model.add(Dropout(0.5))
# 将前面的层的输出拉平
model.add(Flatten())
# 增加256个神经元的密集层和ReLU激活函数
model.add(Dense(256, activation="relu"))
# 添加dropout正则化来随机省略神经元
model.add(Dropout(0.5))
# 添加一个带有类数量和softmax激活函数的密集输出层
model.add(Dense(num_classes, activation="softmax"))
# 用分类交叉熵损失和随机梯度下降优化器编译模型
opt = SGD(learning_rate=0.0001, momentum=0.9)
model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"])
# 显示模型体系结构的摘要
model.summary()
# 初始化图像增强
train_datagen = ImageDataGenerator(rotation_range = 10,  # rotation
                                   width_shift_range = 0.1,  # horizontal shift
                                   height_shift_range = 0.1,
                                   zoom_range = 0.1) # zoom
# 初始化正则化参数-如果没有进一步的改进,训练停止前需要等待多少epoch
monitor_val_loss = EarlyStopping(monitor = "val_loss", 
                                 min_delta = 1e-3, 
                                 patience = 20, # 再等5个epoch
                                 verbose = 1, 
                                 mode = "auto", 
                                 restore_best_weights = True)
# 初始化epochs、batch_size参数
epochs = 100
batch_size = 64
# 使用flow方法动态增强图像。
training_data = train_datagen.flow(X_train_RGB, to_categorical(y_train), batch_size = batch_size)
# 模型评价
validation_data = (X_val_RGB, to_categorical(y_val))
# 模型训练
history = model.fit(training_data,
                    epochs = epochs,
                    steps_per_epoch = num_train_images // batch_size, # 每个epoch的迭代次数
                    batch_size = batch_size,
                    validation_data = validation_data, 
                    callbacks = [PlotLossesKeras(), monitor_val_loss], 
                    verbose = 1
                   )
# 函数用于缩放和重塑每个类的图像
def scale_and_reshape_images(flattened_images_lst = []):
    images_scaled_RGB_lst = []
    for images in flattened_images_lst:
        # 使用与train和val集合相同的缩放器缩放图像
        images_scaled = scaler.transform(images)
        # 重塑为RGB格式
        images_scaled_RGB = np.array(images_scaled).reshape(-1, 128, 128, 3)
        images_scaled_RGB_lst.append(images_scaled_RGB)
    return images_scaled_RGB_lst

# 显示单个图像
def display_image(image_single):
    image_flat = image_single.reshape(1, -1) # 
    image_inv = scaler.inverse_transform(image_flat) 
    image_reshaped = image_inv.reshape(128, 128, 3)
    image = image_reshaped.astype(np.uint8)
    plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) 
    plt.show()

# 解释模型预测:返回预测的类和以%为单位的置信水平
def interpret_model_prediction(predictions):
    # 将推断转换为列表和
    pred_lst = predictions[0,:].tolist()
    # 获取最大值
    max_proba = max(pred_lst)
    # 获取max_probability的索引位置
    pred_idx = pred_lst.index(max_proba)
    return pred_idx, max_proba

# 定义函数来进行推断/预测。
# 接受实际值(String)和图像索引(从0到n的int,其中n是num_test_set)
def make_predictions(scaled_RGB_lst, image_class = '', image_idx = int):
    # 从定义的类字典中获取类的数值
    class_val = classes[image_class]
    # 获取单个图像
    image_single = scaled_RGB_lst[class_val][image_idx]
    # 对一张图像进行预测。必须重新塑造
    pred = model.predict(image_single.reshape(1, 128, 128, 3))
    # 解释模型预测
    pred_class, confidence = interpret_model_prediction(pred)
    # 展示图片
    display_image(image_single)
    print(f"Actual: {image_class}")
    print(f"Predicted: {list(classes.keys())[pred_class]}")
    print(f'Confidence: {round(confidence, 4)}')
# 将图像平面化
images_lst_array = []
for images in test_images:
    # 函数返回两个值
    flattened = flatten_images(images) # Num_test_set是预留作为测试集的图像数量
    images_lst_array.append(flattened)
# 对每个类的图像进行归一化和重塑
images_scaled_RGB_lst = scale_and_reshape_images(images_lst_array)
# 上面定义的类字典中的键
class_keys = list(classes.keys())
# 来自测试集的图像索引
image_idx = 2
for key in class_keys:
    make_predictions(images_scaled_RGB_lst, key, image_idx)
# 保存模型
model.save("disease_detector_model.keras")

资料获取,更多粉丝福利,关注下方公众号获取

在这里插入图片描述

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐