当前位置:首页 » 操作系统 » bf算法D

bf算法D

发布时间: 2023-04-22 01:12:13

A. kmp算法什么意思

KMP算法之所以叫做KMP算法是因为这个算法是由三个人共同提出来的,就取三个人名字的首字母作为该算法的名字。其实KMP算法与BF算法的区别就在于KMP算法巧妙的消除了指针i的回溯问题,只需确定下次匹配j的位置即可,使得问题的复杂度由O(mn)下降到O(m+n)。
在KMP算法中,为了确定在匹配不成功时,下次匹配时j的位置,引入了next[]数组,next[j]的值表示P[0...j-1]中最长后缀的长度等于相同字符序列的前缀。
对于next[]数组的定义如下:
1) next[j] = -1 j = 0
2) next[j] = max(k): 0<k<j P[0...k-1]=P[j-k,j-1]
3) next[j] = 0 其他
如:
P a b a b a
j 0 1 2 3 4
next -1 0 0 1 2
即next[j]=k>0时,表示P[0...k-1]=P[j-k,j-1]
因此KMP算法的思想就是:在匹配过程称,若发生不匹配的情况,如果next[j]>=0,则目标串的指针i不变,将模式串的指针j移动到next[j]的位置继续进行匹配;若next[j]=-1,则将i右移1位,并将j置0,继续进行比较。

B. 【算法笔记】字符串匹配

BF 算法中的 BF 是 Brute Force 的缩写,中文叫作暴力匹配算法,也叫朴素匹配算法:

主串和模式串:
在字符串 A 中查找字符串 B,那字符串 A 就是主串,字符串 B 就是模式串。我们把主串的长度记作 n,模式串的长度记作 m

我们在主串中,检查起始位置分别是 0、1、2…n-m 且长度为 m 的 n-m+1 个子串,看有没有跟模式串匹配的。

BF 算法的时间复杂度是 O(n*m)

等价于

比如匹配Google 和Goo 是最好时间复杂度,匹配Google 和ble是匹配失败的最好时间复杂度。

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth与J.H.Morris和V.R.Pratt同时发现,因此人们称它为克努特—莫里斯—普拉特算法。KMP算法主要分为两个步骤:字符串的自我匹配,目标串和模式串之间的匹配。

看来网上很多的文章,感觉很多的都没有说清楚,这里直接复制阮一峰的内容,讲的很清晰
内容来自 http://www.ruanyifeng.com/blog/

首先,字符串"BBC ABCDAB ABCDABCDABDE"的第一个字符与搜索词"ABCDABD"的第一个字符,进行比较。因为B与A不匹配,所以搜索词后移一位。

因为B与A不匹配,搜索词再往后移。

就这样,直到字符串有一个字符,与搜索词的第一个字符相同为止。

接着比较字符串和搜索词的下一个字符,还是相同。

直到字符串有一个字符,与搜索词对应的字符不相同为止。

这时,最自然的反应是,将搜索词整个后移一位,再从头逐个比较。这样做虽然可行,但是效率很差,因为你要把"搜索位置"移到已经比较过的位置,重比一遍。

一个基本事实是,当空格与D不匹配时,你其实知道前面六个字符是"ABCDAB"。KMP算法的想法是,设法利用这个已知信息,不要把"搜索位置"移回已经比较过的位置,继续把它向后移,这样就提高了效率。

怎么做到这一点呢?可以针对搜索词,算出一张《部分匹配表》(Partial Match Table)。这张表是如何产生的,后面再介绍,这里只要会用就可以了。

已知空格与D不匹配时,前面六个字符"ABCDAB"是匹配的。查表可知,最后一个匹配字符B对应的"部分匹配值"为2,因此按照下面的公式算出向后移动的位数:

因为 6 - 2 等于4,所以将搜索词向后移动4位。

因为空格与C不匹配,搜索词还要继续往后移。这时,已匹配的字符数为2("AB"),对应的"部分匹配值"为0。所以,移动位数 = 2 - 0,结果为 2,于是将搜索词向后移2位。

因为空格与A不匹配,继续后移一位。

逐位比较,直到发现C与D不匹配。于是,移动位数 = 6 - 2,继续将搜索词向后移动4位。

逐位比较,直到搜索词的最后一位,发现完全匹配,于是搜索完成。如果还要继续搜索(即找出全部匹配),移动位数 = 7 - 0,再将搜索词向后移动7位,这里就不再重复了。

下面介绍《部分匹配表》是如何产生的。

首先,要了解两个概念:"前缀"和"后缀"。 "前缀"指除了最后一个字符以外,一个字符串的全部头部组合;"后缀"指除了第一个字符以外,一个字符串的全部尾部组合。

"部分匹配值"就是"前缀"和"后缀"的最长的共有元素的长度。以"ABCDABD"为例,

"部分匹配"的实质是,有时候,字符串头部和尾部会有重复。比如,"ABCDAB"之中有两个"AB",那么它的"部分匹配值"就是2("AB"的长度)。搜索词移动的时候,第一个"AB"向后移动4位(字符串长度-部分匹配值),就可以来到第二个"AB"的位置。

BM(Boyer-Moore)算法。它是一种非常高效的字符串匹配算法,有实验统计,它的性能是着名的KMP 算法的 3 到 4 倍。

BM 算法包含两部分,分别是坏字符规则(bad character rule)和好后缀规则(good suffix shift)

未完待续

参考文章:
字符串匹配的Boyer-Moore算法

C. VR如何渲染动画

在vray3.0及之前的时代,使用vray渲染动画是一件比较繁琐的工作。又是分层渲染又是隔帧预渲染光子,又或者是逐帧预渲染光子。甚至关掉GI单独GI设置等等,这都是为了避免动画渲染的闪烁或者斑点。平衡渲染质量与渲染时间。

当vray3.6及4.0发布之后,使用vray进行动画渲染变得非常简单。2020年vray5.0发布,至今天vray已经更新到5.1。渲染动画在速度上已经有了很快的提升。vray多年GI诟病已经不让我烦恼。

下面就介绍一下vray官方给出的动画渲染设置。

传统上(祖传闪烁),vray动画序列的渲染可能会在帧间产生不想要的闪烁,也被称为“bubbling冒泡”或“boiling沸腾”。这是因为低频噪波在帧间发生变化。

其实V-RayNext(也就是vray4.0) 时候解已经决这些问题,只有两个调整的默认设置:Light Cache Subdivs,,和Retrace数值。虽然推荐的设置在大多数情况下都是适用的(比如室内,室外,环境,包拍摄,特效模拟),但我们建议您在提交到最终的序列渲染之前,还是要渲染具有代表性的帧来测试一下有无问题。(译者:这是免责声明啊)

如果仍然存在一些视觉伪影(诸如噪点、斑点),继续以小数值增加这两个设置,直到它们被解决。接下来就是讲到如何设置。

1.1所有的设置都是在V-Ray默认渲染设置下进行的。可以通过更改到另一个渲染引擎,然后再更改回V-Ray,这就重置vray设置了。这是大前提,如果打开旧版本vray的文件就需要先重置渲染器。

1.2设置图像采样器为“Bucket.”。点击渲染设置> V-Ray标签>图像采样器(抗锯齿)>类型>“Bucket.”。这是最终渲染的首选采样类型,因为它比渐进式稍微快一些,并且与一些辅助技术一起工作得更全面。译者:意思就是“Bucket”模式bug更少。

1.3选择最适合您需要的噪声阈值。0.005的值将去除可见的噪波,而不用渲染后去噪(译者:就不用加降噪了)。要比较这两个值,请查看上面示例中的默认值0.01和0.005之间的差异。

1.4。进入GI选项卡的Light Cache设置,将subdiv设置为3000。增加光缓存子divs确保了光缓存被很好的采样,并且在帧之间是稳定的。与渲染实际帧相比,更高的subdiv对渲染时间的影响可以忽略不计,所以这是一个良好的常规做法,没有任何特别的缺点。

请注意,光缓存的计算方法需要是“每帧”(默认),而不是路径驱动的方法,如“摄像机路径”。

总结:Vray4.0后,官方推荐的动画渲染设置已经不分运动物体和静止物体。动画的渲染设置,在默认参数前提下,仅仅需要调整两个位置:

1.图像采样器使用Bucket.noisethreshold设置为 0.005就不需要降噪了。默认的话也可以添加降噪器即可。

当然动画渲染时间普遍都是偏长的,一般公司都是找一些渲染农场来完成项目的渲染工作,但是好用的一般都贵,稍微实惠点的就不好用,又慢又排队,有兴趣的可以去体验一下这个农场,叫渲染101,目前来说是最好用,效率最高的农场,速度快也不排队,而且最重要的是价格非常低

D. 神经网络如何外推:从前馈网络到图网络

How Neural Networks Extrapolate: From Feedforward to Graph Neural Networks

ICLR2021最高分论文            https://arxiv.org/abs/2009.11848

52页论文,正文占9页,主要都是附录,不过附录里很多图片(一页就一两张图),排除这些一页一图的,只有40页

我们研究用梯度下降法训练的神经网络如何外推,也就是说,它们在训练分布的支持之外学习什么。以前的工作报告了使用神经网络进行外推时混合的实证结果:虽然前馈神经网络,即多层感知器(MLP)在某些简单任务中外推效果不好,但图形神经网络(GNN)——带有MLP模块的结构化网络——在更复杂的任务中取得了一些成功。为了得到理论解释,我们确定了MLPs和GNNs外推良好的条件。首先,我们量化了ReLU-MLPs从原点沿任意方向快速收敛到线性函数的观测结果,这意味着ReLU-MLPs不能外推大多数非线性函数。但是,当训练分布足够“多样化”时,他们可以证明学习线性目标函数。其次,在分析GNNs的成功和局限性时,这些结果提出了一个假设,我们提供了理论和经验证据:GNNs在将算法任务外推到新数据(例如。,较大的图或边权重)依赖于编码体系结构或特征中特定于任务的非线性。我们的理论分析建立在过度参数化网络与神经切线核的联系上。根据经验,我们的理论适用于不同的培训环境

1简介

