【开发者空间实践指导】基于云主机CodeArts IDE 搭建花卉识别系统

举报
开发者空间小蜜蜂 发表于 2024/12/20 11:06:10 2024/12/20
464 0 0
【摘要】 本实验在云主机上用CodeArts IDE结合终端命令运行,通过深度学习技术,实现对花卉种类的自动识别,为花卉研究、园林设计等领域提供技术支持。

一、案例介绍

随着人工智能技术的不断发展,图像识别技术在众多领域得到了广泛应用。花卉识别作为图像识别的一个重要分支,具有很高的研究价值和实际应用前景。本实验在云主机上用CodeArts IDE结合终端命令运行,通过深度学习技术,实现对花卉种类的自动识别,为花卉研究、园林设计等领域提供技术支持。

二、免费领取云主机

如您还没有云主机,可点击链接 ,根据领取指南进行操作。

如您已领取云主机,可直接开始实验。

三、实验流程

四、实验步骤

4.1 登录云主机

在浏览器中输入华为云网址:https://www.huaweicloud.com/ 进入华为云首页

在华为云的首页右上方,点击“登录”,在弹出的对话框中输入自己的用户名和密码。

在华为云首页,依次选择“开发者”>“开发者空间”>“访问开发者空间,领取云主机,快速体验 “立即领取”。

领取后点击“在浏览器中打开”。

4.2 获取数据集

获取数据集为进行图像识别和分类的机器学习任务做准备。数据集中包含了五种不同花卉的图片,分别是雏菊(daisy)、蒲公英(dandelion)、玫瑰(roses)、向日葵(sunflowers)和郁金香(tulips)。每个花卉类别都有相应的子文件夹,用其英文名字进行命名,其中存储了该类别的图片。

在云主机上,依次点击“CodeArts IDE for Python”>“新建工程”>“名称”>“位置”>“基础解释器”>“创建”。

参数设置如下:

名称

data_set

位置

放在自己方便查找的路径下,样例程序中放到了桌面上,路径为:/home/developer/Desktop

基础解释器

Python 3.10.12 /bin/python3

创建完毕后首先创建一个文件夹,“空白处单击鼠标右键”>“新建”>“文件夹”(可以参考如下图片),文件夹命名为:“flower_data”

在桌面上点击鼠标右键,选择“在终端中打开”,进入“flower_data”文件

cd flower_data

然后输入指令获取数据集

sudo wget http://download.tensorflow.org/example_images/flower_photos.tgz

使用tar 命令解压 flower_photos.tgz 文输入指令后会解压出如下图左侧所示文件,可以看到数据集中不同花卉的目录。

tar -xzf flower_photos.tgz

4.3 划分训练集与验证集

我们要将原始的花卉图片数据集分割成两个部分:90%作为训练集,10%作为验证集。划分训练集和验证集的原因是为了更有效地训练和评估机器学习模型。

首先,返回上一级文件

cd ../

再创建一个py文件:“空白处单击鼠标右键”>“新建”>“文件”,文件命名为:“split_data.py”。将下列代码复制到文件中。

代码内容说明:

1)删除并重新创建训练集和验证集的根目录。对于每个花卉类别,程序会创建相应的子目录。

2)遍历每个类别的图片,随机选择10%的图片作为验证集,剩余的90%作为训练集。图片被复制到相应的训练集或验证集目录。处理过程中,程序会在控制台打印出进度条,显示当前正在处理的类别和图片数量。

import os
from shutil import copy, rmtree
import random#导入需要用的包

def mk_file(file_path: str):
if os.path.exists(file_path):
# 如果文件存在,那么将先删除原文件夹在重新创建
        rmtree(file_path)
os.makedirs(file_path)
 
 def main():

    random.seed(0)
 
    split_rate = 0.1
 
    cwd = os.getcwd()
    data_root = os.path.join(cwd, "flower_data")
    origin_flower_path = os.path.join(data_root, "flower_photos")
    assert os.path.exists(origin_flower_path)
    flower_class = [cla for cla in os.listdir(origin_flower_path)
                    if os.path.isdir(os.path.join(origin_flower_path, cla))]
 	  # 建立保存训练集的文件夹
    train_root = os.path.join(data_root, "train")
    mk_file(train_root)
    for cla in flower_class:
        mk_file(os.path.join(train_root, cla))
    # 建立保存验证集的文件夹
    val_root = os.path.join(data_root, "val")
    mk_file(val_root)
    for cla in flower_class:
       
        mk_file(os.path.join(val_root, cla))
 
    for cla in flower_class:
        cla_path = os.path.join(origin_flower_path, cla)
        images = os.listdir(cla_path)
        num = len(images)
    
        eval_index = random.sample(images, k=int(num*split_rate))
        for index, image in enumerate(images):
            if image in eval_index:
         
                image_path = os.path.join(cla_path, image)
                new_path = os.path.join(val_root, cla)
                copy(image_path, new_path)
            else:
        
                image_path = os.path.join(cla_path, image)
                new_path = os.path.join(train_root, cla)
                copy(image_path, new_path)
            print("\r[{}] processing [{}/{}]".format(cla, index+1, num), end="")  # processing bar
        print()
 
    print("processing done!")
  
if __name__ == '__main__':
    main()

代码输入完毕后运行“split_data.py”文件

python3 split_data.py

运行后显示“processing done!”,表示运行成功。

处理过程进度显示效果如下:

4.4 创建神经网络模型

基于AlexNet架构的卷积神经网络模型,通过其多层结构,能够自动从原始图像数据中提取出有用的特征。这些特征比手工设计的特征更加抽象和复杂,能够更好地表示图像内容,从而提高识别的准确性

创建一个py文件:“空白处单击鼠标右键”>“新建”>“文件”,文件命名为:“model.py”。

将下列代码复制到文件中。

import torch.nn as nn
import torch#导入需要用的包
 
class AlexNet(nn.Module):
    def __init__(self, num_classes=1000, init_weights=False):
        super(AlexNet, self).__init__()
      
        self.features = nn.Sequential(  # 卷积层提取图像特征
            nn.Conv2d(3, 48, kernel_size=11, stride=4, padding=2),  
            nn.ReLU(inplace=True), 									
            nn.MaxPool2d(kernel_size=3, stride=2),                 
            nn.Conv2d(48, 128, kernel_size=5, padding=2),        
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),                 
            nn.Conv2d(128, 192, kernel_size=3, padding=1),          
            nn.ReLU(inplace=True),
            nn.Conv2d(192, 192, kernel_size=3, padding=1),        
            nn.ReLU(inplace=True),
            nn.Conv2d(192, 128, kernel_size=3, padding=1),         
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),                 
        )
        self.classifier = nn.Sequential(  # 全连接层对图像分类
            nn.Dropout(p=0.5),			   
            nn.Linear(128 * 6 * 6, 2048),
            nn.ReLU(inplace=True),
            nn.Dropout(p=0.5),
            nn.Linear(2048, 2048),
            nn.ReLU(inplace=True),
            nn.Linear(2048, num_classes),
        )
        if init_weights:
            self._initialize_weights()
            
# 前向传播
    def forward(self, x):
        x = self.features(x)
        x = torch.flatten(x, start_dim=1)	
        x = self.classifier(x)
        return x
        
    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):                        
                nn.init.kaiming_normal_(m.weight, mode='fan_out',  
                                        nonlinearity='relu')
                if m.bias is not None:
                    nn.init.constant_(m.bias, 0)                  
            elif isinstance(m, nn.Linear):            
                nn.init.normal_(m.weight, 0, 0.01)   
                nn.init.constant_(m.bias, 0)   

下载运行所需要的包。

pip install torch
pip install numpy
pip install torchvision
pip install matplotlib

torch PyTorch的核心库,提供了多维数组(称为张量)的操作

numpy Python中用于科学计算的基础库,提供了强大的多维数组对象和一系列用于处理数组的函数

torchvision PyTorch的一个视觉处理库,它提供了流行的数据集、模型架构和用于计算机视觉的常见图像变换。

matplotlib 是一个Python2D绘图库,它可以在各种平台上以各种硬拷贝格式和交互环境生成具有出版品质的图形。

下载完毕后终端输入命令,运行“model.py”文件。

python3 model.py

4.5 训练神经网络模型

训练model模型来对花卉图像进行分类,通过多次迭代(epoch)的训练和验证,模型学习如何从图像中提取特征并正确分类不同种类的花卉。最终,代码保存了在验证集上表现最好的模型参数,以便后续用于预测或进一步的分析。

创建一个py文件:“空白处单击鼠标右键”>“新建”>“文件”,文件命名为:“train.py”

将下列代码复制到文件中。

import torch
import torch.nn as nn
from torchvision import transforms, datasets, utils
import matplotlib.pyplot as plt
import numpy as np
import torch.optim as optim
from model import AlexNet
import os
import json
#导入需要用的包
import time 

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
with open(os.path.join("train.log"), "a") as log:
    log.write(str(device)+"\n")
 #数据预处理
data_transform = {
    "train": transforms.Compose([transforms.RandomResizedCrop(224),       
                                 transforms.RandomHorizontalFlip(p=0.5), 
                                 transforms.ToTensor(),
                                 transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]),#裁剪、翻转
 
    "val": transforms.Compose([transforms.Resize((224, 224)), 
                               transforms.ToTensor(),
                               transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])}
#获取图像数据集的路径
data_root = os.path.abspath(os.path.join(os.getcwd(), "../.."))
image_path = "/home/developer/Desktop/data_set/flower_data/"  				 	

train_dataset = datasets.ImageFolder(root=image_path + "train",		
          transform=data_transform["train"])
train_num = len(train_dataset)
 
train_loader = torch.utils.data.DataLoader(train_dataset,	
                                           batch_size=32, 	
                                           shuffle=True,	
                                           num_workers=0)	
 
validate_dataset = datasets.ImageFolder(root=image_path + "/val",
                                        transform=data_transform["val"])
val_num = len(validate_dataset)
 validate_loader = torch.utils.data.DataLoader(validate_dataset,	
                                              batch_size=32, 
                                              shuffle=True,
                                              num_workers=0)
 
flower_list = train_dataset.class_to_idx
cla_dict = dict((val, key) for key, val in flower_list.items())
 
json_str = json.dumps(cla_dict, indent=4)
with open('class_indices.json', 'w') as json_file:
    json_file.write(json_str)
 
net = AlexNet(num_classes=5, init_weights=True)  	
net.to(device)									 	
loss_function = nn.CrossEntropyLoss()			 	 
optimizer = optim.Adam(net.parameters(), lr=0.0002)	  
 
save_path = './AlexNet.pth'
best_acc = 0.0
 
for epoch in range(150):
    net.train()     					
    running_loss = 0.0					
    time_start = time.perf_counter()	
    for step, data in enumerate(train_loader, start=0):  
        images, labels = data   #获取训练集的图像和标签
        optimizer.zero_grad()	#清除历史梯度
        
        outputs = net(images.to(device))		#正向传播
        loss = loss_function(outputs, labels.to(device))  #计算损失
        loss.backward()				#反向传播	    
        optimizer.step()				#更新参数		
        running_loss += loss.item()
		 #使训练过程可视化
        rate = (step + 1) / len(train_loader)          
        a = "*" * int(rate * 50)
        b = "." * int((1 - rate) * 50)
        with open(os.path.join("train.log"), "a") as log:
              log.write(str("\rtrain loss: {:^3.0f}%[{}->{}]{:.3f}".format(int(rate * 100), a, b, loss))+"\n")
        print("\rtrain loss: {:^3.0f}%[{}->{}]{:.3f}".format(int(rate * 100), a, b, loss), end="")
    print()
    with open(os.path.join("train.log"), "a") as log:
              log.write(str('%f s' % (time.perf_counter()-time_start))+"\n")
    print('%f s' % (time.perf_counter()-time_start))
 
    net.eval()   
    acc = 0.0  
    with torch.no_grad():
        for val_data in validate_loader:
            val_images, val_labels = val_data
            outputs = net(val_images.to(device))
            predict_y = torch.max(outputs, dim=1)[1]  
            acc += (predict_y == val_labels.to(device)).sum().item()    
        val_accurate = acc / val_num
        # 保存准确率最高的那次网络参数
        if val_accurate > best_acc:
            best_acc = val_accurate
            torch.save(net.state_dict(), save_path)
        with open(os.path.join("train.log"), "a") as log:
              log.write(str('[epoch %d] train_loss: %.3f  test_accuracy: %.3f \n' %
              (epoch + 1, running_loss / step, val_accurate))+"\n")
        print('[epoch %d] train_loss: %.3f  test_accuracy: %.3f \n' %
              (epoch + 1, running_loss / step, val_accurate))
with open(os.path.join("train.log"), "a") as log:
      log.write(str('Finished Training')+"\n")
print('Finished Training')

运行前将“train.py”中的“image_path”路径改为“train.py”的路径,右键“train.py”文件,点击复制路径/引用,点击复制路径。

最后再终端输入命令运行“train.py”。

python3 train.py

4.6 使用神经网络模型进行预测

使用一个预训练的模型来预测单个图像的类别,首先对图像进行预处理,然后使用加载的模型进行预测,并输出最可能的类别及其概率。这个脚本可以用来测试模型在未知数据上的表现,或者作为一个简单的图像分类工具。

创建一个py文件:“空白处单击鼠标右键”>“新建”>“文件”,文件命名为:“predict.py”

将下列代码复制到文件中。

import torch
from model import AlexNet
from PIL import Image
from torchvision import transforms
import matplotlib.pyplot as plt
import json
#预处理
data_transform = transforms.Compose(
    [transforms.Resize((224, 224)),
     transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
#img中可以修改图片路径
img = Image.open("/home/developer/Desktop/data_set/flower_data/train/roses/24781114_bc83aa811e_n.jpg")
img = data_transform(img)
img = torch.unsqueeze(img, dim=0)
#读取class_indices.json
try:
    json_file = open('./class_indices.json', 'r')
    class_indict = json.load(json_file)
except Exception as e:
    print(e)
    exit(-1)
 
model = AlexNet(num_classes=5)
model_weight_path = "./AlexNet.pth"
model.load_state_dict(torch.load(model_weight_path, map_location='cpu'))
#关闭Dropout
model.eval()
with torch.no_grad():
    output = torch.squeeze(model(img))    
    predict = torch.softmax(output, dim=0)
    predict_cla = torch.argmax(predict).numpy()
print(class_indict[str(predict_cla)], predict[predict_cla].item())
plt.show()

运行前将“predict.py”中的“img”路径改为“图片”的路径。即img = Image.open("/home/developer/Desktop/data_set/flower_data/train/roses/24781114_bc83aa811e_n.jpg"),本案例中选择玫瑰花图片的路径:“data_set”>“flower_data”>“train”>“roses”选择路径,通过鼠标右击图片名,复制路径。

最后运行“predict.py”文件。

python3 predict.py

运行后,识别图片成功就会出现“roses”字样。

至此,本次实验全部完成。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。