文章目录

  • NNDL 实验三 线性回归
    • 2.2 线性回归
      • 2.2.1 数据集构建
      • 2.2.2 模型构建
      • 2.2.3 损失函数
      • 2.2.4 模型优化
      • 2.2.5 模型训练
      • 2.2.6 模型评估
      • 2.2.7 样本数量 & 正则化系数
    • 2.3 多项式回归
      • 2.3.1 数据集构建
      • 2.3.2 模型构建
      • 2.3.3 模型训练
      • 2.3.4 模型评估
    • 2.4 Runner类介绍
    • 2.5 基于线性回归的波士顿房价预测
      • 2.5.1 数据处理
        • 2.5.1.1 数据清洗
        • 2.5.1.2 数据集划分
        • 2.5.1.3特征工程
      • 2.5.2 模型构建
      • 2.5.3 完善Runner类
      • 2.5.4 模型训练
      • 2.5.5 模型测试
      • 2.5.6 模型预测

NNDL 实验三 线性回归

使用pytorch实现

2.2 线性回归

2.2.1 数据集构建

构造一个小的回归数据集:
生成 150 个带噪音的样本,其中 100 个训练样本,50 个测试样本,并打印出训练数据的可视化分布。
代码:

# 真实函数的参数缺省值为 w=1.2,b=0.5
def linear_func(x,w=1.2,b=0.5):y = w*x + breturn yimport torchdef create_toy_data(func, interval, sample_num, noise = 0.0, add_outlier = False, outlier_ratio = 0.001):# 均匀采样# 使用torch.rand在生成sample_num个随机数X = torch.rand(size = [sample_num]) * (interval[1]-interval[0]) + interval[0]y = func(X)# 生成高斯分布的标签噪声# 使用torch.normal生成0均值,noise标准差的数据epsilon = torch.normal(0,noise,y.shape)y = y + epsilonif add_outlier:     # 生成额外的异常点outlier_num = int(len(y)*outlier_ratio)if outlier_num != 0:# 使用torch.randint生成服从均匀分布的、范围在[0, len(y))的随机Tensoroutlier_idx = torch.randint(len(y),size = [outlier_num])y[outlier_idx] = y[outlier_idx] * 5return X, yfrom matplotlib import pyplot as plt # matplotlib 是 Python 的绘图库
func = linear_func
interval = (-10,10)
train_num = 100 # 训练样本数目
test_num = 50 # 测试样本数目
noise = 2
X_train, y_train = create_toy_data(func=func, interval=interval, sample_num=train_num, noise = noise, add_outlier = False)
X_test, y_test = create_toy_data(func=func, interval=interval, sample_num=test_num, noise = noise, add_outlier = False)X_train_large, y_train_large = create_toy_data(func=func, interval=interval, sample_num=5000, noise = noise, add_outlier = False)# torch.linspace返回一个Tensor,Tensor的值为在区间start和stop上均匀间隔的num个值,输出Tensor的长度为num
X_underlying = torch.linspace(interval[0],interval[1],train_num)
y_underlying = linear_func(X_underlying)# 绘制数据
plt.scatter(X_train, y_train, marker='*', facecolor="none", edgecolor='#e4007f', s=50, label="train data")
plt.scatter(X_test, y_test, facecolor="none", edgecolor='#f19ec2', s=50, label="test data")
plt.plot(X_underlying, y_underlying, c='#000000', label=r"underlying distribution")
plt.legend(fontsize='x-large') # 给图像加图例
plt.savefig('ml-vis.pdf') # 保存图像到PDF文件中
plt.show()

输出结果:

2.2.2 模型构建

import torch torch.seed()  # 设置随机种子
class Op(object):def __init__(self):passdef __call__(self, inputs):return self.forward(inputs)def forward(self, inputs):raise NotImplementedErrordef backward(self, inputs):raise NotImplementedError
# 线性算子
class Linear(Op):def __init__(self, input_size):"""输入:- input_size:模型要处理的数据特征向量长度"""self.input_size = input_size# 模型参数self.params = {}self.params['w'] = torch.randn(self.input_size, 1)self.params['b'] = torch.zeros([1])def __call__(self, X):return self.forward(X)# 前向函数def forward(self, X):N, D = X.shapeif self.input_size == 0:return torch.full(shape=[N, 1], fill_value=self.params['b'])assert D == self.input_size  # 输入数据维度合法性验证# 使用torch.matmul计算两个tensor的乘积y_pred = torch.matmul(X, self.params['w']) + self.params['b']return y_pred# 注意这里我们为了和后面章节统一,这里的X矩阵是由N个x向量的转置拼接成的,与原教材行向量表示方式不一致
input_size = 3
N = 2
X = torch.randn(N,input_size)  # 生成2个维度为3的数据
model = Linear(input_size)
y_pred = model(X)
print("y_pred:", y_pred)  # 输出结果的个数也是2个

