Skip to content

了解如何设计、开发、部署和迭代生产级 ML 应用程序。

License

Notifications You must be signed in to change notification settings

yuanzhongqiao/Made-With-ML-cn

 
 

Repository files navigation

Design · Develop · Deploy · Iterate
Join 40K+ developers in learning how to responsibly deliver value with ML.

     
🔥  Among the top ML repositories on GitHub


设计 · 开发 · 部署 · 迭代
与 40,000 多名开发人员一起学习如何通过 ML 负责任地交付价值。

     
🔥 跻身GitHub 上 顶级 ML 存储库之列


教训

了解如何将机器学习与软件工程相结合,以设计、开发、部署和迭代生产级 ML 应用程序。

教训

概述

在本课程中,我们将从实验(设计+开发)到生产(部署+迭代)。我们将通过激励组件来迭代地完成此任务,从而使我们能够构建可靠的生产系统。

  请务必观看下面的视频,快速了解我们将要构建的内容。
课程概述视频

  • 💡 第一原则:在我们直接进入代码之前,我们对每个机器学习概念都有一个第一原则的理解。
  • 💻 最佳实践:在开发和部署机器学习模型时实施软件工程最佳实践。
  • 📈 规模:在 Python 中轻松扩展 ML 工作负载(数据、训练、调整、服务),而无需学习全新的语言。
  • ⚙️ MLOps:在我们构建端到端机器学习系统时连接 MLOps 组件(跟踪、测试、服务、编排等)。
  • 🚀 开发到生产:学习如何快速可靠地从开发到生产,而不需要对我们的代码或基础设施管理进行任何更改。
  • 🐙 CI/CD:学习如何创建成熟的 CI/CD 工作流程,以与任何堆栈集成的模块化方式持续训练和部署更好的模型。

观众

机器学习不是一个独立的行业,相反,它是一种思考数据的强大方式,不为任何一种类型的人保留。

  • 👩‍💻 所有开发人员:无论是软件/基础设施工程师还是数据科学家,机器学习正日益成为您将要开发的产品的关键部分。
  • 👩‍🎓 大学毕业生:学习行业所需的实践技能,并弥合大学课程与行业期望之间的差距。
  • 👩‍💼 产品/领导力:想要开发技术基础,以便能够构建由机器学习驱动的令人惊叹(且可靠)的产品。

设置

请务必完成本课程,以更详细地了解此存储库中的内容。我们将在下面的部分中提供针对本地笔记本电脑和 Anyscale 集群的说明,因此请务必根据您所使用的内容切换 ► 下拉菜单(默认情况下,Anyscale 说明将处于打开状态)。如果您确实想使用 Anyscale 来运行本课程,我们将提供结构计算(GPU)社区,以便在一天内学习所有内容,请加入我们即将推出的下一个实时队列 →在此注册

我们将首先使用环境和计算配置设置集群。

当地的
您的个人笔记本电脑(单机)将充当集群,其中一个 CPU 将作为头节点,其余一些 CPU 将作为工作节点。本课程中的所有代码都可以在任何个人笔记本电脑上运行,尽管它比在更大的集群上执行相同的工作负载要慢。
任意规模

我们可以使用网页 UI创建一个Anyscale 工作区

- Workspace name: `madewithml`
- Project: `madewithml`
- Cluster environment name: `madewithml-cluster-env`
# Toggle `Select from saved configurations`
- Compute config: `madewithml-cluster-compute-g5.4xlarge`

或者,我们可以使用CLI通过以下方式创建工作区anyscale workspace create ...

其他(云平台、K8s、本地)

If you don't want to do this course locally or via Anyscale, you have the following options:

Git 设置

按照以下说明创建存储库:创建新存储库→命名Made-With-ML→切换Add a README file非常重要,因为这会创建main分支)→单击Create repository(向下滚动)

现在我们准备克隆包含所有代码的存储库:

git clone https://github.com/GokuMohandas/Made-With-ML.git .

证书

touch .env
# Inside .env
GITHUB_USERNAME="CHANGE_THIS_TO_YOUR_USERNAME"  # ← CHANGE THIS
source .env

虚拟环境

