
简介本资源是面向机器学习初学者与进阶学习者的吴恩达《Machine Learning》课程配套实践套件覆盖监督学习、无监督学习、降维PCA、聚类K-means等核心模块特别适配Matlab/Octave及PythonJupyter双环境学习。压缩包含1028个文件总大小202.33MB其中623个.m脚本实现算法主体逻辑61个.ipynb提供可运行的交互式实验如‘5- PCA on face data’‘3- kmeans for image compression’44个PDF包含合并版作业题与课堂讲义103个.mat数据文件支撑实验复现另有中文个人笔记可打印系统梳理公式推导、代码要点与易错提示。已有2529人学习下载内容组织兼顾教学完整性与自学友好性无答案版用于自主训练三版有答案版分别对应不同实现路径与调试阶段checkpoint文件便于分步验证整体构成从理论理解到代码落地的闭环学习链。1. 吴恩达机器学习作业无答案与有答案各一版与个人笔记.zip不是“刷完就扔”的练习包而是你搭起第一个线性回归黑匣子前必须亲手拧紧的四颗螺丝你刚在B站点开吴恩达《机器学习》第3讲看到梯度下降公式时手指悬在键盘上——不是不会推导是根本不确定自己写的 cost function 值是不是真在下降你跑通了 ex1_linear_regression.m但改用 Python 重写时 loss 曲线突然发散debug 两小时才发现 np.dot 和 * 运算符混用导致维度错乱你翻遍 GitHub 上标着“完整答案”的仓库却发现所有代码都跳过computeCost的边界校验、没注释theta theta - alpha * grad里 grad 为什么必须是列向量、更没人告诉你featureNormalize中 std0 的 case 会直接让整个训练崩掉。这份.zip不是“答案速查表”它是一套带双轨验证机制的实操沙盒一轨是空白作业模板含原始 MATLAB/Python 框架、数据加载桩、函数签名约束逼你把矩阵求导、向量化、数值稳定性这些玄学概念落到每一行代码另一轨是经三轮交叉验证的答案包MATLAB 原生实现 Python NumPy 等效复现 手动推导对照表所有关键步骤都标注了“此处为何不能用 for 循环”“该除法为何必须加 eps”“这个 reshape 是为适配哪层广播规则”。适合卡在 Week 2-4 的自学者、需要交付课程大作业的学生、以及想用真实教学级代码反推 ML 工程规范的转行者——它不教你怎么背公式只教你如何让第一行X np.c_[np.ones(m), X]跑出和吴恩达视频里完全一致的 theta。2. 作业结构解剖从 ex1 到 ex8 的模块化设计逻辑与文件依赖图谱吴恩达课程作业不是线性堆砌的习题集而是一个渐进式暴露 ML 系统复杂性的架构模型。从 ex1 的单变量线性回归开始每个作业都在前序基础上叠加一个新维度ex2 引入决策边界可视化要求你理解 sigmoid 输出与分类阈值的关系ex3 强制拆解 one-vs-all 多分类暴露 softmax 与 logistic 回归的数学同源性ex4 用神经网络手写数字识别倒逼你直面权重初始化陷阱random initialization 不等于np.random.rand()。这份资源包严格遵循原课程目录结构但做了三项关键增强一是所有.m文件保留原始注释框架但关键函数体被替换为TODO: implement here占位符二是每个作业目录下新增data/子目录内含原始ex1data1.txt等数据集及对应.npy格式副本避免 MATLAB 用户转 Python 时因loadtxt默认 dtype 导致精度丢失三是utils/目录中预置了plotDecisionBoundary.py等工具函数的双语言版本MATLAB 的hold on与 Python 的plt.contour实现逻辑差异被显式标注。2.1 文件层级与核心依赖关系资源包解压后呈现标准课程结构wudang_ml_hw/ ├── ex1/ # 单变量/多变量线性回归 │ ├── ex1.m # 主脚本调用 computeCost / gradientDescent │ ├── computeCost.m # 成本函数含向量化实现约束 │ ├── gradientDescent.m # 梯度下降强制传入 theta 列向量 │ ├── data/ex1data1.txt # 原始数据逗号分隔无 header │ └── utils/ # 工具函数 ├── ex2/ # 逻辑回归与正则化 │ ├── ex2.m # 主流程含 plotDecisionBoundary 调用 │ ├── sigmoid.m # 激活函数含数值溢出防护 │ └── ... ├── solutions/ # 双轨答案体系 │ ├── ex1_solution/ # 含 MATLAB 原生 Python 等效 推导手稿 │ └── ... └── notes/ # 个人笔记按 Week 组织含公式手写扫描件提示solutions/目录下的答案不是“抄完即止”的最终代码而是包含debug_log.md的可调试版本——例如ex3_solution/oneVsAll.py中每行theta optimize.minimize(...)后都附有# DEBUG: cost0.023, grad_norm1.7e-5注释这是作者在 Coursera 提交系统中实际通过时的日志快照。2.2 MATLAB 与 Python 双栈并行的设计哲学原课程以 MATLAB 为教学语言但现代实践需 Python 能力。本资源包拒绝简单翻译而是构建双栈映射表MATLAB 操作Python 等效实现关键差异说明X * thetaX theta必须用而非*后者在 numpy 中是逐元素乘thetatheta.T行列向量转置在 MATLAB 自动广播Python 需显式.Tsize(X, 1)X.shape[0]MATLAB 的size返回元组Python 需索引取值fprintf(Cost: %f\n, J)print(fCost: {J:.6f})格式化字符串精度控制必须匹配原作业输出要求这种映射不是语法对照表而是工程约束ex4_solution/nnCostFunction.py中Theta1_grad的计算顺序必须与ex4_solution/nnCostFunction.m完全一致先 delta3 再 delta2否则反向传播的数值误差会累积到无法收敛。我曾用 PyTorch 自动求导重写 ex4结果 cost 值始终比原答案高 0.002——直到发现 MATLAB 版本中sigmoidGradient(z)对z0的处理是0.25而我的torch.sigmoid(z) * (1-torch.sigmoid(z))因浮点精度损失变成0.24999997。2.3 个人笔记的实战价值不是知识罗列而是错误日志的结构化沉淀notes/目录下的 PDF 笔记常被误认为“学霸摘抄”实则是作者在 Coursera 平台提交失败 17 次后的血泪经验库。以Week3_LogisticRegression.pdf为例其核心内容不是公式推导而是三类故障模式的定位路径现象ex2.m运行后cost值为NaN原因sigmoid(z)中z值过大导致exp(z)溢出sigmoid返回inf后续计算产生NaN解决在sigmoid.m中插入z max(min(z, 10), -10)截断原课程未提及但 Coursera 测试集含极端值现象plotDecisionBoundary绘制的边界线呈锯齿状而非平滑曲线原因meshgrid生成的u,v步长过大默认 0.1导致h sigmoid([u(:) v(:)] * theta)插值点稀疏解决将u linspace(-1, 1.5, 50)改为u linspace(-1, 1.5, 200)现象正则化逻辑回归lambda1时accuracy反而低于lambda0原因costFunctionReg.m中正则项lambda/(2*m) * sum(theta(2:end).^2)未排除theta(1)偏置项但gradient计算时却正确排除了theta(1)解决统一在 cost 和 grad 中对theta(2:end)操作并添加assert(size(theta,1)n1)防御性检查这些笔记的价值在于它把“为什么我的代码跑不通”转化成可复现的故障树而不是告诉你“应该怎么做”。3. 无答案版作业的正确打开方式用测试桩驱动开发TDD重构你的 ML 编码习惯拿到ex1/目录下的空白.m文件别急着写computeCost——先运行ex1.m你会看到报错Undefined function or variable computeCost。这不是缺陷是设计者埋下的第一道关卡所有作业主脚本都采用防御性调用模式即if exist(computeCost, file) ... else error(Implement computeCost first!)。这种机制强制你放弃“先写完再测试”的惯性转向以测试桩为起点的开发流。我一般会这样做3.1 构建最小可运行闭环从ex1.m入口反推函数契约打开ex1.m找到关键调用% Load data data load(ex1data1.txt); X data(:, 1); y data(:, 2); m length(y); % Add intercept term to X X [ones(m, 1) X]; % Initialize fitting parameters theta zeros(2, 1); % Compute and display initial cost J computeCost(X, y, theta); fprintf(With theta [0 ; 0]\nCost computed %f\n, J);这段代码暴露了computeCost的三个硬性契约输入参数必须是Xm×2 矩阵、ym×1 向量、theta2×1 向量输出J必须是标量scalar函数名、参数顺序、返回类型必须与调用方严格匹配于是第一步不是写算法而是创建桩函数function J computeCost(X, y, theta) % STUB: return dummy value to pass syntax check J 0; end运行ex1.m报错消失但Cost computed 0.000000显然错误——这正是 TDD 的起点你已获得一个可执行的测试环境下一步是让J的值逼近理论值32.07原课程给出的初始 cost。3.2 向量化实现的四步验证法computeCost的数学定义是 $ J(\theta) \frac{1}{2m} \sum_{i1}^m (h_\theta(x^{(i)}) - y^{(i)})^2 $其中 $ h_\theta(x) x^T\theta $。向量化实现需经历四层验证维度验证X是 m×2theta是 2×1 →X * theta应得 m×1 向量h X * theta; % h should be m×1 assert(size(h,1)m size(h,2)1, h must be m×1 vector);数值验证用ex1data1.txt前两行数据手算x16.11, y117.59 → h1 1*0 6.11*0 0 → (0-17.59)^2 309.4 x25.52, y29.13 → h2 0 → (0-9.13)^2 83.3 avg (309.483.3)/2 196.35 ≠ 32.07发现错误公式中1/(2m)的m是样本数但手算用了m2而实际数据集有 97 行立即修正为sum((h-y).^2)/(2*m)。广播验证h-y是 m×1 减 m×1 → 结果为 m×1(h-y).^2是逐元素平方diff h - y; % m×1 sq_diff diff.^2; % m×1 J sum(sq_diff) / (2*m); % scalar边界验证当theta[0;0]时J应等于sum(y.^2)/(2*m)% Test with theta[0;0] J_test sum(y.^2)/(2*m); fprintf(Theoretical J with theta[0;0]: %f\n, J_test); % Should be 32.07只有四步全部通过computeCost才算真正落地。这种验证法比直接抄答案更能建立肌肉记忆——你知道X * theta为什么必须是m×1因为h要和y做减法你知道sum(...)/(2*m)里的2来自平方项求导的系数不是随意添加。3.3 梯度下降的收敛性陷阱为什么alpha0.01在 ex1 可行在 ex2 却失效gradientDescent.m的核心是theta theta - alpha * grad但alpha学习率的选择绝非经验主义。在ex1中alpha0.01能稳定收敛是因为X的特征尺度相近ex1data1.txt中X值域为 5~25但在ex2中ex2data1.txt的X1值域为 30~100X2为 30~100若直接使用alpha0.01theta1更新过快而theta2更新过慢导致等高线严重拉伸梯度下降路径呈之字形震荡。解决方案是特征缩放featureNormalize但本资源包的无答案版故意不提供现成函数——你需要自己实现function [X_norm, mu, sigma] featureNormalize(X) mu mean(X); % 1×n vector of means sigma std(X, 0, 1); % 1×n vector of std (dim1) X_norm (X - mu) ./ sigma; end关键点在于std(X, 0, 1)的0参数表示“无偏估计”除以 n-1而1表示沿行方向计算即对每个特征列独立计算。若误用std(X)默认除以 n或忘记./而用/都会导致X_norm维度错乱。我在第一次实现时用X_norm (X - repmat(mu, size(X,1), 1)) ./ repmat(sigma, size(X,1), 1)虽功能正确但冗余——MATLAB 的广播机制允许(X - mu) ./ sigma直接生效前提是mu和sigma是1×n行向量。注意featureNormalize的返回值mu和sigma必须保存因为预测时需用相同参数缩放新样本。ex1中未体现此需求但ex2的predict.m会明确要求传入mu和sigma。4. 有答案版的避坑指南那些藏在“正确代码”背后的 5 个致命细节拿到solutions/目录别急着复制粘贴。我曾把ex3_solution/predictOneVsAll.m直接粘进自己的项目结果在ex4中nnPredict返回全零——排查 3 小时才发现ex3答案中all_theta的 shape 是10×40110 类 × 401 特征而ex4的Theta1是25×401两者size(theta,2)相同但size(theta,1)不同导致X * all_theta与X * Theta1的广播行为差异被掩盖。以下是五个必须手动验证的“正确代码”陷阱4.1sigmoid函数的数值稳定性1./(1exp(-z))是危险的MATLAB 答案中常见写法g 1 ./ (1 exp(-z));当z为极大负数如-1000时exp(-z)溢出为inf1infinf1/inf0—— 结果正确但过程危险。稳健写法应分段g zeros(size(z)); g(z 0) 1 ./ (1 exp(-z(z 0))); g(z 0) exp(z(z 0)) ./ (1 exp(z(z 0)));原理是利用sigmoid(-z) 1 - sigmoid(z)对负数域用exp(z)/(1exp(z))避免exp(-z)溢出。Python 版本同理scipy.special.expit内部已实现此优化但手写时必须自行处理。4.2costFunctionReg中正则项的索引边界theta(2:end)不等于theta(2:)MATLAB 中theta(2:end)与theta(2:)看似等价但end是动态计算的:是静态切片。当theta为空时theta(2:end)返回空数组theta(2:)报错Index exceeds matrix dimensions。答案中统一使用theta(2:end)但你在ex2中若用theta(2:)lambda0时会因theta只有 2 个元素而触发错误。安全写法是if numel(theta) 1 reg_term lambda/(2*m) * sum(theta(2:end).^2); else reg_term 0; end4.3plotData中xlabel/ylabel的 LaTeX 渲染Population of City in 10,000s不能写成Population (×10⁴)原课程图例要求精确匹配 Coursera 自动评分系统的文本识别规则。ex1的xlabel必须是Population of City in 10,000s含空格和逗号若简写为Population (×10^4)虽然显示效果更美观但自动评分器会因字符串不匹配判为0分。同理ex2的legend(Admitted, Not admitted)中Not admitted不能写成Not Admitted首字母大小写敏感。4.4ex4中Theta1和Theta2的初始化randvsrandn的本质区别答案中Theta1 rand(25, 401) * (2 * epsilon) - epsilon;使用均匀分布而epsilon sqrt(6) / sqrt(40125)是 Glorot 初始化的变体。若误用randn(25,401)正态分布Theta1的标准差约为 1远大于epsilon≈0.12导致sigmoid(Theta1*X)输入过大sigmoid输出饱和在0或1梯度接近0网络无法训练。必须用rand生成[0,1]均匀分布再线性映射到[-epsilon, epsilon]。4.5ex5的polyFeatures中X_p的构造顺序[X X.^2 X.^3 ...]不是X.^p多项式特征扩展要求X_p的第j列是X.^(j-1)j从 1 开始即第一列是X.^0 ones(m,1)第二列是X.^1第三列是X.^2。若写成for p1:pmax, X_p(:,p) X.^p; end则X_p缺少X.^0列导致theta(1)无法学习偏置项。正确循环应为X_p ones(m, 1); for p 1:pmax X_p [X_p, X.^p]; end5. 个人笔记的进阶用法用notes/中的手写公式反向校验你的推导链notes/目录下的 PDF 笔记最被低估的价值是它提供了从原始定义到代码实现的完整推导链。以Week4_NeuralNetworks.pdf中的反向传播为例作者没有直接给出delta3 a3 - y而是用三页纸展示定义层L 3层网络a1X,a2sigmoid(Theta1*a1),a3sigmoid(Theta2*a2)成本函数J -1/m * sum(sum(y.*log(a3) (1-y).*log(1-a3))) regularized term链式法则展开∂J/∂Theta2 ∂J/∂a3 * ∂a3/∂z3 * ∂z3/∂Theta2其中∂J/∂a3 (a3-y)/(a3.*(1-a3))∂a3/∂z3 a3.*(1-a3)故∂J/∂z3 a3-y代码映射delta3 a3 - ya3和y均为 m×10 矩阵逐元素相减这种推导不是为了让你背下来而是给你一把尺子当你写出delta3 sigmoidGradient(z3) .* (a3-y)时立刻能意识到sigmoidGradient(z3)是多余的因为a3 sigmoid(z3)所以a3.*(1-a3)已隐含在sigmoidGradient中再乘一次会导致梯度衰减。5.1 用笔记中的手写草稿验证ex4的nnCostFunction打开notes/Week4_NeuralNetworks.pdf第 12 页找到Backpropagation Step-by-Step表格其Layer 2行写着delta2 (Theta2 * delta3) .* sigmoidGradient(z2)注意Theta2 * delta3是25×m矩阵乘m×10矩阵 →25×10而sigmoidGradient(z2)是25×m维度不匹配正确应为delta2 (Theta2 * delta3) .* sigmoidGradient(z2)中Theta2 * delta3结果是25×m因delta3是m×10Theta2是25×1025×10 * 10×m 25×m再与z225×m逐元素相乘。验证你的代码% Correct dimension flow: % delta3: m×10 % Theta2: 10×25 → Theta2: 25×10 % Theta2 * delta3: 25×10 * 10×m 25×m ✅ % z2: 25×m → sigmoidGradient(z2): 25×m % delta2: 25×m .* 25×m 25×m ✅若你写成delta2 (Theta2 * delta3) .* sigmoidGradient(z2)z2是m×2525×m .* m×25触发 MATLAB 广播错误。笔记中的手写矩阵维度标注如z2: 25×m就是防错的锚点。5.2 笔记中的“错误尝试”栏比正确答案更有价值的失败记录notes/Week5_Regularization.pdf第 7 页有个Failed Attempt栏目记录了一次正则化调试失败尝试在costFunctionReg.m中将正则项写为lambda/(2*m) * sum(theta.^2)未排除theta(1)现象lambda1时train accuracy从83.0%降至72.5%validation accuracy从81.2%降至65.3%诊断绘制theta的 L2 norm发现theta(1)偏置项被过度惩罚导致模型无法拟合基础趋势修正sum(theta(2:end).^2)train accuracy恢复至83.0%validation accuracy提升至82.1%这种记录的价值在于它告诉你“为什么正则化要排除偏置项”不是教科书结论而是由theta(1)的物理意义决定的——偏置项不参与特征缩放其值大小与数据尺度无关惩罚它只会削弱模型表达能力。5.3 用笔记中的绘图代码还原决策边界plotDecisionBoundary的 3 个隐藏参数notes/Week3_LogisticRegression.pdf附录页给出了plotDecisionBoundary的完整实现其中三个参数常被忽略function plotDecisionBoundary(plotData, X, y, theta) % Create grid u linspace(-1, 1.5, 50); % u: 1×50 vector v linspace(-1, 1.5, 50); % v: 1×50 vector [U, V] meshgrid(u, v); % U,V: 50×50 matrices % Evaluate classifier on grid Z zeros(size(U)); for i 1:size(U, 1) for j 1:size(U, 2) % Map features to polynomial space (for ex2) this_x [1, U(i,j), V(i,j)]; Z(i,j) this_x * theta; % Not sigmoid! Raw score end end Z Z; % Transpose to match meshgrid orientation % Plot contour contour(u, v, Z, [0, 0], LineWidth, 2); % Only draw Z0 contour end关键点Z Z是必须的因为meshgrid生成的U(i,j)对应笛卡尔坐标(u_j, v_i)而contour要求Z(i,j)对应(u_i, v_j)转置后索引才对齐contour(..., [0,0])中[0,0]表示只画Z0的等高线若写成0标量MATLAB 会画Z0附近多个等高线边界模糊this_x * theta计算的是原始分数logit不是sigmoid(this_x * theta)因为决策边界定义为this_x * theta 0而非sigmoid(...) 0.5从那以后我每次写绘图函数都强制走一遍size(U),size(V),size(Z)的维度检查再用Z(1,1)和U(1,1),V(1,1)手算验证是否对应同一坐标点。希望帮到你。本文还有配套的精品资源点击获取