利用 Python 实现 遗传算法(GeneticAlgorithm)

要求

题目

核心代码

生成初代

我采用的是2进制来表示染色体,先随机出一堆0和1的列表

def getFisrtGroup(group_size, chrom_length):
    group = []
    for i in range(group_size):
        temp = []
        for j in range(chrom_length):
            temp.append(random.randint(0, 1))
        group.append(temp)
    return group
GA循环
for i in range(generation):
    obj_value = calobjValue(group, chrom_length, max_value, min_value, divid)   # 个体评价
    fit_value = calfitValue(obj_value)  # 获取群体适应值
    best_individual, best_fit = best(group, fit_value)  # 返回最优基因, 最优适应值
    if( abs(f(xx)+186.730909) < 0.000001):#找到最优解
    
    crossover(group, fit_value, pc) # 交配
    mutation(group, pm) # 变异
解码

div代表每个参数的开始位置和末尾位置,方便分隔参数。这个函数会返回一个包含参数的列表。

'''
b 染色体
chrom_length 染色体长度
max_value,min_value 最大最小值
div 分割
'''
def b2d(b, chrom_length, max_value, min_value, div):
    rwno = []
    for i in range(len(div)):
        。。。
        for j in range(star, end):
            t += b[j] * (math.pow(2, j - star))
        t = t * max_value / (math.pow(2, end - star + 1) - 1) - min_value
        rwno.append(t)
    return rwno
获取适应值

因为都是求函数最小值,所以我用的是e^(-x)这个函数来表示适应值,当计算结果减去预估的最小值,结果越逼近1就代表计算结果离最小值越近。

e^-x

#适应函数
def s(x):
    return math.exp(-abs(x-1))
选择交叉方案

我用的是轮盘选择,先求出每个子代的适应值的占比,然后把它们按它的占比分在[0, 1]的区间上面,随机出0到1的随机数,看看这个随机数落在谁的上面。

# 转轮盘选择法
def selection(group, fit_value):
    newfit_value = [] #[ [[染色体], [锚点]],... ]
    newgroup = [] #[ [父], [母], [父], [母],....]
    # 适应度总和
    total_fit = sum_fit(fit_value)
    # 设置各个的锚点
    t = 0
    for i in range(len(group)):
        t += fit_value[i]/total_fit
        newfit_value.append([group[i], t])
    # 转轮盘选择法
    for i in range(len(newfit_value)):
        parents = len(newfit_value) # 初始化指针
        r = random.random() #指针
        for j in range(len(newfit_value)):#看看指针指到睡了
            if newfit_value[j][1] > r:
                parents = j
                break
        newgroup.append(newfit_value[parents][0])
        
    return newgroup
交配

先用上面的轮盘选出一堆父代母代,然后开始交叉。

def crossover(group, fit_value, pc):
    parents_group = selection(group, fit_value) #[ [[父], [母]],....]
    group_len = len(parents_group)
    for i in range(0, group_len, 2):
        if(random.random() < pc): # 看看是否要交配
            cpoint = random.randint(0, len(parents_group[0])) # 随机交叉点
            。。。

繁衍

继续重复计算适应值→选择→交配的过程模拟物竞天择适者生存的遗传算法,知道推衍出想要的结果。

计算结果

generation = 1000    # 繁衍代数
group_size = 2000     # 染色体数量,偶数
chrom_length = 500   # 染色体长度

结果

找出两个最优解:

[2.3566456537597764, 2.3564076733830963]
[0.7849757859540485, 2.3563759723412123]

精确到小数点后六位:

F(x) = 1.0000002663624468
x = [0.7851439319246674, 2.356238727907994]
染色体 = [0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1,1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1,0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1]
适应值 = 0.9999997336375888
代数 = 839

最后

感觉遗传算法挺玄学的,开局一串随机数,全靠变异,还容易陷入局部最优解的状况。如果有大致函数图像,可以尝试把初代种群洒在一个全局最优解的附近,这样开局就是高富帅了。变异几率高的话的确可以很快把适应值拉上去,但达到顶峰的时候会有更大的波动,很难得到想要的答案,每次快接近的时候就被一个变异给甩出去了。但是变异几率不高可能好多代都在原地踏步,我想到的解决方案就是,一开始变异几率高,先把适应值升高到一定程度之后,在把变异几率给调下来,这样就可以稍稍解决刚才说到的起步慢、波动大的两个问题。还有就是如果检测到发现自己陷入局部最优解(或者说长期适应值不增长),可以再次把变异几率调高来逃脱。如果染色体数量太多,会拖慢适应改变速度,染色体长度同理,交配几率的影响大概和变异几率一样吧。

