飞桨课程项目学习-手写数字识别笔记

特别注明:本文内容包括但不限于代码,图片均来自AI Studio 官网课程中

一个完整的深度学习模型一般包含以下几个内容:

  • 数据获取与处理
  • 模型设计:网络结构和损失函数
  • 训练配置:优化器与资源配置
  • 训练过程
  • 模型保存与测试

下面以手写数字识别项目为例展开讲解:

数据获取与处理
本次学习使用百度提供的公开的数据集,因此自行获取数据的过程暂不涉及。
飞桨提供了多个封装好的数据集API,涵盖计算机视觉、自然语言处理、推荐系统等多个领域,帮助读者快速完成机器学习任务。如在手写数字识别任务中,通过paddle.dataset.mnist可以直接获取处理好的MNIST训练集、测试集,飞桨API支持如下常见的学术数据集:

  • mnist
  • cifar
  • Conll05
  • imdb
  • imikolov
  • movielens
  • sentiment
  • uci_
  • housing
  • wmt14
  • wmt16
    通过paddle.dataset.mnist.train()函数设置数据读取器,batch_size设置为8,即一个批次有8张图片和8个标签,代码如下所示。
import paddle
# 如果~/.cache/paddle/dataset/mnist/目录下没有MNIST数据,API会自动将MINST数据下载到该文件夹下
# 设置数据读取器,读取MNIST数据训练集
trainset = paddle.dataset.mnist.train()
# 包装数据读取器,每次读取的数据数量设置为batch_size=8
train_reader = paddle.batch(trainset, batch_size=8)

我们通过调用飞桨提供的API(paddle.dataset.mnist)加载MNIST数据集。但在工业实践中,我们面临的任务和数据环境千差万别,通常需要自己编写适合当前任务的数据处理程序,一般涉及如下五个环节:

  • 读入数据
  • 划分数据集
  • 生成批次数据
  • 训练样本集乱序
  • 校验数据有效性
#数据处理部分之前的代码,加入部分数据处理的库
import paddle
import paddle.fluid as fluid
from paddle.fluid.dygraph.nn import Linear
import numpy as np
import os
import gzip
import json
import random

在实际应用中,保存到本地的数据存储格式多种多样,如MNIST数据集以json格式存储在本地,其数据存储结构如 图2 所示。
在这里插入图片描述
在本地./work/目录下读取文件名称为mnist.json.gz的MINST数据,并拆分成训练集、验证集和测试集,实现方法如下所示。

def load_data(mode='train'):
    datafile = './work/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))
    
    # 校验数据
    imgs_length = len(imgs)

    assert len(imgs) == len(labels), \
          "length of train_imgs({}) should be the same as train_labels({})".format(len(imgs), len(label))
    
    # 获得数据集长度
    imgs_length = len(imgs)
    
    # 定义数据集每个数据的序号,根据序号读取数据
    index_list = list(range(imgs_length))
    # 读入数据时用到的批次大小
    BATCHSIZE = 100
    
    # 定义数据生成器
    def data_generator():
        if mode == 'train':
            # 训练模式下打乱数据
            random.shuffle(index_list)
        imgs_list = []
        labels_list = []
        for i in index_list:
            # 将数据处理成希望的格式,比如类型为float32,shape为[1, 28, 28]
            img = np.reshape(imgs[i], [1, IMG_ROWS, IMG_COLS]).astype('float32')
            label = np.reshape(labels[i], [1]).astype('float32')
            imgs_list.append(img) 
            labels_list.append(label)
            if len(imgs_list) == BATCHSIZE:
                # 获得一个batchsize的数据,并返回
                yield np.array(imgs_list), np.array(labels_list)
                # 清空数据读取列表
                imgs_list = []
                labels_list = []
    
        # 如果剩余数据的数目小于BATCHSIZE,
        # 则剩余数据一起构成一个大小为len(imgs_list)的mini-batch
        if len(imgs_list) > 0:
            yield np.array(imgs_list), np.array(labels_list)
    return data_generator

模型设计之网络结构:完成网络结构类的编写,包含__init__()函数和前向计算函数forward()
下面以经典的全连接神经网络为例:
在这里插入图片描述

# 多层全连接神经网络实现
class MNIST(fluid.dygraph.Layer):
    def __init__(self):
        super(MNIST, self).__init__()
        # 定义两层全连接隐含层,输出维度是10,激活函数为sigmoid
        self.fc1 = Linear(input_dim=784, output_dim=10, act='sigmoid') # 隐含层节点为10,可根据任务调整
        self.fc2 = Linear(input_dim=10, output_dim=10, act='sigmoid')
        # 定义一层全连接输出层,输出维度是1,不使用激活函数
        self.fc3 = Linear(input_dim=10, output_dim=1, act=None)
    
    # 定义网络的前向计算
    def forward(self, inputs, label=None):
        inputs = fluid.layers.reshape(inputs, [inputs.shape[0], 784])
        outputs1 = self.fc1(inputs)
        outputs2 = self.fc2(outputs1)
        outputs_final = self.fc3(outputs2)
        return outputs_final

