感谢大家的帮助和这里的 cmets,我能够建立一个答案。 DEAP 文档非常有用,但无论如何我还是想分享我的答案以及一些希望对其他人有所帮助的 cmets。
我使用了此处 https://github.com/DEAP/deap/blob/b46dde2b74a3876142fdcc40fdf7b5caaa5ea1f4/examples/ga/onemax.py 的 OneMax 示例以及此处的演练:https://deap.readthedocs.org/en/latest/examples/ga_onemax.html。我发现这两页也非常宝贵,运算符:https://deap.readthedocs.org/en/latest/tutorials/basic/part2.html#next-step 和创建类型:https://deap.readthedocs.org/en/latest/tutorials/basic/part1.html#creating-types
所以我的解决方案就在这里(抱歉格式化,这是我第一次发布长代码并添加 cmets)。基本上,您真正需要做的就是使适应度评估函数(此处为eval_Inidividual)成为您要优化的函数 F。您可以通过在初始化(此处为 random_initialization)和突变(此处为 mutate_inputs)时限制它们的可能值来限制 F 的 N 个变量/输入中的每一个的范围(和分布)。
最后一点:我使用多处理库编写了多核代码(只需两行代码并更改您使用的映射函数!)。在此处阅读更多信息:https://deap.readthedocs.org/en/default/tutorials/distribution.html
代码(阅读我的 cmets 以获得更多解释):
import random
from deap import base
from deap import creator
from deap import tools
start_clock = time.clock()
NGEN = 100 # number of generations to run evolution on
pop_size = 10000 # number of individuals in the population. this is the number of points in the N-dimensional space you start within
CXPB = 0.5 # probability of cross-over (reproduction) to replace individuals in population by their offspring
MUTPB = 0.2 # probability of mutation
mutation_inside = 0.05 # prob mutation within individual
num_cores = 6
N = 8 # the number of variables you are trying to optimize over. you can limit the range (and distribtuion) of each of them by limiting their possible values at initialization and mutation.
def eval_Inidividual(individual):
# this code runs on your individual and outputs the 'fitness' of the individual
def mutate_inputs(individual, indpb):
# this is my own written mutation function that takes an individual and changes each element in the tuple with probability indpb
# there are many great built in such mutation functions
def random_initialization():
# this creates each individual with an N-tuple where N is the number of variables you are optimizing over
creator.create("FitnessMax", base.Fitness, weights=(-1.0,)) # negative if trying to minimize mean, positive if trying to maximize sharpe. can be a tuple if you are trying to maximize/minimize over several outputs at the same time e.g. maximize mean, minimize std for fitness function that returns (mean, std) would need you to use (1.0, -1.0)
creator.create("Individual", list, fitness=creator.FitnessMax)
toolbox = base.Toolbox()
# Attribute generator
toolbox.register("attr_floatzzz", random_initialization) # i call it attr_floatzzz to make sure you know you can call it whatever you want.
# Structure initializers
toolbox.register("individual", tools.initRepeat, creator.Individual,
toolbox.attr_floatzzz, N) # N is the number of variables in your individual e.g [.5,.5,.5,.5,.1,100] that get
# fed to your fitness function evalOneMax
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
import multiprocessing as mp
pool = mp.Pool(processes=num_cores)
toolbox.register("map", pool.map) # these 2 lines allow you to run the computation multicore. You will need to change the map functions everywhere to toolbox.map to tell the algorithm to use a multicored map
# Operator registering
toolbox.register("evaluate", eval_Inidividual)
toolbox.register("mate", tools.cxTwoPoint)
toolbox.register("mutate", mutate_inputs, indpb = mutation_inside)
toolbox.register("select", tools.selTournament, tournsize=3)
def main():
# random.seed(64)
pop = toolbox.population(n=pop_size) # these are the different individuals in this population,
# each is a random combination of the N variables
print("Start of evolution")
# Evaluate the entire population
fitnesses = list(toolbox.map(toolbox.evaluate, pop))
for ind, fit in zip(pop, fitnesses):
ind.fitness.values = fit #this runs the fitness (min mean on each of the individuals)
# print(" Evaluated %i individuals" % len(pop))
# Begin the evolution
for g in range(NGEN):
print("-- Generation %i --" % g)
f.write("-- Generation %i --\n" % g)
# f.write("-- Generation %i --\n" % g)
# g = open('GA_generation.txt','w')
# g.write("-- Generation %i --" % g)
# g.close()
# Select the next generation individuals
offspring = toolbox.select(pop, len(pop)) # this selects the best individuals in the population
# Clone the selected individuals
offspring = list(toolbox.map(toolbox.clone, offspring)) #ensures we don’t own a reference to the individuals but an completely independent instance.
# Apply crossover and mutation on the offspring
for child1, child2 in zip(offspring[::2], offspring[1::2]): #this takes all the odd-indexed and even-indexed pairs child1, child2 and mates them
if random.random() < CXPB:
toolbox.mate(child1, child2)
del child1.fitness.values
del child2.fitness.values
for mutant in offspring:
if random.random() < MUTPB:
toolbox.mutate(mutant)
del mutant.fitness.values
# Evaluate the individuals with an invalid fitness
invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
fitnesses = toolbox.map(toolbox.evaluate, invalid_ind)
for ind, fit in zip(invalid_ind, fitnesses):
ind.fitness.values = fit
# print(" Evaluated %i individuals" % len(invalid_ind))
# The population is entirely replaced by the offspring
pop[:] = offspring
# Gather all the fitnesses in one list and print the stats
fits = [ind.fitness.values[0] for ind in pop]
# length = len(pop)
# mean = sum(fits) / length
# sum2 = sum(x*x for x in fits)
# std = abs(sum2 / length - mean**2)**0.5
print(" Min %s" % min(fits))
# print(" Max %s" % max(fits))
# print(" Avg %s" % mean)
# print(" Std %s" % std)
print("-- End of (successful) evolution --")
best_ind = tools.selBest(pop, 1)[0]
print("Best individual is %s with mean %s" % (best_ind,
best_ind.fitness.values[0])
done = time.clock() - start_clock # the clock doens't work on the multicored version. I have no idea how to make it work :)
print "time taken: ", done, 'seconds'
if __name__ == "__main__":
main()
p.s.:时钟在多核版本上不起作用。我不知道如何使它工作:)