<图像分类学习笔记P1>——《图像分类》

图像分类——使用PaddlePaddle平台

一、图像分类概述

1.什么是图像分类

在这里插入图片描述

2.图像分类粒度

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.图像分类发展历程

在这里插入图片描述

4.图像分类问题的挑战

在这里插入图片描述

二、图像分类常用数据集介绍

1.MNIST数据集

在这里插入图片描述
MNIST数据集地址链接:http://yann.lecun.com/exdb/mnist

2.CIFAR10数据集

在这里插入图片描述
CIFAR数据集地址链接:http://www.cs.toronto.edu/~kriz/cifar.html

3.ImageNet数据集

在这里插入图片描述
ImageNet数据集地址链接:https://image-net.org

4.FDDB人脸数据集

在这里插入图片描述
FDDB人脸数据集地址链接:http://vis-www.cs.umass.edu/fddb/index.html#download

5.WIDER Face数据集

在这里插入图片描述
WIDER Face数据集地址链接:http://shuoyang1213.me/WIDERFACE

三、图像分类的应用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、利用CNN实现图像分类

1.数据集介绍

在这里插入图片描述

2.总体步骤

在这里插入图片描述

2.1数据预处理

给图像做标注(也称打标签)在这里插入图片描述

  • 将数据分类,例如90%的是训练集,10%的是测试集
  • 训练集和测试集的格式都是一样的。因为在神经网络计算的时候,使用数字较为方便,这里不用字符串进行计算。而最终显示的时候,再使用字符串进行显示。
    在这里插入图片描述

2.2模型结构

在这里插入图片描述

五、PaddlePaddle综合案例——使用CNN实现水果分类

示例1:基于CNN实现水果分类
水果分类(CNN)项目地址链接:https://aistudio.baidu.com/projectdetail/7656905

前期文件准备:准备添加fruits数据集(此数据集已公开,下载上传即可)、添加测试检验图片文件testImg(这个可自定义,满足要求即可)
总体准备文件展示:在这里插入图片描述

  • testImg文件是用于检验训练模型的文件图片,可以自定义,需要满足要求:其水果图片种类是apple、banana、pear、grape、orange,即需要和训练的数据集fruits的水果图片种类保持一致!
    (1)添加fruits数据集:
    在data文件夹中,上传fruits.zip在这里插入图片描述
    (2)解压数据集fruits.zip在这里插入图片描述在这里插入图片描述
    (3)添加测试文件testImg(这个可自定义)
    这里采用zip型文件添加举例在这里插入图片描述在这里插入图片描述在这里插入图片描述
    (4)运行代码:
    运行第一部分代码:在这里插入图片描述
    在这里插入图片描述
    运行第二部分代码:在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    运行第三部分代码:
    在这里插入图片描述
# 利用CNN实现水果分类

############################ 数据预处理 ############################
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 = {}  # 记录每个类别有哪些图片  key:水果名称   value:存放图片路径列表


# 将图片路径存入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  # 插入name-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:  # 写入测试集
            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  # 计数器加1

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

############################ 模型搭建、训练、保存 ############################
# 导入paddlepaddle包
import paddle
# 紧跟着开启静态图模式
#在PaddlePaddle 2.x版本中,默认开启了动态图模式(dynamic graph mode),
#通过设置paddle.enable_static()来启用静态图模式
paddle.enable_static()
import paddle.fluid as fluid
import numpy
import sys
import os
from multiprocessing import cpu_count
import time
import matplotlib.pyplot as plt



def train_mapper(sample):
    """
    根据传入的一行文本样本数据,读取相应的图像数据并返回
    :param sample: 元组,格式 (图片路径,类别)
    :return: 返回图像数据、类别
    """
    img, label = sample  # img为图像路径,label为所属的类别
    if not os.path.exists(img):
        print("图像不存在")

    # 读取图像数据
    img = paddle.dataset.image.load_image(img)
    # 对图像进行缩放,缩放到统一大小
    img = paddle.dataset.image.simple_transform(im=img,  # 原始图像数据
                                                resize_size=128,  # 图像缩放大小
                                                crop_size=128,  # 裁剪图像大小
                                                is_color=True,  # 彩色图像
                                                is_train=True)  # 训练模式,随机裁剪

    # 对图像数据进行归一化处理,将每个像素值转换到0~1之间
    img = img.astype("float32") / 255.0
    return img, label  # 返回图像数据(归一化处理后的)、类别


