Membangun Server Model TensorFlow Standar

Tutorial ini menunjukkan cara menggunakan komponen TensorFlow Serving untuk membuat TensorFlow ModelServer standar yang secara dinamis menemukan dan menyajikan versi baru model TensorFlow terlatih. Jika Anda hanya ingin menggunakan server standar untuk menyajikan model Anda, lihat tutorial dasar Penyajian TensorFlow .

Tutorial ini menggunakan model Regresi Softmax sederhana yang diperkenalkan dalam tutorial TensorFlow untuk klasifikasi gambar tulisan tangan (data MNIST). Jika Anda belum mengetahui apa itu TensorFlow atau MNIST, lihat tutorial MNIST Untuk Pemula ML .

Kode untuk tutorial ini terdiri dari dua bagian:

  • File Python mnist_saved_model.py yang melatih dan mengekspor beberapa versi model.

  • File C++ main.cc yang merupakan TensorFlow ModelServer standar yang menemukan model baru yang diekspor dan menjalankan layanan gRPC untuk menyajikannya.

Tutorial ini langkah-langkah melalui tugas-tugas berikut:

  1. Latih dan ekspor model TensorFlow.
  2. Kelola pembuatan versi model dengan TensorFlow Serving ServerCore .
  3. Konfigurasikan pengelompokan menggunakan SavedModelBundleSourceAdapterConfig .
  4. Sajikan permintaan dengan TensorFlow Melayani ServerCore .
  5. Jalankan dan uji layanan.

Sebelum memulai, instal dulu Docker

Latih dan ekspor Model TensorFlow

Pertama, jika Anda belum melakukannya, kloning repositori ini ke mesin lokal Anda:

git clone https://github.com/tensorflow/serving.git
cd serving

Hapus direktori ekspor jika sudah ada:

rm -rf /tmp/models

Latih (dengan 100 iterasi) dan ekspor model versi pertama:

tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
  --training_iteration=100 --model_version=1 /tmp/mnist

Latih (dengan 2000 iterasi) dan ekspor model versi kedua:

tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
  --training_iteration=2000 --model_version=2 /tmp/mnist

Seperti yang Anda lihat di mnist_saved_model.py , pelatihan dan ekspor dilakukan dengan cara yang sama seperti di tutorial dasar Penyajian TensorFlow . Untuk tujuan demonstrasi, Anda dengan sengaja menurunkan iterasi pelatihan untuk proses pertama dan mengekspornya sebagai v1, sambil melatihnya secara normal untuk proses kedua dan mengekspornya sebagai v2 ke direktori induk yang sama -- seperti yang kami harapkan akan dicapai oleh yang terakhir akurasi klasifikasi yang lebih baik karena pelatihan yang lebih intensif. Anda akan melihat data pelatihan untuk setiap pelatihan yang dijalankan di direktori /tmp/mnist Anda:

$ ls /tmp/mnist
1  2

ServerCore

Sekarang bayangkan model v1 dan v2 dihasilkan secara dinamis saat runtime, saat algoritme baru sedang diujicobakan, atau saat model dilatih dengan kumpulan data baru. Dalam lingkungan produksi, Anda mungkin ingin membangun server yang dapat mendukung peluncuran bertahap, di mana v2 dapat ditemukan, dimuat, diujicobakan, dipantau, atau dikembalikan saat menyajikan v1. Alternatifnya, Anda mungkin ingin menghapus v1 sebelum membuka v2. TensorFlow Serving mendukung kedua opsi tersebut -- meskipun opsi yang satu bagus untuk menjaga ketersediaan selama transisi, opsi lainnya bagus untuk meminimalkan penggunaan sumber daya (misalnya RAM).

TensorFlow Serving Manager melakukan hal itu. Ini menangani siklus hidup penuh model TensorFlow termasuk memuat, menyajikan, dan membongkar model tersebut serta transisi versi. Dalam tutorial ini, Anda akan membangun server di atas TensorFlow Serving ServerCore , yang secara internal membungkus AspiredVersionsManager .

int main(int argc, char** argv) {
  ...

  ServerCore::Options options;
  options.model_server_config = model_server_config;
  options.servable_state_monitor_creator = &CreateServableStateMonitor;
  options.custom_model_config_loader = &LoadCustomModelConfig;

  ::google::protobuf::Any source_adapter_config;
  SavedModelBundleSourceAdapterConfig
      saved_model_bundle_source_adapter_config;
  source_adapter_config.PackFrom(saved_model_bundle_source_adapter_config);
  (*(*options.platform_config_map.mutable_platform_configs())
      [kTensorFlowModelPlatform].mutable_source_adapter_config()) =
      source_adapter_config;

  std::unique_ptr<ServerCore> core;
  TF_CHECK_OK(ServerCore::Create(options, &core));
  RunServer(port, std::move(core));

  return 0;
}

