新闻详情

新闻详情

首页 / 资讯中心 / 详情

前馈神经网络入门:从正向传播到反向传播的完整图解

发布时间:2026/10/2 9:09:21来源:尧图网络
前馈神经网络入门:从正向传播到反向传播的完整图解
1. 从黑盒到白盒我为什么建议你先搞懂前馈神经网络前馈神经网络Feedforward Neural NetworkFNN这个名字很多刚入门的朋友看到就头大。我在带新人时最常说的一句话是你别管它叫神经网络还是深度学习它本质上就是一个套娃版的逻辑回归。你把这句话想明白了后面所有关于卷积、循环、Transformer的东西都顺了。这篇文章要解决三件事前馈神经网络到底是什么、它内部的计算过程长什么样、以及为什么图像处理时大家不约而同选了卷积神经网络CNN而不是它。第三点尤其重要因为很多人在面试或者项目选型时被问到图像为什么用CNN不用全连接网络就卡壳了。我会用实际算例和项目经验把这层窗户纸捅破。适合谁看刚入门的算法工程师、转行做AI的开发者、还有在学校学了理论但没亲手推过一遍的在校生。看之前你最好懂一点点Python和高中数学里的函数求导不懂也没关系我会把每个公式掰开揉碎地讲。2. 前馈神经网络的核心结构与设计思想2.1 为什么叫前馈——信息只走单向道前馈神经网络这个名字里有两个关键词前馈和网络。前馈的意思是信息从输入层进入网络之后逐层向后传递中间没有回环、没有跨层跳跃标准的FNN里也不会像循环神经网络RNN那样把上一时刻的输出再接回这一时刻的输入。你可以把它想象成一条单向的生产线原料从入口进每一道工序加工完就传给下一道最后从出口出来成品。那网络又是什么意思它指的是一堆神经元也叫节点按照层次结构连接起来。常见的前馈神经网络长这样输入层接收数据中间是若干隐藏层最后一层是输出层。每一层的每个神经元都和下一层的每个神经元相连这种连接方式叫全连接所以前馈神经网络通常也叫多层感知机MLPMultilayer Perceptron或者全连接网络Fully Connected Network。我见过不少初学者把全连接和前馈当成两个不同的东西其实是一回事。只要是每一层的所有节点都连接到下一层的所有节点同时信息只往前传它就是标准的前馈神经网络。2.2 神经元的计算逻辑加权求和加激活函数拆开看单个神经元它的计算就两步第一步把输入做一个加权求和再加一个偏置。假设上一层传来n个输入(x_1, x_2, ..., x_n)每个输入对应一个权重(w_1, w_2, ..., w_n)这个神经元自己的偏置是(b)那么它先算出[ z \sum_{i1}^{n} w_i x_i b w_1 x_1 w_2 x_2 ... w_n x_n b ]第二步把z送入激活函数(f)得到这个神经元的输出[ a f(z) ]这里面的权重(w)和偏置(b)就是网络要学习的参数。整个网络的学习过程本质上就是在不断调整这些参数让最终的输出接近我们想要的目标。可能有人会问为什么要加激活函数如果只是算加权和那一层层线性函数叠起来还是线性函数不管网络叠多少层本质上都等价于一个线性模型根本学不了复杂的东西。激活函数给网络引入了非线性这才让神经网络有能力去拟合那些弯弯绕绕的分布。后面我会专门讲常用激活函数的选型。2.3 设计思路背后的逻辑为什么每层要那么多神经元我经常反过来被问一个问题那么简单的加权求和加激活为什么能搞定图像识别、语音识别这种复杂任务这里有个著名的理论叫万能逼近定理一个带有足够多隐藏神经元的前馈神经网络能够以任意精度逼近任何连续函数。用人话说就是只要你的神经元数量够多、网络够宽它理论上可以画出任何你想要的输入到输出的映射关系。但要注意理论可以做到和实际能做到是两回事。神经元越多参数越多模型就越容易把训练数据里的噪声也背下来这就是过拟合。所以设计网络时不是把神经元堆得越多越好而是要根据数据量、任务难度和计算资源来权衡。后面我会详细讲怎么避免过拟合。3. 从输入到输出前向传播的手把手算例3.1 一个最小的前馈神经网络为了让你彻底看清前向传播的过程我在这里构造一个非常小的网络2个输入1个隐藏层2个神经元1个输出层1个神经元。激活函数全部用Sigmoid后面我会解释为什么这里先选它。网络结构如下输入层(x_1 0.5)(x_2 0.8)隐藏层权重(w_{11} 0.1)(w_{12} 0.3)(w_{21} 0.4)(w_{22} 0.6)隐藏层偏置(b_1 0.2)(b_2 -0.1)输出层权重(v_1 0.7)(v_2 0.5)输出层偏置(c 0.3)这里的命名规则需要说清楚(w_{11})表示第1个输入到第1个隐藏神经元的权重(w_{12})表示第2个输入到第1个隐藏神经元的权重注意下标顺序不要和编程里搞混了。3.2 逐步计算每个节点的输出先算第一个隐藏神经元的加权和[ z_{h1} w_{11}x_1 w_{12}x_2 b_1 0.1 \times 0.5 0.3 \times 0.8 0.2 0.05 0.24 0.2 0.49 ]Sigmoid函数是[ \sigma(z) \frac{1}{1 e^{-z}} ]所以第一个隐藏神经元的输出是[ a_{h1} \sigma(0.49) \frac{1}{1 e^{-0.49}} \approx \frac{1}{1 0.6126} \approx 0.6201 ]再算第二个隐藏神经元[ z_{h2} w_{21}x_1 w_{22}x_2 b_2 0.4 \times 0.5 0.6 \times 0.8 - 0.1 0.2 0.48 - 0.1 0.58 ][ a_{h2} \sigma(0.58) \frac{1}{1 e^{-0.58}} \approx \frac{1}{1 0.5599} \approx 0.6411 ]隐藏层算完之后这两个输出作为输出层的输入[ z_o v_1 a_{h1} v_2 a_{h2} c 0.7 \times 0.6201 0.5 \times 0.6411 0.3 ][ z_o 0.4341 0.3206 0.3 1.0547 ][ a_o \sigma(1.0547) \frac{1}{1 e^{-1.0547}} \approx \frac{1}{1 0.3482} \approx 0.7417 ]所以这个网络在输入((0.5, 0.8))时最终输出大约是0.7417。前向传播就是这么简单你顺着网络一层层算下去就行。实际训练时我们还会对这个输出和真实标签之间算一个损失函数然后通过反向传播更新权重。反向传播的原理我在第4章讲。3.3 为什么前向传播代码实现时用矩阵运算上面这个例子只有2个神经元手算还能接受。但真实的网络往往有几百上千个输入、几百个神经元的隐藏层如果手算每个节点根本算不完。所以工程实现上一定会用矩阵运算。把刚才的例子写成矩阵形式就是[ z_{hidden} W_{hidden} \cdot x b_{hidden} ]其中(W_{hidden})是一个2x2的矩阵行对应隐藏神经元列对应输入(x)是2维列向量。算完之后经过激活函数得到隐藏层输出向量然后再过一层矩阵运算得到输出。用NumPy写前向传播的代码也就几行import numpy as np def sigmoid(x): return 1 / (1 np.exp(-x)) # 输入和参数 x np.array([0.5, 0.8]) W_hidden np.array([[0.1, 0.3], # 第一个隐藏神经元的权重 [0.4, 0.6]]) # 第二个隐藏神经元的权重 b_hidden np.array([0.2, -0.1]) W_output np.array([0.7, 0.5]) b_output np.array([0.3]) # 前向传播 z_hidden W_hidden x b_hidden a_hidden sigmoid(z_hidden) z_output W_output a_hidden b_output a_output sigmoid(z_output) print(隐藏层输出:, a_hidden) print(最终输出:, a_output)跑一下这段代码输出结果和我手算的0.7417差不多。矩阵运算不仅在写法上简洁更重要的是GPU和NumPy底层对矩阵乘法做了深度优化用矢量化的方式一口气算完比自己写循环快几个数量级。你真的想在深度学习这条路上走远矩阵运算的手感和直觉必须练出来。4. 训练前馈神经网络反向传播的本质4.1 损失函数是训练的方向盘前向传播算出的输出不能白算你得知道它和正确答案差了多少。这个差距用一个函数来衡量叫做损失函数。回归任务常用均方误差MSE分类任务常用交叉熵Cross Entropy。以我们的例子来说假设真实标签是(y 0.9)网络输出(a_o \approx 0.7417)如果使用均方误差[ L \frac{1}{2}(y - a_o)^2 \frac{1}{2}(0.9 - 0.7417)^2 \approx 0.0125 ]前面的1/2纯粹是为了求导方便把平方求导后的2消掉不影响优化的方向。训练的目标就是不断调整网络的权重和偏置让这个损失值尽可能小。怎么调梯度下降——沿损失函数下降最快的方向更新参数。4.2 链式法则与梯度如何一层层回传反向传播Backpropagation听起来高大上本质就是微积分里的链式法则。你想知道损失(L)对某个权重比如(w_{11})的影响那就把从(L)到(w_{11})这条路径上的导数全部乘起来。按我们例子的路径是[ L \rightarrow a_o \rightarrow z_o \rightarrow a_{h1} \rightarrow z_{h1} \rightarrow w_{11} ]所以[ \frac{\partial L}{\partial w_{11}} \frac{\partial L}{\partial a_o} \cdot \frac{\partial a_o}{\partial z_o} \cdot \frac{\partial z_o}{\partial a_{h1}} \cdot \frac{\partial a_{h1}}{\partial z_{h1}} \cdot \frac{\partial z_{h1}}{\partial w_{11}} ]每一项都很好算(\frac{\partial L}{\partial a_o} a_o - y 0.7417 - 0.9 -0.1583)(\frac{\partial a_o}{\partial z_o} a_o(1 - a_o) 0.7417 \times 0.2583 \approx 0.1916)Sigmoid的导数(\frac{\partial z_o}{\partial a_{h1}} v_1 0.7)(\frac{\partial a_{h1}}{\partial z_{h1}} a_{h1}(1 - a_{h1}) 0.6201 \times 0.3799 \approx 0.2356)(\frac{\partial z_{h1}}{\partial w_{11}} x_1 0.5)全部乘起来[ \frac{\partial L}{\partial w_{11}} \approx -0.1583 \times 0.1916 \times 0.7 \times 0.2356 \times 0.5 \approx -0.00250 ]然后按照梯度下降的公式更新权重[ w_{11}^{new} w_{11} - \eta \cdot \frac{\partial L}{\partial w_{11}} ]如果学习率(\eta 0.1)那么[ w_{11}^{new} 0.1 - 0.1 \times (-0.00250) 0.10025 ]你看权重只是刷新了一点点。正是这一点点更新让网络的输出在正确的方向上挪了一步。4.3 为什么Sigmoid容易让梯度消失在中间层激活函数的选择上Sigmoid其实是个坑。它的导数最大也就是(0.25)在(z0)处一旦网络层数加深梯度经过每一层都要乘一次小于1的数比如0.25四层之后梯度就缩小到原来的(0.25^4 \approx 0.0039)几乎传不回去了。这就是梯度消失。深层网络里靠近输入层的参数几乎收不到有效的梯度训练会非常慢甚至停滞。现代的隐藏层基本都用ReLU线性整流单元Rectified Linear Unit替代Sigmoid。它的表达式是[ ReLU(z) \max(0, z) ]导数在z大于0时恒为1负数时恒为0这样正区间梯度不会衰减。但它也有问题如果某个神经元在训练中被推到负数区域它的梯度恒为0这个神经元就死了。所以后来又有了Leaky ReLU、参数化ReLU等变体。我个人的经验是隐藏层默认用ReLU或者Leaky ReLU输出层根据任务来定——回归任务直接线性输出二分类任务用Sigmoid多分类任务用Softmax。5. 激活函数与参数初始化容易被忽略的坑5.1 激活函数选型对比与使用场景为了让你快速决策我把常用激活函数整理成一张表激活函数公式输出范围适用场景缺点Sigmoid(1/(1e^{-z}))(0, 1)二分类输出层梯度消失、输出均值不为0Tanh((e^z-e^{-z})/(e^ze^{-z}))(-1, 1)隐藏层旧式习惯依然有梯度消失问题ReLU(\max(0, z))[0, ∞)隐藏层默认选择神经元可能坏死Leaky ReLU(z) 如果 (z0)否则 (0.01z)全实数防止ReLU坏死参数需要调Softmax(\frac{e^{z_i}}{\sum_j e^{z_j}})(0, 1)且和为1多分类输出层只用于输出层初学的时候最容易搞混的是Sigmoid和Softmax。Sigmoid是逐元素地输出一个0到1之间的概率适合二分类Softmax是让所有输出节点的值加起来等于1变成概率分布适合多分类。举个例子如果网络输出层有10个节点对应10个数字类别你用Softmax就会得到10个加起来为1的概率值概率最大的那个就是模型的预测。5.2 权重初始化为什么不能全设置成0有一次我让一个实习生自己实现个小网络他把所有参数都初始化为0。跑了两轮发现损失一点不变。为什么如果某层的所有参数都是0那么这一层所有神经元的输出都是相同的反向传播时所有神经元收到完全一样的梯度然后它们仍然以同样的方式更新——等于这一层只有一个有效神经元网络再深也白搭。权重初始化的原则是对称破缺。一般推荐使用He初始化适用于ReLU族或者Xavier初始化适用于Sigmoid/Tanh。比如He初始化就是从均值为0、标准差为(\sqrt{2/n_{in}})的正态分布中采样其中(n_{in})是本层输入神经元的个数。这样做的目的是让每一层的输出方差保持在合理范围内避免信号在传播过程中过快膨胀或衰减。偏置项则可以直接初始化为0不会带来对称问题。5.3 数据标准化被忽略的前置步骤我在实际项目里见过一个很典型的反面案例一个特征的取值范围是0到10000另一个特征是0到1。网络刚训练时梯度几乎被大数值特征主导模型会非常不稳定loss曲线抖得和心电图一样。解决办法就是数据标准化Standardization让每个特征均值为0标准差为1。公式是[ x_{standardized} \frac{x - \mu}{\sigma} ]其中(\mu)是训练集上的均值(\sigma)是标准差。注意测试集上也要用训练集的均值和标准差不能拿测试集自己重新算。6. 训练过程与超参数调节一个完整的小型项目实战6.1 任务定义与数据准备我拿一个最简单的例子来展示训练过程手写数字识别。用MNIST数据集每张图是28x28的灰度图共10个类别。把每张图的像素值拉平成一个784维的向量喂给一个前馈神经网络。这个例子非常适合入门因为它的数据量适中、任务清晰而且能直观看到从全连接到卷积之间到底差了什么。先加载数据并做预处理from sklearn.datasets import fetch_openml from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler import numpy as np # 加载MNIST数据集X是图像数据y是标签 X, y fetch_openml(mnist_784, version1, return_X_yTrue, as_frameFalse) X X.astype(np.float32) # 数据标准化 scaler StandardScaler() X scaler.fit_transform(X) # 划分训练集和测试集 X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, random_state42)6.2 搭建一个两层的前馈网络这里我不用TensorFlow或者PyTorch而是直接用NumPy手写一个简单的两层网络方便你看清每一步都在干什么。这个网络结构是784输入→ 64隐藏层→ 10输出。# 参数初始化He初始化 def init_params(n_input, n_hidden, n_output): np.random.seed(42) W1 np.random.randn(n_input, n_hidden) * np.sqrt(2.0 / n_input) b1 np.zeros((1, n_hidden)) W2 np.random.randn(n_hidden, n_output) * np.sqrt(2.0 / n_hidden) b2 np.zeros((1, n_output)) return W1, b1, W2, b2 def relu(z): return np.maximum(0, z) def softmax(z): exp_z np.exp(z - np.max(z, axis1, keepdimsTrue)) # 减去最大值防止溢出 return exp_z / np.sum(exp_z, axis1, keepdimsTrue) def forward(X, W1, b1, W2, b2): z1 X W1 b1 a1 relu(z1) z2 a1 W2 b2 a2 softmax(z2) return z1, a1, z2, a2 # 初始化网络 W1, b1, W2, b2 init_params(784, 64, 10)有几点值得说明softmax里我先减去了每行的最大值再算指数这是为了防止exp计算时数值溢出ReLU在(z0)时导数不为0能够缓解梯度消失。6.3 反向传播与梯度下降更新有了前向传播再写反向传播就顺着链式法则一步步来。这里用交叉熵损失函数配合softmax输出层有一个漂亮的数学性质softmax 交叉熵的梯度等于模型预测概率减去真实标签的one-hot编码也就是[ \frac{\partial L}{\partial z_2} a_2 - y_{onehot} ]这个性质省去了一大堆中间推导代码自然就短了def compute_loss_gradients(X, y_onehot, W1, b1, W2, b2): z1, a1, z2, a2 forward(X, W1, b1, W2, b2) m X.shape[0] # 输出层梯度 dz2 a2 - y_onehot dW2 (a1.T dz2) / m db2 np.sum(dz2, axis0, keepdimsTrue) / m # 隐藏层梯度 dz1 (dz2 W2.T) * (z1 0) # ReLU的导数 dW1 (X.T dz1) / m db1 np.sum(dz1, axis0, keepdimsTrue) / m return dW1, db1, dW2, db2注意(dz1)的计算中((z1 0))是一个布尔矩阵乘上去就是把ReLU导数中负数部分清零。整个计算过程没有用到任何深度学习框架完全是从反向传播的数学原理推出来的。6.4 训练循环与关键超参数调优训练循环是最朴素的小批量梯度下降# one-hot编码标签 def one_hot(y, num_classes10): y y.astype(int) eye np.eye(num_classes) return eye[y] y_train_onehot one_hot(y_train) y_test_onehot one_hot(y_test) # 训练参数 learning_rate 0.1 epochs 50 batch_size 128 for epoch in range(epochs): # 每个epoch打乱数据 indices np.random.permutation(X_train.shape[0]) X_train_shuffled X_train[indices] y_train_shuffled y_train_onehot[indices] for i in range(0, X_train.shape[0], batch_size): X_batch X_train_shuffled[i:ibatch_size] y_batch y_train_shuffled[i:ibatch_size] dW1, db1, dW2, db2 compute_loss_gradients(X_batch, y_batch, W1, b1, W2, b2) # 更新参数 W1 - learning_rate * dW1 b1 - learning_rate * db1 W2 - learning_rate * dW2 b2 - learning_rate * db2 # 每个epoch结束后计算一次accuracy _, _, _, a2 forward(X_test, W1, b1, W2, b2) predictions np.argmax(a2, axis1) accuracy np.mean(predictions y_test.astype(int)) print(fEpoch {epoch1}/{epochs}, Test Accuracy: {accuracy:.4f})我自己在跑这个例子时大概20个epoch后准确率能到97%左右。对MNIST这种简单数据集来说一个纯手写的两层前馈网络已经表现不错了。但如果你拿它去做更复杂的任务比如CIFAR-10图像分类准确率就会直线下降这时候就该让CNN出场了。超参数方面我踩过的坑和经验可以分享一下学习率learning_rate学习率太大loss会发散参数在最优解附近震荡太小收敛极慢。推荐先用对数网格搜索0.010.0010.0001试一轮再细化。Batch sizebatch太小梯度噪声大训练不稳定batch太大收敛变慢且容易陷入局部最优。128、256是常见选择。Epoch数早停法比硬设epoch数靠谱得多——验证集loss连续好几个epoch不降就停。7. 图像处理为什么用CNN而不是前馈神经网络7.1 参数爆炸一张小图就压垮全连接层很多人在项目里问过这个问题网上答案也很多但能把过程讲透的不多。我直接拿数字说话。假设输入图像是32x32x3的彩色小图这已经是很小的分辨率了。把它拉平后得到一个(32 \times 32 \times 3 3072)维的向量。如果第一个隐藏层有1024个神经元那么这一层的权重矩阵大小就是[ 3072 \times 1024 3,145,728 ]约314万个参数。这还只是第一层。如果再多几层参数量轻松突破千万甚至上亿。那时候你想要训练好模型需要的不只是海量数据还有海量GPU显存和时间。而CNN在这种尺寸的输入上通常几百KB的模型就能干得相当漂亮。问题还不止参数数量。图像数据的维度稍微变大一点参数就按平方级别增长。这是全连接层的致命弱点它对输入维度极不友好。7.2 打乱的像素还能分类说明全连接浪费了空间结构我给新人做过一个实验把图像的所有像素随机打乱后用全连接网络训练分类。结果准确率居然没有太大变化。这说明什么说明全连接网络只学到了像素值的统计分布完全没利用图像的空间结构。图像中相邻像素是高度相关的——猫的耳朵旁边大概率还是猫的耳朵而不是随机一坨噪声。这种局部相关性是全连接网络完全不关心的。它把每个像素当成独立的特征很自然地丢掉了空间上下文信息。CNN的设计思路正好对症下药。它的关键组件是卷积核——一个小的滑动窗口比如3x3每次只看图像的一个局部区域。因为针对局部计算参数量大大减少因为同一个卷积核要在整张图上滑动不同位置共享同一套参数模型天然具备平移不变性。对比维度前馈神经网络/FNN卷积神经网络/CNN参数数量大随输入维度平方增长小取决于卷积核大小和通道数空间结构利用不利用通过局部感受野利用平移不变性不具备天然具备适合数据表格数据、向量输入图像、语音、视频等网格结构数据可解释性相对较差卷积核有一定特征提取含义7.3 从全连接到卷积感受野与权重共享我再深入一点讲CNN到底是靠哪两个思想解决了全连接的问题。第一个思想是局部感受野。每一个卷积核只连接输入图像的一个局部区域这个区域的大小就是卷积核大小。它假设图像的特征主要来自局部比如边缘、纹理、角点这些局部特征组合起来才能形成高层的语义概念。人眼看图也是这个套路——先看局部轮廓再组合全局结构。第二个思想是权重共享。同一个卷积核在整张图上反复使用意味着检测竖直边缘的核在整个图上的作用是一样的。这样网络就不需要为每一个位置各自学习一套检测边缘的参数参数数量一下子降了好几个量级。所以回到那个热搜问题不是前馈神经网络完全不能做图像而是它在图像任务上的性价比太低了。在数据量有限、计算资源固定的前提下CNN用更小的参数规模、更强的归纳偏置取得了更好的效果。如果数据量大到离谱、算力足够多理论上全连接网络也能拟合图像但那是拿钱和时间硬砸实际工程里没人这么干。8. 常见问题与训练排查实录8.1 损失不下降先检查梯度与数据我见过的训练失败案例中损失完全不动最常见的原因有三个学习率太低、梯度为零、数据没做标准化。如果loss完全没有变化先在代码里打印一下梯度的范数np.linalg.norm看是否接近0。是的话说明梯度消失了检查激活函数是不是用了Sigmoid、网络层数是不是太深。如果梯度数值巨大说明梯度爆炸可以把梯度做裁剪gradient clipping或者把学习率调小。我调试时有个习惯先拿一两个样本过拟合再全量训练。如果模型在一个样本上都记不住说明代码有bug如果单样本能过拟合但全量数据loss不降那大概率是数据预处理或者学习率的问题。8.2 训练集准确率高测试集上拉胯——过拟合的应对过拟合是前馈网络里最常遇到的问题尤其是参数多、数据少的时候。模型把训练集的细节和噪声都背下来了自然泛化不好。我常用的三板斧是增加数据量数据增强不只在图像领域有效表格数据也可以做加噪声、特征组合等扰动。正则化在损失函数后面加参数的L2范数约束让权重别太大。L2正则化的实际效果相当于让网络更平滑不轻易被单个特征带偏。Dropout则是每次训练随机丢弃一部分神经元强制网络学到冗余的特征表达而不是过度依赖某几个节点。早停法监控验证集loss一旦连续几个epoch不下降就停止训练。这比固定epoch数好用得多。下面是一个L2正则化之后参数更新的示意代码lambda_reg 0.01 # 正则化强度 dW2 lambda_reg * W2 # L2正则的梯度 dW1 lambda_reg * W1注意L2正则的梯度就等于参数本身更新时权重会向零方向收缩。这个操作简单有效推荐优先尝试。8.3 常用排查问题速查表现象可能原因排查方向Loss不下降学习率过低/梯度消失/数据未标准化打印梯度范数尝试调大学习率Loss发散到NaN学习率过高/数据有异常值调小学习率检查输入数据中是否有NaN训练集精度高测试集低过拟合加Dropout、L2正则化做数据增强训练和测试loss差距大数据分布不一致检查数据切分是否随机有无泄露中间层输出全一样权重初始化全零或对称重新初始化用He/Xavier方法准确率一直等于类别分布模型没学到有效特征检查标签是否有错是否类别不均衡9. 写在最后从知道到会用还需要几个实弹练习前馈神经网络是所有深度学习方法的地基。卷积神经网络就是加了局部连接和权重共享的前馈网络循环神经网络就是带反馈连接的前馈网络Transformer本质上也是一个参数共享的前馈结构。把这些都搞明白了再往上走你不会有那么多这到底什么鬼的困惑。按照我的经验给你留三个练习做完才算真正入门练习一手写一个两层网络在MNIST上跑到95%以上准确率。这个练习能帮你彻底掌握前向传播、反向传播和梯度下降。练习二给网络增加一个隐藏层变成3层手动调学习率、batch size和隐藏层宽度记录每一组参数对收敛速度和最终准确率的影响。这能帮你建立超参数直觉。练习三用同样的流程训练一个CNN和一个全连接网络分别在不同的数据量下对比他们的测试准确率差距。数据量少、数据量中等、数据量很大都试一遍你会发现数据量足够大的时候两者的差距在缩小甚至在纯表格任务里前馈网络还能反超。这就是为什么很多广告点击率预估、推荐系统模型至今依然选择MLP结构——特征本来就是非结构化的没有空间结构可以利用全连接反而是最合理的选择。最后给你一个实际经验不要纸上谈兵。参数初始化的差异、学习率的敏感度、激活函数带来的训练稳定性的变化这些感觉不是你读十篇文章能获得的必须亲手跑几轮才能建立直觉。训练过程中loss曲线怎么抖动、准确率怎么爬升、哪一步开始过拟合这些信号比任何理论都更能教会你如何调试模型。先动手跑通一个最小例子再逐步加复杂度这是最快的入门路径。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Redis缓存比MySQL查询快116倍?Spring Boot缓存实战全程复盘 2026/10/2 10:37:32

