勇敢学习机器学习:解决梯度消失和梯度爆炸问题(第二部分)

原文:towardsdatascience.com/courage-to-learn-ml-tackling-vanishing-and-exploding-gradients-part-2-d0b8aed1ce7a

欢迎回到“勇敢学习机器学习”的新篇章。对于那些刚开始这个系列的人来说,这个系列旨在使这些复杂主题变得易于理解和吸引人,就像导师和学习者之间的轻松对话一样,灵感来源于“不喜欢被讨厌的勇气”,特别关注机器学习。

这次我们将继续探索如何克服梯度消失和梯度爆炸的挑战。在我们的开场部分,我们讨论了为什么保持稳定的梯度对于确保网络中的有效学习至关重要。我们揭示了不稳定的梯度如何成为深化网络的障碍,本质上限制了深度“学习”的潜力。为了使这些概念生动起来,我们使用了一个名为 DNN(Delicious Nutritious Nibbles 的缩写)的微型冰淇淋工厂的类比,并绘制平行线来阐明类似于编排无缝工厂生产线的高效 DNN 训练策略。

现在,在这个第二部分中,我们将更深入地探讨每个提出的解决方案,用同样的清晰和创造力来审视它们,就像我们的冰淇淋工厂一样生动。以下是本部分我们将涵盖的主题列表:

  1. 激活函数

  2. 权重初始化

  3. 批量归一化

  4. 实践中的经验

激活函数

激活函数是我们“工厂”设置的核心。它们负责在我们深度神经网络(DNN)生产线的前向和反向传播中传递信息。选择正确的激活函数对于 DNN 生产线和 DNN 训练过程的顺利运行至关重要。这部分内容不仅仅是简单列举激活函数及其优缺点,在这里,我将使用问答格式来揭示不同激活函数创建背后的深层推理,并回答一些经常被忽视的重要问题。

将这些函数想象成我们冰淇淋生产类比中的搅拌机。我并不是要提供一个可用的搅拌机目录,而是要提供对每个搅拌机的深入审查和理解,以及任何特定改进背后的原因。

激活函数究竟是什么,我该如何选择正确的函数?

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/e05596d1d1e5c0238dd89f1225b2cf09.png

作者使用 ChatGPT 创建的图像

激活函数是授予神经网络模型灵活性和强大功能以捕捉线性和非线性关系的关键元素。逻辑回归和深度神经网络之间的关键区别在于这些激活函数与多层结合。它们共同允许神经网络近似广泛的功能。然而,这种力量也伴随着挑战。激活函数的选择需要更加仔细的考虑。错误的选择可能导致模型无法有效学习,尤其是在反向传播过程中。

想象一下,你是我们深度神经网络冰淇淋工厂的经理。你希望仔细选择适合生产线的正确激活函数(想想它们就像冰淇淋搅拌机)。这意味着做你的作业,并找到最适合你需求的最佳选择。

因此,选择有效激活函数的第一步涉及解决两个关键问题:

激活函数的选择如何影响梯度消失和梯度爆炸等问题?什么标准定义了一个好的激活函数?

注意,为了处理不稳定的梯度,我们的讨论重点放在隐藏层的激活上。对于输出激活函数,选择取决于任务,是回归问题还是分类问题,以及是否是多类问题。

在处理隐藏层中激活函数的选择时,问题更多地与梯度消失相关。这可以追溯到我们传统的激活函数 sigmoid(非常传统或基本模型)。sigmoid 函数因其能够将输入映射到概率范围(0, 1)而得到广泛应用,这在二元分类任务中特别有用。这种能力使得研究人员能够调整概率阈值以对预测进行分类,从而增强模型的灵活性和性能。

然而,它在隐藏层中的应用导致了重大的挑战,最显著的是梯度消失问题。这可以归因于两个主要因素:

  • 在正向传播过程中,sigmoid 函数将输入压缩到 0 和 1 之间一个非常狭窄的范围。如果一个网络只在隐藏层使用 sigmoid 作为激活函数,那么通过多层重复应用将进一步缩小这个范围。这种压缩效应不仅减少了输出的变异性,还引入了对正值的偏差。因为无论输入的符号如何,输出都保持在 0 和 1 之间。

  • 在反向传播过程中,sigmoid 函数(具有钟形曲线)的导数产生介于 0 和 0.25 之间的值。这个小的范围会导致尽管输入存在,但它们在通过多层传播时梯度迅速减小,导致梯度消失。由于早期层梯度是连续层导数的乘积,这种小导数的复合乘积导致梯度指数级减小,从而阻碍早期层的学习效果。

为了克服这些限制,理想的激活函数应具有以下特性:

  • 非线性。允许网络捕捉复杂模式。

  • 非饱和。函数及其导数不应过度压缩输入范围,以防止梯度消失。

  • 零中心输出。函数应允许正负输出,确保节点之间的平均输出不会引入对任何方向的偏差。

  • 计算效率。函数及其导数应易于计算,以促进高效学习。

考虑到这些基本特性,流行的激活函数是如何建立在我们的基本模型 Sigmoid 之上的,以及是什么使它们脱颖而出?

本节旨在提供对几乎所有当前激活函数的概述。

Tanh,对 Sigmoid 的简单调整。 双曲正切(tanh)函数可以看作是 sigmoid 的修改版本,在输出范围方面提供了直接的增强。通过缩放和移动 sigmoid,tanh 实现了 [-1, 1] 的输出范围,具有零均值。这种零中心输出是有利的,因为它符合我们对于有效激活函数的标准,确保输入数据和梯度不太偏向任何特定方向,无论是正还是负。

尽管有这些好处,tanh 在非线性形状方面仍然保留了 sigmoid 的核心特征,这意味着它仍然将输出压缩到狭窄的范围。这种压缩导致了与 sigmoid 观察到的问题相似,导致梯度饱和。因此,它影响了网络在反向传播期间有效学习的功能。

ReLU,神经网络中的热门选择。 ReLU(修正线性单元)因其简单性而突出,作为一个分段线性函数,其中 f(x) = max(0, x)。这意味着对于任何负输入,它输出零,否则与输入相同。ReLU 特别吸引人的是它的简单设计,轻松满足我们上面讨论的四个关键特性中的三个。它在正侧的线性性质避免了将输出压缩到狭窄的范围,与 sigmoid 或 tanh 不同,并且其导数简单,要么是 0,要么是 1。

