PaddlePaddle基本用法详解(二)、PaddelPaddle训练水果分类模型

1、基本用法

PaddlePaddle基本用法详解(二)、PaddelPaddle训练水果分类模型

2、训练水果分类模型

PaddlePaddle基本用法详解(二)、PaddelPaddle训练水果分类模型
1、数据集预处理与模型定义代码:

import os

###################################第一部分:水果预处理部分#################################
# 定义一组变量
name_dict = {"apple": 0, "banana": 1, "grape": 2, "orange": 3, "pear": 4}  # 水果名称和数组对应字典
data_root_path = "data/fruits/"  # 数据样本所在目录
test_file_path = data_root_path + "test.txt"  # 测试集文件路径
train_file_path = data_root_path + "train.txt"  # 训练集文件路径


name_data_list = {}  # 记录每个类别的图片路径
# 将文件路径存入临时字典
def save_train_test_file(path, name):
    if name not in name_data_list:  # 当前水果没有在字典中,新增
        img_list = []
        img_list.append(path)  # 将图片添加到列表
        name_data_list[name] = img_list  # 将“名称-图片列表”键值对插入字典
    else:  # 当前水果已经在字典中,添加到相应的列表
        name_data_list[name].append(path)


# 遍历所有子目录,读取出所有图片文件,并插入字典、保存到测试集、训练集
dirs = os.listdir(data_root_path)
for d in dirs:
    full_path = data_root_path + d  # 目录名称 + 子目录名称

    if os.path.isdir(full_path):  # 目录
        imgs = os.listdir(full_path)  # 列出子目录中的文件
        for img in imgs:
            save_train_test_file(full_path + "/" + img,  # 图片文件完整路径
                                 d)  # 子目录名称(类别名称)
    else:  # 文件
        pass

# 将字典中的内容保存文件中
with open(test_file_path, "w") as f:  # 清空测试集文件
    pass
with open(train_file_path, "w") as f:  # 清空训练集文件
    pass

# 遍历字典,将内容写入文件
for name, img_list in name_data_list.items():
    i = 0
    num = len(img_list)  # 每个类别图片数量
    print("%s: %d张图像" % (name, num))

    for img in img_list:  # 遍历每个列表,将图片路径存入文件
        if i % 10 == 0:  # 每10张写一张到测试集
            with open(test_file_path, "a") as f:
                line = "%s\t%d\n" % (img, name_dict[name])
                f.write(line)  # 写入文件
        else:  # 其它写入训练集
            with open(train_file_path, "a") as f:
                line = "%s\t%d\n" % (img, name_dict[name])
                f.write(line)  # 写入文件
        i += 1

print("数据预处理完成.")

###################################第二部分:水果预处理部分################################
import paddle
import paddle.fluid as fluid
import numpy as np
import sys
import os
from multiprocessing import cpu_count
import matplotlib.pyplot as plt



# 数据准备
## 定义reader
## train_mapper函数:对传入的图片路径进行读取,返回图像数据(多通道矩阵)、标签
def train_mapper(sample):
    img, label = sample  # 将sample中值赋给img, label

    if not os.path.exists(img):
        print(img, "图片文件不存在")

    # 读取图片文件
    img = paddle.dataset.image.load_image(img)  # 读取图片
    # 对图像进行简单变换:修剪、设置大小,输出(3, 100, 100)张量
    img = paddle.dataset.image.simple_transform(im=img, # 原图像数据
                                                resize_size=100, # 重设图像大小为100*100
                                                crop_size=100, # 裁剪成100*100
                                                is_color=True, # 彩色图像
                                                is_train=True) # 是否用于训练,影响裁剪策略
    # 对图像数据进行归一化处理,像素的值全部计算压缩到0~1之间
    img = img.astype("float32") / 255.0

    return img, label   # 返回图像数据、标签

