宾夕法尼亚大学人工智能和机器学习基础笔记-全-

宾夕法尼亚大学人工智能和机器学习基础笔记(全)

01:人工智能基础导论 🧠

在本节课中,我们将要学习人工智能的基础概念,包括对智能的哲学思考、AI系统的设计目标,以及本课程的核心内容——理性智能体和规划算法。

我叫克里斯·卡利森·伯奇,是宾夕法尼亚大学工程与应用科学学院的教授。欢迎来到我们的人工智能课程,这是“Python人工智能与机器学习基础”专项课程的一部分。

我们的专项课程将深入探讨核心主题,帮助你理解现代深度学习和经典人工智能背后的数学与算法基础。

什么是智能?🤔

上一节我们介绍了课程的基本情况,本节中我们来看看一个根本性的哲学问题:智能意味着什么?我们还将探讨科幻作品如何常常预示人工智能领域的科学进步。

我们将以科幻作品为起点,思考作为AI系统设计者,我们希望创建什么样的系统。以下是两种主要的设计思路:

  • 我们应该构建像人类一样思考和行动的AI智能体吗?
  • 还是应该构建能够理性思考和行动的系统?

聚焦理性智能体 🎯

在本课程中,我们将聚焦于理性智能体。我们将发展一套关于“理性行动”意味着什么的理论,并开发相应的算法。

理性智能体需要规划。规划智能体必须从众多可能的行动中进行选择,以创建一系列行动,从而以最优的方式达成其目标。

搜索算法:规划的核心工具 🔍

为了实现规划,我们将开发的第一组算法是一个广泛的类别,称为搜索算法

我们将从经典的深度优先搜索和广度优先搜索算法出发,逐步构建,最终学习AI领域最著名的搜索算法之一:A*搜索算法

A*搜索算法最初是为机器人导航开发的,它正是你从智能手机获取驾驶路线指引功能背后的核心技术。

实践环节:Python编程 🐍

为了帮助你将这些AI算法具体化,你将完成一系列简短的Python编码作业。

作为本课程的一部分,我们将提供适合进阶初学者的全面Python复习。如果你刚刚开始学习编程,可以考虑尝试我们的另一个专项课程“Python与Java编程入门”。

课程总结与展望 📚

本节课中,我们一起学习了人工智能的入门概念,探讨了智能的本质,并明确了本课程将专注于理性智能体与规划算法。我们介绍了实现规划的核心工具——搜索算法,特别是A*算法,并概述了通过Python编程进行实践的学习路径。

完成这门专注于理性智能体和规划等重要主题的课程后,你将有机会通过我们专项课程中的其他课程学习更多AI基础知识,这些课程将教你机器学习和深度学习的统计与数学基础。

02:人工智能概述 🧠

在本模块中,我们将探讨人工智能的基本哲学背景,并回顾一些预示了当今AI发展的经典科幻作品。我们将从“智能”的定义出发,了解历史上思想家们如何区分人类与机器,并初步接触本课程将使用的Python语言。

什么是智能?

智能意味着什么?为了让一台计算机被认为是智能的,它是否必须拥有心智,或者必须表现得像人类一样?

哲学基础:从笛卡尔到图灵

上一节我们提出了关于智能本质的问题。本节中,我们来看看两位重要思想家的观点。

首先,我们将谈论勒内·笛卡尔,他是现代西方哲学的奠基人之一。他深入思考了如何区分人类与一个对人类进行高度逼真模拟的机器。

接着,我们将谈论艾伦·图灵,他是计算机科学的创始人之一。他试图定义“机器能思考吗?”这个问题,并提出了“机器能否通过行为被当作人类?”的检验方式。

科幻作品中的预言

在探讨了哲学定义后,我们转向流行文化。科幻作品常常预示人工智能的未来。

以下是几部具有代表性的影片:

  • 《2001太空漫游》:片中名为HAL的AI角色,与如今许多家庭拥有的亚马逊Alexa系统非常相似。
  • 《终结者》:影片中的AI系统能够执行计算机视觉任务。这类任务直到最近随着深度神经网络的出现才成为可能。

课程技术基础:Python语言

了解了AI的概念与历史展望后,我们需要掌握实现它的工具。本课程将使用Python编程语言。

我们将从Python语言的基础开始。随着课程的推进,希望你能够越来越精通Python语言。

总结

本节课中,我们一起学习了人工智能的哲学起源,从笛卡尔和图灵的思考中理解了定义机器智能的挑战。通过回顾《2001太空漫游》和《终结者》等科幻作品,我们看到了早期对AI技术的惊人预见。最后,我们明确了Python将作为本课程探索AI与机器学习实践的主要工具。

03:哲学中的AI-I 🤖

在本节课中,我们将要学习人工智能在哲学思想中的起源。我们将探讨“智能”和“心灵”的本质,并了解历史上哲学家们如何思考这些问题,以及这些思考如何影响了现代人工智能的测试标准。

智能与心灵的哲学追问

如果我们对构建人工智能体感兴趣,首先需要停下来问自己:智能意味着什么?或者说,拥有心灵意味着什么?

这些问题在历史上一直被哲学家们争论不休。

笛卡尔的哲学奠基

一个例子是17世纪的哲学家勒内·笛卡尔。他常被称为西方哲学之父,因为许多现代西方哲学都是直接回应他的著作。

笛卡尔对数学,尤其是几何学也有重大影响,例如我们熟知的笛卡尔坐标系。

笛卡尔有一句名言:“我思故我在”,出自他的著作《第一哲学沉思集》。在这本书中,笛卡尔进行了一项哲学练习:他首先抛弃所有非绝对确定的信念,然后试图确立哪些是唯一可以确定知晓的。

即使像对世界的感知这样的物理体验,也可能是一场梦或由恶魔制造的幻觉。通过“我思故我在”,他提出,一个人的意识意味着他的存在。

身心二元论

与这个想法相关的是身心二元论。这种观点认为,你的心灵是本质元素,是你的精神核心,是构成“你”的那个部分。而这个部分在某种程度上与你的肉体形式,即你的身体,是分离的。

例如,如果你的身体某部分在事故中失去,那并不会使你变得比现在更不像“你”。你仍然是你,你仍然存在。

他心问题

一旦我确定了我存在,我如何知道其他人也存在?如果我无法确定他人拥有心灵,我如何知道他人存在?

如果其他人只是人类的模拟呢?他们可能是自动机。人们的身体和外表可能被机械地复制。我们的身体和动物的身体基本上只是与世界互动和移动的复杂机器。肌肉可以被齿轮、活塞或凸轮等取代。

那么,我如何知道你不是一个极其逼真的人类复制品呢?

历史上的自动机

笛卡尔对这个话题感兴趣的部分原因是,在17和18世纪,有一个庞大的业余爱好者产业,致力于建造栩栩如生的自动机。

  • 左侧:我们有一个18世纪的国际象棋自动机,名为“土耳其行棋傀儡”。它被建造得看起来像是一个能真正下棋的人工智能体。但秘密是,实际上有一个人藏在里面,操纵机械移动棋子。这是一个骗局,但对当时的许多人来说非常具有说服力。
  • 右侧:我们有一个真正的机械自动机,能够写出一首诗并画一幅画。这个自动机现藏于费城的富兰克林科学博物馆。

笛卡尔对可能存在栩栩如生、甚至能以类似我们身体运动方式移动的人类复制品这一想法很着迷。他想要制定一个测试,以确定某人是否是自动机或真正的人。

笛卡尔的测试标准

他得出的结论是,或许区分自动机与人的关键在于,自动机只能以特定的预定方式做出反应。如果你想与这样的机器进行开放式的对话,它不太可能使用人类语言。这在17世纪的自动机中当然是正确的。

但这在今天仍然成立吗?我们将在课程后面看到自然语言生成的最新技术水平。

图灵与智能测试

现在,我们来看看其他一些哲学家,他们提出了类似的测试,以判断某人是否是人类或实际上是自动机。

另一位思考“什么构成智能”以及“什么条件能让我们满意地认为某物是智能的”这一问题的哲学家是艾伦·图灵,他是计算机科学领域的奠基人之一。

艾伦·图灵在第二次世界大战期间,于一个叫布莱切利园的地方,对设计和使用第一台数字计算机起到了关键作用。布莱切利园是英国秘密利用计算机破解德国恩尼格玛密码的地方。艾伦·图灵的这项密码破译工作是第一台现代计算机最成功的应用之一。

艾伦·图灵对人工智能产生兴趣,是因为在20世纪50年代,许多人对计算机着迷,并提出诸如“机器真的能够思考吗?”这样的问题。艾伦·图灵认为这是一个很难直接回答的问题。

图灵测试的提出

由于“思考”太难定义,图灵没有试图直接回答“机器能思考吗”这个问题,而是提出了一个替代方案,后来被称为“图灵测试”。

图灵提出的替代性问题是:一台机器是否有可能如此逼真地模仿人类,以至于人类评判者无法将该机器与真实的人类区分开来?

图灵的想法受到一个名为“模仿游戏”的派对游戏的启发。在模仿游戏中,两个人会去到房子的不同房间,派对上其他人通过发送问题与他们互动。藏在其他房间里的人会打字回复答案,其他玩家必须仅根据这些打字回复来猜测谁是谁。

模仿游戏与图灵提出的测试机器是否智能的构想非常相似。

图灵测试的流程

在图灵测试中,有一位人类评判者与一台计算机或一个人进行互动。在测试过程中,他们通过文本消息进行对话。在会话结束时,评判者必须说出他们是在与人还是在与机器互动。

如果一台机器成功地说服评判者他/她正在与一个人交谈,那么我们就可以说这足以证明机器本身是智能的。如果一个系统能够冒充人类,那么它就是一台会思考的机器。

图灵测试的本质在于“通过”这个概念,即冒充你本不是的事物,并说服他人相信你是与你真实身份不同的东西。

图灵的个人悲剧

这个概念对艾伦·图灵来说实际上相当悲剧。艾伦·图灵是同性恋者,而当时在英国,同性恋是非法的。图灵被发现与另一名男子有染,并被定罪。结果,他被判处化学阉割作为监禁的替代方案。这是一种通过操纵你的激素和情绪来实施的极其可怕的事情。最终,图灵自杀了。

由于他在布莱切利园的工作是政府严格保守的秘密,直到近50年后,他对计算机科学的贡献才最终得到认可。在这些努力被解密后,人们才知道,艾伦·图灵领导的密码破译工作通过破解德国恩尼格玛密码,有效地使盟军得以提前结束第二次世界大战。

直到21世纪,英国才真正认识到它对艾伦·图灵犯下了多么严重的不公。他本应被视为民族英雄,而不是被当作罪犯对待。


本节课总结:本节课我们一起学习了人工智能的哲学起源。我们从笛卡尔对“我思故我在”和身心二元论的探讨开始,理解了他对智能本质的思考以及区分人与自动机的早期尝试。接着,我们重点学习了艾伦·图灵提出的图灵测试,这是一个通过判断机器能否在对话中冒充人类来评估其智能的经典方法。我们还了解了图灵本人的生平及其悲剧,这为理解图灵测试中“通过”概念的深层含义提供了背景。这些哲学思考为后续我们理解现代人工智能的目标和挑战奠定了基础。

04:哲学中的AI-II

在本节课中,我们将继续探讨人工智能的哲学基础,重点关注约翰·塞尔对图灵测试的批判,以及他提出的“中文房间”思想实验。我们还将了解基于规则的早期AI系统(如ELIZA)如何运作,并讨论“强AI”与“弱AI”的哲学区分。最后,我们会看到哲学家丹尼尔·丹尼特如何通过一个有趣的假想实验来挑战塞尔的观点。

约翰·塞尔的批判

上一节我们介绍了图灵测试,本节中我们来看看哲学家约翰·塞尔对其提出的挑战。

塞尔认为,图灵测试不足以证明机器拥有真正的智能。他主张,图灵测试可以通过简单的符号操作来通过,而这种操作并非真正的智能。

想象一下,我给机器一个符号,机器只是通过查找该符号并执行一些预定的操作来回应。如果你把我的输入符号想象成对话中的一个回合,比如“你今天怎么样?”,那么机器可能通过查表输出一个看似合理的回答,比如“我很好,你呢?”。

塞尔认为,这种类型的符号操作仅仅是语法层面的。它只是在做一些基础的事情,类似于正则表达式转换。一个遵循语法规则的机器并不真正理解对话的含义

如果你同意塞尔的观点,那么仅仅表现出对话的能力,并不足以证明某物真正拥有智能。

中文房间思想实验

为了阐明他的观点,塞尔提出了一个著名的思想实验,称为“中文房间”。

这个实验设想有一个人在一个房间里工作,他接收用中文写成的信息,然后生成同样用中文写成的回复。这个人并不懂中文;他手边有一本厚厚的规则手册,告诉他当看到特定形状的符号(输入)时,应该输出哪些特定形状的符号(输出)。他只是在机械地遵循符号操作规则。

这个实验传达的信息是:即使我们能够构建一个通过符号操作来产生看似合理对话的系统,我们可能也不会认为它的行为构成了智能行为。这就像房间里的人看着中文符号来想出一个好的中文回复,但他实际上并不理解中文。

基于规则的系统实例:ELIZA

以下是早期人工智能系统的一个著名例子,它使用基于规则的响应来模仿对话。

最早的著名AI系统之一是一个名为ELIZA的程序。ELIZA是一个模拟的心理治疗师,它模仿了一种称为“罗杰斯式”的心理治疗方法。在这种疗法中,你向治疗师诉说你的感受或困扰,而他们通过提问来回应。

罗杰斯式心理治疗很容易被模仿。你可以假装成一个罗杰斯式治疗师,只需把某人说的话转换成一个问题。事实上,这正是早期程序ELIZA的工作方式。

这是一个ELIZA与真人(本例中是我)交互的示例记录:

  • ELIZA:我是心理治疗师。请描述你的问题。每次你说完话,只需按两次回车键。
  • 用户:我感到非常孤独。
  • ELIZA:你为什么说你感到非常孤独?
  • 用户:我觉得我几乎一年没离开过房子了。
  • ELIZA:是什么让你相信这一点?
  • 用户:全球大流行,我害怕感染病毒。
  • ELIZA:也许你应该咨询医生。我只是心理治疗师。
  • 用户:我为不能见到母亲而感到难过。
  • ELIZA:跟我说说你的家庭。

你可以看到,ELIZA只是以一种确定性的方式转换用户输入来生成其响应。ELIZA的架构与“中文房间”的符号操作实验类似,而塞尔认为,这并非智能。

强AI与弱AI

塞尔的符号操作思想引出了“强人工智能”与“弱人工智能”的区分。

  • 弱AI:一个并非真正智能,只是表现出智能表象的系统。塞尔认为,像ELIZA这样的系统就是弱AI。
  • 强AI:一个真正拥有意识、理解和心智的智能系统。

塞尔进一步假设,人类大脑中必定有某种东西使我们拥有智能,并主张生物大脑是拥有智能的必要基础。然而,这个论点受到了其他哲学家的挑战。

丹尼尔·丹尼特的挑战

哲学家丹尼尔·丹尼特通过一个有趣的假想实验来反驳塞尔关于生物大脑是智能必要条件的观点。

在这个思想实验中,丹尼特想象自己被美国国防部招募去执行一项绝密任务:拆除俄克拉荷马州地下的一枚炸弹。由于炸弹泄漏大量辐射,军方无法派人直接维修,因为辐射会损伤大脑。于是他们提议,先将执行任务者的大脑取出,放在远处的一个容器里,然后用微型无线电收发器替换所有连接大脑与身体的神经元。

丹尼特自愿接受了这个任务。他的大脑漂浮在容器中,而他的身体则前往俄克拉荷马州。在拆除炸弹的过程中,他的身体受到辐射严重损坏,大脑与身体之间的所有神经无线电链接都中断了。他的大脑作为一个有意识的实体仍然存在于容器中。

后来,科学家们为他“复活”了一个新的合成身体,并且连同一个完全复制其原大脑信息流和计算水平的合成大脑。那么问题来了:那个生物大脑对于他拥有自我意识和与世界互动来说,真的是必要的吗?

这个实验旨在说明,智能可能更关乎信息处理的结构和模式,而非承载它的特定生物基质。

总结与课程方向

本节课中,我们一起学习了约翰·塞尔对图灵测试和符号操作AI的批判,了解了“中文房间”思想实验和早期AI程序ELIZA的工作原理。我们还探讨了“强AI”与“弱AI”的哲学区分,以及丹尼尔·丹尼特如何挑战生物大脑是智能必要前提的观点。

大多数人工智能研究者并不关心“强AI”假说。只要他们的程序能工作,他们并不真正在乎这是智能的模拟还是真正的智能。这不会是一门关于哲学的课程,本节内容已是我们将涉及的最哲学的部分。

像强AI与弱AI这样的概念,更多是一个哲学难题,而非已融入主流人工智能研究的问题。因此,我们将把“是什么使我们成为智能生物”以及“宣布一个系统智能的必要条件是什么”这些基础问题留给哲学家们去探讨。

在本课程中,我们将最终更多地关注实用的算法,这些算法将让我们能够构建出实现某些智能元素的程序。

05:通用人工智能 🤖

在本节课中,我们将要学习通用人工智能(AGI)的概念,并探讨其与哲学思考及实际人工智能研究之间的关系。

概述

本节内容将介绍哲学家对人工智能的思考,对比人类思维与模拟思维的区别,并回顾人工智能研究领域从追求通用智能到专注于具体机器学习任务的转变。最后,我们将讨论近年来通用人工智能概念如何重新引起学界关注。

哲学家的思考

哲学家在思考人工智能时,会探讨一些非常引人入胜的问题。

他们思考如何区分人类思维的工作方式与模拟思维可能的工作方式。

他们会提出这样的问题:如果你的大脑被从身体中取出,放入一个营养丰富的容器中,然后所有通过感知系统传入大脑的电脉冲都被模拟宇宙的计算机探针所取代。

那么,你作为容器中的大脑所产生的思考,与你作为人类时的思考是否相同?

如果相同,那么这与人工智能程序通过其自身的电脉冲反映其所见世界时进行的思考,在本质上又有何不同?

研究重点的转变

上一节我们介绍了哲学家对通用人工智能的抽象思考,本节中我们来看看实际研究领域的侧重点。

这类问题虽然引人入胜,但人工智能研究人员往往不会过多思考它们。

人工智能研究人员通常更关注人工智能的实际应用,并思考如何设计能够运行的程序。

数十年来,人工智能领域专注于非常具体的子问题,而非试图解决通用人工智能的问题。

事实上,该领域在几十年里基本上将自己重新命名为“机器学习”。

该领域专注于那些可以被设定基准、并且其结果可以像排行榜一样进行分析的具体问题。

例如,“你能识别照片中出现什么物体”这样的问题,成为了我们实现开发真正人工智能系统这一更宏大目标的替代品。

随着研究重点转向机器学习而非通用人工智能,该领域的许多人将我们之前提出的哲学问题暂时搁置了。

如果你有兴趣探索这些问题,我推荐播客“Philosophize This!”,它经常探讨与通用人工智能相关的问题。

通用人工智能的回归

尽管该领域多年来专注于自包含的机器学习任务,但在过去几年里,我们可能实现通用人工智能的观念已开始重新回到对话中。

2022年,一名谷歌员工开始担心他们的大型语言模型系统(当时称为LaMDA)似乎显示出感知的迹象,或者表现出你可能期望一个真正能推理的智能体所表达的东西的迹象。

当然,他没有去找他的上司谈论他的担忧,而是去找了《华盛顿邮报》,并随即被解雇。

此人的想法受到了该领域一些人的嘲笑,但我认为我们都已更接近这样一种立场:也许通用人工智能并不像我们曾经认为的那样遥远。

我自己在使用GPT-3时就有过一次相当深刻的体验,我通过其私人测试版获得了早期访问权限。

它生成类人文本的能力确实不可思议,与我过去20年在自然语言处理研究中所见的任何东西都不同。

新的研究探索

现在,人工智能研究人员开始更认真地探讨这些问题。

这个来自微软研究院的团队早期接触了GPT-4,并通过审视它是否展现出拥有通用人工智能所需的前提属性这一视角,探索了其能力。

这篇论文中让我觉得非常有趣的一点是,GPT-4似乎拥有某种“心智理论”。

“心智理论”是指你理解与你交谈的人拥有与你不同的世界表征和感知,并且你创建了一个关于他们对世界看法的内部模型。

GPT-4似乎具备一些可能暗示其拥有这种能力的特性。

这确实非常惊人,并将我们带回了哲学与人工智能的领域。

总结

本节课中我们一起学习了通用人工智能的概念。我们探讨了哲学家对其本质的思辨,回顾了人工智能研究历史上从宏大目标到具体机器学习任务的务实转变,并了解了随着大型语言模型的出现,关于机器是否具备真正推理与感知能力的讨论如何再次成为前沿话题。理解这些背景有助于我们把握人工智能领域的现状与未来可能的发展方向。

06:科幻中的AI 🚀

在本节课中,我们将探讨人工智能在科幻作品中的起源和描绘。科幻不仅激发了公众对AI的想象,也常常预示了技术发展的方向。我们将看到,许多科幻作品的核心主题——如如何定义人类、如何与智能体互动——直接呼应了AI领域的哲学与技术挑战。

除了哲学渊源,人工智能还深深植根于悠久的科幻传统。

上一节我们讨论了何为人工智能,以及如何设计一个智能体。本节中,我们来看看科幻作品如何描绘这些智能体。之前我们谈到,设计一个智能体可以有以下几种目标:使其像人一样思考、像人一样行动、理性地思考或理性地行动。

科幻作品中一个常见的主题是,试图创造出能以类人方式行事的智能系统。

以下是一些著名的科幻作品如何描绘这一主题:

  • 《星际迷航:下一代》:其中的角色“数据”是一个安卓机器人,他的人生目标是尽可能像人类一样行事。他缺乏我们认为构成人性的许多要素,例如情感。他还有一些奇怪的癖好,比如出于某种原因,他不能使用缩写,必须说“cannot”而不是“can't”。
  • 《西部世界》:这部HBO剧集(改编自1970年代同名电影)设定在一个仿照美国西部建造的主题公园,里面充满了人工智能体。人类游客在此实现幻想,并以极其可怕的方式对待这些AI系统,因为他们认为AI并非真人,只是被制造得看起来和行动像人。该剧的核心主题探讨了何以为人、何以为奴,以及AI系统是否可能具备足够的人性,从而应被视为人类并享有相应的尊重与尊严。
  • 《太空堡垒卡拉狄加》:在这个科幻系列中,AI系统作为潜伏者混迹于星际飞船船员之中。被称为“赛隆人”的机器人制造得如此先进,以至于与人类几乎无法区分。该剧也是对当时新闻中恐怖主义等事件的寓言,飞船上弥漫的对赛隆人的猜疑,类似于人们可能曾有的“潜伏者就在身边”的感觉。
  • 《银翼杀手》:这部电影直接探讨了人类如何辨别互动对象是人还是自动机器(复制人)。影片围绕一名追捕逃亡复制人的侦探展开,这同样是一个关于AI系统逃离人类控制并试图伪装成人的叙事。片中使用的“沃伊特-坎普夫测试”非常类似于图灵测试,直接映射了关于人工智能的哲学问题:如何判断某人是否是自动机器?这呼应了笛卡尔关于设计测试来检验某人是否为自动机器的想法。事实上,电影直接引用了笛卡尔,主角的名字“德卡德”显然是对“笛卡尔”的轻微改动。

科幻与人工智能有着美妙的联系,它常常预见AI领域的发展方向,并在相关技术真正实现前的几十年就想象出可能性。

有许多实例显示,科幻向我们展示了AI未来可能实现的能力,并在电影上映几十年后成为现实。

以下是《终结者》中的一个片段,展示了机器人的平视显示器。这是透过机器人眼睛看到的视图,你可以看到它所看到的景象以及它正在执行的计算机视觉任务,比如物体识别。你会看到它识别了一辆摩托车,读取了标志上的文字,识别了人物并进行扫描、估算其体重和身体尺寸。事实上,这个场景中,终结者全身赤裸地在酒吧里走动,寻找一个体型与自己相同的人,以便拿走他的衣服融入社会。(至于为何机器人能时间旅行却不能带上衣服,原因不明。)

《终结者1》和《终结者2》中展示的技术(拍摄于1980年代和1990年代初),在当时是科幻。随着人工智能的不断进步,终结者系列电影中的许多元素如今已成为科学事实。幸运的是,不是谋杀机器人那部分;遗憾的是,也不是时间旅行那部分。

过去几年,我们在计算机视觉领域取得了惊人的进展。我们现在能够进行图像分类,将图像输入计算机视觉系统,它就能告诉我们其中包含什么物体,比如这张照片中的人、一些羊和一只狗。计算机视觉可以在这些物体周围绘制粗略的边界框,或进行精确的分割,以指示照片中哪些像素对应这些物体。这正是《终结者》平视显示器中发生的事(当时是手绘动画)。如今,通过计算机视觉,终结者那种对图像进行推理的能力已成为可能,这非常了不起。你的智能手机现在可以自动识别数千种物体。在这些计算机视觉进步之前,你必须手动给照片添加标签才能搜索其中的内容。现在,你可以搜索照片中的任何东西,从扶手椅到摩天大楼,正是因为计算机视觉变得如此出色,以至于可以部署在智能手机上。

还有许多其他领域,我们已经从科幻跨越到了科学事实。有时,科幻作者想象的某些技术的用途与现实大相径庭。

我的一个朋友开了个关于《银翼杀手》中沃伊特-坎普夫测试的玩笑:面试官问里昂:“你准备好测试了吗?”里昂说:“我准备好了。”而在现实中,测试更像是这样:我们现在被要求通过挑出所有包含交通灯的方块来证明我们是人类。实际上,这就是我们现在被要求证明自己是人类的那种测试。这是谷歌验证码的一个例子,当你注册网络账户时,它会弹出,迫使你证明自己是人类而不是机器人。验证码是“全自动区分计算机和人类的公开图灵测试”的首字母缩写,并且常常导致相当程度的挫败感。

还有其他例子表明,科幻对计算机能力的想象走在了现实可能性的前面。

这是一部1980年代的电影,叫《战争游戏》。一个大学年龄的年轻人黑进了一个计算机系统,发现它可以下棋和一些其他游戏。其中一个游戏叫“全球热核战争”。然而,这并非游戏,实际上是计算机在管理美国的核武库。在这个场景中,计算机即将对俄罗斯发动攻击,控制室里的人们拼命想办法阻止它。这是一场与时间的赛跑,因为计算机正在破解核发射密码的加密。在计算机试图破解加密的同时,他们让它开始玩井字棋游戏。他们将玩家数量设置为0,让计算机自己跟自己下。他们希望说服计算机认识到,井字棋没有必胜策略。计算机学到了井字棋无法获胜,并由此推断出,全球热核战争也没有好的获胜策略。

本节课中,我们一起学习了人工智能在科幻作品中的丰富描绘。我们看到,从《星际迷航》的数据到《西部世界》的宿主,从《银翼杀手》的复制人到《终结者》的视觉系统,科幻不仅提出了关于智能、人性和伦理的深刻问题,也常常惊人地预见了技术发展的轨迹。许多昔日的科幻构想,如计算机视觉和自动化测试,如今已成为我们日常生活的一部分。理解这些科幻叙事,有助于我们更好地思考当前AI技术的发展及其对社会的影响。

07:科幻中的AI-II

概述

在本节课中,我们将继续探讨科幻作品对人工智能发展的影响,并了解这些虚构概念如何逐步转变为现实技术。我们将回顾AI在游戏领域的里程碑,分析科幻电影中的AI设想,并介绍推动这些技术实现的关键研究项目。

游戏作为AI的试金石

上一节我们讨论了科幻作品中AI的早期形象,本节中我们来看看AI在现实世界中的一个经典应用领域:游戏。数十年来,计算机进行游戏对决一直是人工智能研究的核心课题。

多种游戏都曾作为AI的挑战性问题。在20世纪90年代末,IBM设计了一个名为深蓝的人工智能系统,它击败了国际象棋特级大师加里·卡斯帕罗夫。当时人们认为国际象棋需要人类的智慧,但深蓝证明了这是错误的。

一台下棋机器超越了世界上最好的人类棋手。如今,人类棋手基本上总是被机器彻底击败。

从国际象棋到危险边缘

2013年,IBM在AI游戏系统方面取得了另一项成功。他们设计了一个名为沃森的问答系统,用于参加电视智力竞赛节目《危险边缘》。

要在《危险边缘》中获胜,需要能够根据线索推断并回答琐碎问题。沃森在一场正面交锋中击败了保持该节目最长连胜纪录的肯·詹宁斯。

围棋:更宏大的挑战

2016年,谷歌DeepMind开发的一个名为AlphaGo的系统击败了围棋世界冠军李世石。围棋之所以有趣,是因为其可能的走法空间和棋盘配置空间远大于国际象棋棋盘上的配置空间。

因此,这是一个更具雄心的挑战,因为它需要AI系统为寻找游戏的可能解决方案而探索多得多的潜在配置。这个空间如此之大,以至于无法穷尽地探索所有可能的解决方案。

事实上,即使是国际象棋,也无法对其所有可能的解决方案进行穷举搜索。穷举搜索只适用于走法更有限的游戏,例如井字棋或跳棋。

在本课程的搜索模块中,我们将讨论游戏对弈、寻找最佳下一步的搜索,以及无法在整个可能走法空间中进行搜索所带来的影响。

科幻中的理性AI设想

在电影《2001太空漫游》中,有一个名为哈尔9000的机器人,负责控制宇宙飞船。有趣的是,电影制作人将哈尔表现为一个无形的声音。

以下是与哈尔进行访谈的电影片段。这个片段关联到那些被设计为理性思考的AI系统的理念。哈尔声称自己是完美的,不会犯错。但事实证明这并非事实。实际上,在电影后期,它最终谋杀了船员。

《2001太空漫游》于1968年上映,远在个人电脑出现之前。电影制作人对未来的计算技术有一个愿景。他们的愿景包括可以与计算机对话、计算机能够推理你所说的话,然后用自然语言回应的想法。

科幻成为现实

这个想法如今已渗透到我们的日常生活中,例如亚马逊的Alexa等设备。你可以发出像“Alexa,打开我的灯”这样的命令。这与40多年前科幻电影中设想的“关闭舱门,哈尔”的能力非常相似。

我们还有许多其他科幻想法已经转化为现实。这是《星球大战》中的C-3PO。他的角色是一个懂得数万种语言的翻译员。

C-3PO就像现在的谷歌翻译。

科幻已经变成了科学事实。这是我在《星球大战》中最喜欢的角色,R2-D2。他能做什么?嗯,实际上有点难说。它似乎并没有真正做什么。

所以也许它更像一个Roomba(扫地机器人)之类的。

DARPA:推动AI前沿

人工智能前沿技术得以推进的一种方式是通过研究投资。美国AI研究的一个重要资助机构是一个名为DARPA的机构,即国防高级研究计划局。

DARPA自20世纪60年代以来一直在投资AI研究,并在2018年宣布将投入20亿美元用于AI研究。我本人的许多学术资金也来自DARPA。事实上,许多语言技术,如谷歌翻译、苹果Siri,都得益于DARPA的项目。例如,谷歌翻译就源于我在21世纪初参与的一个DARPA项目。

从挑战赛到自动驾驶

许多自动驾驶汽车技术可以追溯到2005年的DARPA大挑战赛。最初的大挑战是让全自动驾驶汽车在几条预定路线之一上穿越沙漠。

有5支队伍完成了比赛,他们的汽车完全自主地在沙漠中行驶。斯坦福大学以不到7小时的时间完成了路线。

几年后,DARPA赞助了城市挑战赛。与在沙漠中驾驶不同(在那里撞上东西也没什么大不了的),这次是让汽车在一个军事基地上行驶,风险要高得多。自动驾驶车辆必须应对其他更重大的障碍。

这张照片展示了宾夕法尼亚大学参加城市大挑战的参赛车辆。宾大是2008年实际完成城市大挑战的六支队伍之一。目前,自动驾驶汽车感觉即将到来。有几家公司已经将这项技术商业化,并试图让它成为我们日常生活的一部分。

机器人挑战

随着自动驾驶汽车变得越来越可行,DARPA已经开始应对更大的挑战。他们有一个名为机器人挑战赛的项目。在这个挑战中,研究人员必须设计能够完成诸如搬运锤子、拧水龙头和开门等任务的人形机器人。

尽管这些任务看起来很基本,但事实证明,机器人完成它们超级困难。这里有一个相当有趣的失误集锦,向你展示机器人完成这些任务到底有多难。

就像自动驾驶汽车因DARPA大挑战而进步一样,人形机器人也随着时间的推移变得更好,现在可以很好地完成这些任务。

一家名为波士顿动力的公司生产性能非常强大的人形机器人和四足机器人。他们的机器能够完成诸如举重、在崎岖地形上行走以及从意外干扰中恢复平衡等任务。

总结

本节课中,我们一起学习了科幻构想如何引领人工智能技术的发展。我们看到AI在游戏领域不断突破,从国际象棋到围棋;分析了《2001太空漫游》等科幻作品中对人机交互的前瞻性设想,这些设想如今已通过智能语音助手成为现实;最后,我们了解了DARPA等机构通过设立重大挑战赛,在推动自动驾驶、机器人等尖端技术从科幻走向现实的过程中所起的关键作用。许多来自科幻的激动人心的想法最终都变成了科学事实。因此,如果你想了解人工智能的未来可能是什么样子,可以看看科幻作品中那些富有想象力的事情。

08:Python复习-概述 🐍

在本节课中,我们将对Python语言进行一个温和的介绍。我们将探讨Python的起源、可用的编程环境以及其核心语言要素。通过本教程,初学者能够理解Python的基本概念和优势。

Python的历史与设计目标

上一节我们介绍了本模块的学习内容,本节中我们来看看Python语言的背景。

Python由吉多·范罗苏姆于1989年开始开发。其最初的灵感来源于荷兰国家数学与计算机科学研究所开发的一种名为ABC的语言。正如其名ABC所示,该语言旨在设计得非常简单,以便非程序员学习。许多具备计算机素养的科学家并非计算机科学家,他们可能从事物理、社会科学或语言学等其他学科。ABC语言背后的理念是剔除所有使编程语言入门困难的因素。

1999年,吉多向DARPA提交了一份名为“为所有人的计算机编程”的资金提案。在提案中,他阐述了Python的设计目标:

  • 首先,它应该简单直观,并且与主要竞争语言一样强大。
  • 其次,它应该是开源的,以便任何人都能为其开发做出贡献。
  • 第三,它应该像普通英语一样易于理解。
  • 第四,它应该适合日常任务,允许很短的开发时间。

Python的设计目标包括能够实现复杂程序的快速原型设计。Python在这方面取得了成功,部分原因在于其语法非常简洁、紧凑和直观,使得编写Python代码超级容易。还有其他原因使得在Python中进行原型设计很容易。与其他现代编程语言一样,Python具有自动垃圾回收功能,这意味着您不必像在C这样的旧语言中那样自己进行内存分配和释放。

Python的另一个优势是您几乎可以在任何平台上运行它而无需更改代码。Python内置了许多有用的类型,包括字典和集合等,这些对于构建更大、更复杂的算法(如我们将在人工智能中研究的算法)非常有用。随着时间的推移,Python还积累了大量的第三方库,这些库易于整合到您自己的代码中。许多这些外部包与数据科学、人工智能和机器学习相关。

吉多·范罗苏姆幽默地宣布自己为Python的“终身仁慈独裁者”。他建立了一种机制,允许其他人就应将哪些内容纳入Python语言的下一版本提出建议。这些建议被称为PEP,即Python增强提案。PEP 8是编写Python代码的官方风格指南。它讨论了如何一致地格式化代码,使其对所有使用Python语言的人来说看起来都很熟悉。它包括诸如应使用空格而非制表符进行缩进、变量名应使用下划线分隔单词而非驼峰式命名法等细节。遵循PEP 8风格指南将有助于您的代码保持一致的风格。代码被阅读的频率远高于被编写的频率,因此投入时间使您的代码对他人可读非常重要且值得。

Python编程环境

上一节我们了解了Python的历史,本节中我们来看看可以使用的各种Python环境。

创建和运行Python代码有许多不同的方式。一种称为REPL环境。REPL代表读取、求值、打印循环。要开始使用REPL环境,您只需在计算机上打开终端应用程序,并在shell中键入python。REPL环境是测试语言不同元素的有用工具。

请注意,您应该知道Python有许多不同的版本。

您也可以编写自己的Python脚本,然后从命令行运行它们。您可以使用您喜欢的文本编辑器,将文件保存为.py文件。然后通过在终端中键入python后跟脚本名称来运行Python脚本。Python将运行您的脚本并打印出它生成的任何输出。

除了在您想要的任何文本编辑器中编写Python代码并在命令行上运行之外,您还可以使用IDE。

IDE代表集成开发环境。使用IDE的一个优势是它有许多功能可以帮助您进行调试。您可以设置断点并检查变量的内容,而不是简单地在代码中到处散布打印语句。如果您以前从未使用过集成开发环境,那么花时间安装一个并学习如何使用其调试器是值得的。我建议现在花时间在线做一些关于如何使用调试器的教程。调试器是软件工程师的一种强大工具。使用调试器将是一项有用的技能,无论是对于您当前的课程还是未来的职业生涯。

我个人最喜欢的与Python交互的方式是使用Python笔记,也称为Jupyter笔记本。它们允许您将代码块与文本块混合,并且您可以使用Markdown格式化语言格式化文本,这还允许您插入图像和数学公式。您可以在自己的计算机上安装Jupyter笔记本,也可以在线运行它们。

Python的简洁性与语法特点

上一节我们介绍了不同的编程环境,本节中我们通过对比来感受Python的简洁性及其独特的语法。

让我们看两个简单的程序,一个用Java编写,一个用Python编写。您可以看到Python程序非常简单。要在Python中编写经典的“Hello World”程序,您只需键入:

print("Hello world")

另一方面,在Java中,您必须创建一个类,用与该类相同的名称命名您的文件,创建一个main方法,并调用System.out.println。因此,您可以看到这个Java程序有许多元素对于第一次编程的人来说是难以接近的。

Python与您可能遇到的大多数其他语言不同的一个有趣之处在于,空白符是有意义的。这是什么意思?我的意思是,Python使用缩进来表示代码块,而不是像在Java中那样用花括号表示。让我们看看那是什么样子。在Java中,我们像在这个if语句中一样用花括号表示块。在Python中,要有一个if语句,您只需编写if、条件语句、冒号,然后后面缩进的所有内容将在该条件语句为真时执行。

核心数据类型预览

在接下来的课程中,我们将深入探讨Python的一些最重要的数据类型,例如序列(包括字符串、列表和元组),然后我们将讨论哈希表(在Python中称为字典)。

本节课中我们一起学习了Python的简要历史、其核心设计目标、多种可用的编程环境(如REPL、脚本、IDE和Jupyter笔记本),并通过与Java的简单对比,了解了Python语法简洁直观的特点,特别是其使用缩进定义代码块的独特方式。这些基础知识为我们后续深入学习Python用于人工智能和机器学习打下了坚实的基础。

09:Python复习-对象与类型 🐍

在本节课中,我们将要学习Python编程语言中关于对象与类型的核心概念。理解这些概念是掌握Python进行数据科学和机器学习工作的基础。我们将从对象的基本定义开始,逐步探讨类型系统、动态类型特性,以及Python中几种重要的内置数据类型,如数字、字符串、列表、元组和字典。

对象与类型基础

在Python中,所有数据都被视为对象。当一个对象变得不可访问时,它会被垃圾回收机制删除。

Python是一种强类型语言,这意味着每个对象都有一个固定的类型,解释器不允许将与该类型不兼容的事物组合在一起。例如,不能尝试将字符串与整数组合。

如果你想查看对象的类型,可以使用 type() 函数。或者,你可以使用 isinstance() 方法来检查特定对象是否属于特定类型。

x = 10
print(type(x))  # 输出: <class 'int'>
print(isinstance(x, int))  # 输出: True

动态类型与静态类型

虽然Python是强类型的,但它与Java的一个区别在于:Python是动态类型的,而Java是静态类型的。

在Java中,声明变量时也必须声明该变量的类型。例如,要创建一个整数 x,必须在首次创建时声明 x 是整数。同样,如果要声明字符串 y,必须指明它是字符串。

在Python中,则不需要这种静态类型声明。我可以创建一个变量 x,当它通过被赋值为字符串 "foo" 而存在时,它会被动态地确定为字符串类型。随后,我可以通过在代码中稍后写一条 x = 2 的语句,将变量 x 重新赋值为不同的类型(从字符串变为整数)。每次更改变量赋值时,类型都会自动确定和更新。

Python与Java的另一个区别是,在Java中,方法具有类型签名。定义方法时,会说明其返回类型,或使用 void 关键字明确表示没有返回类型。同时,也会定义方法每个参数的类型。

在Python中,这不是必需的。函数没有类型签名,它们不会告诉你返回类型是什么,也不会告诉你每个参数的类型是什么。这使得在Python中定义函数更容易,但缺点是类型错误只在运行时才会被捕获。因此,如果传入一个类型不正确的变量,它不会在编译时被捕获,只会在运行代码时被捕获。

数学基础

Python支持各种数学字面量,如整数、浮点数和布尔值。你可以用多种不同的方式声明它们。例如,可以使用 2e9 这样的表示法来声明对应20亿的浮点数。

Python支持各种数学运算符,如算术运算符、幂运算符(用 ** 表示)、取模运算符(用 % 表示,会给出余数)。数学比较运算符如小于、等于、大于或等于、不等于的写法符合预期。逻辑运算符如 andornot 是写出来的,而不是像在其他语言中可能看到的用符号表示。

你可以使用 += 运算符来递增数学变量的计数,例如,可以说 x += 1。然而,Python不支持 ++-- 这样的单元运算符。

字符串操作

在Python中创建字符串很简单。你可以使用单引号或双引号来声明字符串。对于多行字符串或用作文档字符串的字符串,可以使用三引号这种特殊语法。

字符串可以使用 + 运算符连接在一起,该运算符被重载以同时用于数字和字符串。

与其他编程语言一样,一些特殊字符以反斜杠字符为前缀。例如,\n 表示换行。如果你需要一个包含序列 \n 的字符串,而不是通过添加另一个反斜杠来转义该特殊字符,你可以在字符串声明前添加一个 r,这意味着该字符串是原始字符串,你不需要转义特殊字符。

Python还支持使用百分号进行特殊的字符串格式化。例如,可以声明一个包含多个占位符的字符串,如 %s 代表字符串的占位符,%d 代表整数的占位符。然后,可以使用 % 运算符传入一个参数列表,以便格式化字符串。

字符串本身是不可变的,这意味着当你创建它们时,它们只被创建一次。当你修改它们时,例如通过将它们连接在一起,会创建一个全新的字符串,而不会更新内存中的原字符串。

字符串的不可变性对你检查两个字符串是否相等的方式有影响。在Python中有两种不同的检查相等性的方法:== 会比较两个字符串并检查它们的值是否相同;is 运算符检查两个变量是否指向内存中的同一个对象。

例如,如果我创建一个末尾带空格的字符串 x = "f ",然后设置 y = x,那么 ==is 运算符都会返回 True,因为它们的值相同,并且指向内存中的同一个字符串。如果我随后对字符串 x 使用 strip() 操作符,那将创建一个全新的对象。因此,== 运算符会返回 True,但 is 运算符会返回 False

列表与可变性

列表是可变的。如果我创建一个包含整数 [1, 2, 3, 4] 的列表 x,并将变量 y 设置为等于变量 x,那么它们都指向内存中的同一个位置。如果我向列表 x 的末尾追加一些内容,append() 操作符只会更新同一个对象,而不是像字符串操作符那样创建一个新对象。因此,如果我查看变量 y 的内容,会发现它也被更新了。

如果我需要创建列表的副本,可以使用切片操作符(我们稍后会看到),我可以复制 x,这将创建一个包含与 x 相同值的全新对象。

Python内置序列类型

Python有三种内置的序列类型:元组列表字符串。这三种类型共享相同的语法来访问其中的元素。它们的不同之处在于是否可变,以及是否为特定类型的序列进行了专门化。

  • 元组:是一个简单、不可变的有序项目序列。不可变意味着元组在创建后不能被修改。元组中的项目可以是混合类型,因此可以混合整数和字符串,甚至集合类型。
  • 字符串:与元组类似,字符串是不可变对象。然而,字符串不能是混合类型,它们是字符序列。在Python中,常规字符串是Unicode字符序列。在旧版本的Python中,字符串是8位字符,意味着只能表示ASCII字符。
  • 列表:与元组和字符串不同,列表是可变的有序项目序列。像元组一样,它们可以是混合类型。

声明它们的方式略有不同:声明元组使用圆括号 ();声明列表使用方括号 [];声明字符串使用引号 ""''

创建序列变量后,可以使用 [ ] 表示法访问其中的项目。例如,如果想访问第二个元素,可以说 [1],因为Python序列的索引从0开始。Python还允许你从列表的右侧访问序列中的元素,使用 [-1] 来获取列表中的最后一个元素。

Python扩展了用于访问序列中元素的 [ ] 表示法,也允许你访问子序列。你可以使用 [起始索引:结束索引] 表示法指定一个范围。结束索引是排他的,意味着不选择该元素。这种表示法称为切片,它返回子序列的副本。

切片表示法非常灵活。例如,它允许你使用负索引从序列的右侧开始计数。它还允许你隐式省略两个数字中的第一个或第二个。如果省略第一个数字,它将从序列的开头开始。如果省略最后一个数字,它将一直到序列的末尾。切片操作符甚至允许你通过添加第三个参数来选择每隔n个项目。

列表操作

列表是Python内置的三种序列类型中唯一可变的。以下是你可以对列表执行的一些操作:

  • 追加元素:使用 append() 方法将项目添加到列表末尾。
  • 插入元素:使用 insert() 方法在特定索引处插入元素。
  • 查找索引:使用 index() 方法查找元素的首次出现位置。如果该元素在列表中任何地方都找不到,它将返回 -1
  • 计数:使用 count() 方法计算元素出现的次数。
  • 删除元素:使用 remove() 方法删除元素。
  • 排序与反转:Python列表也允许对列表进行排序和反转。sort() 方法会原地排序列表,意味着它不会创建列表的新副本。如果你确实想要一个列表的副本,可以使用 sorted() 函数,它将返回一个排序后列表的副本。你也可以向 sort() 方法传入某个函数,以使用你自己定义的比较方法对列表进行原地排序。

字符串操作

字符串有一组特殊的操作符:

  • 分割:使用 split() 操作符将字符串分割成单词,它接受一个参数,即你想要分割的字符。这将返回一个由该字符分隔的字符串标记列表。
  • 连接:使用 join() 操作符执行与分割相反的操作,传入一个要连接在一起的标记列表。
  • 其他操作:字符串还支持各种操作符,用于将字符串大写、删除尾随和前导空格等。

字典:键值对映射

除了序列类型,Python还提供了一个称为字典的内置映射,允许轻松存储和操作键值对。

与我们看过的序列类型不同,字典是无序的。它们提供恒定的平均时间查找,以将键与值关联起来。它们通过哈希表实现这种恒定时间查找。因此,键必须是不可变的。

你可以使用花括号 {} 初始化一个Python字典。键值对被指定为两个项目,中间用冒号分隔,多个键值对之间用逗号分隔。

为了查找与键关联的值,只需使用我们在序列类型中用于按索引查找的方括号表示法。例如,如果我有这个字典 d,我可以通过 d["user"] 来查找与键 "user" 关联的值。

你只能通过键查询Python字典,而不能通过值查询。如果你尝试在这里查询一个值,比如 "R2D2",那么你会得到一个 KeyError,因为 "R2D2" 是一个值,而不是一个键。

将值与键关联或覆盖现有键的值的语法是相同的。我们说 字典[键] = 值,这将更新字典中的键值对。

字典有几个有用的方法:

  • keys():调用字典的 keys() 方法可以获取字典当前键的列表。
  • values():类似地,调用 values() 方法会给你当前值的列表。
  • items():你还可以使用 items() 方法获取字典中所有项目的列表。它返回一个元组列表,其中第一个元素是键,第二个元素是关联的值。

Python内置的 collections 包也有一些专门的字典:

  • 默认字典:称为 defaultdict,它会自动初始化不存在的字典值。因此,如果你搜索字典中尚不存在的键,字符串的默认字典将返回空字符串。你也可以为整数创建默认字典。
  • 计数器:与整数的默认字典类似的是一个名为 Counter 的类。计数器将为键创建一个默认字典,用于计算这些键的值。因此,如果我查找当前不在我的计数器中的键,它将返回值 0。我可以递增计数器字典中的值,这些值会得到适当的更新。

本节课中我们一起学习了Python中对象与类型的核心概念。我们了解了Python的强类型和动态类型特性,探讨了数字、字符串、列表、元组和字典这几种基本数据类型的特性与操作。理解对象的可变性与不可变性、序列的索引与切片、以及字典的键值对映射机制,是编写高效、正确Python代码的关键。这些基础知识将为后续学习更复杂的数据结构和算法打下坚实的基础。

10:任务环境与Python复习 🧠💻

在本模块中,我们将探讨人工智能的核心目标,并复习本课程将使用的主要编程工具——Python。我们将理解“理性行为”的概念,并学习如何利用Python高效地实现算法。


科幻作品中的“人工智能”常常探讨一个问题:当机器开始以类人的方式行动时会发生什么。

但这真的是人工智能的目标吗?在我们设计自己的人工智能系统时,应该尝试设计那些以类人方式行动或思考的系统,还是应该考虑如何设计能够理性思考和行动的机器?

理性行动这一概念,将是我们本课程大部分内容的研究重点。事实上,我们甚至会以一种你可能适用于自身日常行为的方式,来定义“理性行动”的含义。


上一节我们探讨了人工智能的目标,本节中我们来看看实现这些目标的核心工具。Python是一门出色的编程语言,它能让你快速地对算法进行原型设计。本课程的所有作业都将使用Python完成。因此,本模块将帮助你快速掌握Python,即使你之前从未用它编程过。

当我最初开始使用Python编程时,它带来了一些启示。我认为,这就是编程语言应有的工作方式。

Python摒弃了许多语法格式要求,例如在其他编程语言(如Java)中你可能已经习惯的花括号和复杂的函数定义。Python真正将代码精简到必要的核心部分,通常Python程序看起来就像伪代码,但它们确实可以运行。

如果你希望从事数据科学领域的职业,Python尤其有用。因为许多与数据科学和机器学习相关的算法都以优秀的第三方库形式实现,可以轻松导入到你的Python程序中。

以下是Python的一些关键优势:

  • 语法简洁:代码结构清晰,接近自然语言和伪代码。
  • 生态丰富:拥有大量强大的第三方库(如NumPy, Pandas, Scikit-learn, TensorFlow)。
  • 易于集成:方便导入和使用各种先进算法库。

例如,如果你想训练一个最先进的计算机视觉系统或自然语言处理系统,Python是一门能让这一切变得极其简单的语言。


在本节课中,我们一起学习了人工智能中“理性行动”的核心目标,并复习了Python作为实现工具的主要优势。我们了解到Python以其简洁的语法和强大的生态系统,特别适合用于数据科学和机器学习领域的快速开发和算法实现。在接下来的学习中,我们将运用Python来实践各种理性智能体的构建。

11:理性智能体-I

在本节课中,我们将要学习如何设计人工智能系统。我们将从一个核心概念入手:理性智能体。我们将探讨什么是智能体,什么是理性行为,以及如何将两者结合来构建有效的人工智能系统。

什么是智能体?

上一节我们介绍了构建人工智能系统的一种方法。本节中我们来看看构成这个系统的核心单元:智能体。

一个智能体被定义为任何能够感知其环境并对其采取行动的事物。

智能体用于感知环境的部分称为传感器,用于对环境采取行动的部分称为执行器。智能体从传感器接收到的信号称为感知。一个感知代表了智能体在某一时刻的感知输入,可以表示为一个向量,包含了智能体通过其传感器接收到的所有输入。

除了执行器和传感器,我们还需要考虑智能体与环境的关系。事实上,我们可以为智能体和环境建立一个数学表示。

以下是智能体与环境交互的基本模型:

  • 智能体函数:智能体由一个称为智能体函数的函数来定义。该函数以一系列感知作为输入,并将该序列映射到一系列动作上。
  • 动作集合:动作是从智能体可以通过其执行器执行的一组可能动作中选取的。例如,动作可以是“增加轮子转速”、“打开灯”或“发出声音”。具体的动作集合取决于智能体拥有的执行器。

我们需要区分智能体函数这个数学抽象和我们为实现该函数而编写的智能体程序。智能体程序是在某个物理系统上运行的具体实现。一个智能体函数可以通过各种程序来实现。

最简单的解决方案可以是一个查找表,它将每个可能的感知序列与给定该序列的最佳行动关联起来。然而,如果序列长度无限制或感知组合数量呈指数级增长,这种简单的查找表可能变得不可行。因此,我们将开始开发更复杂的算法来选取最佳行动。

值得注意的是,我们对智能体的定义非常通用,它包含了任何能通过传感器感知环境并通过执行器对其采取行动的事物。因此,智能体可以涵盖极广的范围:

  • 物理实体:如机器人。
  • 软件实体:如监控股市数据流(例如来自雅虎财经)并通过执行交易等操作来影响其环境的智能代理。
  • 人类:我们的感官(视觉、听觉、触觉)是传感器,我们的肢体、手指、嘴巴或声音是执行器。
  • 简单设备:如恒温器。它用温度计感知房间环境,如果温度低于某个阈值,则通过调节锅炉来提高散热器和房间的温度来改变环境。

这就是我们将要使用的智能体的工作定义。

什么是理性行为?

我们已经了解了智能体的概念。接下来,让我们转向理性行为的理念。我们真正关心的不仅仅是构建任何智能体,而是构建理性智能体。那么,我们首先需要问:什么是理性?

我们将从一个定义开始,然后逐步完善它,直到得到一个我们满意的最终定义。

让我们从简单的开始。一个理性智能体是某种感知环境,然后理性行事的智能体。让我们将理性行为定义为做正确的事。显然,做正确的事比做错事要好。

但这引出了一个问题:什么是“做正确的事”?当我们谈论理性行为时,如何定义“正确的事”?

定义“正确的事”

“做正确的事”意味着什么?这实际上是一个非常有趣且复杂的问题。我们可以从哲学路径来探讨。道德哲学对“做正确的事”或“什么是正确的事”提出了几种不同的观点。

人工智能领域通常专注于一种称为结果主义的哲学论点。结果主义的理念是,我们应该根据一个智能体(或一个人)所采取行动的后果来评估其行为。

当你将一个智能体置于环境中时,它会根据感知生成一系列动作。智能体的行为将影响其周围的环境。因此,我们想要说的是:智能体对环境产生的影响是否令人满意?我们可能希望将“做正确的事”定义为让智能体选择那些将导致理想后果的行动。

这是开始完善我们对理性行为定义的一种可能方式。它可以意味着做那些会产生最佳后果的事情。

理性是否需要全知?

如果我们应该选择会产生最佳结果的行动,这是否意味着我们应该有能力精确预见到我们行动的每一个结果?当我们承诺采取某个行动时,似乎不可能确切知道选择的结果会是什么。

想象一下这种情况:你在人行道上看到朋友,于是停下来打招呼。然后,楼上公寓的一个窗式空调机掉下来把你压扁了。你停下来和朋友打招呼的决定是不理性的吗?因为停下来导致了糟糕的后果。

试图选择能带来好结果(比如活下去)的行动显然是可取的,但说你行为不理性是不公平的,因为你根本无法预见到那个结果。

我们需要确保,我们对理性智能体的定义不应该要求全知。它不应该必须能够预见未来,看到每个行动的每个结果会是什么。理性不能要求像神一样的能力来预见“如果我选择这个行动,那么这将是最终结果”。


本节课中我们一起学习了人工智能设计的核心概念:理性智能体。我们首先定义了智能体是任何能够通过传感器感知环境并通过执行器对其采取行动的系统。接着,我们探讨了理性行为的含义,引入了结果主义的观点,即应根据行动的后果来评估行为,并明确了理性智能体的定义不应要求全知,即无需预知所有未来结果。这为后续设计具体算法来实现理性智能体奠定了基础。

12:理性智能体-II

在本节课中,我们将要学习理性智能体的核心概念,特别是如何通过定义性能度量来评估智能体的行为是否理性。我们将探讨经济学中的理性选择理论,并将其与人工智能中的智能体设计联系起来。

理性选择理论与有限理性

经济学领域对理性行为有自己的定义。有一种理论称为理性选择理论,它包含了有限理性的概念。这意味着个体只能基于他们可获得的信息做出决策,因为他们不可能全知全能。理性选择理论由赫伯特·西蒙提出。

以下是他在1953年的开创性论文《理性选择的行为模型》中的一句话总结:“在这篇论文中,我提出了一个模型,用于描述具有有限计算能力的生物体的理性选择。”对我们而言,生物体可能就是智能体。有限的计算能力导致了经济学中的有限理性概念。有限计算能力的概念对人工智能也至关重要。

赫伯特·西蒙是一位经济学家、政治学家和认知科学家。他是唯一一位同时获得诺贝尔经济学奖和图灵奖的人。阿尔弗雷德·诺贝尔在1895年设立诺贝尔奖时,指定每年颁发五个奖项给“在前一年为人类带来最大利益的人”。他选择的五个领域是物理学、化学、医学、文学与和平。当时,计算尚未成为一个独立的领域,因此没有诺贝尔计算机科学奖。与之相当的奖项是图灵奖,赫伯特·西蒙因其对人工智能的贡献也获得了此奖。

理性选择理论是理解经济行为乃至更广泛社会行为的框架。其基本思想是,整个社会或市场的行动是个人行为的结果。每个个体都在考虑一组可能的替代方案后做出自己的决策。理性选择理论背后的基本假设是,个体以自利的方式行事,他们会选择对自己最有利的替代方案。

定义性能度量

“理性选择是挑选最理想的替代方案”这一概念仍需要我们定义一些东西。如果个体有偏好,允许他们在一组可能的结果中进行选择,那么我们就需要一种方法来评估每个结果的效用

现在,我们将从性能度量的一般概念开始。我们如何知道一个智能体的行为是否理性?非正式地说,它应该做“正确的事”。理想情况下,如果它是理性的,它应该在每种情况下都做正确的事。我们如何客观地知道它是否做了正确的事?让我们定义一个性能度量。

这将是一个客观的、可衡量的成功标准,用于评估智能体的行为。这意味着它将根据某个行动带来的后果,为该智能体选择该特定行动的行为打分。我们可以定义这个分数,使其与我们作为系统设计者所关心的事情相关。这将使我们能够说,给定智能体选择的一系列行动,它是否选择了正确的行动来最大化其性能度量?如果是,我们就说它的行为是理性的。

以下是一个我们可以为机器人吸尘器创建的性能度量示例。假设我们讨论的智能体是Roomba。它有一组传感器和执行器。我们希望它的行为是理性的,因此我们可以给它一个性能度量让它去尝试最大化。

我们可以为Roomba设计什么样的性能度量?如果它试图通过最大化该性能度量来理性行事,它的行为会是怎样的?

我们可以用几种不同的方式来设计性能度量。例如,我们可以说,在某个时间点T,当它的清洁程序终止时,机器人每清洁一个方块就得一分。所以它应该尝试增加清洁方块的数量。或者,我们可以给它每清洁一个方块得一分,但每移动一次就扣一分。这将减少不必要的移动量,这实际上是一个非常适合Roomba的功能。我的机器人吸尘器往往以一种完全随机的方式清洁房间。它会反复多次清洁同一个地方,并且常常刚好错过一些本应清洁的脏污区域。

为了惩罚机器人错过太多脏污区域,我们可能会添加一个阈值,允许我们说,如果它没有足够彻底地清洁房间,那么它就未能完成工作。我们将给它一个大惩罚,比如扣100分。如果Roomba选择了一系列行动来最大化我们给它的性能度量,那么我们就说它的行为是理性的。如果它做了导致分数很低的事情,那么我们就说它的行为不理性。

如何设计好的性能度量

当存在许多可能的性能度量时,我们如何创建一个好的性能度量?一个好的经验法则是:根据你希望达成的目标来设计性能度量,而不是根据你认为智能体应该如何行为来设计。如果你试图规定智能体应该如何做它的工作,而不是你想要完成什么,那么这有时会导致奇怪的行为。

想想这个例子:我们之前说,在时间T机器人终止时,每有一个清洁方块就给一分。如果我们改为给机器人每清洁一个方块就加一分,而不是最终清洁方块的总数,会怎么样?这似乎是一个非常微妙的区别。我们现在没有说明结果应该是什么,而是试图告诉机器人我们认为它应该如何行为。事实证明,这是一个“小心你的愿望”的案例。因为如果机器人试图基于这个定义理性行事,那么它将尝试最大化这个新的性能度量。机器人最大化这个度量的一种方法是清洁一个方块,然后在上面倒上灰尘,然后再清洁它。这将是一种意想不到的坏行为,但它仍然会最大化分数。智能体的行为可能根据我们如何定义性能度量而涌现。因此,我们需要小心设计它们。在本课程后面,当我们讨论强化学习时,我们会谈到奖励函数,你将看到改变定义奖励函数的方式将如何影响智能体涌现出的行为。

理性智能体的定义

现在我们有了性能度量的定义,我们可以开始构建我们对理性智能体的定义。我们将说,一个理性智能体是这样一个智能体:对于每一个可能的感知序列 P,选择一个行动 A,以最大化其性能度量。显然,这将导致比那些会导致性能度量得分较低的行动序列更理想的一系列行动。

但是,等等。机器如何知道哪些行动将最大化其性能度量?

就像我们之前说的,我们不能要求全知全能来实现理性。因此,我们不能要求最大化实际性能,因为智能体必须对所有结果有完全的了解。这在大多数时候是不可能的。但在我们将考虑的一些问题中,比如玩井字棋这样的简单游戏,实际上有可能完全预测游戏的所有可能结果,因此你可以最大化实际性能。

一个有趣的注意事项是,计算限制使得完全理性对于几乎所有问题都是无法实现的,包括像国际象棋或围棋这样更复杂的游戏。我们将在课程后面看到,对于一个程序来说,考虑这些游戏的所有可能结果在计算上是不可能的。因此,我们希望修改理性智能体的定义,以包含计算约束和不确定性意味着机器不能全知全能这一事实。因此,不能要求它们最大化实际性能。

最终定义:最大化期望值

我们将最终确定理性智能体的定义。我们将说,一个理性智能体是这样一个智能体:对于每个可能的感知序列 P,应该选择一个行动 A,以最大化其性能度量的期望值

这一变化意味着智能体不必知道实际结果会是什么。最大化期望值这一概念是一个非常强大的概念,在本课程中会反复出现。在下一个模块中,我们将学习MinimaxExpectimax算法。这两种算法都用于在游戏中最大化结果的期望值。Minimax算法适用于我们与一个同样试图最大化自己在游戏中得分的理性对手对弈的情况。而Expectimax算法适用于结果受机会影响的情况,比如掷骰子或抽牌。

总结

本节课中,我们一起学习了理性智能体的核心定义。我们从经济学中的理性选择理论和有限理性概念出发,引出了在人工智能中定义智能体理性行为的关键——性能度量。我们了解到,一个好的性能度量应基于目标而非行为方式来设计。最后,我们得出了理性智能体的最终定义:一个对于每个感知序列,都选择能最大化其性能度量期望值的行动的智能体。这一定义考虑到了现实世界中的计算限制和不确定性,为后续学习博弈论中的Minimax和Expectimax等算法奠定了基础。

13:任务环境

在本节课中,我们将学习如何定义和描述智能体(Agent)所面临的任务环境。我们将通过一个名为“PEAS”的框架来系统地分析问题,并比较不同任务环境(如自动驾驶出租车与送货无人机)的异同。

上一节我们定义了理性智能体及其性能度量。本节中,我们将进一步探讨智能体可以运行的不同类型的环境。

我们可以将按照性能度量行事的智能体,视为特定问题或任务的解决方案。例如,一个理性的吸尘器智能体就是解决清洁灰尘问题的方案。我们可以通过指定以下元素来创建一个问题规范:

  • 智能体的性能度量。
  • 智能体运行的环境。
  • 智能体将用来与环境交互的传感器。
  • 智能体将用来与环境交互的执行器。

Russell和Norvig将这四个元素缩写为PEAS。它们共同定义了一个任务环境。PEAS并不定义智能体函数或智能体程序,但它为我们提供了一种理解问题的方式。我们的智能体程序/函数将是这个问题的解决方案。

任务环境示例:自动驾驶出租车

让我们看一个如何为自动驾驶出租车指定任务环境的例子。我们需要思考:

  • 我们希望出租车最大化什么样的性能度量?
  • 出租车将在什么环境中运行?
  • 环境中哪些相关元素是它必须处理的?
  • 自动驾驶出租车需要什么样的执行器和传感器?

以下是针对PEAS框架的详细分析:

性能度量
我们可以考虑将一系列不同元素纳入性能度量,例如:

  • 确保出租车行驶安全。
  • 乘客能在短时间内到达目的地。
  • 出租车本身遵守所有交通法规。
  • 行驶过程舒适。
  • 最大化公司的利润。

环境
自动驾驶出租车运行的环境包括:

  • 道路和十字路口。
  • 道路上的其他车辆和交通状况。
  • 行人。
  • 需要接送至目的地的顾客。

执行器
自动驾驶出租车可能拥有的执行器类型包括:

  • 转向机制。
  • 油门。
  • 刹车。
  • 转向灯。
  • 喇叭。

传感器
自动驾驶出租车可能拥有的传感器类型包括:

  • 摄像头。
  • 激光雷达系统(LiDAR,是“光探测与测距”的缩写)。
  • 速度表。
  • 用于地图导航的GPS。

综合来看,这些是为解决“充当自动驾驶出租车司机”这一问题而设计智能系统时,任务环境的不同重要元素。

任务环境对比:送货无人机

现在,让我们看看另一个不同的任务环境。当我们从一个问题转向一个类似问题时,情况会如何变化?如果我们从自动驾驶出租车转向亚马逊Prime Air送货无人机,会发生什么?

以下是一段关于亚马逊无人机送货计划的视频片段摘要:
亚马逊一直在开发技术,以便部署一组自动驾驶无人机作为其送货车队的一部分。亚马逊相信,最终这些无人机将用于将包裹直接送到客户家门口。新的无人机能够垂直起飞并倾斜机身以水平飞行。它是全电动的,飞行距离为15英里,能够运送重达5磅的包裹,并使用机器学习来避免撞到人、电线和其他地面障碍物。

请花点时间思考一下,您将如何为亚马逊送货无人机定义PEAS任务环境的不同元素?

  • 在此任务环境中,它的性能度量有何不同?
  • 智能体需要应对空中送货平台的哪些环境元素?
  • 您需要什么样的传感器来导航空域?
  • 无人机需要什么样的执行器才能在空气中移动并成功取送包裹?

使用PEAS框架进行问题定义

为PEAS的每个元素创建一个任务环境的考虑事项列表,可以很好地开始为我们希望理性智能体解决的问题制定解决方案。PEAS可以帮助我们定义需要考虑的事项范围,例如:

  • 我们的智能体将处于何种环境。
  • 我们的智能体将拥有何种物理硬件。
  • 我们如何开始衡量其成功。

在定义了任务环境之后,我们就可以通过构建智能体函数来开始制定我们的理性智能体。这是我们的数学模型,用于描述给定感知序列时,我们希望智能体执行什么动作。

然后,我们可以开始编写智能体程序,即在实际硬件上运行的具体实现。我们为智能体程序选择的算法将取决于我们所处理的任务环境的类型。

本节课中,我们一起学习了如何使用PEAS框架来定义和分析智能体的任务环境。我们通过自动驾驶出租车和送货无人机两个具体案例,详细拆解了性能度量、环境、执行器和传感器这四个核心要素。理解任务环境是设计有效智能体解决方案的第一步。接下来,我将讨论任务环境的一系列不同特征,这些特征将改变我们用于实现智能体的算法和方法。

14:任务环境的属性 🧠

在本节课中,我们将学习如何描述和分类智能体(Agent)所面临的任务环境。理解这些属性对于设计有效的AI系统至关重要。

完全可观察与部分可观察

上一节我们介绍了智能体的基本概念,本节中我们来看看任务环境的第一个关键属性:可观察性。

一些任务环境是完全可观察的,而另一些只是部分可观察的。例如,如果我们设计一个下棋的智能体,它可以感知其环境的完整状态。下棋的AI系统能看到整个棋盘,没有任何信息对它隐藏。如果一个任务智能体的传感器能够检测到环境中与智能体选择行动相关的所有方面,那么该任务环境就被认为是完全可观察的。

与完全可观察的任务环境相反,许多任务环境只是部分可观察的。自动驾驶汽车在一个部分可观察的环境中运行。它们只能通过传感器感知信息。因此,它们可以获取一些关于其直接周围环境的信息,但无法获取完整的全局图景。例如,在自动驾驶汽车或自动出租车中,环境的某些部分可能被其他物体遮挡而无法观察。例如,行人可能被其他车辆遮挡,或者建筑物可能阻挡传感器,使其无法看到拐角处的情况。

部分可观察的环境也可能是由传感器噪声或不准确造成的。另一个部分可观察环境的例子,虽然不如自动出租车那么令人兴奋,是我们可靠的扫地机器人。它在部分可观察的环境中运行,因为它的传感器只能检测到正下方的灰尘。如果它有一张标明了所有脏污位置的房间完整地图,并且地图在清洁过程中会更新,那么这将是一个完全可观察的环境。

确定性与非确定性

接下来,我们探讨环境的另一个属性:确定性。

智能体函数接收一系列感知信息,然后返回一个行动。一个有用的区分是,当智能体选择采取哪个行动时会发生什么。你期望发生的结果是否保证会发生?

在像国际象棋这样的确定性环境中,当智能体选择一个行动,比如移动它的一个兵,那么我们可以确定地知道该行动的即时结果。如果智能体选择前进,兵就会向前移动;如果选择斜向移动,就会吃掉对手的棋子。思考确定性环境的另一种方式是,在智能体选择一个行动后,完成该行动后环境的状态将是完全可知的。世界的最终状态将完全由当前状态和智能体选择的行动决定。

如果不是这种情况,那么我们称该环境为非确定性环境。在非确定性环境中,智能体可以选择行动,但结果是不确定的。基于智能体执行该行动,环境可能产生许多种可能的结果状态。这可能出现在机会游戏中。我们人工智能课程中将讨论的许多问题设定都是游戏,因为它们是封闭世界,环境定义得非常明确。涉及掷骰子或抽牌的游戏与国际象棋不同,因为结果不是确定性的。这是因为有几种可能的结果。具有非确定性结果的环境在本质上是随机的。随机意味着概率性。如果我们能够量化每种可能结果的可能性,那么该环境就是一个随机环境。非确定性环境与此类似,只是我们尚未量化不同可能结果的可能性。

片段式与序列式

任务环境可以是片段式的,也可以是序列式的。

片段式环境是指智能体需要处理自包含的片段。智能体感知环境,然后执行单个行动,每个行动的选择不依赖于任何先前的行动。这方面的一个例子是装配线上挑选出有缺陷零件并将其丢弃的机器人。每次它检查面前的零件时,关于该零件是否有缺陷的决策都独立于它在序列式环境中的所有过去决策。

在序列式环境中,当前的决策会影响所有未来的行动。在这种情况下,一个即时决策将影响接下来可能的选择空间。对未来产生影响使得序列式环境比片段式环境更具挑战性。在这种情况下,智能体需要提前规划未来的多个步骤,以实现期望的结果。

静态与动态

任务环境中需要考虑的另一个维度是环境是静态的还是动态的。

如果环境在智能体思考采取什么行动时保持不变,那么它就是静态环境。这方面的一个例子是填字游戏,你可以在采取行动写出一个单词或输入一个字母之前思考任意长的时间。在智能体完成决定采取什么行动之前,没有任何变化。

这与动态环境形成对比。在动态环境中,当智能体正在思考采取什么行动时,其周围的环境正在不断变化。这使得许多任务更具挑战性,因为时间是关键。例如,如果一辆汽车或行人突然出现在它们的路径上,它们必须刹车。从接收到感知输入到决定汽车需要刹车之间经过的时间极其重要,因为汽车正在空间中疾驰。

也可能存在介于静态和动态之间的任务环境。如果一个环境实际上不随时间变化,但智能体的分数确实会变化,那么它可以被归类为半动态环境。这方面的一个例子是带有时钟的下棋游戏,棋盘的实际状态不会改变,但花费太长时间会受到一些惩罚。

离散与连续

接下来,我们有离散环境与连续环境的区别。

这种区别适用于环境的状态以及时间处理方式。在棋盘游戏中,环境可以用离散数量的不同状态来表示。在离散环境中,还有数量有限的明确定义的行动。这意味着智能体可以采取的行动集合是有限的。

在连续环境中,我们需要将环境的状态表示或我们处理时间的方式视为连续的。例如,如果我们正在构建一个控制炼油厂的AI系统,温度设置和石油输出将随时间平滑地经历一个连续的值范围。

单智能体与多智能体

我们将用来分类任务环境的最后一个属性是环境中是单个智能体在行动,还是存在多个智能体。

之前,我们讨论了确定性与非确定性环境。这还有另一种变体,即环境完全是确定性的,除了另一个智能体的行动。例如国际象棋。我们可以以战略性的方式对待其他智能体。当我们有一个竞争性的多智能体环境时,我们可以认为一个智能体在与另一个智能体竞争,那么我们将需要设计与其他智能体对抗的策略。我们可以假设其他智能体在游戏设定中也理性地行动。提高你自己的性能度量通常会降低对手的性能度量。

填字游戏是单智能体环境的一个例子。只有一个智能体试图找出谜题的解决方案。国际象棋是多智能体环境的一个例子,我们的智能体有一个对手。经典的视频游戏《吃豆人》有多个对手,所有这些小鬼魂都试图吃掉你。虽然大多数时候我们认为多智能体环境是竞争性的,但有时智能体的目标是一致的。在这种情况下,我们可以认为这些环境是合作性的。

什么应该被视为智能体

什么时候应该将某物视为智能体?如果我们谈论的是自动驾驶汽车,那么为什么我们觉得电话杆应该是环境的一部分,但另一辆汽车也许应该被视为一个智能体?

基本的经验法则是思考性能度量。如果某物有自己的性能度量,并且它试图优化该度量,那么这就是将其建模为另一个智能体而不是环境一部分的一个很好的理由。

总结

本节课中我们一起学习了描述任务环境的六个关键属性:可观察性、确定性、任务结构、动态性、状态/时间连续性以及智能体数量。所有这些任务环境的不同要素将帮助我们决定解决它们需要哪些要素。不同的参数化可能导致更容易或更难解决的问题。我们能想到的最困难的任务环境将是连续的、部分可观察的、随机的和多智能体的,很像自动驾驶汽车的例子。

目前,我们将把自己限制在相对简单的任务环境中。我们将从研究静态、完全可观察、确定性、离散的任务环境开始,比如国际象棋这样的棋盘游戏。随着课程的进展,我们将研究越来越复杂的任务环境。

15:Python复习-函数 🐍

在本节课中,我们将要学习Python中函数的核心概念。我们将从函数的基本定义开始,逐步探讨其与Java等语言的区别、参数的灵活性、变量的作用域以及函数作为“一等公民”的高级特性。通过对比和示例,你将清晰地掌握Python函数的强大与独特之处。

函数定义基础

上一节我们介绍了课程概述,本节中我们来看看如何在Python中定义一个函数。

一个函数定义以关键字 def 开始,然后是函数名、一对圆括号、参数列表、一个闭合的圆括号,最后是一个冒号。函数体需要缩进。

你可以在函数定义后立即添加一个可选的文档字符串。文档字符串由三个引号定义。

关键字 return 指示函数要返回的值。如果未给出 return 语句,Python使用 None 关键字。

函数体通过缩进来界定。第一行缩进减少的代码就落在了函数定义之外。Python使用空格来划分代码块,这与之前介绍的条件语句相同。空格定义了哪些内容属于函数内部,以及函数在哪里结束。

与Java不同,Python不声明返回类型或函数参数的类型。

代码示例:

def function_name(arg1, arg2):
    """
    这是一个文档字符串。
    用于说明函数的功能。
    """
    # 函数体
    result = arg1 + arg2
    return result

多返回值与函数签名

了解了基础定义后,我们来看看Python函数与Java的一些关键区别。

Java和Python之间一个有趣的差异是,Python允许方法拥有多个返回值。在Java中,从函数返回多个值的唯一方法是创建一个专门为此目的设计的对象。在Python中,你可以通过在 return 语句后用逗号分隔列出所有值来轻松返回多个值。这会自动将你返回的不同值打包成一个元组。因此,具有多个返回值的函数的返回类型是一个元组。

代码示例:

def get_user_info():
    name = "Alice"
    age = 30
    city = "New York"
    return name, age, city  # 返回一个元组

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/upenn-aiml-ess/img/ac52ccad2b59e62e76c06399ee7d6214_5.png)

# 调用函数并解包返回值
user_name, user_age, user_city = get_user_info()

Java和Python在函数签名的定义方式上也有所不同。在Java中,方法签名包括方法名及其参数的类型。由于这种签名定义,Java允许类拥有多个同名方法,这些方法根据其参数的数量和类型进行区分。例如,如果一个类负责将数字相加,它可以有多个名为 add 的函数,这些函数接受不同数量或不同类型的参数。

与Java不同,Python中的函数签名仅仅是函数名本身。因此,不可能有两个具有相同名称的不同函数,即使它们的参数数量或顺序不同。不过,Python类确实允许运算符重载。因此,如果你需要用双等号比较两个对象或用加号运算符将两个对象相加,这是可能的,只需在该类中实现一个魔术方法即可。

参数的灵活性

尽管Python不允许你定义多个同名但参数数量不同的函数,但它允许同一个函数接受不同数量的参数。Python通过几种方式实现这一点。

你可以为函数参数提供默认值。当你这样做时,这些参数就变成了可选的。这意味着在调用函数时,你可以为这些参数指定值,这将覆盖默认值;或者你可以省略这些参数,此时将使用它们的默认值。这意味着我可以用几种不同的方式调用我的函数:我可以传入所有参数,包括那些有默认值的参数,或者只传入那些没有指定默认值的参数。

Python要求非默认参数始终位于有默认值的参数之前。如果在函数定义中不遵循此要求,Python将返回语法错误。

代码示例:

def greet(name, greeting="Hello"):
    print(f"{greeting}, {name}!")

# 多种调用方式
greet("Alice")           # 输出: Hello, Alice!
greet("Bob", "Hi")       # 输出: Hi, Bob!

Python在参数顺序方面也出奇地灵活。只要在调用中指定了参数,就可以不按顺序传递参数,这称为关键字参数。例如,如果我定义了一个带有参数A、B和C的函数,我实际上可以以任何顺序调用该函数,只要我明确使用它们的关键字。与其按A、B、C的顺序调用函数,我实际上可以按C、B、A的相反顺序调用,只要我指定 C=某个值B=某个值A=某个值。未明确给出参数名称关键字的参数被假定为默认顺序。

Python用来提供传递给函数的参数数量灵活性的另一种机制是通过使用 *args 关键字。*args 是一种将可变数量的非关键字参数传递到函数中的方式。

代码示例:

def print_everything(*args):
    for thing in args:
        print(thing)

# 调用方式一:直接传入多个参数
print_everything("apple", "banana", "cherry")

# 调用方式二:传入一个列表并使用 * 解包
my_list = [1, 2, 3]
print_everything(*my_list)

如果你想在函数中接受可变数量的关键字参数,可以像使用 *args 一样使用 **kwargs*args**kwargs 的符号有点复杂,因为我们使用了 ***,但一旦你习惯了,它就成了一种传递任意数量参数的非常方便的方法。

以下是两种可以将关键字参数传递到使用 **kwargs 定义的函数中的方法示例:你可以直接传递带有关键字及其值的参数,或者可以传入一个字典。类似于使用 * 符号解包传递给使用 *args 的函数的列表,你可以使用双星号 ** 来解包传递给使用 **kwargs 的函数的字典。

代码示例:

def print_info(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

# 调用方式一:直接传入关键字参数
print_info(name="Alice", age=30, city="NYC")

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/upenn-aiml-ess/img/ac52ccad2b59e62e76c06399ee7d6214_13.png)

# 调用方式二:传入一个字典并使用 ** 解包
my_dict = {"job": "Engineer", "hobby": "Reading"}
print_info(**my_dict)

尽管Python没有像Java那样重载函数的能力,但其函数参数方面的灵活性可以说同样有用。

变量作用域与默认参数的妙用

Python在使用变量方面相当宽松。你可以定义一个函数并引用一个未在函数作用域内定义的变量。在这种情况下,函数会看到该变量的最新值。例如,在函数 add 中,我引用了一个变量 i,该变量未在函数本身内定义,而是在我代码的其他地方定义。当我更新 i 时,即使传入相同的值,函数 add 的输出也会不同,因为 i 在我代码的不同位置被赋予了不同的值。因此,函数看到的是 i 的最新值。

代码示例:

i = 5

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/upenn-aiml-ess/img/ac52ccad2b59e62e76c06399ee7d6214_17.png)

def add(a, b):
    return a + b + i  # 使用了全局变量 i

print(add(1, 2))  # 输出: 8 (1+2+5)

i = 10
print(add(1, 2))  # 输出: 13 (1+2+10)

默认参数的一个有趣特性是,你可以在一种称为动态规划的程序中非常巧妙地使用它们。动态规划是编码递归算法的一种高效方法。动态规划使用一个称为记忆化的过程。记忆化是一种优化技术,用于存储昂贵函数调用的结果并返回缓存的结果。这可以用于计算斐波那契数的程序中,其中每个数字都依赖于之前的两个计算。

我们可以使这个程序高效的方法是,每次计算某个数字N的斐波那契数时,我们将结果存储在名为 fibs 的Python字典中。在这里,你可以看到我将字典 fibs 作为我的 fib 函数的默认参数。我已经将 fibs 字典初始化为空。默认参数值只在我们第一次调用函数时被求值。因此,我不会在每次调用 fib 时都创建一个新的空字典。事实上,后续每次对 fib 的调用都会增加 fibs 字典的大小。这使我能够记住每个结果,因此我只为特定的N值计算一次斐波那契数。

代码示例:

def fib(n, fibs={}):
    if n in fibs:
        return fibs[n]
    if n <= 1:
        result = n
    else:
        result = fib(n-1) + fib(n-2)
    fibs[n] = result
    return result

print(fib(10))  # 快速计算出结果,利用了记忆化

函数作为一等公民

Python和Java之间一个有趣的差异是,函数是一等对象。什么是一等对象?我指的是可以动态创建、销毁、传递给函数、作为值返回,并拥有与编程语言中所有其他变量相同权利的对象。在Python中,函数是真正的一等公民。你可以将函数作为参数传递给其他函数,可以将函数作为值返回,可以将函数赋值给变量,甚至可以将它们存储在数据结构中。这允许你做很多非常有趣、复杂的事情。

例如,我可以编写这个 compose 函数,它将函数 F、函数 G 和一些数据 X 作为参数。这个 compose 函数将是一个高阶函数,它首先将函数 G 应用于数据 X,然后将 F 应用于该结果。一旦我定义了这个组合函数,我就可以向它传递任何两个函数和任何我想要的数据。

代码示例:

def compose(f, g, x):
    return f(g(x))

# 使用示例:先求和,再将结果转为字符串
result = compose(str, sum, [1, 2, 3])
print(result)  # 输出: "6"

总结

本节课中我们一起学习了Python函数的核心知识。我们从最基本的函数定义语法开始,了解了其与Java在返回值、签名上的区别。接着,我们深入探讨了Python函数参数的强大灵活性,包括默认参数、关键字参数、*args**kwargs。我们还看到了Python宽松的变量作用域规则以及如何巧妙利用默认参数实现记忆化。最后,我们认识到函数在Python中是“一等公民”,可以作为参数传递和返回,这为编写高阶函数和更抽象的代码打开了大门。掌握这些概念,将帮助你更高效、更优雅地使用Python进行编程。

16:Python复习-类

在本节课中,我们将学习如何在Python中实现类,以及如何通过继承来创建子类。我们将涵盖类的基本定义、构造函数、方法调用、继承、方法重写、多重继承以及Python中的特殊“魔法”方法。

概述

类(Class)是面向对象编程的核心概念,它允许我们将数据(属性)和操作数据的方法(函数)捆绑在一起,创建出自定义的数据类型。通过继承,我们可以基于现有类创建更专门化的新类,实现代码的复用和扩展。

定义类

在Python中定义一个类非常简单。只需要使用关键字 class,后跟类名和一个冒号即可。与定义函数和条件语句类似,类的主体内容需要缩进。

class Student:
    pass

类可以拥有属性,这些属性是该类所有实例共有的变量。

构造函数与 self 参数

在Python中,构造函数有一个特殊的名称:__init__。这是一个“魔法方法”,在创建类的新实例时会自动调用。

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

你会注意到,类中定义的每个方法都以参数 self 开头。self 代表类的当前实例。这个关键字只在类定义内部使用,在外部调用方法时不需要显式传递。

调用方法

有两种主要方式可以调用对象的方法。

  1. 使用点号(.)表示法:这是最常见的方式。

    student1 = Student("Alice", 20)
    student1.introduce()
    
  2. 直接使用类名调用:将实例作为参数传递给类的方法。

    Student.introduce(student1)
    

创建子类与继承

你可以通过创建子类来扩展一个已有的类,使其更加专门化。这允许你复用父类(或超类)的方法和属性,并可以按需重写它们。

定义子类的语法同样直接:使用 class 关键字,后跟子类名、括号内的父类名,然后是冒号。这相当于Java中的 extends 关键字。

class AIStudent(Student):
    pass

子类的构造函数

为了定义子类的构造函数,你需要定义自己的 __init__ 方法。通常,你既需要初始化子类,也需要初始化父类。

你可以通过显式调用父类的 __init__ 方法来实现这一点。在Python中,一个常见的做法是让子类 __init__ 方法的第一行调用父类的初始化函数。

class AIStudent(Student):
    def __init__(self, name, age, specialization):
        super().__init__(name, age)  # 调用父类Student的__init__方法
        self.specialization = specialization

方法重写与扩展

在子类中,你可以通过定义同名方法来重写父类的方法。此时,父类的原始代码将不会被执行。

在某些情况下,你可能希望扩展父类的方法,即在执行子类新代码的同时也执行父类的代码。为此,你需要像在构造函数中那样,显式调用父类的版本。

class AIStudent(Student):
    def introduce(self):
        super().introduce()  # 先执行父类的introduce方法
        print(f"I am specializing in {self.specialization}.")

注意:这是你唯一需要显式将 self 作为参数传递给祖先类方法的情况。

多重继承

Python支持多重继承,即一个子类可以继承自多个父类。这允许子类获得所有父类的方法。

class A:
    def foo(self):
        print("A's foo")

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/upenn-aiml-ess/img/b9a6d85a6f21e7e17602ee2c504392b3_5.png)

class B:
    def bar(self):
        print("B's bar")

class C(A, B):  # 类C继承自A和B
    pass

c = C()
c.foo()  # 输出:A's foo
c.bar()  # 输出:B's bar

然而,当多个父类拥有同名方法时,调用哪个方法会变得棘手。Python使用一种称为方法解析顺序(MRO)的算法来决定。在上例中,如果A和B都有 foo 方法,C().foo() 将调用类A的 foo 方法。这可能导致意外的错误,因此使用多重继承时需要谨慎。

魔法方法与运算符重载

我们已经见过一个特殊的“魔法”方法 __init__。这些以双下划线开头和结尾的方法,允许我们使用特殊的语法。

例如,通过实现 __eq__ 方法,你可以使用 == 运算符来比较两个类的实例。

class Student:
    def __init__(self, name):
        self.name = name

    def __eq__(self, other):
        return self.name == other.name

s1 = Student("Alice")
s2 = Student("Alice")
print(s1 == s2)  # 输出:True

类似地,你可以实现 __add__ 来定义 + 运算符的行为,实现 __len__ 来让内置函数 len() 作用于你的类。

__name__ 变量与主方法

__name__ 是一个特殊的内置变量。当一个Python脚本被直接运行时,__name__ 的值被设置为 "__main__"。这为我们提供了一种定义“主方法”的约定。

class MyClass:
    pass

if __name__ == "__main__":
    # 当脚本被直接运行时,执行这里的代码
    obj = MyClass()
    print("Script is running directly.")

鸭子类型

Python不强制要求对象实现特定的接口(如Java那样)。相反,它采用“鸭子类型”的理念:如果一个对象有我们需要的方法,那么我们就可以使用它,而不关心它具体是什么类型。

“如果它走起路来像鸭子,叫起来像鸭子,游起泳来像鸭子,那么它就是鸭子。”

class Duck:
    def fly(self):
        print("Duck flying")

class Airplane:
    def fly(self):
        print("Airplane flying")

def lift_off(entity):
    entity.fly()  # 我们不关心entity的具体类型,只关心它是否有fly方法

duck = Duck()
plane = Airplane()

lift_off(duck)   # 输出:Duck flying
lift_off(plane)  # 输出:Airplane flying

如果传递给 lift_off 的对象没有 fly 方法,Python会抛出一个 AttributeError 异常。

总结

本节课我们一起学习了Python中类的核心概念。我们了解了如何定义类和构造函数,如何使用 self 参数,以及如何调用方法。我们深入探讨了继承机制,包括创建子类、重写和扩展方法,以及需要注意的多重继承问题。我们还介绍了Python中强大的“魔法方法”,它们允许我们自定义运算符行为,并理解了“鸭子类型”这一灵活的编程理念。掌握这些知识是使用Python进行面向对象编程和构建复杂程序的基础。

17:Python复习-for循环 🔄

在本节课中,我们将要学习Python编程语言中一个核心的控制流结构:for循环。我们将从基础的循环语法开始,逐步深入到更高级、更“Pythonic”的概念,如列表推导式和生成器。这些工具能帮助你更高效、更简洁地处理数据集合。


理解Python中的for循环

上一节我们介绍了课程概述,本节中我们来看看Python中for循环的基本工作原理。

for循环在Python中用于遍历集合中的每个项目,然后执行一段代码块。如果你有一个现有的列表,Python中的for循环会遍历其中的每一项。

如果你想遍历特定数量的项目,Python有一个名为range的函数,它可以生成一个数字列表。你可以使用for x in range(5)来执行一段代码五次。

循环中的项目实际上可以比单个变量名更复杂。它可以是一个元组。因此,你经常可以遍历成对的事物。事实上,Python有一个内置方法enumerate,它通常很有用。

enumerate会从列表中的项目生成一个元组列表,其中元组的第一个元素是该项目在列表中的索引,元组的第二个元素是列表中的项目本身。


列表推导式:简洁的循环工具

上一节我们介绍了基础的for循环,本节中我们来看看一个非常有趣的Python结构,称为列表推导式。

列表推导式可以显著减少你为了对列表中每个项目执行表达式而必须编写的代码行数。

以下是列表推导式的一个例子。在上面的代码块中,我展示了使用for循环的正常做法。

假设我们想对一个整数列表中的每个数字求平方。通常,我们会有一个要处理的整数列表。然后,我们会创建一个空的正方形列表,并遍历列表中的每个整数,将那个数的平方追加到正方形列表中。

Python列表推导式允许我们用一行代码完成这个任务。

我们可以用列表推导式创建一个新列表。如果你来自另一种编程语言,Python列表推导式的语法可能需要一点时间来适应。但一旦你掌握了它,它是一个非常强大的工具。

列表推导式会创建一个新列表。因此,我们使用与初始化列表相同的符号来创建列表推导式。我们以一个左方括号开始。然后,我们写出一个我们想要应用到列表中每个项目的表达式,例如这里的x平方,即x * x。接着,我们简单地写出for循环的语法:for x in nums,其中x是将在我们表达式中处理的变量。结果与上面的代码块完全相同。

以下是列表推导式的另外两个例子。

在第一个例子中,我遍历列表中的每个元素并简单地将其加倍。所以我的表达式是element * 2,我将该表达式应用到列表li中的每个元素。

for循环一样,我们可以在列表中处理的变量也可以是元组。在第二个例子中,我对列表li中每个元组的第二个元素进行立方运算。

列表推导式还允许我们应用过滤条件。只要满足过滤条件,我们就可以有一个想要应用到列表中每个元素的表达式。例如,只要元素在加倍前的值大于4,我就可以将列表li中的每个元素加倍。


字典与集合推导式

上一节我们学习了列表推导式,本节中我们来看看Python也提供了执行字典和集合推导式的方法。

我可以创建一个字典,而不是列表。列表推导式使用左方括号和右方括号创建一个新列表。而字典或集合推导式使用左花括号和右花括号创建一个字典或集合。

在这个例子中,我正在创建一个新字典,将列表list_one中每个元组的第一个元素映射为键,对应的值是列表list_one中每个元组的第二个元素。

在第二个例子中,我正在从列表list_two中的项目创建一个新集合。同样,字典推导式和集合推导式可以展开成一个完整的for循环。但使用推导式方法提供了一种非常简洁的单行方式来创建新的字典或集合。


生成器:动态迭代器

Python有另一种称为生成器的迭代器对象,它只需在代码中插入一个名为yield的关键字即可自动创建。这是一种动态生成迭代器的非常有趣的方式,而无需实际创建一个显式的迭代器对象。

生成器是完整的迭代器对象,包括__next__魔术方法。但我们创建生成器的方式是使用yield关键字。

yield关键字可以插入到一个函数中,当该函数被调用时,它将自动返回一个生成器对象。例如,我可以在这里创建一个函数f,其中包含两个yield语句。如果我检查我的函数f的类型,它确实是一个函数。但一旦我调用该函数,返回的类型就是一个生成器对象。

生成器对象允许我以与任何可迭代对象相同的方式调用for循环。例如,如果我有一个for i in f(6)的循环,它将首先yield 6,然后yield 6+1 即 7。

Python中生成器的工作方式实际上非常巧妙。每次我们调用生成器的next方法时,函数将一直运行,直到遇到一个yield语句,然后它会停止并返回yield的值。下一次,它将从函数离开的地方完全恢复。它会维护与函数相关的所有状态信息,因此它可以像什么都没发生一样开始。

使用生成器有几个好处。首先,与编写标准的迭代器对象相比,它们使用的代码要少得多。由于Python的巧妙设计,生成器会自动维护函数的局部状态。值是一个一个计算的,这意味着它们只在需要时才被计算。这避免了将整个序列存储在内存中,因此对于像一次性聚合项目这样的任务来说非常高效。

如果你正在处理无限序列,生成器至关重要,但如果你需要检查每个单独的项目,它们可能难以使用。


生成器应用示例:合并有序列表

以下是使用生成器合并两个有序列表的函数示例。它将把列表leftright合并成一个列表,作为流输出,而无需将流的整个值存储在内存中。

我们已经将列表LR存储在内存中,所以我们将跟踪四件事:列表L的长度、列表R的长度、我们在L中的当前位置(用i表示)以及我们在列表R中的当前位置(用j表示)。然后我们将执行一些逻辑。

当指针i尚未到达列表L的末尾,或者指针j尚未到达列表R的末尾时,while循环内的逻辑简单地决定返回哪个数字:指针i指向的数字或指针j指向的数字。如果i指向的项目值小于j指向的项目值,那么我们将yield i指向的值。同样,yield语句将自动为我们构建一个迭代器。类似地,如果我们返回列表R中由j指向的项目,我们使用yield语句来完成。

由于我们的merge函数中有关键字yieldmerge函数的返回值实际上是一个生成器。所以merge的返回值不会是一个合并后的列表,而是一个类似迭代器的对象。

因此,我们可以说while True,然后从生成器中打印下一个项目。然而,就像所有迭代器一样,这最终会导致一个StopIteration异常。如果我们想从merge返回一个列表,那么我们可以使用列表推导式符号。或者,只要我们最后处理StopIteration异常,就可以使用带有生成器的while循环。


总结

本节课中我们一起学习了Python中for循环的核心概念及其高级应用。我们从基础的循环遍历开始,了解了如何使用rangeenumerate。接着,我们深入探讨了列表推导式,这是一种编写更简洁、更高效代码的强大工具。我们还扩展到了字典和集合推导式。最后,我们介绍了生成器的概念,它通过yield关键字提供了一种动态、内存高效的方式来创建迭代器,并看到了一个合并有序列表的实际应用示例。掌握这些工具将极大地提升你在数据科学和机器学习项目中使用Python处理数据的能力。

18:Python复习-导入模块 📦

在本节课中,我们将要学习Python中一个极其强大的功能:导入外部包和文件。这个功能允许你将他人开发的程序或自己编写的代码模块整合到你的项目中,极大地提高了代码的复用性和开发效率。

导入模块的基本语法

Python通过import语句来导入模块。其基本语法是使用关键字import,后跟模块的名称。导入后,你就可以访问该模块中已实现的函数。

以下是四种不同的导入方式示例:

1. 导入整个模块
这是最基础的方式。导入后,需要使用模块名.函数名的格式来调用函数。

import math
result = math.sqrt(16)  # 调用math模块中的sqrt函数

2. 从模块中导入特定函数
如果你只需要使用模块中的某个特定函数,可以使用from ... import ...语法。这样可以直接调用函数,无需添加模块名前缀。

from math import sqrt
result = sqrt(16)  # 直接调用sqrt函数

3. 导入模块中的所有函数(不推荐)
使用from module import *可以导入模块中的所有函数。这虽然方便,但可能导致命名冲突,通常不推荐在生产代码中使用。

from math import *
result = sqrt(16)

4. 为模块设置别名
为了在保持代码清晰的同时减少打字量,可以为导入的模块设置一个简短的别名。

import numpy as np
array = np.array([1, 2, 3])  # 使用别名np调用函数

上一节我们介绍了导入模块的基本语法,本节中我们来看看一个使用别名的具体例子。

使用别名导入:以queue模块为例

以下示例展示了如何使用别名导入queue模块,并利用其中的PriorityQueue(优先队列)对象。

import queue as Q  # 为queue模块设置别名Q
pq = Q.PriorityQueue()  # 创建优先队列对象

优先队列允许我们放入多个项目,然后按照优先级顺序取出。下面的while循环演示了如何清空一个优先队列:

while not pq.empty():
    print(pq.get())  # 获取并打印下一个项目

优先队列中的项目默认按升序(从小到大)取出。

屏幕右侧的代码展示了优先队列如何处理元组。它并非只处理整数值,而是根据元组中的第一个元素进行排序。这样,我们可以为任何类型的对象关联一个优先级。在下面的例子中,我为一系列字符串分配了优先级,以确保它们按照对话应有的顺序打印出来。

导入自定义文件

除了导入外部开发的模块,你还可以导入自己编写的Python文件。

例如,你可以在喜欢的文本编辑器中完成作业一的脚本编写。然后,在命令行中键入python启动Python交互式环境(REPL)。你无需将作业中的每个函数复制粘贴到命令行环境中,可以直接导入它。

导入自定义文件的语法与导入标准模块相同,只需省略文件末尾的.py扩展名。

import homework1  # 假设你的文件名为 homework1.py

导入后,你就可以运行和测试你的代码了。这里我们展示一个使用assert语句测试homework1concatenate函数的例子:

assert homework1.concatenate([1, 2], [3, 4]) == [1, 2, 3, 4]

如果我们的concatenate函数实现有误,在修改并保存文件后,Python REPL环境并不会自动感知到文件的变化,我们需要重新导入它。

重新加载模块

为了重新加载已修改的模块代码,我们可以使用Python内置的importlib库。

importlib库对于从文件重新加载代码非常有用。你可以使用importlib.reload()函数来重新加载一个模块。

import importlib
importlib.reload(homework1)  # 重新加载 homework1 模块

使用Pip安装第三方包

除了Python内置模块,还有大量由第三方开发的软件包可供使用。pip是一个程序,允许你轻松安装这些外部开发的Python包。

pip代表“Python包安装器”。只要包被列在Python包索引(PyPI)中,你就可以使用pip安装它。

运行pip非常简单,只需在终端中键入:

pip install package_name

如果你在运行他人开发的或你在另一台电脑上开发的Python脚本时遇到“ModuleNotFoundError”(模块未找到错误),通常的解决方法就是运行pip install并指定错误信息中报告的缺失模块名。

如果你在Jupyter Notebook(例如Google Colab)中开发或运行Python代码,同样可以使用pip命令。方法是在代码单元格中,在命令前加上感叹号!。在Python笔记本中,以感叹号为前缀的命令会自动在命令行中为你运行。

!pip install nltk  # 在Jupyter Notebook中安装nltk包

总结

本节课中我们一起学习了Python导入模块的核心知识。我们掌握了四种导入语法:导入整个模块、导入特定函数、导入所有函数(不推荐)以及使用别名导入。我们还学习了如何导入和重新加载自己编写的文件,并了解了如何使用pip工具来安装和管理第三方Python包。这些技能是构建复杂Python项目、利用丰富生态库的基础,对于后续学习数据科学和机器学习至关重要。

19:无信息搜索导论 🧭

在本模块中,我们将学习人工智能中的核心问题之一:搜索问题。我们将了解如何将许多现实世界任务形式化为搜索问题,并介绍两种基础的解决算法。

搜索问题概述

在人工智能领域,我们希望解决的许多问题都涉及寻找能够达成某个目标的最佳行动序列。

这些问题被称为搜索问题,因为它们通常需要在众多可能的行动序列组合中进行搜索,以找到最优解。

许多不同类型的问题都可以被归结为搜索问题。从地图导航到解决谜题,再到为你的扫地机器人编程以清洁房屋,所有这些不同的任务都可以被视为搜索问题。因此,它们可以使用相同的算法来寻找解决方案。

本模块内容

在本模块中,我们将给出搜索问题的正式定义,并学习两种解决搜索问题的经典算法:广度优先搜索和深度优先搜索。这些是最短路径算法的实例,它们被称为无信息搜索算法盲目搜索算法,因为它们不利用关于目标位置的外部知识。

除了广度优先搜索和深度优先搜索,我们还将探讨这些算法的几种变体,它们具有理想的计算复杂度特性。

核心概念与算法

上一节我们介绍了搜索问题的普遍性,本节中我们来看看其核心定义和即将学习的算法。

搜索问题可以形式化为寻找从初始状态目标状态的路径。一个状态代表了问题在某个时间点的具体情况。行动则会导致状态之间的转换。

以下是两种基础的无信息搜索算法:

  • 广度优先搜索:该算法从初始状态开始,逐层探索所有可能的状态。它首先检查所有一步可达的状态,然后是两步可达的状态,依此类推,直到找到目标。这保证了找到的路径是最短的(如果边权重一致)。其时间复杂度为 O(b^d),其中 b 是分支因子,d 是目标深度。
  • 深度优先搜索:该算法从初始状态开始,沿着一条路径尽可能深地探索,直到尽头或找到目标,然后回溯并尝试其他分支。它不保证找到最短路径,并且在最坏情况下可能需要探索整个搜索空间,时间复杂度为 O(b^m),其中 m 是最大深度。

总结

本节课中我们一起学习了人工智能中搜索问题的基本概念。我们了解到,从路径规划到谜题求解等众多任务都可以被建模为搜索问题。我们介绍了两种基础的无信息搜索算法——广度优先搜索和深度优先搜索,它们在不依赖额外领域知识的情况下,通过系统性地探索状态空间来寻找解决方案。在接下来的章节中,我们将深入探讨这些算法的具体实现、特性及其变体。

20:搜索问题-I

在本节课中,我们将要学习人工智能中一个广泛的问题类别:搜索问题。我们将了解如何将许多计算机科学问题形式化为搜索问题,并探索解决这类问题的通用方法。

概述:什么是搜索问题?🔍

本模块将介绍人工智能中一类广泛的问题,称为搜索问题。我们可以将计算机科学中的许多问题形式化为搜索问题,这些问题都可以使用同一套方法来解决。

我们将要探讨的解决问题方法源于早期的算法研究,特别是最短路径算法。我们将看到如何将最短路径算法应用于许多问题,在这些问题中,我们需要在一系列可能的行动序列中进行搜索,以达到期望的目标。

在本模块中,你将学习如何正式定义一个搜索问题,并了解一系列不同的算法,用于解决这个关于搜索问题的通用数学定义。

我们将要研究的搜索问题类别被称为无信息搜索算法。名称中的“无信息”部分源于这样一个事实:我们在探索环境时不使用任何额外的信息。在下一个模块中,我们将学习如何利用额外信息来增强搜索算法。

我们将研究经典的算法,如深度优先搜索和广度优先搜索。然后,我们还将探讨它们的一些有趣变体,这些变体具有一些良好的计算复杂度特性。

从简单反射智能体到问题求解智能体 🤖

在模块1中,我们将理性智能体定义为:给定一个输入感知序列,能够选择最佳行动以最大化其性能度量的智能体。有时,采取什么行动是最佳选择并不立即显而易见。

在这种情况下,智能体通常需要提前规划,并考虑许多可能的行动序列。这种提前规划并尝试制定最佳可能行动序列的过程就叫做搜索。执行搜索的智能体被称为问题求解智能体

最简单的智能体类型是简单反射智能体。一个简单反射智能体使用其传入的传感器数据(我们将其定义为感知),然后仅使用当前感知来决定采取什么行动。

我们这里的例子是一个使用超声波测距仪传感器数据的简单反射智能体。它使用一个非常简单的算法来决定做什么。它向前行驶,直到传感器告诉它即将撞到墙。如果检测到前方有墙,它就停下来,向左转,并检查那里是否也有墙。如果那里也有墙,它就转180度。一旦前方没有墙,它就向前行驶。

这个简单反射智能体与更复杂的智能体之间的主要区别在于,这个智能体只是对其直接环境做出反应,而不进行提前规划。

搜索:寻找行动序列的路径 🧭

问题求解智能体不能简单地根据当前感知选择单一行动。相反,它心中有一个目标,并且必须规划一系列行动以达到该目标。规划一系列行动的过程在人工智能中被称为搜索

我们在这里使用的“搜索”一词,与谈论互联网搜索时的常用方式含义不同。相反,这个术语指的是寻找解决方案的过程,该解决方案由从当前状态出发的一系列行动组成,我们的智能体将利用这些行动,使自身达到某个期望的目标状态。

在这个视频中,我展示了一个问题求解智能体。我点击了网格中的某些方格,希望智能体访问这些位置,用红点表示。蓝点代表智能体的起点。每个红点都是我们希望机器人访问的点。

问题求解智能体必须找到一个行动序列,将其从起始状态带到目标状态。解决方案就是一条路径。从起始状态到目标状态可能存在多条路径,这意味着搜索问题可能存在多个解决方案。

我们感兴趣的是找到最优解。我们将考虑一个解决方案“最优”意味着什么。我们将有一些标准,允许我们比较解决方案,并告诉我们这一系列步骤比另一系列也能到达目标状态的步骤更好。

任务环境对搜索的影响 🌍

在模块1中,我们还讨论了任务环境。任务环境的不同特性会影响搜索问题解决方案的性质。

请记住,我们将环境分为完全可观察环境部分可观察环境。这反映了下国际象棋(在任何时间点我们都能看到棋盘的完整状态)与自动驾驶汽车(我们无法观察整个环境,环境的某些元素是隐藏的)之间的区别。国际象棋发生在完全可观察的环境中,而自动驾驶汽车则在部分可观察的任务环境中运行。

同样,我们讨论了任务环境的其他维度,取决于我们采取的行动是否会产生确定性的结果。如果我们选择移动国际象棋中的马,我们确切地知道它最终会落在哪里,因为在国际象棋中走一步的结果是确定性的。在非确定性环境中,当智能体选择一个行动时,结果可能与其预期相符,也可能不符。

对于本模块,我们将专注于完全可观察、确定性的环境,在这种环境中一切都是已知的。如果我们有那种任务环境,那么任何我们可以形式化为搜索问题的解决方案都将是一个固定的行动序列。这意味着可以存在一个有序的行动列表,智能体可以执行这些行动,从其初始状态移动到其目标状态。

如果我们进入更复杂的环境,要么在计算解决方案时没有完整信息可用,要么行动是非确定性的,那么我们就需要一种不同类型的解决方案。我们将需要一个应急计划,而不是一个固定的行动序列。在课程后面,我们将学习如何制定这样的计划。

总结 📝

本节课中我们一起学习了人工智能中搜索问题的基本概念。我们了解到,搜索是智能体为达到目标而规划一系列行动的过程。我们区分了简单反射智能体与问题求解智能体,后者需要进行搜索。我们还探讨了任务环境(如完全可观察与确定性)如何影响搜索解决方案的形式,即一个固定的行动序列路径。在接下来的课程中,我们将深入探讨具体的无信息搜索算法。

21:搜索问题-II 🔍

在本节课中,我们将学习如何将现实世界中的问题形式化为搜索问题。我们将通过两个具体例子——八数码拼图和地图导航——来理解搜索问题的核心构成要素,并看到看似不同的问题如何能用统一的框架来解决。


将拼图视为搜索问题 🧩

上一节我们介绍了搜索问题的基本概念,本节中我们来看看如何将拼图游戏形式化为一个搜索问题。拼图是人工智能中一个有趣的挑战,因为它们是完全可观测确定性的,非常适合作为搜索问题的起点,并能清晰地定义其中涉及的数学要素。

我们将使用一个滑动拼图作为贯穿的例子。这个滑动拼图的实例被称为八数码问题。它由一个3x3的网格组成,其中包含编号为1到8的八个方块,以及一个位于第九个位置的空白方格。挑战在于通过一系列移动,将方块从初始配置转换到目标状态,即方块按数字1到8递增的顺序排列。

以下是定义搜索问题的关键步骤:

1. 定义状态集合
状态集合是拼图所有可能的配置,即八个方块和空白方格的所有可能排列顺序。

2. 定义动作集合
动作集合定义了在一个状态下可以执行的操作,这些操作会将我们从一个状态转移到另一个状态。在这个例子中,动作是滑动一个方块,也可以等价地看作是与相邻方块交换空白方格的位置。当空白方格在网格中心时,可能的动作最多(向左、向右、向上、向下移动)。当空白方格在边缘或角落时,可能的动作数量会减少。

3. 定义性能度量
在模块1中,我们讨论了理性智能体如何试图最大化性能度量。搜索问题也使用性能度量的概念。其目的是判断一个将我们带到目标状态的解决方案是否比另一个同样能达到目标的解决方案更好。对于拼图,性能度量应能回答“这个解决方案有多好?”显然,最佳解决方案是移动步数最少的那个。因此,我们不是最大化性能度量,而是最小化成本。在八数码问题中,每个动作具有单位成本,意味着向左、向右、向上或向下移动的成本相同。

4. 定义解决方案
搜索问题的解决方案是从起始状态到目标状态的一系列动作序列。在这个例子中,我们可以通过说明每一步移动了哪个方块来表示动作序列。


将地图导航视为搜索问题 🗺️

八数码问题是我们能形式化为搜索问题的一个例子。另一个看似无关但也能形式化为搜索问题的任务是地图导航

我们这里的例子是在罗马尼亚度假。假设你发现自己身处阿拉德市,然后突然想起当天晚些时候有一班从布加勒斯特起飞的飞机。问题就变成了:如何从阿拉德最快地到达布加勒斯特?

这可以方便地用一个图来表示,图中的每个节点都用字母A到Z标记,代表各个城市。

让我们讨论如何将地图导航任务表示为搜索问题。

1. 定义状态集合
在这种情况下,状态集合是地图上的城市集合。当前状态是我们当前所在的城市。

2. 定义目标状态
目标状态是我们想要到达的城市,在这个例子中是布加勒斯特。

3. 定义动作集合
动作是从一个城市开车到另一个城市,前提是它们在图中是相连的。

4. 定义解决方案
解决方案是为了从初始状态(阿拉德)到达最终目标状态(布加勒斯特)而采取的一系列动作。我们可以将解决方案表示为按旅行顺序经过的城市列表。

5. 定义性能度量
最后,我们需要为地图导航任务定义一个性能度量。我们希望最小化诸如旅行时间或行驶距离之类的指标。

解决罗马尼亚度假问题,就是应用一个算法来找到从阿拉德到布加勒斯特的最短路径。我们将要学习的算法与谷歌地图为你提供路线时实际使用的算法非常相似。谷歌地图比我们的问题更复杂的唯一一点是,它必须考虑可能影响某些路段行驶时间的因素,例如交通拥堵或事故。


总结 ✨

本节课中,我们一起学习了如何将不同领域的问题形式化为统一的搜索问题框架。八数码拼图和地图导航看似完全不同,但两者都可以被形式化为具有状态集合动作集合目标状态性能度量(成本) 的搜索问题。因此,我们可以应用完全相同的算法来解决它们。理解这个通用框架是设计和实现有效搜索算法的第一步。

22:为何关注搜索与规划 🧭

在本节课中,我们将探讨为何在人工智能课程中需要学习搜索与规划算法,而不是直接聚焦于像ChatGPT这样的大型语言模型。我们将分析大型语言模型的工作原理,并理解它们在解决规划类问题上的局限性。


上一节我们介绍了课程的整体结构,本节中我们来看看为何要关注搜索与规划这类“经典”人工智能问题。你可能会问,为什么我们要研究地图导航或滑块拼图问题,而不是直接学习像ChatGPT这样激动人心的大型语言模型。

大型语言模型确实是非常令人兴奋的领域,它们也是我的研究方向。事实上,我在宾夕法尼亚大学工程学院在线课程中专门开设了自然语言处理课程。我们将在课程后期深入探讨它们。但首先,我想简要介绍一下大型语言模型的工作原理,以便你自己思考:它们是规划智能体吗?它们能否像我们将要学习的其他算法一样,找到具有相同保证的最短路径?


大型语言模型如何生成文本

首先,让我们理解ChatGPT等大型语言模型如何生成文本。

我们向模型提供一个“提示”。例如,我给出的提示是:“My favorite professor at the University of Pennsylvania is Chris Callison-Burch.” 接下来,模型会尝试像手机输入法自动补全一样,去完成这个句子。

与手机通常只生成一个单词(例如我的姓氏“Birch”)不同,大型语言模型会继续生成整个段落。它接着写道:“He‘s a professor in the Comp and Information Science Department, and he’s the director of the Natural Language Processing Group at the Institute for Research and Cognitive Science.”

第一句是正确的事实,我确实是计算机与信息科学系的教授。但第二句是一个被自信陈述的错误事实,技术术语称之为“幻觉”。

语言模型产生幻觉的部分原因在于,它们生成文本的方式仅仅是基于词语关联。在下图中,我用颜色编码了每个单词,以显示模型在生成时认为该词出现的可能性。

我们可以看到,它将“Birch”标记为非常可能,但将“accomplished”标记为不太可能。然而它仍然生成了“He is an incredibly accomplished professor.” 如果我们点击“accomplished”,会发现语言模型认为我是一位“有成就的教授”的概率只有1%或更低。

实际上,模型会为词汇表中的所有单词分配一个概率分布,然后从这个分布中进行采样。因此,大约有一半的时间,它可能会生成“He‘s an incredibly knowledgeable professor”或“an incredibly engaging professor”。

这种基于概率分布的采样意味着,GPT等大型语言模型本质上只是通过词语关联来生成文本。它们能够生成任何事实性信息,这本身就相当了不起。

它们能够生成一些事实性信息的原因是,在预训练阶段,它们已经在互联网上的海量文本(约一万亿词)上进行了训练。从中,它学习到了一些信息,使得生成的句子听起来像是事实。它学会了将我的名字和宾夕法尼亚大学与我在那里担任计算机与信息科学系教授的角色关联起来,也将我的名字与我从事的自然语言处理研究领域关联起来。

但它也生成了关于我是一个不存在的机构的负责人的信息,而这个机构在我到达宾大之前就已经关闭了。


大型语言模型的能力与局限

尽管语言模型经常产生幻觉,它们仍然在广泛的任务中非常有用。大型语言模型的一个显著涌现能力是它们能够捕捉提示中的模式。

以下是一个“少样本提示”的例子。我输入了一个包含四行的表格,给出了教授姓名、他们工作的大学和所属的院系。我以我自己、英语系的Karen Rle、心理学系的David Brainard以及传播学院的Emily Falk为例。

这是一个初始提示。然后,我可以要求它为其他大学的教授完成新的行。在这种提示的上下文中,它能够进行“上下文学习”。它识别出我正在构建一个具有特定模式的表格:每一行都有姓名、大学和院系三个语义部分。当我用新的姓名提示它时,它能够完成它学习到的模式,并生成那些教授所属的大学和院系。

这是通过在海量文本上进行预训练使大型语言模型具备的一项非常惊人的能力。

另一项涌现的惊人能力是“指令遵循”。我们可以给大型语言模型下达指令,例如“以第一人称写一篇Chris Callison-Burch的传记”,它能够生成遵循我们给定指令的文本。


大型语言模型能作为规划智能体吗?

一个很自然的问题是:我们能利用这些能力让大型语言模型成为规划智能体吗?我们能要求大型语言模型找到从Arad到Bucharest的最短路径吗?

让我们试试看。首先记住,从Arad到Bucharest的最短路径是:Arad -> Sibiu -> Rimnicu Vilcea -> Pitesti -> Bucharest。这条路径的总成本是:140公里 + 80公里 + 97公里 + 101公里 = 418公里。我们把这个正确答案记在心里。

然后,我们直接问GPT:“What‘s the shortest path from Arad to Bucharest?” 令人惊讶的是,它答对了。它给出了正确的路径:Arad -> Sibiu -> Rimnicu Vilcea -> Pitesti -> Bucharest。

它实际上产生了正确的最短路径,但理由完全错误。请注意,在我的提示中,我没有提供任何关于地图本身的信息,没有给出带权重的无向图。它之所以能给出正确答案,是因为它在互联网上见过这个例子。这是一个非常著名的例子,所有人工智能入门课程都会使用它,模型只是记住了它,或者将“从Arad到Bucharest的最短路径”与这个信息关联了起来。

如果我们问一个后续问题,比如“这条路径的最低路径成本是多少?”,而不是生成正确答案418,它会产生一个不可能的、错误的路径成本:366。

如果我们点击这个数字,会再次看到它只是对词语(这里是数字)有一个概率分布。这既不是生成最短路径的正确方法,也不是分析实际路径成本的正确方法。


测试模型的泛化能力

如果我们从一个它可能在训练数据中见过的著名问题,转换到一个高度类似但全新的问题,这一点会更加明显。

在这里,我拿罗马尼亚地图,将所有城市名替换为《星球大战》中的行星名。所有的路径成本与之前完全相同。因此,这张地图上的最短路径应该相同,只是地点名称不同。例如,Arad变成了Alderaan。从Alderaan出发,我们应该去:Starkiller Base -> Ryloth -> Naboo -> Kessel。因为使用了相同的边权重,这条最短路径的成本同样是418公里。

现在,我将这个信息给GPT。作为提示的一部分,我给出了:“Here‘s a list of distances between nodes in an undirected graph: [完整的节点和边权重列表]。What is the shortest path from Alderaan to Kessel?”

它会给出一个完全错误的答案和一个错误的路径成本。如果我让它重新生成,它会给出一个完全不同的路径和答案。


结论

由于大型语言模型的工作方式——通过从概率分布中采样来尝试生成下一个词——它们本身并不是规划智能体。它们无法自然地找到最短路径,或者独立完成我们在人工智能中希望实现的一些非常基础的事情。

我认为,将经典人工智能算法与大型语言模型相结合,前景非常广阔。正因如此,我们将从这些经典算法开始学习。


本节课中我们一起学习了关注搜索与规划算法的原因。我们分析了大型语言模型基于概率关联的文本生成机制,了解了其产生“幻觉”的原因,并通过具体测试证明了它们在解决需要精确推理和规划的图搜索问题上的根本局限性。这为我们后续深入学习能够提供确定性解决方案的经典搜索算法奠定了重要的认知基础。

23:搜索问题建模-I

在本节课中,我们将学习如何形式化地定义一个搜索问题。理解搜索问题的构成要素是设计有效搜索算法的基础。

概述

一个搜索问题可以被系统地定义为六个核心组成部分。本节将逐一介绍这些组成部分,并通过一个“吸尘器世界”的简单例子来具体说明。

搜索问题的六个要素

上一节我们提到了搜索问题需要六个要素,本节中我们来看看具体是哪六个。

以下是定义一个搜索问题所需的六个组成部分:

  1. 状态集合:所有可能情况的集合。
  2. 初始状态:搜索开始时所处的状态。
  3. 动作集合:从任何状态可以执行的所有可能操作的集合。
  4. 转移模型:一个函数,描述在特定状态下执行特定动作后,会到达哪个新状态。其形式为 RESULT(s, a) = s',其中 s 是当前状态,a 是执行的动作,s' 是结果状态。
  5. 目标测试:一个函数,用于检查给定状态是否为目标状态。其形式为 GOAL-TEST(s) = True/False
  6. 路径耗散函数:为从初始状态到目标状态的每条路径分配一个成本值。它通常由每一步的动作成本累加而成。动作成本函数 c(s, a, s') 定义了从状态 s 通过动作 a 到达状态 s' 所需的成本,且必须满足 c(s, a, s') ≥ 0

示例:吸尘器世界

为了更直观地理解这些概念,我们来看一个经典的“吸尘器世界”例子。

状态定义

假设我们有一个仅包含两个单元格(A和B)的世界。一个吸尘器代理位于其中一个单元格中。每个单元格可以是干净的或脏的。

那么,这个世界的总状态数是多少?代理有2个可能位置,每个单元格有2种(干净/脏)状态。因此,总状态数为:2(代理位置) * 2(A格状态) * 2(B格状态) = 8

更一般地,对于一个有 N 个单元格的世界,总状态数为:N * 2^N

下图展示了这8种可能的状态:

初始状态与动作

在定义搜索问题时,我们需要从这8个状态中指定一个作为初始状态。算法应该能够从任意指定的初始状态开始运行。

接下来,我们需要定义动作集合转移模型。在这个世界中,可能的动作包括:

  • Suck:清扫当前单元格。
  • Left:向左移动(如果可能)。
  • Right:向右移动(如果可能)。

转移模型

转移模型定义了在特定状态下执行动作后会发生什么。下图以图形方式展示了从某个状态出发的转移:

例如,在左上角的状态(代理在左格,两格都脏):

  • 执行 Left 动作:撞墙,状态不变。
  • 执行 Right 动作:代理移动到右格。
  • 执行 Suck 动作:左格变干净,代理仍在左格,进入新状态。

目标测试与路径耗散

在这个问题中,目标测试是检查是否所有单元格都干净了。因此,目标状态是代理在任何位置,但A格和B格均为干净的状态。

对于路径耗散,我们通常采用简单的定义:每个动作的成本为1。因此,一条路径的总成本就是该路径中动作的数量。

解与最优解

基于以上完整定义,一个就是一系列能将我们从初始状态带到目标状态的动作序列。

可能存在多个解。最优解是指没有其他解的总路径成本比它更低。评估搜索算法好坏的一个关键标准,就是看它能否保证找到最优解。

总结

本节课中,我们一起学习了如何形式化地定义一个搜索问题。我们明确了构成搜索问题的六个核心要素:状态集合、初始状态、动作集合、转移模型、目标测试和路径耗散函数。我们通过“吸尘器世界”这个具体例子,演示了如何应用这些要素来建模一个实际问题。理解这个框架是后续学习各类搜索算法(如广度优先搜索、A*搜索等)的重要基础。

24:搜索问题建模-II 🧩

在本节课中,我们将学习如何将一个现实世界的问题抽象并建模为一个搜索问题。我们将深入探讨状态表示、动作定义以及抽象过程的核心概念,并通过八数码拼图等例子来具体说明。


将问题抽象为搜索问题

上一节我们介绍了搜索问题的基本组成部分。本节中我们来看看如何将现实世界的问题“映射”到这些组成部分上。这个过程本质上是一种抽象。

我们所做的是,将现实世界的问题从其具体情境中抽离出来,转化为一个可以通过定义状态集合初始状态转移函数目标测试来处理的搜索问题。


抽象与表示

当我们把某件事表述为一个搜索问题时,大部分工作在于创建问题的表示。你可以将搜索问题的形式化定义本身看作一种表示。我们真正在做的是,抽象掉所有与“如何找到解决方案”无关的东西

现实世界中有许多事物在我们的日常行为中很重要,但在将问题表述为搜索问题时却无关紧要。例如,如果我们试图在地图上旅行,找到从一个城市到另一个城市的最快路线。

  • 在现实生活中,我们到达目的地的方式是相关的:我们乘坐出租车、网约车、自己开车、骑自行车或步行等。
  • 但是,当我们将问题抽象为搜索问题时,所有这些方式本质上都被归入一个等价类。动作就只是“从一个位置移动到另一个相连的位置”。

我们可以选择的动作类型,将取决于我们问题表述的复杂或简单程度。状态的数量可能的动作数量会极大地影响搜索的组合复杂性。

实例:八数码拼图的状态表示

让我们回到八数码拼图的例子。如何表示八数码拼图中的状态?

我们说过,所有数字的排列顺序很重要,棋盘的布局很重要。我们真正关心的是棋盘上各个方块的位置,并且能够枚举所有可能的位置。

基本上,我们可以将其表示为:

  • 一个二维数组
  • 或者只是一个简单的一维数组,我们按顺序读取排列。

因此,一个起始状态可以用这个一维数组表示:[7, 2, 4, 5, 空白, 6, 8, 3, 1]。这就是棋盘状态的一个很好的表示。

初始状态就是这些列表中的一个。

动作可以定义为从中心位置可能的移动集合。我们可以将空白格向上、向右、向左或向下移动。在某些特定位置(如角落或边缘),我们可能无法进行所有方向的移动。

转移模型是在我们应用动作后改变表示的东西。我们可以遍历当前状态,并按升序/降序排列。

路径成本:每次移动的权重相等。每个动作的成本为1。总路径成本将是我们采取的动作数量。

抽象的艺术与挑战

将问题表述为搜索问题的一个棘手之处在于,现实世界非常复杂。


我们需要做的是抽象掉细节抽象问题,以简化我们要解决的问题。你可以将状态视为现实世界状态的等价类,将动作视为不同现实世界动作组合的等价类。

我们将把所有从A城市到相邻B城市的不同方式(开车、步行等)归并为一个单一的动作,一个单一的等价类。

这种抽象的概念非常棒,因为它简化了实际问题,使其更容易、更可能让我们以这种数学方式来考虑它。

核心概念回顾与扩展

到目前为止,我们遇到的不同概念包括:

  • 状态空间:从初始状态出发,通过任何动作序列可以到达的所有可能状态的集合。这里事情变得有趣,因为理论上我们可以有一个无限的搜索空间,这也没问题。
  • 分支因子:当从每个状态可能有很多动作时,状态空间会迅速变得非常大。也可能并非所有状态都能从特定配置到达。例如在拼图游戏中,你可能无法从任何给定的起始状态得到所有可能的排列。
  • 路径:一个动作序列。
  • 搜索树:一个非常有用的概念是,我们如何表述搜索问题可以表示为一棵搜索树。我们从根节点(初始状态)开始。分支因子与我们在每个状态可以采取多少动作有关。
  • 边界:我们将有一个称为边界的概念,它包含了所有可供扩展的状态。意思是,我将选择要对哪个状态应用动作,以产生通往解决方案的下一个状态。
  • 解决方案:解决方案将是从初始状态到满足目标测试的最终状态的一条路径。


本节课中我们一起学习了如何将现实问题抽象为搜索问题的关键步骤。我们理解了状态和动作的表示方法,以及通过等价类进行抽象的重要性。我们还回顾并扩展了状态空间、路径、搜索树和边界等核心概念,为后续学习具体的搜索算法打下了坚实的基础。

25:基本搜索算法 🧠

在本节课中,我们将学习搜索算法的基本概念,特别是如何通过搜索树和搜索图来表示和解决搜索问题。我们将从最通用的树搜索算法开始,然后探讨如何通过避免重复状态将其优化为图搜索。

搜索树表示法 🌳

上一节我们介绍了搜索问题的基本概念,本节中我们来看看如何用搜索树来表示搜索空间。

搜索树是一种表示所有可能路径的结构。树的根节点是初始状态。从该状态出发,通过应用可能的动作(或转换)来生成子节点,从而扩展树。

以下是构建搜索树的关键步骤:

  1. 将初始状态作为根节点。
  2. 从当前节点(状态)出发,应用所有可能的动作,生成新的状态作为其子节点。
  3. 在树搜索中,即使到达的是同一个状态,不同的路径也会被视为不同的节点。

下图展示了从初始状态“Arad”出发,通过相邻城市连接生成子节点“Sibiu”、“Timisoara”和“Zerind”的搜索树片段。

通用树搜索算法 🔍

理解了搜索树的表示后,我们来看一个通用的树搜索算法伪代码。这个算法定义了如何系统地探索搜索空间以找到目标。

算法从一个包含初始状态的“边界”列表开始。只要边界不为空,算法就会根据某种策略选择一个节点进行扩展,检查它是否是目标状态。如果不是,则扩展该节点(即生成其所有子节点),并将这些子节点添加回边界列表。

以下是该算法的核心步骤:

  1. 初始化边界:将初始状态放入边界列表。
  2. 循环检查:当边界列表不为空时,执行以下操作:
    a. 选择节点:根据特定策略从边界中选择一个节点。
    b. 移除节点:将该节点从边界中移除。
    c. 目标测试:检查该节点是否为目标状态。如果是,则返回该节点(即找到解)。
    d. 扩展节点:如果不是目标,则扩展该节点,生成所有可能的后继状态(子节点)。
    e. 更新边界:将这些新生成的子节点添加到边界列表中。
  3. 无解情况:如果边界列表变空,则说明不存在从初始状态到目标状态的路径。

选择边界中下一个要扩展节点的策略(步骤2a)至关重要,不同的策略(如深度优先、广度优先)将导致完全不同的搜索行为。

搜索树中的节点数据结构 📦

上一节我们介绍了算法的流程,本节中我们来看看算法操作的具体对象——节点。在搜索树中,一个“节点”不仅仅是一个状态,它是一个包含更多信息的数据结构。

对于一个八数码游戏,状态是棋盘的布局。但搜索树中的节点是一个数据结构,它包含:

  • 状态:当前棋盘的具体布局。
  • 父节点指针:指向到达当前节点的上一个节点。
  • 子节点列表:指向从当前节点可以到达的所有后续节点。
  • 深度:从根节点到当前节点的路径长度。
  • 路径成本:从初始状态到达当前状态所累积的代价。

下图展示了一个八数码游戏搜索树的节点结构示例。

对于每个节点,我们可以应用一个“扩展”函数。这个函数会利用该节点所包含状态的所有可能动作和转换模型,生成一组对应的新状态,从而创建一组新的子节点,并更新深度、路径成本等字段。

重复状态问题与图搜索 🔄

在通用搜索问题中,一个常见的问题是重复访问相同的状态。如果我们未能检测到重复状态,可能会将一个线性复杂度的问题变成指数级复杂的问题。

例如,左侧是一个线性问题,如果允许走回头路和冗余路径,搜索空间就会如右侧所示呈指数级膨胀。这会将一个可处理的问题变得难以处理。我们真正需要做的是确保避免冗余地扩展相同的状态。

为了解决这个问题,我们可以对基础的树搜索算法进行增强,引入一个额外的数据结构来记录所有已经访问过的状态。这个数据结构通常是一个集合,我们称之为“已探索集”。它帮助我们记住所有已经扩展过的节点,从而将树搜索转化为图搜索。

下图对比了无重复状态检测(树搜索,可能指数增长)和有检测(图搜索,避免冗余)的情况。

图搜索算法 🗺️

基于对重复状态问题的分析,我们现在来看图搜索算法。它是对树搜索的一个简单但关键的修改。

图搜索与树搜索的主要区别在于增加了一个“已探索集”。算法在从边界中选择一个节点进行扩展后,会先将该节点加入已探索集。然后,在扩展该节点生成子节点时,会检查每个子节点对应的状态是否已经存在于已探索集(或边界)中。如果已经存在,则忽略该子节点,不将其加入边界。这样可以有效避免循环和冗余路径,确保搜索不会重复访问同一状态。

以下是图搜索算法的伪代码,突出显示了与树搜索的主要差异:

function GRAPH-SEARCH(problem):
    frontier = {INITIAL-STATE(problem)} // 初始化边界
    explored = {} // 初始化已探索集为空

    while frontier is not empty:
        node = POP(frontier) // 根据策略从边界选择节点
        add node to explored // 将节点加入已探索集

        if GOAL-TEST(problem, STATE(node)):
            return SOLUTION(node) // 找到目标,返回解
        for child in EXPAND(node, problem): // 扩展节点
            if child.state not in explored and child.state not in frontier:
                add child to frontier // 仅当状态未被探索且不在边界中时加入
    return failure // 边界为空,无解

使用已探索集的一个潜在缺点是内存消耗。对于状态空间很大的问题(例如八数码游戏有约9!种状态),记录所有已访问状态可能需要大量内存。因此,在评估搜索算法时,我们不仅会分析其找到解的速度(时间复杂度),也会分析其内存需求(空间复杂度)。

下图直观对比了树搜索与图搜索的伪代码逻辑。

总结 📝

本节课中我们一起学习了基本搜索算法的核心思想。我们首先了解了如何使用搜索树来表示问题的所有可能路径,并学习了通用的树搜索算法框架。接着,我们认识到树搜索可能因重复状态导致效率低下,进而引入了“节点”数据结构来封装状态、路径等完整信息。为了解决重复状态问题,我们通过在算法中加入“已探索集”,将树搜索优化为图搜索,从而避免了冗余扩展,显著提升了搜索效率。最后,我们对比了树搜索和图搜索的伪代码,明确了图搜索通过状态查重来保证搜索在状态空间图上进行,而非在可能包含重复状态的树上进行。这种抽象的搜索形式化方法(无论是树还是图)是许多更高级人工智能算法的基础。

26:无信息搜索策略

在本节课中,我们将要学习搜索算法中的核心概念——无信息搜索策略。我们将探讨什么是无信息搜索,如何通过不同的队列数据结构实现不同的搜索策略,以及如何评估这些策略的性能。


上一节我们介绍了搜索问题的基本框架和边界(Frontier)的概念。本节中,我们来看看如何从边界中选择下一个要扩展的节点,即搜索策略。

一旦我们构建了边界,就可以开始研究具体的搜索策略。我们用来从边界中选择下一个扩展节点的策略,被称为无信息搜索策略。无信息搜索的另一个名称是盲目搜索。这意味着我们不会利用任何关于问题世界的额外信息来指导搜索,而仅仅依据问题本身的定义(例如罗马尼亚地图)进行搜索。我们甚至不会考虑当前节点是否大致朝向目标(布加勒斯特)的方向。


这种搜索是“盲目”的。盲目搜索的核心思想是,我们只使用问题定义中提供的信息。非正式地说,这意味着边界上所有非目标节点看起来都一样好,我们可以选择其中任何一个进行扩展。在后续课程中,我们将开始学习有信息搜索,届时我们将能够区分边界上的非目标节点,并允许某些节点获得更高的优先级,利用关于世界的启发式信息来指导搜索顺序。

那么,什么是搜索策略?它指的就是我们扩展边界队列中节点的顺序。当我们创建搜索算法时,我们会给它不同类型的队列:优先级队列、先进先出队列或后进先出队列。通过为边界实现这些不同类型的队列数据结构,算法在决定下一个扩展哪个节点时会产生不同的行为,从而得到不同的搜索算法。

根据我们赋予搜索算法的策略,它将表现出不同的行为。我们通过多个维度来评估搜索策略的性能。

以下是评估搜索策略的几个关键维度:

  • 完备性:如果解存在,算法是否总能保证找到一个解?
  • 最优性:算法是否总能首先找到成本最低的解?当我们找到一个解时,是否保证该解与其他任何解相比具有最低的路径成本?
  • 复杂度:正如之前提到的,我们关注算法的渐近特性,包括时间复杂度空间复杂度(存储已访问集合等辅助数据结构所需的内存量)。

一些用于分析算法渐近运行时间的有用变量包括:

  • 分支因子 b:这是从任何状态可以采取的可能行动的最大数量。
  • 目标节点深度 d:搜索树中目标节点的最浅深度。
  • 最大深度 m:搜索空间中任何路径的最大长度。如果图是循环的,最大深度可能是无限的。

当我们讨论时间复杂度和空间复杂度时,需要回顾数据结构和算法的基础知识。我们将讨论大O表示法。你已经了解时间复杂度的大O表示法,空间复杂度在算法课程中可能涉及过,但它与时间复杂度的概念完全类似。

空间的单位是任意的,讨论千字节、兆字节还是字节并不重要。原因在于大O表示法会忽略这些常数因子(如千、百万)。我们只讨论大O表示法,这使我们能够在上界方面进行比较。

当我们讨论设置搜索策略的不同方法时,我提到我们将使用队列数据结构作为边界。我们选择的不同队列类型将导致不同的搜索策略。


本节课中,我们一起学习了无信息(盲目)搜索策略的基本概念。我们了解到,搜索策略本质上决定了扩展边界节点的顺序,而通过为边界实现不同类型的队列(如FIFO、LIFO、优先级队列),可以得到不同的搜索算法。我们还介绍了评估搜索策略的几个关键标准:完备性、最优性以及时间和空间复杂度,并回顾了用于复杂度分析的大O表示法和相关变量(分支因子b、目标深度d等)。下一节,我们将具体探讨几种经典的无信息搜索算法。

27:广度优先搜索与深度优先搜索回顾 🧭

在本节课中,我们将要学习两种基础的图搜索算法:广度优先搜索(BFS)和深度优先搜索(DFS)。我们将回顾它们的基本思想、实现方式、性质以及各自的适用场景。


广度优先搜索(BFS)回顾

广度优先搜索的核心思想是,从起始状态开始,逐层向外扩展,总是优先扩展最浅的、未被扩展的节点。其目标是逐步向外辐射,选择那些最初离起始状态最近的节点。

为了实现广度优先搜索,我们需要将边界队列(frontier)实现为一个先进先出队列(FIFO Queue)。每次创建一个后继节点时,只需将其放入列表的末尾。

以下是广度优先搜索的伪代码:

function BFS(initialState):
    frontier = FIFO_Queue()
    frontier.enqueue(Node(state=initialState))
    explored = set()

    while frontier is not empty:
        node = frontier.dequeue()  # 弹出最浅的节点
        if node.state == goalState:
            return solution_path(node)
        explored.add(node.state)

        for action in possible_actions(node.state):
            child = Node(state=apply(action, node.state), parent=node)
            if child.state not in explored and child not in frontier:
                if child.state == goalState:
                    return solution_path(child)
                frontier.enqueue(child)
    return failure  # 无解

在BFS中,检查节点是否为目标状态的时机是在节点被扩展时。如果我们不这样做,算法可能会多运行一层。

接下来,我们可以分析BFS的性质:

  • 完备性:是的。如果分支因子有限,BFS保证能找到解。
  • 时间复杂度:在最坏情况下,需要探索的节点数约为 O(b^d),其中 b 是分支因子,d 是最浅目标节点的深度。
  • 空间复杂度:与时间复杂度相同,也是 O(b^d),因为需要存储所有已访问的节点以避免重复。
  • 最优性:在所有行动代价相同(例如,每个行动代价为1)的条件下,BFS保证能找到最短路径(即深度最浅)的解。如果行动代价不同,BFS则不是最优的。

BFS的渐近复杂度并不理想,因为它是指数级的。当深度 d 较大时,所需的时间和内存会急剧增长。

例如,假设分支因子为10:

  • 当最大深度为2时,探索节点数约为110,时间在毫秒级,内存需求在千字节级。
  • 当最大深度为10时,探索节点数约为10^10,可能需要数小时,并且如果每个节点用1KB的数据结构表示,则需要约10TB的内存。

从这个例子中我们可以学到两点:

  1. 内存需求有时比实际执行时间更关键。
  2. 这类具有指数复杂度的问题,通常无法通过无信息搜索方法有效解决。我们将在后续课程中学习能大幅减少搜索时间的有信息搜索方法。


深度优先搜索(DFS)回顾

上一节我们介绍了逐层扩展的广度优先搜索,本节中我们来看看另一种策略:深度优先搜索。

深度优先搜索的核心思想与BFS相反,它试图尽可能深地探索图的分支。它不是扩展最浅的节点,而是扩展最深的节点,即“一条路走到黑”。

为了实现深度优先搜索,我们需要将边界队列实现为一个后进先出队列(LIFO Queue,即栈)。这意味着每当生成一个后继节点时,它会被放到边界队列的最前面。

与BFS类似,我们可以分析DFS的性质:

  • 完备性完备。如果搜索空间深度无限(或存在循环),DFS可能会先沿着一条错误路径无限深入,从而永远找不到目标。
  • 时间复杂度:在最坏情况下,需要探索的节点数约为 O(b^m),其中 b 是分支因子,m 是状态空间的最大深度。如果 m 远大于目标深度 d,这会非常糟糕。
  • 空间复杂度:比BFS好得多,仅为 O(b*m),是线性的。
  • 最优性:DFS不是最优算法,它不保证找到最短路径。


BFS与DFS的比较与应用场景

我们已经了解了两种由不同优先级队列实现的算法:广度优先搜索和深度优先搜索。

以下是选择使用哪种算法的一些指导原则:

应该使用深度优先搜索的情况:

  • 空间复杂度是主要限制因素时,因为DFS具有线性空间复杂度,而非指数级。
  • 一个实际适用场景是:存在许多可能的解,并且错误路径能很快终止(即搜索空间深度有限)。

应该使用广度优先搜索的情况:

  • 当搜索空间可能深度无限时。
  • 当我们知道解可能位于较短的路径上,并且需要找到最短路径(在行动代价相同的条件下)。

这两种算法具有不同的特性,形成了一种权衡:

  • 广度优先搜索是完备且最优的(在等代价条件下),但需要指数级的空间。
  • 深度优先搜索甚至不是完备的(除非深度有限),也不是最优的,但它使用的空间量相对合理。

总结

本节课中我们一起学习了两种基础的图搜索策略:广度优先搜索和深度优先搜索。我们回顾了它们的工作原理、伪代码实现、各自的优缺点(完备性、最优性、时间与空间复杂度)以及典型的应用场景。理解这两种基本算法是学习更高级搜索技术的重要基础。

28:深度受限搜索与迭代加深搜索 🧠

在本节课中,我们将学习如何结合两种无信息搜索策略的优点,设计出更高效的算法。我们将重点介绍深度受限搜索迭代加深搜索,并分析它们的性能。

概述

上一节我们讨论了深度优先搜索和广度优先搜索各自的优缺点。本节中,我们来看看能否设计一种算法,结合两者的优点。我们将从深度受限搜索开始,它是构建新算法的基础模块。

深度受限搜索

深度受限搜索是深度优先搜索的一种变体。其核心思想是:在搜索过程中,限制搜索的最大深度为某个数值 L。一旦达到深度 L,就不再扩展该节点的后继节点。

以下是深度受限搜索的伪代码描述:

def depth_limited_search(node, problem, limit):
    if problem.is_goal(node.state):
        return solution(node)
    elif limit == 0:
        return 'cutoff'
    else:
        cutoff_occurred = False
        for child in expand(node, problem):
            result = depth_limited_search(child, problem, limit - 1)
            if result == 'cutoff':
                cutoff_occurred = True
            elif result is not None:
                return result
        if cutoff_occurred:
            return 'cutoff'
        else:
            return None

如果限制深度 L 恰好等于最浅目标节点的深度,那么深度受限搜索是最优的。然而,如果 L 小于最浅目标节点的深度,算法将变得不完整,因为它会在找到解之前停止。反之,如果 L 大于目标深度,它可能找不到最优解。

深度受限搜索的优势在于其空间复杂度较低。其空间复杂度为 O(b × L),其中 b 是分支因子。时间复杂度为 O(b^L)

迭代加深搜索

为了克服深度受限搜索的缺点,我们引入迭代加深搜索。它不是固定一个深度限制,而是逐步增加限制深度 L

其基本策略如下:

  1. 从深度限制 L = 0 开始。
  2. 执行深度限制为 L 的深度受限搜索。
  3. 如果找到解,则返回。
  4. 如果未找到解,则将深度限制 L 增加 1,然后重复步骤 2。

这个过程可以形象地理解为:先探索深度为 0 的所有节点,然后是深度为 1 的所有节点,接着是深度为 2 的节点,依此类推,直到找到目标。

迭代加深搜索结合了深度优先搜索和广度优先搜索的优点:

  • 完整性:只要没有无限路径,它就是完整的,因为深度限制最终会增加到无穷大。
  • 最优性:在路径代价一致的情况下,它是最优的。因为它会先探索深度为 3 的所有节点,然后才探索深度为 4 的节点,因此找到的第一个解必然是最浅的(即最优的)。
  • 空间复杂度:与深度受限搜索相同,为 O(b × d),其中 d 是最浅目标节点的深度。这远优于广度优先搜索的 O(b^d)
  • 时间复杂度:虽然看起来重复探索了浅层节点,但其渐进时间复杂度与广度优先搜索相同,为 O(b^d)

性能分析

理解如何分析这些搜索算法的性能至关重要。以下是需要掌握的分析要点:

  • 渐进时间复杂度:算法运行时间随问题规模增长的趋势。
  • 渐进空间复杂度:算法所需内存空间随问题规模增长的趋势。
  • 完整性:当解存在时,算法是否保证能找到解。
  • 最优性:算法是否保证能找到最优解(例如,路径最短或代价最低的解)。

通过分析这些属性,我们可以判断在何种情况下应该使用哪种搜索算法。

总结

本节课中我们一起学习了两种重要的无信息搜索策略:深度受限搜索和迭代加深搜索。深度受限搜索通过限制搜索深度来控制空间使用,但可能不完整或非最优。迭代加深搜索通过逐步增加深度限制,巧妙地结合了深度优先搜索的空间效率和广度优先搜索的完整性及最优性(在代价一致的情况下),成为一种非常实用的搜索算法。掌握这些算法的原理和性能分析,是选择合适工具解决不同搜索问题的基础。

29:启发式搜索导论 🧭

在本节课中,我们将要学习一种能更快找到问题解决方案的搜索方法——启发式搜索。我们将了解什么是启发式知识,以及如何利用它来引导搜索过程。

启发式搜索概述

我们常常可以更快地找到搜索问题的解决方案,前提是我们拥有一些关于当前状态距离目标状态大致远近的知识。

上一节我们介绍了无信息搜索算法,它们不利用任何关于目标位置的知识。本节中我们来看看启发式搜索算法。这类算法能够将关于剩余距离的启发式知识融入搜索过程。

我们将看到,启发式搜索算法通常能够比无信息搜索算法更快地找到解决方案。

启发式搜索的局限与优势

然而,我们也会发现,如果只是简单地融入启发式信息,某些启发式搜索算法虽然能找到解决方案,但这些方案不一定是最优解

以下是两个关键点:

  • 例如,我们将看到,贪婪搜索算法通常比无信息搜索更快地到达一个解,但不能保证该解是最优的。
  • 相比之下,在本模块中,我们将重点学习最著名的启发式搜索算法——A*搜索。它能够保证首先返回最优解。

A*搜索的核心:可采纳启发函数

A*搜索之所以能取得这一卓越成果,是因为它对可以融入的启发式知识类型施加了约束。

A*搜索需要一个可采纳启发函数。可采纳启发函数保证永远不会高估到达目标的剩余距离。

通过使用可采纳启发函数,A*搜索成为一种最优算法,能够保证首先返回最优解。

总结

本节课中我们一起学习了启发式搜索的基本概念。我们了解到,利用关于目标距离的启发式知识可以显著加快搜索速度。同时,我们认识到简单的启发式方法(如贪婪搜索)可能无法找到最优解,而A*搜索通过要求可采纳启发函数这一关键约束,成功地在利用启发式信息的同时,保证了找到最优解。

30:一致代价搜索 (Uniform Cost Search) 🧭

在本节课中,我们将要学习一种新的无信息搜索算法——一致代价搜索。我们将了解它如何考虑行动的成本,以及它与广度优先搜索的区别。


上一节我们介绍了广度优先搜索和深度优先搜索,它们都假设每一步的成本是相同的。但在现实问题中,例如星际旅行,从一个星球到另一个星球的距离或时间成本是不同的。本节中,我们来看看如何将这种成本因素纳入搜索过程。

一致代价搜索是一种用于加权图的搜索树算法。当我们有一张宇宙地图,并且知道前往相邻星球的距离时,这个算法就会将这些距离成本考虑在内。

其动机正是为了解决这类地图导航问题。我们不再假设所有步骤的成本都相等,而是允许一个更通用的算法。现在,对于关心行动成本的问题(无论是从一个地方到另一个地方的旅行时间还是距离),这些成本都将被整合到算法中。

这引出了一个重要的概念:我们使用优先队列来实现一致代价搜索。在整个过程中,我们将路径成本定义为函数 g(n)。路径成本是指从初始节点到达当前特定节点需要多少成本。对于深度优先搜索和广度优先搜索,我们可以简单地将 g(n) 视为为到达当前节点所扩展的节点数量。但更一般地说,路径成本将是为了到达这里,从一个节点转换到其后继节点的成本总和。它是遍历每个行动以从一个节点到另一个节点的成本之和,这是一个简单的加法过程。这意味着,假设我们所有的成本都是正数(这是许多搜索算法的要求),那么随着路径的扩展,g(n) 也会单调增加。


一致代价搜索算法是一种扩展搜索空间的方式,类似于广度优先搜索。但它不是扩展深度最浅的节点,而是扩展路径成本最低的节点。在广度优先搜索中,我们使用先进先出队列,而在一致代价搜索中,你将使用一个优先队列。你添加到优先队列中的每个新节点都会有一个相关的成本,即到达该节点的路径成本 g(n),然后你只需简单地移除当前路径成本最低的那个节点。

广度优先搜索和一致代价搜索之间有一个细微的区别:测试节点是否达到目标状态的时机。在一致代价搜索中,是在节点被选择进行扩展时进行测试;而在广度优先搜索中,是在你将其添加到边界时进行测试。在进行广度优先搜索时,你保证拥有最低成本;但在进行一致代价搜索时,可能有多种方式到达同一个节点,队列中可能仍然存在成本更低的一条路径。


关于搜索的一个有趣之处在于,你可以可视化搜索的形状。这实际上是一致代价搜索得名的原因。搜索的形状将绘制出一张等价类的“地图”,它根据成本均匀地扩展搜索的形状。所有处于等价类中的节点(即成本小于或等于100的节点)将遵循这些等高线之一。在广度优先搜索中,我们有这种同心圆状的搜索形状,从中间初始状态开始,以这种均匀增长的方式向外扩展。一致代价搜索则具有不同的拓扑结构,地图上有不同的轮廓线。它将所有具有相似距离的节点保持在同一“层”中,然后将所有其他具有等效距离的节点放在另一层,并逐渐向外扩展。在我们的拓扑结构中,内部的节点将是成本最低的节点,并逐渐添加成本越来越高的节点。因此,它为我们提供了一种优先探索路径的方式,而不是将所有路径视为平等,它会优先考虑成本较低的路径。

让我们看看它是什么样子的。这里我再次绘制了宇宙地图。我们将从凯瑟尔出发,试图到达奥德朗。根据从凯瑟尔出发的最低成本来扩展节点,下一个应该扩展哪个节点?它将是贝斯本,然后是杰纳斯,接着是马布。随着我继续扩展,我将首先搜索所有成本低于200的节点,所以蓝色环内的所有节点都是路径成本低于200的节点。然后,灰色环内的所有节点将是路径成本低于300的节点,这就是扩展的顺序。一致代价搜索的理念是,不是先扩展直接相邻的节点,而是先扩展成本最低的节点。


但是,一致代价搜索有什么问题呢?其中一个问题是,我们可能对星系的形状有所了解,我们可能会问:当我们知道目标正好在相反方向时,为什么我们甚至要考虑前往福拉方向的路径?我们为什么要费心朝这个方向走呢?这个想法引出了我们的第一个有信息搜索策略。到目前为止,我们一直在讨论无信息搜索,而我们在这里添加的信息是:我们知道目标所在的方向。


本节课中我们一起学习了一致代价搜索算法。我们了解到,它是一种考虑行动成本的搜索方法,使用路径成本函数 g(n) 和优先队列来选择下一个扩展的节点。与广度优先搜索不同,它在节点被弹出队列进行扩展时才检查目标状态。我们还看到了算法如何根据成本均匀地扩展搜索空间,形成成本等高线。最后,我们指出了它的一个潜在缺点——可能探索远离目标的方向,这为引入利用额外信息(如目标方向)的启发式搜索策略做好了铺垫。

31:启发函数 🧠

在本节课中,我们将要学习启发式搜索策略。与无信息搜索不同,启发式搜索会利用一个估计值,这个估计值包含了当前状态到目标状态的距离信息。我们将探讨两种启发式搜索策略:最佳优先搜索和A*搜索,并理解启发函数的核心作用。

上一节我们介绍了无信息搜索,本节中我们来看看如何利用额外信息来更高效地搜索。

启发式搜索与评估函数

在启发式搜索策略中,除了路径本身,我们还会包含一个对到目标距离的估计值。我们将研究两种启发式搜索策略,其中一种称为最佳优先搜索策略。我们将利用这个到目标的距离估计值,完全基于一个评估函数来决定如何探索。

本课程这部分将描述几个不同的函数:

  • 路径成本函数G(n)。它表示从起始节点到当前节点 n 的实际累积成本。
  • 评估函数F(n)。它用于评估节点 n 的优先级。
  • 启发函数H(n)。这将是我们使用的启发函数,它估计从节点 n 到目标节点的成本。

对于最佳优先搜索,其评估函数 F(n) 将直接采用对到目标距离的估计值 H(n)。这个估计值将是我们使用的核心信息。

接下来,我们将看看贪心搜索,以及有史以来最酷的算法之一——A*搜索。

启发信息:直线距离

我们将使用什么作为我们的启发信息呢?我们会使用一个距离表。这个表会给我们精确的距离吗?答案是否定的,因为如果我们需要精确距离,就必须通过搜索算法来计算。相反,这个表提供给我们的是一个启发式距离。

这是一个近似值,表示我们可能需要行进多远。在这里,我们将使用一种称为直线距离的近似方法。我们只需计算两点之间的直线距离,忽略中间的任何路径。例如,从Arad到Bucharest的直线距离是366公里。

关键点在于,这个距离低估了沿着道路实际到达目标所需的真实距离。这种计算距离的方式在英语中被称为“直线距离”,有一个有趣的习语叫“as the crow flies”(乌鸦飞行的路线),意思是如果我不需要走街道去大学,我可以直接飞过去。也许对于这门课,应该叫“as the drone flies”(无人机飞行的路线)。如果我能直接飞过去,而不是走街道,那就是直线距离。所以,如果你直接朝那个方向前往Bucharest,那就是直线距离。这就是你在图表中看到的。

这将是对沿着路径行进真实成本的一个低估。这是一个合理的猜测,可以作为真实路径成本的下界。直线距离被称为启发式估计

启发式的含义与起源

“启发式”一词来源于希腊语“Eureka”,意思是经验法则、简化或是有根据的猜测。

它之所以有用,是因为这种简化将减少可能解决方案的搜索空间。你可能知道这个故事:漫画中展示了阿基米德在浴缸里。故事是这样的,克里特国王交给他一个任务,测量国王王冠的体积。国王想知道:“我的王冠里有多少黄金?”

要解决这个问题,你并不想真的熔化王冠来测量其中黄金的体积,因为那样会毁掉王冠。王冠形状复杂,很难从几何上精确估算黄金的体积。故事说,阿基米德非常深入地思考这个问题,以至于让浴缸的水满到边缘。当他进入浴缸时,看到水溢出来,意识到:“我身体的体积排开了等体积的水。”他们可以使用的经验法则(启发式方法)就是将国王的王冠放入水中,测量排水量,这就能告诉他们黄金的体积。当他跳进浴缸或意识到这一点时,他大喊“Eureka!”(我找到了!)然后赤身裸体地跑上街头。这就是那个故事。

总之,启发式就是一个经验法则,它是一个很好的估计,但不一定是绝对正确的。启发式算法会考虑合理的近似值,以便更快地找到解决方案。

启发函数 H(n)

一个启发函数用 H(n) 表示,它接受状态图中的任何给定状态 n,并返回一个从该状态到目标状态距离的估计值

这里的关键在于这是一个“估计值”。我们不知道到目标的真实距离,或者我们不需要预先计算到目标的真实距离。如果有人给我们启发式估计值,那么这将允许我们走捷径,而不必在搜索问题中计算所有可能的路径直到完成。


本节课中我们一起学习了启发式搜索的核心概念。我们了解到启发函数 H(n) 是对从当前节点到目标节点成本的估计,它通常设计为真实成本的下界(如直线距离)。我们探讨了启发式的含义,它源于“Eureka”,代表一种简化问题、加速求解的经验法则。最后,我们明确了启发函数的作用:通过提供有根据的猜测来引导搜索方向,避免穷举,从而更高效地找到解决方案。

32:贪婪最佳优先搜索 🧭

在本节课中,我们将要学习第一个启发式搜索算法——贪婪最佳优先搜索。我们将了解其核心思想、工作原理、实现方式,并通过实例分析其优缺点。

上一节我们介绍了搜索算法的基本概念,本节中我们来看看一种具体的启发式搜索方法。

算法核心思想

贪婪最佳优先搜索的核心思想是:在每一步扩展节点时,总是选择看起来最接近目标的节点。它使用一个启发式函数 h(n) 来估计从当前节点 n 到目标节点的剩余距离,并基于此估计值做出决策。

其节点评估函数 f(n) 的公式为:
f(n) = h(n)

这与我们之前学过的一致代价搜索不同,一致代价搜索使用 f(n) = g(n),即从起点到当前节点的实际路径成本。而贪婪最佳优先搜索完全忽略已发生的路径成本 g(n),只关注对未来距离的启发式估计 h(n)

算法实现步骤

以下是贪婪最佳优先搜索的实现流程,我们使用优先队列来管理待扩展的节点边界。

  1. 初始化:将起始状态放入优先队列(边界)中,并记录路径来源。
  2. 循环搜索:当边界不为空时,执行以下步骤:
    a. 从优先队列中弹出评估值 f(n) 最小的节点(即启发式估计最接近目标的节点)。
    b. 检查该节点是否为目标状态。如果是,则搜索成功,结束。
    c. 如果不是目标,则“扩展”该节点,即找出从该节点可以到达的所有相邻节点(后继状态)。
    d. 对于每一个未访问过的后继节点,计算其启发式估计值 h(后继),并将其以该值为优先级加入优先队列。
    e. 记录从当前节点到每个后继节点的路径,以便最终重建完整路径。

Python代码示例

以下是用Python实现贪婪最佳优先搜索的简化代码框架:

import heapq

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/upenn-aiml-ess/img/c863f2dd3334d89f477ff71a2ecb1005_1.png)

def greedy_best_first_search(start, goal, heuristic, get_neighbors):
    frontier = []  # 优先队列
    heapq.heappush(frontier, (heuristic(start, goal), start))
    came_from = {start: None}  # 记录路径
    visited = set([start])

    while frontier:
        _, current = heapq.heappop(frontier)

        if current == goal:
            break  # 找到目标

        for next_node in get_neighbors(current):
            if next_node not in visited:
                visited.add(next_node)
                # 优先级仅由启发式函数决定
                priority = heuristic(next_node, goal)
                heapq.heappush(frontier, (priority, next_node))
                came_from[next_node] = current

    # 重建路径...
    return came_from

启发式函数示例

启发式函数 h(n) 的选择取决于具体问题:

  • 在地图导航问题中h(n) 通常是当前城市到目标城市的直线距离(欧几里得距离)。
  • 在网格寻路问题中,常用曼哈顿距离,即两点在X轴和Y轴方向上的绝对距离之和。公式为:
    h(n) = |x₁ - x₂| + |y₁ - y₂|

算法性能演示

为了直观比较,我们参考了Red Blob Games(一个非常有趣的算法教程网站)的示例。

  • 在开阔场地:如下图所示,左侧是广度优先搜索(BFS),右侧是贪婪最佳优先搜索(Greedy BFS)。贪婪最佳优先搜索利用启发式信息,几乎直线冲向目标(X),速度非常快。

  • 在复杂地形中:如下图所示,当存在障碍物时,贪婪最佳优先搜索的路径(右侧亮灰色区域)可能不是最短的。它因为“目光短浅”地追求当前看来最近的目标,而错过了更优的路径(左侧未被探索的浅灰色区域)。


罗马尼亚地图问题实例

让我们用经典的“从Arad到Bucharest”寻路问题来逐步分析算法。

  1. 第一步:从Arad出发,扩展得到三个相邻城市:Sibiu, Timisoara, Zerind。查询它们到Bucharest的直线距离(启发值)分别为:253, 329, 374。优先队列排序后,选择Sibiu进行扩展。
  2. 第二步:扩展Sibiu,得到新城市:Fagaras, Oradea, Rimnicu Vilcea。它们的启发值分别为:176, 380, 193。现在边界上的所有节点按启发值排序,最小的是Fagaras(176),因此扩展Fagaras。
  3. 第三步:扩展Fagaras时,发现其相邻城市包含目标Bucharest。将其加入边界并立即找到目标。
  4. 最终路径:Arad -> Sibiu -> Fagaras -> Bucharest,总路径成本为450。

然而,存在一条更优的路径:Arad -> Sibiu -> Rimnicu Vilcea -> Pitesti -> Bucharest,总成本为418。这说明贪婪最佳优先搜索找到的路径不一定是最优的

算法特性分析

基于以上实例和演示,我们可以总结贪婪最佳优先搜索的特性:

  • 不完备性:不能保证找到解。如果启发式函数引导不当,算法可能会在环路中无限循环。例如,从Iasi出发,可能因为Neamt的启发值比Vaslui低而选择前往Neamt,但从Neamt只能返回Iasi,导致死循环。
  • 非最优性:如罗马尼亚地图实例所示,它找到的解可能不是成本最低的路径。
  • 时间复杂度:最坏情况下可能与状态空间大小成指数关系,但一个好的启发式函数可以极大提高效率。
  • 空间复杂度:与广度优先搜索类似,在最坏情况下需要存储所有边界节点。

总结

本节课中我们一起学习了贪婪最佳优先搜索算法。它是一种启发式搜索方法,其核心在于每一步都选择启发式估计值 h(n) 最小的节点进行扩展,即选择“看起来”最接近目标的节点。

我们了解了它的工作原理、Python实现方式,并通过地图导航和网格寻路的实例,直观地看到了它的优势(在开阔场地的速度)和劣势(可能不完备、非最优、在复杂地形中表现不佳)。关键在于,它只考虑了到达目标的估计成本,而完全忽略了目前已付出的路径成本

下一节,我们将学习一种能克服这些缺点的更优算法——A*搜索,它巧妙地结合了路径成本和启发式估计。

33:A*搜索算法详解 🧭

在本节课中,我们将要学习一种非常著名的搜索算法——A*算法。我们将了解它的核心思想、工作原理、关键要求,以及如何通过启发式函数来优化搜索过程。


什么是A*算法?

A*算法是最佳优先搜索算法中最著名的一种。它拥有一些非常出色的特性,能够保证其行为是最优的。

上一节我们介绍了最佳优先搜索的基本概念,本节中我们来看看A*算法的具体实现。

A*算法的核心思想是:我们希望剪枝掉那些已知代价高昂的路径,同时优先扩展最有希望的路径。到目前为止,我们只讨论了两种最佳优先搜索算法:

  • F(n) = G(n) 时,我们实现的是一致代价搜索
  • F(n) = H(n) 时,我们实现的是贪婪最佳优先搜索

而当 F(n) = G(n) + H(n) 时,我们实现的就是A*搜索。其中:

  • G(n) 是从起始节点到节点 n 的实际路径代价。
  • H(n) 是从节点 n 到目标节点的启发式估计代价

为了实现真正的A*搜索,我们需要对启发式函数 H(n) 有一个特殊的要求。


可采纳启发式函数

A*算法能够工作的关键概念在于,启发式函数 H(n) 必须是可采纳的

可采纳性的定义是:对于图中的任意节点 nH(n) 永远不会高估从该节点到达目标的真实代价。换句话说,启发式估计总是乐观的,它总是小于或等于到达目标的真实距离。

用公式可以表示为:H(n) ≤ h*(n),其中 h*(n) 是从节点 n 到目标的真实距离。当我们到达目标节点时,启发式值必须等于 0

一个可采纳启发式的例子是我们已经见过的直线距离。在道路网络中,两点间的直线距离永远不会高估它们之间的实际道路距离。

如果我们拥有一个可采纳的启发式函数,那么A*搜索就能保证找到最优解(即最短路径)。


A* vs. 贪婪最佳优先搜索

让我们通过一个动画示例来比较A*搜索和贪婪最佳优先搜索的行为。

在贪婪最佳优先搜索中,节点旁边的数字表示它们被扩展的顺序。贪婪搜索并非最优,因为它从未探索真实的最低成本路径。

而在右侧,真正的A算法找到了真实的最低成本路径。虽然它比贪婪最佳优先搜索扩展了更多的节点,但它保证总能首先找到到达目标的最短路径。因此,只要启发式函数是可采纳的,A就是最优的。

可采纳性背后的思想是,它提供了一个乐观的剩余代价估计。它会“减慢”糟糕的计划,但永远不会超过到达目标的真实成本。


A*算法工作流程示例

让我们以罗马尼亚地图为例,看看A*算法是如何工作的。

我们的起点是 Arad。我们将使用一个优先级队列作为边界。节点的优先级由 F(n) = G(n) + H(n) 决定。

Arad 出发:

  • 路径成本 G(Arad) = 0
  • 启发式估计 H(Arad) 是到 Bucharest 的直线距离。

我们将 Arad 的三个邻居添加到优先级队列中。扩展 Arad 后,每个邻居节点都会有一个复合成本 F(n)

  • 对于 SibiuG = 140(从Arad到Sibiu的实际距离),H = 253(直线距离),所以 F = 393
  • 对于 TimisoaraG = 118H = 329F = 447

现在我们的优先级队列中有不同的值,因此我们将扩展 F 值最小的节点,即 Sibiu

一个很酷的特性是,我们不必显式地将已访问节点(如 Arad)从图中删除。因为当我们尝试从 Sibiu 再次扩展回 Arad 时,这条路径的 G 成本会变得很高(140 + 140),它会被推到优先级队列的很后面,以至于我们永远不会再处理它。

我们不断弹出 F(n) 值最小的节点进行扩展。当我们首次将 Bucharest 加入边界队列时,我们不能立即返回这条路径。我们必须继续扩展队列中 F 值比它小的节点,以验证当前到达 Bucharest 的路径是否确实是成本最低的。这是A*算法保证最优性的关键步骤。

最终,当 Bucharest 成为边界队列中 F 值最小的节点时,我们就找到了到达目标的最优路径。


其他问题的启发式函数

我们也可以将其他问题(如八数码问题)表述为搜索问题。

八数码问题的分支因子不大,但平均解大约需要22步。一个好的启发式函数能显著减少搜索过程。

以下是两种可采纳的启发式函数:

  1. 错位棋子数:计算不在目标位置的棋子数量。这至少需要移动那么多步。
  2. 曼哈顿距离:计算每个棋子移动到其目标位置所需步数的总和(只计水平和垂直移动)。

这两种启发式都是可采纳的,因为它们都低估了实际所需的移动次数。


通过放松约束生成启发式

一种系统化生成可采纳启发式的方法是放松约束。我们取一个带有若干限制的问题,然后减少其中一个或多个限制,计算在这个放松后的问题中的解的成本。这个成本将成为原问题的一个可采纳启发式。

对于八数码游戏,规则是只能将棋子移动到相邻的空白格。

  • 如果我们放松“只能移到空白格”的约束,只要求“可以移到任何相邻格”,我们就得到了曼哈顿距离启发式。
  • 如果我们进一步放松,允许“将棋子移动到任何位置”(忽略相邻和空白格约束),我们就得到了错位棋子数启发式。

放松后问题的精确解的成本,是原问题所需步骤数的一个下界。


启发式的优劣:支配性

既然两种启发式都是可采纳的,我们如何知道哪个更好呢?它们都能帮助A*以最优方式运行,但需要扩展的节点数量不同。

我们可以使用支配性这个概念来衡量一个启发式是否优于另一个。

启发式 H2 支配 启发式 H1,如果对于搜索图中的每一个节点 n,都有 H2(n) ≥ H1(n),并且两者都是可采纳的。我们希望启发式估计尽可能接近真实值。如果 H2 是乐观的,并且它返回的估计值总是大于或等于 H1,那么它对剩余成本的估计就更准确。

在八数码问题中:

  • 使用错位棋子数启发式,平均需要扩展约227个节点。
  • 使用曼哈顿距离启发式,平均仅需扩展约73个节点。

启发式估计越好,需要扩展的节点就越少,找到解决方案的速度也就越快。


最佳与最差的可采纳启发式

  • 最佳的可采纳启发式就是真实代价 h*(n)。如果我们知道真实距离,就可以直奔目标,这基本上就是知道了精确剩余距离的贪婪最佳优先搜索。
  • 最差的可采纳启发式恒为0的启发式,即 H(n) = 0。这很糟糕,因为它会使A*退化为一致代价搜索

显然,真实代价启发式支配所有其他启发式,而恒为零的启发式被所有其他启发式支配。


本节课中我们一起学习了A搜索算法。我们了解了它的核心公式 F(n) = G(n) + H(n),以及保证其最优性的关键——可采纳的启发式函数。我们还学习了如何通过放松约束来生成启发式,以及如何使用支配性概念来比较不同启发式的优劣。A算法因其在保证找到最优解的同时,能有效利用启发式信息来指导搜索方向,而成为人工智能和路径规划等领域中最重要、最常用的算法之一。

34:A*搜索算法-II

在本节课中,我们将深入学习A搜索算法的核心原理,特别是其保证找到最优解的关键——可采纳性。我们将探讨启发式函数的设计要求,并通过一个证明草图来理解A算法的最优性保证。

上一节我们介绍了A*搜索是一种最佳优先搜索,它结合了路径成本和启发式估计。本节中我们来看看如何确保这种算法能找到最优解。

可采纳性:乐观的启发式

A*算法能够保证找到最优解的关键在于其使用的启发式函数必须是可采纳的。可采纳性意味着启发式函数对剩余成本的估计必须是乐观的,即它永远不会高估从当前节点到目标节点的真实成本。

以下是可采纳启发式的核心思想:

  • 乐观估计:启发式函数 H(n) 给出的估计值,必须小于或等于从节点 n 到目标节点的真实剩余成本。
  • 避免高估:如果启发式函数高估了剩余成本(即过于悲观),它可能会让实际上的最优路径在优先级队列中排名靠后,从而被非最优路径抢先探索。
  • 形式化定义:一个启发式函数 H 是可采纳的,当且仅当对于搜索树中的任意节点 n,都有 0 <= H(n) <= 从 n 到目标的真实成本

在之前的八数码拼图例子中,曼哈顿距离就是一个可采纳的启发式函数。我们也可以通过放松问题约束(例如,允许方块直接“穿墙”)来构造可采纳的启发式。

实现A*算法最困难的部分通常就是设计一个合适的、可采纳的启发式函数。

启发式的优劣:支配性

并非所有可采纳启发式都是同等有效的。我们引入了支配性的概念来比较它们。

以下是关于启发式支配性的要点:

  • 如果一个可采纳启发式 H1 对于所有节点 n 的估计值都大于或等于另一个可采纳启发式 H2 的估计值(即 H1(n) >= H2(n)),那么 H1 支配 H2
  • 被支配的启发式(H2)提供的信息量更少。虽然两者都保持乐观(不超估),但支配性启发式(H1)的估计值更接近真实成本,因此通常能引导搜索更高效地朝向目标。
  • 在设计启发式时,我们的目标是在保持可采纳性的前提下,让估计值尽可能大(即尽可能接近真实成本)。

A* 最优性证明草图

现在,让我们通过一个证明草图来理解为什么使用可采纳启发式的A*搜索能够保证找到最优解(即路径成本最低的解)。

我们将使用搜索树的表示法。假设我们有两个目标节点:

  • 节点 A:最优目标节点,具有最低的路径成本 G(A)
  • 节点 B:次优目标节点,路径成本 G(B) > G(A)

我们需要证明,在A*搜索中,A(或它的某个祖先节点)一定会比 B 更早被从边界(优先级队列)中取出并扩展

以下是证明的逻辑步骤:

  1. 祖先节点的 F 成本:设 n 是通往目标 A 路径上的任意一个祖先节点(包括 A 本身)。根据定义,其评估函数 F(n) = G(n) + H(n)
  2. F(n) 与 G(A) 的关系:由于 n 在通往 A 的路径上,所以从起点到 n 的真实成本 G(n) 必然小于等于到 A 的总成本 G(A)。同时,根据可采纳性,H(n) 小于等于从 n 到 A 的真实剩余成本。因此,F(n) <= G(A)。当 n 就是 A 时,因为 H(A) 在目标处必须为0(否则会高估),所以 F(A) = G(A)
  3. F(A) 与 F(B) 的关系:由于 A 是最优目标,G(A) < G(B)。同样,在目标节点处 H(A) = H(B) = 0。因此,F(A) = G(A) < G(B) = F(B)
  4. 排序逻辑:结合第2和第3步,对于 A 的任意祖先节点 n,有 F(n) <= F(A) < F(B)
  5. 结论:A*的边界队列总是优先扩展 F 值最小的节点。因为所有 A 的祖先节点的 F 值都严格小于 F(B),所以它们都一定会比节点 B 更早被扩展。因此,算法必然会先发现最优目标 A,然后才发现次优目标 B。这满足了最优性的定义。

本节课中我们一起学习了A搜索算法保证最优性的核心——可采纳启发式。我们理解了可采纳性要求启发式函数必须乐观估计(永不超估),并了解了如何通过支配性来比较不同启发式的效率。最后,我们通过一个证明草图,清晰地看到了A算法为何能确保优先找到成本最低的解路径。掌握这些概念是有效应用和实现A*搜索的基础。

35:A*搜索的特性 🧭

在本节课中,我们将深入探讨A搜索算法的特性、行为及其在实际中的应用。我们将了解它与其他搜索算法的区别,并通过一个视频游戏路径查找的实例,学习如何用简单的Python代码实现广度优先搜索,这是理解A搜索的重要基础。

A*搜索与均匀代价搜索的对比

上一节我们介绍了A*搜索的基本概念,本节中我们来看看它与均匀代价搜索在节点扩展顺序上的不同。

  • 均匀代价搜索可以被视为A*搜索的一个特例,其启发式函数 h(n) 始终等于 0
  • 均匀代价搜索只关注从起点到当前节点的实际路径成本 g(n)
  • 这有时会导致算法探索错误方向上的路径。在我们之前“星系导航”的例子中,目标是从Kesel前往Al Zand,但算法可能会先向相反方向(如Chiband)探索多个节点,之后才找到目标。

我们可以通过“等高线”来可视化节点的扩展过程。

  • 对于均匀代价搜索,等高线基于路径成本 g(n) 划分。例如,所有成本小于等于50的节点构成一个轮廓,小于等于100的构成下一个轮廓,以此类推。
  • 等高线从起点开始均匀地向所有方向扩展。

A*搜索的启发式引导

A*搜索在 g(n) 的基础上加入了启发式成本 h(n),这改变了其扩展行为。

  • A*搜索的扩展方向会受到目标的“吸引”,其等高线会向目标方向拉伸。
  • 但为了保证找到最优解,A*搜索不会盲目地直奔目标。它会“谨慎权衡” g(n)(已付出的成本)和 h(n)(预计剩余成本),因此仍会探索一些看似不必要的路径。

以下是两种极端情况的对比:

  • 均匀代价搜索:评估函数为 f(n) = g(n),仅按已发生的路径成本排序。
  • 贪婪最佳优先搜索:评估函数为 f(n) = h(n),完全忽略路径成本,只扩展看起来离目标最近的节点。
  • A*搜索:采取折中策略,评估函数为 f(n) = g(n) + h(n),同时考虑过去和未来的成本,因此比贪婪搜索更保守和可靠。

A*搜索的实际应用

A*搜索因其高效和最优性,被广泛应用于各种需要路径查找的场景。

  • 地图与导航:智能手机上的地图应用在为你规划行车路线时,底层很可能使用了A*搜索算法。
  • 机器人运动规划:用于机器人的导航和避障。
  • 资源与工序规划:可用于优化供应链或操作序列的调度问题。
  • 视频游戏:这是A*搜索一个非常酷的应用领域,用于控制游戏角色(包括AI角色)寻找从起点到目的地的最佳路径。

实例:视频游戏中的路径查找

接下来,我们通过一个视频游戏路径查找的实例,来具体理解如何实现搜索算法。我们将首先实现广度优先搜索(BFS)。

在视频游戏中,可以将地图建模为图(Graph)。

  • 节点:代表地图上的关键位置或路径点。
  • :代表节点之间可通行的路径,被墙壁等障碍物阻挡的区域则没有边相连。
  • 地图可以表示为精细的网格,也可以表示为房间与路径点组成的抽象网络。

以下是实现广度优先搜索(BFS)的核心步骤,该算法会均匀地向外探索所有方向。

我们可以用大约10行Python代码实现基础的BFS。以下是来自Red Blob Games教程的示例代码框架:

# 示例:广度优先搜索(BFS)框架
frontier = Queue()  # 创建一个先进先出(FIFO)队列作为边界
frontier.put(start_node)
visited = set()     # 记录已访问节点,防止重复探索
visited.add(start_node)

![](https://github.com/OpenDocCN/dsai-notes-zh/raw/master/docs/upenn-aiml-ess/img/08de709a4f10d7d64667ec45b5998c56_13.png)

while not frontier.empty():
    current = frontier.get()
    for next_node in neighbors(current):  # 获取当前节点的所有后继节点
        if next_node not in visited:
            frontier.put(next_node)
            visited.add(next_node)

这段代码的核心逻辑是:

  1. 创建一个先进先出队列 frontier 来存储待探索的边界节点。
  2. 创建一个集合 visited 来记录所有已访问过的节点,这是保证效率、避免无限循环的关键。
  3. 只要边界队列不为空,就取出第一个节点进行“扩展”。
  4. “扩展”意味着获取该节点的所有相邻节点(后继节点)。
  5. 对于每个未访问过的后继节点,将其加入边界队列并标记为已访问。

然而,基础的BFS只完成了探索。为了找到一条具体的路径,我们还需要记录路径信息。

记录与重建路径

我们需要在搜索过程中记录每个节点的“父节点”(即从哪个节点来到当前节点),以便在找到目标后能回溯出完整路径。

以下是实现路径记录和回溯的一种方法:

  • 创建一个 came_from 字典(或类似数据结构),在将新节点加入边界时,记录它是由哪个节点扩展而来的。
  • came_from 数据结构可以同时起到 visited 集合的作用——如果一个节点在 came_from 中已有记录,则说明它已被访问过。

当到达目标节点(如图中的紫色X)时,通过 came_from 字典不断向前追溯,直到回到起点,就能得到一条从起点到目标的路径(注意顺序是反的,需要反转)。

# 路径回溯示例
current = goal_node
path = []
while current != start_node:
    path.append(current)
    current = came_from[current]
path.append(start_node)
path.reverse()  # 反转列表,得到从起点到目标的路径

另一种实现方式是显式地在队列中存储“路径-节点”对。

  • 利用Python队列可以存储任意对象的特性,将 (当前路径列表, 当前节点) 作为一个整体放入队列。
  • 这样,当弹出队列项时,就直接获得了从起点到该节点的完整路径。


总结

本节课中我们一起学习了A搜索算法的关键特性。我们了解到A搜索通过结合实际成本 g(n) 和启发式估计 h(n),在保证找到最优解的同时,能更有效地引导搜索方向。我们还将A与均匀代价搜索、贪婪最佳优先搜索进行了对比。最后,通过视频游戏路径查找的实例,我们学习了广度优先搜索的实现原理,包括如何探索地图、记录访问状态以及重建最终路径,这些是理解更复杂搜索算法(如A)的重要基础。

01:统计学在数据科学中的介绍

在本节课中,我们将要学习统计学和概率论在人工智能与机器学习中的核心作用。这些数学基础是理解AI模型如何工作、如何设计新算法的关键。

课程概述

我很荣幸地向大家介绍来自宾夕法尼亚大学工程与应用科学学院的杰出同事,Hamhmed Hassani。Hmed将为大家讲授机器学习和人工智能的数学基础。

课程内容概览

Hmed,能否请你为我们概述一下,在你的课程中将涵盖哪些主题?

当然,谢谢Chris。当前的课程将首先涵盖机器学习与人工智能所需的核心概率论工具和概念。随后,我们将学习另一个关于“估计”的主题。这里的“估计”指的是,利用从总体或社会中抽取的数据点或样本来估算各种数据量、总体或社会特征的任务。

核心概念的应用实例

让我们思考一个具体例子。假设我们想构建一个能够预测患者是否患有癌症的机器学习系统。你能告诉我们,你课程中的数学基础如何帮助完成这类机器学习任务吗?

好的。如果一个AI模型要利用患者的信息(例如患者的fMRI扫描)来预测癌症,那么该AI模型必须利用该fMRI扫描来估计患癌的可能性或概率。一旦完成了这个估计(这是AI模型的主要任务),预测就会基于这个概率估计得出。因此,这里有两个关键词:估计概率,它们将是本专项课程中要涵盖的内容。

课程作业形式

我们专项课程中的大多数课程都侧重于使用Python进行实践作业。但在这门课程中,我们不会使用Python。你能介绍一下你课程的作业形式吗?

本专项课程的作业旨在加深学习者对课程中所教授的主要工具、算法和概念的理解。

为什么程序员需要关注统计学?

考虑到我们的课程主要面向Python编程,为什么程序员应该关心统计学呢?

统计学和概率论是AI模型和AI算法的主要数学基础。深刻理解这些基础概念,将极大地帮助你理解算法在做什么、它们是如何设计的。如果你想设计新的方法、新的模型和新的算法,这类统计概念无疑是至关重要的。

总结

本节课中,我们一起学习了统计学与概率论作为AI和机器学习基石的重要性。我们了解到,估计概率是构建预测模型(如癌症诊断系统)的核心。尽管本课程不涉及Python编程,但其数学原理是理解所有AI算法运作机制的关键。希望这能激励你深入学习这门课程,并享受从Hammed教授那里学习的乐趣。

02:数据科学入门 🚀

在本节课中,我们将要学习数据科学的基本定义及其核心组成部分。我们将从一个宏观的视角开始,然后通过一个直观的任务来初步体验数据科学的工作流程。

概述

让我们从本课程的第一个模块开始。本课程的核心内容是探讨如何运用统计学的基本概念来发展数据科学。

因此,一个自然的起点是为数据科学提供一个宽泛的定义,并介绍其主要构成部分。这就是我们接下来要做的事情。

数据科学的定义与构成

上一节我们介绍了本模块的起点,本节中我们来看看数据科学的具体定义和它的主要组成部分。

数据科学是一个跨学科领域,它结合了统计学、计算机科学和领域专业知识,旨在从数据中提取知识和洞见。其核心构建模块包括数据收集、数据处理、分析与建模,以及结果解释与部署。

你的第一个数据科学任务

在了解了数据科学的基本框架后,你将开始实践你的第一个数据科学任务。

正如你将看到的,这个任务有一个非常直观的解决方案,你可能之前已经做过很多次类似的事情。然而,在本课程中,我们希望深入挖掘,理解如何为我们提出的解决方案、估计和预测提供精确且可解释的统计保证。

以下是该任务的核心步骤简介:

  1. 问题定义:明确你要从数据中回答的问题。
  2. 数据收集与探索:获取相关数据并进行初步查看,了解其结构和特征。
  3. 数据预处理:清洗数据,处理缺失值或异常值,为分析做准备。
  4. 分析与建模:应用统计方法或机器学习模型来分析数据。
  5. 结果评估与解释:评估模型性能,并解释结果的实际意义。

从直观方法到统计保证

虽然许多数据科学任务始于直观的解决方法,但专业的实践要求我们超越直觉。关键在于为我们的结论提供坚实的统计基础,例如使用置信区间假设检验

例如,一个简单的平均值计算是直观的:
mean_value = sum(data) / len(data)

但为了评估这个估计的可靠性,我们可能需要计算其95%的置信区间,这为我们的估计提供了统计上的保证。

总结

本节课中我们一起学习了数据科学的入门知识。我们从其宽泛的定义和核心构成模块开始,并通过一个直观的任务引出了数据科学的工作流程。最重要的是,我们强调了在提供解决方案和预测时,追求精确与可解释的统计保证的重要性,这是将直观实践转化为严谨科学的关键一步。

03:离散数学复习I - 变量、多项式、集合 📚

在本节中,我们将回顾离散数学中的一些非常基础的内容。我们将分为两个小节:离散数学复习I和离散数学复习II。正如你将看到的,这里我们只会涉及最基础的概念。这些内容对你来说应该非常熟悉,你可能在高中或大学已经学过。因此,我们将非常快速地过一遍,主要是为了唤醒你对之前所学知识的记忆。

变量 🧮

我们在数学中处理的第一个概念是变量。几乎在所有的数学以及本课程中,我们都会处理各种类型和形式的变量。一个正式的定义是:变量是一个通常用字母表示的符号,它代表一个可以变化的量或值。通常,你熟悉的方程中的 xyz,或者 αβγ 等,都是我们使用的所谓变量。我们通常在方程、序列、未知数中处理它们,而这些方程或未知数的基本构建块就是变量。

作为一个简单的例子,我们考虑这个方程:y = x + 5xy 是我们处理的两个变量,y 的值将是 x 的值加上数字 5

再举一个简单的例子来表示这个方程。假设有两个兄弟姐妹,哈维尔和约兰达。我们知道约兰比比哈维尔大五岁。回到我们的方程,变量 x 可以代表哈维尔的年龄,y 可以代表约兰达的年龄。我们知道约兰比比哈维尔大五岁,这意味着 y = x + 5。如果 x(即哈维尔的年龄)是 11,那么 y 就是 11 + 5,即 y = 16

系数、下标与指数 🔢

上一节我们介绍了变量的基本概念。本节中,我们来看看变量在方程中通常如何出现。变量要么带有一些系数(即一个标量数字乘以变量),要么被提升到某个幂次(例如,x4 次方写作 x⁴x⁵ 等)。

首先介绍系数的含义。正如我所说,在我们的方程中,变量通常乘以一个标量值,这个数字被称为变量后面的系数。默认系数是 1(我们通常不写出 1),但它可以是任何其他数字,如 25.2-1-2 等。例如,3.5 * a 意味着 a 的值将乘以 3.5

另一个重要的事情是,我们经常在序列中使用变量。我们有一个相同类型的变量序列,并使用下标来表示序列中的这些变量元素。例如,我们处理序列 S₁S₂S₃S₄... 可以继续下去。这里的每个 S 都是一个变量,但这些变量因为被放在一个序列中而具有某种共性。下标 i 表示变量在序列中的索引。这强调了我们将使用下标(有时是上标)来表示变量属于同一类型,但由于下标或上标的不同,它们之间可能存在其他差异。例如,我们有时使用 x₁x₂,有时使用向量表示法。一个向量 x(用向量符号表示)对应一个数字向量 [x₁, x₂, ..., x₁₀],这是一个 10 维向量。这个向量的第一个坐标是 x₁,第二个坐标是 x₂,最后一个坐标是 x₁₀。我们到处使用 x 来表示向量及其坐标,因为它们共享某些概念,而 xᵢ 表示向量 x 的第 i 个坐标。

现在,正如我所说,我们也会在方程中使用变量的幂次。指数表示变量的重复乘法,通常用一个上标数字来表示。例如,x⁴ 表示 x 自乘四次。我们有时也会使用变量的。平方根,表示为 √xx 应为正数),是一个数 y,使得 y² = x。通常,y±y 在平方后都等于 x。我们也可以考虑其他次数的根。例如,125 的立方根有时表示为 125^(1/3),结果是 5。一般来说,我们可以处理 x^α,其中 α 是一个实数。它可以是 1/31/21/50.2-0.3 等等。这表明幂次不仅限于整数,只要 x 来自正确的定义域,你可以看 x 的任何幂次。

多项式 ➕✖️

上一节我们讨论了指数和根。现在让我们把这些概念放在一起,谈谈多项式。通常,我们处理的方程涉及变量的多个幂次以及它们后面的系数。每个“幂次乘以系数”的组合被称为一个。而一系列相加的项的组合被称为一个多项式

以下是一个多项式的例子:
P(x) = 3x⁴ - 2x² + x - 10

每一项如下:

  • 第一项是 -10(可以看作是 -10 * x⁰,因为任何数的 0 次方都是 1)。
  • 第二项是 x(系数为 1,幂次为 1)。
  • 第三项是 -2x²(系数为 -2,幂次为 2)。
  • 第四项是 3x⁴(系数为 3,幂次为 4)。

多项式中最大的幂次通常被称为该多项式的次数。因此,这个多项式的次数是 4。通常,我们按照项的幂次降序排列来表示多项式。在这个例子中,第一项具有最大的幂次 4,然后是 2,接着是 1,最后是常数项 -10

集合 📦

另一个我们将要使用的概念是集合。集合是称为元素的不同对象的集合。在下面的例子中,集合 A 由六个元素组成,这些元素可以是各种类型。

A = {x, 0.01, -10, 4.5, "hello", π}

例如,集合 A 中的一个元素是实数 0.01,另一个元素是变量 x,还有一个元素是数字 -10。这里我们使用的是非常一般的集合概念,一个集合可以是任何事物的集合。

集合通常用大写字母表示,它们的元素通常显示在大括号 {} 内。这是另一个集合 B 的例子,它只是三个实数的集合:B = {1, 2, 3}。集合 B 中的对象具有相同的类型,而集合 A 中的对象具有不同的类型。

集合中元素的顺序并不重要,重要的是集合本身这个整体。集合不包含元素的重复,如果一个元素在集合中,它只出现一次,重要的是对象本身,而不是对象的重复。

空集(不包含任何元素的集合)通常用符号 {} 表示。

一些快速符号:

  • 符号表示属于。例如,x ∈ A 表示元素 x 属于集合 A。或者,0.01 ∈ A
  • 符号表示不属于

数字类型 🔢

正如我所说,我们正在快速回顾对本课程有用的不同概念,这些都是非常基础的概念,我相信你们都见过,只是一个快速的回顾。

我们通常处理三种类型的数字:整数自然数有理数,然后我们还有实数,它类似于有理数但比有理数更一般,目前这种区别对本课程来说并不重要。

  • 整数 是没有小数点的数字,如 -30-10235 等。所有离散的数字,包括正数和负数。整数的集合用 表示。
    ℤ = {..., -3, -2, -1, 0, 1, 2, 3, ...}

  • 自然数 是严格为正的整数,如 123... 一直到正无穷。它不包括 0。自然数的集合通常用 表示。
    ℕ = {1, 2, 3, ...}

  • 有理数 是所有可以表示为两个整数之比的数字的集合,通常用 表示。
    ℚ = { m/n | m, n ∈ ℤ, n ≠ 0 }
    例如,2/3 是一个有理数,它不是整数,属于

  • 实数 是所有你能想象到的数字的集合,有理数是实数的一个严格子集。实数线上所有的点都代表一个实数。有些点是整数,有些是自然数(正的那些),有些是有理数(线上非常密集),还有一些不是有理数但却是实数(如 π√2)。实数的集合用 表示。

集合构造器符号 🛠️

最后,一个在本课程中对我们有用的符号是集合构造器符号。这是一种以更紧凑的形式书写集合的方式。

让我举个例子来说明这个符号。假设我们想以一种紧凑的形式写出所有介于 -50200 之间的整数集合。

一种方法是写出:S = {-50, -49, -48, ..., 0, 1, 2, ..., 200}

更紧凑的表示法是使用集合构造器:
S = { x ∈ ℤ | -50 ≤ x ≤ 200 }
这表示:集合 S 是所有 x 的集合,其中 x 的类型是整数,并且 x-50200 之间(包括两端)。

另一个例子是我在上一张幻灯片中使用的有理数集合:
ℚ = { m/n | m, n ∈ ℤ, n ≠ 0 }

我相信你以前见过这样的例子,这是一种非常紧凑地表示集合的方式。

让我再次强调,我们有实数集 ,它是所有实数的集合。如果你看实数线,线上的任何点都代表一个实数。其中一些点是整数,一些是自然数(正的那些),一些是有理数,然后还有一些数字不是有理数但却是实数。实数集包含了所有你能想象到的数字。

总结 📝

在本节课中,我们一起回顾了离散数学的几个核心基础概念:

  1. 变量:代表可变数值的符号,是构建数学表达式的基础。
  2. 系数、下标与指数:系数是变量前的乘数;下标用于标识序列中的变量;指数表示变量的重复乘法。
  3. 多项式:由变量幂次项及其系数相加构成的表达式,其最高幂次称为多项式的次数。
  4. 集合:不同元素的无序集合,包含空集、属于关系等基本概念。
  5. 数字类型:包括整数 、自然数 、有理数 和实数
  6. 集合构造器:一种用条件描述来精确定义集合的紧凑表示法。

这些概念是后续学习人工智能和机器学习中更复杂数学工具的基石。下一节,我们将继续复习离散数学的其他重要内容。

04:离散数学复习II-函数 📚

在本节课中,我们将要学习离散数学中的核心概念之一:函数。函数描述了输入集合(定义域)与输出集合(值域)之间的关系,是理解算法、数据映射和机器学习模型的基础。

上一节我们介绍了变量和集合的概念,本节中我们来看看函数。

函数的定义与表示

一个函数描述了一个关系,它将一个称为定义域的输入集合中的元素,映射到一个称为值域的输出集合中的元素。

例如,一个函数可以接受一个来自实数集的输入 x,并将其加上数字5。这个函数可以表示为 f(x) = x + 5

我们通常用 f(x) 来表示函数,读作“f of x”。这里的 f 代表函数的功能,它作用于来自某个定义域的输入变量 x

回到之前的例子,我们的 f(x) 就是 x + 5

当然,我们也可以用其他字母来表示函数,例如 g(x)h(x)。你可以将其视为任何函数。例如,α(x) 就是一个由 α 表示并作用于输入 x 的函数。

以下是另一个例子:

  • g(x) = x² - 1:输入值 x 被平方,然后减去1,结果即为函数的输出。

多变量函数

函数也可以依赖于多个变量。

例如,可以定义 f(x, y) = 7x + 3y。变量 xy 可以来自实数域,7x + 3y 就是输出。

以下是另一个更复杂的例子:

  • g(x, y, z) = x⁵ - y / z²:这是定义这三个输入之间关系的另一种方式。

分段函数

函数不一定需要一个简短、明确的公式来描述其输入。函数可以是分段函数

分段函数根据输入值的不同,具有不同的功能规则。

例如,定义以下函数 f(x)

  • 如果 x 是负数,则输出为 1
  • 如果 x 是非负数(即零或正数),则 f(x) = 2x

如果我们想将 f 作为 x 的函数用图形表示,其图像如下:

  • x 为负数时,f 的值恒为 1,图像是一条水平线。
  • x 为非负数时,f(x) = 2x,图像是一条斜率为 2 的直线。

在图像上,我们通常用一个空心圆点来表示该点不包含在函数值中(例如,在 x=0 处,根据规则应取 2x 的值,即 0,而不是 1)。

这意味着:

  • 如果 x = -2,则 f(-2) = 1
  • 如果 x = 5,则 f(5) = 2 * 5 = 10

本节课中我们一起学习了函数的基本概念。我们了解到函数是定义域到值域的映射关系,可以用公式如 f(x) = x + 5 表示。函数可以是单变量的,也可以是多变量的,如 f(x, y) = 7x + 3y。此外,函数还可以是分段的,即根据输入的不同区间采用不同的计算规则。理解函数是学习更复杂数学和机器学习模型的关键一步。

05:数据科学简明解读 📊

在本节中,我们将从一个非常广阔的视角来理解数据科学是什么。换句话说,我们将尝试用简单的语言来定义数据科学。

在给出数据科学的广义定义之前,让我们先尝试构思一个非常简单的数据科学任务。这本质上可能是你需要解决的第一个数据科学任务。

这个任务非常简单,我们将主要考虑两个任务。但如果你仔细思考,会发现这两个任务在本质上是相同的。

第一个任务是估算美国费城所有女性的平均身高。假设费城的人口分布在地图各处。我们用整数 1, 2, 3 ... 直到 N 来索引每个人,其中 N 是费城女性的总人数。每个人都有一个身高,例如第 i 个人的身高是 H_i。我们想要理解、估算或计算的是女性的平均身高,即 (H_1 + H_2 + ... + H_N) / N。这里重要的是,费城的人口大约有数百万,这意味着 N 可能是一个非常大的数字,数量级在百万级别。

我们要考虑的第二个任务是估算费城中投票给某位特定候选人的选民比例。这本质上是同一类问题。同样,费城所有成年人(例如 18 岁以上)每人被分配一个数字,我们再次称之为 H_i,但这里的 H_i 代表不同的含义:它是一个二进制值。如果为 0,表示投票给候选人 A;如果为 1,表示投票给候选人 B。我们想要估算或计算的同样是 H_i 的平均值,这代表了投票给该候选人的选民百分比。

我们试图估算的这个量,其挑战在于人口数量(或数据点数量)非常庞大,通常达到数百万级别。而在我们的数据科学应用中,总体中的个体数量或数据点数量可能极其庞大,例如数亿或数十亿。这就是挑战所在。同时,考虑到 N 很大,我们通常预算有限。换句话说,我们希望用有限的预算快速、准确地获得估算结果。例如,在这个具体例子中,有限的预算意味着你可能需要在几天内估算出平均身高或投票给某候选人的百分比,并且你只有一个小团队(比如 10 人)来为你工作。

现在,让我们思考一下如何估算这个平均身高。第一个想到的方法是挨家挨户敲门。这意味着前往费城的每一个地址,敲门询问每个人的身高,收集所有数据,然后计算平均值。

这个方法的问题在于,城市有数百万人口,因此成本极高且非常耗时。如果你敲每扇门需要 10 分钟,那么为每个人投入 10 分钟将累积成巨大的总时间,你无法在几天内完成这个任务,并且还需要大量其他资源。因此,这本质上不是一个非常实用的想法。作为数据科学家,我们不喜欢这种方法。

让我们思考另一个更聪明的想法。记住,我们只是想得到一个合理的、良好的平均身高估算值。我们可以想到的第二个方法是随机抽样。随机抽样意味着我们不去调查费城的所有人,而是只随机选择一小部分人,然后计算这个小随机子集的平均值。这是一个非常直观的想法。

同样,如果费城有大约数百万人口,我们不去调查总体中的所有个体,而是随机抽取一个小子集。总人数 N 的数量级是百万,但我们随机选择一个小样本,例如数量级为数千。每个被选中的 H'_i 都是城市中完全随机选择的人。你只需随机选择一个地址,询问该地址中人的身高,这就成为你获得的一个数据点。根据这个随机样本,你的最终估算值将是 (H'_1 + H'_2 + ... + H'_n) / n。如果随机样本的数量 n 相对较小,那么这就是估算原始平均值的一种非常高效的方法。

正如我们稍后将看到的,通过随机抽样得到的这个数字,通常是原始身高平均值的一个非常好的估计。这对你们大多数人来说可能凭直觉就很清楚。在本课程的第一个模块中,我们将学习支撑这种估算的数学原理,并利用概率论中的技术来理解这个估计值相对于真实总体平均值的好坏程度。

恭喜你,你本质上已经解决了你的第一个数据科学任务。你学到的基本技术——随机抽样——非常直观。

在本节课中,我们一起学习了数据科学的一个基本视角,并通过一个估算城市人口平均属性的具体例子,引入了随机抽样这一核心方法。我们了解到,面对海量数据(N 很大)和有限资源时,通过随机选取一个较小的子集(n 较小)进行计算,可以高效且相对准确地估算总体参数。这为后续深入学习数据科学的数学基础和技术应用打开了大门。

06:定义数据科学 📊

在本节课中,我们将学习数据科学的核心定义。我们将从一个简单的任务出发,逐步理解数据科学如何通过收集和分析数据,来研究现实世界的现象,并最终获得有价值的见解。


在上一节中,我们解决了第一个数据科学任务(计算平均身高)。现在,我们将尝试提出一个简单而广泛的数据科学定义。

通常,在数据科学中,我们的目标是研究某个现实世界的现象。这个现象可以是任何你想研究的物理或现实世界中的事物。

为了研究这个现象,第一步是从该现象中收集数据。在我们的例子中,计算平均身高这个非常基础和简单的任务里,收集数据就是随机抽取人群样本。

一旦你收集了关于这个现象的数据,下一步就是分析这些数据。你收集数据,然后分析它,以理解现实世界现象的某些方面。在计算平均身高的案例中,分析部分非常简单,就是计算随机样本子集的平均值。

你分析数据,最终获得关于你想要评估的底层现实世界现象的某种知识、见解或模式。这些本质上就是你在以通用和广泛的方式思考数据科学时,所能想到的所有基本组成部分。

当然,到目前为止,我们只讨论了非常非常简单的数据科学任务。还有许多更有趣、更重要的任务可以通过数据科学技术来解决。我们从简单的开始,比如估计平均身高或估计支持某位候选人的选民比例。第二个任务实际上是在选举期间,统计学家和公司通常会做的事情。这是一个真实且重要的任务。

但还有许多其他任务。例如,在医疗诊断领域,一个非常重要的问题是估计一个人在接下来五年内患上乳腺癌的可能性。这里,概率是你想要估计的参数。为了做到这一点,你必须收集数据,比如从之前被诊断出癌症和未被诊断出癌症的人那里收集数据。利用这些数据,你本质上想要理解模式或提出预测因子,来估计他们在未来五年内患癌的可能性。同样的问题也存在于其他疾病中,例如,你可以考虑阿尔茨海默病,估计未来20年内患病的可能性。这是一个非常重要的问题,数据科学一直在试图帮助解决。

同样,你可以想到医疗诊断领域内的许多其他场景。

如今,数据科学几乎可以应用于你能想到的任何领域。数据科学最重要的领域之一是在线营销。例如,再次是估计用户点击特定广告的可能性。亚马逊在商品推荐等方面对此投入了大量资金。或者,当你打开Facebook页面时,在右侧看到的广告。这些广告是根据你的个人资料高度定制的。在这些广告背后,运行着一个复杂的算法,它以你的个人资料作为输入,试图找出可能对你有益、且能最大化你点击概率的高度优化的广告。这里发生了许多有趣的事情,这同样是数据科学的另一个实例。人们还可以想到许多其他类型的任务。

综上所述,这里给出一个非常广泛的数据科学定义:数据科学涉及数据的获取、存储和分析方法,以有效地提取有用的知识、信息、见解和模式。


本节课中,我们一起学习了数据科学的基本流程和广泛定义。我们了解到,数据科学始于对现实世界现象的研究,通过收集数据分析数据,最终获得关于该现象的知识或见解。我们还探讨了从简单的平均身高计算到复杂的医疗诊断和在线广告推荐等多个实际应用场景,认识到数据科学方法的普适性和强大能力。其核心目标是 有效提取有用的知识、信息、见解和模式

07:随机抽样 I

在本节中,我们将以更正式和数学化的方式,来理解我们之前为那个简单的数据科学任务(即估计平均身高)所提供的解决方案。这里将要学习的概念具有普遍性,虽然我们的例子是估计平均身高,但正如我们将看到的,这些概念适用于更广泛的数据科学或估计任务。

概述

我们将从一个具体问题出发:如何估计费城成年女性的平均身高。这是一个现实世界中的现象,涉及一个非常庞大的人群。我们将学习如何通过随机抽样来高效地收集数据,并利用这些数据来估计我们关心的总体参数。

问题定义

我们的目标是估计费城成年女性的平均身高。这是一个现实世界中的现象,涉及一个非常庞大的人群。

我们有一个包含大量个体的总体,其身高分别为 H₁, H₂, ..., H_N。这里的 N 代表总体规模,对我们来说,N 的数量级可能是数百万。在其他应用中,N 可能更大,达到数十亿甚至数万亿。

总体规模用 N 表示。我们的任务很简单:估计平均身高这个参数 μ。

μ 是总体中所有身高的平均值。μ 是未知的,我们必须从总体中收集一部分人的数据(即一个子集),才能对其进行估计。

正如之前提到的,通常总体规模 N 非常大,挨家挨户敲门或获取总体中的所有值通常是不可行或成本极高的。

数据采集的基本思路

因此,数据采集的基本思路是进行随机抽样

随机抽样是指,我们本质上是从总体中选择一个子集,并尝试根据这个选定的子集来估计未知参数 μ。

在下一张幻灯片中,我将解释随机抽样,即当我们随机选择这个子集时。

一旦我们选择了这个子集(这是数据采集任务),我们就会收集数据。让我在这里标注为“来自随机子集的数据”。

收集到这些数据后,我们将在下一个模块中分析这些数据并进行估计。

随机抽样的具体操作

那么,随机抽样具体做什么呢?我们将从集合 {H₁, ..., H_N} 中均匀随机地选择第 i 个数据点。

这是我们一直在讨论的最简单的随机抽样方式。这就像你在费城随机选择一个地址,去敲门询问身高。

因此,X_i,即你选择的第 i 个随机地址所获得的数据点,将是从这个总体中随机选择的一个数字。

数据表示

于是,我们有了数据 X₁, X₂, ..., X_n。

这里的小写 n 是我们收集的数据点的数量。例如,我们均匀随机地选择了 100 个不同的人,询问他们的身高,这 100 个数字就是我们的数据点 X。从现在起,X_i 就是第 i 个数据点,例如,来自第 i 个随机地址的信息或身高。

数据点数量与总体规模的关系

我还想强调一个事实:通常,数据点的数量 n 远小于总体规模 N。

总体规模,即整个总体的大小,不是我们能控制的。为了提高效率,我们通常需要高效且智能地选择数据点。通常我们会有很多数据点,但我们选取的数据点数量 n 与实际总体规模 N 并不可比。

好消息是,即使数据点数量 n 远小于总体规模 N,你仍然可以对平均参数提供非常好的估计。

总结

本节课中,我们一起学习了随机抽样的基本概念。我们从估计费城女性平均身高这个具体问题出发,定义了总体、参数(μ)和数据(X_i)等核心概念。我们了解到,由于总体规模庞大,直接测量所有个体不现实,因此需要通过随机抽样来获取一个代表性的子集数据。随机抽样的核心是均匀随机地从总体中选择个体。最后,我们明确了即使样本量 n 远小于总体量 N,只要抽样是随机的,我们仍然能够基于样本对总体参数做出有效的估计。下一节,我们将探讨如何具体利用这些样本数据来进行估计。

08:随机抽样II 📊

在本节课中,我们将要学习随机抽样中数据点的概率分布,并理解如何利用样本均值来估计总体参数。我们将分析样本均值的统计特性,并探讨如何评估其作为估计量的好坏。


上一节我们介绍了从总体中随机抽取数据点的概念。本节中我们来看看单个数据点 Xi 的概率分布规律。

Xi 是一个随机变量,它代表从总体中随机抽取的第 i 个人的身高。总体包含 n 个人,其身高分别为 h1, h2, ..., hn

Xi 的概率分布如下:它取值为 h1 的概率是 1/n,取值为 h2 的概率也是 1/n,以此类推。因为抽样是均匀随机的,所以每个身高值被选中的概率都相等。

用公式可以表示为:

P(Xi = hk) = 1/n, 对于 k = 1, 2, ..., n


当我们进行抽样时,我们会收集 n 个这样的数据点:X1, X2, ..., Xn。一个重要的前提是,这些数据点是相互独立地从总体中抽取的。这意味着选择其中一个数据点不会影响选择另一个数据点的概率。


现在我们已经收集了数据集 X1Xn。接下来的问题是,我们如何处理这个数据集,以获取关于真实世界现象(例如总体平均身高 μ)的有价值信息?

最简单的答案是计算数据点的平均值,即样本均值,通常记为 。样本均值 被用作对总体参数 μ 的一个估计

用公式表示为:

x̄ = (X1 + X2 + ... + Xn) / n

由于 X1Xn 本身是随机变量,它们的平均值 也是一个随机变量。这意味着 不是一个固定值,它会根据不同的抽样结果以不同的概率取不同的值。因此, 拥有自己的概率分布。

为了评估 作为 μ 的估计量是否“好”,我们需要分析 的统计特性。核心在于理解估计的误差,即 与真实值 μ 之间的差距 x̄ - μ

我们需要定义不同的度量标准来量化这个估计量的性能、误差和置信度。


在下一节中,我们将开始学习概率论中的相关概念。这些知识将帮助我们计算随机变量 的统计特征,并分析估计误差 x̄ - μ,从而判断样本均值作为估计量的有效性。


本节课中我们一起学习了:

  1. 随机变量 Xi 的概率分布:它均匀地取总体中的每一个值。
  2. 样本数据点 X1, ..., Xn 是独立抽取的。
  3. 使用样本均值 来估计总体均值 μ
  4. 认识到 本身是一个随机变量,其统计特性决定了它作为估计量的好坏。
  5. 提出了核心问题:如何分析和量化估计误差 x̄ - μ,这将是后续概率论学习的重点。

09:概率论基础 🎲

在本节课中,我们将要学习概率论的基本概念。概率论是数据科学和机器学习领域的主要语言,几乎所有概念和技术都基于此发展。因此,了解、学习和记住概率论的基本概念至关重要。

概述 📋

在数据科学和机器学习中,几乎所有的理论保证都是基于概率论发表的。概率论是数据科学概念得以发展的主要语言。因此,掌握概率论的基本概念非常重要。

本模块将致力于回顾概率论的基本概念,例如概率密度函数(PDF)、期望和方差。我们将回顾它们的主要性质,并解释这些概念在何种意义上对我们有用。

核心概念与重要性 🔑

上一节我们概述了本模块的目标,本节中我们来看看概率论的核心地位。

我想再次强调,概率论是几乎所有数据科学和机器学习概念与技术得以发展的主要语言。因此,加深对它的理解至关重要。

以下是本模块将要涵盖的几个核心概念:

  • 概率密度函数:描述连续随机变量在各点取值可能性大小的函数。其公式为:对于连续随机变量 (X),其概率密度函数 (f(x)) 满足 (P(a \leq X \leq b) = \int_{a}^{b} f(x) , dx)。
  • 期望:随机变量取值的加权平均,代表其“平均值”。其公式为:对于离散随机变量 (E[X] = \sum_{i} x_i p_i);对于连续随机变量 (E[X] = \int_{-\infty}^{\infty} x f(x) , dx)。
  • 方差:衡量随机变量取值与其期望的偏离程度。其公式为:(Var(X) = E[(X - E[X])^2])。

总结 🏁

本节课中我们一起学习了概率论在数据科学和机器学习中的基础性地位。我们明确了本模块将重点回顾概率密度函数、期望和方差等核心概念及其性质,并理解它们在实际应用中的价值。掌握这些基础知识是深入学习后续内容的关键。

10:基础概率论 I 📊

在本节课中,我们将回顾概率论中的一些基本概念。这些概念对于分析我们的估计器以及后续课程中将要遇到的其他概念都非常有帮助。

随机变量

上一节我们介绍了课程概述,本节中我们来看看随机变量。什么是随机变量?我将先给出一个非正式的定义,稍后再给出更正式的定义。

非正式或直观地说,随机变量是一个可以取多个实数值,且每个值对应不同概率的变量。变量 X 可以取不同的值,例如 x1, x2, ..., xk。每个值 xi 被取到的概率为 pi。这些概率值 pi 介于 0 和 1 之间,并且所有概率之和为 1。

以下是几个简单的例子:

  • 抛硬币:假设抛一枚公平的硬币。我们可以定义随机变量 X:当结果为正面时 X=0,概率为 0.5;当结果为反面时 X=1,概率也为 0.5。
  • 掷骰子:掷一个公平的六面骰子。随机变量 X 可以取 1 到 6 的整数值,每个值出现的概率都是 1/6。

直观上,随机变量就是一个其值被随机选择的变量。

现在,我们来看一个更正式的定义。随机变量 X 是一个从某个概率结果集合 S 到实数集的映射。例如,在抛硬币的例子中,结果集合 S = {正面, 反面}。映射 X 定义为:X(正面) = 0X(反面) = 1。这意味着 X 取值 0 的概率是 0.5,取值 1 的概率也是 0.5。

离散与连续随机变量

我们已经讨论了离散随机变量并列举了一些例子。离散随机变量是指其可能取值的集合是离散的、有限的集合,例如 {x1, x2, ..., xk},每个值对应概率 p1, p2, ..., pk

接下来,我们看看连续随机变量。连续随机变量通常通过概率密度函数 来定义。

概率密度函数给出了随机变量 X 取值的分布情况。这个函数记作 p(x),其值在 0 到 1 之间,并且在整个实数域上的积分等于 1。从 PDF 我们可以知道,X 的值落在区间 [a, b] 内的概率,就是 p(x) 在该区间上的积分。

以下是两个著名的连续随机变量例子:

  • 高斯(正态)随机变量:其概率密度函数 p(x) 由以下公式给出:
    p(x) = (1 / (sqrt(2π) * σ)) * exp(-(x - μ)² / (2σ²))
    其中 μσ 是参数。μ 表示分布的平均值(均值),σ² 表示分布的方差。高斯分布的 PDF 图形是一个关于 μ 对称的钟形曲线。

  • 指数分布:其概率密度函数 p(x) 形式如下:
    x >= 0 时,p(x) = λ * exp(-λx)
    x < 0 时,p(x) = 0
    其中 λ 是参数。指数分布的 PDF 图形从 λ 开始,随着 x 增大而呈指数衰减至 0。

总结

本节课中我们一起学习了概率论的基础知识。我们首先介绍了随机变量的直观和正式定义,并通过抛硬币和掷骰子的例子加以说明。接着,我们区分了离散随机变量和连续随机变量,并重点讲解了连续随机变量的概率密度函数概念。最后,我们以高斯分布和指数分布为例,展示了两种重要的连续概率分布及其 PDF 形式。这些概念是理解后续机器学习中统计推断和模型分析的基础。

11:基础概率论II 📊

在本节课中,我们将要学习随机变量的两个核心概念:期望方差。上一节我们介绍了随机变量的基本概念,本节中我们来看看如何量化随机变量的“中心位置”和“离散程度”。

期望(Expectation)

期望,或称均值,是随机变量所有可能取值的加权平均。权重就是每个值对应的概率。

对于离散型随机变量,其定义如下:
设随机变量X可以取值 x1, x2, ..., xk,对应的概率为 P1, P2, ..., Pk。则X的期望 E[X] 为:
E[X] = Σ (xi * Pi),其中求和 i 从1到 k

对于连续型随机变量,其定义是离散定义的扩展。设其概率密度函数为 p(x),则期望 E[X] 为:
E[X] = ∫ x * p(x) dx,积分区间为整个定义域(通常为负无穷到正无穷)。

简而言之,期望代表了随机变量在大量重复试验中的平均结果。

方差(Variance)

方差衡量的是随机变量的取值相对于其期望(均值)的离散程度或波动大小。

直观上,我们观察随机变量所有可能的取值(由其概率密度函数描述)。其期望 E[X] 是这些取值的中心点。方差则计算每个取值 x 与中心点 E[X] 的差距(即 x - E[X]),将这个差距平方以消除正负号的影响,最后对所有可能的 x 求这个平方差的加权平均。

以下是方差的正式定义。

对于离散型随机变量,方差 Var(X) 定义为:
Var(X) = E[(X - E[X])^2] = Σ Pi * (xi - E[X])^2

对于连续型随机变量,方差 Var(X) 定义为:
Var(X) = E[(X - E[X])^2] = ∫ p(x) * (x - E[X])^2 dx

因此,方差是随机变量取值与其均值之间“平均平方距离”的度量。方差越大,说明数据的波动越大;方差越小,说明数据越集中在均值附近。


本节课中我们一起学习了随机变量的期望与方差。期望描述了随机变量的平均或中心趋势,而方差则描述了其取值的离散或波动程度。理解这两个概念是后续学习概率分布、统计推断及机器学习中许多算法(如评估模型误差)的基础。

12:基础概率论III 📊

在本节课中,我们将要学习方差的概念,理解它如何描述随机变量的离散程度,并通过计算离散和连续随机变量的方差来加深理解。

方差的意义

上一节我们介绍了期望,它描述了随机变量的“中心”位置。本节中我们来看看方差,它衡量的是随机变量取值围绕其期望的分散程度。

如果随机变量的方差很小,这意味着随机变量的取值高度集中在期望值附近。

方差 Var(X) 的公式定义为:
Var(X) = E[(X - E[X])^2]

如果方差很小,即 E[(X - E[X])^2] 的值很小,则意味着随机变量 X 的取值非常接近其期望值 E[X]。其概率分布图看起来会非常“尖瘦”,数值紧密地聚集在平均值周围。

反之,如果随机变量的方差很大,即 E[(X - E[X])^2] 的值很大,则意味着随机变量的取值可能离平均值很远。其概率分布图会显得比较“扁平”和分散,数值广泛地散布在平均值周围。

方差计算示例

以下是两个具体随机变量的方差计算过程,一个是离散的,一个是连续的。

离散随机变量:伯努利分布

考虑一个简单的伯努利随机变量 X,例如抛一枚公平硬币。X 以1/2的概率取值为0(反面),以1/2的概率取值为1(正面)。

首先计算其期望 E[X]
E[X] = (1/2)*0 + (1/2)*1 = 1/2

接着计算其方差 Var(X)
Var(X) = E[(X - E[X])^2] = (1/2)*(0 - 1/2)^2 + (1/2)*(1 - 1/2)^2 = (1/2)*(1/4) + (1/2)*(1/4) = 1/4

因此,对于这个公平硬币的伯努利随机变量,其方差为 1/4

连续随机变量:高斯(正态)分布

现在考虑一个连续随机变量 X,它服从高斯(正态)分布。其概率密度函数(PDF)为:
p(x) = (1 / sqrt(2πσ^2)) * exp(-(x - μ)^2 / (2σ^2))

这个PDF的图像是关于 μ 对称的钟形曲线。

首先,其期望 E[X] 可以通过积分计算:
E[X] = ∫_{-∞}^{∞} x * p(x) dx
由于PDF关于 μ 完全对称,可以推断出(或通过计算证实)这个积分的值正好是 μ。所以 E[X] = μ

接着计算其方差 Var(X)
Var(X) = E[(X - μ)^2] = ∫_{-∞}^{∞} (x - μ)^2 * p(x) dx
这个积分也可以计算,最终结果是 σ^2

综上所述,对于高斯随机变量,其PDF中的参数 μ 就是它的期望(均值),而参数 σ^2 就是它的方差。

总结

本节课中我们一起学习了方差的概念。方差 Var(X) = E[(X - E[X])^2] 是衡量随机变量取值离散程度的核心指标。方差小意味着数据集中,方差大意味着数据分散。我们通过计算伯努利分布和高斯分布的期望与方差,具体理解了如何应用这些公式,并明确了在高斯分布中,参数 μσ^2 分别对应期望和方差的直观意义。

13:进阶概率论I 🎲

在本节中,我们将学习一组随机变量及其联合密度函数。我们将探讨这些随机变量取值的概率如何通过联合密度函数相互关联并量化。接着,我们将介绍独立性的概念,并探讨独立性在计算(例如某些随机变量的方差)中的意义。

联合密度函数

上一节我们介绍了单个随机变量的概率密度函数。本节中,我们来看看两个随机变量的情况。

给定两个随机变量 XYX 可以取特定值 xY 可以取特定值 yXY 的联合密度函数本质上给出了密度,或者更直观地说,给出了 X 取值 x 同时 Y 取值 y 的概率。这就是事件 X = xY = y 同时发生的联合概率。

这个函数对实数域上的每一个 xy 都有定义。通常,事件 X = xY = y 是相互依赖或相关的。联合密度函数 f(x, y) 本质上就是用来量化或刻画这种相关性的。

给定联合密度函数 f(x, y),我们可以计算 XY 不同事件的概率。以下是计算概率的通用方法:

例如,X 的值落在区间 [A, B] 内,同时 Y 的值落在区间 [C, D] 内的概率,可以通过对 xAByCD 积分联合密度函数 f(x, y) 来计算。

更一般地,X 的值落入某个集合 A(可以是区间、区间的并集或实轴上的复杂子集),同时 Y 的值落入集合 B 的概率,可以通过以下积分公式计算:

P(X ∈ A, Y ∈ B) = ∫∫_{x∈A, y∈B} f(x, y) dx dy

对于本课程而言,理解这个核心公式至关重要。

扩展到多个随机变量

现在我们已经定义了两个随机变量的联合密度函数,可以轻松地将这个概念推广到多个随机变量的集合。

给定 n 个随机变量 X₁, X₂, ..., Xₙ,它们的联合密度函数定义如下:

f(x₁, x₂, ..., xₙ) 直观上表示 X₁ 取值 x₁X₂ 取值 x₂,...,Xₙ 取值 xₙ 的概率。

对于任何特定的值 x₁xₙ,这个联合密度函数都会给出相应的概率。

同样地,我们可以使用联合密度函数来计算这些随机变量不同事件的概率。以下是计算多个随机变量落入指定区间概率的方法:

例如,X₁ 落入区间 [A₁, B₁]X₂ 落入区间 [A₂, B₂],...,Xₙ 落入区间 [Aₙ, Bₙ] 的概率,可以通过对 x₁A₁B₁x₂A₂B₂,...,xₙAₙBₙ 积分联合密度函数 f(x₁, x₂, ..., xₙ) 来计算。

P(X₁ ∈ [A₁, B₁], ..., Xₙ ∈ [Aₙ, Bₙ]) = ∫_{A₁}^{B₁} ... ∫_{Aₙ}^{Bₙ} f(x₁, ..., xₙ) dx₁ ... dxₙ

随机变量的独立性

讨论了联合密度函数之后,我们现在可以通过联合密度的概念来定义随机变量的独立性。

两个随机变量 XY 被称为独立的,当且仅当它们的联合密度函数可以分解为各自边缘密度函数的乘积。

用公式表示,对于任意实数 xy,有:

f(x, y) = f_X(x) * f_Y(y)

其中 f_X(x)X 的边缘密度函数,f_Y(y)Y 的边缘密度函数。

这直观地告诉我们:X 取值 xY 取值 y 的概率,等于 X 取值 x 的概率乘以 Y 取值 y 的概率。这正是我们熟悉的概率论中关于事件独立性的经典定义:两个事件交集的概率等于各自概率的乘积。

同样地,我们可以将独立性概念推广到 n 个随机变量。

n 个随机变量 X₁, X₂, ..., Xₙ 是独立的,当且仅当它们的联合密度函数 f(x₁, x₂, ..., xₙ) 可以分解为各自边缘密度函数的乘积:

f(x₁, x₂, ..., xₙ) = f_{X₁}(x₁) * f_{X₂}(x₂) * ... * f_{Xₙ}(xₙ)

总结

本节课中我们一起学习了概率论中的两个核心进阶概念。

首先,我们介绍了联合密度函数,它描述了多个随机变量同时取特定值的概率分布,是计算相关事件概率的基础工具。

其次,我们定义了随机变量的独立性,其关键判别条件是联合密度函数可分解为各变量边缘密度函数的乘积。独立性是简化许多概率计算(如方差计算)的重要前提。

理解联合密度与独立性,是深入学习机器学习中多维数据建模、贝叶斯推断等高级主题的基石。

14:进阶概率论II 🧮

在本节课程中,我们将学习随机变量期望与方差的三个重要关系。这些关系在后续课程中会非常有用。

上一节我们介绍了独立性与联合密度函数。本节中,我们来看看期望与方差的一些重要性质。

以下是三个核心关系,我们将逐一介绍。

  1. 期望的线性性:对于任意两个随机变量 XY,无论它们是否相关,都有:
    E[X + Y] = E[X] + E[Y]
    这个性质可以推广到任意多个随机变量。

  2. 独立随机变量乘积的期望:如果随机变量 XY 相互独立,那么对于任意函数 fg,有:
    E[f(X) * g(Y)] = E[f(X)] * E[g(Y)]
    特别地,当 fg 是恒等函数时,即 E[X * Y] = E[X] * E[Y]

  1. 独立随机变量和的方差:如果随机变量 X₁, X₂, ..., Xₙ 相互独立,那么:
    Var(X₁ + X₂ + ... + Xₙ) = Var(X₁) + Var(X₂) + ... + Var(Xₙ)
    注意,这个性质要求随机变量相互独立。

接下来,我们将详细证明第三个关系,即独立随机变量和的方差公式。

证明过程如下。设 X₁, X₂, ..., Xₙ 相互独立。记 μᵢ = E[Xᵢ]

首先,根据期望的线性性,和的期望等于期望的和:
E[∑ᵢ Xᵢ] = ∑ᵢ μᵢ

根据方差的定义,我们有:
Var(∑ᵢ Xᵢ) = E[(∑ᵢ Xᵢ - ∑ᵢ μᵢ)²] = E[(∑ᵢ (Xᵢ - μᵢ))²]

展开平方项:
E[(∑ᵢ (Xᵢ - μᵢ))²] = E[∑ᵢ (Xᵢ - μᵢ)² + 2 * ∑ᵢ∑ⱼ (i≠j) (Xᵢ - μᵢ)(Xⱼ - μⱼ)]

再次利用期望的线性性,上式等于:
∑ᵢ E[(Xᵢ - μᵢ)²] + 2 * ∑ᵢ∑ⱼ (i≠j) E[(Xᵢ - μᵢ)(Xⱼ - μⱼ)]

其中,第一项 E[(Xᵢ - μᵢ)²] 正是 Xᵢ 的方差 Var(Xᵢ)

对于第二项中的交叉项 E[(Xᵢ - μᵢ)(Xⱼ - μⱼ)],由于 XᵢXⱼ 独立,根据独立随机变量乘积的期望性质,有:
E[(Xᵢ - μᵢ)(Xⱼ - μⱼ)] = E[Xᵢ - μᵢ] * E[Xⱼ - μⱼ]

E[Xᵢ - μᵢ] = E[Xᵢ] - μᵢ = 0。因此,所有的交叉项期望值均为零。

于是,我们得到:
Var(∑ᵢ Xᵢ) = ∑ᵢ Var(Xᵢ)

证明完毕。

本节课中我们一起学习了随机变量期望与方差的三个核心性质:期望的线性性、独立变量乘积的期望性质以及独立变量和的方差可加性。这些是概率论和后续机器学习课程中非常重要的基础工具。

16:统计估计 📊

在本节课中,我们将要学习统计估计的核心概念。我们将从一个具体的例子出发,探讨如何使用随机抽样来估计总体特征,并分析这种估计方法的优劣。课程将重点介绍样本均值这一估计量,并引入期望、方差以及中心极限定理等关键工具来量化估计的准确性。

从随机抽样到统计估计框架

在上一模块中,我们开始讨论估计问题,并介绍了随机抽样。这是一种简单、直观且非常有效的方法,用于估计大规模总体的特征。我们当时的例子是估计美国所有女性的平均身高。

然而,这种方法对于许多其他应用和例子也至关重要。例如,估计将投票给某位候选人的选民百分比,是我们将要考虑的另一个应用。我们将把所有这类应用纳入一个统一且通用的统计估计框架中。

我们通过随机抽样引入的主要估计量是样本均值,它简单地是样本数据的平均值。

公式样本均值 = (数据点1 + 数据点2 + ... + 数据点n) / n

分析估计量的质量

在本模块中,我们的目标是分析这个估计量有多好。为此,我们需要计算抽样分布的期望和方差。通过这样做,我们将观察到我们的估计质量与收集的数据点数量之间有趣的联系。

进一步地,为了提供精确的误差范围,我们将引入概率论中另一个非常重要的工具:中心极限定理。中心极限定理是统计学和数据科学中最有效、应用最广泛的工具箱之一,也是表征估计误差和置信区间的主要技术。

总结

本节课中我们一起学习了统计估计的基础。我们从随机抽样的实际应用出发,建立了统一的统计估计框架,并聚焦于样本均值这一核心估计量。我们明确了分析估计量质量需要计算其期望和方差,并预告了中心极限定理在量化估计不确定性中的关键作用。

16:样本均值分析-期望 📊

在本节课中,我们将要学习如何分析样本均值这一估计量的期望性质。我们将回顾之前学过的概率论工具,并将其应用于一个具体的例子:估计美国女性的平均身高。通过计算样本均值的期望,我们将理解这个估计量在“平均”意义上的表现。


上一节我们回顾了两个随机变量的独立性与联合密度函数,并讨论了期望和方差的三个重要法则。现在,让我们回到贯穿始终的例子——估计美国女性的平均身高。在这个例子上,我们将讨论我们所设计的估计量的具体性质。掌握了概率论复习中学到的工具后,我们就能尝试估计这些我们将要看到的性质。

存在一个真实世界的现象。在我们的案例中,这是一个非常简单的任务。我们有一个身高总体,即第一个人的身高 H₁,第二个人的身高 H₂,一直到 H_N。请记住,总体大小 N 可能非常大,例如美国成年女性的总数可能达到数亿。我们的任务是估计平均身高。这个量就是所有身高从 1 到 N 的总和除以 N。这就是我们的任务。

我们希望通过从该总体中获得的数据来解决这个任务,估计这个平均身高。我们有一个数据采集模块,它为我们提供数据 X₁ 到 X_n。然后,我们希望通过样本均值来分析我们收集的这 n 个随机变量的数据(请记住,小写的 n 远小于大写的 N)。样本均值是 (X₁ + ... + X_n) / n,即 X̄。这就是我们的估计量。

我们还讨论过 X 的分布。X 的分布如下:X 是社会中第一个人的身高,概率为 1/N;是第二个人的身高,概率为 1/N;一直到第 N 个人的身高,概率为 1/N。同样重要的是,X 是独立的,因为每次我们选择一个新的人都是完全随机的,并且独立于之前选择的人。此外,所有 X 都具有相同类型的概率法则,因为每个 X 只是从社会中随机选择的一个人身高。

样本均值是我们的估计量,让我再写一遍:X̄ = (1/n) * Σ_{i=1}^{n} X_i。接下来,我将尝试估计 X̄ 的基本性质,例如它的均值和方差。从这些基本性质中,我们将看到这个估计量 X̄ 相对于真实值的好坏程度。


现在,让我们从样本均值的期望开始计算。我们要计算的是 E[X̄]。根据定义,X̄ = (1/n) * Σ_{i=1}^{n} X_i。因此,E[X̄] = E[(1/n) * Σ_{i=1}^{n} X_i]。1/n 是常数,可以提到期望外面,得到 (1/n) * E[Σ_{i=1}^{n} X_i]。

现在,我们应用上一节讨论的第一个关系:期望的线性性质。它告诉我们,和的期望等于期望的和。所以,E[Σ_{i=1}^{n} X_i] = Σ_{i=1}^{n} E[X_i]。

请记住,所有的 X_i 都具有完全相同的分布或法则。X_i 是一个随机选择的人的身高。它们都具有完全相同的概率分布。换句话说,所有 E[X_i] 彼此相等。所以,这等于 n 乘以其中任何一个 X 的期望。我们称之为 E[X₁],因为所有 X 的法则相同。因此,结果是 (1/n) * n * E[X₁] = E[X₁]。

那么,E[X₁] 很容易计算。根据给定的概率法则,X₁ 以概率 1/N 等于 H₁,以概率 1/N 等于 H₂,一直到以概率 1/N 等于 H_N。因此,E[X₁] = (1/N) * H₁ + (1/N) * H₂ + ... + (1/N) * H_N = (H₁ + H₂ + ... + H_N) / N。这恰好就是总体平均身高 μ。

我们在这里学到了什么?我们学到的是,在平均意义上,我们的估计量是精确的。即,E[X̄] 恰好等于 μ。一般来说,样本均值 X̄ 是一个随机变量,它有一个概率密度函数,可能是一个复杂的密度函数。但重要的是,在期望中,或者说 X̄ 的期望值,恰好是我们试图估计的值 μ。所以,在平均意义上,我们的估计量 X̄ 是精确的,它没有偏差。

但我们也应该注意到,期望本身并不是量化我们的估计量在估计真实值 μ 方面好坏的良好指标。换句话说,我可以在这里给你两个具有相同平均值 μ 的随机变量的例子。X̄ 可能有两种不同的概率密度函数。一种可能是分布较为分散,虽然期望值也是 μ,但它所取的值可能离 μ 相当远。另一种可能是分布非常集中在 μ 周围,期望值同样等于 μ。然而,右边这个 PDF 非常集中在均值 μ 附近。因此,在大多数情况下,你得到的 X̄ 结果值非常接近 μ,而左边的 PDF 其值则离 μ 相当远。在期望上,两者都是精确的,都给出值 μ,但右边具有右侧 PDF 的估计量更集中在 μ 周围。换句话说,它的值相对于均值 μ 的变化要小得多。

这本质上提示我们,为了量化 X̄ 的误差,或者为了量化我们的估计量 X̄ 最终的好坏,我们需要计算 X̄ 的另一个性质:方差。如果我们回到这两个例子,右边这个方差低,左边这个方差高。通过计算 X̄ 的方差,我们就能本质上理解我们处于哪种情况。这就是我们下一个目标。

17:样本均值分析-方差 📊

在本节课中,我们将要学习如何计算样本均值的方差。我们将从方差的定义出发,逐步推导出样本均值方差的公式,并探讨其重要含义,特别是样本数量如何影响估计的精确度。

上一节我们介绍了样本均值的概念,本节中我们来看看样本均值的方差。

计算样本均值的方差

根据定义,样本均值 的计算公式为:

X̄ = (X₁ + X₂ + ... + Xₙ) / n

其中,X₁Xₙ 是独立同分布的随机变量,n 是样本数量。

现在,我们来计算 的方差。方差衡量的是随机变量与其期望值之间的离散程度。

根据方差的性质,对于一个常数 α 和一个随机变量 X,有:

Var(αX) = α² * Var(X)

同时,对于一组独立的随机变量,它们之和的方差等于各自方差之和:

Var(X₁ + X₂ + ... + Xₙ) = Var(X₁) + Var(X₂) + ... + Var(Xₙ)

以下是计算样本均值方差 Var(X̄) 的步骤:

  1. 将常数因子 1/n 提取出来。
  2. 应用方差的性质 Var(αX) = α² * Var(X)
  3. 由于 Xᵢ 是独立的,应用方差的可加性。
  4. 由于 Xᵢ 同分布,它们的方差都等于总体方差 σ_pop²

具体推导如下:

Var(X̄) = Var( (X₁ + X₂ + ... + Xₙ) / n )

= (1/n)² * Var(X₁ + X₂ + ... + Xₙ)

= (1/n²) * [Var(X₁) + Var(X₂) + ... + Var(Xₙ)]

= (1/n²) * (n * σ_pop²)

= σ_pop² / n

因此,我们得到了核心结论:样本均值的方差等于总体方差除以样本数量 n

总体方差 σ_pop² 的定义

总体方差 σ_pop² 是一个描述整个总体离散度的固定值。假设总体有 N 个个体,其取值(例如身高)为 H₁, H₂, ..., H_N,总体均值为 μ,则总体方差定义为:

σ_pop² = (1/N) * Σ_{i=1}^{N} (Hᵢ - μ)²

这个值完全由总体本身决定,不依赖于我们抽取的样本。

方差含义与样本数量的影响

样本均值方差 σ_pop² / n 的公式揭示了统计学中一个极其重要的规律。

Var(X̄) = σ_pop² / n

从这个公式可以看出,样本均值 的方差与样本数量 n 成反比。σ_pop² 是一个固定值,因此随着样本数量 n 的增加, 的方差会越来越小。

方差越小,意味着样本均值 的分布越集中在其期望值 μ(即真实的总体均值)周围。我们可以通过概率密度函数(PDF)的形状变化来直观理解这一点。

以下是不同样本数量 n 下,样本均值 的概率密度函数(PDF)示意图:

  • n = 1 就是单个样本 X₁ 的分布。其 PDF 形状与总体分布相同,较为分散。
  • n = 10 是10个独立样本的平均值。其 PDF 的均值仍为 μ,但宽度(离散程度)已经收窄,大约为 σ_pop / √10
  • n = 100:PDF 进一步收窄,宽度约为 σ_pop / √100 = σ_pop / 10。与 n=10 相比,宽度缩小了约 1/√10 倍。
  • n = 10000:PDF 变得非常尖锐,高度集中在 μ 附近,宽度约为 σ_pop / 100

核心结论是:随着样本数量 n 的增大,样本均值 1/√n 的速度越来越集中地围绕在真实总体均值 μ 周围

这意味着,我们收集的数据越多,用样本均值来估计总体均值就越精确。这种收敛速度(1/√n)是许多统计推断和机器学习算法的理论基础。

本节课中我们一起学习了样本均值方差的计算与含义。我们推导出关键公式 Var(X̄) = σ_pop² / n,并认识到样本数量 n 的增加会显著降低估计的方差,使样本均值更可靠地逼近总体真实均值,其收敛速度与 1/√n 成正比。这是理解统计估计精度和设计实验样本量的基础。

18:另一个例子 - 哪位候选人将获胜 🗳️

在本节中,我们将讨论另一个例子。我们将探讨一个可以使用我们目前所学的思想来解决或估计的任务。

概述

我们将要解决或估计的任务如下:考虑一场即将到来的总统选举。其中一位候选人希望估计某个州(例如宾夕法尼亚州)中会投票支持他/她的选民比例。作为总统的数据科学顾问,我们需要快速提供结果。我们将从宾夕法尼亚州中均匀随机地选择1000人,询问他们打算投票给哪位候选人,并通过计算样本均值来估计支持我们候选人的选民比例。

问题建模

现在,让我们将一切放入我们一直在讨论的框架中。这里存在一个真实世界的现象。

  • 我们有一个包含 N 个人的总体。
  • 每个个体心中都有一个数字。对于第 i 个个体,数字 Y_i1(如果该人投票给我们的候选人),否则是 0(如果投票给另一位候选人)。

因此,整个宾夕法尼亚州支持我们候选人的选民比例 μ 就是所有 Y_i 的平均值:

公式:μ = (Y₁ + Y₂ + ... + Y_N) / N

这里的 N 非常大(例如数百万),我们无法挨家挨户询问。因此,我们需要从总体中抽取一个更小的样本。

数据采集与分析

我们将通过数据采集模块收集数据 X₁X_n。这里的小写 n(例如1000)远小于大写 N

  • 每个数据点 X_i 是一个随机变量,因为我们是从总体中完全随机地选择一个人。
  • 我们询问这个人,其值 X_i0 还是 1

然后,我们将分析这些数据。在这种情况下,数据分析模块非常简单:我们将计算样本均值

公式:X̄ = (X₁ + X₂ + ... + X_n) / n

我们希望样本均值 能成为总体比例 μ 的一个良好估计。这与之前的例子(估计平均身高)设置完全相同,只是这里的 Y_i 是简单的二元值(0或1),而不是实数值。

随机变量的概率分布

现在,我们来计算 X_i 的概率。由于我们是从总体中均匀随机地选择一个人:

  • X_i = 1 的概率等于我们选到一个支持我们候选人的个体的概率。这个概率恰好等于总体中支持者的比例 μ
  • X_i = 0 的概率则是 1 - μ

此外,因为每次选择都是完全随机的,并且独立于之前的选择,所以 X_i 具有相同的概率分布。这种分布被称为伯努利分布,其参数为 μ

代码/公式描述:X_i ~ Bernoulli(μ)

这意味着 X_i 以概率 μ 取值为1,以概率 1-μ 取值为0。

估计量的期望与方差

我们基于这种随机抽样的估计量是 。为了分析 ,我们需要计算它的期望和方差。这与之前的计算完全类似。

首先,计算 X_i 的期望值 E[X_i]

公式:E[X_i] = 0 * (1 - μ) + 1 * μ = μ

因此,我们的估计量 的期望值也是 μ。这意味着,平均而言,我们的估计量给出的正是我们希望找到的真实值 μ

接下来,计算 的方差 Var(X̄)。与之前类似, 的方差等于 X_i 的方差除以样本量 n

公式:Var(X̄) = Var(X_i) / n

现在计算 Var(X_i)

公式:Var(X_i) = E[(X_i - μ)²] = (0 - μ)² * (1 - μ) + (1 - μ)² * μ = μ(1 - μ)

将结果代入,得到:

公式:Var(X̄) = μ(1 - μ) / n

结论与意义

我们得到了与之前任务完全相同的结论:

  1. 无偏性:估计量 的期望值等于真实参数 μ,说明这是一个无偏估计。
  2. 方差递减:估计量 的方差为 μ(1-μ)/n。这是一个仅取决于总体(固定常数)的数值除以样本量 n
  3. 样本量的影响:随着样本量 n 的增加,方差变得越来越小,并且与 n 成反比。这意味着收集更多数据可以使我们的估计更加精确和可靠。

因此,关于之前平均身高任务的所有推论和结论,在这个选举预测的例子中同样完全适用。通过随机抽样和计算样本均值,我们可以有效地估计总体中的比例,并且其准确性随着样本量的增加而提高。


本节课总结:在本节课中,我们一起学习了如何将数据科学框架应用于一个实际问题——预测选举中候选人的支持率。我们建立了总体模型,定义了二元随机变量,说明了如何通过随机抽样收集数据,并计算了样本均值估计量的期望和方差。我们得出结论,样本均值是总体比例的无偏估计,并且其精度随样本量增加而提高。这再次验证了统计推断中核心概念的有效性。

19:通用框架 🧠

在本节课中,我们将学习如何将之前学过的概念整合到一个更广泛的通用框架中。这个框架将帮助我们理解从现实世界现象到数据分析的完整流程。


上一节我们介绍了样本均值和期望等具体概念,本节中我们来看看如何将这些概念置于一个统一的框架下。

我们目前所学的知识可以概括为以下框图:

首先,存在一个我们想要了解的现实世界物理现象

我们想要学习关于这个现象的一些底层参数

例如,我们可能想估计人群的平均身高,或者估计会投票给某位候选人的选民百分比。

因此,存在一些我们想要估计的参数

为了估计这些参数,我们需要收集数据。这就引出了数据采集模块。

数据采集模块为我们提供了数据点。

这些数据点记为 X₁ 到 Xₙ

关于这些数据点,一个重要的概念是随机样本。从统计学角度,我们对数据点序列 X₁ 到 Xₙ 进行建模。

我们将它们建模为随机变量 Xᵢ

这些随机变量是独立同分布的。

简称为 IID。换句话说,每个 Xᵢ

性质一:独立性。每个数据点都独立于其他数据点。

我们获得的关于这个现实世界现象的所有样本或数据点都是相互独立的。

性质二:同分布。它们具有相同的分布,因为它们是由同一个现象产生的。

这就是我们对 Xᵢ 所做的 IID 假设。

这是我们在整个课程中关于数据所使用的基本统计假设。

一旦我们有了 Xᵢ,我们就要处理它们。这就是数据分析模块。

我们将处理这些数据,本质上是为了获得关于底层现实世界现象的知识。

我们将计算某种关于数据 X₁ 到 Xₙ 的函数。

这个函数会给出关于现实世界的某些属性,例如我们一直在使用的样本均值

例如,(样本均值)就是我们根据已有数据点计算的一个函数。

这个函数通常被称为统计量

统计量是样本数据的一个函数。一个基本的定义是:统计量是一个其值可以从样本数据中计算出来的量,它是样本数据的函数。

这里重要的是,统计量的结果是一个随机值。因为数据是随机产生的,Xᵢ 是随机变量,因此统计量的结果也将是一个随机变量。

举个例子,到目前为止我们尝试计算的函数或统计量就是 ,即数据点 Xᵢ 的平均值。 是一个随机变量,因为 Xᵢ 是随机变量。

因此,我们从数据中计算出的任何统计量,其结果都是一个随机变量。我们需要分析它的不同性质,例如,到目前为止我们已经计算了这个随机变量的期望和均值。

但需要记住的关键点是,我们从数据中计算出的这个统计量 ,通常是一个随机变量。


本节课中我们一起学习了机器学习与统计推断的通用框架。我们了解到,整个过程始于一个我们想要理解的现实世界现象及其参数,通过数据采集获得独立同分布的样本数据,最后通过数据分析模块计算统计量来推断这些参数。理解这个框架是后续深入学习具体算法和模型的基础。

20:高斯分布及其性质 📊

在本节课中,我们将要学习高斯分布(也称为正态分布)及其一些关键性质。我们将介绍其定义、参数、标准形式,以及一个重要的概念——Z值。这些概念和符号将在后续的中心极限定理和置信区间计算中反复使用。

高斯分布的定义与参数

上一节我们介绍了概率分布的基本概念,本节中我们来看看最经典的高斯分布。

高斯分布通过其概率密度函数(PDF)定义。其PDF公式如下:

\[f(x) = \frac{1}{\sigma\sqrt{2\pi}} e^{-\frac{1}{2}\left(\frac{x-\mu}{\sigma}\right)^2} \]

在表示上,我们通常使用以下符号:\(X \sim \mathcal{N}(\mu, \sigma^2)\)。其中,\(\mathcal{N}\) 代表正态分布,\(\mu\)\(\sigma^2\) 是高斯分布的两个参数。

对于服从上述PDF的随机变量 \(X\),其期望值(均值)和方差是已知的:

  • 期望值\(\mathbb{E}[X] = \mu\)
  • 方差\(\text{Var}(X) = \sigma^2\)

高斯分布的PDF图形是一个对称的钟形曲线,以均值 \(\mu\) 为中心对称。方差 \(\sigma^2\) 决定了曲线的宽度,\(\sigma\) 越大,曲线越宽、越平缓。

标准高斯分布

通常,我们会特别关注均值为0、方差为1的高斯分布,称之为标准高斯分布或标准正态分布。其参数为 \(\mu = 0\)\(\sigma^2 = 1\)

标准高斯分布的PDF公式简化为:

\[\phi(z) = \frac{1}{\sqrt{2\pi}} e^{-\frac{z^2}{2}} \]

在本课程中,我们将始终使用 \(Z\) 来表示服从标准高斯分布的随机变量,即 \(Z \sim \mathcal{N}(0, 1)\)。而 \(z\) 则用于表示该随机变量的某个具体取值(实现值)。

一个重要的关系是,任何高斯分布都可以表示为标准高斯分布的线性变换。具体公式如下:

如果 \(X \sim \mathcal{N}(\mu, \sigma^2)\)\(Z \sim \mathcal{N}(0, 1)\),那么:

\[X = \mu + \sigma Z \]

这意味着,一个一般的高斯随机变量 \(X\),可以通过对标准高斯变量 \(Z\) 进行缩放(乘以 \(\sigma\))和平移(加上 \(\mu\))得到。请记住这个关系,我们将在后续章节中用到它。

累积分布函数与Z值

现在,我们来定义与高斯分布相关的另外两个重要概念。

首先,是标准高斯分布的累积分布函数(CDF)。我们使用 \(\Phi(z)\) 来表示它:

\[\Phi(z) = P(Z \leq z) = \int_{-\infty}^{z} \frac{1}{\sqrt{2\pi}} e^{-\frac{t^2}{2}} dt \]

从图形上看,\(\Phi(z)\) 表示标准高斯PDF曲线下,从 \(-\infty\) 到点 \(z\) 左侧的面积。

其次,是一个称为 \(z_{\alpha}\)(或Z值)的关键概念。以下是它的定义:

\(z_{\alpha}\) 是实数轴上的一个点,满足标准高斯随机变量 \(Z\) 取值大于 \(z_{\alpha}\) 的概率恰好为 \(\alpha\)。用公式表达为:

\[P(Z > z_{\alpha}) = \alpha \]

从图形上理解,在标准高斯PDF曲线下,\(z_{\alpha}\) 点右侧的尾部面积正好等于 \(\alpha\)

由于PDF曲线下的总面积为1,\(z_{\alpha}\) 点左侧的面积就是 \(1 - \alpha\)。因此,\(z_{\alpha}\) 值与CDF函数 \(\Phi\) 存在一个简单的关系:

\[\Phi(z_{\alpha}) = 1 - \alpha \]

或者等价地:

\[z_{\alpha} = \Phi^{-1}(1 - \alpha) \]

其中 \(\Phi^{-1}\) 是CDF的反函数。这个关系将概率 \(\alpha\) 与具体的分位点 \(z_{\alpha}\) 联系了起来。


本节课中我们一起学习了高斯分布的核心内容。我们回顾了高斯分布的定义、参数(均值 \(\mu\) 和方差 \(\sigma^2\))及其图形特征。我们重点介绍了标准高斯分布 \(\mathcal{N}(0, 1)\),并理解了任何高斯变量都可以通过 \(X = \mu + \sigma Z\) 从标准形式变换得到。最后,我们定义了累积分布函数 \(\Phi(z)\) 和至关重要的 \(z_{\alpha}\) 值,它描述了分布尾部的概率。这些概念和符号是概率论与统计学的基石,将在机器学习和数据科学的后续学习中频繁出现。

21:中心极限定理 I 🧮

在本节课中,我们将要学习统计学中一个极其重要的定理——中心极限定理。这个定理不仅在统计学中至关重要,在物理学、数学、工程学等众多科学领域也广泛应用。我们将首先通过直观的方式理解这个定理,然后介绍其精确的数学表述。对于本课程而言,理解其直观图像和近似应用更为关键。

中心极限定理的直观图像

上一节我们介绍了中心极限定理的重要性,本节中我们来看看它的核心思想。中心极限定理主要处理一组独立同分布的随机变量。

以下是其核心设定:

  • 我们有一组独立同分布的随机变量:X₁, X₂, ..., Xₙ
  • “独立同分布”意味着这些变量相互独立,并且具有完全相同的概率分布。
  • 我们关心这些随机变量的样本均值,其计算公式为:
    X̄ = (X₁ + X₂ + ... + Xₙ) / n

中心极限定理的核心结论是:无论原始随机变量Xᵢ服从何种分布,只要样本数量n足够大,样本均值的分布就会近似于一个正态分布(高斯分布)

深入理解均值和方差

为了更具体地理解这个近似,我们需要知道这个近似正态分布的参数。我们首先回顾样本均值的均值和方差。

以下是相关定义和计算:

  • 设每个随机变量Xᵢ的总体均值为 μ,总体方差为 σ²
  • 根据期望的线性性质,样本均值的期望值(均值)为:
    E[X̄] = μ
  • 样本均值的方差为:
    Var(X̄) = σ² / n

可以看到,样本均值的方差比单个变量的方差缩小了n倍。这意味着随着样本量增加,的取值会越来越集中在总体均值μ附近。

中心极限定理的近似表述

基于以上讨论,中心极限定理的直观近似可以表述为:当n很大时,样本均值近似服从一个正态分布。

我们可以将其写作:
X̄ ≈ N(μ, σ²/n)
这里的“≈”表示近似,并且包含一个随着n增大而趋于零的误差项。在实际应用中,当样本量n较大时,我们通常会忽略这个误差,直接使用正态分布来进行计算和推断。

因此,我们近似认为服从一个均值为μ、方差为σ²/n的正态分布。正态分布由其均值和方差唯一确定,所以我们就能完全描述的近似分布了。

概率密度函数的图像化理解

让我们从概率密度函数的角度来直观感受中心极限定理。假设原始变量X的分布是任意的(例如不对称的),其概率密度函数可能形状不规则。

以下是随着样本量变化的趋势:

  • 当样本量n较小时,样本均值的分布可能仍保留一些原始分布的特征。
  • 随着样本量n不断增大,的概率密度函数形状会越来越接近一个钟形曲线,即正态分布的图形。
  • 这个近似正态分布的中心(均值)μ处。
  • 这个近似正态分布的宽度(分散程度) 由标准差 σ/√n 决定。n越大,曲线越瘦高,表示的取值越集中。

需要再次强调,这是一个帮助理解的直观图像,并非严格的数学表述。例如,当原始变量是离散型时,谈论概率密度函数就不完全精确。我们将在后续讨论更正式的表述。

总结

本节课中我们一起学习了中心极限定理的直观思想。我们了解到,对于来自同一总体的独立随机样本,其样本均值的分布,在样本量足够大时会趋近于正态分布N(μ, σ²/n)。这个定理的强大之处在于,它对原始总体的分布形式没有特殊要求,奠定了许多统计推断方法(如参数估计、假设检验)的理论基础。在后续课程中,我们将直接应用这个近似结果来解决实际问题。

21:中心极限定理II

在本节课中,我们将深入学习中心极限定理的核心思想、正式表述及其直观意义。我们将理解为何样本均值的分布会趋近于正态分布,以及这一性质在数据科学中的重要性。

中心极限定理的核心思想

上一节我们介绍了中心极限定理的基本概念。本节中,我们来看看该定理的一个关键特性:它不关心原始数据的分布形态

中心极限定理并不关心随机变量 ( X ) 的初始分布。原始变量 ( X ) 的概率密度函数 ( f_X(x) ) 可以是任何非常一般的分布。例如,它可以是任意形状的分布。

中心极限定理指出,只要随机变量 ( X_i ) 是独立同分布的,那么当你观察样本均值 ( \bar{X} ) 的概率密度函数时,随着样本数量 ( n ) 增大,这个分布会越来越像一个简单、漂亮的钟形曲线方程所描述的形态。

因此,只要 ( X_i ) 是独立同分布的,( X ) 的原始分布具体是什么并不重要,它可以是任何分布。最终重要的是,样本均值 ( \bar{X} ) 会变成一个高斯(正态)分布,其均值和方差由 ( X ) 的均值和方差决定,外加一些随着 ( n ) 增大而趋于 0 的可忽略误差。

用公式表示,样本均值 ( \bar{X} ) 近似服从以下正态分布:
[
\bar{X} \sim \mathcal{N}(\mu, \frac{\sigma^2}{n})
]
其中 ( \mu ) 是 ( X ) 的总体均值,( \sigma^2 ) 是 ( X ) 的总体方差,( n ) 是样本数量。当 ( n ) 很大时,近似误差可以忽略。

这就是中心极限定理背后的直观图像。

中心极限定理的正式表述

理解了直观思想后,我们现在来解释中心极限定理的正式版本。

回忆一下,当 ( n ) 变得很大时,样本均值 ( \bar{X} ) 在渐近意义上会非常接近一个高斯随机变量。我们所说的正是这个高斯分布。

让我们先看看这个高斯分布的累积分布函数,我们用 ( \Phi ) 表示。对于均值为 ( \mu )、方差为 ( \sigma^2/n ) 的正态分布,其在点 ( x ) 的 CDF 定义为:
[
\Phi_{\mu, \sigma^2/n}(x) = P(\text{Gaussian} \leq x)
]
同时,我们看看随机变量 ( \bar{X} )(样本均值)的 CDF。记作 ( F_{\bar{X}}(x) ),它表示 ( \bar{X} ) 小于 ( x ) 的概率。

中心极限定理的正式表述如下:对于实数轴上的任意一点 ( x ),样本均值 ( \bar{X} ) 的 CDF 与对应高斯分布的 CDF 之间的差异非常小。具体来说,这个差异的上界是某个常数 ( C ) 除以 ( \sqrt{n} ):
[
| F_{\bar{X}}(x) - \Phi_{\mu, \sigma^2/n}(x) | \leq \frac{C}{\sqrt{n}}
]
这里,( n ) 是样本数量(或数据点数量),而 ( C ) 是一个常数。这个常数 ( C ) 依赖于原始随机变量 ( X ) 的分布,但它是一个固定值(例如 5、10 等),与 ( n ) 无关。重要的是,这个误差(两个 CDF 之间的差异)非常非常小,并且随着数据点数量 ( n ) 的增加而消失。

以下是该定理的直观图示:

  • ( F_{\bar{X}}(x) ) 和 ( \Phi_{\mu, \sigma^2/n}(x) ) 都是递增函数。
  • 随着 ( n ) 增大,( F_{\bar{X}}(x) ) 的曲线会越来越接近 ( \Phi_{\mu, \sigma^2/n}(x) ) 的曲线。
  • 在任意点 ( x ) 处,两条曲线之间的垂直距离(即误差)始终小于 ( C / \sqrt{n} )。
  • 随着样本数量 ( n ) 变得越来越大,任意点 ( x ) 处两个 CDF 之间的差异会变得越来越小。

这就是中心极限定理的正式版本(Berry-Esseen 版本),它很重要。然而,在本课程中,我希望大家真正记住并掌握的是下面这个图像:( \bar{X} ) 的行为就像一个高斯随机变量加上一些误差,但在本课程涉及的所有应用中,我们通常假设数据点数量 ( n ) 足够大,以至于这个误差与高斯随机变量部分相比可以忽略不计。

因此,我们通常忽略这个误差,只处理我们看到的高斯部分。这使得基于正态分布的统计推断(如置信区间、假设检验)在实际应用中成为可能和有效的工具。

总结

本节课中我们一起学习了中心极限定理的深入内容。我们明确了该定理的核心在于样本均值的分布形态与原始分布无关,最终都会趋近于正态分布。我们学习了该定理的正式数学表述,即样本均值累积分布函数与理论正态分布累积分布函数之间的误差,其上界以 ( C / \sqrt{n} ) 的形式收敛。最重要的是,我们理解了在实际应用中,当样本量足够大时,我们可以安全地忽略这个误差,直接将样本均值视为服从正态分布,从而为后续的统计分析和机器学习方法奠定了坚实的理论基础。

22:置信区间与点估计介绍 🎯

在本节课中,我们将要学习两个核心的统计推断概念:置信区间点估计。我们将首先利用中心极限定理来理解如何量化估计的不确定性,然后探讨更一般的参数估计框架。

概述

上一节我们介绍了中心极限定理这一重要工具。本节中,我们来看看如何应用它来构建置信区间。置信区间是数据科学和机器学习中几乎所有领域用于表征误差范围的主要量。通常,数据科学中的所有数值研究都会计算并报告置信区间。

在本模块中,我们将为样本均值估计量引入并推导置信区间,并通过一些示例来加深理解。这将完成我们对样本均值估计的分析。

接下来,我们将开始探索一个关于估计的更通用视角,其目标是估计数据的参数。这个框架的正式名称是点估计。我们将解释点估计的两个主要原则,即无偏估计原则,以及最小方差无偏估计原则。


置信区间

既然我们已经学习了中心极限定理这一重要工具,现在可以开始学习置信区间了。置信区间是数据科学和机器学习几乎所有领域中,用于表征误差范围的主要量。通常,数据科学中的所有数值研究都会计算并报告置信区间项。

在本模块中,我们将为样本均值估计量引入并推导置信区间,并提供一些示例以进一步加深理解。这将完成我们对样本均值估计的分析。

核心概念与构建

中心极限定理指出,样本均值 \(\bar{X}\) 的抽样分布近似服从正态分布,其均值为总体均值 \(\mu\),标准差为 \(\frac{\sigma}{\sqrt{n}}\)(即标准误)。基于此,我们可以构建一个区间来估计总体参数。

一个常见的 95% 置信区间 的公式为:
[
\bar{X} \pm 1.96 \times \frac{\sigma}{\sqrt{n}}
]
其中,\(\bar{X}\) 是样本均值,\(\sigma\) 是总体标准差(通常用样本标准差 \(s\) 估计),\(n\) 是样本大小。

以下是构建置信区间的关键步骤:

  1. 从数据中计算样本统计量(如均值)。
  2. 确定该统计量的抽样分布(通常借助中心极限定理)。
  3. 根据所需的置信水平(如95%),找到对应的临界值(如1.96)。
  4. 计算标准误,并结合临界值得到误差范围。
  5. 用样本统计量加减误差范围,得到置信区间。

点估计

接下来,我们将开始探索一个更通用的参数估计视角,其目标是估计数据的参数。这个框架的正式名称是点估计

点估计为我们提供了一个单一的数值,作为未知总体参数的最佳猜测。我们将解释点估计的两个主要原则。

估计原则

以下是点估计中两个核心的评价准则:

  1. 无偏性:一个估计量 \(\hat{\theta}\) 被称为是无偏的,如果它的期望值等于真实参数值 \(\theta\),即:
    [
    E[\hat{\theta}] = \theta
    ]
    无偏性意味着估计量在多次重复抽样中没有系统性的高估或低估。

  2. 最小方差无偏估计:在所有无偏估计量中,方差最小的那个被认为是最有效的。它意味着该估计量的结果在真实值周围波动最小。寻找最小方差无偏估计量是点估计的一个重要目标。


总结

本节课中我们一起学习了统计推断的两个基础模块。首先,我们利用中心极限定理构建了置信区间,它提供了一个可能包含总体参数的范围,并量化了估计的不确定性。接着,我们介绍了点估计的框架,它旨在给出未知参数的单一最佳估计值,并重点讨论了无偏性最小方差这两个核心评价原则。理解这些概念对于评估数据科学和机器学习中任何模型的可靠性与准确性至关重要。

24:置信区间 I 📊

在本节课中,我们将要学习置信区间的基本概念。我们将利用中心极限定理部分学到的知识和概念来计算置信区间。首先,我们会解释并阐述“置信区间”这一术语的含义,探讨如何从概念和数学上理解并量化它。

背景回顾与目标设定

上一节我们介绍了中心极限定理,本节中我们来看看如何应用它。首先,快速回顾一下我们目前的研究背景。

到目前为止,我们的设定是估计给定总体的均值。从数据科学的角度来看,存在一个真实世界的现象。在统计学上,我们将其视为一个总体,其均值用 μ 表示,而 μ 的值是未知的。

我们能做的是从这一物理现象中收集数据。数据采集模块会给我们数据 x₁, x₂, ..., xₙ。在统计学上,我们认为这些数据点 xᵢ 是独立同分布的。我们还注意到或假设,由于它们来自同一个总体,xᵢ 的期望值(均值)恰好是 μ

我们的任务就是估计未知的 μ 值。数据分析模块为此设计了一个点估计量,我们的估计量是样本均值 ,即 xᵢ 的平均值。这是一个对 μ 的估计。

在本节中,我们将讨论 μ 有多接近。我们已经计算了 的均值(恰好是 μ)和方差(是 σ²/n,其中 σ 是总体方差)。现在,我们将给出关于 与其试图近似或估计的真实值 μ 之间接近程度的更精确误差界限。

实际上,我们唯一能接触到的就是数据 x₁, x₂, ..., xₙ。我们将使用这些数据来弄清楚我们的估计值 与真实值 μ 有多接近。这是我们唯一能计算的东西。我们不知道 μ 的值,对 μ 的唯一了解都来自数据,例如

误差的量化思路

我们的目标在此。第一个需要思考的问题是:如何量化 在近似 μ 时的误差?正确的数学概念是什么?

思考这个问题,首先想到的最简单的想法如下: 旨在估计 μ。那么为什么不直接考虑 恰好等于 μ 的事件呢?让我们看看概率 P(X̄ = μ)。毕竟,如果 在近似 μ,我们希望 在大多数时候能给出 μ 的精确值。这是一个合理的想法,但实际上存在一个问题。

问题是,通常情况下,例如当 xᵢ 的分布是连续分布时,这个概率值恰好是零。为什么?因为如果你看 的概率密度函数,如果 xᵢ 是连续随机变量, 的 PDF 是一个连续函数,是一个连续的 PDF。即使 的均值恰好是 μ 恰好等于 μ 的概率显然是零。例如,如果 xᵢ 是指数随机变量或高斯随机变量,它们的平均值恰好等于 μ 的概率是零。

因此,这确实不是量化误差或量化 μ 接近程度的正确概念。但我们可以将其扩展到正确的概念。我们实际上想看在多大比例的情况下 接近 μ,不是恰好等于,而是接近。那么,为什么不围绕 μ 值画一个小区间呢?

引入区间概念

这是一个围绕 μ 值的小区间,称之为 μ + βμ - β。然后看看 的值落在这个区间内的概率,并认为 β 是一个很小的数。

所以,回到思路。思路一是点概率,点概率很可能为零,所以这个思路行不通。但是,如果我们不看点,而是看围绕正确值 μ 的区间,比如 μ ± β,那么下面的概念就很有意义了:概率 P(μ ∈ [X̄ - β, X̄ + β])。这个量很有意义,因为它不是点值。点值是零。但如果你认为 β 是一个很小的数,让我给你举个例子。

例如,如果 β = 0.01,一个非常小的数。那么我们问的是:概率 P(μ ∈ [X̄ - 0.01, X̄ + 0.01]) 是多少?我们在这里问的是,正确值 μ 落入围绕 值的这个非常小的区间的概率是多少?记住, 是你从数据中计算出来的东西。例如,假设你从数据中计算出 X̄ = 5。你问的是:概率 P(μ ∈ [4.99, 5.01]) 是多少?本质上,我们要计算这个可能性,这个概率。现在这突然变得有意义了,因为它不是一个精确的点,而是一个小区间,区间没有零概率。

置信区间的正式定义

将这个概念推广到置信区间的实际概念,关于置信区间我们要问的主要问题如下:

我们给定样本数据 x₁, x₂, ..., xₙ,可以将其视为独立同分布随机变量序列。我们还给定一个置信水平 1 - α,将 α 视为一个很小的数。通常在实践中,α 可以取 0.050.02 等。

我们要寻找一个值 β,使得真实值 μ(记住,μ 是未知的)落入区间 [X̄ - β, X̄ + β] 的概率是 1 - α

本质上,我们要做的是找到这个区间,使得 μ 在该区间内的概率是 1 - α。记住 α 是一个小数。例如,α = 0.05,那么我希望这个概率是 0.95。这是一个假设。问题是:什么样的区间使得在 95% 的情况下,从我计算的 值出发,我可以有这个区间 [X̄ - β, X̄ + β],使得 μ 值落入该区间?我们要找到 β 的值。

我们将根据 αn 以及 X 分布的性质(例如 xᵢ 的方差)来找到 β。这就是置信区间的概念。所以,我们现在的任务是找到 β。一旦我们找到 β,它就会给我们一个区间。例如,这个区间使得在 95% 的情况下,μ 的真实值落入该区间,并且该区间是从 计算出来的,而 是从数据点计算出来的。

概率的等价转换

我们将这样做,但在此之前,让我解释一下,这里的概率可以用一种稍微不同的方式书写,这将帮助我们精确计算这个概率。

概率 P(μ ∈ [X̄ - β, X̄ + β]) 恰好等于概率 P(X̄ ∈ [μ - β, μ + β])。当我谈到这个区间时,你们中的一些人可能已经想到了这一点。所以,之前是 μ ± β 的区间,然后我突然写了 μ[X̄ - β, X̄ + β] 之间。但这两者是同一件事。

我在这里声称这两个概率实际上是相等的。这两个事件是完全相同的。为什么?原因很简单,让我为你快速做一下代数运算,只是为了向你展示它们是相同的。

让我从左手边开始。这个条件告诉我们:μ ≥ X̄ - βμ ≤ X̄ + β

现在,从第一个不等式,本质上,让我把 β 移到另一边,这会告诉我 X̄ ≤ μ + β。第二个不等式会告诉我,通过把 β 移到另一边,X̄ ≥ μ - β。这正好就是事件 X̄ ∈ [μ - β, μ + β]


本节课中我们一起学习了置信区间的基本概念。我们从回顾估计总体均值的背景出发,探讨了为何不能直接用点概率来量化估计误差,从而引入了围绕真实值的小区间思想。我们正式定义了置信区间:在给定置信水平 1 - α 下,寻找一个区间 [X̄ - β, X̄ + β],使得未知总体均值 μ 落在此区间内的概率为 1 - α。最后,我们通过代数转换,证明了寻找该区间等价于考虑样本均值 落在区间 [μ - β, μ + β] 内的概率。这为我们下一节具体计算置信区间奠定了理论基础。

25:置信区间II 🎯

在本节课中,我们将继续学习置信区间的构建。上一节我们介绍了置信区间的基本概念,本节中我们将推导出置信区间的具体数学公式,并讨论其在实践中面临的一个关键问题。

概述

我们的目标是找到一个值 β,使得真实均值 μ 落在区间 [X̄ - β, X̄ + β] 内的概率恰好为 1 - α。正如上一节所解释的,这个概率等价于样本均值 落在区间 [μ - β, μ + β] 内的概率。

推导置信区间公式

以下是推导置信区间公式的关键步骤。

步骤一:概率等价转换

我们首先处理更便于计算的概率形式:
P( μ ∈ [X̄ - β, X̄ + β] ) = P( X̄ ∈ [μ - β, μ + β] )

步骤二:标准化处理

将区间条件进行重写和标准化:
P( μ - β ≤ X̄ ≤ μ + β )
这等价于:
P( -β ≤ X̄ - μ ≤ β )
为了应用中心极限定理,我们对不等式两边同时除以 σ / √n
P( -β/(σ/√n) ≤ (X̄ - μ)/(σ/√n) ≤ β/(σ/√n) )

步骤三:应用中心极限定理

根据中心极限定理,当样本量 n 足够大时,标准化后的统计量 (X̄ - μ)/(σ/√n) 近似服从标准正态分布 Z ~ N(0, 1)。因此,上述概率可以近似为:
P( -β/(σ/√n) ≤ Z ≤ β/(σ/√n) ) ≈ 1 - α

步骤四:利用正态分布的对称性

标准正态分布的概率密度函数关于 0 对称。我们希望中间区域的面积为 1 - α,那么两侧尾部的总面积就是 α。由于对称性,每个尾部的面积就是 α/2

在标准正态分布中,我们定义 z_{α/2} 为这样一个点:其右侧曲线下的面积恰好为 α/2。根据对称性,左侧对应点为 -z_{α/2}

因此,区间的上限必须满足:
β/(σ/√n) = z_{α/2}

步骤五:求解 β

由此,我们可以解出 β
β = z_{α/2} * (σ / √n)

最终公式与解释

β 代回最初的区间,我们得到了总体均值 μ100(1-α)% 置信区间公式:
CI = [ X̄ - z_{α/2} * (σ/√n), X̄ + z_{α/2} * (σ/√n) ]

核心公式
CI = X̄ ± z_{α/2} * (σ / √n)

这个公式的意义是:我们有大约 100(1-α)% 的置信度认为,真实总体均值 μ 落在这个计算出的区间内。这里的“大约”是因为我们使用了中心极限定理的近似,当样本量 n 足够大时,这个近似是合理的。

实践中面临的问题

虽然我们推导出了漂亮的公式,但在实际应用时立刻会遇到一个障碍:公式依赖于总体标准差 σ,而这个值通常是未知的

在现实的数据科学工作中,我们通常只能接触到样本数据 X₁, X₂, ..., Xₙ,而无法直接知道总体的真实方差 σ²

解决方案与后续方向

作为数据科学家,我们自然的思路是:用数据来估计未知参数。因此,要获得一个完全可计算的置信区间,下一步就是利用我们手头的样本数据来估计 σ 的值。

在接下来的章节中,我们将学习如何从数据中估计 σ。这个过程不仅会解决当前的问题,还将向我们揭示估计理论中一些有趣的新概念。

总结

本节课中我们一起学习了:

  1. 从概率等价出发,通过标准化处理推导置信区间。
  2. 应用中心极限定理,将问题转化为标准正态分布下的概率计算。
  3. 利用正态分布的对称性,通过分位数 z_{α/2} 确定了区间半径 β
  4. 得到了总体均值置信区间的核心公式:X̄ ± z_{α/2} * (σ/√n)
  5. 指出了该公式在实际应用中的主要限制:需要已知总体标准差 σ,并提出了用样本数据估计 σ 的解决方向。

26:点估计 📊

在本节课中,我们将学习点估计的核心概念。点估计是统计学和机器学习中,利用样本数据来估计未知总体参数的关键方法。我们将从一个更宏观的视角来理解这个过程,并探讨几个具体的例子。


总体框架与问题定义

上一节我们讨论了如何计算置信区间,这需要从数据中估计总体方差。本节中,我们将这个问题置于一个更普遍的视角下,即点估计

让我们回顾一下我们一直在讨论的总体框架图。我们面对的是某个现实世界的现象。

这个现象背后关联着一些参数。我们将其中的一个参数称为 θ。我们的核心任务就是去估计这个参数 θ。

到目前为止,我们主要讨论的是以总体均值作为参数 θ 的例子。但 θ 也可以是总体方差,或任何其他描述该现实世界现象的未知参数。这里我们旨在建立一个更通用的视角。

为了估计 θ,我们唯一能接触到的就是这个现象产生的数据。数据采集模块会给我们提供 N 个独立同分布的数据样本:x₁, x₂, ..., xₙ

这些数据随后被输入到数据分析模块。该模块的目标是设计一个估计量,来估计这个潜在的参数 θ。

估计量的设计

具体来说,我们需要设计一个统计量,记作 θ̂(读作“theta hat”)。

这个统计量 θ̂ 以样本数据作为输入,并输出一个对参数 θ 的估计值

这大致构成了我们知识获取的完整框架。在统计学语境下,“获取知识”通常意味着从底层数据中估计某个参数或统计量,或者更广义地说,是从数据中学习某种普遍模式。

现在,我们有了一个更通用的参数 θ,它不再局限于分布的均值。θ 可以是方差,也可以是任何与底层现象相关的参数。作为数据科学家,我们的任务就是设计一个统计量 θ̂,用它来估计 θ 的值。

我们称这样的统计量 θ̂ 为参数 θ 的一个点估计量。这就是点估计的核心含义。

点估计的正式定义

以下是点估计的正式定义:

  • 点估计:参数 θ 的一个点估计,是指可以被视为 θ 合理取值的单个数值

  • 点估计量:点估计是通过选择一个合适的统计量(即我们设计的 θ̂),并根据给定的样本数据计算其值而得到的。这个统计量 θ̂ 被称为 θ 的点估计量


点估计实例

让我们回到之前的框架图,看几个具体的估计问题例子。

实例一:估计总体均值 (μ)

这是我们目前最熟悉的例子。此时,参数 θ 是总体均值

我们假设样本数据 x₁, ..., xₙ 独立同分布地来自某个分布,该分布的均值是未知值 μ。我们的目标就是估计 μ。

因此,参数 θ = μ。我们需要设计一个估计量,记作 μ̂,它以数据为输入,输出对 μ 的估计。

最常用的估计量就是样本均值
μ̂ = (x₁ + x₂ + ... + xₙ) / n

对于这个估计量,我们已经了解很多:我们知道它的行为特性,可以通过中心极限定理来理解,并能构建其置信区间等。这是我们前几节课重点讨论的内容。

实例二:估计总体方差 (σ²)

另一个常见的例子是估计总体方差

同样,数据点 x₁, ..., xₙ 独立同分布地来自某个分布。该分布的均值记为 μ,方差记为 σ²

此时,我们的目标参数 θ 就是方差 σ²。

我们的任务是设计一个估计量,来估计 σ² 的值。一个常用的点估计量是样本方差
σ̂² = Σ (xᵢ - μ̂)² / (n-1)
其中 μ̂ 是样本均值。


总结

本节课中,我们一起学习了点估计的基本概念。我们从计算置信区间所需的方差估计出发,将问题推广到更一般的参数估计框架。我们明确了参数 θ、样本数据、估计量 θ̂ 之间的关系,并给出了点估计的正式定义。最后,我们通过估计总体均值估计总体方差两个经典例子,具体说明了点估计的应用。理解点估计是进行更复杂统计推断和机器学习模型构建的重要基础。

27:方差估计-有偏与无偏(第一部分) 📊

在本节课中,我们将学习如何从数据中估计一个分布的方差,并评估我们设计的估计量是否“好”。我们将从一个非常直观的估计量开始,分析其性质,并探讨它是否有改进的空间。

概述与问题设定

我们的设定如下:我们有 n 个数据点 x1, x2, ..., xn,它们独立同分布地来自某个我们未知的分布。我们只知道该分布的均值记为 μ,方差记为 σ²。作为数据科学家,我们唯一能接触到的信息就是这些数据点 x1xn。换句话说,我们既不知道 μ 的真实值,也不知道 σ² 的真实值。因此,我们需要从数据中近似估计出这些参数。

现在,我们的目标是估计方差 σ²

设计一个直观的估计量

根据定义,方差 σ² 的公式是:
σ² = E[(X - μ)²]
其中 X 是分布中的随机变量,E 表示期望。

让我们尝试设计一个估计量。首先,我们假设一个理想情况:我们知道均值 μ 的真实值

在这种情况下,从数据中估计 σ² 会变得非常简单。因为对于每个数据点 xi,计算 (xi - μ)² 就得到了随机变量 (X - μ)² 的一个样本。要估计 E[(X - μ)²],一个很好的方法就是计算这些样本的均值,即样本平均。

因此,如果 μ 已知,一个好的估计量是:
σ²_hat (μ已知) = (1/n) * Σ (xi - μ)²

这个估计量在期望上等于真实的 σ²,因为每个 (xi - μ)² 的期望就是 E[(X - μ)²]

然而,问题的关键在于,我们并不知道 μ 的真实值。我们只能从数据中估计它。

用样本均值替代真实均值

我们已经知道如何估计均值 μ:一个非常好的方法就是使用样本均值
μ_hat = x̄ = (1/n) * Σ xi

一个很自然的想法是,在我们设计的估计量公式中,用样本均值 来替代未知的真实均值 μ

因此,我们得到了最终的方差估计量:
σ²_bar = (1/n) * Σ (xi - x̄)²

这个估计量完全由数据计算得出:xi 是单个数据点, 是所有数据点的平均值。这是一个非常直观且基于我们已有知识的估计量。

评估估计量:偏差的概念

设计出一个估计量后,作为数据科学家,下一步总是要评估它的好坏。评估估计量性能的第一步,就是检查它是否是无偏的

那么,什么是估计量的偏差呢?

给定一个用于估计参数 θ 的点估计量 θ_hat,其偏差定义为:
Bias(θ_hat) = E[θ_hat] - θ

其中,期望 E[θ_hat] 是对所有可能的数据 x1, ..., xn 的随机性取的。因为数据是随机变量,所以估计量 θ_hat 本身也是一个随机变量。偏差衡量的是估计量期望值与真实参数值之间的差距。

理想情况下,我们希望估计量在平均意义上是准确的。也就是说,平均来看,我们的估计量 θ_hat 应该给出真实值 θ

因此:

  • 如果 Bias(θ_hat) = 0,即 E[θ_hat] = θ,则称估计量 θ_hat无偏的
  • 否则,估计量就是有偏的

直观地理解,我们可以想象估计量 θ_hat 输出值的概率分布。这个分布有一个平均值 E[θ_hat]。如果这个平均值恰好落在真实参数值 θ 上,那么估计量就是无偏的;如果存在一个差距,那么这个差距就是偏差。

本节总结

在本节中,我们一起学习了方差估计的起点。我们从一个理想情况(已知均值)出发,设计了一个直观的方差估计量。接着,面对均值未知的现实,我们用样本均值进行了替代,得到了一个完全基于数据的估计量:σ²_bar = (1/n) * Σ (xi - x̄)²

最后,我们介绍了评估估计量好坏的首要标准——偏差。一个无偏估计量意味着其期望值等于待估参数的真实值。那么,我们刚刚设计的这个方差估计量 σ²_bar 究竟是无偏的还是有偏的呢?这将是下一节我们要深入分析和解答的核心问题。

28:方差估计-有偏与无偏(第二部分)📊

在本节课中,我们将要学习如何判断我们设计的方差估计量是否存在偏差,并探讨如何修正它以得到一个无偏估计量。我们还将看到这个无偏估计量如何应用于构建置信区间。

上一节我们介绍了方差估计的基本概念,本节中我们来看看我们设计的估计量是否是无偏的。

现在检验我们为方差设计的估计量是否存在偏差。我们估计量的期望值,即 1/n * Σ (X_i - X̄)^2 的期望,需要被计算。

期望是线性算子,求和与期望运算可以交换顺序。因此,我们可以将期望展开计算。

以下是计算步骤:

  1. 展开平方项:(X_i - X̄)^2 = X_i^2 + X̄^2 - 2 * X_i * X̄
  2. 将期望代入求和:E[1/n * Σ (X_i^2 + X̄^2 - 2 * X_i * X̄)]
  3. 利用期望的线性性质,得到:1/n * Σ E[X_i^2] + E[X̄^2] - 2 * E[X̄ * (1/n * Σ X_i)]
  4. 注意到 (1/n * Σ X_i) 就是 ,因此最后一项简化为 2 * E[X̄^2]
  5. 最终表达式简化为:E[X_1^2] - E[X̄^2]

接下来,我们需要计算 E[X_1^2]E[X̄^2]。这里会用到方差的一个基本公式。

对于任意随机变量 Y,其方差公式为:Var(Y) = E[Y^2] - (E[Y])^2。我们可以利用这个公式反推 E[Y^2]

以下是具体计算:

  • 对于 X_1Var(X_1) = σ^2 = E[X_1^2] - μ^2,因此 E[X_1^2] = σ^2 + μ^2
  • 对于 Var(X̄) = σ^2 / n,且 E[X̄] = μ。因此 E[X̄^2] = Var(X̄) + (E[X̄])^2 = σ^2 / n + μ^2

将这两个结果代入之前的表达式 E[X_1^2] - E[X̄^2]

计算差值:
E[估计量] = (σ^2 + μ^2) - (σ^2 / n + μ^2) = σ^2 * (1 - 1/n)

由此可见,我们估计量的期望值 E[σ̂^2_bar] 并不等于真实的总体方差 σ^2,而是等于 σ^2 * (1 - 1/n)。因此,我们最初设计的估计量是一个有偏估计量

这个偏差的大小可以计算出来。

偏差定义为估计量的期望与真实参数值之差:Bias = E[σ̂^2_bar] - σ^2
代入我们得到的结果:Bias = σ^2 * (1 - 1/n) - σ^2 = -σ^2 / n
偏差不为零,且为负值,表明我们的估计量平均而言会低估真实的方差。

虽然我们的估计量有偏,但可以通过一个简单的调整使其变为无偏。

我们的目标是消除期望表达式中的因子 (1 - 1/n)。方法是将原来的估计量除以这个因子。

定义新的估计量 σ̂^2
σ̂^2 = (1 / (1 - 1/n)) * (1/n * Σ (X_i - X̄)^2) = 1/(n-1) * Σ (X_i - X̄)^2
这个新的估计量 σ̂^2 的期望值恰好等于 σ^2,因此它是一个无偏估计量

直观上,n-1 的出现是因为我们用样本均值 代替了总体均值 μ 进行估计,这消耗了数据中的一个“自由度”。为了进行无偏估计,我们需要在分母上使用 n-1 而非 n 来进行校正。

现在,我们找到了一个估计方差的好方法。回想之前构建置信区间时,我们需要知道总体标准差 σ

之前,对于总体均值 μ100*(1-α)% 置信区间公式为:
[ X̄ - Z_(α/2) * (σ / √n), X̄ + Z_(α/2) * (σ / √n) ]
当时我们假设 σ 已知。

现在我们有了从数据中估计 σ 的方法。首先用无偏估计量得到方差估计 σ̂^2,然后取其平方根得到标准差的估计 σ̂

因此,完全基于数据可计算的最终置信区间公式为:
[ X̄ - Z_(α/2) * (σ̂ / √n), X̄ + Z_(α/2) * (σ̂ / √n) ]
其中,σ̂ = √( 1/(n-1) * Σ (X_i - X̄)^2 )

本节课中我们一起学习了如何分析方差估计量的偏差,并通过将分母从 n 调整为 n-1 得到了无偏的样本方差公式 S^2 = 1/(n-1) * Σ (X_i - X̄)^2。最后,我们看到了如何将这个无偏估计量应用于构建总体均值的置信区间,从而得到一个完全由样本数据决定的实用统计工具。

29:点估计的两个原则 📊

在本节课中,我们将要学习点估计的两个核心原则:无偏估计原则和最小方差无偏估计原则。我们将理解为什么无偏性是一个好的性质,以及如何在多个无偏估计量中做出选择。

概述

上一节我们介绍了估计量,并指出我们通常更倾向于使用无偏估计量。这是因为无偏性是一个优良性质,它意味着估计量的期望值等于我们试图估计的真实参数值。

本节中,我们将正式探讨点估计的两个主要原则。第一个是无偏估计原则,我们将以更正式的方式阐述它。接着,我们将介绍第二个原则,这个原则在后续学习中非常有用。

无偏估计原则

首先,我们来正式定义无偏估计原则。其基本设定如下:假设我们有从某个分布中独立同分布抽取的样本数据 X1, X2, ..., Xn

利用这些数据,我们设计一个估计量 θ_hat(X1, ..., Xn) 来估计底层参数 θ

由于 X 是随机变量,估计量 θ_hat 本身也是一个随机变量,因此它有自己的概率密度函数。

无偏估计原则告诉我们,我们希望估计量 θ_hat 的期望值(对数据 X 求期望)恰好等于真实参数值 θ。这意味着估计量的偏差应为零。

用公式表示,即:
E[θ_hat] = θ

当我们为参数 θ 在多个不同的估计量中进行选择时,我们通常更偏好那些无偏的估计量。因为平均而言,这些估计是准确的。

最小方差无偏估计原则

接下来,我们介绍第二个原则:最小方差无偏估计原则。

让我们先通过一个直观的例子来理解这个原则。假设我们有三个无偏估计量,它们都用于估计同一个参数 θ。它们的概率密度函数如下图所示。

  • 第一个估计量 θ_hat1 的概率密度函数分布较宽。
  • 第二个估计量 θ_hat2 的概率密度函数分布更集中一些。
  • 第三个估计量 θ_hat3 的概率密度函数分布最为集中。

这三个估计量都是无偏的,因此它们都满足第一个原则。

现在的问题是:在这三个估计量中,你更倾向于选择哪一个?

答案是第三个估计量 θ_hat3。通常,我们会更偏好一个在真实参数值 θ 附近更集中的估计量。

从数量上讲,“更集中”意味着它具有更小的方差。方差的公式是随机变量与其均值(期望)之差的平方的期望值。对于无偏估计量,其均值就是 θ。因此,方差衡量了估计量围绕真实值 θ 的波动程度。

方差越小,估计量在 θ 附近的分布就越集中。

这就是第二个原则:在所有用于估计参数 θ 的无偏估计量中,我们通常更偏好具有最小方差的那个。这样的估计量被称为参数 θ最小方差无偏估计量

请注意,我们是在所有无偏估计量中寻找方差最小的。因为我们希望最小化方差的同时,确保我们的估计量是无偏的,即它们围绕的是正确的值——我们试图估计的底层参数的真实值。

总结

本节课中我们一起学习了点估计的两个核心原则。

  1. 无偏估计原则:一个好的估计量,其期望值应等于待估参数的真实值,即 E[θ_hat] = θ。这保证了估计量在长期平均意义上是准确的。
  2. 最小方差无偏估计原则:在满足无偏性的所有估计量中,我们应选择方差最小的那个。方差 Var(θ_hat) 衡量了估计量的波动性,方差越小,估计结果越稳定、越精确。

理解这两个原则为我们评估和选择统计模型中的估计量提供了基本框架。

00:机器学习基础导论 🧠

在本节课中,我们将要学习机器学习的基本概念、应用领域、课程涵盖的核心主题以及它在当今时代的重要性。

欢迎回到宾夕法尼亚大学与Python结合的人工智能与机器学习专业课程。Victor Preciado教授将为我们讲授机器学习课程。首先,我们从宏观层面来了解什么是机器学习。

机器学习本质上是将“学习”这一概念应用于计算设备的背景下。学习是一个系统通过经验来提升其性能的过程。在机器学习的语境中,系统就是一台计算机器。性能是衡量这些机器所做预测质量的指标。而经验则是通过结构化和非结构化的数据输入到机器中。

上一节我们介绍了机器学习的抽象定义,本节中我们来看看它在现实世界中的具体应用。

机器学习在科学和工业领域有着非常广泛的应用。以下是其主要应用领域:

  • 金融
  • 医疗保健
  • 机器人技术
  • 自然语言处理
  • 自动驾驶汽车

在这些领域中,从头开始构建一个描述解决问题步骤的算法通常非常困难。机器学习所做的,不是一步步构建算法,而是提出一个学习架构,并将数据输入到这个架构中,以便优化算法能够随时间迭代地调整和提升该架构的性能。

了解了应用之后,接下来我们看看在这门课程中学习者将会接触到哪些主题。

课程将从广泛介绍不同类型的机器学习问题开始。一种是监督学习问题,即数据带有标签。例如,你可以向机器输入带有内容标签的图像。另一种是无监督学习问题,即提供没有标签的图像。在这种情况下,机器应该能够根据相似性对图像进行聚类。

在介绍了这两种问题类型后,我们将讨论泛化的概念。即,一台机器如何分类它过去从未见过的图像?例如,如果你给机器看了许多鸟类的例子,它如何识别一只从未见过的鸟,并判断它是一只鸟?此时,我们还将涵盖欠拟合过拟合的主题,探讨架构的合适灵活性。最后,我们将介绍衡量这些机器学习架构性能的方法。

课程内容听起来很丰富,那么学习者将完成哪些类型的作业来配合这些讲座呢?

我们将结合使用Python的实践应用项目和理论问题。通过实践项目,我们希望学生培养应用所教技术处理真实数据的技能。但这并非全部,我们还希望提供理论工具,以理解这些算法在做什么以及它们为何这样做。

在我看来,机器学习现在比以往任何时候都更加重要。你同意吗?

当然。你可以在工业界甚至我们的日常生活中看到这一点,例如GPT的出现。我们正处在一个非常重要的时刻,强大的计算架构(从硅谷产业中CPU和GPU的大规模发展可见一斑)与大数据时代交汇。我们可以获取海量数据并将其输入到这些机器学习架构中。这为机器学习架构的兴起提供了完美的土壤。

确实如此。我认为未来几乎所有的工程师都需要学习机器学习的基础知识。因此,我们邀请你加入宾夕法尼亚大学的专业课程,学习Victor教授的课程,这样你也能掌握机器学习的精髓。

本节课中我们一起学习了机器学习的核心定义、其多样化的应用场景、课程将深入探讨的关键主题(如监督/无监督学习、泛化、过拟合与欠拟合),以及结合实践与理论的学习方法。我们认识到,在强大算力与海量数据汇聚的当下,掌握机器学习基础对未来工程师至关重要。

01:导论与统计学习概述

在本节课中,我们将要学习统计学习的基本概念。统计学习为理解机器学习算法提供了理论基础,并构成了模型拟合、估计、推断和评估等核心概念的框架。

什么是统计学习?

上一节我们介绍了课程的开端,本节中我们来看看统计学习的核心定义。

统计学习是一套从数据中学习的工具集。其核心思想是,我们通常对预测一个输出变量(通常称为响应变量或因变量)感兴趣,这个变量基于一个或多个输入变量(通常称为预测变量或自变量)。输入变量记为 X,输出变量记为 Y。统计学习的目标是找到一个函数 f,使得 Y = f(X) + ε。其中,ε 代表随机误差项,其均值为零,且与 X 独立。函数 f 代表了 X 中关于 Y 的系统性信息。

统计学习的目的

理解了基本定义后,我们来看看我们为何需要统计学习。主要有两个目的:预测推断

以下是两种主要目的的简要说明:

  • 预测:在许多情况下,我们拥有输入变量 X,但输出 Y 不易获得。此时,我们可以将 X 输入到通过历史数据训练好的函数 f 的估计)中,以获得准确的预测 。这里的准确性取决于可约误差和不可约误差。
  • 推断:我们可能希望理解 XY 之间的关系。具体来说,我们想知道哪些输入变量对输出有影响,这种影响是正相关还是负相关,以及这种关系是否可以用线性方程来概括等。此时,我们更关注函数 f 本身的形式,而不仅仅是预测结果。

如何估计函数 f?

既然我们的目标是找到函数 f,那么下一个问题自然是如何从数据中估计它。大多数统计学习方法都可以被归类为参数方法非参数方法

以下是两种主要方法的对比:

  • 参数方法:这种方法包含两个步骤。首先,我们假设函数 f 具有某种特定的参数化形式(例如,一个线性模型:f(X) = β₀ + β₁X₁ + β₂X₂ + ...)。然后,我们使用训练数据来拟合或训练模型,即估计模型中的参数(如 β₀, β₁, β₂ 等)。这种方法简化了估计 f 的问题,变为只需估计一组参数。但如果假设的函数形式与真实的 f 相差甚远,模型的效果会很差。
  • 非参数方法:这种方法不对函数 f 的具体形式做先验假设。相反,它试图让数据本身来决定 f 的形状。这种方法可以拟合出非常复杂的 f,但需要大量的观测数据才能获得准确的估计,并且可能因为过于灵活而导致过拟合

模型精度与过拟合

在估计模型时,我们必须关注其预测新数据的能力,这引出了对模型精度的评估以及一个关键挑战——过拟合。

评估模型精度的一个核心概念是均方误差。对于一组给定的数据点,MSE的计算公式为:
MSE = (1/n) * Σ(y_i - f̂(x_i))²
其中 n 是数据点的数量。然而,我们真正关心的是模型在未见过的测试数据上的 MSE(测试 MSE),而不是在训练数据上的 MSE(训练 MSE)。模型可能通过变得非常复杂来完美拟合训练数据(训练 MSE 很低),但这通常会导致测试 MSE 很高,这种现象就是过拟合。我们的目标是找到一个模型,使测试 MSE 最小化。

总结

本节课中我们一起学习了统计学习的基础。我们首先定义了统计学习是寻找输入变量 X 与输出变量 Y 之间关系函数 f 的框架。我们探讨了学习的两个主要目的:预测和推断。接着,我们介绍了估计 f 的两种主要途径:参数方法和非参数方法。最后,我们讨论了模型评估的核心——均方误差,并指出了追求过低训练误差可能导致过拟合,而我们的终极目标是最小化模型在未知数据上的测试误差。这些概念为理解后续更具体的机器学习算法奠定了坚实的理论基础。

03:统计学习入门 📊

在本节课中,我们将要学习统计学习的基本概念。我们将从一个简单的例子开始,介绍核心术语和理论框架,为后续深入学习机器学习方法奠定基础。

从示例开始

为了理解统计学习,我们来看一个非常简单的例子。假设我们拥有包含200次营销活动的历史数据。对于每次活动,我们记录了在广播、电视和报纸广告上的投入金额,以及最终产生的总销售额。

在这个例子中,我们有一个希望预测的输出变量“销售额”,以及三个用于预测的输入变量:广播、电视和报纸广告投入。换句话说,我们试图回答的问题是:如何利用前述三种渠道的投入金额来预测销售额?

我们期望找到一个函数,能够将销售额近似地表示为这三个参数的函数。在下图中,你可以看到Y轴上的销售额与电视、广播和报纸广告投入之间的关系。例如,在第一张图中,我们可以选择一个特定的投入水平,并查看历史上所有围绕该投入水平的营销活动所产生的平均销售额。

核心术语与符号

上一节我们通过一个例子引出了预测问题,本节中我们来正式定义将要用到的符号和术语。

我们将用大写字母 X 表示输入向量。这是一个包含 X₁Xₚ 的向量,这些是我们将用于进行预测的输入特征。同时,我们将使用小写粗体字母 x 来表示这个输入向量的一个具体取值。这同样是一个p维向量,包含 x₁xₚ 这些条目。

在之前的例子中,我们有三个输入,因此 p(即用于解决预测问题的特征或输入的数量)等于3。具体来说,我们可以设定 X₁ 对应电视投入,X₂ 对应广播投入,X₃ 对应报纸投入。

请注意,大写向量 X 包含的是作为输入的变量,这与具体的数值不同。为了澄清大写 X 和小写 x 的区别,我们可以看一个具体例子。我们可以定义一个包含三个值的小写向量 x

x = [1000, 800, 900]

因此,如果我们说 X = x,这表示 X 的第一个分量(即电视投入)等于1000,意味着在电视上投入了1000个单位;X 的第二个分量(广播投入)等于800;X 的第三个分量等于小写 x 的第三个分量,即900个单位。通过令 X = x,我们实际上是指定了输入向量 X 中所有输入的一个具体取值。

类似地,我们将使用大写字母 Y 表示输出变量,而输出的一个具体值将用小写 y 表示。在之前的例子中,我们的输出变量是销售额,我们将变量 Y 分配给销售额。如果我们说 y = 2500,并且令 Y = y,那么我们实际上是在说销售额等于2500个单位。

理论框架:加法模型

现在,让我们转向研究统计学习问题的适当理论框架。在本课程中,我们将假设 X 是一个随机变量向量,而 Y 是一个标量随机变量。

在统计学习领域,通常假设输出变量是使用所谓的加法模型生成的。该模型的形式如下:

Y = f(X) + ε

这个公式本质上说明,你观察到的实验输出值 y,是输入变量的某个函数值加上一个 ε 值。以下是其中每个元素的解释:

  • f 是一个未知函数,称为回归函数。这个回归函数将是本课程中一个非常重要的组成部分。
  • ε 是我们所称的测量噪声。这是一个随机变量,我们已知其均值为0,方差为 σ²

例如,在我们之前的广告示例中,根据这个模型,我们有:

销售额 = f(广播投入, 电视投入, 报纸投入) + ε

有一个非常重要的点需要注意:这个回归函数 f 对你来说是未知的。这是“自然”用来生成你在实验中观察到的数据的函数。

统计学习问题

上一节我们介绍了数据生成的理论模型,本节中我们来看看统计学习要解决的核心问题。

统计学习问题,如前所述,就是利用历史数据(即从加法模型中抽取的随机样本)来估计这个未知的回归函数 f

本质上,f 是未知的,你只能访问一个数据集,而你真正想要确定的是这个函数 f 是什么——即“自然”用来生成数据的函数。因此,本课程的一个重要部分将是尝试开发各种技术来估计 f

总结

本节课中我们一起学习了统计学习的入门知识。我们从预测销售额的实例出发,定义了输入变量 X、输出变量 Y 以及它们的取值表示。接着,我们介绍了描述数据生成过程的加法模型 Y = f(X) + ε,并明确了回归函数 f 和测量噪声 ε 的概念。最后,我们指出统计学习的核心目标就是利用观测数据来估计这个未知的回归函数 f。理解这些基础概念是后续学习各种具体机器学习算法的关键。

04:回归函数 📈

在本节课程中,我们将学习回归函数的核心理论及其在实际应用中的估计方法。我们将从理论定义出发,探讨其与条件期望的关系,并最终介绍一种基于数据集的实用估计方法。

理论回顾:回归函数与条件期望

上一节我们介绍了回归函数的基本概念。本节中,我们来看看它的数学定义。

从统计学角度可以证明,回归函数等于给定输入 x 时输出 y 的条件期望。其公式如下:

F(x) = E[y | x]

如果我们已知条件概率密度函数 f(y|x),则可以通过积分计算这个期望值:

F(x) = ∫ y * f(y|x) dy

请注意,对 y 积分后,结果将是输入向量 x 的函数。然而在实践中,我们通常无法直接获得这个条件概率密度函数。

优化视角:最小化均方误差

从优化理论的角度,同样可以证明回归函数是以下优化问题的解:

F = argmin_g E[ (y - g(x))^2 ]

这个优化问题在所有可能的函数 g 中寻找一个解,使得 yg(x) 之差的平方的期望值最小。

以下是关于此优化问题的一些关键点:

  • 均方误差:期望项 E[ (y - g(x))^2 ] 被称为均方误差。它衡量了使用函数 g 进行预测时的平均误差大小。
  • 最优解:可以证明,这个优化问题的最优解正是我们之前定义的回归函数 F(x),即条件期望 E[y | x]

实践设定:从数据中估计回归函数

在理论部分,我们了解了回归函数的性质。现在,我们转向实践中估计回归函数的重要细节。

在实际场景中,我们假设无法直接获取条件概率密度,但拥有从以下加性模型生成的样本数据:

y_i = f(x_i) + ε_i

其中 ε_i 是噪声,满足 E[ε] = 0Var(ε) = σ²。函数 f 的形式未知。

我们的问题是:给定一个包含 n 对观测值的数据集 D = { (x_1, y_1), ..., (x_n, y_n) },如何找到一个对真实回归函数 f 的估计,我们将其记为 f_hat

为了直观理解,考虑下图(假设输入 x 为一维标量)。每个数据点 (x_i, y_i) 对应图中的一个散点。我们的目标是从这些散点中估计出潜在的函数关系 f

初始方法:精确匹配的局限

一种直观的想法是利用回归函数是条件期望这一事实,并使用经验均值来近似理论期望。

具体方法是:对于想要预测的特定值 x,找出数据集中所有输入 X_i 恰好等于 x 的点,然后计算这些点对应输出 Y_i 的平均值。公式如下:

f_hat(x) = (1 / |D_x|) * Σ_{i ∈ D_x} y_i
其中 D_x = { i | X_i = x }

然而,这种方法并不实用。原因在于,对于连续取值的 x,在数据集中找到恰好等于某个具体实数值的 X_i 的概率极低。通常,我们可能一个都找不到。

改进方法:基于邻域的估计

为了克服上述限制,我们需要采用另一种方法。其核心思想是放宽“精确等于”的条件,转而考虑“足够接近”的点。

我们不再要求 X_i 精确等于 x,而是考虑那些与 x 的距离小于等于某个半径 r 的点。定义邻域索引集如下:

N_r(x) = { i | ||X_i - x|| ≤ r }

然后,我们计算落在这个邻域内所有数据点的输出平均值,作为对 f(x) 的估计:

f_hat(x) = (1 / |N_r(x)|) * Σ_{i ∈ N_r(x)} y_i

这个过程可以形象地理解为:以 x 为中心,开设一个宽度为 2r 的“窗口”,然后使用窗口内所有数据点的 y 值来计算局部平均值。通过选择合适的半径 r,我们总能找到一些邻近的点来进行估计。

总结

本节课中我们一起学习了回归函数的理论定义及其实际估计方法。

我们首先了解到回归函数在理论上等于条件期望 E[y|x],并且是均方误差最小化问题的解。接着,我们探讨了在实际统计学习问题中,如何利用数据集来估计这个函数。最初的精确匹配法因数据稀疏性而不可行,因此我们引入了基于邻域的估计方法。该方法通过计算目标点附近一个邻域内数据输出的平均值,来近似条件期望,从而实现对回归函数的有效估计。

05:维度灾难 📈

在本节课程中,我们将探讨一个在机器学习中至关重要的概念——维度灾难。我们将从回顾局部平均法开始,逐步理解当数据维度增加时,这种方法为何会失效。

回顾:局部平均法

在上一节中,我们学习了如何使用局部平均法来估计回归函数 f(x)。具体做法是:对于一个给定的输入点 x,我们考虑一个以该点为中心、宽度为 2R 的窗口,然后计算落入该窗口内所有数据点的 y 值的平均值,以此作为 f(x) 的估计值。

这种方法在一维数据(即 p = 1)中效果良好,如下图所示,绿色线代表通过局部平均得到的估计函数。

维度灾难的引入

既然我们已经有了估计 f(x) 的方法,那么问题是否就解决了呢?答案是否定的。这是因为存在一个被称为“维度灾难”的现象。

维度灾难是指,当问题的输入变量数量(即维度 p)远大于1时出现的问题。在我们之前的一维示例中无法体现这一点,但当 p 很大时,数据集中的点往往会彼此远离,导致局部平均法变得不可行。

为了说明维度灾难,我们将考虑不同维度 p 下的场景。

不同维度下的期望点数分析

以下是分析步骤,我们将从一维开始,逐步增加维度。

一维情况 (p = 1)

假设有 n 个点均匀随机分布在区间 S₁ = [-1, 1] 上。我们选取其中一个点 x(用红点表示),并考虑一个以 x 为中心、长度为 2R 的窗口 Dᵣ(x)

由于点是均匀分布的,单位长度上的期望点数为 n / 2。因此,窗口 Dᵣ(x) 内的期望点数 E[N] 为:
E[N] = (n / 2) * (2R) = nR

二维情况 (p = 2)

现在,考虑 n 个点均匀随机分布在半径为1的圆盘 S₂ 内。我们同样选取一个点 x,并考虑一个以 x 为中心、半径为 R 的小圆 Dᵣ(x)

单位面积上的点密度为 n / π。小圆的面积为 πR²。因此,小圆内的期望点数为:
E[N] = (n / π) * (πR²) = nR²

高维情况 (p 为任意值)

我们将概念推广到 p 维空间。考虑一个 p 维超球体 Sₚ,其半径为1,中心在原点。其体积 VₚRᵖ 成正比,即 Vₚ ∝ Rᵖ

Sₚ 内均匀随机分布 n 个点。对于其中任意一点 x,考虑一个以 x 为中心、半径为 R 的小超球体 Dᵣ(x)

大超球体内的点密度为 n / Vₚ(1)。小超球体的体积为 Vₚ(R) ∝ Rᵖ。因此,小超球体内的期望点数为:
E[N] ≈ n * Rᵖ

总结规律:

  • p = 1E[N] = nR
  • p = 2E[N] = nR²
  • p = pE[N] ≈ nRᵖ

模拟实验与结果

为了验证上述理论,我们进行了一个模拟实验。

实验设置如下:

  • p 维单位超球体 Sₚ 内随机生成 n = 1000 个点。
  • 对于球内任意一点 x,计算与其距离小于 R = 0.1 的点的数量。
  • 对维度 p = 1, 2, ..., 5 分别重复上述过程100次,计算经验平均值和标准差。

实验结果如下图所示。红色曲线表示理论预期值 1000 * (0.1)ᵖ,蓝色曲线表示模拟得到的经验平均值。

核心结论:维度灾难的影响

模拟结果的关键发现并非仅仅是理论值与经验值吻合,而是揭示了随着维度 p 的增加,半径为 R 的小超球体内包含的点数会以指数级速度急剧减少。

这意味着,当我们处理输入维度 p 非常高的问题时,以任何点 x 为中心的局部小区域内,数据点的数量将变得极少。在实践中,对于非常大的 p,这个数量几乎为零。

因此,如果我们想在高维空间中使用基于小半径 R 的局部平均法,我们将在局部窗口(即高维超球体)内找不到足够的数据点进行平均,从而导致方法失效。

本节总结

在本节课中,我们一起学习了维度灾难的概念。我们首先回顾了局部平均法,然后通过数学推导和模拟实验证明,随着数据维度的增加,数据点在空间中的分布变得极其稀疏,使得依赖局部邻域的估计方法(如局部平均)需要海量数据才能保持有效性,这在实际应用中构成了巨大挑战。理解维度灾难是学习后续降维技术和选择合适机器学习模型的重要基础。

06:参数化模型 📊

在本节课中,我们将学习如何通过参数化模型来应对高维诅咒,并介绍几种常见的参数化模型,如线性模型和多项式模型。

概述

上一节我们讨论了高维诅咒。简而言之,当问题中的输入维度很高时,高维诅咒使我们无法在目标点 x 周围进行局部平均来估计回归函数 F(x)。从数学描述上看,随着维度 P 的增加,任何球体内的样本数量会呈指数级减少。因此,对于大多数现实世界的高维问题,我们将没有足够的样本来进行局部平均。在这种情况下,我们需要寻找替代方法来克服高维诅咒。

参数化模型简介

本节中,我们将探讨一种特定的方法:使用参数化模型。在参数化模型中,我们使用一个函数 F_hat(x) 来近似回归函数 F(x)。这个函数包含一些自由参数 θ(一个参数向量),我们需要从数据中学习这些参数。

一个经典的参数化模型例子是线性模型。在线性模型中,我们有一个函数 F_L,它以 x 为参数,并包含一组参数 ββ 扮演了上述 θ 的角色)。这个函数的形状等于一个常数加上第一个特征乘以一个常数,再加上第二个特征乘以另一个常数,依此类推,直到我们处理完输入向量中的所有 P 个特征。

记住,我们的输入向量有 P 个维度:x1xP。因此,上述方程中的 Xi 不是样本,而是输入向量 x 的分量。

参数估计

一旦我们有了一个参数化模型(例如上述的线性模型),我们就可以利用数据集 D 中的观测值来估计参数 β。我们将从数据中获得的估计参数记为 β_i_hat。因此,我们可以使用估计的线性模型(记为 F_L_hat)来近似回归函数。F_LF_L_hat 之间的唯一区别在于,参数 β0βP 被替换为从数据中获得的 β0_hatβP_hat

这个模型之所以不受高维诅咒影响,主要原因在于,为了估计参数 β_i,我们需要利用整个数据集 D,而不仅仅是围绕点 x、半径为 r 的小球内的少量样本。

其他参数化模型

除了线性模型,我们还有多种参数化模型可供选择。

以下是几种常见的参数化模型:

  • 线性模型:你可能已经熟悉的模型。
  • 多项式模型:我们将在课程中介绍。
  • 回归树:我们将在课程中介绍。
  • 支持向量机:另一种强大的模型。

例如,对于 P = 1,我们可以简单地使用下面的表达式构建一个多项式模型。在这个模型中,我们有一个常数 α0,加上另一个常数乘以输入 x,再加上另一个常数乘以输入 x 的平方,依此类推,直到达到输入的 d 次幂。实际上,我们得到的是一个对数据的多项式拟合。

在下面的图表中,我展示了使用之前见过的点云进行的多项式拟合。我们可以看到:

  • d = 2 时,我们本质上拟合了一个穿过点云的抛物线形状。
  • d = 3 时,我们拟合了一个三次函数,它能更好地穿过点云的中心,这似乎是近似真实回归函数的一个良好候选。
  • d = 20 时,我们会得到一个非常波动的函数,它虽然大致穿过点云中心,但会在这些点周围剧烈摆动,这是一种称为过拟合的不良效应。

总结

本节课中,我们一起学习了如何利用参数化模型来克服高维诅咒。我们介绍了参数化模型的基本概念,即使用带参数的函数 F_hat(x; θ) 来近似回归函数。我们重点探讨了线性模型和多项式模型作为例子,并解释了如何从数据中估计模型参数。最后,我们简要列举了其他类型的参数化模型,并通过图示说明了多项式模型中阶数选择的重要性,高阶模型可能导致过拟合。参数化模型通过利用整个数据集进行全局学习,有效避免了高维空间下样本稀疏的问题。

07:模型质量评估 📊

在本节课程中,我们将学习如何评估机器学习模型的质量。核心在于理解训练误差与测试误差的区别,以及如何利用它们来选择一个“恰到好处”的模型,避免模型过于简单或过于复杂。

概述

评估模型质量是机器学习流程中的关键步骤。我们将区分两种类型的数据:训练数据集测试数据集。通过计算这两种数据集上的误差,我们可以判断模型在“见过”的数据和“未见”的数据上的表现,从而选择泛化能力最佳的模型。

训练误差与测试误差

上一节我们介绍了参数模型的概念。本节中,我们来看看如何量化模型的预测表现。

在解决实际的机器学习问题时,我们需要区分两种类型的数据。

一方面,我们有训练数据集,记作 D_TR。这个数据集包含 n 个训练点,用于估计我们所考虑的参数模型 的未知参数 θ

一旦我们训练好模型的参数,训练均方误差 定义如下。具体来说,训练过程的均方误差根据以下公式定义:

MSE_train = (1/n) * Σ_{i=1}^{n} (y_i - f̂(x_i))^2

本质上,我们有 n 个点,因此用因子 1/n 进行归一化。然后,我们对训练数据集中的所有点对 (x_i, y_i) 进行求和,求和项是模型预测值 f̂(x_i) 与实际输出值 y_i 之间的误差的平方。我们计算这些平方误差的经验平均值,称之为均方误差。

另一方面,我们还有测试数据集,记作 D_T。在这种情况下,我们有 m 个测试点,这些数据是你的学习算法在训练期间未曾见过的。我们可以使用这些数据,通过所谓的测试均方误差来估计模型在未来预测中的性能。

因此,测试均方误差 由以下表达式定义:

MSE_test = (1/m) * Σ_{j=1}^{m} (y_j - f̂(x_j))^2

这里,由于有 m 个测试点,我们用因子 1/m 进行归一化。求和遍历测试数据集中的所有点,括号内的表达式与之前相同,本质上是给定输入 x 后,实际输出值与预测输出值之间的误差平方。求和与归一化后,即得到测试数据集的均方误差。

在实践中,测试均方误差能更好地反映我们模型的性能。

训练与测试误差的对比

理解了两种误差的定义后,我们通过一个具体例子来观察它们的差异。

在本幻灯片中,我们说明了训练均方误差和测试均方误差之间的区别。具体来说,我们将考虑两幅不同的点云图。左侧的点云代表训练数据集,而右侧的点云代表测试数据集。这两幅图中的点云都来自相同的加性模型,我们假设这两幅图中每个样本 (x_i, y_i) 都来自相同的联合概率密度函数。

在底部的图表中,我们计算了从1次到8次多项式的训练和测试均方误差。

在此图表中,我们用蓝色线条绘制了训练均方误差随多项式次数增加的变化。我们可以观察到,这个函数随着次数的增加而单调递减。这是训练均方误差的一个普遍特征,其原因在于,随着多项式次数的增加,我们能够越来越好地拟合给定的训练集。

在同一图表中,我们用红色线条绘制了测试均方误差随多项式次数增加的变化。我们观察到,在这个特定案例中,该函数并非单调递减,而是在次数 d = 3 时呈现出一个最小值。这表明,在本实验所考虑的多项式函数层次结构中,三次多项式可能是最佳选择。

模型复杂度与误差的关系

通过多项式回归的例子,我们看到了测试误差存在最小值。现在,我们将这个概念推广到更一般的模型复杂度(或称“灵活性”)上。

关于训练和测试均方误差,我们有以下几点评论。下方有一个概念图,描述了训练和测试均方误差随模型层次结构灵活性变化的演变。

在下面的灰色图表中,我们绘制了训练均方误差随模型灵活性变化的曲线。这里的灵活性是多项式次数的一般化,本质上是衡量一个函数跟随数据集中点集的能力的指标。

在同一图中,我们也用红色绘制了测试均方误差。正如我们之前所见,测试均方误差并非单调递减,而是在某个特定的灵活性值处呈现最小值。由于测试均方误差是衡量我们模型未来预测性能的指标,这个精确的灵活性水平正是我们应该选择来训练模型的水平。

具体来说:

  • 当灵活性水平低于最优水平时,参数模型 不够灵活,无法准确地学习回归函数 f。这可能是图中这两个点所代表的情况。
  • 相反,当灵活性高于最优水平时,模型 过于灵活,并开始拟合我们训练数据中的噪声。这本质上是我们在几页前看到的20次多项式例子中观察到的“抖动”现象。这对应于曲线此部分的绿色方块所代表的情况。
  • 最后,蓝色方块代表了在最优灵活性水平(即测试均方误差最小化时)的训练和测试均方误差值。

再次强调,这个最优灵活性水平是我们应该用来训练模型的水平。

总结

本节课中,我们一起学习了评估模型质量的核心方法。我们明确了训练误差MSE_train)和测试误差MSE_test)的定义与区别。关键在于,训练误差会随着模型复杂度(灵活性)增加而持续降低,但测试误差会先降后升,形成一个“U”形曲线。测试误差的最低点对应着模型复杂度的最优选择,此时模型既能捕捉数据中的真实规律,又不会过度拟合噪声。选择这个最优复杂度,是构建泛化能力强的机器学习模型的关键。

08:偏差-方差权衡 📊

在本节课程中,我们将学习一个核心的理论框架,用以解释测试均方误差的形状。我们将从数据生成模型开始,逐步推导出测试误差的分解,并最终理解模型复杂度(灵活性)如何影响偏差和方差,以及它们之间的权衡关系。


数据生成模型

我们从一个训练数据集 D_TR 开始,它包含 n 个数据点。这些点是根据以下加性模型随机均匀抽取生成的:

y_i = f(x_i) + ε_i

其中:

  • x_i 是从边际分布 p(x) 中均匀抽取的。
  • f(x) 是未知的回归函数,自然界使用它来生成数据。
  • ε_i 是测量误差,服从概率密度函数 p_ε,通常假设其均值为0,方差为 σ²

我们的目标是估计这个未知的回归函数 f


模型训练与参数估计

为了估计 f,我们选择一个参数化函数 f̂_θ,其中 θ 是参数向量。我们的任务是找到最优参数值 θ̂,以最小化训练均方误差:

θ = argmin_θ (1/n) Σ_{i=1}^n (y_i - f̂_θ(x_i))²*

这个表达式就是训练MSE。我们通过最小化它来得到最优参数 θ。将 θ 代入 f̂_θ,我们就得到了训练好的模型 f̂_{θ*}


测试误差的理论分析

现在,我们使用这个训练好的模型来分析其测试误差。考虑一个从未用于训练过程的新数据点 (x₀, y₀),它同样从上述加性模型中抽取。

测试均方误差可以理论上写为以下期望值:

Test MSE = E[(y₀ - f̂_{θ*}(x₀))²]

由于 x₀ 是随机变量,f̂_{θ*}(x₀) 也是随机变量,因此我们需要用期望来得到一个确定的测试误差值。


测试误差的分解

利用统计工具,可以证明上述测试MSE可以分解为三个项:

Test MSE = Bias² + Variance + Irreducible Error

以下是偏差项和方差项的具体表达式:

  • 偏差平方 (Bias²)
    Bias² = [E[f̂_{θ*}(x₀)] - f(x₀)]²
    它衡量了模型预测值的期望与真实回归函数值之间的差异。偏差高意味着模型系统性地偏离了真实关系。

  • 方差 (Variance)
    Variance = E[(f̂_{θ}(x₀) - E[f̂_{θ}(x₀)])²]
    它衡量了模型预测值围绕其自身期望的波动程度。方差高意味着模型对训练数据中的随机噪声非常敏感。

  • 不可约误差 (Irreducible Error)
    σ²
    这是数据中固有噪声的方差。即使我们知道了真实的 f(x),这个误差也无法消除。

前两项(偏差平方和方差)之和被称为可约误差,因为通过选择合适的模型 ,我们可以减少这部分误差。最后一项(不可约误差)是无论如何都无法消除的。


模型复杂度的影响

一个关键的观察是:可约误差中的两项都依赖于我们用于训练的参数化模型的灵活性(复杂度)。

  • 偏差 随着模型灵活性的增加而单调下降。更灵活的模型能更好地拟合数据的潜在结构。
  • 方差 随着模型灵活性的增加而单调上升。过于灵活的模型会过度拟合训练数据中的噪声。

下图展示了这种关系:

  • 蓝色曲线代表偏差²,随灵活性增加而下降。
  • 橙色曲线代表方差,随灵活性增加而上升。
  • 虚线代表不可约误差 σ²,是常数。
  • 红色曲线是前三项之和,即总测试误差。它呈现出一个凸函数形状,并在一个最优的灵活性水平(图中箭头处)达到最小值。这体现了偏差-方差权衡。

多项式拟合示例

我们可以通过不同次数的多项式拟合来直观展示这种权衡。以下是使用1次、3次和20次多项式,在10组独立生成的数据点云上进行拟合的结果。

以下是不同复杂度模型的拟合效果对比:

  • 1次多项式(左图):所有线性拟合线彼此非常接近。这表明模型非常“僵硬”,无法随数据点的变化而改变。结果是方差低,但偏差高(拟合线无法捕捉数据的真实曲线趋势)。
  • 3次多项式(中图):拟合效果良好,能很好地捕捉数据点云中间的趋势。这表明三次多项式的灵活性水平是“恰到好处”的,其偏差和方差都相对较低
  • 20次多项式(右图):拟合线在数据点周围剧烈摆动。这表明模型过于灵活,过度拟合了每一个数据点(包括噪声)。结果是偏差低,但方差极高


总结

在本节课中,我们一起学习了统计学习理论中一些非常重要的主题。

我们首先定义了回归函数,并了解了维数灾难的概念。接着,我们探讨了参数化模型的使用,以及评估模型不确定性的方法。最后,我们深入研究了偏差-方差权衡这一核心概念。

理解偏差-方差权衡对于机器学习实践至关重要。它告诉我们,在模型选择时,不能一味追求在训练集上的完美拟合(低偏差),而需要找到一个平衡点,使模型既能够捕捉数据规律,又不会对噪声过度敏感,从而在未知数据(测试集)上获得最佳性能。

02:线性回归导论 🧮

在本节课中,我们将要学习线性回归。线性回归是机器学习中的一个基础概念,它既是一种基本的预测建模技术,也是构建更复杂算法的基石。

概述

本周,我们将介绍线性回归。我相信很多人对它已经有所了解。线性回归在机器学习中用于基于多个输入特征预测连续输出的任务。其简单性和可解释性使其成为金融、经济和医疗保健等多个应用领域的首选方法。

线性回归简介

上一节我们概述了本周的学习内容,本节中我们来看看线性回归的具体定义。

线性回归是机器学习中的一个基础概念。它既是一种基本的预测建模技术,也是构建更复杂算法的基石。

在机器学习中,线性回归用于基于多个输入特征预测连续输出的任务。其简单性和可解释性使其成为金融、经济和医疗保健等多个应用领域的首选方法。

核心概念

以下是线性回归的核心组成部分,我们将逐一进行解释。

  • 模型公式:线性回归模型试图通过一个线性方程来拟合输入特征(X)与输出目标(y)之间的关系。其基本公式为:
    y = β₀ + β₁X₁ + β₂X₂ + ... + βₙXₙ + ε
    其中,y是预测值,β₀是截距,β₁βₙ是特征系数,X₁Xₙ是输入特征,ε是误差项。
  • 目标:目标是找到一组系数(β值),使得模型预测值与实际观测值y之间的差异(通常使用均方误差)最小化。
  • 应用场景:适用于预测房价、销售额、股票趋势等连续数值问题。

总结

本节课中我们一起学习了线性回归的导论。我们了解到线性回归是一种用于预测连续值的基础机器学习算法,其模型简单且易于解释,是许多实际应用和高级算法的起点。

10:线性代数回顾 🧮

在本节中,我们将回顾线性代数中的几个核心概念,为后续学习线性回归打下基础。我们将介绍矩阵、矩阵转置、矩阵乘法以及单位矩阵。

矩阵基础

矩阵是一个由数字排列成的矩形阵列。一个具有 m 行和 n 列的矩阵可以表示为:

A = [a_ij]

其中,i 表示行索引(从1到m),j 表示列索引(从1到n),a_ij 是矩阵中第 i 行、第 j 列的元素。

例如,一个3行4列的矩阵可以表示为:

A = [
    [a_11, a_12, a_13, a_14],
    [a_21, a_22, a_23, a_24],
    [a_31, a_32, a_33, a_34]
]

我们可以使用下标来索引矩阵中的元素。例如,a_13 表示第一行第三列的元素。

矩阵转置

矩阵的转置是一个基本操作,用上标 T 表示(例如 A^T)。转置操作将矩阵的行转换为列。

具体来说,如果矩阵 Am 行和 n 列,那么其转置矩阵 A^T 将有 n 行和 m 列。原矩阵的第 i 行会变成转置矩阵的第 i 列。

用公式表示,转置矩阵的元素定义为:

(A^T)_ij = A_ji

转置操作具有以下性质:

  • (AT)T = A:对矩阵转置两次,得到原矩阵。
  • (AB)^T = B^T A^T:两个矩阵乘积的转置,等于各自转置后交换顺序的乘积。
  • (A + B)^T = A^T + B^T:矩阵和的转置,等于转置的和。

矩阵乘法

理解了矩阵和转置后,我们来看矩阵乘法。矩阵乘法不是简单的元素对应相乘。

给定两个矩阵 A(m × n)和 B(n × p),它们的乘积 C = AB 是一个 m × p 的矩阵。

矩阵 C 中第 i 行、第 j 列的元素 c_ij 计算公式如下:

c_ij = Σ (a_ik * b_kj),其中 k 从 1 求和到 n

简单来说,c_ij 是矩阵 A 的第 i 行与矩阵 B 的第 j 列对应元素乘积之和。

矩阵乘法遵循以下规则:

  • 结合律(AB)C = A(BC)。矩阵相乘的顺序不变,但括号可以改变结合方式。
  • 分配律A(B + C) = AB + AC。矩阵乘法对矩阵加法满足分配律。
  • 不满足交换律AB ≠ BA。这是矩阵乘法的一个重要特性,顺序至关重要。

单位矩阵

最后,我们介绍单位矩阵。一个 n × n 的单位矩阵记作 I_n,它是一个方阵。

其定义是:主对角线上的所有元素都是 1,其余所有元素都是 0

例如,3×3的单位矩阵是:

I_3 = [
    [1, 0, 0],
    [0, 1, 0],
    [0, 0, 1]
]

单位矩阵在矩阵乘法中的作用类似于数字 1 在普通乘法中的作用。对于任何 m × n 的矩阵 A,都有:

A I_n = I_m A = A


本节课中,我们一起回顾了线性代数的核心基础:矩阵的定义与索引、矩阵的转置操作及其性质、矩阵乘法的规则(特别是其不满足交换律的特性),以及单位矩阵的定义和作用。掌握这些概念对于理解后续的机器学习算法至关重要。

11:特征值与特征向量 📐

在本节课中,我们将学习线性代数中的几个核心概念,包括向量的表示、内积与外积,并最终引入机器学习中至关重要的特征值与特征向量概念。

向量代数基础

首先,我们介绍向量的基本表示。一个向量通常用小写粗体字母表示,例如 x。它包含实数元素,本质上是 R^n 空间中的一个元素。按照惯例,一个 n 维向量 x 是一个 n 行 1 列的矩阵,即一个列向量。

我们可以使用下标 x_i 来索引向量 x 中的元素。注意,在表示元素时,我们移除了粗体。

接下来,我们看看向量之间的运算。以下是两种主要的向量乘积。

内积

内积是两个同维度向量 xy 之间的运算,其结果是一个标量。我们使用 <x, y> 的符号来表示内积。

根据定义,内积等于 x^T y。由于 x 是列向量,x^T 是一个行向量。y 是列向量。这个矩阵乘法的维度是 (1×n) 乘以 (n×1),结果是一个 1×1 的矩阵,即一个实数。

其显式计算公式为:
<x, y> = x^T y = Σ_{i=1}^{n} x_i * y_i

内积满足交换律,即 <x, y> = <y, x>

外积

外积是另一种向量乘积。两个同维度向量 xy 的外积定义为 x y^T。注意,转置符号在 y 上。

x 是 (n×1) 的列向量,y^T 是 (1×n) 的行向量。因此,外积的结果是一个 (n×n) 的矩阵。

该矩阵的第 (i, j) 个元素为:
(x y^T)_{ij} = x_i * y_j

矩阵与向量的乘积

对于一个 (m×n) 的矩阵 A 和一个 n 维向量 x,我们可以定义乘积 A x。矩阵 A 的维度是 (m×n),向量 x 的维度是 (n×1),内维匹配,因此结果是 (m×1) 的向量 y

结果向量 y 的第 i 个元素由以下公式给出:
y_i = Σ_{j=1}^{n} A_{ij} * x_j

特征值与特征向量 🎯

上一节我们介绍了向量和矩阵的基本运算,本节中我们来看看线性代数中一个核心且强大的概念:特征值与特征向量。

这些概念与方阵(即行数和列数相等的矩阵)相关。考虑一个 (n×n) 的方阵 M

我们说一个 n 维的列向量 v(其元素可以是复数)是矩阵 M 的一个特征向量,如果存在一个复数 λ(称为特征值),使得以下方程成立:
M v = λ v

这个方程被称为特征方程。如果我们能找到满足该方程的 λv,那么 λ 就是特征值,v 就是对应的特征向量。

对于一个 (n×n) 的方阵,通常存在 n 组可能的特征值和特征向量解。

对称矩阵的特殊性质

对于一类特殊的矩阵——对称矩阵(满足条件 M = M^T),其性质更加优良:

  1. 所有特征值 λ 都是实数
  2. 所有特征向量 v 都是 n 维的实向量
  3. 任意两个不同特征向量之间的内积为零,即它们是相互垂直(正交)的。这可以表示为:
    <v_i, v_j> = 0 (当 i ≠ j 时)

总结

本节课中,我们一起学习了线性代数的关键基础。我们从向量的表示和两种乘积(内积与外积)开始,然后深入探讨了矩阵与向量的乘法。最后,我们引入了机器学习中至关重要的特征值与特征向量概念,并了解了对称矩阵在此背景下所具有的优良数学性质(实数特征值、正交特征向量)。理解这些概念是掌握后续更复杂机器学习算法(如主成分分析PCA)的基石。

12:线性回归 📈

在本节课中,我们将要学习线性回归。这是一种用于建模输入变量与输出变量之间线性关系的基础方法。我们将从定义模型开始,逐步介绍如何从数据中估计模型参数,并最终利用模型进行预测。

模型定义

线性回归基于一个加性模型。根据该模型,输出变量 y 由输入向量 x 和一组参数 β 的线性组合,加上测量噪声 ε 生成。

公式
y = β₀ + β₁x₁ + β₂x₂ + ... + βₚxₚ + ε

其中:

  • x = [x₁, x₂, ..., xₚ]ᵀ 是一个包含 p 个输入变量的随机向量。
  • β = [β₀, β₁, ..., βₚ]ᵀ 是决定性的、但未知的系数。
  • ε 是测量噪声。

输入向量 x 服从边际分布 fₓ(x),噪声 ε 服从分布 f_ε(ε)。通过这个加性模型,我们可以推导出联合分布 f(x, y)。

问题陈述

在上一节我们定义了模型,本节中我们来看看如何从数据中学习它。

我们拥有一个包含 n 个样本的训练数据集,每个样本是一个输入-输出对 (Xᵢ, yᵢ)。我们假设这些样本是独立地从上述联合分布 f(x, y) 中抽取的。

我们的目标是估计未知系数 β。我们将用 β̂(读作“beta hat”)来表示基于数据得到的估计值。一旦我们获得了估计值 β̂,就可以对新的输入 x 预测其对应的输出 ŷ

预测公式
ŷ = β̂₀ + β̂₁x₁ + β̂₂x₂ + ... + β̂ₚxₚ

参数估计:最小二乘法

为了从训练数据中找到最优的系数估计 β̂,我们需要解决一个优化问题。核心思想是找到一组参数,使得模型的预测值与真实观测值之间的差距最小。

这个差距通过残差平方和来衡量。以下是计算RSS的步骤:

  1. 对于第 i 个数据点,计算其残差(预测误差):eᵢ = yᵢ - (θ₀ + θ₁xᵢ₁ + ... + θₚxᵢₚ)。这里的 θ 代表我们正在尝试的一组通用参数。
  2. 将所有数据点的残差平方后求和,得到RSS。

优化目标
β̂ = argmin_θ RSS(θ) = argmin_θ Σᵢ (yᵢ - (θ₀ + θ₁xᵢ₁ + ... + θₚxᵢₚ))²

使用矩阵和向量表示法,可以更简洁地表达这个问题。定义设计矩阵 X(包含所有输入数据,并添加一列1以对应截距项 β₀)和输出向量 y,则RSS可以写为:

公式
RSS(θ) = || y - Xθ ||²

其中,||·|| 表示向量的 L2 范数(长度)。这个推导基于一个事实:一个向量长度的平方等于其各分量平方之和。

解析解

利用优化工具,我们可以为上述最小二乘问题找到一个解析解(闭合形式解)。

公式
β̂ = (XᵀX)⁻¹ Xᵀ y

矩阵 (XᵀX)⁻¹ Xᵀ 被称为 X伪逆。这个公式直接给出了最优参数估计 β̂

一元线性回归示例

现在,让我们看一个最简单的特例:一元线性回归,即只有一个输入变量 (p=1)。模型简化为:

公式
y = β₀ + β₁x + ε

此时,参数估计 β̂₀(截距)和 β̂₁(斜率)有更简单的计算公式:

公式
β̂₁ = Σᵢ (xᵢ - x̄)(yᵢ - ȳ) / Σᵢ (xᵢ - x̄)²
β̂₀ = ȳ - β̂₁ x̄

其中,ȳ 分别是输入和输出数据的样本均值。

下图展示了一个一元线性回归的实例:

  • 灰色直线代表真实的回归线(由自然使用的 β₀ 和 β₁ 生成)。
  • 蓝色直线是我们根据数据估计出的回归线(使用 β̂₀ 和 β̂₁)。
  • 数据点散落在直线周围,体现了噪声 ε 的影响。
  • 红色的垂直线段代表了每个数据点的残差(eᵢ)。RSS正是所有这些红色线段长度的平方和。

总结

本节课中我们一起学习了线性回归的核心内容。我们首先介绍了加性模型,明确了输入、输出、参数和噪声的关系。接着,我们定义了从数据中估计参数的问题,并引入了最小二乘法作为解决方案,其目标是最小化残差平方和。我们看到了该问题的矩阵表示及其解析解——伪逆公式。最后,通过一元线性回归的例子,我们直观地理解了截距、斜率、残差以及估计线与真实线之间的关系。线性回归是机器学习中最基础且重要的模型,为理解更复杂的方法奠定了基础。

13:系数不确定性 📊

在本节课中,我们将学习线性回归模型中系数估计的统计特性。我们将探讨为什么估计出的系数是随机变量,如何计算它们的期望和方差,并通过一个数值示例来直观理解这些概念。


上一节我们介绍了线性回归模型的基本形式。本节中,我们来看看模型系数的估计值所具有的不确定性。

我们假设观测到的数据集由以下形式的加性线性模型生成:
Y = M_x * β + ε
这是一个紧凑的模型表示形式。其中,我们有 p 维的数据点,其输出向量 Y 可以写成设计矩阵 M_x 与系数向量 β 的乘积,再加上一个测量噪声向量 ε。向量 ε 包含随机变量 ε_1, ε_2, ..., ε_n,每个 ε_i 都服从特定的分布。

在之前的课程中我们看到,可以使用以下表达式从数据集中估计线性系数 β_hat
β_hat = (M_x^T * M_x)^{-1} * M_x^T * y
这里,输出值被堆叠成向量 y,输入向量被堆叠成矩阵 M_x

一个非常重要的点是,数据点 X_iY_i 是随机的。因此,系数 β_hat 本身也是随机变量。你可以通过观察 β_hat 的表达式来理解这一点:因为 M_x 包含随机点 X,向量 y 包含随机值 Y_i,所以这个表达式的结果是一个随机向量。

既然 β_hat 是随机变量,我们就可以研究它们的期望和方差。具体来说,可以分析其均值。可以证明,β_hat_i 的期望值恰好等于它试图估计的真实值 β_i。当这种情况发生时,我们说这个估计量是无偏的

我们还可以分析向量 β_hat 的协方差矩阵。假设给定了数据矩阵 M_x,其协方差矩阵可以写成底部表达式所示的形式:
Cov(β_hat | M_x) = σ² * (M_x^T * M_x)^{-1}
本质上,这里的 M_x 是编译了所有输入向量的矩阵,而 σ² 是测量噪声的方差。


在接下来的内容中,我们将展示如何为 p = 1(即只有一个输入变量)的情况显式计算协方差矩阵的各个元素。

假设我们只有一个输入,线性回归模型采用以下形式:
Y = β_0 + β_1 * X + ε
本质上,我们只有一个估计的截距 β_0_hat 和一个估计的斜率 β_1_hat。请注意,协方差矩阵的对角线元素正是这些估计系数的方差。

为了理解这一点,请记住,如果我们看协方差矩阵的 (i, j) 元素,它等于 E[(X_i - μ_i)(X_j - μ_j)]。这个矩阵的对角线元素对应 i = j 的情况,因此该项变成了 (X_i - μ_i)² 的期望,而这正是随机变量 X_i 的方差的定义。

利用这个事实,我们可以计算给定数据集下 β_1_hatβ_0_hat 的方差。这些方差的形式如下列表达式所示:
Var(β_1_hat) = σ² / Σ_{i=1}^{n} (x_i - x̄)²
Var(β_0_hat) = σ² * [1/n + x̄² / Σ_{i=1}^{n} (x_i - x̄)²]
正如你所注意到的,它们依赖于输入数据点的值以及测量噪声的方差。在本课程中,我们将用 SD 表示随机变量的标准差,因此上述方差可以写成每个估计系数标准差的平方。


为了说明估计量 β_1_hat 的统计特性,让我们考虑以下数值示例。

在这个例子中,我们考虑一个不现实但具有说明性的情况。具体来说,我们考虑训练数据集的1000个独立实现,其中 k 从1到1000。请注意,在实践中这并不典型,通常我们只有一个数据集实现,但为了说明,我们假设这个不现实的场景。我们还假设每个数据集包含 n = 100 个样本。

具体来说,我们考虑从1到100的输入输出对 (x_i^(k), y_i^(k)),其中上标 (k) 代表我们考虑的第 k 个特定训练数据集。

现在,对于每个训练数据集,我们将计算相应的估计值 β_0_hat^(k)β_1_hat^(k),其中上标 k 同样从1到1000,代表训练数据集的不同实现。

执行这些计算后,我们展示了1000个 β_1_hat 实现值(对应1000个不同的 k)的直方图。请注意,直方图以0.5为中心,这是我们预期的理论值,因为真实的 β_1 = 0.5。同时,该分布曲线的标准差极接近理论标准差0.05。从直方图可以清楚地看出,β_1_hat 的分布近似遵循高斯分布。


本节课中我们一起学习了线性回归系数估计的不确定性。我们了解到,由于数据是随机的,估计出的系数 β_hat 也是随机变量。我们证明了普通最小二乘估计量是无偏的,并推导了其协方差矩阵的表达式。通过一个单输入变量的特例,我们具体计算了斜率和截距估计值的方差。最后,通过一个数值模拟示例,我们直观地观察到了估计系数的抽样分布,验证了其围绕真实值波动且近似正态分布的特性。理解这种不确定性对于评估模型估计的可靠性至关重要。

14:置信区间 📊

在本节课中,我们将要学习如何为线性回归模型的参数构建置信区间。我们将从回顾参数估计量的分布特性开始,逐步推导出置信区间的计算公式,并讨论其背后的假设与注意事项。

上一节我们介绍了参数估计量 beta1_hat 的抽样分布特性。本节中我们来看看如何利用这种分布特性来构建一个区间,使我们能以一定的概率确信真实的参数值位于该区间内。

参数估计量的分布回顾

通过绘制 beta1_hat 在1000个不同数据集上的1000个不同实现值的直方图,我们得到了一个接近正态分布的图形,其中心位于真实值 beta1 附近。

理论上可以证明,beta1_hat 的概率密度函数近似服从正态分布。我们知道 beta1_hat 的期望值等于真实的 beta1,因此我们知道这个钟形曲线的中心。同时,我们也有给定数据下 beta1_hat 方差的表达式。

从正态分布到置信区间

尽管我们永远无法精确获知自然界用于生成观测数据的真实 beta1 值,但我们可以基于数据按照以下步骤构建置信区间。

一个关键的观察是:对于一个均值为 mu、方差为 sigma^2 的正态分布,其95%的概率质量位于区间 mu ± 2*sigma 内。换句话说,如果我们观察正态分布曲线下 mu - 2*sigmamu + 2*sigma 之间的面积,该面积等于0.95,表明随机变量有95%的概率会落在这个区间段内。

将这一事实应用于我们的随机变量 beta1_hat,我们可以说 beta1_hat 有95%的概率位于区间 beta1 ± 2*sigma_{beta1_hat} 内。我们可以用以下不等式序列来重写这个事件:
beta1 - 2*sigma_{beta1_hat} <= beta1_hat <= beta1 + 2*sigma_{beta1_hat}

通过一个简单的代数变换,我们可以将上述不等式改写为以下形式:
beta1_hat - 2*sigma_{beta1_hat} <= beta1 <= beta1_hat + 2*sigma_{beta1_hat}

构建置信区间

现在,我们将这个不等式序列以概率区间的形式重新表述。我们得到以下结论:beta1 位于区间 [beta1_hat - 2*sigma_{beta1_hat}, beta1_hat + 2*sigma_{beta1_hat}] 内的概率是95%。

这个表达式告诉我们,有95%的概率,自然界用于生成数据的真实参数值 beta1 位于这个给定的区间内。重要的是,我们可以使用训练数据集来计算 beta1_hat 及其标准差的估计值。

以下是计算 beta1_hat 及其标准差的关键公式:

  • beta1_hat 的计算公式:beta1_hat = sum((x_i - x_mean)*(y_i - y_mean)) / sum((x_i - x_mean)^2)
  • beta1_hat 的方差公式:Var(beta1_hat) = sigma^2 / sum((x_i - x_mean)^2)

将计算出的 beta1_hat 值和 sigma_{beta1_hat} 代入上述区间表达式,我们就能得到一个明确的数值区间。我们以95%的置信度认为,真实的 beta1 位于该区间内。这就是 beta1 的95%置信区间。

扩展到截距项

我们可以使用完全相同的逻辑来计算截距项 beta0 的置信区间。

以下是计算 beta0 置信区间的步骤:

  1. 使用 beta0_hat 的均值和方差表达式。
  2. 得出结论:beta0 有95%的概率位于区间 beta0_hat ± 2*sigma_{beta0_hat} 内。

重要假设与警告

在应用上述结论之前,必须牢记我们为得出这些结论所做的假设。

以下是构建置信区间所依赖的关键假设:

  1. 正态性假设:我们假设 beta1_hat 服从正态分布。这仅在特定情况下近似成立。对于某些问题,这一假设可能不适用,需要特别注意。
  2. 噪声方差已知:我们假设我们知道测量噪声的方差 sigma^2。在实践中,这通常不成立。不过,我们将在后续课程中看到估计 sigma^2 的实用方法。

本节课中我们一起学习了如何为线性回归模型的斜率 beta1 和截距 beta0 构建95%置信区间。我们回顾了估计量的正态分布特性,利用正态分布的性质推导出区间公式,并强调了该方法所依赖的正态性和已知噪声方差这两个关键假设。理解置信区间有助于我们量化参数估计的不确定性。

15:假设检验 📊

在本节课中,我们将要学习假设检验这一核心统计概念。假设检验为我们提供了一种系统性的方法,用于判断数据中的模式是否具有统计显著性,还是仅仅由随机性导致。我们将从一个简单的线性模型例子出发,理解其背后的逻辑和步骤。

动机与问题设定

上一节我们介绍了线性模型。本节中我们来看看如何判断模型中的某个输入变量是否真的对输出有影响。

假设我们有一个从线性模型生成的数据集 D,其中 p = 1。模型的输出可以表示为:
y = β₀ + β₁ * x₁ + ε
其中,ε 是测量噪声。

观察这个模型生成的数据,我们想要判断输入变量 x₁ 是否真的影响输出变量 y

x₁ 不影响 y 时,模型中的 β₁ * x₁ 项会消失。换句话说,我们可以通过设置 β₁ = 0 来数学化地描述这种情形。此时,输出 y 将简化为一个常数加上测量噪声。

为什么不能直接检查估计值?

为了判断 x₁ 是否影响输出,一个诱人的想法是直接估计 β₁ 的值(记作 β̂₁),然后检查它是否等于 0

然而,这不是一个好方法,原因如下:当真实的 β₁ = 0 时,我们知道估计量 β̂₁ 是一个以 0 为中心的正态分布。因此,β̂₁ 恰好等于 0 的概率将是 0

为了理解这一点,可以想象一个用于描述人群体重的正态分布。例如,男性体重的分布可能以 80 公斤为中心。如果我们问“随机抽取的个体体重恰好等于 82.371817... 公斤的概率是多少?”,这个事件的概率是 0,因为连续随机变量取任意一个特定精确值的概率为零。但是,我们可以问“体重在 78 到 79 公斤之间的概率是多少?”,这个概率是分布曲线下对应区间的面积,是一个正数。

原假设与备择假设

基于上述问题,我们提出以下两个假设:

  • 原假设 (H₀)x₁y 之间没有关系。即 β₁ = 0
  • 备择假设 (Hₐ)x₁y 之间存在某种关系。即 β₁ ≠ 0

为了分析这些假设,我们需要研究随机变量 β̂₁ 的统计性质。

利用置信区间进行检验

假设原假设 H₀ 为真,即 β₁ = 0。在这种情况下,我们知道随机变量 β̂₁ 服从一个以 0 为中心、标准差为 σ_{β̂₁} 的正态分布。

因此,有 95% 的概率,β̂₁ 会落在以下置信区间内:
0 ± 2 * σ_{β̂₁}

这意味着,如果 β̂₁ 的观测值没有落在这个置信区间内,我们就有了强有力的统计证据来拒绝原假设。这是因为,如果原假设为真,β̂₁ 落在此区间外的概率只有 5%,这是一个很小的概率。因此,当原假设为真时,β̂₁ 落在置信区间外的情况不太可能发生。

等效的 t 统计量检验

除了使用置信区间,我们还可以进行等效但形式不同的检验。第一种方法是构造一个随机变量 t₁
t₁ = β̂₁ / σ_{β̂₁}

当原假设 H₀ 为真时,这个随机变量服从一个以 0 为中心、标准差为 1 的标准正态分布。

因此,我们有 95% 的概率,变量 t₁ 会落在置信区间 0 ± 2 * 1 内,也就是区间 [-2, 2] 内。这等价于 |t₁| ≤ 2

换句话说,如果 |t₁| > 2,意味着 t₁ 的观测值落在了标准正态分布的尾部,那么我们就有强有力的统计证据认为原假设 H₀ 不太可能为真。这与之前基于置信区间的结论完全一致。

数值模拟验证

为了验证我们的理论,考虑以下数值示例:我们设定一个 p = 1 的线性模型,其中输入 x₁ 不影响输出,即真实参数 β₁ = 0。我们假设输入 x₁ 服从正态分布,测量噪声的方差为 1

我们可以使用上述模型生成 1000 个不同的数据集,并为每个数据集计算 t₁ 的值。

下图展示了这 1000 次实现中 t₁ 值的分布直方图。可以观察到,它近似服从一个以 0 为中心、方差为 1 的正态分布,这与我们之前的论断一致。因此,如果计算出的 t₁ 值不在 [-2, 2] 范围内,我们就有强有力的统计证据拒绝 β₁ = 0 的原假设。从直方图中可以看到,t₁ 值落在此区间外的情况很少,尽管偶尔也会发生。

总结

本节课中我们一起学习了假设检验的基本思想。我们从判断线性模型中变量是否显著的问题出发,引入了原假设 (H₀)备择假设 (Hₐ) 的概念。我们了解到,不能通过简单地检查参数估计值是否为零来做判断,而应考察其在原假设下的分布。我们学习了两种等效的检验方法:一是检查参数估计值 β̂₁ 是否落在以零为中心的置信区间内;二是计算标准化的 t 统计量,并检查其绝对值是否超过临界值(如 2)。如果统计量落在预期分布的小概率区域(如两端的 5%),我们就有证据拒绝原假设,认为变量可能是显著的。

16:第3周-导论

概述

在本节课中,我们将要学习线性回归的扩展内容。我们将重点介绍如何在回归模型中纳入分类输入变量、非线性效应以及交互项。这些技术能帮助我们构建更精确的模型,以更好地捕捉现实世界数据的复杂性。

课程内容

本周课程将继续讲解线性回归。

具体而言,课程将展示如何在回归模型中纳入分类输入变量。

同时,课程也会涵盖非线性效应和交互项。

诸如决策树、随机森林和神经网络等机器学习算法,凭借其固有的灵活性和对变量间复杂交互关系进行建模的能力,在捕捉非线性关系方面表现出色。

因此,通过恰当地处理分类输入变量并将非线性效应纳入建模过程,机器学习模型能够更好地捕捉真实世界数据的细微之处,从而得到更准确的预测结果。

接下来,让我们深入探讨这个主题。

总结

本节课中,我们一起学习了线性回归模型的扩展应用。我们了解到,通过引入分类变量、非线性效应和交互项,可以显著提升模型对复杂数据模式的拟合能力。这些概念是连接传统线性回归与更强大的机器学习算法(如决策树和神经网络)的重要桥梁,为后续学习更复杂的模型奠定了基础。

17:分类输入 📊

在本节课中,我们将要学习如何将线性模型扩展到处理分类输入变量。我们将回顾线性模型的基础,并学习如何将性别等定性变量纳入回归分析。

概述 📋

在之前的章节中,我们研究了形式为 y = β₀ + β₁x₁ + ... + βₚxₚ + ε 的线性模型。我们假设输入变量 x₁, ..., xₚ 是定量的,即它们取实数值。然而,在实际应用中,我们经常遇到性别、婚姻状况等定性变量,也称为分类变量。本节将介绍如何扩展线性模型以处理这类输入。

上一节我们介绍了线性模型参数估计与假设检验的基础,本节中我们来看看如何处理分类变量。

线性模型回顾 🔄

我们研究的线性模型形式如下:

y = β₀ + β₁x₁ + β₂x₂ + ... + βₚxₚ + ε

其中:

  • y 是输出变量。
  • β₀ 是截距(常数项)。
  • x₁, ..., xₚp 个输入变量。
  • β₁, ..., βₚ 是每个输入变量对应的权重(参数)。
  • ε 是测量噪声,服从某个分布 f_ε

我们从一个未知的总体分布 F_X 中随机抽取输入向量 X,然后根据上述模型生成对应的输出 Y,从而形成一个包含 n 个观测值的数据集 D = {(Xᵢ, Yᵢ)}

模型的真实参数 β₀, ..., βₚ 对我们来说是未知的。我们只能使用数据集 D 来估计这些参数,得到估计值 β̂₀, ..., β̂ₚ。这些估计值是随机变量,通常围绕真实参数值呈高斯分布。

为了量化估计的不确定性,我们使用置信区间。例如,参数 βᵢ 的95%置信区间为:

[β̂ᵢ - 2 × SE(β̂ᵢ), β̂ᵢ + 2 × SE(β̂ᵢ)]

其中 SE(β̂ᵢ) 是估计值 β̂ᵢ 的标准误差(即标准差)。我们可以声称,真实参数 βᵢ 有95%的概率落在这个区间内。

此外,我们使用假设检验来判断某个输入变量 xᵢ 是否对输出 y 有显著影响。原假设 H₀ 通常为 βᵢ = 0,意味着该变量无影响。我们计算 t 统计量

t = β̂ᵢ / SE(β̂ᵢ)

如果 |t| ≥ 2,我们就有足够的统计证据在95%置信水平下拒绝原假设,认为该变量有显著影响。

引入分类变量 👥

在实践中,输入变量可能是定性的(分类变量)。例如:

  • 性别:男性或女性。
  • 婚姻状况:单身、已婚等。
  • 种族:白种人、非裔、亚裔等。

为了在线性模型中纳入这类变量,我们需要对其进行编码。下面以分析性别对信用卡余额的影响为例进行说明。

在这个例子中,我们只考虑性别这一个输入变量(p = 1)。

  • 输出变量 Yᵢ:个体 i 的信用卡余额。
  • 输入变量 Xᵢ:个体 i 的性别(分类变量)。

我们需要将分类变量“性别”转换为模型可以处理的数值形式。

以下是处理分类变量的标准步骤:

第一步:创建虚拟变量
我们创建一个新的数值变量 x 来编码性别信息。

  • 如果个体 i 是女性,则令 xᵢ = 1
  • 如果个体 i 是男性,则令 xᵢ = 0

这样,分类信息就被转换成了0或1的数值。

第二步:建立模型
将编码后的变量 x 代入线性模型:

y = β₀ + β₁x + ε

现在,我们可以分析这个模型:

  • x = 1(女性)时,模型为:y = β₀ + β₁ + ε
  • x = 0(男性)时,模型为:y = β₀ + ε

通过比较可以看出,参数 β₁ 量化了性别为女性时,对信用卡余额的额外影响(增量或减量)。β₀ 则代表了男性(基准组)的平均余额水平。

实例分析:性别与信用卡余额 💳

我们使用一个真实的信用卡数据集来拟合上述模型,并得到参数估计。

以下是回归分析的结果摘要表(部分):

变量 系数估计 (Coefficient) 标准误差 (Std. Error) t 统计量 (t-statistic)
截距 β̂₀ = 509.80 33.13 15.39
性别[x=1] β̂₁ = 19.73 46.05 0.43

结果解读:

  1. 截距 β̂₀ = 509.80:这表示在模型中,当 x=0(即男性)时,预测的信用卡平均余额约为509.80美元。
  2. 性别系数 β̂₁ = 19.73:这表示女性(x=1)的平均信用卡余额预计比男性高约19.73美元。女性的预测余额为 β̂₀ + β̂₁ = 509.80 + 19.73 = 529.53 美元。
  3. 标准误差:衡量了系数估计的波动性。
  4. t 统计量:用于假设检验。

假设检验:性别是否有显著影响?❓

现在,我们检验性别是否对信用卡余额有显著影响。

  • 原假设 H₀β₁ = 0(性别无影响)。
  • 备择假设 H₁β₁ ≠ 0(性别有影响)。

检验统计量就是上表中的 t = β̂₁ / SE(β̂₁) = 0.43

决策规则:在95%置信水平下,如果 |t| ≥ 2,则拒绝原假设。

由于 |0.43| < 2,我们无法拒绝原假设 H₀

结论:基于当前数据,我们没有足够的统计证据表明性别对信用卡余额有显著影响。也就是说,观测到的男女之间19.73美元的余额差异,很可能只是由随机波动引起的,而非系统性差异。

需要注意的是,假设检验的结果是“无法拒绝原假设”,而非“证明原假设为真”。我们只能说数据没有提供支持“性别有影响”这一结论的强有力证据。

总结 🎯

本节课中我们一起学习了如何在线性回归模型中处理分类输入变量。

  1. 核心方法:通过创建虚拟变量(如0和1)将分类变量转化为数值形式。
  2. 模型解释:在 y = β₀ + β₁x + ε 模型中,β₀ 代表基准组(x=0)的平均输出,β₁ 代表另一组(x=1)相对于基准组的平均差异。
  3. 统计推断:我们同样可以使用置信区间假设检验(基于t统计量)来分析分类变量影响的显著性和不确定性。
  4. 实例结论:在信用卡余额的例子中,分析显示性别的影响在统计上不显著。

这为我们分析包含定性因素(如用户类型、地区、产品类别)的现实世界数据提供了强大的工具。在接下来的课程中,我们将探讨更复杂的模型扩展。

18:处理多类别分类输入 📊

在本节课中,我们将学习如何处理具有两个以上类别的分类变量作为线性模型的输入。我们将以“种族”为例,探讨如何将其编码并纳入模型,以分析其对信用卡余额的影响。


概述

上一节我们介绍了如何处理一个具有两个水平(例如,男/女)的分类变量。本节中,我们来看看当分类变量具有三个或更多水平时,应如何构建线性模型。我们将以种族(简化分为非裔美国人、亚裔、白种人)为例,演示完整的建模与分析步骤。


构建模型的具体步骤

以下是处理多类别分类变量的标准流程。

步骤一:选择基线类别

首先,我们需要从所有类别中选择一个作为基线参照组。在本例中,我们选择“非裔美国人”作为基线。你可以选择集合中的任何标签作为基线,选择不同基线会影响模型系数的解释,但不会改变模型的整体预测。

步骤二:定义虚拟变量

对于一个具有 K 个类别的分类变量,我们需要创建 K-1虚拟变量。本例中有三个类别,因此需要创建两个虚拟变量。

我们为每个个体 i 定义两个虚拟变量:

  • X_i1:表示个体 i 是否为亚裔。
  • X_i2:表示个体 i 是否为白种人。

其赋值规则如下:

  • 如果个体 i 是亚裔,则 X_i1 = 1,否则 X_i1 = 0
  • 如果个体 i 是白种人,则 X_i2 = 1,否则 X_i2 = 0
  • 如果个体 i 是非裔美国人(基线),则 X_i1 = 0X_i2 = 0

步骤三:建立线性模型

引入虚拟变量后,我们可以建立以下线性模型:

Balance_i = β_0 + β_1 * X_i1 + β_2 * X_i2 + ε_i

其中:

  • Balance_i 是个体 i 的信用卡余额。
  • β_0 是截距。
  • β_1β_2 是模型参数,分别衡量亚裔和白种人相对于基线(非裔美国人)对余额的平均影响。
  • ε_i 是随机误差项。

这个模型会根据个体 i 的种族分化为三种情况:

  1. 如果个体 i 是亚裔 (X_i1=1, X_i2=0):Balance_i = β_0 + β_1 + ε_i
  2. 如果个体 i 是白种人 (X_i1=0, X_i2=1):Balance_i = β_0 + β_2 + ε_i
  3. 如果个体 i 是非裔美国人 (X_i1=0, X_i2=0):Balance_i = β_0 + ε_i

这里,β_0 代表了基线类别(非裔美国人)的平均信用卡余额估计值。


模型估计与假设检验

使用真实数据集对模型进行拟合后,我们可以得到参数估计值,并评估其统计显著性。

参数估计结果

以下是模型拟合后可能得到的输出表格示例:

系数 估计值 标准误 t 统计量
截距 (β_0) β̂_0 SE(β̂_0) t_0 = β̂_0 / SE(β̂_0)
亚裔 (β_1) β̂_1 SE(β̂_1) t_1 = β̂_1 / SE(β̂_1)
白种人 (β_2) β̂_2 SE(β̂_2) t_2 = β̂_2 / SE(β̂_2)
  • 估计值:参数 β 的点估计。
  • 标准误:衡量估计值的不确定性。
  • t 统计量:用于检验系数是否显著不等于零。

进行假设检验

我们可以针对每个系数提出研究问题,并通过假设检验来寻找答案。例如,要检验“身为亚裔是否对信用卡余额有影响”,可以设立以下假设:

  • 原假设 H₀: β_1 = 0 (身为亚裔对信用卡余额无影响)
  • 备择假设 H₁: β_1 ≠ 0 (身为亚裔对信用卡余额有影响)

决策规则:通常,如果 t 统计量的绝对值大于 2(近似对应 5% 的显著性水平),我们就有足够的证据拒绝原假设,认为该效应是统计显著的。

结果解读

  • 如果 |t_1| ≤ 2,如上例所示,则我们不能拒绝原假设。这意味着没有强有力的统计证据表明身为亚裔会对信用卡余额产生显著影响
  • 同理,如果 |t_2| ≤ 2,我们也不能拒绝 β_2 = 0 的原假设。即,没有强有力的统计证据表明身为白种人会对信用卡余额产生显著影响

总结

本节课中我们一起学习了如何处理具有多个水平的分类变量。核心步骤包括:选择基线类别创建虚拟变量将其纳入线性模型,以及通过假设检验解读系数的统计显著性。我们了解到,当某个类别对应的 t 统计量绝对值较小时,意味着该类别与基线组之间的差异在统计上并不显著。这种方法使我们能够系统性地评估多个分类属性对连续结果变量的影响。

19:非线性效应 📈

在本节课程中,我们将学习如何利用线性回归的框架来处理输入与输出之间的非线性关系。我们将通过一个具体的车辆数据集示例,展示如何通过引入输入变量的高次幂来拟合多项式模型,从而捕捉数据中的非线性效应。


在上一节中,我们介绍了如何扩展线性回归以处理分类变量。本节中,我们来看看如何使用相同的数学工具来考虑非线性效应。

为了说明这种方法,我们将考虑一个具体的例子。假设我们有一个包含392辆车辆的数据集。对于每辆车,我们将马力(horsepower) 作为输入,每加仑英里数(miles per gallon) 作为输出。换句话说,我们的数据集是成对的(每加仑英里数, 马力)。

输入马力与输出每加仑英里数之间的关系绘制在下图中。本质上,我们有一个散点图,其中每辆车由一个灰点表示。这些点的坐标是车辆的马力和对应的每加仑英里数。因此,在这个散点图中有392个灰点。

在同一图中,我们展示了三条不同的拟合曲线。橙色曲线是标准线性回归在该数据集上的结果。浅蓝色曲线是使用二次多项式(即二次拟合)进行回归的结果。绿色曲线是使用五次多项式进行回归的结果。

通常,我们可以使用与线性回归完全相同的数学工具来找到这些多项式拟合的系数。具体来说,我们将通过定义由输入变量的不同幂次构成的人工输入来扩展输入空间。

特别地,我们假设输出每加仑英里数(MPG) 满足以下关系:
MPG = β₀ + β₁ * HP + β₂ * HP² + ... + βₖ * HPᵏ
这个表达式定义了输入变量HP(马力) 和输出变量MPG(每加仑英里数) 之间的多项式关系。

我们可以使用与寻找线性回归系数完全相同的方法来找到系数 β₀ 到 βₖ。具体来说,我们可以将 HP 视为我们的第一个变量,HP² 视为第二个变量,以此类推,直到 HPᵏ 视为第k个变量。然后,我们定义一个包含这些新变量的输入向量 x
x = [HP, HP², ..., HPᵏ]
一旦定义了这个输入向量,对于第 i 辆车,Yᵢ 是其每加仑英里数,Xᵢ 则包含新定义的变量(即马力的各次幂)。

在之前的图中,我们观察到当 k=2(即二次拟合)时,对数据的拟合效果最好。在下表中,我们查看从这个二次拟合中获得的数值系数。

以下是二次拟合的系数结果:

  • β₀_hat(截距):56.9001
  • β₁_hat(HP的系数):-0.4662
  • β₂_hat(HP²的系数):0.0012

这些系数对应的标准误差和T统计量如下:

  • β₀_hat:标准误差为1.8004,T统计量为31.6。
  • β₁_hat:标准误差为0.0311,T统计量为-15.0。
  • β₂_hat:标准误差为0.0001,T统计量为10.1。

注意,这些T统计量的绝对值都远大于2。因此,我们没有强有力的统计证据声称某些输入变量不重要。换句话说,马力平方(Horsepower²) 是一个可靠的输入变量。


在本节课中,我们一起学习了如何将线性回归框架扩展用于拟合非线性关系。核心方法是引入原始输入变量的高次幂作为新的特征,从而将问题转化为一个更高维度的线性回归问题。我们通过车辆马力与油耗的例子,具体演示了二次多项式拟合的过程,并解读了其系数的统计显著性。这种方法为我们提供了一种强大而灵活的工具,用以建模数据中复杂的非线性模式。

20:交互项

在本节课程中,我们将学习一种在回归模型中引入非线性效应的方法:交互项。我们将探讨如何通过创建新的人工变量来捕捉两个或多个预测变量之间的协同效应,并理解其在模型中的意义。

上一节我们介绍了处理非线性关系的基本方法。本节中,我们来看看如何通过引入交互项来建模变量之间的相互作用。

交互项的概念与应用

我们回到之前见过的一个数据集,其中分析了200个不同的营销活动。对于每个活动,我们将输出变量销售额视为电视广告和广播广告的函数。在这个模型中,我们只考虑两个输入变量。

注意:这个模型假设电视广告和广播广告的效果是彼此独立的。然而,在实际情况中,广播广告可能会提高电视广告的效果。

在统计学中,变量之间的这种协同效应被称为交互作用。我们可以通过创建新的人工变量来分析和建模这种效应,如下方公式所示。

核心模型公式
销售额 = β₀ + β₁ * TV + β₂ * Radio + β₃ * (TV * Radio)

在这个特定模型中,除了原始变量TV和Radio,我们还添加了一个人工变量,它考虑了电视广告和广播广告投入的乘积

事实证明,使用我们之前介绍的线性回归工具,我们可以从数据中估计出 β₁、β₂ 和 β₃ 的值。本质上,TV被视为第一个输入变量,Radio是第二个,而 TV * Radio 被视为第三个输入变量。我们暂时忽略这第三个变量是TV和Radio乘积构成的人工变量这一事实。

利用这种抽象,我们可以执行线性拟合。具体来说,对于每个营销活动:

  • 输出变量 y_i 是该活动产生的销售额。
  • 输入向量 X_i 是一个 p=3 维的向量,包含三个特征:电视广告投入、广播广告投入以及这两个值的乘积。

模型结果解读

在下表中,我们可以找到线性回归得到的系数。

以下是回归系数表:

  • 第一列:估计的系数值 β_hat
  • 第二列:系数的标准误差。
  • 第三列:t统计量。

注意,所有t统计量的绝对值都大于2。因此,所有被视为输入的项都与输出相关。换句话说,任何假设这三个输入中有一个不相关的检验都会被拒绝。

通俗地讲,这告诉我们广播广告和电视广告之间的交互作用是一个重要因素。

使用交互项的注意事项:层级原则

在使用交互项时,有一个重要原则需要牢记,即层级原则

层级原则告诉我们:如果模型中包含了一个交互项(例如 TV * Radio),那么即使t统计量显示这些项不显著,我们也应该同时包含构成该交互项的主效应项(即TV和Radio)。

例如,在我们之前看到的表中,每当交互项 TV * Radio 是重要的,其主效应项TV和Radio也必须包含在模型中,即使它们的t统计量小于2。这个原则的原因是,如果没有主效应项,交互项将难以解释。

定性与定量变量的交互

现在,我们来看一个包含定性变量定量变量之间交互作用的案例。

考虑一个预测个人信用卡余额的问题,输入变量包括一个定量变量(如收入)和一个定性变量(如是否是学生)。变量“学生”有两个水平(是/否),变量“收入”是一个实数。

1. 无交互项的模型

我们可以建立一个不考虑交互作用的模型,将收入和“学生”状态作为两个独立变量。在这种情况下,模型如下:

核心模型公式
余额_i = β₀ + β₁ * 收入_i + β₂ * 学生_i

其中,如果个体i是学生,则 学生_i = 1,否则为0。

这个模型会 bifurcate(分叉)成两种情况:

  • 当个体是学生时(学生_i = 1),模型为:余额 = (β₀ + β₂) + β₁ * 收入
  • 当个体不是学生时(学生_i = 0),模型为:余额 = β₀ + β₁ * 收入

我们可以绘制这两条回归线。注意,这两条线的斜率完全相同(都是β₁),但截距不同。这告诉你,如果你是学生,你的回归函数会在非学生的基础上增加一个值β₂,但这两条线是平行的。

2. 包含交互项的模型

现在考虑包含交互项的模型。在这种情况下,个体i的余额计算如下:

核心模型公式
余额_i = β₀ + β₁ * 收入_i + β₂ * 学生_i + β₃ * (收入_i * 学生_i)

同样,这个模型也分为两种情况:

  • 如果个体i是学生(学生_i = 1),模型简化为:余额 = (β₀ + β₂) + (β₁ + β₃) * 收入
  • 如果个体i不是学生(学生_i = 0),模型简化为:余额 = β₀ + β₁ * 收入

与之前一样,我们可以比较这些模型的斜率和截距。特别地,截距会改变,而且在这个案例中,斜率也会改变。不仅截距增加了β₂,斜率也改变了β₃。

在下图中,我们看到学生和非学生的回归线不仅截距不同斜率也不同

总结

本节课中,我们一起学习了交互项在回归分析中的应用。我们了解到:

  1. 交互项可以捕捉预测变量之间的协同效应,为模型引入非线性。
  2. 通过将变量的乘积作为新特征加入,可以使用线性回归工具进行拟合和解释。
  3. 必须遵循层级原则:当模型中包含交互项时,应同时包含其对应的主效应项。
  4. 交互项不仅适用于两个定量变量之间,也适用于定性与定量变量之间,这允许不同组别的回归线拥有不同的斜率和截距。

至此,我们完成了线性回归主题的学习。下周,我们将开始一个全新的主题:分类

21:线性回归讲解-第一部分 📊

在本节课中,我们将要学习线性回归的基础知识。我们将使用两个数据集(大学数据和波士顿数据),通过Python实践线性回归模型的构建、评估和解读。课程将涵盖从数据导入、模型拟合到结果分析的完整流程。


数据准备与导入 📥

首先,我们需要导入必要的Python库并加载数据集。

以下是本教程所需的库:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import statsmodels.api as sm
import statsmodels.formula.api as smf
from sklearn.linear_model import LinearRegression

现在,我们将大学数据集作为Pandas数据框导入,并重命名列以便于处理。

data = pd.read_csv('college.csv')
data.columns = ['new_name1', 'new_name2', ...]  # 根据实际列名重命名
data.head()

在数据集中,每一行代表一所大学,每一列代表一个特征。在Python中,第一个索引是0。


数据预处理 🔧

上一节我们导入了原始数据,本节中我们将对数据进行预处理,添加一个新列。

我们将添加一个名为“接受率”的新列,它是“录取人数”与“申请人数”的比值。

data['accept_rate'] = data['accept'] / data['apps']

使用Statsmodels进行线性回归 📈

现在,我们开始使用普通最小二乘法构建线性回归模型。首先介绍使用statsmodels库的两种方法。

以下是使用smf.ols方法进行拟合的步骤:

model_smf = smf.ols('grad_rate ~ top25perc', data=data)
fit0 = model_smf.fit()
print(fit0.summary())

在结果摘要中,我们需要关注几个关键统计量:

  • R-squared值:衡量模型拟合优度,本例中为0.2028。
  • 系数估计值
    • 截距 β0_hat = 42
    • 斜率 β1_hat = 0.41
  • 标准误差、t值、P值和95%置信区间:例如,斜率β1的95%置信区间为[0.36, 0.46]。


使用Statsmodels API的另一种方法

除了公式接口,statsmodels还提供了直接的API接口进行线性回归。

以下是使用sm.OLS方法的步骤。注意,使用此方法时需要手动为自变量添加常数项以包含截距。

X = sm.add_constant(data['top25perc'])  # 添加常数项
y = data['grad_rate']
model_sm = sm.OLS(y, X)
fit1 = model_sm.fit()
print(fit1.summary())

此方法得到的结果与第一种方法完全相同。


使用Scikit-learn进行线性回归 🤖

除了statsmodels,我们还可以使用scikit-learn库来构建线性回归模型。

以下是使用scikit-learn的步骤:

X_sk = data[['top25perc']]  # 注意双括号,以保持DataFrame结构
y_sk = data['grad_rate']
model_sk = LinearRegression(fit_intercept=True)
fit2 = model_sk.fit(X_sk, y_sk)

# 获取系数
print(f"截距 (β0_hat): {fit2.intercept_}")
print(f"斜率 (β1_hat): {fit2.coef_[0]}")

所有方法得到的系数估计值都是一致的。斜率β1_hat = 0.41的含义是:自变量top25perc每增加1%,因变量grad_rate平均增加0.41%。


模型可视化与诊断 👁️

上一节我们拟合了模型,本节中我们通过绘图来直观展示拟合效果并进行诊断。

首先,我们绘制原始数据散点图和拟合的回归线。

plt.scatter(data['top25perc'], data['grad_rate'], color='red', label='原始数据')
plt.plot(data['top25perc'], fit0.fittedvalues, color='blue', label='拟合直线')
plt.xlabel('top25perc')
plt.ylabel('grad_rate')
plt.legend()
plt.show()

其次,我们可以使用Q-Q图来检查残差是否服从正态分布,这是线性回归的重要假设之一。

import statsmodels.api as sm
sm.qqplot(fit0.resid, line='s')
plt.show()

此外,绘制残差图可以检查模型是否存在异方差等问题。

plt.scatter(fit0.fittedvalues, fit0.resid)
plt.axhline(y=0, color='red', linestyle='--')
plt.xlabel('拟合值')
plt.ylabel('残差')
plt.show()

关键统计量计算 🧮

基于模型结果,我们可以计算几个关键的统计量来评估模型性能。

以下是这些统计量的定义和计算公式:

  • 残差平方和RSS = Σ(y_i - ŷ_i)²
  • 残差标准误RSE = sqrt(RSS / (n - p - 1)),其中n是样本数,p是自变量个数(本例中p=1)。
  • 总平方和TSS = Σ(y_i - ȳ)²
  • R-squaredR² = (TSS - RSS) / TSS

我们可以手动编程计算这些值:

RSS = np.sum((y - fit0.fittedvalues) ** 2)
n = len(y)
RSE = np.sqrt(RSS / (n - 2))  # p=1, 所以自由度是 n-2
TSS = np.sum((y - np.mean(y)) ** 2)
R_squared_manual = (TSS - RSS) / TSS

当然,我们也可以直接从拟合结果中获取R-squared值:fit0.rsquared。RSE是测量误差标准差σ的估计值,对于计算置信区间至关重要。


假设检验与P值 🧪

在统计学中,我们通过假设检验来判断自变量是否对因变量有显著影响。

我们建立以下假设:

  • 零假设 H₀:自变量与因变量无关,即 β1 = 0
  • 备择假设 H₁:自变量与因变量有关,即 β1 ≠ 0

我们使用P值来做出统计决策。通常将显著性水平设为0.05。

  • 如果 P值 < 0.05,则在95%的置信水平下拒绝零假设,认为自变量显著。
  • 如果 P值 ≥ 0.05,则无法拒绝零假设,认为自变量不显著。

在本例的摘要表中,top25perc对应的P值远小于0.05,因此我们拒绝零假设,得出结论:top25percgrad_rate之间存在显著的统计关系。


预测与置信区间 🔮

线性回归模型不仅可以给出点预测,还可以给出预测值的置信区间,以量化预测的不确定性。

对于一个给定的自变量值x_new,其点预测为:
ŷ_new = β0_hat + β1_hat * x_new

例如,当top25perc = 50时:

x_new = 50
y_pred = fit0.params['Intercept'] + fit0.params['top25perc'] * x_new

该点的预测值约为60%。我们还可以构建该预测值的95%置信区间:
预测区间 = ŷ_new ± 2 * RSE

我们可以编程计算:

y_pred_lower = y_pred - 2 * RSE
y_pred_upper = y_pred + 2 * RSE
print(f"95% 预测区间: [{y_pred_lower:.2f}, {y_pred_upper:.2f}]")

对于top25perc=50,其毕业率的95%预测区间大约在36%到97%之间。这个区间较宽,表明对于单个观测值的预测存在相当大的不确定性。


总结 📝

本节课中我们一起学习了线性回归的第一部分。我们掌握了:

  1. 使用statsmodelsscikit-learn库在Python中实现简单线性回归。
  2. 解读回归摘要,理解系数、R-squared、P值等关键统计量的含义。
  3. 通过可视化(散点图、拟合线、Q-Q图、残差图)来诊断模型。
  4. 计算并理解RSS、RSE、TSS等核心统计量。
  5. 进行假设检验,利用P值判断变量的统计显著性。
  6. 使用拟合模型进行点预测,并构建预测值的置信区间。

这些内容是理解和使用线性回归模型的基础。在接下来的课程中,我们将在此基础上探讨更复杂的多元线性回归模型。

22:线性回归讲解-第二部分

📚 课程概述

在本节课中,我们将继续深入学习线性回归。我们将从上一节介绍的线性回归基本概念出发,探讨如何评估线性回归模型的性能,并介绍一种关键的优化算法——梯度下降法。通过本课的学习,你将掌握衡量模型好坏的标准以及模型优化的核心思想。

上一节我们介绍了线性回归的基本形式,即用一个线性方程 y = w*x + b 来拟合数据。本节中,我们来看看如何判断这个拟合的“好坏”,以及如何找到最优的 wb

📊 评估模型性能:损失函数

为了衡量模型预测值与真实值之间的差距,我们需要一个量化指标,这个指标被称为损失函数。在线性回归中,最常用的损失函数是均方误差

均方误差的计算公式如下:
MSE = (1/n) * Σ(y_i - ŷ_i)^2
其中:

  • n 是数据点的数量。
  • y_i 是第 i 个数据点的真实值。
  • ŷ_i 是模型对第 i 个数据点的预测值,即 ŷ_i = w*x_i + b

MSE的值越小,说明模型的预测越准确,拟合效果越好。我们的目标就是找到一组参数 wb,使得MSE的值最小。

🔍 寻找最优参数:梯度下降法

既然我们的目标是最小化损失函数MSE,那么如何找到使MSE最小的 wb 呢?这里我们引入一种非常重要的优化算法——梯度下降法

梯度下降法的核心思想是:通过迭代的方式,逐步调整参数,使损失函数值不断减小。它利用损失函数对各个参数的梯度(即导数)来指导参数更新的方向。

以下是梯度下降法的基本步骤:

  1. 初始化参数:随机选择一组初始的 wb 值。
  2. 计算梯度:计算当前参数下,损失函数MSE关于 wb 的梯度。
    • 关于 w 的梯度:∂MSE/∂w = (2/n) * Σ(ŷ_i - y_i) * x_i
    • 关于 b 的梯度:∂MSE/∂b = (2/n) * Σ(ŷ_i - y_i)
  3. 更新参数:沿着梯度的反方向(即下降最快的方向)更新参数。更新公式为:
    • w_new = w_old - α * (∂MSE/∂w)
    • b_new = b_old - α * (∂MSE/∂b)
      其中,α 是一个非常重要的超参数,称为学习率。它控制着每次参数更新的步长。
  4. 重复迭代:重复步骤2和步骤3,直到损失函数的值收敛到最小值,或达到预设的迭代次数。

学习率 α 的选择至关重要。如果学习率太小,收敛速度会非常慢;如果学习率太大,可能会在最小值附近震荡,甚至无法收敛。

🎯 核心概念总结

本节课中我们一起学习了线性回归的两个核心进阶概念:

  1. 损失函数:我们使用均方误差来量化模型预测的误差,其目标是找到使MSE最小的模型参数。
  2. 梯度下降法:这是一种通过计算损失函数梯度并迭代更新参数来最小化损失函数的优化算法。其关键在于学习率的设置,它影响着优化的效率和最终结果。

理解损失函数和梯度下降法,是掌握包括线性回归在内的众多机器学习模型如何被“训练”出来的关键。在接下来的课程中,我们将看到这些概念在更复杂模型中的应用。

23:分类导论 🎯

在本节课中,我们将要学习机器学习中的一个核心任务——分类。分类的目标是预测一个类别型的输出,这意味着预测结果是离散的标签,而不是连续的数值。

上一节我们介绍了机器学习的基本范畴,本节中我们来看看分类任务的具体定义和流程。

什么是分类?🤔

分类是机器学习的一项基础任务。其目标是根据输入数据预测一个类别标签。例如,根据邮件内容判断它是“垃圾邮件”还是“正常邮件”,或者根据医学影像判断肿瘤是“良性”还是“恶性”。

分类与回归任务的关键区别在于输出类型:

  • 分类:输出是离散的类别(如“是/否”、“A/B/C”)。
  • 回归:输出是连续的数值(如房价、温度)。

分类如何工作?⚙️

分类任务通常遵循以下流程:

以下是分类模型训练与预测的核心步骤:

  1. 准备标注数据集:我们需要一个数据集,其中每个数据样本都带有已知的、正确的类别标签。这称为“标注数据”。
  2. 训练模型:算法(模型)会分析这些标注数据,学习输入特征与输出标签之间的模式和关系
  3. 进行预测:训练完成后,模型可以将学到的模式应用于新的、未见过的数据,并预测其所属的类别。

常见的分类算法 📊

机器学习领域有多种算法可用于解决分类问题。

以下是几种最常用的分类算法:

  • 逻辑回归:尽管名字中有“回归”,但它是一种经典的分类算法,尤其适用于二分类问题。它通过一个S形函数(Sigmoid函数)来估计样本属于某个类别的概率。
    • 核心公式P(y=1|x) = 1 / (1 + e^(-z)),其中 z 是输入特征的线性组合。
  • 决策树:通过一系列“是/否”问题(基于数据特征)构建树状结构,最终到达代表预测类别的叶子节点。
  • 支持向量机:试图找到一个最优的“超平面”来清晰地区分不同类别的数据点,并最大化类别之间的边界。

本节课中我们一起学习了机器学习中分类任务的基本概念。我们明确了分类的目标是预测离散的类别标签,了解了其从数据准备、模型训练到最终预测的工作流程,并认识了几种常见的分类算法,如逻辑回归决策树支持向量机。从下一节开始,我们将深入探讨这些算法的具体原理与应用。

24:分类问题入门 🧠

在本节课中,我们将要学习机器学习中的分类问题。我们将从回归问题过渡到分类问题,理解其核心定义,并学习一种重要的理论模型——生成模型。

上一节我们介绍了回归问题,其输出是连续数值。本节中我们来看看分类问题,其输出是离散的类别标签。

分类问题的定义

在分类问题中,我们处理的是定性输出。具体来说,我们有一个离散的类别集合 C,其中包含 k 个类别标签。对于给定的输入 x,输出变量 y 将从集合 C 中取值。

我们的目标是构建一个分类器 C(x),该函数将输入 x(一个 p 维向量)映射到离散的类别标签集合中。

公式表示:
C: R^p -> C

以下是分类问题的典型例子:

  • 图像分类:例如,区分图片中是狗还是猫。此时,类别集合 C = {狗, 猫}。输入 X 是从图像中提取的特征向量(例如像素值、形状、颜色等)。分类器接收这个特征向量,并输出预测的类别。

需要注意的是,分类器可能会预测正确,也可能会出错,这会产生分类错误,我们将在后续课程中分析。

生成模型

为了从理论角度研究分类问题,我们将引入生成模型的概念。生成模型描述了数据是如何被“生成”出来的。

我们假设数据集 D 中的样本点(输入 X 和输出 Y)是按照以下两个步骤生成的:

  1. 生成输入:首先,从一个边缘分布 F(x) 中随机采样一个输入 Xi
  2. 分配标签:在得到输入 Xi 的具体值后,我们使用一个条件概率质量函数(PMF) 来为其分配一个输出标签 Yi

这个条件概率函数定义如下:
P(Y = k | X = x) = p_k(x)
其中,k 是类别集合 C 中的一个标签。函数 p_k(x) 被称为条件类别概率。它告诉我们,对于给定的输入 x,其输出为类别 k 的概率是多少。

一个数值示例

让我们通过一个具体的数值例子来理解这两个步骤。在本例中,我们将生成100个样本点。

步骤1:定义分布

  • 假设输入 x 服从 [-2, 2] 区间上的均匀分布,即 x ~ Uniform(-2, 2)。这对应了第一步的边缘分布 F(x)
  • 条件类别概率 p(x) 由以下S型函数(Sigmoid Function) 给出:
    p(x) = 1 / (1 + e^(-x))
    这个函数给出了当输入为 x 时,输出标签为 1 的概率。输出为 0 的概率则是 1 - p(x)

步骤2:生成样本
以下是生成两个样本点的过程:

  1. 第一个样本

    • 从均匀分布中采样,得到 x1 = 0.44
    • 计算条件概率:p(0.44) ≈ 0.70。这意味着标签为 1 的概率是70%,为 0 的概率是30%。
    • 我们“抛掷”一枚有偏硬币(正面(1)概率70%,反面(0)概率30%)。假设结果为 1
    • 因此,第一个数据点为 (x1=0.44, y1=1)
  2. 第二个样本

    • 再次采样,得到 x2 = -1.1
    • 计算条件概率:p(-1.1) ≈ 0.10。这意味着标签为 1 的概率是10%,为 0 的概率是90%。
    • 抛掷有偏硬币(正面概率10%)。假设结果为 0
    • 因此,第二个数据点为 (x2=-1.1, y2=0)

重复此过程100次,我们就得到了如图所示的样本点云。

结果分析

在生成的数据集中:

  • 输入 x 在区间 [-2, 2] 内。
  • 输出 y 取值为 01(图中用蓝色圆点表示)。

图中的灰色曲线是条件概率函数 p(x) 的图形表示,即S型函数。观察此图,我们可以发现:

  • 当函数值接近 1 时(曲线右端),其对应的输入点(x值较大)的输出标签大多为 1,只有极少数为 0
  • 当函数值接近 0 时(曲线左端),其对应的输入点(x值较小)的输出标签大多为 0,但也会混有少量 1

本节课中我们一起学习了分类问题的基本概念。我们明确了分类与回归的区别,即输出是离散的类别标签。我们引入了生成模型作为理解分类问题的理论框架,它通过边缘分布条件类别概率来描述数据的生成过程。最后,我们通过一个具体的数值示例,演示了如何根据S型函数生成分类数据集,并观察了数据分布与概率函数之间的关系。理解这些基础是后续学习具体分类算法(如逻辑回归、决策树等)的关键。

25:贝叶斯分类器与局部平均

在本节课中,我们将学习分类问题的核心概念——贝叶斯最优分类器,并探讨如何在实际中通过局部平均法来近似它。我们还将讨论高维数据带来的挑战。

贝叶斯最优分类器的定义

上一节我们阐述了分类问题并解释了数据集的生成方式。本节中,我们来看看如何定义一个理论上最优的分类器。

当我们有了分类问题并定义了数据集后,可以定义所谓的贝叶斯最优分类器,记作 C(x)

其定义由以下表达式给出:
C(x) = argmax_k P(Y=k | X=x)

这个定义告诉我们,对于一个给定的输入 x,我们需要查看所有可能的类别标签 k 对应的条件类别概率 P(Y=k | X=x)。然后,我们选择那个能使条件类别概率最大化的标签 K。换句话说,给定输入 X,贝叶斯最优分类器会分配一个能最大化条件类别概率的标签 K

我们稍后会看到,这个分类器能最小化分类错误率,这是衡量分类器质量的一个指标。

一个具体例子

让我们回顾上一张幻灯片的例子,为这个贝叶斯最优分类器找到一个明确的形式。

回到之前的幻灯片,我们观察到函数 P1(x) 由灰色曲线给出。同时,我们有 P0(x) 的表达式,它等于 1 - P1(x)。这对于二分类问题总是成立的,因为得到类别0的概率应该是1减去得到类别1的概率。

因此,如果我们画出函数 1 - P1(x),会得到一条与灰色曲线非常相似但大致对称的曲线。它将是一个不对称的S形曲线,仍然通过中间点(即 x=0, y=0.5 的点)。

现在,根据贝叶斯最优分类器的定义,对于任何 x 值,我们将分配一个标签 C(x),它对应于最大的条件类别概率。

例如,对于图中这个特定的 x 值,类别1的条件概率是这里的这个值,而类别0的条件概率是这里的这个值。由于类别0在这个 x 值上提供了更大的概率值,我们将把这个点分类为0。对于这个区域(特别是当 x < 0)的所有点,情况都是如此。

相反,对于 x > 0 的值,评估条件类别概率会显示 P1 总是大于 P0。因此,我们将为所有 x ≥ 0 的点分配标签1。在 x=0 的点,可以任意将其分配给任一类别。

更正式地表述,由于当 x ≥ 0P1 ≥ P0,贝叶斯最优分类器将在 x ≥ 0 时取值为1,否则(即 x < 0 时)取值为0。

实践中的局限与局部平均法

然而,在实践中应用这个逻辑存在一个限制,因为我们通常并不知道用于生成数据集的条件类别概率。

在实践中,我们被给予数据集,但并未被给予生成模型。这就像处理线性模型时,我们被给予数据集,但并不知道自然界用来生成这些点的参数 β0, β1, ..., βp。换句话说,只有“自然界”知道数据集是如何生成的,但我们无法窥探那个生成过程,它对我们来说是一个黑箱,我们无法访问生成过程内部的参数。

解决这个问题的一个可能方法是采用局部平均法。

让我展示局部平均法如何在我们之前展示的数据集上工作。回到幻灯片,如果我把内容清理一下,局部平均法的工作方式如下:

我想估计特定 x 值(例如 x = -0.2)的 P1(x)P0(x)。我将选择一个特定宽度的窗口,例如在 -0.40 之间的值(-0.2 是窗口的中心,向左右各移动0.2个单位)。现在,我将聚焦于这个窗口内的点,并统计该窗口内类别1和类别0的数量。

在特定 x 值(例如 x = -0.2)处的 P1(x) 定义,等于包含在该窗口内的点集中类别1所占的比例。P0(-0.2) 则是该窗口内类别0所占的比例。

回到图中,通过执行局部平均,我得到了图中蓝色曲线所代表的数值函数,它是灰色曲线(即真实的 P1(x))的一个不错的近似。我们可以称这个蓝色函数为 P1_hat(x),因为它是 P1(x) 的近似值。

这个 P1_hat(x) 是我们可以从数据中计算出来的,而真实的 P1(x) 对我们来说是完全隐藏的,我们不会知道这条灰色曲线。

一旦我们计算出了 P1_hat(x),我们现在就可以找到贝叶斯最优分类器的一个近似,我在这里用 C_hat 表示。这个分类器的规则与之前完全相同,即当 P1_hat(x) ≥ P0_hat(x) 时,我们将为该特定输入分配类别1。

在这种情况下,分类器的分割点并不正好是之前的0值,而是略高于0。但你可以看到,对于超过这个特定阈值的任何点,我们将分配 C(x) = 1;对于低于该阈值的点,我们将有 C_hat(x) = 0

与回归的联系及高维挑战

需要记住的是,局部平均法对我们来说并不是新技术。特别是,我们在描述回归问题时曾讨论过它。具体来说,如果我们有一个非常大的数据集,可以通过查看与待回归点足够接近的输入所对应的输出来解决回归问题。

你还应该记得,在那种情况下会出现所谓的“维度灾难”问题,而同样的情况也会在这里发生。本质上,当 x 是一个高维输入向量时,进行局部平均并不能可靠地估计条件类别概率,原因与在高维设置下执行局部平均不是回归问题的好解决方案相同。

特别是在高维空间中,所有输入点彼此之间都非常遥远,我们将无法找到足够接近我们想要进行分类的输入向量的点。因此,如果我们想统计在以待分类点 x 为中心的给定球体内包含的不同类别的点的数量,我们将没有足够的点来进行可靠的统计。

为了克服这个问题,我们将求助于结构化模型,这与我们解决回归问题时采取的方法相同。

总结

本节课中,我们一起学习了贝叶斯最优分类器的理论定义,它通过最大化后验概率来实现最小化分类错误。由于真实的条件概率未知,我们引入了局部平均法来从数据中近似估计这些概率。然而,在高维空间中,局部平均法因“维度灾难”而失效,这引导我们转向需要结构化模型(如后续将学的逻辑回归、决策树等)来解决实际的分类问题。

26:逻辑回归 📊

在本节课中,我们将要学习一种重要的参数化模型——逻辑回归。我们将探讨其核心函数形式、参数含义以及函数形状如何随参数变化。

概述

上一节我们介绍了维数灾难如何阻碍我们使用局部方法准确估计数据集的类别条件概率。因此,我们需要转向参数化模型。逻辑回归就是其中一种重要的参数化模型。

逻辑函数模型

在逻辑回归中,我们考虑一个二元分类问题,类别为 C0 和 C1。目前,我们假设输入是一维的,即 p = 1,因此输入只是一个标量值。

类别条件概率的具体参数化表示如下:

  • 给定输入 x,标签为 1 的概率是一个由参数 β0β1 参数化的函数,其表达式如下:
    P(Y=1 | X=x) = e^(β0 + β1*x) / (1 + e^(β0 + β1*x))
    我们称此函数为 P1,即类别 1 的条件概率。

  • 类别 0 的条件概率表达式与 P1 类似,但分子为 1:
    P(Y=0 | X=x) = 1 / (1 + e^(β0 + β1*x))

你应该意识到,输出为 1 的概率加上输出为 0 的概率之和应为 1,因为这是仅有的两种可能输出。你可以验证,这两个条件概率函数之和确实为 1。

函数形状分析

这个函数被称为 Sigmoid 函数。我们可以通过观察一些具体例子来研究其形状。

首先,为简化分析,假设 β0 = 0β1 = 1。此时,Sigmoid 函数为:
P1(x) = e^x / (1 + e^x)

现在,我们来看 P1(x) 作为 x 的函数时的形状:

  • x = 0 时,e^0 = 1,所以 P1(0) = 1 / (1 + 1) = 1/2
  • x 趋近于正无穷时,e^x 也趋近于正无穷,分母中的 e^x 将主导常数 1,因此函数值渐近地趋近于 1。
  • x 趋近于负无穷时,e^x 趋近于 0,因此函数值渐近地趋近于 0。

所以,我们得到一个从 0 增长到 1 的 S 形曲线,这也是“Sigmoid”(源自希腊字母 Sigma)一词的由来。

参数的影响

接下来,我们看看参数 β1β0 如何改变这个函数的形状。

改变 β1 的值:

  • 如果将 β1 从 1 增加到 2,函数 P1(x) 的 S 形曲线会变得更陡峭。这实质上加速了函数的增长和下降速率。
  • 相反,如果将 β1 减小到 0.5(即小于 1),函数 P1(x) 的 S 形曲线会变得更平缓,增长速率会慢得多。

因此,通过改变 β1 的值,我们可以调节 Sigmoid 函数的增长速率。

改变 β0 的值:

参数 β0 的作用是使整个 Sigmoid 函数曲线在水平方向上左右平移。

综上所述,两个参数 β0β1 共同作用,使我们能够:

  1. 调节 Sigmoid 函数的增长速率。
  2. 将 Sigmoid 函数曲线向左或向右平移。

总结

本节课中,我们一起学习了逻辑回归的核心——Sigmoid 函数。我们了解了其数学表达式,并分析了参数 β0(控制平移)和 β1(控制曲线陡峭度)如何影响这个 S 形函数的形状。这为我们理解逻辑回归模型如何对数据进行分类奠定了基础。

27:最大似然估计 📊

在本节课中,我们将要学习如何利用最大似然估计这一准则,从观测到的数据中估计逻辑回归模型的参数。我们将从定义似然函数开始,逐步推导出最大似然估计量,并通过一个信用违约预测的实际案例来演示其应用。

概述

假设我们有一个包含输入 X 和输出 Y 的数据集。我们相信数据是由一个具有特定参数 β0β1 的逻辑函数生成的,但这些参数对我们来说是未知的。我们的目标是从数据中估计出这些参数。

似然函数的定义

上一节我们介绍了逻辑回归模型的基本形式。本节中,我们来看看如何构建用于参数估计的似然函数。

给定一组输入 X,似然函数被定义为在给定这些输入的条件下,观测到一组特定输出 Y 的条件概率。

对于单个数据点 (Xi, Yi),其条件概率由以下逻辑函数给出:

P(Yi=1 | Xi) = 1 / (1 + exp(-(β0 + β1 * Xi)))
P(Yi=0 | Xi) = 1 - P(Yi=1 | Xi)

我们假设模型参数是 θ0θ1,它们是 β0β1 的通用表示。

构建完整数据集的似然函数

现在,我们假设数据集中的各个数据点是独立随机生成的。根据独立性的定义,观测到整个数据集的联合概率等于每个数据点条件概率的乘积。

因此,似然函数 L(θ0, θ1) 定义为:

L(θ0, θ1) = ∏ P(Yi | Xi; θ0, θ1)

其中, 表示对所有数据点 i 求乘积。

请注意,这个似然函数仅依赖于未知参数 θ0θ1,因为 XiYi 是已知的观测数据。

重写似然函数

为了便于计算,我们可以根据输出 Yi 的值(0 或 1)将乘积项分组。

以下是重写后的似然函数形式:

L(θ0, θ1) = [∏_{Yi=1} P(Yi=1 | Xi; θ0, θ1)] * [∏_{Yi=0} P(Yi=0 | Xi; θ0, θ1)]

第一个乘积项针对所有 Yi=1 的样本,使用 P(Yi=1 | Xi) 的公式;第二个乘积项针对所有 Yi=0 的样本,使用 P(Yi=0 | Xi) 的公式。这两个表达式在数学上是等价的。

最大似然估计

一旦我们有了似然函数,最大似然估计量就很容易表述了。

我们的参数估计值 β0_hatβ1_hat,将通过最大化似然函数 L(θ0, θ1) 来获得:

(β0_hat, β1_hat) = argmax_{θ0, θ1} L(θ0, θ1)

这些值就是我们对真实未知参数 β0β1 的最佳估计。

实例演示:信用违约预测

为了具体说明最大似然估计的应用,我们来看一个信用违约预测的例子。

我们使用一个名为“违约”的数据集,其中包含从银行借款的个人的历史数据。数据点标记为:

  • 蓝色圆圈:成功还款的个人。
  • 橙色叉号:违约(未能还款)的个人。

每个数据点的坐标是该个人的“余额”和“收入”。通过分析发现,“收入”对预测违约的帮助不大,而“余额”则是一个非常有用的预测指标。

在接下来的实验中,我们将仅使用“余额”作为输入 X,来预测违约(输出 Y=1)的概率。

模型拟合结果

使用最大似然估计对“违约”数据集进行逻辑回归拟合后,我们得到以下系数:

  • 截距 (β0_hat): -10.65
  • 余额的系数 (β1_hat): 0.0055

与线性回归类似,估计值 β_hat 是随机变量,因此也有标准误(近似于估计值的标准差):

  • β0_hat 的标准误: 0.36
  • β1_hat 的标准误: 0.0002

进行预测

在得到 β0_hatβ1_hat 后,我们可以构建预测函数来估计个人违约的概率。

预测函数 P1_hat 定义为仅关于输入“余额”的函数,其形式是一个逻辑函数,其中的参数被我们的估计值所替代:

P1_hat(balance) = 1 / (1 + exp(-(β0_hat + β1_hat * balance)))

使用这个函数,我们可以对个人的违约概率进行预测。例如:

  • 如果一个人的余额是 $1,000,其违约概率约为 0.6%
  • 如果一个人的余额是 $2,000,其违约概率则跃升至近 60%

这个结果与数据分布图是吻合的:在余额较低的区域(如$1,000),违约点(橙色叉号)的比例远低于余额较高的区域(如$2,000)。

总结

本节课中,我们一起学习了最大似然估计在逻辑回归中的应用。我们从定义单个数据点的条件概率出发,基于数据独立性假设构建了整个数据集的似然函数。通过最大化这个似然函数,我们可以从数据中估计出模型的参数 β0β1。最后,我们通过一个信用违约预测的实例,演示了如何利用估计出的参数进行概率预测。最大似然估计为我们提供了一种从数据中学习模型参数的有力且原理清晰的框架。

28:逻辑回归中的假设检验 📊

在本节课中,我们将要学习如何在逻辑回归的框架下应用假设检验。我们将回顾假设检验的核心概念,并学习如何利用它来判断一个特定的输入变量是否对输出变量有显著影响。

概述

上一节我们介绍了逻辑回归的基本模型。本节中,我们来看看如何评估模型中每个输入变量的重要性。我们将通过假设检验来回答一个关键问题:某个输入变量是否真的影响了输出结果?

假设检验回顾

在机器学习的学习过程中,我们无法得知模型参数(如 β0, β1)的真实值。我们只能接触到由“自然”生成的数据集。因此,我们无法确切知道 β1 是否等于 0(这对应着输入不影响输出的情况)。

我们通过最大似然估计得到的估计值 β1_hat 是一个随机变量,因为它依赖于从“自然”中随机收集的数据集。这个随机变量是无偏的,因此当真实的 β1 等于 0 时,β1_hat 的分布将围绕 0 波动。此外,这个随机变量的标准差可以从数据中计算出来。

Z统计量的计算与应用

一旦我们有了一个数据集,我们就能计算出 β1_hat 的标准差以及 β1_hat 的一个具体实现值。利用这两个值,我们可以计算 Z 统计量 Z1,其公式为 β1_hat 除以它的标准差。

Z1 = β1_hat / std(β1_hat)

可以证明,由于 β1_hat 服从正态分布,Z1 也服从一个均值为 0、方差为 1 的标准正态分布。这个分布有 95% 的概率质量落在区间 [-2, 2] 内。这意味着 |Z1| < 2 的概率是 95%。

因此,如果计算出的 |Z1| 大于 2,我们就有了统计证据来拒绝原假设(即输入不影响输出)。

单变量案例演示

我们可以用之前视频中见过的“违约”数据集来演示这个想法。在这个案例中,我们使用单个输入变量(个人余额)来预测其违约概率。

使用最大似然估计,我们可以计算出 β0_hatβ1_hat 的值。它们的标准差可以通过任何统计软件包计算。将估计值除以对应的标准差,我们就得到了 Z 统计量。在这个案例中,Z 统计量的绝对值大于 2。

因此,我们没有统计证据来接受“输入不影响输出”的假设。换句话说,余额与预测违约概率是相关的。

扩展到多变量逻辑回归

在处理多个变量(即 p > 1)时,我们可以使用多元逻辑函数,其定义如下:

P(Y=1|X) = 1 / (1 + exp(-(β0 + β1*x1 + ... + βp*xp)))

这里,条件类别概率(类别为 1)的形状与之前相似,唯一的区别是指数部分变成了一个具有 p 个输入的线性回归形式。我们假设“自然”根据这个条件概率生成数据点,但参数 β0βp 对我们来说是未知的。

多变量案例的参数估计与检验

使用可用的数据集,我们可以通过最大似然估计来计算这些参数的估计值 β0_hatβp_hat。一旦有了这些估计值,我们就可以用它们来近似条件类别概率并进行预测。

在下面的表格中,我们使用“违约”数据集,但这次考虑三个不同的输入特征:余额、收入以及一个表示该个体是否为学生的分类变量。处理分类变量的方法与在线性回归中相同,即定义一个虚拟变量 x3(是学生则为 1,否则为 0)。

引入这个虚拟变量后,可以运行最大似然估计。在多元情况下,似然函数的形式与 p=1 时类似,它是参数 β0βp 的函数。找到这个函数的最大值,就能为我们提供参数的估计值 β0_hatβp_hat

根据这个程序并使用“违约”数据集,我们可以找到 β0_hatβ3_hat 的估计值。同样,标准统计软件包可以计算出这些 β_hat 的标准差。将估计值除以标准差,就得到了 Z 统计量。

请注意,与 β2_hat(对应收入变量)相关的 Z 统计量绝对值小于 2。因此,不能拒绝原假设。这表明第二个变量“收入”对于预测违约概率并不显著。

需要强调的是,一旦移除了这个不显著的变量,你需要使用剩下的两个输入变量(余额和学生身份)重新计算逻辑回归的系数。你不能在移除变量后继续使用原来的系数。

总结

本节课中我们一起学习了如何在逻辑回归中应用假设检验。我们回顾了假设检验的原理,学习了如何通过计算 Z 统计量来判断一个输入变量是否对输出有显著影响。我们从单变量案例入手,然后扩展到多变量逻辑回归,并了解了如何处理分类变量以及如何解释检验结果。关键在于,如果某个变量的 Z 统计量绝对值大于 2,我们就有证据认为该变量是显著的;反之,则可以考虑将其从模型中移除,并重新拟合模型。

29:多类别逻辑回归

在本节课中,我们将要学习逻辑回归的扩展形式——多类别逻辑回归。我们将探讨当输出类别超过两个时,如何对模型进行建模和参数估计。

概述

到目前为止,我们学习的逻辑回归仅适用于两个输出类别的情况,这被称为二元分类设置。然而,在许多实际场景中,我们会遇到K个不同的类别,其中K通常大于2。在这种情况下,我们可以使用多类别逻辑回归。

多类别逻辑回归模型

上一节我们介绍了二元逻辑回归,本节中我们来看看当类别数量K大于2时,模型形式如何变化。

多类别逻辑回归使用以下参数化形式来表示条件类别概率。具体来说,输出等于标签k(k可以从1到K)的概率,在给定输入x的条件下,由以下公式给出:

\[P(Y=k | X=x) = \frac{e^{\beta_{0k} + \beta_{1k}x_1 + ... + \beta_{pk}x_p}}{\sum_{l=1}^{K} e^{\beta_{0l} + \beta_{1l}x_1 + ... + \beta_{pl}x_p}} \]

请注意,在这个特定情况下,参数β有两个下标:β_{pk}。第一个下标p表示该β值对应于第p个输入变量。第二个下标k表示这个β_{pk}对应于类别k的条件概率。

因此,对于每个类别k,我们有一组参数:β_{0k}, β_{1k}, ..., β_{pk},其中β_{pk}是变量x_p的权重。

在分母中,我们对所有可能的类别(从1到大写K)进行求和,求和项是与分子形式相同的指数项,但对应于类别l。

参数估计与预测

在这个模型设定下,我们仍然可以使用最大似然估计法来估计未知参数β_hat。这在形式上与我们之前看到的二元逻辑回归是等价的。

以下是参数估计与模型应用的核心步骤:

  1. 参数估计:使用训练数据和最大似然估计法,计算出所有类别对应的参数估计值β_hat。
  2. 概率计算:一旦获得了β_hat的值,我们就可以通过将上述条件类别概率函数中的β替换为β_hat,来构建条件类别概率的估计。
  3. 类别预测:对于一个新的输入x,我们计算它属于每个类别k的概率P(Y=k|X=x),然后将概率最高的类别作为预测结果。

总结

本节课中我们一起学习了逻辑回归技术的最后一部分——多类别逻辑回归。我们了解了当分类问题中存在两个以上类别时,如何扩展逻辑回归模型。该模型通过为每个类别定义一组参数,并使用Softmax函数来确保所有类别的预测概率之和为1。模型的参数同样可以通过最大似然估计法进行学习,并用于对新样本进行类别预测。

00:深度学习基础入门 🧠

在本节课中,我们将要学习深度学习的基础概念,了解其与人类大脑处理信息方式的联系,并预览整个课程的核心内容。

从生物视觉系统理解深度学习

上一节我们介绍了课程背景,本节中我们来看看如何通过人类视觉处理系统来理解深度学习。

让我们以自然的“相机”——眼睛为例。当光线照射到视网膜时,会被一系列细胞(如视杆细胞和视锥细胞)转化为电压信号。一个典型的手机摄像头约有5000万像素,而人类视网膜约有1亿个此类细胞,它们本质上就像像素点。在接收光线后,信息会经过多层细胞(如双极细胞、神经节细胞)的处理,这些细胞将光信号转化为神经冲动,进而识别边缘、形状、颜色,甚至对不同类型的运动方向敏感。所有这些信息以大约每秒10MB的速度传递到大脑,比许多Wi-Fi连接还要快。

大脑在这些输入之上进行了多层处理。它将光场输入转化为物体、记忆等概念,能够再次识别同一张面孔,并根据所见进行推断。大致来说,神经计算是一系列小型计算逐层进行的过程。这种计算最神秘或最深刻的特性在于,它是由相当基础的小神经元执行的。每个神经元的工作方式相对独立,但它们共同协作,完成了这些奇迹般的计算。

因此,深度学习是我们尝试在计算机上模仿生物大脑运作的领域。这属于人工智能范畴,近年来,尤其是在当前,深度学习已成为人工智能的代名词,并推动着众多领域的进步。

深度学习驱动的技术与应用

上一节我们探讨了深度学习的生物灵感,本节中我们来看看深度学习所赋能的一些具体技术和应用领域。

以下是深度学习技术应用的一些例子:

  • 自然语言处理:深度网络在自然语言处理方面变得极其出色。大多数人都体验过类似ChatGPT或Google Gemini的模型,它们能以有趣的方式处理文本,进行问答对话。
  • 多模态模型:有些模型同时使用文本和图像,甚至加入声音处理。
  • 视频生成:存在能够创建视频的模型。
  • 自动驾驶:自动驾驶汽车的大部分技术环节如今都使用了神经网络。
  • 科学研究:今天,大多数科学领域都在使用深度学习技术,无论是识别望远镜中的新星系,还是辨别人体内不同类型的细胞。

很难想象有哪个科学或工程领域尚未受到深度学习的影响,或者没有在积极使用它。

深度学习基础课程内容预览

上一节我们看到了深度学习的广泛应用,本节中我们将预览本门基础课程的核心学习内容。

课程始于对“智能”的定义。我们试图构建人工智能,因此应该问自己智能究竟意味着什么。我认为,一个智能有机体或智能机器应具备三个基本属性:它应该能够感知世界、理解世界(理解其环境),并能够基于这种理解采取行动。

基于此,我们将回顾人类尝试构建智能的历史。这始于20世纪40年代艾伦·图灵、麦卡洛克和皮茨等人的早期思想,他们试图构建能够以某种方式计算的机器。然后我们将穿越60年代、80年代、90年代,直至今天,了解我们如何构建了非常不同类型的网络。

接着,我们将从零开始构建深度网络。故事的第一部分从感知机开始。这是一个用于区分两类对象(例如苹果和橙子)的非常简单的模型。我们将讨论随机梯度下降——一种非常流行的拟合感知机的方法,确保感知机能正确区分苹果和橙子。

这会进展到所谓的核方法,它们是感知机更复杂的变体。核方法 incidentally 是神经网络的前身,在大约10年前主导了我们的机器学习技术,并且此后也在发展。然后,我们将研究全连接网络,这将是我们首次深入了解神经网络(特别是深度神经网络)的模样。它包含多层结构,神经元的工作方式相对基础。我们将使用一种称为反向传播的算法或技术来拟合神经网络。

如今我们使用的所有神经网络,包括全连接网络,都离不开反向传播。反向传播本质上就是链式法则,只是在深度学习中我们以略有不同的方式应用它。因此,课程的第一部分为我们提供了开始探索深度学习的基础知识。

进阶课程内容展望

上一节概述了基础课程,本节中我们简要了解一下在宾夕法尼亚大学的完整课程中,学生还将学习哪些进阶内容。

例如,我们将研究架构的演进:

  • 卷积神经网络:特别适用于理解自然图像或声音。
  • 基于注意力的网络:在理解文本方面非常流行,因为它们能够审视大量信息并聚焦于关键证据片段。

这大致完成了关于神经架构的故事。然后,我们将研究如何训练这些架构,探讨优化算法,并进行更多数学分析,了解这些算法的工作原理、何时该使用哪一种以及如何在实践中调整它们以获得良好结果。

深度学习仍然是一个非常模糊的领域,尽管取得了诸多进展和令人着迷的成果。因此,课程重点在于从基本数学原理和大量动手编程经验中,理解和培养对这些模型的直觉。课程后期还会深入探讨网络为何有效(或为何本应无效却有效)的一些细节。我们还将研究生成模型,如变分自编码器和生成对抗网络。这构成了本课程展开的理论画布。

本节课中,我们一起学习了深度学习如何从人类视觉系统获得灵感,探索了其推动的多项关键技术,并预览了从智能定义、历史发展到感知机、全连接网络及反向传播等核心概念的课程路线图。希望这为你开启了深度学习探索之旅。

01:深度学习历史 🧠

在本模块中,我们将开启课程的第一章,通过回顾历史来了解人工智能的发展脉络。理解这段历史能帮助我们看清当前技术在整个发展长河中的位置。

历史背景

对智能的探索由来已久。人类模仿生物体智能的尝试,其历史已接近85年。

上一节我们介绍了本模块的目标,本节中我们将具体回顾这段历史。我们将了解人们尝试构建人工智能的不同方式。

以下是人工智能发展历程中的几个关键阶段:

  • 早期构想与符号主义:在计算机诞生初期,研究者希望通过形式化的逻辑规则和符号系统来模拟人类思维。
  • 连接主义的兴起:受生物神经网络的启发,研究者开始构建由简单单元相互连接而成的计算模型,这是现代深度学习的雏形。
  • 专家系统时代:在特定领域,通过编码人类专家的知识规则,构建能够进行推理和决策的系统。
  • 统计学习与机器学习:随着数据量的增长和计算能力的提升,基于概率统计和从数据中自动学习模式的机器学习方法成为主流。
  • 深度学习的复兴:得益于大数据、强大算力(如GPU)和算法改进(如反向传播、ReLU激活函数),深层神经网络的能力被重新发掘并取得突破性进展。

这段历史为我们提供了一份路线图。我们能够将本课程中涵盖的不同主题,追溯为这份路线图上的重要里程碑。

核心概念示例

为了更具体地理解,我们可以看一个早期神经网络的核心计算单元——感知机的简化公式。一个感知机对输入进行加权求和,并通过一个激活函数产生输出:

# 感知机的简化代码表示
def perceptron(inputs, weights, bias):
    # 计算加权和
    weighted_sum = sum([x * w for x, w in zip(inputs, weights)]) + bias
    # 应用阶跃激活函数
    output = 1 if weighted_sum > 0 else 0
    return output

其中,inputs 是输入向量,weights 是对应的权重向量,bias 是偏置项。这个简单的模型是许多复杂神经网络的基础构件。

总结

本节课中,我们一起学习了人工智能,特别是深度学习的发展简史。我们从早期的符号主义探索,历经连接主义、专家系统、统计学习等阶段,最终看到了深度学习在当代的复兴。理解这段历史有助于我们把握整个领域的演进逻辑,并为后续深入学习具体技术奠定坚实的基础。

03:什么是智能 🤔

在本节课中,我们将要学习“智能”这一核心概念。我们将探讨智能的定义、它在不同生物体中的表现,以及它与机器智能的区别。


概述

智能是一个难以精确定义但易于观察的概念。我们通常通过一个实体能否适应环境变化、执行复杂任务来识别其智能。本节将分析从人类到植物,再到计算机程序的各种智能表现形式,并提炼其关键特性。


智能的定义与观察

智能很难定义,但很容易判断某物是否具有智能。

所有人都认同人类具有智能。你和我都是智能的。我们可以做许多不同的事情:我们可以开车,可以解微积分方程。

我们还可以说话和唱歌等等。这些都是你会联想到的智能行为。

你也会同意,狗不如你聪明。但同时你也会同意,狗是智能的。它知道当你扔出飞盘时应该去接住;它知道当你感到有点悲伤时如何安慰你;归根结底,狗可以在世界上活动,并做出与计算机截然不同的事情。

蚂蚁也是智能的,可能不如狗聪明,但它们能做很多巧妙的事情。许多蚂蚁可以聚集在一起建造结构。它们群居生活,并拥有与这些不同个体聚集、共同生活以执行特定任务相关的社会结构。当周围环境发生变化时,它们能够适应。这些都是我们今天认识到或会将其描述为智能行为特征的事情。

简而言之,智能就是关于适应能力——根据你周围世界的变化来改变你行为的能力。我们做所有这些事情是为了一个目的:生存。生物体的最终目标是生存,而任何使生存变得困难的事情都需要去适应。为了高效地做到这一点,你需要智能。


植物是智能的吗?

根据这个定义,我们可以问第二个问题:植物是智能的吗?在某种程度上,是的。有些植物表现出行为:你把一盆植物放在窗边,它会向窗户移动以获得更多阳光。虽然它不能自己移动并走到房间的不同位置(除非你移动它),但它肯定能做到这一点。所以它们显然不如能移动的动物聪明,但它们也算是有某种智能。

这里有一个有趣的例子:一种叫做“海鞘”的植物。海鞘是生活在海底的植物。当它们出生时,它们是动物,拥有神经系统和神经节细胞。这种植物在海底游动,找到一块又大又肥的岩石居住,上面有苔藓可供其获取营养。在那个时候,海鞘会消化掉自己的神经节细胞,并且不再移动。它不再需要这些细胞,因为它已经找到了一个可以终生使用的营养来源。

这常被用作教授的隐喻:当他们还是像你我这样的学生时,他们努力学习,然后他们去了大学,消化了自己的大脑,之后就不再思考了。这不是一个很好的笑话,但我可以开这种玩笑。海鞘为了保护自己,会在周围形成一层厚厚的覆盖物,称为“被囊”,这就是它名字的由来。所以,这是一种曾经可以移动的植物,但现在不再移动了,因为它没有了神经系统。


智能的关键特性

我想向你们强调我们所举这些例子的显著特性。

所有这些例子都是生物体,具体来说是活的生物体。它们可以四处活动,可以做机器做不到的事情。机器表现出一种不同的智能。

为了让这一点更清晰,让我们看看AlphaGo。AlphaGo是一家名为DeepMind(位于英国伦敦)的公司构建的计算机程序,用于玩一种叫做“围棋”的游戏。围棋在东亚非常流行,对于没接触过的人来说,它与国际象棋没有太大不同,基本上是一种非常困难的游戏,被广泛认为是人类智能的堡垒之一。在此之前,没有计算机能在围棋上击败人类。

DeepMind接受了这个挑战,他们构建了一个下围棋的计算机程序。这是一个非常棒的程序。他们试图让它与这个人竞争。他叫李世石,是韩国围棋冠军,当时被广泛认为是世界上最好的围棋棋手之一。经过三场比赛,DeepMind的AlphaGo程序赢得了对这个人的全部三场比赛。对于大多数围棋棋手来说,计算机怎么可能在这个非常困难的任务上击败人类,这有点令人惊讶,或者说非常震惊。

我不想听起来很傲慢,但我想给你们看一句俏皮话。这个人(一位美国围棋冠军)说:“如果你想打败这台机器,你所要做的就是拔掉插头。机器就不能再玩了。然后你就默认获胜了。”当然,这是个玩笑,但它触及了一个非常重要的问题:当我冲过来打你时,你会跑开。如果你不跑开,那就不算是一种非常智能的行为。如果你对机器做同样的事情,机器不会跑开。机器对其能做的事情有一个非常非常狭窄的定义。你可以在其定义之外的任何方面影响它,而机器无法做出反应。

所以,AlphaGo非常擅长围棋,是这项狭窄任务中的佼佼者。因此,当我们谈论智能时,我们必然对展示多种不同行为感兴趣,这些行为允许我们适应许多不同的事情。当然,也存在非常有用的、狭窄智能的例子,这就是计算机的现状,它们是不同的事物。

这只是我的观点。我是作为机器人学家被培养出来的,所以我这样思考智能。你们中的一些人可能更多的是计算机科学家,你们可能会将智能视为计算机擅长某一特定任务的更狭义定义。这完全一致,也很恰当。但下次你看到一台机器时,问问自己:这台机器的哪些特性让你想称它为智能或不智能?那些只能被动地对来自外界的刺激做出反应的机器,其智能概念是有限的。如果我把钥匙掉在这个教室后面,无论你从这个角度给我多少图像,我都无法找到它们。我必须亲自去那里寻找。我们感兴趣的是设计能够拥有这些行为的机器。


总结

本节课中,我们一起学习了智能的核心概念。我们了解到,智能的本质是适应环境变化的能力,其根本目的是为了生存。我们观察了从人类、动物到植物展现出的不同层级的智能,并将其与像AlphaGo这样的狭窄机器智能进行了对比。关键的区别在于,生物智能具有主动性、适应性和行为的多样性,而当前典型的机器智能则擅长特定、定义明确的任务。理解这种区别是思考人工智能未来发展的基础。

04:智能的组成部分 🧠

在本节课中,我们将要学习构成智能的三个核心组成部分。理解这些部分有助于我们明确本课程的重点方向。

智能通常被认为由三个相互关联的部分构成:感知、行动和认知。这三者共同作用,使生物或机器能够与环境互动并做出决策。

感知 👁️

上一节我们介绍了智能的整体框架,本节中我们来看看第一个组成部分:感知。

感知是指观察和理解事物的能力。它涉及接收来自外部世界的信号,例如通过眼睛看、耳朵听或皮肤感受。

以下是关于感知的关键点:

  • 感知是智能系统获取外部信息的主要途径。
  • 它处理来自各种感官的原始数据。
  • 在计算机科学中,计算机视觉等领域专门研究视觉感知。

行动 🏃

在了解了如何获取信息后,我们接下来看看智能的第二个组成部分:行动。

行动是指影响和改变事物的能力。例如行走、飞行(对鸟类而言),或在有物体靠近时改变自身位置。

以下是关于行动的关键点:

  • 行动是智能系统对外部世界产生影响的输出。
  • 它涉及运动规划、控制理论等。
  • 机械工程等领域的课程通常专注于如何行动,并假设系统已充分理解感知到的信息。

认知 🤔

感知和行动并非孤立存在,将它们连接起来的粘合剂是第三个组成部分:认知。

认知是大脑进行的工作。大脑接收来自感官(如眼睛、鼻子、皮肤)的刺激,然后进行计算处理,最终决定下一步应该走向哪里或如何移动手脚。

真正的智能行为不仅是对刺激做出反应。例如,当我寻找丢失的钥匙时,我会想象如果走到房间的某个位置,世界会是什么样子。我之所以去房间后面寻找,是因为我推测钥匙可能掉在那里。这种根据可能获得的观察结果(刺激)来采取行动的能力,对于表现出有趣的行为至关重要。

本课程的焦点 🎯

以上三个概念共同构成了智能。然而,本课程不会涵盖所有三个方面。

不同的大学课程会侧重这三个方面的不同部分。例如:

  • 计算机视觉课程主要讨论感知
  • 机械工程、控制论或运动规划课程主要讨论行动

在本课程中,我们将重点讨论中间的部分:认知

我们将做出以下假设:

  1. 已经有人为我们提供了某些刺激(感知输入)。
  2. 我们知道需要采取什么行动或如何使用这些刺激。

我们关注的核心问题是:如何高效地进行这个认知处理过程。这涉及智能体中一个非常具体的部分,而非其全部。你可以将本课程的重点——学习——理解为认知的核心。

总结 📝

本节课中我们一起学习了智能的三个组成部分:感知(接收信息)、行动(影响世界)和认知(处理信息并决策)。我们明确了本课程将聚焦于认知部分,特别是如何通过学习来高效地处理信息,为后续的具体机器学习算法学习奠定基础。

05:认知的目标 🎯

在本节课中,我们将探讨学习和认知的核心目标,理解为什么在资源有限的情况下,学习对于智能体至关重要。

上一节我们讨论了智能体的基本概念,本节中我们来看看学习和认知的根本目的。

学习的必要性:从“超级智能体”说起

我想强调的第二点是协调或学习的目标。为了让你理解这一点,让我举一个例子。

想象你是一个“超级智能体”。这个智能体拥有无限快的速度、无限的智慧,并且在性能上没有任何限制。现在,你正在驾驶一辆汽车。为了理解如何驾驶汽车,你必然需要知道你周围其他汽车会做什么。

“超级智能体”并不觉得这是个问题,因为对于其他汽车可能做的每一件小事,它都能在脑海中非常快速地模拟出它们将要做什么,并采取必要的行动。例如,当你在车道上行驶时,如果有一辆车要插到你前面,“超级智能体”能精确地知道将会发生什么,因为它以无限快的速度感知到了,并且它精确地知道它应该稍微踩一下刹车。

所以,如果你在所能进行的计算类型上没有限制,如果你在所能获得的刺激或感知类型上没有限制,那么你就不需要任何学习。因为你可以直接使用你的刺激并采取行动,而无需总结这些刺激,也无需使用过去的知识。

学习的核心目标:总结与效率

因此,我们使用学习的原因,是因为我们希望使这个过程更有效率。我们希望在当前的观察与过去的观察相似时,能够理解这种相似性,然后基本上重复我们过去采取的那些行动。因为我们无法像“超级智能体”那样快速地模拟事物,也无法像“超级智能体”那样高效地计算事物。

所以,学习归根结底是一个总结过去经验,并利用这种总结来采取当前行动的过程。它本质上是你所采取行动的一种先验

仅仅因为昨天有辆车插了你的队,并不意味着那辆车今天也会插你的队。这就是为什么你今天不应该因为这个原因而刹车——你应该根据你现在接收到的观察来刹车。学习提供了一种先验,例如,它使得“驾驶野马汽车的人通常喜欢插队”这种可能性增加。这些正是我们将要从过去数据和经验中学习的先验类型。

机器学习算法的本质:输出先验

因此,一个运行算法的机器,并不是直接给你输出。它给你的是关于输出的一个先验。你实际采取的输出或行动,取决于你当前的观察是什么。

这与一个国际象棋程序非常不同。国际象棋程序对状态有非常清晰的概念,它不需要过多依赖于这种“给定状态应该采取什么行动”的推理,其行动是确定性的。

以下是机器学习与“超级智能体”直接计算的关键区别:

  • 资源有限性:我们无法进行无限快、无限复杂的计算。
  • 学习的角色:学习是对过去经验的总结,用于提高当前决策的效率。
  • 先验知识:学习的结果是形成先验,它影响但不直接决定当前行动。
  • 决策流程:最终行动 = 当前观察 + 从学习中获得的行为先验

本节课中我们一起学习了认知和学习的目标。我们通过“超级智能体”的例子认识到,学习之所以必要,是因为现实中的智能体(包括人类和机器)都受到计算和感知资源的限制。学习的核心是总结过去经验以形成先验知识,从而提高在面临新情况时的决策效率,而非直接给出答案。理解这一点是区分简单程序与具备学习能力的智能系统的关键。

06:智能的起源 (1942-1950) 🧠

在本节课中,我们将要学习人工智能思想的早期起源,了解在20世纪40年代,科学家们如何开始将生物大脑的运作抽象为数学模型,从而为现代人工智能奠定基础。

现代人工智能思想的萌芽

让我们思考人们是如何开始思考“智能”这一概念的。这并非人类首次探讨智能。人们从20世纪40年代初就开始尝试理解并构建智能。大致来说,大多数人会同意,我们现代意义上的人工智能概念始于40年代初。

麦卡洛克与皮茨的神经元模型

上一节我们提到了人工智能思想的萌芽,本节中我们来看看两位关键的先驱者。左边这位是沃伦·麦卡洛克,他是芝加哥大学的神经科学教授。右边这位是沃尔特·皮茨,他是一位数学家、逻辑学家,先后在芝加哥大学和麻省理工学院工作。

他们共同构建了第一个神经元模型。他们的思路是:我们拥有大脑,大脑由许多神经元构成。大脑拥有多种不同神经元这一事实,大约在20世纪初就已为人所知。这两位研究者感兴趣的是,将这些生物神经元抽象成他们能更好理解的数学对象。

生物神经元是复杂的实体。例如,你的大脑大约有1014个连接,分布在约109个神经元之间。


神经元是大量化学反应的场所,存在许多反应。电脉冲在神经元之间传递。如果你学习神经科学课程,大约会花一半时间仅仅研究这些传递信息的小反应。

为了构建智能计算机或智能机器,我们并不总是需要模拟这种复杂性。因此,麦卡洛克和皮茨提出,让神经元成为一个简单的对象。它是一个接收n个输入(x1, x2, x3, ..., Xn)的盒子。


它产生一个输出。这与生物神经元并不十分接近,但它是其一个非常核心的抽象。生物神经元接收来自许多不同神经元的多种输入,在神经元末端产生一个脉冲——神经元要么“放电”,要么“不放电”。这类似于这个数学神经元的输出。

它如何选择放电或不放电呢?这取决于一个函数。神经科学家会告诉你生物神经元中的函数是什么。在机器学习或学习中,我们感兴趣的是构造能产生特定类型输出的函数。这里有一个小启示:我们知道人类生物大脑能做智能的事情。与其直接复制生物大脑的运作,不如将其抽象成一个非常简化的对象。这个对象看起来与生物神经元完全不同,但现在你可以对这个对象进行操作。

大致来说,我们今天使用的神经元与这类神经元非常相似。我们稍微改变了一下函数,也稍微改变了输出,但本质上没有太大不同。我忘了提到的另一点是,沃尔特·皮茨是一位逻辑学家,他热衷于用逻辑原理来捕捉生物学特性。这就是为什么这个模型如此简化——这个神经元的输出是一个布尔值。

图灵与智能的哲学思考

大约在同一时期,战争结束后,在英国的艾伦·图灵发展了他的计算理论。他对生物大脑如何进行生物计算越来越感兴趣。他提出了一种思考智能的方式,这种方式至今仍非常流行。

例如,你可以看到这篇名为《计算机器与智能》的论文,作者是艾伦·图灵。第一节叫做“模仿游戏”。在这里他说:我认为,计算机是能让人类相信它是人类的东西。如果一个人从未见过计算机给出答案,那么如果我能回答你所有的问题,而你并不知道我是人还是计算机,那么从所有实际目的来看,我就是人类。这就是我们后来所说的图灵测试

这是他工作中更具哲学性的部分。他工作中更具体的部分是创建了神经元模型。他开始将神经元视为具有阈值非线性的对象,接收多个输入并产生多个输出。

大致来说,艾伦·图灵在英国构想(而非实际构建)的神经元,与麦卡洛克和皮茨的神经元并没有太大不同。它是同一个对象,同一种数学抽象,人们开始将其视为构建智能组件的一种方式。

控制论学会的诞生

与此同时,在美国马萨诸塞州的剑桥(图灵在英国剑桥),由诺伯特·维纳领导的一批教授开始自称为“控制论学会”。他们想要设想能做人所能做之事的机器,这就是他们自称控制论学会的原因。

这是一次会议的照片,这是诺伯特·维纳,这是麦卡洛克,这是皮茨,我想这是格雷·沃尔特。

如果你需要更多学习这门课的动力,我可以展示诺伯特·维纳在40年代撰写的控制论教科书的目录。即使在今天,它也是一本值得阅读的经典教科书。它以一些哲学问题开始,比如“时间是什么?”,这也是牛顿《自然哲学的数学原理》的第一章。然后它讨论了群论、一些物理学概念。

反馈 作为两个相互作用事物结合的概念被提出。就像我们在行动和感知之间形成一个循环一样,大脑内部也存在反馈回路,使你能够做非常不同的事情。例如,如果你视野的某一部分看到重复且无用的东西,你的大脑会自动将其关闭,让你的眼睛聚焦于场景的其余部分,这样你就不必浪费计算能力来处理这些变化的东西。在现代机器学习中,我们称之为 注意力机制。更广泛地说,你会认为这就是反馈。

然后还有关于语言等内容。因此,维纳认为在追求智能过程中基础的概念,也基本上是我们本课程将要学习的概念。我们将研究信息论、反馈、连续信号的表示等。

所以,在过去的80年左右,我们思考智能的方式在其语言表述上发生了变化,但其核心原则并没有太大改变。

总结

本节课中我们一起学习了人工智能在1942年至1950年间的早期起源。我们了解到,麦卡洛克和皮茨如何将复杂的生物神经元抽象为简单的数学模型(接收多个输入 x1, x2, ..., xn,通过一个函数产生一个布尔输出),这成为了现代人工神经网络的基础。同时,艾伦·图灵从哲学和计算模型层面定义了机器智能(图灵测试),而诺伯特·维纳等人创立的控制论学会则引入了 反馈 等核心概念。这些早期工作确立了抽象、数学建模和系统交互作为构建智能机器的基本思路,其影响延续至今。

07:表示学习 🧠

在本节课中,我们将要学习一个核心概念——表示学习。我们将探讨机器如何从连续的感官信号中提取有意义的、离散的表示,以及如何根据任务需求选择合适的表示粒度。


什么是表示学习? 🤔

上一节我们讨论了机器学习的基本流程,本节中我们来看看表示学习。表示学习指的是这样一个过程:我们利用来自传感器的刺激信号,并从中创建出有意义的、压缩后的表示。

例如,我观察从面前椅子反射过来的一堆像素或光子,并将其识别为“一把椅子”。我能辨认出你们中有人穿着格子衬衫,是通过观察相邻像素的不同模式实现的。这些都是我从本质上连续的信号中创造出的离散表示

世界以连续的方式演变。为了理解它、处理它,我们将其压缩成离散的表示。我们将那些随时间变化不大的事物视为对象

为了进一步简化对对象的描述,我们给它们赋予了名称,例如红色、蓝色、绿色等。


表示学习的核心问题:压缩的粒度 ⚖️

那么,表示学习的核心问题是:你应该在何时停止压缩?

我拥有一个连续的、范围巨大的连续信号。我可以将其压缩到几乎没有信息量。例如,我可以说这个房间里的一切都是一个“对象”,但这无助于我与他人交流或四处活动。我也可以说一切都是“一堆分子”,这是另一个极端,这种描述对于我与世界互动同样没有太大用处。

根据你所做的事情类型,你会选择特定的粒度。这就像向朋友介绍摇滚乐和古典乐:如果对方是新手,你会用一种方式解释;如果你面对的是发烧友,你会用更细腻、词汇完全不同的语言来描述同一首歌。

因此,根据机器需要执行的任务类型,我们用来压缩连续信号的“语言”是不同的。

  • 高压缩:意味着你想用很少的符号
  • 低压缩:意味着你想用很多符号来描述同一事物。

这就是表示学习的含义。


信息论的基础 📊

为了理解何时应该压缩、何时不应该压缩,我们需要借助一个领域的知识。图中这位人物——克劳德·香农,在40年代末开创了信息论这一领域,专门研究此类问题。

在接下来的课程中,我们将学习信息论中的一些概念,以更好地把握表示的尺度。


早期人工智能的发展 🌱

其发展历程大致如下图所示:

这大致是人工智能发展的最初几年,特点是谈论很多,实际行动较少。粗略地说,每个人都在进行深度思考,但并没有太多具体的实践成果。


总结 📝

本节课中我们一起学习了表示学习的核心思想。我们了解到,机器通过将连续的感官数据压缩成离散的、有意义的表示(即“对象”)来理解世界。关键在于,根据不同的任务目标,我们需要选择不同粒度的表示——有时需要高度压缩(使用少量符号),有时则需要保留更多细节(使用大量符号)。克劳德·香农的信息论为我们提供了衡量和选择合适表示的理论工具。最后,我们回顾了人工智能早期“重思考、轻实践”的发展阶段,为后续更具体的技术学习做好了铺垫。

08:智能重载-1960-2000 🧠

在本节课中,我们将回顾人工智能发展史上一个关键时期——从1960年代到2000年。我们将了解早期神经网络的诞生、其面临的挑战、以及后续如何通过新的思想和算法实现复兴。核心内容包括感知机、连接主义思想的兴衰、反向传播算法的再发现,以及卷积神经网络和支持向量机的出现。

感知机的诞生:第一个神经网络 🤖

上一节我们介绍了早期人工智能的萌芽。本节中我们来看看第一个真正意义上的人工神经网络是如何被构建出来的。

大约在60年代末期,人们开始着手构建实物。下图展示了有史以来第一个神经网络。图中人物名为弗兰克·罗森布拉特,他是康奈尔大学和伊萨卡海军研究中心的研究员。这台机器与你在麦卡洛克-皮茨神经元模型中看到的完全相同:它接收一系列输入,并输出一个布尔值(0或1)。它被称为“感知机”,而这台机器重达五吨。

这就是第一个神经网络,也是最简单的神经网络——仅由一个神经元构成。这是人类首次设计出人工神经网络。

在数学上,我们在本课程后续部分会这样表示它:

output = sign( w1*x1 + w2*x2 + ... + wd*xd )

想象一下,你有一张橙子的图片,x1, x2, ..., xd 代表图片中的像素。典型的图片非常大,例如手机拍摄的图片从1000万到5000万像素不等,这意味着有1000万到5000万个数字。你将每个像素乘以一个不同的数字 W1, W2, ..., WdW 是你选择的一个向量,它让你能够判断这张图片是橙子还是苹果。

判断方式如下:你对内部求和结果应用一个符号函数。如果符号函数内部的值是正数,则返回+1;如果是负数,则返回-1。然后你可以标注:如果这个函数的输出是正数,我就称之为橙子;如果是负数,则称之为苹果。你需要选择 w1wd 的值,以确保在你收集的某个训练数据集中,所有图片都能被正确分类——橙子被识别为橙子,苹果被识别为苹果。

一旦你找到了这些 w 值,你就可以对一张不属于训练集的新图片运行同样的计算,从而猜测它是苹果还是橙子。我将在下一讲中更精确地重复这一点,但简而言之,这就是机器学习:利用训练数据中的模式来猜测权重 W1Wd 的值,然后使用这些权重对不属于训练数据的新图片进行推断。

连接主义的挫折与寒冬 ❄️

上一节我们看到了感知机的工作原理。本节中我们来探讨它为何一度陷入低谷。

这是一段历史,也是一个悲剧。这类思想被称为学习中的“连接主义”思想,即人们从一个更基础的层面(神经元)开始,神经元组合在一起形成表征并产生输出。在60年代末,麻省理工学院有一位非常著名的研究员名叫马文·明斯基。他和西摩·帕佩特合著了一本书,书中指出这类函数只能解决简单问题。具体来说,如果你有一堆标记为+1的点和一堆标记为-1的点,你只能用一条直线(线性函数)来分割它们。这正是感知机所做的(我们将在下一讲中看到这一点)。它无法解决下图所示的问题:

这里有一堆加号,这里有一堆减号,这里又有一堆加号,这里又有一堆减号。没有一条直线能干净利落地把加号和减号分开。在这种情况下,感知机模型显然无法解决此类问题。

于是明斯基他们说:“看,感知机能解决一些问题,但不能解决另一些问题。”但其他所有人都将此理解为对感知机的严厉批评。由于明斯基在当时是非常著名的人物,所以大家都认为“感知机没什么用”。基本上,人们开始停止研究连接主义方法。与此同时,其他一些领域如规划、逻辑等在70年代初变得非常流行,这就是为什么这类学习失去了动力。

神经网络的复兴与卷积思想 🔄

上一节我们了解了神经网络遭遇的寒冬。本节中我们来看看它是如何重新流行起来的。

大约在80年代末,神经网络再次流行起来。当时人们发现,在视网膜或视觉处理的早期阶段,存在一种叫做“卷积”的过程。你正在创建类似边缘或颜色的特征。他们开始将这类特征融入人工神经网络。这整个第二阶段的学习也由一项重要发现引领,即“反向传播”算法(我们将在几讲后看到)。这是一种训练权重 W1Wd 的算法。还记得我说过我们必须找到能正确分类苹果和橙子的权重吗?反向传播就是一种让我们找到这些权重的算法。

该算法虽然早在60年代就由一位名叫孙正义的教授构建出来(我们几讲后也会看看他的一些工作),但它发表在一篇日文论文中,基本上不为世界其他地区所知。因此,在80年代中期,杰弗里·辛顿和鲁梅尔哈特重新发现了这个算法。那才是真正让所有人开始重视这项工作的时候。反向传播被认为是训练人工神经网络(即我们看到的神经元的组合,我们见过一个神经元,你可以将许多神经元组合在一起)的一种非常好的方法,它可以为每个神经元找到权重。

大约在那时,人们注意到,大脑内部有不同的部分,有些负责听觉,有些负责视觉处理。在视觉处理部分内部,又有不同的子部分:V1皮层识别边缘和颜色,V2皮层将这些特征组合成边缘和颜色的组合,一直到V4或主要皮层,它识别人脸、人物和语言等。神经科学的这一进展基本上让人们相信,可以在人工架构中构建类似的结构。这就是卷积神经网络的价值所在。因此,卷积神经网络是特定类型神经元的良好组合,这些神经元特别适合处理图像。

从理论到应用:CNN与SVM的登场 📈

上一节我们看到了神经网络如何借鉴生物学原理。本节中我们来看看这些思想如何转化为实际应用,以及其他重要模型的出现。

扬·勒丘恩是纽约大学的教授,他现在也是Facebook研究的负责人。他成名是因为他是最早训练卷积神经网络来识别手写数字的少数人之一。即使在90年代末,美国邮政系统也在使用自动检测信件上邮政编码的技术,以便根据信件上写的邮政编码将信件分拣到不同的区域。由于邮政编码是人写的,你需要一种可靠的方法来发现或猜测写的是什么数字。

机器学习领域接下来的技术进步是由瓦普尼克等人完成的,他们构建了支持向量机模型。支持向量机非常流行,因为它们特别容易使用。所有关于神经网络重新发现、分类数字等事情,都被更广泛的人群所忽视,因为神经网络非常难以使用,只有专家才能使用它们,而不擅长训练神经网络的人永远无法让它们工作。而支持向量机是基本上大多数人都能让其工作的东西。

这里有一个经验教训:今天你和我能够很好地进行深度学习,很大程度上与我们对神经网络和深度学习的理解有关,但也因为过去15-20年间人们编写了大量的库、软件和优秀代码,使得使用这些东西变得非常、非常容易。


本节课中我们一起学习了:从1960年代到2000年人工智能,特别是神经网络的发展历程。我们回顾了第一个感知机的诞生及其数学原理,了解了连接主义思想因局限性而遭遇的寒冬,探讨了借助反向传播算法和神经科学发现(尤其是视觉皮层原理)带来的神经网络复兴,并最终看到了卷积神经网络在图像识别中的实际应用,以及支持向量机作为易用替代方案的兴起。这段历史揭示了技术进步、理论突破与工程实践之间的紧密互动。

09:智能革命-2006

在本节课中,我们将要学习深度学习现代时代的开端,了解其关键的转折点——2012年的ImageNet竞赛,并探讨推动这一领域进步的核心因素。

现代深度学习的开端

上一节我们回顾了神经网络的历史发展。本节中我们来看看现代深度学习的正式兴起。

现代深度学习时代的开端大致在2006年左右。当时谷歌开始构建大型神经网络,并在内部训练它们用于图像识别。然而,真正的分水岭时刻发生在2012年。

ImageNet竞赛与转折点

这里有一个名为ImageNet的数据集。ImageNet是一批图像,大约有130万张,收集自一个非常古老的网站Flickr。斯坦福大学的研究人员从这个网站下载了大量图像。因为人们通常会在图片下方写上名称,所以他们也获得了这些图像的一些标注信息,并额外通过人工标注了一些。

以下是关于ImageNet数据集的关键信息:

  • 该数据集包含大约1000个不同的类别。
  • 类别包括不同品种的狗、不同的车辆、不同的乐器,以及许多其他人工和自然物体。

在2010年代初期,计算机视觉会议中曾有一项竞赛,参赛者需要在这个数据集上争取获得最佳的分类准确率。这是最终版本的数据集,在你的笔记本电脑上存储大约需要50GB的空间。你需要从这100万张图像中尽可能多地进行分类。

在2011年,完成这项任务的最佳方法大约有30%的图像分类错误。从2007或2008年这项竞赛开始,到2011年,错误率从大约32%-34%下降到了30%。

突破性的成就

2012年,多伦多大学的两位学生Alex Krizhevsky和Ilya Sutskever,在他们的导师Geoffrey Hinton(正是重新推广了反向传播算法的那位)的指导下,构建了一个神经网络,将错误率降低到了15%。这比前一年25%的错误率大幅下降。所有人都感到非常震惊,因为在此之前,即使将错误率降低1%都异常困难。然后这篇论文出现了,在短短一年内将错误率降低了整整10%。正是从那时起,大家开始注意到并认为,也许神经网络确实有效。

当时这些网络使用起来仍然非常复杂。Alex Krizhevsky是一位出色的程序员,这个网络运行良好很大程度上归功于他的编程技巧。但事实是,这些网络重新回到了聚光灯下。

后续发展与现状

自2012年以来,当然,许多人已经将这些网络用于解决许多不同类型的问题。现在,ImageNet的错误率已经低于5%,并且已经不再作为竞赛项目。因为如果你训练一个人来分类这些图像,他也会得到大约5%的错误率。

这是因为,举个例子,ImageNet中有非常多不同品种的狗,共有118个不同的犬种。要区分一个品种和另一个品种通常相当困难。你或许认识自己的狗,认识朋友的狗,但认识不了更多。所以,即使是人类在图像分类方面也表现得不太好。现在,机器的表现基本上和人类一样好,甚至可能更好。

技术进步的本质

我们今天看到的进步,是始于40年代的大量形式化思考、始于60年代并在90年代末得到完善的大量技术思想的成果。在过去的10年里,这些核心思想本身并没有太大变化。我们基本上仍然在使用90年代初发现的同类思想,但我们极大地增强了它们的能力,并围绕这些思想构建了许多非常巧妙的技术或“技巧”,使它们的效果远比90年代时好得多。

以下是推动进步的几个关键因素:

  • 计算机速度更快。
  • 我们拥有更多的数据来训练这些模型。
  • 90年代还没有发明GPU,现在我们可以利用它们来减少训练这些网络所需的时间。

总结

本节课中我们一起学习了现代深度学习的起点,了解了2012年ImageNet竞赛如何成为关键的转折点,并认识到当前深度学习的巨大成功并非源于全新的理论突破,而是基于几十年前的思想,在更强大的计算能力、更丰富的数据和更高效的硬件(如GPU)支持下实现的。我们研究神经网络的思考方式的演变,也将围绕深度学习研究大量的相关技术。

10:感知机模型 🧠

在本节课中,我们将要学习一个非常经典且简单的机器学习模型——感知机。感知机是神经网络和深度学习的基础,它是一种用于解决二元分类问题的模型。我们将了解它的工作原理、如何做出预测,以及它与我们之前学过的线性回归模型有何不同。


感知机简介

上一节我们介绍了用于预测连续值的线性回归模型。本节中,我们来看看一个用于分类的简单模型——感知机。

感知机是一个古老的模型。它最初由弗兰克·罗森布拉特(Frank Rosenblatt)提出,他建造了一台机器,用于区分左侧打孔和右侧打孔的穿孔卡片。

感知机是一个分类器,这与我们之前学习的回归模型(回归器)不同。

感知机接收一个输入 x,并预测输出 +1-1。因此,它是一个二元分类器。

它的工作方式如下:假设输入 X 是一个 D 维向量。模型还有一组同样是 D 维的参数 w。它计算 w 的转置与 x 的点积(w^T x)。

到目前为止,它的计算步骤与线性回归相同。不同之处在于,感知机不会直接输出这个值,而是会应用一个 sign 函数(符号函数)。

sign 函数非常简单:如果输入参数为正数,则输出 +1;如果输入参数为负数,则输出 -1。因此,感知机输出的是参数的符号。

以下是感知机的预测公式:

预测值 = sign(w^T x)

这就是我们的分类器模型——感知机。到目前为止,它并不复杂。


如何训练感知机

现在,我们想了解如何为感知机找到正确的参数 w。就像我们专注于如何找到线性回归的权重一样,我们现在也想找到感知机的权重。我们需要将感知机“拟合”到训练数据集上。

以下是感知机做出预测的方式。在这种情况下,我们有一个更清晰的方式来定义预测是否正确。

如果你为一张橙子的图片预测了“苹果”,那么你显然是错误的。这里没有“你错了多少”的概念。这与预测房价不同,房价预测有“偏离真实价格多少”的概念。对于二元分类器,结果要么正确,要么错误。

因此,我们的目标可以看作是一个 0-1 损失。如果你做出了错误的预测,即真实标签 y_i 与你预测的标签不同,你会受到 1 的惩罚。如果你预测正确,则惩罚为 0

我们希望优化的目标函数是平均错误率,即你在 N 个训练样本上犯错误的平均次数。

这里没有特别复杂的内容。我们只是在一个有非常自然的“正确”概念的环境中。

这个目标函数有一个名字,叫做 0-1 损失


从二元分类到多类分类

如果我们面对的不是二元分类问题,而是有 1000 个类别的分类问题呢?你还能使用这个目标函数吗?

当然可以,因为“正确”的概念依然存在。但是,我们也可以考虑不同种类的目标函数。

以 ImageNet 数据集为例,它包含大约 1000 个类别,其中大约 150 个是不同品种的狗。对于人类来说,区分某些品种的狗已经很困难了,有些品种看起来非常相似。

因此,期望我们的模型从这 150 种狗(或更广泛地说,从这 1000 个类别)中准确预测出正确的品种,可能过于苛刻了。我们该怎么办?

一种思路是,模型可以预测 100 个(或 1000 个)实数,表示属于每个类别的概率。例如,输出“这张图 90% 是猫,但有 10% 的概率是狗”。

那么,如何评估这样的预测呢?我需要一个可以计算的目标函数。如果给你一张自然图片,你如何说它是“90% 的猫”?

我们知道,狗与狗相似,猫与猫相似,但狗和猫是不同的。如果模型把狗误认为猫,我们可能不会惩罚得太重;但如果模型把狗误认为是飞机,我们就应该给予较大的惩罚。

这要求我们了解数据集中对象类别之间的某种关系。因此,我们需要坐下来,为这 1000 个类别定义一个合适的“距离”或相似度度量,然后才能计算预测的惩罚。

另一种方法是,对于每个类别,收集许多人(比如全班同学)对一批图片的看法(多少人认为是猫,多少人认为是狗),从而得到“真实”的概率分布,然后检查模型的预测是否接近这个分布。

所以,当我们有很多类别时,需要以稍微不同的方式思考如何做出预测和定义损失。对于回归,我们只关注成本(误差)。对于两个类别,就是正确或错误。对于 1000 个甚至一百万个类别,你必须更加仔细地考虑如何选择损失函数。


总结

本节课中,我们一起学习了感知机模型。我们了解到:

  1. 感知机是一个简单的二元分类器,其核心公式是 预测值 = sign(w^T x)
  2. 它使用 0-1 损失 作为训练目标,即只关心预测是否正确,而不关心错误的程度。
  3. 当分类问题从简单的二元扩展到多类(如 1000 个类别)时,简单的 0-1 损失可能不再适用。我们需要设计更精细的损失函数,能够考虑类别之间的相似性,并对不同程度的错误给予不同的惩罚。

感知机是理解更复杂神经网络模型的重要基石。在接下来的课程中,我们将探索如何扩展这些概念,以处理更现实、更复杂的分类任务。

11:感知机替代损失函数 🧠

在本节课中,我们将要学习感知机模型中的一个核心挑战——0-1损失函数不可微的问题,并探讨如何通过引入“替代损失函数”来解决这一难题,从而利用成熟的优化技术来训练模型。

概述

上一节我们介绍了感知机的基本原理。本节中我们来看看其训练过程中遇到的一个关键障碍:我们真正希望最小化的目标函数(0-1损失)在数学上难以处理。为了解决这个问题,机器学习领域引入了“替代损失函数”的概念。

0-1损失函数的局限性

感知机的目标是做出正确分类。一个直观的衡量标准是0-1损失:模型预测正确时损失为0,预测错误时损失为1。这个目标函数的好处是含义清晰。

然而,这个目标函数有一个严重的缺点:它不可微。因为它只在两个离散值(0和1)之间跳跃,我们无法对其求导,也就无法使用基于梯度下降等成熟的优化算法来最小化它。

因此,我们需要为这个目标函数寻找一个替代品。我们希望最小化错误的数量(0-1损失),但由于优化技术的限制,我们无法直接最小化它。所以,我们选择调整目标函数,使其变得可微,从而能够利用现成的优化工具。

替代损失函数的概念

这就是为什么在机器学习中,我们使用所谓的替代损失函数。这些损失函数具有两个特点:

  1. 它们是可微的
  2. 我们认为它们在效果上接近0-1损失

让我们通过图示来理解0-1损失的样子。我将以 y * (w^T x) 作为横轴(其中 y 是真实标签,w^T x 是感知机的加权输出)。当这个值为正时,表示预测正确;为负时,表示预测错误。

以下是0-1损失的图示:

  • 在横轴的正半轴(预测正确),损失为 0
  • 在横轴的负半轴(预测错误),损失为 1

正如你所见,这个函数在0点处有一个跳跃,是不可微的

常见的替代损失函数

以下是几种常用的替代损失函数,它们都是连续且可微的。

1. 合页损失

合页损失是一种常用的替代损失。它的设计思想是:如果预测正确且有一定的“安全边际”,则不给予惩罚;如果预测错误,则根据错误的严重程度给予线性增长的惩罚。

合页损失的公式为:
L_hinge = max(0, 1 - y * (w^T x))

让我们分析这个表达式:

  • y * (w^T x) >= 1 时(预测非常正确),损失为 0
  • y * (w^T x) < 1 时,损失为 1 - y * (w^T x),这是一个线性函数。

这个函数是可微的(除了在 y * (w^T x) = 1 这个点),因此我们可以计算梯度并更新参数 w 来减少损失。它是0-1损失的一个良好代理。

2. 指数损失

指数损失是另一种替代损失函数。它的公式为:
L_exp = exp(-y * (w^T x))

它的特点是:

  • y * (w^T x) 为正且很大时(预测非常正确),损失趋近于 0
  • y * (w^T x) 为0时,损失为 1
  • y * (w^T x) 为负时(预测错误),损失会大于1并快速增长。

指数损失与合页损失有所不同。即使预测正确,只要 y * (w^T x) 不是无穷大,它仍然会给出一个微小的惩罚,它“鼓励”模型做出置信度极高的预测。

3. 逻辑损失

逻辑损失函数你可能已经非常熟悉,它在逻辑回归中被广泛使用。其公式通常与对数似然相关。

你可以回家自己绘制这个函数的图像,观察它与0-1损失的关系。

回归问题中的替代损失

需要强调的是,使用替代损失的思想并不仅限于分类问题。在回归问题中我们也见过类似的例子。

我们之前说过,我们可能并不总是喜欢使用平方误差(L2损失)。有时,我们会使用绝对误差(L1损失),或者结合L1和L2的损失(如Huber损失)。这些也都是替代损失函数,你可以根据具体问题选择使用哪一种。

总结

本节课中我们一起学习了以下核心内容:

  1. 感知机模型的目标是最小化分类错误(0-1损失)。
  2. 0-1损失函数不可微,导致无法直接使用基于梯度的优化算法。
  3. 为了解决这个问题,我们引入了替代损失函数(如合页损失、指数损失、逻辑损失)。这些函数连续可微,且行为上近似0-1损失。
  4. 选择哪种替代损失取决于具体要解决的问题,没有绝对的好坏之分。
  5. 使用替代损失的思想也适用于回归任务,如选择L1、L2或Huber损失。

通过引入替代损失函数,我们成功地将一个难以优化的离散目标,转换为了一个可以利用成熟优化技术解决的连续问题,这是机器学习算法得以有效训练的关键一步。

12:引言-感知机-随机梯度下降-核方法

在本节课中,我们将要学习机器学习中的几个核心概念:感知机、随机梯度下降以及核方法。我们将从最简单的线性分类模型开始,逐步深入到更复杂的非线性分类技术。

感知机:第一个神经网络 🧠

上一节我们介绍了线性回归,本节中我们来看看感知机。感知机是你在本课程中将会遇到的众多神经网络中的第一个。

它与线性回归非常相似。但感知机的目标不是用一条直线拟合一系列点,而是找到一条直线,将两组点分开。这条直线的一侧是所有红色点,另一侧是所有蓝色点。

感知机是1958年在康奈尔大学建造的第一个人工网络。正如其建造者弗兰克·罗森布拉特所说,这是第一台能够产生原创想法的机器。

感知机的核心思想是找到一个线性决策边界。其基本公式可以表示为:

y = sign(w·x + b)

其中,w是权重向量,x是输入特征,b是偏置项,sign是符号函数,输出+1或-1代表不同的类别。

随机梯度下降:优化学习过程 📉

理解了感知机的目标后,我们需要一种方法来找到那条最优的分离直线。这就是随机梯度下降的用武之地。

随机梯度下降是一种优化算法,用于最小化模型的误差(或损失函数)。与标准的梯度下降每次迭代使用全部数据计算梯度不同,SGD每次只随机选取一个(或一小批)样本来更新模型参数,这使得它在处理大规模数据时效率更高。

以下是其参数更新过程的核心步骤:

  1. 初始化参数:随机初始化权重w和偏置b
  2. 循环迭代:对于训练集中的每个样本(或小批量样本):
    • 计算当前样本的预测值。
    • 计算预测值与真实标签之间的误差(损失)。
    • 计算损失函数关于参数wb的梯度。
    • 沿梯度反方向更新参数:w = w - η * ∇w, b = b - η * ∇b。其中η是学习率,控制更新步长。
  3. 重复:直到损失函数收敛或达到预设的迭代次数。

核方法:处理非线性问题 ✨

上一节我们介绍了用直线(线性模型)进行分类的感知机。然而,现实世界中的数据往往不是线性可分的。本节中我们来看看核方法如何解决这个问题。

核方法是能够以更复杂的方式分离两组点的技术。想象一条蜿蜒的曲线,它穿过散布的红点和蓝点,但始终将红点保持在其左侧,蓝点保持在其右侧。这比一条直线要复杂得多。核方法构建的模型比线性模型更复杂。

核方法的精髓在于“核技巧”。它通过一个映射函数φ,将原始低维空间中的数据点x映射到高维特征空间。在高维空间中,原本非线性可分的数据可能变得线性可分。感知机等线性模型就可以在这个新空间中找到分离超平面。

我们无需显式计算复杂的高维映射φ(x),只需计算原始空间中数据点的核函数K(x_i, x_j),其等价于高维空间中的内积φ(x_i)·φ(x_j)。常用的核函数包括:

  • 线性核K(x_i, x_j) = x_i·x_j
  • 多项式核K(x_i, x_j) = (x_i·x_j + c)^d
  • 径向基函数核K(x_i, x_j) = exp(-γ * ||x_i - x_j||^2)

总结

本节课中我们一起学习了机器学习中三个紧密相连的基础概念。我们从感知机开始,认识了第一个能够进行线性分类的神经网络模型。为了训练这个模型,我们引入了随机梯度下降算法,它通过迭代更新参数来高效地最小化误差。最后,为了突破线性模型的限制,我们探讨了核方法,它利用核技巧将数据映射到高维空间,从而巧妙地处理了非线性分类问题。这些概念为理解更复杂的现代神经网络和深度学习模型奠定了重要的基础。

13:感知机的随机梯度下降 - 第一部分 🧠

在本节课中,我们将要学习如何通过一种名为“梯度下降”的优化方法来最小化感知机的损失函数。我们将从直观的图像理解开始,逐步推导出更新权重的具体公式。

概述

我们面临的核心问题是:如何最小化损失函数?假设我们有一个权重向量 W,它决定了感知机的预测。我们的目标是调整 W,使得损失值降低。

理解梯度下降

上一节我们介绍了损失函数的概念,本节中我们来看看如何通过计算来优化它。

假设我们的数据集中只有一个样本,因此我们可以将整个损失函数图像绘制在一张图上。当前,由于权重 W 的初始值不合适,我们的损失值可能处于一个较高的位置(例如,预测结果严重为负)。为了减少损失,我们需要沿着能够降低损失的方向移动 W

这个过程的核心思想是计算损失函数关于权重 W 的导数(即梯度)。W 是我们需要改变的变量,而输入 x 和真实标签 y 是固定的。通过计算梯度,我们可以知道 W 应向哪个方向调整以减小损失。

具体步骤如下:

  1. 计算当前 W 下的梯度。
  2. W 向梯度的反方向(即负梯度方向)移动一小步。
  3. 更新后的 W 将对应一个稍小的损失值,意味着预测稍微更准确了一些。

这种方法被称为梯度下降。你总是沿着负梯度的方向“下降”以最小化损失。

那么,何时停止呢?对于合页损失函数,当损失降到0时,梯度也为0,此时没有进一步下降的空间,因此可以停止。而对于指数损失函数,损失曲线渐近于0但永不为0,理论上存在微小的梯度,因此需要设定一个停止条件(如迭代次数或损失阈值)。

计算感知机的梯度

现在,我们来具体计算感知机合页损失的梯度。我们需要求解损失函数 L 关于权重 W 的偏导数 ∂L/∂W

观察合页损失函数的图像,我们可以分两种情况讨论:

以下是两种情况的总结:

  • 情况一:预测正确
    • 当感知机预测正确时,即 ywᵀx 同号,损失值为0。此时,损失函数在该点的梯度为 0
  • 情况二:预测错误
    • 当感知机预测错误时,即 ywᵀx 异号,损失值为 -y * (wᵀx)。此时,损失函数关于 W 的梯度为 -y * x

因此,对于任意一个样本,我们都可以根据其预测正确与否来计算梯度。

权重更新规则

假设我们的数据集中只有一个样本。我们可以将权重 W 初始化为任意值。

以下是更新权重的步骤:

  1. 如果初始化幸运地落在了预测正确的区域(梯度为0),则无需更新。
  2. 如果初始化落在了预测错误的区域,我们可以根据计算出的梯度来更新 W

具体的更新公式为:
W_new = W_old + η * (y * x)

其中:

  • W_old 是旧的权重。
  • η 是学习率,控制每次更新的步长(在当前的简化推导中,我们暂时将其视为1)。
  • (y * x) 是负梯度(因为梯度是 -y*x,负梯度就是 y*x)。

执行这个更新操作后,损失会减少一点点,但通常不会直接变为零。我们需要多次迭代这个过程,逐步降低损失。

总结

本节课中我们一起学习了感知机训练的核心——随机梯度下降法的基本原理。我们了解到,通过计算损失函数关于权重的梯度,并让权重向负梯度方向更新,可以逐步降低模型的预测误差。我们推导出了在合页损失下,权重更新的具体规则:W = W + y * x(当预测错误时)。这为下一节我们将要讨论的在完整数据集上进行迭代优化奠定了基础。

14:感知机的随机梯度下降 - 第二部分 🧠

在本节课中,我们将要学习如何利用随机梯度下降算法来训练感知机模型。我们将深入探讨算法的具体更新规则、其背后的直观理解,以及算法在何种条件下会收敛。

上一节我们介绍了感知机的损失函数,本节中我们来看看如何通过梯度下降来最小化这个损失。

我们知道,逻辑损失函数在原点右侧为零,在原点左侧为负。如果感知机对一个样本的预测正确,那么它很可能位于原点右侧,此时损失为零,损失函数关于权重 W 的导数也为 0。如果感知机预测错误,那么它很可能位于原点左侧,此时损失函数的导数是多少呢?是 -y * x

这为我们提供了一个非常自然的训练感知机的算法。以下是其工作原理:

你拥有你的数据。在每一次迭代中(你会进行很多次迭代),首先初始化感知机的权重,例如初始化为 0。在第 t 次迭代时,你从训练数据(假设有 n 个样本)中随机、均匀地抽取一个样本。我们称这个样本为 x_ω_t, y_ω_t

你在这个样本上运行感知机。如果感知机预测正确,你完全不改变权重。如果感知机预测错误(可以通过比较真实标签 y_ω_t 和感知机的预测 sign(W_t * x_ω_t) 来检查),这意味着我们位于原点左侧。

现在,我将按照负梯度的方向更新我的旧权重。我们知道合页损失函数是这样的:如果我将权重稍微向右移动,就能稍微减少在这个样本上的损失,从而可能对这个新样本做出稍好的预测。

所以我取我的旧权重 W_t,这个梯度是 y_ω_t * x_ω_t,然后将它们相加。这意味着我在旧权重的基础上向右移动了一点,从而改进了在这个特定样本上的损失。

正如她所说,我不必按照梯度的精确幅度移动,我可以移动 0.5 * y * x0.1 * y * x。通常,我可以相对于某个标量常数(我们称之为学习率 η)乘以梯度来移动。在这个表达式中,我将学习率设为 1,所以暂时不用担心它。假设我们向右移动一个单位的梯度。

是否每个人都清楚,这样移动权重会改善感知机的误差?如果你位于非常靠近原点的位置,那么像这样移动会将你带到原点的右侧,现在你在更新后就能正确分类那个特定样本了。

这样的移动会改善感知机在其他样本上的性能吗?一个稍微简单的说法是:权重 W 是一个向量,对于所有样本都是相同的权重。我们改进了在这个特定样本上的性能,它也会改善在相似样本上的性能。假设还有其他样本也处于这个损失水平,一旦我们将权重稍微向右移动,那些样本的性能也会自动改善。

但也可能存在一些样本位于原点右侧,当你将权重向右移动时,它们的误差反而会恶化。对一个样本正确的权重,对另一个样本可能并不正确。因此,感知机从数据中均匀随机地采样一个样本和标签时,它改进了在该样本上的性能。这可能会改善其他一些样本的性能,也可能会恶化另一些样本的性能,但关键在于这个过程会无限进行下去。

这个过程会停止吗?我们将讨论线性可分数据的含义。粗略的理解是:如果存在一个 W,使得感知机在训练数据集上的误差为 0(即所有样本都被正确分类),那么这个方法将找到那个 W。这是一个我们稍后会做的简单证明,这就是数据集线性可分的含义:如果存在一个解,你将在有限次迭代后找到它,从而停止这种误差的来回震荡。

如果不存在这样的 W(例如,所有橙子在这里,所有苹果在这里,但橙子和苹果的点云有重叠),那么就不存在一个能干净地分隔这两个点云的 W。在这种情况下,感知机将像这样在误差之间持续震荡,永远不会停止。

这被称为感知机算法,也是弗兰克·罗森布拉特在60年代实现的。我们将以一个稍微不同的名字来认识它:随机梯度下降。

它被称为随机梯度下降,因为我们在每次迭代中使用梯度来更新权重。它被称为“随机”梯度下降,因为我们从整个数据中选取一个特定样本来计算梯度,并且仅使用该样本来更新权重。因此,当我们更新一次权重时,我们并不确切知道这对所有其他样本做了什么,我们只知道它对这一个特定样本做了什么。这里存在某种随机性,因为我们随机选择想要改进的样本。我们将更深入地探讨这一点,但就目前而言,这是我们实现随机梯度下降最简单的方式。

正如你所见,这并不复杂。只要你有一个可以求导的目标函数,并且有一个可以均匀采样的数据集,你就可以实现随机梯度下降。这就是为什么它既是最简单的方法,也是最通用的方法。


本节课中我们一起学习了感知机的随机梯度下降算法。我们理解了算法的核心更新规则:当预测错误时,按照 W_new = W_old + y * x 的规则更新权重。我们探讨了算法在数据线性可分时会收敛到解,在非线性可分时会持续震荡。最后,我们认识到这个简单算法是更广泛的随机梯度下降方法的一个具体实例,其核心思想是通过随机采样单个样本的梯度来迭代优化模型参数。

15:理解SGD为何在感知机中收敛 🧠

在本节课中,我们将要学习随机梯度下降(SGD)算法在感知机模型中为何能够收敛。我们将通过数学推导来理解,每次权重更新是如何改善模型在误分类样本上的表现的。

上一节我们介绍了感知机的权重更新规则,本节中我们来看看这个更新过程为何有效。

权重更新与预测改善

我们之前通过图示说明了,当权重处于某个位置且模型对某个样本分类错误时,沿着梯度方向更新权重可以改善该样本上的损失。我们可以将这个陈述用数学语言表达。

W_t 为第 t 次迭代时的权重向量。当模型对一个样本 (x, y) 分类错误时(其中 y ∈ {+1, -1}),我们按照以下规则更新权重:
W_{t+1} = W_t + y * x

这个新权重 W_{t+1} 在刚刚被误分类的样本 x 上的预测值,可以通过计算 y * (W_{t+1} · x) 得到。这个值代表了更新后的感知机对该样本的“置信度”。

数学推导:证明预测得到改善

为了证明更新确实改善了模型在该样本上的表现,我们来比较更新前后的预测值。

更新后的预测值计算如下:
y * (W_{t+1} · x) = y * ((W_t + y*x) · x)

将其展开:
= y * (W_t · x) + y * (y * (x · x))
= y * (W_t · x) + y^2 * ||x||^2

由于 y 的取值为 +1-1,因此 y^2 总是等于 1。同时,向量 x 与其自身的点积 ||x||^2 是它的范数平方,这个值总是大于零的。

因此,公式可以简化为:
y * (W_{t+1} · x) = y * (W_t · x) + ||x||^2

在这个等式中:

  • y * (W_t · x) 是更新前模型在该样本上的预测值。根据感知机的错误判断条件,如果模型分类错误,这个值 小于等于 0
  • ||x||^2 是一个 恒大于 0 的标量。

所以,更新后的预测值 y * (W_{t+1} · x) 等于一个小于等于零的数加上一个正数。这意味着,每次对误分类样本进行SGD更新后,模型在该样本上的预测值(置信度)都会严格增加

从几何意义上理解,权重向量被朝着使该样本正确分类的方向推动,且推动的幅度与样本自身的范数有关。

收敛的保证与局限

根据上述推导,在每一次迭代中,只要模型对一个样本分类错误,更新后就一定能改善模型对这个特定样本的分类情况。

然而,这并不意味着同时改善了所有其他样本的分类结果。模型的收敛依赖于一个关键前提:训练数据必须是线性可分的

如果数据线性可分,SGD算法可以逐步修正所有误分类的样本,最终找到一个能够完美分类所有训练数据的超平面,此时算法停止。

如果数据不是线性可分的(例如,存在矛盾的样本,一个正类样本被包围在负类样本中,或者反之),那么SGD可能永远无法收敛。因为修正一个样本的错误可能会导致其他样本被错误分类,算法会陷入无限的振荡之中。

历史背景

值得一提的是,感知机算法由罗森布拉特在20世纪60年代中期提出。而随机梯度下降(SGD)作为一种优化方法,其思想甚至可以追溯到更早。例如,罗宾斯和门罗在1951年的一篇论文中就已经讨论了类似的方法,尽管它当时更多地出现在运筹学文献中,人们并未立即意识到它与后来机器学习中SGD的本质联系。

本节课中我们一起学习了SGD在感知机中收敛的原理。我们通过数学公式证明了每次更新如何提升误分类样本的预测值,并讨论了算法收敛的前提条件(数据线性可分)及其在非线性可分数据上的局限。这是理解更复杂优化算法的基础。

16:SGD的通用形式 🎯

在本节课中,我们将学习如何用更通用的语言重写随机梯度下降(SGD),并理解其在拟合机器学习模型中的核心作用。我们将从定义损失函数开始,逐步推导出SGD和梯度下降(GD)的更新公式,并解释其中的关键概念。


概述

我们将讨论如何用更通用的语言重写优化过程,并在后续课程中沿用此形式。给定任何我们希望求解的目标函数,都可以应用此方法。

假设 L⁽ⁱ⁾ 是模型在数据集中第 i 个样本上的某种损失。这是我们赋予它的名称。它是你选择的某种替代损失函数。

拟合我们的机器学习模型,等同于最小化整个数据集上的平均损失。我们希望找到能最小化此目标函数的 W*。

我们假设此目标函数是可微的,因此可以对 L⁽ⁱ⁾ 关于权重 W 求导。


随机梯度下降(SGD)的引入

这便将我们引向了SGD。在每次迭代中,我们可以从数据集中均匀随机地采样一个样本。我们有一个权重 wₜ(我用括号表示这是第 t 次迭代的权重)。

在每次迭代中,我们随机采样一个样本,称其索引为 ωₜ。我们计算该特定损失在当前权重向量 wₜ 下关于 w 的导数,然后沿着负梯度的方向更新权重向量 wₜ

通常,我们不会简单地用一个单位的梯度来更新权重,而是用一个标量参数 η 来缩放梯度。η 被称为学习率,它大于 0。你稍后会明白它为何重要,但目前它只是我们应用于梯度的一个缩放因子。这就是SGD。

wₜ₊₁ = wₜ - η * ∇L⁽ωₜ⁾(wₜ)

这两个公式在某种意义上是一种非常通用的拟合模型的方法。任何时候,只要你有一个具有合理损失函数的模型和一个包含 n 个样本的数据集,你都可以运行这个方法来拟合模型。

我们已经为感知器模型这样做了。如果你好奇,可以回家为线性回归尝试这个方法。你知道线性回归的解析解,你可以为线性回归运行这个方法,并检查是否能得到与你已知的闭式解相同的答案。

你应该得到相同的答案。我们沿着负梯度的方向下降,因为函数的导数指向这个方向。你不必只选取一个特定样本 ωₜ,你可以选取10个样本,可以选取100个样本。通常,你可以选取整个数据集来计算梯度。


从SGD到梯度下降(GD)

我可以重写这个问题。我不必像上面那样写,我可以写成:w* 是 arg min over w of L(w),其中 L(w) 是所有小损失的平均值。

现在,我可以用梯度下降(而不是随机梯度下降)来求解这个方程。在这个目标函数中没有求和的概念,我可以直接求导。

wₜ₊₁ = wₜ - η * ∇L(wₜ)

一系列函数之和的导数是什么?和的导数就是各个导数的和。因此,一堆量的平均值的导数就是所有这些量导数的平均值。

所以在这种情况下,上式等于 wₜ - η * (1/n) * Σ ∇L⁽ⁱ⁾(wₜ)。这被称为梯度下降(GD),而不是随机梯度下降,因为我们没有采样任何东西,而是取了所有样本并平均了梯度。😊

这是拟合感知器模型的另一种方法。你可以在家尝试,会发现它的效果稍差一些。


术语与重要概念

好的。所以,这只是一些术语或重写。如前所述,ωₜ 是一个随机变量,取值范围从1到n,它告诉我们从数据集中采样了哪个索引(哪个图像)。

传统上,将 dL/dW 写作 ∇L,这只是同一量的不同名称。然而,需要记住的重要一点是:标量关于向量的梯度是一个向量

损失是一个实数值。当你求损失关于权重的导数时,你是在问自己:如果我以某种方式扰动我的权重,这个标量会如何变化?如果你扰动权重的第一个元素,你会得到这一项,它是损失关于第一个权重的导数;如果你扰动第二个权重,你会得到这一项,它是损失关于第二个权重的导数,依此类推。因此,损失关于一组权重(即一个向量 w)的梯度也是一个向量。

这在现在看来非常简单,但当你实现反向传播时,我保证你们中有一半人会犯这个错误。简单来说,如果我们的权重是 P 维向量。

那么损失的导数也是一个 P 维向量。如果 L 是标量,这是成立的。如果 L 是一个向量会发生什么?我也可以求一个向量关于另一个向量的导数,结果将是一个矩阵。

所以,向量和矩阵的导数在某种意义上是非常简单的量。思考这个问题的唯一方式是:如果 F(w) 是一个取值在 Rᵐ 中的函数,那么 dF(w)/dw 是一个取值在 Rᵐˣᵖ 中的函数。这个函数的第 ij 个元素恰好是 dFᵢ/dwⱼ,即你函数(导数的分子)的第 i 个元素关于第 j 个权重的导数。

所以,这看起来像一个矩阵,可能看起来有点复杂,它是一个向量关于另一个向量的导数,但从根本上说,它只是所有小标量导数排列成的一个矩阵。



总结

在本节课中,我们一起学习了随机梯度下降(SGD)的通用数学形式。我们定义了基于单个样本的损失 L⁽ⁱ⁾,并说明了最小化平均损失是模型拟合的目标。我们推导了SGD的更新规则 wₜ₊₁ = wₜ - η∇L⁽ωₜ⁾(wₜ),其中 ωₜ 是随机采样的索引。接着,我们通过考虑所有样本的平均损失,自然过渡到了梯度下降(GD)的更新规则 wₜ₊₁ = wₜ - η∇L(wₜ)。最后,我们强调了梯度的维度:标量关于向量的梯度是一个同维度的向量,而向量关于向量的梯度是一个矩阵,这是理解后续算法实现的关键基础。

17:感知机的对偶表示 👁️‍🗨️

在本节课中,我们将要学习感知机算法的另一种表达形式,称为“对偶表示”。我们将从回顾感知机的权重更新规则开始,逐步推导出对偶形式,并分析其含义与计算特性。

概述

我们将讨论的内容被称为感知机的对偶表示。首先,让我们再次写出感知机的权重更新方程。

权重更新方程的回顾

我们设定学习率恰好为1。权重更新规则可以写作:
w_{t+1} = w_t + y_i x_i
其中,(x_i, y_i) 是在第 t 次迭代中被错误分类的样本。

为了简化推导,我们假设初始权重向量 w_0 = 0。我们从零向量开始,然后持续运行随机梯度下降(SGD)算法。

权重的线性组合表示

一个关键的观察是:最终的权重向量 w_T 是所有错误分类样本的线性组合。

如果 w_0 = 0,那么:

  • w_1 = 0 + y_1 x_1 (第一个错误)
  • w_2 = w_1 + y_2 x_2 (第二个错误)

即使中间有样本被正确分类,最终找到的权重 w 始终是所有错误样本的线性组合。因此,我们可以将其写作:
w = Σ_{i=1}^{n} α_i y_i x_i

在这个公式中:

  • y_i 是第 i 个样本的真实标签(+1 或 -1)。
  • x_i 是第 i 个样本的特征向量。
  • α_i 是一个非负整数,代表在训练过程中,模型在第 i 个样本上犯错的次数。

理解系数 α_i

这是一个需要仔细思考的概念。假设我们运行感知机算法100万次迭代,共有100个样本(n=100)。在训练过程中:

  • 在第一个样本上,我们可能犯了50次错误。
  • 在第二个样本上,我们可能犯了73次错误。
  • 在第三个样本上,我们可能犯了157次错误。
    那么,对应的 α_i 值就是50, 73, 157,等等。

这个表达式是正确的,因为我们从零向量开始,每次犯错,我们就把对应的 y_i x_i 加到权重上。因此,最终的解可以写成这种求和形式。

α_i 的值是在训练完成后才知道的。我们无法预先知道它们。它们是在训练感知机过程中,在每个样本上累积的错误次数。

α_i 的数量正好等于训练样本的数量 n。其中一些可能为零,因为你可能从未在该样本上犯错,或者从未采样到该样本。

假设我们运行非常长的时间,并且每个样本都被采样了很多次。如果数据是线性可分的(即存在一个超平面 w 能将数据完美分开,达到零错误率),那么这些 α_i 值最终将收敛(停止增长)。这是因为感知机停止更新权重,也就停止了犯错,从而停止了 α_i 的增加。

这提供了一种判断训练何时停止的方法:你可以将 α_i 记录为一个向量。一旦这个向量停止变化,你就知道感知机已经拟合完成,无需继续训练。

对偶表示的定义

这些变量 α_i 被称为感知机的对偶表示。在模型存储时,你可以选择存储权重向量 w,也可以选择存储对偶变量 α

  • 权重 w 是一个实数向量,有 p 个维度(特征数量)。
  • 对偶变量 α 是一组非负整数,有 n 个值(样本数量)。

你可以根据情况选择存储哪一个。如果你处理的是非常高维的数据(例如 p 很大),而样本数量 n 相对较小,那么存储 α 可能更节省空间。这强调了权重向量的大小和对偶向量的大小是不同的概念。

对偶形式的预测函数

现在,让我们清晰地重写公式。我们之前的感知机预测函数是:
f(x) = sign(w^T x)

现在,我们说最终的解 w* 恰好是上面的线性组合表达式。我们可以将这个表达式代入预测函数中的 w*

f(x) = sign( (Σ_{i=1}^{n} α_i y_i x_i)^T x )

根据线性代数,我们可以将求和移到内积内部:

f(x) = sign( Σ_{i=1}^{n} α_i y_i (x_i^T x) )

我们并没有做任何魔法变换,只是将对偶表示声称的答案代入了我们的预测器 f

在这个公式中,需要特别注意一项:x_i^T x。这是你的输入向量之间的内积x_i 是一个向量,x_i^T x 是一个实数。任何时候你看到输入之间的这种内积,都可以做一些非常巧妙的事情(我们很快会看到)。但现在,请记住权重可以用这个公式表示。

计算复杂度分析

现在,给定任何新图像 x 进行预测时,你必须计算整个求和式。

以下是计算这个求和式所需的操作:

  • 求和中有多少项?有 n 项(样本数量)。
  • 每一项涉及什么操作?计算一个 p 维向量(或 d 维向量)的内积 x_i^T x

因此,计算这个函数的时间复杂度大约是 O(n * p) 次浮点运算(flops)。

如果我们使用原始的权重形式进行预测 f(x) = sign(w^T x),需要多少次浮点运算?

  • 如果 xp 维向量,w 也是 p 维向量。
  • 那么需要 p 次乘法运算,即 O(p) 次浮点运算。

显然,在每次进行预测(推理)时,使用对偶形式 O(n*p) 比使用原始权重形式 O(p) 要消耗更多的计算资源。

总结

本节课中,我们一起学习了感知机的对偶表示:

  1. 我们推导出,最终的感知机权重可以表示为所有错误分类样本的线性组合 w = Σ α_i y_i x_i,其中 α_i 是样本 i 上犯错的次数。
  2. 系数 α_i 构成了感知机的对偶表示,与原始的权重表示 w 是等价的,但维度不同(α 的维度是样本数 nw 的维度是特征数 p)。
  3. 我们得到了对偶形式的预测函数 f(x) = sign( Σ α_i y_i (x_i^T x) )
  4. 我们分析了对偶形式在预测时的计算复杂度为 O(n*p),高于原始权重形式的 O(p)。这种计算上的代价是将计算负担从训练阶段(学习 α)转移到了推理阶段。

对偶表示的重要性将在后续学习支持向量机(SVM)时得到充分体现,因为它是理解核方法(Kernel Method)的关键基础。

18:非线性分类器 🧠

在本节课中,我们将要学习如何通过特征映射(Feature Mapping)将非线性问题转化为线性问题,从而使用我们熟悉的线性模型(如线性回归、感知机)来解决。核心思想是:通过一个函数 φ(x) 将原始输入数据映射到一个新的、更高维的特征空间,在这个新空间中,原本非线性可分的数据可能变得线性可分。

从多项式回归说起

上一节我们介绍了线性模型。本节中我们来看看,当数据关系是非线性时,我们该如何处理。

你是否知道如何拟合多项式回归?你在高中时很可能已经做过类似的事情。

假设我有一个函数 y = f(x)。如何为我的数据拟合一个二次多项式呢?

我的输入是实数值,输出也是实数值。我想为这个问题拟合一个线性回归模型。或者,更准确地说,我想为这些数据拟合一个二次多项式。

如何拟合一个二次多项式呢?我取我的输入 x,然后将它们转换成这样一个特殊的向量:[1, x, x²]。现在我的模型中有三个参数,我的 y 可以表示为:y = a * 1 + b * x + c * x²。这就是一个通用的二次多项式。

但正如你所见,我可以将这个表达式视为 w(权重向量)与某个线性向量 z 的点积。我原本是标量输入,但将其转换成了三维输入。现在我有一个三维权重向量,就可以进行线性回归了。你们以前都做过这个,对吧?

简单来说,我们可以通过将输入扩展为这些单项式项的形式来拟合多项式。然后,我们就可以拟合一个非线性函数。这不再是一个线性回归,但我们仍然可以通过将 x1 视为一个新“虚构”输入的不同维度来“作弊”。

这就是我们拟合多项式回归的方法。你可以对任何阶数的多项式进行此操作。这是最古老的技巧:我们将看似复杂的东西,通过增加输入空间的维度,使得我们可以使用一个更简单的模型(在这里是线性模型)来拟合它。

在这个例子中,我们只知道如何拟合线性回归,但我们想拟合一个二次函数。我们可以通过假装这些是特征(features)来将二次函数重写为一个线性模型。特征之间不必相互独立,特征是你选择的任何东西。

特征空间的一般概念

这个概念是通用的。通常,你可以取你的输入 x,然后将它们转换到一个特征空间。让我们称这些特征为 φ(x),然后拟合一个模型:ŷ = wᵀ φ(x)

现在,你能告诉我如何拟合下面这个特定的分类问题吗?

假设我正在做分类。你可以对感知机做同样的事情。就像我们之前做的感知机是 sign(wᵀ x),你现在可以做 sign(wᵀ φ(x)),没什么大区别。

假设我们的正类样本(+)都靠近原点,而负类样本(-)都分布在离原点大致相同距离的位置。不存在一个线性的超平面来分离这两类数据。你会怎么做?

这是二维数据。你可以做一个高斯变换,或者用极坐标(r 和 θ)来表示这些点。当你观察这两团点云时,会发现它们距离原点的半径明显不同。因此,在极坐标的第一个维度上,你会看到一个能将它们分开的超平面。所以,你将拟合一个圆。但为了使用线性回归来拟合这个圆,你必须首先以某种方式转换输入。

圆是一个非线性函数。圆的方程是 x₁² + x₂² = C(C为常数)。这显然是 x₁x₂ 的非线性函数。

但是,假设我们只想使用线性回归来拟合它,你必须首先将 x₁x₂ 转换到某个新的坐标系中,并确保在这个新坐标系中,圆看起来像一个平面。极坐标就是这样一个坐标系的例子。在极坐标中,圆就是一个平面,对吧?

这是一种非常直观的方式来记住核技巧(Kernel Trick):任何时候,当你无法拟合一个超平面(即无法用线性模型分离两团点云)时,如果你将输入转换到另一个坐标系中,那么你就可以在新的坐标系中拟合一个线性模型。

另一个图示例子

这些是我们的蓝色点,这些是我们的红色点。显然,不存在一个能分隔两者的超平面。但如果你想象将它们转换到某个其他函数空间(在这个例子中,它比二次项或极坐标更复杂),那么在这个新空间中,分隔函数就是一个线性函数。

具体计算

就像我们对二次多项式所做的那样,我们实际上是在为自己创建一个特征空间 φ(x)。例如,如果 x 是实值输入,那么 φ(x) 可以是一个三维向量:[1, √2 x, x²]。这里的 √2 并不关键,只是为了在计算点积时得到整洁的结果(例如得到 2 而不是其他值)。现在你的 w 也必须是三维的,但你可以拟合一个线性模型。

你也可以对更高维的输入做同样的事情。所以,如果你有一个二维输入 x(即 x 本身是二维的),那么一个二次特征映射 φ(x) 可以是这样的:这些是展开 (x₁, x₂)² 时得到的所有单项式。

以下是可能的特征向量构成:

  • 1
  • √2 x₁
  • √2 x₂
  • x₁²
  • x₂²
  • √2 x₁x₂

正如我所说,你可以将输入转换为 φ(x),然后就可以毫无顾虑地运行感知机算法。

与之前一样,带有特征映射的感知机也有对偶表示。α 值(阿尔法)是相同的,它们仍然代表错误分类的次数。现在,每当你在线性感知机算法或 SGD 中看到 x 时,只需将其替换为 φ(x),无需任何其他更改。

我们可以将预测器写为应用于以下求和结果的符号函数:
sign( Σᵢ αᵢ yᵢ φ(xᵢ)ᵀ φ(x) )

你再次看到了内积:φ(xᵢ)ᵀ φ(x)。这里 φ(xᵢ) 是你所有的训练输入,φ(x) 是你的测试数据点。

因此,对于测试数据 x,预测步骤如下:

  1. 首先,取测试数据 x,使用你为 φ 定义的任何函数,创建 φ(x)
  2. 拥有你所有的训练数据及其对应的 φ(xᵢ)
  3. 计算上述求和。
  4. 这就是你进行预测的方法。

到目前为止,我们还没有做任何非常复杂的事情。我们只是引入了特征空间的概念,并用 φ(x) 替换了线性模型中看到的所有 x

一个关键问题

我们不知道如何计算 φ(x)。我给了你几个例子,你可以利用直觉来计算 φ(x)(例如多项式展开、极坐标变换)。但在一般情况下,你并不知道如何计算 φ(x)。这正是核方法(Kernel Methods)要解决的核心问题,它允许我们在不知道 φ(x) 显式形式的情况下,直接计算内积 φ(xᵢ)ᵀ φ(x)。这将是后续课程的重要内容。

总结

本节课中我们一起学习了非线性分类的核心预处理思想——特征映射。我们了解到,通过一个函数 φ(x) 将数据从原始空间映射到高维特征空间,可以在新空间中用线性模型解决原始空间中的非线性问题。我们以多项式回归和圆形决策边界为例,具体说明了如何构造特征映射。最后,我们指出了直接设计 φ(x) 的困难,这为引入强大的核方法奠定了基础。

19:核方法入门 🧠

在本节课中,我们将要学习核方法的基本概念。核方法是机器学习中一个强大的工具,它允许我们在不显式计算高维特征映射的情况下,在高维空间中进行计算。理解核方法对于后续学习卷积核等更具体的概念至关重要。

从内积到核函数

上一节我们介绍了特征映射的概念。在之前的表达式中,我们经常看到内积运算,例如 ΦᵀΦxᵀx。核方法的核心思想正是利用了这种内积结构。

任何出现内积的地方,你都可以通过使用核方法来重写它,从而减少计算求和所需的浮点运算次数。

以下是核方法的基本形式。假设我们的特征映射 Φ(x) 是一个二次映射:Φ(x) = [1, √2 x, x²]ᵀ。对于数据集中的另一个样本 x‘,其特征映射为 Φ(x‘) = [1, √2 x‘, x‘²]ᵀ

当我们计算内积 Φ(x)ᵀ Φ(x‘) 时,实际上是将这两个向量相乘:
Φ(x)ᵀ Φ(x‘) = 1*1 + (√2 x)*(√2 x‘) + (x²)*(x‘²) = 1 + 2xx‘ + x²x‘²

仔细思考,你会发现这个结果等于:
(1 + x * x‘)²

这是一个非常重要的结论:这两个特征向量的内积可以表示为一个简洁的函数。这个函数就被称为核函数

核函数的直观理解 🧩

一种简单直观的理解方式是:当 xx‘ 相似时,这个核函数的值会很大。

例如:

  • 如果 x = 1x‘ = -1, 那么 (1 + 1*(-1))² = 0
  • 如果 x = 1x‘ = 2, 那么 (1 + 1*2)² = 9

核函数本质上是衡量两个输入之间相似性的函数。你可以设计任何你认为能衡量两个输入相似性的函数作为核函数,上面这个就是其中一个例子。

因此,核函数是对“相似性”这一概念的正式化。它是一个以两个输入为参数并返回一个实数的函数。对于我们来说,xx‘ 是两个输入,输出是一个实数,代表它们之间的相似度。

如果你对“两个输入何时相同”有直观的理解(例如,两幅图像都是橙色,或都是黑色),那么你可以简单地写一个Python函数来检查两幅图像是否相似,并将其作为核函数。任何你对事物相似性的直观理解,都可以写成一个函数。你不再需要费力地去构造一个显式的特征空间。

在上面的表达式中,并没有显式的 Φ(x)Φ(x) 是隐含的。你只需要给我这个核函数,我就可以假装知道 Φ(x) 是什么。

其他类型的核函数

二次核并非唯一的核函数,还存在许多其他类型。

这是二次核的向量版本公式:
K(x, x‘) = (xᵀ x‘ + c)²

假设 x 是一个 p 维向量,xᵀ x‘ 是两个向量的内积,是一个实数。加上常数 c 再平方,结果仍然是一个实数。核函数总是返回实数,这一点毫无疑问。它们可以接受任何输入,但必须返回一个实数。

这是另一个核函数的例子,称为高斯核或径向基函数核:
K(x, x‘) = exp(-||x - x‘||²)

这个函数的特性是:

  • 如果 xx‘ 差异很大,那么这个核函数返回值将非常接近 0(因为是指数函数的负大数次方)。
  • 如果 xx‘ 非常相似,甚至完全相同,那么这个函数返回值是 1

所以,核函数就是相似性度量函数,是衡量两个输入相似度的任何方法。

总结

本节课中,我们一起学习了核方法的基础知识。我们了解到核函数是一种衡量两个数据点相似度的函数,它能够隐式地将数据映射到高维空间进行计算,而无需显式构造复杂的特征映射。我们探讨了二次核和高斯核的例子,并理解了核函数的核心在于其返回一个代表相似度的实数值。掌握核函数的概念是理解后续更复杂的机器学习模型(如支持向量机、卷积神经网络中的卷积核)的重要基石。

20:核感知机算法详解 🧠

在本节课中,我们将学习核感知机算法。核感知机与特征空间中的感知机在本质上完全相同,只是我们将以一种不同的方式来表达和实现它。

上一节我们介绍了感知机的基本原理,本节中我们来看看如何通过“对偶形式”和“核技巧”来构建核感知机。

算法初始化

在开始训练之前,我们需要初始化对偶变量。由于尚未对任何样本做出错误判断,因此所有初始值都应设为0。

公式表示:
α_i = 0, for i = 1 to n

迭代训练过程

在每一轮迭代中,算法会从数据集中随机抽取一个样本及其对应的标签。

假设我们的数据集为 D,当前迭代中抽样的样本记为 x_ωt,其标签为 y_ωt

判断预测错误

如何检查预测是否错误?在标准感知机中,我们要求 y * (w^T * x) > 0。现在,我们的权重向量 w 由对偶变量和样本特征表示。

权重向量公式:
w = Σ (α_i * y_i * x_i), i from 1 to n

在每次迭代中,α_i 的值会更新,但基于当前的 α_i 值,我们可以得到当前感知机所维护的 w。因此,检查感知机是否犯错,就等价于计算以下求和式。

预测判断公式:
Σ (α_i * y_i * <φ(x_i), φ(x_ωt)>)

我们只是将 w 的表达式代入原判断式,并用特征映射 φ 后的内积来表示。如果该求和结果不符合符号要求,则判定为预测错误。

更新规则

如果检测到预测错误,我们需要更新模型。在对偶形式的感知机中,没有直接的权重 w,只有对偶变量 α

因此,当出现错误时,我们只需将当前抽样样本 x_ωt 对应的对偶变量 α_ωt 增加1。

更新公式:
α_ωt = α_ωt + 1

这类似于在原始SGD感知机中更新权重 w 的操作。

算法运行与收敛

在下一轮迭代中,我们抽样新的数据点,再次计算整个求和式。如果发现错误,则再次增加对应 α 值。

随着迭代次数增加,部分样本的 α 值会不断增大。最终,当算法在所有样本上不再犯错时,α 值将停止更新,此时核感知机模型即训练完成。

这个算法的核心在于,我们无需显式地存储和计算高维权重向量 w,只需记住对偶变量 α 即可。

核函数的作用

这个算法被称为核感知机,原因在于我们使用了特征映射 φ 的内积。

我们可以将这个内积写成一个核函数 K

核函数定义:
K(x_i, x_j) = <φ(x_i), φ(x_j)>

核函数接收两个输入,返回一个实数,用于衡量这两个输入之间的相似性。因此,实现核感知机时,我们既不需要权重 w,也不需要知道特征映射 φ 的具体形式,只需要能够计算核函数 K 即可。

以下是核感知机算法的核心预测步骤:

预测公式(使用核函数):
Σ (α_i * y_i * K(x_i, x_ωt))

算法的直观理解

这个求和式捕捉了抽样样本 x_ωt 与训练集中所有其他样本 x_i 的相似性。

你对你新抽样图像的输出预测,是基于它与训练集中所有其他图像的相似度的函数。

让我们更细致地思考一下:例如,如果 x_ix_ωt 非常相似,并且 α_i 的值很大(意味着过去在该样本上犯了很多错误),那么在预测 x_ωt 时,y_i 的贡献(权重)就会很大。

核心思想:
我们预测 x_ωt 的输出,表示为所有与 x_ωt 相似的图像的输出的加权和,权重则由过去在这些相似图像上犯错的次数(即 α_i)决定。

如果训练集中的某个图像与你刚抽样的图像非常相似,并且你过去在该图像上犯了大量错误,那么你就知道应该在这个求和式中更多地参考它的输出来修正当前预测。


本节课中我们一起学习了核感知机算法。我们了解到,核感知机通过对偶变量 α 隐式地表示模型权重,并利用核函数 K 在高维特征空间中计算样本相似性,从而避免了直接处理高维特征向量的复杂性。算法通过迭代抽样、核函数计算预测、判断错误并更新对偶变量的过程进行训练,最终得到一个基于样本相似性和历史错误进行预测的分类器。

21:Gram矩阵 🧮

在本节课中,我们将学习Gram矩阵的概念。我们将了解它在核感知器算法中的作用,以及如何通过预计算Gram矩阵来优化算法性能。同时,我们也会探讨其计算上的挑战和一些优化方法。

Gram矩阵的引入与定义

上一节我们介绍了核感知器的运行原理。本节中我们来看看如何优化其计算过程。

运行核感知器并不廉价,因为需要不断计算内积或核函数。但请注意,x_omega_t是训练数据集中的一个样本。如果能预先为所有样本对计算核函数值,就无需重复计算。

以下是具体做法:

  1. 获取你的数据。
  2. 预先计算所有样本对的核函数值,例如 k(x1, x2), k(x2, x3) 等。
  3. 之后,只需代入这些值,整个求和过程可以写成一个矩阵向量乘法。

其中,向量是阿尔法值(alpha)构成的向量,矩阵则是由所有核函数值构成的矩阵。

这个矩阵有一个名称,叫做Gram矩阵

Gram矩阵是一个矩阵,其第 i 行第 j 列的元素是核函数 k 应用于第 i 个输入和第 j 个输入的结果。公式表示为:
G[i, j] = k(x_i, x_j)
因此,它就是一个包含所有核函数值的矩阵。

Gram矩阵的应用与计算考量

正如之前所说,一旦计算出Gram矩阵(G),就可以将整个求和写成矩阵向量乘积的形式,其中矩阵是 G,向量是 alpha * y(此处 y 是标签向量)。

需要记住一个重要细节:阿尔法值(alpha)在每次迭代后都会变化,因为分类错误的次数在每次迭代后都可能更新。

必须认识到,Gram矩阵通常不是小对象。如果你有100万张图片,那么Gram矩阵中的元素数量将达到10^12(1万亿)个,这是一个非常庞大的数字。

因此,尽管核方法看起来像是基于线性函数的简单模型,但实际运行起来计算量非常巨大。事实上,直到大约2010至2012年,工业界中许多机器学习算法本质上都是基于核方法的变体。

优化技术与方法

为了减少计算这类求和(本质上是矩阵向量乘积)所需的浮点运算次数,人们发展了大量技术。

例如,可以将矩阵进行LU分解或其他因子分解,并随时间更新这种分解,等等。

这些方法通常被称为Nyström方法。你可以在维基百科或其他资料上阅读更多相关内容。

总结

本节课中,我们一起学习了Gram矩阵。我们了解到,通过预计算所有训练样本对的核函数值来构建Gram矩阵,可以将核感知器中的重复计算转化为高效的矩阵运算。同时,我们也认识到Gram矩阵可能非常庞大,计算成本高,并简要介绍了一些如Nyström方法之类的优化技术来应对这一挑战。

22:Mercer定理与核函数验证 🔍

在本节课中,我们将要学习如何判断一个函数是否是一个合法的核函数。核函数是衡量输入之间相似度的工具,但并非所有函数都能作为核函数使用。我们将通过Mercer定理来理解核函数的数学条件,并学习如何在实际中验证一个核函数的有效性。

核函数的基本要求

上一节我们介绍了核函数是衡量输入相似度的工具。本节中我们来看看,一个函数要成为合法的核函数,需要满足哪些条件。

核函数是一个关于两个输入 xx' 的函数。首先,核函数必须是对称函数。这意味着交换两个输入的顺序,函数值保持不变。

公式: k(x, x') = k(x', x)

Mercer定理的核心条件

除了对称性,核函数还需要满足一个更本质的条件,这由Mercer定理描述。该定理指出,如果一个对称函数 k 满足特定的正则性条件,那么它可以被表示为某个特征空间中的内积。

直观上,这个条件类似于矩阵的正半定性。对于一个矩阵 A,如果对于所有向量 x,都有 xᵀAx ≥ 0,那么 A 是正半定的。Mercer定理将这个概念推广到了函数空间。

对于核函数 k,其条件表述为:对于定义域 X 上的任意函数 f,以下积分必须非负。

公式: ∬ k(x, x') f(x) f(x') dx dx' ≥ 0

你可以将 f(x)f(x') 想象成无限维的向量,这个积分条件就类似于无限维向量空间中的二次型非负条件。

从理论到实践:Gram矩阵验证

理论上我们需要验证上述积分条件,但在实际机器学习任务中,我们只有有限的数据点。因此,我们可以通过检查由数据构造的Gram矩阵是否正半定,来验证核函数在给定数据集上的有效性。

以下是验证步骤:

  1. 给定数据集 {x¹, x², ..., xⁿ} 和一个候选核函数 k
  2. 计算Gram矩阵 G,其中每个元素 Gᵢⱼ = k(xⁱ, xʲ)
  3. 检查矩阵 G 是否为正半定矩阵。

为什么这有效?如果核函数 k 是合法的,那么存在某个特征映射 φ,使得 k(xⁱ, xʲ) = φ(xⁱ)ᵀ φ(xʲ)。由此可以证明,对于任意向量 u,都有 uᵀGu ≥ 0,这正是正半定矩阵的定义。

代码逻辑:

# 假设已计算得到Gram矩阵 G
import numpy as np

# 计算G的特征值
eigenvalues = np.linalg.eigvals(G)

# 检查所有特征值是否非负(考虑数值误差)
is_positive_semidefinite = np.all(eigenvalues > -1e-10)

if is_positive_semidefinite:
    print("该核函数在给定数据上是有效的。")
else:
    print("该核函数不是有效的。")

核函数的特征分解视角

如果一个核函数满足Mercer条件,那么它可以被分解为一系列特征函数(无限维的特征向量)的加权内积之和。

公式: k(x, x') = Σᵢ λᵢ φᵢ(x) φᵢ(x')

其中,λᵢ 是特征值,φᵢ 是相互正交的特征函数。这类似于矩阵的特征值分解。这些特征函数 φᵢ 就构成了我们寻找的隐式特征空间。

虽然我们可能不知道这些具体的特征函数 φᵢ 是什么(因为我们只定义了核函数 k),但Mercer定理保证了它们的存在。我们可以将所有 φᵢ(x) 拼接成一个(可能是无限维的)大特征向量 Φ(x),从而使得核函数可以表示为 Φ(x)ᵀ Φ(x')。这从概念上连接了核函数与特征空间内积的本质。

总结

本节课中我们一起学习了核函数合法性的验证方法。我们了解到,一个合法的核函数必须是对称的,并且其对应的Gram矩阵对于任何数据集都应是正半定的。Mercer定理从数学上保证了满足这些条件的核函数,必然对应着某个高维(甚至无限维)特征空间的内积。在实际应用中,我们可以通过计算数据Gram矩阵的特征值来快速验证一个核函数的有效性,这比直接构思复杂的特征映射要简单得多。

23:全连接网络入门 🧠

在本节课中,我们将要学习神经网络的一个关键发展——全连接网络。我们将从感知机出发,理解如何通过叠加多层感知机构建更强大的模型。

上一节我们介绍了感知机,它是一种单层神经网络。本节中我们来看看更复杂的结构。

从感知机到全连接网络

我们现在已经知道神经网络的基本形态是感知机,它是一种单层神经网络。

接下来我们将学习全连接网络。这些是比核方法更复杂的模型。

你可以简单地把它想象成一个感知机叠加在另一个感知机之上,然后再叠加一个,如此反复。每个感知机接收来自其下方一层的输入,对数据点(例如红点和蓝点)进行分类,其分类能力会比前一层略有提升,然后将结果传递给下一层。

这将是我们学习的第一个深度神经网络例子。

核心概念与结构

以下是全连接网络的核心运作方式:

  • 层级结构:网络由输入层、一个或多个隐藏层以及输出层组成。
  • 全连接:每一层的每个神经元都与前一层的所有神经元相连接。
  • 前向传播:数据从输入层开始,逐层经过计算,最终得到输出。这个过程可以用以下公式表示:
    a⁽ˡ⁾ = σ(W⁽ˡ⁾ a⁽ˡ⁻¹⁾ + b⁽ˡ⁾)
    其中,a⁽ˡ⁾ 是第 l 层的激活值,W⁽ˡ⁾ 是权重矩阵,b⁽ˡ⁾ 是偏置向量,σ 是激活函数。
  • 逐步优化:每一层都学习从输入数据中提取更抽象或更复杂的特征,使得最终的分类或预测更加准确。

上图展示了全连接网络的结构。可以看到,信息从左侧的输入层流入,经过中间多个隐藏层的处理,最终到达右侧的输出层。每一层的神经元都与相邻层的所有神经元相连。

总结

本节课中我们一起学习了全连接网络的基本概念。我们了解到,全连接网络通过将多个感知机层叠起来,构建了深度神经网络的基础。每一层都接收前一层的信息并进行处理,使得网络能够学习数据中更复杂的模式和关系,从而完成比单层感知机更复杂的任务。这是理解现代深度学习模型的重要一步。

24:学习特征向量 🧠

在本节课中,我们将要学习核函数与特征向量之间的关系,并探讨深度学习如何自动学习特征向量。我们将从核函数的优势开始,逐步过渡到深度学习的核心思想。

核函数的优势

上一节我们介绍了核函数的基本概念。本节中我们来看看核函数相比特征向量的优势。

核函数易于构造。这正是核函数的优点,它比直接处理特征向量要方便得多。

核函数与相似性度量

接下来,我们通过一个例子来理解核函数如何衡量相似性。

假设我给你两个这样的字符串。你认为它们有多相似?我试图让它们相似,所以我猜它们有些相似。这是一个合法的英文单词,而另一个是经过打乱的。你可能听说过,如果保持单词的首字母和尾字母不变,你基本上可以猜出这个单词。这就是我尝试做的事情,并创建了这个字符串。你和我都会同意它们彼此有些相似。再比如另一串完全不同的字符。

如何为字符串编写核函数

那么,如何为字符串编写一个核函数呢?以下是思考步骤。

给定这个字符串,你可以想出某种方法,将这个字符串转换为另一个字符串。人们可能听说过一种叫做编辑距离的方法。编辑距离是指将字符串A更改为字符串B所需的最少字符更改次数。

这是一个你可以用动态规划编写的算法。你可以编写一个Python函数,接收两个字符串并计算它们的编辑距离。

我需要更改多少个字符?这看起来不像我们能写下的任何数学函数。但你可以在Python代码中实现它。你可以检查格拉姆矩阵是否具有非负特征值,并验证这是否是一个合法的核函数。

这就是核函数,因为它是一种度量。因此,核函数可以是非常复杂的东西。取决于你如何构造它们,它们可能看起来不像你在纸上写下的那些漂亮的分析函数。

从核函数到深度学习

从核函数过渡到深度学习相当容易,你只需学习特征向量φ。到目前为止,我们一直在讨论如何构思新的特征向量。在深度学习中,我们将对自动学习特征向量感兴趣。

用一句话概括,这就是深度学习的定义。

总结

本节课中我们一起学习了核函数在衡量复杂数据(如字符串)相似性方面的应用,并理解了其相对于手工设计特征向量的优势。最后,我们探讨了深度学习的核心思想:自动学习有效的特征表示,而无需手动设计核函数或特征映射。

25:随机特征模型 🎲

在本节课中,我们将要学习一种名为“随机特征模型”的简单而强大的方法。它提供了一种无需设计复杂函数,即可构建有效特征向量的途径。

概述

在深入探讨特征向量之前,我们先来看一个简单的案例。在这个案例中,我们以一种非常直接、不复杂的方式来构建特征向量。这种方法源于一篇名为“随机特征模型”的优秀论文,它也是本章的阅读材料。

随机特征模型的核心思想

上一节我们提到了构建特征向量的需求,本节中我们来看看随机特征模型是如何具体实现的。

假设我们的特征向量是 Φ(x)。我们可以将线性模型 wᵀΦ(x) 展开为求和形式:∑ᵢ wᵢ Φᵢ(x)。其中,wᵢ 是第 i 个权重,Φᵢ(x) 是特征向量 Φ(x) 的第 i 个分量。

我们可以选择一组简单的特征,其形式为:Φ(x) = σ(Sx)。这里,S 是一个矩阵,x 是输入向量,σ 是一个非线性函数。这只是一种选择,好坏未知。我们也可以选择其他特征,但这里我们选择这种特定形式:某个非线性函数 σ 作用于 Sx

我们假设函数 σ 独立地作用于向量的每一个元素。例如,如果 σ(x) = x²(x 为实数),那么对于向量 vσ(v) = [v₁², v₂², ..., v_d²]ᵀ。因此,σ 是一个将其操作独立应用于输入向量每个分量的函数。

这仅仅是选择特定类型特征的一种方式。

此外,我们将使用一个非常特殊的矩阵 S。我们甚至不会以巧妙的方式创建这个矩阵,而是简单地用随机数填充它。S 是一个矩阵,其每个元素都采样自高斯随机变量。我们称之为特征矩阵。因此,S 是一个充满随机项的矩阵,并无特殊之处。

为何有效:平移不变核

这篇论文指出,对于平移不变核,上述随机特征的选择是有效的。

平移不变核意味着核函数 k(x, x') 满足 k(x, x') = k(x - x')。也就是说,xx' 在核函数公式中从不单独出现,总是以 x - x' 的形式出现。这就是“平移不变”的含义:如果对 xx' 同时加上相同的常数,核函数值不变。

对于这类核函数,该论文表明,你可以选择一个随机矩阵 S 和一个非线性函数 σ(例如,论文中选择了余弦函数,因为可以利用傅里叶变换来证明一些性质,但你也可以选择其他函数),这样得到的特征向量不仅维度不会比 x 大太多,而且其内积能够近似匹配原始核函数的输出。

论文的核心观点是:与其花费大量精力设计复杂的核函数,你也可以选择这种简单的表示方式——它不仅可以用核函数表示,还可以表示为一个简单的特征向量,并且对于许多问题都效果良好。

这只是一种特定的选择。使用随机矩阵来创建特征是一种非常“廉价”的技巧,它几乎不消耗计算资源(因为你甚至不需要动脑思考),并且能生成大量特征。根据 S 的大小,你可以创建任意维度的特征向量。

直观理解与示例

让我们看一个例子。假设我们有一个包含所有图像的矩阵,我们创建一个 n × n 的矩阵,其中每个元素 Kᵢⱼ = k(xᵢ, xⱼ)

如前所述,k(xᵢ, xⱼ) = σ(Sᵀxᵢ)ᵀ σ(Sᵀxⱼ)。这是对元素 xᵢ 应用特征函数后,与元素 xⱼ 的特征进行内积的结果。

下图试图说明,这个复杂的核矩阵可以被分解为多个简单核的线性组合。这些简单核使得某些图像块彼此相似。虽然你未必知道这个具体核函数是什么(实际上是该特征向量的傅里叶变换),但关键在于,这个复杂的核可以表示为一系列简单核的和。你自己也可以设计简单核,但随机特征方法让生成它们变得非常容易,而它们的组合却能近似我们原本想要的复杂核函数。

因此,这旨在说明,这种简单的随机特征方法并不“简单”,它可以表示为许多其他核的组合。论文中也展示了它在多个数据集上表现良好。

对我们而言,这里的启示是:在某些情况下,你不需要过于纠结使用何种特征。这种随机特征模型(及其对应的核函数)非常强大。例如,在深度学习兴起之前的约20年里,语音识别(如识别音素或单词)领域一直广泛应用这类方法。当时大多数手机或电话中的语音识别系统,使用的就是这类技术。

从随机特征到神经网络

现在,我们有了特征 Φ(x) = σ(Sx)。就像之前一样,我们希望使用一个权重向量 w 来构建分类器:wᵀΦ(x) 就是我们的分类器。

一旦确定了模型,为了最小化模型误差,你可以使用你喜欢的代理损失函数(如铰链损失、逻辑损失),并通过梯度下降或随机梯度下降来优化模型。

这里的关键区别在于:

  • 随机特征模型中,矩阵 S固定的(随机生成后不再改变),我们只优化权重 w
  • 神经网络中,矩阵 S(相当于第一层的权重)不是固定的,它也会被优化。

你可以将目标函数视为仅关于 w 的函数(如果 S 固定)。但如果 S 不固定,需要你去寻找最优的 S(而非随机的 S),那么你可以很容易地将目标函数视为关于两个变量 wS 的函数。此时,你不仅会找到最优的 w,还会找到最优的 S

直观上,这就是一个最简单的神经网络——一个单隐藏层神经网络。目前,你可以这样理解:随机特征模型和神经网络之间没有本质的巨大差异。神经网络只是多学习了一个对象——特征变换矩阵 S。随机特征模型选择了一种特殊类型的特征向量,而神经网络则进一步学习了这个特征向量本身。

总结

本节课中,我们一起学习了随机特征模型。我们了解到,通过使用随机生成矩阵 S 和一个简单的非线性函数 σ,可以高效地构建出能够近似复杂平移不变核函数的特征映射。这种方法计算廉价且易于实现。我们还探讨了它与神经网络的联系:随机特征模型可视为一个固定了第一层权重的神经网络,而神经网络则通过同时优化所有权重(包括第一层的 S)来学习更优的特征表示。这为理解从传统核方法到现代深度学习之间的过渡提供了清晰的视角。

26:学习特征矩阵 🧠

在本节课中,我们将探讨一个核心概念:通过学习特征矩阵 S 来转换原始数据,以及这一选择如何从根本上改变了我们优化问题的性质。我们将看到,这个看似简单的步骤引入了非线性、高维度和非凸性,使得问题变得更加复杂。


上一节我们介绍了感知机的基本线性模型。本节中我们来看看,当我们决定不直接使用原始特征 x,而是通过学习一个特征矩阵 S 来生成新特征时,会发生什么。

我们可能只是做了一件非常基础的事情,但我们已经完全改变了问题。在这个新问题中,损失函数是权重 W 的线性函数。这一点对大家来说容易理解吗?如果你使用合页损失函数,你会得到 -y * w^T * x

现在,你得到的是 -y * w^T * σ(s^T * x)。这里的 σ 代表一个非线性激活函数。整个表达式仍然是关于 W 的线性函数,因此求导是简单的。前提是 S 是固定的。

如果 S 不是固定的,那么这个函数就不再是关于 WS 的线性函数了。这对大家来说明显吗?WS 是相互乘在一起的。关于 W 的导数依赖于 S,关于 S 的导数也依赖于 W。因此,这是一个非线性函数。只有当 S 固定时,它才是关于 W 的线性函数。

仅仅因为我们选择学习 S,我们就从线性函数的世界进入了非线性函数的世界。非线性函数是比线性函数复杂得多的对象。

我们让问题变得更难了。我们引入了来自 σ 的非线性,所以即使不考虑 S,它显然也不是线性函数。但现在,由于 Wσ 以某种方式相互乘在一起,它更是一个非线性函数。所以,这是一个非线性函数,而非线性函数。

在参数数量上,如果 W 是一个 P 维向量(即原始特征维度是 P),那么 S 是一个大小为 D x P 的矩阵。因为我们总是进行 s^T * x 运算,而 xD 维向量。所以 S 是一个有 D * P 个元素的矩阵。因此,我们现在需要拟合的参数总数是:WP 个,SD * P 个。根据 D 的值,这可能远大于 P

我们通过选择学习 S 使模型变得更复杂。如前所述,如果你的函数有很多参数需要拟合,由于维度灾难,你需要更多数据来拟合这个函数。所以现在,因为你选择学习 S,你应该获取更多数据来拟合你的模型。这是一个高维问题,或者至少是一个维度更大的问题。如果你的 S 非常大,那么这就是一个高维问题,同时也是一个非线性问题。

目前对你来说可能不那么明显的是,它还是一个非凸问题。

以下是凸函数和非凸函数的直观对比:

  • 凸函数看起来基本上像抛物线。抛物线很好,因为它只有一个最低点。当你沿着抛物线梯度下降时,你不可能掉到最低点以外的任何地方。
  • 非凸函数看起来像这样(想象一个多峰的函数,有多个山谷和山峰)。例如,如果你从这个位置开始梯度下降,你可能会卡在这里,得到一个局部最优解。如果你从这里开始,则会下降到另一个地方。所以,根据你初始化的位置,你可能会得到不同的答案。这就是非凸函数的样子,它们比凸函数复杂得多。

对于凸函数,问题只在于你以多快的速度到达底部,没有其他玄机。但对于非凸函数,你能否到达全局最低点,还取决于你从哪里开始。因此,这类问题比最小化抛物线这类问题要复杂得多。所以,非凸优化是一个比凸优化复杂得多的领域,而我们在拟合感知机时做的就是凸优化。

我们通过选择同时学习 S,使问题变得复杂得多。正如他所说,我可以把这看作是一个两层神经网络。

第一层简单地是这些对象的名称,关于“层”是什么并没有特别的意义。S 是第一组参数,W 是第二组参数。


本节课中我们一起学习了通过学习特征矩阵 S 来构建模型的核心思想。我们了解到,这一做法将简单的线性分类问题转变为一个涉及非线性变换、更高维度参数空间以及非凸优化挑战的复杂问题。这实际上构成了神经网络中“层”的概念基础,其中 SW 分别对应不同层的参数。理解这种复杂性的引入,是深入理解现代深度学习模型的关键一步。

27:深度全连接网络 🧠

在本节课中,我们将学习深度全连接网络的基本概念。我们将从上一章的两层网络出发,扩展到具有多个隐藏层的深度网络结构,并理解其如何通过组合特征来构建复杂的模型。


上一节我们介绍了使用单个权重矩阵 S 和偏置向量 b 的两层感知机模型。本节中,我们来看看如何将这种结构扩展为多层,即深度全连接网络。

在本例中,我将选择将最后一层的权重标记为 V,而非 W。你马上就会明白这样重命名的原因。

与之前仅有两个参数(如 SV)不同,你现在可以拥有许多这样的参数。你可以创建复杂的特征,这些特征是其他特征的函数。想象一下,σ(S1 * x) 是一种特征。当你对其应用另一个矩阵 S2^T 并在外部加上非线性激活函数时,你会得到一个更复杂的特征。

因此,你首先使用 S^T * x 创建一个简单特征,然后通过再次乘以 S2^T 使其变得更复杂,并且你可以多次重复这个过程。

在这个公式中,我将其写成了适用于所有时间步的通用形式。无论你最终得到什么,它都是你的特征向量 φ(x)

一旦你有了特征向量 φ(x),你就可以使用一个向量 V 在该特征向量上创建一个线性模型进行分类。

我们所做的,无非是将这个两层神经网络写成一个 L 层神经网络,其中我们用多个 S 矩阵代替了原来的一个 S 矩阵。这就是一个深度神经网络。

除了使用相同的操作堆叠多个层之外,它本身并没有什么特别“深奥”之处。因此,每当你看到这个复杂的表达式时,都无需担心。你只需将这里写的一切替换为 φ(x),然后将其想象成我们相同的感知机模型。

但需要认识到的重要一点是,神经网络或深度网络通过组合旧特征来创建新特征。旧的特征是第一层的 σ(S1 * x),第二层则接收这些特征并使它们变得更加复杂。

这个过程会持续进行若干次。在每一层,你接收旧的特征,将其乘以某个矩阵 S,然后应用某个非线性函数 σ 使其变得更复杂,再将其传递给下一层。

因此,整个运算 σ(S * 输入) 就是人们所称的一个“层”。之所以称之为层,是因为在人脑中存在类似的分层操作,人们注意到这些操作具有层次结构,每一级这样的层次就称为一个层。对我们而言,它只是一个数学表达式。

所以,这就是神经网络。如果上一章的问题因为有两个权重(SV)而显得复杂,那么本章的问题则更加复杂,因为这里真的有很多、很多的权重。

每个 S 矩阵都提供了大量参数,它们在你的网络中累加起来,共同构成了你的权重向量。

以下是深度网络的关键组成部分:

  • :每一层执行运算 σ(S * 上一层输出),其中 σ 是非线性激活函数。
  • 特征组合:每一层都基于前一层的输出构建更复杂、更抽象的特征。
  • 参数:深度网络拥有大量参数,主要来源于每一层的权重矩阵 S

本节课中,我们一起学习了深度全连接网络。我们了解到,深度网络本质上是将多个“层”(即 σ(S * 输入) 运算)堆叠起来。每一层都接收前一层的输出作为输入,并通过权重矩阵和非线性变换,生成更高级的特征表示。最终,这些深层特征被传递给一个线性分类器(如权重向量 V)进行决策。虽然这引入了大量需要学习的参数,但其核心思想仍然是特征的层级化组合与变换。

28:神经网络学习何种特征 👁️🧠

在本节课中,我们将探讨神经网络在学习过程中,其内部各层究竟学会了识别什么样的特征。我们将从第一层的简单特征开始,逐步深入到更高层的复杂特征,并将其与人类视觉处理系统进行类比。


上一节我们介绍了神经网络的基本结构,本节中我们来看看神经网络内部究竟学到了什么。特征函数 φ 可以表示为 φ = S^T x。我们可以取一个训练好的神经网络,检查其第一层之后学习到的特征类型。

以下是第一层学习到的特征示例:

  • 这些特征看起来像是边缘,中间有明亮的区域,两侧被两条暗线包围。
  • 这个特征与绿色相关。每当图像中出现绿色区域时,该特征的值就会很大。
  • 这是绿色到粉色的渐变等。

这就是训练好的神经网络在第一或第二层后,其特征呈现的样子。

这很有趣,因为它与人类眼睛的视觉处理方式相似。眼睛的视网膜接收光线,以某种方式处理后,将其传递给某些神经元。可以想象,信息从眼睛传递到称为 V1皮层 的大脑区域,这是大脑视觉处理通路的第一层级。

事实证明,通过测量(例如在V1神经元上放置电极,观察不同视觉输入下电极记录到的高电压),人们发现V1神经元的特征与神经网络第一层的特征非常相似。这一认识已有大约50年的历史。

它们对边缘、颜色以及简单梯度的简单函数做出反应。你在作业中接触过的 Gabor滤波器 特征看起来就与此完全相同。

以上是第一、二层(例如第二层)的特征。随着我们向网络的更高层迈进,这些特征会变得更加复杂。

以下是更高层特征的示例:

  • 你会看到这些特征是更基础特征(如边缘、颜色等)的函数。
  • 如果一个神经元检测到水平边缘作为一个特征,另一个检测到垂直边缘,那么一个组合这些特征的神经元就能学会识别更复杂的模式。

特征通过矩阵 S 进行线性组合,并施加非线性激活函数,从而变得更加复杂。人们花费了大量时间来观察这些特征并猜测它们的功能。

例如,这个特征可能对应什么?一个足球?一个高尔夫球?很难确切猜出这些特征的真实含义,但可以肯定的是,你会同意这些特征比第一层的特征复杂得多。😊

随着网络层级的升高,特征会变得更加复杂。例如,这些可能是“眼睛”的特征。某张特定图片可能包含很多眼睛,或者这可能是一个高尔夫球等。

这是因为生成这些特征的数据集(称为 ImageNet)包含大量猫狗等宠物的照片。人们喜欢宠物,所以会拍摄宠物眼睛和面部的特写。这就是神经网络中会出现的特征类型。

所有这些都旨在让你相信,随着网络层级的升高,特征确实变得越来越复杂。输入是真实的自然图像,而这些就是这些图像的特征。


接下来,我想简要介绍一下眼睛的特征。神经网络通过训练进行学习,而人类的视觉处理通路则包括眼睛和大脑。

大脑在你出生后开始学习,但眼睛本身并不真正“学习”。眼睛的结构是经过数千年进化形成的。基本上,你一出生,眼睛的神经元处理机制就是完善的,之后不会有根本性的改变。

虽然有一些微小的适应性变化(例如,当你从暗室走到明亮的阳光下时,一种叫做 视紫红质 的分子会调整其分泌量),但神经元的根本功能不会改变。


本节课中我们一起学习了神经网络各层学习到的特征。我们从简单的边缘和颜色特征开始,看到它们如何随着网络层级的加深,组合成更复杂、更抽象的模式(如眼睛、特定物体)。同时,我们将此过程与人类视觉系统中V1皮层的功能进行了有趣的类比,并指出生物视觉系统中部分硬连线特征与神经网络学习特征之间的异同。理解特征如何逐层抽象,是理解深度学习工作原理的关键。

29:哺乳动物视网膜处理机制 👁️

在本节课中,我们将学习哺乳动物视网膜如何将进入眼睛的连续光信号,转化为大脑可以处理的离散神经信号。这是一个复杂而高效的前端信息处理系统。

视网膜的早期研究与结构 🧬

20世纪初,西班牙神经科学家圣地亚哥·拉蒙-卡哈尔通过显微镜观察了大量微小的神经元回路,并绘制了他在显微镜下所见一切的优美图画。其中一幅便是哺乳动物视网膜的图示。观察其工作机制非常有趣。

光感受器:信号接收的第一步 ☀️🌙

这是视网膜的背面,即离角膜最远的部分。光线从角膜进入眼睛。光线大致从这个方向进入。视网膜中有两种主要的光感受器细胞。

以下是它们的类型与功能:

  • 视杆细胞:在黑暗或光线不足的环境中对光更敏感。
  • 视锥细胞:在光线充足的环境中被激活并处理信息。

可以看到,视杆细胞的数量远多于视锥细胞。这是因为人体或视网膜在进化过程中,为了更好地应对黑暗环境而发展出这种结构,因为在黑暗中辨别物体更为困难。

双极细胞:从连续到离散的转换 ⚡

这是光处理的第一步。光子进入眼睛,与光感受器细胞内的化学物质或分子相互作用,引发化学反应并产生向下传递的电脉冲。

这些细胞被称为双极细胞。双极细胞接收从每一个视杆和视锥细胞传来的电脉冲,并进行整合与平均处理。

双极细胞的输出通常是类似这样的脉冲(尖峰信号):
输出 = 脉冲(当光子输入超过阈值)
因此,如果在一定时间内有大量光子进入,就会产生一个脉冲。如果长时间内只有少量光子进入,则不会产生脉冲。即使光子持续不断地照射到眼睛,双极细胞的输出也是这些离散的脉冲。这是将连续信号转换为离散信号的第一步。研究这种转换发生的方式和时机非常有意思,许多科学家都在研究双极细胞的这类输入。

无长突细胞:抑制冗余信号 🚫

这些细胞非常特别,在典型的神经网络结构中看不到。它们被称为无长突细胞,负责抑制信号。可以将视网膜想象成一个大型相机。如果你看到某个物体从相机的中心向你移动,你通常不会关心输入图像其他部分发生的事情。因此,如果某个区域的信号非常强(例如有大量脉冲产生),你就希望抑制来自其他部分的信号。

这些抑制性细胞连接视网膜的不同部分(本质上是传感器的不同区域),并抑制那些冗余的信息。如果相同的运动发生在多个地方,只在一个地方追踪它就足够了,无需在整个视野范围内追踪。这是一个非常好的课程项目,你可以构建一个神经网络,创建这类抑制机制,并验证其重要性。

神经节细胞:特征提取与信息压缩 🎯

经过上述处理后,输入的信息量被大幅减少。你能探测到的最微小的光点,例如在一个完全黑暗的房间里看到的一个极小光点,大约相当于有十亿个光子照射到你的眼睛。这大约十亿个光子经过双极细胞处理后,被转换成一个脉冲。这就是视网膜从输入信号中消除的冗余信息量。

这类似于我们的输入图像是百万像素、三通道的大图像,而经过处理后输出的是少数特征(例如100或200个特征)。视网膜处理过程消除了同样类型的冗余。执行最终输出的是神经节细胞

神经节细胞的输出看起来很像这样。这些细胞接收那些脉冲,然后做出反应。有些细胞对特定角度(如1.0度角)的运动产生反应,有些对颜色产生反应,还有些对梯度等产生反应。

总结 📝

本节课中,我们一起学习了哺乳动物视网膜的层级处理机制。从视杆细胞视锥细胞接收光信号开始,到双极细胞将连续光信号转换为离散的神经脉冲,再到无长突细胞通过横向抑制消除空间冗余信息,最后神经节细胞提取特定特征(如运动、颜色、边缘)并将高度压缩的信息传递给大脑。这套复杂而精妙的系统是与生俱来的,无需后天学习,它体现了生物视觉系统在进化过程中形成的高效信息处理策略。

30:神经网络为何有效 🧠

在本节课中,我们将探讨神经网络为何如此强大和有效。我们将了解其核心优势,特别是它如何自动学习特征,以及它作为“通用近似器”的能力。

概述

上一节我们讨论了神经网络的灵感来源。本节中,我们将回归技术细节,解释训练神经网络的核心过程,并深入探讨其两大关键优势:自动特征学习通用近似能力。理解这些概念是掌握现代深度学习的基础。

神经网络训练的本质

训练神经网络的核心任务,与许多其他机器学习模型一样,是计算所有权重。本质上没有变化。

对于之前讨论的二分类问题,你仍然需要最小化合页损失(hinge loss)。区别在于,现在你需要对每一个权重求导,而不仅仅是对其中一个。然后,你需要逐个更新所有权重。

在深入反向传播之前,我们先了解几个重要观点。

无需手动设计特征的力量 💪

无需手动挑选特征的能力非常强大,这是目前深度学习如此流行、超越其他机器学习方法的最主要原因。

你可能知道这一点,但未必能完全体会其意义。举例来说,在我像你们这个年纪,也就是本科毕业、开始读研的时候,一个计算机视觉领域的研究者几乎不可能听懂自然语言处理(NLP)领域的学术报告,反之亦然。这两个领域当时是完全不同的世界,使用截然不同的技术和特征工程方法。

今天,情况已大不相同。神经网络作为一种优秀的机器学习模型,其用于解决计算机视觉问题的核心概念,可以迁移到解决NLP领域的不同问题上。它以惊人的方式将这些领域融合在了一起,因为人们不再需要“烹饪”自己的特征了。

十年前,在一篇计算机视觉的会议论文中,你需要设计自己的特征;在一篇NLP的会议论文中,你会选择不同类型的特征。如今,长达数十年的特征工程工作,基本上被自动学习这些特征所取代。

我们学习到的特征是否与过去手工创建的特征相同,这一点并不明确。事实上,我认为我们学到的特征与过去手工设计的并不相同,否则性能不会提升得如此显著。我们似乎学到了不同类型的特征,但这彻底消除了不同学术领域之间的技术壁垒。

然而,这种热潮也存在一些不合理的冲动。在许多领域,例如医学影像(研究大脑或肺部图像以进行预测),人们已经开发出了非常复杂的特征构建方法。当人们开始将深度网络应用于这些领域时,他们发现这些网络的效果并不理想。按理说,既然能自动学习特征,性能应该更好才对。因此,你仍然能看到这种思维的残余:人们将神经网络应用于那些原始特征本就非常优秀的问题上,结果发现性能远不如旧方法。但由于应用这些新技术的巨大诱惑和对其更好性能的期望,人们仍在不断尝试。

但无论如何,核心故事是:你不再需要手动挑选特征了。现在,我可以去听一位NLP教授的讲座,并能理解个大概。

深度网络是通用近似器 🌐

深度网络是通用近似器,这一点我们已经多次提及,这里我们再次用语言(而非数学)来阐述:对于任何你想拟合数据的函数,只要网络足够大、层数足够多、宽度足够宽,你就能拟合这个函数。

但这并不意味着你需要的数据量会减少。实际上,网络越大,由于其高维特性,你通常需要更多的数据来拟合。但只要数据足够,你就能拟合它。

这就是“通用近似器”的含义:无论多么复杂的预测任务,你都可以(在理论上)实现。

总结

本节课中,我们一起学习了神经网络有效的核心原因。

首先,我们回顾了神经网络训练的本质是优化所有权重,这需要通过计算每个权重的梯度(反向传播)来实现。

接着,我们重点探讨了神经网络的两大关键优势:

  1. 自动特征学习:神经网络能够从数据中自动学习有效的特征表示,这取代了传统机器学习中繁琐且需要领域知识的手工特征工程,极大地促进了不同AI子领域(如CV和NLP)的融合。
  2. 通用近似能力:理论上,一个足够大、足够深的神经网络可以近似任意复杂的函数,这赋予了它解决极其复杂问题的潜力。

理解这些原理,有助于我们把握深度学习的核心价值,并在实际应用中更好地利用这一强大工具。

31:反向传播算法入门 🧠

在本节课中,我们将要学习神经网络训练的核心算法——反向传播。我们将了解其基本概念、工作原理以及它与高中数学知识的联系。

概述

反向传播是一种用于训练神经网络的算法。它的目标是找到一组最优的权重参数,使得神经网络在给定数据上的预测误差最小。本质上,反向传播的原理与你高中微积分中学过的链式法则并无不同,只是我们将从一个新的视角来理解和应用它。

核心概念:链式法则

上一节我们概述了反向传播的目标。为了理解其工作原理,我们首先需要回顾一个基础的数学概念。

在微积分中,链式法则用于计算复合函数的导数。如果有一个函数 y = f(g(x)),那么 y 关于 x 的导数可以通过以下公式计算:

dy/dx = (df/dg) * (dg/dx)

在神经网络的语境下,整个网络可以看作一个极其复杂的复合函数。网络的最终输出(预测值)是由输入数据经过层层加权求和与激活函数变换后得到的。我们的目标是调整每一层的权重,以减少最终输出与真实值之间的误差。

反向传播的工作流程

理解了链式法则的基础后,本节中我们来看看反向传播是如何利用这一原理来更新权重的。

反向传播的过程可以分为两个主要阶段:前向传播和反向传播。

以下是反向传播算法的关键步骤:

  1. 前向传播:输入数据从网络的第一层流向最后一层,计算出网络的预测输出。
  2. 计算损失:使用损失函数(如均方误差)比较预测输出与真实标签,计算出总误差。
  3. 反向传播误差:这是算法的核心。误差从输出层开始,沿着网络反向流动,利用链式法则计算损失函数相对于网络中每一个权重的梯度(即导数)。
  4. 更新权重:根据计算出的梯度,使用优化算法(如梯度下降)沿着梯度反方向微调每个权重,以减小损失。

这个过程会反复迭代(一个epoch接一个epoch),直到网络的性能达到满意水平或误差不再显著下降。

总结

本节课中我们一起学习了反向传播算法。我们了解到,反向传播是训练神经网络、优化其权重参数的关键方法。它的核心思想是利用微积分中的链式法则,将最终输出的误差逐层反向传递,并计算出每个权重对总误差的“贡献度”(梯度),从而指导权重的更新。虽然现代深度学习框架已经自动完成了这些复杂的计算,但理解反向传播的基本原理,对于构建和调试神经网络模型至关重要。

32:深度学习术语 🧠

在本节课中,我们将学习深度学习中的一些核心术语和概念。这些术语是研究人员为网络中的不同组成部分所起的名字。理解它们有助于我们更清晰地讨论和构建神经网络模型。

上一节我们介绍了神经网络的基本思想,本节中我们来看看构成网络的具体组件及其名称。

激活函数 🔌

在神经网络中,每个神经元内部都包含一个非线性函数。这个函数决定了神经元的输出。以下是几种常见的非线性激活函数。

以下是几种常见的激活函数及其定义:

  • 符号函数 (Sign Function):这是我们在第一讲中看到的McCulloch-Pitts神经元所使用的函数。它预测其输入的符号。其公式为:
    y = sign(W^T * x)
    其中 sign 是符号函数。

  • 阈值函数 (Threshold Function):这是符号函数的一个相关变体。你可以将其视为一个阈值函数:如果参数大于零,则返回1;否则返回0。它不是一个线性函数。

  • Sigmoid / Logistic 函数:其形状呈S形。当 x 非常大且为正时,输出接近1;当 x 非常大且为负时,输出接近0;当 x 为0时,输出为0.5。Sigmoid函数可以看作是阈值函数的一个平滑版本。

  • 双曲正切函数 (Hyperbolic Tangent):这是一个与Sigmoid类似的函数。当 x 非常大且为正时,输出接近1;当 x 非常大且为负时,输出接近-1;在零点输出为0。

  • 线性整流单元 (ReLU):其定义为 f(x) = max(0, x)。当 x 大于0时,输出就是 x;当 x 小于0时,输出为0。它在原点右侧是线性的,在左侧也是线性的(输出恒为0),只是在原点处有一个“拐点”。它非常接近一个线性函数。

  • 渗漏线性整流单元 (Leaky ReLU):这是ReLU的一个变体。在原点右侧,它与ReLU相同;在原点左侧,它有一个微小的正斜率,而不是完全为0。

这些都是在历史上被用来替代Sigmoid函数的不同函数名称。有些效果更好,有些则较差,其中存在合理的性能差异原因,我们稍后会看到。

最重要的是:除非你对你的问题有特殊了解,明确不应使用ReLU,否则你应该使用ReLU。通常不要使用线性函数,因为它的效果很差。如今,你几乎看不到Sigmoid被使用,有时会看到Tanh被使用,而ReLU则被广泛使用。

从单输出到多输出 🎯

之前我们考虑感知机时,我们知道如何拟合一个二分类感知机。对于多分类问题,可以通过“一对多”或“一对一”等策略训练多个感知机。然而,在神经网络中,有一种更优雅的方式。

我们一直将最终输出 V^T * h 视为一个向量。但 V 不一定是一个向量,V 可以是一个矩阵。

例如,假设 V 是一个大小为 p × 5 的矩阵。那么 V^T * h(其中 hp 维特征向量)的结果就是一个5维向量。

这5个维度中的每一个,我们都可以解释为对应一个类别的得分(例如:猫 vs 非猫,狗 vs 非狗,大象 vs 非大象,长颈鹿 vs 非长颈鹿)。这样,我们就不需要训练多个独立的感知机,可以在同一个模型中直接获得5个不同类别的输出。

这在概念上与训练多个共享输入特征的感知机没有太大不同,只是以一种更紧凑的方式将它们组织在一起。我们将看到解释这种输出的不同方式,但目前请记住:输出不需要是一个标量,它可以是一个向量;扩展来说,最后一层的权重 V 也不需要是向量,它可以是一个矩阵。

前激活与后激活 ⚙️

我们一直将中间输出称为“特征”,并将继续这样做。但我们需要区分应用非线性函数 σ 之前和之后的部分。

  • 前激活 (Pre-activation):指在应用非线性函数 σ 之前的值。我们用 h 表示。即 h = W^T * x(对于第一层)。
  • 后激活 / 激活 / 特征 (Post-activation / Activation / Feature):指在应用非线性函数 σ 之后的值。我们用 aσ(h) 表示。即 a = σ(h)

有时在论文中,特征也被直接称为“激活”,两者是同一回事。

区分这两者在实现反向传播算法时非常有用,因为我们需要以略微不同的方式处理它们。我们可以将 W^T * x 视为一个层(线性层),将 σ 视为另一个层(非线性激活层)。σ 层没有可学习的参数,它只是一个对输入执行的操作。

隐藏层 🕵️♂️

在神经网络中,除了最后的输出层,所有中间层(即它们的激活值)都被称为隐藏层 (Hidden Layers)

例如,当人们说“我有一个带一个隐藏层的神经网络”时,他们通常指的是这样的结构:输入 x,经过一个线性变换 S^T 和一个激活函数 σ,得到第一个隐藏特征 a1 = σ(S^T x)。然后这个特征再经过另一个线性变换 V^T 得到最终输出 y

在这个网络中,SV 是可学习的参数,因此这是一个两层网络。由于我们无法直接观察到输入 x 和最终输出 y 之间的内部状态(a1),所以这些中间层被称为“隐藏”层。

这些只是你在论文中会经常看到的名字。如果不了解它们,可能会感到困惑,但它们本质上只是名称。

网络的“胖”与“瘦” 📏

我们还会用一些名称来描述网络结构。例如,我们会说一个网络是“瘦”的,如果其隐藏层的维度不大。

让我们用数字说明:如果输入 x 是一个 d 维向量,第一层的权重矩阵 S 的大小是 p × d,那么前激活 h1 的维度就是 p

  • 如果 p 非常大,我们就说这个网络非常“胖” (Fat)
  • 如果 p 非常小,我们就说这个网络非常“瘦” (Thin)

这只是一种思考网络容量的方式。


本节课总结 🎓

在本节课中,我们一起学习了深度学习中的关键术语:

  1. 激活函数:如ReLU、Sigmoid、Tanh,它们为网络引入非线性,其中ReLU是最常用且效果良好的选择。
  2. 多输出层:通过使用矩阵而非向量作为最终权重,神经网络可以优雅地处理多分类问题。
  3. 前激活与后激活:区分了应用非线性函数之前(h)和之后(a)的值,这对理解网络计算和实现反向传播至关重要。
  4. 隐藏层:指网络中除输入层和输出层外的中间层,其状态在训练过程中是“隐藏”的。
  5. 网络形状:用“胖”和“瘦”来描述隐藏层维度的大小,这反映了网络的容量和复杂度。

理解这些术语是阅读文献、与他人交流以及构建自己神经网络模型的基础。

33:权重 🧠

在本节课中,我们将学习神经网络中一个核心的简化概念:权重。我们将了解为什么将所有网络参数统称为一个向量 W 可以极大地简化我们的表达和思考过程,并理解这与实际代码实现(如PyTorch)之间的关系。


我们今后将不再讨论网络中的单个参数。

原因很简单:反复书写那个庞大而复杂的公式过于繁琐。因此,我们将所有参数统称为 w。每当我提到 w 时,你应该想象自己将所有参数取出,并将它们拼接成一个大向量。这就是我们网络的表示方式。

我们总是说 W 是一个 P 维向量,可以想象 P 非常大。所有参数的拼接都包含在这个向量中。

如果你理解了这一点,那么我就可以将我的神经网络简单地写成一个关于两个变量的函数:x 是输入,W 是权重。

公式: f(x, W)

这不再只是一个简单的线性函数加一个激活函数,它内部包含了许多非线性函数和矩阵运算。但我可以像这样把它写下来,这将极大地简化我们的工作。

这就是我们的函数,也是我们的目标(稍后我们会讨论更多关于目标函数的内容)。拟合一个神经网络,本质上就是寻找最优的 W

这等同于寻找最优的 VS1S2S3 等参数,而这些都隐含在这个 W 之中。

需要记住的一点是,即使我们以这种非常简单的形式写下表达式,当你使用 PyTorch 时,PyTorch 会将网络的不同权重维护为一个大的矩阵列表。

因此,根据特定层的结构,每个权重可能是一个矩阵或一个向量。当你调用 model.parameters() 时,你将得到这个大的列表作为输出。在第二次作业中,你将学习如何获取并修改这个列表。

从概念上讲,这没有任何不同,这只是 PyTorch 选择维护其权重的方式。因为在这里,我们并不关心代码的具体实现细节,而是专注于表达式本身,所以我们将其简单地视为向量。


本节课总结

本节课中,我们一起学习了神经网络权重的简化表示方法。我们了解到,将所有参数拼接成一个高维向量 W 可以简化数学表达和理论分析。同时,我们也认识到,在实际的编程框架(如 PyTorch)中,这些权重是以矩阵列表的形式组织和管理的,但这并不改变其背后的核心概念。掌握这种抽象表示是理解后续优化算法的基础。

34:神经网络反向传播概述 🧠

在本节课中,我们将要学习神经网络中一个核心的优化算法——反向传播。我们将通过一个简单的例子,理解它如何自动、高效地计算损失函数对网络参数的梯度,从而指导参数更新。


上一讲我们介绍了定义目标函数(损失函数)的重要性。现在,我们希望计算这个目标函数的梯度,以找到正确的参数 W

如果只是拟合一个线性函数,那么直接对损失函数求导,然后使用梯度下降法即可。

但如果处理的是包含多个层的神经网络,手动为每一种网络架构计算导数会变得非常繁琐。

因此,反向传播是一种非常巧妙的方法,它能以自动化的方式计算导数。

我们将通过一个简单的例子来演示这个过程:一个一维的回归神经网络模型。

为了帮助理解,我们先回顾一下模型结构。输入 X 是一个 D 维向量(例如一张图片)。隐藏层只有一个神经元,因此权重 W 也是一个 D 维向量。第二层的权重 v 是一个标量。模型的预测输出是 Y_hat

我们希望预测值 Y_hat 接近真实值 y,回归误差(损失)定义如下:

Loss = (y - Y_hat)²

损失函数 L 依赖于参数 Wv。我们的目标是计算 ∂L/∂W∂L/∂v,以便更新 Wv 来减小损失。


我们可以将计算过程可视化为一个计算图。计算图以 WX 作为输入,经过一系列操作得到最终输出。

以下是前向计算图的步骤:

  1. 计算 z = WᵀX
  2. z 应用非线性激活函数 σ,得到 h = σ(z)
  3. 计算预测值 Y_hat = v * h
  4. 计算损失 L = (y - Y_hat)²

在代码中,zhY_hat 这些都可以看作是中间变量。


反向传播的核心目的是高效地计算链式法则的导数。关键在于,当我们进行前向计算时,会生成并存储所有中间变量的值(如 zhY_hat)。

在反向计算梯度(例如 ∂L/∂v)时,我们会发现链式法则的展开式中反复出现这些已计算好的中间值。

因此,反向传播的本质是:巧妙地缓存前向传播中计算出的中间结果,以便在反向应用链式法则求导时复用它们,避免重复计算。

这听起来可能很平凡,但却是其高效性的关键。计算图每一步的输出,正是反向传播计算梯度时所需的信息。


另一个需要注意的现象是,在梯度计算表达式中,总会看到每个操作(层)的导数出现。

例如,激活函数 σ 的导数 σ' 会出现在链式法则中,它连接了该层输入和输出的梯度。

我们稍后会看到具体的计算过程。


本节课中我们一起学习了反向传播的基本概念。我们了解到,反向传播通过将神经网络表示为计算图,并缓存前向传播的中间结果,从而高效、自动化地计算损失函数对所有参数的梯度。这为使用梯度下降法优化复杂神经网络奠定了基础。

35:通过示例理解反向传播 🧠

在本节课中,我们将通过一个具体的例子,学习神经网络中一个核心算法——反向传播。我们将使用一种简洁的符号表示法,并一步步推导如何计算损失函数对模型参数的梯度。理解这个过程是掌握神经网络训练的关键。


引入简洁符号表示法

上一节我们介绍了计算图的概念。本节中,我们来看看一种能极大简化反向传播计算的符号表示法。

这种表示法非常巧妙,其背后有深厚的纯数学根源,但我们现在无需深究。其规则如下:每次我们想写损失函数 L 对变量 V 的导数 dL/dV 时,我们将其写作 V_bar。这就是变量 V 的协变导数。

这只是一个符号。它的目的是让我们的计算变得极其简单,从此你无需再费脑筋进行反向传播计算。

我们的目标是计算 dL/dWdL/dV,用我们的符号表示就是 W_barV_bar。这是我们希望计算的两个量。


定义前向传播计算图

首先,我们需要明确前向传播的步骤。我们的前向计算图可以用以下四个方程描述:

  1. z = W^T * x
  2. h = σ(z) (其中 σ 是激活函数,如 ReLU)
  3. e = V * h
  4. L = (y - e)^2 / 2

这些就是前向图的所有步骤。正如之前提到的,我们应该缓存每一步的输出,即 zheL。到目前为止,一切都还很简单。


反向传播的核心模式

现在让我们开始反向传播。首先,dL/dL 是多少?是 1,因为一个量对自身的导数为 1。我们可以将其写作 L_bar = 1

接下来,我们想计算 E_bar,即 dL/de。我们可以利用链式法则写出:
E_bar = dL/de = (dL/dL) * (dL/de) = L_bar * (dL/de)

我们知道 L_bar = 1。那么 dL/de 怎么算?这很简单,L 是前向图第四步的输出,所以 dL/de 就是第四步方程右边对 e 的导数。从 L = (y - e)^2 / 2 可得,dL/de = -(y - e)

这里发生了一件非常重要的事情,这也是反向传播的关键所在:
L 是第四步的输出,e 是第四步的输入之一(当然,e 也是第三步的输出)。我们想计算输入 ebar 版本(即 E_bar),我们可以将其写为输出 Lbar 版本(即 L_bar)乘以 L 是如何由 e 创建的导数。

简单来说,我想知道损失对某个输入的敏感度。我首先检查损失对该操作输出的敏感度,然后乘以该输出对我关心的输入的敏感度。这就是链式法则的文字描述。

记住这个核心模式:右边变量的 bar 版本等于左边变量的 bar 版本乘以左边变量是如何由右边变量创建的(即其导数或敏感度)。


逐步计算梯度

现在我们已经有了 E_bar,让我们继续计算其他变量的梯度。

计算 V_bar 和 H_bar
每当你有了左边某个变量的 bar 版本,你就用它来计算右边变量的 bar 版本。

V_bar 是什么?V_bar 是其输出 ebar 版本乘以 e 是如何由 V 创建的导数,即 de/dV
用公式表示:V_bar = E_bar * (de/dV)
de/dV 是什么?从 e = V * h 可知,de/dV = h

类似地,H_bar 是什么?H_bar = E_bar * (de/dh)
e = V * h 可知,de/dh = V

所以:
V_bar = E_bar * h
H_bar = E_bar * V

计算 Z_bar
现在我们有了 H_bar,我们想计算 Z_bar
Z_bar 是其输出 hbar 版本乘以 h 是如何由 z 创建的导数,即 dh/dz
用公式表示:Z_bar = H_bar * (dh/dz)
dh/dz 是激活函数 σ 对其输入 z 的导数,记作 σ'(z)

因此:Z_bar = H_bar * σ'(z)
如果 σ 是 ReLU 激活函数,那么当 z > 0σ'(z) = 1,否则为 0。只要你知道了非线性激活函数,你就知道它的导数,也就能像这样进行反向传播。

计算 W_bar 和 X_bar
现在我们有了 Z_bar,可以计算 W_barX_bar 了。这里涉及到向量乘法,需要小心维度。

W_bar 是什么?W_bar = Z_bar * (dz/dW)
Z_bar 是一个标量,dz/dW 是一个向量(因为 z = W^T * x)。dz/dW = x
所以:W_bar = Z_bar * x

类似地,X_bar 是什么?X_bar = Z_bar * (dz/dx)
dz/dx = W
所以:X_bar = Z_bar * W

注意,我们已经得到了我们最初的目标 W_barV_bar


前向传播与反向传播的协作

让我们回顾一下整个过程的关键点。

首先,从左到右运行前向传播图。你会注意到,你缓存的中间结果(z, h, e)正是你计算反向传播时需要用到的。

例如,计算 V_bar = E_bar * h 时,h 就是你之前缓存的值,直接代入即可。而 E_bar 则是由反向传播上一步计算得到的。

这是一个非常重要的规律

  • 前向传播从输入到输出。
  • 反向传播从输出回到输入。
  • 在每一步,反向传播都使用上一步反向传播的结果,以及前向传播在该步骤缓存的数据。

这很容易理解,但必须牢记:反向传播就像前向传播一样,接收上一步的输出。但反向传播还额外接收一个输入——它使用前向传播在那里缓存的数据。


总结

本节课中,我们一起学习了反向传播算法通过一个具体示例的实现过程。我们首先引入了一种简洁的 _bar 符号来表示梯度。然后,我们一步步推导了如何从损失函数 L 开始,利用链式法则和缓存的前向传播中间结果,依次计算出损失对网络中每个参数(V, W)和中间变量(e, h, z)的梯度。我们总结出了反向传播的核心模式:右边变量的梯度等于左边变量的梯度乘以连接它们的局部导数。最后,我们强调了前向传播与反向传播的高效协作机制:前向传播缓存数据,反向传播利用这些数据高效计算梯度。掌握这一流程是理解和实现神经网络训练的基础。

36:反向传播梯度与对抗样本 🔍

在本节课中,我们将要学习反向传播算法除了计算权重梯度外,还能为我们提供哪些额外的重要信息。我们将重点探讨损失函数对输入特征的梯度,并了解其在生成对抗样本这一有趣现象中的应用。

反向传播的额外输出 📊

上一节我们介绍了反向传播如何计算模型权重的梯度。本节中我们来看看,除了权重梯度,反向传播过程还能输出哪些有价值的信息。

反向传播过程结束时,你会得到损失函数相对于模型中每一个权重的导数。在我们的简单模型中,W 和 V 是仅有的两个权重。因此,你会得到模型中每一个权重的导数。

然而,我们不仅仅能得到权重的梯度。我们还能得到其他信息。例如,E_bar 是什么?它是否具有意义?

H 是我第一层的特征。H_bar 表示损失函数相对于这些特征的变化率。如果我稍微改变这些特征,损失会如何变化?你有时可能希望观察这个值,以了解损失对某些特征的敏感程度。

因此,作为反向传播的额外输出,你会得到许多可以用于调试、检查或进行研究的量。

计算依赖关系与内存优化 ⚙️

一个自然的问题是:我们能否在不计算 H_bar 的情况下计算 W_bar?因为我们只需要 W_bar 和 V_bar,似乎不需要 H_bar。

这是一个需要记住的重要概念。就像在前向计算图中,要计算某个变量,你需要经过它左侧的所有计算步骤。类似地,在反向传播中,要计算任何变量的梯度(即其 “bar” 版本),你必须经过其右侧的所有计算步骤。

你无法在计算上“短路”这个过程。我的意思是,在纸面上你可以简化链式法则,但为了计算它,你仍然需要完成相同的工作量。

一种思考方式是,如果你试图节省内存,人们可能会尝试不去计算某些层的特征,因为这些特征很容易重新计算。非线性函数(如 Sigmoid 或 ReLU 的应用)通常计算非常快速。因此,有时人们不会存储线性层的输出,而只存储其输入,然后在反向传播时动态计算输出。这是一种为了节省内存而采取的策略。

损失对输入的梯度:X_bar 🎯

反向传播提供的另一个非常重要的量是 X_bar,即损失函数对输入 X 的梯度(dL/dX)。它衡量了损失对输入微小扰动的敏感程度。

通常,在训练网络时我们并不关心这个值。但你可以观察它,并判断图像是否被模型稳健地分类。如果我稍微改变图像,损失会发生多大变化?如果损失大幅增加,那么我的模型并没有很好地理解这张图像,或者说没有很好地理解其邻近的图像。

以下是关于这个梯度的一个著名应用实例。

对抗样本:一个引人深思的现象 🐼➡️🐒

几年前(大约2015年),研究人员注意到一个现象:你可以拿一个训练好的神经网络(例如一个预测1000个类别的网络),并生成所谓的“对抗输入”。

假设这是一张熊猫的图片。网络预测这是一只熊猫,概率为60%。对于一个随机模型,如果有1000个类别,正确预测的概率是0.1%。因此,即使60%的概率看起来不高,它也远比随机模型的基线(0.1%)要好得多。这是一个不错的模型,当它看到熊猫时,能识别出熊猫。

这是我们的输入 X。我们可以利用 dL/dX,对 X 执行梯度上升。训练模型时,我们沿着损失减少的方向移动(梯度下降),以改善损失。但你可以利用 dL/dX,沿着使损失增加的方向扰动 X。

我可以进行如下操作:

x_prime = x + alpha * dL_dx

这就是对 X 的梯度上升。😊

这会产生什么效果?这将增加模型在那个特定输入 X 上的损失。在相关论文中,这个扰动被称为 epsilon,但本质上它就是通过反向传播计算出的 dL/dX。

如果你这样迭代几次,执行多步梯度上升,生成的图像在视觉上变化不大,但损失却会发生巨大变化。

对你我而言,这看起来仍然像一只熊猫,我们不会被欺骗。但对网络而言,它看起来像一只长臂猿(Gibbon),并且网络对此非常确信,有99%的信心认为这是一只长臂猿(一种猴子)。这显然不是熊猫。

你对输入所做的扰动通常可以非常微小,却能引起损失的大幅变化,这告诉你 dL/dX 的值相当大。对于网络中的大多数输入,情况都是如此。

因此,现在有一个庞大的研究领域致力于研究为什么会出现这种对抗样本,以及如何修复它们。因为很容易拿一个训练好的网络,通过展示仅被微小扰动或略带对抗性的输入,就使其性能变得非常糟糕。

这就像你看到闪烁的图像或某些视觉错觉时会感到头疼,无法正确理解几何形状一样。这是神经网络的类似版本。

这个故事的核心在于,你基本上可以用五行代码通过运行反向传播来完成这个实验。当你运行反向传播时,dL/dX 是免费得到的,你不需要做任何特殊计算来获取它。

总结 📝

本节课中我们一起学习了:

  1. 反向传播不仅输出模型权重的梯度(W_bar, V_bar),还输出中间层特征(H_bar)和输入(X_bar)的梯度。
  2. 计算某个梯度(如 W_bar)依赖于其后续所有计算步骤的梯度,无法跳过。
  3. 损失对输入的梯度(X_bar = dL/dX)揭示了模型对输入扰动的敏感性。
  4. 通过对输入执行梯度上升(x = x + alpha * dL_dx),可以生成“对抗样本”——人类难以察觉但会导致模型严重误判的微小扰动图像。
  5. 对抗样本的存在表明神经网络决策边界存在脆弱性,这是当前一个重要的研究领域。而探索这一切的基础工具——dL/dX,正是反向传播自动提供的。

37:反向传播的替代视角 🔄

在本节中,我们将探讨反向传播算法的一个关键替代视角,理解梯度如何在网络的不同部分之间分配。这对于设计和调试神经网络至关重要。


上一节我们介绍了反向传播的基本流程,本节中我们来看看梯度分配背后的直观逻辑。

一个非常重要的思考方式是:将前向图中的操作视为一个整体。例如,一个操作 W1 * x1 + W2 * x2 产生输出 z

我们知道,w1_bar(即 w1 的梯度)等于 z_bar(即 z 的梯度)乘以 ∂z/∂w1,也就是 x1。因此,w1_bar = z_bar * x1。同理,w2_bar = z_bar * x2

理解或记忆这一点的关键在于:w1 获得的梯度,是由其输出 z 的梯度 z_bar 分配的。这个分配是公平的,基于每个权重对输出的贡献大小。

可以将此视为两个项共同创造了输出 z。存在一个来自反向传播上层的梯度 z_bar,你的任务是以某种方式将这个 z_bar 分配给 w1_barw2_bar

以下是梯度分配的核心规则:

  • 如果 x1 的值非常大,那么 w1 将获得更大份额的梯度,因为 w1_bar = z_bar * x1
  • 如果 x2 的值非常大,那么 w2 将获得更大份额的梯度。

因此,W1W2 以这样的方式分享来自 Z 的传入梯度:如果其中一个在创造输出时扮演了更重要的角色(即其输入值更大),它也会获得更大份额的梯度。


这个原理在构建复杂神经网络时尤为重要。设想一个场景:这是你的第一个网络 H1,其权重是 W1;然后这里有另一个大型网络 H2,其权重是 W2,输出是 H2

这里,H1 的输出是 x1H2 的输出是 x2。我们暂时忽略中间可能存在的非线性激活函数。

如果 H2 的输出与 H1 相比非常小,那么这个网络(即使它本身非常庞大)将不会获得大份额的梯度。它从 Z 获得的梯度将始终很小。

因此,当人们构建非常大的网络时,经常发生的情况是:一个庞大的网络坐在这里,但它获得的用于训练的梯度如此之小,以至于网络的权重几乎不更新。

网络权重的更新幅度,即你对 W2 所做的更新,是其获得梯度大小的函数。如果它没有产生高幅度的输出,那么它可能无法获得足够的梯度回报,从而无法有效训练。


所以,当你组合大型架构或创建自己的新架构时,必须非常小心,因为你可能会遇到这种不一致性。通常当人们说“神经网络/深度学习只是超参数调优”或“深度学习需要我训练大量超参数”时,他们忽略的正是这种思考。

如果你以网络“条件良好”的方式设计它们,如果你思考梯度如何回传并检查权重是否被正确更新,那么你并不真的需要过多地调优超参数。我喜欢说,在我大多数论文中,我们只使用一组超参数设置,仅此而已,用于论文中的所有实验。

因此,如果你能认识到反向传播的工作原理,你就可以极大地简化工作,并减少在拟合网络时遇到的所有麻烦。


本节课中我们一起学习了反向传播的梯度分配视角。我们了解到,梯度根据每个参数对前向传播输出的贡献比例进行分配。这一原理提醒我们,在设计神经网络时,需要确保网络各部分能获得足够的梯度流以进行有效训练,而不仅仅是盲目地增加网络规模或调参。理解这一点有助于构建更稳定、更高效的模型。

38:实现反向传播的抽象方法 🧠

在本节课中,我们将要学习如何通过抽象化的方法来简化神经网络中反向传播的实现。我们将理解“层”的概念,以及如何为每一层定义前向和反向计算函数,从而避免手动重复复杂的链式法则推导。


正如我们之前所说,神经网络包含前向计算图和反向计算图。当你创建自己的网络架构时,不希望每次都重复所有步骤。因此,一个非常清晰的抽象思路是:将每一个独立的步骤或层(无论是进行线性变换的层,还是简单地应用非线性激活函数的层)都视为一个独立的计算单元。

每一个这样的层都配备一个特定的前向函数。前向函数接收前一层的输出作为一个参数,同时接收该层特定的权重矩阵作为另一个参数。它的任务是生成该层的输出。这是我们前向计算图中的一个步骤。

在代码中,如果使用Python类来表示一个层,你可以像下面这样为该类编写一个前向函数:

def forward(self, input, weights):
    # 计算该层的输出
    output = ... # 例如:output = weights @ input
    return output

同样,你也可以为该类编写一个反向函数,因为反向计算也包含相同数量的步骤,只是以相反的顺序运行。

反向函数接收什么作为输入呢?它接收 d_loss_by_d_hk(即损失对该层输出的梯度,记作 hk_bar)作为输入。同时,它也接收该层在前向传播中生成的输出 hk,以及该层拥有的权重参数。

因此,无论是全连接层还是非线性激活层,每一层都将拥有两个这样的函数:

  • 一个前向函数,使用该层的权重和输入作为参数,生成该层的输出。
  • 一个反向函数,使用该层输出的梯度 hk_bar、该层前向输出 hk 以及该层的参数作为参数。

那么反向函数返回什么呢?它返回两个结果:

  1. w_bar(或记作 sk_bar):该层权重的梯度。
  2. h_k-1_bar:该层输入的梯度(即传递给前一层的梯度)。

理解这一点非常重要:反向函数接收该层输出的梯度,并返回该层权重的梯度以及该层输入的梯度。

为了给你一个更直观的图像,假设我们有一个层执行运算 e = v * h。那么:

  • 前向函数很简单:接收 vh 作为输入,返回 e 作为输出。
  • 反向函数则对应反向传播中的两步计算:它接收 e_bare 的梯度)和 h 作为输入,返回 v_barh_bar 作为输出。

在你的作业中,你将尝试为线性层(如 W^T * x)和非线性层(如 sigma 激活函数)编写这样的前向和反向函数,从而理解如何将这些部分组合在一起。

如果对于神经网络中你想执行的每一个复杂操作(例如卷积、复杂的非线性激活函数等),都必须手动编写这两个函数,那将非常困难。

PyTorch 等现代深度学习框架最大的好处就在于此。如果你需要创建一个框架内没有的新层,你只需要编写该层的前向函数。PyTorch 会自动地、在内部为你完成反向版本的计算,自动应用链式法则。你不再需要手动编写反向函数。


回顾21世纪头十年的研究论文,大约10页纸中有8页都在讨论如何推导链式法则和编写这类反向函数。而现在,我们可以用一行代码完成所有这些工作。这极大地降低了深度学习的入门门槛,使得人人都能更容易地进行深度学习实践。


本节课中,我们一起学习了神经网络层的抽象概念。我们明确了每一层都应具备前向和反向计算功能,并理解了反向函数如何接收输出梯度并返回权重和输入梯度。最重要的是,我们认识到现代深度学习框架(如 PyTorch)通过自动微分机制,使我们只需定义前向计算,从而极大地简化了反向传播的实现过程。

posted @ 2026-03-26 12:23  布客飞龙III  阅读(5)  评论(0)    收藏  举报