欢迎光临
我们一直在努力

【机器学习精通】第8章 | 神经网络基础:感知机到多层感知机

摘要:本章深入讲解神经网络的基础理论,从生物神经元启发到感知机模型,揭示单层感知机的局限性,完整推导多层感知机的结构与反向传播算法,详解激活函数演进历程与权重初始化策略,并通过NumPy从零实现神经网络完成手写数字分类实战。


环境声明

  • Python版本:Python 3.12+
  • 核心依赖:NumPy 1.24+, Matplotlib 3.7+, Scikit-learn 1.3+
  • 开发工具:PyCharm / VS Code / Jupyter Notebook
  • 操作系统:Windows / macOS / Linux

pip install numpy matplotlib scikit-learn


学习目标

完成本章学习后,你将能够:

  • 理解生物神经元的工作机制与人工神经元的数学抽象
  • 掌握感知机模型的原理、训练算法及其局限性
  • 独立完成多层感知机前向传播与反向传播的数学推导
  • 深入理解链式法则在梯度计算中的应用
  • 熟练运用各类激活函数的特点与适用场景
  • 掌握Xavier与He权重初始化方法的数学原理
  • 使用NumPy从零实现完整的神经网络训练流程
  • 独立完成手写数字分类实战项目

  • 1. 感知机原理与局限性

    1.1 生物神经元的启发

    神经网络的设计灵感来源于生物神经系统。人脑约包含860亿个神经元,每个神经元通过突触与其他神经元连接,形成复杂的网络结构。

    生物神经元的工作机制:

    组成部分功能描述
    树突 接收来自其他神经元的信号输入
    细胞体 整合输入信号,进行信息处理
    轴突 输出信号至其他神经元
    突触 连接不同神经元的信号传递节点

    信息传递过程:

  • 树突接收来自多个前驱神经元的电化学信号
  • 细胞体对输入信号进行加权求和
  • 当膜电位超过阈值时,产生动作电位(脉冲)
  • 信号通过轴突传递至下游神经元
  • 关键特性:

    • 整合性:神经元整合多个输入信号
    • 阈值特性:只有超过阈值才触发输出
    • 可塑性:突触连接强度可随学习改变

    1.2 感知机模型

    1943年,McCulloch和Pitts提出了第一个人工神经元模型(M-P模型)。1957年,Frank Rosenblatt在此基础上发明了感知机(Perceptron),成为神经网络发展的里程碑。

    感知机的数学模型:

    y=f(∑i=1nwixi+b)=f(wTx+b)y = f\\left(\\sum_{i=1}^{n} w_i x_i + b\\right) = f(w^T x + b)y=f(i=1nwixi+b)=f(wTx+b)

    其中:

    • x=[x1,x2,…,xn]Tx = [x_1, x_2, …, x_n]^Tx=[x1,x2,,xn]T 为输入特征向量
    • w=[w1,w2,…,wn]Tw = [w_1, w_2, …, w_n]^Tw=[w1,w2,,wn]T 为权重向量
    • bbb 为偏置项
    • f(⋅)f(\\cdot)f() 为激活函数(通常使用阶跃函数)

    阶跃函数定义:

    f(z)={1if z≥00if z<0f(z) = \\begin{cases} 1 & \\text{if } z \\geq 0 \\\\ 0 & \\text{if } z < 0 \\end{cases}f(z)={10if z0if z<0

    感知机的几何解释:

    感知机在特征空间中定义了一个超平面 wTx+b=0w^T x + b = 0wTx+b=0,将空间划分为两个区域:

    • 超平面一侧的样本被分类为正类(输出1)
    • 另一侧的样本被分类为负类(输出0)

    1.3 感知机学习算法

    感知机使用迭代算法更新权重,核心思想是:当分类错误时,调整权重使超平面向误分类样本移动。

    算法步骤:

    输入: 训练集 {(x_i, y_i)},学习率 η
    初始化: w = 0, b = 0
    重复:
    对于每个样本 (x_i, y_i):
    计算预测值: ŷ = sign(w^T x_i + b)
    如果 ŷ ≠ y_i:
    w ← w + η * y_i * x_i
    b ← b + η * y_i
    直到所有样本被正确分类或达到最大迭代次数

    权重更新规则的推导:

    当样本 (xi,yi)(x_i, y_i)(xi,yi) 被误分类时,满足 yi(wTxi+b)≤0y_i(w^T x_i + b) \\leq 0yi(wTxi+b)0

    更新后的权重应满足:

    yi(wnewTxi+bnew)=yi[(w+ηyixi)Txi+(b+ηyi)]y_i(w_{new}^T x_i + b_{new}) = y_i[(w + \\eta y_i x_i)^T x_i + (b + \\eta y_i)]yi(wnewTxi+bnew)=yi[(w+ηyixi)Txi+(b+ηyi)]

    =yi(wTxi+b)+ηyi2xiTxi+ηyi2= y_i(w^T x_i + b) + \\eta y_i^2 x_i^T x_i + \\eta y_i^2=yi(wTxi+b)+ηyi2xiTxi+ηyi2

    =yi(wTxi+b)+η(∥xi∥2+1)>yi(wTxi+b)= y_i(w^T x_i + b) + \\eta (\\|x_i\\|^2 + 1) > y_i(w^T x_i + b)=yi(wTxi+b)+η(xi2+1)>yi(wTxi+b)

    这表明更新后,样本被正确分类的可能性增加。

    收敛性定理(Novikoff, 1962):

    如果训练数据线性可分,感知机算法在有限步内收敛。设:

    • R=max⁡i∥xi∥R = \\max_i \\|x_i\\|R=maxixi 为样本的最大范数
    • γ\\gammaγ 为分离超平面的几何间隔

    则收敛所需的更新次数不超过 (R/γ)2(R/\\gamma)^2(R/γ)2

    1.4 感知机的局限性:异或问题

    1969年,Minsky和Papert在《Perceptrons》一书中证明了单层感知机的致命局限:无法解决非线性可分问题。

    异或问题(XOR Problem):

    x1x_1x1x2x_2x2XOR输出
    0 0 0
    0 1 1
    1 0 1
    1 1 0

    几何分析:

    在二维平面上,异或问题的四个样本点分布如下:

    • 负类(输出0):(0,0) 和 (1,1)
    • 正类(输出1):(0,1) 和 (1,0)

    不存在一条直线能将两类样本完全分开。正类样本位于对角位置,任何线性超平面都无法正确分类。

    深层原因:

    感知机只能表示线性函数,而异或问题是非线性可分的。这一发现导致神经网络研究进入第一次寒冬期。

    补充:Minsky的批评虽然指出了单层感知机的局限,但也为多层网络的发展指明了方向。1986年,Rumelhart等人提出反向传播算法,使训练多层网络成为可能,开启了神经网络的复兴。


    2. 多层感知机结构

    2.1 从单层到多层

    多层感知机(Multi-Layer Perceptron, MLP)通过引入隐藏层,解决了单层感知机的非线性问题。MLP也被称为前馈神经网络(Feedforward Neural Network)或深度神经网络(DNN)。

    MLP的核心创新:

  • 隐藏层:在输入层和输出层之间添加一个或多个隐藏层
  • 非线性激活:使用非线性激活函数,使网络具备表示复杂函数的能力
  • 分层特征提取:低层提取简单特征,高层组合形成复杂特征
  • 万能近似定理(Universal Approximation Theorem):

    1989年,Cybenko和Hornik等人证明:具有至少一个隐藏层的前馈神经网络,只要隐藏层神经元数量足够,配合非线性激活函数,可以以任意精度近似任何连续函数。

    数学表述:设 σ(⋅)\\sigma(\\cdot)σ() 为非线性激活函数,K⊂RnK \\subset \\mathbb{R}^nKRn 为紧致集,f:K→Rf: K \\to \\mathbb{R}f:KR 为连续函数。对于任意 ϵ>0\\epsilon > 0ϵ>0,存在整数 NNN、权重 wiw_iwi、偏置 bib_ibiviv_ivi,使得:
    ∣f(x)−∑i=1Nviσ(wiTx+bi)∣<ϵ\\left|f(x) – \\sum_{i=1}^{N} v_i \\sigma(w_i^T x + b_i)\\right| < \\epsilonf(x)i=1Nviσ(wiTx+bi)<ϵ
    对所有 x∈Kx \\in KxK 成立。

    2.2 网络层结构详解

    一个典型的三层MLP包含:输入层、一个隐藏层、输出层。

    输入层:

    • 接收原始特征数据
    • 神经元数量等于特征维度
    • 不对数据进行任何变换

    隐藏层:

    • 进行非线性特征变换
    • 神经元数量和层数是超参数
    • 每个神经元执行:hj=σ(∑iwjixi+bj)h_j = \\sigma(\\sum_i w_{ji} x_i + b_j)hj=σ(iwjixi+bj)

    输出层:

    • 产生最终预测结果
    • 神经元数量取决于任务类型
    • 回归任务:1个神经元(线性输出)
    • 二分类:1个神经元(Sigmoid输出)
    • 多分类:KKK 个神经元(Softmax输出)

    层间连接:

    • 全连接(Dense):每层神经元与下一层所有神经元相连
    • 权重矩阵 W[l]∈Rnl×nl−1W^{[l]} \\in \\mathbb{R}^{n_l \\times n_{l-1}}W[l]Rnl×nl1
    • 偏置向量 b[l]∈Rnlb^{[l]} \\in \\mathbb{R}^{n_l}b[l]Rnl

    2.3 前向传播算法

    前向传播(Forward Propagation)计算网络输出,是神经网络推理和训练的基础。

    符号定义:

    符号含义维度
    LLL 网络总层数(含输入输出层) 标量
    n[l]n^{[l]}n[l] lll 层的神经元数量 标量
    W[l]W^{[l]}W[l] lll 层的权重矩阵 (n[l],n[l−1])(n^{[l]}, n^{[l-1]})(n[l],n[l1])
    b[l]b^{[l]}b[l] lll 层的偏置向量 (n[l],1)(n^{[l]}, 1)(n[l],1)
    z[l]z^{[l]}z[l] lll 层的线性输出 (n[l],1)(n^{[l]}, 1)(n[l],1)
    a[l]a^{[l]}a[l] lll 层的激活输出 (n[l],1)(n^{[l]}, 1)(n[l],1)
    σ[l]\\sigma^{[l]}σ[l] lll 层的激活函数

    前向传播公式:

    对于第 lll 层(l=1,2,…,Ll = 1, 2, …, Ll=1,2,,L):

    z[l]=W[l]a[l−1]+b[l]z^{[l]} = W^{[l]} a^{[l-1]} + b^{[l]}z[l]=W[l]a[l1]+b[l]

    a[l]=σ[l](z[l])a^{[l]} = \\sigma^{[l]}(z^{[l]})a[l]=σ[l](z[l])

    其中 a[0]=xa^{[0]} = xa[0]=x 为输入。

    向量化的批量计算:

    对于 mmm 个样本的批量数据 X∈Rn[0]×mX \\in \\mathbb{R}^{n^{[0]} \\times m}XRn[0]×m

    Z[l]=W[l]A[l−1]+b[l]Z^{[l]} = W^{[l]} A^{[l-1]} + b^{[l]}Z[l]=W[l]A[l1]+b[l]

    A[l]=σ[l](Z[l])A^{[l]} = \\sigma^{[l]}(Z^{[l]})A[l]=σ[l](Z[l])

    其中 A[l]∈Rn[l]×mA^{[l]} \\in \\mathbb{R}^{n^{[l]} \\times m}A[l]Rn[l]×m,偏置 b[l]b^{[l]}b[l] 通过广播机制自动扩展。

    计算图表示:

    输入 X → [线性: Z = WX + b] → [激活: A = σ(Z)] → 输出
    ↑ ↑
    权重W 激活函数
    偏置b


    3. 反向传播算法详解

    3.1 问题定义与目标

    神经网络的训练目标是最小化损失函数:

    min⁡W,b1m∑i=1mL(yi,y^i)\\min_{W, b} \\frac{1}{m} \\sum_{i=1}^{m} \\mathcal{L}(y_i, \\hat{y}_i)W,bminm1i=1mL(yi,y^i)

    其中 L\\mathcal{L}L 为损失函数,y^i\\hat{y}_iy^i 为网络预测输出。

    核心问题:如何高效计算损失函数对所有参数的梯度?

    解决方案:反向传播算法(Backpropagation),由Rumelhart、Hinton和Williams于1986年提出。

    3.2 链式法则基础

    反向传播的核心是微积分中的链式法则(Chain Rule)。

    单变量链式法则:

    y=f(u)y = f(u)y=f(u)u=g(x)u = g(x)u=g(x),则:

    dydx=dydu⋅dudx\\frac{dy}{dx} = \\frac{dy}{du} \\cdot \\frac{du}{dx}dxdy=dudydxdu

    多变量链式法则:

    y=f(u1,u2,…,un)y = f(u_1, u_2, …, u_n)y=f(u1,u2,,un)ui=gi(x)u_i = g_i(x)ui=gi(x),则:

    ∂ypartialx=∑i=1n∂y∂ui⋅∂ui∂x\\frac{\\partial y}{partial x} = \\sum_{i=1}^{n} \\frac{\\partial y}{\\partial u_i} \\cdot \\frac{\\partial u_i}{\\partial x}partialxy=i=1nuiyxui

    3.3 反向传播的数学推导

    定义第 lll 层的误差项(Error Term):

    δ[l]=∂L∂z[l]\\delta^{[l]} = \\frac{\\partial \\mathcal{L}}{\\partial z^{[l]}}δ[l]=z[l]L

    表示损失函数对第 lll 层线性输出的梯度。

    输出层的误差计算:

    对于输出层 LLL

    δ[L]=∂L∂z[L]=∂L∂a[L]⊙σ′[L](z[L])\\delta^{[L]} = \\frac{\\partial \\mathcal{L}}{\\partial z^{[L]}} = \\frac{\\partial \\mathcal{L}}{\\partial a^{[L]}} \\odot \\sigma'^{[L]}(z^{[L]})δ[L]=z[L]L=a[L]Lσ[L](z[L])

    其中 ⊙\\odot 表示逐元素乘法(Hadamard积)。

    隐藏层的误差反向传播:

    lll 层的误差可由第 l+1l+1l+1 层计算得到:

    δ[l]=∂L∂z[l]=∂L∂z[l+1]⋅∂z[l+1]∂a[l]⋅∂a[l]∂z[l]\\delta^{[l]} = \\frac{\\partial \\mathcal{L}}{\\partial z^{[l]}} = \\frac{\\partial \\mathcal{L}}{\\partial z^{[l+1]}} \\cdot \\frac{\\partial z^{[l+1]}}{\\partial a^{[l]}} \\cdot \\frac{\\partial a^{[l]}}{\\partial z^{[l]}}δ[l]=z[l]L=z[l+1]La[l]z[l+1]z[l]a[l]

    =(W[l+1]Tδ[l+1])⊙σ′[l](z[l])= (W^{[l+1]T} \\delta^{[l+1]}) \\odot \\sigma'^{[l]}(z^{[l]})=(W[l+1]Tδ[l+1])σ[l](z[l])

    参数梯度的计算:

    得到误差项后,权重和偏置的梯度为:

    ∂L∂W[l]=δ[l]a[l−1]T\\frac{\\partial \\mathcal{L}}{\\partial W^{[l]}} = \\delta^{[l]} a^{[l-1]T}W[l]L=δ[l]a[l1]T

    ∂L∂b[l]=δ[l]\\frac{\\partial \\mathcal{L}}{\\partial b^{[l]}} = \\delta^{[l]}b[l]L=δ[l]

    完整的反向传播流程:

    步骤操作公式
    1 前向传播 计算并保存所有 z[l]z^{[l]}z[l]a[l]a^{[l]}a[l]
    2 输出层误差 δ[L]=∇a[L]L⊙σ′[L](z[L])\\delta^{[L]} = \\nabla_{a^{[L]}}\\mathcal{L} \\odot \\sigma'^{[L]}(z^{[L]})δ[L]=a[L]Lσ[L](z[L])
    3 反向传播误差 δ[l]=(W[l+1]Tδ[l+1])⊙σ′[l](z[l])\\delta^{[l]} = (W^{[l+1]T} \\delta^{[l+1]}) \\odot \\sigma'^{[l]}(z^{[l]})δ[l]=(W[l+1]Tδ[l+1])σ[l](z[l])
    4 计算梯度 ∂L∂W[l]=δ[l]a[l−1]T\\frac{\\partial \\mathcal{L}}{\\partial W^{[l]}} = \\delta^{[l]} a^{[l-1]T}W[l]L=δ[l]a[l1]T∂L∂b[l]=δ[l]\\frac{\\partial \\mathcal{L}}{\\partial b^{[l]}} = \\delta^{[l]}b[l]L=δ[l]
    5 参数更新 W[l]←W[l]−η∂L∂W[l]W^{[l]} \\leftarrow W^{[l]} – \\eta \\frac{\\partial \\mathcal{L}}{\\partial W^{[l]}}W[l]W[l]ηW[l]L

    3.4 梯度下降与参数更新

    批量梯度下降(Batch GD):

    使用全部训练数据计算梯度:

    W[l]:=W[l]−ηm∑i=1m∂Li∂W[l]W^{[l]} := W^{[l]} – \\frac{\\eta}{m} \\sum_{i=1}^{m} \\frac{\\partial \\mathcal{L}_i}{\\partial W^{[l]}}W[l]:=W[l]mηi=1mW[l]Li

    随机梯度下降(SGD):

    每次使用单个样本:

    W[l]:=W[l]−η∂Li∂W[l]W^{[l]} := W^{[l]} – \\eta \\frac{\\partial \\mathcal{L}_i}{\\partial W^{[l]}}W[l]:=W[l]ηW[l]Li

    小批量梯度下降(Mini-batch GD):

    使用 bbb 个样本的批量:

    W[l]:=W[l]−ηb∑i=1b∂Li∂W[l]W^{[l]} := W^{[l]} – \\frac{\\eta}{b} \\sum_{i=1}^{b} \\frac{\\partial \\mathcal{L}_i}{\\partial W^{[l]}}W[l]:=W[l]bηi=1bW[l]Li

    这是实践中最常用的方法,兼顾计算效率和收敛稳定性。


    4. 激活函数演进

    激活函数引入非线性,是神经网络能够学习复杂模式的关键。不同激活函数有不同的特性,选择合适的激活函数对网络性能至关重要。

    4.1 Sigmoid函数

    定义:

    σ(x)=11+e−x\\sigma(x) = \\frac{1}{1 + e^{-x}}σ(x)=1+ex1

    导数:

    σ′(x)=σ(x)(1−σ(x))\\sigma'(x) = \\sigma(x)(1 – \\sigma(x))σ(x)=σ(x)(1σ(x))

    特点:

    优点缺点
    输出范围(0,1),可解释为概率 两端饱和,梯度趋近于0
    平滑可导 输出非零中心化
    计算涉及指数,开销较大

    梯度消失问题:

    ∣x∣|x|x 较大时,σ′(x)≈0\\sigma'(x) \\approx 0σ(x)0,导致深层网络梯度消失,参数无法更新。

    4.2 Tanh函数

    定义:

    tanh⁡(x)=ex−e−xex+e−x=2σ(2x)−1\\tanh(x) = \\frac{e^x – e^{-x}}{e^x + e^{-x}} = 2\\sigma(2x) – 1tanh(x)=ex+exexex=2σ(2x)1

    导数:

    tanh⁡′(x)=1−tanh⁡2(x)\\tanh'(x) = 1 – \\tanh^2(x)tanh(x)=1tanh2(x)

    特点:

    • 输出范围(-1,1),零中心化
    • 相比Sigmoid,梯度更强(最大值为1)
    • 仍存在饱和问题

    4.3 ReLU函数

    定义:

    ReLU(x)=max⁡(0,x)\\text{ReLU}(x) = \\max(0, x)ReLU(x)=max(0,x)

    导数:

    ReLU′(x)={1x>00x<0\\text{ReLU}'(x) = \\begin{cases} 1 & x > 0 \\\\ 0 & x < 0 \\end{cases}ReLU(x)={10x>0x<0

    特点:

    优点缺点
    计算简单,无指数运算 负值区域神经元"死亡"
    缓解梯度消失问题 输出非零中心化
    收敛速度快

    神经元死亡问题:

    当输入为负时,梯度为0,神经元不再更新。如果大量神经元死亡,网络表达能力下降。

    4.4 Leaky ReLU与PReLU

    Leaky ReLU:

    LeakyReLU(x)=max⁡(αx,x)\\text{LeakyReLU}(x) = \\max(\\alpha x, x)LeakyReLU(x)=max(αx,x)

    其中 α\\alphaα 为小的正数(通常0.01),允许负值区域有小的梯度。

    PReLU(Parametric ReLU):

    α\\alphaα 设为可学习参数,让网络自适应调整。

    4.5 Swish函数

    2017年,Google Brain通过自动搜索发现Swish激活函数。

    定义:

    Swish(x)=x⋅σ(x)=x1+e−x\\text{Swish}(x) = x \\cdot \\sigma(x) = \\frac{x}{1 + e^{-x}}Swish(x)=xσ(x)=1+exx

    特点:

    • 自门控机制:输入自身作为门控信号
    • 在负值区域有非单调性
    • 在深层网络中表现优于ReLU
    • 计算开销略高于ReLU

    4.6 GELU函数

    GELU(Gaussian Error Linear Unit)是BERT、GPT等Transformer模型的默认激活函数。

    定义:

    GELU(x)=x⋅Φ(x)=x⋅12[1+erf(x2)]\\text{GELU}(x) = x \\cdot \\Phi(x) = x \\cdot \\frac{1}{2}\\left[1 + \\text{erf}\\left(\\frac{x}{\\sqrt{2}}\\right)\\right]GELU(x)=xΦ(x)=x21[1+erf(2x)]

    其中 Φ(x)\\Phi(x)Φ(x) 为标准正态分布的累积分布函数。

    近似计算:

    GELU(x)≈0.5x(1+tanh⁡[2π(x+0.044715×3)])\\text{GELU}(x) \\approx 0.5x\\left(1 + \\tanh\\left[\\sqrt{\\frac{2}{\\pi}}\\left(x + 0.044715x^3\\right)\\right]\\right)GELU(x)0.5x(1+tanh[π2(x+0.044715x3)])

    特点:

    • 平滑非单调,处处可导
    • 在Transformer架构中表现优异
    • 计算复杂度较高

    4.7 激活函数选择指南

    场景推荐激活函数原因
    隐藏层(通用) ReLU / Leaky ReLU 计算高效,缓解梯度消失
    深层CNN ReLU / Swish 收敛快,性能好
    Transformer GELU 与自注意力机制配合好
    输出层(二分类) Sigmoid 输出概率解释
    输出层(多分类) Softmax 多类概率归一化
    输出层(回归) 线性(无激活) 无界输出

    5. 权重初始化策略

    权重初始化对神经网络的训练至关重要。不良的初始化可能导致梯度消失、梯度爆炸或对称性问题。

    5.1 零初始化与随机初始化

    零初始化:

    所有权重设为0。导致所有神经元计算相同输出,梯度相同,无法学习不同特征。

    随机初始化:

    从均匀分布或正态分布采样:

    Wij∼U(−ϵ,ϵ)或Wij∼N(0,σ2)W_{ij} \\sim \\mathcal{U}(-\\epsilon, \\epsilon) \\quad \\text{或} \\quad W_{ij} \\sim \\mathcal{N}(0, \\sigma^2)WijU(ϵ,ϵ)WijN(0,σ2)

    问题:当网络较深时,方差可能逐层累积或衰减。

    5.2 Xavier初始化

    2010年,Xavier Glorot和Yoshua Bengio提出Xavier初始化(也称Glorot初始化)。

    核心思想:

    保持每层输入和输出的方差一致,防止信号在前向传播中爆炸或消失。

    数学推导:

    假设:

    • 权重独立同分布,均值为0
    • 输入与权重独立
    • 激活函数在0附近近似线性

    对于第 lll 层:

    z[l]=∑j=1n[l−1]wj[l]aj[l−1]z^{[l]} = \\sum_{j=1}^{n^{[l-1]}} w_j^{[l]} a_j^{[l-1]}z[l]=j=1n[l1]wj[l]aj[l1]

    方差:

    Var(z[l])=n[l−1]⋅Var(w[l])⋅Var(a[l−1])\\text{Var}(z^{[l]}) = n^{[l-1]} \\cdot \\text{Var}(w^{[l]}) \\cdot \\text{Var}(a^{[l-1]})Var(z[l])=n[l1]Var(w[l])Var(a[l1])

    为使 Var(z[l])=Var(a[l−1])\\text{Var}(z^{[l]}) = \\text{Var}(a^{[l-1]})Var(z[l])=Var(a[l1]),需要:

    Var(w[l])=1n[l−1]\\text{Var}(w^{[l]}) = \\frac{1}{n^{[l-1]}}Var(w[l])=n[l1]1

    同时考虑反向传播,取平均:

    Var(w[l])=2n[l−1]+n[l]\\text{Var}(w^{[l]}) = \\frac{2}{n^{[l-1]} + n^{[l]}}Var(w[l])=n[l1]+n[l]2

    Xavier初始化公式:

    W[l]∼U(−6n[l−1]+n[l],6n[l−1]+n[l])W^{[l]} \\sim \\mathcal{U}\\left(-\\sqrt{\\frac{6}{n^{[l-1]} + n^{[l]}}}, \\sqrt{\\frac{6}{n^{[l-1]} + n^{[l]}}}\\right)W[l]U(n[l1]+n[l]6,n[l1]+n[l]6)

    或正态分布:

    W[l]∼N(0,2n[l−1]+n[l])W^{[l]} \\sim \\mathcal{N}\\left(0, \\frac{2}{n^{[l-1]} + n^{[l]}}\\right)W[l]N(0,n[l1]+n[l]2)

    适用场景:

    • 配合Sigmoid或Tanh激活函数
    • 全连接层和卷积层

    5.3 He初始化

    2015年,Kaiming He等人针对ReLU激活函数提出He初始化。

    核心思想:

    ReLU将负值置为0,导致输出方差减半。需要调整初始化方差进行补偿。

    数学推导:

    对于ReLU,约一半的神经元输出为0,因此:

    Var(a[l])=12n[l−1]Var(w[l])Var(a[l−1])\\text{Var}(a^{[l]}) = \\frac{1}{2} n^{[l-1]} \\text{Var}(w^{[l]}) \\text{Var}(a^{[l-1]})Var(a[l])=21n[l1]Var(w[l])Var(a[l1])

    为使方差保持一致:

    Var(w[l])=2n[l−1]\\text{Var}(w^{[l]}) = \\frac{2}{n^{[l-1]}}Var(w[l])=n[l1]2

    He初始化公式:

    W[l]∼N(0,2n[l−1])W^{[l]} \\sim \\mathcal{N}\\left(0, \\frac{2}{n^{[l-1]}}\\right)W[l]N(0,n[l1]2)

    或均匀分布:

    W[l]∼U(−6n[l−1],6n[l−1])W^{[l]} \\sim \\mathcal{U}\\left(-\\sqrt{\\frac{6}{n^{[l-1]}}}, \\sqrt{\\frac{6}{n^{[l-1]}}}\\right)W[l]U(n[l1]6,n[l1]6)

    适用场景:

    • 配合ReLU及其变体(Leaky ReLU、PReLU)
    • 现代深度网络的标准初始化方法

    5.4 正交初始化

    核心思想:

    使用正交矩阵初始化权重,保持范数在传播过程中不变。

    方法:

  • 从标准正态分布生成随机矩阵
  • 进行QR分解得到正交矩阵
  • 使用正交矩阵作为初始权重
  • 优势:

    • 防止梯度消失和爆炸
    • 适用于RNN等循环网络

    5.5 初始化方法选择

    激活函数推荐初始化方法
    Sigmoid / Tanh Xavier初始化
    ReLU / Leaky ReLU He初始化
    线性激活 Xavier初始化
    深层网络 He初始化或正交初始化

    6. 损失函数设计

    损失函数衡量预测值与真实值的差异,指导网络参数更新。

    6.1 均方误差(MSE)

    定义:

    LMSE=1m∑i=1m(yi−y^i)2\\mathcal{L}_{\\text{MSE}} = \\frac{1}{m} \\sum_{i=1}^{m} (y_i – \\hat{y}_i)^2LMSE=m1i=1m(yiy^i)2

    适用场景:

    • 回归任务
    • 输出为连续值

    梯度:

    ∂L∂y^i=−2m(yi−y^i)\\frac{\\partial \\mathcal{L}}{\\partial \\hat{y}_i} = -\\frac{2}{m}(y_i – \\hat{y}_i)y^iL=m2(yiy^i)

    6.2 交叉熵损失

    二分类交叉熵:

    LBCE=−1m∑i=1m[yilog⁡(y^i)+(1−yi)log⁡(1−y^i)]\\mathcal{L}_{\\text{BCE}} = -\\frac{1}{m} \\sum_{i=1}^{m} \\left[y_i \\log(\\hat{y}_i) + (1-y_i)\\log(1-\\hat{y}_i)\\right]LBCE=m1i=1m[yilog(y^i)+(1yi)log(1y^i)]

    多分类交叉熵(Softmax Loss):

    LCE=−1m∑i=1m∑k=1Kyiklog⁡(y^ik)\\mathcal{L}_{\\text{CE}} = -\\frac{1}{m} \\sum_{i=1}^{m} \\sum_{k=1}^{K} y_{ik} \\log(\\hat{y}_{ik})LCE=m1i=1mk=1Kyiklog(y^ik)

    其中 y^ik=ezik∑jezij\\hat{y}_{ik} = \\frac{e^{z_{ik}}}{\\sum_{j}e^{z_{ij}}}y^ik=jezijezik 为Softmax输出。

    适用场景:

    • 分类任务
    • 与Sigmoid/Softmax输出层配合

    优势:

    • 梯度形式简洁,收敛快
    • 对错误预测惩罚更大

    6.3 Hinge Loss

    定义:

    Lhinge=1m∑i=1mmax⁡(0,1−yi⋅y^i)\\mathcal{L}_{\\text{hinge}} = \\frac{1}{m} \\sum_{i=1}^{m} \\max(0, 1 – y_i \\cdot \\hat{y}_i)Lhinge=m1i=1mmax(0,1yiy^i)

    其中 yi∈{−1,+1}y_i \\in \\{-1, +1\\}yi{1,+1}

    适用场景:

    • 支持向量机
    • 最大间隔分类

    6.4 损失函数选择指南

    任务类型输出层损失函数
    回归 线性 MSE / MAE
    二分类 Sigmoid 二分类交叉熵
    多分类 Softmax 多分类交叉熵
    多标签分类 Sigmoid 二分类交叉熵(每个标签独立)

    7. 实战案例:使用NumPy从零实现神经网络进行手写数字分类

    7.1 项目概述

    本实战案例使用纯NumPy实现一个多层感知机,完成MNIST手写数字分类任务。通过从零实现,深入理解神经网络的每个细节。

    7.2 完整代码实现

    """
    使用NumPy从零实现神经网络
    任务:MNIST手写数字分类
    """

    import numpy as np
    import matplotlib.pyplot as plt
    from sklearn.datasets import fetch_openml
    from sklearn.model_selection import train_test_split
    from sklearn.preprocessing import OneHotEncoder
    from sklearn.metrics import accuracy_score, confusion_matrix
    import warnings
    warnings.filterwarnings('ignore')

    # 设置随机种子保证可复现
    np.random.seed(42)

    class NeuralNetwork:
    """
    多层感知机神经网络
    支持任意层数和每层的神经元数量
    """

    def __init__(self, layer_dims, activation='relu', initialization='he'):
    """
    初始化神经网络

    参数:
    layer_dims: 列表,包含每层神经元数量 [输入层, 隐藏层1, …, 输出层]
    activation: 隐藏层激活函数,可选 'relu', 'tanh', 'sigmoid'
    initialization: 权重初始化方法,可选 'he', 'xavier', 'random'
    """
    self.layer_dims = layer_dims
    self.num_layers = len(layer_dims) 1 # 不包含输入层
    self.activation = activation
    self.initialization = initialization
    self.parameters = {}
    self.caches = {}

    # 初始化权重和偏置
    self._initialize_parameters()

    def _initialize_parameters(self):
    """
    初始化网络参数(权重和偏置)
    """

    for l in range(1, self.num_layers + 1):
    n_prev = self.layer_dims[l1] # 前一层神经元数量
    n_curr = self.layer_dims[l] # 当前层神经元数量

    if self.initialization == 'he':
    # He初始化:适用于ReLU
    std = np.sqrt(2.0 / n_prev)
    self.parameters[f'W{l}'] = np.random.randn(n_curr, n_prev) * std

    elif self.initialization == 'xavier':
    # Xavier初始化:适用于Sigmoid/Tanh
    limit = np.sqrt(6.0 / (n_prev + n_curr))
    self.parameters[f'W{l}'] = np.random.uniform(limit, limit,
    (n_curr, n_prev))

    else: # random
    self.parameters[f'W{l}'] = np.random.randn(n_curr, n_prev) * 0.01

    # 偏置初始化为0
    self.parameters[f'b{l}'] = np.zeros((n_curr, 1))

    def _relu(self, Z):
    """ReLU激活函数"""
    return np.maximum(0, Z)

    def _relu_derivative(self, Z):
    """ReLU导数"""
    return (Z > 0).astype(float)

    def _sigmoid(self, Z):
    """Sigmoid激活函数"""
    return 1 / (1 + np.exp(Z))

    def _sigmoid_derivative(self, Z):
    """Sigmoid导数"""
    s = self._sigmoid(Z)
    return s * (1 s)

    def _tanh(self, Z):
    """Tanh激活函数"""
    return np.tanh(Z)

    def _tanh_derivative(self, Z):
    """Tanh导数"""
    return 1 np.tanh(Z) ** 2

    def _softmax(self, Z):
    """
    Softmax激活函数(用于多分类输出层)
    使用数值稳定性技巧
    """

    exp_Z = np.exp(Z np.max(Z, axis=0, keepdims=True))
    return exp_Z / np.sum(exp_Z, axis=0, keepdims=True)

    def _activation_forward(self, Z, activation_type):
    """
    前向传播激活函数
    """

    if activation_type == 'relu':
    return self._relu(Z)
    elif activation_type == 'sigmoid':
    return self._sigmoid(Z)
    elif activation_type == 'tanh':
    return self._tanh(Z)
    elif activation_type == 'softmax':
    return self._softmax(Z)
    else:
    raise ValueError(f"未知的激活函数: {activation_type}")

    def _activation_backward(self, dA, Z, activation_type):
    """
    反向传播激活函数导数
    """

    if activation_type == 'relu':
    return dA * self._relu_derivative(Z)
    elif activation_type == 'sigmoid':
    return dA * self._sigmoid_derivative(Z)
    elif activation_type == 'tanh':
    return dA * self._tanh_derivative(Z)
    elif activation_type == 'softmax':
    # Softmax + CrossEntropy 的梯度简化为 (A – Y)
    return dA
    else:
    raise ValueError(f"未知的激活函数: {activation_type}")

    def forward_propagation(self, X):
    """
    前向传播

    参数:
    X: 输入数据,形状为 (n_features, n_samples)

    返回:
    AL: 输出层激活值
    caches: 缓存中间结果用于反向传播
    """
    caches = {}
    A = X
    caches['A0'] = X

    # 隐藏层前向传播
    for l in range(1, self.num_layers):
    W = self.parameters[f'W{l}']
    b = self.parameters[f'b{l}']

    # 线性部分: Z = W * A + b
    Z = np.dot(W, A) + b
    caches[f'Z{l}'] = Z

    # 激活部分: A = activation(Z)
    A = self._activation_forward(Z, self.activation)
    caches[f'A{l}'] = A

    # 输出层(使用Softmax)
    W = self.parameters[f'W{self.num_layers}']
    b = self.parameters[f'b{self.num_layers}']
    Z = np.dot(W, A) + b
    caches[f'Z{self.num_layers}'] = Z

    AL = self._activation_forward(Z, 'softmax')
    caches[f'A{self.num_layers}'] = AL

    return AL, caches

    def compute_cost(self, AL, Y):
    """
    计算交叉熵损失

    参数:
    AL: 模型输出,形状为 (n_classes, n_samples)
    Y: 真实标签(one-hot编码),形状为 (n_classes, n_samples)

    返回:
    cost: 标量损失值
    """
    m = Y.shape[1]

    # 添加小常数防止log(0)
    epsilon = 1e-8
    AL = np.clip(AL, epsilon, 1 epsilon)

    # 交叉熵损失
    cost = np.sum(Y * np.log(AL)) / m

    return cost

    def backward_propagation(self, AL, Y, caches):
    """
    反向传播

    参数:
    AL: 输出层激活值
    Y: 真实标签
    caches: 前向传播的缓存

    返回:
    grads: 各层参数的梯度
    """
    grads = {}
    m = Y.shape[1]
    L = self.num_layers

    # 输出层误差(Softmax + CrossEntropy的组合梯度)
    dZL = AL Y

    # 输出层梯度
    A_prev = caches[f'A{L1}']
    grads[f'dW{L}'] = np.dot(dZL, A_prev.T) / m
    grads[f'db{L}'] = np.sum(dZL, axis=1, keepdims=True) / m

    # 反向传播到隐藏层
    dA = np.dot(self.parameters[f'W{L}'].T, dZL)

    for l in range(L1, 0, 1):
    Z = caches[f'Z{l}']

    # 通过激活函数反向传播
    dZ = self._activation_backward(dA, Z, self.activation)

    # 计算梯度
    A_prev = caches[f'A{l1}']
    grads[f'dW{l}'] = np.dot(dZ, A_prev.T) / m
    grads[f'db{l}'] = np.sum(dZ, axis=1, keepdims=True) / m

    # 传播到前一层
    if l > 1:
    dA = np.dot(self.parameters[f'W{l}'].T, dZ)

    return grads

    def update_parameters(self, grads, learning_rate):
    """
    使用梯度下降更新参数

    参数:
    grads: 参数梯度
    learning_rate: 学习率
    """
    for l in range(1, self.num_layers + 1):
    self.parameters[f'W{l}'] -= learning_rate * grads[f'dW{l}']
    self.parameters[f'b{l}'] -= learning_rate * grads[f'db{l}']

    def train(self, X, Y, epochs=100, learning_rate=0.1, batch_size=64,
    X_val=None, Y_val=None, verbose=True):
    """
    训练神经网络

    参数:
    X: 训练数据
    Y: 训练标签(one-hot编码)
    epochs: 训练轮数
    learning_rate: 学习率
    batch_size: 批量大小
    X_val: 验证数据(可选)
    Y_val: 验证标签(可选)
    verbose: 是否打印训练进度

    返回:
    history: 训练历史记录
    """
    m = X.shape[1]
    num_batches = m // batch_size
    history = {'train_loss': [], 'train_acc': [], 'val_loss': [], 'val_acc': []}

    for epoch in range(epochs):
    # 随机打乱数据
    permutation = np.random.permutation(m)
    X_shuffled = X[:, permutation]
    Y_shuffled = Y[:, permutation]

    epoch_loss = 0

    for i in range(num_batches):
    # 获取批量数据
    start = i * batch_size
    end = start + batch_size
    X_batch = X_shuffled[:, start:end]
    Y_batch = Y_shuffled[:, start:end]

    # 前向传播
    AL, caches = self.forward_propagation(X_batch)

    # 计算损失
    batch_loss = self.compute_cost(AL, Y_batch)
    epoch_loss += batch_loss

    # 反向传播
    grads = self.backward_propagation(AL, Y_batch, caches)

    # 更新参数
    self.update_parameters(grads, learning_rate)

    # 计算训练集指标
    AL_train, _ = self.forward_propagation(X)
    train_loss = self.compute_cost(AL_train, Y)
    train_acc = self.compute_accuracy(X, Y)
    history['train_loss'].append(train_loss)
    history['train_acc'].append(train_acc)

    # 计算验证集指标
    if X_val is not None and Y_val is not None:
    AL_val, _ = self.forward_propagation(X_val)
    val_loss = self.compute_cost(AL_val, Y_val)
    val_acc = self.compute_accuracy(X_val, Y_val)
    history['val_loss'].append(val_loss)
    history['val_acc'].append(val_acc)

    # 打印进度
    if verbose and (epoch % 10 == 0 or epoch == epochs 1):
    if X_val is not None:
    print(f"Epoch {epoch:3d}/{epochs} – "
    f"loss: {train_loss:.4f} – acc: {train_acc:.4f} – "
    f"val_loss: {val_loss:.4f} – val_acc: {val_acc:.4f}")
    else:
    print(f"Epoch {epoch:3d}/{epochs} – "
    f"loss: {train_loss:.4f} – acc: {train_acc:.4f}")

    return history

    def predict(self, X):
    """
    预测类别

    参数:
    X: 输入数据

    返回:
    predictions: 预测的类别索引
    """
    AL, _ = self.forward_propagation(X)
    predictions = np.argmax(AL, axis=0)
    return predictions

    def compute_accuracy(self, X, Y):
    """
    计算准确率

    参数:
    X: 输入数据
    Y: 真实标签(one-hot编码)

    返回:
    accuracy: 准确率
    """
    predictions = self.predict(X)
    true_labels = np.argmax(Y, axis=0)
    accuracy = np.mean(predictions == true_labels)
    return accuracy

    def load_and_preprocess_data(n_samples=10000):
    """
    加载并预处理MNIST数据集

    参数:
    n_samples: 使用的样本数量(用于快速测试)

    返回:
    预处理后的训练和测试数据
    """
    print("正在加载MNIST数据集…")

    # 加载数据
    mnist = fetch_openml('mnist_784', version=1, parser='auto')
    X = mnist.data.values if hasattr(mnist.data, 'values') else mnist.data
    y = mnist.target.values if hasattr(mnist.target, 'values') else mnist.target

    # 限制样本数量(可选,用于快速测试)
    if n_samples < len(X):
    indices = np.random.choice(len(X), n_samples, replace=False)
    X = X[indices]
    y = y[indices]

    # 数据归一化到[0, 1]
    X = X.astype('float32') / 255.0

    # 划分训练集和测试集
    X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
    )

    # One-hot编码标签
    encoder = OneHotEncoder(sparse_output=False)
    y_train_onehot = encoder.fit_transform(y_train.reshape(1, 1)).T
    y_test_onehot = encoder.transform(y_test.reshape(1, 1)).T

    # 转置数据以适应神经网络输入 (n_features, n_samples)
    X_train = X_train.T
    X_test = X_test.T

    print(f"训练集大小: {X_train.shape[1]}")
    print(f"测试集大小: {X_test.shape[1]}")
    print(f"特征维度: {X_train.shape[0]}")
    print(f"类别数量: {y_train_onehot.shape[0]}")

    return X_train, X_test, y_train_onehot, y_test_onehot, y_test

    def plot_training_history(history):
    """
    绘制训练历史曲线
    """

    fig, axes = plt.subplots(1, 2, figsize=(12, 4))

    # 损失曲线
    axes[0].plot(history['train_loss'], label='Train Loss')
    if history['val_loss']:
    axes[0].plot(history['val_loss'], label='Val Loss')
    axes[0].set_xlabel('Epoch')
    axes[0].set_ylabel('Loss')
    axes[0].set_title('Training Loss')
    axes[0].legend()
    axes[0].grid(True, alpha=0.3)

    # 准确率曲线
    axes[1].plot(history['train_acc'], label='Train Acc')
    if history['val_acc']:
    axes[1].plot(history['val_acc'], label='Val Acc')
    axes[1].set_xlabel('Epoch')
    axes[1].set_ylabel('Accuracy')
    axes[1].set_title('Training Accuracy')
    axes[1].legend()
    axes[1].grid(True, alpha=0.3)

    plt.tight_layout()
    plt.savefig('training_history.png', dpi=150)
    plt.show()

    def visualize_predictions(X, y_true, y_pred, n_samples=10):
    """
    可视化预测结果
    """

    fig, axes = plt.subplots(2, 5, figsize=(12, 6))
    axes = axes.flatten()

    # 随机选择样本
    indices = np.random.choice(X.shape[1], n_samples, replace=False)

    for i, idx in enumerate(indices):
    # 重塑图像 (28×28)
    img = X[:, idx].reshape(28, 28)

    axes[i].imshow(img, cmap='gray')
    color = 'green' if y_pred[idx] == y_true[idx] else 'red'
    axes[i].set_title(f'True: {y_true[idx]}, Pred: {y_pred[idx]}', color=color)
    axes[i].axis('off')

    plt.tight_layout()
    plt.savefig('predictions.png', dpi=150)
    plt.show()

    # 主程序
    if __name__ == "__main__":
    # 加载数据
    X_train, X_test, y_train, y_test_onehot, y_test = load_and_preprocess_data(
    n_samples=10000
    )

    # 进一步划分验证集
    val_size = int(0.1 * X_train.shape[1])
    X_val = X_train[:, val_size:]
    y_val = y_train[:, val_size:]
    X_train = X_train[:, :val_size]
    y_train = y_train[:, :val_size]

    print(f"最终训练集: {X_train.shape[1]} 样本")
    print(f"验证集: {X_val.shape[1]} 样本")

    # 创建神经网络
    # 输入层: 784 (28×28像素)
    # 隐藏层1: 256
    # 隐藏层2: 128
    # 输出层: 10 (0-9数字)
    layer_dims = [784, 256, 128, 10]

    print(f"\\n网络结构: {layer_dims}")
    print(f"总参数数量: {sum(layer_dims[i] * layer_dims[i+1] + layer_dims[i+1] for i in range(len(layer_dims)1))}")

    nn = NeuralNetwork(
    layer_dims=layer_dims,
    activation='relu',
    initialization='he'
    )

    # 训练网络
    print("\\n开始训练…")
    history = nn.train(
    X_train, y_train,
    epochs=50,
    learning_rate=0.1,
    batch_size=128,
    X_val=X_val,
    Y_val=y_val,
    verbose=True
    )

    # 绘制训练曲线
    plot_training_history(history)

    # 测试集评估
    print("\\n测试集评估:")
    test_acc = nn.compute_accuracy(X_test, y_test_onehot)
    print(f"测试准确率: {test_acc:.4f}")

    # 可视化预测
    y_pred = nn.predict(X_test)
    y_true = np.argmax(y_test_onehot, axis=0)
    visualize_predictions(X_test, y_true, y_pred)

    # 混淆矩阵
    cm = confusion_matrix(y_true, y_pred)
    print("\\n混淆矩阵:")
    print(cm)

    7.3 代码解析

    网络架构设计:

    层神经元数量激活函数说明
    输入层 784 28×28图像展平
    隐藏层1 256 ReLU 特征提取
    隐藏层2 128 ReLU 特征提取
    输出层 10 Softmax 10类分类

    关键实现细节:

  • 向量化计算:所有操作使用NumPy矩阵运算,支持批量处理
  • 数值稳定性:Softmax使用减去最大值的技巧防止指数溢出
  • 梯度检查:交叉熵与Softmax的组合梯度简化为 (AL – Y)
  • He初始化:配合ReLU激活函数,防止梯度消失
  • 训练超参数:

    超参数值说明
    学习率 0.1 较大学习率加速收敛
    批量大小 128 平衡计算效率和稳定性
    训练轮数 50 足够收敛
    优化器 SGD 基础梯度下降

    7.4 运行结果预期

    在MNIST数据集上(10000样本),该网络预期达到:

    • 训练准确率:约95-98%
    • 验证准确率:约92-95%
    • 测试准确率:约92-95%

    8. 避坑小贴士

    8.1 梯度消失与梯度爆炸

    问题表现:

    • 梯度消失:深层网络参数几乎不更新,损失停滞
    • 梯度爆炸:损失突然变为NaN或急剧增大

    解决方案:

  • 使用合适的权重初始化(He/Xavier)
  • 使用ReLU等不易饱和的激活函数
  • 梯度裁剪(Gradient Clipping)
  • 批归一化(Batch Normalization)
  • 8.2 学习率设置

    学习率过大:损失震荡不收敛
    学习率过小:收敛极慢,陷入局部最优

    建议:

    • 从0.1或0.01开始尝试
    • 使用学习率衰减策略
    • 监控训练和验证损失曲线

    8.3 过拟合问题

    表现:训练准确率高,验证准确率低

    解决方案:

  • 增加训练数据
  • 使用正则化(L1/L2)
  • Dropout
  • 早停(Early Stopping)
  • 8.4 数据预处理

    必须进行的预处理:

  • 归一化/标准化:将特征缩放到相似范围
  • 标签编码:分类任务使用One-hot编码
  • 数据清洗:处理缺失值和异常值
  • 8.5 调试技巧

  • 从小网络开始:先用小数据集和小网络验证代码正确性
  • 梯度检查:使用数值梯度验证反向传播实现
  • 监控中间值:检查各层激活值和梯度的分布
  • 可视化:绘制损失曲线和权重分布

  • 9. 本章小结

    本章从感知机出发,逐步深入到多层感知机的核心原理,构建了完整的神经网络理论基础。

    核心知识点回顾:

    主题关键内容
    感知机 生物启发、数学模型、学习算法、异或局限
    MLP结构 输入层、隐藏层、输出层、前向传播
    反向传播 链式法则、误差反向传播、参数更新
    激活函数 Sigmoid、Tanh、ReLU、Swish、GELU演进
    权重初始化 Xavier、He初始化的数学原理
    损失函数 MSE、交叉熵、Hinge Loss的适用场景

    一句话总结:

    神经网络通过多层非线性变换提取特征,反向传播算法高效计算梯度,合理的激活函数和权重初始化是训练成功的关键。

    下一步学习建议:

  • 深入学习卷积神经网络(CNN),适用于图像处理
  • 学习循环神经网络(RNN/LSTM),适用于序列数据
  • 了解优化算法的进阶内容(Adam、RMSprop)
  • 学习正则化技术(Dropout、BatchNorm)

  • 如果本文对你有帮助,欢迎点赞、收藏、评论交流!持续关注我,获取更多机器学习深度教程。

    标签:python 机器学习 深度学习 神经网络 反向传播

    赞(0)
    未经允许不得转载:171主机测评 » 【机器学习精通】第8章 | 神经网络基础:感知机到多层感知机
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址