粉丝6.0万获赞2.8万

大家根据我给到的网页进入到我的 github 主页之后,我已经将最新版本的圣诞树代码上传了,那么你可以点击这个位置有个 releases, 点进去之后可以看到这版本的更新内容。首先 可以将音乐和图片写进代码里,这样你就可以发送给朋友了,但是请记得发送给朋友的时候,嗯,需要把整个文件夹打包,或者你也可以采用跟我一样把它上传在 github 上的方式,这样 朋友收到的时候可以直接下载,或者可以通过他给到链接打开就行了。那修改图片和音乐的位置的代码在这里,就你可以用 ctrl 加 f 位置微调,操作系统的话在就会出现这里有一个搜索框,比如说我搜索它的关键字可以定位到 图片的位置,那就在这里你就可以修改图片的路径和音乐的路径,但是这个图片和音乐的文件请你一定要放在跟这个 html 文件同样的路径下面,你想我就放在这里。然后如果你要加多个图片的话,这里是用逗号,要用英文的逗号,然后把这个复制一遍, 就是一样的架构。然后那个图片假如是 photo 二的话,你就修改它的名字,和你图片的名字一样就可以了,那我这就是以一张图片作为视例,然后音乐也是一样的放一个音乐啊。我们还是保留了这个在网页上上传音乐和图片的功能,如果你按 h 的 话可以隐藏掉这个篮筐, 就这样就不见了。那第三个的话音乐可以自动播放,我尝试了一下谷歌浏览器的话,还是会出现限制音乐自动播放的,那如果出现了限制情况的话,你可以点击屏幕的任意位置,他就会开始播放音乐。第四个功能就是新增了一个性质的功能, 我对这个屏幕比一的话,它就会出现这个性质,然后后面的球还是会根据手的移动来进行转旋转。文字的内容你也可以在代码里面进行修改, 我们还是在这里搜索它的关键字 friend, 因为,嗯,我的视力里面是有这个关键字的,你也可以搜索书信内容配置,我在这里加了一个注上,还可以解锁到,那这里就是标题的位置,这是书信的内容,你可以修改这个斜杠 n 是 换行符,就是可以写不一样的内容在里面。第二个功能就是新增一个 merry christmas, 那 你可以通过手指比二的形式,然后它会伴随烟花弹出, 就这样子,然后你可以移动手指,它也会进行旋转,那这烟花的颜色你也可以在代码里面进行修改,现在我用的是绿色、银色和金色的搭配, 然后这就是主要介绍,那代码的话就在这下面这个 s s 里面可以下载,我们下载点击了之后就会弹出下载的提示,然后我已经下载好了,下载好了之后解压它就是这样的一个样子,那你就双击这个 icloud 文件,如果你不想对内容进行修改的话,然后允许上头,然后这边就可以了,我们可以用 maccode 或者是 id 二打开它,这样的话实际上如果你有修改代码的需求的话,这个也会比较方便。我们如果使用 id 二的话,在麦克上面我们可以运行一个这样的代码,然后它就会启动这个外部服务。 接下来这个就是我们也可以通过这个链接来访问它。那如果你有用手机操作的需求的话,实际上你的手机跟电脑可以连接同一个网段,也可以访问,但是也可以通过你手机上自己打开一个梯子,然后运行这个 h 条文件都可以。那现在我们可以用这个页面,我是比较希望用谷歌来运行,所以我新建一个网页 回车之后它会出现一个这样的情况,但是没有关系,我们点击点击就会进入到这里,现在会自动播放音乐,然后它会识别你的手,但其实它应该会弹出一个摄像头的访问权限通知你就点击允许就可以了。 然后我接下来就可以对它进行操作一二,然后可以调用图片,还是比较丝滑的。以上就是这个项目的使用教程,如果有不会的话,还是可以评论区留言问我。

