EN

Teeport

远程优化平台,算法留在笔记本上,问题留在控制室里,中间只传数据,两边各改两行代码就能接上。

在 SPEAR3 这样的加速器上,优化问题在控制室里,通常是一段 Matlab 脚本,它设几块磁铁,再把束流读回来;优化算法则在各人的笔记本电脑上,其中不少是 Python 写的。要试一种新算法,就得把它拷到控制室的电脑上,手工接到脚本上,在那里装它的运行环境往往还需要管理员权限(装的过程也可能弄坏控制系统自己的配置),换下一种算法又要再来一遍。我想让优化器留在它原来的地方运行,脚本也一行不动,于是有了 Teeport。2019 到 2021 年我在 SLAC 写了它的服务器,仪表盘,插件和大部分适配器。2021 年,Xiaobiao Huang,Minghao Song 和我把它写成论文,发表在 Frontiers in Big Data 上。

算法与问题之间的墙

在我 2020 年的幻灯片里,算法与问题之间隔着一堵砖墙,墙上写着三个词。距离和语言指的就是上面说的笔记本电脑和 Matlab,保密指的则是脚本本身:评估脚本里可能存着控制系统的令牌(token),或者一些不希望别人看到的旋钮,因此它应当留在原地。Teeport 不动墙两边的代码,只让数据穿过这堵墙,主要是 X(要尝试的设定值)往一边走,Y(测到的结果)往另一边回。

一堵写着保密,距离和语言的砖墙,隔在你的算法(在笔记本电脑上,多半是 Python)与优化问题(在控制室的电脑上,多半是 Matlab)之间。一根 Teeport 管子穿过墙:X 从算法送到问题,Y 送回来。 保密 · 距离 · 语言 Teeport XYXY 你的算法 在笔记本电脑上, 多半是 Python optimize(evaluate) 优化问题 在控制室的电脑上, 多半是 Matlab Y = evaluate(X)
按我 2020 年幻灯片里的图重画,Teeport 是穿过墙的那根管子。

run_ 与 use_

还是拿那段 Matlab 脚本来说。在 Teeport 看来它只是一个函数,Y = evaluate(X);算法则是一个以这样的函数为参数的函数,optimize(evaluate)。在控制室里,teeport.runEvaluator 把脚本发布出去并给出一个 id。在笔记本上,use_evaluator 拿着这个 id,交回一个普通的本地函数:

from teeport import Teeport
teeport = Teeport('ws://localhost:8080/')
evaluate = teeport.use_evaluator('c4oiY1_oe')

你的优化器像调用其他任何函数一样调用它,看上去它就是本地的。测量仍然在控制室里完成,而且脚本什么时候运行由发布它的人决定,因此你的优化器除了通过这个脚本以外接触不到机器。优化器也有同样的一对调用,于是有问题要解的人也可以按 id 借用一种算法。

隐形的优化器

use_evaluator 是花工夫最多的一个函数(它在 Python 客户端里)。在服务器上,每一次运行都是一个任务(task),而一个任务需要一个优化器客户端,也即一个持续运行并不断产生 X 的函数。这里并没有这样的函数,只有你自己的循环,它什么时候调用 evaluate(X) 都可以。因此你的第一次调用会悄悄在客户端里启动一个私有的优化器,并创建任务。这个优化器的循环永不结束:它等待一个 future 交来下一个 X,把 X 发出去,再把回来的 Y 放进第二个 future,也就是你的 evaluate(X) 正在等的那一个。对你来说它是一个阻塞的函数,于是现成的算法一行不改就能在远端的问题上运行。

对 use_evaluator(id) 返回的 evaluate(X) 的一次调用:1,你的代码用 X 调用 evaluate;2,evaluate 把下一个 X 放进一个 future;3,等着这个 future 的隐形私有优化器把 X 发给远端评估器;4,Y 回来;5,隐形优化器把 Y 放进第二个 future;6,一直等着这个 future 的 evaluate 把 Y 返回给你的代码。 你的代码 调用 evaluate(X) 可以是一个普通循环 也可以是任何算法 evaluate(X) use_evaluator(id) 交给你的函数, 它一直阻塞, 直到 Y 回来 隐形优化器 私有,由你的 第一次调用启动, 循环永不结束 远端评估器 在服务器的另一侧, 测量在那里 完成 1 · X 6 · Y 2 · 下一个 X 5 · 下一个 Y 两个 future 3 · X 4 · Y
每调用一次 evaluate(X),两个 future 就把 X 送到隐形优化器,再把 Y 送回给你。

待发队列

服务器是一个很小的 Node.js WebSocket 服务,做的事尽可能少。来 SLAC 之前我在 Visual3D 写过同一类服务器,混合现实手术导航系统里的每台头显和工作站都通过它通信。Teeport 的服务器把 X 交给评估器,把 Y 送回优化器,旁观的客户端都收到一份 Y,历史记录也由它保存。每一个 X 都先进入待发队列(pending queue),只有任务处于运行状态时才继续往前送,暂停和恢复的全部机制就是这一个判断:暂停,这一批 X 就在队列里等着;恢复,服务器把队列重放给评估器。算法和问题两边都不知道中间发生过什么,也都不必为此加一行代码。

