图片分类及Paddle派部署实例

本文提供了一个在AI Studio上训练猫狗分类模型并部署到Paddle派硬件的完整流程。从数据预处理、参数设置、网络结构定义到训练、预测和模型转换,详细解释了每个步骤,最终实现模型在Paddle派上的运行。
摘要由CSDN通过智能技术生成

项目简介

这是一个demo 项目,用于演示如何在 AI Studio 上训练一个“小”模型,然后把它转化成一个可以部署到Paddle派硬件上的模型。

为了简单起见,在此只训练一个猫猫和狗狗的二分类模型。

进入项目时,已经引用了 AI Studio 的公开数据集"猫狗大战数据集"作为训练数据。数据存储在 data/data62/ 目录下,以压缩包的形式存在。执行下面的代码,进入目录,将训练数据解压

In[1]

!cd /home/aistudio/data/data62 && unzip -q train.zip 
!cd /home/aistudio/data/data62 && unzip -q test.zip

数据预处理

训练集中的数据按照

cat.123.jpg

dog.456.jpg

的命名方式。由于数据中存在一些破损的图片,所以需要先清洗一下数据。同时,为了方便训练,将数据的一行准备成

文件名\t类别

的格式,并输出到和图片同级目录下的label.txt文件中。猫猫的类别是1,狗狗的类别是0。执行以下代码,进行数据的简单清洗

In[2]

#数据清洗
import codecs
import os
from PIL import Image

train_file_list = os.listdir('data/data62/train')
with codecs.open("data/data62/train/label.txt", 'w') as out_file:
    for file in train_file_list:
        try:
            img = Image.open(os.path.join('data/data62/train', file))
            if file.find('cat') != -1:
                out_file.write("{0}\t{1}\n".format(file, 1))
            else:
                out_file.write("{0}\t{1}\n".format(file, 0))
        except Exception as e:
            pass
            # 存在一些文件打不开,此处需要稍作清洗        

参数设置

设置基础训练参数,例如

  • 图片尺寸,注意是 chw 格式
  • 训练数据路径
  • 保存模型的输出路径
  • 训练轮数、训练批次大小
  • 是否使用GPU
  • 学习率变化等

其中类别数量会在读取数据时提前计算,初始为-1,仅用作占位

In[3]

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import numpy as np
import uuid
import random
import time
import six
import sys
import functools
import math
import paddle
import paddle.fluid as fluid
import paddle.dataset.flowers as flowers
import argparse
import functools
import subprocess
import codecs
import distutils.util
from paddle.fluid import core
from paddle.fluid.initializer import MSRA
from paddle.fluid.param_attr import ParamAttr
from PIL import Image, ImageEnhance
import logging


train_parameters = {
    "input_size": [3, 224, 224],
    "class_dim": -1,
    "data_dir": "data/data62/train",
    "save_model_dir": "./classify-model",
    "mode": "train",
    "num_epochs": 120,
    "image_count": -1,
    "train_batch_size": 50,
    "mean_rgb": [127.5, 127.5, 127.5],
    "use_gpu": True,            # 根据自己的环境,选择适当的设备进行训练
    "image_distort_strategy": {
        "need_distort": True,
        "expand_prob": 0.5,
        "expand_max_ratio": 4,
        "hue_prob": 0.5,
        "hue_delta": 18,
        "contrast_prob": 0.5,
        "contrast_delta": 0.5,
        "saturation_prob": 0.5,
        "saturation_delta": 0.5,
        "brightness_prob": 0.5,
        "brightness_delta": 0.125
    },
    "rsm_strategy": {
        "learning_rate": 0.02,
        "lr_epochs": [20, 40, 60, 80, 100],
        "lr_decay": [1, 0.5, 0.25, 0.1, 0.01, 0.002]
    },
    "momentum_strategy": {
        "learning_rate": 0.005,
        "lr_epochs": [20, 40, 60, 80, 100],
        "lr_decay": [1, 0.5, 0.25, 0.1, 0.01, 0.002]
    }
}

定义网络结构

设定网络结构,此处定义了三个常用的网络结构

  • resnet
  • mobile-net
  • vgg-net

为了训练一个小模型,此处使用mobile-net。如果是其他项目或者其他用途,使用其他网络结构亦可

In[4]

class ResNet():
    def __init__(self, layers=50):
        self.layers = layers
        
    def name(self):
        return 'resnet'

    def net(self, input, class_dim=1000):
        layers = self.layers
        supported_layers = [50, 101, 152]
        assert layers in supported_layers, \
            "supported layers are {} but input layer is {}".format(supported_layers, layers)

        if layers == 50:
            depth = [3, 4, 6, 3]
        elif layers == 101:
            depth = [3, 4, 23, 3]
        elif layers == 152:
            depth = [3, 8, 36, 3]
        num_filters = [64, 128, 256, 512]

        conv = self.conv_bn_layer(
            input=input,
            num_filters=64,
            filter_size=7,
            stride=2,
            act='relu',
            name="conv1")
        conv = fluid.layers.pool2d(
            input=conv,
            pool_size=3,
            pool_stride=2,
            pool_padding=1,
            pool_type='max')

        for block in range(len(depth)):
            for i in range(depth[block]):
                if layers in [101, 152] and block == 2:
                    if i == 0:
                        conv_name = "res" + str(block + 2) + "a"
                    else:
                        conv_name = "res" + str(block + 2) + "b" + str(i)
                else:
                    conv_name = "res" + str(block + 2) + chr(97 + i)
                conv = self.bottleneck_block(
                    input=conv,
                    num_filters=num_filters[block],
                    stride=2 if i == 0 and block != 0 else 1,
                    name=conv_name)

        pool = fluid.layers.pool2d(
            input=conv, pool_size=7, pool_type='avg', global_pooling=True)
        stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0)
        out = fluid.layers.fc(input=pool,
                              size=class_dim,
                              act='softmax', 
                              param_attr=fluid.param_attr.ParamAttr(
                                  initializer=fluid.initializer.Uniform(-stdv,
                                                                        stdv)))
        return out

    def conv_bn_layer(self,
                      input,
                      num_filters,
                      filter_size,
                      stride=1,
                      groups=1,
                      act=None,
                      name=None):
        conv = fluid.layers.conv2d(
            input=input,
            num_filters=num_filters,
            filter_size=filter_size,
            stride=stride,
            padding=(filter_size - 1) // 2,
            groups=groups,
            act=None,
            param_attr=ParamAttr(name=name + "_weights"),
            bias_attr=False,
            name=name + '.conv2d.output.1')
        if name == "conv1":
            bn_name = "bn_" + name
        else:
            bn_name = "bn" + name[3:]
        return fluid.layers.batch_norm(
            input=conv,
            act=act,
            name=bn_name + '.output.1',
            param_attr=ParamAttr(name=bn_name + '_scale'),
            bias_attr=ParamAttr(bn_name + '_offset'),
            moving_mean_name=bn_name + '_mean',
            moving_variance_name=bn_name + '_variance', )

    def shortcut(self, input, ch_out, stride, name):
        ch_in = input.shape[1]
        if ch_in != ch_out or stri
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值