机器学习梯度下降法举例

本文是参考Andrew Ng网上课程和别人总结的机器学习笔记,作为笔者学习的参考,笔者主要实现了一些程序问题。

持续更新中…

更新…
先以最为简单的例子举例,比如有一个函数为 y = x 2 y=x^2 y=x2现在要求当x等于多少的时候y最小。
采用梯度下降法,即往梯度下降的方向走,已知梯度为 d y d x = 2 x \frac{dy}{dx}=2x dxdy=2x所以梯度下降的方向即 − 2 x -2x 2x,所以参数 x x x的更迭方式为 x = x + ( − 2 x ) = x − 2 x x=x+(-2x)=x-2x x=x+(2x)=x2x但通常我们加入一个表示步长的参数 η \eta η,所以更迭变为 x = x − 2 η x x=x-2\eta x x=x2ηx
于是代码如下:

import numpy as np
import time

s = time.time()

x = 10000*np.random.randn(1)  #产生服从正太分布的一个数(均值=0,方差=1),扩大10000倍
eta = 0.001
i = 1
while True:
    y = x**2
    x -= eta*2*x
    if y<=0.0001:
        print('x is %.6f\ny is %.6f\nand steps are %d'%(x,y,i))
        break
    i += 1
e = time.time()
print('time is %.4f second'%(e-s))

在这里插入图片描述
对于两个参数,也是一样的求法,如 z = x 2 + y + x y z=x^2+y+xy z=x2+y+xy
参数更迭: x = x − η d z d x = x − η ( 2 x + y ) ; y = y − η d z d y = y − η ( 1 + x ) x=x-\eta\frac{dz}{dx}=x-\eta (2x+y); y=y-\eta\frac{dz}{dy}=y-\eta (1+x) x=xηdxdz=xη(2x+y);y=yηdydz=yη(1+x)

import numpy as np
import time

s = time.time()

x,y = 10*np.random.randn(2)  #产生服从正太分布的一个数(均值=0,方差=1),扩大10000倍
eta = 0.001
i = 1

while True:
    z = x**2+y+x*y
    x -= eta*(2*x+y)
    y -= eta*(1+x)
    if z<=-10:
        print('x is %.6f\ny is %.6f\nz is %.6f\nand steps are %d'%(x,y,z,i))
        break
    i += 1
e = time.time()
print('time is %.4f second'%(e-s))

在这里插入图片描述

1 两个参数梯度下降法

现在有一组数据,plot之后如下图

x = np.array([1,3,4,7,9,10,11,18])
y = np.array([5,12,12,20,32,30,33,60])

在这里插入图片描述
现在问:当x等于8的时候,y的取值是多少?

首先看这个图,具有线性,于是我们假设先用一条直线拟合(即一次函数)
采用梯度下降法
我们的hypothesis为(两个参数 θ 0 和 θ 1 \theta_0和\theta_1 θ0θ1
在这里插入图片描述
loss function或说cost function或说目标函数(objective function)为
J ( θ 0 , θ 1 ) = 1 2 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) 2 J(\theta_0,\theta_1)=\frac{1}{2m}\sum_{i=1}^{m}(h_\theta(x^{(i)})-y^{(i)})^2 J(θ0,θ1)=2m1i=1m(hθ(x(i))y(i))2
有两个参数,使用梯度下降法参数更新为
在这里插入图片描述
用python写code

import numpy as np
import matplotlib.pyplot as plt

x = np.array([1,3,4,7,9,10,11,18])
y = np.array([5,12,12,20,32,30,33,60])

def Gradient_descent(x):
    alpha = 0.001; m = len(x)
    theta0,theta1 = np.random.randint(1,6,2) #initialize two parameters with int between [1,6)
    while(True):
        h = theta0 + theta1*x
        J = 1/(2*m)*np.sum(((h-y)**2))
        theta0 = theta0 - alpha*1/m*np.sum((h-y))
        theta1 = theta1 - alpha*1/m*np.sum(((h-y)*x))
        print(J,theta0,theta1)
        if J <=5:
            return theta0, theta1
            break

