回归——线性回归模型复现

回归——线性回归模型复现

问题重述

现在有一个二维空间中的点集 [ x i , y i ] [x_i,y_i] [xi,yi],需要使用如下线性模型拟合:
y = w ∗ x + b y=w*x+b y=wx+b
要求拟合误差尽可能小。对于所有的点 ( x i , y i ) (x_i,y_i) (xi,yi),误差用如下函数衡量:
l o s s = ∑ ( y i − ( w ∗ x i + b ) ) 2 loss=\sum(y_i-(w*x_i+b))^2 loss=(yi(wxi+b))2
其中:

  • w ∗ x i + b w*x_i+b wxi+b表示预测的值
  • y i y_i yi表示真实的值
  • y i − ( w ∗ x i + b ) y_i-(w*x_i+b) yi(wxi+b)表示预测值与真实值的偏差,取平方使得每一项都为正数
  • 最后将每一组$ (x_i,y_i)$的偏差求和即为总的偏差值

求解思路——梯度下降法

求解的目标是通过改变 w w w b b b,使得对于点集 [ x i , y i ] [x_i,y_i] [xi,yi]计算出的 l o s s loss loss函数的值最小。

根据导数的含义,我们知道 ∂ l o s s ∂ w \frac{\partial{loss}}{\partial{w}} wloss表示当前状态下 w w w微小的变化造成的 l o s s loss loss变化量的多少,同理, ∂ l o s s ∂ b \frac{\partial{loss}}{\partial{b}} bloss表示当前状态下 b b b微小的变化造成的 l o s s loss loss变化量的多少,而 ( ∂ l o s s ∂ w , ∂ l o s s ∂ b ) (\frac{\partial{loss}}{\partial{w}},\frac{\partial{loss}}{\partial{b}}) (wloss,bloss)为函数 l o s s loss loss的梯度, l o s s loss loss函数延负梯度方向下降最快

经过计算,我们可以得到:
∂ l o s s ∂ w = ∑ 2 ∗ x i ∗ ( y i − ( w ∗ x i + b ) ) ∂ l o s s ∂ b = ∑ 2 ∗ ( y i − ( w ∗ x i + b ) ) \frac{\partial{loss}}{\partial{w}}=\sum2*x_i*(y_i-(w*x_i+b))\\ \frac{\partial{loss}}{\partial{b}}=\sum2*(y_i-(w*x_i+b)) wloss=2xi(yi(wxi+b))bloss=2(yi(wxi+b))
于是,我们可以沿着负梯度方向,通过如下公式不断更新 w w w b b b,使得 l o s s loss loss以最快的速度不断减小直至局部最小值:
w n e w = w o l d − α ∗ ∂ l o s s ∂ w = w o l d − α ∗ ∑ 2 ∗ x i ∗ ( y i − ( w ∗ x i + b ) ) b n e w = b o l d − α ∗ ∂ l o s s ∂ b = b o l d − α ∗ ∑ 2 ∗ ( y i − ( w ∗ x i + b ) ) w_{new}=w_{old}-\alpha*\frac{\partial{loss}}{\partial{w}}=w_{old}-\alpha*\sum2*x_i*(y_i-(w*x_i+b))\\ b_{new}=b_{old}-\alpha*\frac{\partial{loss}}{\partial{b}}=b_{old}-\alpha*\sum2*(y_i-(w*x_i+b)) wnew=woldαwloss=woldα2xi(yi(wxi+b))bnew=boldαbloss=boldα2(yi(wxi+b))
其中 α \alpha α称为学习率(learningRate),也就是沿负梯度方向每一次前进的“步伐长度”,如果 α \alpha α选择太小将会导致下降速度过慢,需要迭代多次才能到达局部最小值点。如果 α \alpha α选择过大将会导致步伐过大错过了局部最小值点,从而在最小值点附近震荡。

