机器学习系列——线性回归1

作为机器学习的第一课,先啰嗦地简单介绍一下,这是一个从公式推导到python实践的一门 “ 机器通俗演义 ” 系列课程(就是阐述一下自己的拙见),不定期更新,欢迎大家提出意见!
顺便推荐一下吴恩达老师的机器学习课程!(B站有资源)
(下面是正文部分)

线性回归模型

我们由浅入深,先从简单的二元线性回归模型开始。这节课从简单的二维x, y入手,如果对于数学公式推导有些障碍的,可以略过,关于里面每一个公式的 “ 实际意义 ” 会在之后的课程里介绍!

模型简介

在这里插入图片描述
有这么一副图,我们想要找到一条直线,让它可以尽可能的经过所有的点
在这里插入图片描述
就好像这两根线,我们就需要通过 “ 一番操作 ” 拟合出一条类似绿线那样尽可能经过所有点的线。

一次函数

首先让我们看一下我们从初中开始第一个接触的函数——一次函数!
y = f(x) = kx + b
很简单对不对?恭喜你,你已经会线性回归的绝大部分了!

代价函数(CostFunction)

刚才说“尽可能经过所有点的线”,我们可以看图得出结论,绿线比红线 “ 厉害 ” ,但是机器还不会这么高级的操作啊?所以,在数学上,我们就可以通过“距离”来评估一条直线的 “ 优劣程度 ” ,这个就是我们的代价函数——
J ( w , b ) = 1 2 m ∑ i = 1 m ( ( w ∗ x ( i ) + b ) − y ( i ) ) 2 J(w, b) =\frac{1}{2m} \sum_{i=1}^{m} ( (w * x^{(i)}+ b) - y^{(i)})^2 J(w,b)=2m1i=1m((wx(i)+b)y(i))2
看起来有一点复杂,且听我逐步分解。
首先w, b,就是上面一次函数对应的 k, b; 然后 m 就是样本个数(简单理解为你有几个点,比如例图中就是m = 4)然后 x ( i ) x^{(i)} x(i) 就是每一个点的横坐标, y ( i ) y^{(i)} y(i) 就是每一个点的纵坐标 (其实 i 表示第 i 个样本)所以令
h ( x ) = w x + b h(x)=wx+b h(x)=wx+b
那么原式就可以写成
J ( w , b ) = 1 2 m ∑ i = 1 m ( h ( x ( i ) ) − y ( i ) ) 2 J(w, b) =\frac{1}{2m} \sum_{i=1}^{m} (h(x^{(i)}) - y^{(i)})^2 J(w,b)=2m1i=1m(h(x(i))y(i))2
那么不是恰好是点纵向到线的距离吗?!在这里插入图片描述
即为途中蓝色虚线长度的平方,
我们把点到线的垂直距离求和,那么总和越小的,是不是就可以说明这根线就尽量贴合我们的数据了?所以这个就是代价函数的意义

模型简介之梅开二度

有了上面的铺垫,我们不难这么想——不断搜索着w, b的值,然后通过代价函数来评估出最好的那一条。于是就有如下过程

Step 1:
 Initialization(w, b)
 
Step 2:
	while(CostFunction(w, b) > 0.00001):  #--- 误差在0.00001以内的时候我们觉得差不多了, 停止训练
		Update(w, b)

那么如何Update呢?我们可以利用梯度下降来做,可能数学比较厉害的同志想到了,这种问题不是可以用 “ 最小二乘法 ” 来解决吗?是的,但是以后我们还要拓展到多元呢!最小二乘的复杂性就体现出来了

梯度下降

想象一下你站在高峰之巅,然后突然口渴想下山喝水,你要走那一条路呢?
在这里插入图片描述
显然得,我们这么走一定是最快的,但是为什么呢?
在这里插入图片描述
啊!因为这里的坡度最陡啊!
是的,这个就是梯度下降的精髓,每一次选取 “ 坡度 ” 最陡的地方往下走。根据数学知识可以得知,导数指示方向是增长方向,那么我们将其取负方向,不就是最陡的斜坡而下降吗?!于是有
Θ i = Θ i − 1 − α ∇ J ( Θ ) \Theta_i = \Theta_{i-1} - \alpha\nabla J(\Theta) Θi=Θi1αJ(Θ)
我们来举一个例子来理解
在这里插入图片描述
上图是一个经典的二次函数 f ( x ) = x 2 f(x)=x^2 f(x)=x2,此时假设我们站在这里( x 0 = 1 x_0 = 1 x0=1),我们要去往 “ 谷底 ” 在这里插入图片描述
先令 α = 0.3 \alpha = 0.3 α=0.3 根据公式可以得到,迭代的 x 1 = x 0 + 0.3 ∗ f ′ ( x 0 ) = 1 − 0.3 ∗ 2 = 0.4 x_1=x_0+0.3*f'(x_0) =1-0.3*2=0.4 x1=x0+0.3f(x0)=10.32=0.4在这里插入图片描述
大概就是这个样子
同理,我们可以一直迭代,直到我们得到最低点——大概长这个样子(大家熟悉的图像)
在这里插入图片描述
这个就是我们的梯度下降法。

对于CostFunction的梯度下降

这里给出推导过程(如果不感兴趣可以直接看结论)
J ( w , b ) = 1 2 m ∑ i = 1 m ( ( w ∗ x ( i ) + b ) − y ( i ) ) 2 J(w, b) =\frac{1}{2m} \sum_{i=1}^{m} ( (w * x^{(i)} + b) - y^{(i)})^2 J(w,b)=2m1i=1m((wx(i)+b)y(i))2

g ( x ) = x 2 g(x) = x^2 g(x)=x2
h ( x ) = ( w ∗ x ( i ) + b ) − y ( i ) h(x) = (w * x^{(i)} + b) - y^{(i)} h(x)=(wx(i)+b)y(i)

J ( w , b ) = 1 2 m ∑ i = 1 m g ( h ( x ) ) J(w, b)=\frac{1}{2m}\sum_{i=1}^{m}g(h(x)) J(w,b)=2m1i=1mg(h(x))
根据链式法则得到
∂ J ( w , b ) ∂ w = 1 2 m ∑ i = 1 m g ′ ( h ( w ) ) h ′ ( w ) \frac{\partial J(w, b)}{\partial w}=\frac{1}{2m}\sum_{i=1}^{m} g'(h(w))h'(w) wJ(w,b)=2m1i=1mg(h(w))h(w)
把除 w w w 外所有字母看成参数,代入
∂ J ( w , b ) ∂ w = 1 2 m ∑ i = 1 m 2 ∗ ( ( w ∗ x ( i ) + b ) − y ( i ) ) ∗ x ( i ) \frac{\partial J(w, b)}{\partial w}=\frac{1}{2m}\sum_{i=1}^{m} 2*((w * x^{(i)} + b) - y^{(i)})*x^{(i)} wJ(w,b)=2m1i=1m2((wx(i)+b)y(i))x(i)
∂ J ( w , b ) ∂ w = 1 m ∑ i = 1 m ( ( w ∗ x ( i ) + b ) − y ( i ) ) ∗ x ( i ) \frac{\partial J(w, b)}{\partial w}=\frac{1}{m}\sum_{i=1}^{m} ((w * x^{(i)} + b) - y^{(i)})*x^{(i)} wJ(w,b)=m1i=1m((wx(i)+b)y(i))x(i)
同理可得
∂ J ( w , b ) ∂ b = 1 m ∑ i = 1 m ( ( w ∗ x ( i ) + b ) − y ( i ) ) \frac{\partial J(w, b)}{\partial b}=\frac{1}{m}\sum_{i=1}^{m} ((w * x^{(i)} + b) - y^{(i)}) bJ(w,b)=m1i=1m((wx(i)+b)y(i))

代码实现

综上所述,最后一番梳理,只要按步骤来逐个计算,就可以得到最终我们的模型了—— Python代码送的上(numpy)

import numpy as np
#--- Step 0: 定义真实函数 (y)
def RealFunction(x):                            
    return 0.5 * x - 4.3

start = 5    
#--- Step 1: 设置数据集(刚才例子里的点集)
trainX = np.array([i for i in range(start, start + n)], dtype = np.float32)           
trainY = np.array([RealFunction(i) for i in range(start, n + start)], dtype = np.float32) 

#--- Step 2: 设置超参数
np.random.seed(1)
w, b = np.random.uniform(-1, 1, (2))            # --- 初始化 w, b
n = 20                                          # --- 样本数 (m)

esp = 100000                                    # --- 训练次数
alpha = 0.003                                   # --- 学习速率

#--- Step 3: 定义CostFunction, 即误差Loss
def Loss(x, y):                                 # --- 返回误差
    return sum((w * x + b - y) ** 2) / float(n * 2)

#--- Step 4: 定义训练框架
def Train(x, y):
    global w, b

    for i in range(esp):     
        if(Loss(x, y) < 0.000001):				# --- 误差太小不继续训练
            break

        predictY = w * x + b					# --- 预测的结果

        deltaW = np.dot(x, (predictY - y)) / float(n) 
        deltaB = np.sum(predictY - y) / float(n)

        w = w - alpha * deltaW
        b = b - alpha * deltaB

        if (i + 1) % 1000 == 0:					# --- 查看更新的 w, b
            print(w, b)
    print("Loss:", Loss(x, y))   
#--- Step 5: 运行
if __name__ == '__main__':
    Train(trainX, trainY)

已知上面的 w = 0.5, b = -4.3,运行结果如下所示——
在这里插入图片描述
可以看到误差已经非常小了!说明算法的正确性,确实收敛了

总结回顾

首先我们提出了 “ 拟合绿线问题 ” ,接着利用梯度下降法来优化算法。后面的课程会具体介绍里面的每一个小步骤,并且介绍它在现实生活中的运用,并且提出一些问题——比如:为什么可以用梯度下降法优化问题?如果陷入局部最优解怎么办?如何判断算法优劣?究竟什么才是人工智能?以及微积分线性代数的补充知识,推广线性回归模型等,也许会在将来更新!

设置悬念,尽情期待!

我是Machillka,蒟蒻一枚。如果有说错的地方,各位大神千千万万要指出来。
谢谢大家!欢迎各位神犇指点!
(转载请标注出处与博主姓名)
(QQ:2437844684)
(欢迎各位大牛评论)
——————都看到这里了,不点个赞是不是也觉得不好意思呀~

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值