Dokumen ini menjelaskan cara memperluas Penyajian TensorFlow dengan jenis servis baru. Jenis servable yang paling menonjol adalah SavedModelBundle
, namun dapat berguna untuk menentukan jenis servable lainnya, untuk menyajikan data yang sesuai dengan model Anda. Contohnya meliputi: tabel pencarian kosakata, logika transformasi fitur. Kelas C++ apa pun bisa menjadi servable, misalnya int
, std::map<string, int>
atau kelas apa pun yang ditentukan dalam biner Anda -- sebut saja YourServable
.
Mendefinisikan Loader
dan SourceAdapter
untuk YourServable
Untuk mengaktifkan TensorFlow Serving untuk mengelola dan menyajikan YourServable
, Anda perlu menentukan dua hal:
Kelas
Loader
yang memuat, menyediakan akses ke, dan membongkar instanceYourServable
.SourceAdapter
yang membuat instance loader dari beberapa format data dasar, misalnya jalur sistem file. Sebagai alternatif dariSourceAdapter
, Anda dapat menulisSource
lengkap. Namun, karena pendekatanSourceAdapter
lebih umum dan lebih modular, kami fokus pada pendekatan ini di sini.
Abstraksi Loader
didefinisikan dalam core/loader.h
. Hal ini mengharuskan Anda untuk menentukan metode untuk memuat, mengakses, dan membongkar jenis server Anda. Data yang memuat serverable dapat berasal dari mana saja, namun biasanya data tersebut berasal dari jalur sistem penyimpanan. Mari kita asumsikan hal itu terjadi pada YourServable
. Mari kita asumsikan lebih lanjut bahwa Anda sudah memiliki Source<StoragePath>
yang Anda sukai (jika belum, lihat dokumen Sumber Kustom ).
Selain Loader
Anda, Anda perlu menentukan SourceAdapter
yang membuat instance Loader
dari jalur penyimpanan tertentu. Kebanyakan kasus penggunaan sederhana dapat menentukan dua objek secara ringkas dengan kelas SimpleLoaderSourceAdapter
(dalam core/simple_loader.h
). Kasus penggunaan tingkat lanjut dapat memilih untuk menentukan kelas Loader
dan SourceAdapter
secara terpisah menggunakan API tingkat yang lebih rendah, misalnya jika SourceAdapter
perlu mempertahankan beberapa status, dan/atau jika status perlu dibagikan di antara instance Loader
.
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 kebutuhan Anda.
Implementasi HashmapSourceAdapter
memiliki dua bagian:
Logika untuk memuat peta hash dari file, di
LoadHashmapFromFile()
.Penggunaan
SimpleLoaderSourceAdapter
untuk mendefinisikanSourceAdapter
yang memancarkan pemuat peta hash berdasarkanLoadHashmapFromFile()
.SourceAdapter
baru dapat dibuat instance-nya dari pesan protokol konfigurasi bertipeHashmapSourceAdapterConfig
. Saat ini, pesan konfigurasi hanya berisi format file, dan untuk tujuan implementasi referensi hanya didukung satu format sederhana.Perhatikan panggilan ke
Detach()
di destruktor. Panggilan ini diperlukan untuk menghindari perlombaan antara penghancuran status dan pemanggilan lambda Pencipta yang sedang berlangsung di thread lain. (Meskipun adaptor sumber sederhana ini tidak memiliki status apa pun, kelas dasar tetap memaksa Detach() dipanggil.)
Mengatur objek YourServable
untuk dimuat di manajer
Berikut adalah cara menghubungkan loader SourceAdapter
for YourServable
baru Anda ke sumber dasar jalur penyimpanan, dan manajer (dengan penanganan kesalahan yang buruk; kode sebenarnya harus lebih berhati-hati):
Pertama, buat manajer:
std::unique_ptr<AspiredVersionsManager> manager = ...;
Kemudian, buat adaptor sumber YourServable
dan sambungkan ke manajer:
auto your_adapter = new YourServableSourceAdapter(...);
ConnectSourceToTarget(your_adapter, manager.get());
Terakhir, buat sumber jalur sederhana dan sambungkan 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 objek YourServable
yang dimuat
Berikut ini cara menangani YourServable
yang dimuat, 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 server yang dipancarkan. Misalnya:
Kumpulan thread bersama atau sumber daya lain yang digunakan oleh beberapa server.
Struktur data read-only bersama yang digunakan oleh beberapa servable, untuk menghindari overhead waktu dan ruang dalam mereplikasi struktur data di setiap instance servable.
Status bersama yang waktu dan ukurannya inisialisasi dapat diabaikan (misalnya kumpulan thread) dapat dibuat dengan cepat oleh SourceAdapter, yang kemudian menyematkan penunjuk ke status tersebut di setiap pemuat yang dapat diservis yang dipancarkan. Pembuatan status bersama yang mahal atau besar harus ditunda ke panggilan Loader::Load() pertama yang berlaku, yaitu diatur oleh pengelola. Secara simetris, panggilan Loader::Unload() ke server akhir yang menggunakan status bersama mahal/besar akan menghancurkannya.