GN快速入门指南

GN快速入门指南,第1张

运行 gn ,你只需从命令行运行 gn ,对于大型项目,GN是与源码一起的。

与其他一些构建系统不同,在GN中你可以设置你自己的构建目录,和你想要的设置。这让你可以根据需要维护不同的构建,可以根据自己的需要并行维护不同的构建。

一旦你生成了一个构建目录, ninja 文件将被自动生成,如果你在该目录下进行构建时,文件已经过期, ninja 则会自动重新生成,所以你不必重新运行 gn 。

建立一个构建目录:

在你的构建目录上运行设置构建参数:

这将d出一个编辑器,在该文件中输入build args,像这样:

可用的变量将取决于你的构建,你可以看到可用参数的列表和它们的默认值。

通过键入:

可以看到可用的参数列表和默认值,这个命令必须指定编译目录,因为不同的目录有不同的参数值。

Chrome的开发者也可以阅读 Chrome特有的构建配置 说明以了解更多信息。

运行 gn args out/Default (根据需要替换成你的构建目录),然后为常见的交叉编译选项添加以下一行或多行:

更多信息请参见 GN cross compiles 。

转到 examples/simple_build 目录,这是一个最小的GN仓库的root目录。

在该目录中,有一个 tutorial 目录。这里已经有一个 tutorial.cc 文件,但没有与构建挂钩。在该目录中为我们的新目标创建一个新的 BUILD.gn 文件,用于我们的新目标:

现在我们只需要告诉编译器这个新的目标。

打开目录( simple_build )下的 BUILD.gn 文件,GN从加载这个根文件,然后从这里开始加载所有的依赖项,所以我们只需要在这里添加对这个文件中的新目标的引用。

你可以把我们的新目标作为一个依赖关系加入到现有的目标中去,但把一个可执行文件作为依赖关系并没有什么意义。通常情况下,将一个可执行文件作为另一个可执行文件的依赖项是没有意义的(它们不能被链接)。

所以让我们做一个 tools group 组。在GN中,一个 group 只是一个依赖关系的集合,没有编译或链接:

从 simple_build 目录下的命令行:

执行 ./out/tutorial

你应该看到 Hello from the tutorial. 输出到控制台。

题外话: GN 鼓励静态库的目标名称不是全局唯一的。要建立一个这样的库,你可以把标签和它的路径(但没有前面的 // )给 ninja :

所以前面的tutorial可以是:

让我们看看在下列文件 examples/simple_build/BUILD.gn 中定义的目标。这里有一个静态库定义了一个函数, GetStaticText() :

还有一个共享库,定义了一个函数 GetSharedText() :

这也说明了如何为一个目标设置预处理程序的定义,要设置多个以上的定义或赋值,请使用这种形式:

现在我们来看看依赖这两个库的可执行文件:

这个可执行文件包括一个源文件,并依赖于前面的两个库,以冒号开头的标签指的是当前BUILD.gn文件中具有该名称的目标。

在 simple_build 目录下的命令行中:

注意,你 不需要 重新运行GN。当任何构建文件发生变化时,GN会自动重新构建

ninja文件。因为ninja在开始执行时打印出 [1/1] Regenerating ninja files 时,你就知道这个发生了。

一个库的用户经常需要用到 compile flags 、 defines 、 include directories ,要做到这一点,把所有这些设置放到一个 "config "中就可以,这是一个命名的设置集合(但不包括源和依赖关系)。

要将一个配置的设置应用于目标,请将其添加到 configs 列表中。

一个配置可以应用于所有依赖当前配置的目标,只要把它的标签放在 public_configs 列表中。

public_configs 也适用于当前的目标,所以不需要在两个地方都列出一个配置。

构建配置将设置一些默认适用于每个 target 的设置。

默认情况下,这些通常会被设置为默认的配置列表。你可以用 print 命令看到 你可以使用 print 命令看到这一点,这对调试很有用:

运行GN将打印类似的东西:

目标可以修改这个列表以改变其默认值。

例如,构建设置可能会通过添加 no_exceptions 配置来默认关闭异常,但目标可以通过用不同的配置来重新启用它们:

我们上面的打印命令也可以用字符串插值来表达,这是一种将数值转换成字符串的方法。它使用符号"$"来指代一个变量。

执行 ninja -C out hello

你可以通过 declare_args 声明你接受哪些参数并指定默认值。

参见 gn help buildargs 以了解其工作原理。

参见 gn help declare_args 以了解声明参数的具体细节。

在一个给定的范围内多次声明一个参数是一个错误,所以在确定参数的范围和命名时应该谨慎。

你可以在verbose模式下运行GN,以看到很多详细过程,使用 -v 参数就可以:

你可以运行 gn desc <build_dir><targetname>来获取有关

一个给定的目标。

获取 ldflags 信息

假设你想知道你的 TWO_PEOPLE 定义来自哪里:

另一个特别有趣的变体:

更多信息见 gn help desc 。

所有可以参与依赖关系的图(目标、配置和工具链)都由标签来识别,一个常见的标签看起来像:

这个例子包括一个source-root绝对路径、一个冒号和一个target,这意味着要在 "base/test/BUILD.gn "中寻找名为 "test_support "的目标。 如果有必要,你也可以指定系统的绝对路径。通常情况下,这样的路径会通过构建参数来指定,所以开发者可以指定组件在他们系统中的位置。

一个规范的标签包括正在使用的工具链的标签。通常情况下,工具链标签隐含地继承自当前的执行环境,但你可以覆盖它以指定跨工具链的依赖关系。

这里 GN 将在文件"//build/toolchain/win "中寻找名为 "msvc "的工具链定义,以知道如何编译这个目标。

如果你想引用同一构建文件中的东西,你可以省略路径名称,只用冒号开头。这种格式被推荐用于同文件中的标签引用。

标签可以被指定为相对于当前目录的标签。从风格上看,我们更倾向于对所有非文件本地的引用使用绝对路径,除非一个构建文件需要在不同的环境下运行(比如一个项目既需要独立运行,又需要拉到目录层次中不同位置的其他项目中)。

如果一个名字没有被指定,它将继承目录名称。从风格上看,我们倾向于在可能的情况下省略冒号和名称。

论文:Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift

1.数值问题。

    输入变量的数量级不一致可能会引起数值问题。因为tansig的非线性区间大约在[-1.7,1.7]。意味着要使神经元有效,tansig( w1*x1 + w2*x2 +b) 里的 w1*x1 +w2*x2 +b 数量级应该在 1 (1.7所在的数量级)左右。这时输入较大,就意味着权值必须较小,一个较大,一个较小,两者相乘,就引起数值问题了。

2.求解需要

    在训练前我们将数据归一化是为了更方便的求解。

     那么,究竟给求解带来了什么方便呢?

    这个问题不能一概而论,不同的算法,在归一化中得到的好处各不相同。目前大部算法,都比较需要归一化,特别是常用的梯度下降法(或梯度下降的衍生方法),归一化和不归一化,对梯度下降法的影响非常大。不同的算法,对归一化的依赖程序不同。

    Batch Normalization(简称BN)就是对每一批数据进行归一化,确实如此,对于训练中某一个batch的数据{x1,x2,...,xn},注意这个数据是可以输入也可以是网络中间的某一层输出。在BN出现之前,我们的归一化 *** 作一般都在数据输入层,对输入的数据进行求均值以及求方差做归一化,但是BN的出现打破了这一个规定,我们可以在网络中任意一层进行归一化处理,因为我们现在所用的优化方法大多都是min-batch SGD,所以我们的归一化 *** 作就成为Batch Normalization。

    因为深层神经网络在做非线性变换前的 激活输入值 (就是那个x=WU+B,U是输入) 随着网络深度加深或者在训练过程中,其分布逐渐发生偏移或者变动,之所以训练收敛慢,一般是整体分布逐渐往非线性函数的取值区间的上下限两端靠近 (对于Sigmoid函数来说,意味着激活输入值WU+B是大的负值或正值),所以这 导致反向传播时低层神经网络的梯度消失 ,这是训练深层神经网络收敛越来越慢的 本质原因 , 而BN就是通过一定的规范化手段,把每层神经网络任意神经元这个输入值的分布强行拉回到均值为0方差为1的标准正态分布 ,其实就是把越来越偏的分布强制拉回比较标准的分布,这样使得激活输入值落在非线性函数对输入比较敏感的区域,这样输入的小变化就会导致损失函数较大的变化,意思是 这样让梯度变大,避免梯度消失问题产生,而且梯度变大意味着学习收敛速度快,能大大加快训练速度。

我们把网络中间层在训练过程中,数据分布的改变称之为:“ Internal Covariate Shift ”。 BN的提出,就是要解决在训练过程中,中间层数据分布发生改变的情况。BatchNorm就是在深度神经网络训练过程中使得每一层神经网络的输入保持相同分布的。

怎么做?

1、求每一个训练批次数据的均值和方差

2、使用求得的均值和方差对该批次的训练数据做归一化,获得0-1分布。其中ε是为了避免除数为0时所使用的微小正数。

3、尺度变换和偏移:将xi乘以γ调整数值大小,再加上β增加偏移后得到yi,这里的γ是尺度因子,β是平移因子。 这一步是BN的精髓,由于归一化后的xi基本会被限制在正态分布下,使得网络的表达能力下降。为解决该问题,我们引入两个新的参数:γ,β。γ和β是在训练时网络自己学习得到的。

解决了什么?

一个标准的归一化步骤就是减均值除方差,在这种归一化中引入了两个需要学习的参数。

    a中左图是没有经过任何处理的输入数据,曲线是sigmoid函数,如果数据在梯度很小的区域,那么学习率就会很慢甚至陷入长时间的停滞。减均值除方差后,数据就被移到中心区域如右图所示,对于大多数激活函数而言,这个区域的梯度都是最大的或者是有梯度的(比如ReLU),这可以看做是一种对抗梯度消失的有效手段。 对于一层如此,如果对于每一层数据都那么做的话,数据的分布总是在随着变化敏感的区域,相当于不用考虑数据分布变化了,这样训练起来更有效率。

    减均值除方差得到的分布是正态分布。 如果数据本身就很不对称,或者激活函数未必是对方差为1的数据最好的效果,比如Sigmoid激活函数,在-1~1之间的梯度变化不大,那么非线性变换的作用就不能很好的体现 ,换言之就是,减均值除方差 *** 作后可能会削弱网络的性能。针对该情况,在前面三步之后加入第4步完成真正的batch normalization。

     BN的本质就是利用优化变一下方差大小和均值位置,使得新的分布更切合数据的真实分布,保证模型的非线性表达能力。

如何在验证集中使用?

    对于预测阶段时所使用的均值和方差,其实也是来源于训练集。比如我们在模型训练时我们就记录下每个batch下的均值和方差,待训练完毕后,我们求整个训练样本的均值和方差期望值,作为我们进行预测时进行BN的的均值和方差

CNN中的BN

    卷积神经网络的特征是对应到一整张特征响应图上的,所以做BN时也应以响应图为单位而不是按照各个维度。比如在某一层,batch大小为m,响应图大小为w×h,则做BN的数据量为m×w×h。

    BN在深层神经网络的作用非常明显:若神经网络训练时遇到收敛速度较慢,或者“梯度爆炸”等无法训练的情况发生时都可以尝试用BN来解决。同时,常规使用情况下同样可以加入BN来加速模型训练,甚至提升模型精度。

    BN对batch是independent的,过小的batch size会导致其性能下降,一般来说每GPU上batch设为32最合适。但是对于一些其他深度学习任务batch size往往只有1-2,比如目标检测,图像分割,视频分类上,输入的图像数据很大,较大的batchsize显存吃不消。

深度网络中的数据维度一般是[N, C, H, W]或者[N, H, W,C]格式,N是batch size,H/W是feature的高/宽,C是feature的channel,压缩H/W至一个维度,其三维的表示如上图,假设单个方格的长度是1,那么其表示的是[6, 6,*, * ]

BN在batch的维度上norm,归一化维度为[N,H,W],对batch中对应的channel归一化;

LN避开了batch维度,归一化的维度为[C,H,W];

IN 归一化的维度为[H,W];

而GN介于LN和IN之间,其首先将channel分为许多组(group),对每一组做归一化,及先将feature的维度由[N, C, H, W]reshape为[N, G,C//G , H, W],归一化的维度为[C//G , H, W]

    传统角度来讲,在深度学习没有火起来之前,提取特征通常是使用SIFT,HOG和GIST特征,这些特征有一个共性,都具有按group表示的特性,每一个group由相同种类直方图的构建而成,这些特征通常是对在每个直方图(histogram)或每个方向(orientation)上进行组归一化(group-wise norm)而得到。而更高维的特征比如VLAD和Fisher Vectors(FV)也可以看作是group-wise feature,此处的group可以被认为是每个聚类(cluster)下的子向量sub-vector。

    从深度学习上来讲,完全可以认为卷积提取的特征是一种非结构化的特征或者向量,拿网络的第一层卷积为例,卷积层中的的卷积核filter1和此卷积核的其他经过transform过的版本filter2(transform可以是horizontal flipping等),在同一张图像上学习到的特征应该是具有相同的分布,那么,具有相同的特征可以被分到同一个group中,按照个人理解,每一层有很多的卷积核,这些核学习到的特征并不完全是独立的,某些特征具有相同的分布,因此可以被group。

    导致分组(group)的因素有很多,比如频率、形状、亮度和纹理等,HOG特征根据orientation分组,而对 神经网络 来讲,其提取特征的机制更加复杂,也更加难以描述,变得不那么直观。

    另在神经科学领域,一种被广泛接受的计算模型是对cell的响应做归一化,此现象存在于浅层视觉皮层和整个视觉系统。

    作者基于此,提出了组归一化(Group Normalization)的方式,且效果表明,显著优于BN、LN、IN等。GN的归一化方式避开了batch size对模型的影响,特征的group归一化同样可以解决$Internal$ $Covariate$ $Shift$的问题,并取得较好的效果。


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/11352457.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-15
下一篇2023-05-15

发表评论

登录后才能评论

评论列表(0条)

    保存