好家伙,这作业我上周就想写了
太久没更新博客了,因为这段时间实在没解决啥技术问题(或者说,遇到了技术问题懒得解决)。
生活方面嘛,我在社交上取得了重大突破。
梯度下降法
利用了:
- python
- spyder
- 最优化导论p92页
所谓最优化技术,就是要搞最优化。那么,这里,我们需要想办法拟合出一条最优的直线出来,这能有多难(how hard can it be)?——很难,绝对值求导问题困了我好久,最后一看好家伙,损失函数不用绝对值呐。
大概就是这么几步,目的是找到最优的斜率k和y轴截距取值b,让损失函数最小。
具体来说,
- 先把损失函数(二次方形式的比绝对值好用些,绝对值形式的求导好像会出问题)给出来,用符号变量的形式;
- 然后再用sympy库里的求导功能把偏导表达式搞到手;
- 后面就是对照书本上的梯度下降公式,一层一层往前推进了,可以把这些系数放在一个扩张的list里面;
- 当偏导数非常小的时候,就当作收敛完成,跳出。
呃呃,
老夫聊发少年狂,欢迎指正错误!
代码:
from sympy import *#符号运算 有点像matlab
import matplotlib.pyplot as plt#画图用
import random
a=[]
b=[]
alpha= 0.001
error= 0.00000001
n= 10
for i in range(n):
a.append(10*random.random())
b.append(10*random.random())
plt.scatter(a,b) #绘制初步的散点图,就是两个list对应嘛
########################################
#函数
x1, x2 = symbols('x1, x2')
dist=[]
for i in range(9):
dist.append((x1*a[i]+x2-b[i])**2)
z= sum(dist)#是的,符号变量这都顶得住,还真能求导
d1=diff(z,x1)
d2=diff(z,x2)
########################################
#start
px=[]
py=[]
px.append(0)
py.append(0)
k=0
temp1=d1.subs({x1:px[k],x2:py[k]})
temp2=d2.subs({x1:px[k],x2:py[k]})
while(abs(d1.subs({x1:px[k],x2:py[k]})+ d2.subs({x1:px[k],x2:py[k]}))> error):#每一次都更新一对新的函数k与b(kx+b)
px.append(px[k]-alpha*d1.subs({x1:px[k],x2:py[k]}))
py.append(py[k]-alpha*d2.subs({x1:px[k],x2:py[k]}))
k= k+1
########################################
#拟合直线
print(px[k],py[k])
y=[]
for i in range(n):
y.append(px[k]*a[i]+py[k])
plt.plot(a,y)#画线,理论上两个点就成
########################################
#损失函数值
cost=[]
for i in range(n):
cost.append((px[k]*a[i]+py[k]-b[i])**2)#可以更简单一些!
print(sum(cost)/(2*n))
一些结果:
欢迎来重庆玩!