Vizuara-机器学习基础笔记-全-
Vizuara 机器学习基础笔记(全)
001:机器学习基础课程介绍 🎯

在本节课中,我们将介绍“机器学习基础”这门课程的目标、内容结构以及学习它的重要性。我们将探讨扎实的数学和编程基础对于深入理解机器学习的关键作用。
大家好,欢迎来到名为“机器学习基础”的新课程。
我是 Sharia Pant 博士。我于2022年从麻省理工学院获得博士学位。
在此之前,我于2017年从印度马德拉斯理工学院完成了学士学位。
我本科以及博士期间的所有正规教育都是在机械工程系完成的。
我在2019年或2020年左右学习了第一门正式的机器学习课程。
那是麻省理工学院的一门研究生级别的高级机器学习课程。
这门课程让我接触到了许多可以融入我研究中的思想。之后,
我在一些研究问题中使用了机器学习中的某些框架,例如科学机器学习、使用神经网络进行图像分类等,这非常吸引人。当我参加这些课程时,
我确实注意到了世界顶尖大学的机器学习课程与其他地方的教学方式之间的差异。
这些课程非常强调基础知识。
我的意思是,它们非常强调机器学习背后的数学,非常强调微积分、概率论和线性代数。
同时也非常强调从零开始编写代码。
如果你将此与许多在线课程进行比较,
那些课程试图通过让你做一些简单的Kaggle项目或其他项目来给你一些实践经验,让你感觉能够自己构建和运行机器学习模型。
但最终,当你回顾时,你将无法向他人解释清楚其中的原理,而这正是检验你是否深入理解某事物的标准。我注意到,
如果你问一个正在学习机器学习的人一个简单的问题,比如:为什么神经网络需要激活函数?如果没有激活函数会发生什么?
你会发现,大多数人将无法回答这个问题。
理解没有激活函数时神经网络会发生什么,是一个非常简单直观的思考过程。
但从一个真正的概念层面来思考这个问题,你需要深入理解神经网络如何工作、到底发生了什么,以及这一切如何与线性代数联系起来。
上一节我们介绍了课程的目标和重要性,本节中我们来看看这门课程将具体涵盖哪些核心内容。
以下是本课程将涵盖的主要数学领域:
- 线性代数:处理向量、矩阵和高维数据的基础。
- 概率论:理解数据中的不确定性和统计推断。
- 微积分:优化算法(如梯度下降)的核心。
- 优化:寻找最佳参数或模型的核心理论。
此外,课程将强调从零开始编码,以确保你不仅理解理论,还能将其付诸实践。

本节课中我们一起学习了“机器学习基础”课程的开篇介绍。我们了解了拥有坚实的数学和编程基础对于深入、真正理解机器学习算法至关重要,而不仅仅是停留在应用层面。本课程旨在填补这一空白,通过强调线性代数、概率论、微积分和优化等核心数学概念,并结合从零开始的编程实践,帮助你建立对机器学习的深刻直觉和扎实功底。
002:向量、变换与空间

在本节课中,我们将学习机器学习所需的数学基础,特别是线性代数。我们将从机器学习的角度出发,重点理解线性代数的核心概念及其直观的几何意义,而非深入其所有细节。
向量:两种视角
上一节我们介绍了本课程的目标,本节中我们来看看线性代数中最基本的概念:向量。
在物理学中,向量被定义为具有大小和方向的量。在坐标系中,向量的起点可以是任意位置,不一定在原点。
在计算机科学中,向量通常指一个数字列表。例如,一个学生的信息(学号347,年龄20,体重70公斤)可以表示为一个三维向量。
对于机器学习而言,我们主要讨论的向量几乎总是以原点为起点的。这意味着我们关注的是向量的方向和大小,而不关心它在空间中的绝对位置。在二维平面(xy平面)中,一个向量具有两个维度:x维度和y维度。

向量的表示与运算
理解了向量的基本定义后,我们来看看如何表示和操作向量。
在数学上,一个二维向量可以写作 v = [x, y]。向量的基本运算包括加法和标量乘法。
以下是向量运算的规则:
- 向量加法:对应分量相加。v + w = [x1 + x2, y1 + y2]
- 标量乘法:每个分量乘以标量。c * v = [cx, cy]
从几何上看,向量加法遵循平行四边形法则,标量乘法会改变向量的长度(可能还有方向)。
线性变换与矩阵
向量本身是静态的,而线性变换描述了如何对向量进行“操作”或“映射”。这是线性代数的核心。
一个线性变换需要满足两个条件:
- 可加性:T(v + w) = T(v) + T(w)
- 齐次性:T(c * v) = c * T(v)
在二维空间中,任何线性变换都可以用一个2x2矩阵来描述。矩阵的每一列代表了该变换将标准基向量(i-hat 和 j-hat)移动到的位置。
例如,一个变换矩阵 M = [[a, b], [c, d]] 作用于向量 v = [x, y] 的结果是:
M * v = x * [a, c] + y * [b, d] = [ax + by, cx + dy]
向量空间与子空间
最后,我们来探讨向量存在的“舞台”——向量空间。
向量空间是一个集合,其中的元素(向量)可以进行加法和标量乘法运算,并且运算结果仍然在这个集合中。常见的例子是所有二维实向量的集合 R²。
子空间是向量空间的一个子集,它本身也满足向量空间的所有条件。例如,在 R³(三维空间)中,任何穿过原点的直线或平面都是一个子空间。
理解向量空间有助于我们思考机器学习算法(如主成分分析PCA)所操作的数据所处的抽象空间。

本节课中我们一起学习了线性代数的基石:向量。我们从物理和计算机两种视角认识了向量,学习了其表示与基本运算。我们探讨了线性变换的概念及其与矩阵的等价关系,并初步了解了向量空间与子空间。这些概念为理解机器学习模型如何处理和转换数据奠定了坚实的基础。
003:矩阵乘法即线性变换

在本节课中,我们将学习线性代数的一个核心概念:线性变换。我们将探讨矩阵乘法如何实现线性变换,以及这种变换对向量产生的几何影响。理解这一概念对于构建坚实的机器学习基础至关重要。
什么是变换?
变换,可以理解为一个函数,它将一个输入向量映射为一个输出向量。例如,在一个二维XY空间中,存在向量 v1 和 v2。一个变换函数 F 可以将 v1 转换为 v2。请注意,在本讲座中,输入和输出向量的符号(如 u 或 v)可能交替使用,但每次都会明确指明其角色。
简而言之,变换就是改变向量的某种操作。变换后,向量可能仍在原空间内,但其方向和长度可能发生了改变。
线性变换的特性
在众多变换类型中,线性变换是线性代数的基石。线性变换必须满足两个关键特性:
- 所有直线在变换后必须保持为直线。
- 原点位置必须保持不变。
第一个特性“直线保持为直线”需要特别注意其含义。第二个特性“原点固定”则相对直观。
为了更清晰地理解第一个特性,让我们通过图示来观察。


上一节我们介绍了线性变换的基本定义和特性。接下来,我们将深入探讨矩阵如何具体地表示和执行线性变换。
004:矩阵乘法与复合变换

在本节课中,我们将学习线性代数中的一个核心概念:矩阵乘法。我们将回顾矩阵如何作为线性变换作用于向量,并深入探讨两个矩阵相乘如何代表一个复合线性变换。理解这一点对于掌握机器学习中的许多算法至关重要。
矩阵作为线性变换
上一节我们介绍了矩阵可以看作一个线性变换函数。本节中,我们来看看具体的例子。
线性变换是一个函数,它将一个向量 v 变换为另一个向量 v'。在二维平面中,变换矩阵是一个 2x2 的矩阵,向量则包含 x 和 y 两个维度。
以下是两个变换示例,帮助我们回顾这个概念。
示例1:旋转变换
假设有一个变换,它将 xy 空间中的任何向量逆时针旋转 90 度。
我们想观察向量 v 在逆时针旋转 90 度后的位置。为了便于描述,我们设定一个具体坐标:假设向量 v 的端点位于 (2, 1)。

示例2:剪切变换
现在,让我们考虑另一种常见的线性变换:剪切变换。想象一个力将网格的顶部向右推,而底部保持固定。
我们同样想观察一个向量在这种剪切变换下的结果。
追踪基向量的变换
为了理解任意向量在变换后的位置,一个有效的方法是追踪标准基向量的变换结果。
在二维空间中,标准基向量是 i-hat (1, 0) 和 j-hat (0, 1)。任何向量都可以表示为这两个基向量的线性组合。因此,如果我们知道变换后 i-hat 和 j-hat 的位置,我们就能通过相同的线性组合,计算出任何向量变换后的位置。
以下是追踪基向量的步骤:
- 确定变换前基向量 i-hat 和 j-hat 的位置。
- 应用线性变换,观察 i-hat 和 j-hat 移动到了哪里。
- 变换后基向量的新坐标,就构成了变换矩阵的列。
例如,对于一个逆时针旋转90度的变换:
- i-hat (1, 0) 移动到了 (0, 1)。
- j-hat (0, 1) 移动到了 (-1, 0)。
因此,对应的旋转矩阵是:
[[0, -1], [1, 0]]
矩阵乘法:复合变换
上一节我们介绍了单个矩阵对向量的变换。本节中,我们来看看当两个矩阵相乘时会发生什么,这代表了一个复合变换。
假设我们有两个连续的线性变换。首先应用变换 A,然后应用变换 B。向量 v 的最终位置是 B(A(v))。
在矩阵表示中,如果变换 A 对应矩阵 M_A,变换 B 对应矩阵 M_B,那么先进行 A 再进行 B 的复合变换,就等价于用矩阵 M_B * M_A 乘以向量 v。
核心公式:M_composite = M_B * M_A
(注意乘法的顺序是从右向左,代表变换的应用顺序)。
复合变换的几何意义
从几何角度看,矩阵乘法 M_B * M_A 意味着:先进行由 M_A 定义的变换,紧接着再进行由 M_B 定义的变换。
计算这个复合变换矩阵的列,同样可以通过追踪基向量来完成:
- 看 i-hat 首先被 M_A 变换到了哪里。
- 然后将这个结果再输入 M_B 进行变换。
- 最终得到的位置就是复合矩阵的第一列。
- 对 j-hat 重复此过程,得到复合矩阵的第二列。
总结

本节课中我们一起学习了线性代数中矩阵乘法的核心思想。我们回顾了矩阵作为线性变换的作用,并掌握了通过追踪基向量 i-hat 和 j-hat 来理解变换的方法。最重要的是,我们明白了两个矩阵相乘 M_B * M_A 代表了一个复合变换,即先应用 M_A 变换,再应用 M_B 变换。理解矩阵乘法的这一几何意义,是打通线性代数与机器学习中空间变换概念的关键。
005:线性代数 - 3D线性变换 🧮


欢迎来到机器学习基础的新一讲。
我们将继续学习线性代数。在前两讲中,我们了解了矩阵乘法如何直接与线性变换相关联。我们也学习了两个矩阵相乘,就像是两个线性变换依次应用(级联或组合)。所有这些内容我们都是在二维(2D)空间中学习的。
在本讲中,我们将看到一些在三维(3D)空间中非常相似的概念,这些概念也可以推广到任意维度。
本讲内容相对简短,因为我们不会像在2D中那样详细探讨3D中的所有内容,但我想向你展示事物在3D中是如何呈现的,就像在2D中一样。
从2D到3D的过渡
在学习矩阵乘法时,你可能听说过结合律。为了证明像 A × B × C(其中A、B、C是矩阵)这样的式子,你可以先计算 B × C,然后再与 A 相乘;或者先计算 A × B,然后再与 C 相乘,结果相同。
在2D中证明这一点,可以定义通用的矩阵A、B、C。例如,A可以是 [[a, b], [c, d]],B可以是 [[e, f], [g, h]],C可以是 [[i, j], [k, l]]。然后,你可以通过先计算这两个矩阵的乘积,再与另一个矩阵相乘,来证明等式两边相等。
但这过程可能有些繁琐。因为如果我们从线性变换的角度来看,矩阵乘法本身就是对向量施加变换的操作。
结合律的几何视角
当我们看到三个矩阵相乘 A × B × C 时,它的几何意义是依次对向量施加三个变换:首先应用变换 C,然后应用变换 B,最后应用变换 A。
因此,无论你写成 (A × B) × C 还是 A × (B × C),它们都表示相同的几何过程:先应用 C,再应用 B,最后应用 A。括号只是改变了计算的顺序,但最终施加到向量上的变换序列是相同的。这就直观地证明了矩阵乘法的结合律。

3D中的线性变换
现在,让我们将视角扩展到3D。在3D空间中,向量有三个分量 (x, y, z),而表示线性变换的矩阵是 3×3 矩阵。
一个 3×3 矩阵对一个3D向量的变换,可以理解为该矩阵的每一列定义了变换后新坐标系的基向量(i帽、j帽、k帽)在原始坐标系中的位置。
以下是3D中一些基本线性变换类型的示例:
- 缩放:沿坐标轴拉伸或压缩空间。
- 代码表示:
scale_matrix = np.diag([sx, sy, sz]),其中sx,sy,sz是各轴的缩放因子。
- 代码表示:
- 旋转:围绕某个轴旋转空间。例如,绕z轴旋转θ角度的矩阵是:
- 公式:
R_z(θ) = [[cosθ, -sinθ, 0], [sinθ, cosθ, 0], [0, 0, 1]]
- 公式:
- 剪切:使空间在一个方向上发生倾斜变形。
- 反射:关于某个平面翻转空间。
与2D类似,两个 3×3 矩阵 M1 和 M2 的相乘 M2 × M1,表示先应用变换 M1,再应用变换 M2。结果矩阵 M_result 的每一列,就是原始基向量 (1,0,0), (0,1,0), (0,0,1) 依次经过 M1 和 M2 变换后的最终位置。
高维推广
这些概念并不局限于3D。对于n维空间中的向量,线性变换由一个 n×n 矩阵表示。矩阵乘法仍然对应变换的复合,结合律同样成立。机器学习中经常处理高维数据(例如,每个数据点是有多个特征的向量),理解线性变换的几何直观至关重要。
总结
在本节课中,我们一起学习了:

- 从几何变换的角度理解了矩阵乘法结合律,避免了繁琐的代数证明。
- 将2D中的线性变换概念推广到3D空间,了解了 3×3 矩阵的作用。
- 认识到这些关于矩阵、变换和乘法的原理可以自然地推广到更高维度,为理解机器学习算法中处理高维数据奠定了基础。
核心要点是:矩阵代表对空间的线性变换,矩阵乘法代表变换的依次应用(复合)。 无论维度如何,这一几何本质保持不变。
006:行列式的物理直觉
在本节课中,我们将学习线性代数中的一个核心概念——行列式。我们将不从传统的数学公式角度,而是从一个几何或物理直觉的角度来理解它。这种视角将帮助你更直观地把握线性变换的本质。
线性变换回顾
上一节我们介绍了线性变换,它可以将二维空间进行拉伸或挤压。为了直观展示,我们通常观察单位向量 i 和 j 在变换后的位置。
拉伸空间的例子
让我们看一个拉伸空间的线性变换例子。考虑以下变换矩阵 M:

M = [[2, -2],
[-1, 1]]

这个矩阵对应着对二维空间的一种变换。要理解这个变换,我们只需追踪单位向量 i 和 j 的去向。
- i 向量的去向:变换后,单位向量 i 会移动到矩阵 M 的第一列所表示的位置,即
[2, -1]。 - j 向量的去向:变换后,单位向量 j 会移动到矩阵 M 的第二列所表示的位置,即
[-2, 1]。
原始的单位向量 i 和 j 构成了一个标准的单位正方形。经过变换后,这两个向量被拉长并改变了方向,这意味着整个空间被拉伸了。空间中的每一个向量,不仅仅是单位向量,都会经历类似的变换。

挤压空间的例子
接下来,我们看一个挤压空间的例子。考虑另一个变换矩阵:
M_squish = [[0.5, 0],
[0, 0.5]]
以下是这个变换的效果:
- i 向量的去向:变换后,单位向量 i 移动到
[0.5, 0],长度缩短为原来的一半。 - j 向量的去向:变换后,单位向量 j 移动到
[0, 0.5],长度同样缩短为原来的一半。
在这个变换中,两个单位向量都向原点方向收缩。结果,由它们张成的单位正方形面积大大缩小,整个空间被均匀地挤压了。
行列式的几何意义
现在,我们引入行列式。在上述例子中,变换矩阵的行列式(det)量化了这种面积变化。
- 对于拉伸的例子,变换后的面积大于原始面积,其行列式值为一个正数。
- 对于挤压的例子,变换后的面积小于原始面积,其行列式值为一个小于1的正数。
更一般地,行列式的绝对值表示线性变换对面积(在二维中)或体积(在三维中)的缩放比例。行列式的符号则指示了变换是否改变了空间的“手性”或方向(类似于将平面翻转)。

总结

本节课中,我们一起学习了行列式的几何直觉。我们通过观察线性变换如何拉伸或挤压由单位向量张成的空间,理解了行列式本质上衡量了变换对空间面积的缩放因子。记住这个物理图像,将帮助你更直观地理解许多涉及行列式的线性代数概念。
007:非方阵的变换
在本节课中,我们将要学习线性代数中的一个重要概念:非方阵所代表的线性变换。我们将探讨非方阵如何作用于向量,以及这种变换在几何上的含义。
概述
到目前为止,我们主要研究了方阵,例如在二维空间中使用的2x2矩阵。这些矩阵代表了在相同维度空间内的线性变换,如旋转、剪切和缩放。然而,在实际应用中,尤其是在机器学习中,我们经常需要处理非方阵。本节课程将解答一个关键问题:当一个矩阵不是方阵时,它代表什么样的变换?
从方阵到非方阵
上一节我们介绍了方阵如何作为线性变换的表示。例如,一个2x2矩阵 M 的列向量定义了新的基向量,任何原始向量 v 都可以通过这些新基向量来表示变换后的结果。
公式表示:M * v = v'

现在,我们来看看非方阵的情况。考虑一个3行2列的矩阵,其形式如下:

矩阵示例:
[ a11, a12 ]
[ a21, a22 ]
[ a31, a32 ]
这个矩阵有两列,但有三行。根据我们对方阵的理解,矩阵的每一列代表一个基向量变换后的位置。对于一个2x2矩阵,这两列对应的是二维空间中 i 和 j 基向量的新位置。
非方阵的几何解释
那么,一个3x2矩阵的几何意义是什么?它有两列,这意味着它仍然是从两个基向量出发进行变换。但是,它有三行,这表示变换后的向量将存在于一个三维空间中。
核心概念:一个 m x n 的矩阵将一个 n 维空间中的向量,映射(或变换)到一个 m 维空间中。
在我们的例子中(3x2矩阵):
- 输入空间:二维空间(因为列数n=2,对应两个基向量)。
- 输出空间:三维空间(因为行数m=3,变换后向量的坐标由三个数字描述)。
因此,这个变换将一个二维平面“提升”或“嵌入”到了一个三维空间里。原始二维平面上的每一个点,在经过这个3x2矩阵变换后,都变成了三维空间中的一个点。
矩阵与向量的作用
接下来,我们看看这个矩阵如何作用于一个向量。
一个3x2矩阵只能与一个二维向量(即拥有两个分量的向量)相乘。相乘的结果是一个三维向量。
运算示例:
设矩阵 A = [[1, 2], [3, 4], [5, 6]],向量 v = [7, 8]^T。
它们的乘积是:
A * v = 7*[1, 3, 5]^T + 8*[2, 4, 6]^T = [7+16, 21+32, 35+48]^T = [23, 53, 83]^T
以下是这个过程的分解:
- 矩阵的第一列
[1, 3, 5]^T是原始二维空间中第一个基向量(如i-hat)变换后在三维空间中的位置。 - 矩阵的第二列
[2, 4, 6]^T是原始二维空间中第二个基向量(如j-hat)变换后在三维空间中的位置。 - 变换结果就是向量 v 的每个分量,分别对这两个新的三维基向量进行缩放后相加。

重要特性与应用

理解非方阵变换的特性对机器学习至关重要。

