《PyTorch深度学习实践》第四节:反向传播

指路《PyTorch深度学习实践》第三节:反向传播

上节课学到权重的更新过程其实就是 :利用损失函数loss对权重的导数,通过梯度下降法一步步对权重更新最终达到损失函数最小。

这次课主要是利用torch来进行反向传播,达到权重更新的效果。

在这里插入图片描述

**补充:**下图是一个简单地例子,我们用线性模型构成一个神经网络,那么线性变化下,无论多少层最后都会化为一样的形式。也就是说无论增加多少权重,最后都会没有意义,因此每一层后都有必要加入一个非线性函数 。这里先一笔带过,具体的激活函数后面会讲到。
在这里插入图片描述
在网络中反向传播其实就是一长串的链式求导:L对z的导数室友Z之后的网络传播回来的,算出L对X的导数后,又可以继续向前传播。实质上就是一直链式求导,找到L对w(权重)的梯度,然后利用梯度下降。
在这里插入图片描述
这是一个具体求L对w梯度的例子:
在这里插入图片描述
以上就是 反向传播的原理,对于用pytorch实现反向传播的过程,在代码中写了一些注释,但是对于tensor的概念如下图,目前没有完全理解
在这里插入图片描述
在这里插入图片描述

课堂中的代码实例:

import torch

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

w = torch.Tensor([1.0])
w.requires_grad = True   #计算梯度

def forward(x):
    return x*w

'forward中w已经是一个tensor,那么在运算时,x会自动类型转换成tensor,得到的结果也是一个tensor'

def loss(x,y):
    y_pred = forward(x)
    return (y_pred-y)**2

print("predict (before training):", "x=4", "y=",forward(4).item())

for epoch in range(100):
    for x, y in zip(x_data,y_data):

        "正向传播,计算出损失loss,得到的l就是一个张量"
        l = loss(x, y)

        "反向传播,计算出每个需要的梯度,注意:backward后上一步画出的计算图就会被释放,下一次循环时又被loss所画出"
        l.backward()

        "l.backward()计算出了整个计算图中所需的梯度,我们需要用loss对w的导数对w的值进行更新"
        "在torch中这个值就存储于w,此时torch中w是一个tenor"
        "它包含了值data和导数grid,其中grid也是一个tensor"
        "如果直接使用w.grid则会在此处又建立一个计算图,但我们不需要,我们只需要在下一个循环的loss处生成计算图"
        w.data -= 0.01*w.grad.data

        "由于之前l.backward计算出的grid会被保留,如果不进行清零,那么每次都会进行累加"
        w.grad.data.zero_()

    print("progress", epoch,l.item())

print("predict(after training):", "x=4", "y=",forward(4).item())

结果为:
predict (before training): x=4 y= 4.0
……
progress 99 9.094947017729282e-13
predict(after training): x=4 y= 7.999998569488525

作业:y=w1*x^2 +w2-x+b
loss = (y_pred - y)^2
其实就是对w1、w2、b这三个参数都进行反向传播,利用l.baclward计算出每个梯度,有梯度之后就可以利用loss对这三个参数的梯度对其进行各自的更新
代码如下:

import torch

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

w1 = torch.Tensor([1.0])
w1.requires_grad = True
w2 = torch.Tensor([1.0])
w2.requires_grad = True
b = torch.Tensor([1.0])
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 (before training):", "x=4", "y=",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 -= 0.01*w1.grad.data
        w1.grad.data.zero_()
        w2.data -= 0.01 * w2.grad.data
        w2.grad.data.zero_()
        b.data -= 0.01 * b.grad.data
        b.grad.data.zero_()

    print("progress", epoch,l.item())

print("w1=", w1.item(), "w2=", w2.item(), "b=", b.item())
print("predict(after training):", "x=4", "y=",forward(4).item())

结果为:
predict (before training): x=4 y= 21.0
……
progress 99 0.00631808303296566
w1= 0.24038191139698029 w2= 0.9266766309738159 b= 0.99135422706604
predict(after training): x=4 y= 8.544171333312988

我们在最后尝试输出b.data查看data是是个tensor还是标量

print("w1=", w1.item(), "w2=", w2.item(), "b=", b.data)

结果为:w1= 0.24038191139698029 w2= 0.9266766309738159 b= tensor([0.9914])
说明data也并不是一个标量

猜你喜欢

转载自blog.csdn.net/weixin_44894550/article/details/120843943