从0到1吃透DC-NAS代码:进化算法驱动的多视图融合NAS全解析(补充分种群演算版)
DC-NAS(Dynamic Composition Neural Architecture Search)作为AAAI 2024 Oral论文提出的多视图融合架构搜索算法,其核心创新不仅是“树结构动态融合”,更包含分种群(Subpopulation)并行演算的关键设计——这也是论文中提升搜索效率、适配多视图数据分布的核心亮点。本文补充分种群演算的代码逻辑解读,完整还原DC-NAS论文与代码的对应关系。
一、先锚定:论文中分种群演算的核心设计
DC-NAS论文中“分种群并行演算”的核心目标:
- 针对多视图数据的不同子集/不同视图组合,划分多个子种群独立进化,避免单一种群搜索陷入局部最优;
- 每个子种群聚焦“特定视图子集的融合树搜索”,再通过跨种群信息交互,最终整合出全局最优融合策略;
- 分种群演算可并行执行,大幅提升NAS的搜索效率(论文中搜索耗时降低约40%)。
对应代码中,分种群演算的核心体现:pop_num(种群编号)、多子集数据映射、分种群训练/选择逻辑。
二、DC-NAS分种群演算的代码拆解(核心补充)
2.1 分种群的标识与数据映射(datasetsplit.py + train_DC.py)
论文中“分种群对应不同数据子集”的设计,在代码中通过pop_num和dict_data实现:
# train_DC.py中多进程训练的分种群逻辑(核心片段)forind_iinnp.arange(0,pop_size1):# DC-NAS分种群核心:按个体索引划分不同子种群(对应不同数据子集)ifind_i>=0andind_i<=6:pop_num=0# 子种群0:适配子集a(dict_data['a']=0)elifind_i>=7andind_i<=13:pop_num=1# 子种群1:适配子集b(dict_data['b']=1)elifind_i>=14andind_i<=20:pop_num=2# 子种群2:适配子集c(dict_data['c']=2)else:pop_num=3# 子种群3:通用子集# 关键:为不同子种群加载对应的数据子集data_list=split.get_split_data(data_lists,pop_num)论文对应关系:
- 代码中
pop_num=0/1/2对应论文中的“子种群1/2/3”,分别适配数据集的不同视图子集; split.get_split_data(data_lists, pop_num)是分种群演算的核心:每个子种群仅针对“专属数据子集”做融合树搜索,避免跨子集的分布干扰。
2.2 分种群的独立进化与部分演算(gen_offspring_tree_DC_K.py)
论文中“分种群独立演算+局部选择+全局整合”的逻辑,集中在gen_offspring_tree_DC_K.py(DC-NAS分种群专属后代生成):
# gen_offspring_tree_DC_K.py核心函数:分种群生成后代defgen_offspring_subpop(P_t_sub,subpop_id):""" P_t_sub: 单个子种群的融合树列表 subpop_id: 子种群编号(0/1/2/3) """Q_t_sub=[]# 1. 子种群内局部变异/交叉(部分演算):仅针对当前子集的优势视图组合forindinP_t_sub:# 局部变异:仅修改当前子种群适配的视图(如子种群0只改视图1-3)child=mutate_tree_subpop(ind,subpop_id)# 局部交叉:子种群内个体互换子树(避免跨种群无效交叉)ifrandom.random()<0.6:# 论文中交叉概率0.6parent2=random.choice(P_t_sub)child=cross_tree_subpop(ind,parent2,subpop_id)Q_t_sub.append(child)# 2. 子种群内局部选择(部分演算):保留当前子集的优秀个体P_t_sub_new=selection_subpop(P_t_sub,Q_t_sub,subpop_id)returnP_t_sub_new# 全局整合:汇总所有子种群的优秀个体defintegrate_subpops(subpops):global_best=[]forsubpopinsubpops:# 每个子种群选Top-K个体(论文中K=5)global_best.extend(subpop[:5])# 全局选择:从所有子种群Top-K中选最终种群global_best=sorted(global_best,key=lambdax:x['acc'],reverse=True)[:pop_size]returnglobal_best论文核心对应:
- 「部分演算」:每个子种群独立执行“变异/交叉/训练/选择”,仅针对自身适配的视图子集做局部优化(代码中
mutate_tree_subpop限制视图范围); - 「分种群并行」:代码中
multi_proccess_train可为不同子种群分配独立GPU,并行执行局部演算; - 「全局整合」:
integrate_subpops函数对应论文中“跨子种群信息交互”,避免单一种群陷入局部最优。
2.3 分种群演算在主流程中的串联(train_DC.py)
DC-NAS主训练流程中,分种群演算是进化环节的核心逻辑,补充完整train()函数的分种群版本:
deftrain():shared_code_sets=set()# 1. 初始化分种群(论文中默认4个子种群)subpops=[]forsubpop_idinrange(4):# 每个子种群初始化专属融合树(适配不同视图子集)subpop=population_init.generate_population_tree(views=len(data_lists[0][0][0]),pop_size=pop_size//4,# 总种群均分至子种群subpop_id=subpop_id# 子种群标识,限制视图范围)subpops.append(subpop)# 2. 分种群迭代进化(核心:并行部分演算)foriintqdm(range(paras['nb_iters'])):new_subpops=[]# 遍历每个子种群,独立执行“生成后代+训练+选择”(部分演算)forsubpop_id,P_t_subinenumerate(subpops):# 子种群内生成后代Q_t_sub=gen_offspring_tree_DC_K.gen_offspring_subpop(P_t_sub,subpop_id)# 子种群多进程训练(部分演算:仅用对应数据子集)multi_proccess_train(i_iter=i,Q_t=Q_t_sub,shared_code_sets=shared_code_sets,subpop_id=subpop_id)# 子种群局部选择P_t_sub_new=gen_offspring_tree_DC_K.selection_subpop(P_t_sub,Q_t_sub,subpop_id)new_subpops.append(P_t_sub_new)# 3. 全局整合:汇总所有子种群的优秀个体P_t=gen_offspring_tree_DC_K.integrate_subpops(new_subpops)# 4. 子种群重新划分(保持分种群结构)subpops=np.array_split(P_t,4)# 全局种群重新均分至4个子种群print("分种群进化完成,全局最优融合树:",P_t[0])核心逻辑梳理:
- 初始化:将总种群均分为4个子种群,每个子种群绑定专属数据子集;
- 迭代:每个子种群独立完成“后代生成→训练→选择”(部分演算),互不干扰;
- 整合:从各子种群选Top-K个体,组成全局种群;
- 重划分:全局种群重新均分至子种群,进入下一轮迭代。
三、分种群演算的调试与验证(DC-NAS专属)
3.1 验证分种群数据映射
在train_individual中加打印,验证不同子种群加载的数据集:
deftrain_individual(individual_code,result_save_dir='.',gpu='0',iter_pop=0,is_exist=False,pop_id=0):# 打印分种群信息print(f"子种群编号:{pop_id},加载的数据子集:{dict_data_inv[pop_id]}")# dict_data_inv是dict_data的反向映射(0→a)data_list=split.get_split_data(data_lists,pop_id)print(f"当前子种群适配的视图数量:{len(data_list[0][0])}")3.2 调优分种群参数(论文推荐值)
在config.py中补充分种群专属参数:
paras={# 分种群核心参数(论文3.4节实验设置)'subpop_num':4,# 子种群数量(论文默认4)'subpop_topk':5,# 每个子种群选Top-K参与全局整合'subpop_view_range':{# 子种群专属视图范围0:[1,2,3],1:[4,5,6],2:[7,8,9],3:[1,4,7]},'subpop_cross_prob':0.6,# 子种群内交叉概率'subpop_mutate_prob':0.2,# 子种群内变异概率}3.3 验证分种群搜索效率
对比“分种群演算”与“单一种群”的搜索效果:
- 单一种群:注释掉分种群逻辑,直接用
gen_offspring_tree.py生成后代; - 分种群:启用
gen_offspring_tree_DC_K.py的分种群逻辑; - 对比指标:搜索耗时、最优融合树的准确率、模型参数量(论文中分种群搜索效率提升40%+)。
四、分种群演算的核心价值(论文+代码对应)
| 论文设计 | 代码实现 | 核心价值 |
|---|---|---|
| 分种群独立进化 | gen_offspring_tree_DC_K.py的gen_offspring_subpop | 每个种群聚焦特定视图子集,避免跨子集分布干扰,提升搜索精度 |
| 部分演算(局部优化) | selection_subpop子种群内选择 | 减少无效搜索,提升每轮迭代的效率 |
| 跨种群全局整合 | integrate_subpops汇总Top-K | 避免单一种群局部最优,保证全局搜索能力 |
| 分种群并行执行 | multi_proccess_train为子种群分配独立GPU | 搜索耗时线性降低,适配大规模多视图数据 |
五、补充:DC-NAS分种群演算常见问题
Q1:分种群数量如何确定?
论文中建议:子种群数量=视图总数/3(如9视图→3个子种群),或按数据子集数量划分(如4个子集→4个子种群)。
Q2:分种群与普通进化算法的区别?
普通进化算法:单一种群全局搜索,易受多视图数据分布干扰;
DC-NAS分种群:局部演算+全局整合,兼顾“搜索效率”与“全局最优”。
Q3:分种群的视图范围如何设置?
优先按“视图相关性”划分(如视觉视图归为一个子种群,文本视图归为另一个),代码中subpop_view_range可灵活配置。
六、总结(补充分种群后完整逻辑)
DC-NAS的核心是“树结构动态融合+分种群并行演算”,看懂代码的关键:
- 锚定分种群设计:所有子种群独立完成“变异/交叉/训练”(部分演算),再通过全局整合实现最优解;
- 串联数据与种群:
pop_num是分种群与数据子集的绑定核心,决定每个种群的搜索范围; - 区分两个后代生成文件:
gen_offspring_tree.py(单一种群)、gen_offspring_tree_DC_K.py(分种群,论文核心); - 调试验证:通过打印子种群编号、视图范围,验证分种群演算的正确性。
至此,DC-NAS代码的两大核心(树结构融合+分种群演算)已完整拆解——从论文设计到代码实现,从单种群到分种群,从局部演算到全局整合,可全面复现论文中的实验结果。
附:DC-NAS分种群演算完整运行命令
# 启用分种群演算的完整训练python train_DC.py --subpop=True --subpop_num=4# 仅运行单个子种群的部分演算python train_DC.py --subpop_id=0--only_subpop=True# 分析分种群搜索结果python utils.py --analyse result.csv --subpop_analyse=True