news 2026/8/27 4:55:54

反向传播、CNN与ResNet:计算机视觉核心知识点全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
反向传播、CNN与ResNet:计算机视觉核心知识点全解析

很多同学入门计算机视觉时,都经历过这样一个阶段:从开源仓库下载了完整的图像分类项目,用现成的预训练权重跑通了 demo,准确率还挺高;可一旦把自己的业务图片丢进去,效果立刻崩掉。想调参,不知道从哪入手;想改成自己的任务,又看不懂网络定义里的每一行代码在干什么。

问题出在哪?出在很多教程把“学会调用模型”当成了“学会深度学习”。模型层的复制粘贴,替代不了底层原理的理解。计算机视觉最核心的技术主线,其实只有一条:神经网络通过前向传播做预测,通过反向传播学参数;CNN 在神经网络基础上,用卷积和池化解决图像特征提取问题;ResNet 则在 CNN 基础上,用残差学习解决了更深的网络难以训练的问题。三步走完,就是从理论到工程的关键路径。

这篇文章不打算堆砌花哨的网络结构,而是把这条主线彻底讲透。读完你会搞清楚:反向传播到底在算什么?卷积层为什么比全连接层更适合图像?ResNet 的恒等映射为什么能解决梯度消失和网络退化?文章会提供 numpy 手写反向传播、PyTorch 搭建 CNN 与 ResNet 残差块的完整代码,方便你边读边练。本文涉及的知识点,基本覆盖了计算机视觉入门阶段最关键的几个核心概念,值得收藏备用。

1. 为什么要把反向传播、CNN 和 ResNet 放在一起学

很多初学者的学习路径是割裂的:先学“反向传播的公式推导”,再学“CNN 的网络结构”,最后看一篇“ResNet 论文解读”。结果每个知识点都似懂非懂,遇到实际问题时依然无法串联起来。

从技术演进的角度看,这三个知识点不是三个并列章节,而是一条连续的升级线:

技术要解决的核心问题
反向传播神经网络的参数如何自动学习
CNN如何用少量参数高效提取图像特征
ResNet网络加深到一定程度后,如何还能被稳定训练

先有反向传播,神经网络才真正“可学习”;面对图像数据,全连接网络参数量太大且无视空间结构,于是 CNN 登场;CNN 越深效果越好,但深到一定程度后梯度消失、退化问题凸显,于是 ResNet 登场。每一次升级都对应一个真实且具体的工程痛点。理解了痛点,你就不会再问“为什么要加这一层”“为什么这里要用 1x1 卷积”这类问题。

这篇文章适合以下几类读者:

  • 刚入门深度学习,跑过分类 demo,但对底层原理不清晰的初学者。
  • 想转计算机视觉方向,正在补核心基础的非 CV 方向开发。
  • 已经在用 PyTorch 做项目,但需要系统梳理“神经网络如何训练、CNN 如何设计、ResNet 为什么有效”的工程师。

如果你处在“代码能跑但心里没底”的阶段,这篇文章的性价比会非常高。

2. 神经网络的核心:从感知机到前向传播

2.1 感知机与神经元的基本计算

神经网络的最小单位是“神经元”。最早的模型叫感知机,它的计算方式非常朴素:把输入做加权求和,再加上偏置,然后通过一个激活函数输出。

单个神经元的输出可以写成:

z = w1*x1 + w2*x2 + ... + wn*xn + b a = f(z)

其中w是权重,b是偏置,f是激活函数。权重决定“每个输入对结果的影响程度”,偏置决定“神经元被激活的难易程度”。训练神经网络的核心任务,就是找到一组最优的wb,让预测结果逼近真实标签。

单个感知机只能解决线性可分问题,能力有限。把大量神经元组织成“层”,并且堆叠多层,就形成了多层感知机。每一层接收上一层的输出,经过线性变换和激活函数后,再传给下一层。

2.2 激活函数为什么不可或缺

如果网络只有线性变换,那么多层线性变换最终可以合并成一次线性变换。也就是说,没有激活函数,无论网络多深,表达能力都和单层线性模型等价。激活函数的本质是给网络引入非线性。

常用于分类任务的激活函数有:

  • Sigmoid:将输入压缩到 0 到 1 之间,公式为 σ(z) = 1 / (1 + e^(-z)),适合二分类输出,但两端导数趋近于 0,容易梯度消失。
  • Tanh:将输入压缩到 -1 到 1 之间,比 Sigmoid 均值更接近 0,但仍存在饱和区。
  • ReLU:max(0, z),计算简单,正区间导数恒为 1,能有效缓解梯度消失,是目前 CNN 中最常用的激活函数。

