飞桨图像分类入门——多种网络模型在手写数字识别的应用

什么是图像分类

图像分类是基于深度学习的cv分类任务。 核心是从给定的分类集合中给图像分配一个标签的任务。 实际上我们的任务是分析一个输入图像并返回一个图像分类的标签。 标签总是来自预定义的可能类别集。

首先导入必要的包

numpy---------->python第三方库,用于进行科学计算

PIL------------> Python Image Library,python第三方图像处理库

matplotlib----->python的绘图库 pyplot:matplotlib的绘图框架

os------------->提供了丰富的方法来处理文件和目录

#导入需要的包
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
import os
import paddle.nn.functional as F
import paddle
from paddle.vision import transforms as T
print("本教程基于Paddle的版本号为:"+paddle.__version__)
本教程基于Paddle的版本号为:2.0.1

Step1:准备数据。

(1)数据集介绍MNIST数据集包含60000个训练集和10000测试数据集。分为图片和标签,图片是28*28的像素矩阵,标签为0~9共10个数字。
在这里插入图片描述

#导入数据集Compose的作用是将用于数据集预处理的接口以列表的方式进行组合。
#导入数据集Normalize的作用是图像归一化处理,支持两种方式: 1. 用统一的均值和标准差值对图像的每个通道进行归一化处理; 2. 对每个通道指定不同的均值和标准差值进行归一化处理。
from paddle.vision.transforms import Compose, Normalize
transform = Compose([Normalize(mean=[127.5],std=[127.5],data_format='CHW')])
# 使用transform对数据集做归一化
print('下载并加载训练数据') 
train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=transform)
test_dataset = paddle.vision.datasets.MNIST(mode='test', transform=transform)
print('加载完成')
#看一下数据集中的图片
train_data0, train_label_0 = train_dataset[0][0],train_dataset[0][1]
train_data0 = train_data0.reshape([28,28])
plt.figure(figsize=(2,2))
print(plt.imshow(train_data0, cmap=plt.cm.binary))
print('train_data0 的标签为: ' + str(train_label_0))

图像增强
通过一些数据增广的方式去扩充训练样本,可以增加训练样本的丰富度,提升模型的泛化性能。

下面这个流程图是图片预处理并被送进网络训练的一个过程,需要经过解码、随机裁剪、水平翻转、归一化、通道转换以及组batch,最终训练的过程。
在这里插入图片描述
1.图像变换类:图像变换类是在随机裁剪与翻转之间进行的操作,也可以认为是在原图上做的操作。主要方式包括AutoAugment和RandAugment,基于一定的策略,包括锐化、亮度变化、直方图均衡化等,对图像进行处理。这样网络在训练时就已经见过这些情况了,之后在实际预测时,即使遇到了光照变换、旋转这些很棘手的情况,网络也可以从容应对了。

2.图像裁剪类:图像裁剪类主要是在生成的在通道转换之后,在图像上设置掩码,随机遮挡,从而使得网络去学习一些非显著性的特征。否则网络一直学习很重要的显著性区域,之后在预测有遮挡的图片时,泛化能力会很差。主要方式包括:CutOut、RandErasing、HideAndSeek、GridMask。这里需要注意的是,在通道转换前后去做图像裁剪,其实是没有区别的。因为通道转换这个操作不会修改图像的像素值。

3.图像混叠类:组完batch之后,图像与图像、标签与标签之间进行混合,形成新的batch数据,然后送进网络进行训练。这也就是图像混叠类数据增广方式,主要的有Mixup与Cutmix两种方式。

这里由于数据是灰度图且格式较小,故选择随机翻转方法来做图像增广。

