首页 > 其他分享 >手动用梯度下降法和随机梯度下降法实现一元线性回归

手动用梯度下降法和随机梯度下降法实现一元线性回归

时间:2024-09-11 10:36:25浏览次数:12  
标签:一元 plt loss 梯度 self 下降 pred model

手动用梯度下降法实现一元线性回归

实验目的

本次实验旨在通过手动实现梯度下降法和随机梯度下降法来解决一元线性回归问题。具体目标包括:

  1. 生成训练数据集,并使用matplotlib进行可视化。
  2. 设计一个`LinearModel`类来实现一元线性回归的批量梯度下降法。
  3. 使用matplotlib显示拟合结果。
  4.  修改`LinearModel`类来实现随机梯度下降法,并重复上述实验步骤。

实验环境

Python版本:3.x
库:NumPy, Matplotlib

实验步骤

步骤1:准备数据

  1. 生成100个训练样本,其中自变量X取值服从均值为0,方差为1的正态分布。
  2. 设定因变量Y的关系式为Y = 4X + 3 + er,其中er为误差项,取值服从均值为0,方差为1的正态分布。
  3. 使用Matplotlib绘制生成的数据点。
import numpy as np
import matplotlib.pyplot as plt

# 设置随机种子以保证结果可复现
np.random.seed(0)

# 生成100个训练样本
X = np.random.normal(loc=0, scale=1, size=100)  # X服从N(0,1)
e_r = np.random.normal(loc=0, scale=1, size=100)  # 误差项e_r服从N(0,1)
Y = 4 * X + 3 + e_r  # Y = 4*X + 3 + e_r

# 使用matplotlib显示生成的数据
plt.figure(figsize=(8, 6))
plt.scatter(X, Y, color='blue', label='Actual Data')
plt.title('Generated Data for Linear Regression')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.grid(True)
plt.show()

步骤2:定义LinearModel类

  1. 定义一个`LinearModel`类,包含模型初始化、前向传播、损失计算、梯度计算和参数更新等方法。
  2. 在类中实现批量梯度下降法的训练逻辑,通过设置最大迭代次数或验证集错误率来停止迭代。
class LinearModel:
    def __init__(self):
        self.w = np.random.randn()  # 初始化权重w
        self.b = np.random.randn()  # 初始化偏置b

    def forward(self, X):
        """ 计算预测值 """
        return self.w * X + self.b

    def loss(self, y_pred, y_true):
        """ 计算平均平方误差损失 """
        return np.mean((y_pred - y_true) ** 2)

    def gradient(self, X, y_pred, y_true):
        """ 计算梯度 """
        dw = 2 * np.mean((y_pred - y_true) * X)
        db = 2 * np.mean(y_pred - y_true)
        return dw, db

    def update(self, dw, db, learning_rate):
        """ 更新权重和偏置 """
        self.w -= learning_rate * dw
        self.b -= learning_rate * db

    def train(self, X, Y, epochs, learning_rate):
        """ 训练模型 """
        losses = []
        for epoch in range(epochs):
            # 前向传播
            y_pred = self.forward(X)
            # 计算损失
            loss = self.loss(y_pred, Y)
            losses.append(loss)
            # 计算梯度
            dw, db = self.gradient(X, y_pred, Y)
            # 更新参数
            self.update(dw, db, learning_rate)
            # 打印损失
            if epoch % 100 == 0:
                print(f'Epoch {epoch}: Loss {loss:.4f}')
        return losses

# 使用上面的LinearModel类进行训练
model = LinearModel()
losses = model.train(X, Y, epochs=1000, learning_rate=0.01)

# 绘制损失函数的变化情况
plt.figure(figsize=(8, 6))
plt.plot(losses, label='Loss over epochs')
plt.title('Training Loss Over Time')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.grid(True)
plt.show()

# 使用matplotlib显示拟合结果
plt.figure(figsize=(8, 6))
plt.scatter(X, Y, color='blue', label='Actual Data')
plt.plot(X, model.forward(X), color='red', label=f'Fitted Line (w={model.w:.2f}, b={model.b:.2f})')
plt.title('Fitted Line on Generated Data')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.grid(True)
plt.show()

步骤3:显示拟合结果

  1. 使用Matplotlib绘制生成的训练数据点。
  2. 使用Matplotlib绘制批量梯度下降法得到的拟合直线。