# 读取训练集文件,将路径、标签作为参数调用train_mapper函数
def train_r(train_list, buffered_size=1024):
    def reader():
        with open(train_list, "r") as f: # 打开训练集
            lines = [line.strip() for line in f]  # 读取出所有样本行

            for line in lines:
                # 去掉每行的换行符,并根据tab字符进行拆分,得到两个字段
                img_path, lab = line.replace("\n", "").split("\t")
                yield img_path, int(lab)

    # xmap_readers高阶函数,作用是将reader产生的数据穿个train_mapper函数进行下一步处理
    return paddle.reader.xmap_readers(train_mapper, # 二次处理函数
                                      reader, # 原始reader
                                      cpu_count(), # 线程数(和cpu数量一致)
                                      buffered_size) # 缓冲区大小

BATCH_SIZE = 32  # 批次大小

# 定义reader
train_reader = train_r(train_list=train_file_path)# train_file_path为训练集文件路径
random_train_reader = paddle.reader.shuffle(reader=train_reader, # 原始reader
                                            buf_size=1300) # 缓冲区大小
batch_train_reader = paddle.batch(random_train_reader,
                                  batch_size=BATCH_SIZE)  # 批量读取器
# 定义变量
image = fluid.layers.data(name="image", shape=[3, 100, 100], dtype="float32")
label = fluid.layers.data(name="label", shape=[1], dtype="int64")


# 创建VGG模型
def vgg_bn_drop(image, type_size):  # 其包含批归一化层与丢弃层
    def conv_bn_block(ipt, num_filter, groups, dropout):
        # 创建Convolution2d,BatchNorm,Dropout,Pool2d组
        return fluid.nets.img_conv_group(input=ipt,  # 输入图像数据,【N,C,H,W】格式
                                         pool_stride=2,  # 池化步长值
                                         pool_size=2,  # 池化区域大小
                                         conv_num_filter=[num_filter] * groups,  # 卷积核的数量(即组的数量*每一组卷积核的数量)
                                         conv_filter_size=3,  # 卷积核大小
                                         conv_act="relu",  # 激活函数
                                         conv_with_batchnorm=True,  # 即卷积完成后是否要进行批量归一化操作
                                         pool_type="max"  # 池化的类型
                                         )

    # VGG前面的5组卷积池化
    conv1 = conv_bn_block(image, 64, 2, [0.0, 0.0])  # 表示卷积核数量;2表示组数;[0.0,0.0]表示每组卷积的丢弃率
    conv2 = conv_bn_block(conv1, 128, 2, [0.0, 0.0])
    conv3 = conv_bn_block(conv2, 256, 3, [0.0, 0.0, 0.0])
    conv4 = conv_bn_block(conv3, 512, 3, [0.0, 0.0, 0.0])
    conv5 = conv_bn_block(conv4, 512, 3, [0.0, 0.0, 0.0])

    drop = fluid.layers.dropout(x=conv5, dropout_prob=0.2)
    fc1 = fluid.layers.fc(input=drop, size=512, act=None)

    bn = fluid.layers.batch_norm(input=fc1, act="relu")
    drop2 = fluid.layers.dropout(x=bn, dropout_prob=0.0)

    fc2 = fluid.layers.fc(input=drop2, size=512, act=None)
    predict = fluid.layers.fc(input=fc2,
                              size=type_size,
                              act="softmax")
    return predict


# 调用上面的函数创建VGG
predict = vgg_bn_drop(image=image, type_size=5)  # type_size和水果类别一致
# 损失函数
cost = fluid.layers.cross_entropy(input=predict,  # 预测值
                                  label=label)  # 真实值
avg_cost = fluid.layers.mean(cost)
# 计算准确率
accuracy = fluid.layers.accuracy(input=predict,  # 预测值
                                 label=label)  # 真实值
# 优化器
optimizer = fluid.optimizer.Adam(learning_rate=0.00001)  # 自适应梯度下降优化器
optimizer.minimize(avg_cost)

# 创建Executor
place = fluid.CUDAPlace(0)  # GPU上执行
exe = fluid.Executor(place)  # 执行器
exe.run(fluid.default_startup_program())  # 初始化变量

# 定义feeder
feeder = fluid.DataFeeder(feed_list=[image, label], place=place)

costs = []  # 记录损失值
accs = []  # 记录准确率
times = 0
batches = []  # 记录批次

