我知道用Python来编写这种类型的软件并不是最佳选择。我的理由是希望在Raspberry Pi 3的决策中使用这种算法(我还不确定这会如何进行),而且我将使用的库和API(Adafruit电机HATs、Google服务、OpenCV、各种传感器等)在Python中导入都很友好,更不用说我对于rPi来说,在这个环境中更加舒适。虽然我已经诅咒过面向对象的编程语言,如Java或C++对我来说更有意义,但我宁愿处理Python的低效性,并专注于rPi的整体集成大局。
我不会在这里解释代码,因为脚本中的注释部分已经很好地记录了这些。我的问题如上所述;这可以被认为是基本的遗传算法吗?如果不是,它必须具备什么才能成为基本的AI或遗传代码?我对于这种问题解决方法是否走在正确的道路上?我知道通常会有加权变量和函数来促进“适者生存”,但我想这些可以在需要时加入。
我已经阅读了很多关于这个话题的论坛和文章。我不想复制我几乎不理解的别人的代码,并将其作为我更大项目的基础;我想确切地了解它的工作原理,这样我才不会在途中因为某件事情不工作而感到困惑。所以,我只是试图理解它的基本工作原理,并按照我的理解来编写。请记住我想继续使用Python。对于这个,我知道rPi有多个C++、Java等环境,但如前所述,我使用的硬件组件大多只有Python API来实现。如果我错了,请在算法层面解释,而不是只用一段代码(再次强调,我真的想理解这个过程)。另外,除非与我的问题相关,否则请不要挑剔代码惯例,每个人都有自己的风格,这只是一个草图。现在就展示给大家,感谢阅读!
# Created by @X3r0, 7/3/2016# Basic genetic algorithm utilizing a two dimensional array system.# the 'DNA' is the larger array, and the 'gene' is a smaller array as an element# of the DNA. There exists no weighted algorithms, or statistical tracking to# make the program more efficient yet; it is straightforwardly random and solves# its problem randomly. At this stage, only the base element is iterated over.# Basic Idea:# 1) User inputs constraints onto array# 2) Gene population is created at random given user constraints# 3) DNA is created with randomized genes ( will never randomize after )# a) Target DNA is created with loop control variable as data (basically just for some target structure)# 4) CheckDNA() starts with base gene from DNA, and will recurse until gene matches the target gene# a) Randomly select two genes from DNA# b) Create a candidate gene by splicing both parent genes together# c) Check candidate gene against the target gene# d) If there exists a match in gene elements, a child gene is created and inserted into DNA# e) If the child gene in DNA is not equal to target gene, recurse until it isimport randomDNAsize = 32geneSize = 5geneDiversity = 9geneSplit = 4numRecursions = 0DNA = []targetDNA = []def init(): global DNAsize, geneSize, geneDiversity, geneSplit, DNA print("This is a very basic form of genetic software. Input variable constraints below. " "Good starting points are: DNA strand size (array size): 32, gene size (sub array size: 5, gene diversity (randomized 0 - x): 5" "gene split (where to split gene array for splicing): 2") DNAsize = int(input('Enter DNA strand size: ')) geneSize = int(input('Enter gene size: ')) geneDiversity = int(input('Enter gene diversity: ')) geneSplit = int(input('Enter gene split: ')) # initializes the gene population, and kicks off # checkDNA recursion initPop() checkDNA(DNA[0])def initPop(): # builds an array of smaller arrays # given DNAsize for x in range(DNAsize): buildDNA() # builds the goal array with a recurring # numerical pattern, in this case just the loop # control variable buildTargetDNA(x)def buildDNA(): newGene = [] # builds a smaller array (gene) using a given geneSize # and randomized with vaules 0 - [given geneDiversity] for x in range(geneSize): newGene.append(random.randint(0,geneDiversity)) # append the built array to the larger array DNA.append(newGene)def buildTargetDNA(x): # builds the target array, iterating with x as a loop # control from the call in init() newGene = [] for y in range(geneSize): newGene.append(x) targetDNA.append(newGene)def checkDNA(childGene): global numRecursions numRecursions = numRecursions+1 gene = DNA[0] targetGene = targetDNA[0] parentGeneA = DNA[random.randint(0,DNAsize-1)] # randomly selects an array (gene) from larger array (DNA) parentGeneB = DNA[random.randint(0,DNAsize-1)] pos = random.randint(geneSplit-1,geneSplit+1) # randomly selects a position to split gene for splicing candidateGene = parentGeneA[:pos] + parentGeneB[pos:] # spliced gene given split from parentA and parentB print("DNA Splice Position: " + str(pos)) print("Element A: " + str(parentGeneA)) print("Element B: " + str(parentGeneB)) print("Candidate Element: " + str(candidateGene)) print("Target DNA: " + str(targetDNA)) print("Old DNA: " + str(DNA)) # iterates over the candidate gene and compares each element to the target gene # if the candidate gene element hits a target gene element, the resulting child # gene is created for x in range(geneSize): #if candidateGene[x] != targetGene[x]: #print("false ") if candidateGene[x] == targetGene[x]: #print("true ") childGene.pop(x) childGene.insert(x, candidateGene[x]) # if the child gene isn't quite equal to the target, and recursion hasn't reached # a max (apparently 900), the child gene is inserted into the DNA. Recursion occurs # until the child gene equals the target gene, or max recursuion depth is exceeded if childGene != targetGene and numRecursions < 900: DNA.pop(0) DNA.insert(0, childGene) print("New DNA: " + str(DNA)) print(numRecursions) checkDNA(childGene)init()print("Final DNA: " + str(DNA))print("Number of generations (recursions): " + str(numRecursions))
回答:
我现在正在研究进化计算,所以我希望我的回答对你有帮助。个人来说,我主要使用Java,因为这是我的主要语言之一,而且为了便携性,因为我在Linux、Windows和Mac上都进行了测试。在我的案例中,我使用排列编码,但如果你还在学习GA的工作原理,我强烈推荐使用二进制编码。这是我称之为初始种群的东西。我尝试描述我的程序工作流程:
1-. 设置我的主要变量
这些是种群大小、个体大小、变异率、交叉率。你还需要创建一个目标函数,并决定你使用的交叉方法。举个例子,假设我的种群大小等于50
,个体大小是4
,变异率是0.04%
,交叉率是90%
,交叉方法将是轮盘赌法。我的目标函数只想检查我的个体是否能够以二进制表示数字15,所以最佳个体必须是1111
。
2-. 初始化我的种群
为此,我创建了50
个个体(50
由我的种群大小决定),并随机生成基因。
3-. 循环开始
对于种群中的每个个体,你需要:
- 根据目标函数评估适应度。如果一个个体由以下字符表示:
00100
,这意味着他的适应度是1。正如你所见,这是一个简单的适应度函数。你可以在学习过程中创建自己的函数,比如fitness = 1/numberOfOnes
。你还需要将所有适应度的总和分配给一个名为populationFitness
的变量,这在下一步中会很有用。 - 选择最佳个体。对于这项任务,有很多方法可以使用,但我们将使用之前提到的轮盘赌法。在这种方法中,你为种群中的每个个体分配一个值。这个值由以下公式给出:
(fitness/populationFitness) * 100
。所以,如果你的种群适应度是10,而某个个体的适应度是3,这意味着这个个体有30%的几率被选中与另一个个体进行交叉。同样,如果另一个个体的适应度是4,他的值将是40%。 - 应用交叉。一旦你有了种群中“最佳”的个体,你需要创建一个新的种群。这个新种群由之前种群中的其他个体组成。对于每个个体,你创建一个从0到1的随机数。如果这个数字在0.9的范围内(因为我们的交叉率是
90%
),这个个体可以繁殖,所以你选择另一个个体。每个新个体都有这两个父母,他们继承了他们的基因。例如:假设parentA = 1001
和parentB = 0111
。我们需要用这些基因创建一个新个体。有很多方法可以做到这一点,统一交叉、单点交叉、双点交叉等。我们将使用单点交叉。在这种方法中,我们在第一个基因和最后一个基因之间选择一个随机点。然后,我们根据parentA
的前几个基因和parentB
的后几个基因创建一个新个体。视觉上展示如下:
parentA = 1001
parentB = 0111
crossoverPoint = 2
newIndividual = 1011
如你所见,新个体共享了父母的基因。
- 一旦你有了带有新个体的新种群,你应用变异。在这种情况下,对于新种群中的每个个体,生成一个介于0和1之间的随机数。如果这个数字在0.04的范围内(因为我们的
mutationRate = 0.04
),你在一个随机基因上应用变异。在二进制编码中,变异只是将1变为0或反之。视觉上展示如下:
individual = 1011
randomPoint = 3
mutatedIndividual = 1010
-
获取最佳个体
-
如果这个个体已经达到了解决方案,则停止。否则,重复循环
-
结束
如你所见,我的英语不是很好,但我希望你能理解遗传算法的基本概念。如果你真的有兴趣学习这个,你可以查看以下链接:
http://www.obitko.com/tutorials/genetic-algorithms/这个链接更清晰地解释了遗传算法的基础知识
http://natureofcode.com/book/chapter-9-the-evolution-of-code/这本书也解释了什么是GA,但也提供了Processing中的一些代码,基本上是Java。但我想你能理解。
我还推荐以下书籍:
遗传算法导论 – Melanie Mitchell
理论与实践中的进化算法 – Thomas Bäck
遗传算法导论 – S. N. Sivanandam
如果你没有钱,你可以很容易地找到这些书的PDF版本。另外,你可以随时在scholar.google.com上搜索文章,几乎所有都是免费下载的。