#绘制两种方法的损失函数曲线
plt.figure(figsize=(10, 6))
plt.plot(losses, label='Batch Gradient Descent Loss')
plt.plot(sgd_losses, label='Stochastic Gradient Descent Loss')
plt.title('Comparison of Training Loss Over Time')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.grid(True)
plt.show()
#比较拟合直线
plt.figure(figsize=(10, 6))
plt.scatter(X, Y, color='blue', label='Actual Data')
plt.plot(X, model.forward(X), color='green', label=f'Batch GD Fitted Line (w={model.w:.2f}, b={model.b:.2f})')
plt.plot(X, sgd_model.forward(X), color='red', label=f'SGD Fitted Line (w={sgd_model.w:.2f}, b={sgd_model.b:.2f})')
plt.title('Comparison of Fitted Lines from Batch GD and SGD')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.grid(True)
plt.show()

步骤4:实现随机梯度下降法

  1. 修改`LinearModel`类为`SGDLinearModel`类,使得每次迭代仅使用一个样本点来估计梯度并更新参数。
  2. 使用新类重复步骤2和步骤3的操作。
class SGDLinearModel:
    def __init__(self):
        self.w = np.random.randn()  # 初始化权重w
        self.b = np.random.randn()  # 初始化偏置b

    def forward(self, x_i):
        """ 计算单个样本的预测值 """
        return self.w * x_i + self.b

    def loss(self, y_pred, y_true):
        """ 计算单个样本的平方误差损失 """
        return (y_pred - y_true) ** 2

    def gradient(self, x_i, y_pred, y_true):
        """ 计算单个样本的梯度 """
        dw = 2 * (y_pred - y_true) * x_i
        db = 2 * (y_pred - y_true)
        return dw, db

    def update(self, dw, db, learning_rate):
        """ 更新权重和偏置 """
        self.w -= learning_rate * dw
        self.b -= learning_rate * db

    def train(self, X, Y, epochs, learning_rate):
        """ 训练模型 """
        num_samples = len(X)
        losses = []

        for epoch in range(epochs):
            epoch_loss = 0
            indices = np.arange(num_samples)
            np.random.shuffle(indices)  # 打乱样本顺序

            for idx in indices:
                # 随机选择一个样本
                x_i = X[idx]
                y_i = Y[idx]

                # 前向传播
                y_pred = self.forward(x_i)
                # 计算损失
                loss = self.loss(y_pred, y_i)
                epoch_loss += loss / num_samples  # 平均损失
                # 计算梯度
                dw, db = self.gradient(x_i, y_pred, y_i)
                # 更新参数
                self.update(dw, db, learning_rate)

            losses.append(epoch_loss)
            # 打印损失
            if epoch % 100 == 0:
                print(f'Epoch {epoch}: Loss {epoch_loss:.4f}')

        return losses

# 使用SGDLinearModel类进行训练
sgd_model = SGDLinearModel()
sgd_losses = sgd_model.train(X, Y, epochs=1000, learning_rate=0.01)

# 绘制损失函数的变化情况
plt.figure(figsize=(8, 6))
plt.plot(sgd_losses, label='Loss over epochs (SGD)')
plt.title('Training Loss Over Time with SGD')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.grid(True)
plt.show()

# 使用matplotlib显示拟合结果
plt.figure(figsize=(8, 6))
plt.scatter(X, Y, color='blue', label='Actual Data')
plt.plot(X, sgd_model.forward(X), color='red', label=f'Fitted Line (w={sgd_model.w:.2f}, b={sgd_model.b:.2f})')
plt.title('Fitted Line on Generated Data with SGD')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.grid(True)
plt.show()

实验结果分析

数据可视化

生成的训练数据点在二维坐标系中展示,可以看到数据点大致呈线性分布,但存在一定的噪声干扰。

批量梯度下降法结果

使用批量梯度下降法训练得到的模型能够较好地拟合训练数据,得到的拟合直线接近真实关系式\(Y = 4X + 3\)。

随机梯度下降法结果

使用随机梯度下降法训练得到的模型同样能够拟合训练数据,但在训练过程中损失函数的变化更为波动。最终拟合直线与批量梯度下降法得到的结果相近。

损失函数对比

绘制两种方法的损失函数随迭代次数变化的曲线,可以看到随机梯度下降法的损失函数曲线更加波动,而批量梯度下降法的曲线较为平滑。

结论

通过本实验,我们成功实现了批量梯度下降法和随机梯度下降法来解决一元线性回归问题。两种方法都能有效地拟合数据,但在训练过程中表现出不同的特性。批量梯度下降法虽然收敛较慢,但训练过程更加稳定;而随机梯度下降法则收敛较快,但由于每次迭代仅使用一个样本点,因此训练过程更加波动。在实际应用中,可以根据具体需求选择合适的方法。

标签:一元,plt,loss,梯度,self,下降,pred,model
From: https://www.cnblogs.com/qimoxuan/p/18407823

相关文章

  • 梯度下降方法,求解问题 最入门思想
    第一部分:求下面函数取得的最小值时,此时X的值是多少?何为梯度下降,本质就是从该点切线方向,慢慢走下去。切线方向:就是给定一个很小的增量值,试探一下方向。  1、方向的增量值: 2、不断迭代,当增量为很小时,意味着x应该是 1#超参数2m=0.023n=0.000000014#代码函......
  • 基于matlab的通过解方程来动态调整学习率的想法和固定学习率的梯度下降法
    通过解方程来动态调整学习率的想法,在实际应用中可能并不实用,因为它涉及到解符号方程,这可能会非常复杂或无法解析地求解,同时会增加计算复杂度和时间,固定学习率或基于某种规则(如线搜索)调整学习率更为常见。建议探索更高级的梯度下降变体(如Adam、RMSprop等),这些算法自动调整学习率......
  • 微盟集团:营收下降、股价暴跌,投资者信心何时归?
    在近日发布的2024年中期业绩报告中,微盟集团(HK:02013)再次向市场展示了其深陷困境的财务现状。这家曾被誉为“SaaS第一股”的云端商业及营销解决方案提供商,如今却面临着收入增长乏力、盈利遥遥无期、市场信心严重受挫的多重困境。报告显示,微盟集团2024年上半年的营业收入仅为8......
  • 什么是GPT-3的自回归架构?为什么GPT-3无需梯度更新和微调
    文章目录知识回顾GPT-3的自回归架构何为自回归架构为什么架构会影响任务表现自回归架构的局限性与双向模型的对比小结为何无需梯度更新和微调为什么不需要怎么做到不需要......
  • 【机器学习】梯度提升和随机森林的概念、两者在python中的实例以及梯度提升和随机森林
    引言梯度提升(GradientBoosting)是一种强大的机器学习技术,它通过迭代地训练决策树来最小化损失函数,以提高模型的预测性能随机森林(RandomForest)是一种基于树的集成学习算法,它通过组合多个决策树来提高预测的准确性和稳定性文章目录引言一、梯度提升1.1基本原理1.1.1......
  • 最优化(13):近似点梯度法、Nesterov算法
    6.1  近似点梯度法        6.1.1 邻近算子(proximaloperator):主要介绍proximaloperator的相关定义和性质        6.1.2  近似点梯度法:给出了proximalgradientmethod算法框架        6.1.3 应用举例:LASSOproblem和Low-rankmatrixcomp......
  • 基于Python的机器学习系列(18):梯度提升分类(Gradient Boosting Classification)
    简介        梯度提升(GradientBoosting)是一种集成学习方法,通过逐步添加新的预测器来改进模型。在回归问题中,我们使用梯度来最小化残差。在分类问题中,我们可以利用梯度提升来进行二分类或多分类任务。与回归不同,分类问题需要使用如softmax这样的概率模型来处理类别标......
  • 关于正点原子input子系统,驱动中按键中断只检测了上升或下降沿却可以实现连按(EV_REP)的
    问题在学习到Linux内核input子系统时,产生了一个疑惑。可以看到,我们改造按键中断驱动程序(请见keyinputdriver.c(内核驱动代码)),通过检测按键的上升沿和下降沿,在中断处理函数(上半部内)通过mod_timer(&dev->timer,jiffies+msecs_to_jiffies(20))函数启动定时器。在定时器处理函数中上......
  • 基于Python的机器学习系列(17):梯度提升回归(Gradient Boosting Regression)
    简介        梯度提升(GradientBoosting)是一种强大的集成学习方法,类似于AdaBoost,但与其不同的是,梯度提升通过在每一步添加新的预测器来减少前一步预测器的残差。这种方法通过逐步改进模型,能够有效提高预测准确性。梯度提升回归的工作原理        在梯度提升......
  • 信息学奥赛一本通1058:求一元二次方程
    【题目描述】利用公式x1=−b+b2−4ac√2a,x2=−b−b2−4ac√2a�1=−�+�2−4��2�,�2=−�−�2−4��2�,求一元二次方程ax2+bx+c=0��2+��+�=0的根,其中a�不等于00。结果要求精确到小数点后55位。【输入】输入一行,包含三个浮点数a,b,c�,�,�(它们之间以一个空格分开),分别表示方程ax2+bx+c=0��2+��+�=0的系数。......