模型设计之损失函数:均方误差常用于回归问题,对于分类问题人们比较习惯于使用交叉熵误差。交叉熵损失函数的设计是基于最大似然思想:最大概率得到观察结果的假设是真的。
softmax函数:又名归一化指数函数,实际是sigmoid函数二分类问题到多分类的推广。能够将多个输出转化为对应的概率,且概率和为1,具体可以参考一分钟理解softmax函数(超简单)
交叉熵损失函数:loss = -ln(对应正确解的输出概率)

用交叉熵作为损失函数时需要改变部分代码:

  • 数据处理部分,将标签改为int64(飞桨框架默认将标签处理成int64)
  • 网络结构部分,输出层改为self.fc = Linear(input_dim=980, output_dim=1, act=‘softmax’)
  • 训练过程,损失函数设置loss = fluid.layers.cross_entropy(predict, label)

训练配置:优化器,资源配置

  • 优化器:找到一个合适的学习率以使训练效果最佳

    学习率是优化器的一个参数,调整学习率看似是一件非常麻烦的事情,需要不断的调整步长,观察训练时间和Loss的变化。经过研究员的不断的实验,当前已经形成了四种比较成熟的优化算法:SGD、Momentum、AdaGrad和Adam,每种优化算法均有更多的参数设置,详情可查阅飞桨的官方API文档

  • 资源配置:多级多卡训练,分布式训练(模型并行,数据并行)

训练过程:可视化分析,校验等

  • 过拟合:
    情况1:训练数据存在噪音,导致模型学到了噪音,而不是真实规律。
    情况2:使用强大模型(表示空间大)的同时训练数据太少,导致在训练数据上表现良好的候选假设太多,锁定了一个“虚假正确”的假设。

    对于情况1,我们使用数据清洗和修正来解决。 对于情况2,我们或者限制模型表示能力,或者收集更多的训练数据。

    而清洗训练数据中的错误,或收集更多的训练数据往往是一句“正确的废话”,在任何时候我们都想获得更多更高质量的数据。在实际项目中,更快、更低成本可控制过拟合的方法,只有限制模型的表示能力。

模型测试
模型测试需要注意的方放就是,测试的数据同样要转化为飞桨tensor变量 传入模型才能正常进行工作,并且转化为飞桨tensor变量之前,要先将数据转化为网络期待接受的格式。

# 读取一张本地的样例图片,转变成模型输入的格式
def load_image(img_path):
    # 从img_path中读取图像,并转为灰度图
    im = Image.open(img_path).convert('L')
    im.show()
    im = im.resize((28, 28), Image.ANTIALIAS)
    im = np.array(im).reshape(1, 1, 28, 28).astype(np.float32)
    # 图像归一化
    im = 1.0 - im / 255.
    return im

# 定义预测过程
with fluid.dygraph.guard():
    model = MNIST()
    params_file_path = 'mnist'
    img_path = './work/example_0.jpg'
    # 加载模型参数
    model_dict, _ = fluid.load_dygraph("mnist")
    model.load_dict(model_dict)
    
    model.eval()
    tensor_img = load_image(img_path)
    #模型反馈10个分类标签的对应概率
    results = model(fluid.dygraph.to_variable(tensor_img))
    #取概率最大的标签作为预测输出
    lab = np.argsort(results.numpy())
    print("本次预测的数字是: ", lab[0][-1])

刚刚接触深度学习与paddle框架,还有很多不懂的地方,再接再厉!

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于全连接神经网络手写数字识别项目的代码示例: ```python import numpy as np import matplotlib.pyplot as plt import tensorflow as tf from keras.datasets import mnist # 加载 MNIST 数据集 (x_train, y_train), (x_test, y_test) = mnist.load_data() # 数据预处理 x_train = x_train / 255.0 x_test = x_test / 255.0 x_train = x_train.reshape(-1, 784) x_test = x_test.reshape(-1, 784) y_train = tf.keras.utils.to_categorical(y_train, 10) y_test = tf.keras.utils.to_categorical(y_test, 10) # 定义模型 model = tf.keras.models.Sequential([ tf.keras.layers.Dense(128, activation='relu', input_shape=(784,)), tf.keras.layers.Dense(10, activation='softmax') ]) # 编译模型 model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) # 训练模型 model.fit(x_train, y_train, epochs=10, validation_data=(x_test, y_test)) # 评估模型 test_loss, test_acc = model.evaluate(x_test, y_test) print('Test accuracy:', test_acc) # 使用模型进行预测 predictions = model.predict(x_test) ``` 这个代码使用了 TensorFlow 和 Keras 库来构建和训练模型,使用 MNIST 数据集进行手写数字识别。模型由两个全连接层组成,其中第一个层包含 128 个神经元,使用 ReLU 激活函数,第二个层包含 10 个神经元,使用 softmax 激活函数。模型使用交叉熵损失函数进行优化,在训练过程中使用了验证集进行评估。最后,模型评估了在测试集上的准确率,并使用模型进行了预测。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值