【问题标题】:Genetic Algorithm optimization in C++C++ 中的遗传算法优化
【发布时间】:2011-05-24 09:49:32
【问题描述】:

我正在寻找添加或省略代码的有效方法,以帮助我的遗传算法程序更快地返回结果。该程序的目标是接受一个字符串并创建尽可能匹配的其他字符串。无论哪个新制作的字符串与最接近(前 5 个)匹配的字符串都与其他字符串匹配并产生后代(其中一些具有将新随机数放入字符串而不影响长度的突变)。一切都很好,但是要使一些较长的字符串(4 及以上)完美匹配,需要数代人。 对不起 tl; dr 长度,但这是我当前的代码。批评吧!

    #include "stdio.h"
    #include "fstream"
    #include "ctime"
    #include "iostream"
    #include "string"
    #include "windows.h"

    #define CHARACTERS 16
    #define STRINGS 100
    /*
    Enter String(max 16 chars)
    Generate 100 words of the same length
    Check for Fitness(how close each word is to the string)
    Every generation: display top 5
    Clone the top 5
    Top 20 reproduce(mix each other's chars)
    1/1000 chance the children might mutate(each newly mixed string or char might have a completely random number)

    */

    typedef struct _stringHolder
    {
        char randString[CHARACTERS];
        int fitness;
    }StringHolder;


//Randomly generate 100 words
void generate(char *myString, StringHolder *SH)
{
    unsigned seed = time(0);
    srand(seed);
        //int i = 0;
    int j = 0;
    char randChar;
        //char showString[CHARACTERS];
    for(int i=0; i<STRINGS; i++)
    {
        for(int j=0; j<strlen(myString); j++)
        {
            randChar = ('a' + (rand() %26));
            SH[i].randString[j] = randChar;
        }
        //limiter so that it doesn't crash
        SH[i].randString[strlen(myString)] = 0;
    }
}

//Check the similarity of the random strings to the original string.
void getFitness(char *myString, StringHolder *SH)
{
    for(int i=0; i<STRINGS; i++)
    {
        for(int j=0; j<strlen(myString); j++)
        {
            if(SH[i].randString[j] == myString[j])
            { SH[i].fitness++; }
        }
    }
}

//Sort the strings
void sortByFitness(char *myString, StringHolder *SH)
{

        bool swapped = 1;
        while(swapped)
        {
            swapped = 0;
            for(int a=0; a<STRINGS-1; a++)
            {
                if(SH[a].fitness < SH[a+1].fitness)
                {
                    swapped = 1;


                        StringHolder temp[STRINGS]; 
                        temp[a] = SH[a+1]/*.randString[i]*/;
                        SH[a+1]/*.randString[i]*/ = SH[a]/*.randString[i]*/;
                        SH[a]/*.randString[i]*/ = temp[a];

                    /*if(SH[a].fitness < SH[a+1].fitness)
                    { swapped = 0; }*/
                }
            }
        }//while
}

