paddlepaddle学习日志01手写数字识别

paddlepaddle学习日志01手写数字识别

前言

学习的课程为百度AI Studio上的百度架构师手把手教深度学习

导入库

import paddle
import paddle.fluid as fluid
from paddle.fluid.dygraph.nn import Linear, Conv2D, Pool2D
import numpy as np
import os
import gzip
import json
import random
from PIL import Image
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import cv2

数据处理

def load_data(mode='train'):
    datafile = 'mnist.json.gz'
    print('loading mnist dataset from {} ......'.format(datafile))
    # 加载json数据文件
    data = json.load(gzip.open(datafile))
    print('mnist dataset load done')
    # 将读取到的数据区分为训练集,验证集,测试集
    train_set, val_set, eval_set = data
    if mode == "train":
        imgs, labels = train_set[0], train_set[1]
    elif mode == "valid":
        imgs, labels = val_set[0], val_set[1]
    elif mode == "eval":
        imgs, labels = eval_set[0], eval_set[1]
    else:
        raise Exception("mode can only be one of ['train', 'valid', 'eval']")
    print("训练数据集数量:", len(imgs))
    # 数据集相关参数
    IMG_ROWS = 28
    IMG_COLS = 28
    # # 打印数据信息
    # imgs, labels = train_set[0], train_set[1]
    # print("训练数据集数量:", len(imgs))
    # imgs, labels = val_set[0], val_set[1]
    # print("验证数据集数量:", len(imgs))
    # imgs, labels = eval_set[0], eval_set[1]
    # print("测试数据集数量:", len(imgs))
    # imgs, labels = train_set[0], train_set[1]
    # print("训练数据集数量:", len(imgs))
    # 校验数据
    imgs_length = len(imgs)
    # 机器校验
    assert len(imgs) == len(labels), \
        "length of train_imgs({}) should be the same as train_labels({})".format(len(imgs), len(labels))
    # 定义数据集每个数据的序号,根据序号读取数据
    index_list = list(range(imgs_length))
    # 定义批次长度
    BATCHSIZE = 100
    # # 随机打乱训练数据的索引序号
    # random.shuffle(index_list)

    # 定义数据生成器,返回批次数据
    def data_generator():
        if mode == "train":
            # 训练模式下打乱数据
            random.shuffle(index_list)
        imgs_list = []
        labels_list = []
        for i in index_list:
            # 处理数据格式
            img = np.reshape(imgs[i], [1, IMG_ROWS, IMG_COLS]).astype('float32')
            label = np.reshape(labels[i], [1]).astype('int64')
            imgs_list.append(img)
            labels_list.append(label)
            if len(imgs_list) == BATCHSIZE:
                yield np.array(imgs_list), np.array(labels_list)
                imgs_list = []
                labels_list = []
        if len(imgs_list) > 0:
            yield np.array(imgs_list), np.array(labels_list)
        return data_generator
    train_loader = data_generator
    return train_loader

模型设计

# 多层卷积神经网络实现
class MNIST(fluid.dygraph.Layer):
    def __init__(self):
        super(MNIST, 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,卷积步长steride=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=10, act='softmax')

    # 定义网络前向计算过程,卷积后紧接着使用池化层,最后使用全连接层计算最终输出
    # 加入对每一层输入和输出的尺寸和数据内容的打印,根据check参数决策是否打印每层的参数和输出尺寸
    def forward(self, inputs, label=None, check_shape=False, check_content=False):
        # 给不同层的输出不同命名,方便调试
        outputs1 = self.conv1(inputs)
        outputs2 = self.pool1(outputs1)
        outputs3 = self.conv2(outputs2)
        outputs4 = self.pool2(outputs3)
        _outputs4 = fluid.layers.reshape(outputs4, [outputs4.shape[0], -1])
        outputs5 = self.fc(_outputs4)

        # 选择是否打印神经网络每层的参数尺寸和输出尺寸,验证网络结构是否设置正确
        if check_shape:
            # 打印每层网络设置的超参数-卷积核尺寸,卷积步长,卷积padding,池化核尺寸
            print("\n########## print network layer's superparams ##########")
            print("conv1-- kernel_size:{}, padding:{}, stride:{}".
                  format(self.conv1.weight.shape, self.conv1._padding, self.conv1._stride))
            print("conv2-- kernel_size:{}, padding:{}, stride:{}".
                  format(self.conv2.weight.shape, self.conv2._padding, self.conv2._stride))
            print("pool1-- pool_type:{}, pool_size:{}, pool_stride:{}".
                  format(self.pool1._pool_type, self.pool1._pool_size, self.pool1._pool_stride))
            print("pool2-- pool_type:{}, pool2_size:{}, pool_stride:{}".
                  format(self.pool2._pool_type, self.pool2._pool_size, self.pool2._pool_stride))
            print("fc-- weight_size:{}, bias_size_{}, activation:{}".
                  format(self.fc.weight.shape, self.fc.bias.shape, self.fc._act))

            # 打印每层的输出尺寸
            print("\n########## print shape of features of every layer ##########")
            print("inputs_shape:{}".format(inputs.shape))
            print("outputs1_shape:{}".format(outputs1.shape))
            print("outputs2_shape:{}".format(outputs2.shape))
            print("outputs3_shape:{}".format(outputs3.shape))
            print("outputs4_shape:{}".format(outputs4.shape))
            print("outputs5_shape:{}".format(outputs5.shape))

        # 选择是否打印训练过程中的参数和输出内容,可用于训练过程中的调试
        if check_content:
            print("\n########## print convolution layer's kernel ##########")
            print("conv1 params -- kernel weights:", self.conv1.weight[0][0])
            print("conv2 params -- kernel weights:", self.conv2.weight[0][0])
            # 创建随机数,随机打印某一个通道的输出值
            idx1 = np.random.randint(0, outputs1.shape[1])
            idx2 = np.random.randint(0, outputs3.shape[1])
            # 打印卷积-池化后的结果,仅打印batch中第一个图像对应的特征
            print("\nThe {}th channel of conv1 layer:".format(idx1), outputs1[0][idx1])
            print("The {}th channel of conv2 layer:".format(idx2), outputs3[0][idx2])
            print("The output of last layer:", outputs2[0], '\n')

        # 如果label不是None,则计算分类精度并返回
        if label is not None:
            acc = fluid.layers.accuracy(input=outputs5, label=label)
            return outputs5, acc
        else:
            return outputs5

训练配置

# 定义数据读取后存放的位置,CPU或者GPU
# place = fluid.CUDAPlace(0)时,数据读取到GPU上
# place = fluid.CPUPlace()时,数据读取到CPU上
place = fluid.CUDPlace(0) if use_gpu else fluid.CPUPlace()
# 定义飞桨动态图工作环境
with fluid.dygraph.guard(place):
    # 声明网络结构
    model = MNIST()
    # 启动训练模式
    model.train()
    # 定义数据读取函数,数据读取batch_size设置为16
    train_loader = load_data('train')
    # 定义DataLoader对象用于加载Python生成器产生的数据
    data_loader = fluid.io.DataLoader.from_generator(capacity=5, return_list=True)
    # 设置数据生成器
    data_loader.set_batch_generator(train_loader, places=place)

    # 定义优化器,不同的优化算法模型
    # # SGD随机梯度下降算法
    # optimizer = fluid.optimizer.SGDOptimizer(learning_rate=0.01, parameter_list=model.parameters())
    # # Momentum动量算法
    # optimizer = fluid.optimizer.MomentumOptimizer(learning_rate=0.01, momentum=0.9, parameter_list=model.parameters())
    # # AdaGrad自适应学习率算法
    # optimizer = fluid.optimizer.AdagradOptimizer(learning_rate=0.01, parameter_list=model.parameters())
    # Adam优化算法
    # optimizer = fluid.optimizer.AdamOptimizer(learning_rate=0.01, parameter_list=model.parameters())

    # 各种优化算法均可加入正则化项,避免过拟合,参数regularization_coeff调节正则化项的权重(以Adam为例)
    optimizer = fluid.optimizer.SGDOptimizer(learning_rate=0.01,
                                              regularization=fluid.regularizer.L2Decay(regularization_coeff=0.1),
                                              parameter_list=model.parameters())

训练过程

# 声明批次编号和训练损失
iters = []
losses = []

EPOCH_NUM = 5
for epoch_id in range(EPOCH_NUM):
    for batch_id, data in enumerate(train_loader()):
        # image_data = np.array([x[0] for x in data]).astype('float32')
        # label_data = np.array([x[1] for x in data]).astype('float32').reshape(-1, 1)
        # 准备数据
        image_data, label_data = data
        # 将数据转为飞桨动态图格式
        image = fluid.dygraph.to_variable(image_data)
        label = fluid.dygraph.to_variable(label_data)
        # 前向计算,同时拿到模型输出值和分类正确率
        predict, acc = model(image, label)
        # if batch_id == 0 and epoch_id == 0:
        #     # 打印模型参数和每层输出的尺寸
        #     predict, acc = model(image, label, check_shape=True, check_content=False)
        # elif batch_id == 401:
        #     # 打印模型参数和每层输出的值
        #     predict, acc = model(image, label, check_shape=False, check_content=True)
        # else:
        #     predict, acc = model(image, label)

        # 计算损失,使用交叉熵损失函数,取一个批次样本损失的平均值
        loss = fluid.layers.cross_entropy(predict, label)
        avg_loss = fluid.layers.mean(loss)

        # 累计迭代次数和对应的loss
        iters.append(batch_id + epoch_id * len(list(train_loader())))
        losses.append(avg_loss)

        # 打印Loss的情况
        if batch_id % 200 == 0:
            print("epoch: {}, batch: {}, loss is: {}".format(epoch_id, batch_id, avg_loss.numpy(), acc.numpy()))
        # 后向传播,更新参数
        avg_loss.backward()
        optimizer.minimize(avg_loss)
        model.clear_gradients()
# 保存模型
fluid.save_dygraph(model.state_dict(), 'mnist')
print("Model has been saved.")

校验

with fluid.dygraph.guard():
    print('star evaluation ......')
    # 加载模型参数
    model = MNIST()
    model_state_dict, _ = fluid.load_dygraph('mnist')
    model.load_dict(model_state_dict)

    model.eval()
    eval_loader = load_data('eval')

    acc_set = []
    avg_loss_set = []
    for batch_id, data in enumerate(eval_loader()):
        x_data, y_data = data
        img = fluid.dygraph.to_variable(x_data)
        label = fluid.dygraph.to_variable(y_data)
        prediction, acc = model(img, label)
        loss = fluid.layers.cross_entropy(input=prediction, label=label)
        avg_loss = fluid.layers.mean(loss)
        acc_set.append(float(acc.numpy()))
        avg_loss_set.append(float(avg_loss.numpy()))

    # 计算多个batch的平均损失和准确率
    acc_val_mean = np.array(acc_set).mean()
    avg_loss_val_mean = np.array(avg_loss_set).mean()

    print('loss={}, acc={}'.format(avg_loss_val_mean, acc_val_mean))

可视化

# Matplotlib
plt.figure()
plt.title("train loss", fontsize=24)
plt.xlabel("iter", fontsize=14)
plt.ylabel("loss", fontsize=14)
plt.plot(iters, losses, color='red', label='train loss')
plt.grid()
plt.show()
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青右

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值