AI大模型开发——3.深度学习基础(2)

8. 损失函数

        损失函数( Loss Functions), 也称为代价函数, 是用于评估模型预测值与真实值之间差异的函数。在神经网络训练过程中,损失函数用于指导模型参数的更新方向和幅度, 以使模型预测的结果尽可能接近真实值。
        常见的损失函数有以下两个。
        (1) 均方误差( Mean Squared Error, MSE), 其公式如下:

                                        MSE= \frac {1}{n} \sum \limits _{i=1}^{n}(y_{i}- \hat {y}_{i})^{2}

        其中, y_{i}是样本i的真实值,\hat {y}_{i}是模型预测值, n是样本数量。MSE是衡量模型预测值与真实值差异的一种方式, 通过计算预测值与实际值差的平方后, 取平均得到。MSE越小, 表示模型的预测值与真实值越接近,即模型的性能越好。它被广泛用于回归问题中,如预测房价、股票价格等。

        (2) 交叉熵损失( Cross- Entropy Loss), 其公式如下:

                                         CE=- \sum \limits _{i}y_{i} \log ( \hat {y}_{i})

        其中,y_{i}是样本属于类i的真实概率(一般为0或1),\hat {y}_{i}是模型预测样本属于类别i的概率。交叉熵损失用于衡量两个概率分布之间的差异, 特别是在分类问题中, 用于衡量模型预测的概率分布与实际标签的概率分布之间的差异。交叉熵损失越小, 意味着模型预测的概率分布与真实的分布越接近, 即模型的性能越好。

        对于多分类问题, 公式扩展为对所有类别进行求和。

                                        CE=- \sum \limits _{c=1}^{M}y_{o,c} \log ( \hat {y}_{o,c})

        其中, M是类别总数, y_{o,c}是观测值o的真实标签在类别c上的指示器(如果o属于类别c,则为1, 否则为0),\hat {y}_{o,c}是模型预测观测值o属于类别c的概率。

        损失函数的选择依赖于具体的任务类型(如回归或分类)和数据特性。例如, 对于回归任务,均方误差损失(MSE) 和平均绝对误差损失(MAE) 是常见的选择;对于分类任务, 交叉熵损失是标准选择。

        平均绝对误差损失计算的是模型预测值与真实值之间差异的绝对值的平均值。

        以下代码展示了如何使用TensorFlow库计算二分类问题的交叉熵损失。

import tensorflow as tf

# 真实标签
y_true = tf.constant([0, 1, 0, 1])

# 预测概率
y_pred = tf.constant([0.1, 0.9, 0.2, 0.8])

# 计算二分类交叉熵损失
loss = tf.keras.losses.binary_crossentropy(y_true, y_pred)

# 打印损失值
print(loss.numpy())

        代码结果如下:

D:\ana\envs\sd\python.exe D:\pythoncode\sd\wucha.py 
2024-08-11 10:48:58.129433: I tensorflow/core/platform/cpu_feature_guard.cc:193] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2024-08-11 10:48:58.141566: I tensorflow/core/common_runtime/process_util.cc:146] Creating new thread pool with default inter op setting: 2. Tune using inter_op_parallelism_threads for best performance.
0.1642519

进程已结束,退出代码为 0


        上述代码首先定义了真实的标签(y_ true) 和模型预测的概率(y_ pred), 然后通过 tflkeras.losses.binary_crossentropy 函数计算这些预测相对于真实标签的二分类交叉熵损失, 并打印出计算结果。

        选择合适的损失函数, 并合理地评估模型性能, 是提高模型准确性和鲁棒性的关键。

        鲁棒性是指模型在面对输入数据的噪声、异常值或未见过的情况时,保持性能稳定和准确的能力。

9. 向前传播

        向前传播( Forward Propagation) 是神经网络中计算预测输出的过程。在该过程中, 输入数据从输入层逐层传递至输出层。每一层的节点(神经元)都会根据输入数据和自身参数(权重和偏置)计算出一个输出, 这个输出经过激活函数后成为下一层的输入。

        向前传播有以下几个步骤:

        (1)初始化输入:向前传播的起点是网络的输入层, 这里的输入就是特征数据。

        (2)计算隐藏层:对于每个隐藏层, 计算其神经元的加权和, 再加上偏置项。然后, 将这个求和结果通过激活函数, 以非线性方式转换输出结果。

        (3)输出层计算:在神经网络的最后一层(输出层) 重复这一过程, 但激活函数可能会根据具体任务(如回归或分类) 而有所不同。

        (4)产生预测结果:输出层的输出即为网络对给定输入的预测值。

