style: html to md syntax

This commit is contained in:
Plumbiu
2023-08-24 10:31:27 +08:00
parent 229e847514
commit 0a96f3658b
88 changed files with 459 additions and 459 deletions

View File

@@ -4,20 +4,20 @@
大学的真意是综合而全面的培养一个人。为什么大学有这样的职责?因为这是人最后的受教育阶段(研究生、博士生也是在大学里接受教育)。从接受教育开始到走向社会为止,这期间是人,变成一个人最为宝贵的阶段。 大学的真意是综合而全面的培养一个人。为什么大学有这样的职责?因为这是人最后的受教育阶段(研究生、博士生也是在大学里接受教育)。从接受教育开始到走向社会为止,这期间是人,变成一个人最为宝贵的阶段。
<strong>大学是唯一可以与来自五湖四海、不同学科背景的人共处一个校园的时期,这里就应该是开放而需要激烈思想碰撞的地方</strong>。大学是专业的,但同时更是广博的,我们在黄金的年龄来到这里,就不要轻易的错过这样疯狂吸纳不同看法的机会。同样,大学是未来所有可能性的孵化器,请保持一颗尝试新事物的心,索取大学所能给予的任何一切,并让它成为提升自我的工具。 **大学是唯一可以与来自五湖四海、不同学科背景的人共处一个校园的时期,这里就应该是开放而需要激烈思想碰撞的地方**。大学是专业的,但同时更是广博的,我们在黄金的年龄来到这里,就不要轻易的错过这样疯狂吸纳不同看法的机会。同样,大学是未来所有可能性的孵化器,请保持一颗尝试新事物的心,索取大学所能给予的任何一切,并让它成为提升自我的工具。
工具,我并不避讳这个词。只不过我并不想将这个词与人画等号。人非工具,而是使用工具的。我们的祖先经过数百万年的努力和尝试,才学会使用并创造工具,目的就是不再沦为工具,我们站在 21 世纪也不应该心甘情愿的将自己锻造成一个工具,这是返祖与退化的表现。 工具,我并不避讳这个词。只不过我并不想将这个词与人画等号。人非工具,而是使用工具的。我们的祖先经过数百万年的努力和尝试,才学会使用并创造工具,目的就是不再沦为工具,我们站在 21 世纪也不应该心甘情愿的将自己锻造成一个工具,这是返祖与退化的表现。
21 世纪是人类对高科技和超级想象力、创造力最渴求的百年。一个想法和主意胜过千万个重复的机械化劳动,虽然后者也能带来一定程度的好处,但这并不我们的目标。大学是否能迸发出惊人的创造力,在于学生和教师的思想与行为。而不同的学科交叉和碰撞会让创造力和科技的创新更大概率出现。 21 世纪是人类对高科技和超级想象力、创造力最渴求的百年。一个想法和主意胜过千万个重复的机械化劳动,虽然后者也能带来一定程度的好处,但这并不我们的目标。大学是否能迸发出惊人的创造力,在于学生和教师的思想与行为。而不同的学科交叉和碰撞会让创造力和科技的创新更大概率出现。
听说乔布斯有对禅宗修习的经历,而他的工作可能并不与禅宗搭边。但他的成功却不能不说与他广泛的涉猎有关。工具是没有办法创造工具的,只有人才能创造。<strong>我们大学生应该去思考在大学四年如何想办法把自己锻造成真正的人。</strong> 听说乔布斯有对禅宗修习的经历,而他的工作可能并不与禅宗搭边。但他的成功却不能不说与他广泛的涉猎有关。工具是没有办法创造工具的,只有人才能创造。**我们大学生应该去思考在大学四年如何想办法把自己锻造成真正的人。**
这个人不是做题的机器,不是刷题的工具,不是眼中只有考高分的单一生物,当然更不可能是成天浑浑噩噩、行尸走肉的颓丧者、躺平者。说到这里,可能会讲,难道不躺平去卷吗?并不是,我反对 “卷”,<strong>因为 “卷” 的含义是无意义的恶性竞争和没有实际突破的简单重复劳动,边际效益递减的不划算却无奈的选择。</strong>“卷” 不等于 “勤奋” 、 “创造” 和 “想要变得更强” ,将之画等号我认为是当前观念中一个很大的误区。<strong>我们需要大学生有自己的思考和创造力,需要大学生是一个综合全面发展的人。</strong>只有这样大学才有活力、希望,社会才有动力,国家才有未来。 这个人不是做题的机器,不是刷题的工具,不是眼中只有考高分的单一生物,当然更不可能是成天浑浑噩噩、行尸走肉的颓丧者、躺平者。说到这里,可能会讲,难道不躺平去卷吗?并不是,我反对 “卷”,**因为 “卷” 的含义是无意义的恶性竞争和没有实际突破的简单重复劳动,边际效益递减的不划算却无奈的选择。**“卷” 不等于 “勤奋” 、 “创造” 和 “想要变得更强” ,将之画等号我认为是当前观念中一个很大的误区。**我们需要大学生有自己的思考和创造力,需要大学生是一个综合全面发展的人。**只有这样大学才有活力、希望,社会才有动力,国家才有未来。
我知道大学可能并不如你们想象的那般美好,有不负责的、划水上课的老师以及你看不惯的、瞧不起的种种行为,但这并不是自己选择放弃和抱怨的理由。因为,我相信大学还有认真负责的老师、有思想的学者以及有想法的同学,我们需要和自己钦佩、三观相符的人多接触,让自己成为你佩服的人的样子,而非因为种种不好的现象而选择全盘的否定、甚至自暴自弃。 我知道大学可能并不如你们想象的那般美好,有不负责的、划水上课的老师以及你看不惯的、瞧不起的种种行为,但这并不是自己选择放弃和抱怨的理由。因为,我相信大学还有认真负责的老师、有思想的学者以及有想法的同学,我们需要和自己钦佩、三观相符的人多接触,让自己成为你佩服的人的样子,而非因为种种不好的现象而选择全盘的否定、甚至自暴自弃。
<strong> 要有自己的目标,年轻是实现自己目标最好的资本。</strong>为了这个目标,在大学里徜徉、像海绵一样吸纳如水般的知识和见识。博采众长而非简单功利。可能你今天听了不重要的课(相对于专业课),但只要是值得听的老师讲的有涵养的课,你就不算枉费时光。因为这样的经历并不会让你浪费时间,而会在未来的某刻显示出它的价值。 ** 要有自己的目标,年轻是实现自己目标最好的资本。**为了这个目标,在大学里徜徉、像海绵一样吸纳如水般的知识和见识。博采众长而非简单功利。可能你今天听了不重要的课(相对于专业课),但只要是值得听的老师讲的有涵养的课,你就不算枉费时光。因为这样的经历并不会让你浪费时间,而会在未来的某刻显示出它的价值。
不要让自己的大脑空空,刷抖音、看游戏直播或者看无聊的视频或许是娱乐的方式,但这些是你可以在余生每天都可做的最没有技术含量的事,而且这些并不会让你大脑填入真正有价值的东西。<strong>去做只有大学时光才能做的事吧!</strong>丰富自己、创造自己、提升自己。多看一页经典的著作,这是人类上百年乃至上千年思想的精华。多认真的听一节有价值的课吧,这是老师积几十年的学识认真准备的盛宴。 不要让自己的大脑空空,刷抖音、看游戏直播或者看无聊的视频或许是娱乐的方式,但这些是你可以在余生每天都可做的最没有技术含量的事,而且这些并不会让你大脑填入真正有价值的东西。**去做只有大学时光才能做的事吧!**丰富自己、创造自己、提升自己。多看一页经典的著作,这是人类上百年乃至上千年思想的精华。多认真的听一节有价值的课吧,这是老师积几十年的学识认真准备的盛宴。
可能你会说,大学没有好的课程,老师都在划水。如果你有这样的看法,我想说,可能是你了解的太少所致,多去了解一下一定有让你满意的老师。另外,为什么大学会出现这样不好的课程呢?因为老师不愿意好好上课。为什么老师不愿意好好教学呢?因为在功利化的指挥棒下,好好上课是性价比最低的行为。如此,你就知道大学只知道功利化、工具化的接受教育,而不培养人文素养的恶果了吧! 可能你会说,大学没有好的课程,老师都在划水。如果你有这样的看法,我想说,可能是你了解的太少所致,多去了解一下一定有让你满意的老师。另外,为什么大学会出现这样不好的课程呢?因为老师不愿意好好上课。为什么老师不愿意好好教学呢?因为在功利化的指挥棒下,好好上课是性价比最低的行为。如此,你就知道大学只知道功利化、工具化的接受教育,而不培养人文素养的恶果了吧!

View File

@@ -43,7 +43,7 @@
好处是本身就是落地项目,在论证项目可行性时具有很强的说服力,这类项目也相对来说会容易获奖。对于想要做实际落地项目的技术人员来说是不错的锻炼机会。 好处是本身就是落地项目,在论证项目可行性时具有很强的说服力,这类项目也相对来说会容易获奖。对于想要做实际落地项目的技术人员来说是不错的锻炼机会。
坏处是甲方<strong>可能</strong>提出大量需求,技术人员需付出大量精力跟进,然而因为项目本身参与比赛而无法收取原定的外包费用,技术人员成为白菜大学生被白嫖(当然这个潜在可能性带来的坏处也因人而异,如果不在乎频繁改动需求 / 愿意做没有外包费用的无偿奉献,只想锻炼自己,那就无所谓)。 坏处是甲方**可能**提出大量需求,技术人员需付出大量精力跟进,然而因为项目本身参与比赛而无法收取原定的外包费用,技术人员成为白菜大学生被白嫖(当然这个潜在可能性带来的坏处也因人而异,如果不在乎频繁改动需求 / 愿意做没有外包费用的无偿奉献,只想锻炼自己,那就无所谓)。
- 自立初创项目 - 自立初创项目

View File

@@ -10,11 +10,11 @@ GPA一个酷似成绩的东西
毕竟在高中,一份理想的成绩意味着一个光明的未来。 毕竟在高中,一份理想的成绩意味着一个光明的未来。
但是我想说,<strong>在大学,请摆脱高中的绩点惯性</strong> 但是我想说,**在大学,请摆脱高中的绩点惯性**
在大学,绩点其实只是一个获得资源的工具,高的绩点并不代表光明的未来,也不能够代表高超的学习能力和扎实的专业知识。同时我们要明白,与高中截然不同的是,大学是一个多目标优化问题,绩点只是优化问题的一个维度,而非所有。 在大学,绩点其实只是一个获得资源的工具,高的绩点并不代表光明的未来,也不能够代表高超的学习能力和扎实的专业知识。同时我们要明白,与高中截然不同的是,大学是一个多目标优化问题,绩点只是优化问题的一个维度,而非所有。
> <strong>author晓宇</strong> > **author晓宇**
所以本文会讲述 GPA 能够带来什么,什么是一个合理的对待 GPA 的态度,如果需要,如何获得一个较高的 GPA 。 所以本文会讲述 GPA 能够带来什么,什么是一个合理的对待 GPA 的态度,如果需要,如何获得一个较高的 GPA 。
@@ -90,7 +90,7 @@ B. 大一进来从来不太在意 GPA大部分经历在研究 Github 项目
当你已经成为大学生的时候GPA成绩不是和一个人的优秀的呈正相关的这不过是一个通往一些资源的途径同样的也有很多资源可以不用 GPA可以靠个人硬实力去争取例如实习例如科研助理云云。只是说如果你不知道干啥先认真学好专业课知识是一个保有收益的事情但当有其他选择的时候可以权衡但也不可走另外一个极端则完全不在乎 GPA在职业规划并不清晰的时候不要自废道路。 当你已经成为大学生的时候GPA成绩不是和一个人的优秀的呈正相关的这不过是一个通往一些资源的途径同样的也有很多资源可以不用 GPA可以靠个人硬实力去争取例如实习例如科研助理云云。只是说如果你不知道干啥先认真学好专业课知识是一个保有收益的事情但当有其他选择的时候可以权衡但也不可走另外一个极端则完全不在乎 GPA在职业规划并不清晰的时候不要自废道路。
最后想说的是,一个获得资源的玩具罢了,不值得让你<strong>常沉苦海,永失真道</strong> 最后想说的是,一个获得资源的玩具罢了,不值得让你**常沉苦海,永失真道**
## GPA 补充内容: ## GPA 补充内容:

View File

@@ -4,11 +4,11 @@
相信转专业的人里,不少是慕 HDU 的强势理工科热门专业来的。但是在转专业之前,你需要先确认以下几点。 相信转专业的人里,不少是慕 HDU 的强势理工科热门专业来的。但是在转专业之前,你需要先确认以下几点。
1. 你是<strong>跟风</strong>听你家七大姑八大姨说这个专业好,才想转来这个专业的吗? 1. 你是**跟风**听你家七大姑八大姨说这个专业好,才想转来这个专业的吗?
2. 你确定你<strong>所向往的</strong>和这个专业所学的<strong>相关</strong>吗?有没有比这个专业更贴切的选择? 2. 你确定你**所向往的**和这个专业所学的**相关**吗?有没有比这个专业更贴切的选择?
3. 你确定你能良好适应(<strong>至少不反感</strong>)这个专业所学的专业课吗? 3. 你确定你能良好适应(**至少不反感**)这个专业所学的专业课吗?
以上的问题,如果有觉得不确定的,也没关系,你至少有一学期在学校里探索。可以是问该学院的学长学姐的感受,可以是进研究相关专业知识的社团学习,也可以是自己研究。总之,不能转专业转得迷迷糊糊,因为虽然 HDU 转专业机制比较友好,<strong>但转专业机会只有一次</strong>,如果你转进去之后发现自己完全不适应,那也只能自认倒霉。 以上的问题,如果有觉得不确定的,也没关系,你至少有一学期在学校里探索。可以是问该学院的学长学姐的感受,可以是进研究相关专业知识的社团学习,也可以是自己研究。总之,不能转专业转得迷迷糊糊,因为虽然 HDU 转专业机制比较友好,**但转专业机会只有一次**,如果你转进去之后发现自己完全不适应,那也只能自认倒霉。
像笔者本人最初其实想做游戏开发,本身也热爱绘画之类的艺术。当年只觉得游戏开发和计算机有关,一门心思转计算机,后来转成功之后才发现其实数媒的培养计划更贴合笔者想学的,而现在所在的计科学得更多的是计算机理论方面的知识,也跟游戏开发不搭边。 像笔者本人最初其实想做游戏开发,本身也热爱绘画之类的艺术。当年只觉得游戏开发和计算机有关,一门心思转计算机,后来转成功之后才发现其实数媒的培养计划更贴合笔者想学的,而现在所在的计科学得更多的是计算机理论方面的知识,也跟游戏开发不搭边。
@@ -29,16 +29,16 @@
::: :::
转专业填报截止时间一般是在期末考试结束前后,届时<strong>最多填两个</strong>意向专业。 转专业填报截止时间一般是在期末考试结束前后,届时**最多填两个**意向专业。
转专业公示时间一般在开学前后。在转专业结果公示一周内,<strong>可以申请放弃转专业</strong>,此时视作已用过一次转专业机会,<strong>不可再次转专业</strong>。所以如果是非某个专业不去,建议只填报一个意向专业,以防被第二个专业录取,失去转专业资格。 转专业公示时间一般在开学前后。在转专业结果公示一周内,**可以申请放弃转专业**,此时视作已用过一次转专业机会,**不可再次转专业**。所以如果是非某个专业不去,建议只填报一个意向专业,以防被第二个专业录取,失去转专业资格。
## 转专业后的选课 ## 转专业后的选课
在转专业公示结束后,转专业才正式生效。在公示期期间,如果想提前选课,需要走特殊退改选;也可以等转专业生效后再正常选课。 在转专业公示结束后,转专业才正式生效。在公示期期间,如果想提前选课,需要走特殊退改选;也可以等转专业生效后再正常选课。
需要注意的是,<strong>你必须退掉原专业所有的课程</strong>。如果在选课结束后,你仍有未退的原专业课程,你必须含泪又交学费又上课,说不好还要考这个课的试。其中要特别注意原专业的短学期实践课,这个课程比较容易被忽视。 需要注意的是,**你必须退掉原专业所有的课程**。如果在选课结束后,你仍有未退的原专业课程,你必须含泪又交学费又上课,说不好还要考这个课的试。其中要特别注意原专业的短学期实践课,这个课程比较容易被忽视。
在排课时,请找到你转入专业的培养计划,根据培养计划的<strong>课程号</strong>进行选课而不是课程名。HDU 有些课程同名不同号,如果选择了同名不同号的课程,只能寻求课程替代(而且有概率不成功)。这种情况常见于你发现你原来专业的课程和转入专业的某课程名字一样,你懒得换了,殊不知这两个课程完全不是一个课程号,喜变纯纯冤种。 在排课时,请找到你转入专业的培养计划,根据培养计划的**课程号**进行选课而不是课程名。HDU 有些课程同名不同号,如果选择了同名不同号的课程,只能寻求课程替代(而且有概率不成功)。这种情况常见于你发现你原来专业的课程和转入专业的某课程名字一样,你懒得换了,殊不知这两个课程完全不是一个课程号,喜变纯纯冤种。
另外,建议根据开课班级排课。有些课程虽然课程号相同,但可能开给不同学院。比如计算机学院的课程经常和卓越或计算机二专业的一些课程同号,如果你选了其他专业的开课班级的班,期末考试可能会不一样(如计科和卓越的电路与电子学课程号同号,但在 20 级是分开期末考试的)。建议看清开课班级再选课。 另外,建议根据开课班级排课。有些课程虽然课程号相同,但可能开给不同学院。比如计算机学院的课程经常和卓越或计算机二专业的一些课程同号,如果你选了其他专业的开课班级的班,期末考试可能会不一样(如计科和卓越的电路与电子学课程号同号,但在 20 级是分开期末考试的)。建议看清开课班级再选课。

View File

@@ -10,15 +10,15 @@
概括一下:摒弃伸手,被动思维,能够主动争取各种机会,带着一个能够独当一面的能力进入实验室,与老师能够形成合作关系。 概括一下:摒弃伸手,被动思维,能够主动争取各种机会,带着一个能够独当一面的能力进入实验室,与老师能够形成合作关系。
<strong>能力上:</strong>目前计算机上的科研主要在两大方向,第一大方向是 AI关于这件事情是不是畸形要后期在讨论第二大方向是系统数据库 **能力上:**目前计算机上的科研主要在两大方向,第一大方向是 AI关于这件事情是不是畸形要后期在讨论第二大方向是系统数据库
对于数据库与系统,我目前还没有涉及 对于数据库与系统,我目前还没有涉及
<strong>领域的基础能力:</strong>这里要我力推我们的课题教程,有较好的 AI 路线图,尽管 AI 有非常多子方向,如 NLP,CV多模态CV 下面又有检测 语义分割NLP 又有推荐系统等云云,但是无论如何他们的源头都是 MLPMLP 的源头都是多维线性回归,都是基于统计学习理论体系下,都是使用 Pytorch,都要学习数学理论体系,所以是可以要有一套类似的培养体系的。视觉被推荐 cs231n NLP 被推荐 CS224n。 **领域的基础能力:**这里要我力推我们的课题教程,有较好的 AI 路线图,尽管 AI 有非常多子方向,如 NLP,CV多模态CV 下面又有检测 语义分割NLP 又有推荐系统等云云,但是无论如何他们的源头都是 MLPMLP 的源头都是多维线性回归,都是基于统计学习理论体系下,都是使用 Pytorch,都要学习数学理论体系,所以是可以要有一套类似的培养体系的。视觉被推荐 cs231n NLP 被推荐 CS224n。
论文的阅读能力:在了解一个领域的时候,最开始会发现什么词都不懂,一篇文章无论是从语言上还是英文上都无法阅读,所以能否具备快速阅读并读懂一篇文章的能力也是非常重要的。 论文的阅读能力:在了解一个领域的时候,最开始会发现什么词都不懂,一篇文章无论是从语言上还是英文上都无法阅读,所以能否具备快速阅读并读懂一篇文章的能力也是非常重要的。
<strong>如何寻找老师上:</strong> **如何寻找老师上:**
学校内和学校外都可以寻求合作,在学校内, 学校内和学校外都可以寻求合作,在学校内,

View File

@@ -56,7 +56,7 @@ ps:QQ 有长截图的功能,妈妈再也不用担心我不会滚动捕捉了
![](static/01.jpg) ![](static/01.jpg)
<strong>这并不需要一个找到懂得如何解决问题的人 (或者甚至是一个人 —— 这种做法通常被称为橡皮鸭,因为你可以把一只橡皮鸭当作你的练习对象) ,因为主要目标是让你弄清楚你自己的想法,弄清楚你的理解和代码到底在哪里卡住了。这样你可以知道应该专注于哪一部分,以便更好地理解。</strong> **这并不需要一个找到懂得如何解决问题的人 (或者甚至是一个人 —— 这种做法通常被称为橡皮鸭,因为你可以把一只橡皮鸭当作你的练习对象) ,因为主要目标是让你弄清楚你自己的想法,弄清楚你的理解和代码到底在哪里卡住了。这样你可以知道应该专注于哪一部分,以便更好地理解。**
### 欢迎大家阅读 ### 欢迎大家阅读

View File

@@ -13,7 +13,7 @@
### 这篇讲义讲什么 ### 这篇讲义讲什么
- 首先,如上文所述,如何轻松地利用本章乃至整个讲义 - 首先,如上文所述,如何轻松地利用本章乃至整个讲义
- 在第一点的基础上,引申出我自己归纳的<strong>编程入门之“道”</strong> - 在第一点的基础上,引申出我自己归纳的**编程入门之“道”**
### 请随意喷这篇讲义 ### 请随意喷这篇讲义
@@ -28,7 +28,7 @@
1. 这里的文章的最大的作用是帮你打开信息壁垒,告诉你编程的世界有哪些东西,可以去学什么。 1. 这里的文章的最大的作用是帮你打开信息壁垒,告诉你编程的世界有哪些东西,可以去学什么。
2. 把讲义当成字典来用。很多文章并不是完全对新人友好的,你现在不需要看懂,甚至可能不需要看。你只要大概记下有这么个概念和工具,当下次要用到的时候,再查阅、再仔细学习就好。 2. 把讲义当成字典来用。很多文章并不是完全对新人友好的,你现在不需要看懂,甚至可能不需要看。你只要大概记下有这么个概念和工具,当下次要用到的时候,再查阅、再仔细学习就好。
简单来说就是,<strong>抱着平和的心态,随便看看</strong>,知道这一章都讲了哪些东西,看完有个印象就好,然后常回家看看。 简单来说就是,**抱着平和的心态,随便看看**,知道这一章都讲了哪些东西,看完有个印象就好,然后常回家看看。
技术细节本身永远都不是最重要的,重要的是思想和方法,如何快速掌握一门技术。 技术细节本身永远都不是最重要的,重要的是思想和方法,如何快速掌握一门技术。
@@ -38,7 +38,7 @@
这是我的第一个也是最重要的建议。 这是我的第一个也是最重要的建议。
无论是学一门语言,还是学一个工具:<strong>尽可能地先用最短的时间搞懂这个东西是做什么的然后以最快的方式把它“run”起来。</strong> 无论是学一门语言,还是学一个工具:**尽可能地先用最短的时间搞懂这个东西是做什么的然后以最快的方式把它“run”起来。**
当你已经能跑起一个语言、一个工具的最简单的示例的时候,再去花时间慢慢了解背后的复杂的内容,再去拓展即可。先用起来,跑起来,带着问题去翻资料。 当你已经能跑起一个语言、一个工具的最简单的示例的时候,再去花时间慢慢了解背后的复杂的内容,再去拓展即可。先用起来,跑起来,带着问题去翻资料。
@@ -58,7 +58,7 @@
那么该怎么学呢? 那么该怎么学呢?
<strong>先简单地会一样东西的最核心的部分,再去找一个实际的编程场景、编程任务、项目。你会在完成这个项目中遇到各种各样的问题,无论是遗漏了知识点还是压根没思路,这时候不断地用搜索引擎来学习。( </strong>[2.3 高效的信息检索](../2.%E9%AB%98%E6%95%88%E5%AD%A6%E4%B9%A0/2.3%E9%AB%98%E6%95%88%E7%9A%84%E4%BF%A1%E6%81%AF%E6%A3%80%E7%B4%A2.md)<strong></strong> **先简单地会一样东西的最核心的部分,再去找一个实际的编程场景、编程任务、项目。你会在完成这个项目中遇到各种各样的问题,无论是遗漏了知识点还是压根没思路,这时候不断地用搜索引擎来学习。( **[2.3 高效的信息检索](../2.%E9%AB%98%E6%95%88%E5%AD%A6%E4%B9%A0/2.3%E9%AB%98%E6%95%88%E7%9A%84%E4%BF%A1%E6%81%AF%E6%A3%80%E7%B4%A2.md)****
举个例子:你想做一个小程序,来检测某电影院的电影预售。程序大概要做到不断刷新网页,一检测到这个电影预售了,就马上发短信给自己手机(或者直接帮你抢) 举个例子:你想做一个小程序,来检测某电影院的电影预售。程序大概要做到不断刷新网页,一检测到这个电影预售了,就马上发短信给自己手机(或者直接帮你抢)
@@ -85,7 +85,7 @@
刚开始你可能什么都不会,什么地方都被阻塞,但当你把坑踩遍了。就发现,哎嘿,不好意思,这玩意我怎么又会! 刚开始你可能什么都不会,什么地方都被阻塞,但当你把坑踩遍了。就发现,哎嘿,不好意思,这玩意我怎么又会!
<strong>所以让我们基于这个“任务驱动”,再看看本章的内容。这些内容大多看了就忘,因为细节非常多,而且并不一定能解决你手头上的问题。但这些文档,带你领进了新的领域的大门,让你的工具箱里多了一个可以解决问题的工具,以后用到了可以想起他们。并且,这些文章多是通俗的,且作者多是讲述了 ta 所认为的该语言/工具的最核心、最精华的部分,或者说第一次入门最需要学习的部分。</strong> **所以让我们基于这个“任务驱动”,再看看本章的内容。这些内容大多看了就忘,因为细节非常多,而且并不一定能解决你手头上的问题。但这些文档,带你领进了新的领域的大门,让你的工具箱里多了一个可以解决问题的工具,以后用到了可以想起他们。并且,这些文章多是通俗的,且作者多是讲述了 ta 所认为的该语言/工具的最核心、最精华的部分,或者说第一次入门最需要学习的部分。**
## 圈子 ## 圈子

View File

@@ -20,9 +20,9 @@
当然在这里我们主要讲的是代码编辑器,一个好的编辑器可以节省开发时间,提高工作效率,它们都能提供非常方便易用的开发环境。你可以用它们来编写代码,查看源文件和文档等,简化你的工作。以下是一些常用的代码编辑器,每个不同的编辑器都有不尽相同的目标用户群体。 当然在这里我们主要讲的是代码编辑器,一个好的编辑器可以节省开发时间,提高工作效率,它们都能提供非常方便易用的开发环境。你可以用它们来编写代码,查看源文件和文档等,简化你的工作。以下是一些常用的代码编辑器,每个不同的编辑器都有不尽相同的目标用户群体。
- <em>Visual Studio Code</em> : 微软 VS 系列的新作品,适用于多平台的代码编辑器,其很好服从了轻量化 + 拓展的 Unix 思想,在整体快捷方便的同时具有极强的功能拓展空间,是值得首要推荐的编辑器。 - *Visual Studio Code* : 微软 VS 系列的新作品,适用于多平台的代码编辑器,其很好服从了轻量化 + 拓展的 Unix 思想,在整体快捷方便的同时具有极强的功能拓展空间,是值得首要推荐的编辑器。
- <em>Vim </em>: Vim 是从 vi 发展出来的一个文本编辑器,在程序员中被广泛使用,运行在 Linux 环境下。 - *Vim*: Vim 是从 vi 发展出来的一个文本编辑器,在程序员中被广泛使用,运行在 Linux 环境下。
- <em>GNU Emacs</em> : Emacs 是一个轻便、可扩展、免费的编辑器,它比其它的编辑器要更强大,是一个整合环境,或可称它为集成开发环境。它可以处理文字,图像,高亮语法,将代码更直观地展现给开发者。 - *GNU Emacs* : Emacs 是一个轻便、可扩展、免费的编辑器,它比其它的编辑器要更强大,是一个整合环境,或可称它为集成开发环境。它可以处理文字,图像,高亮语法,将代码更直观地展现给开发者。
### 什么是编译器 ### 什么是编译器

View File

@@ -12,7 +12,7 @@ author:wenjing
## ACM 能为我带来什么? ## ACM 能为我带来什么?
显然,做为一名计算机专业的学生,编程是一项必须掌握的技能。再次引用 Niklaus Emil Wirth 的一句话:<strong>程序=算法 + 数据结构。</strong>例如在大一开设的程序设计基础中,我们需要重点学习链表这一数据结构,熟悉运用分支与循环结构(勉强也算算法吧)。然而,在 ACM 中,这是基础到不值一提的事物,宛如空气与水一般基础。你们是否想过,花了大量课时学习的这些知识,其实小学生也可以学会(看看远处的小学编程补习班吧,家人们)那做为大学生去学习这些知识,是否应当得到一些不止于考试内容的知识呢? 显然,做为一名计算机专业的学生,编程是一项必须掌握的技能。再次引用 Niklaus Emil Wirth 的一句话:**程序=算法 + 数据结构。**例如在大一开设的程序设计基础中,我们需要重点学习链表这一数据结构,熟悉运用分支与循环结构(勉强也算算法吧)。然而,在 ACM 中,这是基础到不值一提的事物,宛如空气与水一般基础。你们是否想过,花了大量课时学习的这些知识,其实小学生也可以学会(看看远处的小学编程补习班吧,家人们)那做为大学生去学习这些知识,是否应当得到一些不止于考试内容的知识呢?
我认为有两个方向,一是我们去学习一些更底层的逻辑与原理,此外就是学习如何更好的利用链表,实现一些别的数据结构做不到的事情,我认为 ACM 可以极大的提升我们对后者的理解。 我认为有两个方向,一是我们去学习一些更底层的逻辑与原理,此外就是学习如何更好的利用链表,实现一些别的数据结构做不到的事情,我认为 ACM 可以极大的提升我们对后者的理解。

View File

@@ -119,7 +119,7 @@ Div.1、Div.2、Div.3、Div.4 数字越小难度越大。
这是一场笔者之前赛后补过的 Div.2,画面右下角分别为赛后公告和题解,右侧便是开启 VP 的按钮。 这是一场笔者之前赛后补过的 Div.2,画面右下角分别为赛后公告和题解,右侧便是开启 VP 的按钮。
![](https://cdn.xyxsw.site/wenjing10.png) ![](https://cdn.xyxsw.site/wenjing10.png)
<em>VP</em><em>模拟赛时的好处就是在虚拟参赛中获得真实比赛才能积累的经验,比如这里笔者发现通过前三题后,我应该先去看看 F 题因为做出来的人更多我有更大的可能性做出来ACM 中题目并不是 100% 按难度排序。</em> *VP模拟赛时的好处就是在虚拟参赛中获得真实比赛才能积累的经验,比如这里笔者发现通过前三题后,我应该先去看看 F 题因为做出来的人更多我有更大的可能性做出来ACM 中题目并不是 100% 按难度排序。*
![](https://cdn.xyxsw.site/wenjing11.png) ![](https://cdn.xyxsw.site/wenjing11.png)

View File

@@ -12,7 +12,7 @@
## 学了算法就相当于学好了计算机吗? ## 学了算法就相当于学好了计算机吗?
学好了算法当然不等于学好了计算机科学。计算机科学是一个非常庞大的知识体系,包括更为底层的计算机组成原理、编译原理等,更为表层的 AI开发等是一门综合性学科。总的来说算法是计算机科学中较为重要的一部分<strong>远远</strong>不是全部。 学好了算法当然不等于学好了计算机科学。计算机科学是一个非常庞大的知识体系,包括更为底层的计算机组成原理、编译原理等,更为表层的 AI开发等是一门综合性学科。总的来说算法是计算机科学中较为重要的一部分**远远**不是全部。
## 学算法就要用《算法导论》一类的书吗? ## 学算法就要用《算法导论》一类的书吗?
@@ -32,6 +32,6 @@ ACM 是美国计算机协会Association for Computing Machinery的缩写
在我校,参加 ACM 社团姑且叫做社团并不代表能够参加有含金量的团体赛ICPC、CCPC 等)。你需要先参加由我校教练刘春英老师组织的各种比赛,有资格进入集训队后,才有机会代表学校参加比赛(当然不限名额的个人赛想参加就参加)。 在我校,参加 ACM 社团姑且叫做社团并不代表能够参加有含金量的团体赛ICPC、CCPC 等)。你需要先参加由我校教练刘春英老师组织的各种比赛,有资格进入集训队后,才有机会代表学校参加比赛(当然不限名额的个人赛想参加就参加)。
进入集训队后采取末位淘汰制度(最后留下来的人在 20 人左右),最后留下来的人才有机会参加比赛。<strong>因此个人并不推荐 0 基础的同学对于 ACM 过于执着</strong>,有 0 基础的同学最后进入校队的例子,不过这通常意味着你一天至少得刷一道算法题。如果还是想尝试的同学,可以去洛谷 ([www.luogu.com.cn](http://www.luogu.com.cn))、Codeforces([www.codeforces.com](http://www.codeforces.com))、Atcoder([atcoder.jp](https://atcoder.jp/)) 等平台上注册账号,练习题目,参加这些网站定期组织的一些比赛。 进入集训队后采取末位淘汰制度(最后留下来的人在 20 人左右),最后留下来的人才有机会参加比赛。**因此个人并不推荐 0 基础的同学对于 ACM 过于执着**,有 0 基础的同学最后进入校队的例子,不过这通常意味着你一天至少得刷一道算法题。如果还是想尝试的同学,可以去洛谷 ([www.luogu.com.cn](http://www.luogu.com.cn))、Codeforces([www.codeforces.com](http://www.codeforces.com))、Atcoder([atcoder.jp](https://atcoder.jp/)) 等平台上注册账号,练习题目,参加这些网站定期组织的一些比赛。
如果经过一段时间的练习能够在 Codefoces[www.codeforces.com](http://www.codeforces.com))上达到 1400 以上的 Rating那么可以再观望观望参与 ACM。 如果经过一段时间的练习能够在 Codefoces[www.codeforces.com](http://www.codeforces.com))上达到 1400 以上的 Rating那么可以再观望观望参与 ACM。

View File

@@ -22,9 +22,9 @@ C 语言其实是一门优秀的承上启下的语言,既具有高级语言的
但是其功能毕竟受限,有时候用起来会苦恼其操作受限以及各种奇奇怪怪的 bug 问题。 但是其功能毕竟受限,有时候用起来会苦恼其操作受限以及各种奇奇怪怪的 bug 问题。
<strong>如果为了增强自身的编程能力和计算机素养培养解决问题的能力C 语言的你的不二选择。在这里强烈推荐 jyy 老师的各类课程。(</strong><strong>[http://jyywiki.cn/](http://jyywiki.cn/)</strong><strong></strong> **如果为了增强自身的编程能力和计算机素养培养解决问题的能力C 语言的你的不二选择。在这里强烈推荐 jyy 老师的各类课程。([http://jyywiki.cn/](http://jyywiki.cn/)**
<strong>我们的任务一部分会使用 C 语言,一方面培养大家编程能力,一方面辅助大家期末考试。</strong> **我们的任务一部分会使用 C 语言,一方面培养大家编程能力,一方面辅助大家期末考试。**
### C++ ### C++
@@ -34,7 +34,7 @@ C 语言其实是一门优秀的承上启下的语言,既具有高级语言的
- 更高级的语言特征,可自定义数据类型 - 更高级的语言特征,可自定义数据类型
- 标准库 - 标准库
<strong>C++ 既有 C 面向过程的特点,又拥有面向对象的特性,是一门系统级的语言。</strong> **C++ 既有 C 面向过程的特点,又拥有面向对象的特性,是一门系统级的语言。**
编译器、操作系统的开发,高性能服务器的开发,游戏引擎的开发,硬件编程,深度学习框架的开发......只要是和底层系统或者是与性能相关的事情,通常都会有 C++ 的一席之地。 编译器、操作系统的开发,高性能服务器的开发,游戏引擎的开发,硬件编程,深度学习框架的开发......只要是和底层系统或者是与性能相关的事情,通常都会有 C++ 的一席之地。
@@ -46,7 +46,7 @@ Python 在图里是电锯,适合干比较“狂野”的任务,也是深度
使用缩进控制语句是此语言的特点。 使用缩进控制语句是此语言的特点。
<strong>作为深度学习的主要使用语言,我们将以</strong><strong>P</strong><strong>ython 为主。</strong> **作为深度学习的主要使用语言,我们将以****P****ython 为主。**
## JAVA ## JAVA
@@ -54,7 +54,7 @@ Python 在图里是电锯,适合干比较“狂野”的任务,也是深度
他太老了,虽然不少框架都依托于 Java但是不得不说一些地方略有落后。 他太老了,虽然不少框架都依托于 Java但是不得不说一些地方略有落后。
<strong>频繁应用于</strong><strong>W</strong><strong>eb 开发,安卓应用等等。</strong> **频繁应用于****W****eb 开发,安卓应用等等。**
![](https://cdn.xyxsw.site/boxcnPv2FcyQxGLjYHThSaJNwRf.jpeg) ![](https://cdn.xyxsw.site/boxcnPv2FcyQxGLjYHThSaJNwRf.jpeg)

View File

@@ -22,7 +22,7 @@
更严重的是,他可能会透支学校的信誉。 更严重的是,他可能会透支学校的信誉。
<strong>同时,先学好 C 语言对你有以下帮助:</strong> **同时,先学好 C 语言对你有以下帮助:**
1. 掌握计算机底层知识C 语言是一种高效的系统级语言,它的语法和数据结构设计直接映射到底层计算机硬件,通过学习 C 语言可以更深入地了解计算机底层运作原理,为理解更高级的编程语言和开发工具奠定基础。 1. 掌握计算机底层知识C 语言是一种高效的系统级语言,它的语法和数据结构设计直接映射到底层计算机硬件,通过学习 C 语言可以更深入地了解计算机底层运作原理,为理解更高级的编程语言和开发工具奠定基础。
2. 提高编程能力C 语言的语法相对较为简单,但是它要求程序员手动管理内存,这需要编程者深入了解内存结构和指针的使用。通过学习 C 语言,可以锻炼编程能力,提高代码质量和效率。 2. 提高编程能力C 语言的语法相对较为简单,但是它要求程序员手动管理内存,这需要编程者深入了解内存结构和指针的使用。通过学习 C 语言,可以锻炼编程能力,提高代码质量和效率。
@@ -65,7 +65,7 @@ NJU-ICS-PA 南京大学计算机系统基础
有且仅有大学有这样好的资源帮助你了 有且仅有大学有这样好的资源帮助你了
## <strong>坚持了好久还是搞不定,我想放弃了</strong> ## **坚持了好久还是搞不定,我想放弃了**
![](https://cdn.xyxsw.site/boxcnuNXrb5zOppCZAlGQ19wuDk.jpg) ![](https://cdn.xyxsw.site/boxcnuNXrb5zOppCZAlGQ19wuDk.jpg)

View File

@@ -12,7 +12,7 @@ Visual Studio以下简称 VS是 Windows 下最完美的 C/C++ 等语言的
什么是 IDE什么是代码编辑器什么是编译器等等细碎问题参考文档 [3.1 该使用哪个编辑器???](3.1%E8%AF%A5%E4%BD%BF%E7%94%A8%E5%93%AA%E4%B8%AA%E7%BC%96%E8%BE%91%E5%99%A8%EF%BC%9F%EF%BC%9F%EF%BC%9F.md) 看不懂的话直接无脑装 什么是 IDE什么是代码编辑器什么是编译器等等细碎问题参考文档 [3.1 该使用哪个编辑器???](3.1%E8%AF%A5%E4%BD%BF%E7%94%A8%E5%93%AA%E4%B8%AA%E7%BC%96%E8%BE%91%E5%99%A8%EF%BC%9F%EF%BC%9F%EF%BC%9F.md) 看不懂的话直接无脑装
### <strong>下载</strong> ### **下载**
[https://visualstudio.microsoft.com/zh-hans/downloads/](https://visualstudio.microsoft.com/zh-hans/downloads/) [https://visualstudio.microsoft.com/zh-hans/downloads/](https://visualstudio.microsoft.com/zh-hans/downloads/)
@@ -60,7 +60,7 @@ VS 是项目制,你需要创建一个项目才能开始编写代码并运行
阅读完以后,就可以将代码全部删去,编写自己的代码了。 阅读完以后,就可以将代码全部删去,编写自己的代码了。
注意控制台项目初始源文件后缀为.cpp 为 C++ 文件,如果编写 C 语言<strong>建议将后缀改为.c</strong>。.cpp 存在隐患:如果不小心使用了 C++ 的语法而非 C 存在的语法,编译器并不会报错,且 C 与 C++ 在某些特性存在区别。 注意控制台项目初始源文件后缀为.cpp 为 C++ 文件,如果编写 C 语言**建议将后缀改为.c**。.cpp 存在隐患:如果不小心使用了 C++ 的语法而非 C 存在的语法,编译器并不会报错,且 C 与 C++ 在某些特性存在区别。
### “运行”你的 C 语言代码 ### “运行”你的 C 语言代码
@@ -88,7 +88,7 @@ IDE 相比于代码编辑器,最强大的一点莫过于成熟的调试系统
![](https://cdn.xyxsw.site/boxcnydHyaNPqUEVVWmbdGofX0d.png) ![](https://cdn.xyxsw.site/boxcnydHyaNPqUEVVWmbdGofX0d.png)
### <strong>深色主题</strong> ### **深色主题**
需要深色主题请在工具 - 主题里更改为深色 需要深色主题请在工具 - 主题里更改为深色

View File

@@ -17,7 +17,7 @@
## Work an Example Yourself ## Work an Example Yourself
尝试设计算法的第一步是<strong>自己(手动)处理至少一个问题实例,为每个参数选择特定值。</strong>往往需要确定<strong>一个正确的示例,以及错误的示例。</strong> 尝试设计算法的第一步是**自己(手动)处理至少一个问题实例,为每个参数选择特定值。**往往需要确定**一个正确的示例,以及错误的示例。**
如果你在这一步陷入困境,这通常意味着两件事中的一件。第一种情况是问题不明确,不清楚你应该做什么。在这种情况下,你必须在继续之前解决问题。如果你正在解决自己创造的问题,你可能需要更仔细地思考正确的答案应该是什么,并完善你对问题的定义。 如果你在这一步陷入困境,这通常意味着两件事中的一件。第一种情况是问题不明确,不清楚你应该做什么。在这种情况下,你必须在继续之前解决问题。如果你正在解决自己创造的问题,你可能需要更仔细地思考正确的答案应该是什么,并完善你对问题的定义。
@@ -25,15 +25,15 @@
## Write Down What You Just Did ## Write Down What You Just Did
这一步中,必须思考解决问题所做的工作,并写下<strong>解决该特定实例的步骤。</strong>思考这一步骤的另一种方式是,写下一组清晰的指示,<strong>其他人可以按照这些指示来重现刚刚解决的特定问题实例的答案</strong>。如果在步骤 1 中执行了多个实例,那么也将重复步骤 2 多次,对步骤 1 中的每个实例重复一次。如果一条指令有点复杂,那没关系,只要指令稍后有明确的含义,我们将把这些复杂的步骤转化为它们自己的编程问题,这些问题将单独解决。 这一步中,必须思考解决问题所做的工作,并写下**解决该特定实例的步骤。**思考这一步骤的另一种方式是,写下一组清晰的指示,**其他人可以按照这些指示来重现刚刚解决的特定问题实例的答案**。如果在步骤 1 中执行了多个实例,那么也将重复步骤 2 多次,对步骤 1 中的每个实例重复一次。如果一条指令有点复杂,那没关系,只要指令稍后有明确的含义,我们将把这些复杂的步骤转化为它们自己的编程问题,这些问题将单独解决。
## Generalize Your Steps ## Generalize Your Steps
<strong>将步骤 2 得到的具体步骤,抽象为一般性的结论。</strong>有时可能很难概括步骤。发生这种情况时,返回步骤 1 和 2 可能会有所帮助。做更多的问题实例将提供更多的信息供参考,更能帮助深入算法。这个过程通常被称为编写“伪代码”,以编程方式设计算法,而不使用特定的目标语言。几乎所有的程序员在编写任何实际代码之前都会使用这种方法来确保他们的算法是正确的。 **将步骤 2 得到的具体步骤,抽象为一般性的结论。**有时可能很难概括步骤。发生这种情况时,返回步骤 1 和 2 可能会有所帮助。做更多的问题实例将提供更多的信息供参考,更能帮助深入算法。这个过程通常被称为编写“伪代码”,以编程方式设计算法,而不使用特定的目标语言。几乎所有的程序员在编写任何实际代码之前都会使用这种方法来确保他们的算法是正确的。
## Test Your Algorithm ## Test Your Algorithm
在步骤 3 之后,我们有了一个我们认为正确的算法。然而,我们完全有可能在这一路上搞砸了。步骤 4 的主要目的是确保我们的步骤在继续之前是正确的。为了实现这一点,我们使用<strong>不同于设计算法时使用的参数值</strong>来测试我们的算法。我们手动执行算法,并将其获得的答案与正确的答案进行比较。如果它们不同,那么我们知道我们的算法是错误的。我们使用的测试用例(参数值)越多,我们就越能确信我们的算法是正确的。不幸的是,通过测试无法确保我们的算法是正确的。要完全确定你的算法是正确的,唯一的方法就是正式证明它的正确性(使用数学证明),这超出了这个专门化的范围。 在步骤 3 之后,我们有了一个我们认为正确的算法。然而,我们完全有可能在这一路上搞砸了。步骤 4 的主要目的是确保我们的步骤在继续之前是正确的。为了实现这一点,我们使用**不同于设计算法时使用的参数值**来测试我们的算法。我们手动执行算法,并将其获得的答案与正确的答案进行比较。如果它们不同,那么我们知道我们的算法是错误的。我们使用的测试用例(参数值)越多,我们就越能确信我们的算法是正确的。不幸的是,通过测试无法确保我们的算法是正确的。要完全确定你的算法是正确的,唯一的方法就是正式证明它的正确性(使用数学证明),这超出了这个专门化的范围。
确定好的测试用例是一项重要的技能,可以随着实践而提高。对于步骤 4 中的测试,您需要使用至少产生几个不同答案的情况进行测试(例如,如果您的算法有“是”或“否”答案,则应使用同时产生“是”和“否”的参数进行测试)。您还应该测试任何角落情况,其中行为可能与更一般的情况不同。每当您有条件决定(包括计算位置的限制)时,您应该在这些条件的边界附近测试潜在的角点情况。 确定好的测试用例是一项重要的技能,可以随着实践而提高。对于步骤 4 中的测试,您需要使用至少产生几个不同答案的情况进行测试(例如,如果您的算法有“是”或“否”答案,则应使用同时产生“是”和“否”的参数进行测试)。您还应该测试任何角落情况,其中行为可能与更一般的情况不同。每当您有条件决定(包括计算位置的限制)时,您应该在这些条件的边界附近测试潜在的角点情况。
@@ -47,7 +47,7 @@
在黑盒测试中,测试人员只考虑功能的预期行为,而不考虑设计测试用例的任何实现细节。缺乏对实现细节的访问是这种测试方法的由来——函数的实现被视为测试人员无法查看的“黑盒子”。 在黑盒测试中,测试人员只考虑功能的预期行为,而不考虑设计测试用例的任何实现细节。缺乏对实现细节的访问是这种测试方法的由来——函数的实现被视为测试人员无法查看的“黑盒子”。
事实上我们无需执行步骤 1-5 就能够为假设问题设想好的测试用例。实际上,在开始解决问题之前,您可以针对问题提出一组黑盒测试。一些程序员提倡<strong>测试优先</strong>的开发方法。一个优点是,如果您在开始之前编写了一个全面的测试套件,那么在实现代码之后就不太可能在测试上有所疏漏。另一个优点是,通过提前考虑你的情况,你在开发和实现算法时能够降低错误率。 事实上我们无需执行步骤 1-5 就能够为假设问题设想好的测试用例。实际上,在开始解决问题之前,您可以针对问题提出一组黑盒测试。一些程序员提倡**测试优先**的开发方法。一个优点是,如果您在开始之前编写了一个全面的测试套件,那么在实现代码之后就不太可能在测试上有所疏漏。另一个优点是,通过提前考虑你的情况,你在开发和实现算法时能够降低错误率。
- 选择测试用例的一些建议 - 选择测试用例的一些建议

View File

@@ -1,6 +1,6 @@
# C 语言前置概念学习 # C 语言前置概念学习
如何学习 C 语言?<strong>第一步:Throw away the textbook。</strong>也许你可以通过以下途径: 如何学习 C 语言?**第一步:Throw away the textbook。**也许你可以通过以下途径:
以下方式难度由易到难,但并不意味着收获由小到大: 以下方式难度由易到难,但并不意味着收获由小到大:
@@ -14,9 +14,9 @@
4.Web[CNote](https://github.com/coderit666/CNote)(例子密集,学习曲线平滑,覆盖面广且具有深度) 4.Web[CNote](https://github.com/coderit666/CNote)(例子密集,学习曲线平滑,覆盖面广且具有深度)
5.Book<strong>教材替换用书——《C Primer Plus》</strong>(基础且深入的恰到好处,有一定拓展,可能后面的章节有点难懂,是一本不可多得的好书,不要忽视课本习题及 Projects 5.Book**教材替换用书——《C Primer Plus》**(基础且深入的恰到好处,有一定拓展,可能后面的章节有点难懂,是一本不可多得的好书,不要忽视课本习题及 Projects
6.MOOC[Introductory C Programming 专项课程](https://www.coursera.org/specializations/c-programming)<strong>全英文</strong>,好处是涉及到计算机思维,包含许多常用 tools 的教学例如 git、make、emacs、gdb视频讲解结合文档阅读对于 C 的重要核心知识讲解透彻,难度颇高,建议用作提升) 6.MOOC[Introductory C Programming 专项课程](https://www.coursera.org/specializations/c-programming)**全英文**,好处是涉及到计算机思维,包含许多常用 tools 的教学例如 git、make、emacs、gdb视频讲解结合文档阅读对于 C 的重要核心知识讲解透彻,难度颇高,建议用作提升)
7.Web[LinuxC 一站式编程](https://akaedu.github.io/book/)(难度大,枯燥硬核,收获多,基于 linux 7.Web[LinuxC 一站式编程](https://akaedu.github.io/book/)(难度大,枯燥硬核,收获多,基于 linux
@@ -38,4 +38,4 @@
![](https://cdn.xyxsw.site/Hqzbbs6iYobnxWxz11Ocfa9gnHd.png) ![](https://cdn.xyxsw.site/Hqzbbs6iYobnxWxz11Ocfa9gnHd.png)
### <strong>CS education is more than just “learning how to code”!</strong> ### **CS education is more than just “learning how to code”!**

View File

@@ -54,9 +54,9 @@ typedef struct Node* Link;
例如,若链表无头结点,则对于在链表中第一个数据结点之前插入一个新结点,或者对链表中第一个数据结点做删除操作,都必须要当做特殊情况,进行特殊考虑;而若链表中设有头结点,以上两种特殊情况都可被视为普通情况,不需要特殊考虑,降低了问题实现的难度。 例如,若链表无头结点,则对于在链表中第一个数据结点之前插入一个新结点,或者对链表中第一个数据结点做删除操作,都必须要当做特殊情况,进行特殊考虑;而若链表中设有头结点,以上两种特殊情况都可被视为普通情况,不需要特殊考虑,降低了问题实现的难度。
<strong>链表有头结点,也不一定都是有利的。例如解决约瑟夫环问题,若链表有头结点,在一定程度上会阻碍算法的实现。</strong> **链表有头结点,也不一定都是有利的。例如解决约瑟夫环问题,若链表有头结点,在一定程度上会阻碍算法的实现。**
<strong>所以,对于一个链表来说,设置头指针是必要且必须的,但有没有头结点,则需要根据实际问题特殊分析。</strong> **所以,对于一个链表来说,设置头指针是必要且必须的,但有没有头结点,则需要根据实际问题特殊分析。**
首元结点:指的是链表开头第一个存有数据的结点。 首元结点:指的是链表开头第一个存有数据的结点。
@@ -329,7 +329,7 @@ int ListDelete(Link *L, int i, int* e)
- 3 出列后,从 5 开始数 12 数 2所以 2 出列; - 3 出列后,从 5 开始数 12 数 2所以 2 出列;
- 最后只剩下 5 自己,所以 5 胜出。 - 最后只剩下 5 自己,所以 5 胜出。
那么,究竟要如何用链表实现约瑟夫环呢?如何让一个含 5 个元素的约瑟夫环,能从第 5 个元素出发,访问到第 2 个元素呢?上面所讲的链表操作显然是难以做到的,解决这个问题就需要用到<strong>循环链表</strong> 那么,究竟要如何用链表实现约瑟夫环呢?如何让一个含 5 个元素的约瑟夫环,能从第 5 个元素出发,访问到第 2 个元素呢?上面所讲的链表操作显然是难以做到的,解决这个问题就需要用到**循环链表**
## 循环链表 ## 循环链表

View File

@@ -21,7 +21,7 @@ It is very dark in here.
Bye! Bye!
尽管可能微不足道,但该程序确实展示 <em>了</em>任何文本冒险中最重要的方面:描述性文本。一个好的故事是制作一款好的冒险游戏的要素之一。 尽管可能微不足道,但该程序确实展示 *了*任何文本冒险中最重要的方面:描述性文本。一个好的故事是制作一款好的冒险游戏的要素之一。
## 为什么要用英文? ## 为什么要用英文?

View File

@@ -12,7 +12,7 @@
举个例子,一条林道可能隐藏着陷阱。虽然通道似乎从位置 A 通向位置 B但实际上终点是位置 C即掉进坑了。 举个例子,一条林道可能隐藏着陷阱。虽然通道似乎从位置 A 通向位置 B但实际上终点是位置 C即掉进坑了。
假设我们的洞口被警卫挡住了。玩家就过不去,我们可以简单地将通道的<em>目的地</em>更改为终点位置(或 <em>NULL</em>),但这会导致对<em>诸如 go cave 和 look cave</em> 这样的命令做出不正确的回应:“你在这里看不到任何洞穴。我们需要一个将通道的实际终点和虚假终点分开的单独属性。为此,我们将引入一个属性 prospect 来表示后者。 假设我们的洞口被警卫挡住了。玩家就过不去,我们可以简单地将通道的*目的地*更改为终点位置(或 *NULL*),但这会导致对*诸如 go cave 和 look cave* 这样的命令做出不正确的回应:“你在这里看不到任何洞穴。我们需要一个将通道的实际终点和虚假终点分开的单独属性。为此,我们将引入一个属性 prospect 来表示后者。
1. 在许多冒险中,玩家以及游戏中的 NPC 在携带量方面受到限制。给每件物品一个重量,角色库存中所有物品的总重量不应超过该角色所能承载的最大重量。当然,我们也可以给一个物体一个非常高的重量,使它不可移动(一棵树,一座房子,一座山)。 1. 在许多冒险中,玩家以及游戏中的 NPC 在携带量方面受到限制。给每件物品一个重量,角色库存中所有物品的总重量不应超过该角色所能承载的最大重量。当然,我们也可以给一个物体一个非常高的重量,使它不可移动(一棵树,一座房子,一座山)。
2. RPG 式的冒险游戏需要角色的整个属性范围 ( 玩家与非玩家 ),例如 HP。HP 为零的对象要么死了,要么根本不是角色。 2. RPG 式的冒险游戏需要角色的整个属性范围 ( 玩家与非玩家 ),例如 HP。HP 为零的对象要么死了,要么根本不是角色。
@@ -120,7 +120,7 @@ extern OBJECT objs[];
::: warning 🤔 思考题:你能否自行实现上述伪代码? ::: warning 🤔 思考题:你能否自行实现上述伪代码?
::: :::
现在,我们已经可以使用新属性 (如果你完成了上面的思考题),<strong>details</strong> 用于新识别的命令<em>外观`<object>`</em><strong>textGo</strong> 在我们的命令 <em>go</em> 实现中替换固定文本<em>“OK</em>”。 现在,我们已经可以使用新属性 (如果你完成了上面的思考题),**details** 用于新识别的命令*外观`<object>`***textGo** 在我们的命令 *go* 实现中替换固定文本*“OK*”。
## location.c ## location.c
@@ -331,11 +331,11 @@ void executeInventory(void)
::: warning 🤔 思考题:仔细观察这段代码,看看与你写的有何不同? ::: warning 🤔 思考题:仔细观察这段代码,看看与你写的有何不同?
::: :::
权重检查利用了新功能 <em>weightOfContents</em>它将在<em>misc.c</em>中实现。在同一模块中,我们还对一些现有函数进行了修改,以支持最后几个属性。 权重检查利用了新功能 *weightOfContents*它将在*misc.c*中实现。在同一模块中,我们还对一些现有函数进行了修改,以支持最后几个属性。
属性内容将替换固定文本<em>“You see”。</em>在列出玩家的库存时,原始文本已经有点奇怪了,但是现在函数<em>listObjectsAtLocation</em>用于显示任何可能对象的内容(请参阅上面的函数<em>expertLook</em>),我们真的需要一些更灵活的东西。 属性内容将替换固定文本*“You see”。*在列出玩家的库存时,原始文本已经有点奇怪了,但是现在函数*listObjectsAtLocation*用于显示任何可能对象的内容(请参阅上面的函数*expertLook*),我们真的需要一些更灵活的东西。
在函数 <em>getPassage</em> 中我们将属性<em>目标</em>替换为 prospect并改进<em>对所有</em>命令(而不仅仅是 <em>go</em> and <em>look</em>)的响应,这些命令应用于位于“隐藏通道”另一端的位置。 在函数 *getPassage* 中我们将属性*目标*替换为 prospect并改进*对所有*命令(而不仅仅是 *go* and *look*)的响应,这些命令应用于位于“隐藏通道”另一端的位置。
## misc.h ## misc.h
@@ -462,8 +462,8 @@ function outputEdge(from, to, style)
注意: 注意:
- 尽量不要太担心浪费仅在某些类型的对象中使用的属性上的内存空间(例如,<em>textGo</em>仅用于通道),或者许多重复的字符串文本。 - 尽量不要太担心浪费仅在某些类型的对象中使用的属性上的内存空间(例如,*textGo*仅用于通道),或者许多重复的字符串文本。
- 为了演示属性 prospect 的使用,我们使洞穴无法访问。当您查看新<em>地图时,</em>这一点立即变得很明显。进入洞穴的箭头是虚线的,这意味着这是一个虚假的通道,但不是实际的通道。请放心,洞穴将在下一章重新开放。 - 为了演示属性 prospect 的使用,我们使洞穴无法访问。当您查看新*地图时,*这一点立即变得很明显。进入洞穴的箭头是虚线的,这意味着这是一个虚假的通道,但不是实际的通道。请放心,洞穴将在下一章重新开放。
- 请注意,更详细的描述往往需要一个更大的字典(更多的对象,更多的标签)。例如,命令 look silver coin 现在返回 "该硬币的正面有一只鹰"。玩家通过输入一个命令 look eagle 来查看银币,但程序并不知道鹰是什么意思 (显然这样子是不行的)。 - 请注意,更详细的描述往往需要一个更大的字典(更多的对象,更多的标签)。例如,命令 look silver coin 现在返回 "该硬币的正面有一只鹰"。玩家通过输入一个命令 look eagle 来查看银币,但程序并不知道鹰是什么意思 (显然这样子是不行的)。
输出样例 输出样例

View File

@@ -13,7 +13,7 @@
打开一个封闭的通道(在这里是进入洞穴)涉及到改变一些属性值: 打开一个封闭的通道(在这里是进入洞穴)涉及到改变一些属性值:
- 目的地从 NULL(空地点) 变为洞穴 - 目的地从 NULL(空地点) 变为洞穴
- <strong>textGo</strong>从 "警卫阻止你...... "改为 "你走进山洞" - **textGo**从 "警卫阻止你...... "改为 "你走进山洞"
- 在一些特殊情况下,描述和细节不需要改变。但对于一个门洞或栅栏,其中之一(或两者)通常会包含一些从 "开放 "到 "关闭 "的文字。 - 在一些特殊情况下,描述和细节不需要改变。但对于一个门洞或栅栏,其中之一(或两者)通常会包含一些从 "开放 "到 "关闭 "的文字。
有许多方法来实现这一目标。在这里,我们将讨论一种简单、可维护和通用的方法。 有许多方法来实现这一目标。在这里,我们将讨论一种简单、可维护和通用的方法。
@@ -22,7 +22,7 @@
接下来,我们引入一个名为条件的新属性,它决定了某个对象是否存在。这两个通道将被赋予互斥的条件,因此在任何时候都只能有一个存在。 接下来,我们引入一个名为条件的新属性,它决定了某个对象是否存在。这两个通道将被赋予互斥的条件,因此在任何时候都只能有一个存在。
每个条件将被实现为一个布尔函数:<strong>TRUE</strong>意味着该对象存在,<strong>FALSE</strong>意味着它不存在。 每个条件将被实现为一个布尔函数:**TRUE**意味着该对象存在,**FALSE**意味着它不存在。
```c ```c
bool intoCaveIsOpen(void) bool intoCaveIsOpen(void)
@@ -281,7 +281,7 @@ int listObjectsAtLocation(OBJECT *location)
注意: 注意:
1. 警卫不可能会死,所以可以说我们的条件函数中的<strong>HP</strong>是很无用的。当然,这很容易通过添加一个 kill 命令来解决,见第 20 章。 1. 警卫不可能会死,所以可以说我们的条件函数中的**HP**是很无用的。当然,这很容易通过添加一个 kill 命令来解决,见第 20 章。
2. 这两个条件函数是互补的;它们有资格成为重复的代码。为了消除这一点,我们可能决定让一个函数调用另一个函数(用''操作符来否定结果)。一个匿名函数没有(稳定的)名字,但我们可以用它的对象来指代它。我们可以用 intoCaveBlocked 的条件函数代替。 2. 这两个条件函数是互补的;它们有资格成为重复的代码。为了消除这一点,我们可能决定让一个函数调用另一个函数(用''操作符来否定结果)。一个匿名函数没有(稳定的)名字,但我们可以用它的对象来指代它。我们可以用 intoCaveBlocked 的条件函数代替。
3. 为了简单起见,条件函数没有参数。实际上,传递一个参数 OBJECT *obj 可能更好;这使得编写更多的通用条件函数成为可能,可以在多个对象中重复使用。 3. 为了简单起见,条件函数没有参数。实际上,传递一个参数 OBJECT *obj 可能更好;这使得编写更多的通用条件函数成为可能,可以在多个对象中重复使用。
4. 在理论上,任何对象都可以成为 "条件"。在下一章,你可以看到一个类似的技术被应用于此。 4. 在理论上,任何对象都可以成为 "条件"。在下一章,你可以看到一个类似的技术被应用于此。

View File

@@ -246,7 +246,7 @@ bool matchCommand(const char *src, const char *pattern)
我们调整各种命令的实现,以利用新的数组参数。 我们调整各种命令的实现,以利用新的数组参数。
## <strong>inventory.h</strong> ## **inventory.h**
```c ```c
extern bool executeGet(void); extern bool executeGet(void);
@@ -256,7 +256,7 @@ extern bool executeGive(void);
extern bool executeInventory(void); extern bool executeInventory(void);
``` ```
## <strong>inventory.c</strong> ## **inventory.c**
```c ```c
#include <stdbool.h> #include <stdbool.h>

View File

@@ -1,6 +1,6 @@
# 2.探索未知 # 2.探索未知
::: tip <font size=5><strong> 驾驭项目,而不是被项目驾驭</strong></font> ::: tip <font size=5>**驾驭项目,而不是被项目驾驭**</font>
你和一个项目的关系会经历 4 个阶段: 你和一个项目的关系会经历 4 个阶段:
@@ -35,9 +35,9 @@
::: :::
下面的代码示例包含三个函数,每个步骤一个函数: 下面的代码示例包含三个函数,每个步骤一个函数:
1. 函数<em>getInput</em> 1. 函数*getInput*
2. 函数<em>parseAndExecute</em> 2. 函数*parseAndExecute*
3. 函数<em>main</em>,负责重复调用其他两个函数。 3. 函数*main*,负责重复调用其他两个函数。
## main.c ## main.c
@@ -70,7 +70,7 @@ int main()
::: warning 🤔 思考题static 是什么意思?我为什么要用他? ::: warning 🤔 思考题static 是什么意思?我为什么要用他?
::: :::
## <strong>parsexec.h</strong> ## **parsexec.h**
```c ```c
extern bool parseAndExecute(char *input); extern bool parseAndExecute(char *input);
@@ -86,7 +86,7 @@ extern 是干什么的?.h 文件又在干嘛?
在这里用指针是为了传参的时候可以传字符串哦 在这里用指针是为了传参的时候可以传字符串哦
::: :::
## <strong>parsexec.c</strong> ## **parsexec.c**
```c ```c
#include <stdbool.h> #include <stdbool.h>
@@ -126,9 +126,9 @@ bool parseAndExecute(char *input)
你的编译器可能会给出警告 the unused variablenoun这些不用担心将会在下一章解决。 你的编译器可能会给出警告 the unused variablenoun这些不用担心将会在下一章解决。
返回<em>false</em>将导致主循环结束。 返回*false*将导致主循环结束。
::: warning <font size=5><strong>RTFM&&STFW</strong></font> ::: warning <font size=5>**RTFM&&STFW**</font>
搞懂 strtok 和 strcmp 的用法 搞懂 strtok 和 strcmp 的用法
::: :::

View File

@@ -99,7 +99,7 @@ bx = torch.cat((xs[0], bs[0], xs[1], bs[1], xs[2], bs[2], xs[3], bs[3], xs[4], b
这个故事折射出,大公司中程序员的编程习惯也许不比你好多少,他们也会写出 Copy-Paste 这种难以维护的代码。但反过来说,重视编码风格这些企业看中的能力,你从现在就可以开始培养。 这个故事折射出,大公司中程序员的编程习惯也许不比你好多少,他们也会写出 Copy-Paste 这种难以维护的代码。但反过来说,重视编码风格这些企业看中的能力,你从现在就可以开始培养。
::: :::
<em>传统上,文本冒险是由(许多)不同位置组成的虚拟世界。虽然这不是必需的(一些冒险发生在一个房间里!),但这是解释</em><em>数据结构</em><em>使用的好方法。</em> *传统上,文本冒险是由(许多)不同位置组成的虚拟世界。虽然这不是必需的(一些冒险发生在一个房间里!),但这是解释**数据结构**使用的好方法。*
我们首先定义一个[结构](http://en.wikipedia.org/wiki/Struct_(C_programming_language))来表示一个位置。它包含两个简单的属性开始(稍后可能会有更多的属性)。 我们首先定义一个[结构](http://en.wikipedia.org/wiki/Struct_(C_programming_language))来表示一个位置。它包含两个简单的属性开始(稍后可能会有更多的属性)。
@@ -136,7 +136,7 @@ struct location locs[2] = {
}; };
``` ```
让我们把它付诸实践。在上一章(<em>parsexec.c</em> 的代码示例中,我们更改了第 4、18 和 22 行)。 让我们把它付诸实践。在上一章(*parsexec.c* 的代码示例中,我们更改了第 4、18 和 22 行)。
## <strong>parsexec.c</strong> ## <strong>parsexec.c</strong>
@@ -237,9 +237,9 @@ void executeGo(const char *noun)
} }
``` ```
在 C 语言中,你可以使用单个语句来定义类型(<em>结构位置</em>),声明变量(<em>locs</em>)并用其初始值填充它。 在 C 语言中,你可以使用单个语句来定义类型(*结构位置*),声明变量(*locs*)并用其初始值填充它。
思考题:变量<em>locs</em>是[静态分配的](http://en.wikipedia.org/wiki/Static_memory_allocation),什么是静态分配? 思考题:变量*locs*是[静态分配的](http://en.wikipedia.org/wiki/Static_memory_allocation),什么是静态分配?
静态分配和动态分配有什么不同之处? 静态分配和动态分配有什么不同之处?

View File

@@ -1,17 +1,17 @@
# 4.创建对象 # 4.创建对象
<em>在我们继续之前,我</em><em>们</em><em>在这里使用的是</em><em>[哲学意义上](https://en.wikipedia.org/wiki/Object_(philosophy))</em><em>的“对象”一词。它与</em><em>[面向对象编程](https://en.wikipedia.org/wiki/Object-oriented_programming)</em><em>无关,也与</em><em>Java</em><em></em><em>C#</em><em>和</em><em>Python</em><em>等编程语言中预定义的“对象”类型没有任何共同之处。下面,我将定义一个名为 object 的</em><em>结构体。</em> *在我们继续之前,我们在这里使用的是[哲学意义上](https://en.wikipedia.org/wiki/Object_(philosophy))的“对象”一词。它与[面向对象编程](https://en.wikipedia.org/wiki/Object-oriented_programming)无关也与JavaC#和Python等编程语言中预定义的“对象”类型没有任何共同之处。下面,我将定义一个名为 object 的结构体。*
冒险游戏中的大多数谜题都围绕着<strong>物品</strong>。例子: 冒险游戏中的大多数谜题都围绕着**物品**。例子:
- 必须找到一把钥匙,然后用来解锁某扇门。 - 必须找到一把钥匙,然后用来解锁某扇门。
- 必须杀死守卫或者诱骗守卫才能开启房间 - 必须杀死守卫或者诱骗守卫才能开启房间
所以,为了表示这个物品,我们可以使用如下[结构](http://en.wikipedia.org/wiki/Struct_(C_programming_language)) 所以,为了表示这个物品,我们可以使用如下[结构](http://en.wikipedia.org/wiki/Struct_(C_programming_language))
- <strong>description: </strong><strong>对物品的描述</strong> - **description: ****对物品的描述**
- <strong>tag: </strong><strong>物品的类型</strong> - **tag: ****物品的类型**
- <strong>location: </strong><strong>物品所在</strong><strong>的位置。这是</strong><strong>对应</strong><strong>上一章中定义的</strong><strong>物品</strong><strong>位置</strong><strong>的指针。</strong> - **location: ****物品所在****的位置。这是****对应****上一章中定义的****物品****位置****的指针。**
```c ```c
struct object { struct object {
@@ -87,30 +87,30 @@ for (obj = objs; obj < objs + 5; obj++)
那么,我们有合并这个物品(或地点)列表有什么好处呢?答案是这会让我们的代码变得更加简单,因为许多函数(如上面的函数通过这样的列表)只需要扫描单个列表就可以实现,而不是三个列表。有人可能会说没必要,因为每个命令仅适用于一种类型的对象: 那么,我们有合并这个物品(或地点)列表有什么好处呢?答案是这会让我们的代码变得更加简单,因为许多函数(如上面的函数通过这样的列表)只需要扫描单个列表就可以实现,而不是三个列表。有人可能会说没必要,因为每个命令仅适用于一种类型的对象:
- 命令 <em>go</em> 适用于位置对象。 - 命令 *go* 适用于位置对象。
- 命令 <em>get</em> 应用于获得物品。 - 命令 *get* 应用于获得物品。
- 命令 kill 适应用于杀死人物。 - 命令 kill 适应用于杀死人物。
但这种方法不太对劲,原因有三: 但这种方法不太对劲,原因有三:
1. 某些命令适用于多种类型的对象,尤其是<em>检查</em> 1. 某些命令适用于多种类型的对象,尤其是*检查*
2. 有时候会出现很没意思的交互方式,比如说你要吃掉守卫,他说不行。 2. 有时候会出现很没意思的交互方式,比如说你要吃掉守卫,他说不行。
3. 某些对象在游戏中可能具有多个角色。比如说队友系统NPC 可以是你的物品也可以是对象 3. 某些对象在游戏中可能具有多个角色。比如说队友系统NPC 可以是你的物品也可以是对象
将所有对象放在一个大列表中很容易添加一个名为“type”的属性来<em>构造对象</em>,以帮助我们区分不同类型的对象。 将所有对象放在一个大列表中很容易添加一个名为“type”的属性来*构造对象*,以帮助我们区分不同类型的对象。
::: warning 🤔 怎么做怎么遍历呢?先思考吧 ::: warning 🤔 怎么做怎么遍历呢?先思考吧
::: :::
但是,对象通常具有同样有效的其他特征: 但是,对象通常具有同样有效的其他特征:
- <strong>Locations通过</strong><strong>道路</strong><strong>连接(将在后面介绍)。如果一个物体无法通过一条通道到达,那么它就不是一个位置。就是这么简单。</strong> - **Locations通过****道路****连接(将在后面介绍)。如果一个物体无法通过一条通道到达,那么它就不是一个位置。就是这么简单。**
- <strong>Items玩家唯一可以捡起的物品;</strong><strong>可以给他们整一个重量的属性</strong> - **Items玩家唯一可以捡起的物品;****可以给他们整一个重量的属性**
- <strong>Actors玩家唯一可以与之交谈交易战斗的对象;当然,前提是他们还活着!</strong><strong>可以加一个 HP 属性</strong> - **Actors玩家唯一可以与之交谈交易战斗的对象;当然,前提是他们还活着!****可以加一个 HP 属性**
我们还要向数组中添加一个对象:玩家自己。 我们还要向数组中添加一个对象:玩家自己。
在上一章中,有一个单独的变量 <em>locationOfPlayer</em>。我们将删除它,然后换上用户的位置属性取代他! 在上一章中,有一个单独的变量 *locationOfPlayer*。我们将删除它,然后换上用户的位置属性取代他!
例如,此语句会将玩家移入洞穴: 例如,此语句会将玩家移入洞穴:
@@ -163,7 +163,7 @@ OBJECT objs[] = {
}; };
``` ```
<strong>注意:</strong>要编译此模块,编译器<em>必须</em>支持 Constant folding。这排除了一些更原始的编译器如 [Z88DK](http://en.wikipedia.org/wiki/Z88DK)。 **注意:**要编译此模块,编译器*必须*支持 Constant folding。这排除了一些更原始的编译器如 [Z88DK](http://en.wikipedia.org/wiki/Z88DK)。
以下模块将帮助我们找到与指定名词匹配的对象。 以下模块将帮助我们找到与指定名词匹配的对象。
@@ -173,7 +173,7 @@ OBJECT objs[] = {
extern OBJECT *getVisible(const char *intention, const char *noun); extern OBJECT *getVisible(const char *intention, const char *noun);
``` ```
::: warning <font size=5><strong>🤔 指针?函数?希望你已经掌握这是什么了</strong></font> ::: warning <font size=5>**🤔 指针?函数?希望你已经掌握这是什么了**</font>
::: :::
## noun.c ## noun.c
@@ -232,7 +232,7 @@ OBJECT *getVisible(const char *intention, const char *noun)
} }
``` ```
这是另一个辅助程序的函数。它打印存在于特定位置的对象物品NPC的列表。它将用于函数 <em>executeLook</em>,在下一章中,我们将介绍另一个需要它的命令。 这是另一个辅助程序的函数。它打印存在于特定位置的对象物品NPC的列表。它将用于函数 *executeLook*,在下一章中,我们将介绍另一个需要它的命令。
## misc.h ## misc.h
@@ -268,7 +268,7 @@ int listObjectsAtLocation(OBJECT *location)
} }
``` ```
<em>location.c</em> 中,命令环<em>顾四周的实现</em>,并根据新的数据结构进行调整。旧的位置数组被删除,变量 <em>locationOfPlayer</em> 也是如此。 *location.c* 中,命令环*顾四周的实现*,并根据新的数据结构进行调整。旧的位置数组被删除,变量 *locationOfPlayer* 也是如此。
## location.h ## location.h
@@ -302,7 +302,7 @@ void executeLook(const char *noun)
void executeGo(const char *noun) void executeGo(const char *noun)
{ {
//消除了函数<em>executeGo</em>中的循环,代码更优雅了~ //消除了函数*executeGo*中的循环,代码更优雅了~
OBJECT *obj = getVisible("where you want to go", noun); OBJECT *obj = getVisible("where you want to go", noun);
if (obj == NULL) if (obj == NULL)
{ {

View File

@@ -24,7 +24,7 @@
| 玩家从演员那里收到物品 | ask | silver->location = player; | | 玩家从演员那里收到物品 | ask | silver->location = player; |
| 列出其他演员的库存 | examine | listObjectsAtLocation(guard); | | 列出其他演员的库存 | examine | listObjectsAtLocation(guard); |
你可以尝试去使用这些命令(上面的前两个示例已经在上一章中实现了)。现在,我们将为玩家和非玩家角色介绍一些典型的<strong>物品栏</strong>操作(命令<em>获取</em>、<em>掉落</em>、<em>给予</em>、<em>询问</em>和<em>物品栏</em>)。 你可以尝试去使用这些命令(上面的前两个示例已经在上一章中实现了)。现在,我们将为玩家和非玩家角色介绍一些典型的**物品栏**操作(命令*获取*、*掉落*、*给予*、*询问*和*物品栏*)。
::: warning 🤔 思考题: ::: warning 🤔 思考题:
你能不能尝试自己实现一下上面的命令? 你能不能尝试自己实现一下上面的命令?
@@ -32,7 +32,7 @@
如果你可以在不参考下面内容的情况下就写出基本内容会有很大收获的 如果你可以在不参考下面内容的情况下就写出基本内容会有很大收获的
::: :::
## <strong>parsexec.c</strong> ## **parsexec.c**
```c ```c
#include <stdbool.h> #include <stdbool.h>
@@ -91,7 +91,7 @@ bool parseAndExecute(char *input)
新命令由以下模块实现。 新命令由以下模块实现。
## <strong>inventory.h</strong> ## **inventory.h**
```c ```c
extern void executeGet(const char *noun); extern void executeGet(const char *noun);
@@ -101,7 +101,7 @@ extern void executeGive(const char *noun);
extern void executeInventory(void); extern void executeInventory(void);
``` ```
## <strong>inventory.c</strong> ## **inventory.c**
```c ```c
#include <stdio.h> #include <stdio.h>
@@ -160,7 +160,7 @@ void executeInventory(void)
} }
``` ```
注意:由于动词名词比较好弄,命令 <em>ask</em> 和 <em>give</em> 只有一个参数item。 注意:由于动词名词比较好弄,命令 *ask**give* 只有一个参数item。
::: warning 🤔 思考题: ::: warning 🤔 思考题:
为什么我们要这样设计? 为什么我们要这样设计?
@@ -168,7 +168,7 @@ void executeInventory(void)
你能否为这些命令多加几个参数? 你能否为这些命令多加几个参数?
::: :::
从本质上讲,<em>get</em>, <em>drop</em>, <em>give</em> and <em>ask 这些命令</em>除了将项目从一个地方移动到另一个地方之外,什么都不做。单个函数 <em>move 对象</em>可以对所有四个命令执行该操作。 从本质上讲,*get*, *drop*, *give* and *ask 这些命令*除了将项目从一个地方移动到另一个地方之外,什么都不做。单个函数 *move 对象*可以对所有四个命令执行该操作。
## move.h ## move.h
@@ -229,7 +229,7 @@ void moveObject(OBJECT *obj, OBJECT *to)
::: warning 🤔 思考题:识别一些我们拿不了的物品需要考虑什么因素? ::: warning 🤔 思考题:识别一些我们拿不了的物品需要考虑什么因素?
::: :::
命令“get”使用函数<em>getVisible</em>将名词转换为 object就像命令“go”一样;请参阅上一章。但是对于对玩家(或其他一些参与者)已经持有的对象进行<em>drop</em>, <em>ask</em>, <em>give 等</em>命令时,我们需要稍微不同的东西。我们将在 <em>noun.c</em> 中添加一个函数 <em>getPossession</em> 命令“get”使用函数*getVisible*将名词转换为 object就像命令“go”一样;请参阅上一章。但是对于对玩家(或其他一些参与者)已经持有的对象进行*drop*, *ask*, *give 等*命令时,我们需要稍微不同的东西。我们将在 *noun.c* 中添加一个函数 *getPossession*
## noun.h ## noun.h
@@ -318,9 +318,9 @@ OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun)
} }
``` ```
注意新函数45-75 行) <em>getPossession</em> 是 <em>getObject</em> 的装饰器wrapper参见第 52 行),它要么返回匹配的对象,要么返回 NULL如果没有合适的对象与名词匹配 注意新函数45-75 行) *getPossession**getObject* 的装饰器wrapper参见第 52 行),它要么返回匹配的对象,要么返回 NULL如果没有合适的对象与名词匹配
函数 <em>actor 这里</em>用于命令 <em>give</em> 和 <em>ask</em>,但它也可能由其他命令调用。所以我们在<em>misc.c</em>中定义了它。 函数 *actor 这里*用于命令 *give**ask*,但它也可能由其他命令调用。所以我们在*misc.c*中定义了它。
## misc.h ## misc.h
@@ -370,7 +370,7 @@ int listObjectsAtLocation(OBJECT *location)
::: warning 🤔 思考题:上面第四行中的函数 actorHere 返回的指针指向什么? ::: warning 🤔 思考题:上面第四行中的函数 actorHere 返回的指针指向什么?
::: :::
在第 9 行中,有一个详尽的,硬编码的非玩家角色列表(到目前为止,只有一个:<em>守卫</em>)。 在第 9 行中,有一个详尽的,硬编码的非玩家角色列表(到目前为止,只有一个:*守卫*)。
在第 10 章中,我们将开始使用属性作为区分角色与项目和其他非参与者对象的更优雅方式。 在第 10 章中,我们将开始使用属性作为区分角色与项目和其他非参与者对象的更优雅方式。

View File

@@ -1,17 +1,17 @@
# 6.绘制地图 # 6.绘制地图
作为一个 RPG 游戏怎么能没有地图呢,<em>是时候绘制地图了!</em> 作为一个 RPG 游戏怎么能没有地图呢,*是时候绘制地图了!*
绘制地图的最佳工具始终是:一支铅笔和一张纸。基本地图由<strong>位置</strong>(矩形)组成,由道路(箭头)连接。我们已经在第 3 章中创建了位置,现在我们将开始添加道路。 绘制地图的最佳工具始终是:一支铅笔和一张纸。基本地图由**位置**(矩形)组成,由道路(箭头)连接。我们已经在第 3 章中创建了位置,现在我们将开始添加道路。
在虚拟世界中,“道路”可能是连接两个位置的任何东西:一条路,一扇门,沙漠中。基本上,一段经文具有以下属性: 在虚拟世界中,“道路”可能是连接两个位置的任何东西:一条路,一扇门,沙漠中。基本上,一段经文具有以下属性:
- 起点(位置)。 - 起点(位置)。
- 目标(位置)。 - 目标(位置)。
- 叙述性描述,例如“森林小径”。 - 叙述性描述,例如“森林小径”。
-<em>go</em> 命令中往哪里走的描述性标记 -*go* 命令中往哪里走的描述性标记
考虑到这些属性,第 4 章中定义的结构对象就非常适合存储道路了。事实上,一个道路与一个项目或 NPC 并没有太大的不同它作为“可见出口”存在于某个位置该位置是起点。它只是与某些命令的行为不同特别是命令“go”应用于道路<em>go</em>将改变玩家的位置。 考虑到这些属性,第 4 章中定义的结构对象就非常适合存储道路了。事实上,一个道路与一个项目或 NPC 并没有太大的不同它作为“可见出口”存在于某个位置该位置是起点。它只是与某些命令的行为不同特别是命令“go”应用于道路*go*将改变玩家的位置。
```c ```c
struct object { struct object {
@@ -24,9 +24,9 @@ struct object {
注意: 注意:
- 显然,<em>目的地</em>在大多数其他对象物品NPC中都没有使用 - 显然,*目的地*在大多数其他对象物品NPC中都没有使用
- 通道总是朝一个方向运行;要双向连接两个位置我们总是必须创建两个单独的通道。乍一看这似乎很笨拙但它确实给了我们很大的灵活性来完善命令“go”的行为 - 通道总是朝一个方向运行;要双向连接两个位置我们总是必须创建两个单独的通道。乍一看这似乎很笨拙但它确实给了我们很大的灵活性来完善命令“go”的行为
- 在大地图上,你可能会发现手动创建所有通道很乏味。所以,我强烈建议你使用自定义工具<em>生成</em>地图中重复性更强的部分。这里不会介绍这一点,但您可能会在第 9 章中找到一些灵感,我们将在其中讨论自动胜场。 - 在大地图上,你可能会发现手动创建所有通道很乏味。所以,我强烈建议你使用自定义工具*生成*地图中重复性更强的部分。这里不会介绍这一点,但您可能会在第 9 章中找到一些灵感,我们将在其中讨论自动胜场。
::: warning 🤔 思考题:为什么创建两个通道可以使我们的程序更加灵活? ::: warning 🤔 思考题:为什么创建两个通道可以使我们的程序更加灵活?
::: :::
@@ -75,7 +75,7 @@ OBJECT objs[] = {
}; };
``` ```
我们将在 <em>misc.c</em> 中添加一个小的帮助函数,以确定两个给定位置之间是否存在通道。 我们将在 *misc.c* 中添加一个小的帮助函数,以确定两个给定位置之间是否存在通道。
## misc.h ## misc.h
@@ -139,7 +139,7 @@ int listObjectsAtLocation(OBJECT *location)
} }
``` ```
我们将在命令“go”的实现中使用新功能<em>getPassage</em>来确定是否存在可以将玩家带到所需位置的通道。 我们将在命令“go”的实现中使用新功能*getPassage*来确定是否存在可以将玩家带到所需位置的通道。
## location.h ## location.h
@@ -201,7 +201,7 @@ void executeGo(const char *noun)
} }
``` ```
我们还将使用新功能<em>getPassage</em>来确定从玩家站立的位置是否可以看到某个位置。未通过通道连接到当前位置的位置不被视为可见。 我们还将使用新功能*getPassage*来确定从玩家站立的位置是否可以看到某个位置。未通过通道连接到当前位置的位置不被视为可见。
## noun.h ## noun.h

View File

@@ -1,23 +1,23 @@
# 7.增大距离 # 7.增大距离
<em>一个典型的冒险包含许多谜题。</em><em>众所周知,[Infocom](https://en.wikipedia.org/wiki/Infocom)</em><em>的冒险很难完成。解决每个难题可能需要数周甚至数月的反复试验。</em> *一个典型的冒险包含许多谜题。众所周知,[Infocom](https://en.wikipedia.org/wiki/Infocom)的冒险很难完成。解决每个难题可能需要数周甚至数月的反复试验。*
<em>当玩家操纵角色失败后,如果只是返回“你</em><em>不能这么操作</em><em>”来回应玩家</em><em>,会很 nt很没意思</em><em>。</em> *当玩家操纵角色失败后,如果只是返回“你不能这么操作”来回应玩家,会很 nt很没意思。*
<em>它忽略了</em><em>电脑</em><em>游戏的一个重要方面,而这也是生活本身的一部分:玩家必须从错误中吸取教训。</em> *它忽略了电脑游戏的一个重要方面,而这也是生活本身的一部分:玩家必须从错误中吸取教训。*
当你的游戏反复输入东西都是,你不能这样做的时候,会显得很无聊的。 当你的游戏反复输入东西都是,你不能这样做的时候,会显得很无聊的。
<em>冒险游戏至少应该做的是解释为什么玩家的命令无法完成:“你不能这样做,因为......”这有助于使虚拟世界更具说服力,故事更可信,游戏更有趣。</em> *冒险游戏至少应该做的是解释为什么玩家的命令无法完成:“你不能这样做,因为......”这有助于使虚拟世界更具说服力,故事更可信,游戏更有趣。*
我们已经付出了相当大的努力让游戏解释<strong>为什么</strong>某些命令是无效的。只需看看<em>名词.cinventory.clocation.c</em><em>move.c</em>中的许多<em>printf</em>调用。但随着游戏变得越来越复杂,这正成为一个相当大的负担。我们需要一种更结构化的方法来检测和处理错误情况。这就是我们在本章中将要讨论的内容。 我们已经付出了相当大的努力让游戏解释**为什么**某些命令是无效的。只需看看*名词.cinventory.clocation.c**move.c*中的许多*printf*调用。但随着游戏变得越来越复杂,这正成为一个相当大的负担。我们需要一种更结构化的方法来检测和处理错误情况。这就是我们在本章中将要讨论的内容。
大多数命令对一个或多个对象进行操作,例如: 大多数命令对一个或多个对象进行操作,例如:
- 玩家拿起一件物品,然后把它交给另一个 NPC。 - 玩家拿起一件物品,然后把它交给另一个 NPC。
- 玩家沿着一条通道到另一个位置。 - 玩家沿着一条通道到另一个位置。
首先要检查的(在[解析器](http://en.wikipedia.org/wiki/Parsing)捕获检测是否会有明显[拼写错误](http://en.wikipedia.org/wiki/Typographical_error)之后)是这些对象<strong>是否存在</strong>; 首先要检查的(在[解析器](http://en.wikipedia.org/wiki/Parsing)捕获检测是否会有明显[拼写错误](http://en.wikipedia.org/wiki/Typographical_error)之后)是这些对象**是否存在**;
失败应该导致类似“这里没有...“或”你看不到任何东西...”等文字出现。在本章中,我们将构建一个通用函数,每个命令都可以使用它来找出玩家是否在可及的范围内。 失败应该导致类似“这里没有...“或”你看不到任何东西...”等文字出现。在本章中,我们将构建一个通用函数,每个命令都可以使用它来找出玩家是否在可及的范围内。
@@ -38,7 +38,7 @@
| distHereContained | 一个物体NPC 或“容器”)存在于玩家的位置,正在拿着另一个物体 | object->location != NULL &&<br/>object->location->location == player->location | | distHereContained | 一个物体NPC 或“容器”)存在于玩家的位置,正在拿着另一个物体 | object->location != NULL &&<br/>object->location->location == player->location |
| distOverthere | 对象是附近的位置 | getPassage(player->location, object) != NULL | | distOverthere | 对象是附近的位置 | getPassage(player->location, object) != NULL |
第一种情况对象是玩家可能看起来微不足道但它仍然很重要。例如命令“examine yourself”<em>不应该</em>返回“这里没有你自己”。 第一种情况对象是玩家可能看起来微不足道但它仍然很重要。例如命令“examine yourself”*不应该*返回“这里没有你自己”。
我试图遵循一个逻辑顺序:附近的事物最高优先级,随后优先级会变低。 我试图遵循一个逻辑顺序:附近的事物最高优先级,随后优先级会变低。
@@ -48,7 +48,7 @@
请注意,我们有七种不同的“这里”案例,但只有一种是“不在这里”。这是因为通常,游戏只需要提供有关玩家可以感知的事物的信息。如果它不在这里,那么就没什么可说的了。 请注意,我们有七种不同的“这里”案例,但只有一种是“不在这里”。这是因为通常,游戏只需要提供有关玩家可以感知的事物的信息。如果它不在这里,那么就没什么可说的了。
在最左边的列中,我们为每个案例提出了一个符号名称。我们将在名为 <strong>DISTANCE</strong> 的[枚举](http://en.wikipedia.org/wiki/Enumerated_type)中收集这些名称。 在最左边的列中,我们为每个案例提出了一个符号名称。我们将在名为 **DISTANCE** 的[枚举](http://en.wikipedia.org/wiki/Enumerated_type)中收集这些名称。
```c ```c
typedef enum { typedef enum {
@@ -91,7 +91,7 @@ DISTANCE getDistance(OBJECT *from, OBJECT *to)
注:自行实验即可 注:自行实验即可
::: :::
就这样!我们可以调用此函数并对其返回值进行比较。例如,我们在 noun<em>.c</em>中有以下代码: 就这样!我们可以调用此函数并对其返回值进行比较。例如,我们在 noun*.c*中有以下代码:
```c ```c
else if (!(obj == player || else if (!(obj == player ||
@@ -125,9 +125,9 @@ else if (getDistance(player, obj) >= distNotHere)
::: warning 🤔 尝试理解一下这样做的意义 ::: warning 🤔 尝试理解一下这样做的意义
::: :::
这只是一个例子,让你对这个概念有所了解;您将在下面找到<em>noun.c</em>的实际实现,看起来略有不同。 这只是一个例子,让你对这个概念有所了解;您将在下面找到*noun.c*的实际实现,看起来略有不同。
是时候把事情落实到位了。枚举 <em>DISTANCE</em> 和函数 <em>getDistance</em> 的定义被添加到 <em>misc.h</em> 和 <em>misc.c</em> 中,因为我们将在多个模块中使用它们。 是时候把事情落实到位了。枚举 *DISTANCE* 和函数 *getDistance* 的定义被添加到 *misc.h**misc.c* 中,因为我们将在多个模块中使用它们。
## misc.h ## misc.h
@@ -237,7 +237,7 @@ extern void executeLook(const char *noun);
extern void executeGo(const char *noun); extern void executeGo(const char *noun);
``` ```
在函数 <em>executeGo</em> 中,我们可以用检查距离来替换大多数 <em>if</em> 条件。 在函数 *executeGo* 中,我们可以用检查距离来替换大多数 *if* 条件。
## location.c ## location.c
@@ -297,9 +297,9 @@ void executeGo(const char *noun)
::: warning 🤔 思考题:你能否为 switch 函数增加更多 case 来完善判断条件? ::: warning 🤔 思考题:你能否为 switch 函数增加更多 case 来完善判断条件?
::: :::
函数 <em>executeGet</em> 也是如此。 函数 *executeGet* 也是如此。
## <strong>inventory.h</strong> ## **inventory.h**
```c ```c
extern void executeGet(const char *noun); extern void executeGet(const char *noun);
@@ -309,7 +309,7 @@ extern void executeGive(const char *noun);
extern void executeInventory(void); extern void executeInventory(void);
``` ```
## <strong>inventory.c</strong> ## **inventory.c**
```c ```c
#include <stdbool.h> #include <stdbool.h>
@@ -372,7 +372,7 @@ void executeInventory(void)
} }
``` ```
最后,我们将调整 noun<em>.c</em>中的约束。我们正在向函数<em>getObject</em>添加两个参数,以便找到特定名词的匹配项,同时忽略任何被认为不存在的对象。这将在下一章中得到真正的回报,我们将在下一章中介绍具有相同标签的不同对象。 最后,我们将调整 noun*.c*中的约束。我们正在向函数*getObject*添加两个参数,以便找到特定名词的匹配项,同时忽略任何被认为不存在的对象。这将在下一章中得到真正的回报,我们将在下一章中介绍具有相同标签的不同对象。
## noun.h ## noun.h
@@ -463,7 +463,7 @@ OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun)
::: warning 🤔 思考题:你能理解什么时候加 const什么时候不用吗 ::: warning 🤔 思考题:你能理解什么时候加 const什么时候不用吗
::: :::
在本章中,<em>距离</em>的概念主要用于在游戏可以给用户的不同响应之间进行选择。但是,距离的好处并不局限于<strong>输出</strong>端;它可以同样很好地用于在<strong>输入</strong>端进行改进。在下一章中,我们将使用距离来提高对用户输入的名词的识别。 在本章中,*距离*的概念主要用于在游戏可以给用户的不同响应之间进行选择。但是,距离的好处并不局限于**输出**端;它可以同样很好地用于在**输入**端进行改进。在下一章中,我们将使用距离来提高对用户输入的名词的识别。
输出样例 输出样例

View File

@@ -1,8 +1,8 @@
# 8.移动方向 # 8.移动方向
<em>传统的文本冒险使用</em><em>[指南针方向](https://en.wikipedia.org/wiki/Cardinal_direction)</em><em>进行导航。</em> *传统的文本冒险使用[指南针方向](https://en.wikipedia.org/wiki/Cardinal_direction)进行导航。*
例如,我们在第 6 章中绘制的地图上,玩家可能想<strong>向东</strong>移动,从田野移动到洞穴。我们可以通过给连接<strong>Cave</strong>的通道标上“east”来实现这一点。但是我们首先需要解决两个问题。 例如,我们在第 6 章中绘制的地图上,玩家可能想**向东**移动,从田野移动到洞穴。我们可以通过给连接**Cave**的通道标上“east”来实现这一点。但是我们首先需要解决两个问题。
1. 我们可能仍然想把这段通道称为“entrance”和“east”。但现在一个对象只能有一个标签。 1. 我们可能仍然想把这段通道称为“entrance”和“east”。但现在一个对象只能有一个标签。
2. 在更大的地图上具有更多的位置和道路标签“east”将被定义多次。到目前为止标签在我们的游戏中是全球独一无二的没有重复项。 2. 在更大的地图上具有更多的位置和道路标签“east”将被定义多次。到目前为止标签在我们的游戏中是全球独一无二的没有重复项。
@@ -80,9 +80,9 @@ OBJECT objs[] = {
}; };
``` ```
当然,要让这个改动生效,我们还需要调整<em>noun.c</em>中的<em>objectHasTag</em>函数。 当然,要让这个改动生效,我们还需要调整*noun.c*中的*objectHasTag*函数。
<em>同时,我们将让函数 getVisible</em>和<em>getPossession</em> 告知玩家他必须更具体的选择你到底是银币还是金币,而不是随机选择任何一个对象。 *同时,我们将让函数 getVisible*和*getPossession* 告知玩家他必须更具体的选择你到底是银币还是金币,而不是随机选择任何一个对象。
## noun.h ## noun.h
@@ -91,7 +91,7 @@ extern OBJECT *getVisible(const char *intention, const char *noun);
extern OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun); extern OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun);
``` ```
## <strong>noun.c</strong> ## **noun.c**
```c ```c
#include <stdbool.h> #include <stdbool.h>
@@ -188,7 +188,7 @@ OBJECT *getPossession(OBJECT *from, const char *verb, const char *noun)
} }
``` ```
问题 #3 可以通过从函数<em>parseAndExecute</em>中删除一个 [空格](http://en.wikipedia.org/wiki/Space_(punctuation))字符来解决(下面的第 10 行)。这个解决方案远非完美('silver' 和 'coin' 之间的双空格是打咩的),但直到我们在第 13 章中让自己成为一个更好的解析器之前。 问题 #3 可以通过从函数*parseAndExecute*中删除一个 [空格](http://en.wikipedia.org/wiki/Space_(punctuation))字符来解决(下面的第 10 行)。这个解决方案远非完美('silver' 和 'coin' 之间的双空格是打咩的),但直到我们在第 13 章中让自己成为一个更好的解析器之前。
## parsexec.c ## parsexec.c
@@ -246,9 +246,9 @@ bool parseAndExecute(char *input)
} }
``` ```
模块<em>main.c</em>、<em>inventory.c</em>、<em>location.c</em>、<em>move.c</em> 和<em>misc.c</em>保持不变 模块*main.c*、*inventory.c*、*location.c*、*move.c* 和*misc.c*保持不变
现在对象数组 ( <em>object.c</em> ) 开始在多个维度上增长(特别是在引入多个标签的情况下),我们需要一种使其更易于维护的方法。 现在对象数组 ( *object.c* ) 开始在多个维度上增长(特别是在引入多个标签的情况下),我们需要一种使其更易于维护的方法。
::: warning 🤔 猜猜看该怎么办? ::: warning 🤔 猜猜看该怎么办?
::: :::

View File

@@ -2,9 +2,9 @@
## 前言 ## 前言
本来打算让各位做下面的任务来进行进一步的学习的,但是想了想,实在是,<strong>太无聊啦</strong> 本来打算让各位做下面的任务来进行进一步的学习的,但是想了想,实在是,**太无聊啦**
又想让你们来做一个管理系统,但是又想到你们可能会进行无数个管理系统,<strong>这也太无聊啦</strong> 又想让你们来做一个管理系统,但是又想到你们可能会进行无数个管理系统,**这也太无聊啦**
因此呢,我打算带大家玩一个文字冒险游戏![源头取自这里](https://github.com/helderman/htpataic),如果你想自己体验全流程的话可以试试玩哦! 因此呢,我打算带大家玩一个文字冒险游戏![源头取自这里](https://github.com/helderman/htpataic),如果你想自己体验全流程的话可以试试玩哦!
@@ -32,7 +32,7 @@
在这种情况下,系统能跑起来才是王道,跑不起来什么都是浮云,追求面面俱到只会增加代码维护的难度。 在这种情况下,系统能跑起来才是王道,跑不起来什么都是浮云,追求面面俱到只会增加代码维护的难度。
唯一可以把你从 bug 的混沌中拯救出来的就是 KISS 法则,它的宗旨是<strong>从易到难,逐步推进</strong>, 一次只做一件事,少做无关的事。 唯一可以把你从 bug 的混沌中拯救出来的就是 KISS 法则,它的宗旨是**从易到难,逐步推进**, 一次只做一件事,少做无关的事。
如果你不知道这是什么意思,我们以可能发生的 `str` 成员缓冲区溢出问题来作为例子。KISS 法则告诉你,你应该使用 `assert(0)`, 就算不"得体"地处理上述问题,仍然不会影响表达式求值的核心功能的正确性。 如果你不知道这是什么意思,我们以可能发生的 `str` 成员缓冲区溢出问题来作为例子。KISS 法则告诉你,你应该使用 `assert(0)`, 就算不"得体"地处理上述问题,仍然不会影响表达式求值的核心功能的正确性。

View File

@@ -16,7 +16,7 @@
[GDB 快速入门教程](https://www.bilibili.com/video/BV1EK411g7Li/) [GDB 快速入门教程](https://www.bilibili.com/video/BV1EK411g7Li/)
### <strong>GDB 使用表</strong> ### **GDB 使用表**
`run (r)`运行程序 `run (r)`运行程序
@@ -50,7 +50,7 @@
`ptype`查看详细信息 `ptype`查看详细信息
#### <strong>TUI</strong> #### **TUI**
`ctrl + x + a`开启 `ctrl + x + a`开启

View File

@@ -20,7 +20,7 @@ C 艹可能没那么容易了····比如说虚函数调用,那你就不太
你可以写任何一个指令,他完全不会检查 也不会优化 编译器默认你知道你在干什么。 你可以写任何一个指令,他完全不会检查 也不会优化 编译器默认你知道你在干什么。
然后 C 编译器就会将这部分代码 <strong>原封不动地 </strong>拷贝进你的二进制代码当中 然后 C 编译器就会将这部分代码 **原封不动地**拷贝进你的二进制代码当中
当然,你可以通过 RTFM 来将 C 语言的变量塞到汇编中处理。 当然,你可以通过 RTFM 来将 C 语言的变量塞到汇编中处理。

View File

@@ -2,7 +2,7 @@
引自 nju-ics-pa 引自 nju-ics-pa
## <strong>光玉</strong> ## **光玉**
想象一下你正在玩 Flappy Bird你今晚的目标是拿到 100 分,不然就不睡觉。经过千辛万苦,你拿到了 99 分,就要看到成功的曙光的时候,你竟然失手了!你悲痛欲绝,滴血的心在呼喊着,“为什么上天要这样折磨我?为什么不让我存档?” 想象一下你正在玩 Flappy Bird你今晚的目标是拿到 100 分,不然就不睡觉。经过千辛万苦,你拿到了 99 分,就要看到成功的曙光的时候,你竟然失手了!你悲痛欲绝,滴血的心在呼喊着,“为什么上天要这样折磨我?为什么不让我存档?”
@@ -10,7 +10,7 @@
想象一下你正在写代码,你今晚的目标是实现某一个新功能,不然就不睡觉。经过千辛万苦,你终于把代码写好了,保存并编译运行,你看到调试信息一行一行地在终端上输出。就要看到成功的曙光的时候,竟然发生了错误!你仔细思考,发现你之前的构思有着致命的错误,但之前正确运行的代码已经永远离你而去了。你悲痛欲绝,滴血的心在呼喊着,“为什么上天要这样折磨我?”你绝望地倒在屏幕前 ... ... 这时,你发现身边渐渐出现无数的光玉,把你包围起来,耀眼的光芒令你无法睁开眼睛 ... ... 等到你回过神来,你发现屏幕上正是那份之前正确运行的代码!但在你的记忆中,你确实经历过那悲痛欲绝的时刻 ... ... 这一切真是不可思议啊 ... ... 想象一下你正在写代码,你今晚的目标是实现某一个新功能,不然就不睡觉。经过千辛万苦,你终于把代码写好了,保存并编译运行,你看到调试信息一行一行地在终端上输出。就要看到成功的曙光的时候,竟然发生了错误!你仔细思考,发现你之前的构思有着致命的错误,但之前正确运行的代码已经永远离你而去了。你悲痛欲绝,滴血的心在呼喊着,“为什么上天要这样折磨我?”你绝望地倒在屏幕前 ... ... 这时,你发现身边渐渐出现无数的光玉,把你包围起来,耀眼的光芒令你无法睁开眼睛 ... ... 等到你回过神来,你发现屏幕上正是那份之前正确运行的代码!但在你的记忆中,你确实经历过那悲痛欲绝的时刻 ... ... 这一切真是不可思议啊 ... ...
## <strong>人生如戏</strong><strong></strong><strong>戏如人生</strong> ## **人生如戏********戏如人生**
人生就像不能重玩的 Flappy Bird但软件工程领域却并非如此而那不可思议的光玉就是“版本控制系统”。版本控制系统给你的开发流程提供了比朋也收集的更强大的光玉能够让你在过去和未来中随意穿梭避免上文中的悲剧降临你的身上。 人生就像不能重玩的 Flappy Bird但软件工程领域却并非如此而那不可思议的光玉就是“版本控制系统”。版本控制系统给你的开发流程提供了比朋也收集的更强大的光玉能够让你在过去和未来中随意穿梭避免上文中的悲剧降临你的身上。
@@ -18,7 +18,7 @@
在本节,我们使用 `git` 进行版本控制。下面简单介绍如何使用 `git` 在本节,我们使用 `git` 进行版本控制。下面简单介绍如何使用 `git`
### <strong>游戏设置</strong> ### **游戏设置**
首先你得安装 `git` : 首先你得安装 `git` :
@@ -52,7 +52,7 @@ git init
进行初始化。初始化后会创建一个隐藏的文件夹名为 `.git` git 会基于这个文件夹来进行版本控制功能。 进行初始化。初始化后会创建一个隐藏的文件夹名为 `.git` git 会基于这个文件夹来进行版本控制功能。
### <strong>查看</strong><strong>commit</strong><strong>信息</strong> ### **查看****commit****信息**
使用 使用
@@ -147,7 +147,7 @@ subject为commit概述
你可以使用 `git log` 查看存档记录,你应该能看到刚才编辑的注释。 你可以使用 `git log` 查看存档记录,你应该能看到刚才编辑的注释。
### <strong>读档</strong><strong>(回溯到某一个 commit</strong> ### **读档****(回溯到某一个 commit**
如果你遇到了上文提到的让你悲痛欲绝的情况,现在你可以使用光玉来救你一命了。首先使用 `git log` 来查看已有的存档,并决定你需要回到哪个过去。每一份存档都有一个 `hash code`,例如 `b87c512d10348fd8f1e32ddea8ec95f87215aaa5` , 你需要通过 `hash code` 来告诉 `git` 你希望读哪一个档。使用以下命令进行读档: 如果你遇到了上文提到的让你悲痛欲绝的情况,现在你可以使用光玉来救你一命了。首先使用 `git log` 来查看已有的存档,并决定你需要回到哪个过去。每一份存档都有一个 `hash code`,例如 `b87c512d10348fd8f1e32ddea8ec95f87215aaa5` , 你需要通过 `hash code` 来告诉 `git` 你希望读哪一个档。使用以下命令进行读档:
@@ -194,7 +194,7 @@ git checkout -B 分支名
不同的分支之间不会相互干扰,这也给项目的分布式开发带来了便利。有了分支功能,你就可以像第三视点那样在一个世界的不同时间 ( 一个分支的多个存档 ),或者是多个平行世界(多个分支)之间来回穿梭了。 不同的分支之间不会相互干扰,这也给项目的分布式开发带来了便利。有了分支功能,你就可以像第三视点那样在一个世界的不同时间 ( 一个分支的多个存档 ),或者是多个平行世界(多个分支)之间来回穿梭了。
### <strong>更多功能</strong> ### **更多功能**
以上介绍的是 `git` 的一些基本功能,`git` 还提供很多强大的功能,例如使用 `git diff` 比较同一个文件在不同版本中的区别,使用 `git bisect` 进行二分搜索来寻找一个 bug 在哪次提交中被引入... 以上介绍的是 `git` 的一些基本功能,`git` 还提供很多强大的功能,例如使用 `git diff` 比较同一个文件在不同版本中的区别,使用 `git bisect` 进行二分搜索来寻找一个 bug 在哪次提交中被引入...
@@ -252,7 +252,7 @@ git checkout -B 分支名
如果有就直接跳过这一步 如果有就直接跳过这一步
如果没有,打开 ShellWindows 下打开 Git Bash <em>前提是你已经安装好了 git 在桌面右键应该会有 Git bash here 选项 </em>),创建 SSH Key 如果没有,打开 ShellWindows 下打开 Git Bash *前提是你已经安装好了 git 在桌面右键应该会有 Git bash here 选项 *),创建 SSH Key
```bash ```bash
ssh-keygen -t rsa -C "youremail@example.com" # youremail为你注册用的电子邮件地址 ssh-keygen -t rsa -C "youremail@example.com" # youremail为你注册用的电子邮件地址

View File

@@ -4,7 +4,7 @@
## 什么是环境? ## 什么是环境?
环境是<strong>包的集合</strong>,我们一般用 Anaconda 来配置虚拟环境。 环境是**包的集合**,我们一般用 Anaconda 来配置虚拟环境。
[戳这里安装](https://www.anaconda.com/) [戳这里安装](https://www.anaconda.com/)

View File

@@ -27,11 +27,11 @@
打开 [Python 官方网站](https://www.python.org/)找到“Download”里的“Latest: Python 3.x.y”。 打开 [Python 官方网站](https://www.python.org/)找到“Download”里的“Latest: Python 3.x.y”。
<strong>下载完成后请大家按照下图的示意务必勾选“Add Python 3.x to PATH”然后再点击“Install Now”等待安装完成后关闭安装程序。</strong> **下载完成后请大家按照下图的示意务必勾选“Add Python 3.x to PATH”然后再点击“Install Now”等待安装完成后关闭安装程序。**
<strong>注意windows11 安装好后 命令行输入 python 可能会跳到 Microsoft 应用商店 可在 customize installation自定义安装next 勾选 install for all users</strong> **注意windows11 安装好后 命令行输入 python 可能会跳到 Microsoft 应用商店 可在 customize installation自定义安装next 勾选 install for all users**
<font size=5><strong>GNU/Linux 系统</strong></font> <font size=5>**GNU/Linux 系统**</font>
在终端输入 `sudo apt install python3` 即可完成 Python3 的全部安装流程 在终端输入 `sudo apt install python3` 即可完成 Python3 的全部安装流程

View File

@@ -135,9 +135,9 @@ s
可变对象的示例包括列表和字典。不可变对象的示例包括元组和函数。 可变对象的示例包括列表和字典。不可变对象的示例包括元组和函数。
我们假定已经知道了如何使用 `==` 运算符来检查两个表达式的计算结果是否<strong>相同</strong> 我们假定已经知道了如何使用 `==` 运算符来检查两个表达式的计算结果是否**相同**
我们现在引入一个新的比较运算符 `is`,它检查两个表达式的计算结果是否<strong>相同</strong> 我们现在引入一个新的比较运算符 `is`,它检查两个表达式的计算结果是否**相同**
```python ```python
>>> 2 + 2 == 3 + 1 >>> 2 + 2 == 3 + 1

View File

@@ -37,7 +37,7 @@ iterator = iter(iterable)
# do something # do something
``` ```
- 首先,在可迭代对象上调用内置 `iter` 函数以创建对应的<em>迭代器</em> - 首先,在可迭代对象上调用内置 `iter` 函数以创建对应的*迭代器*
- 要获取序列中的下一个元素,在此迭代器上调用内置 `next` 函数。 - 要获取序列中的下一个元素,在此迭代器上调用内置 `next` 函数。
如果没有下一个元素了,怎么办? 如果没有下一个元素了,怎么办?
@@ -76,7 +76,7 @@ StopIteration
## 英语练习,对迭代器的类比 ## 英语练习,对迭代器的类比
<strong>Analogy</strong>: An iterable is like a book (one can flip through the pages) and an iterator for a book would be a bookmark (saves the position and can locate the next page). Calling `iter` on a book gives you a new bookmark independent of other bookmarks, but calling `iter` on a bookmark gives you the bookmark itself, without changing its position at all. Calling `next` on the bookmark moves it to the next page, but does not change the pages in the book. Calling `next` on the book wouldn't make sense semantically. We can also have multiple bookmarks, all independent of each other. **Analogy**: An iterable is like a book (one can flip through the pages) and an iterator for a book would be a bookmark (saves the position and can locate the next page). Calling `iter` on a book gives you a new bookmark independent of other bookmarks, but calling `iter` on a bookmark gives you the bookmark itself, without changing its position at all. Calling `next` on the bookmark moves it to the next page, but does not change the pages in the book. Calling `next` on the book wouldn't make sense semantically. We can also have multiple bookmarks, all independent of each other.
## 生成器:懒人迭代器! ## 生成器:懒人迭代器!

View File

@@ -1,6 +1,6 @@
# CS61A Sec1 # CS61A Sec1
<strong>观前须知:</strong> **观前须知:**
本章节内容基于 Berkeley 大学的教材 [Composing Programs](http://www.composingprograms.com/) by [John DeNero](http://www.denero.org/),并在此基础上做了部分修改,是在[知识共享协议](https://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh)下所许可的。 本章节内容基于 Berkeley 大学的教材 [Composing Programs](http://www.composingprograms.com/) by [John DeNero](http://www.denero.org/),并在此基础上做了部分修改,是在[知识共享协议](https://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh)下所许可的。
@@ -28,7 +28,7 @@ from urllib.request import urlopen
这个 Python 代码是一个导入语句,加载了在互联网上访问数据的功能。实际上,它提供了一个叫做 urlopen 的函数,它可以在一个[统一资源定位符URL](https://developer.mozilla.org/zh-CN/docs/Learn/Common_questions/Web_mechanics/What_is_a_URL)上访问内容,可以通过它来访问互联网上的数据。 这个 Python 代码是一个导入语句,加载了在互联网上访问数据的功能。实际上,它提供了一个叫做 urlopen 的函数,它可以在一个[统一资源定位符URL](https://developer.mozilla.org/zh-CN/docs/Learn/Common_questions/Web_mechanics/What_is_a_URL)上访问内容,可以通过它来访问互联网上的数据。
<strong>语句和表达式</strong> **语句和表达式**
Python 代码由语句和表达式组成。大体上,计算机程序由以下指令组成 Python 代码由语句和表达式组成。大体上,计算机程序由以下指令组成
@@ -37,7 +37,7 @@ Python 代码由语句和表达式组成。大体上,计算机程序由以下
语句通常描述行动;当 Python 解释器执行一个语句时,它执行相应的动作。另一方面,表达式通常描述的是计算;当 Python 评估一个表达式时,它计算该表达式的值。在这篇文章下,介绍了几种类型的声明和表达方式。 语句通常描述行动;当 Python 解释器执行一个语句时,它执行相应的动作。另一方面,表达式通常描述的是计算;当 Python 评估一个表达式时,它计算该表达式的值。在这篇文章下,介绍了几种类型的声明和表达方式。
<strong>赋值语句</strong> **赋值语句**
```python ```python
shakespeare = urlopen('http://www.composingprograms.com/shakespeare.txt') shakespeare = urlopen('http://www.composingprograms.com/shakespeare.txt')
@@ -47,7 +47,7 @@ shakespeare = urlopen('http://www.composingprograms.com/shakespeare.txt')
将变量名 `shakespeare``=` 和后面的表达式的值联系起来。该表达式将 `urlopen` 函数应用于一个 URL该 URL 包含威廉 - 莎士比亚 37 部戏剧的完整文本,全部保存在一个文本文件中。 将变量名 `shakespeare``=` 和后面的表达式的值联系起来。该表达式将 `urlopen` 函数应用于一个 URL该 URL 包含威廉 - 莎士比亚 37 部戏剧的完整文本,全部保存在一个文本文件中。
<strong>函数</strong> **函数**
函数封装了操作数据的逻辑。 函数封装了操作数据的逻辑。
@@ -64,7 +64,7 @@ shakespeare = urlopen('http://www.composingprograms.com/shakespeare.txt')
你可能不了解 `urlopen` 这个函数背后的逻辑,但这不影响你去调用这个函数,这就是函数封装的好处之一。 你可能不了解 `urlopen` 这个函数背后的逻辑,但这不影响你去调用这个函数,这就是函数封装的好处之一。
<strong>因此,函数是本章节关注的重点。</strong> **因此,函数是本章节关注的重点。**
我们来看另一个赋值语句: 我们来看另一个赋值语句:
@@ -74,7 +74,7 @@ words = set(shakespeare.read().decode().split())
这个语句将名字词与莎士比亚戏剧中出现的所有出现过的词(重复出现的词只统计一次)的集合联系起来,其中有 33,721(?) 个词。上述语句包含一个读取、解码和分割的命令链,每个命令都在一个中间计算实体上操作:我们从打开的 URL 中读取数据然后将数据解码成文本最后将文本分割成单词。所有这些词都被放在一个集合SetPython 中的一种数据类型)中。 这个语句将名字词与莎士比亚戏剧中出现的所有出现过的词(重复出现的词只统计一次)的集合联系起来,其中有 33,721(?) 个词。上述语句包含一个读取、解码和分割的命令链,每个命令都在一个中间计算实体上操作:我们从打开的 URL 中读取数据然后将数据解码成文本最后将文本分割成单词。所有这些词都被放在一个集合SetPython 中的一种数据类型)中。
<strong>对象</strong> **对象**
前文中提到的 Set不仅仅是数据类型也是一个对象。对象用一种能同时处理两者复杂性的方式把数据和操作该数据的逻辑无缝衔接在一起。 前文中提到的 Set不仅仅是数据类型也是一个对象。对象用一种能同时处理两者复杂性的方式把数据和操作该数据的逻辑无缝衔接在一起。
@@ -91,7 +91,7 @@ words = set(shakespeare.read().decode().split())
这是一个复合表达式,其值是所有长度为 6 的、本身和反向拼写都在原集合中的词组成的集合。其中的 `w[::-1]` 是一种隐式表达,它枚举了 `w` 中的所有字母,但因为 `step = -1` 规定了步长是反方向的。 这是一个复合表达式,其值是所有长度为 6 的、本身和反向拼写都在原集合中的词组成的集合。其中的 `w[::-1]` 是一种隐式表达,它枚举了 `w` 中的所有字母,但因为 `step = -1` 规定了步长是反方向的。
<strong>解释器</strong> **解释器**
计算复合表达式需要一个精确的程序,以可预测的方式解释代码。一个能实现程序和计算符合表达式的程序被称为解释器;没错,其实解释器是程序(可能再写一篇文章来讲讲解释器和编译器的区别?) 计算复合表达式需要一个精确的程序,以可预测的方式解释代码。一个能实现程序和计算符合表达式的程序被称为解释器;没错,其实解释器是程序(可能再写一篇文章来讲讲解释器和编译器的区别?)
@@ -109,9 +109,9 @@ words = set(shakespeare.read().decode().split())
每种强大的语言都有三种这样的机制: 每种强大的语言都有三种这样的机制:
- <strong>原始的表达式和语句</strong>,代表了该语言提供的最简单的构建模块。 - **原始的表达式和语句**,代表了该语言提供的最简单的构建模块。
- <strong>组合的方式</strong>,由较简单的元素建立成复合元素。 - **组合的方式**,由较简单的元素建立成复合元素。
- <strong>抽象的手段</strong>,通过它,复合元素可以作为单位被命名和操作。 - **抽象的手段**,通过它,复合元素可以作为单位被命名和操作。
在编程中,我们处理两种元素:函数和数据。(很快就会发现,它们其实并不那么明显)。不那么正式地说,数据是我们想要操作的东西,而函数描述了操作数据的规则。因此,任何强大的编程语言都应该能够描述原始数据和原始函数,以及有一些方法来组合和抽象函数和数据。 在编程中,我们处理两种元素:函数和数据。(很快就会发现,它们其实并不那么明显)。不那么正式地说,数据是我们想要操作的东西,而函数描述了操作数据的规则。因此,任何强大的编程语言都应该能够描述原始数据和原始函数,以及有一些方法来组合和抽象函数和数据。
@@ -133,20 +133,20 @@ words = set(shakespeare.read().decode().split())
0.9921875 0.9921875
``` ```
这些数学表达式使用<em>中缀</em>符号,其中<em>运算符</em>(例如,+-*,或/)出现在<em>操作数</em>数字之间。Python 包括许多形成复合表达式的方法。我们不会试图立即列举它们,而是会随着我们的学习引入新的表达形式,以及它们所支持的语言特性。 这些数学表达式使用*中缀*符号,其中*运算符*(例如,+-*,或/)出现在*操作数*数字之间。Python 包括许多形成复合表达式的方法。我们不会试图立即列举它们,而是会随着我们的学习引入新的表达形式,以及它们所支持的语言特性。
最重要的一种复合表达式是<em>调用表达式</em>它将一个函数应用于一些参数。回顾一下代数函数的数学概念是一个从一些自变量到因变量的映射。例如一个求最大值的函数将其的多个输入映射到当中最大值的一个单一的输出。Python 表达函数应用的方式与传统数学中相同。 最重要的一种复合表达式是*调用表达式*它将一个函数应用于一些参数。回顾一下代数函数的数学概念是一个从一些自变量到因变量的映射。例如一个求最大值的函数将其的多个输入映射到当中最大值的一个单一的输出。Python 表达函数应用的方式与传统数学中相同。
```python ```python
>>> max(7.5, 9.5) >>> max(7.5, 9.5)
9.5 9.5
``` ```
这个调用表达式有子表达式:<em>操作符</em>是括号前的表达式,它包含了一个用逗号分隔的<em>操作数</em>列表。 这个调用表达式有子表达式:*操作符*是括号前的表达式,它包含了一个用逗号分隔的*操作数*列表。
![](https://cdn.xyxsw.site/call_expression.png) ![](https://cdn.xyxsw.site/call_expression.png)
运算符指定了一个<em>函数</em>。当这个调用表达式被评估时,我们说对<em>参数</em>`7.5``9.5`<em>调用</em>函数 `max`,并<em>返回</em>一个 9.5 的<em>返回值</em> 运算符指定了一个*函数*。当这个调用表达式被评估时,我们说对*参数*`7.5``9.5`*调用*函数 `max`,并*返回*一个 9.5 的*返回值*
调用表达式中参数的顺序很重要。例如,函数 `pow` 计算第一个参数的第二个参数次方。 调用表达式中参数的顺序很重要。例如,函数 `pow` 计算第一个参数的第二个参数次方。
@@ -166,7 +166,7 @@ words = set(shakespeare.read().decode().split())
不会产生歧义,因为函数名总是优先于其参数。 不会产生歧义,因为函数名总是优先于其参数。
此外,函数符号以一种直接的方式延伸到<em>嵌套表达式</em>,其中的元素本身就是复合表达式。在嵌套的调用表达式中,与复合的中缀表达式不同,嵌套的结构在括号中是完全明确的。 此外,函数符号以一种直接的方式延伸到*嵌套表达式*,其中的元素本身就是复合表达式。在嵌套的调用表达式中,与复合的中缀表达式不同,嵌套的结构在括号中是完全明确的。
```python ```python
>>> max(min(1, -2), min(pow(3, 5), -4)) >>> max(min(1, -2), min(pow(3, 5), -4))
@@ -205,7 +205,7 @@ Python 定义了大量的函数,包括上一节中提到的运算符函数,
### 变量名和环境 ### 变量名和环境
编程语言的一个关键方面是它提供了使用变量名来指代计算对象的手段。如果一个值被赋予了一个变量名,我们就说这个变量名与这个值<em>绑定</em>了。 编程语言的一个关键方面是它提供了使用变量名来指代计算对象的手段。如果一个值被赋予了一个变量名,我们就说这个变量名与这个值*绑定*了。
在 Python 中,我们可以使用赋值语句建立新的绑定,其中包含左边的变量名 `=` 右边的值。 在 Python 中,我们可以使用赋值语句建立新的绑定,其中包含左边的变量名 `=` 右边的值。
@@ -225,9 +225,9 @@ Python 定义了大量的函数,包括上一节中提到的运算符函数,
1.0002380197528042 1.0002380197528042
``` ```
`=` 符号在 Python以及许多其他语言中被称为<em>赋值</em>操作符。赋值是我们最简单的抽象手段,因为它允许我们使用简单的名称来指代复合操作的结果。用这种方式,复杂的程序就是通过一步一步地建立复杂度越来越高的计算对象来构建的。 `=` 符号在 Python以及许多其他语言中被称为*赋值*操作符。赋值是我们最简单的抽象手段,因为它允许我们使用简单的名称来指代复合操作的结果。用这种方式,复杂的程序就是通过一步一步地建立复杂度越来越高的计算对象来构建的。
将变量名与值绑定,然后通过变量名检索这些值意味着解释器必须保持某种内存,以跟踪变量名、值和绑定。这样的内存空间被称为<em>环境</em> 将变量名与值绑定,然后通过变量名检索这些值意味着解释器必须保持某种内存,以跟踪变量名、值和绑定。这样的内存空间被称为*环境*
变量名也可以被绑定到函数上。例如,变量名 `max` 与我们使用的求最大值的函数绑定。与数字不同的是函数在呈现为文本时很棘手所以当被要求描述一个函数时Python 会打印一个识别描述。 变量名也可以被绑定到函数上。例如,变量名 `max` 与我们使用的求最大值的函数绑定。与数字不同的是函数在呈现为文本时很棘手所以当被要求描述一个函数时Python 会打印一个识别描述。
@@ -256,7 +256,7 @@ Python 定义了大量的函数,包括上一节中提到的运算符函数,
2 2
``` ```
在 Python 中,名称通常被称为<em>变量名</em>或<em>变量</em>,因为它们在执行程序的过程中可能被绑定到不同的值。当一个名称通过赋值被绑定到一个新的值时,它就不再被绑定到任何以前的值。人们甚至可以将内置名称与新值绑定。 在 Python 中,名称通常被称为*变量名*或*变量*,因为它们在执行程序的过程中可能被绑定到不同的值。当一个名称通过赋值被绑定到一个新的值时,它就不再被绑定到任何以前的值。人们甚至可以将内置名称与新值绑定。
```python ```python
>>> max = 5 >>> max = 5
@@ -315,7 +315,7 @@ Python 定义了大量的函数,包括上一节中提到的运算符函数,
1. 计算运算符和操作数的子表达式,然后 1. 计算运算符和操作数的子表达式,然后
2. 将作为运算符子表达式的值的函数应用于作为运算符子表达式的值的参数。 2. 将作为运算符子表达式的值的函数应用于作为运算符子表达式的值的参数。
即使这是个简单的程序也说明了关于一般过程的一些重要观点。第一步决定了为了完成一个调用表达式的计算过程,我们必须首先计算其他表达式。因此,计算过程在本质上是<em>递归的</em>;也就是说,作为其步骤之一,它也包括调用规则本身。 即使这是个简单的程序也说明了关于一般过程的一些重要观点。第一步决定了为了完成一个调用表达式的计算过程,我们必须首先计算其他表达式。因此,计算过程在本质上是*递归的*;也就是说,作为其步骤之一,它也包括调用规则本身。
例如,计算 例如,计算
@@ -328,7 +328,7 @@ Python 定义了大量的函数,包括上一节中提到的运算符函数,
![](https://cdn.xyxsw.site/expression_tree.png) ![](https://cdn.xyxsw.site/expression_tree.png)
这张插图被称为<em>表达式树</em>。在计算机科学中Tree一种数据结构我们将在后续的章节中进行讨论通常是自上而下生长的。树中每一点的对象被称为节点在这张插图的情况下节点是与值配对的表达式。 这张插图被称为*表达式树*。在计算机科学中Tree一种数据结构我们将在后续的章节中进行讨论通常是自上而下生长的。树中每一点的对象被称为节点在这张插图的情况下节点是与值配对的表达式。
计算它的根,即顶部的完整表达式,需要首先计算作为其子表达式的分支。叶表达式(即没有分支的节点)代表函数或数字。内部节点有两个部分:我们的计算规则所适用的调用表达式,以及该表达式的结果。从这棵树的计算来看,我们可以想象操作数的值是向上渗滤的,从末端节点开始,然后在越来越高的层级上进行组合。 计算它的根,即顶部的完整表达式,需要首先计算作为其子表达式的分支。叶表达式(即没有分支的节点)代表函数或数字。内部节点有两个部分:我们的计算规则所适用的调用表达式,以及该表达式的结果。从这棵树的计算来看,我们可以想象操作数的值是向上渗滤的,从末端节点开始,然后在越来越高的层级上进行组合。
@@ -357,7 +357,7 @@ Python 定义了大量的函数,包括上一节中提到的运算符函数,
这个语句不返回一个值,也不在某些参数上调用一个函数,因为赋值的目的是将一个变量名绑定到一个值上。 这个语句不返回一个值,也不在某些参数上调用一个函数,因为赋值的目的是将一个变量名绑定到一个值上。
一般来说,赋值语句不是被计算而是<em>被执行</em>;它们不产生一个值,而是做一些改变。每种类型的表达式或语句都有自己的计算或执行过程。 一般来说,赋值语句不是被计算而是*被执行*;它们不产生一个值,而是做一些改变。每种类型的表达式或语句都有自己的计算或执行过程。
### 纯函数和非纯函数 ### 纯函数和非纯函数

View File

@@ -1,7 +1,7 @@
# 3.X 聊聊设计模式和程序设计 # 3.X 聊聊设计模式和程序设计
<em>Author: yyl *Author: yyl
Last revised 2022/08/07</em> Last revised 2022/08/07*
## 前言 ## 前言

View File

@@ -8,9 +8,9 @@
首先下载 VMware 首先下载 VMware
如果是 pro16 版本key <strong>ZF3R0-FHED2-M80TY-8QYGC-NPKYF</strong> 如果是 pro16 版本key **ZF3R0-FHED2-M80TY-8QYGC-NPKYF**
如果是 pro17 版本key <strong>JU090-6039P-08409-8J0QH-2YR7F</strong><strong> </strong> 如果是 pro17 版本key **JU090-6039P-08409-8J0QH-2YR7F**
本文写的时候用的版本是 pro16但目前已经更新到 pro17 所以来更新个 key如下安装与 16 版本无异) 本文写的时候用的版本是 pro16但目前已经更新到 pro17 所以来更新个 key如下安装与 16 版本无异)
@@ -109,7 +109,7 @@
![](https://cdn.xyxsw.site/boxcnnLCJzGoFrUbWIMAPGFkxcb.png) ![](https://cdn.xyxsw.site/boxcnnLCJzGoFrUbWIMAPGFkxcb.png)
<strong>至此 恭喜安装完成!</strong> **至此 恭喜安装完成!**
之后就可以在桌面上右键 之后就可以在桌面上右键
@@ -117,4 +117,4 @@
打开命令行 打开命令行
<strong>开始你的 Linux 学习吧</strong> **开始你的 Linux 学习吧**

View File

@@ -3,12 +3,12 @@
::: warning 💡与 VMware 安装二选一 安装了 VMware 不用 wsl ::: warning 💡与 VMware 安装二选一 安装了 VMware 不用 wsl
::: :::
先说<strong>坏处</strong> 先说**坏处**
1. 开启 hyperv 的后果是 如果你电脑装模拟器玩手游的话 装了 hyperv 你的模拟器是打不开的(目前只有 `蓝叠国际版HyperV版`(性能很差)支持共存 hyperv 和模拟器) 1. 开启 hyperv 的后果是 如果你电脑装模拟器玩手游的话 装了 hyperv 你的模拟器是打不开的(目前只有 `蓝叠国际版HyperV版`(性能很差)支持共存 hyperv 和模拟器)
2. WSL 很难装辣 安装过程中会出很多 bug 需要你自行 STFW 2. WSL 很难装辣 安装过程中会出很多 bug 需要你自行 STFW
## <strong>官方文档</strong> ## **官方文档**
## [史上最全的 WSL 安装教程](https://blog.csdn.net/wojiuguowei/article/details/122100090) ## [史上最全的 WSL 安装教程](https://blog.csdn.net/wojiuguowei/article/details/122100090)
@@ -18,7 +18,7 @@
![](https://cdn.xyxsw.site/boxcnYVkEecWdUs710e8h6G9GTh.png) ![](https://cdn.xyxsw.site/boxcnYVkEecWdUs710e8h6G9GTh.png)
如果你的 windows 版本为<strong>家庭版</strong> 那么 hyperv 选项是没有的 如果你的 windows 版本为**家庭版** 那么 hyperv 选项是没有的
你需要右键以管理员权限打开以下脚本来强行开启 hyperv 你需要右键以管理员权限打开以下脚本来强行开启 hyperv

View File

@@ -49,7 +49,7 @@ Linux 命令行中的命令使用格式都是相同的:
man 3 freopen man 3 freopen
``` ```
### <strong>统计代码行数</strong> ### **统计代码行数**
第一个例子是统计一个目录中 (包含子目录) 中的代码行数。如果想知道当前目录下究竟有多少行的代码,就可以在命令行中键入如下命令: 第一个例子是统计一个目录中 (包含子目录) 中的代码行数。如果想知道当前目录下究竟有多少行的代码,就可以在命令行中键入如下命令:
@@ -65,7 +65,7 @@ find . | grep '\.c$\|\.h$' | xargs wc -l
我们最后的任务是统计这些文件所占用的总行数,此时可以用 `man` 查看 `wc` 命令。`wc` 命令的 `-l` 选项能够计算代码的行数。`xargs` 命令十分特殊,它能够将标准输入转换为参数,传送给第一个参数所指定的程序。所以,代码中的 `xargs wc -l` 就等价于执行 `wc -l aaa.c bbb.c include/ccc.h ...`, 最终完成代码行数统计。 我们最后的任务是统计这些文件所占用的总行数,此时可以用 `man` 查看 `wc` 命令。`wc` 命令的 `-l` 选项能够计算代码的行数。`xargs` 命令十分特殊,它能够将标准输入转换为参数,传送给第一个参数所指定的程序。所以,代码中的 `xargs wc -l` 就等价于执行 `wc -l aaa.c bbb.c include/ccc.h ...`, 最终完成代码行数统计。
### <strong>统计磁盘使用情况</strong> ### **统计磁盘使用情况**
以下命令统计 `/usr/share` 目录下各个目录所占用的磁盘空间: 以下命令统计 `/usr/share` 目录下各个目录所占用的磁盘空间:
@@ -83,7 +83,7 @@ du -sc /usr/share/* | sort -nr | more
此时将会看到输出的前几行结果。`more` 工具使用空格翻页,并可以用 `q` 键在中途退出。`less` 工具则更为强大,不仅可以向下翻页,还可以向上翻页,同样使用 `q` 键退出。这里还有一个[关于 less 的小故事](http://en.wikipedia.org/wiki/Less_(Unix)). 此时将会看到输出的前几行结果。`more` 工具使用空格翻页,并可以用 `q` 键在中途退出。`less` 工具则更为强大,不仅可以向下翻页,还可以向上翻页,同样使用 `q` 键退出。这里还有一个[关于 less 的小故事](http://en.wikipedia.org/wiki/Less_(Unix)).
### <strong>在 Linux 下编写 Hello World 程序</strong> ### **在 Linux 下编写 Hello World 程序**
Linux 中用户的主目录是 `/home/用户名称`, 如果你的用户名是 `user`, 你的主目录就是 `/home/user`. 用户的 `home` 目录可以用波浪符号 `~` 替代,例如临时文件目录 `/home/user/Templates` 可以简写为 `~/Templates`. 现在我们就可以进入主目录并编辑文件了。如果 `Templates` 目录不存在,可以通过 `mkdir` 命令创建它: Linux 中用户的主目录是 `/home/用户名称`, 如果你的用户名是 `user`, 你的主目录就是 `/home/user`. 用户的 `home` 目录可以用波浪符号 `~` 替代,例如临时文件目录 `/home/user/Templates` 可以简写为 `~/Templates`. 现在我们就可以进入主目录并编辑文件了。如果 `Templates` 目录不存在,可以通过 `mkdir` 命令创建它:
@@ -100,7 +100,7 @@ cd Templates
可以完成目录的切换。注意在输入目录名时,`tab` 键可以提供联想。 可以完成目录的切换。注意在输入目录名时,`tab` 键可以提供联想。
#### <strong> 你感到键入困难吗?</strong> #### ** 你感到键入困难吗?**
::: warning 💡 你可能会经常要在终端里输入类似于 ::: warning 💡 你可能会经常要在终端里输入类似于

View File

@@ -35,7 +35,7 @@ apt-get install vim
如果您能够遵循上述步骤,并且坚持使用新的编辑器完成您所有的文本编辑任务,那么学习一个复杂的代码编辑器的过程一般是这样的:头两个小时,您会学习到编辑器的基本操作,例如打开和编辑文件、保存与退出、浏览缓冲区。当学习时间累计达到 20 个小时之后,您使用新编辑器的效率应该已经和使用老编辑器一样快。在此之后,其益处开始显现:有了足够的知识和肌肉记忆后,使用新编辑器将大大节省你的时间。而现代文本编辑器都是些复杂且强大的工具,永远有新东西可学:学的越多,效率越高。 如果您能够遵循上述步骤,并且坚持使用新的编辑器完成您所有的文本编辑任务,那么学习一个复杂的代码编辑器的过程一般是这样的:头两个小时,您会学习到编辑器的基本操作,例如打开和编辑文件、保存与退出、浏览缓冲区。当学习时间累计达到 20 个小时之后,您使用新编辑器的效率应该已经和使用老编辑器一样快。在此之后,其益处开始显现:有了足够的知识和肌肉记忆后,使用新编辑器将大大节省你的时间。而现代文本编辑器都是些复杂且强大的工具,永远有新东西可学:学的越多,效率越高。
## <strong>Vim 的哲学</strong> ## **Vim 的哲学**
在编程的时候,你会把大量时间花在阅读/编辑而不是在写代码上。所以Vim 是一个_多模态_编辑 器它对于插入文字和操纵文字有不同的模式。Vim 是可编程的(可以使用 Vimscript 或者像 Python 一样的其他程序语言Vim 的接口本身也是一个程序语言键入操作以及其助记名是命令这些命令也是可组合的。Vim 避免了使用鼠标因为那样太慢了Vim 甚至避免用 上下左右键因为那样需要太多的手指移动。 在编程的时候,你会把大量时间花在阅读/编辑而不是在写代码上。所以Vim 是一个_多模态_编辑 器它对于插入文字和操纵文字有不同的模式。Vim 是可编程的(可以使用 Vimscript 或者像 Python 一样的其他程序语言Vim 的接口本身也是一个程序语言键入操作以及其助记名是命令这些命令也是可组合的。Vim 避免了使用鼠标因为那样太慢了Vim 甚至避免用 上下左右键因为那样需要太多的手指移动。

View File

@@ -14,7 +14,7 @@
<font color=green>大白话 -> 提取后的逻辑链条</font> -> <font color=red>科研写作 -> 英文翻译</font> <font color=green>大白话 -> 提取后的逻辑链条</font> -> <font color=red>科研写作 -> 英文翻译</font>
<strong>干了什么:</strong> **干了什么:**
1. 如果没有想清楚要做的是什么,要写什么,可以先用大白话,在草稿上写,有利于理清思路,抽丝剥茧 1. 如果没有想清楚要做的是什么,要写什么,可以先用大白话,在草稿上写,有利于理清思路,抽丝剥茧
@@ -45,7 +45,7 @@
之所以要用大白话是因为基础的不足,如果有一定功底的人,可能先天写出来文字自带规范性,所以仅供大家参考) 之所以要用大白话是因为基础的不足,如果有一定功底的人,可能先天写出来文字自带规范性,所以仅供大家参考)
<strong>表达规范性:</strong> **表达规范性:**
此处的方法论为一句话,则是从模仿到超越的浑然天成。 此处的方法论为一句话,则是从模仿到超越的浑然天成。

View File

@@ -2,11 +2,11 @@
author:廖总 author:廖总
<em>Last revised 2023/04/18</em> *Last revised 2023/04/18*
先声夺人AI 时代最大的陷阱,就是盲目考察 AI 能为我们做什么,而不去考虑我们能为 AI 提供什么 先声夺人AI 时代最大的陷阱,就是盲目考察 AI 能为我们做什么,而不去考虑我们能为 AI 提供什么
## <em>免责声明</em> ## *免责声明*
本文纯文本量达 16k我也不知道字数统计的 28k 是怎么来的),在这 游离散乱的主线 和 支离破碎的文字 中挣扎,可能浪费您生命中宝贵的十数分钟。 本文纯文本量达 16k我也不知道字数统计的 28k 是怎么来的),在这 游离散乱的主线 和 支离破碎的文字 中挣扎,可能浪费您生命中宝贵的十数分钟。
@@ -616,7 +616,7 @@ AutoGPT 主要特性如下:
作为正题的回归,我们需要重新考虑什么是一个 AI一个能帮助我们的 AI 应当处于什么样的现实形态? 作为正题的回归,我们需要重新考虑什么是一个 AI一个能帮助我们的 AI 应当处于什么样的现实形态?
<em>我们需要的 </em><em>AI</em><em> 仅仅是大语言模型吗?如果是,它能帮我们做什么呢?如果不是,那 AI 的实质是什么呢?</em> *我们需要的 **AI** 仅仅是大语言模型吗?如果是,它能帮我们做什么呢?如果不是,那 AI 的实质是什么呢?*
我首先武断地认为,我们需要的 AI并不是一个语言模型实体而是一个复杂智能系统 我首先武断地认为,我们需要的 AI并不是一个语言模型实体而是一个复杂智能系统
@@ -803,7 +803,7 @@ Generative Agents 的知觉设计:关联性难题
仅就这方面而言,作为一个方向性的倡议,对知觉系统的开发可能分为以下步骤 仅就这方面而言,作为一个方向性的倡议,对知觉系统的开发可能分为以下步骤
#### <em>数据处理/管理</em> #### *数据处理/管理*
- 对 办公文件/数据 构建通用读取接口 - 对 办公文件/数据 构建通用读取接口
- 以同类信息为单位设计通用的字段由人设计和管理AI 能力尚不至此) - 以同类信息为单位设计通用的字段由人设计和管理AI 能力尚不至此)
@@ -827,7 +827,7 @@ Generative Agents 的知觉设计:关联性难题
- 如储存进 mongoDB - 如储存进 mongoDB
- (设计孪生数据的自动更新机制) - (设计孪生数据的自动更新机制)
#### <em>知觉系统驱动</em> #### *知觉系统驱动*
- 基于上述索引数据库,以视图为单位进行访问,并设计 视图 2 Prompt 的转化格式 - 基于上述索引数据库,以视图为单位进行访问,并设计 视图 2 Prompt 的转化格式

View File

@@ -2,7 +2,7 @@
author:Marlene author:Marlene
<em>Last revised 2023/07/26</em> *Last revised 2023/07/26*
## 引言 ## 引言

View File

@@ -10,7 +10,7 @@
### CV(计算机视觉) ### CV(计算机视觉)
计算机视觉旨在<strong>用计算机模拟人类处理图片信息的能力</strong>,就比如这里有一张图片——手写数字 9 计算机视觉旨在**用计算机模拟人类处理图片信息的能力**,就比如这里有一张图片——手写数字 9
![](https://cdn.xyxsw.site/boxcnvQiaAx6WgPx64s8fBklVwh.png) ![](https://cdn.xyxsw.site/boxcnvQiaAx6WgPx64s8fBklVwh.png)
@@ -18,7 +18,7 @@
相信你通过上面简单的介绍应该能够了解到计算机视觉是在干嘛了,接下来我会举几个相对复杂的例子来让大家了解一下目前的 cv 是在做怎样的研究: 相信你通过上面简单的介绍应该能够了解到计算机视觉是在干嘛了,接下来我会举几个相对复杂的例子来让大家了解一下目前的 cv 是在做怎样的研究:
::: warning 🐱 <strong>图像分割</strong>是在图片中对物体分类,并且把它们所对应的位置标示出来。下图就是把人的五官,面部皮肤和头发分割出来,效 (小) 果 (丑) 图如下: ::: warning 🐱 **图像分割**是在图片中对物体分类,并且把它们所对应的位置标示出来。下图就是把人的五官,面部皮肤和头发分割出来,效 (小) 果 (丑) 图如下:
::: :::
<table> <table>
@@ -29,15 +29,15 @@
</tr> </tr>
</table> </table>
::: warning 🐱 <strong>图像生成</strong>相信大家一定不陌生NovalAI 在 2022 年火的一塌糊涂,我觉得不需要我过多赘述,对它 (Diffusion model) 的改进工作也是层出不穷,这里就放一张由可控姿势网络 (ControlNet) 生成的图片吧: ::: warning 🐱 **图像生成**相信大家一定不陌生NovalAI 在 2022 年火的一塌糊涂,我觉得不需要我过多赘述,对它 (Diffusion model) 的改进工作也是层出不穷,这里就放一张由可控姿势网络 (ControlNet) 生成的图片吧:
::: :::
![](https://cdn.xyxsw.site/boxcnUjnRociXua1yKj6dmU1A3c.png) ![](https://cdn.xyxsw.site/boxcnUjnRociXua1yKj6dmU1A3c.png)
::: warning 🐱 <strong>三维重建</strong>也是很多研究者关注的方向,指的是传入对同一物体不同视角的照片,来生成 3D 建模的任务。这方面比图像处理更加前沿并且难度更大。具体见[4.6.5.4 神经辐射场 (NeRF)](4.6.5.4%E7%A5%9E%E7%BB%8F%E8%BE%90%E5%B0%84%E5%9C%BA(NeRF).md) 章节。 ::: warning 🐱 **三维重建**也是很多研究者关注的方向,指的是传入对同一物体不同视角的照片,来生成 3D 建模的任务。这方面比图像处理更加前沿并且难度更大。具体见[4.6.5.4 神经辐射场 (NeRF)](4.6.5.4%E7%A5%9E%E7%BB%8F%E8%BE%90%E5%B0%84%E5%9C%BA(NeRF).md) 章节。
::: :::
如果对计算机视觉有兴趣,可以通过以下路线进行学习:深度学习快速入门—> 经典网络。本块内容的主要撰写者之一<strong>SRT 社团</strong>多数成员主要从事 CV 方向研究,欢迎与我们交流。 如果对计算机视觉有兴趣,可以通过以下路线进行学习:深度学习快速入门—> 经典网络。本块内容的主要撰写者之一**SRT 社团**多数成员主要从事 CV 方向研究,欢迎与我们交流。
### NLP(自然语言处理) ### NLP(自然语言处理)
@@ -56,9 +56,9 @@
而多模态就是让计算机能够将不同模态的信息相对应,一种常用的方法就是让计算机把图片的内容和文本的内容理解为相同的语义(在这个领域一般用一个较长的向量来表示语义)。 而多模态就是让计算机能够将不同模态的信息相对应,一种常用的方法就是让计算机把图片的内容和文本的内容理解为相同的语义(在这个领域一般用一个较长的向量来表示语义)。
也就是说我<strong>传入一张狗子的照片经过模型得到的向量</strong>与<strong>DOG 这个单词经过模型得到的向量</strong>相近。 也就是说我**传入一张狗子的照片经过模型得到的向量**与**DOG 这个单词经过模型得到的向量**相近。
具体的任务比如说<strong>图片问答</strong>,传入一张图片,问 AI 这张图片里面有几只猫猫,它们是什么颜色,它告诉我有一只猫猫,是橙色的: 具体的任务比如说**图片问答**,传入一张图片,问 AI 这张图片里面有几只猫猫,它们是什么颜色,它告诉我有一只猫猫,是橙色的:
![](https://cdn.xyxsw.site/boxcnrMvM1THshjXXOuh8WXi2zr.jpg) ![](https://cdn.xyxsw.site/boxcnrMvM1THshjXXOuh8WXi2zr.jpg)

View File

@@ -175,7 +175,7 @@ def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
![](https://cdn.xyxsw.site/boxcnXbd7bqnqPwF8f1Up8rHq5e.png) ![](https://cdn.xyxsw.site/boxcnXbd7bqnqPwF8f1Up8rHq5e.png)
<em>θ 表示当前的权重值。J(θ) 表示「当前权重的代价」。</em> *θ 表示当前的权重值。J(θ) 表示「当前权重的代价」。*
这个等式表示,在当前权重值下,我们估价程序的偏离程度。 这个等式表示,在当前权重值下,我们估价程序的偏离程度。
@@ -203,7 +203,7 @@ def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
不过幸运的是,有很多办法来处理这种情况。有许多机器学习算法可以处理非线性数据。除此之外,灵活使用线性回归也能拟合更复杂的线条。在所有的情况下,寻找最优权重这一基本思路依然适用。 不过幸运的是,有很多办法来处理这种情况。有许多机器学习算法可以处理非线性数据。除此之外,灵活使用线性回归也能拟合更复杂的线条。在所有的情况下,寻找最优权重这一基本思路依然适用。
<strong>如果你还是无法理解,你可以将 cost 类比为你出错误的程度,而数学科学家找到各种方法来降低这种程度,当程度降到最低时,我们就可以知道我们要求的数值了</strong> **如果你还是无法理解,你可以将 cost 类比为你出错误的程度,而数学科学家找到各种方法来降低这种程度,当程度降到最低时,我们就可以知道我们要求的数值了**
另外我忽略了过拟合overfitting的概念。得到一组能完美预测原始数据集中房价的权重组很简单但用这组权重组来预测原始数据集之外的任何新房屋其实都不怎么准确。这也是有许多解决办法的如[正则化](https://link.zhihu.com/?target=http%3A//en.wikipedia.org/wiki/Regularization_%2528mathematics%2529%23Regularization_in_statistics_and_machine_learning)以及使用[交叉验证](https://link.zhihu.com/?target=http%3A//en.wikipedia.org/wiki/Cross-validation_%2528statistics%2529)的数据集)。学习如何应对这一问题,是学习如何成功应用机器学习技术的重点之一。 另外我忽略了过拟合overfitting的概念。得到一组能完美预测原始数据集中房价的权重组很简单但用这组权重组来预测原始数据集之外的任何新房屋其实都不怎么准确。这也是有许多解决办法的如[正则化](https://link.zhihu.com/?target=http%3A//en.wikipedia.org/wiki/Regularization_%2528mathematics%2529%23Regularization_in_statistics_and_machine_learning)以及使用[交叉验证](https://link.zhihu.com/?target=http%3A//en.wikipedia.org/wiki/Cross-validation_%2528statistics%2529)的数据集)。学习如何应对这一问题,是学习如何成功应用机器学习技术的重点之一。
@@ -226,7 +226,7 @@ def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
![](https://cdn.xyxsw.site/boxcnhbR6lGSXd6UAEpRvSIYSHg.png) ![](https://cdn.xyxsw.site/boxcnhbR6lGSXd6UAEpRvSIYSHg.png)
<em>箭头头表示了函数中的权重。</em> *箭头头表示了函数中的权重。*
然而,这个算法仅仅能用于处理一些简单的问题,就是那些输入和输出有着线性关系的问题。但如果真实价格和决定因素的关系并不是如此简单,那我们该怎么办?比如说,地段对于大户型和小户型的房屋有很大影响,然而对中等户型的房屋并没有太大影响。那我们该怎么在我们的模型中收集这种复杂的信息呢? 然而,这个算法仅仅能用于处理一些简单的问题,就是那些输入和输出有着线性关系的问题。但如果真实价格和决定因素的关系并不是如此简单,那我们该怎么办?比如说,地段对于大户型和小户型的房屋有很大影响,然而对中等户型的房屋并没有太大影响。那我们该怎么在我们的模型中收集这种复杂的信息呢?
@@ -392,13 +392,13 @@ model.add(Activation('relu'))# 激活函数,你可以理解为加上这个东
### 卷积是如何工作的 ### 卷积是如何工作的
之前我们提到过,我们可以把一整张图片当做一串数字输入到神经网络里面。不同的是,这次我们会利用<strong>平移不变性</strong>的概念来把这件事做得更智能。 之前我们提到过,我们可以把一整张图片当做一串数字输入到神经网络里面。不同的是,这次我们会利用**平移不变性**的概念来把这件事做得更智能。
当然也有最新研究说卷积不具备平移不变性,但是我这里使用这个概念是为了大伙更好的理解,举个例子:你将 8 无论放在左上角还是左下角都改变不了他是 8 的事实 当然也有最新研究说卷积不具备平移不变性,但是我这里使用这个概念是为了大伙更好的理解,举个例子:你将 8 无论放在左上角还是左下角都改变不了他是 8 的事实
![](https://cdn.xyxsw.site/boxcnHo4tt4wmnC7sUykRPPLKmm.png) ![](https://cdn.xyxsw.site/boxcnHo4tt4wmnC7sUykRPPLKmm.png)
我们将一张图像分成这么多个小块,然后输入神经网络中的是一个小块。<em>每次判断一张小图块。</em> 我们将一张图像分成这么多个小块,然后输入神经网络中的是一个小块。*每次判断一张小图块。*
然而,有一个非常重要的不同:对于每个小图块,我们会使用同样的神经网络权重。换一句话来说,我们平等对待每一个小图块。如果哪个小图块有任何异常出现,我们就认为这个图块是「异常」 然而,有一个非常重要的不同:对于每个小图块,我们会使用同样的神经网络权重。换一句话来说,我们平等对待每一个小图块。如果哪个小图块有任何异常出现,我们就认为这个图块是「异常」

View File

@@ -84,7 +84,7 @@
- 最优解 (Optimal Solution) - 最优解 (Optimal Solution)
- 在所有解决方案中路径成本最低的解决方案。 - 在所有解决方案中路径成本最低的解决方案。
- 在搜索过程中,数据通常存储在<strong>节点 (Node)</strong> 中,节点是一种包含以下数据的数据结构: - 在搜索过程中,数据通常存储在**节点 (Node)** 中,节点是一种包含以下数据的数据结构:
- 状态——state - 状态——state
- 其父节点通过该父节点生成当前节点——parent node - 其父节点通过该父节点生成当前节点——parent node
@@ -312,6 +312,6 @@ def remove(self):
- 深度限制的极大极小算法 (Depth-Limited Minimax) - 深度限制的极大极小算法 (Depth-Limited Minimax)
- 总共有$255168$个可能的井字棋游戏,以及有$10^{29000}$个可能的国际象棋中游戏。到目前为止,最小最大算法需要生成从某个点到<strong>终端条件</strong>的所有假设游戏状态。虽然计算所有的井字棋游戏状态对现代计算机来说并不是一个挑战,但目前用来计算国际象棋是不可能的。 - 总共有$255168$个可能的井字棋游戏,以及有$10^{29000}$个可能的国际象棋中游戏。到目前为止,最小最大算法需要生成从某个点到**终端条件**的所有假设游戏状态。虽然计算所有的井字棋游戏状态对现代计算机来说并不是一个挑战,但目前用来计算国际象棋是不可能的。
- 深度限制的 Minimax 算法在停止之前只考虑预先定义的移动次数,而从未达到终端状态。然而,这不允许获得每个动作的精确值,因为假设的游戏还没有结束。为了解决这个问题,深度限制 Minimax 依赖于一个评估函数,该函数从给定状态估计游戏的预期效用,或者换句话说,为状态赋值。例如,在国际象棋游戏中,效用函数会将棋盘的当前配置作为输入,尝试评估其预期效用(基于每个玩家拥有的棋子及其在棋盘上的位置),然后返回一个正值或负值,表示棋盘对一个玩家对另一个玩家的有利程度。这些值可以用来决定正确的操作,并且评估函数越好,依赖它的 Minimax 算法就越好。 - 深度限制的 Minimax 算法在停止之前只考虑预先定义的移动次数,而从未达到终端状态。然而,这不允许获得每个动作的精确值,因为假设的游戏还没有结束。为了解决这个问题,深度限制 Minimax 依赖于一个评估函数,该函数从给定状态估计游戏的预期效用,或者换句话说,为状态赋值。例如,在国际象棋游戏中,效用函数会将棋盘的当前配置作为输入,尝试评估其预期效用(基于每个玩家拥有的棋子及其在棋盘上的位置),然后返回一个正值或负值,表示棋盘对一个玩家对另一个玩家的有利程度。这些值可以用来决定正确的操作,并且评估函数越好,依赖它的 Minimax 算法就越好。

View File

@@ -2,7 +2,7 @@
人类根据现有的知识进行推理并得出结论。表示知识并从中得出结论的概念也被用于人工智能中,在本章中我们将探讨如何实现这种行为。 人类根据现有的知识进行推理并得出结论。表示知识并从中得出结论的概念也被用于人工智能中,在本章中我们将探讨如何实现这种行为。
::: warning <font size=5><strong>说好的 AI 呢?怎么感觉越来越偏了?</strong></font> ::: warning <font size=5>**说好的 AI 呢?怎么感觉越来越偏了?**</font>
如果有这样的疑问的同学,可能存在一定的误区,认为人工智能就是局限在深度学习的算法或者说机器学习的部分算法上,其实这是对这个领域一个巨大的误解。 如果有这样的疑问的同学,可能存在一定的误区,认为人工智能就是局限在深度学习的算法或者说机器学习的部分算法上,其实这是对这个领域一个巨大的误解。
@@ -42,7 +42,7 @@
- 命题符号通常是用于表示命题的字母$P、Q、R$ - 命题符号通常是用于表示命题的字母$P、Q、R$
- 逻辑连接词 (Logical Connectives) - 逻辑连接词 (Logical Connectives)
- 逻辑连接词是连接命题符号的逻辑符号,以便以更复杂的方式对世界进行推理。 - 逻辑连接词是连接命题符号的逻辑符号,以便以更复杂的方式对世界进行推理。
- <strong>Not</strong><strong> </strong><strong>(</strong>$\lnot$<strong>)</strong> 逻辑非:命题真值的反转。例如,如果 $P$:“正在下雨”,那么 $¬P$:“没有下雨”。 - **Not**** ****(**$\lnot$**)** 逻辑非:命题真值的反转。例如,如果 $P$:“正在下雨”,那么 $¬P$:“没有下雨”。
- 真值表用于将所有可能的真值赋值与命题进行比较。该工具将帮助我们更好地理解与不同逻辑连接词相关联的命题的真值。例如,下面是我们的第一个真值表: - 真值表用于将所有可能的真值赋值与命题进行比较。该工具将帮助我们更好地理解与不同逻辑连接词相关联的命题的真值。例如,下面是我们的第一个真值表:
| $P$ | $\lnot P$ | | $P$ | $\lnot P$ |
@@ -50,7 +50,7 @@
| false(0) | true(1) | | false(0) | true(1) |
| true(1) | false(0) | | true(1) | false(0) |
- <strong>And(</strong>$\land$<strong>)</strong> 逻辑乘 (合取): 连接两个不同的命题。当这两个命题$P$和$Q$用$∧$连接时,得到的命题$P∧Q$只有在$P$和$Q$都为真的情况下才为真。 - **And(**$\land$**)** 逻辑乘 (合取): 连接两个不同的命题。当这两个命题$P$和$Q$用$∧$连接时,得到的命题$P∧Q$只有在$P$和$Q$都为真的情况下才为真。
| $P$ | $Q$ | $P\land Q$ | | $P$ | $Q$ | $P\land Q$ |
| --- | --- | ---------- | | --- | --- | ---------- |
@@ -59,7 +59,7 @@
| 1 | 0 | 0 | | 1 | 0 | 0 |
| 1 | 1 | 1 | | 1 | 1 | 1 |
- <strong>Or(</strong>$\lor$<strong>)</strong> 逻辑和 (析取): 只要它的任何一个参数为真,它就为真。这意味着要使 $P Q$为真,$P$ 或 $Q$ 中至少有一个必须为真。 - **Or(**$\lor$**)** 逻辑和 (析取): 只要它的任何一个参数为真,它就为真。这意味着要使 $P Q$为真,$P$ 或 $Q$ 中至少有一个必须为真。
| $P$ | $Q$ | $P\lor Q$ | | $P$ | $Q$ | $P\lor Q$ |
| --- | --- | --------- | | --- | --- | --------- |
@@ -70,7 +70,7 @@
- 值得一提的是Or 有两种类型:同或 Or 和异或 Or。在异或中如果$P\lor Q$为真,则$P∧Q$为假。也就是说,一个异或要求它只有一个论点为真,而不要求两者都为真。如果$P、Q$或$P∧Q$中的任何一个为真,则包含或为真。在 Or($\lor$) 的情况下,意图是一个包含的 Or。 - 值得一提的是Or 有两种类型:同或 Or 和异或 Or。在异或中如果$P\lor Q$为真,则$P∧Q$为假。也就是说,一个异或要求它只有一个论点为真,而不要求两者都为真。如果$P、Q$或$P∧Q$中的任何一个为真,则包含或为真。在 Or($\lor$) 的情况下,意图是一个包含的 Or。
- <strong>Implication (→)</strong> 逻辑蕴含:表示“如果$P$,则$Q$的结构。例如,如果$P$:“正在下雨”,$Q$:“我在室内”,则$P→ Q$的意思是“如果下雨,那么我在室内。”在$P$的情况下,意味着$Q$$P$被称为前件,$Q$ 被称为后件。 - **Implication (→)** 逻辑蕴含:表示“如果$P$,则$Q$的结构。例如,如果$P$:“正在下雨”,$Q$:“我在室内”,则$P→ Q$的意思是“如果下雨,那么我在室内。”在$P$的情况下,意味着$Q$$P$被称为前件,$Q$ 被称为后件。
- 当前件为真时,在后件为真的情况下,整个蕴含逻辑为真(这是有道理的:如果下雨,我在室内,那么“如果下雨,那么我在室内”这句话是真的)。当前件为真时,如果后件为假,则蕴含逻辑为假(如果下雨时我在外面,那么“如果下雨,那么我在室内”这句话是假的)。然而,当前件为假时,无论后件如何,蕴含逻辑总是真的。这有时可能是一个令人困惑的概念。从逻辑上讲,我们不能从蕴含中学到任何东西$(P→ Q)$如果前件 ($P$) 为假。看一下我们的例子,如果没有下雨,这个蕴含逻辑并没有说我是否在室内的问题。我可能是一个室内型的人,即使不下雨也不在外面走,或者我可能是一个室外型的人,不下雨的时候一直在外面。当前件是假的,我们说蕴含逻辑是真的。 - 当前件为真时,在后件为真的情况下,整个蕴含逻辑为真(这是有道理的:如果下雨,我在室内,那么“如果下雨,那么我在室内”这句话是真的)。当前件为真时,如果后件为假,则蕴含逻辑为假(如果下雨时我在外面,那么“如果下雨,那么我在室内”这句话是假的)。然而,当前件为假时,无论后件如何,蕴含逻辑总是真的。这有时可能是一个令人困惑的概念。从逻辑上讲,我们不能从蕴含中学到任何东西$(P→ Q)$如果前件 ($P$) 为假。看一下我们的例子,如果没有下雨,这个蕴含逻辑并没有说我是否在室内的问题。我可能是一个室内型的人,即使不下雨也不在外面走,或者我可能是一个室外型的人,不下雨的时候一直在外面。当前件是假的,我们说蕴含逻辑是真的。
@@ -81,7 +81,7 @@
| 1 | 0 | 0 | | 1 | 0 | 0 |
| 1 | 1 | 1 | | 1 | 1 | 1 |
- <strong>Biconditional (</strong>$\leftrightarrow$<strong>)</strong> :是一个双向的蕴含。你可以把它读成“如果且仅当”$P↔ Q$等同$P→ Q$和$Q→ P$合在一起。例如,如果$P$:“正在下雨”,$Q$:“我在室内”,那么$P↔ Q$的意思是“如果下雨,那么我在室内”,“如果我在室内,那么就在下雨。”这意味着我们可以推断出比简单蕴含更多的东西。如果$P$为假,那么$Q$ 也为假;如果不下雨,我们知道我也不在室内。 - **Biconditional (**$\leftrightarrow$**)** :是一个双向的蕴含。你可以把它读成“如果且仅当”$P↔ Q$等同$P→ Q$和$Q→ P$合在一起。例如,如果$P$:“正在下雨”,$Q$:“我在室内”,那么$P↔ Q$的意思是“如果下雨,那么我在室内”,“如果我在室内,那么就在下雨。”这意味着我们可以推断出比简单蕴含更多的东西。如果$P$为假,那么$Q$ 也为假;如果不下雨,我们知道我也不在室内。
| $P$ | $Q$ | $P\leftrightarrow Q$ | | $P$ | $Q$ | $P\leftrightarrow Q$ |
| --- | --- | -------------------- | | --- | --- | -------------------- |

View File

@@ -342,11 +342,11 @@ print(Counter(data))
- 到目前为止,我们已经研究了概率问题,给出了我们观察到的一些信息。在这种范式中,时间的维度没有以任何方式表示。然而,许多任务确实依赖于时间维度,例如预测。为了表示时间变量,我们将创建一个新的变量$X$,并根据感兴趣的事件对其进行更改,使$X_t$ 是当前事件,$X_{t+1}$ 是下一个事件,依此类推。为了能够预测未来的事件,我们将使用马尔可夫模型。 - 到目前为止,我们已经研究了概率问题,给出了我们观察到的一些信息。在这种范式中,时间的维度没有以任何方式表示。然而,许多任务确实依赖于时间维度,例如预测。为了表示时间变量,我们将创建一个新的变量$X$,并根据感兴趣的事件对其进行更改,使$X_t$ 是当前事件,$X_{t+1}$ 是下一个事件,依此类推。为了能够预测未来的事件,我们将使用马尔可夫模型。
### 马尔科夫假设 (<strong>The Markov Assumption</strong>) ### 马尔科夫假设 (**The Markov Assumption**)
- 马尔科夫假设是一个假设,即当前状态只取决于有限的固定数量的先前状态。想想预测天气的任务。在理论上,我们可以使用过去一年的所有数据来预测明天的天气。然而,这是不可行的,一方面是因为这需要计算能力,另一方面是因为可能没有关于基于 365 天前天气的明天天气的条件概率的信息。使用马尔科夫假设,我们限制了我们以前的状态(例如,在预测明天的天气时,我们要考虑多少个以前的日子),从而使这个任务变得可控。这意味着我们可能会得到感兴趣的概率的一个更粗略的近似值,但这往往足以满足我们的需要。此外,我们可以根据最后一个事件的信息来使用马尔可夫模型(例如,根据今天的天气来预测明天的天气)。 - 马尔科夫假设是一个假设,即当前状态只取决于有限的固定数量的先前状态。想想预测天气的任务。在理论上,我们可以使用过去一年的所有数据来预测明天的天气。然而,这是不可行的,一方面是因为这需要计算能力,另一方面是因为可能没有关于基于 365 天前天气的明天天气的条件概率的信息。使用马尔科夫假设,我们限制了我们以前的状态(例如,在预测明天的天气时,我们要考虑多少个以前的日子),从而使这个任务变得可控。这意味着我们可能会得到感兴趣的概率的一个更粗略的近似值,但这往往足以满足我们的需要。此外,我们可以根据最后一个事件的信息来使用马尔可夫模型(例如,根据今天的天气来预测明天的天气)。
### 马尔科夫链 (<strong>Markov Chain</strong>) ### 马尔科夫链 (**Markov Chain**)
- 马尔科夫链是一个随机变量的序列,每个变量的分布都遵循马尔科夫假设。也就是说,链中的每个事件的发生都是基于之前事件的概率。 - 马尔科夫链是一个随机变量的序列,每个变量的分布都遵循马尔科夫假设。也就是说,链中的每个事件的发生都是基于之前事件的概率。
- 为了构建马尔可夫链,我们需要一个过渡模型,该模型将根据当前事件的可能值来指定下一个事件的概率分布。 - 为了构建马尔可夫链,我们需要一个过渡模型,该模型将根据当前事件的可能值来指定下一个事件的概率分布。
@@ -401,9 +401,9 @@ print(model.sample(50))
- 基于隐马尔科夫模型,可以实现多种任务: - 基于隐马尔科夫模型,可以实现多种任务:
- 筛选 Filtering: 给定从开始到现在的观察结果,计算出<strong>当前</strong>状态的概率分布。例如,给从从特定时间开始到今天人们带伞的信息,我们产生一个今天是否下雨的概率分布。 - 筛选 Filtering: 给定从开始到现在的观察结果,计算出**当前**状态的概率分布。例如,给从从特定时间开始到今天人们带伞的信息,我们产生一个今天是否下雨的概率分布。
- 预测 Prediction: 给定从开始到现在的观察,计算<strong>未来</strong>状态的概率分布。 - 预测 Prediction: 给定从开始到现在的观察,计算**未来**状态的概率分布。
- 平滑化 Smoothing: 给定从开始到现在的观察,计算<strong>过去</strong>状态的概率分布。例如,鉴于今天人们带了雨伞,计算昨天下雨的概率。 - 平滑化 Smoothing: 给定从开始到现在的观察,计算**过去**状态的概率分布。例如,鉴于今天人们带了雨伞,计算昨天下雨的概率。
- 最可能的解释 Most likely explanation: 鉴于从开始到现在的观察,计算最可能的事件顺序。 - 最可能的解释 Most likely explanation: 鉴于从开始到现在的观察,计算最可能的事件顺序。
- 最可能的解释任务可用于语音识别等过程,根据多个波形,人工智能推断出给这些波形带来的最有可能的单词或音节的序列。接下来是一个隐马尔科夫模型的 Python 实现,我们将用于最可能的解释任务: - 最可能的解释任务可用于语音识别等过程,根据多个波形,人工智能推断出给这些波形带来的最有可能的单词或音节的序列。接下来是一个隐马尔科夫模型的 Python 实现,我们将用于最可能的解释任务:

View File

@@ -1,6 +1,6 @@
# 你可能会需要的术语介绍 # 你可能会需要的术语介绍
众所周知一个领域的黑话对新人来说是比较不友好的为此我从知乎上找了一篇黑话大赏bushi做了点改良放在这里。如果遇到看不懂的词了可以来这找找。<strong>在系统学习之前可以先无视这篇文章,遇到问题再来找找</strong><u>。</u> 众所周知一个领域的黑话对新人来说是比较不友好的为此我从知乎上找了一篇黑话大赏bushi做了点改良放在这里。如果遇到看不懂的词了可以来这找找。**在系统学习之前可以先无视这篇文章,遇到问题再来找找**<u>。</u>
> 作者Young<br/>链接:[https://www.zhihu.com/question/469612040/answer/2008770105](https://www.zhihu.com/question/469612040/answer/2008770105)<br/>来源:知乎 > 作者Young<br/>链接:[https://www.zhihu.com/question/469612040/answer/2008770105](https://www.zhihu.com/question/469612040/answer/2008770105)<br/>来源:知乎
@@ -38,7 +38,7 @@
- 体素:我把世界变成 MC 了,世界是一堆方块,他们在不同视角下有各自的颜色和透明度 - 体素:我把世界变成 MC 了,世界是一堆方块,他们在不同视角下有各自的颜色和透明度
- 点云:我每采样一次得到一个点,由这些点去表示我要的物体,不太直观,来张图 - 点云:我每采样一次得到一个点,由这些点去表示我要的物体,不太直观,来张图
这是我用照片重建的独角兽<strong>稀疏</strong>点云,红色的不用管,是照相机视角(图不够多,巨糊) 这是我用照片重建的独角兽**稀疏**点云,红色的不用管,是照相机视角(图不够多,巨糊)
![](https://cdn.xyxsw.site/boxcnWx8hYfT6kFug4A1iA3uftg.png) ![](https://cdn.xyxsw.site/boxcnWx8hYfT6kFug4A1iA3uftg.png)

View File

@@ -1,6 +1,6 @@
# 深度学习快速入门 # 深度学习快速入门
## <strong>刘二大人(Pytorch)</strong> ## **刘二大人(Pytorch)**
## 速成课:人工智能 ## 速成课:人工智能
[【速成课人工智能】Ai - [21 集全/中英双语] - Artificial Intelligence_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1P7411r7Dw) [【速成课人工智能】Ai - [21 集全/中英双语] - Artificial Intelligence_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1P7411r7Dw)
@@ -62,7 +62,7 @@ Crash course 的课程可以基本了解pytorch的内容但是当然有很
## torch 我还不会呢! ## torch 我还不会呢!
学会一个<strong>庞大并且高度封装</strong>的包并不是一蹴而就的,我们建议从实践开始,比如说自己搭建一个神经网络来实现 MNIST 的分类。在使用这些函数和类的过程中你能更快地掌握它们的方法。 学会一个**庞大并且高度封装**的包并不是一蹴而就的,我们建议从实践开始,比如说自己搭建一个神经网络来实现 MNIST 的分类。在使用这些函数和类的过程中你能更快地掌握它们的方法。
# 关于梯度下降算法: # 关于梯度下降算法:
@@ -103,12 +103,12 @@ Crash course 的课程可以基本了解pytorch的内容但是当然有很
# 接下来干什么? # 接下来干什么?
- <strong>我想学 CV !!!!!!</strong> - **我想学 CV !!!!!!**
你可以在 CV 模块中找到[4.6.5.3CV中的经典网络](4.6.5.3CV%E4%B8%AD%E7%9A%84%E7%BB%8F%E5%85%B8%E7%BD%91%E7%BB%9C.md) ,这里是一些最最经典的论文,我们推荐你阅读它们的原文并且复现它们的代码,这可以同时锻炼你的<strong>coding 能力和论文阅读能力</strong>,在阅读前,请参见[如何读论文](../1.%E6%9D%AD%E7%94%B5%E7%94%9F%E5%AD%98%E6%8C%87%E5%8D%97/1.10%E5%A6%82%E4%BD%95%E8%AF%BB%E8%AE%BA%E6%96%87.md) 。本模块的撰写者<strong>SRT 社团</strong>主要从事 CV 方向的研究,遇到问题欢迎与我们交流。(你都完成这些了不至于找不到我们的联系方式吧~<strong>如果你读完了经典网络模块,你可以在它的最后找到接下来的学习路线~</strong> 你可以在 CV 模块中找到[4.6.5.3CV中的经典网络](4.6.5.3CV%E4%B8%AD%E7%9A%84%E7%BB%8F%E5%85%B8%E7%BD%91%E7%BB%9C.md) ,这里是一些最最经典的论文,我们推荐你阅读它们的原文并且复现它们的代码,这可以同时锻炼你的**coding 能力和论文阅读能力**,在阅读前,请参见[如何读论文](../1.%E6%9D%AD%E7%94%B5%E7%94%9F%E5%AD%98%E6%8C%87%E5%8D%97/1.10%E5%A6%82%E4%BD%95%E8%AF%BB%E8%AE%BA%E6%96%87.md) 。本模块的撰写者**SRT 社团**主要从事 CV 方向的研究,遇到问题欢迎与我们交流。(你都完成这些了不至于找不到我们的联系方式吧~**如果你读完了经典网络模块,你可以在它的最后找到接下来的学习路线~**
- <strong>我想做</strong><strong>NLP</strong><strong> !!!!!!</strong> - **我想做****NLP**** !!!!!!**
NLP 研究方向庞大且复杂,若直接从 GPT 系列开始不免有些过于困难。我们建议你从了解 NLP 的任务开始,在有足够的基础后开始学习 RNNLSTM 基准方法后向 [4.6.7Transformer](4.6.7Transformer.md) 进发 ,这个方法广泛运用在几乎所有深度学习领域,尤其是 NLP 的前沿研究已经无法离开 Transformer 了 hhhh。这个模块中我们也加入了一些 Transformer 的改进工作,包括 NLPCV和多模态 NLP 研究方向庞大且复杂,若直接从 GPT 系列开始不免有些过于困难。我们建议你从了解 NLP 的任务开始,在有足够的基础后开始学习 RNNLSTM 基准方法后向 [4.6.7Transformer](4.6.7Transformer.md) 进发 ,这个方法广泛运用在几乎所有深度学习领域,尤其是 NLP 的前沿研究已经无法离开 Transformer 了 hhhh。这个模块中我们也加入了一些 Transformer 的改进工作,包括 NLPCV和多模态
- <strong>如果你想做多模态,对比学习等</strong>,请同时了解 CV 和 NLP 模块。这将是你后续知识的基础。多模态我们没有完善的讲义推出,对比学习可以参见[4.6.8对比学习](4.6.8%E5%AF%B9%E6%AF%94%E5%AD%A6%E4%B9%A0.md) 。这是撰写者之一的论文阅读笔记,不保证准确性与理解是否准确,可以作为论文阅读路线图来参考~ - **如果你想做多模态,对比学习等**,请同时了解 CV 和 NLP 模块。这将是你后续知识的基础。多模态我们没有完善的讲义推出,对比学习可以参见[4.6.8对比学习](4.6.8%E5%AF%B9%E6%AF%94%E5%AD%A6%E4%B9%A0.md) 。这是撰写者之一的论文阅读笔记,不保证准确性与理解是否准确,可以作为论文阅读路线图来参考~

View File

@@ -4,11 +4,11 @@
![](https://cdn.xyxsw.site/boxcnTUlm8EI0byGJJQ78IqGWGx.png) ![](https://cdn.xyxsw.site/boxcnTUlm8EI0byGJJQ78IqGWGx.png)
#### aImage classification <strong>图像分类</strong> #### aImage classification **图像分类**
- 识别这个图片整体所属的类别,解决的是"what"问题,给这个图片打上相应的标签,在 a 图内标签是 `bottlecupcube`,其他类型的图片也都有它们自己的标签,然后把这些打上标签的图片带进网络结构里作为训练集训练。 - 识别这个图片整体所属的类别,解决的是"what"问题,给这个图片打上相应的标签,在 a 图内标签是 `bottlecupcube`,其他类型的图片也都有它们自己的标签,然后把这些打上标签的图片带进网络结构里作为训练集训练。
#### bObject localization <strong>目标检测</strong>(对象定位) #### bObject localization **目标检测**(对象定位)
- 识别图片中各个物体所在的位置,解决的是"where"问题,此处还细分两个问题: - 识别图片中各个物体所在的位置,解决的是"where"问题,此处还细分两个问题:
@@ -20,12 +20,12 @@
![](https://cdn.xyxsw.site/boxcnoyxKL4bOeYOOjrh6it0BHd.gif) ![](https://cdn.xyxsw.site/boxcnoyxKL4bOeYOOjrh6it0BHd.gif)
#### cSemantic segmentation <strong>语义分割</strong> #### cSemantic segmentation **语义分割**
- 语义分割需要进一步判断图像中哪些像素属于哪个目标(进阶目标检测)。 - 语义分割需要进一步判断图像中哪些像素属于哪个目标(进阶目标检测)。
- 看图右下角两个 `cube` 是连在一块的 并没有分出哪一部分是哪一个的 `cube` - 看图右下角两个 `cube` 是连在一块的 并没有分出哪一部分是哪一个的 `cube`
#### dInstance segmentation <strong>实例分割</strong> #### dInstance segmentation **实例分割**
- 实例分割需要区分出哪些像素属于第一个物体、哪些像素属于第二个物体,即目标检测 + 语义分割。 - 实例分割需要区分出哪些像素属于第一个物体、哪些像素属于第二个物体,即目标检测 + 语义分割。
- 看图右下角两个 `cube` 是分开的 - 看图右下角两个 `cube` 是分开的

View File

@@ -107,7 +107,7 @@ One batch tensor data: [tensor([[ 0.9451, -0.4923, -1.8178],
- shufflebool 类型,在每个 epoch 开始的时候,是否对数据进行重新打乱; - shufflebool 类型,在每个 epoch 开始的时候,是否对数据进行重新打乱;
- num_workersint 类型加载数据的进程数0 意味着所有的数据都会被加载进主进程,默认为 0。 - num_workersint 类型加载数据的进程数0 意味着所有的数据都会被加载进主进程,默认为 0。
<strong>思考题</strong> **思考题**
按照上述代码One batch tensor data 的输出是否正确,若不正确,为什么? 按照上述代码One batch tensor data 的输出是否正确,若不正确,为什么?

View File

@@ -58,7 +58,7 @@ print(type(img2))
''' '''
``` ```
首先用读取图片,查看一下图片的类型为 PIL.JpegImagePlugin.JpegImageFile这里需要注意<strong>PIL.JpegImagePlugin.JpegImageFile 类是 PIL.Image.Image 类的子类</strong>。然后,用 transforms.ToTensor() 将 PIL.Image 转换为 Tensor。最后再将 Tensor 转换回 PIL.Image。 首先用读取图片,查看一下图片的类型为 PIL.JpegImagePlugin.JpegImageFile这里需要注意**PIL.JpegImagePlugin.JpegImageFile 类是 PIL.Image.Image 类的子类**。然后,用 transforms.ToTensor() 将 PIL.Image 转换为 Tensor。最后再将 Tensor 转换回 PIL.Image。
## 对 PIL.Image 和 Tensor 进行变换 ## 对 PIL.Image 和 Tensor 进行变换
@@ -202,7 +202,7 @@ display(img2)
标准化是指每一个数据点减去所在通道的平均值再除以所在通道的标准差数学的计算公式output=(inputmean)/std 标准化是指每一个数据点减去所在通道的平均值再除以所在通道的标准差数学的计算公式output=(inputmean)/std
而对图像进行标准化,就是对图像的每个通道利用均值和标准差进行正则化。这样做的目的,是<strong>为了保证数据集中所有的图像分布都相似,这样在训练的时候更容易收敛,既加快了训练速度,也提高了训练效果</strong> 而对图像进行标准化,就是对图像的每个通道利用均值和标准差进行正则化。这样做的目的,是**为了保证数据集中所有的图像分布都相似,这样在训练的时候更容易收敛,既加快了训练速度,也提高了训练效果**
让我来解释一下:首先,标准化是一个常规做法,可以理解为无脑进行标准化后再训练的效果,大概率要好于不进行标准化。 让我来解释一下:首先,标准化是一个常规做法,可以理解为无脑进行标准化后再训练的效果,大概率要好于不进行标准化。

View File

@@ -10,17 +10,17 @@ AlexNet 有 6 千万个参数和 650,000 个神经元。
[论文](http://www.cs.toronto.edu/~fritz/absps/imagenet.pdf) [论文](http://www.cs.toronto.edu/~fritz/absps/imagenet.pdf)
### <strong>网络框架图</strong> ### **网络框架图**
![](https://cdn.xyxsw.site/boxcng0jB2dmDD18EwU8nAIFPIc.png) ![](https://cdn.xyxsw.site/boxcng0jB2dmDD18EwU8nAIFPIc.png)
### <strong>使用 ReLU 激活函数代替 tanh</strong> ### **使用 ReLU 激活函数代替 tanh**
在当时,标准的神经元激活函数是 tanh()函数,这种饱和的非线性函数在梯度下降的时候要比非饱和的非线性函数慢得多,因此,在 AlexNet 中使用 ReLU 函数作为激活函数。 在当时,标准的神经元激活函数是 tanh()函数,这种饱和的非线性函数在梯度下降的时候要比非饱和的非线性函数慢得多,因此,在 AlexNet 中使用 ReLU 函数作为激活函数。
![](https://cdn.xyxsw.site/boxcnFlENdpKXUR7l4MhUXFKzfg.png) ![](https://cdn.xyxsw.site/boxcnFlENdpKXUR7l4MhUXFKzfg.png)
### <strong>采用 Dropout 防止过拟合</strong> ### **采用 Dropout 防止过拟合**
dropout 方法会遍历网络的每一层,并设置消除神经网络中节点的概率。假设网络中的每一层,每个节点都以抛硬币的方式设置概率,每个节点得以保留和消除的概率都是 0.5,设置完节点概率,我们会消除一些节点,然后删除掉从该节点进出的连线,最后得到一个节点更少,规模更小的网络(如下图所示),然后再用反向传播方法进行训练。 dropout 方法会遍历网络的每一层,并设置消除神经网络中节点的概率。假设网络中的每一层,每个节点都以抛硬币的方式设置概率,每个节点得以保留和消除的概率都是 0.5,设置完节点概率,我们会消除一些节点,然后删除掉从该节点进出的连线,最后得到一个节点更少,规模更小的网络(如下图所示),然后再用反向传播方法进行训练。
@@ -32,7 +32,7 @@ dropout 方法会遍历网络的每一层,并设置消除神经网络中节点
### ###
### <strong>视频讲解</strong> ### **视频讲解**
# 思考 # 思考
@@ -40,7 +40,7 @@ dropout 方法会遍历网络的每一层,并设置消除神经网络中节点
AlexNet 中有着卷积和 MLP 两种不同的网络结构,那两者之间有着何种区别和联系呢?(可以从两者的权值矩阵去思考) AlexNet 中有着卷积和 MLP 两种不同的网络结构,那两者之间有着何种区别和联系呢?(可以从两者的权值矩阵去思考)
### <strong>思考 2</strong> ### **思考 2**
卷积中有一个叫感受野的概念,是什么意思呢?不同的感受野对网络有什么影响? 卷积中有一个叫感受野的概念,是什么意思呢?不同的感受野对网络有什么影响?

View File

@@ -2,7 +2,7 @@
图像分割领域的开山之作。 图像分割领域的开山之作。
首次将<strong>End-to-End</strong>的思想应用在了 CV 领域。 首次将**End-to-End**的思想应用在了 CV 领域。
[知乎](https://zhuanlan.zhihu.com/p/30195134) [知乎](https://zhuanlan.zhihu.com/p/30195134)
@@ -18,7 +18,7 @@
FCN 对图像进行像素级的分类,从而解决了语义级别的图像分割问题。与经典的 CNN 在卷积层之后使用全连接层得到固定长度的特征向量进行分类不同FCN 可以接受任意尺寸的输入图像,采用反卷积层对最后一个卷积层的 feature map 进行上采样, 使它恢复到输入图像相同的尺寸,从而可以对每个像素都产生了一个预测, 同时保留了原始输入图像中的空间信息, 最后在上采样的特征图上进行逐像素分类。 FCN 对图像进行像素级的分类,从而解决了语义级别的图像分割问题。与经典的 CNN 在卷积层之后使用全连接层得到固定长度的特征向量进行分类不同FCN 可以接受任意尺寸的输入图像,采用反卷积层对最后一个卷积层的 feature map 进行上采样, 使它恢复到输入图像相同的尺寸,从而可以对每个像素都产生了一个预测, 同时保留了原始输入图像中的空间信息, 最后在上采样的特征图上进行逐像素分类。
<strong>简单的来说FCN 与 CNN 的区域在把于 CNN 最后的全连接层换成卷积层,输出的是一张已经 Label 好的图片。</strong> **简单的来说FCN 与 CNN 的区域在把于 CNN 最后的全连接层换成卷积层,输出的是一张已经 Label 好的图片。**
### 反卷积 ### 反卷积

View File

@@ -8,13 +8,13 @@ NeRF 想做这样一件事,不需要中间三维重建的过程,仅根据位
![](https://cdn.xyxsw.site/boxcn6jg09V944MU1sBsstmdaib.png) ![](https://cdn.xyxsw.site/boxcn6jg09V944MU1sBsstmdaib.png)
你可以看到,这 100 张图片是对一个乐高推土机的多角度拍摄结果。我们需要的是一个可<strong>以获取这个推土机在任意角度下拍摄的图片</strong>的模型。如图所示: 你可以看到,这 100 张图片是对一个乐高推土机的多角度拍摄结果。我们需要的是一个可**以获取这个推土机在任意角度下拍摄的图片**的模型。如图所示:
![](https://cdn.xyxsw.site/boxcnLEEyuUWOwiJOePhmmsAakd.gif) ![](https://cdn.xyxsw.site/boxcnLEEyuUWOwiJOePhmmsAakd.gif)
现在来看 NeRF 网络: 现在来看 NeRF 网络:
在 NeRF 中,我们把空间<strong>认为是一个个的小方块叠成的空间</strong>(可以理解为 MC)每一个方块有以下属性: 在 NeRF 中,我们把空间**认为是一个个的小方块叠成的空间**(可以理解为 MC)每一个方块有以下属性:
- 3 个位置坐标(x,y,z) - 3 个位置坐标(x,y,z)
- 透明度$\sigma$ - 透明度$\sigma$
@@ -24,27 +24,27 @@ NeRF 想做这样一件事,不需要中间三维重建的过程,仅根据位
## 得到模型 ## 得到模型
我们需要的是每个视角下的图片,可以理解为从一个视角发射<strong>光线</strong><u>一根光线对应一个像素点</u>。这些光线穿透路径上的所有方块,把这些方块上的属性信息以某种方式累计,就能得到这个像素的颜色。这是 一个已有的公式,只要我们获得每个小方块的颜色信息和不透明度,我们就能知道这个角度下的视图。(这个我们后面介绍) 我们需要的是每个视角下的图片,可以理解为从一个视角发射**光线**<u>一根光线对应一个像素点</u>。这些光线穿透路径上的所有方块,把这些方块上的属性信息以某种方式累计,就能得到这个像素的颜色。这是 一个已有的公式,只要我们获得每个小方块的颜色信息和不透明度,我们就能知道这个角度下的视图。(这个我们后面介绍)
现在的难点在于:我们不知道<strong>每个小方块的颜色信息</strong>(因为颜色会随着观察角度变化)。众所周知,算法解决不了的问题就扔给神经网络试试啦~ 现在的难点在于:我们不知道**每个小方块的颜色信息**(因为颜色会随着观察角度变化)。众所周知,算法解决不了的问题就扔给神经网络试试啦~
<strong>为了获取根据角度变化而变化的颜色信息,我们选择了神经网络。</strong> **为了获取根据角度变化而变化的颜色信息,我们选择了神经网络。**
<strong>这个网络的输入是:</strong> **这个网络的输入是:**
- 小方块的位置坐标(x,y,z) - 小方块的位置坐标(x,y,z)
- 观察角度(以二维坐标表示两个偏转角) - 观察角度(以二维坐标表示两个偏转角)
<strong>这个网络的输出是:</strong> **这个网络的输出是:**
- 对应的小方块的 RGB 信息 - 对应的小方块的 RGB 信息
- 不透明度 - 不透明度
![](https://cdn.xyxsw.site/boxcni4q9Cp8G7H9HjKMrfImcZe.jpg) ![](https://cdn.xyxsw.site/boxcni4q9Cp8G7H9HjKMrfImcZe.jpg)
在这里,作者选择了最简单的 MLP因此<strong>这是一个输入为 5 维,输出为 4 维向量</strong>($R,G,B,\sigma$)的简单网络,值得注意的是,不透明度与观察角度无关,这里在网络中进行了特殊处理,让这个值与后两维无关。 在这里,作者选择了最简单的 MLP因此**这是一个输入为 5 维,输出为 4 维向量**($R,G,B,\sigma$)的简单网络,值得注意的是,不透明度与观察角度无关,这里在网络中进行了特殊处理,让这个值与后两维无关。
<strong>现在我们能够输入坐标和视角信息得到小方块的颜色和不透明度,我们就可以对光线穿过的小方块进行计算了。</strong> **现在我们能够输入坐标和视角信息得到小方块的颜色和不透明度,我们就可以对光线穿过的小方块进行计算了。**
## 进行渲染 ## 进行渲染
@@ -54,9 +54,9 @@ NeRF 想做这样一件事,不需要中间三维重建的过程,仅根据位
这个公式对光线上的所有小方块的颜色进行加权求和,权重是关于不透明度$\sigma$的一个函数$T(\sigma)$,不透明度在[0,1]之间,越不透明这个值越大。也就是越不透明,占的颜色比重越高,比如空气的$\sigma$就接近于 0乐高本身就接近 1。而求和的结果就是这个光线对应像素的颜色。 这个公式对光线上的所有小方块的颜色进行加权求和,权重是关于不透明度$\sigma$的一个函数$T(\sigma)$,不透明度在[0,1]之间,越不透明这个值越大。也就是越不透明,占的颜色比重越高,比如空气的$\sigma$就接近于 0乐高本身就接近 1。而求和的结果就是这个光线对应像素的颜色。
这里展开说一下$T(\sigma)$,我们把不透明度理解为光线在这个小方块被阻止的概率,越不透明,越容易阻挡光线,而光线一旦被阻挡,就不用计算后面的小方块颜色了。因此,我们的$T(\sigma)$就表示<strong>光线能够行进到这个小方块的概率</strong>,也就是这点之前所有小方块的$(1-\sigma)$的乘积。 这里展开说一下$T(\sigma)$,我们把不透明度理解为光线在这个小方块被阻止的概率,越不透明,越容易阻挡光线,而光线一旦被阻挡,就不用计算后面的小方块颜色了。因此,我们的$T(\sigma)$就表示**光线能够行进到这个小方块的概率**,也就是这点之前所有小方块的$(1-\sigma)$的乘积。
这段要仔细看和推导,第一遍不容易直接懂。顺带一提,我们的<strong>小方块</strong>学名叫<strong>体素</strong><del>为了显得我们更专业一点以后就叫它体素罢</del> 这段要仔细看和推导,第一遍不容易直接懂。顺带一提,我们的**小方块**学名叫**体素**<del>为了显得我们更专业一点以后就叫它体素罢</del>
![](https://cdn.xyxsw.site/boxcnnwHy3Hlhbu2bOsi6r2BYJe.png) ![](https://cdn.xyxsw.site/boxcnnwHy3Hlhbu2bOsi6r2BYJe.png)
@@ -84,7 +84,7 @@ NeRF 想做这样一件事,不需要中间三维重建的过程,仅根据位
我们使用了两个网络:粗网络和精细网络。 我们使用了两个网络:粗网络和精细网络。
粗网络就是上述采样方法用的普通网络,而<strong>粗网络输出的不透明度值会被作为一个概率分布函数</strong>,精细网络根据这个概率分布在光线上进行采样,不透明度越大的点,它的邻域被采样的概率越大,也就实现了我们要求的在实体上多采样,空气中少采样。最后精细网络输出作为结果,因此粗网络可以只求不透明度,无视颜色信息。 粗网络就是上述采样方法用的普通网络,而**粗网络输出的不透明度值会被作为一个概率分布函数**,精细网络根据这个概率分布在光线上进行采样,不透明度越大的点,它的邻域被采样的概率越大,也就实现了我们要求的在实体上多采样,空气中少采样。最后精细网络输出作为结果,因此粗网络可以只求不透明度,无视颜色信息。
![](https://cdn.xyxsw.site/boxcnwl72wntQgYMFvRPTWY5fPf.png) ![](https://cdn.xyxsw.site/boxcnwl72wntQgYMFvRPTWY5fPf.png)

View File

@@ -10,19 +10,19 @@
### 1.Pixel-nerf ### 1.Pixel-nerf
<strong>Pixel-nerf</strong><strong> </strong>对输入图像使用卷积进行特征提取再执行 nerf若有多个输入对每个视角都执行 CNN在计算光线时取每一个已有视角下该坐标的特征经过 mlp 后算平均。可以在少量视角下重建视图,需要进行预训练才能使用,有一定自动补全能力(有限) **Pixel-nerf**** **对输入图像使用卷积进行特征提取再执行 nerf若有多个输入对每个视角都执行 CNN在计算光线时取每一个已有视角下该坐标的特征经过 mlp 后算平均。可以在少量视角下重建视图,需要进行预训练才能使用,有一定自动补全能力(有限)
![](https://cdn.xyxsw.site/boxcnEiUODOd4FOBxYIZmmihyef.png) ![](https://cdn.xyxsw.site/boxcnEiUODOd4FOBxYIZmmihyef.png)
### 2.IBRnet ### 2.IBRnet
<strong>IBRnet</strong><strong> </strong>是 pixel-nerf 的改进版,取消了 CNN并且在 mlp 后接入了 transformer 结构处理体密度(不透明度),对这条光线上所有的采样点进行一个 transformer。同时在获取某个体素的颜色和密度时作者用了本视角相邻的两个视角获取对应体素在这两张图片中的像素以图片像素颜色视角图片特征作为 mlp 的输入。 **IBRnet**** **是 pixel-nerf 的改进版,取消了 CNN并且在 mlp 后接入了 transformer 结构处理体密度(不透明度),对这条光线上所有的采样点进行一个 transformer。同时在获取某个体素的颜色和密度时作者用了本视角相邻的两个视角获取对应体素在这两张图片中的像素以图片像素颜色视角图片特征作为 mlp 的输入。
![](https://cdn.xyxsw.site/boxcnwH75jIO9NiVwQaBqDrbe8e.png) ![](https://cdn.xyxsw.site/boxcnwH75jIO9NiVwQaBqDrbe8e.png)
### 3.MVSnerf ### 3.MVSnerf
<strong>MVSnerf</strong><strong> </strong>它用 MVS 的方法构建代价体然后在后面接了一个 nerfMVS 是使用<strong>多视角立体匹配</strong>构建一个代价体,用 3D 卷积网络进行优化,这里对代价体进行 nerf 采样,可以得到可泛化网络。它需要 15min 的微调才能在新数据上使用。<strong>多视角立体匹配是一种传统算法,通过光线,几何等信息计算图像中小块的相似度,得出两个相机视角之间的位置关系。这个算法也被广泛使用在得到我们自己采样的数据的相机变换矩阵上(我就是这么干的)</strong> **MVSnerf**** **它用 MVS 的方法构建代价体然后在后面接了一个 nerfMVS 是使用**多视角立体匹配**构建一个代价体,用 3D 卷积网络进行优化,这里对代价体进行 nerf 采样,可以得到可泛化网络。它需要 15min 的微调才能在新数据上使用。**多视角立体匹配是一种传统算法,通过光线,几何等信息计算图像中小块的相似度,得出两个相机视角之间的位置关系。这个算法也被广泛使用在得到我们自己采样的数据的相机变换矩阵上(我就是这么干的)**
![](https://cdn.xyxsw.site/boxcnbd2YxumunZR9LZG3ANrPrb.png) ![](https://cdn.xyxsw.site/boxcnbd2YxumunZR9LZG3ANrPrb.png)
@@ -45,13 +45,13 @@
## 2)可以 zero-shot 或者 fine-tune 类 ## 2)可以 zero-shot 或者 fine-tune 类
<strong>MVSnerf</strong><strong>,上面已经说了。</strong> **MVSnerf****,上面已经说了。**
# 2.速度提升 # 2.速度提升
### 1.instan-ngp ### 1.instan-ngp
使用了<strong>哈希表</strong>结构的<strong>instant-ngp</strong>,渲染完美只需要几分钟(采样正常的情况下)这块的速度已经到极致了。 使用了**哈希表**结构的**instant-ngp**,渲染完美只需要几分钟(采样正常的情况下)这块的速度已经到极致了。
展开说说其实这也是神经网络发展的一个方向以前的深层网络倾向于把所有东西用网络参数表示这样推理速度就会慢这里使用哈希表的快速查找能力存储一些数据信息instant-ngp 就是把要表达的模型数据特征按照不同的精细度存在哈希表中,使用时通过哈希表调用或插值调用。 展开说说其实这也是神经网络发展的一个方向以前的深层网络倾向于把所有东西用网络参数表示这样推理速度就会慢这里使用哈希表的快速查找能力存储一些数据信息instant-ngp 就是把要表达的模型数据特征按照不同的精细度存在哈希表中,使用时通过哈希表调用或插值调用。
@@ -61,15 +61,15 @@
### 1.Human-nerf ### 1.Human-nerf
<strong>Human-nerf</strong><strong> </strong>生成可编辑的人体运动视频建模,输入是一段人随便动动的视频。输出的动作可以编辑修改,并且对衣物折叠等有一定优化。使用的模型并非全隐式的,并且对头发和衣物单独使用变换模型。使用了逆线性蒙皮模型提取人物骨骼(可学习的模型),上面那个蓝色的就是姿态矫正模块,这个模块赋予骨骼之间运动关系的权重(因为使用的是插值处理同一运动时不同骨骼的平移旋转矩阵,一块骨骼动会牵动其他骨骼)图中的 Ω 就是权重的集合,它通过 mlp 学习得到。然后得到显式表达的人物骨骼以及传入视频中得到的对应骨骼的 meshskeletal motion 就是做游戏人物动作用的编辑器这种,后面残差链接了一个 non-rigid-motion非刚性动作这个是专门处理衣物和毛发的主要通过学习得到然后粗暴的加起来就能得到模型再经过传统的 nerf 渲染出图像。 **Human-nerf**** **生成可编辑的人体运动视频建模,输入是一段人随便动动的视频。输出的动作可以编辑修改,并且对衣物折叠等有一定优化。使用的模型并非全隐式的,并且对头发和衣物单独使用变换模型。使用了逆线性蒙皮模型提取人物骨骼(可学习的模型),上面那个蓝色的就是姿态矫正模块,这个模块赋予骨骼之间运动关系的权重(因为使用的是插值处理同一运动时不同骨骼的平移旋转矩阵,一块骨骼动会牵动其他骨骼)图中的 Ω 就是权重的集合,它通过 mlp 学习得到。然后得到显式表达的人物骨骼以及传入视频中得到的对应骨骼的 meshskeletal motion 就是做游戏人物动作用的编辑器这种,后面残差链接了一个 non-rigid-motion非刚性动作这个是专门处理衣物和毛发的主要通过学习得到然后粗暴的加起来就能得到模型再经过传统的 nerf 渲染出图像。
![](https://cdn.xyxsw.site/boxcnHRnNXHvwVXrRmM8wnl53p9.png) ![](https://cdn.xyxsw.site/boxcnHRnNXHvwVXrRmM8wnl53p9.png)
### 2.Neural Body ### 2.Neural Body
<strong>Neural Body</strong> 通过下面这种<strong>单视角视频</strong>或稀<strong>疏视角照片</strong>来生成人体建模。 **Neural Body** 通过下面这种**单视角视频**或稀**疏视角照片**来生成人体建模。
因为生成的是人体建模,作者使用了他们以前的工作 EasyMocap 得到<strong>SMPL 模型(就是人体的结构)然后在 SMPL 表面生成一些 latent code包含颜色不透明度和位置也就是下左中的那些点。</strong> 因为生成的是人体建模,作者使用了他们以前的工作 EasyMocap 得到**SMPL 模型(就是人体的结构)然后在 SMPL 表面生成一些 latent code包含颜色不透明度和位置也就是下左中的那些点。**
[EasyMocap 的代码](https://link.zhihu.com/?target=https%3A//github.com/zju3dv/EasyMocap) [EasyMocap 的代码](https://link.zhihu.com/?target=https%3A//github.com/zju3dv/EasyMocap)
@@ -85,25 +85,25 @@ EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作
个人感觉这个模型不能很好处理光影效果,还有待改进。 个人感觉这个模型不能很好处理光影效果,还有待改进。
是个预训练模型,<strong>训练的模块就是这个 3D 卷积神经网络</strong> 是个预训练模型,**训练的模块就是这个 3D 卷积神经网络**
![](https://cdn.xyxsw.site/boxcnbclBwg3BsubGOrt8vZf0qb.png) ![](https://cdn.xyxsw.site/boxcnbclBwg3BsubGOrt8vZf0qb.png)
### 3.wild-nerf ### 3.wild-nerf
<strong>wild-nerf</strong> 思路很简单,就是加入了新的输入参数来调整白天黑夜等等一些简单的变化,并且把行人车辆之类的在采样过程中<strong>不固定的物品</strong>作为<strong>随机项</strong>,在渲染时按照概率加入。 **wild-nerf** 思路很简单,就是加入了新的输入参数来调整白天黑夜等等一些简单的变化,并且把行人车辆之类的在采样过程中**不固定的物品**作为**随机项**,在渲染时按照概率加入。
### 4.D-nerf ### 4.D-nerf
<strong>D-nerf</strong> 是一种动态编辑的 nerf输入为x,y,z,相机位置,相机角度,<strong>时间 t。</strong> **D-nerf** 是一种动态编辑的 nerf输入为x,y,z,相机位置,相机角度,**时间 t。**
把整个网络分为两块,一块是正常的 nerf 渲染,另一块是下面这个,输入时间与现在的位置坐标,输出<strong>这个位置坐标中的物体现在的位置</strong>与 t=0 时的<strong>位置的差</strong>。再用 t=0 时物体的点信息进行渲染。 把整个网络分为两块,一块是正常的 nerf 渲染,另一块是下面这个,输入时间与现在的位置坐标,输出**这个位置坐标中的物体现在的位置**与 t=0 时的**位置的差**。再用 t=0 时物体的点信息进行渲染。
在此网络的单个输出上貌似是不监督的,因为没办法进行人为标注。这点我不是很确定,以后如果发现了会来修改的。 在此网络的单个输出上貌似是不监督的,因为没办法进行人为标注。这点我不是很确定,以后如果发现了会来修改的。
![](https://cdn.xyxsw.site/boxcnYeaiioqtFzQlztsTwiEpzg.png) ![](https://cdn.xyxsw.site/boxcnYeaiioqtFzQlztsTwiEpzg.png)
渲染经过形变的物体时,光线其实是在 t=0 时刻进行渲染的,因为推土机的铲子放下去了,所以<strong>光线是弯曲的</strong> 渲染经过形变的物体时,光线其实是在 t=0 时刻进行渲染的,因为推土机的铲子放下去了,所以**光线是弯曲的**
![](https://cdn.xyxsw.site/boxcng7xDooDmmpbCJRyLJBucwe.png) ![](https://cdn.xyxsw.site/boxcng7xDooDmmpbCJRyLJBucwe.png)
@@ -115,13 +115,13 @@ EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作
### 1.clip-nerf ### 1.clip-nerf
<strong>clip-nerf</strong><strong> 太贵了玩不起,没仔细研究,应该是文本跟 3D 建模关联,跟 clip 一样。</strong> **clip-nerf**** 太贵了玩不起,没仔细研究,应该是文本跟 3D 建模关联,跟 clip 一样。**
# 6.生成类(指加入新物体或者额外生成新场景) # 6.生成类(指加入新物体或者额外生成新场景)
### 1.GRAF ### 1.GRAF
<strong>GRAF</strong><strong> </strong>把 GAN 与 nerf 结合,增加了两个输入,分别是<strong>外观/形状编码 z</strong>和<strong>2D 采样编码 v</strong>z 用来改变渲染出来东西的特征比如把生成的车变色或者变牌子suv 变老爷车之类的。v(s,u)用来改变下图 2 中训练时选择光线的标准。这里训练时不是拿 G 生成的整张图扔进 D 网络,而是根据 v 的参数选择一些光线组成的 batch 扔进 D 进行辨别 **GRAF**** **把 GAN 与 nerf 结合,增加了两个输入,分别是**外观/形状编码 z**和**2D 采样编码 v**z 用来改变渲染出来东西的特征比如把生成的车变色或者变牌子suv 变老爷车之类的。v(s,u)用来改变下图 2 中训练时选择光线的标准。这里训练时不是拿 G 生成的整张图扔进 D 网络,而是根据 v 的参数选择一些光线组成的 batch 扔进 D 进行辨别
![](https://cdn.xyxsw.site/boxcnVyFqHIoA2MGGc4JJo9tObh.png) ![](https://cdn.xyxsw.site/boxcnVyFqHIoA2MGGc4JJo9tObh.png)
@@ -129,7 +129,7 @@ EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作
### 2.GIRAFFE ### 2.GIRAFFE
<strong>GIRAFFE</strong> 是 GRAF 的改进工作,可以把图片中的物品,背景一个个解耦出来单独进行改变或者移动和旋转,也可以增加新的物品或者减少物品,下图中蓝色是不可训练的模块,橙色可训练。以我的理解好像要设置你要解耦多少个(N)物品再训练,网络根据类似 k 近邻法的方法在特征空间上对物品进行分割解耦,然后分为 N 个渲染 mlp 进行训练,训练前加入外观/形状编码 z。最后还是要扔进 D 训练。 **GIRAFFE** 是 GRAF 的改进工作,可以把图片中的物品,背景一个个解耦出来单独进行改变或者移动和旋转,也可以增加新的物品或者减少物品,下图中蓝色是不可训练的模块,橙色可训练。以我的理解好像要设置你要解耦多少个(N)物品再训练,网络根据类似 k 近邻法的方法在特征空间上对物品进行分割解耦,然后分为 N 个渲染 mlp 进行训练,训练前加入外观/形状编码 z。最后还是要扔进 D 训练。
![](https://cdn.xyxsw.site/boxcnB04hwHA1o64WBvYSyVTDod.png) ![](https://cdn.xyxsw.site/boxcnB04hwHA1o64WBvYSyVTDod.png)
@@ -137,7 +137,7 @@ EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作
### 3.OSF ### 3.OSF
<strong>OSF</strong>Object-Centric Neural Scene Rendering可以给移动的物体生成合理的阴影和光照效果。加入了新的坐标信息光源位置与相机坐标等一起输入。对每个小物件构建一个单独的小 nerf计算这个小 nerf 的体素时要先经过光源照射处理(训练出来的)然后在每个小物件之间也要计算反射这样的光线影响,最后进行正常的渲染。<del>这篇文章没人写 review有点冷门这些都是我自己读完感觉的不一定对。</del> **OSF**Object-Centric Neural Scene Rendering可以给移动的物体生成合理的阴影和光照效果。加入了新的坐标信息光源位置与相机坐标等一起输入。对每个小物件构建一个单独的小 nerf计算这个小 nerf 的体素时要先经过光源照射处理(训练出来的)然后在每个小物件之间也要计算反射这样的光线影响,最后进行正常的渲染。<del>这篇文章没人写 review有点冷门这些都是我自己读完感觉的不一定对。</del>
![](https://cdn.xyxsw.site/boxcnV7YcKIq5y8TkOGEGzrPc5g.png) ![](https://cdn.xyxsw.site/boxcnV7YcKIq5y8TkOGEGzrPc5g.png)
@@ -147,9 +147,9 @@ EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作
作者用了几个我比较陌生的技术,比如超网络 hypernet还有超网络与 gan 结合的 INR-Gan。 作者用了几个我比较陌生的技术,比如超网络 hypernet还有超网络与 gan 结合的 INR-Gan。
<strong>hypernet</strong>:把随机初始化和直接梯度回传更新的网络参数用另一个神经网络来更新,就是我们要同时训练两个网络,一个是本体,一个是调整参数用的超网络。 **hypernet**:把随机初始化和直接梯度回传更新的网络参数用另一个神经网络来更新,就是我们要同时训练两个网络,一个是本体,一个是调整参数用的超网络。
<strong>INR-Gan</strong>:把超网络技术与 Gan 结合,并且用了 INR 技术,这个技术类似 nerf不过是处理图片用到的是构建一个坐标(x,y)->RGB 的网络,可以让图片达到更高分辨率,也就是把离散的像素变成连续的。 **INR-Gan**:把超网络技术与 Gan 结合,并且用了 INR 技术,这个技术类似 nerf不过是处理图片用到的是构建一个坐标(x,y)->RGB 的网络,可以让图片达到更高分辨率,也就是把离散的像素变成连续的。
左边是常规卷积网络生成图像,右边是用 INR 生成图像。 左边是常规卷积网络生成图像,右边是用 INR 生成图像。
@@ -161,12 +161,12 @@ EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作
2.因为使用神经网路去表示图片,占用内存更大。 2.因为使用神经网路去表示图片,占用内存更大。
因此,作者设计了<strong>FMM</strong>去应对这两个问题,这也是 Hyper-nerf-gan 借鉴的主要部分。 因此,作者设计了**FMM**去应对这两个问题,这也是 Hyper-nerf-gan 借鉴的主要部分。
FMM 主要是把要学习的矩阵转化为两个低秩矩阵,去先生成他们俩再相乘,减少网络计算量。 FMM 主要是把要学习的矩阵转化为两个低秩矩阵,去先生成他们俩再相乘,减少网络计算量。
![](https://cdn.xyxsw.site/boxcn0oHY54dgL2bxmryxjqxC6f.png) ![](https://cdn.xyxsw.site/boxcn0oHY54dgL2bxmryxjqxC6f.png)
现在开始讲 Hyper-nerf-gan 本身,它看上去其实就是 nerf 接在 gan 上。不过有一些变化,比如输入不再包含视角信息,我<strong>很怀疑它不能很好表达反光效果</strong>。而且抛弃了粗网络细网络的设计,只使用粗网络减少计算量。这里的 generator 完全就是 INR-Gan 的形状,生成权重,然后再经过 nerf 的 mlp 层生成,没啥别的了,就这样吧。 现在开始讲 Hyper-nerf-gan 本身,它看上去其实就是 nerf 接在 gan 上。不过有一些变化,比如输入不再包含视角信息,我**很怀疑它不能很好表达反光效果**。而且抛弃了粗网络细网络的设计,只使用粗网络减少计算量。这里的 generator 完全就是 INR-Gan 的形状,生成权重,然后再经过 nerf 的 mlp 层生成,没啥别的了,就这样吧。
![](https://cdn.xyxsw.site/boxcnc9bZ1nqt3Lighlrj9zSrdd.png) ![](https://cdn.xyxsw.site/boxcnc9bZ1nqt3Lighlrj9zSrdd.png)

View File

@@ -5,7 +5,7 @@
![](https://cdn.xyxsw.site/boxcnXzgaIhmUQ7HQtEn52ksWIf.png) ![](https://cdn.xyxsw.site/boxcnXzgaIhmUQ7HQtEn52ksWIf.png)
这里主要是记录一下它的原理: 这里主要是记录一下它的原理:
首先是一个经典关键点匹配技术:<strong>SIFT</strong> 首先是一个经典关键点匹配技术:**SIFT**
# SIFT 特征点匹配 # SIFT 特征点匹配
@@ -17,7 +17,7 @@
下面是原理方法: 下面是原理方法:
首先是<strong>高斯金字塔</strong>,它是把原图先放大两倍,然后使用高斯滤波(高斯卷积)对图像进行模糊化数次,取出倒数第三层缩小一半继续进行这个过程,也就是说它是由一组一组的小金字塔组成的。 首先是**高斯金字塔**,它是把原图先放大两倍,然后使用高斯滤波(高斯卷积)对图像进行模糊化数次,取出倒数第三层缩小一半继续进行这个过程,也就是说它是由一组一组的小金字塔组成的。
![](https://cdn.xyxsw.site/boxcnKJWrCUc5cPOuZg01HqNCsc.png) ![](https://cdn.xyxsw.site/boxcnKJWrCUc5cPOuZg01HqNCsc.png)

View File

@@ -2,25 +2,25 @@
下面给出了 NLP 的四大常见的应用。由于预训练的模型是在连续的文本序列上训练的,所以需要进行一些修改才能将其应用于不同的这些 NLP 任务。 下面给出了 NLP 的四大常见的应用。由于预训练的模型是在连续的文本序列上训练的,所以需要进行一些修改才能将其应用于不同的这些 NLP 任务。
<strong>分类 (text classification)</strong> 给一句话或者一段文本,判断一个标签。 **分类 (text classification)** 给一句话或者一段文本,判断一个标签。
![](https://cdn.xyxsw.site/PxE3b05ApofzZ1x8u49cirdUnye.png) ![](https://cdn.xyxsw.site/PxE3b05ApofzZ1x8u49cirdUnye.png)
图 2分类 (text classification) 图 2分类 (text classification)
<strong>蕴含 (textual entailment)</strong> 给一段话,和一个假设,看看前面这段话有没有蕴含后面的假设。 **蕴含 (textual entailment)** 给一段话,和一个假设,看看前面这段话有没有蕴含后面的假设。
![](https://cdn.xyxsw.site/OuhabfzABoqxQxxS1n1cPLTinKb.png) ![](https://cdn.xyxsw.site/OuhabfzABoqxQxxS1n1cPLTinKb.png)
图 3蕴含 (textual entailment) 图 3蕴含 (textual entailment)
<strong>相似 (Similarity)</strong> 判断两段文字是否相似。 **相似 (Similarity)** 判断两段文字是否相似。
![](https://cdn.xyxsw.site/ByeFbxTfToxFlgxh6xmcIKeRnzd.png) ![](https://cdn.xyxsw.site/ByeFbxTfToxFlgxh6xmcIKeRnzd.png)
图 4相似 (Similarity) 图 4相似 (Similarity)
<strong>多选题 (Multiple Choice)</strong> 给个问题,从 N 个答案中选出正确答案。 **多选题 (Multiple Choice)** 给个问题,从 N 个答案中选出正确答案。
![](https://cdn.xyxsw.site/ZYgybsj5dol1Ifx96Koc6SRpnmc.jpeg) ![](https://cdn.xyxsw.site/ZYgybsj5dol1Ifx96Koc6SRpnmc.jpeg)

View File

@@ -1,13 +1,13 @@
# 推荐系统概念解释 and 一个好的推荐系统 # 推荐系统概念解释 and 一个好的推荐系统
- <strong>用户满意度</strong> - **用户满意度**
- 用户满意度是推荐系统测评的重要指标,但是实际上,用户满意度数据获得的方式十分有限,因为这是一种用户的主观情感。 - 用户满意度是推荐系统测评的重要指标,但是实际上,用户满意度数据获得的方式十分有限,因为这是一种用户的主观情感。
- 设计合适的方式对于用户的满意度进行回收分析,是改进推荐系统的一个很好的方式。这样的的方式包括但不限于,设计合适的调查问卷,在物品的购买结束后附上一份满意度调查。 - 设计合适的方式对于用户的满意度进行回收分析,是改进推荐系统的一个很好的方式。这样的的方式包括但不限于,设计合适的调查问卷,在物品的购买结束后附上一份满意度调查。
- 满意度在一些程度上可以细分为更加具体的信息。例如点击率,用户停留时间,转化率,完播率,或者是哔站视频点赞,三连的比例。 - 满意度在一些程度上可以细分为更加具体的信息。例如点击率,用户停留时间,转化率,完播率,或者是哔站视频点赞,三连的比例。
- <strong>预测准确度</strong> - **预测准确度**
- <strong>召回率(Recall)</strong> - **召回率(Recall)**
$$ $$
Recall =\frac{\sum_{u\in U}{\vert R(u)\cap T(u) \vert}}{\sum_{u\in U \vert T(u)\vert}} Recall =\frac{\sum_{u\in U}{\vert R(u)\cap T(u) \vert}}{\sum_{u\in U \vert T(u)\vert}}
@@ -19,7 +19,7 @@
- 召回率的意义?可以参考机器学习中留下的定义进行理解 - 召回率的意义?可以参考机器学习中留下的定义进行理解
- <strong>精确率</strong> - **精确率**
$$ $$
Precision =\frac{\sum_{u\in U}{\vert R(u)\cap T(u)\vert}}{\sum_{u\in U}{\vert R(u) \vert}} Precision =\frac{\sum_{u\in U}{\vert R(u)\cap T(u)\vert}}{\sum_{u\in U}{\vert R(u) \vert}}
@@ -31,7 +31,7 @@
- 精确率的意义? - 精确率的意义?
- <strong>覆盖率</strong> - **覆盖率**
- 描述了一个系统对于物品长尾的发掘能力。 - 描述了一个系统对于物品长尾的发掘能力。
- 覆盖率的一个定义可以是: - 覆盖率的一个定义可以是:
@@ -42,7 +42,7 @@
- 覆盖率的意义:覆盖率越高,以为这系统中被推荐给用户的物品,占所有物品的比例越大,对于一个好的推荐系统,不仅需要有较高的用户满意度,还需要有较高的覆盖率。 - 覆盖率的意义:覆盖率越高,以为这系统中被推荐给用户的物品,占所有物品的比例越大,对于一个好的推荐系统,不仅需要有较高的用户满意度,还需要有较高的覆盖率。
- 当然对于覆盖率的定义,不止以上的这一种,甚至说,在实际使用上,上述简单的覆盖率不足以支撑大规模复杂系统的覆盖率计算,所以如何对于覆盖率进行修正和更新?信息熵与基尼系数! - 当然对于覆盖率的定义,不止以上的这一种,甚至说,在实际使用上,上述简单的覆盖率不足以支撑大规模复杂系统的覆盖率计算,所以如何对于覆盖率进行修正和更新?信息熵与基尼系数!
- 推荐了解,马太效应,一个强者更强,弱者更弱的效应,在推荐系统中也同样存在。 - 推荐了解,马太效应,一个强者更强,弱者更弱的效应,在推荐系统中也同样存在。
- <strong>多样性</strong> - **多样性**
- 假设,$s(i,j)$ 定义了物品 i 和 j 之间的相似度,给用户 $u$ 的推荐列表 $R(u)$的多样性定义: - 假设,$s(i,j)$ 定义了物品 i 和 j 之间的相似度,给用户 $u$ 的推荐列表 $R(u)$的多样性定义:
$$ $$
@@ -52,12 +52,12 @@
$$ $$
Diversity = \frac{1}{\vert U\vert}\sum_{u\in U}{Diversity(R(u))} Diversity = \frac{1}{\vert U\vert}\sum_{u\in U}{Diversity(R(u))}
$$ $$
- <strong>信任度</strong> - **信任度**
- 用户对于该系统的信任程度 - 用户对于该系统的信任程度
- <strong>实时性</strong> - **实时性**
- 系统对于数据更新的时效性 - 系统对于数据更新的时效性
- <strong>健壮性</strong> - **健壮性**
- 系统对于外来攻击的防护性 - 系统对于外来攻击的防护性

View File

@@ -12,12 +12,12 @@
- 时间信息对于用户的的影响可以主要分为以下几项: - 时间信息对于用户的的影响可以主要分为以下几项:
- <strong>用户的兴趣是变化的</strong> - **用户的兴趣是变化的**
对于一个用户,其幼年时期和青年时期喜欢的动画片是不一样的;晴天和雨天想要的物品是不一样的;一个人开始工作前和开始工作后的需求也是不同的。 对于一个用户,其幼年时期和青年时期喜欢的动画片是不一样的;晴天和雨天想要的物品是不一样的;一个人开始工作前和开始工作后的需求也是不同的。
所以应该关注用户的近期行为,确定他的兴趣,最后给予用户推荐。 所以应该关注用户的近期行为,确定他的兴趣,最后给予用户推荐。
- <strong>物品具有生命周期</strong> - **物品具有生命周期**
流行物品会随着热度持续火爆一段时间,但最终会无人问津;生活必需品无论在什么时候都有稳定的需求量。 流行物品会随着热度持续火爆一段时间,但最终会无人问津;生活必需品无论在什么时候都有稳定的需求量。
- <strong>季节效应</strong> - **季节效应**
正如概述中列出的冬衣与夏衣的区别,应该在合适的季节给用户推荐合适的物品。 正如概述中列出的冬衣与夏衣的区别,应该在合适的季节给用户推荐合适的物品。
### 系统时间特性分析 ### 系统时间特性分析
@@ -25,10 +25,10 @@
- 当系统由之前的静态系统变成随时间变化的时变系统后,需要关注特性也会发生变化,则需要重新观测一些数据,以推断系统的关于时间变化的特性。 - 当系统由之前的静态系统变成随时间变化的时变系统后,需要关注特性也会发生变化,则需要重新观测一些数据,以推断系统的关于时间变化的特性。
下面是一些可以用来观测的数据: 下面是一些可以用来观测的数据:
- <strong>确定系统的用户增长数</strong>,以判断系统的增长情况或是衰退情况。 - **确定系统的用户增长数**,以判断系统的增长情况或是衰退情况。
- <strong>物品的平均在线天数</strong>,即将满足用户物品互动次数的物品标记为在线,测算物品的平均在线天数以标量物品的生命周期。 - **物品的平均在线天数**,即将满足用户物品互动次数的物品标记为在线,测算物品的平均在线天数以标量物品的生命周期。
- 系统的时效性,判断<strong>相隔一段时间的物品流行度向量的相似度</strong>,若是相隔一段时间的相似度仍然较大,说明经过一段时间后,该物品还是被大众喜欢,则说明这件物品具有持久流行性。而对于系统来说,若是系统中大量物品的相似度变化都不大,则说明这个系统是一个推荐热度较持久物品的系统,说明系统的时效性较弱。 - 系统的时效性,判断**相隔一段时间的物品流行度向量的相似度**,若是相隔一段时间的相似度仍然较大,说明经过一段时间后,该物品还是被大众喜欢,则说明这件物品具有持久流行性。而对于系统来说,若是系统中大量物品的相似度变化都不大,则说明这个系统是一个推荐热度较持久物品的系统,说明系统的时效性较弱。
- 系统对于用户的黏着性,统计<strong>用户的平均活跃天数</strong>,或者计算<strong>相隔一段时间的用户活跃度</strong>,以此判断系统对于用户的留存力或者说黏着性。 - 系统对于用户的黏着性,统计**用户的平均活跃天数**,或者计算**相隔一段时间的用户活跃度**,以此判断系统对于用户的留存力或者说黏着性。
### 推荐系统的实时性 ### 推荐系统的实时性
@@ -45,9 +45,9 @@
综上,时间多样性会提高用户的满意度,所以如何在确保精度的条件下提高系统的时间多样性呢? 综上,时间多样性会提高用户的满意度,所以如何在确保精度的条件下提高系统的时间多样性呢?
- <strong>需要用户在有新行为时,更新推荐列表</strong> - **需要用户在有新行为时,更新推荐列表**
传统的离线更新的推荐系统无法满足需求,所以需要使用实时推荐系统。 传统的离线更新的推荐系统无法满足需求,所以需要使用实时推荐系统。
- <strong>需要用户在没有新行为的时候,经常变化推荐列表</strong> - **需要用户在没有新行为的时候,经常变化推荐列表**
通常采取以下三种方法: 通常采取以下三种方法:
- 生成推荐列表时加入一定的随机性。 - 生成推荐列表时加入一定的随机性。
@@ -58,7 +58,7 @@
### 时间上下文推荐算法 ### 时间上下文推荐算法
- <strong>最近最热门</strong> - **最近最热门**
一种最朴素的思想, 在系统引入了时间信息之后,最简单的非个性化推荐算法就是给用户推荐最近最热门的物品。 一种最朴素的思想, 在系统引入了时间信息之后,最简单的非个性化推荐算法就是给用户推荐最近最热门的物品。
给定时间 T物品 i 在最近的流行度可定义为: 给定时间 T物品 i 在最近的流行度可定义为:
@@ -67,10 +67,10 @@
n_i(T)= \sum_{(u,i,t) \in Train ,t<T} \frac{1}{1+\alpha(T-t)} n_i(T)= \sum_{(u,i,t) \in Train ,t<T} \frac{1}{1+\alpha(T-t)}
$$ $$
- <strong>时间上下文相关的 itemCF 算法</strong> - **时间上下文相关的 itemCF 算法**
itemCF 算法所依赖的核心部分,在引入时间信息后可以进行进一步更新 itemCF 算法所依赖的核心部分,在引入时间信息后可以进行进一步更新
- <strong>物品相似度</strong> 利用用户行为,计算物品间的相似度,用户在相隔很短的时间内喜欢的物品通常具有更高的相似度,所以可以在相似度计算公式中引入时间信息,使得相似度计算更加准确。 - **物品相似度** 利用用户行为,计算物品间的相似度,用户在相隔很短的时间内喜欢的物品通常具有更高的相似度,所以可以在相似度计算公式中引入时间信息,使得相似度计算更加准确。
原本的相似度公式为: 原本的相似度公式为:
$$ $$
@@ -91,7 +91,7 @@
其中$\alpha$ 是时间衰减参数,它的取值与系统的对于自身定义有关系。收到用户兴趣变化的额外影响。 其中$\alpha$ 是时间衰减参数,它的取值与系统的对于自身定义有关系。收到用户兴趣变化的额外影响。
- <strong>在线推荐</strong> 用户近期行为相比用户很久之前的行为,更能体现用户目前的兴趣,所以在进行预测时,应当加重用户近期行为的权重,但不应该偏离用户长期行为的行为基调。 - **在线推荐** 用户近期行为相比用户很久之前的行为,更能体现用户目前的兴趣,所以在进行预测时,应当加重用户近期行为的权重,但不应该偏离用户长期行为的行为基调。
原本的用户u对于物品i的兴趣$p(u,i)$ 可通过如下公式计算: 原本的用户u对于物品i的兴趣$p(u,i)$ 可通过如下公式计算:
$$p(u,i)=\sum_{j\in N(u)}{sim(i,j)}$$ $$p(u,i)=\sum_{j\in N(u)}{sim(i,j)}$$
@@ -106,11 +106,11 @@
在上面的更新后公式中,$t_0$ 表示当前时间,该公式表明,当 $t_{uj}$ 与 $t_0$ 越靠近和物品j相似的物品就会在用户u的推荐列表中获得更高的排名。其中的$\beta$和上文的 $\alpha$ 是一样的,需要根据系统的情况选择合适的值。 在上面的更新后公式中,$t_0$ 表示当前时间,该公式表明,当 $t_{uj}$ 与 $t_0$ 越靠近和物品j相似的物品就会在用户u的推荐列表中获得更高的排名。其中的$\beta$和上文的 $\alpha$ 是一样的,需要根据系统的情况选择合适的值。
- <strong>时间上下文相关的userCF算法</strong> - **时间上下文相关的userCF算法**
与itemCF算法类似userCF在引入时间信息后也可以进行更新 与itemCF算法类似userCF在引入时间信息后也可以进行更新
- <strong>用户兴趣相似度</strong> 用户相似度在引入时间信息后会将用户相同的逆时序选择相似度降低。简单来说就是A一月BF1长时间在线二月BF5长时间在线而B一月BF5长时间在线二月BF1长时间在线C行为信息与A相同。如果不引入时间信息那么AB的相似度与AC的相似度是一样的而实际上AC的相似度会大于AB的相似度。 - **用户兴趣相似度** 用户相似度在引入时间信息后会将用户相同的逆时序选择相似度降低。简单来说就是A一月BF1长时间在线二月BF5长时间在线而B一月BF5长时间在线二月BF1长时间在线C行为信息与A相同。如果不引入时间信息那么AB的相似度与AC的相似度是一样的而实际上AC的相似度会大于AB的相似度。
userCF的用户uv间相似度的基本公式为 userCF的用户uv间相似度的基本公式为
@@ -130,7 +130,7 @@
同样增加了一个时间衰减因子用户uv对于i的作用时间差距越大那么两人的相似度会相应降低。 同样增加了一个时间衰减因子用户uv对于i的作用时间差距越大那么两人的相似度会相应降低。
- <strong>相似兴趣用户的最近行为</strong> 对于用户u来说存在最近行为与用户u相似的用户v那么用户v的最近行为将会比用户u很久之前的行为更具有参考价值。 - **相似兴趣用户的最近行为** 对于用户u来说存在最近行为与用户u相似的用户v那么用户v的最近行为将会比用户u很久之前的行为更具有参考价值。
userCF中用户u对于物品i兴趣的基础公式为 userCF中用户u对于物品i兴趣的基础公式为
@@ -146,7 +146,7 @@
p(u,i)=\sum_{v\in S(u,k)}{w_{ui}r_{vi}} \frac{1}{1+\alpha(\vert t_0-t_{vi}\vert)} p(u,i)=\sum_{v\in S(u,k)}{w_{ui}r_{vi}} \frac{1}{1+\alpha(\vert t_0-t_{vi}\vert)}
$$ $$
- <strong>时间段图模型</strong> - **时间段图模型**
同样是一个基于图的推荐系统模型,引入时间信息,建立一个二分图时间段图模型: 同样是一个基于图的推荐系统模型,引入时间信息,建立一个二分图时间段图模型:
$$ $$
@@ -169,11 +169,11 @@
在构建了引入时间信息的图结构后最简单的思想就是利用PersonalRank算法给用进行个性化推荐。但由于其复杂度较高所以引入路径融合算法。 在构建了引入时间信息的图结构后最简单的思想就是利用PersonalRank算法给用进行个性化推荐。但由于其复杂度较高所以引入路径融合算法。
一般来说,图上两个点的相关度强有以下的特征: 一般来说,图上两个点的相关度强有以下的特征:
- <strong>两个顶点间有很多路径</strong> - **两个顶点间有很多路径**
- <strong>两个顶点间路径比较短</strong> - **两个顶点间路径比较短**
- <strong>两点间不经过出度大的点</strong> ,即不经过与很多其他点相连的节点,在推荐系统思维中等效于不与过热门物品关系紧密。 - **两点间不经过出度大的点** ,即不经过与很多其他点相连的节点,在推荐系统思维中等效于不与过热门物品关系紧密。
#### 路径融合算法 #### 路径融合算法
@@ -199,15 +199,15 @@
### 地点信息效应 ### 地点信息效应
- <strong>基于用户当前位置的推荐</strong>:对于用户当前位置,为其推荐距离更近的餐馆,娱乐场所或消费场所。 - **基于用户当前位置的推荐**:对于用户当前位置,为其推荐距离更近的餐馆,娱乐场所或消费场所。
- <strong>基于用户活跃位置的推荐</strong>:对于用户长期活跃的区域,降低该区域内物品的权重,提高范围外物品的权重,以提高系统的新鲜度。 - **基于用户活跃位置的推荐**:对于用户长期活跃的区域,降低该区域内物品的权重,提高范围外物品的权重,以提高系统的新鲜度。
### 基于位置的推荐算法 ### 基于位置的推荐算法
- 明尼苏达大学的LARS推荐系统Location Aware Recommender System,位置感知推荐系统)。 - 明尼苏达大学的LARS推荐系统Location Aware Recommender System,位置感知推荐系统)。
- <strong>对于数据的预处理</strong> - **对于数据的预处理**
将物品分为两类:(1)有空间属性的物品,餐馆,商店,旅游景点。(2)没有空间属性的物品,图书电影等。 将物品分为两类:(1)有空间属性的物品,餐馆,商店,旅游景点。(2)没有空间属性的物品,图书电影等。
@@ -223,9 +223,9 @@
(用户,用户位置,物品,物品位置,评分):记录了某个位置的用户,对于某个地点的物品的评分。 (用户,用户位置,物品,物品位置,评分):记录了某个位置的用户,对于某个地点的物品的评分。
- <strong>研究前两组数据</strong>:发现两种特征:(1)兴趣本地化,不同位置的用户存在较大的兴趣差异,不同国家和不同地区的差异。(2)活动本地化,一个用户往往在附近的地区活动。 - **研究前两组数据**:发现两种特征:(1)兴趣本地化,不同位置的用户存在较大的兴趣差异,不同国家和不同地区的差异。(2)活动本地化,一个用户往往在附近的地区活动。
- <strong>对于不同数据的处理</strong> - **对于不同数据的处理**
- 第一种数据LARS的基本思想是采用树状结构来进行数据集划分。 - 第一种数据LARS的基本思想是采用树状结构来进行数据集划分。
@@ -236,7 +236,7 @@
(3)LARS通过该节点的行为数据利用基本推荐算法进行为用户进行推荐。 (3)LARS通过该节点的行为数据利用基本推荐算法进行为用户进行推荐。
但是,对于上述过程,若是树的深度较大,则划分到每个节点的用户数据将较少,难以训练出一个令人满意的模型。所以有改进方法如下: 但是,对于上述过程,若是树的深度较大,则划分到每个节点的用户数据将较少,难以训练出一个令人满意的模型。所以有改进方法如下:
从根节点出发,利用每个中间节点的数据训练出一个模型,而最终的推荐结果,是这一些列推荐模型所产出的推荐结果的加权结果。这个模型也被称为“<strong>金字塔模型</strong>”,其中<strong>深度</strong>是影响这个模型性能的重要参数,选取合适的深度对于该算法十分重要。 从根节点出发,利用每个中间节点的数据训练出一个模型,而最终的推荐结果,是这一些列推荐模型所产出的推荐结果的加权结果。这个模型也被称为“**金字塔模型**”,其中**深度**是影响这个模型性能的重要参数,选取合适的深度对于该算法十分重要。
- 第二种数据对于物品i在用户u推荐列表中的权重公式进行修正 - 第二种数据对于物品i在用户u推荐列表中的权重公式进行修正
(1)首先忽略物品的位置信息利用itemCF算法计算用户u对物品i的兴趣。 (1)首先忽略物品的位置信息利用itemCF算法计算用户u对物品i的兴趣。

View File

@@ -4,7 +4,7 @@
VIT前Transformer模型被大量应用在NLP自然语言处理当中而在CV领域Transformer的注意力机制attention也被广泛应用比如Se模块CBAM模块等等注意力模块这些注意力模块能够帮助提升网络性能。 VIT前Transformer模型被大量应用在NLP自然语言处理当中而在CV领域Transformer的注意力机制attention也被广泛应用比如Se模块CBAM模块等等注意力模块这些注意力模块能够帮助提升网络性能。
<strong>VIT的工作展示了不需要依赖CNN的结构也可以在图像分类任务上达到很好的效果</strong> **VIT的工作展示了不需要依赖CNN的结构也可以在图像分类任务上达到很好的效果**
同时VIT也影响了近2年的CV领域改变了自2012年AlexNet提出以来卷积神经网络在CV领域的绝对统治地位。 同时VIT也影响了近2年的CV领域改变了自2012年AlexNet提出以来卷积神经网络在CV领域的绝对统治地位。
@@ -24,7 +24,7 @@
结构上VIT 采取的是原始 Transformer 模型,方便开箱即用,即在 encoder-decoder 结构上与 NLP 的 Transform 模型并无差别。 结构上VIT 采取的是原始 Transformer 模型,方便开箱即用,即在 encoder-decoder 结构上与 NLP 的 Transform 模型并无差别。
主要做出的贡献在于<strong>数据处理和分类头</strong> 主要做出的贡献在于**数据处理和分类头**
### Patch embedding ### Patch embedding
@@ -38,7 +38,7 @@
> 今天天气不错,我要去看电影 > 今天天气不错,我要去看电影
其中<strong>我</strong>则编码为[0.50.60.6] 其中**我**则编码为[0.50.60.6]
而具体来说 Word embedding 分为以下两步 而具体来说 Word embedding 分为以下两步

View File

@@ -6,9 +6,9 @@
# 前言 # 前言
BERT 是一种基于 transformer 架构的自然语言处理模型,它把在 cv 领域广为应用的<strong>预训练(pre-trainning)</strong>和<strong>微调(fine-tune)</strong>的结构成功引入了 NLP 领域。 BERT 是一种基于 transformer 架构的自然语言处理模型,它把在 cv 领域广为应用的**预训练(pre-trainning)**和**微调(fine-tune)**的结构成功引入了 NLP 领域。
简单来说BERT 就是一种<strong>认识几乎所有词的</strong><strong>训练好</strong>的网络,当你要做一些下游任务时,可以在 BERT 预训练模型的基础上进行一些微调,以进行你的任务。也就是 backbone 模型,输出的是文本特征。 简单来说BERT 就是一种**认识几乎所有词的****训练好**的网络,当你要做一些下游任务时,可以在 BERT 预训练模型的基础上进行一些微调,以进行你的任务。也就是 backbone 模型,输出的是文本特征。
举个例子,我要做一个文本情感分析任务,也就是把文本对情感进行分类,那我只需要在 BERT 的基础上加一个 mlp 作为分类头,在我的小规模数据上进行继续训练即可(也就是微调)。 举个例子,我要做一个文本情感分析任务,也就是把文本对情感进行分类,那我只需要在 BERT 的基础上加一个 mlp 作为分类头,在我的小规模数据上进行继续训练即可(也就是微调)。
@@ -24,9 +24,9 @@ mlp 的重点和创新并非它的模型结构,而是它的训练方式,前
在文本被输入模型之前,我们要对它进行一些处理: 在文本被输入模型之前,我们要对它进行一些处理:
1. <strong>词向量</strong>(wordpiece embedding):单词本身的向量表示。每个词(或者进行时过去时后缀之类的)会被记录为一个向量。它们被储存在一个字典里,这一步其实就是在字典中查找这个词对应的向量。 1. **词向量**(wordpiece embedding):单词本身的向量表示。每个词(或者进行时过去时后缀之类的)会被记录为一个向量。它们被储存在一个字典里,这一步其实就是在字典中查找这个词对应的向量。
2. <strong>位置向量</strong>(position embedding):将单词的位置信息编码成特征向量。构建 position embedding 有两种方法BERT 是初始化一个 position embedding<strong>然后通过训练将其学出来</strong>;而 Transformer 是通过<strong>制定规则</strong>来构建一个 position embedding。 2. **位置向量**(position embedding):将单词的位置信息编码成特征向量。构建 position embedding 有两种方法BERT 是初始化一个 position embedding**然后通过训练将其学出来**;而 Transformer 是通过**制定规则**来构建一个 position embedding。
3. <strong>句子向量</strong>(segment embedding):用于区分两个句子的向量表示。这个在问答等非对称句子中是用于区别的。(这个主要是因为可能会用到对句子的分析中) 3. **句子向量**(segment embedding):用于区分两个句子的向量表示。这个在问答等非对称句子中是用于区别的。(这个主要是因为可能会用到对句子的分析中)
BERT 模型的输入就是上面三者的和,如图所示: BERT 模型的输入就是上面三者的和,如图所示:
@@ -34,7 +34,7 @@ BERT 模型的输入就是上面三者的和,如图所示:
## 模型结构 ## 模型结构
简单来说BERT 是 transformer<strong>编码器</strong>的叠加,<strong>也就是下图左边部分</strong>。这算一个 block。 简单来说BERT 是 transformer**编码器**的叠加,**也就是下图左边部分**。这算一个 block。
![](https://cdn.xyxsw.site/boxcnPg8594YzCdnX6KZxpEYYod.png) ![](https://cdn.xyxsw.site/boxcnPg8594YzCdnX6KZxpEYYod.png)
@@ -50,7 +50,7 @@ BERT 训练方式跟 cv 里的很多 backbone 模型一样,是先用几个具
跟以往的 nlp 模型不同BERT 的掩码并非 transformer 那样,给前面不给后面,而是在句子中随机把单词替换为 mask让模型去猜也就是完形填空。下面给个例子 跟以往的 nlp 模型不同BERT 的掩码并非 transformer 那样,给前面不给后面,而是在句子中随机把单词替换为 mask让模型去猜也就是完形填空。下面给个例子
<strong>划掉的单词是被 mask 的</strong> **划掉的单词是被 mask 的**
正常的掩码I am a <del>little cat</del> 正常的掩码I am a <del>little cat</del>

View File

@@ -14,7 +14,7 @@ cv 领域,其实预训练模型早已推广,一般是在 imagenet 上进行
那么问题来了,既然我们要学习 BERT 的随机掩码,那么我们应该对什么做 mask 呢? 那么问题来了,既然我们要学习 BERT 的随机掩码,那么我们应该对什么做 mask 呢?
因为图片不像文本,有单词这一基础单位。图片的基础单位像素在被单独拿出来的时候包含的语义信息是完全不如单词的。因为像素的语义信息与<strong>上下左右的连续关系</strong>很密切。于是作者采用了像 VIT 那样把图片分成好几个 patch对 patch 做随机掩码。 因为图片不像文本,有单词这一基础单位。图片的基础单位像素在被单独拿出来的时候包含的语义信息是完全不如单词的。因为像素的语义信息与**上下左右的连续关系**很密切。于是作者采用了像 VIT 那样把图片分成好几个 patch对 patch 做随机掩码。
# 模型结构与训练方式 # 模型结构与训练方式

View File

@@ -16,7 +16,7 @@
对比学习,故名思意,是对比着来学习。而我们拿来对比的东西就是在模型眼里的语义,也就是我们叫做特征的向量。 对比学习,故名思意,是对比着来学习。而我们拿来对比的东西就是在模型眼里的语义,也就是我们叫做特征的向量。
在具体讲对比之前,我们先看看传统的<strong>监督学习</strong>是怎么学特征的: 在具体讲对比之前,我们先看看传统的**监督学习**是怎么学特征的:
数据 + 模型=> 特征,特征对人工标注进行学习,也就是说我们要把模型抽取的特征尽可能的靠近人工标注 数据 + 模型=> 特征,特征对人工标注进行学习,也就是说我们要把模型抽取的特征尽可能的靠近人工标注
@@ -26,15 +26,15 @@
![](https://cdn.xyxsw.site/boxcnJ6HpIJqxJuxiz7Cw5GopSh.png) ![](https://cdn.xyxsw.site/boxcnJ6HpIJqxJuxiz7Cw5GopSh.png)
我们通过<strong>正样本</strong>(跟拿到的特征<strong>应当相近</strong>的另一个特征)与<strong>负样本</strong>(反之)的对比,使得 我们通过**正样本**(跟拿到的特征**应当相近**的另一个特征)与**负样本**(反之)的对比,使得
越相近的物体,它们的特征就在超球面上越靠近,越不像的物体离的越远,去学习图片更本质的特征 越相近的物体,它们的特征就在超球面上越靠近,越不像的物体离的越远,去学习图片更本质的特征
那么具体的对比学习方法我在后面结合一些论文一起讲吧~ 那么具体的对比学习方法我在后面结合一些论文一起讲吧~
这部分内容更像一个综述,讲述对比学习这几年的发展路程,所以我会尽可能的描述作者在论文里讲的<strong>故事</strong>,来方便大家弄清为什么要这么做。 这部分内容更像一个综述,讲述对比学习这几年的发展路程,所以我会尽可能的描述作者在论文里讲的**故事**,来方便大家弄清为什么要这么做。
<strong>可能会有很多我的主观理解在此</strong>,并且<strong>不会</strong>深入细节。可以算是一个总结和分享,我会在这里带着读者过一遍近期对比学习的工作来给大家一个对比学习方向的直观感性理解。 **可能会有很多我的主观理解在此**,并且**不会**深入细节。可以算是一个总结和分享,我会在这里带着读者过一遍近期对比学习的工作来给大家一个对比学习方向的直观感性理解。
同时因为笔者水平,视野,精力有限,不可能包含所有的算法,也不可能保证完全正确。因此仅作为笔记分享使用。若有错误,请多多指正。 同时因为笔者水平,视野,精力有限,不可能包含所有的算法,也不可能保证完全正确。因此仅作为笔记分享使用。若有错误,请多多指正。

View File

@@ -14,7 +14,7 @@
既然有了上面这个发现,那么作者想我能不能把分类任务推到极致呢? 既然有了上面这个发现,那么作者想我能不能把分类任务推到极致呢?
于是他们<strong>把每一个图片当作一个类别</strong>,去跟其他的图片做对比,具体模型如下 于是他们**把每一个图片当作一个类别**,去跟其他的图片做对比,具体模型如下
![](https://cdn.xyxsw.site/boxcnPNukes2FlNwUFSKiqIJEbd.png) ![](https://cdn.xyxsw.site/boxcnPNukes2FlNwUFSKiqIJEbd.png)
@@ -24,9 +24,9 @@
2.后面接了一个 Non-param Softmax非参数 softmax其实就是一个不被训练的把所有特征投射到超球面上的一个分类头把所有特征模长变为 1 2.后面接了一个 Non-param Softmax非参数 softmax其实就是一个不被训练的把所有特征投射到超球面上的一个分类头把所有特征模长变为 1
3.后面的<strong>Memory Bank</strong>是这篇文章的<strong>重点</strong>,它是一个<strong>动态字典</strong>。我们把每一个图片抽取出来的特征存入 memory bank每次计算时抽取其中部分作为一个 batch 进行对比学习,把更新后的模型得到的特征替换 memory bank 里原先的特征。 3.后面的**Memory Bank**是这篇文章的**重点**,它是一个**动态字典**。我们把每一个图片抽取出来的特征存入 memory bank每次计算时抽取其中部分作为一个 batch 进行对比学习,把更新后的模型得到的特征替换 memory bank 里原先的特征。
4.具体损失函数用的是一个叫 NCEloss 的损失,它把多分类问题分为<strong>若干个二分类问题</strong><strong>是</strong>与<strong>不是</strong>,每个 batch 中只有一个的 ground truth 是yes其余都是no 4.具体损失函数用的是一个叫 NCEloss 的损失,它把多分类问题分为**若干个二分类问题****是**与**不是**,每个 batch 中只有一个的 ground truth 是yes其余都是no
在训练的时候,相当于是有一组以前的编码器抽取的特征 A,B,C,D...,一组当前编码器抽取的特征 a,b,c,d...,对它们进行对比学习。对 a 来说A 是正样本,其他都是负样本,同理类推。 在训练的时候,相当于是有一组以前的编码器抽取的特征 A,B,C,D...,一组当前编码器抽取的特征 a,b,c,d...,对它们进行对比学习。对 a 来说A 是正样本,其他都是负样本,同理类推。
@@ -38,9 +38,9 @@
用动量更新的方法去更新 memory bank 中的特征 用动量更新的方法去更新 memory bank 中的特征
也就是让特征的变化<strong>不那么剧烈</strong> 也就是让特征的变化**不那么剧烈**
原因:如果一直保持更新,<strong>特征总体的变化就会比较大</strong>,而我们在大数据集上训练的时候,等第二次调用一个特征时,它跟现在的特征分布已经大相径庭,那就不好训练了,也就是<strong>特征缺乏一致性</strong>。因此我们引入动量更新来确保特征进行平稳的改变,而非突变。 原因:如果一直保持更新,**特征总体的变化就会比较大**,而我们在大数据集上训练的时候,等第二次调用一个特征时,它跟现在的特征分布已经大相径庭,那就不好训练了,也就是**特征缺乏一致性**。因此我们引入动量更新来确保特征进行平稳的改变,而非突变。
#### 关于动量的小拓展 #### 关于动量的小拓展
@@ -60,4 +60,4 @@ m 表示动量k 是新的特征q 是上一个特征,只要设置小的
总体来说Inst Disc 把对比学习成功引入了 CV 领域,核心思想是构建动态字典进行对比学习 总体来说Inst Disc 把对比学习成功引入了 CV 领域,核心思想是构建动态字典进行对比学习
<strong>PS若无特殊说明最后保留下来去做下游任务的模型只有编码器其他都删除了。</strong> **PS若无特殊说明最后保留下来去做下游任务的模型只有编码器其他都删除了。**

View File

@@ -6,9 +6,9 @@
![](https://cdn.xyxsw.site/boxcnC10uzdj0G0BJPlUZKFIi7C.png) ![](https://cdn.xyxsw.site/boxcnC10uzdj0G0BJPlUZKFIi7C.png)
这是处理音频的一个例子,<strong>给模型 t 时刻以前的信息,让它抽取特征并对后文进行预测,真正的后文作为正样本,负样本当然是随便选取就好啦。</strong> 这是处理音频的一个例子,**给模型 t 时刻以前的信息,让它抽取特征并对后文进行预测,真正的后文作为正样本,负样本当然是随便选取就好啦。**
不同于之前说的个体判别,这个是<strong>生成式模型</strong>,这个模型不止可以处理音频,还可以处理图片(每一个块换成一个词)或者处理图片(以 patch 为单位)。 不同于之前说的个体判别,这个是**生成式模型**,这个模型不止可以处理音频,还可以处理图片(每一个块换成一个词)或者处理图片(以 patch 为单位)。
是不是有点眼熟?这跟我前面写的 BERT 和 MAE 其实异曲同工,不过这两位是随机 mask而非时序性的 mask。 是不是有点眼熟?这跟我前面写的 BERT 和 MAE 其实异曲同工,不过这两位是随机 mask而非时序性的 mask。

View File

@@ -14,9 +14,9 @@ MoCo 是 Inst Disc 的改进工作,那我们自然要先看一下 Inst Disc
## 3.NCEloss 负样本分类不合理的问题 ## 3.NCEloss 负样本分类不合理的问题
NCE 把<strong>所有负样本都视作一样的</strong>,但实际上负样本<strong>并不能被完全归为一类</strong> NCE 把**所有负样本都视作一样的**,但实际上负样本**并不能被完全归为一类**
举个例子:我现在的正样本是<strong>猫猫</strong>,然后有两个负样本是<strong>狗勾</strong>和<strong>汽车</strong>,那<strong>猫猫</strong>肯定跟<strong>狗勾</strong>更相近,跟<strong>汽车</strong>更不相似,也就是说<strong>狗</strong>的得分虽然低于<strong>猫</strong>,但是一定要高于<strong>汽车</strong><strong>而不是像 NCE 那样把狗和车打成一类</strong>,这样不利于模型学习。 举个例子:我现在的正样本是**猫猫**,然后有两个负样本是**狗勾**和**汽车**,那**猫猫**肯定跟**狗勾**更相近,跟**汽车**更不相似,也就是说**狗**的得分虽然低于**猫**,但是一定要高于**汽车****而不是像 NCE 那样把狗和车打成一类**,这样不利于模型学习。
并且它也不是很灵活,下文细讲 并且它也不是很灵活,下文细讲
@@ -34,7 +34,7 @@ NCE 把<strong>所有负样本都视作一样的</strong>,但实际上负样
## 2.针对动量更新不能完全解决特征一致性差的问题 ## 2.针对动量更新不能完全解决特征一致性差的问题
作者提出了一个新的<strong>动量编码器</strong>来替代动量更新。 作者提出了一个新的**动量编码器**来替代动量更新。
动量编码器是独立于原编码器的一个编码器它的参数是根据原编码器动量更新的k 和 q 就是指代全部参数了 动量编码器是独立于原编码器的一个编码器它的参数是根据原编码器动量更新的k 和 q 就是指代全部参数了
@@ -52,9 +52,9 @@ NCE 把<strong>所有负样本都视作一样的</strong>,但实际上负样
q·k 其实就是各个特征(因为那时候用的都是 transformer 了,这里就是 trnasformer 里的 k 和 q q·k 其实就是各个特征(因为那时候用的都是 transformer 了,这里就是 trnasformer 里的 k 和 q
这里分母级数上的<strong>k 是代表负样本的个数,也就是 k=batchsize-1总样本-正样本)</strong>。其实就是<strong>对一个 batch 做 k+1 分类</strong>,并且引入了一个<strong>超参数 T</strong>。它的名字叫做<strong>温度参数</strong>,控制的是 softmax 后得分分布的平滑程度(直观理解,不是很严谨) 这里分母级数上的**k 是代表负样本的个数,也就是 k=batchsize-1总样本-正样本)**。其实就是**对一个 batch 做 k+1 分类**,并且引入了一个**超参数 T**。它的名字叫做**温度参数**,控制的是 softmax 后得分分布的平滑程度(直观理解,不是很严谨)
T 越大,损失函数就越对所有负样本<strong>一视同仁</strong>,退化为二分类的 NCElossT 越小,损失函数就<strong>越关注一些难分类的特征</strong>,但有时候会出现两张其实都是猫猫的图片,你硬要让模型说猫猫跟猫猫不一样,这也不太好,这个参数要根据数据集情况适中调整。 T 越大,损失函数就越对所有负样本**一视同仁**,退化为二分类的 NCElossT 越小,损失函数就**越关注一些难分类的特征**,但有时候会出现两张其实都是猫猫的图片,你硬要让模型说猫猫跟猫猫不一样,这也不太好,这个参数要根据数据集情况适中调整。
![](https://cdn.xyxsw.site/boxcnhuabU9XzXmVQfu0ruENs83.png) ![](https://cdn.xyxsw.site/boxcnhuabU9XzXmVQfu0ruENs83.png)

View File

@@ -8,9 +8,9 @@ x 是输入的图片,它经过两种不同的数据增强得到 xi 和 xj 两
![](https://cdn.xyxsw.site/boxcnq5TYzSltn6CsPM3Bn3xxAb.png) ![](https://cdn.xyxsw.site/boxcnq5TYzSltn6CsPM3Bn3xxAb.png)
左右的<strong>f 都是编码器</strong>,并且是<strong>完全一致共享权重</strong>的,可以说是同一个。 左右的**f 都是编码器**,并且是**完全一致共享权重**的,可以说是同一个。
而 g 是一层 mlp 结构,只在训练中使用,<strong>应用到下游任务时用的仅仅是 f</strong>(与前面几篇一样都是 RES50很神奇的是就仅仅多了这么一层 mlp它在 imagenet 上的正确率直接加了十个点。 而 g 是一层 mlp 结构,只在训练中使用,**应用到下游任务时用的仅仅是 f**(与前面几篇一样都是 RES50很神奇的是就仅仅多了这么一层 mlp它在 imagenet 上的正确率直接加了十个点。
关于这点也很奇怪,作者做了很多实验但是也没有很合理的解释。 关于这点也很奇怪,作者做了很多实验但是也没有很合理的解释。

View File

@@ -2,7 +2,7 @@
# 前言 # 前言
与前面的一些工作不同SwAV<strong>不再进行个体判别任务</strong>,而是提出了新的任务————<strong>聚类</strong> 与前面的一些工作不同SwAV**不再进行个体判别任务**,而是提出了新的任务————**聚类**
并在训练的模型结构上也做了相应改动,而非只调整训练方法。 并在训练的模型结构上也做了相应改动,而非只调整训练方法。
@@ -26,17 +26,17 @@
## 聚类中心? ## 聚类中心?
首先我们有个新的东西<strong>prototypes</strong>,它是<strong>聚类中心的集合</strong>,也就是许多作为聚类中心的向量构成的矩阵。 首先我们有个新的东西**prototypes**,它是**聚类中心的集合**,也就是许多作为聚类中心的向量构成的矩阵。
这些聚类中心是我设定在超球面上的,离散的一些点,我希望让不同的特征向它们靠拢以进行区分(也就是所谓聚类)。 这些聚类中心是我设定在超球面上的,离散的一些点,我希望让不同的特征向它们靠拢以进行区分(也就是所谓聚类)。
更直白地讲,我在地上撒了一把面包屑,地上本来散乱的蚂蚁会向面包屑聚集,形成一个个<strong>小团体</strong>。蚂蚁就是<strong>不同图像的特征</strong>,面包屑就是<strong>我设定的聚类中心</strong> 更直白地讲,我在地上撒了一把面包屑,地上本来散乱的蚂蚁会向面包屑聚集,形成一个个**小团体**。蚂蚁就是**不同图像的特征**,面包屑就是**我设定的聚类中心**
## 聚类中心我知道了,然后呢? ## 聚类中心我知道了,然后呢?
先说我拿他干了什么,再一步步讲为什么要这么做吧。 先说我拿他干了什么,再一步步讲为什么要这么做吧。
首先我们手里有抽取出来的特征<strong>z1</strong><strong>z2</strong>,以及一个我随机初始化的<strong>聚类中心矩阵 c</strong>。我分别求这个<strong>矩阵</strong>和<strong>z1</strong><strong>z2</strong>的内积,并<strong>进行一些变换</strong>得到 Q1,Q2。当 z1z2 都是正样本时,我希望<strong>Q1 与 z2 相近</strong><strong>Q2 与 z1 相近</strong>。如果有一个是负样本则尽可能远离。也就是拿 Q 当 ground-truth 做训练。最后这步前面已经讲过 NCEloss 等损失函数了,用它们就可以达成这个任务。 首先我们手里有抽取出来的特征**z1****z2**,以及一个我随机初始化的**聚类中心矩阵 c**。我分别求这个**矩阵**和**z1****z2**的内积,并**进行一些变换**得到 Q1,Q2。当 z1z2 都是正样本时,我希望**Q1 与 z2 相近****Q2 与 z1 相近**。如果有一个是负样本则尽可能远离。也就是拿 Q 当 ground-truth 做训练。最后这步前面已经讲过 NCEloss 等损失函数了,用它们就可以达成这个任务。
而我们的优化要采用 [K-means](https://zhuanlan.zhihu.com/p/78798251)(不懂可以看这里)的类似做法,先对聚类中心进行优化,再对特征进行优化。 而我们的优化要采用 [K-means](https://zhuanlan.zhihu.com/p/78798251)(不懂可以看这里)的类似做法,先对聚类中心进行优化,再对特征进行优化。
@@ -46,13 +46,13 @@ sowhy相信你现在肯定是一脸懵不过别急希望我能为你
## 首先是第一步,为什么要求内积? ## 首先是第一步,为什么要求内积?
如果你有好好了解线性代数的几何性质,应当了解<strong>两个向量的内积就是一个向量在另一个向量上的投影</strong>,而一个向量与一个矩阵的内积,<strong>就是把这个向量投影到这个矩阵代表的基空间中</strong> 如果你有好好了解线性代数的几何性质,应当了解**两个向量的内积就是一个向量在另一个向量上的投影**,而一个向量与一个矩阵的内积,**就是把这个向量投影到这个矩阵代表的基空间中**
我做的第一步就是把<strong>抽出来的特征 z 用聚类中心的向量表示,这样更加方便对比聚类成功与否</strong> 我做的第一步就是把**抽出来的特征 z 用聚类中心的向量表示,这样更加方便对比聚类成功与否**
## 然后是第二步,我说的变换是什么呢? ## 然后是第二步,我说的变换是什么呢?
我们现在求内积是为了把特征投影到聚类中心空间,为了避免模型训练坍塌(就是网络把特征全部聚到同一个点,<del>开摆~</del>)我要保证每个聚类中心被<strong>"使用"</strong>的次数,所以我们请出了<strong>Sinkhorn-Knopp 算法。</strong>这个算法比较硬核,我在这里不展开了,大家知道它是干啥的就行,具体的推导可以看我后面贴的视频,那里面有讲。 我们现在求内积是为了把特征投影到聚类中心空间,为了避免模型训练坍塌(就是网络把特征全部聚到同一个点,<del>开摆~</del>)我要保证每个聚类中心被**"使用"**的次数,所以我们请出了**Sinkhorn-Knopp 算法。**这个算法比较硬核,我在这里不展开了,大家知道它是干啥的就行,具体的推导可以看我后面贴的视频,那里面有讲。
## 第三步应该不用怎么讲了吧? ## 第三步应该不用怎么讲了吧?
@@ -64,7 +64,7 @@ sowhy相信你现在肯定是一脸懵不过别急希望我能为你
# 总结 # 总结
主要贡献是上面我说的三步聚类算法以及后面的小 trick<strong>Sinkhorn-Knopp 算法难度较高,大家有兴趣的话自行观看后面这个视频理解哈~</strong> 主要贡献是上面我说的三步聚类算法以及后面的小 trick**Sinkhorn-Knopp 算法难度较高,大家有兴趣的话自行观看后面这个视频理解哈~**
# 相关资料 # 相关资料

View File

@@ -2,25 +2,25 @@
# 前言 # 前言
这篇论文的主要特点是<strong>它的训练不需要负样本</strong>,并且能保证<strong>模型不坍塌</strong> 这篇论文的主要特点是**它的训练不需要负样本**,并且能保证**模型不坍塌**
当一个普通的对比学习模型没有负样本时,它的损失函数就<strong>只有正样本之间的差距</strong>,这样模型只会学到一个<strong>捷径解</strong>————你给我什么输入我都输出同一个值,这样 loss 就永远=0 了(<del>开摆</del> 当一个普通的对比学习模型没有负样本时,它的损失函数就**只有正样本之间的差距**,这样模型只会学到一个**捷径解**————你给我什么输入我都输出同一个值,这样 loss 就永远=0 了(~~开摆~~
<strong>BYOL</strong>就解决了这一问题,使得训练不再需要负样本。 **BYOL**就解决了这一问题,使得训练不再需要负样本。
# 模型结构 # 模型结构
前半部分很普通,跟 SimCLR 是基本一致的,一个图片经过两种不同的数据增强,进入两个编码器,得到两个不同的特征。 前半部分很普通,跟 SimCLR 是基本一致的,一个图片经过两种不同的数据增强,进入两个编码器,得到两个不同的特征。
值得一提的是,这里下面的这个粉色的编码器用的是<strong>动量编码器</strong>的更新方式。也就是说它是紫色那个编码器的动量编码器。 值得一提的是,这里下面的这个粉色的编码器用的是**动量编码器**的更新方式。也就是说它是紫色那个编码器的动量编码器。
而提取特征之后,经过两个 `SimCLR` 中提出的额外的 mlp 层 z在此之后它们给紫色的那支加了一个新的模块<strong>predictor</strong> 而提取特征之后,经过两个 `SimCLR` 中提出的额外的 mlp 层 z在此之后它们给紫色的那支加了一个新的模块**predictor**
<strong>predictor</strong>的模型结构就是跟 z 一样的<strong>mlp 层</strong>。它的任务是<strong>通过紫色的特征去预测粉色的特征</strong>。也就是说它的代理任务换成了<strong>生成式</strong> **predictor**的模型结构就是跟 z 一样的**mlp 层**。它的任务是**通过紫色的特征去预测粉色的特征**。也就是说它的代理任务换成了**生成式**
![](https://cdn.xyxsw.site/boxcne7eizRhw5GKRSpF40KcMEh.png) ![](https://cdn.xyxsw.site/boxcne7eizRhw5GKRSpF40KcMEh.png)
而具体的损失只有预测特征和真实特征的损失,用的是<strong>MSEloss</strong> 而具体的损失只有预测特征和真实特征的损失,用的是**MSEloss**
下面的粉色分支最后一步是不进行梯度回传的。它的更新完全依赖紫色的那个编码器。 下面的粉色分支最后一步是不进行梯度回传的。它的更新完全依赖紫色的那个编码器。
@@ -42,29 +42,29 @@ BN 根据批次的均值和方差进行归一化
推理时,均值、方差是基于所有批次的期望计算所得。 推理时,均值、方差是基于所有批次的期望计算所得。
因此,博客作者认为,虽然我们只用了正样本进行训练,但是这个正样本包含了<strong>本批次所有样本的信息</strong>(均值,方差),所以<strong>实际上并不是真正的无负样本。</strong> 因此,博客作者认为,虽然我们只用了正样本进行训练,但是这个正样本包含了**本批次所有样本的信息**(均值,方差),所以**实际上并不是真正的无负样本。**
而这个 batch 的均值,即平均图片,可以看作 `SawAV` 里的聚类中心,是所有历史样本的聚类中心。(<del>很玄学</del> 而这个 batch 的均值,即平均图片,可以看作 `SawAV` 里的聚类中心,是所有历史样本的聚类中心。(<del>很玄学</del>
### 作者看到这个博客就急了 ### 作者看到这个博客就急了
如果真是这样的话,<strong>BYOL 就还是没有逃脱出对比学习的范畴</strong>,它还是找了一个东西去做对比,其创新性就大大降低了。所以作者赶紧做实验,看看能不能找到 BYOL 模型不坍塌的另外一种解释。最终又写了一篇论文进行回应。 如果真是这样的话,**BYOL 就还是没有逃脱出对比学习的范畴**,它还是找了一个东西去做对比,其创新性就大大降低了。所以作者赶紧做实验,看看能不能找到 BYOL 模型不坍塌的另外一种解释。最终又写了一篇论文进行回应。
  这篇论文叫 BYOL works even without batch statistics即在没有 BN 的时候 BYOL 照样能工作,详细的消融实验结果如下表所示   这篇论文叫 BYOL works even without batch statistics即在没有 BN 的时候 BYOL 照样能工作,详细的消融实验结果如下表所示
![](https://cdn.xyxsw.site/boxcncmJWb99mlUUIFTPjGoCqYb.png) ![](https://cdn.xyxsw.site/boxcncmJWb99mlUUIFTPjGoCqYb.png)
<strong>BN 非常关键</strong>:只要是 `projector`SimCLR 提出的 mlp中没有 BN 的地方SimCLR 性稍微下降;但是 BYOL 全都模型坍塌了。 **BN 非常关键**:只要是 `projector`SimCLR 提出的 mlp中没有 BN 的地方SimCLR 性稍微下降;但是 BYOL 全都模型坍塌了。
<strong>有 BN 也会坍塌</strong>:作者找到了特例(红色框),即使当 `projector` 有 BN 的时候BYOL 还是训练失败了 。如果 BN 真的很关键,它真的提供了隐式负样本的对比学习的话,训练就不应该失败 **有 BN 也会坍塌**:作者找到了特例(红色框),即使当 `projector` 有 BN 的时候BYOL 还是训练失败了 。如果 BN 真的很关键,它真的提供了隐式负样本的对比学习的话,训练就不应该失败
<strong>完全没有 BNSimCLR 也坍塌</strong>(最后三列的结果。要注意 SimCLR 只有一层 projector。这表明完全不用归一化SimCLR 这种使用负样本进行对比学习的方式也无法训练。 **完全没有 BNSimCLR 也坍塌**(最后三列的结果。要注意 SimCLR 只有一层 projector。这表明完全不用归一化SimCLR 这种使用负样本进行对比学习的方式也无法训练。
最终结论BN 跟它原来的设计初衷一样,主要作用就是提高模型训练时的稳定性,从而不会导致模型坍塌 。作者进一步延伸,如果一开始就能让模型初始化的比较好,后面的训练即使离开了 BN 也没有问题。 最终结论BN 跟它原来的设计初衷一样,主要作用就是提高模型训练时的稳定性,从而不会导致模型坍塌 。作者进一步延伸,如果一开始就能让模型初始化的比较好,后面的训练即使离开了 BN 也没有问题。
作者为此又设计了一个实验,使用 `group norm`+`weight standardization` (前者也是一种归一化方式,后者是一种卷积权重标准化方式,但都没有对 batch 中的数据进行融合BYOL 的 top-准确率可以达到 74.1%和原来精度可以认为是一样了74.3%)。 作者为此又设计了一个实验,使用 `group norm`+`weight standardization` (前者也是一种归一化方式,后者是一种卷积权重标准化方式,但都没有对 batch 中的数据进行融合BYOL 的 top-准确率可以达到 74.1%和原来精度可以认为是一样了74.3%)。
<strong>至今其实这个问题也没有一个很合理能服众的解释。</strong> **至今其实这个问题也没有一个很合理能服众的解释。**
# 总结 # 总结

View File

@@ -30,13 +30,13 @@ BYOL 之后,大家都发现对比学习是靠许许多多的小 trick 和技
原论文中提出的解释并不是最完美的。而且这个问题的解释涉及了动力学等知识,我也没有足够的知识储备去讲解这个问题,这里只能讲一些与解答相关的信息,如果有兴趣可以看下面链接中的解释: 原论文中提出的解释并不是最完美的。而且这个问题的解释涉及了动力学等知识,我也没有足够的知识储备去讲解这个问题,这里只能讲一些与解答相关的信息,如果有兴趣可以看下面链接中的解释:
这里要涉及到一个机器学习的经典算法,<strong>EM 算法</strong>,它也是<strong>k-means</strong>的核心思想之一。 这里要涉及到一个机器学习的经典算法,**EM 算法**,它也是**k-means**的核心思想之一。
因为本文的主旨原因,我不会在这里细讲这个算法,但是大家了解这是个什么东西即可。 因为本文的主旨原因,我不会在这里细讲这个算法,但是大家了解这是个什么东西即可。
<strong>EM 算法</strong>用于优化带有未知参数的模型,`k-means` 的聚类中心就可以看作一个未知参数,我们要同时优化模型本体和聚类中心。所以我们先对其中一个目标 A 做<strong>随机初始化</strong>,然后<strong>先优化</strong>另一个目标 B再反过来用另一个目标 B 优化后<strong>的结果优化被随机初始化的目标 A</strong>这就是一次迭代只要不断循环这个迭代EM 算法往往能找到最优解。 **EM 算法**用于优化带有未知参数的模型,`k-means` 的聚类中心就可以看作一个未知参数,我们要同时优化模型本体和聚类中心。所以我们先对其中一个目标 A 做**随机初始化**,然后**先优化**另一个目标 B再反过来用另一个目标 B 优化后**的结果优化被随机初始化的目标 A**这就是一次迭代只要不断循环这个迭代EM 算法往往能找到最优解。
这里可以把<strong>经过 predictor 预测头的特征</strong>作为 `k-means` 里的特征,而另一个作为<strong>目标的特征</strong>作为<strong>聚类中心</strong>,经过预测头的特征直接反向传播进行优化,作为目标的特征则是通过上面说的对称的操作经过预测头进行优化。 这里可以把**经过 predictor 预测头的特征**作为 `k-means` 里的特征,而另一个作为**目标的特征**作为**聚类中心**,经过预测头的特征直接反向传播进行优化,作为目标的特征则是通过上面说的对称的操作经过预测头进行优化。
最最直白地解读结论的话,可以说是,这种先后优化的 EM 算法,使得模型“来不及“去把权重全部更新为 0。模型坍塌具体的推导需要动力学的知识这里不做展开。 最最直白地解读结论的话,可以说是,这种先后优化的 EM 算法,使得模型“来不及“去把权重全部更新为 0。模型坍塌具体的推导需要动力学的知识这里不做展开。

View File

@@ -20,7 +20,7 @@ MoCo v3它缝合了 MoCo 和 SimSiam以及新的骨干网络 VIT。
![](https://cdn.xyxsw.site/boxcnMMhbVk6wc81H8BSoack7Mg.png) ![](https://cdn.xyxsw.site/boxcnMMhbVk6wc81H8BSoack7Mg.png)
在使用 VIT 训练的时候batchsize 不算太大时训练很平滑,但是一旦 batchsize 变大,训练的图像就会出现如上图这样的<strong>波动</strong>。于是作者去查看了每一层的梯度,发现问题出在<strong>VIT 的第一层线性变换</strong>上。也就是下图中的粉色那个层,<strong>把图片打成 patch 后展平做的线性变换</strong> 在使用 VIT 训练的时候batchsize 不算太大时训练很平滑,但是一旦 batchsize 变大,训练的图像就会出现如上图这样的**波动**。于是作者去查看了每一层的梯度,发现问题出在**VIT 的第一层线性变换**上。也就是下图中的粉色那个层,**把图片打成 patch 后展平做的线性变换**
![](https://cdn.xyxsw.site/boxcniBkiypcv6IQbxr9D6JukOb.png) ![](https://cdn.xyxsw.site/boxcniBkiypcv6IQbxr9D6JukOb.png)

View File

@@ -8,7 +8,7 @@
在周志华的机器学习一书半监督学习章节中,有对基本的图学习策略进行基本的描述,详见我为了应付课程考试整理的[图半监督学习](http://blog.cyasylum.top/index.php/2020/07/05/%E5%9B%BE%E5%8D%8A%E7%9B%91%E7%9D%A3%E5%AD%A6%E4%B9%A0/)。其基本思路是这样的,通过”样本距离度量“刻画获取样本之间的联系,将样本嵌入到“图”,即样本即其关系的集合中。后通过图将半监督学习中有标记样本的标签对未标记样本进行传递,从而获取未标记样本的属性,进行学习。 在周志华的机器学习一书半监督学习章节中,有对基本的图学习策略进行基本的描述,详见我为了应付课程考试整理的[图半监督学习](http://blog.cyasylum.top/index.php/2020/07/05/%E5%9B%BE%E5%8D%8A%E7%9B%91%E7%9D%A3%E5%AD%A6%E4%B9%A0/)。其基本思路是这样的,通过”样本距离度量“刻画获取样本之间的联系,将样本嵌入到“图”,即样本即其关系的集合中。后通过图将半监督学习中有标记样本的标签对未标记样本进行传递,从而获取未标记样本的属性,进行学习。
如此,便定下来图网络的基本思路,即通过<em>信息在图上的传递</em>,迭代学习知识。有了这样的基础,我们便可以开始对图网络进行讨论了。 如此,便定下来图网络的基本思路,即通过*信息在图上的传递*,迭代学习知识。有了这样的基础,我们便可以开始对图网络进行讨论了。
接下来,我们从最基础的部分来讲讲,信息是如何在图上进行传播的。 接下来,我们从最基础的部分来讲讲,信息是如何在图上进行传播的。
@@ -55,7 +55,7 @@ $$
现在,我们可以尝试用$\mathbf{L}$对图进行表示了。 现在,我们可以尝试用$\mathbf{L}$对图进行表示了。
另外还有个<em>随机游走归一化拉普拉斯矩阵</em> 另外还有个*随机游走归一化拉普拉斯矩阵*
$$ $$
\mathbf{L}^{sym}=\mathbf{D}^{-1}\mathbf{L}=\mathbf{I}-\mathbf{D}^{-1}\mathbf{A} \mathbf{L}^{sym}=\mathbf{D}^{-1}\mathbf{L}=\mathbf{I}-\mathbf{D}^{-1}\mathbf{A}
$$ $$

View File

@@ -212,7 +212,7 @@ The End~~~~~~~~~~
## 补充内容:下个定义 ## 补充内容:下个定义
数据分析是独立于开发和算法岗的另一个方向,它主要是通过<strong>应用</strong>机器学习和深度学习的<strong>已有算法</strong>来分析现实问题的一个方向 数据分析是独立于开发和算法岗的另一个方向,它主要是通过**应用**机器学习和深度学习的**已有算法**来分析现实问题的一个方向
我们常说:数据是客观的,但是解读数据的人是主观的。 我们常说:数据是客观的,但是解读数据的人是主观的。

View File

@@ -11,17 +11,17 @@ Email: yqykrhf@163.com
## 术语的介绍 ## 术语的介绍
<strong>Benchmark</strong>评测的基准。通常会是一些公开的数据集。 **Benchmark**评测的基准。通常会是一些公开的数据集。
<strong>Baseline:</strong> 基准,一般指的是一个现有的工作。 **Baseline:** 基准,一般指的是一个现有的工作。
<strong>SOTA </strong>(state-of-art): 截止目前,指标最好。 **SOTA **(state-of-art): 截止目前,指标最好。
举个例子: 举个例子:
我们选取 XXX-Net 作为我们的 Baseline在加入我们设计的注意力机制的模块在 KITTI 这个 Benchmark 上性能达到了 SOTA。 我们选取 XXX-Net 作为我们的 Baseline在加入我们设计的注意力机制的模块在 KITTI 这个 Benchmark 上性能达到了 SOTA。
<strong>Backbone:</strong> **Backbone:**
这个单词原意指的是人的脊梁骨,后来引申为支柱,核心的意思。 这个单词原意指的是人的脊梁骨,后来引申为支柱,核心的意思。
@@ -29,13 +29,13 @@ Email: yqykrhf@163.com
所以将这一部分网络结构称为 backbone 十分形象,仿佛是一个人站起来的支柱。 所以将这一部分网络结构称为 backbone 十分形象,仿佛是一个人站起来的支柱。
<strong>Solid</strong> **Solid**
一般是描述这个工作非常扎实。 一般是描述这个工作非常扎实。
这个工作很 solid。每一步都 make sense合理。没有特意为了刷 benchmark 上的指标,用一些 fancy trick奇技淫巧 这个工作很 solid。每一步都 make sense合理。没有特意为了刷 benchmark 上的指标,用一些 fancy trick奇技淫巧
<strong>Robust</strong> **Robust**
鲁棒性,是描述一个系统受到外界的干扰情况下,仍然能保持较好的性能。 鲁棒性,是描述一个系统受到外界的干扰情况下,仍然能保持较好的性能。
@@ -76,7 +76,7 @@ Step 3. 验证解决方案的有效性。
从上一小节的几个例子当中,其实不同的人做研究所需要完成的工作是完全不一样的。很多时候只需要做 step 3 即可,从功利的角度来讲这是性价比最高的。 从上一小节的几个例子当中,其实不同的人做研究所需要完成的工作是完全不一样的。很多时候只需要做 step 3 即可,从功利的角度来讲这是性价比最高的。
如果我们是一个合格的博士或者我们致力于如此,那么首先的第一步要找到一个好的问题,这是一个非常重要的开始,<strong>一个好的问题往往意味着研究已经成功了一半。 </strong>什么是一个好的问题?它可能会有以下几个特点: 如果我们是一个合格的博士或者我们致力于如此,那么首先的第一步要找到一个好的问题,这是一个非常重要的开始,**一个好的问题往往意味着研究已经成功了一半。 **什么是一个好的问题?它可能会有以下几个特点:
1. 理论上能实现某种意义上的统一,从而使得问题的描述变得非常优雅。比如 [DepthAwareCNN](https://arxiv.org/abs/1803.06791) 1. 理论上能实现某种意义上的统一,从而使得问题的描述变得非常优雅。比如 [DepthAwareCNN](https://arxiv.org/abs/1803.06791)
2. 对于之后的工作非常具有启发的作用,甚至达到某种意义的纠偏作用。比如 [OccuSeg](https://arxiv.org/abs/2003.06537) 2. 对于之后的工作非常具有启发的作用,甚至达到某种意义的纠偏作用。比如 [OccuSeg](https://arxiv.org/abs/2003.06537)
@@ -91,7 +91,7 @@ Step 3. 验证解决方案的有效性。
2. 做加法。举个例子:图片可以做语义分割。那么图片 + 深度图如何更好的做语义分割。图片 + 文字描述的做语义分割。现在的语义分割的标注都是 0123 这些数字,然后每一个数字对应一个实际的类别,这个对应表是认为规定的。如果我把 01 的对应关系换掉。重新训练以后就,网络的性能是否会影响? 2. 做加法。举个例子:图片可以做语义分割。那么图片 + 深度图如何更好的做语义分割。图片 + 文字描述的做语义分割。现在的语义分割的标注都是 0123 这些数字,然后每一个数字对应一个实际的类别,这个对应表是认为规定的。如果我把 01 的对应关系换掉。重新训练以后就,网络的性能是否会影响?
3. 做减法。对于点云的语义分割的标注,通过是非常费时费力的。那么对于点云来说,少量的标注是否是可行的?比如只标注百分之 10 的点。 3. 做减法。对于点云的语义分割的标注,通过是非常费时费力的。那么对于点云来说,少量的标注是否是可行的?比如只标注百分之 10 的点。
以上是一些技巧,把输入调整一下,约束去掉一些,就会有很多新的问题。这个过程通常被叫做<strong>“调研”</strong> 以上是一些技巧,把输入调整一下,约束去掉一些,就会有很多新的问题。这个过程通常被叫做**“调研”**
这个过程在是一个相对比较痛苦的过程,因为调研的过程中你会发现很多问题,想到很多所谓创新的解决方法,但是实际上你会发现你的解决方法已经有很多人做过了。这一阶段调整心态很重要,切忌急于求成。 这个过程在是一个相对比较痛苦的过程,因为调研的过程中你会发现很多问题,想到很多所谓创新的解决方法,但是实际上你会发现你的解决方法已经有很多人做过了。这一阶段调整心态很重要,切忌急于求成。
@@ -114,9 +114,9 @@ Step 3. 验证解决方案的有效性。
## 快速出成果的捷径与方法 ## 快速出成果的捷径与方法
如何快速的出成果,不管别人如何帮你,前提是你自己要足够的强。不能存在 <strong>“靠别人” </strong>的想法。 如何快速的出成果,不管别人如何帮你,前提是你自己要足够的强。不能存在 **“靠别人” **的想法。
对于一个博士生来讲,出成果保毕业,那么可能要对学术的进展要敏感,比如 Nerf 八月份刚出来的时候,如果你非常敏锐的意识到这个工作的基础性和重要性。那么你稍微思考一两个月,总是能有一些创新的 ieda 产生的。所以这个<strong>timing 和 senstive</strong>就非常重要,当然导师是不是审稿人可能更重要。 对于一个博士生来讲,出成果保毕业,那么可能要对学术的进展要敏感,比如 Nerf 八月份刚出来的时候,如果你非常敏锐的意识到这个工作的基础性和重要性。那么你稍微思考一两个月,总是能有一些创新的 ieda 产生的。所以这个**timing 和 senstive**就非常重要,当然导师是不是审稿人可能更重要。
对于一个本科生来讲,当然是跟着指导老师的脚步去做。但是如果指导老师只是把你当成一个工具人,一直打杂货的话。你想发论文,一种所谓的捷径是 A+B。就是把一个方法直接拿过来用在另一个地方大概率这样会有一些问题那么你就可以针对性的改进如何针对性的改进不好的方式是 A+B 套娃,好一些的方式是分析这个不好的原因在哪里,现有的方法多大程度可以帮助解决这个问题,或者现有的方法解决不了这个问题,但是其中的一个模块是否是可以参考的。 对于一个本科生来讲,当然是跟着指导老师的脚步去做。但是如果指导老师只是把你当成一个工具人,一直打杂货的话。你想发论文,一种所谓的捷径是 A+B。就是把一个方法直接拿过来用在另一个地方大概率这样会有一些问题那么你就可以针对性的改进如何针对性的改进不好的方式是 A+B 套娃,好一些的方式是分析这个不好的原因在哪里,现有的方法多大程度可以帮助解决这个问题,或者现有的方法解决不了这个问题,但是其中的一个模块是否是可以参考的。

View File

@@ -148,7 +148,7 @@ AI 是一个复杂且多样化的研究领域,他能取得如此长远的发
而这些都不会使他停滞 而这些都不会使他停滞
<strong>这是本讲义想做的第三件事,拥有学习新技术,跟上时代的能力**</strong> **这是本讲义想做的第三件事,拥有学习新技术,跟上时代的能力****
而愿不愿意在这激荡翻腾的年份,贡献出你的力量,让世界变得更好/更坏,就取决于你的选择了! 而愿不愿意在这激荡翻腾的年份,贡献出你的力量,让世界变得更好/更坏,就取决于你的选择了!

View File

@@ -14,7 +14,7 @@
而我也常常遇到学弟学妹们去向我提问:什么是嵌入式? 而我也常常遇到学弟学妹们去向我提问:什么是嵌入式?
<strong>我觉得以我通俗的话来讲就是:在硬件设备上写软件代码。</strong>虽然这种说法并不是完全准确,但是对于初学者而言暂时性的保持这样的认知,在探索嵌入式的过程中不断完善自己的学习体系,已是极好。 **我觉得以我通俗的话来讲就是:在硬件设备上写软件代码。**虽然这种说法并不是完全准确,但是对于初学者而言暂时性的保持这样的认知,在探索嵌入式的过程中不断完善自己的学习体系,已是极好。
不如举一个大学里玩嵌入式的常见概念吧:机器人。 不如举一个大学里玩嵌入式的常见概念吧:机器人。
@@ -42,11 +42,11 @@
说相对实在点的东西的话在大学中或者在杭州电子科技大学学了嵌入式的一些基础知识后你可以去参与一些相关的竞赛全国大学生电子设计竞赛、全国大学生智能车竞赛、全国大学生工程实践与创新能力大赛、Robot Master 机甲大师竞赛等等),也许你已经了解到杭电的环境会让你不断地接触许许多多的竞赛,在竞赛的学习过程中你可以获得一定的能力、获得一定的感悟,也许能获得到一定的荣誉,如果你足够优秀的话可以最后保研上岸,成为别人眼里的佼佼者。 说相对实在点的东西的话在大学中或者在杭州电子科技大学学了嵌入式的一些基础知识后你可以去参与一些相关的竞赛全国大学生电子设计竞赛、全国大学生智能车竞赛、全国大学生工程实践与创新能力大赛、Robot Master 机甲大师竞赛等等),也许你已经了解到杭电的环境会让你不断地接触许许多多的竞赛,在竞赛的学习过程中你可以获得一定的能力、获得一定的感悟,也许能获得到一定的荣誉,如果你足够优秀的话可以最后保研上岸,成为别人眼里的佼佼者。
<strong>但是,笔者想说的是:</strong> **但是,笔者想说的是:**
大学不再是像从前那般循规蹈矩,你可以在大学的生活中尝试各种各样的事情,这四年时光本就是一个不断试错的过程。如果你本身对竞赛十分感兴趣,或者说想要通过竞赛让自己之后的路走的更加顺畅,那么我会祝愿你能学有所成,并且最终能获得到自己满意的成绩; 大学不再是像从前那般循规蹈矩,你可以在大学的生活中尝试各种各样的事情,这四年时光本就是一个不断试错的过程。如果你本身对竞赛十分感兴趣,或者说想要通过竞赛让自己之后的路走的更加顺畅,那么我会祝愿你能学有所成,并且最终能获得到自己满意的成绩;
<strong>但我更希望你是真正地对嵌入式感兴趣,热爱创造它的时光,热爱披荆斩棘后成功的欣喜,热爱它的生命,热爱它赋予你的意义...在这段学习历程中,竞赛会是你成长的一部分,但不是全部,也不能是全部。作为一个伪理想主义者(我认为完全的理想主义者不会痛苦,只有现实的理想主义者才会痛不欲生),生命中总会有更重要的东西,比如爱,无论是喜爱还是热爱,比如人,无论是亲朋还是蒹葭。</strong> **但我更希望你是真正地对嵌入式感兴趣,热爱创造它的时光,热爱披荆斩棘后成功的欣喜,热爱它的生命,热爱它赋予你的意义...在这段学习历程中,竞赛会是你成长的一部分,但不是全部,也不能是全部。作为一个伪理想主义者(我认为完全的理想主义者不会痛苦,只有现实的理想主义者才会痛不欲生),生命中总会有更重要的东西,比如爱,无论是喜爱还是热爱,比如人,无论是亲朋还是蒹葭。**
科技的最终意义是提高生产力,但科技带来的意义也远不止于此,我希望你们在接下来学习嵌入式的过程中,能不忘本心,钦佩自己的永远独立,钦佩自己的永远自由,不被世界的功利化所迷惑,感受嵌入式那独特而又真实的生命力! 科技的最终意义是提高生产力,但科技带来的意义也远不止于此,我希望你们在接下来学习嵌入式的过程中,能不忘本心,钦佩自己的永远独立,钦佩自己的永远自由,不被世界的功利化所迷惑,感受嵌入式那独特而又真实的生命力!

View File

@@ -48,7 +48,7 @@ Intel 的 STC89C51\C52 系列早在上世纪 80 年代就已经广泛运用,
如果我们去图书馆里的书架上拿书并观看,则需要:走到对应书架 - 拿书(获取数据)- 回到书桌,这需要花费相当一部分的时间,此时硬盘相当于书架;如果我们直接拿书桌上的书,则相对速度会快很多,此时书桌相当于主存;如果我们手上就有一本书,那么我们低头就可以看到,手就相当于寄存器。所以,寄存器是 CPU 内部用来存放数据的一些小型的存储区域,用来暂时存放参与运算的数据和运算结果以及一些 CPU 运行所需要的信息。 如果我们去图书馆里的书架上拿书并观看,则需要:走到对应书架 - 拿书(获取数据)- 回到书桌,这需要花费相当一部分的时间,此时硬盘相当于书架;如果我们直接拿书桌上的书,则相对速度会快很多,此时书桌相当于主存;如果我们手上就有一本书,那么我们低头就可以看到,手就相当于寄存器。所以,寄存器是 CPU 内部用来存放数据的一些小型的存储区域,用来暂时存放参与运算的数据和运算结果以及一些 CPU 运行所需要的信息。
以我举例而言,<strong>可见寄存器获得数据的速度会快于主存与硬盘,而存储数据的大小将会小于主存与硬盘</strong>,如果这块不清楚的话也可以去看 也许你会用上的基础知识 中的存储器知识部分。 以我举例而言,**可见寄存器获得数据的速度会快于主存与硬盘,而存储数据的大小将会小于主存与硬盘**,如果这块不清楚的话也可以去看 也许你会用上的基础知识 中的存储器知识部分。
而从汇编语言的角度来讲(此为 Intel 的汇编语法): 而从汇编语言的角度来讲(此为 Intel 的汇编语法):
@@ -79,7 +79,7 @@ ORG 0BH
以上简单例举了寄存器的一般作用,以汇编语言出发去讲的原因是:它能有效地展现底层代码的工作原理,既不会像机器语言那样只用 0、1 表示的晦涩难懂,又不会像高级语言那般难以直观地看到底层的工作方式。但是,我们做嵌入式入门开发的过程中并不会让你直接去写汇编语言,而是以最基础的 C 语言相比汇编而言C 在功能上、结构性、可读性、可维护性上有明显的优势),通过 Keil、IAR 等拥有交叉编译器的 C 语言软件开发系统来完成高级语言、汇编语言、机器语言的转码工作,从而通过 C 语言的编写来控制单片机等嵌入式系统的开发。 以上简单例举了寄存器的一般作用,以汇编语言出发去讲的原因是:它能有效地展现底层代码的工作原理,既不会像机器语言那样只用 0、1 表示的晦涩难懂,又不会像高级语言那般难以直观地看到底层的工作方式。但是,我们做嵌入式入门开发的过程中并不会让你直接去写汇编语言,而是以最基础的 C 语言相比汇编而言C 在功能上、结构性、可读性、可维护性上有明显的优势),通过 Keil、IAR 等拥有交叉编译器的 C 语言软件开发系统来完成高级语言、汇编语言、机器语言的转码工作,从而通过 C 语言的编写来控制单片机等嵌入式系统的开发。
而抽象层面的 C 代码需要通过访问寄存器来直接控制硬件。所以在嵌入式开发的过程中C 有了特殊的含义:<strong>C 里的数字代表的可能只是一个地址或者一个数据,但是在嵌入式开发里,这样一个数字也可以代表着一种寄存器状态。</strong> 而抽象层面的 C 代码需要通过访问寄存器来直接控制硬件。所以在嵌入式开发的过程中C 有了特殊的含义:**C 里的数字代表的可能只是一个地址或者一个数据,但是在嵌入式开发里,这样一个数字也可以代表着一种寄存器状态。**
下面引入一个 STM32F1 系列的 GPIO 部分寄存器图(来源正点原子提供的 F1 参考手册): 下面引入一个 STM32F1 系列的 GPIO 部分寄存器图(来源正点原子提供的 F1 参考手册):
@@ -146,9 +146,9 @@ typedef struct
所以由以上提到的例子而言C 语言可以从如下三方面进行与寄存器之间的控制: 所以由以上提到的例子而言C 语言可以从如下三方面进行与寄存器之间的控制:
1. 寄存器的地址可以使用<strong>指针变量</strong>来访问。 1. 寄存器的地址可以使用**指针变量**来访问。
2. C 语言中的<strong>结构体可以用于表示寄存器映射</strong> 2. C 语言中的**结构体可以用于表示寄存器映射**
3. C 语言中的<strong>位域可以用于表示寄存器中的位</strong> 3. C 语言中的**位域可以用于表示寄存器中的位**
而且 C 语言中的内联汇编可以用于直接访问寄存器。在某些情况下,如果我们需要直接访问寄存器来完成复杂的硬件控制操作,则可以使用汇编语言指令来直接访问寄存器,从而实现复杂的硬件控制操作。常见的如,堆栈大小的设置等。 而且 C 语言中的内联汇编可以用于直接访问寄存器。在某些情况下,如果我们需要直接访问寄存器来完成复杂的硬件控制操作,则可以使用汇编语言指令来直接访问寄存器,从而实现复杂的硬件控制操作。常见的如,堆栈大小的设置等。

View File

@@ -6,11 +6,11 @@
而在此栏目中,我们将讲述相关操作系统在嵌入式上的应用,让你的嵌入式产品更加的智慧!(当然裸机并不一定就比带操作系统的嵌入式产品差,只是应用方向不同或者说有时候需要考虑产品的成本问题) 而在此栏目中,我们将讲述相关操作系统在嵌入式上的应用,让你的嵌入式产品更加的智慧!(当然裸机并不一定就比带操作系统的嵌入式产品差,只是应用方向不同或者说有时候需要考虑产品的成本问题)
Ps本栏目只例举几个目前开发工程中常见的操作系统的学习与开发<strong>具体的移植过程可 web 或者自行探索 - 相信我,出色的移植能力是嵌入式开发者必不可少的。</strong> Ps本栏目只例举几个目前开发工程中常见的操作系统的学习与开发**具体的移植过程可 web 或者自行探索 - 相信我,出色的移植能力是嵌入式开发者必不可少的。**
## RTOS ## RTOS
MCU 本身就能做到一定的实时性,那为什么还是需要 RTOS实时操作系统<strong>其实评判实时系统的关键并不是系统对外部事件的处理速度,而是处理事件的时间的可预见性和确定性。</strong>举个例子Windows 操作系统在 CPU 没有其他任务时可以在很短的时间内对外部事件作出一定的响应,但是当某些后台任务在运行时,有时候响应速度会变得很慢甚至出现假死现象,这并不是因为 Windows 速度不够快或者效率不够高导致的,而是因为 Windows 对事件的响应不能提供准确性,所以其不能算作一个实时操作系统。<strong>并且在笔者看来,实时操作系统除了可以达到完成每次任务所需时间的一致性外,其相应的操作系统产品(例如我们本栏目将重点介绍的 FreeRTOS这里可以简单提一下为啥要选 FreeRTOS显而易见因为-Free还具有可以简化整体架构、开发等工作的作用。</strong> MCU 本身就能做到一定的实时性,那为什么还是需要 RTOS实时操作系统**其实评判实时系统的关键并不是系统对外部事件的处理速度,而是处理事件的时间的可预见性和确定性。**举个例子Windows 操作系统在 CPU 没有其他任务时可以在很短的时间内对外部事件作出一定的响应,但是当某些后台任务在运行时,有时候响应速度会变得很慢甚至出现假死现象,这并不是因为 Windows 速度不够快或者效率不够高导致的,而是因为 Windows 对事件的响应不能提供准确性,所以其不能算作一个实时操作系统。**并且在笔者看来,实时操作系统除了可以达到完成每次任务所需时间的一致性外,其相应的操作系统产品(例如我们本栏目将重点介绍的 FreeRTOS这里可以简单提一下为啥要选 FreeRTOS显而易见因为-Free还具有可以简化整体架构、开发等工作的作用。**
RTOS 中最重要的概念则是“任务”。 RTOS 中最重要的概念则是“任务”。
@@ -24,7 +24,7 @@ RTOS 中最重要的概念则是“任务”。
![](https://cdn.xyxsw.site/boxcntQgR61yRboDpyb1bpI10Xp.png) ![](https://cdn.xyxsw.site/boxcntQgR61yRboDpyb1bpI10Xp.png)
所以,<strong>其实可以这么说RTOS 将整个流程变成了很多个 while1【每个任务都是个 while1】。</strong> 所以,**其实可以这么说RTOS 将整个流程变成了很多个 while1【每个任务都是个 while1】。**
并且根据我上述所描述的内容,一个任务需要的属性大致如下(以启动函数为例进行介绍): 并且根据我上述所描述的内容,一个任务需要的属性大致如下(以启动函数为例进行介绍):
@@ -63,7 +63,7 @@ int main{
如果你已经对以上所涉及到的方面有了一定的了解,那么欢迎来到机器人开发者的殿堂-Robot Operating System 如果你已经对以上所涉及到的方面有了一定的了解,那么欢迎来到机器人开发者的殿堂-Robot Operating System
由于硬件技术的飞速发展,针对于机器人软件设计的框架也面临着极大的挑战,而 ROS 的出现无异是所有机器人开发者的福音,因为如果按照以前的制作一个机器人流程来讲,也许你要经历以下步骤:硬件结构搭建、控制处理、相关算法构建等等,但是 ROS 的开源共享模式令其可以在其平台上巧妙利用别人的开源模型完成自己的机器人搭建,<strong>也就是说 Ros 的出现打破了原本各个开发者(或团队)闭门造车的开发现象,使得其可以共享优秀的机器人应用软件,换句话说就是提高了机器人研发的软件复用率。(毕竟哪个团队都不可能同时在建图、导航、视觉等机器人应用方面处于顶尖位置)</strong> 由于硬件技术的飞速发展,针对于机器人软件设计的框架也面临着极大的挑战,而 ROS 的出现无异是所有机器人开发者的福音,因为如果按照以前的制作一个机器人流程来讲,也许你要经历以下步骤:硬件结构搭建、控制处理、相关算法构建等等,但是 ROS 的开源共享模式令其可以在其平台上巧妙利用别人的开源模型完成自己的机器人搭建,**也就是说 Ros 的出现打破了原本各个开发者(或团队)闭门造车的开发现象,使得其可以共享优秀的机器人应用软件,换句话说就是提高了机器人研发的软件复用率。(毕竟哪个团队都不可能同时在建图、导航、视觉等机器人应用方面处于顶尖位置)**
![](https://cdn.xyxsw.site/boxcnRy7E27xggqNshXX3cu4J5Q.png) ![](https://cdn.xyxsw.site/boxcnRy7E27xggqNshXX3cu4J5Q.png)
@@ -71,9 +71,9 @@ int main{
但是 Linux 只是一个通用系统,并没有在机器人开发上提供相应的中间件,所以 ROS 提供了基于 TCP/UDP 的通信接口(机器人的工作当然需要通讯),在再此之上提供了相应的基础开发库供给至应用层。 但是 Linux 只是一个通用系统,并没有在机器人开发上提供相应的中间件,所以 ROS 提供了基于 TCP/UDP 的通信接口(机器人的工作当然需要通讯),在再此之上提供了相应的基础开发库供给至应用层。
此时应用层则有个很重要的概念-Master管理者其负责管理整个系统的正常运行。如果我们需要获得比较成熟的相关领域开源机器人包按以往的操作必将是进行一次比较复杂的移植你需要考虑各种因素比如硬件支持、与其他移植包是否冲突等等<strong>但是在 ROS 系统中引入了功能包的概念,你可以在 ROS 社区中下载相关版本(与你的 ROS 版本相匹配的机器人应用功能包完成一次非常简单的移植过程CV你不需要关注其内部的具体运行机制只需关注接口的定义与使用规则便可进行相应的二次开发在 ROS 中你需要关注的是相关节点之间的关系,可以通过 rqt_graph 获取清晰的节点图),相当于给你做好了一个跟机器人开发有关的高集成度</strong><strong>SDK</strong><strong>平台。</strong>(当然如果你感兴趣的话可以做一定的了解,但这将牵扯到相关内容的庞大体系,比如如果你想了解自主导航是如何运行的,你首先需要了解 SLAM 算法的运行机制以及激光雷达或者相关深度摄像机的运用,然后你需要了解什么是深度信息什么是里程计信息,为什么可以表示机器人的位置信息,要如何进行一些相关的位置信息修正,然后 bulabula。<strong>以笔者自身的学习经历而言,学习相关的理论基础体系,将对你的二次开发有极大的帮助,而不会造成盲目使用接口的情况</strong> 此时应用层则有个很重要的概念-Master管理者其负责管理整个系统的正常运行。如果我们需要获得比较成熟的相关领域开源机器人包按以往的操作必将是进行一次比较复杂的移植你需要考虑各种因素比如硬件支持、与其他移植包是否冲突等等**但是在 ROS 系统中引入了功能包的概念,你可以在 ROS 社区中下载相关版本(与你的 ROS 版本相匹配的机器人应用功能包完成一次非常简单的移植过程CV你不需要关注其内部的具体运行机制只需关注接口的定义与使用规则便可进行相应的二次开发在 ROS 中你需要关注的是相关节点之间的关系,可以通过 rqt_graph 获取清晰的节点图),相当于给你做好了一个跟机器人开发有关的高集成度****SDK****平台。**(当然如果你感兴趣的话可以做一定的了解,但这将牵扯到相关内容的庞大体系,比如如果你想了解自主导航是如何运行的,你首先需要了解 SLAM 算法的运行机制以及激光雷达或者相关深度摄像机的运用,然后你需要了解什么是深度信息什么是里程计信息,为什么可以表示机器人的位置信息,要如何进行一些相关的位置信息修正,然后 bulabula。**以笔者自身的学习经历而言,学习相关的理论基础体系,将对你的二次开发有极大的帮助,而不会造成盲目使用接口的情况**
根据以上我讲述的相关内容可知:<strong>ROS 系统的优点在于,你能将社区里的有关机器人的开发模块集大成于一身,并且通过 ROS 与控制板通讯(此时类似于 STM32 的裸机主控便变成了控制板 - 用于接收 ROS 的调控完成相应电机、舵机的控制,或者完成一定的例如 oled 显示的简单任务),从而完成 ROS 系统内部开源算法对整个机器人的控制。</strong> 根据以上我讲述的相关内容可知:**ROS 系统的优点在于,你能将社区里的有关机器人的开发模块集大成于一身,并且通过 ROS 与控制板通讯(此时类似于 STM32 的裸机主控便变成了控制板 - 用于接收 ROS 的调控完成相应电机、舵机的控制,或者完成一定的例如 oled 显示的简单任务),从而完成 ROS 系统内部开源算法对整个机器人的控制。**
以下我简单介绍一下 ROS 的基础通讯方式: 以下我简单介绍一下 ROS 的基础通讯方式:
@@ -147,7 +147,7 @@ void chatterCallback(const std_msgs::String::ConstPtr& msg)
<Bilibili bvid='BV1zt411G7Vn'/> <Bilibili bvid='BV1zt411G7Vn'/>
<strong>提一嘴:很多人学 ROS 就学一个开头 - 比如就学了古月居的 21 讲,就认为自己已经了解到了 ROS 的大部分内容了</strong><strong>(不会有人现在还是纯看视频学习吧)</strong><strong>,实际上这是非常错误的想法。当你学完了视频的内容后,你甚至可能不会移植 wiki 上的功能包x_x甚至不知道如何去开发一个真实的机器人因为此 21 讲只是理论上的讲解,去做一个虚拟机器人在 gazebo 上运行。ROS 的学习上需要我们花大量的心思去学会接触新的东西,你们并不能只局限于我提供的推荐学习资料,因为相应的功能包不是一成不变的,而且也不是只有那么几个功能包,当你感受了 ROS 的自主建图、自主导航、机械臂控制、机器学习开发等等等等等等后,你才会发现 ROS 的世界是如此美妙!</strong> **提一嘴:很多人学 ROS 就学一个开头 - 比如就学了古月居的 21 讲,就认为自己已经了解到了 ROS 的大部分内容了****(不会有人现在还是纯看视频学习吧)****,实际上这是非常错误的想法。当你学完了视频的内容后,你甚至可能不会移植 wiki 上的功能包x_x甚至不知道如何去开发一个真实的机器人因为此 21 讲只是理论上的讲解,去做一个虚拟机器人在 gazebo 上运行。ROS 的学习上需要我们花大量的心思去学会接触新的东西,你们并不能只局限于我提供的推荐学习资料,因为相应的功能包不是一成不变的,而且也不是只有那么几个功能包,当你感受了 ROS 的自主建图、自主导航、机械臂控制、机器学习开发等等等等等等后,你才会发现 ROS 的世界是如此美妙!**
2、b 站赵虚左 ROS 课程(讲得细致多了,需要耐心看下去,要是我入门 ROS 的时候有这个视频就好了) 2、b 站赵虚左 ROS 课程(讲得细致多了,需要耐心看下去,要是我入门 ROS 的时候有这个视频就好了)

View File

@@ -168,7 +168,7 @@ mysql> select group_concat(id,username separator '_') from users;
![](https://cdn.xyxsw.site/boxcniDohuM3F8FbMqz7YSC0Y5g.png) ![](https://cdn.xyxsw.site/boxcniDohuM3F8FbMqz7YSC0Y5g.png)
<strong>真是惊人的壮举!我完全不认识这个叫 Liki5 的家伙,但我居然知道了他的密码对应的哈希值!</strong> **真是惊人的壮举!我完全不认识这个叫 Liki5 的家伙,但我居然知道了他的密码对应的哈希值!**
<del>那么到这里 SQL 注入你就已经完全学会了,接下来做一些小练习吧。</del> <del>那么到这里 SQL 注入你就已经完全学会了,接下来做一些小练习吧。</del>
@@ -787,8 +787,8 @@ INSERT 语句也被成功执行了,向数据库中插入了 Liki3 的数据
因此,从 MySQL 5.6.x 开始,有了取代 `information_schema` 的表名查询方式,如下所示 因此,从 MySQL 5.6.x 开始,有了取代 `information_schema` 的表名查询方式,如下所示
```python ```python
select table_name from mysql.innodb_index_stats where database_name=<em>database</em>(); select table_name from mysql.innodb_index_stats where database_name=*database*();
select table_name from mysql.innodb_table_stats where database_name=<em>database</em>(); select table_name from mysql.innodb_table_stats where database_name=*database*();
``` ```
![](https://cdn.xyxsw.site/boxcnbMtjAq8osStjcSbFuIdDSc.png) ![](https://cdn.xyxsw.site/boxcnbMtjAq8osStjcSbFuIdDSc.png)
@@ -804,8 +804,8 @@ select table_name from mysql.innodb_table_stats where database_name=<em>database
其中就包含了存储数据库和对应的数据表,于是就有了如下的表名查询方式 其中就包含了存储数据库和对应的数据表,于是就有了如下的表名查询方式
```sql ```sql
select table_name from sys.schema_table_statistics_with_buffer where table_schema=<em>database</em>(); select table_name from sys.schema_table_statistics_with_buffer where table_schema=*database*();
select table_name from sys.x$schema_table_statistics_with_buffer where table_schema=<em>database</em>(); select table_name from sys.x$schema_table_statistics_with_buffer where table_schema=*database*();
``` ```
![](https://cdn.xyxsw.site/boxcnV68mdIQmovJwczDsOc53gc.png) ![](https://cdn.xyxsw.site/boxcnV68mdIQmovJwczDsOc53gc.png)

View File

@@ -21,15 +21,15 @@
[现代 JavaScript 教程](https://zh.javascript.info/) [现代 JavaScript 教程](https://zh.javascript.info/)
::: warning 🎈 ::: warning 🎈
<strong>快速上手的参考建议</strong> **快速上手的参考建议**
<strong>HTML</strong><strong> </strong>可以先认知常用标签( body / div / span / a / img 等)及其常用属性 **HTML**** **可以先认知常用标签( body / div / span / a / img 等)及其常用属性
<strong>CSS </strong>了解常见的颜色属性(字体颜色 / 背景颜色 / 边框颜色 等)、字体相关属性(字号 / 字重 / 行高 等、盒子模型padding / border / margin、用于布局的属性float / flex / grid、单位px / rem / em / vh / vw 等、选择器id 选择器 / 类选择器 等) **CSS**了解常见的颜色属性(字体颜色 / 背景颜色 / 边框颜色 等)、字体相关属性(字号 / 字重 / 行高 等、盒子模型padding / border / margin、用于布局的属性float / flex / grid、单位px / rem / em / vh / vw 等、选择器id 选择器 / 类选择器 等)
<strong>JS</strong><strong> </strong>了解基本语法(变量定义 / 判断 / 循环 / 函数定义 / etc与 DOM 操作 **JS**** **了解基本语法(变量定义 / 判断 / 循环 / 函数定义 / etc与 DOM 操作
涉及<strong>前后端交互</strong>的部分可以了解 fetch 的使用 涉及**前后端交互**的部分可以了解 fetch 的使用
其他诸如 HTML5 / CSS3 / ES6+ 的知识可以暂时跳过,<del>任务要用到再查</del> 其他诸如 HTML5 / CSS3 / ES6+ 的知识可以暂时跳过,<del>任务要用到再查</del>
@@ -102,7 +102,7 @@
#### 基本要求 #### 基本要求
- 可以对 todo 进行增删改查 - 可以对 todo 进行增删改查
- 至少存在 <strong>待完成</strong>/<strong>已完成</strong> 两种不同的状态Todo 应该能够在不同状态间切换。更进一步,你也可以设计一个 <strong>进行中</strong> 状态。 - 至少存在 **待完成**/**已完成** 两种不同的状态Todo 应该能够在不同状态间切换。更进一步,你也可以设计一个 **进行中** 状态。
#### 额外发挥 #### 额外发挥

View File

@@ -2,7 +2,7 @@
::: warning 📌 ::: warning 📌
如果是有一定基础的同学,可以考虑采用一些辅助工具(React / Vue / jQuery 等),样式方面也可以采用你喜欢的组件库(Antd / ElementUI /<strong> </strong>Bootstrap 等)实现。 如果是有一定基础的同学,可以考虑采用一些辅助工具(React / Vue / jQuery 等),样式方面也可以采用你喜欢的组件库(Antd / ElementUI / Bootstrap 等)实现。
::: :::

View File

@@ -24,9 +24,9 @@ Hello~这里是杭电助手技术部后端,无论基础如何,您都可以
官网虽然是英文,但是非常非常的友好,近年还刚翻新过一次好看了许多,还有各种可爱的吉祥物插图。 官网虽然是英文,但是非常非常的友好,近年还刚翻新过一次好看了许多,还有各种可爱的吉祥物插图。
这只吉祥物囊袋鼠的英文学名为 <strong>Gopher</strong>,每位热爱 Golang 的开发者都会自称 <strong>Gopher</strong> (就像 jvaver 一样(x),而它的造型出于创始人之一 Rob Pike 的妻子之手。 这只吉祥物囊袋鼠的英文学名为 **Gopher**,每位热爱 Golang 的开发者都会自称 **Gopher** (就像 jvaver 一样(x),而它的造型出于创始人之一 Rob Pike 的妻子之手。
#### 视频资料(<strong>P2-P3</strong>) #### 视频资料(**P2-P3**)
<Bilibili bvid='BV1zR4y1t7Wj'/> <Bilibili bvid='BV1zR4y1t7Wj'/>
@@ -74,7 +74,7 @@ https://www.jetbrains.com/go/
GoLand 可以使用教育邮箱学生认证白嫖噢~👀 GoLand 可以使用教育邮箱学生认证白嫖噢~👀
::: :::
#### 视频资料(<strong>P4-P6</strong>) #### 视频资料(**P4-P6**)
<Bilibili bvid='BV1zR4y1t7Wj'/> <Bilibili bvid='BV1zR4y1t7Wj'/>
@@ -99,7 +99,7 @@ https://polarisxu.studygolang.com/posts/go/2022-dev-env/
Golang 的语法是 C/C++ 系的,在许多地方你都可以看到他们的影子,这对未来 C 的学习更有自顶向下的帮助。当然,如果你曾经用过 Java、PythonGolang 的语法你可能会不太习惯,这不会是问题~在熟悉语法后,你会发现 “Golang 一把梭” 是真实存在的 🤓。 Golang 的语法是 C/C++ 系的,在许多地方你都可以看到他们的影子,这对未来 C 的学习更有自顶向下的帮助。当然,如果你曾经用过 Java、PythonGolang 的语法你可能会不太习惯,这不会是问题~在熟悉语法后,你会发现 “Golang 一把梭” 是真实存在的 🤓。
<strong>对于基础语法的学习,无需一时学习过深,也不必花费过多时间在此</strong>。<strong>即使半懵半懂,在多次实践后也会渐渐领悟</strong> **对于基础语法的学习,无需一时学习过深,也不必花费过多时间在此**。**即使半懵半懂,在多次实践后也会渐渐领悟**
本次任务并不需要用到反射、并发等高级特性(学到时可选择性暂时避开),最深只需要用到结构体与方法的相关知识。 本次任务并不需要用到反射、并发等高级特性(学到时可选择性暂时避开),最深只需要用到结构体与方法的相关知识。
@@ -110,7 +110,7 @@ Golang 的语法是 C/C++ 系的,在许多地方你都可以看到他们的影
#### 文字资料: #### 文字资料:
- 非常推荐的 Go Tour 中文版。Go Tour 是 <strong>Go 官方为初学者打造的渐进式教程</strong>,你可以跟随着它的步伐一点点探索 Go 语言 。Go Tour 的代码都充满着它的<strong>设计哲学与最佳实践</strong>,是每位 Gopher 的必经之路。同时它也是<strong>交互式的</strong>,左侧是教程,右侧能直接敲代码,在网页上运行。 - 非常推荐的 Go Tour 中文版。Go Tour 是 **Go 官方为初学者打造的渐进式教程**,你可以跟随着它的步伐一点点探索 Go 语言 。Go Tour 的代码都充满着它的**设计哲学与最佳实践**,是每位 Gopher 的必经之路。同时它也是**交互式的**,左侧是教程,右侧能直接敲代码,在网页上运行。
https://tour.go-zh.org/welcome/1 https://tour.go-zh.org/welcome/1
@@ -133,7 +133,7 @@ HTTP 协议起草与演进之路十分坎坷,但每一步都举足轻重,在
#### 文字资料: #### 文字资料:
- 非常著名的阮一峰博客 <strong>(他的博客可以从最早开始都过一遍,很多计算机科普可以说永不过时)</strong> - 非常著名的阮一峰博客 **(他的博客可以从最早开始都过一遍,很多计算机科普可以说永不过时)**
https://www.ruanyifeng.com/blog/2016/08/http.html https://www.ruanyifeng.com/blog/2016/08/http.html
@@ -183,7 +183,7 @@ https://www.runoob.com/http/http-intro.html
请运用你在第三小节中学习的 `Golang 包(依赖)管理` 正确地安装 Gin 并学习使用它。 请运用你在第三小节中学习的 `Golang 包(依赖)管理` 正确地安装 Gin 并学习使用它。
<strong>相关资料</strong> **相关资料**
- [GitHub - gin-gonic/gin: Gin is a HTTP web framework written in Go (Golang)](https://github.com/gin-gonic/gin) - Gin 的官方仓库及权威文档。 - [GitHub - gin-gonic/gin: Gin is a HTTP web framework written in Go (Golang)](https://github.com/gin-gonic/gin) - Gin 的官方仓库及权威文档。
- [Go Gin Example](https://github.com/eddycjy/go-gin-example) - 使用 Gin 的一个小项目,难度较高。 - [Go Gin Example](https://github.com/eddycjy/go-gin-example) - 使用 Gin 的一个小项目,难度较高。

View File

@@ -6,13 +6,13 @@
## 章节题目解释 ## 章节题目解释
- 何为 Web可以狭义地理解为<strong>「</strong><strong>前端</strong><strong>」+「后端」</strong> - 何为 Web可以狭义地理解为<strong>「前端」+「后端」</strong>
- 何为开发:明确产品需求,写代码,调试代码,部署项目,写项目文档,维护项目 - 何为开发:明确产品需求,写代码,调试代码,部署项目,写项目文档,维护项目
- 何为入门:不知道要马上学会,而是知道 Web 开发是什么,以及如何去学 - 何为入门:不知道要马上学会,而是知道 Web 开发是什么,以及如何去学
## 前端?后端? ## 前端?后端?
### <strong>行业背景</strong> ### **行业背景**
前端开发和后端开发可以说是 2023 年以前,计算机学生就业最广泛的方向(当然工资也不低) 前端开发和后端开发可以说是 2023 年以前,计算机学生就业最广泛的方向(当然工资也不低)
@@ -20,7 +20,7 @@
我们接触互联网,直接使用最多的是什么?——软件 我们接触互联网,直接使用最多的是什么?——软件
同样,我们可以狭义地把大部分软件开发理解为:<strong>「软件」(程序员需要做的部分)=「</strong><strong>前端</strong><strong>」+「后端」</strong> 同样,我们可以狭义地把大部分软件开发理解为:**「软件」(程序员需要做的部分)=「****前端****」+「后端」**
所以大部分计算机学生毕业,都是为公司的具体的业务,开发对应的手机 APP、网站、电脑软件。 所以大部分计算机学生毕业,都是为公司的具体的业务,开发对应的手机 APP、网站、电脑软件。
@@ -28,13 +28,13 @@
本文写于 2023 年 4 月2023 年以来AIChatGPT、Copilot、MidJourney正在颠覆每个领域。可能在不远的将来大部分的前后端开发都能通过 AI 自动生成 99% 的代码,然后人工审核、校对、修改剩下的 1%。 本文写于 2023 年 4 月2023 年以来AIChatGPT、Copilot、MidJourney正在颠覆每个领域。可能在不远的将来大部分的前后端开发都能通过 AI 自动生成 99% 的代码,然后人工审核、校对、修改剩下的 1%。
### <strong>步入正题 - 何为前后端 - 通俗认识</strong> ### **步入正题 - 何为前后端 - 通俗认识**
<strong>前端</strong> **前端**
前端可以狭义地理解为,一个软件中看得到的部分。比如网页上的文字图片、各种花里胡哨的样式、以及交互操作。广义上来说,大家用的各种 APP、电脑上的应用程序用户界面的部分都是前端干的活。 前端可以狭义地理解为,一个软件中看得到的部分。比如网页上的文字图片、各种花里胡哨的样式、以及交互操作。广义上来说,大家用的各种 APP、电脑上的应用程序用户界面的部分都是前端干的活。
<strong>后端</strong> **后端**
相对于前端,后端当然是「看不见的部分」。 相对于前端,后端当然是「看不见的部分」。
@@ -44,13 +44,13 @@
所以一个软件的关键数据,肯定不是在用户侧(即前端)的。需要有这么一个东西,来存储数据(存储数据的地方叫数据库),来解析用户的请求,这就是后端。 所以一个软件的关键数据,肯定不是在用户侧(即前端)的。需要有这么一个东西,来存储数据(存储数据的地方叫数据库),来解析用户的请求,这就是后端。
<strong>例子</strong> **例子**
举个详细的例子,购物软件上点了下单并支付,这时候前端就会发送一个网络请求,告诉后端:<em>用户某某某,买了什么东西,价格和数量是多少,收货地址是多少。。。</em> 举个详细的例子,购物软件上点了下单并支付,这时候前端就会发送一个网络请求,告诉后端:<em>用户某某某,买了什么东西,价格和数量是多少,收货地址是多少。。。</em>
后端收到了信息,先解析,然后修改数据库中存储的关键信息,比如新建一个订单信息,把商品的数量 -1 等等,再把下单的结果告诉给前端。前端收到信息后,就会渲染页面,提示「下单成功」! 后端收到了信息,先解析,然后修改数据库中存储的关键信息,比如新建一个订单信息,把商品的数量 -1 等等,再把下单的结果告诉给前端。前端收到信息后,就会渲染页面,提示「下单成功」!
### <strong>深入 - 何为前后端 - 技术剖析</strong> ### **深入 - 何为前后端 - 技术剖析**
在了解了前后端的宏观概念后,我们继续来感受一下背后的技术细节吧! 在了解了前后端的宏观概念后,我们继续来感受一下背后的技术细节吧!
@@ -79,7 +79,7 @@
想知道前端需要用到什么技术,就来看看前端到底需要解决什么问题吧! 想知道前端需要用到什么技术,就来看看前端到底需要解决什么问题吧!
1. <strong>页面渲染</strong> 1. **页面渲染**
无论是做网页,还是做 APP 界面,都得「画」出界面。 无论是做网页,还是做 APP 界面,都得「画」出界面。
@@ -89,7 +89,7 @@
<em>(拓展:还有一些技术能够做到跨平台,比如通过某种技术把浏览器包装成一个 APP就能只出同时支持浏览器和 APP 的</em><em>前端</em><em>;比如创建新的第三方前端框架,能把程序员写的代码转换成原生的 IOS、安卓 APP</em> <em>(拓展:还有一些技术能够做到跨平台,比如通过某种技术把浏览器包装成一个 APP就能只出同时支持浏览器和 APP 的</em><em>前端</em><em>;比如创建新的第三方前端框架,能把程序员写的代码转换成原生的 IOS、安卓 APP</em>
1. <strong>用户交互</strong> 1. **用户交互**
如何实现“点击「留言」按钮,系统自动提交留言”?或者当用户点击按钮的时候,检测一下用户输入的内容是不是空。 如何实现“点击「留言」按钮,系统自动提交留言”?或者当用户点击按钮的时候,检测一下用户输入的内容是不是空。

View File

@@ -40,7 +40,7 @@
### 信用、货币的引入 ### 信用、货币的引入
引入一个概念,<strong>信用</strong> 引入一个概念,**信用**
做面粉和做面包的都彼此信任,相信对面总有一天会兑现承诺,允许赊账 做面粉和做面包的都彼此信任,相信对面总有一天会兑现承诺,允许赊账
@@ -61,9 +61,9 @@
| 交易面包 | 信用-10获得 25 个面包 | 信用 +11 | | 交易面包 | 信用-10获得 25 个面包 | 信用 +11 |
| 期末信用 | 0 | 1 | | 期末信用 | 0 | 1 |
稍微看一下就会发现,这个所谓的信用,和现在的<strong>货币</strong>没有任何区别,如果用现在的话说,一个信用就相当于 25 个面包 稍微看一下就会发现,这个所谓的信用,和现在的**货币**没有任何区别,如果用现在的话说,一个信用就相当于 25 个面包
因此,可以得到一个结论,<strong>货币就是信用</strong> 只是现在我们在使用货币时,信任的不是对面的人,而是国家,<strong>货币事实上就是国家信用</strong> 因此,可以得到一个结论,**货币就是信用** 只是现在我们在使用货币时,信任的不是对面的人,而是国家,**货币事实上就是国家信用**
> 这个加入第三方解决问题的思想在计算机科学里也非常常见(没有什么问题是加一个中间层不能解决的),在经济学里亦是如此。但额外补充,引入第三方信用的方案看似是分散了风险,但当考虑金融资产之间的关联性时,可能已经分散的风险又会集中,这是系统性风险的最大来源。(比如,国家如果破产了怎么办?)对应到对第三方的信用丧失,最常见的应对策略是买入避险资产,目前唯一的公认避险资产是黄金。(黄金从性质上来说具有天然的信用(不可人工制造,也就是不会突然增加减少,自然保有量即是信用),而且没有货币作用之外的属性(不能吃,不能穿,没有用,不是工业原料),是天然的货币) > 这个加入第三方解决问题的思想在计算机科学里也非常常见(没有什么问题是加一个中间层不能解决的),在经济学里亦是如此。但额外补充,引入第三方信用的方案看似是分散了风险,但当考虑金融资产之间的关联性时,可能已经分散的风险又会集中,这是系统性风险的最大来源。(比如,国家如果破产了怎么办?)对应到对第三方的信用丧失,最常见的应对策略是买入避险资产,目前唯一的公认避险资产是黄金。(黄金从性质上来说具有天然的信用(不可人工制造,也就是不会突然增加减少,自然保有量即是信用),而且没有货币作用之外的属性(不能吃,不能穿,没有用,不是工业原料),是天然的货币)
@@ -73,7 +73,7 @@
### 价格对分配结果的影响 ### 价格对分配结果的影响
上面的情况中,我们始终在讨论一种可以周而复始,永远循环的情况。<strong>财富也不会增长或者减少</strong>。出现这种情况的根本原因是每次期初各方的货币总是等于期末各方的货币。换言之,如果每期中,有一方的货币总是减少一点,那么我们就无法建立一个可以永远循环下去的经济系统了。下面用表来举个例子。 上面的情况中,我们始终在讨论一种可以周而复始,永远循环的情况。**财富也不会增长或者减少**。出现这种情况的根本原因是每次期初各方的货币总是等于期末各方的货币。换言之,如果每期中,有一方的货币总是减少一点,那么我们就无法建立一个可以永远循环下去的经济系统了。下面用表来举个例子。
面包价格4 元/个,其他条件不变 面包价格4 元/个,其他条件不变
@@ -86,7 +86,7 @@
可以看到,由于价格比例的变动,为了维持原先的消费状况,面粉厂不得不增加相应的开支,再 1 轮交易之后,面粉厂就会因为没有货币而无法参与交易。 可以看到,由于价格比例的变动,为了维持原先的消费状况,面粉厂不得不增加相应的开支,再 1 轮交易之后,面粉厂就会因为没有货币而无法参与交易。
因此,在不均衡的价格体系中,<strong>假设没有外部货币补充,处于弱势的部门只能通过削减消费来维持经济系统的运转</strong>。而且,不难想到,<strong>即使有外部的货币补充,货币补充通常也难以直接送到弱势方</strong>,这反而会造成弱势方在分配面包时处于更加弱势的地位,不得不消费更少的面包。这可能是今天经常说的“剥削”。 因此,在不均衡的价格体系中,**假设没有外部货币补充,处于弱势的部门只能通过削减消费来维持经济系统的运转**。而且,不难想到,**即使有外部的货币补充,货币补充通常也难以直接送到弱势方**,这反而会造成弱势方在分配面包时处于更加弱势的地位,不得不消费更少的面包。这可能是今天经常说的“剥削”。
这里还可以深入讨论一下,我们可以讨论一下价格比例的变动进而产生的分配变动。 这里还可以深入讨论一下,我们可以讨论一下价格比例的变动进而产生的分配变动。
@@ -98,7 +98,7 @@
更一般地,可以说,面粉厂消费的面包比例为 k而面包厂消费的面包比例为 1-k。 更一般地,可以说,面粉厂消费的面包比例为 k而面包厂消费的面包比例为 1-k。
<strong>也就是说,价格的绝对值并不怎么重要,重要的是价格之间的比值,这种价格比值的差异形成了分配的阶级性。</strong> **也就是说,价格的绝对值并不怎么重要,重要的是价格之间的比值,这种价格比值的差异形成了分配的阶级性。**
> 我们可以尝试着换一个角度来思考这个问题,从上述讨论中可以思考怎么样的价格调控是合理的,怎么样的是不合理的,通常来说,一些从直觉上感觉非常公平的定价方式,例如在成本基础上统一加一定量的利润,实际上是最不合理的,会带来非常严重的分配问题。 > 我们可以尝试着换一个角度来思考这个问题,从上述讨论中可以思考怎么样的价格调控是合理的,怎么样的是不合理的,通常来说,一些从直觉上感觉非常公平的定价方式,例如在成本基础上统一加一定量的利润,实际上是最不合理的,会带来非常严重的分配问题。
@@ -122,17 +122,17 @@
几轮循环下来,面粉厂和面包厂都会拥有非常多的货币。 几轮循环下来,面粉厂和面包厂都会拥有非常多的货币。
但显然,单纯有货币没有用,<strong>如果我们的系统里生产力不会提升,再多的货币也不能购买到超过 50 个面包</strong> 但显然,单纯有货币没有用,**如果我们的系统里生产力不会提升,再多的货币也不能购买到超过 50 个面包**
我们来讨论一下,由于这里大家都有了很多储蓄<strong>,面粉厂和面包厂都会有一种自己可以消费更多面包、或者不用工作也不会饿死的错觉</strong> 我们来讨论一下,由于这里大家都有了很多储蓄**,面粉厂和面包厂都会有一种自己可以消费更多面包、或者不用工作也不会饿死的错觉**
<strong>这种错觉是错误的,而它是如此的真实,一定会有人付诸实践,因此,这种错觉一定会被打破。</strong> **这种错觉是错误的,而它是如此的真实,一定会有人付诸实践,因此,这种错觉一定会被打破。**
假设现在发生了第一种情况,面粉厂觉得自己有了很多储蓄,愿意多消费更多面包,而面包厂也不甘示弱,觉得自己如果要减少面包消费,卖出的额外的面包需要涨价。 假设现在发生了第一种情况,面粉厂觉得自己有了很多储蓄,愿意多消费更多面包,而面包厂也不甘示弱,觉得自己如果要减少面包消费,卖出的额外的面包需要涨价。
假设面粉厂现在愿意以原价购买 25 个面包,额外还想购买 5 个面包,并与面包厂达成了协议,额外的部分每个付费 4 元,那么面包的价格就来到了 2.333 元,同样的,这种价格上涨也会导致双方认为自己的储蓄缩水,进而又回到工作的状态。 假设面粉厂现在愿意以原价购买 25 个面包,额外还想购买 5 个面包,并与面包厂达成了协议,额外的部分每个付费 4 元,那么面包的价格就来到了 2.333 元,同样的,这种价格上涨也会导致双方认为自己的储蓄缩水,进而又回到工作的状态。
从上述的讨论中可以发现,<strong>货币增加后,面包的价格并不一定立即增长,价格的涨幅通常也与货币的增幅没有直接关系,而是买卖双方针对价格博弈的后果。但可以肯定的是,脉冲式的价格上涨一定会出现</strong> 从上述的讨论中可以发现,**货币增加后,面包的价格并不一定立即增长,价格的涨幅通常也与货币的增幅没有直接关系,而是买卖双方针对价格博弈的后果。但可以肯定的是,脉冲式的价格上涨一定会出现**
### 印钞部门 ### 印钞部门
@@ -148,7 +148,7 @@
| 交易面包 | 货币-48102获得 24 个面包 | 货币 +52102 | 购买 2 个面包(-4 | | 交易面包 | 货币-48102获得 24 个面包 | 货币 +52102 | 购买 2 个面包(-4 |
| 期末 | 10224 个面包) | 10224 个面包) | 02 个面包) | | 期末 | 10224 个面包) | 10224 个面包) | 02 个面包) |
上述现象的神奇之处在于,<strong>铸币部门不做任何工作就获得了面包分配,而面粉厂与面包厂在不了解经济运行全貌的情况下,总是认为自己是由于节俭而增加了储蓄</strong> 上述现象的神奇之处在于,**铸币部门不做任何工作就获得了面包分配,而面粉厂与面包厂在不了解经济运行全貌的情况下,总是认为自己是由于节俭而增加了储蓄**
剩下的问题同情况 2 所讨论的,储蓄的积累会带来脉冲式的价格体系变化。 剩下的问题同情况 2 所讨论的,储蓄的积累会带来脉冲式的价格体系变化。
@@ -203,9 +203,9 @@
| 还清债务 | -10(0) | +10(100) | | 还清债务 | -10(0) | +10(100) |
| 期末 | 0 | 100 | | 期末 | 0 | 100 |
可以看到,这里看起来货币的结余情况一样,但实际上面粉厂减少了面包消费用于偿还债务,也就是说,<strong>通过上述描述货币和消费情况表格的表达方式,我们无法完整描述这一过程</strong>。在接下来,会引入简单的资产负债表,用于刻画这一过程。 可以看到,这里看起来货币的结余情况一样,但实际上面粉厂减少了面包消费用于偿还债务,也就是说,**通过上述描述货币和消费情况表格的表达方式,我们无法完整描述这一过程**。在接下来,会引入简单的资产负债表,用于刻画这一过程。
可惜的是,从另一角度说,面粉厂接下来若要重新获得储蓄,需要在接下来的 4 期内都只消费 10 个面包,否则面粉厂就无法恢复储蓄。更何况,面包厂未必有意愿自己消费 60 个面包,因此,<strong>在这种古早的经济系统下,超前的借贷实际上会降低经济活力,形成经济不景气的现象</strong> 可惜的是,从另一角度说,面粉厂接下来若要重新获得储蓄,需要在接下来的 4 期内都只消费 10 个面包,否则面粉厂就无法恢复储蓄。更何况,面包厂未必有意愿自己消费 60 个面包,因此,**在这种古早的经济系统下,超前的借贷实际上会降低经济活力,形成经济不景气的现象**
从另一个角度来探讨,可以发现面粉厂还债的时候实际上是通过还面包的方式来进行还债的,由此,可以推出另一个结论:当经济系统中一方货币不足时,可以通过降低消费或者提供服务的方式来偿还债务,也就是说经济系统中的债务量可以大于经济系统中的货币数量。关于这部分内容,下文还会有一些讨论。 从另一个角度来探讨,可以发现面粉厂还债的时候实际上是通过还面包的方式来进行还债的,由此,可以推出另一个结论:当经济系统中一方货币不足时,可以通过降低消费或者提供服务的方式来偿还债务,也就是说经济系统中的债务量可以大于经济系统中的货币数量。关于这部分内容,下文还会有一些讨论。
@@ -217,7 +217,7 @@
要回答这个问题,我们就需要讨论一下货币的本质是什么了。 要回答这个问题,我们就需要讨论一下货币的本质是什么了。
考虑你想要买一只鸡来吃,在人类社会中,鸡是一种商品,而你拥有货币。看起来你拥有对鸡(商品)的支配权,但实际并非如此。因为你不能走进大山里用货币向大自然换一只鸡来,<strong>实际上,在你购买这个商品时付出的货币,是购买了打猎或者养殖鸡的人的劳动力,而非是购买了鸡这种商品本身</strong>。同样,价值 1000 元在上文的意思就是,如何建造一个需要 1000 元才能够买得到的劳动力才能建造的博物馆,而不是说博物馆本身价值 1000 元。 考虑你想要买一只鸡来吃,在人类社会中,鸡是一种商品,而你拥有货币。看起来你拥有对鸡(商品)的支配权,但实际并非如此。因为你不能走进大山里用货币向大自然换一只鸡来,**实际上,在你购买这个商品时付出的货币,是购买了打猎或者养殖鸡的人的劳动力,而非是购买了鸡这种商品本身**。同样,价值 1000 元在上文的意思就是,如何建造一个需要 1000 元才能够买得到的劳动力才能建造的博物馆,而不是说博物馆本身价值 1000 元。
明白了这一点,就很好解释如何建造这个博物馆了,我们引入一个新的经济部门,叫建筑商,建筑商雇佣工人来完成博物馆的建设,每个工人的工资是 4 元,工人会把工资的全部都用来购买面包。所以,建造博物馆需要 1000/4=250 个人/期单位的劳动力。只要经济可以正常循环下去,每期都有工人来参与建设、获得面包,价值 1000 元的博物馆就可以建成。 明白了这一点,就很好解释如何建造这个博物馆了,我们引入一个新的经济部门,叫建筑商,建筑商雇佣工人来完成博物馆的建设,每个工人的工资是 4 元,工人会把工资的全部都用来购买面包。所以,建造博物馆需要 1000/4=250 个人/期单位的劳动力。只要经济可以正常循环下去,每期都有工人来参与建设、获得面包,价值 1000 元的博物馆就可以建成。
@@ -259,7 +259,7 @@
因此,只要政府部门能够敏锐地发现生产余力的存在,并且向经济系统中添加适量货币,就能够促进经济的发展,形成繁荣的经济现象。 因此,只要政府部门能够敏锐地发现生产余力的存在,并且向经济系统中添加适量货币,就能够促进经济的发展,形成繁荣的经济现象。
<strong>可惜的是,要增加多少储蓄才能让人们有足够多的消费意愿这一问题根本无法准确回答,政府部门在这一过程中总是倾向于多发行货币,因此,这种情况下通常也会带来商品价格的上涨。</strong> **可惜的是,要增加多少储蓄才能让人们有足够多的消费意愿这一问题根本无法准确回答,政府部门在这一过程中总是倾向于多发行货币,因此,这种情况下通常也会带来商品价格的上涨。**
## 产出结构、资源分配 ## 产出结构、资源分配
@@ -275,9 +275,9 @@
定价 4 元这一动作,其实就是说经济系统内的其他部门花 2 个面包供养农机厂,农机厂消费 2 个面包,产出一台农机。 定价 4 元这一动作,其实就是说经济系统内的其他部门花 2 个面包供养农机厂,农机厂消费 2 个面包,产出一台农机。
在这里,暂时不考虑 4 元这个定价是否合理,<strong>可以发现虽然农机厂生产的农机本身可以提高面包产量,但最终农机厂得到的供养却与</strong><strong>起</strong><strong>贡献的面包产量不成正比</strong>。而且,可以预见的是,在出售 10 台农机后,农机就不会被需要,这意味着农机厂若没有依靠这 10 期的供养产出更高效的农机就会被放弃供养而倒闭。 在这里,暂时不考虑 4 元这个定价是否合理,**可以发现虽然农机厂生产的农机本身可以提高面包产量,但最终农机厂得到的供养却与****起****贡献的面包产量不成正比**。而且,可以预见的是,在出售 10 台农机后,农机就不会被需要,这意味着农机厂若没有依靠这 10 期的供养产出更高效的农机就会被放弃供养而倒闭。
<strong>这一事实说明经济系统的运行规则存在其固有缺陷,并不一定可以把资源倾斜给实际提供产出的部门,相反,随着面包产量增加、政府增发货币,农机厂可能是收入提升最少的,意味着农机厂获得的资源分配会越来越少。</strong> **这一事实说明经济系统的运行规则存在其固有缺陷,并不一定可以把资源倾斜给实际提供产出的部门,相反,随着面包产量增加、政府增发货币,农机厂可能是收入提升最少的,意味着农机厂获得的资源分配会越来越少。**
## 不可能的指数增长 ## 不可能的指数增长
@@ -301,7 +301,7 @@
可以发现,一开始,不论大家如何努力生产,缺口都保持在 9 以上,甚至还有扩大的趋势,但随着时间推移,很快在第 9 期就迎来了经济衰退,经济系统不再需要这么多农机,在现行的经济评价指标下可以认为是经济陷入了衰退。 可以发现,一开始,不论大家如何努力生产,缺口都保持在 9 以上,甚至还有扩大的趋势,但随着时间推移,很快在第 9 期就迎来了经济衰退,经济系统不再需要这么多农机,在现行的经济评价指标下可以认为是经济陷入了衰退。
<strong>仅从上表就不难看出,追求指数增长是不可能的,经济体通常会在极短的时间以出乎所有人预料的速度内陷入衰退。</strong> **仅从上表就不难看出,追求指数增长是不可能的,经济体通常会在极短的时间以出乎所有人预料的速度内陷入衰退。**
除此之外,我们可以从实际增长方式的角度论证指数增长是不可能的。 除此之外,我们可以从实际增长方式的角度论证指数增长是不可能的。