ServerCore::Create() mengambil parameter ServerCore::Options. Berikut beberapa opsi yang umum digunakan:

  • ModelServerConfig yang menentukan model yang akan dimuat. Model dideklarasikan melalui model_config_list , yang mendeklarasikan daftar model statis, atau melalui custom_model_config , yang mendefinisikan cara khusus untuk mendeklarasikan daftar model yang mungkin diperbarui saat runtime.
  • PlatformConfigMap yang memetakan dari nama platform (seperti tensorflow ) ke PlatformConfig , yang digunakan untuk membuat SourceAdapter . SourceAdapter mengadaptasi StoragePath (jalur tempat versi model ditemukan) ke model Loader (memuat versi model dari jalur penyimpanan dan menyediakan antarmuka transisi status ke Manager ). Jika PlatformConfig berisi SavedModelBundleSourceAdapterConfig , SavedModelBundleSourceAdapter akan dibuat, yang akan kami jelaskan nanti.

SavedModelBundle adalah komponen kunci dari TensorFlow Serving. Ini mewakili model TensorFlow yang dimuat dari jalur tertentu dan menyediakan antarmuka Session::Run yang sama dengan TensorFlow untuk menjalankan inferensi. SavedModelBundleSourceAdapter mengadaptasi jalur penyimpanan ke Loader<SavedModelBundle> sehingga masa pakai model dapat dikelola oleh Manager . Harap perhatikan bahwa SavedModelBundle adalah penerus SessionBundle yang tidak digunakan lagi. Pengguna dianjurkan untuk menggunakan SavedModelBundle karena dukungan untuk SessionBundle akan segera dihapus.

Dengan semua ini, ServerCore secara internal melakukan hal berikut:

  • Membuat instance FileSystemStoragePathSource yang memantau jalur ekspor model yang dideklarasikan dalam model_config_list .
  • Membuat instance SourceAdapter menggunakan PlatformConfigMap dengan platform model yang dideklarasikan dalam model_config_list dan menghubungkan FileSystemStoragePathSource ke platform tersebut. Dengan cara ini, setiap kali versi model baru ditemukan di jalur ekspor, SavedModelBundleSourceAdapter menyesuaikannya dengan Loader<SavedModelBundle> .
  • Membuat instance penerapan spesifik Manager yang disebut AspiredVersionsManager yang mengelola semua instans Loader yang dibuat oleh SavedModelBundleSourceAdapter . ServerCore mengekspor antarmuka Manager dengan mendelegasikan panggilan ke AspiredVersionsManager .

Setiap kali versi baru tersedia, AspiredVersionsManager ini memuat versi baru, dan berdasarkan perilaku defaultnya, membongkar versi lama. Jika Anda ingin mulai melakukan penyesuaian, Anda dianjurkan untuk memahami komponen yang dibuat secara internal, dan cara mengonfigurasinya.

Perlu disebutkan bahwa TensorFlow Serving dirancang dari awal agar sangat fleksibel dan dapat diperluas. Anda dapat membuat berbagai plugin untuk menyesuaikan perilaku sistem, sambil memanfaatkan komponen inti umum seperti ServerCore dan AspiredVersionsManager . Misalnya, Anda dapat membuat plugin sumber data yang memantau penyimpanan cloud, bukan penyimpanan lokal, atau Anda dapat membuat plugin kebijakan versi yang melakukan transisi versi dengan cara berbeda -- bahkan, Anda bahkan dapat membuat plugin model kustom yang berfungsi model non-TensorFlow. Topik-topik ini berada di luar cakupan tutorial ini. Namun, Anda dapat merujuk ke sumber kustom dan tutorial kustom yang dapat diservis untuk informasi lebih lanjut.

Pengelompokan

Fitur khas server lainnya yang kami inginkan dalam lingkungan produksi adalah batching. Akselerator perangkat keras modern (GPU, dll.) yang digunakan untuk melakukan inferensi pembelajaran mesin biasanya mencapai efisiensi komputasi terbaik ketika permintaan inferensi dijalankan dalam jumlah besar.

Batching dapat diaktifkan dengan menyediakan SessionBundleConfig yang tepat saat membuat SavedModelBundleSourceAdapter . Dalam hal ini kami menetapkan BatchingParameters dengan nilai default yang cukup banyak. Batching dapat disempurnakan dengan mengatur nilai batas waktu khusus, ukuran_batch, dll. Untuk detailnya, silakan merujuk ke BatchingParameters .

SessionBundleConfig session_bundle_config;
// Batching config
if (enable_batching) {
  BatchingParameters* batching_parameters =
      session_bundle_config.mutable_batching_parameters();
  batching_parameters->mutable_thread_pool_name()->set_value(
      "model_server_batch_threads");
}
*saved_model_bundle_source_adapter_config.mutable_legacy_config() =
    session_bundle_config;

Setelah mencapai batch penuh, permintaan inferensi digabungkan secara internal menjadi satu permintaan besar (tensor), dan tensorflow::Session::Run() dipanggil (dari situlah peningkatan efisiensi aktual pada GPU berasal).