从工程角度看,ReLU 的巨大优势是“导数稳定”。它在正区间导数恒为 1,多个梯度相乘时不会因为激活函数导数过小而快速衰减。这一点在后面理解 ResNet 时还会反复出现。

2.3 前向传播的矩阵表达

实际工程中不会写 for 循环逐个神经元计算,而是用矩阵运算批量完成。一个两层的全连接网络,前向传播可以写成:

Z1 = X @ W1 + b1 A1 = σ(Z1) Z2 = A1 @ W2 + b2 A2 = σ(Z2)

输入矩阵X的形状是[N, D]N是样本数,D是特征数。W1W2是两层的权重矩阵,b1b2是偏置。A1是隐藏层的输出,A2是最终输出。

这里的计算过程就是“前向传播”。前向传播本身只是完成了一次预测,真正让模型从随机初始化变成有效模型的,是接下来的反向传播。

3. 反向传播算法:让网络真正“学会”的发动机

3.1 损失函数与梯度下降

要让网络学会正确分类,首先需要一个衡量“预测到底有多差”的指标,这个指标就是损失函数。分类任务常用交叉熵损失,回归任务常用均方误差损失。

有了损失值之后,问题变成:如何通过调整wb让损失值不断变小?答案就是梯度下降。梯度的方向是函数值上升最快的方向,所以参数沿着梯度的反方向更新,就能让损失下降:

θ = θ - η * ∂L/∂θ

其中η是学习率。学习率太大,参数更新过猛,损失可能震荡甚至发散;学习率太小,网络收敛缓慢。调参时最先检查的往往就是这一项。

3.2 链式法则与两层网络推导

损失函数是网络输出的函数,而网络输出又依赖于每一层的权重。想求“损失对深层参数的梯度”,必须依赖微积分里的链式法则。这就是反向传播算法的数学基础。

以一个两层网络为例:

z1 = W1 x + b1 a1 = σ(z1) z2 = W2 a1 + b2 a2 = σ(z2) L = 0.5 * ||y - a2||^2

其中x是输入,y是标签,L是损失。要更新输出层权重W2,需要计算∂L/∂W2,用链式法则展开:

∂L/∂W2 = (∂L/∂a2) * (∂a2/∂z2) * (∂z2/∂W2)

定义误差信号:

δ2 = (a2 - y) * σ'(z2)

那么:

∂L/∂W2 = δ2 * a1^T ∂L/∂b2 = δ2

继续往更浅的一层传播,得到隐藏层的误差信号:

δ1 = (W2^T * δ2) * σ'(z1) ∂L/∂W1 = δ1 * x^T ∂L/∂b1 = δ1

这就是反向传播的核心过程:先做一次前向传播,算出每层的输出;再根据损失,从输出层逐层往回计算梯度并更新参数。为什么要叫“反向”?因为误差信号从输出层开始,逐层向输入层方向传播。

3.3 用 numpy 手动实现一次反向传播

理论知识看再多,都不如手写一个最小实现来得直观。下面用 numpy 实现一个 2-4-1 结构的两层网络,解决 XOR 异或问题。XOR 是非线性可分问题,单层感知机无法解决,但两层网络可以。

import numpy as np np.random.seed(42) # 网络结构:2 -> 4 -> 1 w1 = np.random.randn(2, 4) * 0.5 b1 = np.zeros((1, 4)) w2 = np.random.randn(4, 1) * 0.5 b2 = np.zeros((1, 1)) # XOR 数据集 X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]], dtype=np.float32) y = np.array([[0], [1], [1], [0]], dtype=np.float32) def sigmoid(z): return 1.0 / (1.0 + np.exp(-z)) learning_rate = 0.5 for epoch in range(10000): # 前向传播 z1 = X @ w1 + b1 a1 = sigmoid(z1) z2 = a1 @ w2 + b2 a2 = sigmoid(z2) loss = np.mean((a2 - y) ** 2) # 反向传播 d_a2 = 2 * (a2 - y) / len(X) d_z2 = d_a2 * a2 * (1 - a2) d_w2 = a1.T @ d_z2 d_b2 = np.sum(d_z2, axis=0, keepdims=True) d_a1 = d_z2 @ w2.T d_z1 = d_a1 * a1 * (1 - a1) d_w1 = X.T @ d_z1 d_b1 = np.sum(d_z1, axis=0, keepdims=True) # 参数更新 w2 -= learning_rate * d_w2 b2 -= learning_rate * d_b2 w1 -= learning_rate * d_w1 b1 -= learning_rate * d_b1 if epoch % 1000 == 0: print(f"Epoch {epoch:4d}, Loss: {loss:.6f}") print("训练后的预测结果(应接近 0,1,1,0):") print(np.round(a2, 4))

