【机器学习】自定义数据集使用框架的线性回归方法对其进行拟合

一、使用框架的线性回归方法

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_tensornumpy 数组转换为 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_errorr2_score 计算测试集的均方误差和决定系数。
相关推荐
笛柳戏初雪4 分钟前
Python中容器类型的数据(上)
开发语言·python
清弦墨客5 分钟前
【蓝桥杯】43695.填字母游戏
python·蓝桥杯·编程算法
Erik_LinX16 分钟前
day1-->day7| 机器学习(吴恩达)学习笔记
笔记·学习·机器学习
查理零世1 小时前
保姆级讲解 python之zip()方法实现矩阵行列转置
python·算法·矩阵
刀客1231 小时前
python3+TensorFlow 2.x(四)反向传播
人工智能·python·tensorflow
时间很奇妙!1 小时前
decison tree 决策树
算法·决策树·机器学习
liruiqiang052 小时前
机器学习 - 初学者需要弄懂的一些线性代数的概念
人工智能·线性代数·机器学习·线性回归
Icomi_2 小时前
【外文原版书阅读】《机器学习前置知识》1.线性代数的重要性,初识向量以及向量加法
c语言·c++·人工智能·深度学习·神经网络·机器学习·计算机视觉
sysu632 小时前
95.不同的二叉搜索树Ⅱ python
开发语言·数据结构·python·算法·leetcode·面试·深度优先
羊小猪~~2 小时前
深度学习项目--基于LSTM的糖尿病预测探究(pytorch实现)
人工智能·pytorch·rnn·深度学习·神经网络·机器学习·lstm