那么本篇的强化学习方法适用于哪一种呢? 这其实不大好说。。 我没有能互动的环境,只有静态数据集,所以 off-Policy 看上去更适合一些,但即使是 off-policy 的方法通常也需要与环境进行交互不断产生新数据用于训练。因此本篇的方法属于 batch reinforcement learning,或称 offline reinforcement learning,不过我倾向于使用 batch 这个词,因为 offline 和 off-policy 很容易混淆。上右图显示的就是 batch (offline) reinforcement learning,其特点是一次性收集完一批数据后就只用这批数据进行训练,在正式部署之前不再与环境作任何交互。
我们知道深度学习近年来在图像和 NLP 领域取得了很大的进展,一大原因是算力和数据的爆炸式增长。然而对于主流的深度强化学习算法来说,需要不断与环境进行交互来获取数据,这通常意味着需要边训练边收集数据。然而许多领域是无法像传统强化学习那样有条件频繁与环境进行交互的,存在成本太高或者安全性太低的原因,甚至会引发伦理问题,典型的例子如无人驾驶和医疗。所以这时候人们自然会去想,训练强化学习时也收集一堆固定的数据,然后不断重复利用,不再收集新的,仿照深度学习那样在固定数据集上大力出奇迹,这样是否可行呢? 因此 batch reinforcement learning 近年来受到越来越多学术界和工业界的关注,被广泛认为是实现强化学习大规模应用到实际的一个有效途径。而推荐系统就很适合这种模式,因为直接线上探索交互代价太大,影响用户体验,但收集用户行为日志却相对容易且数据量大。
另一方面,推荐系统作为一个系统,光有算法肯定是不行的。上文提到 batch reinforcement learning 无需与环境互动,仅靠数据集就能训练,那么在训练完模型真正上线以后就需要与环境交互了,而这个过程中需要有中间载体,用于快速获得信息、清洗原始数据并转化成模型可输入的格式。在本篇中这个前道工序我们主要使用 Flink。Flink 官网上的自我介绍是 ”数据流上的有状态计算 (Stateful Computations over Data Streams)“:
换言之随着数据的不断流入,其可以保存和访问之前的数据和中间结果,当到达特定的条件后一并计算。对于我们的强化学习模型来说,需要累计一定的用户行为才能作为模型输入作推荐,所以需要在 Flink 中实时保存之前的行为数据,这就要用到 Flink 强大的状态管理功能。
这里有一点值得注意,Flink 由于数据源延迟的关系严格意义上很难做到实时,但可以做到近实时。 实际上从心理学的角度来看,太过实时的推荐反应可能会引起用户反感 (仅个人观点)。所谓物极必反,用户可能觉得自己的隐私被侵犯了进而导致恐慌 (怎么这个视频我就点进去看了 3 秒钟,你就能给我推荐一大堆同类的?),或者觉得自己的自由选择被系统操控了 (我刚看了个单反,还没想买呢,你就给我推荐一大堆别的型号的,是一定要我买吗?) 。从理性的角度来看用户最终可能也会理解这些推荐结果,不会觉得有什么太大的问题,只不过推荐的场景不像是一般工作场景,人往往处于比较放松的时刻,比如刷短视频、新闻、购物、音乐推荐等等。这样的时刻大概率是非理性的源泉,否则也就不会有什么双11,618了,而推荐系统作为整个商业系统的重要一环需要将各种因素考虑在内。所以用 Flink 做到近实时就算是比较折衷的方案了。
另外,离线训练使用的深度学习框架是 PyTorch,这个不像 Tensorflow 那样部署方便,所以这里采用近年来流行的 FastAPI 做成 api 服务,在 Flink 中获取满足条件的特征后直接调用服务进行推理,产生推荐后存到数据库中,服务器在下次用户请求时可直接从数据库中调用推荐结果。
整体架构见下图, 完整代码和流程见 FlinkRL (https://github.com/massquantity/flink-reinforcement-learning) 和 DBRL (https://github.com/massquantity/DBRL) 。
下面介绍使用的三种算法,限于篇幅,这里仅仅大致介绍原理,欲了解细节可参阅原论文。下面是主要符号表:
\(s \in \mathcal{S} \;\qquad\qquad\) 状态 (state)
\(a \in \mathcal{A} \qquad\qquad\) 动作 (action)
\(r \in \mathcal{R} \,\qquad\qquad\) 奖励 (reward)