ReLU 令人感兴趣的一个方面是它能够关闭负输入的神经元,为模型引入稀疏性。类似于通过关闭某些神经元实现的 dropout 正则化的效果。这可能导致更通用的模型。然而,它也导致了“死亡 ReLU”问题,其中神经元由于零输出和梯度而变得不活跃并停止学习。虽然一些神经元可能会复活,但早期层的神经元尤其可能永久性地被关闭。这类似于在冰淇淋生产线中停止反馈,早期阶段无法根据客户反馈进行调整或为后续阶段提供有用的中间产品。

另一个需要考虑的问题是 ReLU 在x=0 处的非可微性,这是由于其线性段之间的尖锐过渡。在实践中,像 PyTorch 这样的框架使用子梯度概念来管理这一点,通常将导数在x=0 处设置为 0.5 或[0, 1]之间的另一个值。这通常不会引起问题,因为精确的零输入很少见,数据变化很大。

那么,ReLU 是你正确的选择吗?许多研究人员说是的,多亏了它的简单性、效率和主要深度学习框架的支持。此外,最近的研究,如arxiv.org/abs/2310.04564中的一项,突出了 ReLU 的持续相关性,标志着机器学习世界的一种复兴。

在某些应用中,一个称为ReLU6的变体被用来限制输出在 6 以内,以防止过大的激活。这种修改,受实际考虑的启发,进一步说明了 ReLU 在各种神经网络架构中的适应性。为什么限制到 6?你可以在这篇帖子中找到答案。

Leaky ReLUs,对经典 ReLU 的轻微调整。当我们仔细观察 ReLU 时,会出现一些问题。它对负输入的零输出,导致“死亡 ReLU”问题,即神经元在训练过程中停止更新。此外,ReLU 对正值的偏好可能会在模型中引入方向偏差。为了克服这些缺点同时保留 ReLU 的优点,研究人员开发了几个变体,包括“漏出”ReLU 的概念。

Leaky ReLUs 修改了 ReLU 的负部分,给它一个小的非零斜率。这种调整允许负输入产生小的负输出,有效地“漏出”到原本为零输出的区域。这个漏出的斜率由超参数α控制,通常设置得接近 0,以保持稀疏性和保持神经元活跃之间的平衡**。通过允许轻微的负输出,Leaky ReLU 旨在将激活函数的输出集中在零周围,防止神经元变得不活跃,从而解决“死亡 ReLU”问题**。

然而,将α作为一个超参数引入,给模型调整增加了一层复杂性。为了管理这一点,已经开发出了原始 Leaky ReLU 的变体:

  • 随机 Leaky ReLU (RReLU):这个版本在训练期间随机化α在指定的范围内,在评估期间固定它。这种随机性可以帮助正则化模型并防止过拟合。

  • 参数化 Leaky ReLU (PReLU):PReLU 允许α在训练期间学习,使激活函数适应数据集的具体需求。尽管这可以通过将α调整到训练数据中来提高模型性能,但它也冒着过拟合的风险。

指数线性单元(ELU),通过增强对泄漏的控制对 Leaky ReLU 的改进。 Leaky ReLUs 和 ELU 都允许负值,这有助于将单元激活的平均值推向零,并保持激活函数的活力。Leaky ReLUs 的挑战在于它们无法调节这些负值的程度;理论上,这些值可以扩展到负无穷大,尽管目的是保持它们较小。ELU 通过为非正值引入非线性指数曲线来解决这个问题,有效地将负输出范围缩小并控制在最大为−𝛼(其中𝛼是一个新的超参数,通常设置为 1)。此外,ELU 是一个平滑函数。其指数部分使得负值和正值之间的过渡无缝,这对于基于梯度的优化是有利的,因为它确保了所有输入值上都有一个定义良好的梯度。这一特性也解决了 ReLU 和 Leaky ReLUs 中出现的不可微问题。

缩放指数线性单元(SELU),具有自归一化特性的增强 ELU。 SELU 本质上是一个缩放版本的 ELU,旨在在神经网络中维持零均值和单位方差——我们将在关于批量归一化的讨论中进一步探讨这一概念。通过整合一个固定的缩放因子λ(大于 1),SELU 确保正净输入的斜率超过 1。这一特性特别有用,因为它在梯度较低层减小时放大梯度,有助于防止在深度神经网络中经常遇到的梯度消失问题。

注意,缩放因子λ应用于负数和正数输入,以在反向传播过程中均匀缩放梯度。这种均匀缩放有助于在网络中维持方差,这对于 SELU 激活函数的自归一化特性至关重要。

对于 SELU,参数(α和λ)具有固定值且不可学习,这简化了调整过程,因为需要调整的参数更少。您可以在PyTorch 中的 SELU 实现中找到这些特定值。

SELU 是由 Günter Klambauer 等人在其论文中引入的。他们的论文内容全面,包含令人印象深刻的 92 页附录,为那些对α和λ特定值推导过程感兴趣的读者提供了详细见解。您可以在论文本身中找到这些参数的计算和背后的理由。

SELU 确实是在激活函数的世界中一个复杂的“混合器”,但它有一些特定的要求。它在前馈或顺序网络中最有效,可能不适合像 RNNs、LSTMs 或具有跳跃连接的架构,因为其设计原因。

SELU 的自归一化特性要求输入特征进行标准化——具有 0 均值和单位标准差至关重要。此外,每个隐藏层的权重都必须使用 LeCun 正态初始化进行初始化,其中权重是从均值为 0、方差为 _1/fanin 的正态分布中抽取的。如果你不熟悉“fan_in”这个术语,我将在一个专门的关于权重初始化的会话中解释它。

总结来说,为了确保 SELU 的自归一化能够有效运作,你需要确保输入特征已归一化,并且网络结构保持一致,没有任何中断。这种一致性有助于在整个网络中保持自归一化效果,而不会出现任何泄漏。

GELU(高斯误差线性单元)是一种创新的激活函数,它结合了 Dropout 的正则化思想。 与传统的 ReLU 不同,ReLU 对于负输入输出为零,而 leaky ReLU、ELU 和 SELU 允许负输出。这有助于将激活的均值更接近零,以类似于 ReLU 的方式减少偏差,但不会完全将负输入置零。然而,这种泄漏意味着它们失去了“即将死亡的 ReLU”的一些好处,即某些神经元的失活可能导致更稀疏、更通用的模型。

