2018年5月7日星期一

程序员社区骂战:不满政治正确,LLVM元老宣布退出

Root 发自 凹非寺量子位 出品 | 公众号 QbitAI

上周,有件事在程序员的圈子里炸开了锅。

对LLVM(众多语言编译器的后台)有巨大贡献的元老级程序员Rafael Ávila de Espíndola忿忿不平地写了封邮件,宣布自己要立刻马上退出LLVM社区,注销账号。

Rafael退出的原因主要有两个。

一是LLVM社区最近推行的《社区行为守则(LLVM Community Code of Conduct)》。

守则里规定,社区里的程序员之间必须要互相尊重,如果有人不认同这个守则,那么就没有资格参加会议。

他认为这个规定本身就很分裂,自相矛盾。

守则一方面倡导大家要包容不同的意见和声音,但另一方面又说,谁不同意这个守则就要剥夺他参加社区会议的资格。

第二个他看不过眼的点是,LLVM社区合作的Outreachy实习项目公然搞性别种族歧视。

Outreachy实习项目的网页显示,实习生申请人必须满足两个条件的任一个:女性(天生的或者变形的都可以),变形为男性的女性,以及无性别者,或是非裔、拉丁裔等少数种族。

换句话说,如果你是一个亚裔男子或者白种男子,就没有资格申请这个实习项目。

Rafael认为,这种做法是赤果果的另一种"种族"歧视。

这一下搞得LLVM社区很多人都很紧张,其中Renato Golin公开回信说:

知道Rafael你要离开社区,我特别难过。我知道这决定对你来说,一定不容易。因为不满社区内部制度,你就要离开这个技术圈子,可见你的决心。但我之所以推行这个《社区行为守则》,就是想修正社会不公的现象。可惜因为我不够了解社交模式及规律,我一辈子都和社会不公的现象作抗争。你的退出,对所有人来说都不是件好事。这次事件给大家很大的舆论压力以及负面影响。我希望我们能私底下好好谈一谈,相信我们可以一起解决这个问题的。

事件始末

本来,LLVM推出《社区行为守则》的初衷是好的。

GitHub曾在去年做了一次问卷调查,有超过5000个开发者参与。

结果显示,有18%的开发者认为在开源社区里受到了言语上的人身攻击。有50%的人称,见过其他人之间发生争执。

比方说,说话很难听,爆粗,指名道姓玩针对,以及给别人贴标签。超过40%的开发者说他们有和其他人起过冲突。

为了改善LLVM开发者社区的互动环境,LLVM项目的另一发起人,Tanya Lattner才有心促进社区守则的落成。

LLVM项目的主要发起人,也是Clang编译器的作者,属于大神级别的程序员Chris Lattner在公开回应中解释,他最在意的是LLVM社区能否长久的稳定。

他希望制定一些底层的原则,保证社区的良好运行。哪怕有一天LLVM的几个主要核心人物离开了,这个社区也不受影响。

这才引入了《社区行为守则》。守则里主要强调,社区的程序员之间要包容不同的意见和声音,和别人沟通的时候言语友善一些,不要进行人身攻击。

至于种族歧视,他坦承在这个问题上,自己并不是个专家。他的本意是希望增加社区思想的多样性。他明确指出,他认同Rafael的部分观点:Outreachy实习项目中的政策确实是变相的种族歧视。LLVM应该在这点上做出修正。

另外,Chris也反驳Rafael第一diss的点:LLVM并没有因为Rafael不同意守则就把他踢出会议。

在这点上,Chris觉得Rafael可能是对守则有什么误会。

他反复在好几次公开回应中邀请Rafael,希望有机会能坐下来,好好谈谈。

舆论掀起的狂风巨浪

可万万没想到,Rafael的退出,引发了程序员的群骂。

想围观骂战的,请前往评论区:https://ift.tt/2rfJAbq

很多人赞同Rafael的观点,认为这个守则是个狗屁(Bullshit)。只有当一个人心里是有把尺子去衡量身边的人的时候,才会说,我们不以xx取人。

否则,就像Rafael说的,LLVM成立之初,大家都是凭本事行走江湖,根本没有人意识到对方的种族或者性别的不同。

如果某个地方拉横幅喊口号,强调"我们要讲诚信"。那么潜台词是什么,大家心底都清楚:)

