news 2026/10/22 8:41:52

无需训练也能做架构搜索?NASWOT 初始化评分机制解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
无需训练也能做架构搜索?NASWOT 初始化评分机制解析

1. 这篇论文到底在解决什么问题

第一次看到Neural Architecture Search without Training这个标题,我脑子里蹦出来的第一个念头是:不训练也能做架构搜索?这要么是个标题党,要么是真的把某个关键假设给拆掉了。读完论文之后我确认是后者,而且它拆掉的这个假设,恰恰是过去几年 NAS 领域最贵的那块成本。

先把背景说清楚。NAS 要干的事情,是在一个巨大的候选架构空间里,找到在目标任务上表现最好的那个网络结构。问题在于,评估一个候选架构好不好,传统做法是把它完整训练一遍,看验证集精度。训练一个网络动辄几小时到几天,而搜索空间里可能有成千上万个候选,这个组合爆炸直接把 NAS 变成了大厂才玩得起的游戏。后来大家想办法加速,比如权重共享、超网、代理模型、性能预测器,本质都是在“怎么少训练一点还能估准”上做文章。

这篇论文的思路更激进:它压根不看训练后的性能,而是看网络在初始化状态下、还没开始训练时的行为特征,用这个特征去预测这个架构训练完之后大概好不好。换句话说,它把“评估一个架构”这件事,从“训练完再看”提前到了“初始化就能看”。

这个想法为什么成立?论文给出的核心洞察是:一个架构在随机初始化时,它对输入数据的响应方式,已经隐含了它的表达能力、梯度传播特性、以及信息流动的通畅程度。一个初始化就“死掉”或者“爆炸”的网络,训练起来大概率也好不到哪去;而一个初始化时响应丰富、梯度分布健康的网络,往往更有潜力。这个逻辑其实和我们在实际调网络时的直觉是一致的——你搭完一个网络,跑一个前向,看看输出是不是全一样、梯度是不是全零,心里大概就有数了。论文做的事情,是把这个直觉量化成一个可计算的分数,然后用它来排序候选架构。

它提出的这个分数叫NASWOT,全称是 Neural Architecture Search without Training。核心计算非常轻量:给网络喂一批输入,看每个 ReLU 激活单元在 batch 内的激活模式(activation pattern),统计不同输入样本之间激活模式的差异程度,用这个差异度作为架构的评分。差异越大,说明这个架构对输入越敏感、表达越丰富,越可能是好架构。

适合谁来读这篇?如果你正在做 NAS 相关的研究或者工程落地,尤其是被算力卡住、想找低成本评估方案的人,这篇必读。如果你只是对“为什么初始化状态能反映网络潜力”这个反直觉的结论感兴趣,它也值得花时间。哪怕你不做 NAS,理解“初始化行为可以预测训练结果”这个视角,对你调参、诊断网络也有实际帮助。

2. 核心思路拆解:为什么初始化状态能当“预言机”

2.1 从“训练后评估”到“初始化评估”的范式转变

传统 NAS 的评估流程可以概括成一句话:候选架构 → 完整训练 → 验证精度 → 排序。这个链条里,训练是绝对的成本大头。权重共享类方法(比如 ENAS、DARTS)试图通过让所有候选共享一套权重来摊薄成本,但共享权重会引入偏差——共享的那套权重未必适合每个候选,评估出来的排名可能失真。性能预测器类方法(比如基于学习曲线外推)需要先跑一部分训练才能预测,还是逃不掉训练。

这篇论文的转变在于:它问了一个更根本的问题——我们真的需要“训练后”的信息吗?如果一个架构的潜力在初始化时就写在它的结构里,那我们只需要一次前向传播就能读出来。这个假设如果成立,评估成本就从“训练一个网络”降到“跑一次前向”,量级上差了好几个数量级。

我一开始是怀疑的。因为随机初始化本身带有很大的随机性,同一个架构换一个随机种子,初始化状态就不一样,那评分岂不是不稳定?论文对此的回应是:它看的不是单个神经元的绝对激活值,而是激活模式在样本间的相对差异,这个统计量对随机种子不敏感。换句话说,它抓的是结构决定的、统计意义上的性质,而不是某一次初始化的偶然结果。这一点很关键,也是它能 work 的前提。

2.2 NASWOT 分数的计算逻辑

把 NASWOT 的计算拆开,其实就三步。

第一步,给网络随机初始化权重,然后喂一批输入样本(论文里用的是一小批,比如 16 或 32 个样本,不需要标签)。

