深度学习基础教程-用paddle实现-之数字识别

手写数字识别

本文是学习博客,转载自百度paddle框架的学习文档,代码自己敲了一遍,(由于python2和python3 的区别)会有一点改动。

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

代码:

from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
import paddle
import paddle.fluid as fluid

"""
我们需要设置 inference_program 函数。我们想用这个程序来演示三个不同的分类器,每个分类器都定义为 Python 函数。 
我们需要将图像数据输入到分类器中。Paddle 为读取数据提供了一个特殊的层 layer.data 层。 
让我们创建一个数据层来读取图像并将其连接到分类网络。
"""


def softmax_regression(img,label):
    """
    定义softmax分类器:
        一个一softmax为激活函数的全链接层
    :return:
        predict_image --分类结果
    """
    predict_img = fluid.layers.fc(input = img,size = 10,act = 'softmax')
    return predict_img,label


def multilayer_perception(img,label):
    """
        定义多层感知机分类器
        含有两个隐藏层(全连接层)的多层感知机
        其中钱两个隐藏层的激活函数是RULU,输出层的激活函数是softmax
    :return:
        predict_img --分类结果
    """
    # 建立第一个隐层(全链接层) ,激活函数为relu
    hidden_1 = fluid.layers.fc(input=img,size=200,act='relu')
    # 建立第二个隐层(全连接层) , 激活函数为relu
    hidden_2 = fluid.layers.fc(input=hidden_1,size=200,act='relu')
    # # 以softmax为激活函数的全连接输出层,输出层的大小必须为数字的个数10
    prediction = fluid.layers.fc(input=hidden_2,size=10,act='softmax')
    return  prediction , label


def converlutional_neural_network(img,label):
    """
    定义卷积神经网络分类器:
        输入的二维图像经过两个卷积-池化层,使用softmax为激活函数的全连接层作为输出层
    :return:
        predict --分类结果
    """

    #第一个卷积-池化层,使用20个5*5的滤波器,池化大小为2,池化步长为2,激活函数为RELU
    conv_pool_1 = fluid.nets.simple_img_conv_pool(
        input = img, # 输入数据的名称
        filter_size = 5 , #滤波器尺寸
        num_filters = 20 , #滤波器数量
        pool_size = 2,   #池化大小
        pool_stride = 2, #池化步长
        act = 'relu'
    )
    conv_pool_1 = fluid.layers.batch_norm(conv_pool_1)
    #第二个卷积-池化层,使用50个5*5的滤波器,池化大小为2,池化步长为2,激活函数为relu
    conv_pool_2 = fluid.nets.simple_img_conv_pool(
        input = conv_pool_1, #输入数据
        filter_size = 5,
        num_filters = 50,
        pool_size = 2,
        pool_stride = 2,
        act = 'relu'
    )

    prediction = fluid.layers.fc(input=conv_pool_2,size=10,act='softmax')

    return  prediction ,label


def train_progam(img,label):
    """
    配置 train_program
    :return:
    predict --分类结果
    avg_cost --平均损失
    acc      --准确率
    """
    # predict,label = softmax_regression(img,label) #取消注释将使用softmax回归
    # predict,label = multilayer_perception(img,label) #取消注释将使用多层感知机
    predict ,label = converlutional_neural_network(img,label) #取消注释将使用卷据-池化网络

    #使用交叉熵计算predit和label之间的损失函数
    cost = fluid.layers.cross_entropy(input = predict,label=label)
    avg_cost = fluid.layers.mean(cost)

    #计算分类准确率
    acc = fluid.layers.accuracy(input=predict,label=label)
    return predict, [avg_cost, acc]


def optimizer_funtion():
    """
    优化函数: Adam optimizer ,神经网络中常用的优化函数
    learning_rate 是学习率,它的大小与网络的训练收敛速度有关
    """
    return fluid.optimizer.Adam(learning_rate=0.001)


def set_Feeder():
    """
    下一步,我们开始训练过程。paddle.dataset.mnist.train()和paddle.dataset.mnist.test()分别做训练和测试数据集。这两个函数各自返回一个reader——PaddlePaddle中的reader是一个Python函数,每次调用的时候返回一个Python yield generator(生成器)。
下面shuffle是一个reader decorator,它接受一个reader A,返回另一个reader B。reader B 每次读入buffer_size条训练数据到一个buffer里,然后随机打乱其顺序,并且逐条输出。
batch是一个特殊的decorator,它的输入是一个reader,输出是一个batched reader。在PaddlePaddle里,一个reader每次yield一条训练数据,而一个batched reader每次yield一个minibatch。
    :return:
    """
    #一个minibatch中有64个数据
    BATCH_SIZE = 64

    train_reader = paddle.batch(
        paddle.reader.shuffle(
            reader=paddle.dataset.mnist.train(), #下载训练集,一个一次只能yield一条数的生成器
            buf_size= 500                  #读取500条数据后打乱顺序再《逐条》输出
        ),
        batch_size = BATCH_SIZE          #把逐条得到的数据,每64个作为以后minibatch输出
    )

    test_reader = paddle.batch(
        reader=paddle.dataset.mnist.test(),  # 下载训练集,一个一次只能yield一条数的生成器,
        batch_size = BATCH_SIZE  # 把逐条得到的数据,每64个作为以后minibatch输出
    )
    return train_reader ,test_reader


def event_haddle(pass_id,batch_id,cost):
    # 打印训练的中间结果,训练轮次,batch数,损失函数
    print("Pass_id: %d, Batch_id_ %d, Cost: %f" % (pass_id, batch_id, cost))


