一、什么是线性模型
1、定义
线性模型是一种用于建模和预测的简单数学模型,其基本形式是一个线性方程,比如可以认为 y=wx+b 就是一个简单的线性模型。它的存在,是假设输入与输出之间存在线性关系。
对于一个具有 n 个输入特征()的线性模型,可以表示为以下形式:
其中,y 是预测输出值,()是输入特征值,()是模型的权重参数。 表示模型的截距,而 () 分别表示输入特征() 的权重。
2、用途
线性模型广泛应用于回归分析和分类问题中。在回归问题中,线性模型用于预测连续的输出值;在分类问题中,线性模型可以通过设置适当的阈值将预测结果映射为离散的分类标签。
3、从线性到非线性
在神经网络中,每一层的输出都是前一层输出的线性组合,而没有使用激活函数的情况下,线性组合的叠加仍然是线性的。这意味着即使有多个隐藏层,整个网络仍然可以表示为输入特征的线性组合,没有引入非线性的变换。
如果在神经网络中不使用激活函数,那么整个网络将被表示为一个多层线性模型,无法学习和表示非线性的关系。线性模型只能学习线性关系,无法适应复杂的非线性数据。
激活函数的引入是为了引入非线性变换,使得神经网络能够学习和表示非线性模式。激活函数对线性组合的输出进行非线性的映射,为网络引入了非线性性质,从而使网络能够学习更加复杂的模式和决策边界。
因此,通过使用激活函数,神经网络可以从线性模型向非线性模型拓展,并具备学习和表示非线性关系的能力。
二、本节案例与分析
1、实际背景
假定一个学生自学某课程,他学习1小时,可以习得2个知识点,学习2小时,可以习得4个知识点,学习3小时,可以习得6个知识点,则已知的数据(1,2),(2,4),(3,6),问:如果学生学习4个小时,预测一下他能够习得多少个知识点?
2、模型定义
这里我们将(1,2),(2,4),(3,6)这三个数据称之为训练集,用于训练和更新模型里面的参数,而(4,?)称之为测试集,用于测试这个预测模型是否能够最大可能的反映实际模型。如果我们可以暂时使用 这个简单的线性模型来进行思考w和b取值应该是多少,才能让线性模型尽可能的去反映真实的数据规律。
在本问题中,为了简化模型,我们现在开始,变更为使用 这个模型。
3、确定损失函数
单个训练误差我们选取的方式有:
对整体使用均值误差(Mean Square Error):
4、求解与记录
5、代码与结论
import numpy as np
import matplotlib.pyplot as plt
# 设置数据集
x_data_set = [1.0, 2.0, 3.0]
y_data_set = [2.0, 4.0, 6.0]
# 定义模型,模型是 y = ω * x
def linearModel(x):
return w * x
# 定义损失函数规则,规则是 (预测输出 - 实际输出) ** 2
# 若要计算MSE,只需要除以len(x_data_set)即可
def lossFcn(x, y):
y_predict = linearModel(x)
return (y_predict - y) ** 2
# 存放 w 和 MSE误差 的空列表,方便后续绘图
w_list = []
MSE_list = []
# 开始测试 1.0 ~ 3.0 不同的40个w值下的数据情况,步长0.05
for w in np.arange(1.0, 3.01, 0.05):
print(f"\n当前的w是{w:.2f}\n")
loss_sum = 0 # 每个新的w出现就清空一下误差总和
# 把几组真实的x和真实的y抽取出来,计算误差
for x_data, y_data in zip(x_data_set, y_data_set):
# 预测输出值是 w * x,调用linearModel函数求得
y_predict = linearModel(x_data)
# 单个样本损失值
loss = lossFcn(x_data, y_data)
# 单个损失计入总损失
loss_sum += loss
# 打印数据
print("\t真实x\t真实y\t预测y\t误差")
print(f"\t{x_data:.2f}\t{y_data:.2f}\t{y_predict:.2f}\t{loss:.2f}")
print(f"总误差:{loss_sum:.2f}")
print(f"MSE误差:{loss_sum / len(x_data_set):.2f}")
# 把 w 的取值和 MSE_loss 记录在对应的列表中
w_list.append(w)
MSE_list.append(loss_sum / len(x_data_set))
print("\n========================")
plt.plot(w_list, MSE_list)
plt.xlabel("omega")
plt.ylabel("MSE_Loss")
plt.show()
6、模型为y=wx+b的情景
由于多了一个偏置量b,那么需要做以下变动:
(1)把linearModel的模型更改为 y=wx+b,损失函数的计算不变,设w在1~3之间,步长0.05(共40个w取值);b在-2~2之间,步长0.1(共40个b取值);
(2)当取到某一个w的时候,b可以是-2~2的任意值,因此(w,b)的组合一共有1600种,根据代码逻辑,每取一个w,就要对这40个b全部计算一次数据,因此需要在w的取值循环内部,加入一个嵌套循环,用于取b的数值;
(3)增加一个用于装入b的空列表,并单独用一个循环把b的40个取值导入进去;
(4)将w和b作为三维绘图的底部平面的两个轴,MSE_Loss作为三维绘图的z轴,绘图代码参见代码块内容。
import matplotlib.pyplot as plt
import numpy as np
# 设置数据集
x_data_set = [1.0, 2.0, 3.0]
y_data_set = [2.0, 4.0, 6.0]
# 定义模型,模型是 y = ω * x + b , 其中包含了2个待优化的参数w和b
def linearModel(x):
return w * x + b
# 定义损失函数规则
def lossFcn(x, y):
y_predict = linearModel(x)
return (y_predict - y) ** 2
# 存放 w b 和 MSE误差 的空列表
w_list = []
b_list = []
MSE_list = []
# 开始测试 1.0 ~ 3.0 不同的40个w值下的数据情况
for w in np.arange(1.0, 3.0, 0.05):
# 每出现一个w就往列表里面添加,列表总共会添加40个w值
w_list.append(w)
# 在相同的w情况,考查b变化的情况下,MSE的大小
for b in np.arange(-2.0, 2.0, 0.1):
print(f"\n当前的w是{w:.2f}, b是{b:.2f}\n")
loss_sum = 0 # 每个新的w和b出现就清空一下误差总和
# 把几组真实的x和真实的y抽取出来,计算误差
for x_data, y_data in zip(x_data_set, y_data_set):
# 预测输出值是 w * x + b,调用linearModel函数求得
y_predict = linearModel(x_data)
# 损失值是 预测输出值 - 真实输出值
loss = lossFcn(x_data, y_data)
# 更新总误差
loss_sum += loss
# 打印数据
print("\t真实x\t真实y\t预测y\t误差")
print(f"\t{x_data:.2f}\t{y_data:.2f}\t{y_predict:.2f}\t{loss:.2f}")
print(f"总误差:{loss_sum:.2f}")
print(f"MSE误差:{loss_sum / len(x_data_set):.2f}")
# 把MSE_loss 记录在对应的列表中,共 40 * 40 = 1600个
MSE_list.append(loss_sum / len(x_data_set))
print("\n========================")
# 将b的值导入到b_list中,共40个数据
for b in np.arange(-2.0, 2.0, 0.1):
b_list.append(b)
print(len(w_list)) # 40
print(len(b_list)) # 40
print(len(MSE_list)) # 1600
# 开始绘图,对x/y底面用np.meshgrid()方法
w_axes, b_axes = np.meshgrid(w_list, b_list)
# z轴数据要和x、y匹配,reshape = 40*40
MSE_axes = np.array(MSE_list).reshape(40, 40)
# ax = fig.add_subplot(projection='3d')创建了一个三维坐标轴对象,并将其赋值给变量ax。
# 通过设置projection='3d'参数,告诉Matplotlib想要创建一个三维的坐标轴。
# ax.plot_surface(w_axes, b_axes, MSE_axes, cmap='viridis')使用plot_surface()函数在三维坐标系中绘制曲面。它需要三个参数:
# w_axes是自变量w的网格坐标
# b_axes是自变量b的网格坐标
# MSE_axes是因变量MSE的对应值
# 通过将这些参数传递给plot_surface()函数,可以绘制出根据w、b和MSE值形成的曲面。其中,cmap='viridis'参数指定了曲面的颜色映射,使用viridis表示以蓝色到黄色渐变的颜色。
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
ax.plot_surface(w_axes, b_axes, MSE_axes, cmap='jet')
ax.set_xlabel('w')
ax.set_ylabel('b')
ax.set_zlabel('MSE')
plt.show()
7、注意与补充
代码中用到了zip(x,y)函数,这个函数的作用如下
设:x=[1.0, 2.0, 3.0],y=[3.0, 6.0, 9.0],使用z=zip(x,y),对z进行遍历输出为元组类型
z[1]=(1.0,3.0)
z[2]=(2.0,6.0)
z[3]=(3.0,9.0)
即:
x y zip(x,y)
1.0 3.0 (1.0,3.0)
2.0 6.0 (2.0,6.0)
3.0 9.0 (3.0,9.0)