一、使用框架的线性回归方法
1. 基础原理
在自求导线性回归中,我们需要先自定义参数 ,并且需要通过数学公式来对w和b进行 求导,然后在反向传播过程中通过梯度下降的方式来更新参数 ,从而降低损失值。
2. 实现步骤
① 散点输入
有一些散点,将它们绘制在一个二维坐标中,其分布如下图所示:
② 定义前向模型
准备好数据之后,就需要定义前向模型了。在这里给出了"定义前向模型"组件,如下图所示。
③ 定义损失函数和优化器
在选择好前向的模型后,需要定义反向传播过程中用到的一些超参数。在深度学习的三种框架中,关于损失函数和优化器的代码实现都已经封装好了,只需要选择使用哪种即可。
④ 开始迭代
在选择好损失函数及优化器之后,我们就可以进行迭代了。通过不断的迭代更新,使w和b的值不断更新,从而降低损失函数值,使直线的拟合效果更好,本实验中,"开始迭代"组件中默认选择的迭代次数是1000次,可以选择不同的迭代次数来观察直线的拟合效果。
⑤ 显示频率设置
迭代次数选好之后,就开始进行迭代了,为了能够观察到迭代过程中的现象,给出了"显示频率设置"的组件,该组件能够设置每迭代多少次,显示一次当前的参数值和损失值。
⑥ 拟合线显示与输出
选择好显示频率之后,通过"拟合线显示与输出"组件来查看我们的迭代过程中参数、直线及损失值的变化,内容如下图所示:
二、pytorch框架线性回归
1. 数据部分:
- 首先自定义了一个简单的数据集,特征
X
是 100 个随机样本,每个样本一个特征,目标值y
基于线性关系并添加了噪声。 - 将
numpy
数组转换为 PyTorch 张量,方便后续在模型中使用。
2. 模型定义部分:
方案 1 :使用 nn.Sequential
直接按顺序定义了一个线性层,简洁直观。
python
import torch
import torch.nn as nn
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score
# 自定义数据集
X = np.random.rand(100, 1).astype(np.float32)
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)
# 转换为 PyTorch 张量
X_tensor = torch.from_numpy(X)
y_tensor = torch.from_numpy(y)
# 定义线性回归模型
model = nn.Sequential(
nn.Linear(1, 1)
)
# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
# 训练模型
num_epochs = 1000
for epoch in range(num_epochs):
# 前向传播
outputs = model(X_tensor)
loss = criterion(outputs, y_tensor)
# 反向传播和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 100 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
# 模型评估
with torch.no_grad():
y_pred = model(X_tensor).numpy()
mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)
print(f"均方误差 (MSE): {mse}")
print(f"决定系数 (R²): {r2}")
# 输出模型的系数和截距
print("模型系数:", model[0].weight.item())
print("模型截距:", model[0].bias.item())
方案 2 :使用 nn.ModuleList
存储线性层,在 forward
方法中依次调用层进行前向传播,适合动态构建层序列。
python
import torch
import torch.nn as nn
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score
# 自定义数据集
X = np.random.rand(100, 1).astype(np.float32)
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)
# 转换为 PyTorch 张量
X_tensor = torch.from_numpy(X)
y_tensor = torch.from_numpy(y)
# 定义线性回归模型
class LinearRegression(nn.Module):
def __init__(self):
super(LinearRegression, self).__init__()
self.layers = nn.ModuleList([
nn.Linear(1, 1)
])
def forward(self, x):
for layer in self.layers:
x = layer(x)
return x
model = LinearRegression()
# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
# 训练模型
num_epochs = 1000
for epoch in range(num_epochs):
# 前向传播
outputs = model(X_tensor)
loss = criterion(outputs, y_tensor)
# 反向传播和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 100 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
# 模型评估
with torch.no_grad():
y_pred = model(X_tensor).numpy()
mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)
print(f"均方误差 (MSE): {mse}")
print(f"决定系数 (R²): {r2}")
# 输出模型的系数和截距
print("模型系数:", model.layers[0].weight.item())
print("模型截距:", model.layers[0].bias.item())
方案 3 :使用 nn.ModuleDict
以字典形式存储层,通过键名调用层,适合需要对层进行命名和灵活访问的场景。
python
import torch
import torch.nn as nn
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score
# 自定义数据集
X = np.random.rand(100, 1).astype(np.float32)
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)
# 转换为 PyTorch 张量
X_tensor = torch.from_numpy(X)
y_tensor = torch.from_numpy(y)
# 定义线性回归模型
class LinearRegression(nn.Module):
def __init__(self):
super(LinearRegression, self).__init__()
self.layers = nn.ModuleDict({
'linear': nn.Linear(1, 1)
})
def forward(self, x):
x = self.layers['linear'](x)
return x
model = LinearRegression()
# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
# 训练模型
num_epochs = 1000
for epoch in range(num_epochs):
# 前向传播
outputs = model(X_tensor)
loss = criterion(outputs, y_tensor)
# 反向传播和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 100 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
# 模型评估
with torch.no_grad():
y_pred = model(X_tensor).numpy()
mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)
print(f"均方误差 (MSE): {mse}")
print(f"决定系数 (R²): {r2}")
# 输出模型的系数和截距
print("模型系数:", model.layers['linear'].weight.item())
print("模型截距:", model.layers['linear'].bias.item())
方案 4 :直接继承 nn.Module
,在 __init__
方法中定义线性层,在 forward
方法中实现前向传播逻辑,是最常见和基础的定义模型方式。
python
import torch
import torch.nn as nn
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score
# 自定义数据集
X = np.random.rand(100, 1).astype(np.float32)
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)
# 转换为 PyTorch 张量
X_tensor = torch.from_numpy(X)
y_tensor = torch.from_numpy(y)
# 定义线性回归模型
class LinearRegression(nn.Module):
def __init__(self):
super(LinearRegression, self).__init__()
self.linear = nn.Linear(1, 1)
def forward(self, x):
return self.linear(x)
model = LinearRegression()
# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
# 训练模型
num_epochs = 1000
for epoch in range(num_epochs):
# 前向传播
outputs = model(X_tensor)
loss = criterion(outputs, y_tensor)
# 反向传播和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 100 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
# 模型评估
with torch.no_grad():
y_pred = model(X_tensor).numpy()
mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)
print(f"均方误差 (MSE): {mse}")
print(f"决定系数 (R²): {r2}")
# 输出模型的系数和截距
print("模型系数:", model.linear.weight.item())
print("模型截距:", model.linear.bias.item())
3. 训练和评估部分:
- 定义了均方误差损失函数
nn.MSELoss
和随机梯度下降优化器torch.optim.SGD
。 - 通过多个 epoch 进行训练,每个 epoch 包含前向传播、损失计算、反向传播和参数更新。
- 训练结束后,在无梯度计算模式下进行预测,并使用
scikit-learn
的指标计算均方误差和决定系数评估模型性能,最后输出模型的系数和截距。
三、tensorflow框架线性回归
1. 数据部分:
- 首先自定义了一个简单的数据集,特征
X
是 100 个随机样本,每个样本一个特征,目标值y
基于线性关系并添加了噪声。 - tensorflow框架不需要
numpy
数组转换为相应的张量,可以直接在模型中使用数据集。
2. 模型定义部分:
方案 1:model = tf.keras.Sequential([tf.keras.layers.Dense(1, input_shape=(1,))])
解释:
- 此方案使用
tf.keras.Sequential
构建模型,在列表中直接定义了一个Dense
层,input_shape=(1,)
表明输入数据的形状。 - 编译模型时,选择随机梯度下降(SGD)优化器和均方误差损失函数。
- 训练完成后,使用
sklearn
的指标评估模型,并输出模型的系数和截距。
python
import tensorflow as tf
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score
# 自定义数据集
X = np.random.rand(100, 1).astype(np.float32)
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)
# 构建模型
model = tf.keras.Sequential([
tf.keras.layers.Dense(1, input_shape=(1,))
])
# 编译模型
model.compile(optimizer=tf.keras.optimizers.SGD(learning_rate=0.01),
loss='mean_squared_error')
# 训练模型
history = model.fit(X, y, epochs=1000, verbose=0)
# 模型评估
y_pred = model.predict(X)
mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)
print(f"均方误差 (MSE): {mse}")
print(f"决定系数 (R²): {r2}")
# 输出模型的系数和截距
weights, biases = model.layers[0].get_weights()
print(f"模型系数: {weights[0][0]}")
print(f"模型截距: {biases[0]}")
方案 2:model = tf.keras.Sequential()
解释:
- 这种方式先创建一个空的
Sequential
模型,再使用add
方法添加Dense
层。 - 后续编译、训练、评估和输出模型参数的步骤与方案 1 类似。
python
import tensorflow as tf
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score
# 自定义数据集
X = np.random.rand(100, 1).astype(np.float32)
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)
# 构建模型
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(1, input_shape=(1,)))
# 编译模型
model.compile(optimizer=tf.keras.optimizers.SGD(learning_rate=0.01),
loss='mean_squared_error')
# 训练模型
history = model.fit(X, y, epochs=1000, verbose=0)
# 模型评估
y_pred = model.predict(X)
mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)
print(f"均方误差 (MSE): {mse}")
print(f"决定系数 (R²): {r2}")
# 输出模型的系数和截距
weights, biases = model.layers[0].get_weights()
print(f"模型系数: {weights[0][0]}")
print(f"模型截距: {biases[0]}")
方案 3:自定义模型类
解释:
- 继承
Model
基类创建自定义模型类Linear
,在__init__
方法中定义Dense
层。 call
方法用于实现前向传播逻辑,类似于 PyTorch 中的forward
方法。- 后续的编译、训练、评估和参数输出流程和前面方案一致。
python
import tensorflow as tf
from tensorflow.keras import Model
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score
# 自定义数据集
X = np.random.rand(100, 1).astype(np.float32)
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)
# 自定义模型类
class Linear(Model):
def __init__(self):
super(Linear, self).__init__()
self.linear = tf.keras.layers.Dense(1)
def call(self, x, **kwargs):
x = self.linear(x)
return x
# 构建模型
model = Linear()
# 编译模型
model.compile(optimizer=tf.keras.optimizers.SGD(learning_rate=0.01),
loss='mean_squared_error')
# 训练模型
history = model.fit(X, y, epochs=1000, verbose=0)
# 模型评估
y_pred = model.predict(X)
mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)
print(f"均方误差 (MSE): {mse}")
print(f"决定系数 (R²): {r2}")
# 输出模型的系数和截距
weights, biases = model.linear.get_weights()
print(f"模型系数: {weights[0][0]}")
print(f"模型截距: {biases[0]}")
方案 4:函数式 API 构建模型
解释:
- 使用函数式 API 构建模型,先定义输入层,再定义
Dense
层,最后使用Model
类将输入和输出连接起来形成模型。 - 编译、训练、评估和参数输出的步骤和前面方案相同。注意这里通过
model.layers[1]
获取Dense
层的权重和偏置,因为第一层是输入层。
python
import tensorflow as tf
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score
# 自定义数据集
X = np.random.rand(100, 1).astype(np.float32)
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)
# 定义函数构建模型
def linear():
input = tf.keras.layers.Input(shape=(1,), dtype=tf.float32)
y = tf.keras.layers.Dense(1)(input)
model = tf.keras.models.Model(inputs=input, outputs=y)
return model
# 构建模型
model = linear()
# 编译模型
model.compile(optimizer=tf.keras.optimizers.SGD(learning_rate=0.01),
loss='mean_squared_error')
# 训练模型
history = model.fit(X, y, epochs=1000, verbose=0)
# 模型评估
y_pred = model.predict(X)
mse = mean_squared_error(y, y_pred)
r2 = r2_score(y, y_pred)
print(f"均方误差 (MSE): {mse}")
print(f"决定系数 (R²): {r2}")
# 输出模型的系数和截距
weights, biases = model.layers[1].get_weights()
print(f"模型系数: {weights[0][0]}")
print(f"模型截距: {biases[0]}")
3. 训练和评估部分:
- 使用
fit
方法对模型进行训练,verbose=0
表示不显示训练过程中的详细信息,训练过程中的损失信息会存储在history
对象中。 - 通过多个 epoch 进行训练,每个 epoch 包含前向传播、损失计算、反向传播和参数更新。
- 使用
predict
方法进行预测,计算均方误差和决定系数评估模型性能,通过model.linear.get_weights()
获取模型的系数和截距。
四、paddlepaddle框架线性回归
1. 数据部分:
- 首先自定义了一个简单的数据集,特征
X
是 100 个随机样本,每个样本一个特征,目标值y
基于线性关系并添加了噪声。 - 将
numpy
数转换为Paddlepaddle张量,方便后续在模型中使用。
2. 模型定义部分:
方案 1:使用 nn.Sequential
组网
代码解释
① 数据生成与转换:
- 生成自定义的特征矩阵
X
和目标值向量y
,并添加高斯噪声模拟真实数据。 - 使用
paddle.to_tensor
将numpy
数组转换为 PaddlePaddle 张量。
② 模型组网:
- 使用
nn.Sequential
快速构建线性回归模型,只包含一个nn.Linear
层。
③ 损失函数和优化器:
- 选择均方误差损失函数
nn.MSELoss
和随机梯度下降优化器paddle.optimizer.SGD
。
④ 模型训练:
- 进行多个轮次的训练,在每个轮次中进行前向传播、损失计算、反向传播和参数更新。
- 记录每一轮的损失值,用于后续绘制损失曲线。
⑤ 损失曲线绘制:
- 使用
matplotlib
绘制训练损失随轮次的变化曲线,直观展示模型的训练过程。
⑥ 模型评估:
- 在无梯度计算的模式下进行预测,计算预测结果的均方误差和决定系数。
⑦ 输出模型参数:
- 获取模型的系数和截距并输出。
python
import paddle
import paddle.nn as nn
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score
import matplotlib.pyplot as plt
# 自定义数据集
# 生成 100 个样本,每个样本有 1 个特征
X = np.random.rand(100, 1).astype(np.float32)
# 根据特征生成目标值,添加一些噪声
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)
# 将 numpy 数组转换为 PaddlePaddle 张量
X = paddle.to_tensor(X)
y = paddle.to_tensor(y)
# 使用 nn.Sequential 组网
model = nn.Sequential(
nn.Linear(1, 1)
)
# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters())
# 训练模型
num_epochs = 1000
losses = []
for epoch in range(num_epochs):
# 前向传播
outputs = model(X)
loss = criterion(outputs, y)
losses.append(loss.numpy()[0])
# 反向传播和优化
optimizer.clear_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 100 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.numpy()[0]:.4f}')
# 绘制训练损失曲线
plt.plot(range(num_epochs), losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss')
plt.show()
# 模型评估
with paddle.no_grad():
y_pred = model(X).numpy()
mse = mean_squared_error(y.numpy(), y_pred)
r2 = r2_score(y.numpy(), y_pred)
print(f"均方误差 (MSE): {mse}")
print(f"决定系数 (R²): {r2}")
# 输出模型的系数和截距
weights = model[0].weight.numpy()[0][0]
bias = model[0].bias.numpy()[0]
print(f"模型系数: {weights}")
print(f"模型截距: {bias}")
方案 2:单独定义,使用类的方式 class nn.Layer
组网
代码解释
此方案与方案 1 的主要区别在于模型的组网方式,具体如下:
模型组网:
① 定义一个继承自 nn.Layer
的自定义模型类 LinearRegression
。
② 在 __init__
方法中初始化 nn.Linear
层。
③ 在 forward
方法中定义前向传播逻辑。
后续步骤:
损失函数、优化器的选择,模型训练、评估以及参数输出等步骤与方案 1 基本相同。
python
import paddle
import paddle.nn as nn
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score
import matplotlib.pyplot as plt
# 自定义数据集
# 生成 100 个样本,每个样本有 1 个特征
X = np.random.rand(100, 1).astype(np.float32)
# 根据特征生成目标值,添加一些噪声
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)
# 将 numpy 数组转换为 PaddlePaddle 张量
X = paddle.to_tensor(X)
y = paddle.to_tensor(y)
# 自定义模型类,继承自 nn.Layer
class LinearRegression(nn.Layer):
def __init__(self):
super(LinearRegression, self).__init__()
self.linear = nn.Linear(1, 1)
def forward(self, x):
return self.linear(x)
# 创建模型实例
model = LinearRegression()
# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters())
# 训练模型
num_epochs = 1000
losses = []
for epoch in range(num_epochs):
# 前向传播
outputs = model(X)
loss = criterion(outputs, y)
losses.append(loss.numpy()[0])
# 反向传播和优化
optimizer.clear_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 100 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.numpy()[0]:.4f}')
# 绘制训练损失曲线
plt.plot(range(num_epochs), losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss')
plt.show()
# 模型评估
with paddle.no_grad():
y_pred = model(X).numpy()
mse = mean_squared_error(y.numpy(), y_pred)
r2 = r2_score(y.numpy(), y_pred)
print(f"均方误差 (MSE): {mse}")
print(f"决定系数 (R²): {r2}")
# 输出模型的系数和截距
weights = model.linear.weight.numpy()[0][0]
bias = model.linear.bias.numpy()[0]
print(f"模型系数: {weights}")
print(f"模型截距: {bias}")
3. 训练和评估部分:
- 使用
train_losses
列表记录每一轮训练的损失值,方便后续绘制训练损失曲线,直观观察模型的训练过程。 - 将数据集按 80:20 的比例划分为训练集和测试集,以更准确地评估模型的泛化能力。
- 使用
scikit-learn
中的mean_squared_error
和r2_score
计算测试集的均方误差和决定系数。