【超参数寻优】量子遗传算法(QGA) 超参数寻优的java实现

原文链接:https://blog.csdn.net/Luqiang_Shi/article/details/84672658

【超参数寻优】量子遗传算法(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]));
    }
}

下面是程序运行产生的结果,我没有想转载的那位大佬用图画出来了
在这里插入图片描述
这篇文章理论讲的很好,可以看看学习学习 --------量子遗传算法详解

原文链接:加载失败,请重新获取