【超参数寻优】量子遗传算法(QGA) 超参数寻优的java实现
本文基于【超参数寻优】量子遗传算法(QGA) 超参数寻优的python实现
这篇文章改写为Java代码实现,其中适应度计算本文简化了操作。
后期想改写成解决TSP问题的量子遗传算法,如有推荐的文章或者代码,希望各位分享给我一下。嘻嘻
如有错误,或者可以改进的地方希望各位读者指出,谢谢啦。
package com.hust.hui.alarm.common.test.path.qga;
import java.util.*;
/**
* @program: quick_Netty
* @description: 量子遗传算法(QGA) 超参数寻优
* @author: Mr.Liu
* @create: 2019-11-25 12:29
**/
public class QGA {
/**种群数**/
int population_size;
/**染色体数,对应需要寻优的参数个数**/
int chromosome_num;
/**染色体长度**/
int chromosome_length;
/**染色体十进制数值最大值**/
double max_value;
/**染色体十进制数值最小值**/
double min_value;
/**迭代次数**/
int iter_num;
/**量子旋转角度 **/
double deta;
/**
* 初始化类参数
* @param population_size 种群数
* @param chromosome_num 染色体数,对应需要寻优的参数个数
* @param chromosome_length 染色体长度
* @param max_value 染色体十进制数值最大值
* @param min_value 染色体十进制数值最小值
* @param iter_num 迭代次数
* @param deta 量子旋转角度
*/
public QGA(int population_size, int chromosome_num, int chromosome_length,
double max_value, double min_value, int iter_num, double deta) {
this.population_size = population_size;
this.chromosome_num = chromosome_num;
this.chromosome_length = chromosome_length;
this.max_value = max_value;
this.min_value = min_value;
this.iter_num = iter_num;
this.deta = deta;
}
/**
* 种群的量子形式初始化
*/
public List<double[][]> species_origin_angle(){
//种群的量子角度列表
List<double[][]> population_Angle = new ArrayList<>();
for (int i = 0; i < chromosome_num; i++) {
//存储每个染色体所有取值的量子角度
double[][] tmp1 = new double[population_size][];
for (int j = 0; j <population_size ; j++) {
//存储量子角度
double[] tmp2 = new double[chromosome_length];
for (int k = 0; k < chromosome_length; k++) {
tmp2[k] = 3.14 * 2 * Math.random();
}
tmp1[j] = tmp2;
}
population_Angle.add(tmp1);
}
return population_Angle ;
}
/**
* 将初始化的量子角度序列转换为种群的量子系数列表
* @param population_Angle
* @return
*/
public List<double[][][]> population_Q(List<double[][]> population_Angle){
//种群的量子系数列表
List<double[][][]> population_Q = new ArrayList<>();
int size = population_Angle.size();
for (int i = 0; i < size ; i++) {
int length1 = population_Angle.get(i).length;
//存储每个染色体所有取值的量子系数对
double[][][] tmp1 = new double[length1][2][];
for (int j = 0; j < length1; j++) {
int length2 = population_Angle.get(i)[j].length;
//存储每个染色体的每个取值的量子对
double[][] tmp2 = new double[2][];
//存储量子对的一半
double[] tmp3 = new double[length2];
//存储量子对的另一半
double[] tmp4 = new double[length2];
for (int k = 0; k < length2; k++) {
tmp3[k] = Math.sin(population_Angle.get(i)[j][k]);
tmp4[k] = Math.cos(population_Angle.get(i)[j][k]);
}
tmp2[0] = tmp3;
tmp2[1] = tmp4;
tmp1[j] = tmp2;
}
population_Q.add(tmp1);
}
return population_Q;
}
/**
* 计算适应度函数值
* 将种群的量子列表转换为二进制列表
* @param population_Q 种群的量子列表
* @return population_Binary:种群的二进制列表
*/
public List<double[][]> translation(List<double[][][]> population_Q){
//种群的二进制列表
List<double[][]> population_Binary = new ArrayList<>();
int size = population_Q.size();
for (int i = 0; i < size; i++) {
int length1 = population_Q.get(i).length;
double[][] tmp1 = new double[length1][];
for (int j = 0; j < length1 ; j++) {
int length2 = population_Q.get(i)[j][0].length;
double[] tmp2 = new double[length2];
for (int k = 0; k < length2; k++) {
if(Math.pow(population_Q.get(i)[j][0][k],2)>Math.random()){
tmp2[k] = 1;
}else {
tmp2[k] = 0;
}
}
tmp1[j] = tmp2;
}
population_Binary.add(tmp1);
}
return population_Binary;
}
/**
* 求适应度函数数值列表
* @param population_Binary 种群的二进制列表
* @return
*/
public Map<String, Object> fitness(List<double[][]> population_Binary){
int size = population_Binary.size();
//1 . 对应寻优参数的列表,存储所有参数的可能取值
//染色体的二进制表现形式转换为十进制并设置在[min_value,max_value]之间 解码
double[][] parameters = new double[size][];
for (int i = 0; i <size ; i++) {
int lenght1 = population_Binary.get(i).length;
double[] tmp1 = new double[lenght1];
for (int j = 0; j < lenght1; j++) {
double total = 0.0;
int lenght2 = population_Binary.get(i)[j].length;
for (int k = 0; k < lenght2; k++) {
//计算二进制对应的十进制数值
total += population_Binary.get(i)[j][k] * Math.pow(2,k);
}
//将十进制数值坐落在[min_value,max_value]之间
double value = (total*(max_value-min_value)) / Math.pow(2,lenght2) + min_value;
tmp1[j] = value;
}
parameters[i] = tmp1;
}
int lenght3 = parameters[0].length;
// 2 求适应度
double[] fitness_value = new double[lenght3];
for (int i = 0; i < lenght3; i++) {
fitness_value[i] = Math.pow(Math.E, -0.001*parameters[0][i]) * Math.pow(0.8*parameters[0][i],2);
}
//3.找到最优的适应度函数值和对应的参数二进制表现形式
double best_fitness = 0.0;
int pb = population_Binary.get(0)[0].length;
double[][] best_parameter_Binary = new double[size][];
double[][] best_parameter = new double[size][];
for (int i = 0; i <size ; i++) {
best_parameter_Binary[i] = new double[pb];
best_parameter[i] = new double[pb];
}
int len1 = population_Binary.get(0).length;
for (int i = 0; i < len1; i++) {
if(best_fitness<fitness_value[i]){
best_fitness = fitness_value[i];
for (int j = 0; j < size; j++) {
best_parameter_Binary[j] = population_Binary.get(j)[i];
best_parameter[j] = parameters[j];
}
}
}
Map<String , Object> map = new HashMap<>();
map.put("parameters",parameters);
map.put("fitness_value",fitness_value);
map.put("best_parameter_Binary",best_parameter_Binary);
map.put("best_fitness",best_fitness);
map.put("best_parameter",best_parameter);
return map;
}
/**
* 全干扰交叉
* 对种群量子角度列表进行全干扰交叉
* @param population_Angle
*/
public double[][][] crossover(List<double[][]> population_Angle){
//初始化一个空列表,全干扰交叉后的量子角度列表
double[][][] population_Angle_crossover = new double[population_Angle.size()][][];
for (int i = 0; i < chromosome_num; i++) {
double[][] tmp11 = new double[population_size][chromosome_length];
for (int j = 0; j < population_size; j++) {
double[] tmp12 = new double[chromosome_length];
for (int k = 0; k < chromosome_length; k++) {
tmp12[k] = 0.0;
}
tmp11[j] = tmp12;
}
population_Angle_crossover[i] = tmp11;
}
int size = population_Angle.size();
for (int i = 0; i < size; i++) {
for (int j = 0; j < population_Angle.get(i).length; j++) {
for (int k = 0; k <population_Angle.get(i)[j].length ; k++) {
int ni = (j-k+population_Angle.get(i).length) % population_Angle.get(i).length;
population_Angle_crossover[i][j][k] = population_Angle.get(i)[ni][k];
}
}
}
return population_Angle_crossover;
}
/**
* 采用量子门变换矩阵进行量子变异
* @param population_Angle_crossover 全干扰交叉后的量子角度列表
* @param population_Angle 种群的量子角度列表
* @param best_parameter_Binary 种群的二进制列表
* @param best_fitness 找到最优的适应度函数值和对应的参数二进制表现形式
*/
public List<double[][]> mutation(double[][][] population_Angle_crossover,List<double[][]> population_Angle,double[][] best_parameter_Binary,double best_fitness){
List<double[][]> list = new ArrayList<>();
for (int i = 0; i <population_Angle_crossover.length ; i++) {
list.add(population_Angle_crossover[i]);
}
//交叉后的种群量子系数列表
List<double[][][]> population_Q_crossover = population_Q(list);
//交叉后的种群二进制数列表
List<double[][]> population_Binary_crossover = translation(population_Q_crossover);
Map<String , Object> map = fitness(population_Binary_crossover);
//求出交叉后的适应度函数值列表
double[][] parameters = (double[][])map.get("parameters");
double[] fitness_crossover = (double[])map.get("fitness_value");
double[][] best_parameter_Binary_crossover = (double[][])map.get("best_parameter_Binary");
double best_fitness_crossover = (double)map.get("best_fitness");
//初始化每一个量子位的旋转角度
double[][][] Rotation_Angle = new double[population_Angle_crossover.length][][];
for (int i = 0; i < population_Angle_crossover.length; i++) {
int length = population_Angle_crossover[i].length;
double[][] tmp1 = new double[length][];
for (int j = 0; j < length; j++) {
int length2 = population_Angle_crossover[i][j].length;
double[] tmp2 = new double[length2];
for (int k = 0; k < length2; k++) {
tmp2[k] = 0.0;
}
tmp1[j] = tmp2;
}
Rotation_Angle[i] = tmp1;
}
double deta2 = deta;
//求每个量子位的旋转角度
for (int i = 0; i < chromosome_num; i++) {
for (int j = 0; j <population_size ; j++) {
if(fitness_crossover[j] <= best_fitness){
for (int k = 0; k < chromosome_length; k++) {
int s1 = 0;
double a1 = population_Q_crossover.get(i)[j][0][k];
double b1 = population_Q_crossover.get(i)[j][1][k];
if (population_Binary_crossover.get(i)[j][k] == 0 && best_parameter_Binary[i][k]==0 && a1*b1>0)
s1 = -1;
if (population_Binary_crossover.get(i)[j][k] == 0 && best_parameter_Binary[i][k]==0 && a1*b1<0)
s1 = 1;
if (population_Binary_crossover.get(i)[j][k] == 0 && best_parameter_Binary[i][k]==0 && a1*b1==0)
s1 = -1;
if (population_Binary_crossover.get(i)[j][k] == 0 && best_parameter_Binary[i][k]==1 && a1*b1>0)
s1 = 1;
if (population_Binary_crossover.get(i)[j][k] == 0 && best_parameter_Binary[i][k]==1 && a1*b1<0)
s1 = -1;
if (population_Binary_crossover.get(i)[j][k] == 0 && best_parameter_Binary[i][k]==1 && a1*b1==0)
s1 = 1;
if (population_Binary_crossover.get(i)[j][k] == 1 && best_parameter_Binary[i][k]==0 && a1*b1>0)
s1 = -1;
if (population_Binary_crossover.get(i)[j][k] == 1 && best_parameter_Binary[i][k]==0 && a1*b1<0)
s1 = 1;
if (population_Binary_crossover.get(i)[j][k] == 1 && best_parameter_Binary[i][k]==0 && a1*b1==0)
s1 = -1;
if (population_Binary_crossover.get(i)[j][k] == 1 && best_parameter_Binary[i][k]==1 && a1*b1>0)
s1 = 1;
if (population_Binary_crossover.get(i)[j][k] == 1 && best_parameter_Binary[i][k]==1 && a1*b1<0)
s1 = -1;
if (population_Binary_crossover.get(i)[j][k] == 1 && best_parameter_Binary[i][k]==1 && a1*b1==0)
s1 = 1;
Rotation_Angle[i][j][k] = deta2 * s1;
}
}else {
for (int k = 0; k < chromosome_length; k++) {
int s2 = 0;
double a2 = population_Q_crossover.get(i)[j][0][k];
double b2 = population_Q_crossover.get(i)[j][1][k];
if (population_Binary_crossover.get(i)[j][k] == 0 && best_parameter_Binary[i][k]==0 && a2*b2>0)
s2 = -1;
if (population_Binary_crossover.get(i)[j][k] == 0 && best_parameter_Binary[i][k]==0 && a2*b2<0)
s2 = 1;
if (population_Binary_crossover.get(i)[j][k] == 0 && best_parameter_Binary[i][k]==0 && a2*b2==0)
s2 = -1;
if (population_Binary_crossover.get(i)[j][k] == 0 && best_parameter_Binary[i][k]==1 && a2*b2>0)
s2 = 1;
if (population_Binary_crossover.get(i)[j][k] == 0 && best_parameter_Binary[i][k]==1 && a2*b2<0)
s2 = -1;
if (population_Binary_crossover.get(i)[j][k] == 0 && best_parameter_Binary[i][k]==1 && a2*b2==0)
s2 = 1;
if (population_Binary_crossover.get(i)[j][k] == 1 && best_parameter_Binary[i][k]==0 && a2*b2>0)
s2 = -1;
if (population_Binary_crossover.get(i)[j][k] == 1 && best_parameter_Binary[i][k]==0 && a2*b2<0)
s2 = 1;
if (population_Binary_crossover.get(i)[j][k] == 1 && best_parameter_Binary[i][k]==0 && a2*b2==0)
s2 = -1;
if (population_Binary_crossover.get(i)[j][k] == 1 && best_parameter_Binary[i][k]==1 && a2*b2>0)
s2 = 1;
if (population_Binary_crossover.get(i)[j][k] == 1 && best_parameter_Binary[i][k]==1 && a2*b2<0)
s2 = -1;
if (population_Binary_crossover.get(i)[j][k] == 1 && best_parameter_Binary[i][k]==1 && a2*b2==0)
s2 = 1;
Rotation_Angle[i][j][k] = deta2 * s2;
}
}
}
}
//根据每个量子位的旋转角度,生成种群新的量子角度列表
for (int i = 0; i < chromosome_num; i++) {
for (int j = 0; j < population_size; j++) {
for (int k = 0; k < chromosome_length; k++) {
population_Angle.get(i)[j][k] = population_Angle.get(i)[j][k] + Rotation_Angle[i][j][k];
}
}
}
return population_Angle;
}
public static void main(String[] args) {
/**种群数**/
int population_size = 20;
/**染色体数,对应需要寻优的参数个数**/
int chromosome_num = 10;
/**染色体长度**/
int chromosome_length = 10;
/**染色体十进制数值最大值**/
double max_value = 20;
/**染色体十进制数值最小值**/
double min_value = 1;
/**迭代次数**/
int iter_num = 50;
/**量子旋转角度 **/
double deta = 0.2;
double[] results = new double[iter_num];
double best_fitness = 0.0;
double[][] best_parameter = new double[20][];
QGA qga = new QGA(population_size,chromosome_num,chromosome_length,max_value,min_value,iter_num,deta);
//种群初始化
List<double[][]> population_Angle = qga.species_origin_angle();
for (double[][] a:population_Angle) {
System.err.println("【");
for (int i = 0; i <a.length ; i++) {
for (int j = 0; j < a[i].length; j++) {
System.err.print(a[i][j]+" ");
}
}
System.err.println("】");
}
for (int i = 0; i < iter_num ; i++) {
List<double[][][]> population_Q = qga.population_Q(population_Angle);
//将量子系数转换为二进制形式
List<double[][]> population_Binary = qga.translation(population_Q);
//计算本次迭代的适应度函数值列表,最优适应度函数值及对应的参数
Map<String , Object> map = qga.fitness(population_Binary);
//求出交叉后的适应度函数值列表
double[][] parameters = (double[][])map.get("parameters");
double[] fitness_value = (double[])map.get("fitness_value");
double[][] current_parameter_Binary = (double[][])map.get("best_parameter_Binary");
double current_fitness = (double)map.get("best_fitness");
double[][] current_parameter = (double[][])map.get("best_parameter");
if(current_fitness>best_fitness){
best_fitness = current_fitness;
best_parameter = current_parameter;
}
System.out.println("iteration is :"+i+1+";Best parameters:");
for (int j = 0; j < best_parameter.length; j++) {
System.out.print("【");
for (int k = 0; k <best_parameter[j].length ; k++) {
System.out.print(best_parameter[j][k]+" ");
}
System.out.print("】");
}
System.out.println(";Best fitness:"+best_fitness);
System.out.println();
System.out.println();
results[i] = best_fitness;
//全干扰交叉
double[][][] population_Angle_crossover = qga.crossover(population_Angle);
//量子旋转变异
population_Angle = qga.mutation(population_Angle_crossover,population_Angle,current_parameter_Binary,current_fitness);
}
System.out.println("Final results are :'"+ Arrays.toString(results));
System.out.println("Final parameters are :'"+ Arrays.toString(best_parameter[best_parameter.length-1]));
}
}
下面是程序运行产生的结果,我没有想转载的那位大佬用图画出来了
这篇文章理论讲的很好,可以看看学习学习 --------量子遗传算法详解