Hướng dẫn này chỉ cho bạn cách sử dụng các thành phần Phục vụ TensorFlow để xây dựng Máy chủ mô hình TensorFlow tiêu chuẩn có chức năng tự động phát hiện và phục vụ các phiên bản mới của mô hình TensorFlow đã được đào tạo. Nếu bạn chỉ muốn sử dụng máy chủ tiêu chuẩn để phục vụ các mô hình của mình, hãy xem hướng dẫn cơ bản về Phục vụ TensorFlow .
Hướng dẫn này sử dụng mô hình hồi quy Softmax đơn giản được giới thiệu trong hướng dẫn TensorFlow để phân loại hình ảnh viết tay (dữ liệu MNIST). Nếu bạn không biết TensorFlow hoặc MNIST là gì, hãy xem hướng dẫn MNIST dành cho người mới bắt đầu học ML .
Mã cho hướng dẫn này bao gồm hai phần:
Tệp Python mnist_saved_model.py huấn luyện và xuất nhiều phiên bản của mô hình.
Tệp C++ main.cc là Máy chủ mô hình TensorFlow tiêu chuẩn giúp phát hiện các mô hình được xuất mới và chạy dịch vụ gRPC để phục vụ chúng.
Hướng dẫn này sẽ thực hiện các nhiệm vụ sau:
- Đào tạo và xuất mô hình TensorFlow.
- Quản lý phiên bản mô hình với TensorFlow Serve
ServerCore
. - Định cấu hình phân nhóm bằng cách sử dụng
SavedModelBundleSourceAdapterConfig
. - Phục vụ yêu cầu với TensorFlow Serve
ServerCore
. - Chạy và kiểm tra dịch vụ.
Trước khi bắt đầu, trước tiên hãy cài đặt Docker
Đào tạo và xuất mô hình TensorFlow
Trước tiên, nếu bạn chưa làm như vậy, hãy sao chép kho lưu trữ này vào máy cục bộ của bạn:
git clone https://github.com/tensorflow/serving.git
cd serving
Xóa thư mục xuất nếu nó đã tồn tại:
rm -rf /tmp/models
Huấn luyện (với 100 lần lặp) và xuất phiên bản đầu tiên của mô hình:
tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
--training_iteration=100 --model_version=1 /tmp/mnist
Huấn luyện (với 2000 lần lặp) và xuất phiên bản thứ hai của mô hình:
tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
--training_iteration=2000 --model_version=2 /tmp/mnist
Như bạn có thể thấy trong mnist_saved_model.py
, việc đào tạo và xuất được thực hiện giống như trong hướng dẫn cơ bản về TensorFlow Serve . Với mục đích trình diễn, bạn đang cố tình quay số vòng lặp huấn luyện cho lần chạy đầu tiên và xuất nó dưới dạng v1, trong khi huấn luyện nó bình thường cho lần chạy thứ hai và xuất nó dưới dạng v2 vào cùng thư mục mẹ -- như chúng tôi mong đợi thư mục sau sẽ đạt được độ chính xác phân loại tốt hơn do được đào tạo chuyên sâu hơn. Bạn sẽ thấy dữ liệu huấn luyện cho mỗi lần huấn luyện trong thư mục /tmp/mnist
của mình:
$ ls /tmp/mnist
1 2
Lõi máy chủ
Bây giờ hãy tưởng tượng v1 và v2 của mô hình được tạo động trong thời gian chạy, khi các thuật toán mới đang được thử nghiệm hoặc khi mô hình được huấn luyện với một tập dữ liệu mới. Trong môi trường sản xuất, bạn có thể muốn xây dựng một máy chủ có thể hỗ trợ triển khai dần dần, trong đó v2 có thể được phát hiện, tải, thử nghiệm, giám sát hoặc hoàn nguyên trong khi cung cấp v1. Ngoài ra, bạn có thể muốn gỡ bỏ v1 trước khi đưa lên v2. TensorFlow Serve hỗ trợ cả hai tùy chọn -- trong khi một tùy chọn phù hợp để duy trì tính khả dụng trong quá trình chuyển đổi, tùy chọn còn lại phù hợp để giảm thiểu mức sử dụng tài nguyên (ví dụ: RAM).
Manager
phục vụ TensorFlow thực hiện chính xác điều đó. Nó xử lý toàn bộ vòng đời của các mô hình TensorFlow bao gồm tải, phục vụ và dỡ bỏ chúng cũng như chuyển đổi phiên bản. Trong hướng dẫn này, bạn sẽ xây dựng máy chủ của mình trên TensorFlow Serve ServerCore
, bao bọc bên trong 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()
lấy tham số ServerCore::Options. Dưới đây là một số tùy chọn thường được sử dụng:
-
ModelServerConfig
chỉ định các mô hình sẽ được tải. Các mô hình được khai báo thông quamodel_config_list
, khai báo danh sách tĩnh các mô hình hoặc thông quacustom_model_config
, xác định cách tùy chỉnh để khai báo danh sách các mô hình có thể được cập nhật khi chạy. -
PlatformConfigMap
ánh xạ từ tên của nền tảng (chẳng hạn nhưtensorflow
) tớiPlatformConfig
, được sử dụng để tạoSourceAdapter
.SourceAdapter
điều chỉnhStoragePath
(đường dẫn phát hiện phiên bản mô hình) thànhLoader
mô hình (tải phiên bản mô hình từ đường dẫn lưu trữ và cung cấp giao diện chuyển trạng thái cho TrìnhManager
). NếuPlatformConfig
chứaSavedModelBundleSourceAdapterConfig
thì mộtSavedModelBundleSourceAdapter
sẽ được tạo và chúng tôi sẽ giải thích sau.
SavedModelBundle
là thành phần chính của TensorFlow Serve. Nó đại diện cho một mô hình TensorFlow được tải từ một đường dẫn nhất định và cung cấp giao diện Session::Run
giống như TensorFlow để chạy suy luận. SavedModelBundleSourceAdapter
điều chỉnh đường dẫn lưu trữ thành Loader<SavedModelBundle>
để vòng đời mô hình có thể được quản lý bởi Manager
. Xin lưu ý rằng SavedModelBundle
là phiên bản kế thừa của SessionBundle
không được dùng nữa. Người dùng được khuyến khích sử dụng SavedModelBundle
vì tính năng hỗ trợ cho SessionBundle
sẽ sớm bị xóa.
Với tất cả những điều này, ServerCore
nội bộ thực hiện những việc sau:
- Khởi tạo
FileSystemStoragePathSource
giám sát đường dẫn xuất mô hình được khai báo trongmodel_config_list
. - Khởi tạo
SourceAdapter
bằng cách sử dụngPlatformConfigMap
với nền tảng mô hình được khai báo trongmodel_config_list
và kết nốiFileSystemStoragePathSource
với nó. Bằng cách này, bất cứ khi nào một phiên bản mô hình mới được phát hiện trong đường dẫn xuất,SavedModelBundleSourceAdapter
sẽ điều chỉnh nó thànhLoader<SavedModelBundle>
. - Khởi tạo một triển khai cụ thể của
Manager
được gọi làAspiredVersionsManager
để quản lý tất cả các phiên bảnLoader
như vậy được tạo bởiSavedModelBundleSourceAdapter
.ServerCore
xuất giao diện TrìnhManager
bằng cách ủy quyền các cuộc gọi đếnAspiredVersionsManager
.
Bất cứ khi nào có phiên bản mới, AspiredVersionsManager
này sẽ tải phiên bản mới và theo hành vi mặc định của nó sẽ dỡ phiên bản cũ. Nếu muốn bắt đầu tùy chỉnh, bạn nên hiểu các thành phần mà nó tạo ra bên trong và cách định cấu hình chúng.
Điều đáng nói là TensorFlow Serve được thiết kế từ đầu nên rất linh hoạt và có khả năng mở rộng. Bạn có thể xây dựng nhiều plugin khác nhau để tùy chỉnh hành vi của hệ thống, đồng thời tận dụng các thành phần cốt lõi chung như ServerCore
và AspiredVersionsManager
. Ví dụ: bạn có thể xây dựng plugin nguồn dữ liệu giám sát lưu trữ đám mây thay vì lưu trữ cục bộ hoặc bạn có thể xây dựng plugin chính sách phiên bản thực hiện chuyển đổi phiên bản theo cách khác -- trên thực tế, bạn thậm chí có thể xây dựng plugin mô hình tùy chỉnh phục vụ các mô hình không phải TensorFlow. Những chủ đề này nằm ngoài phạm vi của hướng dẫn này. Tuy nhiên, bạn có thể tham khảo nguồn tùy chỉnh và hướng dẫn có thể phân phát tùy chỉnh để biết thêm thông tin.
trộn
Một tính năng máy chủ điển hình khác mà chúng tôi muốn có trong môi trường sản xuất là tạo khối. Các bộ tăng tốc phần cứng hiện đại (GPU, v.v.) được sử dụng để thực hiện suy luận máy học thường đạt được hiệu quả tính toán tốt nhất khi các yêu cầu suy luận được chạy theo lô lớn.
Có thể bật tính năng tạo khối bằng cách cung cấp SessionBundleConfig
thích hợp khi tạo SavedModelBundleSourceAdapter
. Trong trường hợp này, chúng tôi đặt BatchingParameters
với khá nhiều giá trị mặc định. Việc tạo khối có thể được tinh chỉnh bằng cách đặt các giá trị thời gian chờ tùy chỉnh, batch_size, v.v. Để biết chi tiết, vui lòng tham khảo 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;
Khi đạt đến lô đầy đủ, các yêu cầu suy luận sẽ được hợp nhất nội bộ thành một yêu cầu lớn duy nhất (tensor) và tensorflow::Session::Run()
được gọi (đây là nguồn gốc của việc tăng hiệu suất thực tế trên GPU).
Phục vụ với người quản lý
Như đã đề cập ở trên, Manager
lý phục vụ TensorFlow được thiết kế để trở thành một thành phần chung có thể xử lý việc tải, phục vụ, dỡ tải và chuyển đổi phiên bản của các mô hình được tạo bởi các hệ thống máy học tùy ý. API của nó được xây dựng dựa trên các khái niệm chính sau:
Có thể phục vụ : Có thể phục vụ là bất kỳ đối tượng mờ nào có thể được sử dụng để phục vụ các yêu cầu của khách hàng. Kích thước và mức độ chi tiết của một thành phần có thể phân phát rất linh hoạt, sao cho một thành phần có thể phân phát có thể bao gồm mọi thứ từ một phân đoạn duy nhất của bảng tra cứu đến một mô hình học máy duy nhất cho đến một bộ mô hình. Một dịch vụ có thể thuộc bất kỳ loại và giao diện nào.
Phiên bản có thể phục vụ : Các phiên bản có thể phục vụ được lập phiên bản và
Manager
phục vụ TensorFlow có thể quản lý một hoặc nhiều phiên bản của một phiên bản có thể phục vụ. Việc lập phiên bản cho phép tải đồng thời nhiều phiên bản của một phiên bản có thể phân phát, hỗ trợ triển khai và thử nghiệm dần dần.Luồng có thể phục vụ : Luồng có thể phục vụ là chuỗi các phiên bản của một luồng có thể phục vụ, với số phiên bản ngày càng tăng.
Mô hình : Một mô hình học máy được biểu thị bằng một hoặc nhiều dịch vụ. Ví dụ về các dịch vụ có thể phục vụ là:
- Phiên TensorFlow hoặc các trình bao bọc xung quanh chúng, chẳng hạn như
SavedModelBundle
. - Các loại mô hình học máy khác.
- Bảng tra cứu từ vựng.
- Nhúng bảng tra cứu.
Một mô hình tổng hợp có thể được biểu diễn dưới dạng nhiều dịch vụ có thể phân phát độc lập hoặc dưới dạng một dịch vụ tổng hợp duy nhất. Một phần có thể phân phát cũng có thể tương ứng với một phần của Mô hình, chẳng hạn như với một bảng tra cứu lớn được phân chia trên nhiều phiên bản
Manager
.- Phiên TensorFlow hoặc các trình bao bọc xung quanh chúng, chẳng hạn như
Để đặt tất cả những điều này vào bối cảnh của hướng dẫn này:
Các mô hình TensorFlow được thể hiện bằng một loại có thể phân phát --
SavedModelBundle
.SavedModelBundle
bên trong bao gồm mộttensorflow:Session
được ghép nối với một số siêu dữ liệu về biểu đồ nào được tải vào phiên và cách chạy biểu đồ đó để suy luận.Có một thư mục hệ thống tệp chứa luồng xuất TensorFlow, mỗi luồng nằm trong thư mục con riêng có tên là số phiên bản. Thư mục bên ngoài có thể được coi là biểu diễn được tuần tự hóa của luồng có thể phục vụ cho mô hình TensorFlow đang được phục vụ. Mỗi lần xuất tương ứng với một dịch vụ có thể được tải.
AspiredVersionsManager
giám sát luồng xuất và quản lý vòng đời của tất cả các dịch vụSavedModelBundle
một cách linh hoạt.
TensorflowPredictImpl::Predict
thì chỉ cần:
- Yêu cầu
SavedModelBundle
từ người quản lý (thông qua ServerCore). - Sử dụng
generic signatures
để ánh xạ các tên tensor logic trongPredictRequest
với các tên tensor thực và liên kết các giá trị với các tensor. - Chạy suy luận.
Kiểm tra và chạy máy chủ
Sao chép phiên bản xuất đầu tiên vào thư mục được giám sát:
mkdir /tmp/monitored
cp -r /tmp/mnist/1 /tmp/monitored
Sau đó khởi động máy chủ:
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 &
Máy chủ sẽ phát ra thông báo nhật ký mỗi giây có nội dung "Phiên bản mong muốn dành cho có thể phục vụ ...", có nghĩa là máy chủ đã tìm thấy bản xuất và đang theo dõi sự tồn tại liên tục của nó.
Hãy chạy ứng dụng khách với --concurrency=10
. Điều này sẽ gửi các yêu cầu đồng thời đến máy chủ và do đó kích hoạt logic phân nhóm của bạn.
tools/run_in_docker.sh python tensorflow_serving/example/mnist_client.py \
--num_tests=1000 --server=127.0.0.1:8500 --concurrency=10
Kết quả là đầu ra trông giống như:
...
Inference error rate: 13.1%
Sau đó, chúng tôi sao chép phiên bản xuất thứ hai vào thư mục được giám sát và chạy lại thử nghiệm:
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
Kết quả là đầu ra trông giống như:
...
Inference error rate: 9.5%
Điều này xác nhận rằng máy chủ của bạn tự động phát hiện phiên bản mới và sử dụng nó để phục vụ!