新手入门第一课,什么是深度学习

初识神经网络

我们这里要解决的问题是,将手写数字的灰度图像(28 像素×28 像素)划分到 10 个类别 中(0~9)。我们将使用 MNIST 数据集,这个数据集包含 60 000 张训练图像和 10 000 张测试图 像。

Step1:准备数据

1.MINIST数据集包含60000个训练集和10000测试数据集。分为图片和标签,图片是28*28的像素矩阵,标签为0~9共10个数字。 2.定义读取MNIST数据集的train_reader和test_reader,指定一个Batch的大小为128,也就是一次训练或验证128张图像。 3.paddle.dataset.mnist.train()或test()接口已经为我们对图片进行了灰度处理、归一化、居中处理等处理。

#导入需要的包
import numpy as np    
import paddle as paddle
import paddle.fluid as fluid
from PIL import Image   #调用图像处理库,包含图像类
import matplotlib.pyplot as plt
import os

train_reader = paddle.batch(paddle.reader.shuffle(paddle.dataset.mnist.train(),
                                                  buf_size=512),
                    batch_size=128)
#train_reader是用于训练的数据提供器
test_reader = paddle.batch(paddle.dataset.mnist.test(),
                           batch_size=128)
#test_reader是用于测试的数据提供器
#paddle.batch()表示每batch_size组成一个batch

补充注释:

  1. numpy:Python的一种开源的数值计算扩展包,as的意思是在导入后为了方便起的别名。
  2. paddle是一种深度学习框架,在其中使用fluid.data创建数据变量。   
    import paddle.fluid as fluid
    
    # 定义一个数据类型为int64的二维数据变量x,x第一维的维度为3,第二个维度未知,要在程序执行过程中才能确定,因此x的形状可以指定为[3, None]
    x = fluid.data(name="x", shape=[3, None], dtype="int64")
    
    # 大多数网络都会采用batch方式进行数据组织,batch大小在定义时不确定,因此batch所在维度(通常是第一维)可以指定为None
    batched_x = fluid.data(name="batched_x", shape=[None, 3, None], dtype='int64')
    

    使用fluid.layers.fill_constant来创建常量 

    import paddle.fluid as fluid
    data = fluid.layers.fill_constant(shape=[3, 4], value=16, dtype='int64')
    

                                                                              

  3. Matplotlib.plt是面向对象的绘图

  4. PaddlePaddle提供了读取MINST训练集和测试集的接口分别为paddle.dataset.mnist.train()paddle.dataset.mnist.test()。paddle.reader.shuffle()表示每次缓存BUF_SIZE个数据项,并进行打乱。

打印一下,观察一下mnist数据集

temp_reader = paddle.batch(paddle.dataset.mnist.train(),
                           batch_size=1)
temp_data=next(temp_reader())#将28*28的手写数字数据图像转换成向量形式存储,得到784的向量
print(temp_data)

Step2:配置网络

以下的代码就是定义一个简单的多层感知器,一共有三层,两个大小为100的隐藏层和一个大小为10的输出层,因为MNIST数据集是手写0到9的灰度图像,类别有10个,所以最后的输出大小是10。最后输出层的激活函数是Softmax,所以最后的输出层相当于一个分类器。加上一个输入层的话,多层感知器的结构是:输入层-->>隐层-->>隐层-->>输出层。                                                    

# 定义多层感知器
def multilayer_perceptron(input):
    # 第一个全连接层,激活函数为ReLU
    hidden1 = fluid.layers.fc(input=input, size=100, act='relu') #在神经网络中构建一个全连接层
    # 第二个全连接层,激活函数为ReLU
    hidden2 = fluid.layers.fc(input=hidden1, size=100, act='relu')
    # 以softmax为激活函数的全连接输出层,大小为10
    prediction = fluid.layers.fc(input=hidden2, size=10, act='softmax')
    return prediction

 定义输入层,输入的是图像数据。图像是28*28的灰度图,所以输入的形状是[1, 28, 28],如果图像是32*32的彩色图,那么输入的形状是[3. 32, 32],因为灰度图只有一个通道,而彩色图有RGB三个通道。

# 定义输入输出层
image = fluid.layers.data(name='image', shape=[1, 28, 28], dtype='float32')  #单通道,28*28像素值
label = fluid.layers.data(name='label', shape=[1], dtype='int64')            #图片标签

补充注释:

  1. 关于paddle.fluid.data