可以倡导大家怎么做会更好。但是搞一个规定出来,还强制要求每个人都按这个标准去遵守,否则违者踢"群",这样的做法太恶心了。只允许一种思想形态存在的做法本身就很危险,"政治正确"会营造出一个非常恐怖的氛围。

大家群攻的点主要是:凭单一标准去维护社会正义的战士(Social Justice Warriors),是一种相当可怕的存在。

作为programmer,你怎么看?

最后,附事件始末介绍:https://ift.tt/2rnMcDj

欢迎大家关注我们的专栏:量子位 - 知乎专栏

诚挚招聘

量子位正在招募编辑/记者,工作地点在北京中关村。期待有才气、有热情的同学加入我们!相关细节,请在量子位公众号(QbitAI)对话界面,回复"招聘"两个字。

量子位 QbitAI · 头条号签约作者

վ'ᴗ' ի 追踪AI技术和产品新动态



via 量子位 - 知乎专栏 https://ift.tt/2rraZ9x
RSS Feed

RSS5

IFTTT

程序员社区骂战:不满政治正确,LLVM元老宣布退出

Root 发自 凹非寺量子位 出品 | 公众号 QbitAI

上周,有件事在程序员的圈子里炸开了锅。

对LLVM(众多语言编译器的后台)有巨大贡献的元老级程序员Rafael Ávila de Espíndola忿忿不平地写了封邮件,宣布自己要立刻马上退出LLVM社区,注销账号。

Rafael退出的原因主要有两个。

一是LLVM社区最近推行的《社区行为守则(LLVM Community Code of Conduct)》。

守则里规定,社区里的程序员之间必须要互相尊重,如果有人不认同这个守则,那么就没有资格参加会议。

他认为这个规定本身就很分裂,自相矛盾。

守则一方面倡导大家要包容不同的意见和声音,但另一方面又说,谁不同意这个守则就要剥夺他参加社区会议的资格。

第二个他看不过眼的点是,LLVM社区合作的Outreachy实习项目公然搞性别种族歧视。

Outreachy实习项目的网页显示,实习生申请人必须满足两个条件的任一个:女性(天生的或者变形的都可以),变形为男性的女性,以及无性别者,或是非裔、拉丁裔等少数种族。

换句话说,如果你是一个亚裔男子或者白种男子,就没有资格申请这个实习项目。

Rafael认为,这种做法是赤果果的另一种"种族"歧视。

这一下搞得LLVM社区很多人都很紧张,其中Renato Golin公开回信说:

知道Rafael你要离开社区,我特别难过。我知道这决定对你来说,一定不容易。因为不满社区内部制度,你就要离开这个技术圈子,可见你的决心。但我之所以推行这个《社区行为守则》,就是想修正社会不公的现象。可惜因为我不够了解社交模式及规律,我一辈子都和社会不公的现象作抗争。你的退出,对所有人来说都不是件好事。这次事件给大家很大的舆论压力以及负面影响。我希望我们能私底下好好谈一谈,相信我们可以一起解决这个问题的。

事件始末

本来,LLVM推出《社区行为守则》的初衷是好的。

GitHub曾在去年做了一次问卷调查,有超过5000个开发者参与。

结果显示,有18%的开发者认为在开源社区里受到了言语上的人身攻击。有50%的人称,见过其他人之间发生争执。

比方说,说话很难听,爆粗,指名道姓玩针对,以及给别人贴标签。超过40%的开发者说他们有和其他人起过冲突。

为了改善LLVM开发者社区的互动环境,LLVM项目的另一发起人,Tanya Lattner才有心促进社区守则的落成。

LLVM项目的主要发起人,也是Clang编译器的作者,属于大神级别的程序员Chris Lattner在公开回应中解释,他最在意的是LLVM社区能否长久的稳定。

他希望制定一些底层的原则,保证社区的良好运行。哪怕有一天LLVM的几个主要核心人物离开了,这个社区也不受影响。

这才引入了《社区行为守则》。守则里主要强调,社区的程序员之间要包容不同的意见和声音,和别人沟通的时候言语友善一些,不要进行人身攻击。

至于种族歧视,他坦承在这个问题上,自己并不是个专家。他的本意是希望增加社区思想的多样性。他明确指出,他认同Rafael的部分观点:Outreachy实习项目中的政策确实是变相的种族歧视。LLVM应该在这点上做出修正。

另外,Chris也反驳Rafael第一diss的点:LLVM并没有因为Rafael不同意守则就把他踢出会议。

在这点上,Chris觉得Rafael可能是对守则有什么误会。

他反复在好几次公开回应中邀请Rafael,希望有机会能坐下来,好好谈谈。

舆论掀起的狂风巨浪

可万万没想到,Rafael的退出,引发了程序员的群骂。

想围观骂战的,请前往评论区:https://ift.tt/2rfJAbq

很多人赞同Rafael的观点,认为这个守则是个狗屁(Bullshit)。只有当一个人心里是有把尺子去衡量身边的人的时候,才会说,我们不以xx取人。

否则,就像Rafael说的,LLVM成立之初,大家都是凭本事行走江湖,根本没有人意识到对方的种族或者性别的不同。

如果某个地方拉横幅喊口号,强调"我们要讲诚信"。那么潜台词是什么,大家心底都清楚:)

可以倡导大家怎么做会更好。但是搞一个规定出来,还强制要求每个人都按这个标准去遵守,否则违者踢"群",这样的做法太恶心了。只允许一种思想形态存在的做法本身就很危险,"政治正确"会营造出一个非常恐怖的氛围。

大家群攻的点主要是:凭单一标准去维护社会正义的战士(Social Justice Warriors),是一种相当可怕的存在。

作为programmer,你怎么看?

最后,附事件始末介绍:https://ift.tt/2rnMcDj

欢迎大家关注我们的专栏:量子位 - 知乎专栏

诚挚招聘

量子位正在招募编辑/记者,工作地点在北京中关村。期待有才气、有热情的同学加入我们!相关细节,请在量子位公众号(QbitAI)对话界面,回复"招聘"两个字。

量子位 QbitAI · 头条号签约作者

վ'ᴗ' ի 追踪AI技术和产品新动态



via 量子位 - 知乎专栏 https://ift.tt/2rraZ9x
RSS Feed

RSS5

IFTTT

Ian Goodfellow畅谈,离散的失败与连续的失败

花栗子 编译自 Veronikach量子位 出品 | 公众号 QbitAI

五月了,美国研究生申请季也差不多过去了。不知道大家有没有成功脱离失学儿童团。

Ian Goodfellow是来自谷歌大脑的科学家。作为GAN的爸爸,他也是MIT科技评论选中的"35 under 35"中的一员。

不过,背着金光闪闪履历的他,就是爱讲自己的被拒史。大概,也是想给失落的人类一些虚无的希望吧。

这一次,他光顾了最适合秀失败的场所之一,访谈节目How I Fail,接受了金发碧眼的助理教授维罗妮卡 (Veronika Cheplygina) 的黄金12问。

看看,除了被MIT放凉之外,Goodfellow还享受了怎样的失败——

实践篇

怎样描述自己的工作?

G:我是谷歌的AI研究人员,手底下还有一群小伙伴。我们就是要努力理解,AI是怎样失败的,这样才能建立一套清晰的工程原则,对AI开发负责。

我把大量的精力花在研究怎样让AI更加安全上——比如怎样防止黑客欺骗AI系统,去做他们想做的事情。

怎样描述这份非官方履历?

G:我的小伙伴Moritz Hardt发推告诉大家,一段成功的科研事业,往往是从收到一大摞厉害的研究生院的拒信开始。

然后,我就列出了自己被拒的经历,回应了他。但那些 (上拉至推特截图) 经历并不是我完整的被拒旅程,以下这一份可能比较全——

· 那时候,还在斯坦福读本科的我,生物和化学都略显捉急,但还是打算从事神经学方面的工作。成绩是过得去,但感觉要当教授的话这分数还是不够好。

· 把重心移到计算机上之后,我就申请了几份本科生的实习,谷歌当时没要我

· 我还申请过一份跟着斯坦福教授工作的实习,申请的时候提交了成绩单。教授回复说,我的课你怎么得的A?

以我的成绩确实拿不到A,我还以为是curve太善良了,然而事实是系统出现了问题。结果学校就把我的成绩改下去了

· 有几家大型科技公司给了我实习,但不是做机器学习,也不是计算机视觉。简历里面,大家是看不到这些的,只能看到最后的成功。

