使用 DEAP 最小化 multi-objective 函数
Minimizing multi-objective function using DEAP
我正在尝试通过使用 DEAP 库最小化自定义函数来执行多重 objective 优化。虽然我在对几个 objectives(目标)进行最小化时得到了不错的结果,但对于超过 3 或 4 个,它无法收敛。通常它会将第一个 objective 最小化为 0,同时让其他 objective 跳来跳去(不最小化)。
我使用 sci-kit 库构建了一个元模型(岭回归)来描述一些模拟数据,因此我的模型基于系数和截距(包含在我的代码中)。新预测基于约 150 个均匀变化的输入。
有一个最小化 3 个目标的年份选项,以及一个最小化 8 个目标的月份选项。
我已经将我的 代码 作为要点包括在内,因为它非常大。
请找HERE.
问题:
任何人都知道剩余的 objective 未被最小化的原因可能是什么?我尝试过选择、变异和交叉过程,但还没有成功。或者它可能与模型本身有关?我也尝试过不同的重量来健身,但不知为何似乎并没有什么不同。
年度目标的结果:
每月目标的结果:
只是回答我自己的问题。
看来我在评估期间没有返回正确类型的值。
更改为差异的 RMSE 而不是目标和预测之间的绝对差异达到了目的:
def EvaluateObjective(individual):
prediction = calculate(individual, for_sensitivity)
prediction = [int(i) for i in prediction]
# diff = []
# for y in range(len(targets)):
# output = math.sqrt((targets[y] - prediction[y]) ** 2)
# #output = abs(targets[y] - prediction[y])
# diff.append(output)
rmse = np.sqrt((sum((i - j)**2 for i, j in zip(prediction, targets)) / len(targets)))
return (rmse,)
您为我一直苦苦挣扎的问题提供了解决方案。好方法,一个小技巧让我的程序也能运行!
我很确定一定有很多 deap 用户像我一样尝试使用两个以上的权重,比如 weights=(-1.0, -1.0, 1.0)。
我将post 3 个参数的简单示例(2 个参数最小化,1 个参数最大化。)
例子是关于"How to load as many items as possible with conditions of maximum weight, maximum size"
条件:
- 最小化权重总和。
- 最小化大小和。
- 最大化值的总和。
from numpy import array
import numpy
import random
from deap import base, creator, tools, algorithms
### Multi-objective Optimization Problem ###
IND_INIT_SIZE = 5
MAX_WEIGHT = 2000 # kg
MAX_SIZE = 1500 # m**3
# Create the item dictionary:
r = array([[213, 508, 22], # 1st arg : weight / 2nd arg : size / 3rd arg : value
[594, 354, 50],
[275, 787, 43],
[652, 218, 46],
[728, 183, 43],
[856, 308, 33],
[727, 482, 45],
[762, 683, 26],
[707, 450, 19],
[909, 309, 45],
[979, 247, 42],
[259, 705, 42],
[260, 543, 14],
[899, 825, 17],
[446, 360, 35],
[491, 818, 47],
[647, 404, 17],
[604, 623, 32],
[900, 840, 45],
[374, 127, 33]] )
NBR_ITEMS = r.shape[0]
items = {}
# Create random items and store them in the items' dictionary.
for i in range(NBR_ITEMS):
items[i] = ( r[i][0] , r[i][1] , r[i][2] )
creator.create("Fitness", base.Fitness, weights=(-1.0, 1.0 )) # Note here <- I used only two weights! (at first, I tried weights=(-1.0 , -1.0, 1.0)) but it crashes. With deap, you cannot do such a thing.
creator.create("Individual", set, fitness=creator.Fitness)
toolbox = base.Toolbox()
# Attribute generator
toolbox.register("attr_item", random.randrange, NBR_ITEMS)
# Structure initializers
toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_item, n=IND_INIT_SIZE) #
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
def evaluation(individual):
weight = 0.0
size =0.0
value = 0.0
# Maximize or Minimize Conditions
for item in individual:
weight += items[item][0] # It must be minimized.
size += items[item][1] # It must be minimized.
value += items[item][2] # It must be maximized.
# Limit Conditions
if weight > MAX_WEIGHT or size > MAX_SIZE:
return 10000, 0
if value == 0:
value = 0.0000001
MinFitess_score = weight + size # NOTE : Minimize weight, size
MaxFitenss_score = value # NOTE : Maximize weight, size
return MinFitess_score , MaxFitenss_score,
def cxSet(ind1, ind2):
"""Apply a crossover operation on input sets. The first child is the
intersection of the two sets, the second child is the difference of the
two sets.
"""
temp = set(ind1) # Used in order to keep type
ind1 &= ind2 # Intersection (inplace)
ind2 ^= temp # Symmetric Difference (inplace)
return ind1, ind2
def mutSet(individual):
"""Mutation that pops or add an element."""
if random.random() < 0.5:
if len(individual) > 0: # We cannot pop from an empty set
individual.remove(random.choice(sorted(tuple(individual))))
else:
individual.add(random.randrange(NBR_ITEMS))
return individual, # NOTE comma(,) , if there's no comma, an error occurs.
toolbox.register("mate", cxSet)
toolbox.register("mutate", mutSet)
toolbox.register("select", tools.selNSGA2) # NSGA-2 applies to multi-objective problems such as knapsack problem
toolbox.register("evaluate", evaluation)
def main():
ngen = 300 # a number of generation < adjustable value >
pop = toolbox.population(n= 300)
hof = tools.ParetoFront() # a ParetoFront may be used to retrieve the best non dominated individuals of the evolution
stats = tools.Statistics(lambda ind: ind.fitness.values)
stats.register("avg", numpy.mean, axis=0)
stats.register("std", numpy.std, axis=0)
stats.register("min", numpy.min, axis=0)
stats.register("max", numpy.max, axis=0)
algorithms.eaSimple(pop, toolbox, 0.7, 0.2, ngen=ngen, stats=stats, halloffame=hof, verbose=True)
return hof, pop
if __name__ == "__main__":
hof, pop = main()
print(hof) # non-dominated individuals' list # the fittest value is placed on the most right side.
理想结果:
- 个人({1, 2, 19, 4}) 或
- 个人({1, 2, 19, 3})
因为他们的总分很相近。您将获得其中一个结果。
我正在尝试通过使用 DEAP 库最小化自定义函数来执行多重 objective 优化。虽然我在对几个 objectives(目标)进行最小化时得到了不错的结果,但对于超过 3 或 4 个,它无法收敛。通常它会将第一个 objective 最小化为 0,同时让其他 objective 跳来跳去(不最小化)。
我使用 sci-kit 库构建了一个元模型(岭回归)来描述一些模拟数据,因此我的模型基于系数和截距(包含在我的代码中)。新预测基于约 150 个均匀变化的输入。
有一个最小化 3 个目标的年份选项,以及一个最小化 8 个目标的月份选项。
我已经将我的 代码 作为要点包括在内,因为它非常大。 请找HERE.
问题: 任何人都知道剩余的 objective 未被最小化的原因可能是什么?我尝试过选择、变异和交叉过程,但还没有成功。或者它可能与模型本身有关?我也尝试过不同的重量来健身,但不知为何似乎并没有什么不同。
年度目标的结果:
每月目标的结果:
只是回答我自己的问题。
看来我在评估期间没有返回正确类型的值。
更改为差异的 RMSE 而不是目标和预测之间的绝对差异达到了目的:
def EvaluateObjective(individual):
prediction = calculate(individual, for_sensitivity)
prediction = [int(i) for i in prediction]
# diff = []
# for y in range(len(targets)):
# output = math.sqrt((targets[y] - prediction[y]) ** 2)
# #output = abs(targets[y] - prediction[y])
# diff.append(output)
rmse = np.sqrt((sum((i - j)**2 for i, j in zip(prediction, targets)) / len(targets)))
return (rmse,)
您为我一直苦苦挣扎的问题提供了解决方案。好方法,一个小技巧让我的程序也能运行!
我很确定一定有很多 deap 用户像我一样尝试使用两个以上的权重,比如 weights=(-1.0, -1.0, 1.0)。
我将post 3 个参数的简单示例(2 个参数最小化,1 个参数最大化。)
例子是关于"How to load as many items as possible with conditions of maximum weight, maximum size"
条件:
- 最小化权重总和。
- 最小化大小和。
- 最大化值的总和。
from numpy import array
import numpy
import random
from deap import base, creator, tools, algorithms
### Multi-objective Optimization Problem ###
IND_INIT_SIZE = 5
MAX_WEIGHT = 2000 # kg
MAX_SIZE = 1500 # m**3
# Create the item dictionary:
r = array([[213, 508, 22], # 1st arg : weight / 2nd arg : size / 3rd arg : value
[594, 354, 50],
[275, 787, 43],
[652, 218, 46],
[728, 183, 43],
[856, 308, 33],
[727, 482, 45],
[762, 683, 26],
[707, 450, 19],
[909, 309, 45],
[979, 247, 42],
[259, 705, 42],
[260, 543, 14],
[899, 825, 17],
[446, 360, 35],
[491, 818, 47],
[647, 404, 17],
[604, 623, 32],
[900, 840, 45],
[374, 127, 33]] )
NBR_ITEMS = r.shape[0]
items = {}
# Create random items and store them in the items' dictionary.
for i in range(NBR_ITEMS):
items[i] = ( r[i][0] , r[i][1] , r[i][2] )
creator.create("Fitness", base.Fitness, weights=(-1.0, 1.0 )) # Note here <- I used only two weights! (at first, I tried weights=(-1.0 , -1.0, 1.0)) but it crashes. With deap, you cannot do such a thing.
creator.create("Individual", set, fitness=creator.Fitness)
toolbox = base.Toolbox()
# Attribute generator
toolbox.register("attr_item", random.randrange, NBR_ITEMS)
# Structure initializers
toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_item, n=IND_INIT_SIZE) #
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
def evaluation(individual):
weight = 0.0
size =0.0
value = 0.0
# Maximize or Minimize Conditions
for item in individual:
weight += items[item][0] # It must be minimized.
size += items[item][1] # It must be minimized.
value += items[item][2] # It must be maximized.
# Limit Conditions
if weight > MAX_WEIGHT or size > MAX_SIZE:
return 10000, 0
if value == 0:
value = 0.0000001
MinFitess_score = weight + size # NOTE : Minimize weight, size
MaxFitenss_score = value # NOTE : Maximize weight, size
return MinFitess_score , MaxFitenss_score,
def cxSet(ind1, ind2):
"""Apply a crossover operation on input sets. The first child is the
intersection of the two sets, the second child is the difference of the
two sets.
"""
temp = set(ind1) # Used in order to keep type
ind1 &= ind2 # Intersection (inplace)
ind2 ^= temp # Symmetric Difference (inplace)
return ind1, ind2
def mutSet(individual):
"""Mutation that pops or add an element."""
if random.random() < 0.5:
if len(individual) > 0: # We cannot pop from an empty set
individual.remove(random.choice(sorted(tuple(individual))))
else:
individual.add(random.randrange(NBR_ITEMS))
return individual, # NOTE comma(,) , if there's no comma, an error occurs.
toolbox.register("mate", cxSet)
toolbox.register("mutate", mutSet)
toolbox.register("select", tools.selNSGA2) # NSGA-2 applies to multi-objective problems such as knapsack problem
toolbox.register("evaluate", evaluation)
def main():
ngen = 300 # a number of generation < adjustable value >
pop = toolbox.population(n= 300)
hof = tools.ParetoFront() # a ParetoFront may be used to retrieve the best non dominated individuals of the evolution
stats = tools.Statistics(lambda ind: ind.fitness.values)
stats.register("avg", numpy.mean, axis=0)
stats.register("std", numpy.std, axis=0)
stats.register("min", numpy.min, axis=0)
stats.register("max", numpy.max, axis=0)
algorithms.eaSimple(pop, toolbox, 0.7, 0.2, ngen=ngen, stats=stats, halloffame=hof, verbose=True)
return hof, pop
if __name__ == "__main__":
hof, pop = main()
print(hof) # non-dominated individuals' list # the fittest value is placed on the most right side.
理想结果:
- 个人({1, 2, 19, 4}) 或
- 个人({1, 2, 19, 3})
因为他们的总分很相近。您将获得其中一个结果。