y_pred: tensor([[ 0.7946],
[-3.1321]])

2.2.3 损失函数

回归任务中常用的评估指标是均方误差
均方误差(mean-square error, MSE)是反映估计量与被估计量之间差异程度的一种度量。

import torch
# 损失函数
def mean_squared_error(y_true, y_pred):"""输入:- y_true: tensor,样本真实标签- y_pred: tensor, 样本预测标签输出:- error: float,误差值"""assert y_true.shape[0] == y_pred.shape[0]# torch.square计算输入的平方值# torch.mean沿 axis 计算 x 的平均值,默认axis是None,则对输入的全部元素计算平均值。error = torch.mean(torch.square(y_true - y_pred))return error# 构造一个简单的样例进行测试:[N,1], N=2
y_true = torch.tensor([[-0.2], [4.9]], dtype=torch.float32)
y_pred = torch.tensor([[1.3], [2.5]], dtype=torch.float32)error = mean_squared_error(y_true=y_true, y_pred=y_pred).item()
print("error:", error)
error: 4.005000114440918

思考:没有除2合理么?谈谈自己的看法,写到实验报告。
合理,2只是一个常数,它不会影响均方误差的准确性。

2.2.4 模型优化

经验风险 ( Empirical Risk ),即在训练集上的平均损失。

 #模型优化
def optimizer_lsm(model, X, y, reg_lambda=0):"""输入:- model: 模型- X: tensor, 特征数据,shape=[N,D]- y: tensor,标签数据,shape=[N]- reg_lambda: float, 正则化系数,默认为0输出:- model: 优化好的模型"""N, D = X.shape# 对输入特征数据所有特征向量求平均x_bar_tran = torch.mean(X, axis=0).T# 求标签的均值,shape=[1]y_bar = torch.mean(y)# paddle.subtract通过广播的方式实现矩阵减向量x_sub =  torch.subtract(X, x_bar_tran)# 使用paddle.all判断输入tensor是否全0if  torch.all(x_sub == 0):model.params['b'] = y_barmodel.params['w'] = torch.zeros(shape=[D])return model# paddle.inverse求方阵的逆tmp =  torch.inverse( torch.matmul(x_sub.T, x_sub) +reg_lambda * torch.eye(num_rows=(D)))w =  torch.matmul(torch.matmul(tmp, x_sub.T), (y - y_bar))b = y_bar -  torch.matmul(x_bar_tran, w)model.params['b'] = bmodel.params['w'] =  torch.squeeze(w, axis=-1)return model

思考1. 为什么省略1/N了不影响效果?
它是个系数,对于求解优化的问题,它不会造成优化结果的改变。

思考 2. 什么是最小二乘法( Least Square Method , LSM )
最小二乘法主要是通过最小化误差的平方和寻找数据的最佳函数匹配。

2.2.5 模型训练

在准备了数据、模型、损失函数和参数学习的实现之后,我们开始模型的训练。在回归任务中,模型的评价指标和损失函数一致,都为均方误差。
通过上文实现的线性回归类来拟合训练数据,并输出模型在训练集上的损失。

input_size = 1
model = Linear(input_size)
model = optimizer_lsm(model,X_train.reshape([-1,1]),y_train.reshape([-1,1]))
print("w_pred:",model.params['w'].item(), "b_pred: ", model.params['b'].item())y_train_pred = model(X_train.reshape([-1,1])).squeeze()
train_error = mean_squared_error(y_true=y_train, y_pred=y_train_pred).item()
print("train error: ",train_error)

w_pred: 1.2005535364151 b_pred: 0.6063849329948425
train error: 5.124952793121338

2.2.6 模型评估

下面用训练好的模型预测一下测试集的标签,并计算在测试集上的损失。

y_test_pred = model(X_test.reshape([-1,1])).squeeze()
test_error = mean_squared_error(y_true=y_test, y_pred=y_test_pred).item()
print("test error: ",test_error)

test error: 3.3286447525024414

2.2.7 样本数量 & 正则化系数

1.调整训练数据的样本数量,由 100 调整到 5000,观察对模型性能的影响。