不过,我也很感谢Willow Garage和斯坦福的CURIS项目,给了我关于机器人视觉的暑期实习机会。

· 读研和读博的时候,我基本上没有过校外的fellowship。这就是说,我得当助教,或者选择专业相关的其他校内工作,很难把精力集中在自己的研究兴趣上。

那时,我一直在申像魁北克的PBEEE这样的fellowship。从09年开始的四年时间里,不停地尝试,从来没成功过。

直到13年,才从谷歌那里拿到了第一个深度学习的Fellowship。

· 读博期间,我的论文投到像ECCV这样的各种视觉会议,基本上都是被拒。我在机器人感知上做了很多,但都是不见天日。

怎样碾压挫折?

G:高中时期,我有三年都在学校的辩论队。两个教练很厉害,一个是Kerry Koda,一个是Thomas King。

我也很惊讶,这段经历居然可以在好几个不同的方面,给我的科研带来帮助。

光是对抗挫折,所有辩手都要训练,怎样从情感上对待失败。每一轮辩论都有输赢,没有谁可以一直赢。

如果长期受到辩论环境的浸染,就会习惯这种节奏,输掉一轮之后很快进入下一轮。输赢都属于动态平衡。

罗列失败=秀优越?

G:我发关于失败的推文,观众似乎都没有这样的感觉。也有一些人,还会谢谢我分享这些经历。

人们有这样的想法我完全可以理解,但我觉得大多数观众还是可以理解,我是希望帮助大家逃脱冒名顶替综合征 (Impostor Syndrome)。

不愿分享成功?

V:另一方面,你觉得人们会不会因为对失败习以为常,而不去分享自己的成功?

G:不会,我们基本上都是被动分享,不管是工作总结,还是申请资金的时候。

往会议和期刊投论文的时候,每个人都会用上自己的全部能量,尽情把成功的地方表现出来,把不太成功的部分都扫到地毯下面去。

我个人还是会尽力削弱这样的动力,但它还是不会很快就消失的。

哲学篇

离散的还是连续的?

V:之前,我们都是用一些离散的点,比如获得职位或者发表论文,来描述成功和失败。有没有其他类型的失败呢?

G:其实,我觉得那些离散的点,大多不是很重要。

我在推特上发过,申研究生的时候拒过我的学校列表,但那都还好,因为还是有很多学校录了我

比如,2009年我遇到最大的困境,不是收到MIT和CMU的拒信;而是不知道自己能不能在拿到录信的学校,比如斯坦福和伯克利,做起自己想做的研究

那时候很方,不知道我会跟着哪位教授,因为博士生有轮换制度,录信里面都没有明确的导师。于是,我跑去了蒙特利尔大学,提前把Yoshua Bengio锁定为我的导师。

读博时期,最大的困境是,我的大部分时间都花在,用无监督特征学习方法,来解决计算机视觉的监督学习问题。Alex, Ilya和Geoff赢了ImageNet比赛,我就懵B了。

耗费时间写那种钻进死胡同的论文,可能就是主要的失败了。

我的研究如果能影响其他人,那就是成功,即便被大会拒了也没关系。如果一项研究产生不了什么影响,就算在大会上发表了也可以算失败。

今天你失败了么?

V:有什么正在经历的失败么?或者对未来有什么犹疑?

G:4年了,我一直想了解,为什么神经网络那么容易被input里一点小小的干扰"迷乱心智"。怎么才能在这种情况下,建立一个高准确度的模型,没有谁知道。

从传统观点来看成败,今年ICML审稿很严,感觉我投的论文基本都没戏了。

但在一个美好的日子,我可能会写出三五个想法,然后感觉它们都实现不了。每个想法的时间成本不高,我可以尝试很多完全不同的想法。某些想法上的失败,也就是我工作流程里最普通的一部分。

怎样才算成功?

V:要评判一个研究人员是否成功,你觉得成果的发表应该在评判标准里占到多大比重?有没有其他因素容易被忽略?

G:我们对成功的评判,可能会让这个领域错过许多成功人士。

举个栗子,我们要花很长时间来评估研究成果和研究人员,但我们没有花多少时间去考察这个评估过程本身

没有谁有义务去保证,大会的审稿是公平的是准确的。

从2014年NIPS的一致性实验里面,可以看出审稿流程还是有不少噪音的。可是从结果来看,并没有人要致力于制定出更好的审查流程。

升华篇

ML的失败,不是普通的失败?

V:你觉得机器学习领域跟失败之间的关系,和其他领域有什么不同?这会不会对不同人群产生不同的影响?

G:机器学习领域的期待值很高,因为这里总是可以快速产生很厉害的研究成果,并且能够帮助其他人快速产生研究成果。

比如,Ilya Sutskever在谷歌学术里,已经被引用过5万多次了;再看数学领域,最近的四位菲尔茨奖得主,没有一个引用数超过5千

我们这个领域,成功是爆发式的,这一点有些奇怪。一部分原因可能是,我们太爱用Arxiv.org了,而其他领域的研究人员可能更偏爱同行评审过的论文。

不过说实话,我也不知道这个现象会对不同人群产生什么样的影响。

怎么看待ML的负面/阴性结果?

G:机器学习很难从负面结果里获得价值,因为我们一般都不知道负面结果是怎样造成的。

得到负面结果,可能是想法从根本上就错了,也可能是因为一个很小的bug。不幸的算法,各有各的不幸。

想和ML老炮说什么?

G:我想跟他们说,关于某个想法的贡献应该怎样分配,学界需要一个更好的方式来处理争议。

现状是,那些自认没有获得应有的引用或者点名的人,得为自己维权

如果只是论文作者失误漏掉了,那还好说。但如果双方争执不下,场面就十分尴尬。

没有权威机构来裁决,协商又无果的情况下,大家只能回归"是胡萝卜还是大棒"的选择,可是大多数人也给不起胡萝卜。

一个资深教授,如果要向一个博士生要出处,压力就很大了。我受到的关注越多,也就要花越多的时间处理这种事。

如果某个会议或者期刊能生出一个部门,以第三方视角专门解决这样的争议,情况可能就会乐观很多。

想跟过去的自己说什么?

G:快去用GPU挖矿啊。

采访结束了,重要的信息可能有很多,但我在意的是,为什么我碰不上系统bug给我个A的好事?

欢迎大家关注我们的专栏:量子位 - 知乎专栏

诚挚招聘

量子位正在招募编辑/记者,工作地点在北京中关村。期待有才气、有热情的同学加入我们!相关细节,请在量子位公众号(QbitAI)对话界面,回复"招聘"两个字。

量子位 QbitAI · 头条号签约作者

վ'ᴗ' ի 追踪AI技术和产品新动态



via 量子位 - 知乎专栏 https://ift.tt/2rvYs4P
RSS Feed

RSS5

IFTTT

Chrome暗藏的恐龙跳一跳,已经被AI轻松掌握了

夏乙 郭一璞 发自 凹非寺量子位 出品 | 公众号 QbitAI

什么!未连接到互联网!!

明明是联网状态,为什么我想访问的页面

无!法!打!开!

淡定。

作为一个Google Chrome浏览器的用户,当你看到上面那个页面时,不要沮丧。换个角度一想,墙内还能有更多的Play时间哦~

你有没有注意到画面里那个小恐龙?

当你遇到打不开网页的时候,只需要再点击一下这个页面(手机),或者按下空格(电脑),随着小恐龙轻轻一跳——

一个新世界开启了。

这个"恐龙跳一跳"其实是藏在Chrome浏览器里好多年的一个彩蛋。小恐龙是一只霸王龙(T-Rex)。

2013年Chrome开始用这个小恐龙的图像代替令人烦恼的404页面。2014年秋天,这只恐龙被正式改造成一个横版小游戏。以彩蛋的方式隐藏在新版Chrome浏览器里。

呐,如果你还不知道这个彩蛋,可以抓紧试一试。比方说——

  • 访问一个不翻墙就看不了的网页
  • 或者直接输入:chrome://dino
  • 或者访问:Chrome dino game (需翻墙)

后来,这个小游戏也成了不少AI练手的对象。

比如最近就有人在YouTube上贴了一段视频,展示了他如何用神经网络+遗传算法,让一个AI系统独秀于浏览器之中。

我们把精华的部分截取了一下,就是下面这段视频。

动图版:

视频版:

AI玩恐龙跑_腾讯视频

总而言之,一句话,这个AI能轻松玩到2万多分……

你能玩到几分?大概率是玩不到这个成绩的吧。毕竟在chromedino.com页面上,人类玩家的历史最高分是18842

不过,上传这段视频的作者,并没有详细公布他用的方法,当然也没有给出一个开源的地址。不过不要紧,也有别人公开分享了更多细节。

例如,GitHub上就有一个开源的代码"IAMDinosaur",同样也是利用神经网络+遗传算法,来搞定恐龙跳一跳。

地址在此:ivanseidel/IAMDinosaur

美中不足,上面这个项目也没有配上太详尽的解读。然而好消息是,最近有个国外的小哥Ravi Munde,列了一份非常详尽的教程。

这个教程用的方法是强化学习中的Q-learning,比较适合入门练手,而且对硬件的要求不高。

量子位搬运这份教程如下。

Q-learning了解/复习一下

对动物来说,强化学习的能力是与生俱来的。拿儿童学步来举例,如果小朋友努力的迈出第一步,就会获得父母的鼓励——可能是鼓掌叫好,也可能是一块糖;但如果小朋友坚决不肯学习走路,那父母就不会给它糖吃了。强化学习就是依照这类激励行为而设置的。

而在这个游戏中,对我们的AI小恐龙来说,强化学习需要让他在无监督的情况下,先认识到做出不同动作的结果,并且以获得高分为最高激励。

Ravi Munde用Q-learning模拟了一个特殊函数,这个函数驱动AI在不同状况下做出正确的选择。

Q-learning是强化学习的一种无模型实现,根据Q值对每个状态进行判断此时如果采取行动,能获得怎样的奖励。一个样本Q表让我们了解数据的结构。在恐龙跑酷游戏中,状态是当前的游戏截图,能采取的行动是跳或不跳[0,1]

Ravi Munde决定用深度神经网络来决定小恐龙何时起跳,而且要在最简单的强化学习实现基础上,引入不同参数来辅助它。

缺乏已标记的数据让强化学习非常不稳定。为了获得适用于这个游戏的数据,Munde小哥决定,先让小恐龙自己瞎跳几千次,把每个动作的反馈记下来,然后从数据中随机挑选一些来训练模型。

但之后,Munde小哥发现,他训练了一个倔强的模型——模型坚定的认为,跳,一定比不跳好。所以,为了让模型在训练时能在跳与不跳之间多尝试一下,他引入了一个函数ɛ来决定行动的随机性,然后再逐渐减小它的值来削减随机性,最终让模型去选择最有可能获得奖励的行动。

赞誉分布(Credit Assignment)问题可能会让模型陷入混乱——目前获得的奖励究竟来自于过去的哪个行为呢?在恐龙跑酷游戏中,小恐龙跳到半空中后无法再次跳跃,但模型可能会在恐龙处于半空中时发出跳跃指令,这种情况就让恐龙非常容易砸到仙人掌上。

在这种情况下,"砸到仙人掌上"这个负反馈实际上是此前上一次做出跳跃决定的结果,而不是刚刚恐龙在半空中时做出的跳跃结果所导致的。

在面临这种问题的情况下,可以引入贴现因子(Discount Factor)γ来决定模型做出动作时看得多远。γ间接解决了赞誉分布问题,在这个游戏中,当γ=0.99时,模型认识到在无障碍时随便跳会导致真的遇到障碍时自己正在半空中,无法继续跳跃。

除了这两个参数之外,后面就几乎不需要任何参数了。

#game parameters GAMMA = 0.99 # decay rate of past observations original 0.99 OBSERVATION = 50000. # timesteps to observe before training EXPLORE = 100000 # frames over which to anneal epsilon FINAL_EPSILON = 0.0001 # final value of epsilon INITIAL_EPSILON = 0.1 # starting value of epsilon REPLAY_MEMORY = 50000 # number of previous transitions to remember BATCH = 32 # size of minibatch FRAME_PER_ACTION = 1

你需要准备的是

  • Python 3.6
  • Selenium
  • OpenCV
  • PIL
  • Chromium driver for Selenium
  • Keras

略微解释一下这几个工具。

构建这个AI模型,需要用Python编程。而游戏是用JavaScript写成的。所以,得借助一些工具才能更好地沟通。

