阿里云PAI + pytorch大语言模型开发环境简介

PAI-DSW 快速入门

阿里云机器学习PAI(Platform of Artificial Intelligence) 是集数据管理,模型管理,开发,训练,部署为一体的机器学习平台,并为企业级算法团队和数据科学团队提供了一站式开箱即用的机器学习平台解决方案。主要包括:

可视化建模和分布式训练 PAI-Designer

Notebook交互式AI研发 PAI-DSW(Data Science Workshop)

云原生AI基础平台 PAI-DLC(Deep Learning Containers)

在线预测服务 PAI-EAS(Elastic Algorithm Service)

其中,PAI-DSW是一款在阿里巴巴集团内上百个团队的打磨之下,为数据科学团队和算法团队们量身定制的云端机器学习交互式开发IDE,使读取数据、开发、训练及部署模型更简单高效且安全。

PAI-DSW集成了Jupyterlab、Code-Server等多种开源项目,并从网络与数据上打通了ODPS多种数据源,方便用户在构建模型的时候免去重新构建数据管道的工作。同时支持将开发环境直接保存为容器镜像并发起离线训练任务,为人工智能数字化转型添砖加瓦。

1. 安装和配置

首先通过以下命令安装 PAI Python SDK:

!python -m pip install "alipai>=0.4.4"

随后在命令行终端中配置需要使用的资源,按照引导输入阿里云 AccessKey,并指定使用的工作空间及 OSS Bucket:

# 以下命令,请在 命令行终端 中执行.
python -m pai.toolkit.config

我们可以通过 get_default_session() 来验证 SDK 是否配置成功:

import pai
from pai.session import get_default_session

print(pai.__version__)

sess = get_default_session()

# 获取当前使用的工作空间信息
assert sess.workspace_name is not None
print(sess.workspace_name)

2. 模型训练

现在我们将使用 Pytorch 构建一个简单的模型,通过 (w_1x_1 + w_2x_2^2 + w_3x_3^3 + b) 来拟合正弦函数 (y = \sin(x)).

2.1 数据集准备

首先需要准备用于拟合的数据点作为训练集。我们可以直接在本地构造数据点,保存至 ./data/ 目录下,用于后续模型的训练:

import torch
import math
import os
from pai.common.oss_utils import upload

x = torch.linspace(-math.pi, math.pi, 2000)
y = torch.sin(x)
p = torch.tensor([1, 2, 3])
xx = x.unsqueeze(-1).pow(p)

# 将生成的数据点保存为`./data/tensor.pt`
ds_path = './data'
os.makedirs(ds_path, exist_ok=True)
ds = torch.cat((xx, y.reshape(len(xx), -1)), dim=1)
torch.save(ds, ds_path + '/tensor.pt')

# 上传至 OSS Bucket 中
ds_uri = upload(ds_path, oss_path="sdk-quickstart/data/", bucket=sess.oss_bucket)

2.2 模型训练脚本准备

现在定义我们的 PyTorch 模型及训练方法,保存为 train.py 文件,并放置在 ./train_src/ 目录下,以便配置后续参数:

import os

train_src_dir = "./train_src"
os.makedirs(train_src_dir, exist_ok=True)

该脚本是以 PyTorch 官方提供的 PyTorch nn 示例 为基础,修改了:

  • 数据集加载逻辑,从而能加载我们上传到 OSS 中的数据集;

  • 模型保存逻辑,从而训练结束后能将训练好的模型输出至我们的 OSS Bucket,保存到 PAI_OUTPUT_MODEL 指定的路径中.

%%writefile train_src/train.py
# -*- coding: utf-8 -*-~
import torch
import os

def train(model, xx, y):
loss_fn = torch.nn.MSELoss(reduction='sum')
learning_rate = 1e-6
for t in range(2000):
y_pred = model(xx)
loss = loss_fn(y_pred, y)
if t % 100 == 99:
print("Step %d/2000: Loss = %.4f" %(t + 1, loss.item()))
model.zero_grad()
loss.backward()

with torch.no_grad():
for param in model.parameters():
param -= learning_rate * param.grad


if __name__ == "__main__":
model = torch.nn.Sequential(
    torch.nn.Linear(3, 1),
    torch.nn.Flatten(0, 1)
)

# 加载我们构造的 `tensor.pt` 数据集
ds_path = os.environ.get("PAI_INPUT_TRAIN_DATA", './data')
ds = torch.load(os.path.join(ds_path, 'tensor.pt'))
xx, y = ds[:, :3], ds[:, 3:]
y = y.reshape((len(y)))

train(model, xx, y)

# 保存模型为 TorchScript 格式,便于后续部署调用
output_model_path = os.environ.get("PAI_OUTPUT_MODEL", "./model/")
os.makedirs(output_model_path, exist_ok=True)
m = torch.jit.script(model)
m.save(os.path.join(output_model_path, "sinNN.pt"))

