(番外篇3)机器学习课程 实践案例
- 实战项目一:简单线性模型下BGD、SGD、Mini-Batch GD、公式解OSL和LWLR的实现 (python)
- 实战项目二:利用logistic回归进行数据分类(python)
- 实战项目三:利用LDA进行数据分类(python)
- 实战项目四:利用BP神经网络识别手写数字(python)
- 实战项目五: 利用k-means实现图像压缩(python)
实战项目一:简单线性模型下BGD、SGD、Mini-Batch GD、公式解OSL和LWLR的实现 (python)
注:在梯度下降算法中,需要特别留意学习率α\alphaα(步长)的大小设置。以BGD为例,如果α\alphaα设置过大,则会出现总误差不减反增的现象,最终导致溢出。通过查看中间输出可看到,其过程中误差函数的偏导数出现正负号轮流出现的规律,可以推断这是由于α\alphaα过大导致的震荡现象,从而使得偏导数越来越大,总误差趋向无穷。
SGD中步长更合适的方法应该是采取自适应方式,即不应当将其设为一个常值,原因在于在最后收敛处,较大的步长会影响其得到稳定的优解,而在一开始迭代时,较小的步长会影响到其迭代的速度,因此总体上步长的设置应该逐步减小。
myLm.py
import numpy as np
from numpy import dot
from numpy.linalg import inv
import random
def Lm(X,Y,method,alpha = 0.001,epsilon = 0.0000001,o = None,tau = None):
'''
X:样本矩阵 [1,x1,x2,x3,...,xn]
Y:样本标签值向量 [y]
method:训练参数时使用的方法,有OLS、BGD、SGD、MBGD、LWLM
alpha: 学习速率(步长)
epsilon:迭代终止阈值
return:本函数通过使用相应的算法,给出简单线性回归模型的参数估计值
'''
if(method == 'OLS'):
theta_0 = dot(dot(inv(dot(X.T,X)),X.T),Y)
return theta_0
elif(method == 'BGD'):
#初始值设置
theta_0 = np.ones(shape = X.shape[1])
#计算当前损失函数的总误差
error_0 = 0.5*dot((dot(X,theta_0)-Y).T,dot(X,theta_0)-Y)
#启动循环
error = epsilon+1
#迭代次数n
n = 0
while(error > epsilon):
#计算全部样本误差函数的梯度
G = dot(dot(X.T,X),theta_0)-dot(X.T,Y)
#更新theta
theta_0 = theta_0 - alpha*G
#计算步长更新后的损失函数的总误差
error_1 = 0.5*dot((dot(X,theta_0)-Y).T,dot(X,theta_0)-Y)
#计算前后二者的差
error = abs(error_1-error_0)
#将新一轮的误差保存用于下一轮
error_0 = error_1
# 输出迭代过程
# print('---------------第',n,'轮迭代--------------')
# print('theta:',theta_0)
# print('error:',error)
# print('G:',G,'\n')
n = n + 1
print('BGD Iteration Times: ',n)
return theta_0
elif(method == 'SGD'):
#初始值设置
theta_0 = np.ones(shape = X.shape[1])
#计算当前初始值下损失函数的总误差
error_0 = 0.5*dot((dot(X,theta_0)-Y).T,dot(X,theta_0)-Y)
#启动循环
error = epsilon+1
#样本量
m = X.shape[0]
#遍历列表
k = list(range(m))
#迭代次数
n = 0
while(error > epsilon):
#选择一个随机数[] r = random.randint(0,m-1)
#遍历乱序列表
random.shuffle(k)
#计算当前样本下的梯度
for r in k:
G = (dot(X[r,:],theta_0)-Y[r])*X[r,:]
#更新theta的值
theta_0 = theta_0 - alpha*G
#计算步长更新后theta_1下损失函数的总误差
error_1 = 0.5*dot((dot(X,theta_0)-Y).T,dot(X,theta_0)-Y)
#计算误差修正值大小
error = abs(error_1-error_0)
#将新一轮的误差保存用于下一轮
error_0 = error_1
# 输出迭代过程
# if(n%100 == 0):
# print('---------------第',n,'轮迭代--------------')
# print('theta:',theta_0)
# print('error:',error)
# if(n > 8000):
# alpha = 0.00001
# print('r:',r)
# print('G:',G,'\n')
n = n + 1
print('SGD Iteration Times: ',n)
return theta_0
elif(method == 'MBGD'):
#初始值设置
theta_0 = np.ones(shape = X.shape[1])
#计算当前损失函数的总误差
error_0 = 0.5*dot((dot(X,theta_0)-Y).T,dot(X,theta_0)-Y)
#启动循环
error = epsilon+1
#样本量
m = X.shape[0]
#遍历列表
k = list(range(m))
#迭代次数n
n = 0
while(error > epsilon):
#随机选取一定批量的样本
random.shuffle(k)
minBatch = k[:m//10]
minX = X[minBatch]
minY = Y[minBatch]
#计算小批量样本误差函数的梯度
G = dot(dot(minX.T,minX),theta_0)-dot(minX.T,minY)
#更新theta
theta_0 = theta_0 - alpha*G
#计算步长更新后的损失函数的总误差
error_1 = 0.5*dot((dot(X,theta_0)-Y).T,dot(X,theta_0)-Y)
#计算前后二者的差
error = abs(error_1-error_0)
#将新一轮的误差保存用于下一轮
error_0 = error_1
# 输出迭代过程
# print('---------------第',n,'轮迭代--------------')
# print('theta:',theta_0)
# print('error:',error)
# print('G:',G,'\n')
n = n + 1
print('MBGD Iteration Times: ',n)
return theta_0
elif(method == 'LWLM'):
#局部加权线性回归
XCopy = X[:,1:]-o
d = []
for i in range(XCopy.shape[0]):
d.append(dot(XCopy[i],XCopy[i]))
d = np.array(d)
w = np.exp(-d**2/(2*tau**2))
W = np.diag(w)
theta_0 = dot(dot(dot(inv(dot(dot(X.T,W),X)),X.T),W),Y)
return theta_0
else:
print('No Such Method In this Func.')
myLmtest.py 测试代码
import myLm
import numpy as np
import pandas as pd
if __name__ == '__main__':
samData = pd.read_table('mlData/regreData/simpleRegre.txt',header = None)
#转换为二维数组
sample = np.array(samData)
#将属性值与标签值分开
sampleX = sample[:,:np.shape(sample)[1]-1]
sampleY = sample[:,sample.shape[1]-1]
x = np.array([0])
#Testing
theta = myLm.Lm(sampleX,sampleY,method = 'LWLM',o = x,tau = 1)
print('LWLM:',theta)
theta = myLm.Lm(sampleX,sampleY,method = 'SGD')
print('SGD:',theta)
theta = myLm.Lm(sampleX,sampleY,method = 'BGD')
print('BGD:',theta)
theta = myLm.Lm(sampleX