简介这份CS229课程资料包面向希望系统入门并夯实机器学习理论的学习者也适合对照作业与解答自学的读者覆盖从监督学习基础到强化学习等核心主题。包内共47个文件以30份PDF讲义与复习笔记为主体辅以7个ZIP作业及数据包、6个MATLAB脚本和4个DAT数据文件压缩包约9.22MB兼顾理论阅读、公式推导与编程实践。已有1322人学习说明其在机器学习自学者中具有一定参考价值。讲义涉及线性回归、逻辑回归、生成学习、支持向量机、学习理论、EM算法、因子分析、PCA、ICA与强化学习作业及配套解答可用于检验推导和建模思路数据与脚本便于复现实验。线性代数、概率、凸优化、隐马尔可夫模型和高斯过程等复习笔记则能帮助读者补齐数学基础适合按章节研读并结合作业查漏补缺。1. 一张推导链的地图CS229 讲义真正在讲什么CS229 这套讲义和作业放在一起最反直觉的一点是它不按算法清单组织而是沿着「假设 → 似然 → 求解 → 诊断」这条推导链一路铺下去。骨架大致分五块监督学习回归、分类、GLM、生成式模型与核方法、学习理论与正则化、无监督EM、PCA、强化学习MDP。真正的岔路口在「判别式还是生成式」——往左是逻辑回归和 SVM往右是高斯判别分析和朴素贝叶斯两条路最后又在核技巧与学习理论上碰头。已经跑过模型、却说不清损失函数为什么长这样的人以及考前要把整门课重新连起来的人读这套材料的收益最大。2. 监督学习主线从最小二乘到 GLM 的同一套配方这一章的内容看起来最基础其实最容易被略读因为它表面上就是几个熟悉到腻的模型。作业里出错最多的往往不是后面的 EM 和 SVM而是这里——损失函数的来源说不清楚后面所有「为什么这个梯度长这样」都只能靠背。合理的读法是把它当成一条推导链先定假设再写似然再求导最后才看解的形式。2.1 最小二乘不是拍脑袋似然、梯度与正规方程线性回归的假设是 h_θ(x) θᵀx目标函数写成 J(θ) ½ Σᵢ (θᵀx⁽ⁱ⁾ − y⁽ⁱ⁾)²前面的 ½ 纯粹是为了求导时把 2 约掉不影响最优解的位置。对 θ 求梯度得到 ∇J Xᵀ(Xθ − y)令其为零解出正规方程 θ (XᵀX)⁻¹Xᵀy这个式子在讲义里通常会和梯度下降并列给出但作业更关心的是两者各自的适用条件。真正值得反复看的是它后面那段概率解释。假设 y⁽ⁱ⁾ θᵀx⁽ⁱ⁾ ε⁽ⁱ⁾ε 独立同分布于 N(0, σ²)那么写出似然函数、取对数、丢掉与 θ 无关的常数项之后剩下的正是负的最小二乘目标。也就是说平方损失不是约定俗成的选择而是「高斯噪声」这个假设的直接产物。把噪声换成拉普拉斯分布同一套推导会给出 L1 损失换成伯努利分布就得到下一节的交叉熵。这一步是整个课程的第一个「原来如此」也是复习时最该自己白纸推一遍的地方。局部加权线性回归是这一节的补充内容它不再拟合一套全局参数而是对每个查询点单独解一个加权最小二乘权重取 w⁽ⁱ⁾ exp(−‖x⁽ⁱ⁾ − x‖² / 2τ²)τ 越小越只看邻近点。它在讲义里被归为「非参数方法」的引子τ 的角色等价于后来的核宽度这个直觉在读到 SVM 的 RBF 核时会第二次出现。import numpy as np def normal_equation(X, y): # X 需要事先补一列全 1 当截距项形状为 (m, n1) # 用 pinv 而不是 invX^T X 接近奇异时共线特征不会直接报错 return np.linalg.pinv(X.T X) X.T y def batch_gd(X, y, lr0.01, epochs1000): theta np.zeros(X.shape[1]) m X.shape[0] for _ in range(epochs): grad X.T (X theta - y) / m # 除以 m 让学习率与样本量解耦 theta - lr * grad return theta两段代码对应两种解法正规方程做一次矩阵求逆复杂度约 O(n³)n 是特征维度特征少样本多时最省事梯度下降每轮 O(mn)特征维度很大时反而是唯一可行的路子。作业里如果出现「跑不动」或「结果和解析解差很多」先查两件事X 有没有补截距列特征量纲差距是不是太大没标准化时 lr 会非常难调。2.2 逻辑回归梯度长得像来源完全不同逻辑回归的假设是 P(y1|x;θ) g(θᵀx)g 是 sigmoid。写出伯努利似然再取负对数得到交叉熵损失求导后梯度形式是 (h_θ(x) − y)·x和最小二乘的梯度长得几乎一样。这个巧合是复习时的第一个错觉来源——两者形式相同但一个来自高斯假设加恒等链接另一个来自伯努利假设加 logit 链接来源完全不同。GLM 那一节会把这件事彻底说清。作业里常考的一个问题是为什么分类不用平方损失两个理由一是 g(θᵀx) 是非线性的平方损失对 θ 不再是凸函数梯度下降可能停在局部极小二是当预测严重错误、sigmoid 饱和时平方损失的梯度会趋近于零等于错得越离谱学得越慢而交叉熵的梯度里饱和项被约掉了错误越大梯度越大。这条对比在考试里几乎必出。逻辑回归的求解除了梯度下降讲义还给了牛顿法θ : θ − H⁻¹∇其中 Hessian H XᵀDXD 是对角阵对角元为 h⁽ⁱ⁾(1 − h⁽ⁱ⁾)。牛顿法在凸问题上二次收敛迭代十几次通常就够代价是每步要解一个 (n1) 维线性方程组。def newton_step(X, y, theta, ridge1e-6): h 1.0 / (1.0 np.exp(-X theta)) grad X.T (h - y) D h * (1 - h) H X.T (D[:, None] * X) ridge * np.eye(X.shape[1]) # 加一点岭项防奇异 return theta - np.linalg.solve(H, grad) # solve 比 inv 数值上更稳ridge这一项在讲义里没有但作业数据出现完全可分的情况时 Hessian 会接近奇异‖θ‖ 会一路发散加一个极小的岭项是最省事的补救。多分类的 softmax 版本要注意参数冗余把所有 θ_j 同时减去同一个向量预测概率不变所以 Hessian 一定奇异这也是很多实现默认加正则的原因。2.3 指数族与 GLM把前两节收进同一个模板指数族的一般形式是 p(y;η) b(y)·exp(ηᵀT(y) − a(η))η 叫自然参数T(y) 是充分统计量a(η) 是归一化项。讲义用一张表把三个分布塞进这个框架这张表基本就是这一章的浓缩版分布自然参数 η充分统计量 T(y)a(η)导出的模型链接函数高斯 N(μ,1)μyη²/2最小二乘恒等伯努利 B(φ)log(φ/(1−φ))ylog(1e^η)逻辑回归logit多项分布log(φ_k/φ_K)one-hotlog Σ e^{η_j}softmax 回归softmaxGLM 的构造只有三步假定 y|x;θ 服从某个指数族分布令自然参数 η θᵀx这就是「线性」的含义预测时输出 E[y|x;θ]而指数族有个漂亮性质——E[y;η] ∂a(η)/∂η所以预测值直接由 a 的导数给出。三步走完最小二乘、逻辑回归、softmax 全部变成同一套配方在不同分布下的实例。梳理下来会发现这一节真正的价值不是记住三个模型而是记住「链接函数由分布决定」这条规则。复习时如果能把「为什么逻辑回归用 logit 而不是 probit」答成「因为伯努利分布的自然参数就是 logit」说明这块是真懂了。作业里偶尔会要求推导泊松回归套路完全一样写出泊松的指数族形式读出自然参数是 log λ链接函数就是 log。3. 判别与生成的岔路GDA、朴素贝叶斯与 SVM 核方法第二章的所有模型都是直接对 P(y|x) 建模这一章换了方向先对 P(x|y) 和 P(y) 建模再用贝叶斯公式反推。两条路在同一批数据上会给出不同的决策边界而它们各自的假设强度、样本效率、鲁棒性差异是这一章最值得记住的东西。3.1 GDA 与朴素贝叶斯先建模 p(x|y)再翻回 p(y|x)高斯判别分析假设 y 服从伯努利在给定 y 的条件下 x 服从多维高斯且两个类共享同一个协方差矩阵 Σ。参数估计就是最朴素的频率统计φ 是正类比例μ₀ 和 μ₁ 是两个类的特征均值Σ 用两类各自的中心化样本合并估计。把这两个高斯密度代进贝叶斯公式会发现二次项因为 Σ 相同而抵消最终 P(y1|x) 化简成 sigmoid(θᵀx) 的形式——决策边界仍然是线性的。这里有个非常容易记反的结论GDA 蕴含逻辑回归的函数形式反过来不成立。也就是说 GDA 的假设更强它额外假定了 x|y 是高斯的因此当假设成立时GDA 的样本效率更高小数据下往往比逻辑回归准但当数据实际上不是高斯尤其不是共享协方差时GDA 会系统性地偏逻辑回归因为只假设了 sigmoid 形式反而更稳。这个「生成式渐近效率高、判别式更鲁棒」的取舍在作业讲解里通常要展开讨论一次。朴素贝叶斯把假设推得更极端在给定 y 的条件下各个特征相互独立。于是 P(x|y) 拆成连乘参数量从指数级降到线性级。文本分类是它的经典场景词表就是特征取值是词出现的次数或 0/1。它最大的坑是零概率某个词在某个类里从没出现过连乘结果直接归零整个后验被一票否决。补法就是拉普拉斯平滑分子加 1、分母加词表大小或加 k这也是作业里最常被扣分的一行代码。3.2 最大间隔与对偶为什么预测只用到内积SVM 的出发点换了个角度不建模概率只找间隔最大的那个超平面。先定义几何间隔 γ⁽ⁱ⁾ y⁽ⁱ⁾(θᵀx⁽ⁱ⁾ b)/‖θ‖它表示点到超平面的带符号距离把 θ 缩放不改变超平面所以可以约定最近的样本满足 y⁽ⁱ⁾(θᵀx⁽ⁱ⁾ b) 1优化目标就写成 min ½‖θ‖²约束是所有样本的函数间隔不小于 1。这是一个凸二次规划讲义接着上拉格朗日乘子把带约束问题转成对偶问题。对偶形式是 max Σαᵢ − ½ΣΣ y⁽ⁱ⁾y⁽ʲ⁾αᵢαⱼ⟨x⁽ⁱ⁾, x⁽ʲ⁾⟩约束为 αᵢ ≥ 0 且 Σαᵢy⁽ⁱ⁾ 0。KKT 条件给出一个关键性质只有 αᵢ 0 的样本才出现在 w 的展开式里这些点就是支持向量其余样本删掉不影响模型。预测式随之变成 Σαᵢy⁽ⁱ⁾⟨x⁽ⁱ⁾, x⟩ b整个表达式里只剩内积。这一步是整个课程里最重要的结构转换。一旦发现预测只依赖内积就等于拿到了核化的门票把 ⟨x, z⟩ 整体替换成 K(x, z)模型在隐式的高维空间里工作而计算量不跟着维度走。之后的支持向量机、以及后来的核岭回归、核 PCA全都建立在这个观察上。3.3 核技巧与软间隔把内积换掉就够了核函数定义为 K(x, z) ⟨φ(x), φ(z)⟩φ 是某个从原空间到高维空间的映射。它的合理性不需要显式构造 φ 来验证只要核矩阵对所有样本都半正定Mercer 条件就一定存在对应的内积空间。这一条在作业里偶尔以证明题出现判断一个函数是不是合法核做法就是验证核矩阵半正定。核函数形式关键参数适用场景线性核⟨x, z⟩无特征维度远大于样本数多项式核(⟨x,z⟩ c)^dd 阶数、c 常数特征交互明显、d 不大高斯 RBFexp(−‖x−z‖² / 2σ²)σ 或 γ 1/2σ²边界弯曲、样本量中等软间隔是另一处必考内容原始问题太硬一个噪声点就能让问题无解于是给每个样本加松弛变量 ξᵢ目标改成 min ½‖θ‖² CΣξᵢ。C 控制惩罚力度C 很大接近硬间隔偏差低方差高C 小则容忍更多越界偏差高方差低。RBF 核的 γ 跟 C 是同一类旋钮γ 大单个样本影响半径小边界绕着点转过拟合γ 小边界接近线性。作业里调参翻车最多的就是这两个参数一起乱试正确做法是先固定一个粗扫另一个。def svm_predict(X_test, X_sv, y_sv, alpha_sv, b, kernel): # 只需保存支持向量非支持向量对预测没有任何贡献 K kernel(X_test, X_sv) # (m_test, n_sv) return np.sign(K (alpha_sv * y_sv) b) # 实践中 alpha 用容差判断浮点解很少精确为 0 # support_mask alpha 1e-6这段代码说明一件容易被忽略的事核化之后预测成本正比于支持向量的数量而不是特征维度。所以「样本量十万级、特征几千维」的场景下 RBF 核会明显变慢线性核或者线性模型往往更划算——不是效果更好的问题是能不能跑完的问题。4. 泛化、隐变量与决策偏差方差、EM/PCA 与 MDP前三章是「有标签、有监督」的世界这一章的三块内容彼此独立考题形式也差别很大但它们在复习时经常被压到最后、草草翻过结果是考试里最稳能拿的分反而丢了。4.1 偏差-方差与泛化界诊断比调参重要把期望测试误差分解会得到「不可约噪声 偏差² 方差」三项。偏差衡量模型族的表达能力够不够方差衡量它对训练集扰动的敏感程度。这个分解的价值在于它给出了一张诊断表训练误差和测试误差都高是高偏差加数据没用应该加特征或者换更复杂的模型训练误差很低但测试误差高是高方差加数据有用或者加正则、减特征。学习曲线就是把这条判断可视化的工具——横轴样本量纵轴误差两条曲线收敛在一起且都高说明欠拟合中间留一条大缝说明过拟合。提示拿到一个效果不好的模型先画学习曲线再动手改比直接调超参省时间得多。这条经验在后面所有模型上都适用。理论部分的核心是有限假设类的一致收敛界对大小为 k 的有限假设类以 1−δ 的概率所有假设的经验误差与真实误差之差不超过 sqrt(log(2k/δ) / 2m)。它把「训练误差低能不能推出泛化误差低」量化成一个样本量公式。无限假设类则用 VC 维替换 log kd 维空间里的线性分类器 VC 维是 d1这个结论要能说清直觉d1 个点可以被线性分类器打散d2 个点不行。样本复杂度大致是 m O((d log(1/δ))/ε)它解释了一个常被忽视的现象——参数越多需要的样本越多而且是对数级的「够用」而不是线性的「充裕」。4.2 EM 与 PCA隐变量和降维EM 处理的是含隐变量的最大似然。直接优化对数似然 log Σ_z P(x,z;θ) 时对数里面有求和梯度很难处理。EM 的做法是构造一个下界用当前参数 θ_t 计算隐变量的后验把 log P(x,z;θ) 在这个后验下求期望得到 Q(θ|θ_t)然后最大化它。E 步算后验也就是责任度M 步更新参数两步交替对数似然单调不减。单调性可以严格证明来自 Jensen 不等式但「单调不减」不等于「收敛到全局最优」——这是最容易误读的一处。EM 只保证收敛到局部极值或鞍点结果高度依赖初始化高斯混合模型里如果某个分量的均值初始化和另一个重合那个分量会永远分不到责任度方差越缩越小最后退化成一个尖峰。工程上的补法是多次随机初始化取最优或者用 k-means 的结果做初值。PCA 的思路完全不同不建模概率直接找方差最大的方向。步骤固定——中心化、算协方差矩阵、特征分解、取前 k 个特征向量做投影。方差解释率就是前 k 个特征值之和除以总和它是选 k 最直接的依据。这里最常漏的一步是中心化不减去均值第一主成分会被数据整体的偏移方向带偏得到的方向没有意义。import numpy as np def pca(X, k): Xc X - X.mean(axis0) # 必须中心化否则第一主成分被均值方向污染 C Xc.T Xc / (Xc.shape[0] - 1) # 协方差矩阵形状 (n, n) w, V np.linalg.eigh(C) # 实对称矩阵用 eigh结果升序且数值稳定 idx np.argsort(w)[::-1][:k] # 取最大的 k 个特征值 return Xc V[:, idx], w[idx] / w.sum() # 返回投影坐标与各主成分方差占比输出两个东西投影后的低维表示以及每个主成分解释了多少方差。实践中如果前两三个主成分加起来不到 60%说明数据本身没有明显的低维结构强行降维会丢信息。PCA 和白化是两件事白化在此之上还要把每个方向除以特征值的平方根让各维方差都变成 1讲义里通常作为独立小节出现。4.3 MDP 与强化学习值函数是唯一的主线强化学习部分把问题换成五元组 (S, A, P, γ, R)状态、动作、转移概率、折扣因子、奖励。策略 π 是从状态到动作的映射值函数 V^π(s) 是从 s 出发按 π 行动的期望折扣回报。整个理论建立在 Bellman 等式上V^π(s) Σ_a π(a|s) Σ_{s} P(s|s,a)[R(s,a,s) γV^π(s)]最优值函数则把求和换成取最大。模型已知时值迭代和策略迭代是两条标准解法。值迭代反复套用最优 Bellman 算子直到收敛策略迭代则在「评估当前策略」和「贪心改进」之间交替通常迭代次数更少但每轮更贵。模型未知时用 Q-learning靠采样更新 Q(s,a) ← Q(s,a) α[r γ max_{a} Q(s,a) − Q(s,a)]方括号里那项叫 TD 误差。连续状态或者连续动作的场景讲义接着引出 LQR 和策略梯度策略梯度的核心式子只有一行∇J E[∇log π(a|s) · R]把「让高回报的动作概率变大」写成了可采样的形式。import numpy as np def value_iteration(T, R, gamma0.99, tol1e-8): # T: (n_states, n_actions, n_states) 转移概率 R: (n_states, n_actions) 即时奖励 V np.zeros(T.shape[0]) while True: Q R gamma * T V # 对每个 (s, a) 算期望回报T V 得到 (n_states, n_actions) V_new Q.max(axis1) # 最优 Bellman 算子的 max 部分 if np.max(np.abs(V_new - V)) tol: return V_new V V_new代码里最需要注意形状T V那一行把三维张量按最后一维和向量做缩并得到的是每个状态-动作对的期望后继价值。收敛判据用最大变化量而不是迭代次数因为不同问题的收敛速度差几个数量级。写作业时如果结果发散先查 γ 是不是大于等于 1再查奖励是不是漏了折扣。5. 五个高频翻车点假设层面、数值层面与诊断层面这一章列的是复习时最容易被「我已经懂了」这句话盖过去的地方。每一条都按同一个格式写错在哪、为什么会漏、怎么补。5.1 假设层面的两个反向记忆易漏点一把 GDA 和逻辑回归的假设强度记反。很多人下意识觉得「逻辑回归更简单所以假设更强」实际正好相反GDA 假定了 x|y 是高斯的且共享协方差假设更强逻辑回归只假定了 sigmoid 形式更弱。为什么漏两个模型最终都能写成同一条 sigmoid 边界看上去是同一种东西差别藏在「数据从哪来」这一层平时只调包不看假设的人根本不会碰到这个问题。怎么补记结论时绑定适用条件一起记——「数据少、大概符合高斯 → 用 GDA不确定、要稳 → 用逻辑回归」并在纸上写一遍「GDA 蕴含 LRLR 不蕴含 GDA」的推导方向。易漏点二把 EM 的单调性读成全局最优。「对数似然单调不减」只在说每一步不会变差没说最后到的是全局最大。为什么漏课本上的图大多是一条漂亮的上升曲线容易让人以为曲线终点就是最高点。怎么补记住 EM 是局部方法工程上必须配多次随机初始化混合高斯时要专门检查有没有分量退化方差趋近 0那通常就是初始化撞上了。5.2 实现层面的两个数值陷阱易漏点三正则化把截距项一起罚了且没有先标准化。对 θ₀ 加惩罚会让模型强行穿过原点附近数据整体偏移越大偏得越狠没标准化就对全部特征用同一个 λ量纲大的特征被压得几乎失效。为什么漏绝大多数库默认已经处理好了自己手写目标函数时才会暴露而作业恰好需要手写。怎么补正则项写成 θ[1:] 而不是 θ标准化放在划分训练测试集之后、只在训练集上算均值和方差再套用到测试集顺序错了会引入轻微的数据泄漏。易漏点四核化之后仍然按特征维度估复杂度。用 RBF 核的 SVM预测成本正比于支持向量数量和特征维度无关反过来特征维度几千、样本几万时线性核常常又快又准。为什么漏课堂上讲核技巧时强调的是「可以隐式映射到无限维」听起来全是好处成本那一面被略过了。怎么补记住一条选择顺序——特征维度远大于样本量先试线性核样本量中等、边界明显弯曲再上 RBF两个超参 C 和 γ 不要同时乱扫先固定 γ 粗扫 C再细调。5.3 诊断层面的一个方向错误易漏点五学习曲线读反用加数据去治高偏差。训练误差和测试误差都高、且两条线已经贴在一起是高偏差此时加数据几乎不会改善只有中间留一条大缝才是高方差加数据才有效。为什么漏多数人的第一反应是「效果不好就多标点数据」这个直觉在深度学习时代被反复强化但在小模型、特征不足的场景里是纯粹浪费。怎么补固定一个流程——先画学习曲线两条线贴合就加特征或换更复杂的模型留缝就加数据或加正则把这个判断写成清单每次调参前先过一遍。6. 复习清单用三张表把整门课过一遍复习到后期最有效的动作不是再刷一遍讲义而是做一次「合上书的自检」。我的做法是准备三张表一张列模块和它依赖的前置知识一张列每个模块必须能白纸推出来的式子一张列作业里错过的题和错因。三张表填不满的地方就是真正要回头补的地方。模块必须能独立推出的式子卡住时回看线性/逻辑回归梯度、正规方程、Hessian2.1、2.2GLM三个分布的自然参数与 a(η)2.3GDA / 朴素贝叶斯参数估计、决策边界为何线性3.1SVM对偶形式、KKT、预测式3.2、3.3学习理论偏差方差分解、一致收敛界4.1EM / PCAE 步 M 步、方差解释率4.2MDPBellman 最优方程、Q-learning 更新4.3第二张表我习惯按「能不能在 15 分钟内写完」来标记写完的划掉写不出来的标红第二天只看标红的。第三张表更关键作业讲解里那些「这里其实还有一种情况」的批注往往就是考试的发散点抄一遍比自己重新想一遍省时间。还有一个具体技巧值得单独拎出来把每一章的代码改成「故意写错」的版本然后观察它会怎么坏。比如把 PCA 的中心化那行删掉看第一主成分指向哪里把逻辑回归的牛顿法去掉岭项在完全可分的数据上看 θ 怎么发散把值迭代的 γ 改成 1.0看回报还收不收敛。这种反向实验比正向跑通一遍记得牢得多因为它把「参数为什么这么设」变成了一个看得见的后果而不是一句注释。血泪经验是我曾经把「看懂推导」当成「掌握」结果一到限时手推就卡在中间某一步回头翻笔记才发现自己从来没独立写过完整链条。从那以后我每次复习这块内容都强制走一遍「合上书 → 白纸推 → 对照讲义找断点」的流程哪怕只推一条链。希望帮到你。本文还有配套的精品资源点击获取