目录

0.代码架构

 1.数据集dataloader.py

2.模型 net.py

4.训练train.py

5.测试test.py

6.可视化结果


运用线性网络结构

0.代码架构

 1.数据集dataloader.py

import paddle
from paddle.nn import Linear
import paddle.nn.functional as F
import numpy as np
import os
import random


def load_data():

    ## 从文件导入数据
    datafile = './data/housing.data'
    # np.fromfile(frame, dtype = float, count=-1, sep=’’):
    # frame:文件、字符串;dtype:读取的数据以此类型存储;count:读入元素个数,-1表示读入整个文件;sep: 数据分割字符串,如果是空串,写入文件为二进制
    data = np.fromfile(datafile, sep=' ', dtype=np.float32)

    ## 数据形状变换
    # 每条数据包括14项,其中前面13项是影响因素,第14项是相应的房屋价格中位数
    feature_names = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE',
                     'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV']
    feature_num = len(feature_names)
    # 将原始数据进行Reshape,变成[N, 14]这样的形状
    data = data.reshape([data.shape[0] // feature_num, feature_num])

    ## 数据划分
    # 将原数据集拆分成训练集和测试集
    # 这里使用80%的数据做训练,20%的数据做测试
    # 测试集和训练集必须是没有交集的
    ratio = 0.8
    offset = int(data.shape[0] * ratio)
    training_data = data[:offset]

    ## 数据归一化
    # 计算train数据集的最大值,最小值,平均值
    maximums, minimums, avgs = training_data.max(axis=0), training_data.min(axis=0), \
                               training_data.sum(axis=0) / training_data.shape[0]

    # 记录数据的归一化参数,在预测时对数据做归一化
    global max_values # global 相当于定义一个全局变量,在函数中可以改变值
    global min_values
    global avg_values
    max_values = maximums
    min_values = minimums
    avg_values = avgs

    # 对数据进行归一化处理
    for i in range(feature_num):
        data[:, i] = (data[:, i] - avgs[i]) / (maximums[i] - minimums[i])

    # 训练集和测试集的划分比例
    training_data = data[:offset]
    test_data = data[offset:]
    return training_data, test_data,max_values,min_values,avg_values

# 验证数据集读取程序的正确性
training_data, test_data,max_values,min_values,avg_values = load_data()
print('The shape of training data:')
print(training_data.shape)
print('Training data:')
print(training_data[1,:])

2.模型 net.py

import paddle
from paddle.nn import Linear
import paddle.nn.functional as F
import numpy as np
import os
import random
import dataloader

# 线性回归网络结构,继承paddle.nn.Layer父类
class Regressor(paddle.nn.Layer):

    # self代表类的实例自身
    def __init__(self):
        # 初始化父类中的一些参数
        super(Regressor, self).__init__()
        # 定义一层全连接层,输入维度是13,输出维度是1
        self.fc = Linear(in_features=13, out_features=1)

    # 网络的前向计算
    # 框架指定,在调用模型实例时会自动执行
    def forward(self, inputs):
        x = self.fc(inputs)
        return x

# # 具体模型结构
# class Network(object):
#     def __init__(self, num_of_weights):
#         # 随机产生w的初始值
#         # 为了保持程序每次运行结果的一致性,此处设置固定的随机数种子
#         np.random.seed(0)
#         self.w = np.random.randn(num_of_weights, 1) # randn产生[0,1),参数为不同维度,返回指定维度的array
#         self.b = 0.
#
#     # 前向传播
#     def forward(self, x):
#         z = np.dot(x, self.w) + self.b # 线性模型
#         return z
#
#     #均方损失函数
#     def loss(self, z, y):
#         error = z - y
#         cost = error * error
#         cost = np.mean(cost) # mean求取均值
#         return cost
#
#     # 梯度计算
#     def gradient(self, x, y):
#         z = self.forward(x) # 线性模型
#         N = x.shape[0]
#         gradient_w = 1. / N * np.sum((z - y) * x, axis=0) # w的梯度计算,即gradient_w = (z-y)*x &= np.mean(gradient_w, axis=0)
#         gradient_w = gradient_w[:, np.newaxis] # gradient_w和w保持一致的形状(13,1)。np.newaxis:插入新维度
#         gradient_b = 1. / N * np.sum(z - y) # b的梯度计算
#         return gradient_w, gradient_b
#
#     # 梯度更新
#     # eta:移动步长
#     def update(self, gradient_w, gradient_b, eta=0.01):
#         self.w = self.w - eta * gradient_w # 更新参数
#         self.b = self.b - eta * gradient_b
#
#     def train(self, training_data, num_epochs, batch_size=10, eta=0.01):
#         n = len(training_data)
#         losses = [] # 存放每次训练的损失
#         for epoch_id in range(num_epochs): # 遍历每个小批量数据
#             # 在每轮迭代开始之前,将训练数据的顺序随机打乱
#             # 然后再按每次取batch_size条数据的方式取出
#             np.random.shuffle(training_data) # 随机打乱顺序
#             # 将训练数据进行拆分,每个mini_batch包含batch_size条的数据
#             mini_batches = [training_data[k:k + batch_size] for k in range(0, n, batch_size)]
#             for iter_id, mini_batch in enumerate(mini_batches): # 小批量中循环数据
#                 x = mini_batch[:, :-1]
#                 y = mini_batch[:, -1:]
#                 z = self.forward(x)
#                 loss = self.loss(z, y)
#                 gradient_w, gradient_b = self.gradient(x, y) # 计算梯度
#                 self.update(gradient_w, gradient_b, eta) # 更新梯度
#                 losses.append(loss)
#                 print('Epoch {:3d} / iter {:3d}, loss = {:.4f}'.
#                       format(epoch_id, iter_id, loss))
#
#         return losses
#
#
# ## 测试模型
# # 获取数据
# training_data, test_data = dataloader.load_data()
# x = training_data[:, :-1]
# y = training_data[:, -1:]
# # 调用模型
# print('\nTest model:')
# net = Network(13)
# # 此处可以一次性计算多个样本的预测值和损失函数
# x1 = x[0:3]
# y1 = y[0:3]
# z = net.forward(x1)
# print('predict: ', z)
# loss = net.loss(z, y1)
# print('loss:', loss)

4.训练train.py

import numpy as np
import paddle
from paddle.nn import Linear
import paddle.nn.functional as F
import os
import random

import dataloader
import net

# 声明定义好的线性回归模型
model = net.Regressor()
# 开启模型训练模式
model.train()
# 加载数据
training_data, test_data,max_values,min_values,avg_values = dataloader.load_data()
# 定义优化算法,使用随机梯度下降SGD
# 学习率设置为0.01
opt = paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters())

EPOCH_NUM = 10  # 设置外层循环次数
BATCH_SIZE = 10  # 设置batch大小

# 定义外层循环
for epoch_id in range(EPOCH_NUM): # 遍历所有划分的小块
    # 在每轮迭代开始之前,将训练数据的顺序随机的打乱
    np.random.shuffle(training_data)
    # 将训练数据进行拆分,每个batch包含10条数据
    mini_batches = [training_data[k:k + BATCH_SIZE] for k in range(0, len(training_data), BATCH_SIZE)]
    # 定义内层循环
    for iter_id, mini_batch in enumerate(mini_batches): # 遍历每个小块里的数据
        x = np.array(mini_batch[:, :-1])  # 获得当前批次训练数据
        y = np.array(mini_batch[:, -1:])  # 获得当前批次训练标签(真实房价)
        # 将numpy数据转为tensor格式
        house_features = paddle.to_tensor(x)
        prices = paddle.to_tensor(y)

        # 前向计算
        predicts = model(house_features)

        # 计算损失
        loss = F.square_error_cost(predicts, label=prices)
        avg_loss = paddle.mean(loss)
        if iter_id % 20 == 0:
            print("epoch: {}, iter: {}, loss is: {}".format(epoch_id, iter_id, avg_loss.numpy()))

        # 反向传播,计算每层参数的梯度值
        avg_loss.backward()
        # 更新参数,根据设置好的学习率迭代一步
        opt.step()
        # 清空梯度变量,以备下一轮计算
        opt.clear_grad()

# 保存模型参数,文件名为LR_model.pdparams
# .state_dict()保存模型中训练出的所有参数
paddle.save(model.state_dict(), './run_models/LR_model.pdparams')
print("Save model at LR_model.pdparams!")

5.测试test.py

import numpy as np
import paddle
from paddle.nn import Linear
import paddle.nn.functional as F
import os
import random

import dataloader
import net

# 从dataloader中已加载的测试集中,随机选择一条作为测试数据
def test_all():
    # 遍历每个测试数据
    for idx in range(test_data.shape[0]):
        print(f"The {idx} test:")
        one_data, label = test_data[idx, :-1], test_data[idx, -1]
        # 修改该条数据shape为[1,13]
        one_data =  one_data.reshape([1,-1])
        # 将数据转为tensor格式
        one_data = paddle.to_tensor(one_data)
        predict = model(one_data)

        # 对结果做反归一化处理
        predict = predict * (max_values[-1] - min_values[-1]) + avg_values[-1]
        # 对label数据做反归一化处理
        label = label * (max_values[-1] - min_values[-1]) + avg_values[-1]

        print("Inference result is {}, the corresponding label is {}".format(predict.numpy(), label))


model = net.Regressor()
training_data, test_data,max_values,min_values,avg_values = dataloader.load_data()


# 参数为保存模型参数的文件地址
model_dict = paddle.load('./run_models/LR_model.pdparams')
model.load_dict(model_dict)
model.eval() # 模型的状态调整为eval()(校验)

print('/nStart test!')
# 参数为数据集的文件地址
test_all()

6.可视化结果

# 训练目标:到一个参数解w和b,使得损失函数取得极小值
import paddle
from paddle.nn import Linear
import paddle.nn.functional as F
import numpy as np
import os
import random
import dataloader
import net

training_data, test_data = dataloader.load_data()
x = training_data[:, :-1]
y = training_data[:, -1:]
net = model.Network(13)
losses = []
#只画出参数w5和w9在区间[-160, 160]的曲线部分,以及包含损失函数的极值
w5 = np.arange(-160.0, 160.0, 1.0)
w9 = np.arange(-160.0, 160.0, 1.0)
losses = np.zeros([len(w5), len(w9)])

#计算设定区域内每个参数取值所对应的Loss
for i in range(len(w5)):
    for j in range(len(w9)):
        net.w[5] = w5[i]
        net.w[9] = w9[j]
        z = net.forward(x)
        loss = net.loss(z, y)
        losses[i, j] = loss

#使用matplotlib将两个变量和对应的Loss作3D图
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# figure(num=None, figsize=None, dpi=None, facecolor=None, edgecolor=None, frameon=True)
# num:图像名称。figsize:宽和高。dpi:分辨率。facecolor:背景颜色。edgecolor:边框颜色。frameon:是否显示边框。
fig = plt.figure()# 自定义图像
ax = Axes3D(fig) # 3D图
w5, w9 = np.meshgrid(w5, w9) # 从坐标向量中返回坐标矩阵
ax.plot_surface(w5, w9, losses, rstride=1, cstride=1, cmap='rainbow') # 设计图像
plt.show()

更多推荐