考虑到在即将死亡的 ReLU 和 Dropout 随机失活和再激活神经元的能力中看到的稀疏性好处,GELU 将这一概念进一步发展。它结合了即将死亡的 ReLU 的零输出特征和随机性元素,使神经元有可能“复活”。这种方法不仅保持了有益的稀疏性,还重新引入了神经元活动,使 GELU 成为一个稳健的解决方案。为了充分理解其机制,让我们更仔细地看看 GELU 的定义:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/549173fa213981fae8a3825ab57e97c1.png

Image created by author using Mathcha.com

在 GELU 激活函数中,CDF Φ(x),即标准高斯累积分布函数,起着关键作用。这个函数表示一个标准正态随机变量将具有小于或等于 x 的值的概率。Φ(x) 从 0(对于负输入)平滑过渡到 1(对于正输入),有效地控制了当用正态分布 N(0,1) 模型时输入的缩放。根据 Dan Hendrycks 等人的一篇论文(source),使用正态分布是合理的,因为神经元输入往往遵循正态分布,尤其是在使用批量归一化时。

函数的设计允许当x减少时,输入被“丢弃”的频率更高,这使得转换既具有随机性又依赖于输入值。这种机制通过使通常的直线函数 f(x) = x 更平滑,并避免分段线性函数中的突然变化,有助于保持形状与 ReLU 函数相似。GELU 最显著的特征是它可以完全失活神经元,从而可能允许它们在输入变化时重新激活。这种随机性质就像一个选择性的 dropout,它不是完全随机的,而是依赖于输入,给神经元再次活跃的机会。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/338a3cfb76e93aa32e01277570aa74bf.png

来自维基百科的累积分布函数。来源:upload.wikimedia.org/wikipedia/commons/thumb/c/ca/Normal_Distribution_CDF.svg/300px-Normal_Distribution_CDF.svg.png

总结来说,GELU 相较于 ReLU 的主要优势在于它考虑了输入值的整个范围,而不仅仅是它们是正数还是负数。当Φ(x)减少时,它增加了 GELU 函数输出更接近 0 的可能性,以一种概率性的方式“降低”神经元的活性。这种方法比典型的 dropout 方法更复杂,因为它依赖于数据来确定神经元的失活,而不是随机进行。我发现这种方法非常迷人;它就像在手工制作的甜点中添加了一抹柔软的奶油,微妙但显著地提升了甜点。

由于其在语言处理任务中的效率和强大性能,GELU 已成为模型如GPT-3BERT和其他 Transformers 中流行的激活函数。尽管由于其概率性质而计算密集,但标准高斯累积分布的曲线Φ(x)与 sigmoid 和 tanh 函数相似。有趣的是,GELU 可以使用 tanh 或通过公式 x(1.702*x)来近似。尽管有这些简化的可能性,但 PyTorch 对 GELU 的实现足够快,因此这些近似通常是不必要的。

在我们深入探讨更多原因之前,让我们先尝试总结一下。

通过回顾 ReLU 及其它受其启发的激活函数,究竟什么是好的激活函数?

Günter Klambauer 等人提出的论文,其中介绍了 SELU,突出了有效激活函数的基本特征:

  1. 范围:它应该输出正负值,以帮助管理网络中的平均激活水平。

  2. 饱和区域:这些区域中导数接近零,有助于稳定来自低层的过高方差。

  3. 放大斜率:当低层方差太低时,斜率大于一对于提升方差至关重要。

  4. 连续性:连续的曲线确保了一个平衡点,其中方差抑制和增加的效果是平衡的。

此外,我建议为“理想”激活函数增加两个标准:

  1. 非线性:这是显而易见且必要的,因为线性函数无法有效地模拟复杂模式。

  2. 动态输出:能够输出零并根据输入数据改变输出的能力,允许动态神经元激活和去激活,这使得网络能够高效地适应变化的数据条件。

你能给我一个更直观的解释,说明为什么我们希望激活函数输出负值吗?

将激活函数想象成搅拌机,它们将原始输入数据转换。就像可能偏袒某些成分的搅拌机一样,激活函数可以根据其固有特性引入偏差。例如,sigmoid 和 ReLU 函数通常只产生非负输出,无论输入如何。这类似于一个搅拌机,无论你放入什么成分,总是产生相同的味道。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/8eb99f76c0df457357ee1798a537adda.png

由作者使用 ChatGPT 创建的图像。

为了最小化这种偏差,拥有能够输出负值和正值的激活函数是有益的。**本质上,我们追求的是零中心输出。**想象一个代表激活函数输出的跷跷板:对于 Sigmoid 和 ReLU 这样的函数,跷跷板严重偏向正侧,因为这些函数要么忽略,要么将负输入置零。Leaky ReLU 试图通过允许负输入产生轻微的负输出来平衡这个跷跷板,尽管由于其负斜率的线性和常数性质,这种调整是微小的。另一方面,指数线性单元(ELU)通过其指数成分在负侧提供更动态的推动,帮助跷跷板在零点达到更平衡的状态。这种平衡对于保持神经网络中健康的梯度流和高效学习至关重要,因为它确保了正负更新都对训练做出贡献,避免了单向更新的局限性。

我们能否创建一个类似于使用 min(0, x)来将正输入置零的激活函数 ReLU?为什么我们更倾向于选择从负侧接近零的函数,而不是将正输入置零?

在这里,负侧的饱和意味着一旦输入值低于某个阈值,进一步的降低对输出的影响越来越小。这限制了大型负输入的影响。

当然,你可以设计一个版本的 ReLU,使其将正值置零,而让负值保持不变,就像 f(x) = min(x, 0) 这样。这在技术上是可以实现的,因为这里重要的方面不是值的符号,而是将非线性引入网络。重要的是记住,这些激活函数通常用于隐藏层,而不是输出层,因此它们不会直接影响最终输出的符号。换句话说,网络中存在这些激活函数意味着最终输出仍然可以是正的或负的,不受这些层特定特性的影响。

无论输出的符号如何,网络的权重和偏差都可以调整以匹配所需的输出符号。例如,使用传统的 ReLU,如果输出是 1 并且后续层的权重是 1,输出仍然是 1。同样,如果一个提议的 ReLU 变体输出 -1,而权重是 -1,结果仍然是 1。本质上,我们更关心输出的幅度而不是其符号。

因此,ReLU 在负侧饱和与在正侧饱和在本质上没有区别。然而,我们重视零中心激活函数的原因是它们防止了对正或负值的固有偏好,避免了模型中的不必要偏差。这种平衡有助于在整个网络中保持中性和有效性。

