想象你面前有一大箱乐高积木,红的、蓝的、方的、圆的、带齿轮的、带轮子的……你的任务是拼出一栋最漂亮的房子。然而,积木的种类是有限的——箱子里没有三角形屋顶片,你就永远搭不出尖顶小屋;箱子里全是基础方块,再怎么发挥创意也雕不出花式阳台。AI 领域里的“Neural Architecture Search(神经架构搜索,NAS)”也一样:它要做的事情,就是从一个“积木池”里自动拼出最好的神经网络。而这个积木池——在NAS里称为“搜索空间”——直接决定了最终能拼出的网络的上限,也就是“天花板”。 如果搜索空间太小,NAS 算法再聪明也找不到足够好的网络;如果搜索空间太大,NAS 要尝试的组合多到爆炸,算到天荒地老也搜不完。所以,搜索空间设计不是随手圈一个范围,而是一门“既有料、又不乱”的平衡艺术。本文会用“乐高搭房子”这个比喻贯穿始终,带你理解搜索空间的三种粒度(单元级、层级、整体网络)、组合爆炸的数学本质、Cell 堆叠与跳连、约束机制,以及经典论文中的经验设定。你会发现,这就像在给 NAS 搭一个积木池——池子的深度和宽度,决定了 AI 能自动盖出多高的楼。

岗位关联

对 AI 从业者而言,掌握搜索空间设计意味着你不再被动地拿现成网络来用,而是能亲手为自家任务设计“自动找网络”的边界——这是从算法使用者迈向 AutoML 核心开发者的关键一步。

目录
  1. 可视化演示
  2. 搜索空间定位
  3. 单元级搜索
  4. 层级搜索
  5. 整体网络搜索
  6. 空间效率平衡
  7. 堆叠与跳连
  8. 约束机制设计
  9. 经验设定指南
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

展示神经架构搜索中单元级、层级、整体网络三种搜索粒度的结构差异,以及搜索空间大小与搜索效率的平衡关系。

本节配有交互动效(进入视口后自动加载,约 3KB)。

NAS搜索空间三种粒度 Cell: 单元级 Hier: 层级 Full: 整体 ~10^N 三种搜索粒度对应不同空间规模

搜索空间定位

打开一盒乐高,你会发现包装盒背面印着“本套装含 236 个零件、12 种类型”。这行小字其实就是积木世界的“搜索空间”——告诉你在这个套装里能拼出什么,不能拼出什么。NAS 的第一步,恰恰不是写搜索算法,而是先定义这个“零件清单”。搜索空间是所有候选网络结构的集合,NAS 算法只能从里面挑网络,空间里没有的结构,再强的算力也搜不出来。因此,搜索空间的设计,从根本上划定了 NAS 效果的天花板。

在 AutoML 的拼图里,NAS 有三大要素:搜索空间、搜索策略、性能评估策略。搜索策略负责“怎么找”,性能评估负责“好不好”,而搜索空间负责“能从哪些里面找”。三者像乐高项目中的零件库、拼法说明书和质检环节——零件库决定了你能搭的出形态,拼法说明书决定了效率,质检决定了最终效果是否达标。一个优秀的搜索空间设计,应该在保证覆盖“好结构”的前提下,尽量压缩冗余区域,让搜索策略能高效地收敛到好方案。

形式上,搜索空间可以写成一个集合:

回到乐高的比喻:如果积木套装里只有 20 个零件,你不可能拼出埃菲尔铁塔——不是拼法不够巧,是零件清单根本没给够。同样,搜索空间设计是 NAS 的“地基工程”,它决定的是上限而非下限。理解了这一点,你就明白了为什么很多 NAS 论文花了大量篇幅精心设计搜索空间,而不是直接扔给算法一个无限大的候选集。

S={N1,N2,…,NM}\mathcal{S} = \{\mathcal{N}_1, \mathcal{N}_2, \ldots, \mathcal{N}_M\}
这个式子把搜索空间定义为所有候选网络结构组成的集合,M 越大,可选网络越多。
  1. 候选网络结构\mathcal{N}_i 表示搜索空间中的第 i 个候选网络架构,对应一个具体积木组合方案。
    Ni\mathcal{N}_i
  2. 集合构造花括号 \{...\} 把所有候选结构收集在一起,构成一个整体集合。
    {N1,N2,…,NM}\{\mathcal{N}_1, \mathcal{N}_2, \ldots, \mathcal{N}_M\}
  3. 空间大小|\mathcal{S}| = M 表示搜索空间中有 M 种可能结构,是衡量空间规模的核心指标。
    ∣S∣=M|\mathcal{S}| = M

单元级搜索

有了乐高零件池,下一步是设计“标准窗子模块”——Cell。所谓 Cell,就是神经网络中一个可重复堆叠的基础单元,内部由若干节点和连接组成。单元级搜索的思路很聪明:与其搜整个网络的每一层,不如只搜一个 Cell 的内部结构,然后把这个 Cell 复制堆叠 N 次构造成整个网络。就像搭房子时先设计一个精美的标准窗子模块,然后整栋楼所有窗户都用它,省时又统一。

为什么单元级搜索可行?深层的直觉是:神经网络中不同层的局部特征提取模式高度相似——低层识别边缘、高层识别纹理,但计算模式常常是“卷积+池化+非线性”的某种组合。NASNet 等经典工作用实践证明了这一点:搜索一个优秀的 Normal Cell 和一个 Reduction Cell,然后交替堆叠,就能在 ImageNet 上取得超越手工设计的效果。这种“搜小放大”的策略,把搜索复杂度从天文学数字降到了可计算范围。

Cell 内部的结构可以用有向无环图(DAG)描述:

单元级搜索就像是设计一个“万能窗子原型”:你只需要精心打磨这一种窗子,整栋楼都在复用。这也解释了为什么 NASNet 能在当年刷榜——它没有发明更玄妙的搜索算法,而是把搜索空间设计成了“细胞级”的精致小空间,让搜索策略在这个小空间里更容易找到宝石。

G=(V,E)\mathcal{G} = (V, E)
Cell 被建模为一个有向无环图,节点 V 是特征表示,边 E 是数据流向。
  1. 节点集合V = \{v_1, v_2, \ldots, v_n\} 表示 Cell 内部的 n 个中间节点,每个节点是一个待定操作的位置。
    V={v1,v2,…,vn}V = \{v_1, v_2, \ldots, v_n\}
  2. 边集合E = \{(i, j) \mid v_i, v_j \in V\} 表示节点之间的连接,每条边选择一种操作类型(如 3x3 卷积)。
    E={(i,j)∣vi,vj∈V}E = \{(i, j) \mid v_i, v_j \in V\}
  3. 有向无环约束DAG 保证信息只能向前传播,不会形成环路,这是神经网络可训练的前提。
    G=(V,E),DAG\mathcal{G} = (V, E), \quad \text{DAG}

层级搜索

如果说单元级搜索只关注“标准窗子”,那稍复杂的房子还需要考虑:不同楼层是不是该配不同的窗子?层级搜索正是这个思路——它把网络拆分成多个抽象层次,每一层用不同的搜索粒度。最典型的是三层结构:最低层是基础操作(卷积、池化等),中间层是 Cell 内部的连接模式,最高层是 Cell 之间的网络连接方式。三者组合起来,构成一个多粒度的搜索空间。

这种分层设计的好处很直观:低层操作捕捉细节纹理,高层连接决定信息流动的范围,不同层级各司其职。就像一栋办公楼,底层大堂用落地窗、中层办公区用标准窗、顶层会议室用天窗——每层因地制宜,整体才和谐。层级搜索还能有效减少搜索冗余:不在高维空间里穷举低层细节,而是先固定低层操作池,再逐层向上组合,让搜索过程更聚焦。

层级搜索空间的数学表示,是各层子空间的笛卡尔积:

用乐高的语言说,层级搜索意味着你有一个基础零件库(底层),一套标准模块图纸(中层),和一栋楼的总体规划(高层)。设计时先把零件库定好,再画模块图,最后排楼层布局,一步步收紧。这种“先粗后细”的策略,让 NAS 既能照顾局部感受野,又能兼顾全局拓扑,比单层搜索更具表达力。

