Merge branch 'master' into master
@@ -12,13 +12,13 @@
|
||||
|
||||
我分为两大块:先想清楚你干了什么,在训练好你表达的规范性
|
||||
|
||||
<font color=green>大白话 -》提取后的逻辑链条</font> -》<font color=red>科研写作 -》英文翻译</font>
|
||||
<font color=green>大白话 -> 提取后的逻辑链条</font> -> <font color=red>科研写作 -> 英文翻译</font>
|
||||
|
||||
<strong>干了什么:</strong>
|
||||
**干了什么:**
|
||||
|
||||
1. 如果没有想清楚要做的是什么,要写什么,可以先用大白话,在草稿上写,有利于理清思路,抽丝剥茧
|
||||
|
||||
失败案例:一上来直接英文【】‘’写作,一会 we want ,一会 80 个词语的长难句,思路英语都不清晰
|
||||
失败案例:一上来直接英文[ ] ' '写作,一会 we want,一会 80 个词语的长难句,思路英语都不清晰
|
||||
|
||||
2. 先列出 Outline 每一个科研 section 你打算做什么,尝试去回答问题
|
||||
|
||||
@@ -33,9 +33,11 @@
|
||||
|
||||
1: How do we verify that we solved it:
|
||||
|
||||
1a) Experimental results1b)
|
||||
1a) Experimental results
|
||||
|
||||
TheoryExtra space? Future work!Extra points for havingFigure 1
|
||||
1b) Theory Extra space? Future work!
|
||||
|
||||
Extra points for having Figure 1
|
||||
|
||||
on the first page
|
||||
|
||||
@@ -43,7 +45,7 @@
|
||||
|
||||
之所以要用大白话是因为基础的不足,如果有一定功底的人,可能先天写出来文字自带规范性,所以仅供大家参考)
|
||||
|
||||
<strong>表达规范性:</strong>
|
||||
**表达规范性:**
|
||||
|
||||
此处的方法论为一句话,则是从模仿到超越的浑然天成。
|
||||
|
||||
@@ -51,7 +53,6 @@
|
||||
|
||||
2. 迭代式写作,尝试多次更改写作的内容,优秀的作品都是改出来的,在把一部分的意思表达清晰知识
|
||||
|
||||
|
||||
上述内容是写作的怎么去写,而下面则是内容层面,什么样的文章算是一篇好的文章
|
||||
|
||||
::: warning 📌
|
||||
@@ -59,6 +60,6 @@ C 会文章与 A 会文章的区别认知:
|
||||
|
||||
(1).C 是对于相关工作一个是罗列,A 是整理相关工作的脉络和方法类别,以及方法缺陷。
|
||||
|
||||
(2).对于设计的方法,C会只是说明我们比另外几个模型好,并不能从原理层面深入分析为什么比别人好,而A会则是能够说明每一部设计对模型的增量效果,以及为什么要做这一步。
|
||||
(2).对于设计的方法,C 会只是说明我们比另外几个模型好,并不能从原理层面深入分析为什么比别人好,而 A 会则是能够说明每一部设计对模型的增量效果,以及为什么要做这一步。
|
||||
|
||||
:::
|
||||
:::
|
||||
|
||||
@@ -2,20 +2,20 @@
|
||||
|
||||
author:廖总
|
||||
|
||||
<em>Last revised 2023/04/18</em>
|
||||
*Last revised 2023/04/18*
|
||||
|
||||
先声夺人:AI 时代最大的陷阱,就是盲目考察 AI 能为我们做什么,而不去考虑我们能为 AI 提供什么
|
||||
|
||||
### <em>免责声明</em>
|
||||
## *免责声明*
|
||||
|
||||
本文纯文本量达 16k(我也不知道字数统计的 28k 是怎么来的),在这 游离散乱的主线 和 支离破碎的文字 中挣扎,可能浪费您生命中宝贵的十数分钟。
|
||||
|
||||
但如果您坚持尝试阅读,可能看到如下内容(假设没在其中绕晕的话 ):
|
||||
但如果您坚持尝试阅读,可能看到如下内容(假设没在其中绕晕的话):
|
||||
|
||||
- 对大语言模型本质 以及 AI 时代人们生产创作本位 的讨论
|
||||
- 对大语言模型 上下文学习(In-Context Learning,ICL)和 思维链(Chain of Thought,COT)能力的几种通识性认知
|
||||
- 围绕 Prompt Decomposition 对使用大语言模型构建复杂应用的基础讨论
|
||||
- 对当前热门大模型 Agent 化框架(如 Generative Agents (即斯坦福 25 人小镇)、AutoGPT)其本质的讨论
|
||||
- 对当前热门大模型 Agent 化框架(如 Generative Agents(即斯坦福 25 人小镇)、AutoGPT)其本质的讨论
|
||||
- 对使用大语言模型构建智能系统(基于全局工作空间意识理论)的初步讨论
|
||||
- 对使用大语言模型构建符合当今生产需求的智能系统的方法论讨论
|
||||
|
||||
@@ -31,7 +31,7 @@ author:廖总
|
||||
- LLMs 能力考察:讨论了大语言模型涌现的一系列基本能力,并讨论基于这些基本能力和工程化,大模型能做到哪一步
|
||||
- Decomp 方法论:将大语言模型微分化使用的方法论,以此展开对大语言模型的新认知
|
||||
- AI 作为智能系统:结合 Generative Agents、AutoGPT 两项工作讨论大语言模型本身的局限性,围绕人类认知模型的启发,讨论通过构建复杂系统使得 LLMs Agent 化的可能性
|
||||
- 予智能以信息:讨论基于 LLMs 构建能够充分帮助我们提升生产力的 AI 剩余的一切痛点。借以回到主题 —— 在 AI 时代,我们要打造什么样的生产和信息管理新范式 (有一说,还是空口无凭)
|
||||
- 予智能以信息:讨论基于 LLMs 构建能够充分帮助我们提升生产力的 AI 剩余的一切痛点。借以回到主题 —— 在 AI 时代,我们要打造什么样的生产和信息管理新范式(有一说,还是空口无凭)
|
||||
|
||||
总体而言,本文包括对 LLM 领域近一个月的最新几项工作(TaskMatrix、HuggingGPT、Generative Agents、AutoGPT)的讨论,并基于此考察一个真正可用的 AI 会以什么样的形态出现在我们面前。
|
||||
|
||||
@@ -43,7 +43,7 @@ author:廖总
|
||||
|
||||
仅作展望。
|
||||
|
||||
# 引言
|
||||
## 引言
|
||||
|
||||
在开启正式讨论之前,我们希望从两个角度分别对 AI 进行讨论,从而夹逼出我们 从 AI 到 智能系统 的主题
|
||||
|
||||
@@ -56,7 +56,7 @@ author:廖总
|
||||
|
||||
以前只知前边两句,现在才知精髓全在后者
|
||||
|
||||
## 形而下者器:LLMs + DB 的使用样例
|
||||
### 形而下者器:LLMs + DB 的使用样例
|
||||
|
||||
(为了不让话题一开场就显得那么无聊,我们先来谈点有意思的例子)
|
||||
|
||||
@@ -77,7 +77,7 @@ author:廖总
|
||||
|
||||
(后面会给出更多关联的讨论,这里就先不赘叙了)
|
||||
|
||||
## 形而上者道:对 LLM 既有智能能力及其局限性的讨论
|
||||
### 形而上者道:对 LLM 既有智能能力及其局限性的讨论
|
||||
|
||||
这一节中,想讨论一下人工智能与人类智能的碰撞()
|
||||
|
||||
@@ -99,7 +99,7 @@ ChatGPT Plugins 在两篇论文两个角度的基础上,对 LLMs 的能力的
|
||||
- 为 AI 提供接口,为 AI 拓展能力
|
||||
- 建模自身问题,促进有效生成
|
||||
|
||||
### 从人工智能到人类智能
|
||||
#### 从人工智能到人类智能
|
||||
|
||||
在上面的论断中,我们看似已经能将绝大多数智能能力出让予 AI 了,但我还想从另一角度对 AI 与人类的能力进行展开讨论:
|
||||
|
||||
@@ -109,7 +109,7 @@ ChatGPT Plugins 在两篇论文两个角度的基础上,对 LLMs 的能力的
|
||||
- “人工”智能:辅佐 AI 实现的智能
|
||||
- 人类智能:于人类独一无二的东西
|
||||
|
||||
### AI 智能的形态
|
||||
#### AI 智能的形态
|
||||
|
||||
大语言模型的原始目的是制造一个“压缩器”,设计者们希望他能有效地学习世界上所有信息,并对其进行通用的压缩。
|
||||
|
||||
@@ -120,11 +120,11 @@ ChatGPT Plugins 在两篇论文两个角度的基础上,对 LLMs 的能力的
|
||||
> “人总是要死的,苏格拉底也是人,所以苏格拉底是要死的”<br/>这是一个经典苏格拉底式的三段论,其中蕴含着人类对于演绎推理能力的智慧。<br/>假设上面的样本是 LLM 既有学习的,而这时来了一个新的样本:<br/>“人不吃饭会被饿死,我是人,所以我也是要恰饭的嘛”<br/>那么对于一个理想的智能压缩器而言,其可能发现新句与旧句之间的关联,并有效学习到了句子的表征形式及其背后的逻辑
|
||||
|
||||
$$
|
||||
S1=<(人,苏格拉底,死),三段式推理>
|
||||
S1=<(人,苏格拉底,死),三段式推理>
|
||||
$$
|
||||
|
||||
$$
|
||||
S2=<(人,我,恰饭),三段式推理>
|
||||
S2=<(人,我,恰饭),三段式推理>
|
||||
$$
|
||||
|
||||
> 而随后,压缩器会倾向于储存三段式推理这一智能结构,并在一定程度上丢弃后来的(人,我,恰饭)这一实体关系组,仅简单建模其间联系,并在生成时按需调整预测权重。
|
||||
@@ -144,7 +144,7 @@ LLM 的实质上还是通过“语言结构”对“外显人类智能”进行
|
||||
|
||||
而也正是这些固有缺陷,为人类的自我定位和进一步利用 AI 找到了立足点。
|
||||
|
||||
### 赋能 AI 实现智能
|
||||
#### 赋能 AI 实现智能
|
||||
|
||||
作为上面一点的衍生,我们可以从大体两个角度去辅助 AI 智能的实现:
|
||||
|
||||
@@ -200,13 +200,13 @@ LLM 的实质上还是通过“语言结构”对“外显人类智能”进行
|
||||
|
||||
简而言之,我希望能追随着 AI 的发展,讨论是否能构建这样一个通用的 AI 框架,并将其引入工作生产的方方面面。希望能讨论及如何对生产信息进行有效的管理,也包括如何让我们更好调用 AI,如何让 AI 满足我们的生产需要。
|
||||
|
||||
# LLMs:生成原理及能力考察
|
||||
## LLMs:生成原理及能力考察
|
||||
|
||||
相信无论是否专业,各位对 LLMs 的生成原理都有着一定的认知
|
||||
|
||||
简单来说,这就是一个单字接龙游戏,通过自回归地预测“下一个字”。在这个过程的训练中,LLMs 学习到了知识结构,乃至一系列更复杂的底层关联,成为了一种人类无法理解的智能体。
|
||||
|
||||
## In-Context Learning / Chain of Thought
|
||||
### In-Context Learning / Chain of Thought
|
||||
|
||||
经过人们对模型背后能力的不懈考察,发现了一系列亮点,其中最瞩目的还是两点:
|
||||
|
||||
@@ -219,13 +219,13 @@ ICL(In-Context Learning,上下文学习)和 COT(Chain of Thought,思
|
||||
|
||||
虽然学界对此没有太大的共识,但其原理无非在于给予 LLMs 更翔实的上下文,让输出与输入有着更紧密的关联与惯性。(从某种意义上来说,也可以将其认为是一种图灵机式的编程)
|
||||
|
||||
> ICL:<br/>
|
||||
> ICL:<br/>
|
||||
|
||||
ICL 为输出增加惯性
|
||||
|
||||
> 可以简单认为,通过 ICL Prompt,能强化人类输入到机器输出的连贯性,借以提升输出的确定性。<br/>在经过“回答”的 finetune 之前,大模型的原始能力就是基于给定文本进行接龙,而 ICL 的引入则在“回答”这一前提条件下,降低了机器开始接龙这一步骤中的语义跨度,从而使得输出更加可控。<br/>
|
||||
|
||||
COT:<br/>
|
||||
COT:<br/>
|
||||
|
||||
COT 为输出增加关联
|
||||
|
||||
@@ -233,14 +233,13 @@ COT 为输出增加关联
|
||||
|
||||
进一步的,ICL 的发现,让 LLMs 能避免过多的传统 Finetune,轻易将能力运用在当前的情景中;COT 的发现,使得通过 LLMs 解决复杂问题成为可能。此二者的组合,为 LLMs 的通用能力打下了基础。
|
||||
|
||||
|
||||
## TaskMatrix.AI
|
||||
### TaskMatrix.AI
|
||||
|
||||
微软对 [TaskMatrix.AI](https://arxiv.org/abs/2303.16434) 这一项目的研究,很大程度上展示了 LLMs 基于 ICL 和 COT 所能展现的能力
|
||||
|
||||
(需要注意的是,TaskMatrix.AI 更大程度上是一个愿景向的调研案例,尚未正式落地生态)
|
||||
|
||||

|
||||

|
||||
|
||||
TaskMatrix 的生态愿景
|
||||
|
||||
@@ -261,7 +260,7 @@ TaskMatrix 的生态愿景
|
||||
|
||||
(当然,硬要说的话,对 ICL 和 COT 两种能力都有一个狭义与广义之争,但这不重要,因为我喜欢广义)
|
||||
|
||||
### ICL for TaskMatrix
|
||||
#### ICL for TaskMatrix
|
||||
|
||||
> 狭义的 ICL:从输入的既有样例中学习分布和规范<br/>广义的 ICL:有效的将输入内容有效运用到输出中
|
||||
|
||||
@@ -275,7 +274,7 @@ TaskMatrix 的生态愿景
|
||||
- Usage Example:API 的调用方法样例
|
||||
- Composition Instruction:API 的使用贴士,如应该与其它什么 API 组合使用,是否需要手动释放等
|
||||
|
||||
> 样例:打开文件 API<br/>
|
||||
> 样例:打开文件 API<br/>
|
||||
|
||||
基于此类文档内容和 ICL 的能力,LLMs 能从输入中习得调用 API 的方法,依此快速拓展了其横向能力
|
||||
|
||||
@@ -287,21 +286,21 @@ COT for TaskMatrix
|
||||
|
||||
在 TaskMatirx 中,通过该模式,让 MCFM 将任务转化为待办大纲,并最终围绕大纲检索并组合 API,完成整体工作
|
||||
|
||||
> 样例:写论文<br/>构建完成工作大纲<br/>
|
||||
> 样例:写论文<br/>构建完成工作大纲<br/>
|
||||
|
||||
TaskMatrix 自动围绕目标拆解任务
|
||||
|
||||
> 自动调用插件和组件<br/>
|
||||
> 自动调用插件和组件<br/>
|
||||
|
||||
TaskMatrix 自动为任务创建 API 调用链
|
||||
|
||||
## 初步考察
|
||||
### 初步考察
|
||||
|
||||
基于上述的简单介绍,我们已经初步认识了 AI 在实际情景中的高度可用性
|
||||
|
||||
而接下来,我们继续从工程的角度揭示这种可用性的根源 —— 其源自一项通用的 Prompt 技术
|
||||
|
||||
# Prompt Decomposition:方法论
|
||||
## Prompt Decomposition:方法论
|
||||
|
||||
我们可以认为,TaskMatirx 的能力极大程度上依托于 Prompt Decomposition 的方法
|
||||
|
||||
@@ -309,11 +308,11 @@ TaskMatrix 自动为任务创建 API 调用链
|
||||
|
||||
[[2210.02406] Decomposed Prompting: A Modular Approach for Solving Complex Tasks (](https://arxiv.org/abs/2210.02406)[arxiv.org](https://arxiv.org/abs/2210.02406)[)](https://arxiv.org/abs/2210.02406)
|
||||
|
||||
## 原始 Decomp
|
||||
### 原始 Decomp
|
||||
|
||||
Decomp 的核心思想为将复杂问题通过 Prompt 技巧,将一个复杂的问题由 LLMs 自主划分为多个子任务。随后,我们通过 LLMs 完成多个任务,并将过程信息最终组合并输出理想的效果
|
||||
|
||||

|
||||

|
||||
|
||||
几种 Prompt 方法图示
|
||||
|
||||
@@ -321,13 +320,13 @@ Decomp 的核心思想为将复杂问题通过 Prompt 技巧,将一个复杂
|
||||
|
||||
而对于 Decomp 过程,则又是由一个原始的 Decomp Prompt 驱动
|
||||
|
||||

|
||||

|
||||
|
||||
Decomp 方法执行样例
|
||||
|
||||
在实际运行中,Decomp 过程由一个任务分解器,和一组程序解析器组成
|
||||
|
||||
其中分解器作为语言中枢,需要被授予如何分解复杂任务 —— 其将根据一个问题 Q 构建一个完整的提示程序 P ,这个程序包含一系列简单的子问题 Q_i,以及用于处理该子问题的专用函数 f_i(可以通过特定小型 LLM 或专用程序,也可以以更小的提示程序 P_i 形式呈现)。
|
||||
其中分解器作为语言中枢,需要被授予如何分解复杂任务 —— 其将根据一个问题 Q 构建一个完整的提示程序 P,这个程序包含一系列简单的子问题 Q_i,以及用于处理该子问题的专用函数 f_i(可以通过特定小型 LLM 或专用程序,也可以以更小的提示程序 P_i 形式呈现)。
|
||||
|
||||
模型将通过递归运行完整的提示程序,来获得理想的答案。
|
||||
|
||||
@@ -335,19 +334,19 @@ Decomp 方法执行样例
|
||||
|
||||
我们也可以认为,在每个子任务中,我们通过 Prompt 将 LLMs 的能力进行了劣化,从而让其成为一个专职的功能零件。而这种对单个 LLMs 能力迷信的削减,正延伸出了后续的发展趋势。
|
||||
|
||||
## Decomp 衍生
|
||||
### Decomp 衍生
|
||||
|
||||
Decomp 的原始功能实际上并不值得太过关注,但我们急需考虑,该方法还能用于处理些什么问题。
|
||||
|
||||
### 递归调用
|
||||
#### 递归调用
|
||||
|
||||
我们可以构建规则,让 Decomp 方法中的分解器递归调用自身,从而使得一个可能困难的问题无限细分,并最终得以解决
|
||||
|
||||
### 外部调用
|
||||
#### 外部调用
|
||||
|
||||
通过问题的分解和通过“专用函数”的执行,我们可以轻易让 LLMs 实现自身无法做到的调用 API 工作,例如主动从外部检索获取回答问题所需要的知识。
|
||||
|
||||

|
||||

|
||||
|
||||
Decomp 方法调用外部接口样例
|
||||
|
||||
@@ -355,11 +354,11 @@ Decomp 方法调用外部接口样例
|
||||
|
||||
基于此,我们还希望进一步研究基于这些机制能整出什么花活儿,并能讨论如何进一步利用 LLMs 的能力
|
||||
|
||||
## 回顾:HuggingGPT 对 Decomp 方法的使用
|
||||
### 回顾:HuggingGPT 对 Decomp 方法的使用
|
||||
|
||||
[HuggingGPT](https://arxiv.org/abs/2303.17580) 一文也许并未直接参考 Decomp 方法,而是用一些更规范的手法完成该任务,但其充分流水线化的 Prompt 工程无疑是 Decomp 方法在落地实践上的最佳注脚
|
||||
|
||||

|
||||

|
||||
|
||||
HuggingGPT
|
||||
|
||||
@@ -373,7 +372,7 @@ HuggingGPT
|
||||
|
||||
接下来,我们会讨论一个很新的,在为 Agent 模拟任务构建框架上,把 Decomp 和 Prompting 技术用到登峰造极的样例。
|
||||
|
||||
# Generative Agents:社群模拟实验
|
||||
## Generative Agents:社群模拟实验
|
||||
|
||||
[[2304.03442] Generative Agents: Interactive Simulacra of Human Behavior (](https://arxiv.org/abs/2304.03442)[arxiv.org](https://arxiv.org/abs/2304.03442)[)](https://arxiv.org/abs/2304.03442)
|
||||
|
||||
@@ -383,7 +382,7 @@ Generative Agents 一文通过的自然语言框架 AI 构建出了一个模拟
|
||||
|
||||
因为,其本质是一个信息管理框架的实验。
|
||||
|
||||
## 简要介绍
|
||||
### 简要介绍
|
||||
|
||||
简单介绍该项目构建的框架:
|
||||
|
||||
@@ -399,7 +398,7 @@ Generative Agents 构建了一套框架,让 NPC 可以感知被模块化的世
|
||||
|
||||
根据 NPC 的决策,NPC 能反向更新自身所使用的记忆数据库,并提炼总结出高层记忆供后续使用。
|
||||
|
||||
## 世界沙盒的构建
|
||||
### 世界沙盒的构建
|
||||
|
||||
相比角色信息的构建是重头戏,世界沙盒的构建使用的方法要相对朴素一些
|
||||
|
||||
@@ -407,7 +406,7 @@ Generative Agents 构建了一套框架,让 NPC 可以感知被模块化的世
|
||||
|
||||
- 一方面,其包含场景中既有对象,包括建筑和摆件等的基础层级信息
|
||||
|
||||

|
||||

|
||||
|
||||
Generative Agents 的场景信息管理
|
||||
|
||||
@@ -419,7 +418,7 @@ Generative Agents 的场景信息管理
|
||||
|
||||
同时,空间信息会被自动组成自然语言 Prompt,用于帮助 Agent 更好地理解外部信息。甚至当 Agent 希望获取空间信息时,其能主动递归调用世界信息,从而让 NPC 能准确找到其希望抵达的叶子节点。
|
||||
|
||||
## Agent 构建
|
||||
### Agent 构建
|
||||
|
||||
模型中的 Agent 由 数据库 + LLMs 构建
|
||||
|
||||
@@ -431,13 +430,13 @@ Generative Agents 的场景信息管理
|
||||
|
||||
而对于过去经验的输入,则是文章的一大亮点
|
||||
|
||||
## 记忆模式
|
||||
### 记忆模式
|
||||
|
||||
对于 Agent 的记忆,依托于一个储存信息流的数据库
|
||||
|
||||
数据库中核心储存三类关键记忆信息 memory, planning and reflection
|
||||
|
||||
### Memory
|
||||
#### Memory
|
||||
|
||||
对于 Agent 每个时间步观测到的事件,会被顺序标记时间戳储存进记忆数据库中
|
||||
|
||||
@@ -449,11 +448,11 @@ Generative Agents 的场景信息管理
|
||||
|
||||
对于对记忆数据库进行索引的情况,会实时评估上述三个指标,并组合权重,返回对记忆索引内容的排序
|
||||
|
||||
### Reflection
|
||||
#### Reflection
|
||||
|
||||
反思机制用于定期整理当前的 memory 数据库,让 npc 构建对世界和自身的高层认知
|
||||
|
||||
反思机制依靠一个自动的过程,反思-提问-解答
|
||||
反思机制依靠一个自动的过程,反思 - 提问 - 解答
|
||||
|
||||
在这个过程中,Agent 需要复盘自身所接受的记忆,并基于记忆对自己进行追问:
|
||||
|
||||
@@ -465,7 +464,7 @@ Generative Agents 的场景信息管理
|
||||
|
||||
进一步的,我们将这些洞察以相同的形式重新储存至记忆库中,由此模拟人类的记忆认知过程
|
||||
|
||||
### Planning
|
||||
#### Planning
|
||||
|
||||
Planning 的核心在于鼓励 Agent 为未来做出一定的规划,使得后续行动变得可信
|
||||
|
||||
@@ -475,13 +474,13 @@ Planning 的核心在于鼓励 Agent 为未来做出一定的规划,使得后
|
||||
|
||||
在此基础上,Agent 也需要对环境做出反应而调整自己的计划表(例如自身判断外界交互的优先级比当前计划更高。
|
||||
|
||||
## 交互构建
|
||||
### 交互构建
|
||||
|
||||
基于上述记忆框架,进一步实时让 Agent 自行感知并选择与其它 Agent 构建交互
|
||||
|
||||
并最终使得复杂的社群在交互中涌现
|
||||
|
||||
## 启发
|
||||
### 启发
|
||||
|
||||
Generative Agent 框架主要带来了一些启发,不止于 AI-NPC 的构建,其操作的诸多细节都是能进一步为我们在实际的工程中所延拓的。
|
||||
|
||||
@@ -497,7 +496,7 @@ Generative Agent 框架主要带来了一些启发,不止于 AI-NPC 的构建
|
||||
- AI x 信息自动化系统的构建:基于 AI + 软件系统而非基于人工对数据进行收集和管理
|
||||
- etc...
|
||||
|
||||
# AutoGPT:自动化的智能软件系统
|
||||
## AutoGPT:自动化的智能软件系统
|
||||
|
||||
[Torantulino/Auto-GPT: An experimental open-source attempt to make GPT-4 fully autonomous. (](https://github.com/Torantulino/Auto-GPT)[github.com](https://github.com/Torantulino/Auto-GPT)[)](https://github.com/Torantulino/Auto-GPT)[github.com/Torantulino/Auto-GPT](https://github.com/Torantulino/Auto-GPT)
|
||||
|
||||
@@ -530,7 +529,7 @@ AutoGPT 主要特性如下:
|
||||
|
||||
(如下是 AutoGPT 的基础 Prompt)
|
||||
|
||||
```
|
||||
```txt
|
||||
[
|
||||
{
|
||||
'content': 'You are Eliza, an AI designed to write code according to my requirements.\n'
|
||||
@@ -613,11 +612,11 @@ AutoGPT 主要特性如下:
|
||||
]
|
||||
```
|
||||
|
||||
# 回归正题:AI 作为智能系统
|
||||
## 回归正题:AI 作为智能系统
|
||||
|
||||
作为正题的回归,我们需要重新考虑什么是一个 AI,一个能帮助我们的 AI 应当处于什么样的现实形态?
|
||||
|
||||
<em>我们需要的 </em><em>AI</em><em> 仅仅是大语言模型吗?如果是,它能帮我们做什么呢?如果不是,那 AI 的实质是什么呢?</em>
|
||||
*我们需要的 **AI** 仅仅是大语言模型吗?如果是,它能帮我们做什么呢?如果不是,那 AI 的实质是什么呢?*
|
||||
|
||||
我首先武断地认为,我们需要的 AI,并不是一个语言模型实体,而是一个复杂智能系统
|
||||
|
||||
@@ -625,9 +624,9 @@ AutoGPT 主要特性如下:
|
||||
|
||||
接下来,我们会围绕此进行展开
|
||||
|
||||
## 意识理论之于 AI:全局工作空间理论
|
||||
### 意识理论之于 AI:全局工作空间理论
|
||||
|
||||
全局工作空间理论(英语:Global workspace theory,GWT)是美国心理学家[伯纳德·巴尔斯](https://zh.wikipedia.org/w/index.php?title=%E4%BC%AF%E7%BA%B3%E5%BE%B7%C2%B7%E5%B7%B4%E5%B0%94%E6%96%AF&action=edit&redlink=1)提出的[意识](https://zh.wikipedia.org/wiki/%E6%84%8F%E8%AF%86)模型。该理论假设意识与一个全局的“广播系统”相关联,这个系统会在整个大脑中广播资讯。大脑中专属的智能处理器会按照惯常的方式自动处理资讯,这个时候不会形成[意识](https://zh.wikipedia.org/wiki/%E6%84%8F%E8%AF%86)。当人面对新的或者是与习惯性刺激不同的事物时,各种专属智能处理器会透过合作或竞争的方式,在全局工作空间中对新事物进行分析以获得最佳结果,而意识正是在这个过程中得以产生。
|
||||
全局工作空间理论(英语:Global workspace theory,GWT)是美国心理学家伯纳德·巴尔斯提出的[意识](https://zh.wikipedia.org/wiki/%E6%84%8F%E8%AF%86)模型。该理论假设意识与一个全局的“广播系统”相关联,这个系统会在整个大脑中广播资讯。大脑中专属的智能处理器会按照惯常的方式自动处理资讯,这个时候不会形成[意识](https://zh.wikipedia.org/wiki/%E6%84%8F%E8%AF%86)。当人面对新的或者是与习惯性刺激不同的事物时,各种专属智能处理器会透过合作或竞争的方式,在全局工作空间中对新事物进行分析以获得最佳结果,而意识正是在这个过程中得以产生。
|
||||
|
||||
这通常被认为是 神经科学家接受度最高的哲学理论
|
||||
|
||||
@@ -635,7 +634,7 @@ AutoGPT 主要特性如下:
|
||||
|
||||
其提醒我们,就连我们的意识主体性,也只是陈述自我的一个表述器而已。我们是否应当反思对语言能力的过度迷信,从而相信我们能通过训练模型构建 All in One 的智能实体?
|
||||
|
||||

|
||||

|
||||
|
||||
全局工作空间理论
|
||||
|
||||
@@ -649,7 +648,7 @@ AutoGPT 主要特性如下:
|
||||
- 知觉系统(现在)
|
||||
- 运动系统(未来)
|
||||
|
||||
### 例子:意识系统 For Generative Agent
|
||||
#### 例子:意识系统 For Generative Agent
|
||||
|
||||
单独解释的话,或许会比较麻烦,毕竟我对认知科学并不专业
|
||||
|
||||
@@ -671,9 +670,9 @@ AutoGPT 主要特性如下:
|
||||
|
||||
当然,我个人对该问题的认知与 GPT4 并非完全相同,包括注意系统与运动系统的部分。但其实我并不一定需要将所有东西全都呈现出来,因为在框架上它已然如此。
|
||||
|
||||
记忆、评估、反思这几块的设计通过 Prompt 把 LLMs 劣化成专用的智能处理器单元, 并系统性实现信息的整合与输出。从整体的观点上来看,Generative Agents 中的 Agent,其主体性并不在于 LLM,而是在于这个完整的系统。(相应的,LLMs 只是这个系统的运算工具和陈述工具)
|
||||
记忆、评估、反思这几块的设计通过 Prompt 把 LLMs 劣化成专用的智能处理器单元,并系统性实现信息的整合与输出。从整体的观点上来看,Generative Agents 中的 Agent,其主体性并不在于 LLM,而是在于这个完整的系统。(相应的,LLMs 只是这个系统的运算工具和陈述工具)
|
||||
|
||||
### 例子:AutoGPT 的考察
|
||||
#### 例子:AutoGPT 的考察
|
||||
|
||||
我们再从相同的角度考察 AutoGPT 这一项目:
|
||||
|
||||
@@ -690,7 +689,7 @@ AutoGPT 主要特性如下:
|
||||
|
||||
这也对应 AutoGPT 虽然看似有着极强的能力,但实际智能效果又不足为外人道也
|
||||
|
||||
## 构建一个什么样的智能系统
|
||||
### 构建一个什么样的智能系统
|
||||
|
||||
再次回归正题,Generative Agents 和 AutoGPT 这两个知名项目共同将 AI 研究从大模型能力研究导向了智能系统能力研究。而我们也不能驻足不前,我们应当更积极地考虑我们对于一个 AI 智能体有着什么样的需求,也对应我们需要构建、要怎么构建一个基于 LLMs 语言能力的可信可用的智能系统。
|
||||
|
||||
@@ -708,7 +707,7 @@ AutoGPT 主要特性如下:
|
||||
|
||||
这些问题都在指导、质问我们究竟需要一个怎样的智能系统。
|
||||
|
||||
# 予智能以信息:难题与展望
|
||||
## 予智能以信息:难题与展望
|
||||
|
||||
回到最开始的话题,我们构建一个可用智能系统的基底,依旧是信息系统
|
||||
|
||||
@@ -724,7 +723,7 @@ AutoGPT 主要特性如下:
|
||||
|
||||
而接下来,我们希望对其进行逐一评估,讨论他们各自将作用的形式,讨论他们需要做到哪一步,又能做到哪一步。
|
||||
|
||||
## 知觉系统:构建 AI 可读的结构化环境
|
||||
### 知觉系统:构建 AI 可读的结构化环境
|
||||
|
||||
知觉系统负责让智能体实现信息的感知,其中也包括对复杂输入信息的解析
|
||||
|
||||
@@ -752,7 +751,7 @@ AutoGPT 所使用的 Commands 接口中,就有很大一部分接口用于实
|
||||
- args: "file": `"<file>"`
|
||||
- 读取文件并解析文本数据
|
||||
|
||||
这些访问接口由程序集暴露给 GPT ,将知觉系统中实际使用的微观处理器隐藏在了系统框架之下
|
||||
这些访问接口由程序集暴露给 GPT,将知觉系统中实际使用的微观处理器隐藏在了系统框架之下
|
||||
|
||||
AutoGPT 所实际感知的信息为纯文本的格式,得益于以开放性 Web 为基础的网络世界环境,AutoGPT 能较方便地通过搜索(依赖于搜索引擎 API)和解析 html 文件(依赖于软件辅助,GPT 难以自行裁剪 html 中过于冗杂的格式信息),从而有效阅读绝大多数互联网信息。
|
||||
|
||||
@@ -804,7 +803,7 @@ Generative Agents 的知觉设计:关联性难题
|
||||
|
||||
仅就这方面而言,作为一个方向性的倡议,对知觉系统的开发可能分为以下步骤
|
||||
|
||||
### <em>数据处理/管理</em>
|
||||
#### *数据处理/管理*
|
||||
|
||||
- 对 办公文件/数据 构建通用读取接口
|
||||
- 以同类信息为单位,设计通用的字段(由人设计和管理,AI 能力尚不至此)
|
||||
@@ -828,7 +827,7 @@ Generative Agents 的知觉设计:关联性难题
|
||||
- 如储存进 mongoDB
|
||||
- (设计孪生数据的自动更新机制)
|
||||
|
||||
### <em>知觉系统驱动</em>
|
||||
#### *知觉系统驱动*
|
||||
|
||||
- 基于上述索引数据库,以视图为单位进行访问,并设计 视图 2 Prompt 的转化格式
|
||||
|
||||
@@ -847,7 +846,7 @@ Generative Agents 的知觉设计:关联性难题
|
||||
|
||||
- 对于 Agent 开启的指定任务线程(区分于主线程的感知模块),其起始 Prompt 可能呈这样的形式
|
||||
|
||||
> <br/>如上是你的目标,为了实现这个目标,你可能需要获取一系列的信息,为了帮助你获得信息,我会为你提供一系列的索引访问接口,请你通过如下格式输出语句让我为你返回信息。<br/>注:如果你请求错误,请你阅读返回的报错信息以自我纠正<br/>例:<br/>< 通过接口名称检索("接口名称")><br/>< 通过接口功能检索("访问网页")><br/>< 通过父级名称检索("父级名称")>
|
||||
> <br/>如上是你的目标,为了实现这个目标,你可能需要获取一系列的信息,为了帮助你获得信息,我会为你提供一系列的索引访问接口,请你通过如下格式输出语句让我为你返回信息。<br/>注:如果你请求错误,请你阅读返回的报错信息以自我纠正<br/>例:<br/>< 通过接口名称检索 ("接口名称")><br/>< 通过接口功能检索 ("访问网页")><br/>< 通过父级名称检索 ("父级名称")>
|
||||
|
||||
- 为 GPT 设计自动化指令解析与执行模块
|
||||
|
||||
@@ -861,7 +860,7 @@ Generative Agents 的知觉设计:关联性难题
|
||||
|
||||
> TBD:号被 OpenAI 噶了,我也很绝望啊
|
||||
|
||||
## 工作记忆:组织 AI 记忆系统
|
||||
### 工作记忆:组织 AI 记忆系统
|
||||
|
||||
记忆系统的构成其实相较知觉系统等更为抽象,它用于管理 AI 运行时作为背景的长期记忆,以及定义决定了 AI 当前任务及目标的短期记忆。
|
||||
|
||||
@@ -869,9 +868,9 @@ Generative Agents 的知觉设计:关联性难题
|
||||
|
||||
但我们依旧能从前人的工作中获得一定的参考。
|
||||
|
||||
### AutoGPT 的记忆设计:粗放但有效
|
||||
#### AutoGPT 的记忆设计:粗放但有效
|
||||
|
||||
在 长时记忆(过去)、评估系统(价值)、注意系统(关注) 这三个要素中,AutoGPT 做得比较好的无疑只有第一个。
|
||||
在 长时记忆(过去)、评估系统(价值)、注意系统(关注)这三个要素中,AutoGPT 做得比较好的无疑只有第一个。
|
||||
|
||||
AutoGPT 的核心记忆设计依赖于预包装的 Prompt 本体,这一包装包含如下部分:
|
||||
|
||||
@@ -899,15 +898,15 @@ AutoGPT 的核心记忆设计依赖于预包装的 Prompt 本体,这一包装
|
||||
|
||||
但从另一角度,其“自主将收集到的信息写入记忆”这一功能作为一个 以完成任务为目标 的 Agent 而言无疑是非常合适的架构设计。
|
||||
|
||||
### Generative Agents 的记忆设计:精心构建的金字塔
|
||||
#### Generative Agents 的记忆设计:精心构建的金字塔
|
||||
|
||||
区别于 AutoGPT 主动写入的记忆,Generative Agents 的记忆源自被动的无限感知和记录,因此显得更加没有目的性。也正因如此,其需要一种更妥善的管理形式。
|
||||
|
||||
Generative Agent 通过自动化评估记忆的价值,并构建遗忘系统、关注系统等用于精准从自己繁杂的记忆中检索对于当前情景有用的信息。
|
||||
|
||||

|
||||

|
||||
|
||||
Generative Agents :基于 Reflection 构建记忆金字塔
|
||||
Generative Agents:基于 Reflection 构建记忆金字塔
|
||||
|
||||
进一步的,其通过反思机制强化了记忆的价值,使得高层洞察从既有记忆的连结中涌现,这一机制通常被用于将 信息转化为知识,并构建出了有效记忆的金字塔。
|
||||
|
||||
@@ -915,7 +914,7 @@ Generative Agents :基于 Reflection 构建记忆金字塔
|
||||
|
||||
相关的更有效的记忆管理无疑很快就会被更新的项目学习。
|
||||
|
||||
### 记忆系统的构建讨论(放飞大脑)
|
||||
#### 记忆系统的构建讨论(放飞大脑)
|
||||
|
||||
但从某种意义上来说,对于一个我们希望其帮助我们工作的智能体而言,像 Generative Agent 这般的巨大数据库也许并未有充分的价值,何况我们所输入的内容原始层级就较高(这一层可能在前面的知觉系统中,就让一定程度上的高层洞见自主产生了),不易于进一步的堆叠。
|
||||
|
||||
@@ -933,7 +932,7 @@ Generative Agents :基于 Reflection 构建记忆金字塔
|
||||
|
||||
(可以遇见的,以 AutoGPT 的热度,半个月内就会有人为其设计相应的 mod)
|
||||
|
||||
## 运动系统:让 AI 可及一切
|
||||
### 运动系统:让 AI 可及一切
|
||||
|
||||
基于知觉系统和记忆系统,已经能构建一个使用语言解决问题的智能体了。但最为关键的改造世界部分则依旧缺席。
|
||||
|
||||
@@ -943,7 +942,7 @@ Generative Agents :基于 Reflection 构建记忆金字塔
|
||||
|
||||
- 我们大胆假设未来游戏中的 Agent 能通过 API 驱动自身在场景中无拘无束(拼装行为树
|
||||
- 再大胆假设他们能使用 API 实时把需求的内容转化为发布给玩家的任务(拼装任务节点
|
||||
- 继续大胆假设, AI 根据我的需求把今天要配的啥比表直接配完,当场下班(笑
|
||||
- 继续大胆假设,AI 根据我的需求把今天要配的啥比表直接配完,当场下班(笑
|
||||
|
||||
(而这一切,都是可能,且近在眼前的)
|
||||
|
||||
@@ -963,7 +962,7 @@ AI 能做的一切都基于我们的赋予,包括语言能力,包括思维
|
||||
- 我们不该将其当作独立的智能体看待,但能在其基础上通过构建系统创建智能 Agent
|
||||
- 为此,我们需要通过信息工程,让 AI 能够真正感知和改造世界,从而改变我们的生产进程
|
||||
|
||||
# 寄予厚望
|
||||
## 寄予厚望
|
||||
|
||||
感谢有人忍受了我阴间的行文和一路跑偏的思路,真能看到这里
|
||||
|
||||
|
||||
262
4.人工智能/4.12LLMAgent之结构化输出.md
Normal file
@@ -0,0 +1,262 @@
|
||||
# LLM Agent 之结构化输出
|
||||
|
||||
author:Marlene
|
||||
|
||||
*Last revised 2023/07/26*
|
||||
|
||||
## 引言
|
||||
|
||||
自去年年底以来,GPT 的迅速发展诞生了一系列大模型。出现了更新、更大、更强的 GPT-4。OpenAI 不断推出 GPT-4,ChatGPT Plugins,代码解释器,Function calling,图片处理等等。7 月的 WAIC 上,笔者也有幸见到了国内一众企业相继展示自家的大模型。在这段时间里,LLM 从最初的 PE 工程走向智能体交互。而笔者从最开始考虑 LLM 能不能多人协作,思考”一个专家完成所有任务好还是很多人分工完成好“,到各种论文层出不穷,到如今火热的 LLM Agent 开发模式。可以说,如果你从大学里随便问某个人都知道 GPT,甚至大部分都用过。
|
||||
|
||||
好了,前言少叙。进入正题。众所周知,Agent 基本= LLM(大型语言模型)+ 记忆 + 规划技能 + 工具使用。
|
||||
|
||||
想要使用工具,让 GPT 掌握如何使用工具,常见的方法是告知 GPT 工具(通常是一个可以调用的函数)的参数,让 GPT 生成这些参数即可。那么如何让 GPT 可靠的生成这些规定的参数呢?换一种说法,如何让 GPT 输出结构化的数据信息呢?
|
||||
|
||||
## 原理及相关框架
|
||||
|
||||
现如今大部分的结构化输出工具的原理都是:告诉 GPT 要输出一个怎么样的结构即可。没错~当然,为什么会出现这么多开发工具都用来解决这个问题,明明是一个简单的原理呢?
|
||||
|
||||
```txt
|
||||
1. 通过 prompt 告知 LLM 我们所需要的返回格式,并进行生成。
|
||||
2. 通过一些规则来检查返回结果,如果不符合格式,生成相关错误信息。
|
||||
3. 将上一次的生成内容和检查的错误信息告知 LLM,进行下一次的修正生成。
|
||||
4. 重复 2-3 步骤,直到生成的内容完全符合我们的要求。
|
||||
```
|
||||
|
||||
首先,关于怎样描述这样一个结构的 prompt 模板,众口难调。有些人认为结构就应该用自然语言描述,这样足够简单,上手难度足够低,方便快速迭代开发。有些人认为结构描述?JSON Schema 不就够了?有些人觉得 YAML 也可以。有些人觉得上面这些对于我的需求还是够不着啊,于是自己造了一个伪代码描述。
|
||||
其次,自动处理修正机制也可以做很多文章。还有许多对性能和开销的优化。
|
||||
下文就是关于一众框架的简单分析。希望会对选择困难症的你有所帮助。
|
||||
|
||||
### **guardrails**
|
||||
|
||||
guardrails 这个项目,就是将上述的步骤做了进一步的抽象与封装,提供更加 high level 的配置与 API 来完成整个过程。
|
||||
优点:
|
||||
|
||||
1. 定义了一套 RAIL spec
|
||||
2. 更聚焦于错误信息
|
||||
|
||||
```markdown
|
||||
<rail version="0.1">
|
||||
|
||||
<output>
|
||||
<object name="patient_info">
|
||||
<string name="gender" description="Patient's gender" />
|
||||
<integer name="age" format="valid-range: 0 100" />
|
||||
<list
|
||||
name="symptoms"
|
||||
description="Symptoms that the patient is currently experiencing. Each symptom should be classified into a separate item in the list.">
|
||||
<object>
|
||||
<string name="symptom" description="Symptom that a patient is experiencing"/>
|
||||
<string
|
||||
name="affected area"
|
||||
description="What part of the body the symptom is affecting"
|
||||
format="valid-choices: {['head', 'neck', 'chest']}"
|
||||
on-fail-valid-choices="reask"
|
||||
/>
|
||||
</object>
|
||||
</list>
|
||||
<list name="current_meds" description="Medications the patient is currently taking and their response">
|
||||
<object>
|
||||
<string name="medication" description="Name of the medication the patient is taking" />
|
||||
<string
|
||||
name="response"
|
||||
description="How the patient is responding to the medication"
|
||||
/>
|
||||
</object>
|
||||
</list>
|
||||
</object>
|
||||
</output>
|
||||
|
||||
<prompt>
|
||||
|
||||
Given the following doctor's notes about a patient, please extract a dictionary that contains the patient's information.
|
||||
|
||||
{{doctors_notes}}
|
||||
|
||||
@complete_json_suffix_v2
|
||||
</prompt>
|
||||
</rail>
|
||||
```
|
||||
|
||||
可以看到,guardrails 定义了一套类似 xml 的语言用于结构化输出,又结合了自然语言的 prompt。虽然比起常见的模板语言要更加“繁琐”,但可以包含的内容也可以更加完善。比如可以提供字段的描述信息,检查规范,一定程度上也能帮助 LLM 更好地理解需求,生成预期的结果。
|
||||
|
||||
```markdown
|
||||
I was given the following JSON response, which had problems due to incorrect values.
|
||||
|
||||
{
|
||||
"patient_info": {
|
||||
"symptoms": [
|
||||
{
|
||||
"affected area": {
|
||||
"incorrect_value": "face & hair",
|
||||
"error_message": "Value face & hair is not in choices ['head', 'neck', 'chest']."
|
||||
}
|
||||
},
|
||||
{
|
||||
"affected area": {
|
||||
"incorrect_value": "beard, eyebrows & nares",
|
||||
"error_message": "Value beard, eyebrows & nares is not in choices ['head', 'neck', 'chest']."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Help me correct the incorrect values based on the given error messages.
|
||||
```
|
||||
|
||||
后续 LLM 的返回可以仅针对这部分问题的修正,而不需要再重复生成整个 json。生成的新结果会由 guardrails 再自动填写回原来的位置,非常丝滑。除了 json 格式的检查外,RAIL spec 中还提供了通过脚本检查的扩展支持,可以用来检查更加复杂的内容,例如 Python 代码是否合法,结果中是否有敏感信息,甚至通过 LLM 再来检查生成的内容是否有害,做结果过滤等。
|
||||
|
||||
### **NeMo-Guardrails**
|
||||
|
||||
来自 Nvidia 的一个同名项目,其目标相比 guardrails 更有野心,想要确保 LLM 应用整体的可信度,无害性以及数据安全性等,而不仅仅只是输出的结构化检查和修复。因此其实现思路上也复杂不少,设计了一种专门的 Colang 语言,来支持更加通用多样的业务流,而不仅仅是生成 -> 检查 -> 修复。不过它的设计都是基于对话做的。实际开发应用可能不太合适。
|
||||
|
||||
```markdown
|
||||
define user ask capabilities
|
||||
"What can you do?"
|
||||
"What can you help me with?"
|
||||
"tell me what you can do"
|
||||
"tell me about you"
|
||||
"How can I use your help?"
|
||||
|
||||
define flow
|
||||
user ask capabilities
|
||||
bot inform capabilities
|
||||
|
||||
define bot inform capabilities
|
||||
"I am an AI assistant which helps answer questions based on a given knowledge base. For this interaction, I can answer question based on the job report published by US Bureau of Labor Statistics."
|
||||
```
|
||||
|
||||
从代码可以看出其结合了 python 和自然语言,方便相似度检索。
|
||||
其整体的运作流程如下:
|
||||
|
||||
1. 根据用户输入识别用户意图。在这一步,系统会将用户的输入在 flow 定义的各种用户回复文本中做相似性查找,也就是上面文件中“What can you do?”这一连串内容。这些检索到的预设用户意图内容,结合其它信息如对话样例,最近聊天记录等,形成整体的 prompt,发给 LLM 来生成回复。最终再从回复中提取用户意图。
|
||||
2. 根据意图,判断下一步操作动作。这一步有两种做法,一是当前的状态能够匹配上预定义的 flow。例如用户就是提了一个 bot 能力的问题,那么就会匹配上面定义的 user ask capabilities,下一步动作自然就是 bot inform capabilities。如果没有匹配上,就要由 LLM 自己来决定下一步动作,这时候也会跟生成用户意图一样,对于 flow 定义做一个相似性查找,将相关信息发给 LLM 来做生成。
|
||||
3. 生成 bot 回复。如果上一步生成的 bot 回复意图已经有明确定义了(例如上面的 bot 能力的回复),那么就直接用预定义的回复内容来回复用户。如果没有,就跟生成用户意图一样,做意图的相似性查找,将相关信息给 LLM 来生成回复。注意到很多动态的问题例如 QA 场景,是很难预先定义好回复内容的,这里也支持对接知识库,同样是做 vector search 之后,将相关 context 信息发给 LLM 来生成具体回复。
|
||||
|
||||
### guidance
|
||||
|
||||
之前在 guardrails 中的做法是在 prompt 中给出说明和示范,希望 LLM 能够遵循指令来输出。但现实中往往会出现各种问题,例如额外带了一些其它的文字说明,或者生成的 json 格式不正确等,所以需要后续的 ReAsk 来进行修正。LangChain 里也提供了各种 output parser 来帮忙提取回复中的结构化信息部分,但也经常容易运行失败。
|
||||
|
||||
在 guidance 中,也是通过“模板语言”来定义 LLM 的输出结构,以确保输出格式的正确性。
|
||||
|
||||
```markdown
|
||||
# load a model locally (we use LLaMA here)
|
||||
guidance.llm = guidance.llms.Transformers("your_local_path/llama-7b", device=0)
|
||||
|
||||
# we can pre-define valid option sets
|
||||
valid_weapons = ["sword", "axe", "mace", "spear", "bow", "crossbow"]
|
||||
|
||||
# define the prompt
|
||||
program = guidance("""The following is a character profile for an RPG game in JSON format.
|
||||
json
|
||||
{
|
||||
"description": "{{description}}",
|
||||
"name": "{{gen 'name'}}",
|
||||
"age": {{gen 'age' pattern='[0-9]+' stop=','}},
|
||||
"armor": "{{#select 'armor'}}leather{{or}}chainmail{{or}}plate{{/select}}",
|
||||
"weapon": "{{select 'weapon' options=valid_weapons}}",
|
||||
"class": "{{gen 'class'}}",
|
||||
"mantra": "{{gen 'mantra'}}",
|
||||
"strength": {{gen 'strength' pattern='[0-9]+' stop=','}},
|
||||
"items": [{{#geneach 'items' num_iterations=3}}
|
||||
"{{gen 'this'}}",{{/geneach}}
|
||||
]
|
||||
}""")
|
||||
|
||||
# execute the prompt
|
||||
program(description="A quick and nimble fighter.", valid_weapons=valid_weapons)
|
||||
```
|
||||
|
||||
在之前传统的做法中,这一整个 json 都需要由 LLM 来生成。但是 json 的结构是我们预先定义的,例如有哪些字段,开闭的花括号等,其实都不需要 LLM 来生成。
|
||||
优点:
|
||||
|
||||
1. 生成的 json 结构是保证合法且可控的,不会出现语法错误或者缺失/错误字段等。
|
||||
2. 通过 LLM 生成的 token 数量减少了,理论上可以提升生成速度。
|
||||
|
||||
除了 prompt 模板,它还提供了:
|
||||
|
||||
- 支持 hidden block,例如 LLM 的一些推理过程可能并不需要暴露给最终用户,就可以灵活利用这个特性来生成一些中间结果。
|
||||
- Generation caching,自动把已经生成过的结果缓存起来,提升速度。
|
||||
- 支持 HuggingFace 模型的 guidance acceleration,进一步提升生成速度。
|
||||
- Token healing,不看这个我还不知道 LLM 有这种问题……
|
||||
- Regex pattern guide,在模板的基础上进一步通过正则表达来限定生成的内容规范。
|
||||
|
||||
从项目代码来看,还是有比较浓的“research 味道”的,可读性并不好。实际测试结果也比较翻车。
|
||||
|
||||
### lmql
|
||||
|
||||
在 guidance 的基础上,lmql 这个项目进一步把“prompt 模板”这个概念推进到了一种新的编程语言。从官网能看到给出的一系列示例。语法结构看起来有点像 SQL,但函数与缩进都是 Python 的风格。
|
||||

|
||||
从支持的功能来看,相比 guidance 毫不逊色。例如各种限制条件,代码调用,各种 caching 加速,工具集成等基本都具备。这个框架的格式化输出是其次,其各种可控的输出及语言本身或许更值得关注。
|
||||
|
||||
### TypeChat
|
||||
|
||||
TypeChat 将 prompt 工程替换为 schema 工程:无需编写非结构化的自然语言 prompt 来描述所需输出的格式,而是编写 TS 类型定义。TypeChat 可以帮助 LLM 以 JSON 的形式响应,并且响应结果非常合理:例如用户要求将这句话「我可以要一份蓝莓松饼和一杯特级拿铁咖啡吗?」转化成 JSON 格式,TypeChat 响应结果如下:
|
||||

|
||||
其本质原理是把 interface 之类的 ts 代码作为 prompt 模板。因此它不仅可以对输出结果进行 ts 校验,甚至能够输入注释描述,不可谓非常方便 js 开发者。不过,近日 typechat 爆火,很多开发者企图尝试将 typechat 移植到 python,笔者认为这是缘木求鱼,因为其校验本身依赖的是 ts。笔者在开发过程中,将 typechat 融合到自己的库中,效果不错。但是它本身自带的 prompt 和笔者输入的 prompt 还是存在冲突,还是需要扣扣源码。
|
||||
|
||||
### Langchain
|
||||
|
||||
如果你关注了过去几个月中人工智能的爆炸式发展,那你大概率听说过 LangChain。简单来说,LangChain 是一个 Python 和 JavaScript 库,由 Harrison Chase 开发,用于连接 OpenAI 的 GPT API(后续已扩展到更多模型)以生成人工智能文本。
|
||||
|
||||
langchain 具有特别多的结构化输出工具。例如使用 yaml 定义 Schema,输出结构化 JSON。使用 zodSchema 定义 Schema,输出结构化 JSON。使用 FunctionParameters 定义 Schema,输出结构化 JSON。
|
||||
|
||||
但是笔者这里不打算介绍 langchain。究其原因,是笔者被 langchain 折磨不堪。明明可以几行代码写清楚的东西,langchain 可以各种封装,花了好几十行才写出来。更何况,笔者是用 ts 开发,开发时甚至偷不了任何懒,甚至其文档丝毫不友好。这几天,《机器之心》发布文章表示放弃 langchain。要想让 LangChain 做笔者想让它做的事,就必须花大力气破解它,这将造成大量的技术负担。因为使用人工智能本身就需要花费足够的脑力。LangChain 是为数不多的在大多数常用情况下都会增加开销的软件之一。所以笔者建议非必要,不使用 langchain。
|
||||
|
||||
## LLM 对于结构化信息的理解
|
||||
|
||||
LLM 的可控性、稳定性、事实性、安全性等问题是推进企业级应用中非常关键的问题,上面分享的这些项目都是在这方面做了很多探索,也有很多值得借鉴的地方。总体思路上来说,主要是:
|
||||
|
||||
- 提供一套 prompt 模板定义,允许用户指定 LLM 生成的格式或内容主题。
|
||||
- 在模板基础上,也有不少项目进一步设计了相应的编程语言,让 LLM 与确定性程序的交互更加直观。
|
||||
- 提供各类 validator,保证生成内容符合预期,并且提供了自动处理/修正机制。
|
||||
- 更进一步,也可以在生成前进行干预,例如在 prompt 中给近似案例,修改模型 decode 时的概率分布等。
|
||||
- 其它在可控性基础上做的各种性能与开销的优化,例如缓存,减少 token 消耗量,对开源模型能力的挖掘等。
|
||||
|
||||
即使我们不直接使用上述的项目做开发,也可以从中学习到很多有用的思路。当然也非常期待这个领域出现更多有意思的想法与研究,以及 prompt 与编程语言结合能否碰撞出更多的火花。
|
||||
|
||||
同时笔者认为自动处理机制、自己设计的编程语言等等内容,随着时间发展,一定会层出不穷,不断迭代更新。笔者抛去这些时效性较弱的内容,从描述信息和位置信息两方面思考 peompt 模板该如何设计,当然只是浅浅的抛砖引玉一下。
|
||||
|
||||
### 描述信息
|
||||
|
||||
到底哪种方式更容易于 LLM 去理解?我们不谈框架的设计,只考虑 prompt 的设计。上述框架关于这方面有一些参考,例如有些直接拿 json 作为 prompt 模板,有些拿 xml 作为 prompt 模板,有些拿自己设计的语言作为 prompt,有些拿自然语言作为 prompt 模板。时至今日,选用哪种最适合 LLM 去理解格式化的信息,输出格式化的内容完全没有盖棺定论。甚至时至今日,格式化输出问题还是没有得到可靠稳定的解决,要不然笔者肯定不会介绍这么多框架实践了。
|
||||
|
||||
笔者认为不管哪种方式,都可以从两个方面考量:更简单,更结构。如果想要在开发的时候更简单,或者在使用时更简单,选择 md、yaml 方式描述结构化信息更合适。如果想要更结构化的方式,选择 json、xml、ts,输出都能更有结构,甚至之后做结构校验都更方便。
|
||||
|
||||
想要 LLM 结构化输出更加稳定和理想,笔者认为选择 prompt 模板时必须考虑每个字段是否有足够的辅助信息。例如 xml 描述时,每个标签都有一个描述属性描述这个标签时什么意思。
|
||||
|
||||
#### 额外引申
|
||||
|
||||
笔者之前在开发 LLM 应用时,也曾思考类似的问题。笔者需要将多模态的数据进行结构化的标注,方便 LLM 去理解。但是标注成什么样却是一个很大的难题。笔者选择的是 JSON。但是,关于里面许多内容的标注。笔者在众多方案中徘徊。在细节处深挖,如何设计一种既简单,又能表示各种结构复杂关系,还能够节约 token 的方案及其的难。
|
||||
> 关于后续如何解决,请容笔者卖个关子 sai~
|
||||
|
||||
### 位置信息
|
||||
|
||||
是否有人注意到 llm 对于关键信息在 prompt 中的位置会对结果产生影响呢?在设计 prompt 方面,人们通常建议为语言模型提供详尽的任务描述和背景信息。近期的一些语言模型有能力输入较长的上下文,但它究竟能多好地利用更长的上下文?这一点却相对少有人知。近日,有学者研究发现如果上下文太长,语言模型会更关注其中的前后部分,中间部分却几乎被略过不看,导致模型难以找到放在输入上下文中部的相关信息。下文部分是该论文一些核心内容:
|
||||

|
||||
这是由其本身训练和结构设计有关的,但却对于我们开发有着莫大的帮助和指导意义。
|
||||

|
||||
相比之下,在多文档问答任务上,查询感知型上下文化的影响很小。特别指出,当相关信息位于输入上下文的最开始时,它可以提高性能,但在其他设置中会稍微降低性能。借此,我们可以认为,将重要的信息放在开头,结尾放置结构化模板,或许是一种优质选择。
|
||||
|
||||
那么如果真的为其提供这么多 token,那会真的有用吗?这个问题的答案是:由下游任务决定。因为这取决于所添加上下文的边际价值以及模型有效使用长输入上下文的能力。所以如果能有效地对检索文档排序(让相关信息与输入上下文的起始处更近)或对已排序的列表进行截断处理(必要时返回更少的文档),那么也许可以提升基于语言模型的阅读器使用检索上下文的能力。
|
||||
|
||||
## 题外话
|
||||
|
||||
之前,妙鸭相机突然爆火。其只需 9.9 即可生成同款数字分身,效果拔群。但是很多人发现,其生成的内容极其容易造成肖像权侵犯,这显然是有问题的。更有甚至的是,用户发现妙鸭相机的用户协议存在问题。根据该应用最初版本的用户服务协议,用户需授权妙鸭相机在全世界(包括元宇宙等虚拟空间)范围内享有永久的、不可撤销的、可转让的、可转授权的、免费的和非独家的许可,使得妙鸭相机可以任何形式、任何媒体或技术(无论现在已知或以后开发)使用用户的内容。对于上述内容,妙鸭相机称系“为了使我方能够提供、确保和改进本服务(包括但不限于使用 AI 生成内容作为再训练数据等)”。
|
||||
|
||||
一句话理解,就是你的肖像它随便用,与你无关。
|
||||
|
||||
这不禁让我联想到一部非常发人深省的剧作:《黑镜》。它的第六季第一集讲述的同样是隐私的问题。该集中,主人公的生活隐私由于同意了用户协议,被无时无刻搜集。然后当天晚上就发现流媒体电视上居然出现了跟她同名的电视剧,内容与它当天的生活一模一样,台词甚至更加夸张。于是她的不方便公之于众的生活变得一塌涂地,但她甚至没有办法打官司,因为肯定会输。更令人深省的是,电视剧的主人公是 AI 生成的视频,其肖像确是根据现实存在的明星生成的。那位明星也无法对她的肖像有任何权利。这样一个荒诞的故事,但是仔细想想,却又非常可能发生。
|
||||
|
||||
如今的社会出现了各种大模型。大模型的发展必定需要大数据的支撑。企业为了盈利必定会想方设法的搜集数据,然后肆意使用,转卖。而很多用户对此不自知,更有甚至是非常乐意。例如抖音、B 站,当你对其交互时,你希望它推荐更适合你的视频,它也在搜集你的数据,这是明知且主动的。
|
||||
|
||||
隐私的掠夺是无声的。你认为你的一下点击是没啥价值的隐私数据,殊不知这正中了资本家的下怀。几年前,我也是这样的。高中的大门出现了闸机,可以刷脸进校园。我当时以为这需要像手机解锁一样需要扫描人脸 ID。结果发现,我可以直接进去,闸机上甚至会出现我的照片。我仔细看了看,发现是我入学的证件照。原来一张照片就能刷脸进校园。原来就连学校也可以不经同学同意,将照片用作其他用途。那更何况其他的呢。
|
||||
我想,未来,这样的隐私问题会越来越多。
|
||||
|
||||
## 参考
|
||||
|
||||
<https://mp.weixin.qq.com/s?__biz=MzA3MzI4MjgzMw==&mid=2650885029&idx=4&sn=ac01576a8957b41529dd3c877d262d5e&chksm=84e48fdbb39306cd8979a4fa7f7da14a9428dc28ccc47880d668ef6293b1a8b7b0964569ec36&mpshare=1&scene=23&srcid=0725w9FPsVnOOzkPGPB7lH8h&sharer_sharetime=1690303766527&sharer_shareid=d2396b329b12f49d34967e2b183540dd#rd>
|
||||
<https://mp.weixin.qq.com/s/BngY2WgCcpTOlvdyBNJxqA>
|
||||
<https://microsoft.github.io/TypeChat/>
|
||||
<https://mp.weixin.qq.com/s?__biz=MzA3MzI4MjgzMw==&mid=2650885029&idx=4&sn=ac01576a8957b41529dd3c877d262d5e&chksm=84e48fdbb39306cd8979a4fa7f7da14a9428dc28ccc47880d668ef6293b1a8b7b0964569ec36&mpshare=1&scene=23&srcid=0725w9FPsVnOOzkPGPB7lH8h&sharer_sharetime=1690303766527&sharer_shareid=d2396b329b12f49d34967e2b183540dd#rd>
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
无数伟大的科学家究其一生的研究和探索它,但是你发现本章内容少有相关内容,还是以深度学习为主?为什么?
|
||||
|
||||
## 原因一:时代的浪潮
|
||||
## 原因一:时代的浪潮
|
||||
|
||||
近乎全民深度学习的浪潮下,机器学习的知识被科研界一而再再而三的抛掷脑后,大家争先恐后的刷点,并使用深度学习的解决问题,因此深度学习领域的知识材料得到了井喷式的增长,而少有人愿意投入非常长的时间去研究机器学习的每一条数学公式的背后机理。
|
||||
|
||||
@@ -34,7 +34,7 @@ ZZM 曾经尝试过投入大量时间去钻研数学以及机器学习相关的
|
||||
|
||||
如果你阅览了本章节的数学相关知识和内容以及拓展感觉非常感兴趣并且毫无压力的话,我推荐你尝试去啃一啃大家公认的困难的书籍,比如说著名的花书,互联网上,社区内也有大量的辅助材料来帮助你更进一步的入门
|
||||
|
||||
# 科研导向明显
|
||||
## 科研导向明显
|
||||
|
||||
整篇教程大范围的在教怎么从科研角度去理解一些知识,感觉和工业上的逻有不符之处。
|
||||
|
||||
@@ -48,7 +48,7 @@ ZZM 曾经尝试过投入大量时间去钻研数学以及机器学习相关的
|
||||
|
||||
因此如果你对这方面感兴趣,可能你需要别的途径去获取更多的思考和资源了。
|
||||
|
||||
# 繁杂的知识内容
|
||||
## 繁杂的知识内容
|
||||
|
||||
这点非常抱歉,AI 领域的知识本身就是网状的,复杂的,甚至是互相引用的,这点会导致不可避免的内容变得冗长。
|
||||
|
||||
@@ -56,8 +56,11 @@ ZZM 曾经尝试过投入大量时间去钻研数学以及机器学习相关的
|
||||
|
||||
而不是别人强行灌输给你的
|
||||
|
||||
# 还有更多???
|
||||
## 还有更多???
|
||||
|
||||
联系 ZZM,我努力改
|
||||
::: tip 邮箱
|
||||
1264517821@qq.com
|
||||
:::
|
||||
|
||||

|
||||
<img src=https://cdn.xyxsw.site/boxcnfYSoVgoERduiWP0jWNWMxf.jpg width=200>
|
||||
@@ -1,65 +1,72 @@
|
||||
# 对AI大致方向的概述
|
||||
# 对 AI 大致方向的概述
|
||||
|
||||
## 前言
|
||||
|
||||
# 前言
|
||||
在这个时代,相关内容是非常泛滥的,我们在本章内容中,大致的写一些目前比较有名的方向以及它的简介(也许会比 wiki 和百度有趣一点?)
|
||||
|
||||
在这个时代,相关内容是非常泛滥的,我们在本章内容中,大致的写一些目前比较有名的方向以及它的简介(也许会比wiki和百度有趣一点?)
|
||||
|
||||
# 深度学习 的大致方向分类
|
||||
## 深度学习 的大致方向分类
|
||||
|
||||
本模块会粗略地介绍目前审读学习的研究与应用领域,在这里提前说明:笔者也只是一名普通的杭电学生,视野与认知有限,某些领域我们了解较多就会介绍地更加详细,某些领域了解较少或笔者中无人从事相关研究,就难免会简略介绍甚至有所偏颇,欢迎大家的指正。
|
||||
|
||||
## CV(计算机视觉)
|
||||
### CV(计算机视觉)
|
||||
|
||||
计算机视觉旨在<strong>用计算机模拟人类处理图片信息的能力</strong>,就比如这里有一张图片——手写数字 9
|
||||
计算机视觉旨在**用计算机模拟人类处理图片信息的能力**,就比如这里有一张图片——手写数字 9
|
||||
|
||||

|
||||

|
||||
|
||||
对我们人类而言,能够很轻松地知道这张图片中包含的信息(数字 9),而对计算机来说这只是一堆像素。计算机视觉的任务就是让计算机能够从这堆像素中得到‘数字 9’这个信息。
|
||||
|
||||
相信你通过上面简单的介绍应该能够了解到计算机视觉是在干嘛了,接下来我会举几个相对复杂的例子来让大家了解一下目前的 cv 是在做怎样的研究:
|
||||
|
||||
<strong>图像分割</strong>是在图片中对物体分类,并且把它们所对应的位置标示出来。下图就是把人的五官,面部皮肤和头发分割出来,效(小)果(丑)图如下:
|
||||
::: warning 🐱 **图像分割**是在图片中对物体分类,并且把它们所对应的位置标示出来。下图就是把人的五官,面部皮肤和头发分割出来,效 (小) 果 (丑) 图如下:
|
||||
:::
|
||||
|
||||

|
||||
<table>
|
||||
<tr>
|
||||
<td><img src=https://cdn.xyxsw.site/boxcnxn5GlJZmsrMV5qKNwMlDPc.jpg width=175></td>
|
||||
<td><img src=https://cdn.xyxsw.site/boxcnokdWGegr2XCi1vfg0ZZiWg.png width=200></td>
|
||||
<td><img src=https://cdn.xyxsw.site/boxcn2o9ilOZg6jI6ssTYWhoeme.png width=200></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||

|
||||
::: warning 🐱 **图像生成**相信大家一定不陌生,NovalAI 在 2022 年火的一塌糊涂,我觉得不需要我过多赘述,对它 (Diffusion model) 的改进工作也是层出不穷,这里就放一张由可控姿势网络 (ControlNet) 生成的图片吧:
|
||||
:::
|
||||
|
||||

|
||||

|
||||
|
||||
<strong>图像生成</strong>相信大家一定不陌生,NovalAI 在 2022 年火的一塌糊涂,我觉得不需要我过多赘述,对它(Diffusion model)的改进工作也是层出不穷,这里就放一张由可控姿势网络(ControlNet)生成的图片吧:
|
||||
::: 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) 章节。
|
||||
:::
|
||||
|
||||

|
||||
如果对计算机视觉有兴趣,可以通过以下路线进行学习:深度学习快速入门—> 经典网络。本块内容的主要撰写者之一**SRT 社团**多数成员主要从事 CV 方向研究,欢迎与我们交流。
|
||||
|
||||
<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) 章节。
|
||||
### NLP(自然语言处理)
|
||||
|
||||
如果对计算机视觉有兴趣,可以通过以下路线进行学习:深度学习快速入门—> 经典网络。本块内容的主要撰写者之一<strong>SRT 社团</strong>多数成员主要从事 CV 方向研究,欢迎与我们交流。
|
||||
这就更好理解了,让计算机能够像人类一样,理解文本中的“真正含义”。在计算机眼中,文本就是单纯的字符串,NLP 的工作就是把字符转换为计算机可理解的数据。举个例子,ChatGPT(或者 New Bing) 都是 NLP 的成果。在过去,NLP 领域被细分为了多个小任务,比如文本情感分析、关键段落提取等。而 ChatGPT 的出现可以说是集几乎所有小任务于大成,接下来 NLP 方向的工作会向 ChatGPT 的方向靠近。
|
||||
|
||||
## NLP(自然语言处理)
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src=https://cdn.xyxsw.site/boxcnyh6pakAkcxCKq6pLylSdef.png width=580></td>
|
||||
<td><img src=https://cdn.xyxsw.site/boxcnwWnoEDulgWdqGkY0WeYogc.png width=200></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
这就更好理解了,让计算机能够像人类一样,理解文本中的“真正含义”。在计算机眼中,文本就是单纯的字符串,NLP 的工作就是把字符转换为计算机可理解的数据。举个例子,ChatGPT(或者 New Bing)都是 NLP 的成果。在过去,NLP 领域被细分为了多个小任务,比如文本情感分析、关键段落提取等。而 ChatGPT 的出现可以说是集几乎所有小任务于大成,接下来 NLP 方向的工作会向 ChatGPT 的方向靠近。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 多模态(跨越模态的处理)
|
||||
### 多模态 (跨越模态的处理)
|
||||
|
||||
模态,可以简单理解为数据形式,比如图片是一种模态,文本是一种模态,声音是一种模态,等等……
|
||||
|
||||
而多模态就是让计算机能够将不同模态的信息相对应,一种常用的方法就是让计算机把图片的内容和文本的内容理解为相同的语义(在这个领域一般用一个较长的向量来表示语义)。
|
||||
|
||||
也就是说我<strong>传入一张狗子的照片经过模型得到的向量</strong>与<strong>DOG 这个单词经过模型得到的向量</strong>相近。
|
||||
也就是说我**传入一张狗子的照片经过模型得到的向量**与**DOG 这个单词经过模型得到的向量**相近。
|
||||
|
||||
具体的任务比如说<strong>图片问答</strong>,传入一张图片,问 AI 这张图片里面有几只猫猫,它们是什么颜色,它告诉我有一只猫猫,是橙色的:
|
||||
具体的任务比如说**图片问答**,传入一张图片,问 AI 这张图片里面有几只猫猫,它们是什么颜色,它告诉我有一只猫猫,是橙色的:
|
||||
|
||||

|
||||

|
||||
|
||||
## 对比学习
|
||||
### 对比学习
|
||||
|
||||
因为传统 AI 训练一般都需要数据集标注,比如说图片分割数据集需要人工在数万张图片上抠出具体位置,才能进行训练,这样的人力成本是巨大的,而且难以得到更多数据。因此,对比学习应运而生,这是一种不需要进行标注或者只需要少量标注的训练方式,具体可见[4.6.8对比学习](4.6.8%E5%AF%B9%E6%AF%94%E5%AD%A6%E4%B9%A0.md) 。
|
||||
因为传统 AI 训练一般都需要数据集标注,比如说图片分割数据集需要人工在数万张图片上抠出具体位置,才能进行训练,这样的人力成本是巨大的,而且难以得到更多数据。因此,对比学习应运而生,这是一种不需要进行标注或者只需要少量标注的训练方式,具体可见[4.6.8 对比学习](4.6.8%E5%AF%B9%E6%AF%94%E5%AD%A6%E4%B9%A0.md) 。
|
||||
|
||||
## 强化学习
|
||||
### 强化学习
|
||||
|
||||
强调模型如何依据环境(比如扫地机器人在学习家里的陈设,这时陈设就是环境)的变化而改进,以取得最大的收益(比如游戏得到最高分)。
|
||||
|
||||
@@ -67,25 +74,26 @@
|
||||
|
||||
强化学习主要理论来源于心理学中的动物学习和最优控制的控制理论。说的通俗点,强化学习就是操控智能体与环境交互、去不断试错,在这个过程中进行学习。因此,强化学习被普遍地应用于游戏、资源优化分配、机器人等领域。强化学习本身已经是个老东西了,但是和深度学习结合之后焕发出了第二春——深度强化学习(DRL)。
|
||||
|
||||
深度强化学习最初来源是2013年谷歌DeepMind团队发表的《Playing Atari with Deep Reinforcement Learning》一文,正式提出Deep Q-network(DQN)算法。在这篇论文中,DeepMind团队训练智能体Agent玩雅达利游戏,并取得了惊人的成绩。事实上,深度强化学习最为人熟知的成就是AlphaGO Zero,它没有使用任何人类棋谱进行训练,训练了三天的成就就已经超过了人类几千年的经验积累<del>导致柯洁道心破碎</del>。
|
||||
深度强化学习最初来源是 2013 年谷歌 DeepMind 团队发表的《Playing Atari with Deep Reinforcement Learning》一文,正式提出 Deep Q-network(DQN)算法。在这篇论文中,DeepMind 团队训练智能体 Agent 玩雅达利游戏,并取得了惊人的成绩。事实上,深度强化学习最为人熟知的成就是 AlphaGO Zero,它没有使用任何人类棋谱进行训练,训练了三天的成就就已经超过了人类几千年的经验积累<del>导致柯洁道心破碎</del>。
|
||||
|
||||
# 交叉学科&经典机器学习算法
|
||||
## 交叉学科&经典机器学习算法
|
||||
|
||||
交叉学科巨大的难度在于你往往需要掌握多个学科以及其相对应的知识。
|
||||
|
||||
举个例子:如果你想要做出一个可以识别病人是否得了某种疾病,现在你得到了一批数据,你首先得自己可以标注出或者找到这个数据中,哪些是有问题的,并且可以指明问题在哪,如果你想分出更具体的,比如具体哪里有问题,那你可能甚至需要熟悉他并且把他标注出来。
|
||||
|
||||
目前其实全学科都有向着AI走的趋势,例如量化金融,医疗,生物科学(nature的那篇有关氨基酸的重大发现真的很cool)。他们很多都在用非常传统的机器学习算法,甚至有的大公司的算法岗在处理某些数据的时候,可能会先考虑用最简单的决策树试一试
|
||||
目前其实全学科都有向着 AI 走的趋势,例如量化金融,医疗,生物科学 (nature 的那篇有关氨基酸的重大发现真的很 cool)。他们很多都在用非常传统的机器学习算法,甚至有的大公司的算法岗在处理某些数据的时候,可能会先考虑用最简单的决策树试一试
|
||||
|
||||
当然,在大语言模型出现的趋势下,很多学科的应用会被融合会被简化会被大一统(科研人的崇高理想),但是不得不提的是,传统的机器学习算法和模型仍然希望你能去了解甚至更进一步学习。
|
||||
当然,在大语言模型出现的趋势下,很多学科的应用会被融合会被简化会被大一统 (科研人的崇高理想),但是不得不提的是,传统的机器学习算法和模型仍然希望你能去了解甚至更进一步学习。
|
||||
|
||||
除了能让你了解所谓前人的智慧,还可以给你带来更进一步的在数学思维,算法思维上的提高。
|
||||
|
||||
# And more?
|
||||
## And more?
|
||||
|
||||
我们对AI的定义如果仅仅只有这些内容,我认为还是太过于狭隘了,我们可以把知识规划,知识表征等等东西都可以将他划入AI的定义中去,当然这些还期待着你的进一步探索和思考~
|
||||
我们对 AI 的定义如果仅仅只有这些内容,我认为还是太过于狭隘了,我们可以把知识规划,知识表征等等东西都可以将他划入 AI 的定义中去,当然这些还期待着你的进一步探索和思考~
|
||||
|
||||
## 特别致谢
|
||||
|
||||
# 特别致谢
|
||||
非常荣幸能在本章中得到 IIPL 智能信息处理实验室 [http://iipl.net.cn](http://iipl.net.cn) 的宝贵贡献,衷心感谢他们的无私支持与帮助!
|
||||
|
||||
非常荣幸能在本章中得到 IIPL智能信息处理实验室 http://iipl.net.cn 的宝贵贡献,衷心感谢他们的无私支持与帮助!
|
||||
希望加入 IIPL?欢迎移步[SRT 社团介绍](SRT.md)~
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 机器学习(AI)快速入门(quick start)
|
||||
|
||||
本章内容需要你掌握一定的 python 基础知识。
|
||||
::: warning 😇 本章内容需要你掌握一定的 python 基础知识。
|
||||
|
||||
如果你想要快速了解机器学习,并且动手尝试去实践他,你可以先阅览本部分内容。
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
当然我需要承认一点,为了让大家都可以看懂,我做了很多抽象,具有了很多例子,某些内容不太准确,这是必然的,最为准确的往往是课本上精确到少一个字都不行的概念,这是难以理解的。
|
||||
|
||||
本篇内容只适合新手理解使用,所以不免会损失一些精度。
|
||||
:::
|
||||
|
||||
# 什么是机器学习
|
||||
## 什么是机器学习
|
||||
|
||||
这个概念其实不需要那么多杂七杂八的概念去解释。
|
||||
|
||||
@@ -22,17 +23,17 @@
|
||||
|
||||
然后你给了他更多信息,比如说国家给出了某些条例,他分析这个条例一出,房价就会降低,他给你了个新的数据。
|
||||
|
||||
因此我们得出一个结论:机器学习 = 泛型算法。
|
||||
因此我们得出一个结论:机器学习 = 泛型算法。
|
||||
|
||||
甚至深度学习,也只是机器学习的一部分,不过使用了更多技巧和方法,增大了计算能力罢了。
|
||||
|
||||

|
||||

|
||||
|
||||
# 两种机器学习算法
|
||||
## 两种机器学习算法
|
||||
|
||||
你可以把机器学习算法分为两大类:监督式学习(supervised Learning)和非监督式学习(unsupervised Learning)。要区分两者很简单,但也非常重要。
|
||||
|
||||
## 监督式学习
|
||||
### 监督式学习
|
||||
|
||||
你是卖方的,你公司很大,因此你雇了一批新员工来帮忙。
|
||||
|
||||
@@ -42,15 +43,15 @@
|
||||
|
||||
近三个月来,每当你的城市里有人卖了房子,你都记录了下面的细节——卧室数量、房屋大小、地段等等。但最重要的是,你写下了最终的成交价:
|
||||
|
||||

|
||||

|
||||
|
||||
然后你让新人根据着你的成交价来估计新的数量
|
||||
|
||||

|
||||

|
||||
|
||||
这就是监督学习,你有一个参照物可以帮你决策。
|
||||
|
||||
## 无监督学习
|
||||
### 无监督学习
|
||||
|
||||
没有答案怎么办?
|
||||
|
||||
@@ -66,7 +67,7 @@
|
||||
|
||||
这其实就是一种经典的聚类算法
|
||||
|
||||

|
||||

|
||||
|
||||
可以把特征不一样的数据分开,有非常多的操作,你感兴趣可以选择性的去了解一下。
|
||||
|
||||
@@ -78,29 +79,27 @@
|
||||
|
||||
但是「机器在少量样本数据的基础上找出一个公式来解决特定的问题」不是个好名字。所以最后我们用「机器学习」取而代之。而深度学习,则是机器在数据的基础上通过很深的网络(很多的公式)找一个及解决方案来解决问题。
|
||||
|
||||
# 看看 Code
|
||||
## 看看 Code
|
||||
|
||||
如果你完全不懂机器学习知识,你可能会用一堆 if else 条件判断语句来判断比如说房价
|
||||
|
||||
```python
|
||||
def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
|
||||
price = 0 # In my area, the average house costs $200 per sqft
|
||||
price_per_sqft = 200
|
||||
if neighborhood == "hipsterton":
|
||||
price = 0 # In my area, the average house costs $200 per sqft
|
||||
price_per_sqft = 200 i f neighborhood == "hipsterton":
|
||||
# but some areas cost a bit more
|
||||
price_per_sqft = 400
|
||||
elif neighborhood == "skid row":
|
||||
price_per_sqft = 400 elif neighborhood == "skid row":
|
||||
# and some areas cost less
|
||||
price_per_sqft = 100 # start with a base price estimate based on how big the place is
|
||||
price = price_per_sqft * sqft # now adjust our estimate based on the number of bedrooms
|
||||
if num_of_bedrooms == 0:
|
||||
# Studio apartments are cheap
|
||||
price = price - 20000
|
||||
else:
|
||||
price_per_sqft = 100 # start with a base price estimate based on how big the place is
|
||||
price = price_per_sqft * sqft # now adjust our estimate based on the number of bedrooms
|
||||
if num_of_bedrooms == 0:
|
||||
# Studio apartments are cheap
|
||||
price = price — 20000
|
||||
else:
|
||||
# places with more bedrooms are usually
|
||||
# more valuable
|
||||
price = price + (num_of_bedrooms * 1000)
|
||||
return price
|
||||
price = price + (num_of_bedrooms * 1000)
|
||||
return price
|
||||
```
|
||||
|
||||
假如你像这样瞎忙几个小时,最后也许会得到一些像模像样的东西。但是永远感觉差点东西。
|
||||
@@ -119,7 +118,7 @@ def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
|
||||
|
||||
如果你可以找到这么一个公式:
|
||||
|
||||
Y(房价)=W(参数)*X1(卧室数量)+W*X2(面积)+W*X3(地段)
|
||||
Y(房价)=W(参数) \* X1(卧室数量) + W \*X2(面积) + W \* X3(地段)
|
||||
|
||||
你是不是会舒服很多,可以把他想象成,你要做菜,然后那些参数就是佐料的配比
|
||||
|
||||
@@ -139,7 +138,7 @@ def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
|
||||
|
||||
第二步把每个数值都带入进行运算。
|
||||
|
||||

|
||||

|
||||
|
||||
比如说,如果第一套房产实际成交价为 25 万美元,你的函数估价为 17.8 万美元,这一套房产你就差了 7.2 万。
|
||||
|
||||
@@ -151,7 +150,7 @@ def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
|
||||
|
||||
第三步:
|
||||
|
||||
通过尝试所有可能的权重值组合,不断重复第二步。哪一个权重组合的代价最接近于 0,你就使用哪个。当你找到了合适的权重值,你就解决了问题!
|
||||
通过尝试所有可能的权重值组合,不断重复第二步。哪一个权重组合的代价最接近于 0,你就使用哪个。当你找到了合适的权重值,你就解决了问题!
|
||||
|
||||
兴奋的时刻到了!
|
||||
|
||||
@@ -168,21 +167,21 @@ def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
|
||||
|
||||
为了避免这种情况,数学家们找到了很多种[聪明的办法](https://link.zhihu.com/?target=http%3A//en.wikipedia.org/wiki/Gradient_descent)来快速找到优秀的权重值。下面是一种:
|
||||
|
||||

|
||||

|
||||
|
||||
这就是被称为 loss 函数的东西。
|
||||
|
||||
这是个专业属于,你可以选择性忽略他,我们将它改写一下
|
||||
|
||||

|
||||

|
||||
|
||||
<em>θ 表示当前的权重值。 J(θ) 表示「当前权重的代价」。</em>
|
||||
*θ 表示当前的权重值。J(θ) 表示「当前权重的代价」。*
|
||||
|
||||
这个等式表示,在当前权重值下,我们估价程序的偏离程度。
|
||||
|
||||
如果我们为这个等式中所有卧室数和面积的可能权重值作图的话,我们会得到类似下图的图表:
|
||||
|
||||

|
||||

|
||||
|
||||
因此,我们需要做的只是调整我们的权重,使得我们在图上朝着最低点「走下坡路」。如果我们不断微调权重,一直向最低点移动,那么我们最终不用尝试太多权重就可以到达那里。
|
||||
|
||||
@@ -194,7 +193,7 @@ def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
|
||||
|
||||
当你使用一个机器学习算法库来解决实际问题时,这些都已经为你准备好了。但清楚背后的原理依然是有用的。
|
||||
|
||||

|
||||

|
||||
|
||||
枚举法
|
||||
|
||||
@@ -204,13 +203,13 @@ 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)的数据集)。学习如何应对这一问题,是学习如何成功应用机器学习技术的重点之一。
|
||||
|
||||
换言之,尽管基本概念非常简单,要通过机器学习得到有用的结果还是需要一些技巧和经验的。但是,这是每个开发者都能学会的技巧。
|
||||
|
||||
# 更为智能的预测
|
||||
## 更为智能的预测
|
||||
|
||||
我们通过上一次的函数假设已经得到了一些值。
|
||||
|
||||
@@ -225,25 +224,25 @@ def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
|
||||
|
||||
我们换一个好看的形式给他展示
|
||||
|
||||

|
||||

|
||||
|
||||
<em>箭头头表示了函数中的权重。</em>
|
||||
*箭头头表示了函数中的权重。*
|
||||
|
||||
然而,这个算法仅仅能用于处理一些简单的问题,就是那些输入和输出有着线性关系的问题。但如果真实价格和决定因素的关系并不是如此简单,那我们该怎么办? 比如说,地段对于大户型和小户型的房屋有很大影响,然而对中等户型的房屋并没有太大影响。那我们该怎么在我们的模型中收集这种复杂的信息呢?
|
||||
然而,这个算法仅仅能用于处理一些简单的问题,就是那些输入和输出有着线性关系的问题。但如果真实价格和决定因素的关系并不是如此简单,那我们该怎么办?比如说,地段对于大户型和小户型的房屋有很大影响,然而对中等户型的房屋并没有太大影响。那我们该怎么在我们的模型中收集这种复杂的信息呢?
|
||||
|
||||
所以为了更加的智能化,我们可以利用不同的权重来多次运行这个算法,收集各种不同情况下的估价。
|
||||
|
||||

|
||||

|
||||
|
||||
然后我们把四种整合到一起,就得到一个超级答案
|
||||
|
||||

|
||||

|
||||
|
||||
这样我们相当于得到了更为准确的答案
|
||||
|
||||
# 神经网络是什么
|
||||
## 神经网络是什么
|
||||
|
||||

|
||||

|
||||
|
||||
我们把四个超级网络的结合图整体画出来,其实这就是个超级简单的神经网络,虽然我们省略了很多的内容,但是他仍然有了一定的拟合能力
|
||||
|
||||
@@ -272,7 +271,7 @@ class LinearModel(torch.nn.Module):
|
||||
y_pred=self.linear(x)
|
||||
return y_pred
|
||||
'''
|
||||
线性模型所必须的前馈传播,即wx+b
|
||||
线性模型所必须的前馈传播,即 wx+b
|
||||
'''
|
||||
|
||||
model=LinearModel()
|
||||
@@ -299,36 +298,38 @@ y_test=model(x_test)
|
||||
print('y_pred=',y_test.data)
|
||||
```
|
||||
|
||||
# 由浅入深(不会涉及代码)
|
||||
## 由浅入深(不会涉及代码)
|
||||
|
||||
# 为什么不教我写代码?
|
||||
::: warning 😇 为什么不教我写代码?
|
||||
|
||||
因为你可能看这些基础知识感觉很轻松毫无压力,但是倘若附上很多代码,会一瞬间拉高这里的难度,虽然仅仅只是调包。
|
||||
|
||||
但是我还是会在上面贴上一点代码,但不会有很详细的讲解,因为很多都是调包,没什么好说的,如果你完全零基础,忽略这部分内容即可
|
||||
|
||||
:::
|
||||
|
||||
我们尝试做一个神奇的工作,那就是用神经网络来识别一下手写数字,听上去非常不可思议,但是我要提前说的一点是,图像也不过是数据的组合,每一张图片有不同程度的像素值,如果我们把每一个像素值都当成神经网络的输入值,然后经过一个黑盒,让他识别出一个他认为可能的数字,然后进行纠正即可。
|
||||
|
||||
机器学习只有在你拥有数据(最好是大量数据)的情况下,才能有效。所以,我们需要有大量的手写「8」来开始我们的尝试。幸运的是,恰好有研究人员建立了 [MNIST 手写数字数据库](https://link.zhihu.com/?target=http%3A//yann.lecun.com/exdb/mnist/),它能助我们一臂之力。MNIST 提供了 60,000 张手写数字的图片,每张图片分辨率为 18×18。即有这么多的数据。
|
||||
|
||||
```python
|
||||
(X_train, y_train), (X_test, y_test) = mnist.load_data()
|
||||
#这段是导入minist的方法,但是你看不到,如果你想看到的话需要其他操作
|
||||
#这段是导入 minist 的方法,但是你看不到,如果你想看到的话需要其他操作
|
||||
```
|
||||
|
||||
我们试着只识别一个数字 8
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
我们把一幅 18×18 像素的图片当成一串含有 324 个数字的数组,就可以把它输入到我们的神经网络里面了:
|
||||
|
||||

|
||||

|
||||
|
||||
为了更好地操控我们的输入数据,我们把神经网络的输入节点扩大到 324 个:
|
||||
|
||||

|
||||

|
||||
|
||||
请注意,我们的神经网络现在有了两个输出(而不仅仅是一个房子的价格)。第一个输出会预测图片是「8」的概率,而第二个则输出不是「8」的概率。概括地说,我们就可以依靠多种不同的输出,利用神经网络把要识别的物品进行分组。
|
||||
|
||||
@@ -345,17 +346,17 @@ model.add(Activation('relu'))# 激活函数,你可以理解为加上这个东
|
||||
|
||||
现在唯一要做的就是用各种「8」和非「8」的图片来训练我们的神经网络了。当我们喂给神经网络一个「8」的时候,我们会告诉它是「8」的概率是 100% ,而不是「8」的概率是 0%,反之亦然。
|
||||
|
||||
# 仅此而已吗
|
||||
## 仅此而已吗
|
||||
|
||||
当数字并不是正好在图片中央的时候,我们的识别器就完全不工作了。一点点的位移我们的识别器就掀桌子不干了
|
||||
|
||||

|
||||

|
||||
|
||||
这是因为我们的网络只学习到了正中央的「8」。它并不知道那些偏离中心的「8」长什么样子。它仅仅知道中间是「8」的图片规律。
|
||||
|
||||
在真实世界中,这种识别器好像并没什么卵用。真实世界的问题永远不会如此轻松简单。所以,我们需要知道,当「8」不在图片正中时,怎么才能让我们的神经网络识别它。
|
||||
|
||||
## 暴力方法:更多的数据和更深的网络
|
||||
### 暴力方法:更多的数据和更深的网络
|
||||
|
||||
他不能识别靠左靠右的数据?我们都给他!给他任何位置的图片!
|
||||
|
||||
@@ -365,19 +366,19 @@ model.add(Activation('relu'))# 激活函数,你可以理解为加上这个东
|
||||
|
||||
当然,你同时也需要更强的拟合能力和更深的网络。
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
一层一层堆叠起来,这种方法很早就出现了。
|
||||
|
||||
## 更好的方法?
|
||||
### 更好的方法?
|
||||
|
||||
你可以通过卷积神经网络进行进一步的处理
|
||||
|
||||
作为人类,你能够直观地感知到图片中存在某种层级(hierarchy)或者是概念结构(conceptual structure)。比如说,你在看
|
||||
|
||||

|
||||

|
||||
|
||||
你会快速的辨认出一匹马,一个人。
|
||||
|
||||
@@ -387,25 +388,25 @@ model.add(Activation('relu'))# 激活函数,你可以理解为加上这个东
|
||||
|
||||
有人对此做过研究,人的眼睛可能会逐步判断一个物体的信息,比如说你看到一张图片,你会先看颜色,然后看纹理然后再看整体,那么我们需要一种操作来模拟这个过程,我们管这种操作叫卷积操作。
|
||||
|
||||

|
||||

|
||||
|
||||
## 卷积是如何工作的
|
||||
### 卷积是如何工作的
|
||||
|
||||
之前我们提到过,我们可以把一整张图片当做一串数字输入到神经网络里面。不同的是,这次我们会利用<strong>平移不变性</strong>的概念来把这件事做得更智能。
|
||||
之前我们提到过,我们可以把一整张图片当做一串数字输入到神经网络里面。不同的是,这次我们会利用**平移不变性**的概念来把这件事做得更智能。
|
||||
|
||||
当然也有最新研究说卷积不具备平移不变性,但是我这里使用这个概念是为了大伙更好的理解,举个例子:你将 8 无论放在左上角还是左下角都改变不了他是 8 的事实
|
||||
|
||||

|
||||

|
||||
|
||||
我们将一张图像分成这么多个小块,然后输入神经网络中的是一个小块。<em>每次判断一张小图块。</em>
|
||||
我们将一张图像分成这么多个小块,然后输入神经网络中的是一个小块。*每次判断一张小图块。*
|
||||
|
||||
然而,有一个非常重要的不同:对于每个小图块,我们会使用同样的神经网络权重。换一句话来说,我们平等对待每一个小图块。如果哪个小图块有任何异常出现,我们就认为这个图块是「异常」
|
||||
|
||||

|
||||

|
||||
|
||||
换一句话来说,我们从一整张图片开始,最后得到一个稍小一点的数组,里面存储着我们图片中的哪一部分有异常。
|
||||
|
||||
## 池化层
|
||||
### 池化层
|
||||
|
||||
图像可能特别大。比如说 1024*1024 再来个颜色 RGB
|
||||
|
||||
@@ -413,7 +414,7 @@ model.add(Activation('relu'))# 激活函数,你可以理解为加上这个东
|
||||
|
||||
让我们先来看每个 2×2 的方阵数组,并且留下最大的数:
|
||||
|
||||

|
||||

|
||||
|
||||
每一波我们只保留一个数,这样就大大减少了图片的计算量了。
|
||||
|
||||
@@ -429,13 +430,13 @@ model.add(Activation('relu'))# 激活函数,你可以理解为加上这个东
|
||||
|
||||
我们也要感谢显卡,这项技术早就出现了但是一直算不了,有了显卡让这件事成为了可能。
|
||||
|
||||
## 作出预测
|
||||
### 作出预测
|
||||
|
||||
到现在为止,我们已经把一个很大的图片缩减到了一个相对较小的数组。
|
||||
|
||||
你猜怎么着?数组就是一串数字而已,所以我们我们可以把这个数组输入到另外一个神经网络里面去。最后的这个神经网络会决定这个图片是否匹配。为了区分它和卷积的不同,我们把它称作「全连接」网络
|
||||
|
||||

|
||||

|
||||
|
||||
我们的图片处理管道是一系列的步骤:卷积、最大池化,还有最后的「全连接」网络。
|
||||
|
||||
@@ -445,10 +446,10 @@ model.add(Activation('relu'))# 激活函数,你可以理解为加上这个东
|
||||
|
||||
比如说,第一个卷积的步骤可能就是尝试去识别尖锐的东西,而第二个卷积步骤则是通过找到的尖锐物体来找鸟类的喙,最后一步是通过鸟喙来识别整只鸟,以此类推。
|
||||
|
||||
# 结语
|
||||
## 结语
|
||||
|
||||
这篇文章仅仅只是粗略的讲述了一些机器学习的一些基本操作,如果你要更深一步学习的话你可能还需要更多的探索。
|
||||
|
||||
# 参考资料
|
||||
## 参考资料
|
||||
|
||||
[machine-learning-for-software-engineers/README-zh-CN.md at master · ZuzooVn/machine-learning-for-sof](https://github.com/ZuzooVn/machine-learning-for-software-engineers/blob/master/README-zh-CN.md#%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E6%A6%82%E8%AE%BA)
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
# 程序示例——maze 迷宫解搜索
|
||||
|
||||
::: warning 😋
|
||||
阅读程序中涉及搜索算法的部分,然后运行程序,享受机器自动帮你寻找路径的快乐!
|
||||
完成习题
|
||||
:::
|
||||
|
||||
::: tip 📥
|
||||
本节附件下载 <Download url="https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/code/1-Lecture.zip"/>
|
||||
本节附件下载 <Download url="https://cdn.xyxsw.site/code/1-Lecture.zip"/>
|
||||
:::
|
||||
|
||||
/4.人工智能/code/MAZE.zip
|
||||
|
||||
# Node
|
||||
## Node
|
||||
|
||||
```python
|
||||
# 节点类 Node
|
||||
@@ -21,7 +20,7 @@ class Node:
|
||||
self.action = action # 存储采取的行动
|
||||
```
|
||||
|
||||
## 节点复习:
|
||||
## 节点复习
|
||||
|
||||
- 节点是一种包含以下数据的数据结构:
|
||||
- 状态——state
|
||||
@@ -29,7 +28,7 @@ class Node:
|
||||
- 应用于父级状态以获取当前节点的操作——action
|
||||
- 从初始状态到该节点的路径成本——path cost
|
||||
|
||||
# 堆栈边域——DFS
|
||||
## 堆栈边域——DFS
|
||||
|
||||
```python
|
||||
class StackFrontier: # 堆栈边域
|
||||
@@ -50,11 +49,11 @@ class StackFrontier: # 堆栈边域
|
||||
return node
|
||||
```
|
||||
|
||||
## 深度优先搜索复习:
|
||||
## 深度优先搜索复习
|
||||
|
||||
- 深度优先搜索算法在尝试另一个方向之前耗尽每个方向。在这些情况下,边域作为堆栈数据结构进行管理。这里需要记住的流行语是“后进先出”。在将节点添加到边域后,第一个要删除和考虑的节点是最后一个要添加的节点。这导致了一种搜索算法,该算法在第一个方向上尽可能深入,直到尽头,同时将所有其他方向留到后面。“不撞南墙不回头”
|
||||
深度优先搜索算法在尝试另一个方向之前耗尽每个方向。在这些情况下,边域作为堆栈数据结构进行管理。这里需要记住的流行语是“后进先出”。在将节点添加到边域后,第一个要删除和考虑的节点是最后一个要添加的节点。这导致了一种搜索算法,该算法在第一个方向上尽可能深入,直到尽头,同时将所有其他方向留到后面。“不撞南墙不回头”
|
||||
|
||||
# 队列边域——BFS
|
||||
## 队列边域——BFS
|
||||
|
||||
```python
|
||||
class QueueFrontier(StackFrontier): # 队列边域
|
||||
@@ -67,11 +66,11 @@ class QueueFrontier(StackFrontier): # 队列边域
|
||||
return node
|
||||
```
|
||||
|
||||
## 广度优先搜索复习:
|
||||
## 广度优先搜索复习
|
||||
|
||||
- 广度优先搜索算法将同时遵循多个方向,在每个可能的方向上迈出一步,然后在每个方向上迈出第二步。在这种情况下,边域作为队列数据结构进行管理。这里需要记住的流行语是“先进先出”。在这种情况下,所有新节点都会排成一行,并根据先添加的节点来考虑节点(先到先得!)。这导致搜索算法在任何一个方向上迈出第二步之前,在每个可能的方向上迈出一步。
|
||||
广度优先搜索算法将同时遵循多个方向,在每个可能的方向上迈出一步,然后在每个方向上迈出第二步。在这种情况下,边域作为队列数据结构进行管理。这里需要记住的流行语是“先进先出”。在这种情况下,所有新节点都会排成一行,并根据先添加的节点来考虑节点(先到先得!)。这导致搜索算法在任何一个方向上迈出第二步之前,在每个可能的方向上迈出一步。
|
||||
|
||||
# 迷宫解——Maze_solution
|
||||
## 迷宫解——Maze_solution
|
||||
|
||||
```python
|
||||
class Maze:
|
||||
@@ -111,7 +110,7 @@ class Maze:
|
||||
# 打印结果
|
||||
def print(self):
|
||||
...
|
||||
# 寻找邻结点,返回元组(动作,坐标(x,y))
|
||||
# 寻找邻结点,返回元组 (动作,坐标 (x,y))
|
||||
def neighbors(self, state):
|
||||
row, col = state
|
||||
candidates = [
|
||||
@@ -130,8 +129,8 @@ class Maze:
|
||||
self.num_explored = 0 # 已搜索的路径长度
|
||||
# 将边界初始化为起始位置
|
||||
start = Node(state=self.start, parent=None, action=None)
|
||||
frontier = StackFrontier() # 采用DFS
|
||||
# frontier = QueueFrontier() # 采用BFS
|
||||
frontier = StackFrontier() # 采用 DFS
|
||||
# frontier = QueueFrontier() # 采用 BFS
|
||||
frontier.add(start)
|
||||
# 初始化一个空的探索集
|
||||
self.explored = set() # 存储已搜索的结点
|
||||
@@ -148,7 +147,7 @@ class Maze:
|
||||
actions = []
|
||||
cells = []
|
||||
while node.parent is not None: # 遍历父节点得到路径动作
|
||||
actions.append(node.action)
|
||||
actions.append(node.action)
|
||||
cells.append(node.state)
|
||||
node = node.parent
|
||||
actions.reverse()
|
||||
@@ -166,7 +165,7 @@ class Maze:
|
||||
...
|
||||
```
|
||||
|
||||
# Quiz
|
||||
## Quiz
|
||||
|
||||
1. 在深度优先搜索(DFS)和广度优先搜索(BFS)之间,哪一个会在迷宫中找到更短的路径?
|
||||
1. DFS 将始终找到比 BFS 更短的路径
|
||||
@@ -176,7 +175,7 @@ class Maze:
|
||||
5. 两种算法总是能找到相同长度的路径
|
||||
2. 下面的问题将问你关于下面迷宫的问题。灰色单元格表示墙壁。在这个迷宫上运行了一个搜索算法,找到了从 A 点到 B 点的黄色突出显示的路径。在这样做的过程中,红色突出显示的细胞是探索的状态,但并没有达到目标。
|
||||
|
||||

|
||||

|
||||
|
||||
在讲座中讨论的四种搜索算法中——深度优先搜索、广度优先搜索、曼哈顿距离启发式贪婪最佳优先搜索和曼哈顿距离启发式$A^*$
|
||||
|
||||
@@ -190,21 +189,20 @@ class Maze:
|
||||
7. 可能是四种算法中的任何一种
|
||||
8. 不可能是四种算法中的任何一种
|
||||
3. 为什么有深度限制的极大极小算法有时比没有深度限制的极大极小更可取?
|
||||
1. 深度受限的极大极小算法可以更快地做出决定,因为它探索的状态更少
|
||||
2. 深度受限的极大极小算法将在没有深度限制的情况下实现与极大极小算法相同的输出,但有时会使用较少的内存
|
||||
3. 深度受限的极大极小算法可以通过不探索已知的次优状态来做出更优化的决策
|
||||
4. 深度限制的极小极大值永远不会比没有深度限制的极大极小值更可取
|
||||
4. 下面的问题将询问您关于下面的 Minimax 树,其中绿色向上箭头表示 MAX 玩家,红色向下箭头表示 MIN 玩家。每个叶节点都标有其值。
|
||||
1. 深度受限的极大极小算法可以更快地做出决定,因为它探索的状态更少
|
||||
2. 深度受限的极大极小算法将在没有深度限制的情况下实现与极大极小算法相同的输出,但有时会使用较少的内存
|
||||
3. 深度受限的极大极小算法可以通过不探索已知的次优状态来做出更优化的决策
|
||||
4. 深度限制的极小极大值永远不会比没有深度限制的极大极小值更可取
|
||||
4. 下面的问题将询问您关于下面的 Minimax 树,其中绿色向上箭头表示 MAX 玩家,红色向下箭头表示 MIN 玩家。每个叶节点都标有其值。
|
||||
|
||||

|
||||

|
||||
|
||||
根节点的值是多少?
|
||||
|
||||
- 2
|
||||
- 3
|
||||
- 4
|
||||
- 5
|
||||
- 6
|
||||
- 7
|
||||
- 8
|
||||
- 9
|
||||
1. 2
|
||||
2. 3
|
||||
3. 4
|
||||
4. 5
|
||||
5. 6
|
||||
6. 7
|
||||
7. 8
|
||||
8. 9
|
||||
|
||||
@@ -1,61 +1,64 @@
|
||||
# 项目:Tic-Tac-Toe 井字棋
|
||||
|
||||
我们为你提供了一个简单有趣的项目,帮助你进行知识巩固,请认真阅读文档内容。
|
||||
::: warning 😋 我们为你提供了一个简单有趣的项目,帮助你进行知识巩固,请认真阅读文档内容。
|
||||
|
||||
如果你卡住了,请记得回来阅读文档,或请求身边人的帮助。
|
||||
:::
|
||||
|
||||
::: tip 📥
|
||||
本节附件下载 <Download url="https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/code/1-Projects.zip"/>
|
||||
本节附件下载 <Download url="https://cdn.xyxsw.site/code/1-Projects.zip"/>
|
||||
:::
|
||||
|
||||
`pip3 install -r requirements.txt`
|
||||
|
||||
# 理解
|
||||
## 理解
|
||||
|
||||
- 这个项目有两个主要文件:`runner.py` 和 `tictactoe.py`。`tictactoe.py` 包含了玩游戏和做出最佳动作的所有逻辑。`runner.py` 已经为你实现,它包含了运行游戏图形界面的所有代码。一旦你完成了 `tictactoe.py` 中所有必需的功能,你就可以运行 `python runner.py` 来对抗你的人工智能了!
|
||||
- 让我们打开 `tictactoe.py` 来了解所提供的内容。首先,我们定义了三个变量:X、O 和 EMPTY,以表示游戏的可能移动。
|
||||
- 函数 `initial_state` 返回游戏的启动状态。对于这个问题,我们选择将游戏状态表示为三个列表的列表(表示棋盘的三行),其中每个内部列表包含三个值,即 X、O 或 EMPTY。以下是我们留给你实现的功能!
|
||||
这个项目有两个主要文件:`runner.py` 和 `tictactoe.py`。`tictactoe.py` 包含了玩游戏和做出最佳动作的所有逻辑。`runner.py` 已经为你实现,它包含了运行游戏图形界面的所有代码。一旦你完成了 `tictactoe.py` 中所有必需的功能,你就可以运行 `python runner.py` 来对抗你的人工智能了!
|
||||
|
||||
# 说明
|
||||
让我们打开 `tictactoe.py` 来了解所提供的内容。首先,我们定义了三个变量:X、O 和 EMPTY,以表示游戏的可能移动。
|
||||
|
||||
- 实现 `player`, `actions`, `result`, `winner`, `terminal`, `utility`, 以及 `minimax`.
|
||||
函数 `initial_state` 返回游戏的启动状态。对于这个问题,我们选择将游戏状态表示为三个列表的列表(表示棋盘的三行),其中每个内部列表包含三个值,即 X、O 或 EMPTY。以下是我们留给你实现的功能!
|
||||
|
||||
- `player` 函数应该以棋盘状态作为输入,并返回轮到哪个玩家(X 或 O)。
|
||||
## 说明
|
||||
|
||||
- 在初始游戏状态下,X 获得第一步。随后,玩家交替进行每一个动作。
|
||||
- 如果提供结束棋盘状态作为输入(即游戏已经结束),则任何返回值都是可接受的。
|
||||
- `actions` 函数应该返回一组在给定的棋盘状态上可以采取的所有可能的操作。
|
||||
实现 `player`, `actions`, `result`, `winner`, `terminal`, `utility`, 以及 `minimax`.
|
||||
|
||||
- 每个动作都应该表示为元组 `(i,j)`,其中 `i` 对应于移动的行(0、1 或 2),`j` 对应于行中的哪个单元格对应于移动(也是 0、1、或 2)。
|
||||
- 可能的移动是棋盘上任何没有 X 或 O 的单元格。
|
||||
- 如果提供结束棋盘状态作为输入,则任何返回值都是可接受的。
|
||||
- `result` 函数以一个棋盘状态和一个动作作为输入,并且应该返回一个新的棋盘状态,而不修改原始棋盘。
|
||||
- `player` 函数应该以棋盘状态作为输入,并返回轮到哪个玩家(X 或 O)。
|
||||
|
||||
- 如果 `action` 函数接受了一个无效的动作,你的程序应该<u>raise an exception</u>.
|
||||
- 返回的棋盘状态应该是从原始输入棋盘,并让轮到它的玩家在输入动作指示的单元格处移动所产生的棋盘。
|
||||
- 重要的是,原始棋盘应该保持不变:因为 Minimax 最终需要在计算过程中考虑许多不同的棋盘状态。这意味着简单地更新棋盘上的单元格本身并不是 `result` 函数的正确实现。在做出任何更改之前,你可能需要先对棋盘状态进行<u>deep copy</u>。
|
||||
- `winner` 函数应该接受一个棋盘作为输入,如果游戏结束,则返回游戏的获胜者。
|
||||
- 在初始游戏状态下,X 获得第一步。随后,玩家交替进行每一个动作。
|
||||
- 如果提供结束棋盘状态作为输入(即游戏已经结束),则任何返回值都是可接受的。
|
||||
- `actions` 函数应该返回一组在给定的棋盘状态上可以采取的所有可能的操作。
|
||||
|
||||
- 如果 X 玩家赢得了游戏,函数应该返回 X。如果 O 玩家赢得了比赛,函数应该返回 O。
|
||||
- 一个人可以通过水平、垂直或对角连续三次移动赢得比赛。
|
||||
- 你可以认为最多会有一个赢家(也就是说,没有一个棋盘会同时有两个玩家连着三个,因为这将是一个无效的棋盘状态)。
|
||||
- 如果游戏没有赢家(要么是因为游戏正在进行,要么是因为比赛以平局结束),函数应该返回 `None`。
|
||||
- `terminal` 函数应该接受一个棋盘作为输入,并返回一个布尔值,指示游戏是否结束。
|
||||
- 每个动作都应该表示为元组 `(i,j)`,其中 `i` 对应于移动的行(0、1 或 2),`j` 对应于行中的哪个单元格对应于移动(也是 0、1、或 2)。
|
||||
- 可能的移动是棋盘上任何没有 X 或 O 的单元格。
|
||||
- 如果提供结束棋盘状态作为输入,则任何返回值都是可接受的。
|
||||
- `result` 函数以一个棋盘状态和一个动作作为输入,并且应该返回一个新的棋盘状态,而不修改原始棋盘。
|
||||
|
||||
- 如果游戏结束,要么是因为有人赢得了游戏,要么是由于所有单元格都已填充而没有人获胜,则函数应返回 `True`。
|
||||
- 否则,如果游戏仍在进行中,则函数应返回 `False`。
|
||||
- `utility` 函数应接受结束棋盘状态作为输入,并输出该棋盘的分数。
|
||||
- 如果 `action` 函数接受了一个无效的动作,你的程序应该<u>raise an exception</u>.
|
||||
- 返回的棋盘状态应该是从原始输入棋盘,并让轮到它的玩家在输入动作指示的单元格处移动所产生的棋盘。
|
||||
- 重要的是,原始棋盘应该保持不变:因为 Minimax 最终需要在计算过程中考虑许多不同的棋盘状态。这意味着简单地更新棋盘上的单元格本身并不是 `result` 函数的正确实现。在做出任何更改之前,你可能需要先对棋盘状态进行<u>deep copy</u>。
|
||||
- `winner` 函数应该接受一个棋盘作为输入,如果游戏结束,则返回游戏的获胜者。
|
||||
|
||||
- 如果 X 赢得了比赛,则分数为 1。如果 O 赢得了比赛,则分数为-1。如果比赛以平局结束,则分数为 0。
|
||||
- 你可以假设只有当 `terminal(board)` 为 True 时,才会在棋盘上调用 `utility`。
|
||||
- `minimax` 函数应该以一个棋盘作为输入,并返回玩家在该棋盘上移动的最佳移动。
|
||||
- 如果 X 玩家赢得了游戏,函数应该返回 X。如果 O 玩家赢得了比赛,函数应该返回 O。
|
||||
- 一个人可以通过水平、垂直或对角连续三次移动赢得比赛。
|
||||
- 你可以认为最多会有一个赢家(也就是说,没有一个棋盘会同时有两个玩家连着三个,因为这将是一个无效的棋盘状态)。
|
||||
- 如果游戏没有赢家(要么是因为游戏正在进行,要么是因为比赛以平局结束),函数应该返回 `None`。
|
||||
- `terminal` 函数应该接受一个棋盘作为输入,并返回一个布尔值,指示游戏是否结束。
|
||||
|
||||
- 返回的移动应该是最佳动作 `(i,j)`,这是棋盘上允许的动作之一。如果多次移动都是同样最佳的,那么这些移动中的任何一次都是可以接受的。
|
||||
- 如果该棋盘是结束棋盘状态,则 `minimax` 函数应返回 `None`。
|
||||
- 对于所有接受棋盘作为输入的函数,你可以假设它是一个有效的棋盘(即,它是包含三行的列表,每行都有三个值 X、O 或 EMPTY)。你不应该修改所提供的函数声明(每个函数的参数的顺序或数量)。、
|
||||
- 一旦所有功能都得到了正确的实现,你就应该能够运行 `python runner.py` 并与你的人工智能进行比赛。而且,由于井字棋是双方最佳比赛的平局,你永远不应该能够击败人工智能(尽管如果你打得不好,它可能会打败你!)
|
||||
- 如果游戏结束,要么是因为有人赢得了游戏,要么是由于所有单元格都已填充而没有人获胜,则函数应返回 `True`。
|
||||
- 否则,如果游戏仍在进行中,则函数应返回 `False`。
|
||||
- `utility` 函数应接受结束棋盘状态作为输入,并输出该棋盘的分数。
|
||||
|
||||
# 提示
|
||||
- 如果 X 赢得了比赛,则分数为 1。如果 O 赢得了比赛,则分数为 -1。如果比赛以平局结束,则分数为 0。
|
||||
- 你可以假设只有当 `terminal(board)` 为 True 时,才会在棋盘上调用 `utility`。
|
||||
- `minimax` 函数应该以一个棋盘作为输入,并返回玩家在该棋盘上移动的最佳移动。
|
||||
|
||||
- 返回的移动应该是最佳动作 `(i,j)`,这是棋盘上允许的动作之一。如果多次移动都是同样最佳的,那么这些移动中的任何一次都是可以接受的。
|
||||
- 如果该棋盘是结束棋盘状态,则 `minimax` 函数应返回 `None`。
|
||||
对于所有接受棋盘作为输入的函数,你可以假设它是一个有效的棋盘(即,它是包含三行的列表,每行都有三个值 X、O 或 EMPTY)。你不应该修改所提供的函数声明(每个函数的参数的顺序或数量)。、
|
||||
一旦所有功能都得到了正确的实现,你就应该能够运行 `python runner.py` 并与你的人工智能进行比赛。而且,由于井字棋是双方最佳比赛的平局,你永远不应该能够击败人工智能(尽管如果你打得不好,它可能会打败你!)
|
||||
|
||||
## 提示
|
||||
|
||||
- 如果你想在不同的 Python 文件中测试你的函数,你可以用类似于 `from tictactoe import initial_state` 的代码来导入它们。
|
||||
- 欢迎在 `tictactoe.py` 中添加其他辅助函数,前提是它们的名称不会与模块中已有的函数或变量名称冲突。
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
# 搜索
|
||||
|
||||
在我们日常生活中,其实有非常多的地方使用了所谓的 AI 算法,只是我们通常没有察觉。
|
||||
::: warning 😅 在我们日常生活中,其实有非常多的地方使用了所谓的 AI 算法,只是我们通常没有察觉。
|
||||
|
||||
比如美团的外卖程序里面,可以看到外卖员到达你所在的位置的路线,它是如何规划出相关路线的呢?
|
||||
|
||||
在我们和电脑下围棋下五子棋的时候,他是如何“思考”的呢?希望你在阅读完本章内容之后,可以有一个最基本的理解。并且,我们还会给你留下一个井字棋的小任务,可以让你的电脑和你下井字棋,是不是很 cool
|
||||
|
||||
让我们现在开始吧!
|
||||
:::
|
||||
|
||||
# 基本定义
|
||||
## 基本定义
|
||||
|
||||
也许第一次看会觉得云里雾里,没有必要全部记住所有的概念。可以先大致浏览一遍之后,再后续的代码中与概念进行结合,相信你会有更深入的理解
|
||||
::: warning 🤔 也许第一次看会觉得云里雾里,没有必要全部记住所有的概念。可以先大致浏览一遍之后,再后续的代码中与概念进行结合,相信你会有更深入的理解
|
||||
:::
|
||||
|
||||
> 即检索存储在某个[数据结构](https://zh.wikipedia.org/wiki/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84)中的信息,或者在问题域的搜索空间中计算的信息。 --wiki
|
||||
|
||||
@@ -18,140 +20,164 @@
|
||||
|
||||
导航是使用搜索算法的一个典型的搜索,它接收您的当前位置和目的地作为输入,并根据搜索算法返回建议的路径。
|
||||
|
||||

|
||||

|
||||
|
||||
在计算机科学中,还有许多其他形式的搜索问题,比如谜题或迷宫。
|
||||
|
||||

|
||||
<table>
|
||||
<tr>
|
||||
<td><img src=https://cdn.xyxsw.site/SYw4bOzqAo65PQxZQLucbZAxnHd.png width=520></td>
|
||||
<td><img src=https://cdn.xyxsw.site/LPgEbVQg2oZBSexmGWwcwfbdnVd.png width=520></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||

|
||||
|
||||
# 举个例子
|
||||
## 举个例子
|
||||
|
||||
要找到一个数字华容道谜题的解决方案,需要使用搜索算法。
|
||||
|
||||
- 智能主体(Agent)
|
||||
- 智能主体 (Agent)
|
||||
|
||||
- 感知其环境并对该环境采取行动的实体。
|
||||
- 例如,在导航应用程序中,智能主体将是一辆汽车的代表,它需要决定采取哪些行动才能到达目的地。
|
||||
- 状态(State)
|
||||
感知其环境并对该环境采取行动的实体。
|
||||
|
||||
例如,在导航应用程序中,智能主体将是一辆汽车的代表,它需要决定采取哪些行动才能到达目的地。
|
||||
|
||||
- 状态 (State)
|
||||
|
||||
智能主体在其环境中的配置。
|
||||
|
||||
例如,在一个数字华容道谜题中,一个状态是所有数字排列在棋盘上的任何一种方式。
|
||||
|
||||
- 智能主体在其环境中的配置。
|
||||
- 例如,在一个数字华容道谜题中,一个状态是所有数字排列在棋盘上的任何一种方式。
|
||||
- 初始状态(Initial State)
|
||||
|
||||
- 搜索算法开始的状态。在导航应用程序中,这将是当前位置。
|
||||
搜索算法开始的状态。在导航应用程序中,这将是当前位置。
|
||||
|
||||

|
||||

|
||||
|
||||
- 动作(Action)
|
||||
- 动作 (Action)
|
||||
|
||||
- 一个状态可以做出的选择。更确切地说,动作可以定义为一个函数。当接收到状态$s$作为输入时,$Actions(s)$将返回可在状态$s$ 中执行的一组操作作为输出。
|
||||
- 例如,在一个数字华容道中,给定状态的操作是您可以在当前配置中滑动方块的方式。
|
||||
一个状态可以做出的选择。更确切地说,动作可以定义为一个函数。当接收到状态$s$作为输入时,$Actions(s)$将返回可在状态$s$ 中执行的一组操作作为输出。
|
||||
|
||||

|
||||
例如,在一个数字华容道中,给定状态的操作是您可以在当前配置中滑动方块的方式。
|
||||
|
||||
- 过渡模型(Transition Model)
|
||||

|
||||
|
||||
- 对在任何状态下执行任何适用操作所产生的状态的描述。
|
||||
- 更确切地说,过渡模型可以定义为一个函数。
|
||||
- 在接收到状态$s$和动作$a$作为输入时,$Results(s,a)$返回在状态$s$中执行动作$a$ 所产生的状态。
|
||||
- 例如,给定数字华容道的特定配置(状态$s$),在任何方向上移动正方形(动作$a$)将导致谜题的新配置(新状态)。
|
||||
- 过渡模型 (Transition Model)
|
||||
|
||||

|
||||
对在任何状态下执行任何适用操作所产生的状态的描述。
|
||||
|
||||
- 状态空间(State Space)
|
||||
更确切地说,过渡模型可以定义为一个函数。
|
||||
|
||||
- 通过一系列的操作目标从初始状态可达到的所有状态的集合。
|
||||
- 例如,在一个数字华容道谜题中,状态空间由所有$\frac{16!}{2}$种配置,可以从任何初始状态达到。状态空间可以可视化为有向图,其中状态表示为节点,动作表示为节点之间的箭头。
|
||||
在接收到状态$s$和动作$a$作为输入时,$Results(s,a)$返回在状态$s$中执行动作$a$ 所产生的状态。
|
||||
|
||||

|
||||
例如,给定数字华容道的特定配置(状态$s$),在任何方向上移动正方形(动作$a$)将导致谜题的新配置(新状态)。
|
||||
|
||||
- 目标测试(Goal Test)
|
||||

|
||||
|
||||
- 确定给定状态是否为目标状态的条件。例如,在导航应用程序中,目标测试将是智能主体的当前位置是否在目的地。如果是,问题解决了。如果不是,我们将继续搜索。
|
||||
- 路径成本(Path Cost)
|
||||
- 状态空间 (State Space)
|
||||
|
||||
- 完成给定路径相关的代价。例如,导航应用程序并不是简单地让你达到目标;它这样做的同时最大限度地减少了路径成本,为您找到了达到目标状态的最快方法。
|
||||
通过一系列的操作目标从初始状态可达到的所有状态的集合。
|
||||
|
||||
# 解决搜索问题
|
||||
例如,在一个数字华容道谜题中,状态空间由所有$\frac{16!}{2}$种配置,可以从任何初始状态达到。状态空间可以可视化为有向图,其中状态表示为节点,动作表示为节点之间的箭头。
|
||||
|
||||
- 解(solution)
|
||||

|
||||
|
||||
- 从初始状态到目标状态的一系列动作。
|
||||
- 最优解(Optimal Solution)
|
||||
- 目标测试 (Goal Test)
|
||||
|
||||
确定给定状态是否为目标状态的条件。例如,在导航应用程序中,目标测试将是智能主体的当前位置是否在目的地。如果是,问题解决了。如果不是,我们将继续搜索。
|
||||
|
||||
- 路径成本 (Path Cost)
|
||||
|
||||
完成给定路径相关的代价。例如,导航应用程序并不是简单地让你达到目标;它这样做的同时最大限度地减少了路径成本,为您找到了达到目标状态的最快方法。
|
||||
|
||||
## 解决搜索问题
|
||||
|
||||
### 解 (solution)
|
||||
|
||||
从初始状态到目标状态的一系列动作。
|
||||
|
||||
### 最优解 (Optimal Solution)
|
||||
|
||||
- 在所有解决方案中路径成本最低的解决方案。
|
||||
- 在搜索过程中,数据通常存储在<strong>节点(Node)</strong> 中,节点是一种包含以下数据的数据结构:
|
||||
- 在搜索过程中,数据通常存储在<strong>节点 (Node)</strong> 中,节点是一种包含以下数据的数据结构:
|
||||
|
||||
- 状态——state
|
||||
- 其父节点,通过该父节点生成当前节点——parent node
|
||||
- 应用于父级状态以获取当前节点的操作——action
|
||||
- 从初始状态到该节点的路径成本——path cost
|
||||
- 状态——state
|
||||
- 其父节点,通过该父节点生成当前节点——parent node
|
||||
- 应用于父级状态以获取当前节点的操作——action
|
||||
- 从初始状态到该节点的路径成本——path cost
|
||||
- 节点包含的信息使它们对于搜索算法非常有用。
|
||||
|
||||
它们包含一个状态,可以使用目标测试来检查该状态是否为最终状态。
|
||||
它们包含一个状态,可以使用目标测试来检查该状态是否为最终状态。
|
||||
|
||||
如果是,则可以将节点的路径成本与其他节点的路径代价进行比较,从而可以选择最佳解决方案。
|
||||
如果是,则可以将节点的路径成本与其他节点的路径代价进行比较,从而可以选择最佳解决方案。
|
||||
|
||||
一旦选择了节点,通过存储父节点和从父节点到当前节点的动作,就可以追溯从初始状态到该节点的每一步,而这一系列动作就是解决方案。
|
||||
一旦选择了节点,通过存储父节点和从父节点到当前节点的动作,就可以追溯从初始状态到该节点的每一步,而这一系列动作就是解决方案。
|
||||
|
||||
- 然而,节点只是一个数据结构——它们不搜索,而是保存信息。为了实际搜索,我们使用了边域(frontier),即“管理”节点的机制。边域首先包含一个初始状态和一组空的已探索项目(探索集),然后重复以下操作,直到找到解决方案:
|
||||
然而,节点只是一个数据结构——它们不搜索,而是保存信息。为了实际搜索,我们使用了边域 (frontier),即“管理”节点的机制。边域首先包含一个初始状态和一组空的已探索项目(探索集),然后重复以下操作,直到找到解决方案:
|
||||
|
||||
- 重复
|
||||
重复:
|
||||
|
||||
- 如果边域为空
|
||||
1. 如果边域为空
|
||||
- 停止,搜索问题无解
|
||||
2. 从边域中删除一个节点。这是将要考虑的节点。
|
||||
3. 如果节点包含目标状态。
|
||||
- 返回解决方案,停止
|
||||
否则:
|
||||
- 展开节点(找到可以从该节点到达的所有新节点),并将生成的节点添加到边域。
|
||||
- 将当前节点添加到探索集。
|
||||
|
||||
- 停止,搜索问题无解
|
||||
- 从边域中删除一个节点。这是将要考虑的节点。
|
||||
- 如果节点包含目标状态
|
||||
|
||||
- 返回解决方案,停止
|
||||
- 否则
|
||||
|
||||
- 展开节点(找到可以从该节点到达的所有新节点),并将生成的节点添加到边域。
|
||||
- 将当前节点添加到探索集。
|
||||
|
||||

|
||||
|
||||

|
||||
<table>
|
||||
<tr>
|
||||
<td><img src=https://cdn.xyxsw.site/K53FbGmswoM7JAxqJZxcQEjdnES.png width=520></td>
|
||||
<td><img src=https://cdn.xyxsw.site/THhpbemEHoxl80xHeTjc9d35nVh.png width=520></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
边域从节点 A 初始化开始
|
||||
|
||||
a. 取出边域中的节点 A,展开节点 A,将节点 B 添加到边域。
|
||||
b. 取出节点 B,展开,添加......
|
||||
c. 到达目标节点,停止,返回解决方案
|
||||
1. 取出边域中的节点 A,展开节点 A,将节点 B 添加到边域。
|
||||
2. 取出节点 B,展开,添加......
|
||||
3. 到达目标节点,停止,返回解决方案
|
||||
|
||||

|
||||
|
||||

|
||||
<table>
|
||||
<tr>
|
||||
<td><img src=https://cdn.xyxsw.site/XmnObIGaUoF4ssxkgzUc4vTUnmf.png width=520></td>
|
||||
<td><img src=https://cdn.xyxsw.site/Wsntb9rLwogdAKxpJgLchrI8nae.png width=520></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
会出现什么问题?节点 A-> 节点 B-> 节点 A->......-> 节点 A。我们需要一个探索集,记录已搜索的节点!
|
||||
|
||||
## 不知情搜索(Uninformed Search)
|
||||
### 不知情搜索 (Uninformed Search)
|
||||
|
||||
- 在之前对边域的描述中,有一件事没有被提及。在上面伪代码的第 1 阶段,应该删除哪个节点?这种选择对解决方案的质量和实现速度有影响。关于应该首先考虑哪些节点的问题,有多种方法,其中两种可以用堆栈(深度优先搜索)和队列(广度优先搜索)的数据结构来表示。
|
||||
- 深度优先搜索(Depth-First Search)
|
||||
在之前对边域的描述中,有一件事没有被提及。在上面伪代码的第 1 阶段,应该删除哪个节点?这种选择对解决方案的质量和实现速度有影响。关于应该首先考虑哪些节点的问题,有多种方法,其中两种可以用堆栈(深度优先搜索)和队列(广度优先搜索)的数据结构来表示。
|
||||
|
||||
- 深度优先搜索算法在尝试另一个方向之前耗尽每个方向。在这些情况下,边域作为堆栈数据结构进行管理。这里需要记住的流行语是“后进先出”。在将节点添加到边域后,第一个要删除和考虑的节点是最后一个要添加的节点。这导致了一种搜索算法,该算法在第一个方向上尽可能深入,直到尽头,同时将所有其他方向留到后面。“不撞南墙不回头”
|
||||
- (一个例子:以你正在寻找钥匙的情况为例。在深度优先搜索方法中,如果你选择从裤子里搜索开始,你会先仔细检查每一个口袋,清空每个口袋,仔细检查里面的东西。只有当你完全筋疲力尽时,你才会停止在裤子里搜索,开始在其他地方搜索。)
|
||||
- 优点
|
||||
#### 深度优先搜索 (Depth-First Search)
|
||||
|
||||
- 在最好的情况下,这个算法是最快的。如果它“运气好”,并且总是(偶然)选择正确的解决方案路径,那么深度优先搜索需要尽可能少的时间来找到解决方案。
|
||||
- 缺点
|
||||
深度优先搜索算法在尝试另一个方向之前耗尽每个方向。在这些情况下,边域作为堆栈数据结构进行管理。这里需要记住的流行语是“后进先出”。在将节点添加到边域后,第一个要删除和考虑的节点是最后一个要添加的节点。这导致了一种搜索算法,该算法在第一个方向上尽可能深入,直到尽头,同时将所有其他方向留到后面。“不撞南墙不回头”
|
||||
|
||||
- 所找到的解决方案可能不是最优的。
|
||||
- 在最坏的情况下,该算法将在找到解决方案之前探索每一条可能的路径,从而在到达解决方案之前花费尽可能长的时间。
|
||||
(一个例子:以你正在寻找钥匙的情况为例。在深度优先搜索方法中,如果你选择从裤子里搜索开始,你会先仔细检查每一个口袋,清空每个口袋,仔细检查里面的东西。只有当你完全筋疲力尽时,你才会停止在裤子里搜索,开始在其他地方搜索。)
|
||||
|
||||

|
||||
- 优点
|
||||
- 在最好的情况下,这个算法是最快的。如果它“运气好”,并且总是(偶然)选择正确的解决方案路径,那么深度优先搜索需要尽可能少的时间来找到解决方案。
|
||||
- 缺点
|
||||
- 所找到的解决方案可能不是最优的。
|
||||
- 在最坏的情况下,该算法将在找到解决方案之前探索每一条可能的路径,从而在到达解决方案之前花费尽可能长的时间。
|
||||
|
||||

|
||||
<table>
|
||||
<tr>
|
||||
<td><img src=https://cdn.xyxsw.site/SGVWbCcTlobQwJxSjKvcNyJAnEG.png width=520></td>
|
||||
<td><img src=https://cdn.xyxsw.site/Vv9Sb26QfoMrkqx5apycIYPJnlf.png width=520></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||

|
||||
<table>
|
||||
<tr>
|
||||
<td><img src=https://cdn.xyxsw.site/Gjd5bpdpcoIxGtxcUJ0c2OVfnOf.png width=520></td>
|
||||
<td><img src=https://cdn.xyxsw.site/M2vZbA5hpoT9RExuAGwcBHF1nmh.png width=520></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||

|
||||
|
||||
- 代码实现
|
||||
- 代码实现
|
||||
|
||||
```python
|
||||
def remove(self):
|
||||
@@ -163,27 +189,33 @@ def remove(self):
|
||||
return node
|
||||
```
|
||||
|
||||
- 广度优先搜索(Breadth-First Search)
|
||||
#### 广度优先搜索 (Breadth-First Search)
|
||||
|
||||
- 广度优先搜索算法将同时遵循多个方向,在每个可能的方向上迈出一步,然后在每个方向上迈出第二步。在这种情况下,边域作为队列数据结构进行管理。这里需要记住的流行语是“先进先出”。在这种情况下,所有新节点都会排成一行,并根据先添加的节点来考虑节点(先到先得!)。这导致搜索算法在任何一个方向上迈出第二步之前,在每个可能的方向上迈出一步。
|
||||
- (一个例子:假设你正在寻找钥匙。在这种情况下,如果你从裤子开始,你会看你的右口袋。之后,你会在一个抽屉里看一眼,而不是看你的左口袋。然后在桌子上。以此类推,在你能想到的每个地方。只有在你用完所有位置后,你才会回到你的裤子上,在下一个口袋里找。)
|
||||
- 优点
|
||||
广度优先搜索算法将同时遵循多个方向,在每个可能的方向上迈出一步,然后在每个方向上迈出第二步。在这种情况下,边域作为队列数据结构进行管理。这里需要记住的流行语是“先进先出”。在这种情况下,所有新节点都会排成一行,并根据先添加的节点来考虑节点(先到先得!)。这导致搜索算法在任何一个方向上迈出第二步之前,在每个可能的方向上迈出一步。
|
||||
|
||||
- 该算法可以保证找到最优解。
|
||||
- 缺点
|
||||
(一个例子:假设你正在寻找钥匙。在这种情况下,如果你从裤子开始,你会看你的右口袋。之后,你会在一个抽屉里看一眼,而不是看你的左口袋。然后在桌子上。以此类推,在你能想到的每个地方。只有在你用完所有位置后,你才会回到你的裤子上,在下一个口袋里找。)
|
||||
|
||||
- 几乎可以保证该算法的运行时间会比最短时间更长。
|
||||
- 在最坏的情况下,这种算法需要尽可能长的时间才能运行。
|
||||
- 优点
|
||||
- 该算法可以保证找到最优解。
|
||||
- 缺点
|
||||
- 几乎可以保证该算法的运行时间会比最短时间更长。
|
||||
- 在最坏的情况下,这种算法需要尽可能长的时间才能运行。
|
||||
|
||||

|
||||
<table>
|
||||
<tr>
|
||||
<td><img src=https://cdn.xyxsw.site/S6SRbMUrcoYQCYxZGgJczkdcnBP.png width=520></td>
|
||||
<td><img src=https://cdn.xyxsw.site/Xg7Qbv59IoQB3bxPFO1ceXgRnkf.png width=520></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||

|
||||
<table>
|
||||
<tr>
|
||||
<td><img src=https://cdn.xyxsw.site/X34Rb5R7AonUg3xYs7DcQzSfndg.png width=520></td>
|
||||
<td><img src=https://cdn.xyxsw.site/PQeZbJv3Bom6NYxa6lccT084nFn.png width=520></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
- 代码实现
|
||||
代码实现
|
||||
|
||||
```python
|
||||
def remove(self):
|
||||
@@ -195,80 +227,83 @@ def remove(self):
|
||||
return node
|
||||
```
|
||||
|
||||
## 知情搜索(Informed Search)
|
||||
## 知情搜索 (Informed Search)
|
||||
|
||||
- 广度优先和深度优先都是不知情的搜索算法。也就是说,这些算法没有利用他们没有通过自己的探索获得的关于问题的任何知识。然而,大多数情况下,关于这个问题的一些知识实际上是可用的。例如,当人类进入一个路口时,人类可以看到哪条路沿着解决方案的大致方向前进,哪条路没有。人工智能也可以这样做。一种考虑额外知识以试图提高性能的算法被称为知情搜索算法。
|
||||
- 贪婪最佳优先搜索(Greedy Best-First Search)
|
||||
广度优先和深度优先都是不知情的搜索算法。也就是说,这些算法没有利用他们没有通过自己的探索获得的关于问题的任何知识。然而,大多数情况下,关于这个问题的一些知识实际上是可用的。例如,当人类进入一个路口时,人类可以看到哪条路沿着解决方案的大致方向前进,哪条路没有。人工智能也可以这样做。一种考虑额外知识以试图提高性能的算法被称为知情搜索算法。
|
||||
|
||||
- 贪婪最佳优先搜索扩展最接近目标的节点,如启发式函数$h(n)$所确定的。顾名思义,该函数估计下一个节点离目标有多近,但可能会出错。贪婪最佳优先算法的效率取决于启发式函数的好坏。例如,在迷宫中,算法可以使用启发式函数,该函数依赖于可能节点和迷宫末端之间的曼哈顿距离。曼哈顿距离忽略了墙壁,并计算了从一个位置到目标位置需要向上、向下或向两侧走多少步。这是一个简单的估计,可以基于当前位置和目标位置的$(x,y)$坐标导出。
|
||||
### 贪婪最佳优先搜索 (Greedy Best-First Search)
|
||||
|
||||

|
||||
贪婪最佳优先搜索扩展最接近目标的节点,如启发式函数$h(n)$所确定的。顾名思义,该函数估计下一个节点离目标有多近,但可能会出错。贪婪最佳优先算法的效率取决于启发式函数的好坏。例如,在迷宫中,算法可以使用启发式函数,该函数依赖于可能节点和迷宫末端之间的曼哈顿距离。曼哈顿距离忽略了墙壁,并计算了从一个位置到目标位置需要向上、向下或向两侧走多少步。这是一个简单的估计,可以基于当前位置和目标位置的$(x,y)$坐标导出。
|
||||
|
||||
- 然而,重要的是要强调,与任何启发式算法一样,它可能会出错,并导致算法走上比其他情况下更慢的道路。不知情的搜索算法有可能更快地提供一个更好的解决方案,但它比知情算法更不可能这样。
|
||||

|
||||
|
||||

|
||||
然而,重要的是要强调,与任何启发式算法一样,它可能会出错,并导致算法走上比其他情况下更慢的道路。不知情的搜索算法有可能更快地提供一个更好的解决方案,但它比知情算法更不可能这样。
|
||||
|
||||

|
||||
<table>
|
||||
<tr>
|
||||
<td><img src=https://cdn.xyxsw.site/SU2DbQeN2oxs5ex3K3NcMaJfnch.png width=520></td>
|
||||
<td><img src=https://cdn.xyxsw.site/HkvdbcEdmo6RtjxOqqic31XFnSh.png width=520></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
- $A^*$搜索
|
||||
|
||||
- 作为贪婪最佳优先算法的一种发展,$A^*$搜索不仅考虑了从当前位置到目标的估计成本$h(n)$,还考虑了直到当前位置为止累积的成本$g(n)$。通过组合这两个值,该算法可以更准确地确定解决方案的成本并在旅途中优化其选择。该算法跟踪(到目前为止的路径成本+到目标的估计成本,$g(n)+h(n)$),一旦它超过了之前某个选项的估计成本,该算法将放弃当前路径并返回到之前的选项,从而防止自己沿着$h(n)$错误地标记为最佳的却长而低效的路径前进。
|
||||
|
||||
- 然而,由于这种算法也依赖于启发式,所以它依赖它所使用的启发式。在某些情况下,它可能比贪婪的最佳第一搜索甚至不知情的算法效率更低。对于最佳的$A^*$搜索,启发式函数$h(n)$应该:
|
||||
|
||||
- 可接受,从未高估真实成本。
|
||||
|
||||
- 一致性,这意味着从新节点到目标的估计路径成本加上从先前节点转换到该新节点的成本应该大于或等于先前节点到目标的估计路径成本。用方程的形式表示,$h(n)$是一致的,如果对于每个节点n$和后续节点n'$,从n$到$n'$的步长为c$,满足$h(n)≤h(n')+c$。
|
||||
### $A^*$搜索
|
||||
|
||||

|
||||
作为贪婪最佳优先算法的一种发展,$A^{*}$ 搜索不仅考虑了从当前位置到目标的估计成本 $h(n)$ ,还考虑了直到当前位置为止累积的成本 $g(n)$ 。通过组合这两个值,该算法可以更准确地确定解决方案的成本并在旅途中优化其选择。该算法跟踪(到目前为止的路径成本 + 到目标的估计成本, $g(n)+h(n)$ ),一旦它超过了之前某个选项的估计成本,该算法将放弃当前路径并返回到之前的选项,从而防止自己沿着 $h(n)$ 错误地标记为最佳的却长而低效的路径前进。
|
||||
|
||||

|
||||
然而,由于这种算法也依赖于启发式,所以它依赖它所使用的启发式。在某些情况下,它可能比贪婪的最佳第一搜索甚至不知情的算法效率更低。对于最佳的$A^*$搜索,启发式函数$h(n)$应该:
|
||||
|
||||
# 对抗性搜索
|
||||
- 可接受,从未高估真实成本。
|
||||
- 一致性,这意味着从新节点到目标的估计路径成本加上从先前节点转换到该新节点的成本应该大于或等于先前节点到目标的估计路径成本。用方程的形式表示,$h(n)$是一致的,如果对于每个节点 n$和后续节点 n'$,从 n$到$n'$的步长为 c$,满足$h(n) ≤ h(n') + c$.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src=https://cdn.xyxsw.site/BbIiba1pwo3uI7x4k7QcwicznGc.png width=520></td>
|
||||
<td><img src=https://cdn.xyxsw.site/HhG9bcJP2okKMMxY0FGclP0AnXY.png width=520></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## 对抗性搜索
|
||||
|
||||
尽管之前我们讨论过需要找到问题答案的算法,但在对抗性搜索中,算法面对的是试图实现相反目标的对手。通常,在游戏中会遇到使用对抗性搜索的人工智能,比如井字游戏。
|
||||
|
||||
- 极大极小算法(Minimax)
|
||||
### 极大极小算法 (Minimax)
|
||||
|
||||
- 作为对抗性搜索中的一种算法,Minimax 将获胜条件表示为$(-1)$表示为一方,$(+1)$表示为另一方。进一步的行动将受到这些条件的驱动,最小化的一方试图获得最低分数,而最大化的一方则试图获得最高分数。
|
||||
|
||||

|
||||
|
||||
- 井字棋 AI 为例
|
||||
|
||||
- $s_0$: 初始状态(在我们的情况下,是一个空的3X3棋盘)
|
||||
|
||||

|
||||
- 作为对抗性搜索中的一种算法,Minimax 将获胜条件表示为$(-1)$表示为一方,$(+1)$表示为另一方。进一步的行动将受到这些条件的驱动,最小化的一方试图获得最低分数,而最大化的一方则试图获得最高分数。
|
||||
|
||||
- $Players(s)$: 一个函数,在给定状态$$s$$的情况下,返回轮到哪个玩家(X或O)。
|
||||
|
||||

|
||||
|
||||
- $Actions(s)$: 一个函数,在给定状态$$s$$的情况下,返回该状态下的所有合法动作(棋盘上哪些位置是空的)。
|
||||
|
||||

|
||||
|
||||
- $Result(s, a)$: 一个函数,在给定状态$$s$$和操作$$a$$的情况下,返回一个新状态。这是在状态$$s$$上执行动作$$a$$(在游戏中移动)所产生的棋盘。
|
||||
|
||||

|
||||
|
||||
- $Terminal(s)$: 一个函数,在给定状态$$s$$的情况下,检查这是否是游戏的最后一步,即是否有人赢了或打成平手。如果游戏已结束,则返回True,否则返回False。
|
||||
|
||||

|
||||
|
||||
- $Utility(s)$: 一个函数,在给定终端状态s的情况下,返回状态的效用值:$$-1、0或1$$。
|
||||
|
||||
|
||||

|
||||
|
||||

|
||||
#### 井字棋 AI 为例
|
||||
|
||||
- 算法的工作原理:
|
||||
- $s_0$: 初始状态(在我们的情况下,是一个空的 3X3 棋盘)
|
||||
|
||||
- 该算法递归地模拟从当前状态开始直到达到终端状态为止可能发生的所有游戏状态。每个终端状态的值为$(-1)$、$0$或$(+1)$。
|
||||

|
||||
|
||||

|
||||
- $Players(s)$: 一个函数,在给定状态$s$的情况下,返回轮到哪个玩家(X 或 O)。
|
||||
|
||||
- 根据轮到谁的状态,算法可以知道当前玩家在最佳游戏时是否会选择导致状态值更低或更高的动作。
|
||||

|
||||
|
||||
- $Actions(s)$: 一个函数,在给定状态$s$的情况下,返回该状态下的所有合法动作(棋盘上哪些位置是空的)。
|
||||
|
||||

|
||||
|
||||
- $Result(s, a)$: 一个函数,在给定状态$s$和操作$a$的情况下,返回一个新状态。这是在状态$s$上执行动作$a$(在游戏中移动)所产生的棋盘。
|
||||
|
||||

|
||||
|
||||
- $Terminal(s)$: 一个函数,在给定状态$s$的情况下,检查这是否是游戏的最后一步,即是否有人赢了或打成平手。如果游戏已结束,则返回 True,否则返回 False。
|
||||
|
||||

|
||||
|
||||
- $Utility(s)$: 一个函数,在给定终端状态 s 的情况下,返回状态的效用值:$-1、0 或 1$。
|
||||
|
||||

|
||||
|
||||
算法的工作原理:
|
||||
|
||||
- 该算法递归地模拟从当前状态开始直到达到终端状态为止可能发生的所有游戏状态。每个终端状态的值为$(-1)$、$0$或$(+1)$。
|
||||

|
||||
|
||||
- 根据轮到谁的状态,算法可以知道当前玩家在最佳游戏时是否会选择导致状态值更低或更高的动作。
|
||||
|
||||
通过这种方式,在最小化和最大化之间交替,算法为每个可能的动作产生的状态创建值。举一个更具体的例子,我们可以想象,最大化的玩家在每一个回合都会问:“如果我采取这个行动,就会产生一个新的状态。如果最小化的玩家发挥得最好,那么该玩家可以采取什么行动来达到最低值?”
|
||||
|
||||
@@ -278,42 +313,43 @@ def remove(self):
|
||||
|
||||
在得到这些值之后,最大化的玩家会选择最高的一个。
|
||||
|
||||

|
||||

|
||||
|
||||
- 具体算法:
|
||||
具体算法:
|
||||
|
||||
- 给定状态 $s$
|
||||
- 给定状态 $s$
|
||||
- 最大化玩家在$Actions(s)$中选择动作$a$,该动作产生$Min-value(Result(s,a))$ 的最高值。
|
||||
- 最小化玩家在$Actions(s)$中选择动作$a$,该动作产生$Max-value(Result(s,a))$ 的最小值。
|
||||
|
||||
- 最大化玩家在$Actions(s)$中选择动作$a$,该动作产生$Min-value(Result(s,a))$ 的最高值。
|
||||
- 最小化玩家在$Actions(s)$中选择动作$a$,该动作产生$Max-value(Result(s,a))$ 的最小值。
|
||||
```txt
|
||||
Function Max-Value(state):
|
||||
v=-∞
|
||||
if Terminal(state):
|
||||
return Utility(state)
|
||||
for action in Actions(state):
|
||||
v = Max(v, Min-Value(Result(state, action)))
|
||||
return v
|
||||
Function Min-Value(state):
|
||||
v=+∞
|
||||
if Terminal(state):
|
||||
return Utility(state)
|
||||
for action in Actions(state):
|
||||
v = Min(v, Max-Value(Result(state, action)))
|
||||
return v
|
||||
```
|
||||
|
||||
- Function Max-Value(state):
|
||||
- $$v=-\infty$$
|
||||
- if $Terminal(state)$:
|
||||
- return $Utility(state)$
|
||||
- for $action$ in $Actions(state)$:
|
||||
- $$v = Max(v, Min-Value(Result(state, action)))$$
|
||||
- return $v$
|
||||
- Function Min-Value(state):
|
||||
- $$v=\infty$$
|
||||
- if $Terminal(state)$:
|
||||
- return $Utility(state)$
|
||||
- for $action$ in $Actions(state)$:
|
||||
- $$v = Min(v, Max-Value(Result(state, action)))$$
|
||||
- return $v$
|
||||
不会理解递归?也许你需要看看这个:[阶段二:递归操作](../3.%E7%BC%96%E7%A8%8B%E6%80%9D%E7%BB%B4%E4%BD%93%E7%B3%BB%E6%9E%84%E5%BB%BA/3.6.4.2%E9%98%B6%E6%AE%B5%E4%BA%8C%EF%BC%9A%E9%80%92%E5%BD%92%E6%93%8D%E4%BD%9C.md)
|
||||
|
||||
不会理解递归?也许你需要看看这个:[阶段二:递归操作](../3.%E7%BC%96%E7%A8%8B%E6%80%9D%E7%BB%B4%E4%BD%93%E7%B3%BB%E6%9E%84%E5%BB%BA/3.6.4.2%E9%98%B6%E6%AE%B5%E4%BA%8C%EF%BC%9A%E9%80%92%E5%BD%92%E6%93%8D%E4%BD%9C.md)
|
||||
### $\alpha$-$\beta$剪枝 (Alpha-Beta Pruning)
|
||||
|
||||
- $\alpha$-$\beta$剪枝(Alpha-Beta Pruning)
|
||||
作为一种优化 Minimax 的方法,Alpha-Beta 剪枝跳过了一些明显不利的递归计算。在确定了一个动作的价值后,如果有初步证据表明接下来的动作可以让对手获得比已经确定的动作更好的分数,那么就没有必要进一步调查这个动作,因为它肯定比之前确定的动作不利。
|
||||
|
||||
- 作为一种优化Minimax的方法,Alpha-Beta剪枝跳过了一些明显不利的递归计算。在确定了一个动作的价值后,如果有初步证据表明接下来的动作可以让对手获得比已经确定的动作更好的分数,那么就没有必要进一步调查这个动作,因为它肯定比之前确定的动作不利。
|
||||
|
||||
- 这一点最容易用一个例子来说明:最大化的玩家知道,在下一步,最小化的玩家将试图获得最低分数。假设最大化玩家有三个可能的动作,第一个动作的值为4。然后玩家开始为下一个动作生成值。要做到这一点,如果当前玩家做出这个动作,玩家会生成最小化者动作的值,并且知道最小化者会选择最低的一个。然而,在完成最小化器所有可能动作的计算之前,玩家会看到其中一个选项的值为3。这意味着没有理由继续探索最小化玩家的其他可能行动。尚未赋值的动作的值无关紧要,无论是10还是(-10)。如果该值为10,则最小化器将选择最低选项3,该选项已经比预先设定的4差。如果尚未估价的行动结果是(-10),那么最小化者将选择(-10)这一选项,这对最大化者来说更加不利。因此,在这一点上为最小化者计算额外的可能动作与最大化者无关,因为最大化玩家已经有了一个明确的更好的选择,其值为4。
|
||||
这一点最容易用一个例子来说明:最大化的玩家知道,在下一步,最小化的玩家将试图获得最低分数。假设最大化玩家有三个可能的动作,第一个动作的值为 4。然后玩家开始为下一个动作生成值。要做到这一点,如果当前玩家做出这个动作,玩家会生成最小化者动作的值,并且知道最小化者会选择最低的一个。然而,在完成最小化器所有可能动作的计算之前,玩家会看到其中一个选项的值为 3。这意味着没有理由继续探索最小化玩家的其他可能行动。尚未赋值的动作的值无关紧要,无论是 10 还是(-10)。如果该值为 10,则最小化器将选择最低选项 3,该选项已经比预先设定的 4 差。如果尚未估价的行动结果是(-10),那么最小化者将选择(-10)这一选项,这对最大化者来说更加不利。因此,在这一点上为最小化者计算额外的可能动作与最大化者无关,因为最大化玩家已经有了一个明确的更好的选择,其值为 4。
|
||||
|
||||

|
||||

|
||||
|
||||
- 深度限制的极大极小算法(Depth-Limited Minimax)
|
||||
### 深度限制的极大极小算法 (Depth-Limited Minimax)
|
||||
|
||||
- 总共有$255168$个可能的井字棋游戏,以及有$10^{29000}$个可能的国际象棋中游戏。到目前为止,最小最大算法需要生成从某个点到<strong>终端条件</strong>的所有假设游戏状态。虽然计算所有的井字棋游戏状态对现代计算机来说并不是一个挑战,但目前用来计算国际象棋是不可能的。
|
||||
|
||||
- 深度限制的 Minimax 算法在停止之前只考虑预先定义的移动次数,而从未达到终端状态。然而,这不允许获得每个动作的精确值,因为假设的游戏还没有结束。为了解决这个问题,深度限制 Minimax 依赖于一个评估函数,该函数从给定状态估计游戏的预期效用,或者换句话说,为状态赋值。例如,在国际象棋游戏中,效用函数会将棋盘的当前配置作为输入,尝试评估其预期效用(基于每个玩家拥有的棋子及其在棋盘上的位置),然后返回一个正值或负值,表示棋盘对一个玩家对另一个玩家的有利程度。这些值可以用来决定正确的操作,并且评估函数越好,依赖它的 Minimax 算法就越好。
|
||||
深度限制的 Minimax 算法在停止之前只考虑预先定义的移动次数,而从未达到终端状态。然而,这不允许获得每个动作的精确值,因为假设的游戏还没有结束。为了解决这个问题,深度限制 Minimax 依赖于一个评估函数,该函数从给定状态估计游戏的预期效用,或者换句话说,为状态赋值。例如,在国际象棋游戏中,效用函数会将棋盘的当前配置作为输入,尝试评估其预期效用(基于每个玩家拥有的棋子及其在棋盘上的位置),然后返回一个正值或负值,表示棋盘对一个玩家对另一个玩家的有利程度。这些值可以用来决定正确的操作,并且评估函数越好,依赖它的 Minimax 算法就越好。
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# 程序示例——命题逻辑与模型检测
|
||||
|
||||
::: warning 😋
|
||||
阅读程序中涉及命题逻辑的部分,然后“玩一玩”程序!
|
||||
|
||||
@@ -6,9 +7,10 @@
|
||||
:::
|
||||
|
||||
::: tip 📥
|
||||
本节附件下载 <Download url="https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/code/2-Lecture.zip"/>
|
||||
本节附件下载 <Download url="https://cdn.xyxsw.site/code/2-Lecture.zip"/>
|
||||
:::
|
||||
# Sentence——父类
|
||||
|
||||
## Sentence——父类
|
||||
|
||||
```python
|
||||
class Sentence(): # 父类
|
||||
@@ -21,12 +23,12 @@ class Sentence(): # 父类
|
||||
def symbols(self):
|
||||
"""返回逻辑表达式中所有命题符号的集合。"""
|
||||
return set()
|
||||
@classmethod # @classmethod装饰器 使得类方法可以在类上被调用 Sentence.validate(...)
|
||||
@classmethod # @classmethod 装饰器 使得类方法可以在类上被调用 Sentence.validate(...)
|
||||
def validate(cls, sentence):
|
||||
"""验证操作数是否是Sentence或其子类"""
|
||||
"""验证操作数是否是 Sentence 或其子类"""
|
||||
if not isinstance(sentence, Sentence):
|
||||
raise TypeError("must be a logical sentence")
|
||||
@classmethod # @classmethod装饰器 使得类方法可以在类上被调用 Sentence.parenthesize(...)
|
||||
@classmethod # @classmethod 装饰器 使得类方法可以在类上被调用 Sentence.parenthesize(...)
|
||||
def parenthesize(cls, s):
|
||||
"""如果表达式尚未加圆括号,则加圆括号。"""
|
||||
def balanced(s):
|
||||
@@ -46,7 +48,7 @@ class Sentence(): # 父类
|
||||
return f"({s})"
|
||||
```
|
||||
|
||||
# Symbol——命题符号类
|
||||
## Symbol——命题符号类
|
||||
|
||||
```python
|
||||
class Symbol(Sentence):
|
||||
@@ -71,12 +73,12 @@ class Symbol(Sentence):
|
||||
return {self.name}
|
||||
```
|
||||
|
||||
# Not——逻辑非类
|
||||
## Not——逻辑非类
|
||||
|
||||
```python
|
||||
class Not(Sentence):
|
||||
def __init__(self, operand):
|
||||
"""验证操作数是否是Sentence或其子类"""
|
||||
"""验证操作数是否是 Sentence 或其子类"""
|
||||
Sentence.validate(operand)
|
||||
self.operand = operand
|
||||
def __eq__(self, other):
|
||||
@@ -94,13 +96,13 @@ class Not(Sentence):
|
||||
return self.operand.symbols()
|
||||
```
|
||||
|
||||
# And——逻辑乘类
|
||||
## And——逻辑乘类
|
||||
|
||||
```python
|
||||
class And(Sentence):
|
||||
def __init__(self, *conjuncts):
|
||||
for conjunct in conjuncts:
|
||||
"""验证操作数是否是Sentence或其子类"""
|
||||
"""验证操作数是否是 Sentence 或其子类"""
|
||||
Sentence.validate(conjunct)
|
||||
self.conjuncts = list(conjuncts)
|
||||
def __eq__(self, other):
|
||||
@@ -124,13 +126,13 @@ class And(Sentence):
|
||||
return set.union(*[conjunct.symbols() for conjunct in self.conjuncts])
|
||||
```
|
||||
|
||||
# Or——逻辑和类
|
||||
## Or——逻辑和类
|
||||
|
||||
```python
|
||||
class Or(Sentence):
|
||||
def __init__(self, *disjuncts):
|
||||
for disjunct in disjuncts:
|
||||
"""验证操作数是否是Sentence或其子类"""
|
||||
"""验证操作数是否是 Sentence 或其子类"""
|
||||
Sentence.validate(disjunct)
|
||||
self.disjuncts = list(disjuncts)
|
||||
def __eq__(self, other):
|
||||
@@ -151,12 +153,12 @@ class Or(Sentence):
|
||||
return set.union(*[disjunct.symbols() for disjunct in self.disjuncts])
|
||||
```
|
||||
|
||||
# Implication——逻辑蕴含类
|
||||
## Implication——逻辑蕴含类
|
||||
|
||||
```python
|
||||
class Implication(Sentence):
|
||||
def __init__(self, antecedent, consequent):
|
||||
"""验证操作数是否是Sentence或其子类"""
|
||||
"""验证操作数是否是 Sentence 或其子类"""
|
||||
Sentence.validate(antecedent)
|
||||
Sentence.validate(consequent)
|
||||
"""前件"""
|
||||
@@ -183,12 +185,12 @@ class Implication(Sentence):
|
||||
return set.union(self.antecedent.symbols(), self.consequent.symbols())
|
||||
```
|
||||
|
||||
# Biconditional——逻辑等值类
|
||||
## Biconditional——逻辑等值类
|
||||
|
||||
```python
|
||||
class Biconditional(Sentence):
|
||||
def __init__(self, left, right):
|
||||
"""验证操作数是否是Sentence或其子类"""
|
||||
"""验证操作数是否是 Sentence 或其子类"""
|
||||
Sentence.validate(left)
|
||||
Sentence.validate(right)
|
||||
self.left = left
|
||||
@@ -215,7 +217,7 @@ class Biconditional(Sentence):
|
||||
return set.union(self.left.symbols(), self.right.symbols())
|
||||
```
|
||||
|
||||
# Model_check()——模型检测算法
|
||||
## Model_check()——模型检测算法
|
||||
|
||||
```python
|
||||
def model_check(knowledge, query):
|
||||
@@ -234,7 +236,7 @@ def model_check(knowledge, query):
|
||||
def check_all(knowledge, query, symbols, model):
|
||||
"""检查给定特定模型的知识库是否推理蕴含查询结论。"""
|
||||
# 如果模型已经为所有的命题符号赋值
|
||||
if not symbols: # symbols为空即所有 symbols都在模型中被赋值
|
||||
if not symbols: # symbols 为空即所有 symbols 都在模型中被赋值
|
||||
# 若模型中的知识库为真,则查询结论也必须为真
|
||||
if knowledge.evaluate(model):
|
||||
return query.evaluate(model)
|
||||
@@ -244,10 +246,10 @@ def model_check(knowledge, query):
|
||||
# 选择其余未使用的命题符号之一
|
||||
remaining = symbols.copy()
|
||||
p = remaining.pop()
|
||||
# 创建一个命题符号为true的模型
|
||||
# 创建一个命题符号为 true 的模型
|
||||
model_true = model.copy()
|
||||
model_true[p] = True
|
||||
# 创建一个命题符号为false的模型
|
||||
# 创建一个命题符号为 false 的模型
|
||||
model_false = model.copy()
|
||||
model_false[p] = False
|
||||
# 确保在两种模型中都进行蕴含推理
|
||||
@@ -259,7 +261,7 @@ def model_check(knowledge, query):
|
||||
return check_all(knowledge, query, symbols, dict())
|
||||
```
|
||||
|
||||
# 线索游戏
|
||||
## 线索游戏
|
||||
|
||||
在游戏中,一个人在某个地点使用工具实施了谋杀。人、工具和地点用卡片表示。每个类别的一张卡片被随机挑选出来,放在一个信封里,由参与者来揭开真相。参与者通过揭开卡片并从这些线索中推断出信封里必须有什么来做到这一点。我们将使用之前的模型检查算法来揭开这个谜团。在我们的模型中,我们将已知与谋杀有关的项目标记为 True,否则标记为 False。
|
||||
|
||||
@@ -287,7 +289,7 @@ def check_knowledge(knowledge):
|
||||
if model_check(knowledge, symbol):
|
||||
termcolor.cprint(f"{symbol}: YES", "green")
|
||||
elif not model_check(knowledge, Not(symbol)):
|
||||
# 模型检测无法确定知识库可以得出 Not(symbol) 即 symbol是可能的
|
||||
# 模型检测无法确定知识库可以得出 Not(symbol) 即 symbol 是可能的
|
||||
print(f"{symbol}: MAYBE")
|
||||
else:
|
||||
termcolor.cprint(f"{symbol}: No", "red")
|
||||
@@ -311,21 +313,21 @@ knowledge.add(Not(ballroom))
|
||||
check_knowledge(knowledge)
|
||||
```
|
||||
|
||||
# Mastermind 游戏
|
||||
## Mastermind 游戏
|
||||
|
||||
在这个游戏中,玩家一按照一定的顺序排列颜色,然后玩家二必须猜测这个顺序。每一轮,玩家二进行猜测,玩家一返回一个数字,指示玩家二正确选择了多少颜色。让我们用四种颜色模拟一个游戏。假设玩家二猜测以下顺序:
|
||||
|
||||

|
||||

|
||||
|
||||
玩家一回答“二”。因此,我们知道其中一些两种颜色位于正确的位置,而另两种颜色则位于错误的位置。根据这些信息,玩家二试图切换两种颜色的位置。
|
||||
|
||||

|
||||

|
||||
|
||||
现在玩家一回答“零”。因此,玩家二知道切换后的颜色最初位于正确的位置,这意味着未被切换的两种颜色位于错误的位置。玩家二切换它们。
|
||||
|
||||

|
||||

|
||||
|
||||
在命题逻辑中表示这一点需要我们有(颜色的数量)$^2$个原子命题。所以,在四种颜色的情况下,我们会有命题 red0,red1,red2,red3,blue0…代表颜色和位置。下一步是用命题逻辑表示游戏规则(每个位置只有一种颜色,没有颜色重复),并将它们添加到知识库中。最后一步是将我们所拥有的所有线索添加到知识库中。在我们的案例中,我们会补充说,在第一次猜测中,两个位置是错误的,两个是正确的,而在第二次猜测中没有一个是对的。利用这些知识,模型检查算法可以为我们提供难题的解决方案。
|
||||
在命题逻辑中表示这一点需要我们有 (颜色的数量)$^2$个原子命题。所以,在四种颜色的情况下,我们会有命题 red0,red1,red2,red3,blue0…代表颜色和位置。下一步是用命题逻辑表示游戏规则(每个位置只有一种颜色,没有颜色重复),并将它们添加到知识库中。最后一步是将我们所拥有的所有线索添加到知识库中。在我们的案例中,我们会补充说,在第一次猜测中,两个位置是错误的,两个是正确的,而在第二次猜测中没有一个是对的。利用这些知识,模型检查算法可以为我们提供难题的解决方案。
|
||||
|
||||
```python
|
||||
from logic import *
|
||||
@@ -379,9 +381,9 @@ for symbol in symbols:
|
||||
print(symbol)
|
||||
```
|
||||
|
||||
# Quiz
|
||||
## Quiz
|
||||
|
||||
1. 下面的问题将问你关于以下逻辑句子的问题。 1.如果 Hermione 在图书馆,那么 Harry 在图书馆。 2.Hermione 在图书馆里。 3.Ron 在图书馆,Ron 不在图书馆。 4.Harry 在图书馆。 5.Harry 不在图书馆,或者 Hermione 在图书馆。 6.Rom 在图书馆,或者 Hermione 在图书馆。
|
||||
1. 下面的问题将问你关于以下逻辑句子的问题。1.如果 Hermione 在图书馆,那么 Harry 在图书馆。2.Hermione 在图书馆里。3.Ron 在图书馆,Ron 不在图书馆。4.Harry 在图书馆。5.Harry 不在图书馆,或者 Hermione 在图书馆。6.Rom 在图书馆,或者 Hermione 在图书馆。
|
||||
|
||||
以下哪一个逻辑蕴含推理是正确的?
|
||||
|
||||
@@ -395,21 +397,21 @@ for symbol in symbols:
|
||||
2. 除了讲义上讨论的连接词之外,还有其他的逻辑连接词。其中最常见的是“异或”(用符号$\oplus$表示)。表达式$A\oplus B$表示句子“A 或 B,但不是两者都有。”以下哪一个在逻辑上等同于$A\oplus B$?
|
||||
1. $(A ∨ B) ∧ ¬ (A ∨ B)$
|
||||
2. $(A ∨ B) ∧ (A ∧ B)$
|
||||
3. $(A ∨ B) ∧ ¬ (A ∧ B)$
|
||||
4. $(A ∧ B) ∨ ¬ (A ∨ B)$
|
||||
3. $(A ∨ B) ∧ ¬ (A ∧ B)$
|
||||
4. $(A ∧ B) ∨ ¬ (A ∨ B)$
|
||||
|
||||
3. 设命题变量$R$为“今天下雨”,变量$C$为“今天多云”,变量$S$ 为“今天晴”。下面哪一个是“如果今天下雨,那么今天多云但不是晴天”这句话的命题逻辑表示?
|
||||
3. 设命题变量$R$为“今天下雨”,变量$C$为“今天多云”,变量$S$ 为“今天晴”。下面哪一个是“如果今天下雨,那么今天多云但不是晴天”这句话的命题逻辑表示?
|
||||
|
||||
1. $(R → C) ∧ ¬S$
|
||||
2. $R → C → ¬S$
|
||||
3. $R ∧ C ∧ ¬S$
|
||||
4. $R → (C ∧ ¬S)$
|
||||
5. $(C ∨ ¬S) → R$
|
||||
1. $(R → C) ∧ ¬S$
|
||||
2. $R → C → ¬S$
|
||||
3. $R ∧ C ∧ ¬S$
|
||||
4. $R → (C ∧ ¬S)$
|
||||
5. $(C ∨ ¬S) → R$
|
||||
|
||||
4. 在一阶逻辑中,考虑以下谓词符号。$Student(x)$表示“x 是学生”的谓词。$Course(x)$代表“x 是课程”的谓词,$Enrolled(x,y)$表示“x 注册了 y”的谓词以下哪一项是“有一门课程是 Harry 和 Hermione 都注册的”这句话的一阶逻辑翻译?
|
||||
1. $∀x(Course(x)∧Enrolled(Harry, x) ∧ Enrolled(Hermione, x))$
|
||||
2. $∀x(Enrolled(Harry, x) ∨ Enrolled(Hermione, x))$
|
||||
3. $∀x(Enrolled(Harry, x) ∧ ∀y Enrolled(Hermione, y))$
|
||||
4. $∃xEnrolled(Harry, x) ∧ ∃y Enrolled(Hermione, y)$
|
||||
5. $∃x(Course(x) ∧ Enrolled(Harry, x) ∧ Enrolled(Hermione, x))$
|
||||
6. $∃x(Enrolled(Harry, x) ∨ Enrolled(Hermione, x))$
|
||||
4. 在一阶逻辑中,考虑以下谓词符号。$Student(x)$表示“x 是学生”的谓词。$Course(x)$代表“x 是课程”的谓词,$Enrolled(x,y)$表示“x 注册了 y”的谓词以下哪一项是“有一门课程是 Harry 和 Hermione 都注册的”这句话的一阶逻辑翻译?
|
||||
1. $∀x(Course(x)∧Enrolled(Harry, x) ∧ Enrolled(Hermione, x))$
|
||||
2. $∀x(Enrolled(Harry, x) ∨ Enrolled(Hermione, x))$
|
||||
3. $∀x(Enrolled(Harry, x) ∧ ∀y Enrolled(Hermione, y))$
|
||||
4. $∃xEnrolled(Harry, x) ∧ ∃y Enrolled(Hermione, y)$
|
||||
5. $∃x(Course(x) ∧ Enrolled(Harry, x) ∧ Enrolled(Hermione, x))$
|
||||
6. $∃x(Enrolled(Harry, x) ∨ Enrolled(Hermione, x))$
|
||||
|
||||
@@ -1,106 +1,124 @@
|
||||
# 项目:扫雷,骑士与流氓问题
|
||||
|
||||
我们为你提供了两个简单有趣的项目,帮助你进行知识巩固,请认真阅读文档内容。
|
||||
::: warning 😋 我们为你提供了两个简单有趣的项目,帮助你进行知识巩固,请认真阅读文档内容。
|
||||
|
||||
如果你卡住了,请记得回来阅读文档,或请求身边人的帮助。
|
||||
:::
|
||||
|
||||
::: tip 📥
|
||||
本节附件下载 <Download url="https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/code/2-Projects.zip"/>
|
||||
本节附件下载 <Download url="https://cdn.xyxsw.site/code/2-Projects.zip"/>
|
||||
:::
|
||||
|
||||
`pip3 install -r requirements.txt`
|
||||
|
||||
# 骑士与流氓问题
|
||||
## 骑士与流氓问题
|
||||
|
||||
## 背景
|
||||
### 背景
|
||||
|
||||
- 在 1978 年,逻辑学家雷蒙德·斯穆里安(Raymond Smullyan)出版了《这本书叫什么名字?》,这是一本逻辑难题的书。在书中的谜题中,有一类谜题被斯穆里安称为“骑士与流氓”谜题。
|
||||
- 在骑士与流氓谜题中,给出了以下信息:每个角色要么是骑士,要么是流氓。骑士总是会说实话:如果骑士陈述了一句话,那么这句话就是真的。相反,流氓总是说谎:如果流氓陈述了一个句子,那么这个句子就是假的。
|
||||
- 谜题的目标是,给出每个角色说的一组句子,确定每个角色是骑士还是流氓。
|
||||
- 比如,这里有一个简单的谜题只有一个名为 A 的角色。A 说:“我既是骑士又是流氓。”
|
||||
- 从逻辑上讲,我们可以推断,如果 A 是骑士,那么这句话一定是真的。但我们知道这句话不可能是真的,因为 A 不可能既是骑士又是流氓——我们知道每个角色要么是骑士,要么是流氓,不会出现是流氓的骑士或是骑士的流氓。所以,我们可以得出结论,A 一定是流氓。
|
||||
- 那个谜题比较简单。随着更多的字符和更多的句子,谜题可以变得更加棘手!你在这个问题中的任务是确定如何使用命题逻辑来表示这些谜题,这样一个运行模型检查算法的人工智能可以为我们解决这些谜题。
|
||||
在 1978 年,逻辑学家雷蒙德·斯穆里安(Raymond Smullyan)出版了《这本书叫什么名字?》,这是一本逻辑难题的书。在书中的谜题中,有一类谜题被斯穆里安称为“骑士与流氓”谜题。
|
||||
|
||||
## 理解
|
||||
在骑士与流氓谜题中,给出了以下信息:每个角色要么是骑士,要么是流氓。骑士总是会说实话:如果骑士陈述了一句话,那么这句话就是真的。相反,流氓总是说谎:如果流氓陈述了一个句子,那么这个句子就是假的。
|
||||
|
||||
- 看一下 `logic.py`,你可能还记得讲义的内容。无需了解此文件中的所有内容,但请注意,此文件为不同类型的逻辑连接词定义了多个类。这些类可以相互组合,所以表达式 `And(Not(A), Or(B, C))` 代表逻辑语句:命题 A 是不正确的,同时,命题 B 或者命题 C 是正确的。(这里的“或”是同或,不是异或)
|
||||
- 回想一下 `logic.py`,它还包含一个 函数 `model_check` 。`model_check` 输入知识库和查询结论。知识库是一个逻辑命题:如果知道多个逻辑语句,则可以将它们连接在一个表达式中。 递归考虑所有可能的模型,如果知识库推理蕴含查询结论,则返回 `True`,否则返回 `False`。
|
||||
- 现在,看看 `puzzle.py`,在顶部,我们定义了六个命题符号。例如,`AKnight` 表示“A 是骑士”的命题,`AKnave` 而表示“A 是流氓”的句子。我们也为字符 B 和 C 定义了类似的命题符号。
|
||||
- 接下来是四个不同的知识库 `knowledge0`, `knowledge1`, `knowledge2`, and `knowledge3`,它们将分别包含推断即将到来的谜题 0、1、2 和 3 的解决方案所需的知识。请注意,目前,这些知识库中的每一个都是空的。这就是你进来的地方!
|
||||
- 这个 `puzzle.py` 的 `main` 函数在所有谜题上循环,并使用模型检查来计算,给定谜题的知识,无论每个角色是骑士还是无赖,打印出模型检查算法能够得出的任何结论。
|
||||
谜题的目标是,给出每个角色说的一组句子,确定每个角色是骑士还是流氓。
|
||||
|
||||
## 明确
|
||||
比如,这里有一个简单的谜题只有一个名为 A 的角色。A 说:“我既是骑士又是流氓。”
|
||||
|
||||
- 将知识添加到知识库 `knowledge0`, `knowledge1`, `knowledge2`, 和 `knowledge3` 中,以解决以下难题。
|
||||
从逻辑上讲,我们可以推断,如果 A 是骑士,那么这句话一定是真的。但我们知道这句话不可能是真的,因为 A 不可能既是骑士又是流氓——我们知道每个角色要么是骑士,要么是流氓,不会出现是流氓的骑士或是骑士的流氓。所以,我们可以得出结论,A 一定是流氓。
|
||||
|
||||
- 谜题 0 是背景中的谜题。它只包含一个简单的角色 A
|
||||
那个谜题比较简单。随着更多的字符和更多的句子,谜题可以变得更加棘手!你在这个问题中的任务是确定如何使用命题逻辑来表示这些谜题,这样一个运行模型检查算法的人工智能可以为我们解决这些谜题。
|
||||
|
||||
A 说:“我既是骑士又是流氓。”
|
||||
### 理解
|
||||
|
||||
看一下 `logic.py`,你可能还记得讲义的内容。无需了解此文件中的所有内容,但请注意,此文件为不同类型的逻辑连接词定义了多个类。这些类可以相互组合,所以表达式 `And(Not(A), Or(B, C))` 代表逻辑语句:命题 A 是不正确的,同时,命题 B 或者命题 C 是正确的。(这里的“或”是同或,不是异或)
|
||||
|
||||
回想一下 `logic.py`,它还包含一个 函数 `model_check` 。`model_check` 输入知识库和查询结论。知识库是一个逻辑命题:如果知道多个逻辑语句,则可以将它们连接在一个表达式中。递归考虑所有可能的模型,如果知识库推理蕴含查询结论,则返回 `True`,否则返回 `False`。
|
||||
|
||||
现在,看看 `puzzle.py`,在顶部,我们定义了六个命题符号。例如,`AKnight` 表示“A 是骑士”的命题,`AKnave` 而表示“A 是流氓”的句子。我们也为字符 B 和 C 定义了类似的命题符号。
|
||||
|
||||
接下来是四个不同的知识库 `knowledge0`, `knowledge1`, `knowledge2`, and `knowledge3`,它们将分别包含推断即将到来的谜题 0、1、2 和 3 的解决方案所需的知识。请注意,目前,这些知识库中的每一个都是空的。这就是你进来的地方!
|
||||
|
||||
这个 `puzzle.py` 的 `main` 函数在所有谜题上循环,并使用模型检查来计算,给定谜题的知识,无论每个角色是骑士还是无赖,打印出模型检查算法能够得出的任何结论。
|
||||
|
||||
### 明确
|
||||
|
||||
将知识添加到知识库 `knowledge0`, `knowledge1`, `knowledge2`, 和 `knowledge3` 中,以解决以下难题。
|
||||
|
||||
- 谜题 0 是背景中的谜题。它只包含一个简单的角色 A
|
||||
|
||||
A 说:“我既是骑士又是流氓。”
|
||||
|
||||
- 谜题 1 有两个角色:A 和 B
|
||||
|
||||
A 说:“我们都是流氓。”
|
||||
A 说:“我们都是流氓。”
|
||||
|
||||
B 什么都没说。
|
||||
B 什么都没说。
|
||||
|
||||
- 谜题 2 有两个角色:A 和 B
|
||||
|
||||
A 说:“我们是同一种身份。”
|
||||
A 说:“我们是同一种身份。”
|
||||
|
||||
B 说:“我们不是同一种身份。”
|
||||
B 说:“我们不是同一种身份。”
|
||||
|
||||
- 谜题 3 有三个角色:A,B 和 C
|
||||
|
||||
A 说:“我是骑士”或者 A 说:“我是流氓”(这里“或”是异或,不是同或),但你不知道 A 说的是哪句话。
|
||||
A 说:“我是骑士”或者 A 说:“我是流氓”(这里“或”是异或,不是同或),但你不知道 A 说的是哪句话。
|
||||
|
||||
B 说:“A 说过‘我是流氓’。”
|
||||
B 说:“A 说过‘我是流氓’。”
|
||||
|
||||
B 又说:“C 是流氓。”
|
||||
B 又说:“C 是流氓。”
|
||||
|
||||
C 说:“A 是骑士。”
|
||||
C 说:“A 是骑士。”
|
||||
|
||||
- 上述每个谜题中,每个角色要么是骑士,要么是流氓。骑士说的每一句话都是真的,流氓说的每一句话都是假的。
|
||||
- 一旦你完成了一个问题的知识库,你应该能够运行 `python puzzle.py` 来查看谜题的解决方案。
|
||||
上述每个谜题中,每个角色要么是骑士,要么是流氓。骑士说的每一句话都是真的,流氓说的每一句话都是假的。
|
||||
|
||||
## 提示
|
||||
一旦你完成了一个问题的知识库,你应该能够运行 `python puzzle.py` 来查看谜题的解决方案。
|
||||
|
||||
- 对于每个知识库,你可能想要编码两种不同类型的信息:(1)关于问题本身结构的信息(即骑士与流氓谜题定义中给出的信息),以及(2)关于角色实际说了什么的信息。
|
||||
- 考虑一下,如果一个句子是由一个角色说出的,这意味着什么。在什么条件下这句话是真的?在什么条件下这个句子是假的?你如何将其表达为一个合乎逻辑的句子?
|
||||
- 每个谜题都有多个可能的知识库,可以计算出正确的结果。你应该尝试选择一个能对谜题中的信息进行最直接的知识库,而不是自己进行逻辑推理。你还应该考虑谜题中信息最简洁的表达方式是什么。
|
||||
### 提示
|
||||
|
||||
- 例如,对于谜题 0,设置 `knowledge0=AKnave` 将产生正确的输出,因为通过我们自己的推理,我们知道 A 一定是一个无赖。但这样做违背了这个问题的精神:目标是让你的人工智能为你做推理。
|
||||
- 您不需要(也不应该)修改 `logic.py` 来完成这个问题。
|
||||
对于每个知识库,你可能想要编码两种不同类型的信息:(1)关于问题本身结构的信息(即骑士与流氓谜题定义中给出的信息),以及(2)关于角色实际说了什么的信息。
|
||||
|
||||
# 扫雷
|
||||
考虑一下,如果一个句子是由一个角色说出的,这意味着什么。在什么条件下这句话是真的?在什么条件下这个句子是假的?你如何将其表达为一个合乎逻辑的句子?
|
||||
|
||||
每个谜题都有多个可能的知识库,可以计算出正确的结果。你应该尝试选择一个能对谜题中的信息进行最直接的知识库,而不是自己进行逻辑推理。你还应该考虑谜题中信息最简洁的表达方式是什么。
|
||||
|
||||
例如,对于谜题 0,设置 `knowledge0=AKnave` 将产生正确的输出,因为通过我们自己的推理,我们知道 A 一定是一个无赖。但这样做违背了这个问题的精神:目标是让你的人工智能为你做推理。
|
||||
|
||||
您不需要(也不应该)修改 `logic.py` 来完成这个问题。
|
||||
|
||||
## 扫雷
|
||||
|
||||
写一个 AI 来玩扫雷游戏。
|
||||
|
||||

|
||||

|
||||
|
||||
## 背景
|
||||
### 背景
|
||||
|
||||
### 扫雷
|
||||
#### 扫雷游戏
|
||||
|
||||
- 扫雷器是一款益智游戏,由一个单元格网格组成,其中一些单元格包含隐藏的“地雷”。点击包含地雷的单元格会引爆地雷,导致用户输掉游戏。单击“安全”单元格(即不包含地雷的单元格)会显示一个数字,指示有多少相邻单元格包含地雷,其中相邻单元格是指从给定单元格向左、向右、向上、向下或对角线一个正方形的单元格。
|
||||
- 例如,在这个 3x3 扫雷游戏中,三个 1 值表示这些单元格中的每个单元格都有一个相邻的单元格,该单元格是地雷。四个 0 值表示这些单元中的每一个都没有相邻的地雷。
|
||||
扫雷器是一款益智游戏,由一个单元格网格组成,其中一些单元格包含隐藏的“地雷”。点击包含地雷的单元格会引爆地雷,导致用户输掉游戏。单击“安全”单元格(即不包含地雷的单元格)会显示一个数字,指示有多少相邻单元格包含地雷,其中相邻单元格是指从给定单元格向左、向右、向上、向下或对角线一个正方形的单元格。
|
||||
例如,在这个 3x3 扫雷游戏中,三个 1 值表示这些单元格中的每个单元格都有一个相邻的单元格,该单元格是地雷。四个 0 值表示这些单元中的每一个都没有相邻的地雷。
|
||||
|
||||

|
||||

|
||||
|
||||
- 给定这些信息,玩家根据逻辑可以得出结论,右下角单元格中一定有地雷,左上角单元格中没有地雷,因为只有在这种情况下,其他单元格上的数字标签才会准确。
|
||||
- 游戏的目标是标记(即识别)每个地雷。在游戏的许多实现中,包括本项目中的实现中,玩家可以通过右键单击单元格(或左键双击,具体取决于计算机)来标记地雷。
|
||||
给定这些信息,玩家根据逻辑可以得出结论,右下角单元格中一定有地雷,左上角单元格中没有地雷,因为只有在这种情况下,其他单元格上的数字标签才会准确。
|
||||
|
||||
### 命题逻辑
|
||||
游戏的目标是标记(即识别)每个地雷。在游戏的许多实现中,包括本项目中的实现中,玩家可以通过右键单击单元格(或左键双击,具体取决于计算机)来标记地雷。
|
||||
|
||||
- 你在这个项目中的目标是建立一个可以玩扫雷游戏的人工智能。回想一下,基于知识的智能主体通过考虑他们的知识库来做出决策,并根据这些知识做出推断。
|
||||
- 我们可以表示人工智能关于扫雷游戏的知识的一种方法是,使每个单元格成为命题变量,如果单元格包含地雷,则为真,否则为假。
|
||||
#### 命题逻辑
|
||||
|
||||

|
||||
你在这个项目中的目标是建立一个可以玩扫雷游戏的人工智能。回想一下,基于知识的智能主体通过考虑他们的知识库来做出决策,并根据这些知识做出推断。
|
||||
|
||||
我们可以表示人工智能关于扫雷游戏的知识的一种方法是,使每个单元格成为命题变量,如果单元格包含地雷,则为真,否则为假。
|
||||
|
||||

|
||||
|
||||
我们现在掌握了什么信息?我们现在知道八个相邻的单元格中有一个是地雷。因此,我们可以写一个逻辑表达式,如下所示,表示其中一个相邻的单元格是地雷。
|
||||
|
||||
- 我们现在掌握了什么信息?我们现在知道八个相邻的单元格中有一个是地雷。因此,我们可以写一个逻辑表达式,如下所示,表示其中一个相邻的单元格是地雷。
|
||||
- `Or(A,B,C,D,E,F,G,H)`
|
||||
- 但事实上,我们知道的比这个表达所说的要多。上面的逻辑命题表达了这样一种观点,即这八个变量中至少有一个是真的。但我们可以做一个更有力的陈述:我们知道八个变量中有一个是真的。这给了我们一个命题逻辑命题,如下所示。
|
||||
|
||||
```
|
||||
但事实上,我们知道的比这个表达所说的要多。上面的逻辑命题表达了这样一种观点,即这八个变量中至少有一个是真的。但我们可以做一个更有力的陈述:我们知道八个变量中有一个是真的。这给了我们一个命题逻辑命题,如下所示。
|
||||
|
||||
```txt
|
||||
Or(
|
||||
And(A, Not(B), Not(C), Not(D), Not(E), Not(F), Not(G), Not(H)),
|
||||
And(Not(A), B, Not(C), Not(D), Not(E), Not(F), Not(G), Not(H)),
|
||||
@@ -113,92 +131,102 @@ Or(
|
||||
)
|
||||
```
|
||||
|
||||
- 这是一个相当复杂的表达!这只是为了表达一个单元格中有 1 意味着什么。如果一个单元格有 2、3 或其他值,这个表达式可能会更长。
|
||||
- 试图对这类问题进行模型检查也会很快变得棘手:在 8x8 网格(微软初级游戏模式使用的大小)上,我们有 64 个变量,因此需要检查
|
||||
$$
|
||||
2^64
|
||||
$$
|
||||
这是一个相当复杂的表达!这只是为了表达一个单元格中有 1 意味着什么。如果一个单元格有 2、3 或其他值,这个表达式可能会更长。
|
||||
|
||||
个可能的模型——太多了,计算机无法在任何合理的时间内计算。对于这个问题,我们需要更好地表达知识。
|
||||
试图对这类问题进行模型检查也会很快变得棘手:在 8x8 网格(微软初级游戏模式使用的大小)上,我们有 64 个变量,因此需要检查$2^{64}$个可能的模型——太多了,计算机无法在任何合理的时间内计算。对于这个问题,我们需要更好地表达知识。
|
||||
|
||||
### 知识表示
|
||||
#### 知识表示
|
||||
|
||||
相反,我们将像下面这样表示人工智能知识的每一句话。
|
||||
|
||||
- 相反,我们将像下面这样表示人工智能知识的每一句话。
|
||||
- `{A, B, C, D, E, F, G, H} = 1`
|
||||
- 这种表示法中的每个逻辑命题都有两个部分:一个是网格中与提示数字有关的一组单元格 `cell`,另一个是数字计数 `count`,表示这些单元格中有多少是地雷。上面的逻辑命题说,在单元格 A、B、C、D、E、F、G 和 H 中,正好有 1 个是地雷。
|
||||
- 为什么这是一个有用的表示?在某种程度上,它很适合某些类型的推理。考虑下面的游戏。
|
||||
|
||||

|
||||
这种表示法中的每个逻辑命题都有两个部分:一个是网格中与提示数字有关的一组单元格 `cell`,另一个是数字计数 `count`,表示这些单元格中有多少是地雷。上面的逻辑命题说,在单元格 A、B、C、D、E、F、G 和 H 中,正好有 1 个是地雷。
|
||||
|
||||
- 利用左下数的知识,我们可以构造命题 `{D,E,G}=0`,意思是在 D、E 和 G 单元中,正好有 0 个是地雷。凭直觉,我们可以从这句话中推断出所有的单元格都必须是安全的。通过推理,每当我们有一个 `count` 为 0 的命题时,我们就知道该命题的所有 `cell` 都必须是安全的。
|
||||
- 同样,考虑下面的游戏。
|
||||
为什么这是一个有用的表示?在某种程度上,它很适合某些类型的推理。考虑下面的游戏。
|
||||
|
||||

|
||||

|
||||
|
||||
- 我们的人工智能会构建命题 `{E,F,H}=3`。凭直觉,我们可以推断出所有的 E、F 和 H 都是地雷。更一般地说,任何时候 `cell` 的数量等于 `count`,我们都知道这个命题的所有单元格都必须是地雷。
|
||||
- 一般来说,我们只希望我们的命题是关于那些还不知道是安全的还是地雷的 `cell`。这意味着,一旦我们知道一个单元格是否是地雷,我们就可以更新我们的知识库来简化它们,并可能得出新的结论。
|
||||
- 例如,如果我们的人工智能知道命题 `{A,B,C}=2`,那么我们还没有足够的信息来得出任何结论。但如果我们被告知 C 是安全的,我们可以将 C 从命题中完全删除,留下命题 `{A,B}=2`(顺便说一句,这确实让我们得出了一些新的结论)
|
||||
- 同样,如果我们的人工智能知道命题 `{A,B,C}=2`,并且我们被告知 C 是一颗地雷,我们可以从命题中删除 C,并减少计数的值(因为 C 是导致该计数的地雷),从而得到命题 `{A、B}=1`。这是合乎逻辑的:如果 A、B 和 C 中有两个是地雷,并且我们知道 C 是地雷,那么 A 和 B 中一定有一个是地雷。
|
||||
- 如果我们更聪明,我们可以做最后一种推理。
|
||||
利用左下数的知识,我们可以构造命题 `{D,E,G}=0`,意思是在 D、E 和 G 单元中,正好有 0 个是地雷。凭直觉,我们可以从这句话中推断出所有的单元格都必须是安全的。通过推理,每当我们有一个 `count` 为 0 的命题时,我们就知道该命题的所有 `cell` 都必须是安全的。
|
||||
|
||||

|
||||
同样,考虑下面的游戏。
|
||||
|
||||
- 考虑一下我们的人工智能根据中间顶部单元格和中间底部单元格会知道的两个命题。从中上角的单元格中,我们得到 `{A,B,C}=1`。从底部中间单元格中,我们得到 `{A,B,C,D,E}=2`。从逻辑上讲,我们可以推断出一个新的知识,即 `{D,E}=1`。毕竟,如果 A、B、C、D 和 E 中有两个是地雷,而 A、B 和 C 中只有一个是地雷的话,那么 D 和 E 必须是另一个地雷。
|
||||
- 更一般地说,任何时候我们有两个命题满足 `set1=count1` 和 `set2=count2`,其中 `set1` 是 `set2` 的子集,那么我们可以构造新的命题 `set2-set1=count2-count1`。考虑上面的例子,以确保你理解为什么这是真的。
|
||||
- 因此,使用这种表示知识的方法,我们可以编写一个人工智能智能主体,它可以收集有关扫雷的知识,并希望选择它知道安全的单元格!
|
||||

|
||||
|
||||
## 理解
|
||||
我们的人工智能会构建命题 `{E,F,H}=3`。凭直觉,我们可以推断出所有的 E、F 和 H 都是地雷。更一般地说,任何时候 `cell` 的数量等于 `count`,我们都知道这个命题的所有单元格都必须是地雷。
|
||||
|
||||
- 这个项目有两个主要文件:`runner.py` 和 `minesweeper.py`。`minesweeper.py` 包含游戏本身和 AI 玩游戏的所有逻辑。`runner.py` 已经为你实现,它包含了运行游戏图形界面的所有代码。一旦你完成了 `minesweeper.py` 中所有必需的功能,你就可以运行 `python runner.py` 来玩扫雷了(或者让你的 AI 为你玩)!
|
||||
- 让我们打开 `minesweeper.py` 来了解提供了什么。这个文件中定义了三个类,`Minesweeper`,负责处理游戏;`Sentence`,表示一个既包含一组 `cell` 又包含一个 `count` 的逻辑命题;以及 `MinesweeperAI`,它处理根据知识做出的推断。
|
||||
- `Minesweeper` 类已经完全实现了。请注意,每个单元格都是一对 `(i,j)`,其中 `i` 是行号(范围从 `0` 到 `height-1`),`j` 是列号(范围从 `0` 到 `width-1`)。
|
||||
- `Sentence` 类将用于表示背景中描述的形式的逻辑命题。每个命题中都有一组 `cell`,以及 `count` 表示其中有多少单元格是地雷。该类还包含函数 `known_mines` 和 `known_safes`,用于确定命题中的任何单元格是已知的地雷还是已知的安全单元格。它还包含函数 `mark_mine` 和 `mark_safe`,用于响应有关单元格的新信息来更新命题。
|
||||
- 最后,`MinesweeperAI` 类将实现一个可以玩扫雷的 AI。AI 类跟踪许多值。`self.moves_made` 包含一组已经点击过的所有单元格,因此人工智能知道不要再选择这些单元格。`self.mines` 包含一组已知为地雷的所有单元格。`self.safes` 包含一组已知安全的所有单元格。而 `self.knowledge` 包含了人工智能知道是真的所有命题的列表。
|
||||
- `mark_mine` 函数为 `self.mines` 添加了一个单元格,因此 AI 知道这是一个地雷。它还循环遍历人工智能知识中的所有命题,并通知每个命题该单元格是地雷,这样,如果命题包含有关地雷的信息,它就可以相应地更新自己。`mark_safe` 函数也做同样的事情,只是针对安全单元格。
|
||||
- 剩下的函数 `add_knowledge`、`make_safe_move` 和 `make_random_move` 由你完成!
|
||||
一般来说,我们只希望我们的命题是关于那些还不知道是安全的还是地雷的 `cell`。这意味着,一旦我们知道一个单元格是否是地雷,我们就可以更新我们的知识库来简化它们,并可能得出新的结论。
|
||||
|
||||
## 明确
|
||||
例如,如果我们的人工智能知道命题 `{A,B,C}=2`,那么我们还没有足够的信息来得出任何结论。但如果我们被告知 C 是安全的,我们可以将 C 从命题中完全删除,留下命题 `{A,B}=2`(顺便说一句,这确实让我们得出了一些新的结论)
|
||||
|
||||
- 完成 `minesweeper.py` 中的 `Sentence` 类和 `MinesweeperAI` 类的实现。
|
||||
- 在 `Sentence` 类中,完成 `known_mines`、`known_safes`、`mark_mine` 和 `mark_safe` 的实现。
|
||||
同样,如果我们的人工智能知道命题 `{A,B,C}=2`,并且我们被告知 C 是一颗地雷,我们可以从命题中删除 C,并减少计数的值(因为 C 是导致该计数的地雷),从而得到命题 `{A、B}=1`。这是合乎逻辑的:如果 A、B 和 C 中有两个是地雷,并且我们知道 C 是地雷,那么 A 和 B 中一定有一个是地雷。
|
||||
|
||||
- `known_mines` 函数应该返回 `self.cells` 中已知为地雷的所有单元格的集合。
|
||||
- `known_safes` 函数应该返回 `self.cells` 中已知安全的所有单元格的集合。
|
||||
- `mark_mine` 函数应该首先检查单元格是否是命题中包含的单元格之一。
|
||||
如果我们更聪明,我们可以做最后一种推理。
|
||||
|
||||
- 如果 `cell` 在命题中,函数应该更新命题,使单元格不再在命题中但仍然表示一个逻辑正确的命题,因为该 `cell` 已知是地雷。
|
||||
- 如果命题中没有 `cell`,则不需要采取任何行动。
|
||||
- `mark_safe` 函数应该首先检查单元格是否是命题中包含的单元格之一。
|
||||

|
||||
|
||||
- 如果 `cell` 在命题中,则函数应更新命题,使单元格不再在命题中但仍然表示一个逻辑正确的命题,因为该 `cell` 已知是安全的。
|
||||
- 如果命题中没有 `cell`,则不需要采取任何行动。
|
||||
- 在 `MinesweeperAI` 类中,完成 `add_knowledge`、`make_safe_move` 和 `make_random_move` 的实现。
|
||||
考虑一下我们的人工智能根据中间顶部单元格和中间底部单元格会知道的两个命题。从中上角的单元格中,我们得到 `{A,B,C}=1`。从底部中间单元格中,我们得到 `{A,B,C,D,E}=2`。从逻辑上讲,我们可以推断出一个新的知识,即 `{D,E}=1`。毕竟,如果 A、B、C、D 和 E 中有两个是地雷,而 A、B 和 C 中只有一个是地雷的话,那么 D 和 E 必须是另一个地雷。
|
||||
|
||||
- `add_knowledge` 应该接受一个单元格(表示为元组 `(i,j)`)及其相应的 `count`,并使用 AI 可以推断的任何新信息更新 `self.mines`、`self.safes`、`self.moves_made` 和 `self.knowledge`,因为该单元格是已知的安全单元格,其附近有计数地雷。
|
||||
更一般地说,任何时候我们有两个命题满足 `set1=count1` 和 `set2=count2`,其中 `set1` 是 `set2` 的子集,那么我们可以构造新的命题 `set2-set1=count2-count1`。考虑上面的例子,以确保你理解为什么这是真的。
|
||||
|
||||
因此,使用这种表示知识的方法,我们可以编写一个人工智能智能主体,它可以收集有关扫雷的知识,并希望选择它知道安全的单元格!
|
||||
|
||||
### 理解
|
||||
|
||||
这个项目有两个主要文件:`runner.py` 和 `minesweeper.py`。`minesweeper.py` 包含游戏本身和 AI 玩游戏的所有逻辑。`runner.py` 已经为你实现,它包含了运行游戏图形界面的所有代码。一旦你完成了 `minesweeper.py` 中所有必需的功能,你就可以运行 `python runner.py` 来玩扫雷了(或者让你的 AI 为你玩)!
|
||||
|
||||
让我们打开 `minesweeper.py` 来了解提供了什么。这个文件中定义了三个类,`Minesweeper`,负责处理游戏;`Sentence`,表示一个既包含一组 `cell` 又包含一个 `count` 的逻辑命题;以及 `MinesweeperAI`,它处理根据知识做出的推断。
|
||||
|
||||
`Minesweeper` 类已经完全实现了。请注意,每个单元格都是一对 `(i,j)`,其中 `i` 是行号 (范围从 `0` 到 `height-1`),`j` 是列号 (范围从 `0` 到 `width-1`)。
|
||||
|
||||
`Sentence` 类将用于表示背景中描述的形式的逻辑命题。每个命题中都有一组 `cell`,以及 `count` 表示其中有多少单元格是地雷。该类还包含函数 `known_mines` 和 `known_safes`,用于确定命题中的任何单元格是已知的地雷还是已知的安全单元格。它还包含函数 `mark_mine` 和 `mark_safe`,用于响应有关单元格的新信息来更新命题。
|
||||
|
||||
最后,`MinesweeperAI` 类将实现一个可以玩扫雷的 AI。AI 类跟踪许多值。`self.moves_made` 包含一组已经点击过的所有单元格,因此人工智能知道不要再选择这些单元格。`self.mines` 包含一组已知为地雷的所有单元格。`self.safes` 包含一组已知安全的所有单元格。而 `self.knowledge` 包含了人工智能知道是真的所有命题的列表。
|
||||
|
||||
`mark_mine` 函数为 `self.mines` 添加了一个单元格,因此 AI 知道这是一个地雷。它还循环遍历人工智能知识中的所有命题,并通知每个命题该单元格是地雷,这样,如果命题包含有关地雷的信息,它就可以相应地更新自己。`mark_safe` 函数也做同样的事情,只是针对安全单元格。
|
||||
|
||||
剩下的函数 `add_knowledge`、`make_safe_move` 和 `make_random_move` 由你完成!
|
||||
|
||||
### 明确
|
||||
|
||||
完成 `minesweeper.py` 中的 `Sentence` 类和 `MinesweeperAI` 类的实现。
|
||||
在 `Sentence` 类中,完成 `known_mines`、`known_safes`、`mark_mine` 和 `mark_safe` 的实现。
|
||||
|
||||
- `known_mines` 函数应该返回 `self.cells` 中已知为地雷的所有单元格的集合。
|
||||
- `known_safes` 函数应该返回 `self.cells` 中已知安全的所有单元格的集合。
|
||||
- `mark_mine` 函数应该首先检查单元格是否是命题中包含的单元格之一。
|
||||
- 如果 `cell` 在命题中,函数应该更新命题,使单元格不再在命题中但仍然表示一个逻辑正确的命题,因为该 `cell` 已知是地雷。
|
||||
- 如果命题中没有 `cell`,则不需要采取任何行动。
|
||||
- `mark_safe` 函数应该首先检查单元格是否是命题中包含的单元格之一。
|
||||
- 如果 `cell` 在命题中,则函数应更新命题,使单元格不再在命题中但仍然表示一个逻辑正确的命题,因为该 `cell` 已知是安全的。
|
||||
- 如果命题中没有 `cell`,则不需要采取任何行动。
|
||||
|
||||
在 `MinesweeperAI` 类中,完成 `add_knowledge`、`make_safe_move` 和 `make_random_move` 的实现。
|
||||
|
||||
- `add_knowledge` 应该接受一个单元格(表示为元组 `(i,j)`)及其相应的 `count`,并使用 AI 可以推断的任何新信息更新 `self.mines`、`self.safes`、`self.moves_made` 和 `self.knowledge`,因为该单元格是已知的安全单元格,其附近有计数地雷。
|
||||
- 该函数应将该 `cell` 标记为游戏中的一个动作。
|
||||
- 函数应该将 `cell` 标记为安全单元格,同时更新包含该单元格的任何命题。
|
||||
- 该函数应该根据 `cell` 和 `count` 的值,在人工智能的知识库中添加一个新命题,以表明 `cell` 的邻居有 `count` 是地雷。请确保在命题中只包含状态尚未确定的单元格。
|
||||
- 如果根据 `self.knowledge` 中的任何一个命题,新的单元格可以被标记为安全的或地雷,那么函数应该这样做。
|
||||
- 如果根据 `self.knowledge` 中的任何一个命题,可以推断出新的命题(使用背景技术中描述的子集方法),那么这些命题也应该添加到知识库中。
|
||||
- 请注意,每当你对人工智能的知识做出任何改变时,都有可能得出以前不可能的新推论。如果可能的话,请确保将这些新的推断添加到知识库中。
|
||||
|
||||
- 该函数应将该 `cell` 标记为游戏中的一个动作。
|
||||
- 函数应该将 `cell` 标记为安全单元格,同时更新包含该单元格的任何命题。
|
||||
- 该函数应该根据 `cell` 和 `count` 的值,在人工智能的知识库中添加一个新命题,以表明 `cell` 的邻居有 `count` 是地雷。请确保在命题中只包含状态尚未确定的单元格。
|
||||
- 如果根据 `self.knowledge` 中的任何一个命题,新的单元格可以被标记为安全的或地雷,那么函数应该这样做。
|
||||
- 如果根据 `self.knowledge` 中的任何一个命题,可以推断出新的命题(使用背景技术中描述的子集方法),那么这些命题也应该添加到知识库中。
|
||||
- 请注意,每当你对人工智能的知识做出任何改变时,都有可能得出以前不可能的新推论。如果可能的话,请确保将这些新的推断添加到知识库中。
|
||||
- `make_safe_move` 应该返回一个已知安全的选择 `(i,j)`。
|
||||
|
||||
- 必须知道返回的动作是安全的,而不是已经做出的动作。
|
||||
- 如果无法保证安全移动,则函数应返回 `None`。
|
||||
- 该函数不应修改 `self.moves_made`、`self.mines`、`self.safes` 或 `self.knowledge`。
|
||||
- `make_random_move` 应该返回一个随机选择 `(i,j)`。
|
||||
|
||||
- `make_random_move` 应该返回一个随机选择 `(i,j)`。
|
||||
- 如果无法安全移动,将调用此功能:如果人工智能不知道移动到哪里,它将选择随机移动。
|
||||
- 此举不得是已经采取的行动。
|
||||
- 此举决不能是已知的地雷行动。
|
||||
- 如果无法进行此类移动,则函数应返回 `None`。
|
||||
|
||||
## 提示
|
||||
### 提示
|
||||
|
||||
- 确保你已经彻底阅读了背景部分,以了解知识在这个人工智能中是如何表现的,以及人工智能是如何进行推理的。
|
||||
- 如果对面向对象编程感觉不太舒服,你可能会发现<u>python 关于类</u>的文档很有帮助。
|
||||
- 你可以在<u>python 关于集合</u>的文档中找到一些常见的集合操作。
|
||||
- 如果对面向对象编程感觉不太舒服,你可能会发现[<u>python 关于类</u>](https://docs.python.org/3/tutorial/classes.html)的文档很有帮助。
|
||||
- 你可以在[<u>python 关于集合</u>](https://docs.python.org/3/library/stdtypes.html#set)的文档中找到一些常见的集合操作。
|
||||
- 在 `Sentence` 类中实现 `known_mines` 和 `known_safes` 时,请考虑:在什么情况下,你确信命题的单元格是安全的?在什么情况下,你确定一个命题的单元格是地雷?
|
||||
- `add_knowledge` 做了很多工作,可能是迄今为止你为该项目编写的最长的函数。一步一步地实现此函数的行为可能会有所帮助。
|
||||
- 如果愿意,欢迎您向任何类添加新方法,但不应修改任何现有函数的定义或参数。
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# 知识推理
|
||||
|
||||
人类根据现有的知识进行推理并得出结论。表示知识并从中得出结论的概念也被用于人工智能中,在本章中我们将探讨如何实现这种行为。
|
||||
::: warning 😱
|
||||
# 说好的 AI 呢?怎么感觉越来越偏了?
|
||||
|
||||
::: warning <font size=5>**说好的 AI 呢?怎么感觉越来越偏了?**</font>
|
||||
|
||||
如果有这样的疑问的同学,可能存在一定的误区,认为人工智能就是局限在深度学习的算法或者说机器学习的部分算法上,其实这是对这个领域一个巨大的误解。
|
||||
|
||||
@@ -20,36 +20,47 @@
|
||||
|
||||
较为基础的知识各位可以看以下的内容。
|
||||
:::
|
||||
# 基础知识
|
||||
|
||||
- 基于知识的智能主体(Knowledge-Based Agents)
|
||||
- 智能主体通过对内部的知识表征进行操作来推理得出结论。
|
||||
- “根据知识推理得出结论”是什么意思?
|
||||
- 让我们开始用哈利波特的例子来回答这个问题。 考虑以下句子:
|
||||
1. 如果没有下雨,哈利今天会去拜访海格。
|
||||
2. 哈利今天拜访了海格或邓布利多,但没有同时拜访他们。
|
||||
3. 哈利今天拜访了邓布利多。
|
||||
- 基于这三个句子,我们可以回答“今天下雨了吗?”这个问题,尽管没有一个单独的句子告诉我们今天是否下雨,根据推理我们可以得出结论“今天下雨了”。
|
||||
- 陈述句(Sentence)
|
||||
- 陈述句是知识表示语言中关于世界的断言。 陈述句是人工智能存储知识并使用它来推断新信息的方式。
|
||||
## 基础知识
|
||||
|
||||
# 命题逻辑(Propositional Logic)
|
||||
### 基于知识的智能主体 (Knowledge-Based Agents)
|
||||
|
||||
智能主体通过对内部的知识表征进行操作来推理得出结论。
|
||||
|
||||
“根据知识推理得出结论”是什么意思?
|
||||
|
||||
让我们开始用哈利波特的例子来回答这个问题。考虑以下句子:
|
||||
|
||||
1. 如果没有下雨,哈利今天会去拜访海格。
|
||||
2. 哈利今天拜访了海格或邓布利多,但没有同时拜访他们。
|
||||
3. 哈利今天拜访了邓布利多。
|
||||
基于这三个句子,我们可以回答“今天下雨了吗?”这个问题,尽管没有一个单独的句子告诉我们今天是否下雨,根据推理我们可以得出结论“今天下雨了”。
|
||||
|
||||
### 陈述句 (Sentence)
|
||||
|
||||
陈述句是知识表示语言中关于世界的断言。陈述句是人工智能存储知识并使用它来推断新信息的方式。
|
||||
|
||||
## 命题逻辑 (Propositional Logic)
|
||||
|
||||
命题逻辑基于命题。命题是关于世界的陈述,可以是真也可以是假,正如上面例子中的句子。
|
||||
|
||||
- 命题符号(Propositional Symbols)
|
||||
- 命题符号通常是用于表示命题的字母$P、Q、R$
|
||||
- 逻辑连接词(Logical Connectives)
|
||||
- 逻辑连接词是连接命题符号的逻辑符号,以便以更复杂的方式对世界进行推理。
|
||||
- <strong>Not</strong><strong> </strong><strong>(</strong>$\lnot$<strong>)</strong> 逻辑非: 命题真值的反转。 例如,如果 $P$:“正在下雨”,那么 $¬P$:“没有下雨”。
|
||||
- 真值表用于将所有可能的真值赋值与命题进行比较。 该工具将帮助我们更好地理解与不同逻辑连接词相关联的命题的真值。 例如,下面是我们的第一个真值表:
|
||||
### 命题符号 (Propositional Symbols)
|
||||
|
||||
命题符号通常是用于表示命题的字母$P、Q、R$
|
||||
|
||||
### 逻辑连接词 (Logical Connectives)
|
||||
|
||||
逻辑连接词是连接命题符号的逻辑符号,以便以更复杂的方式对世界进行推理。
|
||||
|
||||
- <strong>Not</strong><strong> </strong><strong>(</strong>$\lnot$<strong>)</strong> 逻辑非:命题真值的反转。例如,如果 $P$:“正在下雨”,那么 $¬P$:“没有下雨”。
|
||||
真值表用于将所有可能的真值赋值与命题进行比较。该工具将帮助我们更好地理解与不同逻辑连接词相关联的命题的真值。例如,下面是我们的第一个真值表:
|
||||
|
||||
| $P$ | $\lnot P$ |
|
||||
| -------- | --------- |
|
||||
| false(0) | true(1) |
|
||||
| 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$ |
|
||||
| --- | --- | ---------- |
|
||||
@@ -58,7 +69,7 @@
|
||||
| 1 | 0 | 0 |
|
||||
| 1 | 1 | 1 |
|
||||
|
||||
- <strong>Or(</strong>$\lor$<strong>)</strong> 逻辑和(析取): 只要它的任何一个参数为真,它就为真。 这意味着要使 $P ∨ Q$为真,$P$ 或 $Q$ 中至少有一个必须为真。
|
||||
- **Or(**$\lor$**)** 逻辑和 (析取): 只要它的任何一个参数为真,它就为真。这意味着要使 $P ∨ Q$为真,$P$ 或 $Q$ 中至少有一个必须为真。
|
||||
|
||||
| $P$ | $Q$ | $P\lor Q$ |
|
||||
| --- | --- | --------- |
|
||||
@@ -67,12 +78,11 @@
|
||||
| 1 | 0 | 1 |
|
||||
| 1 | 1 | 1 |
|
||||
|
||||
值得一提的是,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。
|
||||
- **Implication (→)** 逻辑蕴含:表示“如果$P$,则$Q$的结构。例如,如果$P$:“正在下雨”,$Q$:“我在室内”,则$P→ Q$的意思是“如果下雨,那么我在室内。”在$P$的情况下,意味着$Q$,$P$被称为前件,$Q$ 被称为后件。
|
||||
|
||||
- <strong>Implication (→)</strong> 逻辑蕴含: 表示“如果$P$,则$Q$的结构。例如,如果$P$:“正在下雨”,$Q$:“我在室内”,则$P→ Q$的意思是“如果下雨,那么我在室内。”在$P$的情况下,意味着$Q$,$P$被称为前件,$Q$ 被称为后件。
|
||||
|
||||
- 当前件为真时,在后件为真的情况下,整个蕴含逻辑为真(这是有道理的:如果下雨,我在室内,那么“如果下雨,那么我在室内”这句话是真的)。当前件为真时,如果后件为假,则蕴含逻辑为假(如果下雨时我在外面,那么“如果下雨,那么我在室内”这句话是假的)。然而,当前件为假时,无论后件如何,蕴含逻辑总是真的。这有时可能是一个令人困惑的概念。从逻辑上讲,我们不能从蕴含中学到任何东西$(P→ Q)$如果前件($P$)为假。看一下我们的例子,如果没有下雨,这个蕴含逻辑并没有说我是否在室内的问题。我可能是一个室内型的人,即使不下雨也不在外面走,或者我可能是一个室外型的人,不下雨的时候一直在外面。当前件是假的,我们说蕴含逻辑是真的。
|
||||
当前件为真时,在后件为真的情况下,整个蕴含逻辑为真(这是有道理的:如果下雨,我在室内,那么“如果下雨,那么我在室内”这句话是真的)。当前件为真时,如果后件为假,则蕴含逻辑为假(如果下雨时我在外面,那么“如果下雨,那么我在室内”这句话是假的)。然而,当前件为假时,无论后件如何,蕴含逻辑总是真的。这有时可能是一个令人困惑的概念。从逻辑上讲,我们不能从蕴含中学到任何东西$(P→ Q)$如果前件 ($P$) 为假。看一下我们的例子,如果没有下雨,这个蕴含逻辑并没有说我是否在室内的问题。我可能是一个室内型的人,即使不下雨也不在外面走,或者我可能是一个室外型的人,不下雨的时候一直在外面。当前件是假的,我们说蕴含逻辑是真的。
|
||||
|
||||
| $P$ | $Q$ | $P\to Q$ |
|
||||
| --- | --- | -------- |
|
||||
@@ -81,8 +91,9 @@
|
||||
| 1 | 0 | 0 |
|
||||
| 1 | 1 | 1 |
|
||||
|
||||
|
||||
- <strong>Biconditional (</strong>$\leftrightarrow$<strong>)</strong> :是一个双向的蕴含。你可以把它读成“如果且仅当”$P↔ Q$等同$P→ Q$和$Q→ P$合在一起。例如,如果$P$:“正在下雨”,$Q$:“我在室内”,那么$P↔ Q$的意思是“如果下雨,那么我在室内”,“如果我在室内,那么就在下雨。”这意味着我们可以推断出比简单蕴含更多的东西。如果$P$为假,那么$Q$ 也为假;如果不下雨,我们知道我也不在室内。
|
||||
|
||||
|
||||
| $P$ | $Q$ | $P\leftrightarrow Q$ |
|
||||
| --- | --- | -------------------- |
|
||||
| 0 | 0 | 1 |
|
||||
@@ -90,31 +101,44 @@
|
||||
| 1 | 0 | 0 |
|
||||
| 1 | 1 | 1 |
|
||||
|
||||
- 模型(Model)
|
||||
- 模型是对每个命题的真值赋值。 重申一下,命题是关于世界的陈述,可以是真也可以是假。 然而,关于世界的知识体现在这些命题的真值中。 模型是提供有关世界的信息的真值赋值。
|
||||
- 例如,如果 $P$:“正在下雨。” 和 $Q$:“今天是星期二。”,模型可以是以下真值赋值:$\set{P = True, Q = False}$。 此模型表示正在下雨,但不是星期二。 然而,在这种情况下有更多可能的模型(例如,$\set{P = True, Q = True}$,星期二并且下雨)。 事实上,可能模型的数量是命题数量的 2 次方。 在这种情况下,我们有 2 个命题,所以 $2^2=4$ 个可能的模型。
|
||||
- 知识库(Knowledge Base (KB))
|
||||
- 知识库是基于知识的智能主题已知的一组陈述句。 这是关于人工智能以命题逻辑语句的形式提供的关于世界的知识,可用于对世界进行额外的推理。
|
||||
- 蕴含推理(Entailment ($\vDash$))
|
||||
- 如果 $α ⊨ β$($α$蕴含推理出 $β$),那么在任何 $α$为真的世界中,$β$也为真。
|
||||
- 例如,如果 $α$:“今天是一月的星期二”和 $β$:“今天是星期二”,那么我们知道 $α ⊨ β$。 如果确实是一月的星期二,我们也知道这是星期二。 蕴含推理不同于逻辑蕴含。 逻辑蕴涵是两个命题之间的逻辑连接。 另一方面,推理蕴含关系是指如果 $α$中的所有信息都为真,则 $β$中的所有信息都为真。
|
||||
### 模型 (Model)
|
||||
|
||||
# 推理(Inference)
|
||||
模型是对每个命题的真值赋值。重申一下,命题是关于世界的陈述,可以是真也可以是假。然而,关于世界的知识体现在这些命题的真值中。模型是提供有关世界的信息的真值赋值。
|
||||
|
||||
例如,如果 $P$:“正在下雨。”和 $Q$:“今天是星期二。”,模型可以是以下真值赋值:$\set{P = True, Q = False}$。此模型表示正在下雨,但不是星期二。然而,在这种情况下有更多可能的模型(例如,$\set{P = True, Q = True}$,星期二并且下雨)。事实上,可能模型的数量是命题数量的 2 次方。在这种情况下,我们有 2 个命题,所以 $2^2=4$ 个可能的模型。
|
||||
|
||||
### 知识库 (Knowledge Base (KB))
|
||||
|
||||
知识库是基于知识的智能主题已知的一组陈述句。这是关于人工智能以命题逻辑语句的形式提供的关于世界的知识,可用于对世界进行额外的推理。
|
||||
|
||||
### 蕴含推理 (Entailment ($\vDash$))
|
||||
|
||||
如果 $α ⊨ β$($α$蕴含推理出 $β$),那么在任何 $α$为真的世界中,$β$也为真。
|
||||
|
||||
例如,如果 $α$:“今天是一月的星期二”和 $β$:“今天是星期二”,那么我们知道 $α ⊨ β$。如果确实是一月的星期二,我们也知道这是星期二。蕴含推理不同于逻辑蕴含。逻辑蕴涵是两个命题之间的逻辑连接。另一方面,推理蕴含关系是指如果 $α$中的所有信息都为真,则 $β$中的所有信息都为真。
|
||||
|
||||
## 推理 (Inference)
|
||||
|
||||
推理是从原有命题推导出新命题的过程。
|
||||
|
||||
- 模型检查算法(Model Checking algorithm)
|
||||
- 确定是否$KB ⊨ α$(换句话说,回答问题:“我们能否根据我们的知识库得出结论 $α$为真?”)
|
||||
- 枚举所有可能的模型。
|
||||
- 如果在 $KB$为真的每个模型中,$α$也为真,则 $KB ⊨ α$。
|
||||
- 一个例子
|
||||
- $P$: 今天是星期四,$Q$: 今天下雨,$R$: 我将出门跑步$
|
||||
- $KB$: 如果今天是星期四并且不下雨,那我将出门跑步;今天是星期四;今天不下雨。$(P\land\lnot Q)\to R,P,\lnot Q$
|
||||
- 查询结论(query): $R$
|
||||
### 模型检查算法 (Model Checking algorithm)
|
||||
|
||||

|
||||
确定是否$KB ⊨ α$(换句话说,回答问题:“我们能否根据我们的知识库得出结论 $α$为真?”)
|
||||
|
||||
- 接下来,让我们看看如何将知识和逻辑表示为代码。
|
||||
- 枚举所有可能的模型。
|
||||
- 如果在 $KB$为真的每个模型中,$α$也为真,则 $KB ⊨ α$。
|
||||
|
||||
#### 一个例子
|
||||
|
||||
$P$: 今天是星期四,$Q$: 今天下雨,$R$: 我将出门跑步$
|
||||
|
||||
$KB$: 如果今天是星期四并且不下雨,那我将出门跑步;今天是星期四;今天不下雨。$(P\land\lnot Q)\to R,P,\lnot Q$
|
||||
|
||||
查询结论 (query): $R$
|
||||
|
||||

|
||||
|
||||
接下来,让我们看看如何将知识和逻辑表示为代码。
|
||||
|
||||
```python
|
||||
from logic import * # 创建新类,每个类都有一个名称或一个符号,代表每个命题。
|
||||
@@ -126,22 +150,23 @@ knowledge = And( # 从“和”逻辑连接词开始,因为每个命题都代
|
||||
Implication(Not(rain), hagrid), # ¬(今天下雨) → (哈利拜访了海格)
|
||||
Or(hagrid, dumbledore), # (哈利拜访了海格) ∨ (哈利拜访了邓布利多).
|
||||
Not(And(hagrid, dumbledore)), # ¬(哈利拜访了邓布利多 ∧ 哈利拜访了海格) i.e. 哈利没有同时去拜访海格和邓布利多。
|
||||
dumbledore # 哈利拜访了邓布利多。请注意,虽然之前的命题包含多个带有连接符的符号,但这是一个由一个符号组成的命题。 这意味着我们将在这个 KB 中,Harry 拜访了 Dumbledore 作为事实。
|
||||
dumbledore # 哈利拜访了邓布利多。请注意,虽然之前的命题包含多个带有连接符的符号,但这是一个由一个符号组成的命题。这意味着我们将在这个 KB 中,Harry 拜访了 Dumbledore 作为事实。
|
||||
)
|
||||
```
|
||||
|
||||
- 要运行模型检查算法,需要以下信息:
|
||||
要运行模型检查算法,需要以下信息:
|
||||
|
||||
- 知识库(KB),将用于得出推论
|
||||
- 一个查询结论(query),或者我们感兴趣的命题是否被$KB$包含
|
||||
- 命题符号,所有使用的符号(或原子命题)的列表(在我们的例子中,这些是 rain、hagrid 和 dumbledore)
|
||||
- 模型,将真值和假值分配给命题
|
||||
- 模型检查算法如下所示:
|
||||
- 知识库 (KB),将用于得出推论
|
||||
- 一个查询结论 (query),或者我们感兴趣的命题是否被$KB$包含
|
||||
- 命题符号,所有使用的符号(或原子命题)的列表(在我们的例子中,这些是 rain、hagrid 和 dumbledore)
|
||||
- 模型,将真值和假值分配给命题
|
||||
|
||||
模型检查算法如下所示:
|
||||
|
||||
```python
|
||||
def check_all(knowledge, query, symbols, model):# 如果模型对每个符号都有一个赋值
|
||||
# (下面的逻辑可能有点混乱:我们从命题符号列表开始。该函数是递归的,每次调用自身时,它都会从命题符号列表中弹出一个命题符号并从中生成模型。 因此,当命题符号列表为空时,我们知道我们已经完成生成模型,其中包含每个可能的命题真值分配。)
|
||||
if not symbols:
|
||||
# (下面的逻辑可能有点混乱:我们从命题符号列表开始。该函数是递归的,每次调用自身时,它都会从命题符号列表中弹出一个命题符号并从中生成模型。因此,当命题符号列表为空时,我们知道我们已经完成生成模型,其中包含每个可能的命题真值分配。)
|
||||
if not symbols:
|
||||
# 如果知识库在模型中为真,则查询结论也必须为真
|
||||
if knowledge.evaluate(model):
|
||||
return query.evaluate(model)
|
||||
@@ -160,163 +185,166 @@ def check_all(knowledge, query, symbols, model):# 如果模型对每个符号都
|
||||
return(check_all(knowledge, query, remaining, model_true) and check_all(knowledge, query, remaining, model_false))
|
||||
```
|
||||
|
||||
- 请注意,我们只对$KB$为真的模型感兴趣。 如果$KB$为假,那么我们知道真实的条件并没有出现在这些模型中,使它们与我们的案例无关。
|
||||
请注意,我们只对$KB$为真的模型感兴趣。如果$KB$为假,那么我们知道真实的条件并没有出现在这些模型中,使它们与我们的案例无关。
|
||||
|
||||
> 另一个例子:假设 $P$:Harry 扮演找球手,$Q$:Oliver 扮演守门员,$R$:Gryffindor获胜。 我们的$KB$指定$P$, $Q$, $(P ∧ Q) \to R$。换句话说,我们知道$P$为真,即Harry扮演找球手,$Q$为真,即Oliver扮演守门员,并且如果$P$和$Q$都为真, 那么$R$也为真,这意味着Gryffindor赢得了比赛。 现在想象一个模型,其中Harry扮演击球手而不是找球手(因此,Harry没有扮演找球手,$¬P$)。 嗯,在这种情况下,我们不关心Gryffindor是否赢了(无论$R$是否为真),因为我们的$KB$中有信息表明Harry扮演的是找球手而不是击球手。 我们只对$P$和$Q$ 为真的模型感兴趣。)
|
||||
> 另一个例子:假设 $P$:Harry 扮演找球手,$Q$:Oliver 扮演守门员,$R$:Gryffindor 获胜。我们的$KB$指定$P$, $Q$, $(P ∧ Q) \to R$。换句话说,我们知道$P$为真,即 Harry 扮演找球手,$Q$为真,即 Oliver 扮演守门员,并且如果$P$和$Q$都为真,那么$R$也为真,这意味着 Gryffindor 赢得了比赛。现在想象一个模型,其中 Harry 扮演击球手而不是找球手 (因此,Harry 没有扮演找球手,$¬P$)。嗯,在这种情况下,我们不关心 Gryffindor 是否赢了 (无论$R$是否为真),因为我们的$KB$中有信息表明 Harry 扮演的是找球手而不是击球手。我们只对$P$和$Q$ 为真的模型感兴趣。)
|
||||
|
||||
- 此外,`check_all` 函数的工作方式是递归的。 也就是说,它选择一个命题符号,创建两个模型,其中一个符号为真,另一个为假,然后再次调用自己,现在有两个模型因该命题符号的真值分配不同而不同。 该函数将继续这样做,直到所有符号都已在模型中分配了真值,使 `symbol` 符号为空。 一旦它为空(由 `if not symbols` 行标识),在函数的每个实例中(其中每个实例都包含不同的模型),函数检查$KB$是否为给定的有效模型。 如果$KB$在此模型中为真,函数将检查查询结论是否为真,如前所述。
|
||||
此外,`check_all` 函数的工作方式是递归的。也就是说,它选择一个命题符号,创建两个模型,其中一个符号为真,另一个为假,然后再次调用自己,现在有两个模型因该命题符号的真值分配不同而不同。该函数将继续这样做,直到所有符号都已在模型中分配了真值,使 `symbol` 符号为空。一旦它为空(由 `if not symbols` 行标识),在函数的每个实例中(其中每个实例都包含不同的模型),函数检查$KB$是否为给定的有效模型。如果$KB$在此模型中为真,函数将检查查询结论是否为真,如前所述。
|
||||
|
||||
# 知识工程(Knowledge Engineering)
|
||||
## 知识工程 (Knowledge Engineering)
|
||||
|
||||
知识工程是弄清楚如何在 AI 中表示命题和逻辑的工程。
|
||||
|
||||
## 推理规则(Inference Rules)
|
||||
### 推理规则 (Inference Rules)
|
||||
|
||||
- 模型检查不是一种有效的算法,因为它必须在给出答案之前考虑每个可能的模型(提醒:如果在$KB$为真的所有模型(真值分配)下,查询结论$R$为真,则$R$ 也为真)。 推理规则允许我们根据现有知识生成新信息,而无需考虑所有可能的模型。
|
||||
- 推理规则通常使用将顶部部分(前提)与底部部分(结论)分开的水平条表示。 前提是我们有什么知识,结论是根据这个前提可以产生什么知识。
|
||||
模型检查不是一种有效的算法,因为它必须在给出答案之前考虑每个可能的模型(提醒:如果在$KB$为真的所有模型(真值分配)下,查询结论$R$为真,则$R$ 也为真)。推理规则允许我们根据现有知识生成新信息,而无需考虑所有可能的模型。
|
||||
|
||||

|
||||
推理规则通常使用将顶部部分(前提)与底部部分(结论)分开的水平条表示。前提是我们有什么知识,结论是根据这个前提可以产生什么知识。
|
||||
|
||||
- 肯定前件(Modus Ponens)
|
||||

|
||||
|
||||
- 如果我们知道一个蕴涵及其前件为真,那么后件也为真。
|
||||
#### 肯定前件 (Modus Ponens)
|
||||
|
||||

|
||||
如果我们知道一个蕴涵及其前件为真,那么后件也为真。
|
||||
|
||||
- 合取消除(And Elimination)
|
||||

|
||||
|
||||
- 如果 And 命题为真,则其中的任何一个原子命题也为真。 例如,如果我们知道哈利与罗恩和赫敏是朋友,我们就可以得出结论,哈利与赫敏是朋友。
|
||||
#### 合取消除 (And Elimination)
|
||||
|
||||

|
||||
如果 And 命题为真,则其中的任何一个原子命题也为真。例如,如果我们知道哈利与罗恩和赫敏是朋友,我们就可以得出结论,哈利与赫敏是朋友。
|
||||
|
||||
- 双重否定消除(Double Negation Elimination)
|
||||

|
||||
|
||||
- 被两次否定的命题为真。 例如,考虑命题“哈利没有通过考试是不正确的”。 这两个否定相互抵消,将命题“哈利通过考试”标记为真。
|
||||
#### 双重否定消除 (Double Negation Elimination)
|
||||
|
||||

|
||||
被两次否定的命题为真。例如,考虑命题“哈利没有通过考试是不正确的”。这两个否定相互抵消,将命题“哈利通过考试”标记为真。
|
||||
|
||||
- 蕴含消除(Implication Elimination)
|
||||

|
||||
|
||||
- 蕴涵等价于被否定的前件和后件之间的 Or 关系。 例如,命题“如果正在下雨,哈利在室内”等同于命题“(没有下雨)或(哈利在室内)”。
|
||||
#### 蕴含消除 (Implication Elimination)
|
||||
|
||||

|
||||
蕴涵等价于被否定的前件和后件之间的 Or 关系。例如,命题“如果正在下雨,哈利在室内”等同于命题“(没有下雨) 或 (哈利在室内)”。
|
||||
|
||||
| $P$ | $Q$ | $P\to Q$ | $\lnot P\lor Q$ |
|
||||
| --- | --- | -------- | --------------- |
|
||||
| 0 | 0 | 1 | 1 |
|
||||
| 0 | 1 | 1 | 1 |
|
||||
| 1 | 0 | 0 | 0 |
|
||||
| 1 | 1 | 1 | 1 |
|
||||

|
||||
|
||||
- 等值消除(Biconditional Elimination)
|
||||
| $P$ | $Q$ | $P\to Q$ | $\lnot P\lor Q$ |
|
||||
| --- | --- | -------- | --------------- |
|
||||
| 0 | 0 | 1 | 1 |
|
||||
| 0 | 1 | 1 | 1 |
|
||||
| 1 | 0 | 0 | 0 |
|
||||
| 1 | 1 | 1 | 1 |
|
||||
|
||||
- 等值命题等价于蕴涵及其逆命题的 And 关系。 例如,“当且仅当 Harry 在室内时才下雨”等同于(“如果正在下雨,Harry 在室内”和“如果 Harry 在室内,则正在下雨”)。
|
||||
#### 等值消除 (Biconditional Elimination)
|
||||
|
||||

|
||||
等值命题等价于蕴涵及其逆命题的 And 关系。例如,“当且仅当 Harry 在室内时才下雨”等同于 (“如果正在下雨,Harry 在室内”和“如果 Harry 在室内,则正在下雨”)。
|
||||
|
||||
- 德摩根律(De Morgan’s Law)
|
||||

|
||||
|
||||
- 可以将 And 连接词变成 Or 连接词。考虑以下命题:“哈利和罗恩都通过了考试是不正确的。” 由此,可以得出“哈利通过考试不是真的”或者“罗恩不是真的通过考试”的结论。 也就是说,要使前面的 And 命题为真,Or 命题中至少有一个命题必须为真。
|
||||
#### 德摩根律 (De Morgan’s Law)
|
||||
|
||||

|
||||
可以将 And 连接词变成 Or 连接词。考虑以下命题:“哈利和罗恩都通过了考试是不正确的。”由此,可以得出“哈利通过考试不是真的”或者“罗恩不是真的通过考试”的结论。也就是说,要使前面的 And 命题为真,Or 命题中至少有一个命题必须为真。
|
||||
|
||||
- 同样,可以得出相反的结论。考虑这个命题“哈利或罗恩通过考试是不正确的”。 这可以改写为“哈利没有通过考试”和“罗恩没有通过考试”。
|
||||

|
||||
|
||||

|
||||
同样,可以得出相反的结论。考虑这个命题“哈利或罗恩通过考试是不正确的”。这可以改写为“哈利没有通过考试”和“罗恩没有通过考试”。
|
||||
|
||||
- 分配律(Distributive Property)
|
||||

|
||||
|
||||
- 具有两个用 And 或 Or 连接词分组的命题可以分解为由 And 和 Or 组成的更小单元。
|
||||
#### 分配律 (Distributive Property)
|
||||
|
||||

|
||||
具有两个用 And 或 Or 连接词分组的命题可以分解为由 And 和 Or 组成的更小单元。
|
||||
|
||||

|
||||

|
||||
|
||||
## 知识和搜索问题
|
||||

|
||||
|
||||
- 推理可以被视为具有以下属性的搜索问题:
|
||||
### 知识和搜索问题
|
||||
|
||||
- 初始状态:知识库
|
||||
- 动作:推理规则
|
||||
- 过渡模型:推理后的新知识库
|
||||
- 目标测试:检查我们要证明的语句是否在知识库中
|
||||
- 路径成本:证明中的步骤数
|
||||
- 这显示了搜索算法的通用性,使我们能够使用推理规则根据现有知识推导出新信息。
|
||||
推理可以被视为具有以下属性的搜索问题:
|
||||
|
||||
# 归结(Resolution)
|
||||
- 初始状态:知识库
|
||||
- 动作:推理规则
|
||||
- 过渡模型:推理后的新知识库
|
||||
- 目标测试:检查我们要证明的语句是否在知识库中
|
||||
- 路径成本:证明中的步骤数
|
||||
|
||||
- 归结是一个强大的推理规则,它规定如果 Or 命题中的两个原子命题之一为假,则另一个必须为真。 例如,给定命题“Ron 在礼堂”或“Hermione 在图书馆”,除了命题“Ron 不在礼堂”之外,我们还可以得出“Hermione 在图书馆”的结论。 更正式地说,我们可以通过以下方式定义归结:
|
||||
这显示了搜索算法的通用性,使我们能够使用推理规则根据现有知识推导出新信息。
|
||||
|
||||

|
||||
## 归结 (Resolution)
|
||||
|
||||

|
||||
归结是一个强大的推理规则,它规定如果 Or 命题中的两个原子命题之一为假,则另一个必须为真。例如,给定命题“Ron 在礼堂”或“Hermione 在图书馆”,除了命题“Ron 不在礼堂”之外,我们还可以得出“Hermione 在图书馆”的结论。更正式地说,我们可以通过以下方式定义归结:
|
||||
|
||||
- 归结依赖于互补文字,两个相同的原子命题,其中一个被否定而另一个不被否定,例如$P$和$¬P$。
|
||||
- 归结可以进一步推广。 假设除了“Rom 在礼堂”或“Hermione 在图书馆”的命题外,我们还知道“Rom 不在礼堂”或“Harry 在睡觉”。 我们可以从中推断出“Hermione 在图书馆”或“Harry 在睡觉”。 正式地说:
|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
归结依赖于互补文字,两个相同的原子命题,其中一个被否定而另一个不被否定,例如$P$和$¬P$。
|
||||
|
||||
- 互补文字使我们能够通过解析推理生成新句子。 因此,推理算法定位互补文字以生成新知识。
|
||||
- 从句(Clause)是多个原子命题的析取式(命题符号或命题符号的否定,例如$P$, $¬P$)。 析取式由Or逻辑连接词 ($P ∨ Q ∨ R$) 相连的命题组成。 另一方面,连接词由And逻辑连接词 ($P ∧ Q ∧ R$) 相连的命题组成。 从句允许我们将任何逻辑语句转换为合取范式 (CNF),它是从句的合取,例如:$(A ∨ B ∨ C) ∧ (D ∨ ¬E) ∧ (F ∨ G)$。
|
||||
- 命题转换为合取范式的步骤、
|
||||
归结可以进一步推广。假设除了“Rom 在礼堂”或“Hermione 在图书馆”的命题外,我们还知道“Rom 不在礼堂”或“Harry 在睡觉”。我们可以从中推断出“Hermione 在图书馆”或“Harry 在睡觉”。正式地说:
|
||||
|
||||
- 等值消除
|
||||

|
||||
|
||||
- 将$(α↔ β)$转化为$(α→ β)∧ (β → α)$
|
||||
- 蕴含消除
|
||||

|
||||
|
||||
互补文字使我们能够通过解析推理生成新句子。因此,推理算法定位互补文字以生成新知识。
|
||||
|
||||
从句 (Clause) 是多个原子命题的析取式(命题符号或命题符号的否定,例如$P$, $¬P$)。析取式由 Or 逻辑连接词 ($P ∨ Q ∨ R$) 相连的命题组成。另一方面,连接词由 And 逻辑连接词 ($P ∧ Q ∧ R$) 相连的命题组成。从句允许我们将任何逻辑语句转换为合取范式 (CNF),它是从句的合取,例如:$(A ∨ B ∨ C) ∧ (D ∨ ¬E) ∧ (F ∨ G)$。
|
||||
|
||||
命题转换为合取范式的步骤、
|
||||
|
||||
1. 等值消除
|
||||
- 将$(α↔ β)$转化为$(α→ β)∧ (β → α)$
|
||||
2. 蕴含消除
|
||||
- 将$(α→ β)$转化为$\lnotα∧β$
|
||||
- 使用德摩根定律,将否定向内移动,直到只有原子命题被否定(而不是从句)
|
||||
|
||||
- 将$\lnot(\alpha∧β)$转换为$\lnotα\lor\lnotβ$
|
||||
- 下面是一个转换$(P∧Q)\to R$
|
||||
|
||||
到合取范式的例子:
|
||||
|
||||
3. 使用德摩根定律,将否定向内移动,直到只有原子命题被否定(而不是从句)
|
||||
- 将$\lnot(\alpha∧β)$转换为$\lnotα\lor\lnotβ$
|
||||
4. 下面是一个转换$(P∧Q)\to R$到合取范式的例子:
|
||||
- $(P ∨ Q) → R$
|
||||
- $\lnot(P\lor Q)\lor R$蕴含消除
|
||||
- $(\lnot P\land\lnot Q)\lor R$德摩根律
|
||||
- $(\lnot P\lor R)\land(\lnot Q\lor R)$分配律
|
||||
- 归结命题及其否定,即$\lnot P$和$P$,得到空从句$()$。空从句总是假的,这是有道理的,因为$P$和$\lnot P$ 不可能都是真的。归结算法使用了这个事实。
|
||||
|
||||
- 确定是否$KB⊨α$:
|
||||
归结命题及其否定,即$\lnot P$和$P$,得到空从句$()$。空从句总是假的,这是有道理的,因为$P$和$\lnot P$ 不可能都是真的。归结算法使用了这个事实。
|
||||
|
||||
- 检查:$(KB∧\lnotα)$是矛盾的吗?
|
||||
- 确定是否$KB⊨α$:
|
||||
- 检查:$(KB∧\lnotα)$是矛盾的吗?
|
||||
- 如果是这样,那么$KB⊨α$。
|
||||
- 否则,$KB$无法蕴含推理出$\alpha$。
|
||||
|
||||
- 如果是这样,那么$KB⊨α$。
|
||||
- 否则,$KB$无法蕴含推理出$\alpha$。
|
||||
- 矛盾证明是计算机科学中经常使用的一种工具。如果我们的知识库是真的,并且它与$\lnot α$相矛盾,那就意味着$\lnot\alpha$是假的,因此$α$必须是真的。从技术上讲,该算法将执行以下操作:
|
||||
矛盾证明是计算机科学中经常使用的一种工具。如果我们的知识库是真的,并且它与$\lnot α$相矛盾,那就意味着$\lnot\alpha$是假的,因此$α$必须是真的。从技术上讲,该算法将执行以下操作:
|
||||
|
||||
- 确定是否$KB⊨α$:
|
||||
- 将$(KB∧\lnotα)$转换为合取范式。
|
||||
- 继续检查,看看我们是否可以使用归结来生成一个新的从句。
|
||||
- 如果我们生成了空从句(相当于 False),那么恭喜你!我们得出了一个矛盾,从而证明了$KB⊨α$。
|
||||
- 然而,如果没有实现矛盾,并且不能推断出更多的从句,那么就没有蕴含性。
|
||||
- 以下是一个示例,说明了该算法的工作原理:
|
||||
- $(A ∨ B) ∧ (¬B ∨ C) ∧ (¬C)\vDash A?$
|
||||
- $(A ∨ B) ∧ (¬B ∨ C) ∧ (¬C) ∧ (¬A)$
|
||||
- $(\lnot B\lor C)\land\lnot C\vDash\lnot B\implies(A ∨ B) ∧ (¬B ∨ C) ∧ (¬C) ∧ (¬A)\land (\lnot B)$
|
||||
- $(A\lor B)\land\lnot B\vDash A\implies(A ∨ B) ∧ (¬B ∨ C) ∧ (¬C) ∧ (¬A)\land (\lnot B)\land(A)$
|
||||
- $(\lnot A\land A)\vDash ()\implies(A ∨ B) ∧ (¬B ∨ C) ∧ (¬C) ∧ (¬A)\land (\lnot B)\land(A)\land ()\implies False$
|
||||
- 确定是否$KB⊨α$:
|
||||
- 将$(KB∧\lnotα)$转换为合取范式。
|
||||
- 继续检查,看看我们是否可以使用归结来生成一个新的从句。
|
||||
- 如果我们生成了空从句(相当于 False),那么恭喜你!我们得出了一个矛盾,从而证明了$KB⊨α$。
|
||||
- 然而,如果没有实现矛盾,并且不能推断出更多的从句,那么就没有蕴含性。
|
||||
- 以下是一个示例,说明了该算法的工作原理:
|
||||
- $(A ∨ B) ∧ (¬B ∨ C) ∧ (¬C)\vDash A?$
|
||||
- $(A ∨ B) ∧ (¬B ∨ C) ∧ (¬C) ∧ (¬A)$
|
||||
- $(\lnot B\lor C)\land\lnot C\vDash\lnot B\implies(A ∨ B) ∧ (¬B ∨ C) ∧ (¬C) ∧ (¬A)\land (\lnot B)$
|
||||
- $(A\lor B)\land\lnot B\vDash A\implies(A ∨ B) ∧ (¬B ∨ C) ∧ (¬C) ∧ (¬A)\land (\lnot B)\land(A)$
|
||||
- $(\lnot A\land A)\vDash ()\implies(A ∨ B) ∧ (¬B ∨ C) ∧ (¬C) ∧ (¬A)\land (\lnot B)\land(A)\land ()\implies False$
|
||||
|
||||
# 一阶逻辑(First Order Logic)
|
||||
## 一阶逻辑 (First Order Logic)
|
||||
|
||||
- 一阶逻辑是另一种类型的逻辑,它使我们能够比命题逻辑更简洁地表达更复杂的想法。一阶逻辑使用两种类型的符号:常量符号和谓词符号。常量符号表示对象,而谓词符号类似于接受参数并返回 true 或 false 值的关系或函数。
|
||||
- 例如,我们回到霍格沃茨不同的人和家庭作业的逻辑谜题。常量符号是指人或房子,如 Minerva、Pomona、Gryffindor、Hufflepuff 等。谓语符号是一些常量符号的真或虚的属性。例如,我们可以使用句子 `person(Minerva)` 来表达 Minerva 是一个人的想法。同样,我们可以用 `house(Gryffindor)` 这个句子来表达 Gryffindor 是一所房子的想法。所有的逻辑连接词都以与以前相同的方式在一阶逻辑中工作。例如,$\lnot$`House(Minerva)` 表达了 Minerva 不是房子的想法。谓词符号也可以接受两个或多个自变量,并表达它们之间的关系。例如,BelongsTo 表达了两个论点之间的关系,即人和人所属的房子。因此,Minerva 拥有 Gryffindor 的想法可以表达为 `BelongsTo(Minerva,Gryffindor)`。一阶逻辑允许每个人一个符号,每个房子一个符号。这比命题逻辑更简洁,因为命题逻辑中每个人的房屋分配都需要不同的符号。
|
||||
- 全称量化(Universal Quantification)
|
||||
一阶逻辑是另一种类型的逻辑,它使我们能够比命题逻辑更简洁地表达更复杂的想法。一阶逻辑使用两种类型的符号:常量符号和谓词符号。常量符号表示对象,而谓词符号类似于接受参数并返回 true 或 false 值的关系或函数。
|
||||
|
||||
- 量化是一种可以在一阶逻辑中使用的工具,可以在不使用特定常量符号的情况下表示句子。全称量化使用符号$∀$来表示“所有”。例如,$\forall x(BelongsTo(x, Gryffindor) → ¬BelongsTo(x, Hufflepuff))$表达了这样一种观点,即对于每个符号来说,如果这个符号属于 Gryffindor,那么它就不属于 Hufflepuff。
|
||||
- 存在量化(Existential Quantification)
|
||||
例如,我们回到霍格沃茨不同的人和家庭作业的逻辑谜题。常量符号是指人或房子,如 Minerva、Pomona、Gryffindor、Hufflepuff 等。谓语符号是一些常量符号的真或虚的属性。例如,我们可以使用句子 `person(Minerva)` 来表达 Minerva 是一个人的想法。同样,我们可以用 `house(Gryffindor)` 这个句子来表达 Gryffindor 是一所房子的想法。所有的逻辑连接词都以与以前相同的方式在一阶逻辑中工作。例如,$\lnot$`House(Minerva)` 表达了 Minerva 不是房子的想法。谓词符号也可以接受两个或多个自变量,并表达它们之间的关系。例如,BelongsTo 表达了两个论点之间的关系,即人和人所属的房子。因此,Minerva 拥有 Gryffindor 的想法可以表达为 `BelongsTo(Minerva,Gryffindor)`。一阶逻辑允许每个人一个符号,每个房子一个符号。这比命题逻辑更简洁,因为命题逻辑中每个人的房屋分配都需要不同的符号。
|
||||
|
||||
- 存在量化是一个与全称量化平行的概念。然而,虽然全称量化用于创建对所有$x$都成立的句子,但存在量化用于创建至少对一个$x$成立的句子。它使用符号$∃$表示。例如,$∃x(House(x) ∧ BelongsTo(Minerva, x))$ 意味着至少有一个符号既是房子,又是属于 Minerva。换句话说,这表达了Minerva 拥有房子的想法。
|
||||
- 存在量化和全称量化可以用在同一个句子中。例如,$∀x(Person(x) → (∃y(House(y) ∧ BelongsTo(x, y))))$表达了这样一种观点,即如果$x$是一个人,那么这个人至少拥有一个房子$y$。换句话说,这句话的意思是每个人都拥有一所房子。
|
||||
### 全称量化 (Universal Quantification)
|
||||
|
||||
量化是一种可以在一阶逻辑中使用的工具,可以在不使用特定常量符号的情况下表示句子。全称量化使用符号$∀$来表示“所有”。例如,$\forall x(BelongsTo(x, Gryffindor) → ¬BelongsTo(x, Hufflepuff))$表达了这样一种观点,即对于每个符号来说,如果这个符号属于 Gryffindor,那么它就不属于 Hufflepuff。
|
||||
|
||||
### 存在量化 (Existential Quantification)
|
||||
|
||||
存在量化是一个与全称量化平行的概念。然而,虽然全称量化用于创建对所有$x$都成立的句子,但存在量化用于创建至少对一个$x$成立的句子。它使用符号$∃$表示。例如,$∃x(House(x) ∧ BelongsTo(Minerva, x))$ 意味着至少有一个符号既是房子,又是属于 Minerva。换句话说,这表达了 Minerva 拥有房子的想法。
|
||||
|
||||
存在量化和全称量化可以用在同一个句子中。例如,$∀x(Person(x) → (∃y(House(y) ∧ BelongsTo(x, y))))$表达了这样一种观点,即如果$x$是一个人,那么这个人至少拥有一个房子$y$。换句话说,这句话的意思是每个人都拥有一所房子。
|
||||
|
||||
还有其他类型的逻辑,它们之间的共同点是,它们都是为了表示信息而存在的。这些是我们用来在人工智能中表示知识的系统。
|
||||
|
||||
# 补充材料
|
||||
## 补充材料
|
||||
|
||||
Introduction to the Theory of Computation, Third International Edition (Michael Sipser)
|
||||
|
||||
具体数学:计算机科学基础.第 2 版
|
||||
具体数学:计算机科学基础。第 2 版
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# 程序示例
|
||||
|
||||
::: tip
|
||||
阅读程序,然后“玩一玩”程序!
|
||||
|
||||
完成习题
|
||||
:::
|
||||
|
||||
|
||||
::: tip 📥
|
||||
本节附件下载 <Download url="https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/code/3-Lecture.zip"/>
|
||||
本节附件下载 <Download url="https://cdn.xyxsw.site/code/3-Lecture.zip"/>
|
||||
:::
|
||||
|
||||
本节代码不做额外梳理,[不确定性问题](./4.3.3%E4%B8%8D%E7%A1%AE%E5%AE%9A%E6%80%A7%E9%97%AE%E9%A2%98.md) 中已有解释。
|
||||
@@ -23,20 +23,18 @@
|
||||
6. About 0.327
|
||||
7. About 0.5
|
||||
8. None of the above
|
||||
2. 想象一下,抛出两枚硬币,每枚硬币都有正面和反面,50% 的时间出现正面,50% 的时间出现反面。抛出这两枚硬币后,其中一枚是正面,另一枚是反面的概率是多少?
|
||||
1. 0
|
||||
2. 0.125
|
||||
3. 0.25
|
||||
4. 0.375
|
||||
5. 0.5
|
||||
6. 0.625
|
||||
7. 0.75
|
||||
8. 0.875
|
||||
9. 1
|
||||
3. 回答关于贝叶斯网络的问题,问题如下:
|
||||
|
||||

|
||||
|
||||
2. 想象一下,抛出两枚硬币,每枚硬币都有正面和反面,50% 的时间出现正面,50% 的时间出现反面。抛出这两枚硬币后,其中一枚是正面,另一枚是反面的概率是多少?
|
||||
1. 0
|
||||
2. 0.125
|
||||
3. 0.25
|
||||
4. 0.375
|
||||
5. 0.5
|
||||
6. 0.625
|
||||
7. 0.75
|
||||
8. 0.875
|
||||
9. 1
|
||||
3. 回答关于贝叶斯网络的问题,问题如下:
|
||||

|
||||
以下哪句话是真的?
|
||||
|
||||
1. 假设我们知道有轨道维护,那么是否有雨并不影响列车准时到达的概率。
|
||||
@@ -48,11 +46,11 @@
|
||||
1. 0.008
|
||||
2. 0.012
|
||||
3. 0.024
|
||||
4. 0.028
|
||||
5. 0.02
|
||||
6. 0.06
|
||||
7. 0.12
|
||||
8. 0.2
|
||||
9. 0.429
|
||||
4. 0.028
|
||||
5. 0.02
|
||||
6. 0.06
|
||||
7. 0.12
|
||||
8. 0.2
|
||||
9. 0.429
|
||||
10. 0.6
|
||||
11. None of the above
|
||||
|
||||
@@ -7,76 +7,92 @@
|
||||
:::
|
||||
|
||||
::: tip 📥
|
||||
本节附件下载 <Download url="https://pic-hdu-cs-wiki-1307923872.cos.ap-shanghai.myqcloud.com/code/3-Projects.zip"/>
|
||||
本节附件下载 <Download url="https://cdn.xyxsw.site/code/3-Projects.zip"/>
|
||||
:::
|
||||
|
||||
## 背景
|
||||
|
||||
- GJB2 基因的突变版本是导致新生儿听力障碍的主要原因之一。每个人都携带两个版本的基因,因此每个人都有可能拥有 0、1 或 2 个听力障碍版本的 GJB2 基因。不过,除非一个人接受基因测试,否则要知道一个人拥有多少个变异的 GJB2 基因并不那么容易。这是一些 "隐藏状态":具有我们可以观察到的影响(听力损伤)的信息,但我们不一定直接知道。毕竟,有些人可能有 1 或 2 个突变的 GJB2 基因,但没有表现出听力障碍,而其他人可能没有突变的 GJB2 基因,但仍然表现出听力障碍。
|
||||
- 每个孩子都会从他们的父母那里继承一个 GJB2 基因。如果父母有两个变异基因,那么他们会将变异基因传给孩子;如果父母没有变异基因,那么他们不会将变异基因传给孩子;如果父母有一个变异基因,那么该基因传给孩子的概率为 0.5。不过,在基因被传递后,它有一定的概率发生额外的突变:从导致听力障碍的基因版本转变为不导致听力障碍的版本,或者反过来。
|
||||
- 我们可以尝试通过对所有相关变量形成一个贝叶斯网络来模拟所有这些关系,就像下面这个网络一样,它考虑了一个由两个父母和一个孩子组成的家庭。
|
||||
GJB2 基因的突变版本是导致新生儿听力障碍的主要原因之一。每个人都携带两个版本的基因,因此每个人都有可能拥有 0、1 或 2 个听力障碍版本的 GJB2 基因。不过,除非一个人接受基因测试,否则要知道一个人拥有多少个变异的 GJB2 基因并不那么容易。这是一些 "隐藏状态":具有我们可以观察到的影响(听力损伤)的信息,但我们不一定直接知道。毕竟,有些人可能有 1 或 2 个突变的 GJB2 基因,但没有表现出听力障碍,而其他人可能没有突变的 GJB2 基因,但仍然表现出听力障碍。
|
||||
|
||||

|
||||
每个孩子都会从他们的父母那里继承一个 GJB2 基因。如果父母有两个变异基因,那么他们会将变异基因传给孩子;如果父母没有变异基因,那么他们不会将变异基因传给孩子;如果父母有一个变异基因,那么该基因传给孩子的概率为 0.5。不过,在基因被传递后,它有一定的概率发生额外的突变:从导致听力障碍的基因版本转变为不导致听力障碍的版本,或者反过来。
|
||||
|
||||
- 家庭中的每个人都有一个 `Gene` 随机变量,代表一个人有多少个特定基因(例如,GJB2 的听力障碍版本):一个 0、1 或 2 的值。家族中的每个人也有一个 `Trait` 随机变量,它是 `yes` 或 `no`,取决于该人是否表达基于该基因的性状(例如,听力障碍)。从每个人的 `Gene` 变量到他们的 `Trait` 变量之间有一个箭头,以编码一个人的基因影响他们具有特定性状的概率的想法。同时,也有一个箭头从母亲和父亲的 `Gene` 随机变量到他们孩子的 `Gene` 随机变量:孩子的基因取决于他们父母的基因。
|
||||
- 你在这个项目中的任务是使用这个模型对人群进行推断。给出人们的信息,他们的父母是谁,以及他们是否具有由特定基因引起的特定可观察特征(如听力损失),你的人工智能将推断出每个人的基因的概率分布,以及任何一个人是否会表现出有关特征的概率分布。
|
||||
我们可以尝试通过对所有相关变量形成一个贝叶斯网络来模拟所有这些关系,就像下面这个网络一样,它考虑了一个由两个父母和一个孩子组成的家庭。
|
||||
|
||||

|
||||
|
||||
家庭中的每个人都有一个 `Gene` 随机变量,代表一个人有多少个特定基因(例如,GJB2 的听力障碍版本):一个 0、1 或 2 的值。家族中的每个人也有一个 `Trait` 随机变量,它是 `yes` 或 `no`,取决于该人是否表达基于该基因的性状(例如,听力障碍)。从每个人的 `Gene` 变量到他们的 `Trait` 变量之间有一个箭头,以编码一个人的基因影响他们具有特定性状的概率的想法。同时,也有一个箭头从母亲和父亲的 `Gene` 随机变量到他们孩子的 `Gene` 随机变量:孩子的基因取决于他们父母的基因。
|
||||
|
||||
你在这个项目中的任务是使用这个模型对人群进行推断。给出人们的信息,他们的父母是谁,以及他们是否具有由特定基因引起的特定可观察特征(如听力损失),你的人工智能将推断出每个人的基因的概率分布,以及任何一个人是否会表现出有关特征的概率分布。
|
||||
|
||||
## 理解
|
||||
|
||||
- 打开 `data/family0.csv`,看看数据目录中的一个样本数据集(你可以在文本编辑器中打开,或者在 Google Sheets、Excel 或 Apple Numbers 等电子表格应用程序中打开)。注意,第一行定义了这个 CSV 文件的列:`name`, `mother`, `father`, 和 `trait`。下一行表明 Harry 的母亲是 Lily,父亲是 James,而 `Trait` 的空单元格意味着我们不知道 Harry 是否有这种性状。同时,James 在我们的数据集中没有列出父母(如母亲和父亲的空单元格所示),但确实表现出了性状(如 `Trait` 单元格中的 1 所示)。另一方面,Lily 在数据集中也没有列出父母,但没有表现出这种性状(如 `Trait` 单元格中的 0 表示)。
|
||||
- 打开 `heredity.py`,首先看一下 `PROBS` 的定义。`PROBS` 是一个包含若干常数的字典,代表各种不同事件的概率。所有这些事件都与一个人拥有多少个特定的突变基因,以及一个人是否基于该基因表现出特定的性状有关。这里的数据松散地基于 GJB2 基因的听力障碍版本和听力障碍性状的概率,但通过改变这些值,你也可以用你的人工智能来推断其他的基因和性状!
|
||||
- 首先,`PROBS["gene"]` 代表了该基因的无条件概率分布(即如果我们对该人的父母一无所知的概率)。根据分布代码中的数据,在人群中,有 1% 的机会拥有该基因的 2 个副本,3% 的机会拥有该基因的 1 个副本,96% 的机会拥有该基因的零副本。
|
||||
- 接下来,`PROBS["trait"]` 表示一个人表现出某种性状(如听力障碍)的条件概率。这实际上是三个不同的概率分布:基因的每个可能值都有一个。因此,`PROBS["trait"][2]` 是一个人在有两个突变基因的情况下具有该特征的概率分布:在这种情况下,他们有 65% 的机会表现出该特征,而有 35% 的机会不表现出该特征。同时,如果一个人有 0 个变异基因,他们有 1% 的机会表现出该性状,99% 的机会不表现出该性状。
|
||||
- 最后,`PROBS["mutation"]` 是一个基因从作为相关基因突变为不是该基因的概率,反之亦然。例如,如果一个母亲有两个变异基因,并因此将其中一个传给她的孩子,就有 1% 的机会突变为不再是变异基因。相反,如果一个母亲没有任何变异基因,因此没有把变异基因传给她的孩子,但仍有 1% 的机会突变为变异基因。因此,即使父母双方都没有变异基因,他们的孩子也可能有 1 个甚至 2 个变异基因。
|
||||
- 最终,你计算的概率将以 `PROBS` 中的这些数值为基础。
|
||||
- 现在,看一下 `main` 函数。该函数首先将数据从一个文件加载到一个字典 `people` 中。`people` 将每个人的名字映射到另一个包含他们信息的字典中:包括他们的名字,他们的母亲(如果数据集中有一个母亲),他们的父亲(如果数据集中有一个父亲),以及他们是否被观察到有相关的特征(如果有则为 `True`,没有则为 `False`,如果我们不知道则为 `None`)。
|
||||
- 接下来,`main` 中定义了一个字典 `probabilities`,所有的概率最初都设置为 0。这就是你的项目最终要计算的内容:对于每个人,你的人工智能将计算他们有多少个变异基因的概率分布,以及他们是否具有该性状。例如,`probabilities["Harry"]["gene"][1]` 将是 Harry 有 1 个变异基因的概率,而 `probabilities["Lily"]["trait"][False]` 将是 Lily 没有表现出该性状的概率。
|
||||
- 如果不熟悉的话,这个 `probabilities` 字典是用 [python 字典](https://www.python.org/dev/peps/pep-0274/)创建的,在这种情况下,它为我们的 `people` 中的每个 `person` 创建一个键/值对。
|
||||
- 最终,我们希望根据一些证据来计算这些概率:鉴于我们知道某些人有或没有这种特征,我们想确定这些概率。你在这个项目中的任务是实现三个函数来做到这一点: `joint_probability` 计算一个联合概率,`update` 将新计算的联合概率添加到现有的概率分布中,然后 `normalize` 以确保所有概率分布最后和为 1。
|
||||
打开 `data/family0.csv`,看看数据目录中的一个样本数据集(你可以在文本编辑器中打开,或者在 Google Sheets、Excel 或 Apple Numbers 等电子表格应用程序中打开)。注意,第一行定义了这个 CSV 文件的列:`name`, `mother`, `father`, 和 `trait`。下一行表明 Harry 的母亲是 Lily,父亲是 James,而 `Trait` 的空单元格意味着我们不知道 Harry 是否有这种性状。同时,James 在我们的数据集中没有列出父母(如母亲和父亲的空单元格所示),但确实表现出了性状(如 `Trait` 单元格中的 1 所示)。另一方面,Lily 在数据集中也没有列出父母,但没有表现出这种性状(如 `Trait` 单元格中的 0 表示)。
|
||||
|
||||
打开 `heredity.py`,首先看一下 `PROBS` 的定义。`PROBS` 是一个包含若干常数的字典,代表各种不同事件的概率。所有这些事件都与一个人拥有多少个特定的突变基因,以及一个人是否基于该基因表现出特定的性状有关。这里的数据松散地基于 GJB2 基因的听力障碍版本和听力障碍性状的概率,但通过改变这些值,你也可以用你的人工智能来推断其他的基因和性状!
|
||||
|
||||
首先,`PROBS["gene"]` 代表了该基因的无条件概率分布(即如果我们对该人的父母一无所知的概率)。根据分布代码中的数据,在人群中,有 1% 的机会拥有该基因的 2 个副本,3% 的机会拥有该基因的 1 个副本,96% 的机会拥有该基因的零副本。
|
||||
|
||||
接下来,`PROBS["trait"]` 表示一个人表现出某种性状(如听力障碍)的条件概率。这实际上是三个不同的概率分布:基因的每个可能值都有一个。因此,`PROBS["trait"][2]` 是一个人在有两个突变基因的情况下具有该特征的概率分布:在这种情况下,他们有 65% 的机会表现出该特征,而有 35% 的机会不表现出该特征。同时,如果一个人有 0 个变异基因,他们有 1% 的机会表现出该性状,99% 的机会不表现出该性状。
|
||||
|
||||
最后,`PROBS["mutation"]` 是一个基因从作为相关基因突变为不是该基因的概率,反之亦然。例如,如果一个母亲有两个变异基因,并因此将其中一个传给她的孩子,就有 1% 的机会突变为不再是变异基因。相反,如果一个母亲没有任何变异基因,因此没有把变异基因传给她的孩子,但仍有 1% 的机会突变为变异基因。因此,即使父母双方都没有变异基因,他们的孩子也可能有 1 个甚至 2 个变异基因。
|
||||
|
||||
最终,你计算的概率将以 `PROBS` 中的这些数值为基础。
|
||||
|
||||
现在,看一下 `main` 函数。该函数首先将数据从一个文件加载到一个字典 `people` 中。`people` 将每个人的名字映射到另一个包含他们信息的字典中:包括他们的名字,他们的母亲(如果数据集中有一个母亲),他们的父亲(如果数据集中有一个父亲),以及他们是否被观察到有相关的特征(如果有则为 `True`,没有则为 `False`,如果我们不知道则为 `None`)。
|
||||
接下来,`main` 中定义了一个字典 `probabilities`,所有的概率最初都设置为 0。这就是你的项目最终要计算的内容:对于每个人,你的人工智能将计算他们有多少个变异基因的概率分布,以及他们是否具有该性状。例如,`probabilities["Harry"]["gene"][1]` 将是 Harry 有 1 个变异基因的概率,而 `probabilities["Lily"]["trait"][False]` 将是 Lily 没有表现出该性状的概率。
|
||||
|
||||
如果不熟悉的话,这个 `probabilities` 字典是用 [python 字典](https://www.python.org/dev/peps/pep-0274/)创建的,在这种情况下,它为我们的 `people` 中的每个 `person` 创建一个键/值对。
|
||||
|
||||
最终,我们希望根据一些证据来计算这些概率:鉴于我们知道某些人有或没有这种特征,我们想确定这些概率。你在这个项目中的任务是实现三个函数来做到这一点: `joint_probability` 计算一个联合概率,`update` 将新计算的联合概率添加到现有的概率分布中,然后 `normalize` 以确保所有概率分布最后和为 1。
|
||||
|
||||
## 明确
|
||||
|
||||
- 完成 `joint_probability`、`update` 和 `normalize` 的实现。
|
||||
- `joint_probability` 函数应该接受一个 `people` 的字典作为输入,以及关于谁拥有多少个变异基因,以及谁表现出该特征的数据。该函数应该返回所有这些事件发生的联合概率。
|
||||
完成 `joint_probability`、`update` 和 `normalize` 的实现。
|
||||
|
||||
- 该函数接受四个数值作为输入:`people`, `one_gene`, `two_genes`, 和 `have_trait`。
|
||||
`joint_probability` 函数应该接受一个 `people` 的字典作为输入,以及关于谁拥有多少个变异基因,以及谁表现出该特征的数据。该函数应该返回所有这些事件发生的联合概率。
|
||||
|
||||
- `people` 是一个在 "理解"一节中描述的人的字典。键代表名字,值是包含 `mother` 和 `father` 键的字典。你可以假设 `mother` 和 `father` 都是空白的(数据集中没有父母的信息),或者 `mother` 和 `father` 都会指代 `people` 字典中的其他人物。
|
||||
- `one_gene` 是一个集合,我们想计算所有集合元素有一个变异基因的概率。
|
||||
- `two_genes` 是一个集合,我们想计算所有集合元素有两个变异基因的概率。
|
||||
- `have_trait` 是一个集合,我们想计算所有集合元素拥有该性状的概率。
|
||||
- 对于不在 `one_gene` 或 t `wo_genes` 中的人,我们想计算他们没有变异基因的概率;对于不在 `have_trait` 中的人,我们想计算他们没有该性状的概率。
|
||||
|
||||
- 例如,如果这个家庭由 Harry、James 和 Lily 组成,那么在 `one_gene = {"Harry"}`、`two_genes = {"James"}` 和 `trait = {"Harry"、"James"}` 的情况下调用这个函数,应该计算出 Lily 没有变异基因、Harry 拥有一个变异基因、James 拥有两个变异基因、Harry 表现出该性状、James 表现出该性状和 Lily 没有表现出该性状的联合概率。
|
||||
- 对于数据集中没有列出父母的人,使用概率分布 `PROBS["gene"]` 来确定他们有特定数量基因的概率。
|
||||
- 对于数据集中有父母的人来说,每个父母都会把他们的两个基因中的一个随机地传给他们的孩子,而且有一个 `PROBS["mutation"]` 的机会,即它会发生突变(从变异基因变成正常基因,或者相反)。
|
||||
- 使用概率分布 `PROBS["trait"]` 来计算一个人具有或不具有形状的概率。
|
||||
- `update` 函数将一个新的联合分布概率添加到 `probabilities` 中的现有概率分布中。
|
||||
- 该函数接受四个数值作为输入:`people`, `one_gene`, `two_genes`, 和 `have_trait`。
|
||||
|
||||
- 该函数接受五个值作为输入:`probabilities`, `one_gene`, `two_genes`, `have_trait`, 和 `p`。
|
||||
- `people` 是一个在 "理解"一节中描述的人的字典。键代表名字,值是包含 `mother` 和 `father` 键的字典。你可以假设 `mother` 和 `father` 都是空白的(数据集中没有父母的信息),或者 `mother` 和 `father` 都会指代 `people` 字典中的其他人物。
|
||||
- `one_gene` 是一个集合,我们想计算所有集合元素有一个变异基因的概率。
|
||||
- `two_genes` 是一个集合,我们想计算所有集合元素有两个变异基因的概率。
|
||||
- `have_trait` 是一个集合,我们想计算所有集合元素拥有该性状的概率。
|
||||
- 对于不在 `one_gene` 或 t `wo_genes` 中的人,我们想计算他们没有变异基因的概率;对于不在 `have_trait` 中的人,我们想计算他们没有该性状的概率。
|
||||
|
||||
- `probabilities` 是一个在 "理解 "部分提到的字典。每个人都被映射到一个 `"gene"` 分布和一个 `"trait"` 分布。
|
||||
- `one_gene` 是一个集合,我们想计算所有集合元素有一个变异基因的概率。
|
||||
- `two_genes` 是一个集合,我们想计算所有集合元素有两个变异基因的概率。
|
||||
- `have_trait` 是一个集合,我们想计算所有集合元素拥有该性状的概率。
|
||||
- `p` 是联合分布的概率。
|
||||
- 对于概率中的每个人,该函数应该更新 `probabilities[person]["gene"]` 分布和 `probabilities[person]["trait"]` 分布,在每个分布中的适当数值上加上 `p`。所有其他数值应保持不变。
|
||||
- 例如,如果"Harry"同时出现在 `two_genes` 和 `have_trait` 中,那么 `p` 将被添加到 `probabilities["Harry"]["gene"][2]` 和 `probabilities["Harry"]["trait"][True]`。
|
||||
- 该函数不应返回任何值:它只需要更新 `probabilities` 字典。
|
||||
- `normalize` 函数更新 `probabilities` 字典,使每个概率分布被归一化(即和为 1,相对比例相同)。
|
||||
- 例如,如果这个家庭由 Harry、James 和 Lily 组成,那么在 `one_gene = {"Harry"}`、`two_genes = {"James"}` 和 `trait = {"Harry"、"James"}` 的情况下调用这个函数,应该计算出 Lily 没有变异基因、Harry 拥有一个变异基因、James 拥有两个变异基因、Harry 表现出该性状、James 表现出该性状和 Lily 没有表现出该性状的联合概率。
|
||||
- 对于数据集中没有列出父母的人,使用概率分布 `PROBS["gene"]` 来确定他们有特定数量基因的概率。
|
||||
- 对于数据集中有父母的人来说,每个父母都会把他们的两个基因中的一个随机地传给他们的孩子,而且有一个 `PROBS["mutation"]` 的机会,即它会发生突变(从变异基因变成正常基因,或者相反)。
|
||||
- 使用概率分布 `PROBS["trait"]` 来计算一个人具有或不具有形状的概率。
|
||||
|
||||
- 该函数接受一个单一的值:`probabilities`。
|
||||
`update` 函数将一个新的联合分布概率添加到 `probabilities` 中的现有概率分布中。
|
||||
|
||||
- `probabilities` 是一个在"理解"部分提到的字典。每个人都被映射到一个 `"gene"` 分布和一个 `"trait"` 分布。
|
||||
- 对于 `probabilities` 中每个人的两个分布,这个函数应该将该分布归一化,使分布中的数值之和为 1,分布中的相对数值是相同的。
|
||||
- 例如,如果 `probabilities["Harry"]["trait"][True]` 等于 `0.1`,概率 `probabilities["Harry"]["trait"][False]` 等于 `0.3`,那么你的函数应该将前一个值更新为 `0.25`,后一个值更新为 `0.75`: 现在数字之和为 1,而且后一个值仍然比前一个值大三倍。
|
||||
- 该函数不应返回任何值:它只需要更新 `probabilities` 字典。
|
||||
- 除了规范中要求你实现的三个函数外,你不应该修改 `heredity.py` 中的任何其他东西,尽管你可以编写额外的函数和/或导入其他 Python 标准库模块。如果熟悉的话,你也可以导入 `numpy` 或 `pandas`,但是你不应该使用任何其他第三方 Python 模块。
|
||||
- 该函数接受五个值作为输入:`probabilities`, `one_gene`, `two_genes`, `have_trait`, 和 `p`。
|
||||
|
||||
- `probabilities` 是一个在 "理解 "部分提到的字典。每个人都被映射到一个 `"gene"` 分布和一个 `"trait"` 分布。
|
||||
- `one_gene` 是一个集合,我们想计算所有集合元素有一个变异基因的概率。
|
||||
- `two_genes` 是一个集合,我们想计算所有集合元素有两个变异基因的概率。
|
||||
- `have_trait` 是一个集合,我们想计算所有集合元素拥有该性状的概率。
|
||||
- `p` 是联合分布的概率。
|
||||
- 对于概率中的每个人,该函数应该更新 `probabilities[person]["gene"]` 分布和 `probabilities[person]["trait"]` 分布,在每个分布中的适当数值上加上 `p`。所有其他数值应保持不变。
|
||||
- 例如,如果"Harry"同时出现在 `two_genes` 和 `have_trait` 中,那么 `p` 将被添加到 `probabilities["Harry"]["gene"][2]` 和 `probabilities["Harry"]["trait"][True]`。
|
||||
- 该函数不应返回任何值:它只需要更新 `probabilities` 字典。
|
||||
|
||||
`normalize` 函数更新 `probabilities` 字典,使每个概率分布被归一化(即和为 1,相对比例相同)。
|
||||
|
||||
- 该函数接受一个单一的值:`probabilities`。
|
||||
|
||||
- `probabilities` 是一个在"理解"部分提到的字典。每个人都被映射到一个 `"gene"` 分布和一个 `"trait"` 分布。
|
||||
- 对于 `probabilities` 中每个人的两个分布,这个函数应该将该分布归一化,使分布中的数值之和为 1,分布中的相对数值是相同的。
|
||||
- 例如,如果 `probabilities["Harry"]["trait"][True]` 等于 `0.1`,概率 `probabilities["Harry"]["trait"][False]` 等于 `0.3`,那么你的函数应该将前一个值更新为 `0.25`,后一个值更新为 `0.75`: 现在数字之和为 1,而且后一个值仍然比前一个值大三倍。
|
||||
- 该函数不应返回任何值:它只需要更新 `probabilities` 字典。
|
||||
|
||||
除了规范中要求你实现的三个函数外,你不应该修改 `heredity.py` 中的任何其他东西,尽管你可以编写额外的函数和/或导入其他 Python 标准库模块。如果熟悉的话,你也可以导入 `numpy` 或 `pandas`,但是你不应该使用任何其他第三方 Python 模块。
|
||||
|
||||
## 一个联合概率例子
|
||||
|
||||
- 为了帮助你思考如何计算联合概率,我们在下面附上一个例子。
|
||||
- 请考虑以下 `people` 的值:
|
||||
为了帮助你思考如何计算联合概率,我们在下面附上一个例子。
|
||||
|
||||
请考虑以下 `people` 的值:
|
||||
|
||||
```python
|
||||
{
|
||||
@@ -86,12 +102,17 @@
|
||||
}
|
||||
```
|
||||
|
||||
- 这里我们将展示 `joint_probability(people, {"Harry"}, {"James"}, {"James"})` 的计算。根据参数,`one_gene` 是 `{"Harry"}`,`two_genes` 是 `{"James"}`,而 `has_trait` 是 `{"James"}`。因此,这代表了以下的概率:Lily 没有变异基因,不具有该性状;Harry 有一个变异基因,不具有该性状;James 有 2 个变异基因,具有该性状。
|
||||
- 我们从 Lily 开始(我们考虑人的顺序并不重要,只要我们把正确的数值乘在一起,因为乘法是可交换的)。Lily 没有变异基因,概率为 `0.96`(这就是 `PROBS["gene"][0]`)。鉴于她没有变异基因,她没有这个性状的概率为 `0.99`(这是 `PROBS["trait"][0][False]`)。因此,她没有变异基因且没有该性状的概率是 `0.96*0.99=0.9504`。
|
||||
- 接下来,我们考虑 James。James 有 2 个变异基因,概率为 `0.01`(这是 `PROBS["gene"][2]`)。鉴于他有 2 个变异基因,他确实具有该性状的概率为 `0.65`。因此,他有 2 个变异基因并且他确实具有该性状的概率是 `0.01*0.65=0.0065`。
|
||||
- 最后,我们考虑 Harry。Harry 有 1 个变异基因的概率是多少?有两种情况可以发生。要么他从母亲那里得到这个基因,而不是从父亲那里,要么他从父亲那里得到这个基因,而不是从母亲那里。他的母亲 Lily 没有变异基因,所以 Harry 会以 `0.01` 的概率从他母亲那里得到这个基因(这是 `PROBS["mutation"]`),因为从他母亲那里得到这个基因的唯一途径是基因突变;相反,Harry 不会从他母亲那里得到这个基因,概率是 `0.99`。他的父亲 James 有 2 个变异基因,所以 Harry 会以 `0.99` 的概率从他父亲那里得到这个基因(这是 `1-PROBS["mutation"]`),但会以 `0.01` 的概率从他母亲那里得到这个基因(突变的概率)。这两种情况加在一起可以得到 `0.99*0.99+0.01*0.01=0.9802`,即 Harry 有 1 个变异基因的概率。
|
||||
- 考虑到 Harry 有 1 个变异基因,他没有该性状的概率是 `0.44`(这是 `PROBS["trait"][1][false]`)。因此,哈利有 1 个变异基因而没有该性状的概率是 `0.9802 * 0.44 = 0.431288`。
|
||||
- 因此,整个联合概率是三个人中每个人的所有这些数值相乘的结果: `0.9504 * 0.0065 * 0.431288 = 0.0026643247488`。
|
||||
这里我们将展示 `joint_probability(people, {"Harry"}, {"James"}, {"James"})` 的计算。根据参数,`one_gene` 是 `{"Harry"}`,`two_genes` 是 `{"James"}`,而 `has_trait` 是 `{"James"}`。因此,这代表了以下的概率:Lily 没有变异基因,不具有该性状;Harry 有一个变异基因,不具有该性状;James 有 2 个变异基因,具有该性状。
|
||||
|
||||
我们从 Lily 开始(我们考虑人的顺序并不重要,只要我们把正确的数值乘在一起,因为乘法是可交换的)。Lily 没有变异基因,概率为 `0.96`(这就是 `PROBS["gene"][0]`)。鉴于她没有变异基因,她没有这个性状的概率为 `0.99`(这是 `PROBS["trait"][0][False]`)。因此,她没有变异基因且没有该性状的概率是 `0.96*0.99=0.9504`。
|
||||
|
||||
接下来,我们考虑 James。James 有 2 个变异基因,概率为 `0.01`(这是 `PROBS["gene"][2]`)。鉴于他有 2 个变异基因,他确实具有该性状的概率为 `0.65`。因此,他有 2 个变异基因并且他确实具有该性状的概率是 `0.01*0.65=0.0065`。
|
||||
|
||||
最后,我们考虑 Harry。Harry 有 1 个变异基因的概率是多少?有两种情况可以发生。要么他从母亲那里得到这个基因,而不是从父亲那里,要么他从父亲那里得到这个基因,而不是从母亲那里。他的母亲 Lily 没有变异基因,所以 Harry 会以 `0.01` 的概率从他母亲那里得到这个基因(这是 `PROBS["mutation"]`),因为从他母亲那里得到这个基因的唯一途径是基因突变;相反,Harry 不会从他母亲那里得到这个基因,概率是 `0.99`。他的父亲 James 有 2 个变异基因,所以 Harry 会以 `0.99` 的概率从他父亲那里得到这个基因(这是 `1-PROBS["mutation"]`),但会以 `0.01` 的概率从他母亲那里得到这个基因(突变的概率)。这两种情况加在一起可以得到 `0.99*0.99+0.01*0.01=0.9802`,即 Harry 有 1 个变异基因的概率。
|
||||
|
||||
考虑到 Harry 有 1 个变异基因,他没有该性状的概率是 `0.44`(这是 `PROBS["trait"][1][false]`)。因此,哈利有 1 个变异基因而没有该性状的概率是 `0.9802 * 0.44 = 0.431288`。
|
||||
|
||||
因此,整个联合概率是三个人中每个人的所有这些数值相乘的结果:`0.9504 * 0.0065 * 0.431288 = 0.0026643247488`。
|
||||
|
||||
## 提示
|
||||
|
||||
|
||||
@@ -1,64 +1,66 @@
|
||||
# 不确定性问题
|
||||
|
||||
- 上一讲中,我们讨论了人工智能如何表示和推导新知识。然而,在现实中,人工智能往往对世界只有部分了解,这给不确定性留下了空间。尽管如此,我们还是希望我们的人工智能在这些情况下做出尽可能好的决定。例如,在预测天气时,人工智能掌握了今天的天气信息,但无法 100% 准确地预测明天的天气。尽管如此,我们可以做得比偶然更好,今天的讲座是关于我们如何创造人工智能,在有限的信息和不确定性的情况下做出最佳决策。
|
||||
上一讲中,我们讨论了人工智能如何表示和推导新知识。然而,在现实中,人工智能往往对世界只有部分了解,这给不确定性留下了空间。尽管如此,我们还是希望我们的人工智能在这些情况下做出尽可能好的决定。例如,在预测天气时,人工智能掌握了今天的天气信息,但无法 100% 准确地预测明天的天气。尽管如此,我们可以做得比偶然更好,今天的讲座是关于我们如何创造人工智能,在有限的信息和不确定性的情况下做出最佳决策。
|
||||
|
||||
## 概率(Probability)
|
||||
## 概率 (Probability)
|
||||
|
||||
- 不确定性可以表示为多个事件以及每一个事件发生的可能性或概率。
|
||||
不确定性可以表示为多个事件以及每一个事件发生的可能性或概率。
|
||||
|
||||
### 概率世界
|
||||
|
||||
- 每一种可能的情况都可以被视为一个世界,由小写的希腊字母$ω$表示。例如,掷骰子可以产生六个可能的世界:骰子出现 1 的世界,骰子出现 2 的世界,依此类推。为了表示某个世界的概率,我们写$P(ω)$。
|
||||
每一种可能的情况都可以被视为一个世界,由小写的希腊字母$ω$表示。例如,掷骰子可以产生六个可能的世界:骰子出现 1 的世界,骰子出现 2 的世界,依此类推。为了表示某个世界的概率,我们写$P(ω)$。
|
||||
|
||||
### 概率公理
|
||||
|
||||
- $0<P(ω)<1$ :表示概率的每个值必须在0和1之间。
|
||||
- 0是一个不可能发生的事件,就像掷一个标准骰子并出现7一样。
|
||||
- 1是肯定会发生的事件,比如掷标准骰子,得到的值小于10。
|
||||
- $0<P(ω)<1$ :表示概率的每个值必须在 0 和 1 之间。
|
||||
- 0 是一个不可能发生的事件,就像掷一个标准骰子并出现 7 一样。
|
||||
- 1 是肯定会发生的事件,比如掷标准骰子,得到的值小于 10。
|
||||
- 一般来说,值越高,事件发生的可能性就越大。
|
||||
- 每一个可能发生的事件的概率加在一起等于 1。
|
||||
|
||||
$
|
||||
\sum_{\omega\in\Omega}P(\omega)=1
|
||||
$
|
||||
$$\sum_{\omega\in\Omega}P(\omega)=1$$
|
||||
|
||||
- 用标准骰子掷出数字 R 的概率可以表示为 $P(R)$ 。在我们的例子中,$P(R)=1/6$ ,因为有六个可能的世界(从 1 到 6 的任何数字),并且每个世界有相同的可能性发生。现在,考虑掷两个骰子的事件。现在,有 36 个可能的事件,同样有相同的可能性发生。
|
||||
用标准骰子掷出数字 R 的概率可以表示为 $P(R)$ 。在我们的例子中,$P(R)=1/6$ ,因为有六个可能的世界(从 1 到 6 的任何数字),并且每个世界有相同的可能性发生。现在,考虑掷两个骰子的事件。现在,有 36 个可能的事件,同样有相同的可能性发生。
|
||||
|
||||

|
||||

|
||||
|
||||
- 然而,如果我们试图预测两个骰子的总和,会发生什么?在这种情况下,我们只有 11 个可能的值(总和必须在 2 到 12 之间),而且它们的出现频率并不相同。
|
||||
然而,如果我们试图预测两个骰子的总和,会发生什么?在这种情况下,我们只有 11 个可能的值(总和必须在 2 到 12 之间),而且它们的出现频率并不相同。
|
||||
|
||||

|
||||

|
||||
|
||||
- 为了得到事件发生的概率,我们将事件发生的世界数量除以可能发生的世界总数。例如,当掷两个骰子时,有 36 个可能的世界。只有在其中一个世界中,当两个骰子都得到 6 时,我们才能得到 12 的总和。因此,$P(12)=\frac{1}{36}$,或者,换句话说,掷两个骰子并得到两个和为 12 的数字的概率是$\frac{1}{36}$。$P(7)$是多少?我们数了数,发现和 7 出现在 6 个世界中。因此,$P(7)=\frac{6}{36}=\frac{1}{6}$。
|
||||
为了得到事件发生的概率,我们将事件发生的世界数量除以可能发生的世界总数。例如,当掷两个骰子时,有 36 个可能的世界。只有在其中一个世界中,当两个骰子都得到 6 时,我们才能得到 12 的总和。因此,$P(12)=\frac{1}{36}$,或者,换句话说,掷两个骰子并得到两个和为 12 的数字的概率是$\frac{1}{36}$。$P(7)$是多少?我们数了数,发现和 7 出现在 6 个世界中。因此,$P(7)=\frac{6}{36}=\frac{1}{6}$。
|
||||
|
||||
### 无条件概率(Unconditional Probability)
|
||||
### 无条件概率 (Unconditional Probability)
|
||||
|
||||
- 无条件概率是指在没有任何其他证据的情况下对命题发生的概率。到目前为止,我们所问的所有问题都是无条件概率的问题,因为掷骰子的结果并不取决于之前的事件。
|
||||
无条件概率是指在没有任何其他证据的情况下对命题发生的概率。到目前为止,我们所问的所有问题都是无条件概率的问题,因为掷骰子的结果并不取决于之前的事件。
|
||||
|
||||
## 条件概率(Conditional Probability)
|
||||
## 条件概率 (Conditional Probability)
|
||||
|
||||
- 条件概率是在给定一些已经揭示的证据的情况下,命题发生的概率。正如引言中所讨论的,人工智能可以利用部分信息对未来进行有根据的猜测。为了使用这些影响事件在未来发生概率的信息,我们需要依赖条件概率。
|
||||
- 条件概率用以下符号表示:$P(a|b)$,意思是“如果我们知道事件$b$已经发生,事件$a$发生的概率”,或者更简洁地说,“给定$b$的概率”。现在我们可以问一些问题,比如如果昨天下雨,今天下雨的概率是多少$P(今天下雨 | 昨天下雨)$,或者给定患者的测试结果,患者患有该疾病的概率 $P(疾病 | 测试结果)$ 是多少。
|
||||
- 在数学上,为了计算给定$b$的条件概率,我们使用公式:$P(a|b)=\frac{P(a\land b)}{P(b)}$
|
||||
- 换句话说,给定$b$为真的概率等于$a$并且$b$为真,除以$b$的概率。对此进行推理的一种直观方式是认为“我们对$a$并且$b$都为真的事件(分子)感兴趣,但只对我们知道$b$为真(分母)的世界感兴趣。“除以 $b$ 将可能的世界限制在 $b$ 为真的世界。以下是上述公式的代数等价形式:
|
||||
条件概率是在给定一些已经揭示的证据的情况下,命题发生的概率。正如引言中所讨论的,人工智能可以利用部分信息对未来进行有根据的猜测。为了使用这些影响事件在未来发生概率的信息,我们需要依赖条件概率。
|
||||
|
||||
条件概率用以下符号表示:$P(a|b)$,意思是“如果我们知道事件$b$已经发生,事件$a$发生的概率”,或者更简洁地说,“给定$b$的概率”。现在我们可以问一些问题,比如如果昨天下雨,今天下雨的概率是多少$P(今天下雨 | 昨天下雨)$,或者给定患者的测试结果,患者患有该疾病的概率 $P(疾病 | 测试结果)$ 是多少。
|
||||
|
||||
在数学上,为了计算给定$b$的条件概率,我们使用公式:$P(a|b)=\frac{P(a\land b)}{P(b)}$
|
||||
|
||||
换句话说,给定$b$为真的概率等于$a$并且$b$为真,除以$b$的概率。对此进行推理的一种直观方式是认为“我们对$a$并且$b$都为真的事件(分子)感兴趣,但只对我们知道$b$为真(分母)的世界感兴趣。“除以 $b$ 将可能的世界限制在 $b$ 为真的世界。以下是上述公式的代数等价形式:
|
||||
|
||||
$P(a\land b)=P(b)P(a|b)$
|
||||
|
||||
$P(a\land b)=P(a)P(b|a)$
|
||||
|
||||
- 例如,考虑$P(总和为12|在一个骰子上掷出6)$,或者掷两个骰子假设我们已经掷了一个骰子并获得了六,得到十二的概率。为了计算这一点,我们首先将我们的世界限制在第一个骰子的值为六的世界:
|
||||
例如,考虑$P(总和为 12|在一个骰子上掷出 6)$,或者掷两个骰子假设我们已经掷了一个骰子并获得了六,得到十二的概率。为了计算这一点,我们首先将我们的世界限制在第一个骰子的值为六的世界:
|
||||
|
||||

|
||||

|
||||
|
||||
- 现在我们问,在我们将问题限制在(除以$P(6)$,或第一个骰子产生 6 的概率)的世界中,事件 a(和为 12)发生了多少次?
|
||||
现在我们问,在我们将问题限制在(除以$P(6)$,或第一个骰子产生 6 的概率)的世界中,事件 a(和为 12)发生了多少次?
|
||||
|
||||

|
||||

|
||||
|
||||
## 随机变量(Random Variables)
|
||||
## 随机变量 (Random Variables)
|
||||
|
||||
- 随机变量是概率论中的一个变量,它有一个可能取值的域。例如,为了表示掷骰子时的可能结果,我们可以定义一个随机变量 Roll,它可以取值$\set{0,1,2,3,4,5,6}$。为了表示航班的状态,我们可以定义一个变量 flight,它采用$\set{准时、延迟、取消}$的值。
|
||||
- 通常,我们对每个值发生的概率感兴趣。我们用概率分布来表示这一点。例如:
|
||||
随机变量是概率论中的一个变量,它有一个可能取值的域。例如,为了表示掷骰子时的可能结果,我们可以定义一个随机变量 Roll,它可以取值$\set{0,1,2,3,4,5,6}$。为了表示航班的状态,我们可以定义一个变量 flight,它采用$\set{准时、延迟、取消}$的值。
|
||||
|
||||
通常,我们对每个值发生的概率感兴趣。我们用概率分布来表示这一点。例如:
|
||||
|
||||
$P(Flight=准时)=0.6$
|
||||
|
||||
@@ -66,30 +68,37 @@ $P(Flight=延迟)=0.3$
|
||||
|
||||
$P(Flight=取消)=0.1$
|
||||
|
||||
- 用文字来解释概率分布,这意味着航班准时的可能性为 60%,延误的可能性为 30%,取消的可能性为 10%。注意,如前所述,所有可能结果的概率之和为 1。
|
||||
- 概率分布可以更简洁地表示为向量。例如,$P(Flight)=<0.6,0.3,0.1>$。为了便于解释,这些值有一个固定的顺序(在我们的情况下,准时、延迟、取消)。
|
||||
用文字来解释概率分布,这意味着航班准时的可能性为 60%,延误的可能性为 30%,取消的可能性为 10%。注意,如前所述,所有可能结果的概率之和为 1。
|
||||
|
||||
### 独立性(Independence)
|
||||
概率分布可以更简洁地表示为向量。例如,$P(Flight)=<0.6,0.3,0.1>$。为了便于解释,这些值有一个固定的顺序(在我们的情况下,准时、延迟、取消)。
|
||||
|
||||
- 独立性是指一个事件的发生不会影响另一个事件发生的概率。例如,当掷两个骰子时,每个骰子的结果与另一个骰子的结果是独立的。用第一个骰子掷出 4 不会影响我们掷出的第二个骰子的值。这与依赖事件相反,比如早上的云和下午的雨。如果早上多云,下午更有可能下雨,所以这些事件是有依赖性的。
|
||||
- 独立性可以用数学定义:事件$a$和$b$是独立的,当且仅当$a$并且$b$的概率等于$a$的概率乘以$b$的概率:$P(a∧b)=P(a)P(b)$。
|
||||
### 独立性 (Independence)
|
||||
|
||||
## 贝叶斯规则(Bayes’ Rule)
|
||||
独立性是指一个事件的发生不会影响另一个事件发生的概率。例如,当掷两个骰子时,每个骰子的结果与另一个骰子的结果是独立的。用第一个骰子掷出 4 不会影响我们掷出的第二个骰子的值。这与依赖事件相反,比如早上的云和下午的雨。如果早上多云,下午更有可能下雨,所以这些事件是有依赖性的。
|
||||
|
||||
- 贝叶斯规则在概率论中常用来计算条件概率。换句话说,贝叶斯规则说,给定$b$条件下$a$的概率等于给定$a$的条件下$b$概率,乘以$b$的概率除以$a$ 的概率。
|
||||
- $P(b|a)=\frac{P(a|b)P(b)}{P(a)}$
|
||||
- 例如,如果早上有云,我们想计算下午下雨的概率,或者$P(雨|云)$。我们从以下信息开始:
|
||||
独立性可以用数学定义:事件$a$和$b$是独立的,当且仅当$a$并且$b$的概率等于$a$的概率乘以$b$的概率:$P(a∧b)=P(a)P(b)$。
|
||||
|
||||
- 80% 的雨天下午开始于多云的早晨,或$P(云|雨)$。
|
||||
- 40% 的日子早晨多云,或$P(云)$。
|
||||
- 10% 的日子有下雨的下午,或$P(雨)$。
|
||||
- 应用贝叶斯规则,我们计算$\frac{0.8*0.1}{0.4}=0.2$。也就是说,考虑到早上多云,下午下雨的可能性是 20%。
|
||||
- 除了$P(a)$和$P(b)$之外,知道$P(a|b)$还允许我们计算$P(b|a)$。这是有帮助的,因为知道给定未知原因的可见效应的条件概率$P(可见效应|未知原因)$,可以让我们计算给定可见效应的未知原因的概率$P(未知原因|可见效应)$。例如,我们可以通过医学试验来学习$P(医学测试结果|疾病)$,在医学试验中,我们对患有该疾病的人进行测试,并观察测试结果发生的频率。知道了这一点,我们就可以计算出$P(疾病|医学检测结果)$,这是有价值的诊断信息。
|
||||
## 贝叶斯规则 (Bayes’Rule)
|
||||
|
||||
## 联合概率(Joint Probability)
|
||||
贝叶斯规则在概率论中常用来计算条件概率。换句话说,贝叶斯规则说,给定$b$条件下$a$的概率等于给定$a$的条件下$b$概率,乘以$b$的概率除以$a$ 的概率。
|
||||
|
||||
- 联合概率是指多个事件全部发生的可能性。
|
||||
- 让我们考虑下面的例子,关于早上有云,下午有雨的概率。
|
||||
$P(b|a)=\frac{P(a|b)P(b)}{P(a)}$
|
||||
|
||||
例如,如果早上有云,我们想计算下午下雨的概率,或者$P(雨 | 云)$。我们从以下信息开始:
|
||||
|
||||
- 80% 的雨天下午开始于多云的早晨,或$P(云 | 雨)$。
|
||||
- 40% 的日子早晨多云,或$P(云)$。
|
||||
- 10% 的日子有下雨的下午,或$P(雨)$。
|
||||
|
||||
应用贝叶斯规则,我们计算$\frac{0.8*0.1}{0.4}=0.2$。也就是说,考虑到早上多云,下午下雨的可能性是 20%。
|
||||
|
||||
除了$P(a)$和$P(b)$之外,知道$P(a|b)$还允许我们计算$P(b|a)$。这是有帮助的,因为知道给定未知原因的可见效应的条件概率$P(可见效应 | 未知原因)$,可以让我们计算给定可见效应的未知原因的概率$P(未知原因 | 可见效应)$。例如,我们可以通过医学试验来学习$P(医学测试结果 | 疾病)$,在医学试验中,我们对患有该疾病的人进行测试,并观察测试结果发生的频率。知道了这一点,我们就可以计算出$P(疾病 | 医学检测结果)$,这是有价值的诊断信息。
|
||||
|
||||
## 联合概率 (Joint Probability)
|
||||
|
||||
联合概率是指多个事件全部发生的可能性。
|
||||
|
||||
让我们考虑下面的例子,关于早上有云,下午有雨的概率。
|
||||
|
||||
| C=云 | C=$\lnot$云 |
|
||||
| ---- | ----------- |
|
||||
@@ -99,114 +108,116 @@ $P(Flight=取消)=0.1$
|
||||
| ---- | ----------- |
|
||||
| 0.1 | 0.9 |
|
||||
|
||||
- 从这些数据来看,我们无法判断早上的云是否与下午下雨的可能性有关。为了做到这一点,我们需要看看这两个变量所有可能结果的联合概率。我们可以将其表示在下表中:
|
||||
从这些数据来看,我们无法判断早上的云是否与下午下雨的可能性有关。为了做到这一点,我们需要看看这两个变量所有可能结果的联合概率。我们可以将其表示在下表中:
|
||||
|
||||
| | R=雨 | R=$\lnot$ 雨 |
|
||||
| ----------- | ---- | ------------ |
|
||||
| C=云 | 0.08 | 0.32 |
|
||||
| C=$\lnot$云 | 0.02 | 0.58 |
|
||||
|
||||
- 现在我们可以知道有关这些事件同时发生的信息了。例如,我们知道某一天早上有云,下午有雨的概率是 0.08。早上没有云,下午没有雨的概率是 0.58。
|
||||
- 使用联合概率,我们可以推导出条件概率。例如,如果我们感兴趣的是在下午下雨的情况下,早上云层的概率分布。$P(C|雨)=\frac{P(C,雨)}{P(雨)}$旁注:在概率上,逗号和$∧$可以互换使用。因此,$P(C,雨)=P(C\land 雨)$。换句话说,我们将降雨和云层的联合概率除以降雨的概率。
|
||||
- 在最后一个方程中,可以将$P(雨)$视为$P(C,雨)$乘以的某个常数$\alpha=\frac{1}{P(雨)}$。因此,我们可以重写$P(C|雨)=\frac{P(C,雨)}{P(雨)}=αP(C,雨)$,或$α<0.08,0.02>=<0.8,0.2>$。考虑到下午有雨,将$α$分解后,我们可以得到 C 的可能值的概率比例。也就是说,如果下午有雨,那么早上有云和早上没有云的概率的比例是$0.08:0.02$。请注意,0.08 和 0.02 的总和不等于 1;然而,由于这是随机变量 C 的概率分布,我们知道它们应该加起来为 1。因此,我们需要通过算$α$来归一化这些值,使得$α0.08+α0.02=1$。最后,我们可以说$P(C|雨)=<0.8,0.2>$。
|
||||
现在我们可以知道有关这些事件同时发生的信息了。例如,我们知道某一天早上有云,下午有雨的概率是 0.08。早上没有云,下午没有雨的概率是 0.58。
|
||||
|
||||
## 概率规则(Probability Rules)
|
||||
使用联合概率,我们可以推导出条件概率。例如,如果我们感兴趣的是在下午下雨的情况下,早上云层的概率分布。$P(C|雨)=\frac{P(C,雨)}{P(雨)}$旁注:在概率上,逗号和$∧$可以互换使用。因此,$P(C,雨)=P(C\land 雨)$。换句话说,我们将降雨和云层的联合概率除以降雨的概率。
|
||||
|
||||
- 否定(Negation): $P(\lnot a)=1-P(a)$。这源于这样一个事实,即所有可能世界的概率之和为 1,互补事件$\lnot a$和 $a$ 包括所有可能世界。
|
||||
- 包含-排除 Inclusion-Exclusion:$P(a\lor b)=P(a)+P(b)-P(a\land b)$。这可以用以下方式解释:$a$或$b$为真的世界等于$a$为真的所有世界,加上$b$为真的所有世界。然而,在这种情况下,有些世界被计算两次(a和$b$都为真的世界)。为了消除这种重叠,我们将$a$和$b$ 都为真的世界减去一次(因为它们被计算了两次)。
|
||||
在最后一个方程中,可以将$P(雨)$视为$P(C,雨)$乘以的某个常数$\alpha=\frac{1}{P(雨)}$。因此,我们可以重写$P(C|雨)=\frac{P(C,雨)}{P(雨)}=αP(C,雨)$,或$α<0.08,0.02>=<0.8,0.2>$。考虑到下午有雨,将$α$分解后,我们可以得到 C 的可能值的概率比例。也就是说,如果下午有雨,那么早上有云和早上没有云的概率的比例是$0.08:0.02$。请注意,0.08 和 0.02 的总和不等于 1;然而,由于这是随机变量 C 的概率分布,我们知道它们应该加起来为 1。因此,我们需要通过算$α$来归一化这些值,使得$α0.08+α0.02=1$。最后,我们可以说$P(C|雨)=<0.8,0.2>$。
|
||||
|
||||
> 下面是一个例子,可以说明这一点。假设我 80% 的时间吃冰淇淋,70% 的时间吃饼干。如果我们计算今天我吃冰淇淋或饼干的概率,不减去$P(冰淇淋∧饼干)$,我们错误地得出 0.7+0.8=1.5。这与概率在 0 和 1 之间的公理相矛盾。为了纠正我同时吃冰淇淋和饼干的天数计算两次的错误,我们需要减去$P(冰淇淋∧饼干)$一次。
|
||||
## 概率规则 (Probability Rules)
|
||||
|
||||
- 边缘化(Marginalization):$P(a)=P(a,b)+P(a,\lnot b)$。这里的观点是,$b$和$\lnot b$是独立的概率。也就是说,$b$和$\lnot b$同时发生的概率为0。我们也知道$b$和$\lnot b$的总和为1。因此,当$a$发生时,$b$可以发生也可以不发生。当我们把$a$和$b$发生的概率加上$a$和$\lnot b$的概率时,我们得到的只是$a$ 的概率。
|
||||
- 随机变量的边缘化可以用:$P(X=x_i)=\sum_jP(X=x_i,Y=y_j)$表示
|
||||
- 方程的左侧表示“随机变量$X$具有$x_i$值的概率” 例如,对于我们前面提到的变量C,两个可能的值是早上有云和早上没有云。等式的正确部分是边缘化的概念。$P(X=x_i)$等于$x_i$以及随机变量$Y$的每一个值的所有联合概率之和。例如,$P(C=云)=P(C=云,R=雨)+P(C=云,R=\lnot 雨)=0.08+0.32=0.4$。
|
||||
- 否定 (Negation): $P(\lnot a)=1-P(a)$。这源于这样一个事实,即所有可能世界的概率之和为 1,互补事件$\lnot a$和 $a$ 包括所有可能世界。
|
||||
- 包含 - 排除 Inclusion-Exclusion:$P(a\lor b)=P(a)+P(b)-P(a\land b)$。这可以用以下方式解释:$a$或$b$为真的世界等于$a$为真的所有世界,加上$b$为真的所有世界。然而,在这种情况下,有些世界被计算两次(a 和$b$都为真的世界)。为了消除这种重叠,我们将$a$和$b$ 都为真的世界减去一次(因为它们被计算了两次)。
|
||||
|
||||
- 条件边缘化: $P(a)=P(a|b)P(b)+P(a|\lnot b)P(\lnot b)$。这是一个类似于边缘化的想法。事件$a$发生的概率等于给定$b$的概率乘以$b$的概率,再加上给定$\lnot b$的概率乘以$\lnot b$ 的概率。
|
||||
- $P(X=x_i)=\sum_jP(X=x_i|Y=y_i)P(Y=y_i)$
|
||||
- 在这个公式中,随机变量$X$取$x_i$值概率等于$x_i$以及随机变量$Y$的每个值的联合概率乘以变量$Y$取该值的概率之和。如果我们还记得$P(a|b)=\frac{P(a,b)}{P(b)}$,就可以理解这个公式。如果我们将这个表达式乘以$P(b)$,我们得到$P(a,b)$,从这里开始,我们做的与边缘化相同。
|
||||
> 下面是一个例子,可以说明这一点。假设我 80% 的时间吃冰淇淋,70% 的时间吃饼干。如果我们计算今天我吃冰淇淋或饼干的概率,不减去$P(冰淇淋∧饼干)$,我们错误地得出 0.7+0.8=1.5。这与概率在 0 和 1 之间的公理相矛盾。为了纠正我同时吃冰淇淋和饼干的天数计算两次的错误,我们需要减去$P(冰淇淋∧饼干)$一次。
|
||||
- 边缘化 (Marginalization):$P(a)=P(a,b)+P(a,\lnot b)$。这里的观点是,$b$和$\lnot b$是独立的概率。也就是说,$b$和$\lnot b$同时发生的概率为 0。我们也知道$b$和$\lnot b$的总和为 1。因此,当$a$发生时,$b$可以发生也可以不发生。当我们把$a$和$b$发生的概率加上$a$和$\lnot b$的概率时,我们得到的只是$a$ 的概率。
|
||||
|
||||
## 贝叶斯网络(Bayesian Networks)
|
||||
随机变量的边缘化可以用:$P(X=x_i)=\sum_jP(X=x_i,Y=y_j)$表示
|
||||
|
||||
- 贝叶斯网络是一种表示随机变量之间相关性的数据结构。贝叶斯网络具有以下属性:
|
||||
方程的左侧表示“随机变量$X$具有$x_i$值的概率”例如,对于我们前面提到的变量 C,两个可能的值是早上有云和早上没有云。等式的正确部分是边缘化的概念。$P(X=x_i)$等于$x_i$以及随机变量$Y$的每一个值的所有联合概率之和。例如,$P(C=云)=P(C=云,R=雨)+P(C=云,R=\lnot 雨)=0.08+0.32=0.4$。
|
||||
|
||||
- 它们是有向图。
|
||||
- 图上的每个节点表示一个随机变量。
|
||||
- 从 X 到 Y 的箭头表示 X 是 Y 的父对象。也就是说,Y 的概率分布取决于 X 的值。
|
||||
- 每个节点 X 具有概率分布$P(X|Parents(X))$。
|
||||
- 让我们考虑一个贝叶斯网络的例子,该网络包含影响我们是否按时赴约的随机变量。
|
||||
- 条件边缘化:$P(a)=P(a|b)P(b)+P(a|\lnot b)P(\lnot b)$。这是一个类似于边缘化的想法。事件$a$发生的概率等于给定$b$的概率乘以$b$的概率,再加上给定$\lnot b$的概率乘以$\lnot b$ 的概率。
|
||||
|
||||

|
||||
$P(X=x_i)=\sum_jP(X=x_i|Y=y_i)P(Y=y_i)$
|
||||
|
||||
- 让我们从上到下描述这个贝叶斯网络:
|
||||
在这个公式中,随机变量$X$取$x_i$值概率等于$x_i$以及随机变量$Y$的每个值的联合概率乘以变量$Y$取该值的概率之和。如果我们还记得$P(a|b)=\frac{P(a,b)}{P(b)}$,就可以理解这个公式。如果我们将这个表达式乘以$P(b)$,我们得到$P(a,b)$,从这里开始,我们做的与边缘化相同。
|
||||
|
||||
- rain 是这个网络的根节点。这意味着它的概率分布不依赖于任何先前的事件。在我们的例子中,Rain 是一个随机变量,可以采用以下概率分布的值$\set{none,light,heavy}$:
|
||||
## 贝叶斯网络 (Bayesian Networks)
|
||||
|
||||
| none | light | heavy |
|
||||
| ---- | ----- | ----- |
|
||||
| 0.7 | 0.2 | 0.1 |
|
||||
贝叶斯网络是一种表示随机变量之间相关性的数据结构。贝叶斯网络具有以下属性:
|
||||
|
||||
- 它们是有向图。
|
||||
- 图上的每个节点表示一个随机变量。
|
||||
- 从 X 到 Y 的箭头表示 X 是 Y 的父对象。也就是说,Y 的概率分布取决于 X 的值。
|
||||
- 每个节点 X 具有概率分布$P(X|Parents(X))$。
|
||||
|
||||
- Maintenance对是否有列车轨道维护进行编码,取值为$\set{yes,no}$。Rain是Maintenance的父节点,这意味着Maintenance概率分布受到Rain的影响。
|
||||
让我们考虑一个贝叶斯网络的例子,该网络包含影响我们是否按时赴约的随机变量。
|
||||
|
||||

|
||||
|
||||
| R | yes | no |
|
||||
| ----- | --- | --- |
|
||||
| none | 0.4 | 0.6 |
|
||||
| light | 0.2 | 0.8 |
|
||||
| heavy | 0.1 | 0.9 |
|
||||
让我们从上到下描述这个贝叶斯网络:
|
||||
|
||||
- rain 是这个网络的根节点。这意味着它的概率分布不依赖于任何先前的事件。在我们的例子中,Rain 是一个随机变量,可以采用以下概率分布的值$\set{none,light,heavy}$:
|
||||
|
||||
- Train是一个变量,用于编码列车是准时还是晚点,取值为$\set{on\ time,delayed}$。请注意,列车上被“Maintenance”和“rain”指向。这意味着两者都是Train的父对象,它们的值会影响Train的概率分布。
|
||||
| none | light | heavy |
|
||||
| ---- | ----- | ----- |
|
||||
| 0.7 | 0.2 | 0.1 |
|
||||
|
||||
- Maintenance 对是否有列车轨道维护进行编码,取值为$\set{yes,no}$。Rain 是 Maintenance 的父节点,这意味着 Maintenance 概率分布受到 Rain 的影响。
|
||||
|
||||
| R | M | On time | Delayed |
|
||||
| ------ | --- | ------- | ------- |
|
||||
| none | yes | 0.8 | 0.2 |
|
||||
| none | no | 0.9 | 0.1 |
|
||||
| light | yes | 0.6 | 0.4 |
|
||||
| light | no | 0.7 | 0.3 |
|
||||
| heavry | yes | 0.4 | 0.6 |
|
||||
| heavy | no | 0.5 | 0.5 |
|
||||
| R | yes | no |
|
||||
| ----- | --- | --- |
|
||||
| none | 0.4 | 0.6 |
|
||||
| light | 0.2 | 0.8 |
|
||||
| heavy | 0.1 | 0.9 |
|
||||
|
||||
- Train 是一个变量,用于编码列车是准时还是晚点,取值为$\set{on\ time,delayed}$。请注意,列车上被“Maintenance”和“rain”指向。这意味着两者都是 Train 的父对象,它们的值会影响 Train 的概率分布。
|
||||
|
||||
- Appointment 是一个随机变量,表示我们是否参加约会,取值为$\set{attend, miss}$。请注意,它唯一的父级是Train。关于贝叶斯网络的这一点值得注意:父子只包括直接关系。的确,Maintenance会影响Train是否准时,而Train是否准时会影响我们是否赴约。然而,最终,直接影响我们赴约机会的是Train是否准时,这就是贝叶斯网络所代表的。例如,如果火车准时到达,可能会有大雨和轨道维护,但这对我们是否赴约没有影响。
|
||||
| R | M | On time | Delayed |
|
||||
| ------ | --- | ------- | ------- |
|
||||
| none | yes | 0.8 | 0.2 |
|
||||
| none | no | 0.9 | 0.1 |
|
||||
| light | yes | 0.6 | 0.4 |
|
||||
| light | no | 0.7 | 0.3 |
|
||||
| heavry | yes | 0.4 | 0.6 |
|
||||
| heavy | no | 0.5 | 0.5 |
|
||||
|
||||
- Appointment 是一个随机变量,表示我们是否参加约会,取值为$\set{attend, miss}$。请注意,它唯一的父级是 Train。关于贝叶斯网络的这一点值得注意:父子只包括直接关系。的确,Maintenance 会影响 Train 是否准时,而 Train 是否准时会影响我们是否赴约。然而,最终,直接影响我们赴约机会的是 Train 是否准时,这就是贝叶斯网络所代表的。例如,如果火车准时到达,可能会有大雨和轨道维护,但这对我们是否赴约没有影响。
|
||||
|
||||
| T | attend | miss |
|
||||
| ------- | ------ | ---- |
|
||||
| on time | 0.9 | 0.1 |
|
||||
| delayed | 0.6 | 0.4 |
|
||||
| T | attend | miss |
|
||||
| ------- | ------ | ---- |
|
||||
| on time | 0.9 | 0.1 |
|
||||
| delayed | 0.6 | 0.4 |
|
||||
|
||||
例如,如果我们想找出在没有维护和小雨的一天火车晚点时错过约会的概率,或者$P(light,no,delayed,miss)$,我们将计算如下:$P(light)P(no|light)P(delayed|light,no)P(miss|delayed)$。每个单独概率的值可以在上面的概率分布中找到,然后将这些值相乘以产生$P(light,no,delayed,miss)$。
|
||||
|
||||
- 例如,如果我们想找出在没有维护和小雨的一天火车晚点时错过约会的概率,或者$P(light,no,delayed,miss)$,我们将计算如下:$P(light)P(no|light)P(delayed|light,no)P(miss|delayed)$。每个单独概率的值可以在上面的概率分布中找到,然后将这些值相乘以产生$P(light,no,delayed,miss)$。
|
||||
### 推理 (Inference)
|
||||
|
||||
|
||||
### 推理(Inference)
|
||||
|
||||
- 在知识推理,我们通过蕴含来看待推理。这意味着我们可以在现有信息的基础上得出新的信息。我们也可以根据概率推断出新的信息。虽然这不能让我们确切地知道新的信息,但它可以让我们计算出一些值的概率分布。推理具有多个属性。
|
||||
在知识推理,我们通过蕴含来看待推理。这意味着我们可以在现有信息的基础上得出新的信息。我们也可以根据概率推断出新的信息。虽然这不能让我们确切地知道新的信息,但它可以让我们计算出一些值的概率分布。推理具有多个属性。
|
||||
- Query 查询变量 $X$:我们要计算概率分布的变量。
|
||||
- Evidence variables 证据变量$E$: 一个或多个观测到事件$e$ 的变量。例如,我们可能观测到有小雨,这一观测有助于我们计算火车延误的概率。
|
||||
- Hidden variables 隐藏变量 $H$: 不是查询结论的变量,也没有被观测到。例如,站在火车站,我们可以观察是否下雨,但我们不知道道路后面的轨道是否有维修。因此,在这种情况下,Maintenance 将是一个隐藏的变量。
|
||||
- The goal 目标: 计算$P(X|e)$。例如,根据我们知道有小雨的证据 $e$ 计算 Train 变量(查询)的概率分布。
|
||||
- 举一个例子。考虑到有小雨和没有轨道维护的证据,我们想计算 Appointment 变量的概率分布。也就是说,我们知道有小雨,没有轨道维护,我们想弄清楚我们参加约会和错过约会的概率是多少,$P(Appointment|light,no)$。从联合概率部分中,我们知道我们可以将约会随机变量的可能值表示为一个比例,将$P(Appointment|light,no)$重写为$αP(Appointment,light,no)$。如果 Appointment 的父节点仅为 Train 变量,而不是 Rain 或 Maintenance,我们如何计算约会的概率分布?在这里,我们将使用边缘化。$P(Appointment,light,no)$的值等于$α[P(Appointment,light,no,delay)+P(Appointment,light,no,on\ time)]$。
|
||||
- The goal 目标:计算$P(X|e)$。例如,根据我们知道有小雨的证据 $e$ 计算 Train 变量 (查询) 的概率分布。
|
||||
|
||||
举一个例子。考虑到有小雨和没有轨道维护的证据,我们想计算 Appointment 变量的概率分布。也就是说,我们知道有小雨,没有轨道维护,我们想弄清楚我们参加约会和错过约会的概率是多少,$P(Appointment|light,no)$。从联合概率部分中,我们知道我们可以将约会随机变量的可能值表示为一个比例,将$P(Appointment|light,no)$重写为$αP(Appointment,light,no)$。如果 Appointment 的父节点仅为 Train 变量,而不是 Rain 或 Maintenance,我们如何计算约会的概率分布?在这里,我们将使用边缘化。$P(Appointment,light,no)$的值等于$α[P(Appointment,light,no,delay)+P(Appointment,light,no,on\ time)]$。
|
||||
|
||||
### 枚举推理
|
||||
|
||||
- 枚举推理是在给定观测证据$e$和一些隐藏变量$Y$的情况下,找到变量$X$ 的概率分布的过程。
|
||||
- $P(X|e)=\alpha P(X,e)=\alpha \sum_yP(X,e,y)$
|
||||
- 在这个方程中,$X$代表查询变量,$e$代表观察到的证据,$y$代表隐藏变量的所有值,$α$归一化结果,使我们最终得到的概率加起来为1。用文字来解释这个方程,即给定$e$的$X$的概率分布等于$X$和$e$的归一化概率分布。为了得到这个分布,我们对$X、e$和$y$的归一化概率求和,其中$y$每次取隐藏变量$Y$ 的不同值。
|
||||
- Python 中存在多个库,以简化概率推理过程。我们将查看库 `pomegranate`,看看如何在代码中表示上述数据。
|
||||
枚举推理是在给定观测证据$e$和一些隐藏变量$Y$的情况下,找到变量$X$ 的概率分布的过程。
|
||||
|
||||
$P(X|e)=\alpha P(X,e)=\alpha \sum_yP(X,e,y)$
|
||||
|
||||
在这个方程中,$X$代表查询变量,$e$代表观察到的证据,$y$代表隐藏变量的所有值,$α$归一化结果,使我们最终得到的概率加起来为 1。用文字来解释这个方程,即给定$e$的$X$的概率分布等于$X$和$e$的归一化概率分布。为了得到这个分布,我们对$X、e$和$y$的归一化概率求和,其中$y$每次取隐藏变量$Y$ 的不同值。
|
||||
|
||||
Python 中存在多个库,以简化概率推理过程。我们将查看库 `pomegranate`,看看如何在代码中表示上述数据。
|
||||
|
||||
```python
|
||||
from pomegranate import *
|
||||
'''创建节点,并为每个节点提供概率分布'''
|
||||
# Rain节点没有父节点
|
||||
# Rain 节点没有父节点
|
||||
rain = Node(DiscreteDistribution({
|
||||
"none": 0.7,
|
||||
"light": 0.2,
|
||||
"heavy": 0.1
|
||||
}), name="rain")
|
||||
# Track maintenance节点以rain为条件
|
||||
# Track maintenance 节点以 rain 为条件
|
||||
maintenance = Node(ConditionalProbabilityTable([
|
||||
["none", "yes", 0.4],
|
||||
["none", "no", 0.6],
|
||||
@@ -215,7 +226,7 @@ maintenance = Node(ConditionalProbabilityTable([
|
||||
["heavy", "yes", 0.1],
|
||||
["heavy", "no", 0.9]
|
||||
], [rain.distribution]), name="maintenance")
|
||||
# Train node节点以rain和maintenance为条件
|
||||
# Train node 节点以 rain 和 maintenance 为条件
|
||||
train = Node(ConditionalProbabilityTable([
|
||||
["none", "yes", "on time", 0.8],
|
||||
["none", "yes", "delayed", 0.2],
|
||||
@@ -230,7 +241,7 @@ train = Node(ConditionalProbabilityTable([
|
||||
["heavy", "no", "on time", 0.5],
|
||||
["heavy", "no", "delayed", 0.5],
|
||||
], [rain.distribution, maintenance.distribution]), name="train")
|
||||
# Appointment节点以列车为条件
|
||||
# Appointment 节点以列车为条件
|
||||
appointment = Node(ConditionalProbabilityTable([
|
||||
["on time", "attend", 0.9],
|
||||
["on time", "miss", 0.1],
|
||||
@@ -252,7 +263,7 @@ model.bake()
|
||||
# 计算给定观测的概率
|
||||
probability = model.probability([["none", "no", "on time", "attend"]])
|
||||
print(probability)
|
||||
'''我们可以使用该模型为所有变量提供概率分布,给出一些观测到的证据。在以下情况下,我们知道火车晚点了。给定这些信息,我们计算并打印变量Rain、Maintenance和Appointment的概率分布。'''
|
||||
'''我们可以使用该模型为所有变量提供概率分布,给出一些观测到的证据。在以下情况下,我们知道火车晚点了。给定这些信息,我们计算并打印变量 Rain、Maintenance 和 Appointment 的概率分布。'''
|
||||
# 根据火车晚点的证据计算预测
|
||||
predictions = model.predict_proba({
|
||||
"train": "delayed"
|
||||
@@ -269,38 +280,40 @@ for node, prediction in zip(model.states, predictions):
|
||||
print(f" {value}: {probability:.4f}")
|
||||
```
|
||||
|
||||
- 上面的代码使用了枚举推理。然而,这种计算概率的方法效率很低,尤其是当模型中有很多变量时。另一种方法是放弃精确推理,转而采用近似推理。这样做,我们在生成的概率中会失去一些精度,但这种不精确性通常可以忽略不计。相反,我们获得了一种可扩展的概率计算方法。
|
||||
上面的代码使用了枚举推理。然而,这种计算概率的方法效率很低,尤其是当模型中有很多变量时。另一种方法是放弃精确推理,转而采用近似推理。这样做,我们在生成的概率中会失去一些精度,但这种不精确性通常可以忽略不计。相反,我们获得了一种可扩展的概率计算方法。
|
||||
|
||||
### 采样(Sampling)
|
||||
### 采样 (Sampling)
|
||||
|
||||
- 采样是一种近似推理技术。在采样中,根据每个变量的概率分布对其值进行采样。
|
||||
采样是一种近似推理技术。在采样中,根据每个变量的概率分布对其值进行采样。
|
||||
|
||||
> 要使用骰子采样生成分布,我们可以多次掷骰子,并记录每次获得的值。假设我们把骰子掷了 600 次。我们计算得到 1 的次数,应该大约是 100,然后对其余的值 2-6 重复采样。然后,我们将每个计数除以投掷的总数。这将生成掷骰子的值的近似分布:一方面,我们不太可能得到每个值发生概率为 1/6 的结果(这是确切的概率),但我们会得到一个接近它的值。
|
||||
|
||||
- 如果我们从对 Rain 变量进行采样开始,则生成的值 none 的概率为 0.7,生成的值 light 的概率为 0.2,而生成的值 heavy 的概率则为 0.1。假设我们的采样值为 none。当我们得到 Maintenance 变量时,我们也会对其进行采样,但只能从 Rain 等于 none 的概率分布中进行采样,因为这是一个已经采样的结果。我们将通过所有节点继续这样做。现在我们有一个样本,多次重复这个过程会生成一个分布。现在,如果我们想回答一个问题,比如什么是$P(Train=on\ time)$,我们可以计算变量 Train 具有准时值的样本数量,并将结果除以样本总数。通过这种方式,我们刚刚生成了$P(Train=on\ {time})$的近似概率。
|
||||
如果我们从对 Rain 变量进行采样开始,则生成的值 none 的概率为 0.7,生成的值 light 的概率为 0.2,而生成的值 heavy 的概率则为 0.1。假设我们的采样值为 none。当我们得到 Maintenance 变量时,我们也会对其进行采样,但只能从 Rain 等于 none 的概率分布中进行采样,因为这是一个已经采样的结果。我们将通过所有节点继续这样做。现在我们有一个样本,多次重复这个过程会生成一个分布。现在,如果我们想回答一个问题,比如什么是$P(Train=on\ time)$,我们可以计算变量 Train 具有准时值的样本数量,并将结果除以样本总数。通过这种方式,我们刚刚生成了$P(Train=on\ {time})$的近似概率。
|
||||
|
||||

|
||||
<table>
|
||||
<tr>
|
||||
<td><img src=https://cdn.xyxsw.site/CreObGAg4oXB0oxe2hMcQbYZnAc.png width=520></td>
|
||||
<td><img src=https://cdn.xyxsw.site/Vr96bdSafoV4kBxJ3x2cAU0TnOg.png width=520></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||

|
||||
我们也可以回答涉及条件概率的问题,例如$P(rain=light|train=on\ {time})$。在这种情况下,我们忽略 Train 值为 delay 的所有样本,然后照常进行。我们计算在$Train=\text{on time}$的样本中有多少样本具有变量$Rain=light$,然后除以$Train=\text{on time}$的样本总数。
|
||||
|
||||
- 我们也可以回答涉及条件概率的问题,例如$P(rain=light|train=on\ {time})$。在这种情况下,我们忽略 Train 值为 delay 的所有样本,然后照常进行。我们计算在$Train=\text{on time}$的样本中有多少样本具有变量$Rain=light$,然后除以$Train=\text{on time}$的样本总数。
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src=https://cdn.xyxsw.site/KsELbuMTCoKZkGxU9U5czQpanKg.png width=520></td>
|
||||
<td><img src=https://cdn.xyxsw.site/MrP0b2FbXofDsOxgnmncufUynAB.png width=520></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||

|
||||
| 去除$T= on time$的样本 | 选择$R=light$的样本 |
|
||||
| --------------------- | ------------------ |
|
||||
|  |  |
|
||||
|
||||

|
||||
|
||||
去除$T= on time$的样本
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
选择$R=light$的样本
|
||||
|
||||
- 在代码中,采样函数可以是 `generate_sample`:
|
||||
在代码中,采样函数可以是 `generate_sample`:
|
||||
|
||||
```python
|
||||
'''如果你对pomegrante库不熟悉,没有关系,考虑generate_sample为一个黑盒,或者你可以在python解释器中查看model.states, state.distribution的值以了解model在该库中的实现方式'''
|
||||
'''如果你对 pomegrante 库不熟悉,没有关系,考虑 generate_sample 为一个黑盒,或者你可以在 python 解释器中查看 model.states, state.distribution 的值以了解 model 在该库中的实现方式'''
|
||||
import pomegranate
|
||||
from collections import Counter
|
||||
def generate_sample():
|
||||
@@ -321,49 +334,51 @@ def generate_sample():
|
||||
# 返回生成的样本
|
||||
return sample
|
||||
# 采样
|
||||
# 观测到train=delay,计算appointment分布
|
||||
# 观测到 train=delay,计算 appointment 分布
|
||||
N = 10000
|
||||
data = []
|
||||
# 重复采样10000次
|
||||
# 重复采样 10000 次
|
||||
for i in range(N):
|
||||
# 根据我们之前定义的函数生成一个样本
|
||||
sample = generate_sample()
|
||||
# 如果在该样本中,Train的变量的值为delay,则保存样本。由于我们对给定train=delay的appointment概率分布感兴趣,我们丢弃了train=on time的采样样本。
|
||||
# 如果在该样本中,Train 的变量的值为 delay,则保存样本。由于我们对给定 train=delay 的 appointment 概率分布感兴趣,我们丢弃了 train=on time 的采样样本。
|
||||
if sample["train"] == "delayed":
|
||||
data.append(sample["appointment"])
|
||||
# 计算变量的每个值出现的次数。我们可以稍后通过将结果除以保存的样本总数来进行归一化,以获得变量的近似概率,该概率加起来为1。
|
||||
# 计算变量的每个值出现的次数。我们可以稍后通过将结果除以保存的样本总数来进行归一化,以获得变量的近似概率,该概率加起来为 1。
|
||||
print(Counter(data))
|
||||
```
|
||||
|
||||
### 似然加权
|
||||
|
||||
- 在上面的采样示例中,我们丢弃了与我们所掌握的证据不匹配的样本。这是低效的。解决这一问题的一种方法是使用似然加权,使用以下步骤:
|
||||
在上面的采样示例中,我们丢弃了与我们所掌握的证据不匹配的样本。这是低效的。解决这一问题的一种方法是使用似然加权,使用以下步骤:
|
||||
|
||||
- 首先固定证据变量的值。
|
||||
- 使用贝叶斯网络中的条件概率对非证据变量进行采样。
|
||||
- 根据其可能性对每个样本进行加权: 所有证据出现的概率。
|
||||
- 例如,如果我们观察到$Train=\text{on time}$,我们将像之前一样开始采样。我们对给定概率分布的 Rain 值进行采样,然后对 Maintenance 进行采样,但当我们到达 Train 时,我们总是按照观测值取值。然后,我们继续进行,并在给定$Train=\text{on time}$的情况下,根据其概率分布对 Appointment 进行采样。既然这个样本存在,我们就根据观察到的变量在给定其采样父变量的情况下的条件概率对其进行加权。也就是说,如果我们采样了 Rain 并得到了 light,然后我们采样了 Maintenance 并得到了 yes,那么我们将用$P(Train=\text{on time}|light,yes)$来加权这个样本。
|
||||
- 首先固定证据变量的值。
|
||||
- 使用贝叶斯网络中的条件概率对非证据变量进行采样。
|
||||
- 根据其可能性对每个样本进行加权:所有证据出现的概率。
|
||||
|
||||
## 马尔科夫模型(Markov Models)
|
||||
例如,如果我们观察到$Train=\text{on time}$,我们将像之前一样开始采样。我们对给定概率分布的 Rain 值进行采样,然后对 Maintenance 进行采样,但当我们到达 Train 时,我们总是按照观测值取值。然后,我们继续进行,并在给定$Train=\text{on time}$的情况下,根据其概率分布对 Appointment 进行采样。既然这个样本存在,我们就根据观察到的变量在给定其采样父变量的情况下的条件概率对其进行加权。也就是说,如果我们采样了 Rain 并得到了 light,然后我们采样了 Maintenance 并得到了 yes,那么我们将用$P(Train=\text{on time}|light,yes)$来加权这个样本。
|
||||
|
||||
- 到目前为止,我们已经研究了概率问题,给出了我们观察到的一些信息。在这种范式中,时间的维度没有以任何方式表示。然而,许多任务确实依赖于时间维度,例如预测。为了表示时间变量,我们将创建一个新的变量$X$,并根据感兴趣的事件对其进行更改,使$X_t$ 是当前事件,$X_{t+1}$ 是下一个事件,依此类推。为了能够预测未来的事件,我们将使用马尔可夫模型。
|
||||
## 马尔科夫模型 (Markov Models)
|
||||
|
||||
### 马尔科夫假设(<strong>The Markov Assumption</strong>)
|
||||
到目前为止,我们已经研究了概率问题,给出了我们观察到的一些信息。在这种范式中,时间的维度没有以任何方式表示。然而,许多任务确实依赖于时间维度,例如预测。为了表示时间变量,我们将创建一个新的变量$X$,并根据感兴趣的事件对其进行更改,使$X_t$ 是当前事件,$X_{t+1}$ 是下一个事件,依此类推。为了能够预测未来的事件,我们将使用马尔可夫模型。
|
||||
|
||||
- 马尔科夫假设是一个假设,即当前状态只取决于有限的固定数量的先前状态。想想预测天气的任务。在理论上,我们可以使用过去一年的所有数据来预测明天的天气。然而,这是不可行的,一方面是因为这需要计算能力,另一方面是因为可能没有关于基于 365 天前天气的明天天气的条件概率的信息。使用马尔科夫假设,我们限制了我们以前的状态(例如,在预测明天的天气时,我们要考虑多少个以前的日子),从而使这个任务变得可控。这意味着我们可能会得到感兴趣的概率的一个更粗略的近似值,但这往往足以满足我们的需要。此外,我们可以根据最后一个事件的信息来使用马尔可夫模型(例如,根据今天的天气来预测明天的天气)。
|
||||
### 马尔科夫假设 (**The Markov Assumption**)
|
||||
|
||||
### 马尔科夫链(<strong>Markov Chain</strong>)
|
||||
马尔科夫假设是一个假设,即当前状态只取决于有限的固定数量的先前状态。想想预测天气的任务。在理论上,我们可以使用过去一年的所有数据来预测明天的天气。然而,这是不可行的,一方面是因为这需要计算能力,另一方面是因为可能没有关于基于 365 天前天气的明天天气的条件概率的信息。使用马尔科夫假设,我们限制了我们以前的状态(例如,在预测明天的天气时,我们要考虑多少个以前的日子),从而使这个任务变得可控。这意味着我们可能会得到感兴趣的概率的一个更粗略的近似值,但这往往足以满足我们的需要。此外,我们可以根据最后一个事件的信息来使用马尔可夫模型(例如,根据今天的天气来预测明天的天气)。
|
||||
|
||||
- 马尔科夫链是一个随机变量的序列,每个变量的分布都遵循马尔科夫假设。也就是说,链中的每个事件的发生都是基于之前事件的概率。
|
||||
- 为了构建马尔可夫链,我们需要一个过渡模型,该模型将根据当前事件的可能值来指定下一个事件的概率分布。
|
||||
### 马尔科夫链 (**Markov Chain**)
|
||||
|
||||

|
||||
马尔科夫链是一个随机变量的序列,每个变量的分布都遵循马尔科夫假设。也就是说,链中的每个事件的发生都是基于之前事件的概率。
|
||||
|
||||
- 在这个例子中,基于今天是晴天,明天是晴天的概率是 0.8。这是合理的,因为晴天之后更可能是晴天。然而,如果今天是雨天,明天下雨的概率是 0.7,因为雨天更有可能相继出现。使用这个过渡模型,可以对马尔可夫链进行采样。从一天是雨天或晴天开始,然后根据今天的天气,对第二天的晴天或雨天的概率进行采样。然后,根据明天的情况对后天的概率进行采样,以此类推,形成马尔科夫链:
|
||||
为了构建马尔可夫链,我们需要一个过渡模型,该模型将根据当前事件的可能值来指定下一个事件的概率分布。
|
||||
|
||||

|
||||

|
||||
|
||||
- 给定这个马尔可夫链,我们现在可以回答诸如“连续四个雨天的概率是多少?”这样的问题。下面是一个如何在代码中实现马尔可夫链的例子:
|
||||
在这个例子中,基于今天是晴天,明天是晴天的概率是 0.8。这是合理的,因为晴天之后更可能是晴天。然而,如果今天是雨天,明天下雨的概率是 0.7,因为雨天更有可能相继出现。使用这个过渡模型,可以对马尔可夫链进行采样。从一天是雨天或晴天开始,然后根据今天的天气,对第二天的晴天或雨天的概率进行采样。然后,根据明天的情况对后天的概率进行采样,以此类推,形成马尔科夫链:
|
||||
|
||||

|
||||
|
||||
给定这个马尔可夫链,我们现在可以回答诸如“连续四个雨天的概率是多少?”这样的问题。下面是一个如何在代码中实现马尔可夫链的例子:
|
||||
|
||||
```python
|
||||
from pomegranate import *
|
||||
@@ -381,37 +396,42 @@ transitions = ConditionalProbabilityTable([
|
||||
], [start])
|
||||
# 创造马尔科夫链
|
||||
model = MarkovChain([start, transitions])
|
||||
# 采样50次
|
||||
# 采样 50 次
|
||||
print(model.sample(50))
|
||||
```
|
||||
|
||||
## 隐马尔科夫模型(Hidden Markov Models)
|
||||
## 隐马尔科夫模型 (Hidden Markov Models)
|
||||
|
||||
- 隐马尔科夫模型是一种具有隐藏状态的系统的马尔科夫模型,它产生了一些观察到的事件。这意味着,有时候,人工智能对世界有一些测量,但无法获得世界的精确状态。在这些情况下,世界的状态被称为隐藏状态,而人工智能能够获得的任何数据都是观察结果。下面是一些这方面的例子:
|
||||
隐马尔科夫模型是一种具有隐藏状态的系统的马尔科夫模型,它产生了一些观察到的事件。这意味着,有时候,人工智能对世界有一些测量,但无法获得世界的精确状态。在这些情况下,世界的状态被称为隐藏状态,而人工智能能够获得的任何数据都是观察结果。下面是一些这方面的例子:
|
||||
|
||||
- 对于一个探索未知领域的机器人来说,隐藏状态是它的位置,而观察是机器人的传感器所记录的数据。
|
||||
- 在语音识别中,隐藏状态是所讲的话语,而观察是音频波形。
|
||||
- 在衡量网站的用户参与度时,隐藏的状态是用户的参与程度,而观察是网站或应用程序的分析。
|
||||
- 举个例子。我们的人工智能想要推断天气(隐藏状态),但它只能接触到一个室内摄像头,记录有多少人带了雨伞。这里是我们的传感器模型(sensor model),表示了这些概率:
|
||||
- 对于一个探索未知领域的机器人来说,隐藏状态是它的位置,而观察是机器人的传感器所记录的数据。
|
||||
- 在语音识别中,隐藏状态是所讲的话语,而观察是音频波形。
|
||||
- 在衡量网站的用户参与度时,隐藏的状态是用户的参与程度,而观察是网站或应用程序的分析。
|
||||
|
||||

|
||||
举个例子。我们的人工智能想要推断天气 (隐藏状态),但它只能接触到一个室内摄像头,记录有多少人带了雨伞。这里是我们的传感器模型 (sensor model),表示了这些概率:
|
||||
|
||||
- 在这个模型中,如果是晴天,人们很可能不会带伞到大楼。如果是雨天,那么人们就很有可能带伞到大楼来。通过对人们是否带伞的观察,我们可以合理地预测外面的天气情况。
|
||||

|
||||
|
||||
在这个模型中,如果是晴天,人们很可能不会带伞到大楼。如果是雨天,那么人们就很有可能带伞到大楼来。通过对人们是否带伞的观察,我们可以合理地预测外面的天气情况。
|
||||
|
||||
### 传感器马尔科夫假设
|
||||
|
||||
- 假设证据变量只取决于相应的状态。例如,对于我们的模型,我们假设人们是否带雨伞去办公室只取决于天气。这不一定反映了完整的事实,因为,比如说,比较自觉的、不喜欢下雨的人可能即使在阳光明媚的时候也会到处带伞,如果我们知道每个人的个性,会给模型增加更多的数据。然而,传感器马尔科夫假设忽略了这些数据,假设只有隐藏状态会影响观察。
|
||||
- 隐马尔科夫模型可以用一个有两层的马尔科夫链来表示。上层,变量$X$,代表隐藏状态。底层,变量$E$,代表证据,即我们所拥有的观察。
|
||||
假设证据变量只取决于相应的状态。例如,对于我们的模型,我们假设人们是否带雨伞去办公室只取决于天气。这不一定反映了完整的事实,因为,比如说,比较自觉的、不喜欢下雨的人可能即使在阳光明媚的时候也会到处带伞,如果我们知道每个人的个性,会给模型增加更多的数据。然而,传感器马尔科夫假设忽略了这些数据,假设只有隐藏状态会影响观察。
|
||||
|
||||

|
||||
隐马尔科夫模型可以用一个有两层的马尔科夫链来表示。上层,变量$X$,代表隐藏状态。底层,变量$E$,代表证据,即我们所拥有的观察。
|
||||
|
||||
- 基于隐马尔科夫模型,可以实现多种任务:
|
||||

|
||||
|
||||
- 筛选 Filtering: 给定从开始到现在的观察结果,计算出<strong>当前</strong>状态的概率分布。例如,给从从特定时间开始到今天人们带伞的信息,我们产生一个今天是否下雨的概率分布。
|
||||
- 预测 Prediction: 给定从开始到现在的观察,计算<strong>未来</strong>状态的概率分布。
|
||||
- 平滑化 Smoothing: 给定从开始到现在的观察,计算<strong>过去</strong>状态的概率分布。例如,鉴于今天人们带了雨伞,计算昨天下雨的概率。
|
||||
- 最可能的解释 Most likely explanation: 鉴于从开始到现在的观察,计算最可能的事件顺序。
|
||||
- 最可能的解释任务可用于语音识别等过程,根据多个波形,人工智能推断出给这些波形带来的最有可能的单词或音节的序列。接下来是一个隐马尔科夫模型的 Python 实现,我们将用于最可能的解释任务:
|
||||
基于隐马尔科夫模型,可以实现多种任务:
|
||||
|
||||
- 筛选 Filtering: 给定从开始到现在的观察结果,计算出<strong>当前</strong>状态的概率分布。例如,给从从特定时间开始到今天人们带伞的信息,我们产生一个今天是否下雨的概率分布。
|
||||
- 预测 Prediction: 给定从开始到现在的观察,计算<strong>未来</strong>状态的概率分布。
|
||||
- 平滑化 Smoothing: 给定从开始到现在的观察,计算<strong>过去</strong>状态的概率分布。例如,鉴于今天人们带了雨伞,计算昨天下雨的概率。
|
||||
- 最可能的解释 Most likely explanation: 鉴于从开始到现在的观察,计算最可能的事件顺序。
|
||||
|
||||
最可能的解释任务可用于语音识别等过程,根据多个波形,人工智能推断出给这些波形带来的最有可能的单词或音节的序列。
|
||||
|
||||
接下来是一个隐马尔科夫模型的 Python 实现,我们将用于最可能的解释任务:
|
||||
|
||||
```python
|
||||
from pomegranate import *
|
||||
@@ -440,7 +460,7 @@ model = HiddenMarkovModel.from_matrix(
|
||||
model.bake()
|
||||
```
|
||||
|
||||
- 请注意,我们的模型同时具有传感器模型和过渡模型。对于隐马尔可夫模型,我们需要这两个模型。在下面的代码片段中,我们看到了人们是否带伞到大楼的观察序列,根据这个序列,我们将运行模型,它将生成并打印出最可能的解释(即最可能带来这种观察模式的天气序列):
|
||||
请注意,我们的模型同时具有传感器模型和过渡模型。对于隐马尔可夫模型,我们需要这两个模型。在下面的代码片段中,我们看到了人们是否带伞到大楼的观察序列,根据这个序列,我们将运行模型,它将生成并打印出最可能的解释 (即最可能带来这种观察模式的天气序列):
|
||||
|
||||
```python
|
||||
from model import model
|
||||
@@ -462,4 +482,4 @@ for prediction in predictions:
|
||||
print(model.states[prediction].name)
|
||||
```
|
||||
|
||||
- 在这种情况下,程序的输出将是 rain,rain,sun,rain,rain,rain,rain,sun,sun。根据我们对人们带伞或不带伞到大楼的观察,这一输出代表了最有可能的天气模式。
|
||||
在这种情况下,程序的输出将是 rain,rain,sun,rain,rain,rain,rain,sun,sun。根据我们对人们带伞或不带伞到大楼的观察,这一输出代表了最有可能的天气模式。
|
||||
|
||||
341
4.人工智能/4.3.4.1程序示例.md
Normal file
@@ -0,0 +1,341 @@
|
||||
# 程序示例
|
||||
|
||||
::: tip
|
||||
阅读程序并运行
|
||||
|
||||
完成习题
|
||||
:::
|
||||
|
||||
::: tip 📥
|
||||
本节附件下载 <Download url="https://cdn.xyxsw.site/code/4-Lecture.zip"/>
|
||||
:::
|
||||
|
||||
## Hospital(局部搜索)
|
||||
|
||||
```python
|
||||
import random
|
||||
|
||||
class Space():
|
||||
def __init__(self, height, width, num_hospitals):
|
||||
"""创建一个具有给定维度的新状态空间"""
|
||||
self.height = height # 高度
|
||||
self.width = width # 宽度
|
||||
self.num_hospitals = num_hospitals # 医院数量
|
||||
self.houses = set() # 住房位置集合
|
||||
self.hospitals = set() # 医院位置集合
|
||||
|
||||
def add_house(self, row, col):
|
||||
"""在状态空间中的特定位置添加住房"""
|
||||
self.houses.add((row, col))
|
||||
|
||||
def available_spaces(self):
|
||||
"""返回住房或医院当前未使用的所有单元格"""
|
||||
# 考虑所有可能的单元格
|
||||
candidates = set(
|
||||
(row, col)
|
||||
for row in range(self.height)
|
||||
for col in range(self.width)
|
||||
)
|
||||
# 排除所有住房和医院
|
||||
for house in self.houses:
|
||||
candidates.remove(house)
|
||||
for hospital in self.hospitals:
|
||||
candidates.remove(hospital)
|
||||
return candidates
|
||||
|
||||
def hill_climb(self, maximum=None, image_prefix=None, log=False):
|
||||
"""执行爬山算法找到解决方案"""
|
||||
count = 0
|
||||
# 从随机初始化的医院位置开始
|
||||
self.hospitals = set()
|
||||
for i in range(self.num_hospitals):
|
||||
self.hospitals.add(random.choice(list(self.available_spaces())))
|
||||
...
|
||||
# 执行算法,直到达到最大迭代次数
|
||||
while maximum is None or count < maximum:
|
||||
count += 1
|
||||
best_neighbors = []
|
||||
best_neighbor_cost = None
|
||||
# 考虑所有医院移动
|
||||
for hospital in self.hospitals:
|
||||
# 考虑一下那家医院的所有邻居
|
||||
for replacement in self.get_neighbors(*hospital):
|
||||
# 生成一组相邻的医院
|
||||
neighbor = self.hospitals.copy()
|
||||
neighbor.remove(hospital)
|
||||
neighbor.add(replacement)
|
||||
# 检查邻居是否是迄今为止最好的
|
||||
cost = self.get_cost(neighbor)
|
||||
if best_neighbor_cost is None or cost < best_neighbor_cost:
|
||||
best_neighbor_cost = cost
|
||||
best_neighbors = [neighbor]
|
||||
elif best_neighbor_cost == cost:
|
||||
best_neighbors.append(neighbor)
|
||||
# 没有一个邻居比目前的状态更好
|
||||
if best_neighbor_cost >= self.get_cost(self.hospitals):
|
||||
return self.hospitals
|
||||
# 移动到价值最高的邻居
|
||||
else:
|
||||
...
|
||||
self.hospitals = random.choice(best_neighbors)
|
||||
...
|
||||
|
||||
def random_restart(self, maximum, image_prefix=None, log=False):
|
||||
"""多次重复爬山算法"""
|
||||
best_hospitals = None
|
||||
best_cost = None
|
||||
# 重复爬山算法的固定次数
|
||||
for i in range(maximum):
|
||||
hospitals = self.hill_climb()
|
||||
cost = self.get_cost(hospitals)
|
||||
if best_cost is None or cost < best_cost:
|
||||
best_cost = cost
|
||||
best_hospitals = hospitals
|
||||
...
|
||||
else:
|
||||
...
|
||||
...
|
||||
return best_hospitals
|
||||
|
||||
def get_cost(self, hospitals):
|
||||
"""计算从住房到最近医院的距离总和"""
|
||||
cost = 0
|
||||
for house in self.houses:
|
||||
cost += min(
|
||||
abs(house[0] - hospital[0]) + abs(house[1] - hospital[1])
|
||||
for hospital in hospitals
|
||||
)
|
||||
return cost
|
||||
|
||||
def get_neighbors(self, row, col):
|
||||
"""返回尚未包含住房或医院的邻居"""
|
||||
candidates = [
|
||||
(row - 1, col),
|
||||
(row + 1, col),
|
||||
(row, col - 1),
|
||||
(row, col + 1)
|
||||
]
|
||||
neighbors = []
|
||||
for r, c in candidates:
|
||||
if (r, c) in self.houses or (r, c) in self.hospitals:
|
||||
continue
|
||||
if 0 <= r < self.height and 0 <= c < self.width:
|
||||
neighbors.append((r, c))
|
||||
return neighbors
|
||||
|
||||
def output_image(self, filename):
|
||||
"""生成所有房屋和医院的图像(不作要求)"""
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
cell_size = 100
|
||||
cell_border = 2
|
||||
cost_size = 40
|
||||
padding = 10
|
||||
|
||||
# Create a blank canvas
|
||||
img = Image.new(
|
||||
"RGBA",
|
||||
(self.width * cell_size,
|
||||
self.height * cell_size + cost_size + padding * 2),
|
||||
"white"
|
||||
)
|
||||
house = Image.open("assets/images/House.png").resize(
|
||||
(cell_size, cell_size)
|
||||
)
|
||||
hospital = Image.open("assets/images/Hospital.png").resize(
|
||||
(cell_size, cell_size)
|
||||
)
|
||||
font = ImageFont.truetype("assets/fonts/OpenSans-Regular.ttf", 30)
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
for i in range(self.height):
|
||||
for j in range(self.width):
|
||||
|
||||
# Draw cell
|
||||
rect = [
|
||||
(j * cell_size + cell_border,
|
||||
i * cell_size + cell_border),
|
||||
((j + 1) * cell_size - cell_border,
|
||||
(i + 1) * cell_size - cell_border)
|
||||
]
|
||||
draw.rectangle(rect, fill="black")
|
||||
|
||||
if (i, j) in self.houses:
|
||||
img.paste(house, rect[0], house)
|
||||
if (i, j) in self.hospitals:
|
||||
img.paste(hospital, rect[0], hospital)
|
||||
|
||||
# Add cost
|
||||
draw.rectangle(
|
||||
(0, self.height * cell_size, self.width * cell_size,
|
||||
self.height * cell_size + cost_size + padding * 2),
|
||||
"black"
|
||||
)
|
||||
draw.text(
|
||||
(padding, self.height * cell_size + padding),
|
||||
f"Cost: {self.get_cost(self.hospitals)}",
|
||||
fill="white",
|
||||
font=font
|
||||
)
|
||||
|
||||
img.save(filename)
|
||||
|
||||
# 创建一个状态空间并随机添加住房
|
||||
s = Space(height=10, width=20, num_hospitals=3)
|
||||
for i in range(15):
|
||||
s.add_house(random.randrange(s.height), random.randrange(s.width))
|
||||
# 使用局部搜索来确定医院位置
|
||||
hospitals = s.random_restart(maximum=100, image_prefix="hospitals", log=True)
|
||||
```
|
||||
|
||||
## Production(线性规划)
|
||||
|
||||
```python
|
||||
import scipy.optimize
|
||||
# Objective Function: 50x_1 + 80x_2
|
||||
# Constraint 1: 5x_1 + 2x_2 <= 20
|
||||
# Constraint 2: -10x_1 + -12x_2 <= -90
|
||||
result = scipy.optimize.linprog(
|
||||
[50, 80], # Cost function: 50x_1 + 80x_2
|
||||
A_ub=[[5, 2], [-10, -12]], # Coefficients for inequalities
|
||||
b_ub=[20, -90], # Constraints for inequalities: 20 and -90
|
||||
)
|
||||
if result.success:
|
||||
print(f"X1: {round(result.x[0], 2)} hours")
|
||||
print(f"X2: {round(result.x[1], 2)} hours")
|
||||
else:
|
||||
print("No solution")
|
||||
```
|
||||
|
||||
## Schedule(约束满足)
|
||||
|
||||
```python
|
||||
"""没有任何启发式或推理的自然回溯搜索"""
|
||||
VARIABLES = ["A", "B", "C", "D", "E", "F", "G"]
|
||||
CONSTRAINTS = [
|
||||
("A", "B"),
|
||||
("A", "C"),
|
||||
("B", "C"),
|
||||
("B", "D"),
|
||||
("B", "E"),
|
||||
("C", "E"),
|
||||
("C", "F"),
|
||||
("D", "E"),
|
||||
("E", "F"),
|
||||
("E", "G"),
|
||||
("F", "G")
|
||||
]
|
||||
|
||||
def backtrack(assignment):
|
||||
"""运行回溯搜索以查找赋值"""
|
||||
# 检查赋值是否完成
|
||||
if len(assignment) == len(VARIABLES):
|
||||
return assignment
|
||||
# 尝试一个新变量
|
||||
var = select_unassigned_variable(assignment)
|
||||
for value in ["Monday", "Tuesday", "Wednesday"]:
|
||||
new_assignment = assignment.copy()
|
||||
new_assignment[var] = value
|
||||
if consistent(new_assignment):
|
||||
result = backtrack(new_assignment)
|
||||
if result is not None:
|
||||
return result
|
||||
return None
|
||||
|
||||
def select_unassigned_variable(assignment):
|
||||
"""按顺序选择尚未赋值的变量"""
|
||||
for variable in VARIABLES:
|
||||
if variable not in assignment:
|
||||
return variable
|
||||
return None
|
||||
|
||||
|
||||
def consistent(assignment):
|
||||
"""检查分配是否一致"""
|
||||
for (x, y) in CONSTRAINTS:
|
||||
# 仅考虑变量赋值都已指定的弧
|
||||
if x not in assignment or y not in assignment:
|
||||
continue
|
||||
# 如果两者的值相同,则不一致
|
||||
if assignment[x] == assignment[y]:
|
||||
return False
|
||||
# 如果没有不一致的地方,那么赋值是一致的
|
||||
return True
|
||||
|
||||
solution = backtrack(dict())
|
||||
print(solution)
|
||||
```
|
||||
|
||||
使用命令`pip install python-constraint`安装 constraint 库
|
||||
|
||||
```python
|
||||
from constraint import *
|
||||
|
||||
problem = Problem()
|
||||
|
||||
# 添加变量
|
||||
problem.addVariables(
|
||||
["A", "B", "C", "D", "E", "F", "G"],
|
||||
["Monday", "Tuesday", "Wednesday"]
|
||||
)
|
||||
|
||||
# 添加约束
|
||||
CONSTRAINTS = [
|
||||
("A", "B"),
|
||||
("A", "C"),
|
||||
("B", "C"),
|
||||
("B", "D"),
|
||||
("B", "E"),
|
||||
("C", "E"),
|
||||
("C", "F"),
|
||||
("D", "E"),
|
||||
("E", "F"),
|
||||
("E", "G"),
|
||||
("F", "G")
|
||||
]
|
||||
for x, y in CONSTRAINTS:
|
||||
problem.addConstraint(lambda x, y: x != y, (x, y))
|
||||
|
||||
# Solve problem
|
||||
for solution in problem.getSolutions():
|
||||
print(solution)
|
||||
```
|
||||
|
||||
## Quiz
|
||||
|
||||
1. 对于以下哪一项,即使多次重新运行算法,也会始终找到相同的解决方案?
|
||||
假设一个问题的目标是最小化成本函数,并且状态空间中的每个状态都有不同的成本。
|
||||
1. Steepest-ascent hill-climbing,每次从不同的初始状态开始
|
||||
2. Steepest-ascent hill-climbing,每次都从相同的初始状态开始
|
||||
3. Stochastic hill-climbing,每次从不同的初始状态开始
|
||||
4. Stochastic hill-climbing,每次都从相同的初始状态开始
|
||||
5. 无论是 steepest-ascent 还是 stochastic hill climbing,只要你总是从同一个初始状态开始
|
||||
6. 无论是 steepest-ascent 还是 stochastic hill climbing,只要每次都从不同的初始状态开始
|
||||
7. 没有任何版本的爬山算法能保证每次都能得到相同的解决方案
|
||||
|
||||
2. 下面两个问题都会问你关于下面描述的优化问题。
|
||||
一位农民正在尝试种植两种作物,`作物 1` 和`作物 2`,并希望实现利润最大化。农民将从种植的每英亩`作物 1` 中获得 500 美元的利润,从种植的每英亩`作物 2` 中获得 400 美元的利润。然而,农民今天需要在早上 7 点到晚上 7 点之间的 12 个小时内完成所有的种植。种植一英亩的`作物 1` 需要 3 个小时,种植一英亩`作物 2` 需要 2 个小时。农民在供应方面也很有限:他有足够的供应种植 10 英亩的`作物 1`,有足够的资源种植 4 英亩的`作物 2`。假设变量 C1 表示要种植的`作物 1` 的英亩数,变量 C2 表示要种植`作物 2` 的英亩数。
|
||||
|
||||
对于这个问题,什么是有效的目标函数?
|
||||
|
||||
1. 10 \* C1 + 4 \* C2
|
||||
2. -3 \* C1 - 2 \* C2
|
||||
3. 500 \* 10 \* C1 + 400 \* 4 \* C2
|
||||
4. 500 \* C1 + 400 \* C2
|
||||
5. C1 + C2
|
||||
|
||||
3. 这个问题的制约因素是什么?
|
||||
1. 3 \* C1 + 2 \* C2 <= 12, C1 <= 10, C2 <= 4
|
||||
2. 3 \* C1 + 2 \* C2 <= 12, C1 + C2 <= 14
|
||||
3. 3 \* C1 <= 10, 2 \* C2 <= 4
|
||||
4. C1 + C2 <= 12, C1 + C2 <= 14
|
||||
|
||||
4. 下面的问题将问你以下考试安排约束满足图,其中每个节点代表一个课程。每门课程都与可能的考试日的初始域相关联(大多数课程可能在周一、周二或周三;少数课程已经被限制在一天内)。两个节点之间的边意味着这两个课程必须在不同的日子进行考试。
|
||||
|
||||
在对整个问题满足弧一致性之后,变量 C、D 和 E 的结果域是什么?
|
||||
|
||||
1. C 的域是\{Mon,Tue\},D 的域是\{Wed\},E 的域是\{Mon\}
|
||||
2. C 的域是\{Mon\},D 的域是\{Wed\},E 的域为\{Tue\}
|
||||
3. C 的域是\{Mon\},D 的域是\{Tue\},E 的域为\{Wed\}
|
||||
4. C 的域是\{Mon\},D 的域是\{Mon,Wed\},E 的域是\{Tue,Wed\}
|
||||
5. C 的域是\{Mon,Tue,Wed\},D 的域是\{Mon,Wed\},E 的域是\{Mon,Tue,Wed\}
|
||||
6. C 的域是\{Mon\},D 的域是\{Mon,Wed\},E 的域是\{Mon,Tue,Wed\}
|
||||
138
4.人工智能/4.3.4.2项目:填词游戏.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# 项目——填词游戏
|
||||
|
||||
::: tip
|
||||
我们为你提供了一个简单有趣的项目,帮助你进行知识巩固,请认真阅读文档内容。
|
||||
|
||||
如果你卡住了,请记得回来阅读文档,或请求身边人的帮助。
|
||||
:::
|
||||
|
||||
::: tip 📥
|
||||
本节附件下载 <Download url="https://cdn.xyxsw.site/code/4-Projects.zip"/>
|
||||
:::
|
||||
|
||||
编写一个人工智能来完成填词游戏。
|
||||
|
||||
能够实现将文字转换为图片。
|
||||
|
||||
```shell
|
||||
$ python generate.py data/structure1.txt data/words1.txt output.png
|
||||
|█|█|█|█|█|█|█|█|█|█|█|█|█|█|
|
||||
|█|█|█|█|█|█|█|M|█|█|█|█|R|█|
|
||||
|█|I|N|T|E|L|L|I|G|E|N|C|E|█|
|
||||
|█|N|█|█|█|█|█|N|█|█|█|█|S|█|
|
||||
|█|F|█|█|L|O|G|I|C|█|█|█|O|█|
|
||||
|█|E|█|█|█|█|█|M|█|█|█|█|L|█|
|
||||
|█|R|█|█|█|S|E|A|R|C|H|█|V|█|
|
||||
|█|█|█|█|█|█|█|X|█|█|█|█|E|█|
|
||||
|█|█|█|█|█|█|█|█|█|█|█|█|█|█|
|
||||
```
|
||||
|
||||

|
||||
|
||||
## 背景
|
||||
|
||||
你如何生成一个填字游戏?考虑到填字游戏的结构 (即网格中哪些方格需要填入字母),以及要使用的单词列表,问题就变成了选择哪些单词应该填入每个垂直或水平的方格序列。我们可以将这种问题建模为一个约束满足问题。每一个方格序列都是一个变量,我们需要决定它的值 (在可能的单词域中哪个单词将被填入该序列)。考虑一下下面的字谜结构。
|
||||
|
||||

|
||||
|
||||
在这个结构中,我们有四个变量,代表了我们需要填入这个字谜的四个单词 (在上图中每个单词都用数字表示)。每个变量由四个值定义:它开始的行 (`i`值),它开始的列 (`j`值),单词的方向 (纵向或横向 down or across),以及单词的长度。例如,`变量1`将是一个由第 1 行 (假设从顶部计数的 0 索引)、第 1 列 (假设从左边计数的 0 索引)、方向为`across`和`4`的长度表示的变量。
|
||||
|
||||
与许多约束满足问题一样,这些变量有一元和二元约束。变量的一元约束是由其长度决定的。例如,对于`变量1`来说,数值`BYTE`可以满足一元约束,但是数值`BIT`则不能 (它有错误的字母数量)。因此,任何不满足变量的一元约束的值都可以立即从变量的域中删除。
|
||||
|
||||
变量的二元约束是由其与相邻变量的重合度给出的。`变量1`有一个邻居:`变量2`。`变量2`有两个邻居:`变量1`和`变量3`。对于每一对相邻的变量,这些变量都有一个重叠部分:一个它们共同的单方块。我们可以将这种重叠表示为每个变量有用相同字符位置的索引对。例如,`变量1`和`变量2`之间的重叠可以表示为一对`(1, 0)`,这意味着`变量1`在索引 1 处的字符必然与`变量2`在索引 0 处的字符相同 (再次假设索引从 0 开始)。因此,`变量2`和`变量3`之间的重叠将被表示为一对`(3, 1)`,`变量2`的值的字符`3`必须与`变量3`的值的字符`1`相同。
|
||||
|
||||
对于这个问题,我们将增加一个额外的约束条件,即所有的单词必须是不同的:同一个单词不应该在谜题中重复出现多次。
|
||||
|
||||
那么,接下来的挑战是写一个程序来找到一个满意的赋值:为每个变量提供一个不同的词 (来自给定的词汇表),从而满足所有的一元和二元约束。
|
||||
|
||||
## 理解
|
||||
|
||||
这个项目中有两个 Python 文件:`crossword.py`和`generate.py`。第一个文件已经完全为你写好了,第二个文件有一些函数留给你去实现。
|
||||
|
||||
首先,让我们看一下`crossword.py`。这个文件定义了两个类,`Variable`(代表填字游戏中的变量) 和`Crossword`(代表填字游戏本身)。
|
||||
|
||||
注意,要创建一个变量,我们必须指定四个值:它的第`i`行,第`j`列,它的方向 (常数`Variable.ACROSS`或常数`Variable.DOWN``),以及它的长度(`length``)。
|
||||
|
||||
字谜类需要两个值来创建一个新的字谜:一个定义了字谜结构的`structure_file`(`_`用来代表空白单元格,任何其他字符都代表不会被填入的单元格) 和一个定义了字词列表 (每行一个) 的`word_file`,用来作为游戏的词汇表。这些文件的三个例子可以在项目的数据目录中找到,也欢迎你自己创建。
|
||||
|
||||
特别要注意的是,对于任何一个字谜对象的字谜,我们都会存储以下的数值:
|
||||
|
||||
- `crossword.height`是一个整数,代表填字游戏的高度。
|
||||
- `crossword.width`是一个整数,代表填字游戏的宽度。
|
||||
- `crossword.structure`是一个二维列表,代表字谜的结构。对于任何有效的第 i 行和第 j 列,如果该单元格是空白的,`crossword.structure[i][j]`将为真 (必须在该单元格中填入一个字符),否则将为假 (该单元格中没有字符要填)。
|
||||
- `crossword.words`是一个包含所有单词的集合,在构建填字游戏的时候,可以从这些单词中提取。
|
||||
- `crossword.variables`是谜题中所有变量的集合 (每个变量都是一个 Variable 对象)。
|
||||
- `crossword.overlaps`是一个字典,它将一对变量映射到它们的重合处。对于任何两个不同的变量 v1 和 v2,如果这两个变量没有重叠,`crossword.overlaps[v1, v2]`将是`None`,如果这两个变量有重叠,则是一对整数`(i, j)`。这对`(i, j)`应被解释为:`v1`的第`i`个字符的值必须与`v2`的第`j`个字符的值相同。
|
||||
|
||||
`Crossword`对象还支持一个方法`neighbors`,它可以返回与给定变量重叠的所有变量。也就是说,`crossword.neighbors(v1)`将返回一个与变量`v1`相邻的所有变量的集合。
|
||||
|
||||
接下来,看一下`generate.py`。在这里,我们定义了一个`CrosswordCreator`类,我们将用它来解决填字游戏。当一个`CrosswordCreator`对象被创建时,它得到一个填字游戏的属性,它应该是一个`Crossword`对象 (因此具有上面描述的所有属性)。每个`CrosswordCreator`对象还得到一个域属性:一个字典,它将变量映射到该变量可能作为一个值的一组词。最初,这组词是我们词汇表中的所有词,但我们很快就会写函数来限制这些域。
|
||||
|
||||
我们还为你定义了一些函数,以帮助你测试你的代码:`print`将向终端打印你的填字游戏的一个给定的赋值 (每个赋值,在这个函数和其他地方,是一个字典,将变量映射到它们相应的词)。同时,`save`将生成一个与给定作业相对应的图像文件 (如果你无法使用这个函数,你需要`pip3 install Pillow`)。 `letter_grid`是一个被`print`和`save`使用的辅助函数,它为给定的赋值生成一个所有字符在其适当位置的 2D 列表:你可能不需要自己调用这个函数,但如果你想的话,欢迎你这样做。
|
||||
|
||||
最后,注意`solve`函数。这个函数做了三件事:首先,它调用`enforce_node_consistency`来强制执行填字游戏的节点一致性,确保变量域中的每个值都满足一元约束。接下来,该函数调用`ac3`来强制执行弧一致性,确保二元约束得到满足。最后,该函数在最初的空赋值 (空字典 dict()) 上调用`backtrack`,试图计算出问题的解决方案。
|
||||
|
||||
不过,`enforce_node_consistency`、`ac3`和`backtrack`等函数还没有实现 (以及其他函数)。这就是你的任务。
|
||||
|
||||
## 明确
|
||||
|
||||
完成`grece_node_consistency`, `revise`, `ac3`, `assignment_complete`, `consistent`, `order_domain_values`, `selected_unassigned_variable`和`backtrack`在`generate.py`中的实现,这样如果有有解的话你的人工智能就能生成完整的字谜。
|
||||
|
||||
- `enforce_node_consistency`函数应该更新`self.domains`,使每个变量都是节点一致的。
|
||||
- 回顾一下,当对每个变量来说,其域中的每个值都与该变量的一元约束一致时,就实现了节点一致性。在填字游戏的情况下,这意味着要确保变量域中的每个值的字母数与变量的长度相同。
|
||||
- 要从一个变量`v`的域中移除一个值`x`,因为`self.domains`是一个将变量映射到数值集的字典,你可以调用`self.domains[v].remove(x)`。
|
||||
- 这个函数不需要返回值。
|
||||
- `revise`函数应该使变量 x 与变量 y 保持弧一致性。
|
||||
- `x`和`y`都是`Variable`对象,代表谜题中的变量。
|
||||
- 回顾一下,当`x`的域中的每一个值在`y`的域中都有一个不引起冲突的可能值时,`x`就与`y`保持弧一致性。(在填字游戏的背景下,冲突是指一个方格,两个变量对它的字符值意见不一)。
|
||||
- 为了使`x`与`y`保持一致,你要从`x`的域中删除任何在`y`的域中没有相应可能值的值。
|
||||
- 回顾一下,你可以访问`self.crossword.overlaps`来获得两个变量之间的重叠,如果有的话。
|
||||
- `y`的域应该不被修改。
|
||||
- 如果对`x`的域进行了修改,该函数应返回`True`;如果没有修改,则应返回`False`。
|
||||
|
||||
- `ac3`函数应该使用`AC3`算法,对问题实施弧一致性。回顾一下,当每个变量域中的所有值都满足该变量的二进制约束时,就实现了弧一致性。
|
||||
- 回顾一下,`AC3`算法保持着一个要处理的弧的队列。这个函数需要一个叫做`arcs`的可选参数,代表要处理的弧的初始列表。如果`arcs`是`None`,你的函数应该从问题中的所有弧的初始队列开始。否则,你的算法应该从一个初始队列开始,该队列中只有在列表`arcs`中的弧 (其中每个弧是一个变量`x`和另一个变量`y`的元组`(x,y)`)。
|
||||
- 回顾一下,为了实现`AC3`,你要一次一次地修改队列中的每个弧。不过,任何时候你对一个域做了改变,你可能需要在队列中增加额外的弧,以确保其他弧保持一致。
|
||||
- 你可能会发现在`ac3`的实现中调用`revise`函数是很有帮助的。
|
||||
- 如果在执行弧一致性的过程中,你从一个域中删除了所有剩余的值,则返回`False`(这意味着问题无解,因为这个变量已经没有可能的值了)。否则,返回`True`。
|
||||
- 你不需要担心在这个函数中强制执行词的唯一性 (你将在`consistent`函数中实现这个检查。)
|
||||
|
||||
- `assignment_complete`函数应该 (如其名所示) 检查一个给定的赋值是否完成。
|
||||
- `assignment`是一个字典,其中键是`Variable`对象,值是代表这些变量将采取的单词的字符串。
|
||||
- 如果每个字谜变量都被分配到一个值 (不管这个值是什么),那么这个赋值就是完整的。
|
||||
- 如果赋值完成,该函数应该返回`True`,否则返回`False`。
|
||||
|
||||
- `consistent`函数应该检查一个给定的`assignment`是否一致。
|
||||
- `assignment`是一个字典,其中的键是`Variable`对象,值是代表这些变量将采取的词语的字符串。请注意,赋值不一定是完整的:不是所有的变量都会出现在赋值中。
|
||||
- 如果一个赋值满足问题的所有约束条件,那么它就是一致的:也就是说,所有的值都是不同的,每个值的长度都是正确的,并且相邻的变量之间没有冲突。
|
||||
- 如果赋值是一致的,该函数应该返回`True`,否则返回`False`。
|
||||
|
||||
- `order_domain_values`函数应该返回一个`var`域中所有数值的列表,根据最小约束值启发式排序。
|
||||
- `var`将是一个变量对象,代表谜题中的一个变量。
|
||||
- 回顾一下,最小约束值启发式的计算方法是一个赋值导致约束邻近的未分配的变量的数量。也就是说,如果给`var`赋值的结果是排除了邻近变量的`n`个可能的选择,你应该按照`n`的升序排列你的结果。
|
||||
- 请注意,在`assignment`中出现的任何变量都已经有了一个值,因此在计算相邻未赋值变量被排除的值的数量时不应该被计算在内。
|
||||
- 对于排除相邻变量相同数量可能选择的域值,任何排序都是可以接受的。
|
||||
- 回顾一下,你可以访问`self.crossword.overlaps`来获得两个变量之间的重叠,如果有的话。
|
||||
- 首先通过返回一个任意顺序的数值列表来实现这个函数可能会有帮助 (这仍然会产生正确的填字游戏)。一旦你的算法开始工作,你就可以回去确保这些值是以正确的顺序返回的。
|
||||
- 你可能会发现根据一个特定的 key 来对一个[列表](https://docs.python.org/3/howto/sorting.html)进行排序是很有帮助的:Python 包含一些有用的函数来实现这一点。
|
||||
|
||||
- `select_unassigned_variable`函数应该根据最小剩余值启发式,然后是度启发式,返回字谜中尚未被赋值的单个变量。
|
||||
- `assignment`是一个字典,其中键是`Variable`对象,值是代表这些变量将承担的单词的字符串。你可以假设赋值不会是完整的:不是所有的变量都会出现在`assignment`中。
|
||||
- 你的函数应该返回一个`Variable`对象。你应该返回在其域中剩余数值最少的变量。如果变量之间存在平局,你应该在这些变量中选择度最大的变量 (拥有最多的邻居)。如果在这两种情况下都相同,你可以在相同的变量中任意选择。
|
||||
- 首先通过返回任意未分配的变量来实现这个函数可能是有帮助的 (这应该仍然会产生正确的填字游戏)。一旦你的算法开始工作,你就可以回去修改这个函数确保你是根据启发式方法返回一个变量。
|
||||
- 你可能会发现根据一个特定的 key 来对一个列表进行[排序](https://docs.python.org/3/howto/sorting.html)是很有帮助的:Python 包含一些有用的函数来实现这一点。
|
||||
|
||||
- `backtrack`函数应该接受一个部分赋值`assignment`作为输入,并且使用回溯搜索,如果有可能的话,返回一个完整的令人满意的变量赋值。
|
||||
- `assignment`是一个字典,其中键是`Variable`对象,值是代表这些变量将承担的单词的字符串。你可以假设赋值不会是完整的:不是所有的变量都会出现在`assignment`中。
|
||||
- 如果有可能生成一个令人满意的字谜,你的函数应该返回完整的赋值:一个字典,其中每个变量是一个键,值是该变量应该承担的单词。如果不可能产生令人满意的赋值,该函数应该返回`None`。
|
||||
- 如果你愿意,你可能会发现,如果你把搜索和推理交织在一起,你的算法会更有效率 (比如每次做新的赋值时都要保持弧一致性)。我们不要求你这样做,但允许你这样做,只要你的函数仍然产生正确的结果。(正是由于这个原因,`ac3`函数允许一个`arcs`的参数,以防你想从不同的弧队列开始)。
|
||||
|
||||
除了要求你实现的函数外,你不应该修改`generate.py`中的任何其他东西,尽管你可以编写额外的函数和/或导入其他 Python 标准库模块。如果你熟悉`numpy`或`pandas`,你也可以导入它们,但是你不应该使用任何其他的第三方 Python 模块。你不应该修改`crossword.py`中的任何东西。
|
||||
|
||||
## 提示
|
||||
|
||||
- 对于`order_domain_values`和`select_unassigned_variable`来说,不以启发式方法实现它们,然后再添加启发式方法可能会有帮助。你的算法仍然可以工作:只是在找到一个解决方案之前,它可能会探索更多的分配,而不是它需要的。
|
||||
|
||||
- 要运行你的程序,你可以运行类似`python generate.py data/structure1.txt data/words1.txt`的命令,指定一个结构文件和一个单词文件。如果可以进行赋值,你应该看到打印出来的赋值。你也可以为图像文件添加一个额外的命令行参数,如运行`python generate.py data/structure1.txt data/words1.txt output.png`,可以为生成的填字游戏生成一个图像表示。
|
||||
|
||||
- `Crossword`类有一个`neighbors`函数,可以用来访问某个特定变量的所有邻居 (即重叠的变量)。在你需要确定某个特定变量的邻居时,请随时使用这个函数。
|
||||
301
4.人工智能/4.3.4最优化.md
Normal file
@@ -0,0 +1,301 @@
|
||||
# 最优化
|
||||
|
||||
最优化是指从一组可能的选项中选择最佳选项。我们已经遇到过试图找到最佳选项的问题,比如在极大极小算法中,今天我们将学习一些工具,可以用来解决更广泛的问题。
|
||||
|
||||
## 局部搜索 (Local Search)
|
||||
|
||||
局部搜索是一种保持单一节点并通过移动到邻近的节点进行搜索的搜索算法。这种类型的算法与我们之前看到的搜索类型不同。例如,在解决迷宫的过程中,我们想找到通往目标的最快捷的方法,而局部搜索则对寻找问题的最佳答案感兴趣。通常情况下,局部搜索会带来一个不是最佳但 "足够好 "的答案,以节省计算能力。考虑一下下面这个局部搜索问题的例子:我们有四所房子在设定的位置。我们想建两所医院,使每所房子到医院的距离最小。这个问题可以形象地描述如下:
|
||||
|
||||

|
||||
|
||||
在这幅图中,我们看到的是房屋和医院的可能配置。它们之间的距离是用曼哈顿距离 (向上、向下和向两侧移动的次数;在[搜索](4.3.1搜索.md) 中详细讨论) 来衡量的,从每个房子到最近的医院的距离之和是 17。我们称其为成本 __(cost)__,因为我们试图使这个距离最小化。在这种情况下,一个状态将是房屋和医院的任何一个配置。
|
||||
|
||||
把这个概念抽象化,我们可以把每一种房屋和医院的配置表现为下面的状态空间图。图中的每一条都代表一个状态的值,在我们的例子中,它是房屋和医院配置的成本。
|
||||
|
||||

|
||||
|
||||
从这个可视化的角度来看,我们可以为我们接下来的讨论定义几个重要的术语:
|
||||
|
||||
- 目标函数 __(Objective Function)__ 是一个函数,我们用它来最大化解决方案的值。
|
||||
- 成本函数 __(Cost Function)__ 是一个我们用来最小化解决方案成本的函数 (这就是我们在房屋和医院的例子中要使用的函数。我们想要最小化从房屋到医院的距离)。
|
||||
- 当前状态 __(Current State)__ 是指函数目前正在考虑的状态。
|
||||
- 邻居状态 __(Neighbor State)__ 是当前状态可以过渡到的一个状态。在上面的一维状态空间图中,邻居状态是指当前状态两侧的状态。在我们的例子中,邻居状态可以是将其中一家医院向任何方向移动一步所产生的状态。邻居状态通常与当前状态相似,因此,其值与当前状态的值接近。
|
||||
|
||||
请注意,局部搜索算法的工作方式是考虑当前状态下的一个节点,然后将该节点移动到当前状态的一个邻节点处。这与极大极小算法不同,例如,在极大极小算法中,状态空间中的每一个状态都被递归地考虑。
|
||||
|
||||
## 爬山算法 (Hill Climbing)
|
||||
|
||||
爬山算法是局部搜索算法的一种类型。在这个算法中,邻居的状态与当前的状态进行比较,如果其中任何一个状态更好,我们就把当前的节点从当 - 的状态改为该邻居的状态。“好状态”的定义是由目标函数决定的,倾向于一个较高的值,或一个递减函数,倾向于一个较低的值。
|
||||
|
||||
一个爬山算法在伪代码中会有以下样子:
|
||||
|
||||
```txt
|
||||
function Hill-Climb(problem):
|
||||
current = initial state of problem
|
||||
repeat:
|
||||
neighbor = best valued neighbor of current
|
||||
if neighbor not better than current:
|
||||
return current
|
||||
current = neighbor
|
||||
```
|
||||
|
||||
在这个算法中,我们从一个当前状态开始。在一些问题中,我们会知道当前的状态是什么,而在其他问题中,我们将不得不从随机选择一个状态开始。然后,我们重复以下动作:我们评估邻居状态,选择一个具有最佳值的邻居状态。然后,我们将这个邻居状态的值与当前状态的值进行比较。如果邻居状态更好,我们将当前状态切换到邻居状态,然后重复这个过程。当我们将最佳邻居与当前状态进行比较,并且当前状态更好时,该过程就结束了。然后,我们返回当前状态。
|
||||
|
||||
使用爬山算法,我们可以开始改进我们在例子中分配给医院的位置。经过几次转换,我们得到了以下状态:
|
||||
|
||||

|
||||
|
||||
在这个状态下,成本是 11,比初始状态的成本 17 有所提高。然而,这还不是最佳状态。例如,将左边的医院移到左上角的房子下面,会使成本达到 9,比 11 好。然而,这个版本的爬山算法无法达到这个目标,因为所有的邻居状态都至少和当前状态的成本一样高。从这个意义上说,爬坡算法是短视的,它经常满足于比其他一些解决方案更好的解决方案,但不一定是所有可能的解决方案中最好的。
|
||||
|
||||
### 局部和全局最小值和最大值
|
||||
|
||||
如上所述,爬山算法可能卡在局部最大值或最小值中。局部最大值是一个比其相邻状态有更高值的状态。而全局最大值是指在状态空间的所有状态中具有最高值的状态。
|
||||
|
||||

|
||||
|
||||
相比之下,局部最小值是一个比其相邻状态的值更低的状态。与此相对,全局最小值是指在状态空间中所有状态中具有最低值的状态。
|
||||
|
||||

|
||||
|
||||
爬山算法的问题是,它们可能会在局部最小和最大中结束。一旦算法到达一个点,其邻居状态就目标函数而言,比当前状态更糟糕,算法就会停止。特殊类型的局部最大值和最小值包括平坦的局部最大值/最小值 __(flat local maximum/minimum)__,即多个数值相同的状态相邻,形成一个plateau,其邻居状态的数值更差;以及 __shoulder__,邻居状态既可以更好,也可以更差。从 plateau 的中间开始,算法将无法向任何方向推进。
|
||||
|
||||

|
||||
|
||||
### 爬山算法的变体
|
||||
|
||||
由于爬山算法的局限性,人们想到了多种变体来克服卡在局部最小值和最大值的问题。该算法的所有变体的共同点是,无论采用何种策略,每一种变体都有可能陷入局部最小或最大,并且没有办法继续优化。下面的算法是这样表述的:数值越大越好,但它们也适用于成本函数,其目标是使成本最小化。
|
||||
|
||||
- __Steepest-ascent__: 选择值最高的邻居状态。
|
||||
- Stochastic: 从值较高的邻居状态中随机选择。这样做,我们选择去任何比我们的值更高的方向。
|
||||
- __First-choice__: 选择第一个值较高的邻居状态。
|
||||
- __Random-restart__: 进行多次爬山。每次都从一个随机状态开始。比较每次试验的最大值,并在这些最大值中选择一个。
|
||||
- __Local Beam Search__: 选择值最高的 k 个邻居状态。这与大多数本地搜索算法不同,它使用多个节点进行搜索,而不是只有一个节点。
|
||||
|
||||
虽然局部搜索算法并不总是给出最好的解决方案,但在考虑所有可能的状态在计算上不可行的情况下,它们往往能给出足够好的解决方案。
|
||||
|
||||
## 模拟退火算法 (Simulated Annealing)
|
||||
|
||||
尽管我们已经看到了可以改进爬山算法的变种,但它们都有一个共同的错误:一旦算法达到局部最大值,它就会停止运行。模拟退火算法允许算法在卡在局部最大值时"摆脱"自己。
|
||||
|
||||
退火是指加热金属并让其缓慢冷却的过程,其作用是使金属变硬。这被用来比喻模拟退火算法,该算法开始时温度较高,更有可能做出随机决定,随着温度的降低,它变得不太可能做出随机决定,变得更加"坚定"。这种机制允许算法将其状态改变为比当前状态更差的邻居状态,这就是它如何摆脱局部最大值的原因。以下是模拟退火法的伪代码:
|
||||
|
||||
```txt
|
||||
function Simulated-Annealing(problem, max):
|
||||
current = initial state of problem
|
||||
for t = 1 to max:
|
||||
T = Temperature(t)
|
||||
neighbor = random neighbor of current
|
||||
ΔE = how much better neighbor is than current
|
||||
if ΔE > 0:
|
||||
current = neighbor
|
||||
with probability e^(ΔE/T) set current = neighbor
|
||||
return current
|
||||
```
|
||||
|
||||
该算法将一个`problem`和`max`作为输入,`max`是它应该重复的次数。对于每个迭代,`T`是用一个`Temperature`函数来设置的。这个函数在早期迭代中返回一个较高的值 (当`t`较低时),在后期迭代中返回一个较低的值 (当`t`较高时)。然后,随机选择一个邻居状态,并计算`ΔE`,使其量化邻居状态比当前状态好的程度。如果邻居状态比当前状态好 (`ΔE>0`),像以前一样,我们将当前状态设置为邻居状态。然而,当邻居状态较差时 (`ΔE<0`),我们仍然可能将我们的当前状态设置为该邻居状态,并且我们以$e^{ΔE/t}$的概率这样做。这里的意思是,更小的`ΔE`将导致邻居状态被选择的概率降低,而温度`t`越高,邻居状态被选择的概率越高。这意味着邻居状态越差,被选择的可能性就越小,而算法在其过程中越早,就越有可能将一个较差的邻居状态设置为当前状态。这背后的数学原理如下:`e`是一个常数 (大约 2.72),`ΔE`是负数 (因为这个邻居比当前状态更糟糕)。温度`t`越高,ΔE/`t`就越接近于 0,使概率更接近于 1。
|
||||
|
||||
### 旅行商问题 (Traveling Salesman Problem)
|
||||
|
||||
在旅行商问题中,任务是连接所有的点,同时选择最短的距离。例如,这就是快递公司需要做的事情:找到从商店到所有客户家的最短路线,然后再返回。
|
||||
|
||||
| 优化前 | 优化后 |
|
||||
| ------------------------------ | ------------------------------ |
|
||||
|  |  |
|
||||
|
||||
在这种情况下,邻居状态可以被看作是两个箭头互换位置的状态。计算每一个可能的组合使得这个问题在计算上要求很高 (10 个点给了我们 10! 或者说 3,628,800 条可能的路线)。通过使用模拟退火算法,可以以较低的计算成本找到一个好的解决方案。
|
||||
|
||||
## 线性规划 (Linear Programming)
|
||||
|
||||
线性规划是一个优化线性方程 (y=ax₁+bx₂+...形式的方程) 的问题系列。
|
||||
|
||||
线性规划有以下内容:
|
||||
|
||||
- 一个我们想要最小化的成本函数:c₁x₁ + c₂x₂ + ... + cₙxₙ。这里,每个 x 是一个变量,它与一些成本 c 相关联。
|
||||
- 一个约束条件,它表示为一个变量的总和,它要么小于或等于一个值 (a₁x₁+a₂x₂+...+aₙxₙ≤b),要么正好等于这个值 (a₁x₁+a₂x₂+...+aₙxₙ=b)。在这种情况下,x 是一个变量,a 是与之相关的一些资源,而 b 是我们可以为这个问题投入多少资源。
|
||||
- 变量的域 (例如,一个变量不能是负数),形式为 lᵢ≤xᵢ≤uᵢ。
|
||||
|
||||
请考虑以下例子:
|
||||
|
||||
- 两台机器,X₁和 X₂。X₁的运行成本为 50 美元/小时,X₂的运行成本为 80 美元/小时。我们的目标是使成本最小化。这可以被表述为一个成本函数:50x₁+80x₂。
|
||||
- X₁每小时需要 5 个单位的劳动力。X₂每小时需要 2 个单位的劳动力。总共需要花费 20 个单位的劳动力。这可以被形式化为一个约束条件:5x₁ + 2x₂ ≤ 20。
|
||||
- X₁每小时生产 10 个单位的产品。X₂每小时生产 12 个单位的产品。公司需要 90 个单位的产出。这是另一个约束条件。从字面上看,它可以被改写为 10x₁+12x₂≥90。然而,约束条件必须是 (a₁x₁+a₂x₂+...+aₙxₙ≤b) 或 (a₁x₁+a₂x₂+...+aₙxₙ=b)。因此,我们乘以 (-1),得到一个所需形式的等价方程:(-10x₁)+(-12x₂)≤-90。
|
||||
|
||||
线性规划的优化算法需要几何学和线性代数的背景知识,而我们并不想假设这些知识。相反,我们可以使用已经存在的算法,如 Simplex 和 Interior-Point。
|
||||
|
||||
下面是一个使用 Python 中 scipy 库的线性规划例子:
|
||||
|
||||
```python
|
||||
import scipy.optimize
|
||||
# Objective Function: 50x_1 + 80x_2
|
||||
# Constraint 1: 5x_1 + 2x_2 <= 20
|
||||
# Constraint 2: -10x_1 + -12x_2 <= -90
|
||||
result = scipy.optimize.linprog(
|
||||
[50, 80], # Cost function: 50x_1 + 80x_2
|
||||
A_ub=[[5, 2], [-10, -12]], # Coefficients for inequalities
|
||||
b_ub=[20, -90], # Constraints for inequalities: 20 and -90
|
||||
)
|
||||
if result.success:
|
||||
print(f"X1: {round(result.x[0], 2)} hours")
|
||||
print(f"X2: {round(result.x[1], 2)} hours")
|
||||
else:
|
||||
print("No solution")
|
||||
```
|
||||
|
||||
## 约束满足(Constraint Satisfaction)
|
||||
|
||||
约束满足问题是一类需要在满足某些条件下为变量赋值的问题。
|
||||
|
||||
约束条件满足问题具有一下特性:
|
||||
|
||||
- 变量集合{x₁,x₂,...,xₙ}。
|
||||
- 每个变量域的集合{D₁, D₂, ..., Dₙ}。
|
||||
- 一组约束条件 C
|
||||
|
||||
数独可以表示为一个约束满足问题,每个空方块是一个变量,域是数字 1-9,而约束是不能彼此相等的方块。
|
||||
|
||||

|
||||
|
||||
再考虑一个例子。每个学生 1-4 都在选修 A、B、...、G 中的三门课程。每门课程都需要有考试,可能的考试日是星期一、星期二和星期三。但是,同一个学生不能在同一天有两次考试。在这种情况下,变量是课程,域是天数,约束条件是哪些课程不能在同一天安排考试,因为是同一个学生在考试。这可以直观地显示如下:
|
||||
|
||||

|
||||
|
||||
这个问题可以用约束条件来解决,约束条件用图来表示。图中的每个节点是一门课程,如果两门课程不能安排在同一天,则在它们之间画一条边。在这种情况下,该图看起来是这样的:
|
||||
|
||||

|
||||
|
||||
关于约束满足问题,还有几个值得了解的术语:
|
||||
|
||||
- 硬约束 (Hard Constraint) 是指在一个正确的解决方案中必须满足的约束。
|
||||
- 软约束 (Soft Constraint) 是一种约束,表示哪种解决方案比其他解决方案更受欢迎。
|
||||
- 一元约束 (Unary Constraint) 是指只涉及一个变量的约束。在我们的例子中,一元约束是指课程 A 在周一不能有考试{A≠周一}。
|
||||
- 二元约束 (Binary Constraint) 是一种涉及两个变量的约束。这就是我们在上面的例子中使用的约束类型,表示两个课程不能有相同的值{A ≠ B}。
|
||||
|
||||
### 节点一致性 (Node Consistency)
|
||||
|
||||
节点一致性是指一个变量域中的所有值都满足该变量的一元约束。
|
||||
|
||||
例如,让我们拿两门课程,A 和 B。每门课程的域是{Monday, Tuesday, Wednesday},约束条件是{A≠Mon,B≠Tue,B≠Mon,A≠B}。现在,A 和 B 都不是一致的,因为现有的约束条件使它们不能取其域中的每一个值。然而,如果我们从 A 的域中移除 Monday,那么它就会有节点一致性。为了实现 B 的节点一致性,我们必须从它的域中删除 Monday 和 Tuesday。
|
||||
|
||||
### 弧一致性 (Arc Consistency)
|
||||
|
||||
弧一致性是指一个变量域中的所有值都满足该变量的二元约束 (注意,我们现在用"弧"来指代我们以前所说的 "边")。换句话说,要使 X 对 Y 具有弧一致性,就要从 X 的域中移除元素,直到 X 的每个选择都有 Y 的可能选择。
|
||||
|
||||
考虑到我们之前的例子,修改后的域:A:{Tuesday, Wednesday}和 B:{Wednesday}。如果 A 与 B 是弧一致的,那么无论 A 的考试被安排在哪一天 (从它的域来看),B 仍然能够安排考试。A 与 B 是弧一致的吗?如果 A 取值为 Tuesday,那么 B 可以取值为 Wednesday。然而,如果 A 取值为 Wednesday,那么就没有 B 可以取的值 (记住,其中一个约束是 A≠B)。因此,A 与 B 不是弧一致的。为了改变这种情况,我们可以从 A 的域中删除 Wednesday。然后,A 的任何取值 (Tuesday 是唯一的选择) 都会给 B 留下一个取值 (Wednesday)。现在,A 与 B 是弧一致的。让我们看看一个伪代码的算法,使一个变量相对于其他变量是弧一致的 (注意,csp 代表 "约束满足问题")。
|
||||
|
||||
```python
|
||||
function Revise(csp, X, Y):
|
||||
revised = false
|
||||
for x in X.domain:
|
||||
if no y in Y.domain satisfies constraint for (X,Y):
|
||||
delete x from X.domain
|
||||
revised = true
|
||||
return revised
|
||||
```
|
||||
|
||||
这个算法从跟踪 X 的域是否有任何变化开始,使用变量 revised,这在我们研究的下一个算法中会很有用。然后,代码对 X 的域中的每一个值进行重复,看看 Y 是否有一个满足约束条件的值。如果是,则什么都不做,如果不是,则从 X 的域中删除这个值。
|
||||
|
||||
通常情况下,我们感兴趣的是使整个问题的弧一致,而不仅仅是一个变量相对于另一个变量的一致性。在这种情况下,我们将使用一种叫做 AC-3 的算法,该算法使用 Revise:
|
||||
|
||||
```python
|
||||
function AC-3(csp):
|
||||
queue = all arcs in csp
|
||||
while queue non-empty:
|
||||
(X, Y) = Dequeue(queue)
|
||||
if Revise(csp, X, Y):
|
||||
if size of X.domain == 0:
|
||||
return false
|
||||
for each Z in X.neighbors - {Y}:
|
||||
Enqueue(queue, (Z,X))
|
||||
return true
|
||||
```
|
||||
|
||||
该算法将问题中的所有弧添加到一个队列中。每当它考虑一个弧时,它就把它从队列中删除。然后,它运行 Revise 算法,看这个弧是否一致。如果做了修改使其一致,则需要进一步的行动。如果得到的 X 的域是空的,这意味着这个约束满足问题是无法解决的 (因为没有任何 X 可以取的值会让 Y 在约束条件下取任何值)。如果问题在上一步中没有被认为是不可解决的,那么,由于 X 的域被改变了,我们需要看看与 X 相关的所有弧是否仍然一致。也就是说,我们把除了 Y 以外的所有 X 的邻居,把他们和 X 之间的弧添加到队列中。然而,如果 Revise 算法返回 false,意味着域没有被改变,我们只需继续考虑其他弧。
|
||||
|
||||
虽然弧一致性的算法可以简化问题,但不一定能解决问题,因为它只考虑了二元约束,而没有考虑多个节点可能的相互连接方式。我们之前的例子中,4个学生中的每个人都在选修3门课程,对其运行AC-3后,仍然没有变化。
|
||||
|
||||
我们讲过[搜索](4.3.1搜索.md)问题。一个约束满足问题可以被看作是一个搜索问题:
|
||||
|
||||
- 初始状态 (Initial state):空赋值 (所有变量都没有分配任何数值)。
|
||||
- 动作 (Action):在赋值中加入一个{变量=值};也就是说,给某个变量一个值。
|
||||
- 过渡模型 (Transition model):显示添加赋值如何改变变量。这没有什么深度:过渡模型返回包括最新动作后的赋值的状态。
|
||||
- 目标测试 (Goal test):检查所有变量是否被赋值,所有约束条件是否得到满足。
|
||||
- 路径成本函数 (Path cost function):所有路径的成本都是一样的。正如我们前面提到的,与典型的搜索问题相比,优化问题关心的是解决方案,而不是通往解决方案的路线。
|
||||
|
||||
然而,把约束满足问题作为一个普通的搜索问题来处理,是非常低效的。相反,我们可以利用约束满足问题的结构来更有效地解决它。
|
||||
|
||||
### 回溯搜索 (Backtracking Search)
|
||||
|
||||
回溯搜索是一种考虑约束满足搜索问题结构的搜索算法。一般来说,它是一个递归函数,只要值满足约束,它就会尝试继续赋值。如果违反了约束,它将尝试不同的赋值。让我们看看它的伪代码:
|
||||
|
||||
```python
|
||||
function Backtrack(assignment, csp):
|
||||
if assignment complete:
|
||||
return assignment
|
||||
var = Select-Unassigned-Var(assignment, csp)
|
||||
for value in Domain-Values(var, assignment, csp):
|
||||
if value consistent with assignment:
|
||||
add {var = value} to assignment
|
||||
result = Backtrack(assignment, csp)
|
||||
if result ≠ failure:
|
||||
return result
|
||||
remove {var = value} from assignment
|
||||
return failure
|
||||
```
|
||||
|
||||
换句话说,如果当前赋值完成,则该算法返回当前赋值。这意味着,如果完成了算法,它将不会执行任何额外的操作,它只会返回已成立的赋值。如果赋值不完整,算法会选择任何尚未赋值的变量。然后,算法尝试为变量赋值,并对结果赋值再次运行回溯算法(递归)。然后,它检查结果值。如果不是失败,则表示赋值已完成,并且应返回此赋值。如果结果值失败,则删除最近的赋值,并尝试新的可能值,重复相同的过程。如果域中所有可能的值都返回失败,这意味着我们需要回溯。也就是说,问题出在之前的一些作业上。如果这种情况发生在我们开始使用的变量上,那么这意味着没有解决方案满足约束。
|
||||
|
||||
考虑以下行动方案:
|
||||
|
||||

|
||||
|
||||
我们从空赋值开始。然后,我们选择变量 A,并给它赋值`Mon`。然后,使用这个赋值,我们再次运行算法。既然 A 已经有了一个赋值,算法将考虑 B,并将`Mon`赋值给它。此赋值返回`false`,因此算法将尝试在`Tue`为 B 赋值,而不是在给定上一个赋值的情况下为 C 赋值。这个新的赋值满足约束条件,在给定这个赋值的情况下,下一步将考虑一个新的变量。例如,如果将`Tue`或`Wed`也赋值给 B 会导致失败,那么算法将回溯并返回到考虑 A,为其分配另一个值,即`Tue`。如果`Tue`和`Wed`也失败了,那么这意味着我们已经尝试了所有可能的赋值,该问题是无法解决的。
|
||||
|
||||
在源代码部分,您可以从头开始实现的回溯算法。然而,这种算法被广泛使用,因此,多个库已经包含了它的实现。
|
||||
|
||||
## 推理 (Inference)
|
||||
|
||||
尽管回溯搜索比简单搜索更有效,但它仍然需要大量的算力。另一方面,满足弧一致性需要的算力较低。通过将回溯搜索与推理交织在一起(满足弧一致性),我们可以得到一种更有效的算法。该算法被称为“保持弧一致性”__(Maintaining Arc-Consistency)__ 算法。该算法将在每次新的回溯搜索分配之后满足弧一致性。具体来说,在我们对 X 进行新的赋值后,我们将调用`AC-3`算法,并从所有弧 (Y,X) 的队列开始,其中 Y 是 X 的邻居 (而不是问题中所有弧的队列)。以下是一个经过修订的 Backtrack 算法,该算法保持了弧的一致性。
|
||||
|
||||
```python
|
||||
function Backtrack(assignment, csp):
|
||||
if assignment complete:
|
||||
return assignment
|
||||
var = Select-Unassigned-Var(assignment, csp)
|
||||
for value in Domain-Values(var, assignment, csp):
|
||||
if value consistent with assignment:
|
||||
add {var = value} to assignment # new here
|
||||
inferences = Inference(assignment, csp) # new here
|
||||
if inferences ≠ failure:
|
||||
add inferences to assignment
|
||||
result = Backtrack(assignment, csp)
|
||||
if result ≠ failure:
|
||||
return result
|
||||
remove {var = value} and inferences from assignment # new here
|
||||
return failure
|
||||
```
|
||||
|
||||
Inference 函数运行 AC-3 算法,如前所述。它的输出是通过满足弧一致性可以做出的所有推断。从字面上看,这些是可以从以前的赋值和约束满足问题的结构中推导出来的新赋值。
|
||||
|
||||
还有其他方法可以提高算法的效率。到目前为止,我们随机选择了一个未分配的变量。然而,有些选择比其他选择更有可能更快地找到解决方案。这需要使用启发式方法。启发式是一条经验法则,这意味着,通常情况下,它会比遵循随机的方法带来更好的结果,但不能保证总是更优。
|
||||
|
||||
__最小剩余值 (Minimum Remaining Values(MRV))__ 就是这样一种启发式方法。这里的想法是,如果一个变量的域被推理限制了,现在它只剩下一个值 (甚至是两个值),那么通过进行这种赋值,我们将减少以后可能需要进行的回溯次数。也就是说,我们迟早要做这个赋值,因为它是从满足弧一致性中推断出来的。如果这项任务失败了,最好尽快发现,避免以后的回溯。
|
||||
|
||||

|
||||
|
||||
例如,在给定当前赋值的情况下缩小变量的域后,使用 MRV 启发式,我们接下来将选择变量 C,并以 Wed 为其赋值。
|
||||
|
||||
__度 (Degree)__ 启发式依赖于变量的度,其中度是指将一个变量连接到其他变量的弧数。通过一次赋值选择度最高的变量,我们约束了多个其他变量,从而加快了算法的进程。
|
||||
|
||||

|
||||
|
||||
例如,上面所有的变量都有相同大小的域。因此,我们应该选择一个度最高的域,它将是变量 E。
|
||||
|
||||
这两种启发式方法并不总是适用的。例如,当多个变量在其域中具有相同的最小值时,或者当多个变数具有相同的最高度时。
|
||||
|
||||
另一种提高算法效率的方法是,当我们从变量的域中选择一个值时,使用另一种启发式方法。在这里,我们使用 __最小约束值 (Least Constraining Values)__ 启发式,在这里我们选择将约束最少其他变量的值。这里的想法是,在度启发式中,我们希望使用更可能约束其他变量的变量,而在这里,我们希望这个变量对其他变量的约束最少。也就是说,我们希望找到可能是最大潜在麻烦源的变量 (度最高的变量),然后使其尽可能不麻烦 (为其赋值约束其他变量最少的值)。
|
||||
|
||||

|
||||
|
||||
例如,让我们考虑变量 C。如果我们将`Tue`分配给它,我们将对所有 B、E 和 F 施加约束。然而,如果我们选择`Wed`,我们将只对 B 和 E 施加约束。因此,选择`Tue`可能更好。
|
||||
|
||||
总之,优化问题可以用多种方式来表述。在这,我们考虑了局部搜索、线性规划和约束满足。
|
||||
@@ -2,18 +2,21 @@
|
||||
|
||||
人工智能(Artificial Intelligence, AI)是机器,特别是计算机系统对人类智能过程的模拟。人工智能是一个愿景,目标就是让机器像我们人类一样思考与行动,能够代替我们人类去做各种各样的工作。人工智能研究的范围非常广,包括演绎、推理和解决问题、知识表示、学习、运动和控制、数据挖掘等众多领域。
|
||||
|
||||
# 人工智能、机器学习与深度学习关系
|
||||
## 人工智能、机器学习与深度学习关系
|
||||
|
||||
人工智能是一个宏大的愿景,目标是让机器像我们人类一样思考和行动,既包括增强我们人类脑力也包括增强我们体力的研究领域。而学习只是实现人工智能的手段之一,并且,只是增强我们人类脑力的方法之一。所以,人工智能包含机器学习。机器学习又包含了深度学习,他们三者之间的关系见下图。
|
||||
|
||||

|
||||

|
||||
|
||||
# 如何学习本节内容
|
||||
## 如何学习本节内容
|
||||
|
||||
作者深知学习人工智能时面临许多繁碎数学知识,复杂数学公式的痛苦,因此,本节内容重在讲解核心概念和算法,略去了复杂的数学推导,尽可能以直觉的方式去理解,本文的数学知识,高中生足以掌握。阅读本节内容不需要人工智能基础,你可以直接从本节入门 AI。本节内容的算法、项目实现将使用 python 实现,需要掌握一定的 python 基础语法。当然如果你急于了解 AI,却又不会 python,没有关系,你可以选择跳过其中的编程部分,着眼于其中的概念、算法,程序语言是算法实现的工具,并非学习算法的必须品。
|
||||
|
||||
# 学习建议
|
||||
## 学习建议
|
||||
|
||||
本节内容是作者根据[哈佛的 CS50AI 导论](https://cs50.harvard.edu/ai/2020/)以及 [Andrew Ng 的机器学习专项课程](https://www.coursera.org/specializations/machine-learning-introduction)简化编写,当然你可以直接学习这两门课程。本节内容的总学习时间应该是二到三个月,如果你在某个知识点上卡住了,你也许需要反复阅读讲义,必要时向身边人求助。
|
||||
|
||||
# 目录
|
||||
## 补充材料
|
||||
|
||||

|
||||
人工智能现代方法(第四版)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# FAQ:常见问题
|
||||
|
||||
## 我是非计算机专业的,感觉AI很火,可以看这篇内容吗
|
||||
## 我是非计算机专业的,感觉 AI 很火,可以看这篇内容吗
|
||||
|
||||
如果你不打算做相关研究的话,我觉得你最先应该考虑的是熟练掌握使用AI工具,本章内容更偏向于完善AI方面的知识体系架构
|
||||
如果你不打算做相关研究的话,我觉得你最先应该考虑的是熟练掌握使用 AI 工具,本章内容更偏向于完善 AI 方面的知识体系架构
|
||||
|
||||
## 我对AI/CV/NLP/blabla研究方向很感兴趣可以看这篇内容吗?
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
因此如果你想学某个知识体系,可以参考本章内容的路线,但是若你有足够强大的能力可以直接应对国外课程体系的困难,那么我非常推荐你去直接看英文内容
|
||||
|
||||
因为我们在降低门槛的时候也一定程度上让各位损失了一定的训练,在概括的过程中,信息量被稀释了,抽象地描述也许更能让你get到一些思想性的内容
|
||||
因为我们在降低门槛的时候也一定程度上让各位损失了一定的训练,在概括的过程中,信息量被稀释了,抽象地描述也许更能让你 get 到一些思想性的内容
|
||||
|
||||
## 我数学不好可以学吗
|
||||
|
||||
@@ -30,11 +30,9 @@
|
||||
|
||||
你应该更多地依赖自己而不是学校
|
||||
|
||||
## [如果不是相关领域可以找到这个领域工作吗](https://www.quora.com/How-do-I-get-a-job-in-Machine-Learning-as-a-software-programmer-who-self-studies-Machine-Learning-but-never-has-a-chance-to-use-it-at-work)
|
||||
|
||||
|
||||
# [如果不是相关领域可以找到这个领域工作吗](https://www.quora.com/How-do-I-get-a-job-in-Machine-Learning-as-a-software-programmer-who-self-studies-Machine-Learning-but-never-has-a-chance-to-use-it-at-work)
|
||||
|
||||
> “我正在为团队招聘专家,但你的 MOOC 并没有给你带来工作学习机会。我大部分机器学习方向的硕士也并不会得到机会,因为他们(与大多数工作)上过 MOOC 的人一样)并没有深入地去理解。他们都无法帮助我的团队解决问题。” Ross C. Taylor
|
||||
> “我正在为团队招聘专家,但你的 MOOC 并没有给你带来工作学习机会。我大部分机器学习方向的硕士也并不会得到机会,因为他们(与大多数工作)上过 MOOC 的人一样)并没有深入地去理解。他们都无法帮助我的团队解决问题。”Ross C. Taylor
|
||||
|
||||
## 人工智能,深度学习,机器学习,数据分析,我该如何区分
|
||||
|
||||
@@ -42,23 +40,19 @@
|
||||
|
||||
机器学习包括深度学习
|
||||
|
||||

|
||||

|
||||
|
||||
[同时向你推荐这个 Data Analytics,Data Analysis,数据挖掘,数据科学,机器学习,大数据的区别是什么?](https://www.quora.com/What-is-the-difference-between-Data-Analytics-Data-Analysis-Data-Mining-Data-Science-Machine-Learning-and-Big-Data-1)
|
||||
|
||||

|
||||

|
||||
|
||||
## 我没有任何相关概念
|
||||
|
||||
尝试阅读以下内容
|
||||
|
||||
- [形象的机器学习简介](http://www.r2d3.us/visual-intro-to-machine-learning-part-1/)
|
||||
- [一份温柔的机器学习指南](https://blog.monkeylearn.com/a-gentle-guide-to-machine-learning/)
|
||||
- [为开发者准备的机器学习简介](http://blog.algorithmia.com/introduction-machine-learning-developers/)
|
||||
- [菜鸟的机器学习基础](https://www.analyticsvidhya.com/blog/2015/06/machine-learning-basics/)
|
||||
- [你如何向非计算机专业的人来解释机器学习与数据挖掘?](https://www.quora.com/How-do-you-explain-Machine-Learning-and-Data-Mining-to-non-Computer-Science-people)
|
||||
- [在罩子下的机器学习,博文简单明了地介绍了机器学习的原理](https://georgemdallas.wordpress.com/2013/06/11/big-data-data-mining-and-machine-learning-under-the-hood/)
|
||||
- [机器学习是什么?它是如何工作的呢?](https://www.youtube.com/watch?v=elojMnjn4kk&list=PL5-da3qGB5ICeMbQuqbbCOQWcS6OYBr5A&index=1)
|
||||
- [深度学习——一份非技术性的简介](http://www.slideshare.net/AlfredPong1/deep-learning-a-nontechnical-introduction-69385936)
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
## 深度学习框架
|
||||
|
||||

|
||||

|
||||
|
||||
### 1、深度学习框架是什么
|
||||
|
||||
@@ -113,9 +113,9 @@ PyTorch 完全基于 Python。
|
||||
|
||||
官网如下
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
选择 Conda 或者 Pip 安装皆可
|
||||
|
||||
@@ -127,9 +127,9 @@ PyTorch 完全基于 Python。
|
||||
|
||||
如果你使用 conda 安装 pytorch 太慢或者失败,不妨换个下载源试试
|
||||
|
||||
在 [cmd](https://so.csdn.net/so/search?q=cmd&spm=1001.2101.3001.7020) 命令行中,输入添加以下命令:
|
||||
在 cmd 命令行中,输入添加以下命令:
|
||||
|
||||
```
|
||||
```bash
|
||||
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/msys2/
|
||||
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
|
||||
@@ -140,15 +140,21 @@ conda config --set show_channel_urls yes
|
||||
|
||||
### TensorFlow
|
||||
|
||||

|
||||

|
||||
|
||||
#### 教程
|
||||
|
||||
[在 Windows 上配置 pytorch!(CPU 和 GPU 版)](https://www.bilibili.com/video/BV1YY4y1B7cA?spm_id_from=333.337.search-card.all.click&vd_source=8e0b454d3850af2ce4435d1ca2d9e040)
|
||||
[在 Windows 上配置 pytorch!(CPU 和 GPU 版)](https://www.bilibili.com/video/BV1YY4y1B7cA)
|
||||
|
||||
[Windows 下 PyTorch 入门深度学习环境安装与配置 CPU GPU 版](https://www.bilibili.com/video/BV1S5411X7FY?p=1&vd_source=8e0b454d3850af2ce4435d1ca2d9e040)
|
||||
<Bilibili bvid='BV1YY4y1B7cA'/>
|
||||
|
||||
[最新 TensorFlow 2.8 极简安装教程](https://www.bilibili.com/video/BV1i34y1r7dv/?spm_id_from=333.788&vd_source=8e0b454d3850af2ce4435d1ca2d9e040)
|
||||
[Windows 下 PyTorch 入门深度学习环境安装与配置 CPU GPU 版](https://www.bilibili.com/video/BV1S5411X7FY)
|
||||
|
||||
<Bilibili bvid='BV1S5411X7FY'/>
|
||||
|
||||
[最新 TensorFlow 2.8 极简安装教程](https://www.bilibili.com/video/BV1i34y1r7dv)
|
||||
|
||||
<Bilibili bvid='BV1i34y1r7dv'/>
|
||||
|
||||
#### 思考题:为什么需要 CUDA 版本???
|
||||
|
||||
@@ -161,17 +167,17 @@ cuda 版本需要额外配置,我们将这个任务留给聪明的你!!!
|
||||
同时按下键盘的 win+r 键,打开 cmd,键入 `dxdiag` 然后回车
|
||||
系统、显卡、声卡以及其他输入设备的信息都在这里了。(给出我的界面)
|
||||
|
||||

|
||||

|
||||
|
||||
cuda 版本查看
|
||||
|
||||
桌面空白位置摁下右键
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
#### linux
|
||||
|
||||
@@ -187,11 +193,11 @@ nvidia-smi
|
||||
|
||||
通常大家所指的 cuda 是位于/usr/local 下的 cuda
|
||||
|
||||

|
||||

|
||||
|
||||
当然可以看到 cuda 是 cuda-11.6 所指向的软链接(类似 windows 的快捷方式),所以我们如果要切换 cuda 版本只需要改变软链接的指向即可。
|
||||
|
||||

|
||||

|
||||
|
||||
cuda driver version 是 cuda 的驱动版本。
|
||||
|
||||
@@ -199,9 +205,9 @@ cuda runtimer version 是我们实际很多时候我们实际调用的版本。
|
||||
|
||||
二者的版本是可以不一致的。如下图所示:
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
一般来讲 cuda driver 是向下兼容的。所以 cuda driver version >= cuda runtime version 就不会太大问题。
|
||||
|
||||
@@ -211,13 +217,13 @@ cuda runtimer version 是我们实际很多时候我们实际调用的版本。
|
||||
|
||||
以 pytorch 为例,可以看到在安装过程中我们选择的 cuda 版本是 10.2
|
||||
|
||||

|
||||

|
||||
|
||||
那么这个 cudatookit10.2 和 nvidia-smi 的 11.7 以及 nvcc -V 的 11.4 三者有什么区别呢?
|
||||
|
||||
pytorch 实际只需要 cuda 的链接文件,即.so 文件,这些链接文件就都包含的 cudatookkit 里面。并不需要 cuda 的头文件等其他东西,如下所示
|
||||
|
||||

|
||||

|
||||
|
||||
所以我们如果想让使用 pytorch-cuda 版本,我们实际上不需要/usr/local/cuda。只需要在安装驱动的前提下,在 python 里面安装 cudatookit 即可。
|
||||
|
||||
@@ -227,8 +233,8 @@ pytorch 实际只需要 cuda 的链接文件,即.so 文件,这些链接文
|
||||
|
||||
Cudnn 是一些链接文件,你可以理解成是为了给 cuda 计算加速的东西。同样的我们也可以用以下命令查看/usr/local/cuda 的 cudnn:
|
||||
|
||||

|
||||

|
||||
|
||||
以及 pytorch 的 cuda 环境的 cudnn
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -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/>来源:知乎
|
||||
|
||||
@@ -38,10 +38,10 @@
|
||||
- 体素:我把世界变成 MC 了,世界是一堆方块,他们在不同视角下有各自的颜色和透明度
|
||||
- 点云:我每采样一次得到一个点,由这些点去表示我要的物体,不太直观,来张图
|
||||
|
||||
这是我用照片重建的独角兽<strong>稀疏</strong>点云,红色的不用管,是照相机视角(图不够多,巨糊)
|
||||
这是我用照片重建的独角兽**稀疏**点云,红色的不用管,是照相机视角(图不够多,巨糊)
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
先这些,后续想起来了可能会补充。
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
# 深度学习快速入门
|
||||
|
||||
## <strong>刘二大人(Pytorch)</strong>
|
||||
## **刘二大人(Pytorch)**
|
||||
|
||||
## [【速成课:人工智能】Ai - [21 集全/中英双语] - Artificial Intelligence_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1P7411r7Dw/?spm_id_from=333.999.0.0&vd_source=2cb6252f9211ae9d29cf1f76f0aea8d7)
|
||||
## 速成课:人工智能
|
||||
[【速成课:人工智能】Ai - [21 集全/中英双语] - Artificial Intelligence_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1P7411r7Dw)
|
||||
|
||||
<Bilibili bvid='BV1P7411r7Dw'/>
|
||||
|
||||
Crash course 的课程,可以基本了解pytorch的内容,但是当然有很多内容已经有些过时
|
||||
|
||||
@@ -59,13 +62,13 @@ Crash course 的课程,可以基本了解pytorch的内容,但是当然有很
|
||||
|
||||
## torch 我还不会呢!
|
||||
|
||||
学会一个<strong>庞大并且高度封装</strong>的包并不是一蹴而就的,我们建议从实践开始,比如说自己搭建一个神经网络来实现 MNIST 的分类。在使用这些函数和类的过程中你能更快地掌握它们的方法。
|
||||
学会一个**庞大并且高度封装**的包并不是一蹴而就的,我们建议从实践开始,比如说自己搭建一个神经网络来实现 MNIST 的分类。在使用这些函数和类的过程中你能更快地掌握它们的方法。
|
||||
|
||||
# 关于梯度下降算法:
|
||||
|
||||
### 损失
|
||||
|
||||

|
||||

|
||||
|
||||
首先我们需要有一个损失函数$F(x),x=true-predict$
|
||||
|
||||
@@ -74,13 +77,13 @@ Crash course 的课程,可以基本了解pytorch的内容,但是当然有很
|
||||
|
||||
### 梯度下降
|
||||
|
||||

|
||||

|
||||
|
||||
假设损失函数为$y=x^2$,梯度下降的目的是快速找到导数为 0 的位置(附近)
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
以此类推,我们最后的 w 在 0 的附近反复横跳,最后最接近目标函数的权重 w 就是 0。
|
||||
|
||||
@@ -94,18 +97,18 @@ Crash course 的课程,可以基本了解pytorch的内容,但是当然有很
|
||||
|
||||
# 关于 MINIST
|
||||
|
||||

|
||||

|
||||
|
||||
这个数据集可以说是最最经典的数据集了,里面有 0-9 这 10 个数字的手写图片和标注,正确率最高已经到了 99.7%.
|
||||
|
||||
# 接下来干什么?
|
||||
|
||||
- <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 的任务开始,在有足够的基础后开始学习 RNN,LSTM 基准方法后向 [4.6.7Transformer](4.6.7Transformer.md) 进发 ,这个方法广泛运用在几乎所有深度学习领域,尤其是 NLP 的前沿研究已经无法离开 Transformer 了 hhhh。这个模块中我们也加入了一些 Transformer 的改进工作,包括 NLP,CV,和多模态
|
||||
|
||||
- <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) 。这是撰写者之一的论文阅读笔记,不保证准确性与理解是否准确,可以作为论文阅读路线图来参考~
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
进入官网后选择 Install,在下面表格中按照你的配置进行选择:
|
||||
|
||||

|
||||

|
||||
|
||||
其中 Package 部分选择安装的途径,这里主要介绍 Pip 和 Conda 两种途径。
|
||||
|
||||
@@ -17,7 +17,7 @@ Pip 在通过 python 官网下载 python 并安装时可以选择同时安装 pi
|
||||
3. 对于 Windows 用户,在 C:\Users\xx\pip 目录下(没有 pip 目录就新建)创建一个 pip.ini 文件,并将下面代码块中内容复制进去:
|
||||
4. 对于 Linux 用户,同样在~/.pip/pip.conf 进行配置。如果没有.pip 目录就新建,然后将下面代码块中内容复制进去:
|
||||
|
||||
```
|
||||
```bash
|
||||
[global]
|
||||
index-url = http://pypi.douban.com/simple
|
||||
extra-index-url = https://pypi.mirrors.ustc.edu.cn/simple/
|
||||
@@ -56,8 +56,8 @@ conda config --show channels
|
||||
|
||||
同时按下 Win+R,运行 cmd,输入 `dxdiag` 并回车。系统、显卡、声卡以及其他设备信息都会显示。
|
||||
|
||||

|
||||

|
||||
|
||||
cuda 版本查看
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
### CV 领域的大任务
|
||||
|
||||

|
||||

|
||||
|
||||
#### (a)Image classification <strong>图像分类</strong>
|
||||
#### (a)Image classification **图像分类**
|
||||
|
||||
- 识别这个图片整体所属的类别,解决的是"what"问题,给这个图片打上相应的标签,在 a 图内标签是 `bottle,cup,cube`,其他类型的图片也都有它们自己的标签,然后把这些打上标签的图片带进网络结构里作为训练集训练。
|
||||
|
||||
#### (b)Object localization <strong>目标检测</strong>(对象定位)
|
||||
#### (b)Object localization **目标检测**(对象定位)
|
||||
|
||||
- 识别图片中各个物体所在的位置,解决的是"where"问题,此处还细分两个问题:
|
||||
|
||||
@@ -18,27 +18,27 @@
|
||||
|
||||
- 这张图我们需要标注两个类别 `head(头)、helmet(头盔)`
|
||||
|
||||

|
||||

|
||||
|
||||
#### (c)Semantic segmentation <strong>语义分割</strong>
|
||||
#### (c)Semantic segmentation **语义分割**
|
||||
|
||||
- 语义分割需要进一步判断图像中哪些像素属于哪个目标(进阶目标检测)。
|
||||
- 看图右下角两个 `cube` 是连在一块的 并没有分出哪一部分是哪一个的 `cube`
|
||||
|
||||
#### (d)Instance segmentation <strong>实例分割</strong>
|
||||
#### (d)Instance segmentation **实例分割**
|
||||
|
||||
- 实例分割需要区分出哪些像素属于第一个物体、哪些像素属于第二个物体,即目标检测 + 语义分割。
|
||||
- 看图右下角两个 `cube` 是分开的
|
||||
|
||||
#### (e)Key Point 人体关键点检测
|
||||
|
||||

|
||||

|
||||
|
||||
通过人体关键节点的组合和追踪来识别人的运动和行为,对于描述人体姿态,预测人体行为至关重要。
|
||||
|
||||
#### (f)Scene Text Recognition(STR)场景文字识别
|
||||
|
||||

|
||||

|
||||
|
||||
很多照片中都有一些文字信息,这对理解图像有重要的作用。
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
利用两张图片或者其他信息生成一张新的图片
|
||||
|
||||

|
||||

|
||||
|
||||
利用左边两张小图生成右边的图片
|
||||
|
||||
@@ -56,6 +56,6 @@
|
||||
|
||||
将输入图片分辨率增加
|
||||
|
||||

|
||||

|
||||
|
||||
当然还有一些新兴领域我们没有写入~
|
||||
|
||||
@@ -20,7 +20,7 @@ PyTorch 中的 Dataset 类是一个抽象类,它可以用来表示数据集。
|
||||
|
||||
下面我们来编写一个简单的例子,看下如何使用 Dataset 类定义一个 Tensor 类型的数据集。
|
||||
|
||||
```
|
||||
```python
|
||||
import torch
|
||||
from torch.utils.data import Dataset
|
||||
|
||||
@@ -43,7 +43,7 @@ class MyDataset(Dataset):
|
||||
|
||||
然后我们来看一下如何调用刚才定义的数据集。首先随机生成一个 10*3 维的数据 Tensor,然后生成 10 维的标签 Tensor,与数据 Tensor 相对应。利用这两个 Tensor,生成一个 MyDataset 的对象。查看数据集的大小可以直接用 len() 函数,索引调用数据可以直接使用下标。
|
||||
|
||||
```
|
||||
```python
|
||||
# 生成数据
|
||||
data_tensor = torch.randn(10, 3)
|
||||
target_tensor = torch.randint(2, (10,)) # 标签是0或1
|
||||
@@ -67,7 +67,7 @@ DataLoader 是一个迭代器,最基本的使用方法就是传入一个 Datas
|
||||
|
||||
DataLoader 类的调用方式如下:
|
||||
|
||||
```
|
||||
```python
|
||||
from torch.utils.data import DataLoader
|
||||
tensor_dataloader = DataLoader(dataset=my_dataset, # 传入的数据集, 必须参数
|
||||
batch_size=2, # 输出的batch大小
|
||||
@@ -107,7 +107,7 @@ One batch tensor data: [tensor([[ 0.9451, -0.4923, -1.8178],
|
||||
- shuffle:bool 类型,在每个 epoch 开始的时候,是否对数据进行重新打乱;
|
||||
- num_workers:int 类型,加载数据的进程数,0 意味着所有的数据都会被加载进主进程,默认为 0。
|
||||
|
||||
<strong>思考题</strong>
|
||||
**思考题**
|
||||
|
||||
按照上述代码,One batch tensor data 的输出是否正确,若不正确,为什么?
|
||||
|
||||
@@ -117,7 +117,7 @@ Torchvision 库中的 torchvision.datasets 包中提供了丰富的图像数据
|
||||
|
||||
下表中列出了 torchvision.datasets 包所有支持的数据集。各个数据集的说明与接口,详见链接 [https://pytorch.org/vision/stable/datasets.html](https://pytorch.org/vision/stable/datasets.html)。
|
||||
|
||||

|
||||

|
||||
|
||||
注意,torchvision.datasets 这个包本身并不包含数据集的文件本身,它的工作方式是先从网络上把数据集下载到用户指定目录,然后再用它的加载器把数据集加载到内存中。最后,把这个加载后的数据集作为对象返回给用户。
|
||||
|
||||
@@ -129,11 +129,11 @@ MNIST 数据集是一个著名的手写数字数据集,因为上手简单,
|
||||
|
||||
MNIST 数据集是 NIST 数据集的一个子集,MNIST 数据集你可以通过[这里](http://yann.lecun.com/exdb/mnist/)下载。它包含了四个部分。
|
||||
|
||||

|
||||

|
||||
|
||||
MNIST 数据集是 ubyte 格式存储,我们先将“训练集图片”解析成图片格式,来直观地看一看数据集具体是什么样子的。具体怎么解析,我们在后面数据预览再展开。
|
||||
|
||||

|
||||

|
||||
|
||||
接下来,我们看一下如何使用 Torchvision 来读取 MNIST 数据集。
|
||||
|
||||
@@ -143,7 +143,7 @@ MNIST 数据集是 ubyte 格式存储,我们先将“训练集图片”解析
|
||||
|
||||
以 MNIST 为例,我们可以用如下方式调用:
|
||||
|
||||
```
|
||||
```python
|
||||
# 以MNIST为例
|
||||
import torchvision
|
||||
mnist_dataset = torchvision.datasets.MNIST(root='./data',
|
||||
@@ -173,7 +173,7 @@ torchvision.datasets.MNIST 是一个类,对它进行实例化,即可返回
|
||||
|
||||
如果想要查看 mnist_dataset 中的具体内容,我们需要把它转化为列表。(如果 IOPub data rate 超限,可以只加载测试集数据,令 train=False)
|
||||
|
||||
```
|
||||
```python
|
||||
mnist_dataset_list = list(mnist_dataset)
|
||||
print(mnist_dataset_list)
|
||||
```
|
||||
@@ -182,7 +182,7 @@ print(mnist_dataset_list)
|
||||
|
||||
这里图像数据是 PIL.Image.Image 类型的,这种类型可以直接在 Jupyter 中显示出来。显示一条数据的代码如下。
|
||||
|
||||
```
|
||||
```python
|
||||
display(mnist_dataset_list[0][0])
|
||||
print("Image label is:", mnist_dataset_list[0][1])
|
||||
```
|
||||
|
||||
@@ -27,7 +27,7 @@ Torchvision 库中的 torchvision.transforms 包中提供了常用的图像操
|
||||
|
||||
我们来看一个具体的例子加深理解。将图片进行一下数据类型的相互转换。具体代码如下:
|
||||
|
||||
```
|
||||
```python
|
||||
from PIL import Image
|
||||
from torchvision import transforms
|
||||
|
||||
@@ -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 进行变换
|
||||
|
||||
@@ -68,7 +68,7 @@ torchvision.transforms 提供了丰富的图像变换方法,例如:改变尺
|
||||
|
||||
将输入的 PIL Image 或 Tensor 尺寸调整为给定的尺寸,具体定义为:
|
||||
|
||||
```
|
||||
```python
|
||||
torchvision.transforms.Resize(size, interpolation=2)
|
||||
```
|
||||
|
||||
@@ -81,7 +81,7 @@ torchvision.transforms.Resize(size, interpolation=2)
|
||||
|
||||
在 resize 之后呢,一般会接一个 crop 操作,crop 到指定的大小。对于高与宽接近的图片来说,这么做问题不大,但是高与宽的差距较大时,就会 crop 掉很多有用的信息。关于这一点,我们在后续的图像分类部分还会遇到,到时我在详细展开。
|
||||
|
||||
```
|
||||
```python
|
||||
from PIL import Image
|
||||
from torchvision import transforms
|
||||
|
||||
@@ -105,7 +105,7 @@ torchvision.transforms 提供了多种剪裁方法,例如中心剪裁、随机
|
||||
|
||||
先说中心剪裁,在中心裁剪指定的 PIL Image 或 Tensor,其定义如下:
|
||||
|
||||
```
|
||||
```python
|
||||
torchvision.transforms.CenterCrop(size)
|
||||
```
|
||||
|
||||
@@ -113,7 +113,7 @@ torchvision.transforms.CenterCrop(size)
|
||||
|
||||
然后是随机剪裁,在一个随机位置剪裁指定的 PIL Image 或 Tensor,定义如下:
|
||||
|
||||
```
|
||||
```python
|
||||
torchvision.transforms.RandomCrop(size, padding=None)
|
||||
```
|
||||
|
||||
@@ -121,13 +121,13 @@ torchvision.transforms.RandomCrop(size, padding=None)
|
||||
|
||||
最后要说的是 FiveCrop,我们将给定的 PIL Image 或 Tensor ,分别从四角和中心进行剪裁,共剪裁成五块,定义如下:
|
||||
|
||||
```
|
||||
```python
|
||||
torchvision.transforms.FiveCrop(size)
|
||||
```
|
||||
|
||||
size 可以是 int 或 tuple,用法同上。掌握了各种剪裁的定义和参数用法以后,我们来看一下这些剪裁操作具体如何调用,代码如下:
|
||||
|
||||
```
|
||||
```python
|
||||
from PIL import Image
|
||||
from torchvision import transforms
|
||||
|
||||
@@ -158,13 +158,13 @@ for img in imgs:
|
||||
|
||||
以概率 p 随机水平翻转图像,定义如下:
|
||||
|
||||
```
|
||||
```python
|
||||
torchvision.transforms.RandomHorizontalFlip(p=0.5)
|
||||
```
|
||||
|
||||
以概率 p 随机垂直翻转图像,定义如下:
|
||||
|
||||
```
|
||||
```python
|
||||
torchvision.transforms.RandomVerticalFlip(p=0.5)
|
||||
```
|
||||
|
||||
@@ -172,7 +172,7 @@ torchvision.transforms.RandomVerticalFlip(p=0.5)
|
||||
|
||||
这里的随机翻转,是为数据增强提供方便。如果想要必须执行翻转操作的话,将 p 设置为 1 即可。图片翻转代码如下:
|
||||
|
||||
```
|
||||
```python
|
||||
from PIL import Image
|
||||
from torchvision import transforms
|
||||
|
||||
@@ -202,7 +202,7 @@ display(img2)
|
||||
|
||||
标准化是指每一个数据点减去所在通道的平均值,再除以所在通道的标准差,数学的计算公式:output=(input−mean)/std
|
||||
|
||||
而对图像进行标准化,就是对图像的每个通道利用均值和标准差进行正则化。这样做的目的,是<strong>为了保证数据集中所有的图像分布都相似,这样在训练的时候更容易收敛,既加快了训练速度,也提高了训练效果</strong>。
|
||||
而对图像进行标准化,就是对图像的每个通道利用均值和标准差进行正则化。这样做的目的,是**为了保证数据集中所有的图像分布都相似,这样在训练的时候更容易收敛,既加快了训练速度,也提高了训练效果**。
|
||||
|
||||
让我来解释一下:首先,标准化是一个常规做法,可以理解为无脑进行标准化后再训练的效果,大概率要好于不进行标准化。
|
||||
|
||||
@@ -212,7 +212,7 @@ display(img2)
|
||||
|
||||
torchvision.transforms 提供了对 Tensor 进行标准化的函数,定义如下:
|
||||
|
||||
```
|
||||
```python
|
||||
torchvision.transforms.Normalize(mean, std, inplace=False)
|
||||
```
|
||||
|
||||
@@ -224,7 +224,7 @@ torchvision.transforms.Normalize(mean, std, inplace=False)
|
||||
|
||||
我们来看看以 (R, G, B) 均值和标准差均为 (0.5, 0.5, 0.5) 来标准化图片后,是什么效果:
|
||||
|
||||
```
|
||||
```python
|
||||
from PIL import Image
|
||||
from torchvision import transforms
|
||||
|
||||
@@ -254,7 +254,7 @@ display(img_norm)
|
||||
|
||||
Compose 类是将多个变换组合到一起,它的定义如下:
|
||||
|
||||
```
|
||||
```python
|
||||
torchvision.transforms.Compose(transforms)
|
||||
```
|
||||
|
||||
@@ -262,7 +262,7 @@ torchvision.transforms.Compose(transforms)
|
||||
|
||||
我们还是结合例子动手试试,如果我们想要将图片变为 200*200 像素大小,并且随机裁切成 80 像素的正方形。那么我们可以组合 Resize 和 RandomCrop 变换,具体代码如下所示:
|
||||
|
||||
```
|
||||
```python
|
||||
from PIL import Image
|
||||
from IPython.display import display
|
||||
from torchvision import transforms
|
||||
@@ -292,7 +292,7 @@ Compose 类是未来我们在实际项目中经常要使用到的类,结合 to
|
||||
|
||||
我们还是以读取 MNIST 数据集为例,看下如何在读取数据的同时,完成数据预处理等操作。具体代码如下:
|
||||
|
||||
```
|
||||
```python
|
||||
from torchvision import transforms
|
||||
from torchvision import datasets
|
||||
|
||||
@@ -320,7 +320,7 @@ print(type(item[0]))
|
||||
|
||||
我们下面先来看看,在图像分类实战中使用的 transform,可以感受一下实际使用的 transforms 是什么样子:
|
||||
|
||||
```
|
||||
```python
|
||||
transform = transforms.Compose([
|
||||
transforms.RandomResizedCrop(dest_image_size),
|
||||
transforms.RandomHorizontalFlip(),
|
||||
|
||||
@@ -10,29 +10,29 @@ AlexNet 有 6 千万个参数和 650,000 个神经元。
|
||||
|
||||
[论文](http://www.cs.toronto.edu/~fritz/absps/imagenet.pdf)
|
||||
|
||||
### <strong>网络框架图</strong>
|
||||
### **网络框架图**
|
||||
|
||||

|
||||

|
||||
|
||||
### <strong>使用 ReLU 激活函数代替 tanh</strong>
|
||||
### **使用 ReLU 激活函数代替 tanh**
|
||||
|
||||
在当时,标准的神经元激活函数是 tanh()函数,这种饱和的非线性函数在梯度下降的时候要比非饱和的非线性函数慢得多,因此,在 AlexNet 中使用 ReLU 函数作为激活函数。
|
||||
|
||||

|
||||

|
||||
|
||||
### <strong>采用 Dropout 防止过拟合</strong>
|
||||
### **采用 Dropout 防止过拟合**
|
||||
|
||||
dropout 方法会遍历网络的每一层,并设置消除神经网络中节点的概率。假设网络中的每一层,每个节点都以抛硬币的方式设置概率,每个节点得以保留和消除的概率都是 0.5,设置完节点概率,我们会消除一些节点,然后删除掉从该节点进出的连线,最后得到一个节点更少,规模更小的网络(如下图所示),然后再用反向传播方法进行训练。
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
###
|
||||
|
||||
###
|
||||
|
||||
### <strong>视频讲解</strong>
|
||||
### **视频讲解**
|
||||
|
||||
# 思考
|
||||
|
||||
@@ -40,7 +40,7 @@ dropout 方法会遍历网络的每一层,并设置消除神经网络中节点
|
||||
|
||||
AlexNet 中有着卷积和 MLP 两种不同的网络结构,那两者之间有着何种区别和联系呢?(可以从两者的权值矩阵去思考)
|
||||
|
||||
### <strong>思考 2</strong>
|
||||
### **思考 2**
|
||||
|
||||
卷积中有一个叫感受野的概念,是什么意思呢?不同的感受野对网络有什么影响?
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
图像分割领域的开山之作。
|
||||
|
||||
首次将<strong>End-to-End</strong>的思想应用在了 CV 领域。
|
||||
首次将**End-to-End**的思想应用在了 CV 领域。
|
||||
|
||||
[知乎](https://zhuanlan.zhihu.com/p/30195134)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
### 框架图
|
||||
|
||||

|
||||

|
||||
|
||||
### 同 CNN 的对比
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
FCN 对图像进行像素级的分类,从而解决了语义级别的图像分割问题。与经典的 CNN 在卷积层之后使用全连接层得到固定长度的特征向量进行分类不同,FCN 可以接受任意尺寸的输入图像,采用反卷积层对最后一个卷积层的 feature map 进行上采样, 使它恢复到输入图像相同的尺寸,从而可以对每个像素都产生了一个预测, 同时保留了原始输入图像中的空间信息, 最后在上采样的特征图上进行逐像素分类。
|
||||
|
||||
<strong>简单的来说,FCN 与 CNN 的区域在把于 CNN 最后的全连接层换成卷积层,输出的是一张已经 Label 好的图片。</strong>
|
||||
**简单的来说,FCN 与 CNN 的区域在把于 CNN 最后的全连接层换成卷积层,输出的是一张已经 Label 好的图片。**
|
||||
|
||||
### 反卷积
|
||||
|
||||
@@ -26,7 +26,7 @@ FCN 对图像进行像素级的分类,从而解决了语义级别的图像分
|
||||
|
||||
这里图像的反卷积使用了这一种反卷积手段使得图像可以变大,FCN 作者使用的方法是这里所说反卷积的一种变体,这样就可以获得相应的像素值,图像可以实现 end to end。
|
||||
|
||||

|
||||

|
||||
|
||||
### 视频
|
||||
|
||||
|
||||
@@ -21,11 +21,11 @@
|
||||
|
||||
如图所示,随着层数越来越深,预测的效果反而越来越差(error 越大)
|
||||
:::
|
||||

|
||||

|
||||
|
||||
## 网络模型
|
||||
|
||||

|
||||

|
||||
|
||||
::: warning 😺
|
||||
我们可以看到,ResNet 的网络依旧非常深,这是因为研究团队不仅发现了退化现象,还采用出一个可以将网络继续加深的 trick:shortcut,亦即我们所说的 residual。
|
||||
@@ -35,7 +35,7 @@
|
||||
:::
|
||||
### residual 结构
|
||||
|
||||

|
||||

|
||||
|
||||
## 网络代码
|
||||
|
||||
@@ -197,7 +197,7 @@ def resnet101(num_classes=1000, include_top=True):
|
||||
|
||||
## 视频
|
||||
|
||||
https://www.bilibili.com/video/BV1P3411y7nn
|
||||
<Bilibili bvid='BV1P3411y7nn'/>
|
||||
|
||||
## 思考
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
## 网络框架
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
::: warning 😺
|
||||
@@ -45,7 +45,7 @@ U-net 网络的结构如图所示,蓝色箭头代表卷积和激活函数,
|
||||
|
||||
## 视频
|
||||
|
||||
https://www.bilibili.com/video/BV1Vq4y127fB
|
||||
<Bilibili bvid='BV1Vq4y127fB'/>
|
||||
|
||||
## 思考 1
|
||||
::: warning 🤔
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
[CNN 与 MLP 之间的关系,优缺点](https://www.editcode.net/archive/detail/89781)
|
||||
|
||||
[MLP(多层感知机)只是 CNN(卷积网络)的一个特例](https://blog.csdn.net/u010165147/article/details/82851717#:~:text=%E6%98%BE%E7%84%B6%E5%8F%AF%E4%BB%A5%E6%8E%A8%E5%AF%BC%E5%87%BA%EF%BC%8C%E5%BD%93%20CNN%E5%8D%B7%E7%A7%AF%E6%A0%B8%E5%A4%A7%E5%B0%8F%E4%B8%8E%E8%BE%93%E5%85%A5%E5%A4%A7%E5%B0%8F%E7%9B%B8%E5%90%8C%20%E6%97%B6%E5%85%B6%E8%AE%A1%E7%AE%97%E8%BF%87%E7%A8%8B%E7%AD%89%E4%BB%B7%E4%BA%8EMLP%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4MLP%E7%AD%89%E4%BB%B7%E4%BA%8E,%E5%8D%B7%E7%A7%AF%E6%A0%B8%E5%A4%A7%E5%B0%8F%E4%B8%8E%E6%AF%8F%E5%B1%82%E8%BE%93%E5%85%A5%E5%A4%A7%E5%B0%8F%E7%9B%B8%E5%90%8C%20%E7%9A%84CNN%EF%BC%88%E5%A6%82%E8%BE%93%E5%85%A5%E5%9B%BE%E7%89%87%E4%B8%BA100x100%EF%BC%8C%E5%8D%B7%E7%A7%AF%E6%A0%B8%E5%A4%A7%E5%B0%8F%E4%B8%BA100x100%EF%BC%89%EF%BC%8C%E6%89%80%E4%BB%A5MLP%E6%98%AFCNN%E7%9A%84%E4%B8%80%E4%B8%AA%E7%89%B9%E4%BE%8B%E3%80%82%20%E8%80%8C%E5%8D%B7%E7%A7%AF%E6%A0%B8%E5%A4%A7%E5%B0%8F%E4%B8%8E%E6%AF%8F%E5%B1%82%E8%BE%93%E5%85%A5%E5%A4%A7%E5%B0%8F%E7%9B%B8%E5%90%8C%E4%BC%9A%E7%9B%B4%E6%8E%A5%E4%B8%A2%E5%A4%B1%E9%9D%9E%E5%B8%B8%E5%A4%9A%E7%9A%84%E8%BE%93%E5%85%A5%E7%A9%BA%E9%97%B4%E4%BF%A1%E6%81%AF%EF%BC%8C%E6%89%80%E4%BB%A5MLP%E8%BF%99%E7%A7%8D%E8%BF%90%E8%A1%8C%E6%A8%A1%E5%BC%8F%E4%B8%8D%E9%80%82%E5%90%88%E5%9B%BE%E5%83%8F%E8%BF%99%E7%A7%8D%E7%A9%BA%E9%97%B4%E4%BF%A1%E6%81%AF%E4%B8%B0%E5%AF%8C%E7%9A%84%E6%95%B0%E6%8D%AE%E3%80%82)
|
||||
|
||||
### 1.2
|
||||
|
||||
[深度理解感受野](https://blog.csdn.net/weixin_40756000/article/details/117264194)
|
||||
@@ -53,9 +51,3 @@
|
||||
### 3.2
|
||||
|
||||
[ResNet 残差、退化等细节解读](https://blog.csdn.net/a8039974/article/details/122380735)
|
||||
|
||||
## 思考 4
|
||||
|
||||
### 4.1
|
||||
|
||||
[U-Net 和 ResNet:长短跳跃连接的重要性(生物医学图像分割)](https://www.jianshu.com/p/20a47427823c)
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
- 你可以先行尝试一下怎么把在 MNIST 上训练的网络真正投入应用,比如识别一张你自己用黑笔写的数字~
|
||||
|
||||

|
||||

|
||||
|
||||
- 比如你可以尝试训练一个网络来实现人体五官分割(笔者之前就玩过这个)数据集采用 [helen 数据集](https://pages.cs.wisc.edu/~lizhang/projects/face-parsing/),关于数据集的架构你可以搜一搜,自己设计一个 Dataloader 和 YourModle 来实现前言中的五官分割效果(真的很有乐子 hhh)
|
||||
|
||||

|
||||

|
||||
|
||||
- 当然你也可以尝试一些自己感兴趣的小任务来锻炼工程能力~
|
||||
|
||||
|
||||
@@ -6,15 +6,15 @@ NeRF 想做这样一件事,不需要中间三维重建的过程,仅根据位
|
||||
|
||||
在生成建模前,我们需要对被建模物体进行密集的采样,如下图是一个示例的训练集,它含有 100 张图片以及保存了每一张图片相机参数(表示拍摄位置,拍摄角度,焦距的矩阵)的 json 文件。
|
||||
|
||||

|
||||

|
||||
|
||||
你可以看到,这 100 张图片是对一个乐高推土机的多角度拍摄结果。我们需要的是一个可<strong>以获取这个推土机在任意角度下拍摄的图片</strong>的模型。如图所示:
|
||||
你可以看到,这 100 张图片是对一个乐高推土机的多角度拍摄结果。我们需要的是一个可**以获取这个推土机在任意角度下拍摄的图片**的模型。如图所示:
|
||||
|
||||

|
||||

|
||||
|
||||
现在来看 NeRF 网络:
|
||||
|
||||
在 NeRF 中,我们把空间<strong>认为是一个个的小方块叠成的空间</strong>(可以理解为 MC)每一个方块有以下属性:
|
||||
在 NeRF 中,我们把空间**认为是一个个的小方块叠成的空间**(可以理解为 MC)每一个方块有以下属性:
|
||||
|
||||
- 3 个位置坐标(x,y,z)
|
||||
- 透明度$\sigma$
|
||||
@@ -24,27 +24,27 @@ NeRF 想做这样一件事,不需要中间三维重建的过程,仅根据位
|
||||
|
||||
## 得到模型
|
||||
|
||||
我们需要的是每个视角下的图片,可以理解为从一个视角发射<strong>光线</strong>,<u>一根光线对应一个像素点</u>。这些光线穿透路径上的所有方块,把这些方块上的属性信息以某种方式累计,就能得到这个像素的颜色。这是 一个已有的公式,只要我们获得每个小方块的颜色信息和不透明度,我们就能知道这个角度下的视图。(这个我们后面介绍)
|
||||
我们需要的是每个视角下的图片,可以理解为从一个视角发射**光线**,<u>一根光线对应一个像素点</u>。这些光线穿透路径上的所有方块,把这些方块上的属性信息以某种方式累计,就能得到这个像素的颜色。这是 一个已有的公式,只要我们获得每个小方块的颜色信息和不透明度,我们就能知道这个角度下的视图。(这个我们后面介绍)
|
||||
|
||||
现在的难点在于:我们不知道<strong>每个小方块的颜色信息</strong>(因为颜色会随着观察角度变化)。众所周知,算法解决不了的问题就扔给神经网络试试啦~
|
||||
现在的难点在于:我们不知道**每个小方块的颜色信息**(因为颜色会随着观察角度变化)。众所周知,算法解决不了的问题就扔给神经网络试试啦~
|
||||
|
||||
<strong>为了获取根据角度变化而变化的颜色信息,我们选择了神经网络。</strong>
|
||||
**为了获取根据角度变化而变化的颜色信息,我们选择了神经网络。**
|
||||
|
||||
<strong>这个网络的输入是:</strong>
|
||||
**这个网络的输入是:**
|
||||
|
||||
- 小方块的位置坐标(x,y,z)
|
||||
- 观察角度(以二维坐标表示两个偏转角)
|
||||
|
||||
<strong>这个网络的输出是:</strong>
|
||||
**这个网络的输出是:**
|
||||
|
||||
- 对应的小方块的 RGB 信息
|
||||
- 不透明度
|
||||
|
||||

|
||||

|
||||
|
||||
在这里,作者选择了最简单的 MLP,因此,<strong>这是一个输入为 5 维,输出为 4 维向量</strong>($R,G,B,\sigma$)的简单网络,值得注意的是,不透明度与观察角度无关,这里在网络中进行了特殊处理,让这个值与后两维无关。
|
||||
在这里,作者选择了最简单的 MLP,因此,**这是一个输入为 5 维,输出为 4 维向量**($R,G,B,\sigma$)的简单网络,值得注意的是,不透明度与观察角度无关,这里在网络中进行了特殊处理,让这个值与后两维无关。
|
||||
|
||||
<strong>现在我们能够输入坐标和视角信息得到小方块的颜色和不透明度,我们就可以对光线穿过的小方块进行计算了。</strong>
|
||||
**现在我们能够输入坐标和视角信息得到小方块的颜色和不透明度,我们就可以对光线穿过的小方块进行计算了。**
|
||||
|
||||
## 进行渲染
|
||||
|
||||
@@ -54,19 +54,19 @@ NeRF 想做这样一件事,不需要中间三维重建的过程,仅根据位
|
||||
|
||||
这个公式对光线上的所有小方块的颜色进行加权求和,权重是关于不透明度$\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>
|
||||
|
||||

|
||||

|
||||
|
||||
上面所说的公式具体如下:t 是我们的$\sigma$,$t_f,t_n$分别是离发射点最远的体素和最近的体素。这个公式求得是像素的颜色。
|
||||
|
||||

|
||||

|
||||
|
||||
思路总体如上,这里放一张找来的渲染过程示意图(<del>不知道为什么有点包浆</del>)
|
||||
|
||||

|
||||

|
||||
|
||||
# 算法细节部分
|
||||
|
||||
@@ -84,12 +84,12 @@ NeRF 想做这样一件事,不需要中间三维重建的过程,仅根据位
|
||||
|
||||
我们使用了两个网络:粗网络和精细网络。
|
||||
|
||||
粗网络就是上述采样方法用的普通网络,而<strong>粗网络输出的不透明度值会被作为一个概率分布函数</strong>,精细网络根据这个概率分布在光线上进行采样,不透明度越大的点,它的邻域被采样的概率越大,也就实现了我们要求的在实体上多采样,空气中少采样。最后精细网络输出作为结果,因此粗网络可以只求不透明度,无视颜色信息。
|
||||
粗网络就是上述采样方法用的普通网络,而**粗网络输出的不透明度值会被作为一个概率分布函数**,精细网络根据这个概率分布在光线上进行采样,不透明度越大的点,它的邻域被采样的概率越大,也就实现了我们要求的在实体上多采样,空气中少采样。最后精细网络输出作为结果,因此粗网络可以只求不透明度,无视颜色信息。
|
||||
|
||||

|
||||

|
||||
|
||||
## 位置编码
|
||||
|
||||
学过 cv 的大家想必对这个东西耳熟能详了吧~,这里的位置编码是对输入的两个位置和一个方向进行的(体素位置,相机位置和方向),使用的是类似 transformer 的三角函数类编码如下。位置编码存在的意义是放大原本的 5 维输入对网络的影响程度,把原本的 5D 输入变为 90 维向量;并且加入了与其他体素的相对位置信息。
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -10,21 +10,21 @@
|
||||
|
||||
### 1.Pixel-nerf
|
||||
|
||||
<strong>Pixel-nerf</strong><strong> </strong>对输入图像使用卷积进行特征提取再执行 nerf,若有多个输入,对每个视角都执行 CNN,在计算光线时,取每一个已有视角下该坐标的特征,经过 mlp 后算平均。可以在少量视角下重建视图,需要进行预训练才能使用,有一定自动补全能力(有限)
|
||||
**Pixel-nerf**** **对输入图像使用卷积进行特征提取再执行 nerf,若有多个输入,对每个视角都执行 CNN,在计算光线时,取每一个已有视角下该坐标的特征,经过 mlp 后算平均。可以在少量视角下重建视图,需要进行预训练才能使用,有一定自动补全能力(有限)
|
||||
|
||||

|
||||

|
||||
|
||||
### 2.IBRnet
|
||||
|
||||
<strong>IBRnet</strong><strong> </strong>是 pixel-nerf 的改进版,取消了 CNN,并且在 mlp 后接入了 transformer 结构处理体密度(不透明度),对这条光线上所有的采样点进行一个 transformer。同时,在获取某个体素的颜色和密度时,作者用了本视角相邻的两个视角,获取对应体素在这两张图片中的像素,以图片像素颜色,视角,图片特征作为 mlp 的输入。
|
||||
**IBRnet**** **是 pixel-nerf 的改进版,取消了 CNN,并且在 mlp 后接入了 transformer 结构处理体密度(不透明度),对这条光线上所有的采样点进行一个 transformer。同时,在获取某个体素的颜色和密度时,作者用了本视角相邻的两个视角,获取对应体素在这两张图片中的像素,以图片像素颜色,视角,图片特征作为 mlp 的输入。
|
||||
|
||||

|
||||

|
||||
|
||||
### 3.MVSnerf
|
||||
|
||||
<strong>MVSnerf</strong><strong> </strong>它用 MVS 的方法构建代价体然后在后面接了一个 nerf,MVS 是使用<strong>多视角立体匹配</strong>构建一个代价体,用 3D 卷积网络进行优化,这里对代价体进行 nerf 采样,可以得到可泛化网络。它需要 15min 的微调才能在新数据上使用。<strong>多视角立体匹配是一种传统算法,通过光线,几何等信息计算图像中小块的相似度,得出两个相机视角之间的位置关系。这个算法也被广泛使用在得到我们自己采样的数据的相机变换矩阵上(我就是这么干的)</strong>
|
||||
**MVSnerf**** **它用 MVS 的方法构建代价体然后在后面接了一个 nerf,MVS 是使用**多视角立体匹配**构建一个代价体,用 3D 卷积网络进行优化,这里对代价体进行 nerf 采样,可以得到可泛化网络。它需要 15min 的微调才能在新数据上使用。**多视角立体匹配是一种传统算法,通过光线,几何等信息计算图像中小块的相似度,得出两个相机视角之间的位置关系。这个算法也被广泛使用在得到我们自己采样的数据的相机变换矩阵上(我就是这么干的)**
|
||||
|
||||

|
||||

|
||||
|
||||
此处涉及较多图形学,使用了平面扫描算法,其中有单应性变换这个角度变换算法,推导与讲解如下:
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
平面扫描就是把 A 视角中的某一像素点(如图中红色区域)的相邻的几个像素提取出来,用单应性变换转换到 B 视角中,这时候用的深度是假设的深度,遍历所有假设的深度,计算通过每一个假设深度经过单应性变换得到的像素小块和 B 视角中对应位置的差值(loss),取最小的 loss 处的深度作为该像素的深度。
|
||||
|
||||

|
||||

|
||||
|
||||
构建代价体:
|
||||
|
||||
@@ -45,37 +45,37 @@
|
||||
|
||||
## 2)可以 zero-shot 或者 fine-tune 类
|
||||
|
||||
<strong>MVSnerf</strong><strong>,上面已经说了。</strong>
|
||||
**MVSnerf****,上面已经说了。**
|
||||
|
||||
# 2.速度提升
|
||||
|
||||
### 1.instan-ngp
|
||||
|
||||
使用了<strong>哈希表</strong>结构的<strong>instant-ngp</strong>,渲染完美只需要几分钟(采样正常的情况下)这块的速度已经到极致了。
|
||||
使用了**哈希表**结构的**instant-ngp**,渲染完美只需要几分钟(采样正常的情况下)这块的速度已经到极致了。
|
||||
|
||||
展开说说:其实这也是神经网络发展的一个方向,以前的深层网络倾向于把所有东西用网络参数表示,这样推理速度就会慢,这里使用哈希表的快速查找能力存储一些数据信息,instant-ngp 就是把要表达的模型数据特征按照不同的精细度存在哈希表中,使用时通过哈希表调用或插值调用。
|
||||
|
||||

|
||||

|
||||
|
||||
# 3.可编辑(指比如人体运动等做修改工作的)
|
||||
|
||||
### 1.Human-nerf
|
||||
|
||||
<strong>Human-nerf</strong><strong> </strong>生成可编辑的人体运动视频建模,输入是一段人随便动动的视频。输出的动作可以编辑修改,并且对衣物折叠等有一定优化。使用的模型并非全隐式的,并且对头发和衣物单独使用变换模型。使用了逆线性蒙皮模型提取人物骨骼(可学习的模型),上面那个蓝色的就是姿态矫正模块,这个模块赋予骨骼之间运动关系的权重(因为使用的是插值处理同一运动时不同骨骼的平移旋转矩阵,一块骨骼动会牵动其他骨骼)图中的 Ω 就是权重的集合,它通过 mlp 学习得到。然后得到显式表达的人物骨骼以及传入视频中得到的对应骨骼的 mesh,skeletal motion 就是做游戏人物动作用的编辑器这种,后面残差链接了一个 non-rigid-motion(非刚性动作),这个是专门处理衣物和毛发的,主要通过学习得到,然后粗暴的加起来就能得到模型,再经过传统的 nerf 渲染出图像。
|
||||
**Human-nerf**** **生成可编辑的人体运动视频建模,输入是一段人随便动动的视频。输出的动作可以编辑修改,并且对衣物折叠等有一定优化。使用的模型并非全隐式的,并且对头发和衣物单独使用变换模型。使用了逆线性蒙皮模型提取人物骨骼(可学习的模型),上面那个蓝色的就是姿态矫正模块,这个模块赋予骨骼之间运动关系的权重(因为使用的是插值处理同一运动时不同骨骼的平移旋转矩阵,一块骨骼动会牵动其他骨骼)图中的 Ω 就是权重的集合,它通过 mlp 学习得到。然后得到显式表达的人物骨骼以及传入视频中得到的对应骨骼的 mesh,skeletal motion 就是做游戏人物动作用的编辑器这种,后面残差链接了一个 non-rigid-motion(非刚性动作),这个是专门处理衣物和毛发的,主要通过学习得到,然后粗暴的加起来就能得到模型,再经过传统的 nerf 渲染出图像。
|
||||
|
||||

|
||||

|
||||
|
||||
### 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 是通过多视角视频生成骨架以及 SMPL 模型的一个工作,演示视频右下。
|
||||
|
||||

|
||||

|
||||
|
||||
这是 EasyMocap 的演示。
|
||||
|
||||
@@ -85,27 +85,27 @@ EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作
|
||||
|
||||
个人感觉这个模型不能很好处理光影效果,还有待改进。
|
||||
|
||||
是个预训练模型,<strong>训练的模块就是这个 3D 卷积神经网络</strong>。
|
||||
是个预训练模型,**训练的模块就是这个 3D 卷积神经网络**。
|
||||
|
||||

|
||||

|
||||
|
||||
### 3.wild-nerf
|
||||
|
||||
<strong>wild-nerf</strong> 思路很简单,就是加入了新的输入参数来调整白天黑夜等等一些简单的变化,并且把行人车辆之类的在采样过程中<strong>不固定的物品</strong>作为<strong>随机项</strong>,在渲染时按照概率加入。
|
||||
**wild-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 时物体的点信息进行渲染。
|
||||
|
||||
在此网络的单个输出上貌似是不监督的,因为没办法进行人为标注。这点我不是很确定,以后如果发现了会来修改的。
|
||||
|
||||

|
||||

|
||||
|
||||
渲染经过形变的物体时,光线其实是在 t=0 时刻进行渲染的,因为推土机的铲子放下去了,所以<strong>光线是弯曲的</strong>。
|
||||
渲染经过形变的物体时,光线其实是在 t=0 时刻进行渲染的,因为推土机的铲子放下去了,所以**光线是弯曲的**。
|
||||
|
||||

|
||||

|
||||
|
||||
# 4.用于辅助传统图像处理
|
||||
|
||||
@@ -115,31 +115,31 @@ EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作
|
||||
|
||||
### 1.clip-nerf
|
||||
|
||||
<strong>clip-nerf</strong><strong> 太贵了玩不起,没仔细研究,应该是文本跟 3D 建模关联,跟 clip 一样。</strong>
|
||||
**clip-nerf**** 太贵了玩不起,没仔细研究,应该是文本跟 3D 建模关联,跟 clip 一样。**
|
||||
|
||||
# 6.生成类(指加入新物体或者额外生成新场景)
|
||||
|
||||
### 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 进行辨别
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
### 2.GIRAFFE
|
||||
|
||||
<strong>GIRAFFE</strong> 是 GRAF 的改进工作,可以把图片中的物品,背景一个个解耦出来单独进行改变或者移动和旋转,也可以增加新的物品或者减少物品,下图中蓝色是不可训练的模块,橙色可训练。以我的理解好像要设置你要解耦多少个(N)物品再训练,网络根据类似 k 近邻法的方法在特征空间上对物品进行分割解耦,然后分为 N 个渲染 mlp 进行训练,训练前加入外观/形状编码 z。最后还是要扔进 D 训练。
|
||||
**GIRAFFE** 是 GRAF 的改进工作,可以把图片中的物品,背景一个个解耦出来单独进行改变或者移动和旋转,也可以增加新的物品或者减少物品,下图中蓝色是不可训练的模块,橙色可训练。以我的理解好像要设置你要解耦多少个(N)物品再训练,网络根据类似 k 近邻法的方法在特征空间上对物品进行分割解耦,然后分为 N 个渲染 mlp 进行训练,训练前加入外观/形状编码 z。最后还是要扔进 D 训练。
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
### 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>
|
||||
|
||||

|
||||

|
||||
|
||||
### 4.Hyper-nerf-gan
|
||||
|
||||
@@ -147,13 +147,13 @@ EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作
|
||||
|
||||
作者用了几个我比较陌生的技术,比如超网络 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 生成图像。
|
||||
|
||||

|
||||

|
||||
|
||||
这种方法存在两个问题:
|
||||
|
||||
@@ -161,12 +161,12 @@ EasyMocap 是通过多视角视频生成骨架以及 SMPL 模型的一个工作
|
||||
|
||||
2.因为使用神经网路去表示图片,占用内存更大。
|
||||
|
||||
因此,作者设计了<strong>FMM</strong>去应对这两个问题,这也是 Hyper-nerf-gan 借鉴的主要部分。
|
||||
因此,作者设计了**FMM**去应对这两个问题,这也是 Hyper-nerf-gan 借鉴的主要部分。
|
||||
|
||||
FMM 主要是把要学习的矩阵转化为两个低秩矩阵,去先生成他们俩再相乘,减少网络计算量。
|
||||
|
||||

|
||||

|
||||
|
||||
现在开始讲 Hyper-nerf-gan 本身,它看上去其实就是 nerf 接在 gan 上。不过有一些变化,比如输入不再包含视角信息,我<strong>很怀疑它不能很好表达反光效果</strong>。而且抛弃了粗网络细网络的设计,只使用粗网络减少计算量。这里的 generator 完全就是 INR-Gan 的形状,生成权重,然后再经过 nerf 的 mlp 层生成,没啥别的了,就这样吧。
|
||||
现在开始讲 Hyper-nerf-gan 本身,它看上去其实就是 nerf 接在 gan 上。不过有一些变化,比如输入不再包含视角信息,我**很怀疑它不能很好表达反光效果**。而且抛弃了粗网络细网络的设计,只使用粗网络减少计算量。这里的 generator 完全就是 INR-Gan 的形状,生成权重,然后再经过 nerf 的 mlp 层生成,没啥别的了,就这样吧。
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -2,62 +2,62 @@
|
||||
|
||||
如何使用和怎么下载就不讲了,直接搜就有,它可以把多个拍摄同一物体的图片转换为它们对应视角的相机矩阵和拍摄角度,可以实现自制数据集做 nerf。它的流程(SFM 算法)可以概括如下:
|
||||
|
||||

|
||||

|
||||
|
||||
这里主要是记录一下它的原理:
|
||||
首先是一个经典关键点匹配技术:<strong>SIFT</strong>
|
||||
首先是一个经典关键点匹配技术:**SIFT**
|
||||
|
||||
# SIFT 特征点匹配
|
||||
|
||||
## DOG 金字塔
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
下面是原理方法:
|
||||
|
||||
首先是<strong>高斯金字塔</strong>,它是把原图先放大两倍,然后使用高斯滤波(高斯卷积)对图像进行模糊化数次,取出倒数第三层缩小一半继续进行这个过程,也就是说它是由一组一组的小金字塔组成的。
|
||||
首先是**高斯金字塔**,它是把原图先放大两倍,然后使用高斯滤波(高斯卷积)对图像进行模糊化数次,取出倒数第三层缩小一半继续进行这个过程,也就是说它是由一组一组的小金字塔组成的。
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
然后是基于高斯金字塔的 DOG 金字塔,也叫差分金字塔,它是把相邻的高斯金字塔层做减法得到的,因为经过高斯模糊,物体的轮廓(或者说不变特征)被模糊化,也就是被改变。通过相减可以得到这些被改变的点。
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
## 空间极值点检测
|
||||
|
||||
为了找到变化的最大的几个点来作为特征点,我们需要找到变化的极值点,因此需要进行比较,这里是在整个金字塔中进行对比,我们提取某个点周边 3*3*3 的像素点进行比较,找到最大或最小的局部极值点。
|
||||
|
||||

|
||||

|
||||
|
||||
同时我们也对关键点分配方向,也就是这个点在图片空间中的梯度方向
|
||||
|
||||
梯度为:
|
||||
|
||||

|
||||

|
||||
|
||||
梯度方向为:
|
||||
|
||||

|
||||

|
||||
|
||||
我们计算以关键点为中心的邻域内所有点的梯度方向,然后把这些 360 度范围内的方向分配到 36 个每个 10 度的方向中,并构建方向直方图,这里的示例使用了 8 个方向,几个随你其实:
|
||||
|
||||

|
||||

|
||||
|
||||
取其中最大的为主方向,若有一个方向超过主方向的 80%,那么把它作为辅方向。
|
||||
|
||||
操作可以优化为下图,先把关键点周围的像素分成 4 块,每块求一次上面的操作,以这个 4 个梯度直方图作为关键点的方向描述。也就是一个 2*2*8(方向数量)的矩阵作为这个点的方向特征。
|
||||
|
||||

|
||||

|
||||
|
||||
实验表明,使用 4*4*8=122 的描述更加可靠。
|
||||
|
||||

|
||||

|
||||
|
||||
特征点的匹配是通过计算两组特征点的 128 维的关键点的欧式距离实现的。欧式距离越小,则相似度越高,当欧式距离小于设定的阈值时,可以判定为匹配成功。
|
||||
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
|
||||
该任务目前在学术上是检索出不同摄像头下的相同行人图片,同时数据集中只有人的全身照,如下图所示。
|
||||
|
||||

|
||||

|
||||
|
||||
但是实际上在实际应用中的时候会和检测结合,简单来说先框出目标后分类,如下图所示。
|
||||
|
||||

|
||||

|
||||
|
||||
这个方向做的比较的奇怪,该模块只做整体性介绍,同时希望学习该模块的你对经典网络有所了解。
|
||||
|
||||
@@ -2,27 +2,27 @@
|
||||
|
||||
下面给出了 NLP 的四大常见的应用。由于预训练的模型是在连续的文本序列上训练的,所以需要进行一些修改才能将其应用于不同的这些 NLP 任务。
|
||||
|
||||
<strong>分类 (text classification):</strong> 给一句话或者一段文本,判断一个标签。
|
||||
**分类 (text classification):** 给一句话或者一段文本,判断一个标签。
|
||||
|
||||

|
||||

|
||||
|
||||
图 2:分类 (text classification)
|
||||
|
||||
<strong>蕴含 (textual entailment):</strong> 给一段话,和一个假设,看看前面这段话有没有蕴含后面的假设。
|
||||
**蕴含 (textual entailment):** 给一段话,和一个假设,看看前面这段话有没有蕴含后面的假设。
|
||||
|
||||

|
||||

|
||||
|
||||
图 3:蕴含 (textual entailment)
|
||||
|
||||
<strong>相似 (Similarity):</strong> 判断两段文字是否相似。
|
||||
**相似 (Similarity):** 判断两段文字是否相似。
|
||||
|
||||

|
||||

|
||||
|
||||
图 4:相似 (Similarity)
|
||||
|
||||
<strong>多选题 (Multiple Choice):</strong> 给个问题,从 N 个答案中选出正确答案。
|
||||
**多选题 (Multiple Choice):** 给个问题,从 N 个答案中选出正确答案。
|
||||
|
||||

|
||||

|
||||
|
||||
图 5:多选题 (Multiple Choice)
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# 推荐系统概念解释 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}}
|
||||
@@ -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}}
|
||||
@@ -31,7 +31,7 @@
|
||||
- 精确率的意义?
|
||||
|
||||
|
||||
- <strong>覆盖率</strong>
|
||||
- **覆盖率**
|
||||
|
||||
- 描述了一个系统对于物品长尾的发掘能力。
|
||||
- 覆盖率的一个定义可以是:
|
||||
@@ -42,7 +42,7 @@
|
||||
- 覆盖率的意义:覆盖率越高,以为这系统中被推荐给用户的物品,占所有物品的比例越大,对于一个好的推荐系统,不仅需要有较高的用户满意度,还需要有较高的覆盖率。
|
||||
- 当然对于覆盖率的定义,不止以上的这一种,甚至说,在实际使用上,上述简单的覆盖率不足以支撑大规模复杂系统的覆盖率计算,所以如何对于覆盖率进行修正和更新?信息熵与基尼系数!
|
||||
- 推荐了解,马太效应,一个强者更强,弱者更弱的效应,在推荐系统中也同样存在。
|
||||
- <strong>多样性</strong>
|
||||
- **多样性**
|
||||
|
||||
- 假设,$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))}
|
||||
$$
|
||||
- <strong>信任度</strong>
|
||||
- **信任度**
|
||||
|
||||
- 用户对于该系统的信任程度
|
||||
- <strong>实时性</strong>
|
||||
- **实时性**
|
||||
|
||||
- 系统对于数据更新的时效性
|
||||
- <strong>健壮性</strong>
|
||||
- **健壮性**
|
||||
|
||||
- 系统对于外来攻击的防护性
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 推荐系统的外围架构
|
||||
|
||||

|
||||

|
||||
|
||||
<center>推荐系统外围架构图</center>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
若是将推荐系统的任务细分,可以结合现实实际情况:将最新加入的物品推荐给用户;商业上需要宣传的物品推荐给用户;为用户推荐不同种类的物品。
|
||||
**复杂的特征和情况不同的任务**会让推荐系统变得非常复杂,所以推荐系统的架构为了方便考虑,采用多个不同的推荐引擎组成,每个推荐引擎专门负责某一类特征和一种任务,而推荐系统再将推荐引擎的结果按照一定的优先级合并,排序并返回给UI系统。
|
||||
|
||||

|
||||

|
||||
|
||||
<center>推荐系统的架构</center>
|
||||
如上图所示。
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
- 推荐列表筛选、过滤、重排列部分
|
||||
|
||||

|
||||

|
||||
|
||||
以上为推荐引擎的架构图。
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ $$Preference(u,i)=r_{ui}=p^T_uq_i=\sum^F_{f=1}{p_{u,k}q_{i,k}}$$
|
||||
|
||||
在研究图模型之前,需要用已有的数据生成一个图,设二元组 $(u,i)$ 表示用u对于物品 i 产生过行为。令 $G(V,E)$ 表示用户物品二分图,其中$V=V_U\cup V_I$ 由用户顶点集合和物品顶点集合组成,$E$ 是边的集合。对于数据集中的二元组 $(u,i)$ 图中都会有对应的边 $e(v_u,v_i)\in E$ 如下图所示。
|
||||
|
||||

|
||||

|
||||
|
||||
### 基于图的推荐算法
|
||||
|
||||
|
||||
@@ -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 在最近的流行度可定义为:
|
||||
@@ -67,10 +67,10 @@
|
||||
n_i(T)= \sum_{(u,i,t) \in Train ,t<T} \frac{1}{1+\alpha(T-t)}
|
||||
$$
|
||||
|
||||
- <strong>时间上下文相关的 itemCF 算法</strong>
|
||||
- **时间上下文相关的 itemCF 算法**
|
||||
itemCF 算法所依赖的核心部分,在引入时间信息后可以进行进一步更新
|
||||
|
||||
- <strong>物品相似度</strong> 利用用户行为,计算物品间的相似度,用户在相隔很短的时间内喜欢的物品通常具有更高的相似度,所以可以在相似度计算公式中引入时间信息,使得相似度计算更加准确。
|
||||
- **物品相似度** 利用用户行为,计算物品间的相似度,用户在相隔很短的时间内喜欢的物品通常具有更高的相似度,所以可以在相似度计算公式中引入时间信息,使得相似度计算更加准确。
|
||||
原本的相似度公式为:
|
||||
|
||||
$$
|
||||
@@ -91,7 +91,7 @@
|
||||
|
||||
其中$\alpha$ 是时间衰减参数,它的取值与系统的对于自身定义有关系。收到用户兴趣变化的额外影响。
|
||||
|
||||
- <strong>在线推荐</strong> 用户近期行为相比用户很久之前的行为,更能体现用户目前的兴趣,所以在进行预测时,应当加重用户近期行为的权重,但不应该偏离用户长期行为的行为基调。
|
||||
- **在线推荐** 用户近期行为相比用户很久之前的行为,更能体现用户目前的兴趣,所以在进行预测时,应当加重用户近期行为的权重,但不应该偏离用户长期行为的行为基调。
|
||||
原本的用户u对于物品i的兴趣$p(u,i)$ 可通过如下公式计算:
|
||||
|
||||
$$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$ 是一样的,需要根据系统的情况选择合适的值。
|
||||
|
||||
- <strong>时间上下文相关的userCF算法</strong>
|
||||
- **时间上下文相关的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间相似度的基本公式为:
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
|
||||
同样增加了一个时间衰减因子,用户uv对于i的作用时间差距越大,那么两人的相似度会相应降低。
|
||||
|
||||
- <strong>相似兴趣用户的最近行为</strong> 对于用户u来说,存在最近行为与用户u相似的用户v,那么用户v的最近行为,将会比用户u很久之前的行为更具有参考价值。
|
||||
- **相似兴趣用户的最近行为** 对于用户u来说,存在最近行为与用户u相似的用户v,那么用户v的最近行为,将会比用户u很久之前的行为更具有参考价值。
|
||||
|
||||
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)}
|
||||
$$
|
||||
|
||||
- <strong>时间段图模型</strong>
|
||||
- **时间段图模型**
|
||||
同样是一个基于图的推荐系统模型,引入时间信息,建立一个二分图时间段图模型:
|
||||
|
||||
$$
|
||||
@@ -169,11 +169,11 @@
|
||||
在构建了引入时间信息的图结构后,最简单的思想就是利用PersonalRank算法给用进行个性化推荐。但由于其复杂度较高,所以引入路径融合算法。
|
||||
一般来说,图上两个点的相关度强有以下的特征:
|
||||
|
||||
- <strong>两个顶点间有很多路径</strong>
|
||||
- **两个顶点间有很多路径**
|
||||
|
||||
- <strong>两个顶点间路径比较短</strong>
|
||||
- **两个顶点间路径比较短**
|
||||
|
||||
- <strong>两点间不经过出度大的点</strong> ,即不经过与很多其他点相连的节点,在推荐系统思维中等效于不与过热门物品关系紧密。
|
||||
- **两点间不经过出度大的点** ,即不经过与很多其他点相连的节点,在推荐系统思维中等效于不与过热门物品关系紧密。
|
||||
|
||||
#### 路径融合算法
|
||||
|
||||
@@ -199,15 +199,15 @@
|
||||
|
||||
### 地点信息效应
|
||||
|
||||
- <strong>基于用户当前位置的推荐</strong>:对于用户当前位置,为其推荐距离更近的餐馆,娱乐场所或消费场所。
|
||||
- **基于用户当前位置的推荐**:对于用户当前位置,为其推荐距离更近的餐馆,娱乐场所或消费场所。
|
||||
|
||||
- <strong>基于用户活跃位置的推荐</strong>:对于用户长期活跃的区域,降低该区域内物品的权重,提高范围外物品的权重,以提高系统的新鲜度。
|
||||
- **基于用户活跃位置的推荐**:对于用户长期活跃的区域,降低该区域内物品的权重,提高范围外物品的权重,以提高系统的新鲜度。
|
||||
|
||||
### 基于位置的推荐算法
|
||||
|
||||
- 明尼苏达大学的LARS推荐系统(Location Aware Recommender System,位置感知推荐系统)。
|
||||
|
||||
- <strong>对于数据的预处理</strong>
|
||||
- **对于数据的预处理**
|
||||
|
||||
|
||||
将物品分为两类:(1)有空间属性的物品,餐馆,商店,旅游景点。(2)没有空间属性的物品,图书电影等。
|
||||
@@ -223,9 +223,9 @@
|
||||
(用户,用户位置,物品,物品位置,评分):记录了某个位置的用户,对于某个地点的物品的评分。
|
||||
|
||||
|
||||
- <strong>研究前两组数据</strong>:发现两种特征:(1)兴趣本地化,不同位置的用户存在较大的兴趣差异,不同国家和不同地区的差异。(2)活动本地化,一个用户往往在附近的地区活动。
|
||||
- **研究前两组数据**:发现两种特征:(1)兴趣本地化,不同位置的用户存在较大的兴趣差异,不同国家和不同地区的差异。(2)活动本地化,一个用户往往在附近的地区活动。
|
||||
|
||||
- <strong>对于不同数据的处理</strong>
|
||||
- **对于不同数据的处理**
|
||||
|
||||
- 第一种数据:LARS的基本思想是,采用树状结构来进行数据集划分。
|
||||
|
||||
@@ -236,7 +236,7 @@
|
||||
(3)LARS通过该节点的行为数据,利用基本推荐算法进行为用户进行推荐。
|
||||
|
||||
但是,对于上述过程,若是树的深度较大,则划分到每个节点的用户数据将较少,难以训练出一个令人满意的模型。所以有改进方法如下:
|
||||
从根节点出发,利用每个中间节点的数据训练出一个模型,而最终的推荐结果,是这一些列推荐模型所产出的推荐结果的加权结果。这个模型也被称为“<strong>金字塔模型</strong>”,其中<strong>深度</strong>是影响这个模型性能的重要参数,选取合适的深度对于该算法十分重要。
|
||||
从根节点出发,利用每个中间节点的数据训练出一个模型,而最终的推荐结果,是这一些列推荐模型所产出的推荐结果的加权结果。这个模型也被称为“**金字塔模型**”,其中**深度**是影响这个模型性能的重要参数,选取合适的深度对于该算法十分重要。
|
||||
|
||||
- 第二种数据:对于物品i在用户u推荐列表中的权重公式进行修正
|
||||
(1)首先忽略物品的位置信息,利用itemCF算法计算用户u对物品i的兴趣。
|
||||
|
||||
@@ -10,5 +10,5 @@
|
||||
<br/><br/>
|
||||
而SRSs则是将用户和商品的交互建模为一个动态的序列并且利用序列的依赖性来活捉当前和最近用户的喜好。
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
如下图是阿里巴巴著名的“千人千面”推荐系统
|
||||
|
||||

|
||||

|
||||
|
||||
还有短视频应用用户数量的急剧增长,这背后,视频推荐引擎发挥着不可替代的作用
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
具体其发展历程参考:
|
||||
|
||||
- [https://mp.weixin.qq.com/s/Mcikp99bsVgxAaykctmcAw](https://mp.weixin.qq.com/s/Mcikp99bsVgxAaykctmcAw) 知识图谱的前世今生
|
||||
- [https://www.it610.com/article/1277333416756396032.htm](https://www.it610.com/article/1277333416756396032.htm) 知识图谱历史发展
|
||||
|
||||
在大致了解知识图谱的历史发展脉络后,我们或许对它有了一个初步的认知——一个由抽象符号构成的知识库,目的是为了让计算机理解人类的语义信息,打个不太恰当的比方,就是个计算机理解人类世界的大脑。
|
||||
|
||||
@@ -42,4 +41,4 @@
|
||||
在成功搭建起知识图谱这个数据库后,接下来就是最重要的一步了,让计算机理解——表示学习。目前这个方向,最重要的就是向量化,将节点和关系全部向量化,一方面有向量的平移不变性的好处,另一方面也方便计算,在从中穿插点图论的相关知识,例如将知识图谱看成特大号异构图进行处理。不过这方面方向太多,难以一一列举。
|
||||
|
||||
- [https://www.cnblogs.com/fengwenying/default.html?page=5](https://www.cnblogs.com/fengwenying/default.html?page=5) 胡萝不青菜的博客
|
||||
- [https://space.bilibili.com/497998686?spm_id_from=333.337.0.0](https://space.bilibili.com/497998686?spm_id_from=333.337.0.0) up 主骰子 AI,知识图谱在推荐系统上的利用
|
||||
- [up主 骰子 AI](https://space.bilibili.com/497998686?spm_id_from=333.337.0.0) up 主 骰子 AI,知识图谱在推荐系统上的利用
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
VIT前Transformer模型被大量应用在NLP自然语言处理当中,而在CV领域,Transformer的注意力机制attention也被广泛应用,比如Se模块,CBAM模块等等注意力模块,这些注意力模块能够帮助提升网络性能。
|
||||
|
||||
而<strong>VIT的工作展示了不需要依赖CNN的结构,也可以在图像分类任务上达到很好的效果</strong>。
|
||||
而**VIT的工作展示了不需要依赖CNN的结构,也可以在图像分类任务上达到很好的效果**。
|
||||
|
||||
同时VIT也影响了近2年的CV领域,改变了自2012年AlexNet提出以来卷积神经网络在CV领域的绝对统治地位。
|
||||
|
||||
@@ -18,13 +18,13 @@
|
||||
|
||||
## 模型详解
|
||||
|
||||

|
||||

|
||||
|
||||
### 模型主题结构
|
||||
|
||||
结构上,VIT 采取的是原始 Transformer 模型,方便开箱即用,即在 encoder-decoder 结构上与 NLP 的 Transform 模型并无差别。
|
||||
|
||||
主要做出的贡献在于<strong>数据处理和分类头</strong>
|
||||
主要做出的贡献在于**数据处理和分类头**
|
||||
|
||||
### Patch embedding
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
> 今天天气不错,我要去看电影
|
||||
|
||||
其中<strong>我</strong>则编码为[0.5,0.6,0.6]
|
||||
其中**我**则编码为[0.5,0.6,0.6]
|
||||
|
||||
而具体来说 Word embedding 分为以下两步
|
||||
|
||||
@@ -51,9 +51,9 @@
|
||||
|
||||
例如
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
其中该张图片的编码为[0.5,0.6,0.3,....]
|
||||
|
||||
@@ -70,4 +70,4 @@
|
||||
|
||||
## 视频
|
||||
|
||||
https://www.bilibili.com/video/BV15P4y137jb
|
||||
<Bilibili bvid='BV15P4y137jb'/>
|
||||
|
||||
@@ -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 作为分类头,在我的小规模数据上进行继续训练即可(也就是微调)。
|
||||
|
||||
@@ -24,19 +24,19 @@ mlp 的重点和创新并非它的模型结构,而是它的训练方式,前
|
||||
|
||||
在文本被输入模型之前,我们要对它进行一些处理:
|
||||
|
||||
1. <strong>词向量</strong>(wordpiece embedding):单词本身的向量表示。每个词(或者进行时过去时后缀之类的)会被记录为一个向量。它们被储存在一个字典里,这一步其实就是在字典中查找这个词对应的向量。
|
||||
2. <strong>位置向量</strong>(position embedding):将单词的位置信息编码成特征向量。构建 position embedding 有两种方法:BERT 是初始化一个 position embedding,<strong>然后通过训练将其学出来</strong>;而 Transformer 是通过<strong>制定规则</strong>来构建一个 position embedding。
|
||||
3. <strong>句子向量</strong>(segment embedding):用于区分两个句子的向量表示。这个在问答等非对称句子中是用于区别的。(这个主要是因为可能会用到对句子的分析中)
|
||||
1. **词向量**(wordpiece embedding):单词本身的向量表示。每个词(或者进行时过去时后缀之类的)会被记录为一个向量。它们被储存在一个字典里,这一步其实就是在字典中查找这个词对应的向量。
|
||||
2. **位置向量**(position embedding):将单词的位置信息编码成特征向量。构建 position embedding 有两种方法:BERT 是初始化一个 position embedding,**然后通过训练将其学出来**;而 Transformer 是通过**制定规则**来构建一个 position embedding。
|
||||
3. **句子向量**(segment embedding):用于区分两个句子的向量表示。这个在问答等非对称句子中是用于区别的。(这个主要是因为可能会用到对句子的分析中)
|
||||
|
||||
BERT 模型的输入就是上面三者的和,如图所示:
|
||||
|
||||

|
||||

|
||||
|
||||
## 模型结构
|
||||
|
||||
简单来说,BERT 是 transformer<strong>编码器</strong>的叠加,<strong>也就是下图左边部分</strong>。这算一个 block。
|
||||
简单来说,BERT 是 transformer**编码器**的叠加,**也就是下图左边部分**。这算一个 block。
|
||||
|
||||

|
||||

|
||||
|
||||
说白了就是一个 多头自注意力=>layer-norm=> 接 feed forward(其实就是 mlp)=>layer-norm,没有什么创新点在这里。因为是一个 backbone 模型,它没有具体的分类头之类的东西。输出就是最后一层 block 的输出。
|
||||
|
||||
@@ -50,7 +50,7 @@ BERT 训练方式跟 cv 里的很多 backbone 模型一样,是先用几个具
|
||||
|
||||
跟以往的 nlp 模型不同,BERT 的掩码并非 transformer 那样,给前面不给后面,而是在句子中随机把单词替换为 mask,让模型去猜,也就是完形填空。下面给个例子:
|
||||
|
||||
<strong>划掉的单词是被 mask 的</strong>
|
||||
**划掉的单词是被 mask 的**
|
||||
|
||||
正常的掩码:I am a <del>little cat</del>
|
||||
|
||||
@@ -74,6 +74,8 @@ BERT 因为是以完型填空训练的,因此不能用于文本生成任务,
|
||||
|
||||
# 相关资料:
|
||||
|
||||
李沐的【BERT 论文逐段精读【论文精读】】 [https://www.bilibili.com/video/BV1PL411M7eQ/?share_source=copy_web&vd_source=59df19b7fca15c3fb440b91c21605fc6](https://www.bilibili.com/video/BV1PL411M7eQ/?share_source=copy_web&vd_source=59df19b7fca15c3fb440b91c21605fc6)
|
||||
李沐的【BERT 论文逐段精读【论文精读】】https://www.bilibili.com/video/BV1PL411M7eQ
|
||||
|
||||
<Bilibili bvid='BV1PL411M7eQ'/>
|
||||
|
||||
原论文:[https://arxiv.org/pdf/1810.04805v2](https://arxiv.org/pdf/1810.04805v2)
|
||||
|
||||
@@ -14,7 +14,7 @@ cv 领域,其实预训练模型早已推广,一般是在 imagenet 上进行
|
||||
|
||||
那么问题来了,既然我们要学习 BERT 的随机掩码,那么我们应该对什么做 mask 呢?
|
||||
|
||||
因为图片不像文本,有单词这一基础单位。图片的基础单位像素在被单独拿出来的时候包含的语义信息是完全不如单词的。因为像素的语义信息与<strong>上下左右的连续关系</strong>很密切。于是作者采用了像 VIT 那样把图片分成好几个 patch,对 patch 做随机掩码。
|
||||
因为图片不像文本,有单词这一基础单位。图片的基础单位像素在被单独拿出来的时候包含的语义信息是完全不如单词的。因为像素的语义信息与**上下左右的连续关系**很密切。于是作者采用了像 VIT 那样把图片分成好几个 patch,对 patch 做随机掩码。
|
||||
|
||||
# 模型结构与训练方式
|
||||
|
||||
@@ -28,7 +28,7 @@ cv 领域,其实预训练模型早已推广,一般是在 imagenet 上进行
|
||||
|
||||
在这里,作者为了加大任务的难度,扩大了被 mask 掉的比例,避免模型只学到双线性插值去修补缺的图像。作者把 75% 的 patch 进行 mask,然后放入模型训练。从下图可以看出,被 mask 的块是不进行编码的,这样也可以降低计算量,减少成本。
|
||||
|
||||

|
||||

|
||||
|
||||
在被保留的块通过编码器后,我们再在原先位置插入只包含位置信息的 mask 块,一起放入解码器。
|
||||
|
||||
@@ -38,12 +38,14 @@ cv 领域,其实预训练模型早已推广,一般是在 imagenet 上进行
|
||||
|
||||
下面是原论文给的训练结果,可以看到效果是很惊人的。(有些图我脑补都补不出来)
|
||||
|
||||

|
||||

|
||||
|
||||
# 相关资料
|
||||
|
||||
更具体的比如模型性能对比最好还是去看原论文或者李沐老师的讲解
|
||||
|
||||
李沐【MAE 论文逐段精读【论文精读】】 [https://www.bilibili.com/video/BV1sq4y1q77t/?share_source=copy_web&vd_source=59df19b7fca15c3fb440b91c21605fc6](https://www.bilibili.com/video/BV1sq4y1q77t/?share_source=copy_web&vd_source=59df19b7fca15c3fb440b91c21605fc6)
|
||||
李沐【MAE 论文逐段精读【论文精读】】 https://www.bilibili.com/video/BV1sq4y1q77t
|
||||
|
||||
<Bilibili bvid='BV1sq4y1q77t'/>
|
||||
|
||||
原论文:[https://arxiv.org/pdf/2111.06377v2.pdf](https://arxiv.org/pdf/2111.06377v2.pdf)
|
||||
|
||||
@@ -38,7 +38,9 @@
|
||||
|
||||
论文的优秀讲解
|
||||
|
||||
[Transformer 中 Self-Attention 以及 Multi-Head Attention 详解_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV15v411W78M?spm_id_from=333.337.search-card.all.click&vd_source=2cb6252f9211ae9d29cf1f76f0aea8d7)
|
||||
[Transformer 中 Self-Attention 以及 Multi-Head Attention 详解_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV15v411W78M)
|
||||
|
||||
<Bilibili bvid='BV15v411W78M'/>
|
||||
|
||||
除此之外就是相关代码,不要求你可以完全自己复现,但是要保证非常重要的知识都懂
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
对比学习,故名思意,是对比着来学习。而我们拿来对比的东西就是在模型眼里的语义,也就是我们叫做特征的向量。
|
||||
|
||||
在具体讲对比之前,我们先看看传统的<strong>监督学习</strong>是怎么学特征的:
|
||||
在具体讲对比之前,我们先看看传统的**监督学习**是怎么学特征的:
|
||||
|
||||
数据 + 模型=> 特征,特征对人工标注进行学习,也就是说我们要把模型抽取的特征尽可能的靠近人工标注
|
||||
|
||||
@@ -24,17 +24,17 @@
|
||||
|
||||
直观来讲,我们把特征的向量进行一下归一化,它们就分布在一个超球面上。简单起见,我们先看 3 维向量
|
||||
|
||||

|
||||

|
||||
|
||||
我们通过<strong>正样本</strong>(跟拿到的特征<strong>应当相近</strong>的另一个特征)与<strong>负样本</strong>(反之)的对比,使得
|
||||
我们通过**正样本**(跟拿到的特征**应当相近**的另一个特征)与**负样本**(反之)的对比,使得
|
||||
|
||||
越相近的物体,它们的特征就在超球面上越靠近,越不像的物体离的越远,去学习图片更本质的特征
|
||||
|
||||
那么具体的对比学习方法我在后面结合一些论文一起讲吧~
|
||||
|
||||
这部分内容更像一个综述,讲述对比学习这几年的发展路程,所以我会尽可能的描述作者在论文里讲的<strong>故事</strong>,来方便大家弄清为什么要这么做。
|
||||
这部分内容更像一个综述,讲述对比学习这几年的发展路程,所以我会尽可能的描述作者在论文里讲的**故事**,来方便大家弄清为什么要这么做。
|
||||
|
||||
<strong>可能会有很多我的主观理解在此</strong>,并且<strong>不会</strong>深入细节。可以算是一个总结和分享,我会在这里带着读者过一遍近期对比学习的工作来给大家一个对比学习方向的直观感性理解。
|
||||
**可能会有很多我的主观理解在此**,并且**不会**深入细节。可以算是一个总结和分享,我会在这里带着读者过一遍近期对比学习的工作来给大家一个对比学习方向的直观感性理解。
|
||||
|
||||
同时因为笔者水平,视野,精力有限,不可能包含所有的算法,也不可能保证完全正确。因此仅作为笔记分享使用。若有错误,请多多指正。
|
||||
|
||||
|
||||
@@ -8,15 +8,15 @@
|
||||
|
||||
作者团队认为,让这些猎豹,雪豹的标签相互接近(指互相在判别时都排名靠前)的原因并不是它们有相似的标签,而是它们有相似的图像特征。
|
||||
|
||||

|
||||

|
||||
|
||||
## 个体判别任务
|
||||
|
||||
既然有了上面这个发现,那么作者想我能不能把分类任务推到极致呢?
|
||||
|
||||
于是他们<strong>把每一个图片当作一个类别</strong>,去跟其他的图片做对比,具体模型如下
|
||||
于是他们**把每一个图片当作一个类别**,去跟其他的图片做对比,具体模型如下
|
||||
|
||||

|
||||

|
||||
|
||||
先介绍一下模型结构:
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
|
||||
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 是正样本,其他都是负样本,同理类推。
|
||||
|
||||
@@ -38,9 +38,9 @@
|
||||
|
||||
用动量更新的方法去更新 memory bank 中的特征
|
||||
|
||||
也就是让特征的变化<strong>不那么剧烈</strong>
|
||||
也就是让特征的变化**不那么剧烈**
|
||||
|
||||
原因:如果一直保持更新,<strong>特征总体的变化就会比较大</strong>,而我们在大数据集上训练的时候,等第二次调用一个特征时,它跟现在的特征分布已经大相径庭,那就不好训练了,也就是<strong>特征缺乏一致性</strong>。因此我们引入动量更新来确保特征进行平稳的改变,而非突变。
|
||||
原因:如果一直保持更新,**特征总体的变化就会比较大**,而我们在大数据集上训练的时候,等第二次调用一个特征时,它跟现在的特征分布已经大相径庭,那就不好训练了,也就是**特征缺乏一致性**。因此我们引入动量更新来确保特征进行平稳的改变,而非突变。
|
||||
|
||||
#### 关于动量的小拓展
|
||||
|
||||
@@ -48,11 +48,11 @@
|
||||
|
||||
A 是起始点,B 是第一次更新后的点,C 是第二次更新后的点
|
||||
|
||||

|
||||

|
||||
|
||||
而在我们刚刚提到的动量更新里,它的公式可以概括为:
|
||||
|
||||

|
||||

|
||||
|
||||
m 表示动量,k 是新的特征,q 是上一个特征,只要设置小的动量就可以使改变放缓。
|
||||
|
||||
@@ -60,4 +60,4 @@ m 表示动量,k 是新的特征,q 是上一个特征,只要设置小的
|
||||
|
||||
总体来说,Inst Disc 把对比学习成功引入了 CV 领域,核心思想是构建动态字典进行对比学习
|
||||
|
||||
<strong>PS:若无特殊说明,最后保留下来去做下游任务的模型只有编码器,其他都删除了。</strong>
|
||||
**PS:若无特殊说明,最后保留下来去做下游任务的模型只有编码器,其他都删除了。**
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
# 1.时序性定义(生成式模型)
|
||||
|
||||

|
||||

|
||||
|
||||
这是处理音频的一个例子,<strong>给模型 t 时刻以前的信息,让它抽取特征并对后文进行预测,真正的后文作为正样本,负样本当然是随便选取就好啦。</strong>
|
||||
这是处理音频的一个例子,**给模型 t 时刻以前的信息,让它抽取特征并对后文进行预测,真正的后文作为正样本,负样本当然是随便选取就好啦。**
|
||||
|
||||
不同于之前说的个体判别,这个是<strong>生成式模型</strong>,这个模型不止可以处理音频,还可以处理图片(每一个块换成一个词)或者处理图片(以 patch 为单位)。
|
||||
不同于之前说的个体判别,这个是**生成式模型**,这个模型不止可以处理音频,还可以处理图片(每一个块换成一个词)或者处理图片(以 patch 为单位)。
|
||||
|
||||
是不是有点眼熟?这跟我前面写的 BERT 和 MAE 其实异曲同工,不过这两位是随机 mask,而非时序性的 mask。
|
||||
|
||||
@@ -24,4 +24,4 @@
|
||||
|
||||
(这篇论文我准备开个新坑放着了,因为说实话不算对比学习,算多模态)
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -14,9 +14,9 @@ MoCo 是 Inst Disc 的改进工作,那我们自然要先看一下 Inst Disc
|
||||
|
||||
## 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 那样把狗和车打成一类**,这样不利于模型学习。
|
||||
|
||||
并且它也不是很灵活,下文细讲
|
||||
|
||||
@@ -24,7 +24,7 @@ NCE 把<strong>所有负样本都视作一样的</strong>,但实际上负样
|
||||
|
||||
右边就是 memory bank 啦
|
||||
|
||||

|
||||

|
||||
|
||||
# MoCo 做出的改进
|
||||
|
||||
@@ -34,11 +34,11 @@ NCE 把<strong>所有负样本都视作一样的</strong>,但实际上负样
|
||||
|
||||
## 2.针对动量更新不能完全解决特征一致性差的问题
|
||||
|
||||
作者提出了一个新的<strong>动量编码器</strong>来替代动量更新。
|
||||
作者提出了一个新的**动量编码器**来替代动量更新。
|
||||
|
||||
动量编码器是独立于原编码器的一个编码器,它的参数是根据原编码器动量更新的,k 和 q 就是指代全部参数了
|
||||
|
||||

|
||||

|
||||
|
||||
这样的话就是解码器在缓慢更新,比对特征使用动量更新要更有连续性。
|
||||
|
||||
@@ -48,17 +48,17 @@ NCE 把<strong>所有负样本都视作一样的</strong>,但实际上负样
|
||||
|
||||
[(什么?你看到这了还不会交叉熵?戳这里)](https://zhuanlan.zhihu.com/p/149186719)
|
||||
|
||||

|
||||

|
||||
|
||||
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>,退化为二分类的 NCEloss;T 越小,损失函数就<strong>越关注一些难分类的特征</strong>,但有时候会出现两张其实都是猫猫的图片,你硬要让模型说猫猫跟猫猫不一样,这也不太好,这个参数要根据数据集情况适中调整。
|
||||
T 越大,损失函数就越对所有负样本**一视同仁**,退化为二分类的 NCEloss;T 越小,损失函数就**越关注一些难分类的特征**,但有时候会出现两张其实都是猫猫的图片,你硬要让模型说猫猫跟猫猫不一样,这也不太好,这个参数要根据数据集情况适中调整。
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
上面那张是 T 较大的情况,下面是 T 较小的情况(x 轴是各个类别,y 轴是分类得分)
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
x 是输入的图片,它经过两种不同的数据增强得到 xi 和 xj 两个正样本,而同一个 mini-batch 里的所有其他样本都作为负样本。<del>说白了还是个体判别任务</del>
|
||||
|
||||

|
||||

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

|
||||

|
||||
|
||||
# 总结
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# 前言
|
||||
|
||||
与前面的一些工作不同,SwAV<strong>不再进行个体判别任务</strong>,而是提出了新的任务————<strong>聚类</strong>
|
||||
与前面的一些工作不同,SwAV**不再进行个体判别任务**,而是提出了新的任务————**聚类**
|
||||
|
||||
并在训练的模型结构上也做了相应改动,而非只调整训练方法。
|
||||
|
||||
@@ -20,39 +20,39 @@
|
||||
|
||||
下图左边是常规的对比学习(比如 SimCLR)的结构,右图是 SWAV 的结构,不难看出多了一个叫 prototypes 的东西。这个东西其实是聚类中心向量所构成的矩阵。
|
||||
|
||||

|
||||

|
||||
|
||||
下面的内容可能有些理解上的难度(反正我第一次听讲解的时候就云里雾里的),我会尽可能直白地描述这个过程。
|
||||
|
||||
## 聚类中心?
|
||||
|
||||
首先我们有个新的东西<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。当 z1,z2 都是正样本时,我希望<strong>Q1 与 z2 相近</strong>,<strong>Q2 与 z1 相近</strong>。如果有一个是负样本则尽可能远离。也就是拿 Q 当 ground-truth 做训练。最后这步前面已经讲过 NCEloss 等损失函数了,用它们就可以达成这个任务。
|
||||
首先我们手里有抽取出来的特征**z1**,**z2**,以及一个我随机初始化的**聚类中心矩阵 c**。我分别求这个**矩阵**和**z1**,**z2**的内积,并**进行一些变换**得到 Q1,Q2。当 z1,z2 都是正样本时,我希望**Q1 与 z2 相近**,**Q2 与 z1 相近**。如果有一个是负样本则尽可能远离。也就是拿 Q 当 ground-truth 做训练。最后这步前面已经讲过 NCEloss 等损失函数了,用它们就可以达成这个任务。
|
||||
|
||||
而我们的优化要采用 [K-means](https://zhuanlan.zhihu.com/p/78798251)(不懂可以看这里)的类似做法,先对聚类中心进行优化,再对特征进行优化。
|
||||
|
||||

|
||||

|
||||
|
||||
so,why?相信你现在肯定是一脸懵,不过别急,希望我能为你讲懂。
|
||||
|
||||
## 首先是第一步,为什么要求内积?
|
||||
|
||||
如果你有好好了解线性代数的几何性质,应当了解<strong>两个向量的内积就是一个向量在另一个向量上的投影</strong>,而一个向量与一个矩阵的内积,<strong>就是把这个向量投影到这个矩阵代表的基空间中</strong>。
|
||||
如果你有好好了解线性代数的几何性质,应当了解**两个向量的内积就是一个向量在另一个向量上的投影**,而一个向量与一个矩阵的内积,**就是把这个向量投影到这个矩阵代表的基空间中**。
|
||||
|
||||
我做的第一步就是把<strong>抽出来的特征 z 用聚类中心的向量表示,这样更加方便对比聚类成功与否</strong>。
|
||||
我做的第一步就是把**抽出来的特征 z 用聚类中心的向量表示,这样更加方便对比聚类成功与否**。
|
||||
|
||||
## 然后是第二步,我说的变换是什么呢?
|
||||
|
||||
我们现在求内积是为了把特征投影到聚类中心空间,为了避免模型训练坍塌(就是网络把特征全部聚到同一个点,<del>开摆~</del>)我要保证每个聚类中心被<strong>"使用"</strong>的次数,所以我们请出了<strong>Sinkhorn-Knopp 算法。</strong>这个算法比较硬核,我在这里不展开了,大家知道它是干啥的就行,具体的推导可以看我后面贴的视频,那里面有讲。
|
||||
我们现在求内积是为了把特征投影到聚类中心空间,为了避免模型训练坍塌(就是网络把特征全部聚到同一个点,<del>开摆~</del>)我要保证每个聚类中心被**"使用"**的次数,所以我们请出了**Sinkhorn-Knopp 算法。**这个算法比较硬核,我在这里不展开了,大家知道它是干啥的就行,具体的推导可以看我后面贴的视频,那里面有讲。
|
||||
|
||||
## 第三步应该不用怎么讲了吧?
|
||||
|
||||
@@ -64,7 +64,7 @@ so,why?相信你现在肯定是一脸懵,不过别急,希望我能为你
|
||||
|
||||
# 总结
|
||||
|
||||
主要贡献是上面我说的三步聚类算法以及后面的小 trick,<strong>Sinkhorn-Knopp 算法难度较高,大家有兴趣的话自行观看后面这个视频理解哈~</strong>
|
||||
主要贡献是上面我说的三步聚类算法以及后面的小 trick,**Sinkhorn-Knopp 算法难度较高,大家有兴趣的话自行观看后面这个视频理解哈~**
|
||||
|
||||
# 相关资料
|
||||
|
||||
|
||||
@@ -2,25 +2,25 @@
|
||||
|
||||
# 前言
|
||||
|
||||
这篇论文的主要特点是<strong>它的训练不需要负样本</strong>,并且能保证<strong>模型不坍塌</strong>。
|
||||
这篇论文的主要特点是**它的训练不需要负样本**,并且能保证**模型不坍塌**。
|
||||
|
||||
当一个普通的对比学习模型没有负样本时,它的损失函数就<strong>只有正样本之间的差距</strong>,这样模型只会学到一个<strong>捷径解</strong>————你给我什么输入我都输出同一个值,这样 loss 就永远=0 了(<del>开摆</del>)
|
||||
当一个普通的对比学习模型没有负样本时,它的损失函数就**只有正样本之间的差距**,这样模型只会学到一个**捷径解**————你给我什么输入我都输出同一个值,这样 loss 就永远=0 了(~~开摆~~)
|
||||
|
||||
而<strong>BYOL</strong>就解决了这一问题,使得训练不再需要负样本。
|
||||
而**BYOL**就解决了这一问题,使得训练不再需要负样本。
|
||||
|
||||
# 模型结构
|
||||
|
||||
前半部分很普通,跟 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 层**。它的任务是**通过紫色的特征去预测粉色的特征**。也就是说它的代理任务换成了**生成式**。
|
||||
|
||||

|
||||

|
||||
|
||||
而具体的损失只有预测特征和真实特征的损失,用的是<strong>MSEloss</strong>。
|
||||
而具体的损失只有预测特征和真实特征的损失,用的是**MSEloss**。
|
||||
|
||||
下面的粉色分支最后一步是不进行梯度回传的。它的更新完全依赖紫色的那个编码器。
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
### 有篇博客在复现 BYOL 时,不小心没加这个 BN 层,导致模型直接摆烂。那么 BN 到底藏着什么呢?
|
||||
|
||||

|
||||

|
||||
|
||||
我们得先来回顾一下 BN 做了什么。
|
||||
|
||||
@@ -42,29 +42,29 @@ BN 根据批次的均值和方差进行归一化
|
||||
|
||||
推理时,均值、方差是基于所有批次的期望计算所得。
|
||||
|
||||
因此,博客作者认为,虽然我们只用了正样本进行训练,但是这个正样本包含了<strong>本批次所有样本的信息</strong>(均值,方差),所以<strong>实际上并不是真正的无负样本。</strong>
|
||||
因此,博客作者认为,虽然我们只用了正样本进行训练,但是这个正样本包含了**本批次所有样本的信息**(均值,方差),所以**实际上并不是真正的无负样本。**
|
||||
|
||||
而这个 batch 的均值,即平均图片,可以看作 `SawAV` 里的聚类中心,是所有历史样本的聚类中心。(<del>很玄学</del>)
|
||||
|
||||
### 作者看到这个博客就急了
|
||||
|
||||
如果真是这样的话,<strong>BYOL 就还是没有逃脱出对比学习的范畴</strong>,它还是找了一个东西去做对比,其创新性就大大降低了。所以作者赶紧做实验,看看能不能找到 BYOL 模型不坍塌的另外一种解释。最终又写了一篇论文进行回应。
|
||||
如果真是这样的话,**BYOL 就还是没有逃脱出对比学习的范畴**,它还是找了一个东西去做对比,其创新性就大大降低了。所以作者赶紧做实验,看看能不能找到 BYOL 模型不坍塌的另外一种解释。最终又写了一篇论文进行回应。
|
||||
|
||||
这篇论文叫 BYOL works even without batch statistics,即在没有 BN 的时候 BYOL 照样能工作,详细的消融实验结果如下表所示 :
|
||||
|
||||

|
||||

|
||||
|
||||
<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>完全没有 BN,SimCLR 也坍塌</strong>(最后三列的结果。要注意 SimCLR 只有一层 projector)。这表明完全不用归一化,SimCLR 这种使用负样本进行对比学习的方式也无法训练。
|
||||
**完全没有 BN,SimCLR 也坍塌**(最后三列的结果。要注意 SimCLR 只有一层 projector)。这表明完全不用归一化,SimCLR 这种使用负样本进行对比学习的方式也无法训练。
|
||||
|
||||
最终结论:BN 跟它原来的设计初衷一样,主要作用就是提高模型训练时的稳定性,从而不会导致模型坍塌 。作者进一步延伸,如果一开始就能让模型初始化的比较好,后面的训练即使离开了 BN 也没有问题。
|
||||
|
||||
作者为此又设计了一个实验,使用 `group norm`+`weight standardization` (前者也是一种归一化方式,后者是一种卷积权重标准化方式,但都没有对 batch 中的数据进行融合),BYOL 的 top-准确率可以达到 74.1%,和原来精度可以认为是一样了(74.3%)。
|
||||
|
||||
<strong>至今其实这个问题也没有一个很合理能服众的解释。</strong>
|
||||
**至今其实这个问题也没有一个很合理能服众的解释。**
|
||||
|
||||
# 总结
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ BYOL 之后,大家都发现对比学习是靠许许多多的小 trick 和技
|
||||
|
||||
虽然看起来只有左边预测右边,其实右边也有一个 predictor 去预测左边的特征,两边是对称的,左右的优化有先后顺序。
|
||||
|
||||

|
||||

|
||||
|
||||
结构其实没什么特殊的地方,主要讲讲思想。
|
||||
|
||||
@@ -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。(模型坍塌)具体的推导需要动力学的知识,这里不做展开。
|
||||
|
||||
@@ -44,16 +44,15 @@ BYOL 之后,大家都发现对比学习是靠许许多多的小 trick 和技
|
||||
|
||||
这是作者总结的所有”孪生网络“的模型结构,很精炼。
|
||||
|
||||

|
||||

|
||||
|
||||
下面是这些网络训练结果的对比,也列出了它们分别有哪些 trick(用的是分类任务)
|
||||
|
||||
```
|
||||
负样本 动量编码器 训练轮数
|
||||
```
|
||||
负样本 动量编码器 训练轮数
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
具体结果还是图片比较直观(
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -10,7 +10,7 @@ MoCo v3,它缝合了 MoCo 和 SimSiam,以及新的骨干网络 VIT。
|
||||
|
||||
可能因为和前面的工作太像了,作者就没有给模型总览图,我们借 MoCo 的总览图来讲
|
||||
|
||||

|
||||

|
||||
|
||||
总体架构其实没有太多变化,还是 memory bank 的结构,右边也还是动量编码器,不过加入了 SimCLR 提出的 projection head(就是额外的那层 mlp),并且在对比上用了 SimSiam 的预测头对称学习方式。具体也不展开了,都是老东西缝合在一起。
|
||||
|
||||
@@ -18,11 +18,11 @@ MoCo v3,它缝合了 MoCo 和 SimSiam,以及新的骨干网络 VIT。
|
||||
|
||||
作者在用 VIT 做骨干网络训练的时候,发现如下问题:
|
||||
|
||||

|
||||

|
||||
|
||||
在使用 VIT 训练的时候,batchsize 不算太大时训练很平滑,但是一旦 batchsize 变大,训练的图像就会出现如上图这样的<strong>波动</strong>。于是作者去查看了每一层的梯度,发现问题出在<strong>VIT 的第一层线性变换</strong>上。也就是下图中的粉色那个层,<strong>把图片打成 patch 后展平做的线性变换</strong>。
|
||||
在使用 VIT 训练的时候,batchsize 不算太大时训练很平滑,但是一旦 batchsize 变大,训练的图像就会出现如上图这样的**波动**。于是作者去查看了每一层的梯度,发现问题出在**VIT 的第一层线性变换**上。也就是下图中的粉色那个层,**把图片打成 patch 后展平做的线性变换**。
|
||||
|
||||

|
||||

|
||||
|
||||
在这一层中,梯度会出现波峰,而正确率则会突然下跌。
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
|
||||
## 强化学习的基本过程
|
||||
前面已经介绍过强化学习的核心过程,在于智能体与环境进行交互,通过给出的奖励反馈作为信号学习的过程。简单地用图片表示如下:
|
||||

|
||||

|
||||
正是在这个与环境的交互过程中,智能体不断得到反馈,目标就是尽可能地让环境反馈的奖励足够大。
|
||||
|
||||
## 强化学习过程的基本组成内容
|
||||
为了便于理解,我们引入任天堂经典游戏——[新超级马里奥兄弟U](https://www.nintendoswitch.com.cn/new_super_mario_bros_u_deluxe/pc/index.html),作为辅助理解的帮手。作为一个2D横向的闯关游戏,它的状态空间和动作空间无疑是简单的。
|
||||
|
||||

|
||||

|
||||
|
||||
1.智能体(Agent):它与环境交互,可以观察到环境并且做出决策,然后反馈给环境。在马里奥游戏中,能操控的这个马里奥本体就是智能体。
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
5.策略(Policy):智能体采取动作的规则,分为**确定性策略**与**随机性策略**。确定性策略代表在相同的状态下,智能体所输出的动作是唯一的。而随机性策略哪怕是在相同的状态下,输出的动作也有可能不一样。这么说有点过于抽象了,那么请思考这个问题:在下面这张图的环境中,如果执行确定性策略会发生什么?(提示:着重关注两个灰色的格子)
|
||||
|
||||

|
||||

|
||||
|
||||
因此,在强化学习中我们一般使用随机性策略。随机性策略通过引入一定的随机性,使环境能够被更好地探索。同时,如果策略固定——你的对手很容易能预测你的下一步动作并予以反击,这在博弈中是致命的。
|
||||
随机性策略$\pi$定义如下:
|
||||
|
||||
@@ -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/)。其基本思路是这样的,通过”样本距离度量“刻画获取样本之间的联系,将样本嵌入到“图”,即样本即其关系的集合中。后通过图将半监督学习中有标记样本的标签对未标记样本进行传递,从而获取未标记样本的属性,进行学习。
|
||||
|
||||
如此,便定下来图网络的基本思路,即通过<em>信息在图上的传递</em>,迭代学习知识。有了这样的基础,我们便可以开始对图网络进行讨论了。
|
||||
如此,便定下来图网络的基本思路,即通过*信息在图上的传递*,迭代学习知识。有了这样的基础,我们便可以开始对图网络进行讨论了。
|
||||
|
||||
接下来,我们从最基础的部分来讲讲,信息是如何在图上进行传播的。
|
||||
|
||||
@@ -55,7 +55,7 @@ $$
|
||||
|
||||
现在,我们可以尝试用$\mathbf{L}$对图进行表示了。
|
||||
|
||||
另外还有个<em>随机游走归一化拉普拉斯矩阵</em>
|
||||
另外还有个*随机游走归一化拉普拉斯矩阵*
|
||||
$$
|
||||
\mathbf{L}^{sym}=\mathbf{D}^{-1}\mathbf{L}=\mathbf{I}-\mathbf{D}^{-1}\mathbf{A}
|
||||
$$
|
||||
@@ -81,7 +81,7 @@ $
|
||||
|
||||
## ChebNet 及其思考
|
||||
|
||||
ChebNet 的引入是当今神经网络大热门的开端,也是图卷积网络的基础。其思路为,使用切比雪夫多项式对卷积过程 K 阶拟合([参考](https://zhuanlan.zhihu.com/p/138420723))
|
||||
ChebNet 的引入是当今神经网络大热门的开端,也是图卷积网络的基础。其思路为,使用切比雪夫多项式对卷积过程 K 阶拟合 ([参考](https://zhuanlan.zhihu.com/p/138420723))
|
||||
|
||||
ChebNet 假设$g\theta$对$\Lambda$的滤波结果是原始特征值多项式函数,而网络的目的是抛弃原本通过矩阵相乘来对卷积结果进行求解,而通过参数学习来对结果进行表示,给出下式
|
||||
|
||||
@@ -96,7 +96,7 @@ $$
|
||||
其中有切比雪夫多项式在矩阵上的表示,具体数学背景可以详细查看
|
||||
|
||||
$$
|
||||
T_0(L) = I\ T_1(L)=L\ T_{n+1}(L)=2LT_n(L) - T_{n-1}(L)
|
||||
T_0(L) = I\ T_1(L)=L\ T_{n+1}(L)=2LT_n(L) - T_{n-1}(L)
|
||||
$$
|
||||
|
||||
有$\beta_k$为网络的待学习参数
|
||||
@@ -114,9 +114,7 @@ $$
|
||||
\mathbf{U}^\mathsf{T}x
|
||||
\end{matrix}
|
||||
$$
|
||||
|
||||
,并对其中无关输入信号 $x$ 的部分进行改写
|
||||
|
||||
并对其中无关输入信号 $x$ 的部分进行改写
|
||||
|
||||
$$
|
||||
\mathbf{U}\begin{matrix}\sum_{k=0}^K
|
||||
@@ -163,7 +161,6 @@ x
|
||||
\end{matrix}
|
||||
$$
|
||||
|
||||
|
||||
作为 ChebNet 的卷积结构
|
||||
|
||||
其中值得注意的一点是,ChebNet 的 K 值限制了卷积核的多项式次数,但是这里的多项式次数描述了什么呢?其实就是卷积的“范围”,即单次卷积内最高可获得的 K 阶相邻节点信息。在 K=n 的时候,我们从理论上可以通过单次卷积,获取一张连通图上所有结点的信息,而这也是原方法难以计算的根本原因。
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
# 数据科学
|
||||
|
||||
author:zzm
|
||||
# 本章内容会从一个小故事开始
|
||||
|
||||
## 本章内容会从一个小故事开始
|
||||
|
||||
讲讲某个人在大一的悲惨经历来为大家串起来一个精简的数据科学工作包括了哪些步骤,同时给各位介绍一些优质的教程
|
||||
|
||||
同时,这章内容将详细阐述[与人合作的生死疲劳](https://www.bilibili.com/video/BV1494y1o7jp/?spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=2cb6252f9211ae9d29cf1f76f0aea8d7)
|
||||
|
||||
# 悲惨世界
|
||||
同时,这章内容将详细阐述[与人合作的生死疲劳](../1.杭电生存指南/1.5小组作业避雷指南.md)
|
||||
|
||||
## 悲惨世界
|
||||
|
||||
::: danger 若有雷同,纯属瞎编~~根据真实事件改编
|
||||
|
||||
@@ -16,45 +17,50 @@ author:zzm
|
||||
请欣赏小故事的同时,根据自己的需求选择自己想学的教程
|
||||
|
||||
:::
|
||||
## Day1
|
||||
|
||||
### Day1
|
||||
|
||||
你是一个可怜的大一学生,学校的短学期的第一天,你的心情非常好,因为要放寒假了,只要再坚持过这个短学期,你的快乐假期要来了!什么是短学期?不知道啊,也没听学长说过,好像是新研究出来的一个课程,去试试看吧。
|
||||
|
||||
当你快乐的走进教室,老师告诉你:“你们看看PPT上的任务,自由选择啊!”
|
||||
当你快乐的走进教室,老师告诉你:“你们看看 PPT 上的任务,自由选择啊!”
|
||||
|
||||
你看到PPT上赫然印着
|
||||
你看到 PPT 上赫然印着
|
||||
::: tip 任务目标
|
||||
基础系统:
|
||||
基础系统:
|
||||
|
||||
1. 淘宝客户价值分析系统,实现爬取数据,数据处理,数据分析。
|
||||
2. 二手房数据分析预测系统,实现爬取数据,数据分析,绘制图表。
|
||||
3. 智能停车场运营分析系统,实现爬取数据,数据分析,绘制图表。
|
||||
4. 影视作品分析系统,实现爬取数据,数据分析,绘制图表。
|
||||
升级系统:
|
||||
|
||||
升级系统:
|
||||
|
||||
1. 利用爬虫理论,实现 12306 抢票小助手系统。
|
||||
2. 利用数据分析方法,实现淘宝商品排行分析。
|
||||
3. 利用爬虫原理,爬 Google 搜索引擎分析。”
|
||||
要求实现三项以上的功能模块或三种以上的特征分析或提取。
|
||||
|
||||
:::
|
||||
|
||||
心中一惊,暗道不妙,这都什么玩意,怎么还有爬谷歌,淘宝和抢12306的票啊,这tm不是犯法的么!这我要能做出来我还上什么大一的学啊!🥺🥺🥺🥺
|
||||
心中一惊,暗道不妙,这都什么玩意,怎么还有爬谷歌,淘宝和抢 12306 的票啊,这 tm 不是犯法的么!这我要能做出来我还上什么大一的学啊!🥺🥺🥺🥺
|
||||
|
||||
老师紧接着补充“十个人一组啊!一周内做完,数据自己想办法,第三天就要检查你们的进度了!”
|
||||
|
||||
这是你倒是暗暗松了一口气,好像十个人一起干也没有那么复杂!😎(这时正是愚昧之峰,错误的认为工作总量就是工作量除以十)迅速的组好队之后,你问了问大伙的进度,what?大伙都没有python基础,只有我有?幸好学了hdu-wiki和datawhale的[聪明方法学python](https://github.com/datawhalechina/learn-python-the-smart-way)
|
||||
这是你倒是暗暗松了一口气,好像十个人一起干也没有那么复杂!😎(这时正是愚昧之峰,错误的认为工作总量就是工作量除以十)迅速的组好队之后,你问了问大伙的进度,what?大伙都没有 python 基础,只有我有?幸好学了 hdu-wiki 和 datawhale 的[聪明方法学 python](https://github.com/datawhalechina/learn-python-the-smart-way)
|
||||
|
||||
那就把教程分给大伙吧,我们选一个最简单的,二手房数据的分析系统好了!
|
||||
|
||||
第一天选好题了,又是大下午的,摆了摆了,你开心的打开电脑,打开了steam,开摆!
|
||||
第一天选好题了,又是大下午的,摆了摆了,你开心的打开电脑,打开了 steam,开摆!
|
||||
|
||||
day 1 End!🤣
|
||||
|
||||
## Day 2
|
||||
### Day 2
|
||||
|
||||
昨天真是美滋滋的一天,玩了一晚上的你有点头昏脑涨,今天就开始干活好了,反正一周时间呢,比期末复习周可长太多了,就做这么个玩意我还能做不出来吗?
|
||||
|
||||
虽然你没有学过爬虫,但是你很幸运的找到了github上一个现成的爬虫代码,虽然费了一翻力气,但是仍然躲过了某房价网站的爬虫,他成功爬下来了,我们就把他存在哪里呢?~~(爬虫待补充)
|
||||
虽然你没有学过爬虫,但是你很幸运的找到了 github 上一个现成的爬虫代码,虽然费了一翻力气,但是仍然躲过了某房价网站的爬虫,他成功爬下来了,我们就把他存在哪里呢?~~(爬虫待补充)
|
||||
|
||||
先试试excel好了,毕竟这是大家最耳熟能详的存表格的方法,但是你貌似没有深入了解过他,打开了datawhale的[free-excel](https://github.com/datawhalechina/free-excel),你才惊讶的发现,wow,原来他有这么多牛逼的功能啊!它除了可以将房价统计,找到它的平均价格,算出他的最高价格之类以外,竟然也可以把他可视化!甚至它还可以对房价进行多元分析!根据房屋数量面积地段等等因素帮你预测房价,甚至可以自动帮你检索和去除重复数据,实在是太好用啦!
|
||||
先试试 excel 好了,毕竟这是大家最耳熟能详的存表格的方法,但是你貌似没有深入了解过他,打开了 datawhale 的[free-excel](https://github.com/datawhalechina/free-excel),你才惊讶的发现,wow,原来他有这么多牛逼的功能啊!它除了可以将房价统计,找到它的平均价格,算出他的最高价格之类以外,竟然也可以把他可视化!甚至它还可以对房价进行多元分析!根据房屋数量面积地段等等因素帮你预测房价,甚至可以自动帮你检索和去除重复数据,实在是太好用啦!
|
||||
|
||||
当然,这只是一个理想状态,残酷的现实很快给你当头一棒!当你试着多爬点不同城市数据的时候,他崩了!这么脆弱的吗?!干点活就喊累的吗?!😨
|
||||
|
||||
@@ -62,22 +68,22 @@ day 1 End!🤣
|
||||
|
||||
之前好像看到有一个教程叫做[wonderful-sql](https://github.com/datawhalechina/wonderful-sql?from=from_parent_mindnote)
|
||||
|
||||
他提到“随着社会的快速发展,各类企业数字化转型迫在眉睫,SQL 应用能力日趋重要。 在诸多领域中 SQL 应用广泛,数据分析、开发、测试、维护、产品经理等都有可能会用到SQL,而在学校里系统性讲授 SQL 的课程较少,但是面试及日常工作中却经常会涉及到 SQL。”
|
||||
他提到“随着社会的快速发展,各类企业数字化转型迫在眉睫,SQL 应用能力日趋重要。在诸多领域中 SQL 应用广泛,数据分析、开发、测试、维护、产品经理等都有可能会用到 SQL,而在学校里系统性讲授 SQL 的课程较少,但是面试及日常工作中却经常会涉及到 SQL。”
|
||||
|
||||
确实学校没有教过,但是幸好你有教程,折腾了一翻之后,你发现你对数据库有了更深的理解,他帮助了我们在容纳大量的多种不同的数据形式的时候不用专门去考虑怎么设计一个数据结构而是规划了一定的存储方法后全部塞给他,完全不用考虑具体的物理性的以及性能问题存储模式,并且他很多高级的功能可以帮助你便捷的把数据组织成一般情况下难以到达的形式,他的底层设计被严格的包装起来让你在进行数据增删改查的时候都又快又好。
|
||||
|
||||
并且它可以非常方便的存一些excel不好存的所谓的非结构化的数据,比如说图像等等,并且他不会动不动就喊累!处理几十万条也是一下子!
|
||||
并且它可以非常方便的存一些 excel 不好存的所谓的非结构化的数据,比如说图像等等,并且他不会动不动就喊累!处理几十万条也是一下子!
|
||||
|
||||
当然同时你也了解到,你所用的是关系型数据库,是老东西了,目前还有很多较为前沿的非关系型数据库,例如MongoDB(这玩意什么都能存,比如说地图),Neo4j(像一张蜘蛛网一样的结构,图)等等,他们不用固定的表来存储,可以用图存或者键值对进行存储,听起来好像非常的高级,不过你暂时用不到,数据搞都搞下来了,量也够了,是时候看看队友做到哪了?说不定后面你都不用做了,已经做的够多够累的了!
|
||||
当然同时你也了解到,你所用的是关系型数据库,是老东西了,目前还有很多较为前沿的非关系型数据库,例如 MongoDB(这玩意什么都能存,比如说地图),Neo4j(像一张蜘蛛网一样的结构,图)等等,他们不用固定的表来存储,可以用图存或者键值对进行存储,听起来好像非常的高级,不过你暂时用不到,数据搞都搞下来了,量也够了,是时候看看队友做到哪了?说不定后面你都不用做了,已经做的够多够累的了!
|
||||
|
||||
什么?!刚开始学python?!woc!完蛋,你逐渐来到了绝望之谷,唉!明天继续做吧!看来休息不了了。
|
||||
什么?!刚开始学 python?!woc! 完蛋,你逐渐来到了绝望之谷,唉!明天继续做吧!看来休息不了了。
|
||||
day 2 End 😔!
|
||||
|
||||
## Day 3
|
||||
### Day 3
|
||||
|
||||
God!No!昨天已经够累的了,今天老师还要讲课,还要早起!你期待着老师可以降低要求,可是当老师托起长音,讲起了他知道了学生的累,所以今天决定开始讲课了!(现在讲有毛用啊,你明天就要验收我们的进度了!)
|
||||
God!No! 昨天已经够累的了,今天老师还要讲课,还要早起!你期待着老师可以降低要求,可是当老师托起长音,讲起了他知道了学生的累,所以今天决定开始讲课了!(现在讲有毛用啊,你明天就要验收我们的进度了!)
|
||||
|
||||
而他却慢悠悠的开始讲python的历史,把这点内容讲了足足两节课,你终于绷不住了,本来时间就不够,他竟然又浪费了你足足一早上的时间!这也太该死了!🤬
|
||||
而他却慢悠悠的开始讲 python 的历史,把这点内容讲了足足两节课,你终于绷不住了,本来时间就不够,他竟然又浪费了你足足一早上的时间!这也太该死了!🤬
|
||||
|
||||
你回到了寝室,准备今天争取数据分析完就直接交上去好了!
|
||||
|
||||
@@ -85,23 +91,25 @@ God!No!昨天已经够累的了,今天老师还要讲课,还要早起!你
|
||||
|
||||
这个野鸡房价网站每个城市的排版不一样,你爬虫爬取的完全是按照顺序标的,也就是说你爬取的所有房价信息处于混沌状态!完全就相当于给每个房子爬了一段句子的描述!
|
||||
|
||||
没有办法了,看来今天有的折腾了,你找到了一个叫pandas(熊猫?)的东西,找到了这个教程[Joyful-Pandas](https://github.com/datawhalechina/joyful-pandas),开始了一天的学习!
|
||||
没有办法了,看来今天有的折腾了,你找到了一个叫 pandas(熊猫?)的东西,找到了这个教程[Joyful-Pandas](https://github.com/datawhalechina/joyful-pandas),开始了一天的学习!
|
||||
|
||||
你了解到pandas是一个开源的Python数据处理库,提供了高性能、易用、灵活和丰富的数据结构,可以帮助用户轻松地完成数据处理、清洗、分析和建模等任务。你使用了DataFrame来装载二维表格对象。
|
||||
你了解到 pandas 是一个开源的 Python 数据处理库,提供了高性能、易用、灵活和丰富的数据结构,可以帮助用户轻松地完成数据处理、清洗、分析和建模等任务。你使用了 DataFrame 来装载二维表格对象。
|
||||
|
||||
用一些关键词来提取数据中隐藏的信息,例如提取“平米”前面的数字放到‘area'列,提取房价到'price’列,提取位置到'locate'里面,当然你也遇到了可怕的bug,提取所有“室”和“厅”前面的数字,他总是告诉你有bug,全部输出之后才发现你提取到了“地下室”结果他没法识别到数字所以炸了!
|
||||
用一些关键词来提取数据中隐藏的信息,例如提取“平米”前面的数字放到‘area'列,提取房价到'price’列,提取位置到'locate'里面,当然你也遇到了可怕的 bug,提取所有“室”和“厅”前面的数字,他总是告诉你有 bug,全部输出之后才发现你提取到了“地下室”结果他没法识别到数字所以炸了!
|
||||
|
||||
将数据勉强弄得有序之后,你提取了平均数填充到缺失数据的房屋里面,将一些处理不了的删掉。
|
||||
|
||||
当然,你也额外了解到pandas这只可爱的小熊猫还有非常多强大的功能,例如数据可视化,例如分类数据,甚至可以让房屋按照时序排列,但是你实在不想动了!
|
||||
当然,你也额外了解到 pandas 这只可爱的小熊猫还有非常多强大的功能,例如数据可视化,例如分类数据,甚至可以让房屋按照时序排列,但是你实在不想动了!
|
||||
|
||||
不论怎么说,你勉强有了一份看得过去的数据,你看了看表,已经晚上十一点半了,今天实在是身心俱疲!
|
||||
|
||||
问问队友吧,什么,他们怎么还是在python语法?!你就像进了米奇不妙屋~队友在想你说“嘿~你呀瞅什么呢~是我!你爹~”
|
||||
问问队友吧,什么,他们怎么还是在 python 语法?!你就像进了米奇不妙屋~队友在说
|
||||
|
||||
此时你像一头挨了锤的老驴,曾经的你有好多奢望,你想要GPA,想要老师的认同,甚至想要摸一摸水里忽明忽暗的🐟,可是一切都随着你的hadworking变成了泡影。
|
||||
~~“嘿~你呀瞅什么呢~是我!你爹~”~~
|
||||
|
||||
可是步步逼近的截止日期不允许你有太多的emo期,说好的七天时间,最后一天就剩下展示了!也就是说实际上只有6天的开发时间,也就是说你必须得挑起大梁了
|
||||
此时你像一头挨了锤的老驴,曾经的你有好多奢望,你想要 GPA,想要老师的认同,甚至想要摸一摸水里忽明忽暗的🐠,可是一切都随着你的 hardworking 变成了泡影。
|
||||
|
||||
可是步步逼近的截止日期不允许你有太多的 emo 时间,说好的七天时间,最后一天就剩下展示了!也就是说实际上只有 6 天的开发时间,也就是说你必须得挑起大梁了
|
||||
|
||||
> 世界上只有一种真正的英雄主义,那就是看清生活的真相之后,依然热爱生活
|
||||
|
||||
@@ -109,19 +117,19 @@ God!No!昨天已经够累的了,今天老师还要讲课,还要早起!你
|
||||
|
||||
day 3 end!👿 👹 👺 🤡
|
||||
|
||||
## Day 4
|
||||
### Day 4
|
||||
|
||||
老师在验收的时候认为你什么工作也没做,他认为一份数据实在是太单薄了,特别是被你疯狂结构优化后的数据已经没几个特征了,让你去做点看得到的东西,不然就要让你不及格了,你的心里很难过,你想到也许你需要一些更好看的东西。数据可视化你在昨天的pandas看到过,可是你并没有详细了解,你觉得pandas已经在昨天把你狠狠的暴捶一顿了,并且老师想要更好看的图。
|
||||
老师在验收的时候认为你什么工作也没做,他认为一份数据实在是太单薄了,特别是被你疯狂结构优化后的数据已经没几个特征了,让你去做点看得到的东西,不然就要让你不及格了,你的心里很难过,你想到也许你需要一些更好看的东西。数据可视化你在昨天的 pandas 看到过,可是你并没有详细了解,你觉得 pandas 已经在昨天把你狠狠的暴捶一顿了,并且老师想要更好看的图。
|
||||
|
||||
于是你考虑pandas配合Matplotlib画一些简单的图(Matplotlib的缺点是它的绘图语法比较繁琐,需要编写较多的代码才能得到漂亮的图形。)
|
||||
于是你考虑 pandas 配合 Matplotlib 画一些简单的图(Matplotlib 的缺点是它的绘图语法比较繁琐,需要编写较多的代码才能得到漂亮的图形。)
|
||||
|
||||
加上Plotly绘制一些复杂的图,让你的图有着更漂亮的交互效果,然后加上看起来很牛逼的英语描述
|
||||
加上 Plotly 绘制一些复杂的图,让你的图有着更漂亮的交互效果,然后加上看起来很牛逼的英语描述
|
||||
|
||||
你找到了下面的教程:
|
||||
|
||||
你找到了下面的教程
|
||||
[matplotlib奇遇记文字教程](https://github.com/datawhalechina/fantastic-matplotlib)
|
||||
[matplotlib 奇遇记文字教程](https://github.com/datawhalechina/fantastic-matplotlib)
|
||||
|
||||
[极好的Plotly文字教程:](https://github.com/datawhalechina/wow-plotly)
|
||||
[极好的 Plotly 文字教程:](https://github.com/datawhalechina/wow-plotly)
|
||||
[视频教程](https://www.bilibili.com/video/BV1Df4y1A7aR)
|
||||
|
||||
🤗
|
||||
@@ -129,17 +137,17 @@ day 3 end!👿 👹 👺 🤡
|
||||
|
||||
这时你认为你的任务已经完成了!于是早早就心满意足的早早睡着了🍻 🥂。最近真的太累了,天天一两点睡,早上惊醒,做梦都是在爬数据分析数据!太可怕了!
|
||||
|
||||
在梦里,你好像看到了美好的假期时光。 😪
|
||||
在梦里,你好像看到了美好的假期时光。 😪
|
||||
|
||||
day 4 end!~🤤
|
||||
|
||||
## Day 5
|
||||
### Day 5
|
||||
|
||||
你睡得很死,因为你已经你做完了所有的东西,第二天只要美美的验收结束,买了机票就可以回家了,可是老师仍然制止了你,跟你说如果你今晚走了就给你挂科,因为你没有用机器学习来分析他!
|
||||
|
||||
可是机票今晚就要起飞了啊!😰你已经要气疯了,想和老师据理力争,但是又害怕这么一个课被打上不及格的分数,这实在是太难受了!
|
||||
|
||||
终归你还是在老师的逼迫下,改签了机票,好吧,多少得加点功能了!呜呜呜~🤢 🤮
|
||||
终归你还是在老师的逼迫下,改签了机票,好吧,多少得加点功能了!呜呜呜~🤢 🤮
|
||||
|
||||
可是你并不完全会机器学习的算法,可怜的大一本科生的你没有学信息论也没有学最优化理论,很多算法你完全不懂其理论知识!听说西瓜书很好,可是你在图书馆借到了西瓜书之后根本看不懂!
|
||||
|
||||
@@ -149,21 +157,21 @@ day 4 end!~🤤
|
||||
|
||||
你对着他啃了半天,觉得很多东西你都能看懂了,你脑子里已经有了很多思路,你想按使用高级的机器学习的算法!
|
||||
|
||||
但是!时间还是太紧张了!你没有办法从头开始实现了!
|
||||
但是!时间还是太紧张了!你没有办法从头开始实现了!
|
||||
|
||||
你想尝试[pytorch文字教程](https://github.com/datawhalechina/thorough-pytorch),但是时间也不够让你去重整数据去训练了。你随便塞在线性层里的数据梯度直接爆炸,你这时候还不知道归一化的重要性,紧张之下把几万几十万的房价往里面塞,结果结果烂成💩了,并且你没有波如蝉翼的基础知识并不够让你去解决这些个bug,只能疯狂的瞎挑参数,可是结果往往不如人意~
|
||||
你想尝试[pytorch 文字教程](https://github.com/datawhalechina/thorough-pytorch),但是时间也不够让你去重整数据去训练了。你随便塞在线性层里的数据梯度直接爆炸,你这时候还不知道归一化的重要性,紧张之下把几万几十万的房价往里面塞,结果结果烂成💩了,并且你那薄如蝉翼的基础知识并不够让你去解决这些个 bug,只能疯狂的瞎调参数,可是结果往往不如人意~
|
||||
|
||||
时间来到了晚上八点,明天就要最后验收了,走投无路的你把目光看向了远在几十千米外已经入职了的大哥,晚上跟他打电话哭诉你最近的遭遇,你实在搞不懂,为什么十二生肖大伙都属虎,就你属驴。
|
||||
|
||||
大哥嘎嘎猛,连夜打车过来,我在因疫情封校的最后两个小时赶出了学校,和大哥一起租了个酒店,通宵奋战,他采取了更多更为优雅的特征工程和模型调参的方式,让模型优雅的收敛到了一定程度,再用春秋笔法进行汇总,在半夜两点半,终于将内容搞定了
|
||||
大哥嘎嘎猛,连夜打车过来,你在因疫情封校的最后两个小时跑出了学校,和大哥一起租了个酒店,通宵奋战,他采取了更多更为优雅的特征工程和模型调参的方式,让模型优雅的收敛到了一定程度,再用春秋笔法进行汇总,在半夜两点半,终于将内容搞定了😭
|
||||
|
||||
终于你可以睡个好觉了~
|
||||
|
||||
day 5 end!😍 🥰 😘
|
||||
|
||||
## Day 6
|
||||
### Day 6
|
||||
|
||||
验收日,老师端坐在底下,宛如一尊大佛,提出了一系列无关紧要的问题,比如问我们能不能拿这个程序给老年人查资料???
|
||||
验收日,老师端坐在底下,宛如一尊大佛,提出了一系列无关紧要的问题,比如问“我们能不能拿这个程序给老年人查资料???”
|
||||
|
||||
等等问题和技术一点关系都没有!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
@@ -173,20 +181,19 @@ day 5 end!😍 🥰 😘
|
||||
|
||||
The End~~~~~~~~~~
|
||||
|
||||
# 事后总结
|
||||
## 事后总结
|
||||
|
||||
你在那个暑假详细了解和学习一下数据科学竞赛,发现他的含金量在职场领域有时候相当高,并且对提升自身的实力也有相当大的帮助!
|
||||
你在那个暑假详细了解和学习一下数据科学竞赛,发现他的含金量在职场领域有时候相当高,并且对提升自身的实力也有相当大的帮助!
|
||||
|
||||
[数据竞赛Baseline & Topline分享](https://github.com/datawhalechina/competition-baseline)
|
||||
[数据竞赛 Baseline & Topline 分享](https://github.com/datawhalechina/competition-baseline)
|
||||
|
||||
你还发现了之前从来没有注意到的kaggle平台以及一些很棒的综合实践项目!
|
||||
你还发现了之前从来没有注意到的 kaggle 平台以及一些很棒的综合实践项目!
|
||||
|
||||
例如[根据贷款申请人的数据信息预测其是否有违约的可能](https://github.com/datawhalechina/team-learning-data-mining/tree/master/FinancialRiskControl)
|
||||
|
||||
[根据汽车类型等信息预测二手汽车的交易价格](https://github.com/datawhalechina/team-learning-data-mining/tree/master/SecondHandCarPriceForecast)
|
||||
|
||||
例如:[使用公开的arXiv论文完成对应的数据分析操作](https://github.com/datawhalechina/team-learning-data-mining/tree/master/AcademicTrends)
|
||||
|
||||
例如:[使用公开的 arXiv 论文完成对应的数据分析操作](https://github.com/datawhalechina/team-learning-data-mining/tree/master/AcademicTrends)
|
||||
|
||||
想到如果你早做准备,没有荒废大一的时光,也许你不但能圆满的通过这次课程,也可以开辟更为广阔的新世界了吧~
|
||||
|
||||
@@ -196,31 +203,31 @@ The End~~~~~~~~~~
|
||||
|
||||
::: danger 再次警告,本章内容有很多瞎编的内容,不要全信
|
||||
|
||||
比如说一天学完pandas,一天学完sql之类的都是很不现实的!希望大家注意!
|
||||
比如说一天学完 pandas,一天学完 sql 之类的都是很不现实的!希望大家注意!
|
||||
|
||||
当然你也可以在需要用的时候再研究,也来得及,就是很累
|
||||
|
||||
不要打击到大家的自信心!
|
||||
:::
|
||||
|
||||
# 补充内容:下个定义
|
||||
## 补充内容:下个定义
|
||||
|
||||
数据分析是独立于开发和算法岗的另一个方向,它主要是通过<strong>应用</strong>机器学习和深度学习的<strong>已有算法</strong>来分析现实问题的一个方向
|
||||
数据分析是独立于开发和算法岗的另一个方向,它主要是通过**应用**机器学习和深度学习的**已有算法**来分析现实问题的一个方向
|
||||
|
||||
我们常说:数据是客观的,但是解读数据的人是主观的。
|
||||
|
||||
数据这门科学就像中西医混合的一门医学,既要有西医的理论、分析模型以及实验,又需要有中医的望闻问切这些个人经验。
|
||||
|
||||
|
||||
> 这世界缺的真不是算法和技术,而是能用算法、技术解决实际问题的人
|
||||
|
||||
|
||||
# 什么是数据科学
|
||||
## 什么是数据科学
|
||||
|
||||
数据科学是当今计算机和互联网领域最热门的话题之一。直到今天,人们已经从应用程序和系统中收集了相当大量的数据,现在是分析它们的时候了。从数据中产生建议并创建对未来的预测。[在这个网站中](https://www.quora.com/Data-Science/What-is-data-science),您可以找到对于数据科学的更为精确的定义。
|
||||
|
||||
同时,我向各位推荐一个非常有趣的科普视频想你讲解数据分析师到底在做什么:[怎么会有这么性感的职业吶?](https://www.bilibili.com/video/BV1ZW4y1x7UU/?spm_id_from=333.999.0.0&vd_source=2cb6252f9211ae9d29cf1f76f0aea8d7)
|
||||
同时,我向各位推荐一个非常有趣的科普视频想你讲解数据分析师到底在做什么:[怎么会有这么性感的职业吶?](https://www.bilibili.com/video/BV1ZW4y1x7UU)
|
||||
|
||||
# Datawhale的生态体系
|
||||
<Bilibili bvid='BV1ZW4y1x7UU'/>
|
||||
|
||||
在与Datawhale开源委员会的负责人文睿进行一翻畅谈之后。zzm受震惊于其理念以及已经构建的较为完善的体系架构,毅然决然的删除了本章和其广泛的体系比起来相形见绌的内容。为了更大伙更好的阅读以及学习体验,我们决定在本章内容引入了[datawhale人工智能培养方案数据分析体系](https://datawhale.feishu.cn/docs/doccn0AOicI3LJ8RwhY0cuDPSOc#),希望各位站在巨人的肩膀上,争取更进一步的去完善它。
|
||||
## Datawhale 的生态体系
|
||||
|
||||
在与 Datawhale 开源委员会的负责人文睿进行一翻畅谈之后。zzm 受震惊于其理念以及已经构建的较为完善的体系架构,毅然决然的删除了本章和其广泛的体系比起来相形见绌的内容。为了更大伙更好的阅读以及学习体验,我们决定在本章内容引入了[datawhale 人工智能培养方案数据分析体系](https://datawhale.feishu.cn/docs/doccn0AOicI3LJ8RwhY0cuDPSOc#),希望各位站在巨人的肩膀上,争取更进一步的去完善它。
|
||||
|
||||
@@ -1,28 +1,27 @@
|
||||
# 如何做研究
|
||||
|
||||
# 0. 讲在前面
|
||||
## 0. 讲在前面
|
||||
|
||||
Author: 任浩帆
|
||||
|
||||
Email: yqykrhf@163.commailto:yqykrhf@163.com
|
||||
Author:任浩帆
|
||||
|
||||
Email: yqykrhf@163.com
|
||||
术语介绍的补充:Spy
|
||||
|
||||
仅供参考,如有不足,不吝赐教。
|
||||
|
||||
# 术语的介绍
|
||||
## 术语的介绍
|
||||
|
||||
<strong>Benchmark:</strong>评测的基准。通常会是一些公开的数据集。
|
||||
**Benchmark:**评测的基准。通常会是一些公开的数据集。
|
||||
|
||||
<strong>Baseline:</strong> 基准,一般指的是一个现有的工作。
|
||||
**Baseline:** 基准,一般指的是一个现有的工作。
|
||||
|
||||
<strong>SOTA </strong>(state-of-art): 截止目前,指标最好。
|
||||
**SOTA **(state-of-art): 截止目前,指标最好。
|
||||
|
||||
举个例子:
|
||||
|
||||
我们选取 XXX-Net 作为我们的 Baseline,在加入我们设计的注意力机制的模块,在 KITTI 这个 Benchmark 上性能达到了 SOTA。
|
||||
|
||||
<strong>Backbone:</strong>
|
||||
**Backbone:**
|
||||
|
||||
这个单词原意指的是人的脊梁骨,后来引申为支柱,核心的意思。
|
||||
|
||||
@@ -30,13 +29,13 @@ Email: yqykrhf@163.commailto:yqykrhf@163.com
|
||||
|
||||
所以将这一部分网络结构称为 backbone 十分形象,仿佛是一个人站起来的支柱。
|
||||
|
||||
<strong>Solid</strong>
|
||||
**Solid**
|
||||
|
||||
一般是描述这个工作非常扎实。
|
||||
|
||||
这个工作很 solid。 每一步都 make sense(合理)。没有特意为了刷 benchmark 上的指标,用一些 fancy trick(奇技淫巧)。
|
||||
这个工作很 solid。每一步都 make sense(合理)。没有特意为了刷 benchmark 上的指标,用一些 fancy trick(奇技淫巧)。
|
||||
|
||||
<strong>Robust</strong>
|
||||
**Robust**
|
||||
|
||||
鲁棒性,是描述一个系统受到外界的干扰情况下,仍然能保持较好的性能。
|
||||
|
||||
@@ -44,16 +43,16 @@ Email: yqykrhf@163.commailto:yqykrhf@163.com
|
||||
|
||||
我们的系统的图片加入大量的噪声,已经旋转平移缩放以后,仍然能正确的分类,这表明了我们的工作具有一定的鲁棒性。
|
||||
|
||||
# 坐而论道
|
||||
## 坐而论道
|
||||
|
||||
## 2.1 研究是什么
|
||||
### 2.1 研究是什么
|
||||
|
||||
从实际的几个例子讲起:
|
||||
|
||||
1. 某学生,被老师分配了一个课题的名字:《语义分割》。之后开始看相关的论文,了解到有实时语义分割,视频语义分割,跨模态语义分割等等子任务或者交叉任务,然后跟导师开始汇报自己的一些感想,最后在老师的建议之下拟定了具体的课题,开始思考解决方案。
|
||||
2. 某学生,被老师分配了一个课题的名字:《存在遮挡情况下的单目人体重建》 。之后这个学生对这个问题提出了有效的解决方案。
|
||||
3. 某同学在 waymo(Google 自动驾驶子公司)实习,发现没有用神经网络来直接处理点云的工作。于是决定做一个神经网络能够直接输入点云,经过几番尝试以后,提出了《第一个能直接处理点云的网络》。
|
||||
4. 某高校的本科生在 lcw 下的指导下做科研的流程: 老师直接给给一个 basic idea,然后让本科做实验,在这个工程中非常有针对性的指导。
|
||||
4. 某高校的本科生在 lcw 下的指导下做科研的流程:老师直接给给一个 basic idea,然后让本科做实验,在这个工程中非常有针对性的指导。
|
||||
|
||||
例 1 是在给定一个大题目的基础下,去阅读论文寻找小题目。
|
||||
|
||||
@@ -73,55 +72,55 @@ Step 3. 验证解决方案的有效性。
|
||||
|
||||
有些问题是一直存在,但没有彻底解决的。这一类的问题通常,就不存在 Step 1。从事这一课题的研究者经常会在 2,3 之间来回反复。
|
||||
|
||||
## 2.2 如何做研究
|
||||
### 2.2 如何做研究
|
||||
|
||||
从上一小节的几个例子当中,其实不同的人做研究所需要完成的工作是完全不一样的。很多时候只需要做 step 3 即可,从功利的角度来讲这是性价比最高的。
|
||||
|
||||
如果我们是一个合格的博士或者我们致力于如此,那么首先的第一步要找到一个好的问题,这是一个非常重要的开始,<strong>一个好的问题往往意味着研究已经成功了一半。 </strong>什么是一个好的问题?它可能会有以下几个特点:
|
||||
如果我们是一个合格的博士或者我们致力于如此,那么首先的第一步要找到一个好的问题,这是一个非常重要的开始,**一个好的问题往往意味着研究已经成功了一半。 **什么是一个好的问题?它可能会有以下几个特点:
|
||||
|
||||
1. 理论上能实现某种意义上的统一,从而使得问题的描述变得非常优雅。比如 [DepthAwareCNN](https://arxiv.org/abs/1803.06791)
|
||||
2. 对于之后的工作非常具有启发的作用,甚至达到某种意义的纠偏作用。 比如 [OccuSeg](https://arxiv.org/abs/2003.06537)
|
||||
3. 本身足够 solid,可以作为 meta algorithm。 比如 Mask-RCNN
|
||||
4. 是一个大家没有引起足够重视,却非常棘手且非常迫切的问题。 比如相机快速运动下的重建,[MBA-VO](https://openaccess.thecvf.com/content/ICCV2021/papers/Liu_MBA-VO_Motion_Blur_Aware_Visual_Odometry_ICCV_2021_paper.pdf)
|
||||
2. 对于之后的工作非常具有启发的作用,甚至达到某种意义的纠偏作用。比如 [OccuSeg](https://arxiv.org/abs/2003.06537)
|
||||
3. 本身足够 solid,可以作为 meta algorithm。比如 Mask-RCNN
|
||||
4. 是一个大家没有引起足够重视,却非常棘手且非常迫切的问题。比如相机快速运动下的重建,[MBA-VO](https://openaccess.thecvf.com/content/ICCV2021/papers/Liu_MBA-VO_Motion_Blur_Aware_Visual_Odometry_ICCV_2021_paper.pdf)
|
||||
|
||||
### 2.2.1 如何去找一个好的问题
|
||||
#### 2.2.1 如何去找一个好的问题
|
||||
|
||||
如何确保自己选的问题是一个好的问题?这需要和指导老师及时的反馈。如果指导老师不给力,那么一些方法仅供参考。
|
||||
|
||||
1. 自己和工业界的一些人去交流与沟通,看看实际落地的痛点是什么?面对这些痛点,已有的研究方法能否解决,是否有一些现有的 benchmark 或者容易制作的 benchmark 来做为评价标准。
|
||||
2. 做加法。举个例子:图片可以做语义分割。 那么图片 + 深度图如何更好的做语义分割。 图片 + 文字描述的做语义分割。现在的语义分割的标注都是 0,1,2,3 这些数字,然后每一个数字对应一个实际的类别,这个对应表是认为规定的。如果我把 0,1 的对应关系换掉。重新训练以后就,网络的性能是否会影响?
|
||||
3. 做减法。对于点云的语义分割的标注,通过是非常费时费力的。 那么对于点云来说,少量的标注是否是可行的?比如只标注百分之 10 的点。
|
||||
2. 做加法。举个例子:图片可以做语义分割。那么图片 + 深度图如何更好的做语义分割。图片 + 文字描述的做语义分割。现在的语义分割的标注都是 0,1,2,3 这些数字,然后每一个数字对应一个实际的类别,这个对应表是认为规定的。如果我把 0,1 的对应关系换掉。重新训练以后就,网络的性能是否会影响?
|
||||
3. 做减法。对于点云的语义分割的标注,通过是非常费时费力的。那么对于点云来说,少量的标注是否是可行的?比如只标注百分之 10 的点。
|
||||
|
||||
以上是一些技巧,把输入调整一下,约束去掉一些,就会有很多新的问题。 这个过程通常被叫做<strong>“调研”</strong>
|
||||
以上是一些技巧,把输入调整一下,约束去掉一些,就会有很多新的问题。这个过程通常被叫做**“调研”**
|
||||
|
||||
这个过程在是一个相对比较痛苦的过程,因为调研的过程中你会发现很多问题,想到很多所谓创新的解决方法,但是实际上你会发现你的解决方法已经有很多人做过了。这一阶段调整心态很重要,切忌急于求成。
|
||||
|
||||
### 2.2.2 如果提出解决方法
|
||||
#### 2.2.2 如果提出解决方法
|
||||
|
||||
这个阶段需要百折不挠,小步快跑了。 一下是有一些可能有帮助的技巧:
|
||||
这个阶段需要百折不挠,小步快跑了。一下是有一些可能有帮助的技巧:
|
||||
|
||||
1. 多读本领域的论文。(说起来非常玄妙,会在如何读论文部分详细解释)
|
||||
2. 读一些基础,跨领域的论文。 把其他领域的方法搬过来直接用。直接用通常情况下会存在一些问题,那么需要针对性的做一些改进。
|
||||
2. 读一些基础,跨领域的论文。把其他领域的方法搬过来直接用。直接用通常情况下会存在一些问题,那么需要针对性的做一些改进。
|
||||
3. 从历史出发。将你面对的问题抽象成数学问题,这个数学问题可能过去很多人都遇到过,去看一看他们是如何解决的,从中获取一些灵感。
|
||||
|
||||
### 2.2.3 如果做实验
|
||||
#### 2.2.3 如果做实验
|
||||
|
||||
做实验的目的是为了快速的验证想法的正确性。 以下两个东西最好要有
|
||||
做实验的目的是为了快速的验证想法的正确性。以下两个东西最好要有
|
||||
|
||||
1. 版本控制
|
||||
2. 日志系统
|
||||
|
||||
剩下就是一些工程习惯的问题,比如出现错误用 `std::cerr` 而不是 `std::cout`。这是一个需要实践积累的部分,与做研究有些脱节,之后有时间会在其他小节做一些补充。
|
||||
|
||||
# 快速出成果的捷径与方法
|
||||
## 快速出成果的捷径与方法
|
||||
|
||||
如何快速的出成果,不管别人如何帮你,前提是你自己要足够的强。不能存在 <strong>“靠别人” </strong>的想法。
|
||||
如何快速的出成果,不管别人如何帮你,前提是你自己要足够的强。不能存在 **“靠别人” **的想法。
|
||||
|
||||
对于一个博士生来讲,出成果保毕业,那么可能要对学术的进展要敏感,比如 Nerf 八月份刚出来的时候,如果你非常敏锐的意识到这个工作的基础性和重要性。那么你稍微思考一两个月,总是能有一些创新的 ieda 产生的。 所以这个<strong>timing 和 senstive</strong>就非常重要,当然导师是不是审稿人可能更重要。
|
||||
对于一个博士生来讲,出成果保毕业,那么可能要对学术的进展要敏感,比如 Nerf 八月份刚出来的时候,如果你非常敏锐的意识到这个工作的基础性和重要性。那么你稍微思考一两个月,总是能有一些创新的 ieda 产生的。所以这个**timing 和 senstive**就非常重要,当然导师是不是审稿人可能更重要。
|
||||
|
||||
对于一个本科生来讲,当然是跟着指导老师的脚步去做。但是如果指导老师只是把你当成一个工具人,一直打杂货的话。你想发论文,一种所谓的捷径是 A+B。就是把一个方法直接拿过来用在另一个地方,大概率这样会有一些问题,那么你就可以针对性的改进,如何针对性的改进?不好的方式是 A+B 套娃,好一些的方式是分析这个不好的原因在哪里,现有的方法多大程度可以帮助解决这个问题,或者现有的方法解决不了这个问题,但是其中的一个模块是否是可以参考的。
|
||||
|
||||
## 3.2 学习别人是如何改进网络的(Beta)
|
||||
### 3.2 学习别人是如何改进网络的(Beta)
|
||||
|
||||
自 UNet 提出后就有许多的魔改版本,如 UNet++, U2Net, 而这些 UNet 的性能也十分优异。
|
||||
|
||||
@@ -132,13 +131,13 @@ Step 3. 验证解决方案的有效性。
|
||||
1. 你认为你提出的改进方法是有效的,但是实际是不 OK 的
|
||||
2. 你认为你提出的方法可能有效,实际上也确实有效。然而你不能以令人信服的方式说明这为什么有效。
|
||||
|
||||
举个例子 ResNet 为什么有效。“因为网络越深,可以拟合的函数空间就会复杂,但是越深网络效果反而变差。那么从一个角度来思考:网络至少某一层 i 开始到最后一层 k,如果学习到的函数是 f(x)=x 的恒等映射,那么网络变深以后至少输出是和 i-1 层的是一模一样的,从而网络变深可能不一定会变好,但是至少不会变差才对。” 看起来很有道理,然后 CVPR2021 分享会,ResNet 的作者之一,xiangyu zhang 说 “当时也完全不能使人很信服的解释为什么 ResNet 就一定效果好,感觉更像是基于一些灵感,得到了一个很棒的东西,更像是一个工程化的问题,而不是一个研究。但我们可以先告诉别人这个是非常有效的,至于为什么有效,可能需要其他人来解决。”
|
||||
举个例子 ResNet 为什么有效。“因为网络越深,可以拟合的函数空间就会复杂,但是越深网络效果反而变差。那么从一个角度来思考:网络至少某一层 i 开始到最后一层 k,如果学习到的函数是 f(x)=x 的恒等映射,那么网络变深以后至少输出是和 i-1 层的是一模一样的,从而网络变深可能不一定会变好,但是至少不会变差才对。”看起来很有道理,然后 CVPR2021 分享会,ResNet 的作者之一,xiangyu zhang 说“当时也完全不能使人很信服的解释为什么 ResNet 就一定效果好,感觉更像是基于一些灵感,得到了一个很棒的东西,更像是一个工程化的问题,而不是一个研究。但我们可以先告诉别人这个是非常有效的,至于为什么有效,可能需要其他人来解决。”
|
||||
|
||||
再举一个例子 BN(Batch normalization)为什么有效,你去看 BN 的原论文和之后关于 BN 为什么有效的研究,会发现原论文认为有效的原因是不太能让人信服的。 但这不妨碍 BN 有效,而且非常快的推广起来。
|
||||
再举一个例子 BN(Batch normalization) 为什么有效,你去看 BN 的原论文和之后关于 BN 为什么有效的研究,会发现原论文认为有效的原因是不太能让人信服的。但这不妨碍 BN 有效,而且非常快的推广起来。
|
||||
|
||||
其实这件事可以类比于中医,做研究就好比要提出一套理论,但是我不知怎得忽然发现有一个方子经过测试非常有效,但是我确实不能给出一个很好的理论解释说明这个房子为什么有效。但是我尽快把这个方子告诉大家,这同样是非常有意义的。
|
||||
|
||||
举这个两个例子是为了说明,类似 ResNet 这种拍一拍脑袋就想出的 idea,一天可能能想出十几个,但是最后做出来,并且真正 work 的非常少。这里面就存在一个大浪淘沙的过程,可能我们看到的经典的网络,比如 Unet 就是拍拍脑袋,迅速做实验出来的。 我认为这种思考方式仅仅值得参考,并不值得效仿。 现在早已经不是 5 年前那样,却设计各种 fancy 的网络结构去发论文的年代了。
|
||||
举这个两个例子是为了说明,类似 ResNet 这种拍一拍脑袋就想出的 idea,一天可能能想出十几个,但是最后做出来,并且真正 work 的非常少。这里面就存在一个大浪淘沙的过程,可能我们看到的经典的网络,比如 Unet 就是拍拍脑袋,迅速做实验出来的。我认为这种思考方式仅仅值得参考,并不值得效仿。现在早已经不是 5 年前那样,却设计各种 fancy 的网络结构去发论文的年代了。
|
||||
|
||||
那么我们应该如何对待神经网络?(之后再写)
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# 4.人工智能
|
||||
|
||||
## 开篇
|
||||
对于所谓AI的开篇该怎么写,我思考了很久,因为这实在是太过于宏大的话题了,从2012年开始这个行业迎来了所谓的技术爆炸阶段
|
||||
|
||||
对于所谓 AI 的开篇该怎么写,我思考了很久,因为这实在是太过于宏大的话题了,从 2012 年开始这个行业迎来了所谓的技术爆炸阶段
|
||||
|
||||
> 宇宙的时间尺度来看,一个文明的技术在科技发展的过程中,可能短时间内快速发展、科技发展速度不断增加的现象 --------《三体》
|
||||
|
||||
@@ -10,30 +12,30 @@
|
||||
|
||||
阅读本篇内容的群体,我想主要是自动化或计算机的大学生,更多的是没有基础的同学才会翻阅。
|
||||
|
||||
因此本篇不将技术,笔者将从自己的视角,笔者进入大学到现在对所谓AI发展的思想感受的变迁为明线,为将要开启人工智能学习的大伙勾勒出一个笔者眼中的,**人工智能**时代。
|
||||
因此本篇不将技术,笔者将从自己的视角,笔者进入大学到现在对所谓 AI 发展的思想感受的变迁为明线,为将要开启人工智能学习的大伙勾勒出一个笔者眼中的,**人工智能**时代。
|
||||
|
||||
同时,我也会在本篇内容中给你,你可以在本篇内容中获得什么。
|
||||
> 这是一个最好的时代,也是一个最坏的时代;
|
||||
>
|
||||
>
|
||||
> 这是一个智慧的年代,这是一个愚蠢的年代;
|
||||
>
|
||||
>
|
||||
> 这是一个信任的时期,这是一个怀疑的时期。
|
||||
>
|
||||
>
|
||||
> 这是一个光明的季节,这是一个黑暗的季节;
|
||||
>
|
||||
>
|
||||
> 这是希望之春,这是失望之冬;
|
||||
>
|
||||
>
|
||||
> 人们面前应有尽有,人们面前一无所有;
|
||||
>
|
||||
>
|
||||
> 人们正踏上天堂之路,人们正走向地狱之门。
|
||||
>
|
||||
> ——《双城记》 查尔斯·狄更斯
|
||||
>
|
||||
> ——《双城记》查尔斯·狄更斯
|
||||
|
||||
## 看山是山
|
||||
|
||||
2020年,在一门杭电的程序设计实践课上,老师要求我们用C语言去实现一些算法,我本来是将目标定为去大厂赚更多的钱的,对所谓AI仅仅停留在概念上,对其内容一无所知。
|
||||
2020 年,在一门杭电的程序设计实践课上,老师要求我们用 C 语言去实现一些算法,我本来是将目标定为去大厂赚更多的钱的,对所谓 AI 仅仅停留在概念上,对其内容一无所知。
|
||||
|
||||
在实验的过程中,偶然和一位转专业学长偶然聊起到程设变态难得题目设计,要求用C语言实现KNN之类的算法,这TM对于我当时的水平简直是太难了!聊到他自己所在的某个实验室本科生的入组任务也不过是这个难度偏低一点点。
|
||||
在实验的过程中,偶然和一位转专业学长偶然聊起到程设变态难得题目设计,要求用 C 语言实现 KNN 之类的算法,这 TM 对于我当时的水平简直是太难了!聊到他自己所在的某个实验室本科生的入组任务也不过是这个难度偏低一点点。
|
||||
|
||||
带着投机主义的心态,想着能不能混到一些论文之类的成果更好就业,毅然决然上了船。
|
||||
|
||||
@@ -43,9 +45,9 @@
|
||||
|
||||
对所谓的科研,所谓的论文,所谓的项目的含金量都是一知半解,只不过是“看到感觉他很火,感觉他很好,具体怎么样我不知道”的心态。这也是在当时的市场上,很多人的心态,由此也是人工智能第一轮狂潮的热点所在,因为大家其实很多都不清楚这个新技术,究竟有什么样的上线,吹起了很大的泡泡。
|
||||
|
||||
就算是有点远见的本科生,也仅仅是看到了所谓的CV和NLP在学校和整个社会大规模宣传下的科普性的概念,也许也没有深入了解过,当时的我也一样。但是我也陷入了同样的狂热中,仅仅是因为他足够火热或有足够的前景,我就想着跟随着潮流走。
|
||||
就算是有点远见的本科生,也仅仅是看到了所谓的 CV 和 NLP 在学校和整个社会大规模宣传下的科普性的概念,也许也没有深入了解过,当时的我也一样。但是我也陷入了同样的狂热中,仅仅是因为他足够火热或有足够的前景,我就想着跟随着潮流走。
|
||||
|
||||
我看了一点非常基础的教程,老师便给我发了两篇非常刺激的CV论文,都是他专业下比较前沿的文章了,我对这到底意味着什么仍然是一无所知,我完全没有搭建起合理的知识框架,我眼里AI只有深度学习,只有用框架写的那几行短短的代码,于是开启了受难之旅。
|
||||
我看了一点非常基础的教程,老师便给我发了两篇非常刺激的 CV 论文,都是他专业下比较前沿的文章了,我对这到底意味着什么仍然是一无所知,我完全没有搭建起合理的知识框架,我眼里 AI 只有深度学习,只有用框架写的那几行短短的代码,于是开启了受难之旅。
|
||||
|
||||
老师并没有做错什么,他只是在这个人工智能大潮下的一朵浪花,他也尽其所能的做到了对本科学生的关注,错的是我,我没有仔细考究过,也没有站在足够高的角度去审视如果我加入了他的工作,我在这个行业中会处在什么样的位置。
|
||||
|
||||
@@ -71,44 +73,46 @@
|
||||
|
||||
**我厌恶他!我厌恶他破坏了科研的纯洁性!我厌恶他成为了急功近利者的帮凶!我厌恶他堆砌的沙堆是充斥着无产者的血和泪!我厌恶他让马太效应发挥到了极致!我厌恶他让所有人都贴上了他的面具,但可能对本质上的东西一无所知!我厌恶他只注重结果,完全不注重过程然后让写的故事变成了捏造!**
|
||||
|
||||
但是,现在我会说,也许当时的我真的错了。我并没有思考过所谓人类的智能和AI的智能的关系,也忽视了当某一个趋势或方向发展到极致之后,量变会引发什么样的质变。
|
||||
但是,现在我会说,也许当时的我真的错了。我并没有思考过所谓人类的智能和 AI 的智能的关系,也忽视了当某一个趋势或方向发展到极致之后,量变会引发什么样的质变。
|
||||
|
||||
[推荐大伙可以看看这个](https://www.bilibili.com/video/BV11c41157aU/?spm_id_from=333.999.0.0&vd_source=2cb6252f9211ae9d29cf1f76f0aea8d7)
|
||||
[推荐大伙可以看看这个](https://www.bilibili.com/video/BV11c41157aU)
|
||||
|
||||
## 看山是山
|
||||
> 孟德尔出生于奥地利帝国(今天的捷克共和国)的西里西亚,是现代遗传学的创始人。尽管几千年来农民就知道动植物的杂交可以促进某些理想的性状,但孟德尔在1856年至1863年之间进行的豌豆植物实验建立了许多遗传规则,现称为孟德尔定律。
|
||||
<Bilibili bvid='BV11c41157aU'/>
|
||||
|
||||
## 看山还是山
|
||||
|
||||
> 孟德尔出生于奥地利帝国(今天的捷克共和国)的西里西亚,是现代遗传学的创始人。尽管几千年来农民就知道动植物的杂交可以促进某些理想的性状,但孟德尔在 1856 年至 1863 年之间进行的豌豆植物实验建立了许多遗传规则,现称为孟德尔定律。
|
||||
|
||||
在孟德尔那个时代,人们不知道基因,人们也看不到那么小的东西,他给基因取了个名字叫遗传因子。他没能掌握“真实的规律”,可是我们不得不承认的是,他是一个真正有科研精神的人的科研人。 -
|
||||
|
||||
我在不断地绝望之后,走向了极端,我放弃了跟进这个方面的学习,孟尝高洁,空余报国之情;阮籍猖狂,岂效穷途之哭!我失去了搞科研的热情,只想一心去做些别的。
|
||||
|
||||
我看到了南大的课程,我去看一生一芯,去看jyy老师的OS,我听到了蒋老师对未来AI的发展充满了信心,我虽然很崇拜他,但我仍对此嗤之以鼻,我不相信。
|
||||
我看到了南大的课程,我去看一生一芯,去看 jyy 老师的 OS,我听到了蒋老师对未来 AI 的发展充满了信心,我虽然很崇拜他,但我仍对此嗤之以鼻,我不相信。
|
||||
|
||||
一直到有一天,相先生在实验室玩一个叫chatGPT的东西,虽然之前懵懵懂懂的有了解过GPT3之类的东西,但是都对此行的发展没有什么了解,只是知道他又非常大的参数的语言模型,在好奇之下,我去亲自体验chat GPT,我受震惊于他能准确无误的理解我的意思,甚至能替我写代码,只要将问题拆解,他几乎可以就任何一个问题给出一个反而化之的答案。
|
||||
一直到有一天,相先生在实验室玩一个叫 chatGPT 的东西,虽然之前懵懵懂懂的有了解过 GPT3 之类的东西,但是都对此行的发展没有什么了解,只是知道他又非常大的参数的语言模型,在好奇之下,我去亲自体验 chat GPT,我受震惊于他能准确无误的理解我的意思,甚至能替我写代码,只要将问题拆解,他几乎可以就任何一个问题给出一个反而化之的答案。
|
||||
|
||||
随后没过多久,GPT4与new bing应运而生,可以理解用户的意图和情感,根据用户的偏好和反馈来调整输出,甚至利用网络搜索来增强其的知识和回答能力,他们还结合了CV的功能,可以让他们来进行图像的生成工作。作为科研人的最高追求,大一统,一通半通的解决所有问题的模型竟然真的可能在我的有生之年实现,不由得震惊至极。同时,大模型也进入了CV领域,出现了segmenting anything这样可以做到零样本迁移这样的神奇功能,auto GPT出现了在电脑主机上直接替人解决问题甚至是完成某一项工程任务的GPT,以及可以在手机上本地做的mini GPT,技术的爆炸以及变革似乎一瞬间到来了,但是当我回过头展望的时候,正是我最看不起的沙砾,堆叠成了如此强大石之巨人,并且随着资本的涌入,他还在不断强大!!!
|
||||
随后没过多久,GPT4 与 new bing 应运而生,可以理解用户的意图和情感,根据用户的偏好和反馈来调整输出,甚至利用网络搜索来增强其的知识和回答能力,他们还结合了 CV 的功能,可以让他们来进行图像的生成工作。作为科研人的最高追求,大一统,一通半通的解决所有问题的模型竟然真的可能在我的有生之年实现,不由得震惊至极。同时,大模型也进入了 CV 领域,出现了 segmenting anything 这样可以做到零样本迁移这样的神奇功能,auto GPT 出现了在电脑主机上直接替人解决问题甚至是完成某一项工程任务的 GPT,以及可以在手机上本地做的 mini GPT,技术的爆炸以及变革似乎一瞬间到来了,但是当我回过头展望的时候,正是我最看不起的沙砾,堆叠成了如此强大石之巨人,并且随着资本的涌入,他还在不断强大!!!
|
||||
|
||||
2012年,被我们认定为人工智能学习的开篇之作,Alex net诞生了,由Alex Krizhevsky和他的导师Geoffrey Hinton以及Ilya Sutskever设计,在2012年的ImageNet大规模视觉识别挑战赛中获得了冠军,展示了深度学习在图像分类方面的强大能力,并且正式启动了深度学习的革命,在当时他也引发了大量的争议,奉承这符号主义的大师们对着他指指点点,可是他们并不能阻碍时代的巨石碾过一切非议,并且在各个领域都爆发出极其强大的生命力。
|
||||
2012 年,被我们认定为人工智能学习的开篇之作,Alex net 诞生了,由 Alex Krizhevsky 和他的导师 Geoffrey Hinton 以及 Ilya Sutskever 设计,在 2012 年的 ImageNet 大规模视觉识别挑战赛中获得了冠军,展示了深度学习在图像分类方面的强大能力,并且正式启动了深度学习的革命,在当时他也引发了大量的争议,奉承这符号主义的大师们对着他指指点点,可是他们并不能阻碍时代的巨石碾过一切非议,并且在各个领域都爆发出极其强大的生命力。
|
||||
|
||||
想起在学操作系统的时候,linus在几十年前被大老师tanenbaum狂喷,说整了什么垃圾玩意儿。当时的minix基本上可以说是横扫江湖,linus却坚持说用户只考虑用户态是否好用而不在乎内核有多牛逼,当时的论战基本上把各类大神都炸出来,结果几十年后的如今我们发现原来遍布世界的居然是宏内核/混合内核。
|
||||
想起在学操作系统的时候,linus 在几十年前被大老师 tanenbaum 狂喷,说整了什么垃圾玩意儿。当时的 minix 基本上可以说是横扫江湖,linus 却坚持说用户只考虑用户态是否好用而不在乎内核有多牛逼,当时的论战基本上把各类大神都炸出来,结果几十年后的如今我们发现原来遍布世界的居然是宏内核/混合内核。
|
||||
|
||||
时代的发展连大佬都可以拍死在沙滩上!
|
||||
|
||||
从短期来看,也许未来 GPT 会接管小 AI 形成一套上下左右俱为一体的 AI 智能模型,在所谓自动驾驶,智能家居领域发挥极其卓越的作用。
|
||||
|
||||
从长远来看,不由得联想起 AI 在围棋方面 alpha zero 的论文里面提到过,当他们不适用人类的知识的时候,反而模型的效果好很多,有没有可能 AI 在短短的未来总结出一套人类自然语言的规则后,自发创造出一个全新的语言,最终就彻底脱离人类变成一种全新的生命形式,从而彻底颠覆人类以公理为基础的数学,创造一套全新的数学体系,数学体系重做,物理学是否也会迎来质变?
|
||||
|
||||
从短期来看,也许未来GPT会接管小AI形成一套上下左右俱为一体的AI智能模型,在所谓自动驾驶,智能家居领域发挥极其卓越的作用。
|
||||
AI 是一个复杂且多样化的研究领域,他能取得如此长远的发展,并非是仅仅一个两个人靠着所谓的理论研究就可以推动起来的,它伴随着底层的硬件设施配套的完善,算力的突破性增长等等,发展本身,也许就是兼容并蓄的,我们应该在这个发展的洪流前,找到自己的位置以更为谦卑谨慎的姿态,进行更为长远的思考和学习吧。
|
||||
|
||||
从长远来看,不由得联想起AI在围棋方面alpha zero的论文里面提到过,当他们不适用人类的知识的时候,反而模型的效果好很多,有没有可能AI在短短的未来总结出一套人类自然语言的规则后,自发创造出一个全新的语言,最终就彻底脱离人类变成一种全新的生命形式,从而彻底颠覆人类以公理为基础的数学,创造一套全新的数学体系,数学体系重做,物理学是否也会迎来质变?
|
||||
|
||||
AI是一个复杂且多样化的研究领域,他能取得如此长远的发展,并非是仅仅一个两个人靠着所谓的理论研究就可以推动起来的,它伴随着底层的硬件设施配套的完善,算力的突破性增长等等,发展本身,也许就是兼容并蓄的,我们应该在这个发展的洪流前,找到自己的位置以更为谦卑谨慎的姿态,进行更为长远的思考和学习吧。
|
||||
|
||||
> 三花聚顶本是幻,脚下腾云亦非真。大梦一场终须醒,无根无极本归尘。
|
||||
> 三花聚顶本是幻,脚下腾云亦非真。大梦一场终须醒,无根无极本归尘。
|
||||
|
||||
## 结语
|
||||
让我们回到最开始的那几句话
|
||||
这是一个最好的时代(AI技术正在改变人们的生活)
|
||||
|
||||
也是一个最坏的时代(AI也许取代大量人的饭碗)
|
||||
让我们回到最开始的那几句话
|
||||
这是一个最好的时代(AI 技术正在改变人们的生活)
|
||||
|
||||
也是一个最坏的时代(AI 也许取代大量人的饭碗)
|
||||
|
||||
这是一个智慧的年代(很多顶尖的科学家正在改变世界)
|
||||
|
||||
@@ -116,7 +120,7 @@ AI是一个复杂且多样化的研究领域,他能取得如此长远的发展
|
||||
|
||||
这是一个信任的时期(人们将更加信任这个社会会因此变好)
|
||||
|
||||
这是一个怀疑的时期(AI技术带来伦理,毁灭世界等方面的讨论)
|
||||
这是一个怀疑的时期(AI 技术带来伦理,毁灭世界等方面的讨论)
|
||||
|
||||
这是一个光明的季节(前沿科研或科技从来没有离普通的本科生这么近)
|
||||
|
||||
@@ -126,7 +130,7 @@ AI是一个复杂且多样化的研究领域,他能取得如此长远的发展
|
||||
|
||||
这是失望之冬(我国仍有很多需要发展的地方)
|
||||
|
||||
人们面前应有尽有(人们以后可能拥有了AI也就拥有了一切)
|
||||
人们面前应有尽有(人们以后可能拥有了 AI 也就拥有了一切)
|
||||
|
||||
人们面前一无所有(隐私,版权,安全等问题正在受到质疑)
|
||||
|
||||
@@ -144,7 +148,7 @@ AI是一个复杂且多样化的研究领域,他能取得如此长远的发展
|
||||
|
||||
而这些都不会使他停滞
|
||||
|
||||
**这是本讲义想做的第三件事,拥有学习新技术,跟上时代的能力**
|
||||
**这是本讲义想做的第三件事,拥有学习新技术,跟上时代的能力****
|
||||
|
||||
而愿不愿意在这激荡翻腾的年份,贡献出你的力量,让世界变得更好/更坏,就取决于你的选择了!
|
||||
|
||||
|
||||
@@ -1,35 +1,36 @@
|
||||
# FunRec概述
|
||||
# FunRec 概述
|
||||
|
||||
# 序言
|
||||
## 序言
|
||||
|
||||
这是一篇datawhale的相当优秀的推荐系统教程,因此特别请相先生废了九牛二虎之力把FunRec的半套内容,较为完整的移植到了本wiki中。
|
||||
这是一篇 datawhale 的相当优秀的推荐系统教程,因此特别废了九牛二虎之力把 FunRec 的半套内容,较为完整的移植到了本 wiki 中。
|
||||
|
||||
## 为什么要专门移植这篇?
|
||||
### 为什么要专门移植这篇?
|
||||
|
||||
zzm个人以为推荐系统是一个非常有趣的横向和纵向都有很多应用的领域(放到外面是因为放到某一个模块下会因为次级链接太多把wiki撑爆了)
|
||||
zzm 个人以为推荐系统是一个非常有趣的横向和纵向都有很多应用的领域(放到外面是因为放到某一个模块下会因为次级链接太多把 wiki 撑爆了)
|
||||
|
||||
若你想尝试一个新领域,也许这是一个不错的切入点。更何况,如果你想足够完整的构建一个有实际价值的推荐系统,可能需要你去了解相当全面的知识。
|
||||
|
||||
在学习了基础内容之后,如果你想向着科研领域进发,也许对你而言最好的方式或许是选择一个大佬然后去follow他的进度。
|
||||
在学习了基础内容之后,如果你想向着科研领域进发,也许对你而言最好的方式或许是选择一个大佬然后去 follow 他的进度。
|
||||
|
||||
如果你想去找相关的工作,你可以自行去深入学习有关本教程内容的实践部分,甚至是阅读算法面经。
|
||||
|
||||
同时只放上半部的原因是毕竟本偏内容是人工智能大类下的内容,后续可能会涉及一些前后端以及一些更为深入的东西,如果你只是想大致了解一下,那么阅读放在本片的内容被也许是一个不错的选择。
|
||||
|
||||
再次感谢Datawhale的大伙做出了如此卓著的贡献
|
||||
再次感谢 Datawhale 的大伙做出了如此卓著的贡献
|
||||
|
||||
## 正文
|
||||
|
||||
# 正文
|
||||
本教程主要是针对具有机器学习基础并想找推荐算法岗位的同学。教程内容由推荐系统概述、推荐算法基础、推荐系统实战和推荐系统面经四个部分组成。本教程对于入门推荐算法的同学来说,可以从推荐算法的基础到实战再到面试,形成一个闭环。每个部分的详细内容如下:
|
||||
|
||||
- **推荐系统概述。** 这部分内容会从推荐系统的意义及应用,到架构及相关的技术栈做一个概述性的总结,目的是为了让初学者更加了解推荐系统。
|
||||
- **推荐系统算法基础。** 这部分会介绍推荐系统中对于算法工程师来说基础并且重要的相关算法,如经典的召回、排序算法。随着项目的迭代,后续还会不断的总结其他的关键算法和技术,如重排、冷启动等。
|
||||
- **推荐系统实战。** 这部分内容包含推荐系统竞赛实战和新闻推荐系统的实践。其中推荐系统竞赛实战是结合阿里天池上的新闻推荐入门赛做的相关内容。新闻推荐系统实践是实现一个具有前后端交互及整个推荐链路的项目,该项目是一个新闻推荐系统的demo没有实际的商业化价值。
|
||||
- **推荐系统实战。** 这部分内容包含推荐系统竞赛实战和新闻推荐系统的实践。其中推荐系统竞赛实战是结合阿里天池上的新闻推荐入门赛做的相关内容。新闻推荐系统实践是实现一个具有前后端交互及整个推荐链路的项目,该项目是一个新闻推荐系统的 demo 没有实际的商业化价值。
|
||||
- **推荐系统算法面经。** 这里会将推荐算法工程师面试过程中常考的一些基础知识、热门技术等面经进行整理,方便同学在有了一定推荐算法基础之后去面试,因为对于初学者来说只有在公司实习学到的东西才是最有价值的。
|
||||
|
||||
**特别说明**:项目内容是由一群热爱分享的同学一起花时间整理而成,**大家的水平都非常有限,内容难免存在一些错误和问题,如果学习者发现问题,也欢迎及时反馈,避免让后学者踩坑!** 如果对该项目有改进或者优化的建议,还希望通过下面的二维码找到项目负责人或者在交流社区中提出,我们会参考大家的意见进一步对该项目进行修改和调整!如果想对该项目做一些贡献,也可以通过上述同样的方法找到我们!
|
||||
|
||||
为了方便学习和交流,**我们建立了FunRec学习社区(微信群+知识星球)**,微信群方便大家平时日常交流和讨论,知识星球方便沉淀内容。由于我们的内容面向的人群主要是学生,所以**知识星球永久免费**,感兴趣的可以加入星球讨论(加入星球的同学先看置定的必读帖)!**FunRec学习社区内部会不定期分享(FunRec社区中爱分享的同学)技术总结、个人管理等内容,[跟技术相关的分享内容都放在了B站](https://space.bilibili.com/431850986/channel/collectiondetail?sid=339597)上面**。由于微信群的二维码只有7天内有效,所以直接加下面这个微信,备注:**Fun-Rec**,会被拉到Fun-Rec交流群,如果觉得微信群比较吵建议直接加知识星球!。
|
||||
为了方便学习和交流,**我们建立了 FunRec 学习社区(微信群 + 知识星球)**,微信群方便大家平时日常交流和讨论,知识星球方便沉淀内容。由于我们的内容面向的人群主要是学生,所以**知识星球永久免费**,感兴趣的可以加入星球讨论(加入星球的同学先看置定的必读帖)!**FunRec 学习社区内部会不定期分享 (FunRec 社区中爱分享的同学) 技术总结、个人管理等内容,[跟技术相关的分享内容都放在了 B 站](https://space.bilibili.com/431850986/channel/collectiondetail?sid=339597)上面**。由于微信群的二维码只有 7 天内有效,所以直接加下面这个微信,备注:**Fun-Rec**,会被拉到 Fun-Rec 交流群,如果觉得微信群比较吵建议直接加知识星球!。
|
||||
|
||||
<div align=center>
|
||||
<div align=center>
|
||||
<img src="https://ryluo.oss-cn-chengdu.aliyuncs.com/图片image-20220408193745249.png" />
|
||||
</div>
|
||||
|
||||
@@ -97,7 +97,7 @@ $$
|
||||
print(similarity_matrix)
|
||||
```
|
||||
|
||||
```
|
||||
```python
|
||||
A B C D E
|
||||
A 1.000000 -0.476731 -0.123091 0.532181 0.969458
|
||||
B -0.476731 1.000000 0.645497 -0.310087 -0.478091
|
||||
@@ -124,7 +124,7 @@ $$
|
||||
print(f'与物品{target_item}最相似的{num}个物品为:{sim_items}')
|
||||
```
|
||||
|
||||
```
|
||||
```python
|
||||
与物品E最相似的2个物品为:['A', 'D']
|
||||
```
|
||||
|
||||
@@ -147,7 +147,7 @@ $$
|
||||
print(f'用户{target_user}对物品{target_item}的预测评分为:{target_item_pred}')
|
||||
```
|
||||
|
||||
```
|
||||
```python
|
||||
用户 Alice 对物品E的预测评分为:4.6
|
||||
```
|
||||
|
||||
@@ -260,10 +260,4 @@ $$
|
||||
# 参考资料
|
||||
|
||||
* [基于用户的协同过滤来构建推荐系统:https://mp.weixin.qq.com/s/ZtnaQrVIpVOPJpqMdLWOcw](https://mp.weixin.qq.com/s/ZtnaQrVIpVOPJpqMdLWOcw)
|
||||
* [协同过滤算法概述:https://chenk.tech/posts/8ad63d9d.html](https://chenk.tech/posts/8ad63d9d.html)
|
||||
* B站黑马推荐系统实战课程
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -234,7 +234,7 @@ UserCF算法的两个步骤:
|
||||
print(similarity_matrix)
|
||||
```
|
||||
|
||||
```
|
||||
```python
|
||||
1 2 3 4 5
|
||||
1 1.000000 0.852803 0.707107 0.000000 -0.792118
|
||||
2 0.852803 1.000000 0.467707 0.489956 -0.900149
|
||||
@@ -253,7 +253,7 @@ UserCF算法的两个步骤:
|
||||
print(f'与用户{target_user}最相似的{num}个用户为:{sim_users}')
|
||||
```
|
||||
|
||||
```
|
||||
```python
|
||||
与用户 Alice 最相似的2个用户为:['user1', 'user2']
|
||||
```
|
||||
|
||||
@@ -277,7 +277,7 @@ UserCF算法的两个步骤:
|
||||
print(f'用户{target_user}对物品{target_item}的预测评分为:{target_item_pred}')
|
||||
```
|
||||
|
||||
```
|
||||
```python
|
||||
用户 Alice 对物品E的预测评分为:4.871979899370592
|
||||
```
|
||||
|
||||
@@ -341,5 +341,4 @@ $$
|
||||
# 参考资料
|
||||
|
||||
* [基于用户的协同过滤来构建推荐系统:https://mp.weixin.qq.com/s/ZtnaQrVIpVOPJpqMdLWOcw](https://mp.weixin.qq.com/s/ZtnaQrVIpVOPJpqMdLWOcw)
|
||||
* [协同过滤算法概述:https://chenk.tech/posts/8ad63d9d.html](https://chenk.tech/posts/8ad63d9d.html)
|
||||
* B站黑马推荐系统实战课程
|
||||
|
||||
@@ -85,7 +85,7 @@ $$
|
||||
|
||||
Ok,到这里平淡无奇, 前向传播也大致上快说完了, 还差最后一步。 最后这一步,就是做多分类问题,然后求损失,这就是training那边做的事情。 但是在详细说这个之前, 我想先简单回忆下word2vec里面的skip-gram Model, 这个模型,如果回忆起来,这里理解起来就非常的简单了。
|
||||
|
||||
这里只需要看一张图即可, 这个来自cs231N公开课PPT, 我之前整理w2v的时候用到的,详细内容可看我[这篇博客](https://zhongqiang.blog.csdn.net/article/details/106948860), 这里的思想其实也是从w2v那边过来的。
|
||||
这里只需要看一张图即可, 这个来自cs231N公开课PPT, 我之前整理w2v的时候用到的,这里的思想其实也是从w2v那边过来的。
|
||||
|
||||
<div align=center>
|
||||
<img src="https://img-blog.csdnimg.cn/20200624193409649.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhvbmdxaWFuZw==,size_1,color_FFFFFF,t_70#pic_center" alt="在这里插入图片描述" style="zoom:70%;" />
|
||||
|
||||
@@ -103,7 +103,7 @@ Word2vec包含两个模型,**Skip-gram与CBOW**。下面,我们先讲**Skip-
|
||||
我们滑动窗口,再以banking为中心词
|
||||
|
||||
|
||||
<img src="https://ryluo.oss-cn-chengdu.aliyuncs.com/图片4.png"在这里插入图片描述" />
|
||||
<img src="https://ryluo.oss-cn-chengdu.aliyuncs.com/图片4.png" />
|
||||
|
||||
|
||||
那么,如果我们在整个语料库上不断地滑动窗口,我们可以得到所有位置的$P(o|c)$,我们希望在所有位置上**最大化单词o在单词c周围出现了这一事实**,由极大似然法,可得:
|
||||
|
||||
@@ -239,7 +239,7 @@ $$
|
||||
|
||||
### 编程实践
|
||||
|
||||
下面我们通过kaggle上的一个ctr预测的比赛来看一下GBDT+LR模型部分的编程实践, [数据来源](https://github.com/zhongqiangwu960812/AI-RecommenderSystem/tree/master/GBDT%2BLR/data)
|
||||
下面我们通过kaggle上的一个ctr预测的比赛来看一下GBDT+LR模型部分的编程实践, [数据来源](https://github.com/zhongqiangwu960812/AI-RecommenderSystem/tree/master/Rank/GBDT%2BLR/data)
|
||||
|
||||
我们回顾一下上面的模型架构, 首先是要训练GBDT模型, GBDT的实现一般可以使用xgboost, 或者lightgbm。训练完了GBDT模型之后, 我们需要预测出每个样本落在了哪棵树上的哪个节点上, 然后通过one-hot就会得到一些新的离散特征, 这和原来的特征进行合并组成新的数据集, 然后作为逻辑回归的输入,最后通过逻辑回归模型得到结果。
|
||||
|
||||
|
||||
@@ -151,6 +151,6 @@ def DeepFM(linear_feature_columns, dnn_feature_columns):
|
||||
**参考资料**
|
||||
- [论文原文](https://arxiv.org/pdf/1703.04247.pdf)
|
||||
- [deepctr](https://github.com/shenweichen/DeepCTR)
|
||||
- [FM](https://github.com/datawhalechina/team-learning-rs/blob/master/RecommendationSystemFundamentals/04%20FM.md)
|
||||
- [FM](https://github.com/datawhalechina/fun-rec/blob/master/docs/ch02/ch2.1/ch2.1.2/FM.md)
|
||||
- [推荐系统遇上深度学习(三)--DeepFM模型理论和实践](https://www.jianshu.com/p/6f1c2643d31b)
|
||||
- [FM算法公式推导](https://blog.csdn.net/qq_32486393/article/details/103498519)
|
||||
@@ -118,7 +118,7 @@ def Shared_Bottom(dnn_feature_columns, num_tasks=None, task_types=None, task_nam
|
||||
|
||||
参考资料:
|
||||
|
||||
[https://developer.aliyun.com/article/793252](https://link.zhihu.com/?target=https%3A//developer.aliyun.com/article/793252)
|
||||
[https://developer.aliyun.com/article/793252](https://developer.aliyun.com/article/793252)
|
||||
|
||||
https://zhuanlan.zhihu.com/p/291406172
|
||||
|
||||
|
||||
@@ -77,8 +77,8 @@ OK, 到这里就把MMOE的故事整理完了,模型结构本身并不是很
|
||||
|
||||
那么, 为什么多任务学习为什么是有效的呢? 这里整理一个看到比较不错的答案:
|
||||
>多任务学习有效的原因是引入了归纳偏置,两个效果:
|
||||
> - 互相促进: 可以把多任务模型之间的关系看作是互相先验知识,也称为归纳迁移,有了对模型的先验假设,可以更好提升模型的效果。解决数据稀疏性其实本身也是迁移学习的一个特性,多任务学习中也同样会体现
|
||||
>- 泛化作用:不同模型学到的表征不同,可能A模型学到的是B模型所没有学好的,B模型也有其自身的特点,而这一点很可能A学不好,这样一来模型健壮性更强
|
||||
> - 互相促进: 可以把多任务模型之间的关系看作是互相 先验知识,也称为归纳迁移,有了对模型的先验假设,可以更好提升模型的效果。解决数据稀疏性其实本身也是迁移学习的一个特性,多任务学习中也同样会体现
|
||||
> - 泛化作用:不同模型学到的表征不同,可能A模型学到的是B模型所没有学好的,B模型也有其自身的特点,而这一点很可能A学不好,这样一来模型健壮性更强
|
||||
|
||||
## MMOE模型的简单复现之多任务预测
|
||||
### 模型概貌
|
||||
|
||||
BIN
4.人工智能/static/4.3-0.jpg
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
4.人工智能/static/4.3.4-0.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
4.人工智能/static/4.3.4-1.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
4.人工智能/static/4.3.4-10.png
Normal file
|
After Width: | Height: | Size: 186 KiB |
BIN
4.人工智能/static/4.3.4-11.png
Normal file
|
After Width: | Height: | Size: 304 KiB |
BIN
4.人工智能/static/4.3.4-12.png
Normal file
|
After Width: | Height: | Size: 148 KiB |
BIN
4.人工智能/static/4.3.4-13.png
Normal file
|
After Width: | Height: | Size: 183 KiB |
BIN
4.人工智能/static/4.3.4-14.png
Normal file
|
After Width: | Height: | Size: 137 KiB |
BIN
4.人工智能/static/4.3.4-2.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
4.人工智能/static/4.3.4-3.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
4.人工智能/static/4.3.4-4.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
4.人工智能/static/4.3.4-5.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
4.人工智能/static/4.3.4-6.png
Normal file
|
After Width: | Height: | Size: 86 KiB |
BIN
4.人工智能/static/4.3.4-7.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
4.人工智能/static/4.3.4-8.png
Normal file
|
After Width: | Height: | Size: 141 KiB |
BIN
4.人工智能/static/4.3.4-9.png
Normal file
|
After Width: | Height: | Size: 127 KiB |
BIN
4.人工智能/static/4.3.4.2-0.png
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
4.人工智能/static/4.3.4.2-1.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 143 KiB After Width: | Height: | Size: 143 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |