资讯动态

吴恩达机器学习作业Python复现:从梯度下降到正则化实战指南

发布时间:2026/10/16 1:44:53 来源:尧图企业网站定制
简介本资源是面向机器学习初学者与自学者的吴恩达《Machine Learning》课程全周期学习套件覆盖理论理解、编程实践与知识内化三大环节。压缩包共1028个文件总计202.33MB主体包含623个MATLAB/Octave脚本.m、61个Jupyter Notebook.ipynb——含带checkpoint的双版本作业如logistic_regression_v1.ipynb与-checkpoint.ipynb、103个.mat数据文件、44个PDF含合并版作业题、课堂讲义及可打印中文笔记以及配套说明文本与图像素材。已有2534人下载学习印证其在自学路径中的高实用性。读者可直接获取无答案版作业用于独立训练对照有答案三版含分步调试版理解实现逻辑中文笔记系统梳理课程重点与公式推导PDF讲义与题目合集支持离线研读全部文件按章节编号组织如“5- PCA on face data”结构清晰便于循序渐进复现课程全部7大核心实验从线性回归到PCA人脸降维。1. 吴恩达机器学习作业无答案与有答案各一版与个人笔记.zip这不是资源包而是一套可复用的「自学闭环训练系统」你下载过这个压缩包解压后看到ex1/ex2/ex3/一串文件夹里面是.m或.py脚本、data/里的.txt和.mat还有几份 PDF 笔记——但真正卡住你的从来不是“怎么跑通 ex1_linear_reg.m”而是为什么 cost function 改一行参数梯度下降就发散为什么逻辑回归里 sigmoid 输出明明在 (0,1)但predict()却总返回全 0为什么向量化实现比 for 循环快 17 倍但自己手写却更慢这个 ZIP 的价值根本不在“有没有答案”而在于它天然构成一个「输入-执行-反馈-修正」的最小闭环无答案版逼你推导公式、调试维度、理解矩阵乘法的隐式广播有答案版不是抄作业而是做「逆向工程」——把标准解法反拆成每一步的数学动因个人笔记则记录了某开发者在第 3 次重写computeCost()时发现的维度陷阱以及在plotDecisionBoundary()里漏掉hold on导致图像覆盖的真实翻车现场。它适合两类人刚学完微积分和线性代数、想用真实任务验证抽象概念的新手也适合教了三年 ML 课、正为学生总在theta theta - alpha * grad这行卡住而头疼的某高校导师。这不是资料汇编是带血丝的实践切片。2. 从零跑通 ex1用 Python 复现 MATLAB 原版作业绕开 4 类环境兼容性雷区吴恩达原课程作业以 MATLAB/Octave 为主但当前主流开发环境已是 Python。直接pip install matlab不现实必须做等价替换。核心原则是不追求语法镜像而追求计算语义一致。比如size(X, 2)在 MATLAB 中返回列数在 NumPy 中对应X.shape[1]但若X是(m,1)向量MATLAB 默认列向量NumPy 则可能是(m,)一维数组——这里就是第一个坑。2.1 数据加载与格式对齐.txt与.mat的隐式类型陷阱原作业ex1/data/ex1data1.txt是两列浮点数用空格分隔。MATLAB 的load(ex1data1.txt)会自动识别为(m,2)矩阵。Python 中若用np.loadtxt()默认读成 float64但若数据含空行或注释会报ValueError: could not convert string to float。import numpy as np # ✅ 正确做法显式指定分隔符、跳过空行、强制二维 data np.loadtxt(ex1/data/ex1data1.txt, delimiter,, skiprows0).reshape(-1, 2) # 注意原作业数据实际是逗号分隔很多镜像仓库误传为空格导致 shape 错乱 X data[:, 0:1] # 取第一列保持 (m,1) 形状非 (m,) y data[:, 1:2] # 同理避免 y.shape (m,) 导致后续广播错误提示X[:, 0:1]和X[:, 0]行为完全不同。前者返回(m,1)二维数组后者返回(m,)一维数组。在np.dot(X.T, X)中若X是一维X.T仍是(m,)点积结果为标量而非(1,1)矩阵——这会导致后续theta np.linalg.inv(X.T X) X.T y维度不匹配。2.2 梯度下降实现alpha、迭代次数、收敛判断的三重耦合调参原作业ex1/ex1.m中alpha 0.01,iterations 1500是经验值。但在 Python 中若未归一化特征alpha0.01会导致theta爆炸nan。必须同步处理# ✅ 特征归一化仅对 X不含 y def feature_normalize(X): mu np.mean(X, axis0) # 按列求均值 → (1, n) sigma np.std(X, axis0) # 按列求标准差 → (1, n) X_norm (X - mu) / sigma return X_norm, mu, sigma X_norm, mu, sigma feature_normalize(X) # X 是 (m,1)mu/sigma 也是 (1,1) # ✅ 梯度下降主循环关键在 cost 计算与 theta 更新的原子性 def gradient_descent(X, y, theta, alpha, num_iters): m len(y) J_history np.zeros(num_iters) for iter in range(num_iters): # 向量化计算预测值X 是 (m,2) [含 x01]theta 是 (2,1) → h 是 (m,1) h X theta # 计算代价函数逐元素平方后求均值 J (1/(2*m)) * np.sum((h - y)**2) J_history[iter] J # 向量化梯度更新X.T (h-y) → (2,m) (m,1) (2,1) gradient (1/m) * X.T (h - y) theta theta - alpha * gradient return theta, J_history # 初始化X 需添加偏置列 x01 X_with_bias np.hstack((np.ones((len(X_norm), 1)), X_norm)) theta np.zeros((X_with_bias.shape[1], 1)) # (2,1) alpha 0.01 num_iters 1500 theta, J_history gradient_descent(X_with_bias, y, theta, alpha, num_iters)参数说明X_with_bias必须显式添加全 1 列MATLAB 中X [ones(m, 1), data(:,1)]对应此处np.hstacktheta初始化为(n1,1)列向量不能是(n1,)一维否则X theta会触发ValueErrorJ_history存储每次迭代的J用于绘制收敛曲线——这是判断alpha是否过大的唯一可靠依据。3. 从答案版反向破译如何把标准解法拆解成可教学的推导链有答案版的价值不在于“抄”而在于“拆”。当你看到computeCost.m中一行J 1/(2*m) * sum((X*theta - y).^2);要能反向还原出① 为什么是1/(2*m)而非1/m→ 因为后续求导后2会消去简化梯度表达式② 为什么用sum()而非mean()→ MATLAB 中sum(vec)/length(vec)与mean(vec)数值等价但sum更强调“累加”这一数学动作③.^2是逐元素平方对应 NumPy 的**2若误写为^2位运算会直接报错。3.1 代价函数computeCost的三层教学拆解我们以ex1的线性回归为例将标准答案拆解为三个认知层级层级教学目标对应代码片段关键提问L1数值计算层理解J是一个标量由预测误差平方和缩放得到J (1/(2*m)) * np.sum((h - y)**2)“如果y是(m,1)h是(m,)h-y结果是什么形状会触发广播吗”L2矩阵代数层理解(h-y)是(m,1)其转置(1,m)与自身点积 (h-y).T (h-y)等价于sum((h-y)**2)J (1/(2*m)) * ((h - y).T (h - y))[0,0]“(h-y).T (h-y)返回(1,1)矩阵为何要[0,0]取值不取会怎样”L3几何解释层理解J是m个点到拟合直线的垂直距离y方向的平方和最小化J即寻找最佳投影手绘yθ₀θ₁x与散点图标出每个(xᵢ,yᵢ)到直线的竖直误差线“如果改用欧氏距离斜向定义误差代价函数形式会变吗梯度下降还适用吗”注意在ex2逻辑回归中computeCost使用log(h)和log(1-h)当h极接近 0 或 1 时log(0)会返回-inf。标准答案中常加入epsilon 1e-15截断h np.clip(h, epsilon, 1-epsilon)。这是数值稳定性必修课不是“玄学”。3.2 正规方程normalEqn的维度验证术ex1提供了不用迭代的解析解theta pinv(X*X)*X*y。在 Python 中对应np.linalg.pinv(X.T X) X.T y。但新手常在此翻车# ❌ 错误X 未添加偏置列X.shape(m,1)X.T X 结果为标量pinv 失效 theta_wrong np.linalg.pinv(X.T X) X.T y # X 是 (m,1) # ✅ 正确X 必须是 (m,2)含 x01 列 X_full np.hstack((np.ones((m,1)), X)) # (m,2) theta np.linalg.pinv(X_full.T X_full) X_full.T y验证技巧执行前打印维度print(fX_full: {X_full.shape}, X_full.T X_full: {(X_full.T X_full).shape}) # 应输出 X_full: (97, 2), X_full.T X_full: (2, 2) # 若输出 (1,1)说明 X 少了一维需检查是否漏了 np.ones 列4. 个人笔记的「血泪经验」避坑指南5 条真实踩坑记录与可执行修复方案这份 ZIP 里的个人笔记不是漂亮 PPT而是某开发者在深夜调试时记下的即时反应。以下是高频、致命、且文档极少提及的 5 类问题按「现象 → 原因 → 解决」结构整理4.1 现象plotData()绘图空白控制台无报错原因MATLAB 中plot(x, y, rx, MarkerSize, 10)自动调用figure创建窗口Python 的plt.plot()若未显式plt.show()图像对象生成但不渲染。更隐蔽的是若在 Jupyter 中多次运行同一 cellplt会累积多个 axes新图覆盖旧图导致看似“空白”。解决import matplotlib.pyplot as plt plt.figure(figsize(8,6)) # 显式创建新 figure plt.plot(X, y, rx, markersize10) plt.xlabel(Population of City in 10,000s) plt.ylabel(Profit in $10,000s) plt.show() # 必须尤其在脚本中4.2 现象sigmoid(z)输出全为1.0或0.0cost计算得inf原因z值过大如z 50np.exp(-z)下溢为0sigmoid 1/(10) 1z过小如z -50np.exp(-z)上溢为infsigmoid 1/(1inf) 0。此时log(sigmoid)或log(1-sigmoid)产生-inf。解决使用scipy.special.expit(z)稳定版 sigmoid或手动截断def sigmoid(z): z np.clip(z, -500, 500) # 防止 exp 溢出 return 1 / (1 np.exp(-z))4.3 现象predict()返回全0或全1准确率恒为 50%原因theta未初始化或初始化为全0但sigmoid(0)0.5阈值0.5下所有预测均为0因int(0.5)0。更常见的是X未归一化theta在梯度下降中发散最终theta极大sigmoid(theta.T x)恒为0或1。解决初始化theta np.random.normal(0, 0.01, (n,1))强制检查theta值域print(theta range:, theta.min(), theta.max())若abs(theta) 1e3立即停止并检查alpha和归一化predict函数中明确阈值p (h 0.5).astype(int)而非依赖int()隐式转换。4.4 现象ex3神经网络nnCostFunction梯度检验失败gradApprox 与 gradComputed 差异 1e-4原因梯度检验要求theta为实数向量但代码中theta1和theta2是矩阵。若直接theta np.concatenate([theta1.ravel(), theta2.ravel()])再unroll时顺序必须严格一致。常见错误是theta1.ravel()默认 C-order行优先而 MATLAB 是 Fortran-order列优先导致unroll后权重错位。解决统一使用orderFtheta1_unrolled theta1.ravel(orderF) # 匹配 MATLAB theta2_unrolled theta2.ravel(orderF) theta np.concatenate([theta1_unrolled, theta2_unrolled])4.5 现象ex4反向传播中delta3计算正确但delta2维度始终不匹配原因delta2 (theta2.T delta3) * sigmoidGradient(z2)中theta2是(10,26)10 个输出26 个输入delta3是(10, m)theta2.T delta3得(26, m)但z2是(26, m)sigmoidGradient(z2)也是(26, m)点乘无问题。错误常出在z2的计算z2 theta1 a1若a1是(26, m)但theta1是(25, 26)漏了偏置行则z2为(25, m)与delta3维度不匹配。解决在feedforward中打印所有中间变量形状print(fa1: {a1.shape}, theta1: {theta1.shape}, z2: {z2.shape}, a2: {a2.shape}) # 正确应为 a1:(26,m), theta1:(25,26), z2:(25,m), a2:(26,m) [含 bias]5. 笔记进阶用法用「三色标注法」把个人笔记转化为可交付的教学资产个人笔记的价值常被低估为“备忘录”。但真正让它升级为可复用资产的是一种结构化标注法用三种颜色标记笔记中的信息颗粒度并在教学或协作时按需抽取。这不是花哨技巧而是把混沌经验转化为确定性知识的硬核流程。5.1 三色标注规则与物理载体假设你用 PDF 阅读器如 Adobe Acrobat 或 Foxit打开笔记或用 Obsidian/Typora 编辑 Markdown 笔记按以下规则高亮颜色标注对象示例教学用途蓝色可验证的数学事实公式、定理、维度约束、等价变换∇_θ J(θ) (1/m) X^T (Xθ - y)X ∈ ℝ^(m×n)sigmoid(z) sigmoid(z)(1-sigmoid(z))作为板书核心写在黑板最左侧学生必须抄录并当场推导黄色可复现的操作步骤命令、函数调用、参数设置、文件路径np.loadtxt(ex1data1.txt, delimiter,).reshape(-1,2)alpha0.001, iterations4000plt.xlim([4, 24])写成 Jupyter Notebook 的 code cell学生粘贴即运行无需修改红色可规避的典型错误维度错配、函数误用、数值陷阱、环境差异X[:,0] vs X[:,0:1]log(0) → -inffor i1:m在 Python 中应为range(m)Octave 的 .m 文件在 Python 中需重写制作成「错误锦囊」卡片课前发放让学生先猜错因再揭晓答案。提示不要用彩色笔手写——电子化是前提。PDF 高亮可导出为文本Adobe 支持导出高亮注释Markdown 可用 HTML 标签span stylecolor:blue实现Obsidian 支持 CSS snippet 定制高亮样式。5.2 从笔记到课堂一个 15 分钟教学模块设计以ex2逻辑回归的决策边界绘制为例用三色笔记驱动教学【蓝】抛出数学事实3 分钟“决策边界是θ^T x 0的解集。当θ^T x 0sigmoid(θ^T x) 0.5预测为 1反之为 0。所以边界就是θ^T x 0这条直线。”学生任务在白板上写出θ₀ θ₁x₁ θ₂x₂ 0解出x₂关于x₁的表达式。【黄】执行操作步骤5 分钟# 生成网格点 u np.linspace(-1, 1.5, 50) v np.linspace(-1, 1.5, 50) U, V np.meshgrid(u, v) # 计算每个网格点的预测值 Z np.zeros(U.shape) for i in range(len(u)): for j in range(len(v)): # 构造特征向量 [1, u_i, v_j, u_i^2, u_i*v_j, ...] x_poly mapFeature(np.array([[u[i]], [v[j]]])) Z[j,i] sigmoid(x_poly.T theta) plt.contour(U, V, Z, levels[0.5], colorsred)学生任务复制代码修改levels[0.5]为[0.3, 0.7]观察边界变化。【红】暴露典型错误7 分钟展示一份“错误笔记”❌Z[j,i] sigmoid(np.array([1, u[i], v[j]]) theta)—— 漏了多项式特征映射mapFeature导致边界是直线而非曲线。❌plt.contour(U, V, Z)—— 未指定levels默认画多条等高线淹没决策边界。学生任务分组诊断错误用print(Z.shape, U.shape)验证维度并修复。这种设计让笔记不再是静态文档而成为教学活动的“活体脚本”。我曾在某高校助教培训中用此法学员反馈“第一次觉得‘看懂答案’和‘教会别人’之间原来只差一层标注。”6. 把 ZIP 当作「能力刻度尺」用 3 个渐进式验证任务检验你是否真正掌握不要满足于“跑通 ex1”。真正的掌握体现在你能独立完成三个递进式任务——它们不来自作业题而是从工业界真实需求中提炼的“能力刻度尺”。每个任务都对应一个可验证的输出做完就能清晰定位自己的段位。6.1 任务一给ex1添加 L2 正则化使theta收敛更稳定入门段位要求修改computeCost和gradient函数加入超参数lambda_使代价函数变为J(θ) (1/2m) Σ(hᵢ−yᵢ)² (λ_/2m) Σⱼ₌₁ⁿ θⱼ²注意θ₀不参与正则化验证输出当lambda_0时结果与原作业完全一致np.allclose(J_new, J_original)当lambda_1.0时theta[1:]的 L2 范数应比lambda_0时小 15% 以上绘制lambda_从0到10的J_train和J_cv曲线需自行划分验证集找到J_cv最小的lambda_。关键代码补丁def computeCostReg(X, y, theta, lambda_): m len(y) h X theta J (1/(2*m)) * np.sum((h - y)**2) # 加正则项theta[1:] 是除 theta0 外的所有参数 J (lambda_/(2*m)) * np.sum(theta[1:]**2) return J def gradientReg(X, y, theta, lambda_): m len(y) h X theta grad (1/m) * X.T (h - y) # theta0 不正则化 grad[1:] (lambda_/m) * theta[1:] return grad6.2 任务二将ex3的 one-vs-all 逻辑回归无缝迁移到sklearn并对比性能进阶层位要求不修改原始数据和标签用sklearn.linear_model.LogisticRegression重现实验要求C1/lambda_sklearn用C原作业用lambda_二者互为倒数solverliblinear适配小数据集输出与原作业完全相同的pred向量np.array_equal(pred_sklearn, pred_original)。验证输出训练时间对比time.time()测量sklearn应比手写快 3 倍以上theta形状对比sklearn的coef_是(10, n_features)需np.vstack([model.intercept_, model.coef_.T])重构为(n_features1, 10)以匹配原作业结构绘制混淆矩阵确认sklearn与手写版本的accuracy_score相差 0.001。6.3 任务三为ex4神经网络添加早停机制专家段位要求在nnCostFunction的梯度下降循环中每 100 次迭代计算一次验证集J_cv若连续 5 次J_cv上升则终止训练并返回最优theta。验证输出终止迭代次数应比num_iters10000少 2000~4000 次最终J_train应略高于无早停版本但J_cv应低 5% 以上保存J_train_history和J_cv_history绘制双曲线图明确标出早停点vertical line。核心逻辑best_J_cv float(inf) patience_counter 0 best_theta theta.copy() for iter in range(num_iters): # ... 梯度下降更新 theta ... if iter % 100 0: J_cv computeCostReg(X_cv, y_cv, theta, lambda_) if J_cv best_J_cv: best_J_cv J_cv best_theta theta.copy() patience_counter 0 else: patience_counter 1 if patience_counter 5: print(fEarly stopping at iteration {iter}) break这三个任务没有一个是作业原有内容但每一个都直指工业落地的核心能力正则化是防止过拟合的基石框架迁移是工程效率的生命线早停是模型鲁棒性的试金石。我带过的某跨平台系统项目就是靠这套“刻度尺”筛选实习生——能完成任务三的直接进入模型部署组。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