【Intel校企合作课程】基于VGG-16检测农作物与杂草

1.作业简介:检测并清除杂草

1.1问题描述

        杂草是农业经营中不受欢迎的入侵者,它们通过窃取营养、水、土地和其他关键资源来破坏种植,这些入侵者会导致产量下降和资源部署效率低下。一种已知的方法是使用杀虫剂来清除杂草,但杀虫剂会给人类带来健康风险。我们的目标是利用计算机视觉技术可以自动检测杂草的存在,开发一种只在杂草上而不是在作物上喷洒农药的系统,并使用针对性的修复技术将其从田地中清除,从而最小化杂草对环境的负面影响。

1.2预期解决方案

        我们期待您将其部署到模拟的生产环境中——这里推理时间和二分类准确度(F1分数)将作为评分的主要依据。

1.3数据集

        https://filerepo.idzcn.com/hack2023/Weed_Detection5a431d7.zip

1.4图像展示

​  

CROP                                                           WEED

2.数据预处理

2.1导入相应的包

        准备所需的库和工具,以便后续进行数据处理、模型训练和评估等任务。

import os
import sys
import time
import argparse
import itertools
import torch
import torch.nn.functional as F
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import intel_extension_for_pytorch as ipex
import pandas as pd
import shutil

from torch import nn, optim
from torch.autograd import Variable
from torchvision import models
from matplotlib.patches import Rectangle
from sklearn.metrics import confusion_matrix, accuracy_score, balanced_accuracy_score
from torchvision import transforms
from PIL import Image
from torch.utils.data import Dataset, DataLoader, SubsetRandomSampler
from sklearn.model_selection import train_test_split, StratifiedKFold
from sklearn.metrics import f1_score

2.2数据集结构

# 数据集路径
data_dir = 'Weed_Detection/data'

Data = []
# 通过txt文件的第一个数字分辨是农作物还是杂草,获取第一个数字
for file in os.listdir(data_dir):
    if file.endswith(".txt"):
        file_path = os.path.join(data_dir, file)
        with open(file_path, 'r') as f:
            data = f.readline()
            root, ext = os.path.splitext(file_path)
            new_file_path = root + ".jpeg"
            # 图片和标签对应
            Data.append((new_file_path, int(data[0][0])))

# 将数据集分成3部分, train, val, test
for divide in ['train', 'val', 'test']:
    divide_dir = os.path.join('Weed_Detection', divide)
    # 每部分的数据集都包含两部分,农作物和杂草
    for kinds in ['crop', 'weed']:
        kinds_dir = os.path.join(divide_dir, kinds)
        os.makedirs(kinds_dir, exist_ok = True)

# 将train, val, test按比例分别划分为0.7, 0.2, 0.1
train_data, testVal_data = train_test_split(Data, test_size = 0.3, random_state = 42)
test_data, val_data = train_test_split(testVal_data, test_size = 0.2, random_state = 42)

# 将train_data中的文件分类,并复制到train/crop or weed下
for file in train_data:
    if (file[1] == 0):
        shutil.copy(file[0], 'Weed_Detection/train/crop')
    else:
        shutil.copy(file[0], 'Weed_Detection/train/weed')

# 将val_data中的文件分类,并复制到val/crop or weed下
for file in val_data:
    if (file[1] == 0):
        shutil.copy(file[0], 'Weed_Detection/val/crop')
    else:
        shutil.copy(file[0], 'Weed_Detection/val/weed')
        
# 将test_data中的文件分类,并复制到test/crop or weed下
for file in test_data:
    if (file[1] == 0):
        shutil.copy(file[0], 'Weed_Detection/test/crop')
    else:
        shutil.copy(file[0], 'Weed_Detection/test/weed')

         运行这段代码,得到如下图所示的目录结构:

 数据集结构

  子文件夹结构

2.3提取数据集

        这段代码定义了一个名为SelfDataset的自定义数据集类。这个自定义数据集类用于加载、处理和组织图像数据,以便于机器学习和深度学习模型的训练。

# 创建自定义数据集
class SelfDataset(Dataset):
    # 初始化方法,接收数据集的根目录和可选的转换方法
    def __init__(self, root_dir, transform=None):
        self.root_dir = root_dir
        self.transform = transform
        self.classes = ['crop', 'weed']
        self.data = self.load_data()
    
    # 定义加载数据的方法
    def load_data(self):
        data = []
        for class_idx, class_name in enumerate(self.classes):
            class_path = os.path.join(self.root_dir, class_name)
            for file_name in os.listdir(class_path):
                file_path = os.path.join(class_path, file_name)
                if os.path.isfile(file_path) and file_name.lower().endswith('.jpeg'):
                    data.append((file_path, class_idx))
        return data
    
    # 定义获取数据集长度的方法
    def __len__(self):
        return len(self.data)
    
    # 定义根据索引获取数据的方法
    def __getitem__(self, idx):
        img_path, label = self.data[idx]
        img = Image.open(img_path).convert('RGB')
        if self.transform:
            img = self.transform(img)
        return img, label

2.4数据增强、构建数据集

        为后续的模型训练、评估和验证提供了必要的数据准备。

1.数据增强:通过transforms.Compose创建了一个数据增强的组合,其中包括:

transforms.RandomResizedCrop(64): 随机调整图像大小并裁剪为64x64像素大小。这有助于增加数据的多样性,使模型更好地泛化。

transforms.RandomHorizontalFlip(): 随机水平翻转图像。也是一种常用的数据增强技术,可以帮助模型更好地泛化。

transforms.ToTensor(): 将图像转换为PyTorch的Tensor格式,使其可以直接用于PyTorch模型。

2.构建数据集:使用自定义的SelfDataset类创建了训练、测试和验证数据集的实例。每个实例都接收相应的数据集路径和之前定义的数据增强转换。创建 DataLoader:使用PyTorch的DataLoader创建了三个数据加载器,分别用于训练、测试和验证。每个加载器设置了批次大小(batch_size)为64,每次从数据集中提取64个样本。shuffle=True仅用于训练加载器,在每个训练时代开始时,训练数据会被打乱。这可以防止模型过拟合。测试和验证加载器的shuffle参数设置为False,使用原始的数据顺序。

train_dataset_path = 'Weed_Detection/train'
test_dataset_path = 'Weed_Detection/test'
val_dataset_path = 'Weed_Detection/val'

transform = transforms.Compose([
    transforms.RandomResizedCrop(64),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
])

train_dataset = SelfDataset(root_dir=train_dataset_path, transform=transform)
test_dataset = SelfDataset(root_dir=test_dataset_path, transform=transform)
val_dataset = SelfDataset(root_dir=val_dataset_path, transform=transform)

batch_size = 64
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)

3.使用卷积神经网络识别肺炎图像 

3.1VGG-16架构

        VGG-16是一种深度卷积神经网络模型,由Simonyan和Zisserman在文献《Very Deep Convolutional Networks for Large-Scale Image Recognition》中提出。VGG-16的特点包括:

1.结构简单:模型层次很深,达到了16层,但每一层的结构都很简单,就是一层一层顺序堆叠。
2.卷积层均采用相同的卷积核参数:每个卷积层都使用3×3的卷积核,步长为1,采用padding保持卷积后图像空间分辨率不变。
3.池化层均采用相同的池化核参数:池化层采用2×2的最大池化,步长为2。
4.参数多:最后三个全连接层的参数太多,需要的存储容量大,不利于部署。

VGG-16架构

3.2卷积神经网络

        卷积神经网络(Convolutional Neural Networks,CNN)是一种深度学习的代表算法,专门用于处理具有类似网格结构的数据,如图像、语音信号等。卷积神经网络由若干个卷积层和子采样层(池化层)构成,其特点包括:

1.卷积层是CNN的核心层,每一层的神经元只与部分邻层神经元连接,这种连接方式减少了网络中的参数数量,增强了网络的泛化能力。
2.卷积层中的每个神经元都只对部分输入进行响应,通过共享权值的方式,使得网络能够学习到输入数据的局部特征。
3.卷积神经网络中的池化层用于降低数据的维度,减少计算量,同时保留重要信息,有助于防止过拟合。
4.卷积神经网络通过逐层卷积和池化操作,将输入数据逐步抽象和转化为更高层次的特征表示。
5.卷积神经网络能够自动提取输入数据的特征,避免了手工设计特征的繁琐过程,使得网络能够更好地适应各种不同的数据集和任务。

3.3深度神经网络

        深度神经网络(DNN)是深度学习领域中一种重要的技术,是一种多层感知器。DNN使用神经网络来建模输入数据的复杂特征,通过学习从原始数据到目标输出的映射关系,自动提取输入数据的特征,从而提高了分类和预测的准确率。

        DNN通常包含多个隐藏层,这些隐藏层通过全连接的方式将输入层和输出层连接起来。在训练过程中,DNN通过反向传播算法不断调整神经元的权重,以最小化预测结果与真实结果之间的误差。

3.4更改VGG-16网络结构

        使用PyTorch框架对VGG16模型进行修改和配置。具体来说,代码的作用是加载预训练的VGG16模型,关闭其某些部分的梯度计算(以加速训练并减少计算需求),然后修改其分类器部分以适应特定的任务。传统的VGG16网络的输出是1000的大小,为了适应本项目,将网络改成了2分类问题。

vgg16_model = models.vgg16(pretrained=True)

for param in vgg16_model.features.parameters():
    param.requires_grad = False

num_features = vgg16_model.classifier[6].in_features
vgg16_model.classifier[6] = nn.Sequential(
    nn.Linear(num_features, 512),
    nn.ReLU(),
    nn.Dropout(0.5),
    nn.Linear(512, 2)
)

 

运行结果 

4.在GPU上训练

4.1参数设置

1定义损失函数:这里定义了一个交叉熵损失函数(CrossEntropyLoss)。交叉熵损失常用于分类问题,它衡量的是预测概率分布与真实概率分布之间的距离。

2定义优化器:这里使用了Adam优化器。Adam是一种自适应学习率的优化算法,结合了Adagrad和RMSprop的特点。vgg16_model.parameters()表示模型的参数,lr=0.001设置了学习率为0.001,weight_decay=1e-4设置了权重衰减为1e-4,用于正则化。

3定义学习率调度器:这里添加了一个学习率调度器。ReduceLROnPlateau是一个根据验证性能调整学习率的策略。当验证性能停止提升时,学习率会按指定的因子(这里是0.1)进行衰减。patience参数表示在性能停止提升之前,不会调整学习率的轮数,这里是3轮。

# 定义交叉熵损失函数
criterion = nn.CrossEntropyLoss()
# 定义Adam优化器
optimizer = optim.Adam(vgg16_model.parameters(), lr=0.001, weight_decay=1e-4)
# 添加学习率调度器
scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='max', factor=0.1, patience=3, verbose=True)

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 判断是否有可用的CUDA设备(即GPU)
vgg16_model.to(device) # 将模型移动到指定的设备上(GPU或CPU)

4.2在GPU上训练50次

        我使用了三个数据集,分别为train,val,test。

训练集(train):

用途:用于训练机器学习模型。模型通过学习训练集中的样本来调整参数,使其能够捕捉输入数据的模式和特征。

特点:训练集通常是最大的数据集,包含用于模型训练的大量样本。高质量、多样性的训练集有助于提高模型的泛化能力,使其在未见过的数据上表现良好。

验证集(val):

用途:用于调整模型超参数、选择模型架构和进行早停等操作。验证集上的性能评估有助于避免模型在训练集上过拟合,提高对未知数据的泛化能力。

特点:验证集通常是从独立于训练集的数据中划分出来的,模型在训练过程中不使用验证集的信息。在训练过程中,通过监控验证集上的性能来调整模型的参数和架构。

