预期函数:y = 5+3*x
函数模型:y = a +b*x,训练求参:a,b值
数据集:第一列是x值,第二列是y值
梯度下降算法:原理请看吴恩达机器学习课程“单变量线性回归”
# 数据获取函数
def fileIn(fileName):
data = [[],[]]
fr = open(fileName,'r',encoding='utf-8')
# 读出文件所有内容
arrayLines = fr.readlines()
# 针对有BOM的UTF-8文本,应该去掉BOM,否则后面会引发错误。
arrayLines[0] = arrayLines[0].lstrip('\ufeff')
for line in arrayLines:
# s.strip(rm),当rm空时,默认删除空白符(包括'\n','\r','\t',' ')
line = line.strip()
line = line.split(' ') # line = [xxx,xxx,xxx,xxx] 列表
data[0].append(float(line[0]))
data[1].append(float(line[1]))
return data # [[0.0,0.1,0.2,0.3,...x],[5.0,5.3,5.6,5.9,...y]]
# 梯度下降核心计算机参数值 ,inialArg表示a,b初始化参数值,stepL表示梯度下降时学习速率
# 假设函数:f(x)=a+bx
# 代价函数:J = 1/(2len(data[0]))Sum((a+bx-y)^2)
# 代价函数对参数a求偏导:deva=suma/len(data[0]),len(data[0])表示数据的数量
# 代价函数对参数b求偏导:deva=sumb/len(data[0]),
# a = a - stepL*deva
# b = b - stepL*devb
def calArg(data,inialArg,stepL):
a,b = inialArg[0],inialArg[1]
while 1:
dev1 = 0 # 参数a的偏导
dev2 = 0 # 参数b的偏导
suma = 0 # 参数a的偏导值求和
sumb = 0 # 参数b的偏导值求和
for i in range(len(data[0])):
tempy1 = a+b*data[0][i]-data[1][i] # (a+b*xi) - yi x=xi时,参数a的偏导值
tempy2 = (a+b*data[0][i]-data[1][i])*data[0][i] # [(a+b*xi) - yi]*xi x=xi时,参数b的偏导值
suma += tempy1
sumb += tempy2
dev1 = suma/len(data[0])
dev2 = sumb/len(data[0])
tempa = a - stepL*(dev1)
tempb = b - stepL*(dev2)
a = tempa
b = tempb
print(dev1,dev2) # 每次参数a,b相应的偏导数值
if abs(dev1-0)<0.00001 and abs(dev2-0)<0.00001: # 当偏导都趋近于0时,代表已经达到最优点了,训练完成,凸面的最小值导数等于0
break
return a,b
def alg(stepL):
data = fileIn("data.txt")
a,b=0,0 # 初始化(a,b)参数值为0,0
a,b=calArg(data,[a,b],stepL)
print(a,b)
if __name__ == '__main__':
alg(0.0001) # 设置参数修改步长为0.0001
梯度下降效果:前面的数值是参数a,b在相应变化值的偏导数值,最后一行是最终得到的参数值
向量化:numpy数组操作比循环高效
原公式:3x+5y-13 = z
import numpy as np
import math
# n为一个样本中,属性的数量
# m为样本的数量
# X=[x1,x2,x3] (n,m)
# xList = np.array([[0,1],[0,2],[0,3],[0,0],[1,0],[1,1],[1,2],[1,3],[2,0],[2,1],[2,2],[2,3],[3,0],[3,1],[3,2],[3,3]])
# 第一行表示x,第二行表示y
xList = np.array([[0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3],[1,2,3,0,0,1,2,3,0,1,2,3,0,1,2,3]])
# 原始正确的z值
zList = np.array([-7,-2,3,-12,-9,-3,3,8,-6,-1,6,9,-3,2,7,12]) # >12表示1,小于12表示0
# 原始z值经过激活函数后的y
yVal = 1/(1+np.exp(-1*zList)) # >12表示1
yVal = np.round(yVal,3) # 保留3位小数,四舍五入
zList.resize(16,1)
# 定义w,dw,b
w1,w2 = 0,0
dw = np.zeros((2,1)) # dw = np.zeros((n,1))
w=np.array([[w1],[w2]])
b=np.zeros((1,16))
a = 0.03
i=0
while(i<1000000):
zhat=np.dot(w.T,xList)+b # 求Z=[z1,z2,...,zm] = w.T*X +b
yhat = 1/(1+np.exp(-1*zhat)) # 求a
dz = yhat-yVal
print(np.round(dz,3))
dz.resize((16, 1))
m = len(dz)
dw = 1/m*np.dot(xList,dz)
db = 1 / m * np.sum(dz)
w = w - a*dw
b = b - a*db
i+=1
print("b:",np.round(b,3)," w:",np.round(w,3))