import torch
import torchvision
import torch.nn as nn
import numpy as np
import torchvision.transforms as transforms
# ================================================================== #
# 1. Basic autograd example 1 #
# ================================================================== #
# Create tensors.
x = torch.tensor(4., requires_grad=True)
w = torch.tensor(5., requires_grad=True)
b = torch.tensor(6., requires_grad=True)
# Build a computational graph.
y = w * x + b # y = 5 * x + 6
# Compute gradients.
y.backward()
# Print out the gradients.
print(x.grad) # x.grad = w
print(w.grad) # w.grad = x
print(b.grad) # b.grad = 1
这段小程序的目的是使用Pytorch的自动求导功能实现对函数中的参数进行求导。这项工作是整个神经网络优化的基础。我们先看看最简单的线性函数的求导方法。
对于y = w * x + b而言,分别对w,x和b进行求导。这个过程非常清晰。这三个参数的导数分布为x,w和1。程序运行的结果也印证了这一点。我们再来看看一个复杂点的例子。
================================================================== #
# 2. Basic autograd example 2 #
# ================================================================== #
# Create tensors of shape (10, 3) and (10, 2).
x = torch.randn(10, 3)
y = torch.randn(10, 2)
# Build a fully connected layer.
linear = nn.Linear(3, 2)
print ('w: ', linear.weight)
print ('b: ', linear.bias)
# Build loss function and optimizer.
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(linear.parameters(), lr=0.01)
# Forward pass.
pred = linear(x)
# Compute loss.
loss = criterion(pred, y)
print('loss: ', loss.item())
# Backward pass.
loss.backward()
# Print out the gradients.
print ('dL/dw: ', linear.weight.grad)
print ('dL/db: ', linear.bias.grad)
# 1-step gradient descent.
optimizer.step()
# You can also perform gradient descent at the low level.
# linear.weight.data.sub_(0.01 * linear.weight.grad.data)
# linear.bias.data.sub_(0.01 * linear.bias.grad.data)
# Print out the loss after 1-step gradient descent.
pred = linear(x)
loss = criterion(pred, y)
print('loss after 1 step optimization: ', loss.item())
分析:
首先明确这段代码的目的是利用Pytorch内置的BP算法完成函数拟合任务。输入为x,输出为y。要拟合的关系是y=f(x)中的f函数。
现在请闭上眼睛回忆一下,刚刚这段简短的程序完成了哪些工作?
- 定义一组输入数据;
- 定义计算图;
- 定义损失函数;
- 优化,拟合参数。
数据的构造部分先不多说,我们先看看计算图是什么?
linear = nn.Linear(3, 2)
这里的计算模型是一个线性模型,和案例一中的模型是类似的。区别在于现在的输入不再是一个数,而是一个矩阵。
那么如何nn.Linear这个线性模型,建立从x到y的映射关系呢?我们需要对线性模型的参数进行搜索,从而找到最合适的,最接近真实情况的函数参数。参数优化的过程可以通过BP反向传播算法来实现。
也许刚刚开始接触深度学习的朋友可能会对反向传播的过程感到疑惑。没关系,不妨把这个过程视为小猫在玩平衡木,重心偏左身体就向右移动,重心向右身体就向左移动。直到身体平衡为止。重心偏左还是偏右对应梯度的概念。调整身体平衡的过程可以与反向传播相对应。
#评估偏差的函数
loss = criterion(pred, y)
#调整的过程
loss.backward()
至于如何调整以及为什么这样调整,此处暂时不作讨论,当后续研究损失函数时,我将就这一问题详细展开。
现在只需要记住拟合函数的大体流程(上面的四个步骤)。请记住复杂的网络也离不开这四个步骤,很多复杂的网络拆解开来同样遵循最基本的设计思路。