for pass_id in range(15):
    train_cost = 0

    for batch_id, data in enumerate(batch_train_reader()):
        times += 1

        train_cost, train_acc = exe.run(program=fluid.default_main_program(),
                                        feed=feeder.feed(data),  # 喂入一个batch数据
                                        fetch_list=[avg_cost, accuracy])  # 获取结果
        if batch_id % 20 == 0:
            print("pass_id:%d, bat_id:%d, cost:%f, acc:%f" %
                  (pass_id, batch_id, train_cost[0], train_acc[0]))
            accs.append(train_acc[0])  # 记录准确率
            costs.append(train_cost[0])  # 记录损失值
            batches.append(times)  # 记录训练批次数

# 保存模型
model_save_dir = "model/fruits/"  # 模型保存路径
if not os.path.exists(model_save_dir):  # 如果模型路径不存在则创建
    os.makedirs(model_save_dir)
fluid.io.save_inference_model(dirname=model_save_dir,  # 保存路径
                              feeded_var_names=["image"],  # 使用模型需传入的参数
                              target_vars=[predict],  # 模型结果
                              executor=exe)  # 模型
print("模型保存完成.")

# 训练过程可视化
plt.figure('training', facecolor='lightgray')
plt.title("training", fontsize=24)
plt.xlabel("iter", fontsize=20)
plt.ylabel("cost/acc", fontsize=20)
plt.plot(batches, costs, color='red', label="Training Cost")
plt.plot(batches, accs, color='green', label="Training Acc")
plt.legend()
plt.grid()
plt.savefig("train.png")
plt.show()

PaddlePaddle基本用法详解(二)、PaddelPaddle训练水果分类模型

2、加载模型,预测图像

############################# 第三部分:加载模型,使用模型执行预测 ################################
from PIL import Image

import paddle.fluid as fluid
import paddle
import numpy
import matplotlib.pyplot as plt

def load_img(path):  # 从指定路径读取图片数据
    img = paddle.dataset.image.load_and_transform(
        path,  # 图片路径
        100, 100,  # resize图像大小、裁剪大小
        False  # 是否用于训练
    )
    # 因为需要对图像进行归一化,所以需要将图像转变为float32的格式
    img = (img.astype("float32")) / 255.0  # 进行归一化
    return img


# 定义执行器
place = fluid.CPUPlace()  # 在预测时,计算量不大,所以没有必要在cuda上计算
infer_exe = fluid.Executor(place)  # 创建执行器
model_save_dir= "model/fruits/"  # 模型的保存路径

infer_imgs = []  # 用来存放待预测图像数据
test_img = "putao.png"  # 待预测图片路径
infer_imgs.append(load_img(test_img))  # 读取图像数据,添加到待预测的列表中
# 因为神经网络无法读取列表数据,所以需要将列表数据转换为数组数据输入神经网络
infer_imgs = numpy.array(infer_imgs)  # 转换为数组

# 加载保存的模型
infer_program,feed_target_names,fetch_targets= \
                                fluid.io.load_inference_model(model_save_dir,   # 模型保存路径
                                                              infer_exe)        # 要执行模型的Executor
# 使用模型执行预测
result = infer_exe.run(
                    infer_program,  # 预测的program
                    feed={feed_target_names[0]: infer_imgs},  # 喂入待预测的数据
                    fetch_list=fetch_targets  # 取得操作结果并返回
                )

print(result)   # 得到的result是一个各个分类概率的二维数组
"""
[array([[9.9999964e-01, 5.7820136e-24, 2.9262706e-10, 3.9078353e-07,1.4152669e-19]], dtype=float32)]
"""

index=numpy.argmax(result[0])
name_dict = {"apple": 0, "banana": 1, "grape": 2, "orange": 3, "pear": 4}
# 遍历字典
for k,v in name_dict.items():       # 对分类字典进行迭代返回的是字典的键,值
    if index==v:
        print("预测结果为:",k)

# 显示待预测的图片
img = Image.open(test_img)
plt.imshow(img)
plt.show()

PaddlePaddle基本用法详解(二)、PaddelPaddle训练水果分类模型

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
乘风的头像乘风管理团队
上一篇 2022年4月20日 下午6:37
下一篇 2022年4月20日 下午6:48

相关推荐