我明白对于像 Leaky ReLU 这样的函数,我们希望输出负值以使输出围绕零中心。但为什么 ELU、SELU 和 GELU 特别设计为在负输入时饱和?

要理解这一点,我们可以看看 ReLU 背后的生物灵感。ReLU 模仿具有阈值的生物神经元;高于这个阈值的输入会激活神经元,而低于这个阈值的输入则不会。这种在活跃和静止状态之间切换的能力对神经功能至关重要。当考虑 ELU、SELU 和 GELU 这样的变体时,你会注意到它们的设计解决了两个不同的需求:

  • 正值区域:允许在正向传播过程中,超过阈值的信号保持不变地通过,本质上传输了所需的信号。

  • 负值区域:用于最小化或过滤掉不需要的信号,并减轻大负值的影响,就像一个泄漏的门。

这些函数本质上充当输入的门,管理哪些应该以及不应该影响神经元的输出。例如,SELU 独特地利用这两个方面:

  • 正值区域:缩放因子 λ(大于 1)不仅允许信号通过,还会略微放大信号。在反向传播过程中,该区域的导数保持不变(大约 1.0507),增强小的但有用的梯度以对抗梯度消失。

  • 负区域:导数介于 0 和λα(典型值λ ≈ 1.0507 和α ≈ 1.6733)之间,导致最大导数约为 1.7583。在这里,函数几乎接近零,有效地将过大的梯度减小,有助于解决梯度爆炸问题。

这里有一个非常好的图表,用于说明这些激活函数的第一导数。

这种设计使得这些激活函数在增强有用信号的同时,抑制可能的有害极端值,为网络提供更稳定的 学习环境。

激活函数作为门控的概念并不是一个新想法。它在 LSTMs 等结构中有很强的先例,其中 sigmoid 函数决定要记住、更新或忘记什么。这个门控概念帮助我们理解为什么 ReLU 的变体被设计成特定的方式。例如,GELU 充当一个动态门控,它使用从标准正态分布的累积分布函数(CDF)导出的缩放因子。这种缩放允许当输入接近零时,一小部分输入通过,并允许较大的正值基本无变化地通过。通过控制输入对后续层的影响程度,GELU 促进了有效的信息流管理,这在像 transformers 这样的架构中特别有用。

所提到的三种激活函数,ELU、SELU 和 GELU,都使负侧更加平滑。这种负输入的平滑饱和不仅减轻了大型负值的影响,还使网络对输入数据的波动不那么敏感,导致更稳定的特征表示。

总的来说,饱和的具体区域,无论是正还是负,在本质上并不重要,因为这些激活函数在网络的中间层运行,权重和偏差可以相应地调整。**然而,这些函数的设计,允许一侧信号不变或甚至放大,而另一侧饱和,这是重要的。**这种安排有助于组织信号并促进有效的反向传播,增强网络的总体性能和学习稳定性。

我们应该在何时选择每个激活函数?为什么 ReLU 在实践上仍然是最受欢迎的激活函数?

选择合适的激活函数取决于几个因素,包括计算资源、网络架构的具体需求以及先前模型的经验证据。

  1. 计算资源:如果您有足够的计算资源,可以通过交叉验证实验不同的激活函数,这可以提供有价值的见解。这允许您根据您的特定模型和数据集调整激活函数。请注意,当使用 SELU 时,通常不需要批量归一化,这可以简化架构,而其他函数可能需要批量归一化。

  2. 经验证据:某些函数已成为特定应用的行业标准。例如,GELU 由于其在这些架构中的有效性,通常被选为训练 transformer 模型的优选选择。SELU 由于其自归一化特性和无需调整的超参数,特别适用于训练稳定性至关重要的深层网络。

  3. 计算效率和简单性:在计算效率和简单性是优先考虑的场景中,ReLU 及其变体如 PReLU 和 ELU 是优秀的选择。它们避免了参数调整的需要,并支持模型的稀疏性和泛化,有助于减少过拟合。

尽管出现了更复杂的函数,ReLU 由于其简单性和效率而仍然非常受欢迎。它的实现简单,易于理解,并提供了一种清晰的方法在不复杂化计算的情况下引入非线性。该函数能够将负部分置零简化了计算并提高了计算速度,这在大型网络中尤其有利。

ReLU 的设计本质上通过将负激活置零来增加模型的稀疏性,这可以提高泛化能力——鉴于过拟合是训练深度神经网络的一个重大挑战,这是一个关键因素。此外,ReLU 不需要任何额外的超参数,这与引入模型训练额外复杂性的 PReLU 或 ELU 等函数形成对比。此外,由于 ReLU 已被广泛采用,许多机器学习框架和库为其提供了专门的优化,使其成为许多开发者的实用选择。

总而言之,虽然新的激活函数为特定场景提供了某些好处,但 ReLU 在简单性、效率和有效性方面的平衡使其成为许多应用的优选选择。在前进到任何激活函数时,彻底了解其特征对于确保它与您的模型需求相匹配以及便于在模型训练期间进行故障排除至关重要。

PyTorch 提供了各种激活函数,每个函数都有其特定的应用和好处,这些在文档中有详细说明。由于篇幅限制,这里不会涵盖所有可能的激活函数,例如 softplus。重要的是将这些函数视为以不同方式修改输入的混合器,建立在它们前辈的功能之上。理解每个函数如何从上一个函数演变,有助于快速掌握新的函数并评估它们的优缺点。我们将在后面深入探讨这些激活函数如何与不同的权重初始化策略相互作用,进一步增强这些工具在神经网络设计中的有效使用。

对于 PyTorch 激活函数的更详细探索,你可以始终参考PyTorch 的官方文档

权重初始化

好吧,让我们停止寻找完美的激活函数以稳定梯度,并专注于另一个关键方面,通过有效地初始化权重来正确设置我们的神经网络。

在深入探讨最流行的权重初始化方法之前,让我们解决一个基本问题:

注意,权重初始化实际上比乍看之下要复杂得多,这篇帖子只是触及了这个主题的表面。正如我提到的,选择合适的权重初始化起点对于网络的有效优化至关重要。如果你想要更深入和更全面的理解,我建议查看这里提供的详细综述链接。这可以真正增强你对涉及技术的掌握。

为什么权重初始化很重要,它如何帮助减轻梯度不稳定的问题?

