输入为,每个圆圈为一个神经元,连接神经元之间的线对应不同的权值,所以从输入到第一个隐藏层
(hidden layer)共有5*6=30个权值如下图
w为6*5的矩阵
整个函数的解析式不容易直接写出,所以直接端到端的求很困难,故使用链式法则反向传播导数,最终
对于矩阵的求导,cookbook有现成的公式,pytorch也有现成的函数调用
如,计算图(Computational Graph)如下
发现函数可以简化如下
y的计算公式可简化,对于这种线性变换不管多少层都可以简化,这样模型的复杂度不够高,中间的权重没有意义,所有在每一层的输出都要加一层非线性的变化函数(激活函数sigmoid relu)如
Tensor是pytorch里存数据的东西,包含两个数据类型data,grad(导数),可以是数值、向量、矩阵
构建模型就是构建一个计算图
①先计算整个模型的损失(前向传播forward)
②反向传播backward,得到梯度值
③对权重进行更新
pytorch框架的backward()相当于把梯度计算函数(对loss函数进行求导,以及多层嵌套函数的求导链式法则)给提前封装好进行调用了因此在实际应用中使用梯BP算法,我们只需要根据实际问题定义好损失函数即可
写一个使用pytorch拟合y=wx 并画图,使用SGD
import matplotlib.pyplot as plt
import torch
x_data = [1.0,2.0,3.0]
y_data = [2.0,4.0,6.0]
#随机梯度下降拟合y=wx
w = torch.Tensor([1.0]) #初始权值为1,设置为Tensor类型
w.requires_grad=True #设置w需要反向传播
a=0.01 #学习率为0.01
def forward(x): #求当前权值下预测值
return x*w #运算符重载
def loss(x,y): ##求单个点的loss值
y_pred=forward(x)
return (y_pred-y)**2
epoch_list=[]
cost_list=[]
print('predict(before training)','x=4 y=',forward(4).item()) ###训练前对x=4.0的y值预测
for epoch in range(100):
for x,y in zip(x_data,y_data):
loss_val=loss(x,y) #一个点求loss
loss_val.backward() #自动反向传播,自动求计算图需要求梯度的权值,并存到w.grad中,并释放计算图
print('\tgrad:',x,y,w.grad.item())
w.data=w.data-a*w.grad.data #更新权值,要加data,不然又创建计算图了
w.grad.data.zero_() #梯度清零
print('epoch:',epoch,'w=',w.item(),'loss=',loss_val.item())
epoch_list.append(epoch)
cost_list.append(loss_val.item()) #一轮中最后一个样本的loss
print('predict(after training)','x=4 y=',forward(4).item()) ###训练后对x=4.0的y值预测
plt.plot(epoch_list,cost_list)
plt.ylabel('loss')
plt.xlabel('epoch')
plt.show()
if __name__ == "__main__":
main()
每调用一次loss函数,就构造一次计算图
调用backward()自动计算计算图里的梯度即反向传播,然后释放计算图(动态计算图)
构建计算图时直接使用张量,权重w更新的时候使用.data,不能直接使用张量,否则创建新的计算图(不要在释放后用tensor直接计算,会构建新的计算图,要用item()标量)
最后w.grad.data.zero_()把梯度清零,避免影响下一次计算结果
写一个使用pytorch拟合y=w1x ^2+w2x+b
import matplotlib.pyplot as plt
import torch
from mpl_toolkits.mplot3d import Axes3D
x_data = [1.0,2.0,3.0]
y_data = [2.0,4.0,6.0]
#随机梯度下降拟合y=w1x^2+w2x+b
w1 = torch.Tensor([1.0]) #初始权值为1,设置为Tensor类型
w2 = torch.Tensor([1.0])
b = torch.Tensor([1.0])
w1.requires_grad=True #设置w1需要反向传播更新
w2.requires_grad=True #设置w2需要反向传播更新
b.requires_grad=True #设置b需要反向传播更新
a=0.001 #学习率为0.001
def forward(x): #求当前权值下预测值
return x**2*w1+x*w2+b #运算符重载
def loss(x,y): ##求单个点的loss值
y_pred=forward(x)
return (y_pred-y)**2
epoch_list=[]
cost_list=[]
print('predict(before training)','x=4 y=',forward(4).item()) ###训练前对x=4.0的y值预测
for epoch in range(100):
for x,y in zip(x_data,y_data):
loss_val=loss(x,y) #一个点求loss
loss_val.backward() #自动反向传播,自动求计算图需要求梯度的权值,并存到w.grad中,并释放计算图
print('\tgrad:',x,y,w1.grad.item(),w2.grad.item(),b.grad.item())
w1.data=w1.data-a*w1.grad.item() #更新权值,要加data,不然又创建计算图了
w2.data=w2.data-a*w2.grad.item()
b.data=b.data-a*b.grad.item()
w1.grad.data.zero_() #梯度清零
w2.grad.data.zero_()
b.grad.data.zero_()
print('epoch:',epoch,'loss=',loss_val.item())
epoch_list.append(epoch)
cost_list.append(loss_val.item()) #一轮中最后一个样本的loss
print('predict(after training)','x=4 y=',forward(4).item()) ###训练后对x=4.0的y值预测
plt.plot(epoch_list,cost_list)
plt.ylabel('loss')
plt.xlabel('epoch')
plt.show()
if __name__ == "__main__":
main()
.data(a)
将变量a变为tensor,将
requires_grad
设置为Flase
a.item()
Tensor类型的变量a转换成float类型