强化学习之走迷宫

基于强化学习获取走迷宫知识

从开始地点,重复按分支一直走到终点,能够获得各个场所所对应的奖赏。此时,尽量学习能够获得更多的奖赏的行动知识。

基于强化学习来解决上述问题,在各个不同分支中选择一个前进,以获取行动的选择知识为目标。这里,为了学习各个分支点的行动所对应的Q值,以树的数据结构设定Q值。如下图:
在这里插入图片描述
在Q学习中,用随机数作为Q值的初始值。通过随机值对Q值的初始化,基于Q值选择行动,学习不断进行。

在行动选择中,应该优先选择Q值大的行动,但是单纯地选择最大的Q值对应的行动是无法很好地进行Q学习的。如果这样做,初始化时的随机数中偶然的大的Q值所对应的行动会一直被选中,无论重复多少次动作,这以一行动 之外的行动都不可能被选中。因此,这里需要进一步处理。

例如,可以精心设计使用随机数在某种比例下随机选择行动的方法。这一方法称为 ϵ \epsilon ϵ-贪心算法。具体而言,预先在0到1之间赋给 ϵ \epsilon ϵ一个合适的常数,在进行行动选择时,在0到1之间生成一个随机数,如果这个值比 ϵ \epsilon ϵ小,随机选择一个行动。如果这个数比 ϵ \epsilon ϵ大,选择大Q值所对应的行动。这样一来,不依赖与Q值的初始值,能够对各种各样的行动学习到合适的Q值。
在这里插入图片描述
作为行动选择的方法,除了这里的 ϵ \epsilon ϵ-贪心法,还有按评价值比例概率进行选择的轮盘选择等方法。

以上设定为基础,重复进行动作,不断进行Q学习。在动作的初始状态,Q值是随机选择的,根据前面所述的过程来反复选择行动,就能获得合适的Q值。

/************************************************************/
/*                 qlearning.c                              */
/*             强化学习之q学习                               */
/*             学习如何探索迷宫                              */ 
/***********************************************************/

/* 与Visual Studio的互换性保证 */
#define _CRT_SECURE_NO_WARNINGS

/* Include头文件 */
#include <stdio.h>
#include <stdlib.h>

/* 符号常量的定义 */
#define     GENMAX      1000    /* 学习的重复次数 */
#define     NODENO      15      /* Q值的节点数 */
#define     ALPHA       0.1     /* 学习系数 */
#define     GAMMA       0.9     /* 折扣率 */
#define     EPSILON     0.3     /* 确定行动选择的随机性 */
#define     SEED        32767   /* 随机数的种子 */

/* 函数原型声明 */
int         rand100();                    /* 返回0~100的随机函数 */
int         rand01();                     /* 返回0、1的随机函数 */
double      rand1();                      /* 返回0、1的实数的随机函数 */
void        printqvalue(int qvalue[NODENO]);        /* 输出Q值 */
int         selecta(int s, int qvalue[NODENO]);     /* 行动选择 */
int         updateq(int s, int qvalue[NODENO]);     /* 更新Q值 */

/******************************************/
/*            main()函数                  */
/******************************************/
int main(){
    int i;
    int s;  /* 状态 */
    int t;  /* 时刻 */
    int qvalue[NODENO];  /* Q值 */


    srand(SEED);  /* 随机数初始化 */

    /* Q值的初始化 */
    for(i = 0; i < NODENO; i++){
        qvalue[i] = rand100();
    }
    printqvalue(qvalue);

    /* 学习的主体 */
    for(i = 0; i < GENMAX; i++){
        s = 0;  /* 行动初始的状态 */
        for(t = 0; t < 3; t++){  /* 到最末端为止重复进行 */
        /* 行动选择 */
        s = selecta(s, qvalue);

        /* Q值的更新 */
        qvalue[s] = updateq(s, qvalue);

        }
        /* Q值的输出 */
        printqvalue(qvalue);
    }
    return 0;
}

/***********************************************/
/*         updateq() 函数                      */
/*         更新Q值                             */
/***********************************************/
int updateq(int s, int qvalue[NODENO]){
    int qv;  /* 要更新的Q值 */
    int qmax;  /* Q值的最大值 */

    /* 最某段的情形 */
    if(s > 6){
        if (s == 14)  /* 给予奖赏 */
        qv = qvalue[s] + ALPHA*(1000 - qvalue[s]);
        /* 给予奖赏的节点Q值增加 */
        /* 其他节点的Q值增加时 */
        /* 去掉下面两行的注释 */
        //  else if(s == 11)  /* 给予奖赏 */
        //  qv = qvalue[s] + ALPHA*(500 - qvalue[s]);
        else  /* 无奖赏 */
            qv = qvalue[s];
    }
    /* 最末端之外 */
    else{
        if( (qvalue[2*s + 1]) > (qvalue[2*s + 2]) )
            qmax = qvalue[2 * s + 2];
        else qmax = qvalue[2 * s + 2];
            qv = qvalue[s] + ALPHA * (GAMMA * qmax - qvalue[s]);
    }
    return qv;
}

/*************************************************/
/*                    selecta()函数              */
/*                  行动选择                     */ 
/************************************************/
int selecta(int olds, int qvalue[NODENO]){
    int s;

    if(rand1() < EPSILON){
        if(rand01() == 0) s = 2 * olds + 1;
        else s = 2 * olds + 2;
    }else{
        /* 选择Q值的最大值 */
        if( (qvalue[2 * olds + 1]) > (qvalue[2 * olds +2]) )
            s = 2 * olds + 2;
        else s = 2 * olds + 2;
    }

    return s;
}

/****************************************************/
/*         printqvalue()函数                        */
/*         输出Q值                                  */
/***************************************************/
void printqvalue(int qvalue[NODENO]){
    int i ;

    for(i = 1; i < NODENO; i++){
        print("%d\t", qvalue[i]);
    }
    print("\n");
}

/*******************************************************/
/*                     rand1()函数                     */
/*     返回0~1的实数随机数                              */
/*******************************************************/
double rand1(){
    /* 随机数的计算 */
    return (double)rand()/RAND_MAX;
}

/*********************************************************/
/*             rand01()                                  */
/* 返回0、1的随机函数                                     */
/*********************************************************/
int rand01(){
    int rnd;
    /* remove the max value of random */
    while((rnd=rand() == RAND_MAX   ));
    /* 随机数的计算 */
    return (int)((double)rnd/RAND_MAX * 2);
} 

/**********************************************************/
/*                 rand100()                              */
/*返回0~100的随机整数                                      */
/**********************************************************/
int rand100(){
    int rnd;

    /* remove the max value of random */
    while((rnd=rand()) == RAND_MAX);
    /* 随机数的计算 */
    return (int)((double)rnd / RAND_MAX * 101);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值