我是强化学习的新手。最近我学习了近似Q学习,或者称为基于特征的Q学习,这种方法通过特征来描述状态以节省空间。我尝试在一个简单的网格游戏中实现这种方法。在这个游戏中,智能体应该学会避免进入火坑(用“f”标记),并尽可能多地吃掉点点。以下是使用的网格:
…A
.f.f
.f.f
…f
这里的A表示智能体的起始位置。现在,在实现过程中,我设置了两个特征。一个是1/(到最近点点的距离的平方),另一个是(到火坑的距离)+1。当智能体进入火坑时,程序会返回-100的奖励。如果它进入已经访问过的非火坑位置(因此没有点点可吃),奖励是-50。如果它进入未访问过的点点,奖励是+500。在上面的网格中,无论初始权重是什么,程序都无法学习到正确的权重值。具体来说,在输出中,第一个训练会话获得的分数(它吃掉的点点数量)是3,但对于所有其他训练会话,分数仅为1,并且权重收敛到错误的值,即权重1(到火坑的距离)为-125,权重2(到未访问点点的距离)为25。是我代码中有什么具体问题,还是我对近似Q学习的理解有误?
我尝试调整环境给出的奖励和初始权重,但这些都没有解决问题。以下是整个程序的链接:https://repl.it/repls/WrongCheeryInterface
这是主循环中发生的情况:
while(points != NUMPOINTS){bool playerDied = false;if(!start){ if(!atFirepit()){ r = 0; if(visited[player.x][player.y] == 0){ points += 1; r += 500; }else{ r += -50; } }else{ playerDied = true; r = -100; }}//Update visitedvisited[player.x][player.y] = 1;if(!start){ //This is based off the q learning update formula pairPoint qAndA = getMaxQAndAction(); double maxQValue = qAndA.q; double sample = r; if(!playerDied && points != NUMPOINTS) sample = r + (gamma2 * maxQValue); double diff = sample - qVal; updateWeights(player, diff);}// checking end game conditionif(playerDied || points == NUMPOINTS) break;pairPoint qAndA = getMaxQAndAction();qVal = qAndA.q;int bestAction = qAndA.a;//update player and q valueplayer.x += dx[bestAction];player.y += dy[bestAction];start = false;}
我预期两个权重都应该是正值,但其中一个(给出到火坑距离的权重)是负值。
我还预期程序会随着时间的推移学会进入火坑是坏事,去未访问的点点也是坏事,但没有那么坏。
回答:
可能不是你想听到的答案,但:
-
在尝试近似Q学习之前,你有尝试过实现更简单的表格Q学习吗?在你的设置中,只有少数状态和动作,它会完美工作。如果你在学习,我强烈建议你从更简单的案例开始,以便更好地理解和直觉地掌握强化学习的工作原理。
-
你知道使用近似器而不是学习精确的Q函数会带来什么影响吗?在某些情况下,由于问题的复杂性(例如,当状态空间是连续的),你应该近似Q函数(或政策,具体取决于算法),但这可能会引入一些收敛问题。此外,在你的案例中,你试图手动选择一些特征,这通常需要对问题(即环境)和学习算法有深入的了解。
-
你理解超参数alpha和gamma的含义吗?你不能随机选择它们。有时它们对于获得预期结果至关重要,这并不总是如此,具体取决于问题和学习算法。在你的案例中,观察你的权重收敛曲线,很明显你使用的alpha值太高了。正如你指出的,在第一次训练会话之后,你的权重保持不变。
因此,实用建议如下:
-
在尝试更复杂的事情之前,确保使用表格Q学习算法解决你的网格游戏。
-
尝试不同的alpha、gamma和奖励值。
-
更深入地阅读关于近似强化学习的内容。一本非常好且易于理解的书(从零开始)是经典的Sutton和Barto的书:强化学习:引言,你可以免费获取,2018年更新过。