以下是使用 Python 和 NumPy库实现的一个简单的向前传播过程。
 

import numpy as np

def sigmoid(x):
    # Sigmoid激活函数
    return 1 / (1 + np.exp(-x))

# 初始化权重和偏置
W1 = np.array([[0.2, 0.8], [0.4, 0.6]])
b1 = np.array([0.1, 0.2])
W2 = np.array([[0.5], [0.9]])
b2 = np.array([0.3])

# 输入数据
X = np.array([[0.5, 0.3]])

# 向前传播计算
H = sigmoid(np.dot(X, W1) + b1)  # 隐藏层输出
Y_hat = sigmoid(np.dot(H, W2) + b2)  # 预测输出

# 打印预测输出
print("预测输出:", Y_hat)

        上述代码用H= sigmoid( np. dot(X, W1)+b1)计算了隐藏层的输出。这里通过np. dot(X, W1)计算输入数据X和权重W1的点积, 加上偏置b1后, 将结果通过 Sigmoid函数转换成(0,1)区间的值, 从而得到隐藏层的激活输出H。

        Y_ hat= sigmoid( np. dot(H, W2)+b2)计算了最终的预测输出值。这里使用隐藏层输出H作为输入, 通过同样的过程(点积、加偏置、 Sigmoid激活)计算得到预测结果 Y_ hat。

        向前传播是理解神经网络工作原理的基础。下面将探讨如何通过向后传播算法调整网络中的权重和偏置,以最小化损失函数,从而优化网络性能。


10.反向传播

        反向传播是通过计算梯度并更新网络中的权重和偏置来最小化损失函数的过程。反向传播确保了能够有效地训练深度神经网络, 使其在给定的任务上性能更好。

10.1 反向传播的基本概念

        (1)损失函数:在训练神经网络时, 首先需要定义一个损失函数(如均方误差、交叉熵等),用于衡量模型的预测值与实际值之间的差距。

        (2)梯度计算:反向传播算法的核心是计算损失函数关于网络权重的梯度。这些梯度指示了损失函数相对于每个权重的变化率,可告知如何调整权重以减少损失。

        (3)权重更新:一旦计算出梯度, 就可以使用梯度下降或其他优化算法更新网络的权重,以减少损失函数的值。

10.2 反向传播的步骤

        (1)计算输出层梯度。计算损失函数相对于输出层输出的梯度, 通常涉及损失函数相对于网络输出的导数。对于不同的损失函数, 这一步的计算会有所不同。
        (2)传播梯度到隐藏层。利用链式法则将输出层的梯度反向传播到隐藏层。对于每一层,计算损失相对于该层权重的梯度。这涉及以下知识点:
        链式法则允许计算通过多个函数组合而成的复合函数的导数。在神经网络中, 每一层的输出都依赖于前一层的输出,形成了一个复合函数的链。当需要计算损失函数关于任意一层权重的导数时, 链式法则能够将这个导数分解为每一层输出关于其输入的导数的乘积。这种方法不仅为计算梯度提供了数学基础,也使得通过反向传播算法有效地更新网络参数成为可能,从而优化整个网络的性能。

        1)损失相对于该层输出的梯度。
        2) 该层输出相对于该层输入的梯度(激活函数的导数)。
        3)该层输入相对于权重的梯度(前一层的输出)。
        这些梯度会相乘, 结果就是损失相对于该层权重的梯度。

        (3)更新权重和偏置。一旦计算得到权重的梯度, 就可以更新权重了。更新公式通常是:新的权重=旧的权重-学习率 × 梯度。偏置的更新过程类似, 也是基于其梯度进行更新。
        学习率是控制在更700新神经网络的权重时, 梯度下降步长大小的一个关键性参数, 它决定了每次参数更新的幅度。

        (4)重复直到收敛。该过程(前向传播、反向传播、更新参数)会在整个训练集上重复多次(即多个 epoch)。每次迭代过程中,网络的损失应该会逐渐减少, 网络的预测性能应该会逐渐提高。
        在机器学习和优化领域,收敛是指模型训练过程中, 通过反复迭代, 损失函数的值逐渐稳定并接近最小值, 模型的预测性能达到或接近最优, 表明学习过程已达到稳定状态。
        下面以一个简单的神经网络为例,进一步说明输出层的参数是如何计算和调整的。


