木薯树疾病识别基于vgg16图片分类

木薯树疾病识别基于vgg16图片分类

  • 前言
  • 一、数据集分析:
  • 二、数据预处理方法:
    • 1. 添加划分验证集需要的文件夹
    • 2.读入数据
    • 3.数据集拆分函数:
    • 4.划分验证集
    • 5.将划分好的图片分类保存
    • 6.原始图片预处理:
  • 三、创建网络模型:
  • 四、设置模型参数:
  • 五、模型训练:
  • 六、图片预测分类:
  • 总结


前言

木薯树叶病识别与模型集成
广西多丘陵旱地,自然条件适宜木薯生产。广西一直大面积种植木薯,保持着全国木薯
生产前列的地位。木薯不仅是农民收入的主要来源,而且其加工产品丰富,产业链条长,经
济影响面广。然而,木薯病虫害诊断和防治问题给种植木薯的农民生产带来了巨大的挑战。
主要问题如下:
(1)农业专家的离线问诊,存在时效性不高的问题;
(2)农业专家的在线问诊,存在着农民拍摄的图片专业度不高,影响了专家在线问诊判别木薯病虫害的精度。
针对上述问题,基于 VGG-16 深度学习神经网络设计了识别出四种疾病、木薯健康
的叶子和非木薯叶子(共六类)的模型,通过大数据技术、云计算技术的帮助下,成功运行
模型识别分类了一万五千多张木薯图片。


一、数据集分析:

原始数据集包含两个文件夹
1 包含所有图片的data文件夹
2 包含所有图片的名字和分类的csv文件,共6个类别
木薯树疾病识别基于vgg16图片分类_第1张图片

二、数据预处理方法:

1. 添加划分验证集需要的文件夹

代码如下(示例):

os.makedirs('./data-raw/train/0')
os.makedirs('./data-raw/train/1')
os.makedirs('./data-raw/train/2')
os.makedirs('./data-raw/train/3')
os.makedirs('./data-raw/train/4')
os.makedirs('./data-raw/train/5')

os.makedirs('./data-raw/vel/0')
os.makedirs('./data-raw/vel/1')
os.makedirs('./data-raw/vel/2')
os.makedirs('./data-raw/vel/3')
os.makedirs('./data-raw/vel/4')
os.makedirs('./data-raw/vel/5')

2.读入数据

读取train.csv文件
将image_id以列表保存到data_img_name
将label以列表保存到label
注意要去掉第一行

代码如下(示例):

import csv
f_csv = open('./data/raw/2021hwjx/train.csv', "r")
read = csv.reader(f_csv)
a = list(read)
data_img_name = []
label = []
for i in a:
    data_img_name.append(i[0])
    label.append(i[1])
data_img_name.remove('image_id')
label.remove('label')

3.数据集拆分函数:

将列表full_list按比例ratio(随机)划分为2个子列表sublist_1与sublist_2
:param full_list: 数据列表
:param ratio: 子列表1
:param shuffle: 子列表2
:return:

代码如下(示例):

def data_split(full_list, ratio, shuffle=False):

    n_total = len(full_list)
    offset = int(n_total * ratio)
    if n_total == 0 or offset < 1:
        return [], full_list
    if shuffle:
        random.shuffle(full_list)
    sublist_1 = full_list[:offset]
    sublist_2 = full_list[offset:]
    return sublist_1, sublist_2

4.划分验证集

对数据集进行切片分类,按比例划分 验证集:训练集=2:8
对每个类别随机选取80%再合并到一个列表
(可直接从csv表格看出每个类别分别到第几行结束)
代码如下(示例):

train_0 = data_img_name[:978]
test_data0, train_data0 = data_split(train_0, ratio=0.2)
test_label_0 = [0]*len(test_data0)
train_label_0 = [0]*len(train_data0)

train_1 = data_img_name[978:2948]
test_data1, train_data1 = data_split(train_1, ratio=0.2)
test_label_1 = [1]*len(test_data1)
train_label_1 = [1]*len(train_data1)

train_2 = data_img_name[2948:5095]
test_data2, train_data2 = data_split(train_2, ratio=0.2)
test_label_2 = [2]*len(test_data2)
train_label_2 = [2]*len(train_data2)

train_3 = data_img_name[5095:10637]
test_data3, train_data3 = data_split(train_3, ratio=0.2)
test_label_3 = [3]*len(test_data3)
train_label_3 = [3]*len(train_data3)

train_4 = data_img_name[10637:12956]
test_data4, train_data4 = data_split(train_4, ratio=0.2)
test_label_4 = [4]*len(test_data4)
train_label_4 = [4]*len(train_data4)

train_5 = data_img_name[12956:]
test_data5, train_data5 = data_split(train_5, ratio=0.2)
test_label_5 = [5]*len(test_data5)
train_label_5 = [5]*len(train_data5)

# 训练集
train_data = train_data0 + train_data1 + train_data2 + train_data3 + train_data4 + train_data5
train_label = train_label_0 + train_label_1 + train_label_2 + train_label_3 + train_label_4 + train_label_5

# 验证集
test_data = test_data0 + test_data1 + test_data2 + test_data3 + test_data4 + test_data5
test_label = test_label_0 + test_label_1 + test_label_2 + test_label_3 + test_label_4 + test_label_5

5.将划分好的图片分类保存

将原始图片复制到分好类别的文件夹下

代码如下(示例):

import shutil

root_dir = './data/raw/2021hwjx/train_img'

a = 6
train_range = []