人类在许多任务中推断得很好。例如,我们可以对任意大的数应用算术。人们可能想知道,神经网络是否也能做到这一点,并将其推广到任意远离训练数据的示例中(Lake et al.,2017)。奇怪的是,以前的工作报告混合外推结果与神经网络。早宏裂期的工作表明,前馈神经网络,又称多层感知器(MLPs),在学习简单多项式函数时不能很好地进行外推(Barnard&Wessels,1992;Haley&Soloway,1992年)。然而,最近的研究表明,图神经网络(GNNs)(Scarselli et al.,2009)是一类具有MLP构建块的结构化网络,在具有挑战性的算法任务中,如预测物理系统的时间演化(Battaglia et al.,2016),可以推广到比训练嫌咐图大得多的图,学习图形算法(Velickovic et al.,2020),求解数学方程(Lample&Charton,2020)。

为了解释这个难题,我们正式研究了梯度下降(GD)训练的神经网络是如何外推的,即它们在训练分布的支持之外学习什么。我们说,如果一个神经网络在训练分布之外学习了一个任务,它就能很好地进行外推。乍一看,似乎神经网络可以在训练分布之外任意行为,因为它们具有高容量(Zhang et al.,2017),并且是通用逼近器(Cybenko,1989;Funahashi,1989年;Hornik等人,1989年;库尔科娃,1992年)。然而,神经网络受到梯度下降训练的限制(Hardt等人,2016;Soudry等人,2018年)。在我们的分析中,我们通过类比过参数化神经网络的训练动态和通过神经切线核(NTK)的核回归,明确考虑了这种隐式偏差(Jacot等人,2018)。

从前馈网络、最简单的神经网络和更复杂的体系结构(如GNNs)的构建块开始,我们建立了由GD训练的具有ReLU激活的过参数mlp的预测从原点沿任意方向收敛到线性函数。我们证明了两层网络的收敛速度,并从经验上观察到收敛经常发生在训练数据附近(图1),这表明ReLU-MLPs不能很好地外推大多数非线性任务。我们强调,我们的结果并不是基于ReLU网络具有有限多个线性区域的事实(Arora et al.,2018;Hanin&Rolnick,2019年;Hein等人,2019年)。虽然有有限多个线性区域意味着ReLU MLPs最终会变为线性,但MLPs是否会学习到接近训练分布的正确目标函数并没有说明。相比之下,我们的结果是非渐近的,并且量化了MLPs将学习什么样的函数接近于训练分布。其次,我们确定了mlp外推良好的条件:任务是线性的,训练分布的几何结构是充分“多样化”的。据我们所知蔽者闭,我们的结果是这种前馈神经网络的第一个外推结果。

然后,我们将我们对前馈神经网络的见解与GNNs联系起来,以解释GNNs在某些算法任务中外推得好的原因。先前的工作报告了可以通过动态规划(DP)解决的任务的成功外推(Bellman,1966),其计算结构与GNNs一致(Xu等人,2020)。DP更新通常可以分解为非线性和线性步骤。因此,我们假设GD训练的GNN可以在DP任务中很好地外推,如果我们在架构和输入表示中编码适当的非线性(图2)。重要的是,编码非线性可能不需要GNNs插值,因为MLP模块可以很容易地学习训练分布中的许多非线性函数(Cybenko,1989;Hornik等人,1989年;Xu等人,2020),但GNNs正确外推至关重要。我们使用图NTK(Du等人,2019b)证明了简化情况下的这一假设。在经验上,我们验证了三个DP任务的假设:最大度、最短路径和n体问题。我们证明了具有适当结构、输入表示和训练分布的GNNs可以很好地预测具有未知大小、结构、边权值和节点特征的图。我们的理论解释了以往工作的经验成功,并指出了它们的局限性:成功的外推依赖于编码任务特定的非线性,这需要领域知识或广泛的模型搜索。从更广泛的角度来看,我们的见解超越了GNNs,并广泛应用于其他神经网络。

总之,我们研究神经网络如何外推。首先,由GD训练的ReLU-mlp以O(1/t)的速率沿原点方向收敛为线性函数。其次,为了解释为什么GNNs在一些算法任务中可以很好地外推,我们证明了ReLU-MLPs在线性任务中可以很好地外推,从而引出一个假设:当适当的非线性被编码到结构和特征中时,神经网络可以很好地外推。我们用一个简化的例子证明了这个假设,并为更一般的情况提供了经验支持。

1.1相关工作

早期的工作显示了MLP不能很好地外推的示例任务,例如学习简单多项式(Barnard&Wessels,1992;Haley&Soloway,1992年)。相反,我们展示了ReLU MLPs如何外推的一般模式,并确定MLPs外推良好的条件。最近的工作研究了在NTK和平均场两种情况下,梯度下降对MLP产生的隐性偏差(Bietti和Mairal,2019;Chizat&Bach,2018年;Song等人,2018年)。与我们的结果相关,一些工作表明MLP预测收敛于“简单”分段线性函数,例如,具有很少的线性区域(Hanin&Rolnick,2019;Maennel等人,2018年;Savarese等人,2019年;威廉姆斯等人,2019年)。我们的工作不同之处在于,这些工作都没有明确研究外推法,有些只关注一维输入。最近的研究还表明,在NTK区域的高维环境中,MLP在某些标度极限下至多是一个渐近线性预测因子(Ba等人,2020;Ghorbani等人,2019年)。我们研究不同的设置(外推),我们的分析是非渐近性质,不依赖于随机矩阵理论。

先前的工作通过在较大的图上进行测试来探索GNN外推(Battaglia et al.,2018;Santoro等人,2018年;萨克斯顿等人,2019年;Velickovic等人,2020年)。我们是第一个从理论上研究GNN外推法的人,我们完成了外推法的概念,包括看不见的特征和结构。

2准备工作

3前馈神经网络如何外推

前馈网络是最简单的神经网络和更复杂的体系结构(如GNNs)的构建块,因此我们首先研究它们在GD训练时是如何外推的。在本文中,我们假设ReLU激活。第3.3节包含其他激活的初步结果。

3.1 RELU MLP的线性外推行为

通过架构,ReLU网络学习分段线性函数,但是在训练数据的支持之外,这些区域究竟是什么样的呢?图1举例说明了当GD对各种非线性函数进行训练时,ReLU MLP如何进行外推。这些例子表明,在训练支持之外,预测很快就会沿着原点的方向线性化。我们通过线性回归对MLPs的预测进行了系统的验证:决定系数(R2)总是大于0.99(附录C.2)。也就是说,ReLU MLPs几乎立即在训练数据范围之外“线性化”。

我们使用GD通过神经切线核(NTK)训练的神经网络的隐式偏差来形式化这个观察:GD训练的过参数化网络的优化轨迹等价于具有特定神经切线核的核回归的轨迹,在一系列被称为“NTK制度”的假设下(Jacot等人,2018年)。我们在这里提供了一个非正式的定义;更多详情,请参阅Jacot等人(2018)和附录A。

定义2。

(非正式)在NTK区域训练的神经网络是无限宽的,以一定的比例随机初始化,并且由GD以无穷小的步长训练。

先前的工作通过NTK分析过参数化神经网络的优化和分布泛化(Allen-Zhu等人,2019a;b类;Arora等人,2019a;b类;曹顾,2019;杜等人,2019c;一个;李亮,2018;日田和铃木,2021年)。相反,我们分析外推。

定理1将我们从图1中观察到的结果形式化:在训练数据范围之外,沿着原点的任何方向tv,两层ReLU MLP的预测迅速收敛为速率为O(1/t)的线性函数。线性系数β收敛速度中的常数项依赖于训练数据和方向v。证据见附录B.1

定理1

ReLU网络具有有限多个线性区域(Arora等人,2018;汉宁和罗尔尼克,2019),因此他们的预测最终成为线性。相反,定理1是一个更细粒度的分析MLP如何外推,并提供了收敛速度。虽然定理1假设两层网络处于NTK状态,但实验证实,线性外推行为发生在具有不同深度、宽度、学习速率和批量大小的网络上(附录C.1和C.2)。我们的证明技术也可能扩展到更深层次的网络。

图4a提供了一个更积极的结果:MLP在许多不同的超参数上很好地外推了线性目标函数。虽然学习线性函数一开始似乎非常有限,但在第4节中,这一见解将有助于解释GNN在非线性实际任务中的外推特性。在此之前,我们首先从理论上分析了MLPs外推的好时机。

3.2当RELU MLPS可证明外推井

图4a显示,当目标函数为线性时,MLP可以很好地外推。然而,这并不总是正确的。在本节中,我们展示了成功的外推依赖于训练数据的几何结构。直观地说,训练分布必须足够“多样化”,以便进行正确的推断

我们提供了两个条件,将训练数据的几何结构与外推联系起来。引理1指出,过参数化的mlp只需二维例子就可以学习线性目标函数。

实验:训练数据的几何结构影响外推。

定理2中的条件形式化了一种直觉,即训练分布必须是“多样的”,才能成功地进行外推,例如,D包括所有方向。从经验上讲,当满足定理2的条件时(图4b中的“all”),外推误差确实很小。相反,当训练示例仅限于某些方向时,外推误差要大得多(图4b和图3)。

与之前的工作相关,定理2提出了为什么虚假相关性可能会损害外推,补充了因果关系论点(Arjovsky et al.,2019;Peters等人,2016年;Rojas Carulla等人,2018年)。当训练数据具有虚假相关性时,某些特征组合丢失;e、 例如,骆驼可能只出现在沙漠中的图像收集。因此,定理2的条件不再成立,模型可能外推错误。定理2也类似于线性模型的可辨识条件,但更为严格。如果训练数据具有全(特征)秩,我们可以唯一地识别一个线性函数。mlp更具表现力,因此识别线性目标函数需要附加约束。

综上所述,我们分析了ReLU-MLPs是如何外推的,并提供了两个启示:(1)MLPs由于其线性外推而不能外推大多数非线性任务(定理1);当目标函数是线性函数时,如果训练分布是“多样的”(定理2),mlp可以很好地外推。在下一节中,这些结果将帮助我们理解更复杂的网络是如何外推的。

3.3具有其他激活功能的MLPS