Sajikan dengan Manajer

Seperti disebutkan di atas, TensorFlow Serving Manager dirancang untuk menjadi komponen umum yang dapat menangani pemuatan, penyajian, pembongkaran, dan transisi versi model yang dihasilkan oleh sistem pembelajaran mesin arbitrer. API-nya dibangun berdasarkan konsep-konsep utama berikut:

  • Servable : Servable adalah objek buram apa pun yang dapat digunakan untuk melayani permintaan klien. Ukuran dan granularitas dari suatu yang dapat diservis bersifat fleksibel, sehingga satu yang dapat diservis dapat mencakup apa saja, mulai dari satu pecahan tabel pencarian, satu model yang dipelajari mesin, hingga serangkaian model. Server dapat berupa jenis dan antarmuka apa pun.

  • Versi yang Dapat Diservis : Servable memiliki versi dan TensorFlow Serving Manager dapat mengelola satu atau lebih versi dari sebuah servable. Pembuatan versi memungkinkan lebih dari satu versi server yang dapat dimuat secara bersamaan, mendukung peluncuran dan eksperimen bertahap.

  • Aliran yang Dapat Diservis : Aliran yang dapat diservis adalah urutan versi dari sebuah yang dapat diservis, dengan nomor versi yang semakin bertambah.

  • Model : Model yang dipelajari mesin diwakili oleh satu atau lebih yang dapat diservis. Contoh yang dapat diservis adalah:

    • Sesi TensorFlow atau pembungkus di sekitarnya, seperti SavedModelBundle .
    • Jenis model pembelajaran mesin lainnya.
    • Tabel pencarian kosakata.
    • Menyematkan tabel pencarian.

    Model komposit dapat direpresentasikan sebagai beberapa server independen, atau sebagai satu server komposit. Suatu yang dapat diservis mungkin juga sesuai dengan sebagian kecil Model, misalnya dengan tabel pencarian besar yang dibagi ke dalam banyak instans Manager .

Untuk memasukkan semua ini ke dalam konteks tutorial ini:

  • Model TensorFlow diwakili oleh satu jenis servable -- SavedModelBundle . SavedModelBundle secara internal terdiri dari tensorflow:Session yang dipasangkan dengan beberapa metadata tentang grafik apa yang dimuat ke dalam sesi dan cara menjalankannya untuk inferensi.

  • Terdapat direktori sistem file yang berisi aliran ekspor TensorFlow, masing-masing dalam subdirektorinya sendiri yang namanya merupakan nomor versi. Direktori luar dapat dianggap sebagai representasi serial dari aliran yang dapat diservis untuk model TensorFlow yang disajikan. Setiap ekspor sesuai dengan server yang dapat dimuat.

  • AspiredVersionsManager memantau aliran ekspor, dan mengelola siklus hidup semua servis SavedModelBundle secara dinamis.

TensorflowPredictImpl::Predict lalu:

  • Meminta SavedModelBundle dari manajer (melalui ServerCore).
  • Menggunakan generic signatures untuk memetakan nama tensor logis di PredictRequest ke nama tensor sebenarnya dan mengikat nilai ke tensor.
  • Menjalankan inferensi.

Uji dan jalankan server

Salin versi ekspor pertama ke folder yang dipantau:

mkdir /tmp/monitored
cp -r /tmp/mnist/1 /tmp/monitored

Kemudian mulai server:

docker run -p 8500:8500 \
  --mount type=bind,source=/tmp/monitored,target=/models/mnist \
  -t --entrypoint=tensorflow_model_server tensorflow/serving --enable_batching \
  --port=8500 --model_name=mnist --model_base_path=/models/mnist &

Server akan mengeluarkan pesan log setiap satu detik yang mengatakan "Versi yang bercita-cita untuk dapat diservis ...", yang berarti server telah menemukan ekspor, dan melacak kelanjutan keberadaannya.

Mari kita jalankan klien dengan --concurrency=10 . Ini akan mengirimkan permintaan bersamaan ke server dan dengan demikian memicu logika batching Anda.

tools/run_in_docker.sh python tensorflow_serving/example/mnist_client.py \
  --num_tests=1000 --server=127.0.0.1:8500 --concurrency=10

Yang menghasilkan output seperti:

...
Inference error rate: 13.1%

Kemudian kami menyalin versi kedua ekspor ke folder yang dipantau dan menjalankan kembali pengujian:

cp -r /tmp/mnist/2 /tmp/monitored
tools/run_in_docker.sh python tensorflow_serving/example/mnist_client.py \
  --num_tests=1000 --server=127.0.0.1:8500 --concurrency=10

Yang menghasilkan output seperti:

...
Inference error rate: 9.5%

Ini mengonfirmasi bahwa server Anda secara otomatis menemukan versi baru dan menggunakannya untuk melayani!