train error: 4.095644950866699

2.调整正则化系数,观察对模型性能的影响。

train error: 4.089155673980713

2.3 多项式回归

2.3.1 数据集构建

import math
import torch
import matplotlib.pyplot as plt
import numpy as np
# sin函数: sin(2 * pi * x)
def sin(x):y =torch.sin(2 * math.pi * x)return y
def create_toy_data(func, interval, sample_num, noise = 0.0, add_outlier = False, outlier_ratio = 0.001):# 均匀采样# 使用torch.rand在生成sample_num个随机数X = torch.rand(size = [sample_num]) * (interval[1]-interval[0]) + interval[0]y = func(X)# 生成高斯分布的标签噪声# 使用torch.normal生成0均值,noise标准差的数据epsilon = torch.tensor(np.random.normal(0,noise,size=y.shape[0]))y = y + epsilonif add_outlier:     # 生成额外的异常点outlier_num = int(len(y)*outlier_ratio)if outlier_num != 0:# 使用torch.randint生成服从均匀分布的、范围在[0, len(y))的随机Tensoroutlier_idx = torch.rand(len(y),shape = [outlier_num])y[outlier_idx] = y[outlier_idx] * 5return X, y
func = sin
interval = (0,1)
train_num = 15
test_num = 10
noise = 0.5 #0.1
X_train, y_train = create_toy_data(func=func, interval=interval, sample_num=train_num, noise = noise)
X_test, y_test = create_toy_data(func=func, interval=interval, sample_num=test_num, noise = noise)X_underlying = torch.linspace(interval[0],interval[1],steps=100)
y_underlying = sin(X_underlying)# 绘制图像
plt.rcParams['figure.figsize'] = (8.0, 6.0)
plt.scatter(X_train, y_train, facecolor="none", edgecolor='#e4007f', s=50, label="train data")
#plt.scatter(X_test, y_test, facecolor="none", edgecolor="r", s=50, label="test data")
plt.plot(X_underlying, y_underlying, c='#000000', label=r"$\sin(2\pi x)$")
plt.legend(fontsize='x-large')
plt.savefig('ml-vis2.pdf')
plt.show()

2.3.2 模型构建

套用求解线性回归参数的方法来求解多项式回归参数

import  torch
# 多项式转换
def polynomial_basis_function(x, degree=2):if degree == 0:return torch.ones(shape=x.shape, dtype=torch.loat32)x_tmp = xx_result = x_tmpfor i in range(2, degree + 1):x_tmp = torch.multiply(x_tmp, x)  # 逐元素相乘x_result = torch.concat((x_result, x_tmp), axis=-1)return x_result# 简单测试
data = [[2], [3], [4]]
X = torch.as_tensor(data=data, dtype=torch.float32)
degree = 3
transformed_X = polynomial_basis_function(X, degree=degree)
print("转换前:", X)
print("阶数为", degree, "转换后:", transformed_X)

转换前: tensor([[2.],
[3.],
[4.]])
阶数为 3 转换后: tensor([[ 2., 4., 8.],
[ 3., 9., 27.],
[ 4., 16., 64.]])

2.3.3 模型训练

对于多项式回归,可以同样使用前面线性回归中定义的LinearRegression算子、训练函数train、均方误差函数mean_squared_error。

 for i, degree in enumerate([0, 1, 3, 8]):  # []中为多项式的阶数model = Linear(degree)X_train_transformed = polynomial_basis_function(X_train.reshape([-1, 1]), degree)X_underlying_transformed = polynomial_basis_function(X_underlying.reshape([-1, 1]), degree)model = optimizer_lsm(model, X_train_transformed, y_train.reshape([-1, 1]))  # 拟合得到参数y_underlying_pred = model(X_underlying_transformed).squeeze()print(model.params)# 绘制图像plt.subplot(2, 2, i + 1)plt.scatter(X_train, y_train, facecolor="none", edgecolor='#e4007f', s=50, label="train data")plt.plot(X_underlying, y_underlying, c='#000000', label=r"$\sin(2\pi x)$")plt.plot(X_underlying, y_underlying_pred, c='#f19ec2', label="predicted function")plt.ylim(-2, 1.5)plt.annotate("M={}".format(degree), xy=(0.95, -1.4))# plt.legend(bbox_to_anchor=(1.05, 0.64), loc=2, borderaxespad=0.)
plt.legend(loc='lower left', fontsize='x-large')
plt.savefig('ml-vis3.pdf')
plt.show()

2.3.4 模型评估

