基于PaddlePaddle 新工具 API 的【猴痘识别】

举报
livingbody 发表于 2022/11/22 01:09:23 2022/11/22
【摘要】 一、基于PaddlePaddle 新工具 API 的【猴痘识别】还记否,曾经开始学习神经网络,需要手动遍历文件夹,手动生成数据列表?还即否,曾经划分数据集,不断for循环抽取数据?多看看飞桨 API, 以前的问题现在都可以轻松得到解决。本文通过猴痘识别例子,介绍 数据集常用工具 DatasetFolder 和 random_split 使用。本文采取了2种方式进行模型训练预测:加载Padd...

一、基于PaddlePaddle 新工具 API 的【猴痘识别】

  • 还记否,曾经开始学习神经网络,需要手动遍历文件夹,手动生成数据列表?
  • 还即否,曾经划分数据集,不断for循环抽取数据?
    多看看飞桨 API, 以前的问题现在都可以轻松得到解决。

本文通过猴痘识别例子,介绍 数据集常用工具 DatasetFolder 和 random_split 使用。

本文采取了2种方式进行模型训练预测:

  • 加载PaddlePaddle内置模型库并使用 HAPI 进行训练预测
  • 自定义CNN模型并使用普通API进行训练预测

本教程可以较好的加速PaddlePaddle学习理解。

二、数据集介绍

  • 数据集文件名为45-data.zip。
  • 该数据集包含2个类别不同病症图像。
  • 图像大小不一,格式为.jpg。


1.数据解压缩

# 数据解压缩
!unzip -qoa data/data172723/45-data.zip -d 45-data

2.导入必要python包

# 导入需要的包

import shutil
import tempfile
import cv2
import numpy as np
import paddle
import paddle.vision.transforms as T
from pathlib import Path
from paddle.vision.datasets import DatasetFolder
import os,PIL,pathlib
print(paddle.version.cuda())
print(paddle.__version__)
11.2
2.3.2

3.使用DatasetFolder读取数据集

此处只需一句 DatasetFolder 类即可,而以往需要写个get_data_list。。。。。。

total_datadir = './45-data/'

train_transforms = T.Compose([
    T.Resize([224, 224]),                  # 将输入图片resize成统一尺寸
    T.RandomRotation(degrees=(-10, 10)),   # 随机旋转,-10到10度之间随机选
    T.RandomHorizontalFlip(),         # 随机水平翻转 选择一个概率概率
    T.RandomVerticalFlip(),           # 随机垂直翻转
    T.ToTensor(),          # 将PIL Image或numpy.ndarray转换为tensor,并归一化到[0,1]之间
    T.Normalize(           # 标准化处理-->转换为标准正太分布(高斯分布),使模型更容易收敛
        mean=[0.485, 0.456, 0.406], 
        std = [0.229, 0.224, 0.225])  # 其中 mean=[0.485,0.456,0.406]与std=[0.229,0.224,0.225] 从数据集中随机抽样计算得到的。
])

total_data = DatasetFolder(total_datadir,transform=train_transforms)
# 打印数据长度
print(len(total_data))
# 打印第一个数据,Tensor格式的 img 、label
print(total_data[0])

4.random_split切分数据集

random_split(total_data, [train_size, test_size]),一下搞定,而以往还在for循环中。。。。。。

from paddle.io import random_split
train_size = int(0.8 * len(total_data))
test_size  = len(total_data) - train_size
train_dataset, test_dataset = random_split(total_data, [train_size, test_size])
train_dataset, test_dataset
(<paddle.fluid.dataloader.dataset.Subset at 0x7f2dcde15e90>,
 <paddle.fluid.dataloader.dataset.Subset at 0x7f2dcde15d90>)
print(len(train_dataset),len(test_dataset))
1713 429

三、使用现有模型库模型

使用自定义CNN模型可以跳过三,直接运行第四部分。

1.加载MobileNetV3Large模型

# 模型组网并初始化网络
mobilenetv3 = paddle.vision.models.MobileNetV3Large(num_classes=2)

# 可视化模型组网结构和参数
paddle.summary(mobilenetv3,(1, 3, 224, 224))

2.高层 API训练

# 封装模型为一个 model 实例,便于进行后续的训练、评估和推理
model = paddle.Model(mobilenetv3)
# 为模型训练做准备,设置优化器及其学习率,并将网络的参数传入优化器,设置损失函数和精度计算方式
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, 
          test_dataset,
          epochs=100, 
          batch_size=128,
          verbose=1)
Epoch 100/100
step 14/14 [==============================] - loss: 0.2047 - acc: 0.9755 - 318ms/step         
Eval begin...
step 4/4 [==============================] - loss: 0.2706 - acc: 0.9068 - 221ms/step
Eval samples: 429

3. 模型验证

# 用 evaluate 在测试集上对模型进行验证
eval_result = model.evaluate(test_dataset, verbose=1)
print(eval_result)
Eval begin...
step 429/429 [==============================] - loss: 2.6442 - acc: 0.9138 - 29ms/step             
Eval samples: 429
{'loss': [2.6442208], 'acc': 0.9137529137529138}

4.批量预测

# 用 predict 在测试集上对模型进行推理
test_result = model.predict(test_dataset)
# 由于模型是单一输出,test_result的形状为[1, 10000],10000是测试数据集的数据量。这里打印第一个数据的结果,这个数组表示每个数字的预测概率
print(len(test_result))
Predict begin...
step 429/429 [==============================] - 29ms/step        
Predict samples: 429
1
print(test_result[0][0])

# 从测试集中取出一张图片
img, label = test_dataset[0]
print(label)
[[ 5.2088857 -4.8880706]]
0
# 打印推理结果,这里的argmax函数用于取出预测值中概率最高的一个的下标,作为预测标签
import warnings
warnings.filterwarnings('ignore')
pred_label = test_result[0][0].argmax()
print(label)
print(pred_label)
print('true label: {}, pred label: {}'.format(label, pred_label))
# 使用matplotlib库,可视化图片
from matplotlib import pyplot as plt
plt.imshow(img[0])
0
0
true label: 0, pred label: 0





<matplotlib.image.AxesImage at 0x7f88c05daf10>

output_23_2.png

四、自定义模型

选择自定义CNN模型可以直接跳转至此。

1.自定义卷积模型

# 定义卷积神经网络实现猴痘识别

import paddle.nn as nn

class MyCNN(nn.Layer): 
    def __init__(self):
        super(MyCNN,self).__init__()
        self.conv0 = nn.Conv2D(in_channels= 3,out_channels=64, kernel_size=3,stride=1) # 224-3 +1 = 222*222*64
        self.pool0 = nn.MaxPool2D(kernel_size=2,stride=2) # 111*111*64
        self.conv1 = nn.Conv2D(in_channels = 64,out_channels=128,kernel_size=4,stride = 1) # 111-4+1 = 108*108*128
        self.pool1 = nn.MaxPool2D(kernel_size=2,stride=2) # 54*54*128
        self.conv2 = nn.Conv2D(in_channels= 128,out_channels=50,kernel_size=5) # 54-5+1 = 50*50*50
        self.pool2 = nn.MaxPool2D(kernel_size=2,stride=2) # 25*25*50
        self.fc1 = nn.Linear(in_features=50*25*25,out_features=50)
        self.fc2 = nn.Linear(in_features=50,out_features=2)


    def forward(self,input): 
        x = self.conv0(input)
        x = self.pool0(x)
        x = self.conv1(x)
        x = self.pool1(x)
        x = self.conv2(x)
        x = self.pool2(x)
        x = paddle.reshape(x,shape=[x.shape[0],-1])
        x = self.fc1(x) 
        y = self.fc2(x)
        return y

2.dataloader定义

#训练数据加载
train_loader = paddle.io.DataLoader(train_dataset, batch_size=128, shuffle=True)
#测试数据加载
eval_loader = paddle.io.DataLoader(test_dataset, batch_size = 64, shuffle=False)

3.画图函数定义

import matplotlib.pyplot as plt
%matplotlib inline

Batch=0
Batchs=[]
all_train_accs=[]
def draw_train_acc(Batchs, train_accs):
    title="training accs"
    plt.title(title, fontsize=24)
    plt.xlabel("batch", fontsize=14)
    plt.ylabel("acc", fontsize=14)
    plt.plot(Batchs, train_accs, color='green', label='training accs')
    plt.legend()
    plt.grid()
    plt.show()

all_train_loss=[]
def draw_train_loss(Batchs, train_loss):
    title="training loss"
    plt.title(title, fontsize=24)
    plt.xlabel("batch", fontsize=14)
    plt.ylabel("loss", fontsize=14)
    plt.plot(Batchs, train_loss, color='red', label='training loss')
    plt.legend()
    plt.grid()
    plt.show()

4.模型训练并保存

# 训练模型-CNN

model=MyCNN() # 模型实例化
model.train() # 训练模式
cross_entropy = paddle.nn.CrossEntropyLoss()
opt=paddle.optimizer.SGD(learning_rate=0.001, parameters=model.parameters())

epochs_num=20 #迭代次数
for pass_num in range(20):
    for batch_id,data in enumerate(train_loader()):
        image = data[0] #[B,C,H,W]
        label = data[1] #[B,1]
        label=paddle.unsqueeze(label, 1)
        predict=model(image) #数据传入model
        loss = cross_entropy(predict,label)
        avg_loss = paddle.mean(loss)
        acc=paddle.metric.accuracy(predict,label)#计算精度
        
        loss.backward()       
        opt.step()
        opt.clear_grad()   #opt.clear_grad()来重置梯度

        if batch_id!=0 and batch_id%5==0:
            Batch = Batch + 5 
            Batchs.append(Batch)
            all_train_loss.append(loss.numpy()[0])
            all_train_accs.append(acc.numpy()[0]) 
            print("epoch:{},step:{},train_loss:{},train_acc:{}".format(pass_num,batch_id,loss.numpy(),acc.numpy()))        

paddle.save(model.state_dict(),'MyCNN')#保存模型
epoch:0,step:5,train_loss:[148.6786],train_acc:[0.4375]
epoch:0,step:10,train_loss:[6.2304006],train_acc:[0.3515625]
epoch:1,step:5,train_loss:[0.94077164],train_acc:[0.6171875]
epoch:1,step:10,train_loss:[0.63703007],train_acc:[0.71875]
epoch:2,step:5,train_loss:[0.65847814],train_acc:[0.640625]
epoch:2,step:10,train_loss:[0.6516983],train_acc:[0.6953125]
epoch:3,step:5,train_loss:[0.6700153],train_acc:[0.7578125]
draw_train_acc(Batchs,all_train_accs)
draw_train_loss(Batchs,all_train_loss)

output_33_0.png

output_33_1.png

5.模型评估

#模型评估
para_state_dict = paddle.load("MyCNN") 
model = MyCNN()
model.set_state_dict(para_state_dict) #加载模型参数
model.eval() #验证模式

accs = []

for batch_id,data in enumerate(eval_loader()):#测试集
    image=data[0]
    label=data[1]
    label=paddle.unsqueeze(label, 1)
    predict=model(image)       
    acc=paddle.metric.accuracy(predict,label)
    accs.append(acc.numpy()[0])
avg_acc = np.mean(accs)
print("当前模型在验证集上的准确率为:",avg_acc)
当前模型在验证集上的准确率为: 0.6573909

6.猴痘预测

def load_image(img_path):
    '''
    预测图片预处理
    '''
    img = Image.open(img_path) 
    if img.mode != 'RGB': 
        img = img.convert('RGB') 
    img = img.resize((224, 224), Image.BILINEAR)
    img = np.array(img).astype('float32') 
    img = img.transpose((2, 0, 1))  # HWC to CHW 
    img = img/255                # 像素值归一化 
    return img
from PIL import Image

para_state_dict = paddle.load("MyCNN")
model = MyCNN()
model.set_state_dict(para_state_dict) #加载模型参数
model.eval() #验证模式

#展示预测图片
infer_path='45-data/Monkeypox/M01_01_10.jpg'
img = Image.open(infer_path)
plt.imshow(img)          #根据数组绘制图像
plt.show()               #显示图像
#对预测图片进行预处理
infer_imgs = []
infer_imgs.append(load_image(infer_path))
infer_imgs = np.array(infer_imgs)
for i in range(len(infer_imgs)):
    data = infer_imgs[i]
    dy_x_data = np.array(data).astype('float32')
    dy_x_data=dy_x_data[np.newaxis,:, : ,:]
    img = paddle.to_tensor (dy_x_data)
    out = model(img)
    lab = np.argmax(out.numpy())  #argmax():返回最大数的索引
    print("第{}个样本,被预测为:{},真实标签为:{}".format(i+1,str(lab),infer_path.split('/')[1]))       
print("结束")

output_38_0.png

第1个样本,被预测为:1,真实标签为:Monkeypox
结束
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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