在继续讨论GNNs之前,我们通过对其他激活函数tanh的实验来完成MLPs的描述σ(x) =tanh(x),余弦σ(x) =cos(x)(Lapedes&Farber,1987年;McCaughan,1997年;Sopena和Alquezar,1994),和σ(x) =x2(杜和李,2018;Livni等人,2014年)。详情见附录C.4。当激活函数和目标函数相似时,MLPs外推效果较好;e、 例如,当学习tanh时,tanh激活可以很好地推断,但不能推断其他功能(图5)。而且,每个激活函数都有不同的局限性。要用tanh激活外推tanh函数,训练数据范围必须足够宽。当学习具有二次激活的二次函数时,只有两层网络可以很好地进行外推,而更多的层可以得到更高阶的多项式。对于高维数据,余弦激活很难优化,因此我们只考虑一维/二维余弦目标函数。

4图形神经网络如何外推

上面,我们看到非线性任务中的外推对于MLP来说是困难的。尽管存在这一局限性,GNNs在一些非线性算法任务中表现出了很好的外推能力,如直观物理(Battaglia et al.,2016;Janner等人,2019),图算法(Battaglia等人,2018;Velickovic等人,2020)和符号数学(Lample&Charton,2020)。为了解决这个差异,我们建立在MLP结果的基础上,研究GD训练的GNNs是如何外推的。

4.1假设:线性算法对齐有助于外推

我们从一个例子开始:训练GNNs来解决最短路径问题。对于这项任务,先前的工作观察到,具有最小聚集的改进GNN架构可以推广到比训练集中的图更大的图(Battaglia et al.,2018;Velickovic等人,2020):

我们首先提供一个直观的解释(图2a)。最短路径可通过Bellman-Ford(BF)算法(Bellman,1958)求解,并进行以下更新

其中w(v,u)是边(v,u)的权重,d[k][u]是k步内到节点u的最短距离。这两个方程可以很容易地对齐:如果GNNs的MLP模块学习一个线性函数d[k],那么它将模拟BF算法−1] [v]+w(v,u)。由于mlp可以外推线性任务,这种“对齐”可以解释为什么GNNs可以在这个任务中很好地外推。

为了进行比较,我们可以解释为什么我们不希望GNN使用更常用的和聚合(Eqn。1) 在这项任务中推断得很好。对于和聚合,MLP模块需要学习一个非线性函数来模拟BF算法,但定理1表明,它们不会在训练支持之外外推大多数非线性函数。

我们可以将上述直觉推广到其他算法任务。许多GNNs外推良好的任务可以通过动态规划(DP)来解决(Bellman,1966),这是一种具有类似GNNs(Eqn)的递归结构的算法范式。1) (Xu等人,2020年)。

定义3。动态规划(DP)是一个带有更新的递归过程

其中答案[k][s]是迭代k和状态s索引的子问题的解决方案,DP Update是一个任务特定的更新函数,它基于上一次迭代解决子问题。从更广泛的角度出发,我们假设:如果我们将适当的非线性编码到模型结构和输入表示中,使MLP模块只需要学习接近线性的步骤,那么所得到的神经网络就可以很好地外推。

假设1。

我们的假设建立在(Xu等人,2020)的算法对齐框架之上,该框架指出,如果模块“对齐”以便于学习(可能是非线性)函数,则神经网络插值良好。成功的外推更难:模块需要与线性函数对齐。

线性算法对准的应用。

一般来说,线性算法对准不局限于GNN,广泛应用于神经网络。为了满足这种情况,我们可以在结构或输入表示中编码适当的非线性操作(图2)。使用GNNs学习DP算法是在体系结构中编码非线性的一个例子(Battaglia等人,2018;Corso等人,2020年)。另一个例子是对体系结构中的日志和exp变换进行编码,以帮助外推算术任务中的乘法(Trask等人,2018;Madsen&Johansen,2020年)。神经符号程序进一步发展,并对符号操作库进行编码,以帮助推断(Johnson等人,2017年;Mao等人,2019年;易等,2018年)。

对于某些任务,更改输入表示可能更容易(图2b)。有时,我们可以将目标函数f分解为f=g◦ 将h嵌入特征嵌入h和一个简单的目标函数g中,我们的模型可以很好地推断。我们可以通过使用领域知识通过专门的特征或特征转换获得h(Lample&Charton,2020;Webb等人,2020年),或通过X\D中未标记的未标记的未标记的分发数据的表示学习(例如,BERT)(Chen等人,2020年);Devlin等人,2019年;胡等,2020;Mikolov等人,2013b;Peters等人,2018年)。这为表示如何帮助在不同应用领域进行外推提供了新的视角。例如,在自然语言处理中,预处理表示(Mikolov等人,2013a;Wu&Dredze,2019)和使用领域知识进行特征转换(袁等,2020年;Zhang等人,2019)帮助模型在语言之间进行概括,这是一种特殊的外推。在定量金融中,确定正确的“因素”或特征对于深入学习模型至关重要,因为金融市场可能经常处于外推制度中(Banz,1981;法兰西,1993年;罗斯,1976)。

