第一次听到
“增强学习”(Reinforcement Learning)
的时候,我以为只是在“深度学习”的基础上又玩儿的新花样。后来稍微了解了一下,发现其实是完全不同的概念,当然它们并非互斥,反而可以组合,于是又有了
“深度增强学习”(Deep Reinforcement Learning)。
目前很少有用C语言去写一个强化学习的,我认为在嵌入式以及无线传感网络中强化学习也是很有用处的,因此本小编用C语言写了一个强化学习的Demo,供广大网友参考。----QQ:644250062.
这里我们采用2*2 的用例,方便大家的学习和借鉴。
这里的方格,就是Environment。虽然对于电脑前的我们,似乎很容易,但是对Agent来说,他尚且对力量一无所知的。不过,只要Agent知道生命的可贵(Reward),就可以训练出一个Policy。
游戏的目的是让分数最大化,比如踩到陷阱了,-10
。拿到宝贝了,+10
。同样是最终拿到了宝贝,我们希望的是最短路径,那么如果走了多余的路,就要 -1
。
Q-Learning的目的就是学习特定State
下、特定Action
的价值。Q并不是某个本质骑士取的字母,而是表示Quality。
Q-Learning的方法是建立一个表,以state
为行、action
为列。迷宫共有4个格,每个格子都有5个方向,所以Q-table就是4x5的一个表,对应总共20种可能的决策。
首先以0填充Q-table进行初始化,然后观察每一个决策带来的回馈,再更新Q-table。更新的依据是Bellman Equation:
Q(s,a)=r+γ(max(Q(s′,a′))Q(s,a)=r+γ(max(Q(s′,a′))
- s: 当前状态state
- a: 从当前状态下,采取的行动action
- s': 今次行动所产生的新一轮state
- a': 次回action
- r: 本次行动的奖励reward
- γγ : 折扣因数,表示牺牲当前收益,换区长远收益的程度。
那么最关键的问题是:如何计算Q?
Agent所做的每一轮决策(即一盘游戏),称为一个episode,跟美剧里的“集”单位一样。每一次行动,都会更新Q-table。
算法的基本流程:
- 初始化Q-table矩阵
- 选择起始state
- 选择当前state(s)下的一个可能action(a)
- 换移到下一个state(s')
- 重复第3步
- 使用Bellman Equation,更新Q-table
- 将下一个state作为当前state
- 如此迭代三十年,直到大厦崩塌
比如,从state-1开始,可能的action有D, R, N。然后我们选择了D,到了state-3,这个state踩中了陷阱,所以-10。
在state-3又有三种可能的action:U, R, N。 又因为此时Q-table还没有经过更新,所以max(Q(s′,a′)max(Q(s′,a′)当然就是0。假设折扣因数γ=0.7γ=0.7,则有:
Q(1,D)=R(1,D)+0.8×0=−10Q(1,D)=R(1,D)+0.8×0=−10
第一次更新Q-table的结果是:
|
|
|
|
|
|
|
U |
D |
L |
R |
N |
1 |
0 |
-10 |
0 |
0 |
0 |
2 |
0 |
0 |
0 |
0 |
0 |
3 |
0 |
0 |
0 |
0 |
0 |
4 |
0 |
0 |
0 |
0 |
0 |
现在,我们来到了state-3,如果选择R,就到达了state-4,+10。再次更新Q-table为:
|
|
|
|
|
|
|
U |
D |
L |
R |
N |
1 |
0 |
-10 |
0 |
0 |
0 |
2 |
0 |
0 |
0 |
0 |
0 |
3 |
0 |
0 |
0 |
+10 |
0 |
4 |
0 |
0 |
0 |
0 |
0 |
上面是某位大神的案例 我借用过来,下面就是我介绍的C语言版本的demo。
#include
#include
#include
const double lr = 0.7;
int reward[4][5]={{0,-10,0,-1,-1},{0,10,-1,0,-1},{-1,0,0,10,-1},{-1,0,-10,0,10}};
double q_matrix[4][5] = {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}};
int transition_matrix[4][5]= {{-1,2,-1,1,1},{-1,3,0,-1,2},{0,-1,-1,3,3},{1,-1,2,-1,4}};
int valid_actions[4][3] = {{1,3,4},{1,2,4},{0,3,4},{0,2,4}};
int choice(int arr[])
{
srand(time(NULL));
int seed = rand()%3;
int i = 0;
return arr[seed];
}
double max(double arr[])
{
int i;
double max = -10000.0;
for(i = 0; i < 3;i++)
{
if(max < arr[i])
{
max = arr[i];
}
}
return max;
}
int main()
{
int i=0;
for(i = 0;i < 1000;i++)
{
int start_state = 0;
int current_state = start_state;
while(current_state!=3)
{
int action = choice(valid_actions[current_state]);
int next_state = transition_matrix[current_state][action];
int future[3]={0};
double future_rewards[3]={0};
int action_nxt;
int action_next_next;
for(action_nxt = 0; action_nxt < 3;action_nxt++)
{
future[action_nxt] = valid_actions[next_state][action_nxt];
}
for(action_next_next = 0;action_next_next < 3;action_next_next++)
{
future_rewards[action_next_next] = q_matrix[next_state][action_nxt];
}
double q_state = reward[current_state][action] + lr * max(future_rewards);
q_matrix[current_state][action] = q_state;
current_state = next_state;
}
}
int q_i,q_j;
for(q_i = 0;q_i < 4;q_i++)
{
for(q_j = 0;q_j < 5;q_j++)
{
printf("%f.2",q_matrix[q_i][q_j]);
}
printf("\n");
}
return 0;
}