# 训练误差和测试误差
training_errors = []
test_errors = []
distribution_errors = []# 遍历多项式阶数
for i in range(9):model = Linear(i)X_train_transformed = polynomial_basis_function(X_train.reshape([-1, 1]), i)X_test_transformed = polynomial_basis_function(X_test.reshape([-1, 1]), i)X_underlying_transformed = polynomial_basis_function(X_underlying.reshape([-1, 1]), i)optimizer_lsm(model, X_train_transformed, y_train.reshape([-1, 1]))y_train_pred = model(X_train_transformed).squeeze()y_test_pred = model(X_test_transformed).squeeze()y_underlying_pred = model(X_underlying_transformed).squeeze()train_mse = mean_squared_error(y_true=y_train, y_pred=y_train_pred).item()training_errors.append(train_mse)test_mse = mean_squared_error(y_true=y_test, y_pred=y_test_pred).item()test_errors.append(test_mse)# distribution_mse = mean_squared_error(y_true=y_underlying, y_pred=y_underlying_pred).item()# distribution_errors.append(distribution_mse)print("train errors: \n", training_errors)
print("test errors: \n", test_errors)
# print ("distribution errors: \n", distribution_errors)# 绘制图片
plt.rcParams['figure.figsize'] = (8.0, 6.0)
plt.plot(training_errors, '-.', mfc="none", mec='#e4007f', ms=10, c='#e4007f', label="Training")
plt.plot(test_errors, '--', mfc="none", mec='#f19ec2', ms=10, c='#f19ec2', label="Test")
# plt.plot(distribution_errors, '-', mfc="none", mec="#3D3D3F", ms=10, c="#3D3D3F", label="Distribution")
plt.legend(fontsize='x-large')
plt.xlabel("degree")
plt.ylabel("MSE")
plt.savefig('ml-mse-error.pdf')
plt.show()

对于模型过拟合的情况,可以引入正则化方法.

degree = 8 # 多项式阶数
reg_lambda = 0.0001 # 正则化系数X_train_transformed = polynomial_basis_function(X_train.reshape([-1,1]), degree)
X_test_transformed = polynomial_basis_function(X_test.reshape([-1,1]), degree)
X_underlying_transformed = polynomial_basis_function(X_underlying.reshape([-1,1]), degree)model = Linear(degree) optimizer_lsm(model,X_train_transformed,y_train.reshape([-1,1]))y_test_pred=model(X_test_transformed).squeeze()
y_underlying_pred=model(X_underlying_transformed).squeeze()model_reg = Linear(degree) optimizer_lsm(model_reg,X_train_transformed,y_train.reshape([-1,1]),reg_lambda=reg_lambda)y_test_pred_reg=model_reg(X_test_transformed).squeeze()
y_underlying_pred_reg=model_reg(X_underlying_transformed).squeeze()mse = mean_squared_error(y_true = y_test, y_pred = y_test_pred).item()
print("mse:",mse)
mes_reg = mean_squared_error(y_true = y_test, y_pred = y_test_pred_reg).item()
print("mse_with_l2_reg:",mes_reg)# 绘制图像
plt.scatter(X_train, y_train, facecolor="none", edgecolor="#e4007f", s=50, label="train data")
plt.plot(X_underlying, y_underlying, c='#000000', label=r"$\sin(2\pi x)$")
plt.plot(X_underlying, y_underlying_pred, c='#e4007f', linestyle="--", label="$deg. = 8$")
plt.plot(X_underlying, y_underlying_pred_reg, c='#f19ec2', linestyle="-.", label="$deg. = 8, \ell_2 reg$")
plt.ylim(-1.5, 1.5)
plt.annotate("lambda={}".format(reg_lambda), xy=(0.82, -1.4))
plt.legend(fontsize='large')
plt.savefig('ml-vis4.pdf')
plt.show()

2.4 Runner类介绍

机器学习方法流程包括数据集构建、模型构建、损失函数定义、优化器、模型训练、模型评价、模型预测等环节。

为了更方便地将上述环节规范化,我们将机器学习模型的基本要素封装成一个Runner类。

除上述提到的要素外,再加上模型保存、模型加载等功能。

Runner类的成员函数定义如下:

__init__函数:实例化Runner类,需要传入模型、损失函数、优化器和评价指标等;
train函数:模型训练,指定模型训练需要的训练集和验证集;
evaluate函数:通过对训练好的模型进行评价,在验证集或测试集上查看模型训练效果;
predict函数:选取一条数据对训练好的模型进行预测;
save_model函数:模型在训练过程和训练结束后需要进行保存;
load_model函数:调用加载之前保存的模型。