- 降维与升维:一个 m x n 矩阵可以实现从n维空间到m维空间的转换。当 m < n 时,是降维;当 m > n 时,是升维。
- 机器学习中的应用:在机器学习中,这种操作无处不在。
- 全连接层:神经网络中的一层通常就是一个矩阵乘法,其权重矩阵往往是非方阵,用于改变数据的维度。
- 特征映射:将原始特征(如像素)通过线性变换映射到更高维或更低维的特征空间,以便于分类或回归。
- 数据压缩:降维技术(如PCA)的核心步骤就涉及非方阵变换。

总结

本节课中我们一起学习了非方阵的线性变换。我们明确了非方阵(m x n)的几何意义:它将一个n维空间中的向量变换到一个m维空间中。我们通过公式和示例理解了其运算过程,并探讨了这种维度变换在机器学习中的关键应用,如神经网络的层间变换和特征降维。掌握这一概念是理解更复杂机器学习模型的基础。
008:非方阵的变换


欢迎回到机器学习基础课程。我们将继续学习机器学习的数学基础,特别是线性代数。
概述
在本节课中,我们将要学习非方阵所代表的线性变换。到目前为止,我们主要讨论了方阵,但实际应用中会遇到各种形状的矩阵。理解非方阵的变换对于掌握更广泛的机器学习概念至关重要。
回顾:方阵作为变换
上一节我们介绍了矩阵本质上是二维或更高维空间中线性变换的表示。我们看到了不同的矩阵可以表示旋转变换、剪切变换,甚至是旋转和剪切同时发生的复合变换。所有这些变换都可以用矩阵表示。
你肯定注意到了一件事,并且可能产生了一个很自然的问题,这在我第一次学习时也发生过。我们之前总是在看方阵。例如,在二维空间中,我们主要看的是 2x2 矩阵。
假设我们有一个矩阵 M:
M = [[3, 2],
[1, 4]]
这是一个二维空间中的变换。其中,单位向量 i 被变换到位置 (3, 1),单位向量 j 被变换到位置 (2, 4)。这意味着新的基向量(相当于变换后的 i 和 j)分别是 (3, 1) 和 (2, 4)。现在,xy平面上的任何向量都可以用这两个新的基向量来表示。
如果我们有一个向量 v,那么 Mv 会生成一个新的变换后的向量,这个向量可以用新的基向量(即变换后的 i 和 j)来表示。
引入非方阵
现在,你可能会有一个非常普遍的问题:如果矩阵不是方阵会怎样?在实际应用中,你处理的不仅仅是方阵,还会遇到矩形矩阵,即非方阵。
本节内容就是关于:如果矩阵本身是非方阵,那么它能表示什么样的变换?
让我们来看一个非方阵的例子。这是一个 3x2 矩阵:
A = [[a11, a12],
[a21, a22],
[a31, a32]]
它有两列和三行。这个矩阵是做什么的?它对什么类型的向量进行操作?
非方阵的维度含义
理解非方阵变换的关键在于关注其输入和输出空间的维度。
- 列数:决定了输入向量的维度。对于一个 m x n 矩阵(m行,n列),它作用于一个 n 维的输入向量。
- 行数:决定了输出向量的维度。变换结果是一个 m 维的向量。
因此,一个 3x2 矩阵 A 表示一个从 2维空间 到 3维空间 的线性变换。
以下是具体步骤:
- 你从一个二维向量开始,例如
v = [x, y]^T。 - 矩阵 A 与这个向量相乘:
u = A * v。 - 结果 u 是一个三维向量。
这个过程可以想象为将一个平面(2D)中的点“提升”或“映射”到三维空间(3D)中的一个点。
总结

本节课中,我们一起学习了非方阵所代表的线性变换。我们回顾了方阵如何表示同一维度空间内的变换。然后,我们探讨了非方阵的关键特性:它将向量从一个维度空间变换到另一个维度空间。具体来说,一个 m x n 矩阵将 n 维向量变换为 m 维向量。理解这一点是理解后续更复杂线性代数概念(如秩、降维和特征分解)的重要基础。
009:矩阵逆的物理意义

概述
在本节课中,我们将要学习矩阵逆的物理意义。我们将从线性方程组出发,理解矩阵如何表示线性变换,并探讨矩阵的逆运算在几何上如何对应“逆向变换”的过程。
从线性方程组到矩阵表示
上一节我们介绍了矩阵作为线性变换的几何视角。本节中我们来看看如何用矩阵来表示一组线性方程组。
线性方程组中的每个方程,其变量仅与一个缩放系数相乘,然后进行加法或减法运算。例如,形如 αx + βy 的方程是线性的,因为变量x和y分别被系数α和β缩放后相加。变量之间不会相乘(如xy),也不会出现平方(如x²)、立方、对数或三角函数等非线性运算。
一组线性方程组可以简洁地用矩阵乘法来表示。考虑以下方程组:
a₁₁x₁ + a₁₂x₂ + ... + a₁ₙxₙ = b₁
a₂₁x₁ + a₂₂x₂ + ... + a₂ₙxₙ = b₂
...
aₘ₁x₁ + aₘ₂x₂ + ... + aₘₙxₙ = bₘ
我们可以将其写为矩阵形式:
A x = b
其中:
- A 是一个 m×n 的系数矩阵。
- x 是一个包含 n 个变量的列向量。
- b 是一个包含 m 个结果的列向量。

矩阵逆的直观理解
在了解了矩阵可以表示线性变换后,一个自然的问题是:这个变换可以逆转吗?这就是矩阵逆的概念。
从物理意义上讲,如果矩阵 A 代表一个线性变换(例如旋转、缩放),那么它的逆矩阵 A⁻¹ 就代表一个完全相反的变换,能将变换后的向量恢复原状。
用公式表示这个关系就是:
A⁻¹ (A x) = x
或者等价地:
A A⁻¹ = I
其中 I 是单位矩阵,代表“什么都不做”的变换。
逆变换存在的条件
并非所有矩阵都存在逆矩阵。逆矩阵存在的关键条件是矩阵必须是方阵(行数等于列数),并且是满秩的,这意味着其列向量是线性独立的。
以下是一些直观理解:
- 如果一个变换将空间压缩到更低的维度(例如将3D空间投影到2D平面),信息会丢失,你无法从结果唯一地确定原始向量。这种变换没有逆。
- 如果一个变换是“一对一”且“满射”的(即不同输入对应不同输出,且所有输出都可能被达到),那么理论上存在逆变换。
总结
本节课中我们一起学习了矩阵逆的物理意义。我们了解到:
- 线性方程组可以用矩阵乘法 A x = b 表示。
- 矩阵 A 代表一个线性变换。
- 矩阵的逆 A⁻¹ 代表该变换的逆向操作,满足 A⁻¹A = I。
- 只有方阵且满秩(列线性独立)时,逆矩阵才存在。

理解矩阵逆的几何意义,对于后续学习如何求解线性方程组、理解许多机器学习算法中的优化步骤至关重要。
010:点积与线性变换的关系

在本节课中,我们将要学习线性代数中的一个核心概念:点积。我们将探讨点积与之前学习的线性变换之间有何联系,并理解其几何意义。
概述
在之前的课程中,我们学习了线性变换、矩阵乘法作为线性变换、以及矩阵与向量相乘作为向量的线性变换。本节我们将聚焦于点积运算,并揭示它如何与线性变换的概念相关联。
点积的数值计算
首先,我们回顾点积的数值计算方法。点积作用于两个向量,并产生一个标量结果。
例如,有两个向量 a = [1, 2, 3] 和 b = [3, 2, 1]。它们的点积计算如下:
a · b = (1 × 3) + (2 × 2) + (3 × 1) = 3 + 4 + 3 = 10
用公式表示,对于两个 n 维向量 u = [u₁, u₂, ..., uₙ] 和 v = [v₁, v₂, ..., vₙ],点积定义为:
u · v = u₁v₁ + u₂v₂ + ... + uₙvₙ
点积的几何意义
从几何角度看,点积可以理解为一个向量在另一个向量方向上的投影长度与后一个向量长度的乘积。
假设在二维空间中,有向量 u 和 v。将向量 v 投影到 u 所在直线上,会得到一个标量长度(即投影长度)。点积 u · v 就等于这个投影长度乘以向量 u 自身的长度。
有趣的是,这个运算顺序可以互换。我们也可以将向量 u 投影到 v 上,然后用得到的投影长度乘以向量 v 的长度,结果相同。
投影顺序的对称性
你可能会问,为什么投影的顺序不影响最终结果?这背后存在一种几何对称性。
考虑两个长度相等但方向不同的向量 u 和 v。你可以在它们之间画一条对称轴。由于两个向量长度相等,并且点积运算在几何上是对称的,因此无论将哪个向量投影到另一个上,其“有效贡献”是相同的,所以结果不变。更严格的证明可以通过余弦定理和向量夹角公式来完成,但几何直观有助于我们理解这种对称性。
点积与线性变换的联系
现在,我们进入核心部分:点积如何与线性变换联系起来。
我们可以将点积看作一种特殊的线性变换。具体来说,对向量进行点积运算,等价于将该向量通过一个特定的线性变换矩阵,然后与另一个向量进行标准点积。
更直接地说,对于固定的向量 w,函数 f(v) = w · v 是一个从向量空间到标量的线性函数。根据线性代数的知识,任何这样的线性函数都可以表示为某个矩阵(在此例中是一个行向量)与输入向量 v 的矩阵乘法。
例如,向量 w = [w₁, w₂, w₃] 与向量 v 的点积,等价于将 w 视为一个 1×3 的行矩阵,然后与列向量 v 相乘:
w · v = [w₁ w₂ w₃] * [v₁, v₂, v₃]^T
这里,行矩阵 [w₁ w₂ w₃] 就定义了一个从三维空间到一维数轴的线性变换。这个变换将任意输入向量 v 映射到它在 w 方向上的“带符号长度”(即点积值)。
总结
本节课我们一起学习了点积与线性变换的关系。
- 我们回顾了点积的数值计算方法和几何意义(投影)。
- 我们探讨了点积运算中投影顺序的几何对称性。
- 最重要的是,我们建立了点积与线性变换的联系:两个向量的点积,可以理解为其中一个向量(作为行矩阵)对另一个向量实施的线性变换,其结果是一个标量。

理解点积的这一本质,对于后续学习机器学习中诸如余弦相似度、支持向量机、神经网络中的权重计算等概念至关重要。它不仅是数值运算,更是一种衡量向量方向对齐程度的几何工具和线性映射。
011:特征值与特征向量的直观理解


欢迎回到我们的机器学习基础课程。我们将继续学习数学基础,特别是线性代数部分。在未来的课程中,我们当然会学习统计学、概率论等内容。但本节课将是我们在本系列中,为机器学习目的而讲解线性代数基础知识的最后一讲。本节课我将介绍我最喜欢的主题之一:特征值与特征向量。
我之所以喜欢这个主题,是因为对特征值与特征向量的直观理解,通常没有在大学教学中以直观的方式被传授。当我第一次学习这个概念时,它并没有以一种直观的方式介绍给我,而是过分关注了特征值与特征向量的数学方面。因此,我很快就忘记了这个概念本身,甚至在忘记之前,理解起来就非常困难。在本节课中,我们将尝试建立关于特征值与特征向量的一个非常简单的几何直觉。当然,我们将通过线性变换的视角来看待这个问题。
课程概述
在本节课中,我们将从线性变换的角度来理解特征值与特征向量,从而建立其几何直觉,而不仅仅是数学框架。
回顾线性变换
在整个课程中,我们一直在研究线性变换。简单回顾一下,我们将矩阵视为一个线性变换。如果矩阵是方阵,它将在其所在的空间内执行线性变换。如果它是非方阵,则可能将向量从一个空间(例如2D空间)变换到另一个空间(例如3D空间),或者从3D空间变换到2D空间,因此维度可能会增加或减少。
我们还看到,矩阵与向量的乘法是对向量的线性变换,而矩阵与矩阵的乘法则像是复合的线性变换,其中两个线性变换被依次应用。如果你有一个旋转变换和一个缩放变换,你只需要将向量依次与旋转变换对应的矩阵和缩放变换对应的矩阵相乘即可。
从变换视角看特征值与特征向量
在本节课中,我们将从线性变换的角度来看待特征向量和特征值。这将帮助我们理解一个简单的几何直觉,而不仅仅是数学框架。
从数学上讲,我相信你对特征值和特征向量已经很熟悉了。如果你还没有听说过,简单来说:
公式:A * x = λ * x
其中,A 是一个矩阵,x 是一个向量,λ 是一个标量。如果存在这样的关系,那么 x 被称为矩阵 A 的特征向量,λ 被称为对应于该特征向量的特征值。
这里,A 是一个对向量 x 进行变换的线性变换。但这个变换的特殊之处在于,被变换的原始向量 x 仅仅是被缩放了,而 λ 就是这个缩放因子。

核心概念解析
上一节我们回顾了线性变换并引入了特征值的数学定义。本节中,我们来深入理解这个定义的几何意义。
以下是理解特征值与特征向量几何意义的关键点:
- 不变的方向:对于一个线性变换
A,特征向量x在经过变换后,其方向保持不变(或恰好反向)。它不会被旋转到其他方向。 - 纯粹的缩放:特征值
λ量化了特征向量x在该不变方向上被拉伸或压缩的程度。- 如果
|λ| > 1,向量被拉长。 - 如果
0 < |λ| < 1,向量被缩短。 - 如果
λ是负数,向量方向反转,同时长度按|λ|缩放。
- 如果
- 变换的“主轴”:特征向量可以被视为该线性变换的“主轴”。沿着这些方向,变换的效果最简单,仅仅是缩放。理解这些主轴,就抓住了这个变换最核心的几何行为。
总结

本节课中,我们一起学习了特征值与特征向量的直观几何解释。我们了解到,特征向量是线性变换中那些方向保持不变的向量,而特征值则描述了这些向量被缩放的程度。通过从线性变换的视角(而不仅仅是公式计算)来理解这个概念,我们能够更深刻地把握它在机器学习(例如主成分分析、谱聚类等算法)和许多其他领域中的应用本质。记住,特征向量揭示了变换的“内在”结构方向。
012:概率与统计入门 📊

在本节课中,我们将开始学习机器学习中至关重要的数学基础——概率与统计。我们将了解它们为何重要,并学习一些基本概念,为后续更深入的学习打下基础。
为什么概率与统计对机器学习至关重要?🤔
上一节我们介绍了机器学习所需的数学基础。本节中,我们来看看概率与统计扮演的核心角色。
机器学习涉及大量概率与统计知识,因为你需要构建数学模型,基于现有数据进行预测。有时,模型需要基于这些预测做出决策。例如,一个基于人工智能的垃圾邮件分类器必须决定一封邮件是垃圾邮件还是非垃圾邮件。这个决策是二元的。但为了做出预测或决策,它需要使用数学模型,并从收到的邮件中收集数据,然后自动判断。
概率与统计之所以是机器学习中最重要的概念之一,原因在于:在机器学习中,仅仅做出决策是不够的。为了让人们信任机器学习模型,你通常还需要展示你对预测结果的不确定程度。概率正是处理数据不确定性的数学分支。
而统计的作用在于,当你拥有一个庞大的数据集时,它能帮助你分析和总结数据,并提取有意义的见解。因为作为人类,我们无法处理海量数据,更不用说机器学习中常见的成千上万甚至十万个数据点了。除非数据以总结性的方式呈现,否则你无法处理它。统计能帮助你做到这一点。
在本讲座中,我们将学习概率与统计的一些非常基础的内容。随着后续四到五节课的推进,我们将学习概率与统计中更复杂的概念,特别是那些对机器学习有用的部分。当然,我们不会学习概率论的所有内容,那是一个非常庞大且复杂的主题。
基本概念:随机实验与样本空间 🎲
为了理解概率,我们首先需要定义一些基本术语。以下是理解概率论的基础构件:
- 随机实验:指在相同条件下可以重复进行,且每次结果不确定(随机)的过程。例如,抛一枚硬币或掷一个骰子。
- 样本空间:指一个随机实验所有可能结果的集合。通常用符号 S 或 Ω 表示。
- 例如,抛一枚公平硬币的样本空间是
S = {正面, 反面}。 - 掷一个六面骰子的样本空间是
S = {1, 2, 3, 4, 5, 6}。
- 例如,抛一枚公平硬币的样本空间是
- 事件:指样本空间中我们感兴趣的特定结果集合。它是样本空间的一个子集。
- 例如,在掷骰子中,“得到偶数”是一个事件,它对应于集合
E = {2, 4, 6}。
- 例如,在掷骰子中,“得到偶数”是一个事件,它对应于集合
概率的定义与计算 📐
现在我们已经定义了实验和事件,接下来我们看看如何量化一个事件发生的可能性。
概率是对事件发生可能性的数值度量。对于一个随机实验中的事件 A,其概率 P(A) 满足以下公理:
- 任何事件 A 的概率是非负的:P(A) ≥ 0。
- 样本空间 S 的概率为 1:P(S) = 1。
- 对于互斥事件(不能同时发生的事件),它们的并集概率等于各自概率之和。
对于样本空间由有限个等可能结果组成的情况,事件 A 的概率可以用以下公式计算:
P(A) = (事件A中有利结果的数量) / (样本空间中结果的总数)
例如,在掷一个公平的六面骰子时,事件“掷出 3 或 4”的概率计算如下:
- 有利结果:{3, 4},共 2 个。
- 总结果数:6。
- 因此,P(掷出3或4) = 2 / 6 = 1/3。
总结

本节课中,我们一起学习了概率与统计在机器学习中的重要性。我们了解到,概率用于量化预测中的不确定性,而统计则帮助我们从海量数据中提取有意义的总结。我们定义了随机实验、样本空间和事件等基本概念,并学习了在等可能结果情况下计算概率的基本公式。这些基础概念是理解更复杂机器学习模型的基石。在接下来的课程中,我们将以此为基础,继续探索更多相关的概念。
013:条件概率


欢迎回到机器学习基础课程。我们继续学习一些数学基础。在本节课中,我们将了解概率论的一些基础知识。如果你想成为一名专业的机器学习工程师,这些知识是必须掌握的。
本课程主要面向初学者。如果你已经非常熟悉概率论,可能会觉得其中一些概念非常简单。但如果你是初学者或第一次学习,你一定会有所收获。我们将尝试理解一些基本概念,而不深入探讨概率论的极端细节,这些细节在我们后续学习机器学习时可能并不需要。
首先,我想强调机器学习中最需要的两个重要概念是条件概率和贝叶斯定理。因此,当我们谈论概率论基础时,我们将主要关注条件概率,并深入探讨贝叶斯定理。我第一次学习贝叶斯定理时,虽然公式很简单,但其背后的物理直觉以及与公式的对应关系总是令人困惑。每当遇到相关问题时,几乎总是会引起混淆。我第一次学习时感觉并不轻松,但随着直觉的加深,我意识到有更简单的方法来思考和理解贝叶斯定理。我将尽力将这些想法传递给你。
📊 概率快速回顾
事件E的概率P(E)等于有利结果的数量除以结果的总数。例如,如果我们进行的实验是掷一个骰子,事件定义为出现数字4。那么,整个实验空间是{1, 2, 3, 4, 5, 6},而事件空间只包含数字4。所以概率基本上是事件空间的大小除以整个结果空间的大小,即1除以6。这是一个相当容易理解的概念:掷一个普通骰子时,任何给定数字的概率是1/6。
这是快速的回顾,我们不想进一步深入,因为这些是简单的数学定义。
🤔 概率在机器学习中的应用
那么,概率,特别是条件概率,究竟在机器学习中何处使用呢?这几乎无处不在,因为现实世界中存在不确定性。
如果你有一个关于电子邮件的数据集,比如邮件中包含的词语或文本,你想根据文本进行分类。

🔍 理解条件概率
上一节我们回顾了基本概率。本节中,我们来看看条件概率。
条件概率是指在已知另一个事件B已经发生的情况下,事件A发生的概率。记作 P(A|B)。
其公式为:
P(A|B) = P(A ∩ B) / P(B)
其中,P(A ∩ B) 是事件A和事件B同时发生的概率(联合概率),P(B) 是事件B发生的概率。
为了更直观地理解,我们可以将其视为在事件B的“世界”或“空间”中,事件A发生的比例。它衡量了在给定一些额外信息(B已发生)后,我们对事件A发生可能性的评估如何变化。
📝 条件概率示例
以下是理解条件概率的一个简单示例:
假设我们有一个包含100人的数据集。其中,40人是女性,60人是男性。在女性中,10人戴眼镜。在男性中,20人戴眼镜。
现在,我们随机选择一个人。我们想知道:在已知此人是女性的条件下,她戴眼镜的概率是多少?
- 事件A:此人戴眼镜。
- 事件B:此人是女性。
我们需要计算 P(戴眼镜 | 女性)。
根据公式:
P(戴眼镜 | 女性) = P(戴眼镜 ∩ 女性) / P(女性)
- P(戴眼镜 ∩ 女性) = 戴眼镜的女性人数 / 总人数 = 10 / 100 = 0.1
- P(女性) = 女性人数 / 总人数 = 40 / 100 = 0.4
因此,P(戴眼镜 | 女性) = 0.1 / 0.4 = 0.25 或 25%。
这意味着,如果我们已经知道选中的人是女性,那么她戴眼镜的概率是25%。这不同于总体中戴眼镜的概率((10+20)/100 = 30%),因为条件信息(“是女性”)改变了概率。
🧮 贝叶斯定理
理解了条件概率后,我们现在可以探讨机器学习的核心工具之一:贝叶斯定理。
贝叶斯定理提供了一种在已知新证据(数据)的情况下,更新假设(模型参数或类别)概率的方法。它建立了两个条件概率之间的关系。
贝叶斯定理的公式是:
P(A|B) = [P(B|A) * P(A)] / P(B)
其中:
- P(A|B) 是后验概率:在观察到证据B后,假设A为真的概率。
- P(B|A) 是似然:在假设A为真的条件下,观察到证据B的概率。
- P(A) 是先验概率:在观察到任何证据之前,假设A为真的初始概率。
- P(B) 是证据概率:观察到证据B的总概率(在所有可能假设下)。
💡 贝叶斯定理的直观理解
贝叶斯定理的核心思想是“用数据更新信念”。我们从对某件事的初始信念(先验P(A))开始。然后,我们收集到一些新数据或证据(B)。我们想知道,在看到这个证据后,我们的信念应该如何调整。贝叶斯定理通过结合证据在假设成立下的可能性(P(B|A))以及证据本身的普遍性(P(B)),来计算更新后的信念(后验P(A|B))。
一个常见的类比是医学诊断:
- A:患有某种疾病。
- B:检测结果为阳性。
- P(A):人群中该疾病的患病率(先验)。
- P(B|A):如果真有病,检测呈阳性的概率(检测的敏感性/似然)。
- P(B):总体上检测呈阳性的概率。
- P(A|B):在检测呈阳性的条件下,真正患病的概率(后验)。
贝叶斯定理告诉我们,即使检测非常准确(P(B|A)很高),如果疾病本身非常罕见(P(A)很低),那么一个阳性结果可能并不意味着你很可能真的患病,因为假阳性的可能性也需要考虑(这包含在P(B)中)。
🎯 总结
在本节课中,我们一起学习了概率论中两个对机器学习至关重要的基础概念。
首先,我们回顾了基本概率。接着,我们深入探讨了条件概率 P(A|B),它描述了在已知另一事件发生的情况下,某事件发生的概率。我们通过一个关于性别和戴眼镜的简单例子说明了其计算和含义。
最后,我们介绍了贝叶斯定理。这是一个强大的公式,用于在获得新证据后更新事件的概率。我们了解了其组成部分:先验概率、似然、证据概率和后验概率,并讨论了它在“用数据更新信念”中的核心作用。

掌握条件概率和贝叶斯定理是理解许多机器学习算法(如朴素贝叶斯分类器、贝叶斯网络以及更广泛的统计推断)的关键第一步。
014:贝叶斯定理 - 直觉与基础


欢迎来到关于贝叶斯定理的课程。我们将尝试建立一个非常简单的直观理解,来弄明白这个定理究竟在说什么。
在本节课中,我们也将尝试建立这个定理的数学描述,但会更侧重于其背后的逻辑直觉。
概述
在本节课中,我们将要学习贝叶斯定理的核心思想。我们将通过一个具体的医学诊断例子,一步步推导出贝叶斯定理的公式,并理解它在现实世界中的意义。
一个直观的例子
让我们来看一个例子。我们关注女性乳腺癌的病例。
假设数据是这样的:有1%的女性患有乳腺癌。这个数据可能不准确,但我们暂时不考虑这一点,只关注其传达的思想。
有一种叫做乳腺X光检查(mammogram)的技术,类似于对乳房进行X光检查,可以在X光片上看到乳腺癌的发生。
假设在这种检查中,如果确实存在乳腺癌,有80%的概率能够检测出来。这意味着在20%的情况下,即使乳腺癌存在,也无法被检测出来。这是第二个陈述所表达的意思之一。
第三个陈述说,有9.6%的乳腺X光检查会在没有癌症的情况下检测出乳腺癌。这些也被称为假阳性,因为你给出了“有癌症”的错误信息。所以,这9.6%的情况是乳腺X光检查可能给出假阳性。
那么,剩下的情况是什么呢?在90.4%的情况下,乳腺X光检查检测出乳腺癌,并且癌症确实存在。这也是第三个陈述所表达的意思。
构建概率表格
现在,让我们把所有这些信息放入一个表格格式中,以便更容易理解。
我们第一列对应“有癌症”,第二列对应“无癌症”。有1%的概率女性患有乳腺癌,所以这里写1%。有99%的概率她们没有癌症。
第一行说的是:如果某人的乳腺X光检查呈阳性。如果有人患有癌症,有80%的概率乳腺X光检查会呈阳性。但如果有人患有癌症,有20%的概率检查不会呈阳性,意味着检查会呈阴性。这就是乳腺X光检查准确率所表达的意思:在80%的癌症病例中能被检测出来,在20%的癌症病例中检测不出来。

上一节我们通过一个乳腺癌诊断的例子,引入了先验概率和条件概率的概念。本节中,我们来看看如何将这些信息组织起来,并引出贝叶斯定理的核心问题。
以下是构建完整概率表格的步骤:
- 确定先验概率:总体人群中,患癌的概率
P(癌症) = 1%,未患癌的概率P(无癌) = 99%。 - 确定似然概率:
- 在患癌的条件下,检测呈阳性的概率
P(阳性 | 癌症) = 80%。 - 在患癌的条件下,检测呈阴性的概率
P(阴性 | 癌症) = 20%。 - 在未患癌的条件下,检测呈阳性(假阳性)的概率
P(阳性 | 无癌) = 9.6%。 - 在未患癌的条件下,检测呈阴性(真阴性)的概率
P(阴性 | 无癌) = 90.4%。
- 在患癌的条件下,检测呈阳性的概率
- 计算联合概率:将先验概率与条件概率相乘,得到每个细分情况的概率。例如,一个人既患癌且检测呈阳性的概率是
P(癌症) * P(阳性 | 癌症) = 1% * 80% = 0.8%。
通过这个表格,我们可以清晰地看到所有可能情况的概率分布。然而,在实际诊断中,我们更关心一个逆向的问题:已知检测结果呈阳性,这个人真正患癌的概率是多少? 这正是贝叶斯定理要解决的核心问题。
贝叶斯定理的推导与应用
上一节我们得到了完整的概率分布表。现在,我们利用这个表格来回答那个关键问题:检测呈阳性时,实际患癌的概率是多少?
从表格中我们可以直接计算:
- 检测呈阳性的总概率
P(阳性)= 患癌且阳性的概率 + 无癌且阳性的概率 =0.8% + 9.504% = 10.304%。 - 在这部分阳性结果中,真正患癌的比例是
0.8%。
因此,在已知检测呈阳性的条件下,患癌的后验概率为:
P(癌症 | 阳性) = P(癌症且阳性) / P(阳性) = 0.8% / 10.304% ≈ 7.76%
这个计算过程就是贝叶斯定理的直观体现。我们可以将其抽象成通用公式。
贝叶斯定理的公式如下:
P(A|B) = [P(B|A) * P(A)] / P(B)
其中:
P(A|B)是后验概率,即在事件B发生的条件下,事件A发生的概率(这是我们想求的)。P(B|A)是似然概率,即在事件A发生的条件下,事件B发生的概率。P(A)是先验概率,即事件A发生的初始概率。P(B)是证据或边缘概率,即事件B发生的总概率,通常通过全概率公式计算:P(B) = P(B|A)*P(A) + P(B|非A)*P(非A)。
在我们的例子中:
A代表“患癌”,B代表“检测阳性”。P(癌症 | 阳性)是后验概率(≈7.76%)。P(阳性 | 癌症)是似然概率(80%)。P(癌症)是先验概率(1%)。P(阳性)是证据概率(10.304%)。
总结
本节课中,我们一起学习了贝叶斯定理的基础与直觉。
我们从一个乳腺癌诊断的实例出发,通过构建概率表格,直观地理解了先验概率、似然概率、联合概率和后验概率之间的关系。最关键的是,我们学会了如何利用已知的信息(如检测准确率和疾病基础发病率)来更新我们对某个事件(如一个人是否患病)发生概率的认知。这正是贝叶斯定理的核心:在获得新证据后,如何更新假设的概率。

记住这个核心公式 P(A|B) = [P(B|A) * P(A)] / P(B),它将在机器学习的许多领域,特别是分类和概率图模型中,发挥至关重要的作用。
机器学习基础:P15:概率分布

在本节课中,我们将学习概率分布的基础知识。概率分布描述了随机变量所有可能结果及其对应概率的分布情况,是理解数据不确定性和进行预测建模的核心工具。
上一节我们介绍了概率与统计的基本概念,本节中我们来看看概率分布的具体形式。
概率分布描述了随机变量所有可能结果对应的概率如何分布。这种分布本身可以是离散的或连续的。
- 离散分布:当实验结果是可数的、具体的值时,其概率分布是离散的。例如,抛硬币10次,正面朝上的次数只能是0到10之间的整数。
- 连续分布:当实验结果可以取某个区间内的任意值时(或在实践中可视为连续),其概率分布是连续的。
概率分布的核心思想是,进行一次实验时,某些结果出现的可能性更高,而另一些则更低。概率分布为我们提供了这种可能性的整体描述。这些分布在机器学习中至关重要,因为它们能对数据中的不确定性进行建模,并帮助我们进行预测。
例如,伯努利分布常用于二元分类问题,它描述了一次试验中“成功”或“失败”(例如,真或假)的概率。我们最近一篇关于大语言模型中偏见的研究论文,就涉及到了特定输出概率的计算。
以下是几种关键的概率分布及其应用:
1. 伯努利分布
伯努利分布描述单次试验中二元结果的概率分布。
- 公式:
P(X=1) = p,P(X=0) = 1-p。其中,X=1代表“成功”,其概率为p。 - 应用:模拟单次抛硬币、一次点击预测、或任何只有两种可能结果的事件。
2. 二项分布
二项分布描述在固定次数的独立伯努利试验中,“成功”次数的概率分布。
- 公式:
P(X=k) = C(n, k) * p^k * (1-p)^(n-k)。其中,n为试验总次数,k为成功次数,p为单次成功概率。 - 应用:计算抛硬币10次得到6次正面的概率,或在100次广告展示中获得一定点击次数的概率。
3. 均匀分布
均匀分布描述所有结果出现概率均等的情况。
- 离散均匀分布:掷一个公平的六面骰子,每个面朝上的概率都是1/6。
- 连续均匀分布:在区间
[a, b]内,任何子区间取值的概率与该子区间的长度成正比。 - 应用:等概率随机抽样、初始化模型参数。
4. 正态分布
正态分布(又称高斯分布)是最重要的连续分布之一,其概率密度函数呈钟形曲线。
- 公式:
f(x) = (1 / (σ√(2π))) * e^(-(x-μ)²/(2σ²))。其中,μ是均值(决定中心位置),σ是标准差(决定分布的宽度)。 - 应用:自然界中许多现象的近似分布(如身高、测量误差),也是许多统计方法和机器学习算法的基础假设。
5. 泊松分布
泊松分布描述在固定时间或空间间隔内,随机事件发生次数的概率分布。
- 公式:
P(X=k) = (λ^k * e^(-λ)) / k!。其中,λ是单位间隔内事件的平均发生次数,k是实际发生次数。 - 应用:模拟客服中心每小时接到的电话数、网站每分钟的访问次数或放射性物质在给定时间内的衰变次数。

本节课中,我们一起学习了概率分布的核心概念及其在机器学习中的重要性。我们介绍了伯努利分布、二项分布、均匀分布、正态分布和泊松分布这几种关键分布,了解了它们的定义、公式和典型应用场景。理解这些分布是构建机器学习模型、处理数据不确定性和进行统计推断的坚实基础。
016:假设检验与置信区间 🧪

在本节课中,我们将学习统计学中两个核心概念:假设检验与置信区间。它们是数据分析与机器学习的基石,能帮助我们判断数据的真实性、评估模型结果的可信度,并做出基于数据的决策。
概述
假设检验是一种统计方法,用于根据样本数据对总体参数提出假设并进行检验。置信区间则用于估计参数的真实值可能落在哪个范围内。理解这两个概念对于评估机器学习模型的性能、进行A/B测试以及理解数据中的不确定性至关重要。
上一节我们介绍了概率分布与抽样,本节中我们来看看如何利用这些知识对总体参数进行推断。
一个简单的案例
在深入数学细节之前,我们先看一个简单的案例。假设有一家制造电池的公司,他们生产了500块电池,并测试了每块电池的平均续航时间(以小时计)。
这家公司可能由于某些原因,未能生产出高质量的电池。他们实际收集到的电池续航数据可能如下所示:电池序号从1到500,对应的实际续航时间均值为79.5小时(约80小时),标准差为10小时。因此,电池的典型续航时间大约是80 ± 10小时。
然而,假设这家公司的目标是生产平均续航达到100小时的电池。为了掩盖产品不达标的事实,他们可能对数据进行了篡改。篡改的方式是给每一个原始数据都加上20小时。例如,将67小时改为87小时,将79小时改为99小时,将86小时改为106小时。
经过这样的篡改,电池续航的均值变成了接近99.5小时,标准差保持不变。于是,电池续航就从“80 ± 10小时”变成了“100 ± 10小时”,但这完全是人为操纵的结果。
核心概念:零假设与备择假设
面对上述情况,我们如何判断数据是否被篡改?这就需要引入假设检验。假设检验的第一步是建立两个对立的假设。
- 零假设 (Null Hypothesis, H₀):通常代表现状、无效果或没有差异的假设。在电池案例中,零假设可以是“电池的平均续航时间没有达到100小时”,或者更一般地,“样本所来自的总体的均值等于某个特定值”。
- 公式表示:H₀: μ = μ₀ (其中μ是总体均值,μ₀是某个假设值,例如100)
- 备择假设 (Alternative Hypothesis, H₁ 或 Hₐ):代表我们想要证明的、与研究预期一致的情况。在电池案例中,如果我们怀疑公司夸大数据,备择假设可以是“电池的平均续航时间低于100小时”。如果我们只是怀疑数据不真实,也可以是“电池的平均续航时间不等于100小时”。
- 公式表示(单侧检验):H₁: μ < μ₀ 或 H₁: μ > μ₀
- 公式表示(双侧检验):H₁: μ ≠ μ₀
检验的目的,就是利用样本数据提供的证据,决定是拒绝零假设(支持备择假设),还是没有足够证据拒绝零假设。
置信区间:估计的可靠性
除了直接检验假设,我们还可以通过构建置信区间来估计参数。置信区间提供了一个范围,我们有特定程度的信心(例如95%)认为总体参数的真实值落在这个范围内。
例如,根据公司的原始数据(均值79.5,标准差10,样本量500),我们可以计算总体平均续航时间μ的95%置信区间。计算过程涉及样本均值、标准误差和Z分数(或t分数)。
# 示例:计算95%置信区间 (使用Z分数,已知总体标准差或大样本)
import scipy.stats as stats
sample_mean = 79.5
sample_std = 10
n = 500
confidence_level = 0.95
# 计算标准误差
standard_error = sample_std / (n ** 0.5)
# 计算Z分数(对于95%置信度,双尾)
z_score = stats.norm.ppf(1 - (1 - confidence_level) / 2)
# 计算边际误差
margin_of_error = z_score * standard_error
# 计算置信区间
ci_lower = sample_mean - margin_of_error
ci_upper = sample_mean + margin_of_error
print(f"95% 置信区间为: ({ci_lower:.2f}, {ci_upper:.2f}) 小时")
运行类似代码,我们可能得到一个如 (78.62, 80.38) 小时的区间。这个区间完全低于100小时,增强了我们对“电池未达宣称标准”的怀疑。
相反,如果使用篡改后的数据(均值99.5)计算,置信区间可能会是 (98.62, 100.38) 小时。这个区间包含了100小时,但这并不能证明数据真实,只是说明篡改后的数据在统计上“看起来”符合100小时的标准。关键在于数据来源是否可信。
假设检验的步骤
以下是进行假设检验的一般步骤:
- 提出假设:明确零假设H₀和备择假设H₁。
- 选择显著性水平 (α):设定一个阈值(常用0.05),用于判断结果是否具有统计显著性。它代表了当H₀为真时,我们错误地拒绝它的最大概率(第一类错误)。
- 计算检验统计量:根据样本数据、假设的总体参数以及数据分布,计算一个统计量(如Z值、t值)。
- 公式示例(Z检验):Z = (x̄ - μ₀) / (σ / √n)
- 做出决策:
- P值法:计算得到当前样本结果(或更极端结果)的概率(P值)。如果P值 ≤ α,则拒绝H₀。
- 临界值法:将计算出的检验统计量与对应α水平的临界值比较。如果统计量落在拒绝域,则拒绝H₀。
总结
本节课中我们一起学习了假设检验与置信区间的核心思想。我们通过一个电池数据篡改的案例,理解了提出零假设与备择假设的必要性。我们学习了置信区间如何为参数估计提供一个可靠的范围。最后,我们梳理了假设检验的标准步骤,包括设定显著性水平、计算检验统计量以及基于P值或临界值做出统计决策。

掌握这些概念,你就能为评估机器学习模型(如比较两个模型准确率是否有显著差异)、分析实验数据打下坚实的统计学基础。记住,统计推断的目标不是证明,而是在不确定性中做出尽可能合理的判断。
017:朴素贝叶斯分类与模型评估 📊


在本节课中,我们将要学习两个在机器学习与数据科学项目中极其常见的主题:朴素贝叶斯分类器和模型评估。虽然本课程尚未深入探讨机器学习模型的细节,但本讲将为你提供一个概览,让你了解学习分类方法和评估模型效能时将会接触到的核心概念。
上一讲我们探讨了贝叶斯定理和假设检验。本节中,我们将聚焦于一个特定的分类器——朴素贝叶斯分类器。



第一部分:朴素贝叶斯分类器 📈
本部分我们将学习一些理论基础,并通过手算来实践朴素贝叶斯分类。我们会讨论其基本概念、核心假设,并一步步实现一个用于垃圾邮件分类的分类器。在之前的课程中,我们曾根据邮件中是否包含“Nigerian prince”这个词进行分类。今天,我们将看一个稍有不同的例子,同时考虑两个独立的词。
分类的概念



分类,简而言之,就是将给定项目归入两个或多个类别之一。
- 二元分类器:将输入划分到两个类别中。例如,将图像分类为“猫”或“狗”,将邮件分类为“垃圾邮件”或“非垃圾邮件”。
- 多元分类器:将输入划分到多个类别中。例如,著名的MNIST数据集将手写数字图像分类为0到9这10个类别之一。
在这些分类场景中,贝叶斯定理具有极其重要的意义,因为我们将要讨论的朴素贝叶斯分类器正是基于它来工作,用于判断一封邮件属于垃圾邮件还是非垃圾邮件。



第二部分:模型评估 📊


在模型评估部分,我们将讨论混淆矩阵,并学习数据科学家和机器学习工程师必备的性能指标,如准确率、精确率、召回率和F1分数。我们还会简要介绍交叉验证和统计显著性。如果你还不清楚这些术语的含义,不用担心,只需跟随本讲内容,并和我一起进行一些手算练习,我相信你能够完全理解。



本节课中,我们一起学习了朴素贝叶斯分类的基本原理及其在垃圾邮件分类中的应用步骤,并初步了解了评估机器学习模型效能的关键指标和方法。这些是构建和理解机器学习模型的重要基础。
机器学习基础:P18:机器学习微积分入门 🧮

在本节课中,我们将开始学习机器学习中至关重要的数学基础——微积分。我们将从最核心的概念入手,理解它如何成为优化算法和神经网络训练的基石。
在之前的模块中,我们学习了线性代数、统计学和概率论。现在,我们进入我个人最喜爱的部分——微积分。如果你已经熟悉微积分,特别是导数和连续性等概念,本节课会相当轻松,你可以将其视为一次复习。如果你是第一次学习微积分,我相信你也会乐在其中。
在机器学习的反向传播中,例如在神经网络模型里,你经常会用到链式法则。我曾有过从零开始构建神经网络的经历,当时需要定义一个函数来规定每次反向传播时权重的变化。由于网络末端使用了Softmax激活函数,定义关于权重和网络输入的偏导数变得有些棘手。我分享这个经历是想说明,微积分在神经网络乃至整个机器学习中的重要性。只有当你开始处理复杂任务时,才会真正体会到扎实的微积分基础能让你的工作轻松许多。
什么是微积分?
微积分是数学的一个分支,主要研究累积和变化率。
- 累积通常通过积分计算。
- 变化率通过微分计算。
这在优化算法中至关重要。可以说,微积分是人工智能与机器学习(AIML)的数学基础模块之一。如果你听说过梯度下降,那么微积分就是你实现它所需学习的最重要的数学知识。
在神经网络中,有一个权重调整的过程:你从随机权重开始,然后根据神经网络预测值与实际值之间的差距来调整这些权重的值。这个过程的核心就是微积分。
核心概念:导数
导数衡量的是函数在某一点处的瞬时变化率。简单来说,它告诉我们当输入发生微小变化时,输出会如何变化。
在数学上,函数 f(x) 在点 x 处的导数定义为:
f'(x) = lim (h -> 0) [f(x+h) - f(x)] / h
这个公式计算的是当 h(x的变化量)趋近于0时,函数值平均变化率的极限,即瞬时变化率。
为什么导数在机器学习中重要?
在机器学习中,我们经常要找到一个函数(比如模型)的最小值或最大值(通常是损失函数的最小值)。导数在这里起到了“指南针”的作用。
-
梯度下降:这是一种通过迭代调整参数来最小化损失函数的优化算法。其核心更新公式是:
θ_new = θ_old - α * ∇J(θ)
其中:θ代表模型参数(如权重)。α是学习率,控制步长。∇J(θ)是损失函数J关于参数θ的梯度(即多维导数)。梯度指向函数增长最快的方向,因此我们沿着负梯度方向更新参数以寻找最小值。
-
反向传播:在训练神经网络时,我们使用反向传播算法来计算损失函数相对于网络中每一个权重的梯度(偏导数)。链式法则是实现这一计算的关键工具。
连续性
在讨论导数之前,理解连续性很有帮助。一个函数在某点连续,直观上意味着其图像在该点没有“断裂”或“跳跃”。更严格地说,函数 f(x) 在点 c 连续需要满足三个条件:
f(c)有定义。lim (x -> c) f(x)存在。lim (x -> c) f(x) = f(c)。
可导的函数一定连续,但连续的函数不一定可导(例如,在尖点处)。
总结

本节课我们一起学习了机器学习微积分的入门知识。我们了解到微积分是研究变化率和累积的数学分支,并重点探讨了其核心——导数的概念。导数衡量函数的瞬时变化率,是理解梯度下降等优化算法的基础。在神经网络中,通过反向传播和链式法则计算导数,从而调整权重以最小化误差。建立这些核心概念的坚实基础,将为你后续深入理解复杂的机器学习模型扫清重要障碍。
019:链式法则 🧮

在本节课中,我们将学习微积分在机器学习中的一个核心概念——链式法则。链式法则是理解神经网络如何通过反向传播更新权重的基础。我们将通过简单的例子和直观解释来掌握它。
概述
本节课我们将聚焦于链式法则及其在机器学习中的应用。链式法则用于计算复合函数的导数,这在神经网络的多层结构中至关重要,因为它帮助我们理解一层的变化如何影响其他层。

复合函数示例


考虑函数 f(x) = sin(x²)。我们可以将其拆分为两个函数:
- 令 g(x) = x²。
- 则 f(x) = sin(g(x))。
这样,f(x) 就成为了一个复合函数,即一个函数嵌套在另一个函数内部。



链式法则的定义

如果 y = f(g(x)),那么 y 关于 x 的导数 dy/dx 可以通过链式法则计算:
dy/dx = (df/dg) * (dg/dx)
我们也可以引入中间变量 z = g(x),将公式写作:
dy/dx = (dy/dz) * (dz/dx)
这个规则同样适用于偏导数。
链式法则的直观理解



让我们暂时忘记公式,从逻辑上理解链式法则。


假设你想知道汽车油耗(y)如何随行驶速度(x)变化。但油耗并不直接取决于速度,而是取决于发动机转速(z),而转速又取决于速度。因此,速度对油耗的影响可以分解为两步:
- 速度变化对发动机转速的影响(dz/dx)。
- 发动机转速变化对油耗的影响(dy/dz)。

总的影响 dy/dx 就是这两个影响的乘积。这就是链式法则的物理逻辑:它将一个复杂的变化率分解为一系列更简单、更直接的变化率的乘积。

链式法则在机器学习中的应用



在机器学习,尤其是神经网络中,链式法则的作用至关重要。

神经网络由多层组成。在训练过程中,我们需要根据最终输出的误差,来调整网络中每一层的参数(权重)。这个过程称为反向传播。
链式法则使得这种调整成为可能。输出层的误差会通过链式法则,一层一层地反向传递回去,计算出每一层参数应该做出的调整量。每一层的调整都依赖于其后一层的调整结果,这正是复合函数求导的链式过程。


因此,可以说链式法则是神经网络能够“学习”的数学基础。

总结

本节课我们一起学习了链式法则。我们了解了其数学定义 dy/dx = (dy/dz) * (dz/dx),并通过直观例子理解了其核心思想:将整体变化率分解为多个局部变化率的连锁效应。最重要的是,我们明确了链式法则是神经网络反向传播算法的基石,它使得多层网络参数的协同优化成为可能。掌握链式法则,是理解现代机器学习核心运作原理的关键一步。
020:机器学习中的积分学 📚

在本节课中,我们将开始学习机器学习中至关重要的积分学。我们将介绍定积分、不定积分以及微积分基本定理,为后续更复杂的机器学习数学概念打下基础。


从微分到积分 🔄
在之前的课程中,我们学习了导数。导数衡量的是函数在特定瞬间的变化率。
积分,正如你可能已经知道的,是微分的一种反向过程。如果说微分是“求变化率”,那么积分可以被理解为“累积变化量”。

积分的几何意义:面积 📐

积分的一个核心几何意义是求曲线下的面积。如果你对一个函数从点A到点B进行积分,那么该积分的结果就等于该函数曲线在区间 [A, B] 下的面积。

这个运算用以下符号表示:
∫_a^b f(x) dx
其中 ∫ 是积分符号,a 和 b 是积分下限和上限,f(x) 是被积函数,dx 表示对变量 x 进行积分。


黎曼和:面积的近似计算 📊
你可能听说过黎曼和。在黎曼和的方法中,曲线下的面积可以通过对一系列矩形面积求和来近似表示。



以下是使用不同数量矩形进行近似的示意图:



- 第一张图:使用4个矩形来近似面积。
- 第二张图:使用更多(例如10个)矩形来近似面积。
- 第三张图:使用非常多的矩形(例如20个)来近似面积。


你可以观察到,当使用有限个矩形时,我们总是在高估曲线下的实际面积。图中灰色区域的总和就代表了这种高估的程度。

随着矩形数量的增加,每个矩形的宽度变窄,这些灰色区域的总面积会减少,我们的近似值也就越来越接近真实的曲线下面积。当矩形的数量趋近于无穷时,黎曼和的极限就精确地等于定积分的值。
本节课总结 📝


本节课我们一起学习了积分学的基础概念:
- 积分是微分的逆运算,用于累积变化量。
- 定积分
∫_a^b f(x) dx的几何意义是计算函数曲线在区间 [a, b] 下的面积。 - 黎曼和提供了一种通过将面积分割为多个矩形并求和,来近似计算定积分值的方法。矩形数量越多,近似越精确。


这些概念是理解后续机器学习中概率、优化和连续模型的基础。如果你对这些内容已经非常熟悉,可以将其视为一次复习;如果你是初学者,希望这个简明的介绍能帮助你建立直观的理解。下一讲,我们将深入探讨不定积分和微积分基本定理。
021:驱动机器学习的引擎

在本节课中,我们将学习偏导数与梯度,它们是机器学习的重要数学基础之一。我们将从多变量函数入手,逐步介绍偏导数和梯度的概念,并最终解释它们如何与机器学习模型训练的核心——优化过程——联系起来。
多变量函数
上一节我们讨论了单变量函数的导数。然而,现实世界中的大多数函数并非如此简单。它们通常依赖于多个独立变量。
例如,房间内的温度会随着具体位置(坐标X, Y, Z)的变化而变化。在机器学习中,以神经网络为例,其成本函数(或称损失函数)的值取决于网络中所有的权重和偏置参数。如果一个网络有500个权重和500个偏置,那么损失就是这1000个参数的函数。这类依赖于多个变量的函数被称为多变量函数。
一个最简单的多变量函数例子是:
f(x, y) = x² + y²
其图像是一个对称的抛物面。
偏导数
理解了多变量函数后,我们自然会问:如何衡量函数值随某一个特定变量的变化率?这就是偏导数的概念。
对于一个多变量函数 f(x, y, z, ...),其对变量 x 的偏导数,记作 ∂f/∂x,其含义是:在固定其他所有变量(如y, z, ...)不变的情况下,函数 f 相对于 x 的变化率。
计算偏导数非常简单:在求对某个变量的偏导时,将其他所有变量视为常数,然后应用我们熟悉的单变量求导法则。
以下是计算 f(x, y) = x² + y² 偏导数的步骤:
- 对
x求偏导:将y视为常数,y²的导数为0,x²的导数为2x。因此,∂f/∂x = 2x。 - 对
y求偏导:将x视为常数,x²的导数为0,y²的导数为2y。因此,∂f/∂y = 2y。
梯度
我们已经学会了如何分别计算函数对各个变量的偏导数。在优化中,我们需要一个能同时指出所有方向上变化率的工具,这就是梯度。
函数 f 的梯度是一个向量,记作 ∇f(读作“nabla f”)。它的分量由函数对所有变量的偏导数按顺序排列构成。
对于函数 f(x, y) = x² + y²,其梯度为:
∇f = [∂f/∂x, ∂f/∂y] = [2x, 2y]
梯度向量具有极其重要的几何意义:它指向函数值增长最快的方向。相应地,负梯度方向(-∇f)就指向函数值下降最快的方向。
梯度下降法
掌握了梯度的方向性后,我们可以利用它来寻找函数的最小值点,这个过程就是梯度下降法。它是训练几乎所有机器学习模型的核心优化算法。

梯度下降法的思想直观而朴素:既然负梯度方向是函数下降最快的方向,那么只要我们沿着这个方向一小步一小步地移动,最终就能走到(或接近)函数的谷底(最小值点)。

以下是梯度下降法的基本步骤:
- 初始化:随机选择参数的起始点(例如,
x=2, y=1)。 - 计算梯度:在当前点计算函数的梯度(例如,在
(2,1)点,∇f = [4, 2])。 - 更新参数:沿着负梯度方向移动一小步。移动的步长由一个称为学习率(Learning Rate)的超参数
α控制。
参数更新公式为:
[x_new, y_new] = [x_old, y_old] - α * [∂f/∂x, ∂f/∂y]
例如,若学习率α = 0.1,则新位置为:[2, 1] - 0.1 * [4, 2] = [1.6, 0.8]。 - 迭代:重复步骤2和步骤3,直到梯度变得非常小(接近零),或者达到预设的迭代次数。
通过不断迭代,参数 (x, y) 将逐渐逼近使函数 f(x, y) 取得最小值的点 (0, 0)。
总结
本节课中,我们一起学习了机器学习优化的核心数学工具。
- 我们首先认识了多变量函数,它描述了现实世界和机器学习模型中常见的复杂关系。
- 接着,我们学习了偏导数,它衡量了函数在固定其他变量时,沿某一个特定方向的变化率。
- 然后,我们将所有偏导数组合成梯度向量,它指明了函数值增长最快的方向。
- 最后,我们介绍了梯度下降法。通过反复计算梯度并沿负梯度方向更新参数,该算法能够有效地寻找函数的最小值点,这正是训练机器学习模型(最小化损失函数)的本质过程。

理解偏导数和梯度下降,是深入掌握机器学习工作原理的关键一步。
022:机器学习中的梯度下降

概述
在本节课中,我们将学习机器学习中一个核心且至关重要的概念:梯度下降。我们将探讨什么是损失函数,以及如何利用梯度下降来最小化它。此外,我们还将了解反向传播在神经网络中的作用,并讨论一些实际应用中的注意事项。
损失函数的概念
损失函数在机器学习中的概念相当直接。你有一个期望的结果。例如,如果你正在构建一个分类模型或线性回归模型,你有一个目标值,并且希望模型的预测值尽可能接近这个目标值。
但问题在于,你通常不只有一个输入和一个输出。你可能拥有100个输入和对应的10个输出。那么,你如何确保你的模型(可能是一条直线,或者在神经网络中是一个超平面)做出的预测,能够最小化预测值与实际值之间的距离呢?这就是通过损失函数来定义的。
损失函数衡量的是模型预测值与实际真实值之间的差距。
损失函数的量化术语
以下是用于量化损失的几种常见术语。
均方误差 是所有损失平方的平均值。在线性回归中,如果这条直线是你的模型,而这些是你的数据点,那么均方误差的计算公式如下:
MSE = (1/n) * Σ (y_predicted_i - y_actual_i)^2
其中,n 是数据点的数量。如果你对这个结果取平方根,就得到了均方根误差。这种方法主要用于回归问题。
对于分类问题,通常使用交叉熵损失。其公式可以定义为:
Cross-Entropy Loss = - Σ (y_actual_i * log(y_predicted_i))
梯度下降简介
上一节我们介绍了损失函数,它量化了模型的误差。本节中,我们来看看如何通过梯度下降来最小化这个误差。
梯度下降是一种优化算法,用于寻找使损失函数值最小的模型参数。其核心思想是:通过计算损失函数相对于每个参数的梯度(即导数),然后沿着梯度的反方向(即下降最快的方向)更新参数。
参数更新的基本公式如下:
θ_new = θ_old - α * ∇J(θ)
其中:
θ代表模型参数。α是学习率,控制每次更新的步长。∇J(θ)是损失函数J在参数θ处的梯度。
反向传播在神经网络中的应用
理解了梯度下降的基本原理后,我们将其应用到更复杂的神经网络中。在神经网络中,参数数量庞大,直接计算所有梯度非常困难。这时就需要反向传播算法。
反向传播是一种高效计算神经网络中损失函数对所有参数梯度的方法。其过程分为两个步骤:
- 前向传播:输入数据通过网络层层计算,得到最终预测值,并计算损失。
- 反向传播:从输出层开始,将损失沿着网络反向传播,利用链式法则计算损失相对于每一层参数的梯度。
通过反向传播计算出梯度后,我们就可以使用梯度下降法来更新网络中的所有权重和偏置。
实践中的注意事项
在应用梯度下降优化模型时,可能会遇到一些挑战。以下是几个关键的注意事项。
局部极小值与鞍点
梯度下降的目标是找到损失函数的全局最小值。但在复杂模型中,损失函数可能存在多个“低谷”,即局部极小值。优化过程可能会陷入某个局部极小值而无法到达全局最优。此外,在高维空间中,还可能遇到梯度为零但并非极值点的“鞍点”,这也会使优化停滞。
学习率的选择
学习率 α 是一个超参数。如果学习率设置过大,参数更新步伐太大,可能会在最小值附近震荡甚至发散;如果学习率设置过小,收敛速度会非常慢,训练时间过长。通常需要尝试不同的学习率或使用自适应学习率算法。
梯度消失与爆炸
在深度神经网络中,反向传播时梯度可能会随着层数的增加而指数级地减小(消失)或增大(爆炸)。这会导致深层网络的参数难以更新或更新不稳定。使用特定的激活函数(如ReLU)和权重初始化技巧有助于缓解这些问题。

总结
本节课中,我们一起学习了机器学习中的核心优化技术。我们首先定义了损失函数,它用于衡量模型预测的误差。接着,我们深入探讨了梯度下降算法,它是通过沿着损失函数梯度的反方向更新参数来最小化误差。然后,我们了解了反向传播算法,它是在神经网络中高效计算所有参数梯度的关键。最后,我们讨论了实践中可能遇到的问题,如局部极小值、学习率设置以及梯度消失/爆炸现象。掌握这些概念是理解和构建有效机器学习模型的重要基础。
023:机器学习优化入门


欢迎来到机器学习优化新模块的开始。本讲座是“机器学习基础”课程的一部分。今天我们将探讨优化,特别是梯度下降。讲座分为两部分。第一部分,我们将探讨理论:优化究竟意味着什么,以及我们优化的是什么。第二部分,我们将从零开始实现梯度下降。欢迎来到本次讲座。
讲座的结构如前所述。我们将介绍优化本身的概念。当我们说为某个参数进行优化时,其数学含义是什么?损失函数或成本函数究竟是什么?什么是梯度下降?如果你想成为一名严肃的机器学习工程师,这可能是你必须熟悉的唯一最重要的概念。传统梯度下降方法存在哪些问题?我们将在本次讲座中讨论所有这些内容。
让我们看一个非常简单的机器学习模型,我们之前讨论过的线性回归。😊
在线性回归中,这些点是数据点。我们试图做的是拟合一个最能代表这些数据的模型。这样,如果要求你对不属于训练数据的输入数据进行预测,例如对于这里的某个x值,要求你给出对应的y值是什么?通过线性回归得到的这条穿过数据点的直线模型就可以进行预测。你会说,如果你想预测当输入x等于某个值时,输出变量y的值是多少,那么你需要做的就是沿着这条直线,如果直线像这样延伸,让我减小线条粗细,那么你需要做的就是找到对应的y值在哪里。因此,你可以说对于这个特定的x值,对应的y值是这个。为什么?因为模型是这样说的。模型是什么?就是这条直线。
这里有两个参数,假设你只有一维数据,那么只有两个参数:斜率和截距。因此,在这个特定情境下,优化的运作方式是:即使你从一个随机的斜率值和随机的截距值开始,因为你不知道数据是否通过原点,也不知道穿过数据的直线的平均值是否通过原点,或者你不知道...


024:从零实现随机梯度下降 | 优化入门


欢迎回到《机器学习基础》课程。本讲是一个新模块的开始,该模块包含四节讲座,主题是如何在机器学习中大幅改进梯度下降算法。
具体来说,我们将学习随机梯度下降、动量法、均方根传播以及Adam优化器。Adam可能是整个机器学习领域最著名的优化算法。
我最初考虑将这四部分内容录制成一节讲座,但后来认为那样会使讲座过长。因此,我决定将其拆分,并深入探讨每一个主题,这能让大家很好地理解人们为何会想到这些改进梯度下降算法的方法。在本讲中,我们将重点学习随机梯度下降。
我将本讲分为两部分。第一部分讨论随机梯度下降的理论。第二部分将实现该算法,并探讨为何随机梯度下降优于普通的“香草”梯度下降。普通的梯度下降也称为批量梯度下降,因为它是使用整个数据批次来决定参数应改变多少。
你可能会想,我还不了解梯度下降,是否应该学习本讲?别担心,在进入随机梯度下降之前,我们会在讲座第一部分对梯度下降本身进行适当的回顾。现在,让我们开始吧。
梯度下降回顾 🧠
梯度下降是一种用于最小化损失函数或成本函数的算法。
损失函数或成本函数是衡量机器学习模型预测值与真实数据之间差距的指标。在上一讲中我们讨论过,对于线性回归,损失函数可以用均方误差来描述。
假设我们有一些数据点,以及一条描述这些点线性拟合的直线,那么损失函数可以表示为:
均方误差公式:
MSE = (1/n) * Σ (y_i_pred - y_i)^2
其中,n 是数据点的数量,y_i_pred 是模型对第 i 个点的预测值,y_i 是第 i 个点的实际值。之所以称为“均方误差”,是因为它计算了误差的平方,并求其平均值(求和后除以 n)。
梯度下降的目标是找到使这个损失函数值最小的模型参数(例如,线性回归中的斜率和截距)。它通过迭代地沿损失函数梯度的反方向更新参数来实现。
梯度下降参数更新公式:
θ_new = θ_old - α * ∇J(θ)
其中:
θ代表模型参数。α是学习率,控制每次更新的步长。∇J(θ)是损失函数J关于参数θ的梯度(导数)。
在标准的批量梯度下降中,计算梯度 ∇J(θ) 需要使用全部训练数据。对于大型数据集,这会导致每次迭代的计算成本非常高,速度很慢。
随机梯度下降理论 ⚡
上一节我们回顾了标准的批量梯度下降。本节中,我们来看看如何改进它,这就是随机梯度下降的核心思想。
SGD 的关键区别在于:它不使用全部数据来计算梯度。相反,在每次参数更新时,它只随机选择一个训练样本(或一小批样本)来计算梯度。
以下是 SGD 的基本步骤:
- 随机打乱数据:首先,将训练数据集随机打乱顺序。
- 迭代更新:对于打乱后的数据集中的每一个样本(或每一小批样本):
- 使用当前模型参数和当前这个(或这一小批)样本计算损失函数的梯度。
- 使用这个“估计”的梯度来更新模型参数。
随机梯度下降参数更新公式(单个样本):
θ_new = θ_old - α * ∇J_i(θ)
其中,∇J_i(θ) 是仅基于第 i 个训练样本计算出的损失梯度。
与批量梯度下降相比,SGD 有以下几个主要特点:
- 计算高效:每次更新只处理一个或少量样本,计算速度快,内存需求低。
- 引入噪声:由于梯度基于单个样本估计,它不再是整个数据集上的真实平均梯度,而是包含噪声的估计。这可能导致更新路径不稳定( zig-zag 路径)。
- 可能逃离局部极小值:这种噪声有时有助于算法跳出局部最小值,从而可能找到更好的解。
- 需要更多迭代:虽然每次迭代更快,但由于更新方向有噪声,通常需要更多次的迭代(或“周期”,即完整遍历数据集的次数)才能收敛。
为了在纯随机(噪声大)和批量计算(成本高)之间取得平衡,实践中常用小批量随机梯度下降。它每次使用一小批随机样本(例如 32、64、128 个)来计算梯度,这是目前深度学习中最常用的优化变体。
小批量 SGD 参数更新公式:
θ_new = θ_old - α * (1/m) * Σ ∇J_k(θ)
其中,m 是小批量的大小,求和是对该小批量中的所有样本 k 进行。
为何 SGD 更优? 🤔
我们已经了解了 SGD 的理论。你可能会问,使用带噪声的梯度估计真的更好吗?本节我们通过一个类比来理解其优势。
想象你要从山顶(高损失)走到山谷最低点(最小损失)。批量梯度下降就像在每次迈步前,先仔细勘察整个地形,找到最陡的下山方向,然后迈出一步。这很准确,但勘察整个地形(计算全数据梯度)非常耗时。
而 SGD 更像是在每一步,你只快速看一眼脚下附近的一小块地方(一个样本),就决定朝那个方向走一步。虽然每一步的方向可能不是全局最优的,甚至偶尔会走错,但你迈步的速度极快。总体来看,你可能会以更短的总时间到达谷底附近。
对于非常大的数据集(现代机器学习的常态),SGD 的这种“快速但嘈杂”的特性使其在实践中的总收敛时间往往远少于批量梯度下降。此外,噪声带来的随机性有助于模型逃离尖锐的局部极小值,从而可能泛化得更好。
从零实现 SGD 🛠️
理论部分已经清晰,现在让我们动手实现一个简单的随机梯度下降,并将其与批量梯度下降进行比较,以直观感受其差异。
我们将为一个简单的线性回归问题实现优化。假设我们的模型是 y_pred = w * x + b,损失函数为均方误差。
以下是关键代码步骤的概述:

- 生成模拟数据:创建一组带有噪声的线性数据。
- 定义模型和损失:编写预测函数和损失函数(MSE)。
- 实现批量梯度下降:
# 伪代码示意 for epoch in range(num_epochs): # 计算整个数据集的梯度 grad_w = (2/n) * sum((y_pred - y) * x) grad_b = (2/n) * sum(y_pred - y) # 更新参数 w = w - learning_rate * grad_w b = b - learning_rate * grad_b - 实现随机梯度下降:
# 伪代码示意 for epoch in range(num_epochs): # 打乱数据顺序 shuffle(data) for x_i, y_i in data: # 计算单个样本的预测和损失 y_pred_i = w * x_i + b # 计算单个样本的梯度 grad_w_i = 2 * (y_pred_i - y_i) * x_i grad_b_i = 2 * (y_pred_i - y_i) # 用该样本的梯度立即更新参数 w = w - learning_rate * grad_w_i b = b - learning_rate * grad_b_i - 比较结果:运行两种算法,观察:
- 收敛速度:SGD 的损失下降曲线是否在更少的“计算量”或“时间”内快速下降?
- 更新路径:在参数空间中,SGD 的更新路径是否更加曲折(zig-zag),而批量梯度下降的路径则更直接地指向最小值?
- 最终效果:两者最终找到的参数解是否接近?
通过这个简单的实现和对比,你将亲眼看到 SGD 如何通过频繁但基于部分信息的更新,在优化过程中带来效率优势。
总结 📝
本节课中,我们一起学习了梯度下降的一个重要变体——随机梯度下降。
我们首先回顾了标准的批量梯度下降,它使用全部数据计算梯度,准确但计算成本高。然后,我们深入探讨了 SGD 的原理:它通过每次迭代仅随机使用一个或一小批样本来估计梯度,从而极大地提高了每次更新的速度。我们分析了其优缺点,包括计算效率高、引入噪声、可能帮助逃离局部极小值等。最后,我们讨论了如何从零开始实现 SGD 并与批量梯度下降进行比较,以直观理解其工作方式。
SGD 及其变体(如小批量 SGD)是训练大规模机器学习模型,尤其是深度神经网络的基石。理解它是迈入实用机器学习优化领域的关键一步。在接下来的讲座中,我们将以此为基础,学习更先进的优化技术,如动量法和 Adam,它们能进一步改善 SGD 的收敛稳定性与速度。
025:P25 从零实现基于动量的梯度下降




欢迎来到机器学习优化模块的新一讲。本模块是“机器学习基础”课程的一部分。今天我们将学习如何利用动量来改进梯度下降。
在本模块中,我们一直在探讨实现梯度下降的各种方法。上一讲我们学习了随机梯度下降,今天我们将介绍动量方法。本模块还有另外两种方法需要介绍:第三种是RMSProp(均方根传播),最后一种是Adam优化器,这是机器学习中最常用的优化器。如果你还不了解梯度下降,请不要担心,我会在讲座的第一部分进行回顾。
本次讲座分为两部分。第一部分,我将介绍动量梯度下降背后的理论。第二部分,我们将通过代码实现它,以便你能看到相比普通梯度下降,动量方法为何更优。
现在,让我们开始学习。
梯度下降回顾
梯度下降是机器学习中用于最小化损失函数的方法。损失函数是一个指标,用于衡量你的预测值与实际数据点之间的差距。
如果损失函数用 J 表示,机器学习模型参数用 θ 表示。以线性回归为例,即用一条直线拟合一系列数据点,参数就是斜率和截距。损失函数是均方误差,即计算点与直线偏差的平方,然后取平均值。
梯度下降的步骤如下:
- 首先,从参数的某个随机初始值开始。在线性回归的上下文中,就是随机的斜率和截距值。
- 然后,我们不断迭代修改这个 θ,最终找到一个能使损失函数最小化的 θ 值。这就是梯度下降的全部目标。
具体迭代过程如下:
第一步是计算梯度。这个项就是梯度:∇J(θ),即损失函数 J 关于参数 θ 的梯度。
第二步是更新参数。将梯度乘以一个学习率 α,然后用旧的参数值减去这个乘积,得到新的参数值。
参数更新公式为:
θ_new = θ_old - α * ∇J(θ)
然后,重复计算梯度和更新参数这两个步骤,直到满足停止条件。
动量梯度下降理论
上一节我们回顾了标准梯度下降。本节中,我们来看看如何通过引入“动量”来改进它。
标准梯度下降的一个问题是,它在优化过程中可能会在狭窄的沟谷或局部最小值附近振荡,导致收敛缓慢。动量方法通过引入一个“速度”项来解决这个问题,该速度项累积了过去梯度的指数加权平均。
其核心思想是:参数更新不仅依赖于当前的梯度,还依赖于之前更新步骤的“动量”。这类似于一个球滚下山坡时,会积累动量,从而更平稳地穿过平坦区域并加速通过陡峭区域。
以下是动量梯度下降的关键步骤:
- 初始化:除了模型参数 θ,我们还需要初始化一个速度向量 v,其维度与 θ 相同,通常初始化为零。
- 计算当前梯度:在每次迭代中,计算当前参数 θ 下的损失函数梯度 ∇J(θ)。
- 更新速度:使用以下公式更新速度 v。其中 β 是一个超参数,称为动量系数,通常取值在0.9左右。它决定了保留多少历史速度信息。
v = β * v + (1 - β) * ∇J(θ) - 更新参数:使用更新后的速度来调整参数,而不是直接使用原始梯度。
θ = θ - α * v
这里的 α 是学习率。
通过这种方式,如果连续几次梯度的方向一致,速度项会增大,从而加速参数更新。如果梯度方向改变,速度项会因指数衰减而减小,有助于减少振荡。
从零实现动量梯度下降
理解了动量方法的理论后,本节我们将通过Python代码从零开始实现它,并与标准梯度下降进行对比。
我们将使用一个简单的二次函数作为损失函数:J(θ) = θ²。它的最小值在 θ=0 处。我们将观察两种方法寻找最小值的过程。
以下是实现步骤和代码:
首先,我们定义损失函数及其梯度。
def loss_function(theta):
return theta ** 2
def gradient(theta):
return 2 * theta
接下来,我们实现标准梯度下降。
def gradient_descent(theta_init, learning_rate, iterations):
theta = theta_init
history = [theta] # 记录参数变化
for i in range(iterations):
grad = gradient(theta)
theta = theta - learning_rate * grad
history.append(theta)
return history
现在,我们实现动量梯度下降。关键部分是按照前面介绍的公式更新速度和参数。
def momentum_gradient_descent(theta_init, learning_rate, beta, iterations):
theta = theta_init
v = 0 # 初始化速度
history = [theta]
for i in range(iterations):
grad = gradient(theta)
v = beta * v + (1 - beta) * grad # 更新速度
theta = theta - learning_rate * v # 用速度更新参数
history.append(theta)
return history
最后,我们设置初始参数并运行两种方法,比较它们的收敛路径。
# 参数设置
theta_init = 10.0
learning_rate = 0.1
beta = 0.9 # 动量系数
iterations = 50
# 运行优化
gd_history = gradient_descent(theta_init, learning_rate, iterations)
momentum_history = momentum_gradient_descent(theta_init, learning_rate, beta, iterations)
# 打印最终结果
print("标准梯度下降最终 theta:", gd_history[-1])
print("动量梯度下降最终 theta:", momentum_history[-1])
运行这段代码,你可以观察到动量梯度下降的路径更加直接、振荡更少,通常能更快地接近最小值点 0。通过绘制 gd_history 和 momentum_history 的曲线,可以更直观地看到这种差异。
总结
本节课中,我们一起学习了动量梯度下降。
我们首先回顾了标准梯度下降的原理及其可能存在的振荡问题。接着,引入了动量概念,它通过累积过去梯度的指数加权平均(即速度 v)来平滑更新方向,公式为 v = β * v + (1 - β) * ∇J(θ) 和 θ = θ - α * v。最后,我们通过代码实现了两种方法,并直观展示了动量方法如何带来更稳定、更快速的收敛。
动量是优化神经网络和复杂模型时的一个基础且重要的技术,它为后续学习更高级的优化器(如RMSProp和Adam)奠定了基础。
026:从零实现RMSprop梯度下降法




在本节课中,我们将学习一种名为RMSprop(均方根传播)的优化方法,它能使梯度下降在机器学习中表现得更好。这是关于优化方法的四讲模块中的第三讲。在前两讲中,我们介绍了随机梯度下降和基于动量的梯度下降。今天,我们将探讨RMSprop,这是另一种改进普通(批量)梯度下降性能的技术。
本模块是“机器学习基础”课程的一部分。即使你还不完全了解梯度下降,也不必担心,我们会在课程开始时进行简要回顾。
梯度下降法回顾
首先,让我们简要回顾一下梯度下降法。梯度下降是一种最小化损失的方法。损失(Loss)衡量的是模型预测值与实际数据之间的差距,通常由损失函数或成本函数 J(θ) 表示。这里的 θ 代表模型参数。例如,在线性回归中,θ 就是斜率和截距。
我们的目标是找到能使损失 J(θ) 最小化的参数 θ。你可以将其想象成在一个由 J(θ) 函数构成的地形图上行走,目标是找到全局最低点(即全局最小值)。
梯度下降通过以下公式执行一步更新:
θ_new = θ_old - η * ∇J(θ_old)
其中:
- θ_new 是更新后的参数。
- θ_old 是更新前的参数。
- η 是学习率,它决定了每次更新步长的大小。
- ∇J(θ_old) 是损失函数在 θ_old 处的梯度。
这个方法之所以叫“梯度下降”,是因为我们沿着梯度(上升最快的方向)的反方向移动,从而减少损失值。
标准的梯度下降流程包含以下几个简单步骤:
- 初始化参数:为参数 θ 赋予一个随机初始值(例如,在线性回归中,斜率和截距都设为0)。
- 计算梯度:计算当前参数 θ 下的损失函数梯度 ∇J(θ)。
- 更新参数:使用公式 θ = θ - η * ∇J(θ) 更新参数。
- 重复迭代:重复步骤2和步骤3,直到满足停止条件(如达到最大迭代次数或损失变化很小)。
从梯度下降到RMSprop
上一节我们回顾了标准梯度下降的基本步骤。虽然它有效,但在处理复杂地形(如狭窄的山谷)时,学习率的固定性可能导致收敛缓慢或震荡。本节我们将介绍RMSprop算法,它通过自适应地调整每个参数的学习率来解决这个问题。
RMSprop的核心思想是:为每个参数 θ_i 维护一个累积的、衰减的梯度平方均值(称为 s)。梯度大的参数,其 s 值也大,从而在更新时获得较小的有效学习率;梯度小的参数则获得较大的有效学习率。这有助于平滑优化路径。
以下是RMSprop算法的具体步骤:
- 初始化参数:初始化模型参数 θ,并为每个参数初始化累积变量 s = 0。设定学习率 η、衰减率 ρ(通常设为0.9)和一个极小常数 ε(如1e-8,用于防止除以零)。
- 计算当前梯度:在每次迭代中,计算损失函数关于当前参数 θ 的梯度 g = ∇J(θ)。
- 更新累积平方梯度:使用指数移动平均更新累积变量 s。公式为:
s = ρ * s + (1 - ρ) * g²
这里 g² 表示逐元素平方。 - 计算参数更新:计算参数的更新量。RMSprop的更新公式为:
Δθ = - (η / √(s + ε)) * g - 应用更新:使用计算出的更新量来调整参数:
θ = θ + Δθ - 重复迭代:重复步骤2到步骤5,直到模型收敛。
通过这种方式,RMSprop能够自动为每个参数调整步长,在处理非平稳目标或稀疏梯度的问题时(如训练神经网络)通常非常有效。
总结
本节课我们一起学习了RMSprop梯度下降优化算法。我们首先回顾了标准梯度下降的原理与步骤。接着,我们深入探讨了RMSprop,它通过维护一个梯度平方的指数衰减平均值,为每个参数自适应地调整学习率。这使得算法在存在陡峭或平坦区域的复杂损失地形中也能更平稳、更快速地收敛。理解RMSprop是掌握现代深度学习优化器(如Adam)的重要基础。
027:从零实现Adam优化器|让梯度下降更高效




欢迎回到机器学习优化系列讲座。我们正在探讨如何让梯度下降变得更好。本系列讲座是“机器学习基础”课程的一部分。今天,我们将专门探讨Adam优化器。
在之前的三节课中,我们学习了随机梯度下降、基于动量的梯度下降和RMSprop(均方根传播)。这些都是让梯度下降更高效或更好的方法。今天要讨论的Adam优化器,可能是最著名的优化器,即使你在构建生产级机器学习模型时也会用到它。
如果你不熟悉梯度下降,不用担心,我会在本节课开始时为你回顾梯度下降到底是什么。如果你已经熟悉梯度下降,可以直接跳到我们开始讨论Adam优化器的部分。现在,让我们开始这节课。
梯度下降简要回顾
在梯度下降中,我们试图最小化损失函数。损失函数是衡量模型预测值与实际值之间差距的指标。它用 J 表示。θ 是模型参数。例如,如果你使用线性回归,θ 就是斜率和截距。
你将借助梯度来修改斜率和截距的初始值(即 θ 的初始随机假设值)。在新的时间步,θ 的值等于旧时间步的 θ 减去学习率乘以损失函数关于 θ 的梯度。公式如下:
θ_new = θ_old - η * ∇J(θ)
这里之所以称为“下降”,是因为有一个减号,意味着你不是沿着梯度方向移动,而是沿着梯度的相反方向移动。
以下是梯度下降的几个步骤:
首先,从 θ 的随机值开始。其次,计算损失函数关于该特定 θ 值的梯度。然后,根据计算出的梯度更新 θ 的值。最后,重复步骤二和三,直到达到收敛或完成预定的迭代次数。这就是梯度下降的本质。
这种梯度下降方法的问题在于,对于大型数据集,计算效率低下。例如,在线性回归中,如果这些是数据点,模型是这条线,均方误差损失函数定义为:
J(θ) = (1/n) * Σ (y_i_predicted - y_i_actual)²
为了计算这个损失函数关于 θ 的梯度,你需要对所有数据点求和。对于有数百万个数据点的大型数据集,每次迭代都计算这个总和计算量非常大。这就是随机梯度下降的用武之地。
随机梯度下降
在随机梯度下降中,你不是在整个数据集上计算梯度,而是随机选取一个数据点(或一小批数据点),并仅基于该数据点计算梯度。然后更新参数。这显著减少了每次迭代的计算量。
然而,随机梯度下降也有其自身问题。由于梯度是基于单个或少量数据点估计的,它可能非常嘈杂,导致优化路径不稳定,收敛速度可能较慢。
动量梯度下降
为了应对随机梯度下降的噪声问题,我们引入了动量。其思想是不仅要考虑当前梯度,还要考虑过去梯度的移动平均值。这有助于平滑优化路径,特别是在存在噪声的情况下。它就像给优化过程增加了惯性,帮助它更平稳地穿过狭窄的山谷并避免振荡。
动量更新规则如下:
v_t = β * v_{t-1} + (1 - β) * ∇J(θ_t)
θ_{t+1} = θ_t - η * v_t
其中 v_t 是当前动量,β 是动量系数(通常接近0.9),η 是学习率。
RMSprop
RMSprop(均方根传播)是另一种优化算法,旨在解决学习率适应性问题。它通过除以梯度平方的指数移动平均值的平方根来调整每个参数的学习率。这使得每个参数都有其自适应的学习率,对于稀疏梯度或不同尺度的问题特别有效。
RMSprop的更新规则如下:
E[g²]t = β * E[g²] + (1 - β) * (∇J(θ_t))²
θ_{t+1} = θ_t - η / (√(E[g²]_t) + ε) * ∇J(θ_t)
其中 E[g²]_t 是梯度平方的指数移动平均值,ε 是一个小常数,用于防止除以零。
Adam优化器
现在,我们进入本节课的核心:Adam优化器。Adam结合了动量(Momentum)和RMSprop两种方法的优点。它同时计算梯度的一阶矩(均值)和二阶矩(未中心化的方差)的指数移动平均,并使用它们来调整每个参数的学习率。
Adam的名称来源于“自适应矩估计”。以下是Adam优化器的具体步骤:
首先,初始化参数向量 θ、一阶矩向量 m(初始为0)、二阶矩向量 v(初始为0),并设置时间步 t = 0。然后,在每次迭代中执行以下操作:
- 计算当前小批量的损失函数梯度 g_t。
- 更新有偏一阶矩估计:m_t = β₁ * m_{t-1} + (1 - β₁) * g_t
- 更新有偏二阶矩估计:v_t = β₂ * v_{t-1} + (1 - β₂) * g_t²
- 计算一阶矩的偏差校正:m̂_t = m_t / (1 - β₁^t)
- 计算二阶矩的偏差校正:v̂_t = v_t / (1 - β₂^t)
- 更新参数:θ_{t+1} = θ_t - η * m̂_t / (√(v̂_t) + ε)
其中,β₁ 和 β₂ 是指数衰减率(通常分别设为0.9和0.999),η 是学习率,ε 是一个很小的常数(例如10^-8),用于数值稳定性。
Adam的优点在于它通常能快速收敛,并且对超参数的选择相对鲁棒,因此成为许多深度学习任务中的默认优化器。
总结
在本节课中,我们一起学习了Adam优化器。我们从梯度下降的基本概念开始,回顾了其计算效率低下的问题。接着,我们介绍了随机梯度下降作为解决方案,但它引入了噪声。为了平滑优化路径,我们学习了动量梯度下降。然后,为了自适应调整每个参数的学习率,我们探讨了RMSprop。最后,我们将动量和RMSprop的思想结合起来,详细讲解了Adam优化器,它通过自适应地调整每个参数的学习率,并结合了梯度历史信息,从而实现了高效且稳定的优化。Adam因其出色的性能,已成为实践中广泛使用的优化算法。
028:正则化详解


