基于百度飞桨的玉米异常果穗智能筛分案例

基于百度飞桨的玉米异常果穗智能筛分案例

本项目基于百度飞桨构建了玉米异常果穗图像分类模型,实现了玉米制种果穗高通量智能筛分任务。文中着重介绍玉米异常果穗智能筛分模型中的图像数据分类模型的构造方法等。

1 项目背景

玉米作为重要粮食作物,种子质量是影响玉米产量的关键因素;选用优质玉米种子即:玉米制种穗选是重要环节,筛分出异常果穗(机械损伤、虫蛀、败育、病害等),有利于提高玉米种子的纯度和发芽率。传统的玉米制种穗选工作主要依靠人工,费时费力、存在主观误差。因此,研究基于人工智能技术的高通量玉米果穗智能筛分方法,提高玉米制种筛分的速率和效率,具有重要意义。
玉米新品种选育工作多在田间进行,果穗图像易受周围环境(光照、粉尘、花丝附着、散落的碎粒等)影响,图像存在光照不均、霉变果穗颜色变化丰富、背景复杂、噪声大、果穗异常区域形状复杂等,采用传统的图像处理方法对玉米果穗进行筛分鲁棒性,难以满足育种的实际行业需要。异常果穗包括以下几种,如下图所示:

  1. 机械损伤果穗:大型机械设备收获果穗较为新鲜,新鲜果穗含水量较大(30%左右),易造成果穗表皮损伤,露出白色胚乳;受伤胚乳易霉变,对玉米发芽率影响较大,影响产量。
  2. 虫蛀果穗:受种植环境影响果穗发生病虫害,或存储过程中害虫对穗部叮咬,使得玉米果穗失去制种价值。
  3. 霉变果穗:玉米果穗在田间或存储中,由于环境水分含量过高引起穗部发生霉变,籽粒呈现出各种霉斑颜色,失去制种价值。
  4. 畸形果穗:玉米果穗两头大且有籽粒,中间部分小,没有结实籽粒;或果穗只有单侧面有籽粒,或只有很少籽粒散落分布,或果穗顶部秃尖过大,几乎可占果穗1/2以上。
  5. 异种果穗:与所选的目标品种不同的果穗,这部分果穗若混入目标品种果穗中会影响后期制种的纯度。
  6. 败育果穗:由于品种缺陷等原因导致玉米果穗顶部未发育或发育不全,表现为上部无籽粒或籽粒干瘪,严重秃尖可占果穗的1/2以上。

本项目基于飞桨PaddlePaddle框架,快速构建多种经典的卷积神经网络模型,解决玉米异常果穗筛分中的技术难点,实现对玉米果穗的高通量智能筛分。

2 项目方案

项目结合农业玉米异常果穗筛分这一实际问题,基于百度PaddlePaddle,我们研发了高通量玉米果穗智能筛分系统。系统的整体方案如下:

通过飞桨PaddlePaddle框架,构建、训练多种卷积神经网络,并测试它们对玉米果穗图像进行分类效果,调整各网络模型参数,最终选择最有网络模型实现对玉米果穗的精准、高效率筛分。采用的比对网络包括:AlexNet、VGG、ResNet、MobileNet v1和MobileNet v2等。

AlexNet:2012年ImageNet竞赛冠军模型,与此前的LeNet相比,具有更深的网络结构,包含5层卷积和3层全连接,具体结构如下图所示。

VGG:使用大小为3x3的小尺寸卷积核和池化层构造深度卷积神经网络,结构简单,
下图是VGG-16的网络结构示意图,有13层卷积和3层全连接层,在网络最后使用3层全连接层,将最后一层全连接层的输出作为分类预测。

ResNet:2015年ImageNet图像分类、物体定位和目标检测比赛冠军。针对随着网络训练加深导致准确度下降的问题,ResNet提出了残差学习方法来减轻训练深层网络的困难。每个残差模块包含两条路径,其中一条路径是输入特征的直连通路,另一条路径对该特征做两到三次卷积操作得到该特征的残差,最后再将两条路径上的特征相加。残差模块及ResNet不同深度的几种结构如下图。

MobileNet:为移动和嵌入式设备提出的高效模型,MobileNet基于流线型架构(streamlined),使用深度可分离卷积(depthwise separable convolutions)来构建轻量级深度神经网络。如下图,深度可分离卷积把标准卷积分解成深度卷积和逐点卷积两大部分,大幅度降低了模型的参数量和计算量。

