利用面向切面编程技术记录深度强化学习代理数据
探讨如何通过面向切面编程技术优化游戏开发中的数据收集与分析流程,提升深度强化学习代理在游戏测试中的效率与准确性
在游戏开发过程中,玩家测试是一个至关重要的环节。它不仅能帮助发现游戏中的bug,评估用户体验,平衡游戏难度,更能评估游戏的趣味性。正是在这个过程中,开发者能够判断游戏设计的优劣,并发现需要修正的缺陷。然而,玩家测试往往是一个耗时且重复的过程,目前缺乏能够自动化部分测试流程的可靠工具。PEAK项目旨在解决这一问题,但并非替代人类测试者,而是通过集成深度强化学习(DRL)代理的游戏引擎,使设计师能够在任何阶段派遣代理进行测试。 PEAK项目的开发者包括Cristiano Politowski、Al Shifan和Kevin Chua,他们来自安大略科技大学。
我加入该项目的时间较晚。目前,PEAK仅支持2D平台游戏,甚至可能扩展到类似Metroidvania的游戏,因为它们在设计上有许多相似之处。虽然未来可以扩展到其他类型的游戏,但目前2D平台游戏作为概念验证的范围已经足够。 在该项目中,我的主要职责是数据收集、聚合和可视化。具体来说,就是负责代理在游戏过程中收集数据,并利用这些数据评估游戏的平衡性。例如,如果跳跃次数是评估标准之一,我可以简单地添加一个tracked_jumps变量,并在跳跃方法中添加相应的处理逻辑。
然而,由于项目的特殊性,这个过程并不简单。首先,这是一个尚未成熟的项目,在我的工作初期,它经历了两次重大重构。其次,这是一个支持多种游戏的引擎,但缺乏将它们联系在一起的架构,因此数据收集方式必须独立于任何特定游戏。否则,我们将面临大量重复的代码。最后,添加新的数据跟踪和处理功能应尽量减少对代码库的修改,以避免核心游戏代码和数据收集代码混杂在一起。 直接添加变量违反了所有这些要求。
为了解决这个问题,我采用了观察者模式和面向切面编程(AOP)。在项目初期,我并不知道自己在使用AOP,直到教授在一次会议上指出这一点。AOP中的切面是指我们希望添加到代码中的功能,但不能直接添加到代码中,否则会导致多个职责混杂在同一个模块中。对于这个项目来说,我们想要收集和处理的数据就是切面。在AOP中,我们可以指定项目中需要添加切面的部分,这个指定称为切入点,而代码中可以应用切面的点称为连接点。开发者只需要关注AOP中什么时候运行、如何运行以及如何指定连接点。
AOP的经典例子是日志记录。你不希望这些日志出现在核心文件中,否则会违反单一职责原则或者导致高耦合。Python 2.4引入了一个非常酷的特性,即可以通过注解定义方法的包装器,从而只需在目标方法上添加注解即可应用包装器。例如,绿色箭头指向原始函数,红色箭头指向装饰器,橙色箭头指向注解。通过这种简单的定义,我们可以通过注解来定义在函数调用之前和之后要执行的操作。 我使用装饰器的方式如下:首先,我创建了一个名为stats_observer的类,该类包含数据感兴趣的变量,并为每个变量定义了一个记录方法,以确定如何记录它们(是简单的递增还是需要进行其他检查)。
然后,我定义了一个通用的track装饰器,该装饰器接受记录方法的名称作为参数,并通过反射在被注解的方法调用之后调用该方法。因此,你只需要在stats_observer中定义record_something,并在需要跟踪该something的方法上添加@track("something")即可。 虽然装饰器很方便,但它们仍然需要编辑核心游戏文件。我无法接受这一点。因此,我决定使用YAML文件通过反射将记录方法注入到游戏中感兴趣的方法中。例如,如果你想跟踪代理执行的跳跃次数,你只需要在YAML文件中将目标设置为start_jump方法,将记录器设置为record_jump方法即可,这样你就可以在跳跃方法上设置一个观察者。
这是YAML文件的一个示例,挑战在于找到你想要记录的方法。 我创建了一个简单的图表来展示所有组件如何协同工作。使用我收集的示例数据,我创建了一个简单的Streamlit仪表板,这应该类似于设计师在运行代理时看到的内容。当然,目前这并不太有用,因为它并没有提供有价值的信息,但这是一个开始。 我们正在定义实际上有用的数据,并研究设计师如何定义阈值。阈值定义的一个想法是另一个配置文件,其中设计师指定目标人群(即代理行为和技能)、所需的最大值和最小值,以及可能需要代理之间的间隙。
这是一个可能的外观。对于指标,我们与Claude一起进行了头脑风暴,参考了《游戏设计艺术》一书,以制定设计师可能实际发现有用的案例指标。我们得出了该指标列表及收集这些指标的挑战: 完成率:完成关卡需要多少次尝试。 平均完成时间:成功运行的平均时间。 进度:在每次尝试中代理何时死亡? 死亡聚类:死亡分布有多广?这具有挑战性,因为我们不知道如何衡量这一点。 代理采取的不同路径数量:这具有挑战性,因为我们不知道如何指定这一点。
硬币时间成本:收集硬币的运行时间与直接前往目标的运行时间之间的差异。 我们将看到结果如何。我们仍然不确定设计师会发现这个工具有多么有用和易于使用,但这就是我们实验的原因。 。