Selenium是一种流行的浏览器自动化工具,用于向浏览器发送操作指令,以及获取各种游戏参数。

接口的事情搞定了,还得想办法获得游戏截屏。用Selenium也行,但是速度很慢,截屏和处理一次大约得1秒钟。

用PIL和OpenCV能够更好地完成截屏和图像预处理,可以达到5fps的帧率。你可能觉得还是慢,但已经足够对付这个游戏了。

游戏模块

下面这个模块,实现了Python和浏览器(使用Selenium)的沟通。

''' * Game class: Selenium interfacing between the python and browser * __init__(): Launch the broswer window using the attributes in chrome_options * get_crashed() : return true if the agent as crashed on an obstacles. Gets javascript variable from game decribing the state * get_playing(): true if game in progress, false is crashed or paused * restart() : sends a signal to browser-javascript to restart the game * press_up(): sends a single to press up get to the browser * get_score(): gets current game score from javascript variables. * pause(): pause the game * resume(): resume a paused game if not crashed * end(): close the browser and end the game ''' class Game:   def __init__(self,custom_config=True):     chrome_options = Options()     chrome_options.add_argument("disable-infobars")     self._driver = webdriver.Chrome(executable_path = chrome_driver_path,chrome_options=chrome_options)     self._driver.set_window_position(x=-10,y=0)     self._driver.set_window_size(200, 300)     self._driver.get(os.path.abspath(game_url))     #modifying game before training     if custom_config:       self._driver.execute_script("Runner.config.ACCELERATION=0")   def get_crashed(self):     return self._driver.execute_script("return Runner.instance_.crashed")   def get_playing(self):     return self._driver.execute_script("return Runner.instance_.playing")   def restart(self):     self._driver.execute_script("Runner.instance_.restart()")      time.sleep(0.25)# no actions are possible              # for 0.25 sec after game starts,              # skip learning at this time and make the model wait   def press_up(self):     self._driver.find_element_by_tag_name("body").send_keys(Keys.ARROW_UP)   def get_score(self):     score_array = self._driver.execute_script("return Runner.instance_.distanceMeter.digits")     score = ''.join(score_array) # the javascript object is of type array with score in the formate[1,0,0] which is 100.     return int(score)   def pause(self):     return self._driver.execute_script("return Runner.instance_.stop()")   def resume(self):     return self._driver.execute_script("return Runner.instance_.play()")   def end(self):     self._driver.close()

恐龙智能体模块

这个模块在游戏模块的帮助下,用于控制小恐龙的动作。

class DinoAgent:   def __init__(self,game): #takes game as input for taking actions     self._game = game;      self.jump(); #to start the game, we need to jump once     time.sleep(.5) # no action can be performed for the first time when game starts   def is_running(self):     return self._game.get_playing()   def is_crashed(self):     return self._game.get_crashed()   def jump(self):     self._game.press_up()   def duck(self):     self._game.press_down()

游戏状态模块

神经网络直接使用这个模块,来执行操作并获取新的状态。

''' get_state(): accepts an array of actions,         performs the action on the agent  returns : new state, reward and if the game ended. ''' class Game_sate:   def __init__(self,agent,game):     self._agent = agent     self._game = game   def get_state(self,actions):     score = self._game.get_score()      reward = 0.1*score/10 # dynamic reward calculation     is_over = False #game over     if actions[1] == 1: #else do nothing       self._agent.jump()       reward = 0.1*score/11     image = grab_screen()       if self._agent.is_crashed():       self._game.restart()       reward = -11/score       is_over = True     return image, reward, is_over #return the Experience tuple

预处理

游戏修改

原始的游戏相对复杂,比如游戏速度会逐渐加快,障碍物会改变,还会出现云朵、星星、地面纹理等。一次同时学习这么多东西会消耗大量时间,甚至在训练过程中引入不必要的噪音。

为此作者修改了游戏的源代码、简化局面,去除了一些视觉元素(云、历史最佳成绩等),还有让恐龙的奔跑速度保持不变。

图像处理

原始截图的分辨率为1200×300,包含三个通道。作者计划使用4个连续的屏幕截图作为模型的单一输入,也就是1200×300×3×4。