一天学一个变态的人工智能知识第一百一十七期这节课要讲的是对号选项目到跑通代码全流程避坑技巧,时长三十五分钟,看不完先收藏关注我,后续接着看大家跑开元项目是不是经常去打开这个号吧, 那么说打这个号吧当中第一件事干什么?我建议大家,就比如说咱们找到一个开元项目之后啊,咱不要说你上来干啥, 你上来直接就跑,先找什么?先去看一看啊?就人家这个大树是多少,人家这个放个数是多少,一般情况咱们干什么先找这些数量比较多的,找数量多的干啥?你可以这么理解,这就是比如说你上京东买东西,你上京东买东西啊,是不是第一件事你看销量, 那这个 style 树一定程度上决定这个东西有没有人用,用的人越多的,人家官方团队才可能去维护,人家才能可能去修复 bug, 以及大家反馈比较多。所以啊,就是先找优先 style 树高的。大家说什么叫高呢? 我举个例子,比如说一些大一点的开源项目,那可能一般得一 k 加一般。对于论文来说啊,论文大家可能作为领域不一样, 论文来说,我觉着比如哪个论文公开原码,他能有个一百加,我觉得都是有参考的。一百加以上说明这玩意还有人用,还是有可能几千个人在用啊?这件事你们先看,但是你要说四大数就是个位数的,或者说十十几个二十个, 我不建议去考虑,那玩意应该也是没啥影响力,应该大概率可能一堆错误,是不是?所以说首先先看这个,这是第一件事。 第二件事看什么?不要先看这个原码,因为你看其实咱们讲了很多看像,嗯,这里边我有一个习惯,我在看一个原码之前啊,我会想,我要花很多时间成本去调试这个东西,去列代码, 那这个项目可不可能本身有什么问题?怎么看本身有什么问题啊?大家看这一块,这块有一个很大几个字,叫什么?叫做一个 s 九, s 九其实是我比较喜欢看的,就是是别人提的一些问题,你可以当做,比如说你买个商品,你可能去看一个评价,是不是好点开搜看一下,在这里边啊, 你看点击之后它有一个 open, 有 个 close, open 就是 说还在提问呢,然后这个作者没有关闭 close 呢,就是作者已经关闭的,嗯,一般我不看 open 的, 我看 close 的。 一般 close 当中啊,大概率是有人回复的,然后作者肯定也回复了,然后就给它关掉了。我们点开来看一看这块,其实我们后续跟大家说报错怎么解锁关键词, 一般我建议大家这样一件事,先看一看其他人的说法,要是一堆人说这个项目狗屁不是的,这个项目跑都跑不起来,各种各样 bug 宣传不出来,结果也跟论文不一致, 赶紧干什么,及时止损,再去找另外一个项目。所以说建议大家首先去快速刷一遍, 你快去刷一遍时候怎么样?你有印象了,就是大概大家可能遇到什么问题,一会我万一报错了,环境组配的时候,哎,是不是可能干什么?可能我也会找到这个东西啊。嗯,那比如说第一个问题,我觉得作者需要在指明拍子版本以及更多的环境。哎呀,我看有没有回复的啊?没有回复,那我不看了,右边这边他就有回复几个,你再往下找, 你看右边都是有,有的是有一些人回复的,回复的不一定可能是作者,可能是谁,可能是人家就是个个路人,像你啊,像我啊,可能遇到这个问题了,像我,我经常,我经常就是,比如说我看到什么事,然后我跑个项目,然后我看到里边有人问其他的,就是 赠人玫瑰,手有余香的感觉,我就简单回一下,简单看一下,很常见。这里边你看这是,这应该就是个路人,这应该不是个作者,你看人家问了一个问题,在这里边数据集的一些选择,那别人知道会回复一下。所以我建议大家就是当你想去熟悉一个项目的时候, 第一步是先看这个 iso, iso 当中可让你能知道这东西值得去做,这是第一件事。第二件事,这个 iso 当中它可能会告诉你很多你没发现的事。那比如说我在做的时候呀,我说人遇到这个 bug, 那 我可能也有这个 bug, 我 没修复,那是不看人家怎么做都可以改过来。 好了,这给大家说。第二件事,看完 size 之后啊,先看这个 iso, 这个 iso, 你 看完之后,就有时候你看一些商品,那差评一大片的,你压根连买的欲望都没有了。所以说这个 iso 我 建议大家第二个去看, 第三个干什么?第三个看他的 readme 文档啊,我一般是后看 readme 文档,因为大部分 readme 啊,其实写的都还行,但是就像你们买商品,你们愿意看商品介绍吗?你们不愿意,你们愿意看评价,是不是?第三件事,我们再看这个商品介绍,商品介绍就这个 readme 文档,嗯,一般来说啊,能跑得起来的项目效果还凑合,能差不多点东西 一般写的得是相对来说挺多的,还有这个更新日期,然后还有呢,他的一些排行榜单, 还有呢,就是他啊,他这里边可能会对比实验用到的模型,人家的原码,人家的论文是什么?哎,你看挺方便,都给你执行好了,你想用这个对比实验,你想看人家论文,你想去引用,都给你列出来,是不是?哎,我觉得这又挺好的, 越权利格瑞德密,说明人家是越伤心这个事,越伤心这个事人家原码大概率也做越好,然后再往下,我们主要看一般就有这个 usage, 其实名字不一样,有的瑞币当中啊,就直接直接跟你说啊,你去跑什么模型,去做什么事,然后你看这块他说什么,他说那你要跑这个项目,人家原始论文作者,他用的是一个 python 三点八。那我问问大家,咱们看到这句话时候你会不会想一件事,你的 python 三点九,你的 python 三点一零能不能跑呢? 其实我跟大家说大概率是可以的,但是如果说你为了保险起见,咱们就新建一个环境,那我们就照这个例子给大家举个例子。我看到了人家三点八,要大家说那有的是开个项目,他也,他也没靠原版是啥呀? 你通过这个年份大概率就能猜出来了,但是你看这个年份,这个五个月之前,六个月之前,嗯,我好像够呛能猜出来 啊,一般五六月之前,那可能还是三点一二呢,可能三点一一呢,是不是?那我怎么才有三点八呢?这个你这个就不一定了,这个你可以看看 i 九当中的,也可以看看大概年份,没准能推断出来。没推断出来我跟大家没关系,基本上就比如拍套这个包,向下兼容还是很好的,我们都可以来试一试啊。 那这里边你看人家既然说了,人家既然说了他是三点八,那咱就办呗。来打开你的 any control permit。 这会咱们干什么?第一件事,我先新建个环境,新建个环境有个好处,别一会装一堆环境,把我自己的东西咱就全装乱了好不好?来,我们比如说 py 三八吧, 好,比较 p i 三八,比如说我们叫做 p y 啊,三八,然后叫 type net 啊,说一下这个项目名字要叫什么,然后呢,你去指定一下这个 python 版本,等于,然后三点八点零好不好? 然后呢,咱们去创建一个环境,这是第一步,我让他自己先去下载一个环境,我就跟这个原始论文作者一样吧,人用啥环境我就用啥环境。这第一件事,然后第二件事他可能说就是人家用这些包啊,我就用啥环境。这第一件事他可能说就是人家用这些包啊,我就用啥环境。这第一件事他可能说就是人家用这些包啊,咱们回来看 这块呢。接下来第二件事就是,你看啊,人家这个一般项目当中啊,都有,都叫什么?叫做一个 requirements 点 t i t, 这个一般都是作者会写的,他说啊,我用了什么样版本,你们最好跟我一样,因为有时候是这样的,就是比如说论文当中啊,你经常遇到一件事,比如说人家跑了个模型,人家效果挺好的,那我为啥跑了个模型,我效果变差了呢?嗯,这个东西很玄学, 你说能不能受这些排损版本的影响呢?能不能受这些工具包版本影响呢?甚至能不能受苦打版本的影响?嗯,我可以说都有可能这件事吧,解释不清。玄学东西啥都有可能,还有可能人家也随机转参数,那跟你也不一样。 所以说咱们为了保证近乎相同作伴,我们点开一下这个 request, 点 t i t。 简单先看一看。简单看什么? 就你看这个项目当中,人家也没说这个东西是 windows 去跑的还是 linux 去跑的,是不是?哎,但是一般情况下我们我会看几个包,我举个例子啊,就现在,比如说大家可能做很多大模型,是不是?好,我给大家举个小例子, 就这一个啊,就这一个。呃,来,我给大家举个例子,我给大家举个例子啊,哪个包来着?一会我们来找吧。我也,我也忘了哪个包不是这里边的,就之前有同学问我的,然后他那个包,然后我当时也看了很久, 然后后来我一查我就发现了,我真忘哪个包了,后来我一查,这个包只有 linux 能去用, windows 是 用不了的。所以说有时候你要看一看 这里边这些包啊,有没有是 windows 解决不了的,因为一般全是这样,就是 linux 能下能跑的东西。对,就那个分布式,那个东西就是 linux 下能跑的东西啊, windows 不 一定的,就是这个同学说的陈奕迅这个同学说的分布式的。就是我跟大家说一个前提啊,你找有没有一些分布式的包, 但凡是跟分布式相关的, windows 基本上来说是都用不了的。我们那大家说那 windows 用不了怎么办呢?自己租个服务器啊。租个服务器其实也没多钱,两块来钱一小时。现在,现在,现在租服务器很卷啊,你就租这个三零九零,我估计一块五。 以前我租的时候越来越便宜,我也不知道为啥,最开始我租的三零九零四块多,就刚出的时候,然后后来三块多,后来两块多,然后前两天我一看一块多。这东西很便宜啊,你可以自己租个环境跑两天都行的啊。好,这件事我们先看一下这里面有没有啥是温度不能用的,及时止损,别温度。就有朋友说给我磕了两天, 一发现有些包温度压跑不了。这个这个不多啊,但是但凡跟分布式相关的,这里面就挺多了啊。好,那我们看这个环境 来,兄弟们看环境是不是配好了很快啊,然后接下来我们去看他干什么?我去啊,激活下这个环境。呃,激活这个环境,然后我们叫什么名字来着? 我看一看叫什么名字我都忘了。叫这个 p y 三八, type p y 三八,然后 type net。 是 不是这一会我们可能会讲的一篇论文啊?好,那我们激活这个环境就是切换到这个环境当中,那下面干什么?我们是不是说人家这里边是给了我啥?人家这里边他是给了我这样一个 request, 那 我就直接装人家做的依赖环境。行了, 我的新环境直接装跟人相同版本的。那怎么做呢?这块咱们点这个 code, 我 们去下载。嗯,其实你们会用这个 get 命令啊,直接 get 命令也行啊,但是我估计大部分同学可能懒得装,尤其是 windows, 整不明白, 咱就手动下载,下载这个压缩包也行。下载压缩包之后啊,我们保存一下。保存到哪呢?随便找个地方吧。来,我保存一下,比如说就保存,我随便找个地方, 我找,我找一个我的路径。哎呀,我这个路径里面东西太多了,我找一找啊,我的拍唱在这呢,我保存到拍唱当中,然后二零二五里边,然后改个名字吧。改个名字好不好? type library, 然后保存一下。保存完之后呢,咱们自己解压一下。这个很快啊,来保存, 保存完之后呢,你看有这个文件夹是不是?然后呢?接下来我们给它解压出来完之后啊,我们稍等一下,这一块呢,我给它解压出来, 然后。哎呀,这里边我就替换吧,因为我之前解压过了,我今天直播之前我先试了一遍,我先别说啥问题,我先试了一遍,然后你看这里边我把压缩包删掉。咱们是有一个项目了,哎,这个项目完整的东西咱们现在是不能拿到手了。 好了,这是一件事,就是先把这个项目下载好,然后解压好。解压完之后呢,咱们进入到这个路径,我复制一下这个路径, 然后在这里边我进入到这个路径当中。进入完这个路径里边之后啊,然后大家帮我看一下。就你进入到这个路径当中之后,呃,我们看它这里边是不是有文件叫这个 requirements 点 t i t。 那 加么我说装备,你看我说 p i p install install 什么一排位引导杠 r 杠 r, 就是 装一个文件夹,里边指定所有包 requirements, 点一下回车,这回呢,它就自动地按照人家这个版本咔咔咔帮我装东西。呃,但这里我给大家说一个问题啊,就是人家有时候你比如说你看我点开完之后,点开之后,你看它这个 touch, 它一般会写版本号,但是你看比如这个 touch 一 点七点一,是不是它会帮我装这个版本?但是我问题是什么?嗯,就是它默认装的是个 cpu 版本, 然后他想说,那我他装了个 cpu 版本,那我自己要不要重新的去装一个 gpu 版本呢?是可以的啊,就是人家和你这个自己检查一下 人家一般情况下指定的 touch, 还有什么 touch word 那 个东西,它都是个 cpu 版本,那肯定你们是不要的,你们要 gpu 版本是不是重新的给他 p i p i n star, 然后下载完之后你自己再装个 gpu 版本就可以了。 好,那么稍微等一等这块呢?这块因为我是个新的环境,所以说他会装的包挺挺多的。嗯,但是也挺快的,我这个网速非常快啊,所以说他下东西很快,然后他接下来他就会批量帮我把这个包装好。 这样,其实我们现在就有什么这样,咱们现在是不是就手里有这样一个环境了?好,那我们现在第一步干什么?已经把卷板下载下来,已经按照一个方法去配置一个环境,然后再往下看,再往下研究,一般情况下会给你说,就是这里边干啥不是一个手动的手动安装,为啥要一个手动安装?如果说你在你之前老的环境里边,你可以一个手动安装, 但是我们刚才说了,咱们这里边干啥?我们这边人家不就是有一个指定的文件夹吗?这个一般一般大部分看一下吧,都会有这样一个叫 root 点 t i t 的, 这里边干啥?咱们直接偏僻 in star 这个文件啊,你们,你们如果忘了,回头看下录播,这时候该我指定了,你们还记不记我刚才命令了? 来给大家看一下刚才这个命令啊,你们记不住的,来拿手机拍一下,截个图,这这这里面自己百度搜,也就 p i p star 杠 r, 就是 按照一个文件夹要求,一般它叫这个名字 requester t i t, 这也包括了所有包的版本,我们就批量把所有的环境啊,所有的包都装好了, 装好完之后呢,接下来这样就可以了呀。对啊,这样就可以啊,然后再往下,再往下。其实我再跟大家说,你们自己去装一个套式 gpu 版本,这个我就给你们演示了,你们自己下啊,我们套式上树说过,就是比如说咱们自己手动下个点 w 十二文件,然后去装,你们可以装 gpu 版本啊。好,那我回来再看, 我们回到这里边,这里边他可能啊,就是有一些使用方法,你还到时候接来,你去春或者是评估这个模型的时候,你该怎么去做,然后但是大家来看这个命令,很多同学啊,之前看到这就蒙了,他说这个命令当中啊,他是一个 bash 啊,就是执行个什么脚本,然后什么点 a c 是 文件,他说这玩意 windows 也整不了啊,那我这是不就废了,这,这命令我执行不了, 执行不了这个命令该怎么办?我跟大家说下这个方法啊,来,咱们先,嗯,边打边说吧,我们刚才已经创好环境了,咱们在我们这个拍唱当中,我现在已经打开了啊,已经打开了这个项目,打开了这个项目之后呢,接下来 我们来看一下,简单的去浏览一下这个项目,然后啊,先看这里边吧,我觉得网页比较大,我就拿网页为大家再放大一点,但你看网页当中,他说呢,你这里边你想做这个长时间学预测,你该执行哪一个脚本文件?你想执行短序的预测,该执行,然后补全的异常检测的分类的,他是不每一个都列出来了 啊。然后我们举个小例子,比如说我们看这个短时吧,这个少腾啊,因为一会我们就演示这个,就是一会可能一般时间去列,还是这个短时作业比较多, 他是不是执行了一个什么点 s h 文件,大家说这咋办?我不是 delete 一 次,我也执行不了点 s h 文件啊,我跟他说咱们先找你看,他说啊,他说你在这个 script 里边儿当中有一个什么 short term 啊,然后 forest 一个预测,然后还有什么 type set m 四点 s h, 我 说我也不知道是啥啊,咱点开看一看,来,我们去找 找这个 sql 当中,然后按照人家这个要求短序列预测,然后再去找。哎呦我去,这东西太多了,我,我看一下,我记不住了,你要叫叫什么来着? times night, 然后 m 四点 a c h 是 吧? times night, 因为它这里边可以跑好多时间序列源码啊,这是它们在 m 四点。哎,来,你看这块儿, 我给大家对应一下,是不是有这样一个文件,咱们点开这样一个文件就可以了啊?好,然后咱们来去双击,你看现在我就点开这个文件了,这个点 c p n 当中啊,其实你不,你不用怕,说你这个温度执行不了他这里边脚本,他这边脚本大概率就是啊,先执行什么东西,后执行什么东西,我们手动去执行, 其实是都可以的啊。好了,接下来装 gpu 版本啊,太高。嗯,其实一般情况下 touch 是 向下兼容比较好的, 但是一般跟人家一样,一般是跟人一样是最好的,这样可能你复制出来结果你就不会去怀疑是环境导致的还是代码导致的,因为有时候大家你们自己去盘代码时候效果比较差,你自己都懵,你别说你懵,我也懵, 我盘之后我也纳闷,就这玩意为啥效果差?我也不知道啊。那你最好跟人环境一样,那起码我们就能分析其他东西了,控制变量法呗。来,你再看这块,这块你看一下,就是他这一块说了,他说他说你要运行的时候,你要执行这个转点 p y, 然后下面他是给你解解释一些参数是不是?所以说你别看他这个点 s h 文件挺唬人的,里边就是干啥,就是一个让你用 python 执行什么东西。好,那我去找他说呢,现在用这个 python, 但是你们每个开玩笑吧,可能不一样的,不是说所有开玩笑吧都会给你点 s h 文件, 有很多。开玩笑,我会告诉你直接执行什么文件,大概率会告诉你直接执行什么文件啊?这两天这块他说让你去执行这个软点批歪,那我找一找呗, 找到这个 run 点 p y 是 不是啊?这块有个 run 点 p y 是 吧?哎,我找到了,然后呢?他这里边说,他说你在执行的时候啊,你需要指定这些个参数,是不是?好,那我是这样,我先把所有的参数都复制下来,你看这要求所有参数是不是。好,那我来试一下啊,我也不知道能不能跑成功,然后我们,哎,然后还没切换环境, 咱们看我这拍唱当中啊,拍唱右下角,咱们是不是可以去切换这个环境?来,我举个例子,你看我右下角,咱们点开,然后我们去点这个添加一个环境,添加时候选择这个已有的环境,因为这是我 kindle 当中咱们自己创建的 已有环境当中。接下来咱们去找找一下我们新安装好的环境,然后选中他的拍森点 es, 然后呢?接下来我们点这个, ok, 可以了,下面他会读这个进度条,这个进度条如果说你装了一个新的环境,里边包是比较多的,他可能进度条加载的比较慢,但是我这里边包比较少,所以说加载比较快啊,他毕竟是新环境,老环境一般加载比较慢啊。好了,然后再往下,再往下,你看这个转点偏爱当中啊,人家刚才不是说吗?去执行这个,然后他让你去选一些参数,是不是? 好,那这样咱们来去啊,现在还不能转,你看现在还不行,是不是?这块我们稍微等一等,因为你这个进度条啊,还没有加载完,这个这个进度条加载完了他才能去执行这个东西啊,这块还不能配置,那我们那我们 这里稍微等一等,这块他就比较慢了,你看他在一点点加载来看,哎呀,他不用我,我记着啊,他是不用全加载完,然后他就可以去执行了,你看我一直点,其实啊,全执行完之后 稍微等一等吧,他确认完之后啊,就是他会有一个配置,那个命令参数人家在这里吧。大家可能说,哎,人家为什么要直用这种方式呢?人家为什么不把什么拍照的参数给你指定好呢?为什么还要用脚本的方式点 s h 去执行呢?我跟大家说解释一下,为什么。 就是一般情况下,比如说你想去跑实验,很少说在你本机去跑,大概率都是连你的福气啊,比如说你们学校是不是都有福气啊,你们公司是不是都有福气啊?就没准在自己本机上去跑这些东西。因为一般情况下,比如说我们工作的时候,我们自己就是公司就发一个笔记本, 其他所有东西都在服务器上去跑,那我们是不是要连到服务器当中?连到服务器当中大概率是没有。这些面向窗口的都是用什么,都是自己写一个脚本,把菜单写好丢上去直接跑了。 所以说人家开玩笑吧,他也是,他也是为了这样的方便给你们去准备的,不是为了故意难为你们啊。好了,那我们找开这个 run 点 p y 让我们右键,你看有了是不是来,你看我点这个 run 点 run 说他肯定直接跑不起来,他跟你说现在有些错误,是不是?来,别着急啊,在任务当中我们先配置下这个参数,先把参数也配置好,就这一块我们去执行这个 run big 这个东西,然后刚才我是不是要复制一下子了?来,我把我刚才拿的复制过来,你看这不咱输入复制所有参数啊,然后对齐一下啊,来对齐一下。 哎呀哎呀,我看一下,给它复制过来,然后呢,我稍微调整这块前面空一些空格,没关系,空格其实没关系的,然后这样吧,咱们复制完之后,咱们点一下, ok, 点 ok 之后呢,我们来点一下转,看看结果怎么样啊?肯定是有很多报错的。哎,他说现在, 他说现在呢,不认识一些你的面料参数,一堆杠,哎,我看看怎么会有一堆杠呢?你看再点开,再点开这个东西啊,你发现发现就是你复制完之后,实际执行完的时候, 他给你多添加了一个东西啊,他说有一对杠没识别,是不是咱手动给删掉,来把这个杠删掉啊?因为刚才的杠这样写后面是没事的,但是我不知道为什么他给我自动放前面去了,一执行好,那我就删掉,不需要这个杠啊,好,都删掉,每一个杠我都给他删掉,删掉完之后呢,咱们再来去执行,然后看他再给我提示什么东西啊,来 一个个删他这些默认参数。我先不管啊,因为你想去理解这个参数,你就要在原码当中咱们一个个去看了啊。我底 bug 这个操作就给大家讲过很多了,但是我们一般还是很少说从零开始配环境,我就给大家演示一遍,然后点这个, ok, 然后我们再点这个乱, 再看题是什么,他说什么,然后我们就照样去做,哎呀,他说有个 key i, 嗯,我给大家看一下,咱们一点点分析啊,遇到报错没关系,我们来简单分析一下,他说有个 key i, 他 说没有这个,呃,没有这样一个字典当中啊,可能缺少一个东西,呃,貌似这个东西没有啊,那咋办呢?哎,那我得想 这个貌似这个东西他是干什么的,为什么没有呢?那我们简单来分析一下,你看一下这里边啊,就是其其实这个东西啊,我问大家,就是大部分同学,你们一眼就能看出来是不是? 是不是大家一眼就能看出来?他说这里边好像缺啥东西,是不是这个 max 当中他多了一个引号,反而发现他是多了一个引号啊?那还有些同学,他说接下来他不知道这东西怎么办,他说我看不出来这里边是多了一个引号,少了引号咋地呢?我们在这里边大家注意啊,我们可以打成个断点,是不报错了,我打成个断点, 打出了断点完之后呢?我的 bug, 我 只想到断点这,然后我看一看行不行啊?来只想到断点这,我看一下。他在这里边,他说这个任务当中,你看我们传进来是什么?我们传进来的给大家看我们传进来的啊,我给大家截个图, 你看一下我,我在这画个图吧,因为我这 bug 有 点小啊,你看我一传进来这个东西,它是不是啊?它是不是一个,哎,它是不是一个? 一个引号完里边还有个引号啊?还好像感觉多了个引号,我也不知道为什么多一个引号。那我再看一下人家这里边,你看人家这个字典当中啊,我记得应该是个字典吧?来,你看人家这个字典当中他是不是,是不是有一些 key 啊?这些 key 当中。来,我再给大家看, 你看这个 key 当中他有什么?他这个名叫什么?他这个名字跟我们下面这个名字一对比,哎,你发现发现,一对比完我给大家画起来,画一条线吧,你看咱们一对比咋样?一对比我一发现, 我这里边怎么多了个引号呢?人家这里边他是不是没有?他就是就一个引号,我这边两个引号,那感觉我的字幕串多了东西,所以他找不到,是不是 啊?所以说遇到问题不要不要怕啊,就是很常见的一个事,咱干啥遇到问题咱们就到那个断电,那我们去看一看他可能什么问题。哎呀,那我得找。哎,我说你这个变量是在哪来的呢?我又看了下代码, 这个代码当中啊,他说你看,他说是这个在什么你这个 x 当中,哎,这个 x 刚才不是我写的命令行参数吗?他说你指定的命令行参数当中啊, 这个名字你肯定指定错了,因为找不到咱们多一个引号,哎,那我回来看一看,我回来看一看,我这个命令行参数我们找啊,因为我刚才复制的,我连看都没看,我也不知道这里边是啥我连看都没看。我找你看,我找到这块来,我给大家看 这里边来,他是不是有,你看他这里边是不是多了一个引号?那刚才人家脚在那有这个引号,那我也不知道为啥他要有这个东西,到时候改对行不行?因为人家是那个那个命令行里面去执行,你是在拍上面去配,所以说有区别啊,那咱们也改对,我去掉这个引号是不是就可以了?好,那接下来我们再点这个 ok, 点 ok 之后呢?我们再去运行 一个报错一个报错,去看呗,别着急。好,然后接下来他给我执行,哎,他给我一执行的过程当中,我又发现他又出现了一个东西,他又说了一个 keyid, 他 说 keyid 当中啊,他说有个什么叫 model name, 哎,他前面还有到了,还有还有一个什么什么特殊符号,哎,我说这个特殊符号是什么,然后我一看这个报错,他又是我这个配置文件当中,他说你配置文件当中啊,这个 model, 这个 keyid 什么意思?那绝对就是说这个 model 他 没有加载到,那肯定这个 model 名字写错了, 那我们再看一下,我再右键,我点开来看,我看我这个 model 写的是啥呀? model, 来我们找。哎呀,大家来看这块,这个 model 当中啊, 他给的是这样一个名字,这个名字是啥?我也不知道啊,那我们看咱俩复制的这个东西,咱们刚才是不是在我这个点 s, 点 s 选项当中,我就点开了,然后我一看,我看人家写的就这玩意啊,那,那咋办? 你不要忘记人家写的就这玩意啊,那,那咋办?你不要忘记人家是直接引用上面那个 times night。 所以说咱们这要干什么来?我又发现一个问题啊,我说桌上没改,我把这个他们的给它复制过来,然后接下来呢,我们重新再配置一下,在这里边,你把你刚才啊选中的这个 model name 改成软件父的名字啊,来,咱们再点, ok, 让我们再去执行, 再去执行的时候啊,我们再来稍微等一等,哎呀,然后他又,他又告诉我一件事,他又报错了,他说现在这个 touch 啊,软件是,他说现在你的 touch 啊,没有这个库达,因为我是 p i p store 软件 requirement 点 t i t 默认什么默认装置?是那个 cpu 版本儿, 这里边两个方法就是一般情况下你们直接换 gpu 版本能解决的。那我跟大家说,如果说你没有 gpu, 你 找 cpu 包怎么办呢?咱们去找,咱们去找啊,人家这个这些参数当中啊,一般情况下是有的,比如说你看这一块,这是不是有一个参数 叫什么?叫做这个 race 啊? use gpu 默认什么?默认是个处,哎呦,我说默认处,我改成个 false 好 不好?我先看一下命令参数当中啊,我们配不配这个参数? 命令行参数当中,我现在大概一看,大概一看咋样?哎,好像没配这个参数,那我直接改吧。如果说我想用 cpu 去跑,那我就直接把这个东西给它改成一个 false 是 不就行了?让我们再点这个 run 再运行,反正就是执行开一项吧,那你肯定抵遇到一堆报错是不是?你看这块写了又是 cpu, 我 给它放大一下, 你看他说现在在用这个 cpu 跑,是不是?那我们稍微等一等,看看会不会报错啊?所以说遇到报错,我觉得这很正常啊,然后大家可以学会一个方法,你看咱们之前讲了很多的 bug 的 方式,通过 bug 咱们来去屡呗。基本上大家说啊,就是我总花时间去配环境, 花这个时间值不值呢?嗯,其实我跟大家说是挺值的一件事。为什么?积累经验啊?你想想以后你的工作,你的工作大概率要做什么?大家说我要搞底层,算下来开发啊,这个机会少之又少,大概率是套开源东西,跑自己的东西。 你们公司迭代很快啊,基本上来说,那你需要大量配环境,大量立业这些东西,所以说遇到环境的配置问题,我觉着练手是挺好的啊,越配越多,越配越熟练。然后他又给我提留报错,哎呀,我也看一看吧, 他给我提个报错,他说,呀,这一块啊,这一块什么涝,涝损损失的时候他说一个软 type, 什么东西?呃,软 type 什么意思啊?就什么东西为空了。这种情况下,一般来说就是可能你的数据啊,数据没有读到,可能有这个可能,再比如说你调用了什么函数, 这个函数他这个函数没有定义,也是有这样一个可能的。那我,我不知道咋办啊?我,那我,你看,这么看谁能知道啊?咱们点开点,到这之后呢,我们给他打上一个断点, 打上断点之后咱们还是右键,我们去抵 bug 到这来看一看,他跟我提示说什么为空了,那我就抵 bug 到断点。这我到底看一看,你到底是谁空了?数据空了我们就顺着往前捋,在哪读的数据啊?是不是路径给错了?为啥会空啊?是不是?好,我们就着这个事往前去捋啊,别着急 来,别着急,我们再往前去捋,然后这一块我们再做的 bug, 其实这一块我还要还少说给大家说一件事,就是什么?就是这一块其实人家还要让让你去下一个数据集的第二步,第二步这个大家自己去下一下, 他说了,就是他说你把你这个数据集啊下载好,他给你提供了一个谷歌或者百度网盘,然后让你呢下载到这个点编辑的文件当中,因为这个下的比较慢,所以说我是事先啊自己下载好了,已经放到这个位置当中了啊,这里面看一看,人家要求你的数据怎么获取啊?数据放入文件夹啊啊,你都可以看一看, 或者在命令当中当当命令行参数当中去找,人家可能发现什么位置了。好,那么回到这里边,这里边你看人家说给我报个错,是不是?我找找呗,我一般先看这个,先看数据, 这个 pitch x 我 现在不知道是啥,但是往手上一放,我说你有值啊,这个呢?这个我说你也有值啊,这个呢?哎,这我说你也有值啊,这个你有值啊,这个你有值啊,每个值都有哎,但是我一看这个东西,来,兄弟们,你看我这块,哎呀,我说好像发现了一个东西,怎么真的是一个空的呢? 来,大家看这里边,这里边他是不是有个东西,他跟我说什么 nan type, 什么东西,我把手上一放,他说是空的。那大我我,那我不一想这是啥东西吗?我也不知道啥东西啊,那我来找一找, ctrl 点进去好不好?我发现了这块呢,他是有一个函数的定义,你看这块函数定义,他这个函数定义干什么? 他说呀,要在我这个参数当中去选择一个损失函数是不是?好,那我看,我看一下,比如说我这个参,我看你怎么去选这个损失函数。他说呢?你这个 list name 不同的一个 last name 等于啊,不同的啥?不同的 last name 选不同的损失函数,这是我定义好的,那你看人家这块说 if 选了个什么东西? else if else if else if。 那 我大概率就能猜到了,肯定是我,我,我给的一个损失函数 没有包括在这些里边当中,所以他先返回是要空的。你,你猜这么猜对不对?哎呀,那我得想我为啥这要空的呢?我看这这里边 mse mpe mase, 那, 那我的损失函数是啥呀?来,我找一下我的损失函数在哪来着? 哎呀,我我我这跑哪去了?这个代码我找一下,我找一下,咱们该这个来,我,我去搜一下,来,咱们找到。你看这一块,这是我的损失函数,我把鼠标往这一放,我再给大家来看,你看我的损失函数又出现了一个问题,还是我刚才复制的,我复制完之后我连看都没看啊, 你看这损失函数,他又多了什么?他又是多了一个引号,是不是?哎,他叫 s m a p e, 我 先不管这损失函数是什么,其实你看我在这个代码当中,这里边 是不是有这个 s m a p 有 这个损失函数啊?它是有实现的功能啊,但是由于我的名字给错了,所以说现在找不到,所以它返回是个空的,所以它报错了。好,那我们回来,回这边我们看呗,我们找一下,找一下这里边。哎呀,我说看这最后损失函数是不是又多了个引号,我也没看这个东西,那我给它改对好不好?让我们再点这个, ok, 然后接下来我们再去转, 一步一步去看。让大家说我配个开源项目,然后这么多错误吗?嗯,这还是很少错误的,这还是很好的项目的。他没让你改代码呢,有很多开源项目还需要你改代码的,还需要你?就是我跟大家说啊,就是报错能解决的问题 真的都是小问题,什么问题最难跑出来结果差?那东西可难了,你就得慢慢分析了,一行一行代码去分析,为啥呀为啥呀?报错东西啊,还是很友好的,起码有提示,没提示的东西啊,你不知道该怎么改的,那才是最难的。 来,我们再往下看, windows 和这个训练营可以的,但是我不推荐大家用 windows 去跑啊,一般情况下你们还是在服务器上去跑,大家顺便得学一学李磊这些操作。 人家说啊,就是,呃,你们用那个无邦兔也好,用 windows 也好,就是以后你们的工作啊,你们工作的一个生产环境不可能是 windows 环境的啊。没有,公司是是用 windows 做生产环境的。我当时我们当时上班时候老板,嗯,就我比较特,老板呢,都要求用那个三 to s, 然后我说实话我不太喜欢三 to s, 因为我一直就用那个无邦兔,他们全用三 to s, 你 们用啥?其实随便吧,就跟大六。那你看这里边 东西是不是都有了?这里边是不是东西都有了?让你看他说现在迭代然后损失怎么样?哎,那我说我现在能跑完一个循环了,能跑完一次迭代,那说明现在这个代码基本没有问题了,那下面我就可以批量去做事了,是不是? 好,就是给大家演示了一下,就是咱们这个看相吧,咱们该怎么去做吧?啊?就是我随便举个例子,因为今天正好要讲这个算法,那我就,我就随便找了一个算法给大家去举例子, 然后我再给大家说一件事啊,就是很多同学啊,你说我在 d 八的过程当中,咱们遇到一些报错,遇到报错我给大家再说一下,咱们按照什么样的方法去剪索。首先第一件事,咱们先解锁什么?先解锁这个 s u, 先检测啥?先在 iso 当中我们去检测是不是?比如说刚才我遇到一个错误啊?我们来检测一下来,比如说我们刚才是不是遇到这个错误了?好,我检测一下,然后你看它这里边,哎,是不是它有很多什么软 type, 什么什么东西?哎呦,那我说我能不能看一看 人家这些东西,人家遇到报错是不是有跟我相关了?所以现在一般你找,比如说你跑什么?优优有多少个?这个优优才六百多个。六百多其实挺多的了 啊,六百个算多了,这个项目算挺火的了,一般一般项目 s 幺有的是几个,有的是几十个,有的几百几千的,就看这个项目火的火的程度。先在这里边解锁, 这里边解锁完之后,然后你们在谷歌去搜,谷歌搜完之后你在大模型去搜,大模型搜完之后你再找不着,你在百度去搜,反正这些检测我觉着就是一个,是吧?我是喜欢先找这 s 幺,而且我再给大家说一件事, 我真有个习惯,我不知道是不是强迫症啊,我会把每一个 sao 全看一遍,如果说我要把一个 bug 棒,把一个模型当做是我以后应用的一个项目,或者说以现在我论文要以它做的一个 base line 模型, 我要全看一遍的,我要知道人家都遇到什么问题啊,我有个印象,我说以后回来我看,我真的就会从头到尾去看的啊,我不看原码,我也会把这些问题先大家看一看,尤其是人家说了,比如说我的测试结果啊,我的问题,什么东西啊?其实我是特别喜欢看这个的,这个我不知道大家你们有没有这个强迫症,我 一般 ic 我 会过一遍的啊,你们想过一遍可以的。好了,这就给大家说了一下,就是啊,咱们基本的一个逻辑吧,然后配环境还怎么去配? 如果你想要系统化学习恋爱课程,零基础,没有方向,很迷茫,缺乏学习规划,导师放养,无法将专业与恋爱融合,想进入恋爱领域,没有内推渠道,想转行恋爱,但是不知道如何转型?有以上问题可以后台留言。

这是我用 gemino 三十分钟做好的三 d 魔法特效工具,是不是还蛮炫酷的?那么如果我想要把它部署到手机或者分享给朋友的话,我应该怎么做?今天一条视频教会你怎么把 gemino 生成的工具 部署到自己的手机上。第一步,先打开 gmail 写好的代码,点击分享这里选择复制。第二步, microsoft get 号上面打开个人主页,选择这个选项,然后选择新征,为你的工具起个名字,比如说万达,再选择新征 codebase, 然后点击这里新建代码, 等整个 git 代码这里缓存一下之后,我们就可以点击新增文件,把文件命名为 index html, 这个非常重要,要不然后面非常容易出差错。然后我们就可以把代码全部丢进去保存好。 这个时候如果你还想分享给你的朋友的话,我们需要第二个工具叫 word, 点击 add new, 选择 project, 然后添加你刚刚的 git 账户,选择我们刚刚起的旺达工具,什么都不用改,保持默认,直接点击 deploy 就 好。 然后就可以在主页看到你的工具了。兜妹,这里就是你可以分享给朋友的链接,比如说我更换的手机,输入网址工具,又能直接识别使用,然后又可以像电脑端一样去正常的使用这个特效了,虽然说就是在手机上,可能确实没有电脑上的那么 那么美观,那么完善。如果想添加到手机本地,可以点击箭头这里去选择添加到主页里面,然后你就可以在手机里面找到一个类似 app 图标的东西啦,打开即用。你也可以把网址直接发给你的朋友,让你的朋友轻松使用你的 gmail 工具。

很多同学都听说过从 github 上拉代码,却不知道这是什么,又如何操作?其实拉代码的意思就是在 github 上刻录项目,把上面的项目刻录在本地,在本地运行或者修改。接下来会教大家最简单的操作。首先打开你的编辑器, 我这里使用的是 vs code, 点击 ctrl shift 加 p, 在 搜索栏里面搜索 get, 点击 get 克隆,这里需要输入目标仓库的 url, 回到原仓库, 点击 code h t t p s 下面这个就是这个仓库的 url。 但是克隆原仓库的话会有中断的风险,所以我们可以先构到自己的仓库,直接点击 create。 好,现在已经复古到我们自己的仓库里面了,这是我自己的用户名,这是仓库的名字。现在点击 code, 直接复制 url, 回到 vs code 粘贴回车。现在需要新建一个文件夹,这里我直接选择一个, 直接打开就行。好,现在已经成功从 get up 上克隆下来了一个项目,我们可以在本地看到它。

谁说 ai 写代码只能从零到一,不能从一到 n? 修 bug、 重构或者优化的这个轻量级的规范驱动编程项目, openstack 就是 为了 ai 维护长期项目而生的。收获了十二 k star vision ai 团队啊!在真实项目中实践 openstack 后发现,只要规范清晰, ai 的 稳定性是会有质变的。 它不是让 ai 写得更嗨、更氛围,而是解决了一个常见的问题,为什么一旦项目需求变多或变更, ai 就 开始跑偏、忘上下文或反复返工了? openstack 给出了答案, 不是 ai 不 行,是你没有给他一套长期记忆和可追踪的规范。对比起 spacky 和 bmat, 它还是一个非常清亮的规范驱动工具,更适合项目的修改、完善和重构。 那 openstack 是 怎么做到的呢?它有两个核心的设计,一个是规范先行,在写代码之前需要先写清楚规范文档。 第二个核心的设计就是以变更为中心,每一个需求修复和重构都是一个独立的 change。 所以 第一步先提交 change 的 提案,第二步就会平审核对其他给的实现方案不同意让他修改,同意,我们就开始实现代码最终规档和更新规范文档。 所以每个 change 就是 一个完整的生命周期。提出拆解、修改规范、实现和规党。 openstack 啊实际在做的事情就是把对话里的模糊想法固化成 ai 可持续理解的工程事实,并且记录每一次的更改来维护项目。 这一步正是分为编程一直缺失的。如何使用 openstack 呢?我们只要跟着它认真的执行步骤就可以了。这里以我的旧项目悬浮时钟来做演示。第一步我们先检查一下 node js 的 版本是不是大于二十, 按照这个命令来查看一下。检查完之后我们就可以全局安装这个 c i 的 工具,装完可以查看一下 openstack, 有 版本号,说明安装成功了。 接下来我们出场 openstack, 它会配饰我们的工具,我们点回车就可以了。 然后它需要我们去选一下 ide, 市面上常见的 ide 它都支持,这里我选择 ctrl, 进入到项目就可以看到当前的目录下,它生成了适配 ctrl 的 命令行文件, 还有它核心的规范文档。接着我们用 opensback proposal 的 命令来启发我们的需求更改。这里我想对旧版本的 ui 界面进行一下重构, 那修改成用 fig 码画出的比较好看的界面,我们把这张图先上传上去,然后输入需求变更是修改 ui 的 界面,它就开始工作了。改完之后呢,它会在 change 目录下生成一个新的文件夹, 这个文件夹就对应了我们的变更需求,里面有变更提案,设计文档,还有实现的工作分解,还有一些规范文档,那么简单的查一下,如果没有问题就继续执行。下一步我们用 openstack 的 prime, 后面跟着变更了的名称。 变更完成之后出现了一些小 bug, 我 让它修复一下,发现它是数字没有对齐,还有 u y 的 宽度不太对。我给大家说了几次 bug 修复之后,它也会把那个 bug 记录下来,记录到 bug fix 无穷 e q 这个文档里面, 这样它的修改就变得更加可追溯。修改完成之后,我们打开 a x 一 就到了最后一步归档, 我们调用这个 ark 命令,将这个变更进行归档,后面就可以通过命令行去查看的。他会在 ark 目录夹下生成了一个带时间戳的归档文件,里面呢,就包含了我们刚刚需求的一些变更文档。 到这里啊,整个 opensback 的 流程就走完了。回顾一下,其实就是执行了几个命令,加上你的需求,按照命令初步化变更实施 再归档。整体流程还是相对比较清量级的,但它比直接跟科室说方案会繁琐一些,但这样它会有文档,追溯性更好, 长期维护会更有力。很多人会问了, openstack 和 speckey 和 bmat 有 什么区别呢?之前我也出过另外两个工具的视频,可以去我的主页查找。 总体来说,从关注点上, bmat 它是更倾向于项目的整体交付,而 speckey 是 规范生成, openstack 就是 进行项目的长期引进和维护。这何阶段呢? bmat 和 speckey 都偏向于从零到一,而 openstack 是 从一到 n, 而 ai 的 稳定来源呢? b max 是 集中在决策的分工, stack 是 集中在了结构化的文档, openstack 是 结合了规范还有变更历史,大家有兴趣的都可以去讨好体验一下。项目地址我放在了评论区,关注我,带你了解更多有用的 ai 工具。

在这期视频中,我想打破一个错觉,我们将探讨解释型代码运行时实际发生的情况。为什么解释器本质上也是普通的翻译程序,以及这如何使得多语言项目不仅成为可能, 甚至不可避免。我第一次遇到一个将翻译型语言与解释型语言混合来构建单一程序的项目时,心中只有一个疑问,这到底是怎么运作的呢?今天我们就来解答这个问题。大家好,我是 george, 这里是 core dumped。 我 们先快速回顾一下。我们通常认为编程器是一个程序,它接收源代码,将其转换为计算机能理解的指令,并生成一个可执行文件。 但编辑器实际上是以更加模块化的方式设计的,它并非一个单一的黑盒,而是将工作拆分到多个阶段。例如 gaynu 编辑器套件。在编 c 代码时有四个阶段 域,处理器负责移除注视、解析包含指令并展开红。 翻译器将预处理后的 c 代码翻译成绘编代码文件。绘编器将这些绘编文件转换为充满机器指令的目标文件 以及链接器。它接收所有这些目标文件和库,并将它们合并成最终的可执行文件。 由于这种模块化设计,我们无需将所有内容都用同一种语言编辑。例如,我们可以用 c 语言编辑项目的大部分内容,用会编语言编辑少数性能关键的部分,然后在适当的阶段将这些文件传入编辑器流水线。 这种模块化设计意味着工具链的每个阶段都可以接受来自完全不同来源的输入,只要输出格式符合下一阶段的预期, 因此我们可以完全混合使用不同语言,比如 c 和 rust。 我 们可以翻译 rust 部分,并让 rust 翻译器生成一个库,目标文件或静态库,而不是独立的可执行文件。 然后该库可以直接传递给 c 工具链的链接器阶段。最终,我们得到一个由多种翻译语言构建的单一可执行文件。 这里的问题是解释型语言如何适应一个期望目标文件和可链接二进制文件的流程。要回答这个问题,我们需要理解运行解释型语言项目与翻译型语言项目是实际发生的情况。 对于翻译型语言,你需要明确运行翻译器来生成可执行文件,然后运行该可执行文件。而对于解释型语言,通常只需执行一个步骤,你调用解释器并将你的源代码文件作为参数传递项目就直接运行了。 我们今天的第一目标是理解当我们调用解释器时到底发生了什么。让我们先回到翻译型程序。 当你在终端输入一个翻译型程序的名字并按下回车时,你是在请求内核运行一个具有该名称的文件。内核在磁盘上找到它,将其内容加载到内存中,并且因为该文件包含机器指令, cpu 就 可以开始取址解码并执行它们。 内核还会分配该进程可能需要的额外内存,比如占堆等等。在那一刻,我们的翻译型程序就变成了一个进程,这在解释型语言中不可能发生,因为你的代码从未被翻译成机器指令, 因为 python 脚本只是文本,我们不能把它加载到内存中,指望 cpu 去运行它。当然不行, cpu 只懂机器码,不懂 python 代码。 所以当你运行这样的命令时,你实际上并不是在运行你的 python 脚本,而是在运行一个名为 python 的 可执行文件,它位于系统存储的某个位置,操作系统将该可执行文件加载到内存中,开始执行它。 现在我们刚刚创建的进程是 python 解释器,而不是你的 python 脚本。一旦解释器开始运行,它会接受你的脚本文件名作为参数,打开文件并读取其内容,将其作为数据加载到自己的内存空间,通常是堆中。 请注意,你的脚本永远不会成为一个独立的进程。用解释型语言编写的代码本意不是成为自己的进程,它会变成数据,由另一个进程读取,分析并代表你执行的数据。 py 文件对于 python 解释器来说,就像 xlsx 文件,对于 microsoft excel 或者 mp 四文件,对于 vlc 一 样,这些文件不会自己运行它们被另一个知道如何处理它们的程序所使用。 解释器可执行文件中的机器码,指示 cpu 读取你的脚本,通过几个内部步骤将其分解,最终转换成代表你程序的数据结构。 翻译器和解释器都会执行这个解析步骤,区别在于它们之后的操作。翻译器或许这种结构化表示,并将其翻译成稍后执行的机器指令, 而解释器则立即使用 c, p u 来执行该结构所表示的操作。 如果你想知道如何实现,嗯,就是通过这样的代码。例如,如果表达式像这里展示的那样,以数形结构表示,解释器会先获取运算左右两边的值,匹配运算符符号,执行相应操作,然后返回结果。 当然,表达式可以是嵌套的,一个值可以与另一个表达式进行计算。因此,解释器会使用低规调用来先计算内部表达式,然后再将结果用于外部表达式。这就是解释的含义。 分析输入的代码,并根据我们在代码中发现的内容来决定执行什么操作。如果解释器看到一个加号,它就执行加法计算。如果它看到一个减号,它就执行减法计算。 如果他看到一个新号,他就执行乘法运算,以此类推。用非常简单的话来说,编辑解释器就是编辑能够运行其他代码的代码。现在这可能是整个视频中最重要的部分。 解释器本身并没有什么神奇之处,他只是你硬盘上的另一个可执行文件,这意味着他曾经是从原代码翻译而来的。 所有解析脚本、求值表达式、处理变量类类型以及该语言其他所有功能的代码都是用另一种语言,一种翻译型语言编写的。例如官方的 python 解释器就是用 c 语言编写的。 流行的 javascript 运行时, node js 是 用 c 加加编写的。所以当你运行 node main js 时, 你并不是在创建一个 javascript 进程,你是在启动一个 c 加加进程,该进程读取你的 javascript 代码并解释它。当你运行 python main python 时,你并不是在创建一个 python 进程,你是在运行一个 c 程序,该程序读取你的 python 脚本并解释它。如果你还没明白这说明了什么,那么我想说的是, 从非常现实的意义上讲,每个解释型语言项目都已经是一个多语言项目了。我们只是没注意到翻译部分,因为它已经预翻译成了可执行文件。 说到多语言项目,你有没有注意到,越来越多的公司正在将 rust 纳入其关键系统的开发中? 这不是炒作,而是正在发生的事实。既然解释器只是用另一种语言编辑的程序,那么就没有什么能阻止我们扩展它。我们可以直接获取解释器的原代码,并用解释器本身所用的语言编辑额外代码来添加更多功能。 为了让这个想法更清晰,我们来看一个例子。假设我们正在使用 rust 来实现一个类似 python 语言的解释器,而 当创建 python 变量时,解释器应如何处理它们?以这行代码为例,翻译器会直接发出机器指令来加载操作数,执行加法计算,并将结果存储在特定的内存位置。 但在解释型语言中,我们如何表示变量呢?我们如何存储它们的值,以及当变量被使用时,我们如何稍后解锁这些值。 就像编程中的所有事情一样,有无数种方法,但一个简单的方法是定义一个类型用来表示变量可以存储的可能值。变量可以是数字字母串不尔值,而在真实的解释器中,它还可以表示数组、对象类等等。 但为了简单起见,我们只关注这三种类型。现在,当解释器接收到这样一行代码时,他首先会将其解析成一棵树。在执行过程中,解释器快计算表达式,就像我们之前解释的那样,一旦得到结果,他就会创建一个我们定义的类型的新势力。 但现在,解释器必须记住这个变量意背将来使用,为此,它会预先创建一个集合。在这里我使用的是哈希表。一旦变量被创建,解释器就会以变量名为键,将其值存储在哈希表中。 每次定义一个新变量时,解释器都会构建一个新值,并将其插入到这个哈希表中。之后,如果脚本再次使用这些变量中的任何一个解释器,只需在映射中查找它,解锁其值,并在任何需要它的表达式或语句中使用。 此时,你可能在想,为什么我要谈论这些具体的实现细节,尽管这不是一个关于构建解释器的视频。解释器使用这样的结构和集合来表示和存储语言中的所有内容,不仅仅是变量,还包括函数,对象等等。 没有根本性的理由阻止我们添加更多访问这些相同内部结构的翻译代码。 例如,如果解释器通过将变量存储在列表或哈希表中来跟踪它们,我们可以编辑额外的翻译代码来暴露该集合,甚至使用解释器已经依赖的相同结构向其中插入新值。 这意味着我们可以用翻译语言编写性能关键的程序,访问解释语言中定义的值,从结构中提取该值,用它来计算一个新值。将结果包装在解释器用来表示值的结构中,然后将其插入解释器的表格里。 一旦完成这一步,解释语言就能看到并使用这个变量,就好像它是自己生成的一样, 而且这不仅适用于变量,也适用于函数。因为解释器同样使用结构来表示它们, 这就给了我们答案。给定两种语言,编一语言 a 和解释语言 b。 将它们混合在同一个项目中是可行的,因为所有用 a 语言编写的用于解释 b 语言的机制 都可以从 a 语言中访问。这使得我们可以编写额外的翻译代码来创建值注册函数,或者直接与解释器的数据结构进行交互。 换句话说,你不是将解释型语言与翻译型语言混合使用,而是将翻译型语言与解释器相结合,这样两种语言就能在同一个程序中协同工作。 话虽如此,让我来展示一个实际的例子。这里我有一段小型解释器的原代码,它针对我为这个视频专门设计的一个微型编程语言。它并不复杂, 你可以声明、辨亮,计算表达式编辑条件,语句创建简单循环。它甚至还有一个 sleep 关键字可以在执行下一行代码前暂停。非常基础,但对于我们的目的来说已经足够了。 我打算将这个解释器嵌入到一个更大的项目中。因此,与其让它作为独立程序运行,不如将它用作一个库,供我的翻译代码调用。 我的主程序很简单,如果我翻译并运行它,它所做的只是打开一个固定大小的窗口,设置背景颜色,这里是蓝色,并在特定位置绘制一个矩形,这在每一帧都会发生。 现在问题来了,如果我想改变背景颜色或举行的位置,就必须编辑原代码,重新编一整个程序,然后再次运行才能看到变化。 所以挑战在于,我希望这些参数能在我的解释型语言中定义,而不是在翻译型语言中。如果我将解释器的原代码视为一个库,我应该能够读取解释脚本中声明的变量值。这意味着我不必每次想修改什么时都重新编一项目。 要做到这一点,我只需要看看解释器是如何存储变量的。好消息是,它用一个哈希表来记住它们使用变量名作为键。就像我之前展示的例子一样, 既然解释器是用与我程序其他部分相同的语言实现的,那么我没有理由不能从主代码中访问那个哈希表。所以我打算添加一点额外功能,让我的解释器能够暴露它在解释代码时使用的内部数据。 在我的主函数中,我会启动解释器,并让它加载我的脚本文件。然后我让解释器在一个单独的线程上运行脚本,这样它就不会阻测我的主线程。 主线程正忙于会置窗口,剩下的部分其实很简单,我不会硬编码背景颜色,而是会从解释器的变量表中读取 r, g 和 b 的 值,而是会读取解释器的变量 x 和 y。 而且我还要更进一步, 在处理窗口大小调整的代码部分,我会更新显示器哈希表中的两个变量, width 和 height。 这样一来,即使翻译后的代码负责管理窗口,如果解释脚本需要知道当前窗口大小,解释端也能获取到这些信息。 重新编辑并运行项目后,方块正好出现在我的解释代码指定的位置。 现在我的最终可执行文件中包含一个嵌入式解释器。这带来了两个重要的影响。首先,这意味着理解这种解释型语言所需的所有代码都打包在可执行文件内部。 正因如此,我可以关闭程序,修改解释脚本,然后重新运行程序来查看更改,而无需重新翻译任何内容。 乍一听,这似乎并不特别令人印象深刻。很多人可能会想,为什么不直接把参数放在一个 json 文件里读取文件,然后得到同样的结果呢?嗯, 这就引出了第二个影响。因为我用做配置文件的那个文件,其内容实际上是一种编程语言,所以我不局限于仅仅声明变量, 我可以编写实际的代码来动态的随时间更新这些变量。这意味着我可以放开手脚写出像这样的东西。所以当我再次运行程序时,无需重新编辑,就得到了这个结果。 最酷的部分是,如果我调整窗口大小,解释型代码不会崩溃,因为我的编辑型代码会在窗口每次改变大小时持续更新。解释器中代表宽度和高度的变量。 这里是我仅仅通过修改解释型脚本而制作的另一个例子。现在,背景颜色会根据举行相对于窗口中心的位置而改变。 就这样,我们得到了一个多语言项目编,一部分负责处理繁重的工作,比如渲染窗口,而解释部分则控制窗口内部发生的事情。 如果这个例子让你恍然大悟,那是因为这正是向游戏引擎这类实际软件背后的核心理念。 想想 go do 那 些对性能要求极高的部分,比如图形渲染、物理模拟、音频处理,都是用 c 加加这种翻译型语言编写的, 但引擎内部嵌入了一个解释器,这样游戏开发者就可以用一种很酷的解释型语言 go do 脚本来编写代码,控制诸如玩家位置、重力强度、敌人行为,以及基本上所有的游戏逻辑,这一切都无需重新编引引擎。 如果你用过 neo vim, 你 可能会好奇它是如何让你用 luaw 脚本来配置一切的。这之所以可行,是因为 neo vim 内部嵌入了一个 luaw 解释器,所以编写一个 luaw 配置文件或插件,就像是在给这个嵌入的解释器下达指令,从而改变编辑器的外观和行为。 这就是为什么 neovim 可以 根据你的配置看起来像是一个完全不同的程序。虽然从翻译型语言调用解释型代码需要嵌入解释器,但反过来,从解释型语言调用翻译型代码并不是通过嵌入翻译器来实现的。 翻译器是翻译代码的,它不运行代码,所以在这种情境下嵌入翻译器没有意义。 相反,从解释型项目调用翻译型代码通常是通过一种叫做外部函数接口的技术来实现的。这简单来说就是你在翻译型语言中声明函数,而解释型语言能够像调用原声函数一样调用它们。 说到这里,你已经知道这背后的概念机制了,因为我在整个视频中已经隐含的解释过了,但这里有一个明确的版本给那些喜欢坚持看到最后的朋友们。 就像解释器使用专门的结构来表示变量一样,函数也有其自己的结构来表示。 每个函数都会被解析成这样的结构,然后添加到一个集合中。再说一次,我们没有理由不能从编语言中手动创建这样一个函数结构,并直接插入到解释器的函数列表中。 一旦它进入列表,解释脚本就可以调用这个函数,即使它实际上是用编语言实现的。 注意一个重要的事情,函数结构包含一个自断,用于存储一个可调用对象。这个对象接收一个值结构列表,并返回一个新的值结构。为什么?因为这就是在脚本语言中调用函数的含义,你给它参数,它返回一个值。 通常,这个存储的可调用对象指向解释器中评估函数体的代码。但如果我们在解释器外部手动创建函数结构,我们可以将这个字段分配给我们自己的翻译函数。 只要我们的翻译函数接收解释器的值结构列表,并以解释器的格式返回一个值结构,解释器就完全不会抱怨 解释脚本会像运行任何其他函数一样运行它。这正是 python 用来调用 c 函数的相同机制。这不是随便一个 c 函数,它是一个接收 python 内部值结构并返回 python 值结构的 c 函数。 最后,请注意,我在本视频中描述的一切都涉及向解释器添加额外代码以暴露其内部结构,并允许它与外部翻译代码交互。 但这带来了一个问题,如果解释器是域翻译的,我们就无法修改它。我们需要原代码打上额外功能的补丁,然后重新编一整个程序。 幸运的是,现代解释器的设计者知道这一点。他们通过公共 api 特意暴露解释器的部分内部机制,让外部代码无需修改,解释器本身就能集成进来。 唯一的要求就是我们的代码要符合该 api 所施加的约束条件。这意味着你下载的解释器已经包含了与翻译代码交互所需的一切。所以,当我们想让 python 与 c 语言交互时,我们不需要重新翻译 python, 我 们只需将 c 代码翻译成动态库。 当我们运行 python 脚本时,解释器会加载到内存中,并成为一个进程。就像我们之前讨论的那样,当脚本调用 c 函数时,解释器只需请求操作系统加载动态库,这样它就能访问那些翻译好的函数了。 这就是 python 如何能够运行 c 代码的简化解释。这种方法在实际应用中非常普遍,尤其是在数据科学和机器学习领域。 python 依赖高性能原生代码来克服解释型语言固有的局限性。 在结束之前,我想提一下还有另外两种混合解释型语言和翻译型语言的方法。 一种方法是使用转移器,你将代码从解释型语言翻译成翻译型语言,然后像单一语言一样将所有内容一起翻译。这种方法不太常见,但确实存在。 另一种方法是使用独立的模块,在运行时通过进城间通信,如套接字或管道进行通信。这其实并不是真正混合语言,它们只是相互通信的独立程序,但从技术上讲是可行的。 如果您喜欢这个视频或学到了新知识,请点击点赞按钮,我们下期视频再见!