P-2.0.0 A_2 YCSF 遗传算法

下面我将记录我是怎样用python实现遗传算法的
遗传算法的实现步骤:
1.初始化种群
2.评价种群

3.按评价进行淘汰
4.在剩余种群中进行繁衍
5.繁衍时可能变异(在我的程序中是每次变异)
6.评价种群
7.重复3、4、5、6一定次数后输出最好的结果

我希望找到与某一张300*300的图像的cos相似度较高的,用900个10*10的随机颜色的方块组成的300*300的图像。

代码与注释如下:

from PIL import Image
import numpy as np
import random
from time import time

#下两行用于求内积
from itertools import starmap#starmap的用法是starmap(a,b),a是一个映射,b是一个数组,starmap将每一个b中的元素经过a映射,再生成一个新的,与b的长度一样的数组(迭代器)
import operator#operator.mul函数:operator.mul(2,4)输出8,这是个乘法


non0=lambda x:1e-99 if x==0 else x #处理分母为0情况的函数  



#设置种群数量
ppl=int(input('请设置种群数量(请确保这个数可以被3整除,原因见↓):'))

#设置淘汰数量
slct=int(input('请设置淘汰数量(请确保淘汰数可由未淘汰区的两两配对繁殖完全弥补→淘汰数是总数的1/3):'))

#设置变异数量
vary=int(input('请设置变异数量(DNA长度为900):'))

#设置运行次数
times=int(input('请设置运行次数'))


#载入EXAMPLE图像
im0=Image.open('EXAMPLE.BMP')
orign=np.array(im0)
orign.resize(1,orign.size)
orign=orign.astype('object')[0]#object形长度不限



#将EXAMPLE的RGB值-127.5 使cos相似度的范围变为[-1,1]
for i in range(len(orign)): 
    orign[i]=orign[i]-127.5







#初始化种群
race={}#种群集合

for idt in range(ppl):#idt是每个个体的身份序列  #这个循环耗时23.20s/100次
    colormap={}#colormap记录了组成每个个体的小方块的颜色及其序号

    race[idt]=[]#为每个个体创建一个空的数组
    for cnum in range(len(orign)//(3*100)): #为这个个体中的每个小方块设置一个RGB值,载入到colormap中
        colormap[cnum]=(random.randint(0,255)-127.5,random.randint(0,255)-127.5,random.randint(0,255)-127.5)#将RGB值分别-127.5,原因同上



    for i in range(len(orign)): #往idt数组中按RGBRGB...的顺序从第一个像素(从左到右再从上到下)开始填充
        cnum=((i//3)%300//10+((i//3)//300//10)*30)#将像素的序号转化为对应的小方块的序号


        race[idt].append(colormap[cnum][i%3]) #按像素的次序将R、G或B值填入race[idt]这个数组中 #i%3确保了R处是R值     






remain=0#remain在最后一行有详细注释#使得第一次输出的(事实上是未知的)剩余用时为0


for n in range(times+1):#繁殖了time次后还需要再评估一次来得出最好的图像
    t1=time()#计时1

    #评价:







    markboard=[]#markboard记录了每一个idt对应的相似度
    for idt in range(ppl):#这个循环耗时19.53s/100次,意味着对数量为100的种群评价一次需要19秒左右
        pdt=sum(starmap(operator.mul, zip(orign,race[idt])))#计算EXAMPLE与idt的RGB数组的内积  #如果np的数组是int32型的则此处的运算结果就会错  #zip()函数来可以把n个列表合并,并创建一个元组对的列表  #sum()将一个迭代器中的每一个元素都架起来

        pls=np.linalg.norm(orign)*np.linalg.norm(race[idt])#计算↑两个数组的模的和

        mark=((pdt/non0(pls)+1)/2,idt) #计算cos相似度并转化为0~1的小数 #由元组比较大小优先比较元组中的第一个元素,讲相似度与idt以前后次序对应起来  #处理了分母为0的情况
        markboard.append(mark)#实验表明这个指令在前期耗时较长,而在接下来的循环中几乎不占用时间












    #排序:


    markboard.sort()#将markboard排序按相似度从小到大排序


    print('运行进度:'+str(n)+'/'+str(times)+'\n剩余用时:'+str(remain)+'s/ '+str(remain/60)+'min/ '+str(remain/3600)+'h\n现在的最高相似度:'+str(markboard[-1][0]))#输出程序运行进度、剩余用时与现在种群中的最高相似度 #第一次输出次数不计,因为在最后一次繁殖还需要进行一次评价。#输出结果耗时不计




    #判断是否需要输出图像:
    if n==times:#将来可改为相似度达到一定程度停止,或隔一段时间显示一次
        outdata=np.array(race[markboard[-1][1]])#输出排名最好的RGB数组
        outdata.resize(1,90000,3)#将RGBRGB...转化为(RGB)(RGB)...来让PIL解码
        for i in range(len(outdata)):
            outdata[i]=outdata[i]+127.5#将颜色值复原
        outdata=outdata.astype('uint8')#uint8是PIL解码需要的格式

        imout=Image.frombytes('RGB',(300,300),outdata)#将数组信息转化为图像
        imout.save(str(ppl)+'-'+str(times)+'次运行结果.bmp')#保存结果,名字以'种群数量-运行次数'为区分
        imout.show()#显示结果
        file = open(str(ppl)+'-'+str(times)+'次运行结果.txt', 'w')#创建或写入以'种群数量-运行次数'为区分的txt文件
        file.write('最好相似度:'+str(markboard[-1][0]))#写入最好的相似度值
        file.close()#关闭并保存txt文件
        break#跳出循环









    #淘汰与选择(在非淘汰区自由选择):
    spc=[]#spc指淘汰后的空位


    for i in range(slct):#这个循环耗时0.0s/100次
        spc.append(markboard[0][1])#把最差的数组的idt加入到spc中
        markboard.pop(0)#把最差的数组从markboard中删除(这是为了让淘汰完毕的markboard就变成非淘汰区)

    random.shuffle(markboard)#将非淘汰区打乱顺序
    families=[]#families保存了配对了的父与母数组
    for i in range(len(markboard)//2):#整除号保证了输出的整数不会是浮点型的(e.g:3.0)
        i=2*i#i乘以2以后为0,2,4,6...以此取出随机后的markboard中的数组对
        families.append((markboard[i][1],markboard[i+1][1]))


    #繁殖、变异与诞生

    tspc=0#tspc指的是spc(即存储了空余位置的idt值的数组)中元素的序号,其从0开始,逐渐增大(由于淘汰量被要求设置为种群数的1/3的整数,所以tspc会在最后一个family中取到可行的最大值)
    for family in families:#family即单个的数组对

        rand=[]

        randvary=list(range(900))#这个从0到899的数组代表了每一个色块
        random.shuffle(randvary)#将色块数组随机排序
        randvary=randvary[-vary:]#依据vary的值选出vary个需要变异的色块的编号

        for i in range(900):#可以优化吗#random.randint可能耗时较长

            rand.append(random.randint(0,1))#这个数组与色块序号一一对应,0代表从父数组中取色,1代表从母数组中取色(父、母没有详细界定)



        varycolordict={}#varycolordict字典确保了每一个需要变异的色块中的颜色是一致的(如a像素需要变异,若a所在的色块序号不在字典中,则创建一个新颜色;若在字典中,则按字典赋予颜色)(使用这个复杂的方法是因为RGB数组是逐行编写的,而相同色块的序号是不连续的)
        for i in range(270000):#对于新图像的每一个像素:
            color=(i//3)%300//10+((i//3)//300//10)*30#由像素序号映射到色块序号
            if color in randvary:#如果这个色块序号是需要变异的
                try:race[spc[tspc]][i]=varycolordict[color][i%3]#若可以从varycolordict中取出颜色则为这个像素赋予这个颜色
                except:#若上述指令不能执行(即varycolordict中没有这个色块序号的信息)
                    varycolor=[random.randint(0,255)-127.5,random.randint(0,255)-127.5,random.randint(0,255)-127.5]#则为这个色块序号创建一个新颜色
                    race[spc[tspc]][i]=varycolor[i%3]#为这个像素赋予这个新颜色(依据i%3的值决定赋予R、G还是B的值)
                    varycolordict[color]=varycolor#将色块序号→颜色的映射加入varycolordict
            else:#如果这个色块序号是不需要变异的
                if rand[color]==0:#如果需要从父数组取色
                    race[spc[tspc]][i]=race[family[0]][i]#则这个像素的值等于父数组中同序号像素的值
                else:#反之亦然
                    race[spc[tspc]][i]=race[family[1]][i]
        tspc=tspc+1



    t2=time()#计时2
    remain=(t2-t1)*(times-1-n)#remain依据计时1与计时2的最新结果估计从下一次print后开始计算的剩余的用时






84行代码

注意,每次运行会将前一次同名的输出结果覆盖

运行1500次耗时6小时左右,结果如下:
这是目标图像
这里写图片描述

这是随机生成的图像,cos相似度约为51%左右
这里写图片描述

这是运行1000次后的图像1,cos相似度为:0.6624029672983661
这里写图片描述
与目标图像是有一定相似度的
这里写图片描述

使用说明.txt :

1.准备一张名为EXAMPLE.BMP的图像,放在根目录

2.按提示输入运行参数
例子:
种群数量:99
淘汰数量:33
变异数量:90
运行次数:100

3.结果将保存为一张最优图像和一个记录了最高相似度的txt文件


  1. 该图像是源文件的截图,源文件因为操作失误丢失。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值