# 定义reader, 从训练集中读取样本
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)

    return paddle.reader.xmap_readers(train_mapper,  # 将reader读取到的数据进一步处理
                                      reader,  # 读取样本函数,读到数据送到train_mapper进一步处理
                                      cpu_count(),  # 线程数量(和逻辑CPU数量一致)
                                      buffered_size)  # 缓冲区大小

# 定义测试集读取器
def test_mapper(sample):
    img, label = sample

    img = paddle.dataset.image.load_image(img)
    img = paddle.dataset.image.simple_transform(im=img,
                                                resize_size=128,
                                                crop_size=128,
                                                is_color=True,
                                                is_train=False)
    img = img.astype("float32") / 255.0
    return img, label

def test_r(test_list, buffered_size=1024):
    def reader():
        with open(test_list, "r") as f:
            lines = [line.strip() for line in f]
            for line in lines:
                img_path, lab = line.split("\t")

                yield img_path, int(lab)

    return paddle.reader.xmap_readers(test_mapper,
                                      reader,
                                      cpu_count(),
                                      buffered_size)

# 定义reader
BATCH_SIZE = 16  # 批次大小
## 训练集reader
trainer_reader = train_r(train_list=train_file_path)  # 原始读取器
random_train_reader = paddle.reader.shuffle(reader=trainer_reader,
                                            buf_size=1300)  # 随机读取器
batch_train_reader = paddle.batch(random_train_reader,
                                  batch_size=BATCH_SIZE)  # 批量读取器
## 测试集reader
tester_reader = test_r(test_list=test_file_path) # 原始读取器
test_reader = paddle.batch(tester_reader, batch_size=BATCH_SIZE)# 批量读取器

# 变量
image = fluid.layers.data(name="image", shape=[3, 128, 128], dtype="float32")
label = fluid.layers.data(name="label", shape=[1], dtype="int64")


# 搭建CNN
# 结构:输入层 --> 卷积/激活/池化/dropout --> 卷积/激活/池化/dropout -->
#            卷积/激活/池化/dropout --> fc --> dropout --> fc(softmax)
def convolution_neural_network(image, type_size):
    """
    创建CNN
    :param image: 图像数据
    :param type_size: 分类数量
    :return: 一组分类概率(预测结果)
    """
    # 第一组 卷积/激活/池化/dropout
    conv_pool_1 = fluid.nets.simple_img_conv_pool(input=image,  # 输入数据,原始图像
                                                  filter_size=3,  # 卷积核大小3*3
                                                  num_filters=32,  # 卷积核数量
                                                  pool_size=2,  # 池化区域大小2*2
                                                  pool_stride=2,  # 池化步长值
                                                  act="relu")  # 激活函数
    drop = fluid.layers.dropout(x=conv_pool_1, dropout_prob=0.5)

    # 第二组 卷积/激活/池化/dropout
    conv_pool_2 = fluid.nets.simple_img_conv_pool(input=drop,  # 输入数据,上一个dropout输出
                                                  filter_size=3,  # 卷积核大小3*3
                                                  num_filters=64,  # 卷积核数量
                                                  pool_size=2,  # 池化区域大小2*2
                                                  pool_stride=2,  # 池化步长值
                                                  act="relu")  # 激活函数
    drop = fluid.layers.dropout(x=conv_pool_2, dropout_prob=0.5)

    # 第三组 卷积/激活/池化/dropout
    conv_pool_3 = fluid.nets.simple_img_conv_pool(input=drop,  # 输入数据,上一个dropout输出
                                                  filter_size=3,  # 卷积核大小3*3
                                                  num_filters=64,  # 卷积核数量
                                                  pool_size=2,  # 池化区域大小2*2
                                                  pool_stride=2,  # 池化步长值
                                                  act="relu")  # 激活函数
    drop = fluid.layers.dropout(x=conv_pool_3, dropout_prob=0.5)

    # fc
    fc = fluid.layers.fc(input=drop, size=512, act="relu")
    # dropout
    drop = fluid.layers.dropout(x=fc, dropout_prob=0.5)
    # fc
    predict = fluid.layers.fc(input=drop,
                              size=type_size,  # 输出值的个数(分类的数量)
                              act="softmax")
    return predict


# 调用函数,创建CNN
predict = convolution_neural_network(image=image, type_size=5)
# 损失函数
cost = fluid.layers.cross_entropy(input=predict,  # 预测结果
                                  label=label)  # 真实标签
avg_cost = fluid.layers.mean(cost)
# 准确率
accuracy = fluid.layers.accuracy(input=predict,  # 预测结果
                                 label=label)  # 真实标签
# 克隆(复制)一个program, 用于模型评估
test_program = fluid.default_main_program().clone(for_test=True)
# 优化器
optimizer = fluid.optimizer.Adam(learning_rate=0.001)
optimizer.minimize(avg_cost)
#  执行器
place = fluid.CUDAPlace(0)
exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())
# feeder
feeder = fluid.DataFeeder(feed_list=[image, label],  # 指定要喂入的数据
                          place=place)

model_save_dir = "model/fruits/"  # 模型保存路径
costs = []  # 记录损失值
accs = []  # 记录准确率
batches = []  # 记录迭代次数
times = 0

# 开始训练
for pass_id in range(60):
    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),  # 喂入参数
                                        fetch_list=[avg_cost, accuracy])  # 返回损失值、准确率
        if batch_id % 20 == 0:
            print("pass_id:%d, batch_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)  # 记录迭代次数

    # 模型评估
    test_accs = []
    test_costs = []

    for batch_id, data in enumerate(test_reader()):
        test_cost, test_acc = exe.run(program=test_program, # 执行用于测试的program
                                      feed=feeder.feed(data), # 喂入从测试集中读取的数据
                                      fetch_list=[avg_cost, accuracy]) # 获取预测损失值和准确率
        test_accs.append(test_acc[0])
        test_costs.append(test_cost[0])

    test_cost = (sum(test_costs) / len(test_costs)) # 求测试集下损失值的均值
    test_acc = (sum(test_accs) / len(test_accs))# 求测试集下准确率均值

    print("Test:%d, Cost:%f, Acc:%f" % (pass_id, test_cost, test_acc))


# 训练结束后,保存模型
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")
plt.title("training", fontsize=24)
plt.xlabel("iter", fontsize=14)
plt.ylabel("cost/acc", fontsize=14)
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()

############################ 模型加载、预测 ############################
from PIL import Image

# 定义执行器
place = fluid.CPUPlace()
infer_exe = fluid.Executor(place)
model_save_dir = "model/fruits/"

# 加载图像数据
def load_img(path):
    # 读取待测试的图片数据
    img = paddle.dataset.image.load_and_transform(path, 128, 128, False).astype("float32")
    img = img / 255.0
    return img

infer_imgs = [] # 存放要预测图像数据
test_img = "testImg/grape_2.jpg" # 待预测图片路径
infer_imgs.append(load_img(test_img)) # 加载图像数据,并存入待预测列表
infer_imgs = numpy.array(infer_imgs) # 将列表转换为数组

# 加载模型
# 返回值含义:infer_program为预测时执行的program
#           feed_target_names预测时传入的参数
#           fetch_targets 预测结果从哪里获取
infer_program, feed_target_names, fetch_targets = \
    fluid.io.load_inference_model(model_save_dir, infer_exe)

# 执行预测
results = infer_exe.run(infer_program,
                        feed={feed_target_names[0]: infer_imgs}, # 喂入参数
                        fetch_list=fetch_targets)
print(results)

# 对预测结果进行转换
result = numpy.argmax(results[0]) # 取出预测结果,并将概率最大的索引值返回
for k, v in name_dict.items(): # 遍历字典,将数字转换为名称
    if result == v:
        print("预测结果:", k)

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

六、利用VGG实现图像分类

1.什么是VGG

在这里插入图片描述

2.VGG主要参数

在这里插入图片描述

七、PaddlePaddle综合案例——使用VGG实现水果分类

示例2:基于VGG实现水果分类
水果分类(VGG)项目地址链接:https://aistudio.baidu.com/projectdetail/7657685

前期文件准备:准备添加fruits数据集(此数据集已公开,下载上传即可)、添加测试检验图片文件testImg(这个可自定义,满足要求即可)
总体准备文件展示:在这里插入图片描述

  • testImg文件是用于检验训练模型的文件图片,可以自定义,需要满足要求:其水果图片种类是apple、banana、pear、grape、orange,即需要和训练的数据集fruits的水果图片种类保持一致!
    (1)添加fruits数据集:
    在data文件夹中,上传fruits.zip
    在这里插入图片描述
    (2)解压数据集fruits.zip在这里插入图片描述在这里插入图片描述
    (3)添加测试文件testImg(这个可自定义)
    这里采用zip型文件添加举例
    在这里插入图片描述在这里插入图片描述在这里插入图片描述
    (4)运行代码:
    运行第一部分代码:在这里插入图片描述
    在这里插入图片描述
    运行第二部分代码:在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
    运行第三部分代码:在这里插入图片描述
# 利用VGG实现水果分类

############################ 数据预处理 ############################
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 = {}  # 记录每个类别有哪些图片  key:水果名称   value:存放图片路径列表


# 将图片路径存入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  # 插入name-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:  # 写入测试集
            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  # 计数器加1

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

############################ 模型搭建、训练、保存 ############################
# 导入paddlepaddle包
import paddle
# 紧跟着开启静态图模式
#在PaddlePaddle 2.x版本中,默认开启了动态图模式(dynamic graph mode),
#通过设置paddle.enable_static()来启用静态图模式
paddle.enable_static()
import paddle.fluid as fluid
import numpy
import sys
import os
from multiprocessing import cpu_count
import time
import matplotlib.pyplot as plt


def train_mapper(sample):
    """
    根据传入的一行文本样本数据,读取相应的图像数据并返回
    :param sample: 元组,格式 (图片路径,类别)
    :return: 返回图像数据、类别
    """
    img, label = sample  # img为图像路径,label为所属的类别
    if not os.path.exists(img):
        print("图像不存在")

    # 读取图像数据
    img = paddle.dataset.image.load_image(img)
    # 对图像进行缩放,缩放到统一大小
    img = paddle.dataset.image.simple_transform(im=img,  # 原始图像数据
                                                resize_size=128,  # 图像缩放大小
                                                crop_size=128,  # 裁剪图像大小
                                                is_color=True,  # 彩色图像
                                                is_train=True)  # 训练模式,随机裁剪

    # 对图像数据进行归一化处理,将每个像素值转换到0~1之间
    img = img.astype("float32") / 255.0
    return img, label  # 返回图像数据(归一化处理后的)、类别


# 定义reader, 从训练集中读取样本
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)

    return paddle.reader.xmap_readers(train_mapper,  # 将reader读取到的数据进一步处理
                                      reader,  # 读取样本函数,读到数据送到train_mapper进一步处理
                                      cpu_count(),  # 线程数量(和逻辑CPU数量一致)
                                      buffered_size)  # 缓冲区大小