#导入数据集Compose的作用是将用于数据集预处理的接口以列表的方式进行组合。
#导入数据集Normalize的作用是图像归一化处理,支持两种方式: 1. 用统一的均值和标准差值对图像的每个通道进行归一化处理; 2. 对每个通道指定不同的均值和标准差值进行归一化处理。
from paddle.vision.transforms import Compose, Normalize
from paddle.vision.transforms import RandomHorizontalFlip
transform = RandomHorizontalFlip(28)
# 使用随机翻转作数据增强,以及transform对数据集做归一化
transform = Compose([RandomHorizontalFlip(28),Normalize(mean=[127.5],std=[127.5],data_format='CHW')])
print('下载并加载训练数据')
train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=transform)
test_dataset = paddle.vision.datasets.MNIST(mode='test', transform=transform)
print('加载完成')
#看一下数据图片
train_data0, train_label_0 = train_dataset[0][0],train_dataset[0][1]
train_data0 = train_data0.reshape([28,28])
plt.figure(figsize=(2,2))
print(plt.imshow(train_data0, cmap=plt.cm.binary))
print('train_data0 的标签为: ' + str(train_label_0))

Step2.网络配置

什么是模型什么是神经网络

模型
模型简单说可以理解为函数,里面大量的数据和参数组成了认知模式.
神经网络
线性神经网络 (感知机、DNN)
类似于一元函数,模拟人脑神经元的反应。
在这里插入图片描述
如上图单层的网络构成就是简单的感知机。
在这里插入图片描述
如上图由多层线性网络构成就是DNN。

实际上线性神经网络只有3层,输入层、隐藏层 、输出层 ,也就是中间的统称为隐藏层


# 定义多层感知器 
#动态图定义多层感知器
class MLPModel(paddle.nn.Layer):  # 继承paddle.nn.Layer类
    def __init__(self):
        #super(multilayer_perceptron,self).__init__()
        super(MLPModel, self).__init__()
    
        self.flatten=paddle.nn.Flatten()
        self.hidden=paddle.nn.Linear(in_features=784,out_features=128)
        self.output=paddle.nn.Linear(in_features=128,out_features=10)

    def forward(self, x):
       
        x=self.Flatten(x)
        x=self.hidden(x)
        x=F.relu(x)
        x=self.output(x)


        return x

这里搭建了3个网络模型分别为CNN,AlexNetModel,LeNetModel,通过比较发现Alexnet的参数量更多。同时最后在验证集上的准确率也是最好的。

import paddle.fluid as fluid
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, Linear
class CNN(paddle.nn.Layer):
     def __init__(self):
         super(CNN, self).__init__()
         
         # 定义卷积层,输出特征通道num_filters设置为20,卷积核的大小filter_size为5,卷积步长stride=1,padding=2
         # 激活函数使用relu
         self.conv1 = Conv2D(num_channels=1, num_filters=20, filter_size=5, stride=1, padding=2, act='relu')
         # 定义池化层,池化核pool_size=2,池化步长为2,选择最大池化方式
         self.pool1 = Pool2D(pool_size=2, pool_stride=2, pool_type='max')
         # 定义卷积层,输出特征通道num_filters设置为20,卷积核的大小filter_size为5,卷积步长stride=1,padding=2
         self.conv2 = Conv2D(num_channels=20, num_filters=20, filter_size=5, stride=1, padding=2, act='relu')
         # 定义池化层,池化核pool_size=2,池化步长为2,选择最大池化方式
         self.pool2 = Pool2D(pool_size=2, pool_stride=2, pool_type='max')
         # 定义一层全连接层,输出维度是1,不使用激活函数
         self.fc = Linear(input_dim=980, output_dim=1, act=None)

    # 定义网络前向计算过程,卷积后紧接着使用池化层,最后使用全连接层计算最终输出
     def forward(self, inputs):
         x = self.conv1(inputs)
         x = self.pool1(x)
         x = self.conv2(x)
         x = self.pool2(x)
         x = fluid.layers.reshape(x, [x.shape[0], -1])
         x = self.fc(x)
         return x

cnn = CNN()

params_info = paddle.summary(cnn, (1, 1, 28, 28))
print(params_info)
# 卷积神经网络(AlexNet)
class AlexNetModel(paddle.nn.Layer):
    def __init__(self):
        super(AlexNetModel, self).__init__()
        self.conv_pool1 = paddle.nn.Sequential(  
            paddle.nn.Conv2D(in_channels=1, out_channels=6, kernel_size=3, stride=1, padding=1),     
            paddle.nn.ReLU(),       
            paddle.nn.MaxPool2D(kernel_size=2, stride=2)) 

        self.conv_pool2 = paddle.nn.Sequential(
            paddle.nn.Conv2D(in_channels=6, out_channels=16, kernel_size=5, stride=1, padding=0), 
            paddle.nn.ReLU(),       
            paddle.nn.MaxPool2D(kernel_size=2, stride=2))    
                
        self.linear1 = paddle.nn.Linear(400, 120)
        self.linear2 = paddle.nn.Linear(120, 84)
        self.linear3 = paddle.nn.Linear(84, 10)
        self.flatten=paddle.nn.Flatten()

    def forward(self, x):  # 前向传播
        x = self.conv_pool1(x)
        x = self.conv_pool2(x)
        x = self.flatten(x)
        x = self.linear1(x)
        x = self.linear2(x)
        x = self.linear3(x)
        return x

model = AlexNetModel()
paddle.summary(model,(1, 1, 28, 28))
# 多层卷积神经网络实现
class LeNetModel(paddle.nn.Layer):
    def __init__(self):
        super(LeNetModel, self).__init__()
        # 创建卷积和池化层块,每个卷积层后面接着2x2的池化层
        #卷积层L1
        self.conv1 = paddle.nn.Conv2D(in_channels=1,
                                      out_channels=6,
                                      kernel_size=5,
                                      stride=1)
        #池化层L2
        self.pool1 = paddle.nn.MaxPool2D(kernel_size=2,
                                         stride=2)
        #卷积层L3
        self.conv2 = paddle.nn.Conv2D(in_channels=6,
                                      out_channels=16,
                                      kernel_size=5,
                                      stride=1)
        #池化层L4
        self.pool2 = paddle.nn.MaxPool2D(kernel_size=2,
                                         stride=2)
        #线性层L5
        self.fc1=paddle.nn.Linear(256,120)
        #线性层L6
        self.fc2=paddle.nn.Linear(120,84)
        #线性层L7
        self.fc3=paddle.nn.Linear(84,10)

    #正向传播过程
    def forward(self, x):
        x = self.conv1(x)
        x = F.relu(x)
        x = self.pool1(x)
        x = F.relu(x)
        x = self.conv2(x)
        x = self.pool2(x)
        x = paddle.flatten(x, start_axis=1,stop_axis=-1)
        x = self.fc1(x)
        x = F.relu(x)
        x = self.fc2(x)
        x = F.relu(x)
        out = self.fc3(x)
        return out

lenet = LeNetModel()

params_info = paddle.summary(lenet, (1, 1, 28, 28))
print(params_info)

Step3.模型的训练与评估

定义优化函数

使用SGD优化函数,效果不佳。

所以选择使用的是Adam优化方法,同时指定学习率为0.001

from paddle.metric import Accuracy
import paddle.nn.functional as F

# 用Model封装模型
model = paddle.Model(AlexNetModel())   

# 定义损失函数
optim = paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters())
#optim = paddle.optimizer.SGD(learning_rate=scheduler, parameters=model.parameters())

# 配置模型
model.prepare(optim,paddle.nn.CrossEntropyLoss(),Accuracy())

# 训练保存并验证模型
model.fit(train_dataset,test_dataset,epochs=5,batch_size=64,save_dir='multilayer_perceptron',verbose=1)

Step4.输出预测结果

#获取测试集的第一个图片
test_data0, test_label_0 = test_dataset[0][0],test_dataset[0][1]
test_data0 = test_data0.reshape([28,28])
plt.figure(figsize=(2,2))
#展示测试集中的第一个图片
print(plt.imshow(test_data0, cmap=plt.cm.binary))
print('test_data0 的标签为: ’ + str(test_label_0))
#模型预测
result = model.predict(test_dataset, batch_size=1)
#打印模型预测的结果
print(‘test_data0 预测的数值为:%d’ % np.argsort(result[0][0])[0][-1])

aistudio链接:https://aistudio.baidu.com/aistudio/projectdetail/1632322

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值