Redis缓存比MySQL查询快116倍?Spring Boot缓存实战全程复盘

可能很多人看到“Redis缓存比数据库查询快”这种结论,第一反应都是“哦,教科书里都这么说”。但真正让我对这个差距有切身体会的,是最近在苍穹外卖项目里做的一次压测:同一个“根据分类查询菜品列表”的接口,改造成Red…

阅读更多 →
DeepSeek V4 发布窗口临近:1T MoE + 昇腾 950PR + 1M 上下文,用 TaoToken 统一 Key 跑通开源大模型推理链路 2026/10/2 10:37:25

DeepSeek V4 发布窗口临近:1T MoE + 昇腾 950PR + 1M 上下文,用 TaoToken 统一 Key 跑通开源大模型推理链路

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

阅读更多 →
Python爬虫实战:抓取安居客新房数据简易版教程 2026/10/2 10:37:25

Python爬虫实战:抓取安居客新房数据简易版教程

朋友上周问我,说想整理一下上海各个板块的新盘报价,问我有没有现成工具。我说你自己打开安居客一页一页翻不就行了?他说三百多个楼盘,一个个点开再把单价、户型、电话复制进表格,一个晚上就没了。这个场景太熟悉了。很…

阅读更多 →
从Jev到NeoHorse-Jev-4B:开源决策模型如何重塑Agent工作流 2026/10/2 10:37:25