正确的权重初始化确保梯度在整个模型中正确流动,类似于在冰淇淋工厂中半成品在各个部门之间的传递。不仅初始机器设置必须正确,而且每个部门都必须高效工作。

权重初始化旨在确保信息在网络中的前向和反向传播过程中保持稳定流动。过大的或过小的权重可能会引起问题。过大的权重可能会在正向传播期间过度增加输出,导致预测过大。另一方面,非常小的权重可能会过度减少输出。**在反向传播过程中,这些权重的幅度变得至关重要。**如果一个权重过大,它可能会导致梯度爆炸,如果过小,梯度可能会消失。理解这一点,我们避免将权重初始化在极端值,如零(这会消除输出和梯度)或过高的值。这种平衡的方法有助于保持网络的有效性,并防止与梯度不稳定相关的问题。

有什么好的方法来初始化权重?

首先,最好的权重初始化通常来自使用预训练的权重。如果你能获得一组已经经过一些学习并且趋向于最小化损失的权重,从这个点继续是理想的。

然而,如果你是从零开始,你需要仔细考虑如何初始化你的权重,特别是要防止不稳定的梯度。以下是在良好的权重初始化中你应该追求的目标:

  • 避免极端值。正如我们之前讨论的,权重既不应该太大,也不应该太小,也不应该是零。适当缩放的权重有助于在网络训练的前向和反向传递过程中保持稳定性,如前所述。

  • 打破对称性。权重多样化非常重要,以防止神经元相互镜像行为,这会导致它们学习相同的特征而忽略其他特征。这种缺乏差异化的情况会严重限制网络建模复杂模式的能力。不同的初始权重有助于每个神经元开始学习数据的各个方面。这就像在冰淇淋工厂中有各种类型的生产线,可以增强可以生产的口味范围。

  • 在损失表面上有利地定位。初始权重应该将模型放置在损失表面的一个不错的起始位置,以便使向全局最小值的旅程更加可行。由于我们没有清晰的损失景观图,因此在权重初始化中引入一些随机性可能是有益的。

这就是为什么将所有权重都设置为零是有问题的。它会导致对称性问题,其中所有神经元的行为都相同,以相同的速率学习,从而阻止网络有效地捕捉各种模式。零权重还导致零输出,尤其是在 ReLU 及其变体中,导致零梯度。这种缺乏梯度流会完全停止学习,使所有神经元都变得不活跃。

为什么不使用小的随机数初始化所有权重?

虽然使用小的随机数初始化权重可能会有所帮助,但它通常缺乏足够的控制。随机分配的权重可能太小,导致梯度消失问题,在训练过程中更新变得微不足道,从而阻碍学习过程。此外,完全随机的初始化并不能保证打破对称性。例如,如果初始化的值太相似或都具有相同的符号,神经元可能仍然表现得过于相似,无法学习数据的各个方面。

在实践中,使用更结构化的初始化方法。著名的方法包括 Glorot(或 Xavier)初始化、He(或 Kaiming)初始化和 LeCun 初始化。这些技术通常依赖于正态或均匀分布,但会根据前一层和下一层的大小进行调整,提供一种平衡,以促进有效的学习,同时降低梯度消失或爆炸的风险。

如果是这样,为什么不直接使用标准正态分布(N(0,1))进行权重初始化呢?

使用标准正态分布(N(0,1))对随机化过程提供了一些控制,但由于对方差的缺乏控制,它不足以进行最优的权重初始化。均值为零是一个不错的选择,因为它有助于确保权重不会共享相同的符号,从而有效地打破对称性。然而,方差为 1 可能存在问题。

考虑一种情况,其中激活函数的输入 𝑍 依赖于权重。假设 𝑍 是通过将前一层中每个具有从标准正态分布初始化的权重的 𝑁 个神经元的输出求和来计算的。在这里,𝑍 也将是正态分布的,均值为零,但其方差将是 𝑁。例如,如果 𝑁=100,那么 𝑍 的方差变为 100,这太大了,会导致激活函数的输入不受控制,可能在反向传播期间导致梯度不稳定。用冰淇淋工厂作类比,这就像在每台机器的设置中设定了高容错率,由于缺乏质量控制,最终产品与预期结果有显著偏差。

那么,我们为什么关心 𝑍 的方差呢?方差控制着 𝑍 值的分布范围。如果方差太小,𝑍 的输出可能变化不足,无法有效地打破对称性。然而,方差过大可能导致这些值要么过高要么过低。对于像 sigmoid 这样的激活函数,极端高或低的输入会将输出推向函数的饱和尾部,这可能导致梯度消失问题。

因此,当从分布中随机抽取权重进行初始化时,均值和方差都是至关重要的。目标是设置均值为零,以有效地打破对称性,同时最小化方差,以确保半产品(即神经元输出)既不太大也不太小。适当的初始化确保了网络中信息流的稳定,无论是正向还是反向,都保持了高效的学习过程,而没有在梯度中引入不稳定性。因此,对初始化的深思熟虑的方法可以导致一个有效且鲁棒的网络学习。

因此,为了控制神经网络中间层的输出值,这些层也作为后续层的输入,我们在权重初始化时使用精心选择的均值和方差分布。但是,最流行的方法是如何控制这种方差的呢?

在深入探讨最常见的权重初始化方法之前,重要的是要注意,𝑍 的方差不仅受权重初始化方差的影响,还受参与计算 𝑍 的神经元数量影响。如果只使用 16 个神经元,𝑍 的方差是 16,而使用 100 个神经元时,方差会上升到 100。本质上,这种方差不仅受权重抽取分布的影响,还受参与计算的神经元数量(称为“fan-in”)的影响。Fan-in 指的是进入神经元的输入连接数量。同样,“fan-out”指的是神经元拥有的输出连接数量。

让我通过一个例子来说明:假设有一个神经网络中的中间层,有 200 个神经元,连接到前一个层的 100 个神经元和后一个层的 300 个神经元。在这种情况下,该层的 fan-in 是 100,fan-out 是 300。

使用 fan-in 和 fan-out 提供了一种在权重初始化过程中控制方差的机制。

  • Fan-in 在前向传播过程中有助于控制当前层的输出 𝑍 的方差。

  • Fan-out 调整在反向传播过程中后续层权重的影响。

基于对当前层在正向和反向传播过程中输入的神经元数量的考虑,研究人员提出了一系列基于这些想法的初始化方法。这些方法包括 Lecun、Xavier/Glorot 初始化和 He/Kaiming 初始化。这些方法的思想相当相似,它们使用均匀分布或正态分布作为权重随机生成的来源,并使用 fan-in 或 fan-out 来控制方差。这些分布的均值都是 0,以实现输出值的零均值。