for j in range(a):
    if j == 0:
        train_range = train_data0
    if j == 1:
        train_range = train_data1
    if j == 2:
        train_range = train_data2
    if j == 3:
        train_range = train_data3
    if j == 4:
        train_range = train_data4
    if j == 5:
        train_range = train_data5
    for i in range(len(train_range)):
        img_dir = os.path.join(root_dir, train_range[i])
        shutil.move(img_dir, './data-raw/train/{}'.format(j))


for j in range(a):
    if j == 0:
        test_range = test_data0
    if j == 1:
        test_range = test_data1
    if j == 2:
        test_range = test_data2
    if j == 3:
        test_range = test_data3
    if j == 4:
        test_range = test_data4
    if j == 5:
        test_range = test_data5
    for i in range(len(test_range)):
        img_dir = os.path.join(root_dir, test_range[i])
        shutil.move(img_dir, './data-raw/vel/{}'.format(j))

6.原始图片预处理:

对原始进行变换
包括裁剪
归一化
将PIL image转化为VGG16需要的tensor型

代码如下(示例):

from torch.utils.data import DataLoader
from torchvision import datasets, transforms
import torchvision

batch_size = 16

train_transforms = transforms.Compose([
    transforms.RandomResizedCrop(224),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
    transforms.Normalize((.5, .5, .5), (.5, .5, .5))
])
val_transforms = transforms.Compose([
    transforms.RandomResizedCrop(224),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
    transforms.Normalize((.5, .5, .5), (.5, .5, .5))
])

train_dir = './data-raw/train'
train_datasets = datasets.ImageFolder(train_dir, transform=train_transforms)
train_data_loader = torch.utils.data.DataLoader(train_datasets, batch_size=batch_size, shuffle=True)

val_dir = './data-raw/vel'
val_datasets = datasets.ImageFolder(val_dir, transform=val_transforms)
val_data_loader = torch.utils.data.DataLoader(val_datasets, batch_size=batch_size, shuffle=True)

三、创建网络模型:

下载VGG16预训练模型
对模型经行修改
加上一层1000输入6输出的线性层,使其满足我们的分类需求

代码如下(示例):

import torchvision
from torch import nn

vgg16_true = torchvision.models.vgg16(pretrained=True)
vgg16_true.classifier.add_module('add_liner', nn.Linear(1000, 6))

四、设置模型参数:

包括是否支持GPU加速
学习速率

代码如下(示例):

if torch.cuda.is_available():
    vgg16_true = vgg16_true.cuda()
loss_fn = nn.CrossEntropyLoss()

if torch.cuda.is_available():
    loss_fn = loss_fn.cuda()
    
learning_rate = 0.0001   # 学习速率
optimizer = torch.optim.SGD(vgg16_true.parameters(), lr=learning_rate)

五、模型训练:

代码如下(示例):

from torch.utils.tensorboard import SummaryWriter
# 记录训练的次数
total_train_step = 0
# 记录测试的次数
total_test_step = 0
# 训练的轮数
epoch = 100
accuracy_bass = 0

train_data_size = len(train_datasets)
test_data_size = len(val_datasets)

# 添加tensorboard
writer = SummaryWriter("./logs")

for i in range(epoch):
    print("-------第 {} 轮训练开始-------".format(i+1))

    # 训练步骤开始
    vgg16_true.train()
    for data in train_data_loader:
        imgs, targets = data
        imgs = imgs.cuda()
        targets = targets.cuda()
        outputs = vgg16_true(imgs)
        loss = loss_fn(outputs, targets)

        # 优化器优化模型
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        total_train_step = total_train_step + 1
        if total_train_step % 100 == 0:
            print("训练次数:{}, Loss: {}".format(total_train_step, loss.item()))
            writer.add_scalar("train_loss", loss.item(), total_train_step)

    # 测试步骤开始
    vgg16_true.eval()
    total_test_loss = 0
    total_accuracy = 0
    with torch.no_grad():
        for data in val_data_loader:
            imgs, targets = data
            imgs = imgs.cuda()
            targets = targets.cuda()
            outputs = vgg16_true(imgs)
            loss = loss_fn(outputs, targets)
            total_test_loss = total_test_loss + loss.item()
            accuracy = (outputs.argmax(1) == targets).sum()
            total_accuracy = total_accuracy + accuracy

    print("整体测试集上的Loss: {}".format(total_test_loss))
    total = total_accuracy/test_data_size
    print("整体测试集上的正确率: {}".format(total))
    writer.add_scalar("test_loss", total_test_loss, total_test_step)
    writer.add_scalar("test_accuracy", total, total_test_step)
    total_test_step = total_test_step + 1

    torch.save(vgg16_true, "./model_zoo/vgg16_true_{}.pth".format(i))
    
    
    print("模型已保存")

writer.close()

提示:我这里的正确率是记录测试集上正确的个数,并没有除以测试集总个数:

六、图片预测分类:

将需要预测的图片放到docs文件下,需要重新预测图片时从这开始

代码如下(示例):

# 将需要预测的图片放到docs文件下,需要重新预测图片时从这开始
import torchvision
from PIL import Image
import os

imge_name = "58780369.jpg"  # 要预测的图片的名字

root_dir = "./docs"
imge_path = os.path.join(root_dir, imge_name)
image_0 = Image.open(imge_path)
print(image_0)

imge_transforms = torchvision.transforms.Compose([
    transforms.Resize((224, 224)),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
    transforms.Normalize((.5, .5, .5), (.5, .5, .5))
])

image = imge_transforms(image_0)
print(image.shape)

image = torch.reshape(image, (-1, 3, 224, 224))
model = vgg16_true
model = torch.load("./model_zoo/vgg16_true_45.pth", map_location=torch.device('cpu'))

model.eval()
with torch.no_grad():
    output = model(image)
print(output.argmax(1))


总结

你可能感兴趣的:(分类,机器学习,人工智能)