paddle.fluid.data()是一个OP(算子),作用就是创建一个全局变量,可供计算图中的算子访问,可作为占位符用于数据输入。
name 是paddle.fluid.data()创建的全局变量的名字,是输入层输出的前缀标识。   
shape 声明了paddle.fluid.data()创建的全局变量的维度信息。  
shape中的None 表示不确定该维的元素数量,待程序执行中确定。  
shape中的-1 只能在shape的最前面,表示可以适应任何 batch size  
dtype 是paddle.fluid.data()创建的全局变量的数据类型,支 持 bool,float16,float32,float64,int8,int16,int32,int64。   
用户 feed 的数据必须与 paddle.fluid.data() 创建的变量具有相同的 shape ,虽然feed的数据,其类型是unsigned Byte,但softmax 回归是要进行浮点运算的,所以数据类型都转换成了float32 

2.关于paddle.fluid.layers.fc

paddle.fluid.layers.fc()是一个OP,作用就是建立一个全连接层。为每个输入的Tensor创建一个权重变量,即一个从每个输入单元到每个输出单元的全连接权重矩阵。  
FC层将每个输入Tensor和其对应的权重(weights)相乘得到shape为 [M,size] 输出Tensor,其中 M 为batch_size大小。如果有多个输入Tensor,则多个shape为 [M,size] 的Tensor计算结果会被累加起来,作为最终输出。


在这里调用定义好的网络来获取分类器:

# 获取分类器
model = multilayer_perceptron(image)

接着是定义损失函数,这次使用的是交叉熵损失函数,该函数在分类任务上比较常用。定义了一个损失函数之后,还有对它求平均值,因为定义的是一个Batch的损失值。同时我们还可以定义一个准确率函数,这个可以在我们训练的时候输出分类的准确率。

# 获取损失函数和准确率函数
cost = fluid.layers.cross_entropy(input=model, label=label)  #使用交叉熵损失函数,描述真实样本标签和预测概率之间的差值
#一个样本的损失
avg_cost = fluid.layers.mean(cost)
#一个batch的平均损失
acc = fluid.layers.accuracy(input=model, label=label)

 接着是定义优化方法,这次我们使用的是Adam优化方法,同时指定学习率为0.001。

# 定义优化方法
optimizer = fluid.optimizer.AdamOptimizer(learning_rate=0.001)   #使用Adam算法进行优化
opts = optimizer.minimize(avg_cost)

Step3:模型训练 & STEP4:模型评估

接着也是定义一个解析器和初始化参数

# 定义一个使用CPU的解析器
place = fluid.CPUPlace()
exe = fluid.Executor(place)
# 进行参数初始化
exe.run(fluid.default_startup_program())

补充注释:

  1. 当使用CPUPlace()时使用的是CPU,如果是CUDAPlace()使用的是GPU。 
  2. 只有解析器才能执行Program。program默认一共有两个,分别是default_startup_program()和default_main_program()
  3. default_startup_program()定义了模型参数初始化,优化器参数初始化,reader初始化等各种操作。
  4. default_main_program()定义了神经网络模型,前向反向计算,以及模型参数更新,优化器参数更新等各种操作。

输入的数据维度是图像数据和图像对应的标签,每个类别的图像都要对应一个标签,这个标签是从0递增的整型数值。

# 定义输入数据维度
feeder = fluid.DataFeeder(place=place, feed_list=[image, label])
#place 参数表示应将Python端传入的numpy array等数据转换为GPU端或是CPU端的LoDTensor.
#feed_list参数为变量列表
#datafeeder进行数据格式转换

最后就可以开始训练了,我们这次训练5个Pass。在上面我们已经定义了一个求准确率的函数,所以我们在训练的时候让它输出当前的准确率,计算准确率的原理很简单,就是把训练是预测的结果和真实的值比较,求出准确率。每一个Pass训练结束之后,再进行一次测试,使用测试集进行测试,并求出当前的Cost和准确率的平均值。

