使用飞桨机器学习平台区分猫狗分类(内附代码下载链接)

由于飞桨直接提供了算力,我在本地只配置了cpu版本的
本次使用内置的Resnet50来做猫狗分类
大致流程如下

数据处理

基础配置

CONFIG = {
    'model_save_dir': "./output/zodiac",  # 模型保存位置
    'num_classes': 2,   # 结果分类有多少种
    'total_images': 7096, 
    'epochs': 20, # 训练多少轮
    'batch_size': 32,  # 每次取多少样本训练
    'image_shape': [3, 224, 224],  # 图片大小
    'LEARNING_RATE': {  # 学习率
        'params': {
            'lr': 0.00375   
        }
    },
    'OPTIMIZER': {
        'params': {
            'momentum': 0.9
        },
        'regularizer': {
            'function': 'L2',
            'factor': 0.000001
        }
    },
    'LABEL_MAP': [   # 分类标签
        "cat",
        "dog",
    ]
}


def get(full_path):
    for id, name in enumerate(full_path.split('.')):
        if id == 0:
            config = CONFIG

        config = config[name]

    return config

生成标注数据

import io
import os
from PIL import Image
# 数据集根目录
DATA_ROOT = r'/home/aistudio/data/data161626/train'
# 标签List
LABEL_MAP = get('LABEL_MAP')
# 标注生成函数
def generate_annotation(mode):
    # 建立标注文件
    with open('{}/{}.txt'.format(DATA_ROOT, mode), 'w') as f:
        # 对应每个用途的数据文件夹,train/valid/test
        train_dir = '{}/{}'.format(DATA_ROOT, mode)
        # 遍历文件夹,获取里面的分类文件夹
        for path in os.listdir(train_dir):
            # 标签对应的数字索引,实际标注的时候直接使用数字索引
            label_index = LABEL_MAP.index(path)
            # 图像样本所在的路径
            image_path = '{}/{}'.format(train_dir, path)
            # 遍历所有图像
            for image in os.listdir(image_path):
                # 图像完整路径和名称
                image_file = '{}/{}'.format(image_path, image)
                try:
                    # 验证图片格式是否ok
                    with open(image_file, 'rb') as f_img:
                        image = Image.open(io.BytesIO(f_img.read()))
                        image.load()
                        if image.mode == 'RGB':
                            f.write('{}\t{}\n'.format(image_file, label_index))
                except:
                    continue
generate_annotation('train')  # 生成训练集标注文件
generate_annotation('valid')  # 生成验证集标注文件
generate_annotation('test')  # 生成测试集标注文件

自定义数据集

import paddle
import paddle.vision.transforms as T
import numpy as np
from PIL import Image

__all__ = ['ZodiacDataset']

# 定义图像的大小
image_shape = get('image_shape')  # 'image_shape': [3, 224, 224],
IMAGE_SIZE = (image_shape[1], image_shape[2])


class ZodiacDataset(paddle.io.Dataset):
    """
    猫狗数据集类的定义
    """

    def __init__(self, mode='train'):
        """
        初始化函数
        """
        assert mode in ['train', 'test', 'valid'], 'mode is one of train, test, valid.'  # 判断参数合法性

        self.data = []
        """
       根据不同模式选择不同的数据标注文件

       """

        with open(r'/home/aistudio/data/data161626/train/{}.txt'.format(mode)) as f:
            for line in f.readlines():
                info = line.strip().split('\t')

                if len(info) > 0:
                    self.data.append([info[0].strip(), info[1].strip()])  # 进行切分形成数组,每个数组包含图像的地址和label

        if mode == 'train':
            self.transforms = T.Compose([
                T.RandomResizedCrop(IMAGE_SIZE),  # 随机裁剪大小,裁剪地方不同等于间接增加了数据样本 300*300-224*224
                T.RandomHorizontalFlip(0.5),  # 随机水平翻转,概率0.5,也是等于得到一个新的图像
                T.ToTensor(),  # 数据的格式转换和标准化 HWC => CHW
                T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])  # 图像归一化
            ])
        else:  # 评估模式:没必要进行水平翻转增加样本量了,主要是想看看效果
            self.transforms = T.Compose([
                T.Resize(256),  # 图像大小修改
                T.RandomCrop(IMAGE_SIZE),  # 随机裁剪,
                T.ToTensor(),  # 数据的格式转换和标准化 HWC => CHW
                T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])  # 图像归一化
            ])
    def __getitem__(self, index):
        """
        根据索引获取单个样本
        """
        image_file, label = self.data[index]
        image = Image.open(image_file)
        # 转成RGB模式,三通道的
        if image.mode != 'RGB':
            image = image.convert('RGB')

        image = self.transforms(image)  # 得到预处理后的结果

        return image, np.array(label, dtype='int64')  # 对label做个数据转换,int类型转成numpy


    def __len__(self):
        """
        获取样本总数
        """
        return len(self.data)