所有这些都放在内存里。服务器一重启,运行记录就没有了,除非有人事先把它导出成了 JSON。我画过服务器后面的归档数据库,也画过把一次运行回滚到之前某一点的功能,两样都没有做出来。

经过 Teeport 服务器的一个来回,服务器把一切放在内存里。优化器发出 X;服务器把它放进待发队列,只有任务处于运行状态时才转发给评估器,因此暂停的任务让 X 等着,恢复时重放队列。评估器把 Y 送回;服务器把 X 和 Y 追加到历史记录,并把 Y 发给优化器和仪表盘的任务页,后者只收到 Y。 Teeport 服务器 全在内存里 · 导出为 JSON 待发队列 运行中? 暂停时 X 在这里等 · 恢复时重放队列 历史记录 · 每一代的 [X, Y] 优化器 任何算法 评估器 与机器打交道的 那段脚本 仪表盘 任务页 XYY X,仅当任务运行中 只有 Y
任务不在运行状态时 X 就在待发队列里等着,仪表盘的任务页只收到 Y。

仪表盘

仪表盘(React 和 Plotly)也只是又一个客户端。任务页以监视器(monitor)的身份订阅,并且声明只要 Y,于是服务器在发送前把每一代里的 X 抹掉,X 要到你下载这次运行时才一起下来。这样设计是为了大问题:NSGA-II 在一个 500 维的问题上收敛时,历史记录已经堆到 1 GB 左右,浏览器的一个标签页装不下。在任务列表里选几次运行,按 Compare 就能把它们叠在一张图上,其中有的还在运行中也可以;同一个优化器反复运行几次,也可以这样做基准测试(benchmark)。

Teeport 的任务列表,选中了两张任务卡:RCDS vs Lossrate Exp,创建于 2020-06-02 20:42:56;P-GPO vs Lossrate Exp,创建于 2020-06-02 19:28:42。上方工具栏有 New,Compare,More 和按创建时间排序。
任务列表里我们在 SPEAR3 上的两次束损率运行,都创建于 2020 年 6 月 2 日,选中后用于下面的比较。
Teeport 仪表盘的 Evaluation History 面板:PSO,RCDS 和 P-GPO 三次运行叠在 SPEAR3 束损率实验评估器上,每次运行的评估点为圆点,到目前为止的最优值为虚线阶梯。
PSO,RCDS(鲁棒共轭方向搜索)和 P-GPO(一种融入物理知识的高斯过程优化器)在同一个 SPEAR3 束损率评估器上的运行,叠在 Teeport 的一张图上。

在 SPEAR3 上

我们三个人用它做 SPEAR3 储存环上的优化,Minghao 是第一个用户,他测试了原型,Matlab 适配器也有一部分是他写的。在 2021 年 1 月给 SSRL 的报告里我们写道,报告中的在线优化,不论是模拟的还是在环上做的,大部分都经过 Teeport,上面的束损率运行就在其中。做法是在控制室里开着的 Matlab 中把脚本发布出去,然后在笔记本上做优化;一次运行可以先对着模拟的储存环跑,再换到真机上,只需改一个 id。

这堵墙也出现在一种算法的内部。MG-GPO 是 Xiaobiao 的算法,Minghao 和我与他一起开发,全部用 Matlab 写成。我们找不到好用的 Matlab 高斯过程(Gaussian process,GP)程序包,而 Python 有 GPy。于是 GPy 作为 Teeport 的处理器(processor,一种无状态的辅助函数,两边都可以调用)运行。teeport.useProcessor 给 Matlab 代码交回一个 predict 函数,其余部分都留在 Matlab 里。调机的结果在 MG-GPO 页上。

漫画:一个开发者手里拿着本地的 optimize 和 evaluate,evaluate 通过 Teeport 连到 Simulation 评估器或 Experiment 评估器,两者各有自己的 id。
同一份本地代码,对着模拟或对着实验,只差一个 id。
框图:Matlab 里的 MG-GPO 通过 Teeport 把 X0,Y0 和 X1 发给 Python 里的 GPy 处理器,后者返回预测值 Y1。
Matlab 里的 MG-GPO 把数据交给 GPy,再取回预测。

Teeport 之后

Teeport 擅长的是远程运行和算法的基准测试,控制室里手动的调机则需要另一种工具,2021 年我为此开始写 Badger。teeport.info 上的公开实例现在还能打开,任务列表是空的,因为一切都只在内存里。

资料来源:论文(Zhang,Huang 和 Song,Frontiers in Big Data,2021 年),我们给 SSRL 的报告(Huang,Song 和 Zhang,2021 年 1 月),我 2020 年的幻灯片,以及公开的 SPEAR3-ML 仓库。