从Jev到NeoHorse-Jev-4B:开源决策模型如何重塑Agent工作流

Jev 这个名字最近在圈子里频繁出现,你可能也刷到过:有人在 Codex 里给它配了把“决策钥匙”,让它替 Agent 判断下一步是查数据库、改代码还是继续挖掘上下文;也有人用它在本地部署了任务调度链路;甚至有人扒出它在 Git…

阅读更多 →
JavaScript API入门:从DOM操作到事件监听的实战笔记 2026/10/2 10:37:25

JavaScript API入门:从DOM操作到事件监听的实战笔记

很多人一听到"JavaScript APIs"就觉得是另一门语言,或者是什么高不可攀的东西,尤其看到"APIs 第一天"这种标题,第一反应通常是:完了,又要背一长串函数名了。其实完全不是这么回事。API全称是Appli…

阅读更多 →
PostgreSQL DBA最常用SQL:连接、慢查询、锁与vacuum巡检实战 2026/10/2 10:37:25

PostgreSQL DBA最常用SQL:连接、慢查询、锁与vacuum巡检实战

做了这么多年 PostgreSQL DBA,我手里攒下的 SQL 片段非常多,但真正能让我每次巡检、救火、接手新环境时打开就用的,永远就那么几十条。后来我把它们整理成一个文件,起了个名字叫dba_daily.sql,新同事接手时照着跑一圈&…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