欢迎回到机器学习基础课程。本节课我们将学习正则化。首先,我们将学习正则化背后的理论,然后从头开始实现它。
你可能在谷歌搜索“正则化可视化”或其他上下文中见过下面这张图。也许你在领英上也看到过。我必须说,这张展示Lasso和Ridge回归区别的图非常令人困惑。如果你理解其含义,这是一张很棒的图,否则,它可能会让你感到不知所云。但我看到人们反复使用这张图,所以今天我们将花一些时间来解读图中到底在展示什么,以及它如何说明Lasso回归可以强制某些参数恰好为零,而Ridge回归则不会使其恰好为零,而是近似为零。我们将探讨这个想法。一旦你非常理解这张图想表达的意思,我认为你就对正则化有了相当好的掌握。
概述
在本节课中,我们将要学习什么是正则化,它如何防止过拟合,以及L1(Lasso)和L2(Ridge)正则化的核心区别。我们将通过理论和可视化来理解这些概念。
什么是正则化?
首先,什么是正则化?它是机器学习中用于防止过拟合的一种方法。
什么是过拟合?过拟合是指模型试图学习数据中的复杂模式,这些模式可能源于异常值或噪声。当模型试图学习训练数据中的模式,特别是那些可能是异常值或噪声的模式时,模型并没有学习到可泛化的模式。当你提供来自测试数据集的未见数据时,它无法获得很好的结果。
正则化的作用是向模型使用的原始损失函数添加一个惩罚项。这个惩罚项阻止模型学习这些过度复杂的模式。你将会看到这个整体思想被可视化出来。
所以这里的基本前提是,如果你阻止模型学习过于复杂的模式,它就只能学习数据中的总体趋势,这可能会产生一个更好的模型,该模型可以在未见数据集上做出更好的预测。
什么是可泛化模式?
那么,我们所说的可泛化模式是什么意思?这里有一个例子。假设 y 是你的预测,X 是你的数据。
如果你的数据看起来像这样,并且假设这是训练数据,那么很明显,这些小波动或不规则性可能只是噪声。一个过于复杂的模型可能会尝试精确地拟合每一个点,包括这些噪声点。而一个正则化的、更简单的模型则会学习更平滑的、代表数据主要趋势的曲线,从而在未见数据上表现更好。

上一节我们介绍了正则化的基本目的,即防止过拟合。本节中我们来看看两种最常见的正则化方法:Lasso回归和Ridge回归。它们的核心区别在于添加到损失函数中的惩罚项形式不同。
L1与L2正则化
以下是两种主要正则化方法的简要介绍:
-
L1正则化 (Lasso):
- 在损失函数中添加模型权重的绝对值之和作为惩罚项。
- 其公式可以表示为:
损失 = 原始损失 + λ * Σ|w_i|,其中λ是控制惩罚力度的超参数,w_i是模型权重。 - 它倾向于产生稀疏模型,即强制一些不重要的特征权重恰好变为零,从而实现特征选择。
-
L2正则化 (Ridge):
- 在损失函数中添加模型权重的平方和作为惩罚项。
- 其公式可以表示为:
损失 = 原始损失 + λ * Σ(w_i)^2。 - 它倾向于将权重缩小并趋近于零,但通常不会恰好为零。这有助于处理特征共线性问题。
理解可视化图表
现在,让我们回到课程开始时提到的那张令人困惑的图。这张图通常用于直观对比Lasso和Ridge回归。
图中通常包含一个等高线图,代表原始的损失函数(如均方误差),以及一个代表正则化约束的区域(对于L1是菱形,对于L2是圆形)。模型优化的目标是找到同时满足损失最小化和正则化约束的点。
- Lasso (L1) 的菱形角点:由于菱形有尖角,最优解很可能落在某个角上。在角点上,某个坐标轴的值(即某个特征的权重)恰好为零,这就解释了Lasso回归能产生稀疏解、进行特征选择的原因。
- Ridge (L2) 的圆形边界:圆形没有尖角,最优解与圆相切时,权重参数会被均匀地压缩,但很少会恰好为零,因此所有特征通常都会被保留,只是权重值变小。
理解了这张图,你就能直观地把握L1和L2正则化在优化过程中的行为差异。
总结

本节课中我们一起学习了正则化的核心概念。我们了解到正则化是通过向损失函数添加惩罚项来防止模型过拟合的技术。我们重点比较了L1正则化(Lasso)和L2正则化(Ridge):L1通过绝对值惩罚可能导致部分权重为零,适用于特征选择;L2通过平方和惩罚使权重整体缩小但不为零,有助于稳定模型。最后,我们通过解读常见的可视化图表,加深了对两者优化行为差异的理解。掌握这些知识是构建更稳健、泛化能力更强机器学习模型的基础。
029:Python入门基础


欢迎回到机器学习基础课程。这是新模块的开始,我们将介绍机器学习工程师所需的编程基础。
本课程是Python的全新起点。如果你已经熟悉Python基础知识,可以完全跳过本课。如果你不是初学者,本课并非必需。如果你是零基础,没有太多使用或运行程序、编写Python代码的背景,那么本课适合你。让我们开始学习,我们将从非常基础的数据类型开始,然后在本课结束时编写一些更复杂的函数。
Python简介 🐍
首先,Python是一种编程语言。它的书写方式非常易于解释,语法非常容易学习。它是目前机器学习领域最流行的编程语言,也广泛应用于Web开发。相对于许多其他编程语言,学习Python非常容易。对我个人而言,Python比C或C++更容易学习。如果你想成为一名专业的机器学习工程师,当然应该掌握Python。另一个优点是,Python拥有大量非常流行的库,社区支持非常好。此外,由于许多互联网数据库基于Python,像ChatGPT或Anthropic的Claude这样的大型语言模型,在你遇到Python问题时,都非常擅长提供解决方案。
下图显示了从2019年2月到2020年2月,教程搜索中哪些语言最突出。Python位居榜首,其次是Java等。因为在Web开发中Java也被广泛使用,所以你会看到这种趋势。但很明显,Python是世界上最受欢迎的编程语言。

Python库简介 📚
以下是Python中一些在机器学习、数据科学、深度学习等领域非常流行的库。其中一些用于数据可视化,如Seaborn;一些用于数据分析和实现机器学习模型;还有一些用于存储表格数据等。如果你不知道这些库是什么,不用担心,只需将它们视为预定义的代码,这样你就不必重复编写执行某些功能的代码。这些是Python中非常流行的库,当你进入机器学习领域时,将广泛使用它们。
以下是这些库的简要列表:
- NumPy:用于数值计算。
- Pandas:用于数据分析和操作。
- Matplotlib:用于数据可视化。
- Seaborn:基于Matplotlib的统计图形库。
- Scikit-learn:用于机器学习的库。
- TensorFlow / PyTorch:用于深度学习的框架。
总结

在本节课中,我们一起学习了Python编程语言的基本介绍及其在机器学习中的重要性。我们了解到Python因其易学性和强大的社区支持而成为最受欢迎的编程语言之一。我们还简要介绍了一些在机器学习中常用的Python库,这些库将在后续的学习中发挥重要作用。下一节,我们将开始学习Python的基础数据类型。
030:从零实现Python矩阵乘法


在本节课中,我们将学习如何在Python中不借助任何库,从零开始实现矩阵乘法。
对于初学者而言,这是一个极佳的练习。它将让你接触到Python中的多个重要概念:处理列表(这是Python中的基础数据结构)、理解矩阵(本质上是列表的列表)、运用循环、条件语句、掌握Python基本语法,以及将人类逻辑转化为代码。通过这一个练习,你将获得全面的实践。
我们将不使用NumPy或其他任何库,完全从零开始实现矩阵乘法。
矩阵乘法规则概述
矩阵乘法遵循特定规则。假设有两个矩阵M1和M2。只有当第一个矩阵M1的列数等于第二个矩阵M2的行数时,这两个矩阵才能相乘。否则,会出现维度不匹配的错误。
我们可以用维度P、Q、R来一般化地表示。设第一个矩阵的维度为 P × Q,第二个矩阵的维度为 Q × R。其中,Q 必须相同,而 P 和 R 可以不同。
相乘的结果矩阵维度将是 P × R。这意味着结果矩阵有P行和R列。
计算过程详解
那么,如何计算M1乘以M2呢?结果矩阵中的每个元素,都是由M1的一行与M2的一列对应元素相乘再求和得到的。
具体来说,结果矩阵中位于第 i 行、第 j 列的元素(在Python中索引从0开始,即 [i][j]),其计算方式如下:
取M1的第 i 行向量,与M2的第 j 列向量,将它们的对应元素相乘,然后将所有乘积相加。
用公式表示,结果矩阵 C 的元素 C[i][j] 为:
C[i][j] = Σ (M1[i][k] * M2[k][j]),其中求和 Σ 对 k 从0到 Q-1 进行。
代码实现步骤
以下是实现矩阵乘法的具体步骤。我们将逐步构建代码。
首先,需要检查两个矩阵是否可以相乘。这通过比较M1的列数(即 len(M1[0]))和M2的行数(即 len(M2))来完成。
def matrix_multiply(M1, M2):
# 1. 检查维度是否匹配
if len(M1[0]) != len(M2):
return "错误:矩阵维度不匹配,无法相乘。"
如果维度匹配,我们就可以继续。接下来,初始化结果矩阵。结果矩阵的行数等于M1的行数(len(M1)),列数等于M2的列数(len(M2[0]))。我们创建一个全零的二维列表作为初始结果。
# 2. 初始化结果矩阵(P行,R列,全部填充0)
result_rows = len(M1)
result_cols = len(M2[0])
result = [[0 for _ in range(result_cols)] for _ in range(result_rows)]
现在进入核心计算部分。我们需要三层嵌套循环:
- 外层循环
i遍历结果矩阵的每一行(即M1的每一行)。 - 中层循环
j遍历结果矩阵的每一列(即M2的每一列)。 - 内层循环
k遍历共同的维度Q,用于计算点积。
# 3. 三层循环计算每个元素
for i in range(result_rows): # 遍历M1的每一行
for j in range(result_cols): # 遍历M2的每一列
for k in range(len(M2)): # 遍历共同维度Q (即 len(M1[0]) 或 len(M2))
result[i][j] += M1[i][k] * M2[k][j]
最后,函数返回计算得到的结果矩阵。
return result
完整代码与测试
让我们将以上步骤整合,并提供一个测试用例。
def matrix_multiply(M1, M2):
"""
从零实现矩阵乘法。
参数:
M1 (list of lists): 第一个矩阵,维度 P x Q。
M2 (list of lists): 第二个矩阵,维度 Q x R。
返回:
list of lists: 结果矩阵,维度 P x R。如果维度不匹配则返回错误信息。
"""
# 1. 检查维度是否匹配
if len(M1[0]) != len(M2):
return "错误:矩阵维度不匹配,无法相乘。"
# 2. 初始化结果矩阵(P行,R列,全部填充0)
result_rows = len(M1)
result_cols = len(M2[0])
result = [[0 for _ in range(result_cols)] for _ in range(result_rows)]
# 3. 三层循环计算每个元素
for i in range(result_rows): # 遍历M1的每一行 (P)
for j in range(result_cols): # 遍历M2的每一列 (R)
for k in range(len(M2)): # 遍历共同维度Q (即 len(M1[0]) 或 len(M2))
result[i][j] += M1[i][k] * M2[k][j]
return result
# 测试用例
if __name__ == "__main__":
# 定义两个矩阵
A = [[1, 2, 3],
[4, 5, 6]] # 2x3 矩阵
B = [[7, 8],
[9, 10],
[11, 12]] # 3x2 矩阵
# 调用函数进行计算
C = matrix_multiply(A, B)
# 打印结果
print("矩阵 A:")
for row in A:
print(row)
print("\n矩阵 B:")
for row in B:
print(row)
print("\n乘积矩阵 C = A x B:")
if isinstance(C, str):
print(C) # 打印错误信息
else:
for row in C:
print(row)
运行上述代码,你将得到结果矩阵 C,其维度为2x2,计算过程正如我们之前描述的规则所示。
总结

本节课中,我们一起学习了如何在不使用任何外部库的情况下,从零开始在Python中实现矩阵乘法。我们首先理解了矩阵乘法的核心规则——第一个矩阵的列数必须等于第二个矩阵的行数。接着,我们剖析了计算过程:结果矩阵的每个元素都是M1一行与M2一列的点积。最后,我们通过编写包含维度检查、结果初始化和三层嵌套循环的代码,完整实现了这一算法。这个练习巩固了对Python列表、循环和基础算法逻辑的理解,是迈向更复杂机器学习概念的重要一步。
031:Python类入门教程 🐍
在本节课中,我们将要学习Python编程中一个核心但初学者常感困惑的概念:类(Class)。理解类是构建复杂程序,特别是机器学习模型的重要基础。我们将从最基础的概念讲起,解释什么是类、为什么使用类,并通过简单的比喻帮助你建立直观理解。
什么是类?📋
上一节我们介绍了编程基础的重要性,本节中我们来看看Python中的“类”。
类可以被理解为一个蓝图(Blueprint)。这个蓝图用于创建具有相似特征和行为的对象。
为了理解这一点,请看下面的例子。这里有两个对象:student1和student2。student1对象拥有三个属性:姓名、学号和院系。student2对象同样拥有这三个属性:姓名、学号和院系。






那么,类就是定义这个蓝图的数据结构。它规定了student1、student2或任何其他学生对象都应该具备哪些属性。在这个例子中,类定义了三个属性:
- 第一个属性是
name(姓名)。 - 第二个属性是
role_number(学号)。 - 第三个属性是
department(院系)。



另一个例子:图书类 📚
现在让我们思考另一个例子。假设你需要存储关于书籍的信息。一本书的“蓝图”,或者说元数据,可能包含以下信息:
- 作者
- 书名
- 价格(美元)
- 页数
这里,如果你定义一个名为Book的类,并以作者、书名和价格为属性,那么你就可以创建这个类的对象。

以下是这个类的可能结构:
class Book:
def __init__(self, author, book_name, price):
self.author = author
self.book_name = book_name
self.price = price
然后,你可以创建该类的对象:
book1是这个类的第一个对象,其属性值为:作者“Newport”,书名“Deep Work”,价格24。book2是这个类的第二个对象,其属性值为:作者“Author2”,书名“Book Name 2”,价格30。


类的核心优势:重用与组织 🔄
通过上面的例子,我们了解了类的基本形态。在类的定义中,你可以包含各种相似属性的变量。这些变量可以是整数、字符串,甚至是函数。

类的核心优势在于其可重用性。你不需要为每个学生或每本书单独、重复地定义结构。即使你需要定义300个学生,你也不需要创建300个独立且结构各异的对象。所有这些对象都可以是同一个称为“类”的结构的实例(Instances)。




给初学者的提示 💡

我知道,如果你是第一次学习类的概念,可能仍然会感到有些困惑。这是完全正常的。这种困惑通常会在我们实际动手编写代码时消失,所以不必过于担心。
目前,请先尝试理解这个核心思想:类是一个可以容纳数据(属性)和行为(方法)的模板或容器,它允许我们高效地创建和管理多个具有共同特征的对象。



总结 ✨
本节课中我们一起学习了Python中“类”的基本概念。我们了解到:
- 类是一个蓝图,用于创建对象。
- 类定义了对象的属性(如学生的姓名、学号)和未来可以定义的行为。
- 使用类的主要目的是代码重用和组织,避免重复定义相似的数据结构。
- 从同一个类创建出来的具体对象,称为该类的实例。

理解类是迈向面向对象编程和构建复杂机器学习模型的关键一步。在接下来的课程中,我们将通过实际编码来巩固这一概念。
032:Python类与对象在机器学习中的介绍


欢迎回到机器学习编程基础课程。在本节课中,我们将学习关于类的知识,特别是在机器学习的背景下。这是一堂完全面向初学者的课程,我们将尝试理解类以及如何在机器学习中使用它们。同时,我们还将讨论为什么在有函数的情况下还要使用类。让我们开始这节课。
首先,在课程结束时,你将掌握以下四个关键要点:
- 你将理解Python类的基础知识。
- 你将理解如何构建涉及类的代码结构,例如神经网络、线性回归模型或类似的机器学习代码。
- 你将在今天的课程中实现两个模型:第一个是完全从零开始的线性回归模型,第二个是用于执行二分类的简单神经网络。
- 所有这些都将通过使用Python类来定义模型完成。
什么是类?🐕
上一节我们介绍了课程目标,本节中我们来看看什么是类。
用简单的话来说,一个类就像一个用于创建对象的蓝图。你可能听说过面向对象编程,对象就是这个类的一个实例。一种理解方式是想象一个教室,里面有20名学生。每个学生都有一些属性:姓名、身高、学号、所修科目、成绩等等。蓝图基本上就是这个事实:要描述一个学生,你需要这些属性。而实例就是一个学生的具体例子,比如有一个具体的名字叫“Srid”,具体的身高,具体的学号,学生正在修的具体科目等。
以下是一个类的例子,我们定义了一个名为 Dog 的类。我们将解释为什么类内部有某些东西,比如 self 和 __init__ 等。这可能是学生最困惑的部分。
class Dog:
def __init__(self, name):
self.name = name
def bark(self):
print(f"{self.name} says woof!")
一个类也可以是空的。在上面的 Dog 类中,你不需要有任何内容,你可以只在类里面写 pass,那么你也会有一个什么都不做的类。但这里的情况并非如此。类内部有两样东西:一个叫做 name 的属性,以及一个叫做 bark 的方法或函数。bark 函数的作用是打印这只狗的名字,假设狗的名字是“Buddy”。
为什么在机器学习中使用类?🧠
我们已经了解了类的基本概念,现在让我们探讨为什么在机器学习中类如此重要。
在机器学习中,模型(如线性回归、神经网络)通常具有以下共同点:
- 参数:模型需要学习和存储的权重和偏置。
- 前向传播:一个根据输入和当前参数计算输出的函数。
- 训练循环:一个更新参数以最小化损失的过程。
使用类可以将所有这些组件(数据和方法)封装在一个整洁、有组织的单元中。这使得代码更易于管理、调试和复用。例如,你可以创建一个 LinearRegression 类,它内部包含权重、偏置、计算预测值的方法和更新参数的方法。
动手实践:实现线性回归模型📈
理论介绍完毕,现在让我们通过一个具体的例子来巩固理解。以下是使用类实现一个简单线性回归模型的步骤。
我们将创建一个 LinearRegression 类,它能够根据输入数据拟合一条直线。
import numpy as np
class LinearRegression:
def __init__(self):
self.weight = None
self.bias = None
def fit(self, X, y, learning_rate=0.01, epochs=1000):
# 初始化参数
n_samples, n_features = X.shape
self.weight = np.zeros(n_features)
self.bias = 0
# 梯度下降
for _ in range(epochs):
# 计算预测值: y_pred = X * w + b
y_pred = np.dot(X, self.weight) + self.bias
# 计算梯度
dw = (1 / n_samples) * np.dot(X.T, (y_pred - y))
db = (1 / n_samples) * np.sum(y_pred - y)
# 更新参数
self.weight -= learning_rate * dw
self.bias -= learning_rate * db
def predict(self, X):
return np.dot(X, self.weight) + self.bias
代码解释:
__init__:初始化权重和偏置为None。fit:使用梯度下降法训练模型。它接收特征X、目标值y、学习率和迭代次数作为输入。predict:使用训练好的权重和偏置对新数据X进行预测。
扩展应用:实现一个简单神经网络🧩
掌握了线性回归的实现后,我们可以进一步探索更复杂的模型。本节我们将实现一个用于二分类的简单神经网络。
这个网络将有一个隐藏层,使用Sigmoid激活函数。
class SimpleNeuralNetwork:
def __init__(self, input_size, hidden_size, output_size):
# 初始化权重和偏置
self.W1 = np.random.randn(input_size, hidden_size)
self.b1 = np.zeros((1, hidden_size))
self.W2 = np.random.randn(hidden_size, output_size)
self.b2 = np.zeros((1, output_size))
def sigmoid(self, x):
return 1 / (1 + np.exp(-x))
def forward(self, X):
# 前向传播
self.z1 = np.dot(X, self.W1) + self.b1
self.a1 = self.sigmoid(self.z1)
self.z2 = np.dot(self.a1, self.W2) + self.b2
self.a2 = self.sigmoid(self.z2)
return self.a2
def train(self, X, y, learning_rate=0.1, epochs=10000):
for i in range(epochs):
# 前向传播
output = self.forward(X)
# 反向传播(简化版,使用均方误差)
error = output - y
d_output = error * (output * (1 - output)) # Sigmoid导数
error_hidden = d_output.dot(self.W2.T)
d_hidden = error_hidden * (self.a1 * (1 - self.a1))
# 更新权重和偏置
self.W2 -= self.a1.T.dot(d_output) * learning_rate
self.b2 -= np.sum(d_output, axis=0, keepdims=True) * learning_rate
self.W1 -= X.T.dot(d_hidden) * learning_rate
self.b1 -= np.sum(d_hidden, axis=0, keepdims=True) * learning_rate
代码解释:
__init__:随机初始化两层网络的权重和偏置。sigmoid:Sigmoid激活函数。forward:执行前向传播,计算网络输出。train:使用反向传播和梯度下降训练网络。这里使用了一个简化的梯度计算。
总结✨

在本节课中,我们一起学习了Python类与对象在机器学习中的应用。我们首先了解了类作为创建对象蓝图的基本概念。接着,我们探讨了在机器学习中使用类来封装模型参数和方法的优势,这能使代码结构更清晰、更易维护。然后,我们通过动手实践,使用类从头实现了一个线性回归模型和一个简单的二分类神经网络。通过这些例子,你应该对如何使用类来组织机器学习代码有了更具体的认识。掌握类的使用是构建复杂、模块化机器学习项目的重要一步。
033:Python中的NumPy入门
在本节课中,我们将学习NumPy。NumPy是Python中用于科学计算的基础库,尤其在机器学习和数据科学领域至关重要。我们将从Python基础语法回顾开始,然后深入探讨NumPy是什么、为何重要,并通过实践练习来掌握其基本用法。

Python基础语法快速回顾
上一节我们介绍了本节课的目标,本节中我们先快速回顾一下Python的基础语法。Python是一种语法易读、易于学习的编程语言,它是机器学习和数据科学领域最流行的语言。
Python流行的原因包括其丰富的库生态系统和强大的社区支持。以下是Python中的一些基本数据类型和控制结构:
- int:整数类型。
- float:浮点数类型,即带小数点的数字,例如
2.3。 - str:字符串类型。
- bool:布尔类型,取值为
True或False。 - list:列表类型。我们将花一些时间讨论Python列表,因为后面会对比NumPy在数组操作上的优势。
- 条件语句与循环:包括
if-else条件判断、for循环和while循环等。 - 函数:使用
def关键字定义代码块,可以重复调用。
如果你需要更系统地学习Python语法,可以参考提供的链接资源。为了课程的完整性,我们在此做一个简要概述。
什么是NumPy及其应用场景
在回顾了Python基础后,本节我们来看看NumPy是什么以及它如何用于处理数据。NumPy是Numerical Python的缩写,它是一个强大的Python库,主要用于处理大型多维数组和矩阵。
NumPy提供了一个高性能的多维数组对象 ndarray,以及用于操作这些数组的大量函数。在数据科学和机器学习中,我们经常需要高效地执行数值运算,NumPy正是为此而设计。
NumPy在数据科学中的奠基性作用
了解了NumPy的基本定义后,我们来探讨它为何在数据科学和机器学习领域具有如此奠基性的地位。当NumPy被引入时,它解决了Python原生列表在数值计算上的几个关键瓶颈:
- 性能:NumPy数组在内存中连续存储,并且运算由预编译的C代码执行,速度远快于Python列表的循环操作。
- 功能:NumPy提供了大量高级数学函数,方便进行向量化操作,无需编写显式循环。
- 广播机制:NumPy的广播功能允许不同形状的数组进行算术运算,这大大简化了代码。
正是这些特性,使得NumPy成为后续众多科学计算库(如Pandas、SciPy、Scikit-learn)的基础。
NumPy实践练习
理论介绍完毕,现在让我们通过一些动手练习来熟悉NumPy。我们将使用Google Colab来编写和运行Python代码。
首先,我们需要导入NumPy库。在Python中,通常使用 np 作为NumPy的别名。
import numpy as np
以下是几个核心概念的实践示例:
1. 创建数组
我们可以从Python列表创建NumPy数组。
# 创建一维数组
arr_1d = np.array([1, 2, 3, 4, 5])
print("一维数组:", arr_1d)
# 创建二维数组(矩阵)
arr_2d = np.array([[1, 2, 3], [4, 5, 6]])
print("二维数组:\n", arr_2d)
2. 数组属性
每个NumPy数组都有描述其形状、大小和数据类型等信息的属性。
print("数组形状 (shape):", arr_2d.shape)
print("数组维度 (ndim):", arr_2d.ndim)
print("数组元素总数 (size):", arr_2d.size)
print("数组数据类型 (dtype):", arr_2d.dtype)
3. 生成特殊数组
NumPy提供了快速生成特定数组的函数。
# 生成全零数组
zeros_arr = np.zeros((2, 3))
print("全零数组:\n", zeros_arr)
# 生成全一数组
ones_arr = np.ones((3, 2))
print("全一数组:\n", ones_arr)
# 生成单位矩阵
identity_mat = np.eye(3)
print("3x3单位矩阵:\n", identity_mat)
4. 数组运算
NumPy支持元素级运算和矩阵运算。
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
# 元素加法
print("a + b =", a + b)
# 元素乘法
print("a * b =", a * b)
# 点积(内积)
print("a 和 b 的点积:", np.dot(a, b))
5. 数组索引与切片
访问和修改数组元素的方法与Python列表类似。
arr = np.array([[10, 20, 30], [40, 50, 60], [70, 80, 90]])
# 访问单个元素
print("第二行第三列的元素:", arr[1, 2])
# 切片
print("第一行的所有元素:", arr[0, :])
print("第二列的所有元素:", arr[:, 1])
总结

本节课中,我们一起学习了NumPy的基础知识。我们首先快速回顾了Python的基本语法,然后介绍了NumPy库及其在高效处理数值数据方面的核心作用。我们探讨了NumPy相比Python原生列表的优势,包括其卓越的性能、丰富的功能和广播机制。最后,我们通过实际的代码练习,学习了如何创建数组、查看数组属性、进行数组运算以及索引切片。掌握NumPy是深入学习机器学习和数据科学的重要一步。
034:Pandas入门指南 🐼

在本节课中,我们将要学习Python中一个极其重要的库——Pandas。Pandas是进行数据操作、探索和分析的核心工具,尤其在机器学习和数据科学领域不可或缺。我们将从零开始,介绍它的基本概念、常用操作,并通过一个实际的数据集进行动手实践。
什么是Pandas?🤔
上一节我们介绍了课程的整体目标,本节中我们来看看Pandas究竟是什么。
Pandas是一个Python库。这意味着你可以通过导入这个库来轻松使用它。这些库旨在简化你的工作,避免你反复编写相同的代码。Pandas库主要用于数据操作、数据探索或数据分析。
它被引入的原因如下:在之前的课程中,我们讨论了NumPy被引入Python的原因。Python默认有列表,列表类似于数组,可以存储数字和其他数据集。但我们讨论过,NumPy的引入是为了将列表转换为一种能让你更快进行计算的形式。如果你有一个向量...
为什么使用Pandas?🎯
了解了Pandas是什么之后,我们来看看它被创造出来要解决的核心问题。
Pandas被设计用来处理表格数据。在现实世界中,数据通常以表格形式存在,例如电子表格或数据库表。Pandas引入了两个核心数据结构来高效地处理这类数据:
- Series:可以看作是一个带标签的一维数组。其基本结构是一个索引对应一个值。
- 公式/概念:
Series = 索引(Index) + 数据值(Values)
- 公式/概念:
- DataFrame:这是Pandas中最重要的数据结构,它是一个二维的、大小可变的、潜在的异构的表格数据。你可以把它想象成Excel中的一个工作表或SQL中的一个表。
- 公式/概念:
DataFrame = 多个Series的集合(按列组织) + 行索引 + 列标签
- 公式/概念:
本节课的学习目标 📋
在深入细节之前,我们先明确学完本节课后你将掌握什么。
在本节课结束时,你将拥有以下收获:
- 理解Pandas是什么,在何处以及为何使用它。
- 获得加载真实世界数据集的体验,这些数据集大多以CSV文件格式存储。我也会解释为何这是Pandas被引入的初衷之一。
- 探索数据,尝试使用Pandas从数据中获得一些洞见。
- 尝试清理数据,例如处理空行或空列。我们将看到如何清理数据以及如何对数据执行某些转换。
- 在数据上执行一些聚合操作,如求和、求平均值或执行基本分析等。
- 最后,在本节课结束时,我们还将进行一个迷你实践项目,你将在一个简单的数据集上应用今天学到的一些知识。

总的来说,本节课将涵盖Pandas的基本概念,但也涉及一些编码。我将在Google Colab中编写代码,你也可以和我一起打开Google Colab并编写代码,以获得相同的动手经验。
035:Python机器学习数据可视化库入门 - Matplotlib, Seaborn


在本节课中,我们将学习机器学习领域中最著名的一些数据可视化库。具体来说,我们将重点介绍三个库:Matplotlib、Seaborn和Plotly。如果你在机器学习领域有过一些经验,你很可能听说过它们。即使你还不熟悉,也不必担心,我们将从初学者的角度来讲解。欢迎来到本讲。
通过本讲的学习,你将能够:
- 了解在机器学习中最有用的可视化类型及其重要性。
- 对Matplotlib、Seaborn和Plotly这些Python中著名的绘图库有一个清晰的认识。
- 进行一些绘图操作,以探索数据并尝试从中获取洞察。
- 在本讲最后,我们将在一个著名的数据集——泰坦尼克号数据集上,进行一项名为“探索性数据分析”的著名操作。
那么,让我们开始吧。
数据可视化的重要性
数据可视化非常重要。试想,如果你是一家公司,正在为你的商业客户构建一个机器学习模型,你如何向客户传达模型的性能?你如何展示你的工作成果?是呈现一堆表格,还是通过视觉化的方式展示?你必须通过可视化来说服对方,因为人类天生对图像的接受度远高于数字。
正如前面提到的,探索性数据分析是一种技术,即在构建任何机器学习模型之前,通过绘制数据的各个方面来尝试获取洞察。我们今天就会进行这项操作。
或者,如果你想发现数据中哪些特征对于使用机器学习模型进行分类最为重要,这被称为特征工程。这也是可视化数据中相关特征的一部分。
你可以通过准确率、F1分数或其他参数来解释你的模型,还可以绘制混淆矩阵。这些我们也会涉及。
此外,与利益相关者进行沟通是构建机器学习模型非常重要的一环。你是在为他人构建模型。因此,无论你是学生还是行业专业人士,如果你在机器学习领域从事严肃的工作,最终都需要通过精美的可视化来进行沟通。希望本讲能为你提供一个良好的起点。
第一个库:Matplotlib
我们将要看的第一个库是Matplotlib。这个库构成了Python数据可视化的基础。

Matplotlib是一个底层绘图库,它提供了广泛的工具来创建静态、交互式和动画可视化。你可以将其视为绘图领域的“瑞士军刀”。几乎所有其他高级可视化库(如Seaborn)都构建在Matplotlib之上。
以下是Matplotlib的一些核心概念和基本用法:
1. 导入Matplotlib
通常,我们导入pyplot模块,并约定俗成地将其简写为plt。
import matplotlib.pyplot as plt
2. 创建图形和坐标轴
在Matplotlib中,图形是绘图的顶级容器,而坐标轴是实际绘制数据的区域。
fig, ax = plt.subplots() # 创建一个图形和一个坐标轴
3. 基本绘图
你可以使用坐标轴对象的方法来绘制各种图形,例如折线图:
ax.plot([1, 2, 3, 4], [1, 4, 2, 3]) # 绘制数据点 (1,1), (2,4), (3,2), (4,3)
4. 自定义图表
你可以添加标题、坐标轴标签、图例等来美化图表。
ax.set_title('My First Plot')
ax.set_xlabel('X Axis')
ax.set_ylabel('Y Axis')
5. 显示图表
最后,使用plt.show()来显示图形。
plt.show()
Matplotlib非常灵活,可以创建从简单的折线图到复杂的3D图形在内的几乎所有类型的图表。然而,对于常见的统计图表,使用构建在Matplotlib之上的Seaborn库可能更加方便。
第二个库:Seaborn
上一节我们介绍了基础绘图库Matplotlib。本节中,我们来看看Seaborn,它是一个基于Matplotlib的高级统计图形库。
Seaborn简化了许多常见统计图表的创建过程,并且默认具有更美观的样式和颜色主题。它与Pandas数据结构集成得非常好,使得从DataFrame绘制图表变得非常简单。
以下是Seaborn的一些关键特性:
1. 导入Seaborn
import seaborn as sns
2. 内置数据集和美观主题
Seaborn自带一些示例数据集,并设置了更吸引人的默认绘图风格。
sns.set_theme() # 应用默认主题
tips = sns.load_dataset('tips') # 加载示例数据集
3. 绘制统计关系图
例如,用一行代码绘制带有回归拟合线的散点图:
sns.regplot(x='total_bill', y='tip', data=tips)
4. 分类数据可视化
Seaborn擅长绘制分类数据的图表,如箱线图、小提琴图等。
sns.boxplot(x='day', y='total_bill', data=tips)
5. 分布可视化
可以轻松绘制单变量或双变量的分布图,如直方图、核密度估计图。
sns.histplot(data=tips, x='total_bill')
Seaborn通过高级接口封装了复杂的Matplotlib代码,让用户能够更专注于数据和洞察,而非绘图细节。
第三个库:Plotly
我们介绍了用于创建静态图表的Matplotlib和Seaborn。现在,让我们看看Plotly,它是一个用于创建交互式图表的强大库。
Plotly的图表是动态的,你可以缩放、平移、悬停查看数据点详细信息,这对于在网页或仪表板中展示数据尤其有用。
以下是Plotly的核心特点:
1. 导入Plotly
通常使用其express高级接口,它非常简洁。
import plotly.express as px
2. 创建交互式图表
用一行代码创建交互式散点图。
fig = px.scatter(tips, x='total_bill', y='tip', color='smoker')
fig.show()
3. 丰富的交互功能
生成的图表允许你通过鼠标进行缩放、框选、查看数据点具体数值等操作。
4. 多样的图表类型
Plotly支持大量图表类型,包括3D图表、地图、动画图表等。
虽然Plotly功能强大,但对于简单的静态分析,Matplotlib和Seaborn可能更快捷。选择哪个库取决于你的具体需求:静态报告还是交互式展示。
实战:泰坦尼克号数据集EDA
现在,我们将综合运用所学知识,对著名的泰坦尼克号数据集进行一次简单的探索性数据分析。EDA的目标是在建模前理解数据、发现模式、检测异常。
我们将使用Seaborn,因为它与Pandas配合好且绘图简洁。
步骤简述:
- 加载数据:从Seaborn内置数据集中加载泰坦尼克号数据。
titanic = sns.load_dataset('titanic') - 初步查看:使用
.head()、.info()、.describe()了解数据结构和摘要统计。 - 可视化探索:
- 生存情况分布:绘制幸存与未幸存人数的计数图。
sns.countplot(x='survived', data=titanic) - 性别与生存关系:按性别分组查看生存计数。
sns.countplot(x='sex', hue='survived', data=titanic) - 票价分布:绘制票价的直方图或箱线图,观察其分布和离群值。
sns.histplot(x='fare', data=titanic, bins=30) - 舱位等级与生存:分析不同客舱等级的乘客生存率。
sns.barplot(x='pclass', y='survived', data=titanic) - 年龄与生存关系:可以绘制按生存情况分组的年龄小提琴图或箱线图。
sns.boxplot(x='survived', y='age', data=titanic)
- 生存情况分布:绘制幸存与未幸存人数的计数图。
通过这些可视化图表,我们可以直观地得出一些初步洞察,例如:“女性生存率高于男性”、“头等舱乘客生存机会更大”、“儿童和老人可能受到优先救助”等。这些洞察将指导后续的特征工程和模型构建。
总结
本节课中我们一起学习了Python机器学习中三个核心的数据可视化库。
- Matplotlib:提供了基础且强大的绘图功能,是其他库的基石。
- Seaborn:基于Matplotlib,简化了统计图表的创建,默认样式美观,与Pandas集成度高。
- Plotly:专注于创建交互式图表,适合网页和仪表板应用。
我们探讨了数据可视化在机器学习中的关键作用:用于探索性数据分析、特征工程、模型结果解释以及与利益相关者的沟通。最后,我们通过泰坦尼克号数据集的EDA实战,演示了如何利用可视化从数据中获取有价值的洞察。

掌握这些工具将极大地提升你理解数据、展示成果的能力,是机器学习工程师和数据科学家必备的技能。
036:Python Scikit-learn入门
在本节课中,我们将要学习Python中最流行的机器学习库之一——Scikit-learn。我们将以一个简单的数据集为例,完整地走一遍机器学习项目流程,包括数据探索、数据预处理、模型实现与评估。具体来说,我们将实现K近邻和决策树两种模型,并了解其背后的基本原理。

什么是机器学习?
在开始学习Scikit-learn之前,我们先简要讨论一下什么是机器学习。
在传统编程中,我们通过编写明确的规则(如if-else条件语句)来告诉计算机如何根据输入产生输出。然而,在机器学习中,我们不显式地编程定义这些规则。相反,我们让算法从数据中自行“学习”出输入与输出之间的映射关系。这个过程被称为训练。
机器学习的类型
机器学习过程大致可分为三种主要类型:监督学习、无监督学习和强化学习。此外,还有自监督学习、半监督学习等其他术语。
以下是三种主要学习类型的简要介绍:
- 监督学习:在这种学习中,我们为模型提供带有明确标签的训练数据。例如,在训练一个区分猫狗图片的分类器时,输入是图片,对应的标签是“猫”或“狗”。模型的任务是学习从图片到标签的映射关系。
- 无监督学习:在这种学习中,训练数据没有明确的标签。算法的目标是从数据中发现内在的结构或模式,例如将数据点分组到不同的聚类中。
- 强化学习:在这种学习中,一个智能体通过与环境互动来学习。它根据采取的行动获得奖励或惩罚,目标是学习一个策略,以最大化长期累积奖励。
引入Scikit-learn
上一节我们介绍了机器学习的基本概念,本节中我们来看看今天的主角——Scikit-learn。
Scikit-learn(简称sklearn)是Python中一个功能强大且易于使用的机器学习库。它内置了大量经典的机器学习算法,并提供了统一的接口,使得数据预处理、模型训练、预测和评估变得非常简单。
为了使用Scikit-learn,我们首先需要导入它。通常,我们也会导入一些辅助库,如NumPy和Pandas,用于数据处理。
import numpy as np
import pandas as pd
from sklearn import datasets
加载与探索数据
一个机器学习项目始于数据。Scikit-learn内置了一些经典的小型数据集,非常适合用于学习和测试。
本节课我们将使用著名的鸢尾花数据集。这个数据集包含了三种不同品种鸢尾花(山鸢尾、变色鸢尾、维吉尼亚鸢尾)的测量数据,每种有50个样本。每个样本有4个特征:花萼长度、花萼宽度、花瓣长度和花瓣宽度。
以下是加载和初步查看数据的步骤:
# 加载鸢尾花数据集
iris = datasets.load_iris()
# 数据集通常被组织为特征矩阵 X 和目标向量 y
X = iris.data # 特征
y = iris.target # 标签(0, 1, 2 分别代表三种花)
# 查看数据形状
print(f"特征数据形状: {X.shape}") # 输出: (150, 4)
print(f"标签数据形状: {y.shape}") # 输出: (150,)
# 查看特征名称和标签名称
print(f"特征名称: {iris.feature_names}")
print(f"标签名称: {iris.target_names}")
通过查看数据形状,我们知道有150个样本,每个样本有4个特征。标签y是一个包含150个数字(0, 1, 2)的向量,对应三种花的品种。
数据预处理与划分
在将数据喂给模型之前,通常需要进行一些预处理,并将数据划分为训练集和测试集。
数据预处理可能包括处理缺失值、标准化或归一化特征等。鸢尾花数据集非常干净,我们暂时跳过复杂的预处理。
划分数据集至关重要,它让我们可以用一部分数据(训练集)来训练模型,然后用另一部分未见过的数据(测试集)来评估模型的泛化能力。Scikit-learn提供了方便的train_test_split函数。
from sklearn.model_selection import train_test_split
# 将数据随机划分为训练集和测试集,测试集占比20%
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
print(f"训练集大小: {X_train.shape}")
print(f"测试集大小: {X_test.shape}")
random_state参数用于确保每次运行代码时,数据划分的方式都是一致的,这有助于结果的可复现性。
模型一:K近邻算法
现在我们已经准备好了数据,接下来开始实现第一个机器学习模型——K近邻。
K近邻是一种简单直观的监督学习算法,既可用于分类也可用于回归。其核心思想是:对于一个新样本,在特征空间中找出与其最接近的K个训练样本,然后根据这K个“邻居”的标签(通过投票或平均)来预测新样本的标签。
距离通常使用欧几里得距离计算,公式如下:
distance = sqrt((x1-x2)^2 + (y1-y2)^2 + ...)
在Scikit-learn中,实现KNN只需要几行代码:
from sklearn.neighbors import KNeighborsClassifier
# 创建KNN分类器实例,设置邻居数K=3
knn_model = KNeighborsClassifier(n_neighbors=3)
# 使用训练数据拟合(训练)模型
knn_model.fit(X_train, y_train)
# 使用训练好的模型对测试集进行预测
y_pred_knn = knn_model.predict(X_test)
模型训练完成后,我们可以用它对测试集进行预测,得到预测结果y_pred_knn。
模型评估
我们如何知道模型预测得好不好呢?这就需要评估指标。
对于分类问题,一个基础的指标是准确率,即预测正确的样本数占总样本数的比例。
from sklearn.metrics import accuracy_score
# 计算KNN模型的准确率
knn_accuracy = accuracy_score(y_test, y_pred_knn)
print(f"K近邻模型准确率: {knn_accuracy:.2f}")
除了准确率,混淆矩阵、精确率、召回率等也是常用的分类评估指标。
模型二:决策树算法
上一节我们使用K近邻算法对鸢尾花数据进行了分类,本节中我们来看看另一种经典的算法——决策树。
决策树通过一系列if-else决策规则对数据进行划分,最终形成一棵树状结构。它非常易于理解和解释。
以下是使用Scikit-learn实现决策树的步骤:
from sklearn.tree import DecisionTreeClassifier
# 创建决策树分类器实例
tree_model = DecisionTreeClassifier(random_state=42)
# 训练决策树模型
tree_model.fit(X_train, y_train)
# 使用决策树模型进行预测
y_pred_tree = tree_model.predict(X_test)
# 评估决策树模型
tree_accuracy = accuracy_score(y_test, y_pred_tree)
print(f"决策树模型准确率: {tree_accuracy:.2f}")
我们可以比较两个模型的准确率,看看哪种算法在这个数据集上表现更好。
总结
本节课中我们一起学习了使用Scikit-learn库完成一个端到端的机器学习分类项目。
我们首先了解了机器学习的基本概念和类型。然后,我们加载了鸢尾花数据集并进行了初步探索。接着,我们将数据划分为训练集和测试集。之后,我们先后实现了K近邻和决策树两种分类模型,并使用准确率对它们进行了评估。

通过这个简单的示例,你应当对使用Scikit-learn进行数据预处理、模型训练、预测和评估的完整流程有了初步的感性认识。记住,对于更复杂的数据和问题,可能还需要更多的特征工程、模型调参和交叉验证等步骤。
037:Python深度学习库入门 - TensorFlow, Keras, PyTorch


在本节课中,我们将讨论Python中三个最强大的深度学习框架:TensorFlow、Keras和PyTorch。我们将了解它们的重要性,并通过构建一个简单的神经网络来学习它们的基本用法。课程结束时,你将对这些框架有一个清晰的认识。
什么是神经网络?🧠
首先,让我们讨论什么是神经网络。
从本质上讲,神经网络被称为通用函数逼近器。这是因为,一个具有单隐藏层和有限数量节点的神经网络,可以在给定的输入范围内逼近任何连续函数。
一个更简单的理解方式是,将神经网络看作是一堆层的组合。你可能见过类似下图的表示,它通过输入层、一个或多个隐藏层以及最终的输出层来描述一个神经网络。

在这个神经网络中,输入层有三个节点,意味着你可以输入三个值。它有两个隐藏层,以及一个输出节点,最终输出一个数值。
这些神经网络有时也被称为大型复合函数。例如,上图所示的神经网络可以用如下函数表示:
output = σ( W₂ * σ( W₁ * x + b₁ ) + b₂ )
其中:
- W 代表权重。
- b 代表偏置。
- σ 代表激活函数。
在这个神经网络中,如果没有激活函数,输出将只是输入的线性组合,即 y = W₂ * (W₁ * x + b₁) + b₂,这仍然是一个线性函数。激活函数的引入使得网络能够学习和表示复杂的非线性关系。
深度学习框架简介 🛠️
上一节我们介绍了神经网络的基本概念,本节中我们来看看为什么需要专门的框架来实现它们。
手动实现神经网络的所有计算(如前向传播、反向传播和梯度更新)非常繁琐且容易出错。这就是深度学习框架的用武之地。它们提供了高效、模块化的工具来构建和训练神经网络。
以下是三个最流行的Python深度学习框架:
- TensorFlow:由Google开发,是一个用于高性能数值计算的开源库,特别专注于机器学习和深度学习。它提供了灵活性和强大的生产部署能力。
- Keras:最初是一个独立的高级神经网络API,现在已紧密集成到TensorFlow中,作为
tf.keras。它以用户友好、模块化和可扩展性著称,能够快速原型设计。 - PyTorch:由Facebook的AI研究实验室开发,以其动态计算图和“Python化”的设计哲学而闻名,深受学术研究界的喜爱。
实践:使用Keras构建神经网络 💻
了解了基本框架后,让我们动手实践。本节我们将使用Keras构建一个用于二元分类任务的简单神经网络。
我们将使用 scikit-learn 来导入数据。以下是构建模型的步骤:
- 导入必要的库:包括
tensorflow和sklearn的相关模块。 - 准备数据:使用
sklearn生成或加载一个简单的数据集,并将其分为训练集和测试集。 - 构建模型:使用
tf.keras.Sequential顺序模型,添加输入层、隐藏层和输出层。 - 编译模型:指定损失函数、优化器和评估指标。
- 训练模型:在训练数据上拟合模型。
- 评估模型:在测试数据上评估模型的性能。
# 示例代码框架
import tensorflow as tf
from tensorflow import keras
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_classification
# 1. 生成模拟数据
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 2. 构建模型
model = keras.Sequential([
keras.layers.Dense(64, activation='relu', input_shape=(20,)), # 隐藏层
keras.layers.Dense(1, activation='sigmoid') # 输出层
])
# 3. 编译模型
model.compile(optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy'])
# 4. 训练模型
model.fit(X_train, y_train, epochs=10, batch_size=32, validation_split=0.1)
# 5. 评估模型
test_loss, test_acc = model.evaluate(X_test, y_test)
print(f'测试准确率:{test_acc}')
实践:使用PyTorch构建神经网络 ⚡
现在,我们来看看如何使用PyTorch完成相同的任务。PyTorch提供了更底层的控制,其动态图特性使得调试更加直观。
以下是使用PyTorch构建神经网络的关键步骤:
- 定义网络结构:创建一个继承自
torch.nn.Module的类,在__init__中定义层,在forward方法中定义前向传播逻辑。 - 准备数据:将数据转换为PyTorch张量,并可能封装进
DataLoader。 - 定义损失函数和优化器:例如,使用二元交叉熵损失和Adam优化器。
- 训练循环:手动编写循环,在每个周期(epoch)中执行前向传播、计算损失、反向传播和参数更新。
- 模型评估。
# 示例代码框架
import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_classification
# 1. 生成数据并转换为张量
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
X = torch.tensor(X, dtype=torch.float32)
y = torch.tensor(y, dtype=torch.float32).view(-1, 1)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 2. 定义模型
class SimpleNN(nn.Module):
def __init__(self):
super(SimpleNN, self).__init__()
self.layer1 = nn.Linear(20, 64)
self.layer2 = nn.Linear(64, 1)
self.relu = nn.ReLU()
self.sigmoid = nn.Sigmoid()
def forward(self, x):
x = self.relu(self.layer1(x))
x = self.sigmoid(self.layer2(x))
return x
model = SimpleNN()
# 3. 定义损失函数和优化器
criterion = nn.BCELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 4. 训练循环
epochs = 10
for epoch in range(epochs):
model.train()
optimizer.zero_grad() # 清零梯度
outputs = model(X_train)
loss = criterion(outputs, y_train)
loss.backward() # 反向传播
optimizer.step() # 更新参数
print(f'Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.4f}')
# 5. 评估(示例)
model.eval()
with torch.no_grad():
predictions = model(X_test)
predicted_classes = (predictions > 0.5).float()
accuracy = (predicted_classes == y_test).float().mean()
print(f'测试准确率:{accuracy.item():.4f}')
如何选择框架?🤔
我们已经用Keras和PyTorch分别实现了简单的神经网络。那么在实际项目中该如何选择呢?
以下是一些简单的指导原则:
- 选择Keras (tf.keras) 如果:你是一名初学者,希望快速入门和构建原型。你的项目侧重于快速实验和部署,并且你习惯使用TensorFlow生态系统。
- 选择PyTorch 如果:你正在进行学术研究,需要灵活的模型结构和动态计算图以便于调试。你更喜欢Python化的、直观的编程风格。
- 选择TensorFlow (底层API) 如果:你需要对模型进行极其精细的控制,或者项目对生产环境下的性能和部署有非常高的要求。
实际上,两者都非常强大,并且功能在逐渐趋同。对于大多数初学者和常见任务,从 tf.keras 开始是一个极佳的选择。
总结 📚
本节课中我们一起学习了Python深度学习的核心工具。
我们首先了解了神经网络作为通用函数逼近器的基本概念。接着,我们介绍了三大主流框架:TensorFlow、Keras和PyTorch。通过动手实践,我们分别使用 Keras 和 PyTorch 构建并训练了一个简单的二元分类神经网络。最后,我们讨论了如何根据项目需求和个人偏好来选择合适的框架。

掌握这些框架是进入深度学习领域的重要一步。建议你继续在更复杂的数据集和网络结构上进行练习,以加深理解。
038:机器学习算法概览

在本节课中,我们将学习机器学习领域中最常见的一些核心算法。本讲座的目的是为你提供一个清晰的图谱,帮助你理解各种算法在机器学习版图中的位置。你可能听说过许多术语,如支持向量机、深度神经网络、隐马尔可夫模型、强化学习、长短期记忆网络等。这些术语在不同语境下变得非常流行,但很多人并不清楚它们之间的界限、需要学习多少内容,以及如何规划学习路径。因此,本节课不会深入讲解任何具体算法,而是为你绘制一张地图,展示所有存在的不同技术。如果你想在未来六到八个月内学习机器学习,了解这些内容将帮助你明确学习方向,为成为机器学习专家打下坚实基础。
人工智能、机器学习与深度学习
首先,我们来看看人工智能、机器学习和深度学习之间的区别。这些术语有时会被混用,但这并不准确,它们各自有特定的含义。
人工智能是一个广泛的领域,涵盖了一系列使机器或计算机能够获得某种类人智能的技术。人工智能涉及许多其他方面,例如能够执行自主任务的机器人。任何能够做出决策并执行任务的系统都可以归入人工智能的范畴。人工智能有许多早期形式,例如遗传算法和模糊逻辑,其涵盖的范围非常广泛。
而机器学习和深度学习则是实现人工智能最成功的技术。机器学习是指这样一类模型:它们能够在已有数据上进行训练,并对未见过的数据进行预测。在机器学习模型中,数据的特征是现成可用的。这里的“特征”可以理解为数据表中的列。例如,一个包含个人血糖、身体质量指数和胆固醇水平的数据集,每个人的这三个数据点就可以直接作为特征,供机器学习模型学习。
机器学习算法分类
上一节我们了解了人工智能的广阔范畴,以及机器学习在其中的位置。本节中,我们将具体看看机器学习算法的主要分类。机器学习算法通常可以根据学习方式分为三大类:监督学习、无监督学习和强化学习。
以下是这三种主要学习方式的简要介绍:
- 监督学习:模型从带有标签的训练数据中学习。目标是学习一个从输入到输出的映射函数,以便对新的、未见过的输入做出准确预测。这就像有老师提供正确答案来指导学习。
- 无监督学习:模型在没有标签的数据中发现内在结构或模式。目标可能是对数据进行分组、降维或发现异常。这就像在没有指导的情况下自行探索数据。
- 强化学习:智能体通过与环境互动来学习。它通过尝试不同的行动并获得奖励或惩罚来学习达成目标的最佳策略。这就像通过试错来学习游戏。
核心算法简介
了解了三大学习范式后,我们来看看每一类中一些最核心和流行的具体算法。掌握这些算法是构建坚实机器学习基础的关键。
以下是监督学习中的一些代表性算法:

- 线性回归:用于预测连续的数值。其核心思想是找到一条最佳拟合直线(或超平面)。公式可以表示为:
y = w1*x1 + w2*x2 + ... + b,其中w是权重,b是偏置。 - 逻辑回归:尽管名字中有“回归”,但它主要用于分类任务,特别是二分类。它通过Sigmoid函数将线性组合映射到0到1之间的概率。
- 支持向量机:一种强大的分类算法,目标是找到一个能最大化不同类别数据间隔的超平面。
- 决策树与随机森林:决策树通过一系列规则对数据进行分类或回归。随机森林则是通过构建多棵决策树并综合其结果,以提高模型的准确性和鲁棒性。
- 朴素贝叶斯:基于贝叶斯定理,并假设特征之间相互独立。它简单高效,常用于文本分类。
以下是无监督学习中的一些代表性算法:
- K-均值聚类:一种将数据划分为K个簇的聚类算法。目标是使同一个簇内的数据点尽可能相似,不同簇间的数据点尽可能不同。
- 主成分分析:一种降维技术,通过线性变换将原始数据转换为一组各维度线性无关的表示,用于提取主要特征分量。
最后,强化学习有其独特的学习框架,智能体、环境、状态、动作和奖励是其核心概念。深度Q网络和策略梯度方法是当前强化学习领域的重要算法。
深度学习简介
在讨论了传统机器学习算法之后,我们自然要过渡到机器学习的一个强大子领域——深度学习。深度学习本质上是使用深层神经网络(即包含多个隐藏层的神经网络)的机器学习。
深度学习在处理如图像、声音、文本等非结构化数据方面表现出色。以下是一些关键的深度学习架构:
- 卷积神经网络:专门为处理网格状数据(如图像)而设计,通过卷积层自动提取空间层次特征。
- 循环神经网络:用于处理序列数据(如时间序列、文本),具有记忆先前信息的能力。长短期记忆网络 是RNN的一种改进,能更好地学习长期依赖关系。
- 生成对抗网络:由生成器和判别器组成,两者在对抗中共同进步,常用于生成新的、与训练数据相似的数据样本。
总结
本节课中,我们一起学习了机器学习算法的整体图谱。我们从区分人工智能、机器学习和深度学习开始,明确了它们之间的关系。接着,我们探讨了机器学习的三大范式:监督学习、无监督学习和强化学习,并列举了每一类中的核心算法,如线性回归、支持向量机、K-均值聚类等。最后,我们简要介绍了深度学习及其代表性架构,如卷积神经网络和循环神经网络。理解这个概览图有助于你规划学习路径,知道在广阔的机器学习领域中需要关注哪些核心内容。
039:AI的发展方向?演变、当前趋势与职业机会
在本节课中,我们将一起回顾人工智能在过去几十年的发展历程,梳理其演变阶段、分析当前的核心趋势,并探讨未来几年的职业机会。我们将跳出日常的技术新闻,从一个更宏观的视角来理解AI的发展脉络。
概述:为何需要回顾AI发展史?
如果你经常使用领英或其他社交媒体,你一定会不断听到AI/ML领域的新进展。这些消息的涌现速度极快,几乎令人应接不暇。因此,本节课旨在后退一步,纵览全局,观察AI在过去几十年是如何发展的。我们将把这些发展或演变划分为几个不同的阶段,以便看清在特定时期最突出的进展是什么,以及在当前纷繁的噪音中正在发生什么,并展望未来五年左右的情况。这样做的目的是帮助你明确应该关注哪些领域,从而在AI/ML领域获得最佳的职业机会。
AI发展的四个阶段

我们将AI的发展历程划分为四个主要阶段或时代。
第一阶段:2010年之前 - 机器学习与特征工程时代
在2010年之前的阶段,机器学习模型或基于特征工程的模型最为突出。那确实是许多数学基础得以奠定的时期,为基本的概率模型和基础的机器学习模型打下了坚实的理论基础。
第二阶段:2010-2020年 - 深度学习爆发时代

然而,真正的变革和巨大的职业机会转变发生在2010年至2020年。深度学习随着深度神经网络架构的出现而真正爆发,使得利用海量数据训练模型成为可能,并能在生产环境中实际执行有用的任务。
第三阶段:2020-2025年 - 基础模型时代
从2020年到2025年,可以称之为基础模型时代。我们见证了GPT-3.0的发布,以及后续的GPT模型和其他大型语言模型。在这些模型之上,你可以进行微调,或利用单独的数据库执行检索增强生成(RAG)并进行查询。
第四阶段:2025年及以后 - AI智能体时代
现在,在2025年,许多人开始讨论AI智能体。许多人也在谈论模型上下文协议(MCP)等许多其他术语。因此,让我们分阶段审视AI的整个发展过程,并尝试预测接下来会发生什么,以及将出现何种职业机会。
演变历程:从人工神经元到自主AI智能体
这项技术始于像人工神经元或多层感知机这样基础的概念。多层感知机是一种前馈神经网络,起点就是如此简单。如今,它已经发展到能够自主决策并执行行动的自主AI智能体阶段。因此,本节课将概述AI领域已经发生的所有事情、我们周围正在发生的事情,以及我们在不久的将来可以预期发生的事情。
总结与展望
本节课中,我们一起回顾了人工智能从早期机器学习到当前AI智能体时代的演变历程。我们梳理了四个关键发展阶段:特征工程时代、深度学习爆发时代、基础模型时代以及正在兴起的AI智能体时代。理解这一发展脉络,有助于我们在快速变化的技术浪潮中把握核心趋势,并为未来的学习和职业规划找准方向。

浙公网安备 33010602011771号