简体   繁体   English

使用DEAP最小化多目标函数

[英]Minimizing multi-objective function using DEAP

I'm trying to perform multi-objective optimisation by minimizing a custom function using the DEAP library. 我正在尝试通过使用DEAP库最小化自定义函数来执行多目标优化。 Although I'm getting decent results when minimizing for several objectives (targets), for more than 3 or 4 it fails to converge. 尽管在最小化多个目标(目标)时我得到了不错的结果,但是对于3个或4个以上的目标,它无法收敛。 Typically it will minimize the first objective to 0, whilst leaving the other objectives bouncing around (not minimizing). 通常,它将最小化第一个目标为0,同时使其他目标反弹(而不是最小化)。

I built a meta-model (ridge regression) to describe some simulation data using sci-kit library, so my model is based on coefficients and intercepts (included in my code). 我使用sci-kit库构建了一个元模型(岭回归)来描述一些仿真数据,因此我的模型基于系数和截距(包含在我的代码中)。 New predictions are based on ~150 inputs that are being varied uniformly. 新的预测基于约150个输入,这些输入在不断变化。

There is a year option that minimizes for 3 targets, and a month option that minimizes for 8 targets. 有一个年份选项可将3个目标最小化,一个月份选项可将8个目标最小化。

I've included my code as a gist as it is quite large. 我已经将我的代码作为要点包括在内,因为它很大。 Please find it HERE . 请在这里找到它。

Question: Anyone has any idea what the reason might be for the remaining objectives not being minimized? 问题:有人不知道剩余目标没有被最小化的原因是什么? I've tried playing around with the selection, mutation and crossover processes, but no luck yet. 我尝试过选择,变异和交叉过程,但还没有走运。 Or could it possibly be related to the model itself? 还是可能与模型本身有关? I've also tried different weights for the fitness, but for some reason it doesn't seem to make a difference. 我也尝试过不同的重量来适应身体状况,但由于某种原因,它似乎并没有改变。

Results for the year targets: 年度目标结果: 在此处输入图片说明

Results for the monthly targets: 每月目标的结果: 在此处输入图片说明

Just to answer my own question. 只是回答我自己的问题。

It seems that I wasn't returning the right kind of values during evaluation. 似乎在评估过程中我没有返回正确的值。

Changing to the RMSE of the differences instead of absolute differences between objectives and predictions did the trick: 将差异改为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,)

在此处输入图片说明

You gave me the solution to the exact same issue I've been struggling with. 您为我提供了解决我一直在努力解决的相同问题的解决方案。 Nice method, a little trick made my program work too! 不错的方法,一点技巧也使我的程序正常工作!

I'm pretty sure there must be lots of deap users who tried to use more than two weights like weights=(-1.0, -1.0, 1.0) as I did. 我很确定肯定有很多聋子用户尝试像我一样使用两个以上的权重,例如weights =(-1.0,-1.0,1.0)。

I will post the simple example of 3 parameters (2 parameters minimized, 1 parameter maximized.) 我将发布3个参数的简单示例(将2个参数最小化,将1个参数最大化。)

  • The example is about "How to load as many items as possible with conditions of maximum weight, maximum size" 该示例是关于“如何在最大重量,最大尺寸的条件下装载尽可能多的物品”

  • Conditions : 条件 :

    1. Minimize weight sum. 最小化重量总和。
    2. Minimize size sum. 最小化大小总和。
    3. Maximize a sum of values. 最大化价值总和。
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.

The ideal result: 理想的结果:

  1. Individual({1, 2, 19, 4}) or 个人({1、2、19、4})或
  2. Individual({1, 2, 19, 3}) 个人({1、2、19、3})

as their total scores are quite similar. 因为他们的总分非常相似。 You will get one of the results. 您将得到结果之一。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM