pytorch之反向传播(三)

反向传播

    • 反向传播算法
      • 原理
      • 关于层与层之间的顺序
    • pytorch中的反向传播算法
      • Tensor类型数据
      • 代码中说明方法

反向传播算法

反向传播算法,简称BP算法,适合于多层神经元网络的一种学习算法,它建立在梯度下降法的基础上。BP网络的输入输出关系实质上是一种映射关系:一个n输入m输出的BP神经网络所完成的功能是从n维欧氏空间向m维欧氏空间中一有限域的连续映射,这一映射具有高度非线性。它的信息处理能力来源于简单非线性函数的多次复合,因此具有很强的函数复现能力。

看下面这张图,当我们面对这样复杂的数据关系时,如果想用解析式写出他们之间的关系,可能很难达到,那么我们想是否有这样一个算法就像是一张图,图中有着每一层变量和变量之间的关系,我们可以通过这样的关系做出相应的结果。
pytorch之反向传播(三)_第1张图片

原理

算法分为两个阶段:
前向传播阶段:将训练输入送入网络以获得激励响应;
反向传播阶段:将激励响应同训练输入对应的目标输出求差,从而获得隐层和输出层的响应误差。

在输入一些数据的情况下,在运行图中每层数据时会反馈给我们一些值,这些值中包括一般的中间数据,也包括像均方误差一样能评估我们模型指标的数据,若这些评估指标没有达到我们的预期结果,我们可以让数据继续运行反向传播,返回一个梯度值,并根据梯度值进一步对于我们的权重(参数)进行进一步调整。
pytorch之反向传播(三)_第2张图片

关于层与层之间的顺序

假设还是使用比较简单的一次函数举例:
pytorch之反向传播(三)_第3张图片
W1和W2,b1和b2均是输入层中所需要输入的数据,MM和ADD是属于隐含层,MM就是乘上一个W,ADD就是加上一个b值,每一个Layer都是神经网络中的一层数据运算,y就是输出层数据,包含我们的评估指标等。另外,在运算每一层时该算法都会不断的求出每一层和上一层之间偏导数关系,这样在进行反向传播时就可以根据层与层之间的偏导数关系以及输出层的结果返回均方误差关于权值(参数)的偏导函数。有了这些偏导函数就可以对于权值进行进一步调整。

但是对于一元函数若仅仅是这样的操作得到的一个表达式,通过化简就会得到:
pytorch之反向传播(三)_第4张图片
好像经过了两层网络和没有经过神经网络的函数结果基本相同,所以我们通常会在隐含层中添加一些特殊的运算σ以增加模型复杂度:
pytorch之反向传播(三)_第5张图片
举个例子:
下面这一张图,w是权值(参数),x,y为输入层,绿色方块就是隐含层,黄色圆圈就是输出层,橙黄色内是反向传播层。
对于这样一个函数y=x*w,并有他的均方误差表达式
前向传播:在传入w值后,我们就可以由内而外的 将上一层数据结果作为该层的变量进行求偏导数,同时也将数据带入该层表达式中得出相应的输出层值,直到得到评估指标均方误差 loss
反向传播:运用链式法则将逐步求出 loss 对于权值w的偏导数。
pytorch之反向传播(三)_第6张图片
pytorch之反向传播(三)_第7张图片
这样的图叫做计算图

pytorch中的反向传播算法

Tensor类型数据

在pytorch中有一个数据类型叫做Tensor,其中存储着data权值和grad梯度,用于在框架中权值的更新,和梯度的存储供反向传播时应用。
pytorch之反向传播(三)_第8张图片
仍然以上述的简单一维数据举例:

代码中说明方法

import matplotlib.pyplot as plt
import numpy as np
import torch


def forward(x):
    # 这里的w就是初始化时的Tensor对象
    # 在和基本数据相乘时,基本数据类型会转化为Tensor对象与之运算
    # 所以x*w就是Tensor的数据类型
    return x * w


def loss(x, y):
    # Tensor类的数据类型
    y_pred = forward(x)
    # 反回Tensor类的数据类型
    return (y_pred - y) ** 2

# 训练的数据集
x_data = [1, 2, 3]
y_data = [2, 4, 6]
# 创建Tensor对象,初始化权值 w
# 在后续以Tensor数据类型为单位的运算中,都会进行自动求偏导数存储在Tensor类型中,并以返回值的形式存储
w = torch.Tensor([1.0])
# 是否存储运算过程中的计算图,这里设置为True,默认False
# 在后续中通过 Tensor对象.backward() 的方式存储在初始Tensor的变量中
w.requires_grad = True
# w=torch.tensor([1.0],requires_grad=True) 上两句可以用一句代替

l_list=[]
w_list=[]
for epoch in range(300):
    # 存储总体样本的误差值
    l_sum=0
    for x_val, y_val in zip(x_data, y_data):
        # 经过loss函数调用,返回Tensor类的数据类型,用l变量接收
        # l中data数据就是每个样本差值的平方
        l = loss(x_val, y_val)

        l_sum+=l.data.item()

        # 将l中已存在计算图返回给初始的Tensor对象w
        # 这样w就拥有了Tensor中grad的参数存储梯度计算图
        l.backward()
        """
        w下有两个数据data和grad他们的类型均为torch.Tensor
        w       :              
        w.data  :              权重本身
        w.grad  :              损失函数关于权重的导数
        w.grad.data :          w的grad数据下也有data和grad(空),data就是偏导数值
        
        w.item()    :                 对于所有的Tensor和Tensor下的数据类型data,grad
        w.data.item()   :             通过item()取出的值都是float类型的数据
        w.grad.data.item(): 
        w.grad.item()   :   

		float在和Tensor运算时自动成为Tensor,不能将float直接赋值给Tensor
        """
        # 打印出样本值和偏导数
        print('\tgrad:',x_val,y_val,w.grad.data.item())
        # 权值刷新 这种一个参数刷新一次的方式就是随机梯度下降的一种简单体现
        w.data = w.data-0.001*w.grad.data
        # w.data.item() = w.data.item()-0.001*w.grad.data.item()错误

        # 将所有偏导数设置为0,否则在后续运算过程中会有累加效应
        w.grad.data.zero_()
    # 输出迭代次数,误差值和1当前权值
    print("progress:",epoch, l_sum,w.data.item())
    l_list.append(l_sum)
    w_list.append(w.data.item())

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(range(300),w_list,label="the value of w")
ax.plot(range(300),l_list,label="the value of loss")
ax.set_xlabel("epoch")
plt.legend()
plt.show()

pytorch之反向传播(三)_第9张图片
实例化Tensor对象和创建计算图:
pytorch之反向传播(三)_第10张图片
返回计算图,赋值给初始变量中的grad:pytorch之反向传播(三)_第11张图片

你可能感兴趣的:(pytorch深度学习,神经网络,深度学习,网络,人工智能)