Github:https://github.com/izoyo/Python-GeneticAlgorithm

遗传算法Genetic Algorithm)是模拟自然进化过程的一种优化算法,适用于优化复杂的非线性问题。在神经网络中,遗传算法可以用于优化神经网络的结构和参数,以达到更好的学习效果。 下面是一个使用遗传算法优化神经网络模型的 Python 代码示例: ``` import numpy as np from keras.models import Sequential from keras.layers import Dense from keras.utils import to_categorical from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split # 加载数据集 iris = load_iris() X = iris.data y = iris.target # 将类别变量转换为二进制形式 y_binary = to_categorical(y) # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y_binary, test_size=0.2, random_state=42) # 定义神经网络模型结构 def create_model(input_dim, output_dim, nodes, n_layers): model = Sequential() model.add(Dense(nodes, input_dim=input_dim, activation='relu')) for i in range(n_layers-1): model.add(Dense(nodes, activation='relu')) model.add(Dense(output_dim, activation='softmax')) return model # 定义适应度函数 def fitness(model, X_train, y_train, X_test, y_test): model.fit(X_train, y_train, epochs=100, batch_size=10, verbose=0) _, accuracy = model.evaluate(X_test, y_test, verbose=0) return accuracy # 定义遗传算法参数 pop_size = 20 # 种群大小 n_generations = 50 # 迭代次数 mutation_rate = 0.1 # 变异率 n_layers_range = [1, 3] # 神经网络层数范围 nodes_range = [5, 20] # 神经元数量范围 # 初始化种群 pop = [] for i in range(pop_size): n_layers = np.random.randint(n_layers_range[0], n_layers_range[1]+1) nodes = np.random.randint(nodes_range[0], nodes_range[1]+1) model = create_model(X_train.shape[1], y_binary.shape[1], nodes, n_layers) pop.append(model) # 迭代优化 for i in range(n_generations): # 计算适应度 fitness_scores = [] for j in range(pop_size): fitness_scores.append(fitness(pop[j], X_train, y_train, X_test, y_test)) # 选择 parents = np.random.choice(pop, size=pop_size//2, replace=False, p=np.array(fitness_scores)/sum(fitness_scores)) # 交叉 children = [] for j in range(pop_size//2): parent1 = parents[j] parent2 = parents[pop_size//2-1-j] child1 = create_model(X_train.shape[1], y_binary.shape[1], parent1.layers[0].output_shape[1], len(parent1.layers)-1) child2 = create_model(X_train.shape[1], y_binary.shape[1], parent2.layers[0].output_shape[1], len(parent2.layers)-1) for k in range(len(parent1.layers)-1): if np.random.rand() > 0.5: child1.layers[k].set_weights(parent1.layers[k].get_weights()) child2.layers[k].set_weights(parent2.layers[k].get_weights()) else: child1.layers[k].set_weights(parent2.layers[k].get_weights()) child2.layers[k].set_weights(parent1.layers[k].get_weights()) children += [child1, child2] # 变异 for j in range(len(children)): if np.random.rand() < mutation_rate: n_layers = np.random.randint(n_layers_range[0], n_layers_range[1]+1) nodes = np.random.randint(nodes_range[0], nodes_range[1]+1) model = create_model(X_train.shape[1], y_binary.shape[1], nodes, n_layers) children[j] = model # 更新种群 pop = parents + children # 输出最优解 fitness_scores = [] for j in range(pop_size): fitness_scores.append(fitness(pop[j], X_train, y_train, X_test, y_test)) best_model = pop[np.argmax(fitness_scores)] print('Best accuracy:', max(fitness_scores)) print('Best model:') best_model.summary() ``` 以上代码中,首先加载 Iris 数据集,并将类别变量转换为二进制形式。接着定义神经网络模型结构和适应度函数。然后定义遗传算法参数,包括种群大小、迭代次数、变异率、神经网络层数范围和神经元数量范围。然后初始化种群,并进行迭代优化过程。在每次迭代中,先计算种群中每个个体的适应度,然后进行选择、交叉和变异操作,最后更新种群。最终输出最优解,即最高的测试集准确率和对应的神经网络模型结构。 需要注意的是,该代码使用了 Keras 框架来构建神经网络模型,因此需要先安装 Keras 和相关依赖库。如果没有安装,可以通过以下命令进行安装: ``` pip install keras tensorflow scikit-learn numpy ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值