基于达尔文进化论的遗传算法,还能帮你破解同事的密码?| 附代码
量子位今天编译整理的这篇文章,全面地介绍了遗传算法(genetic algorithm),从它的起源和目标,到如何用python实现它。
本文作者是Louis Nicolle,发在法国大数据创业公司SICARA的博客上。
我们先来思考一个问题:
如何创造一个好的人工智能?
最朴素的方法,是创造一个“经验主义的算法”,由一堆规则构成,比如说“如果遇到西瓜,买一个”。有了足够多的规则,我们就能复制自然智能。
但是,这样做工作量巨大,而最终造出的智能也不可能超过它的创作者。花了好多时间,造的东西又不理想,是不是很伤心?
于是出现了一种新方法:我们不要写规则了,干脆重现一下进化过程,先造出一条史前鱼类,放在合适的环境中让它进化,等着它变成人,甚至更高级的生命。这种方法叫做“遗传算法”。
首先,让我们刷新自己的记忆,试着理解一下达尔文提出的自然选择。
这个理论很简单:物种想要生生不息,就得持续自我提升,适者才能生存。种群中最优秀的特质应该传递给后代,而其他个体也不能被遗忘,这样才能维持一定的多样性,自然环境发生变化时才更容易适应。
这是遗传算法的理论基础。
优化问题
遗传算法在优化问题上特别管用。
我们来举个例子:背包问题。
这个著名的数学问题是理查德·卡普在1972年提出的。问题是这样的:
你有两样东西,一个设定了承重能力的背包、一些重量和价值各不相同的盒子,目标是把盒子装到背包里,在不超过重量限制的情况下,装进尽可能高的价值。
它是一个优化问题,有很多可能方案,因此非常适合用遗传算法来解决。
动手教程:用遗传算法破解密码
为了体验这个算法,我们用它来解决一个简单的问题:破解同事的密码。
选择适应度函数
创建遗传算法的时候,第一件事是建立一个评价函数,用来衡量样本的成功与否。
它能帮我们分清丑小鸭和白天鹅,区分开之后,我们才能给成功的样本更多“机会”,让它参与生成下一代。
这一步看起来很简单,其实……嘿嘿嘿……
我们的目标是什么来着?破解密码。因此,函数的目标应该是将“成功/失败”的二元结果从0(一直失败)转换成100(完美)。
最简单的方法是:
fitness score = (number of char correct) / (total number of char)
这样,fitness得分更高的样本,就比其他个体更接近成功,我们这个fitness函数就能精确地为算法种群分类。
def fitness (password, test_word):if (len(test_word) != len(password)):print("taille incompatible")returnelse:score = 0i = 0while (i < len(password)):if (password[i] == test_word[i]):score+=1i+=1return score * 100 / len(password)
创建个体
我们知道了该怎样评价这些个体,但如何定义它们呢?这部分很难,目标是要知道哪些特征要保持不变,哪些是可变的。
为了理清思路,我们来和基因比较一下。DNA是由基因组成的,而每个基因都来自不同的等位基因,也就是说,DNA中的每一个基因,都是从一组等位基因中选出的。你需要为算法种群创建DNA。
在我们这个案例中,个体是词,每个词和密码的长度差不多;每个字母是一个基因,这个字母的赋值是它的等位基因。比如说banana这个词,b是第一个字母的等位基因。
这种创造有什么意义?现在我们知道每个个体都是长度合格的词,但是我们的种群覆盖了这个长度下所有可能的词。
创建第一个种群
上面我们知道了个体的特征,以及如何评估它们,接下来,该开始严格意义上的“进化”了。
在创建第一个种群时,要时刻记住这一点:我们不能将种群指向一个明显很好的方案。我们需要让种群尽可能广、覆盖尽可能多的可能性,完美的第一代种群应该覆盖现存所有等位基因。
所以,我们就要创建由随机字母构成的单词。
import randomdef generateAWord (length):i = 0result = ""while i < length:letter = chr(97 + int(26 * random.random()))result += letteri +=1return resultdef generateFirstPopulation(sizePopulation, password):population = []i = 0while i < sizePopulation:population.append(generateAWord(len(password)))i+=1return population
下一代
有了第一代,想创造下一代,我们需要做两件事:1)从现有的这一代中选择一部分;2)让它们结合在一起创造下一代。
首先,要从第一代中选择用来繁殖的“亲本”。
选择有很多方法,但是你必须牢记:我们的目标是从第一代中选择最好的方案,但不能将其他的都去掉。如果在算法开始创建时,就只选择了那些最好的方案,你会迅速收敛到局部最小值,没有机会找到最佳方案。
我的方法是一方面选择表现好的样本,就是下面代码中的best_sample;另一方面选择随机选择一组个体,也就是下面代码中的lucky_few。
import operator
import randomdef computePerfPopulation(population, password):populationPerf = {}for individual in population:populationPerf[individual] = fitness(password, individual)return sorted(populationPerf.items(), key = operator.itemgetter(1), reverse=True)def selectFromPopulation(populationSorted, best_sample, lucky_few):nextGeneration = []for i in range(best_sample):nextGeneration.append(populationSorted[i][0])for i in range(lucky_few):nextGeneration.append(random.choice(populationSorted)[0])random.shuffle(nextGeneration)return nextGeneration
下一步,育种。
我们依然和生物学来进行类比。有性生殖的目的是将两个个体的DNA结合起来,我们这里要做的事情也差不多。
我们有两个个体,Tom和Jerry,它们的DNA是由自己的等位基因(每个字母的赋值)决定的,为了将它们的DNA结合起来,我们需要将它们的字幕混合一下。在诸多方法中,我们选择最简单的一个:子代的每一个字母,都随机取自亲代的Tom或Jerry。
显然,Tom和Jerry这对亲本能生成不止一个后代,我们需要控制后代的数量,来保持种群规模的稳定。也就是说,第一代的个体数要和第二代的个体数相同。
import randomdef createChild(individual1, individual2):child = ""for i in range(len(individual1)):if (int(100 * random.random()) < 50):child += individual1[i]else:child += individual2[i]return childdef createChildren(breeders, number_of_child):nextPopulation = []for i in range(len(breeders)/2):for j in range(number_of_child):nextPopulation.append(createChild(breeders[i], breeders[len(breeders) -1 -i]))return nextPopulation
接下来,我们要谈一谈遗传带来的变化。
上一步的育种过程会导致个体的自然变异。育种之后,每个个体都必须有一定可能性会看到自己的DNA发生变异。这样做的目标是防止算法收敛到局部最小化。
以下是控制变异的代码:
import randomdef mutateWord(word):index_modification = int(random.random() * len(word))if (index_modification == 0):word = chr(97 + int(26 * random.random())) + word[1:]else:word = word[:index_modification] + chr(97 + int(26 * random.random())) + word[index_modification+1:]return worddef mutatePopulation(population, chance_of_mutation):for i in range(len(population)):if random.random() * 100 < chance_of_mutation:population[i] = mutateWord(population[i])return population
关于如何选择变异率,可以参考R.N.Greenwell、J.E.Angus、M.Finck 1995年的论文Optimal mutation probability for genetic algorithms。
地址:http://www.sciencedirect.com/science/article/pii/089571779500035Z
小结
上面,我们讲了遗传算法的理论基础和适用问题,还讲了如何创建自己的遗传算法。
上文涉及的所有Python 3代码都在GitHub上,地址:https://gist.github.com/NicolleLouis/d4f88d5bd566298d4279bcb69934f51d
教程原文地址:https://blog.sicara.com/was-darwin-a-great-computer-scientist-81ffa1dd72f9
如果你想进一步探索AI和遗传算法,可以看看以下资源:
1. 网页应用
BoxCar是这类算法的一个网页应用,这个算法的目标是创造最有效的两轮车辆。
地址:http://rednuht.org/genetic_cars_2/
2. 移动应用
在Evolution这个App里,你需要创建一个有关节、骨骼和肌肉的“生物”,然后算法会优化它的运动方式来完成特定任务,比如跳、跑、爬台阶等等。
地址:https://play.google.com/store/apps/details?id=com.keiwando.Evolution
3. DIY
最后再推荐一个编程游戏网站。每个月,这个网站都会举办为期一周的比赛,让参赛者创造最好的人工智能,获胜者用的几乎一直是遗传算法。
地址:https://www.codingame.com/home
— 完 —
基于达尔文进化论的遗传算法,还能帮你破解同事的密码?| 附代码相关推荐
- 干货!区块链入门、进阶、行业专家观点!1000篇好文帮你破解区块链密码!(中篇)...
随着区块链概念理论的不断成熟以及强劲技术的不断深耕,区块链已经成为投资圈中备受关注的热点,从区块链1.0时代落地数字货币比特币.莱特币等,打开了区块链通向新弯道的高速路口,到区块链2.0时代开始通过智 ...
- 基于PaddleHub的AI人脸侦测:不再用手打灰机(附代码)
项目实现: 用摄像头做人脸识别 判定头部角度,以此来进行游戏控制 所有代码和相关文件可在github中自取: github: planegame_head_control 效果展示请见B站: 一.项目 ...
- 遗传算法_粒子群算法优化支持向量机分类预测-附代码
遗传算法/粒子群算法优化支持向量机分类预测-附代码 文章目录 遗传算法/粒子群算法优化支持向量机分类预测-附代码 1. 支持向量机简介与参数优化的原理 1.1 支持向量机SVM简介 1.2 优化参数的 ...
- 基于A股周内效应择时策略验证与思考(附代码)
基于A股周内效应择时策略验证与思考 本文思路来自于东吴证券研报<A股市场的周内效应>内容,对A股市场的日历效应在周内表现进行探索. 上述研报的核心内容简述: 1.A股市场在股票指数和个股上 ...
- 【自动驾驶】30.c++实现基于eigen实现欧拉角(RPY), 旋转矩阵, 旋转向量, 四元数之间的变换(附代码)
矩阵的使用可参考系列博客:点击此处 原文链接:基于eigen实现欧拉角(RPY), 旋转矩阵, 旋转向量, 四元数之间的变换. 也可以参考另一篇博客:eigen 中四元数.欧拉角.旋转矩阵.旋转向量. ...
- 基于P2P万信金融-- 万信金融项目之业务大总结(文末附代码地址)
一.项目介绍 1. 行业简介 P2P金融又叫P2P信贷.其中,P2P是 peer-to-peer 或 person-to-person 的简写,意思是:个人对个 人.P2P金融指个人与个人间的小额借贷 ...
- 独家 | 基于Python的遗传算法特征约简(附代码)
作者:Ahmed Gad 翻译:张睿毅 校对:丁楠雅 本文4700字,建议阅读15分钟. 本教程主要使用numpy和sklearn来讨论如何使用遗传算法(genetic algorithm,GA)来减 ...
- python遗传算法_基于Python的遗传算法特征约简(附代码)
导言 在某些情况下,使用原始数据训练机器学习算法可能不是合适的选择.该算法在接受原始数据训练时,必须进行特征挖掘,以检测不同组之间的差异.但这需要大量的数据来自动执行特征挖掘.对于小数据集,数据科学家 ...
- 3星|《一万年的爆发:文明如何加速人类进化》:那些拒绝承认欧洲征服和定居美洲过程中生物学差异的人,事实上也是在否认达尔文进化论...
一万年的爆发(文明如何加速人类进化)(精) 作者在书中向<枪炮病菌与钢铁>叫板,全书风格也有点类似<枪炮病菌与钢铁>的旁征博引,不过程度稍逊.作者认为不同族群之间在基因上的差异 ...
最新文章
- Java 多线程概述
- qq浏览器网页翻译_科研利器 | NCBI网站影响因子与网页翻译插件安装指南
- HTTP协议中的chunked编码解析
- as3+java+mysql(mybatis) 数据自动工具(三)
- 操作选项_消防设施操作员关键技能之六:能切换集中火灾报警控制器、消防联动控制器工作状态...
- python创建一个字符串_Python字符串基本操作
- AAAI 2022 | 可解释和鲁棒的联合文本分类及证据提取
- SAP LUW Database update discuss mengniu 蒙牛
- Android 报错:Conversion to Dalvik format failed: ...
- 【C/C++】inline函数和static函数和宏定义的比较
- 三菱fx2n做从站的modbus通讯_三菱PLC编程多种电缆接线图,收藏向!
- ClassLoader类加载器,以及双亲委派模型
- 微信小程序 生成二维码
- js登录界面使用ajax连接数据库,js用ajax连接数据库数据
- linux安装git lfs
- html注册cab包,OCX控件打包成CAB并实现数字签名过程
- android apk u盘升级_android升级安装包--包解析错误
- 理解区块链的“非对称加密”
- PhpSpreadsheet读取excel
- 物理隔离与数据交换-网闸的设计原理与误区
热门文章
- 手把手教你通过端口映射,轻松搭建Windows远程桌面
- 视觉显著性 matlab,转载图像/视觉显著性检测技术发展情况梳理(Saliency Detection、Visual Attention)...
- python http服务器
- crypto安装_Mac安装Golang和vscode
- MySQL 用sql语句格式化时间和日期
- 配置同时使用内网和外网
- DCMTK读取dicom图像
- VMware发布Project Monterey
- 2021-05-26 使用Android Studio创建手机模拟器
- bind错误:server can't find www.linuxprobe.com: SERVF