Ajuda a proteger a Grande Barreira de Corais com TensorFlow em Kaggle Junte Desafio

Criação de um novo tipo de serviço

Este documento explica como estender o TensorFlow Serving com um novo tipo de serviço. O tipo que possa ser veiculado mais proeminente é SavedModelBundle , mas pode ser útil para definir outros tipos de servables, para servir de dados que vai junto com o seu modelo. Os exemplos incluem: uma tabela de pesquisa de vocabulário, lógica de transformação de recursos. Qualquer classe C ++ pode ser um que possa ser veiculado, por exemplo, int , std::map<string, int> ou qualquer classe definida no seu binário - vamos chamá-lo YourServable .

Definindo um Loader e SourceAdapter para YourServable

Para habilitar TensorFlow Servindo para gerenciar e servir YourServable , você precisa definir duas coisas:

  1. Um Loader classe que cargas, fornece acesso a, e descarrega uma instância de YourServable .

  2. A SourceAdapter que instancia carregadores de caminhos do sistema de arquivos algum formato de dados subjacente, por exemplo. Como uma alternativa a um SourceAdapter , você poderia escrever um completo Source . No entanto, desde o SourceAdapter abordagem é mais comum e mais modular, nos concentramos em-lo aqui.

O Loader abstracção é definido no core/loader.h . Requer que você defina métodos para carregar, acessar e descarregar seu tipo de serviço. Os dados dos quais o serviço é carregado podem vir de qualquer lugar, mas é comum que venham de um caminho do sistema de armazenamento. Vamos supor que é o caso de YourServable . Suponhamos ainda que você já tem uma Source<StoragePath> que você está feliz com (se não, ver a Fonte Personalizado documento).

Além de seu Loader , você precisará definir um SourceAdapter que instancia um Loader de um determinado caminho de armazenamento. A maioria dos casos de uso simples pode especificar os dois objetos de forma concisa com o SimpleLoaderSourceAdapter classe (em core/simple_loader.h ). Casos de uso avançados podem optar por especificar Loader e SourceAdapter aulas separadamente usando as APIs de nível inferior, por exemplo, se o SourceAdapter precisa manter algum estado, e / ou se as necessidades do estado para ser compartilhado entre Loader casos.

Existe uma implementação de referência de um que possa ser veiculado hashmap simples que usa SimpleLoaderSourceAdapter em servables/hashmap/hashmap_source_adapter.cc . Você pode achar que é conveniente para fazer uma cópia de HashmapSourceAdapter e, em seguida, modificá-lo para atender às suas necessidades.

A implementação de HashmapSourceAdapter tem duas partes:

  1. A lógica para carregar um hashmap de um arquivo, em LoadHashmapFromFile() .

  2. O uso de SimpleLoaderSourceAdapter para definir um SourceAdapter que emite hashmap carregadoras com base em LoadHashmapFromFile() . O novo SourceAdapter pode ser instanciada a partir de uma mensagem de protocolo de configuração de tipo HashmapSourceAdapterConfig . Atualmente, a mensagem de configuração contém apenas o formato do arquivo e, para fins de implementação de referência, apenas um único formato simples é suportado.

    Observe a chamada para Detach() no processo de destruição. Esta chamada é necessária para evitar corridas entre o estado de destruição e quaisquer invocações contínuas do lambda do Criador em outros encadeamentos. (Mesmo que este adaptador de fonte simples não tenha nenhum estado, a classe base impõe que Detach () seja chamado.)

Organizando para YourServable objetos para ser carregado em um gerenciador

Aqui é como ligar o seu novo SourceAdapter para YourServable carregadores para uma fonte básica de caminhos de armazenamento, e um gerente (com tratamento de erros ruim; código real deve ser mais cuidadoso):

Primeiro, crie um gerente:

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

Em seguida, crie um YourServable adaptador de fonte e conecte-o ao gerente:

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

Por último, crie uma fonte de caminho simples e conecte-a ao 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());

Aceder carregados YourServable objectos

Aqui é como obter um identificador para um carregada YourServable , e usá-lo:

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();

Avançado: organizar várias instâncias de serviço para compartilhar o estado

SourceAdapters pode hospedar o estado que é compartilhado entre vários servables emitidos. Por exemplo:

  • Um pool de threads compartilhados ou outro recurso usado por vários servables.

  • Uma estrutura de dados somente leitura compartilhada que vários servables usam, para evitar a sobrecarga de tempo e espaço de replicação da estrutura de dados em cada instância servable.

O estado compartilhado cujo tempo de inicialização e tamanho é insignificante (por exemplo, pools de thread) pode ser criado avidamente pelo SourceAdapter, que então incorpora um ponteiro a ele em cada carregador de serviço emitido. A criação de um estado compartilhado caro ou grande deve ser adiada para a primeira chamada Loader :: Load () aplicável, ou seja, controlada pelo gerenciador. Simetricamente, a chamada Loader :: Unload () para o serviço final usando o estado compartilhado caro / grande deve destruí-lo.