嘉宾分享
快来分享你的内容吧~
- 2023-10-15查看全文#经验# #嘉宾分享# 这周看完了一本书,里面有几个点我觉得说得挺好,总结一下分享给大家 1、在许多行业,很多年轻人都有很强的学习能力,可以很快学会岗位要求的技能,而做些分外的事常常能让一些人先人一步。...青碧凝霜:说的对,但不搞4220分享
- 2023-08-12查看全文#技术# #嘉宾分享# 参加线下 Web3组局有感 今天去线下参加了一个 Web3 私人组局,当然我虽然是做技术的,但是在 Web3 领域,还是一个纯纯的小白,这次抱着一个学习的心态,整体听下来,还是有不少收获,这里摘录一些金句和个人感悟,分享给大家 《感谢 Start 老师分享》...北冥森:浅层理解一下,做好信息收集,分析好信息,稳住心态[拥抱]2331分享
- 2023-06-06·@官方运营 学习、求职、生活问题欢迎交流查看全文#嘉宾分享# 今天给大家介绍的嘉宾,是阿常(嘉宾介绍:https://t.zsxq.com/0el348fIq)。 从事软件测试领域 11 年,目前在一家企业担任测试主管,后续会在星球持续分享测试内容合集。 ...编程导航_小y:常姐往期文章分享:1)https://t.zsxq.com/0e14CI9BV2)https://t.zsxq.com/0eFiHAmOU3)https://t.zsxq.com/0edwILnBH4)https://t.zsxq.com/0ewQGRnu75)https://t.zsxq.com/0eLGaWKyA6)https://t.zsxq.com/0e64QPsz27)https://t1860分享
- 2023-05-31·@官方运营 学习、求职、生活问题欢迎交流查看全文#嘉宾分享# 今天给大家介绍的嘉宾,是德福 🧧 老师(嘉宾介绍:https://t.zsxq.com/0es2m3dQd),也是咱们的老熟人,已经在星球回答过上百个问题。 前滴滴IM开放平台负责人,十余年前端经验,目前在一家开源数据库创业公司。 ...编程导航_小y:之前回答过的部分问答:1)https://t.zsxq.com/0e4mofun82)https://t.zsxq.com/0efbbFqnk3)https://t.zsxq.com/0eDVaMrY74)https://t.zsxq.com/0eJZgQJoa......1820分享
- 2023-05-30·@官方运营 学习、求职、生活问题欢迎交流查看全文#嘉宾分享# 今天给大家介绍的嘉宾,是河北王校长(嘉宾介绍:https://t.zsxq.com/0eWN3vNL9)。 本人从业 Java 后端开发已10年,拥有一线互联网大厂经验。 ...编程导航_小y:嘉宾文章分享1)【面经】并发编程和集合面试题总结:https://t.zsxq.com/0e52rj3VO2)聊聊 volatile https://t.zsxq.com/0eMbZE7Sy3)聊聊第三方支付:https://t.zsxq.com/0ehwkgYBs4)从业十余载,JVM 调优思想分享:https://t.zsxq.com/0eGwXGBNV......1930分享
- 2023-05-29·@官方运营 学习、求职、生活问题欢迎交流查看全文#嘉宾分享# 今天给大家介绍的新嘉宾,是拭心 ❤️ 大佬(嘉宾介绍:https://t.zsxq.com/0eh5JiU34) 16 届本科毕业,先后就职于创业公司、字节跳动和喜马拉雅,目前担任安卓技术专家。...编程导航_小y:如果你有安卓技术、职业发展、学习方向、写作出书、面试跳槽、两性关系相关问题,欢迎提问,好的提问才值得好的回答:https://t.zsxq.com/0d2RX6qAz ~1950分享
#经验# #嘉宾分享# 这周看完了一本书,里面有几个点我觉得说得挺好,总结一下分享给大家 1、在许多行业,很多年轻人都有很强的学习能力,可以很快学会岗位要求的技能,而做些分外的事常常能让一些人先人一步。 我们要充分发挥主观能动性。比如知道老板需要在一位重要客户的公司附近预订一家餐厅,你可以主动提出帮忙寻找合适的餐厅并预订好座位。 有些年轻人认为,餐厅预订之类的工作对他们来说太卑微了,根本不值得用心。但是如果不能做好小事,你就没有机会做大事,因为人们不会相信你能做好大事 相反,如果你在小事上也肯花心思,那么你就是在向老板和同事传递一个信息——你也可以把大事做好。 2、 财务自由不是让你提前退休,而是让你获得追求自身幸福、按自己的意愿做决定的底气。 财务自由可以让你工作时更有胆量、说话更有底气,因为你不用担心失去工作的经济后果;又让你更加自信,敢于承担职业发展中的风险。 3、排解工作压力三种方法,无论资历深浅,人人都有工作压力,压力往往是由工作量太大或职场人际关系引发的,定期锻炼,健康饮食,适当表达情绪吐槽压力 4、 健康的饮食,定期持久的锻炼,表达情绪的社交,真的可以让你进入一种更平和的精神情绪状态,从而更有效地应对生活何工作中的各种烦恼何压力 人生要追求梦想。 人生要采取行动。 有时人生也要驻足当下,闻闻花香。 祝大家周末愉快(^з^)-🍻
经验 #职场# #嘉宾分享# 经验 贺哥国庆假期感悟/碎碎念 中国人羞于谈💰,虽然💰不是万能的,但💰能解决大部分的问题 比较成熟的人格就是尽早实现经济独立,并且有能力不为找工作赚钱发愁,才能去谈兴趣和其他想做的事 当然这里面的经济独立:每个人的标准不一样,找到自己那个标准就可以,瞎比较无意义 否则,在没有一定头脑和能力取得经济独立前,所有对爱好的偏执,大概率会因为入不敷出的拮据生活家庭压力,而备受折磨,也不利于在兴趣方面的专注度,影响长足发展 之前看过水哥王昱珩采访的话。他也是上美院时就以名校学生身份给公司出设计图赚钱,PS一下午学会并制作设计图纸,被采用做竞标方案等等 有人采访问:你现在做什么工作呢? 答:我现在就是...玩。 问:那你怎么赚钱呢? 道:赚钱这事是最简单的呀! 问:。。。 聪明的人二十来岁上大学就有自己的谋生途经和技能了,而更多人30岁了可能捉襟见肘,刚刚还完助学贷款,甚至一直在不知道做什么工作赚钱发愁,只自叹底层无背景,天资不足,相貌平平,身无一技之长 最美好的青春活力和热情斗志早早湮灭在工作生活压力的围困之中,还何谈什么兴趣爱好,志向价值之类呢? 经济能力是一个门槛,你迈不进去,就只能是在门槛外着急忙慌的折腾焦虑,折腾累了,精力耗费完了,很多人可能就躺平命运了 这是多数人需要面对的悲哀 所以相对来说,真正的思想成熟是先取得经济独立,否则所谓的思想早熟也只是夜郎自大,根本看不清实际社会和自我,活在自以为是的头脑意识里在现实中不断碰壁转圈 努力学习,提升自己,拿到好 offer,才能让自己有更好的选择和生活💪
前端实用小技巧: 计算图片主要颜色
<html> <head></head> <body> <div class="content ql-editor"> <p>在一般用户popover中都有一个横幅的设计。大概就是这样:</p> <p></p> <p></p> <p></p> <p>这个设计的目的是让用户可以上传自己的横幅图片,来达到个性化的设计。</p> <p></p> <p>但是如果没有横幅的情况下,如果也想让用户有一定个性化的能力,要怎么做呢?</p> <p></p> <p>Tailchat 的做法基于头像颜色计算主要配色方案,来确保整体配色和谐的前提下来确保不同用户的个性化</p> <p></p> <p></p> <p></p> <p>实现的方式非常简单,简单的说就是我们把头像放到一个canvas里,然后通过canvas提取每个颜色的像素信息,通过算法计算出平均值。</p> <p></p> <p>废话不多说我们直接上代码</p> <p></p> <div class="ql-code-block-container"> <div class="ql-code-block"><span class="ql-token hljs-comment">/** * 加载图片 */</span> <span class="ql-token hljs-keyword">async</span> <span class="ql-token hljs-keyword">function</span> <span class="ql-token hljs-title">loadImage(url: string)</span>: <span class="ql-token hljs-title">Promise</span><<span class="ql-token hljs-title">HTMLImageElement</span>> { <span class="ql-token hljs-keyword">const</span> el = <span class="ql-token hljs-variable">document</span>.<span class="ql-token hljs-title">createElement</span>(<span class="ql-token hljs-string">'img'</span>); <span class="ql-token hljs-keyword">return</span> <span class="ql-token hljs-keyword">new</span> <span class="ql-token hljs-title">Promise</span>(<span class="ql-token hljs-function">(resolve, reject) =></span> { el.<span class="ql-token hljs-property">onload</span> = <span class="ql-token hljs-function">() =></span> <span class="ql-token hljs-title">resolve</span>(el); el.<span class="ql-token hljs-property">onerror</span> = reject; el.<span class="ql-token hljs-property">src</span> = url; el.<span class="ql-token hljs-property">crossOrigin</span> = <span class="ql-token hljs-string">'Anonymous'</span>; }); } <span class="ql-token hljs-comment">/** * 获取图片的主要颜色 */</span> <span class="ql-token hljs-keyword">export</span> <span class="ql-token hljs-keyword">async</span> <span class="ql-token hljs-keyword">function</span> <span class="ql-token hljs-title">fetchImagePrimaryColor(imageUrl: string)</span> { <span class="ql-token hljs-keyword">const</span> img = <span class="ql-token hljs-keyword">await</span> <span class="ql-token hljs-title">loadImage(imageUrl)</span>; <span class="ql-token hljs-keyword">const</span> canvas = <span class="ql-token hljs-variable">document</span>.<span class="ql-token hljs-title">createElement</span>(<span class="ql-token hljs-string">'canvas'</span>); canvas.<span class="ql-token hljs-property">width</span> = img.<span class="ql-token hljs-property">width</span>; canvas.<span class="ql-token hljs-property">height</span> = img.<span class="ql-token hljs-property">height</span>; <span class="ql-token hljs-keyword">const</span> ctx = canvas.<span class="ql-token hljs-title">getContext</span>(<span class="ql-token hljs-string">'2d'</span>); <span class="ql-token hljs-keyword">if</span> (!ctx) { <span class="ql-token hljs-keyword">return</span> { <span class="ql-token hljs-attr">r</span>: <span class="ql-token hljs-number">0</span>, <span class="ql-token hljs-attr">g</span>: <span class="ql-token hljs-number">0</span>, <span class="ql-token hljs-attr">b</span>: <span class="ql-token hljs-number">0</span>, <span class="ql-token hljs-attr">a</span>: <span class="ql-token hljs-number">0</span> }; } ctx.<span class="ql-token hljs-title">drawImage</span>(img, <span class="ql-token hljs-number">0</span>, <span class="ql-token hljs-number">0</span>, canvas.<span class="ql-token hljs-property">width</span>, canvas.<span class="ql-token hljs-property">height</span>); <span class="ql-token hljs-keyword">const</span> imageData = ctx.<span class="ql-token hljs-title">getImageData</span>(<span class="ql-token hljs-number">0</span>, <span class="ql-token hljs-number">0</span>, canvas.<span class="ql-token hljs-property">width</span>, canvas.<span class="ql-token hljs-property">height</span>); <span class="ql-token hljs-keyword">let</span> r = <span class="ql-token hljs-number">0</span>; <span class="ql-token hljs-keyword">let</span> g = <span class="ql-token hljs-number">0</span>; <span class="ql-token hljs-keyword">let</span> b = <span class="ql-token hljs-number">0</span>; <span class="ql-token hljs-keyword">let</span> a = <span class="ql-token hljs-number">0</span>; <span class="ql-token hljs-keyword">for</span> (<span class="ql-token hljs-keyword">let</span> row = <span class="ql-token hljs-number">0</span>; row < imageData.<span class="ql-token hljs-property">height</span>; row++) { <span class="ql-token hljs-keyword">for</span> (<span class="ql-token hljs-keyword">let</span> col = <span class="ql-token hljs-number">0</span>; col < imageData.<span class="ql-token hljs-property">width</span>; col++) { r += imageData.<span class="ql-token hljs-property">data</span>[(imageData.<span class="ql-token hljs-property">width</span> * row + col) * <span class="ql-token hljs-number">4</span>]; g += imageData.<span class="ql-token hljs-property">data</span>[(imageData.<span class="ql-token hljs-property">width</span> * row + col) * <span class="ql-token hljs-number">4</span> + <span class="ql-token hljs-number">1</span>]; b += imageData.<span class="ql-token hljs-property">data</span>[(imageData.<span class="ql-token hljs-property">width</span> * row + col) * <span class="ql-token hljs-number">4</span> + <span class="ql-token hljs-number">2</span>]; a += imageData.<span class="ql-token hljs-property">data</span>[(imageData.<span class="ql-token hljs-property">width</span> * row + col) * <span class="ql-token hljs-number">4</span> + <span class="ql-token hljs-number">3</span>]; } } <span class="ql-token hljs-keyword">const</span> sum = imageData.<span class="ql-token hljs-property">width</span> * imageData.<span class="ql-token hljs-property">height</span>; r = <span class="ql-token hljs-title">Math</span>.<span class="ql-token hljs-title">round</span>(r / sum); g = <span class="ql-token hljs-title">Math</span>.<span class="ql-token hljs-title">round</span>(g / sum); b = <span class="ql-token hljs-title">Math</span>.<span class="ql-token hljs-title">round</span>(b / sum); a = <span class="ql-token hljs-title">Math</span>.<span class="ql-token hljs-title">round</span>(a / sum); <span class="ql-token hljs-keyword">return</span> { r, g, b, a, }; } </div> </div> <p></p> <p>工具函数 <code>fetchImagePrimaryColor</code> 接受一个图片的地址,通过 <code>loadImage</code> 函数加载图片并返回一个图片dom</p> <p></p> <p>根据返回的 img dom 的宽高创建canvas的宽高,然后将图片通过 <code>ctx.drawImage(img, 0, 0, canvas.width, canvas.height)</code> 直接绘制到 canvas 中.</p> <p></p> <p>然后通过 <code>ctx.getImageData(0, 0, canvas.width, canvas.height);</code> 获取到该图片的完整像素信息。</p> <p></p> <p>我们通过两个循环分别获取到该图片所有位置中的 rgba 信息,计算其总和并取其平均数,最后返回出该图片的平均 rgba. 即我们可以视为该图片的主要颜色。</p> <p></p> <p>当然,该算法准确来说其实是取平均色,一个极端的例子是比如一张图有一般是红色,一半是绿色,那么最后返回的结果是黄色。当然了,大部分情况下不会出现这种比较极端的例子,在大部分情况下都是比较和谐的。</p> <p></p> <hr class="article-hr" style="height: 0px"> <p><br></p> <p>本文实战用法见:</p> <p></p> <p><a href="https://github.com/msgbyte/tailchat/blob/master/client/web/src/utils/image-helper.ts" target="_blank">https://github.com/msgbyte/tailchat/blob/master/client/web/src/utils/image-helper.ts</a></p> <p></p> <p>我会不定期的从 <a href="https://github.com/msgbyte/tailchat" target="_blank">Tailchat</a> 的源码中拆出一些实用的实战小技巧分享给大家,关注我,并给 <a href="https://github.com/msgbyte/tailchat" target="_blank">Tailchat</a> 点点 star。我将带你以实战理解算法的妙用。</p> <p>#算法# #前端# #技术# #嘉宾分享#</p> </div> </body> </html>
#技术# #嘉宾分享# 参加线下 Web3组局有感 今天去线下参加了一个 Web3 私人组局,当然我虽然是做技术的,但是在 Web3 领域,还是一个纯纯的小白,这次抱着一个学习的心态,整体听下来,还是有不少收获,这里摘录一些金句和个人感悟,分享给大家 《感谢 Start 老师分享》 1、对新事物不要有偏见,这个赛道确实存在很多机会,在你熊市的时候其实是可以积累的,在牛市的时候是会放大你的积累 新人最容易被 Web3 生态的高收益所吸引,这个赛道,动不动就是暴富故事,让人变得亢奋,激动 一旦控制不住,心态,情绪都会受到影响,一旦情绪受到影响,动作变形,就容易被割韭菜 其实 Web3 的生态也是层级分明的,一不小心,新人很容易被盘圈,赌狗这些套进去,我们普通人应该最关注的,是在不确定性的情况下,拿住那些确定性的机会,套利,打新等。要控制自己的贪欲,抱住本金,闲钱投资。 关键词 「机会」「角度」「热度」「趋势」「参与」 《感谢海成老师分享》 1、区块链是一个黑暗森林,我们每个人都是猎物,只要你不上头,你是有机会把你的本金马上变成利润 2、说白了是这个投机市场,在这个过程中,你为自己的成长做了哪些事,这个在财富增长之外另外一个比较重要的 3、未来在哪条赛道,或者哪些项目上是新的新的热点,新的叙事,不知道,你能做的事,就是好好修炼自己,修炼投研体系,交易体系,仓位管理的能力,风险控制的能力,这些事儿是要靠自己知行合一自己修炼的 4、你亏钱亏得多了,这个风险意识慢慢就上来了,然后你这个项目参越的多了,你自然会对项目有一些感觉就慢慢上来了,虽然新人感觉这个赛道很混乱,的确是,我们唯一能做的,就是做好自己的事情,在保护好本金的基础上,在不确定性的情况下,拿住一些确定性的东西 关键词「黑暗森林」「预期管理」「向内修炼自己」「,向外拥抱赛道」「做好自己的事情」 感谢吴老师和雨老师分享的体能恢复操,做完整个人精神舒服好多 最大的收获:信息的敏感度,做研究的重要性,圈子的重要性,执行力的重要性,最后心态管理的重要性 写到这里,不禁回想起,最后的压轴分享,给奥运冠军做体能康复老师,也重点提到了心力的重要性,和最开始说的居然完美闭环了 花精力投资自己永远是最重要的事情,人只能赚到自己认知内的钱,不然凭运气赚的钱,大概率会实力亏掉。 在这个圈子,保护好本金,不下牌桌就永远有机会 个人看法,不构成任何投资建议,希望对大家有启发
#嘉宾分享# 今天给大家介绍的嘉宾,是阿常(嘉宾介绍:https://t.zsxq.com/0el348fIq)。 从事软件测试领域 11 年,目前在一家企业担任测试主管,后续会在星球持续分享测试内容合集。 关于测试、管理相关问题欢迎大家向她提问,好的提问才值得好的回答:https://t.zsxq.com/0d2RX6qAz ~
#嘉宾分享# 今天给大家介绍的嘉宾,是德福 🧧 老师(嘉宾介绍:https://t.zsxq.com/0es2m3dQd),也是咱们的老熟人,已经在星球回答过上百个问题。 前滴滴IM开放平台负责人,十余年前端经验,目前在一家开源数据库创业公司。 比较擅长前端、面试、职场和情感类话题,对于养育人类幼崽也有四年经验可以分享,好的提问才值得好的回答:https://t.zsxq.com/0d2RX6qAz ~
#嘉宾分享# 今天给大家介绍的嘉宾,是河北王校长(嘉宾介绍:https://t.zsxq.com/0eWN3vNL9)。 本人从业 Java 后端开发已10年,拥有一线互联网大厂经验。 擅长 Java、Mysql 底层、并发、JVM、Redis 底层、Spring 源码、SpringBoot 源码、RabbitMQ、Kafka、Netty、SpringCloud 等 Java 从业者的核心技术。 大家有 Java 技术相关的问题可以随时给我提问,星球的语音回复时长是 2 分钟限制,一般的技术问题 2 分钟基本足够回答啦,好的提问才值得好的回答:https://t.zsxq.com/0d2RX6qAz ~ 嘉宾文章分享 1)【面经】并发编程和集合面试题总结:https://t.zsxq.com/0e52rj3VO 2)聊聊 volatile https://t.zsxq.com/0eMbZE7Sy 3)聊聊第三方支付:https://t.zsxq.com/0ehwkgYBs 4)从业十余载,JVM 调优思想分享:https://t.zsxq.com/0eGwXGBNV ......
#嘉宾分享# 今天给大家介绍的新嘉宾,是拭心 ❤️ 大佬(嘉宾介绍:https://t.zsxq.com/0eh5JiU34) 16 届本科毕业,先后就职于创业公司、字节跳动和喜马拉雅,目前担任安卓技术专家。 多年安卓基础技术建设经验,对应用性能优化、ReactNative 、热修复等有着深入的研究和实践;为多款亿级用户软件提供过性能优化方案和工具。 如果你有安卓技术、职业发展、学习方向、写作出书、面试跳槽、两性关系相关问题,欢迎提问,好的提问才值得好的回答:https://t.zsxq.com/0d2RX6qAz ~
#求职# #经验# #职场# #嘉宾分享# 《在人生的过程中,每个人决定不了他的出生环境,但是有一点,我们可以自己把握,那就是可以通过努力决定未来的命运》 周末两天,看了一本书,《金榜题名之后-大学生出路分化之迷》,豆瓣评分 8.7,作者是复旦的一个博士,建议大家也可以看看,我对里面的内容,非常感同身受,今天结合自己的经历和和感悟,有一些思考分享给大家。 “重点大学寄托了万千家庭改变命运的梦想,如今一系列专项招生计划也为更多学子打开了机会之门。然而,金榜题名之后,学子是否如想象那般顺遂? 不同社会经济背景的学生在毕业出路和职业前景上的差距是如何拉开的? 通过对位于京沪的两所重点高校毕业班学生的深度访谈,本书揭示了大学生在上大学 过程中遭遇的一种隐性的挑战:是否洞察大学场域的“游戏规则”,掌握其中“默认”为常规的一系列认知和实践模式。 本书指出,家庭背景优势不仅带来了雄厚的物质支持,更意味一整套关于“上大学”的文化技艺的传承,这使得出身优渥的大学生得以在白热化的出路竞争中抢占先机,而家境平平者却更容易与机会失之交臂。” 对于那些冲破无数壁垒、最终赢在高考的寒门学子而言,考上重点大学虽可说是一个众望所归的胜利,却更是另一轮激烈角逐的开始。 并且,由于这一轮角逐的规则更隐蔽,寒门学子的取胜难度更大,也可能经受更深刻的痛苦。 这里的规则更隐蔽包括但不限于:求职简历包装,导师选择,找工作面试技巧,投递公司内推人脉,职场上和同事之间相处,和领导相处,如何处理人情世故,如何对待生活中的不如意,如何以一个积极的心态面对人生的不确定性等等等。 在当今的知识经济时代和高等教育大众化的社会背景下,一纸名校录取通知书并不能确保将学生带入向上流动的光明前景,而仅仅是一张声称“获胜者通往此地”的游戏人场券。 要在大学场域的这场游戏中获胜,即在毕业前夕可以顺利获得高级职业的入职邀请,或是著名研究所的深造录取,学生需要掌握一整套特殊的技艺。 一套关于“合理”看待与安排大学生活的实践图式,更重要的是,这套技艺在很大程度上是由优势的家庭经济文化背景所赋予的。低微家庭背景出身的学生,即便考入名校,享有学校提供的丰厚资源,或许你也很勤奋努力、执着追求,却很可能因为没有以某种有效的方式组织自己的大学生活,而难以将所取得的名校文凭兑换成更高的职业地位。 换句话说,在获得理想出路方面,“上大学”如今已经不再是一个无差别的传送带,而是高等教育阶段的又一重隐秘的筛选过程,一种与家庭所赋予的文化资本紧密相连的、难以在课堂上学到的技艺。 相信,星球里大部分学弟学妹们,出身于普通家庭,虽然,天生的环境无法改变,但是,如果从小就知道制定目标、计划时间、规划人生,掌握经典读书方法,并且加以践行,那么我们就可以:“在整体资源劣势的情况下,可以创造出局部的优势,进而有机会获得整个战役的胜利,平凡人也可以成就不平凡的事。” 以我个人经历来说, 某种程度上读书确实改变了我的命运,从十八线小城市,高考失利,到双非本科,一路求学上来来到大城市打工,生活,我相信很多球友和我一样的经历,而且大部分人都是在这样过来的。 星球里,鱼皮和小伙伴们沉淀了很多很多质量非常好的内容,专栏,项目,还有嘉宾们无私的分享各自的经历,相比其他同龄人,我们站的起跑线要好太多,那么,这里面,每个人能真正吸收多少,掌握多少,学习多少,看每个人的造化,还是那句话,授人以鱼不如授人以渔。 喻指传授给人既有知识,不如传授给人学习知识的方法。 大家周末愉快~ 本周好文推荐:李开复:大学最重要的七项学习 (移步feishu文档),如果觉得有启发,欢迎点赞❤️https://jnvsh9w7fs.feishu.cn/docx/GqCAdE5PmosMEmx5S8acv0nVnSd
快速让 AI 学会玩贪食蛇游戏
<html> <head></head> <body> <div class="content ql-editor"> <p>大家好,我是千寻哥,现在自动驾驶很火热,其实自动驾驶是一个很大的概念,主要涉及的领域包括强化学习以及计算机视觉。</p> <p><br></p> <p>今天给各位讲讲强化学习的入门知识,并且手把手和大家一起做一个强化学习的Demo。</p> <p><br></p> <p><strong>一、 浅谈强化学习入门</strong></p> <p>说到强化学习,你可能会有一些陌生,但是说到Alpha Go的围棋对决,你可能一下子就明白了。是的,这就是强化学习的能力。</p> <p><br></p> <p>为了让大家更加直观的了解强化学习的能力以及效果,千寻自己开发了一个强化学习玩贪吃蛇的游戏!</p> <p><br></p> <p><img src="https://pic.code-nav.cn/planet_post_image/1655447521608110081/6ep19jaw.jpeg" style="display: block; margin: auto;" align="center" width="380"></p> <p><br></p> <p>怎么样是不是十分的神奇!千寻今天和大家介绍一下,如何利用强化学习算法和ChatGPT让AI快速学会玩贪食蛇游戏。</p> <p><br></p> <p>我们将从理论基础出发,解释强化学习和深度强化学习的概念,并详细介绍使用本项目中所使用的DQN算法来训练AI玩贪食蛇的过程。</p> <p><br></p> <p>同时,我们将展示如何将ChatGPT与强化学习结合,以提供对游戏环境的实时解释和指导。</p> <p><br></p> <p><strong>二、强化学习原理简介</strong></p> <p>强化学习是一种通过与环境交互学习最优行为策略的机器学习方法。在强化学习中,智能体通过观察环境的状态,并根据选择的动作获得奖励或惩罚来学习如何最大化累积奖励。</p> <p><br></p> <p>深度强化学习是将深度学习和强化学习相结合的方法,使用神经网络来近似值函数或策略函数,以解决高维状态空间和动作空间的问题。</p> <p><br></p> <p>在训练贪吃蛇的过程中使用的是PPO强化学习模型,以下是关于PPO算法的原理简介。</p> <p><br></p> <p><strong>三、PPO算法训练智能体原理</strong></p> <p><strong><br></strong></p> <p><strong>定义状态表示</strong></p> <p>首先,需要定义贪吃蛇游戏的状态表示。状态可以包括蛇头位置、蛇身位置、食物位置等信息。这些信息将作为输入提供给PPO算法。</p> <p><br></p> <p><strong>初始化PPO网络</strong></p> <p>使用神经网络作为策略函数,在PPO算法中,通常使用多层感知机(MLP)作为策略网络。策略网络的输入是状态表示,输出是在给定状态下选择每个可能动作的概率。</p> <p><br></p> <p><strong>与环境交互</strong></p> <p>智能体与贪吃蛇环境进行交互。在每个时间步骤中,智能体观察当前状态,并根据策略网络选择一个动作。</p> <p><br></p> <p><strong>收集经验</strong></p> <p>在与环境交互的过程中,记录智能体的状态、动作、奖励等信息,构成经验轨迹。一般通过多次游戏回合进行经验收集。</p> <p><br></p> <p><strong>计算优势函数</strong></p> <p>根据收集到的经验,计算优势函数。优势函数用于估计每个动作相对于平均水平的优势程度,即衡量每个动作相对于当前策略的好坏程度。</p> <p><br></p> <p><strong>更新策略网络</strong></p> <p>使用PPO算法的核心思想,对策略网络进行更新。更新的目标是最大化优势函数,同时限制更新幅度以保证策略的稳定性。</p> <p><br></p> <p><strong>计算策略损失函数</strong></p> <p>根据收集到的经验和优势函数,计算策略损失函数。一般使用似然比优势函数作为损失函数,它包括策略网络输出动作的对数概率和优势函数的乘积。</p> <p><br></p> <p><strong>计算策略更新</strong></p> <p>通过最小化策略损失函数来更新策略网络的参数。在PPO算法中,通常使用梯度下降方法,如Adam优化器,来最小化损失函数。</p> <p><br></p> <p><strong>控制策略更新幅度</strong></p> <p>为了保证策略的稳定性,PPO算法使用了一种重要的技术,即通过限制策略更新幅度来防止太大的策略变化。这可以通过剪切或者概率比例等方式实现。</p> <p><br></p> <p><strong>重复步骤3至步骤6</strong></p> <p>智能体与环境交互,收集经验,并更新策略网络。这个过程会进行多个迭代,直到达到预定的训练轮次或者策略收敛。</p> <p><br></p> <p>以下为部分训练深度强化学习的训练代码:</p> <p><br></p> <div class="ql-code-block-container"> <div class="ql-code-block"><span class="ql-token hljs-comment">#!/usr/bin/python</span> </div> <div class="ql-code-block"><span class="ql-token hljs-comment"># -*- coding: utf-8 -*-</span> </div> <div class="ql-code-block"><span class="ql-token hljs-keyword">from</span> Agent <span class="ql-token hljs-keyword">import</span> AgentDiscretePPO </div> <div class="ql-code-block"><span class="ql-token hljs-keyword">from</span> core <span class="ql-token hljs-keyword">import</span> ReplayBuffer </div> <div class="ql-code-block"><span class="ql-token hljs-keyword">from</span> draw <span class="ql-token hljs-keyword">import</span> Painter </div> <div class="ql-code-block"><span class="ql-token hljs-keyword">from</span> env4Snake <span class="ql-token hljs-keyword">import</span> Snake </div> <div class="ql-code-block"><span class="ql-token hljs-keyword">import</span> random </div> <div class="ql-code-block"><span class="ql-token hljs-keyword">import</span> pygame </div> <div class="ql-code-block"><span class="ql-token hljs-keyword">import</span> numpy <span class="ql-token hljs-keyword">as</span> np </div> <div class="ql-code-block"><span class="ql-token hljs-keyword">import</span> torch </div> <div class="ql-code-block"><span class="ql-token hljs-keyword">import</span> matplotlib.pyplot <span class="ql-token hljs-keyword">as</span> plt </div> <div class="ql-code-block"><br> </div> <div class="ql-code-block"><span class="ql-token hljs-keyword">if</span> __name__ == <span class="ql-token hljs-string">"__main__"</span>: </div> <div class="ql-code-block"><br> </div> <div class="ql-code-block"> <span class="ql-token hljs-comment">#初始化超参数</span> </div> <div class="ql-code-block"> env = Snake() </div> <div class="ql-code-block"> test_env = Snake() </div> <div class="ql-code-block"> act_dim = <span class="ql-token hljs-number">4</span> </div> <div class="ql-code-block"> obs_dim = <span class="ql-token hljs-number">6</span> </div> <div class="ql-code-block"> agent = AgentDiscretePPO() </div> <div class="ql-code-block"> agent.init(<span class="ql-token hljs-number">512</span>, obs_dim, act_dim, if_use_gae=<span class="ql-token hljs-literal">True</span>) </div> <div class="ql-code-block"> agent.state = env.reset() </div> <div class="ql-code-block"> buffer = ReplayBuffer(<span class="ql-token hljs-number">2</span>**<span class="ql-token hljs-number">12</span>, obs_dim, act_dim, <span class="ql-token hljs-literal">True</span>) </div> <div class="ql-code-block"><br> </div> <div class="ql-code-block"> <span class="ql-token hljs-comment">#设定训练迭代的轮数以及数据的批量大小</span> </div> <div class="ql-code-block"> MAX_EPISODE = <span class="ql-token hljs-number">200</span> </div> <div class="ql-code-block"> batch_size = <span class="ql-token hljs-number">64</span> </div> <div class="ql-code-block"><br> </div> <div class="ql-code-block"> rewardList = [] </div> <div class="ql-code-block"> maxReward = -np.inf </div> <div class="ql-code-block"><br> </div> <div class="ql-code-block"> episodeList = [] <span class="ql-token hljs-comment"># 存储训练轮数</span> </div> <div class="ql-code-block"> rewardArray = [] <span class="ql-token hljs-comment"># 存储rewards得分</span> </div> <div class="ql-code-block"><br> </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">for</span> episode <span class="ql-token hljs-keyword">in</span> <span class="ql-token hljs-built_in">range</span>(MAX_EPISODE): </div> <div class="ql-code-block"><br> </div> <div class="ql-code-block"> <span class="ql-token hljs-comment"># 进行强化学习模型的训练</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">with</span> torch.no_grad(): </div> <div class="ql-code-block"> trajectory_list = agent.explore_env(env, <span class="ql-token hljs-number">2</span>**<span class="ql-token hljs-number">12</span>, <span class="ql-token hljs-number">1</span>, <span class="ql-token hljs-number">0.99</span>) </div> <div class="ql-code-block"><br> </div> <div class="ql-code-block"> <span class="ql-token hljs-comment"># 反馈数据存入buffer缓存中</span> </div> <div class="ql-code-block"> buffer.extend_buffer_from_list(trajectory_list) </div> <div class="ql-code-block"><br> </div> <div class="ql-code-block"> <span class="ql-token hljs-comment"># 根据缓存中的反馈数据更新网络结构</span> </div> <div class="ql-code-block"> agent.update_net(buffer, batch_size, <span class="ql-token hljs-number">1</span>, <span class="ql-token hljs-number">2</span>**-<span class="ql-token hljs-number">8</span>) </div> <div class="ql-code-block"><br> </div> <div class="ql-code-block"> <span class="ql-token hljs-comment"># 测试模型的代理获得贪吃蛇的得分</span> </div> <div class="ql-code-block"> ep_reward = testAgent(test_env, agent, episode) </div> <div class="ql-code-block"><br> </div> <div class="ql-code-block"> <span class="ql-token hljs-comment"># 打印训练过程的信息</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-built_in">print</span>(<span class="ql-token hljs-string">'Episode:'</span>, episode, <span class="ql-token hljs-string">'Reward:%f'</span> % ep_reward) </div> <div class="ql-code-block"><br> </div> <div class="ql-code-block"> rewardList.append(ep_reward) </div> <div class="ql-code-block"> episodeList.append(episode) </div> <div class="ql-code-block"> rewardArray.append(ep_reward) </div> <div class="ql-code-block"><br> </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">if</span> episode > MAX_EPISODE / <span class="ql-token hljs-number">3</span> <span class="ql-token hljs-keyword">and</span> ep_reward > maxReward: </div> <div class="ql-code-block"> maxReward = ep_reward </div> <div class="ql-code-block"> <span class="ql-token hljs-built_in">print</span>(<span class="ql-token hljs-string">'保存模型!'</span>) </div> <div class="ql-code-block"> torch.save(agent.act.state_dict(), <span class="ql-token hljs-string">'model_weights/act_weight.pkl'</span>) </div> <div class="ql-code-block"><br> </div> <div class="ql-code-block"> pygame.quit() </div> </div> <p><br></p> <p>代码的每一部分的功能,我已经在代码文件中进行了详细的注释。终端输出训练信息如下:</p> <p><br></p> <p><img src="https://pic.code-nav.cn/planet_post_image/1655447521608110081/stdfky8b.jpeg" style="display: block; margin: auto;" align="center" width="499"></p> <p><br></p> <p>为了进一步的对强化学习的模型训练过程,我们对训练过程的信息进行可视化。</p> <p>添加如下代码:</p> <p><br></p> <div class="ql-code-block-container"> <div class="ql-code-block"><span class="ql-token hljs-comment"># 绘制训练轮数与rewards得分曲线</span> </div> <div class="ql-code-block"> plt.plot(episodeList, rewardArray, label=<span class="ql-token hljs-string">'Actual Rewards'</span>) </div> <div class="ql-code-block"> plt.plot(episodeList, fitted_rewards, label=<span class="ql-token hljs-string">'Fitted Rewards'</span>) </div> <div class="ql-code-block"> plt.xlabel(<span class="ql-token hljs-string">'Episode'</span>) </div> <div class="ql-code-block"> plt.ylabel(<span class="ql-token hljs-string">'Reward'</span>) </div> <div class="ql-code-block"> plt.legend() </div> </div> <p><br></p> <p>我们希望观察迭代训练的次数episode与最终强化学习的模型得分reward之间的关系,如下图所示:</p> <p><img src="https://pic.code-nav.cn/planet_post_image/1655447521608110081/l8hv4ol1.jpeg" style="display: block; margin: auto;" align="center" width="510"></p> <p><br></p> <p>在曲线图像中的Actual Rewards标签为当前迭代轮数下的“实际得分数值”,Fittered Rewards标签为“拟合得分数值”。</p> <p><br></p> <p>通过以上的曲线,我们可以看出在约100轮左右,模型已经进入收敛状态,表示模型性能已经训练完成。</p> <p><br></p> <p><strong>四、ChatGPT与强化学习训练的结合</strong></p> <p>为了进一步优化强化学习的模型性能,将模型训练融入ChatGPT,ChatGPT是一种基于GPT-3.5架构的大型语言模型,具有强大的自然语言处理和生成能力。</p> <p><br></p> <p>那么ChatGPT语言生成模型与强化学习结合可以做什么呢?</p> <p><br></p> <p>必然是引入AI算法从而提供实时的游戏环境解释和指导。包括以下几点:</p> <p><br></p> <p><strong>(1)游戏环境交互</strong>:通过ChatGPT与玩贪食蛇游戏的AI进行实时对话,AI可以向ChatGPT提问关于当前状态和最佳行动的问题。</p> <p><br></p> <p><strong>(2)状态解释</strong>:AI可以将当前状态描述发送给ChatGPT,并从ChatGPT获得对状态的解释和建议。ChatGPT可以帮助AI理解游戏中的复杂状态和策略。</p> <p><br></p> <p><strong>(3)行动建议</strong>:AI可以向ChatGPT询问最佳行动,并根据ChatGPT的建议选择下一步动作。ChatGPT可以基于其语言模型和先前的训练经验提供合理的建议。</p> <p><br></p> <p><strong>(4)策略优化</strong>:AI可以根据ChatGPT提供的建议进行策略优化。AI在每个时间步骤中选择动作后,可以将结果反馈给ChatGPT,以便进行进一步的讨论和改进。</p> <p><br></p> <p><strong>五、训练模型代理的验证</strong></p> <p>经过了ChatGPT的生成模型与PPO算法强化学习模型训练的AI玩贪吃蛇游戏,我们可以编写一个AI自动玩贪吃蛇游戏的推理代码:</p> <p><br></p> <p>定义Snake类的属性</p> <div class="ql-code-block-container"> <div class="ql-code-block"><span class="ql-token hljs-keyword">class</span> <span class="ql-token hljs-title">Snake</span>: </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">def</span> <span class="ql-token hljs-title">__init__</span>(<span class="ql-token hljs-params">self</span>): </div> <div class="ql-code-block"> self.snake_speed = <span class="ql-token hljs-number">100</span> <span class="ql-token hljs-comment"># 贪吃蛇的速度</span> </div> <div class="ql-code-block"> self.windows_width = <span class="ql-token hljs-number">600</span> </div> <div class="ql-code-block"> self.windows_height = <span class="ql-token hljs-number">600</span> <span class="ql-token hljs-comment"># 游戏窗口的大小</span> </div> <div class="ql-code-block"> self.cell_size = <span class="ql-token hljs-number">50</span> <span class="ql-token hljs-comment"># 贪吃蛇身体方块大小,注意身体大小必须能被窗口长宽整除</span> </div> <div class="ql-code-block"> self.map_width = <span class="ql-token hljs-built_in">int</span>(self.windows_width / self.cell_size) </div> <div class="ql-code-block"> self.map_height = <span class="ql-token hljs-built_in">int</span>(self.windows_height / self.cell_size) </div> <div class="ql-code-block"> self.white = (<span class="ql-token hljs-number">255</span>, <span class="ql-token hljs-number">255</span>, <span class="ql-token hljs-number">255</span>) </div> <div class="ql-code-block"> self.black = (<span class="ql-token hljs-number">0</span>, <span class="ql-token hljs-number">0</span>, <span class="ql-token hljs-number">0</span>) </div> <div class="ql-code-block"> self.gray = (<span class="ql-token hljs-number">230</span>, <span class="ql-token hljs-number">230</span>, <span class="ql-token hljs-number">230</span>) </div> <div class="ql-code-block"> self.dark_gray = (<span class="ql-token hljs-number">40</span>, <span class="ql-token hljs-number">40</span>, <span class="ql-token hljs-number">40</span>) </div> <div class="ql-code-block"> self.DARKGreen = (<span class="ql-token hljs-number">0</span>, <span class="ql-token hljs-number">155</span>, <span class="ql-token hljs-number">0</span>) </div> <div class="ql-code-block"> self.Green = (<span class="ql-token hljs-number">0</span>, <span class="ql-token hljs-number">255</span>, <span class="ql-token hljs-number">0</span>) </div> <div class="ql-code-block"> self.Red = (<span class="ql-token hljs-number">255</span>, <span class="ql-token hljs-number">0</span>, <span class="ql-token hljs-number">0</span>) </div> <div class="ql-code-block"> self.blue = (<span class="ql-token hljs-number">0</span>, <span class="ql-token hljs-number">0</span>, <span class="ql-token hljs-number">255</span>) </div> <div class="ql-code-block"> self.dark_blue = (<span class="ql-token hljs-number">0</span>, <span class="ql-token hljs-number">0</span>, <span class="ql-token hljs-number">139</span>) </div> <div class="ql-code-block"> self.BG_COLOR = self.white <span class="ql-token hljs-comment"># 游戏背景颜色</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-comment"># 定义方向</span> </div> <div class="ql-code-block"> self.UP = <span class="ql-token hljs-number">0</span> </div> <div class="ql-code-block"> self.DOWN = <span class="ql-token hljs-number">1</span> </div> <div class="ql-code-block"> self.LEFT = <span class="ql-token hljs-number">2</span> </div> <div class="ql-code-block"> self.RIGHT = <span class="ql-token hljs-number">3</span> </div> <div class="ql-code-block"><br> </div> <div class="ql-code-block"> self.HEAD = <span class="ql-token hljs-number">0</span> <span class="ql-token hljs-comment"># 贪吃蛇头部下标</span> </div> <div class="ql-code-block"><br> </div> <div class="ql-code-block"> pygame.init() <span class="ql-token hljs-comment"># 模块初始化</span> </div> <div class="ql-code-block"> self.snake_speed_clock = pygame.time.Clock() <span class="ql-token hljs-comment"># 创建Pygame时钟对象</span> </div> <div class="ql-code-block"><br> </div> <div class="ql-code-block"> [self.snake_coords,self.direction,self.food,self.state] = [<span class="ql-token hljs-literal">None</span>,<span class="ql-token hljs-literal">None</span>,<span class="ql-token hljs-literal">None</span>,<span class="ql-token hljs-literal">None</span>] </div> </div> <p><br></p> <p>设置奖励条件与游戏终止条件</p> <div class="ql-code-block-container"> <div class="ql-code-block"><span class="ql-token hljs-comment"># 判断蛇死了没</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">def</span> <span class="ql-token hljs-title">snake_is_alive</span>(<span class="ql-token hljs-params">self,snake_coords</span>): </div> <div class="ql-code-block"> tag = <span class="ql-token hljs-literal">True</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">if</span> snake_coords[self.HEAD][<span class="ql-token hljs-string">'x'</span>] == -<span class="ql-token hljs-number">1</span> <span class="ql-token hljs-keyword">or</span> snake_coords[self.HEAD][<span class="ql-token hljs-string">'x'</span>] == self.map_width <span class="ql-token hljs-keyword">or</span> snake_coords[self.HEAD][<span class="ql-token hljs-string">'y'</span>] == -<span class="ql-token hljs-number">1</span> <span class="ql-token hljs-keyword">or</span> \ </div> <div class="ql-code-block"> snake_coords[self.HEAD][<span class="ql-token hljs-string">'y'</span>] == self.map_height: </div> <div class="ql-code-block"> tag = <span class="ql-token hljs-literal">False</span> <span class="ql-token hljs-comment"># 蛇碰壁啦</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">for</span> snake_body <span class="ql-token hljs-keyword">in</span> snake_coords[<span class="ql-token hljs-number">1</span>:]: </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">if</span> snake_body[<span class="ql-token hljs-string">'x'</span>] == snake_coords[self.HEAD][<span class="ql-token hljs-string">'x'</span>] <span class="ql-token hljs-keyword">and</span> snake_body[<span class="ql-token hljs-string">'y'</span>] == snake_coords[self.HEAD][<span class="ql-token hljs-string">'y'</span>]: </div> <div class="ql-code-block"> tag = <span class="ql-token hljs-literal">False</span> <span class="ql-token hljs-comment"># 蛇碰到自己身体啦</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">return</span> tag </div> <div class="ql-code-block"><br> </div> <div class="ql-code-block"> <span class="ql-token hljs-comment"># 判断贪吃蛇是否吃到食物</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">def</span> <span class="ql-token hljs-title">snake_is_eat_food</span>(<span class="ql-token hljs-params">self,snake_coords, food</span>): <span class="ql-token hljs-comment"># 如果是列表或字典,那么函数内修改参数内容,就会影响到函数体外的对象。</span> </div> <div class="ql-code-block"> flag = <span class="ql-token hljs-literal">False</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">if</span> snake_coords[self.HEAD][<span class="ql-token hljs-string">'x'</span>] == food[<span class="ql-token hljs-string">'x'</span>] <span class="ql-token hljs-keyword">and</span> snake_coords[self.HEAD][<span class="ql-token hljs-string">'y'</span>] == food[<span class="ql-token hljs-string">'y'</span>]: </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">while</span> <span class="ql-token hljs-literal">True</span>: </div> <div class="ql-code-block"> food[<span class="ql-token hljs-string">'x'</span>] = random.randint(<span class="ql-token hljs-number">0</span>, self.map_width - <span class="ql-token hljs-number">1</span>) </div> <div class="ql-code-block"> food[<span class="ql-token hljs-string">'y'</span>] = random.randint(<span class="ql-token hljs-number">0</span>, self.map_height - <span class="ql-token hljs-number">1</span>) <span class="ql-token hljs-comment"># 实物位置重新设置</span> </div> <div class="ql-code-block"> tag = <span class="ql-token hljs-number">0</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">for</span> coord <span class="ql-token hljs-keyword">in</span> snake_coords: </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">if</span> [coord[<span class="ql-token hljs-string">'x'</span>],coord[<span class="ql-token hljs-string">'y'</span>]] == [food[<span class="ql-token hljs-string">'x'</span>],food[<span class="ql-token hljs-string">'y'</span>]]: </div> <div class="ql-code-block"> tag = <span class="ql-token hljs-number">1</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">break</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">if</span> tag == <span class="ql-token hljs-number">1</span>: <span class="ql-token hljs-keyword">continue</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">break</span> </div> <div class="ql-code-block"> flag = <span class="ql-token hljs-literal">True</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">else</span>: </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">del</span> snake_coords[-<span class="ql-token hljs-number">1</span>] <span class="ql-token hljs-comment"># 如果没有吃到实物, 就向前移动, 那么尾部一格删掉</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-keyword">return</span> flag </div> </div> <p><br></p> <p>自动玩贪吃蛇游戏部署,设置贪吃蛇的复活命数为10次</p> <p><br></p> <div class="ql-code-block-container"> <div class="ql-code-block"> if __name__ == "__main__": </div> <div class="ql-code-block"> random.seed(100) </div> <div class="ql-code-block"> env = Snake() </div> <div class="ql-code-block"> env.snake_speed = <span class="ql-token hljs-undefined">10</span> </div> <div class="ql-code-block"> agent = AgentDiscretePPO() </div> <div class="ql-code-block"> agent.init(512,6,<span class="ql-token hljs-undefined">4</span>) </div> <div class="ql-code-block"><br> </div> <div class="ql-code-block"> # 加载强化学习的训练模型 </div> <div class="ql-code-block"> agent.act.load_state_dict(torch.load('model_weights/act_weight.pkl')) </div> <div class="ql-code-block"><br> </div> <div class="ql-code-block"> # 设置贪吃蛇复活次数 </div> <div class="ql-code-block"> lifes = <span class="ql-token hljs-undefined">10</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-undefined">for</span> _ in range(lifes): </div> <div class="ql-code-block"> o = env.reset() </div> <div class="ql-code-block"> while <span class="ql-token hljs-undefined">1</span>: </div> <div class="ql-code-block"> env.render() </div> <div class="ql-code-block"> <span class="ql-token hljs-undefined">for</span> event <span class="ql-token hljs-undefined">in</span> pygame.event.get(): </div> <div class="ql-code-block"> <span class="ql-token hljs-undefined">pass</span> </div> <div class="ql-code-block"> a,_ = agent.select_action(o) </div> <div class="ql-code-block"> o2,r,d,_ = env.step(a) </div> <div class="ql-code-block"> o = o2 </div> <div class="ql-code-block"> <span class="ql-token hljs-undefined">if</span> d: break </div> </div> <p><br></p> <p>最终在PyCharm环境中贪吃蛇的运行效果如图:</p> <p><br></p> <p><img src="https://pic.code-nav.cn/planet_post_image/1655447521608110081/cjxikdgv.jpeg" align="center" style="display: block; margin: auto;" width="684"></p> <p><br></p> <p>实际的动图检验效果:</p> <p><br></p> <p><img src="https://pic.code-nav.cn/planet_post_image/1655447521608110081/2c5ybgr3.jpeg" style="display: block; margin: auto;" align="center" width="387"></p> <p><br></p> <p>通过ChatGPT指导的AI自动玩贪吃蛇,怎么样,效果不错吧,是不是很想尝试一下,没事,马上安排上!以下Github地址链接,本地拷贝一下,就可以玩耍了!</p> <p><br></p> <p>Github社区链接:<a href="https://github.com/qianyuqianxun-DeepLearning/SnakeGameAI.git" target="_blank">https://github.com/qianyuqianxun-DeepLearning/SnakeGameAI.git</a></p> <p><br></p> <p>我是千与千寻,一个只讲干货的码农,我们下期见~</p> <p><br></p> </div> </body> </html>
