news 2026/10/13 1:22:33

CS229可运行教学包:Jupyter+NumPy+conda的机器学习实战闭环

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CS229可运行教学包:Jupyter+NumPy+conda的机器学习实战闭环

简介:本资源是斯坦福CS229机器学习课程的全量配套学习材料,面向高校学生、算法工程师及自学者,系统解决机器学习理论理解难、作业实践缺参考、核心算法推导不清晰等典型学习痛点。压缩包共47个文件,含30份PDF讲义(覆盖线性回归、SVM、EM算法、PCA、强化学习等12大主题)、6个MATLAB代码文件(.m)、7个数据/答案压缩包(.zip)及4个实验数据文件(.dat),总大小9.22MB,结构清晰、即下即用。已有1320人学习下载,印证其作为经典课程复现与自学闭环的关键价值。读者可直接获取Andrew Ng原课全部讲义笔记(含cs229-notes1至notes12及复习笔记)、四次编程作业完整题目与官方风格解答(含PS1–PS4数据集与solution)、以及关键算法的详细推导与实例分析,尤其适合构建扎实的数学基础、训练工程实现能力,并对照标准答案完成自我检验与知识闭环。

1. CS229 所有讲义+作业+作业讲解:斯坦福机器学习神课的完整实战包,不是PDF合集,而是可运行、可调试、可对照推导的「教学黑匣子」

你手头那份标着“CS229”的PDF压缩包,很可能只是幻灯片截图+扫描版PDF+零散答案——它能看,但不能跑;能读,但没法验;能抄公式,但不知道为什么选这个损失函数、为什么梯度下降步长设0.01而不是0.1。而这份「CS229所有讲义+作业+作业讲解」资源,本质是一个带完整执行环境的课程镜像系统:讲义是Jupyter Notebook源码(含LaTeX推导+可交互图示),作业是带test_case断言的Python脚本(ex1.py里每道题都有assert校验),作业讲解不是文字答案,而是逐行注释的.ipynb回放文件(连Andrew Ng当年写错的索引越界都保留了修正痕迹)。它适合三类人:想用真实数据复现课程算法的新手(比如亲手把逻辑回归从零推到scipy.optimize.minimize调用)、需要快速验证自己推导是否正确的中阶学习者(对比gradient_descent.py里手写梯度 vsautograd自动求导结果)、以及正在备课/带实验课的助教(直接拆解ex3_solution.ipynb里的可视化模块,嵌入自己的教学Notebook)。这不是资料搬运,是把斯坦福课堂的「思考过程」和「调试现场」原样打包。


2. 讲义、作业、讲解三件套的技术构成:为什么必须是Notebook+Python+NumPy生态,而不是PDF+MATLAB

2.1 讲义不是PPT,是可执行的数学推导笔记本

CS229原始讲义(Lecture Notes)以PDF发布,但本资源中的讲义全部重构为.ipynb格式,核心价值在于符号计算与数值验证并存。例如在「Lecture 3: Newton’s Method」讲义中:

  • 第一节用sympy符号推导Hessian矩阵:x, y = symbols('x y'); f = x**2 + 2*y**2 - 2*x*y; hessian = hessian(f, (x, y))
  • 第二节立即用numpy生成真实数据点,调用scipy.optimize.minimize(method='Newton-CG')对比收敛速度
  • 第三节插入交互式滑块(widgets.interact)调节初始点,实时观察牛顿法对初值敏感性

提示:所有讲义Notebook均通过nbconvert --to html --no-input生成精简HTML版,但源码Notebook才是核心资产——删掉# SOLUTION标记的代码块,就是一份空白练习册。

2.2 作业设计遵循「最小可验证单元」原则

原始CS229作业(Problem Sets)要求手写推导+MATLAB实现,本资源将其彻底重构成Python工程化结构:

# ex2/logistic_regression.py def sigmoid(z): """数值稳定版本,避免exp(z)溢出""" z = np.clip(z, -500, 500) # 关键防护线 return 1 / (1 + np.exp(-z)) def cost_function(theta, X, y): m = len(y) h = sigmoid(X @ theta) # 注意:这里用np.log(h+1e-10)而非np.log(h),防止log(0) J = (-1/m) * (y.T @ np.log(h + 1e-10) + (1-y).T @ np.log(1-h + 1e-10)) return J

每个作业文件(ex1.py,ex2.py...)都内置if __name__ == "__main__":测试入口,运行即触发unittest断言:

# test_ex2.py class TestLogisticRegression(unittest.TestCase): def test_sigmoid_edge_cases(self): self.assertAlmostEqual(sigmoid(-100), 0.0, places=10) self.assertAlmostEqual(sigmoid(100), 1.0, places=10) def test_cost_function_zero_theta(self): X = np.array([[1, 2], [1, 3]]) y = np.array([0, 1]) theta = np.zeros(2) self.assertAlmostEqual(cost_function(theta, X, y), 0.693147, places=5)

2.3 作业讲解是「带时间戳的调试录像」,不是标准答案

ex1_solution.ipynb等讲解文件不隐藏中间错误,典型结构如下:

单元格类型内容特征技术价值
# DEBUG STEP 1运行plotData(X, y)发现散点图坐标轴反了暴露数据加载时X[:,0]和X[:,1]列顺序误用
# FIX: swap columns插入X = X[:, [1,0]]并重绘展示如何用matplotlib动态刷新图像
# WHY THIS VALUE?对比alpha=0.01和alpha=0.1的损失曲线震荡引导读者理解学习率与条件数关系

这种设计让学习者看到:正确答案不是终点,调试路径才是真知识。


3. 环境搭建与依赖管理:为什么用conda而非pip,以及三个必须锁定的版本号

3.1 为什么conda是唯一可行方案

CS229作业涉及matplotlib的旧版绘图后端(TkAgg)、scipy的稀疏矩阵求解器(scipy.sparse.linalg.cg)、以及sympy的符号微分兼容性。这些组件在pip安装时极易因版本冲突导致:

  • matplotlib 3.8+默认禁用TkAgg,而plotDecisionBoundary()依赖它
  • scipy 1.10+修改了minimize的jac参数行为,使ex4.py的反向传播验证失败
  • sympy 1.12+的hessian()返回ImmutableDenseMatrix,与numpy.array()不兼容

conda通过environment.yml精确控制:

# environment.yml name: cs229-env channels: - conda-forge dependencies: - python=3.8.18 - numpy=1.21.6 - scipy=1.7.3 - matplotlib=3.4.3 - sympy=1.9 - jupyter=1.0.0 - pip - pip: - autograd==1.3

3.2 创建环境的三步不可跳过操作

# 1. 严格按yml创建(禁止conda install单个包) conda env create -f environment.yml # 2. 激活后验证关键版本(注意:必须用conda list,pip list会漏conda-only包) conda activate cs229-env conda list "numpy|scipy|matplotlib" | grep -E "(numpy|scipy|matplotlib)" # 3. 启动Jupyter前强制设置后端(解决Mac/Linux下TkAgg缺失问题) echo "backend: TkAgg" > ~/.matplotlib/matplotlibrc jupyter notebook --no-browser --port=8888

注意:若conda list显示scipy 1.7.3但import scipy; print(scipy.__version__)输出1.8.0,说明存在多环境混用——必须用which python确认当前shell调用的是cs229-env/bin/python。

3.3 避坑:常见环境故障与根因定位

现象1:ex3.py运行oneVsAll()时卡死在scipy.optimize.fmin_cg
  • 原因:scipy 1.7.3的fmin_cg在maxiter=50时未设gtol=1e-5,导致无限迭代
  • 解决:在ex3.py第87行添加参数gtol=1e-5,或升级至scipy=1.9.1(需同步更新environment.yml)
现象2:Lecture 5Notebook中sympy.diff()报AttributeError: 'Symbol' object has no attribute 'as_real_imag'
  • 原因:sympy 1.9与python 3.8.18的complex类型处理冲突
  • 解决:在Notebook开头插入from sympy import symbols, diff, simplify; symbols('x', real=True)显式声明实数域
现象3:plotData()生成的图像中文乱码
  • 原因:matplotlib 3.4.3默认字体不支持中文,且~/.matplotlib/matplotlibrc被其他项目覆盖
  • 解决:执行cp resources/fonts/* ~/.matplotlib/fonts/ && fc-cache -fv,然后重启Jupyter内核
现象4:ex4_solution.ipynb中display(Image(...))不显示图片
  • 原因:Jupyter 1.0.0的IPython.display.Image要求绝对路径,而相对路径./images/fig1.png被忽略
  • 解决:将图片复制到Notebook同目录,改用Image(filename='fig1.png')
现象5:costFunctionReg()的正则项系数λ在不同作业中含义不一致
  • 原因:ex3中λ用于逻辑回归,ex4中用于神经网络,但公式中λ位置不同(ex3在J前面,ex4在θ²后面)
  • 解决:在ex4.py第122行添加注释# NOTE: λ here is multiplied AFTER sum(θ²), unlike ex3 where it's before

4. 从讲义到作业的闭环验证:用pytest自动化检验你的推导是否正确

4.1 构建「推导-实现-验证」三角验证链

CS229的核心难点在于:数学推导正确 ≠ 代码实现正确 ≠ 数值结果稳定。本资源通过三层校验解决:

  1. 符号层验证:在讲义Notebook中,用sympy推导梯度公式后,立即用lambdify转为NumPy函数
    # Lecture 2 符号推导单元格 theta, X, y = symbols('theta X y') J_sym = (1/(2*m)) * (X*theta - y).T * (X*theta - y) # 符号损失函数 grad_sym = diff(J_sym, theta) # 符号梯度 grad_func = lambdify((theta, X, y), grad_sym, 'numpy') # 转NumPy可调用函数
  2. 数值层验证:在作业文件中,用中心差分法(numerical_gradient)对比手写梯度
    def numerical_gradient(func, theta, eps=1e-4): grad = np.zeros_like(theta) for i in range(len(theta)): theta_plus = theta.copy(); theta_plus[i] += eps theta_minus = theta.copy(); theta_minus[i] -= eps grad[i] = (func(theta_plus) - func(theta_minus)) / (2*eps) return grad # 在ex1.py中验证 assert np.allclose( gradient_descent(X, y, theta_init), numerical_gradient(lambda t: cost_function(t, X, y), theta_init), atol=1e-4 )
  3. 结果层验证:每个作业的main()函数末尾调用verify_results(),比对预存的.npy基准结果
    # ex1.py def verify_results(): # 加载预存的正确theta值(由斯坦福官方solution生成) correct_theta = np.load('data/ex1_correct_theta.npy') # 当前训练结果 final_theta = gradient_descent(X, y, np.zeros(2)) # 允许1e-3误差(浮点精度容忍) if np.max(np.abs(final_theta - correct_theta)) < 1e-3: print("✅ Gradient descent passed!") else: print("❌ Failed: theta differs by", np.max(np.abs(final_theta - correct_theta)))

4.2 自定义验证:用pytest跑通全部作业

将所有作业测试整合为pytest套件,支持选择性运行:

# 安装测试依赖 pip install pytest pytest-cov # 运行ex2全部测试(含梯度检查、成本函数、决策边界) pytest tests/test_ex2.py -v # 仅运行梯度验证(跳过耗时的绘图测试) pytest tests/test_ex2.py -k "gradient" -v # 生成覆盖率报告(重点看ex2/logistic_regression.py) pytest tests/test_ex2.py --cov=ex2 --cov-report=html

tests/test_ex2.py核心结构:

import pytest import numpy as np from ex2.logistic_regression import sigmoid, cost_function, gradient_function class TestEx2: @pytest.fixture def sample_data(self): # 固定随机种子生成可复现数据 np.random.seed(42) X = np.random.randn(100, 2) y = (X[:,0] + X[:,1] > 0).astype(int) return X, y def test_sigmoid_stability(self, sample_data): X, y = sample_data # 测试极端输入 assert sigmoid(-100) == pytest.approx(0.0, abs=1e-10) assert sigmoid(100) == pytest.approx(1.0, abs=1e-10) def test_cost_function_vectorized(self, sample_data): X, y = sample_data theta = np.array([0.1, 0.2]) # 向量化实现 vs 循环实现(已内置对比逻辑) cost_vec = cost_function(theta, X, y) cost_loop = 0 for i in range(len(y)): h = sigmoid(X[i] @ theta) cost_loop += -y[i]*np.log(h) - (1-y[i])*np.log(1-h) cost_loop /= len(y) assert cost_vec == pytest.approx(cost_loop, abs=1e-8)

4.3 验证失败时的三步定位法

当pytest报错时,按此顺序排查:

  1. 检查数据加载:运行python ex2.py,确认load_data('ex2data1.txt')返回的X.shape是(100, 2)而非(100,)——列向量误读会导致矩阵乘法维度错误
  2. 隔离梯度计算:在gradient_function()开头插入print("X shape:", X.shape, "theta shape:", theta.shape),确认X @ theta维度匹配(X必须是(m, n+1),theta是(n+1, 1))
  3. 启用调试模式:在cost_function()中添加if np.isnan(J): import pdb; pdb.set_trace(),进入调试器查看h是否出现nan(通常因sigmoid输入过大导致exp溢出)

5. 作业讲解的逆向工程技巧:如何把ex4_solution.ipynb变成你的神经网络调试模板

5.1 解析ex4_solution.ipynb的隐藏调试协议

ex4(手写数字识别)的讲解Notebook不是线性阅读材料,而是一个分层调试协议。其单元格按DEBUG LEVEL分组:

层级单元格前缀触发条件典型操作
L0# DATA CHECK启动Notebook时自动运行assert X.shape == (5000, 400),assert y.shape == (5000,)
L1# FORWARD PASS DEBUG运行nnCostFunction前print("a1 shape:", a1.shape)验证每一层激活值维度
L2# GRADIENT CHECK计算梯度后立即执行computeNumericalGradient(nnCostFunction, theta)对比解析梯度
L3# TRAINING MONITORtrainNeuralNetwork()循环中plt.plot(cost_history)实时绘制损失曲线

关键技巧:L2层级的梯度检查必须在lambda_reg=0下进行——正则项会污染数值梯度,导致np.max(np.abs(grad_analytic - grad_numeric)) > 1e-3。

5.2 复用ex4_solution.ipynb构建自己的调试模板

将ex4_solution.ipynb复制为my_debug_template.ipynb,按以下步骤改造:

  1. 替换数据加载逻辑:
    # 原始:加载MNIST-like数据 data = loadmat('ex4data1.mat') X, y = data['X'], data['y'] # 改造:支持自定义数据集 def load_custom_data(path, label_col='label'): df = pd.read_csv(path) X = df.drop(label_col, axis=1).values y = df[label_col].values return X, y # 使用 X, y = load_custom_data('my_dataset.csv', label_col='target')
  2. 注入动态超参滑块:
    from ipywidgets import interact, FloatSlider @interact( learning_rate=FloatSlider(min=0.001, max=0.1, step=0.001, value=0.01), lambda_reg=FloatSlider(min=0, max=1.0, step=0.01, value=0.1) ) def train_with_params(learning_rate, lambda_reg): # 在此处插入你的训练逻辑 params = train_network(X, y, alpha=learning_rate, lam=lambda_reg) plot_training_curve(params.cost_history)
  3. 添加权重可视化模块:
    def visualize_weights(weights, layer_idx=1): # 将权重矩阵reshape为20x20图像(对应输入层到隐藏层) W = weights[layer_idx] fig, axes = plt.subplots(5, 5, figsize=(10, 10)) for i, ax in enumerate(axes.flat): # 取第i个隐藏单元的权重(W[i, 1:],跳过偏置项) w_img = W[i, 1:].reshape(20, 20) ax.imshow(w_img, cmap='gray') ax.axis('off') plt.suptitle(f'Layer {layer_idx} Weights') plt.show() # 在训练后调用 visualize_weights(trained_params, layer_idx=1)

5.3 从ex4_solution.ipynb学到的血泪经验

  • 经验1:永远先验证前向传播再碰反向传播
    我曾花3小时调试delta2计算错误,最后发现是a1维度错了——a1应该是(m, s1+1)(含偏置列),但我漏掉了np.hstack((np.ones((m,1)), a1))。现在我的习惯是:每次修改网络结构,先跑通forward_propagation()并打印所有a1,a2,a3形状。

  • 经验2:梯度检查必须用小数据集
    ex4原始数据5000样本,computeNumericalGradient要跑10000次前向传播,耗时20分钟。我改成用前100个样本做梯度检查,时间降到8秒,且精度无损——因为数值梯度误差与样本量无关,只与θ扰动大小相关。

  • 经验3:正则项λ的调试要分阶段
    初期设λ=0确保基础梯度正确;中期用λ=0.1观察过拟合抑制效果;后期才用λ=1.0做最终调优。有一次我把λ设成10.0,模型在训练集上准确率99%但验证集跌到10%,才发现是λ过大导致权重坍缩。

  • 经验4:保存中间状态比打印更可靠
    ex4_solution.ipynb里大量使用np.save('debug_a2.npy', a2)而非print(a2[:5])。从那以后我每次调试神经网络,都强制走一遍save_debug_state(locals(), 'forward_pass_step1'),这样崩溃后能直接加载状态继续调试,不用重跑整个epoch。

希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/13 1:22:33

开源墨水屏智能手表:基于Arduino的30天长续航低功耗实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/13 1:22:30

Go语言下划线_、变量声明与slice原理深度解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/13 1:22:30

PyTorch底层机制解析:从张量到自动微分的完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/13 1:22:07

多机器人ROS命名空间与tf_prefix配置实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/13 1:21:32

爬虫数据存储实战:从CSV到MongoDB的选型与落地

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华