凸函数性质:函数上任取两点连成线段,取其中点,中点的纵坐标值大于该点映射在函数上的值。
凸函数优点:局部最优=全局最优
但现实中绝大多数的问题函数都是非凸(凹)函数,局部最优值不等于全局最优值,那么我们不想只找到局部最优解,怎么去解决这个问题从而找到全局最优解呢?
在高维空间中,可能存在一个点在一个维度上是极大值,在另一个维度上却是极小值,这种点会使神经网络的参数更新变得艰难,因为当遇到这种点的时候,总体的梯度值为0,参数无法更新。为了解决这个问题,梯度下降法进化为了随机梯度下降法。
目的:前向传播为了求取损失函数值,反向传播为了更新参数,使得参数往损失函数值小的方向走。
流程:前向传播——》反向传播——》前向传播。。。。(迭代N次)
#输入数据
input_x = [1.0,2.0,3.0,5.0,9.0]
input_y = [2.8,6.5,8.9,14.9,25.7]
#初始化权重和定义学习率
w = 1.0
learn_rate = 0.01
#定义线性模型
def linear(x):
y = w * x
return y
#定义损失函数(MSE)
# 梯度下降用的
# def cost(input_x,input_y):
# loss = 0
# for x,y in zip(input_x,input_y):
# compute_y = linear(x)
# loss += (compute_y-y)**2
# return loss/len(input_x)
#随机梯度下降用的
def loss(x,y):
compute_y = linear(x)
return (compute_y-y)**2
#定义梯度计算函数
# 梯度下降用的
# def gradient(input_x,input_y):
# grad = 0
# for x, y in zip(input_x, input_y):
# grad += 2 * x * (linear(x) - y)
# return grad
# 随机梯度下降用的
def gradient(x,y):
grad = 2 * x * (linear(x) - y)
return grad
if __name__ == '__main__':
#梯度下降用的
# for epoch in range(100):
# loss_val = loss(input_x,input_y)
# grad = gradient(input_x,input_y)
# w -= learn_rate * grad
# print("epoch:",epoch,"w=",w,"loss=",loss_val)
# 随机梯度下降用的
for epoch in range(100):
for x, y in zip(input_x, input_y):
loss_val = loss(x, y)
grad = gradient(x, y)
w -= learn_rate * grad
print("epoch:",epoch,"w=",w,"loss=",loss_val)
梯度下降法的更新用的是总样本的梯度(可以并行计算,速度更快,但是存在鞍点问题);随机梯度下降法的更新用的是每一个样本的梯度(不可以并行计算,速度更慢,但是解决了鞍点问题)。
采用折中:使用batch,不是使用总样本,也不是一个一个来,而是将总样本拆成好几份,一份一份地训练
import math
#输入数据
input_x = [1.0, 2.0, 3.0, 5.0, 5.6, 9.0]
input_y = [2.8, 6.5, 8.9, 14.9, 16, 25.7]
#初始化权重和定义学习率
w = 1.0
learn_rate = 0.01
batch = 3
#定义线性模型
def linear(x):
y = w * x
return y
#定义损失函数(MSE)
# 梯度下降用的/batch
def cost(input_x,input_y):
loss = 0
for x,y in zip(input_x,input_y):
compute_y = linear(x)
loss += (compute_y-y)**2
return loss/len(input_x)
#定义梯度计算函数
# 梯度下降用的/batch
def gradient(input_x,input_y):
grad = 0
for x,y in zip(input_x, input_y):
grad += 2 * x * (linear(x) - y)
return grad
if __name__ == '__main__':
#batch
count = math.ceil(len(input_x) / batch)
count_now = 1
num = 0
flag = 0
best_w = 0
min_loss = 99999999
for epoch in range(100):
flag = 1
while flag == 1:
ix = []
iy = []
if count_now < count or count_now == 1:
ix = (input_x[(count_now-1) * batch : count_now * batch])
iy = (input_y[(count_now-1) * batch : count_now * batch])
count_now += 1
elif len(input_x) % batch != 0:
ix = (input_x[(count_now-1) * batch : ])
iy = (input_y[(count_now-1) * batch : ])
count_now = 1
flag = 0
else:
flag = 0
count_now = 1
if len(ix) != 0:
loss_val = cost(ix, iy)
grad = gradient(ix, iy)
w -= learn_rate * grad
if loss_val < min_loss:
best_w = w
min_loss = loss_val
print("epoch:",epoch,"w=",w,"loss=",loss_val)
映射函数式为 f ( x ) = w 1 ∗ x 2 + w 2 ∗ x + b f(x)=w_1*x^2+w_2*x+b f(x)=w1∗x2+w2∗x+b
import torch
#输入数据
input_x = [1.0, 2.0, 3.0, 5.0, 5.6, 9.0]
input_y = [2.8, 6.5, 8.9, 14.9, 16, 25.7]
# input_x = [1.0,2.0,3.0]
# input_y = [2.0,4.0,6.0]
#初始化权重和定义学习率
w1 = torch.Tensor([1.0]) #参数创建为张量类型
w1.requires_grad = True #张量Tensor包括data和grad,前者是存放参数值,后者是存放反向传播计算得到的梯度值
w2 = torch.Tensor([1.0])
w2.requires_grad = True
b = torch.Tensor([1.0])
b.requires_grad = True
learn_rate = 0.01 #学习率
#定义映射函数
def forward(x):
y = w1 * x ** 2 + w2 * x + b
return y
#定义损失函数(MSE)
def loss(x,y):
compute_y = forward(x)
return (compute_y - y) ** 2
if __name__ == '__main__':
# 随机梯度下降用的
for epoch in range(100):
for x, y in zip(input_x, input_y):
loss_val = loss(x, y)
loss_val.backward()
print('\tgrad:',x,y,w1.grad.item(),w2.grad.item(),b.grad.item())
w1.data = w1.data - learn_rate * w1.grad.data #梯度更新
w2.data = w2.data - learn_rate * w2.grad.data
b.data = b.data - learn_rate * b.grad.data
# print(type(w1.grad.data)) w1.grad.data为张量
# print(type(w1.grad.item())) w1.grad.item()为常数
w1.grad.data.zero_() #清空存放的梯度值,准备下一次计算的开始
w2.grad.data.zero_()
b.grad.data.zero_()
print("epoch:",epoch,"loss:",loss_val.item())