class Runner(object):def __init__(self, model, optimizer, loss_fn, metric):self.model = model         # 模型self.optimizer = optimizer # 优化器self.loss_fn = loss_fn     # 损失函数   self.metric = metric       # 评估指标# 模型训练def train(self, train_dataset, dev_dataset=None, **kwargs):pass# 模型评价def evaluate(self, data_set, **kwargs):pass# 模型预测def predict(self, x, **kwargs):pass# 模型保存def save_model(self, save_path):pass# 模型加载def load_model(self, model_path):pass
# optimizer_lsm
def optimizer_lsm(model, X, y, reg_lambda=0):N, D = X.shape# 对输入特征数据所有特征向量求平均x_bar_tran = torch.mean(X, axis=0).T# 求标签的均值,shape=[1]y_bar = torch.mean(y)# torch.subtract通过广播的方式实现矩阵减向量x_sub = torch.subtract(X, x_bar_tran)# 使用torch.all判断输入tensor是否全0if torch.all(x_sub == 0):model.params['b'] = y_barmodel.params['w'] = torch.zeros(shape=[D])return model# torch.inverse求方阵的逆tmp = torch.inverse(torch.matmul(x_sub.T, x_sub) +reg_lambda * torch.eye(D))w = torch.matmul(torch.matmul(tmp, x_sub.T), (y - y_bar))b = y_bar - torch.matmul(x_bar_tran, w)model.params['b'] = bmodel.params['w'] = torch.squeeze(w, axis=-1)return model

2.5 基于线性回归的波士顿房价预测

使用线性回归来对马萨诸塞州波士顿郊区的房屋进行预测。

实验流程主要包含如下5个步骤:

数据处理:包括数据清洗(缺失值和异常值处理)、数据集划分,以便数据可以被模型正常读取,并具有良好的泛化性;
模型构建:定义线性回归模型类;
训练配置:训练相关的一些配置,如:优化算法、评价指标等;
组装训练框架Runner:Runner用于管理模型训练和测试过程;
模型训练和测试:利用Runner进行模型训练和测试。

2.5.1 数据处理

2.5.1.1 数据清洗

import pandas as pd # 开源数据分析和操作工具# 利用pandas加载波士顿房价的数据集
data=pd.read_csv(r"C:\Users\320\Documents\Tencent Files\1377916621\FileRecv/boston_house_prices.csv")
# 查看各字段缺失值统计情况
print(data.isna().sum())

从输出结果看,波士顿房价预测数据集中不存在缺失值的情况。
异常值处理:通过箱线图直观的显示数据分布,并观测数据中的异常值。箱线图一般由五个统计值组成:最大值、上四分位、中位数、下四分位和最小值。一般来说,观测到的数据大于最大估计值或者小于最小估计值则判断为异常值,其中:
最大估计值=上四分位+1.5∗(上四分位−下四分位)
最小估计值=下四分位−1.5∗(上四分位−下四分位)

import matplotlib.pyplot as plt # 可视化工具# 箱线图查看异常值分布
def boxplot(data, fig_name):# 绘制每个属性的箱线图data_col = list(data.columns)# 连续画几个图片plt.figure(figsize=(5, 5), dpi=300)# 子图调整plt.subplots_adjust(wspace=0.6)# 每个特征画一个箱线图for i, col_name in enumerate(data_col):plt.subplot(3, 5, i+1)# 画箱线图plt.boxplot(data[col_name], showmeans=True, meanprops={"markersize":1,"marker":"D","markeredgecolor":'#f19ec2'}, # 均值的属性medianprops={"color":'#e4007f'}, # 中位数线的属性whiskerprops={"color":'#e4007f', "linewidth":0.4, 'linestyle':"--"},flierprops={"markersize":0.4},) # 图名plt.title(col_name, fontdict={"size":5}, pad=2)# y方向刻度plt.yticks(fontsize=4, rotation=90)plt.tick_params(pad=0.5)# x方向刻度plt.xticks([])plt.savefig(fig_name)plt.show()boxplot(data, 'ml-vis5.pdf')

使用四分位值筛选出箱线图中分布的异常值,并将这些数据视为噪声,其将被临界值取代,代码实现如下:

# 四分位处理异常值
num_features=data.select_dtypes(exclude=['object','bool']).columns.tolist()for feature in num_features:if feature =='CHAS':continueQ1  = data[feature].quantile(q=0.25) # 下四分位Q3  = data[feature].quantile(q=0.75) # 上四分位IQR = Q3-Q1 top = Q3+1.5*IQR # 最大估计值bot = Q1-1.5*IQR # 最小估计值values=data[feature].valuesvalues[values > top] = top # 临界值取代噪声values[values < bot] = bot # 临界值取代噪声data[feature] = values.astype(data[feature].dtypes)# 再次查看箱线图,异常值已被临界值替换(数据量较多或本身异常值较少时,箱线图展示会不容易体现出来)
boxplot(data, 'ml-vis6.pdf')

2.5.1.2 数据集划分

import torch
torch.seed()
# 划分训练集和测试集
def train_test_split(X, y, train_percent=0.8):n = len(X)shuffled_indices = torch.randperm(n) # 返回一个数值在0到n-1、随机排列的1-D Tensortrain_set_size = int(n*train_percent)train_indices = shuffled_indices[:train_set_size]test_indices = shuffled_indices[train_set_size:]X = X.valuesy = y.valuesX_train=X[train_indices]y_train = y[train_indices]X_test = X[test_indices]y_test = y[test_indices]return X_train, X_test, y_train, y_test
X = data.drop(['MEDV'], axis=1)
y = data['MEDV']
X_train, X_test, y_train, y_test = train_test_split(X,y)# X_train每一行是个样本,shape[N,D]

2.5.1.3特征工程

import torch
X_train = torch.tensor(X_train ,dtype=torch.float32)
X_test = torch.tensor(X_test ,dtype=torch.float32)
y_train = torch.tensor(y_train ,dtype=torch.float32)
y_test = torch.tensor(y_test ,dtype=torch.float32)
X_min = torch.min(X_train)
X_max = torch.max(X_train)
X_train = (X_trai n -X_min ) /(X_ma x -X_min)
X_test  = (X_tes t -X_min ) /(X_ma x -X_min)
# 训练集构造
train_datase t =(X_train ,y_train)
# 测试集构造
test_datase t =(X_test ,y_test)
print(train_dataset)
print(test_dataset)

2.5.2 模型构建

from nndl.op import Linear
# 模型实例化
input_size = 12
model=Linear(input_size)
#  nndl.op
import torch torch.seed()  # 设置随机种子
class Op(object):def __init__(self):passdef __call__(self, inputs):return self.forward(inputs)def forward(self, inputs):raise NotImplementedErrordef backward(self, inputs):raise NotImplementedError
# 线性算子
class Linear(Op):def __init__(self, input_size):self.input_size = input_size# 模型参数self.params = {}self.params['w'] = torch.randn(self.input_size, 1)self.params['b'] = torch.zeros([1])def __call__(self, X):return self.forward(X)# 前向函数def forward(self, X):N, D = X.shapeif self.input_size == 0:return torch.full(shape=[N, 1], fill_value=self.params['b'])assert D == self.input_size  # 输入数据维度合法性验证# 使用torch.matmul计算两个tensor的乘积y_pred = torch.matmul(X, self.params['w']) + self.params['b']sreturn y_pred

2.5.3 完善Runner类

模型定义好后,围绕模型需要配置损失函数、优化器、评估、测试等信息,以及模型相关的一些其他信息(如模型存储路径等)。
在本章中使用的Runner类为V1版本。其中训练过程通过直接求解解析解的方式得到模型参数,没有模型优化及计算损失函数过程,模型训练结束后保存模型参数。
训练配置中定义:
训练环境,如GPU还是CPU,本案例不涉及;
优化器,本案例不涉及;
损失函数,本案例通过平方损失函数得到模型参数的解析解;
评估指标,本案例利用MSE评估模型效果。
在测试集上使用MSE对模型性能进行评估。