10.3 调整输出层参数(更新权重和偏置)

        (1)计算输出层梯度。在网络的输出层,需要计算损失函数L相对于网络输出j的梯度。该梯度表示损失如何随着网络输出的变化而变化。例如, 对于二分类问题, 如果使用交叉熵损失函数, 则可以计算出相对于网络输出的梯度\frac { \partial L}{ \partial \hat {y}}

        (2)链式法则计算权重梯度。使用链式法则计算损失函数相对于输出层权重W的梯度。链式法则可以通过将损失函数相对于网络输出的梯度与网络输出相对于权重的梯度相乘来实现这一点。对于输出层的每个权重w_{ij}(连接第i个隐藏层神经元和第j个输出层神经元),其梯度可以表示为\frac { \partial L}{ \partial w_{y}}= \frac { \partial L}{ \partial \hat {y}_{J}}. \frac { \partial \hat {y}_{J}}{ \partial w_{y}}。其中,\frac { \partial \hat {y}_{J}}{ \partial w_{ij}}通常是第i个隐藏层神经元的输出。

        (3)计算偏置梯度。损失函数相对于输出层偏置b,的梯度也需要计算。偏置的梯度可以表示为\frac { \partial L}{ \partial b_{j}}

        (4)更新权重和偏置。一旦计算出权重和偏置的梯度,就可以使用这些梯度来更新权重和偏置了。更新的一般公式如下:
                                                W_{new}=W_{old}- \alpha \cdot \frac { \partial L}{ \partial W}
                        ​​​​​​​        ​​​​​​​        ​​​​​​​         b_{new}=b_{old}- \alpha \cdot \frac { \partial L}{ \partial b}
        其中, α是学习率, 它决定了在梯度方向上更新的步长大小。

        (5)反向传播到隐藏层。类似的过程也会发生在隐藏层中。损失函数相对于隐藏层的权重和偏置的梯度会被计算出来, 并用于更新隐藏层的参数。


10.4 示例演示

        下面用一个简单的方程和几个实际数据点来说明反向传播的过程。一个简单的神经网络只有一个输入、一个权重、一个偏置以及一个输出。本例使用均方误差(MSE)作为损失函数,这是回归问题中常用的损失函数。
(1) 网络结构:

        1) 输入:x。
        2)权重:w。
        3)偏置:b。
        4)输出:\hat {y}=w \cdot x+b
        5)真实标签:y。
        6)损失函数(均方误差):L= \frac {1}{2}(y- \hat {y})^{2}

(2)实际数据:

        1)输入:x=2。
        2) 真实标签:y=3。
        3)初始权重:w=0.5。
        4)初始偏置:b=0.5。

(3)向前传播:

        1)计算输出:y=w·x+b=0.5·2+0.5=1.5。
        2)计算损失:L= \frac {1}{2}(y- \hat {y})^{2}= \frac {1}{2}(3-1.5)^{2}=1.125

(4)反向传播。

        1) 计算损失函数相对于输出的梯度:\frac { \partial L}{ \hat { \partial } \hat {y}}= \hat {y}-y=1.5-3=-1.5
        2)计算输出相对于权重的梯度:\frac { \hat { \partial } \hat {y}}{ \bar {e}w}=x=2
        3) 计算损失函数相对于权重的梯度(使用链式法则):\frac { \partial L}{ \partial w}= \frac { \partial L}{ \partial \hat {}y}. \frac { \partial \hat {}y}{ \partial w}=-1.5 \cdot 2=-3
        4) 计算输出相对于偏置的梯度:\frac { \hat {o} \hat {y}}{ \hat {o}b}=1
        5)计算损失函数相对于偏置的梯度(使用链式法则):\frac { \partial L}{ \partial b}= \frac { \partial L}{ \partial \hat {}y}. \frac { \partial \hat {}y}{ \partial b}=-1.5 \cdot 1=-1.5

