<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>第 6 章 模型优化方法 on 《从零学AI指南手册》</title>
		<link>https://mlwithme.github.io/dl/chapter06/</link>
		<description>Recent content in 第 6 章 模型优化方法 on 《从零学AI指南手册》</description>
		<generator>Hugo</generator>
		<language>zh_CN</language>
		
		
		
		
			<atom:link href="https://mlwithme.github.io/dl/chapter06/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>6.1 学习率调度器</title>
				<link>https://mlwithme.github.io/dl/chapter06/cc35bb112783410e/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter06/cc35bb112783410e/</guid>
				<description>&lt;h1 id=&#34;第-6-章-模型优化方法&#34;&gt;第 6 章 模型优化方法&lt;a class=&#34;anchor&#34; href=&#34;#%e7%ac%ac-6-%e7%ab%a0-%e6%a8%a1%e5%9e%8b%e4%bc%98%e5%8c%96%e6%96%b9%e6%b3%95&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在第5章内容中，我们详细介绍了深度学习模型训练过程中会用到的一些辅助技能和工具，以提高模型在训练过程的效率。在本章内容中我们将从模型优化的角度来介绍如何更快以及更好地训练一个深度学习模型。在本章内容中，我们将会详细介绍深度学习中常见的模型优化策略和方法，包括学习率调度器、梯度裁剪策略以及各种不同的归一化技术。同时，我们也将介绍基于梯度下降算法的各种改进版本，包括动量法、AdaGrad、AdaDelta和Adam等。这些算法为构建和优化深度学习模型提供了全面的指导和实践方法，并且能够帮助模型在训练过程中更快地进行收敛。&lt;/p&gt;&#xA;&lt;h1 id=&#34;61-学习率调度器&#34;&gt;6.1 学习率调度器&lt;a class=&#34;anchor&#34; href=&#34;#61-%e5%ad%a6%e4%b9%a0%e7%8e%87%e8%b0%83%e5%ba%a6%e5%99%a8&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在深度学习模型训练过程中，当模型结果不太理想时最常用的做法之一就是动态调整学习率，即在模型的训练过程中采用某种策略让学习率动态变化。如最简单的方法可以是每迭代一轮学习率降为之前的一半。当然， 还可以通过其它一些更为复杂的策略来进行控制，例如在2017年谷歌发布的Transformer模型中，论文作者就采用了如下公式来动态调整学习率：&lt;/p&gt;&#xA;$$&#xA;\text{learning\_rate}=d\_{\text{model}}^{-0.5}\cdot \text{min}(\text{Steps}^{-0.5},\text{Steps}\cdot \text{&#xA;Warmup\_Steps}^{-1.5}) \tag{6-1}&#xA;$$&lt;p&gt;其中$d_{\text{model}}$表示模型的维度，$\text{Steps}$表示小批量迭代的次数，$\text{Warmup\_Steps}$表示前期线性增长的迭代次数。&lt;/p&gt;&#xA;&lt;p&gt;根据式(6-1)中的计算方式，模型在训练过程中学习率的变化情况将如图6-1所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;350&#34; src=&#34;https://mlwithme.github.io/images/dl/2106260913134949230.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 6-1. Transformer动态学习率变化图&lt;/center&gt;&#xA;&lt;p&gt;如图6-1所示，3条曲线分别表示3组参数下学习率随着迭代次的变化情况，其中到达顶点之前的线性增长阶段便是“热身”（Warmup）阶段。&lt;/p&gt;&#xA;&lt;p&gt;当然，除了上述提到的两种学习率动态调整方式，常见的还有常数、线性、余弦变换等变换策略，并且还可以直接借助Transformers框架中的&lt;code&gt;optimization&lt;/code&gt;模块来实现。在本节接下来的内容中，我们将会先介绍如何直接使用Transformers框架中的&lt;code&gt;optimization&lt;/code&gt;模块来快速实现学习率动态调整的目的，然后再简单介绍一下各个方法背后的实现逻辑以及如何模仿来实现自定义的调整方法。&lt;/p&gt;&#xA;&lt;h2 id=&#34;611-使用示例&#34;&gt;6.1.1 使用示例&lt;a class=&#34;anchor&#34; href=&#34;#611-%e4%bd%bf%e7%94%a8%e7%a4%ba%e4%be%8b&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Transformers 框架是一个基于 PyTorch 和 TensorFlow 的开源自然语言处理框架，准确来说它应该是一个基于现有深度学习框架封装而来的高阶API库，由 HuggingFace 公司于2019年所发布 [2] [3]。Transformers 旨在提供便捷的训练、评估和部署最先进的NLP模型，特别是基于注意力机制的 Transformer 模型。该框架是目前最受欢迎和广泛使用的NLP框架之一，主要用于构建和训练自然语言处理模型，包括文本分类、序列标注、机器翻译、问答等任务。在后续的章节内容中我们也将陆续使用到该库。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;400&#34; src=&#34;https://mlwithme.github.io/images/dl/Hugging.png&#34;/&gt; &lt;/div&gt;&lt;center&gt; 图 6-2. Hugging Face公司标志图&lt;/center&gt;&#xA;&lt;p&gt;Transformers 框架包含了各种最先进的NLP模型，如BERT、GPT、RoBERTa、T5等，并且还提供了大量预训练的模型和权重，用户可以直接使用这些预训练模型进行各种NLP任务的微调和迁移学习，无需从头开始训练模型，这大大节省了训练时间和资源。同时，Transformers 框架支持多种语言接口，包括Python、Java、JavaScript等，使得用户可以在不同的平台和环境中使用 Transformers 框架进行NLP任务的开发和部署。此外，Transformers 框架还支持分布式训练和模型并行化，使得用户能够高效地训练大规模的NLP模型。&lt;/p&gt;&#xA;&lt;p&gt;在使用之前首先需要通过如下命令完成&lt;code&gt;在Transformers&lt;/code&gt;框架的安装：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; pip install transformers&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接着通过如下方式导入其中的&lt;code&gt;optimization&lt;/code&gt;模块：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#0e84b5;font-weight:bold&#34;&gt;transformers&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;import&lt;/span&gt; optimization&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在&lt;code&gt;optimization&lt;/code&gt;模块中，一共包含了6种常见的学习率动态调整方式，包括constant、constant_with_warmup、linear、polynomial、cosine 和cosine_with_restarts，其分别通过一个函数来返回对应的实例化对象，下面我们开始分别对其使用方法进行介绍。以下完整示例代码可以参见&lt;code&gt;Code/Chapter06/C01_LearningRate/mian.py&lt;/code&gt;文件。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. constant策略&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;在&lt;code&gt;optimization&lt;/code&gt;模块中可以通过&lt;code&gt;get_constant_schedule&lt;/code&gt;函数来返回对应的常数动态学习率调整方法。顾名思义，常数学习率动态调整就是学习率是一个恒定不变的常数，也就是说相当于没用。为了方便后续对学习率的变化过程可视化，这里先随意定义一个网络模型，示例代码如下所示：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#0e84b5;font-weight:bold&#34;&gt;Model&lt;/span&gt;(nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Module):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;__init__&lt;/span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;         &lt;span style=&#34;color:#007020&#34;&gt;super&lt;/span&gt;(Model, &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;)&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;__init__&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;         &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;fc &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Linear(&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;,&lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;forward&lt;/span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;, x):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt;         out &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;fc(x)&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;sum()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;8&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; out&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;进一步，在模型训练的过程中，我们可以通过以下方式来进行使用：&lt;/p&gt;</description>
			</item>
			<item>
				<title>6.2 梯度裁剪</title>
				<link>https://mlwithme.github.io/dl/chapter06/fc024c283f164849/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter06/fc024c283f164849/</guid>
				<description>&lt;h1 id=&#34;62-梯度裁剪&#34;&gt;6.2 梯度裁剪&lt;a class=&#34;anchor&#34; href=&#34;#62-%e6%a2%af%e5%ba%a6%e8%a3%81%e5%89%aa&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter03/97e1da1143cd4554&#34;&gt;3.3.7节&lt;/a&gt;中，我们首次介绍了深度学习中的梯度爆炸问题，其根本原因在于反向传播算法在求解模型梯度时累乘的计算特性导致越靠近输入层的权重参数越容易出现梯度爆炸的现象。通常来说解决梯度爆炸最直接的两种方法分别是使用较小的学习率和对梯度的大小进行限制。在接下来的这节内容中，我们将介绍深度学习中两种使用最为广泛的梯度裁剪（Gradient Clip）策略以及各自对应的使用方法[1]。&lt;/p&gt;&#xA;&lt;h2 id=&#34;621-基于阈值裁剪&#34;&gt;6.2.1 基于阈值裁剪&lt;a class=&#34;anchor&#34; href=&#34;#621-%e5%9f%ba%e4%ba%8e%e9%98%88%e5%80%bc%e8%a3%81%e5%89%aa&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;基于阈值的梯度裁剪方法是梯度裁剪中最直接也是最简单的方法，其核心思想便是根据给定的区间范围对于现有的梯度进行约束，对于超过该范围的梯度值将直接重新被赋值为区间的端点值。&lt;/p&gt;&#xA;&lt;p&gt;例如对于梯度值$[-3.8,-1.2,1.5,2.8]$，给定梯度的最大值为2.0，那么根据该梯度值将会被限定在区间$[-2.0,2.0]$之间，则裁剪后的梯度值便为$[-2.0,-1.2,1.5,2.0]$。下面借用PyTorch框架中的&lt;code&gt;clip_grad_value_&lt;/code&gt;函数通过一段简单的代码进行示例：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;test_grad_clip&lt;/span&gt;(clip_value&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.8&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;     w &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;tensor([[&lt;span style=&#34;color:#40a070&#34;&gt;1.5&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;0.5&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;3.0&lt;/span&gt;],[&lt;span style=&#34;color:#40a070&#34;&gt;0.5&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;1.&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;2.&lt;/span&gt;]],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;                      dtype&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;float32, requires_grad&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;True&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;     b &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;tensor([&lt;span style=&#34;color:#40a070&#34;&gt;2.&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;0.5&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;3.5&lt;/span&gt;], dtype&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;float32, requires_grad&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;True&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;     x &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;tensor([[&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;3.&lt;/span&gt;]], dtype&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;float32)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;     y &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;mean(torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;matmul(x, w &lt;span style=&#34;color:#666&#34;&gt;**&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt; b &lt;span style=&#34;color:#666&#34;&gt;**&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt;     y&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;backward()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;8&lt;/span&gt;     &lt;span style=&#34;color:#007020&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;# 梯度裁剪前: &amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;9&lt;/span&gt;     &lt;span style=&#34;color:#007020&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;grad_w: &lt;/span&gt;&lt;span style=&#34;color:#70a0d0&#34;&gt;{&lt;/span&gt;w&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;grad&lt;span style=&#34;color:#70a0d0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;10&lt;/span&gt;     &lt;span style=&#34;color:#007020&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;grad_b: &lt;/span&gt;&lt;span style=&#34;color:#70a0d0&#34;&gt;{&lt;/span&gt;b&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;grad&lt;span style=&#34;color:#70a0d0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;11&lt;/span&gt;     torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;utils&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;clip_grad_value_([w, b], clip_value)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;12&lt;/span&gt;     &lt;span style=&#34;color:#007020&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;# 梯度裁剪后: &amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;13&lt;/span&gt;     &lt;span style=&#34;color:#007020&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;grad_w: &lt;/span&gt;&lt;span style=&#34;color:#70a0d0&#34;&gt;{&lt;/span&gt;w&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;grad&lt;span style=&#34;color:#70a0d0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;14&lt;/span&gt;     &lt;span style=&#34;color:#007020&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;grad_b: &lt;/span&gt;&lt;span style=&#34;color:#70a0d0&#34;&gt;{&lt;/span&gt;b&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;grad&lt;span style=&#34;color:#70a0d0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第2~6行是定义了一个简单的线性变换计算过程（平方只是为了让每个权重参数求解得到的梯度不同）。第7行是计算&lt;code&gt;y&lt;/code&gt;关于参数&lt;code&gt;w&lt;/code&gt;和&lt;code&gt;b&lt;/code&gt;的梯度。第11行便是对计算完成的梯度进行裁剪。&lt;/p&gt;&#xA;&lt;p&gt;以下便是上述代码运行结束后的结果：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# 梯度裁剪前: &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt; grad_w: tensor([[&lt;span style=&#34;color:#40a070&#34;&gt;2.0000&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;0.6667&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;4.0000&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;                 [&lt;span style=&#34;color:#40a070&#34;&gt;1.0000&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;2.0000&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;4.0000&lt;/span&gt;]])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt; grad_b: tensor([&lt;span style=&#34;color:#40a070&#34;&gt;1.3333&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;0.3333&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;2.3333&lt;/span&gt;])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#60a0b0;font-style:italic&#34;&gt;# 梯度裁剪后: &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt; grad_w: tensor([[&lt;span style=&#34;color:#40a070&#34;&gt;0.8000&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;0.6667&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;0.8000&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt;                 [&lt;span style=&#34;color:#40a070&#34;&gt;0.8000&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;0.8000&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;0.8000&lt;/span&gt;]])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;8&lt;/span&gt; grad_b: tensor([&lt;span style=&#34;color:#40a070&#34;&gt;0.8000&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;0.3333&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;0.8000&lt;/span&gt;])&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从上述结果可以看出，在进行梯度裁剪后参数&lt;code&gt;w&lt;/code&gt;和&lt;code&gt;b&lt;/code&gt;的梯度均被约束在范围$[-0.8,0.8]$中。&lt;/p&gt;</description>
			</item>
			<item>
				<title>6.3 批归一化</title>
				<link>https://mlwithme.github.io/dl/chapter06/27ed3ed136e24092/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter06/27ed3ed136e24092/</guid>
				<description>&lt;h1 id=&#34;63-批归一化&#34;&gt;6.3 批归一化&lt;a class=&#34;anchor&#34; href=&#34;#63-%e6%89%b9%e5%bd%92%e4%b8%80%e5%8c%96&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在前面两节内容中，我们详细介绍了如何通过学习率动态调整以及梯度裁剪策略来提高模型的效果，在接下来的几节内容中我们将开始陆续介绍一些能够加速模型收敛速度的优化方法。我们知道，在机器学习中一种常见的提高模型收敛速度的方法就是对输入特征进行标准化，例如将每一列特征维度的方差和均值分别标准化为0和1。虽然在深度学习中我们也能够采用这一策略，但这还远远不够。在本节内容中，我们将会介绍深度学习中使用最为广泛的，由谷歌于2015年发表在ICML上所介绍的一种标准化方法——批归一化（Batch Normalization, BN）[1]。&lt;/p&gt;&#xA;&lt;h2 id=&#34;631-批归一化动机&#34;&gt;6.3.1 批归一化动机&lt;a class=&#34;anchor&#34; href=&#34;#631-%e6%89%b9%e5%bd%92%e4%b8%80%e5%8c%96%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在深度学习中，随着网络层数的加深越是越靠近输入层的权重参数其对应的梯度也将会越小（这是由反向传播的性质所决定，可见&lt;a href=&#34;https://mlwithme.github.io/dl/chapter03/97e1da1143cd4554&#34;&gt;3.3节&lt;/a&gt;内容），所以这就导致靠近输出层的权重参数能够更容易的得到训练，而靠近输入层的权重参数则更新缓慢。也正是由于两端的权重参数在更新节奏上相差太大网络底部的参数更新不及时，使得顶部的参数每次都要根据底部的前向传播结果来重新适应数据的分布，从而加大了网络的训练难度。&lt;/p&gt;&#xA;&lt;p&gt;假设现在有式(6-10)所示这么一个网络&#xA;&lt;/p&gt;&#xA;$$&#xA;\mathcal{L}=F_2(F_1(u,\Theta_1),\Theta_2)\tag{6-10}&#xA;$$&lt;p&gt;&#xA;其中$F_1,F_2$为任意的两个非线性变换，$u$为原始的网络输入，$\Theta_1,\Theta_2$分别为两个网络层的参数。&lt;/p&gt;&#xA;&lt;p&gt;现在的目的是通过最小化$\mathcal{L}$来求得参数$\Theta_1,\Theta_2$的取值。此时，我们也可以将$F_2$的输入看成是$x=F_1(u,\Theta_1)$，那么根据式(6-10)有&#xA;&lt;/p&gt;&#xA;$$&#xA;\mathcal{L}=F_2(x,\Theta_2)\tag{6-11}&#xA;$$&lt;p&gt;&#xA;接着根据式(6-12)就可以完成参数$\Theta_2$的迭代求解&#xA;&lt;/p&gt;&#xA;$$&#xA;\Theta_2\leftarrow\Theta_2-\alpha\frac{\partial F_2(x,\Theta_2)}{\partial \Theta_2}\tag{6-12}&#xA;$$&lt;p&gt;&#xA;由式(6-12)可知，由于输入$u$的分布每次在经过网络层$F_1$之后都会发生改变，这意味着网络层$F_2$中的参数$\Theta_2$每次都需要重新来学习适应输入值$x$的分布。也就是说，尽管一开始对原始的输入$u$进行了标准化，但经历过一个网络层后它的分布就发生了改变，那么下一层又需要重新学习另外一种分布，这就意味着每一层其实都是在学习不同的分布。Batch Normalization的思想便是在神经网络中添加一层归一化操作，使得网络中每一层输入的分布都尽可能地接近标准高斯分布，从而减轻这种问题。&lt;/p&gt;&#xA;&lt;h2 id=&#34;632-批归一化原理&#34;&gt;6.3.2 批归一化原理&lt;a class=&#34;anchor&#34; href=&#34;#632-%e6%89%b9%e5%bd%92%e4%b8%80%e5%8c%96%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. 归一化原理&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;假设现在有一个$d$维的网络层，其输出为$x=(x^{(1)},x^{(2)},...,x^{(d)})$，那么对于每一个维度都可以通过式(6-13)中的方法进行标准化&#xA;&lt;/p&gt;&#xA;$$&#xA;\hat{x}^{(k)}=\frac{x^{(k)}-E[x^{(k)}]}{\sqrt{Var[x^{(k)}]}}\tag{6-13}&#xA;$$&lt;p&gt;其中，$E[x^{(k)}]$和$Var[x^{(k)}]$分别是第$k$个维度在所有样本上计算得到的期望和方差。&lt;/p&gt;&#xA;&lt;p&gt;但如果仅仅只是简单通过式(6-13)中的计算方法来对每个维度进行标准化，那么在某些情况下将会改变该维度原有的表示信息。例如在对Sigmoid激活函数的输入值进行标准化时，通过公式(6-13)标准化后的输入值可能只会趋于0附近，从而把Sigmoid变成了一个线性激活函数。为了解决这一问题，可以加入了一组学习的参数$\gamma^{(k)}$和$\beta^{(k)}$来对$\hat{x}^{(k)}$进行了一次线性变换，即&#xA;&lt;/p&gt;&#xA;$$&#xA;y^{(k)}=\gamma^{(k)}\hat{x}^{(k)}+\beta^{(k)}\tag{6-14}&#xA;$$&lt;p&gt;&#xA;其中$y^{(k)}$就是最后得到的标准化结果，而$\gamma^{(k)}$和$\beta^{(k)}$也会随着网络中的权重参数一起训练，当且仅当$\gamma^{(k)}=\sqrt{Var[x^{(k)}]}$，$\beta^{(k)}=E[x^{(k)}]$时，公式(6-14)就变成了恒等变换，也就相当于没有进行标准化（如果网络确实需要的话）。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2. 小批量归一化&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;由于计算机硬件条件的限制等，我们不可能同时将所有的数据一次性输入到网络中进行训练，因此通常情况下都是输入小批量的样本到网络中进行训练，而这也是小批量归一化这个名字的由来。&lt;/p&gt;&#xA;&lt;p&gt;现假设现有一个样本数量为$m$的小批量数据$\mathcal{B}=\{x_1,x_2,\cdots, x_m\}$，同时由于BN是独立地对每个神经元的输出值进行标准化，这意味着每个神经元都有自己独立的参数，这里以对第$k$个神经元标准化为例进行介绍。具体的，对于整个BN的详细过程为&lt;/p&gt;&#xA;&lt;p&gt;①在小批量数据样本上根据式(6-15)计算第$k$个神经元输出结果的均值&#xA;&lt;/p&gt;&#xA;$$&#xA;\mu_{\mathcal{B}}\leftarrow\frac{1}{m}\sum_{i=1}^mx_i\tag{6-15}&#xA;$$&lt;p&gt;&#xA;②在小批量数据样本上根据式(6-16)计算第$k$个神经元输出结果的方差&#xA;&lt;/p&gt;&#xA;$$&#xA;\sigma^2_{\mathcal{B}}\leftarrow\frac{1}{m}\sum_{i=1}^m(x_i-\mu_{\mathcal{B}})^2\tag{6-16}&#xA;$$&lt;p&gt;&#xA;③根据式(6-17)以及$\mu_{\mathcal{B}}$和$\sigma^2_{\mathcal{B}}$对$x_i$进行标准化&#xA;&lt;/p&gt;&#xA;$$&#xA;\hat{x}_i\leftarrow\frac{x_i-\mu_{\mathcal{B}}}{\sqrt{\sigma^2_{\mathcal{B}}+\epsilon}}\tag{6-17}&#xA;$$&lt;p&gt;&#xA;④根据式(6-18)对$\hat{x}_i$进行缩放和平移&#xA;&lt;/p&gt;&#xA;$$&#xA;y_i\leftarrow \gamma\hat{x}_{i}+\beta\equiv &#xA;\text{BN}_{\gamma,\beta}(x_i)\tag{6-18}&#xA;$$&lt;p&gt;&#xA;其中$\mu_{\mathcal{B}}$为在小批量样本$\mathcal{B}$上对$x_i$期望的估计，$\sigma^2_{\mathcal{B}}$为对$x_i$方差的估计，而$\hat{x}_i$则表示标准化后的结果，$y_i$表示线性变换后的结果，也就是最后真正需要的结果。同时，为了防止方差为0的情况在进行标准化时分母额外的加了一个很小的常数$\epsilon$。这里需要说明的是，$\mu_{\mathcal{B}}$和$\sigma^2_{\mathcal{B}}$并不是整个数据集真实的期望与方差，而仅仅只是根据采样的小批量样本估计得到。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;3. 预测时的归一化&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;根据上面内容的介绍，我们已经清楚了批归一化在网络训练时的详细计算过程，同时根据式(6-15)~式(6-18)可知，批归一化中一共有5个参数，$\mu_{\mathcal{B}},\sigma^2_{\mathcal{B}},\epsilon,\gamma$和$\beta$。在这5个参数中，模型在训练阶段里前两个参数是在小批量样本中估计得到，第3个参数则是预先设定的常数（例如1e-5)，后面两个参数是随机初始化后随着网络一起训练得到。所以，现在的问题便是当模型在预测阶段时$\mu_{\mathcal{B}},\sigma^2_{\mathcal{B}}$应该如何得到？&lt;/p&gt;&#xA;&lt;p&gt;为了保证模型在整个测试阶段所使用到的均值$\mu_{\mathcal{B}}$和方差$\sigma^2_{\mathcal{B}}$都相同，一种常见的做法便是在训练过程中采用移动平均策略来估计整个训练集的均值和方差并用于测试阶段中，具体的计算方式为&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;        \text{moving\_mean} &amp;= \text{momentum} \times \text{moving\_mean} + (1.0 - \text{momentum}) \times \text{mean}\\&#xA;        \text{moving\_var} &amp;= \text{momentum} \times \text{moving\_var} + (1.0 - \text{momentum}) \times \text{var}&#xA;\end{aligned}\tag{6-19}&#xA;$$&lt;p&gt;其中$\text{mean}$和$\text{var}$是指在每个小批量样本上通过式(6-15)和式(6-16)估计而来，并且通过调节系数$\text{momentum}$可以控制$\text{moving\_mean}$和$\text{moving\_var}$到底是更接近于真实的值还是训练时每个小批量上的估计值。&lt;/p&gt;</description>
			</item>
			<item>
				<title>6.4 层归一化</title>
				<link>https://mlwithme.github.io/dl/chapter06/fdd5ba4b41f74a0e/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter06/fdd5ba4b41f74a0e/</guid>
				<description>&lt;p&gt;推：在循环神经网络中由于每个样本的序列长度并不相同，如果使用批归一化进行标准化那么当模型推理时只要出现样本序列长度大于训练时最长的样本序列长度时，那么归一化过程将无法进行，因为此时需要对每个时间片的输出结果进行标准化并输入到下一个时刻中。&lt;/p&gt;&#xA;&lt;h1 id=&#34;64-层归一化&#34;&gt;6.4 层归一化&lt;a class=&#34;anchor&#34; href=&#34;#64-%e5%b1%82%e5%bd%92%e4%b8%80%e5%8c%96&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在上一节内容中，我们详细介绍了批归一化的动机原理及实现过程，总体来讲批归一化的核心思想是以一个小批量数据样本为单位在对应维度上进行标准化。但也正是由于这一特性使得批量归一化会受到小批量样本数量的影响，同时，显而易见批归一化也不能直接用于循环神经网络。在这样的背景下，层归一化（Layer Normalization）[1]便应运而生了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;641-层归一化动机&#34;&gt;6.4.1 层归一化动机&lt;a class=&#34;anchor&#34; href=&#34;#641-%e5%b1%82%e5%bd%92%e4%b8%80%e5%8c%96%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;根据&lt;a href=&#34;https://mlwithme.github.io/dl/chapter06/27ed3ed136e24092&#34;&gt;6.3节&lt;/a&gt;内容可知，批归一化需要先计算一个小批量数据中每个通道上所有样本特征图的均值和方差，然后再根据对应的公式进行标准化。可见，此时小批量样本的数量便会影响均值和方差的估计结果。同时，在循环神经网络中由于每个样本的序列长度并不相同，如果使用批归一化进行标准化那么当模型推理时只要出现样本序列长度大于训练时最长的样本序列长度时，那么归一化过程将无法进行，因为此时需要对每个时间片的输出结果进行标准化并输入到下一个时刻中。除此之外，对于训练数据来说其长度越长则对应的样本数量将会越少，如果仍旧使用批归一化这类跨样本的归一化方法那么极端情况下将会出现归一化失真的情况。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;300&#34; src=&#34;https://mlwithme.github.io/images/dl/23042404320.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 6-15. 文本序列批归一化示意图&lt;/center&gt;&#xA;&lt;p&gt;如图6-15所示为文本序列批归一化序列图，其$x$轴、$y$轴和$z$轴分别表示小批量样本数量、词向量维度和样本序列长度，即图6-15中有5个样本，从左到右其长度分别的5、2、4、3和6，且每个词的维度为4维。如果此时对于整个小批量样本同时在$z$轴这个维度上采用批归一化进行标准化，那么在对进行第3个词的位置进行标准化时第2个样本便不会参与，进一步在对第6个词的位置进行标准化时便只有第5个词参与，而这便会影响整个归一化结果。退一步来说，即便通过这样的方式进行标准化，那么当测试样本的长度大于6时，该位置便没有对应的批归一化模型参数。&lt;/p&gt;&#xA;&lt;p&gt;由于跨样本间进行标准化会受到上述因素的影响，因此层归一化提出了以每个样本为独立单位进行标准化的思想。具体地，对于普通的前馈神经网络来说，以每个样本当前层的所有神经元为整体进行标准化；对于卷积神经网络来说，以每个样本在当前层的所有特征通道为整体进行标准化；对于循环神经网络来说，则是以每个样本在当前时刻的输出向量为整体进行标准化，即图6-15中$y$˙轴所在的维度。&lt;/p&gt;&#xA;&lt;h2 id=&#34;642-层归一化原理&#34;&gt;6.4.2 层归一化原理&lt;a class=&#34;anchor&#34; href=&#34;#642-%e5%b1%82%e5%bd%92%e4%b8%80%e5%8c%96%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. 归一化原理&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;从归一化的计算过程来看，层归一化同批归一化的计算公式类似，即式(6-15)~式(6-18)所示先计算均值和方差，然后进行标准化，最后再进行缩放和平移，唯一的差别在于两者选择归一化的维度不同，但也有研究表明缩放和平移操作反而会对于层归一化有害 [3]。如图6-16所示便是两者在对卷积特征进行归一化时维度选择的差异之处。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;600&#34; src=&#34;https://mlwithme.github.io/images/dl/240421120103.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 6-16. 批归一化和层归一化对比度图&lt;/center&gt;&#xA;&lt;p&gt;如图6-16所示，左右两边为分别是批归一化和层归一化的归一化维度示意图，其一共包含有2个样本和3个特征通道。从图6-16(a)可以看出，批归一化在进行标准化时是将所有小批量样本看成的一个整体，并逐一对每个通道进行标准化，且每个通道有各自独立的均值$\mu_i$、方差$\sigma^2_i$和权重参数$\gamma_i,\beta_i$（4个值均为标量）；对于图6-16(b)中的层归一化来说，它在进行标准化时是将每个样本看做一个整体，并同时对所有通道进行标准化，且每个样本均有各自独立的均值$\mu_i$和方差$\sigma^2_i$（2个值均为标量）但共享权重参数$\gamma,\beta$（2个值均为向量，维度为$p\times q\times c$，分别表示特征图的长、宽和通道数）。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2. CNN中的归一化&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;下面仍旧以&lt;a href=&#34;https://mlwithme.github.io/dl/chapter06/27ed3ed136e24092&#34;&gt;6.3.2节&lt;/a&gt;中特征图用层归一化的方式来进行计算示例。如图6-17所示左右两边分别为一个样本，且均有3个特征通道，则层归一化在进行标准化时以每个样本（图中虚线框部分）为单位进行处理，同时可知$\gamma$和$\beta$的维度均为75，即将3个通道拉伸后的总维度。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;300&#34; src=&#34;https://mlwithme.github.io/images/dl/23042597620.jpg&#34;/&gt;&lt;/div&gt;&lt;center&gt;图 6-17. CNN中层归一化计算示例图&lt;/center&gt;&#xA;&lt;p&gt;根据图6-17可知，则此时对于左右两个样本来说其均值和方差分别为&#xA;&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;\mu_1=&amp;\frac{1}{75}(0+2+0+1+0+,...,+0+1+0+0+0)\approx0.4933\\[2ex]&#xA;\sigma^2_1=&amp;\frac{1}{75}((0-0.4933)^2+(2-0.4933)^2+,...,+(0-0.4933)^2)\approx0.3566\\[2ex]&#xA;\mu_2=&amp;\frac{1}{75}(1+2+1+1+1+,...,+0+1+1+0+0)=\approx0.7733\\[2ex]&#xA;\sigma^2_2=&amp;\frac{1}{75}((1-0.7733)^2+(2-0.7733)^2+,...,+(0-0.7733)^2)\approx0.5486\\[2ex]&#xA;\end{aligned}&#xA;\tag{6-23}&#xA;$$&lt;p&gt;&#xA;进一步根据式(6-17)，此时假定$\epsilon=0$，则此时对于左侧的样本点有&#xA;&lt;/p&gt;&#xA;$$&#xA;\frac{0-0.4933}{\sqrt{0.3566+0}}\approx-0.8261,\;\;\;\;\frac{2-0.4933}{\sqrt{0.3566+0}}\approx2.5229,\;\;\;\;\frac{1-0.4933}{\sqrt{0.3566+0}}\approx0.8484\tag{6-24}&#xA;$$&lt;p&gt;对于右侧的样本点有&#xA;&lt;/p&gt;&#xA;$$&#xA;\frac{1-0.7733}{\sqrt{0.5486+0}}\approx0.3060,\;\;\;\;\frac{2-0.7733}{\sqrt{0.5486+0}}\approx1.6561,\;\;\;\;\frac{3-0.7733}{\sqrt{0.5486+0}}\approx3.0062\tag{6-25}&#xA;$$&lt;p&gt;&#xA;根据式(6-18)，此时假定$\gamma=[1,1,...,1]_{1\times75},\beta=[0,0,...,0]_{1\times75}$，则有&#xA;&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;-0.8261\times1+0&amp;=-0.8261\\[1ex]&#xA;2.5229\times1+0&amp;=2.5229\\[1ex]&#xA;0.8484\times1+0&amp;=0.8484\\[2ex]&#xA;0.3060\times1+0&amp;=0.3060\\[1ex]&#xA;1.6561\times1+0&amp;=1.6561\\[1ex]&#xA;3.0062\times1+0&amp;=3.0062\\[1ex]&#xA;\end{aligned}\tag{6-26}&#xA;$$&lt;p&gt;&#xA;这里需要再次提醒的是，所有样本在进行平移和缩放时共享参数$\gamma$和$\beta$。&lt;/p&gt;&#xA;&lt;p&gt;最后，图6-17中每个样本最后一个通道层归一化后的结果（可以同图6-13的结果进行对比）为&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; [[ &lt;span style=&#34;color:#40a070&#34;&gt;0.8484&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.8484&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.8261&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.8261&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.8261&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;  [&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.8261&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.8484&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.8261&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.8261&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.8484&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;  [&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.8261&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.8484&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.8484&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.8484&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.8484&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;  [&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.8261&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.8484&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.8261&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.8261&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.8261&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;  [&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.8261&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.8484&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.8261&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.8261&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0.8261&lt;/span&gt;]]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt; [[&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1.0441&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.3060&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.3060&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1.0441&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1.0441&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;8&lt;/span&gt;  [&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1.0441&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.3060&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1.0441&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;1.6561&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.3060&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;9&lt;/span&gt;  [ &lt;span style=&#34;color:#40a070&#34;&gt;0.3060&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;1.6561&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.3060&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.3060&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1.0441&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;10&lt;/span&gt;  [ &lt;span style=&#34;color:#40a070&#34;&gt;0.3060&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.3060&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1.0441&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1.0441&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1.0441&lt;/span&gt;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;11&lt;/span&gt;  [&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1.0441&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.3060&lt;/span&gt;,  &lt;span style=&#34;color:#40a070&#34;&gt;0.3060&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1.0441&lt;/span&gt;, &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1.0441&lt;/span&gt;]]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上述完整计算示例代码可参见&lt;code&gt;Code/Chapter06/C04_LN/ln_compute.py&lt;/code&gt;文件。&lt;/p&gt;</description>
			</item>
			<item>
				<title>6.5 组归一化</title>
				<link>https://mlwithme.github.io/dl/chapter06/9246afed14eb436c/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter06/9246afed14eb436c/</guid>
				<description>&lt;h1 id=&#34;65-组归一化&#34;&gt;6.5 组归一化&lt;a class=&#34;anchor&#34; href=&#34;#65-%e7%bb%84%e5%bd%92%e4%b8%80%e5%8c%96&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在前面两节内容中我们分别介绍了批归一化和层归一化这两种归一化算法所提出的动机和原理，其中层归一化提出的原因之一便是为了解决批归一化不能直接用于循环神经网络的弊端。然而，由于批归一化在计算过程中会受到小批量样本数量的影响，因此在大规模数据集中当小批量样本数量急剧减少时将会使得模型的效果显著下降。在样的背景下，组归一化（Group Normalization）[1]便应运而生了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;651-组归一化动机&#34;&gt;6.5.1 组归一化动机&lt;a class=&#34;anchor&#34; href=&#34;#651-%e7%bb%84%e5%bd%92%e4%b8%80%e5%8c%96%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在卷积神经网络中，由于批归一化的提出使得模型的效果和收敛速度有了大幅地提升。根据式(6-15)和式(6-16)可知，批归一化在估计均值和方差时均会受到样本数量即批大小的影响，总体上样本数量越多则估计得到的均值和方差越接近于其真实值。然而，在一些大型数据集的图像处理任务中，如基于微软上下文通用对象（Microsoft Common Objects in Context, MS COCO）数据集[2]的目标检测、语义分割任务等，受限于计算机硬件存储的限制模型并不能够使用较大数量的小批量样本。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;330&#34; src=&#34;https://mlwithme.github.io/images/dl/231008145754.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 6-19 小批量大小随错误率变化图[1]&lt;/center&gt;&#xA;&lt;p&gt;如图6-19所示，两条这先分别是基于批归一化和组归一化的ResNet50模型在ImageNet数据集上小批量大小随分类误差率的变化曲线。从图中可以明显看出，随着小批量中样本数量减少，基于批归一化的ResNet50在分类错误率上有了显著地增加，而基于组归一化的ResNet50错误率则相对稳定。当小批量样本减少至2时，两者的误差率扩大到了10个百分点。&lt;/p&gt;&#xA;&lt;h2 id=&#34;652-组归一化原理&#34;&gt;6.5.2 组归一化原理&lt;a class=&#34;anchor&#34; href=&#34;#652-%e7%bb%84%e5%bd%92%e4%b8%80%e5%8c%96%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;从归一化的计算过程来看，组归一化与&lt;a href=&#34;https://mlwithme.github.io/dl/chapter06/fdd5ba4b41f74a0e&#34;&gt;6.4节&lt;/a&gt;内容中层归一化的计算过程类似，即根据式(6-15)~式(6-18)所示先计算均值和方差，然后进行标准化，最后再进行缩放和平移，两者唯一的区别在于层归一化是同时对一个样本中的所有通道进行标准，而组归一化则是先将通道分成多个组在进行归一化，如图6-20所示便是两者在对卷积特征进行归一化时的差异之处。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;580&#34; src=&#34;https://mlwithme.github.io/images/dl/240421120002.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 6-20 层归一化与组归一化对比图&lt;/center&gt;&#xA;&lt;p&gt;如图6-20所示，左右两边为分别是层归一化和组归一化的计算示意图，其一共包含有2个样本和4个特征通道。从图6-20(a)可以看出，层归一化在进行标准化时是将每个样本看做一个整体，并同时对所有通道进行标准化；对于图6-20(b)中的组归一化来说，它同样是将每个样本看做一个整体，但是需要将特征通道划分成若干组（此处为2组），然后在每一组特征中以层归一化的方式进行。因此，在组归一化中如果分组数量为1时那么便等价于层归一化操作。此时需要注意的是，在组归一化中每个样本特征通道分组内均有各自独立的均值$\mu_i$和方差$\sigma^2_i$（2个值均为标量），但共享权重参数$\gamma,\beta$（2个值均为向量，维度为$c$，即通道数）。&lt;/p&gt;&#xA;&lt;p&gt;同时，由于组归一化是以每个样本为整体估算均值和方差对各维度进行标准化，因此组归一化并不需要区分当前是测试状态还是训练状态，其计算过程同训练时保持一致不再赘述。&lt;/p&gt;&#xA;&lt;h2 id=&#34;653-组归一化实现&#34;&gt;6.5.3 组归一化实现&lt;a class=&#34;anchor&#34; href=&#34;#653-%e7%bb%84%e5%bd%92%e4%b8%80%e5%8c%96%e5%ae%9e%e7%8e%b0&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在介绍完整个组归一化操作的原理后，我们再来看如何通过PyTorch进行实现。以下完整示例代码可以参见&lt;code&gt;Code/Chapter06/C05_GN/group_normalization.py&lt;/code&gt;文件。&lt;/p&gt;&#xA;&lt;p&gt;根据第6.5.2节内容的介绍可知，首先需要定义整个组归一化中的相关参数及维度信息，示例代码如下所示：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#0e84b5;font-weight:bold&#34;&gt;GroupNormalization&lt;/span&gt;(nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Module):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;__init__&lt;/span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;,num_groups,num_channels,eps&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1e-5&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;         &lt;span style=&#34;color:#007020&#34;&gt;super&lt;/span&gt;(GroupNormalization, &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;)&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#06287e&#34;&gt;__init__&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; num_channels &lt;span style=&#34;color:#666&#34;&gt;%&lt;/span&gt; num_groups &lt;span style=&#34;color:#666&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;             &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;raise&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;ValueError&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;num_channels must be divisible by num_groups&amp;#39;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;         &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;num_groups &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; num_groups&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt;         &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;num_channels &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; num_channels&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;8&lt;/span&gt;         &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;eps &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; eps&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;9&lt;/span&gt;         &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;gamma &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Parameter(torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;ones([&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, num_channels, &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;]))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;10&lt;/span&gt;         &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;beta &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; nn&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;Parameter(torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;zeros([&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, num_channels, &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;]))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第2行&lt;code&gt;num_groups&lt;/code&gt;表示分组的数量，&lt;code&gt;num_channels&lt;/code&gt;表示特征通道数。第4~5行用于判断分组数能否被特征通道数整除。第9~10行是初始化两个权重参数，分别全为1和0的两个向量。&lt;/p&gt;&#xA;&lt;p&gt;在完成上述初始化工作后便可以进一步实现组归一化的整个前向传播过程，示例代码如下所示：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;forward&lt;/span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;, X):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;         w, h &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; X&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;shape[&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;:]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;         X &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; X&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;reshape([&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;num_groups, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;                       &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;num_channels &lt;span style=&#34;color:#666&#34;&gt;//&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;num_groups, w, h])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;         mean &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;mean(X, dim&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;[&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;], keepdim&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;True&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;         var &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;mean((X &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt; mean) &lt;span style=&#34;color:#666&#34;&gt;**&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;, dim&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;[&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;], keepdim&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;True&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt;         X_hat &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; (X &lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt; mean) &lt;span style=&#34;color:#666&#34;&gt;/&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;sqrt(var &lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;eps)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;8&lt;/span&gt;         X_hat &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; X_hat&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;reshape(&lt;span style=&#34;color:#666&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;num_channels, w, h)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;9&lt;/span&gt;         Y &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;gamma &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt; X_hat &lt;span style=&#34;color:#666&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;beta&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;10&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; Y&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第2行是取输入特征的长和宽。第3~4行是对特征图在通道上进行分组处理，此时&lt;code&gt;X&lt;/code&gt;的形状为&lt;code&gt;[batch_size, num_groups, num_channels//num_groups, w, h]&lt;/code&gt;。第5~6行是分别计算每个样本各组中的特征图的均值和方差。第7行是计算组归一化标准化的结果。第8行是将标准化后的结果在形状上进行还原。第9行则是对标准化后的结果进行平移与缩放。&lt;/p&gt;</description>
			</item>
			<item>
				<title>6.6 动量法</title>
				<link>https://mlwithme.github.io/dl/chapter06/fcbc66ad051a4336/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter06/fcbc66ad051a4336/</guid>
				<description>&lt;h1 id=&#34;66-动量法&#34;&gt;6.6 动量法&lt;a class=&#34;anchor&#34; href=&#34;#66-%e5%8a%a8%e9%87%8f%e6%b3%95&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter03/97e1da1143cd4554&#34;&gt;3.3节&lt;/a&gt;内容中，我们详细介绍了如何通过梯度下降算法来最小化目标函数并以此求解得到模型对应的权重参数。进一步，我们在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter03/55967b0f642b4509&#34;&gt;3.6节&lt;/a&gt;内容中还介绍了什么是随机梯度下降算法和小批量梯度下降算法。在本节内容中我们将会介绍另外一种基于梯度下降改进的动量法（Momentum ）[1]。&lt;/p&gt;&#xA;&lt;h2 id=&#34;661-动量法动机&#34;&gt;6.6.1 动量法动机&lt;a class=&#34;anchor&#34; href=&#34;#661-%e5%8a%a8%e9%87%8f%e6%b3%95%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在使用基于小批量样本的梯度下降算法最小化模型的过程中，我们可以通过调整学习率的大小来加快模型的收敛速速，但是通常情况下我们很难找到一个合适的学习率。过小会使得模型收敛速度慢，而过大则会可能使得目标函数发散，如图6-21所示。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;440&#34; src=&#34;https://mlwithme.github.io/images/dl/231009202727.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 6-21 不同学习率收敛情况图&lt;/center&gt;&#xA;&lt;p&gt;在图6-21中对于该目标函数来说，当学习率设置为0.45时（左）目标函数大约在20次迭代后收敛；当学习率增大至0.55时（右）目标函数则在大约10次迭代便进入了发散状态。同时可以看出，在这两种情况下目标函数在$w_2$上的偏移量都要远大于在$w_1$上的偏移量，这是因为该目标函数在竖直方向上的斜率要远大于水平方向上的斜率。正是因为这些原因使得目标函数在优化过程中梯度来回震荡，导致模型难以收敛或发散。一种有效的做法便是权重参数在当前位置计算梯度时，同时也考虑到在上一次位置时的梯度，而这也被称之为动量法。&lt;/p&gt;&#xA;&lt;h2 id=&#34;662-动量法原理&#34;&gt;6.6.2 动量法原理&lt;a class=&#34;anchor&#34; href=&#34;#662-%e5%8a%a8%e9%87%8f%e6%b3%95%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;动量法是梯度下降算法的一种改进，它引入了动量的概念以加速目标函数收敛过程并减小震荡。动量法的基本思想是在更新参数的过程中，不仅考虑当前的梯度方向，同时也考虑历史累积的梯度信息。具体地，设目标函数在第$t$时刻关于所有权重参数的梯度为$g_t$，速度变量为$v_t$且$v_0=0$，权重参数为$\theta_t$，则第$t+1$时刻结果过$\theta_{t+1}$可通过如下过程计算&#xA;&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;v_{t+1} &amp; = \mu * v_{t} + g_{t+1}, \\[1ex]&#xA;\theta_{t+1} &amp; = \theta_{t} - \gamma * v_{t+1},&#xA;\end{aligned}\tag{6-29}&#xA;$$&lt;p&gt;&#xA;其中$\mu$表示动量系数，$\gamma$表示学习率。为了方便各位读者阅读内容时能够同实践相结合，因此本节及后续几节内容中相关计算公式的符号标记均遵循了PyTorch框架中相应接口描述文档中类似的标记方式。&lt;/p&gt;&#xA;&lt;p&gt;从式(6-29)可以看出，在通过梯度下降算法计算第$t+1$时刻的结果时所依赖的速度$v_{t+1}$便同时考虑了第$t$时刻的速度$v_t$，并通过超参数$\mu$来控制依赖程度，这与&lt;a href=&#34;https://mlwithme.github.io/dl/chapter06/27ed3ed136e24092&#34;&gt;6.3节&lt;/a&gt;内容中式(6-19)通过移动平均来计算均值和方差类似。此时可以看出，当$\mu=0$时式(6-29)便等价于原始的梯度下降算法。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;450&#34; src=&#34;https://mlwithme.github.io/images/dl/231010192445.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 6-22 不同学习率和动量系数收敛情况图&lt;/center&gt;&#xA;&lt;p&gt;&lt;subscribe&gt;55&lt;/subscribe&gt;&lt;/p&gt;&#xA;&lt;br&gt;&#xA;&lt;br&gt;&#xA;&lt;br&gt;</description>
			</item>
			<item>
				<title>6.7 AdaGrad算法</title>
				<link>https://mlwithme.github.io/dl/chapter06/8b83d654898c40a2/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter06/8b83d654898c40a2/</guid>
				<description>&lt;h1 id=&#34;67-adagrad算法&#34;&gt;6.7 AdaGrad算法&lt;a class=&#34;anchor&#34; href=&#34;#67-adagrad%e7%ae%97%e6%b3%95&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter06/fcbc66ad051a4336&#34;&gt;6.6节&lt;/a&gt;内容中，我们介绍了基于动量的梯度下降算法， 其核心思想是目标函数在优化过程中对当前位置梯度进行计算也也应该考虑上一次所处位置时的梯度，以此来提高模型的收敛速度。在本节内容中我们将介绍另外一种从每个特征维度的角度来考虑参数梯度的优化算法。&lt;/p&gt;&#xA;&lt;h2 id=&#34;671-adagrad动机&#34;&gt;6.7.1 AdaGrad动机&lt;a class=&#34;anchor&#34; href=&#34;#671-adagrad%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在机器学习算法中有一种常见的文本向量化表示方法——词频逆文档频率（Term FrequenceInverse Document Frequence, TF-IDF），它最重要的一点便是引入了逆文档频率这一概念。在仅以词频作为特征的表示方法中一个词出现的频率越高往往会被认为该维度的重要性越高，然而在不少情况下频繁出现的词并不具有较高的重要性，例如一些代词或者虚词等。因此，TF-IDF在此基础上通过逆文档频率来修正这一问题，即一个词总的出现次数除以包含有该词的文档数。可以发现，如果一个词出现频繁但是在每个文档中该词具有出现，那么它对应的逆文档频率便很小，最后作用于词频得到的特征值也会相应变小。&lt;/p&gt;&#xA;&lt;p&gt;进一步，杜奇（Duchi）[1]等人认为在深度学习中当输入样本的特征维度较高且较为稀疏时，在目标函数优化中频繁出现的特征维度（本质上是该维度对应的权重参数）其对应的学习率应该较小；相反，极少出现的特征维度其对应的的学习率应该相对较大，以此来提高模型对于这部分参数的学习效率。因此，要达到上述目的办法就是在目标函数优化过程中为每个权重参数赋予一个自适应的学习率。基于这样的动机，Duchi J等人提出了一种自适应学习率的梯度下降算法（Adaptive Gradent, AdaGrad），其核心思想便是根据每个参数截止当前时刻梯度的累积情况来自适应计算下一时刻梯度的大小。&lt;/p&gt;&#xA;&lt;h2 id=&#34;672-adagrad原理&#34;&gt;6.7.2 AdaGrad原理&lt;a class=&#34;anchor&#34; href=&#34;#672-adagrad%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;AdaGrad算法可以根据参数历史梯度的平方累积来动态调整学习率，使得对于不同参数的更新可以有不同的尺度，从而更有效地进行参数优化。具体地，设目标函数在第$t$时刻关于所有权重参数的梯度为$g_t$，累积梯度为$a_t$且$a_0=0$，权重参数为$\theta_t$，则第$t+1$时刻的结果$\theta_{t+1}$可通过如下公式计算&#xA;&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;a_{t+1}&amp;=a_t+g_{t+1}\odot g_{t+1}\\[1ex]&#xA;\theta_{t+1}&amp;=\theta_t-\frac{\gamma}{\sqrt{a_{t+1}+\epsilon}}g_{t+1}&#xA;\end{aligned}\tag{6-30}&#xA;$$&lt;p&gt;其中$\odot$表示按位乘，$\gamma$为学习率，$\epsilon$为平滑项防止分母为0时溢出。&lt;/p&gt;&#xA;&lt;p&gt;根据式(6-30)可以看出，由于AdaGrad累积了每个参数历史梯度值的平方，这将使得对于特征维度中频繁出现的特征对应的参数梯度以更快的速度进行累积，最终该参数对应的学习率则会逐渐减小；相反，对于不经常出现的特征维度其对应参数的学习率则会相对较大。这样，AdaGrad算法便能够更加灵活地适应不同参数的更新尺度。然而，AdaGrad算法也有一些缺点，例如模型在长时间训练中梯度的累积可能会变得过大，导致学习率一直降低（或不变），最终可能较难找到一个有用的解[2]。为了解决这个问题，后续也出现了一些基于AdaGrad的改进算法，如后续我们将要介绍的AdaDelta、RMSprop和 Adam算法。&lt;/p&gt;&#xA;&lt;h2 id=&#34;673-使用示例&#34;&gt;6.7.3 使用示例&lt;a class=&#34;anchor&#34; href=&#34;#673-%e4%bd%bf%e7%94%a8%e7%a4%ba%e4%be%8b&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在介绍完AdaGrad算法的基本原理以后，我们再来看如何使用这一优化算法。在PyTorch框架中，我们可以通过&lt;code&gt;torch.optim.Adagrad()&lt;/code&gt; 模块来使用自适应学习率的梯度下降算法。下面对其中的几个关键参数进行介绍。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#0e84b5;font-weight:bold&#34;&gt;Adagrad&lt;/span&gt;(Optimizer):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;__init__&lt;/span&gt;(&lt;span style=&#34;color:#007020&#34;&gt;self&lt;/span&gt;, params, lr&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1e-2&lt;/span&gt;, lr_decay&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;         weight_decay&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;, initial_accumulator_value&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;, eps&lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;1e-10&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;pass&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第2行&lt;code&gt;params&lt;/code&gt;表示指定模型的权重参数；&lt;code&gt;lr&lt;/code&gt;表示指定学习率；&lt;code&gt;lr_decay&lt;/code&gt;学习率衰减系数，即式(6-30)每次在执行梯度下降之前学习率先衰减为$\gamma / (1 +(t-1) \eta)$，其中$\eta$便为学习率衰减系数，默认情况下$\eta=0$。第3行&lt;code&gt;initial_accumulator_value&lt;/code&gt;为梯度累积项的初始值，即$a_0$；&lt;code&gt;eps&lt;/code&gt;为平滑项系数。&lt;/p&gt;&#xA;&lt;p&gt;最后，我们只需要在模型训练时指定优化器为&lt;code&gt;Adagrad&lt;/code&gt;便可使用基于学习率自适应的梯度下降算法来最小化目标函数。&lt;/p&gt;&#xA;&lt;h2 id=&#34;674-小结&#34;&gt;6.7.4 小结&lt;a class=&#34;anchor&#34; href=&#34;#674-%e5%b0%8f%e7%bb%93&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在本节内容中，我们首先介绍了AdaGrad算法出现的动机，即使得目标函数在优化过程中能够以自适应的方式来为每个权重参数计算得到一个学习率，以不同的尺度来对权重参数进行学习更新；然后介绍了AdaGrad算法的基本原理以及它所存在的弊端；最后介绍了如何在PyTorch中使用基于学习率自适应的梯度下降算法。在下一节内容中，我们将继续介绍基于梯度下降算法改进的优化算法AdaDelta。&lt;/p&gt;&#xA;&lt;h1 id=&#34;引用&#34;&gt;引用&lt;a class=&#34;anchor&#34; href=&#34;#%e5%bc%95%e7%94%a8&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;[1] Duchi J, Hazan E, Singer Y. Adaptive subgradient methods for online learning and stochastic optimization[J]. Journal of machine learning research, 2011, 12(7).&lt;/p&gt;</description>
			</item>
			<item>
				<title>6.8 AdaDelta算法</title>
				<link>https://mlwithme.github.io/dl/chapter06/078f2394980d41d2/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter06/078f2394980d41d2/</guid>
				<description>&lt;h1 id=&#34;68-adadelta算法&#34;&gt;6.8 AdaDelta算法&lt;a class=&#34;anchor&#34; href=&#34;#68-adadelta%e7%ae%97%e6%b3%95&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在&lt;a href=&#34;https://mlwithme.github.io/dl/chapter06/8b83d654898c40a2&#34;&gt;6.7节&lt;/a&gt;内容中我们介绍了一种自适应各个维度梯度的优化算法AdaGrad，其核心思想是根据每个参数历史梯度的累积情况来自适应计算下一时刻各个参数的梯度值。在本节内容中我们将介绍另外一种基于AdaGrad算法改进的，同样也是自适应各维度梯度的模型优化算法AdaDelta，并且值得一提的是在AdaDelta[1]算法中我们并不需要指定一个全局的学习率。&lt;/p&gt;&#xA;&lt;h2 id=&#34;681-adadelta动机&#34;&gt;6.8.1 AdaDelta动机&lt;a class=&#34;anchor&#34; href=&#34;#681-adadelta%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;尽管AdaGrad算法能够自适应地为目标函数中的每个权重参数计算得到一个梯度值，但它最大的弊端在于当优化迭代过程太久时梯度的累积值将会变得过大，导致学习率持续降低最终可能使得目标函数无法收敛。同时，在已经介绍过的几种优化算法中我们都需要通过手动设定一个全局学习率来辅助控制梯度的大小，但过大的学习率往往容易使得迭代过程震荡，而过小的学习率则容易陷入局部最优解。因此理想状况下应该是较大梯度的参数对应使用较小的学习率，而较小梯度的参数应该使用较大的学习率。&lt;/p&gt;&#xA;&lt;p&gt;基于这样的动机，塞勒（Zeiler）等人[1]提出了另外一种自适应学习率的优化算法AdaDelta，其核心思想便是以梯度平方的移动平均来解决AdaGrad中历史梯度累积过大的问题，并同时提出通过历史梯度信息的比值来自适应学习率的做法，使得不同权重参数在更新过程中能够以合适尺度的梯度进行。也正是如此，我们在使用AdaDelta对目标函数进行优化时并不需要指定一个全局学习率。&lt;/p&gt;&#xA;&lt;h2 id=&#34;682-adadelta原理&#34;&gt;6.8.2 AdaDelta原理&lt;a class=&#34;anchor&#34; href=&#34;#682-adadelta%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;AdaDelta算法的原理主要是基于对学习率的自适应调整，解决了一些传统优化算法中学习率难以选取的问题。具体地，设目标函数在第$t$时刻关于所有权重参数的梯度为$g_t$，累积梯度为$v_t$且$v_0=0$，更新梯度为$u_t$且$u_0=0$，移动平均衰减系数为$\rho$，权重参数为$\theta_t$，则第$t+1$时刻的结果$\theta_{t+1}$可通过如下公式计算&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;v_{t+1}&amp;=\rho v_{t}+(1-\rho)g_{t+1}\odot g_{t+1}\\[1ex]&#xA;\Delta x_{t+1}&amp;=\frac{\sqrt{u_{t}+\epsilon}}{\sqrt{v_{t+1}+\epsilon}}g_{t+1}\\[1ex]&#xA;u_{t+1}&amp;=\rho u_{t}+(1-\rho)\Delta x_{t+1}\odot \Delta x_{t+1}\\[1ex]&#xA;\theta_{t+1}&amp;=\theta_t-\gamma\Delta_{t+1}&#xA;\end{aligned}\tag{6-31}&#xA;$$&lt;p&gt;其中$\odot$表示按位乘，$\gamma$为学习率是PyTorch中的一个可选参数，当$\gamma=1$时即不考虑指定学习率，$\epsilon$为平滑项。&lt;/p&gt;&#xA;&lt;p&gt;从式(6-31)累积梯度$v_t$的计算过程可知，由于采用了移动平均衰减策略所以只会累积最近时刻的梯度信息，进而避免了AdaGrad算法中累积梯度过大的问题。同时还可以发现，$\rho$越小则表示累积的梯度信息越少，当$\rho=0$时则表示不对历史梯度进行累积。进一步，更新梯度$u_t$同样也是根据移动平均衰减策略计算得到，它累积的是每个时刻实际用于梯度下降算法中的参数梯度。根据$\Delta x_{t}$的计算过程可知，当$t+1$时刻的梯度$g_{t+1}$变大时分母也会变大使得$\Delta x_{t}$整体变小，而当$t+1$时刻的梯度$g_{t+1}$变小时分母也会相应变小使得$\Delta x_{t}$整体变大。这就使得在训练过程中，对于梯度较大的参数学习率将相对减小，对于梯度较小的参数学习率将相对增大，从而平衡了不同参数的调整幅度。&lt;/p&gt;&#xA;&lt;p&gt;除此以外，蒂勒曼（Tieleman）等人[2]同样也提出了一种类似但更为简单的学习率自适应优化算法RMSprop，并同时也采用了移动平均策略来解决AdaGrad算法中学习率衰减过快的问题。具体地，其计算过程如下所示&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;v_{t+1}&amp;=\rho v_{t}+(1-\rho)g_{t+1}\odot g_{t+1}\\[1ex]&#xA;\theta_{t+1}&amp;=\theta_t-\frac{\gamma}{\sqrt{v_{t+1}+\epsilon}}g_{t+1}&#xA;\end{aligned}\tag{6-32}&#xA;$$&lt;p&gt;其中$\gamma$为学习率，也是一个可选参数。&lt;/p&gt;&#xA;&lt;p&gt;&lt;subscribe&gt;56&lt;/subscribe&gt;&lt;/p&gt;&#xA;&lt;br&gt;&#xA;&lt;br&gt;&#xA;&lt;br&gt;</description>
			</item>
			<item>
				<title>6.9 Adam算法</title>
				<link>https://mlwithme.github.io/dl/chapter06/28ad7fb39987447e/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter06/28ad7fb39987447e/</guid>
				<description>&lt;h1 id=&#34;69-adam算法&#34;&gt;6.9 Adam算法&lt;a class=&#34;anchor&#34; href=&#34;#69-adam%e7%ae%97%e6%b3%95&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在前面几节内容中我们陆续介绍了动量法、AdaGrad和AdaDelta等优化算法。除了动量法以外，其它几种算法都能够分别为每个权重参数自适应计算得到一个学习率，以此来实现对不同的权重参数以不同的尺度进行更新。在本节内容中我们将介绍最后一种通过利用一阶矩和二阶矩信息来自适应各权重参数学习率的优化算法。&lt;/p&gt;&#xA;&lt;h2 id=&#34;691-adam动机&#34;&gt;6.9.1 Adam动机&lt;a class=&#34;anchor&#34; href=&#34;#691-adam%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;动量法在更新参数的过程中不仅会考虑当前梯度的方向同时也会考虑历史梯度的方向，以此来解决目标函数梯度来回震荡的问题；AdaGrad算法在更新参数的过程中通过考虑数据样本特征出现的频次来自适应不同的权重参数所对应的学习率，以此来提高目标函数的收敛速度；AdaDelta和RMSprop算法在更新参数的过程中通过梯度的移动平均来解决AdaGrad中学习率衰减过快的问题，并同时实现了无序手动指定全局学习率。&lt;/p&gt;&#xA;&lt;p&gt;结合AdaGrad算法和RMSprop算法各自的优点，金马（Kingma）[1]等人提出了一种新的学习率自适应算法自适应矩估计（Adaptive Moment Estimation, Adam）。Adam算法可以根据每个参数梯度的趋势性和稳定性在训练的不同阶段自适应调整学习率，使得Adam在处理非平稳（Non-Stationary）的目标函数时仍然能表现良好，同时在面对梯度稀疏的情况下Adam算法也能够有效地进行处理。&lt;/p&gt;&#xA;&lt;h2 id=&#34;692-adam原理&#34;&gt;6.9.2 Adam原理&lt;a class=&#34;anchor&#34; href=&#34;#692-adam%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Adam算法通过考虑梯度的一阶矩和二阶矩来动态调整学习率，使得它能够在不同参数和不同时间步上提供更为平滑和稳定的参数梯度，然后对权重参数进行学习更新。具体地，设目标函数在第$t$时刻关于所有权重参数的梯度为$g_t$，梯度的一阶矩为$m_t$且$m_0=0$，梯度的二阶矩为$v_t$且$v_0=0$，移动平均的衰减系数分别为$\beta_1\in[0,1)$和$\beta_2\in[0,1)$，权重参数为$\theta_t$，则第$t+1$时刻的结果$\theta_{t+1}$可通过如下步骤进行计算&#xA;&lt;/p&gt;&#xA;$$&#xA;\begin{aligned}&#xA;m_{t+1}&amp;=\beta_1m_t+(1-\beta_1)g_{t+1}\\[1ex]&#xA;v_{t+1}&amp;=\beta_2v_t+(1-\beta_2)g_{t+1}\odot g_{t+1}\\[1ex]&#xA;\hat{m}_{t+1}&amp;=\frac{m_{t+1}}{1-\beta_1^{t+1}}\\[1ex]&#xA;\hat{v}_{t+1}&amp;=\frac{v_{t+1}}{1-\beta_2^{t+1}}\\[1ex]&#xA;\theta_{t+1}&amp;=\theta_t-\frac{\gamma \hat{m}_{t+1}}{\sqrt{\hat{v}_{t+1}}+\epsilon}&#xA;\end{aligned}&#xA;\tag{6-33}&#xA;$$&lt;p&gt;其中$\odot$表示按位乘，$\gamma$为学习率，$\beta^t_i$中$t$表示幂次，$\epsilon$为平滑项。&lt;/p&gt;&#xA;&lt;p&gt;在式(6-33)中，Adam算法通过移动平均来分别估计第$t+1$时刻梯度的一阶矩$m_{t+1}$和二阶矩$v_{t+1}$即梯度的均值和近似方差。一阶矩估计可以更好的帮助算法适应目标函数梯度的整体趋势。二阶矩估计则可以用于捕捉梯度的方差或波动性，如果目标函数表面上存在平坦区域或高曲率区域时，则此时梯度的方差可能变化很大，将其作为分母便可以减小学习率以提高稳定性；相反则会增加算法的学习率以提高收敛速度。&lt;/p&gt;&#xA;&lt;p&gt;同时，由于在训练初期$m_0$和$v_0$的初始值均为0，所以一阶矩$m_t$和二阶矩$v_t$的估计可能偏离真实值。为了减小这种偏差，Adam算法引入了偏差校正，即校正后的结果分别为$\hat{m}_{t+1}$和$\hat{v}_{t+1}$。根据式(6-33)可以看出，随着迭代次数$t$的增加$\beta_i^t$将会逐渐趋于0，并且当$t$足够大之后矩估计值便近似等于校正值。&lt;/p&gt;&#xA;&lt;p&gt;&lt;subscribe&gt;52&lt;/subscribe&gt;&lt;/p&gt;&#xA;&lt;br&gt;&#xA;&lt;br&gt;&#xA;&lt;br&gt;</description>
			</item>
			<item>
				<title>6.10 初始化方法</title>
				<link>https://mlwithme.github.io/dl/chapter06/4b81b8d39721434d/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://mlwithme.github.io/dl/chapter06/4b81b8d39721434d/</guid>
				<description>&lt;h1 id=&#34;610-初始化方法&#34;&gt;6.10 初始化方法&lt;a class=&#34;anchor&#34; href=&#34;#610-%e5%88%9d%e5%a7%8b%e5%8c%96%e6%96%b9%e6%b3%95&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;p&gt;在前面几节内容中我们陆续介绍了不同的模型优化方法来加快模型在训练过程中的收敛速度，包括学习率调度器、梯度裁剪、归一化方法和模型优化算法等。在本节内容中，我们将介绍另外一种角度的模型优化算法，即初始化方法。&lt;/p&gt;&#xA;&lt;h2 id=&#34;6101-初始化动机&#34;&gt;6.10.1 初始化动机&lt;a class=&#34;anchor&#34; href=&#34;#6101-%e5%88%9d%e5%a7%8b%e5%8c%96%e5%8a%a8%e6%9c%ba&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;根据&lt;a href=&#34;https://mlwithme.github.io/dl/chapter03/97e1da1143cd4554&#34;&gt;3.3节&lt;/a&gt;内容中梯度下降算法的原理可知，不同的初始化位置对于目标函数最终的收敛速度或收敛情况有着至关重要的影响。神经网络的初始权重决定了网络对输入数据的初始响应。如果初始权重设置得不合理，网络可能会陷入局部最优解或者无法收敛的情况。&lt;/p&gt;&#xA;&lt;div align=center&gt;&lt;img width=&#34;350&#34; src=&#34;https://mlwithme.github.io/images/dl/240225113510.jpg&#34;/&gt; &lt;/div&gt;&lt;center&gt;图 6-23 不同初始化位置收敛情况图&lt;/center&gt;&#xA;&lt;p&gt;如图6-23所示，对于同一个目标函数来说权重的初始值选在不同的地方最终将会得到不同的优化结果。从图中可以看出，当参数初始值选在A点时，目标函数最终将会收敛于局部最优解；而当权重初始值选在B点时，目标函数最终则会收敛于全局最优解。如果是更为极端的情况，不合理的初始位置还将会导致目标函数发散的情况。图示代码参见&lt;code&gt;Code/Chapter06/C07_Init/visual.py&lt;/code&gt;文件。&lt;/p&gt;&#xA;&lt;p&gt;鉴于传统的初始化方法，如随机初始化方法，可能会导致深层网络中梯度消失或爆炸的问题从而使得模型训练变得更加困难，因此，便出现了一系列不同的初始化方法，例如 kaiming 初始化、xavier 初始化等。&lt;/p&gt;&#xA;&lt;h2 id=&#34;6102-初始化原理&#34;&gt;6.10.2 初始化原理&lt;a class=&#34;anchor&#34; href=&#34;#6102-%e5%88%9d%e5%a7%8b%e5%8c%96%e5%8e%9f%e7%90%86&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;在深度学习中，目前最常用的初始化方法是 kaiming 初始化和 xavier 初始化。不过从本质上来讲，两种初始化方法类似，仅仅只是使用了不同的方式来计算方差。初始化的原理都是根据当前层权重参数的数量信息来计算整体方差，然后再对权重参数重新进行采样以保证正向传播中激活值的方差和反向传播中梯度的方差尽可能一致来使得网络的训练更加稳定。具体来说，梯度方差是梯度的离散程度，即每个梯度值相对于梯度均值的偏离程度，梯度的方差较小意味着梯度值相对一致没有过大的波动，而方差较大则意味着梯度值的波动大。在前向传播中激活值的方差影响着网络的表达能力；在反向传播中梯度的方差影响着学习的速度和方向，而保持激活值方差和梯度方差一致可以帮助网络保持前向传播和反向传播之间的平衡，使得信息能够稳定地传递和更新。&lt;/p&gt;&#xA;&lt;p&gt;因此，当采用不同的方式计算得到方差以后，我们便可以使用正态分布或均匀分布来对网络权重进行初始化，所以 kaiming 初始xavier 初始化分别对应了两种不同的初始化方法，即 PyTorch 中的 &lt;code&gt;kaiming_normal_()&lt;/code&gt;、&lt;code&gt;kaiming_uniform_()&lt;/code&gt;、&lt;code&gt;xavier_normal_()&lt;/code&gt;和&lt;code&gt;xavier_uniform_()&lt;/code&gt;。下面我们分别来进行介绍。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1. kaiming 初始化&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;kaiming 初始化方法是一种针对激活函数为ReLU时的神经网络权重初始化方法 [1] [2]。它的目标是将网络层的激活输出的方差保持在一个相对稳定的范围内，以促进网络的稳定训练和收敛。假设我们有一个全连接层（或卷积层），其权重矩阵为$W$，该层的输入特征数为$n_{\text{in}}$，输出特征数为$n_{\text{out}}$。如果使用ReLU作为激活函数，则权重矩阵$W$的每一个元素都将从正态分布$\mathcal{N}(0,\sigma^2)$或均匀分布$\mathcal{U}(0,\sigma^2)$采样而来，其中在两种模式下标准差$\sigma$的计算方式分别为：&#xA;&lt;/p&gt;&#xA;$$&#xA;\sigma=\sqrt{\frac{2}{n_{\text{in}}}}\tag{6-34}&#xA;$$&lt;p&gt;&#xA;或&#xA;&lt;/p&gt;&#xA;$$&#xA;\sigma=\sqrt{\frac{2}{n_{\text{out}}}}\tag{6-35}&#xA;$$&lt;p&gt;&#xA;其中，当$W$为全连接层参数时，$n_{\text{in}}$和$n_{\text{out}}$分别为该层对应的输入输出神经元个数；当$W$为卷积层参数时，$n_{\text{in}}$和$n_{\text{out}}$分别为$k\times k\times \text{in_channels}$和$k\times k\times \text{out_channels}$，$\text{in_channels}$和$\text{out_channels}$分别表示特征图的输入输出通道数，$k$表示卷积核的窗口大小。&lt;/p&gt;&#xA;&lt;p&gt;在计算得到标准差以后，我们便可以将其作为参数使用&lt;code&gt;torch.normal_(0,std)&lt;/code&gt;方法来对权重参数进行采样初始化。下面，我们以PyTorch中的实现代码为例来详细介绍其中的细节。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#f0f0f0;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;kaiming_normal_&lt;/span&gt;(tensor, a &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;, mode &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;fan_in&amp;#39;&lt;/span&gt;, nonlinearity &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;leaky_relu&amp;#39;&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;     fan &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; _calculate_correct_fan(tensor, mode)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;3&lt;/span&gt;     gain &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; calculate_gain(nonlinearity, a)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;4&lt;/span&gt;     std &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; gain &lt;span style=&#34;color:#666&#34;&gt;/&lt;/span&gt; math&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;sqrt(fan)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;5&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;with&lt;/span&gt; torch&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;no_grad():&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;6&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; tensor&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;normal_(&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;, std)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;7&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;8&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;_calculate_correct_fan&lt;/span&gt;(tensor, mode):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;9&lt;/span&gt;     mode &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; mode&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;lower()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;10&lt;/span&gt;     valid_modes &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; [&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;fan_in&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;fan_out&amp;#39;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;11&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; mode &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;in&lt;/span&gt; valid_modes:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;12&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;raise&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;ValueError&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;Mode &lt;/span&gt;&lt;span style=&#34;color:#70a0d0&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#4070a0&#34;&gt; not supported, please use one of &amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;13&lt;/span&gt;     fan_in, fan_out &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; _calculate_fan_in_and_fan_out(tensor)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;14&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; fan_in &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; mode &lt;span style=&#34;color:#666&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#39;fan_in&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;else&lt;/span&gt; fan_out&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;15&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;16&lt;/span&gt; &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06287e&#34;&gt;_calculate_fan_in_and_fan_out&lt;/span&gt;(tensor):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;17&lt;/span&gt;     dimensions &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; tensor&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;dim()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;18&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; dimensions &lt;span style=&#34;color:#666&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;19&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;raise&lt;/span&gt; &lt;span style=&#34;color:#007020&#34;&gt;ValueError&lt;/span&gt;(&lt;span style=&#34;color:#4070a0&#34;&gt;&amp;#34;tensor with fewer than 2 dimensions&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;20&lt;/span&gt;     num_input_fmaps &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; tensor&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;size(&lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;21&lt;/span&gt;     num_output_fmaps &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; tensor&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;size(&lt;span style=&#34;color:#40a070&#34;&gt;0&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;22&lt;/span&gt;     receptive_field_size &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;23&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;if&lt;/span&gt; tensor&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;dim() &lt;span style=&#34;color:#666&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;24&lt;/span&gt;         &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;for&lt;/span&gt; s &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;in&lt;/span&gt; tensor&lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;shape[&lt;span style=&#34;color:#40a070&#34;&gt;2&lt;/span&gt;:]:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;25&lt;/span&gt;             receptive_field_size &lt;span style=&#34;color:#666&#34;&gt;*=&lt;/span&gt; s&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;26&lt;/span&gt;     fan_in &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; num_input_fmaps &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt; receptive_field_size&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;27&lt;/span&gt;     fan_out &lt;span style=&#34;color:#666&#34;&gt;=&lt;/span&gt; num_output_fmaps &lt;span style=&#34;color:#666&#34;&gt;*&lt;/span&gt; receptive_field_size&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#40a070&#34;&gt;28&lt;/span&gt;     &lt;span style=&#34;color:#007020;font-weight:bold&#34;&gt;return&lt;/span&gt; fan_in, fan_out&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，第16~28行是根据输入的权重参数来计算输入或输出特征的个数。第20~21行是分别获得全连接层或卷积层输入输出神经元个数或输入输出特征图个数。当对全连接层进行初始化时，此时&lt;code&gt;tensor.dim() = 2&lt;/code&gt;，则&lt;code&gt; fan_in, fan_out&lt;/code&gt;分别为该层对应的输入输出神经元个数；当对卷积层进行初始化时，此时&lt;code&gt;tensor.dim() = 3&lt;/code&gt;，则&lt;code&gt; fan_in, fan_out&lt;/code&gt;分别为输入输出特征通道可视野内的神经元个数；例如某个卷积层权重的形状为&lt;code&gt;[32,16,3,3]&lt;/code&gt;，则&lt;code&gt;fan_in = 16*3*3,fan_out = 32*3*3&lt;/code&gt;。第8~14行则是根据参数&lt;code&gt;mode&lt;/code&gt;来返回$n_{\text{in}}$或者$n_{\text{out}}$的个数。第3行则是根据指定激活函数的类型来返回对应的缩放尺度值，当&lt;code&gt;nonlinearity = &#39;relu&#39;&lt;/code&gt;时返回$\sqrt{2}$，各个激活函数的建议值可参见函数&lt;code&gt;calculate_gain()&lt;/code&gt;的实现部分。第6行则是使用均值0，标准差为&lt;code&gt;std&lt;/code&gt;对权重参数进行采样初始化。&lt;/p&gt;</description>
			</item>
	</channel>
</rss>
