การสร้างบริการรูปแบบใหม่

เอกสารนี้จะอธิบายวิธีขยายการให้บริการ TensorFlow ด้วยการให้บริการรูปแบบใหม่ ประเภทที่ให้บริการที่โดดเด่นที่สุดคือ SavedModelBundle แต่จะมีประโยชน์ในการกำหนดการให้บริการประเภทอื่นๆ เพื่อแสดงข้อมูลที่สอดคล้องกับโมเดลของคุณ ตัวอย่างได้แก่ ตารางค้นหาคำศัพท์ ตรรกะการแปลงคุณลักษณะ คลาส C++ ใดๆ ก็สามารถให้บริการได้ เช่น int , std::map<string, int> หรือคลาสใดๆ ที่กำหนดไว้ในไบนารี่ของคุณ - ให้เราเรียกมันว่า YourServable

การกำหนด Loader และ SourceAdapter สำหรับ YourServable

หากต้องการเปิดใช้งาน TensorFlow Serving เพื่อจัดการและให้บริการ YourServable คุณต้องกำหนดสองสิ่ง:

  1. คลาส Loader ที่โหลด ให้การเข้าถึง และยกเลิกการโหลดอินสแตนซ์ของ YourServable

  2. SourceAdapter ที่สร้างอินสแตนซ์ของตัวโหลดจากรูปแบบข้อมูลพื้นฐานบางรูปแบบ เช่น เส้นทางของระบบไฟล์ อีกทางเลือกหนึ่งแทน SourceAdapter คุณสามารถเขียน Source แบบเต็มได้ อย่างไรก็ตาม เนื่องจากแนวทาง SourceAdapter เป็นแบบทั่วไปและแบบโมดูลาร์มากกว่า เราจึงมุ่งเน้นที่แนวทางนี้ที่นี่

นามธรรมของ Loader ถูกกำหนดไว้ใน core/loader.h โดยคุณจะต้องกำหนดวิธีการในการโหลด เข้าถึง และยกเลิกการโหลดประเภทบริการของคุณ ข้อมูลที่ใช้ในการโหลดบริการสามารถมาจากที่ใดก็ได้ แต่เป็นเรื่องปกติที่จะมาจากเส้นทางของระบบจัดเก็บข้อมูล ให้เราสมมติว่าเป็นกรณีของ YourServable ให้เราสมมติว่าคุณมี Source<StoragePath> ที่คุณพอใจอยู่แล้ว (หากไม่ โปรดดูเอกสาร แหล่งที่มาที่กำหนดเอง )

นอกจาก Loader ของคุณแล้ว คุณจะต้องกำหนด SourceAdapter ที่สร้างอินสแตนซ์ของ Loader จากพาธพื้นที่จัดเก็บข้อมูลที่กำหนด กรณีการใช้งานที่เรียบง่ายส่วนใหญ่สามารถระบุวัตถุทั้งสองได้อย่างกระชับด้วยคลาส SimpleLoaderSourceAdapter (ใน core/simple_loader.h ) กรณีการใช้งานขั้นสูงอาจเลือกที่จะระบุคลาส Loader และ SourceAdapter แยกกันโดยใช้ API ระดับล่าง เช่น หาก SourceAdapter จำเป็นต้องคงสถานะบางอย่างไว้ และ/หรือหากจำเป็นต้องแชร์สถานะระหว่างอินสแตนซ์ Loader

มีการใช้งานอ้างอิงของ hashmap servable แบบง่ายที่ใช้ SimpleLoaderSourceAdapter ใน servables/hashmap/hashmap_source_adapter.cc คุณอาจพบว่าสะดวกที่จะทำสำเนา HashmapSourceAdapter แล้วแก้ไขให้เหมาะกับความต้องการของคุณ