问题是,这个小哥只有一个i7的CPU可用,所以他的电脑没办法在处理这个尺寸输入的同时玩游戏。所以,还得继续用OpenCV的库调正截图大小、裁剪等。最终输入图像大小为40×20像素,单通道,并用Canny突出显示边缘。

def grab_screen(_driver = None):   #bbox = region of interest on the entire screen   screen = np.array(ImageGrab.grab(bbox=(40,180,440,400)))    image = process_img(screen)#processing image as required   return image  def process_img(image):   #game is already in grey scale canvas, canny to get only edges and reduce unwanted objects(clouds)   # resale image dimensions   image = cv2.resize(image, (0,0), fx = 0.15, fy = 0.10)    #crop out the dino agent from the frame   image = image[2:38,10:50] #img[y:y+h, x:x+w]    image = cv2.Canny(image, threshold1 = 100, threshold2 = 200) #apply the canny edge detection   return image

然后,堆叠4张图创建单个输入,也就是:40×20×4。请注意,这里小恐龙也裁减掉了,因为整个学习过程,只需要知道障碍物和与边缘的距离即可。

模型架构

现在输入有了,用模型输出来玩游戏的方法也有了,只差模型架构。

小哥选择把3个卷积层压平,连接到一个512神经元的全连接层(dense layer)上。池化层直接被砍掉了,这个东西在图像分类问题上很有用,但是玩Dino的时候神经网络只需要知道障碍物的位置,池化层就起不了什么作用了。

这个模型的输出,形状和可能的操作数量一样。模型会预测各种操作的Q值,也叫discounted future reward,然后我们选数值最高的那个。

下面这段代码,就能召唤一个用TensorFlow后端的Keras来搭建的模型:

#model hyper parameters LEARNING_RATE = 1e-4 img_rows , img_cols = 40,20 img_channels = 4 #We stack 4 frames ACTIONS = 2 def buildmodel():   print("Now we build the model")   model = Sequential()   model.add(Conv2D(32, (8, 8), strides=(4, 4), padding='same',input_shape=(img_cols,img_rows,img_channels))) #20*40*4   model.add(Activation('relu'))   model.add(Conv2D(64, (4, 4), strides=(2, 2), padding='same'))   model.add(Activation('relu'))   model.add(Conv2D(64, (3, 3), strides=(1, 1), padding='same'))   model.add(Activation('relu'))   model.add(Flatten())   model.add(Dense(512))   model.add(Activation('relu'))   model.add(Dense(ACTIONS))   adam = Adam(lr=LEARNING_RATE)   model.compile(loss='mse',optimizer=adam)   print("We finish building the model")   return model

开始训练

接下来,就是见证奇迹的时刻~~

也就是用一段代码来训练模型,这段代码的任务是:

  • 从无操作开始,得到初始状态initial state(s_t)
  • 观察玩游戏的过程,代码中的OBSERVATION表示步数
  • 预测一个操作的效果
  • 在Replay Memory中存储经验
  • 训练阶段,从Replay Memory里随机选择一组,用它来训练模型
  • 如果game over了,就重开一局

更详细的,可以看这段自带注释的代码:

'''  Parameters: * model => Keras Model to be trained * game_state => Game State module with access to game environment and dino * observe => flag to indicate wherther the model is to be trained(weight updates), else just play ''' def trainNetwork(model,game_state):   # store the previous observations in replay memory   D = deque() #load from file system   # get the first state by doing nothing   do_nothing = np.zeros(ACTIONS)   do_nothing[0] =1 #0 => do nothing,            #1=> jump    x_t, r_0, terminal = game_state.get_state(do_nothing) # get next step after performing the action   s_t = np.stack((x_t, x_t, x_t, x_t), axis=2).reshape(1,20,40,4) # stack 4 images to create placeholder input reshaped 1*20*40*4     OBSERVE = OBSERVATION   epsilon = INITIAL_EPSILON   t = 0   while (True): 

M2 模型杀回 Coding 和 Agent 领域,MiniMax 想要「普惠智能」-InfoQ每周精要No.900

「每周精要」 NO. 900 2025/11/01 头条 HEADLINE M2 模型杀回 Coding 和 Agent 领域,MiniMax 想要「普惠智能」 精选 SELECTED a16z 将 3000 万开发者标价 3 万亿 网友:几个初创公司 + 大模型就...