1. 加载飞桨、numpy等相关类库
import paddle
import paddle.fluid as fluid
import paddle.fluid.dygraph as dygraph # 动态图的类库
from paddle.fluid.dygraph import Linear # 神经网络的全连接层函数
import numpy as np
import os
import random
2. 数据处理
def load_data():
# 从文件中导入数据
datafile = './work/housing.data'
data = np.fromfile(datafile, sep=' ')
# 每条数据包括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 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
3. 模型设计,定义init函数和forward函数
class Regressor(fluid.dygraph.Layer):
def __init__(self):
super(Regressor, self).__init__()
self.fc = Linear(input_dim=13, output_dim=1, act=None)
def forward(self, inputs):
y = self.fc(inputs)
return y
4. 训练配置,包括四个步骤:指定运行训练的机器资源,声明模型实例,加载训练和测试数据,设置优化器和学习率
训练过程,包括四个步骤:数据准备,前向计算,损失函数,反向传播
with fluid.dygraph.guard(fluid.CPUPlace()):
# 1-指定训练资源:使用GPU,则为fluid.CUDAPlace(0)
# 2-声明定义好的线性回归模型,开启模型训练模式
model = Regressor()
model.train()
# 3-加载数据
training_data, test_data = load_data()
# 4-定义优化算法和学习率
opt = fluid.optimizer.SGD(learning_rate=0.01, parameter_list=model.parameters())
EPOCH_NUM = 10 # 设置外层循环次数
BATCH_SIZE = 10 # 设置batch大小
for epoch_id in range(EPOCH_NUM):
# 1.数据准备:打乱数据,分批次读取数据,将numpy数据转换为variable形式
np.random.shuffle(training_data)
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]).astype('float32')
y = np.array(mini_batch[:, -1:]).astype('float32')
house_features = dygraph.to_variable(x)
prices = dygraph.to_variable(y)
# 2.前向计算
predicts = model(house_features)
# 3.计算损失
loss = fluid.layers.square_error_cost(predicts, label=prices)
avg_loss = fluid.layers.mean(loss)
if iter_id%20==0:
print("epoch: {}, iter: {}, loss is: {}".format(epoch_id, iter_id, avg_loss.numpy()))
# 4.反向传播
avg_loss.backward()
opt.minimize(avg_loss) # 最小化loss,更新参数
model.clear_gradients() # 清除梯度
# 保存模型
fluid.save_dygraph(model.state_dict(), 'LR_model')
5. 保存和测试模型
保存模型在上述第4步的训练完成之后,考虑到在实际应用中,训练模型和使用模型往往是不同的场景,因此选择保存模型之后再加载模型,进而对测试集进行预测
def load_one_example(data_dir):
# 打开文件,并选择最后1条数据用于测试
f = open(data_dir, 'r')
datas = f.readlines()
tmp = datas[-1]
tmp = tmp.strip().split()
one_data = [float(v) for v in tmp]
# 因为训练中使用了归一化的数据,因此需要对测试数据也进行归一化处理
for i in range(len(one_data)-1):
one_data[i] = (one_data[i] - avg_values[i]) / (max_values[i] - min_values[i])
data = np.reshape(np.array(one_data[:-1]), [1, -1]).astype(np.float32)
label = one_data[-1]
data = dygraph.to_variable(data)
label = model(label)
return data, label
with dygraph.guard():
# 读取保存的模型,参数为保存模型参数的文件地址
model_dict, _ = fluid.load_dygraph('LR_model')
model.load_dict(model_dict)
model.eval()
# 读取测试数据集,参数为数据集的文件地址
test_data, label = load_one_example('./work/housing.data')
# 对结果做反归一化处理
results = results * (max_values[-1] - min_values[-1]) + avg_values[-1]
print("Inference result is {}, the corresponding label is {}".format(results.numpy(), label))