线性算法对齐解释了文献中成功的外推,并指出外推一般更难:编码适当的非线性通常需要领域专家或模型搜索。其次,我们为我们的假设提供理论和实证支持。

4.2理论和经验支持

我们验证了我们对三个DP任务的假设:最大度、最短路径和n-体问题,并证明了最大度假设。我们强调了图结构在外推中的作用。

理论分析。

我们从一个简单而基本的任务开始:学习一个图的最大度,一个DP的特例。作为定理1的推论,常用的基于和的GNN(Eqn。1) 无法很好地推断(证据见附录B.4)。

推论1。

具有和聚集和和和读出的GNNs在最大程度上不能很好地外推。为了实现线性算法对齐,我们可以对读出器中唯一的非线性max函数进行编码。定理3证实了具有最大读数的GNN在这个任务中可以很好地外推。

定理3并不是紧跟定理2,因为GNNs中的MLP模块只接受间接的监视。我们分析图NTK(Du等人,2019b)来证明附录B.5中的定理3。虽然定理3假设相同的节点特征,但我们在经验上观察到相同和不相同特征的相似结果(附录中的图16)。

条件的解释。

定理3中的条件类似于定理2中的条件。这两个定理都需要不同的训练数据,用定理3中的图结构或定理2中的方向来度量。在定理3中,如果所有训练图都具有相同的最大或最小节点度,例如,当训练数据来自以下族之一时,违反了该条件:路径、C-正则图(具有C度的正则图)、圈和阶梯。

实验:有助于推断的架构。

我们用两个DP任务来验证我们的理论分析:最大度和最短路径(详见附录C.5和C.6)。而以前的工作只测试不同大小的图(Battaglia et al.,2018;Velickovic等人,2020),我们还测试了具有不可见结构、边权重和节点特征的图。结果支持了我们的理论。对于最大度,具有最大读数的GNNs优于具有和读数的GNNs(图6a),证实了推论1和定理3。对于最短路径,具有最小读数和最小聚集的GNN优于具有和读数的GNN(图6a)。

实验证实了训练图结构的重要性(图7)。有趣的是,这两个任务支持不同的图结构。对于最大度,如定理3所预测的,当训练在树、完全图、扩张图和一般图上时,GNNs外推效果很好,当训练在4-正则图、圈图或梯形图上时,外推误差更大。对于最短路径,当我们改变训练图的稀疏性时,外推误差遵循U形曲线(附录中的图7b和图18)。直觉上,在稀疏或稠密图上训练的模型可能学习退化解。

实验:有助于推断的表征。

最后,我们展示了一个很好的输入表示帮助外推。我们研究了n体问题(Battaglia等人,2016;Watters等人,2017年)(附录C.7),即预测重力系统中n个物体的时间演化。根据之前的工作,输入是一个完整的图形,其中节点是对象(Battaglia等人,2016)。

5与其他分布外设置的连接

我们讨论几个相关的设置。直观地说,从我们上述结果的观点来看,相关设置中的方法可以通过1)学习超出训练数据范围的有用非线性和2)将相关测试数据映射到训练数据范围来改进外推。

领域适应研究对特定目标领域的泛化(Ben-David等人,2010;Blitzer等人,2008年;Mansour等人,2009年)。典型的策略会调整训练过程:例如,使用来自目标域的未标记样本来对齐目标和源分布(Ganin等人,2016;赵等,2018)。在训练期间使用目标域数据可能会导致有用的非线性,并可能通过匹配目标和源分布来减轻外推,尽管学习映射的正确性取决于标签分布(Zhao等人,2019)。

对大量未标记数据的自监督学习可以学习超出标记训练数据范围的有用非线性(Chen et al.,2020;Devlin等人,2019年;He等人,2020年;Peters等人,2018年)。因此,我们的结果提出了一个解释,为什么像BERT这样的预训练表示可以提高分布外鲁棒性(Hendrycks et al.,2020)。此外,自监督学习可以将语义相似的数据映射到相似的表示,因此映射后的一些域外实例可能会落入训练分布中。

不变模型旨在学习在多个训练分布中尊重特定不变性的特征(Arjovsky et al.,2019;Rojas Carulla等人,2018年;周等人,2021)。如果模型真的学习到了这些不变性,这可能发生在线性情况下,当存在混杂或反因果变量时(Ahuja等人,2021;Rosenfeld等人,2021),这可能从本质上增加了训练数据范围,因为模型可以忽略不变特征的变化。

分布鲁棒性考虑了数据分布的小干扰,并确保模型在这些干扰下表现良好(Goh&Sim,2010;Sagawa等人,2020年;Sinha等人,2018年;Staib&Jegelka,2019年)。相反,我们看的是更多的全局扰动。尽管如此,人们还是希望,有助于外推的修改通常也能提高对局部扰动的鲁棒性。

6结论

本文是一个初步的步骤,正式了解如何神经网络训练梯度下降外推。我们确定了MLPs和GNNs按期望外推的条件。我们还提出了一种解释,说明GNNs在复杂的算法任务中是如何能够很好地进行外推的:在架构和特性中编码适当的非线性可以帮助外推。我们的结果和假设与本文和文献中的实证结果一致

E. 页面置换算法的实验

