简介:这份资源面向正在学习斯坦福CS231N计算机视觉公开课、需要完成assignment1编程作业的深度学习入门者与进阶学习者,提供从题目到参考答案的完整闭环,帮助读者在kNN、SVM、Softmax、两层神经网络与特征提取等模块中对照实现、验证思路。压缩包共54个文件,约561.98MB,以ipynb交互式笔记本承载各作业题目与解答,配合py源码模块、pyc缓存、tar与zip打包的CIFAR-10数据集及xml工程配置等,覆盖代码、数据与运行环境三类内容,采用Anaconda下的Jupyter即可打开使用。目前已有2007人学习下载,说明其在同类作业资料中具备一定参考价值。读者可据此获得可直接运行的作业框架、完整答案实现、配套数据集与模块化代码结构,便于逐题复现实验、比对梯度检查与训练结果,并在此基础上理解经典分类器与浅层网络的实现细节。
1. 从一道“反向传播手推题”说起:这场作业到底考什么
很多人第一次打开 cs231n 作业一,看到 kNN、SVM、Softmax、两层神经网络这几个词,以为就是调包跑通、交个 notebook 了事。真正拉开差距的,恰恰是那些不让你调包的地方:手推 SVM 的梯度、手写 Softmax 的数值稳定版本、手推反向传播的链式法则。面试官问深度学习基础时,最爱从这些“看起来最底层”的点切入,因为调包谁都会,能白板推梯度的人不多。这份作业一的价值就在这:它把深度学习入门阶段最容易被跳过、又最常被面试追问的考点,全部逼你手写一遍。适合正在准备算法岗、深度学习方向面试,或者想补牢基础的人。拿分逻辑很简单——不是跑出准确率,而是每一行梯度你都能讲清楚为什么这么写。
2. 高频考点拆解:四个模块的考点分布与分值权重
2.1 kNN:距离度量与交叉验证的送分题
kNN 是作业一里最“友好”的部分,但面试官不会只问你“kNN 是什么”。他们更常问的是:L1 和 L2 距离分别适合什么数据?k 值怎么选?为什么用交叉验证而不是简单切分?
先看距离度量。L1(曼哈顿距离)对异常值更鲁棒,适合特征稀疏、差异体现在“有没有”的场景;L2(欧氏距离)对大差异更敏感,适合特征连续、差异体现在“差多少”的场景。作业里会让你实现两种距离的向量化版本,核心是把双重循环改写成矩阵运算:
# 向量化计算 L2 距离:利用 (a-b)^2 = a^2 + b^2 - 2ab # dists[i,j] = ||X_train[j] - X_test[i]||^2 dists = np.sum(X_test**2, axis=1).reshape(-1, 1) \ + np.sum(X_train**2, axis=1).reshape(1, -1) \ - 2 * X_test.dot(X_train.T)这段代码的关键在于把逐元素循环转成矩阵乘法,reshape(-1,1)和reshape(1,-1)是为了让两个平方和能广播相加。面试官常追问:为什么不能直接开根号?因为 kNN 只需要比较距离大小,平方距离和真实距离单调一致,省掉开根号能减少计算量。这个细节答出来,说明你真理解而不是背代码。
交叉验证部分,作业要求你把训练集分成 k 折,轮流用 k-1 折训练、1 折验证,取平均准确率最高的超参。面试官最想听的是:为什么不能用测试集调参?因为那会造成信息泄露,测试集必须保持“从未见过”的状态。这类题通常这么答——先说交叉验证的目的(估计泛化误差、选超参),再说流程(分折、轮换、取均值),最后点出测试集只在最终评估用一次。
2.2 SVM 与 Softmax:损失函数和梯度的手推是分水岭
这是作业一真正的分水岭。多分类 SVM 的 hinge loss 和 Softmax 的交叉熵损失,作业都要求你手写损失和解析梯度,不许调框架。面试里这两道题出现频率极高,因为能同时考察损失函数理解、梯度推导和数值稳定性意识。
多分类 SVM 的损失是:
# 多分类 SVM hinge loss # scores: (N, C),y: (N,) # 正确类分数减去其他类分数,加 margin=1,取 max(0, ·),再求和 margins = np.maximum(0, scores - scores[np.arange(N), y].reshape(-1, 1) + 1) margins[np.arange(N), y] = 0 # 正确类自身不参与 loss = np.sum(margins) / N梯度部分,作业要求你对 scores 求导。核心逻辑是:对每个样本,只有那些“正确类分数 - 其他类分数 + 1 > 0”的类才会产生梯度,正确类梯度为负的违例数,违例类梯度为 1。面试官常在这里设陷阱:margin 取 0 还是 1?正确类要不要算进求和?这两个点答错,整道题就废了。
Softmax 的坑更隐蔽——数值稳定性。直接算exp(scores)在分数很大时会溢出,标准做法是先减去每行的最大值:
# 数值稳定的 Softmax scores_shifted = scores - np.max(scores, axis=1, keepdims=True) exp_scores = np.exp(scores_shifted) probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True) loss = -np.sum(np.log(probs[np.arange(N), y])) / Nkeepdims=True是为了保持维度对齐,方便广播。面试官最想听的是:减去最大值不改变 Softmax 结果(分子分母同乘一个常数),但能防止 exp 溢出。这个“数学上等价、工程上必须”的点,是区分“会写”和“懂为什么”的关键。
2.3 两层神经网络:反向传播的链式法则实战
作业一最后会让你搭一个两层全连接网络(ReLU + Softmax),手写前向和反向传播。这是整份作业最接近“真实面试白板题”的部分。面试官常给一个简单网络结构,让你推每一层的梯度维度,或者问“为什么 ReLU 的梯度是 0 或 1”。
前向传播的维度变化要能脱口而出:输入 (N, D),第一层权重 (D, H),输出 (N, H),ReLU 不改变维度,第二层权重 (H, C),输出 (N, C)。反向传播时,梯度维度必须和参数维度一一对应,这是检查推导是否正确的第一道防线。
# 两层网络反向传播核心片段 # 第二层:Softmax + 交叉熵的梯度 dscores = probs.copy() dscores[np.arange(N), y] -= 1 dscores /= N # 第二层参数梯度 dW2 = h1.T.dot(dscores) db2 = np.sum(dscores, axis=0) # 经过 ReLU:小于等于 0 的位置梯度截断 dh1 = dscores.dot(W2.T) dh1[h1 <= 0] = 0 # 第一层参数梯度 dW1 = X.T.dot(dh1) db1 = np.sum(dh1, axis=0)这段代码里,dscores先复制概率再对正确类减 1,是 Softmax 交叉熵梯度的标准写法;dh1[h1 <= 0] = 0是 ReLU 反向的“开关”逻辑。面试官常追问:如果 ReLU 换成 Sigmoid,反向传播要改哪里?答案是梯度多乘一项sigmoid(x)*(1-sigmoid(x)),而且要注意 Sigmoid 的梯度消失问题。这类题通常这么答——先写前向公式,再逐层写局部梯度,最后用链式法则串起来,每一步都报维度。
2.4 超参数调优与模型评估:面试里的“工程感”考点
作业一不要求你刷到多高准确率,但要求你理解学习率、正则化强度、网络宽度这些超参怎么影响结果。面试官问这类题,考的是你有没有“调过模型”的真实感。
学习率太大,loss 震荡甚至发散;太小,收敛慢且容易停在局部平坦区。正则化强度太大,模型欠拟合;太小,过拟合。作业里会让你画不同学习率下的 loss 曲线,面试官最想听的是:你怎么判断学习率设错了?看 loss 曲线——前几十次迭代 loss 不降反升,基本就是学习率过大;loss 降得极慢,可能是学习率过小或者初始化有问题。
模型评估部分,作业强调训练集、验证集、测试集的划分纪律。面试官常问:验证集准确率比训练集高,可能是什么原因?常见答案是小数据集波动、正则化在训练时生效而验证时关闭、或者数据划分有偏。这类题答的时候要给出“排查顺序”,而不是只报一个原因。
3. 易错点:五个最容易翻车的题和答法
3.1 易错点一:SVM 梯度把正确类也算进求和
错在哪:很多人在写 hinge loss 梯度时,把正确类自身的 margin 也纳入求和,导致正确类梯度多算了一项。为什么错:正确类和其他类的 margin 定义不同,正确类不参与“正确类减其他类”的比较,它的 margin 恒为 0。怎么答对:先构造 margin 矩阵,把正确类位置显式置 0,再统计每行大于 0 的个数作为正确类梯度,违例类梯度置 1。
3.2 易错点二:Softmax 不减最大值直接 exp
错在哪:分数稍大就溢出成 inf,loss 变成 nan。为什么错:exp增长极快,float 表示范围有限。怎么答对:先减每行最大值再 exp,并说明“数学等价、工程必需”。面试官追问时补一句:减最大值后最大项为 exp(0)=1,不会溢出。
3.3 易错点三:反向传播梯度维度对不上
错在哪:dW1算出来是 (N, D) 而不是 (D, H),或者db忘了沿 batch 维求和。为什么错:链式法则里矩阵乘法的顺序和转置搞混。怎么答对:每写一步梯度就报一次维度,用“参数维度 = 梯度维度”做自检;db一定是对 batch 维求和,因为偏置对每个样本共享。
3.4 易错点四:kNN 用测试集调 k
错在哪:直接拿测试集准确率选 k 值。为什么错:测试集信息泄露,评估结果虚高。怎么答对:明确说“训练集内部做交叉验证选 k,测试集只在最后评估一次”,并解释信息泄露为什么会让线上表现翻车。
3.5 易错点五:ReLU 反向把等于 0 的位置当可导
错在哪:h1 <= 0写成h1 < 0,导致 0 位置梯度保留。为什么错:ReLU 在 0 处不可导,工程上约定梯度为 0。怎么答对:用<= 0截断,并说明这是次梯度约定,面试官通常认可这个工程处理。
4. 答题技巧:把作业一变成面试白板题的通用套路
4.1 白板推梯度的三步模板
面试官让你推任何一个损失函数的梯度,别急着写公式,先走三步:第一步,写出标量形式的损失,明确对哪个变量求导;第二步,逐样本、逐类写局部梯度,标出哪些项参与、哪些被 max 截断;第三步,把局部梯度组装成矩阵形式,报一遍维度。这个模板对 SVM、Softmax、两层网络通用。血泪经验是:很多人第一步就跳去写矩阵,结果维度一乱全盘崩。先标量再矩阵,是白板题最稳的节奏。
4.2 数值稳定性是加分项,不是可选项
只要涉及 exp、log、除法,主动提一句数值稳定性,面试官会默认你“写过真代码”。Softmax 减最大值、交叉熵里 log 和 exp 合并、分母加极小值防除零,这三个点背熟。面试官最想听的不是“我知道会溢出”,而是“我知道怎么改、为什么改完等价”。
4.3 超参问题的回答结构
被问“学习率怎么选”,别只报一个数。按“先粗后细”答:先用对数刻度扫几个量级(如 1e-1 到 1e-5),看 loss 曲线挑下降最稳的区间,再在这个区间内细调。补一句“配合验证集准确率,不看测试集”,工程感就出来了。
4.4 押题思路:作业一最可能被追问的五个方向
按出现频率排:Softmax 数值稳定实现、SVM 梯度推导、反向传播维度检查、交叉验证防泄露、ReLU 梯度截断。这五个方向覆盖了作业一 80% 的可面试点。准备的时候不要背代码,背“每一步为什么这么写”,因为面试官会换数字、换层数、换激活函数,只有逻辑是通用的。
4.5 一个具体方法:把每道题讲给“不懂的人”听
我自己的习惯是,每写完一个模块,合上代码,用大白话把“输入是什么、中间算了什么、梯度为什么长这样”讲一遍,讲不顺的地方就是没真懂的地方。从那以后我每次准备这类底层题,都强制走一遍“合上代码复述”的流程,翻车次数明显少了。这份作业一的题库和笔记,按模块整理好了损失函数、梯度推导和易错点,拿来对着练白板推导正好。希望帮到你。
本文还有配套的精品资源,点击获取