![深度强化学习实践(原书第2版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/297/40216297/b_40216297.jpg)
2.1 剖析智能体
正如上章所述,RL的世界中包含很多实体:
- 智能体:主动行动的人或物。实际上,智能体只是实现了某些策略的代码片段而已。这个策略根据观察决定每一个时间点执行什么动作。
- 环境:某些世界的模型,它在智能体外部,负责提供观察并给予奖励。而且环境会根据智能体的动作改变自己的状态。
我们来探究一下如何在简单的情景下,用Python实现它们。先定义一个环境,限定交互步数,并且不管智能体执行任何动作,它都给智能体返回随机奖励。这种场景不是很有用,却能让我们聚焦于环境和智能体类中的某些方法。先从环境开始吧:
![036-01](https://epubservercos.yuewen.com/10FB3F/20903674308617306/epubprivate/OEBPS/Images/036-01.jpg?sign=1738787319-OpkE1nxxbg2m6DWusFsTrz4kuWbnpYuX-0-b27e5ee40bb024894493842fe769eebe)
前面的代码展示了环境初始化内部状态。在示例场景下,状态就是一个计数器,记录智能体还能和环境交互的步数。
![037-01](https://epubservercos.yuewen.com/10FB3F/20903674308617306/epubprivate/OEBPS/Images/037-01.jpg?sign=1738787319-N2JDAdx9TEJnh4u8QzzEkU54xcJXvuD4-0-b0fd5b933938280683a118b0c5c342d6)
get_observation()
方法能给智能体返回当前环境的观察。它通常被实现为有关环境内部状态的某些函数。不知你是否对-> List[float]
感到好奇,它其实是Python的类型注解,是在Python 3.5版本引入的。在https://docs.python.org/3/library/typing.html的文档中可以查看更多内容。在示例中,观察向量总是0,因为环境根本就没有内部状态。
![037-02](https://epubservercos.yuewen.com/10FB3F/20903674308617306/epubprivate/OEBPS/Images/037-02.jpg?sign=1738787319-vw9cOZMcuR8dyM4OA43pIiD2mGjvS8h7-0-643bbd83e0f4ac30295aea98655cbde6)
get_action()
方法允许智能体查询自己能执行的动作集。通常,智能体能执行的动作集不会随着时间变化,但是当环境发生变化的时候,某些动作可能会变得无法执行(例如在井字棋中,不是所有的位置能都执行所有动作)。而在我们这极其简单的例子中,智能体只能执行两个动作,它们被编码成了整数0和1。
![037-03](https://epubservercos.yuewen.com/10FB3F/20903674308617306/epubprivate/OEBPS/Images/037-03.jpg?sign=1738787319-0qrYzwlMJIQK4wjc7qFscvNvdWsRPORb-0-2962b18f61cde571acf45976c69be9f4)
前面的方法给予智能体片段结束的信号。就像第1章中所述,环境–智能体的交互序列被分成一系列步骤,称为片段。片段可以是有限的,比如国际象棋,也可以是无限的,比如旅行者2号的任务(一个著名的太空探测器,发射于40年前,目前已经探索到太阳系外了)。为了囊括两种场景,环境提供了一种检测片段何时结束的方法,通知智能体它无法再继续交互了。
![037-04](https://epubservercos.yuewen.com/10FB3F/20903674308617306/epubprivate/OEBPS/Images/037-04.jpg?sign=1738787319-A5yWZu3w2yokqp8TF9o72tiDkiG5h6jQ-0-157bccc231a76530ed545aced252e40c)
action()
方法是环境的核心功能。它做两件事——处理智能体的动作以及返回该动作的奖励。在示例中,奖励是随机的,而动作被丢弃了。另外,该方法还会更新已经执行的步数,并拒绝继续执行已结束的片段。
现在该来看一下智能体的部分了,它更简单,只包含两个方法:构造函数以及在环境中执行一步的方法:
![037-05](https://epubservercos.yuewen.com/10FB3F/20903674308617306/epubprivate/OEBPS/Images/037-05.jpg?sign=1738787319-U5YNDhdu5C3axlLzAvZkTvanZXocQZn6-0-a2eff962a59175e78bf05995a262e7fb)
在构造函数中,我们初始化计数器,该计数器用来保存片段中智能体累积的总奖励:
![037-06](https://epubservercos.yuewen.com/10FB3F/20903674308617306/epubprivate/OEBPS/Images/037-06.jpg?sign=1738787319-GNu9zt8Nmsq0EQBm9kKCNT2sHdqauP4Q-0-d7116e295aa78e940448418d0cbd0f76)
step
函数接受环境实例作为参数,并允许智能体执行下列操作:
- 观察环境。
- 基于观察决定动作。
- 向环境提交动作。
- 获取当前步骤的奖励。
对于我们的例子,智能体比较愚笨,它在决定执行什么动作的时候会忽视得到的观察。取而代之的是,随机选择动作。最后还剩下胶水代码,它创建两个类并执行一次片段:
![038-01](https://epubservercos.yuewen.com/10FB3F/20903674308617306/epubprivate/OEBPS/Images/038-01.jpg?sign=1738787319-ebEHz5c5werWpDK7rudXr6JcrDLRW9So-0-809ce18cd8d7d47f9ba511c479eccc3b)
你可以在本书的GitHub库中找到上述代码,就在https://github.com/PacktPublishing/Deep-Reinforcement-Learning-Hands-On- Second-Edition的Chapter02/01_agent_anatomy.py
文件中。它没有外部依赖,只要稍微现代一点的Python版本就能运行。多次运行,智能体得到的奖励总数会是不同的。
前面那简单的代码就展示了RL模型的重要的基本概念。环境可以是极其复杂的物理模型,智能体也可以轻易地变成一个实现了最新RL算法的大型神经网络(NN),但是基本思想还是一致的——每一步,智能体都会从环境中得到观察,进行一番计算,最后选择要执行的动作。这个动作的结果就是奖励和新的观察。
你可能会问,如果基本思想是一样的,为什么还要从头开始实现呢?是否有人已经将其实现为一个通用库了?答案是肯定的,这样的框架已经存在了,但是在花时间讨论它们前,先把你的开发环境准备好吧。