#include <stdio.h>
#define PROCESS_NAME_LEN 32 /*进程名称的最大长度*/
#define MIN_SLICE 10 /*最小碎片的大小*/
#define DEFAULT_MEM_SIZE 1024 /*默认内存的大小*/
#define DEFAULT_MEM_START 0 /*默认内存的起始位置*/

/* 内存分配算法 */
#define MA_FF 1
#define MA_BF 2
#define MA_WF 3

int mem_size=DEFAULT_MEM_SIZE; /*内存大小*/
int ma_algorithm = MA_FF; /*当前分配算法*/
static int pid = 0; /*初始pid*/
int flag = 0; /*设置内存大小标志*/

struct free_block_type
{
int size;
int start_addr;
struct free_block_type *next;
};
struct free_block_type *free_block;

struct allocated_block
{
int pid;
int size;
int start_addr;
char process_name[PROCESS_NAME_LEN];
struct allocated_block *next;
};
struct allocated_block *allocated_block_head;

/*初始化空闲块,默认为一块,可以指定大小及起始地址*/
struct free_block_type* init_free_block(int mem_size)
{

struct free_block_type *fb;

fb=(struct free_block_type *)malloc(sizeof(struct free_block_type));
if(fb==NULL)
{
printf("No mem\n");
return NULL;
}
fb->size = mem_size;
fb->start_addr = DEFAULT_MEM_START;
fb->next = NULL;
return fb;
}

void display_menu()
{
printf("\n");
printf("1 - Set memory size (default=%d)\n", DEFAULT_MEM_SIZE);
printf("2 - Select memory allocation algorithm\n");
printf("3 - New process \n");
printf("4 - Terminate a process \n");
printf("5 - Display memory usage \n");
printf("0 - Exit\n");
}

/*设置内存的大小*/
int set_mem_size()
{
int size;
if(flag!=0)
{ /*防止重复设置*/
printf("Cannot set memory size again\n");
return 0;
}
printf("Total memory size =");
scanf("%d", &size);
if(size>0)
{
mem_size = size;
free_block->size = mem_size;
}
flag=1;
return 1;
}
/*Best-fit使用最小的能够放下将要存放数据的块,First-first使用第一个能够放下将要存放数据的块,Worst-fit使用最大的能够放下将要存放数据的块。*/
/* 设置当前的分配算法 */
/*分区分配算法(Partitioning Placement Algorithm)
*/
void set_algorithm()
{
int algorithm;
printf("\t1 - First Fit\n");/*首次适应算法(FF):。 */
printf("\t2 - Best Fit\n");/*最佳适应算法(BF): */

printf("\t3 - Worst Fit\n");
scanf("%d", &algorithm);
if(algorithm>=1 && algorithm <=3) ma_algorithm=algorithm;
/*按指定算法重新排列空闲区链表*/
rearrange(ma_algorithm);
}

void swap(int* data_1,int* data_2)
{
int temp;
temp=*data_1;
*data_1=*data_2;
*data_2=temp;
}

void rearrange_FF()
{
struct free_block_type *tmp, *work;
printf("Rearrange free blocks for FF \n");
tmp = free_block;
while(tmp!=NULL)
{
work = tmp->next;
while(work!=NULL)
{
if( work->start_addr < tmp->start_addr)
{ /*地址递增*/
swap(&work->start_addr, &tmp->start_addr);
swap(&work->size, &tmp->size);
}
else
{
work=work->next;
}
}
tmp=tmp->next;
}
}
/*按BF算法重新整理内存空闲块链表(未完成)
void rearrange_BF()
{
struct free_block_type *tmp,*work;
printf("Rearrange free blocks for BF\n");
tmp=free_block;
while(tmp!=NULL)
{
work=tmp->next;
while(work!=NULL)
{

}
}

}

*/
/*按WF算法重新整理内存空闲块链表(未完成)
void rearrange_WF()
{
struct free_block_type *tmp,*work;
printf("Rearrange free blocks for WF \n");
tmp=free_block;
while(tmp!=NULL)
{
work=tmp->next;
while(work!=NULL)
{

}
}
}
*/

/*按指定的算法整理内存空闲块链表*/
int rearrange(int algorithm)
{
switch(algorithm)
{
case MA_FF: rearrange_FF(); break;
/*case MA_BF: rearrange_BF(); break; */
/*case MA_WF: rearrange_WF(); break; */
}
}

/*创建新的进程,主要是获取内存的申请数量*/
int new_process()
{
struct allocated_block *ab;
int size;
int ret;
ab=(struct allocated_block *)malloc(sizeof(struct allocated_block));
if(!ab)
exit(-5);
ab->next = NULL;
pid++;
sprintf(ab->process_name, "PROCESS-%02d", pid);
ab->pid = pid;

printf("Memory for %s:", ab->process_name);
scanf("%d", &size);
if(size>0) ab->size=size;
ret = allocate_mem(ab); /* 从空闲区分配内存,ret==1表示分配ok*/
/*如果此时allocated_block_head尚未赋值,则赋值*/
if((ret==1) &&(allocated_block_head == NULL))
{
allocated_block_head=ab;
return 1;
}
/*分配成功,将该已分配块的描述插入已分配链表*/
else if (ret==1)
{
ab->next=allocated_block_head;
allocated_block_head=ab;
return 2;
}
else if(ret==-1)
{ /*分配不成功*/
printf("Allocation fail\n");
free(ab);
return -1;
}
return 3;
}

