一,梯度下降求最小值:
1,配方法
2,求导
3,梯度下降法
首先,什么是梯度
我的理解:
方向导数是在某函数定义域内一点对某方向求导所得的导数,当该函数在某一方向取得最大值时,这时的方向导数就是梯度,此时,函数的变化率最大,变化最快
然后
再来看梯度下降法的代码怎么写
选用 Y = x^2-6x+9 作为参考
1,选择初始化数据:(x,步长,迭代次数的值)
令x=6,则y=81
步长(学习率):lr = 0.3(步长是指数值型数据在每次迭代中更新的幅度,通常表示为一个小数。)
迭代次数:Num = 45
图像如图:
2,开始迭代:
先将函数的导数自己算出:y = 2*x - 6
用for循环完成每次迭代:
for i in range(Num):
x = x-lr*(2*x-6)
3,最后打印出来x
完整代码
import matplotlib.pyplot as plt
import torch
import numpy as np
#函数图象:
x = np.linspace(-1,7,100)
y = x**2 - 6*x + 9
plt.plot(x,y)
plt.show()
#y`=2x-6
#初始化:
x = 6
lr = 0.3 #步长
Num = 45 #迭代次数
for i in range(Num):
x = x-lr*(2*x-6)
print("第",i+1,"次迭代:",x)
运行结果
可以看出到41次时就可以迭代到我们这个函数的最小值
实际上当相邻两次迭代的x的值相差不大时基本就可以确定最小值了
特别情况:
有时会出现x的值在来回震荡,说明步长选取稍大,导致函数不太容易去收敛
有时会出现x的值变化太小,说明步长选取过小,每次迭代x的值基本不变
二,梯度下降法求线性回归方程
数据
猜测线性回归方程:
y = wx
即,初始化:
w=6
lr=50
num=20
类比
一(梯度下降法求最小值):
一 中的x相当于成了现在的w
而,
猜测值与真实值之差越小(w*x-y),就代表w的值越准确
用一个损失方程表示:
loss = 1/2.0 * np.sum((w*x-y)**2)
因为可能是负数故而用平方避免
1/2为了方便求导
然后
对(x*w-y)**2进行求导得
2 *(x*w-y)* x
迭代
for i in range(num):
w_gra = np.mean((w*x-y)*x)
w = w - lr * w_gra
loss = 1/2.0 * np.sum((w*x-y)**2)
完整代码
import matplotlib.pyplot as plt
import torch
import numpy as np
x = np.array([0.18,0.1,0.16,0.08,0.09,0.11,0.12,0.17,0.15,0.14,0.13])
y = np.array([0.36,0.2,0.32,0.16,0.18,0.22,0.24,0.34,0.30,0.28,0.26])
lr = 50
w = 6
num = 20
for i in range(num):
w_gra = np.mean((w*x-y)*x)
w = w - lr * w_gra
loss = 1/2.0 * np.sum((w*x-y)**2)
print("迭代第",i+1,"次,","梯度:",w_gra,",权重:",w,",损失:",loss)
结果
第一种方法用pytoch顺序结构实现梯度下降求线性回归
使用工具pytorch可以让我们更加便捷的去用梯度下降求线性回归方程
数据的准备和初始化:
torch.mm(a,b):矩阵a,b相乘
loss. backward():自动求损失函数的导数
迭代
这里进行模型的前向传播、反向传播和权重更新
for i in range(num):
y_pre = torch.mm( x_data , w)+b
loss = ((y_pre-y_data)**2).mean()
losses.append(loss)
if w.grad is not None:
w.grad.data.zero_()
if b.grad is not None:
b.grad.data.zero_()
loss.backward()
w.data = w.data - lr * w.grad
b.data = b.data - lr * b.grad
完整代码:
import matplotlib.pyplot as plt
import torch
import numpy as np
#准备数据
x_data = torch.tensor([[0.18],[0.1],[0.16],[0.08],[0.09],[0.11],[0.12],[0.17],[0.15],[0.14],[0.13]])
y_data = torch.tensor([[1.36],[1.2],[1.32],[1.16],[1.18],[1.22],[1.24],[1.34],[1.30],[1.28],[1.26]])
#定义参数(初始化)
w = torch.tensor([[10]],requires_grad=True,dtype=torch.float32)
b = torch.tensor([0],requires_grad=True,dtype=torch.float32)
lr = 0.9
num = 5000
losses = []
for i in range(num):
y_pre = torch.mm( x_data , w)+b
loss = ((y_pre-y_data)**2).mean()
losses.append(loss)
if w.grad is not None:
w.grad.data.zero_()
if b.grad is not None:
b.grad.data.zero_()
loss.backward()
w.data = w.data - lr * w.grad
b.data = b.data - lr * b.grad
print("权值(w):",w.item(),"b:",b.item(),"loss:",loss.item(),"迭代次数:",i+1)
plt.figure(figsize=(10, 5))
plt.plot(range(num), losses, label='Loss')
plt.title('f_loss`s picture')
plt.xlabel('epoch')
plt.ylabel('Loss')
plt.legend()
plt.show()
丢失图像:
第二种方法封装类实现梯度下降拟合线性回归 :
这个方法相当于是y_pre,loss的计算和loss,w,b的求导以及步长(学习率),迭代次数等数据的初始化写成了函数方便于调用,将这些函数归到一个类里
数据的初始化:
y_pre,loss的计算:
loss,w,b的求导:
最后
一这组数据为例,通过这种方法求线性回归方程
x_data = torch.tensor([[0.18],[0.1],[0.16],[0.08],[0.09],[0.11],[0.12],[0.17],[0.15],[0.14],[0.13]])
y_data = torch.tensor([[1.36],[1.2],[1.32],[1.16],[1.18],[1.22],[1.24],[1.34],[1.30],[1.28],[1.26]])
num = 5000
lss = Lss(lr=0.9)
for i in range(num):
lss.forward(x_data,y_data)
lss.backward()