MLOps极致细节:4. MLFlow Projects 案例介绍(Gitee代码链接)
MLFlow Projects
允许我们将代码及其依赖项打包为一个可以在其他平台上以可复制(reproducible)和可重用(reusable)的方式运行的项目。每个项目都包括自己的代码和一个MLproject文件,该文件定义了它的依赖项(例如Python环境),以及可以在项目中运行哪些命令以及它们采用的参数。
在这个案例中,我们基于MLFlow的官方GitHub文档,具体说明MLflow Projects
如何被使用,以及结果。首先,我们先简单地过一遍概念,然后介绍如何把这个代码跑起来。关于此代码的详细解释,请参见我的博客:MLOps极致细节:5. MLFlow Projects 案例代码解读。
- 平台:Win10。
- IDE:Visual Studio Code
- 需要预装:Anaconda3。
文章目录
1 MLProject Yaml文件
根本上,MLFlow Projects
的作用就是让其他数据科学家更方便地运行MLFlow项目。在原本的MLFlow项目的基础上,我们需要增加一个MLProject
的yaml文件,在项目的根目录下。
一个MLProject
的例子如下:
name: My Project
conda_env: my_env.yaml
# Can have a docker_env instead of a conda_env, e.g.
# docker_env:
# image: mlflow-docker-example
entry_points:
main:
parameters:
data_file: path
regularization: {type: float, default: 0.1}
command: "python train.py -r {regularization} {data_file}"
validate:
parameters:
data_file: path
command: "python validate.py {data_file}"
MLProject
里面包含了如下几个参数/属性:
name
: 项目名称Entry Points
:可以在项目中运行的命令,以及有关其参数的信息。大多数项目至少包含一个entry point,您希望其他用户调用它。有些项目还可以包含多个entry points:例如,我们可能有一个包含多个特征化算法的Git repo。你也可以以.py
或.sh
文件作为entry points。在MLproject
文件中列出entry points的同时,我们还可以为它们指定参数,包括数据类型和默认值。Environment
:应用于执行项目entry point的软件环境。这包括项目代码所需的所有库依赖项。目前MLFlow支持Conda environments
和Docker containers
。-
Conda environments
:在MLProject
文件中需要添加conda_env
参数的定义,比如:conda_env: conda.yaml
。即,引用在<MLFLOW_PROJECT_DIRECTORY>/conda.yaml
路径下的conda yaml文件。关于conda.yaml
的写法,参见Anaconda 官网。一个conda.yaml
的例子:name: tutorial channels: - conda-forge dependencies: - python=3.7 - pip - pip: - scikit-learn==0.23.2 - mlflow>=1.0 - pandas
-
Docker container environments
:和conda环境类似的,在MLProject
文件中需要添加docker_env
参数的定义。MLFlow支持如下几种定义的方式:- Image without a registry path(还是直接用英文比较合适)。由于未指定registry path,Docker会在运行MLflow项目的系统上搜索此image。如果找不到这个image,Docker会尝试从DockerHub中pull。一个例子:
docker_env: image: mlflow-docker-example-environment
- Mounting volumes and specifying environment variables。
volumes
的作用是将本地的一个路径mount到docker镜像里面的一个路径。environment
可以从host的环境变量中复制,也可以指定为Docker镜像环境的新变量。环境字段应该是一个列表(list)。此列表中的元素可以是两个字符串的列表(用于定义新变量)或单个字符串(用于从host复制变量)。一个例子:
docker_env: image: mlflow-docker-example-environment volumes: ["/local/path:/container/mount/path"] environment: [["NEW_ENV_VAR", "new_var_value"], "VAR_TO_COPY_FROM_HOST_ENVIRONMENT"]
- Image in a remote registry。当MLflow项目运行时,Docker会尝试从指定的registry path中提取镜像。一个例子:
docker_env: image: 012345678910.dkr.ecr.us-west-2.amazonaws.com/mlflow-docker-example-environment:7.0
-
2 运行代码
这个案例中,我们将使用scikit-learn
来训练一个简单的线性回归模型,然后打包这个模型使之可重复使用。代码基于MLFlow官网改写。
这里,我们引用wine quality数据集。在此数据集中,我们基于一些特征,如"fixed acidity",“volatile acidity”,"citric acid"等等,来对wine的"quality"进行预测。
预测的模型我们选择sklearn.linear_model.ElasticNet
,详细的说明参见官网。
2.1 运行代码之前
在运行起代码之前,我们还是需要在我们的主机(host machine)新建虚拟环境(比如conda create -n [your vm name] python=3.8
),然后进入虚拟环境(conda activate [your vm name]
),安装好MLFlow(pip3 install mlflow -i https://pypi.tuna.tsinghua.edu.cn/simple
)。当然,我们也可以不用虚拟环境,而是直接在主机环境中进行MLFlow以及其他依赖的的安装,但我个人依然强烈建议不要随意在主环境中进行操作。
有下面几种方式运行起这个案例的代码:
- 我们把此案例相关代码克隆到本地:
git clone https://gitee.com/yichaoyyds/mlflow-ex-project-basic.git
。然后进入mlflow-ex-project-basic
文件夹,在terminal中运行py文件,比如python main.py
; - 我们把此案例相关代码克隆到本地:
git clone https://gitee.com/yichaoyyds/mlflow-ex-project-basic.git
。然后再按照下面章节的步骤运行mlrun
指令(在terminal中); - 不用把代码克隆到本地。mlflow也支持直接跑git上的代码。下面章节会做具体描述。
一个建议:在通过MLFlow Projects
的方式运行代码前,如果我们对mlflow不了解,我们还是先按照比较原始的方式先把代码跑起来,比如python main.py
。这也是为什么我们依旧在代码中包含了requirements.py
的原因。和之前的案例一样,我们先进入之前创建的虚拟环境,然后激活,比如:conda activate mlFlowEx
(mlFlowEx
是我们之前创建的虚拟环境)。然后,我们在虚拟环境中下载好相关依赖:pip3 install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
。和之前一样,这个案例我们选用的IDE依然是VSCode。
文档结构:
- conda.yaml # MLFlow Projects 所需要的conda的yaml文件
- MLproject # MLFlow Projects 所需要的MLproject文件
- requirements.txt # 我们测试代码的时候用到,包含了测试代码需要的依赖库
- main.py # 展示了如何使用tensorflow2/keras进行模型的训练
- READ.md # readme文件
- config.txt # 我们测试代码的时候用到,设置参数的时候方便一些
- wine-quality.csv # 训练数据集,其实不需要,我们直接从网上下载下来
2.2 第一种运行方式
-
在我们的主机(host machine),新建并进入虚拟环境,安装好
requirements.txt
里面的依赖; -
在VSCode,terminal中,选择你想克隆代码的本地路径;
-
克隆代码:
git clone https://gitee.com/yichaoyyds/mlflow-ex-project-basic.git
。此时,如果你在terminal输入ls
,应该可以看到mlflow-ex-project-basic
文件夹; -
cd mlflow-ex-project-basic
进入文件夹; -
python .\main.py
。你应该能看到类似Mode: loop Test Elasticnet model with different alpha and l1_ratio values. Test - alpha: 0.0, l1_ratio: 0.0. Result: RMSE: 0.68, MAE: 0.54, R2: 0.35 Test - alpha: 0.0, l1_ratio: 0.2. Result: RMSE: 0.68, MAE: 0.54, R2: 0.35 Test - alpha: 0.0, l1_ratio: 0.4. Result: RMSE: 0.68, MAE: 0.54, R2: 0.35 ... Test - alpha: 0.8, l1_ratio: 0.8. Result: RMSE: 0.83, MAE: 0.68, R2: 0.03 Best Elasticnet model (alpha=0.800000, l1_ratio=0.800000): Best model - alpha: 0.8, l1_ratio: 0.8. Result: RMSE: 0.8323634286332126, MAE: 0.6841525289534505, R2: 0.026507009052647468
并且你也会发现,在
mlflow-ex-project-basic
文件夹下面多了一个mlruns
文件夹。 -
运行成功。注意,每次运行的时候需要改一下
config.txt
文件里面的experimentid
值,因为我们每次不能创建相同id的experiment。
2.3 第二种运行方式
-
在我们的主机(host machine),新建并进入虚拟环境;
-
在VSCode,terminal中,选择你想克隆代码的本地路径;
-
克隆代码:
git clone https://gitee.com/yichaoyyds/mlflow-ex-project-basic.git
。此时,如果你在terminal输入ls
,应该可以看到mlflow-ex-project-basic
文件夹; -
注意,我们这里没有进入
mlflow-ex-project-basic
文件夹。运行:mlflow run mlflow-ex-project-basic
-
如果你是第一次运行,那么系统会给你新建一个虚拟机,然后系统进入这个虚拟机平台,安装好依赖,再运行
main.py
文件。运行完后,你会发现在当前目录下,会新生成mlruns
文件夹。以下为terminal代码运行后的一部分日志,详细的日志以及代码的解释请参见我的博客:。2022/03/06 15:20:38 INFO mlflow.projects.utils: === Created directory C:\XXX\Temp\tmp4t1upjb_ for downloading remote URIs passed to arguments of type 'path' === 2022/03/06 15:20:38 INFO mlflow.projects.backend.local: === Running command 'conda activate mlflow-5cbba1deec6e564616d0ebee88bd7d510b35ef53 && python main.py 0.5 0.1 loop mlflowProjectExample20' in run with ID '42a6a0faa2f1486c973fecb851193f56' === Mode: loop Test Elasticnet model with different alpha and l1_ratio values. Test - alpha: 0.0, l1_ratio: 0.0. Result: RMSE: 0.64, MAE: 0.51, R2: 0.36 Test - alpha: 0.0, l1_ratio: 0.2. Result: RMSE: 0.64, MAE: 0.51, R2: 0.36 ... Test - alpha: 0.8, l1_ratio: 0.8. Result: RMSE: 0.8, MAE: 0.66, R2: 0.01 Best Elasticnet model (alpha=0.800000, l1_ratio=0.800000): Best model - alpha: 0.8, l1_ratio: 0.8. Result: RMSE: 0.7980985615795877, MAE: 0.661761764937828, R2: 0.010305314500945628 2022/03/06 15:21:57 INFO mlflow.projects: === Run (ID '42a6a0faa2f1486c973fecb851193f56') succeeded ===
-
运行成功。注意,每次运行的时候需要改一下
config.txt
文件里面的experimentid
值,因为我们每次不能创建相同id的experiment。
2.4 第三种运行方式
这种方式最为简洁,直接调git的URI链接,连下载都免了。
-
在我们的主机(host machine),新建并进入虚拟环境;
-
在我们自己选择的某个本地路径下
mlflow run https://gitee.com/yichaoyyds/mlflow-ex-project-basic.git
-
你会发现在当前目录下,会新生成
mlruns
文件夹。其实第二种和第三种是一样的,只是第二种方式,我们手动克隆了一下,而第三种方式,mlflow帮我们克隆了一下,保存到了系统的temp路径下。我们来看一下运行后的(部分)日志,就一目了然了:
2022/03/06 15:37:12 INFO mlflow.projects.utils: === Fetching project from https://gitee.com/yichaoyyds/mlflow-ex-project-basic.git into C:\XXX\Temp\tmp2my_ysex ===
2022/03/06 15:37:16 INFO mlflow.projects.utils: === Created directory C:\XXX\Temp\tmp9c6kybzr for downloading remote URIs passed to arguments of type 'path' ===
2022/03/06 15:37:16 INFO mlflow.projects.backend.local: === Running command 'conda activate mlflow-5cbba1deec6e564616d0ebee88bd7d510b35ef53 && python main.py 0.5 0.1 loop mlflowProjectExample1' in run with ID '4cd58e551b114c60b416b41225580b17' ===
Mode: loop
Test Elasticnet model with different alpha and l1_ratio values.
Test - alpha: 0.0, l1_ratio: 0.0. Result: RMSE: 0.68, MAE: 0.52, R2: 0.27
Test - alpha: 0.0, l1_ratio: 0.2. Result: RMSE: 0.68, MAE: 0.52, R2: 0.27
...
Test - alpha: 0.8, l1_ratio: 0.8. Result: RMSE: 0.79, MAE: 0.64, R2: 0.03
Best Elasticnet model (alpha=0.800000, l1_ratio=0.800000):
Best model - alpha: 0.8, l1_ratio: 0.8. Result: RMSE: 0.7866516565074876, MAE: 0.6435140676671445, R2: 0.03154140821475915
2022/03/06 15:38:29 INFO mlflow.projects: === Run (ID '4cd58e551b114c60b416b41225580b17') succeeded ===