# 开始训练和测试
for pass_id in range(5):  #  pass_id为0到4
    # 进行训练
    for batch_id, data in enumerate(train_reader()):                        #遍历train_reader
        train_cost, train_acc = exe.run(program=fluid.default_main_program(),#运行主程序
                                        feed=feeder.feed(data),             #给模型喂入数据
                                        fetch_list=[avg_cost, acc])         #fetch 误差、准确率, #fetch_list是用户想得到的变量或命名的结果
        # 每100个批次打印一次信息  误差、准确率
        if batch_id % 100 == 0:
            print('Pass:%d, Batch:%d, Cost:%0.5f, Accuracy:%0.5f' %
                  (pass_id, batch_id, train_cost[0], train_acc[0]))

    # 进行测试
    test_accs = []
    test_costs = []
    #每训练一轮 进行一次测试
    for batch_id, data in enumerate(test_reader()):                         #遍历test_reader
        test_cost, test_acc = exe.run(program=fluid.default_main_program(), #执行训练程序
                                      feed=feeder.feed(data),               #喂入数据
                                      fetch_list=[avg_cost, acc])           #fetch 误差、准确率
        test_accs.append(test_acc[0])                                       #记录每个batch的准确率
        test_costs.append(test_cost[0])                                     #记录每个batch的误差
    # 求测试结果的平均值
    test_cost = (sum(test_costs) / len(test_costs))                         #每轮的平均误差
    test_acc = (sum(test_accs) / len(test_accs))                            #每轮的平均准确率
    print('Test:%d, Cost:%0.5f, Accuracy:%0.5f' % (pass_id, test_cost, test_acc))
    
    #保存模型
    model_save_dir = "/home/aistudio/data/hand.inference.model"
    # 如果保存路径不存在就创建
    if not os.path.exists(model_save_dir):
        os.makedirs(model_save_dir)
    print ('save models to %s' % (model_save_dir))
    fluid.io.save_inference_model(model_save_dir,  #保存推理model的路径
                                  ['image'],      #推理(inference)需要 feed 的数据
                                  [model],        #保存推理(inference)结果的 Variables
                                  exe)            #executor 保存 inference model

 补充注释:

  1. for i,b... in enumeraate(a) 方式需要同时对i,b两个变量同时赋值,i赋值为a当前元素下表,b赋值为a当前元素。
  2. paddle.fluid.io.save_inference_model(dirname, feeded_var_names, target_vars, executor, main_program=None, model_filename=None, params_filename=None, export_for_deployment=True, program_only=False)
  3. append在列表末尾添加新的对象,会修改原来列表。

Step5:模型预测

在预测之前,要对图像进行预处理,处理方式要跟训练的时候一样。首先进行灰度化,然后压缩图像大小为28*28,接着将图像转换成一维向量,最后再对一维向量进行归一化处理。

# 对图片进行预处理
def load_image(file):
    im = Image.open(file).convert('L')                        #将RGB转化为灰度图像,L代表灰度图像,灰度图像的像素值在0~255之间
    im = im.resize((28, 28), Image.ANTIALIAS)                 #resize image with high-quality 图像大小为28*28
    im = np.array(im).reshape(1, 1, 28, 28).astype(np.float32)#返回新形状的数组,把它变成一个 numpy 数组以匹配数据馈送格式。
   # print(im)
    im = im / 255.0 * 2.0 - 1.0                               #归一化到【-1~1】之间
    print(im)
    return im

#使用Matplotlib工具显示这张图像。
img = Image.open('data/data27012/6.png')
plt.imshow(img)   #根据数组绘制图像
plt.show()        #显示图像

 补充·注释:

  1. Image.open()得到的呃Img数据类型是Image对象
  2. img.resize((width, height),Image.ANTIALIAS)
    第一个参数:width,height, 表示设置传入图片的宽和高。
    第二个参数:

    Image.NEAREST :低质量
    Image.BILINEAR:双线性
    Image.BICUBIC :三次样条插值
    Image.ANTIALIAS:高质量
  3. astype 函数用于array中数值类型转换
     

#创建预测用的Executer
infer_exe = fluid.Executor(place)
inference_scope = fluid.core.Scope()  #用于获取一个新的作用域

最后把图像转换成一维向量并进行预测,数据从feed中的image传入。fetch_list的值是网络模型的最后一层分类器,所以输出的结果是10个标签的概率值,这些概率值的总和为1。

开始预测

通过fluid.io.load_inference_model,预测器会从params_dirname(model_save_dir)中读取已经训练好的模型,来对从未遇见过的数据进行预测。

# 加载数据并开始预测
with fluid.scope_guard(inference_scope):   #fluid.scope_guard接口通过With语句可以切换到一个指定的作用域。
    #获取训练好的模型
    #从指定目录中加载 推理model(inference model)
    [inference_program,                                           #推理Program
     feed_target_names,                                           #是一个str列表,它包含需要在推理 Program 中提供数据的变量的名称。 
     fetch_targets] = fluid.io.load_inference_model(model_save_dir,#fetch_targets:是一个 Variable 列表,从中我们可以得到推断结果。model_save_dir:模型保存的路径
                                                    infer_exe)     #infer_exe: 运行 inference model的 executor
    img = load_image('data/data27012/6.png')

    results = exe.run(program=inference_program,     #运行推测程序
                   feed={feed_target_names[0]: img}, #喂入要预测的img
                   fetch_list=fetch_targets)         #得到推测结果,   
  1. 补充注释:fludi.io.load_inference_model会返回有三个元素的元组。

 拿到每个标签的概率值之后,我们要获取概率最大的标签,并打印出来。

# 获取概率最大的label
lab = np.argsort(results)                               #argsort函数返回的是result数组值从小到大的索引值
#print(lab)
print("该图片的预测结果的label为: %d" % lab[0][0][-1])  #-1代表读取数组中倒数第一列  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值