{"id":358899,"date":"2024-05-21T00:21:24","date_gmt":"2024-05-21T00:21:24","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=358899"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-05-21T00:21:24","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=358899","title":{"rendered":"<span>\u041a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 Model Serving \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0438\u0437\u043d\u0443\u0442\u0440\u0438. \u041f\u0438\u0448\u0435\u043c \u0441\u0432\u043e\u0439 \u043d\u0430 Python \u0438 Docker \u0441 \u043d\u0443\u043b\u044f<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041f\u043e \u0441\u0432\u043e\u0435\u0439 \u0441\u0443\u0442\u0438 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043e\u0431\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c\u0438 \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0441\u0438\u0441\u0442\u0435\u043c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u043c \u0438 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c. \u042d\u0442\u043e \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0448\u0430\u0433 \u0432 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u043c \u0446\u0438\u043a\u043b\u0435 \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0412 \u044d\u0442\u043e\u043c \u043e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u0438 \u043c\u044b \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u043c\u0441\u044f \u043d\u0430 \u043a\u043e\u043d\u0446\u0435\u043f\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0431\u0443\u0434\u0435\u043c \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c `<strong>servingml`<\/strong>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0438 \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0442\u0438\u043f\u0438\u0447\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u043d\u0433\u0430 \u043c\u043e\u0434\u0435\u043b\u0438.<\/p>\n<h2>\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b servingml Framework<\/h2>\n<p>\u0424\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a servingml \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0434\u043b\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0438 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f. \u041e\u043d \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0432\u0437\u0430\u0438\u043c\u043e\u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432, \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0438\u0433\u0440\u0430\u0435\u0442 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e \u0432\u0430\u0436\u043d\u0443\u044e \u0440\u043e\u043b\u044c \u0432 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u0438\u0441\u0442\u0435\u043c\u044b:<\/p>\n<ol>\n<li>\n<p><strong>Core<\/strong>. \u0412 \u043e\u0441\u043d\u043e\u0432\u0435 `<strong>servingml`<\/strong> \u043b\u0435\u0436\u0438\u0442 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043e\u0432 \u043c\u043e\u0434\u0435\u043b\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442 \u043e\u0441\u043d\u043e\u0432\u0443 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430. \u042d\u0442\u043e \u044f\u0434\u0440\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u043c \u0438 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e \u0441 scikit-learn \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0430, \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0440\u0443\u0433\u0438\u0445, \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0447\u0442\u043e \u0448\u0438\u0440\u043e\u043a\u0438\u0439 \u0441\u043f\u0435\u043a\u0442\u0440 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043d\u0430\u0448\u0435\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b.<\/p>\n<\/li>\n<li>\n<p><strong>CLI and Build Tools<\/strong>. \u0427\u0442\u043e\u0431\u044b \u043e\u0431\u043b\u0435\u0433\u0447\u0438\u0442\u044c \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043e\u0442 \u043e\u0431\u0443\u0447\u0435\u043d\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 \u043a \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u0435\u043c\u043e\u043c\u0443 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u0443, \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 (CLI) \u0434\u043b\u044f `<strong>servingml`<\/strong>. \u0417\u0430\u0434\u0430\u0447\u0430 \u044d\u0442\u043e\u0433\u043e CLI \u2014 \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0439 \u043a\u043e\u0434 \u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u043e\u0434\u043d\u043e\u043c \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435. \u042d\u0442\u0430 \u043a\u043e\u043d\u0441\u043e\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u0430\u0436\u043d\u044b\u043c \u0448\u0430\u0433\u043e\u043c, \u0443\u043f\u0440\u043e\u0449\u0430\u044e\u0449\u0438\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u0435\u0435 \u0441\u0440\u0435\u0434\u044b.<\/p>\n<\/li>\n<li>\n<p><strong>Project Configuration via YAML<\/strong>. \u041f\u0440\u0438\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c\u044e \u043c\u043d\u043e\u0433\u0438\u0445 Model Serving \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 YAML \u0434\u043b\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u0412 \u044d\u0442\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u044b \u0432\u0430\u0436\u043d\u044b\u0435 \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u044f, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u043c\u043e\u0434\u0435\u043b\u0438, \u0438\u043c\u044f \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u043f\u0443\u0442\u044c \u043a \u0441\u0435\u0440\u0432\u0438\u0441\u0443. \u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438, \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u044f \u0447\u0435\u0442\u043a\u043e\u0435 \u0438 \u0443\u0434\u043e\u0431\u043d\u043e\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430.<\/p>\n<\/li>\n<li>\n<p><strong>Docker Integration<\/strong>. \u0426\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u043e\u0435 \u043c\u0435\u0441\u0442\u043e \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 Docker. \u041f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 `<strong>servingml`<\/strong> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0448\u0430\u0431\u043b\u043e\u043d Dockerfile (<strong>Dockerfile.j2<\/strong>), \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u043f\u0438\u0441\u0430\u043d\u043e, \u043a\u0430\u043a \u0443\u043f\u0430\u043a\u043e\u0432\u0430\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0435\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 Docker. \u042d\u0442\u043e\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442, \u0447\u0442\u043e \u043c\u043e\u0434\u0435\u043b\u044c \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0432 \u043b\u044e\u0431\u043e\u0439 \u0441\u0440\u0435\u0434\u0435, \u0443\u0441\u0442\u0440\u0430\u043d\u044f\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b, \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u044e\u0449\u0438\u0435 \u0438\u0437-\u0437\u0430 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0438\u043b\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p><strong>ServingML Server and Deployment<\/strong>. \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0447\u0430\u0441\u0442\u044c\u044e \u0433\u043e\u043b\u043e\u0432\u043e\u043b\u043e\u043c\u043a\u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0435\u0440\u0432\u0435\u0440 ServingML. \u042d\u0442\u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 Docker, \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0435\u0433\u043e \u043c\u043e\u0434\u0435\u043b\u044c, \u0444\u0430\u0439\u043b Dockerfile \u0438 \u043b\u044e\u0431\u043e\u0439 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0439 \u043a\u043e\u0434. \u0417\u0430\u0442\u0435\u043c \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0437 Docker \u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u0430. \u041f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043c\u043e\u0434\u0435\u043b\u044c \u0441\u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u0440\u043e\u0433\u043d\u043e\u0437\u044b \u0447\u0435\u0440\u0435\u0437 REST API \u0434\u043b\u044f \u043e\u0431\u044b\u0447\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.<\/p>\n<\/li>\n<\/ol>\n<p>\u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0440\u0430\u0437\u0434\u0435\u043b\u0430\u0445 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u044d\u0442\u0438\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432, \u0438\u0437\u0443\u0447\u0430\u044f, \u043a\u0430\u043a \u043e\u043d\u0438 \u0432\u043b\u0438\u044f\u044e\u0442 \u043d\u0430 \u043e\u0431\u0449\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c <strong>servingml<\/strong>. \u041d\u0430\u0448 \u043f\u0443\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0434\u0435\u0442 \u043d\u0430\u0441 \u043e\u0442 \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0439 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043c\u043e\u0434\u0435\u043b\u0438 \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u043e \u0435\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0438 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f.<\/p>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f Model Serving \u043a\u043b\u0430\u0441\u0441\u0430 \u0434\u043b\u044f \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438<\/h2>\n<p>\u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e, \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 <strong>ModelServer, <\/strong>\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u043c \u043a\u043b\u0430\u0441\u0441\u043e\u043c \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f <strong>load<\/strong>, <strong>predict<\/strong>, <strong>preprocess<\/strong> \u0438 <strong>postprocess<\/strong> \u043c\u0435\u0442\u043e\u0434\u043e\u0432. <strong>ModelServer<\/strong> \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u044d\u0442\u0438\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 api \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c <strong>Starlette.<\/strong><\/p>\n<p><strong><em>service.py<\/em><\/strong><\/p>\n<pre><code class=\"python\">import numpy as np  import Starlette  from typing import Dict, List  from servingml import ModelServer from servingml.frameworks.sklearn import load_model   class ModelClass(ModelServer):     def load(self):         self.model = load_model(\"iris_clf\")      def predict(self, body: Dict) -> List:         \"\"\"Generate model predictions from sample\"\"\"         sample_input = np.asarray(body['inputs'])         result: np.ndarray = self.model.predict(sample_input)         return result.tolist()      def postprocess(self, sample_output: List) -> str:         \"\"\"Make postprocessing for returning class name\"\"\"         target_names = ['setosa', 'versicolor', 'virginica']         # Convert numeric prediction to species name         predicted_species = target_names[sample_output[0]]         return predicted_species   model_class = ModelClass(     model_name=\"iris_clf\", )  app: Starlette = model_class.asgi_app <\/code><\/pre>\n<p>\u042d\u0442\u043e \u043d\u0430\u0448 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439 \u043a\u043e\u0434. \u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u043e\u0431\u0443\u0447\u0435\u043d\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0432 \u043d\u0430\u0448\u0435\u043c model store, \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <strong>predict<\/strong>, \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u0438 <strong>postprocess<\/strong>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441, \u0432\u043c\u0435\u0441\u0442\u043e \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e\u0441\u0442\u0435\u0439.<\/p>\n<p>\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f <strong>app<\/strong> \u0437\u0434\u0435\u0441\u044c, \u044d\u0442\u043e <strong>Starlette<\/strong> \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0437\u0430\u0442\u0435\u043c \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f uvicorn \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f asgi \u0441\u0435\u0440\u0432\u0435\u0440\u0430.<\/p>\n<p>\u042d\u0442\u043e <strong>ModelServer<\/strong> \u043a\u043b\u0430\u0441\u0441<\/p>\n<p><strong><em>servingml._model_server.py<\/em><\/strong><\/p>\n<pre><code class=\"python\">from typing import Dict, Any from starlette.applications import Starlette from starlette.requests import Request from starlette.responses import JSONResponse from starlette.routing import Route import logging  class ModelServer:     \"\"\"Class that creates a Starlette app for serving a machine learning model.\"\"\"          def __init__(self, model_name: str) -> None:         self.model_name = model_name         self.model = self.load()         logging.basicConfig(level=logging.INFO)      @property     def asgi_app(self) -> Starlette:         return Starlette(routes=[             Route(f\"\/v2\/models\/{self.model_name}\/infer\", self._predict_fn, methods=[\"POST\"]),         ])      async def _predict_fn(self, request: Request) -> JSONResponse:         \"\"\"Handler for the Starlette application.\"\"\"         try:             data = await request.json()             if not data:                 return JSONResponse({\"error\": \"Invalid input data\"}, status_code=400)             processed_data = self.preprocess(data)             prediction = self.predict(processed_data)             result = self.postprocess(prediction)             return JSONResponse({\"result\": result})         except Exception as e:             logging.error(f\"Error during prediction: {e}\")             return JSONResponse({\"error\": \"Error processing request\"}, status_code=500)      def load(self) -> Any:         \"\"\"Model loading operation.\"\"\"         raise NotImplementedError()      def preprocess(self, body: Dict) -> Any:         \"\"\"Preprocess the event body before validation and action.\"\"\"         return body      def postprocess(self, result: Any) -> Any:         \"\"\"Postprocess the prediction before returning response.\"\"\"         return result      def predict(self, data: Any) -> Any:         \"\"\"Model prediction operation.\"\"\"         raise NotImplementedError() <\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 endpoint \u0434\u043b\u044f \u043c\u043e\u0434\u0435\u043b\u0438: <strong>\/v2\/models\/{self.model_name}\/infer<\/strong>, \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <strong>V2 Inference Protocol<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043e\u043c \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 Model Serving \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a Seldon Core, Bentoml, Nvidia Triton, Onnx Runtime Server \u0438 \u0434\u0440. <\/p>\n<h2>\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0441 scikit-learn<\/h2>\n<p>\u0421\u0443\u0442\u044c \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435, \u044d\u0442\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043e\u0431\u0443\u0447\u0435\u043d\u043d\u043e\u0439 scikit-learn \u043c\u043e\u0434\u0435\u043b\u0438 \u0432 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 model store, \u0438 \u0435\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0432 \u043f\u0430\u043c\u044f\u0442\u044c \u0434\u043b\u044f \u0438\u043d\u0444\u0435\u0440\u0435\u043d\u0441\u0430.<\/p>\n<p><strong><em>servingml.frameworks.sklearn.py<\/em><\/strong>  <\/p>\n<pre><code class=\"python\">import os import joblib  from typing import Union  from sklearn.base import BaseEstimator from sklearn.pipeline import Pipeline  from servingml.constants import MODEL_STORE_SKLEARN, MODEL_STORE_SKLEARN_WORKING   SklearnModel = Union[BaseEstimator, Pipeline]   def save_model(model_name: str, model: SklearnModel) -> None:     if not os.path.exists(MODEL_STORE_SKLEARN):         os.makedirs(MODEL_STORE_SKLEARN)     model_path = os.path.join(MODEL_STORE_SKLEARN, f\"{model_name}.pkl\")     joblib.dump(model, model_path)   def load_model(model_name: str) -> SklearnModel:     print(\"MODEL_STORE_SKLEARN_WORKING\", MODEL_STORE_SKLEARN_WORKING)     model_path = os.path.join(MODEL_STORE_SKLEARN_WORKING, f\"{model_name}.pkl\")     if not os.path.exists(model_path):         raise ValueError(             f\"Model {model_name} is not found at the sklearn model store. Make sure you saved it first.\"         )     return joblib.load(model_path) <\/code><\/pre>\n<p>\u0413\u0434\u0435 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c<\/p>\n<p><strong><em>servingml.frameworks.constants.py<\/em><\/strong><\/p>\n<pre><code class=\"python\">import os   home_directory = os.path.expanduser(\"~\") SERVINGML_WORKING_DIR = os.path.join(home_directory, \"servingml\/svc\") MODEL_STORE_DIR = os.path.join(home_directory, \"servingml\/model_store\") MODEL_STORE_SKLEARN = os.path.join(MODEL_STORE_DIR, \"sklearn\") MODEL_STORE_SKLEARN_WORKING = \".\/model_store\/sklearn\" <\/code><\/pre>\n<p>\u042d\u0442\u043e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u0440\u0430\u043d\u0438\u0442 \u0432\u0441\u0435 \u043d\u0443\u0436\u043d\u044b\u0435 \u0430\u0440\u0442\u0438\u0444\u0430\u043a\u0442\u044b \u0434\u043b\u044f \u0441\u0435\u0440\u0432\u0438\u043d\u0433\u0430 \u043c\u043e\u0434\u0435\u043b\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0435\u043a\u0446\u0438\u0438 \u043f\u0440\u043e cli.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0438\u043c\u0435\u0435\u043c \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e \u0441 scikit-learn \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0431\u0443\u0447\u0438\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u043d\u0430\u0448\u0435\u043c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c model store<\/p>\n<p><strong><em>download_model.py<\/em><\/strong><\/p>\n<pre><code class=\"python\">from sklearn import svm from sklearn import datasets  from servingml.frameworks.sklearn import save_model  # Load training data set iris = datasets.load_iris() X, y = iris.data, iris.target  # Train the model clf = svm.SVC(gamma='scale') clf.fit(X, y)  # Save model to the local Model Store saved_model = save_model(\"iris_clf\", clf)<\/code><\/pre>\n<h2>CLI \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u0434\u0435\u043f\u043b\u043e\u044f<\/h2>\n<p>\u0412 \u044d\u0442\u043e\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u043c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 Python, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 servingml cli \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f Dockerfile, \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u043a \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044e. \u042d\u0442\u043e\u0442 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f, \u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u043d\u043d\u043e\u0441\u0442\u044c \u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0441\u0440\u0435\u0434\u0430\u0445.<\/p>\n<p>\u0412 cli \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0434\u0432\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b <strong>build<\/strong>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u0437\u0434\u0430\u0435\u0442 Dockerfile \u0434\u043b\u044f \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u044b \u0434\u043b\u044f \u043d\u0435\u0433\u043e, \u0438 <strong>deploy<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u044d\u0442\u043e zip \u0430\u0440\u0445\u0438\u0432 \u043d\u0430 <strong>servingml server<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043a\u0430\u043a \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e, \u0442\u0430\u043a \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e.<\/p>\n<p>\u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u0437\u0434\u0430\u0435\u0442 Dockerfile \u0438\u0437 \u0448\u0430\u0431\u043b\u043e\u043d\u0430<\/p>\n<pre><code class=\"python\">def _generate_dockerfile(app_module: str, requirements: List[str], output_path=\"Dockerfile\") -> None:     # Load the template environment     env = Environment(loader=FileSystemLoader('.'))     template = env.get_template('servingml\/Dockerfile.j2')      # Render the template with variables     rendered_dockerfile = template.render(app_module=app_module, requirements=requirements)      # Write the rendered template to a file     with open(os.path.join(SERVINGML_WORKING_DIR, output_path), 'w') as f:         f.write(rendered_dockerfile)<\/code><\/pre>\n<p>\u041c\u044b \u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u0432 \u0448\u0430\u0431\u043b\u043e\u043d\u0435 \u0443 \u043d\u0430\u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f <strong>app_module<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0443\u0442\u0435\u043c \u043a \u043d\u0430\u0448\u0435\u043c\u0443 <strong>Starlette<\/strong> \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0432\u044b\u0448\u0435 \u0438 <strong>requirements<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0443\u0436\u043d\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0448\u0435\u0433\u043e <strong>ModelClass<\/strong>.<\/p>\n<p><strong><em>servingml\/Dockerfile.j2<\/em><\/strong><\/p>\n<pre><code class=\"python\"># Use an official Python runtime as a parent image FROM python:3.9-slim  # Set environment varibles ENV PYTHONDONTWRITEBYTECODE 1 ENV PYTHONUNBUFFERED 1  # Set work directory WORKDIR \/usr\/src\/app  # Install any needed packages specified directly RUN pip install --no-cache-dir {{ requirements | join(\" \") }}  RUN pip install uvicorn starlette  # Copy the current directory contents into the container at \/usr\/src\/app COPY . .  # Run the application CMD [\"uvicorn\", \"{{ app_module }}\", \"--host\", \"0.0.0.0\", \"--port\", \"8090\"] <\/code><\/pre>\n<p>\u041a\u043e\u043c\u043c\u0430\u043d\u0434\u0430 <strong>build,<\/strong> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u0430\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e click \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438:<\/p>\n<ol>\n<li>\n<p><strong>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0440\u0430\u0431\u043e\u0447\u0435\u0433\u043e \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430<\/strong>. \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043b\u0438 <strong>SERVINGML_WORKING_DIR<\/strong>. \u0415\u0441\u043b\u0438 \u043d\u0435\u0442, \u0442\u043e \u043e\u043d \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0435\u0433\u043e. \u0415\u0441\u043b\u0438 \u043e\u043d \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442, \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u0443\u0434\u0430\u043b\u044f\u0435\u0442\u0441\u044f \u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0437\u0430\u043d\u043e\u0432\u043e. \u042d\u0442\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0447\u0438\u0441\u0442\u043e\u0442\u0443 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p><strong>\u0427\u0442\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 YAML<\/strong>. \u041e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0439 \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u044b\u0439 \u0444\u0430\u0439\u043b (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u2014 servingfile.yaml) \u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435.<br \/>\u042d\u0442\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 SimpleNamespace \u0434\u043b\u044f \u043e\u0431\u043b\u0435\u0433\u0447\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430\u043c. \u0414\u0430\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b yaml \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043d \u043d\u0438\u0436\u0435.<\/p>\n<\/li>\n<li>\n<p><strong>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 Dockerfile<\/strong>. \u0412\u044b\u0437\u044b\u0432\u0430\u0435\u0442 <strong>_generate_dockerfile()<\/strong> \u0441 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 YAML (\u0438\u043c\u0435\u043d\u0435\u043c \u0441\u043b\u0443\u0436\u0431\u044b \u0438 \u043f\u0430\u043a\u0435\u0442\u0430\u043c\u0438) \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f Dockerfile.<\/p>\n<\/li>\n<li>\n<p><strong>\u041b\u043e\u0433\u0438\u043a\u0430 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u043e\u0432<\/strong>. \u0421\u043a\u0440\u0438\u043f\u0442 \u043f\u0440\u043e\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u0442 \u0444\u0430\u0439\u043b\u044b \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u0441\u0431\u043e\u0440\u043a\u0438 (build_ctx), \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u0444\u0430\u0439\u043b \u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435 \u0448\u0430\u0431\u043b\u043e\u043d\u0430\u043c \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0438 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 YAML.<br \/>\u0424\u0430\u0439\u043b\u044b, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0448\u0430\u0431\u043b\u043e\u043d\u0430\u043c \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0438 \u043d\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0448\u0430\u0431\u043b\u043e\u043d\u0430\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f, \u043a\u043e\u043f\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0432 <strong>SERVINGML_WORKING_DIR<\/strong>.<\/p>\n<\/li>\n<li>\n<p><strong>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043c\u043e\u0434\u0435\u043b\u0438. <\/strong>\u0418\u043c\u044f \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u044e\u0442\u0441\u044f \u0438\u0437 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 YAML.<br \/>\u0414\u043b\u044f \u043c\u043e\u0434\u0435\u043b\u0435\u0439 scikit-learn (<strong>if framework == &#171;sklearn&#187;<\/strong>\ud83d\ude42 \u0441\u043a\u0440\u0438\u043f\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043b\u0438 \u0444\u0430\u0439\u043b \u043c\u043e\u0434\u0435\u043b\u0438 \u0432 <strong>MODEL_STORE_SKLEARN<\/strong>.<br \/>\u0417\u0430\u0442\u0435\u043c \u0444\u0430\u0439\u043b \u043c\u043e\u0434\u0435\u043b\u0438 \u043a\u043e\u043f\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 <strong>SERVINGML_WORKING_DIR<\/strong>.<\/p>\n<\/li>\n<li>\n<p><strong>\u0410\u0440\u0445\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435. <\/strong>\u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 zip-\u0430\u0440\u0445\u0438\u0432 \u0441 \u0438\u043c\u0435\u043d\u0435\u043c &#171;<strong>master.zip<\/strong>&#187; \u0432 <strong>SERVINGML_WORKING_DIR<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0444\u0430\u0439\u043b Dockerfile, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u0438 \u043c\u043e\u0434\u0435\u043b\u044c. \u042d\u0442\u043e\u0442 \u0430\u0440\u0445\u0438\u0432 \u0437\u0430\u0442\u0435\u043c \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0438.<\/p>\n<\/li>\n<\/ol>\n<p><strong><em>servingml_cli\/build.py<\/em><\/strong><\/p>\n<pre><code class=\"python\">import click import yaml import os import shutil import fs import fnmatch  from typing import List from fs.copy import copy_file from types import SimpleNamespace  from jinja2 import Environment, FileSystemLoader  from constants import SERVINGML_WORKING_DIR, MODEL_STORE_SKLEARN, MODEL_STORE_SKLEARN_WORKING   def _generate_dockerfile(app_module: str, requirements: List[str], output_path=\"Dockerfile\") -> None:     # Load the template environment     env = Environment(loader=FileSystemLoader('.'))     template = env.get_template('servingml\/Dockerfile.j2')      # Render the template with variables     rendered_dockerfile = template.render(app_module=app_module, requirements=requirements)      # Write the rendered template to a file     with open(os.path.join(SERVINGML_WORKING_DIR, output_path), 'w') as f:         f.write(rendered_dockerfile)   @click.command() @click.option(\"--build_ctx\", type=click.Path(), default=\".\", show_default=True, help=\"Path to the build context\") @click.option('--servingfile',                default=\"servingfile.yaml\") def build(build_ctx: str, servingfile: str) -> None:     \"\"\"Build Dockerfile for model\"\"\"          # Create project dir     if not os.path.exists(SERVINGML_WORKING_DIR):         os.makedirs(SERVINGML_WORKING_DIR)     else:         try:             shutil.rmtree(SERVINGML_WORKING_DIR)             os.makedirs(SERVINGML_WORKING_DIR)         except OSError as e:             print(f\"Error: {SERVINGML_WORKING_DIR} : {e.strerror}\")     with open(servingfile, 'r') as file:         data = yaml.safe_load(file)         spec = SimpleNamespace(**data)      # Generate dockerfile using spec attributes     _generate_dockerfile(spec.service, spec.packages)      # Add files to the target directory     ctx_fs = fs.open_fs(build_ctx)     target_fs = fs.open_fs(SERVINGML_WORKING_DIR)     for dir_path, _, files in ctx_fs.walk():         for f in files:             path = fs.path.combine(dir_path, f.name).lstrip(\"\/\")             if any(fnmatch.fnmatch(path, pat) for pat in spec.exclude):                 continue  # Skip this file             # Check if the file matches any of the include patterns             if any(fnmatch.fnmatch(path, pat) for pat in spec.include):                 target_fs.makedirs(dir_path, recreate=True)                 copy_file(ctx_fs, path, target_fs, path)      # Copy model to production directory     framework, model_name = spec.model_name.split(\":\")     if framework == \"sklearn\":         model_path = os.path.join(MODEL_STORE_SKLEARN, f\"{model_name}.pkl\")         if not os.path.exists(model_path):             raise ValueError(                 f\"Model {model_name} is not found at the sklearn model store. Make sure you saved it first.\"             )         target_path = os.path.join(MODEL_STORE_SKLEARN_WORKING, f\"{model_name}.pkl\")         if not os.path.exists(MODEL_STORE_SKLEARN_WORKING):             os.makedirs(MODEL_STORE_SKLEARN_WORKING)         shutil.copyfile(model_path, target_path)          # Save all as zip archive for further deploying     shutil.make_archive(\"master\", 'zip', SERVINGML_WORKING_DIR)   if __name__ == '__main__':     build() <\/code><\/pre>\n<p>\u041f\u043e \u0441\u0443\u0442\u0438, \u044d\u0442\u043e\u0442 \u0441\u043a\u0440\u0438\u043f\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0443\u043f\u0430\u043a\u043e\u0432\u043a\u0438 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0432 \u0441\u0440\u0435\u0434\u0443 Docker, \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043a \u043f\u043e\u0442\u0440\u0435\u0431\u043d\u043e\u0441\u0442\u044f\u043c \u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c \u043c\u043e\u0434\u0435\u043b\u0438. \u041e\u043d \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u0443\u0435\u0442 \u0442\u0430\u043a\u0438\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b, \u043a\u0430\u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u043e\u0432 Dockerfile, \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430\u043c\u0438 \u0438 \u0443\u043f\u0430\u043a\u043e\u0432\u043a\u0443 \u043c\u043e\u0434\u0435\u043b\u0435\u0439, \u0432 \u0435\u0434\u0438\u043d\u044b\u0439 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441, \u0447\u0442\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0441\u0442\u0432\u0443\u0435\u0442 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u043c\u0443 \u0438 \u0431\u0435\u0437\u043e\u0448\u0438\u0431\u043e\u0447\u043d\u043e\u043c\u0443 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044e \u043c\u043e\u0434\u0435\u043b\u0435\u0439.<\/p>\n<p>Yaml \u0444\u0430\u0439\u043b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0439 \u0432\u044b\u0448\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0438, \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p><strong><em>servingfile.yaml<\/em><\/strong><\/p>\n<pre><code class=\"python\">service: \"service:app\"  # Starlette application include: - \"*.py\"  # A pattern for matching which files to include in the Bento exclude: - \"venv\/*\" - \"__pycache__\/*\" - \"servingml_server\/*\" - \"servingml_cli\/*\" - \"*.pyc\" packages:  # Additional pip packages required by the Service - scikit-learn - pandas model_name: \"sklearn:iris_clf\" # Saved model name<\/code><\/pre>\n<p>\u041c\u044b \u0438\u043c\u0435\u0435\u043c \u0437\u0434\u0435\u0441\u044c <strong>model_name<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0437 \u0441\u0435\u0431\u044f \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u043b\u0438, \u0438 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0438, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043c\u044b \u0435\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043b\u0438. \u042d\u0442\u043e\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432\u044b\u0448\u0435 \u0432 <strong>build<\/strong> \u043a\u043e\u043c\u043c\u0430\u043d\u0434\u0435.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0443\u043f\u0430\u043a\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u0441\u043e \u0432\u0441\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u043c, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u0441 Dockerfile, \u043a\u043e\u0434\u043e\u043c \u0438 \u043c\u043e\u0434\u0435\u043b\u044c\u044e, \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 \u043d\u0430\u0448 <strong>servingml server<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u0438\u043b\u0438 \u043d\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435.<\/p>\n<p><strong><em>servingml_cli\/deploy.py<\/em><\/strong><\/p>\n<pre><code class=\"python\">import requests import yaml import click import json  from types import SimpleNamespace   @click.command() @click.option('--servingfile',                default=\"servingfile.yaml\") @click.option('--host',                default=\"localhost\") def deploy(servingfile: str, host: str) -> None:     \"\"\"Deploy model using Dockerfile local or remote\"\"\"     with open(servingfile, 'r') as file:             data = yaml.safe_load(file)             spec = SimpleNamespace(**data)     # Copy model to production directory     _, model_name = spec.model_name.split(\":\")     url = f\"http:\/\/{host}:8000\/deploy_project\"  # Modify with your actual endpoint     files = {'file': open('master.zip', 'rb')}     json_data = json.dumps({'modelname': model_name, 'port': 8090})     data = {'data': json_data}     response = requests.post(url, data=data, files=files)     print(\"response\", response.text)   if __name__ == '__main__':     deploy() <\/code><\/pre>\n<p>\u041c\u044b \u0438\u043c\u0435\u0435\u043c api <strong>http:\/\/{host}:8000\/deploy_project<\/strong>, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 <strong>servingml server<\/strong>, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u043c\u0438\u043c\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f <strong>Docker Image<\/strong>, \u0438 \u043f\u043e\u0440\u0442 \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 \u0432 \u0432\u0438\u0434\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430. \u0421\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, port \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0442\u0430\u043a\u0438\u043c \u0436\u0435, \u043a\u0430\u043a \u0438 \u0432 <strong>Dockerfile.j2<\/strong>, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u043b \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u043f\u043e\u0440\u0442 \u0440\u0430\u0431\u043e\u0442\u044b uvicorn \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438 \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043c cli \u0438\u0437 \u044d\u0442\u0438\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0438\u0445 <strong>servingml build<\/strong> \u0438 <strong>servinml deploy<\/strong>. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f \u0434\u0432\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0444\u0430\u0439\u043b\u0430<\/p>\n<p><strong><em>servingml_cli\/cli.py<\/em><\/strong><\/p>\n<pre><code class=\"python\">import click from build import build from deploy import deploy  @click.group() def cli() -> None:     \"\"\"ServingML Command Line Interface.\"\"\"     pass  cli.add_command(build) cli.add_command(deploy)  if __name__ == \"__main__\":     cli() <\/code><\/pre>\n<p><strong><em>servingml_cli\/setup.py<\/em><\/strong><\/p>\n<pre><code class=\"python\">from setuptools import setup  setup(     name='servingml',     version='0.1',     py_modules=['cli', 'build', 'deploy'],     install_requires=[         'Click',     ],     entry_points='''         [console_scripts]         servingml=cli:cli     ''', ) <\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e, \u043d\u0430\u0445\u043e\u0434\u044f\u0441\u044c \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <strong>servingml_cli<\/strong>, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043a\u043e\u043c\u043c\u0430\u043d\u0434\u0443<\/p>\n<pre><code class=\"powershell\">pip install --editable .<\/code><\/pre>\n<h2>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0441\u0435\u0440\u0432\u0435\u0440 servingml<\/h2>\n<p>\u0421\u0435\u0440\u0432\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0443\u043f\u0430\u043a\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0438\u0437 \u043d\u0435\u0433\u043e docker \u043e\u0431\u0440\u0430\u0437, \u0430 \u0437\u0430\u0442\u0435\u043c \u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440, \u044d\u0442\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043d\u0430\u0448\u0435\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b. \u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f api endpoint <strong>\/deploy_project<\/strong>, \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c fastapi. <\/p>\n<p>\u041d\u0438\u0436\u0435, <strong>deploy_project<\/strong> \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0430\u0441\u043f\u043e\u043a\u043e\u0432\u044b\u0432\u0430\u0435\u0442 \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0435\u0441\u0442\u044c \u0432 \u043d\u0435\u0439 Dockerfile, \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u0443\u0442\u044c \u043a \u043d\u0435\u043c\u0443 \u0441 \u0434\u043e\u043f. \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u0432 <strong>backgound task<\/strong>, \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f <strong>docker image<\/strong> \u0438 <strong>docker container<\/strong>.<\/p>\n<p><strong><em>servingml_server\/server.py<\/em><\/strong><\/p>\n<pre><code class=\"python\">@app.post(\"\/deploy_project\") async def deploy_project(     background_tasks: BackgroundTasks,      data: str = Form(...),      file: UploadFile = File(...) ) -> Dict[str, str]:     try:         build_data = json.loads(data)         build_data = BuildData(**build_data)     except (json.JSONDecodeError, ValidationError) as e:         return {\"error\": f\"Invalid input data: {str(e)}\"}     # Temporary directory to extract files     temp_dir = \"temp_docker_build\"     os.makedirs(temp_dir, exist_ok=True)      temp_file_path = os.path.join(temp_dir, file.filename)      # Save the uploaded file to disk     with open(temp_file_path, \"wb\") as buffer:         buffer.write(file.file.read())  # Read from SpooledTemporaryFile and write to disk      # Extract the ZIP file     with zipfile.ZipFile(temp_file_path, 'r') as zip_ref:         zip_ref.extractall(temp_dir)      # Check if Dockerfile is present     if not os.path.exists(os.path.join(temp_dir, 'Dockerfile')):         return {\"error\": \"Dockerfile not found in the zip\"}      # Build Docker image     image_tag = f\"{build_data.modelname}:latest\"  # You can customize this     background_tasks.add_task(         background_docker_build_task, temp_dir, image_tag, build_data.port, \"docker_build_log.txt\",     )     return {\"message\": \"Docker build started\"}<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f subprocess \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0437\u0434\u0435\u0441\u044c asyncio<\/p>\n<pre><code class=\"python\">async def exec_command(command, log_file_path):     process = await asyncio.create_subprocess_shell(         command,         stdout=asyncio.subprocess.PIPE,         stderr=asyncio.subprocess.PIPE,     )      stdout, stderr = await process.communicate()      with open(log_file_path, \"a\") as log_file:         if stdout:             log_file.write(f\"[stdout]\\n{stdout.decode()}\\n\")         if stderr:             log_file.write(f\"[stderr]\\n{stderr.decode()}\\n\")   async def docker_build_task(temp_dir: str, image_tag: str, port: int, log_file_path: str):     try:         # Step 1: Build the Docker image asynchronously         build_command = f\"docker build -t {image_tag} {temp_dir}\"         await exec_command(build_command, log_file_path)          # Step 2: Run a container from the built image asynchronously         run_command = f\"docker run -d -p {port}:{port} {image_tag}\"         await exec_command(run_command, log_file_path)      except Exception as e:         # Log any errors during the build or run process         with open(log_file_path, \"a\") as log_file:             log_file.write(f\"Error during Docker operations: {e}\\n\")     finally:         # Cleanup         shutil.rmtree(temp_dir)   def background_docker_build_task(temp_dir, image_tag, port, log_file_path):     asyncio.run(docker_build_task(temp_dir, image_tag, port, log_file_path))<\/code><\/pre>\n<p>\u041a\u043e\u0434 \u0432\u044b\u0448\u0435, \u044d\u0442\u043e \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f docker image \u0438\u0437 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u0435\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u0438. \u0422\u0435\u043f\u0435\u0440\u044c, \u0432\u0441\u0435, \u0447\u0442\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0437\u0434\u0435\u0441\u044c, \u044d\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f dockerfile \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0435\u0433\u043e image, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u0442\u0435\u043c \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043d\u0430 dockerhub \u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u043d\u0430 \u043b\u044e\u0431\u043e\u0439 \u0441\u0435\u0440\u0432\u0435\u0440.<\/p>\n<p><strong><em>servingml_server\/Dockerfile<\/em><\/strong><\/p>\n<pre><code class=\"python\"># Use an official Python runtime as a parent image FROM python:3.9-slim  # Set the working directory in the container WORKDIR \/usr\/src\/app  # Copy the local code to the container COPY . .  # Install Docker CLI RUN apt-get update &amp;&amp; apt-get install -y docker.io  # Install any needed packages specified in requirements.txt RUN pip install --no-cache-dir fastapi[all] uvicorn  # Make port 8000 available to the world outside this container EXPOSE 8000  # Define environment variable ENV NAME World  # Run app.py when the container launches CMD [\"uvicorn\", \"server:app\", \"--host\", \"0.0.0.0\", \"--port\", \"8000\"] <\/code><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c image \u0434\u043b\u044f <strong>servingml server<\/strong><\/p>\n<pre><code class=\"powershell\">docker build -t servingml_server .<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043c\u043e\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u043a\u0435\u0442 Docker \u0445\u043e\u0441\u0442\u0430 \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440. \u0414\u0435\u043b\u0430\u044f \u044d\u0442\u043e, \u043c\u044b \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0443 \u0434\u043e\u0441\u0442\u0443\u043f \u043a daemon Docker \u043d\u0430 \u0445\u043e\u0441\u0442\u0435, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0435\u043c\u0443 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b Docker \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u043c\u0438. \u041f\u043e \u0441\u0443\u0442\u0438, \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0441\u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u043c\u0438 \u0432 \u0445\u043e\u0441\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0435.<\/p>\n<pre><code class=\"powershell\">docker run -d -v \/var\/run\/docker.sock:\/var\/run\/docker.sock -p 8000:8000 servingml_server<\/code><\/pre>\n<p>\u041e\u0442\u043b\u0438\u0447\u043d\u043e! \u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c <strong>servingml server<\/strong> \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u043d\u0430\u0448\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438\u0437 \u043d\u0438\u0445 docker conrainer&#8217;s. \u0427\u0442\u043e \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c \u0441\u0435\u0440\u0432\u0438\u043d\u0433 \u0438 \u0434\u0435\u043f\u043b\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f.<\/p>\n<h2>\u0414\u0435\u043f\u043b\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043c\u043e\u0434\u0435\u043b\u0438 \u0447\u0435\u0440\u0435\u0437 cli \u0438 \u0442\u0435\u0441\u0442 api endpoint<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u0434\u0435\u043f\u043b\u043e\u0438\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u043c\u043e\u0434\u0435\u043b\u0438, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0435\u0433\u043e, \u0441\u0434\u0435\u043b\u0430\u0432 \u0438\u0437 \u043d\u0435\u0433\u043e \u0430\u0440\u0445\u0438\u0432<\/p>\n<pre><code class=\"powershell\">servingml build --build-ctx project_path<\/code><\/pre>\n<p>\u0418 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0434\u0435\u043f\u043b\u043e\u0439 \u0430\u0440\u0445\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441 \u043f\u0435\u0440\u0435\u0434\u0430\u0432 \u0435\u0433\u043e \u043d\u0430\u0448\u0435\u043c\u0443 <strong>servingml server<\/strong><\/p>\n<pre><code class=\"powershell\">servingml deploy --host your_host<\/code><\/pre>\n<p>\u0414\u0435\u043f\u043b\u043e\u0439 \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043d\u044f\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0438\u043d\u0443\u0442 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u0414\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0433\u043e\u0442\u043e\u0432 \u043b\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043b\u0438\u0431\u043e \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0435\u0433\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e docker ps, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 image, \u043b\u0438\u0431\u043e \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043b\u043e\u0433\u0438. <\/p>\n<pre><code class=\"powershell\">docker cp container_name:\/usr\/src\/app\/docker_build_log.txt .\/docker_build_log.txt<\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0444\u0430\u0439\u043b\u0430 \u043b\u043e\u0433\u043e\u0432 \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435 \u0435\u0449\u0435 \u043d\u0435\u0442, \u0437\u043d\u0430\u0447\u0438\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0441\u043e\u0437\u0434\u043d\u0438\u044f <strong>image<\/strong> \u0432\u0441\u0435 \u0435\u0449\u0435 \u0438\u0434\u0435\u0442.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0449\u0435\u043d, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441 \u043a \u043d\u0430\u0448\u0435\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c<\/p>\n<p><strong>invoke.py<\/strong><\/p>\n<pre><code class=\"python\">import requests  # Endpoint URL url = \"http:\/\/localhost:8090\/v2\/models\/iris_clf\/infer\"  sample_input = [[5.1, 3.5, 1.4, 0.2]]  # Constructing the payload payload = {     \"inputs\": sample_input }  # Make a POST request response = requests.post(url, json=payload)  # Checking response if response.status_code == 200:     print(\"Success:\", response.json()) else:     print(\"Error:\", response.text) <\/code><\/pre>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043e\u0442\u0432\u0435\u0442\u0430 \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u043a\u043b\u0430\u0441\u0441\u0430 iris.<\/p>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0412 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u044f \u043e\u043f\u0438\u0440\u0430\u043b\u0441\u044f \u043d\u0430 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 bentoml \u0438 mlrun. \u042d\u0442\u043e\u0442 \u043a\u043e\u0434 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0432 production, \u0434\u0430\u0436\u0435 \u043d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u043e\u043d \u0440\u0430\u0431\u043e\u0447\u0438\u0439, \u0441\u0442\u043e\u0438\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0443\u0436\u0435 \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0441 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0431\u043e\u043b\u044c\u0448\u0438\u043c \u0444\u0443\u043a\u043d\u0446\u0438\u043e\u043d\u0430\u043b\u043e\u043c \u0438 \u043d\u0430\u0434\u0435\u0436\u043d\u043e\u0441\u0442\u044c\u044e. \u0415\u0441\u043b\u0438 \u0432\u044b \u0434\u0435\u043b\u0430\u0435\u0442\u0435 \u0434\u0435\u043f\u043b\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 \u043d\u0430 kubernetes \u044f \u0441\u043e\u0432\u0435\u0442\u0443\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c seldon core \u0441 \u0435\u0433\u043e \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 alibi detect, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c data drift, \u0435\u0441\u043b\u0438 \u0436\u0435 \u0432\u044b \u0434\u0435\u043b\u0430\u0435\u0442\u0435 \u0434\u0435\u043f\u043b\u043e\u0439 \u043d\u0430 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0447\u0430\u0441\u0442\u044c\u044e \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430 kubernetes \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 bentoml.<\/p>\n<p>\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0437\u0434\u0435\u0441\u044c &#8212; <a href=\"https:\/\/github.com\/Nikitala0014\/servingml\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/Nikitala0014\/servingml<\/a><\/p>\n<p>\u0422\u0435\u043b\u0435\u0433\u0440\u0430\u043c \u0434\u043b\u044f \u0441\u0432\u044f\u0437\u0438 &#8212; @NLavrenov00<\/p>\n<p>\u041d\u0430\u0434\u0435\u044e\u0441\u044c \u0432\u0430\u043c \u0431\u044b\u043b\u043e \u0442\u0430\u043a\u0436\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u043a\u0430\u043a \u0438 \u043c\u043d\u0435 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044f \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \ud83d\ude42<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/770886\/\"> https:\/\/habr.com\/ru\/articles\/770886\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041f\u043e \u0441\u0432\u043e\u0435\u0439 \u0441\u0443\u0442\u0438 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043e\u0431\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c\u0438 \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0441\u0438\u0441\u0442\u0435\u043c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u043c \u0438 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c. \u042d\u0442\u043e \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0448\u0430\u0433 \u0432 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u043c \u0446\u0438\u043a\u043b\u0435 \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0412 \u044d\u0442\u043e\u043c \u043e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u0438 \u043c\u044b \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u043c\u0441\u044f \u043d\u0430 \u043a\u043e\u043d\u0446\u0435\u043f\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0431\u0443\u0434\u0435\u043c \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c `<strong>servingml`<\/strong>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0438 \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0442\u0438\u043f\u0438\u0447\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u043d\u0433\u0430 \u043c\u043e\u0434\u0435\u043b\u0438.<\/p>\n<h2>\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b servingml Framework<\/h2>\n<p>\u0424\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a servingml \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0434\u043b\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0438 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f. \u041e\u043d \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0432\u0437\u0430\u0438\u043c\u043e\u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432, \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0438\u0433\u0440\u0430\u0435\u0442 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e \u0432\u0430\u0436\u043d\u0443\u044e \u0440\u043e\u043b\u044c \u0432 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u0438\u0441\u0442\u0435\u043c\u044b:<\/p>\n<ol>\n<li>\n<p><strong>Core<\/strong>. \u0412 \u043e\u0441\u043d\u043e\u0432\u0435 `<strong>servingml`<\/strong> \u043b\u0435\u0436\u0438\u0442 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043e\u0432 \u043c\u043e\u0434\u0435\u043b\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442 \u043e\u0441\u043d\u043e\u0432\u0443 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430. \u042d\u0442\u043e \u044f\u0434\u0440\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u043c \u0438 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e \u0441 scikit-learn \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0430, \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0440\u0443\u0433\u0438\u0445, \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0447\u0442\u043e \u0448\u0438\u0440\u043e\u043a\u0438\u0439 \u0441\u043f\u0435\u043a\u0442\u0440 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043d\u0430\u0448\u0435\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b.<\/p>\n<\/li>\n<li>\n<p><strong>CLI and Build Tools<\/strong>. \u0427\u0442\u043e\u0431\u044b \u043e\u0431\u043b\u0435\u0433\u0447\u0438\u0442\u044c \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043e\u0442 \u043e\u0431\u0443\u0447\u0435\u043d\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 \u043a \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u0435\u043c\u043e\u043c\u0443 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u0443, \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 (CLI) \u0434\u043b\u044f `<strong>servingml`<\/strong>. \u0417\u0430\u0434\u0430\u0447\u0430 \u044d\u0442\u043e\u0433\u043e CLI \u2014 \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0439 \u043a\u043e\u0434 \u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u043e\u0434\u043d\u043e\u043c \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435. \u042d\u0442\u0430 \u043a\u043e\u043d\u0441\u043e\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u0430\u0436\u043d\u044b\u043c \u0448\u0430\u0433\u043e\u043c, \u0443\u043f\u0440\u043e\u0449\u0430\u044e\u0449\u0438\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u0435\u0435 \u0441\u0440\u0435\u0434\u044b.<\/p>\n<\/li>\n<li>\n<p><strong>Project Configuration via YAML<\/strong>. \u041f\u0440\u0438\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c\u044e \u043c\u043d\u043e\u0433\u0438\u0445 Model Serving \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 YAML \u0434\u043b\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u0412 \u044d\u0442\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u044b \u0432\u0430\u0436\u043d\u044b\u0435 \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u044f, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u043c\u043e\u0434\u0435\u043b\u0438, \u0438\u043c\u044f \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u043f\u0443\u0442\u044c \u043a \u0441\u0435\u0440\u0432\u0438\u0441\u0443. \u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438, \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u044f \u0447\u0435\u0442\u043a\u043e\u0435 \u0438 \u0443\u0434\u043e\u0431\u043d\u043e\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430.<\/p>\n<\/li>\n<li>\n<p><strong>Docker Integration<\/strong>. \u0426\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u043e\u0435 \u043c\u0435\u0441\u0442\u043e \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 Docker. \u041f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 `<strong>servingml`<\/strong> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0448\u0430\u0431\u043b\u043e\u043d Dockerfile (<strong>Dockerfile.j2<\/strong>), \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u043f\u0438\u0441\u0430\u043d\u043e, \u043a\u0430\u043a \u0443\u043f\u0430\u043a\u043e\u0432\u0430\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0435\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 Docker. \u042d\u0442\u043e\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442, \u0447\u0442\u043e \u043c\u043e\u0434\u0435\u043b\u044c \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0432 \u043b\u044e\u0431\u043e\u0439 \u0441\u0440\u0435\u0434\u0435, \u0443\u0441\u0442\u0440\u0430\u043d\u044f\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b, \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u044e\u0449\u0438\u0435 \u0438\u0437-\u0437\u0430 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0438\u043b\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p><strong>ServingML Server and Deployment<\/strong>. \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0447\u0430\u0441\u0442\u044c\u044e \u0433\u043e\u043b\u043e\u0432\u043e\u043b\u043e\u043c\u043a\u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0435\u0440\u0432\u0435\u0440 ServingML. \u042d\u0442\u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 Docker, \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0435\u0433\u043e \u043c\u043e\u0434\u0435\u043b\u044c, \u0444\u0430\u0439\u043b Dockerfile \u0438 \u043b\u044e\u0431\u043e\u0439 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0439 \u043a\u043e\u0434. \u0417\u0430\u0442\u0435\u043c \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0437 Docker \u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u0430. \u041f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043c\u043e\u0434\u0435\u043b\u044c \u0441\u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u0440\u043e\u0433\u043d\u043e\u0437\u044b \u0447\u0435\u0440\u0435\u0437 REST API \u0434\u043b\u044f \u043e\u0431\u044b\u0447\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.<\/p>\n<\/li>\n<\/ol>\n<p>\u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0440\u0430\u0437\u0434\u0435\u043b\u0430\u0445 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u044d\u0442\u0438\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432, \u0438\u0437\u0443\u0447\u0430\u044f, \u043a\u0430\u043a \u043e\u043d\u0438 \u0432\u043b\u0438\u044f\u044e\u0442 \u043d\u0430 \u043e\u0431\u0449\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c <strong>servingml<\/strong>. \u041d\u0430\u0448 \u043f\u0443\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0434\u0435\u0442 \u043d\u0430\u0441 \u043e\u0442 \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0439 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043c\u043e\u0434\u0435\u043b\u0438 \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u043e \u0435\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0438 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f.<\/p>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f Model Serving \u043a\u043b\u0430\u0441\u0441\u0430 \u0434\u043b\u044f \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438<\/h2>\n<p>\u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e, \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 <strong>ModelServer, <\/strong>\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u043c \u043a\u043b\u0430\u0441\u0441\u043e\u043c \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f <strong>load<\/strong>, <strong>predict<\/strong>, <strong>preprocess<\/strong> \u0438 <strong>postprocess<\/strong> \u043c\u0435\u0442\u043e\u0434\u043e\u0432. <strong>ModelServer<\/strong> \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u044d\u0442\u0438\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 api \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c <strong>Starlette.<\/strong><\/p>\n<p><strong><em>service.py<\/em><\/strong><\/p>\n<pre><code class=\"python\">import numpy as np  import Starlette  from typing import Dict, List  from servingml import ModelServer from servingml.frameworks.sklearn import load_model   class ModelClass(ModelServer):     def load(self):         self.model = load_model(\"iris_clf\")      def predict(self, body: Dict) -> List:         \"\"\"Generate model predictions from sample\"\"\"         sample_input = np.asarray(body['inputs'])         result: np.ndarray = self.model.predict(sample_input)         return result.tolist()      def postprocess(self, sample_output: List) -> str:         \"\"\"Make postprocessing for returning class name\"\"\"         target_names = ['setosa', 'versicolor', 'virginica']         # Convert numeric prediction to species name         predicted_species = target_names[sample_output[0]]         return predicted_species   model_class = ModelClass(     model_name=\"iris_clf\", )  app: Starlette = model_class.asgi_app <\/code><\/pre>\n<p>\u042d\u0442\u043e \u043d\u0430\u0448 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439 \u043a\u043e\u0434. \u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u043e\u0431\u0443\u0447\u0435\u043d\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0432 \u043d\u0430\u0448\u0435\u043c model store, \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <strong>predict<\/strong>, \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u0438 <strong>postprocess<\/strong>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441, \u0432\u043c\u0435\u0441\u0442\u043e \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e\u0441\u0442\u0435\u0439.<\/p>\n<p>\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f <strong>app<\/strong> \u0437\u0434\u0435\u0441\u044c, \u044d\u0442\u043e <strong>Starlette<\/strong> \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0437\u0430\u0442\u0435\u043c \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f uvicorn \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f asgi \u0441\u0435\u0440\u0432\u0435\u0440\u0430.<\/p>\n<p>\u042d\u0442\u043e <strong>ModelServer<\/strong> \u043a\u043b\u0430\u0441\u0441<\/p>\n<p><strong><em>servingml._model_server.py<\/em><\/strong><\/p>\n<pre><code class=\"python\">from typing import Dict, Any from starlette.applications import Starlette from starlette.requests import Request from starlette.responses import JSONResponse from starlette.routing import Route import logging  class ModelServer:     \"\"\"Class that creates a Starlette app for serving a machine learning model.\"\"\"          def __init__(self, model_name: str) -> None:         self.model_name = model_name         self.model = self.load()         logging.basicConfig(level=logging.INFO)      @property     def asgi_app(self) -> Starlette:         return Starlette(routes=[             Route(f\"\/v2\/models\/{self.model_name}\/infer\", self._predict_fn, methods=[\"POST\"]),         ])      async def _predict_fn(self, request: Request) -> JSONResponse:         \"\"\"Handler for the Starlette application.\"\"\"         try:             data = await request.json()             if not data:                 return JSONResponse({\"error\": \"Invalid input data\"}, status_code=400)             processed_data = self.preprocess(data)             prediction = self.predict(processed_data)             result = self.postprocess(prediction)             return JSONResponse({\"result\": result})         except Exception as e:             logging.error(f\"Error during prediction: {e}\")             return JSONResponse({\"error\": \"Error processing request\"}, status_code=500)      def load(self) -> Any:         \"\"\"Model loading operation.\"\"\"         raise NotImplementedError()      def preprocess(self, body: Dict) -> Any:         \"\"\"Preprocess the event body before validation and action.\"\"\"         return body      def postprocess(self, result: Any) -> Any:         \"\"\"Postprocess the prediction before returning response.\"\"\"         return result      def predict(self, data: Any) -> Any:         \"\"\"Model prediction operation.\"\"\"         raise NotImplementedError() <\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 endpoint \u0434\u043b\u044f \u043c\u043e\u0434\u0435\u043b\u0438: <strong>\/v2\/models\/{self.model_name}\/infer<\/strong>, \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <strong>V2 Inference Protocol<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043e\u043c \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 Model Serving \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a Seldon Core, Bentoml, Nvidia Triton, Onnx Runtime Server \u0438 \u0434\u0440. <\/p>\n<h2>\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0441 scikit-learn<\/h2>\n<p>\u0421\u0443\u0442\u044c \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435, \u044d\u0442\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043e\u0431\u0443\u0447\u0435\u043d\u043d\u043e\u0439 scikit-learn \u043c\u043e\u0434\u0435\u043b\u0438 \u0432 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 model store, \u0438 \u0435\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0432 \u043f\u0430\u043c\u044f\u0442\u044c \u0434\u043b\u044f \u0438\u043d\u0444\u0435\u0440\u0435\u043d\u0441\u0430.<\/p>\n<p><strong><em>servingml.frameworks.sklearn.py<\/em><\/strong>  <\/p>\n<pre><code class=\"python\">import os import joblib  from typing import Union  from sklearn.base import BaseEstimator from sklearn.pipeline import Pipeline  from servingml.constants import MODEL_STORE_SKLEARN, MODEL_STORE_SKLEARN_WORKING   SklearnModel = Union[BaseEstimator, Pipeline]   def save_model(model_name: str, model: SklearnModel) -> None:     if not os.path.exists(MODEL_STORE_SKLEARN):         os.makedirs(MODEL_STORE_SKLEARN)     model_path = os.path.join(MODEL_STORE_SKLEARN, f\"{model_name}.pkl\")     joblib.dump(model, model_path)   def load_model(model_name: str) -> SklearnModel:     print(\"MODEL_STORE_SKLEARN_WORKING\", MODEL_STORE_SKLEARN_WORKING)     model_path = os.path.join(MODEL_STORE_SKLEARN_WORKING, f\"{model_name}.pkl\")     if not os.path.exists(model_path):         raise ValueError(             f\"Model {model_name} is not found at the sklearn model store. Make sure you saved it first.\"         )     return joblib.load(model_path) <\/code><\/pre>\n<p>\u0413\u0434\u0435 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c<\/p>\n<p><strong><em>servingml.frameworks.constants.py<\/em><\/strong><\/p>\n<pre><code class=\"python\">import os   home_directory = os.path.expanduser(\"~\") SERVINGML_WORKING_DIR = os.path.join(home_directory, \"servingml\/svc\") MODEL_STORE_DIR = os.path.join(home_directory, \"servingml\/model_store\") MODEL_STORE_SKLEARN = os.path.join(MODEL_STORE_DIR, \"sklearn\") MODEL_STORE_SKLEARN_WORKING = \".\/model_store\/sklearn\" <\/code><\/pre>\n<p>\u042d\u0442\u043e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u0440\u0430\u043d\u0438\u0442 \u0432\u0441\u0435 \u043d\u0443\u0436\u043d\u044b\u0435 \u0430\u0440\u0442\u0438\u0444\u0430\u043a\u0442\u044b \u0434\u043b\u044f \u0441\u0435\u0440\u0432\u0438\u043d\u0433\u0430 \u043c\u043e\u0434\u0435\u043b\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0435\u043a\u0446\u0438\u0438 \u043f\u0440\u043e cli.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0438\u043c\u0435\u0435\u043c \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e \u0441 scikit-learn \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0431\u0443\u0447\u0438\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u043d\u0430\u0448\u0435\u043c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c model store<\/p>\n<p><strong><em>download_model.py<\/em><\/strong><\/p>\n<pre><code class=\"python\">from sklearn import svm from sklearn import datasets  from servingml.frameworks.sklearn import save_model  # Load training data set iris = datasets.load_iris() X, y = iris.data, iris.target  # Train the model clf = svm.SVC(gamma='scale') clf.fit(X, y)  # Save model to the local Model Store saved_model = save_model(\"iris_clf\", clf)<\/code><\/pre>\n<h2>CLI \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u0434\u0435\u043f\u043b\u043e\u044f<\/h2>\n<p>\u0412 \u044d\u0442\u043e\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u043c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 Python, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 servingml cli \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f Dockerfile, \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u043a \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044e. \u042d\u0442\u043e\u0442 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f, \u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u043d\u043d\u043e\u0441\u0442\u044c \u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0441\u0440\u0435\u0434\u0430\u0445.<\/p>\n<p>\u0412 cli \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0434\u0432\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b <strong>build<\/strong>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u0437\u0434\u0430\u0435\u0442 Dockerfile \u0434\u043b\u044f \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u044b \u0434\u043b\u044f \u043d\u0435\u0433\u043e, \u0438 <strong>deploy<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u044d\u0442\u043e zip \u0430\u0440\u0445\u0438\u0432 \u043d\u0430 <strong>servingml server<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043a\u0430\u043a \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e, \u0442\u0430\u043a \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e.<\/p>\n<p>\u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u0437\u0434\u0430\u0435\u0442 Dockerfile \u0438\u0437 \u0448\u0430\u0431\u043b\u043e\u043d\u0430<\/p>\n<pre><code class=\"python\">def _generate_dockerfile(app_module: str, requirements: List[str], output_path=\"Dockerfile\") -> None:     # Load the template environment     env = Environment(loader=FileSystemLoader('.'))     template = env.get_template('servingml\/Dockerfile.j2')      # Render the template with variables     rendered_dockerfile = template.render(app_module=app_module, requirements=requirements)      # Write the rendered template to a file     with open(os.path.join(SERVINGML_WORKING_DIR, output_path), 'w') as f:         f.write(rendered_dockerfile)<\/code><\/pre>\n<p>\u041c\u044b \u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u0432 \u0448\u0430\u0431\u043b\u043e\u043d\u0435 \u0443 \u043d\u0430\u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f <strong>app_module<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0443\u0442\u0435\u043c \u043a \u043d\u0430\u0448\u0435\u043c\u0443 <strong>Starlette<\/strong><\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-358899","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/358899","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=358899"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/358899\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=358899"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=358899"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=358899"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}