测试集(test):

用途:用于评估训练好的模型的性能。测试集中的样本是模型在训练和验证过程中未曾见过的数据,因此测试集上的性能评估更接近模型在真实场景中的表现。

特点:测试集应该是完全独立于训练集和验证集的,确保模型在测试集上的表现不受过拟合或过度调整的影响。测试集上的性能评估是对模型泛化能力的最终验证。

num_epochs = 0
consecutive_f1_count = 0

while num_epochs < 50:
    print(f'第{num_epochs+1}次训练开始...')
    vgg16_model.train() 
    train_loss = 0.0
    for inputs, labels in train_loader:
        inputs, labels = inputs.to(device), labels.to(device)
        outputs = vgg16_model(inputs)
        loss = criterion(outputs, labels)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        train_loss += loss.item()

    val_loss = 0.0
    with torch.no_grad():
        for inputs, labels in val_loader:
            inputs, labels = inputs.to(device), labels.to(device)
            val_outputs = vgg16_model(inputs)
            val_loss += criterion(val_outputs, labels).item()
    
    avg_train_loss = train_loss / len(train_loader)
    avg_val_loss = val_loss / len(val_loader)
    print(f'Epoch [{num_epochs+1}], 第{num_epochs+1}轮:训练集损失: {avg_train_loss:.4f}, 验证集损失: {avg_val_loss:.4f}')

    vgg16_model.eval()
    all_predictions = []
    all_labels = []
    start_time = time.time()
    with torch.no_grad():
        for inputs, labels in test_loader:
            inputs, labels = inputs.to(device), labels.to(device)
            outputs = vgg16_model(inputs)
            _, predicted = torch.max(outputs, 1)
            all_predictions.extend(predicted.cpu().numpy())
            all_labels.extend(labels.cpu().numpy())
    end_time = time.time()
    elapsed_time = end_time - start_time
    print(f'测试集用的时间为: {elapsed_time:.2f} seconds')
    f1 = f1_score(all_labels, all_predictions, average='binary')
    print(f'第{num_epochs+1}轮的测试F1分数: {f1:.4f}')
    scheduler.step(f1)
    num_epochs += 1

4.3查看test数据集F1分数及时间

部分训练结果 

4.4保存为VGG16模型 

# 保存模型的状态字典到文件'vgg16_model.pth'
torch.save(vgg16_model.state_dict(), 'vgg16_model.pth') 
print("模型已保存为 vgg16_model.pth")

4.5使用模型进行推理测试 

        使用预训练好VGG16模型对一张测试图片进行分类预测。首先选择一张测试图片并加载到模型中进行预测。然后,获取模型的输出并对输出进行解析以获得预测标签。最后,显示原始图片和模型的预测结果。

sample_image, true_label = next(iter(test_loader))

sample_image = sample_image.to(device)
with torch.no_grad():
    model_output = vgg16_model(sample_image)

_, predicted_label = torch.max(model_output, 1)
sample_image = sample_image.cpu().numpy()[0]
predicted_label = predicted_label[0].item()
true_label = true_label[0].item()
class_labels = ['crop', 'weed']

plt.imshow(np.transpose(sample_image, (1, 2, 0)))
plt.title(f'TRUE LABEL IS: {class_labels[true_label]}, PREDICT LABEL IS: {class_labels[predicted_label]}')
plt.axis('off')
plt.show()

推理测试结果

5.转移到CPU上

5.1创建VGG16模型

        这段代码定义了一个定制的VGG16模型。以下是对这段代码的主要功能概述:

1.定义模型结构:通过CustomVGG16类定义了一个定制的VGG16模型。这个模型继承自nn.Module,它是一个PyTorch神经网络模型。

2.加载预训练权重:使用预训练的VGG16模型权重,这些权重在训练过程中已经优化过。

3.冻结特征提取层:通过设置requires_grad=False,确保在训练过程中VGG16模型的卷积层(即特征提取层)不会更新。这意味着这些层的权重将保持不变,从而允许模型专注于分类任务,而不是重新学习特征提取。