当地的
export PYTHONPATH=$PYTHONPATH:$PWD
python3 -m venv venv  # recommend using Python 3.10
source venv/bin/activate  # on Windows: venv\Scripts\activate
python3 -m pip install --upgrade pip setuptools wheel
python3 -m pip install -r requirements.txt
pre-commit install
pre-commit autoupdate

Highly recommend using Python 3.10 and using pyenv (mac) or pyenv-win (windows).

任意规模

我们已经通过设置 Anyscale 工作区时使用的集群环境为我们设置了具有适当 Python 版本和库的环境。所以我们只需要运行这些命令:

export PYTHONPATH=$PYTHONPATH:$PWD
pre-commit install
pre-commit autoupdate

笔记本

首先探索jupyter 笔记本,以交互方式演练核心机器学习工作负载。

当地的
# Start notebook
jupyter lab notebooks/madewithml.ipynb
任意规模

单击    Anyscale Workspace 页面右上角的 Jupyter 图标,这将在新选项卡中打开 JupyterLab 实例。然后导航到该notebooks目录并打开madewithml.ipynb笔记本。

脚本

现在,我们将遵循软件工程最佳实践(测试、文档、日志记录、服务、版本控制等),使用干净的 Python 脚本执行相同的工作负载。我们在笔记本中实现的代码将被重构为以下脚本:

madewithml
├── config.py
├── data.py
├── evaluate.py
├── models.py
├── predict.py
├── serve.py
├── train.py
├── tune.py
└── utils.py

注意:根据您的系统资源更改下面的--num-workers--cpu-per-worker和输入参数值。--gpu-per-worker例如,如果您使用的是本地笔记本电脑,则合理的配置是--num-workers 6 --cpu-per-worker 1 --gpu-per-worker 0.

训练

export EXPERIMENT_NAME="llm"
export DATASET_LOC="https://raw.githubusercontent.com/GokuMohandas/Made-With-ML/main/datasets/dataset.csv"
export TRAIN_LOOP_CONFIG='{"dropout_p": 0.5, "lr": 1e-4, "lr_factor": 0.8, "lr_patience": 3}'
python madewithml/train.py \
    --experiment-name "$EXPERIMENT_NAME" \
    --dataset-loc "$DATASET_LOC" \
    --train-loop-config "$TRAIN_LOOP_CONFIG" \
    --num-workers 1 \
    --cpu-per-worker 3 \
    --gpu-per-worker 1 \
    --num-epochs 10 \
    --batch-size 256 \
    --results-fp results/training_results.json

调音

export EXPERIMENT_NAME="llm"
export DATASET_LOC="https://raw.githubusercontent.com/GokuMohandas/Made-With-ML/main/datasets/dataset.csv"
export TRAIN_LOOP_CONFIG='{"dropout_p": 0.5, "lr": 1e-4, "lr_factor": 0.8, "lr_patience": 3}'
export INITIAL_PARAMS="[{\"train_loop_config\": $TRAIN_LOOP_CONFIG}]"
python madewithml/tune.py \
    --experiment-name "$EXPERIMENT_NAME" \
    --dataset-loc "$DATASET_LOC" \
    --initial-params "$INITIAL_PARAMS" \
    --num-runs 2 \
    --num-workers 1 \
    --cpu-per-worker 3 \
    --gpu-per-worker 1 \
    --num-epochs 10 \
    --batch-size 256 \
    --results-fp results/tuning_results.json

实验跟踪

我们将使用MLflow来跟踪我们的实验并存储我们的模型,并使用MLflow 跟踪 UI来查看我们的实验。我们一直将实验保存到本地目录,但请注意,在实际的生产环境中,我们将有一个中心位置来存储所有实验。为所有团队成员启动自己的 MLflow 服务器来跟踪他们的实验或使用诸如Weights & BiasesComet等托管解决方案是很容易/廉价的。

export MODEL_REGISTRY=$(python -c "from madewithml import config; print(config.MODEL_REGISTRY)")
mlflow server -h 0.0.0.0 -p 8080 --backend-store-uri $MODEL_REGISTRY
当地的

If you're running this notebook on your local laptop then head on over to http://localhost:8080/ to view your MLflow dashboard.

任意规模

如果您使用Anyscale Workspaces,那么我们需要首先公开 MLflow 服务器的端口。在 Anyscale Workspace 终端上运行以下命令以生成 MLflow 服务器的公共 URL。

APP_PORT=8080
echo https://$APP_PORT-port-$ANYSCALE_SESSION_DOMAIN

评估

export EXPERIMENT_NAME="llm"
export RUN_ID=$(python madewithml/predict.py get-best-run-id --experiment-name $EXPERIMENT_NAME --metric val_loss --mode ASC)
export HOLDOUT_LOC="https://raw.githubusercontent.com/GokuMohandas/Made-With-ML/main/datasets/holdout.csv"
python madewithml/evaluate.py \
    --run-id $RUN_ID \
    --dataset-loc $HOLDOUT_LOC \
    --results-fp results/evaluation_results.json
{
  "timestamp": "June 09, 2023 09:26:18 AM",
  "run_id": "6149e3fec8d24f1492d4a4cabd5c06f6",
  "overall": {
    "precision": 0.9076136428670714,
    "recall": 0.9057591623036649,
    "f1": 0.9046792827719773,
    "num_samples": 191.0
  },
...

推理

export EXPERIMENT_NAME="llm"
export RUN_ID=$(python madewithml/predict.py get-best-run-id --experiment-name $EXPERIMENT_NAME --metric val_loss --mode ASC)
python madewithml/predict.py predict \
    --run-id $RUN_ID \
    --title "Transfer learning with transformers" \
    --description "Using transformers for transfer learning on text classification tasks."
[{
  "prediction": [
    "natural-language-processing"
  ],
  "probabilities": {
    "computer-vision": 0.0009767753,
    "mlops": 0.0008223939,
    "natural-language-processing": 0.99762577,
    "other": 0.000575123
  }
}]

服务

当地的
# Start
ray start --head
# Set up
export EXPERIMENT_NAME="llm"
export RUN_ID=$(python madewithml/predict.py get-best-run-id --experiment-name $EXPERIMENT_NAME --metric val_loss --mode ASC)
python madewithml/serve.py --run_id $RUN_ID

Once the application is running, we can use it via cURL, Python, etc.:

# via Python
import json
import requests
title = "Transfer learning with transformers"
description = "Using transformers for transfer learning on text classification tasks."
json_data = json.dumps({"title": title, "description": description})
requests.post("http://127.0.0.1:8000/predict", data=json_data).json()
ray stop  # shutdown
任意规模

在 Anyscale Workspaces 中,Ray 已经在运行,因此我们不必像本地那样手动启动/关闭。

# Set up
export EXPERIMENT_NAME="llm"
export RUN_ID=$(python madewithml/predict.py get-best-run-id --experiment-name $EXPERIMENT_NAME --metric val_loss --mode ASC)
python madewithml/serve.py --run_id $RUN_ID

应用程序运行后,我们可以通过 cURL、Python 等使用它:

# via Python
import json
import requests
title = "Transfer learning with transformers"
description = "Using transformers for transfer learning on text classification tasks."
json_data = json.dumps({"title": title, "description": description})
requests.post("http://127.0.0.1:8000/predict", data=json_data).json()

测试

# Code
python3 -m pytest tests/code --verbose --disable-warnings

# Data export DATASET_LOC="https://raw.githubusercontent.com/GokuMohandas/Made-With-ML/main/datasets/dataset.csv" pytest --dataset-loc=$DATASET_LOC tests/data --verbose --disable-warnings

# Model export EXPERIMENT_NAME="llm" export RUN_ID=$(python madewithml/predict.py get-best-run-id --experiment-name $EXPERIMENT_NAME --metric val_loss --mode ASC) pytest --run-id=$RUN_ID tests/model --verbose --disable-warnings

# Coverage python3 -m pytest tests/code --cov madewithml --cov-report html --disable-warnings # html report python3 -m pytest tests/code --cov madewithml --cov-report term --disable-warnings # terminal report

<clipboard-copy aria-label="Copy" class="ClipboardButton btn btn-invisible js-clipboard-copy m-2 p-0 tooltipped-no-delay d-flex flex-justify-center flex-items-center" data-copy-feedback="Copied!" data-tooltip-direction="w" value="# Code python3 -m pytest tests/code --verbose --disable-warnings

Data

export DATASET_LOC="https://raw.githubusercontent.com/GokuMohandas/Made-With-ML/main/datasets/dataset.csv" pytest --dataset-loc=$DATASET_LOC tests/data --verbose --disable-warnings

Model

export EXPERIMENT_NAME="llm" export RUN_ID=$(python madewithml/predict.py get-best-run-id --experiment-name $EXPERIMENT_NAME --metric val_loss --mode ASC) pytest --run-id=$RUN_ID tests/model --verbose --disable-warnings

Coverage

python3 -m pytest tests/code --cov madewithml --cov-report html --disable-warnings # html report python3 -m pytest tests/code --cov madewithml --cov-report term --disable-warnings # terminal report" tabindex="0" role="button">

生产

从现在开始,为了将我们的应用程序部署到生产中,我们需要在 Anyscale 上或在您自己管理的云虚拟机/本地集群上(使用 Ray)。如果不在 Anyscale 上,命令会略有不同,但概念是相同的。

如果您不想自己设置所有这些,我们强烈建议您加入我们即将推出的实时群组{:target="_blank"},我们将提供一个已经为您设置好所有这些基础设施的环境,以便您只专注于机器学习。

验证

如果我们使用 Anyscale 工作区,则会自动为我们设置以下这些凭据。我们不需要在工作区上显式设置这些凭据,但如果我们在本地或在 Anyscale 作业和服务配置运行的集群之外运行,则需要这样做。

export ANYSCALE_HOST=https://console.anyscale.com
export ANYSCALE_CLI_TOKEN=$YOUR_CLI_TOKEN  # retrieved from Anyscale credentials page

集群环境

集群环境决定了我们的工作负载将在哪里执行(操作系统、依赖项等)。我们已经为我们创建了这个集群环境,但这就是我们自己创建/更新集群环境的方式。

export CLUSTER_ENV_NAME="madewithml-cluster-env"
anyscale cluster-env build deploy/cluster_env.yaml --name $CLUSTER_ENV_NAME

计算配置

计算配置决定了我们的工作负载将在哪些资源上执行。我们已经为我们创建了这个计算配置,但这就是我们自己创建它的方式。

export CLUSTER_COMPUTE_NAME="madewithml-cluster-compute-g5.4xlarge"
anyscale cluster-compute create deploy/cluster_compute.yaml --name $CLUSTER_COMPUTE_NAME

任何规模的职位

现在我们已准备好执行 ML 工作负载。我们决定将它们全部合并到一个作业中,但我们也可以为每个工作负载(训练、评估等)创建单独的作业。我们将首先编辑文件$GITHUB_USERNAME中的插槽workloads.yaml

runtime_env:
  working_dir: .
  upload_path: s3://madewithml/$GITHUB_USERNAME/jobs  # <--- CHANGE USERNAME (case-sensitive)
  env_vars:
    GITHUB_USERNAME: $GITHUB_USERNAME  # <--- CHANGE USERNAME (case-sensitive)

这里runtime_env指定我们应该将当前数据上传working_dir到 S3 存储桶,以便我们执行 Anyscale 作业时的所有工作人员都可以访问要使用的代码。稍后用于GITHUB_USERNAME将工作负载的结果保存到 S3,以便我们稍后可以检索它们(例如用于服务)。

现在我们准备提交作业来执行 ML 工作负载:

anyscale job submit deploy/jobs/workloads.yaml

任意规模的服务

在执行我们的 ML 工作负载后,我们就准备好将我们的模型服务投入生产。与我们的 Anyscale 作业配置类似,请务必$GITHUB_USERNAME更改serve_model.yaml.

ray_serve_config:
  import_path: deploy.services.serve_model:entrypoint
  runtime_env:
    working_dir: .
    upload_path: s3://madewithml/$GITHUB_USERNAME/services  # <--- CHANGE USERNAME (case-sensitive)
    env_vars:
      GITHUB_USERNAME: $GITHUB_USERNAME  # <--- CHANGE USERNAME (case-sensitive)

现在我们准备启动我们的服务:

# Rollout service
anyscale service rollout -f deploy/services/serve_model.yaml

# Query curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $SECRET_TOKEN" -d '{ "title": "Transfer learning with transformers", "description": "Using transformers for transfer learning on text classification tasks." }' $SERVICE_ENDPOINT/predict/

# Rollback (to previous version of the Service) anyscale service rollback -f $SERVICE_CONFIG --name $SERVICE_NAME

# Terminate anyscale service terminate --name $SERVICE_NAME

<clipboard-copy aria-label="Copy" class="ClipboardButton btn btn-invisible js-clipboard-copy m-2 p-0 tooltipped-no-delay d-flex flex-justify-center flex-items-center" data-copy-feedback="Copied!" data-tooltip-direction="w" value="# Rollout service anyscale service rollout -f deploy/services/serve_model.yaml

Query

curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $SECRET_TOKEN" -d '{ "title": "Transfer learning with transformers", "description": "Using transformers for transfer learning on text classification tasks." }' $SERVICE_ENDPOINT/predict/

Rollback (to previous version of the Service)

anyscale service rollback -f $SERVICE_CONFIG --name $SERVICE_NAME

Terminate

anyscale service terminate --name $SERVICE_NAME" tabindex="0" role="button">

持续集成/持续交付

我们不会在每次进行更改时都手动部署应用程序。相反,我们将使用 GitHub Actions 自动化此过程!

  1. 创建一个新的 github 分支来保存我们的更改并执行 CI/CD 工作负载:
git remote set-url origin https://github.com/$GITHUB_USERNAME/Made-With-ML.git  # <-- CHANGE THIS to your username
git checkout -b dev
  1. 我们首先将必要的凭据添加到/settings/secrets/actionsGitHub 存储库的页面。
export ANYSCALE_HOST=https://console.anyscale.com
export ANYSCALE_CLI_TOKEN=$YOUR_CLI_TOKEN  # retrieved from https://console.anyscale.com/o/madewithml/credentials
  1. 现在我们可以更改代码(不在main分支上)并将其推送到 GitHub。但为了将我们的代码推送到 GitHub,我们需要先使用我们的凭据进行身份验证,然后再推送到我们的存储库:
git config --global user.name $GITHUB_USERNAME  # <-- CHANGE THIS to your username
git config --global user.email you@example.com  # <-- CHANGE THIS to your email
git add .
git commit -m ""  # <-- CHANGE THIS to your message
git push origin dev

现在,系统将提示您输入用户名和密码(个人访问令牌)。请按照以下步骤获取个人访问令牌:新建 GitHub 个人访问令牌→ 添加名称 → 切换repoworkflow→ 单击Generate token(向下滚动)→ 复制令牌并在提示输入密码时粘贴。

  1. 现在我们可以从该分支启动 PR 到我们的main分支,这将触发工作负载工作流程。如果工作流程(Anyscale Jobs)成功,将直接在 PR 上生成带有培训和评估结果的评论。
  1. 如果我们喜欢结果,我们可以将 PR 合并到main分支中。这将触发服务工作流程,从而将我们的新服务投入生产!

持续学习

通过部署应用程序的 CI/CD 工作流程,我们现在可以专注于不断改进我们的模型。在此基础上扩展以连接到计划运行(cron)、数据管道、通过监控检测到的偏差、在线评估等变得非常容易。而且我们可以轻松添加其他上下文,例如将任何实验与当前生产中的实验进行比较(直接甚至在公关中)等等。

常问问题

Jupyter 笔记本内核

使用 jupyter 配置笔记本时遇到问题吗?默认情况下,jupyter 将在我们的虚拟环境中使用内核,但我们也可以手动将其添加到 jupyter:

python3 -m ipykernel install --user --name=venv

现在我们可以打开一个笔记本→内核(顶部菜单栏)→更改内核→ venv。要删除该内核,我们可以执行以下操作:

jupyter kernelspec list
jupyter kernelspec uninstall venv

About

了解如何设计、开发、部署和迭代生产级 ML 应用程序。

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Jupyter Notebook 97.8%
  • Python 2.1%
  • Other 0.1%