这里通过 torch.jit.script() 将模型导出为 TorchScript 格式,从而允许该模型在非 Python 环境,例如 Web 服务器中加载与推理。

2.3 提交训练作业

我们可以通过 Estimator 指定该脚本,以及启动命令、运行环境 (镜像)、机器规格,并通过 fit() 方法来提交该训练作业:

from pai.estimator import Estimator
from pai.image import retrieve

# 配置训练作业
est = Estimator(
# 训练作业启动命令
command="python train.py",
# 训练作业代码所在目录,对应目录将被上传到 OSS Bucket 上
source_dir="train_src/",
# 训练作业镜像: 使用 PAI 提供的最新的 PyTorch CPU 镜像
image_uri=retrieve(framework_name="PyTorch", framework_version="latest").image_uri,
# 训练使用的机器实例类型
instance_type="ecs.gn6i-c4g1.xlarge",
# 从训练输出日志中通过 regex 采集 metrics
metric_definitions=[
    {
        "Name": "loss",
        "Regex": r".*Loss = ([0-9]*.?[0-9]+(?:[eE][-+]?[0-9]+)?)",
    },
],
)
# 提交训练作业到 PAI,等待训练完成
est.fit(inputs={
    # 训练作业的输入数据,每一个 Key,Value 对是一个 Channel,用户可以通过环境变量 PAI_INPUT_{ChannelNameUpperCase} 获取对应的数据路径
    # 例如以下的 train_data,训练的脚本中可以通过`PAI_INPUT_TRAIN_DATA`获取数据挂载后的路径.
    "train_data": ds_uri,
})
# 查看输出模型的OSS路径
print(est.model_data())

提交作业后,我们可以在命令行终端看到训练作业的 URL,点击该 URL 将跳转到 PAI 控制台,显示该作业的详情。在这里,我们可以跟踪训练指标与日志、查看机器资源使用情况等。

同时本地终端也会持续打印作业的输出日志信息,直到训练作业结束。训练时长在 1 分钟左右。

3. 部署模型为推理服务

训练后的模型会输出到 OSS 中,我们可以通过 est.model_data() 获取模型的输出路径,并创建在线推理服务。

PAI 支持通过 镜像部署 的方式将训练好的模型部署为推理服务,我们只需要额外准备模型服务的代码即可:

# 准备推理代码保存目录
!mkdir -p infer_src
%%writefile infer_src/run.py
from flask import Flask, request
import numpy as np
import torch
import json
import os

app = Flask(__name__)
# 默认模型文件路径
MODEL_PATH = "/eas/workspace/model/"

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = torch.jit.load(os.path.join(MODEL_PATH, "sinNN.pt"), map_location=device).to(device)

@app.route("/", methods=["POST"])
def predict():
data = json.loads(request.data)
input_data = torch.tensor(np.array(data), dtype=torch.float32)
pred = model(input_data)
return json.dumps(pred.tolist())


if __name__ == "__main__":
app.run(host="0.0.0.0", port=int(os.environ.get("LISTENING_PORT", 8000)))

接下来,配置模型推理服务使用的镜像、代码,并创建推理服务对象:

from pai.model import Model, container_serving_spec
from pai.image import retrieve, ImageScope

torch_image = retrieve("PyTorch", framework_version="latest",
image_scope=ImageScope.INFERENCE)

inference_spec = container_serving_spec(
# 推理服务的启动命令
command="python run.py",
# 推理服务使用的本地代码路径
source_dir="./infer_src/",
# 使用的推理镜像
image_uri=torch_image.image_uri,
# 使用的第三方依赖
requirements=[
    "flask"
]
)

# 2. 使用待部署的模型配置一个Model对象
model = Model(
    # model_data 可以是OSS Bucket上已有的模型,或是本地路径的模型
    model_data=est.model_data(),
    inference_spec=inference_spec,
)

# 3. 部署模型到PAI-EAS,创建在线推理服务,返回Predictor对象
p = model.deploy(
    service_name="example_torch_service",
    instance_type="ecs.c6.xlarge",
)


4. 调用推理服务

通过 deploy() 方法返回的 Predictor 对象,我们可以通过发送 HTTP 请求的方式调用该推理服务。在 PAI SDK 中,这是通过 predict() 方法:

import numpy as np

# 我们的 TorchScript 模型要求输入 type 为 `float32`, shape 为 `(batchSize, 3)`
dummy_input = np.random.rand(10, 3).astype(np.float32)

res = p.predict(dummy_input)
print(res)
在测试结束后,记得删除推理服务实例,否则该服务将持续计费:

p.delete_service()

04-05 05:41