目录

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.2 数据清洗

2.5.1.3 数据集划分

2.5.1.4 特征工程

2.5.2 模型构建

2.5.3 完善Runner类

2.5.4 模型训练

2.5.5 模型测试

2.5.6 模型预测


2.2 线性回归

2.2.1 数据集构建

构造一个小的回归数据集:

生成 150 个带噪音的样本,其中 100 个训练样本,50 个测试样本,并打印出训练数据的可视化分布。

import torch
from matplotlib import pyplot as plt# 真实函数的参数缺省值为 w=1.2,b=0.5
def linear_func(x, w=1.2, b=0.5):y = w*x + breturn ydef create_toy_data(func, interval, sample_num, noise=0.0, add_outlier=False, outlier_ratio=0.001):# 均匀采样X = torch.rand([sample_num]) * (interval[1]-interval[0]) + interval[0]y = func(X)# 生成高斯分布的标签噪声epsilon = torch.normal(0, noise, y.shape)y = y + epsilonif add_outlier:     # 生成额外的异常点outlier_num = int(len(y)*outlier_ratio)if outlier_num != 0:outlier_idx = torch.randint(len(y), [outlier_num])y[outlier_idx] = y[outlier_idx] * 5return X, yfunc = 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)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='red', s=50, label="train data")
plt.scatter(X_test, y_test, facecolor="none", edgecolor='blue', 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()

运行结果:

(注:使用torch.normal(0,noise,y.shape)生成0均值,noise标准差的数据)

2.2.2 模型构建

线性模型定义为:

其中权重向量w和偏置b都是可学习的参数。

在实践中,为了提高预测样本的效率,我们通常会将N样本归为一组进行成批地预测,这样可以更好地利用GPU设备的并行计算能力。

y=Xw+b

其中X为N个样本的特征矩阵,y为N个预测值组成的列向量。

(注:在实践中,样本的矩阵X是由N个x的行向量组成。)

import torch
torch.manual_seed(11)  # 设置随机种子# 线性算子
class Linear( ):def __init__(self, input_size):self.input_size = input_size# 模型参数self.params = {}self.params['w'] = torch.randn(self.input_size, 1, dtype=torch.float32)self.params['b'] = torch.zeros(1, dtype=torch.float32)def __call__(self, X):return self.forward(X)# 前向函数def forward(self, X):N, D = X.shapeif self.input_size == 0:return torch.full((N, 1), self.params['b'])assert D == self.input_size  # 输入数据维度合法性验证y_pred = torch.matmul(X, self.params['w']) + self.params['b']return y_predinput_size = 3
N = 2
X = torch.randn(N, input_size, dtype=torch.float32)  # 生成2个维度为3的数据
model = Linear(input_size)
y_pred = model(X)
print("y_pred:", y_pred)   # 输出结果的个数也是2个

运行结果:

2.2.3 损失函数

回归任务中常用的评估指标是均方误差,均方误差是反映估计量与被估计量之间差异程度的一种度量。(回归任务是对连续值的预测)

import torchdef mean_squared_error(y_true, y_pred):assert y_true.shape[0] == y_pred.shape[0]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)

运行结果:(注:代码实现中没有除2)

思考:没有除2合理么?

合理,除以2作用是消除均方误差中平方项时存在的2的倍数,不除以2也能够在优化时进行正确计算。

2.2.4 模型优化

经验风险即在训练集上的平均损失。

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)x_sub = torch.subtract(X, x_bar_tran)if torch.all(x_sub) == 0:model.params['b'] = y_barmodel.params['w'] = torch.zeros(D)return modeltmp = 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

(注:torch.eye(n,m)函数的作用为:返回一个2维张量,对角线位置全1,其它位置全0,n表示行数,m表示列数,默认等于n)

思考1:为什么省略了不影响效果?

1/N为常数, 求偏导后不会影响收敛结果。

思考2:什么是最小二乘法?
最小二乘法是基于均方误差最小化进行模型求解的方法。

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)

运行结果:

model_large = Linear(input_size)
model_large = optimizer_lsm(model_large, X_train_large.reshape([-1, 1]), y_train_large.reshape([-1, 1]))
print("w_pred large:", model_large.params['w'].item(), "b_pred large: ", model_large.params['b'].item())
y_train_pred_large = model_large(X_train_large.reshape([-1,1])).squeeze()
train_error_large = mean_squared_error(y_true=y_train_large, y_pred=y_train_pred_large).item()
print("train error large: ", train_error_large)

运行结果:

由结果可知,预测值与真实值(w=1.2,b=0.5)存在着一定的差距。

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)

运行结果:

y_test_pred_large = model_large(X_test.reshape([-1,1])).squeeze()
test_error_large = mean_squared_error(y_true=y_test, y_pred=y_test_pred_large).item()
print("test error large: ", test_error_large)

运行结果:

2.2.7 样本数量 & 正则化系数

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

增加训练样本后,w和b的预测值更接近真实值(w=1.2,b=0.5)

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

正则化系数为0.1时:

 正则化系数为0.1时:

正则化系数不断变小,损失越来越小

2.3 多项式回归

2.3.1 数据集构建

构建训练和测试数据,其中:

训练数样本 15 个,测试样本 10 个,高斯噪声标准差为 0.1,自变量范围为 (0,1)。

import mathdef sin(x):y = torch.sin(2 * math.pi * x)return y# 生成数据
func = sin
interval = (0, 1)
train_num = 15
test_num = 10
noise = 0.5
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], 100)
y_underlying = sin(X_underlying)# 绘制图像
plt.rcParams['figure.figsize'] = (8.0, 6.0)
plt.scatter(X_train, y_train, marker='*', facecolor="none", edgecolor='red', s=50, label="train data")
plt.scatter(X_test, y_test, facecolor="none", edgecolor="blue", 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()

运行结果:

在输出结果中,黑色的曲线是周期为 1 的 sin 函数曲线,蓝色的圆圈为生成的测试样本数据,红色的五角星为生成的训练样本数据。

2.3.2 模型构建

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

# 多项式转换
def polynomial_basis_function(x, degree=2):if degree == 0:return torch.ones(x.shape, dtype=torch.float32)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), dim=-1)return x_result# 简单测试
data = [[2], [3], [4]]
X = torch.tensor(data=data, dtype=torch.float32)
degree = 3
transformed_X = polynomial_basis_function(X, degree=degree)
print("转换前:\n", X)
print("阶数为", degree, "转换后:\n", transformed_X)

运行结果:

2.3.3 模型训练

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

plt.rcParams['figure.figsize'] = (12.0, 8.0)
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, marker='*', facecolor="none", edgecolor='red', 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(loc='lower left', fontsize='x-large')
plt.savefig('ml-vis3.pdf')
plt.show()

(注:for i, degree in enumerate([0, 1, 3, 8]):的 []中的数为多项式的阶数 )

运行结果:

观察可视化结果,粉色的曲线表示不同阶多项式分布拟合数据的结果:

  • 当 M=0或 M=1 时,拟合曲线较简单,模型欠拟合;
  • 当 M=3时,模型拟合最为合理;
  • 当 M=8时,拟合曲线较复杂,模型过拟合。

2.3.4 模型评估

通过均方误差来衡量训练误差、测试误差以及在没有噪音的加入下sin函数值与多项式回归值之间的误差,更加真实地反映拟合结果。多项式分布阶数从0到8进行遍历。

# 训练误差和测试误差
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)print("train errors: \n", training_errors)
print("test errors: \n", test_errors)
# 绘制图片
plt.rcParams['figure.figsize'] = (8.0, 6.0)
plt.plot(training_errors, '-.', mfc="none", mec='#e4007f', ms=10, c='red', label="Training")
plt.plot(test_errors, '--', mfc="none", mec='#f19ec2', ms=10, c='blue', label="Test")
plt.legend(fontsize='x-large')
plt.xlabel("degree")
plt.ylabel("MSE")
plt.savefig('ml-mse-error.pdf')
plt.show()

运行结果:

train errors: [0.5308755040168762, 0.2900596559047699, 0.2807285189628601, 0.16659073531627655, 0.16653773188591003, 0.16176961362361908, 0.1875329464673996, 0.1526075154542923, 0.16906647384166718]
test errors: [0.3803015351295471, 0.35263150930404663, 0.412276029586792, 0.2859075665473938, 0.2827174961566925, 0.34233444929122925, 0.32521989941596985, 0.8635300397872925, 0.7909313440322876]

观察可视化结果:

  • 当阶数较低的时候,模型的表示能力有限,训练误差和测试误差都很高,代表模型欠拟合;
  • 当阶数较高的时候,模型表示能力强,但将训练数据中的噪声也作为特征进行学习,一般情况下训练误差继续降低而测试误差显著升高,代表模型过拟合。

对于模型过拟合的情况,可以引入正则化方法,通过向误差函数中添加一个惩罚项来避免系数倾向于较大的取值。

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='red', linestyle="--", label="$deg. = 8$")
plt.plot(X_underlying, y_underlying_pred_reg, c='blue', 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函数:调用加载之前保存的模型。

Runner类的框架定义如下: 

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

Runner类的流程如图2.8所示,可以分为 4 个阶段:

  1. 初始化阶段:传入模型、损失函数、优化器和评价指标。
  2. 模型训练阶段:基于训练集调用train()函数训练模型,基于验证集通过evaluate()函数验证模型。通过save_model()函数保存模型。
  3. 模型评价阶段:基于测试集通过evaluate()函数得到指标性能。
  4. 模型预测阶段:给定样本,通过predict()函数得到该样本标签。

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

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

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

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

2.5.1 数据处理

2.5.1.2 数据清洗

对数据集中的缺失值或异常值等情况进行分析和处理,保证数据可以被模型正常读取。

1、缺失值分析

通过isna()方法判断数据中各元素是否缺失,然后通过sum()方法统计每个字段缺失情况,代码实现如下:

import pandas as pddata = pd.read_csv("boston_house_prices.csv")  # 利用pandas加载波士顿房价的数据集
print(data.isna().sum())  # 查看各字段缺失值统计情况

运行结果:

从输出结果看,数据集中不存在缺失值的情况。

2、异常值处理

通过箱线图直观的显示数据分布,并观测数据中的异常值。箱线图一般由五个统计值组成:最大值、上四分位、中位数、下四分位和最小值。一般来说,观测到的数据大于最大估计值或者小于最小估计值则判断为异常值,其中

最大估计值=上四分位+1.5∗(上四分位−下四分位)

最小估计值=下四分位−1.5∗(上四分位−下四分位)

import pandas as pd
import matplotlib.pyplot as pltdata = pd.read_csv("boston_house_prices.csv")  # 利用pandas加载波士顿房价的数据集
print(data.isna().sum())  # 查看各字段缺失值统计情况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": "#C54680"},  # 均值的属性medianprops={"color": "#946279"},  # 中位数线的属性whiskerprops={"color": "#8E004D", "linewidth": 0.4, 'linestyle': "--"},flierprops={"markersize": 0.4},)  # 画箱线图plt.title(col_name, fontdict={"size": 5}, pad=2)plt.yticks(fontsize=4, rotation=90)  # y方向刻度plt.tick_params(pad=0.5)plt.xticks([])  # x方向刻度plt.savefig(fig_name)plt.show()boxplot(data, 'ml-vis5.pdf')

运行结果:

图2.4是箱线图的一个示例,可对照查看具体含义。

从输出结果看,数据中存在较多的异常值(图中上下边缘以外的空心小圆圈)。

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

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 - Q1top = 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.3 数据集划分

本实验比较简单,将数据集划分为两份:训练集和测试集,不包括验证集。

具体代码如下:

import torch
torch.manual_seed(11)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_testX = data.drop(['MEDV'], axis=1)
y = data['MEDV']X_train, X_test, y_train, y_test = train_test_split(X, y)

2.5.1.4 特征工程

为了消除纲量对数据特征之间影响,在模型训练前,需要对特征数据进行归一化处理,将数据缩放到[0, 1]区间内,使得不同特征之间具有可比性。

代码实现如下:

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, dim=0)
X_max = torch.max(X_train, dim=0)
X_train = (X_train-X_min.values)/(X_max.values-X_min.values)
X_test = (X_test-X_min.values)/(X_max.values-X_min.values)
train_dataset = (X_train, y_train)  # 训练集构造
test_dataset = (X_test, y_test)  # 测试集构造

(注:在计算x_train和x_test时,x_min和x_max使用.values才能参与计算)

2.5.2 模型构建

实例化一个线性回归模型,特征维度为 12:

from nndl.op import Linear
# 模型实例化
input_size = 12
model = Linear(input_size)

# op.py
import torchtorch.manual_seed(10)  # 设置随机种子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_sizeself.params = {}self.params['w'] = torch.randn(self.input_size, 1, dtype=torch.float32)self.params['b'] = torch.zeros(1, dtype=torch.float32)def __call__(self, X):return self.forward(X)def forward(self, X):N, D = X.shapeif self.input_size == 0:return torch.full([N, 1], fill_value=self.params['b'])assert D == self.input_size  # 输入数据维度合法性验证y_pred = torch.matmul(X, self.params['w']) + self.params['b']return y_pred

2.5.3 完善Runner类

模型定义好后,围绕模型需要配置损失函数、优化器、评估、测试等信息,以及模型相关的一些其他信息(如模型存储路径等)。

在本章中使用的Runner类为V1版本。其中训练过程通过直接求解解析解的方式得到模型参数,没有模型优化及计算损失函数过程,模型训练结束后保存模型参数。

训练配置中定义:

  • 训练环境,如GPU还是CPU,本案例不涉及;
  • 优化器,本案例不涉及;
  • 损失函数,本案例通过平方损失函数得到模型参数的解析解;
  • 评估指标,本案例利用MSE评估模型效果。

在测试集上使用MSE对模型性能进行评估。

import torch.nn as nn
mse_loss = nn.MSELoss()

具体实现如下:

import os
import torch
from nndl.opitimizer import optimizer_lsmclass 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(model, optimizer=optimizer, loss_fn=None, metric=mse_loss)  # 实例化Runner

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、PTRATIO等的权重为负数,表示该镇的人均犯罪率与房价负相关,学生与教师比例越大,房价越低。CHAS和RAD等为正,表示到径向公路的可达性指数越高,房价越高;临近Charles River房价高。

2.5.5 模型测试

加载训练好的模型参数,在测试集上得到模型的MSE指标。

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

运行结果:

2.5.6 模型预测

使用Runnerload_model函数加载保存好的模型,使用predict进行模型预测,代码实现如下:

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

运行结果:

从输出结果看,预测房价接近真实房价。

参考:飞桨AI Studio - 人工智能学习与实训社区

3.1. 线性回归 — 动手学深度学习 2.0.0-beta1 documentation

神经网络与深度学习(三)线性回归与多项式回归相关推荐

  1. 神经网络与深度学习三:编写单隐层神经网络

    三:编写单隐层神经网络 1 神经网络概述 这篇文章你会学到如何实现一个神经网络,在我们深入学习技术细节之前,现在先大概快速的了解一下如何实现神经网络,如果你对某些内容不甚理解(后面的文章中会深入其中的 ...

  2. 神经网络与深度学习笔记汇总三

    神经网络与深度学习笔记汇总三 往期回顾 将之前掘金写的学习笔记所遇困难搬到这里,方便查看复习 遇到问题: 异常值处理 学习内容 1..drop() 返回的是一个新对象,原对象不会被改变. 2.遇到问题 ...

  3. 神经网络算法未来_“深度学习三巨头”来了俩,Hinton、LeCun预言深度学习的未来...

    当地时间 6 月 23 日,今年的 ACM 图灵奖得主."深度学习三巨头"中的 Geoffrey Hinton.Yann LeCun 在 ACM FCRC 2019上发表演讲,分享 ...

  4. 卷积神经网络学习三:神经网络之深度学习与tinny_cnn中的层

    卷积神经网络学习三:神经网络之深度学习 一.神经网络 神经网络是具有适应性的简单单元组成的广泛并行的网络,它的组织能够模拟生物神经系统对真实世界物体作出的交互反应.在机器学习中,神经网络指" ...

  5. 《神经网络与深度学习》邱希鹏 学习笔记(4)

    <神经网络与深度学习>邱希鹏 学习笔记(4) 完成进度 第二章 机器学习概述 机器学习算法的类型 数据的特征表示 传统的特征学习 特征选择 特征抽取 深度学习方法 评价指标 理论和定理 P ...

  6. 神经网络与深度学习(邱锡鹏)-学习笔记

    神经网络与深度学习 第一章 绪论 第二章 机器学习概述 第三章 线性模型 深度学习是机器学习的一个分支,是指一类问题以及解决这类问题的方法.人工神经网络,也简称神经网络,是一种受人脑神经系统的工作方式 ...

  7. 写给人类的机器学习 四、神经网络和深度学习

    四.神经网络和深度学习 原文:Machine Learning for Humans, Part 4: Neural Networks & Deep Learning 作者:Vishal Ma ...

  8. 《神经网络与深度学习》—学习笔记

    [nndl.github.io] [神经网络与深度学习] [nndl-book] 深度学习基础 深度学习是机器学习的一个分支,是指一类问题以及解决这类问题的方法. 深度学习问题是一个机器学习问题,指从 ...

  9. 神经网络和深度学习的简史

    神经网络和深度学习的简史 神经网络如何从最早的人工智能时代发展到现在的故事. 神经网络和深度学习的简史 序幕--深度学习海啸 "深度学习的浪潮拍打着计算语言学的海岸已经好几年了,但2015年 ...

  10. 吴恩达深度学习deeplearning.ai——第一门课:神经网络与深度学习——第二节:神经网络基础(上)

    2.1 二元分类 (Binary Classification) 这周我们将学习神经网络的基础知识,其中需要注意的是,当实现一个神经网络的时候,我们需要知道一些非常重要的技术和技巧.例如有一个包含 m ...

最新文章

  1. Stack Overflow requires external JavaScript from another domain, which is blocked or failed to load.
  2. jQuery 图片滚动效果
  3. win7 mysql msi_windows下的Mysql安装与基本使用(msi)
  4. 8.11模拟:数据结构
  5. JMetro“ Metro”选项卡,Java的TreeView和ContextMenu(JavaFX)
  6. POJ 1860 Currency Exchange (SPFA松弛)
  7. python opencv用法中文教程
  8. php 创建目录_使用 Zephir 轻松构建 PHP 扩展
  9. 谷歌8月更新修复50多个漏洞
  10. linux雨滴桌面,Rainmeter(雨滴桌面秀)
  11. 【历史上的今天】9 月 26 日:硅晶体管先驱出生;黑客盗取雅虎用户信息;“生物圈 2 号”实验室
  12. 牛逼!这个C++跳棋游戏居然可以让你边玩游戏边学编程!
  13. CSR、SSR、SPA是什么
  14. 【微信小程序系列】微信小程序超简单教程,基本语法,获取用户基本数据信息,实现对云数据库的增删改查及小程序外部api的引用示例(附源码)
  15. 网站优化与seo的方法(seo的优化基础)
  16. 终于完美解决OneNote无法同步的问题!如此简单!
  17. 【计算机网络:自顶向下方法】(一)计算机网络和英特网
  18. 2015国电设风力摆练手
  19. 元宇宙瞎想,现在手机弄个抖音啥的都戒不掉,以后元宇宙估计更上瘾了,有时间还是静静的看书学习更好
  20. 安装nodejs教程

热门文章

  1. 数组中的最长连续子序列
  2. 小米生态链与网络两大定律
  3. 翟彦克什么时候出道的?翟彦克的艺人资料??
  4. wordpress搏客伪静态固定链接设置失败的解决办法
  5. Ubuntu系统下CMake使用教程|1-5
  6. android6.0源码目录简单分析
  7. springboot+java生成二维码图片
  8. 据报道,Intel 发布 ARC 系列显卡
  9. 「硬核」labelme 图片中显示标签
  10. 已阅论文汇总:迁移学习