使用DEAP最小化多目标函数

3
我正在尝试使用DEAP库通过最小化自定义函数来执行多目标优化。虽然在最小化几个目标时(目标),我得到了不错的结果,但对于超过3或4个目标,它无法收敛。通常情况下,它会将第一个目标最小化为0,同时让其他目标反弹(不最小化)。
我使用sci-kit库构建了一个元模型(岭回归)来描述一些模拟数据,因此我的模型基于系数和截距(包含在我的代码中)。新的预测基于大约150个输入,这些输入是均匀变化的。
有一个年份选项,可以最小化3个目标,以及一个月份选项,可以最小化8个目标。
由于代码相当庞大,我已经将其作为gist包含在内。 请在HERE找到它。
问题: 有人知道未被最小化的剩余目标的原因吗?我尝试过调整选择、变异和交叉过程,但还没有成功。或者可能与模型本身有关吗?我也尝试了不同的适应度权重,但出于某种原因似乎没有什么区别。
年度目标结果: enter image description here 月度目标结果: enter image description here
2个回答

3

只是为了回答我的问题。

似乎在评估过程中,我没有返回正确的值。

将目标和预测之间的绝对差异改为差异的均方根误差就解决了问题:

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,)

enter image description here


1

你给了我解决一直以来困扰我的问题的方法。很好的方法,一个小技巧让我的程序也能工作了!

我相信一定有很多Deep用户试图使用超过两个权重,比如weights=(-1.0, -1.0, 1.0)。

我将发布一个简单的例子,其中有3个参数(2个参数最小化,1个参数最大化)。

  • 这个例子是关于“如何在最大重量和最大尺寸的条件下加载尽可能多的物品”。

  • 条件:

    1. 最小化重量总和。
    2. 最小化尺寸总和。
    3. 最大化价值总和。
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. 个体({1, 2, 19, 4}) 或
  2. 个体({1, 2, 19, 3})

因为它们的总分非常相似,所以您将获得其中一个结果。


与Chris的评估分数(使用RMSE)不同,在我的情况下,我将分数分为“MinFitess_score = weight + size”和“MaxFitenss_score = value”:),以便我可以使用“weights =(-1.0,1.0)”让GA工作。 - Dane Lee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接