/*分配内存模块*/
int allocate_mem(struct allocated_block *ab)
{
struct free_block_type *fbt,*pre,*r;
int request_size=ab->size;
fbt=pre=free_block;
while(fbt!=NULL)
{
if(fbt->size>=request_size)
{
if(fbt->size-request_size>=MIN_SLICE)
{
fbt->size=fbt->size-request_size;
}
/*分配后空闲空间足够大,则分割*/

else
{
r=fbt;
pre->next=fbt->next;
free(r);
/*分割后空闲区成为小碎片,一起分配*/

return 1;
}
}
pre = fbt;
fbt = fbt->next;
}

return -1;
}

/*将ab所表示的已分配区归还,并进行可能的合并*/
int free_mem(struct allocated_block *ab)
{
int algorithm = ma_algorithm;
struct free_block_type *fbt, *pre, *work;

fbt=(struct free_block_type*) malloc(sizeof(struct free_block_type));
if(!fbt)
return -1;
fbt->size = ab->size;
fbt->start_addr = ab->start_addr;
/*插入到空闲区链表的头部并将空闲区按地址递增的次序排列*/
fbt->next = free_block;
free_block=fbt;
rearrange(MA_FF);
fbt=free_block;
while(fbt!=NULL)
{
work = fbt->next;
if(work!=NULL)
{
/*如果当前空闲区与后面的空闲区相连,则合并*/
if(fbt->start_addr+fbt->size == work->start_addr)
{
fbt->size += work->size;
fbt->next = work->next;
free(work);
continue;
}
}
fbt = fbt->next;
}
rearrange(algorithm); /*重新按当前的算法排列空闲区*/
return 1;
}

/*?释放ab数据结构节点*/
int dispose(struct allocated_block *free_ab)
{
struct allocated_block *pre, *ab;

if(free_ab == allocated_block_head)
{ /*如果要释放第一个节点*/
allocated_block_head = allocated_block_head->next;
free(free_ab);
return 1;
}
pre = allocated_block_head;
ab = allocated_block_head->next;

while(ab!=free_ab)
{
pre = ab;
ab = ab->next;
}
pre->next = ab->next;
free(ab);
return 2;
}
/*查找要删除的进程*/
struct allocated_block* find_process(int pid)
{
struct allocated_block *temp;
temp=allocated_block_head;
while(temp!=NULL)
{
if(temp->pid==pid)
{
return temp;
}
temp=temp->next;
}
}

/*删除进程,归还分配的存储空间,并删除描述该进程内存分配的节点*/
void kill_process()
{
struct allocated_block *ab;
int pid;
printf("Kill Process, pid=");
scanf("%d", &pid);
ab=find_process(pid);
if(ab!=NULL)
{
free_mem(ab); /*释放ab所表示的分配区*/
dispose(ab); /*释放ab数据结构节点*/

}
}

/* 显示当前内存的使用情况,包括空闲区的情况和已经分配的情况 */

int display_mem_usage()
{
struct free_block_type *fbt=free_block;
struct allocated_block *ab=allocated_block_head;
if(fbt==NULL) return(-1);
printf("----------------------------------------------------------\n");

/* 显示空闲区 */
printf("Free Memory:\n");
printf("%20s %20s\n", " start_addr", " size");
while(fbt!=NULL)
{
printf("%20d %20d\n", fbt->start_addr, fbt->size);
fbt=fbt->next;
}
/* 显示已分配区 */
printf("\nUsed Memory:\n");
printf("%10s %20s %10s %10s\n", "PID", "ProcessName", "start_addr", " size");
while(ab!=NULL)
{
printf("%10d %20s %10d %10d\n", ab->pid, ab->process_name, ab->start_addr, ab->size);
ab=ab->next;
}
printf("----------------------------------------------------------\n");
return 0;
}

**********************************************************************
楼主啊,小女子给你的是残缺版滴,要是你给我分,我就把剩下滴给你,上次在北京大学贴吧都被人骗了,世道炎凉啊O(∩_∩)O~

热点内容
闲鱼和安卓哪个赚钱 发布:2025-05-17 21:15:56 浏览:583
c语言一个c源程序 发布:2025-05-17 21:11:44 浏览:314
如何加密手机的文件 发布:2025-05-17 21:11:43 浏览:915
ios开发文件上传 发布:2025-05-17 21:10:40 浏览:983
g92编程 发布:2025-05-17 21:00:31 浏览:170
汇编语言第三版脚本之家 发布:2025-05-17 20:54:26 浏览:399
资源配置最佳状态叫什么 发布:2025-05-17 20:48:58 浏览:84
定义dns服务器的ip 发布:2025-05-17 20:32:37 浏览:954
android判断图片 发布:2025-05-17 20:32:33 浏览:833
安卓12什么时候适配小米 发布:2025-05-17 20:31:47 浏览:71