在掌握了单层神经网络(线性回归、逻辑回归、Softmax回归)之后,我们正式跨入“深度”学习的领域。从单层到多层是神经网络发展史上的质变,增加的“隐藏层”彻底将神经网络的性能提升到了另一个高度。本文将带你理解深层神经网络的核心概念、激活函数的作用,并手把手教你用PyTorch实现正向传播。

一、异或门问题:单层网络的致命局限

在逻辑门的世界里,与门(AND)、或门(OR)和非与门(NAND)的数据都是线性可分的。这意味着,只要设置合适的权重 w 和偏置 b,就能在二维平面上画出一条直线,完美地把标签0和1分开。因此,最基础的单层感知机(即单层 nn.Linear )能够完美解决这三个逻辑门。

然而,异或门(XOR)的数据是线性不可分的。作为四大基础逻辑门中唯一的例外,无论你怎么调整单层神经网络的权重 w 和偏置 b,你都绝对不可能在二维平面上画出“一条直线”将它的四个点正确分类。

在机器学习的底层表示中,这里的 列全为 1,通常是为偏置项(Bias)预留的“占位符”(即偏置乘以 1 仍然等于偏置本身)。

与门数据(andgate): 与门是一组只有两个特征(x1, x2)的分类数据,当两个特征下的取值都为1时,分类标签为1,其他时候分类标签为0。


或门数据(orgate):或门是一组只有两个特征(x1, x2)的分类数据,只要两个特征中至少有一个为 1(或者都为 1),分类标签就为 1;只有当两个特征都为 0 时,分类标签才为 0。


非与门/与非门数据(nandgate):非与门(通常在工程中被称为“与非门”)本质上是与门(AND)的完全反向操作。当且仅当两个特征都为 1 时,分类标签才为 0;在其他所有情况下,分类标签都为 1。


异或门数据(xorgate):异或门是一组只有两个特征(x1, x2)的分类数据,当且仅当两个特征下的取值不相同时(即一个为 1,一个为 0),分类标签为 1;当两个特征取值相同时(同为 0 或同为 1),分类标签为 0。


在机器学习的底层逻辑中,存在着一个极其重要的物理特性分水岭:线性可分性。

结论:单层神经网络无法解决非线性可分问题。这也是导致第一次人工智能寒冬的根本原因。

二、引入隐藏层:非线性可分解法

为了解决非线性问题,我们需要在输入层和输出层之间加入隐藏层(Hidden Layer)。从结构上看,多层神经网络比单层神经网络多出了“中间层”。隐藏层理论上可以有无限层,所以在图像表示中经常被省略。

隐藏层的物理意义在于:它对原始特征空间进行了扭曲和升维转换。它将原本在低维空间线性不可分的数据,映射到一个新的高维空间中,使其在新空间里变得线性可分。

编号规范

  • 层从左向右:上层到下层
  • 神经元分类:常量神经元(每层只有一个)与特征神经元(带有编号)
  • 符号说明z 是加和结果,σ 是激活函数输出;Hz 表示中间层激活函数,Gz 表示输出层激活函数

image-20260424105910565

为了简化编号,本系列采用如下方式:image-20260424110012046

上标表示层的编号,下标表示神经元的编号。以XOR为例,对于仅有两个特征的单一样本,第一层第一特征神经元的加和结果为:

z₁¹ = b→₁→¹ + x₁·w₁→₁⁰→¹ + x₂·w₂→₁⁰→¹

隐藏层中经 h(z) 处理后的公式为:

σ₁¹ = h(z₁¹) = h(b→₁→¹ + x₁·w₁→₁⁰→¹ + x₂·w₂→₁⁰→¹)

用矩阵表示数据从输入层传入第一层:

Z¹ = W¹·X + B¹

从第一层向第二层传递时,σ₁¹ 和 σ₂¹ 会作为输入传入输出层。对于第二层的唯一输出神经元:

z₁² = b→₁→² + σ₁¹·w₁→₁¹→² + σ₂¹·w₂→₁¹→²
σ₁² = g(z₁²) = g(b→₁→² + σ₁¹·w₁→₁¹→² + σ₂¹·w₂→₁¹→²)

⚠️ 当神经网络层数和神经元数量增加时,计算复杂度急剧上升,模型会变成一个难以理解的“黑箱”。image-20260424112646947

异或门代码示例

image-20260423214934345