训练

import paddle
import numpy as np


train_dataset = ZodiacDataset(mode='train')
valid_dataset = ZodiacDataset(mode='valid')

network = paddle.vision.models.resnet50(num_classes=get('num_classes'), pretrained=True)

model = paddle.Model(network)
model.summary((-1, ) + tuple(get('image_shape')))
EPOCHS = get('epochs')
BATCH_SIZE = get('batch_size')

def create_optim(parameters):
    step_each_epoch = get('total_images')   # get('batch_size')
    lr = paddle.optimizer.lr.CosineAnnealingDecay(learning_rate=get('LEARNING_RATE.params.lr'),
                                                  T_max=step_each_epoch * EPOCHS)

    return paddle.optimizer.Momentum(learning_rate=lr,
                                     parameters=parameters,
                                     weight_decay=paddle.regularizer.L2Decay(get('OPTIMIZER.regularizer.factor'))) #正则化来提升精度


# 模型训练配置
model.prepare(create_optim(network.parameters()),  # 优化器
              paddle.nn.CrossEntropyLoss(),        # 损失函数
              paddle.metric.Accuracy(topk=(1, 5))) # 评估指标

# 训练可视化VisualDL工具的回调函数
visualdl = paddle.callbacks.VisualDL(log_dir='visualdl_log')
# 启动模型全流程训练
model.fit(train_dataset,            # 训练数据集
          valid_dataset,            # 评估数据集
          epochs=EPOCHS,            # 总的训练轮次
          batch_size=BATCH_SIZE,    # 批次计算的样本量大小
          shuffle=True,             # 是否打乱样本集
          verbose=1,                # 日志展示格式
          save_dir='./chk_points/', )# 分阶段的训练模型存储路径
          # callbacks=[visualdl])     # 回调函数使用

model.save(get('model_save_dir'))  # 这里添加train=False参数可将模型保存为静态模型

预测

​ 使用预测样本进行预测

import paddle

predict_dataset = ZodiacDataset(mode='test')
print('测试数据集样本量:{}'.format(len(predict_dataset)))
from paddle.static import InputSpec
# 网络结构示例化
network = paddle.vision.models.resnet50(num_classes=get('num_classes'))
# 模型封装
model_2 = paddle.Model(network, inputs=[InputSpec(shape=[-1] + get('image_shape'), dtype='float32', name='image')])
# 训练好的模型加载
model_2.load(get('model_save_dir'))
print(get('model_save_dir'))
# 模型配置
model_2.prepare()
# 执行预测
result = model_2.predict(predict_dataset)
print(result)
model_2.save("./out/info", training=False)
# 样本映射
LABEL_MAP = get('LABEL_MAP')
# 随机取样本展示
indexs = np.random.randint(1, 646, size=20)

for idx in indexs:
    predict_label = np.argmax(result[0][idx])
    real_label = predict_dataset[idx][1]

    print('样本ID:{}, 真实标签:{}, 预测值:{}'.format(idx, LABEL_MAP[real_label], LABEL_MAP[predict_label]))

单张图片预测验证

import numpy as np
import paddle
import paddle.vision.transforms as T
from PIL import Image
import matplotlib.pyplot as plt

def load_image(image_file):
    im = Image.open(image_file)
    # 将图片调整为跟训练数据一样的大小  224*224,                   设定ANTIALIAS,即抗锯齿.resize是缩放
    im = im.resize((224, 224), Image.ANTIALIAS)
    # 建立图片矩阵 类型为float32
    im = np.array(im).astype(np.float32)
    # 矩阵转置
    im = im.transpose((2, 0, 1))
    # 将像素值从【0-255】转换为【0-1】
    im = im / 255.0
    # print(im)
    im = np.expand_dims(im, axis=0)
    # 保持和之前输入image维度一致
    return im

def sigle_pic_foreast():
    img_file = r"/home/aistudio/data/data161626/train/test/cat/cat_5.jpg"
    # img_file = r"C:\Users\Public\Pictures\Sample Pictures\45fdeb26c9bd4af3b129c99424af932a.jpg"
    image = load_image(img_file)
    from paddle.static import InputSpec

    # 网络结构示例化
    network = paddle.vision.models.resnet50(num_classes=get('num_classes'))

    # 模型封装
    model_2 = paddle.Model(network, inputs=[InputSpec(shape=[-1] + get('image_shape'), dtype='float32', name='image')])

    # 训练好的模型加载
    model_2.load(get('model_save_dir'))

    # 模型配置
    model_2.prepare()
    result = model_2.predict((image,))
    print(result)

sigle_pic_foreast()

转换为静态图,并进行单张图片验证

import time
import numpy as np
import paddle
from PIL import Image
from paddle import fluid
from paddle.static import InputSpec

# 网络结构示例化
from config import get

# 转为静态图
def get_model():
    network = paddle.vision.models.resnet50(num_classes=get('num_classes'), pretrained=True)
    # 模型封装
    model_2 = paddle.Model(network, inputs=[InputSpec(shape=[-1] + get('image_shape'), dtype='float32', name='image')])
    # 训练好的模型加载
    model_2.load("./out/info")

    # 模型配置
    model_2.prepare()
    # 保存为训练模式
    model_2.save("./out", training=False)


# 预处理图片
def load_image(file):
    img = Image.open(file)
    # 统一图像大小
    img = img.resize((224, 224), Image.ANTIALIAS)
    # 转换成numpy值
    img = np.array(img).astype(np.float32)
    # 转换成CHW
    img = img.transpose((2, 0, 1))
    # 转换成BGR
    img = img[(2, 1, 0), :, :] / 255.0
    img = np.expand_dims(img, axis=0)
    return img




# img_file = r"E:\train\train\dog\dog_2001.jpg"
img_file = r"C:\Users\Public\Pictures\Sample Pictures\TBj0nti43n6epO (1).jpg"
# img_file = r"C:\Users\Lenovo\Downloads\969d9e9be2909b3ae2433ac012a1f4c9.jpeg"
# img_file = r"C:\Users\Lenovo\Downloads\bbd7aaacbec520666e8c38457d19d393.jpeg"


def deploy(img_file):
    # 开始预测图片
    img = load_image(img_file)
    loaded_model = paddle.jit.load("./out/info")
    result = loaded_model(img)

    LABEL_MAP = get('LABEL_MAP')
    predict_label = np.argmax(result[0])
    ans = LABEL_MAP[predict_label]
    print(result, predict_label)
    print("预测值:{},预测准确度:{}".format(ans, result[0][0][0][predict_label].numpy()[0]))


if __name__ == '__main__':
    t1 = time.time()
    deploy(img_file)
    print(time.time()-t1)

代码和数据集下载:https://url99.ctfile.com/f/37358799-627781656-ac9444?p=8747 (访问密码: 8747)

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值