强化学习指的是专注于学习如何与环境交互的算法的机器学习。这种算法的一个例子叫做Q-learning。尽管它更接近于蛮力方法,Q-learning可能是最流行的强化学习方法。在我们开始学习Q-learning之前,让我们先讨论一下为什么我们不使用非监督或监督学习方法。
在一个监督学习方法中,你给算法数行数据,每一行都有一个答案,算法会尝试去适应它。这相当于给算法提供狗和猫的图片,每当我们的算法对一张照片给出错误的答案时,告诉它调整自己,以便下次看到类似的观察结果时,它更接近正确的结果。然后,我们希望,在拥有了数不清的数据行之后,或者在这个例子中,是狗或猫的图像,我们的算法能够充分“理解”这样一个问题:“这是狗的图像还是猫的图像?”“在测试阶段始终表现良好。
另一种机器学习方法是无监督学习。与有监督学习不同,无监督学习是一种数据集可能没有标记的方法,或者你有一个数据集,你怀疑在观察之间有关系,但它不明显或太复杂,难以理解。一个无监督学习模型可以识别出不同群体观察的关系。它是无监督的,因为我们不是给电脑一个答案直到它得到它为止,我们只是让电脑告诉我们它看到我们可能遗漏了什么模式对电脑来说没有正确或错误的答案。
如果你想用之前的两种方法制作一个模型来玩电子游戏,你可能会认为监督学习看起来很有前途,因为你可以给它提供游戏实例,并给出正确的步骤。这种方法存在一些问题;模特正在学习模仿最初玩这个游戏的人。此外,这个模型并没有任何end game的概念,它只知道每一步会发生什么,并且在每一步中,它会尝试去做最接近原始玩家所做的事情。
什么是强化学习
强化学习是模型玩游戏的地方,它决定哪些行动能让它更接近最终目标。在大多数情况下,这是一个比之前更好的方法因为现在我们通过学习如何玩这个游戏来训练我们的算法。在算法的游戏风格会受到观察对象的影响之前,我们大多数的想法来自于我们所设定的奖励的大小。
上面的图是我从谷歌搜索q tables中得到的一张随机图片。每一行是游戏的状态每一列是代理可以采取的动作。每个点都是一个q值。假设我们在状态0不采取任何随机行动,代理将采取行动4,因为它最大化了回报,因为所有其他列都是-1。在每一行中,代理将选择最高q的操作,然后根据该操作的成功程度调整该值,我们稍后将对此进行讨论。
从我的经验来看,这听起来可能并不容易实现,而且对于高级模型而言,从好的方面来说,这就是为什么Q-learning对于大多数人而言是第一步的原因,因为它可以通过神经扩展 网络,这是一种了解不同术语的方法,您会在以后的解释中看到很多术语。
我们自己的实现
要获得用于我们的强化学习模型的游戏,只需简单地安装好gym并导入即可。Gym是由open ai创建的python库,可帮助人们测试和学习强化学习。它使我们能够轻松地从游戏中获取模型所需的信息。
代码语言:javascript复制pip install gym
关键字
现在有一些关键字我们应该复习一下。
action:动作是模型根据其位置做出的决定
State:状态是游戏的一个实例,在这个实例中,如果当前状态没有结束游戏,模型将采取一个动作。
Reward:给我们的模型打分,帮助它理解为了打败游戏需要做哪些重要的事情。
Policy:政策是该模式当前实现其目标的总体战略。
Agent:我们用来指强化学习模型的名称。
Q-function: Q函数是一种返回得分的函数,该得分表示在状态下执行特定操作的效果如何。
公式
对于我们的模型来说,为了完成游戏,它需要正确地估计哪些行动会有最高的Qs,这样它就能始终如一地选择要采取的正确行动。如果我们的模型了解了这一点,它的政策或策略将开始产生效果。
这看起来可能不太友好但这就是我们确定新q值的方式。
“时间差异 temporal difference”部分中右侧的两个函数表示我们当前的动作q值,我们从maxQ中减去该值,后者是下一个位置的最高q值。为了这个示例,我们将结果称为NextMoveScore。
左边是我们所采取行动的奖励和折现因子之和。我们称它为评分因子。
我们还剩下两个变量。最左边是我们的旧值在它的右边是我们的学习率或者说我们想要对当前Q值进行的改进的大小。
所以在我们的缩略版中,我们可以说:
新的Q等于旧的Q加上学习速率乘以分数因子乘以NextMoveScore。
我们需要了解的另一件事是探索与利用行动。探索基本上是采取随机动作,以便我们的代理可以尝试其他方式不会采取的动作,并评估他们的q得分有多好,以查看是否需要更改策略。利用意味着代理在每个状态都采取其知道的最佳措施。
在训练模型时,需要进行一些探索,以便能够对应该做的事情有所了解,因此我们为模型提供了一个从1开始逐渐减小到每轮为零的epsilon因子。在每个回合开始时,如果它比epsilon大,我们会从0–1绘制一个随机的十进制数。如果不是,那么AI会决定去哪儿。随着时间的流逝,ai会采取随机动作,因此AI会使用越来越少的随机数,因为 ε衰变。
我们首先要做的是导入:例如:gym和numpy,告诉gym我们要在什么样的环境中训练,在我们的例子中,我们使用“Acrobot-v1”,并创建代理类来实例化代理。
代码语言:javascript复制import gym
import numpy as np
env = gym.make('Acrobot-v1')
class Ai:
def __init__(self,env):
self.DiscreteSize = [10,10,10,10,50, 100]
self.bins = (env.observation_space.high - env.observation_space.low) / self.DiscreteSize
self.LearningRate = 0.1
self.Discount = 0.95
self.Episodes = 50
self.epsilon = 1
self.startepsilondecay = 1
self.endepsilondecay = self.Episodes // 2
self.epsilondecayvalue = self.epsilon / (self.endepsilondecay - self.startepsilondecay)
self.q_table = np.random.uniform(low=-2, high=0, size=(self.DiscreteSize [env.action_space.n]))
在init方法下,我们基本上将状态截断以使其离散,因为其中一些点具有太多的唯一值,并且我们无法使计算机为每个点排一行,因为这将花费很长时间。Episodes是指您希望代理玩游戏的次数。我们还初始化Qtable,以便在每个实例中每个动作的奖励为-2。
代码语言:javascript复制def get_discrete_state(self,state):
discrete_state = (state - env.observation_space.low) / self.bins
discrete_state= tuple(discrete_state.astype(np.int))
return discrete_state
这是一个将非离散连续状态变为离散状态的函数。
代码语言:javascript复制def move(self):
if np.random.random() > self.epsilon:
self.action = np.argmax(self.q_table[self.discrete_state])
else:
self.action = np.random.randint(0, env.action_space.n)
self.new_state, self.reward, done, _ = env.step(self.action)
self.new_discrete_state = self.get_discrete_state(self.new_state)
return done
这是移动函数。if-else的第一部分是当抽取的随机数大于时的正常移动,所以agent正常移动。其他的情况是,所画的随机数小于,所以agent随机移动。然后我们保存新的状态信息并使其离散。我们返回done,这样稍后运行剧集的while循环就会知道Episodes是否已经完成。
代码语言:javascript复制def newq(self):
self.max_future_q = np.max(self.q_table[self.new_discrete_state])
self.current_q = self.q_table[self.discrete_state (self.action,)]
self.new_q = (1 - self.LearningRate) * self.current_q self.LearningRate * (self.reward self.Discount * self.max_future_q)
self.q_table[self.discrete_state (self.action,)] = self.new_q
self.discrete_state = self.new_discrete_state
newq用来计算新的q,它遵循我们之前讲过的公式只是分解成小块
代码语言:javascript复制def epsilondecay(self):
if self.endepsilondecay >= episode >= self.startepsilondecay:
self.epsilon -= self.epsilondecayvalue
最后,Ai类的最后一种方法是epsilon衰减方法。
代码语言:javascript复制qlearner = Ai(env)
qlearner.discrete_state = qlearner.get_discrete_state(env.reset())
done = False
showEvery = 1
所以现在我们可以调用Ai类并传入之前在导入下实例化的环境。reset()重新启动环境,我们确保使用了get discrete state方法。
代码语言:javascript复制for episode in range(qlearner.Episodes):
qlearner.discrete_state= qlearner.get_discrete_state(env.reset()) done = False
if episode % showEvery == 0:
render = True
else:
render = False
while not done:
done = qlearner.move()
if render == True:
env.render()
if not done:
qlearner.newq()
qlearner.epsilondecay()
env.close()
print('final:',qlearner.score)#action to take in each state
这个块运行代理的训练。第一个for循环启动一集if-else,之后是渲染或不渲染游戏的图形表示,设置为0会更快,但你可能想看看你的代理是如何做的。while循环的基本意思是,当游戏还没有完成时,再走一步并更新q表。在每一episode之后,我们会对epsilon进行一些衰减,以稍微改变我们的代理从探索到利用。
最后本文的完整代码:https://pythonprogramming.net/q-learning-algorithm-reinforcement-learning-python-tutorial/
作者:Amir Edris
deephub翻译组