在搭建机器学习模型的过程中我们会进行多次试验; 每次 实验中我们会得到与 机器学习模型关联的任何文件:包括模型本身、包版本、超参数等。我们需要跟踪机器学习实验的所有相关信息; 实验跟踪有助于再现性、组织和优化我们的训练过程。
常见的实验跟踪工具包括MLflow和Weight & Bias
MLflow是一个机器学习生命周期的开源平台,它主要针对以下几个方面来对实验进行追踪,分别是Tracking、Models、Model registry、Projects。
MLflow 将每次实验作为一次run,并跟踪可能影响模型及其结果的任何变量; 例如:参数、指标、元数据、模型本身…MLflow 还会自动记录每次运行的额外信息,例如:源代码、Git 提交、开始和结束时间以及作者。
要在本地运行 MLflow UI,我们使用以下命令,在此命令中,我们使用 SQLite 后端以及当前运行存储库中的文件 mlflow.db:
mlflow ui --backend-store-uri sqlite:///mlflow.db
在实验跟踪中,我们首先需要配置跟踪 URI 和当前实验名称
import mlflow
mlflow.set_tracking_uri("sqlite:///mlflow.db")
mlflow.set_experiment("nyc-taxi-experiment")
# 加载数据集和模型
x_train = ...
y_train = ...
之后初始化mlflow的运行并使用三个 mlflow 命令跟踪相关信息:
with mlflow.start_run():
mlflow.set_tag("developer","Qfl3x")
mlflow.log_param("train-data-path", "data/green_tripdata_2021-01.parquet")
mlflow.log_param("val-data-path", "data/green_tripdata_2021-02.parquet")
alpha = 0.01
mlflow.log_param("alpha", alpha)
lr = Lasso(alpha)
lr.fit(X_train, y_train)
y_pred = lr.predict(X_val)
rmse = mean_squared_error(y_val, y_pred, squared=False)
mlflow.log_metric("rmse", rmse)
mlflow.sklearn.log_model(lr , artifact_path="models_mlflow")
mlflow.log_artifact("vectorizer.pkl", artifact_path="extra_artifacts")
我们也可以使用autolog()来自动记录参数,例如
mlflow.autolog()
mlflow.xgboost.autolog()
Hyperopt是一个用于优化机器学习模型超参数的Python库。它通过搜索超参数空间来最大化或最小化指定的目标函数。以下是Hyperopt可以做的一些主要功能:
通过将 hyperopt 优化目标包装在 with mlflow.start_run() 块中,我们可以跟踪 hyperopt 运行的每个优化运行。然后我们记录 hyperopt 传递的参数以及指标,如下所示:
import xgboost as xgb
from hyperopt import fmin, tpe, hp, STATUS_OK, Trials
from hyperopt.pyll import scope
train = xgb.DMatrix(X_train, label=y_train)
valid = xgb.DMatrix(X_val, label=y_val)
def objective(params):
with mlflow.start_run():
mlflow.set_tag("model", "xgboost")
mlflow.log_params(params)
booster = xgb.train(
params=params,
dtrain=train,
num_boost_round=1000,
evals=[(valid, 'validation')],
early_stopping_rounds=50
)
y_pred = booster.predict(valid)
rmse = mean_squared_error(y_val, y_pred, squared=False)
mlflow.log_metric("rmse", rmse)
return {'loss': rmse, 'status': STATUS_OK}
search_space = {
'max_depth': scope.int(hp.quniform('max_depth', 4, 100, 1)),
'learning_rate': hp.loguniform('learning_rate', -3, 0),
'reg_alpha': hp.loguniform('reg_alpha', -5, -1),
'reg_lambda': hp.loguniform('reg_lambda', -6, -1),
'min_child_weight': hp.loguniform('min_child_weight', -1, 3),
'objective': 'reg:linear',
'seed': 42
}
best_result = fmin(
fn=objective,
space=search_space,
algo=tpe.suggest,
max_evals=50,
trials=Trials()
)
在以上代码中,我们定义了搜索空间和运行优化器的目标。 我们使用 mlflow.start_run() 将训练和验证块包装在内部,并使用 log_params 记录使用的参数,并使用 log_metric 验证 RMSE。
我们可以使用mlflow的load_model方法来加载我们保存的模型
logged_model = 'runs:/{Model UUID in MLflow}/models'
xgboost_model = mlflow.xgboost.load_model(logged_model)
模型注册
mlflow.set_tracking_uri(MLFLOW_TRACKING_URI)
run_id = run_id
model_uri = f"runs:/{run_id}/models"
mlflow.register_model(model_uri=model_uri, name="model-name")
模型转换staging
from mlflow.tracking import MlflowClient
MLFLOW_TRACKING_URI = "sqlite:///mlflow.db"
client = MlflowClient(tracking_uri=MLFLOW_TRACKING_URI)
model_version = 4
new_stage = "Staging"
client.transition_model_version_stage(
name=model_name,
version=model_version,
stage=new_stage,
archive_existing_versions=False
)
Web 服务是一种用于在电子设备之间进行通信的方法。Web服务中有一些方法我们可以使用它来解决我们的问题。
Python中的Flask库、Django库都可以来搭建web框架,这里以Flask举例。
from flask import Flask
app = Flask('ping') # give an identity to your web service
@app.route('/ping', methods=['GET']) # use decorator to add Flask's functionality to our function
def ping():
return 'PONG'
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=9696) # run the code in local machine with the debugging mode true and port 9696
对于一个机器学习模型,我们可以通过加载它的模型文件来搭建web服务进行预测
from flask import Flask, render_template, request
import numpy as np
from sklearn.linear_model import LinearRegression
app = Flask(__name__)
# 生成一些虚构的训练数据
X_train = np.array([[1], [2], [3], [4], [5]])
y_train = np.array([2, 4, 5, 4, 5])
# 训练线性回归模型
model = LinearRegression()
model.fit(X_train, y_train)
@app.route('/')
def home():
return render_template('index.html')
@app.route('/predict', methods=['POST'])
def predict():
if request.method == 'POST':
try:
input_data = float(request.form['input_data'])
input_data = np.array([[input_data]])
# 使用训练好的模型进行预测
prediction = model.predict(input_data)[0]
return render_template('index.html', prediction=prediction)
except ValueError:
return render_template('index.html', error="请输入有效的数值")
if __name__ == '__main__':
app.run(debug=True)
我们使用模板来优化我们的页面
DOCTYPE html>
<html>
<head>
<title>线性回归预测title>
head>
<body>
<h1>线性回归预测h1>
<form action="/predict" method="post">
<label for="input_data">输入数据:label>
<input type="text" name="input_data" id="input_data" placeholder="请输入数值">
<button type="submit">预测button>
form>
{% if prediction %}
<p>预测结果: {{ prediction }}p>
{% endif %}
{% if error %}
<p style="color: red;">{{ error }}p>
{% endif %}
body>
html>
Docker是一种容器化服务。使用 Docker可以将所有项目打包为您想要的系统,并在任何系统机器上运行它。
首先我们需要编写DockerFile来创建镜像
# 使用基础镜像
FROM python:3.8
# 设置工作目录
WORKDIR /app
# 复制应用程序的依赖文件到工作目录
COPY requirements.txt .
# 安装应用程序的依赖
RUN pip install --no-cache-dir -r requirements.txt
# 复制当前目录中的所有文件到工作目录
COPY . .
# 暴露应用程序运行的端口
EXPOSE 5000
# 启动应用程序
CMD ["python", "app.py"]
之后创建并运行镜像启动web服务后,我们可以发送请求来获取预测结果。
docker build -t your-image-name .
docker run -p 5000:5000 your-image-name
Docker Compose是一个用于定义和运行多容器Docker应用程序的工具。通过一个简单的YAML文件,可以配置应用程序的服务、网络和卷,并使用docker-compose命令启动、停止和管理整个应用程序的生命周期。
在Docker Compose中,我们需要定义以下内容:
version: '3'
services:
service1:
image: service1_image
ports:
- "5000:5000"
service2:
build:
context: ./service2
depends_on:
- service1
environment:
- MODEL_NAME=model.pkl # Add the environment variable
以上是一个简单的示例,service1 将通过 HTTP 提供输出数据,并在端口 5000 上监听。service2 依赖于 service1,并可以访问 service1 提供的数据并运行机器学习模型来预测该输出。
Kubernetes 是一个用于自动部署、扩展和操作容器化应用程序的开源平台。它提供了一个可移植、可扩展且易于管理的容器编排解决方案。我们可以在Kubernetes部署我们的Docker容器。
Kubernetes 的核心概念:
在Python中,单元测试是一种测试方法,用于验证程序的各个部分是否按照预期工作。pytest是Python中一种流行的测试框架,它简化了单元测试的编写和执行。以下是一个简单的实例
假设有一个简单的函数,对两个数进行加法:
# my_math.py
def add(x, y):
return x + y
我们将为这个函数编写一个单元测试,测试函数直接使用assert语句来检查条件是否为真,测试函数的名称以test_开头:
# test_my_math.py
from my_math import add
def test_add_positive_numbers():
assert add(2, 3) == 5
def test_add_negative_numbers():
assert add(-2, -3) == -5
def test_add_mixed_numbers():
assert add(2, -3) == -1
要运行这些测试,只需在命令行中执行,pytest将自动查找以test_开头的文件和函数,并执行这些测试。如果所有测试通过,你将看到一个简洁的输出。如果有测试失败,pytest将提供详细的错误信息,帮助你识别问题所在。
pytest
参考:Terraform学习
Terraform 是一个开源的基础设施即代码(Infrastructure as Code,IaC)工具。它允许开发人员使用声明性的配置语言定义基础设施,然后通过命令行工具将该配置部署到各种云提供商(如AWS、Azure、Google Cloud)和本地基础设施中。Terraform 的核心思想是将基础设施的定义与实际的基础设施状态保持同步,实现可重复、可管理的基础设施管理。
Terraform 的核心概念
Terraform 配置文件的扩展名通常为 .tf。配置文件可以包含 Terraform 命令、Provider 配置、资源定义、变量和输出等。下面是一个Terraform的文件结构的示例
my_terraform_project/
|-- main.tf
|-- variable.tf
|-- vars/
| |-- dev.tfvars
| |-- prod.tfvars
|-- modules/
| |-- ec2-instance/
| |-- main.tf
| |-- variables.tf
| |-- outputs.tf
variable.tf 文件定义了全局变量,这些变量将在主 Terraform 配置文件 main.tf 中被引用。这使得在整个项目中可以共享这些变量,而不仅仅是在特定于环境的变量文件中。下面是variable.tf 的例子
variable "region" {
description = "AWS region"
type = string
}
variable "ami_id" {
description = "AMI ID for the EC2 instance"
type = string
}
variable "instance_type" {
description = "EC2 instance type"
type = string
}
variable "key_name" {
description = "Key pair name for SSH access"
type = string
}
variable "subnet_id" {
description = "Subnet ID for the EC2 instance"
type = string
}
variable "security_group_names" {
description = "List of security group names to associate with the EC2 instance"
type = list(string)
}
variable "instance_name" {
description = "Name tag for the EC2 instance"
type = string
}
# 输出定义
output "stream_name" {
value = aws_kinesis_stream.example_stream.name
}
main.tf 文件是主配置文件,用于调用 EC2 实例模块。
provider "aws" {
region = var.region
}
module "my_ec2_instance" {
source = "./modules/ec2-instance"
region = var.region
ami_id = var.ami_id
instance_type = var.instance_type
key_name = var.key_name
subnet_id = var.subnet_id
security_group_names = var.security_group_names
instance_name = var.instance_name
}
output "my_instance_id" {
value = module.my_ec2_instance.instance_id
}
output "my_instance_public_ip" {
value = module.my_ec2_instance.public_ip
}
vars 文件夹包含了 dev.tfvars 和 prod.tfvars,分别代表了开发和生产环境的变量。通过使用不同的变量文件,你可以在不同的环境中使用相同的 Terraform 模块,使用 terraform apply -var-file=vars/dev.tfvars
或 terraform apply -var-file=vars/prod.tfvars
这样的命令来指定特定的环境变量文件。
vars/dev.tfvars 文件:
region = "us-east-1"
ami_id = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
key_name = "dev-keypair"
subnet_id = "subnet-0123456789abcdef0"
security_group_names = ["dev-security-group"]
instance_name = "DevEC2Instance"
vars/prod.tfvars 文件:
region = "us-west-2"
ami_id = "ami-0123456789abcdef0"
instance_type = "t2.large"
key_name = "prod-keypair"
subnet_id = "subnet-0123456789abcdef1"
security_group_names = ["prod-security-group"]
instance_name = "ProdEC2Instance"
modules 文件夹包含 EC2 实例模块,具有自己的 main.tf、variables.tf 和 outputs.tf 文件。使用模块有助于提高 Terraform 代码的可维护性、可读性和可复用性。
module的main.tf 文件:
provider "aws" {
region = var.region
}
resource "aws_instance" "ec2_instance" {
ami = var.ami_id
instance_type = var.instance_type
key_name = var.key_name
subnet_id = var.subnet_id
security_group_names = var.security_group_names
tags = {
Name = var.instance_name
}
}
module的variables.tf 文件:
variable "region" {
description = "AWS region"
}
variable "ami_id" {
description = "AMI ID for the EC2 instance"
}
variable "instance_type" {
description = "EC2 instance type"
}
variable "key_name" {
description = "Key pair name for SSH access"
}
variable "subnet_id" {
description = "Subnet ID for the EC2 instance"
}
variable "security_group_names" {
type = list(string)
description = "List of security group names to associate with the EC2 instance"
}
variable "instance_name" {
description = "Name tag for the EC2 instance"
}
module的outputs.tf 文件:
output "instance_id" {
value = aws_instance.ec2_instance.id
}
output "public_ip" {
value = aws_instance.ec2_instance.public_ip
}
常用基础命令
在 DevOps 领域,持续集成 (CI) 和持续部署 (CD) 在确保以结构化且高效的方式开发、测试、打包和交付软件应用程序方面发挥着关键作用。
GitHub Actions:对于存储库的每次新提交或代码更改,它将自动触发构建、测试和部署我们的服务的作业。
GitHub Actions中的CI的主要目标是确保新的代码变更能够顺利地集成到主代码库,并且通过运行测试和其他验证步骤来确保代码质量。在CI中,通常会包括以下步骤:检出代码、设置环境、运行测试。我们需要编写YAML文件来实现CI过程,需要包含以下关键内容:
下面是一个CI的例子
name: CI
on:
push:
branches:
- main
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run Tests with Pytest
run: pytest
terraform-validation:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.0.0
- name: Initialize Terraform
run: terraform init
- name: Validate Terraform Configuration
run: terraform validate
这个示例包括了两个作业:
CD的主要目标是将通过CI验证的代码部署到生产环境或其他目标环境。CD的YAML文件可能包含部署步骤、发布到服务器或云服务的命令等。在CD中,可能包括以下步骤:检出代码、设置部署环境、执行部署命令。以下是一个示例
name: CD
on:
workflow_run:
workflows: ["CI"]
types:
- completed
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Install Dependencies
run: pip install -r requirements.txt
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1 # 替换为你的AWS区域
- name: Deploy Infrastructure with Terraform
run: |
cd terraform
terraform init
terraform apply -auto-approve
- name: Deploy Python Application to Lambda
run: |
# 在这里添加将 Python 应用程序部署到 Lambda 的命令
# 你可能需要使用 AWS CLI 或其他工具进行部署
上述示例包含了以下关键步骤: