用PaddlePaddle鉴定红酒质量

痴心易碎 提交于 2019-12-11 11:53:39

PaddlePaddle实现多层神经网络

欢迎大家来到这次实验,在这次实验中我们将使用PaddlePaddle来实现一个多层神经网络,这个多层神经网络包含2个隐藏层,并且在隐藏层中使用到了Relu激活函数,在最后的输出层使用了Softmax激活函数。多层神经网络具有比逻辑回归更强的学习能力,并且更适合解决多分类问题,现在让我们进入实验来看看多层神经网络与逻辑回归之间的差异性吧!

你将学会

  • 实现一个具有两个隐藏层的神经网络,用于解决多分类问题

  • 使用batch_norm做数据归一化

  • 在隐藏层中使用Relu激活函数

  • 在输出层使用Softmax激活函数

  • 使用classification_cost

  • 使用Adam作为优化器

现在让我们进入实验吧!

1 - 引用库

首先,载入几个需要用到的库,它们分别是:

  • numpy:一个python的基本库,用于科学计算
  • matplotlib.pyplot:用于生成图,在验证模型准确率和展示成本变化趋势时会使用到
  • paddle.fluid:paddle 的新一代的版本
  • os:在本例中用于获取文件或目录的路径
  • csv:用于对csv文件的存储和读取等操作

In[2]

import matplotlib
import numpy as np
import matplotlib.pyplot as plt
import os
import csv
import paddle
import paddle.fluid as fluid
from __future__ import print_function
try:
    from paddle.fluid.contrib.trainer import *
    from paddle.fluid.contrib.inferencer import *
except ImportError:
    print(
        "In the fluid 1.0, the trainer and inferencer are moving to paddle.fluid.contrib",
        file=sys.stderr)
    from paddle.fluid.trainer import *
    from paddle.fluid.inferencer import *
%matplotlib inline

问题描述:

红酒的品种多样,质量也有高低之分,质量的好坏决定了红酒的价格定位,假设你被聘为一家红酒供应商的红酒质量鉴定专家,红酒供应商给你提供了一些红酒的指标值和评分数据,希望你能从这些数据中学习到红酒的质量鉴定方法。

你的目标:

构建一个多层神经网络来对红酒质量评分

数据集分析:

红酒数据集是采集于葡萄牙北部“Vinho Verde”葡萄酒的数据,它是研究Classification/Regression模型训练的经典数据集。这个数据集包含了红白两种葡萄酒的数据,在本实验中采用了红酒数据作为实验数据,红酒的数据包含 11 个特征值(指标)和一个 0-10 的评分值(由于隐私等问题,在特征值中不包含价格、品牌等因素,只涵盖了红酒的物理化学性质因素):

输入值:

  1. fixed acidity 固定酸度
  2. volatile acidity 挥发性酸度
  3. citric acid 柠檬酸
  4. residual sugar 残糖
  5. chlorides 氯化物
  6. free sulfur dioxide 自由二氧化硫
  7. total sulfur dioxide 总二氧化硫
  8. density 密度
  9. pH pH值
  10. sulphates 硫酸盐
  11. alcohol 酒精

输出值:

12 - quality (0-10的评分) 质量

2 - 数据预处理

文件路径

红酒数据被存储在当前文件夹下的 data 目录中,data 目录中共有两个数据文件,分别是:

  • winequality-red.csv:红(葡萄)酒数据
  • winequality-white.csv:白(葡萄)酒数据

我们暂时先使用数据量较少的红酒数据来训练模型,当然你可以在完成实验后,使用白(葡萄)酒数据来重新训练或者验证你的模型。

In[3]

# 获得当前文件夹
cur_dir = os.path.dirname(os.path.realpath("__file__"))
# 获得文件路径
filename = cur_dir + "/winequality-red.csv"

载入数据

首先,我们使用csv.reader()来读取红酒数据,并存入data数组中,输出数据的属性和一组值。

In[4]

with open(filename) as f:
        reader = csv.reader(f)
        data = []
        for row in reader:
            data.append([i for i in row[0].split(';')])        
            
print( data[0],"\n" )
print( data[1] )
['fixed acidity', '"volatile acidity"', '"citric acid"', '"residual sugar"', '"chlorides"', '"free sulfur dioxide"', '"total sulfur dioxide"', '"density"', '"pH"', '"sulphates"', '"alcohol"', '"quality"'] 

['7.4', '0.7', '0', '1.9', '0.076', '11', '34', '0.9978', '3.51', '0.56', '9.4', '5']

可以看到,数据中存储了关于红酒的11类特征值和1个标签值(分数)。

预处理

现在让我们对数据进行一些预处理操作。观察上面输出的数据样例,我们发现数据是以字符串的形式存储的,并且第一行数据(data[0])存储的是属性,而不是具体的数据,所以我们需要去除第一行数据,并且将剩余的数据类型转换为np.float32的numpy数组。这一操作十分简单,只需要使用 np.array(array).astype(type) 即可完成。 例如,我们有一个 list 为 arr = ['1', '2', '3'] ,我们使用 np.array(arr).astype(np.float32) 既可以将其转化为 numpy 类型的数据。

练习:

取出除第一行外的数据,并将数据类型转换为 np.float32 的 numpy 数组。

特别需要注意除了第一行外,其他的每一行都要转化,所以,可以考虑使用切片技术,将除了第一行意外的数据都放入 np.array()
切片技术:data[5:] 表示从下标为 5 的位置开始向后取得所有的行

In[49]

##练习
data=np.array(data[1:]).astype(np.float32)
print( data[0] )
[ 7.4     0.7     0.      1.9     0.076  11.     34.      0.9978  3.51
  0.56    9.4     5.    ]

** 期望输出: **

[ 7.4000001 0.69999999 0. 1.89999998 0.076 11. 34. 0.99779999 3.50999999 0.56 9.39999962 5. ]

想要训练一个模型,我们首先需要将原始数据集切分为训练数据集(train set)和训练数据集(test set),定义一个ratioratioratio变量,它是一个介于[0,1][0,1][0,1]区间的标量,代表着训练数据占总数据的比重,例如设置ratio=0.8ratio=0.8ratio=0.8,它表示训练数据占总数据量的八成,如果data_num代表数据总数,那么ratio * data_num等于训练集数量。

在数据量不大的情况下,通常的切分方式 8:2 或者 7:3

** 练习: **

将数据划分为训练数据集和测试数据集(因为数据量较少,建议将ratio设置为0.8左右较为合理)

In[50]

# 练习
ratio = 0.8
data_num = len(data)
slice = int(ratio * data_num)
train_set = data[:slice]
test_set = data[slice:]

print( "train set shape:", train_set.shape )
print( "test set shape:", test_set.shape ) 
train set shape: (1273, 12)
test set shape: (319, 12)

如果将ratio设置为0.8则

** 期望输出: **

** train set shape ** (1278, 12)
** test set shape ** (320, 12)

3 - 构造reader

在逻辑回归的实验中我们介绍了reader()的构造方法以及生成器的概念,在这里我们同样构造一个read_data()函数来读取训练数据集train_set或者测试数据集test_set。它的具体实现是在read_data()函数内部构造一个reader(),使用yield关键字来让reader()成为一个Generator(生成器)。

注意 由于红酒的品质鉴定属于多分类问题(将结果划分为0-10的离散整数),所以我们将标签值(评分)的数据类型转化为integer类型。

In[27]

def read_data(data):
    def reader():
        for d in data:
            yield d[:-1], int(d[-1])
    return reader

test_arr = [
            [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 1],
            [0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0]
           ]

reader = read_data(test_arr)
for d in reader():
    print( d )
([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], 1)
([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0)

期望输出:

([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], 1) ([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0)

4 - 训练过程

完成了数据的预处理工作并构造了 read_data() 来读取数据,接下来将进入模型的训练过程,使用 PaddlePaddle 来构造可训练的 Logistic 回归模型,关键步骤如下:

  • 设置训练场所

  • 配置网络结构和优化方法

    • 配置网络结构
    • 定义损失函数 cost
    • 定义优化器 optimizer
  • 训练准备

    • 定义输入数据与网络的映射关系
    • 定义文件路径
    • 事件处理函数
    • 定义执行器
      • 初始化网络参数
  • 模型训练

    • 定义 reader
    • 定义 trainer
    • 开始训练
  • 模型检验

  • 预测

  • 绘制学习曲线

(1)设置训练场所

首先进行设置训练使用的设备。在复杂量较低的时候使用 CPU 就可以完成任务,但是对于大规模计算就需要使用 GPU 训练。目前 GPU 训练都是基于 CUDA 工具之上的。

  • use_cuda=False 表示不使用 GPU 进行训练

In[28]

# 设置训练场所
use_cuda = False
place = fluid.CUDAPlace(1) if use_cuda else fluid.CPUPlace()

** (2)配置网络结构和优化方法 **

这一阶段,我们关注的是网络拓扑结构的配置和优化方法的配置

** 网络结构: **

了解一下我们即将要配置的网络结构,如图所示,它的基本结构是输入层、两个隐藏层和输出层,两个隐藏层使用ReLU激活函数,输出层使用Softmax激活函数(多分类),除此之外,在输入层之后添加一层Batch Normalization对数据进行归一化处理。

 

背景知识

下面我们简单介绍一下网络结构中使用到的 ReLU 以及 Softmax 激活函数:

ReLU(Rectified linear unit)

ReLU激活函数通常比sigmoid和tanh激活函数的表现更好,其中一个原因是 sigmoid 和 tanh 在两端的饱和阶段梯度接近 0,容易造成梯度消失问题(Vanishing Gradient Problem),尤其是在深度网络中更加明显,而 ReLU 在非负区间的梯度为常数,因此不存在梯度消失问题,使得模型的收敛速度维持在一个稳定状态。我们在两个隐藏层上使用 ReLU 作为激活函数。

Softmax

Softmax 是神经网络中另一种激活函数,计算输出层的值。主要用于神经网络最后一层,作为输出层进行多分类,是逻辑回归二分类的推广。

Sigmoid 将结果值映射到 [0,1][0,1][0,1] 区间,用来做二分类。 而 Softmax 函数形式如下,把一个 k 维的向量 (y_1,y_2,y_3,y_4 … y_k.) 映射成 (a_1,a_2,a_3 … a_k.),其中 aia_iai​​ 介于区间[0,1][0,1][0,1],根据 aia_iai​​ 的大小来进行多分类的任务,如取权重最大的一维。

配置网络结构

现在我们已经了解了网络结构,开始着手配置吧!

输入层:

我们可以定义 x = fluid.layers.data(name='x', shape=[11], dtype='float32') 来表示生成一个数据输入层,名称为“x”,数据类型为11维向量;

隐藏层:

我们定义两个隐藏层h1和h2,以h1为例,定义h1 = fluid.layers.fc(input=x, size=32, act='relu'),表示生成一个全连接层类型的隐藏层,输入数据为norm1,神经元个数为32,激活函数为Relu();

输出层:

我们可以定义predict = fluid.layers.fc(input=h2, size=10, act='softmax')表示生成一个全连接层,输入数据为h2,输出结果共有10个,分别表示十个不同的分类,激活函数为Softmax();

标签层

我们可以定义label = fluid.layers.data(name='label', shape=[1], dtype='int64')表示生成一个数据层,名称为“label”,数据类型为包含0-9的整型。

定义损失函数

在配置网络结构之后,我们需要定义一个损失函数来计算梯度并优化参数。fluid 提供很多的损失函数, 在这里我们可以使用 fluid 提供的用于多分类的损失函数。
fluid 在 layers 里面提供了 cross_entropy 函数用来做分类问题的损失函数。这个函数有两个参数分别是 input 和 lable,分别对应预测值和标签值。其形式如下: cost = paddle.layer.cross_entropy(input=y_predict, label=y_label)。
当输入一个batch的数据时,损失算子的输出有多个值,每个值对应一条样本的损失,所以通常会在损失算子后面使用mean等算子,来对损失做归约。 损失规约形式如下:avg_cost = fluid.layers.mean(cost)。 注意,虽然在神经网络知识中没有这个步骤,但是在 fluid 代码中总是建议加入这个步骤。

练习

  1. 使用PaddlePaddle配置网络结构
  2. 定义损失函数
  3. 对定义好的损失函应用 mean 函数

特别的

由于本例使用 trainer 的写法,所以需要将整个网络拓扑结构包装到函数中方便后面使用。

In[61]

#  封装 train_func
def train_func():
    # 输入层
    x = fluid.layers.data(name='x', shape=[11], dtype='float32')
    
    #隐藏层
    ### START CODE HERE ### (≈ 2 lines of code)
    h1 = fluid.layers.fc(input=x, size=32, act='relu')
    h2 = fluid.layers.fc(input=h1, size=16, act='relu')
    ### END CODE HERE ###

    #预测层
    ### START CODE HERE ### (≈ 2 lines of code)
    y_predict = fluid.layers.fc(input=h2, size=10, act='softmax')
    ### END CODE HERE ###

    #标签
    y_label = fluid.layers.data(name='label', shape=[1], dtype='int64')
    
    # 损失函数
    ### START CODE HERE ### (≈ 2 lines of code) 
    cost = fluid.layers.cross_entropy(input=y_predict, label=y_label)
    avg_cost = fluid.layers.mean(cost)
    #acc = fluid.layers.accuracy(input=y_predict, label=y_label)
    ### END CODE HERE ###
    return avg_cost
    

** optimizer **

  1. 创建优化器

参数创建完成后,我们需要定义一个优化器optimizer,在这里我们尝试使用Adam来作为优化器,它的计算公式如下:

\begin{split}m(w, t) & = \beta_1 m(w, t-1) + (1 - \beta_1) \nabla Q_i(w) \\ v(w, t) & = \beta_2 v(w, t-1) + (1 - \beta_2)(\nabla Q_i(w)) ^2 \\ w & = w - \frac{\eta m(w, t)}{\sqrt{v(w,t) + \epsilon}}\end{split}

Adam是一种常用的、效果良好的自适应学习率调整优化算法,通常只需要将参数设置为beta1=0.9,beta2=0.999,epsilon=1e-08,不需要作修改即可让模型产生好的收敛效果。在 fluid 中可以使用接口 fluid.optimizer.Adam() 来创建 Adam 优化器。这个函数接受 4个参数分别是:learning_rate, beta1, beta2 和 epsilon。

  1. 使用优化器

创建优化器仅仅是向 fluid 后台添加了优化器并没有显示的使用。如果想让优化器真正的发挥作用,需要使用优化器,使用的方法十分简单,调用优化器的 minimize 函数即可,这个函数接受的参数就是将要被优化的损失函数。其形式如下:avg_cost

** 练习: **

  1. 创建Adam优化器并且设置参数值:learning_rate=0.2, beta1=0.9, beta2=0.999 和 epsilon=1e-08
  2. 使用优化器,使其作用于 avg_cost

** **特别的** **
由于本例使用 trainer 的写法,所以需要将优化器包装到函数中方便后面使用。

In[52]

#封装 优化器
def optimizer_func():
    #创建optimizer
    ### START CODE HERE ### (≈ 1 lines of code)    
    optimizer=fluid.optimizer.Adam(
        learning_rate=0.2,
        beta1=0.9,
        beta2=0.999,
        epsilon=1e-08
        )
    #opts = optimizer.minimize(avg_cost)
    ### END CODE HERE ###
    return optimizer

** (3)训练准备 **

这个阶段我们关注的是小的相关内容的配置。
** 定义映射 **
输入网络的数据要与网络本身应该接受的数据相匹配。在 fluid 中使用 feed_order 的概念来保证输入的数据与网络接受的数据的顺序是一致的。本示例中使用 feed_order = ['x', 'label'] 来告知网络,输入的数据是分为两部分,第一部分是 x 值,第二部分是 label 值。

In[53]

feed_order = ['x', 'label'] 

** 定义文件路径 **

在 fluid 中,默认模型的相关数据是需要保存在硬盘上的。也就是说在训练阶段会将训练好的模型保存在硬盘上,在将预测阶段可以直接 load 磁盘上的模型数据,进而做出预测。

In[54]

params_dirname = "./DNN_model"

** 定义事件处理函数 **
在 fluid 中,如果是用 trainer 的方式来训练的话,那么,在训练的时候允许开发者自己定义事件回调函数。目前接受的事件有 BeginEpochEvent、EndEpochEvent、BeginStepEvent、EndStepEvent。

In[55]

# Plot data
from paddle.v2.plot import Ploter
train_title = "Train cost"
test_title = "Test cost"
plot_cost = Ploter(train_title, test_title)

step = 0
# 事件处理
def event_handler_plot(event):
    global step
    if isinstance(event, EndStepEvent):
        if event.step % 2 == 0: # 若干个batch,记录cost
            if event.metrics[0] < 10:
                plot_cost.append(train_title, step, event.metrics[0])
                plot_cost.plot()
        if event.step % 20 == 0: # 若干个batch,记录cost
            test_metrics = trainer.test(
            reader=test_reader, feed_order=feed_order)
            if test_metrics[0] < 10:
                plot_cost.append(test_title, step, test_metrics[0])
                plot_cost.plot()

#             if test_metrics[0] < 1.0:
#                 # 如果准确率达到阈值,则停止训练
#                 print('loss is less than 10.0, stop')
#                 trainer.stop()

        # 将参数存储,用于预测使用
        if params_dirname is not None:
            trainer.save_params(params_dirname)
    step += 1

** 定义执行器 **
为了能够运行开发者定义的网络拓扑结构和优化器,需要定义执行器。由执行器来真正的执行参数的初始化和网络的训练过程。

In[56]

# 创建执行器,palce在程序初始化时设定
exe = fluid.Executor(place)
# 初始化执行器
exe.run( fluid.default_startup_program() )
[]

(4)模型训练

** 定义reader **
网络接受的数据实际上是一个又一个的 mini-batch 。 paddle 框架为开发者准备好了 paddle.batch 函数来提供一个又一个 mini-batch。在实际输入数据的时候,我们希望的是数据顺序不要影响网络是训练,paddle 框架也准备了 paddle.reader.shuffle 函数来打乱输入的顺序。

** 练习: ** 设置 BATCH_SIZE 为 10

BATCH_SIZE 的大小决定了 每个 mini-batch 中灌入的数据的数量

In[57]

# 设置 BATCH_SIZE 的大小
### START CODE HERE ### (≈ 1 lines of code) 
BATCH_SIZE = 10
### END CODE HERE ###

# 设置训练reader
train_reader = paddle.batch(
    paddle.reader.shuffle(
        read_data(train_set), 
        buf_size=500),
    batch_size=BATCH_SIZE)

#设置测试 reader
test_reader = paddle.batch(
    paddle.reader.shuffle(
        read_data(test_set), 
        buf_size=500),
    batch_size=BATCH_SIZE)

** 定义trainer **
trainer 负责收集训练需要的相关信息。定义 trainer 时需要提供 3个重要信息:

  1. 网络拓扑结构,通过参数 train_func 设定
  2. 真实训练的设备,通过参数 place 设定
  3. 优化方法,通过参数 optimizer_func 设定

In[62]

#创建训练器
from paddle.fluid.contrib.trainer import *
from paddle.fluid.contrib.inferencer import *
trainer = Trainer(
    train_func= train_func,
    place= place,
    optimizer_func= optimizer_func)

** 开始训练 **
在做好了所有的准备工作之后,就开始开始训练了。由于本例使用的是 trainer 的方法,所以可以直接调用 trainer 的 train 方法来执行训练。train 方法主要需要设置3个参数: reader、num_epochs 和 feeder_order。 其中,reader 表示能够持续提供 mini-batch 的数据源。num_epochs 表示所有的数据将要训练多少轮次(就是一个数字)。 feeder_order 表示数据的顺序。
我们注意到,reader 和 feeder_order 在前面的准备过程中已经准备好了。 除了这三个参数外,train 还接受一个 event_handler 参数。这个参数允许开发者自己定义回调函数,用以在训练过程中打印训练相关的信息,甚至在合适的时候停止训练。 函数的形式如下:

trainer.train(
    reader= ,
    num_epochs= ,
    event_handler= ,
    feed_order= )

** 练习: **

  1. 编写 train 函数
  2. 将 num_epochs 设置为 10

In[63]

from paddle.fluid.contrib.trainer import *
from paddle.fluid.contrib.inferencer import *
### START CODE HERE ### (≈ 1 lines of code)
trainer.train(
    reader=train_reader,
    num_epochs=10,
    event_handler=event_handler_plot,
    feed_order=feed_order)
### END CODE HERE ###

<Figure size 432x288 with 0 Axes>

5 - 预测过程

模型训练完成后,接下来使用训练好的模型在测试数据集上看看效果。 本阶段主要有两个部分:预测和预测效果评估

  • 预测
    • 定义预测网络拓扑结构
    • 定义运算设备
    • 定义预测器
    • 执行预测
  • 效果评估

(1)** 预测 **

** 定义预测网络拓扑结构 **
fluid 设计者认为训练的网络和预测的网络并不一定是完全相同的。所以在预测阶段,开发者需要自己定义测试的网络,但是这个网络拓扑结构和训练网络的拓扑结构必须是兼容的,否则从硬盘中 load 回来的数据是无法应用到预测网络中。

In[64]

# 定义数据的 feeder 为预测使用
feeder = None
    
#定义预测网络拓扑结构
def inference_func():
    global feeder
    x = fluid.layers.data(name='x', shape=[11], dtype='float32')
    h1 = fluid.layers.fc(input=x, size=32, act='relu')
    h2 = fluid.layers.fc(input=h1, size=16, act='relu')
    predict = fluid.layers.fc(input=h2, size=10, act='softmax')
    label = fluid.layers.data(name='label', shape=[1], dtype='int64')
    feeder = fluid.DataFeeder(place=place, feed_list=['x', 'label'])
    return predict

** 定义运算设备 **
一般是 CPU 或者 GPU 设备

In[65]

# 设置训练场所
use_cuda = False
place = fluid.CUDAPlace(1) if use_cuda else fluid.CPUPlace()

** 定义预测器 **
预测器的定义需要3个重要信息:

  1. 预测网络的拓扑结构,由参数 infer_func 设置
  2. 训练好的模型,其实就是训练好的模型的参数,也就是这些数据在磁盘上的路径。由参数 param_path 设置
  3. 具体使用的设备,由参数 place 设置

具体代码形式如下:

inferencer = Inferencer(
    infer_func= , 
    param_path= , 
    place= )

** 练习: ** 自己定义 预测器

In[79]

# 定义预测器
### START CODE HERE ### (≈ 3 lines of code) 
inferencer = Inferencer(
    infer_func =inference_func,
    param_path = params_dirname, 
    place=place)
### END CODE HERE ###

** 执行预测 **
有了 预测器之后 仅仅是有了预测的能力还没有真的去预测结果。真正的预测需要使用 inferencer.infer() 函数。这个函数的参数就将要被预测的数据。 这个函数接受的参数有两种写法:

  1. 形如:{"x":tensor}
  2. feeder.feed() 的结果(实际上这个函数的返回值也是一个字典) 本例中使用 feeder.feed() 的方式。
    下面从 test 数据集中拿出数据来进行预测。

In[80]

# 重新定义 test reader
BATCH_SIZE = 4
#设置测试 reader
test_reader = paddle.batch(
    paddle.reader.shuffle(
        read_data(test_set), 
        buf_size=200),
    batch_size=BATCH_SIZE)

In[81]

for mini_batch in test_reader():    
    #真的执行预测
    mini_batch_data = feeder.feed(mini_batch)
    mini_batch_result = inferencer.infer(mini_batch_data)
    
    # 打印预测结果
    mini_batch_result = np.argsort(mini_batch_result) #找出可能性最大的列标,升序排列
    mini_batch_result = mini_batch_result[0][:, -1]  #把这些列标拿出来
    print('预测结果:%s'%mini_batch_result)
    
    # 打印真实结果    
    label = np.array(mini_batch_data['label']) # 转化为 label
    label = label.flatten() #转化为一个 array
    print('真实结果:%s'%label)
    break    
预测结果:[6 5 5 6]
真实结果:[5 5 6 5]

(2)** 效果评估 **

下面定义评估效果的函数

In[82]


def right_ratio(right_counter, total):
    ratio = float(right_counter)/total
    return ratio

In[83]


# 评估函数 data_set 是一个reader
def evl(data_set):
    total = 0    #操作的元素的总数
    right_counter = 0  #正确的元素

    pass_num = 0
    for mini_batch in data_set():
        pass_num += 1
        #预测
        mini_batch_data = feeder.feed(mini_batch)
        mini_batch_result = inferencer.infer(mini_batch_data)
        
        #预测的结果
        mini_batch_result = np.argsort(mini_batch_result) #找出可能性最大的列标,升序排列
        mini_batch_result = mini_batch_result[0][:, -1]  #把这些列标拿出来
#         print('预测结果:%s'%mini_batch_result)

        label = np.array(mini_batch_data['label']) # 转化为 label
        label = label.flatten() #转化为一个 array
#         print('真实结果:%s'%label)

        #计数
        label_len = len(label)
        total += label_len
        for i in xrange(label_len):
            if mini_batch_result[i] == label[i]:
                right_counter += 1

    ratio = right_ratio(right_counter, total)
    return ratio

In[84]

ratio = evl(train_reader)
print('训练数据的正确率 %0.2f%%'%(ratio*100))

ratio = evl(test_reader)
print('预测数据的正确率 %0.2f%%'%(ratio*100))
训练数据的正确率 44.23%
预测数据的正确率 41.69%

5 - 总结

通过这个练习我们应该记住:

  1. ReLU激活函数比tanh和sigmoid更适合深层神经网络,因为它不存在梯度消失问题

  2. 使用Batch Normalization能够加速模型训练

  3. 利用Softmax可以解决多分类问题

  4. Adam是一种常用的、效果良好的自适应学习率调整优化算法,通常使用它能够得到不错的学习效果。

至此,我们完成了比逻辑回归模型稍复杂的多层神经网络模型的配置和训练,不难发现,在PaddlePaddle中,只需要通过简单地叠加或删除数据层、连接层等,就可以轻易地改变模型结构,自由度很高,大家可以尝试使用更多层数的神经网络或者改变每一层的神经元个数来修改模型,在调试中加深对深度学习的理解和PaddlePaddle框架的熟悉度。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!