我很好奇如何在一组5-6个参数下做到这一点。在找到最大值增加时评估结果。
由于我拥有的参数数量,组合数量似乎很大。但我的选择只是使用for循环吗?
我一直在构建此分配中的网格搜索策略(仅使用for循环),但还有更多变量。
http://nbviewer.ipython.org/github/cs109/content/blob/master/HW3.ipynb
答案 0 :(得分:4)
如果您有一个复杂的黑盒功能,并且需要以非线性方式调整输入,那么这听起来似乎是使用遗传算法(GA)的一个很好的应用。
什么是遗传算法?
通常,您可以将一个可能的参数组合编码为一系列位。这将是' DNA'你的解决方案。例如,您可以为每个值分配8位,将参数1分配为位0-7,将参数2分配为位8-15等。
在此之后,您将创建大量完全随机的解决方案(比如10,000),并使用您的函数对每个解决方案进行评估。在此之后,每个可能的解决方案都能获得与其同行的相对适应性。决定此功能的函数称为适应度函数,是我们尝试优化的目标函数。
根据这个相对频率,您可以根据此频率选择5,000对解决方案,以便更频繁地选择最佳解决方案,但即使是最差的也会有时通过。你'繁殖'#39;这些对中的每一对,通过在比特DNA串上挑选两个随机剪切点,并将该部分从一个交换到另一个,以在下一个群体中产生两个新的后代。
在此之后,您会一次又一次地重复整个过程,直到您感到无聊,或者表现最佳的解决方案足够好。
为什么会有效?
一般而言,最佳解决方案会更频繁地合并。组合它们的过程允许将不同的成功解决方案混合在一起,以创建比父母任何一方更好的东西。
GA是否是正确的工具?
使用GA的好处是,它会尝试优化你抛出的任何东西,而不是真正理解它。它也不关心你有多少独立参数。如果你有100个参数,那么嵌套循环真的是不可能的。重要的是你的健身功能评估的速度有多快。它越快,每秒可以计算的迭代次数就越多。
缺点是需要创建大量机器才能使GA首先工作,并且解决方案不能保证最佳,或者在任何特定的时间范围内到达。
然而,在实践中,他们往往在复杂的问题上做得非常好,因为你无法负担搜索整个可能性空间的问题。它是一个很好的工具,可以放在你的工具箱中,因为你几乎可以把它扔到任何东西。示例:
这是一个简洁,简洁的GA示例。这条线上方的代码是通用的,但是我们在下面解决了找到一条有很多腿的忠诚动物的问题,这不是一种臭味或侵略性。这被编码为4个字节。
import random
class DNA(object):
score = 0
def __init__(self, bits):
self.bits = bits
self.length = len(bits)
# https://en.wikipedia.org/wiki/Crossover_%28genetic_algorithm%29#Two-point_crossover
def two_point_crossover(self, other):
start = random.randint(0, self.length - 1)
end = random.randint(start, self.length - 1)
child_1 = DNA(self.bits[:start] + other.bits[start:end] + self.bits[end:])
child_2 = DNA(other.bits[:start] + self.bits[start:end] + other.bits[end:])
return child_1, child_2
# https://en.wikipedia.org/wiki/Mutation_%28genetic_algorithm%29
def mutate(self, probability):
self.bits = [bit if random.random() > probability else not bit for bit in self.bits]
# Allow us to 'breed' two strings by doing dna_1 * dna_2
def __mul__(self, other):
return self.two_point_crossover(other)
@staticmethod
def decode_byte(bits):
out = 0
for bit in reversed(bits):
out = out << 1
out += bit
return out
def as_bytes(self):
return [DNA.decode_byte(self.bits[start:start+8]) for start in xrange(0, self.length, 8)]
class Population(object):
cumulative_scores = None
total_score = 0
best_score = 0
best_member = None
def __init__(self, members):
self.members = members
self.length = len(members)
def rate(self, fitness_function):
self.cumulative_scores = []
self.total_scores = 0
for member in self.members:
score = fitness_function(member)
member.score = score
self.total_score += score
self.cumulative_scores.append((self.total_score, member))
if score > self.best_score:
self.best_score = score
self.best_member = member
# https://en.wikipedia.org/wiki/Fitness_proportionate_selection
def roulette_wheel_selection(self):
pick = random.uniform(0, self.total_score)
current = 0
pos = 0
while current < pick:
(score, member) = self.cumulative_scores[pos]
pos += 1
current = score
return member
def mutate(self, mutation_rate):
for member in self.members:
member.mutate(mutation_rate)
class GeneticAlgorithm(object):
def __init__(self, fitness_function, population, mutation_rate=0.01):
self.population = population
self.fitness_function = fitness_function
self.mutation_rate=0.01
def mutate(self):
self.population.mutate(self.mutation_rate)
def rate(self):
self.population.rate(self.fitness_function)
def breed(self):
new_members = []
while len(new_members) < self.population.length:
parent_1 = self.population.roulette_wheel_selection()
parent_2 = self.population.roulette_wheel_selection()
new_members += parent_1 * parent_2
self.population = Population(new_members[:self.population.length])
#----------------------------------------#
# My problem here
def my_fitness(dna):
angry, legs, smelly, loyalty = dna.as_bytes()
score = float((510 - angry - smelly) * loyalty * legs) / float(510*255*255)
return score
pop = Population([DNA([0] * 8 * 4) for _ in range(1000)])
pop.mutate(0.5) # Totally randomise our starting set
ga = GeneticAlgorithm(my_fitness, pop)
for _ in range(100):
ga.mutate()
ga.rate()
print "Best so far:", ga.population.best_score
ga.breed()
# Finished!
ga.rate()
angry, legs, smelly, loyalty = ga.population.best_member.as_bytes()
print "Best score: ", ga.population.best_score
print "Angry", angry, "Legs", legs, "Smelly", smelly, "Loyalty", loyalty