第二步,对网络中每个 ReLU 层,记录每个神经元在这批样本上的激活状态。ReLU 的输出要么是 0(未激活),要么是正值(激活)。我们只关心“激活还是没激活”这个二值模式,所以把每个神经元的输出二值化:大于 0 记 1,等于 0 记 0。

第三步,对每个神经元,看它在这批样本上的二值激活模式。如果所有样本都让这个神经元激活(全 1)或者都不激活(全 0),说明这个神经元对输入不敏感,是个“死”神经元或者“常开”神经元,贡献有限。如果不同样本让这个神经元呈现不同的激活模式,说明它在区分输入,是有用的。把所有神经元的这种“区分能力”加起来,就得到整个架构的 NASWOT 分数。

用更形式化的语言:对第 k 个神经元的激活模式向量(长度等于样本数),计算它和自身转置的外积,得到一个样本×样本的矩阵,矩阵元素表示两个样本在这个神经元上是否激活模式一致。把所有神经元的这个矩阵加起来,再取某种范数或者核范数,就得到分数。论文里用的是核矩阵的核范数(或者等价的、更省算力的近似)。

这个计算有多便宜?一次前向传播,加上一些矩阵运算。对比训练一个网络需要的成百上千次前向加反向,这个成本几乎可以忽略。论文里报告的数字是,在 NAS-Bench-201 搜索空间上,用 NASWOT 评估所有候选架构,总共只需要几秒到几十秒(取决于 batch 大小),而完整训练所有候选需要几千 GPU 小时。

2.3 为什么这个分数和最终性能相关

这里是最需要解释“为什么”的地方。NASWOT 分数高,意味着什么?

从信息论的角度看,一个网络的表达能力,取决于它能把输入空间映射到多少种不同的内部表示。如果所有输入都产生相同的激活模式,这个网络本质上是个常数函数,没有表达能力。如果不同输入产生不同的激活模式,网络在区分它们。NASWOT 分数衡量的就是这种区分能力的丰富程度。

从优化的角度看,一个初始化时激活模式就很多样化的网络,通常梯度传播也更健康。因为 ReLU 的激活状态决定了梯度能不能回传:如果一个神经元对所有输入都不激活,它的梯度永远是零,这个参数就学不动。NASWOT 分数高,说明有大量神经元在不同样本上交替激活,梯度有丰富的回传路径,训练时更容易优化。

从经验的角度看,这其实和我们平时诊断网络的做法一脉相承。你搭完一个网络,如果发现某一层输出全是零,你会知道这层废了;如果发现所有样本输出一模一样,你会知道网络没学到东西。NASWOT 只是把这个诊断从“训练后”提前到了“初始化”,并且量化成了一个可比较的分数。

论文在多个搜索空间(NAS-Bench-201、NAS-Bench-101、以及一些移动端搜索空间)上验证了 NASWOT 分数和最终精度之间的相关性。结论是:在 NAS-Bench-201 上,NASWOT 和最终精度的 Spearman 相关系数相当高,足以用来做候选筛选。这意味着你可以先用 NASWOT 把成千上万个候选快速筛到几十个,再对这几十个做完整训练,总成本大幅下降。

3. 实操复现:怎么在自己的项目里用起来

3.1 环境准备与依赖

复现 NASWOT 不需要什么特殊环境,一台有 GPU 的机器(甚至 CPU 也能跑,因为只做前向)加上 PyTorch 就够了。论文官方代码是基于 PyTorch 的,核心逻辑不到一百行。我建议的依赖版本是 PyTorch 1.7 以上,torchvision 配套版本,numpy 用于统计。不需要额外的 NAS 框架,因为 NASWOT 本身是个评估指标,不绑定搜索策略。

如果你用的是 NAS-Bench-201 这类标准 benchmark,还需要下载对应的数据集和搜索空间定义文件。这些在论文的 GitHub 仓库里有说明。我实测下来,整个环境搭起来大概十几分钟,主要时间花在下载数据集上。

提示:NASWOT 只需要前向传播,所以对 GPU 显存要求很低。如果你在搜索空间上批量评估,可以把 batch 设大一点,充分利用并行。但注意 batch 太大会让激活模式的统计变得平滑,反而降低区分度,论文里用的 batch 是 16 到 64 之间,我建议从 32 开始试。

3.2 核心代码实现

下面是我根据论文逻辑重写的 NASWOT 计算核心,去掉了官方代码里一些为了兼容不同搜索空间的封装,保留最本质的部分。你可以直接拿去用。

import torch import torch.nn as nn import numpy as np def compute_naswot_score(model, inputs): """ 计算给定模型在给定输入上的 NASWOT 分数。 model: 待评估的网络,已随机初始化 inputs: 一批输入样本,shape [batch_size, ...] 返回: 标量分数 """ model.eval() activation_patterns = [] # 注册 hook 捕获每个 ReLU 层的输出 hooks = [] def get_hook(name): def hook(module, input, output): # 二值化:大于0记1,等于0记0 binary = (output > 0).float() # 展平空间维度,保留 batch 和通道 # 对于卷积层输出 [B, C, H, W] -> [B, C*H*W] # 对于全连接层输出 [B, C] -> [B, C] if binary.dim() > 2: binary = binary.flatten(2) # [B, C, H*W] binary = binary.permute(0, 2, 1) # [B, H*W, C] binary = binary.reshape(binary.size(0), -1) # [B, H*W*C] activation_patterns.append(binary) return hook for name, module in model.named_modules(): if isinstance(module, nn.ReLU): hooks.append(module.register_forward_hook(get_hook(name))) with torch.no_grad(): _ = model(inputs) for h in hooks: h.remove() # 拼接所有层的激活模式 # 每个元素 shape [B, N_i],N_i 是该层神经元数 # 我们需要对每个神经元计算样本间的核矩阵 total_kernel = None for pattern in activation_patterns: # pattern: [B, N] # 计算样本间相似度:对每个神经元,看两个样本是否激活模式一致 # 等价于 pattern @ pattern.T,但需要按神经元归一化 # 论文用的是未归一化的核矩阵之和 kernel = pattern @ pattern.t() # [B, B] if total_kernel is None: total_kernel = kernel else: total_kernel = total_kernel + kernel # 取核矩阵的核范数(奇异值之和)作为分数 # 也可以用 Frobenius 范数,论文里两者都试过,核范数效果略好 try: score = torch.linalg.matrix_norm(total_kernel, ord='nuc').item() except AttributeError: # 兼容老版本 PyTorch score = torch.norm(total_kernel, p='nuc').item() return score

这段代码有几个细节值得说。第一,hook 注册在 ReLU 层上,因为 NASWOT 只关心 ReLU 的激活模式。如果你的网络用的是其他激活函数(比如 GELU、SiLU),需要相应调整二值化逻辑,但论文的实验都是基于 ReLU 的。第二,卷积层的输出需要展平空间维度,因为同一个通道在不同空间位置的激活模式都算作这个通道的“行为”。第三,核矩阵的核范数计算,在 PyTorch 新版本里用torch.linalg.matrix_norm,老版本用torch.norm。

注意:这段代码假设输入 batch 不会太大(比如不超过 128),因为核矩阵是 B×B 的,B 太大会让矩阵运算变慢。如果你要评估的候选很多,建议固定一个小的 batch(比如 32),对每个候选跑一次。

3.3 在搜索空间上批量评估

有了单模型评分函数,批量评估就简单了:遍历搜索空间里的每个候选架构,实例化、随机初始化、跑一次前向、算分、记录。下面是一个简化的流程。

def evaluate_search_space(search_space, inputs, top_k=50): """ search_space: 可迭代的架构定义列表 inputs: 固定的一批输入样本 top_k: 返回分数最高的前 k 个架构 """ scores = [] for idx, arch in enumerate(search_space): model = build_model_from_arch(arch) # 根据架构定义构建模型 model.apply(init_weights) # 随机初始化 score = compute_naswot_score(model, inputs) scores.append((idx, score, arch)) # 按分数降序排序 scores.sort(key=lambda x: x[1], reverse=True) return scores[:top_k]

这里的关键是inputs要固定。论文里用的是从训练集里随机采样的一小批样本,不需要标签。我建议多采样几批(比如 3 到 5 批),对每个架构算多次分数取平均,这样能降低单批样本带来的方差。实测下来,取 3 批平均之后,分数排名的稳定性明显提升。

还有一个实操细节:随机初始化的方式会影响分数。论文用的是标准的 Kaiming 初始化或者 PyTorch 默认初始化。我建议固定初始化方式,并且在评估不同架构时用相同的随机种子序列,保证可比性。如果你发现同一个架构两次评估分数差异很大,那可能是初始化方式或者 batch 选择有问题。

3.4 从分数到最终选择:怎么用 NASWOT 筛候选

NASWOT 分数本身不是最终精度,它是一个排序信号。实际用法是:用 NASWOT 把大搜索空间快速筛到一个小候选集(比如 top 5% 或 top 50 个),然后对这个小候选集做完整训练,选验证精度最高的那个。

这个流程的有效性取决于 NASWOT 分数和最终精度的相关性。论文报告的相关性在不同搜索空间上不一样:在 NAS-Bench-201 上很高,在 NAS-Bench-101 上中等,在一些更大的搜索空间上会下降。所以你不能盲目相信 NASWOT 的绝对排名,但把它当作一个粗筛工具是靠谱的。

我自己的经验是,NASWOT 特别适合用来排除明显差的架构。那些分数极低的架构,几乎可以肯定训练出来也不行。但分数最高的那几个,未必就是最终最好的,因为架构之间的差异可能很小,NASWOT 的分辨率不够。所以筛完之后,还是要靠训练来定夺。

4. 常见问题与排查技巧实录

4.1 分数不稳定怎么办

这是我最开始遇到的问题。同一个架构,换一批输入样本,NASWOT 分数波动能到 10% 以上。排查下来有几个原因。

第一个原因是 batch 太小。batch 只有 8 的时候,样本间的激活模式统计噪声很大。把 batch 提到 32 或 64,波动明显减小。第二个原因是只跑了一批样本。我后来改成跑 5 批,每批 32 个样本,取平均,分数就稳多了。第三个原因是初始化种子。如果你在评估不同架构时用了不同的随机种子,那分数差异里混入了初始化噪声。固定种子序列可以解决。

还有一个隐蔽的原因:某些架构在初始化时会出现大量“全零”激活,导致核矩阵接近零矩阵,核范数很小。这种架构的分数本身就低,而且方差大。对于这类架构,NASWOT 的判断是“不值得训练”,这个判断通常是对的,所以不用太纠结它的分数波动。

4.2 和训练结果对不上怎么办

如果你发现 NASWOT 分数高的架构,训练出来反而差,先别急着否定这个方法。检查几件事。

第一,你的搜索空间是不是和论文里的类似?NASWOT 在 NAS-Bench-201 这种结构规整、层数固定的空间上表现最好。如果你的搜索空间里有大量非常规结构(比如跳跃连接特别多、层数差异巨大),NASWOT 的假设可能不成立。第二,你的输入样本是不是有代表性?如果采样到的样本恰好都是某一类,激活模式统计会有偏。建议从训练集里分层采样。第三,你的训练配置是不是一致?如果不同架构用了不同的学习率、不同的训练轮数,那最终精度的差异里混入了训练配置的影响,不能全怪 NASWOT。

论文里也承认,NASWOT 和最终精度的相关性不是完美的,尤其在搜索空间很大、架构差异很细微的时候。它的定位是“快速粗筛”,不是“精确预测”。把它和少量完整训练结合,才是正确的用法。

4.3 计算开销到底省了多少

论文里给的数据是,在 NAS-Bench-201 上,完整训练所有 15625 个架构需要大约 3000 GPU 小时(每个架构训练 200 epoch)。用 NASWOT 评估所有架构,只需要几秒到几十秒(取决于 batch 和样本数)。这个对比是惊人的。

但要注意,这个对比是在“评估”环节。如果你最终还是要训练 top 50 个架构,那训练成本是 50 个架构的训练时间,相比 15625 个,还是省了两个数量级。所以整体流程的成本是:NASWOT 评估(可忽略)+ 少量训练(大幅减少)。

我实测下来,在一个中等规模的搜索空间(约 1000 个候选)上,用 NASWOT 筛到 top 20,再训练这 20 个,总时间比训练全部 1000 个少了 95% 以上,而最终选出的架构精度和全量训练选出的最佳架构差距在 0.5% 以内。这个性价比非常高。

4.4 常见问题速查表

问题现象可能原因排查方法解决建议
分数波动大batch 太小、样本批次少、初始化种子不固定增大 batch 到 32-64,多批取平均,固定种子用 5 批×32 样本,固定初始化
分数全为零网络初始化导致 ReLU 全不激活检查初始化方式,看是否有层输出全零换 Kaiming 初始化,检查网络结构
和训练结果相关性低搜索空间差异大、样本无代表性、训练配置不一致检查搜索空间结构,分层采样,统一训练配置只在结构规整的空间用,粗筛而非精筛
计算太慢batch 太大、候选太多、没并行减小 batch,用 GPU 并行,分批评估batch 32,GPU 前向,多进程
核范数计算报错PyTorch 版本旧检查 torch 版本用torch.norm替代torch.linalg.matrix_norm

提示:NASWOT 的官方代码里有一个细节,它对核矩阵做了归一化处理(除以神经元总数),这样不同大小的架构分数可比。我在上面的代码里没加这个归一化,因为如果你只在同一个搜索空间内比较,归一化不影响排序。但如果你要跨搜索空间比较,记得加上。

5. 这个方法的边界与我的实际体会

NASWOT 不是万能的。它的核心假设是“初始化时的激活模式丰富度反映了架构潜力”,这个假设在 ReLU 网络、结构规整的搜索空间上成立得比较好。但如果你的网络用了大量非 ReLU 激活、或者有复杂的门控机制、或者架构差异主要体现在训练动态而非初始化状态上,NASWOT 的预测能力会下降。

论文自己也做了消融实验,发现 NASWOT 在 NAS-Bench-201 上的表现最好,在 NAS-Bench-101 上稍弱,在一些更大的、更异构的搜索空间上进一步下降。这说明它的适用范围是有边界的。你不能把它当成一个通用的、精确的性能预测器,而应该把它当成一个“快速排除差候选”的工具。

我在实际项目里用下来的体会是:NASWOT 最大的价值不是帮你找到最好的架构,而是帮你快速扔掉最差的那些。在一个几千候选的搜索空间里,真正有潜力的可能就几十个,剩下的都是陪跑。NASWOT 能在几秒内把这几十个圈出来,让你不用在陪跑者身上浪费算力。这个定位想清楚了,用起来就很顺手。

还有一个我踩过的坑:一开始我试图用 NASWOT 分数直接做架构排序,选分数最高的那个去训练,结果发现它未必是最好的。后来改成“NASWOT 筛 top 50,再训练选最佳”,效果就稳定了。所以千万别把粗筛当精筛用。

最后分享一个小技巧:如果你手头已经有一些训练好的架构和它们的精度,可以拿这些数据来校准 NASWOT 分数和精度之间的映射关系。比如拟合一个简单的线性回归或者秩相关,看看在你的搜索空间上 NASWOT 的预测能力到底如何。如果相关性很低,那就别硬用,换别的方法。如果相关性不错,那就可以放心用它来加速搜索。这个校准步骤花不了多少时间,但能帮你判断这个方法在你的场景下值不值得用。

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

墨水屏+NB-IoT/GPRS HAT实现低功耗物联网终端开发全指南

简介:一套面向嵌入式开发者的物联网扩展板示例代码包,整合电子纸墨水屏显示、NB-IoT与GPRS蜂窝通信及HAT硬件抽象层标准,适合正在学习低功耗远程可视化设备的单片机工程师。代码基于C语言实现,覆盖墨水屏初始化与刷新、NB-IoT模块…

作者头像 李华
网站建设 2026/10/22 8:40:49

大模型选型指南:从需求到实操,教你选出最适合的AI模型

1. 选型之前先想清楚:你到底要解决什么问题 1.1 大模型不是万能工具箱,先分清你的真实需求 很多人一上来就问“哪个模型最强”,这个问题本身就没有标准答案。我见过太多人花了一周时间对比各种评测榜单,最后发现自己只是想让模型…

作者头像 李华
网站建设 2026/10/22 8:40:36

联邦学习实战:数据不动模型动的隐私保护新范式

数据科学这个圈子里,隐私保护一直是压在案头的一叠“旧账”。过去几年,我经手过不少与数据协作相关的项目,最深的感受是:各方手里明明都有数据,却因为合规壁垒、商业机密、用户隐私这些顾虑,谁也不敢轻易把…

作者头像 李华
网站建设 2026/10/22 8:40:04

办公场景自托管聊天平台:Synapse部署与运维实战

1. 为什么在办公场景里,我更愿意用 Synapse 而不是临时拉个群前段时间帮团队整理内部通讯方案的时候,我决定把 Matrix 协议的服务端 Synapse 装到一台 Ubuntu 服务器上,做一套只跑在本地网络里的办公平台。选这套东西的原因很直接&#xff1a…

作者头像 李华
网站建设 2026/10/22 8:39:28

AI编程模板系统:可复用、可组合、可验证的工程化提效方案

1. 这不是又一个“AI编程插件”,而是一套被低估的工程化提效系统 你有没有过这种体验:写一段数据清洗脚本,光是查pandas的 .groupby() 参数就花了8分钟;调试一个API接口报错,翻了三页Stack Overflow才找到那个少写的…

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

Cherry Studio模型ID静默失效:连字符与下划线的规范化陷阱

1. 问题初现:模型“明明加载了”却始终不工作那天下午三点十七分,我正在调试一个刚接入 Cherry Studio 的多模态推理服务。前端传来的请求参数里,model_id填的是qwen2-vl-7b-chat,日志里清清楚楚写着✅ Model loaded: qwen2-vl-7b…

作者头像 李华