def event_haddle_plot():
    #将训练过程绘图表示
    from paddle.utils.plot import Ploter

    train_prompt = "Train cost"
    test_prompt = "Test cost"
    cost_ploter = Ploter(train_prompt, test_prompt)

    # cost_ploter.append(ploter_title, step, cost)
    # cost_ploter.plot()
    # pass


def train_test(train_test_program,train_test_feed,train_test_reader,exe,avg_cost,acc):
    #将分类准确率存在acc_set中
    acc_set = []
    # 将平均损失存储在avg_loss_set中
    avg_loss_set = []
    # 将测试 reader yield 出的每一个数据传入网络中进行训练
    for test_data in train_test_reader():
         avg_loss_np ,acc_np= exe.run(
            program = train_test_program,
            feed = train_test_feed.feed(test_data),
            fetch_list = [avg_cost,acc]
        )

    acc_set.append(float(acc_np))
    avg_loss_set.append(float(avg_loss_np))
    # 获得测试数据上的准确率和损失值
    acc_val_mean = np.array(acc_set).mean()
    avg_loss_val_mean = np.array(avg_loss_set).mean()
    # 返回平均损失值,平均准确率
    return avg_loss_val_mean, acc_val_mean


def main(save_dirname):
    # 获取数据
    train_reader, test_reader = set_Feeder()
    # 输入原始图像数据,大小为28*28*1
    img = fluid.layers.data(name='img', shape=[1, 28, 28], dtype='float32')
    # 标签层,名称为label,对应输入图片的类别标签
    label = fluid.layers.data(name='label', shape=[1], dtype='int64')

    #定义损失函数、准确率、和预测算法
    predict, [avg_cost, acc] = train_progam(img,label)

    #定义优化函数,传入损失
    optimizer = optimizer_funtion()
    optimizer.minimize(avg_cost)

    #初始化参数
    place = fluid.CPUPlace()
    exe = fluid.Executor(place)
    exe.run(fluid.default_startup_program())
    main_program = fluid.default_main_program()
    # test_program = main_program.clone(for_test=True)

    # 设置数据输入器
    feeder = fluid.DataFeeder(feed_list=[img, label], place=place)

    #设置训练过程的超参
    PASS_NUM = 5
    epochs = [epoch_id for epoch_id in range(PASS_NUM)]



    #创建执行器
    lists = []
    step = 0
    for epoch_id in epochs:
        for step_id , data in enumerate(train_reader()):
            metrics = exe.run(
                program = main_program,
                feed = feeder.feed(data),
                fetch_list=[avg_cost,acc]
            )
            if step % 100 ==0:  #每训练100次打印一次log
                print("step =  %d ; epoch_num = %d ; Cost =  %f ; acc = %f" % (step, epoch_id, metrics[0] , metrics[1]))

            step += 1

        # 测试每个epoch的分类效果
        avg_loss_val, acc_val = train_test(train_test_program = main_program,
                                           train_test_reader = test_reader,
                                           train_test_feed = feeder,
                                           exe = exe,
                                           avg_cost = avg_cost,
                                           acc=acc)
        print("Test with Epoch %d, avg_cost: %s, acc: %s" % (epoch_id, avg_loss_val, acc_val))
        # event_handler_plot(test_prompt, step, metrics[0])
        lists.append((epoch_id, avg_loss_val, acc_val))

        #保存训练好的模型进行预测
        if save_dirname is not None:
            fluid.io.save_inference_model(
                dirname=save_dirname,
                feeded_var_names=['img'],
                target_vars = [predict],
                executor = exe,
            )


def inference(save_dirname,im):
    place = fluid.CPUPlace()
    exe = fluid.Executor(place)
    inference_scope = fluid.core.Scope()
    with fluid.scope_guard(inference_scope):
        """
        使用 fluid.io.load_inference_model 获取 inference program desc,
        feed_target_names 用于指定需要传入网络的变量名
        fetch_targets 指定希望从网络中fetch出的变量名
        """

        [inference_program, feed_target_names,
         fetch_targets] = fluid.io.load_inference_model(
            save_dirname, exe, None, None)
        # 将feed构建成字典 {feed_target_name: feed_target_data}
        # 结果将包含一个与fetch_targets对应的数据列表
        print("feed_target_names:",feed_target_names)
        results = exe.run(
            program = inference_program,
            feed = {feed_target_names[0]:im},
            fetch_list = fetch_targets
        )

        print("results:",results)
        lab = np.argsort(results)
        print("lab = ",lab)


        return lab







def load_test_image(file):
    """读取自己手写数字的图片"""
    im = Image.open(file).convert('L')
    im = im.resize((28, 28), Image.ANTIALIAS)
    im = np.array(im).reshape(1, 1, 28, 28).astype(np.float32)
    im = im / 255.0 * 2.0 - 1.0
    return im



if __name__ == '__main__':
    save_dirname = r"result_train\recognize_digits.inference.model"
    #训练模型,储存model
    # main(save_dirname)

    #读取自己手写的数字图片
    file_im = r'traindata\image_cecognition\infer_8.png'
    im = load_test_image(file_im)

    # 对手写图片进行预测
    lab = inference(save_dirname,im)

    print("Inference result of image/infer_{}.png is: {}".format(file_im[-11:],lab[0][0][0]) ) #这里原文是[0][0][-1]是错的,选出来交叉熵最大的数,应该用[0][0][0]选交叉熵最小的数是预测结构。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值