4.修改分类器层:原始的VGG16模型使用一个全连接层进行分类。这里,全连接层的输入特征数被修改为2,表示该模型适用于具有两个类别的分类任务。同时,添加了一个ReLU激活函数和一个Dropout层来增强模型的性能并防止过拟合。

5.前向传播:通过重写forward函数,确保当输入数据传递给模型时,数据会经过修改后的VGG16模型结构。

class CustomVGG16(nn.Module):
    def __init__(self):
        super(CustomVGG16, self).__init__() # 调用父类的初始化函数
        self.vgg16_model = models.vgg16(pretrained=True) 
        # 将VGG16模型中的features模块(卷积层)的参数设置为不可训练
        for param in self.vgg16_model.features.parameters():
            param.requires_grad = False
        num_features = self.vgg16_model.classifier[6].in_features # 获取VGG16模型中classifier模块的第七个层的输入特征数(即全连接层的输入特征数)
          
        # 修改VGG16模型的classifier模块的第七个层,将其替换为一个包含三个线性层和一个ReLU激活函数、Dropout层的新序列  
        self.vgg16_model.classifier[6] = nn.Sequential(
            nn.Linear(num_features, 512), # 第一层线性层
            nn.ReLU(), # ReLU激活函数
            nn.Dropout(0.5), # Dropout层,保留50%的节点,防止过拟合
            nn.Linear(512, 2) # 第二层线性层,将特征数从512映射到2
        )  
    # 定义前向传播函数
    def forward(self, x):
        return self.vgg16_model(x)   

vgg16_model = CustomVGG16() # 创建CustomVGG16模型实例
vgg16_model.vgg16_model.load_state_dict(torch.load('vgg16_model.pth', map_location=torch.device('cpu'))) #加载预训练的VGG16权重(位于'vgg16_model.pth'文件)到模型实例中

5.2尝试直接在CPU上进行训练

        这段代码用于在测试数据集上评估一个经过修改的VGG16模型的性能,并与之后使用oneAPI相关组件优化过后的代码作比较。

# 尝试直接在CPU上进行训练
vgg16_model.eval()

all_predictions = []
all_labels = []
start_time = time.time()

with torch.no_grad():
    for inputs, labels in test_loader:
        inputs, labels = inputs.to(device), labels.to(device)
        outputs = vgg16_model(inputs)
        _, predicted = torch.max(outputs, 1)
        all_predictions.extend(predicted.cpu().numpy())
        all_labels.extend(labels.cpu().numpy())

end_time = time.time()
elapsed_time = end_time - start_time
print(f'测试集用的时间为: {elapsed_time:.2f} seconds')
f1 = f1_score(all_labels, all_predictions, average='binary')
print(f'F1分数为: {f1:.4f}')

 

 直接使用CPU的推理运行结果

6.使用oneAPI组件

6.1Transfer Learning with oneAPI AI Analytics Toolkit进行迁移学习

class CustomVGG16(nn.Module):
    def __init__(self):
        super(CustomVGG16, self).__init__() # 调用父类的初始化函数
        self.vgg16_model = models.vgg16(pretrained=True) 
        # 将VGG16模型中的features模块(卷积层)的参数设置为不可训练
        for param in self.vgg16_model.features.parameters():
            param.requires_grad = False
        num_features = self.vgg16_model.classifier[6].in_features # 获取VGG16模型中classifier模块的第七个层的输入特征数(即全连接层的输入特征数)
          
        # 修改VGG16模型的classifier模块的第七个层,将其替换为一个包含三个线性层和一个ReLU激活函数、Dropout层的新序列  
        self.vgg16_model.classifier[6] = nn.Sequential(
            nn.Linear(num_features, 512), # 第一层线性层
            nn.ReLU(), # ReLU激活函数
            nn.Dropout(0.5), # Dropout层,保留50%的节点,防止过拟合
            nn.Linear(512, 2) # 第二层线性层,将特征数从512映射到2
        )  
    # 定义前向传播函数
    def forward(self, x):
        return self.vgg16_model(x)   

vgg16_model = CustomVGG16() # 创建CustomVGG16模型实例
vgg16_model.vgg16_model.load_state_dict(torch.load('vgg16_model.pth', map_location=torch.device('cpu'))) #加载预训练的VGG16权重(位于'vgg16_model.pth'文件)到模型实例中

6.2使用Intel Extension for PyTorch进行优化

        这段代码为深度学习模型的训练配置环境,包括确定计算设备、选择优化算法,并利用Intel的硬件优化技术来加速模型训练。

# 将模型移动到CPU上运行,这样可以在CPU上执行模型的所有操作
device = torch.device('cpu')
vgg16_model.to(device)  # 将模型移动到CPU

# 重新构建优化器。这里使用Adam优化器,学习率为0.001,权重衰减为1e-4
optimizer = optim.Adam(vgg16_model.parameters(), lr=0.001, weight_decay=1e-4)

# 使用Intel Extension for PyTorch进行优化。这个扩展可以加速PyTorch模型在Intel硬件上的运行
# ipex.optimize函数会对模型和优化器进行优化,使其更适合在Intel的硬件上运行
# 参数dtype设置为torch.float32,意味着模型和数据都会以32位浮点数格式进行运算,这可以提高计算的精度和稳定性
vgg16_model, optimizer = ipex.optimize(model=vgg16_model, optimizer=optimizer, dtype=torch.float32)

6.3保存使用Intel Extension for PyTorch进行优化的模型

        这段代码的作用是保存一个优化后的VGG16模型到文件,并从该文件中加载模型参数到一个新的模型实例中。在深度学习实践中这是很常见的操作,用于保存训练好的模型、迁移学习或在不同任务之间共享预训练的模型参数。

# 保存模型参数到文件'vgg16_optimized.pth'
torch.save(vgg16_model.state_dict(), 'vgg16_optimized.pth') 

loaded_model = CustomVGG16() # 创建一个新的CustomVGG16模型实例
loaded_model.load_state_dict(torch.load('vgg16_optimized.pth')) # 从文件'vgg16_optimized.pth'中加载模型参数到loaded_model中

6.4使用 Intel® Neural Compressor 量化模型 

        这段代码涉及深度学习模型的量化过程,其主要目的是对预训练的VGG16模型进行量化,通过这种方式,可以优化模型的部署,特别是在资源有限的边缘设备上,同时保持较高的准确性。

from neural_compressor.config import PostTrainingQuantConfig, AccuracyCriterion
from neural_compressor import quantization

assert os.path.exists("./vgg16_optimized.pth"), "文件不存在" # 检查文件是否存在
model = torch.load("./vgg16_optimized.pth") # 尝试加载模型
print("模型加载成功")

model = CustomVGG16() # 加载自定义的VGG16模型
model.load_state_dict(torch.load('vgg16_optimized.pth')) # 从文件'vgg16_optimized.pth'中加载优化后的模型参数
model.to('cpu')  # 将模型移动到CPU上运行
model.eval() # 将模型设置为评估模式,关闭dropout等层

# 定义评估函数
def eval_func(model):
    with torch.no_grad():
        y_true = [] # 存储真实标签
        y_pred = [] # 存储预测标签
        for inputs, labels in train_loader:
            inputs = inputs.to('cpu') # 将输入数据移动到CPU上
            labels = labels.to('cpu') # 将标签数据移动到CPU上
            preds_probs = model(inputs)  # 使用模型进行前向传播,得到预测概率
            preds_class = torch.argmax(preds_probs, dim=-1)  # 获取预测的类别标签
            y_true.extend(labels.numpy()) # 将真实标签添加到列表中
            y_pred.extend(preds_class.numpy()) # 将预测标签添加到列表中
        return accuracy_score(y_true, y_pred)

