1. 安装Python运行环境和Pycharm

安装Pycharm, 配置好Python开发环境。

由于之前使用Django框架进行Web开发时,已经安装过Pycharm并且配置过Python3的环境,在此就不再次配置了,只做一下展示~,Python版本为3.6.3。

pytorch 自定义 Linear pytorch 自定义反向传播_pytorch 自定义 Linear

2.安装PyTorch

(1) 安装PyTorch

首先,进入PyTorch的官网,找到对应的下载位置。操作系统根据自己的系统进行选择,我的是Window10,于是选择Windows,安装方式我选择的是pip方法,语言自然选择Python,因为我的显卡是因特尔的显卡,所以选择CUDA11.3,然后复制下方的链接到本机的控制台进行安装。

pytorch 自定义 Linear pytorch 自定义反向传播_反向传播_02


将安装命令粘贴到控制台后,按下回车就开始下载了,时间可能会有些长,需要多等一会儿~。

pytorch 自定义 Linear pytorch 自定义反向传播_python_03


经过耐心的等待后,安装终于结束了。。。

pytorch 自定义 Linear pytorch 自定义反向传播_反向传播_04


然后,进行测试,验证是否成功安装。

经过验证,安装成功!

pytorch 自定义 Linear pytorch 自定义反向传播_python_05

3. 实现反向传播

1. 反向传播算法介绍

在开始写代码之前,我们先简单介绍一下反向传播算法。

简介

无论是机器学习还是深度学习,都绕不开一个梯度下降。深度学习的大致步骤为:

  • 构建神经网络
  • 数据拟合
  • 选出最佳模型

其中,选出最佳模型的方式,其实就是利用梯度下降算法,选出损失函数最小的那个。在传统的机器学习中,这个比较容易实现。但是在深度学习中,由于存在输入层,隐藏层,输出层,且隐藏层到底有多深,这些都是未知数,因此计算也会更加繁琐。如果,在输出层输出的数据和我们设定的目标及标准相差比较大,这个时候,就需要反向传播。利用反向传播,逐层求出目标函数对各神经元权值的偏函数,构成目标函数对权值向量的梯度,之所以算这个,是为了对权值的优化提供依据,等权值优化了之后,再转为正向传播,直到输出的结果达到设定的标准。

反向传播原理
(1) 导数的链式法则

反向传播的原理其实很好理解,主要的理论就是我们在高等数字中学的导数计算:

pytorch 自定义 Linear pytorch 自定义反向传播_反向传播_06

pytorch 自定义 Linear pytorch 自定义反向传播_pytorch 自定义 Linear_07

pytorch 自定义 Linear pytorch 自定义反向传播_人工智能_08

(2) 正向传播与反向传播

正向传播(forward propagation) 是指对神经网络沿着从输入层到输出层的顺序,依次计算并存储模型的中间变量(包括输出)。

以逻辑回归中的神经元为例:

pytorch 自定义 Linear pytorch 自定义反向传播_pytorch 自定义 Linear_09


在这个神经元中, pytorch 自定义 Linear pytorch 自定义反向传播_反向传播_10 pytorch 自定义 Linear pytorch 自定义反向传播_pytorch_11

我们知道,无论是机器学习还是深度学习,计算之后都会产生一定的损失值,我们把这个损失函数记为 pytorch 自定义 Linear pytorch 自定义反向传播_python_12

反向传播的最终目的是修正权值pytorch 自定义 Linear pytorch 自定义反向传播_反向传播_13,我们让pytorch 自定义 Linear pytorch 自定义反向传播_python_12pytorch 自定义 Linear pytorch 自定义反向传播_反向传播_13求偏导,根据链式法则:

pytorch 自定义 Linear pytorch 自定义反向传播_反向传播_16

pytorch 自定义 Linear pytorch 自定义反向传播_人工智能_17


计算结果:

pytorch 自定义 Linear pytorch 自定义反向传播_pytorch 自定义 Linear_18

pytorch 自定义 Linear pytorch 自定义反向传播_python_19, pytorch 自定义 Linear pytorch 自定义反向传播_人工智能_20其实就是最开始的输入值,可以当做已知的,这个计算过程就是正向传播。

