PyTorch深度学习实践——反向传播

总结:

     在这一节的学习中,学习到反向传播相关知识,对于反向传播算法,同样也是通过三个方面来进行总结:反向传播算法是什么?为什么需要反向传播?如何实现反向传播?

反向传播算法是什么?

给出官方定义:

      BP算法由信号的正向传播和误差的反向传播两个过程组成。

      正向传播时,输入样本从输入层进入网络,经隐层逐层传递至输出层,如果输出层的实际输出与期望输出(导师信号)不同,则转至误差反向传播;如果输出层的实际输出与期望输出(导师信号)相同,结束学习算法。

      反向传播时,将输出误差(期望输出与实际输出之差)按原通路反传计算,通过隐层反向,直至输入层,在反传过程中将误差分摊给各层的各个单元,获得各层各单元的误差信号,并将其作为修正各单元权值的根据。这一计算过程使用梯度下降法完成,在不停地调整各层神经元的权值和阈值后,使误差信号减小到最低限度。

    定义比较官方,简单来说,BP算法实际上是分为正向传播和反向传播,正向传播得到相应损失,反向传播经过一系列过程得到最终梯度

为什么需要反向传播?

    回顾之前学习的简易的线性模型,我们拿到相应的输入x,然后通过权重值w和x相乘得到对应的输出y_hat,最后通过真实值y与y_hat作损失,通过梯度下降或者穷举的方法找到loss的最小值,然后对w进行更新,将线性模型使用简单的神经网络(Neurn)表示得到以下图:

     然而我们知道,深度学习模型不都是简单的线性模型,对于复杂的模型而言,权重与输入更为复杂:

     对于上图的解释,首先要提到的概念便是"输入维度",什么是输入的维度?对此我是这样理解的:我们知道空间中的维度分别对应点,线,面,体。

     对于维度我们也可以从这个角度来理解:维度是指一个属性(方向),那么什么是属性(方向)呢?举个例子,对于一个男生而言,拥有以下属性:

      当财富是第一个属性时,那么穷-富这一方向便是这个属性所独有的,依次类推,身高,性别,好坏就是第二个属性,第三个属性,第四个属性.....但我们会发现,当对于一个男生而言,属性越多,这个男生也就更加的 "具体"了,也就是越来越有真实感(饱满),因此对于这里的数据维度输入,也是同样,不同的x1,x2,x3可以理解为对于一个模型不同方向的 "属性"输入,而这些属性来使得越复杂的模型越为饱满。

     再回归到上图:

 d

     当一个模型输入是多维的,在这里是5维,对于隐藏层h1而言,隐藏层的输出是6维度,而需要使得输入能与h1(h1是hide的简写也就是隐藏层1)的输出对应起来,那就涉及到维度转换,这里可以通过w权重矩阵进行转换,线性代数高数我们当权重矩阵w是6*5的向量时,输入的5维可以转换 为输出6维,因此在输入x-h1的权重矩阵需要6*5也就是30维w,依次类推h1-h2需要6*7=42维w,h2-h3中需要49维w,对于这种复杂的模型,函数之间是一个嵌套非常多的复杂结构,因此想写出loss的解析式变得几乎不可能实现,因此对于w的梯度也无法得到

     因此对于这种复杂的网络,我们考虑能不能将这种网络变成一个计算"图",使用某种方法将网络中的梯度进行传播,再利用链式法将最终的梯度求得,而不是直接求出loss函数再求得最终梯度,这种方法便是Backpropagation反向传播法

如何实现反向传播?

假定两层结构的神经网络:

    构造出基本的计算图:

     对于第一次层结构,输入n维向量,输出m维向量,权重矩阵就该为m*n维矩阵,对于输入的m维向量加入的bias偏置值,我们同样也应该是m*1维的矩阵(每一个hide层单元都需要单独加上b值)。当x与y_hat都是多维输入和输出时,也就与上文神经网络图一一对应起来

     这种计算图也存在一个问题,每一层的输入都是上一次输入的线性函数,那么无论有多少隐藏层层我们也可以通过化简得到output与input的线性组合:

    因此我们在每一层的神经网络中需要一个非线性函数单元Nonlinear Function进行处理,例如,将h1得到的x1转换为/1(1+e^-x1),同理对于x2,x3...也同样进行变换换,使得函数无法进行展开

    计算图构建完毕,那么如何利用链式法制进行局部求导(梯度)呢?如下图:

loss对于z的求导可以看作后一层对于前层的返回结果(这里不用纠结),而为什么需要对于x的局部求导结果呢?对于第一层时,x的局部求导的确用处不大,但对于中间结果时候,是需要知道L对于x的导数结果的

给出具体实例:当模型为一层的网络结构并且b值为0时,假定w为1,输入x为1

    因此对于反向传播求梯度的过程可以这样理解,bp算法在正向传播时(前馈)时,不光会得到最终的loss值,对于每一步的局部梯度,局部导数与相应局部值(局部y_hat,输入w值等)也会得到保存,在反向传播时,模型就可以利用正向传播得到局部梯度再通过链式法消除局部的梯度得到最终loss与w的梯度

代码实现:

   对于代码实现,需要提到tensor数据成员,类似c语言的结构体,分别存储节点的权重(data部分)和上述提到的局部导数(grad部分,grad其实也是一种tensor)

构建线性模型y=w*x的计算图

import torch
x_data = [1.0,2.0,3.0]
y_data = [2.0,4.0,6.0]

w = torch.Tensor([1.0])
print(w)
w.requires_grad = True

def forwrad(x):#这一步会进行数值转换,将两者都转换为tensor变量
    return x*w

def loss(x,y):#理解为动态构建计算图
    y_pred = forwrad(x)
    return (y_pred-y)**2


for epoch in range(100):
    for x,y in zip(x_data,y_data):
        l = loss(x,y)
        l.backward()#将计算链上需要的梯度求出来并梯度结果存到变量中,这里涉及到的变量为w变量
        #调用完计算图会自动释放
        #print(w.grad.item())#把grad里的值变为标量输出
        w.data = w.data-0.01*w.grad.data#不取得grad的data部分会构建出计算图,我们只是对于权重的data部分进行修改
        w.grad.data.zero_()#w的梯度重置为0
    print("Progress",epoch,"%2f"%l.item())
#print(l)
#print(w.data)
#print(w.grad.item())#将梯度转换为标量
#print(w.grad.data)

构建二次模型y = w1*x1^2 + w2*x2 + b

 显然这个二次模型应该为:y=x^2+x+1,对应的结果w1=1,w2 =1,b=1,输入x为4对应预测值该为21

import torch
x_data = [1.0,2.0,3.0]
y_data = [3.0,7.0,13.0]

w1= torch.Tensor([0.3])
w1.requires_grad =True
w2 = torch.Tensor([0.5])
w2.requires_grad =True
b= torch.Tensor([0.8])
b.requires_grad = True


def forward(x):
    return w1*x**2 + w2*x + b
def loss(x,y):
    y_pred = forward(x)
    return (y_pred-y)**2

print("predict after training ", 4, forward(4).item())
for epoch in range(100):
    for x,y in zip(x_data,y_data):
        l = loss(x,y)
        l.backward()
        w1.data = w1.data-0.01*w1.grad.data
        w2.data = w2.data -0.01*w2.grad.data
        b.data = b.data - 0.01*b.grad.data
        print(f"Progress:{epoch}  w1.grad={w1.grad.data} w2.grad={w2.grad.data} b.grad={b.grad.data} loss={l.data.item()}")
        w1.grad.data.zero_()
        w2.grad.data.zero_()
        b.grad.data.zero_()
print(f"w1={w1.data.item():.2f}  w2={w2.data.item():.2f}   b={b.data.item():.2f}")
print("predict after training ", 4, forward(4).item())

结果展示:
 

 本人小白一枚,刚入深度学习坑,纯粹自我总结,有问题请大佬指出!不胜感激

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值