鲍鱼年龄预测

经典的线性回归模型主要用来预测一些存在着线性关系的数据集。回归模型可以理解为:存在一个点集,用一条曲线去拟合它分布的过程。如果拟合曲线是一条直线,则称为线性回归。如果是一条二次曲线,则被称为二次回归。线性回归是回归模型中最简单的一种。 本教程使用PaddlePaddle建立起一个鲍鱼年龄预测模型。

在线性回归中:
(1)假设函数是指,用数学的方法描述自变量和因变量之间的关系,它们之间可以是一个线性函数或非线性函数。 在本次线性回顾模型中,我们的假设函数为 Y’= wX+b ,其中,Y’表示模型的预测结果(预测的鲍鱼年龄),用来和真实的Y区分。模型要学习的参数即:w,b。

(2)损失函数是指,用数学的方法衡量假设函数预测结果与真实值之间的误差。这个差距越小预测越准确,而算法的任务就是使这个差距越来越小。 建立模型后,我们需要给模型一个优化目标,使得学到的参数能够让预测值Y’尽可能地接近真实值Y。这个实值通常用来反映模型误差的大小。不同问题场景下采用不同的损失函数。 对于线性模型来讲,最常用的损失函数就是均方误差(Mean Squared Error, MSE)。

(3)优化算法:神经网络的训练就是调整权重(参数)使得损失函数值尽可能得小,在训练过程中,将损失函数值逐渐收敛,得到一组使得神经网络拟合真实模型的权重(参数)。所以,优化算法的最终目标是找到损失函数的最小值。而这个寻找过程就是不断地微调变量w和b的值,一步一步地试出这个最小值。 常见的优化算法有随机梯度下降法(SGD)、Adam算法等等

# # **Step1.数据准备**
#
# **认识数据:**
#
#
# 数据集共4177行,每行9列
#
# 前8列用来描述鲍鱼的各种信息,分别是性别、长度、直径、高度、总重量、皮重、内脏重量、克重,最后一列为该鲍鱼的年龄
#
#
# **数据准备:**
#
# 1.从文件中加载数据
#
# 2.对数据进行归一化
#
# 3.构造数据集提供器


# 读取文件
import numpy as np
import os
import matplotlib.pyplot as plt

data_X = []
data_Y = []
# 将性别(M:雄性,F:雌性,I:未成年)映射成数字
sex_map = {'I': 0, 'M': 1, 'F': 2}
with open('data/data361/AbaloneAgePrediction.txt') as f:
    for line in f.readlines():
        line = line.split(',')
        line[0] = sex_map[line[0]]
        data_X.append(line[:-1])
        data_Y.append(line[-1:])
# 转换为nparray
data_X = np.array(data_X, dtype='float32')
data_Y = np.array(data_Y, dtype='float32')
# 检查大小
print('data shape', data_X.shape, data_Y.shape)
print('data_x shape[1]', data_X.shape[1])
# 归一化
for i in range(data_X.shape[1]):
    _min = np.min(data_X[:, i])  # 每一列的最小值
    _max = np.max(data_X[:, i])  # 每一列的最大值
    data_X[:, i] = (data_X[:, i] - _min) / (_max - _min)  # 归一化到0-1之间

import paddle
import paddle.fluid as fluid
from sklearn.model_selection import train_test_split

# 分割训练集、测试集
X_train, X_test, y_train, y_test = train_test_split(data_X,  # 被划分的样本特征集
                                                    data_Y,  # 被划分的样本标签
                                                    test_size=0.2,  # 测试集占比
                                                    random_state=0)  # 随机数种子,在需要重复试验的时候,保证得到一组一样的随机数


# 自定义reader,每次返回一个样本数据
def reader_creator(_X, _Y):
    def reader():
        for _x, _y in zip(_X, _Y):
            yield [_x, _y]  # 返回Iterable对象

    return reader


# 一个minibatch中有16个数据
BATCH_SIZE = 20

# 定义了用于训练与验证的数据提供器。提供器每次读入一个大小为BATCH_SIZE的数据批次。
# BATCH_SIZE个数据项组成一个mini batch。
train_reader = paddle.batch(reader_creator(X_train, y_train),
                            batch_size=BATCH_SIZE)
test_reader = paddle.batch(reader_creator(X_test, y_test),
                           batch_size=BATCH_SIZE)

# # **Step2.网络配置**
#
# **(1)网络搭建**:对于线性回归来讲,它就是一个从输入到输出的简单的全连接层。
#
# 对于鲍鱼年龄预测数据集,假设鲍鱼属性和年龄之间的关系可以被属性间的线性组合描述。

# 定义输入的形状和数据类型,张量变量x,表示8维的特征值
x = fluid.layers.data(name='x', shape=[8], dtype='float32')

# 定义输出的形状和数据类型,张量y,表示目标值
y = fluid.layers.data(name='y', shape=[1], dtype='float32')

