{"id":308948,"date":"2020-08-24T21:00:50","date_gmt":"2020-08-24T21:00:50","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=308948"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=308948","title":{"rendered":"\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 Spark \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e MLflow"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/company\/otus\/blog\/516420\/\"><b><i>\u041f\u0440\u0438\u0432\u0435\u0442, \u0445\u0430\u0431\u0440\u043e\u0432\u0447\u0430\u043d\u0435. \u041a\u0430\u043a \u043c\u044b \u0443\u0436\u0435 \u043f\u0438\u0441\u0430\u043b\u0438, \u0432 \u044d\u0442\u043e\u043c \u043c\u0435\u0441\u044f\u0446\u0435 OTUS \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0441\u0440\u0430\u0437\u0443 \u0434\u0432\u0430 \u043a\u0443\u0440\u0441\u0430 \u043f\u043e \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u043c\u0443 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044e, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e <a href=\"https:\/\/otus.pw\/h8IZ\/\">\u0431\u0430\u0437\u043e\u0432\u044b\u0439<\/a> \u0438 <a href=\"https:\/\/otus.pw\/jut8\/\">\u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439<\/a>. \u0412 \u0441\u0432\u044f\u0437\u0438 \u0441 \u044d\u0442\u0438\u043c \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u043c.<\/i><\/b><\/p>\n<hr>\n<p>  \u0426\u0435\u043b\u044c \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u2013 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043e \u043d\u0430\u0448\u0435\u043c \u043f\u0435\u0440\u0432\u043e\u043c \u043e\u043f\u044b\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f <a href=\"https:\/\/mlflow.org\/\">MLflow<\/a>.<\/p>\n<p>  \u041c\u044b \u043d\u0430\u0447\u043d\u0435\u043c \u043e\u0431\u0437\u043e\u0440 <a href=\"https:\/\/mlflow.org\/docs\/latest\/tracking.html\">MLflow<\/a> \u0441 \u0435\u0433\u043e tracking-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438 \u043f\u0440\u043e\u043b\u043e\u0433\u0438\u0440\u0443\u0435\u043c \u0432\u0441\u0435 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438 \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f. \u0417\u0430\u0442\u0435\u043c \u043f\u043e\u0434\u0435\u043b\u0438\u043c\u0441\u044f \u043e\u043f\u044b\u0442\u043e\u043c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f Spark \u0441 MLflow \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e UDF. <a name=\"habracut\"><\/a><\/p>\n<h3>\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442<\/h3>\n<p>  \u041c\u044b \u0432 <a href=\"http:\/\/alpha.company\/moonshots\/alpha-health\">Alpha Health<\/a> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0435 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435 \u0438 \u0438\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442, \u0447\u0442\u043e\u0431\u044b \u0434\u0430\u0442\u044c \u043b\u044e\u0434\u044f\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u0431\u043e\u0442\u0438\u0442\u044c\u0441\u044f \u043e \u0441\u0432\u043e\u0435\u043c \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u0435 \u0438 \u0431\u043b\u0430\u0433\u043e\u043f\u043e\u043b\u0443\u0447\u0438\u0438. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u0434\u0435\u043b\u0438 \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u043b\u0435\u0436\u0430\u0442 \u0432 \u043e\u0441\u043d\u043e\u0432\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u044b\u0445 \u043d\u0430\u043c\u0438 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u0438 \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u0448\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u0432\u043b\u0435\u043a\u043b\u0430 MLflow \u2014 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0432\u0441\u0435 \u0430\u0441\u043f\u0435\u043a\u0442\u044b \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430 \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f. <\/p>\n<h3>MLflow<\/h3>\n<p>  \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0446\u0435\u043b\u044c MLflow \u2013 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u043f\u043e\u0432\u0435\u0440\u0445 \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b \u0431\u044b \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442\u0430\u043c \u043f\u043e data science \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441 \u043b\u044e\u0431\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f (<a href=\"https:\/\/github.com\/h2oai\">h2o<\/a>, <a href=\"https:\/\/keras.io\/\">keras<\/a>, <a href=\"http:\/\/mleap-docs.combust.ml\/\">mleap<\/a>, <a href=\"https:\/\/pytorch.org\/\">pytorch<\/a>, <a href=\"http:\/\/scikit-learn.org\/stable\/\">sklearn<\/a> \u0438 <a href=\"https:\/\/www.tensorflow.org\/\">tensorflow<\/a>), \u0432\u044b\u0432\u043e\u0434\u044f \u0435\u0435 \u0440\u0430\u0431\u043e\u0442\u0443 \u043d\u0430 \u043d\u043e\u0432\u044b\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c.<\/p>\n<p>  MLflow \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0442\u0440\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430:<\/p>\n<ul>\n<li><b>Tracking <\/b>\u2013 \u0437\u0430\u043f\u0438\u0441\u044c \u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430\u043c: \u043a\u043e\u0434, \u0434\u0430\u043d\u043d\u044b\u0435, \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b. \u0421\u043b\u0435\u0434\u0438\u0442\u044c \u0437\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0438 \u043e\u0447\u0435\u043d\u044c \u0432\u0430\u0436\u043d\u043e.<\/li>\n<li><b>Projects<\/b> \u2013 \u0424\u043e\u0440\u043c\u0430\u0442 \u0443\u043f\u0430\u043a\u043e\u0432\u043a\u0438 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043d\u0430 \u043b\u044e\u0431\u043e\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <a href=\"https:\/\/aws.amazon.com\/ru\/sagemaker\/\">SageMaker<\/a>)<\/li>\n<li><b>Models<\/b> \u2013 \u043e\u0431\u0449\u0438\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0432 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f.<\/li>\n<\/ul>\n<p>  <\/p>\n<blockquote><p>MLflow (\u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 \u0432 alpha-\u0432\u0435\u0440\u0441\u0438\u0438) \u2014 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u043c \u0446\u0438\u043a\u043b\u043e\u043c \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430\u043c\u0438, \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435\u043c.<\/p><\/blockquote>\n<p>  <\/p>\n<h3>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 MLflow<\/h3>\n<p>  \u0414\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f MLflow \u043d\u0443\u0436\u043d\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0432\u0441\u044e \u0441\u0440\u0435\u0434\u0443 Python, \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f <a href=\"https:\/\/github.com\/pyenv\/pyenv\">PyEnv<\/a> (\u0447\u0442\u043e\u0431\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c Python \u043d\u0430 Mac, \u0437\u0430\u0433\u043b\u044f\u043d\u0438\u0442\u0435 <a href=\"https:\/\/gist.github.com\/chris-zen\/9e61db6924bd37fbe414f648614ca4c5\">\u0441\u044e\u0434\u0430<\/a>). \u0422\u0430\u043a \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u0443\u044e \u0441\u0440\u0435\u0434\u0443, \u043a\u0443\u0434\u0430 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438.<\/p>\n<pre><code class=\"python\">``` pyenv install 3.7.0 pyenv global 3.7.0 # Use Python 3.7 mkvirtualenv mlflow # Create a Virtual Env with Python 3.7 workon mlflow ```<\/code><\/pre>\n<p>  \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438.<\/p>\n<pre><code class=\"python\">``` pip install mlflow==0.7.0 \\             Cython==0.29 \\              numpy==1.14.5 \\             pandas==0.23.4 \\             pyarrow==0.11.0 ```<\/code><\/pre>\n<p>  <\/p>\n<blockquote><p>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435: \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c PyArrow \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0430\u043a\u0438\u0445 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u043a\u0430\u043a UDF. \u0412\u0435\u0440\u0441\u0438\u0438 PyArrow \u0438 Numpy \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u043e\u0432\u0430\u043b\u0438 \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u0431\u043e\u0439.<\/p><\/blockquote>\n<h3>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c Tracking UI<\/h3>\n<p>  MLflow Tracking \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u0434\u0435\u043b\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Python \u0438 <a href=\"https:\/\/mlflow.org\/docs\/latest\/rest-api.html#rest-api\">REST<\/a> API. \u041f\u043e\u043c\u0438\u043c\u043e \u044d\u0442\u043e\u0433\u043e, \u043c\u043e\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c, \u0433\u0434\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u044b \u043c\u043e\u0434\u0435\u043b\u0438 (localhost, <a href=\"https:\/\/mlflow.org\/docs\/latest\/tracking.html#amazon-s3\">Amazon S3<\/a>, <a href=\"https:\/\/mlflow.org\/docs\/latest\/tracking.html#azure-blob-storage\">Azure Blob Storage<\/a>, <a href=\"https:\/\/mlflow.org\/docs\/latest\/tracking.html#google-cloud-storage\">Google Cloud Storage<\/a> \u0438\u043b\u0438 <a href=\"https:\/\/mlflow.org\/docs\/latest\/tracking.html#sftp-server\">SFTP-\u0441\u0435\u0440\u0432\u0435\u0440<\/a>). \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0432 Alpha Health \u043c\u044b \u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f AWS, \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u043e\u0432 \u0431\u0443\u0434\u0435\u0442 S3.<\/p>\n<pre><code class=\"python\"># Running a Tracking Server mlflow server \\     --file-store \/tmp\/mlflow\/fileStore \\     --default-artifact-root s3:\/\/&lt;bucket&gt;\/mlflow\/artifacts\/ \\     --host localhost     --port 5000<\/code><\/pre>\n<p>  MLflow \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e\u0435 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435. \u0424\u0430\u0439\u043b\u043e\u0432\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u2013 \u044d\u0442\u043e \u043c\u0435\u0441\u0442\u043e, \u0433\u0434\u0435 \u0441\u0435\u0440\u0432\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u0432 \u0438 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u043e\u0432. \u041f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0443\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u043e\u043d \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e\u0435 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435. \u0417\u0434\u0435\u0441\u044c \u0434\u043b\u044f \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430 \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f <code>\/tmp<\/code>.<\/p>\n<p>  \u041f\u043e\u043c\u043d\u0438\u0442\u0435 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e, \u0435\u0441\u043b\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440 mlflow \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0441\u0442\u0430\u0440\u044b\u0445 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u043e\u0432, \u043e\u043d\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0432 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435. \u041e\u0434\u043d\u0430\u043a\u043e \u0438 \u0431\u0435\u0437 \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0431\u044b \u0441\u043c\u043e\u0433\u043b\u0438 \u0438\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 UDF, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0443\u0442\u044c \u0434\u043e \u043c\u043e\u0434\u0435\u043b\u0438.  <\/p>\n<blockquote><p>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435: \u0418\u043c\u0435\u0439\u0442\u0435 \u0432 \u0432\u0438\u0434\u0443, \u0447\u0442\u043e Tracking UI \u0438 \u043a\u043b\u0438\u0435\u043d\u0442 \u043c\u043e\u0434\u0435\u043b\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u043c\u0435\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u0430. \u0422\u043e \u0435\u0441\u0442\u044c \u0432\u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e Tracking UI \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f \u0432 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0435 EC2, \u043f\u0440\u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 MLflow \u0443 \u043c\u0430\u0448\u0438\u043d\u044b \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043f\u0440\u044f\u043c\u043e\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u043a S3 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u043e\u0432. <\/p><\/blockquote>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/8b\/2s\/v5\/8b2sv5y11jb8cy_k_pqsqgfcnwm.png\"><br \/>  <i>Tracking UI \u0445\u0440\u0430\u043d\u0438\u0442 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u044b \u0432 \u0431\u0430\u043a\u0435\u0442\u0435 S3<\/i><\/p>\n<h3>\u0417\u0430\u043f\u0443\u0441\u043a \u043c\u043e\u0434\u0435\u043b\u0435\u0439<\/h3>\n<p>  \u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c Tracking-\u0441\u0435\u0440\u0432\u0435\u0440, \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0442\u044c \u043e\u0431\u0443\u0447\u0430\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u0438.<\/p>\n<p>  \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043c\u044b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0435\u0439 wine \u0438\u0437 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 MLflow \u0432 <a href=\"https:\/\/github.com\/mlflow\/mlflow\/blob\/master\/examples\/sklearn_elasticnet_wine\/train.py\">Sklearn<\/a>.<\/p>\n<pre><code class=\"xml\">MLFLOW_TRACKING_URI=http:\/\/localhost:5000 python wine_quality.py \\   --alpha 0.9   --l1_ration 0.5   --wine_file .\/data\/winequality-red.csv<\/code><\/pre>\n<p>  \u041a\u0430\u043a \u043c\u044b \u0443\u0436\u0435 \u0433\u043e\u0432\u043e\u0440\u0438\u043b\u0438, MLflow \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u043c\u0435\u0442\u0440\u0438\u043a\u0438 \u0438 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u044b \u043c\u043e\u0434\u0435\u043b\u0435\u0439, \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c, \u043a\u0430\u043a \u043e\u043d\u0438 \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u043f\u043e \u043c\u0435\u0440\u0435 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0439. \u042d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043a\u0440\u0430\u0439\u043d\u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u0430, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u0430\u043a \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u043b\u0443\u0447\u0448\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c, \u043e\u0431\u0440\u0430\u0442\u0438\u0432\u0448\u0438\u0441\u044c \u0432 Tracking-\u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0438\u043b\u0438 \u043f\u043e\u043d\u044f\u0432, \u043a\u0430\u043a\u043e\u0439 \u043a\u043e\u0434 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043b \u043d\u0443\u0436\u043d\u0443\u044e \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044e, \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0432\u0448\u0438\u0441\u044c \u043b\u043e\u0433\u0430\u043c\u0438 git hash \u043a\u043e\u043c\u043c\u0438\u0442\u043e\u0432. <\/p>\n<pre><code class=\"python\">with mlflow.start_run():      ... model ...      mlflow.log_param(&quot;source&quot;, wine_path)     mlflow.log_param(&quot;alpha&quot;, alpha)     mlflow.log_param(&quot;l1_ratio&quot;, l1_ratio)      mlflow.log_metric(&quot;rmse&quot;, rmse)     mlflow.log_metric(&quot;r2&quot;, r2)     mlflow.log_metric(&quot;mae&quot;, mae)      mlflow.set_tag('domain', 'wine')     mlflow.set_tag('predict', 'quality')     mlflow.sklearn.log_model(lr, &quot;model&quot;)<\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/tj\/qx\/uu\/tjqxuuynwlemfahl-ebcoksfubc.png\"><br \/>  <i>\u0418\u0442\u0435\u0440\u0430\u0446\u0438\u0438 wine<\/i><\/p>\n<h3>\u0421\u0435\u0440\u0432\u0435\u0440\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0434\u043b\u044f \u043c\u043e\u0434\u0435\u043b\u0438<\/h3>\n<p>  <\/p>\n<blockquote><p>Tracking-\u0441\u0435\u0440\u0432\u0435\u0440 MLflow, \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0439 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u201cmlflow server\u201d, \u0438\u043c\u0435\u0435\u0442 REST API \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u0432 \u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u0444\u0430\u0439\u043b\u043e\u0432\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0430\u0434\u0440\u0435\u0441 tracking-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0441\u0440\u0435\u0434\u044b \u00abMLFLOW_TRACKING_URI\u00bb \u0438 tracking API MLflow \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0432\u044f\u0436\u0435\u0442\u0441\u044f \u0441 tracking-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u043f\u043e \u044d\u0442\u043e\u043c\u0443 \u0430\u0434\u0440\u0435\u0441\u0443, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u044c\/\u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0435, \u043c\u0435\u0442\u0440\u0438\u043a\u0438 \u043b\u043e\u0433\u043e\u0432 \u0438 \u0442.\u0434.<\/p>\n<p>  \u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a: <a href=\"https:\/\/mlflow.org\/docs\/latest\/tracking.html#running-a-tracking-server\">Docs\/\/ Running a tracking server<\/a><\/p><\/blockquote>\n<p>\u0427\u0442\u043e\u0431\u044b \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0439 tracking-\u0441\u0435\u0440\u0432\u0435\u0440 (\u0441\u043c. \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0437\u0430\u043f\u0443\u0441\u043a\u0430) \u0438 Run ID \u043c\u043e\u0434\u0435\u043b\u0438.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/oe\/ib\/-s\/oeib-szw1wzjvb9gvzl9h7hddga.png\"><br \/>  <i>Run ID<\/i><\/p>\n<pre><code class=\"xml\"># Serve a sklearn model through 127.0.0.0:5005 MLFLOW_TRACKING_URI=http:\/\/0.0.0.0:5000 mlflow sklearn serve \\   --port 5005  \\   --run_id 0f8691808e914d1087cf097a08730f17 \\   --model-path model<\/code><\/pre>\n<p>  \u0414\u043b\u044f \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430 MLflow serve, \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0443\u043f \u043a Tracking UI, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043c\u043e\u0434\u0435\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0443\u043a\u0430\u0437\u0430\u0432 <code>--run_id<\/code>.<\/p>\n<p>  \u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u043e\u0434\u0435\u043b\u044c \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0441 Tracking-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u043a\u043e\u043d\u0435\u0447\u043d\u0443\u044e \u0442\u043e\u0447\u043a\u0443 \u043c\u043e\u0434\u0435\u043b\u0438.<\/p>\n<pre><code class=\"python\"># Query Tracking Server Endpoint curl -X POST \\   http:\/\/127.0.0.1:5005\/invocations \\   -H 'Content-Type: application\/json' \\   -d '[ \t{ \t\t&quot;fixed acidity&quot;: 3.42,  \t\t&quot;volatile acidity&quot;: 1.66,  \t\t&quot;citric acid&quot;: 0.48,  \t\t&quot;residual sugar&quot;: 4.2,  \t\t&quot;chloridessssss&quot;: 0.229,  \t\t&quot;free sulfur dsioxide&quot;: 19,  \t\t&quot;total sulfur dioxide&quot;: 25,  \t\t&quot;density&quot;: 1.98,  \t\t&quot;pH&quot;: 5.33,  \t\t&quot;sulphates&quot;: 4.39,  \t\t&quot;alcohol&quot;: 10.8 \t} ]'  &gt; {&quot;predictions&quot;: [5.825055635303461]}<\/code><\/pre>\n<p>  <\/p>\n<h3>\u0417\u0430\u043f\u0443\u0441\u043a \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0438\u0437 Spark<\/h3>\n<p>  \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e Tracking-\u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043c\u043e\u0449\u043d\u044b\u0439 \u0434\u043b\u044f \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0438\u0445 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430serve (\u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a: <a href=\"https:\/\/mlflow.org\/docs\/latest\/models.html#local\">mlflow \/\/ docs \/\/ models # local<\/a>), \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 Spark (batch \u0438\u043b\u0438 streaming) \u2013 \u0435\u0449\u0435 \u0431\u043e\u043b\u0435\u0435 \u043c\u043e\u0449\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0437\u0430 \u0441\u0447\u0435\u0442 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0441\u0442\u0438. <\/p>\n<p>  \u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u044c\u0442\u0435, \u0447\u0442\u043e \u0432\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0440\u043e\u0432\u0435\u043b\u0438 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435 \u0432 \u043e\u0444\u0444\u043b\u0430\u0439\u043d\u0435, \u0430 \u043f\u043e\u0442\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043b\u0438 \u0432\u044b\u0445\u043e\u0434\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u043a\u043e \u0432\u0441\u0435\u043c \u0432\u0430\u0448\u0438\u043c \u0434\u0430\u043d\u043d\u044b\u043c. \u0418\u043c\u0435\u043d\u043d\u043e \u0442\u0443\u0442 Spark \u0438 MLflow \u043f\u043e\u043a\u0430\u0436\u0443\u0442 \u0441\u0435\u0431\u044f \u0441 \u043b\u0443\u0447\u0448\u0435\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b.<\/p>\n<h3>\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c PySpark + Jupyter + Spark<\/h3>\n<p>  <\/p>\n<blockquote><p>\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a: <a href=\"https:\/\/blog.sicara.com\/get-started-pyspark-jupyter-guide-tutorial-ae2fe84f594f\">Get started PySpark \u2014 Jupyter<\/a><\/p><\/blockquote>\n<p>  \u0427\u0442\u043e\u0431\u044b \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c, \u043a\u0430\u043a \u043c\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u0438 MLflow \u043a \u0434\u0430\u0442\u0430\u0444\u0440\u0435\u0439\u043c\u0430\u043c Spark, \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u043d\u0443\u044e \u0440\u0430\u0431\u043e\u0442\u0443 Jupyter notebooks \u0441 PySpark.<\/p>\n<p>  \u041d\u0430\u0447\u043d\u0438\u0442\u0435 \u0441 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 <a href=\"http:\/\/spark.apache.org\/downloads.html\">Apache Spark<\/a>:<\/p>\n<pre><code class=\"python\">cd ~\/Downloads\/ tar -xzf spark-2.4.3-bin-hadoop2.7.tgz mv ~\/Downloads\/spark-2.4.3-bin-hadoop2.7 ~\/ ln -s ~\/spark-2.4.3-bin-hadoop2.7 ~\/spark\u0300<\/code><\/pre>\n<p>  \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 PySpark \u0438 Jupyter \u0432 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u0443\u044e \u0441\u0440\u0435\u0434\u0443:<\/p>\n<pre><code class=\"python\">pip install pyspark jupyter<\/code><\/pre>\n<p>  \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0441\u0440\u0435\u0434\u044b:<\/p>\n<pre><code class=\"python\">export SPARK_HOME=~\/spark export PATH=$SPARK_HOME\/bin:$PATH export PYSPARK_DRIVER_PYTHON=jupyter export PYSPARK_DRIVER_PYTHON_OPTS=&quot;notebook --notebook-dir=${HOME}\/Projects\/notebooks&quot;<\/code><\/pre>\n<p>  \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0432 <code>notebook-dir<\/code>, \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043d\u0430\u0448\u0438 notebook-\u0438 \u0432 \u0436\u0435\u043b\u0430\u0435\u043c\u043e\u0439 \u043f\u0430\u043f\u043a\u0435.<\/p>\n<h3>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c Jupyter \u0438\u0437 PySpark<\/h3>\n<p>  \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u044b \u0441\u043c\u043e\u0433\u043b\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Jupiter \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430 PySpark, \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c Jupyter notebook \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 PySpark.<\/p>\n<pre><code class=\"python\">(mlflow) afranzi:~$ pyspark [I 19:05:01.572 NotebookApp] sparkmagic extension enabled! [I 19:05:01.573 NotebookApp] Serving notebooks from local directory: \/Users\/afranzi\/Projects\/notebooks [I 19:05:01.573 NotebookApp] The Jupyter Notebook is running at: [I 19:05:01.573 NotebookApp] http:\/\/localhost:8888\/?token=c06252daa6a12cfdd33c1d2e96c8d3b19d90e9f6fc171745 [I 19:05:01.573 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation). [C 19:05:01.574 NotebookApp]      Copy\/paste this URL into your browser when you connect for the first time,     to login with a token:         http:\/\/localhost:8888\/?token=c06252daa6a12cfdd33c1d2e96c8d3b19d90e9f6fc171745<\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/zt\/ry\/pv\/ztrypvichaylhljjgzslhrzcnjm.png\"><\/p>\n<p>  \u041a\u0430\u043a \u0431\u044b\u043b\u043e \u0441\u043a\u0430\u0437\u0430\u043d\u043e \u0432\u044b\u0448\u0435, MLflow \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u043e\u0432 \u043c\u043e\u0434\u0435\u043b\u0438 \u0432 S3. \u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u0443 \u043d\u0430\u0441 \u0432 \u0440\u0443\u043a\u0430\u0445 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c, \u043c\u044b \u0438\u043c\u0435\u0435\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0435 \u043a\u0430\u043a UDF \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u043e\u0434\u0443\u043b\u044f <code>mlflow.pyfunc<\/code>.<\/p>\n<pre><code class=\"python\">import mlflow.pyfunc  model_path = 's3:\/\/&lt;bucket&gt;\/mlflow\/artifacts\/1\/0f8691808e914d1087cf097a08730f17\/artifacts\/model' wine_path = '\/Users\/afranzi\/Projects\/data\/winequality-red.csv' wine_udf = mlflow.pyfunc.spark_udf(spark, model_path)  df = spark.read.format(&quot;csv&quot;).option(&quot;header&quot;, &quot;true&quot;).option('delimiter', ';').load(wine_path) columns = [ &quot;fixed acidity&quot;, &quot;volatile acidity&quot;, &quot;citric acid&quot;,             &quot;residual sugar&quot;, &quot;chlorides&quot;, &quot;free sulfur dioxide&quot;,             &quot;total sulfur dioxide&quot;, &quot;density&quot;, &quot;pH&quot;,             &quot;sulphates&quot;, &quot;alcohol&quot;           ]            df.withColumn('prediction', wine_udf(*columns)).show(100, False)<\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/od\/qw\/mf\/odqwmfog-ow3hpy0uywsp9fqero.png\"><br \/>   <i>PySpark \u2013 \u0412\u044b\u0432\u043e\u0434 \u043f\u0440\u043e\u0433\u043d\u043e\u0437\u0430 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u0432\u0438\u043d\u0430<\/i><\/p>\n<p>  \u0414\u043e \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u043c\u044b \u0433\u043e\u0432\u043e\u0440\u0438\u043b\u0438 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c PySpark \u0441 MLflow, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044f \u043f\u0440\u043e\u0433\u043d\u043e\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u0432\u0438\u043d\u0430 \u043d\u0430 \u0432\u0441\u0435\u043c \u043d\u0430\u0431\u043e\u0440\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 wine. \u041d\u043e \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c, \u0435\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u043e\u0434\u0443\u043b\u0438 Python MLflow \u0438\u0437 Scala Spark?<\/p>\n<p>  \u041c\u044b \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u0438 \u044d\u0442\u043e, \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 Spark \u043c\u0435\u0436\u0434\u0443 Scala \u0438 Python. \u0422\u043e \u0435\u0441\u0442\u044c \u043c\u044b \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0438 MLflow UDF \u0432 Python, \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u0435\u0433\u043e \u0438\u0437 Scala (\u0434\u0430, \u0432\u043e\u0437\u043e\u0436\u043d\u043e, \u043d\u0435 \u043b\u0443\u0447\u0448\u0435\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u043d\u043e \u0447\u0442\u043e \u0438\u043c\u0435\u0435\u043c).<\/p>\n<h4>Scala Spark + MLflow<\/h4>\n<p>  \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043c <a href=\"https:\/\/toree.apache.org\/\">Toree Kernel<\/a> \u0432 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 Jupiter. <\/p>\n<h4>\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c Spark + Toree + Jupyter<\/h4>\n<p>  <\/p>\n<pre><code class=\"python\">pip install toree jupyter toree install --spark_home=${SPARK_HOME} --sys-prefix jupyter kernelspec list ``` ``` Available kernels:   apache_toree_scala    \/Users\/afranzi\/.virtualenvs\/mlflow\/share\/jupyter\/kernels\/apache_toree_scala   python3               \/Users\/afranzi\/.virtualenvs\/mlflow\/share\/jupyter\/kernels\/python3 ```<\/code><\/pre>\n<p>  \u041a\u0430\u043a \u0432\u0438\u0434\u043d\u043e \u0438\u0437 \u043f\u0440\u0438\u043a\u0440\u0435\u043f\u043b\u0435\u043d\u043d\u043e\u0433\u043e notebook-\u0430, UDF \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u043d\u043e Spark \u0438 PySpark. \u041c\u044b \u043d\u0430\u0434\u0435\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u044d\u0442\u0430 \u0447\u0430\u0441\u0442\u044c \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u0430 \u0442\u0435\u043c, \u043a\u0442\u043e \u043b\u044e\u0431\u0438\u0442 Scala \u0438 \u0445\u043e\u0447\u0435\u0442 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u0438 \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u043d\u0430 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0435. <\/p>\n<pre><code class=\"scala\">import org.apache.spark.sql.functions.col import org.apache.spark.sql.types.StructType import org.apache.spark.sql.{Column, DataFrame} import scala.util.matching.Regex  val FirstAtRe: Regex = &quot;^_&quot;.r val AliasRe: Regex = &quot;[\\\\s_.:@]+&quot;.r  def getFieldAlias(field_name: String): String = {     FirstAtRe.replaceAllIn(AliasRe.replaceAllIn(field_name, &quot;_&quot;), &quot;&quot;) }  def selectFieldsNormalized(columns: List[String])(df: DataFrame): DataFrame = {     val fieldsToSelect: List[Column] = columns.map(field =&gt;         col(field).as(getFieldAlias(field))     )     df.select(fieldsToSelect: _*) }  def normalizeSchema(df: DataFrame): DataFrame = {     val schema = df.columns.toList     df.transform(selectFieldsNormalized(schema)) }  FirstAtRe = ^_ AliasRe = [\\s_.:@]+  getFieldAlias: (field_name: String)String selectFieldsNormalized: (columns: List[String])(df: org.apache.spark.sql.DataFrame)org.apache.spark.sql.DataFrame normalizeSchema: (df: org.apache.spark.sql.DataFrame)org.apache.spark.sql.DataFrame Out[1]: [\\s_.:@]+ In [2]: val winePath = &quot;~\/Research\/mlflow-workshop\/examples\/wine_quality\/data\/winequality-red.csv&quot; val modelPath = &quot;\/tmp\/mlflow\/artifactStore\/0\/96cba14c6e4b452e937eb5072467bf79\/artifacts\/model&quot;  winePath = ~\/Research\/mlflow-workshop\/examples\/wine_quality\/data\/winequality-red.csv modelPath = \/tmp\/mlflow\/artifactStore\/0\/96cba14c6e4b452e937eb5072467bf79\/artifacts\/model Out[2]: \/tmp\/mlflow\/artifactStore\/0\/96cba14c6e4b452e937eb5072467bf79\/artifacts\/model In [3]: val df = spark.read               .format(&quot;csv&quot;)               .option(&quot;header&quot;, &quot;true&quot;)               .option(&quot;delimiter&quot;, &quot;;&quot;)               .load(winePath)               .transform(normalizeSchema)  df = [fixed_acidity: string, volatile_acidity: string ... 10 more fields] Out[3]: [fixed_acidity: string, volatile_acidity: string ... 10 more fields] In [4]: %%PySpark import mlflow from mlflow import pyfunc  model_path = &quot;\/tmp\/mlflow\/artifactStore\/0\/96cba14c6e4b452e937eb5072467bf79\/artifacts\/model&quot; wine_quality_udf = mlflow.pyfunc.spark_udf(spark, model_path)  spark.udf.register(&quot;wineQuality&quot;, wine_quality_udf) Out[4]: &lt;function spark_udf.&lt;locals&gt;.predict at 0x1116a98c8&gt; In [6]: df.createOrReplaceTempView(&quot;wines&quot;) In [10]: %%SQL SELECT      quality,     wineQuality(         fixed_acidity,         volatile_acidity,         citric_acid,         residual_sugar,         chlorides,         free_sulfur_dioxide,         total_sulfur_dioxide,         density,         pH,         sulphates,         alcohol     ) AS prediction FROM wines LIMIT 10 Out[10]: +-------+------------------+ |quality|        prediction| +-------+------------------+ |      5| 5.576883967129615| |      5|  5.50664776916154| |      5| 5.525504822954496| |      6| 5.504311247097457| |      5| 5.576883967129615| |      5|5.5556903912725755| |      5| 5.467882654744997| |      7| 5.710602976324739| |      7| 5.657319539336507| |      5| 5.345098606538708| +-------+------------------+  In [17]: spark.catalog.listFunctions.filter('name like &quot;%wineQuality%&quot;).show(20, false)  +-----------+--------+-----------+---------+-----------+ |name       |database|description|className|isTemporary| +-----------+--------+-----------+---------+-----------+ |wineQuality|null    |null       |null     |true       | +-----------+--------+-----------+---------+-----------+ <\/code><\/pre>\n<p>  <\/p>\n<h3>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0448\u0430\u0433\u0438<\/h3>\n<p>  \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 MLflow \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 Alpha-\u0432\u0435\u0440\u0441\u0438\u0438, \u043e\u043d\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043c\u043d\u043e\u0433\u043e\u043e\u0431\u0435\u0449\u0430\u044e\u0449\u0435. \u041e\u0434\u043d\u0430 \u043b\u0438\u0448\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0438\u0437 \u043e\u0434\u043d\u043e\u0439 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438 \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043d\u0430 \u043d\u043e\u0432\u044b\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c. <\/p>\n<p>  \u041a \u0442\u043e\u043c\u0443 \u0436\u0435, MLflow \u0441\u0431\u043b\u0438\u0436\u0430\u0435\u0442 Data-\u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043e\u0432 \u0438 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0441\u0442\u043e\u0432 \u043f\u043e Data Science, \u043f\u0440\u043e\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u044f \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438 \u043e\u0431\u0449\u0438\u0439 \u0441\u043b\u043e\u0439. <\/p>\n<p>  \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f MLflow, \u043c\u044b \u0443\u0432\u0435\u0440\u0435\u043d\u044b, \u0447\u0442\u043e \u043f\u043e\u0439\u0434\u0435\u043c \u0434\u0430\u043b\u044c\u0448\u0435 \u0438 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0435 \u0434\u043b\u044f \u043d\u0430\u0448\u0438\u0445 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u043e\u0432 Spark \u0438 \u0432 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445.<\/p>\n<p>  \u0411\u044b\u043b\u043e \u0431\u044b \u043d\u0435\u043f\u043b\u043e\u0445\u043e \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445, \u0432\u043c\u0435\u0441\u0442\u043e \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b. \u0422\u0430\u043a \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0445 \u0442\u043e\u0447\u0435\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0434\u043d\u043e \u0438 \u0442\u043e \u0436\u0435 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043e\u0432 <a href=\"https:\/\/prestodb.io\/\">Presto<\/a> \u0438 <a href=\"https:\/\/aws.amazon.com\/athena\/\">Athena<\/a> \u0441 \u043e\u0434\u043d\u0438\u043c \u0438 \u0442\u0435\u043c \u0436\u0435 Glue metastore.<\/p>\n<p>  \u041f\u043e\u0434\u0432\u043e\u0434\u044f \u0438\u0442\u043e\u0433\u0438, \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u0441\u043f\u0430\u0441\u0438\u0431\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0443 MLFlow \u0437\u0430 \u0442\u043e, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0435 \u043d\u0430\u0448\u0443 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0435\u0435.<\/p>\n<p>  \u0415\u0441\u043b\u0438 \u0432\u044b \u0438\u0433\u0440\u0430\u0435\u0442\u0435\u0441\u044c \u0441 MLflow, \u043d\u0435 \u0441\u0442\u0435\u0441\u043d\u044f\u0439\u0442\u0435\u0441\u044c \u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0430\u043c \u0438 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c, \u043a\u0430\u043a \u0432\u044b \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435, \u0438 \u0442\u0435\u043c \u0431\u043e\u043b\u0435\u0435, \u0435\u0441\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 \u0435\u0433\u043e \u043d\u0430 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0435.<\/p>\n<hr>\n<p>  \u0423\u0437\u043d\u0430\u0442\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u043a\u0443\u0440\u0441\u0430\u0445:<br \/>  <a href=\"https:\/\/otus.pw\/h8IZ\/\">Machine Learning. \u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u0443\u0440\u0441<\/a><br \/>  <a href=\"https:\/\/otus.pw\/jut8\/\">Machine Learning. \u041f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439 \u043a\u0443\u0440\u0441<\/a><\/p>\n<hr>\n<p>  \u0427\u0438\u0442\u0430\u0442\u044c \u0435\u0449\u0451:<\/p>\n<ul>\n<li><a href=\"https:\/\/habr.com\/ru\/company\/otus\/blog\/515046\/\">\u0420\u0438\u0441\u043a\u0438 \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0435\u0440\u0435\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u043c\u0435\u0442\u043e\u0434\u0430 \u0433\u043b\u0430\u0432\u043d\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043a \u0437\u0430\u0434\u0430\u0447\u0430\u043c \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u0441 \u0443\u0447\u0438\u0442\u0435\u043b\u0435\u043c<\/a><\/li>\n<li><a href=\"https:\/\/habr.com\/ru\/company\/otus\/blog\/513672\/\">\u0420\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u044c \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u0441 Docker \u2013 \u0427\u0430\u0441\u0442\u044c 1<\/a><\/li>\n<li><a href=\"https:\/\/habr.com\/ru\/company\/otus\/blog\/515514\/\">\u0420\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u044c \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u0441 Docker \u2013 \u0427\u0430\u0441\u0442\u044c 2<\/a>  <\/li>\n<\/ul>\n<\/div>\n<p> \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\/company\/otus\/blog\/516420\/\"> https:\/\/habr.com\/ru\/company\/otus\/blog\/516420\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/company\/otus\/blog\/516420\/\"><b><i>\u041f\u0440\u0438\u0432\u0435\u0442, \u0445\u0430\u0431\u0440\u043e\u0432\u0447\u0430\u043d\u0435. \u041a\u0430\u043a \u043c\u044b \u0443\u0436\u0435 \u043f\u0438\u0441\u0430\u043b\u0438, \u0432 \u044d\u0442\u043e\u043c \u043c\u0435\u0441\u044f\u0446\u0435 OTUS \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0441\u0440\u0430\u0437\u0443 \u0434\u0432\u0430 \u043a\u0443\u0440\u0441\u0430 \u043f\u043e \u043c\u0430\u0448\u0438\u043d\u043d\u043e\u043c\u0443 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044e, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e <a href=\"https:\/\/otus.pw\/h8IZ\/\">\u0431\u0430\u0437\u043e\u0432\u044b\u0439<\/a> \u0438 <a href=\"https:\/\/otus.pw\/jut8\/\">\u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439<\/a>. \u0412 \u0441\u0432\u044f\u0437\u0438 \u0441 \u044d\u0442\u0438\u043c \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u043c.<\/i><\/b><\/p>\n<hr>\n<p>  \u0426\u0435\u043b\u044c \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u2013 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043e \u043d\u0430\u0448\u0435\u043c \u043f\u0435\u0440\u0432\u043e\u043c \u043e\u043f\u044b\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f <a href=\"https:\/\/mlflow.org\/\">MLflow<\/a>.<\/p>\n<p>  \u041c\u044b \u043d\u0430\u0447\u043d\u0435\u043c \u043e\u0431\u0437\u043e\u0440 <a href=\"https:\/\/mlflow.org\/docs\/latest\/tracking.html\">MLflow<\/a> \u0441 \u0435\u0433\u043e tracking-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438 \u043f\u0440\u043e\u043b\u043e\u0433\u0438\u0440\u0443\u0435\u043c \u0432\u0441\u0435 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438 \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f. \u0417\u0430\u0442\u0435\u043c \u043f\u043e\u0434\u0435\u043b\u0438\u043c\u0441\u044f \u043e\u043f\u044b\u0442\u043e\u043c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f Spark \u0441 MLflow \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e UDF. <\/p>\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-308948","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/308948","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=308948"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/308948\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=308948"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=308948"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=308948"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}