import torch.nn as nn
mse_loss = nn.MSELoss()
import torch
import os
from nndl.opitimizer import optimizer_lsm
class Runner(object):def __init__(self, model, optimizer, loss_fn, metric):# 优化器和损失函数为None,不再关注# 模型self.model = model# 评估指标self.metric = metric# 优化器self.optimizer = optimizerdef train(self, dataset, reg_lambda, model_dir):X, y = datasetself.optimizer(self.model, X, y, reg_lambda)# 保存模型self.save_model(model_dir)def evaluate(self, dataset, **kwargs):X, y = datasety_pred = self.model(X)result = self.metric(y_pred, y)return resultdef predict(self, X, **kwargs):return self.model(X)def save_model(self, model_dir):if not os.path.exists(model_dir):os.makedirs(model_dir)params_saved_path = os.path.join(model_dir, 'params.pdtensor')torch.save(model.params, params_saved_path)def load_model(self, model_dir):params_saved_path = os.path.join(model_dir, 'params.pdtensor')self.model.params = torch.load(params_saved_path)optimizer = optimizer_lsm# 实例化Runner
runner = Runner(model, optimizer=optimizer, loss_fn=None, metric=mse_loss)
#  optimizer_lsm
def optimizer_lsm(model, X, y, reg_lambda=0):N, D = X.shape# 对输入特征数据所有特征向量求平均x_bar_tran = torch.mean(X, axis=0).T# 求标签的均值,shape=[1]y_bar = torch.mean(y)# torch.subtract通过广播的方式实现矩阵减向量x_sub = torch.subtract(X, x_bar_tran)# 使用torch.all判断输入tensor是否全0if torch.all(x_sub == 0):model.params['b'] = y_barmodel.params['w'] = torch.zeros(shape=[D])return model# torch.inverse求方阵的逆tmp = torch.inverse(torch.matmul(x_sub.T, x_sub) +reg_lambda * torch.eye(num_rows=(D)))w = torch.matmul(torch.matmul(tmp, x_sub.T), (y - y_bar))b = y_bar - torch.matmul(x_bar_tran, w)model.params['b'] = bmodel.params['w'] = torch.squeeze(w, axis=-1)return model

2.5.4 模型训练

在组装完成Runner之后,我们将开始进行模型训练、评估和测试。首先,我们先实例化Runner,然后开始进行装配训练环境,接下来就可以开始训练了,相关代码如下:

# 模型保存文件夹
saved_dir = '/home/aistudio/work/models'# 启动训练
runner.train(train_dataset,reg_lambda=0,model_dir=saved_dir)

打印出训练得到的权重:

columns_list = data.columns.to_list()
weights = runner.model.params['w'].tolist()
b = runner.model.params['b'].item()for i in range(len(weights)):print(columns_list[i],"weight:",weights[i])print("b:",b)

CRIM weight: -545.2598266601562
ZN weight: 22.065792083740234
INDUS weight: -8.44003677368164
CHAS weight: 1530.1904296875
NOX weight: -8955.4931640625
RM weight: 2347.146484375
AGE weight: -5.644048690795898
DIS weight: -707.4413452148438
RAD weight: 271.2647705078125
TAX weight: -6.599415302276611
PTRATIO weight: -592.3955688476562
LSTAT weight: -313.0545654296875
b: 35.074371337890625

2.5.5 模型测试

# 加载模型权重
runner.load_model(saved_dir)
mse = runner.evaluate(test_dataset)
print('MSE:', mse.item())

MSE: 14.380061149597168

2.5.6 模型预测

runner.load_model(saved_dir)
pred = runner.predict(X_test[:1])
print("真实房价:",y_test[:1].item())
print("预测的房价:",pred.item())

真实房价: 10.899999618530273
预测的房价: 15.171201705932617

问题1:使用类实现机器学习模型的基本要素有什么优点?
(1)可以提高程序的效率。
(2)易维护:如果需要改变需求,那么也只需要在局部模块进行维护,大大降低了成本。
(3)易扩展:系统更灵活、更容易扩展,而且成本较低。

问题2:算子op、优化器opitimizer放在单独的文件中,主程序在使用时调用该文件。这样做有什么优点?
简洁明了,需要修改时,只需要改其中一部分,不需要进行全篇改动。
问题3:线性回归通常使用平方损失函数,能否使用交叉熵损失函数?为什么?
不能,平方损失函数看重每一个输出结果,交叉熵损失函数只看重正确的结果。因此平方损失函数还和错误结果有关,所以平方损失函数会使正确的分类变大,还会让错误分类都变得更加平均,但实际中后面得调整是没必要的,但是对于回归问题这样的考虑是比较重要得,因而回归问题上使用交叉熵不合适。

