写在前面
最近在学油管上某大佬的自动驾驶课程,看到了强化学习部分,因此又将该大佬的其他课程也学习一下,特此记录。纯属个人学习所用,如有侵权,请联系;本人将立即处理!
Q-Learning介绍和Q表
欢迎来到强化学习教程。在这一部分,我们将关注q学习。
Q-Learning是一种无模型的机器学习形式,在某种意义上,人工智能“代理”不需要知道或拥有它将身处的环境的模型。相同的算法可以在各种环境中使用。
对于给定的环境,一切都被分解为“状态”和“操作”。状态是我们从环境中提取的观察和取样,而行为是代理根据观察做出的选择。在本教程的其余部分中,我们将使用环境的上下文来演示这是如何工作的。
虽然我们的代理实际上不需要了解关于我们环境的任何事情,但是在学习Q-learning如何工作的背景下理解它是如何工作的,这对您来说是有些有用的!
我们将与OpenAI的gym
合作,特别是与“MountainCar-v0”
环境合作。要得到gym,只需做一个pip install gym
。
好,现在让我们看看这个环境。大多数这些基本的健身房环境在工作方式上是非常相似的。要使环境初始化,你做一个gym.make(NAME)
,然后你env.rese
t环境,然后进入每个迭代执行env.step(ACTION)
的循环。让我们看看这个环境:
import gym
env = gym.make("MountainCar-v0")
print(env.action_space.n)
对于各种环境,我们可以查询它们有多少操作/移动是可能的。在本例中,我们可以通过“3”个动作。这意味着,当我们对环境执行步骤时,我们可以为每一步传递一个0、1或2作为我们的“操作”。每次我们这样做的时候,环境会返回给我们一个新的状态,一个奖励,无论环境是否完成,以及一些环境可能拥有的额外信息。
这对我们的模型来说并不重要,但是,就你的理解而言,0表示向左推,1表示不动,2表示向右推。我们不会告诉我们的模型这些,这就是Q学习的力量。这个信息基本上与它无关。模型所需要知道的是行动的选择是什么,以及执行这些行动链的回报会是什么状态。继续:
import gym
env = gym.make("MountainCar-v0")
env.reset()
done = False
while not done:
action = 2 # always go right!
env.step(action)
env.render()
正如你所看到的,尽管要求这辆车一直右转,我们可以看到,它只是没有足够的动力来做到这一点。相反,我们需要在这里建立动力来到达那面旗帜。要做到这一点,我们需要来回移动来建立动力。我们可以编写一个函数来完成这个任务,或者我们可以使用Q-learning来解决它!
Q-learning是如何做到这一点的?所以我们知道我们可以在任何时间采取3个行动。这就是我们的“行动空间”。现在,我们需要我们的“观察空间”。在这种GYM
环境中,观察结果从重置和步骤中返回。例如:
import gym
env = gym.make("MountainCar-v0")
print(env.reset())
会得到[-0.4826636 0. ]
,这是开始观察状态。当环境运行时,我们还可以得到以下信息:
import gym
env = gym.make("MountainCar-v0")
state = env.reset()
done = False
while not done:
action = 2
new_state, reward, done, _ = env.step(action)
print(reward, new_state)
在每个步骤中,我们都会得到新的状态、奖励,无论环境是否完成(我们是否超出了200步的限制),然后返回一个最终的“额外信息”,但是,在这个环境中,这个最终的返回项不被使用。Gym把它放在这里,所以我们可以在不同的环境中使用相同的强化学习程序,而不需要改变任何代码。
以上输出:
-1.0 [-0.26919024 -0.00052001]
-1.0 [-0.27043839 -0.00124815]
-1.0 [-0.2724079 -0.00196951]
-1.0 [-0.27508804 -0.00268013]
-1.0 [-0.27846408 -0.00337604]
-1.0 [-0.28251734 -0.00405326]
-1.0 [-0.28722515 -0.00470781]
-1.0 [-0.29256087 -0.00533573]
-1.0 [-0.29849394 -0.00593307]
到目前为止,奖励总是-1。然后我们观察到这两个值。
再一次,对于我们的代理,这些价值是什么…真的没关系。但是,出于好奇,这些值是位置(沿x/水平轴)和速度。例如,我们可以看到汽车向左移动,因为速度是负的。
有了一般的位置和速度,我们就可以肯定想出某种算法来计算我们是否能到达旗子,或者我们是否应该反过来建立更多的动力,所以我们希望Q学习可以做同样的事情。这两个值就是我们的“观测空间”。这个空间可以是任意大小,但是,空间越大,Q表就会变得越大!
什么是Q表!?
Q- learning的工作方式是,每个行动每个状态都有一个"Q"值。这会创建一个表。为了找出所有可能的状态,我们可以询问环境(如果它对我们很好地告诉我们)…或者我们只是简单地参与环境一段时间来弄明白。
在我们的例子中,我们可以查询环境来找出这些状态值的可能范围:
print(env.observation_space.high)
print(env.observation_space.low)
[0.6 0.07]
[-1.2 -0.07]
对于指数0处的值,我们可以看到高值为0.6,低值为-1.2,然后对于指数1处的值,高值为0.07,低值为-0.07。好的,这些是范围,但从我们输出的上述观察状态之一[-0.27508804 -0.00268013],我们可以看到这些数字可以变得非常细粒度。你能想象一个Q表的大小吗?如果我们要为这些数的每一个组合取一个小数点后8位的值?那是巨大的!更重要的是,它毫无用处。我们不需要那么细的粒度。所以,我们要做的是把这些连续的值转换成离散的值。基本上,我们希望将这些范围划分成更易于管理的范围。
我们将为每个范围使用20组/桶。稍后您可能会决定对这个变量进行调整。
DISCRETE_OS_SIZE = [20, 20]
discrete_os_win_size = (env.observation_space.high - env.observation_space.low)/DISCRETE_OS_SIZE
print(discrete_os_win_size)
[0.09 0.007]
这告诉我们每个桶有多大,基本上每个桶的范围应该增加多少。我们现在可以用以下命令构建q_table
:
import numpy as np
...
q_table = np.random.uniform(low=-2, high=0, size=(DISCRETE_OS_SIZE + [env.action_space.n]))
这是一个20x20x3的形状,它为我们初始化了随机的Q值。20x20位是所有可能状态的桶片的每一个组合。x3钻头用于我们可以采取的每一个可能的动作。
正如你可能已经看到的…即使是这个简单的环境也有一个非常大的表。我们对每一个可能的状态都有一个值!
所以这些值是随机的,在-2和0之间的选择也是一个变量。每一步都是一个-1奖励,而标志是一个0奖励,因此似乎使随机Q值的起始点都为负是有意义的。
这张Q表是我们的圣经。我们将与这张桌子协商,以决定我们的行动。最后的x3是我们的3个动作每一个动作都有与它们相关的Q值。当我们变得“贪婪”并试图“利用”我们的环境时,我们会选择这个状态中Q值最高的动作。然而,有时,尤其是在开始的时候,我们可能会转而希望“探索”并选择一个随机的行动。随着时间的推移,这些随机的动作是我们的模型更好地学习动作的方式。那么随着时间的推移,我们是如何学习的呢?我们需要更新这些Q值!如何更新Q值?
简单!
…这就是我们下一节课要讨论的内容!
原文链接:https://pythonprogramming.net/q-learning-reinforcement-learning-python-tutorial/