# 定义测试集读取器
def test_mapper(sample):
    img, label = sample

    img = paddle.dataset.image.load_image(img)
    img = paddle.dataset.image.simple_transform(im=img,
                                                resize_size=128,
                                                crop_size=128,
                                                is_color=True,
                                                is_train=False)
    img = img.astype("float32") / 255.0
    return img, label


def test_r(test_list, buffered_size=1024):
    def reader():
        with open(test_list, "r") as f:
            lines = [line.strip() for line in f]
            for line in lines:
                img_path, lab = line.split("\t")

                yield img_path, int(lab)

    return paddle.reader.xmap_readers(test_mapper,
                                      reader,
                                      cpu_count(),
                                      buffered_size)


# 定义reader
BATCH_SIZE = 16  # 批次大小
## 训练集reader
trainer_reader = train_r(train_list=train_file_path)  # 原始读取器
random_train_reader = paddle.reader.shuffle(reader=trainer_reader,
                                            buf_size=1300)  # 随机读取器
batch_train_reader = paddle.batch(random_train_reader,
                                  batch_size=BATCH_SIZE)  # 批量读取器
## 测试集reader
tester_reader = test_r(test_list=test_file_path)  # 原始读取器
test_reader = paddle.batch(tester_reader, batch_size=BATCH_SIZE)  # 批量读取器

# 变量
image = fluid.layers.data(name="image", shape=[3, 128, 128], dtype="float32")
label = fluid.layers.data(name="label", shape=[1], dtype="int64")