以上模型介绍内容部分来源于飞桨官方出品的一站式深度学习在线百科。

3 数据说明

本项目图像数据集使用团队研发的玉米异常果穗筛分便携设备和高通量筛分装置(如下图左、右)分别采集果穗图像。

    

采集图像包含正常、霉变、虫蛀、机械损伤和带苞叶等几个类别果穗,共81张图像。实验以7:2:1比例将数据集随机划分为训练集、测试集和验证集,部分图像如下:

说明:针对制种果穗类别样本数据不均衡的问题,也可采用镜像、旋转任意角度、改变亮度等技术实现样本数据的扩增,如下图所示。

4 代码实现

代码实现如下:

!unzip data/data111443/dataset.zip -d work/dataset
import os
import shutil
import numpy as np
import paddle
from paddle.io import Dataset
from paddle.vision.datasets import DatasetFolder, ImageFolder
from paddle.vision.transforms import Compose, Resize, Transpose, ToTensor, Normalize
import paddle.nn.functional as F
'''
参数配置
'''
train_parameters = {
    "class_dim": 4,  # 分类数
    "target_path": r'work',
    'train_image_dir': r'work/dataset/trainImages',
    'eval_image_dir': r'work/dataset/evalImages',
    'test_image_dir': r'work/dataset/testImages',
}

# ## 定义数据集
class Dataset(Dataset):
    """
    步骤一:继承paddle.io.Dataset类
    """
    def __init__(self, mode='train'):
        """
        步骤二:实现构造函数,定义数据读取方式,划分训练和测试数据集
        """
        super(Dataset, self).__init__()
        train_image_dir = train_parameters['train_image_dir']
        eval_image_dir = train_parameters['eval_image_dir']
        test_image_dir = train_parameters['test_image_dir']
        transform_train = Compose([Resize(size=(224, 224)), Transpose(), Normalize()])
        transform_eval = Compose([Resize(size=(224, 224)), Transpose(), Normalize()])
        train_data_folder = DatasetFolder(train_image_dir, transform=transform_train)
        eval_data_folder = DatasetFolder(eval_image_dir, transform=transform_eval)
        test_data_folder = DatasetFolder(test_image_dir, transform=transform_eval)
        self.mode = mode
        if self.mode == 'train':
            self.data = train_data_folder
        elif self.mode == 'eval':
            self.data = eval_data_folder
        elif self.mode == 'test':
            self.data = test_data_folder

    def __getitem__(self, index):
        """
        步骤三:实现__getitem__方法,定义指定index时如何获取数据,并返回单条数据(训练数据,对应的标签)
        """
        data = np.array(self.data[index][0]).astype('float32')
        label = np.array([self.data[index][1]]).astype('int64')
        return data, label

    def __len__(self):
        """
        步骤四:实现__len__方法,返回数据集总数目
        """
        return len(self.data)

train_dataset = Dataset(mode='train')
val_dataset = Dataset(mode='eval')
test_dataset = Dataset(mode='test')


# 定义多种不同神经网络模型
# 定义AlexNet网络
class AlexNet(paddle.nn.Layer):
    def __init__(self, class_dim):
        super(AlexNet, self).__init__()

        self.conv1 = paddle.nn.Conv2D(3, 96, 11, stride=4, padding=2)
        self.pool1 = paddle.nn.MaxPool2D(3, stride=2, padding=0)
        self.conv2 = paddle.nn.Conv2D(96, 256, 5, stride=1, padding=2)
        self.pool2 = paddle.nn.MaxPool2D(3, stride=2, padding=0)
        self.conv3 = paddle.nn.Conv2D(256, 384, 3, stride=1, padding=1)
        self.conv4 = paddle.nn.Conv2D(384, 384, 3, stride=1, padding=1)
        self.conv5 = paddle.nn.Conv2D(384, 256, 3, stride=1, padding=1)
        self.pool3 = paddle.nn.MaxPool2D(3, stride=2, padding=0)

        self.fc1 = paddle.nn.Linear(9216, 4096)
        self.fc2 = paddle.nn.Linear(4096, 4096)
        self.fc3 = paddle.nn.Linear(4096, class_dim)

        self.relu = paddle.nn.ReLU()
        self.dropout = paddle.nn.Dropout(p=0.5)
        self.softmax = paddle.nn.Softmax()

    def forward(self, x):
        x = self.conv1(x)
        x = self.relu(x)
        x = self.pool1(x)
        x = self.conv2(x)
        x = self.relu(x)
        x = self.pool2(x)
        x = self.conv3(x)
        x = self.relu(x)
        x = self.conv4(x)
        x = self.relu(x)
        x = self.conv5(x)
        x = self.relu(x)
        x = self.pool3(x)
        x = paddle.flatten(x, start_axis=1, stop_axis=3)
        x = self.fc1(x)
        x = self.relu(x)
        x = self.fc2(x)
        x = self.relu(x)
        x = self.fc3(x)
        x = self.softmax(x)
        return x
model_alexnet = AlexNet(class_dim=train_parameters["class_dim"])
# 定义ResNet网络
model_resnet = model = paddle.vision.models.resnet50(pretrained=True, num_classes=train_parameters["class_dim"])
# 定义VGG网络
model_vgg = paddle.vision.models.vgg16(pretrained=True, batch_norm=False, num_classes=train_parameters["class_dim"])
# 定义MobileNet v1网络
model_mobilenet_v1 = paddle.vision.models.mobilenet_v1(pretrained=True, num_classes=train_parameters["class_dim"])
# 定义MobileNet v2网络
model_mobilenet_v2= paddle.vision.models.mobilenet_v2(pretrained=True, num_classes=train_parameters["class_dim"])

# 切换使用的网络
model = paddle.Model(model_mobilenet_v1)

# ## 查看模型结构
model.summary((-1, 3, 224, 224))

print('***')

# ## 模型配置:为模型训练做准备,设置优化器,损失函数和精度计算方式

best_train_acc = 0.1

# 保存准确率最高的模型
class SaveBestModel(paddle.callbacks.Callback):
    def __init__(self, target_train_acc=0.1, target_val_acc=0.1, path='./best_model'):
        self.target_train_acc = target_train_acc
        self.target_val_acc = target_val_acc
        self.epoch = None
        self.path = path

    def on_epoch_end(self, epoch, logs=None):
        self.epoch = epoch
        global best_train_acc
        if logs.get('acc') > self.target_train_acc:
            self.target_train_acc = logs.get('acc')
            best_train_acc = self.target_train_acc

    def on_eval_end(self, logs=None):
        if logs.get('acc') > self.target_val_acc:
            self.target_val_acc = logs.get('acc')
            self.model.save(self.path)
            print('best train acc is {}, best val acc is {} at epoch {}'.format(self.target_train_acc,
                                                                                self.target_val_acc, self.epoch))

# 调用飞桨框架的VisualDL模块,保存信息到目录中。
model_type = 'mobilenet_v1/'
callback_visualdl = paddle.callbacks.VisualDL(log_dir='visualdl_log_dir/'+model_type)
callback_savebestmodel = SaveBestModel(path='work/'+model_type+'best_model')
callbacks = [callback_visualdl, callback_savebestmodel]

model.prepare(optimizer=paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters()),
              loss=paddle.nn.CrossEntropyLoss(),
              metrics=paddle.metric.Accuracy())

# ## 模型训练
model.fit(train_dataset,
          val_dataset,
          epochs=50,
          batch_size=8,
          callbacks=callbacks,
          verbose=2)

print('***')

print('%.5f' % best_train_acc)

# ## 启动模型评估,指定数据集,设置日志格式

res = model.evaluate(test_dataset, verbose=1)

print('%.5f' % res['acc'])

5 项目展示

项目对比了各模型在相同数据集下的不同性能,如下图所示。经过50轮迭代训练后,ResNet与MobileNet等模型在玉米果穗分类任务中取得的效果优于AlexNet和VGG等模型的效果。

    
    

6 总结提高

本项目针对玉米异常果穗智能筛分这一农业领域实际生产问题,分别构造了AlexNet、VGG、ResNet、MobileNet等多种卷积神经网络进行图像分类识别。针对数据集相对较小的情况,选择较小的Batchsize,并调用PaddlePaddle的图像增强API进行数据增强处理,可以有效提升玉米异常果穗识别的准确率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值