注意:

  • 如果步伐足够小,则在不断逼近最小值点的过程中,每一次计算出的 ∂ l o s s ∂ w \frac{\partial{loss}}{\partial{w}} wloss ∂ l o s s ∂ b \frac{\partial{loss}}{\partial{b}} bloss都会不断减小,从而即使不用调整 α \alpha α每次移动步伐也会不断减小,最终收敛到局部最小值点
    yRC3qI.png

  • 如果步伐过大导致剧烈的震荡,每一次计算出的 ∂ l o s s ∂ w \frac{\partial{loss}}{\partial{w}} wloss ∂ l o s s ∂ b \frac{\partial{loss}}{\partial{b}} bloss都会增大,从而导致步伐进一步增大,震荡幅度不断增大。这是一个正反馈,最终导致 l o s s loss loss达到无穷大
    yRCJdP.png

模型复现

数据的生成

使用软件:matlab

首先在matlab中使用 y = 0.7 ∗ x + 1.22 + e r r y=0.7*x+1.22+err y=0.7x+1.22+err生成100个点的数据,其中 e r r err err为一个服从正态分布 N ( 0 , 2 ) N(0,2) N(0,2)的随机抖动。得到的点如下图所示:

yRPASg.png

之后将点的数据写入excel表格中

模型求解

编译环境:Pytorch3.7

语言:python

代码:

#coding=utf-8
import numpy as np
import xlrd

#读取excel文件的内容
class excel_read:
    def __init__(self, excel_path=r'data2.xlsx', encoding='utf-8', index=0):
        self.data = xlrd.open_workbook(excel_path)  ##获取文本对象
        self.table = self.data.sheets()[index]  ###根据index获取某个sheet
        self.rows = self.table.nrows  ##3获取当前sheet页面的总行数,把每一行数据作为list放到 list

    def get_data(self):
        result = []
        for i in range(self.rows):
            col = self.table.row_values(i)  ##获取每一列数据
            #print(col)
            result.append(col)
        #print(result)
        return result


#计算loss
def compute_error_for_line_given_points(b, w, points):
    totalError = 0
    for i in range(0, len(points)):
        x = points[i, 0]
        y = points[i, 1]
        totalError += (y - (w * x + b)) ** 2
    return totalError / float(len(points))

#延负梯度方向更新b和w
def step_gradient(b_current, w_current, points, learningRate):
    b_gradient = 0
    w_gradient = 0
    N = float(len(points))
    for i in range(0, len(points)):
        x = points[i, 0]
        y = points[i, 1]
        b_gradient += -(2 / N) * (y - ((w_current * x) + b_current))
        w_gradient += -(2 / N) * x * (y - ((w_current * x) + b_current))
    new_b = b_current - (learningRate * b_gradient)
    new_w = w_current - (learningRate * w_gradient)
    return [new_b, new_w]

#不断进行迭代
def gradient_descent_runner(points, starting_b, starting_w, learningRate, num_iterations):
    b = starting_b
    w = starting_w
    for i in range(num_iterations):
        b, w = step_gradient(b, w, np.array(points), learningRate)
    return [b, w]

#主程序
def run():
    #初始化
    points = np.array(excel_read().get_data())
    learningRate = 0.00005
    initial_b = 0
    initial_w = 0
    num_iterations = 100000
    #输出初始条件
    print("Starting at b={0},w={1},error={2}".format(initial_b, initial_w,
                                                     compute_error_for_line_given_points(initial_b, initial_w, points)))
    #计算、迭代
    print("Running")
    [b, w] = gradient_descent_runner(points, initial_b, initial_w, learningRate, num_iterations)
    #输出结果
    print("End at b={0},w={1},error={2} after {3} turns".format(b, w, compute_error_for_line_given_points(b,w, points),num_iterations))


if __name__ == '__main__':
    run()

选取学习率为0.0001,迭代次数为50000,得到结果为:
yRPjhT.png

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值