您的位置:首页 > 编程语言

一个Q_learning代码的简明教程实现

2016-10-22 16:27 190 查看

Flappy Bird

在浏览机器学习相关内容的时候,看到有人通过机器学习玩转一个曾经很火的手机游戏Flappy bird。 其使用的算法是Q_learning。



算法如下:

状态矢量空间

在这里一共设计了3个参数:1,小鸟与低管道的垂直距离;2,小鸟与下一个管道出口的水平距离;3,小鸟是否死亡。

行为

对每个状态,我设计了两个可能存在的行为:点击或者是什么都不做。

奖励

奖励完全依赖于“Life”参数,仍然存活则+1,失败则-1000。

学习循环

数组Q初始化为0,同时也总采取最佳操作,这些操作将最大化我的预期奖励。

第一步,观察Flappy Bird所处的状态,并执行可以最大化预期奖励的操作。让游戏引擎执行“tick”操作,随之Flappy Bird进入下一个状态s’。

第二步,观察s’及状态下的奖励,+1则表示小鸟还活着。

第三步,通过Q Learning规则来修改Q数组。Alpha的值被设置成0.7,因为我们需要一个确定的状态,也让学习的可能最大化;同时,Y和lambda都被设置成了1。

第四步,将当前状态设置为s’并重新开始。

原文链接:Flappy Bird hack using Reinforcement Learning

译文链接:亚特兰大极客使用机器学习玩转Flappy Bird

对其所利用的Q_learning进行资料搜索,找到一个简明的教程对Q_Learning进行了介绍。

一个简明教程

具体的教程见链接A Painless Q-learning Tutorial

其解决的问题:利用无监督训练让代理找到走出房间的路线。



C++代码

#include <iostream>
#include<cstring>
#include<cmath>
#include <cstdlib>
using namespace std;

#define ROW    6
#define COLUMN 6
#define STATE_NUM 6
#define ACTION_NUM 6
#define alph 0.8
float a[100][100];
float b[100][100];
/*R(s,a),目标函数*/
float R[100][100]={{-1,-1,-1,-1,0,-1},{-1,-1,-1,0,-1,100},{-1,-1,-1,0,-1,-1},
{-1,0,0,-1,0,-1},{0,-1,-1,0,-1,100},{-1,0,-1,-1,0,100}};
/*Q(s,a),学习函数,初始化为0*/
float Q[100][100];
/*初始化的顺序*/
int initial_can_go[10];//存储可以做的action
int a_can_go[10];//存储可以做的action
int NUM=0;

/*R*/
void get_go_value(float a[100][100],int can_go[10],int state)
{
NUM=0;
for(int i=0;i<ACTION_NUM;i++)
{
if(a[state][i]>=0)
{
can_go[NUM]=i;
NUM++;
}
}
}
float get_max_value(float Q[100][100],int state)
{
float tempmax=0;
for(int i=0;i<ACTION_NUM;i++)
{
if((R[state][i]>=0)&&(Q[state][i]>tempmax))
tempmax=Q[state][i];
}
return tempmax;
}
int get_max_tab(float Q[100][100],int state)
{
float tempmax=0;
int temptab=0;
for(int i=0;i<ACTION_NUM;i++)
{
if((Q[state][i]>tempmax))
{
tempmax=Q[state][i];
temptab=i;
}
}
return temptab;
}
/*initial:初始状态*/
int learning_G(int initial, float R[100][100],float Q[100][100],int flag)
{
float Q_before,Q_new;
int a;   //是端点
float a_2;//是回报值,非端点
memset(initial_can_go,0,10*sizeof(int));
get_go_value(R,initial_can_go,initial);//返回了端点和num
a=initial_can_go[rand()%NUM];
a_2=get_max_value(Q,a);
/*initial_can_go数组存放了可以进行的动作*/
/*a为随机进行的当前action*/
/*a_2为该action下的最大反馈*/
/*被更新的是Q(initial,a)*/
Q_before=Q[initial][a];
Q[initial][a]=R[initial][a]+alph*a_2;
Q_new=Q[initial][a];

if(Q_before==Q_new) flag++;
else flag=0;
if(flag==50)     return 0;
if(Q_new == 100) initial=rand()%STATE_NUM;
else       initial=a;
cout<<"initial="<<initial<<endl;
learning_G(initial,R,Q,flag);
}

int main()
{

cout<<"****************R矩阵****************"<<endl;
for(int i=0; i<STATE_NUM; i++)
{
for(int j=0; j<ACTION_NUM; j++)
{
cout <<R[i][j]<<"\t";
}
cout<<endl;
}
cout<<"**************Q矩阵*******************"<<endl;
for(int i=0; i<STATE_NUM; i++)
{
for(int j=0; j<ACTION_NUM; j++)
{
cout <<Q[i][j]<<"\t";
}
cout<<endl;
}
int flag=0;
int initial=1;
cout<<"initial="<<initial<<endl;
learning_G(initial,R,Q,flag);
cout<<"**************shoulianjuzhen**********"<<endl;
for(int i=0; i<STATE_NUM; i++)
{
for(int j=0; j<ACTION_NUM; j++)
{
cout <<Q[i][j]<<"\t";
}
cout<<endl;
}
int position;
while(1){
cout<<"please input<<";
cin>>position;
cout<<position<<"->";
while(1)
{
int j=get_max_tab(Q,position);
cout<<j<<"->";
if(R[position][j]==100)
{
cout<<"out"<<endl;
break;
}
else
position=j;
}
}
return 0;
}


运行后得到的收敛矩阵



附:

抱歉,写的代码和注释有点乱,两个月前写的代码,现在自己都快忘了。下次有空了再整理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  机器学习