本文档介绍了如何扩展 TensorFlow Serving 以监控不同的存储系统,以发现新的(版本的)模型或要服务的数据。特别是,它涵盖了如何创建和使用一个模块来监控存储系统路径中新子路径的出现,其中每个子路径代表一个要加载的新可服务版本。这种模块称为 Source<StoragePath>
,因为它会发出类型为 StoragePath
(定义为 string
)的对象。它可以与 SourceAdapter
组合,该适配器从源发现的给定路径创建可服务 Loader
。
首先,关于通用性的说明
使用路径作为可服务数据的句柄不是必需的;它仅仅说明了一种将可服务对象摄取到系统中的方式。即使您的环境没有将可服务数据封装在路径中,本文档也会让您熟悉关键抽象。您可以选择为适合您的环境的类型创建 Source<T>
和 SourceAdapter<T1, T2>
模块(例如 RPC 或发布/订阅消息、数据库记录),或者简单地创建一个单一的 Source<std::unique_ptr<Loader>>
,它直接发出可服务加载器。
当然,无论您的源发出什么类型的数据(无论是 POSIX 路径、Google Cloud Storage 路径还是 RPC 句柄),都需要有相应的模块来根据该数据加载可服务对象。这些模块称为 SourceAdapters
。创建自定义模块在 自定义可服务对象 文档中进行了描述。TensorFlow Serving 附带了一个模块,用于根据 TensorFlow 支持的文件系统中的路径实例化 TensorFlow 会话。可以通过扩展 RandomAccessFile
抽象 (tensorflow/core/public/env.h
) 为 TensorFlow 添加对其他文件系统的支持。
本文档重点介绍创建发出 TensorFlow 支持的文件系统中的路径的源。它以如何将您的源与预先存在的模块结合使用以服务 TensorFlow 模型的演练结束。
创建您的源
我们有一个 Source<StoragePath>
的参考实现,称为 FileSystemStoragePathSource
(位于 sources/storage_path/file_system_storage_path_source*
)。FileSystemStoragePathSource
监控特定的文件系统路径,观察数字子目录,并报告其中最新的目录作为其希望加载的版本。本文档将介绍 FileSystemStoragePathSource
的重要方面。您可能会发现复制 FileSystemStoragePathSource
并修改它以满足您的需求很方便。
首先,FileSystemStoragePathSource
实现 Source<StoragePath>
API,它是 Source<T>
API 的特化,其中 T
绑定到 StoragePath
。该 API 包含一个名为 SetAspiredVersionsCallback()
的方法,该方法提供一个闭包,源可以使用它来传达它希望加载特定的一组可服务版本。
FileSystemStoragePathSource
以非常简单的方式使用期望版本回调:它定期检查文件系统(本质上执行 ls
),如果它发现一个或多个看起来像可服务版本的路径,它会确定哪个是最新版本,并使用包含该版本(在默认配置下)的长度为一的列表调用回调。因此,在任何给定时间,FileSystemStoragePathSource
都会请求最多一个可服务对象进行加载,并且它的实现利用了回调的幂等性来保持自身无状态(使用相同的参数重复调用回调不会造成任何危害)。
FileSystemStoragePathSource
具有一个静态初始化工厂(Create()
方法),它接受一个配置协议消息。配置消息包含诸如要监视的基路径和监视间隔之类的详细信息。它还包含要发出的可服务流的名称。(替代方法可能会从基路径中提取可服务流名称,以根据观察更深的目录层次结构来发出多个可服务流;这些变体超出了参考实现的范围。)
实现的大部分内容包括一个定期检查文件系统的线程,以及一些用于识别和排序它发现的任何数字子路径的逻辑。该线程在 SetAspiredVersionsCallback()
中启动(而不是在 Create()
中),因为这是源代码应该“启动”并知道将期望版本请求发送到何处的点。
使用您的源代码加载 TensorFlow 会话
您可能希望将新的源代码模块与 SavedModelBundleSourceAdapter
(servables/tensorflow/saved_model_bundle_source_adapter*
) 结合使用,它将解释您的源代码发出的每个路径作为 TensorFlow 导出,并将每个路径转换为 TensorFlow SavedModelBundle
可服务项的加载器。您可能将 SavedModelBundle
适配器插入 AspiredVersionsManager
,它负责实际加载和服务可服务项。在 servables/tensorflow/simple_servers.cc
中可以找到将这三种类型的模块链接在一起以获得工作服务器库的良好示例。以下是主要代码流的逐步说明(错误处理很差;实际代码应该更加小心)
首先,创建一个管理器
std::unique_ptr<AspiredVersionsManager> manager = ...;
然后,创建一个 SavedModelBundle
源代码适配器并将其插入管理器
std::unique_ptr<SavedModelBundleSourceAdapter> bundle_adapter;
SavedModelBundleSourceAdapterConfig config;
// ... populate 'config' with TensorFlow options.
TF_CHECK_OK(SavedModelBundleSourceAdapter::Create(config, &bundle_adapter));
ConnectSourceToTarget(bundle_adapter.get(), manager.get());
最后,创建您的路径源代码并将其插入 SavedModelBundle
适配器
auto your_source = new YourPathSource(...);
ConnectSourceToTarget(your_source, bundle_adapter.get());
The ConnectSourceToTarget()
函数(在 core/target.h
中定义)仅仅调用 SetAspiredVersionsCallback()
来将 Source<T>
连接到 Target<T>
(Target
是一个捕获期望版本请求的模块,即适配器或管理器)。