Bootstrap

【深度学习】梯度下降与反向传播

🌻个人主页:相洋同学
🥇学习在于行动、总结和坚持,共勉!

目录

1 梯度下降(Gradient Descent)

1.1 极小值问题

1.2 梯度

1.3 梯度下降法

2 反向传播(Backpropagation)

2.1 完整过程

2.2 代码演示


#学习记录#

梯度下降和反向传播是机器学习和深度学习中非常重要的两个概念,尤其是在训练神经网络时。

今天我们来总结一下

1 梯度下降(Gradient Descent)

梯度下降是一种优化算法,用来最小化(或最大化)一个函数。在机器学习中这个函数通常是损失函数(loss function),它衡量的是模型预测值与真实值之间的差距,简单来说,梯度下降就是寻找损失函数的最小值(或最小点)的过程。

1.1 极小值问题

我们先来看一个找极小值问题:

函数f(x)的值受x影响

目标:找到合适的x值,使得f(x)最小

方法:

1.选取一个x_{0},计算在这一点的导数值

2.根据导数的正负,决定x_{0}应当调大还是调小,目标是导数为0,当导数为负我们就使得x增大,为正减小

3.迭代进行1,2,直到x不在变化(或是变化极小)

1.2 梯度

所谓梯度就是指损失函数在当前点上的斜率或方向。它会告诉你损失函数增加最快的方向。意义与导数基本一致

原函数:y = 3x^{2}             导函数:   y = 6x        在x=1处的导数值:6

原函数:y = 3x_{1}^{2} + 4x_{2}^{2} + 5x_{3}^{2}       导函数:y = {6x_{1} , 8x_{2} , 10x_{3}} 在[1,1,1]处的梯度是[6,8,10] 梯度是个向量

1.3 梯度下降法

  1. 选择初始参数:首先,随机选择一组开始的参数。
  2. 计算梯度:梯度指的是损失函数在当前参数下的导数,它指向损失最快增加的方向。因此,向梯度的反方向更新参数,可以使得损失减小。
  3. 更新参数:使用下面的公式来更新每个参数:

\theta _{new}=\theta _{old}-\alpha \Delta _{\theta }J(\theta )

其中,θ 是参数,α 是学习率(控制更新的步长),J(θ) 是损失函数。

在模型训练过程中,我们肯定是希望损失函数越小越好,证明模型越好。所以模型学习的目标就是损失函数最小化,而模型权重会影响损失函数值,所以我们通过梯度下降来找到最优权重。

2 反向传播(Backpropagation)

反向传播是一种特别高效计算梯度的方法,它在神经网络中被广泛使用。当我们在神经网络中使用梯度下降时,反向传播帮助我们找到每一层参数的梯度。

2.1 完整过程

  1. 前向传播:输入数据在神经网络中向前传递,直到产生输出和损失。
  2. 计算损失:根据模型的输出和实际值计算损失函数。
  3. 反向传播:计算损失函数关于每个参数的梯度。这个过程从输出层开始,逆向通过网络,使用链式法则逐层计算梯度。
  4. 更新参数:一旦得到梯度,就使用梯度下降的方法更新网络中的参数。

Tips:方向传播之所以叫反向传播,主要就是因为要逆向通过网络使用呢链式法则逐层计算梯度。

2.2 代码演示

上代码:

import matplotlib.pyplot as pyplot
import math
import sys

# 1.构造样本,0 - 100 的 100 个点
X = [0.01 * x for x in range(100)]
# 预定义函数,y = 4x^2 + 5x + 6
Y = [4 * x ** 2 + 5 * x + 6 for x in X]

def func(x):
    # 1.这里是选用的模型,线性模型
    y = w1 * x ** 2 + w2 * x + w3
    return y

def loss(y_pred, y_true):
    # 2.损失函数,均方差 MSE mean square error
    return (y_pred - y_true) ** 2

# 3.权重随机初始化,这样也可以理解为模型的初始化,预训练模型的意义就是让模型的初始化更好
w1, w2, w3 = 1, 0, 1

# 学习率设置,这里是一个超参数,需要调参(控制权重更新的幅度)
lr = 0.001

# 每次迭代中使用训练模型样本的数量,其对模型的训练效果和训练速度都有重要影响
batch_size = 1
# 训练过程
for epoch in range(1000):  # 模型训练的轮数
    epoch_loss = 0  # 记录每轮的损失
    grad_w1 = 0
    grad_w2 = 0
    grad_w3 = 0
    count = 0  # 这里是初始化
    for x, y_true in zip(X, Y):
        count += 1
        y_pred = func(x)
        epoch_loss += loss(y_pred, y_true)
        # 梯度计算,这里是手动计算梯度,pytorch会自动计算梯度
        # 梯度计算就是求导,这里是求偏导
        grad_w1 += 2 * (y_pred - y_true) * x ** 2
        grad_w2 += 2 * (y_pred - y_true) * x
        grad_w3 += 2 * (y_pred - y_true)
        # 权重更新
        if count == batch_size:
            w1 = w1 - lr * grad_w1/batch_size  # sgd  随机梯度下降
            w2 = w2 - lr * grad_w2/batch_size
            w3 = w3 - lr * grad_w3/batch_size
            count = 0  # 这里是每次更新
            grad_w1 = 0
            grad_w2 = 0
            grad_w3 = 0

    epoch_loss /= len(X)
    print("第%d轮, loss %f" % (epoch, epoch_loss))
    if epoch_loss < 0.00001:
        break

print(f"训练后权重:w1:{w1} w2:{w2} w3:{w3}")

# 使用训练后模型输出预测值
Yp = [func(i) for i in X]

# 预测值与真实值比对数据分布(通过图像查看预测效果)
pyplot.scatter(X, Y, color="green")
pyplot.scatter(X, Yp)
pyplot.show()

以上代码中我们自己提前构造了一个数据集供模型进行预测。

值得注意的点

1.求导的过程我们手动完成了,在使用pytorch构建神经网络的时候,其内部会自动完成求导。

2.batch_size是每次迭代中使用训练模型样本的数量,也就是每算多少个样本更新一次梯度。举个例子来说,就像我们在学习过程中进行总结一样。我们是每天总结调整策略还是每个星期,每个小时或者每年。很显然,每个小时太浪费时间,每年的话时间又太长。

3.梯度下降的公式还有不同的,我们称其为优化器。不同优化器对训练的模型有不同影响,损失函数也是,后续学习中我们会接触更多。

以上

学习在于坚持和总结,共勉

;