# 定义一个简单的线性网络,连接输入和输出的全连接层
# input:输入;
# size:该层输出单元的数目
# act:激活函数
fc2 = fluid.layers.fc(input=x, size=200, bias_attr=True)
drop = fluid.layers.dropout(x=fc2, dropout_prob=0.5)
fc3 = fluid.layers.fc(input=drop, size=800, bias_attr=True, act='relu')
drop = fluid.layers.dropout(x=fc3, dropout_prob=0.5)
fc4 = fluid.layers.fc(input=drop, size=800, bias_attr=True, act='relu')
drop = fluid.layers.dropout(x=fc4, dropout_prob=0.5)
fc5 = fluid.layers.fc(input=drop, size=100, bias_attr=True, act='relu')
y_predict = fluid.layers.fc(input=fc5, size=1, bias_attr=True, act=None)

# **(2)定义损失函数**
#
# 此处使用均方差损失函数。
#
# square_error_cost(input,lable):接受输入预测值和目标值,并返回方差估计,即为(y-y_predict)的平方
cost = fluid.layers.square_error_cost(input=y_predict, label=y)  # 求方差
avg_cost = fluid.layers.mean(cost)  # 对方差求平均值,得到平均损失
# 克隆main_program得到test_program,使用参数for_test来区分该程序是用来训练还是用来测试,该api请在optimization之前使用.
test_program = fluid.default_main_program().clone(for_test=True)
# **(3)定义优化函数**

# 此处使用的是随机梯度下降。
optimizer = fluid.optimizer.AdamOptimizer(learning_rate=0.0001)
opts = optimizer.minimize(avg_cost)

# 完成上述定义,也就是完成了 fluid.default_main_program 的构建过程,fluid.default_main_program 中承载着神经网络模型,前向反向计算,以及优化算法对网络中可学习参数的更新。

# **fluid的设计思想:**
# 用户编写一段python程序,通过调用 Fluid 提供的算子,向一段 Program 中添加**变量**以及**对变量的操作**(Operators )。
#
# 用户**只需要描述核心的前向计算**,不需要关心反向计算、分布式下以及异构设备下如何计算。
#
# Fluid 的 Program 的形式上类似一段 C++ 或 Java 程序。
#
# 包含:
#
# 1.本地变量的定义
#
# 2.一系列的operator
#
#
# **用户完成网络定义后,一段 Fluid 程序中通常存在 2 段 Program:**
#
# 1.**fluid.default_startup_program**:定义了创建模型参数,输入输出,以及模型中可学习参数的初始化等各种操作
#
# default_startup_program 可以由框架自动生成,使用时无需显示地创建
#
#
# 2.**fluid.default_main_program** :定义了神经网络模型,前向反向计算,以及优化算法对网络中可学习参数的更新
#
# 使用Fluid的核心就是构建起 default_main_program

# # **Step3.网络训练 & Step4.网络评估**

# **(1)创建Executor**
#
# 首先定义运算场所 fluid.CPUPlace()和 fluid.CUDAPlace(0)分别表示运算场所为CPU和GPU
#
# Executor:接收传入的program,通过run()方法运行program。

# use_cuda为False,表示运算场所为CPU;use_cuda为True,表示运算场所为GPU
use_cuda = False
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()

# 创建一个Executor实例exe
exe = fluid.Executor(place)

# 正式进行网络训练前,需先执行参数初始化
exe.run(fluid.default_startup_program())

# **(2)定义输入数据维度**
#
# DataFeeder负责将数据提供器(train_reader,test_reader)返回的数据转成一种特殊的数据结构,使其可以输入到Executor中。
#
# feed_list设置向模型输入的向变量表或者变量表名

# In[ ]:


# 告知网络传入的数据分为两部分,第一部分是x值,第二部分是y值
feeder = fluid.DataFeeder(place=place, feed_list=[x, y])

# **(3)定义绘制训练过程的损失值变化趋势的方法draw_train_process**

# In[ ]:


iter = 0;
iters = []
train_costs = []


def draw_train_process(iters, train_costs):
    title = "training cost"
    plt.title(title, fontsize=24)
    plt.xlabel("iter", fontsize=14)
    plt.ylabel("cost", fontsize=14)
    plt.plot(iters, train_costs, color='red', label='training cost')
    plt.grid()
    plt.show()


# **(4)训练并保存模型**
#
# Executor接收传入的program,并根据feed map(输入映射表)和fetch_list(结果获取表) 向program中添加feed operators(数据输入算子)和fetch operators(结果获取算子)。 feed map为该program提供输入数据。fetch_list提供program训练结束后用户预期的变量。
#
# 使用feed方式送入训练数据,先将reader数据转换为PaddlePaddle可识别的Tensor数据,传入执行器进行训练。
#
# 注:enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标

# In[ ]:


# 训练轮数:所有训练数据的一个前向传递和一个后向传递为一轮
EPOCH_NUM = 100
# 模型保存路径
model_save_dir = "/home/aistudio/work/fit_a_line.inference.model"

for pass_id in range(EPOCH_NUM):  # 训练EPOCH_NUM轮
    # 开始训练
    for batch_id, data in enumerate(train_reader()):  # 遍历train_reader迭代器
        train_cost = exe.run(program=fluid.default_main_program(),  # 运行主程序
                             feed=feeder.feed(data),  # 喂入一个batch的训练数据
                             fetch_list=[avg_cost])  # fetch 误差、准确率,fetch_list中设置要获取的值
        if batch_id % 100 == 0:
            print("Pass:%d, Cost:%0.5f" % (pass_id, train_cost[0]))  # 每训练100次,打印一次平均损失值

        iter = iter + 1
        iters.append(iter)
        train_costs.append(train_cost[0])

    # 开始验证,并输出验证集经过一轮的平均损失
    test_costs = []
    for batch_id, data in enumerate(test_reader()):  # 遍历test_reader迭代器
        test_cost = exe.run(program=test_program,  # 运行测试program
                            feed=feeder.feed(data),  # 喂入一个batch的测试数据
                            fetch_list=[avg_cost])  # fetch均方误差,fetch_list中设置要获取的值

        test_costs.append(test_cost[0])
    test_cost = (sum(test_costs) / len(test_costs))  # 每轮的平均误差
    print('Test:%d, Cost:%0.5f' % (pass_id, test_cost))  # 打印平均损失

    # 保存模型
    # 如果保存路径不存在就创建
if not os.path.exists(model_save_dir):
    os.makedirs(model_save_dir)
print('save models to %s' % (model_save_dir))

# 保存训练参数到指定路径中,构建一个专门用预测的program
fluid.io.save_inference_model(model_save_dir,  # 保存预测model的路径
                              ['x'],  # 预测需要 feed 的数据
                              [y_predict],  # 保存预测结果的变量
                              exe)  # exe 保存 inference model
# 绘制训练过程,损失随迭代次数的变化
draw_train_process(iters, train_costs)

# # **Step5.模型预测**
# **(1)创建预测用的Executor**

# In[ ]:


infer_exe = fluid.Executor(place)  # 创建推测用的executor
inference_scope = fluid.core.Scope()  # Scope指定作用域


# **(2)可视化真实值与预测值方法定义**
def draw_infer_result(groud_truths, infer_results):
    title = 'abalone'
    plt.title(title, fontsize=24)
    x = np.arange(1, 20)
    y = x
    plt.plot(x, y)
    plt.xlabel('ground truth', fontsize=14)
    plt.ylabel('infer result', fontsize=14)
    plt.scatter(groud_truths, infer_results, color='green', label='training cost')
    plt.grid()
    plt.show()


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

with fluid.scope_guard(inference_scope):  # 修改全局/默认作用域(scope), 运行时中的所有变量都将分配给新的scope。
    # 从指定目录中加载预测模型
    [inference_program,  # 预测用的program
     feed_target_names,  # 一个str列表,它包含需要在预测 Program 中提供数据的变量的名称。
     fetch_targets] = fluid.io.load_inference_model(  # fetch_targets: 从中可以得到预测结果。
        model_save_dir,  # model_save_dir:模型保存路径
        infer_exe)  # infer_exe: 预测用executor

    # 获取预测数据
    INFER_BATCH_SIZE = 10
    infer_reader = paddle.batch(reader_creator(X_test, y_test), batch_size=INFER_BATCH_SIZE)
    # 从infer_reader中分割x
    infer_data = next(infer_reader())
    infer_x = np.array([data[0] for data in infer_data]).astype("float32")
    infer_y = np.array([data[1] for data in infer_data]).astype("float32")

    results = infer_exe.run(inference_program,  # 预测模型
                            feed={feed_target_names[0]: np.array(infer_x)},  # 喂入要预测的x值
                            fetch_list=fetch_targets)  # 得到推测结果
    infer_results = []  # 预测值
    groud_truths = []  # 真实值
    sum_cost = 0
    for i in range(INFER_BATCH_SIZE):
        infer_result = results[0][i]  # 经过预测后的值
        ground_truth = infer_y[i]  # 真实值
        infer_results.append(infer_result)
        groud_truths.append(ground_truth)
        print("No.%d: infer result is %.2f,ground truth is %.2f" % (i, infer_result, ground_truth))
        cost = np.power(infer_result - ground_truth, 2)
        sum_cost += cost
    print("平均误差为:", sum_cost / INFER_BATCH_SIZE)

    draw_infer_result(groud_truths, infer_results)

结果:
鲍鱼年龄预测_第1张图片
鲍鱼年龄预测_第2张图片

你可能感兴趣的:(机器学习,python,机器学习)