Stotal=Slow×Smid×Shigh\mathcal{S}_{\text{total}} = \mathcal{S}_{\text{low}} \times \mathcal{S}_{\text{mid}} \times \mathcal{S}_{\text{high}}
总搜索空间等于底层、中层、高层三个子空间的笛卡尔积,三者共同决定网络形态。
  1. 底层子空间\mathcal{S}_{\text{low}} 是基础操作层可选的集合,如 3x3 卷积、5x5 卷积、池化等。
    Slow={conv3×3,conv5×5,pool,…}\mathcal{S}_{\text{low}} = \{\text{conv}_{3\times3}, \text{conv}_{5\times5}, \text{pool}, \ldots\}
  2. 中层子空间\mathcal{S}_{\text{mid}} 是 Cell 内部的拓扑结构集合,决定节点如何连接。
    Smid={G1,G2,…}\mathcal{S}_{\text{mid}} = \{\mathcal{G}_1, \mathcal{G}_2, \ldots\}
  3. 高层子空间\mathcal{S}_{\text{high}} 是 Cell 之间如何堆叠与连接的宏观模式。
    Shigh={堆叠方式,跳连模式}\mathcal{S}_{\text{high}} = \{\text{堆叠方式}, \text{跳连模式}\}
  4. 笛卡尔积\times 表示组合所有层级的可能性,总空间是各层空间的完整乘积。
    Stotal=Slow×Smid×Shigh\mathcal{S}_{\text{total}} = \mathcal{S}_{\text{low}} \times \mathcal{S}_{\text{mid}} \times \mathcal{S}_{\text{high}}

整体网络搜索

搭乐高房子时,除了窗户模块,你还得决定房子盖几层、每层多宽、楼梯放哪。整体网络搜索对应这些“宏观布局”问题:网络的深度(层数)、宽度(每层通道数)、全局连接拓扑。与单元级搜索互补,整体网络搜索关心的是“这些 Cell 怎么排布成完整网络”。

深度和宽度是网络容量最基本的两个旋钮。深度太浅,网络表达能力不足;深度太深,训练困难且可能过拟合。宽度同理——通道太少信息瓶颈,通道太多计算量暴涨。整体网络搜索把这些旋钮也纳入了搜索空间,让 NAS 同时调节“层数”和“每层积木的数量”。在 NASNet 的结构里,5 个 Normal Cell 加 2 个 Reduction Cell 组成一个 block,整体网络就是这些 block 的重复,从 6 个 block 到 14 个 block 的变化,就是深度维度的搜索。

整体网络的结构可以写成一个复合函数:

回到乐高:一个小区里建几栋楼、每栋楼几个单元、楼间距多大——这些宏观规划决定了整个社区的品质。整体网络搜索就是为了给 Cell 找到最好的“摆放方式”。某种意义上,它比单元级搜索更考验设计者的全局观:单个 Cell 再精致,整体排布不合理,网络依然无法发挥实力。

N=Stack⁡(C1,C2,…,CL)\mathcal{N} = \operatorname{Stack}(\mathcal{C}_1, \mathcal{C}_2, \ldots, \mathcal{C}_L)
整个网络是把 L 个 Cell 按顺序堆叠而成,L 的取值与每个 Cell 的类型都是搜索目标。
  1. Cell 序列\mathcal{C}_1, \mathcal{C}_2, \ldots, \mathcal{C}_L 表示按顺序排列的 L 个 Cell 单元。
    C1,C2,…,CL\mathcal{C}_1, \mathcal{C}_2, \ldots, \mathcal{C}_L
  2. 堆叠算子\operatorname{Stack}(\cdot) 表示把前一个 Cell 的输出接到后一个 Cell 的输入,形成深层网络。
    Stack⁡(C1,C2,…,CL)\operatorname{Stack}(\mathcal{C}_1, \mathcal{C}_2, \ldots, \mathcal{C}_L)
  3. 全局网络\mathcal{N} 是堆叠后得到的完整网络,其深度由 L 控制,宽度由各 Cell 内部通道数决定。
    N=Stack⁡(C1,C2,…,CL)\mathcal{N} = \operatorname{Stack}(\mathcal{C}_1, \mathcal{C}_2, \ldots, \mathcal{C}_L)

空间效率平衡

乐高套装里零件种类越多,理论上能拼出的花样越多,但拼的时候选择困难也越严重。搜索空间设计最核心的矛盾就在于此:空间太大,搜索算法吃不消;空间太小,又怕漏掉好结构——这就是“空间-效率”的权衡,背后是数学上的组合爆炸。

组合爆炸的威力惊人。假设每层有 6 种可选操作,网络有 10 层,那么候选结构就有 6 的 10 次方——超过 6000 万种。如果每层还要决定连接方式,数字会进一步飙升。NAS 的搜索策略再好,也不可能逐一遍历这种量级的空间。所以,设计搜索空间时必须精打细算:能共享的结构参数化(如 Cell 复用),能剪枝的冗余操作果断删掉,用“小空间精搜索”替代“大空间盲搜索”。

组合爆炸的数学本质是连乘:

明白了组合爆炸,你就知道为什么搜索空间要“抠门”——不是钱的问题,是算力真的花不完。好的搜索空间设计,像一位经验丰富的主厨:菜单上只有 8 道菜,但每道都精心搭配、用料考究,食客(搜索算法)点菜时不会眼花缭乱,又能吃到真正的招牌菜。

∣S∣=∏i=1n∣Oi∣ki=O(c n)|\mathcal{S}| = \prod_{i=1}^{n} |\mathcal{O}_i|^{k_i} = O(c^{\,n})
搜索空间大小等于每层可选操作数的 k 次方连乘,总体随层数 n 指数增长。
  1. 单层选项数|\mathcal{O}_i| 表示第 i 个位置可选择的操作数量,这里是 6 种积木类型。
    ∣Oi∣|\mathcal{O}_i|
  2. 指数项k_i 表示每个位置需要叠加的连接决策数,层数越多指数越高。
    ∣Oi∣ki|\mathcal{O}_i|^{k_i}
  3. 总空间连乘\prod_{i=1}^{n} 把所有位置的选项数相乘,得到总组合数。
    ∏i=1n∣Oi∣ki\prod_{i=1}^{n} |\mathcal{O}_i|^{k_i}
  4. 复杂度量级O(c^{\,n}) 表示组合数随层数 n 呈指数级增长,这就是“爆炸”的来源。
    O(c n)O(c^{\,n})

堆叠与跳连

设计好 Cell 之后,怎么把它堆起来?直接简单堆叠会面临一个经典问题:层数越深,梯度在反向传播时越容易消失,网络训练不动。就像盖很高的楼,如果每层之间没有电梯和连廊,住在顶层的人根本下不来。跳连(Skip Connection)就是这座楼的“电梯”——把某一层的输出直接抄近路接到后面的层上。

ResNet 已经证明,残差结构(跳连的一种)能让上百层的深度网络顺利训练。在 NAS 的搜索空间设计里,跳连同样是一个“必选项”而不是“可选项”:搜索出的 Cell 内部如果完全不支持跳连,搜出来的网络一旦堆深,梯度传播就会出问题。NASNet 等搜索空间中,Cell 的每个节点候选操作里都包含 identity(恒等映射),其实就是给网络留了一条“备用楼梯”。

残差跳连的数学形式非常简洁:

在搜索空间里“支持跳连”,等于默认建筑师可以使用电梯——这是现代高层建筑的基线配置。跳连不仅保障梯度通畅,还让信息可以在网络中“跨层流动”。对 NAS 来说,在搜索空间里预设这一机制,相当于给搜索算法装上安全网,大大降低搜出训练不动网络的风险。

xl+1=xl+F(xl;Wl)x_{l+1} = x_l + \mathcal{F}(x_l; W_l)
跳连把输入 x_l 直接加到变换后的特征上,让梯度可以无损流过。
  1. 输入特征x_l 是当前层的输入,对应楼里这一层的“客流”。
    xlx_l
  2. 变换函数\mathcal{F}(x_l; W_l) 是带权重 W_l 的变换(卷积、池化等),是这层平时要做的“加工”。
    F(xl;Wl)\mathcal{F}(x_l; W_l)
  3. 残差相加x_l + \mathcal{F}(x_l; W_l) 把原始输入和加工结果相加,形成残差连接。
    xl+F(xl;Wl)x_l + \mathcal{F}(x_l; W_l)
  4. 层输出x_{l+1} 作为下一层的输入,既保留了原始信息又加入了新特征。
    xl+1=xl+F(xl;Wl)x_{l+1} = x_l + \mathcal{F}(x_l; W_l)

约束机制设计

盖楼不是想怎么盖就怎么盖——消防通道、承重墙、限高这些规范不能违反。同样,真实部署环境里的 NAS 必须考虑约束:手机上的模型延迟不能超过 20 毫秒、参数量不能超过 5MB、功耗不能超标。搜索空间设计阶段就引入约束,能在源头过滤掉一大批“好看但没法用”的结构。

约束机制的核心思路是把资源指标作为硬性限制条件,插进搜索优化的目标函数里。传统做法是先搜一个高精度网络,再压缩蒸馏去适配硬件——类似于把盖好的楼推倒重装电梯,代价高昂。而“约束内搜索”是从设计图纸阶段就把电梯井预留好,一次到位。这也是 MnasNet、MobileNetV3 等高效 NAS 工作的共同原则。

带约束的 NAS 可写成如下优化问题:

乐高的世界里,建筑规范是底线——积木拼出的塔再好看,结构不稳一碰就倒,那就不合格。约束机制让 NAS 在“好看”和“能用”之间找到交集。对于做移动端部署的工程师来说,在搜索空间层面预设约束,比事后调优省下数周时间,也让方案上线更顺畅。

min⁡α  Lval(w∗(α),α)s.t.Latency⁡(α)≤T\min_{\alpha} \; \mathcal{L}_{\text{val}}\big(w^{*}(\alpha), \alpha\big) \quad \text{s.t.} \quad \operatorname{Latency}(\alpha) \leq T
目标是最小化验证集损失,同时保证推理延迟不超过阈值 T。
  1. 结构参数\alpha 是描述候选网络结构的参数,决定搜索空间中选哪种“积木组合”。
    α\alpha
  2. 最优权重w^{*}(\alpha) 是给定结构 α 下,在训练集上训练得到的最优权重。
    w∗(α)w^{*}(\alpha)
  3. 验证损失\mathcal{L}_{\text{val}}(\cdot) 是在验证集上评估的损失,值越小代表网络泛化越好。
    Lval(w∗(α),α)\mathcal{L}_{\text{val}}\big(w^{*}(\alpha), \alpha\big)
  4. 延迟约束\operatorname{Latency}(\alpha) \leq T 要求当前结构在目标硬件上的推理延迟不超过 T。
    Latency⁡(α)≤T\operatorname{Latency}(\alpha) \leq T

经验设定指南

讲了这么多原理,实际落地时该从哪起步?经验设定是站在前人肩膀上最实用的路径。NASNet 的关键设定包括:Cell 内部节点数取 4-5 个,操作池 6-8 种,Normal Cell 与 Reduction Cell 交替堆叠,末端再接一层全局池化。这套配置像是一份经过验证的乐高图纸——照着拼不会出大错,微调后还能出彩。

DARTS 的设定则更轻量:用 7 个节点组成 Cell,其中前两个是输入节点,操作池固定为 8 种候选操作(3x3 卷积、5x5 卷积、3x3 最大池化、3x3 平均池化、identity、3x3 可分离卷积、5x5 可分离卷积、零操作)。经验法则有三条:操作池不宜超过 8 种,否则检索耗时剧增;初始搜索在小空间(如 8 个 Cell)中进行,找到好结构后再进行放大;约束条件从严格到宽松逐个尝试,找到精度和资源的帕累托前沿。

NASNet 的 Cell 交替结构可以表示为:

这些经验设定就像乐高官方图纸的“经典款”:所有零件都是通用件,但搭配方式经过千锤百炼,闭着眼拼也不会大翻车。对新手而言,最务实的做法不是从零发明新搜索空间,而是先复现 NASNet 或 DARTS 的设定,跑通流程后再逐步替换操作池、调整 Cell 数量,探索属于自己的“图纸”。

Cnorm:(hi−1,hi)↦hi+1,Cred:(hi,hi+1)↦hi+2\mathcal{C}_{\text{norm}}: (h_{i-1}, h_i) \mapsto h_{i+1}, \quad \mathcal{C}_{\text{red}}: (h_i, h_{i+1}) \mapsto h_{i+2}
Normal Cell 保持分辨率,Reduction Cell 降低分辨率,两种 Cell 按固定节奏交替堆叠。
  1. 普通 Cell\mathcal{C}_{\text{norm}} 接收前两层输入 h_{i-1} 和 h_i,输出分辨率不变的特征 h_{i+1}。
    Cnorm:(hi−1,hi)↦hi+1\mathcal{C}_{\text{norm}}: (h_{i-1}, h_i) \mapsto h_{i+1}
  2. 降采样 Cell\mathcal{C}_{\text{red}} 接收前两层输出,经降采样后产生分辨率减半的特征 h_{i+2}。
    Cred:(hi,hi+1)↦hi+2\mathcal{C}_{\text{red}}: (h_i, h_{i+1}) \mapsto h_{i+2}
  3. 交替模式两种 Cell 交替出现,每经过一个 Reduction Cell 特征图尺寸减半、通道数翻倍。
    ⋯→Cnorm→Cnorm→Cred→⋯\cdots \to \mathcal{C}_{\text{norm}} \to \mathcal{C}_{\text{norm}} \to \mathcal{C}_{\text{red}} \to \cdots

AI 应用场景

移动端高效模型自动设计

阶段:模型结构设计(AutoML)