NNDL 实验三 线性回归相关推荐

  1. 回顾 深度学习 实验三 线性回归

    小笔记: 线性回归 1. 生成数据集 2. 模型构建 3. 模型优化 4. 模型优化 5. 模型训练 2. 多项式回归 1. 数据集构建 2. 模型构建 3. 模型训练 4. 模型评估 3. Runn ...

  2. NNDL 实验三 线性模型

    目录 2.2 实现一个简单的线性模型 引言 2.2.1 数据集构建 2.2.2模型构建 2.2.3损失函数 2.2.4 模型优化 2.2.5模型训练 2.2.6模型评估 2.3多项式回归 2.3.1数 ...

  3. NNDL 实验六 卷积神经网络(3) LeNet实现MNIST

    目录 5.3 基于LeNet实现手写体数字识别实验 5.3.1 数据 5.3.1.1 数据预处理 5.3.2 模型构建 1.测试LeNet-5模型,构造一个形状为 [1,1,32,32]的输入数据送入 ...

  4. NNDL 实验八 网络优化与正则化(3)不同优化算法比较

    目录 7.3.1 优化算法的实验设定 7.3.1.1 2D可视化实验 7.3.1.2 简单拟合实验 与Torch API对比,验证正确性 7.3.2 学习率调整 7.3.2.1 AdaGrad算法 7 ...

  5. 机器学习实验一线性回归

    机器学习实验一线性回归 实验题目 1 . 一元线性回归 题目: 应用一元线性回归预测移动餐车的利润.假设你是一家餐饮连锁店的CEO, 考虑在不同的城市开辟新店.该餐饮店已在许多城市拥有移动餐车,现有各 ...

  6. 机器学习实验1 / 线性回归

    实验一 线性回归 源码地址:https://github.com/LinXiaoDe/MachineLearning 参考地址 Aaron:https://blog.csdn.net/Aaron_19 ...

  7. 实验三-密码破解技术

    学   号 201421430010   中国人民公安大学 Chinese people' public security university 网络对抗技术 实验报告   实验三 密码破解技术   ...

  8. 计算机导论excel,[计算机导论实验三Excel.doc

    [计算机导论实验三Excel 实验三 Excel表格处理 实验报告 姓名(学号):_______________ 年级(专业):_____ ________成绩:________ 实验时间:_____ ...

  9. 20155222卢梓杰 实验三 免杀原理与实践

    实验三 免杀原理与实践 1.正确使用msf编码器,msfvenom生成如jar之类的其他文件,veil-evasion,自己利用shellcode编程等免杀工具或技巧 实验步骤如下 1.先对实验二中生 ...

  10. 实验三 JSP应用开发进阶

    全部:https://download.csdn.net/download/weixin_42859280/11218260 实验三 JSP应用开发进阶:PDF版本[已经完成所有代码] 想看文档上面有 ...

最新文章

  1. linux 下面安装 .sh 格式的软件
  2. word树状分支图_交互设计技能 | 抛弃Word,试试用Excel和Xmind来整理思路吧
  3. 主线程 java_java-在子线程中执行主线程方法
  4. VTK:可视化之MultipleRenderWindows
  5. html5 职工入职后台管理系统_ChemCMS是一款基于GO+PHP+MYSQL+HTML5构建的化学内容管理系统
  6. 电脑要什么配置好_收藏好!设计专业学生电脑配置推荐
  7. java笔试必考知识_面试必备:常考Java基础知识总结(持续更新)
  8. Webgoat学习笔记1
  9. Java内部类定义与调用
  10. 最新版校园招聘进大厂系列----------(4)京东篇 -----未完待续
  11. 鼠标测试软件m,赛钛客CYBORG M.M.O.7鼠标
  12. 在线制作证件照教程,只需30秒
  13. <自由之路>LeetCode每日一题(DFS + 记忆化搜索)
  14. linux 查看java_opts_java_opts 参数与JVM内存调优
  15. java抓取百度搜索结果,一个百度搜索结果内容获取爬虫
  16. SSH概述与配置文件说明
  17. Latex中用Bibtex来引用文献
  18. 深度学习中的正则化方法
  19. python 最大子序列之和
  20. 《卓有成效的管理者》读后感

热门文章

  1. mike21换成计算机名称,[转载]mike21基本介绍
  2. 计算机选题方向怎么写,计算机方面方向论文选题 计算机方面论文题目怎么定...
  3. 网站上部署Live2D模型(moc3格式)
  4. 高分GF与环境HJ系列国产卫星遥感影像数据图像免费批量下载方法
  5. 德标螺纹规格对照表_螺栓螺母德标、欧标、国标对照表
  6. 郝斌_数据结构入门笔记
  7. Hbase常用操作命令
  8. VC定时器SetTimer函数
  9. 中国生物能源行业市场规模预测及未来战略规划建议报告2022-2028年
  10. 基于EEG的睡眠分期算法记录3-使用决策树多类支持向量机的自动睡眠阶段分类