目录
- [NAS 基础理论](#NAS 基础理论)
- 搜索空间设计
- 基于强化学习的搜索
- 基于进化的搜索
- DARTS:可微分架构搜索
- [高效 NAS 方法](#高效 NAS 方法)
- [硬件感知 NAS](#硬件感知 NAS)
- [NAS 在不同领域的应用](#NAS 在不同领域的应用)
- 评估指标与基准
- 前沿与展望
1. NAS 基础理论
1.1 什么是神经架构搜索
神经架构搜索 (Neural Architecture Search, NAS) 的定义:
自动设计最优的神经网络架构
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 传统方法: 人工设计架构 │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ 专家经验 → 设计架构 → 训练 → 评估 → 调整 → ... │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ NAS: 自动搜索架构 │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ 搜索空间 → 搜索策略 → 架构评估 → 最优架构 │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
NAS 的三个核心组件:
1. 搜索空间 (Search Space): 定义可能的架构
2. 搜索策略 (Search Strategy): 如何探索搜索空间
3. 评估策略 (Evaluation Strategy): 如何评估架构性能
1.2 NAS 的理论框架
NAS 的数学形式化:
给定:
搜索空间 A
评估函数 f(a) (架构 a 的性能)
计算预算 B
目标:
a* = argmax_{a∈A} f(a)
s.t. 计算成本 ≤ B
挑战:
1. 搜索空间巨大: |A| 可能达到 10^18
2. 评估昂贵: 每个架构需要训练
3. 离散优化: 架构是离散变量
1.3 NAS 的发展历史
NAS 发展时间线:
2017 ──┬── NASNet (强化学习)
│ 首次大规模 NAS
│
2018 ──┼── ENAS (权重共享)
│ 大幅降低计算成本
│
2019 ──┼── DARTS (可微分搜索)
│ 连续松弛,梯度优化
│
2020 ──┼── EfficientNet (复合缩放)
│ 系统化的模型缩放
│
2021 ──┼── AutoFormer (ViT NAS)
│ Transformer 架构搜索
│
2022+ ──┴── 大模型 NAS, 一次性 NAS
2. 搜索空间设计
2.1 搜索空间概述
搜索空间 (Search Space):
定义: 所有可能的架构的集合
设计原则:
1. 表达能力: 能表示好的架构
2. 大小适中: 不能太大 (无法搜索) 也不能太小 (错过好架构)
3. 先验知识: 包含已知的有效设计
搜索空间类型:
1. 宏观搜索空间: 整个网络架构
2. 微观搜索空间: 重复的单元 (Cell)
2.2 Cell-based 搜索空间
Cell-based 搜索空间:
核心思想:
搜索一个基本单元 (Cell)
然后堆叠多个 Cell 形成完整网络
Cell 结构:
- N 个节点 (Node)
- 每个节点有多个输入
- 每个输入有选择的操作
┌─────────────────────────────────────────────────────────────────┐
│ │
│ Cell 结构: │
│ │
│ 输入 ─┬─► [操作1] ─┬─► [操作2] ─┬─► 输出 │
│ │ │ │ │
│ └─► [操作3] ─┘ │ │
│ │ │
│ ┌─► [操作4] ─────────────┘ │
│ │ │
│ └─► [操作5] ───────────────► 输出 │
│ │
└─────────────────────────────────────────────────────────────────┘
python
import torch
import torch.nn as nn
class Cell(nn.Module):
"""
Cell-based 搜索空间中的基本单元
理论:
搜索一个基本 Cell 结构
堆叠多个 Cell 形成完整网络
优势:
- 搜索空间小
- 架构可复用
- 便于迁移
"""
def __init__(self, num_nodes=4, num_ops=8):
super().__init__()
self.num_nodes = num_nodes
# 可选操作
self.ops = nn.ModuleDict({
'none': Zero(),
'skip_connect': Identity(),
'sep_conv_3x1': SepConv(3, 1),
'sep_conv_5x1': SepConv(5, 1),
'sep_conv_3x2': SepConv(3, 2),
'sep_conv_5x2': SepConv(5, 2),
'dil_conv_3x2': DilConv(3, 2),
'avg_pool_3x1': Pool('avg', 3),
'max_pool_3x1': Pool('max', 3)
})
# 节点输入选择
self.node_inputs = nn.ModuleDict()
for i in range(2, num_nodes + 2):
self.node_inputs[f'node_{i}'] = nn.ModuleDict({
f'input_{j}': nn.ModuleDict({
op_name: op for op_name, op in self.ops.items()
})
for j in range(i)
})
def forward(self, s0, s1, weights):
"""
s0, s1: 前两个 Cell 的输出
weights: 架构参数 (每个操作的权重)
"""
states = [s0, s1]
for i in range(2, self.num_nodes + 2):
# 对每个输入加权求和
node_input = 0
for j in range(i):
for op_name, op in self.ops.items():
weight = weights[f'node_{i}'][f'input_{j}'][op_name]
node_input = node_input + weight * op(states[j])
states.append(node_input)
# 拼接所有中间节点
output = torch.cat(states[2:], dim=1)
return output
class SepConv(nn.Module):
"""深度可分离卷积"""
def __init__(self, kernel_size, stride):
super().__init__()
self.op = nn.Sequential(
nn.ReLU(),
nn.Conv2d(32, 32, kernel_size, stride=stride, padding=kernel_size//2, groups=32),
nn.Conv2d(32, 32, 1),
nn.BatchNorm2d(32),
nn.ReLU(),
nn.Conv2d(32, 32, kernel_size, stride=1, padding=kernel_size//2, groups=32),
nn.Conv2d(32, 32, 1),
nn.BatchNorm2d(32)
)
def forward(self, x):
return self.op(x)
"""
Cell-based 搜索空间的优势:
1. 搜索空间小:
只搜索一个 Cell
而非整个网络
2. 可迁移:
Cell 可以在不同数据集上复用
可以堆叠不同数量的 Cell
3. 先验知识:
Cell 结构基于已有的设计经验
2.3 宏观搜索空间
宏观搜索空间:
搜索整个网络架构
包括每一层的操作和连接
优势:
- 更大的搜索空间
- 可能发现更好的架构
劣势:
- 搜索空间巨大
- 计算成本高
- 难以迁移
python
class MacroSearchSpace(nn.Module):
"""
宏观搜索空间
搜索整个网络架构
"""
def __init__(self, num_layers=20, num_ops=8):
super().__init__()
self.num_layers = num_layers
# 每层可选的操作
self.ops = nn.ModuleList([
nn.ModuleDict({
'conv_3x3': nn.Conv2d(32, 32, 3, padding=1),
'conv_5x5': nn.Conv2d(32, 32, 5, padding=2),
'sep_conv_3x3': SepConv(3, 1),
'sep_conv_5x5': SepConv(5, 1),
'dil_conv_3x3': DilConv(3, 1),
'max_pool_3x3': nn.MaxPool2d(3, padding=1),
'avg_pool_3x3': nn.AvgPool2d(3, padding=1),
'skip': nn.Identity()
})
for _ in range(num_layers)
])
def forward(self, x, arch_params):
"""
x: [B, C, H, W]
arch_params: 每层的操作选择
"""
for i in range(self.num_layers):
op_name = arch_params[i]
x = self.ops[i][op_name](x)
return x
"""
宏观 vs 微观搜索空间:
宏观:
搜索整个网络
搜索空间大
难以迁移
微观 (Cell-based):
搜索基本单元
搜索空间小
便于迁移
实践中 Cell-based 更常用
"""
3. 基于强化学习的搜索
3.1 NASNet
论文: "Learning Transferable Architectures for Scalable Image Recognition"
(Zoph et al., 2018)
核心思想:
使用强化学习搜索最优的 Cell 结构
方法:
1. RNN 控制器生成架构描述
2. 训练子模型评估性能
3. 用性能作为奖励更新控制器
python
class NASNetController(nn.Module):
"""
NASNet 控制器
使用 RNN 生成架构描述
理论:
RNN 逐步生成架构的每个选择
使用 REINFORCE 算法训练
"""
def __init__(self, num_ops=8, num_nodes=4):
super().__init__()
self.num_ops = num_ops
self.num_nodes = num_nodes
# RNN 控制器
self.rnn = nn.LSTMCell(32, 32)
# 预测头
self.op_logits = nn.Linear(32, num_ops)
self.input_logits = nn.Linear(32, num_nodes)
# 嵌入
self.op_embedding = nn.Embedding(num_ops, 32)
self.input_embedding = nn.Embedding(num_nodes, 32)
def forward(self, batch_size=1):
"""
生成架构描述
"""
# 初始化
h = torch.zeros(batch_size, 32)
c = torch.zeros(batch_size, 32)
ops = []
inputs = []
for i in range(self.num_nodes):
# 预测操作
op_logit = self.op_logits(h)
op = torch.multinomial(torch.softmax(op_logit, dim=-1), 1)
ops.append(op)
# 预测输入
input_logit = self.input_logits(h)
input_idx = torch.multinomial(torch.softmax(input_logit, dim=-1), 1)
inputs.append(input_idx)
# 更新 RNN
op_emb = self.op_embedding(op)
input_emb = self.input_embedding(input_idx)
h, c = self.rnn(op_emb + input_emb, (h, c))
return ops, inputs
"""
NASNet 的训练:
REINFORCE 算法:
1. 控制器采样架构
2. 训练子模型
3. 用验证准确率作为奖励
4. 更新控制器
奖励: R = 准确率
梯度: ∇θ J(θ) = E[R · ∇θ log p(arch; θ)]
"""
3.2 REINFORCE 算法
python
class REINFORCE:
"""
REINFORCE 算法用于 NAS
理论:
策略梯度方法
用性能作为奖励更新控制器
"""
def __init__(self, controller, lr=0.001):
self.controller = controller
self.optimizer = torch.optim.Adam(controller.parameters(), lr=lr)
# 基线 (减少方差)
self.baseline = 0
def train_step(self, architectures, rewards):
"""
architectures: 采样的架构
rewards: 对应的性能
"""
# 计算策略梯度
log_probs = []
for arch in architectures:
log_prob = self.controller.log_prob(arch)
log_probs.append(log_prob)
log_probs = torch.stack(log_probs)
# 减去基线
advantages = rewards - self.baseline
# 策略梯度损失
loss = -(log_probs * advantages).mean()
# 更新
self.optimizer.zero_grad()
loss.backward()
self.optimizer.step()
# 更新基线
self.baseline = 0.9 * self.baseline + 0.1 * rewards.mean().item()
return loss.item()
"""
REINFORCE 的理论:
策略梯度定理:
∇θ J(θ) = E[∇θ log π(a|s) · R(a)]
在 NAS 中:
策略: π(arch; θ) = 控制器生成架构的概率
奖励: R(arch) = 架构的验证准确率
基线:
b = E[R] (移动平均)
减少方差: ∇θ J(θ) = E[∇θ log π(a|s) · (R(a) - b)]
"""
4. 基于进化的搜索
4.1 进化算法概述
进化算法 (Evolutionary Algorithm) 用于 NAS:
核心思想:
模拟自然选择
保留好的架构,淘汰差的架构
流程:
1. 初始化种群
2. 评估适应度 (性能)
3. 选择 (保留好的)
4. 变异 (生成新架构)
5. 重复步骤 2-4
python
class EvolutionaryNAS:
"""
基于进化的 NAS
理论:
模拟自然选择
保留好的架构,淘汰差的架构
"""
def __init__(self, population_size=50, mutation_rate=0.1):
self.population_size = population_size
self.mutation_rate = mutation_rate
self.population = []
def initialize(self, search_space):
"""初始化种群"""
for _ in range(self.population_size):
arch = search_space.random_architecture()
self.population.append(arch)
def evolve(self, search_space, num_generations=100):
"""进化搜索"""
for gen in range(num_generations):
# 评估适应度
fitness = []
for arch in self.population:
acc = self.evaluate(arch)
fitness.append(acc)
# 选择
selected = self.select(fitness)
# 变异
new_population = []
for arch in selected:
new_arch = self.mutate(arch, search_space)
new_population.append(new_arch)
self.population = new_population
# 返回最优架构
best_idx = np.argmax(fitness)
return self.population[best_idx]
def select(self, fitness):
"""
选择策略
理论:
保留适应度高的个体
轮盘赌选择或锦标赛选择
"""
# 锦标赛选择
selected = []
for _ in range(self.population_size):
# 随机选择 k 个个体
k = 3
candidates = np.random.choice(len(self.population), k, replace=False)
# 选择适应度最高的
best = candidates[np.argmax([fitness[i] for i in candidates])]
selected.append(self.population[best])
return selected
def mutate(self, arch, search_space):
"""
变异操作
理论:
随机修改架构的部分选择
探索搜索空间
"""
new_arch = arch.copy()
# 随机选择要变异的位置
num_mutations = int(len(arch) * self.mutation_rate)
mutation_positions = np.random.choice(len(arch), num_mutations, replace=False)
for pos in mutation_positions:
# 随机选择新操作
new_arch[pos] = search_space.random_operation()
return new_arch
"""
进化算法的优势:
1. 简单: 易于实现
2. 灵活: 可以处理各种约束
3. 并行: 可以并行评估多个架构
劣势:
1. 计算量大
2. 可能陷入局部最优
"""
4.2 AmoebaNet
论文: "Regularized Evolution for Image Classifier Architecture Search"
(Real et al., 2019)
核心创新:
正则化进化: 移除最老的个体 (而非最差的)
理论:
避免过拟合搜索历史
保持种群多样性
5. DARTS:可微分架构搜索
5.1 DARTS 核心思想
论文: "DARTS: Differentiable Architecture Search" (Liu et al., 2019)
核心创新:
将离散的架构选择松弛为连续优化
使用梯度下降搜索架构
理论:
原始问题: 离散选择 (argmax)
松弛后: 连续权重 (softmax)
可以用梯度下降优化
python
class DARTS(nn.Module):
"""
DARTS (Differentiable Architecture Search)
核心创新:
将离散选择松弛为连续优化
使用梯度下降搜索架构
理论:
每个操作有一个权重 α
输出 = Σ α_i · o_i(x)
训练结束后,选择权重最大的操作
"""
def __init__(self, num_nodes=4, num_ops=8):
super().__init__()
self.num_nodes = num_nodes
# 操作
self.ops = nn.ModuleList([
nn.ModuleList([
nn.ModuleDict({
'sep_conv_3x3': SepConv(3, 1),
'sep_conv_5x5': SepConv(5, 1),
'dil_conv_3x3': DilConv(3, 1),
'avg_pool_3x3': nn.AvgPool2d(3, padding=1),
'max_pool_3x3': nn.MaxPool2d(3, padding=1),
'skip_connect': nn.Identity(),
'none': Zero()
})
for _ in range(i) # 每个节点有 i 个输入
])
for i in range(2, num_nodes + 2)
])
# 架构参数 (可学习)
self.arch_params = nn.ParameterList()
for i in range(2, num_nodes + 2):
# 每个节点的每个输入的操作权重
param = nn.Parameter(torch.randn(i, num_ops) * 0.001)
self.arch_params.append(param)
def forward(self, s0, s1):
"""
s0, s1: 前两个 Cell 的输出
"""
states = [s0, s1]
for i in range(self.num_nodes):
# 获取当前节点的架构权重
weights = torch.softmax(self.arch_params[i], dim=-1)
# 对每个输入加权求和
node_input = 0
for j in range(i + 2):
for k, (op_name, op) in enumerate(self.ops[i][j].items()):
if op_name != 'none':
node_input = node_input + weights[j, k] * op(states[j])
states.append(node_input)
# 拼接所有中间节点
output = torch.cat(states[2:], dim=1)
return output
def get_architecture(self):
"""获取最终架构"""
arch = []
for i in range(self.num_nodes):
weights = torch.softmax(self.arch_params[i], dim=-1)
ops = weights.argmax(dim=-1)
arch.append(ops)
return arch
"""
DARTS 的训练:
双层优化:
外层: 优化架构参数 α
内层: 优化网络权重 w
min_α L_val(w*(α), α)
s.t. w*(α) = argmin_w L_train(w, α)
实际实现:
交替优化:
1. 固定 α,更新 w (训练集)
2. 固定 w,更新 α (验证集)
"""
5.2 DARTS 的问题与改进
DARTS 的问题:
1. 搜索不稳定:
架构参数可能震荡
搜索结果不一致
2. 性能差距:
搜索时的性能 ≠ 评估时的性能
权重共享导致评估不准
3. 搜索空间偏好:
倾向于选择 skip_connect
因为 skip_connect 训练更快
改进方法:
1. P-DARTS: 渐进式搜索
2. PC-DARTS: 部分通道连接
3. Fair DARTS: 公平竞争
4. DARTS-: 修正稳定性
python
class FairDARTS(nn.Module):
"""
Fair DARTS
改进:
使用 Sigmoid 替代 Softmax
每个操作独立竞争
理论:
Softmax 导致操作之间竞争
Sigmoid 允许多个操作共存
"""
def __init__(self, num_nodes=4, num_ops=8):
super().__init__()
# 架构参数
self.arch_params = nn.ParameterList([
nn.Parameter(torch.randn(i, num_ops))
for i in range(2, num_nodes + 2)
])
def forward(self, s0, s1):
states = [s0, s1]
for i in range(self.num_nodes):
# 使用 Sigmoid (每个操作独立)
weights = torch.sigmoid(self.arch_params[i])
# 加权求和
node_input = 0
for j in range(i + 2):
for k, op in enumerate(self.ops[i][j]):
node_input = node_input + weights[j, k] * op(states[j])
states.append(node_input)
return torch.cat(states[2:], dim=1)
"""
FairDARTS vs DARTS:
DARTS (Softmax):
操作之间竞争
容易导致 collapse
FairDARTS (Sigmoid):
每个操作独立
更公平的竞争
"""
6. 高效 NAS 方法
6.1 权重共享
权重共享 (Weight Sharing):
核心思想:
所有架构共享同一组权重
避免为每个架构单独训练
理论:
超网络 (Supernet): 包含所有可能的架构
子网络: 从超网络中采样
训练超网络
评估子网络
python
class Supernet(nn.Module):
"""
超网络 (Supernet)
理论:
包含所有可能的架构
训练时随机采样子网络
评估时选择最优子网络
"""
def __init__(self, num_ops=8):
super().__init__()
# 所有可能的操作
self.all_ops = nn.ModuleDict({
'sep_conv_3x3': SepConv(3, 1),
'sep_conv_5x5': SepConv(5, 1),
'dil_conv_3x3': DilConv(3, 1),
'avg_pool_3x3': nn.AvgPool2d(3, padding=1),
'max_pool_3x3': nn.MaxPool2d(3, padding=1),
'skip_connect': nn.Identity()
})
def forward(self, x, arch):
"""
arch: 架构描述 (每层选择的操作)
"""
for op_name in arch:
x = self.all_ops[op_name](x)
return x
def train_step(self, dataloader, num_samples=10):
"""训练步骤: 随机采样多个架构"""
total_loss = 0
for _ in range(num_samples):
# 随机采样架构
arch = self.random_architecture()
# 训练
for batch in dataloader:
x, y = batch
output = self.forward(x, arch)
loss = F.cross_entropy(output, y)
loss.backward()
total_loss += loss.item()
return total_loss / num_samples
"""
权重共享的优势:
1. 高效:
不需要为每个架构单独训练
大幅降低计算成本
2. 一次性:
训练一次超网络
可以评估所有子网络
劣势:
1. 评估不准:
共享权重可能不适合某些架构
2. 搜索空间受限:
需要设计合适的超网络
"""
6.2 一次性 NAS (One-shot NAS)
一次性 NAS:
核心思想:
训练一个超网络
一次性评估所有子网络
流程:
1. 训练超网络 (包含所有架构)
2. 评估所有子网络
3. 选择最优子网络
python
class OneShotNAS:
"""
一次性 NAS
理论:
训练一个超网络
一次性评估所有子网络
选择最优
"""
def __init__(self, supernet):
self.supernet = supernet
def search(self, val_loader):
"""搜索最优架构"""
# 训练超网络
self.train_supernet(val_loader)
# 评估所有子网络
best_arch = None
best_acc = 0
for arch in self.enumerate_architectures():
acc = self.evaluate_architecture(arch, val_loader)
if acc > best_acc:
best_acc = acc
best_arch = arch
return best_arch
"""
一次性 NAS 的优势:
1. 高效:
只训练一次
2. 简单:
实现简单
3. 灵活:
可以评估任意架构
"""
7. 硬件感知 NAS
7.1 硬件感知概述
硬件感知 NAS (Hardware-Aware NAS):
目标:
不仅优化准确率
还优化硬件效率 (延迟、能耗、内存)
多目标优化:
max Accuracy(arch)
s.t. Latency(arch) ≤ T
Memory(arch) ≤ M
Energy(arch) ≤ E
python
class HardwareAwareNAS:
"""
硬件感知 NAS
理论:
同时优化准确率和硬件效率
使用多目标优化
"""
def __init__(self, accuracy_predictor, latency_predictor):
self.accuracy_predictor = accuracy_predictor
self.latency_predictor = latency_predictor
def search(self, target_latency):
"""
搜索满足延迟约束的最优架构
"""
best_arch = None
best_acc = 0
for arch in self.enumerate_architectures():
# 预测准确率
acc = self.accuracy_predictor(arch)
# 预测延迟
latency = self.latency_predictor(arch)
# 检查约束
if latency <= target_latency and acc > best_acc:
best_acc = acc
best_arch = arch
return best_arch
"""
硬件感知的指标:
1. 延迟 (Latency):
推理时间
影响实时性
2. 内存 (Memory):
模型大小和激活内存
影响部署
3. 能耗 (Energy):
功耗
影响移动设备
4. FLOPs:
浮点运算次数
理论计算量
"""
7.2 ProxylessNAS
论文: "ProxylessNAS: Direct Neural Architecture Search on Target Task and Hardware"
(Cai et al., 2019)
核心创新:
直接在目标硬件上搜索
不需要代理任务
理论:
传统 NAS: 在小数据集上搜索 → 迁移
ProxylessNAS: 直接在目标数据集和硬件上搜索
8. NAS 在不同领域的应用
8.1 图像分类
NAS 在图像分类中的应用:
1. NASNet: 搜索最优的 Cell 结构
2. EfficientNet: 复合缩放
3. Once-for-All: 一次性搜索多个模型
8.2 目标检测
NAS 在目标检测中的应用:
1. NAS-FPN: 搜索最优的特征金字塔
2. DetNAS: 搜索检测器的骨干网络
3. SpineNet: 搜索多尺度特征融合
8.3 语义分割
NAS 在语义分割中的应用:
1. Auto-DeepLab: 搜索分割网络架构
2. DPC: 搜索密集预测的 Cell
8.4 NLP
NAS 在 NLP 中的应用:
1. Evolved Transformer: 搜索 Transformer 架构
2. AutoBERT: 搜索 BERT 架构
3. NAS-BERT: 高效的 BERT 搜索
9. 评估指标与基准
9.1 评估指标
┌─────────────────────────────────────────────────────────────────────┐
│ NAS 评估指标 │
├─────────────────┬───────────────────────────────────────────────────┤
│ 指标 │ 定义与说明 │
├─────────────────┼───────────────────────────────────────────────────┤
│ 准确率 │ 在测试集上的分类准确率 │
├─────────────────┼───────────────────────────────────────────────────┤
│ 搜索成本 │ 搜索所需的 GPU 小时数 │
├─────────────────┼───────────────────────────────────────────────────┤
│ FLOPs │ 模型的浮点运算次数 │
├─────────────────┼───────────────────────────────────────────────────┤
│ 参数量 │ 模型的参数数量 │
├─────────────────┼───────────────────────────────────────────────────┤
│ 延迟 │ 推理时间 │
├─────────────────┼───────────────────────────────────────────────────┤
│ 可迁移性 │ 在不同数据集上的表现 │
└─────────────────┴───────────────────────────────────────────────────┘
9.2 基准数据集
┌─────────────────────────────────────────────────────────────────────┐
│ NAS 基准数据集 │
├─────────────────┬───────────────────────────────────────────────────┤
│ 数据集 │ 说明 │
├─────────────────┼───────────────────────────────────────────────────┤
│ NAS-Bench-101 │ 搜索空间: 423K 架构 │
│ NAS-Bench-201 │ 搜索空间: 15K 架构 │
│ CIFAR-10 │ 常用的代理数据集 │
│ ImageNet │ 最终评估数据集 │
└─────────────────┴───────────────────────────────────────────────────┘
10. 前沿与展望
10.1 前沿方向
NAS 的前沿:
1. 大模型 NAS:
搜索 LLM 架构
高效的搜索方法
2. 多目标 NAS:
同时优化多个目标
准确率、延迟、能耗
3. 可解释 NAS:
理解为什么某些架构好
架构设计规律
4. 终身 NAS:
持续搜索新架构
适应新任务和硬件
5. NAS 理论:
搜索空间的理论分析
搜索算法的收敛性
10.2 NAS 的挑战
NAS 的挑战:
1. 计算成本:
搜索成本仍然很高
需要更高效的算法
2. 泛化性:
搜索到的架构可能过拟合
需要更好的评估方法
3. 搜索空间设计:
搜索空间的设计需要先验知识
如何设计更好的搜索空间
4. 可重复性:
NAS 实验难以重复
需要标准化的基准
附录
A. 发展时间线
2017 ──┬── NASNet (强化学习)
│
2018 ──┼── ENAS (权重共享)
│
2019 ──┼── DARTS (可微分搜索)
│
2020 ──┼── EfficientNet (复合缩放)
│
2021 ──┼── Once-for-All (一次性 NAS)
│
2022+ ──┴── 大模型 NAS
B. 核心公式速查
| 公式 | 含义 |
|---|---|
| a* = argmax f(a) | NAS 目标 |
| ∇θ J = ER · ∇log π | REINFORCE 梯度 |
| out = Σ αᵢ · oᵢ(x) | DARTS 松弛 |
| min_α L_val(w*(α), α) | 双层优化 |
C. 推荐资源
- Zoph, B., et al. (2018). NASNet
- Liu, H., et al. (2019). DARTS
- Tan, M., & Le, Q. (2019). EfficientNet
- Cai, H., et al. (2019). ProxylessNAS
文档结束
神经架构搜索深度解析(Neural Architecture Search, NAS)
版本:v1.0 | 最后更新:2026-06-02
目录
- [NAS 基础理论](#NAS 基础理论)
- 搜索空间设计
- 基于强化学习的搜索
- 基于进化的搜索
- DARTS:可微分架构搜索
- [高效 NAS 方法](#高效 NAS 方法)
- [硬件感知 NAS](#硬件感知 NAS)
- [NAS 在不同领域的应用](#NAS 在不同领域的应用)
- 评估指标与基准
- 前沿与展望
1. NAS 基础理论
1.1 什么是神经架构搜索
神经架构搜索 (Neural Architecture Search, NAS) 的定义:
自动设计最优的神经网络架构
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 传统方法: 人工设计架构 │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ 专家经验 → 设计架构 → 训练 → 评估 → 调整 → ... │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ NAS: 自动搜索架构 │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ 搜索空间 → 搜索策略 → 架构评估 → 最优架构 │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
NAS 的三个核心组件:
1. 搜索空间 (Search Space): 定义可能的架构
2. 搜索策略 (Search Strategy): 如何探索搜索空间
3. 评估策略 (Evaluation Strategy): 如何评估架构性能
1.2 NAS 的理论框架
NAS 的数学形式化:
给定:
搜索空间 A
评估函数 f(a) (架构 a 的性能)
计算预算 B
目标:
a* = argmax_{a∈A} f(a)
s.t. 计算成本 ≤ B
挑战:
1. 搜索空间巨大: |A| 可能达到 10^18
2. 评估昂贵: 每个架构需要训练
3. 离散优化: 架构是离散变量
1.3 NAS 的发展历史
NAS 发展时间线:
2017 ──┬── NASNet (强化学习)
│ 首次大规模 NAS
│
2018 ──┼── ENAS (权重共享)
│ 大幅降低计算成本
│
2019 ──┼── DARTS (可微分搜索)
│ 连续松弛,梯度优化
│
2020 ──┼── EfficientNet (复合缩放)
│ 系统化的模型缩放
│
2021 ──┼── AutoFormer (ViT NAS)
│ Transformer 架构搜索
│
2022+ ──┴── 大模型 NAS, 一次性 NAS
2. 搜索空间设计
2.1 搜索空间概述
搜索空间 (Search Space):
定义: 所有可能的架构的集合
设计原则:
1. 表达能力: 能表示好的架构
2. 大小适中: 不能太大 (无法搜索) 也不能太小 (错过好架构)
3. 先验知识: 包含已知的有效设计
搜索空间类型:
1. 宏观搜索空间: 整个网络架构
2. 微观搜索空间: 重复的单元 (Cell)
2.2 Cell-based 搜索空间
Cell-based 搜索空间:
核心思想:
搜索一个基本单元 (Cell)
然后堆叠多个 Cell 形成完整网络
Cell 结构:
- N 个节点 (Node)
- 每个节点有多个输入
- 每个输入有选择的操作
┌─────────────────────────────────────────────────────────────────┐
│ │
│ Cell 结构: │
│ │
│ 输入 ─┬─► [操作1] ─┬─► [操作2] ─┬─► 输出 │
│ │ │ │ │
│ └─► [操作3] ─┘ │ │
│ │ │
│ ┌─► [操作4] ─────────────┘ │
│ │ │
│ └─► [操作5] ───────────────► 输出 │
│ │
└─────────────────────────────────────────────────────────────────┘
python
import torch
import torch.nn as nn
class Cell(nn.Module):
"""
Cell-based 搜索空间中的基本单元
理论:
搜索一个基本 Cell 结构
堆叠多个 Cell 形成完整网络
优势:
- 搜索空间小
- 架构可复用
- 便于迁移
"""
def __init__(self, num_nodes=4, num_ops=8):
super().__init__()
self.num_nodes = num_nodes
# 可选操作
self.ops = nn.ModuleDict({
'none': Zero(),
'skip_connect': Identity(),
'sep_conv_3x1': SepConv(3, 1),
'sep_conv_5x1': SepConv(5, 1),
'sep_conv_3x2': SepConv(3, 2),
'sep_conv_5x2': SepConv(5, 2),
'dil_conv_3x2': DilConv(3, 2),
'avg_pool_3x1': Pool('avg', 3),
'max_pool_3x1': Pool('max', 3)
})
# 节点输入选择
self.node_inputs = nn.ModuleDict()
for i in range(2, num_nodes + 2):
self.node_inputs[f'node_{i}'] = nn.ModuleDict({
f'input_{j}': nn.ModuleDict({
op_name: op for op_name, op in self.ops.items()
})
for j in range(i)
})
def forward(self, s0, s1, weights):
"""
s0, s1: 前两个 Cell 的输出
weights: 架构参数 (每个操作的权重)
"""
states = [s0, s1]
for i in range(2, self.num_nodes + 2):
# 对每个输入加权求和
node_input = 0
for j in range(i):
for op_name, op in self.ops.items():
weight = weights[f'node_{i}'][f'input_{j}'][op_name]
node_input = node_input + weight * op(states[j])
states.append(node_input)
# 拼接所有中间节点
output = torch.cat(states[2:], dim=1)
return output
class SepConv(nn.Module):
"""深度可分离卷积"""
def __init__(self, kernel_size, stride):
super().__init__()
self.op = nn.Sequential(
nn.ReLU(),
nn.Conv2d(32, 32, kernel_size, stride=stride, padding=kernel_size//2, groups=32),
nn.Conv2d(32, 32, 1),
nn.BatchNorm2d(32),
nn.ReLU(),
nn.Conv2d(32, 32, kernel_size, stride=1, padding=kernel_size//2, groups=32),
nn.Conv2d(32, 32, 1),
nn.BatchNorm2d(32)
)
def forward(self, x):
return self.op(x)
"""
Cell-based 搜索空间的优势:
1. 搜索空间小:
只搜索一个 Cell
而非整个网络
2. 可迁移:
Cell 可以在不同数据集上复用
可以堆叠不同数量的 Cell
3. 先验知识:
Cell 结构基于已有的设计经验
2.3 宏观搜索空间
宏观搜索空间:
搜索整个网络架构
包括每一层的操作和连接
优势:
- 更大的搜索空间
- 可能发现更好的架构
劣势:
- 搜索空间巨大
- 计算成本高
- 难以迁移
python
class MacroSearchSpace(nn.Module):
"""
宏观搜索空间
搜索整个网络架构
"""
def __init__(self, num_layers=20, num_ops=8):
super().__init__()
self.num_layers = num_layers
# 每层可选的操作
self.ops = nn.ModuleList([
nn.ModuleDict({
'conv_3x3': nn.Conv2d(32, 32, 3, padding=1),
'conv_5x5': nn.Conv2d(32, 32, 5, padding=2),
'sep_conv_3x3': SepConv(3, 1),
'sep_conv_5x5': SepConv(5, 1),
'dil_conv_3x3': DilConv(3, 1),
'max_pool_3x3': nn.MaxPool2d(3, padding=1),
'avg_pool_3x3': nn.AvgPool2d(3, padding=1),
'skip': nn.Identity()
})
for _ in range(num_layers)
])
def forward(self, x, arch_params):
"""
x: [B, C, H, W]
arch_params: 每层的操作选择
"""
for i in range(self.num_layers):
op_name = arch_params[i]
x = self.ops[i][op_name](x)
return x
"""
宏观 vs 微观搜索空间:
宏观:
搜索整个网络
搜索空间大
难以迁移
微观 (Cell-based):
搜索基本单元
搜索空间小
便于迁移
实践中 Cell-based 更常用
"""
3. 基于强化学习的搜索
3.1 NASNet
论文: "Learning Transferable Architectures for Scalable Image Recognition"
(Zoph et al., 2018)
核心思想:
使用强化学习搜索最优的 Cell 结构
方法:
1. RNN 控制器生成架构描述
2. 训练子模型评估性能
3. 用性能作为奖励更新控制器
python
class NASNetController(nn.Module):
"""
NASNet 控制器
使用 RNN 生成架构描述
理论:
RNN 逐步生成架构的每个选择
使用 REINFORCE 算法训练
"""
def __init__(self, num_ops=8, num_nodes=4):
super().__init__()
self.num_ops = num_ops
self.num_nodes = num_nodes
# RNN 控制器
self.rnn = nn.LSTMCell(32, 32)
# 预测头
self.op_logits = nn.Linear(32, num_ops)
self.input_logits = nn.Linear(32, num_nodes)
# 嵌入
self.op_embedding = nn.Embedding(num_ops, 32)
self.input_embedding = nn.Embedding(num_nodes, 32)
def forward(self, batch_size=1):
"""
生成架构描述
"""
# 初始化
h = torch.zeros(batch_size, 32)
c = torch.zeros(batch_size, 32)
ops = []
inputs = []
for i in range(self.num_nodes):
# 预测操作
op_logit = self.op_logits(h)
op = torch.multinomial(torch.softmax(op_logit, dim=-1), 1)
ops.append(op)
# 预测输入
input_logit = self.input_logits(h)
input_idx = torch.multinomial(torch.softmax(input_logit, dim=-1), 1)
inputs.append(input_idx)
# 更新 RNN
op_emb = self.op_embedding(op)
input_emb = self.input_embedding(input_idx)
h, c = self.rnn(op_emb + input_emb, (h, c))
return ops, inputs
"""
NASNet 的训练:
REINFORCE 算法:
1. 控制器采样架构
2. 训练子模型
3. 用验证准确率作为奖励
4. 更新控制器
奖励: R = 准确率
梯度: ∇θ J(θ) = E[R · ∇θ log p(arch; θ)]
"""
3.2 REINFORCE 算法
python
class REINFORCE:
"""
REINFORCE 算法用于 NAS
理论:
策略梯度方法
用性能作为奖励更新控制器
"""
def __init__(self, controller, lr=0.001):
self.controller = controller
self.optimizer = torch.optim.Adam(controller.parameters(), lr=lr)
# 基线 (减少方差)
self.baseline = 0
def train_step(self, architectures, rewards):
"""
architectures: 采样的架构
rewards: 对应的性能
"""
# 计算策略梯度
log_probs = []
for arch in architectures:
log_prob = self.controller.log_prob(arch)
log_probs.append(log_prob)
log_probs = torch.stack(log_probs)
# 减去基线
advantages = rewards - self.baseline
# 策略梯度损失
loss = -(log_probs * advantages).mean()
# 更新
self.optimizer.zero_grad()
loss.backward()
self.optimizer.step()
# 更新基线
self.baseline = 0.9 * self.baseline + 0.1 * rewards.mean().item()
return loss.item()
"""
REINFORCE 的理论:
策略梯度定理:
∇θ J(θ) = E[∇θ log π(a|s) · R(a)]
在 NAS 中:
策略: π(arch; θ) = 控制器生成架构的概率
奖励: R(arch) = 架构的验证准确率
基线:
b = E[R] (移动平均)
减少方差: ∇θ J(θ) = E[∇θ log π(a|s) · (R(a) - b)]
"""
4. 基于进化的搜索
4.1 进化算法概述
进化算法 (Evolutionary Algorithm) 用于 NAS:
核心思想:
模拟自然选择
保留好的架构,淘汰差的架构
流程:
1. 初始化种群
2. 评估适应度 (性能)
3. 选择 (保留好的)
4. 变异 (生成新架构)
5. 重复步骤 2-4
python
class EvolutionaryNAS:
"""
基于进化的 NAS
理论:
模拟自然选择
保留好的架构,淘汰差的架构
"""
def __init__(self, population_size=50, mutation_rate=0.1):
self.population_size = population_size
self.mutation_rate = mutation_rate
self.population = []
def initialize(self, search_space):
"""初始化种群"""
for _ in range(self.population_size):
arch = search_space.random_architecture()
self.population.append(arch)
def evolve(self, search_space, num_generations=100):
"""进化搜索"""
for gen in range(num_generations):
# 评估适应度
fitness = []
for arch in self.population:
acc = self.evaluate(arch)
fitness.append(acc)
# 选择
selected = self.select(fitness)
# 变异
new_population = []
for arch in selected:
new_arch = self.mutate(arch, search_space)
new_population.append(new_arch)
self.population = new_population
# 返回最优架构
best_idx = np.argmax(fitness)
return self.population[best_idx]
def select(self, fitness):
"""
选择策略
理论:
保留适应度高的个体
轮盘赌选择或锦标赛选择
"""
# 锦标赛选择
selected = []
for _ in range(self.population_size):
# 随机选择 k 个个体
k = 3
candidates = np.random.choice(len(self.population), k, replace=False)
# 选择适应度最高的
best = candidates[np.argmax([fitness[i] for i in candidates])]
selected.append(self.population[best])
return selected
def mutate(self, arch, search_space):
"""
变异操作
理论:
随机修改架构的部分选择
探索搜索空间
"""
new_arch = arch.copy()
# 随机选择要变异的位置
num_mutations = int(len(arch) * self.mutation_rate)
mutation_positions = np.random.choice(len(arch), num_mutations, replace=False)
for pos in mutation_positions:
# 随机选择新操作
new_arch[pos] = search_space.random_operation()
return new_arch
"""
进化算法的优势:
1. 简单: 易于实现
2. 灵活: 可以处理各种约束
3. 并行: 可以并行评估多个架构
劣势:
1. 计算量大
2. 可能陷入局部最优
"""
4.2 AmoebaNet
论文: "Regularized Evolution for Image Classifier Architecture Search"
(Real et al., 2019)
核心创新:
正则化进化: 移除最老的个体 (而非最差的)
理论:
避免过拟合搜索历史
保持种群多样性
5. DARTS:可微分架构搜索
5.1 DARTS 核心思想
论文: "DARTS: Differentiable Architecture Search" (Liu et al., 2019)
核心创新:
将离散的架构选择松弛为连续优化
使用梯度下降搜索架构
理论:
原始问题: 离散选择 (argmax)
松弛后: 连续权重 (softmax)
可以用梯度下降优化
python
class DARTS(nn.Module):
"""
DARTS (Differentiable Architecture Search)
核心创新:
将离散选择松弛为连续优化
使用梯度下降搜索架构
理论:
每个操作有一个权重 α
输出 = Σ α_i · o_i(x)
训练结束后,选择权重最大的操作
"""
def __init__(self, num_nodes=4, num_ops=8):
super().__init__()
self.num_nodes = num_nodes
# 操作
self.ops = nn.ModuleList([
nn.ModuleList([
nn.ModuleDict({
'sep_conv_3x3': SepConv(3, 1),
'sep_conv_5x5': SepConv(5, 1),
'dil_conv_3x3': DilConv(3, 1),
'avg_pool_3x3': nn.AvgPool2d(3, padding=1),
'max_pool_3x3': nn.MaxPool2d(3, padding=1),
'skip_connect': nn.Identity(),
'none': Zero()
})
for _ in range(i) # 每个节点有 i 个输入
])
for i in range(2, num_nodes + 2)
])
# 架构参数 (可学习)
self.arch_params = nn.ParameterList()
for i in range(2, num_nodes + 2):
# 每个节点的每个输入的操作权重
param = nn.Parameter(torch.randn(i, num_ops) * 0.001)
self.arch_params.append(param)
def forward(self, s0, s1):
"""
s0, s1: 前两个 Cell 的输出
"""
states = [s0, s1]
for i in range(self.num_nodes):
# 获取当前节点的架构权重
weights = torch.softmax(self.arch_params[i], dim=-1)
# 对每个输入加权求和
node_input = 0
for j in range(i + 2):
for k, (op_name, op) in enumerate(self.ops[i][j].items()):
if op_name != 'none':
node_input = node_input + weights[j, k] * op(states[j])
states.append(node_input)
# 拼接所有中间节点
output = torch.cat(states[2:], dim=1)
return output
def get_architecture(self):
"""获取最终架构"""
arch = []
for i in range(self.num_nodes):
weights = torch.softmax(self.arch_params[i], dim=-1)
ops = weights.argmax(dim=-1)
arch.append(ops)
return arch
"""
DARTS 的训练:
双层优化:
外层: 优化架构参数 α
内层: 优化网络权重 w
min_α L_val(w*(α), α)
s.t. w*(α) = argmin_w L_train(w, α)
实际实现:
交替优化:
1. 固定 α,更新 w (训练集)
2. 固定 w,更新 α (验证集)
"""
5.2 DARTS 的问题与改进
DARTS 的问题:
1. 搜索不稳定:
架构参数可能震荡
搜索结果不一致
2. 性能差距:
搜索时的性能 ≠ 评估时的性能
权重共享导致评估不准
3. 搜索空间偏好:
倾向于选择 skip_connect
因为 skip_connect 训练更快
改进方法:
1. P-DARTS: 渐进式搜索
2. PC-DARTS: 部分通道连接
3. Fair DARTS: 公平竞争
4. DARTS-: 修正稳定性
python
class FairDARTS(nn.Module):
"""
Fair DARTS
改进:
使用 Sigmoid 替代 Softmax
每个操作独立竞争
理论:
Softmax 导致操作之间竞争
Sigmoid 允许多个操作共存
"""
def __init__(self, num_nodes=4, num_ops=8):
super().__init__()
# 架构参数
self.arch_params = nn.ParameterList([
nn.Parameter(torch.randn(i, num_ops))
for i in range(2, num_nodes + 2)
])
def forward(self, s0, s1):
states = [s0, s1]
for i in range(self.num_nodes):
# 使用 Sigmoid (每个操作独立)
weights = torch.sigmoid(self.arch_params[i])
# 加权求和
node_input = 0
for j in range(i + 2):
for k, op in enumerate(self.ops[i][j]):
node_input = node_input + weights[j, k] * op(states[j])
states.append(node_input)
return torch.cat(states[2:], dim=1)
"""
FairDARTS vs DARTS:
DARTS (Softmax):
操作之间竞争
容易导致 collapse
FairDARTS (Sigmoid):
每个操作独立
更公平的竞争
"""
6. 高效 NAS 方法
6.1 权重共享
权重共享 (Weight Sharing):
核心思想:
所有架构共享同一组权重
避免为每个架构单独训练
理论:
超网络 (Supernet): 包含所有可能的架构
子网络: 从超网络中采样
训练超网络
评估子网络
python
class Supernet(nn.Module):
"""
超网络 (Supernet)
理论:
包含所有可能的架构
训练时随机采样子网络
评估时选择最优子网络
"""
def __init__(self, num_ops=8):
super().__init__()
# 所有可能的操作
self.all_ops = nn.ModuleDict({
'sep_conv_3x3': SepConv(3, 1),
'sep_conv_5x5': SepConv(5, 1),
'dil_conv_3x3': DilConv(3, 1),
'avg_pool_3x3': nn.AvgPool2d(3, padding=1),
'max_pool_3x3': nn.MaxPool2d(3, padding=1),
'skip_connect': nn.Identity()
})
def forward(self, x, arch):
"""
arch: 架构描述 (每层选择的操作)
"""
for op_name in arch:
x = self.all_ops[op_name](x)
return x
def train_step(self, dataloader, num_samples=10):
"""训练步骤: 随机采样多个架构"""
total_loss = 0
for _ in range(num_samples):
# 随机采样架构
arch = self.random_architecture()
# 训练
for batch in dataloader:
x, y = batch
output = self.forward(x, arch)
loss = F.cross_entropy(output, y)
loss.backward()
total_loss += loss.item()
return total_loss / num_samples
"""
权重共享的优势:
1. 高效:
不需要为每个架构单独训练
大幅降低计算成本
2. 一次性:
训练一次超网络
可以评估所有子网络
劣势:
1. 评估不准:
共享权重可能不适合某些架构
2. 搜索空间受限:
需要设计合适的超网络
"""
6.2 一次性 NAS (One-shot NAS)
一次性 NAS:
核心思想:
训练一个超网络
一次性评估所有子网络
流程:
1. 训练超网络 (包含所有架构)
2. 评估所有子网络
3. 选择最优子网络
python
class OneShotNAS:
"""
一次性 NAS
理论:
训练一个超网络
一次性评估所有子网络
选择最优
"""
def __init__(self, supernet):
self.supernet = supernet
def search(self, val_loader):
"""搜索最优架构"""
# 训练超网络
self.train_supernet(val_loader)
# 评估所有子网络
best_arch = None
best_acc = 0
for arch in self.enumerate_architectures():
acc = self.evaluate_architecture(arch, val_loader)
if acc > best_acc:
best_acc = acc
best_arch = arch
return best_arch
"""
一次性 NAS 的优势:
1. 高效:
只训练一次
2. 简单:
实现简单
3. 灵活:
可以评估任意架构
"""
7. 硬件感知 NAS
7.1 硬件感知概述
硬件感知 NAS (Hardware-Aware NAS):
目标:
不仅优化准确率
还优化硬件效率 (延迟、能耗、内存)
多目标优化:
max Accuracy(arch)
s.t. Latency(arch) ≤ T
Memory(arch) ≤ M
Energy(arch) ≤ E
python
class HardwareAwareNAS:
"""
硬件感知 NAS
理论:
同时优化准确率和硬件效率
使用多目标优化
"""
def __init__(self, accuracy_predictor, latency_predictor):
self.accuracy_predictor = accuracy_predictor
self.latency_predictor = latency_predictor
def search(self, target_latency):
"""
搜索满足延迟约束的最优架构
"""
best_arch = None
best_acc = 0
for arch in self.enumerate_architectures():
# 预测准确率
acc = self.accuracy_predictor(arch)
# 预测延迟
latency = self.latency_predictor(arch)
# 检查约束
if latency <= target_latency and acc > best_acc:
best_acc = acc
best_arch = arch
return best_arch
"""
硬件感知的指标:
1. 延迟 (Latency):
推理时间
影响实时性
2. 内存 (Memory):
模型大小和激活内存
影响部署
3. 能耗 (Energy):
功耗
影响移动设备
4. FLOPs:
浮点运算次数
理论计算量
"""
7.2 ProxylessNAS
论文: "ProxylessNAS: Direct Neural Architecture Search on Target Task and Hardware"
(Cai et al., 2019)
核心创新:
直接在目标硬件上搜索
不需要代理任务
理论:
传统 NAS: 在小数据集上搜索 → 迁移
ProxylessNAS: 直接在目标数据集和硬件上搜索
8. NAS 在不同领域的应用
8.1 图像分类
NAS 在图像分类中的应用:
1. NASNet: 搜索最优的 Cell 结构
2. EfficientNet: 复合缩放
3. Once-for-All: 一次性搜索多个模型
8.2 目标检测
NAS 在目标检测中的应用:
1. NAS-FPN: 搜索最优的特征金字塔
2. DetNAS: 搜索检测器的骨干网络
3. SpineNet: 搜索多尺度特征融合
8.3 语义分割
NAS 在语义分割中的应用:
1. Auto-DeepLab: 搜索分割网络架构
2. DPC: 搜索密集预测的 Cell
8.4 NLP
NAS 在 NLP 中的应用:
1. Evolved Transformer: 搜索 Transformer 架构
2. AutoBERT: 搜索 BERT 架构
3. NAS-BERT: 高效的 BERT 搜索
9. 评估指标与基准
9.1 评估指标
┌─────────────────────────────────────────────────────────────────────┐
│ NAS 评估指标 │
├─────────────────┬───────────────────────────────────────────────────┤
│ 指标 │ 定义与说明 │
├─────────────────┼───────────────────────────────────────────────────┤
│ 准确率 │ 在测试集上的分类准确率 │
├─────────────────┼───────────────────────────────────────────────────┤
│ 搜索成本 │ 搜索所需的 GPU 小时数 │
├─────────────────┼───────────────────────────────────────────────────┤
│ FLOPs │ 模型的浮点运算次数 │
├─────────────────┼───────────────────────────────────────────────────┤
│ 参数量 │ 模型的参数数量 │
├─────────────────┼───────────────────────────────────────────────────┤
│ 延迟 │ 推理时间 │
├─────────────────┼───────────────────────────────────────────────────┤
│ 可迁移性 │ 在不同数据集上的表现 │
└─────────────────┴───────────────────────────────────────────────────┘
9.2 基准数据集
┌─────────────────────────────────────────────────────────────────────┐
│ NAS 基准数据集 │
├─────────────────┬───────────────────────────────────────────────────┤
│ 数据集 │ 说明 │
├─────────────────┼───────────────────────────────────────────────────┤
│ NAS-Bench-101 │ 搜索空间: 423K 架构 │
│ NAS-Bench-201 │ 搜索空间: 15K 架构 │
│ CIFAR-10 │ 常用的代理数据集 │
│ ImageNet │ 最终评估数据集 │
└─────────────────┴───────────────────────────────────────────────────┘
10. 前沿与展望
10.1 前沿方向
NAS 的前沿:
1. 大模型 NAS:
搜索 LLM 架构
高效的搜索方法
2. 多目标 NAS:
同时优化多个目标
准确率、延迟、能耗
3. 可解释 NAS:
理解为什么某些架构好
架构设计规律
4. 终身 NAS:
持续搜索新架构
适应新任务和硬件
5. NAS 理论:
搜索空间的理论分析
搜索算法的收敛性
10.2 NAS 的挑战
NAS 的挑战:
1. 计算成本:
搜索成本仍然很高
需要更高效的算法
2. 泛化性:
搜索到的架构可能过拟合
需要更好的评估方法
3. 搜索空间设计:
搜索空间的设计需要先验知识
如何设计更好的搜索空间
4. 可重复性:
NAS 实验难以重复
需要标准化的基准
附录
A. 发展时间线
2017 ──┬── NASNet (强化学习)
│
2018 ──┼── ENAS (权重共享)
│
2019 ──┼── DARTS (可微分搜索)
│
2020 ──┼── EfficientNet (复合缩放)
│
2021 ──┼── Once-for-All (一次性 NAS)
│
2022+ ──┴── 大模型 NAS
B. 核心公式速查
| 公式 | 含义 |
|---|---|
| a* = argmax f(a) | NAS 目标 |
| ∇θ J = ER · ∇log π | REINFORCE 梯度 |
| out = Σ αᵢ · oᵢ(x) | DARTS 松弛 |
| min_α L_val(w*(α), α) | 双层优化 |