解决的问题:手工设计移动端模型非常耗时,且精度与延迟之间的平衡极难把握。传统做法是先拿大模型压缩,效果常打折。利用 NAS 搜索空间设计,在约束(延迟、参数量)内搜索结构,从源头保证可用性。

具体案例:某 App 团队要在骁龙 8 系芯片上部署图像分类模型,用 NAS 在“延迟 ≤ 20ms、参数量 ≤ 4MB”的约束空间内搜索,最终找到比 MobileNetV3 精度高 2.1% 且延迟更低的网络——搜索空间里预设了跳连和深度可分离卷积,避免了事后压缩的精度损失。

垂直领域 OCR 特征网络定制

阶段:特征提取网络搜索

解决的问题:通用 backbone(如 ResNet)在票据识别等特定任务上,特征设计不够匹配。层级搜索允许不同抽象层级使用不同算子,让底层专注边缘纹理、高层专注语义结构。

具体案例:某金融科技公司的 OCR 团队在检测任务上使用层级搜索,底层用 3x3 小卷积核,高层改用膨胀卷积扩大感受野,搜出的定制 backbone 在公开测试集上字符识别率提升 3.8%,同时推理速度满足实时要求。

NAS 平台搜索空间配置中心

阶段:搜索空间基础设施

解决的问题:不同业务线需要不同搜索空间(有的重速度、有的重精度),手工搭建容易出错且无法复用。通过把搜索空间抽象成可配置的代码模块,用统一接口管理操作池、Cell 模板和约束规则,让各团队快速生成新型搜索空间。

具体案例:某企业中台搭建了“搜索空间配置中心”,将单元级、层级、整体网络三种粒度的搜索空间封装为 Python 配置类,产品经理通过修改 YAML 参数就能生成新搜索空间,两周内支撑了 3 个业务线的 NAS 实验。

Python 演示

python64 行
"""NAS搜索空间设计与组合数量统计"""import itertoolsfrom dataclasses import dataclass, field # 操作池(相当于乐高积木的类型)OP_POOL = [    "3x3_conv", "5x5_conv", "3x3_depthwise",    "3x3_max_pool", "3x3_avg_pool", "identity"]  @dataclassclass CellSearchSpace:    """单元级搜索空间:Cell内部有4个节点,每个节点从操作池选一个操作"""    num_nodes: int = 4    ops: list = field(default_factory=lambda: OP_POOL)     def count_ops_combinations(self) -> int:        """仅计算操作选择的组合数"""        return len(self.ops) ** self.num_nodes  @dataclassclass NetworkSearchSpace:    """整体搜索空间:堆叠N个Cell,每个Cell可选Normal或Reduction类型"""    num_cells: int = 6    cell_types: list = field(default_factory=lambda: ["normal", "reduction"])     def count_topologies(self) -> int:        """计算Cell类型的组合数"""        return len(self.cell_types) ** self.num_cells  def build_cell_example():    """构造一个简单的Cell DAG示例:4个节点的连接组合"""    nodes = ["input", "node1", "node2", "output"]    edges = []    for i in range(len(nodes)):        for j in range(i + 1, len(nodes)):            edges.append((nodes[i], nodes[j]))    return nodes, edges  def main():    cell_space = CellSearchSpace()    net_space = NetworkSearchSpace()    cell_combo = cell_space.count_ops_combinations()    topo_combo = net_space.count_topologies()    total = cell_combo * topo_combo    nodes, edges = build_cell_example()     print("=== NAS搜索空间设计演示 ===")    print(f"操作池大小: {len(OP_POOL)}")    print(f"Cell内节点数: {cell_space.num_nodes}")    print(f"Cell内操作组合数: {cell_combo}")    print(f"网络Cell数量: {net_space.num_cells}")    print(f"Cell类型组合数: {topo_combo}")    print(f"总搜索空间大小: {total}")    print(f"Cell DAG候选连接数: {len(edges)}")    print(f"示例连接: {edges[:5]}...")  if __name__ == "__main__":    main()
目的:演示搜索空间设计如何计算组合数量,直观展示“单元级 × 整体级”的搜索规模爆炸。
  1. OP_POOL = [...]定义搜索空间的“积木池”,共 6 种基础操作,相当于乐高零件类型清单。
  2. class CellSearchSpace封装单元级搜索空间,核心属性是节点数和操作池,对应“标准模块”的设计自由度。
  3. count_ops_combinations()计算 Cell 内部的操作组合数,使用 len(self.ops) ** self.num_nodes 体现指数增长。
  4. class NetworkSearchSpace封装整体网络搜索空间,决定 Cell 怎么堆叠,对应“楼层排布”的选择范围。
  5. count_topologies()计算网络宏观拓扑数,公式为 len(self.cell_types) ** self.num_cells。
  6. build_cell_example()生成一个 Cell 的 DAG 候选边集合,展示“任意两点可连”的拓扑设计空间。
  7. main()串起整个演示,输出各层组合数与总空间大小,让大家直观看到 1296 × 64 = 82944 的组合爆炸。