(5) 更新权重和偏置:

        设定学习率α=0.01。

        1)更新权重:w_{new}=w_{old}- \alpha \cdot \frac { \partial L}{ \partial w}=0.5-0.01 \cdot (-3)=0.53
        2)更新偏置:b_{new}=b_{old}- \alpha \cdot \frac { \partial L}{ \partial b}=0.5-0.01 \cdot (-1.5)=0.515

        这个过程,网络的权重和偏置更新了一次。在实际应用中, 这个过程会在整个训练集上反复进行多次(每次称为一个 epoch),直到损失函数的值不再显著下降, 或者达到预定的epoch次数。        

        通过反复进行向前传播、计算损失、反向传播梯度和更新权重的过程,神经网络逐渐学习到将输入映射到正确输出的方法。在下面我们将探讨如何选择合适的优化函数来有效地进行权重更新。

11. 优化函数

        优化函数(又称为优化算法)在神经网络中是用来调整模型参数(如权重和偏置)的算法,目的是最小化或最大化某个目标函数(通常是损失函数)。它们通过计算目标函数相对于模型参数的梯度, 并利用这些梯度信息来更新参数,从而使模型性能逐步改进。在深度学习中, 选择合适的优化算法可以显著提高模型的学习效率和最终性能。

11.1 梯度下降

        梯度下降( Gradient Descent)算法的核心思想是计算损失函数相对于模型参数的梯度(即导数),然后沿着梯度的反方向调整参数, 以步进的方式逐渐减少损失函数的值。梯度方向指示了损失增加的最快方向,因此反方向即为损失减少的最快方向。通过反复迭代这个过程, 梯度下降算法可以使模型参数收敛到损失函数的一个局部最小值, 从而优化模型的性能。公式表示如下:                                        

                                                               θ=θ−α∇L(θ)

        其中, θ表示模型参数, α是学习率(一个小的正数),∇L(θ) 是损失函数相对于参数θ的梯度。
上面示例中中优化函数使用的就是梯度下降算法。学习率控制着参数更新的步长, 太大的学习率可能会导致更新过度甚至发散,而太小的学习率会使训练过程缓慢, 甚至陷入局部最小值。

11.2 随机梯度下降

        随机梯度下降( Stochastic Gradient Descent, SGD) 是梯度下降优化算法的一个变体, 它在每一步更新模型参数时使用从训练集中随机选择的单个样本或一小批样本来计算梯度, 而不是使用整个数据集。这种方法与传统的批量梯度下降( Batch Gradient Descent) 形成对比, 后者在每一步中利用整个训练集来计算梯度。
        在 SGD中, 每次迭代只选择一个训练样本(或一小批样本),计算该样本对应的梯度, 然后更新模型参数。
        对于模型参数θ, 更新规则可以表示为
        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​\theta = \theta - \alpha \nabla _{ \theta }L( \theta ,x^{(i)},y^{(i)})
        其中, α是学习率, \nabla _{ \theta }L( \theta ,x^{(i)},y^{(i)}) 是基于第i个样本计算得到的损失函数的梯度。
        由于每次更新只使用一个样本或一小批样本, SGD可以更快地进行参数更新, 特别是当数据集很大时, 不需要在每一步存储整个数据集的梯度, 因此对内存的需求较低。SGD 引入的随机性有助于模型逃离局部最小值,可能找到更好的全局最小值。SGD适用于在线学习和大规模数据集,因为模型可以即时更新,不需要等待整个数据集处理完毕。由于每次更新只基于一个样本或一小批样本, 使得SGD的收敛路径比批量梯度下降更加嘈杂和不稳定。

11.3 动量

        动量( Momentum) 方法是一种用于加速梯度下降算法的技术, 尤其在面对高曲率、小但一致的梯度,或是带噪声的梯度时表现出色。动量方法受到物理中粒子在斜面上下滚动并因惯性积累速度的启发, 通过在梯度下降过程中累积过去梯度的信息, 来调整每次的参数更新, 使其不仅仅依赖于当前步的梯度, 从而加快学习速度。
        动量方法引入了一个名为“速度”( velocity)的变量v,该变量累积过去梯度的指数级加权平均值, 并用于更新参数。每一次迭代中, 速度更新为梯度方向和过去速度的加权和, 参数的更新则考虑到了这个“速度”, 而不是直接沿着当前梯度方向。
        速度更新表示:
                                                            v=γv+α∇L(θ)
        参数更新表示:
                                                                θ=θ-ν
        其中,θ表示模型参数,α是学习率,∇L(θ)是损失函数相对于参数θ的梯度, γ是动量系数(一般设定为接近1的值, 如0.9),v是速度。

        动量方法通过累积过去梯度来平滑参数更新, 避免了在陡峭的梯度方向上的震荡。在梯度方向一致的情况下,动量会积累, 导致参数更新步长增大, 从而加速学习过程。动量方法广泛应用于深度神经网络的训练, 特别是在训练过程中遇到的损失曲面复杂、梯度更新路径不平滑的情况。动量系数γ的选择对算法性能有显著影响。太小的动量系数几乎不会积累过去的梯度信息,而太大的动量系数可能会导致过度冲过最小值点。

11.4 自适应学习率算法

        自适应学习率算法是一类优化算法, 它们的核心思想是在训练过程中自动调整学习率的大小,以改善训练速度和效果。不同于传统梯度下降算法中固定不变的学习率,自适应学习率算法根据参数的历史更新记录动态来调整每个参数的学习率, 使得训练过程更加高效和稳定。以下是几种主要的自适应学习率算法:
        (1) Adagrad( Adaptive Gradient Algorithm)。 Adagrad 通过累积每个参数的梯度的平方来调整学习率, 对于出现频率较低的特征将赋予更大的学习率, 对于出现频率高的特征将赋予较小的学习率, 特别适合处理稀疏数据, 但在深度学习中可能会因为学习率过度衰减而提前停止学习。
        提前停止学习是因为累积的梯度平方和导致学习率持续减小至接近零, 从而减少了权重的调整幅度, 使得模型无法继续有效学习。
       

        (2)RMSprop( Root Mean Square Propagation)。RMSprop 是对 Adagrad 的改进, 通过引入衰减因子来限制历史信息的无限累积, 从而避免了学习率持续减小到极小的问题。它能够在非凸优化问题中很好地工作, 是训练神经网络的常用算法之一。
        非凸优化问题是指在优化问题中,目标函数为非凸函数的情况, 这意味着函数可能存在多个局部最小值, 使得找到全局最小值变得更加复杂和具有挑战性。

        (3) Adam。 Adam( Adaptive Mome nt Estimation) 结合了 Momentum 和 RMSprop的思想,不仅计算梯度的指数移动平均(类似于 Momentum), 还计算梯度平方的指数移动平均(类似于RMSprop),并对这两个量进行偏差校正。 Adam自适应性强, 通常而言, 它在许多深度学习模型的训练中表现出良好的性能。
        

        (4) AdaDelta。AdaDelta是对RMSprop的扩展, 它进一步减少了学习率的急剧下降。AdaDelta不需要设置默认的学习率,通过使用梯度的平方项的移动平均来调整每个参数的学习率。与RMSprop类似, 但是在某些情况下, AdaDelta可以提供更稳定的性能。
        

        选择哪种优化算法取决于具体问题、数据特性以及模型的复杂性。没有哪一种算法在所有情况下都是最优的。实践中, Adam算法因其稳健性和适应性广受欢迎, 是很多深度学习任务的首选优化算法。然而, 对于某些特定问题, 如具有稀疏特性的数据集, Adagrad 或RMSprop可能会更有效。
        深入了解各种优化算法的原理和特点后, 开发者应该尝试不同的算法, 以找到最适合当前任务的优化策略。实际应用中,经常需要通过交叉验证来比较不同优化算法的性能, 进而做出合适的选择。
        交叉验证是用于评估和比较机器学习模型的泛化能力, 通过将数据集分割成多个小组,然后将其中一组作为测试集, 其余组作为训练集, 进行多轮训练和测试, 每次选择不同的组作为测试集。这种方法可以减少模型评估过程中因数据分割方式不同而导致的性能估计偏差,从而更准地反映不同的优化算法在同一任务上的性能。

         到此我们大模型开发中的深度学习知识全部结束,但是这仅仅是深度学习中很小一部分,如果您想要更加深入了解,可以找笔者微信公众号:ai小白成长之旅  进一步深入探讨。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值