pytorch 自定义 Linear pytorch 自定义反向传播_人工智能_21

但是,计算反向传播就会很复杂,反向传播(back-propagation)指的是计算神经网络参数梯度的方法。总的来说,反向传播依据微积分中的链式法则,沿着从输出层到输入层的顺序,依次计算并存储对输入或输出目标函数有关神经网络各层的中间变量以及参数的梯度。对输入或输出pytorch 自定义 Linear pytorch 自定义反向传播_pytorch_22为任意形状张量的函数pytorch 自定义 Linear pytorch 自定义反向传播_pytorch_23, 通过链式法则,我们有:
pytorch 自定义 Linear pytorch 自定义反向传播_python_24
首先,分别计算目标函数pytorch 自定义 Linear pytorch 自定义反向传播_pytorch 自定义 Linear_25 有关损失项L和正则项s的梯度。
pytorch 自定义 Linear pytorch 自定义反向传播_python_26
其次,依据链式法则计算目标函数有关输出层的梯度pytorch 自定义 Linear pytorch 自定义反向传播_反向传播_27
pytorch 自定义 Linear pytorch 自定义反向传播_反向传播_28
接下来,计算正则项有关两个参数的梯度:
pytorch 自定义 Linear pytorch 自定义反向传播_pytorch_29
现在,我们可以计算最靠近输出层的模型参数的梯度pytorch 自定义 Linear pytorch 自定义反向传播_反向传播_30, 依据链式法则,得到:
pytorch 自定义 Linear pytorch 自定义反向传播_pytorch_31
沿着输出层向隐藏层继续反向传播,隐藏层变量的梯度pytorch 自定义 Linear pytorch 自定义反向传播_pytorch 自定义 Linear_32可以这样计算:
pytorch 自定义 Linear pytorch 自定义反向传播_人工智能_33
最终,我们可以得到最靠近输入层的模型参数的梯度pytorch 自定义 Linear pytorch 自定义反向传播_pytorch_34 \ pytorch 自定义 Linear pytorch 自定义反向传播_python_35, 依据链式法则,得到
pytorch 自定义 Linear pytorch 自定义反向传播_人工智能_36

2. 打开Pycharm

首先,打开我们强大好用的Pycharm!!!

pytorch 自定义 Linear pytorch 自定义反向传播_python_37

3. 创建项目

新建一个Python项目,命名为AI,为了可以使用刚才在终端使用pip指令安装的PyTorch包,选择使用继承全局站点包,然后单击创建。

pytorch 自定义 Linear pytorch 自定义反向传播_反向传播_38


打开main.py,然后开始写代码:

import torch
import matplotlib.pyplot as plt

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

w = torch.Tensor([3.0])  # 初始化权重
w.requires_grad = True  # 说明w需要计算梯度


# 注意其中w是tensor,在实际运算中开始进行数乘。
def forward(x):
    return w * x


# 损失函数的求解,构建计算图,并不是乘法或者乘方运算
def loss(x, y):
    y_pred = forward(x)
    return (y_pred - y) ** 2


print("Predict before training", 4, forward(4).item())  ## 打印学习之前的值,.item表示输出张量的值

learning_rate = 0.01
epoch_list = []
loss_list = []
# 训练
for epoch in range(100):
    for x, y in zip(x_data, y_data):
        l = loss(x, y)
        l.backward()  # 向后传播
        print('\tgrad', x, y, w.grad.item())  # 将梯度存到w之中,随后释放计算图,w.grad.item():取出数值
        w.data = w.data - learning_rate * w.grad.data  # 张量中的grad也是张量,所以取张量中的data,不去建立计算图
        w.grad.data.zero_()  # 释放data
    print("process:", epoch, l.item())
    epoch_list.append(epoch)
    loss_list.append(l.item())

print('Predict after training', 4, forward(4).item())

# 绘制可视化
plt.plot(epoch_list, loss_list)
plt.xlabel("epoch")
plt.ylabel("Loss")
plt.show()

运行结果:

pytorch 自定义 Linear pytorch 自定义反向传播_反向传播_39

pytorch 自定义 Linear pytorch 自定义反向传播_反向传播_40