import torch
def NAND(X):
w = torch.tensor([0.23,-0.15,-0.15])
zhat = X@w
yhat = torch.tensor([int(x) for x in zhat>0],dtype=torch.float32)
return yhat
def OR(X):
w = torch.tensor([-0.08, 0.15,0.15])
zhat = X@w
yhat = torch.tensor([int(x) for x in zhat>0],dtype=torch.float32)
return yhat
def AND(X):
w = torch.tensor([-0.2,0.15, 0.15])
zhat = X@w
yhat = torch.tensor([int(x) for x in zhat>0],dtype=torch.float32)
return yhat
def XOR(X):
#输入值:
input_1 = X
#中间层:
sigma_nand = NAND(input_1)
sigma_or = OR(input_1)
x0 = torch.tensor([[1],[1],[1],[1]],dtype=torch.float32)
#输出层:
input_2 = torch.cat((x0,sigma_nand.view(4,1),sigma_or.view(4,1)),dim=1)
y_and = AND(input_2)
return y_and
X = torch.tensor([[1.,0,0],[1,1,0],[1,0,1],[1,1,1]])
print(XOR(X))
# tensor([0., 1., 1., 0.])

三、激活函数:神经网络的灵魂

重大警告:如果不加激活函数,盲目堆叠多少个隐藏层都等于单层网络!

数学证明:假设一个两层网络都不加激活函数:

第一层:H = XW₁
第二层:Z = HW₂
代入展开:Z = (XW₁)W₂ = X(W₁W₂)

由于矩阵乘法结合律,W₁W₂ 可等效为一个全新的权重矩阵 W_new,最终 Z = XW_new,本质上依然是单层线性网络,毫无非线性表达能力!

激活函数是神经网络的灵魂!它赋予了神经网络非线性表达能力,使其理论上能够拟合任意复杂的函数(万能近似定理)。

隐藏层 vs 输出层激活函数

  • 隐藏层激活函数 h(z):影响模型效果,必须是非线性函数(如ReLU、Sigmoid、Tanh)
  • 输出层激活函数 g(z):只影响输出结果形式,可以是线性函数(恒等函数用于回归,Sigmoid用于二分类,Softmax用于多分类)

✅ 在同一个神经网络中,h(z) 与 g(z) 可以不同,每层上的 h(z) 也可以不同,但同一层上的激活函数必须一致。

四、从0实现深度神经网络的正向传播

在PyTorch中,构建复杂的深层网络必须依靠面向对象编程,通过继承 torch.nn.Module 基类来实现。

nn.Module类的核心结构

构建网络类时,必须重写两个极其重要的方法:

  • __init__(self):初始化方法,用于定义网络中需要的所有层(如 nn.Linear
  • forward(self, x):前向传播方法,定义数据 x 是如何一步步通过这些层的

__init__(self) 需要 in_features 和 out_features 两个参数:

  • in_features:输入该神经网络的特征数目(输入层神经元的数目)
  • out_features:神经网络输出的数目(输出层神经元的数目)

__init__(self) 需要调用父类初始化方法:super().__init__()

在自定义网络的 __init__ 方法中,第一行必须调用 super().__init__()

不需要自己写 __call__,只需要负责把网络前向传播的数学逻辑写进 forward(self, x) 即可。

[AFFILIATE_SLOT_1]

五、PyTorch实现多层感知机(MLP)

以下是一个完整的PyTorch多层感知机示例,包含隐藏层和输出层的定义:

net.train(mode=True)
net.eval()

代码解析:

  • 输入层:特征数量为 in_features
  • 隐藏层:使用ReLU激活函数,增加非线性表达能力
  • 输出层:根据任务选择激活函数(回归用恒等,二分类用Sigmoid,多分类用Softmax)

✅ 通过继承 torch.nn.Module 并重写 forward 方法,我们可以轻松构建任意深度的神经网络。

六、总结与展望

本文从异或门问题出发,揭示了单层神经网络的局限性,并引入隐藏层和激活函数来解决非线性问题。我们深入理解了:

  • 隐藏层:将低维线性不可分数据映射到高维,使其可分
  • 激活函数:打破线性限制,赋予神经网络非线性表达能力
  • PyTorch实现:通过 nn.Module 和 nn.Linear 快速构建深度网络

在后续文章中,我们将进一步探讨反向传播、梯度下降优化以及更复杂的网络结构(如卷积神经网络、循环神经网络),敬请期待!

[AFFILIATE_SLOT_2]

你对深层神经网络还有什么疑问?欢迎在评论区留言讨论!

x0
x0x1x2y_and
1000
1100
1010
1111
x0x1x2y_or
1000
1101
1011
1111
x0x1x2y_nand
1001
1101
1011
1110
x0x1x2y_xor
1000
1101
1011
1110
image-20260423222423409image-20260424105258341