运行这段代码,会看到 Loss 随着迭代次数增加而下降。训练结束后,预测结果会接近 XOR 的目标输出。关键逻辑在于:d_z2是输出层误差信号,d_z1是隐藏层误差信号,而隐藏层误差信号正是由输出层误差信号乘以w2.T反向传递回来的。这就是“反向”二字的由来。

4. 卷积神经网络:面向图像的结构设计

4.1 全连接层处理图像的三大难题

把全连接网络直接用于图像,会立刻遇到三个问题:

第一,参数量爆炸。一张 32x32 的彩色图片,展开后是 3072 维。如果全连接网络第一个隐藏层有 128 个神经元,仅这一层就需要约 39 万个参数。如果是更大的图片,参数量会迅速膨胀到无法训练。

第二,破坏空间结构。图像中相邻像素有强相关性,边缘、纹理、颜色变化都体现在局部区域。把像素打平成向量后,局部信息被彻底打散,网络很难学到“物体是由局部特征组合而成”的规律。

第三,难以保持平移不变性。同一只猫在图片中位置移动一点,全连接网络需要重新学习才能识别,因为它对“每个像素位置”单独建模。

4.2 卷积层:局部感受野与参数共享

CNN 的解决方案是用卷积层替代全连接层。卷积层有两个核心设计:局部连接和参数共享。

局部连接是指每个输出神经元只与输入的一小块区域相连,这一小块区域就是“感受野”。比如 3x3 卷积核,输出位置的每个值只由输入中对应位置附近 3x3 区域的像素计算而来。

参数共享是指同一个卷积核以滑窗方式遍历整张图像,所有位置共享同一组权重。这意味着无论物体出现在图像的左上角还是右下角,同一个卷积核都能检测出同一种特征。

一个具体实例能直观说明参数量的差距。输入是 32x32x3 的图像,如果卷积层使用 32 个 3x3 卷积核,参数量为:

3 * 3 * 3 * 32 + 32 = 896

而同等情况下全连接层的参数量高达几十万。CNN 之所以能处理图像,正是因为这“一减一

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

FX3U高速计数器+摆杆编码器实现±0.1°高精度角度测量

1. 项目概述:为什么摆杆编码器配FX3U高速计数器是工业现场最稳的角度测量方案在自动化产线调试现场,我见过太多因为角度反馈不准导致的定位偏差——伺服电机停在目标位置前后晃动0.5,机械手抓取工件时反复微调,节拍硬生生拖慢2秒&…

作者头像 李华
网站建设 2026/8/27 4:55:07

Claude Code配置本地模型指南:从Ollama到DeepSeek的完整实践

1. 从“云端依赖”到“本地掌控”:为什么我们需要在 Claude Code 里配置本地模型?如果你和我一样,是个重度依赖 Claude Code 来写代码、重构、调试的程序员,那你肯定经历过这种时刻:灵光一闪,想快速让 AI 帮…

作者头像 李华
网站建设 2026/8/27 4:51:22

数字版权保护实战:从指纹识别到风险评估的量化模型构建

1. 从一道赛题看数字版权保护的现实困境去年,我带着几个学生组队参加了深圳杯数学建模竞赛,B题“电子资源版权保护问题”让我们团队陷入了长达数天的激烈讨论。这道题看似是一个经典的数学建模问题,但当我们真正开始构建模型、寻找数据、编写…

作者头像 李华
网站建设 2026/8/27 4:51:09

C盘满了怎么办?从空间分析到安全清理与扩容的全面指南

首先说一个判断: C盘满了,不是靠一个“清理工具”就能根治的。 很多人遇到C盘爆红,第一反应是下载各种“C盘清理大师”“垃圾清理神器”,结果装了一堆软件,空间没少,反而多了几个弹窗广告。更麻烦的是&a…

作者头像 李华
网站建设 2026/8/27 4:49:36

MATLAB主成分分析(PCA)实战:从原理到数学建模应用

1. 项目概述:主成分分析在数学建模中的核心价值在数学建模竞赛和实际数据分析工作中,我们常常会遇到一个令人头疼的问题:手头的数据集变量太多,几十甚至上百个指标纠缠在一起,不仅让模型变得臃肿复杂,还容易…

作者头像 李华
网站建设 2026/8/27 4:47:51

OpenMontage:AI驱动的视频叙事引擎,重塑内容创作工作流

1. 从“拼接”到“叙事”:OpenMontage 是什么,以及它为何值得你关注如果你最近在社交媒体、视频创作社区或者一些技术论坛里逛过,可能已经不止一次地看到OpenMontage这个名字了。它听起来像是一个新的视频剪辑软件,但如果你仅仅把…

作者头像 李华