在这篇文章中,我只提供了一个关于权重初始化方法的快速概述。要查看详细解释,可以参考《动手学机器学习:基于 Scikit-Learn、Keras 和 TensorFlow》一书以及 Weights & Biases 上的这篇帖子,以获取实际见解和历史背景。

# Different types of initializations

| Initialization | Activation functions          | σ² (Normal) |
| -------------- | ----------------------------- | ----------- |
| Xavier/Glorot  | None, tanh, logistic, softmax | 1 / fan_avg |
| He/Kaiming     | ReLU and variants             | 2 / fan_in  |
| LeCun          | SELU                          | 1 / fan_in  |

Lecun 初始化是通过使用较小的权重分布方差来缩小 𝑍 的方差。如果 𝑍 的方差是输入神经元数量和每个权重方差的乘积,那么为了确保 𝑍 有一个方差为 1,每个权重的方差应该是 1/fan-in。因此,Lecun 初始化从 𝑁(0,1/fan-in) 中随机抽取权重。

Xavier/Glorot 初始化不仅考虑了前一层权重(fan-in)的影响,还考虑了这些权重在反向传播中对后续层(fan-out)的影响。它通过使用公式 2/(fan_in + fan_out)) 来平衡正向和反向传播过程中的方差,从而从正态分布 N(0,2/(fan_in + fan_out)) 或均匀分布 (- sqrt(6/ (fan_in + fan_out)), sqrt(6/ (fan_in + fan_out))) 中抽取权重。

均匀分布 (- sqrt(6/ (fan_in + fan_out)), sqrt(6/ (fan_in + fan_out))) 与正态分布具有相同的方差 2/(fan_in + fan_out),因为我们使用下限和上限来定义均匀分布,其方差正是 (上限 - 下限) **2 的 1/12 倍。(source)

He/Kaiming 初始化针对 ReLU 及其变体进行了优化,因为它们具有独特的属性。由于 ReLU 将负输入置零,因此预计一半的神经元激活将是非零的,这可能导致方差减小和梯度消失。为了补偿这一点,He 初始化将 Lecun 方法中使用的方差加倍,实际上使用 2*1/fan_in,从而为使用 ReLU 的层保持必要的平衡。对于漏 ReLU 和 ELU,尽管调整很小(例如,对于 ELU 使用 1.55 的因子而不是 2,source),但原则是相同的,我们希望调整方差以在反向传播期间稳定梯度。相比之下,SELU 需要在所有隐藏层中使用 Lecun 初始化,以利用其自归一化属性。

这次讨论开启了在 PyTorch 等框架中实现权重初始化的有趣方面,这可以作为一个问题来阐述——

PyTorch 中如何实现权重初始化,以及它有什么特别之处?

在 PyTorch 中,线性层中权重初始化的默认方法基于 Lecun 初始化方法。另一方面,Keras 中使用的默认初始化技术是 Xavier/Glorot 初始化。