常见误区

误区既然搜索是自动的,那把能加的操作全都加进空间,选项越多、找到好网络的概率越大。

正解搜索空间过大时,组合数指数爆炸,搜索算法在有限预算内根本扫不完,好结构淹没在大量冗余组合里。这就好比给厨师的食材柜塞满 200 种调料,他反而不知道该怎么调味。好的搜索空间设计是在“覆盖好结构”和“控制规模”之间取平衡,而不是一味求大。

为何常见:直觉上“选择多=可能性多=结果好”,忽略了搜索是带预算的,没有免费的午餐。

误区单元级搜索找到优秀的 Cell 后,随便堆叠、随意连接都能得到高性能网络。

正解Cell 之间的连接方式、堆叠数量、通道数、降采样位置同样深刻影响最终效果。就像窗户模块磨得再漂亮,整栋楼朝向不对、楼层布局混乱,住起来依然别扭。NASNet 之所以强,是“好 Cell + 合理的整体排布”共同作用的结果。

为何常见:看到 NASNet 等论文重点展示 Cell 结构,容易误以为 Cell 是唯一的功臣。

误区NAS 是“全自动”找网络,不需要人类经验,搜索空间随便定一个就行。

正解搜索空间本身就是最强的先验——选择哪些操作、限定层数范围、是否允许跳连,每一条都编码了人类对视觉任务的理解。乐高套装里放哪些零件,本身就决定了能拼出什么。真正好的 NAS,是“人类划定边界 + 机器在边界内寻找”的协作。

为何常见:对“自动”一词的过度解读,把“自动寻找”与“完全无先验”混为一谈。

误区先无约束地搜索到高精度网络,部署时再压缩、剪枝、量化,效果差不多。

正解事后优化会造成精度损失,且可能反复迭代。把延迟、参数量、能耗等约束前置到搜索空间设计中,能直接从源头排除不可部署的结构,正如建筑规范必须前置设计而不是建完再改。MnasNet 和 MobileNetV3 的实践都证明“约束内搜索”优于“先搜后压”。

为何常见:惯性思维地认为搜索和部署是两个独立阶段,忽视了端到端协同设计的价值。

误区操作池塞进 7x7 卷积、膨胀卷积、注意力机制、多尺度模块……越多越好。

正解操作池过大会让搜索空间膨胀,且相似操作之间缺乏区分度,干扰搜索策略的判断。经典搜索空间通常只保留 6-8 种操作,就足以覆盖主流最优结构——做菜不是调料越多越好,搭配得当才是关键。

为何常见:直觉认为“多样性=强大”,忽略搜索算法在高相似度候选之间难以有效区分的问题。

面试题

Q1. NAS 中的“搜索空间”最恰当的理解是什么?

单选题 · easy

  • A.神经网络训练时的学习率
  • B.所有可能网络结构的集合← 正确答案
  • C.训练数据集的子集范围
  • D.损失函数的选择空间

答案:B。搜索空间是 NAS 可选的所有候选网络架构组成的集合,对应乐高积木池。学习率是训练配置,数据集是数据范畴,损失函数是优化目标,都不属于架构层面的搜索空间。选项 B 准确描述了定义核心。

Q2. 搜索空间设计为什么被称为“决定 NAS 天花板”?

单选题 · easy

  • A.因为它决定搜索速度的快慢
  • B.因为空间里没有的结构永远搜不出← 正确答案
  • C.因为它影响训练损失的值
  • D.因为它决定 GPU 显存大小

答案:B。NAS 只能从搜索空间内挑选网络,空间里没有的结构即使算力再强也搜不出来。就像乐高套装里没有三角形屋顶片,你拼不出尖顶小屋。搜索速度、训练损失和显存都是工程问题,不构成效果上限。

Q3. 组合爆炸在 NAS 搜索空间中的表现是什么?

单选题 · mid

  • A.模型参数太多导致内存溢出
  • B.候选结构数量随网络层数指数增长← 正确答案
  • C.训练时梯度值不断变大
  • D.数据集太大导致加载超时

答案:B。搜索空间中每个位置有若干操作选项,整体组合数为各位置选项数连乘,随层数 n 呈 O(c^n) 增长,这就是组合爆炸。参数多、梯度爆炸、数据量大是其他维度的工程问题,与搜索空间的组合规模不是一个概念。

Q4. 以下哪些属于 NAS 搜索空间设计的三种粒度?

多选题 · mid

  • A.单元级搜索← 正确答案
  • B.层级搜索← 正确答案
  • C.整体网络搜索← 正确答案
  • D.超参数搜索

答案:ABC。搜索空间设计的三种粒度是单元级(Cell 内部)、层级(多抽象层组合)和整体网络(宏观排布)。超参数搜索(学习率等)不属于网络架构搜索空间设计,它属于优化过程的外围调参。

Q5. 单元级搜索中"Cell"最贴切的乐高比喻是什么?

单选题 · easy

  • A.整栋房子的外观设计
  • B.可批量复制的标准窗模块← 正确答案
  • C.打地基的砖块类型
  • D.室内装修的风格方案

答案:B。Cell 是搜索到后在网络中反复堆叠复用的基础单元,相当于“标准窗子模块”——设计一次、批量使用。整栋房对应整体网络,地基砖块对应基础操作,装修风格对应训练策略,都与 Cell 的定位不符。

Q6. 跳连(Skip Connection)在深层网络中的核心作用是?

单选题 · mid

  • A.增加网络参数量以提升容量
  • B.缓解梯度消失,让深层网络可训练← 正确答案
  • C.只用于加速推理速度
  • D.减少训练所需的数据量

答案:B。跳连把前层特征直接加到后层,让梯度可以无损回传,缓解极深网络的梯度消失问题。参数增加只是附带现象,推理加速和数据需求都与其核心机制无关。

Q7. 为什么“先搜索后压缩”通常不如“约束内搜索”?

单选题 · hard

  • A.先搜索后压缩会产生额外训练开销
  • B.事后压缩会造成精度损失且需反复迭代← 正确答案
  • C.约束内搜索一定找到全局最优
  • D.先搜索后压缩无法部署到任何设备

答案:B。无约束搜索出的结构可能严重超出部署资源预算,压缩、剪枝等事后手段会损害精度且需要多轮调优。约束内搜索从源头排除不可部署结构,如建筑规范前置设计。选项 A 中的额外开销存在但不是核心问题,C 过于绝对,D 明显错误。

Q8. 搜索空间“不是越大越好”的合理理由有哪些?

多选题 · hard

  • A.大空间导致搜索效率严重下降← 正确答案
  • B.大空间产生大量无区分度的冗余结构← 正确答案
  • C.大空间保证包含更好的结构但找不到也无效← 正确答案
  • D.大空间让搜索算法自动找到最优解

答案:ABC。大空间让搜索算法在有限预算内难以充分探索(A),且相似操作的增多会稀释搜索信号的区分度(B)。即使大空间理论上包含更好的结构(C 的前半句不总是成立),找不到就谈不上收益。D 完全错误——大空间不会自动收敛到最优解,反而更难搜。

Q9. NASNet 的搜索空间设计中,减少搜索复杂度的关键做法是?

单选题 · hard

  • A.对网络的每一层独立搜索操作
  • B.搜索一个 Cell 结构然后堆叠复用← 正确答案
  • C.不包含任何降采样操作
  • D.完全去掉跳连以简化空间

答案:B。NASNet 的精髓在于“搜小放大”——只搜索 Normal Cell 和 Reduction Cell 两种单元,再大规模堆叠复用。如果逐层独立搜索会让空间指数爆炸;不降采样就无法构建层级特征;去掉跳连会让深层网络难以训练。堆叠复用显著压低了搜索成本。

Q10. 关于层级搜索,以下说法正确的有哪些?

多选题 · mid

  • A.将网络拆分为操作、Cell、网络多个层级← 正确答案
  • B.不同层级可以使用不同粒度的搜索策略← 正确答案
  • C.层级搜索完全替代了单元级搜索
  • D.层级之间通过笛卡尔积组合成总空间← 正确答案

答案:ABD。层级搜索的核心是把搜索空间分解为操作级、Cell 级、网络级三个层次,各层独立确定再组合(A、B、D 正确)。它是对单元级搜索的扩展而非替代——单元级搜索依然存在于中层,C 错误。总空间等于各层子空间的笛卡尔积。