给定一组5-6个参数,我很好奇该怎么做。在找到最大的价值增长时评估结果。
由于我拥有的参数数量,组合的数量似乎巨大。但是我的选择仅仅是使用for循环吗?
在此分配中,我一直在构建网格搜索策略(仅使用for循环),但还有更多变量。
http://nbviewer.ipython.org/github/cs109/content/blob/master/HW3.ipynb
如果您具有复杂的黑匣子功能,并且需要以非线性方式调整输入,那么这听起来像是使用遗传算法(GA)的好应用程序。
什么是遗传算法?
通常,您会将参数的一种可能组合编码为一系列位。这将是您解决方案的“ DNA”。例如,您可以为每个值分配8位,参数1为位0-7,参数2为位8-15,依此类推。
之后,您将创建大量完全随机的解决方案(例如10,000个),并根据您的功能进行评估。在此之后,每种可能的解决方案都将获得与之相对的适应性。决定这一点的函数称为适应度函数,它是我们试图优化的目标函数。
根据此相对频率,您可以根据该频率选择5,000对解决方案,这样,最好的选择就会被更频繁地选择,但是即使最差的选择有时也可以通过。您可以通过在位DNA串上选择两个随机的剪接点,然后将这一部分从一个交换到另一个,以在下一个种群中产生两个新的后代,来“繁殖”每对。
此后,您一次又一次地重复整个过程,直到感到无聊或表现最佳的解决方案就足够了。
为什么行得通?
通常,最佳解决方案会更频繁地组合在一起。合并它们的过程允许将不同的成功解决方案混合在一起,以创建可能比任何一个父级更好的解决方案。
通用航空是正确的工具吗?
使用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
Run Code Online (Sandbox Code Playgroud)