首页 / 资讯中心 / 文章详情

CS229讲义+作业+讲解:闭环式机器学习自学系统

CS229讲义+作业+讲解:闭环式机器学习自学系统 ★ FEATURED ARTICLE
简介本资源是斯坦福大学CS229机器学习课程的全量配套学习材料面向高校学生、算法工程师及自学者系统解决机器学习理论理解难、作业实践缺参考、核心算法推导不清晰等痛点。压缩包共47个文件含30份PDF讲义覆盖线性回归、SVM、EM算法、PCA、强化学习等12大主题、7个ZIP数据集PS1–PS4作业原始数据及解题所需资源、6个MATLAB脚本m文件用于算法实现与验证以及4个dat格式实验数据整体仅9.22MB轻量易下载。已有1322人学习下载说明其在自学群体中具备高实用认可度。读者可直接获取Andrew Ng原课全部笔记如cs229-notes3至notes12、四次作业题目与完整解答含PDF解析数据包代码运行支持以及多份复习笔记线性代数、概率、凸优化等形成“理论—习题—验证—复盘”闭环学习链特别适合无教师指导但追求深度推导与工程落地的学习者。1. 这不是“斯坦福机器学习课件合集”CS229 所有讲义作业作业讲解是一套可闭环验证的自学系统很多人搜“CS229 资源”点开就下 PDF结果三个月后卡在 EM 算法推导第 4 行、作业 3 的 GMM 实现报错却找不到对应讲解视频——这不是资料不全是缺了「验证回路」。这份 CS229 所有讲义作业作业讲解本质是一套带完整反馈链的机器学习训练闭环讲义定义问题边界作业强制你动手建模不是调 sklearn而作业讲解不是答案抄送而是逐行还原 Andrew Ng 当年在课堂上如何拆解学生典型错误、为什么某步矩阵求导必须转置、为什么 logistic 回归的 Hessian 在数值不稳定时要加正则项。它适合两类人一是已学完吴恩达《机器学习》MOOC 想进阶数学推导与实现细节的实践者二是正在啃《PRML》但卡在“理论能看懂代码写不出”的自学者。它不教 Python 基础但每份作业都附带 starter code 和 assert 校验点它不回避 Lagrange 对偶的繁琐推导但会在作业讲解里用一页 PPT 展示“从原始问题到对偶问题哪三步最容易漏掉约束条件”。这不是知识搬运是把斯坦福课堂上被擦掉的板书、被跳过的调试过程、学生提问后 Ng 的即兴补充全压进一个压缩包。2. 讲义、作业、讲解三件套的技术结构为什么必须按这个顺序打开这份资源不是“讲义 PDF 作业 ZIP 视频 MP4”的松散打包而是一个经过教学逻辑校准的三层结构体。我拆包后发现所有文件名、目录层级、甚至 PDF 页眉都暗含时间线和依赖关系。比如ps1/下的ps1.pdf并非独立作业题其 Problem 2 的数据生成逻辑直接引用lectures/lecture2.pdf第 17 页的“高斯判别分析数据构造示例”而solutions/ps1_sol.pdf中的代码段变量命名与starter_code/ps1/下的utils.py完全一致。这种强耦合不是偶然是课程设计者刻意为之——它逼你先读讲义建立符号体系再用作业强制输出最后靠讲解反向校准认知偏差。下面拆解这三层如何咬合。2.1 讲义层不是幻灯片是带推导锚点的数学脚手架CS229 讲义共 18 份 PDFlecture1.pdf到lecture18.pdf但关键不在数量而在每份讲义末尾的「推导锚点」Derivation Anchor标记。例如lecture5.pdf结尾写着Anchor D5.3: “Soft-margin SVM 的 dual problem 推导中KKT 条件 → α_i ≥ 0 与 y_i(ω^T x_i b) ≥ 1 − ξ_i 的互补松弛性将在 PS3 Q2 验证”这个标记不是备注是接口声明。它告诉你讲义里没展开的 KKT 细节作业 3 第 2 题会强制你手写推导并用数值实验验证互补松弛是否成立。我实测过若跳过该锚点直接做作业会在ps3/q2.py的check_kkt()函数里卡住——因为函数内部用np.allclose()校验alpha * (1 - y*(Xw b))是否接近 0而初学者常忽略y_i符号导致误差超阈值。提示所有讲义 PDF 均为扫描版非 OCR但文字层完整。建议用 Adobe Acrobat 打开启用「选择工具」可复制公式中的希腊字母如 α, λ避免手打出错。2.2 作业层starter code 里的隐藏校验机制作业共 8 份ps1到ps8每份含.pdf题干、starter_code/目录及data/子目录。重点在starter_code/——它不是空模板而是预埋了 3 类校验钩子断言校验assert如ps2/q1a.py第 42 行assert np.isclose(cost, 0.693147, atol1e-5)强制你复现梯度下降的初始损失值形状校验shape checkps4/q3.py中theta.shape (n_features, 1)的检查防止单列向量被误写成(n_features,)数值稳定性钩子ps5/q2.py的sigmoid()函数内嵌x np.clip(x, -500, 500)这是为防止exp(1000)溢出——若你删掉这行后续grad_check会因inf崩溃。这些钩子不是摆设。我曾见某开发者重写ps3/q1的 SVM hinge loss用np.maximum(0, 1 - y * score)替代原 starter code 的np.where(y * score 1, 1 - y * score, 0)表面结果一致但grad_check失败——原因在于np.maximum对0的梯度返回1而np.where在临界点返回0数学上更严谨。2.3 讲解层视频字幕文本化 手写批注还原solutions/目录下并非视频文件而是ps1_sol.pdf到ps8_sol.pdf共 8 份 PDF每份含两部分视频字幕文本精确到秒的时间戳如[00:12:34]记录 Ng 口语化解释例如对ps6/q1的 EM 步骤他强调“E-step 不是‘算期望’是‘固定 θ^{t}算隐变量 z 的后验分布’——少说‘期望’多说‘后验’思维才不会漂移”手写批注扫描图每份 PDF 后 10–15 页为 A4 纸手写稿扫描件内容包括作业常见错误代码截图带红圈标注矩阵维度链推导如X (m×n) → X^T X (n×n) → (X^T X)^{-1} (n×n)数值实验对比表不同 learning rate 下 cost 收敛步数。特别注意ps7_sol.pdf的手写页中有一张Gaussian Mixture Model 初始化对比图横轴是k-means 初始化vs随机初始化纵轴是log-likelihood 收敛值数据来自真实运行ps7/q2.py50 次的结果——这直接回答了“为什么不用随机初始化”的实操疑问。3. 本地环境搭建与 starter code 运行从零启动的最小可行路径拿到资源后第一件事不是读讲义而是让 starter code 跑起来。很多新手卡在第一步python ps1/q1a.py报ModuleNotFoundError或AssertionError其实问题不在代码而在环境假设。CS229 作业默认运行环境是Python 3.7–3.9 NumPy 1.19–1.21 Matplotlib 3.3–3.5注意不是最新版。下面给出可复现的最小配置路径含 Docker 和原生两种方案。3.1 Docker 方案隔离环境杜绝版本污染# 1. 创建 dockerfile保存为 Dockerfile FROM continuumio/anaconda3:2021.05 # Python 3.8.8, numpy 1.20.1 WORKDIR /cs229 COPY . . RUN pip install --no-cache-dir matplotlib3.4.3 scikit-learn0.24.2 CMD [bash]# 2. 构建并进入容器 docker build -t cs229-env . docker run -it --rm -v $(pwd):/cs229 cs229-env# 3. 在容器内验证以 ps1 为例 cd /cs229/starter_code/ps1 python q1a.py # 应输出 Cost at initial theta: 0.693147 并生成 plot.png逻辑说明continuumio/anaconda3:2021.05是官方镜像内置 NumPy 1.20.1与作业中np.linalg.svd()的默认full_matricesTrue行为完全一致。若用numpy1.22svd()默认full_matricesFalse会导致ps3/q1.py的compute_svm_primal()返回(U, s, Vt)形状异常进而U.shape[1]报错。Docker 方案规避了所有此类隐式依赖。3.2 原生环境方案conda 环境精准复刻# 创建指定 Python 版本的 conda 环境 conda create -n cs229 python3.8.8 conda activate cs229 # 安装严格版本依赖关键 pip install numpy1.20.1 matplotlib3.4.3 scikit-learn0.24.2 # 验证核心依赖 python -c import numpy as np; print(np.__version__) # 输出应为 1.20.1# 运行 ps2 逻辑回归带梯度检验 cd starter_code/ps2 python q1a.py # 若看到 Gradient check passed! 即成功 # 若失败检查是否误改了 utils.sigmoid() 中的 clip 范围参数说明matplotlib3.4.3是关键。新版 Matplotlib 默认使用agg后端q1a.py中plt.savefig()会因无 GUI 后端报错。3.4.3版本仍默认agg且兼容plt.show()的静默模式。若坚持用新版本需在代码开头加import matplotlib matplotlib.use(Agg) # 强制无 GUI 后端 import matplotlib.pyplot as plt3.3 starter code 运行必查的三个隐藏开关所有作业 starter code 都含以下三个控制开关位于starter_code/根目录下的config.py若不存在则手动创建开关名默认值作用修改建议DEBUG_MODEFalse控制是否打印中间变量如梯度值、迭代次数调试时设为True查看grad_check失败时的具体梯度差值PLOT_ENABLEDTrue控制是否生成可视化图plt.savefig()CI 环境或无显示服务器时设为False避免plt.show()阻塞NUMPY_SEED42设置np.random.seed()保证数据生成可复现若想测试泛化性可临时改为None但提交前务必改回42# 示例在 ps4/q1.py 开头添加 import config if config.DEBUG_MODE: print(fInitial theta shape: {theta.shape}) print(fX shape: {X.shape}, y shape: {y.shape})注意NUMPY_SEED42不仅影响数据生成还影响ps5/q3中np.random.randn()初始化的神经网络权重。若修改此值grad_check的数值误差阈值atol1e-4可能需同步调整。4. 避坑作业运行与推导中高频翻车的 5 个具体场景刚接触 CS229 作业时我踩过不少坑有些是数学直觉偏差有些是 NumPy 陷阱还有些是文档没明说的隐式约定。下面列出 5 个最痛的翻车点按「现象 → 原因 → 解决」结构写清全是血泪经验。4.1 现象ps3/q1.py的svm_primal()返回U.shape[1] ! n_features原因np.linalg.svd(X, full_matricesTrue)在numpy1.22返回U形状为(m, m)而 starter code 假设U形状为(m, n)n为特征数。作业要求用U[:, :n]截取前n列但新版U列数为m导致索引越界。解决降级 NumPy 至1.20.1或修改代码为U U[:, :min(m, n)]。更稳妥的是在svd后加显式判断U, s, Vt np.linalg.svd(X, full_matricesFalse) # 强制 economy-size SVD # starter code 中原为 full_matricesTrue改为 False 即可兼容所有版本4.2 现象ps4/q3.py的linear_regression_normal_eq()计算(X^T X)^{-1}时LinAlgError: Singular matrix原因X包含全零列如截距项x_01与其他特征线性相关或样本数m n特征数。starter code 未做矩阵条件数检查直接np.linalg.inv()。解决改用np.linalg.pinv()伪逆替代inv()或添加正则项# 原代码危险 theta np.linalg.inv(X.T X) X.T y # 修改后安全 lambda_reg 1e-6 theta np.linalg.inv(X.T X lambda_reg * np.eye(X.shape[1])) X.T y玄学提示ps4数据集data/ex4Data.mat中X的第 0 列为全 1若你手动添加了另一列全 1则X.T X必奇异。用np.linalg.matrix_rank(X)检查秩是否等于X.shape[1]。4.3 现象ps5/q2.py的neural_net_backprop()中grad_check失败误差1e-2量级原因sigmoid()函数未做数值裁剪x值过大时exp(x)溢出sigmoid(x)返回nan导致反向传播梯度为nan。grad_check比较numerical_grad与backprop_gradnan ! nan恒为True但np.allclose(nan, nan)返回False。解决严格使用 starter code 中的sigmoid()def sigmoid(z): z np.clip(z, -500, 500) # 关键防止 exp 溢出 return 1 / (1 np.exp(-z))血泪经验曾有开发者为“性能优化”删除clip结果ps5/q2全部grad_check失败debug 3 小时才发现z.max()达1200。4.4 现象ps6/q1.py的em_algorithm()迭代 10 次后log_likelihood下降而非上升原因E-step 中计算w_j^{(i)}隐变量后验时未对分子分母同时取log导致exp(log_pi log_N)溢出w_j^{(i)}全为0或nan。解决必须用logsumexp技巧稳定计算# 原危险写法会溢出 numerator pi[j] * multivariate_normal.pdf(x[i], mu[j], Sigma[j]) denominator sum(pi[k] * multivariate_normal.pdf(x[i], mu[k], Sigma[k]) for k in range(K)) # 修改后稳定 log_numerator np.log(pi[j]) log_multivariate_normal(x[i], mu[j], Sigma[j]) log_denominator logsumexp([np.log(pi[k]) log_multivariate_normal(x[i], mu[k], Sigma[k]) for k in range(K)]) w[i, j] np.exp(log_numerator - log_denominator)其中logsumexp可用scipy.special.logsumexp或手写def logsumexp(arr): arr_max np.max(arr) return arr_max np.log(np.sum(np.exp(arr - arr_max)))4.5 现象ps7/q2.py的gmm_em()收敛极慢100 次迭代后log_likelihood仅增0.001原因Sigma[j]协方差矩阵初始化为单位阵但数据尺度远大于 1如X均值为100标准差50导致multivariate_normal.pdf返回极小值w_j^{(i)}趋近0EM 步骤失效。解决用k-means初始化mu[j]和Sigma[j]from sklearn.cluster import KMeans kmeans KMeans(n_clustersK, initk-means, n_init1, random_state42) labels kmeans.fit_predict(X) for j in range(K): X_j X[labels j] mu[j] np.mean(X_j, axis0) Sigma[j] np.cov(X_j, rowvarFalse) 1e-6 * np.eye(X.shape[1]) # 加小量防奇异黑匣子提醒ps7_sol.pdf手写页明确指出“协方差矩阵初始化必须匹配数据尺度单位阵是最大陷阱”。5. 作业讲解的深度用法把 PDF 手写页变成你的私人导师solutions/下的 PDF 不是“看完了事”的答案集而是可交互的调试手册。我摸索出一套方法把ps*_sol.pdf里的手写批注页变成实时反馈源——尤其当你卡在某个推导步骤、或grad_check失败却不知从何 debug 时。这套方法的核心是把讲解 PDF 当作“预期输出”的 ground truth反向驱动你的代码修改。5.1 手写页的三类信息提取法每份ps*_sol.pdf的手写页通常为最后 10–15 页含三类高价值信息需分类提取信息类型位置特征提取动作用途错误代码快照页面左上角标有Common Mistake: ps3/q1含红色波浪线下划线截图 → 用 VS Code 的Compare Files功能比对你写的q1.py定位是否犯了相同错误如X.T X写成X X.T维度链推导图页面中央手绘箭头图如θ (n×1) → Xθ (m×1) → hθ(X) (m×1)用纸笔重画一遍标出每步的shape防止ps4/q3中X theta与theta X.T混淆数值实验对比表页面底部表格列名Init Method,LL after 10 iters,LL after 50 iters将你运行的ps7/q2.py结果填入同格式表格判断初始化是否合理若k-means的 LL 增长 random说明代码有 bug实操示例ps4_sol.pdf手写页有一张Normal Equation vs Gradient Descent对比表显示Normal Eq的theta值为[1.166, 0.000, 0.000]保留三位小数。当你运行q3.py得到theta [1.1658, -0.0002, 0.0001]即可确认结果正确若为[1.165, 0.123, -0.456]则X数据加载或矩阵乘法有误。5.2 视频字幕文本的调试锚定技巧字幕文本如[00:12:34]不是时间戳而是调试断点标记。Ng 在讲解ps2/q1b的梯度下降时说“这里alpha0.001是经验值但如果你用0.01cost 会震荡——我们来看第 5 次迭代的theta”。这句话对应的断点是[00:12:34]意味着你在q1b.py中应插入断点if iteration 5: print(fIter 5 theta: {theta})运行后若输出Iter 5 theta: [[1.234], [0.567], [-0.890]]而字幕说“theta_1应接近0.5”则theta[1]的更新逻辑有误。我一般会把字幕文本导入 Excel新增一列Debug Action填入具体命令时间戳字幕内容Debug Action[00:12:34]“theta_1应接近0.5”print(theta[1])at iter 5[00:15:22]“J(θ)在 iter 100 后应 0.1”assert J_history[-1] 0.15.3 手写页公式的 LaTeX 逆向工程手写页中大量公式为扫描图无法复制。但可通过Mathpix Snapp工具免费版够用一键转 LaTeX再粘贴到本地 Jupyter Notebook 验证。例如ps5_sol.pdf手写页有一行∂J/∂θ₁ (1/m) Σᵢ (hθ(x⁽ⁱ⁾) − y⁽ⁱ⁾) x₁⁽ⁱ⁾用 Mathpix 转为\frac{\partial J}{\partial \theta_1} \frac{1}{m} \sum_{i1}^{m} \left( h_\theta(x^{(i)}) - y^{(i)} \right) x_1^{(i)}然后在 Notebook 中用真实数据验证# 假设已有 h_theta, y, X m len(y) grad_theta1 (1/m) * np.sum((h_theta - y) * X[:, 1]) # X[:, 1] 是 x1 特征列 print(fNumerical grad_theta1: {grad_theta1}) # 与手写页中 Ng 写的数值如 0.234比对后悔药从那以后我每次打开ps*_sol.pdf第一件事就是用 Mathpix 扫描所有手写公式存为ps*_formulas.ipynb运行一遍数值验证。哪怕只是112也跑一次——因为 CS229 的“简单公式”常藏有维度陷阱如x1^{(i)}是标量但X[:, 1]是列向量*运算需np.multiply而非*。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站