# 创建VGG模型
def vgg_bn_drop(image, type_size):
    def conv_block(ipt, num_filter, groups, dropouts):
        # 创建conv2d, batch normal, 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")  # 池化类型

    conv1 = conv_block(image, 64, 2, [0.0, 0.0])  # 第一组卷积/BN/pool操作
    conv2 = conv_block(conv1, 128, 2, [0.0, 0.0])  # 第二组
    conv3 = conv_block(conv2, 256, 3, [0.0, 0.0, 0.0])
    conv4 = conv_block(conv3, 512, 3, [0.0, 0.0, 0.0])
    conv5 = conv_block(conv4, 512, 3, [0.0, 0.0, 0.0])

    drop = fluid.layers.dropout(x=conv5, dropout_prob=0.5)
    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)
# 损失函数
cost = fluid.layers.cross_entropy(input=predict,  # 预测结果
                                  label=label)  # 真实标签
avg_cost = fluid.layers.mean(cost)
# 准确率
accuracy = fluid.layers.accuracy(input=predict,  # 预测结果
                                 label=label)  # 真实标签
# 克隆(复制)一个program, 用于模型评估
test_program = fluid.default_main_program().clone(for_test=True)
# 优化器
optimizer = fluid.optimizer.Adam(learning_rate=0.001) # VGG模型学习率要调整的非常小
optimizer.minimize(avg_cost)
#  执行器
place = fluid.CUDAPlace(0)
exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())
# feeder
feeder = fluid.DataFeeder(feed_list=[image, label],  # 指定要喂入的数据
                          place=place)

model_save_dir = "model/fruits/"  # 模型保存路径
costs = []  # 记录损失值
accs = []  # 记录准确率
batches = []  # 记录迭代次数
times = 0

# 开始训练
for pass_id in range(60):
    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),  # 喂入参数
                                        fetch_list=[avg_cost, accuracy])  # 返回损失值、准确率
        if batch_id % 20 == 0:
            print("pass_id:%d, batch_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)  # 记录迭代次数

    # 模型评估
    test_accs = []
    test_costs = []

    for batch_id, data in enumerate(test_reader()):
        test_cost, test_acc = exe.run(program=test_program,  # 执行用于测试的program
                                      feed=feeder.feed(data),  # 喂入从测试集中读取的数据
                                      fetch_list=[avg_cost, accuracy])  # 获取预测损失值和准确率
        test_accs.append(test_acc[0])
        test_costs.append(test_cost[0])

    test_cost = (sum(test_costs) / len(test_costs))  # 求测试集下损失值的均值
    test_acc = (sum(test_accs) / len(test_accs))  # 求测试集下准确率均值

    print("Test:%d, Cost:%f, Acc:%f" % (pass_id, test_cost, test_acc))

# 训练结束后,保存模型
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")
plt.title("training", fontsize=24)
plt.xlabel("iter", fontsize=14)
plt.ylabel("cost/acc", fontsize=14)
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()

############################ 模型加载、预测 ############################
from PIL import Image

# 定义执行器
place = fluid.CPUPlace()
infer_exe = fluid.Executor(place)
model_save_dir = "model/fruits/"


# 加载图像数据
def load_img(path):
    # 读取待测试的图片数据
    img = paddle.dataset.image.load_and_transform(path, 128, 128, False).astype("float32")
    img = img / 255.0
    return img


infer_imgs = []  # 存放要预测图像数据
test_img = "testImg/pear_2.jpg"  # 待预测图片路径
infer_imgs.append(load_img(test_img))  # 加载图像数据,并存入待预测列表
infer_imgs = numpy.array(infer_imgs)  # 将列表转换为数组

# 加载模型
# 返回值含义:infer_program为预测时执行的program
#           feed_target_names预测时传入的参数
#           fetch_targets 预测结果从哪里获取
infer_program, feed_target_names, fetch_targets = \
    fluid.io.load_inference_model(model_save_dir, infer_exe)

# 执行预测
results = infer_exe.run(infer_program,
                        feed={feed_target_names[0]: infer_imgs},  # 喂入参数
                        fetch_list=fetch_targets)
print(results)

# 对预测结果进行转换
result = numpy.argmax(results[0])  # 取出预测结果,并将概率最大的索引值返回
for k, v in name_dict.items():  # 遍历字典,将数字转换为名称
    if result == v:
        print("预测结果:", k)

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

后记:
●本博客基于B站开源学习资源,是作者学习的笔记记录,仅用于学习交流,不做任何商业用途!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值