遗传算法和一些思考

遗传算法是模拟生物变异进化的算法。抽象一下生物的进化:生物的所有性状由DNA决定,DNA在换代(繁殖)的过程中产生变异和交换,形成新的DNA序列。而生物的适应性由性状决定。

过程(from:百度百科):

a)初始化:设置进化代数计数器t=0,设置最大进化代数T,随机生成M个个体作为初始群体P(0)。
b)个体评价:计算群体P(t)中各个个体的适应度。
c)选择运算:将选择算子作用于群体。选择的目的是把优化的个体直接遗传到下一代或通过配对交叉产生新的个体再遗传到下一代。选择操作是建立在群体中个体的适应度评估基础上的。
d)交叉运算:将交叉算子作用于群体。遗传算法中起核心作用的就是交叉算子。
e)变异运算:将变异算子作用于群体。即是对群体中的个体串的某些基因座上的基因值作变动。
群体P(t)经过选择、交叉、变异运算之后得到下一代群体P(t+1)。
f)终止条件判断:若t=T,则以进化过程中所得到的具有最大适应度个体作为最优解输出,终止计算。
在KK的《失控》中提出,生物的进化看上去不是完全随机而是有一定的方向性的,似乎生物知道如何更适应环境。书中并没有说明为什么,我个人认为,生物在择偶过程中,会有对更适应环境的个体的青睐:吃的好过得好的雄性一般会更健壮,会有更好的嗓音,更强的搏斗能力,更光滑的皮毛,更容易产生后代。也就是说,在自然使用生死在长时间阶段上进行选择之外,还有物种本身透过自己对于适应环境的性状的潜意识认知对基因进行了选择。像人类这种一夫一妻一辈子很不适应自然进化。

所以对于GA中变异这一步,完全的随机性,虽然能够保证对问题的最小假设,但是会导致进化过于盲目。所以我想可以在上下代之间传递fitness和突变的基因,在下一代进行突变时,使用不同的概率对待不同方向的突变。这个有点像蚁群在GA上的移植。把蚁群中,个体对于附近环境的感知和傻傻的随机决策放到个体突变的过程中。

普通GA的代码:

t = 0
T = 10

spieces = [[1, 2],\
         [2, 3],\
         [3, 4],\
         [4, 5],\
         [5, 6]]

def target(params):
    return params[0] * params[0] + params[1] * params[1]

def fitness(params):
    return 10 - target(params)

def live(spieces):
    import random
    probs = roulette(spieces)
    lefts = []
    idx = 0
    for p in probs:
        r = random.random()
        if ( r < p ):
            lefts.append(spieces[idx])          
    return lefts

def roulette(spieces):
    idx = 0
    total = 0
    prob = []
    for params in spieces:
        p = fitness( params )
        total = total + p
        prob.append(p)
        idx = idx + 1

    idx = 0
    for p in prob:
        prob[idx] = p/total
        idx = idx + 1
        
    return prob

def mutate(spieces, count):
    import copy
    import random
    s = copy.deepcopy(spieces)
    i = 0
    muts = []
    while (i < count):
        idx = int(random.random() * len(s))
        
        m = s[idx]
        cha = int(random.random() * len(m))
        ratio = random.random() * 2
        m[cha] = m[cha] * ratio
        muts.append(m)
        
        del s[idx]
        i = i + 1
        
    return muts


def crossover(spieces, count):
    import copy
    import random
    s = copy.deepcopy(spieces)
    i = 0
    crs = []
    while (i < count):
        idx = int(random.random() * len(s))
        a = s[idx]
        del s[idx]
        idx = int(random.random() * len(s))
        b = s[idx]
        del s[idx]

        h = int(random.random() * len(a))
        crs.append(a[:h] + b[h:])
        crs.append(b[:h] + a[h:])
        
        i = i + 2
    return crs


"""main"""
i = 0
end = False
while (i < 10 and (not end)):
    l = live(spieces)
    nc = len(spieces) - len(l)
    cc = int(nc/2)
    mc = nc - cc
    m = mutate(spieces, mc)
    c = crossover(spieces, cc)
    spieces = l + m + c
    print('--------%d--------'%(i))
    for s in spieces:
        print(s)
        
    for s in spieces:
        if(fitness(s) > 9):
            print('best: %r'%(s))
            end = True
            
    i = i + 1

对父代有记忆的GA代码:

t = 0
T = 10

spieces = [[1, 2, {'idx':0 ,'old': 1, 'fit': 0}],\
         [2, 3, {'idx':0 ,'old': 2, 'fit': 0}],\
         [3, 4, {'idx':0 ,'old': 3, 'fit': 0}],\
         [4, 5, {'idx':0 ,'old': 4, 'fit': 0}],\
         [5, 6, {'idx':0 ,'old': 5, 'fit': 0}]]
fitnesses = [0 for i in spieces]
def target(params):
    return params[0] * params[0] + params[1] * params[1]

def fitness(params):
    return 10 - target(params)

def live(spieces, fitnesses):
    import random
    probs = roulette(spieces, fitnesses)
    lefts = []
    idx = 0
    for p in probs:
        r = random.random()
        if ( r < p ):
            lefts.append(spieces[idx])          
    return lefts

def roulette(spieces, fitnesses):
    idx = 0
    total = 0
    prob = []
    del fitnesses[:]
    for params in spieces:
        p = fitness( params )
        fitnesses.append(p)
        total = total + p
        prob.append(p)
        idx = idx + 1

    idx = 0
    for p in prob:
        prob[idx] = p/total
        idx = idx + 1
        
    return prob

def mutate(spieces, count):
    import copy
    import random
    s = copy.deepcopy(spieces)
    i = 0
    muts = []
    while (i < count):
        idx = int(random.random() * len(s))
        
        m = s[idx]
        cha = int(random.random() * len(m))
        ratio = random.random() * 2
        m[cha] = m[cha] * ratio
        muts.append(m)
        
        del s[idx]
        i = i + 1
        
    return muts

def mutateWithMemory(spieces, count, fitnesses):
    import copy
    import random
    s = copy.deepcopy(spieces)
    i = 0
    muts = []
    while (i < count):
        idx = int(random.random() * len(s))
        m = s[idx]
        cha = int(random.random() * (len(m) - 1))
        fitness = fitnesses[idx]
        threshold = 0.5
        if (m[-1]['idx'] == cha):
            memory = m[-1]
            sign = 1
            if (fitness > memory['fit'] and m[cha] < m[-1]['old']):
                #last change is decrease and works well
                sign = -1
            elif (fitness < memory['fit'] and m[cha] > m[-1]['old']):
                #last change is increase and works badly
                sign = -1

            threshold = 0.2 * sign + threshold

        m[-1]['idx'] = cha
        m[-1]['old'] = m[cha]
        m[-1]['fit'] = fitness
        
        direction = 1 if random.random() > threshold else -1
        change = random.random() * m[cha]
        m[cha] = m[cha] + direction * change
        muts.append(m)
        
        del s[idx]
        i = i + 1
        
    return muts

def crossover(spieces, count):
    import copy
    import random
    s = copy.deepcopy(spieces)
    i = 0
    crs = []
    while (i < count):
        idx = int(random.random() * len(s))
        a = s[idx]
        del s[idx]
        idx = int(random.random() * len(s))
        b = s[idx]
        del s[idx]

        h = int(random.random() * len(a))
        crs.append(a[:h] + b[h:])
        crs.append(b[:h] + a[h:])
        
        i = i + 2
    return crs


"""main"""
i = 0
end = False
while (i < 10 and (not end)):
    l = live(spieces, fitnesses)
    nc = len(spieces) - len(l)
    cc = int(nc/2)
    mc = nc - cc
    m = mutateWithMemory(spieces, mc, fitnesses)
    c = crossover(spieces, cc)
    spieces = l + m + c
    print('--------%d--------'%(i))
    for s in spieces:
        print(s)
        
    for s in spieces:
        if(fitness(s) > 9):
            print('best: %r'%(s))
            end = True
            
    i = i + 1


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值