然而,PyTorch 在权重初始化方面提供了一个特别灵活的方法,允许用户根据模型中使用的不同激活函数的具体要求来微调这个过程。这种微调是通过考虑两个关键组件来实现的:

  1. 模式:该组件确定初始化权重的方差是否根据层中输入连接数(fan-in)或输出连接数(fan-out)进行调整。

  2. 增益:这是一个缩放因子,根据模型中使用的激活函数调整初始化权重的规模。PyTorch 提供了一个[torch.nn.init.calculate_gain](https://pytorch.org/docs/stable/nn.init.html#torch.nn.init.calculate_gain)函数,该函数计算一个定制的增益值,优化初始化过程以增强神经网络的总体功能。

这种在自定义权重初始化参数方面的灵活性,使您能够设置一个与您模型中使用的特定激活函数相当且兼容的初始化方法。有趣的是,PyTorch 对权重初始化的实现可以帮助揭示不同初始化方法之间的一些潜在关系。

例如,在审查 PyTorch 关于 SELU 激活函数的文档时,我发现了一个关于权重初始化的有趣方面。文档指出,当使用kaiming_normalkaiming_normal_进行初始化并与 SELU 激活一起使用时,应该选择nonlinearity='linear'而不是nonlinearity='selu'以实现自归一化。这个细节非常吸引人,因为它突出了当 PyTorch 中的默认 Lecun 初始化与设置为 1 的 Kaiming 方法调整时,如何有效地复制 Lecun 初始化方法。这表明 Lecun 初始化是更通用的 Kaiming 初始化方法的一个特定应用。同样,Xavier 初始化方法可以被视为 Lecun 初始化的另一种变体,它调整了输入连接数(fan-in)和输出连接数(fan-out)。

我明白在从分布初始化权重时,我们需要小心选择均值和方差。但我仍然不清楚为什么我们想要从正态分布而不是均匀分布中抽取初始权重。你能解释一下使用一种而不是另一种的理由吗?

你关于在初始化权重时仔细选择分布的均值和方差的重要性是合理的。在初始化神经网络中的权重时,一个重要的考虑因素是是否从正态分布或均匀分布中抽取。虽然没有确凿的研究支持的答案,但有一些合理的理由支持这些选择:

均匀分布具有最高的熵,这意味着在范围内的所有值出现的可能性是相同的。这种无偏的方法在你缺乏关于哪些值可能更适合初始化的先验知识时非常有用。它公平地对待每个潜在权重值,赋予相等的概率。这类似于在信息有限的游戏中均匀地赌注所有队伍——它最大化了有利结果的可能性。由于你不知道哪些具体值能作为良好的初始权重,使用均匀分布确保了一个无偏的起点。

另一方面,正态分布更有可能初始化接近零的小值权重。较小的初始权重通常更受欢迎,因为它们可以减少输出的方差,并在训练过程中帮助保持梯度的稳定性。这类似于为什么我们更倾向于在权重初始化方法中使用较小的方差而不是单位方差。此外,某些激活函数如 sigmoid 和 tanh 在较小的初始权重值下往往表现更好,即使这些激活只在最终输出层而不是隐藏层中使用。

关于似然的概念,你可以参考我之前的文章,我在其中用一个涉及我的猫泡泡的例子来解释似然、最大似然估计(MLE)和最大后验估计(MAP)。

最终,当缺乏先验知识时,均匀分布提供了一个无偏的起点,将所有潜在的权重值视为等可能的。相比之下,正态分布倾向于初始化接近零的小值权重,这有助于梯度稳定性,并适合 sigmoid 和 tanh 等某些激活函数。这些分布之间的选择通常由不同神经网络架构和任务中的经验发现所指导。虽然不存在普遍最优的方法,但了解均匀和正态分布的性质允许做出更明智、针对特定问题的初始化决策。

我们也使用那些权重初始化方法来初始化偏置项吗?我们如何初始化偏置?

好问题。我们不一定使用与权重相同的初始化技术来初始化偏置项。事实上,将所有偏置初始化为 0 是一个常见的做法。原因是,虽然权重决定了每个神经元学习近似底层数据的函数的形状,但偏置仅作为偏移值来上下移动这些函数。因此,偏置不会直接影响权重学习到的整体形状。

由于初始化的主要目标是打破对称性并为权重学习提供一个良好的起点,所以我们不太关心偏差的初始化方式。将它们全部设置为 0 通常就足够了。你可以在CS231n 课程笔记中找到更多详细讨论。

批标准化

在选择了激活函数并正确初始化权重后,我们可以开始训练我们的神经网络(启动我们的迷你冰淇淋工厂生产线)。但是,在初始阶段和训练迭代过程中都需要进行质量控制。两种关键技术是特征归一化和批标准化。

如前所述,在我的关于梯度下降的文章中讨论过,这些技术通过重塑损失景观来加速收敛。特征归一化将此应用于初始数据输入,而批标准化则在每个 epoch 之间对隐藏层输入进行归一化。这两种技术都类似于在“生产线”的不同阶段实施质量检查。

批标准化为什么有效?为什么使每一层的输入具有零均值和单位方差有助于解决梯度问题?

批标准化有助于通过在训练过程中减少层之间的内部协变量偏移来缓解梯度消失/爆炸等问题。让我们先思考一下这种内部偏移最初为什么会发生。当我们根据梯度更新每一层的参数时,每一层的网络就像工厂中的不同部门。每次你更新一个部门的参数(或设置),都会改变下一个部门的输入。这可能会造成一些混乱,因为每个后续部门都必须适应新的变化。这就是我们在深度学习中所说的内部协变量偏移。现在,当这些偏移频繁发生时,网络难以稳定,因为每一层的输入都在不断变化。这就像工厂某一部分的持续变化会导致产品质量的不一致,让工人困惑并打乱工作流程一样。

批标准化旨在通过在训练期间将每一层的输入归一化到具有零均值和单位方差来解决这一问题。它强制执行一个一致、可控的输入分布,层可以预期。回到工厂的类比,就像在输出传递到下一个部门之前为每个部门的输出设定严格的质量标准。例如,设定规则,烘焙部门必须生产大小和形状一致的冰淇淋锥。这样,下一个装饰部门就不必考虑锥形的变化——他们只需向每个标准化的锥形添加相同数量的冰淇淋。

通过归一化减少这种内部协变量偏移,批量归一化防止了在训练过程中梯度变得混乱。层不需要不断调整以适应剧烈变化输入分布,因此梯度保持更稳定。

此外,归一化作为正则化器,平滑了目标景观。这允许使用更高的学习率以实现更快的收敛。通常,批量归一化减少了内部方差偏移,稳定了梯度,正则化了目标,并实现了训练加速。

正如我们在激活部分前面提到的,SELU 使用批量归一化的原理来实现自归一化。对于对批量归一化更深入的探索,我强烈推荐阅读 Johann Huber 在 Medium 上发布的详细文章批量归一化在三个理解层次

如何应用批量归一化?应该在激活之前还是之后应用?如何在训练和测试期间处理它?

批量归一化通过添加一个额外的层来稳定梯度,真正改变了我们训练深度神经网络的方式。在深度学习领域,关于是否在激活函数之前或之后应用它存在争议。说实话,这取决于你的模型,你可能需要做一些实验。只需确保你的方法保持一致,因为改变它可能会导致意外的问题。

在训练期间,批量归一化层计算每个维度上小批量的均值和标准差。然后,这些统计数据被用来归一化输出,确保其均值为零,方差为单位。这个过程可以被视为将输入的分布转换为标准正态分布。与使用整个训练数据集归一化特征的特征归一化不同,批量归一化根据每个小批量进行调整,使其动态且对处理的数据做出响应。

现在,测试是一个不同的情况。在归一化时,重要的一点是不要使用测试数据的均值和方差。相反,这些参数,被视为学习到的特征,应该从训练过程中继承过来。尽管训练过程中的每个小批量都有自己的均值和方差,但一个常见的做法是在整个训练阶段使用这些值的移动平均。这提供了一个稳定的估计,可以在测试期间应用。另一种不太常见的方法是,使用整个训练数据集进行一次额外的 epoch 来计算全面的均值和方差。

当使用 PyTorch 作为你的深度神经网络框架进行训练时,它提供了两个可调整的超参数 γβ,从而提供了额外的灵活性。这些参数允许对批量归一化过程进行微调。通常,默认设置非常有效。然而,需要注意的是,在训练的前向传递过程中,PyTorch 使用有偏估计器来计算方差,但在测试期间切换到无偏估计器来计算移动平均值。这种调整有助于更准确地近似总体标准差,增强模型在未见条件下的可靠性。

正确应用批量归一化对于网络中的有效学习至关重要。它确保网络不仅学习良好,而且能够在不同的数据集和测试场景中保持其性能。将其视为精确校准生产线上的每个环节,确保整个操作无缝且一致。

为什么批量归一化是在前向传递期间应用,而不是在反向传播期间直接应用于梯度?

有几个原因说明为什么批量归一化通常是在前向传递期间应用于输入或激活,而不是在反向传播期间直接应用于梯度。

首先,没有经验证据或实践表明将批量归一化直接应用于梯度的好处。内部协变量偏移的概念主要发生在前向传递期间,因为层输入的分布由于参数的更新而发生变化。因此,在这一阶段应用批量归一化来稳定这些输入,在它们被后续层处理之前是有意义的。此外,直接将批量归一化应用于梯度可能会扭曲梯度幅度和方向所携带的有价值信息。这类似于以改变其固有意义的方式修改客户反馈,这可能会误导我们迷你冰淇淋工厂的生产过程未来的调整。

然而,对梯度进行微调,如梯度裁剪,通常是可接受且有益的。这种技术将梯度限制在一个安全的范围内,防止它们变得过大。这类似于在反馈中过滤掉极端的异常值,有助于保持整体反馈的完整性,同时防止任何可能导致过程脱轨的剧烈反应。在 PyTorch 中,监控梯度范数是一种常见的做法,如果梯度开始爆炸,可以采用梯度裁剪等技术。PyTorch 提供了如 [torch.nn.utils.clip_grad_norm_](https://pytorch.org/docs/stable/generated/torch.nn.utils.clip_grad_norm_.html)[torch.nn.utils.clip_grad_value_](https://pytorch.org/docs/stable/generated/torch.nn.utils.clip_grad_value_.html) 等函数来帮助管理这一点。

您提到了裁剪梯度而不是直接归一化的选项。我们为什么选择裁剪梯度而不是 flooring 梯度?

裁剪梯度是一种简单而有效的技术,有助于防止梯度爆炸问题。我们通常会手动设置梯度的最大值。例如,ReLU 激活函数可以被修改为具有上限 6,在 PyTorch 中称为 ReLU6(了解更多关于 ReLU6 这里)。通过设置这个上限,我们确保在反向传播过程中,当梯度根据链式法则在每一层相乘时,它们的值不会变得过大。这种裁剪直接防止梯度上升到可能导致学习过程脱轨的程度,确保它们保持在可管理的范围内。

另一方面,flooring 梯度会设置一个下限,以防止它们变得过小。然而,它并没有解决梯度消失的根本问题。梯度消失通常是因为某些激活函数,如 sigmoid 或 tanh,当输入远离零时,会严重压缩梯度值。这导致梯度值非常小,使得学习过程变得极其缓慢或停滞。flooring 梯度并不能解决这个问题,因为问题的根源在于激活函数压缩梯度值的本质,而不仅仅是值太小。相反,为了有效地对抗梯度消失,调整网络架构或激活函数的选择更有益。例如,使用不饱和的激活函数(如 ReLU)、添加跳跃连接(如 ResNet 架构中所示)或在 RNN 中使用门控机制(如 LSTM 或 GRU)等技术,可以在反向传播过程中确保梯度在整个网络中有一个更健康的流动,从而内在地防止梯度消失。

总结来说,虽然梯度裁剪有效地管理了过大的梯度,但设置下限的 flooring 方法并没有有效地解决过小梯度的问题。相反,解决与梯度消失相关的问题通常需要做出架构上的调整。

重要的是要注意,在使用梯度裁剪时,梯度裁剪阈值成为了一个额外的超参数,可能需要根据其他研究的结果和激活函数的选择进行调整。一如既往,引入这个额外的超参数为模型训练过程增加了另一层复杂性。

实践经验(个人经历)

在结束之前,很明显,所讨论的所有方法对于解决梯度消失和爆炸问题都是有价值的。这些都是可以增强模型训练过程的实用方法。为了结束这篇帖子,我想以最后一个问题作为结尾——

现实情况是怎样的?实践中通常遵循哪些流程?

在实践中,好消息是您不需要对每个可能的解决方案都进行实验。当涉及到选择激活函数时,ReLU 通常是首选,并且非常经济高效。它将正输入的幅度保持不变(与 sigmoid 和 tanh 不同,它们无论大小都会将大值压缩到 1),在计算及其导数方面非常直接。它也得到主要框架的良好支持。如果您担心死 ReLU 的问题,您可以考虑 Leaky ReLU、ELU、SELU 或 GELU 等替代方案,但通常建议避免 sigmoid 和 tanh 以避免梯度消失。

由于 ReLU 是首选的激活函数,因此对权重初始化过于敏感的担忧较少,这在 sigmoid、tanh 和 SELU 等函数中更为常见。相反,关注您选择的激活函数的推荐权重初始化方法应该足够(例如,由于 ReLU 的非线性考虑,使用 He/Kaiming 初始化与 ReLU)。

总是在您的网络中包含批量归一化。决定(或实验)是否在激活函数之前或之后应用它,并始终如一地坚持这个选择。批量归一化提供了多种好处,包括正则化效果和允许使用更高的学习率,这可以加快训练和收敛速度。

那么,值得实验的是什么?优化器值得一些探索。在之前的一篇文章中,我讨论了各种优化器,包括梯度下降及其流行的变体(更多信息这里)。虽然 Adam 速度快,但可能导致过拟合,并且可能会过快地降低学习率。SGD 是可靠的,并且可以非常有效,尤其是在并行计算环境中。尽管它可能较慢,但如果您旨在从模型中获得最大性能,它是一个可靠的选择。有时,RMSprop 可能是一个更好的替代品。我个人发现,开始时使用 Adam 以获得其速度,然后在后续的周期中切换到 SGD 以找到更好的最小值并防止过拟合是一个很好的策略。


如果您喜欢这个系列这个系列,请记住,您的互动——点赞、评论和关注——不仅仅是支持;它们是推动这个系列继续进行并激励我持续分享的动力源泉。

本系列的其他文章:


参考文献

激活函数

权重初始化

梯度裁剪

考虑柔性负荷的综合能源系统低碳经济优化调度【考虑碳交易机制】(Matlab代码实现)内容概要:本文围绕“考虑柔性负荷的综合能源系统低碳经济优化调度”展开,重点研究在碳交易机制下如何实现综合能源系统的低碳化与经济性协同优化。通过构建包含风电、光伏、储能、柔性负荷等多种能源形式的系统模型,结合碳交易成本与能源调度成本,提出优化调度策略,以降低碳排放并提升系统运行经济性。文中采用Matlab进行仿真代码实现,验证了所提模型在平衡能源供需、平抑可再生能源波动、引导柔性负荷参与调度等方面的有效性,为低碳能源系统的设计与运行提供了技术支撑。; 适合人群:具备一定电力系统、能源系统背景,熟悉Matlab编程,从事能源优化、低碳调度、综合能源系统等相关领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①研究碳交易机制对综合能源系统调度决策的影响;②实现柔性负荷在削峰填谷、促进可再生能源消纳中的作用;③掌握基于Matlab的能源系统建模与优化求解方法;④为实际综合能源项目提供低碳经济调度方案参考。; 阅读建议:建议读者结合Matlab代码深入理解模型构建与求解过程,重点关注目标函数设计、约束条件设置及碳交易成本的量化方式,可进一步扩展至多能互补、需求响应等场景进行二次开发与仿真验证。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值