1.线性模型
线性模型
y
^
=
x
∗
w
\widehat{y}=x*w
y
=x∗w
损失函数
l
o
s
s
=
(
y
^
−
y
)
2
loss=(\widehat{y}-y)^2
loss=(y
−y)2
import numpy as np
import matplotlib.pyplot as plt
x_data=[1,2,3]
y_data=[2,4,6]
def y_hat(x,w):
return x*w
def loss(x,y):
return (y_hat(x,w)-y)**2
w_list,mse_list=[],[]
for w in np.arange(0,4,0.1):
# print('w={}'.format(w),sep='')
# print('w={}'.format(w))
cur_loss=0
for x_i,y_i in zip(x_data,y_data):
cur_loss+=loss(x_i,y_i)
w_list.append(w)
mse_list.append(cur_loss/3)
# print(cur_loss)
plt.figure(figsize=(4,2))
plt.plot(w_list,mse_list)
plt.xlabel('w')
plt.ylabel('mse')
plt.show()
模型
y
^
=
x
∗
w
+
b
\widehat{y}=x*w+b
y
=x∗w+b
损失函数
l
o
s
s
=
(
y
^
−
y
)
2
loss=(\widehat{y}-y)^2
loss=(y
−y)2
mse_list=[]
for w in np.arange(0,4,0.1):
mse_cur=[]
for b in np.arange(-2,2,0.1):
cur_loss=0
for x_i,y_i in zip(x_data,y_data):
cur_loss+=loss_3d(x_i,y_i)
mse_cur.append(cur_loss/3)
mse_list.append(mse_cur)
w=np.arange(0,4,0.1)
b=np.arange(-2,2,0.1)
plt.contourf(w,b,mse_list)
plt.xlabel('w')
plt.ylabel('b')
plt.show()
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
fig = plt.figure()
ax = Axes3D(fig)
mse_list_copy=np.array(mse_list)
ww,bb=np.meshgrid(w,b)#40x40每行相同 40x40每列相同
surf=ax.plot_surface(ww,bb,mse_list_copy, rstride=1, cstride=1, cmap=cm.coolwarm,)
ax.set_zlim(0,35)
ax.set_xlabel('w')
ax.set_ylabel('b')
ax.set_zlabel('mse')
ax.set_title('figure')
fig.colorbar(surf, shrink=0.5, aspect=5)
2.梯度下降
梯度消失
局部最优解(深度学习算法中,并没有过多的局部最优点。)
x_data=[1,2,3]
y_data=[2,4,6]
w=1
alpha=0.01
def cost(xn,yn):
cost=0
for x,y in zip(xn,yn):
cost+=(x*w-y)**2
return cost/len(xn)
def gradient(xn,yn):
grad=0
for x,y in zip(xn,yn):#共用一个w,可以并行计算加速
grad+=2*x*(x*w-y)
return grad/len(xn)
pos=[]
w_list=[]
cost_list=[]
for epoch in range(20):
w-=alpha*gradient(x_data,y_data)
pos.append(epoch)
w_list.append(w)
cost_list.append(cost(x_data,y_data))
# if epoch%100==0:
# print(cost(x_data,y_data))
# print(w)
#并行计算,计算20轮,本应60,实际时间20
import matplotlib.pyplot as plt
plt.figure(figsize=(5,3))
plt.plot(pos, w_list, color='green', label='w_list')
plt.plot(pos, cost_list, color='red', label='cost_list')
plt.legend()
plt.show()
## SGD
x_data=[1,2,3]
y_data=[2,4,6]
w=1
alpha=0.01
def cost(xn,yn):
cost=0
for x,y in zip(xn,yn):
cost+=(x*w-y)**2
return cost/len(xn)
def gradient(x,y):
return 2*x*(x*w-y)
pos=[]
w_list=[]
cost_list=[]
for epoch in range(20):
cur_pos=epoch*len(x_data)
for x_i,y_i in zip(x_data,y_data):#w前后依赖,不能并行计算
w-=alpha*gradient(x_i,y_i)
pos.append(cur_pos)
w_list.append(w)
cost_list.append(cost(x_data,y_data))
# if epoch%100==0:
# print(cost(x_data,y_data))
# print(w)
#不能并行计算,计算20轮,本应60,实际时间60
import matplotlib.pyplot as plt
plt.figure(figsize=(5,3))
plt.plot(pos, w_list, color='green', label='w_list')
plt.plot(pos, cost_list, color='red', label='cost_list')
plt.legend()
plt.show()
随机梯度下降法和梯度下降法的主要区别在于:
1、损失函数由cost()更改为loss()。cost是计算所有训练数据的损失,loss是计算一个训练函数的损失。对应于源代码则是少了两个for循环。
2、梯度函数gradient()由计算所有训练数据的梯度更改为计算一个训练数据的梯度。
3、本算法中的随机梯度主要是指,每次拿一个训练数据来训练,然后更新梯度参数。本算法中梯度总共更新20(epoch)x3 = 60次。梯度下降法中梯度总共更新20(epoch)次。
梯度下降:整体算(mini batch=n),性能高(一轮内部有多个样本并行计算,w的更新是相互独立的),效果差。
随机梯度下降:一个一个算(mini batch=1),性能差(计算相同规模,计算时间是梯度下降n倍),效果好。
折衷:引入mini batch,批量的随机梯度下降。
3.反向传播
简单模型的损失函数更新值可以用解析式进行表示,当遇到复杂模型时,解析式复杂,难以直接表示。基于链式求导法则,引入反向传播。
线性模型无论叠加多少层都会化简为一层,因此引入非线性因素(激活函数),使得神经网络可以逼近任意的非线性函数。
此外,在线性模型的基础上套一个映射函数可以实现分类。(如Sigmoid是R上的x→R上的f(x)→[0,1]上的p)
import torch
x_data=[1,2,3]
y_data=[2,4,6]
w=torch.Tensor([1])
w.requires_grad=True
def forward(x):
return x*w
def loss(x,y):
y_pred=forward(x)
return (y_pred-y)**2
alpha=0.01
for epoch in range(100):
for x,y in zip(x_data,y_data):
l=loss(x,y)#前向计算
l.backward()#反向传播
w.data-=alpha*w.grad.data
w.grad.data.zero_()
print(epoch,l.item())
1.w是Tensor(张量类型),Tensor中包含data和grad,data和grad也是Tensor。grad初始为None,调用l.backward()方法后w.grad为Tensor。
Tensor:w(带计算图) w.grad(带计算图) w.data w.grad.data
标量:xx.item()
取w.grad.data是不会构建计算图的。
2.w是Tensor, forward函数的返回值也是Tensor,loss函数的返回值也是Tensor
3.本算法中反向传播主要体现在,l.backward()。调用该方法后w.grad由None更新为Tensor类型,且w.grad.data的值用于后续w.data的更新。
4.如果w需要计算梯度,那构建的计算图中,跟w相关的tensor都默认需要计算梯度。l.backward()会把计算图中所有需要梯度(grad)的地方都会求出来,然后把梯度都存在对应的待求的参数中,最终计算图被释放。
import torch
x_data=[1,2,3]
y_data=[2,4,6]
w1,w2,b=torch.Tensor([[1],[1],[1]])
w1.requires_grad=w2.requires_grad=b.requires_grad=True
def forward(x):
return w1*x*x+w2*x+b
def loss(x,y):
y_pred=forward(x)
return (y_pred-y)**2
alpha=0.01
for epoch in range(100):
for x,y in zip(x_data,y_data):
l=loss(x,y)
l.backward()
w1.data-=alpha*w1.grad.data
w2.data-=alpha*w2.grad.data
b.data-=alpha*b.grad.data
w1.grad.data.zero_()
w2.grad.data.zero_()
b.grad.data.zero_()
print(epoch,l.item())
4 Pytorch实现线性回归
%%time
import torch
x_data=torch.Tensor([[1],[2],[3]])
y_data=torch.Tensor([[2],[4],[6]])
class LinearModel(torch.nn.Module):
def __init__(self):
super(LinearModel,self).__init__()
self.linear=torch.nn.Linear(1,1)
def forward(self,x):
y_pred=self.linear(x)
return y_pred
model=LinearModel()
criterion=torch.nn.MSELoss(size_average=False)
optimizer=torch.optim.SGD(model.parameters(),lr=0.01)
for epoch in range(1000):
y_pred=model(x_data)
loss=criterion(y_pred,y_data)
if epoch%100 ==0:
print(epoch,loss.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
print('w=',model.linear.weight.item())
print('b=',model.linear.bias.item())
x_test=torch.Tensor([[4]])
y_test=model(x_test)
print(y_test.item())