Creando un nuevo tipo de servicio

Organiza tus páginas con colecciones Guarda y categoriza el contenido según tus preferencias.

Este documento explica cómo extender TensorFlow Serving con un nuevo tipo de servicio. El tipo servable más prominente es SavedModelBundle , pero puede ser útil para definir otros tipos de servables, para servir a los datos que va junto con su modelo. Los ejemplos incluyen: una tabla de búsqueda de vocabulario, lógica de transformación de características. Cualquier clase de C ++ puede ser un servable, por ejemplo, int , std::map<string, int> o cualquier clase definida en el binario - llamémosle YourServable .

La definición de un Loader y SourceAdapter para YourServable

Para habilitar TensorFlow servir para gestionar y servir YourServable , es necesario definir dos cosas:

  1. Un Loader clase que las cargas, proporciona acceso a, y se descargue una instancia de YourServable .

  2. Un SourceAdapter que instancia cargadores de caminos del sistema de archivos algún formato de datos subyacente, por ejemplo. Como una alternativa a un SourceAdapter , se podría escribir un completo Source . Sin embargo, dado que el SourceAdapter enfoque es más común y más modular, nos centramos en aquí.

El Loader abstracción se define en core/loader.h . Requiere que defina métodos para cargar, acceder y descargar su tipo de servidor. Los datos a partir de los cuales se carga el servidor pueden provenir de cualquier lugar, pero es común que provengan de una ruta del sistema de almacenamiento. Supongamos que es el caso de YourServable . Supongamos, además, que ya tiene una Source<StoragePath> que está satisfecho con (si no es así, ver el origen personalizado documento).

Además de su Loader , tendrá que definir un SourceAdapter que instancia un Loader de una ruta de almacenamiento determinado. La mayoría de los casos de uso simples pueden especificar los dos objetos de manera concisa con el SimpleLoaderSourceAdapter clase (en core/simple_loader.h ). Casos de uso avanzados pueden optar por especificar Loader y SourceAdapter clases por separado utilizando las API de nivel inferior, por ejemplo, si el SourceAdapter necesita mantener un cierto estado, y / o si las necesidades del estado que se repartirán entre Loader casos.

Hay una implementación de referencia de una simple servable HashMap que utiliza SimpleLoaderSourceAdapter en servables/hashmap/hashmap_source_adapter.cc . Puede que le resulte conveniente hacer una copia de HashmapSourceAdapter y luego modificarlo para adaptarlo a sus necesidades.

La implementación de HashmapSourceAdapter tiene dos partes:

  1. La lógica para cargar un mapa hash de un archivo, en LoadHashmapFromFile() .

  2. El uso de SimpleLoaderSourceAdapter para definir un SourceAdapter que emite Hashmap cargadoras sobre la base de LoadHashmapFromFile() . El nuevo SourceAdapter puede ser instanciada a partir de un mensaje de protocolo de configuración de tipo HashmapSourceAdapterConfig . Actualmente, el mensaje de configuración contiene solo el formato de archivo y, para el propósito de la implementación de referencia, solo se admite un formato simple.

    Tenga en cuenta la llamada a Detach() en el destructor. Esta llamada es necesaria para evitar carreras entre el estado de derribo y cualquier invocación en curso de la lambda del Creador en otros hilos. (Aunque este adaptador de fuente simple no tiene ningún estado, la clase base, no obstante, impone que se llame a Detach ()).

Disponer lo necesario para YourServable objetos para ser cargados en un gestor de

Aquí es cómo conectar su nuevo SourceAdapter para YourServable cargadores a una fuente básica de rutas de almacenamiento, y un gestor (con mal manejo de errores, el código real debería ser más cuidadoso):

Primero, cree un administrador:

std::unique_ptr<AspiredVersionsManager> manager = ...;

A continuación, crear una YourServable adaptador de fuente y conectarlo a la gerente:

auto your_adapter = new YourServableSourceAdapter(...);
ConnectSourceToTarget(your_adapter, manager.get());

Por último, cree una fuente de ruta simple y conéctela a su adaptador:

std::unique_ptr<FileSystemStoragePathSource> path_source;
// Here are some FileSystemStoragePathSource config settings that ought to get
// it working, but for details please see its documentation.
FileSystemStoragePathSourceConfig config;
// We just have a single servable stream. Call it "default".
config.set_servable_name("default");
config.set_base_path(FLAGS::base_path /* base path for our servable files */);
config.set_file_system_poll_wait_seconds(1);
TF_CHECK_OK(FileSystemStoragePathSource::Create(config, &path_source));
ConnectSourceToTarget(path_source.get(), your_adapter.get());

Acceso cargados YourServable objetos

Aquí es cómo conseguir un identificador a una carga YourServable , y lo utilizan:

auto handle_request = serving::ServableRequest::Latest("default");
ServableHandle<YourServable*> servable;
Status status = manager->GetServableHandle(handle_request, &servable);
if (!status.ok()) {
  LOG(INFO) << "Zero versions of 'default' servable have been loaded so far";
  return;
}
// Use the servable.
(*servable)->SomeYourServableMethod();

Avanzado: organización de varias instancias servibles para compartir el estado

Los SourceAdapters pueden albergar el estado que se comparte entre varios servidores emitidos. Por ejemplo:

  • Un grupo de subprocesos compartido u otro recurso que utilizan varios servidores.

  • Una estructura de datos compartida de solo lectura que utilizan varios servidores, para evitar la sobrecarga de tiempo y espacio de replicar la estructura de datos en cada instancia servible.

El SourceAdapter puede crear con entusiasmo un estado compartido cuyo tiempo y tamaño de inicialización es insignificante (por ejemplo, grupos de subprocesos), que luego incrusta un puntero en cada cargador servible emitido. La creación de un estado compartido costoso o grande debe posponerse a la primera llamada Loader :: Load () aplicable, es decir, gobernada por el administrador. Simétricamente, la llamada Loader :: Unload () al servidor final utilizando el estado compartido caro / grande debería derribarlo.