零点看书

字: 大 中 小
关灯 护眼
零点看书 > 燕归来 > 第一卷少年游 第八十八章异步

第一卷少年游 第八十八章异步

第一卷少年游 第八十八章异步 (第1/2页)

第二天早晨,顾老师没有给十五个人发新题,只让他们把前一天下午没做完的那道电磁问题带回来。
  
  黑板上还是那张已经被他拆得很难看的区域图:边界弯弯曲曲,材料性质在不同位置也不一样,原先那些能让计算一下子变漂亮的对称条件几乎全被拿掉了。昨天江遥最后留下的想法,是把整个区域拆成许多小块,每一个小块只处理附近的信息,再让相邻区域彼此传递结果。她回宿舍以后又想过一阵,觉得这个办法至少有一个很直观的好处:如果一张巨大的地图难以一次看清,也许可以让许多人各守一小块地,每个人只和邻居交换消息,最后慢慢拼出整张地图。
  
  顾老师开课以后却没有让他们继续算,而是在黑板上画了六个圆点,用线把相邻的点连起来。
  
  “现在不谈电磁。”他说,“假设这六个人各自有一个数字,而且谁也看不见全局。每个人只能和直接相连的邻居说话。我们希望过一段时间以后,他们都得到同一个数,这个数接近六个人最初数字的平均值。你们会怎么做?”
  
  这个问题一下子简单了许多。有人马上说,每个人把自己的数字告诉邻居,再取平均;下一轮继续交换,反复做下去,差距就可能越来越小。顾老师让他们真的试。六个人各代表一个点,把自己的数字写在纸上,每一轮只允许看左右相邻者,再更新一次。开始时有人是二,有人是十九,有人是负三,几轮以后,最大的数开始往下走,最小的数开始往上走,原来相差很大的六张纸渐渐靠到一起。
  
  韩思遥不在核心组,这种课堂少了她一句“大家最后都变得没个性了”,反倒让江遥觉得有点安静。她看着那些数字逐渐接近,很容易理解这里发生了什么:没有任何人知道六个数的总和,也没有一个中央裁判负责计算平均值,可每个人只根据局部邻居做一点调整,整体依然可能慢慢达成一致。
  
  顾老师等他们做完,忽然问:“如果不是所有人同时更新呢?”
  
  有人抬头。
  
  “什么意思?”
  
  “刚才我喊一、二、三,你们一起看邻居,一起算,一起写新数。现在不喊了。有人算得快,有人算得慢;有人这轮已经写了新数,旁边那个人还拿着上上一轮的数据。消息传过去也可能晚一点。还会不会收敛?”
  
  教室里一下安静下来。
  
  江遥第一反应觉得应该还是会,只不过慢一些,可真正模拟起来马上出了问题。六个人不再统一听口令,而是各自按照自己“收到”的最新数字更新。有人两秒一次,有人五秒一次,顾老师还故意扣下一两张传递纸条,隔一会儿才递出去。整个过程立刻变得混乱:某个人刚把自己的值往十调整,邻居却还拿着他几分钟前的五继续计算;另一个人连续更新两次后,旁边的人才收到第一条消息。纸面上再也没有整齐的一轮、一轮,只有一串互相穿插的变化。
  
  “现在谁能告诉我这是第几轮?”顾老师问。
  
  没人能回答。
  
  因为“第几轮”这个东西已经不存在了。
  
  江遥突然觉得这个变化比前面的计算本身更有意思。刚才所有人同时更新时,他们其实偷偷拥有了一个全局时钟。虽然没有人知道全局数值,却至少知道现在大家都在进行同一步。这个条件太自然,以至于第一遍做题的时候几乎没人把它当成条件。等顾老师把统一节奏拿掉,他们才发现,所谓“只靠局部信息”还远远不够;你甚至不能默认别人和你生活在同一个时刻。
  
  六个人又试了几轮。数值仍然有逐渐接近的趋势,但速度明显慢了,有时还会短暂往反方向走。一个节点刚接近大家,收到一条迟到的旧消息以后又被拉开。许观澜提出给每条消息加上时间标记,至少让接收者知道这是不是旧信息;陆徊则说,如果所有旧消息都直接丢掉,会不会有些节点因为网络太慢,长时间几乎不参与。简宁很快发现,真正的问题已经不是“怎么算平均值”,而是“在不知道别人什么时候更新、消息什么时候到的情况下,什么规则还能保证大家最后不要彻底跑散”。
  
  江遥开始在灰色本子上画时间线。
  
  她没有急着写公式,只画六条横线,每一条代表一个节点。某条消息从第一条线上发出,过了一段时间才落到第三条线上;另一条消息稍晚发出却先到。图画完以后,原本看起来抽象的“异步”突然变得像生活里极常见的事:两个人同时给第三个人发消息,先发的不一定先被看见;一个人正在依据旧信息做决定时,另一个人的状态可能已经变了。
  
  顾老师这时才在黑板角落写下“异步”两个字。
  
  他没有讲任何正式定义,只说:“真实系统经常没有一个人站在外面喊一、二、三。不同部分各做各的,消息也有延迟。如果一个办法只有所有人同时动作才成立,那它能用的地方会少很多。”
  
  江遥抬头看着黑板,脑子里却忽然闪过很多并不属于这堂课的东西。蚂蚁不会等全体集合后再统一出发,鸟群转弯时也不可能先召开一次会议;城市里的五个传感器更不会保证每一秒都同时上传;甚至她和原既白现在的聊天,也越来越不像以前那样有一段完整、同步的晚上。她发出一句话时,他可能正在考试;他凌晨做完实验后留下的结果,她第二天早晨才看到。两个人并没有因此“失去联系”,只是联系早就不再依赖同一个时刻。
  
  这个联想很快被她压下去。课堂上的问题首先还是课堂上的问题。
  
  上午后半段,十五个人被分成三组,每组都要设计一套在这种“没人统一喊口令”的情况下仍能工作的局部规则。江遥所在这一组很快提出一个直观方案:每个节点收到邻居新值后,不直接替换自己的数,而只往对方靠一点;消息越旧,影响越小。这样就算偶尔收到迟到信息,也不至于一下把自己拖回很远。
  
  第一次模拟效果不错。
  
  第二次,顾老师让一个节点断开了三分钟。
  
  剩下五个仍然逐渐接近,等那个失联节点重新接入以后,系统又开始调整。江遥原以为这是好事,可很快发现另一个问题:失联节点带回来的是一个和其他人差距很大的旧值,它重新加入以后,相当于整个系统突然又被塞进一块过去。大家当然可以慢慢把它拉回来,可如果节点不断掉线、重连,所谓“最终一致”就变得越来越难判断。
  
  沈策说:“那就把掉太久的人权重降低。”
  
  方禾马上反问:“降低多少?如果掉线的是最重要的数据呢?”
  
  “数字哪有重要不重要?”
  
  “现在是平均值没有。换成别的问题就有。”
  
  江遥没有参加这两句争论,她正看着那条重新接入的时间线。她忽然想到,如果一个系统允许局部不断加入、退出,可能真正应该追求的就不是“某一刻所有人完全一样”。在持续变化的世界里,绝对一致或许本身就是不现实的目标。更有意义的问题可能是:即使每个人看到的都是稍微不同、稍微滞后的世界,整体是否还能保持在一个不会失控的范围内?
  
  她把这个想法说出来以后,简宁先皱眉:“那不是降低标准吗?”
  
  “也可能是换标准。”江遥说,“如果系统永远在动,你要求所有人任何时候都完全一样,可能本来就做不到。比如一群人往前走,每个人的位置肯定不一样,但可以保持同一个大方向。”
  
  陆徊说:“那得先定义多不一样还算没散。”
  
  “对。”
  
  几个人又绕回计算。
  
  顾老师一直到最后才点评。他没有宣布谁的方案最好,只指出三组都犯了一个相似错误:一开始大家总想恢复那个已经被拿掉的中央节奏,给消息编号、补时钟、等待慢节点,本质上都在试图重新制造“大家一起走”的条件。这些办法有时当然必要,但如果系统规模足够大、延迟无法控制,等最慢的人本身就会变成代价。
  
  “有时候,”他说,“你们不是要把现实改造成一个同步系统,而是要学会在不同步里工作。”
  
  这句话让江遥在灰色本子上停了很久。
  
  她没有抄。
  
  因为它太像一句适合被单独划线的话,她现在对这种句子已经本能地有点警惕。她只把上午那六条时间线继续补完整,在旁边写下两个问题:**什么时候必须等别人?什么时候不等也可以继续?**
  
  ---
  
  原既白那边,几乎在同一周遇到了一个更加难看的版本。
  
  自动测试系统经过前几轮改造以后,终于可以连续运行,不再因为磁盘写满或者单个任务卡死就整体停摆。宋弈于是做了一件他们之前一直没有胆子做的事:把两个不同版本的模型同时接进去,让测试器并行跑。
  
  本意很简单。他们想比较同一批自动生成的测试,在模型A和模型B上分别会发现什么弱点。按原既白最初设计,每个任务生成一张测试图片以后,同时发给两个模型,两边都返回结果,再统一写入数据库。只要把模型版本记清楚,后面便能比较。
  
  第一晚看起来一切正常。
  
  第二天上午,结果开始出现无法解释的矛盾。
  
  同一张图片在日志里有三次记录,两次显示模型A判断正确,一次却显示模型B输出;某些测试任务标记的是A版本,真正调用的模型进程却已经在半小时前被替换成新权重;还有一批图片生成时依据的是旧模型的弱点,等真正进入评测队列,模型已经更新,结果当然和搜索时完全对不上。
  
  宋弈看着数据库里那些互相打架的记录,第一反应是:“是不是写错标签了?”
  
  查了半天,标签本身没有写错。
  
  真正的问题出在时间。
  
  模型训练、测试生成、任务调度和结果写入四件事并不是按一条整齐的流水线一步一步发生。有些测试任务生成很快,有些慢;模型更新后,队列里仍然躺着按照旧版本生成的任务;某个进程重启以后拿到的是新模型,任务本身却还认为自己在测试旧模型。每一个小模块单独看都“做对了”,组合起来却产生了一批连他们自己都无法再解释的结果。
  
  原既白第一次完整画出时间线时,沉默了好一会儿。
  
  宋弈说:“要不每次模型一更新,就把旧队列全清掉。”
  
  “可以。”
  
  “那不就完了?”
  
  “旧任务全浪费。”
  
  “总比结果不能信好。”
  
  原既白没有反驳。他一开始也倾向于这么做:模型版本变了,就停掉所有测试,清空队列,从头开始。这样最干净,最容易保证一致。可他们很快算了一下,如果以后模型更新频率更高,长时间任务不断被清空,系统大部分时间都在重复做已经做过的事。更何况有些旧任务本身仍有价值,因为比较同一测试在新旧模型上的变化,恰好能告诉他们模型升级以后哪些弱点消失、哪些弱点又出现。
  
  真正需要做的,不是让整个系统每次都停下来等所有东西对齐,而是让每一条结果都能回答:它是在什么模型、什么数据、什么测试器版本和什么时间条件下产生的。
  
  宋弈听完说:“所以不要求大家一起变,但必须知道自己跟谁生的?”
  
  原既白抬头看他。
  
  “你这个说法很难听。”
  
  “能懂就行。”
  
  确实能懂。
  
  他们开始给每一个结果附上完整的“来历”:这张测试图由哪个测试器版本生成,生成时针对的是哪个模型,真正执行时用的又是哪一个模型,数据集版本是什么,任务何时进入队列、何时运行。原本一行结果只需要图片编号和预测值,现在后面多出一长串看起来很烦的元数据。
  
  宋弈抱怨说他们是在给每一张图片办身份证。
  
  原既白却越来越觉得这些“身份证”比想象中重要。一个数字本身几乎什么都不说明。模型准确率从九十二降到八十八,如果不知道测试集有没有变、模型版本有没有变、数据处理有没有变,这四个百分点根本不能直接比较。系统越复杂,“同一个结果”背后可能来自的路径越多,而路径一旦丢掉,很多事实就会变成看起来精确、实际上无法追溯的数字。
  
  叶老师看完新版以后,问的第一件事是:“如果一个任务跨了两个模型版本怎么办?”
  
  原既白已经有准备:“结果不覆盖,分开记。”
  
  “如果测试生成基于A,执行时模型已经是B?”
  
  “也记清楚。它不再是A的纯测试,但可以作为A生成、B执行的一类迁移测试。”
  
  “谁解释?”
  
  “报告层解释,不让底层数据自己假装是一回事。”
  
  叶老师这次没有继续追。
  
  

(本章未完,请点击下一页继续阅读)
『加入书签,方便阅读』
热门推荐
泥泞 极品全能学生 都市极品医神 永恒圣王 文明之万界领主 妖怪茶话会 我娘子天下第一 带着农场混异界 花豹突击队 樱花之国上的世界末日