作业4: PacMan游戏 实验报告
吴政亿 151220129 wuzy.nju@gmail.com
(南京大学 计算机科学与技术系, 南京 210093)
摘要:使用强化学习来自主玩Mr. PACMAN游戏。通过强化学习,得到Q值函数,并根据Q值函数进行决策。理解并深入研究使用的强化算法,并尝试修改程序来提高学习性能。其中,理解epsilon greedy策略与折扣累计奖赏的含义
关键词:强化学习、Q值函数、epsilon greedy、折扣累计奖赏
一、框架代码理解
1. 策略模型
策略模型用 Q-learning 模型表示。步骤如下:
1. 外循环模拟次数num_episodes(框架代码为10)
2. 内循环每次模拟最大步数num_steps(框架代码为SIMULATION_DEPTH=20)
3. 根据当前的state和q-table选择action(框架代码epsilon greedy探索概率为0.3)
4. 根据当前的state和action获得下一步的state和reward
5. 更新q-table: Q[s,a] = Q[s,a] + lr*(r + y*np.max(Q[s1,:]) - Q[s,a])
缺点是 Q-learning 使用最佳 Q 值,它不关心遵循的实际策略,是一个脱离策略的学习算法。可以改为 SARSA 方法,在采取实际行动后再回传Q 值,当发生探索时 SARSA 是个依附策略。
SARSA 的思想很简单,就是增加一个 A ,下一步的 A ,然后据此来估计 Q 值。
另外, Q-Leaning 可能会出现对 Q 值过度估计的问题, Double Q-leaning 可以解决这个问题,使用两个 Q 交替更新。
2. Agent
(1) SIMULATION_DEPTH
在框架代码中, SIMULATION_DEPTH 用来确定模拟的最大深度,防止时间消耗过多,但又能达到一个较高的精度。它初始化为20,代表每次策略评估时,折扣累计奖赏的迭代次数为20次。在 simulate 函数中,它尝试在当前局面下走 SIMULATION_DEPTH 步,然后计算最后状态的预测 Q 值与累计奖赏值。
(2) m_gamma
m_gamma 是折扣累计奖赏的参数
γ
γ
(收益衰减系数),对于
γ
γ
折扣累计奖赏,计算公式为:
可见一直执行到最后,越往后奖赏权重越低,在框架代码中, m_gamma=0.99 m _ g a m m a = 0.99
(3) m_maxPoolSize
框架代码中, m_maxPoolSize=1000 m _ m a x P o o l S i z e = 1000 ,代表在应用 weka 强化学习中,限制最大的 data 数为1000.
m_dataset.randomize(m_rnd);
for (int i = 0; i < dataset.numInstances(); i++) {
m_dataset.add(dataset.instance(i)); // add to the last
}
while (m_dataset.numInstances() > m_maxPoolSize) {
m_dataset.delete(0);
}
在更新数据集时,如果数据集个数超过最大限制 data 数,就把最前面的 data 删掉。
3. QPolicy
对于getAction 和 getActionNoExplore 两个函数的区别,主要就在于是否应用epsilon greedy策略。首先先简要浅析二者代码==相同部分==。
int bestaction = 0;
for(int action=1; action<m_numActions; action++){
if( Q[bestaction] < Q[action] ){
bestaction = action;
}
}
首先遍历Q值,得到其中最佳动作。
int sameactions =0;
for(int action=bestaction+1; action<m_numActions; action++){
if(Q[bestaction] == Q[action]){
sameactions++;
if( m_rnd.nextDouble() < 1.0/(double)sameactions )
bestaction = action;
}
}
然后寻找所有与best action的Q值相同的动作。由于先前的遍历决定了这个best action一定是相同Q值动作序列的第一个,所以从best action的下一个开始遍历,如果发现Q值相同的动作,就以 1n 1 n 的概率替换掉先前的best action。其中 n n 为遍历中发现best action的数量。
接下来则是二者代码==不同部分==。
protected double m_epsilon=0.3;
...
if( m_rnd.nextDouble() < m_epsilon ){
bestaction = m_rnd.nextInt(m_numActions);
}
getActionNoExplore 比 getAction 多了一个 epsilon greedy 的步骤,可见,框架代码中设置了一个执行探索的概率 ,每次 action 他都会以 0.3 0.3 的概率执行探索操作(随机选择一个工作),以 0.7 0.7 的概率执行利用操作(选择一个得分最好的动作)。
epsilon greedy 基于一个概率 m_epsilon 来对探索和利用进行折中,相比之下, getActionNoExplore 更加容易陷入局部最优解里,而 getAction 相比之下多了一部分随机性,可以尽可能的实现最大化收益。对于 m_epsilon 的选择,当不确定性较大,例如概率分布较宽时,则需要更多的探索,此时需要较大的 m_epsilon;若不确定性较小,例如概率分布较集中时,则少量的尝试就可以很好地近似真实奖赏,此时需要的 m_epsilon 较小;并且在后期这个值下降可以令模型更快收敛得到相应最优解,例如令 m_epsilon=1/t√ m _ e p s i l o n = 1 / t 。
二、特征提取
在特征提取中,原有的许多位置都是无效的,我选择了
- NPC 到最近的幽灵的曼哈顿距离
- 各个幽灵的位置
- 蘑菇的位置
- 钻石的位置
- 水果的位置
- 各个幽灵的方位
public static double[] featureExtract(StateObservation obs) {
double[] feature = new double[s_datasetHeader.numAttributes()];
if (obs.getImmovablePositions() != null) {
for (ArrayList<Observation> l : obs.getImmovablePositions()) {
if (l.size() == 0)
continue;
// pellets
else if (l.get(0).itype == 4) {
feature[0] = nearestDir(obs, l);
}
// fruit
else if (l.get(0).itype == 3) {
feature[1] = nearestDir(obs, l);
}
}
}
// 4 ghosts
ArrayList<Observation> allGhost = new ArrayList<>();
if (obs.getPortalsPositions() != null) {
for (ArrayList<Observation> l : obs.getPortalsPositions()) {
allGhost.addAll(l);
}
}
feature[2] = nearestDir(obs, allGhost);
// isNearGhost
feature[5] = isNearGhost(obs, allGhost) ? 1 : 0;
// 4 powerpills
if (obs.getResourcesPositions() != null) {
for (ArrayList<Observation> l : obs.getResourcesPositions()) {
feature[3] = nearestDir(obs, l);
}
}
// 4 ghost direct
Vector2d avatarPos = obs.getAvatarPosition();
int i = 6;
for (Observation o : allGhost) {
double delta_x = o.position.x - avatarPos.x;
double delta_y = o.position.y - avatarPos.y;
double dist = o.position.dist(avatarPos);
feature[i] = Math.acos(delta_x / dist) + (delta_y < 0 ? Math.PI : 0);
i++;
}
return feature;
}
在提取了上述特征后,分数得到提升,但是仍然上下波动。
三、强化学习参数调整
根据一系列可靠实验数据结果表明,当 m_epsilon 上调,并且相应降低 m_gamma 的比例会有着较为不错的效果。但是分数仍会上下波动,需要多次学习后才能稳定下来。
下面的分数均为大量重复实验后的平均分,默认关卡。
探索概率 | 0.2 | 0.4 | 0.6 | 0.8 |
---|---|---|---|---|
分数 | 80 | 90 | 120 | 130 |
可以发现随着探索概率上升,随有波动,但是更容易得到一个相对更优的解。因为该模型已知状态空间等信息,可以更为准确的得到当前局势情况,另外概率分布较宽。
SIMULATION_DEPTH | 10 | 20 | 30 |
---|---|---|---|
分数 | 130 | 110 | 162 |
由于电脑性能,并未再继续增加 SIMULATION_DEPTH 大小,理论上随着 SIMULATION_DEPTH 则规模大,分数会有些许提高,得到这个结果也许是因为实验样本较少。
γ γ | 0.2 | 0.4 | 0.6 | 0.8 | 0.9 | 0.99 |
---|---|---|---|---|---|---|
分数 | 143 | 155 | 169 | 138 | 125 | 90 |
γ γ 代表未来局势分数对当前步骤的奖赏分数,可以发现分数先上升,然后在 0.6 附近达到峰值,随后再下降。
四、实验总结
在本次试验中,我意识到了特征提取与奖赏函数的重要性。同时调参的过程中也让我意识到了众多参数带来的影响,更加深刻的理解了强化学习的步骤与作用。