我正在一个项目中,我试图教一辆车如何通过Python中的Q学习进行驾驶。但是我有一个问题,那就是汽车似乎永远都不会学任何东西(即使在1000000集之后) 由于我真的不知道问题出在哪里,因此我发布了大多数代码(我认为可能与问题有关)。
目前,我有一个Car类和一个Game类作为我的项目结构。该游戏是使用PyGame构建的,基本上是 具有固定像素大小为16px的网格。为了更快地学习,我们制作了一个简单的Collison矩阵来节省运行时间,而不是使用Sprite Collions。 我还实施了各种奖励制度,以鼓励汽车向特定方向行驶,如下所示。 (面包屑和奖励汽车长时间不在同一位置)
要注意的一件事是,汽车的移动方式是这样实现的,即它不会锁定在网格上(以实现平稳的移动)。但是,通过将汽车位置除以网格尺寸,可以将汽车的位置映射到网格。
我使用的q表的大小与此网格相同,每个图块上的可能移动量如下:
for x in range(0, int(GRIDWIDTH)+1):
for y in range(0, int(GRIDHEIGHT)+1):
q_table[(y,x)] = [np.random.uniform(-5, 0) for i in range(NUMBER_OF_ACTIONS)]
在我改变了NUMBER_OF_ACTIONS的情况下,只允许汽车以恒定的速度向前行驶。但同时也要让Car向前迈进。 **值得注意的是,在使用用户输入时,所有这些操作均按预期进行。 Car类中的动作函数是这样写的:
def action(self, choice):
self.rot_speed = 0
if choice == 0:
#self.move(x=1, y=0)
self.rot_speed = PLAYER_ROT_SPEED
self.rot = (self.rot + self.rot_speed * self.game.dt)
elif choice == 1:
#self.move(x=-1, y=0)
self.rot_speed = -PLAYER_ROT_SPEED
self.rot = (self.rot + self.rot_speed * self.game.dt)
elif choice == 2:
self.vel = vec(PLAYER_SPEED, 0).rotate(-self.rot + ROTATE_SPRITE_DEG)
If NUMBER_OF_ACTIONS == 2
self.vel = vec(PLAYER_SPEED, 0).rotate(-self.rot + ROTATE_SPRITE_DEG)
self.pos += self.vel * self.game.dt
Q学习算法如下(不是每个情节都被循环调用)。
def qLearning(self):
#Random Starting Positons on EVERY EPISODE
StartingPositions = self.playerPositions[np.random.randint(0,len(self.playerPositions))]
self.player = Player(self, StartingPosition[0] * TILESIZE , StartingPosition[1] * TILESIZE)
food = self.goal
episode_reward = 0
#RESET BREADCRUMBS FOR EVERY EPISODE
for bread in range(len(self.breadCrumb_array)):
self.wallPositions[self.breadCrumb_array[bread][0]][self.breadCrumb_array[bread][1]] = 3
self.breadCrumb_array = []
self.lastPosition = self.player.posToTile
self.update()
self.dt = 0.1
for i in range(ITERATIONS):
obs = (int(self.player.posToTile.x), int(self.player.posToTile.y))
if np.random.random() > self.epsilon:
action = np.argmax(self.q_table[obs])
else:
action = np.random.randint(0, NUMBER_OF_ACTIONS)
self.player.action(action)
self.update()
if not LEARNING:
self.draw()
if(self.wallPositions[int(self.player.posToTile.x)][int(self.player.posToTile.y)] == 1):
self.player.hitWall = True
elif(self.wallPositions[int(self.player.posToTile.x)][int(self.player.posToTile.y)] == 2):
self.player.hitGoal = True
elif (self.wallPositions[int(self.player.posToTile.x)][int(self.player.posToTile.y)] == 3):
self.wallPositions[int(self.player.posToTile.x)][int(self.player.posToTile.y)] = 0
self.breadCrumb_array.append((int(self.player.posToTile.x),int(self.player.posToTile.y)))
self.player.hitReward = True
if self.player.hitWall:
reward = -DEATH_PENALTY
elif self.player.hitGoal:
reward = FOOD_REWARD
elif self.player.hitReward:
reward = BREADCRUMB_REWARD
self.player.hitReward = False
else:
reward = -MOVE_PENALTY #+ self.distanceTo((player.pos), food)
if i % 100 == 0 and not i == 0 and not reward == -DEATH_PENALTY or reward == FOOD_REWARD:
# Checks how far the distance is between the last position and current.
distance = self.distanceTo(self.lastPosition, self.player.posToTile)
self.lastPosition = self.player.posToTile
if (distance > RADIUS):
if (distance <= 5):
reward += distance
else:
reward += 5
new_obs = (int(self.player.posToTile.x), int(self.player.posToTile.y))
max_future_q = np.max(self.q_table[new_obs])
current_q = self.q_table[obs][action]
if reward == FOOD_REWARD:
new_q = FOOD_REWARD
elif reward == -DEATH_PENALTY:
new_q = -DEATH_PENALTY
else:
new_q = (1 - LEARNING_RATE) * current_q + LEARNING_RATE * (reward + DISCOUNT * max_future_q)
self.q_table[obs][(action)] = new_q
episode_reward += reward
if reward == FOOD_REWARD or reward == -DEATH_PENALTY:
break
#For plotting later
self.episode_rewards.append(episode_reward)
self.epsilon *= EPS_DECAY
在运行q学习时,我尝试将所有的常量更改为不同的值以获得更好的结果,但是,结果似乎 保持不变,即不学习任何东西。一整夜,我尝试使用以下常量,
ITERATIONS = 5000
HM_EPISODES = 1000000
MOVE_PENALTY = 1
DEATH_PENALTY = ITERATIONS * 2
FOOD_REWARD = ITERATIONS
RADIUS = 10
BREADCRUMB_REWARD = 300
EPS_DECAY = (1 - 1/(HM_EPISODES))
LEARNING_RATE = 0.8
DISCOUNT = 0.95
EPSILON_START = 1
但是,如下图所示,即使Epilon正在衰减(几乎达到0),平均结果也永远不会变好(甚至更差)。
到目前为止,尽管有各种奖励系统,但我还尝试使用射线投射,具体取决于汽车与墙壁的距离,该迭代的奖励会受到影响,但是此实现似乎并没有任何区别。因此,由于使用Sprite冲突的计算时间很长,我不再使用该代码。
因此,既然看起来我已经尝试了一切,但无论如何都没有成功,所以我希望也许你们中的任何人都可以看到我的问题所在。
预先感谢您,希望我能提供有关此问题的足够信息。
编辑POST :由于发布了此问题,因此已解决。为了使代理程序正常工作,我将机芯的运动方式从“类似于汽车”更改为方块运动。这使代理能够正确学习。所以如果有人 遇到同样的问题,看看您的动作或环境,看看它是否太复杂。