การใช้งาน HashmapSourceAdapter มีสองส่วน:

  1. ตรรกะในการโหลดแฮชแมปจากไฟล์ใน LoadHashmapFromFile()

  2. การใช้ SimpleLoaderSourceAdapter เพื่อกำหนด SourceAdapter ที่ปล่อยตัวโหลด hashmap ตาม LoadHashmapFromFile() SourceAdapter ใหม่สามารถสร้างอินสแตนซ์ได้จากข้อความโปรโตคอลการกำหนดค่าประเภท HashmapSourceAdapterConfig ในปัจจุบัน ข้อความการกำหนดค่ามีเพียงรูปแบบไฟล์ และเพื่อวัตถุประสงค์ในการใช้งานอ้างอิง รองรับเพียงรูปแบบง่ายๆ เพียงรูปแบบเดียว

    สังเกตการเรียก Detach() ใน destructor การเรียกนี้จำเป็นเพื่อหลีกเลี่ยงการแข่งขันระหว่างการแยกสถานะและการเรียกใช้แลมบ์ดาของ Creator ในเธรดอื่น ๆ (แม้ว่าอะแดปเตอร์ต้นทางแบบธรรมดานี้ไม่มีสถานะใด ๆ แต่คลาสพื้นฐานยังคงบังคับใช้ Detach() ที่ถูกเรียก)

การจัดเตรียมออบเจ็กต์ YourServable ที่จะโหลดในตัวจัดการ

ต่อไปนี้คือวิธีเชื่อมต่อ SourceAdapter ใหม่ของคุณสำหรับตัวโหลด YourServable กับแหล่งพื้นฐานของเส้นทางการจัดเก็บข้อมูลและผู้จัดการ (ที่มีการจัดการข้อผิดพลาดที่ไม่ดี รหัสจริงควรระมัดระวังมากขึ้น):

ขั้นแรก สร้างผู้จัดการ:

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

จากนั้น สร้างอะแดปเตอร์ต้นทาง YourServable และเสียบเข้ากับตัวจัดการ:

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

สุดท้าย สร้างแหล่งที่มาของเส้นทางอย่างง่ายและเสียบเข้ากับอะแดปเตอร์ของคุณ:

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

การเข้าถึงวัตถุ YourServable ที่โหลด

ต่อไปนี้คือวิธีรับหมายเลขอ้างอิงของ YourServable ที่โหลดแล้วและใช้งาน:

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

ขั้นสูง: การจัดเรียงอินสแตนซ์ที่ให้บริการหลายรายการเพื่อแชร์สถานะ

SourceAdapters สามารถกำหนดสถานะที่แชร์ระหว่างบริการที่ปล่อยออกมาหลายรายการ ตัวอย่างเช่น:

  • เธรดพูลที่ใช้ร่วมกันหรือทรัพยากรอื่น ๆ ที่ใช้งานหลายรายการได้

  • โครงสร้างข้อมูลแบบอ่านอย่างเดียวที่ใช้ร่วมกันซึ่งหลายบริการใช้ เพื่อหลีกเลี่ยงเวลาและพื้นที่โอเวอร์เฮดในการจำลองโครงสร้างข้อมูลในแต่ละอินสแตนซ์ที่ให้บริการ

สถานะที่ใช้ร่วมกันซึ่งเวลาและขนาดการเริ่มต้นไม่สำคัญ (เช่น เธรดพูล) สามารถสร้างได้อย่างกระตือรือร้นโดย SourceAdapter ซึ่งจะฝังตัวชี้ไว้ในโหลดเดอร์ที่ให้บริการแต่ละตัวที่ปล่อยออกมา การสร้างสถานะที่ใช้ร่วมกันที่มีราคาแพงหรือขนาดใหญ่ควรถูกเลื่อนออกไปเป็นการเรียก Loader::Load() ที่เกี่ยวข้องครั้งแรก เช่น ควบคุมโดยผู้จัดการ ในเชิงสมมาตร การเรียก Loader::Unload() ไปยังบริการสุดท้ายโดยใช้สถานะการแชร์ที่มีราคาแพง/ขนาดใหญ่ควรทำลายมันลง