Membuat servable jenis baru

Dokumen ini menjelaskan cara memperluas TensorFlow Serving dengan servable jenis baru. Jenis servable paling menonjol adalah SavedModelBundle , tetapi dapat berguna untuk menentukan jenis lain servables, untuk melayani data yang sejalan dengan model Anda. Contohnya meliputi: tabel pencarian kosakata, logika transformasi fitur. Setiap C ++ class bisa menjadi servable, misalnya int , std::map<string, int> atau kelas didefinisikan dalam biner Anda - mari kita menyebutnya YourServable .

Mendefinisikan Loader dan SourceAdapter untuk YourServable

Untuk mengaktifkan TensorFlow Melayani untuk mengelola dan melayani YourServable , Anda perlu menentukan dua hal:

  1. Sebuah Loader kelas yang beban, menyediakan akses ke, dan unloads sebuah contoh dari YourServable .

  2. Sebuah SourceAdapter yang instantiates loader dari beberapa data yang mendasari Format misalnya path file-system. Sebagai alternatif untuk SourceAdapter , Anda bisa menulis lengkap Source . Namun, karena SourceAdapter pendekatan yang lebih umum dan lebih modular, kita fokus pada hal itu di sini.

The Loader abstraksi didefinisikan dalam core/loader.h . Ini mengharuskan Anda untuk menentukan metode untuk memuat, mengakses, dan membongkar jenis servable Anda. Data dari mana servable dimuat dapat berasal dari mana saja, tetapi biasanya berasal dari jalur sistem penyimpanan. Mari kita berasumsi bahwa adalah kasus untuk YourServable . Mari kita lebih lanjut mengasumsikan Anda sudah memiliki Source<StoragePath> bahwa Anda senang dengan (jika tidak, lihat Kustom Sumber dokumen).

Selain Anda Loader , Anda akan perlu untuk menentukan SourceAdapter yang instantiates Loader dari jalur penyimpanan yang diberikan. Kebanyakan penggunaan-kasus sederhana dapat menentukan dua objek ringkas dengan SimpleLoaderSourceAdapter kelas (di core/simple_loader.h ). Canggih penggunaan-kasus dapat memilih untuk menentukan Loader dan SourceAdapter kelas secara terpisah menggunakan API-tingkat yang lebih rendah, misalnya jika SourceAdapter perlu mempertahankan beberapa negara, dan / atau jika kebutuhan negara untuk dibagi di antara Loader contoh.

Ada implementasi referensi dari hashmap servable sederhana yang menggunakan SimpleLoaderSourceAdapter di servables/hashmap/hashmap_source_adapter.cc . Anda mungkin merasa nyaman untuk membuat salinan HashmapSourceAdapter dan kemudian memodifikasinya sesuai dengan kebutuhan Anda.

Pelaksanaan HashmapSourceAdapter memiliki dua bagian:

  1. Logika untuk memuat hashmap dari file, di LoadHashmapFromFile() .

  2. Penggunaan SimpleLoaderSourceAdapter untuk menentukan SourceAdapter yang memancarkan HashMap loader berdasarkan LoadHashmapFromFile() . Baru SourceAdapter dapat dipakai dari pesan protokol konfigurasi jenis HashmapSourceAdapterConfig . Saat ini, pesan konfigurasi hanya berisi format file, dan untuk tujuan implementasi referensi, hanya satu format sederhana yang didukung.

    Catatan panggilan untuk Detach() di destructor. Panggilan ini diperlukan untuk menghindari perlombaan antara meruntuhkan status dan setiap pemanggilan lambda Pencipta yang sedang berlangsung di utas lainnya. (Meskipun adaptor sumber sederhana ini tidak memiliki status apa pun, kelas dasar tetap memberlakukan bahwa Detach() dipanggil.)

Mengatur untuk YourServable objek untuk dimuat di manajer

Berikut adalah cara untuk menghubungkan baru Anda SourceAdapter untuk YourServable loader ke sumber dasar jalur penyimpanan, dan manajer (dengan penanganan error buruk; kode nyata harus lebih berhati-hati):

Pertama, buat pengelola:

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

Kemudian, membuat YourServable adaptor sumber dan hubungkan ke manajer:

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

Terakhir, buat sumber jalur sederhana dan hubungkan ke adaptor Anda:

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

Mengakses dimuat YourServable benda

Berikut adalah cara untuk mendapatkan pegangan untuk dimuat YourServable , dan menggunakannya:

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

Lanjutan: Mengatur beberapa instance yang dapat diservis untuk berbagi status

SourceAdapters dapat menampung status yang dibagikan di antara beberapa servable yang dipancarkan. Sebagai contoh:

  • Kumpulan utas bersama atau sumber daya lain yang digunakan banyak server.

  • Struktur data baca-saja bersama yang digunakan beberapa servable, untuk menghindari overhead waktu dan ruang dalam mereplikasi struktur data di setiap instans servable.

Status bersama yang waktu dan ukuran inisialisasinya dapat diabaikan (misalnya kumpulan utas) dapat dibuat dengan bersemangat oleh SourceAdapter, yang kemudian menyematkan pointer ke sana di setiap pemuat yang dapat ditayangkan yang dipancarkan. Pembuatan status bersama yang mahal atau besar harus ditunda ke panggilan Loader::Load() pertama yang berlaku, yaitu diatur oleh manajer. Secara simetris, panggilan Loader::Unload() ke final servable menggunakan status bersama yang mahal/besar harus meruntuhkannya.