不久前,我探讨了通过操纵模型代码的Python抽象语法树(AST)来简化1 PyMC4的模型规范API 的可能性。PyMC开发人员最终并没有进一步追求这些API更改,但是直到我有机会学习有关Python AST的很多知识之后,PyMC的开发人员才继续追求这些API更改。
好奇的人问我有关AST的经验,我认为我会写一篇关于项目细节的简短文章,希望其他人会发现它有用。
您应该阅读此博客文章,以快速了解我在Python AST中的使用经验或链接的带注释列表,而不是有关模型规范API或Python AST的全面教程。有关我使用Python AST进行的冒险的完整论文记录,请在GitHub上查看我的笔记本。
问题固定链接
最初,PyMC4提出的模型规范API如下所示:
该API的主要缺点是yield关键字令人困惑。许多用户并不真正理解Python生成器,而那些真正理解Python生成器的用户可能只是将其理解 yield为对return它们的直接替代(也就是说,他们可能了解函数以结尾结尾的含义yield foo,但会对感到不舒服bar = yield foo)。
此外,该yield关键字引入了泄漏抽象2:用户不必关心模型是函数还是生成器,也不必关心。更一般而言,用户不必了解有关PyMC的使用方式的任何知识:理想情况下,用户唯一需要考虑的就是他们的数据和模型。在这方面,必须将多个yield关键字嫁接到其代码中是一个很大的入侵。
最终,该模型规范API实质上将问题从我们的版块转移到了用户身上。PyMC项目的重点是为贝叶斯建模提供一个友好且易于使用的界面。
为了进一步列举问题,我们希望:
yield从面向用户的模型规范API中隐藏关键字。
获取用户定义的模型作为生成器。
第一个目标的主要困难在于,一旦我们yield从模型函数中删除,它便不再是生成器。但是,PyMC推理引擎需要将模型作为生成器,因为这使我们可以在各个点中断模型的控制流以执行某些操作:
管理随机变量名称。
执行采样。
我真的不熟悉的其他任意PyMC魔术。
简而言之,用户将他们的模型编写为一个函数,但是我们要求模型作为生成器。
我认为为什么这个问题在这里更具挑战性 。
解决方案固定链接
首先,我写了一FunctionToGenerator堂课:
子类化ast.NodeTransformer(也是FunctionToGenerator如此)是修改AST的推荐方法。的功能性FunctionToGenerator是很好由文档字符串描述:该visit_Assign方法增加了yield通过包装访问关键字的所有分配Assign一个内节点Yield的节点。该visit_FunctionDef方法删除装饰器,并将函数重命名为_pm_compiled_model_generator。总而言之,NodeTransformer使用AST完成后,我们有了一个函数 _pm_compiled_model_generator,它是用户定义函数的修改版本。
二,Model上课时间:
此类不是要实例化的;而是要用作Python装饰器。本质上,它“反编译”该函数以获取该函数的Python源代码。然后,此源代码将传递给parse_snippet3函数,该函数将返回该函数的AST。然后FunctionToGenerator,我们使用上面定义的类修改此AST 。最后,我们重新编译此AST并执行它。回想一下,执行此重新编译的AST定义了一个名为的新函数_pm_compiled_model_generator。然后,通过locals变量4访问的该新函数将绑定到该类的 self.model_generator,这解释了看上去令人困惑的第25行。
最后,面向用户的API如下所示:
如您所见,用户无需yield在指定模型时编写代码,PyMC推理引擎现在可以根据需要简单地调用model_generator方法 linear_regression来生成名为的生成器_pm_compiled_model_generator。成功!
得到教训固定链接
同样,PyMC4的模型规范API将不会合并这些更改:PyMC开发人员此后决定,该yield关键字是用户指定统计模型的最优雅(但不一定是最简单)的方式。这篇文章只是为了总结在进行此询问时所学到的教训。
读取和解析AST是非常安全的:基本上,这只是一种代码自省的形式,这完全是一件有效的事情!当您要修改甚至重写AST时,事情就会开始詹基危险(尤其是如果您想执行修改后的AST 而不是像我想做的那样编写代码时!)。
如果您要以编程方式修改AST(例如yield,在我们的情况下,例如“ 在TensorFlow分配的每个分配之前插入一个关键字”),请停下来考虑一下是否要修改书面代码的语义,以及您确定这是个好主意(例如,yield代码中的关键字具有某种意义,而删除这些关键字会更改代码的明显语义)。
进一步阅读固定链接
在这里,我仅对该项目进行了概述,并且掩盖了许多技术细节。如果您渴望更多,请查看以下资源:
有关该项目的笔记本和更多详细文档位于GitHub上。特别是,仔细阅读README 末尾的链接和引用可能会有所帮助。
对于那些希望像我在这里以编程方式检查/修改Python AST的人一样,您可能会发现此Twitter线程很有帮助。
对于那些想知道PyMC4的模型规范API是如何结束的人,一些非常聪明的人在Twitter上发表了有关这项工作的反馈。