if __name__ == "__main__":
    theta0,theta1 = Gradient_descent(x)
    #plot data
    x1 = np.linspace(np.min(x),np.max(x)+1)
    y1 = theta0 + theta1*x1
    plt.scatter(x,y,marker='x')
    plt.plot(x1,y1)
    plt.show()

结果如下
在这里插入图片描述

43.375 3.00675 2.083625
36.64715182128906 3.012834703125 2.159869203125
31.055311490596658 3.0183128984472654 2.2293845909140626
26.407644730247434 3.02323818189537 2.2927655520599455
22.544711758531772 3.0276594149910023 2.3505539698782667
19.333996925479305 3.03162114306322 2.4032438603746296
16.665362113113904 3.0351639765197063 2.45128560060768
14.447267906771756 3.038324938438401 2.4950897835393393
12.603632886217634 3.0411377814545903 2.5350307323665024
11.071223279127338 3.0436332766557497 2.571449704413933
9.797483416187205 3.045839476956834 2.604657812010998
8.738732550924968 3.0477819572102907 2.634938685352499
7.858666177326327 3.0494840331059296 2.6625509001354555
7.127110425582591 3.050966960734257 2.687730190750377
6.5189867994023265 3.0522501185213633 2.710691467970093
6.013451735119135 3.0533511730925773 2.731630658405858
5.593181460948169 3.0542862304845384 2.7507263814749403
5.243777619977898 3.0550699739999385 2.768141478233133
4.9532732638769845 3.055715789884853 2.784024405157705

第一列是平方误差,可以看到误差在逐渐减小。第二第三列分别是 θ 0 和 θ 1 \theta_0和\theta_1 θ0θ1
注意:code中的alpha是learning rate,这里我取0.001;此处不能取很大,比如取1则结果会越来越差,平方误差会越来越大。

另外,这里设置了J<5时输出,也可以设置<0.01输出,但时间久一点,或者通常的,可以设置迭代的次数,比如对平方误差损失函数迭代计算100次就输出。

1 对结果分析

画出两个参数和损失函数的关系图如下
在这里插入图片描述
我们通过上面梯度下降法找到一条路径使得J越来越小,即找到最小值点。
在上面程序的基础上,如果我们画出theta0,theta1和J的函数的三维图,则如下:
在这里插入图片描述
可以看到找了一条路径来找到最小值
代码:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

x = np.array([1,3,4,7,9,10,11,18])
y = np.array([5,12,12,20,32,30,33,60])

x_scale = []
y_scale = []
z_scale = []
def Gradient_descent(x):
    alpha = 0.001; m = len(x)
    theta0,theta1 = np.random.randint(1,6,2) #initialize two parameters with int between [1,6)
    while(True):
        h = theta0 + theta1*x
        J = 1/(2*m)*np.sum(((h-y)**2))
        theta0 = theta0 - alpha*1/m*np.sum((h-y))
        theta1 = theta1 - alpha*1/m*np.sum(((h-y)*x))
        x_scale.append(theta0)
        y_scale.append(theta1)
        z_scale.append(J)
#        print(J,theta0,theta1)
        if J <=5:
            return theta0, theta1
            break

if __name__ == "__main__":
    theta0,theta1 = Gradient_descent(x)
    #plot data
#    x1 = np.linspace(np.min(x),np.max(x)+1)
#    y1 = theta0 + theta1*x1
#    plt.scatter(x,y,marker='x')
#    plt.plot(x1,y1)
#    plt.show()
    fig = plt.figure()
    ax = fig.add_subplot(111,projection='3d')
    ax.scatter(x_scale,y_scale,z_scale)
    plt.show()
2 三个参数梯度下降法

现在将参数调到三个,即
h θ ( x ) = θ 0 + θ 1 x 1 + θ 2 x 2 h_\theta(x)=\theta_0+\theta_1x_1+\theta_2x_2 hθ(x)=θ0+θ1x1+θ2x2
比如我先假定结果是
y = 2 + 3 x 1 + 7 x 2 y=2+3x_1+7x_2 y=2+3x1+7x2
先随机给出 x 1 和 x 2 的 几 个 值 x_1和x_2的几个值 x1x2,求出y作为真实结果

import matplotlib.pyplot as plt
import numpy as np

x1 = [0,1,2.2,3,3.4,5,8,10,13,15]
x2 = [2,3,4,5,2,3,4,5,18,23]

y = 2+3*np.asfarray(x1) + 7*np.asfarray(x2)

fig = plt.figure()
ax = fig.gca(projection = '3d')

ax.plot(x1,x2,y)
plt.show()

y对应的值为

16
26
36.6
46
26.2
38
54
67
167
208

图如下
在这里插入图片描述

因此再总结一下数据是:

x1 = [0,1,2.2,3,3.4,5,8,10,13,15]
x2 = [2,3,4,5,2,3,4,5,18,23]
y = [ 16. ,  26. ,  36.6,  46. ,  26.2,  38. ,  54. ,  67. , 167. ,
       208. ]

现在假设参数 θ 0 , θ 1 , θ 2 \theta_0,\theta_1,\theta_2 θ0,θ1,θ2都是未知的,要通过上面的数据使用梯度下降法得到这三个参数。
使用同上面两个参数一样的更新方法(这里 x 0 = 1 x_0=1 x0=1
在这里插入图片描述
我J的结果小于1的时候输出值,即
在这里插入图片描述
结果的最后几行为: 第 一 列 是 J , 第 二 列 到 第 四 列 分 别 是 θ 0 , θ 1 , θ 2 第一列是J,第二列到第四列分别是\theta_0,\theta_1,\theta_2 Jθ0,θ1,θ2
在这里插入图片描述
即结果近似是
h = 4 + 3 x 1 + 7 x 2 h=4+3x_1+7x_2 h=4+3x1+7x2
增加数据量并将J小于0.01才输出,则结果如下
θ 0 = 2.077 , θ 1 = 2.997 , θ 2 = 6.997 \theta_0=2.077,\theta_1=2.997,\theta_2=6.997 θ0=2.077,θ1=2.997,θ2=6.997
已经很接近真实函数
对于N个参数的拟合与上面一样

使用正规方程Normal Equation求解

对于线性回归问题,其实要得到最小值就是求导等于0即可得到参数
推导过程要用到矩阵的导数,在此不说了,可以参考课程的文本。参数求导=0可以推导得到,参数向量为
在这里插入图片描述
在这里插入图片描述
代码为

import numpy as np
x1 = [0,1,2.2,3,3.4,5,8,10,13,15]
x2 = [2,3,4,5,2,3,4,5,18,23]
x0 = [1]*len(x1)
y = [ 16. ,  26. ,  36.6,  46. ,  26.2,  38. ,  54. ,  67. , 167. ,
       208. ]
y = np.asfarray(y).T

X = np.mat((x0,x1,x2)).T
theta_left = np.dot(np.dot((np.dot(X.T,X)).I,X.T),y)
最后给出直接调用sklearn包的方法。

通过调用包可以很快的完成,因为所有的方法已经被优秀的人写入包中,代码和解释如下:

# import packages that may be used
import numpy as np
from sklearn import linear_model

#make data linear regression from datasets
x1 = [0,1,2.2,3,3.4,5,8,10,13,15]
x2 = [2,3,4,5,2,3,4,5,18,23]

X = np.array([[0,2],[1,3],[2.2,4],[3,5],[3.4,2],[5,3],[6,4],[10,5],[13,18],[15,23]])

# y = 2+3*x1+7*x2
Y = 2+np.dot(X,np.array([3,2]))

#create linear regression object
reg = linear_model.LinearRegression()

#Train the model using the training sets
reg.fit(X,Y)

#Make predictions using the testing set
test_pred = reg.predict(np.array([[4,2]]))

# The coefficients 
print('coefficients and intercept >> ',(reg.coef_, reg.intercept_))

在这里插入图片描述
从输出的结果知道
θ 0 = 1.999999 , θ 1 = 3 , θ 2 = 7 \theta_0=1.999999, \theta_1=3,\theta_2=7 θ0=1.999999,θ1=3,θ2=7

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值