在了解了神经网络的基本组成部分——神经元、层和激活函数之后,我们现在来思考一个核心设计问题:如何组织这些组成部分以建立有效的前馈网络?决定架构,特别是隐藏层的数量以及每层内的神经元数量,对模型从数据中学习和泛化能力有重要影响。没有一个万能公式;架构设计通常依据启发式方法、问题复杂度和经验性实验。隐藏层数量如何确定?网络的“深度”指的是它包含的隐藏层数量。零个隐藏层: 这种配置会产生一个单层感知器(如果使用适当的激活函数,则是逻辑/Softmax回归)。如第1章所述,这些模型只能学习线性可分模式。一个隐藏层: 具有一个隐藏层的网络理论上能力很强。通用近似定理指出,只要有足够的神经元,一个包含有限数量神经元和合适非线性激活函数的前馈网络,能够以任意精度近似任何连续函数。这相当了不起。对于许多较简单的问题,一个隐藏层通常就足够了。两个或更多隐藏层(深度网络): 尽管一个隐藏层在理论上可以近似任何函数,但深度网络(即具有多个隐藏层的网络)通常能更高效地学习复杂模式。更深的架构使得网络能学习分层特征。早期层可能学习简单特征(如图像中的边缘或纹理),而后续层将这些组合起来以识别更复杂的结构(如形状或物体)。对于复杂任务的给定精度水平,深度网络可能比只有一个隐藏层的宽而浅的网络所需的总神经元数量(以及参数)更少。增加网络深度会带来一系列挑战:梯度消失/爆炸: 训练非常深的神经网络可能会很困难,因为在反向传播过程中梯度会变得非常小或非常大(我们稍后会更详细地讨论这一点)。谨慎的权重初始化、非饱和激活函数(如ReLU)和批量归一化等技术有助于缓解这种情况。计算成本: 更多层意味着在训练(前向和反向传播)和推理过程中需要更多计算。过拟合: 深度网络有更多的参数和容量,如果正则化不当,会增加对训练数据过拟合的风险。指导原则: 从简单开始。最初使用一到两个隐藏层。如果模型欠拟合(未能捕捉到训练数据中的模式),则考虑逐渐增加深度或宽度。每个隐藏层有多少神经元?层的“宽度”指的是它包含的神经元数量。这决定了该层在该抽象层次上的表示能力。神经元过少: 如果隐藏层中的神经元过少,网络可能缺乏学习数据潜在复杂性的能力。这会导致欠拟合,模型即使在训练数据上表现也很差。神经元过多: 使用比所需数量多得多的神经元会使网络容易过拟合。模型可能会开始记忆训练样本,包括它们的噪声,而不是学习可泛化的模式。这会导致在训练集上表现良好,但在未见数据上表现不佳。神经元过多还会增加计算需求和训练时间。尽管正则化(第6章)等技术可以帮助控制更宽网络中的过拟合,但使用过多神经元通常效率低下。常见启发式方法和模式:输入/输出关系: 一种常见做法是选择隐藏层中的神经元数量,使其介于输入层大小和输出层大小之间。2的幂次: 通常,层的大小选择为2的幂次(例如,32、64、128、256、512),部分原因是GPU等硬件上的计算效率,但这并非严格要求。漏斗形结构: 一种流行方法是逐渐减少连续隐藏层中的神经元数量(例如,输入 -> 512 -> 256 -> 128 -> 输出)。这类似于将信息压缩,直到得到进行最终预测所需的核心特征。宽度不变: 有时,所有隐藏层可能具有相同数量的神经元。指导原则: 最佳神经元数量高度依赖于特定数据集和问题。它是您需要调整的主要超参数之一。从基于输入/输出大小或常见做法(例如,漏斗形结构)的合理数量开始,然后进行实验。监控验证集性能以检查是否欠拟合或过拟合,并相应地调整层大小。digraph G { rankdir=LR; node [shape=circle, style=filled, fillcolor="#a5d8ff", fixedsize=true, width=0.5]; edge [arrowhead=none]; subgraph cluster_0 { label = "输入层"; bgcolor="#e9ecef"; i1; i2; i3; i4; } subgraph cluster_1 { label = "隐藏层1 (漏斗形)"; bgcolor="#dee2e6"; h11; h12; h13; } subgraph cluster_2 { label = "隐藏层2 (漏斗形)"; bgcolor="#ced4da"; h21; h22; } subgraph cluster_3 { label = "输出层"; bgcolor="#e9ecef"; o1 [fillcolor="#b2f2bb"]; } {i1, i2, i3, i4} -> {h11, h12, h13}; {h11, h12, h13} -> {h21, h22}; {h21, h22} -> o1; // Add labels for clarity if needed, or keep it clean }前馈网络常使用“漏斗形”结构,在连续的隐藏层中减少神经元数量。输出层配置请记住,输出层的设计完全由任务决定:回归: 通常是一个神经元,使用线性(或无)激活函数。二分类: 一个神经元,使用Sigmoid激活函数。多分类: $N$个神经元(其中$N$是类别数量),使用Softmax激活函数。迭代和实验设计网络架构很少是一次性完成的过程。它通常涉及:从基于问题类型和启发式方法的合理基线架构开始。训练模型并在验证集上评估其性能。观察模型是否欠拟合或过拟合。根据评估结果,迭代调整架构(增加/移除层,改变层宽度)和超参数(如学习率,稍后讨论)。采用正则化(第6章)等技术以提高泛化能力。自动化超参数调整技术可以系统地尝试不同架构,但理解这些设计原则为做出明智选择和指导搜索过程提供了良好根基。例如,在PyTorch中定义一个简单的全连接前馈网络可能看起来像这样,明确显示了层维度:import torch import torch.nn as nn class SimpleMLP(nn.Module): def __init__(self, input_size, hidden_size1, hidden_size2, output_size): super(SimpleMLP, self).__init__() self.layer1 = nn.Linear(input_size, hidden_size1) self.relu1 = nn.ReLU() self.layer2 = nn.Linear(hidden_size1, hidden_size2) self.relu2 = nn.ReLU() self.output_layer = nn.Linear(hidden_size2, output_size) # 输出激活函数(例如 nn.Sigmoid() 或 nn.Softmax(dim=1)) # 通常会在该层之后应用或由损失函数处理。 def forward(self, x): x = self.layer1(x) x = self.relu1(x) x = self.layer2(x) x = self.relu2(x) x = self.output_layer(x) return x # 示例实例化: input_dim = 784 # 例如,用于平展的28x28 MNIST图像 h1_dim = 128 h2_dim = 64 output_dim = 10 # 例如,用于10个数字类别 model = SimpleMLP(input_dim, h1_dim, h2_dim, output_dim) print(model)这个例子定义了一个网络,包含一个输入层、两个隐藏层(分别为128和64个神经元,使用ReLU激活函数)以及一个输出层。具体神经元数量(128、64)代表了基于所讨论原则的设计选择。随着学习的推进,您将培养直觉并使用系统方法来完善这些架构决策,以解决您的特定问题。