//Clone the Top 5 strings
void cloneTopFive(char *myString, StringHolder *SH, StringHolder *cloneString)
{
    for(int i=0; i<5; i++)
    {       
            cloneString[i]/*.randString[j]*/ = SH[i]/*.randString[j]*/;
            //printf("cloneString[%d] now holds %s.\n", i, SH[i].randString);

    }
}
//Reproduce the Top 20 strings by mixing and matching elements between strings
void reproduceTopTwenty(char *myString, StringHolder *SH /*char *cloneString*/)
{
    /*for(int h=5; h<95; h++)
    {*/
        for(int i=0; i<20; i++)
        {
            for(int j=0; j<strlen(myString)-1; j++)
            {
                //char temp[16];
                //temp[i] = 
                SH[i].randString[j] = SH[1 + (rand() %20)].randString[1 + (rand() %strlen(myString)-1)];
                int randomNumber;
                randomNumber = (1 +(rand() %100));
                if(randomNumber == 7)
                {
                    SH[i].randString[1 + (rand() %strlen(myString)-1)] = ('a' + (rand() %26));
                }
            }
        }

}
//Randomize the other 75 numbers and place the cloned Top 5 at the end of the String Holder(SH)
void randomizeOther75(char *myString, StringHolder *SH, StringHolder *cloneString)
{
    for(int i=20; i<STRINGS; i++)
    {
        for(int j=0; j<strlen(myString); j++)
        {
            SH[i].randString[j] = ('a' + (rand() %26));
        }
    }

    for(int i=0; i<5; i++)
    {
        for(int j=0; j<strlen(myString); j++)
        {
            int v = i + 94;
            SH[v].randString[j] = cloneString[i].randString[j];
        }
    }

}
void printGen(char *myString, StringHolder *SH)
{
    for(int i=0; i<5; i++)
        {       
            if(SH[i].fitness == strlen(myString))
             { printf("%s has %d fitness. Perfection!\n", SH[i].randString, SH[i].fitness); }
            else
             printf("%s has %d fitness.\n", SH[i].randString, SH[i].fitness);
        }
}
void main()
{
    char myString[CHARACTERS];
    StringHolder cloneString[5];
    StringHolder SH[STRINGS];
    for(int i=0; i<STRINGS; i++)
    { SH[i].fitness = 0; }

    printf("Enter your name(no whitespaces): ");
    scanf("%s", myString);
    /*while(strlen(myString) >= CHARACTERS)
    {
        printf("Please type a string with less than 16 characters\n");
        scanf("%s", myString);
    }*/
    //printf("%s\n", myString);

    //first generation
    generate(myString, SH);
    int gen = 0;
    while(1)
    {   
        char x = ' ';
    /*  printf("Insert something. Anything!");
        scanf(&x);*/


        /*char newString[CHARACTERS];
        for(int i=0; i<5; i++)
        {
            for( int j=0; j< strlen(myString); j++)
            {           
                newString[j] = SH[i].randString[j]; 
            }
            newString[strlen(myString)] = 0;
            printf("%s has %d fitness.\n", newString, SH[i].fitness);
        }*/

        printf("\n");
        while(x==' ')
        {
            printf("Generation %d: \n", gen);
            getFitness(myString, SH);
            sortByFitness(myString, SH);

            printGen(myString, SH);

            for(int i=0; i<STRINGS; i++)
            { SH[i].fitness = 0; }

            cloneTopFive(myString, SH, cloneString);
            reproduceTopTwenty(myString, SH);
            randomizeOther75(myString, SH, cloneString);
            /*getFitness(myString, SH);
            sortByFitness(myString, SH);

            for(int i=0; i<5; i++)
            {
                printf("%s has %d fitness.\n", SH[i].randString, SH[i].fitness);
            }
            printf("\n");*/

            //printf("\nInsert ' ' to continue!\n");

            //scanf("%c",&x);
            gen++;
        }   
}

【问题讨论】:

    标签: c++ optimization genetic-algorithm genetic-programming


    【解决方案1】:

    GA 收敛不佳的一个重要原因是您的适应度函数。忽略程序其他部分的潜在编码错误,您所做的只是奖励完美匹配的字母。健身景观是这样的(害怕我的 ASCII 艺术!):

    ___________ ___________ | | |_| a b c d e f G h i j k l m

    其中 G 是所需的字母。该算法不知道如何找到 G,但完全靠运气。您基本上已经实现了随机字母暴力搜索。

    使适应度函数奖励“接近”正确解,收敛速度会快得多。还可以调整种群参数、变异、交叉等。

    【讨论】:

    • “使适应度函数奖励“接近”到正确的解决方案,收敛会快得多”:不一定……这取决于你的算子是否有相同的“距离”概念.从代码来看,我不相信他们会这样做。如果将变异算子更改为从字符值中加一或减一,那么是的,这个答案是正确的。如果突变选择了一个新的随机值,那么这个答案是不正确的。 GA 很棘手!
    • 通过仔细阅读代码,我越来越相信这不会起作用。交叉从随机父等位基因中选择,突变基本上不存在(而是随机产生的底部75个个体)。没有任何机制可以对单个等位基因进行任何类型的梯度下降,因此以这种方式改变适应度函数基本上没有任何作用。我不会投反对票,因为 idea 很好,但在这种情况下,它还需要对遗传算子进行修改。
    • 我必须同意答案和评论。调整你的适应度函数以根据与原始的距离而不是仅仅采用汉明距离来奖励可能会有所帮助,尽管这意味着改变你的突变函数以少量增加或减少一个字符,而不是仅仅随机选择另一个字符。
    【解决方案2】:

    对于每个个体,算法的大部分区域(例如适应度评估)都可以独立执行。对于一些非常好的加速,我建议并行执行这些,CUDA 是一个很好的架构。

    【讨论】:

    • 我希望我知道更多能够做像 CUDA 这样的事情。我还是一个新手程序员。
    【解决方案3】:

    不幸的是,遗传算法的本质意味着有时您只需要调整参数,看看是否可以让它更快地找到解决方案。尝试克隆前 10 名、前 7 名或前 3 名。将前 20 名更改为(例如)50 名。提高或降低突变率。

    遗憾的是,我们对遗传算法的了解还不够,无法在不进行这种调整的情况下确定“正确”的参数。

    代码优化是一个完全独立的问题,它可以使每一代运行得更快,但我怀疑你遇到的问题是它需要太多代,所以我不会说这个。

    【讨论】:

    • 没错。我的意思是减少获得“完美”答案所需的代数。
    • 如果您认为答案有误,请解释。对大家都有帮助!
    【解决方案4】:

    您需要查看 GA 的参数。您的人口太少,无法进行如此简单的计算。如果不是 10 或 100K,您应该不会有任何问题将其提高到至少 1000。您只是没有足够的解决方案在池中快速收敛到一个好的结果。

    此外,您的精英主义(您为下一代克隆的候选人数量)相当高。精英主义通常不希望超过 2%。

    你也可以看看你是如何做你的交叉功能的。您通常希望对整个人口执行交叉,而不仅仅是前 20%。将所有 95 个非克隆值传递到交叉函数中,您将看到人口的更多多样性。

    正如 Cameron 所说,您的问题可能在于您的参数而不是您的代码,这是一个完全不同的问题,但这应该对您有所帮助。祝你好运!

    【讨论】:

    • 事实是,我被专门分配到了Top 20。
    • 大种群可能有所帮助,但也值得研究有关小种群进化算法的大量文献。你能引用 2% 的东西吗?这是另一个必须调整的参数。 2% 有时会起作用,0.2% 或 20% 会在其他情况下起作用。我同意“跨越一切”这一点。作为一个明目张胆的广告:看看 Skinner et al 关于使用突变来寻找新的遗传物质 :)
    • 参考资料来自最初来自赖特州立大学的 M. Peterson 和 F. Moore 博士的工作,以及我自己的 EC 研究的个人经验。这可能有点罗嗦,但值得一读 IMO。正如你所指出的,这不是一个硬性规定,它就像调整任何其他控制器一样,但我不记得我使用过的 GA 通过增加精英主义来获得积极的性能。
    • 嗯。我不熟悉他们的工作,但我没有做过很多稳态的东西。当然,在世代遗传算法中,精英主义参数的选择是高度问题并且依赖于表示(就像所有其他参数一样)。我会读一读。
    猜你喜欢
    • 2015-02-18
    • 2013-07-02
    • 2021-03-03
    • 2011-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多