# 配置量化参数,包括后端、精度准则等
conf = PostTrainingQuantConfig(backend='ipex',  # 使用 Intel PyTorch Extension
                               accuracy_criterion=AccuracyCriterion(higher_is_better=True, # 精度准则:越高越好
                                                                    criterion='relative',  # 使用相对误差作为精度准则
                                                                    tolerable_loss=0.01)) # 可接受的损失:0.01
# 使用配置的量化参数对模型进行量化训练和评估
q_model = quantization.fit(model,
                           conf,
                           calib_dataloader=train_loader, # 使用训练数据加载器进行量化和评估
                           eval_func=eval_func) # 使用之前定义的评估函数进行评估
# 定义量化模型保存的路径,如果不存在则创建该路径
quantized_model_path = './quantized_models'
if not os.path.exists(quantized_model_path):
    os.makedirs(quantized_model_path)
q_model.save(quantized_model_path) # 保存量化后的模型到指定路径

         出现下图所示的结果则表明量化成功。

6.5使用量化后的模型在 CPU上进行推理

1.加载模型:

        这段代码用于准备量化后的VGG16模型和其相关的配置信息,以便进行后续的推理或进一步处理。

import json
from neural_compressor import quantization

# 定义量化模型的路径
quantized_model_path = './quantized_models'

# 指定量化模型和配置文件的路径
vgg16_model_path = f'{quantized_model_path}/best_model.pt' # 量化模型的文件路径
json_config_path = f'{quantized_model_path}/best_configure.json' # JSON配置文件的路径

# 从指定路径加载量化模型
vgg16_model = torch.jit.load(vgg16_model_path, map_location='cpu') # 使用CPU加载模型

# 打开并读取JSON配置文件
with open(json_config_path, 'r') as json_file:
    json_config = json.load(json_file) # 读取JSON内容并存储到变量中

2.进行推理:

        这段代码用于评估已经量化的VGG16模型在测试数据集上的分类性能,并输出推理时间和F1分数作为评估指标。

vgg16_model.eval()

y_true = []
y_pred = []

start_time = time.time()
batch_size = 64
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)

with torch.no_grad():
    for inputs, labels in test_loader:
        inputs = inputs.to('cpu')
        labels = labels.to('cpu')
        preds_probs = vgg16_model(inputs)
        preds_class = torch.argmax(preds_probs, dim=-1)
        y_true.extend(labels.numpy())
        y_pred.extend(preds_class.numpy())
f1 = f1_score(y_true, y_pred, average='weighted') # 计算 F1 分数
inference_time = time.time() - start_time # 计算推理时间
print(f"测试集用的时间为: {inference_time} seconds")
print(f"F1分数: {f1}")

使用量化后的模型在CPU上的推理运行结果

6.6结果分析

        通过对比,可以看到使用量化后的模型在CPU上进行推理的时间明显缩短,同时分类准确度(F1分数)也有所提升。这证明了oneAPI优秀的模型压缩能力,在保证模型精确度,F1值的基础上还能够缩小模型的规模。

7.总结

        本次智能应用系统开发主要集中在云端环境,特别是利用了Intel的Jupyter和Google的Colab进行开发与实验。项目的主要目标是解决二分类问题,即识别图片中的作物(crop)或杂草(weed)。

        在解决方案上,我采取了一种在模拟生产环境中部署的方法,主要依据是推理时间和二分类准确度(F1分数)的评价标准。数据集被划分为70%的训练数据、20%的验证数据和10%的测试数据。

        在技术实现上,我们利用了深度学习技术,特别是在Intel的Jupyter和Google Colab上进行了模型的训练。训练过程中,我们使用了GPU进行加速,而在推理阶段,为了优化速度,我们采用了Intel的Extension for PyTorch进行优化,并使用了Intel® Neural Compressor进行模型量化。

        在架构选择上,我们最终选择了VGG-16架构来识别图像。VGG-16具有良好的性能和稳定性,能够满足我们的分类需求。

  • 19
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值