使用PyGAD生成HPC集群作业唯一约束点遇问题求助
问题描述
在HPC项目中,我想用PyGAD生成唯一的点集提交给集群作业——因为集群时间成本高,必须避免重复作业;同时作业涉及物理模拟,数值不能出现负数(比如粒子数、长度),得做范围约束。
根据PyGAD文档,allow_duplicate_genes和gene_space参数应该能满足需求,但运行以下代码时,不仅出现大量重复点,还偶尔生成超出gene_space范围的点:
import pygad import numpy import itertools def mock_function(solution, sol_idx): return -1 * (solution[0] ** 2 + solution[1] ** 2) range = [.1, 1.] param_values = numpy.linspace(range[0], range[1], 10).tolist() initial_population = list(itertools.product(param_values, param_values)) ga = pygad.GA(num_generations=100, num_parents_mating=10, gene_type=float, gene_space={'low': range[0], 'high': range[1]}, fitness_func=mock_function, initial_population=initial_population, mutation_probability=0.2, allow_duplicate_genes=False, ) ga.run() new_points = ga.population unique_points = set([tuple(x) for x in new_points]) print(len(initial_population), len(new_points), len(unique_points)) print(f"Best solution is {ga.best_solution()[0]}.") for point in new_points: for x in point: if not range[0] <= x <= range[1]: print(f"Point {point} is outside gene_space.")
注:GitHub仓库已有开放Issue称最新版本修复了唯一性问题,但示例中问题仍存在,且有点超出范围。请问我忽略了什么?
问题分析与解决
1. 对allow_duplicate_genes的核心误解
这个参数控制的是单个个体内部的基因是否允许重复(比如一个二维解里两个维度的值能不能相同),完全不是你需要的“种群内不同个体不能重复”。这是导致重复点出现的根本原因——你用错了参数。
2. gene_space约束失效的解决
默认情况下,PyGAD的突变、交叉操作可能会突破gene_space的范围,因为部分遗传操作不会自动截断数值。只需添加keep_genes_within=True参数,就能强制所有操作后的基因都被限制在指定范围内。
3. 实现种群个体唯一性的方案
PyGAD原生没有直接控制种群个体唯一的参数,需要手动处理:
- 自定义逻辑,在每一代进化后检查并替换重复个体
- 注意浮点精度问题:直接用
tuple(sol)判断重复可能因浮点误差误判,建议先取固定小数位再去重
修改后的示例代码
import pygad import numpy import itertools def mock_function(solution, sol_idx): return -1 * (solution[0] ** 2 + solution[1] ** 2) # 重命名变量避免和内置函数冲突 range_min = .1 range_max = 1. param_values = numpy.linspace(range_min, range_max, 10).tolist() initial_population = list(itertools.product(param_values, param_values)) # 确保种群内个体唯一的函数 def ensure_unique_population(population, gene_space): unique_pop = [] seen = set() for sol in population: # 浮点取6位小数,避免精度误差导致的伪重复 sol_tuple = tuple(numpy.round(sol, 6)) if sol_tuple not in seen: seen.add(sol_tuple) unique_pop.append(sol) else: # 生成符合约束的新随机个体替换重复项 new_sol = numpy.random.uniform(gene_space['low'], gene_space['high'], size=len(sol)) unique_pop.append(new_sol) return numpy.array(unique_pop) ga = pygad.GA(num_generations=100, num_parents_mating=10, gene_type=float, gene_space={'low': range_min, 'high': range_max}, fitness_func=mock_function, initial_population=initial_population, mutation_probability=0.2, allow_duplicate_genes=False, # 按需保留,控制单个个体内基因是否重复 keep_genes_within=True, # 强制基因不越界 # 每一代进化后执行唯一性检查 on_generation=lambda ga: setattr(ga, 'population', ensure_unique_population(ga.population, ga.gene_space)) ) ga.run() new_points = ga.population unique_points = set([tuple(numpy.round(x, 6)) for x in new_points]) print(len(initial_population), len(new_points), len(unique_points)) print(f"Best solution is {ga.best_solution()[0]}.") for point in new_points: for x in point: if not range_min <= x <= range_max: print(f"Point {point} is outside gene_space.")
关键修改说明
- 重命名
range变量,避免和Python内置函数冲突 - 添加
keep_genes_within=True,彻底解决基因越界问题 - 新增
ensure_unique_population函数,处理种群个体唯一性并解决浮点精度问题 - 使用
on_generation回调,每一代进化后自动执行唯一性检查和替换
内容的提问来源于stack exchange,提问作者dmark04
相关产品推荐
相关产品推荐

