导言

目标读者

本书《TensorStack AI 计算平台 - 用户使用手册》 的目标读者是 “TensorStack AI 计算平台” 的使用者,包括:

  • AI 研究人员
  • 建模工程师
  • 数据处理工程师
  • 机器学习工程师
  • AI 应用开发工程师等

系统管理员、运维人员需要参考另外的《TensorStack AI 计算平台 - 管理员手册》系列。

如何使用

概述 介绍了产品的基本功能和使用模式。

用户首次使用可以跟从快速开始的内容,快速完成基本的体验。

然后,用户可以阅读 AI 开发和应用章节,以学习 AI 开发相关的概念。

其他章节内容如下:

  • 账户和安全 讨论用户账户和系统安全问题。
  • 计算资源 讨论如何使用集群计算资源。
  • 存储 章节对平台的存储方面的支持进行了说明。
  • 辅助 章节描述平台提供的一些重要辅助功能,例如如何处理敏感秘密信息,打包容器镜像等。
  • 命令行工具和 SDK 讨论 TensorStack 平台的提供的命令行工具和 Python SDK 。
  • 操作示例 章节提供了一些具体的操作指南。
  • 参考 章节对 API 提供了完整的描述。
  • 示例 章节提供了一些具体的应用示例,特别是对 LLM 领域的场景提供了全面的支持演示。
  • 集成 章节讨论了一些优秀的第三方工具在 TensorStack 平台上的集成及使用。
  • 附录1:背景 介绍了产品的技术架构和设计思路等。

“TensorStack AI 计算平台” 是一个功能强大且灵活的产品,支持在大规模(10^3 节点)集群上进行各种 AI 场景的计算。用户在一定的时间的学习、使用、探索、积累之后,就能对其功能有深入的理解,并在上面完成各种优秀的工作。

本手册使用的例子一般存放在下列 repos:

反馈

非常欢迎各种反馈,可在 Github Issues 页面 创建 issue。

版权声明

© 2023-2024 TensorStack.

本书/网站的内容版权由 TensorStack 所有,欢迎使用。

概述

产品介绍

“TensorStack AI 计算平台” 是面向 AI 集群的系统软件,针对 AI 集群的硬件架构和 AI 领域的计算任务的特性和需求,提供稳定、可扩展的 AI 技术平台能力,服务 AI 技术研发和规模化落地。

AI 集群的拥有者可以使用这套软件,构建自己的 “AI 私有云” 或 “AI 混合云” 基础设施服务。

通过先进的架构和丰富的 API + 系统服务,“TensorStack AI 计算平台” 合理地隐藏了分布式并行、异构计算、加速计算等技术的复杂细节,提高了抽象层次,并为 AI 领域的各种计算提供了针对性的支持,极大地提升了 AI 技术研究、开发、应用的工作效率。

t9k-arch
图 1:TensorStack AI 计算平台采用云原生架构,由 AI 引擎层(AI Engine, AIE)和 AI 基础层(AI Base, AIB)组成,为上层 AI 应用和底层 AI 算力建立有机连接,提供先进、可扩展的 AI 系统层面的能力。

基本流程

用户使用 “TensorStack AI 计算平台” 的基本交互流程:

  1. 管理员 - 创建 - 项目(Project)并设定项目管理员。
    • 用户以项目管理员或者普通成员的方式使用项目。
    • 用户可以同时使用多个项目。
  2. 管理员 - 创建 - 用户帐户
  3. 用户 - 使用其帐户 - 登录系统。
  4. 用户 - 在项目中 - 完成工作(创建各种计算任务)。
t9k-flow
图 2:用户登陆系统后在 “项目” 中创建计算任务以完成各种工作。

使用功能

用户主要通过创建各种类型 CRD 的实例(instance)使用产品的功能。例如:

  • 创建一个 Notebook CRD 的实例,以使用 Jupyter Notebook;
  • 为了使用 DeepSpeed 进行大规模并行的 LLM 预训练,创建一个 DeepSpeedJob CRD 的实例;
  • 为了部署一个模型推理服务,并支持服务规模的自动伸缩,创建一个 MLService CRD 的实例;
use-t9k
图 3:用户可以通过命令行接口(CLI) 或者可视化的 Web 页面(UI) 创建这些 CRD 的实例。

CLI

CRD 实例(instance)的创建总是可以通过命令行实现,例如使用 kubectl 可以方便的创建一个 Notebook:

# create a notebook
kubectle create -f notebook-tutorial.yaml 
notebook-tutorial.yaml
# notebook-tutorial.yaml
apiVersion: tensorstack.dev/v1beta1
kind: Notebook
metadata:
  name: tutorial
spec:
  type: jupyter
  template:
    spec:
      containers:
        - name: notebook
          image: t9kpublic/torch-2.1.0-notebook:1.77.1
          volumeMounts:
            - name: workingdir
              mountPath: /t9k/mnt
          resources:
            requests:
              cpu: '8'
              memory: 16Gi
              nvidia.com/gpu: 1
            limits:
              cpu: '16'
              memory: 32Gi
              nvidia.com/gpu: 1
      volumes:
        - name: workingdir
          persistentVolumeClaim:
            claimName: tutorial

UI

对于很多 CRD,TensorStack 的 Web 控制台(console)提供了通过表单(form)创建其实例的方式。

例如,可使用如下表单创建 Notebook 实例:

create-notebook-detail
图 4:使用 UI 创建 Notebook。

下一步

  • 跟从快速开始的内容,快速完成基本的体验。
  • 阅读 AI 开发和应用章节,以学习 AI 开发相关的概念。
  • 阅读背景,了解产品的技术架构和设计思路等。

快速入门

欢迎使用“TensorStack AI 平台”!

本节将带领你快速体验 “TensorStack AI 平台” 的基本功能,并完成一个简单的 AI 项目,涵盖模型的构建、训练、部署等。

使用 TensorStack AI 平台之前,你需要:

  • 拥有一个账户,以登录系统。
  • 成为一个项目的成员,以使用集群资源。

下一步

训练你的第一个模型

本教程带领你使用 Notebook,来构建和训练一个 AI 模型。

创建 Notebook

在 TensorStack AI 平台首页,点击模型构建进入构建控制台(Build Console)。

landing-page
图 1:平台首页。

构建控制台(Build Console)的总览页面展示了多种资源,你可以点击右上角的按钮切换 Project,也可以点击事件配额标签页以查看当前 Project 最近发生的事件以及计算资源(CPU、内存、GPU 等)配额。

project
图 2:构建控制台(Build Console)。

创建 PVC

在创建 Notebook 之前,首先需要创建一个用于存储文件的 PVC(持久卷)。在左侧的导航菜单中点击存储 > 持久卷进入 PVC 管理页面,然后点击右上角的创建 PVC

project
图 3:创建 PVC。

在 PVC 创建页面,如下填写各个参数:

  • Name 填写 mnist
  • Size 填写 1Gi

其他参数保持默认即可。完成之后,点击创建

project
图 4:填写 PVC 参数。

在跳转回到 PVC 管理页面之后,可点击右上角的刷新图标来手动刷新 PVC 状态。下图展示 PVC mnist 已经创建完成。

project
图 5:PVC 管理页面。

创建 Notebook

在左侧的导航菜单中点击构建 > Notebook 进入 Notebook 管理页面,然后点击右上角的创建 Notebook

create-notebook
图 6:Notebook 创建页面。

在 Notebook 创建页面,如下填写各个参数:

  • 名称填写 mnist
  • 镜像类型选择 Jupyter镜像选择 t9kpublic/torch-2.1.0-notebook:1.77.1
  • 存储卷选择 mnist
  • 调度器选择默认调度器模板选择 large

完成之后,点击创建

create-notebook-detail
图 7:Notebook 创建详情页面。

在跳转回到 Notebook 管理页面之后,等待刚才创建的 Notebook 准备就绪。第一次拉取镜像可能会花费较长的时间,具体取决于集群的网络状况。点击右上角的刷新图标来手动刷新 Notebook 状态,待 Notebook 开始运行之后,点击右侧的打开进入其前端页面。

connect-notebook
图 8:在 Notebook 管理页面打开 Notebook。

现在 Notebook 已经可以使用了,你可以在这里进行模型的开发与测试。

jupyter
图 9:使用 Notebook。

使用 Notebook 训练模型

在 Notebook 的前端页面,点击左上角的 +,然后点击 Notebook 下的 Python3 以新建一个 .ipynb 文件。

jupyter-create-notebook
图 10:在 Notebook 中创建 .ipynb 文件。

复制下面的训练脚本到该 .ipynb 文件的代码框中。该脚本基于 PyTorch 框架,建立一个简单的卷积神经网络模型,并使用 MNIST 数据集的手写数字图像进行训练和测试。

torch_mnist.py
import os
import shutil

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils.tensorboard import SummaryWriter
from torchvision import datasets, transforms


class Net(nn.Module):

    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, 1)
        self.conv2 = nn.Conv2d(32, 64, 3, 1)
        self.conv3 = nn.Conv2d(64, 64, 3, 1)
        self.pool = nn.MaxPool2d(2, 2)
        self.dense1 = nn.Linear(576, 64)
        self.dense2 = nn.Linear(64, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = F.relu(self.conv3(x))
        x = torch.flatten(x, 1)
        x = F.relu(self.dense1(x))
        output = F.softmax(self.dense2(x), dim=1)
        return output


def train():
    global global_step
    for epoch in range(1, epochs + 1):
        model.train()
        for step, (data, target) in enumerate(train_loader, 1):
            data, target = data.to(device), target.to(device)
            optimizer.zero_grad()
            output = model(data)
            loss = criterion(output, target)
            loss.backward()
            optimizer.step()

            if step % 500 == 0:
                train_loss = loss.item()
                print('epoch {:d}/{:d}, batch {:5d}/{:d} with loss: {:.4f}'.
                      format(epoch, epochs, step, steps_per_epoch, train_loss))
                global_step = (epoch - 1) * steps_per_epoch + step

                writer.add_scalar('train/loss', train_loss, global_step)

        scheduler.step()
        global_step = epoch * steps_per_epoch
        test(val=True, epoch=epoch)


def test(val=False, epoch=None):
    label = 'val' if val else 'test'
    model.eval()
    running_loss = 0.0
    correct = 0

    with torch.no_grad():
        loader = val_loader if val else test_loader
        for data, target in loader:
            data, target = data.to(device), target.to(device)
            output = model(data)
            loss = criterion(output, target)
            running_loss += loss.item()
            prediction = output.max(1)[1]
            correct += (prediction == target).sum().item()

    test_loss = running_loss / len(loader)
    test_accuracy = correct / len(loader.dataset)
    msg = '{:s} loss: {:.4f}, {:s} accuracy: {:.4f}'.format(
        label, test_loss, label, test_accuracy)
    if val:
        msg = 'epoch {:d}/{:d} with '.format(epoch, epochs) + msg
    print(msg)

    writer.add_scalar('{:s}/loss'.format(label), test_loss, global_step)
    writer.add_scalar('{:s}/accuracy'.format(label), test_accuracy,
                      global_step)


device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
kwargs = {
    'num_workers': 1,
    'pin_memory': True
} if torch.cuda.is_available() else {}

torch.manual_seed(1)

model = Net().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=1, gamma=0.7)

dataset_path = './data'
transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.5), (0.5))])
train_dataset = datasets.MNIST(root=dataset_path,
                               train=True,
                               download=True,
                               transform=transform)
train_dataset, val_dataset = torch.utils.data.random_split(
    train_dataset, [48000, 12000])
test_dataset = datasets.MNIST(root=dataset_path,
                              train=False,
                              download=True,
                              transform=transform)
train_loader = torch.utils.data.DataLoader(train_dataset,
                                           batch_size=32,
                                           shuffle=True,
                                           **kwargs)
val_loader = torch.utils.data.DataLoader(val_dataset,
                                         batch_size=400,
                                         shuffle=False,
                                         **kwargs)
test_loader = torch.utils.data.DataLoader(test_dataset,
                                          batch_size=1000,
                                          shuffle=False,
                                          **kwargs)

log_dir = './log'
if os.path.exists(log_dir):
    shutil.rmtree(log_dir, ignore_errors=True)
writer = SummaryWriter(log_dir)

global_step = 0
epochs = 10
steps_per_epoch = len(train_loader)
train()
test()

torch.save(model.state_dict(), 'model_state_dict.pt')

点击上方的运行按钮,可以看到训练开始进行:

jupyter-training
图 11:在 Notebook 中运行训练。

训练结束后,点击左上角的新建文件夹按钮,为新文件夹命名 first-model,并将当前教程产生的所有文件拖拽移动到其中。

create-folder
图 12:在 Notebook 中创建文件夹。

下一步

进行并行训练

本教程带领你使用 PyTorchTrainingJob,将教程训练你的第一个模型中的模型训练改进为使用 GPU 加速的数据并行训练。

在 Notebook 中准备并行训练

回到 Notebook mnist,在 HOME 目录(即左侧边栏文件浏览器显示的根目录 /)下,点击左上角的 +,然后点击 Other 下的 Python File 以新建一个 Python 脚本文件。

create-py-file

向该文件复制以下代码,并将其命名为 torch_mnist_trainingjob.py。该脚本在上一篇教程的脚本的基础上进行了修改以支持数据并行训练。

torch_mnist_trainingjob.py
import argparse
import logging
import os
import shutil

import torch
import torch.distributed as dist
import torch.nn as nn
import torch.nn.functional as F
from torch.nn.parallel import DistributedDataParallel as DDP
import torch.optim as optim
from torch.utils.tensorboard import SummaryWriter
from torchvision import datasets, transforms

parser = argparse.ArgumentParser(
    description='DDP training of PyTorch model for MNIST.')
parser.add_argument(
    '--backend',
    type=str,
    help='Distributed backend',
    choices=[dist.Backend.GLOO, dist.Backend.NCCL, dist.Backend.MPI],
    default=dist.Backend.GLOO)
parser.add_argument('--log_dir',
                    type=str,
                    help='Path of the TensorBoard log directory.')
parser.add_argument('--save_path',
                    type=str,
                    help='Path of the saved model.')
parser.add_argument('--no_cuda',
                    action='store_true',
                    default=False,
                    help='Disable CUDA training.')
logging.basicConfig(format='%(message)s', level=logging.INFO)


class Net(nn.Module):

    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, 1)
        self.conv2 = nn.Conv2d(32, 64, 3, 1)
        self.conv3 = nn.Conv2d(64, 64, 3, 1)
        self.pool = nn.MaxPool2d(2, 2)
        self.dense1 = nn.Linear(576, 64)
        self.dense2 = nn.Linear(64, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = F.relu(self.conv3(x))
        x = torch.flatten(x, 1)
        x = F.relu(self.dense1(x))
        output = F.softmax(self.dense2(x), dim=1)
        return output


def train():
    global global_step
    for epoch in range(1, epochs + 1):
        model.train()
        for step, (data, target) in enumerate(train_loader, 1):
            data, target = data.to(device), target.to(device)
            optimizer.zero_grad()
            output = model(data)
            loss = criterion(output, target)
            loss.backward()
            optimizer.step()

            if step % (500 // world_size) == 0:
                train_loss = loss.item()
                logging.info(
                    'epoch {:d}/{:d}, batch {:5d}/{:d} with loss: {:.4f}'.
                    format(epoch, epochs, step, steps_per_epoch, train_loss))
                global_step = (epoch - 1) * steps_per_epoch + step

                if args.log_dir and rank == 0:
                    writer.add_scalar('train/loss', train_loss, global_step)

        scheduler.step()
        global_step = epoch * steps_per_epoch
        test(val=True, epoch=epoch)


def test(val=False, epoch=None):
    label = 'val' if val else 'test'
    model.eval()
    running_loss = 0.0
    correct = 0

    with torch.no_grad():
        loader = val_loader if val else test_loader
        for data, target in loader:
            data, target = data.to(device), target.to(device)
            output = model(data)
            loss = criterion(output, target)
            running_loss += loss.item()
            prediction = output.max(1)[1]
            correct += (prediction == target).sum().item()

    test_loss = running_loss / len(loader)
    test_accuracy = correct / len(loader.dataset)
    msg = '{:s} loss: {:.4f}, {:s} accuracy: {:.4f}'.format(
        label, test_loss, label, test_accuracy)
    if val:
        msg = 'epoch {:d}/{:d} with '.format(epoch, epochs) + msg
    logging.info(msg)

    if args.log_dir and rank == 0:
        writer.add_scalar('{:s}/loss'.format(label), test_loss, global_step)
        writer.add_scalar('{:s}/accuracy'.format(label), test_accuracy,
                          global_step)


if __name__ == '__main__':
    args = parser.parse_args()

    logging.info('Using distributed PyTorch with %s backend', args.backend)
    dist.init_process_group(backend=args.backend)
    rank = dist.get_rank()
    world_size = dist.get_world_size()
    local_rank = int(os.environ['LOCAL_RANK'])

    use_cuda = not args.no_cuda and torch.cuda.is_available()
    if use_cuda:
        logging.info('Using CUDA')
    device = torch.device('cuda:{}'.format(local_rank) if use_cuda else 'cpu')
    kwargs = {'num_workers': 1, 'pin_memory': True} if use_cuda else {}

    torch.manual_seed(1)

    dataset_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                                'data')
    # rank 0 downloads datasets in advance
    if rank == 0:
        datasets.MNIST(root=dataset_path, train=True, download=True)

    model = Net().to(device)
    model = DDP(model)
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(model.parameters(), lr=0.001 * world_size)
    scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=1, gamma=0.7)

    transform = transforms.Compose(
        [transforms.ToTensor(),
         transforms.Normalize((0.5), (0.5))])
    train_dataset = datasets.MNIST(root=dataset_path,
                                   train=True,
                                   download=False,
                                   transform=transform)
    train_dataset, val_dataset = torch.utils.data.random_split(
        train_dataset, [48000, 12000])
    test_dataset = datasets.MNIST(root=dataset_path,
                                  train=False,
                                  download=False,
                                  transform=transform)
    train_loader = torch.utils.data.DataLoader(train_dataset,
                                               batch_size=32 * world_size,
                                               shuffle=True,
                                               **kwargs)
    val_loader = torch.utils.data.DataLoader(val_dataset,
                                             batch_size=400,
                                             shuffle=False,
                                             **kwargs)
    test_loader = torch.utils.data.DataLoader(test_dataset,
                                              batch_size=1000,
                                              shuffle=False,
                                              **kwargs)

    if args.log_dir and rank == 0:
        if os.path.exists(args.log_dir):
            shutil.rmtree(args.log_dir, ignore_errors=True)
        writer = SummaryWriter(args.log_dir)

    global_step = 0
    epochs = 10
    steps_per_epoch = len(train_loader)
    train()
    test()

    if rank == 0:
        torch.save(model.state_dict(), args.save_path)

创建 Job 进行并行训练

回到模型构建控制台,在左侧的导航菜单中点击构建 > Job 进入 Job 管理页面,然后点击右上角的创建 Job > PyTorch

create-job

为了简化操作,在 Job 创建页面,点击预览 YAML,然后直接复制下面的 YAML 配置文件并粘贴到编辑框中,然后点击创建

job.yaml
apiVersion: batch.tensorstack.dev/v1beta1
kind: PyTorchTrainingJob
metadata:
  name: mnist                    # Job 名称
spec:
  tensorboardSpec:               # TensorBoard 服务器规约
    resources:
      limits:
        cpu: 1
        memory: 1Gi
    trainingLogFilesets:
      - t9k://pvc/mnist/log      # 日志文件路径
    image: tensorflow/tensorflow:2.14.0
                                 # TensorBoard 服务器使用的镜像
  torchrunConfig:
    enabled: true                # torchrun 启动
    maxRestarts: 3
    procPerNode: "4"             # 每个副本启动的进程数
    rdzvBackend: c10d
    extraOptions: []
  replicaSpecs:
    - type: node
      replicas: 1                # 副本数
      restartPolicy: ExitCode
      template:
        spec:
          securityContext:
            runAsUser: 1000
          containers:
            - name: pytorch
              image: t9kpublic/pytorch-1.13.0:sdk-0.5.2
                                       # 容器的镜像
              workingDir: /t9k/mnt     # 工作路径
              args:                    # `python`命令的参数
                - torch_mnist_trainingjob.py
                - "--log_dir"
                - "log"
                - "--save_path"
                - "./model_state_dict.pt"
                - "--backend"
                - "nccl"
              resources:               # 计算资源
                limits:                # 限制量
                  cpu: 8               # CPU
                  memory: 16Gi         # 内存
                  nvidia.com/gpu: 4    # GPU
                requests:              # 请求量
                  cpu: 4
                  memory: 8Gi
                  nvidia.com/gpu: 4
              volumeMounts:
                - name: data
                  mountPath: /t9k/mnt  # 挂载路径
                - name: dshm
                  mountPath: /dev/shm  # 挂载共享内存
          volumes:
            - name: data
              persistentVolumeClaim:
                claimName: mnist       # 要挂载的 PVC
            - name: dshm
              emptyDir:
                medium: Memory
create-job-detail

在跳转回到 Job 管理页面之后,等待刚才创建的 Job 就绪。第一次拉取镜像可能会花费较长的时间,具体取决于集群的网络状况。点击右上角的刷新图标来手动刷新 Job 状态,待 Job 开始运行之后,点击其名称进入详情页面。

job-created

可以看到,Job 及其创建的 4 个 Worker(工作器)正在运行。

job-detail

切换到副本标签页,点击副本的日志会显示其命令行输出,可以看到并行训练的当前进度。

job-log-view
job-log

torch_mnist_trainingjob.py 训练脚本在训练过程中添加了 TensorBoard 回调并将日志保存在了 log 目录下,Job 相应地启动了一个 TensorBoard 服务器用于可视化展示这些数据。点击 TensorBoard 右侧的 Running 进入其前端页面。

tensorboard

一段时间之后,Job 的状态变为 Done,表示训练已经成功完成。回到 Notebook mnist,将当前教程产生的所有文件移动到名为 parallel-training 的新文件夹下。

下一步

部署模型

本教程带领你使用 SimpleMLService,部署模型为推理服务。

在教程训练你的第一个模型进行并行训练中,训练完成的模型都被保存为文件 model_state_dict.pt,这两个模型文件所对应的模型是相同的。本教程将部署这个模型为推理服务。

准备模型文件

这里我们使用 TorchServe 部署 PyTorch 模型。回到 Notebook mnist,在 HOME 目录(即左侧边栏文件浏览器显示的根目录 /)下新建以下文件:

model.py
import torch
from torch import nn
import torch.nn.functional as F


class Net(nn.Module):

    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, 1)
        self.conv2 = nn.Conv2d(32, 64, 3, 1)
        self.conv3 = nn.Conv2d(64, 64, 3, 1)
        self.pool = nn.MaxPool2d(2, 2)
        self.dense1 = nn.Linear(576, 64)
        self.dense2 = nn.Linear(64, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = F.relu(self.conv3(x))
        x = torch.flatten(x, 1)
        x = F.relu(self.dense1(x))
        output = F.log_softmax(self.dense2(x), dim=1)
        return output
handler.py
from torchvision import transforms
from ts.torch_handler.image_classifier import ImageClassifier
from torch.profiler import ProfilerActivity


class MNISTDigitClassifier(ImageClassifier):
    image_processing = transforms.Compose(
        [transforms.ToTensor(),
         transforms.Normalize((0.5), (0.5))])

    def __init__(self):
        super().__init__()
        self.profiler_args = {
            "activities": [ProfilerActivity.CPU],
            "record_shapes": True,
        }

    # def postprocess(self, data):
    #     return data.argmax(1).tolist()

点击左上角的 +,然后点击 Other 下的 Terminal 以新建一个终端。

create-terminal

执行以下命令以打包一个 torch 的模型包(model archive):

# 使用 Notebook 中训练的模型
torch-model-archiver --model-name mnist \
  --version 1.0 \
  --model-file model.py \
  --handler handler.py \
  --serialized-file first-model/model_state_dict.pt

# 如果使用 Job 中训练的模型,切换参数
# --serialized-file parallel-training/model_state_dict.pt

部署推理服务

在 TensorStack AI 平台首页,点击Deploy进入模型部署控制台。

landing-page

模型部署控制台的总览页面展示了当前部署服务的数量以及资源使用情况。在左侧的导航菜单中点击部署 > SimpleMLService,点击右上角的 + 弹出创建对话框,然后复制下面的 YAML 配置文件并粘贴到编辑框中,最后点击创建

apiVersion: tensorstack.dev/v1beta1
kind: SimpleMLService
metadata:
  name: mnist
spec:
  replicas: 1
  storage:
    pvc:
      containerPath: /var/lib/t9k/models
      name: mnist
      subPath: .
  pytorch:
    image: pytorch/torchserve:0.9.0-cpu
    modelsFlag: "mnist=mnist.mar"
    resources: 
      requests:
        cpu: 1
        memory: 1Gi
create-simplemlservice

在跳转回到 SimpleMLService 管理页面之后,等待刚才创建的 SimpleMLService 准备就绪。

  • 第一次拉取镜像可能会花费较长的时间,具体取决于集群的网络状况。
  • 点击右上角的刷新按钮以手动刷新 SimpleMLService 状态。

使用推理服务

查看推理服务地址

待 SimpleMLService 就绪之后,点击其名称进入详情页面。

enter-simplemlservice

页面中展示的 DNS 即为推理服务地址,注意该地址只能从集群内部访问。

simplemlservice-detail

访问推理服务

回到 Notebook mnist,在终端中执行以下命令以下载测试数据,并向推理服务发送请求。注意变量 URL 的值需要修改为实际部署的推理服务的地址。

# 下载测试图像文件
wget https://t9k.github.io/user-manuals/assets/get-started/deployment/{0,1,2}.png

# 注意:此 URL 只适合在集群内当前项目(Project)内部(例如当前项目的 Notebook 中)访问使用
URL="http://mnist.demo.svc.cluster.local/v1/models/mnist:predict"
curl -T 0.png $URL    # 或使用 `1.png`, `2.png`

响应体应是一个类似于下面的 JSON,其预测了图片最有可能是的 5 个数字以及相应的概率:

{
  "0": 1.0,
  "2": 1.7797361302828807e-16,
  "9": 6.094195260341553e-19,
  "6": 1.5410183526346253e-19,
  "5": 7.889719768364669e-20
}

清理

体验结束后,可将当前教程产生的所有文件移动到名为 deployment 的新文件夹下。

也可以将部署的推理服务删除:

# optional, delete service if desired.
kubectl delete SimpleMLService mnist

下一步

AI 开发和应用

TensorStack AI 平台提供了一套完整、全面的工具和服务,对 AI 模型的构建、训练和部署提供全流程的支持,从而助力研究人员轻松、高效地实现 AI 项目,加速 AI 模型的研究、开发和应用。

下图展示了在平台上开发一个深度学习模型的完整流程,以及各个模块发挥的功能:

ai-development

下一步

模型构建

一次完整的模型构建实验由许多步骤组成,包括准备实验数据、开发机器学习算法、选择训练超参数和执行训练等等。

TensorStack AI 平台的模型构建模块可以帮助你在分布式集群中快速方便地完成上述工作。模型构建模块的功能包括:

function
  • Notebook:在线机器学习开发工具,你可以使用此模块直接在平台上开发机器学习脚本。
  • TensorBoard:机器学习可视化工具,实现训练过程可视化、模型可视化。
  • Job:一类任务型资源,其中包括 TensorFlowTrainingJob、MPIJob 等多种资源,使用各种机器学习框架、通信协议来进行分布式计算。其中 TensorFlowTrainingJob 和 PyTorchTrainingJob 集成了 TensorBoard 的创建功能,可以监控训练进程和查看训练结果。
  • AutoTune:超参数调优实验,在给定的搜索空间中查找最优的超参数组合以及机器学习网络结构。AutoTune 在进行超参数调优的过程中需要使用 TrainingJob(根据训练框架选用 TensorFlowTrainingJob、PyTorchTrainingJob 或 XGBoostTrainingJob)对超参数的效果进行验证。

架构

architecture

如上图所示:

  • TensorStack CLI 是 TensorStack AI 平台所使用的命令行工具,可以用于操作几乎所有 TensorStack AI 平台的模块,包括模型构建。
  • Kubernetes API Server 是 Kubernetes 的重要组成部分,负责对外提供接口,接受对集群的操作请求。在此框架中,Kubernetes API Server 需要向模型构建模块提供集群中的资源信息,同时接收资源的创建、删除等请求。
  • 红框中的内容为模型构建模块的组成部分:
    • 控制台(Console):模块的交互界面,你可以通过此界面使用模块的全部功能。
    • 服务器(Server):模块功能的提供者,为你提供查看、创建、修改和删除资源的接口。
    • 控制器(Controller):资源控制器,用于处理资源的创建和修改请求。

下一步

Notebook

JupyterLab 是一款非常流行的机器学习开发工具,它通过友好易用的 Web 界面提供交互式计算环境,支持多种编程语言和执行环境,在机器学习、AI、数据处理、数值模拟、统计建模、数据可视化等领域被广泛使用。

用户可以使用 Notebook CRD 在集群中快速部署一个 JupyterLab 服务,同时本产品还提供 GPU 支持、SSH 访问支持等功能。

创建 Notebook

下面是一个基本的 Notebook 配置示例:

# notebook-tutorial.yaml
apiVersion: tensorstack.dev/v1beta1
kind: Notebook
metadata:
  name: tutorial
spec:
  type: jupyter
  template:
    spec:
      containers:
        - name: notebook
          image: t9kpublic/torch-2.1.0-notebook:1.77.1
          volumeMounts:
            - name: workingdir
              mountPath: /t9k/mnt
          resources:
            requests:
              cpu: '8'
              memory: 16Gi
              nvidia.com/gpu: 1
            limits:
              cpu: '16'
              memory: 32Gi
              nvidia.com/gpu: 1
      volumes:
        - name: workingdir
          persistentVolumeClaim:
            claimName: tutorial

在该例中,spec.template.spec 字段定义所要创建的 Pod 的规约:

  1. 指示 Pod 运行一个 notebook 容器 (spec.template.containers),该容器运行的镜像是 t9kpublic/torch-2.1.0-notebook:1.77.1,这是一个 Notebook 镜像
  2. 通过 spec.template.spec.volumesspec.template.containers[].volumeMounts 指示挂载网络文件系统 PVC tutorial/t9k/mnt
  3. 通过 spec.template.spec.containers[].resources 指定使用的 CPU、memory、GPU 资源 。

使用 GPU

Notebook 支持通过申请使用 GPU 资源,例如:

apiVersion: tensorstack.dev/v1beta1
kind: Notebook
metadata:
  name: tutorial
spec:
  type: jupyter
  template:
    spec:
      containers:
        - name: notebook
          image: t9kpublic/torch-2.1.0-notebook:1.77.1
          volumeMounts:
            - name: workingdir
              mountPath: /t9k/mnt
          resources:
            limits:
              cpu: '16'
              memory: 32Gi
              nvidia.com/gpu: 1
          command: []
      volumes:
        - name: workingdir
          persistentVolumeClaim:
            claimName: tutorial

在该例中:

  • 申请使用 16 个 CPU、32Gi 内存以及一个 NVIDIA GPU;系统会自动将 Notebook 调度到集群中某个能提供这些资源的节点上。

SSH 访问

Notebook 提供运行 SSH Server 的支持。下面的 Notebook 示例运行一个支持 SSH 连接的 JupyterLab 镜像:

apiVersion: tensorstack.dev/v1beta1
kind: Notebook
metadata:
  name: tutorial
spec:
  type: jupyter
  template:
    spec:
      containers:
        - name: notebook
          image: t9kpublic/torch-2.1.0-notebook:1.77.1
          volumeMounts:
            - name: workingdir
              mountPath: /t9k/mnt
          resources:
            limits:
              cpu: '16'
              memory: 32Gi
              nvidia.com/gpu: 1
      volumes:
        - name: workingdir
          persistentVolumeClaim:
            claimName: tutorial
  ssh:
    authorized_keys:
      - example-user
    enabled: true
    serviceType: ClusterIP

在该例中,用户:

  1. 设置 spec.ssh.enabled 字段的值为 true,T9k 系统将会自动创建一个处理 SSH 请求的 Service
  2. 通过 spec.ssh.serviceType 字段指定服务类型为 ClusterIP
  3. 设置自动挂载存放在 Secret/example-user 中的用户 SSH key;

使用此 SSH 服务需要通过 t9k-pf 工具进行端口转发。

资源回收

T9k 系统提供空闲 Notebook 资源回收的支持。系统在检测到 Notebook 处于空闲状态并超过一定时长时,就会自动删除工作负载以释放计算资源。目前,资源回收仅针对 Jupyter 类型的 Notebook,其他类型(例如 RStudio)的 Notebook 不会被回收。

管理员可设置回收策略,使得:

  • Notebook 没有活跃运行超过 1h (管理员可修改此时长)后,标记该 Notebook 为 Idle
  • Notebook 进入 Idle 状态超过 24h (管理员可修改此时长)后,删除该 Notebook 底层工作负载。

如果需要再次使用该 Notebook,你可以在模型构建控制台中手动点击恢复按钮。

Notebook 镜像

T9k 提供了一些预先构建的镜像,与 JupyterLab 原生镜像相比内置了更丰富的工具包,请参阅 Notebook 标准镜像列表

在这些镜像中:

  • 默认启动一个 JupyterLab 服务。
  • 预装了 Python3 以及 tensorflowpytorchkeraspandasscikit-learn 等常用 Python 包。
  • 身份是一个名为 t9kuser 的非 root 用户(用户 ID 为 1000,组 ID 为 1000),$HOME 目录为 /t9k/mnt
  • 预装了 tensorboard 插件,你可以在网页中创建 TensorBoard 以可视化数据。

用户也可以自行构建镜像,并上载到镜像 registry 中供使用。

下一步

用户可尝试如下功能:

参考

TensorBoard

TensorBoard 是 TensorFlow 提供的一种可视化机器学习过程和结果的工具,功能强大且广泛应用于多种框架。

你可以使用本产品在集群中一键部署 TensorBoard,可视化训练模型。

创建 TensorBoard

下面是一个基本的 TensorBoard 配置示例:

# tensorboard-example.yaml
apiVersion: tensorstack.dev/v1beta1
kind: TensorBoard
metadata:
  name: pytorchtrainingjob-tensorboard
  namespace: t9k-example
spec:
  image: docker.mirrors.ustc.edu.cn/tensorflow/serving:2.6.0-gpu
  trainingLogFilesets:
  - t9k://pvc/pytorchtrainingjob-tensorboard-pvc/log

在该例中,TensorBoard 使用 docker.mirrors.ustc.edu.cn/tensorflow/serving:2.6.0-gpu 镜像,对名为 pytorchtrainingjob-tensorboard-pvc 的 PVC 中 /log 路径下的模型数据进行可视化。

FileSet

FileSet 是一种特殊的资源定位符(URI),是一种用于定位多种存储技术中的资源的字符串。

FileSet 的格式为 t9k://storage-type/storage-identity/path,由下列四部分构成:

  • 协议:t9k://
  • 存储器类型:当前 FileSet 支持 PVC(在 FileSet 中写作 pvc) 和 MinIO(在 FileSet 中写作 minio) 两种存储器。
  • 存储器定位方式:FileSet 使用 PVC 的名称来定位 PVC 存储器,使用记录了 MinIO 地址、用户名和密码的 Secret 来定位 MinIO 存储器。
  • 数据在存储器中的路径:模型在存储器中的准确位置。

下面是两个 FileSet 示例:

  • t9k://pvc/pytorchtrainingjob-tensorboard-pvc/log/model 表示:所指向的资源被存储在名为 pytorchtrainingjob-tensorboard-pvc 的 PVC 中的 log/model 路径下。
  • t9k://minio/secret-name/bucket1/log/model 表示:所指向的资源被存储在一个 MinIO 中名为 bucket1 的 Bucket 中的 log/model 路径下,该 MinIO 的地址、用户名和密码被存储在名为 secret-name 的 Secret 中。

TrainingJob 自动创建 TensorBoard

我们在 TensorFlowTrainingJobPyTorchTrainingJob 中集成了 TensorBoard 的创建,你可以在创建 TrainingJob 后直接进入 TensorBoard 监控训练进程和查看训练结果。

资源回收

TensorBoard 提供空闲资源回收的支持,在检测到 TensorBoard 处于空闲状态并超过一定时长时,删除工作负载以释放计算资源。默认情况下(管理员可修改配置):

  • TensorBoard 无人使用超过 1h 后,标记该 TensorBoard 为 Idle
  • TensorBoard 进入 Idle 状态超过 24h 后,删除该 TensorBoard 底层工作负载。

如果需要再次使用该 TensorBoard,你可以在模型构建控制台中手动点击恢复按钮。

AutoTune

为了降低 AI 开发门槛和逐渐实现机器学习自动化,TensorStack AI 平台提供了自动化机器学习 (AutoML)工具 AutoTune。AutoTune 具有以下特点:

  • 内置最新的自动机器学习算法,为用户自动地进行特征工程、神经网络架构搜索、超参调优和模型压缩。
  • 提供可视化展示平台,实时跟踪超参数训练过程,以交互式图形和表格的形式刻画多个不同维度的信息,用户可以借此更好地比较、分析、决策出最优参数。
  • 持海量实验数据的存储,让用户轻松地实现任意实验结果之间的比较。
  • 融合领先的 AI 最佳实践,提供自动化、准确性和协作水平,提高企业 AI 生产效率。

基本结构

concept

在上述结构图中:

  • AutoTune Controller 是 AutoTuneExperiment 的控制器,可以看做是 AutoTune 实验的入口。用户在集群中创建 AutoTuneExperiment 资源后,由控制器创建 AutoTune Server 和 Web 来执行 AutoTune 实验。
  • AutoTune Server 是执行实验的主体,其中包括:
    • Optimizer:超参数调优器,在限定的搜索空间内用特定的调优算法选择合适的超参数组合。
    • Training Manager:训练任务管理器,使用 Optimizer 产生的超参数,创建 TrainingJob 进行训练,并将训练结果反馈给 Optimizer 用于下一次超参数选择。AutoTune 可以同时创建多组 TrainingJob 来测试不同的超参数组合以加快训练效率。目前 AutoTune 支持使用 TensorFlowTrainingJobPyTorchTrainingJobXGBoostTrainingJob 进行训练。
  • AutoTune Web 是 AutoTune 的可视化界面,你可以通过此界面实时查看实验状态,对比各组超参数对实验产生的影响。

AutoTuneExperiment

你可以通过创建 AutoTuneExperiment 来实现自动优化模型超参数。

创建 AutoTuneExperiment

下面是一个基本的 AutoTuneExperiment 示例:

apiVersion: tensorstack.dev/v1beta1
kind: AutoTuneExperiment
metadata:
  name: experiment-sample
spec:
  maxExecSeconds: 7200
  maxTrialNum: 50
  trialConcurrency: 3
  searchSpace: |-
    {
      "batch_size": {"_type": "choice", "_value": [512, 1024, 2048, 4096, 8092]},
      "learning_rate": {"_type": "choice", "_value": [0.0001, 0.001, 0.01, 0.1]}
    }
  trainingConfig:
    type: tensorflow
    tasks:
      - type: worker
        replicas: 1
        template:
          spec:
            securityContext:
              runAsUser: 1000
            containers:
              - command:
                  - python3
                  - dist_mnist.py
                workingDir: /mnt/mnist-distributed
                imagePullPolicy: IfNotPresent
                image: t9kpublic/tensorflow-1.15.2:tuner-2.23
                name: tensorflow
  tuner:
    builtinTunerName: TPE
    classArgs: |-
      {
        "optimize_mode": "minimize", 
        "constant_liar_type": "min"
      }

在该例中:

  • 使用 TensorFlowTrainingJob 进行训练(由 trainingConfig 字段指定,详细配置方法请参阅训练框架支持)。
  • 使用 TPE 算法进行超参数调优,算法的参数为 {"optimize_mode": "minimize", "constant_liar_type": "min"}(由 tuner 字段指定,更多参数请参阅超参数调优算法)。
  • 超参数的搜索空间为 {"batch_size": {"_type": "choice", "_value": [512, 1024, 2048, 4096, 8092]},"learning_rate": {"_type": "choice", "_value": [0.0001, 0.001, 0.01, 0.1]}}(由 searchSpace 字段指定,搜索空间的格式及含义请参阅搜索空间)。
  • 可以同时测试 3 组超参数,最大测试次数为 50(分别由 trialConcurrencymaxTrialNum 字段指定),实验的最大执行时间为 2 小时(7200 秒,由 maxExecSeconds 字段指定),如果时间超出,实验进入 TIMEOUT 状态。

AIStore 的使用

AutoTuneExperiment 支持将实验数据存储在 AIStore 中,通过设置 spec.aistore 字段以使用 AIStore 数据库,其中:

  • spec.aistore.folder 声明实验数据存储在哪个 AIStore 文件夹中,内容应填写文件夹的 ID。
  • spec.aistore.secret 引用一个 K8s Secret,其中应记录 API Key,用于上传数据时进行身份验证。

下面是一个存储 APIKey 的 Secret 示例:

apiVersion: v1
data:
  apikey: ZDQyMjJjZjUtMmI0Ni00Mjk2LWFiMzYtYWI4NmVhZGUwZjQx
kind: Secret
metadata:
  name: aistore-secret
type: Opaque

搜索空间

搜索空间是实验过程中超参数的设置范围,AutoTuneExperiment 会在此范围中选择超参数进行训练,最后找出最优的超参数组合。

搜索空间是一个 JSON 结构,具体格式请参阅搜索空间

训练框架支持

AutoTuneExperiment 支持对多种训练框架进行超参数的调优,包括 TensorFlow、PyTorch 和 XGBoost。

AutoTuneExperiment 通过设置 spec.trainingConfig 字段实现对上述框架的支持。其中:

  • spec.trainingConfig.type 可设置为 tensorflowpytorchxgboost,分别表示使用 TensorFlow、PyTorch 和 XGBoost 框架进行训练。
  • spec.trainingConfig.tasks 字段的设置请根据所使用的框架种类分别参阅 TensorFlowTrainingJobPyTorchTrainingJobXGBoostTrainingJob

超参数调优算法

AutoTuneExperiment 在调参过程中需要使用超参数调优算法对超参数进行选择,对于不同的训练框架和不同的超参数种类,超参数调优算法的效率和效果也是不一样的。

算法根据功能和定义分为两类:

  • Tuner 算法:超参数调优算法,用于选取合适的超参数组合。
  • Assessor 算法:训练评估算法,用于判断当前训练是否符合预期,如果不符合则终止训练。

算法的详细介绍以及参数配置请参阅超参数调优算法

实验状态

AutoTuneExperiment 的生命周期包括以下五个阶段:

  • PENDING:AutoTune 的相关组件(包括 AutoTune Server 和 AutoTune Web)已经创建成功,等待控制器启动 AutoTuneExperiment。
  • RUNNING:AutoTuneExperiment 运行中。
  • TIMEOUT:如果达到最大执行时间(由 spec.maxExecSeconds 字段指定)后,实验仍未完成(实际训练次数小于 maxTrialNum 字段指定的训练次数),则实验超时,不再创建新的训练。
  • DONE:AutoTuneExperiment 在最大执行时间内完成了 maxTrialNum 字段指定的训练次数(无论成功或失败),则实验完成。
  • ERROR:AutoTuneExperiment 初始化阶段或运行阶段出现错误。
phase

下一步

搜索空间

搜索空间用于定义超参数的范围,AutoTune 会在这一范围内对超参数进行组合并测试,最后得到效果最好的一组训练。

格式

{
  "parameter1": {"_type": "choice", "_value":[1, 2, 3, 4]},
  "parameter2": {"_type": "randint", "_value":[1, 10]},
  ...
}

在上述结构中:

  • 每一个条目都记录了一个超参数的名称和搜索方式:
    • 每一个条目的键值(例如 parameter1parameter2)表示超参数的名称。
    • _type 是超参数搜索方法。
    • _value 表示搜索方法所使用的参数。
  • choicerandint 表示超参数的搜索方法,其具体含义请参阅搜索方法

搜索方法

_type_value 格式详细描述
choice数组(数字或字符串)每次训练选取数组 _value 中一个值作为超参数。例:{"learning_rate":{"_type": "choice", "_value": [0.01, 0.02, 0.1, 0.2]}},进行超参数调优时,每一组训练会从四个值中选取一个。
randint[lower, upper]每次训练选取 lowerupper 之间中的一个随机整数(不包括 upper)作为超参数。例:{"learning_rate":{"_type": "randint", "_value": [1, 10]}},进行超参数调优时,每一组训练可能取到的值有 [1, 2, 3, 4, 5, 6, 7, 8, 9]
uniform[low, high]每次训练从 lowerupper 区间内均匀采样作为超参数。
quniform[low, high, q]取值方法为 clip(round(uniform(low, high) / q) * q, low, high),此公式含义为:从 lowhigh 区间内均匀采样,然后将取值除以 q,并四舍五入为整数,然后将超出 [low, high] 区间的值舍弃,加上 lowupper 两个值,构成选值区间。例:_value[0, 10, 2.5],表示超参数的选值范围时 [0, 2.5, 5, 7.5, 10]_value[2, 10, 5],表示超参数的选值范围时 [2, 5, 10]
loguniform[low, high]取值方法为 exp(uniform(log(low), log(high))),此公式含义为:从 log(low)log(high) 区间内均匀采样得到样本 x,然后计算 exp(x) 得到超参数。
qloguniform[low, high, q]取值方法为 clip(round(loguniform(low, high) / q) * q, low, high)(其中 loguniform(low, high) 表示 exp(uniform(log(low), log(high)))),此公式含义参考 quniformloguniform 条目。
normal[mu, sigma]超参数的取值满足正态分布 N(mu, sigma^2)
qnormal[mu, sigma, q]取值方法为 round(normal(mu, sigma) / q) * q,此公式含义参考 quniform 条目。
lognormal[mu, sigma]取值方法为 exp(normal(mu, sigma)),此公式含义参考 loguniform 条目。
qlognoraml[mu, sigma, q]取值方法为 round(exp(normal(mu, sigma)) / q) * q,此公式含义参考 quniformloguniform 条目。

超参数调优算法

AutoTuneExperiment 在调参过程中需要使用超参数调优算法对超参数进行选择,对于不同的训练框架和不同的超参数种类,超参数调优算法的效率和效果也是不一样的。

算法根据功能和定义分为两类:

  • Tuner 算法:超参数调优算法,用于选取合适的超参数组合。
  • Assessor 算法:训练评估算法,用于判断当前超参数的训练中间结果是否符合预期,如果不符合则终止训练。

Tuner 算法

HyperOpt 类算法

HyperOpt 是一个用于超参数调优的 Python 库,其中主要包含三种超参数调优算法:RandomAnnealTPE。三种算法之间的区别以及算法的使用方法请参阅 HyperOpt 文档

算法支持使用的搜索方法有:choicerandintloguniformqloguniform

下面是 AutoTuneExperiment 使用此算法的一个示例(示例中的 classArgs 字段包含当前算法所有参数,有些参数在实际使用中可以选择不指定):

{
  "tuner": {
    "builtinTunerName": "Anneal",
    "classArgs": {
      "optimize_mode": "minimize", 
      "constant_liar_type": "min"
    }
  }
}

Evolution

进化算法(Evolution)是受生物进化启发得到的一种优化算法。进化算法的详细介绍请参阅 Evolutionary algorithm WIKI 文档

下面是 AutoTuneExperiment 使用此算法的一个示例(示例中的 classArgs 字段包含当前算法所有参数,有些参数在实际使用中可以选择不指定):

{
  "tuner": {
    "builtinTunerName": "Evolution",
    "classArgs": {
      "optimize_mode": "minimize", 
      "population_size": 32
    }
  }
}

Batch

Batch 是一种最简单的选参算法,此算法只支持一种超参数的优化(搜索空间中只能有一个条目)且仅支持 choice 搜索方法。

下面是 AutoTuneExperiment 使用此算法的一个示例(Batch 算法不需要填写参数):

{
  "searchSpace": {
      "learning_rate": {"_type": "choice", "_value": [0.0001, 0.001, 0.01, 0.1]}
  },
  "tuner": {
    "builtinTunerName": "Batch"
  }
}

上述示例中,搜索空间中只有一个超参数,且 _typechoice;Batch 算法不需要传入参数,所以没有填写 tuner.classArgs 字段。

GridSearch

一种基本的选参算法,根据搜索空间中的参数和范围,枚举所有可能的超参数组合,一一测试。

算法支持使用的搜索方法有:choicerandintquniform

下面是 AutoTuneExperiment 使用此算法的一个示例(GridSearch 算法不需要填写参数):

{
  "tuner": {
    "builtinTunerName": "GridSearch"
  }
}

MetisTuner

Metis 算法的详细介绍请参阅论文 Metis: Robustly Optimizing Tail Latencies of Cloud Systems

算法支持使用的搜索方法有:choicerandintuniformquniform

下面是 AutoTuneExperiment 使用此算法的一个示例(示例中的 classArgs 字段包含当前算法所有参数,有些参数在实际使用中可以选择不指定):

{
  "tuner": {
    "builtinTunerName": "MetisTuner",
    "classArgs": {
      "optimize_mode": "maximize",
      "no_resampling": true,
      "no_candidates": false,
      "selection_num_starting_points": 600,
      "cold_start_num": 10,
      "exploration_probability": 0.9
    }
  }
}

GPTuner

GPT 是一种能够极大减少超参数优化步骤的贝叶斯优化算法。算法的详细介绍请参阅 NNI GPTuner 文档

算法支持使用的搜索方法有:randintuniformquniformloguniformqloguniform 和数字形式的 choice

下面是 AutoTuneExperiment 使用此算法的一个示例(示例中的 classArgs 字段包含当前算法所有参数,有些参数在实际使用中可以选择不指定):

{
  "tuner": {
    "builtinTunerName": "GPTuner",
    "classArgs": {
      "optimize_mode": "maximize",
      "utility": "ei",
      "kappa": 5,
      "xi": 0,
      "nu": 2.5,
      "alpha": 1e-6,
      "cold_start_num": 10,
      "selection_num_warm_up": 100000,
      "selection_num_starting_points": 250
    }
  }
}

PPOTuner

PPO 算法继承了 OpenAI 中 ppo2 的主要逻辑,并适应 NAS 场景。

算法支持使用的搜索方法有:layer_choiceinput_choice。下面是一个搜索空间设置的示例:

{
  "first_conv": {"_type": "layer_choice", "_value": ["conv5x5", "conv3x3"]},
  "mid_conv": {"_type": "layer_choice", "_value": ["0", "1"]},
  "skip": {
    "_type": "input_choice",
    "_value": {"candidates": ["", ""], "n_chosen": 1}
  }
}

下面是 AutoTuneExperiment 使用此算法的一个示例(示例中的 classArgs 字段包含当前算法所有参数,有些参数在实际使用中可以选择不指定):

{
  "tuner": {
    "builtinTunerName": "PPOTuner",
    "classArgs": {
      "optimize_mode": "maximize",
      "trials_per_update": 20,
      "epochs_per_update": 4,
      "minibatch_size": 4,
      "ent_coef": 0.0,
      "lr": 3e-4,
      "vf_coef": 0.5,
      "max_grad_norm": 0.5,
      "gamma": 0.99,
      "lam": 0.95,
      "cliprange": 0.2
    }
  }
}

PBTTuner

PBT 算法得自 Population Based Training of Neural Networks

下面是 AutoTuneExperiment 使用此算法的一个示例(示例中的 classArgs 字段包含当前算法所有参数,有些参数在实际使用中可以选择不指定):

{
  "tuner": {
    "builtinTunerName": "PBTTuner",
    "classArgs": {
      "optimize_mode": "maximize",
      "population_size": 10,
      "factor": 0.2,
      "resample_probability": 0.25,
      "fraction": 0.2
    }
  }
}

Assessor 算法

Medianstop

Medianstop 算法的逻辑是:如果在某一步 S,当前运行的实验的最佳观测值比所有已经完成的训练的第 S 步前的观测值的中位数差,则停止此次训练。此策略出自论文 Google Vizier: A Service for Black-Box Optimization

下面是 AutoTuneExperiment 使用此算法的一个示例(示例中的 classArgs 字段包含当前算法所有参数,有些参数在实际使用中可以选择不指定):

{
  "assessor": {
    "builtinAssessorName": "Medianstop",
    "classArgs": {
      "optimize_mode": "maximize",
      "start_step": 0
    }
  }
}

在上述示例中,start_step 表示从第几步开始上传观测值(过早上传观测值,可能会错误的停止一些刚开始表现较差的训练)。

Curvefitting

Curvefitting 算法使用学习曲线拟合算法来预测未来的学习曲线性能。其逻辑是:如果在某一步,当前训练的预测结果是收敛的并且比历史上的最佳结果差,则停止此次训练。Curvefitting 算法的详细介绍请参阅 NNI Curvefitting 文档

下面是 AutoTuneExperiment 使用此算法的一个示例(示例中的 classArgs 字段包含当前算法所有参数,有些参数在实际使用中可以选择不指定):

{
  "assessor": {
    "builtinAssessorName": "Curvefitting",
    "classArgs": {
      "optimize_mode": "minimize",
      "epoch_num": 20,
      "start_step": 6,
      "threshold": 0.95,
      "gap": 1
    }
  }
}

模型部署

TensorStack AI 平台的模型部署模块可以帮助你快速地将训练完成的 AI 模型部署为推理服务。

针对不同的应用场景,有以下两种 TensorStack API可供使用:

  • MLService 是完善的模型推理服务,可用于生产环境,具有以下特性:
    • 基于 Serverless 架构,服务容量(serving capacity)可根据负载自动伸缩;
    • 自动暴露服务到集群外部,快速上线。
  • SimpleMLService 是精简的模型推理服务,可用于快速测试、固定容量部署等场景。具有以下特性:
    • 服务副本数目(replica)固定;
    • 集群外部访问需要额外配置 Ingress 等资源。

同时,TensorStack AI 平台对模型部署提供自动化的运维支持,包括性能和资源的监控告警以及故障检测,以保障推理服务长期可靠运行。

架构

模型部署模块的架构如下图:

architecture

根据用户提供的模型存储位置和 AI 框架等设置,模型部署模块的控制器(controller)协调模型下载并启动模型推理服务。

下一步

SimpleMLService

SimpleMLService 用于在 TensorStack AI 平台上简单、快捷地部署 AI 模型推理服务,可用于小规模模型部署,快速测试等场景。

SimpleMLService 具有以下特性:

  • 直接支持 TensorFlow、PyTorch 框架,并允许用户自定义框架,具有良好的可扩展性。
  • 支持 PVC、S3 模型存储方式。
  • 直接支持从集群内部访问推理服务;集群外访问需要用户进行额外配置。
  • 服务容量固定,不支持自动伸缩。

创建 SimpleMLService

下面是一个基本的 SimpleMLService 示例:

apiVersion: tensorstack.dev/v1beta1
kind: SimpleMLService
metadata:
  name: mnist
spec:
  replicas: 1
  storage:
    s3:
      secretName: s3-secret
      uri: s3://models/mnist/
      containerPath: /var/lib/t9k/model
  tensorflow:
    image: t9kpublic/tensorflow-serving:2.6.0
    resources: 
      requests:
        cpu: 1
        memory: 1Gi

本示例的 spec 字段的子字段释义如下:

  • replicas: 定义运行推理服务的副本数量是 1。
  • storage.s3: 设定使用 S3 存储模型,子字段的释义如下:
    • secretName: Secret s3-secret 中存储 S3 配置信息,其详情参见:创建-s3-secret
    • uri: 模型在 S3 中的存储路径是 s3://models/mnist/
    • containerPath: 模型被加载后,在容器中存储模型的文件系统路径是 /var/lib/t9k/model
  • tensorflow: 设定使用 tensorflow 推理框架,子字段释义如下:
    • image: 指定推理服务容器镜像 t9kpublic/tensorflow-serving:2.6.0
    • resources: 这顶一个副本 Pod 使用的资源量。

直接支持的 AI 框架

SimpleMLService 目前直接支持 TensorFlow、PyTorch 两种框架。

TensorFlow

可以通过设置 spec.tensorflow 字段来部署 TensorFlow 框架,参考示例:创建 SimpleMLService

当使用 TensorFlow 时,控制器会在容器中设置下列启动命令:

/usr/bin/tensorflow_model_server \
  --port=9090 \
  --rest_api_port=8080 \
  --model_name=<SimpleMLService name> \
  --model_base_path=<model-dir-in-container>

PyTorch

可以通过设置 spec.pytorch 字段来部署 PyTorch 框架,示例如下:

spec:
  pytroch:
    image: <pytorch-image>
    modelsFlag: "resnet-18=resnet-18.mar"
    resources: 
      requests:
        cpu: 1
        memory: 1Gi

当使用 PyTorch 时,控制器会在容器中设置下列启动命令:

torchserve \
  --start \
  --model-store=<mode-dir> \
  --models <spec.pytorch.modelsFlag>

自定义框架

如果需要使用 PyTorch, TensorFlow 之外的框架,可以通过设置 spec.custom 字段来自定义框架。

用户可在 spec.custom.spec 字段中定义一个完整的 PodSpec,并需要满足下列要求:

  1. 至少设置一个 containers 成员。
  2. 启动推理服务运行命令时,指定正确的模型路径。
  3. 未设置 spec.service 时,推理服务的服务端口应该使用 8080。

示例如下:

apiVersion: tensorstack.dev/v1beta1
kind: SimpleMLService
metadata:
  name: pvc-custom
spec:
  replicas: 1
  storage:
    s3:
      secretName: s3-secret
      uri: s3://models/mnist/
      containerPath: /custom/path
  custom:
    spec:
      containers:
      - name: user-container
        args:
        - --port=9000
        - --rest_api_port=8080
        - --model_name=mnist
        - --model_base_path=/custom/path
        command:
        - /usr/bin/tensorflow_model_server
        image: "t9kpublic/tensorflow-serving:2.6.0"

副本数量

副本数量通过字段 spec.replicas 设置,用于定义 SimpleMLService 的 Pod 数量,默认值是 1。

暴露服务

通过设置 spec.service 字段来选择将服务的哪个端口暴露出来。未设置时,默认将 Pod 的 8080 端口映射到 Service 的 80 端口。

下面是一个示例:

spec:
  service:
    ports:
    - name: http
      port: 80
      targetPort: 8080
      protocol: TCP
    type: ClusterIP

在该例中:

  • 将 Pod 的 8080 端口映射到 Service 的 80 端口,协议是 TCP。
  • Service 的 Type 是 ClusterIP

调度器

SimpleMLService 支持使用两种调度器:

通过 spec.scheduler 字段可以设置欲使用的调度器:

  • 不设置 spec.scheduler 字段,默认使用 Kubernetes 调度器。
  • 设置 spec.scheduler.t9kScheduler 字段,使用 T9k Scheduler 调度器。

在下面的示例中,SimpleMLService 使用 T9k Scheduler 调度器,并申请使用 队列 default 中的资源。

spec:
  scheduler:
    t9kScheduler:
      queue: default

模型存储

SimpleMLService 支持使用 S3 或 PVC 中存储的模型。

S3

如需使用 S3 服务中存储的模型:

  1. 创建存储 S3 服务信息的 Secret
  2. 设置 SimpleMLService 的 spec.storage.s3 字段

创建 S3 Secret

存储 S3 信息的 Secret 需要满足下列条件:

  1. 设置 label tensorstack.dev/resource: s3
  2. 设置 data[.s3cfg] 字段,内容是 Base64 编码的 s3cmd config。

YAML 示例如下:

apiVersion: v1
kind: Secret
metadata:
  name: s3-sample
  labels:
    tensorstack.dev/resource: s3
type: Opaque
data:
  .s3cfg: aG9zdF9iYXNlID0gZXhhbXBsZS5zMwpob3N0X2J1Y2tldCA9IGV4YW1wbGUuczMKYnVja2V0X2xvY2F0aW9uID0gdXMtZWFzdC0xCnVzZV9odHRwcyA9IEZhbHNlCmFjY2Vzc19rZXkgPSB1c2VyCnNlY3JldF9rZXkgPSBwYXNzd29yZApzaWduYXR1cmVfdjIgPSBGYWxzZQo=

其中 data[.s3cfg] 字段 Base64 解码后如下:

host_base = example.s3
host_bucket = example.s3
bucket_location = us-east-1
use_https = False
access_key = user
secret_key = password
signature_v2 = False

设置 spec.storage.s3

设置 SimpleMLService 的 spec.storage.s3 字段来使用存储在 S3 中的模型数据。spec.storage.s3 字段包含下列子字段:

  • secretName: 前述步骤创建的 S3 配置信息的 Secret 名称。
  • uri: 模型在 S3 中的存储标识。
  • containerPath: 模型在容器中的存储路径。

示例如下:

spec:
  storage:
    s3:
      secretName: s3-secret
      uri: s3://models/mnist/
      containerPath: /var/lib/t9k/model

PVC

通过配置 spec.storage.pvc 字段可以使用存储在 PVC 中的模型数据。spec.storage.pvc 字段包含下列子字段:

  • name: 存储模型数据的 PVC 的名称。
  • subPath: 模型在 PVC 中的路径,不可以是绝对路径(即开头不能是 /)。
  • containerPath: 模型在容器中的存储路径。

示例如下:

spec:
  storage:
    pvc:
      name: demo
      subPath: path/mnist
      containerPath: /var/lib/custom

服务状态

SimpleMLService 的状态记录在 status 字段中。

status.address 字段记录了推理服务在集群内的访问地址,子字段如下:

  • url: 推理服务在集群内的访问地址
  • ports: 推理服务可供访问的服务端口

status.conditions 字段表明了当前 SimpleMLService 的状态,包括下列 2 种类型:

  • ModelDownloaded: 模型是否成功地被下载到本地。
  • Ready: 推理服务是否就绪。

在下面的示例中:

  • 访问推理服务的地址是 sample.demo.svc.cluster.local
  • 模型已经下载到容器本地
  • 推理服务处于就绪状态
status:
  address:
    url: sample.demo.svc.cluster.local
    ports:
    - port: 80
      protocol: TCP
  conditions:
  - lastTransitionTime: "2023-12-27T06:52:39Z"
    status: "True"
    type: ModelDownloaded
  - lastTransitionTime: "2023-12-27T06:52:41Z"
    message: Deployment has minimum availability.
    reason: MinimumReplicasAvailable
    status: "True"
    type: Ready

下一步

MLService

MLService 用于在 TensorStack AI 平台上部署 AI 推理服务,其功能全面,可用于生产环境。

概述

MLService 是推理服务的核心 API,由 releasestransformer 两部分构成:

  • spec.releases 定义一个或多个 releases,以提供多版本模型推理服务的支持。
  • 可选的 transformer 定义前处理(pre-processing)和后处理(post-processing)计算。
mlservice-architecture
图 1: MLService 的组成。一个 MLService 由一个或多个模型服务版本(releases) 及前后处理模块(transformer,非必需)构成;不同的 release 和 transformer 可独立进行规模伸缩。

MLService 的主要特性包括:

  • 支持定义多个版本(release)的推理服务,每个 release 包含一个 predictor,其定义了:
    • 模型存储(storage
    • 模型规约(model),包括 modelUriparametersruntime(引用 MLServiceRuntime 定义运行推理服务 Pod 的模版)
    • 计算资源(resources
    • 其他部署参数(minReplicas, maxRelicas, logger ...
  • 每个 release 服务的容量可独立自动伸缩,可通过 minReplicasmaxReplicas 设置容量的上下限。
  • 支持金丝雀(canary release)发布模式。
  • 用户可定制 transformer 组件,以在调用推理服务时进行前处理(pre-processing),以及获得推理结果后进行后处理(post-processing)。
  • transformer 的容量也可独立自动伸缩,可通过 minReplicasmaxReplicas 设置容量的上下限。

示例

下面是一个基本的 MLService 示例:

apiVersion: tensorstack.dev/v1beta1
kind: MLService
metadata:
  name: torch-mnist
spec:
  default: version1
  releases:
    - name: version1
      predictor:
        minReplicas: 1
        maxReplicas: 3
        model:
          parameters:
            "MODEL_PATH": "mnist=model.mar"
          runtime: torchserve
          modelUri: pvc://tutorial/tutorial-examples/deployment/pvc/mlservice-torch/

MLServiceRuntime

示例中,我们使用了 MLServiceRuntime torchserve。 MLServiceRuntime 定义了推理服务的模版,包含了推理服务的关键信息,例如镜像、启动命令、资源需求等,能够方便地帮助用户快速部署多种模型推理服务程序。

一个 MLServiceRuntime 可以被多个 MLService 使用。

定义

一个基本的 MLServiceRuntime 的示例:

apiVersion: tensorstack.dev/v1beta1
kind: MLServiceRuntime
metadata:
  name: torchserve
spec:
  enabled: true
  template:
    spec:
      containers:
      - name: user-container
        image: torchserve:0.9.0-cpu
        args:
          - torchserve
          - --start
          - --model-store=/var/lib/t9k/model
          - --models {{if .MODEL_PATH}}{{.MODEL_PATH}}{{else}}all{{end}}
        resources:
          limits:
            cpu: "200m"
            memory: 200Mi
        ports:
        - containerPort: 8080
          protocol: TCP

该 MLServiceRuntime 在 spec.template 中定义了推理服务的副本(Pod)的模版,以指定容器镜像 torchserve:0.9.0-cpu、启动命令 torchserve 及其他命令行参数等。

使用

用户可以在 MLService 的 predictor 定义中指定要使用的 MLServiceRuntime 名称,例如:

apiVersion: tensorstack.dev/v1beta1
kind: MLService
metadata:
  name: demo
spec:
  default: version1
  releases:
  - name: version1
    predictor:
      model:
        runtime: torchserve
        modelUri: "<your-model-registry/your-model-path>"

用户在 release version1.predictor.model.runtime 中指定了 torchserve,系统在创建推理服务器副本(Pod)时,将会使用名称为 torchserve 的 MLServiceRuntime。

进一步的配置

除了直接使用 MLServiceRuntime 定义好的 Pod 模版,MLService 还支持对其进行进一步的配置和修改。

Parameters

MLService 支持在 predictor.model.parameters 设置参数,该字段是一个 map 类型,key 为参数名,value 为参数值。

在之前的 MLServiceRuntime 示例 中包含了 --models {{if .MODEL_PATH}}{{.MODEL_PATH}}{{else}}all{{end}} 的内容。这里使用了 golang template 的语法,含义为:

  • 如果使用此 MLServiceRuntime 的 MLService 指定了 MODEL_PATH,这一行会被设置为 --model <用户指定的 MODEL_PATH>
  • 如果没有指定 MODEL_PATH,这一行会被设置为 --model all

如下所示,在 MLService 中设置 MODEL_PATH

apiVersion: tensorstack.dev/v1beta1
kind: MLService
metadata:
  name: demo
spec:
  default: version1
  releases:
  - name: version1
    predictor:
      model:
        parameters:
          "MODEL_PATH": "mnist=model.mar"
        runtime: torchserve
        modelUri: "<your-model-registry/your-model-path>"

由上述 MLService 最终产生的副本(Pod)的 args 中会包含 --model mnist=model.mar,指定了使用模型的名称和文件。

StrategicMergePatch

MLServiceRuntime 定义了 Pod 模版,但不一定能适用于所有场景。MLService 支持用户在 MLServiceRuntime 的基础上,进行进一步的叠加修改,例如:

apiVersion: tensorstack.dev/v1beta1
kind: MLService
metadata:
  name: demo
spec:
  default: version1
  releases:
  - name: version1
    predictor:
      model:
        parameters:
          "MODEL_PATH": "mnist=model.mar"
        runtime: torchserve
        modelUri: "<your-model-registry/your-model-path>"
      template:
        spec:
          containers:
            - name: user-container
              image: self-torchserve:latest

将上面 MLService 中 predictor version1template.spec 和之前的 Runtime 定义示例 相比, 可以发现他们都定义了一个名为 user-container 的 container,但是 image 不同。 于是最终生成的 Pod 中,MLService 中定义的 image 会覆盖 MLServiceRuntime 中的 image,但是 MLServiceRuntime 中 args 等其余设置都会被保留。

上述的 StrategicMergePatch 给用户提供了完整的个性化改动方案。除此以外,针对改动频率更高的资源要求(resources),MLService 提供了更方便的个性化改动方案。用户可以直接通过 Predictor 中的 resources 覆盖 Runtime 的资源要求,例如:

apiVersion: tensorstack.dev/v1beta1
kind: MLService
metadata:
  name: demo
spec:
  default: version1
  releases:
  - name: version1
    predictor:
      model:
        modelFormat:
          name: pytorch
        modelUri: "<your-model-registry/your-model-path>"
      resources:
        limits:
          cpu: 500m
          memory: 1Gi

模型存储

MLService 支持 S3 和 PVC 两种存储模型的方式,用户需要根据模型存储的类型填写 MLService 的配置。

PVC

在MLService中使用 PVC 存储模式需要在 spec.releases[*].predictor.model.modelUri 中设置包含前缀 pvc:// 的模型路径。

例如,下面的示例指定模型存储在 PVC tutorialmodels/example/ 路径下:

...
  releases:
    - name: test1
      predictor:
        model:
          modelUri: "pvc://tutorial/models/example"
...

S3

S3 是一种对象存储服务和协议,具有良好的可扩展性、数据可用性和安全性等优点,其协议被多种商业和开源产品支持,并且被广泛部署。

可在 MLService 中通过 spec.releases[*].predictor.model.modelUrispec.releases[*].predictor.storage.s3Storage.secretName 设定 S3 的配置参数,其中:

  • modelUri 必需包含前缀 s3://
  • secretName 指向的Secret 存储的 S3 配置格式应当是 s3cmd 配置文件格式。

例如,下面的示例指定模型在 S3 中的存储 Uri 前缀为 s3://models/example/,S3 的配置信息存储在 Secret s3-model 中:

...
  releases:
    - name: test1
      predictor:
        model:
          modelUri: "s3://models/example/"
        storage:
          s3Storage:
            secretName: s3-model
...

更多配置

发布策略

多版本支持

一个 MLService 可以同时部署多个版本(release)的推理服务,以使用不同的模型文件,或者其他配置等。

在下面的示例中,MLService 同时部署了 nov-02(设置为默认)、nov-05nov-11 三个版本的服务,这三个版本都使用同一个 MLServiceRuntime,但是使用的模型不同(不同的 modelUri):

apiVersion: tensorstack.dev/v1beta1
kind: MLService
metadata:
  name: multi-releases
spec:
  default: nov-02
  releases:
    - name: nov-02
      predictor:
        model:
          runtime: torchserve
          modelUri: pvc://tutorial/model-11-02
    - name: nov-05
      predictor:
        model:
          runtime: torchserve
          modelUri: pvc://tutorial/model-11-05
    - name: nov-11
      predictor:
        model:
          runtime: torchserve
          modelUri: pvc://tutorial/model-11-11

金丝雀发布

MLService 支持金丝雀(canary release)发布策略。用户可以通过 spec.canary 字段设置金丝雀发布对应的模型版本(release),spec.canaryTrafficPercent 字段设置金丝雀发布的路由权重。spec.default 是必需字段,用于设置默认发布。

例如上一节中我们部署了 3 个版本的模型,我们想主要(80% 流量)使用 nov-02 这个版本,并且将刚刚训练好的 nov-11 作为金丝雀版本:

  • 默认发布:nov-02,路由权重为 80%。
  • 金丝雀发布:nov-11,路由权重为 20%。
...
spec:
  default: nov-02
  canary: nov-11
  canaryTrafficPercent: 20
...

日志收集

MLService 支持对预测请求进行日志收集,详情见2.2.2.1日志收集

前处理及后处理

MLService 支持部署含有 transformer 模块的前处理(pre-processing)及后处理(post-processing)的推理服务:

  • 预处理:用户发向推理服务的原始数据,先经过 transformer 预处理,然后再被发送到推理服务。
  • 后处理:推理服务返回的预测结果,先经过 transformer 后处理,然后再返回给用户。

用户可以使用 Tensorstack SDK 编写 transformer 代码,制作镜像,并基于该镜像创建含有 transformer 的推理服务。详细示例请参阅制作并部署含有 Transformer 的模型推理服务

下文展示了一个使用 transformer 的推理服务:

apiVersion: tensorstack.dev/v1beta1
kind: MLService
metadata:
  name: pic-mnist
spec:
  default: origin
  transformer:
    minReplicas: 1
    minReplicas: 5
    template:
      spec:
        containers:
        - name: user-container
          image: t9kpublic/transformer-example:0.1.0
          resources:
            limits:
              cpu: "500m"
              memory: 500Mi

容量伸缩

MLService 支持自动伸缩服务容量:即根据服务负载的变化,自动调节推理服务的部署规模(副本数量)。具体原理可以查看 Knative Autoscaling

用户可以通过设置 spec.releases[*].predictor.minReplicas 字段和 spec.releases[*].predictor.maxReplicas 字段来指定 Predictor 工作负载数量的下限和上限。

同样的,如果用户启用了 Transformer,可以通过 spec.transformer.minReplicas 字段和 spec.transformer.maxReplicas 字段来指定 Transformer 工作负载数量的下限和上限。

以下是一些特殊情况:

  • minReplicas 不填时,工作负载数量的默认最小值为 1。
  • minReplicas 等于 0 时,当没有流量请求时,MLService 会缩容到 0,不再占用系统资源。
  • maxReplicas 不填或设为 0 时,工作负载数量没有上限。

除了负载数量的限制,用户还可以在具体的 Runtime 或者组件(Predictor 或者 Transformer)的 Pod 定义中设置 Knative Autoscaling 相关的 Annotation,例如:

...
spec:
  releases:
    - name: version1
      minReplicas: 1
      maxReplicas: 3
      predictor:
        template:
          metadata:
            annotations: 
              autoscaling.knative.dev/metric: "rps"
              autoscaling.knative.dev/target: "100"
...

在上面的示例中,我们设置了工作负载数量的范围为 [1,3],自动伸缩指标(metric)为 rps,自动伸缩目标(target)为 100。这意味着当每个工作负载每秒处理的请求数量(requests-per-second)达到 100 时,负载会开始扩容,且扩容最大数量为 3,最小数量为 1。

调度器

MLService 支持使用两种调度器:Kubernetes 默认调度器(默认)和 T9k Scheduler。MLService 通过 spec.scheduler 字段设置调度器:

  • 不设置 spec.scheduler 字段,则默认使用 Kubernetes 默认调度器。
  • 设置 spec.scheduler.t9kScheduler 字段,则使用 T9k Scheduler 调度器。

在下面的示例中,使用了 T9k Scheduler 调度器,且工作负载处于队列 default 中。

...
spec:
  scheduler:
    t9kScheduler:
      queue: default
...

服务状态

通过 MLService 的状态字段可以获取如下信息:

  • 推理服务的全局状态及服务地址:status.ready 表明推理服务是否准备就绪,status.address.url 表明全局推理服务地址。
  • 每个部署的模型的状态及服务地址:status.releases[*].ready 表明该版本推理服务是否准备就绪,status.releases[*].url 表明该版本的推理服务地址。
  • Transformer 的状态及服务地址:status.ready 表明 Transformer 服务是否准备就绪,status.transformer.url 表明 Transformer 服务地址。
  • 推理服务没有就绪的原因:status.conditions 以及 status.releases[*].message 等字段中会记录相关报错信息。

多版本支持的示例的状态为例,其 MLService 状态字段如下。从状态字段可以看出,该推理服务处于就绪状态,外部访问地址为 http://multi-releases.<project>.<domain>,某个 release 的访问地址为 http://multi-releases-predict-<release>.<project>.<domain>

status:
  address:
    url: http://multi-releases.<project>.<domain>
  canaryRelease: nov-02
  conditions:
  - lastTransitionTime: "2023-11-27T10:44:27Z"
    status: "False"
    type: Paused
  - lastTransitionTime: "2023-11-27T10:50:04Z"
    status: "True"
    type: Ready
  defaultRelease: nov-05
  releases:
  - name: nov-02
    ready: true
    readyReplicas: 1
    totalReplicas: 1
    trafficPercent: 80
    url: http://multi-releases-predict-nov-02.<project>.<domain>
  - name: nov-05
    ready: true
    readyReplicas: 1
    totalReplicas: 1
    trafficPercent: 20
    url: http://multi-releases-predict-nov-05.<project>.<domain>
  - name: nov-11
    ready: true
    readyReplicas: 1
    totalReplicas: 1
    trafficPercent: 0
    url: http://multi-releases-predict-nov-11.<project>.<domain>

如果推理服务没有就绪,你可以通过查看 status.conditions 中 type 为 Ready 的 reason 以及 message 来查看具体信息,同时 Event 中也会有相关的错误信息。

访问推理服务

MLService 部署成功后,通过状态字段 status.address.url 可以查询到全局推理服务的 Base URL,再加上部署模型对应的路径即可得到访问推理服务的地址。

示例中的服务为例,推理服务地址的状态字段如下:

...
status:
  address:
    url: http://torch-mnist.<project>.<domain>
...

由于服务使用的是 TorchServe 框架,按照其 API 规范,用户可以通过下述命令查看服务状态:

$ curl http://torch-mnist.<project-name>.<domain-name>/v1/models/mnist
{
    "model_version_status": <model-status>
}

并调用推理服务:

# 数据在 https://github.com/t9k/tutorial-examples/blob/v20240206/deployment/pvc/mlservice-torch/test_data/0.png
$ curl -T test_data/0.png http://torch-mnist.<project-name>.<domain-name>/v1/models/mnist:predict
{
    "predictions": <predict-result>
}

下一步

参考

日志收集

MLService 支持对 predictor 和 transformer 服务进行日志收集,包括接收到的 request 和返回的 response 消息。开启日志收集后,系统会为 MLService 添加日志发送能力,其根据配置的接收 URL,将日志发送到 URL 指定的服务。

设置 MLService

用户可以为每个 predictor 和 transformer 设置日志收集功能:

  1. predictor: MLService 的 spec.releases[*].predictor.logger 字段来启用 predictor 的日志收集功能。
  2. transformer:通过设置 MLService 的 spec.transformer.logger 字段启用 transformer 的日志收集功能。

用户可以通过日志收集的下列字段,来设置日志收集配置:

  • urls:url 数组,系统会将收集到的日志发送到 url 对应的服务。
  • mode:表示对哪些内容进行收集记录。可选值是 all, response, request,默认值是 all。
    • all:requests 和 response 都会被收集记录。
    • response:只记录收集 response。
    • request:只记录收集 requests。

接收日志

日志数据通过 HTTP 协议被发送(HTTP POST)到用户提供的 URL。

日志数据格式是 CloudEvent,如下例所示:

Context Attributes,
  specversion: 1.0
  type: tensorstack.dev.mlservice.response
  source: torch-mnist-logger-predict-origin
  id: 0009174a-24a8-4603-b098-09c8799950e9
  time: 2021-04-10T00:23:26.080736102Z
  datacontenttype: application/json
Extensions,
  component: predict
  inferenceurl: /v1/models/mnist
  mlservicename: torch-mnist-logger
  namespace: example
  traceparent: 00-6d69e2d3917689ee301610780af06de8-be01c3cfdf8e446e-00
Data,
{
  "0": 1.0,
  "2": 1.3369853835154544e-10,
  "6": 7.10219507987428e-14,
  "5": 5.859705488843112e-14,
  "9": 3.2580891499658536e-15
}

在上述示例中:

  • type:表明当前 CloudEvent 数据记录 response 内容。
  • source:release 名称是 origin(source 命名规则是 <mlservice-name>-<component>-<release-name>
  • component:组件是 predict
  • inferenceurl:URL path 是 /v1/models/mnist
  • mlservicename:MLService 的名称是 torch-mnist-logger
  • namespace:MLService 所在的 namespace 是 example
  • Data:MLService 向用户返回的 response 内容是 {“0”: 1.0,“2”: 1.3369…}

在 HTTP Request 中:

  1. CloudEvent 的 Data 内容存在 Request Body 中
  2. CloudEvent 的其他内容存在 Request Header 中

可使用 CloudEvent 库来实现接收日志数据的 HTTP Server,具体实现可参考 CloudEvent Sample

示例

部署日志接收服务

我们在集群内部署 event-display 服务来接受日志,注意:

  1. event-display 仅简单地将接收到的 CloudEvents 打印出来;
  2. event-display 作为演示的目的。
event-display.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
 name: event-display
spec:
 replicas: 1
 selector:
   matchLabels:
     app: event-display
 template:
   metadata:
     labels:
       app: event-display
   spec:
     containers:
       - name: event-display
         image: t9kpublic/knative_event_display:1.0.0
         resources:
           limits:
             cpu: 100m
             memory: 100Mi
---
kind: Service
apiVersion: v1
metadata:
 name: event-display
spec:
 selector:
   app: event-display
 ports:
 - protocol: TCP
   port: 80
   targetPort: 8080

部署命令

kubectl create -f event-display.yaml

部署 MLService

请按照使用方法准备环境,基于部署用于生产环境的模型推理服务示例来部署 MLService logger-example。

首先将 mlservice.yaml 修改为下列内容,注意:

  1. event-display 和 MLService 需要部署在同一个 namespace/project 中。
  2. 这个 MLService 仅对 predictor 设置了 logger 服务。
mlservice.yaml
apiVersion: tensorstack.dev/v1beta1
kind: MLService
metadata:
 name: logger-example
spec:
 default: origin
 releases:
   - name: origin
     predictor:
       logger:
         mode: all
         resources:
           limits:
             cpu: "1"
             memory: 2Gi
           requests:
             cpu: "0.5"
             memory: 1Gi
         urls:
         - http://event-display
       minReplicas: 1
       model:
         parameters:
           "MODEL_PATH": "mnist=model.mar"
         runtime: t9k-torchserve
         modelUri: pvc://tutorial/tutorial-examples/deployment/mlservice/torch-pvc/
       containersResources:
       - name: user-container
         resources:
           limits:
             cpu: "500m"
             memory: 1Gi

然后按照 README 文档的操作步骤进行操作。

查看日志

查看 event-display 容器的日志,可看到日志中打印的 CloudEvent 记录了预测请求的详细信息:

terminal.log
$ k get pod -l app=event-display
NAME                             READY   STATUS    RESTARTS   AGE
event-display-7d8d9f97db-lpgg2   1/1     Running   0          14m


$ k logs event-display-7d8d9f97db-lpgg2 
Context Attributes,
  specversion: 1.0
  type: tensorstack.dev.mlservice.request
  source: logger-example-predict-origin
  id: ff726d6b-7fd8-471e-9ddc-de03b201d882
  time: 2024-02-29T08:07:00.849119273Z
Extensions,
  component: predict
  inferenceurl: /v1/models/mnist:predict
  mlservicename: logger-example
  namespace: demo
Data,
  PNG
IHDWfHIDATxc`X`ˬUvo>C0$ůشi˿_{ ZATI̶_Q%̓*y_:=U9;4ɺpJ^{oG8NIx$!K.w;@@4^0
                                                                                                                                     G$Qp֛q?{4g^B
                                                                                                                                                                      <`Rr330
ztB?IENDB`
☁️  cloudevents.Event
Context Attributes,
  specversion: 1.0
  type: tensorstack.dev.mlservice.response
  source: logger-example-predict-origin
  id: ff726d6b-7fd8-471e-9ddc-de03b201d882
  time: 2024-02-29T08:07:01.468872477Z
Extensions,
  component: predict
  inferenceurl: /v1/models/mnist:predict
  mlservicename: logger-example
  namespace: demo
Data,
  {
  "0": 1.0,
  "2": 1.3369905182969433e-10,
  "6": 7.102208632401436e-14,
  "5": 5.859716330864836e-14,
  "9": 3.2580891499658536e-15
}

参考

模型存储

Job

TensorStack 定义了一系列 CRD(称为 Job)以支持批处理(Batch Processing)计算任务,特别是 AI 领域的大规模分布式并行训练类型性质的计算。

t9k-job
图 1:Job 系统的基本原理。用户提交 Job 的定义;Job Controller 1)分析 Job 定义;2)请求计算资源(CPU、RAM、GPU、高速网络、存储...);3)启动、监控、暂停、继续 、终止、调试 Job。

Job 类型

为了支持不同框架的计算任务,TensorStack 提供了一系列 Job:

  • TrainingJob:一类使用分布式计算框架进行机器学习的 T9k Job。
  • MPIJob:MPIJob 使用户能够方便地在集群环境中使用 OpenMPI 进行并行计算。
  • BeamJob:用于在集群中通过 Apache Beam Python SDK 运行分布式计算任务,并支持多种底层计算引擎(例如 Apache Spark, Apache Flink)。
  • GenericJob:一个通用的 T9k Job 资源,支持各种并行计算场景及 T9k 高级调度策略。
    • GenericJob 十分灵活,用户可以使用 GenericJob 实现 MPIJob、PyTorchTrainingJob 等特定功能的 T9k Job;但其自动化程度低,需要手工设置很多参数。
    • GenericJob 的目的是提供一个总是可行的 “通用” 机制,以支持一些其他特定功能 T9k Jobs 还未支持的新的计算场景。

运行模式

T9k Job 支持多种运行模式(spec.runMode):

  • 立即(Immediate)模式:默认、基本模式。Job 被分配资源后,将会立即开始运行。
  • 调试(Debug)模式:帮助用户创建 Job 环境,但不立即执行,用户可以在训练环境中手动启动 Job 或者运行调试代码。
  • 暂停(Pause)模式:暂停执行 Job;在一些场合下(如集群资源不足),用户可随时暂停 Job,待条件允许再继续执行 Job。
  • 弹性(Elastic)伸缩模式:可以动态调整 Job 规模。

以下是各类型 Job 支持的模式列表:

Job 类型立即模式调试模式暂停模式弹性伸缩模式
GenricJob***
PyTorchTrainingJob****
TensorFlowTrainingJob***
XGBoostTrainingJob***
MPIJob***
ColossalAIJob***
DeepSpeedJob****
BeamJob*

各种模式的具体使用方式,请参考对应 Job 类型的文档。

GenericJob

GenericJob 是最基本的 T9k Job 资源,支持使用 T9k 高级调度策略。GenericJob 的使用十分灵活,一个熟练的使用者可以通过 GenericJob 实现 MPIJob、PyTorchTrainingJob 等特定功能的 T9k Job。

创建 GenericJob

下面是一个基本的 GenericJob 配置示例:

apiVersion: batch.tensorstack.dev/v1beta1
kind: GenericJob
metadata:
  name: generic-example
spec:
  successRules:
    - { "worker": [0] }
  failureRules:
    - { "worker": [0] }
    - { "worker": [1] }
  replicaSpecs:
    - type: worker
      replicas: 4
      template:
        spec:
          containers:
            - command:
                - sleep
                - '365'
              image: nginx:latest
              name: sleep

在该例中:

  • 创建 4 个副本(由 spec.replicaSpecs[0].replicas 字段指定),这些副本的角色为 worker(由 spec.replicaSpecs[0].type 字段指定)。每个副本执行命令 sleep 365(由 spec.replicaSpecs[0].template 字段指定)。
  • GenericJob 的成功条件为序号为 0 且角色为 worker 的副本执行完成(由 spec.successRules 字段指定)。
  • GenericJob 的失败条件有两个,任意一个条件达成都会导致 GenericJob 失败(由 spec.failureRules 字段指定):
    • 序号为 0 且角色为 worker 的副本执行失败。
    • 序号为 1 且角色为 worker 的副本执行失败。

成功和失败

GenericJob 的成功和失败条件是通过 spec.successRulesspec.failureRules 字段指定的,其规则如下:

  • spec.successRules 数组包含 GenericJob 的所有成功条件,其中:
    • 任意一个条件达成则 GenericJob 成功。
    • 每个条件是一个由若干副本组成的集合,如果这些副本都执行完成,则该条件达成。
  • spec.failureRules 数组包含 GenericJob 的所有失败条件,其中
    • 任意一个条件达成则 GenericJob 失败。
    • 每个条件是一个由若干副本组成的集合,如果这些副本都失败或者重启次数耗尽,则该条件达成。

在下面的示例中,记录了 3 种 GenericJob 成功的判定条件:

  • 角色为 master 且序号为 0 的副本执行完成。
  • 角色为 worker 且序号为 0、1、2 的三个副本全部执行完成。
  • 角色为 master 且序号为 2 和角色为 worker 且序号为 0、1 的三个副本全部执行完成。

和 1 种 GenericJob 失败的判定:

  • 角色为 master 且序号为 0 的副本执行失败。
...
spec:
  successRules:
  - {"master": [0]}
  - {"worker": [0, 1, 2]}
  - {"master": [2], "worker": [0, 1]}
  failureRules:
  - {"master": [0]}

暴露副本的服务

在分布式计算中,有时需要不同的副本之间进行通信和数据交换。使用者可以通过设置 spec.service 字段来暴露副本的端口。

在下面的示例中,GenericJob 暴露出每一个副本的服务:端口为 2222,域名的格式为 [job-name]-[type]-[rank],例如下例中角色为 worker 且序号为 0 的副本的域名为 generic-example-worker-0

apiVersion: batch.tensorstack.dev/v1beta1
kind: GenericJob
metadata:
  name: generic-example
spec:
  service:
    ports:
      - name: http
        port: 2222
  replicaSpecs:
    - type: worker
      replicas: 1
...

变量替换

在副本的配置信息中有时需要传入副本自身或其他副本的信息,包括序号、角色和副本的服务地址等。GenericJob 通过变量替换的方式提供这些信息,主要有以下 5 种变量:

  • $(type):当前副本的角色。
  • $(rank):当前副本在同类副本中的序号。
  • $(replicas[_type_]):扮演此角色的副本的数量。
  • $(service._type_[_rank_].host):各个副本的域名(当且仅当副本的服务被暴露出来,此变量可用)。
  • $(service.port[_port-name_])spec.service.ports 字段中定义的服务端口号(当且仅当副本的服务被暴露出来,此变量可用)。

上述变量中 _type__rank__port-name_ 需填入具体的角色序号端口名称(由 spec.service.ports[*].name 字段指定)。

变量替换可以被使用在下列字段中:

  • spec.replicaSpecs[*].template.command
  • spec.replicaSpecs[*].template.args
  • spec.replicaSpecs[*].template.env

以下是用 GenericJob 实现的 TensorFlow 分布式框架使用示例,其中 TF_CONFIG 环境变量需要填写所有副本的地址和当前副本的序号等信息,我们使用变量替换的方式添加:

apiVersion: batch.tensorstack.dev/v1beta1
kind: GenericJob
metadata:
  name: generic-example
spec:
  replicaSpecs:
    - type: worker
      replicas: 4
      template:
        spec:
          containers:
            - command:
                - python
                - /mnt/training.py
              image: tensorflow/tensorflow:2.11.0
              name: tensorflow
              env:
                - name: TF_CONFIG
                  value: '{"task":{"type":"$(type)","index":$(rank)},"cluster":{"worker":["$(service.worker[0].host):$(service.port[http])","$(service.worker[1].host):$(service.port[http])","$(service.worker[2].host):$(service.port[http])","$(service.worker[3].host):$(service.port[http])"]}}'

重启机制

GenericJob 为副本提供以下重启机制:

  1. Never:不重启
  2. OnFailure:错误即重启
  3. Always:总是重启(谨慎使用此策略,此策略可能导致 GenericJob 无法停止)

GenericJob 重启机制通过 spec.replicaSpecs[*].restartPolicy 字段指定:

  • spec.replicaSpecs[*].restartPolicy.policy 表示当前副本所使用的重启策略,可以设置为 NeverOnFailureAlways
  • spec.replicaSpecs[*].restartPolicy.limit 表示当前副本的最大重启次数。

不同的角色可以使用不同的重启策略,比如 master 使用 Alwaysworker 使用 OnFailure

清除策略

在 GenericJob 成功或失败后,控制器清理所创建的 Kubernetes 资源,使 GenericJob 不再浪费集群资源(内存、CPU 等)。GenericJob 提供三种策略,通过 spec.cleanUpPolicy 字段指定:

  • All:清除全部副本
  • None:不清除副本
  • Unfinished:清除未结束(处于 PendingRunningUnknown 阶段)的副本
`None` 策略主要用于训练脚本调试阶段。如果需要从副本中读取训练日志,则可以选用此策略。但由于这些副本可能占用资源并影响后续训练,建议你在调试完毕后手动删除这些副本或删除整个 GenericJob。

调度器

目前 GenericJob 支持两种调度器:

  1. Kubernetes 的默认调度器
  2. T9k Scheduler 调度器

调度器通过 spec.scheduler 字段设置:

  • 不设置 spec.scheduler 字段,则默认使用 Kubernetes 的默认调度器。
  • 设置 spec.scheduler.t9kScheduler 字段,则使用 T9k Scheduler 调度器。

在下面的示例中,GenericJob 启用 T9k Scheduler 调度器,将副本插入 default 队列中等待调度,其优先级为 50。

...
spec:
  scheduler:
    t9kScheduler:
      queue: default
      priority: 50

调试模式

GenericJob 支持调试模式。在该模式下,训练环境会被部署好,但不会启动训练,用户可以连入副本测试环境或脚本。

该模式可以通过 spec.runMode.debug 字段来设置:

  • spec.runMode.debug.enabled 表示是否启用调试模式。
  • spec.runMode.debug.replicaSpecs 表示如何配置各个副本的调试模式:
    • spec.runMode.debug.replicaSpecs.type 表示作用于的副本类型。
    • spec.runMode.debug.replicaSpecs.skipInitContainer 表示让副本的 InitContainer 失效,默认为 false
    • spec.runMode.debug.replicaSpecs.command 表示副本在等待调试的时候执行的命令,默认为 sleep inf
    • 如果不填写 spec.runMode.debug.replicaSpecs 字段,则表示所有副本都使用默认设置。

在下面的示例中:

  • 示例一:开启了调试模式,并配置 worker 跳过 InitContainer,并执行 /usr/bin/sshd
  • 示例二:开启了调试模式,副本使用默认调试设置,即不跳过 InitContainer,并执行 sleep inf
# 示例一
...
spec:
  runMode:
    debug:
      enabled: true
      replicaSpecs:
        - type: worker
          skipInitContainer: true
          command: ["/usr/bin/sshd"]

---
# 示例二
...
spec:
  runMode:
    debug:
      enabled: true

暂停模式

GenericJob 支持暂停模式。在该模式下,删除(或不创建)副本,停止训练。

该模式可以通过 spec.runMode.pause 字段来设置:

  • spec.runMode.pause.enabled 表示是否启用暂停模式。
  • spec.runMode.pause.resumeSpecs 表示结束暂停后,如何恢复各个副本:
    • spec.runMode.pause.resumeSpecs.type 表示作用于的副本类型。
    • spec.runMode.pause.resumeSpecs.skipInitContainer 表示让副本的 InitContainer 失效,默认为 false
    • spec.runMode.pause.resumeSpecs.commandspec.runMode.pause.resumeSpecs.args 表示副本在恢复运行时候执行的命令,默认使用 spec.replicaSpecs[0].template 中的命令。
    • 如果不填写 spec.runMode.pause.resumeSpecs 字段,则表示所有副本都使用默认设置。

用户可以随时修改 spec.runMode.pause.enabled 来控制任务暂停,但是不可以更改 spec.runMode.pause.resumeSpecs,所以如果有暂停 GenericJob 的需求,请提前设置好恢复设置。

在下面的示例中:

  • 示例一:开启了暂停模式,并配置 worker 跳过 InitContainer,并执行 /usr/bin/sshd
  • 示例二:开启了暂停模式,副本使用默认恢复设置,即不跳过 InitContainer,并执行 spec.replicaSpecs[0].template 中设置的命令。
# 示例一
...
spec:
  runMode:
    pause:
      enabled: true
      resumeSpecs:
        - type: worker
          skipInitContainer: true
          command: ["/usr/bin/sshd"]

---
# 示例二
...
spec:
  runMode:
    pause:
      enabled: true

GenericJob 状态

GenericJob 的状态和阶段

status.conditions 字段用于描述当前 GenericJob 的状态,包括以下 6 种类型:

  1. Initialized:GenericJob 已经成功创建各子资源,完成初始化。
  2. Running:开始执行任务。
  3. ReplicaFailure:有一个或多个副本出现错误。
  4. Completed:GenericJob 成功。
  5. Failed:GenericJob 失败。
  6. Paused:GenericJob 进入暂停模式,所有副本都已删除或正在删除。

status.phase 字段用于描述当前 GenericJob 所处的阶段,GenericJob 的整个生命周期主要有以下7个阶段:

  1. Pending:GenericJob 刚刚创建,等待副本启动。
  2. Running:副本创建成功,开始执行任务。
  3. Paused:GenericJob 进入暂停模式。
  4. Resuming:GenericJob 正从暂停模式中恢复运行。恢复运行后,切换为 Running 阶段。
  5. Succeeded:GenericJob 成功。
  6. Failed:GenericJob 失败。
  7. Unknown:控制器无法获得 GenericJob 的阶段。

在下面的示例中,GenericJob 所有子资源创建成功,所以类型为 Initalizedcondition 被设为 True;GenericJob 运行结束,所以类型为 Completedcondition 被设置为 True;但是 GenericJob 的训练结果是失败的,所以类型为 Failedcondition 被设置为 True(原因是 The job is failed with rule: { "worker": [0] })。当前 GenericJob 运行阶段为 Failed

...
status:
  conditions:
    - lastTransitionTime: "2021-01-18T02:36:09Z"
      status: "True"
      message: "The job has been initialized successfully."
      reason: "-"
      type: Initializing
    - lastTransitionTime: "2021-01-18T02:36:09Z"
      status: "True"
      message: "All pods are running normally."
      reason: "-"
      type: Running
    - lastTransitionTime: "2021-01-18T02:36:09Z"
      status: "False"
      message: "All pods are running normally."
      reason: "-"
      type: ReplicaFailure
    - lastTransitionTime: "2021-01-18T02:36:31Z"
      status: "False"
      message: 'The job is failed with rule: { "worker": [0] }'
      reason: "Failed"
      type: Completed
    - lastTransitionTime: "2021-01-18T02:36:31Z"
      status: "True"
      message: 'The job is failed with rule: { "worker": [0] }'
      reason: "Failed"
      type: Failed
  phase: Failed

副本的状态

status.tasks 字段用来记录副本的状态,记录的内容主要包括:

  • 副本的重启次数(同一种角色的副本的重启次数之和);
  • 副本当前的运行阶段,此处的“运行阶段”在 K8s Pod 的 5 个阶段的基础上,添加了 CreatingDeleted 分别表示正在创建和已删除;
  • 副本在集群中对应的 Pod 的索引信息。

在下面的示例中,GenericJob 创建了 2 个角色为 worker 的副本,这 2 个副本的重启次数之和为 3,当前均处于 Running 阶段,分别运行在 generic-example-worker-0generic-example-worker-1 这 2 个 Pod 上。

...
status:
  tasks:
  - type: worker
    restartCount: 3
    status:
    - phase: Running
      name: generic-example-worker-0
      uid: e3ec2ee3-6645-4e21-993f-1e472b94e0ae
      containers: []
    - phase: Running
      name: generic-example-worker-1
      uid: 908a93f0-7b8b-491e-85d5-3da0abcb4ca4
      containers: []

副本状态统计

status.aggregate 字段统计了各个阶段的副本数量。

在下面示例中,GenericJob 创建了 3 个副本,其中 1 个处于 Pending 阶段,另外两个处于 Running 阶段。

...
status:
  aggregate:
    creating: 0
    deleted: 0
    failed: 0
    pending: 1
    running: 2
    succeeded: 0
    unknown: 0
...

PyTorchTrainingJob

PyTorchTrainingJob 是服务于 PyTorch 分布式训练框架的 T9k Job。

你可以较为方便地使用 PyTorchTrainingJob 为 PyTorch 训练脚本提供训练环境,并监控训练进程。

创建 PyTorchTrainingJob

下面是一个基本的 PyTorchTrainingJob 配置示例:

apiVersion: batch.tensorstack.dev/v1beta1
kind: PyTorchTrainingJob
metadata:
  name: pytorch-example
spec:
  replicaSpecs:
  - replicas: 4
    restartPolicy: OnFailure
    template:
      spec:
        containers:
        - command:
          - python
          - dist_mnist.py
          image: pytorch/pytorch:2.0.0-cuda11.7-cudnn8-devel
          name: pytorch
    type: worker

在该例中:

  • 创建 4 个副本(由 spec.replicaSpecs[*].replicas 字段指定),副本的角色为 worker(由 spec.replicaSpecs[*].type 字段指定)。
  • 每个副本使用 pytorch/pytorch:2.0.0-cuda11.7-cudnn8-devel 镜像,执行命令 python dist_mnist.py(由 template 字段指定,此处的填写方式参考 PodTemplate)。
  • 当副本失败后,会自动重启(由 spec.replicaSpecs[*].restartPolicy 字段指定)。

使用 torchrun 启动训练

前面的示例中所使用的训练方法比较原始,即直接用 python 启动训练脚本,执行训练。

PyTorch 在后续提供了 torch.distributed.launch 包和 torchrun 工具来更好地启动和管理训练,具体优点包括:支持一机多进程高容错弹性伸缩训练规模等。PyTorchTrainingJob 也支持使用 torchrun 启动训练来继承这些优点。

spec:
  torchrunConfig:
    enabled: true
    maxRestarts: 10
    procPerNode: "1"
    rdzvBackend: c10d
    extraOptions: []

在 PyTorchTrainingJob 的定义中加入上述片段,来使用 torchrun 启动训练,其中:

  • enabled:是否启用 torchrun
  • maxRestarts:训练进程的最多重启次数。
  • procPerNode:一个副本中启动多少个训练进程。除了可以指定一个数字字符串之外,还可以设置为 gpu,表示启动等同于副本所使用的 GPU 数量的训练进程。
  • rdzvBackendtorchrun 所使用的汇合通信方式,可以设置为 c10detcdetcd-v2,但是只有 c10dtorch 内置的。如果用户希望使用 etcd 需要自行搭建 etcd 服务器。
  • extraOptionstorchrun 的其他参数,上面的参数是 torchrun 比较常用的设置,用户也可以通过 extraOptions 字段提供更多 torchrun 的其他设置。

弹性训练

使用 torchrun 启动的 PyTorchTrainingJob 支持弹性伸缩训练规模,通过 spec.elastic 设置伸缩范围和当前期望训练规模。

在下面的示例中,PyTorchTrainingJob 启用弹性训练功能,训练规模的伸缩范围是 [4,10],当前期望训练规模为 7。

spec:
  elastic:
    enabled: true
    minReplicas: 4
    maxReplicas: 10
    expectedReplicas: 7

注:期望训练规模(spec.elastic.expectedReplicas)并不代表实际训练规模,当集群资源数量不足时,控制器可能无法创建足够的副本。

最佳实践

...
spec:
  torchrunConfig:
    enabled: false
    minNodes: 1
    maxRestarts: 10
    procPerNode: "1"
    rdzvBackend: c10d
    extraOptions: []
  replicaSpecs:
  - replicas: 4
    restartPolicy: OnFailure
    template:
      spec:
        containers:
        - command:
          - python
          args:
          - dist_mnist.py
          image: pytorch/pytorch:2.0.0-cuda11.7-cudnn8-devel
          name: pytorch
    type: worker
...

在上面的示例中:spec.replicaSpecs[*].template.spec.containers[0].command 只填写 python,其他参数填写在 spec.replicaSpecs[*].template.spec.containers[0].args 中。这样可以实现以下效果:

  • spec.torchrunConfig.enabled 设置为 false 时,控制器会为训练副本设置正确的环境变量,并通过 python dist_mnist.py 命令启动训练脚本。
  • spec.torchrunConfig.enabled 设置为 true 时,控制器会忽略 python 命令,而是改用 torchrun 命令,其格式为:torchrun <torchrun_args> dist_mnist.py

这样做的优点就是,在切换 torchrun 模式时,不需要对其他字段进行改动。

另外,如果用户使用 Python Module 作为训练脚本,可以参考以下配置:

...
spec:
  torchrunConfig:
    enabled: false
    ...
  replicaSpecs:
  - replicas: 4
    restartPolicy: OnFailure
    template:
      spec:
        containers:
        - command:
          - python
          args:
          - -m
          - training.module
          image: pytorch/pytorch:2.0.0-cuda11.7-cudnn8-devel
          name: pytorch
    type: worker
...

在上面的示例中,当 spec.torchrunConfig.enabled 设置为 true 时,-m 参数同样可以被 torchrun 使用。

成功和失败

在 PyTorch 分布式训练框架中,需要设置 MASTER_ADDRMASTER_PORT,PyTorchTrainingJob 会将第一个训练副本作为 master(主节点)。当分布式训练的主节点成功结束,PyTorch 分布式训练成功;反之,当分布式训练的主节点执行失败,PyTorch 分布式训练失败。

但是 master 的失败有时可能是因为环境因素导致的,比如集群网络断连、集群节点崩溃等等,此类原因导致的失败应该被允许自动恢复。针对这一情况,PyTorchTrainingJob 支持副本重启(请参阅重启机制),并设定了重启次数限制(由 spec.runPolicy.backoffLimit 字段指定),当副本重启次数达到上限后,如果主节点再次失败,则训练失败。此外,PyTorchTrainingJob 可以设置最长执行时间(由 spec.runPolicy.activeDeadlineSeconds 字段指定),当超过这个执行时间后,训练失败。

如果 PyTorchTrainingJob 在没有超过重启次数和没有超过最长执行时间的情况下成功完成了主节点的运行,则训练成功。

重启机制

PyTorchTrainingJob 的 spec.replicaSpec[*].template 字段使用 PodTemplate 的规范填写,但是 Pod 的重启策略并不能满足 PyTorchTrainingJob 的需求,所以 PyTorchTrainingJob 会给副本的重启策略都设置为 Never,并由控制器根据 spec.replicaSpec[*].restartPolicy 字段处理副本的重启。

可选的重启策略有以下四种:

  • Never:不重启
  • OnFailure:失败后重启
  • Always:总是重启
  • ExitCode:特殊退出码重启

使用 Never 重启策略时,Job 的副本失败后不会重启。如果需要调试代码错误,可以选择此策略,便于从副本中读取训练日志。

ExitCode 是一种比较特殊的重启策略,它将失败进程的返回值分为两类:一类是由于系统环境原因或用户操作导致的错误,此类错误可以通过重启解决;另一类是代码错误或者其他不可自动恢复的错误。可重启的退出码包括:

  • 130(128+2):使用 Control+C 终止容器运行。
  • 137(128+9):容器接收到 SIGKILL 信号。
  • 143(128+15):容器接收到 SIGTERM 信号。
  • 138:用户可以自定义这个返回值的含义。如果用户希望程序在某处退出并重启,可以在代码中写入这个返回值。

重启次数限制

如果因为某种原因(例如代码错误或者环境错误并且长时间没有修复),PyTorchTrainingJob 不断地失败重启却无法解决问题,这会导致集群资源的浪费。用户可以通过设置 spec.runPolicy.backoffLimit 字段(默认为 3)来设置副本的最大重启次数。重启次数为所有副本共享,即所有副本重启次数累计达到此数值后,副本将不能再次重启。

清除策略

在训练结束后,可能有些副本仍处于运行状态。这些运行的副本仍然会占用集群资源,PyTorchTrainingJob 提供清除策略,在训练结束后删除这些副本。

PyTorchTrainingJob 提供以下三种策略:

  • None:不删除副本。
  • All:删除所有副本。
  • Unfinished:只删除未结束的副本。
`None` 策略主要用于训练脚本调试阶段。如果需要从副本中读取训练日志,则可以选用此策略。但由于这些副本可能占用资源并影响后续训练,建议用户在调试完毕后手动删除这些副本或删除整个 PyTorchTrainingJob。

调度器

目前 PyTorchTrainingJob 支持使用以下两种调度器:

  1. Kubernetes 的默认调度器
  2. T9k Scheduler 调度器

调度器通过 spec.scheduler 字段设置:

  • 不设置 spec.scheduler 字段,则默认使用 Kubernetes 的默认调度器。
  • 设置 spec.scheduler.t9kScheduler 字段,则使用 T9k Scheduler 调度器。

在下面的示例中,PyTorchTrainingJob 启用 T9k Scheduler 调度器,将副本插入 default 队列中等待调度,其优先级为 50。

...
spec:
  scheduler:
    t9kScheduler:
      queue: default
      priority: 50

TensorBoard 的使用

PyTorchTrainingJob 支持使用 TensorBoard 对训练过程和结果进行实时可视化(由 spec.tensorboardSpec 字段设置)。

在下面的示例中,PyTorchTrainingJob 使用 t9kpublic/tensorflow-2.11.0:cpu-sdk-0.5.2 镜像创建一个 TensorBoard,可视化名为 torch-tensorboard-pvc 的 PVC 中 /log 路径下的模型数据。

...
spec:
  tensorboardSpec:
    image: t9kpublic/tensorflow-2.11.0:cpu-sdk-0.5.2
    trainingLogFilesets:
    - t9k://pvc/torch-tensorboard-pvc/log

调试模式

PyTorchTrainingJob 支持调试模式。在该模式下,训练环境会被部署好,但不会启动训练,用户可以连入副本测试环境或脚本。

该模式可以通过 spec.runMode.debug 字段来设置:

  • spec.runMode.debug.enabled 表示是否启用调试模式。
  • spec.runMode.debug.replicaSpecs 表示如何配置各个副本的调试模式:
    • spec.runMode.debug.replicaSpecs.type 表示作用于的副本类型。
    • spec.runMode.debug.replicaSpecs.skipInitContainer 表示让副本的 InitContainer 失效,默认为 false
    • spec.runMode.debug.replicaSpecs.command 表示副本在等待调试的时候执行的命令,默认为 sleep inf
    • 如果不填写 spec.runMode.debug.replicaSpecs 字段,则表示所有副本都使用默认设置。

在下面的示例中:

  • 示例一:开启了调试模式,并配置 worker 跳过 InitContainer,并执行 /usr/bin/sshd
  • 示例二:开启了调试模式,副本使用默认调试设置,即不跳过 InitContainer,并执行 sleep inf
# 示例一
...
spec:
  runMode:
    debug:
      enabled: true
      replicaSpecs:
        - type: worker
          skipInitContainer: true
          command: ["/usr/bin/sshd"]

---
# 示例二
...
spec:
  runMode:
    debug:
      enabled: true

暂停模式

PyTorchTrainingJob 支持暂停模式。在该模式下,删除(或不创建)副本,停止训练。

该模式可以通过 spec.runMode.pause 字段来设置:

  • spec.runMode.pause.enabled 表示是否启用暂停模式。
  • spec.runMode.pause.resumeSpecs 表示结束暂停后,如何恢复各个副本:
    • spec.runMode.pause.resumeSpecs.type 表示作用于的副本类型。
    • spec.runMode.pause.resumeSpecs.skipInitContainer 表示让副本的 InitContainer 失效,默认为 false
    • spec.runMode.pause.resumeSpecs.commandspec.runMode.pause.resumeSpecs.args 表示副本在恢复运行时候执行的命令,默认使用 spec.replicaSpecs[0].template 中的命令。
    • 如果不填写 spec.runMode.pause.resumeSpecs 字段,则表示所有副本都使用默认设置。

用户可以随时修改 spec.runMode.pause.enabled 来控制任务暂停,但是不可以更改 spec.runMode.pause.resumeSpecs,所以如果有暂停 PyTorchTrainingJob 的需求,请提前设置好恢复设置。

在下面的示例中:

  • 示例一:开启了暂停模式,并配置 worker 跳过 InitContainer,并执行 /usr/bin/sshd
  • 示例二:开启了暂停模式,副本使用默认恢复设置,即不跳过 InitContainer,并执行 spec.replicaSpecs[0].template 中设置的命令。
# 示例一
...
spec:
  runMode:
    pause:
      enabled: true
      resumeSpecs:
        - type: worker
          skipInitContainer: true
          command: ["/usr/bin/sshd"]

---
# 示例二
...
spec:
  runMode:
    pause:
      enabled: true

PyTorchTrainingJob 状态

PyTorchTrainingJob 的状态和阶段

status.conditions 字段用于描述当前 PyTorchTrainingJob 的状态,包括以下 6 种类型:

  1. Initialized:PyTorchTrainingJob 已经成功创建各子资源,完成初始化。
  2. Running:开始执行任务。
  3. ReplicaFailure:有一个或多个副本出现错误。
  4. Completed:PyTorchTrainingJob 成功。
  5. Failed:PyTorchTrainingJob 失败。
  6. Paused:PyTorchTrainingJob 进入暂停模式,所有副本都已删除或正在删除。

status.phase 字段用于描述当前 PyTorchTrainingJob 所处的阶段,PyTorchTrainingJob 的整个生命周期主要有以下7个阶段:

  1. Pending:PyTorchTrainingJob 刚刚创建,等待副本启动。
  2. Running:副本创建成功,开始执行任务。
  3. Paused:PyTorchTrainingJob 进入暂停模式。
  4. Resuming:PyTorchTrainingJob 正从暂停模式中恢复运行。恢复运行后,切换为 Running 阶段。
  5. Succeeded:PyTorchTrainingJob 成功。
  6. Failed:PyTorchTrainingJob 失败。
  7. Unknown:控制器无法获得 PyTorchTrainingJob 的阶段。

在下面的示例中,PyTorchTrainingJob 所有子资源创建成功,所以类型为 Initalizedcondition 被设为 True;PyTorchTrainingJob 运行结束,所以类型为 Completedcondition 被设置为 True;PyTorchTrainingJob 的训练成功结束,所以类型为 Completedcondition 被设置为 True(原因是 The job has finished successfully.)。当前 PyTorchTrainingJob 运行阶段为 Succeeded

...
status:
  conditions:
    - lastTransitionTime: "2023-12-19T02:40:25Z"
      message: The job has been initialized successfully.
      reason: '-'
      status: "True"
      type: Initialized
    - lastTransitionTime: "2023-12-19T02:53:14Z"
      message: The job has finished successfully.
      reason: Succeeded
      status: "False"
      type: Running
    - lastTransitionTime: "2023-12-19T02:53:14Z"
      message: The job has finished successfully.
      reason: Succeeded
      status: "False"
      type: Failed
    - lastTransitionTime: "2023-12-19T02:53:14Z"
      message: The job has finished successfully.
      reason: Succeeded
      status: "True"
      type: Completed
    - lastTransitionTime: "2023-12-19T02:40:25Z"
      message: All pods are running normally.
      reason: '-'
      status: "False"
      type: ReplicaFailure
  phase: Succeeded

副本的状态

status.tasks 字段用来记录副本的状态,记录的内容主要包括:

  • 副本的重启次数(同一种角色的副本的重启次数之和);
  • 副本当前的运行阶段,此处的“运行阶段”在 K8s Pod 的 5 个阶段的基础上,添加了 CreatingDeleted 分别表示正在创建和已删除;
  • 副本在集群中对应的 Pod 的索引信息。

在下面的示例中,PyTorchTrainingJob 创建了 1 个角色为 worker 的副本,当前均处于 Succeeded 阶段,运行在 torch-mnist-trainingjob-5b373-worker-0 这个 Pod 上。

...
status:
  tasks:
  - replicas:
    - containers:
      - exitCode: 0
        name: pytorch
        state: Terminated
      name: torch-mnist-trainingjob-5b373-worker-0
      phase: Succeeded
      uid: d39f91d6-9c48-4c57-bb71-4131226395b6
    type: worker

副本状态统计

status.aggregate 字段统计了各个阶段的副本数量。

在下面示例中,PyTorchTrainingJob 创建了 3 个副本,其中 1 个处于 Pending 阶段,另外两个处于 Running 阶段。

...
status:
  aggregate:
    creating: 0
    deleted: 0
    failed: 0
    pending: 1
    running: 2
    succeeded: 0
    unknown: 0
...

TensorBoard 状态

status.tensorboard 字段用来记录 TensorBoard 的状态。

在下面的示例中,PyTorchTrainingJob 创建了名为 torch-mnist-trainingjob-5b373 的 TensorBoard,TensorBoard 目前运行正常。

status:
  tensorboard:
    action: NOP
    dependent:
      apiVersion: tensorstack.dev/v1beta1
      kind: TensorBoard
      name: torch-mnist-trainingjob-5b373
      namespace: demo
      uid: b09378f3-2164-4f14-a425-a1340fa32d7d
    note: TensorBoard [torch-mnist-trainingjob-5b373] is ready
    ready: true
    reason: DependentReady
    type: Normal

下一步

TensorFlowTrainingJob

TensorFlowTrainingJob 是服务于 TensorFlow 分布式训练框架的 T9k Job。

你可以较为方便地使用 TensorFlowTrainingJob 为 TensorFlow 训练脚本提供训练环境,并监控训练进程。

创建 TensorFlowTrainingJob

下面是一个基本的 TensorFlowTrainingJob 配置示例:

apiVersion: batch.tensorstack.dev/v1beta1
kind: TensorFlowTrainingJob
metadata:
  name: tensorflow-example
spec:
  replicaSpecs:
  - replicas: 4
    restartPolicy: OnFailure
    template:
      spec:
        containers:
        - command:
          - python
          - dist_mnist.py
          image: tensorflow/tensorflow:2.11.0
          name: tensorflow
          resources:
            limits:
              cpu: 1
              memory: 2Gi
            requests:
              cpu: 500m
              memory: 1Gi
    type: worker

在该例中:

  • 创建 4 个副本(由 spec.replicaSpecs[*].replicas 字段指定),副本的角色为 worker(由 spec.replicaSpecs[*].type 字段指定)。
  • 每个副本使用 tensorflow/tensorflow:2.11.0 镜像,执行命令 python dist_mnist.py(由 spec.replicaSpecs<a target="_blank" rel="noopener noreferrer" href="https://kubernetes.io/docs/concepts/workloads/pods/#pod-templates">*].template 字段指定,此处的填写方式参考 [PodTemplate)。
  • 当副本失败后,会自动重启(由 spec.replicaSpecs[*].restartPolicy 字段指定)。

副本的角色

在 TensorFlow 分布式训练框架中,副本有 4 种类型:Chief、Worker、PS 和 Evaluator。

在 TensorFlowTrainingJob 中,副本的类型由 spec.replicaSpecs[*].type 字段指定,分别是 chiefworkerpsevaluator

成功和失败

在 TensorFlow 分布式训练框架中,Chief 是主节点。如果没有指定 Chief,则会选择第一个 Worker 作为主节点。当分布式训练的主节点执行完成时,TensorFlow 分布式训练成功;反之,当分布式训练的主节点执行失败时,TensorFlow 分布式训练失败。

在 TensorFlowTrainingJob 中,如果没有 Chief 副本,则选取序号为 0 的 Worker 节点作为主节点。主节点的失败有时可能是因为环境因素导致的,比如集群网络断连、集群节点崩溃等等,此类原因导致的失败应该被允许自动恢复。针对这一情况,TensorFlowTrainingJob 允许副本重启(请参阅重启机制),并设定了重启次数限制(由 spec.runPolicy.backoffLimit 字段指定),当副本重启次数达到上限后,如果主节点再次失败,则 TensorFlowTrainingJob 失败。此外,TensorFlowTrainingJob 可以设置最长执行时间(由 spec.runPolicy.activeDeadlineSeconds 字段指定),当超过这个执行时间后,TensorFlowTrainingJob 失败。

如果 TensorFlowTrainingJob 在没有超过重启次数和没有超过最长执行时间的情况下成功完成了主节点的运行,则 TensorFlowTrainingJob 成功。

重启机制

TensorFlowTrainingJob 的 spec.replicaSpec[*].template 字段使用 PodTemplate 的规范填写,但是 Pod 的重启策略并不能完全满足 TensorFlowTrainingJob 的需求,所以 TensorFlowTrainingJob 使用 spec.replicaSpec[*].restartPolicy 字段覆盖 spec.replicaSpec[*].template 中指定的重启策略。

可选的重启策略有以下四种:

  • Never:不重启
  • OnFailure:失败后重启
  • Always:总是重启
  • ExitCode:特殊退出码重启

使用 Never 重启策略时,Job 的副本失败后不会重启。如果需要调试代码错误,可以选择此策略,便于从副本中读取训练日志。

ExitCode 是一种比较特殊的重启策略,它将失败进程的返回值分为两类:一类是由于系统环境原因或用户操作导致的错误,此类错误可以通过重启解决;另一类是代码错误或者其他不可自动恢复的错误。可重启的退出码包括:

  • 130(128+2):使用 Control+C 终止容器运行。
  • 137(128+9):容器接收到 SIGKILL 信号。
  • 143(128+15):容器接收到 SIGTERM 信号。
  • 138:用户可以自定义这个返回值的含义。如果用户希望程序在某处退出并重启,可以在代码中写入这个返回值。

重启次数限制

如果因为某种原因(例如代码错误或者环境错误并且长时间没有修复),TensorFlowTrainingJob 不断地失败重启却无法解决问题,这会导致集群资源的浪费。用户可以通过设置 spec.runPolicy.backoffLimit 字段来设置副本的最大重启次数。重启次数为所有副本共享,即所有副本重启次数累计达到此数值后,副本将不能再次重启。

清除策略

在训练结束后,可能有些副本仍处于运行状态,比如 TensorFlow 训练框架中的 PS 经常在训练完成后仍然保持运行。这些运行的副本仍然会占用集群资源,TensorFlowTrainingJob 提供清除策略,在训练结束后删除这些副本。

TensorFlowTrainingJob 提供以下三种策略:

  • None:不删除副本。
  • All:删除所有副本。
  • Unfinished:只删除未结束的副本。
`None` 策略主要用于训练脚本调试阶段。如果需要从副本中读取训练日志,则可以选用此策略。但由于这些副本可能占用资源并影响后续训练,建议你在调试完毕后手动删除这些副本或删除整个 TensorFlowTrainingJob。

调度器

目前 TensorFlowTrainingJob 支持使用以下两种调度器:

  1. Kubernetes 的默认调度器
  2. T9k Scheduler 调度器

调度器通过 spec.scheduler 字段设置:

  • 不设置 spec.scheduler 字段,则默认使用 Kubernetes 的默认调度器。
  • 设置 spec.scheduler.t9kScheduler 字段,则使用 T9k Scheduler 调度器。

在下面的示例中,TensorFlowTrainingJob 启用 T9k Scheduler 调度器,将副本插入 default 队列中等待调度,其优先级为 50。

...
spec:
  scheduler:
    t9kScheduler:
      queue: default
      priority: 50

TensorBoard 的使用

TensorFlowTrainingJob 支持使用 TensorBoard 对训练过程和结果进行实时可视化(由 spec.tensorboardSpec 字段设置)。

在下面的示例中,TensorFlowTrainingJob 使用 t9kpublic/tensorflow-2.11.0:cpu-sdk-0.5.2 镜像创建一个 TensorBoard,可视化名为 tensorflow-tensorboard-pvc 的 PVC 中 /log 路径下的模型数据。

...
spec:
  tensorboardSpec:
    image: t9kpublic/tensorflow-2.11.0:cpu-sdk-0.5.2
    trainingLogFilesets:
    - t9k://pvc/tensorflow-tensorboard-pvc/log
...

调试模式

TensorFlowTrainingJob 支持调试模式。在该模式下,训练环境会被部署好,但不会启动训练,用户可以连入副本测试环境或脚本。

该模式可以通过 spec.runMode.debug 字段来设置:

  • spec.runMode.debug.enabled 表示是否启用调试模式。
  • spec.runMode.debug.replicaSpecs 表示如何配置各个副本的调试模式:
    • spec.runMode.debug.replicaSpecs.type 表示作用于的副本类型。
    • spec.runMode.debug.replicaSpecs.skipInitContainer 表示让副本的 InitContainer 失效,默认为 false
    • spec.runMode.debug.replicaSpecs.command 表示副本在等待调试的时候执行的命令,默认为 sleep inf
    • 如果不填写 spec.runMode.debug.replicaSpecs 字段,则表示所有副本都使用默认设置。

在下面的示例中:

  • 示例一:开启了调试模式,并配置 worker 跳过 InitContainer,并执行 /usr/bin/sshd
  • 示例二:开启了调试模式,副本使用默认调试设置,即不跳过 InitContainer,并执行 sleep inf
# 示例一
...
spec:
  runMode:
    debug:
      enabled: true
      replicaSpecs:
        - type: worker
          skipInitContainer: true
          command: ["/usr/bin/sshd"]

---
# 示例二
...
spec:
  runMode:
    debug:
      enabled: true

暂停模式

TensorFlowTrainingJob 支持暂停模式。在该模式下,删除(或不创建)副本,停止训练。

该模式可以通过 spec.runMode.pause 字段来设置:

  • spec.runMode.pause.enabled 表示是否启用暂停模式。
  • spec.runMode.pause.resumeSpecs 表示结束暂停后,如何恢复各个副本:
    • spec.runMode.pause.resumeSpecs.type 表示作用于的副本类型。
    • spec.runMode.pause.resumeSpecs.skipInitContainer 表示让副本的 InitContainer 失效,默认为 false
    • spec.runMode.pause.resumeSpecs.commandspec.runMode.pause.resumeSpecs.args 表示副本在恢复运行时候执行的命令,默认使用 spec.replicaSpecs[0].template 中的命令。
    • 如果不填写 spec.runMode.pause.resumeSpecs 字段,则表示所有副本都使用默认设置。

用户可以随时修改 spec.runMode.pause.enabled 来控制任务暂停,但是不可以更改 spec.runMode.pause.resumeSpecs,所以如果有暂停 TensorFlowTrainingJob 的需求,请提前设置好恢复设置。

在下面的示例中:

  • 示例一:开启了暂停模式,并配置 worker 跳过 InitContainer,并执行 /usr/bin/sshd
  • 示例二:开启了暂停模式,副本使用默认恢复设置,即不跳过 InitContainer,并执行 spec.replicaSpecs[0].template 中设置的命令。
# 示例一
...
spec:
  runMode:
    pause:
      enabled: true
      resumeSpecs:
        - type: worker
          skipInitContainer: true
          command: ["/usr/bin/sshd"]

---
# 示例二
...
spec:
  runMode:
    pause:
      enabled: true

TensorFlowTrainingJob 状态

TensorFlowTrainingJob 的状态和阶段

status.conditions 字段用于描述当前 TensorFlowTrainingJob 的状态,包括以下 6 种类型:

  1. Initialized:TensorFlowTrainingJob 已经成功创建各子资源,完成初始化。
  2. Running:开始执行任务。
  3. ReplicaFailure:有一个或多个副本出现错误。
  4. Completed:TensorFlowTrainingJob 成功。
  5. Failed:TensorFlowTrainingJob 失败。
  6. Paused:TensorFlowTrainingJob 进入暂停模式,所有副本都已删除或正在删除。

status.phase 字段用于描述当前 TensorFlowTrainingJob 所处的阶段,TensorFlowTrainingJob 的整个生命周期主要有以下7个阶段:

  1. Pending:TensorFlowTrainingJob 刚刚创建,等待副本启动。
  2. Running:副本创建成功,开始执行任务。
  3. Paused:TensorFlowTrainingJob 进入暂停模式。
  4. Resuming:TensorFlowTrainingJob 正从暂停模式中恢复运行。恢复运行后,切换为 Running 阶段。
  5. Succeeded:TensorFlowTrainingJob 成功。
  6. Failed:TensorFlowTrainingJob 失败。
  7. Unknown:控制器无法获得 TensorFlowTrainingJob 的阶段。

在下面的示例中,TensorFlowTrainingJob 所有子资源创建成功,所以类型为 Initalizedcondition 被设为 True;TensorFlowTrainingJob 运行结束,所以类型为 Completedcondition 被设置为 True;TensorFlowTrainingJob 的训练成功结束,所以类型为 Completedcondition 被设置为 True(原因是 The job has finished successfully.)。当前 TensorFlowTrainingJob 运行阶段为 Succeeded

...
status:
  conditions:
    - lastTransitionTime: "2023-12-19T02:40:25Z"
      message: The job has been initialized successfully.
      reason: '-'
      status: "True"
      type: Initialized
    - lastTransitionTime: "2023-12-19T02:53:14Z"
      message: The job has finished successfully.
      reason: Succeeded
      status: "False"
      type: Running
    - lastTransitionTime: "2023-12-19T02:53:14Z"
      message: The job has finished successfully.
      reason: Succeeded
      status: "False"
      type: Failed
    - lastTransitionTime: "2023-12-19T02:53:14Z"
      message: The job has finished successfully.
      reason: Succeeded
      status: "True"
      type: Completed
    - lastTransitionTime: "2023-12-19T02:40:25Z"
      message: All pods are running normally.
      reason: '-'
      status: "False"
      type: ReplicaFailure
  phase: Succeeded

副本的状态

status.tasks 字段用来记录副本的状态,记录的内容主要包括:

  • 副本的重启次数(同一种角色的副本的重启次数之和);
  • 副本当前的运行阶段,此处的“运行阶段”在 K8s Pod 的 5 个阶段的基础上,添加了 CreatingDeleted 分别表示正在创建和已删除;
  • 副本在集群中对应的 Pod 的索引信息。

在下面的示例中,TensorFlowTrainingJob 创建了 1 个角色为 worker 的副本,当前均处于 Succeeded 阶段,运行在 mnist-trainingjob-5b373-worker-0 这个 Pod 上。

...
status:
  tasks:
  - replicas:
    - containers:
      - exitCode: 0
        name: pytorch
        state: Terminated
      name: mnist-trainingjob-5b373-worker-0
      phase: Succeeded
      uid: d39f91d6-9c48-4c57-bb71-4131226395b6
    type: worker

副本状态统计

status.aggregate 字段统计了各个阶段的副本数量。

在下面示例中,TensorFlowTrainingJob 创建了 3 个副本,其中 1 个处于 Pending 阶段,另外两个处于 Running 阶段。

...
status:
  aggregate:
    creating: 0
    deleted: 0
    failed: 0
    pending: 1
    running: 2
    succeeded: 0
    unknown: 0
...

TensorBoard 状态

status.tensorboard 字段用来记录 TensorBoard 的状态。

在下面的示例中,TensorFlowTrainingJob 创建了名为 mnist-trainingjob-5b373 的 TensorBoard,TensorBoard 目前运行正常。

status:
  tensorboard:
    action: NOP
    dependent:
      apiVersion: tensorstack.dev/v1beta1
      kind: TensorBoard
      name: mnist-trainingjob-5b373
      namespace: demo
      uid: b09378f3-2164-4f14-a425-a1340fa32d7d
    note: TensorBoard [mnist-trainingjob-5b373] is ready
    ready: true
    reason: DependentReady
    type: Normal

下一步

DeepSpeedJob

DeepSpeedJob 是服务于 DeepSpeed 分布式训练框架的 T9k Job。

你可以较为方便地使用 DeepSpeedJob 为 DeepSpeed 训练脚本提供训练环境,并监控训练进程。

创建 DeepSpeedJob

下面是一个基本的 DeepSpeedJob 配置示例:

apiVersion: batch.tensorstack.dev/v1beta1
kind: DeepspeedJob
metadata:
  name: deepspeed-example
spec:
  config:
    slotPerWorker: 1
    run:
      python: /t9k/mnt/train.py
  worker:
    replicas: 4
    template:
      spec:
        restartPolicy: OnFailure
        containers:
        - image: deepspeed/deepspeed:v072_torch112_cu117
          imagePullPolicy: IfNotPresent
          name: worker
          resources:
            limits:
              cpu: 4
              memory: 4Gi
            requests:
              cpu: 2
              memory: 2Gi
          volumeMounts:
          - mountPath: /t9k/mnt
            name: code
        volumes:
        - name: code
          persistentVolumeClaim:
            claimName: deepspeed

在该例中:

  • 创建 4 个训练副本,这些副本会启动 sshd 服务。
  • 第一个副本会启动 deepspeed 程序,该程序会通过 pdsh(或其他方式)访问 4 个副本,并在每个副本上运行 /t9k/mnt/train.py 脚本。

训练配置

DeepSpeedJob 在 spec.config 中配置如何执行训练。有以下参数可以设置:

  • run:如何启动训练,以下三个参数只能填写一个,否则报错:
    • python:使用 Python 脚本进行训练。指定 Python 文件以及启动参数。
    • module:使用 Python module 进行训练。指定 Python module 以及启动参数。
    • exec:使用可执行文件/命令进行训练。指定可执行文件以及启动参数。
  • slotsPerWorker:每一个副本上设置多少个“插槽”。“插槽”是继承自 MPI 中的概念,表示一个副本上可以运行多少个训练进程。一般来说该值被设为每个副本分配的 GPU 数量。例如当创建了一个 replica 为 4 的任务,并且给每个副本分配了 2 个 nvidia.com/gpu,则应该将 slotsPerWorker 设为 2,这样最后一共会运行 4 * 2 = 8 个训练进程。
  • localRank:是否传递 LOCAL_RANK 环境变量,默认为 true
  • autotune:启用超参数调优,可以设置为 noneruntune,默认为 nonenone 为不启动超参数调优;tune 只查找最合适的超参数组合,但是不执行训练;run 查找最合适的超参数组合,并用该超参数执行训练。
  • otherArgs:设置其他 DeepSpeed 参数,详见下文。

otherArgs

DeepSpeedJob 希望提供用户足够的灵活性,所以支持用户通过 otherArgs 字段设置传入 DeepSpeed 的参数。config 中的配置实际上也是通过 DeepSpeed 参数实现的,以下列出除了在配置文件中指定的参数之外的其他可用参数:

  • --launcher: 多节点训练使用的启动器后端,目前的选项包括 PDSH、OpenMPI、MVAPICH、SLURM、MPICH。(默认:pdsh)。目前 DeepSpeedJob 只支持 pdsh
  • --no_ssh_check:多节点训练时不执行 ssh 检查。
  • --save_pid: 在 /tmp/<main-pid>.ds 处保存包含启动器进程 ID(pid),其中 <main-pid> 是第一个调用 DeepSpeed 的进程的 pid。PDSH 模式下不支持。
  • --enable_each_rank_log: 将每个 Rank 的 stdout 和 stderr 重定向到不同的日志文件。PDSH 模式下不支持。
  • --bind_cores_to_rank:将每个 Rank 绑定到主机的不同核心。PDSH 模式下不支持。
  • --bind_core_list:要绑定的核心列表,以逗号分隔。例如 1,3-5,7 => [1,3,4,5,7]。 未指定时,系统上的所有核心都将被绑定。PDSH 模式下不支持。

训练的成功和失败判定

DeepSpeedJob 分布式训练框架中,第一个训练副本(下文记为 worker-0)是分布式任务的主节点。当 worker-0 成功结束,则 DeepSpeedJob 训练成功;反之,当 worker-0 执行失败,DeepSpeedJob 训练失败。

如果一次训练执行时间过长,用户可能需要考虑代码是否需要优化、是否需要分配更多资源等问题。DeepSpeedJob 可以设置最长执行时间(由 spec.runPolicy.activeDeadlineSeconds 字段指定),当超过这个执行时间后,训练失败。

清除策略

在训练完毕后,可能有些副本仍处于运行状态。这些运行的副本仍然会占用集群资源,DeepSpeedJob 提供清除策略,可以在训练结束后删除这些训练副本。

DeepSpeedJob 提供以下三种策略:

  • None:不删除副本。
  • All:删除所有副本。
  • Unfinished:只删除未结束的副本。
`None` 策略主要用于训练脚本调试阶段。如果需要从副本中读取训练日志,则可以选用此策略。但由于这些副本可能占用资源并影响后续训练,建议你在调试完毕后手动删除这些副本或删除整个 DeepSpeedJob。

调度策略

目前 DeepSpeedJob 支持两种调度策略:

  1. Kubernetes 的默认调度器
  2. T9k Scheduler

调度策略通过 CRD 的 spec.scheduler 字段设置:

  • 不设置 spec.scheduler 字段,则默认使用 Kubernetes 的默认调度策略。
  • 设置 spec.scheduler.t9kScheduler 字段,则使用 T9k Scheduler 调度器。

在下面的示例中,MPIJob 启用 T9k Scheduler 调度器,将副本插入 default 队列中等待调度,其优先级为 50。

...
spec:
  scheduler:
    t9kScheduler:
      queue: default
      priority: 50

调试模式

DeepSpeedJob 支持调试模式。在该模式下,训练环境会被部署好,但不会启动训练,用户可以连入副本测试环境或脚本。

该模式可以通过 spec.runMode.debug 字段来设置:

  • spec.runMode.debug.enabled 表示是否启用调试模式。
  • spec.runMode.debug.replicaSpecs 表示如何配置各个副本的调试模式:
    • spec.runMode.debug.replicaSpecs.type 表示作用于的副本类型。
    • spec.runMode.debug.replicaSpecs.skipInitContainer 表示让副本的 InitContainer 失效,默认为 false
    • spec.runMode.debug.replicaSpecs.command 表示副本在等待调试的时候执行的命令,默认为 /usr/sbin/sshd -D
    • 如果不填写 spec.runMode.debug.replicaSpecs 字段,则表示所有副本都使用默认设置。

在下面的示例中:

  • 示例一:开启了调试模式,并配置 worker 跳过 InitContainer,并执行 sleep inf
  • 示例二:开启了调试模式,副本使用默认调试设置,即不跳过 InitContainer,并执行 /usr/sbin/sshd -D
# 示例一
...
spec:
  runMode:
    debug:
      enabled: true
      replicaSpecs:
        - type: worker
          skipInitContainer: true
          command: ["sleep", "inf"]

---
# 示例二
...
spec:
  runMode:
    debug:
      enabled: true

暂停模式

DeepSpeedJob 支持暂停模式。在该模式下,删除(或不创建)副本,停止训练。

该模式可以通过 spec.runMode.pause 字段来设置:

  • spec.runMode.pause.enabled 表示是否启用暂停模式。
  • spec.runMode.pause.resumeSpecs 表示结束暂停后,如何恢复各个副本:
    • spec.runMode.pause.resumeSpecs.type 表示作用于的副本类型。
    • spec.runMode.pause.resumeSpecs.skipInitContainer 表示让副本的 InitContainer 失效,默认为 false
    • spec.runMode.pause.resumeSpecs.commandspec.runMode.pause.resumeSpecs.args 表示副本在恢复运行时候执行的命令,默认使用 spec.replicaSpecs[0].template 中的命令。
    • 如果不填写 spec.runMode.pause.resumeSpecs 字段,则表示所有副本都使用默认设置。

用户可以随时修改 spec.runMode.pause.enabled 来控制任务暂停,但是不可以更改 spec.runMode.pause.resumeSpecs,所以如果有暂停 DeepSpeedJob 的需求,请提前设置好恢复设置。

在下面的示例中:

  • 示例一:开启了暂停模式,并配置 worker 跳过 InitContainer,并执行 /usr/bin/sshd
  • 示例二:开启了暂停模式,副本使用默认恢复设置,即不跳过 InitContainer,并执行 spec.replicaSpecs[0].template 中设置的命令。
# 示例一
...
spec:
  runMode:
    pause:
      enabled: true
      resumeSpecs:
        - type: worker
          skipInitContainer: true
          command: ["/usr/bin/sshd"]

---
# 示例二
...
spec:
  runMode:
    pause:
      enabled: true

DeepSpeedJob 状态

DeepSpeedJob 的状态和阶段

status.conditions 字段用于描述当前 DeepSpeedJob 的状态,包括以下 5 种类型:

  1. Initialized:DeepSpeedJob 已经成功创建各子资源,完成初始化。
  2. Running:开始执行任务。
  3. ReplicaFailure:有一个或多个副本出现错误。
  4. Completed:DeepSpeedJob 成功。
  5. Failed:DeepSpeedJob 失败。

status.phase 字段用于描述当前 DeepSpeedJob 所处的阶段,DeepSpeedJob 的整个生命周期主要有以下几个阶段:

  1. Pending:DeepSpeedJob 刚刚创建,等待副本启动。
  2. Running:副本创建成功,开始执行任务。
  3. Succeeded:DeepSpeedJob 成功。
  4. Failed:DeepSpeedJob 失败。
  5. Unknown:控制器无法获得 DeepSpeedJob 的阶段。

在下面的示例中,DeepSpeedJob 所有子资源创建成功,所以类型为 Initalizedcondition 被设为 True;DeepSpeedJob 运行结束,所以类型为 Completedcondition 被设置为 True;但是 DeepSpeedJob 的训练结果是失败的,所以类型为 Failedcondition 被设置为 True。当前 DeepSpeedJob 运行阶段为 Failed

...
status:
  conditions:
    - lastTransitionTime: "2021-01-18T02:36:09Z"
      status: "True"
      message: "The job has been initialized successfully."
      reason: "-"
      type: Initializing
    - lastTransitionTime: "2021-01-18T02:36:09Z"
      status: "True"
      message: "All pods are running normally."
      reason: "-"
      type: Running
    - lastTransitionTime: "2021-01-18T02:36:09Z"
      status: "False"
      message: "All pods are running normally."
      reason: "-"
      type: ReplicaFailure
    - lastTransitionTime: "2021-01-18T02:36:31Z"
      status: "False"
      message: "The job exited with an error code."
      reason: "Failed"
      type: Completed
    - lastTransitionTime: "2021-01-18T02:36:31Z"
      status: "True"
      message: "The job exited with an error code."
      reason: "Failed"
      type: Failed
  phase: Failed

副本的状态

status.tasks 字段用来记录副本的状态,记录的内容主要包括:

  • 副本的重启次数(同一种角色的副本的重启次数之和)
  • 副本当前的运行阶段
  • 副本在集群中对应的 Pod 的索引信息

在下面的示例中,DeepSpeedJob 创建了 2 个训练副本,当前均处于 Running 阶段,分别运行在 deepspeed-example-worker-0deepspeed-example-worker-1 这 2 个 Pod 上。

...
status:
  tasks:
  - type: worker
    restartCount: 0
    status:
    - phase: Running
      name: deepspeed-example-worker-0
      uid: e3ec2ee3-6645-4e21-993f-1e472b94e0ae
      containers: []
    - phase: Running
      name: deepspeed-example-worker-1
      uid: 908a93f0-7b8b-491e-85d5-3da0abcb4ca4
      containers: []

副本状态统计

status.aggregate 字段统计了各个阶段的副本数量。

在下面的示例中,DeepSpeedJob 创建了 3 个副本,其中 1 个处于 Pending 阶段,另外两个处于 Running 阶段。

...
status:
  aggregate:
    creating: 0
    deleted: 0
    failed: 0
    pending: 1
    running: 2
    succeeded: 0
    unknown: 0
...

ColossalAIJob

ColossalAIJob 是服务于 ColossalAI 分布式训练框架的 T9k Job。

你可以较为方便地使用 ColossalAIJob 为 ColossalAI 训练脚本提供训练环境,并监控训练进程。

创建 ColossalAIJob

下面是一个基本的 ColossalAIJob 配置示例:

apiVersion: batch.tensorstack.dev/v1beta1
kind: ColossalAIJob
metadata:
  name: colossalai-example
spec:
  ssh:
    authMountPath: /root/.ssh
    sshdPath: /usr/sbin/sshd
  launcher:
    image: hpcaitech/colossalai:0.3.0
    workingDir: /workspace
    env: []
    resources: 
      limits:
        cpu: 1
        memory: 2Gi
      requests:
        cpu: 500m
        memory: 1Gi
  worker:
    replicas: 2
    procPerWorker: 1
    command:
      - train.py
      - arg1
    torchArgs: []
    template:
      spec:
        restartPolicy: OnFailure
        containers:
          - image: hpcaitech/colossalai:0.3.0
            imagePullPolicy: IfNotPresent
            name: worker
            resources:
              limits:
                cpu: 2
                memory: 8Gi
                nvidia.com/gpu: 1
              requests:
                cpu: 1
                memory: 4Gi
                nvidia.com/gpu: 1
            volumeMounts:
              - mountPath: /workspace
                name: code
        volumes:
          - name: code
            persistentVolumeClaim:
              claimName: colossalai

在该例中:

  • 创建 1 个启动副本,该启动副本是 ColossalAI 在训练中所必须的,启动副本的配置参考 PodTemplate,这里不再赘述(启动副本的配置由 spec.launcher 字段指定)。
  • 创建 2 个执行副本(由 spec.worker.replicas 字段指定),每个执行副本上启动 1 个训练进程(由 spec.worker.procPerWorker 字段指定),训练脚本和参数为 train.py arg1(由 spec.worker.command 字段指定),执行副本的其他配置参考 PodTemplate,这里不再赘述(这些配置由 spec.worker.template 字段指定)。
  • 执行副本需要执行 sshd 程序,等待启动副本发来训练指令。sshd 的路径为 /user/sbin/sshd(由 spec.ssh.sshdPath 字段指定,使用该字段的原因是 sshd 程序必须使用绝对路径调用,所以需要其具体路径)。

成功和失败

在 ColossalAIJob 分布式训练框架中:

  • 如果启动副本执行失败,ColossalAIJob 训练失败。
  • 如果启动副本执行成功,ColossalAIJob 并不一定成功:启动副本的作用是启动训练和监测,无论是训练成功还是失败,启动副本都会正常结束,而不是报错。因此,如果要确定 ColossalAIJob 是否成功结束,需要检查启动副本的日志。

重启机制

与其他 TrainingJob 不同,ColossalAIJob 使用 colossalairun 作为启动命令,在这种情况下,Pod 失败重启后不会再加入到训练中。所以 ColossalAIJob 无法像其他 TrainingJob 那样支持 Pod 失败重启。

清除策略

在 ColossalAIJob 训练结束后,ColossalAIJob 控制器可以清理所创建的 Kubernetes 资源,使 ColossalAIJob 不再浪费集群资源(内存、CPU 等)。一般来说,你需要查看启动副本的日志来确定训练结果,所以启动副本不在清理范围之内,ColossalAIJob 控制器只清理执行副本(通过 spec.runPolicy.cleanUpWorkers 字段设置)。

在下面的示例中,ColossalAIJob 在训练结束后会自动删除所有执行副本:

...
spec:
  runPolicy:
    cleanUpWorkers: true

调度器

目前 ColossalAIJob 支持两种调度器:

  1. Kubernetes 的默认调度器
  2. T9k Scheduler 调度器

调度器通过 spec.scheduler 字段设置:

  • 不设置 spec.scheduler 字段,则默认使用 Kubernetes 的默认调度器。
  • 设置 spec.scheduler.t9kScheduler 字段,则使用 T9k Scheduler 调度器。

在下面的示例中,ColossalAIJob 启用 T9k Scheduler 调度器,将执行副本插入 default 队列中等待调度,其优先级为 50。

...
spec:
  scheduler:
    t9kScheduler:
      queue: default
      priority: 50

调试模式

ColossalAIJob 支持调试模式。在该模式下,训练环境会被部署好,但不会启动训练,用户可以连入副本测试环境或脚本。

该模式可以通过 spec.runMode.debug 字段来设置:

  • spec.runMode.debug.enabled 表示是否启用调试模式。
  • spec.runMode.debug.replicaSpecs 表示如何配置各个副本的调试模式:
    • spec.runMode.debug.replicaSpecs.type 表示作用于的副本类型。
    • spec.runMode.debug.replicaSpecs.skipInitContainer 表示让副本的 InitContainer 失效,默认为 false
    • spec.runMode.debug.replicaSpecs.command 表示副本在等待调试的时候执行的命令,默认为 sleep inf
    • 如果不填写 spec.runMode.debug.replicaSpecs 字段,则表示所有副本都使用默认设置。

在下面的示例中:

  • 示例一:开启了调试模式,并配置 worker 跳过 InitContainer,并执行 /usr/bin/sshd
  • 示例二:开启了调试模式,副本使用默认调试设置,即不跳过 InitContainer,并执行 sleep inf
# 示例一
...
spec:
  runMode:
    debug:
      enabled: true
      replicaSpecs:
        - type: worker
          skipInitContainer: true
          command: ["/usr/bin/sshd"]

---
# 示例二
...
spec:
  runMode:
    debug:
      enabled: true

暂停模式

ColossalAIJob 支持暂停模式。在该模式下,删除(或不创建)副本,停止训练。

该模式可以通过 spec.runMode.pause 字段来设置:

  • spec.runMode.pause.enabled 表示是否启用暂停模式。
  • spec.runMode.pause.resumeSpecs 表示结束暂停后,如何恢复各个副本:
    • spec.runMode.pause.resumeSpecs.type 表示作用于的副本类型。
    • spec.runMode.pause.resumeSpecs.skipInitContainer 表示让副本的 InitContainer 失效,默认为 false
    • spec.runMode.pause.resumeSpecs.commandspec.runMode.pause.resumeSpecs.args 表示副本在恢复运行时候执行的命令,默认使用 spec.replicaSpecs[0].template 中的命令。
    • 如果不填写 spec.runMode.pause.resumeSpecs 字段,则表示所有副本都使用默认设置。

用户可以随时修改 spec.runMode.pause.enabled 来控制任务暂停,但是不可以更改 spec.runMode.pause.resumeSpecs,所以如果有暂停 ColossalAIJob 的需求,请提前设置好恢复设置。

在下面的示例中:

  • 示例一:开启了暂停模式,并配置 worker 跳过 InitContainer,并执行 /usr/bin/sshd
  • 示例二:开启了暂停模式,副本使用默认恢复设置,即不跳过 InitContainer,并执行 spec.replicaSpecs[0].template 中设置的命令。
# 示例一
...
spec:
  runMode:
    pause:
      enabled: true
      resumeSpecs:
        - type: worker
          skipInitContainer: true
          command: ["/usr/bin/sshd"]

---
# 示例二
...
spec:
  runMode:
    pause:
      enabled: true

ColossalAIJob 状态

ColossalAIJob 的状态和阶段

status.conditions 字段用于描述当前 ColossalAIJob 的状态,包括以下 5 种类型:

  1. Initialized:ColossalAIJob 已经成功创建各子资源,完成初始化。
  2. Running:开始执行任务。
  3. ReplicaFailure:有一个或多个副本出现错误。
  4. Completed:ColossalAIJob 成功。
  5. Failed:ColossalAIJob 失败。
  6. Paused:ColossalAIJob 进入暂停模式,所有副本都已删除或正在删除。

status.phase 字段用于描述当前 ColossalAIJob 所处的阶段,ColossalAIJob 的整个生命周期主要有以下几个阶段:

  1. Pending:ColossalAIJob 刚刚创建,等待副本启动。
  2. Running:副本创建成功,开始执行任务。
  3. Paused:ColossalAIJob 进入暂停模式。
  4. Resuming:ColossalAIJob 正从暂停模式中恢复运行。恢复运行后,切换为 Running 阶段。
  5. Succeeded:ColossalAIJob 成功。
  6. Failed:ColossalAIJob 失败。
  7. Unknown:控制器无法获得 ColossalAIJob 的阶段。

在下面的示例中,ColossalAIJob 所有子资源创建成功,所以类型为 Initalizedcondition 被设为 True;ColossalAIJob 运行结束,所以类型为 Completedcondition 被设置为 True;但是 ColossalAIJob 的训练结果是失败的,所以类型为 Failedcondition 被设置为 True。当前 ColossalAIJob 运行阶段为 Failed

...
status:
  conditions:
    - lastTransitionTime: "2021-01-18T02:36:09Z"
      status: "True"
      message: "The job has been initialized successfully."
      reason: "-"
      type: Initializing
    - lastTransitionTime: "2021-01-18T02:36:09Z"
      status: "True"
      message: "All pods are running normally."
      reason: "-"
      type: Running
    - lastTransitionTime: "2021-01-18T02:36:09Z"
      status: "False"
      message: "All pods are running normally."
      reason: "-"
      type: ReplicaFailure
    - lastTransitionTime: "2021-01-18T02:36:31Z"
      status: "False"
      message: "The job exited with an error code."
      reason: "Failed"
      type: Completed
    - lastTransitionTime: "2021-01-18T02:36:31Z"
      status: "True"
      message: "The job exited with an error code."
      reason: "Failed"
      type: Failed
  phase: Failed

副本的状态

status.tasks 字段用来记录副本的状态,记录的内容主要包括:

  • 副本的重启次数(同一种角色的副本的重启次数之和)
  • 副本当前的运行阶段
  • 副本在集群中对应的 Pod 的索引信息

在下面的示例中,ColossalAIJob 创建了 1 个启动副本和 2 个执行副本。执行副本当前均处于 Running 阶段,分别运行在 colossalai-example-worker-0colossalai-example-worker-1 这 2 个 Pod 上;启动副本当前处于 Running 阶段,运行在 colossalai-example-launcher Pod 上。

...
status:
  tasks:
  - type: launcher
    restartCount: 0
    status:
    - phase: Running
      name: colossalai-example-launcher
      uid: 66634db2-35e7-4641-a4dc-adbd5479734e
      containers: []
  - type: worker
    restartCount: 0
    status:
    - phase: Running
      name: colossalai-example-worker-0
      uid: e3ec2ee3-6645-4e21-993f-1e472b94e0ae
      containers: []
    - phase: Running
      name: colossalai-example-worker-1
      uid: 908a93f0-7b8b-491e-85d5-3da0abcb4ca4
      containers: []

副本状态统计

status.aggregate 字段统计了各个阶段的副本数量。

在下面的示例中,ColossalAIJob 创建了 3 个副本,其中 1 个处于 Pending 阶段,另外两个处于 Running 阶段。

...
status:
  aggregate:
    creating: 0
    deleted: 0
    failed: 0
    pending: 1
    running: 2
    succeeded: 0
    unknown: 0
...

XGBoostTrainingJob

XGBoostTrainingJob 是服务于 XGBoost 分布式计算框架的 T9k Job。

你可以较为方便地使用 XGBoostTrainingJob 为 XGBoost 计算程序提供训练环境,并监控训练进程。

创建 XGBoostTrainingJob

下面是一个基本的 XGBoostTrainingJob 配置示例:

apiVersion: batch.tensorstack.dev/v1beta1
kind: XGBoostTrainingJob
metadata:
  name: training-iris-xgb
spec:
  replicaSpecs:
    - type: master
      replicas: 1
      restartPolicy: OnFailure
      template:
        spec:
          containers:
            - name: xgboost
              image: t9kpublic/xgboost-dist-iris:3.7
              command:
                - python3
                - /mnt/main.py
                - --job_type=Train
                - --xgboost_parameter=objective:multi:softprob,num_class:3
                - --n_estimators=10
                - --learning_rate=0.1
                - --model_path=/mnt/xgboost_model/
                - --model_storage_type=local
    - type: worker
      replicas: 2
      restartPolicy: OnFailure
      template:
          containers:
            - name: xgboost
              image: t9kpublic/xgboost-dist-iris:3.7
              command:
                - python3
                - /mnt/main.py
                - --job_type=Train
                - --xgboost_parameter=objective:multi:softprob,num_class:3
                - --n_estimators=10
                - --learning_rate=0.1
                - --model_path=/mnt/xgboost_model/
                - --model_storage_type=local

在该例中:

  • 创建 1 个 master 副本和 2 个 worker 副本(由 spec.replicaSpecs[*].replicas 字段和 spec.replicaSpecs[*].type 字段指定)。
  • 每个副本使用 registry.tensorstack.cn/t9kmirror/xgboost-dist-iris:1.1 镜像,执行命令 python3 /mnt/main.py --job_type=Train --xgboost_parameter=objective:multi:softprob,num_class:3 --n_estimators=10 --learning_rate=0.1 --model_path=/mnt/xgboost_model/ --model_storage_type=local(由 spec.replicaSpecs<a target="_blank" rel="noopener noreferrer" href="https://kubernetes.io/docs/concepts/workloads/pods/#pod-templates">*].template 字段指定,此处的填写方式参考 [PodTemplate)。
  • 当副本失败后,会自动重启(由 spec.replicaSpecs[*].restartPolicy 字段指定)。

成功和失败

在 XGBoost 分布式训练框架中,副本有 2 种类型:Master 和 Worker,其中 Master 是主节点。当分布式训练的主节点成功结束时,XGBoost 分布式训练成功;反之,当分布式训练的主节点执行失败时,XGBoost 分布式训练失败。

但是主节点的失败有时可能是因为环境因素导致的,比如集群网络断连、集群节点崩溃等等,此类原因导致的失败应该被允许自动恢复。针对这一情况,XGBoostTrainingJob 允许副本重启(请参阅重启机制),并设定了重启次数限制(由 spec.runPolicy.backoffLimit 字段指定),当副本重启次数达到上限后,如果主节点再次失败,则训练失败。此外,XGBoostTrainingJob 可以设置最长执行时间(由 spec.runPolicy.activeDeadlineSeconds 字段指定),当超过这个执行时间后,训练失败。

如果 XGBoostTrainingJob 在没有超过重启次数和没有超过最长执行时间的情况下成功完成了主节点的运行,则训练成功。

重启机制

XGBoostTrainingJob 的 spec.replicaSpec[*].template 字段使用 PodTemplate 的规范填写,但是 Pod 的重启策略并不能满足 XGBoostTrainingJob 的需求,所以 XGBoostTrainingJob 使用 spec.replicaSpec[*].restartPolicy 字段覆盖 spec.replicaSpec[*].template 中指定的重启策略。

可选的重启策略有以下四种:

  • Never:不重启
  • OnFailure:失败后重启
  • Always:总是重启
  • ExitCode:特殊退出码重启

使用 Never 重启策略时,Job 的副本失败后不会重启。如果需要调试代码错误,可以选择此策略,便于从副本中读取训练日志。

ExitCode 是一种比较特殊的重启策略,它将失败进程的返回值分为两类:一类是由于系统环境原因或用户操作导致的错误,此类错误可以通过重启解决;另一类是代码错误或者其他不可自动恢复的错误。可重启的退出码包括:

  • 130(128+2):使用 Control+C 终止容器运行。
  • 137(128+9):容器接收到 SIGKILL 信号。
  • 143(128+15):容器接收到 SIGTERM 信号。
  • 138:用户可以自定义这个返回值的含义。如果用户希望程序在某处退出并重启,可以在代码中写入这个返回值。

重启次数限制

如果因为某种原因(例如代码错误或者环境错误并且长时间没有修复),XGBoostTrainingJob 不断地失败重启却无法解决问题,这会导致集群资源的浪费。用户可以通过设置 spec.runPolicy.backoffLimit 字段来设置副本的最大重启次数。重启次数为所有副本共享,即所有副本重启次数累计达到此数值后,副本将不能再次重启。

清除策略

在训练结束后,可能有些副本仍处于运行状态。这些运行的副本仍然会占用集群资源,XGBoostTrainingJob 提供清除策略,在训练结束后删除这些训练节点。

XGBoostTrainingJob 提供以下三种策略:

  • None:不删除副本。
  • All:删除所有副本。
  • Unfinished:只删除未结束的副本。
`None` 策略主要用于训练脚本调试阶段。如果需要从副本中读取训练日志,则可以选用此策略。但由于这些副本可能占用资源并影响后续训练,建议你在调试完毕后手动删除这些副本或删除整个 XGBoostTrainingJob。

调度器

目前 XGBoostTrainingJob 支持使用以下两种调度器:

  1. Kubernetes 的默认调度器
  2. T9k Scheduler 调度器

调度器通过 spec.scheduler 字段设置:

  • 不设置 spec.scheduler 字段,则默认使用 Kubernetes 的默认调度器。
  • 设置 spec.scheduler.t9kScheduler 字段,则使用 T9k Scheduler 调度器。

在下面的示例中,XGBoostTrainingJob 启用 T9k Scheduler 调度器,将副本插入 default 队列中等待调度,其优先级为 50。

...
spec:
  scheduler:
    t9kScheduler:
      queue: default
      priority: 50

调试模式

XGBoostTrainingJob 支持调试模式。在该模式下,训练环境会被部署好,但不会启动训练,用户可以连入副本测试环境或脚本。

该模式可以通过 spec.runMode.debug 字段来设置:

  • spec.runMode.debug.enabled 表示是否启用调试模式。
  • spec.runMode.debug.replicaSpecs 表示如何配置各个副本的调试模式:
    • spec.runMode.debug.replicaSpecs.type 表示作用于的副本类型。
    • spec.runMode.debug.replicaSpecs.skipInitContainer 表示让副本的 InitContainer 失效,默认为 false
    • spec.runMode.debug.replicaSpecs.command 表示副本在等待调试的时候执行的命令,默认为 sleep inf
    • 如果不填写 spec.runMode.debug.replicaSpecs 字段,则表示所有副本都使用默认设置。

在下面的示例中:

  • 示例一:开启了调试模式,并配置 worker 跳过 InitContainer,并执行 /usr/bin/sshd
  • 示例二:开启了调试模式,副本使用默认调试设置,即不跳过 InitContainer,并执行 sleep inf
# 示例一
...
spec:
  runMode:
    debug:
      enabled: true
      replicaSpecs:
        - type: worker
          skipInitContainer: true
          command: ["/usr/bin/sshd"]

---
# 示例二
...
spec:
  runMode:
    debug:
      enabled: true

暂停模式

XGBoostTrainingJob 支持暂停模式。在该模式下,删除(或不创建)副本,停止训练。

该模式可以通过 spec.runMode.pause 字段来设置:

  • spec.runMode.pause.enabled 表示是否启用暂停模式。
  • spec.runMode.pause.resumeSpecs 表示结束暂停后,如何恢复各个副本:
    • spec.runMode.pause.resumeSpecs.type 表示作用于的副本类型。
    • spec.runMode.pause.resumeSpecs.skipInitContainer 表示让副本的 InitContainer 失效,默认为 false
    • spec.runMode.pause.resumeSpecs.commandspec.runMode.pause.resumeSpecs.args 表示副本在恢复运行时候执行的命令,默认使用 spec.replicaSpecs[0].template 中的命令。
    • 如果不填写 spec.runMode.pause.resumeSpecs 字段,则表示所有副本都使用默认设置。

用户可以随时修改 spec.runMode.pause.enabled 来控制任务暂停,但是不可以更改 spec.runMode.pause.resumeSpecs,所以如果有暂停 XGBoostTrainingJob 的需求,请提前设置好恢复设置。

在下面的示例中:

  • 示例一:开启了暂停模式,并配置 worker 跳过 InitContainer,并执行 /usr/bin/sshd
  • 示例二:开启了暂停模式,副本使用默认恢复设置,即不跳过 InitContainer,并执行 spec.replicaSpecs[0].template 中设置的命令。
# 示例一
...
spec:
  runMode:
    pause:
      enabled: true
      resumeSpecs:
        - type: worker
          skipInitContainer: true
          command: ["/usr/bin/sshd"]

---
# 示例二
...
spec:
  runMode:
    pause:
      enabled: true

XGBoostTrainingJob 状态

XGBoostTrainingJob 的状态和阶段

status.conditions 字段用于描述当前 XGBoostTrainingJob 的状态,包括以下 6 种类型:

  1. Initialized:XGBoostTrainingJob 已经成功创建各子资源,完成初始化。
  2. Running:开始执行任务。
  3. ReplicaFailure:有一个或多个副本出现错误。
  4. Completed:XGBoostTrainingJob 成功。
  5. Failed:XGBoostTrainingJob 失败。
  6. Paused:XGBoostTrainingJob 进入暂停模式,所有副本都已删除或正在删除。

status.phase 字段用于描述当前 XGBoostTrainingJob 所处的阶段,XGBoostTrainingJob 的整个生命周期主要有以下7个阶段:

  1. Pending:XGBoostTrainingJob 刚刚创建,等待副本启动。
  2. Running:副本创建成功,开始执行任务。
  3. Paused:XGBoostTrainingJob 进入暂停模式。
  4. Resuming:XGBoostTrainingJob 正从暂停模式中恢复运行。恢复运行后,切换为 Running 阶段。
  5. Succeeded:XGBoostTrainingJob 成功。
  6. Failed:XGBoostTrainingJob 失败。
  7. Unknown:控制器无法获得 XGBoostTrainingJob 的阶段。

在下面的示例中,XGBoostTrainingJob 所有子资源创建成功,所以类型为 Initalizedcondition 被设为 True;XGBoostTrainingJob 运行结束,所以类型为 Completedcondition 被设置为 True;XGBoostTrainingJob 的训练成功结束,所以类型为 Completedcondition 被设置为 True(原因是 The job has finished successfully.)。当前 XGBoostTrainingJob 运行阶段为 Succeeded

...
status:
  conditions:
    - lastTransitionTime: "2023-12-19T02:40:25Z"
      message: The job has been initialized successfully.
      reason: '-'
      status: "True"
      type: Initialized
    - lastTransitionTime: "2023-12-19T02:53:14Z"
      message: The job has finished successfully.
      reason: Succeeded
      status: "False"
      type: Running
    - lastTransitionTime: "2023-12-19T02:53:14Z"
      message: The job has finished successfully.
      reason: Succeeded
      status: "False"
      type: Failed
    - lastTransitionTime: "2023-12-19T02:53:14Z"
      message: The job has finished successfully.
      reason: Succeeded
      status: "True"
      type: Completed
    - lastTransitionTime: "2023-12-19T02:40:25Z"
      message: All pods are running normally.
      reason: '-'
      status: "False"
      type: ReplicaFailure
  phase: Succeeded

副本的状态

status.tasks 字段用来记录副本的状态,记录的内容主要包括:

  • 副本的重启次数(同一种角色的副本的重启次数之和);
  • 副本当前的运行阶段,此处的“运行阶段”在 K8s Pod 的 5 个阶段的基础上,添加了 CreatingDeleted 分别表示正在创建和已删除;
  • 副本在集群中对应的 Pod 的索引信息。

在下面的示例中,XGBoostTrainingJob 创建了 1 个角色为 worker 的副本,当前均处于 Succeeded 阶段,运行在 mnist-trainingjob-5b373-worker-0 这个 Pod 上。

...
status:
  tasks:
  - replicas:
    - containers:
      - exitCode: 0
        name: pytorch
        state: Terminated
      name: mnist-trainingjob-5b373-worker-0
      phase: Succeeded
      uid: d39f91d6-9c48-4c57-bb71-4131226395b6
    type: worker

副本状态统计

status.aggregate 字段统计了各个阶段的副本数量。

在下面示例中,XGBoostTrainingJob 创建了 3 个副本,其中 1 个处于 Pending 阶段,另外两个处于 Running 阶段。

...
status:
  aggregate:
    creating: 0
    deleted: 0
    failed: 0
    pending: 1
    running: 2
    succeeded: 0
    unknown: 0
...

MPIJob

OpenMPI 是一个开源的 MPI(Message Passing Interface)协议的实现项目。

MPIJob 是一种使用 OpenMPI 进行分布式计算的 T9k Job,此资源让你能够方便地在集群环境中使用 OpenMPI 进行训练。

创建 MPIJob

下面的 MPIJob 示例创建了 5 个执行副本,每个执行副本启动 3 个进程,运行随机游走程序:

apiVersion: batch.tensorstack.dev/v1beta1
kind: MPIJob
metadata:
  name: mpi-example
spec:
  worker:
    replicas: 5
    extraMPIArgs:
      - -N
      - "3"
      - --enable-recovery
      - --max-restarts
      - "100"
      - --allow-run-as-root
      - -bind-to
      - none
    cmd:
      - ./random_walk
      - "20"
      - "40"
      - "2"
    template:
      spec:
        containers:
          - name: mpi-worker
            image: t9kpublic/mpi-tutorial:2021022-2
            resources:
              limits:
                cpu: 100m
              requests:
                cpu: 50m
            workingDir: /usr/local/code
  mca:
    btl: ^openib
  runPolicy:
    cleanUpWorkers: true
  ssh:
    sshdPath: /usr/sbin/sshd
  mpiHome: /usr/local

在该例中:

  • 创建 5 个执行副本(由 spec.worker.replicas 字段指定)。
  • spec.worker.template 字段沿用 PodTemplate 的规约,配置执行副本和启动副本的环境。每个执行副本包含一个名为 mpi-worker 的容器(为了确定用于执行 MPI 进程的容器,执行副本定义中必须有一个名为 mpi-worker 的容器)。mpi-worker 容器创建后执行 sshd 命令并等待启动副本连接,所以此容器会忽略 PodTemplate 定义中的 commandargs 字段(因此该例中没有填写这两个字段)。
  • 在执行副本准备完毕后,启动副本向执行副本发送启动命令,令执行副本创建 3 个 MPI 进程,这些进程分别执行 ./random_walk 20 40 2(由 spec.worker.cmd 字段指定)命令。
  • 在训练过程中不使用 Infiniband 进行通信(由 spec.mca.btl 字段指定)。
  • 在训练结束后自动清除副本(由 spec.runPolicy.cleanUpWorkers 字段指定)来释放集群资源。
  • sshd 的路径为 /user/sbin/sshd(由 spec.ssh.sshdPath 字段指定,使用该字段的原因是 sshd 程序必须使用绝对路径调用,所以需要其具体路径)。
  • MPI 安装在 /usr/local 处(由 spec.mpiHome 字段指定,使用该字段的原因是 mpirun 的有些功能需要知道 MPI 的根目录地址才能正确运行)。

运行 Horovod 训练脚本

使用 Horovod 框架的分布式训练脚本也可以使用 MPIJob 进行训练。

在 MPIJob 中需要执行以下操作:

  1. spec.worker.template.spec.containers[mpi-worker].env 字段中添加 NCCL_DEBUG
  2. spec.mca 字段中添加 pml:ob1btl:^openib

下面是使用 MPIJob 执行 Horovod 框架的分布式训练脚本的示例:

apiVersion: batch.tensorstack.dev/v1beta1
kind: MPIJob
metadata:
  name: mpi-example
spec:
  mca:
    btl: ^openib
    pml: ob1
  worker:
    template:
      spec:
        containers:
          - name: mpi-worker
            env: 
            - name: "NCCL_DEBUG"
              value: "INFO"
...

调度器

目前 MPIJob 支持使用以下两种调度器:

  1. Kubernetes 的默认调度器
  2. T9k Scheduler

调度策略通过 spec.scheduler 字段设置:

  • 不设置 spec.scheduler 字段,则使用 Kubernetes 的默认调度器。
  • 设置 spec.scheduler.t9kScheduler 字段,则使用 T9k Scheduler 调度器。

在下面的示例中,MPIJob 启用 T9k Scheduler 调度器,将执行副本插入 default 队列中等待调度,其优先级为 50。

...
spec:
  scheduler:
    t9kScheduler:
      queue: default
      priority: 50

调试模式

MPIJob 支持调试模式。在该模式下,训练环境会被部署好,但不会启动训练,用户可以连入副本测试环境或脚本。

该模式可以通过 spec.runMode.debug 字段来设置:

  • spec.runMode.debug.enabled 表示是否启用调试模式。
  • spec.runMode.debug.replicaSpecs 表示如何配置各个副本的调试模式:
    • spec.runMode.debug.replicaSpecs.type 表示作用于的副本类型。
    • spec.runMode.debug.replicaSpecs.skipInitContainer 表示让副本的 InitContainer 失效,默认为 false
    • spec.runMode.debug.replicaSpecs.command 表示副本在等待调试的时候执行的命令,launcher 的默认命令为 sleep infworker 的默认命令为 /usr/bin/sshd -D
    • 如果不填写 spec.runMode.debug.replicaSpecs 字段,则表示所有副本都使用默认设置。

在下面的示例中:

  • 示例一:开启了调试模式,并配置 worker 跳过 InitContainer,并执行 sleep inf
  • 示例二:开启了调试模式,副本使用默认调试设置,即 worker 不跳过 InitContainer,并执行 /usr/bin/sshd -D
# 示例一
...
spec:
  runMode:
    debug:
      enabled: true
      replicaSpecs:
        - type: worker
          skipInitContainer: true
          command: ["sleep", "inf"]

---
# 示例二
...
spec:
  runMode:
    debug:
      enabled: true

暂停模式

MPIJob 支持暂停模式。在该模式下,删除(或不创建)副本,停止训练。

该模式可以通过 spec.runMode.pause 字段来设置:

  • spec.runMode.pause.enabled 表示是否启用暂停模式。
  • spec.runMode.pause.resumeSpecs 表示结束暂停后,如何恢复各个副本:
    • spec.runMode.pause.resumeSpecs.type 表示作用于的副本类型。
    • spec.runMode.pause.resumeSpecs.skipInitContainer 表示让副本的 InitContainer 失效,默认为 false
    • spec.runMode.pause.resumeSpecs.commandspec.runMode.pause.resumeSpecs.args 表示副本在恢复运行时候执行的命令,默认使用 spec.replicaSpecs[0].template 中的命令。
    • 如果不填写 spec.runMode.pause.resumeSpecs 字段,则表示所有副本都使用默认设置。

用户可以随时修改 spec.runMode.pause.enabled 来控制任务暂停,但是不可以更改 spec.runMode.pause.resumeSpecs,所以如果有暂停 MPIJob 的需求,请提前设置好恢复设置。

在下面的示例中:

  • 示例一:开启了暂停模式,并配置 worker 跳过 InitContainer,并执行 /usr/bin/sshd
  • 示例二:开启了暂停模式,副本使用默认恢复设置,即不跳过 InitContainer,并执行 spec.replicaSpecs[0].template 中设置的命令。
# 示例一
...
spec:
  runMode:
    pause:
      enabled: true
      resumeSpecs:
        - type: worker
          skipInitContainer: true
          command: ["/usr/bin/sshd"]

---
# 示例二
...
spec:
  runMode:
    pause:
      enabled: true

MPIJob 状态

MPIJob 的状态和阶段

status.conditions 字段用于描述当前 MPIJob 的状态,包括以下 5 种类型:

  1. Initialized:MPIJob 已经成功创建各子资源,完成初始化。
  2. Running:开始执行任务。
  3. ReplicaFailure:有一个或多个副本出现错误。
  4. Completed:MPIJob 结束
  5. Failed:MPIJob 失败。
  6. Paused:MPIJob 进入暂停模式,所有副本都已删除或正在删除。

status.phase 字段用于描述当前 MPIJob 所处的阶段,MPIJob 的整个生命周期主要有以下几个阶段:

  1. Pending:MPIJob 刚刚创建,等待副本启动。
  2. Running:副本创建成功,开始执行任务。
  3. Paused:MPIJob 进入暂停模式。
  4. Resuming:MPIJob 正从暂停模式中恢复运行。恢复运行后,切换为 Running 阶段。
  5. Succeeded:MPIJob 结束
  6. Failed:MPIJob 失败。
  7. Unknown:控制器无法获得 MPIJob 的阶段。

在下面的示例中,MPIJob 所有子资源创建成功,所以类型为 Initalizedcondition 被设为 True;MPIJob 运行结束,所以类型为 Completedcondition 被设置为 True;但是 MPIJob 的训练结果是失败的,所以类型为 Failedcondition 被设置为 True。当前 MPIJob 运行阶段为 Failed

...
status:
  conditions:
    - lastTransitionTime: "2021-01-18T02:36:09Z"
      status: "True"
      message: "The job has been initialized successfully."
      reason: "-"
      type: Initializing
    - lastTransitionTime: "2021-01-18T02:36:09Z"
      status: "True"
      message: "All pods are running normally."
      reason: "-"
      type: Running
    - lastTransitionTime: "2021-01-18T02:36:09Z"
      status: "False"
      message: "All pods are running normally."
      reason: "-"
      type: ReplicaFailure
    - lastTransitionTime: "2021-01-18T02:36:31Z"
      status: "False"
      message: "The job exited with an error code."
      reason: "Failed"
      type: Completed
    - lastTransitionTime: "2021-01-18T02:36:31Z"
      status: "True"
      message: "The job exited with an error code."
      reason: "Failed"
      type: Failed
  phase: Failed

副本的状态

status.tasks 字段用来记录副本的状态,记录的内容主要包括:

  • 副本的重启次数(同一种角色的副本的重启次数之和)
  • 副本当前的运行阶段
  • 副本在集群中对应的 Pod 的索引信息

在下面的示例中,MPIJob 创建了 1 个启动副本和 2 个执行副本。当前均处于 Running 阶段,分别运行在 mpi-example-worker-0mpi-example-worker-1 这 2 个 Pod 上;启动副本当前处于 Running 阶段,运行在 mpi-example-launcher Pod 上。

...
status:
  tasks:
  - type: launcher
    restartCount: 0
    status:
    - phase: Running
      name: mpi-example-launcher
      uid: 66634db2-35e7-4641-a4dc-adbd5479734e
      containers: []
  - type: worker
    restartCount: 0
    status:
    - phase: Running
      name: mpi-example-worker-0
      uid: e3ec2ee3-6645-4e21-993f-1e472b94e0ae
      containers: []
    - phase: Running
      name: mpi-example-worker-1
      uid: 908a93f0-7b8b-491e-85d5-3da0abcb4ca4
      containers: []

副本状态统计

status.aggregate 字段统计了各个阶段的副本数量。

在下面示例中,MPIJob 创建了 3 个副本,其中 1 个处于 Pending 阶段,另外两个处于 Running 阶段。

...
status:
  aggregate:
    creating: 0
    deleted: 0
    failed: 0
    pending: 1
    running: 2
    succeeded: 0
    unknown: 0
...

下一步

BeamJob

BeamJob 用于在集群中通过 Apache Beam Python SDK 运行分布式计算任务,并提供多种底层计算引擎,目前支持 Apache Flink,未来会支持 Apache Spark

创建 BeamJob

下面是一个基本的 BeamJob 配置示例,负责统计输入文件中的英文单词出现次数,并将结果存储在输出文件中:

apiVersion: batch.tensorstack.dev/v1beta1
kind: BeamJob
metadata:
  name: beamjob-example
spec:
  flinkClusterTemplate:
    spec:
      flinkVersion: 1.10.1
      image:
        name: t9kpublic/flink:1.10.1
      jobManager:
        accessScope: Cluster
        resources:
          limits:
            cpu: "100m"
            memory: "1Gi"
      taskManager:
        replicas: 2
        resources:
          limits:
            cpu: "100m"
            memory: "2Gi"
      flinkProperties:
        taskmanager.numberOfTaskSlots: "1"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - image: t9kpublic/apache_beam_python3.7_sdk:2.22.0
            name: submit-job
            command:
              - "python3"
            args:
              - "-m"
              - "apache_beam.examples.wordcount"
              - "--input"
              - "/mypvc/input.txt"
              - "--output"
              - "/mypvc/output.txt"
            volumeMounts:
              - mountPath: "/mypvc"
                name: mypvc
          volumes:
            - name: mypvc
              persistentVolumeClaim:
                claimName: mypvc
          restartPolicy: OnFailure

在该例中:

  • 你需要准备好一个名为 mypvc 的 PVC,并将名为 input.txt 的输入文件存放在 PVC 的根路径下。
  • flinkClusterTemplate 字段描述了所要创建的 Flink 集群,其中包含 1 个 Job Manager{target=_blank},所使用的 Flink 版本为 1.10.1。
  • jobTemplate 字段描述了用户如何将所要运行的任务提交给 Flink 集群,其中所使用的 Apache Beam Python SDK 版本为 2.22.0,所运行的程序为 Apache Beam Python SDK 自带的单词统计程序 apache_beam.examples.wordcount

BeamJob 状态

BeamJob 的状态和阶段

status.conditions 字段用于描述当前 BeamJob 的状态,包括以下 2 种类型:

  • ClusterRunning:Flink 集群正在运行
  • JobRunning:用户提交的任务正在运行

status.phase 字段用于描述当前 BeamJob 所处的阶段,BeamJob 的整个生命周期主要有以下几个阶段:

  1. Initializing:BeamJob 刚刚创建,等待 Flink 集群启动。
  2. Running:Flink 集群已启动,用户提交的任务正在运行。
  3. Succeeded:BeamJob 成功。
  4. Failed:BeamJob 失败。
  5. Unknown:控制器执行错误,导致未能获取 BeamJob 当前运行阶段。

status.jobURL 字段是 Flink 集群的 Web UI 中用户提交的此次任务对应的详细信息页面。

在下面的示例中,Flink 集群已启动,所以类型为 ClusterRunningcondition 被设置为 True;用户所提交的任务正在运行,所以类型为 JobRunningcondition 被设置为 True。当前 BeamJob 运行阶段为 Running,如需在 Flink 集群的 Web UI 中查看任务的详细信息,请跳转至 jobURL

...
status:
  conditions:
    - lastTransitionTime: "2021-01-18T02:36:09Z"
      status: "True"
      type: ClusterRunning
    - lastTransitionTime: "2021-01-18T02:36:31Z"
      status: "True"
      type: JobRunning
  phase: Running
  jobURL: /t9k/flink-cluster/beamjob-example-flinkcluster/namespace/t9k-example/#/job/c9f62e4d61d089f351ab1f8b29e1df32/overview/

status.flinkClusterStatus 字段用来记录 Flink 集群的状态,包括所有 Job Manager 和 Task Manager 的运行阶段以及对应的 Pod 索引。

在下面的示例中,BeamJob 创建的 Flink 集群包括 1 个 Job Manager 和 2 个 Task Manager,均处于 Running 阶段(记录在 phase 字段中),对应的 Pod 的索引信息记录在 reference 字段中(包括 Pod 的名称和 UID)。

...
status:
  flinkClusterStatus:
    jobManagerStatus:
    - phase: Running
      reference:
        name: beamjob-example-flinkcluster-jobmanager-0
        uid: 21c67b2d-88d4-4b0a-9044-2311edee5e83
    taskManagerStatus:
    - phase: Running
      reference:
        name: beamjob-example-flinkcluster-taskmanager-0
        uid: c120c704-0730-49c8-8995-5fb719840af7
    - phase: Running
      reference:
        name: beamjob-example-flinkcluster-taskmanager-1
        uid: f1326d53-c5b6-4869-b5e9-8c35b7a7637d

用户提交任务的状态

status.jobStatus 字段用来记录用户所提交的任务的状态,包括运行阶段以及对应的 Pod 索引。

在下面的示例中,BeamJob 创建的用户任务仅包含 1 个 Pod,处于 Succeeded 阶段(记录在 phase 字段中),对应的 Pod 的索引信息记录在 reference 字段中(包括 Pod 的名称和 UID)。用户所提交的任务运行可能出现错误并多次重试,因此 status.jobStatus 字段可能包含多个 Pod。

...
status:
  jobStatus:
  - phase: Succeeded
    reference:
      name: beamjob-example-batchjob-szsn8
      uid: 9aed0159-fe2a-4096-99a7-1c89af5a6f0e

清除策略

在 BeamJob 成功或失败后,所创建的 Flink 集群仍然在运行,占据较多的计算资源。在下面的示例中,你可以在 spec.runPolicy 字段中将 cleanUpCluster 设置为 true,在 BeamJob 运行完毕(无论成功还是失败)之后删除 Flink 集群。

...
spec:
  runPolicy:
    cleanUpCluster: true
...

调度器

目前 BeamJob 支持两种调度器:

  1. Kubernetes 的默认调度器
  2. T9k Scheduler 调度器

调度器通过 spec.scheduler 字段设置:

  • 不设置 spec.scheduler 字段,则默认使用 Kubernetes 的默认调度器。
  • 设置 spec.scheduler.t9kScheduler 字段,则使用 T9k Scheduler 调度器。

在下面的示例中,BeamJob 启用 T9k Scheduler 调度器,将副本插入 default 队列中等待调度,其优先级为 50。

...
spec:
  scheduler:
    t9kScheduler:
      queue: default
      priority: 50
...

资产管理

所谓 AI 资产,指数据集和模型等人工智能相关的数据。

TensorStack AI 平台的资产管理模块(AssetHub,以下简称 AH)对模型和数据集提供完善的管理功能,包括版本管理、持续开发和协同开发等功能。

产品架构

structure

如上图所示,AH 使用 TensorStack AI 平台自研存储系统 AIStore 存储数据,用户可以通过 AH 控制台、命令行工具和 SDK 工具与 AIStore 连接,实现 AH 的各项功能。

版本控制

AH 支持多版本模型管理,用户可以训练和提交多个临时版本模型,发布其中符合预期的模型。

多版本管理通过以下机制实现:

  • Branch:分支,用户可以创建一个新分支来记录模型的临时版本;将新分支合并到主分支上,完成模型的发布。
  • Commit:“交付”,相当于版本快照,便于确定版本和追溯历史。
  • Tag:标签,用户可以为具有“特殊意义”的 Commit 标记标签,比如 best、v1 等。

数据集同样支持 Branch、Commit 和 Tag 的管理方式,不过数据集不会如模型那样频繁产出,所以一般建议数据集只在主分支上持续更新。

S3 接口

在训练(或部署服务)时,除了将数据集和模型下载到本地使用,大多数框架也支持直接从 S3 数据服务上动态获取数据文件。

AH 提供 S3 接口,用户可以在 AH 控制台上创建 S3 凭证,然后使用页面上生成的 S3 配置文件在训练过程中直接通过 S3 接口获取数据。

协同开发

AH 支持文件夹粒度的权限共享。用户可以将一组模型或数据集分享给其他人,实现多人共同开发和训练结果共享的目的。

可分享的权限包括查看权限或编辑权限,编辑权限包含查看权限。分享的目标可以是另一个用户、用户组或者公开给所有人。

下一步

实验管理

TensorStack AI 平台的实验管理模块(Experiment Management,以下简称 EM)提供完善的实验数据追踪功能,能够收集实验元数据、实验中间产物,并可视化和比较实验结果,推动模型进步。

产品架构

structure

如上图所示,EM 使用 TensorStack AI 平台自研存储系统 AIStore 存储数据,用户可以通过 EM 控制台、命令行工具和 SDK 工具与 AIStore 连接,实现 EM 的各项功能。

存储结构

EM 使用树状结构组织一个用户的实验数据,在 Web UI 中体现为目录结构。

# EM 目录结构示意图
user:demo
  ├── em-example/
  │   ├── mnist_dataset
  │   └── mnist_keras
  └── autotune/
      └── keras-tune

节点类型

EM 树状结构中,节点根据存储方式分为四类,用 StorageType 表示:

  • StorageType == 0:不存储数据文件,仅用于组织 EM 树状结构。EM 中文件夹即该类型节点。
  • StorageType == 1:存储一个文件数据。
  • StorageType == 2:存储一组数据文件。
  • StorageType == 3:该类型节点可以创建和管理多个版本,每一个版本中可以存储一组数据文件。

在这四种存储类型的基础上,EM 根据用途实现以下 7 个节点类型:

  • Folder:Storage Type == 0,文件夹结构,用来组织实验数据。
  • Shotrcut:Storage Type == 0,快捷方式,指向另一个节点。
  • Run:Storage Type == 2,记录实验元数据,包括实验基本信息、实验参数和实验指标。
  • Artifact:Storage Type == 2,记录实验的中间产物,也包括未发布的数据集和模型。
  • AutoTune:Storage Type == 2,记录超参数调优实验数据,参考超参数调优实验
  • Model:Storage Type == 3,记录机器学习模型。
  • Dataset:Storage Type == 3,记录机器学习所使用的数据集。

Artifact 没有特定的文件组织结构,用户可根据需要组织上传。

Model 和 Dataset 由 TensorStack 平台的资产管理模块,具体请参考 EM 和 AssetHub 之间的关系

Run 和 Autotune 是实验元数据的存储节点,具有特定的文件组织结构,EM Web 根据这些特定的文件组织结构进行实验数据的可视化。

Run 节点

Run 记录实验元数据,包括实验基本信息、实验参数和实验指标。

Run 节点中包含一个 index.yaml 文件,其中记录其他实验数据在该节点中的相对路径:

hyperparameters: hyperparameters.yaml
metrics:
  train: metrics/train.yaml
  val: metrics/val.yaml
  test: metrics/test.yaml
platform: platform.yaml
git: git.yaml
log: stdout.log
  • hypterparameters:机器学习超参数。
  • metrics:训练指标,由于指标可能产生自不同阶段,同一阶段也可能有多种指标,所以使用上例中的结构记录多个指标文件。
  • platform:平台信息,包括系统版本、python 包版本等。
  • git:代码存储位置,我们一半会将机器学习脚本存储在 GitHub 中。
  • log:日志文件。

上述文件的生成可以由 em 工具自动完成,用户只需要了解如何使用 em 工具。参考 em API 文档

AutoTune 节点

AutoTune 记录超参数调优实验数据,包括实验的基本配置以及每一次训练的参数和指标。

AutoTune 节点的文件结构如下:

.
├── profile.json
├── 17671/
│   ├── metadata.json
│   └── metrics.yaml
...
  • profile.json:记录超参数调优实验的训练配置、超参数搜索空间和调优配置等信息
  • 17671:超参数调优过程中,每一次训练都会创建一个文件夹用来记录训练数据,文件夹名称即训练的 ID(随机生成)。
    • metadata.json:记录训练参数和训练状态。
    • metrics.yaml:记录训练指标,超参数调优创建的训练都只会产生一个指标,调优控制器会根据该指标调整超参数。

可视化

EM 支持使用以下方式对 Run 数据进行可视化:

  • 数据流图:Run 和 Artifact 之间是存在使用和产出关系的,比如一次实验(Run)使用一个 Artifact 作为训练数据,最后产出另一个 Artifact。这种使用和产出关系构成了一个数据流动路线图,即数据流图。用户可以通过数据流图快速跳转到对应数据节点。
image
  • 指标折线图
image

EM 支持使用以下方式对 AutoTune 数据进行可视化:

  • “超参数-指标”图

autotune-pm

  • 指标优化曲线

autotune-opt

  • 各次训练的指标信息

autotune-trial-detail

权限管理

EM 支持节点粒度的权限控制:

  • 用户可以将一个节点分享给另一个用户、用户组或者公开给所有人。
  • 可分享的权限包括查看权限或编辑权限,编辑权限包含查看权限。
  • 文件夹权限修改会传递给所有子节点(当用户被分享了一个文件夹的编辑权限,则该用户自动拥有文件夹中所有节点的编辑权限;取消分享同理)。
  • 当一个节点被移动到另一个文件夹中,节点完全继承该文件夹的权限,覆盖节点之前的权限设置。

EM 和 AssetHub 之间的关系

AssetHub 是 TensorStack AI 平台的资产管理模块,用于管理数据集和模型。

数据集和模型作为实验的输入和输出,也应当作为实验管理的一部分,所以在 EM 中也可以看到 AssetHub 中的数据集和模型数据,如下图所示:

# EM 目录结构示意图
user:demo
  └── t9k-assethub/
      ├── model/
      │   ├── folder1
      │   │   ├── model1
      │   │   ...
      │   ├── folder2
      │   ...
      └── dataset/

数据集和模型分别记录在 EM 的 ./t9k-assethub/dataset./t9k-assethub/model 文件夹中,model 文件夹(dataset 文件夹同样)维护文件夹和模型两级结构,每一个模型都是一个具有版本管理功能的节点。

下一步

账户和安全

TensorStack AI 平台提供全面、系统性的安全支持,以保障平台本身、平台提供的各种工具(例如模型构建控制台)和用户的各种工作负载(例如训练任务)的安全。

账户

账户是用户在 TensorStack AI 平台身份和权限的代表。

在使用 TensorStack AI 平台前,用户需要先联系集群管理员为其创建一个平台账户。

API Key

在使用浏览器场景下(例如使用模型构建控制台),用户能够直接、同步地参与到身份认证和授权流程。用户可以方便地通过交互式的方式提供安全凭证(用户名 + 密码)来完成认证和授权,并随后通过 Cookie + Access Token 建立安全的交互过程。

但是,还有其他环境或者场景不适合采用前述方式。例如,用户通过命令行(环境受限,无法使用浏览器)或者在自动化脚本中向服务器发送请求,此时要求“用户同步进行交互”来获得访问令牌是非常不便捷的;或者,在此过程中需要通过客户程序输入密码,可能造成密码泄漏。同时,有些场景下,我们希望能够只授予客户端部分权限,但直接使用前述 access token 或者 Cookie 并不能更进一步缩小权限。

API Key 是 TensorStack AI 平台应对上述问题的解决方案。它是一种可撤销的、异步的、持久的安全授权方式,具有以下特点:

  • 可以长期持有(适合在脚本中使用)
  • 不会泄漏账户信息(无需使用用户名和密码)
  • 可以选择性地包含账户的部分权限
  • 方便在脚本程序、命令行工具等“非交互场景”进行集成使用
  • 可以随时方便地取消该授权

下一步

项目

项目(Project)是 TensorStack AI 平台为了有效使用集群资源,实现多用户、多项目同时、安全、共享使用集群而提供的机制;它是一个 CRD。

它具有以下特征:

  • 每个项目有一个项目管理员,他可以管理项目的成员
  • 只有项目的管理员和成员可以在项目中执行操作。
  • 每个项目对应一个同名的 Kubernetes 命名空间(Namespace),项目的成员拥有当前命名空间中几乎所有 K8s 资源的操作权限。

项目定义

以下是一个项目的定义(Custom Resource)示例:

apiVersion: tensorstack.dev/v1beta1
kind: Project
metadata:
spec:
  networkPolicy:
    template:
      spec:
        egress:
          - to:
              - namespaceSelector:
                  matchLabels:
                    kubernetes.io/metadata.name: t9k-system
                podSelector:
                  matchLabels:
                    app: security-console-server
        ingress:
          - from:
              - namespaceSelector:
                  matchLabels:
                    kubernetes.io/metadata.name: t9k-system
        policyTypes:
          - Ingress
          - Egress
    useDefaultTemplate: false
  quotaProfile: demo
  resourceQuota:
    template:
      spec:
        hard:
          cpu: '200'
          memory: 1280Gi
          nvidia.com/gpu: '18'
          persistentvolumeclaims: 200Gi
          pods: 1k

注:普通用户(包括项目管理员)不可修改上述项目配置,这里仅用该配置进行演示和讲解。

在上述示例中:

  • 该项目中设置以下网络策略:
    • 该项目中的工作负载可以访问 t9k-system 命名空间中的 security-console-server 服务(由字段 spec.networkPolicy.template.spec.egress 字段指定)。
    • 该项目中的服务可以被 t9k-system 命名空间的任一工作负载访问(由字段 spec.networkPolicy.template.spec.ingress 字段指定)。
  • 该项目使用 demo 资源配额模版。

资源配额与配额模版

一个项目的资源配额(由 spec.resourceQuota 字段指定)表示:当前项目中所能使用的资源上限,包括但不限于 CPU、内存、GPU 和 Pod 数量。

值得说明的一点:项目的资源配额中关于 CPU、内存、GPU、Pod 等资源数量的限制都直接作用于 Pod。即如果你创建一个 T9k Job,它即将创建的 pod 需要申请超过项目资源配额的资源数量,则 T9k Job 会被成功创建,但是 T9k Job 创建 Pod 的请求会被拒绝。

管理员可以使用配额模版批量设置或修改项目的资源配额。项目控制器会自动查找配额模版(由 spec.quotaProfile 字段指定)的内容,据此同步项目的资源配额。

网络策略

管理员可以通过项目的网络策略(由字段 spec.networkPolicy 字段指定)实现以下功能:

  1. 禁止普通用户访问系统级应用,避免保密信息泄漏和系统遭到恶意攻击。
  2. 阻断项目间通信,避免项目之间的互相干扰。
  3. 限定项目的访客 IP,构建安全的项目环境。

项目授权

项目授权信息存储在特定的授权服务器而非项目定义中。

普通用户(包括项目管理员)可以在安全控制台(Security Console)查看自己所在和所管理的项目以及项目的成员。

项目管理员可以通过安全控制台编辑项目成员。

项目的使用范围

项目可以被应用到 TensorStack AI 平台的模型构建、模型部署和工作流三个模块,集群管理员可以设置一个项目的使用范围。

目前项目可选的使用范围包括:

  • build:用户可以在模型构建和工作流模块中使用此项目。
  • deploy:用户可以在模型部署模块中使用此项目。

一个项目可以同时设置上述两个使用范围。

项目成员管理

项目管理员可以在安全控制台设置项目成员:

  • 项目成员可以是用户或用户组,一个用户组被设置为项目成员表示该组中的所有用户都可以使用该项目。
  • 设置项目成员时,可以对每一个成员单独设置项目的使用范围,对成员设置的项目使用范围应为项目所有使用范围的子集。

下一步

计算资源

用户在向集群提交计算任务,使用计算资源时,需要遵循管理员设置的各种策略。

  • 资源配额:用户提交的工作负载需要满足集群的配额策略;
  • 使用 t9k-scheduler:可能需要通过特定的 scheduler 才能使用特定的资源。

资源配额

管理员可在 ProjectQueue 分别设置资源(CPU、Memory、GPU、Storage 等)配额。

  • 针对 Project 的配额限制单个 Project 里的各种计算资源使用上限;
  • 设置在 Queue 上的配额则允许管理员设置特定容量的资源池供用户使用。

t9k-scheduler

t9k-scheduler 调度器专为大规模分布式并行计算及异构资源集群设计,可以更加有效地管理 AI 集群的计算资源和计算任务。相比于 K8s 的默认调度器 kube-schedulert9k-scheduler 在对 AI 计算场景的支持方面进行了增强,并增加了额外的机制以对集群进行更加精细化管理。

适用场景

为并行计算性质的工作负载分配资源,当用户需要部署多个 Pod 协同工作以运行任务时,推荐使用 t9k-scheduler

Queue & PodGroup

t9k-scheduler 有两个重要的机制:

  • Queuet9k-scheduler 提供 queue 让用户工作负载申请集群资源,每一个使用 t9k-scheduler 的 Pod 都可指定一个 queue 为其分配资源。队列的创建/修改由集群管理员负责。
  • PodGroup:PodGroup 是支持 coscheduling 机制重要组成部分。它代表一组 Pod,并定义了这组 Pod 在资源方面的限制条件。当限制条件被满足时,PodGroup 中的 Pod 才会被分配计算资源。

使用

当用户创建 Pod 使用 t9k-scheduler 时,需要进行下列操作:

  1. 将 Pod 使用的调度器名称设置为 t9k-scheduler;
  2. 设置 Pod 所属的队列。

当用户创建一组 Pod 协同完成一项任务,并使用 t9k-scheduler,需要进行下列操作 (用户一般通过使用 T9k-Job 自动化地使用 PodGroup):

  1. 创建一个 PodGroup,并在 PodGroup 中设置所属的队列;
  2. 将 Pod 使用的调度器名称设置为 t9k-scheduler;
  3. 设置 Pod 属于步骤一创建的 PodGroup。

下一步

使用 GPU

用户提交的工作负载,如果需要使用 GPU,需要在工作负载的计算资源配置中指定 GPU 扩展资源。

GPU 使用模式

独占使用

独占模式是指在特定时间段,GPU 卡分配给单一工作负载单独使用。

适用场景:GPU 被满负荷使用,并且计算需要尽快完成。例如 AI 模型的训练。

共享使用

共享模式是指单个物理 GPU 可以同时被多个工作负载使用。

适用场景:对于有些计算,例如交互式的 Notebook,小规模或者低使用量的模型推理服务,经常只需要使用 GPU 的部分计算能力。在这些情况下,让多个计算任务共享使用 GPU,将能极大地提高 GPU 的利用率,进而获得有益的投资回报率。

共享 NVIDIA GPU

以 NVIDIA GPU 为例,下面是 NVIDIA 提供的多种 GPU 共享和并发使用的机制,以支持不同的场景。

MPS

CUDA MPS(多进程服务 / Multi-Process Service)是 CUDA API 的客户端-服务器架构的实现,用于提供同一 GPU 同时给多个进程使用。MPS 是一个 “AI 史前”(深度学习尚未在 GPU 上运行)的方案,是 NVIDIA 为了解决在科学计算领域单个 MPI 进程无法有效利用 GPU 的计算能力而推出的技术。

与时间切片(Time Slicing)相比,MPS 通过在多个客户端之间共享一个 CUDA Context 消除了多个 CUDA 应用之间上下文切换的开销,从而带来更好的计算性能。 此外,MPS 为每个 CUDA 程序提供了单独的内存地址空间,因而可以实现对单个 CUDA 程序实施内存大小使用限制,克服了 Time Slicing 机制在这方面的不足。

优点:

  • 可以控制单个应用的内存大小使用限制;
  • 由于消除了多个 CUDA 应用之间 context swtich 的代价,具有更好的性能;
  • 是一个 CUDA 层面的方案,不依赖于 GPU 的特定架构,支持较早的 GPU 硬件。

缺点:

  • CUDA 应用之间隔离不足:单个应用的错误可以导致整个 GPU 重置(reset);
  • NVIDIA 还未(截止2024/01)正式在 K8s 环境下提供支持。

Time Slicing

时间切片(Time Slicing) 也称为时间共享(Temporal Sharing)是指把多个 CUDA 程序分配到同一个 GPU 上运行,即一个简单的超额订阅(oversubscription)策略。NVIDIA 在 Pascal 架构(GP100,2016 年首发)之上提供了对此技术的支持。这些 GPU 卡上的调度器提供了指令粒度(不再需要等待 CUDA kernel 执行完成)的计算抢占(Compute Premption)技术。当抢占发生时, 当前 CUDA 程序的执行上下文(execution context:寄存器、共享内存等)被交换(swapped)到 GPU DRAM,以便另一个 CUDA 程序运行。

优点:

  • 非常容易设置;
  • 对分区数量无限制;
  • 可在众多 GPU 架构上部署。

缺点:

  • 上下文切换引起的效率降低;
  • 共享 GPU 设备导致的的隔离不足、潜在的 GPU OOM 等;
  • 时间片周期恒定,且无法为每个工作负载设置可用资源的优先级或大小。

MIG

MIG 可以把一个 GPU 划分为最多 7 个独立的 GPU 实例,从而为多个 CUDA 程序提供专用的 GPU 资源,包括流式多处理器 (Streaming Multiprocessors) 和 GPU 引擎。这些 MIG 实例可以为不同的 GPU 客户端(例如进程、容器或 VM)提供更加高级的故障隔离能力和 QoS。

优点:

  • 硬件隔离,并发进程安全运行且互不影响;
  • 在分区级别提供监控和遥测(monitoring & telemetry)数据;
  • 每个分区可以叠加使用其他共享技术,例如 vGPU,time-slicing, MPS。

缺点:

  • 仅在最新的 GPU 架构(Ampere, Hopper)上提供;
  • 重新配置分区布局需在 GPU 空闲(驱逐所有正在运行的进程)时;
  • 一些分区配置会导致部分 SM / DRAM 无法被利用。

vGPU

NVIDIA vGPU 是 NVIDIA 在数据中心提供的 GPU 虚拟化技术,它对具有完整输入输出内存管理单元 (IOMMU) 保护的 VM 提供支持,使得这些 VM 能够同时、直接地访问单个物理 GPU。

除了安全性之外,NVIDIA vGPU 还有其他优势,例如:

  • 支持实时虚拟机迁移(live VM migration);
  • 可设置不同的调度策略,包括 best-effort、equal-share 和 fixed-sharez:
    • 当使用 fixed-share 调度器时可提供可预知的性能;
  • 运行混合的 VDI (Virtual Desktop Infrastructure) 和计算工作负载的能力;
  • 与业界广泛使用的虚拟机管理程序(hypervisor,如 vmware)的集成能力。

缺点:

  • 部署 vGPU 需要额外的软件授权费用;
  • 分区仍然通过时间片(time-slicing)完成。

扩展资源名称

如果用户想知道用户所使用的集群有哪些代表 GPU 的扩展资源名称,请咨询集群管理员。下面列举了一些常见的代表 GPU 的扩展资源。

NVIDIA GPU

当集群安装有 NVIDIA GPU 硬件资源时,通常有下列扩展资源名称:

  • nvidia.com/gpu:一个扩展资源对应一个 NVIDIA GPU 硬件资源。可以申请使用多个 GPU 资源。例如当声明资源 nvidia.com/gpu: 8 时,会有 8 个 NVIDIA GPU 分配给这个工作负载使用。
  • nvidia.com/gpu.shared:通过这个扩展资源,多个工作负载可以共享使用一个 NVIDIA GPU。需要注意,当共享机制是通过 time slicing 实现时,用户为工作负载设置 nvidia.com/gpu.shared 扩展资源的数量不能超过 1(参考)。

NVIDIA 还有其他形式的设备名称,例如,当部署了 MIG 技术时,常见的资源名称有:

  • nvidia.com/mig-3g.20gb:一个扩展资源对应的计算能力是物理 GPU 的 3/7,显存大小是 20GB。
  • nvidia.com/mig-2g.10gb:一个扩展资源对应的计算能力是物理 GPU 的 2/7,显存大小是 10GB。
  • nvidia.com/mig-1g.5gb:一个扩展资源对应的计算能力是物理 GPU 的 1/7,显存大小是 5GB。

AMD GPU

当集群安装有 AMD GPU 硬件资源时,通常有下列扩展资源名称:

  • amd.com/gpu:一个扩展资源对应一个 AMD GPU 硬件资源。同样的,可申请多个 GPU,例如 amd.com/gpu: 2

其他

请参考对应厂商的 device plugin 文档。

GPU 使用示例

独占 GPU

集群中部署了 NVIDIA GPU 后,一般配置扩展资源 nvidia.com/gpu 支持独占使用 GPU。

下面是一个使用 GPU 的 PytorchTrainingJob YAML 示例:

apiVersion: batch.tensorstack.dev/v1beta1
kind: PyTorchTrainingJob
metadata:
 name: pytorch-example
spec:
 replicaSpecs:
 - replicas: 4
   restartPolicy: OnFailure
   template:
     spec:
       containers:
       - command:
         - python
         - dist_mnist.py
         image: pytorch/pytorch:2.0.0-cuda11.7-cudnn8-devel
         name: pytorch
         resources:
           limits:
             nvidia.com/gpu: 4
           requests:
             cpu: 10
             memory: 5Gi
   type: worker

在该例中,spec.replicaSpecs[0].template.spec.containers[0].resources.limits 字段设置了资源量 nvidia.com/gpu: 4,表明一个 replica 会独占使用 4 个 NVIDIA GPU。由于设置了 PyTorchTraiiningJob 的 replica 数量为 4,所以 PyTorchTraiiningJob 总共会占用 16 个 NVIDIA GPU。

共享 GPU

扩展资源 nvidia.com/gpu.shared 代表共享 GPU。

下面是一个以共享方式使用 GPU 的 Notebook YAML 示例:

apiVersion: tensorstack.dev/v1beta1
kind: Notebook
metadata:
  name: tutorial
spec:
  type: jupyter
  template:
    spec:
      containers:
        - name: notebook
          image: t9kpublic/torch-2.1.0-notebook:1.77.1
          volumeMounts:
            - name: workingdir
              mountPath: /t9k/mnt
          resources:
            requests:
              cpu: '8'
              memory: 16Gi
              nvidia.com/gpu.shared: 1
            limits:
              cpu: '16'
              memory: 32Gi
              nvidia.com/gpu.shared: 1
      volumes:
        - name: workingdir
          persistentVolumeClaim:
            claimName: tutorial

在该例中:spec.template.spec.containers[0].resources.limits 字段定义了资源量 nvidia.com/gpu.shared: 1 ,表明这个 Notebook 以共享方式使用一个 NVIDIA GPU。

指定 GPU 型号

不同节点上安装的 GPU 型号经常是不同的,同一厂家的 GPU 对应的扩展资源名称常常是相同的,例如:对于 NVIDIA GPU,在不考虑共享 GPU 的情况下,A100 和 A40 型号对应的扩展资源名称都是 nvidia.com/gpu

调度器为工作负载分配资源时忽略型号信息,如果用户想让工作负载使用特定型号的 GPU,例如:NVIDIA A100-80GBNVIDIA A40,用户可以参考下列方式配置工作负载,使其能被分配到安装有特定型号 GPU 的节点上。

设置 nodeSelector

安装有 GPU 硬件的节点会通过节点标签来表明节点上安装的 GPU 型号。用户在创建工作负载时,可以为其设置 nodeSelectornodeSelector 的作用是通过节点标签来筛选节点,从而工作负载会被分配到期望的节点上。

如果用户将工作负载的 nodeSelector 设置为指定型号 GPU 对应的节点标签,并且为工作负载设置了代表 GPU 的扩展资源数量,那么工作负载就可以使用指定型号的 GPU。

常见的节点标签

如果用户想知道用户所使用的集群有哪些表明 GPU 型号的节点标签,请咨询管理员。

下面是一些表明 GPU 型号的节点标签示例:

GPU 型号节点标签
NVIDIA A100-40GBnvidia.com/gpu.product: NVIDIA-A100-PCIE-40GB
NVIDIA A100-80GBnvidia.com/gpu.product: NVIDIA-A100-PCIE-80GB
NVIDIA GTX 1070nvidia.com/gpu.product: NVIDIA-GeForce-GTX-1070
NVIDIA TITAN-Xnvidia.com/gpu.product: NVIDIA-TITAN-X

常见工作负载的 nodeSelector 字段

下面列举了常见的工作负载,以及工作负载用于设置 nodeSelector 的字段:

工作负载字段
GenericJobspec.replicaSpecs[*].template.spec.nodeSelector
PyTorchTrainingJobspec.replicaSpecs[*].template.spec.nodeSelector
TensorFlowTrainingJobspec.replicaSpecs[*].template.spec.nodeSelector
XGBoostTrainingJobspec.replicaSpecs[*].template.spec.nodeSelector
DeepSpeedJobspec.worker.template.spec.nodeSelector
ColossalAIJobspec.worker.template.spec.nodeSelector
MPIJobspec.worker.template.spec.nodeSelector
BeamJobspec.jobTemplate.spec.template.spec.nodeSelector
Notebookspec.template.spec.nodeSelector
SimpleMLService只有使用自定义框架时,才能通过字段 spec.custom.nodeSelector 设置 nodeSelector
MLService predictorspec.releases[*].predictor.template.spec.nodeSelector
MLService transformerspec.transformer.template..spec.nodeSelector
Podspec.nodeSelector

示例

下面是一个设置了 nodeSelector 的 notebook 示例:

apiVersion: tensorstack.dev/v1beta1
kind: Notebook
metadata:
 name: tutorial-nodeselector
spec:
 type: jupyter
 template:
   spec:
     containers:
       - name: notebook
         image: t9kpublic/torch-2.1.0-notebook:1.77.1
         volumeMounts:
           - name: workingdir
             mountPath: /t9k/mnt
         resources:
           limits:
             cpu: '16'
             memory: 32Gi
             nvidia.com/gpu: 1
     nodeSelector:
       nvidia.com/gpu.product: NVIDIA-A100-PCIE-40GB
     volumes:
       - name: workingdir
         persistentVolumeClaim:
           claimName: tutorial

在该例中: Notebook 的资源量设置了 nvidia.com/gpu: 1,表明 Notebook 要使用一个 GPU。 Notebook 的 nodeSelector 被设置为 nvidia.com/gpu.product: NVIDIA-A100-PCIE-40GB,所以 Notebook 的 Pod 会被分配到含有标签 nvidia.com/gpu.product: NVIDIA-A100-PCIE-40GB 的节点上运行。 从而 Notebook 会被分配一个 NVIDIA GPU A100-40GB。

设置队列

通过 nodeSelector 机制选择特定型号的 GPU 过程繁琐,而且管理员也缺乏对 GPU 使用权限的方便控制。TensorStack 提供了更加便捷的队列机制方便用户使用特定类型的资源。

当满足下列两个要求时,用户可以通过设置队列的方法来使用特定型号的 GPU:

  1. 管理员为集群提供了恰当的配置。例如,设置了队列 A100 以选择安装有 A100 GPU 的计算节点;
  2. 用户有权限使用这个队列。

用户在创建工作负载时,可以进行下列操作,选择特定型号的 GPU:

  • 使用 t9k-scheduler
  • 设置合适队列名称,例如 A100;
  • 设置使用 GPU 扩展资源,例如 nvidia.com/gpu

示例

假设管理员在集群中配置了两个队列,名称分别是:

  • a100:队列可以使用的节点上都安装有 GPU NVIDIA A100-80GB
  • a40:队列可以使用的节点上都安装有 GPU NVIDIA A40-40GB

并且,用户有权限使用这两个队列。

如果用户想创建一个使用 NVIDIA A100-80GB 的 Notebook,用户可以创建下列 Notebook:

apiVersion: tensorstack.dev/v1beta1
kind: Notebook
metadata:
 name: tutorial
spec:
 type: jupyter
 scheduler:
   t9kScheduler:
     queue: a100
 template:
   spec:
     containers:
       - name: notebook
         image: t9kpublic/torch-2.1.0-notebook:1.77.1
         volumeMounts:
           - name: workingdir
             mountPath: /t9k/mnt
         resources:
           limits:
             cpu: '16'
             memory: 32Gi
             nvidia.com/gpu: 1
     volumes:
       - name: workingdir
         persistentVolumeClaim:
           claimName: tutorial

在该例中:

  • Notebook 的资源量设置了 nvidia.com/gpu: 1,表明 Notebook 要使用一个 GPU。
  • 字段 spec.scheduler.t9kScheduler.queue 被设置为 a100,表明 Notebook 使用 T9k Scheduler 进行资源调度,并且使用队列 a100。

用户通过队列的方式使用更加简洁、方便。同时,集群管理员可使用权限等机制,更加方便地实施集群资源管理策略。

参考

K8s Extended resources
https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#extended-resources

Consuming extended resources
https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#consuming-extended-resources

Schedule GPUs | Kubernetes
https://kubernetes.io/docs/tasks/manage-gpus/scheduling-gpus/

Device Plugins
https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/device-plugins/

Assigning Pods to Nodes
https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/

Improving GPU Utilization in Kubernetes
https://developer.nvidia.com/blog/improving-gpu-utilization-in-kubernetes

MIG:NVIDIA Multi-Instance GPU User Guide
https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/gpu-operator-mig.html#configuring-mig-profiles

资源配额

为保证集群资源的合理分配和使用,管理员会在以下两个方面限制普通用户的资源使用(CPU、内存、GPU、Storage 等):

  1. 项目配额:限制用户在一个 Project(项目)中可以使用的资源总量。
  2. 队列配额:限制一个 Queue(队列中)的工作负载可以使用的资源总量。

用户创建的工作负载(如 T9k Job)不能超过上述两种配额的限制,否则工作负载将被拒绝接受。

具体请参考 “项目资源配额” 和 “队列资源配额”。

队列

概述

队列(Queue)是 T9k-Scheduler 提供的集群资源管理机制。

如果使用了 T9k-Scheduler,用户创建工作负载时,则可以选择使用一个特定的 Queue 申请集群资源。

队列设置

管理员创建在集群中创建多个 Queue ,并可设置:

  • Queue 的使用权限,以规定那些人员/组/项目可使用此 queue;
  • Queue 对应的计算节点集合,以方便地管理计算节点的使用;
  • 资源配额,限制通过此 Queue 使用的资源上限。

使用权限

Queue 的使用权限用于控制哪些用户、组、项目可以使用这个队列。队列的使用权限通过两种方式进行设置:

  • 管理员直接设置有权使用队列的用户/用户组。
  • 管理员设置队列的 spec.namespaceSelector(类型是 labelSelector)字段。

当项目满足下列任一条件时,用户有权在项目下创建使用某个队列的工作负载:

  • 队列设置了 spec.namespaceSelector,并且项目对应的 namespace 的标签符合这个 namespaceSelector
  • 项目的用户有权使用这个队列。

节点限制

队列的节点限制用于指定队列可用的集群工作节点(worker node),T9k-Scheduler 只会将队列内的工作负载分配到这些特定的节点上。

队列的 spec.nodeSelector (类型是 labelSelector)字段用于设置队列的节点权限:

  • 字段未设置时,队列可以使用集群内所有的节点
  • 字段设置后,队列可以使用节点标签满足 nodeSelector 的节点。

在下面的节点权限示例中:说明队列可以使用节点标签包含 topology.kubernetes.io/zone: pekingtopology.kubernetes.io/zone: tianjin 的节点。

spec:
  nodeSelector:
    matchExpressions:
    - key: topology.kubernetes.io/zone
      operator: In
      values:
      - peking
      - tianjin

资源配额

队列的资源配额用于限制队列可以使用的资源上限,如果用户创建的工作负载(例如 Job,Pod 等)会导致队列超出资源配额限制,那么系统会拒绝接受此工作负载。

队列的 spec.quota 字段定义队列的资源配额,队列的 status.allocated 字段表明队列已经使用的资源量。

在下面的示例中:

  • 工作负载的 CPU 资源请求量(requests)总和不能超过 40;
  • Queue 已经被分配了 38 个 CPU。
spec:
  quota:
    requests:
      cpu: 40
status:
  allocated:
    cpu: "38"

优先级

spec.priority 字段定义队列的优先级,值类型是 int,范围是 [0,100],数值越大代表队列的优先级越高。队列的优先级会影响下列事件:

  • 优先级较高的队列会被优先分配资源。
  • 如果 T9k-Scheduler 开启了资源抢占行为,优先级较高的队列有权抢占低优先级队列使用的资源。

是否可被抢占资源

spec.preemptible 字段定义队列是否可以被其他队列抢占资源,字段值类型是 bool

  • false ,队列无法被抢占资源;
  • true ,队列可以被抢占资源。

开启/关闭

spec.closed 字段定义队列是否处于关闭状态,当队列被关闭了,用户无法创建使用该队列的工作负载。字段值类型是 bool

  • 字段未设置或被设置为 false 时,队列处于开启状态;
  • 字段被设置为 true 时,队列处于关闭状态。

最大运行时长

最大运行时长会限制队列中 Pod 的运行时长,如果 Pod 的存在时长(存在时长=当前时间 - Pod 创建时间)超过最大运行时长,Pod 会被删除。

队列的 spec.maxDuration 字段设置了队列的最大运行时长:

  • 值类型是 string,并且需要满足正则表达式 ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$
  • 支持的时间单位:y, w(周), d, h, m, s, ms。
  • 示例:“3w”, “2h45m”。
  • 未设置时,队列不受最大运行时长约束。

资源尺寸

资源尺寸(resource shape)会限制队列中工作负载请求资源量的上限,当用户创建超过资源尺寸的工作负载时,工作负载会被系统拒绝。

队列的 spec.resourceShapeProfile 字段设置了队列使用的资源尺寸模版,模型对应的资源尺寸详情存储在 ConfigMap t9k-system/resource-shapes 中。用户可以通过 T9k 产品前端查看队列的资源尺寸设置。

下一步

PodGroup

概述

PodGroup 关联一组协同工作的 Pod,它们共同完成一项计算任务(例如分布式并行模型训练),因此需要作为一个整体来分配资源。通常情况下,用户可以通过创建 T9k Job 类的工作负载来间接使用 PodGroup,而不需要直接创建 PodGroup。

PodGroup 是 T9k 支持 coscheduling 机制的关键组成部分,可以为并行计算提供更好的支持,包括避免死锁场景和提高资源利用率。

规范

下面是一个基本的 PodGroup 示例:

apiVersion: scheduler.tensorstack.dev/v1beta1
kind: PodGroup
metadata:
  name: chorus
  namespace: default
spec:
  minMember: 3
  priority: 50
  queue: default

在该例中:

  • 最少运行数量是 3 个成员 Pod(由 spec.minMember 字段指定)。
  • PodGroup 的优先级是 50(由 spec.priority 字段指定)。
  • PodGroup 使用 default 队列(由 spec.queue 字段指定)申请资源。

队列

spec.queue 设置 PodGroup 欲使用的资源队列,默认值是 default。

优先级

spec.priority 字段设置 PodGroup 的优先级 ,值类型是 int,范围是 [0,100],默认值是 0,数值越大表明优先级越高。在同一个队列中,优先级高的 PodGroup 会被优先分配资源。

最少成员限制

成员数量限制包括两部分,必须同时满足,调度器才会为 PodGroup 分配资源:

  • 最少数量(minMember);
  • 角色最少数量(role minMember),但非必须字段。当未填写时,则自动满足。

最少数量

spec.minMember 设置 PodGroup 的最小运行数量,表明 PodGroup 的 Pod 数量(不包括失败的 Pod)达到最小运行数量时,调度器才会为 PodGroup 分配资源。

本文开头的示例中设置的最小运行数量是 3,但未设置角色最少数量。

角色最少数量

基于角色(role)的最小运行数量通过字段 spec.roles 的子字段设置。

  • spec.roles 是一个记录角色名称和该角色的最小运行数量的数组;
  • PodGroup 的 Pod 通过标签来指定自己的角色。

下面是一个示例:

spec:
  roles:
  - name: master
    minMember: 1
  - name: worker
    minMember: 3

在该示例中,PodGroup 包含两类角色 masterworker。当可运行的 master Pod 数量达到 1,worker Pod 数量达到 3 时,调度器才会为 PodGroup 分配资源。

状态

PodGroup 的状态记录在 status 字段中。

status.conditions 字段记录了当前 PodGroup 的状态,包括下列 2 种类型:

  • GroupScheduled: PodGroup 是否已经被分配过资源
  • SufficientGroupMember: PodGroup 的 Pod 数量是否满足最小运行需求

status.allocated 字段记录了当前 PodGroup 使用的资源量。

PodGroup 的 Pod 的数量:

  • status.pending:处于 Pending phase 的 Pod 数量
  • status.running:处于 Running phase 的 Pod 数量
  • status.succeeded:处于 Succeeded phase 的 Pod 数量
  • status.failed:处于 Failed phase 的 Pod 数量
  • status.unknown:处于 Unknown phase 的 Pod 数量

示例

下面的 YAML 片段展示了一个正常运行中的 PodGroup 的 status 字段:

  • allocated:podgroup 被分配的资源总和;
  • running: 3 个 pod 处于 running 状态;
  • condition SufficientGroupMemberTrue,表示 PodGroup 满足最小成员约束,可以被分配资源;
  • condition GroupScheduledTrue,表示整个 PodGroup 已经被分配资源;
status:
  allocated:
    cpu: 3
    memory: 600M
  conditions:
  - lastTransitionTime: "2023--17T13:54:02Z"
    reason: SufficientMemberPods
    status: "True"
    transitionID: 82ce5bf5-313d-4294-b44b-9b44ffd52213
    type: SufficientGroupMember
  - lastTransitionTime: "2023-12-17T13:48:16Z"
    message: Resources have been allocated to PodGroup
    reason: PodGroupScheduled
    status: "True"
    transitionID: c5a70cac-769c-44c4-a6ba-f4b1227cb135
    type: GroupScheduled
  running: 3

下一步

资源回收

一些交互式工作负载(例如 NotebookTensorBoardExplorer)的计算资源经常被闲置。例如在非工作时间,用户创建的 Notebook 服务虽然没有用户使用,但仍占用大量集群计算资源,造成资源浪费。

为充分利用集群资源,TensorStack AI 平台提供资源回收机制,自动检测并暂停空闲的 Notebook、TensorBoard 和 Explorer 等服务,释放占用的资源。

原理

以 Notebook 为例,介绍资源回收的原理(TensorBoard、 Explorer 或者其他工作负载同理)。

structure

如上图所示:

  1. 集群管理员设置 “资源回收配置” 策略;
  2. 根据配置,Resource Keeper 监听启用回收功能的项目(Project 2)中的 Notebook 状态;
  3. 当 Notebook 空闲时间达到配置中规定的阈值,则 Resource Keeper 对该资源实施暂停操作,以释放资源。

状态检测

很多在 TensorStack AI 平台上运行的服务,使用 PEP Proxy 来处理身份验证和授权。由于其 proxy 所有客户端请求,这个 PEP Proxy 也可以作为检查服务是否空闲的信息来源。

pepproxy

对于 TensorBoard 和 Explorer,对应控制器会向 PEP Proxy 发送请求,检查其上一次请求的时间,如果给定时间内(比如 1 小时,由集群管理员配置)没有再次请求,则控制器判定其为空闲状态。

Jupyter Notebook 本身的 server 就提供了状态查询功能。因此,对于 Notebook 类型的工作负载,Notebook 的控制器会先尝试向 Notebook server 发送请求检查空闲状态。如果处于空闲或请求失败(可能 Notebook 使用的不是 Jupyter 内核,主要发生在自定义 Notebook 上),则继续向 PEP Proxy 发送请求,查询 PEP Proxy 观测到的服务使用情况:例如,如果 1 小时内(由管理员配置)没有请求,则控制器判定其为空闲状态。

对于 RStudio Notebook,目前没有空闲状态的判定,控制器将其视为永远处于活跃状态。

资源使用监控

在 Tensorstack AI 平台创建工作负载后,用户可以通过控制台或命令行工具查看工作负载的资源使用情况。

控制台

用户可以在下列控制台的工作负载的详情页面查看资源监测图表:

  • 模型构建(Build Console):
    • Notebook
    • T9k Job
    • Tensorboard
    • Pod
  • 模型部署(Deploy Console):
    • MLService

当用户定义工作负载时可以选择性地为每个容器设定所需要的资源数量,最常见的可设定资源是 CPU、内存和扩展资源。

以 PyTorchTrainingJob 为例,用户可以查看下面几类资源的使用情况。

CPU / Memory / 扩展资源

CPU(内存)的资源监测图如下所示,图中包含三条折线:

  • 请求量:工作负载声明的 resources.requests.cpuresources.requests.memory
  • 上限:工作负载声明的 resources.limits.cpuresources.limits.memory
  • 使用量:工作负载实际使用的 CPU(内存)资源量
cpu
memory

当工作负载声明扩展资源时,显示扩展资源的资源监测图。

在本例中,PytorchTrainingJob 声明了扩展资源 nvidia.com/gpu: 2,页面显示了工作负载声明的 resources.limits."nvidia.com/gpu" 资源量。

nvidia.com/gpu

NVIDIA GPU

当工作负载声明的扩展资源是 nvidia.com/gpu 时,资源监测图会展示额外的 GPU 相关指标,包括:利用率、温度、功率、显存使用率、已用显存量、SM Clock、TensorCore 利用率。

下面是展示 GPU 利用率和显存使用率的图表:

gpu-utilization
gpu-memory-utilization

网络带宽

网络带宽显示下面两项指标:

  • 接收带宽:所有容器接收数据的网络带宽总计。
  • 发送带宽:所有容器发送数据的网络带宽总计。
network-receive
network-transmit

存储 I/O

存储 I/O 显示下面两项指标:

  • IOPS(读+写):所有容器在节点的物理磁盘上,进行读写的操作次数之和。
  • 吞吐量(读+写):所有容器在节点的物理磁盘上,读写数据的吞吐量。
storage-iops
storage-throughput

命令行工具

用户可以在 Notebook 的终端中,使用 kubectl top 命令查看 Pod 的 CPU、内存使用情况。例如:

(base) [/t9k/mnt t9kuser@managed-notebook-933f6-0]
$ kubectl top pods
NAME                                         CPU(cores)   MEMORY(bytes)   
managed-notebook-933f6-0                     25m          153Mi           
managed-project-event-ctl-854b96f4dd-f6hn8   1m           29Mi 

下一步

存储

TensorStack 平台支持多种类型的存储服务:Block Storage Volumes(块存储卷),Shared Filesystem Volumes (共享文件系统卷),及基于 S3 协议的对象存储。

存储卷(Storage Volumes)

用户可申请使用两种类型的存储卷(Storage Volumes):块存储卷,或者共享文件系统卷

这两种高性能的网络存储卷服务,可为各种类型的工作负载,如 Notebook、T9k Jobs、推理服务等提供持久化存储卷(Persistent Volumes)服务。

  • 支持在集群中使用不同性能等级的存储服务。例如,管理员可设置集群同时提供高性能的 SSD 和海量的 HDD 两种等级的存储服务;
  • 所有 SSD 和 HDD 等级均可创建为 Block Volumes(块存储卷)或 Shared Filesystem Volumes (共享文件系统存储卷);
  • 可随时调整 Volume 大小以增加容量;
  • 存储与计算分开管理,并且可以在不同实例和硬件类型之间移动;
  • 支持存储卷的快照、备份及恢复。
  • 可通过 UI 或 命令行工具 kubectl 轻松管理;

块存储卷(Block Storage Volumes)

Block Storage Volumes (块存储卷)可作为高性能虚拟存储盘挂载到各种类型的工作负载上。这些卷被呈现为通用 Block Device (块设备),操作系统将其视为物理连接存储设备,并且独占使用。

如果集群部署了高性能的 NVMe 的存储节点,并使用了足够快的网络,这种类型的存储卷的性能将会超过本地 SATA 接口的 SSD,并且可以扩展到 PB 级别容量。

共享文件系统卷(Shared Filesystem Volumes)

遵守 POSIX 标准的 Filesystem Volumes(文件系统卷)可以挂载到各种工作负载上,以提供原生共享文件系统。

同时,这些卷可以同时附加到多个工作负载实例上,非常适合作在 Notebook、大规模并行计算 Job、推理服务等场景的存储卷。

对象存储

平台提供基于 S3 协议的对象存储服务,支持方便、通用的数据共享机制及低成本的数据归档服务。

使用

TensorStack 的存储卷(Storage Volumes)系统支持建立在 Kubernetes 的 Storage API 基础之上,通过 API Persistent VolumesStorage Class 等提供用户接口。

同时,为了支持一些特定场景的使用,TensorStack 提供 CRD StorageShimExplorer 以提供扩展支持。

例 1:获得集群中的存储类型:

$ kubectl get sc

例 2:创建存储请求:

# 使用 StorageClass `generic-hdd` 的 Filesystem Volumes (文件系统卷)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-example
spec:
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 100Gi
  storageClassName: generic-hdd
  volumeMode: Filesystem

CRD 资源

存储系统中普通用户相关的 CRD 资源,列表如下:

来源说明
PVCKubernetes动态申请集群持久存储;用户可日常创建此 Resource 以申请存储资源
Storage ClassKubernetes指明存储的类别;管理员创建,用户创建 PVC 时引用
StorageShimTensorStack对各种存储系统的便捷支持,为用户自动创建 PVC;用户可日常创建此 Resource
ExplorerTensorStack文件浏览器,查看和管理 PVC 中的文件

参考

PVC(持久卷)

PVC 是一种 Kubernetes 原生资源,是对存储的需求声明,它抽象了底层存储细节,允许用户请求特定大小和访问模式的存储,而不必关心存储的具体实现。

创建 PVC

下面是一个基本的 PVC 配置示例:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-demo
spec:
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
  storageClassName: cephfs-hdd

在该例中:

  • spec.resources.requests.storage 字段定义了所申请的存储空间容量大小为 1Gi
  • spec.accessModes 字段定义了访问模式为 ReadWriteMany,表示该 PVC 能够同时被多个节点上的 Pod 使用。
  • spec.storageClassName 字段定义了所使用的存储类名称为 cephfs-hdd,集群中可用的存储类由管理员提供。

使用 PVC

下面是在 Pod 中使用 PVC 的示例:

apiVersion: v1
kind: Pod
metadata:
  name: pod-demo
spec:
  containers:
  - name: myfrontend
    image: nginx
    volumeMounts:
    - mountPath: "/var/www/html"
      name: data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: pvc-demo

在该例中,pod-demopvc-demo 作为一个数据卷(volume)来使用,其中容器 myfrontend 将该数据卷挂载到 /var/www/html 目录下。

在 TensorStack AI 平台中,PVC 是通用的持久化存储资源,你在 NotebookJobMLServiceWorkflow 等 TensorStack 资源中都可以使用 PVC。以 Notebook 为例:

apiVersion: tensorstack.dev/v1beta1
kind: Notebook
metadata:
  name: notebook-demo
spec:
  type: jupyter
  template:
    spec:
      containers:
      - image: t9kpublic/torch-2.0.0-notebook:1.72.0
        name: notebook
        resources:
          limits:
            cpu: "4"
            memory: 4Gi
          requests:
            cpu: "0.5"
            memory: 500Mi
        volumeMounts:
        - name: workingdir
          mountPath: /t9k/mnt
      volumes:
      - name: workingdir
        persistentVolumeClaim:
          claimName: pvc-demo

在该例中,notebook-demopvc-demo 作为一个数据卷(volume)来使用,其中容器 notebook 将该数据卷挂载到 /t9k/mnt 目录下。

生命周期

PVC 有以下几种状态:

  • Pending:PVC 正在由对应的存储类处理。
  • Bound:PVC 创建成功,可以被使用。
  • Unknown:无法获取 PVC 状态。

PVC 与 Pod

PVC 的生命周期独立于 Pod。一个 PVC 可以被多个 Pod 使用。当 PVC 正在被 Pod 使用时,它无法被删除。

PVC 与 StorageShim

在 TensorStack AI 平台中,你可以:

  1. 创建一个独立的 PVC,申请全新的存储空间。
  2. 创建一个 StorageShim,将已有存储系统的某个子目录挂载为一个 PVC。此时 StorageShim 控制器将为所创建的 StorageShim 创建一个同名的 PVC,此 PVC 的生命周期由 StorageShim 管理。

容量请求

创建 PVC 时,spec.resources.requests.storage 字段用于指定 PVC 的容量,你无法在 PVC 中存储超过此容量限制的文件。

访问模式

创建 PVC 时,spec.accessModes 字段用于指定 PVC 的访问模式,可选择以下几种访问模式:

  • ReadWriteMany:PVC 能被多个节点上的 Pod 读写。
  • ReadWriteOnce:PVC 只能被一个节点上的 Pod 读写。
  • ReadOnlyMany:PVC 只能被多个节点上的 Pod 读。

一般选择 ReadWriteMany 即可。

存储类

创建 PVC 时,spec.storageClassName 字段用于指定 PVC 的存储类,集群中可用的存储类由管理员提供。

例如,一个集群可能提供两个存储类,名为 cephfs-hddcephfs-ssd,分别提供基于 HDD 机械硬盘和 SSD 固态硬盘的存储空间,用于不同的数据存储目的。

下一步

PVC 快照

如果 PVC 存放了重要的数据,用户可适时制作快照(snapshot),以方便恢复。

CRD 资源

存储系统中与快照相关的 CRD 资源,列表如下:

来源说明
PVCKubernetes动态申请集群持久存储;用户可日常创建此 Resource 以申请存储资源
Volume SnapshotKubernetes针对某一个 PVC 进行快照;用户可日常创建此 Resource
Volume Snapshot ClassKubernetes指明快照的类别,与 StorageClass 一一对应;管理员创建,用户创建 Volume Snapshot 时引用

创建快照

下面是一个基本的 PVC 配置示例:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-demo
spec:
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
  storageClassName: cephfs-hdd

为了对该 PVC 进行快照,用户需要创建如下 VolumeSnapshot 资源:

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: pvc-demo-snapshot
spec:
  volumeSnapshotClassName: cephfs-hdd-snapshotclass
  source:
    persistentVolumeClaimName: pvc-demo

其中:

  • spec.volumeSnapshotClassName 定义了所使用的快照类为 cephfs-hdd-snapshotclass,每个 StorageClass 都有对应的 VolumeSnapshotClass,由管理员负责创建;VolumeSnapshot 指定的 spec.volumeSnapshotClassName 应当与 PVC 的 spec.storageClassName 对应。
  • spec.source.persistentVolumeClaimName 定义了所要快照的 PVC 名称为 pvc-demo

创建完成后,用户可以对 PVC 中的数据进行继续修改;若需要放弃修改,则可方便地使用快照恢复到修改前的数据。

从快照中恢复

如果想将 PVC 中的数据恢复至快照创建时刻的状态,用户需要创建一个新的 PVC(之前的 PVC 仍然可以使用,两个 PVC 之间互不影响):

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-demo-restore
spec:
  accessModes:
  - ReadWriteMany
  dataSource:
    name: pvc-demo-snapshot
    kind: VolumeSnapshot
    apiGroup: snapshot.storage.k8s.io
  resources:
    requests:
      storage: 1Gi
  storageClassName: cephfs-hdd

其中:

  • spec.accessModes 必须与原 PVC 一致。
  • spec.dataSource 引用了所要恢复的名为 pvc-demo-snapshot 的快照,本 PVC 中的数据将与该快照中的数据完全一致。
  • spec.resources.requests.storage 必须与原 PVC 一致。
  • spec.storageClassName 必须与原 PVC 一致。

下一步

StorageShim

StorageShim 用于将已有的存储系统以 PVC 的形式提供给用户使用,例如 S3 bucket 的某个子路径可以作为一个 PVC,分布式文件系统的某个子目录可以作为一个 PVC。通过 StorageShim,用户能够方便地访问已经上传到各类存储系统中的数据,而无需进行复制。目前支持的存储系统包括 S3CephFS,未来可能支持更多的存储系统类型。

创建 StorageShim

S3 类型

下面是一个 S3 类型的 StorageShim 配置示例:

apiVersion: tensorstack.dev/v1beta1
kind: StorageShim
metadata:
  name: storageshim-s3-demo
spec:
  type: s3
  s3:
    uri: "s3://bucket/path/subpath"
    readOnly: false
    secretRef:
      name: s3-secret-demo

其中所引用的 Secret s3-secret-demo 配置如下:

apiVersion: v1
kind: Secret
metadata:
  name: s3-secret-demo
  labels:
    tensorstack.dev/resource: s3-cfg
stringData:
  .s3cfg: <s3cfg>

在该例中,StorageShim storageshim-s3-demo 被创建后,StorageShim 控制器将创建一个同名的 PVC storageshim-s3-demo,该 PVC 的根目录对应 S3 路径 s3://bucket/path/subpath,访问该 S3 路径的登录凭证存储在 Secret s3-secret-demo 中,该 Secret 必须为 S3-cfg 类型

CephFS 类型

下面是一个 CephFS 类型的 StorageShim 配置示例:

apiVersion: tensorstack.dev/v1beta2
kind: StorageShim
metadata:
  name: storageshim-cephfs-demo
spec:
  type: cephfs
  cephfs:
    path: /cephfs/data/user/mydata
    client:
      secretRef:
        name: ceph-client-key-demo
    server:
      configMapRef:
        name: ceph-cluster-config-demo

其中所引用的 Secret ceph-client-key-demo 配置示例如下:

apiVersion: v1
kind: Secret
metadata:
  name: ceph-client-key-demo
  labels:
    tensorstack.dev/resource: ceph-client
stringData:
  userID: <user-id>
  userKey: <user-key>

其中所引用的 ConfigMap ceph-cluster-config-demo 配置示例如下:

apiVersion: v1
kind: ConfigMap
metadata:
  name: ceph-cluster-config-demo
  labels:
    tensorstack.dev/resource: ceph-cluster
data:
  driver: <driver-name>
  clusterID: <cluster-id>
  fsName: <fs-name>

在该例中,StorageShim storageshim-cephfs-demo 被创建后,StorageShim 控制器将创建一个同名的 PVC storageshim-cephfs-demo,该 PVC 的根目录对应 CephFS 文件系统的子目录 /cephfs/data/user/mydata,访问该子目录的登录凭证存储在 Secret ceph-client-key-demo 中,该 Secret 必须为 S3-cfg 类型,该 CephFS 文件系统的相关信息存储在 ConfigMap ceph-cluster-config-demo 中。

下一步

Explorer

Explorer 提供几种展示和管理集群中数据的方法。

创建 Explorer

下面是一个基本的 Explorer 配置示例:

apiVersion: tensorstack.dev/v1beta1
kind: Explorer
metadata:
  name: example
spec:
  storageName: test
  storageType: pvc

在该例中,Explorer 展示和管理名为 test 的持久卷(Persistent Volume)中的数据。

存储方式

Explorer 目前仅支持展示存储在 PVC 中的文件(即 spec.storageType 字段暂时只能设置为 pvc)。

展示和管理方式

Explorer 会自动以多种方式展示和管理文件,目前支持文件浏览器和代码编辑器两种。

文件浏览器

使用第三方软件 File Browser 提供文件管理器形式的界面,支持文件系统浏览、文件上传、文件下载、基本的文件编辑等功能。

代码编辑器

使用第三方软件 VS Code 提供云端集成开发环境(IDE)的支持。开发者可以方便地运行网页版 VS Code,进行远程项目开发。

资源回收

Explorer 提供空闲资源回收的支持,在检测到 Explorer 处于空闲状态并超过一定时长时,删除工作负载以释放计算资源。默认情况下(管理员可修改配置):

  • Explorer 无人使用超过 1h 后,标记该 Explorer 为 Idle
  • Explorer 进入 Idle 状态超过 24h 后,删除该 Explorer 底层工作负载。

如果需要再次使用该 Explorer,你可以在模型构建控制台中手动点击恢复按钮。

下一步

辅助

TensorStack AI 平台提供了一些辅助性资源,它们为其他资源提供支持,或者为用户提供便捷、实用的功能。下表总结了所有辅助性资源:

资源来源作用
SecretKubernetes存储敏感信息并用于配置
ConfigMapKubernetes存储非敏感信息并用于配置
PodKubernetes运行容器,测试镜像和应用程序
ImageBuilderTensorStack构建自定义镜像

Secret

Secret 是一种 Kubernetes 原生资源,用于存储少量敏感信息,比如密码、OAuth 令牌、SSH 密钥等。使用 Secret 可以避免将敏感数据直接写入到 Pod 的定义中或者应用程序代码里,从而提高了安全性。

创建 Secret

下面是一个基本的 Secret 配置示例:

apiVersion: v1
kind: Secret
metadata:
  name: secret-demo
type: Opaque
data:
  key1: dmFsdWUxCg==
  key2: dmFsdWUyCg==

在该例中,secret-demo 存储了两对键值对,其中值经过了 base64 编码。

使用 Secret

PVC 类似,Secret 可以以同样的方式作为数据卷被 Pod、Notebook、Job 等资源挂载。以 PyTorchTrainingJob 为例:

apiVersion: batch.tensorstack.dev/v1beta1
kind: PyTorchTrainingJob
metadata:
  name: pytorchtrainingjob-demo
spec:
  replicaSpecs:
    - type: worker
      replicas: 1
      restartPolicy: OnFailure
      template:
        spec:
          containers:
            - image: pytorch/pytorch:2.0.0-cuda11.7-cudnn8-devel
              name: pytorch
              command:
                - python
                - dist_mnist.py
              resources:
                limits:
                  cpu: '1'
                  memory: 1Gi
                requests:
                  cpu: 500m
                  memory: 500Mi
              volumeMounts:
                - name: data
                  mountPath: /data
                - name: secret
                  mountPath: /secret
          volumes:
            - name: data
              persistentVolumeClaim:
                claimName: pvc-demo
            - name: secret
              secret:
                name: secret-demo

在该例中,pytorchtrainingjob-demopvc-demosecret-demo 均作为数据卷(volume)来使用,其中容器 pytorch 将两个数据卷分别挂载到 /data/secret 目录下。因此,容器 pytorch/secret 目录下将存在两个文件 /secret/key1/secret/key2,文件内容是经过 base64 解码后的对应的值。

Secret 用途

TensorStack AI 平台通过 label tensorstack.dev/resource 来标识 Secret 的用途,主要有以下几种:

  • API Key:拥有 label tensorstack.dev/resource: apikey,用于存放 API Key,可在安全管理控制台创建 API Key。
  • S3-cfg:拥有 label tensorstack.dev/resource: s3-cfg,用于存放 S3 配置文件的内容,可从本地的 $HOME/.s3cfg 文件中获取。
  • S3-env:拥有 label tensorstack.dev/resource: s3-env,用于存放 S3 配置文件的每个字段,请从本地的 $HOME/.s3cfg 文件中获取。
  • Docker:拥有 label tensorstack.dev/resource: docker,用于存放 Docker 配置文件的内容,可从本地的 $HOME/.docker/config.json 文件中获取。
  • SSH Public Key:拥有 label tensorstack.dev/resource: ssh,用于存放 SSH 公钥,可从本地的 $HOME/.ssh/id_rsa.pub 文件中获取。
  • Ceph Client:拥有 label tensorstack.dev/resource: ceph-client,用于存放 Ceph 客户端配置,可从管理员处获取。
  • Custom:拥有 label tensorstack.dev/resource: other,自定义用途。

例如:

下一步

ConfigMap

ConfigMap 是一种 Kubernetes 原生资源,用于存储非机密性配置信息,它可以用来保存配置文件、命令行参数和环境变量等数据。ConfigMap使得容器化应用程序的配置与镜像内容分离,从而提高了应用的可移植性和灵活性。

创建 ConfigMap

下面是一个基本的 ConfigMap 配置示例:

apiVersion: v1
kind: ConfigMap
metadata:
  name: configmap-demo
data:
  key1: value1
  key2: value2

在该例中,configmap-demo 明文存储了两对键值对。

使用 ConfigMap

PVC 类似,ConfigMap 可以以同样的方式作为数据卷被 Pod、Notebook、Job 等资源挂载。以 PyTorchTrainingJob 为例:

apiVersion: batch.tensorstack.dev/v1beta1
kind: PyTorchTrainingJob
metadata:
  name: pytorchtrainingjob-demo
spec:
  replicaSpecs:
    - type: worker
      replicas: 1
      restartPolicy: OnFailure
      template:
        spec:
          containers:
            - image: pytorch/pytorch:2.0.0-cuda11.7-cudnn8-devel
              name: pytorch
              command:
                - python
                - dist_mnist.py
              resources:
                limits:
                  cpu: '1'
                  memory: 1Gi
                requests:
                  cpu: 500m
                  memory: 500Mi
              volumeMounts:
                - name: data
                  mountPath: /data
                - name: configuration
                  mountPath: /config
          volumes:
            - name: data
              persistentVolumeClaim:
                claimName: pvc-demo
            - name: configuration
              configMap:
                name: configmap-demo

在该例中,pytorchtrainingjob-demopvc-democonfigmap-demo 均作为数据卷(volume)来使用,其中容器 pytorch 将两个数据卷分别挂载到 /data/config 目录下。因此,容器 pytorch/config 目录下将存在两个文件 /config/key1/config/key2,文件内容分别是 value1value2

下一步

Pod

Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。

Pod 是一组(一个或多个)容器;这些容器共享存储、网络、以及怎样运行这些容器的声明。Pod 中的内容总是并置的并且一同调度,在共享的上下文中运行。Pod 模拟一个特定应用的“逻辑主机”,其中包含一个或多个应用容器,这些容器相对紧密地耦合在一起。在非云环境中,在相同的物理机或虚拟机上运行的应用类似于在同一逻辑主机上运行的云应用。

除了应用容器,Pod 还可以包含在 Pod 启动期间运行的 Init 容器。你也可以在集群支持临时性容器的情况下,为调试的目的注入临时性容器

通常你不需要直接创建 Pod,甚至单实例 Pod。你会使用诸如 Deployment 或 Job 这类工作负载资源来创建 Pod。如果 Pod 需要跟踪状态,可以考虑 StatefulSet 资源。

Kubernetes 集群中的 Pod 主要有两种用法:

  • 运行单个容器的 Pod:最常见的 Kubernetes 用例; 在这种情况下,可以将 Pod 看作单个容器的包装器,并且 Kubernetes 直接管理 Pod,而不是容器。
  • 运行多个协同工作的容器的 Pod:Pod 可能封装由多个紧密耦合且需要共享资源的共处容器组成的应用程序。这些位于同一位置的容器可能形成单个内聚的服务单元 —— 一个容器将文件从共享卷提供给公众,而另一个单独的 sidecar 容器则刷新或更新这些文件。Pod 将这些容器和存储资源打包为一个可管理的实体。

每个 Pod 都旨在运行给定应用程序的单个实例。如果希望横向扩展应用程序(例如,运行多个实例以提供更多的资源),则应该每个实例使用一个 Pod。在 Kubernetes 中,这通常被称为副本。通常使用一种工作负载资源及其控制器来创建和管理一组 Pod 副本。

Pod 示例

以下是一个 Pod 的 YAML 示例:

apiVersion: v1
kind: Pod
metadata:
  name: test-sdk
spec:
  containers:
    - name: sdk
      image: t9kpublic/t9k-sdk:0.6.0-torch-2.0.1
      command:
        - sleep
        - inf
      resources:
        limits:
          cpu: 500m
          memory: 200Mi

在上述示例中:

  • Pod 使用 t9kpublic/t9k-sdk:0.6.0-torch-2.0.1(由 spec.containers[0].image 字段指定)镜像启动容器 sdk(由 spec.containers[0].name 字段指定)。
  • 容器中执行 sleep inf(由 spec.containers[0].command 字段指定)命令。
  • sdk 容器最多可使用 0.5 个 CPU 和 200Mi 内存(由 spec.containers[0].resources.limits 字段指定)。

应用场景

在 TensorStack AI 平台,你可以使用 Pod 实现以下操作:

  • 测试镜像:在你使用 ImageBuilder 构建镜像后,可通过创建 Pod 并进入 Pod 终端来验证镜像是否符合预期。
  • 存储卷预处理:在训练前,需提前下载好数据,此时可以通过创建 Pod 绑定对应 PVC,在 Pod 终端向其中下载数据。
  • 测试代码:你在 Notebook 中开发后的脚本在训练镜像中并不一定能正常运行,可以用训练镜像创建一个 Pod,来测试训练脚本在新镜像中是否可用。

下一步

ImageBuilder

TensorStack 平台提供 CRD ImageBuilder,方便用户在集群中构建容器镜像。

创建 ImageBuilder

下面是一个基本的 ImageBuilder 定义示例:

# image-builder-example.yaml
apiVersion: tensorstack.dev/v1beta1
kind: ImageBuilder
metadata:
  name: imagebuilder-example
spec:
  dockerConfig:
    secret: docker-config
  tag: t9kpublic/kaniko-executor:v1.19.2
  workspace:
    pvc:
      name: kaniko
      dockerfilePath: ./Dockerfile
      contextPath: "."
  builder:
    kaniko: {}

在该例中:

  • spec.dockerConfig.secret 字段指定使用 Secret docker-config 中记录的 docker 配置,以上传镜像。
  • spec.tag 字段指定目标镜像的名称和标签为 t9kpublic/kaniko-executor:v1.19.2
  • spec.workspace 字段指定构建镜像使用 PVC kaniko 作为工作空间,其中:
    • 在 PVC 相对路径 ./Dockerfile 中存放构建镜像所需的 Dockerfile。
    • 在 PVC 相对路径 . 中存放构建镜像所需要的上下文。
  • spec.builder 字段指定使用 kaniko 来构建镜像。

构建工具

目前 ImageBuilder 支持使用 kaniko 工具来构建镜像。

kaniko

用户可以通过 spec.builder.kaniko 字段来设置 kaniko 的参数。

在下面示例中,ImageBuilder 使用 t9kpublic/kaniko-executor:v1.19.2 启动 kaniko,并在该容器中构建用户镜像;ImageBuilder 不额外设置 kaniko 参数。

spec:
  builder:
    kaniko:
      image: t9kpublic/kaniko-executor:v1.19.2
      args: []

spec.builder.kaniko 的参数介绍:

  • image:如忽略,ImageBuilder 控制器会指定一个默认镜像,所以一般来说可以不设置该字段。
  • args:如忽略,ImageBuilder 构建镜像时执行 kaniko --destination=[image-tag] --context=[context-path] --dockerfile=[dockerfile-path] 命令。如果用户需要使用其他参数,可以在该字段中指定。参考 kaniko additional flags

参考

更加详细的 ImageBuilder API 可直接在集群中查询:

kubectl explain imagebuilder

下一步

工作流

AI 应用由很多基础计算步骤构成,具有很大灵活性,在不同场景需要做各种定制计算处理。例如,一个模型训练过程可能包含数据取样、数据转换、模型训练、模型质检、模型导出等步骤。

为此 TensorStack AI 平台提供了一个灵活的工作流服务,将这些计算步骤组合在一起,集中进行管理和调度,自动化复杂的流程。

架构

工作流模块提供了 WorkflowTemplateWorkflowRunCronWorkflowRun 等自定义扩展资源,以及控制台、服务器、操作器等组件。整体架构如下图所示:

architecture

其中:

  • 控制台(Console)提供前端界面,方便用户对 WorkflowTemplate、WorkflowRun 等资源进行创建、查看、删除等操作。
    • 用户也可以直接使用命令行工具 kubectl 创建 workflow 的资源。
  • 服务器(Server)向工作流控制台提供 API 接口,帮助获取 WorkflowTemplate、WorkflowRun 等资源的详细信息。
  • 控制器(Controller),负责监控集群中的 WorkflowTemplate、WorkflowRun 等资源,并执行一些与资源相关的操作,使资源当前的状态与其理想状态一致。

与其他模块的关系

如下图所示,Workflow 可以将分布式并行作业、非并行作业组合在一起成为复合作业,而且复合作业中可以嵌套复合作业,并通过 T9k 调度器进行计算资源的匹配,最终完成复杂的多步骤计算。

workflow-and-jobs

WorkflowTemplate

WorkflowTemplate 用于在 Kubernetes 中有序、高效、方便地组织运行各类工作负载,例如机器学习流水线中的数据处理、模型训练、推理测试等具有依赖关系的多个步骤。WorkflowTemplate 是一个静态模板,指定了任务的详细规范,最终由 WorkflowRun 实例化并真正开始运行。

创建 WorkflowTemplate

下面的 WorkflowTemplate 示例创建并运行一个 Kubernetes Pod

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: workflowtemplate-sample
spec:
  description: This WorkflowTemplate creates and runs a Pod.
  type: Pod
  pod:
    containers:
      - name: hello
        image: ubuntu:latest
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
        command: ["echo"]
        args: ["Hello TensorStack!"]

在该例中:

  • description 字段简要介绍了该 WorkflowTemplate 的用途,会在控制台中展示。
  • WorkflowTemplate 的类型(由 type 字段指定)是 Pod,表示 WorkflowTemplate 会创建并运行一个 Pod。
  • pod 字段定义所要创建的 Pod 的规约,指示 Pod 运行一个 hello 容器,该容器运行镜像 ubuntu:latest 并打印一个字符串 Hello TensorStack!

WorkflowTemplate 类型

WorkflowTemplate 的 spec.type 字段用于指定 WorkflowTemplate 的类型,可能的取值有:

Pod WorkflowTemplate

Pod WorkflowTemplate 用于创建一个原生的 Kubernetes Pod。

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: pod-workflowtemplate-sample
spec:
  type: Pod
  pod:
    containers:
      - name: hello
        image: ubuntu
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
        command: ["sh", "-c"]
        args: ["echo Hello World!"]

spec.pod 中可以填写的字段与 Kubernetes Pod 相同。

SeqPod WorkflowTemplate

SeqPod WorkflowTemplate 用于创建一个经过包装的 Pod,在 Pod 中按顺序执行一些步骤。

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: seqpod-workflowtemplate-sample
spec:
  type: SeqPod
  seqPod:
    steps:
      - name: hello
        image: ubuntu
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
        command: ["sh", "-c"]
        args: ["echo Hello World!"]
      - name: working
        image: ubuntu
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
        command: ["sh", "-c"]
        args: ["echo I am working!"]
      - name: bye
        image: ubuntu
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
        command: ["sh", "-c"]
        args: ["echo Goodbye!"]

SeqPod 中的每个步骤(step)对应 Kubernetes Pod 中的一个容器,但 SeqPod 会按照顺序依次执行每个步骤,直到所有的步骤成功运行完毕,或者其中某个步骤失败(后续的步骤不会再运行)。

pod.containers[*].commandpod.containers[*].argsseqPod.steps[*].commandseqPod.steps[*].args 等字段中,你有时候可能需要填写带有引号的字符串,有以下几种合法的方式:

command: ["echo"]
args: ["this is a 'quote'"]
command: ['echo']
args: ['this is a "quote"']
command:
  - echo
args:
  - this is a "quote"
command:
  - echo
args:
  - this is a 'quote'

指定 script

SeqPod 的每个步骤可以指定 script 字段,即一段脚本语言(例如 Bash、Python)编写的代码,用于代替 command 字段。script 脚本会在容器开始运行时代替 command 被调用,而 args 会被当做参数传递给 script 脚本。

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: seqpod-workflowtemplate-sample-script
spec:
  type: SeqPod
  seqPod:
    steps:
      - name: hello
        image: python
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
        script: |
          #!/usr/bin/env python3
          print("Hello from Python!")

如果 script 脚本的开头不包含以 #! 开头的字符串(shebang),以下字符串会被自动添加到 script 脚本的开头:

#!/bin/bash
set -e # Immediately exit if any command exited with non-zero status. 

保留目录

为了 SeqPod WorkflowTemplate 的正常工作,最终生成的 Pod 有一些特殊的保留目录:

  • /t9k/workspaces:用于挂载 workspaces,你可以通过 $(workspaces.<workspaceName>.path) 来使用该路径。
  • /t9k/results:用于存储 results,你可以通过 $(results.<resultName>.path) 来使用该路径。
  • /t9k/tools:用于保证 SeqPod 中 steps 顺序执行的辅助工具,与用户无关。
  • /t9k/termination:用于写入 Pod 的 termination message,与用户无关。

Resource WorkflowTemplate

Resource WorkflowTemplate 用于创建另一个 Kubernetes 资源,并监测该资源的运行状态。

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: resource-workflowtemplate-sample
spec:
  type: Resource
  resource:
    manifest: |
      apiVersion: batch/v1
      kind: Job
      metadata:
        generateName: pi-job-
      spec:
        template:
          metadata:
            name: pi
          spec:
            containers:
            - name: pi
              image: perl
              command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
            restartPolicy: Never
        backoffLimit: 4
    successRules:
      fieldSelector: status.succeeded > 0
    failureRules:
      fieldSelector: status.failed > 3

spec.resource 的各个字段含义如下:

  • manifest:所要创建的 Kubernetes 资源的详细配置。
  • successRules:如果所创建的资源满足该条件,本 WorkflowTemplate 视为成功。
  • failureRules:如果所创建的资源满足该条件,本 WorkflowTemplate 视为失败。

fieldSelector 的写法与 Kubernetes 标签选择器的语法相同但更强大,除了标签之外还能应用到资源的任意字段,支持的运算符有 ><==!=innotin 等,多个需要同时满足的条件可以用逗号连接。例如,以下都是合法的 fieldSelector

  • status.succeeded>0
  • status.succeeded > 0
  • status.succeeded > 0,status.failed == 0
  • status.phase in (Succeeded, Failed),status.workflowTemplateSpec.type == DAG

另外,successRulesfailureRules 还支持设置 conditionSelector。如果所创建的资源的 status.conditions 字段包含一个 condition,其 typestatus 都与 conditionSelector 相同,就认为该资源满足条件。

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: resource-workflowtemplate-sample-condition
spec:
  type: Resource
  resource:
    manifest: |
      apiVersion: batch.tensorstack.dev
      kind: TensorFlowTrainingJob
      metadata:
        generateName: t9k-training-job-
      spec:
        ...
    successRules:
      conditionSelector:
        type: Succeeded
        status: "True"
    failureRules:
      conditionSelector:
        type: Failed
        status: "True"

如果所创建的资源类型是下列 T9k Jobs 之一,系统将自动帮助填写 successRulesfailureRules,以减轻你的负担:

  • GenericJob
  • MPIJob
  • BeamJob
  • TensorFlowTrainingJob
  • PyTorchTrainingJob
  • XGBoostTrainingJob

创建 Resource WorkflowTemplate 对应的 WorkflowRun 时需要提供一个 Service Account,使得 WorkflowRun 具有在 Kubernetes 中创建该 Resource 的权限。例如:

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowRun
metadata:
  name: resource-workflowtemplate-sample-run
spec:
  workflowTemplateRef: resource-workflowtemplate-sample
  serviceAccountName: managed-project-sa

在网页中创建 WorkflowRun 时,系统将自动为你配置名为 managed-project-sa 的 Service Account,你不用关心这一项的填写。

T9k Jobs WorkflowTemplate

T9k Workflow 系统对 T9k Jobs 提供更进一步的原生支持,添加以下 WorkflowTemplate 类型:

  • GenericJob
  • TensorFlowTrainingJob
  • PyTorchTrainingJob
  • XGBoostTrainingJob
  • ColossalAIJob
  • DeepSpeedJob
  • MPIJob
  • BeamJob

并在 WorkflowTemplate 的 spec 中添加了相应字段用于填写 T9k Job 的 spec

  • spec.genericJob
  • spec.tensorflowTrainingJob
  • spec.pytorchTrainingJob
  • spec.xgboostTrainingJob
  • spec.colossalaiJob
  • spec.deepspeedJob
  • spec.mpiJob
  • spec.beamJob

相比于在 Resource 类型中将资源的 spec 视作一个很长的字符串,添加原生类型支持的好处是在创建 WorkflowTemplate 时 T9k Job 的 spec 就会得到语法检查,能更早地发现错误,加深了 T9k Workflow 系统和 T9k Job 系统的集成配合。

例如,创建一个 MPIJob 可以使用如下格式(其中 MPIJob 示例来自 MPIJob 文档):

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: mpijob-workflowtemplate-sample
spec:
  type: MPIJob
  mpiJob:
    spec:
      worker:
        replicas: 5
        processesPerWorker: 3
        processRecovery:
          enable: true
          limit: 100
        cmd:
          - ./random_walk
          - "20"
          - "40"
          - "2"
        template:
          spec:
            containers:
              - name: mpi-worker
                image: t9kpublic/mpi-tutorial:2021022-2
                resources:
                  limits:
                    cpu: 100m
                  requests:
                    cpu: 50m
                workingDir: /usr/local/code
      mca:
        btl: ^openib
      runPolicy:
        cleanUpWorkers: true
      ssh:
        sshdPath: /usr/sbin/sshd
      mpiHome: /usr/local

DAG WorkflowTemplate

DAG WorkflowTemplate 用于创建一个由其他 WorkflowTemplate 组成的有向无环图(DAG,Directed Acyclic Graph),按照有向无环图中的依赖关系按顺序执行这些 WorkflowTemplate。

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: dag-workflowtemplate-sample
spec:
  type: DAG
  dag:
    templates:
      - name: a
        workflowTemplateRef: pod-workflowtemplate-sample
        dependencies: []
      - name: b1
        workflowTemplateRef: pod-workflowtemplate-sample
        dependencies: ["a"]
      - name: b2
        workflowTemplateRef: pod-workflowtemplate-sample
        dependencies: ["a"]
      - name: c
        workflowTemplateRef: pod-workflowtemplate-sample
        dependencies: ["b1", "b2"]

在上面的示例中,首先运行 WorkflowTemplate a,等待 WorkflowTemplate a 运行完毕之后再同时运行 WorkflowTemplate b1 和 b2。WorkflowTemplate c 会在 b1 和 b2 都结束后运行。这些 WorkflowTemplates 组成一个从上往下顺序执行的有向无环图:

   a
 /   \
b1   b2
 \   /
   c

指定参数

你可以为 WorkflowTemplate 指定一些参数,并在 spec 中用 $(params.<paramName>) 来引用参数。WorkflowRun 会在运行时为这些参数提供实际值。支持 params 的 WorkflowTemplate 类型有 Pod、SeqPod、DAG,详见支持变量替换的 WorkflowTemplate 字段

Pod WorkflowTemplate 示例:

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: pod-workflowtemplate-sample-params
spec:
  params:
    - name: message
      default: "hi"
  type: Pod
  pod:
    containers:
      - name: hello
        image: ubuntu
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
        command: ["sh", "-c"]
        args: ["echo $(params.message)"]

SeqPod WorkflowTemplate 示例:

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: seqpod-workflowtemplate-sample-params
spec:
  params:
    - name: message
      default: hi
  type: SeqPod
  seqPod:
    steps:
      - name: hello
        image: ubuntu
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
        script: |
          #!/bin/sh
          echo $(params.message)

DAG WorkflowTemplate 在引用其他的 WorkflowTemplate 作为节点时,必须提供该节点需要的 params,可以是静态的字符串,也可以引用 DAG WorkflowTemplate 自身的 params 变量或其他变量。示例:

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: dag-workflowtemplate-sample-params
spec:
  params:
    - name: dag-param
  type: DAG
  dag:
    templates:
      - name: step0
        workflowTemplateRef: pod-workflowtemplate-sample-params
        dependencies: []
        params:
          - name: message
            value: Hello World!
      - name: step1
        workflowTemplateRef: seqpod-workflowtemplate-sample-params
        dependencies: ["step0"]
        params:
          - name: message
            value: "$(params.dag-param)"
      - name: step2
        workflowTemplateRef: seqpod-workflowtemplate-sample-params
        dependencies: ["step1"]
        params:
          - name: message
            value: "DAG WorkflowTemplate provides param $(params.dag-param) for you"

指定工作空间

你可以为 WorkflowTemplate 指定可用的存储空间,并在 spec 中用 $(workspaces.<workspaceName>.path) 来引用存储空间的路径。WorkflowRun 会在运行时指定具体挂载何种存储空间,例如 PVC、Secret、ConfigMap 等。支持 workspaces 的 WorkflowTemplate 类型有 Pod、SeqPod、DAG。

Pod WorkflowTemplate 示例:

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: pod-workflowtemplate-sample-workspace
spec:
  workspaces:
    - name: pod-workspace
  type: Pod
  pod:
    containers:
      - name: hello
        image: ubuntu
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
        command: ["sh", "-c"]
        args: ["echo Hello World! > $(workspaces.pod-workspace.path)/output.txt"]

SeqPod WorkflowTemplate 示例:

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: seqpod-workflowtemplate-sample-workspaces
spec:
  workspaces:
    - name: seqpod-workspace
  type: SeqPod
  seqPod:
    steps:
      - name: hello
        image: ubuntu
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
        script: |
          #!/bin/sh
          echo Hello World! > $(workspaces.seqpod-workspace.path)/output.txt

DAG WorkflowTemplate 在引用其他的 WorkflowTemplate 作为节点时,必须提供该节点需要的 workspaces,一般通过 DAG WorkflowTemplate 自身的 workspaces 继承而来。示例:

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: dag-workflowtemplate-sample-workspaces
spec:
  workspaces:
    - name: dag-workspace
  type: DAG
  dag:
    templates:
      - name: step0
        workflowTemplateRef: pod-workflowtemplate-sample-workspace
        dependencies: []
        workspaces:
          - name: pod-workspace
            workspace: dag-workspace
      - name: step1
        workflowTemplateRef: seqpod-workflowtemplate-sample-workspace
        dependencies: ["step0"]
        workspaces:
          - name: seqpod-workspace
            workspace: dag-workspace
      - name: step2
        workflowTemplateRef: seqpod-workflowtemplate-sample-workspace
        dependencies: ["step1"]
        workspaces:
          - name: seqpod-workspace
            workspace: dag-workspace

输出结果

WorkflowTemplate 可以在运行过程中输出一些字符串,并最终展示在 WorkflowRun 的 status 中。支持 results 的 WorkflowTemplate 类型有 SeqPod、DAG。

每个 result 本质上是一个文件,如下例所示,你可以向 $(results.<resultName>.path) 这个路径写入想要输出的内容。注意写入内容的总和不能超过 4096 字节。

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: seqpod-workflowtemplate-sample-result
spec:
  results:
    - name: my-status
      description: "My status"
  type: SeqPod
  seqPod:
    steps:
      - name: echo
        image: ubuntu
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
        script: |
          echo I am OK > $(results.my-status.path)

results 更重要的用途是在 DAG WorkflowTemplate 的节点之间传递信息。DAG 的各个节点可以通过 $(templates.<workflowtemplateName>.results.<resultName>) 来引用这些 results,一般有两种用途:

  • DAG 的下层节点可以在 paramswhen 字段引用上层节点的 results
  • DAG WorkflowTemplate 可以组合节点的 results 来输出自身的 results
apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: add-workflowtemplate
spec:
  params:
    - name: first
      description: the first operand
    - name: second
      description: the second operand
  results:
    - name: sum
      description: the sum of the first and second operand
  type: SeqPod
  seqPod:
    steps:
      - name: add
        image: ubuntu
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
        env:
          - name: OP1
            value: $(params.first)
          - name: OP2
            value: $(params.second)
        command: ["/bin/sh", "-c"]
        args:
          - echo -n $((${OP1}+${OP2})) | tee $(results.sum.path);
---
apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: sum-three-workflowtemplate
spec:
  params:
    - name: first
      description: the first operand
    - name: second
      description: the second operand
    - name: third
      description: the third operand
  type: DAG
  dag:
    templates:
      - name: first-add
        workflowTemplateRef: add-workflowtemplate
        params:
          - name: first
            value: $(params.first)
          - name: second
            value: $(params.second)
      - name: second-add
        workflowTemplateRef: add-workflowtemplate
        params:
          - name: first
            value: $(templates.first-add.results.sum)
          - name: second
            value: $(params.third)
  results:
    - name: total-sum
      description: the sum of all three operands
      value: $(templates.second-add.results.sum)
    - name: partial-sum
      description: the sum of first two operands
      value: $(templates.first-add.results.sum)

条件分支

在 DAG WorkflowTemplate 中,如果需要在某个条件满足时才执行某个节点,可以设置 when 字段。

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: flip-coin
spec:
  results:
    - name: coin
      description: Which side? Heads or tails?
  type: SeqPod
  seqPod:
    steps:
      - name: flip-coin
        image: python
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
        script: |
          #!/usr/bin/env python3
          import random
          f = open("$(results.coin.path)", "w")
          if random.random() > 0.5:
            f.write("heads")
          else:
            f.write("tails")
          f.close()
---
apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: dag-workflowtemplate-sample-when
spec:
  type: DAG
  dag:
    templates:
      - name: flip-coin
        workflowTemplateRef: flip-coin
      - name: execute-only-if-heads
        workflowTemplateRef: pod-workflowtemplate-sample
        dependencies: ["flip-coin"]
        when:
          - input: "$(templates.flip-coin.results.coin)"
            operator: in
            values: ["heads"]

when 字段包含一些表达式:

  • input:表达式的输入,可以是静态字符串或 paramsresults 等变量。如果未填写,默认为一个空的字符串。
  • operator:表示 inputvalues 的关系,可以是 in 或者 notin
  • values:字符串数组,可以是静态字符串或 paramsresults 等变量。

只有当 when 字段包含的所有表达式结果都为真时,该节点才会被运行,否则会跳过该节点继续运行其他节点。

如果一个节点的 when 表达式中引用了其他节点的 results 变量,相当于引入了前者对后者的依赖关系,前者会在后者运行结束后才开始运行。

失败处理

对于 Pod/SeqPod/Resource WorkflowTemplate,一个 WorkflowRun 只对应一次运行,即使失败也不会重启。也就是说,一个 WorkflowRun 对应产生的 Pod 的 specrestartPolicy 永远是 Never

对于 DAG WorkflowTemplate,DAG 的每个节点都有可能会失败,我们使用 retries 字段来控制节点的重启。

  • retries = 0(默认选项)表示不重启失败的节点。
  • retries > 0 表示会重启失败的节点,并用一个正整数来限制最多可重启的次数。

如果 DAG 的某个节点失败并超过了最大可重启次数,该节点将被视为永久失败,并由 spec.dag.failureStrategy 决定接下来的行为:

  • failureStrategy = StopAllWorkflowTemplates(默认选项)表示停止创建任何新的节点。
  • failureStrategy = StopDependentWorkflowTemplates 表示只停止创建依赖于失败节点的节点,其他分支上的节点正常创建。

注意无论是哪种策略,已开始运行的节点都会等待其运行结束。

在下面的 DAG WorkflowTemplate 示例中,共有两个节点 ab

  • 如果 a 节点运行失败,它最多可以重试 5 次。
  • 如果 b 节点运行失败,它不能进行重试,直接被认定为失败。
  • 如果任意一个节点被认定为失败,整个 DAG WorkflowTemplate 也会被认定为失败,并且由于 spec.dag.failureStrategy 字段的值为 StopAllWorkflowTemplates,所有未开始运行的节点都不再运行。
apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: dag-workflowtemplate-sample-retries
spec:
  type: DAG
  dag:
    failureStrategy: StopAllWorkflowTemplates
    templates:
      - name: a
        workflowTemplateRef: pod-workflowtemplate-sample
        dependencies: []
        retries: 5
      - name: b
        workflowTemplateRef: pod-workflowtemplate-sample
        dependencies: ["a"]
        retries: 0

下一步

WorkflowRun

WorkflowRun 是 WorkflowTemplate 的一次执行,为 WorkflowTemplate 提供运行时所需的一切资源,例如参数(params)、工作空间(workspaces)。

创建引用某个 WorkflowTemplate 的 WorkflowRun

下面的 WorkflowRun 示例为一个 WorkflowTemplate 创建一次运行。

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowRun
metadata:
  name: workflowrun-sample
spec:
  workflowTemplateRef: workflowtemplate-sample

在该例中,workflowTemplateRef 字段标明所要运行的 WorkflowTemplate 的名称,该 WorkflowTemplate 必须是一个已经创建好的、与该 WorkflowRun 在同一个命名空间的 WorkflowTemplate。

创建内嵌 WorkflowTemplate 规约的 WorkflowRun

下面的 WorkflowRun 示例也是为一个 WorkflowTemplate 创建一次运行,但是该 WorkflowTemplate 的规约直接在 WorkflowRun 的规约中填写。

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowRun
metadata:
  name: embedded-workflowrun-sample
spec:
  workflowTemplateSpec:
    type: Pod
    pod:
      containers:
        - name: hello
          image: ubuntu:latest
          command: ["echo"]
          args: ["Hello TensorStack!"]

在该例中,workflowTemplateSpec 字段用于填写所要运行的 WorkflowTemplate 的规约,WorkflowTemplate 规约的写法详见 WorkflowTemplateSpec(坏链)。

WorkflowRun 状态

在下面的示例中,首先创建一个类型为 DAG 的 WorkflowTemplate,然后创建一个 WorkflowRun 引用该 WorkflowTemplate。

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: dag-workflowtemplate-sample
spec:
  type: DAG
  dag:
    templates:
      - name: a
        workflowTemplateRef: pod-workflowtemplate-sample
      - dependencies:
          - a
        name: b1
        workflowTemplateRef: pod-workflowtemplate-sample
      - dependencies:
          - a
        name: b2
        workflowTemplateRef: pod-workflowtemplate-sample
      - dependencies:
          - b1
          - b2
        name: c
        workflowTemplateRef: pod-workflowtemplate-sample
---
apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowRun
metadata:
  labels:
    batch.tensorstack.dev/workflowTemplate: dag-workflowtemplate-sample
  name: dag-workflowtemplate-sample-run
spec:
  serviceAccountName: ''
  workflowTemplateRef: dag-workflowtemplate-sample
status:
  completionTime: '2021-04-16T07:39:05Z'
  conditions:
    - lastTransitionTime: '2021-04-16T07:39:05Z'
      status: 'False'
      type: Running
    - lastTransitionTime: '2021-04-16T07:39:05Z'
      status: 'True'
      type: Completed
  message: All nodes in DAG have succeeded
  nodes:
    a:
      phase: Succeeded
      workflowRunName: dag-workflowtemplate-sample-run-a-pmb2m
    b1:
      phase: Succeeded
      workflowRunName: dag-workflowtemplate-sample-run-b1-mssn6
    b2:
      phase: Succeeded
      workflowRunName: dag-workflowtemplate-sample-run-b2-5db66
    c:
      phase: Succeeded
      workflowRunName: dag-workflowtemplate-sample-run-c-sjpb2
  phase: Succeeded
  startTime: '2021-04-16T07:38:10Z'
  workflowTemplateSpec:
    dag:
      templates:
        - name: a
          workflowTemplateRef: pod-workflowtemplate-sample
        - dependencies:
            - a
          name: b1
          workflowTemplateRef: pod-workflowtemplate-sample
        - dependencies:
            - a
          name: b2
          workflowTemplateRef: pod-workflowtemplate-sample
        - dependencies:
            - b1
            - b2
          name: c
          workflowTemplateRef: pod-workflowtemplate-sample
    type: DAG

WorkflowTemplate dag-workflowtemplate-sample 有四个节点,分别是:

  • a
  • b1
  • b2
  • c

WorkflowRun dag-workflowtemplate-sample-run 被创建后,WorkflowRun 控制器会为这四个节点创建四个 WorkflowRun,分别是

  • dag-workflowtemplate-sample-run-a-pmb2m
  • dag-workflowtemplate-sample-run-b1-mssn6
  • dag-workflowtemplate-sample-run-b2-5db66
  • dag-workflowtemplate-sample-run-c-sjpb2

如果这四个 WorkflowRun 均运行成功,WorkflowRun dag-workflowtemplate-sample-run 即运行成功。

WorkflowRun dag-workflowtemplate-sample-runstatus 字段显示,该 WorkflowRun 处于 Succeeded 状态(见 status.phase 字段),原因是 “All nodes in DAG have succeeded”(见 status.message 字段)。status.nodes 字段记录了该 WorkflowRun 中每个 DAG 节点的名称以及对应的 WorkflowRun 名称和状态。

下一步

CronWorkflowRun

CronWorkflowRun 用于方便地定时执行 WorkflowRun,对于创建周期性的、反复重复的任务很有用。

cron 是一种书写定时计划的格式,用一个字符串指定何时触发任务的执行,通常由以空格分隔的 5 个部分组成:

# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12)
# │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday;
# │ │ │ │ │                                   7 is also Sunday on some systems)
# │ │ │ │ │
# │ │ │ │ │
# * * * * *

例如:

  • 1 0 * * * 表示在每天的 00:01 执行。
  • 45 23 * * 6 表示在每个星期六的 23:45 执行。
  • */5 1,2,3 * * * 表示在每天的第 1、2、3 个小时每隔 5 分钟执行一次(即 01:00,01:05,01:10,…,03:55)。

注意 */n 表示每隔 n 个时间单位执行一次,在某个时间单位多次执行可以用逗号连接(例如 1,2,3)。

为了更方便地创建 cron 表达式,可以使用第三方网页工具,例如 crontab.guru

创建 CronWorkflowRun

下面的 CronWorkflowRun 示例会每分钟创建一个 WorkflowRun。

apiVersion: batch.tensorstack.dev/v1beta1
kind: CronWorkflowRun
metadata:
  name: cronworkflowrun-sample
spec:
  schedule: "*/1 * * * *"
  workflowRun:
    spec:
      workflowTemplateRef: workflowtemplate-sample

在该例中:

  • schedule 字段是一个 cron 格式的字符串,表示每分钟触发一次 WorkflowRun 的运行。
  • 所要运行的 WorkflowRun 由 workflowRun 字段定义,是一个引用 workflowtemplate-sample 的 WorkflowRun。

详细配置 CronWorkflowRun

下面是一个经过详细配置的 CronWorkflowRun 示例,与上一节类似,也会每分钟创建一个 WorkflowRun。

apiVersion: batch.tensorstack.dev/v1beta1
kind: CronWorkflowRun
metadata:
  name: cronworkflowrun-sample
spec:
  schedule: "*/1 * * * *"
  startingDeadlineSeconds: 30
  concurrencyPolicy: "Allow"
  suspend: true
  successfulRunsHistoryLimit: 10
  failedRunsHistoryLimit: 10
  workflowRun:
    spec:
      workflowTemplateRef: workflowtemplate-sample

在该例中:

  • 如果某个 WorkflowRun 由于任何原因未能准时在预设的时间点开始执行,它在 30 秒钟的期限内必须开始执行(由 startingDeadlineSeconds 字段指定),否则将被认为该次执行已失败。
  • 如果到了某个 WorkflowRun 应该开始执行的时间点,但是上一个 WorkflowRun 仍未运行完成,允许这两个 WorkflowRun 同时运行(由 concurrencyPolicy 字段指定)。
  • suspend 字段为 true 表示暂时停止创建新的 WorkflowRun,该字段可以随时变化。
  • 由该 CronWorkflowRun 创建的所有 WorkflowRun 中,最多保留 10 个运行成功的 WorkflowRun 和 10 个运行失败的 WorkflowRun(分别由 successfulRunsHistoryLimitfailedRunsHistoryLimit 字段指定),多余的运行时间较早的 WorkflowRun 会被删除。

CronWorkflowRun 状态

下面是 CronWorkflowRun 的状态示例:

apiVersion: batch.tensorstack.dev/v1beta1
kind: CronWorkflowRun
metadata:
  name: cronworkflowrun-sample
spec:
  schedule: "*/1 * * * *"
  startingDeadlineSeconds: 30
  concurrencyPolicy: "Allow"
  suspend: true
  successfulRunsHistoryLimit: 10
  failedRunsHistoryLimit: 10
  workflowRun:
    spec:
      workflowTemplateRef: workflowtemplate-sample
status:
  active:
  - apiVersion: batch.tensorstack.dev/v1beta1
    kind: WorkflowRun
    name: cronworkflowrun-sample-1631093400
    namespace: t9k-example
    resourceVersion: "220623640"
    uid: 39634803-d8cf-41d4-8a8e-649e0133b11b
  lastScheduleTime: "2021-09-08T09:30:00Z"
  conditions:
  - lastTransitionTime: "2021-09-08T09:23:00Z"
    message: At least one WorkflowRun has started
    status: "True"
    type: HasStarted
  - lastTransitionTime: "2021-09-08T09:30:00Z"
    message: There are running WorkflowRuns
    status: "True"
    type: IsRunning
  - lastTransitionTime: "2021-09-08T09:23:35Z"
    message: There are successful WorkflowRuns
    status: "True"
    type: HasSuccessfulRun
  - lastTransitionTime: "2021-09-08T09:22:08Z"
    message: No failed WorkflowRuns yet
    status: "False"
    type: HasFailedRun

该 CronWorkflowRun 的 status 字段显示:

  • 正在执行中的 WorkflowRun 有一个,其基本信息记录在 status.active 字段中。
  • 最新的 WorkflowRun 的创建时间是 2021-09-08T09:30:00Z(由 status.lastScheduleTime 字段描述)。
  • 在由该 CronWorkflowRun 创建的 WorkflowRun 中,已开始过至少一次 WorkflowRun(可能已结束或未结束),有正在运行中的 WorkflowRun,有已成功的 WorkflowRun,没有失败的 WorkflowRun(由 status.conditions 字段描述)。

WorkflowTrigger

TensorStack AI 平台提供了一个灵活的工作流服务,除了支持手动执行工作流 WorkflowRun,还提供了 CronWorkflowRun 用于定时执行。

Workflow Trigger 模块额外提供了一种基于特定事件自动触发执行 WorkflowRun 的能力,便于用户在一些特定场景下的自动化工作流运行。

架构

Workflow Trigger 模块提供了 EventListener 和 WorkflowTrigger 自定义扩展资源,整体架构如下图所示:

workflow-trigger-architecture

其中:

  • EventListener 作为事件入口接收 JSON 格式的 HTTP POST 请求,同时将请求信息转换成 CloudEvents 格式并转发至事件队列。
  • WorkflowTrigger 绑定一个或多个 EventListener 作为事件源,接收来自这些 EventListener 的 CloudEvents 格式的事件消息,并触发一个 WorkflowRun 的运行。特别地,支持对事件内容进行过滤,以及解析事件的某些字段的值填充到 WorkflowRun 的参数中。

快速开始

下面将通过几个简单的步骤来演示 Workflow Trigger 模块的基本使用方法。下面创建的所有资源请确保属于同一个命名空间。

1)创建 WorkflowTemplate

创建文件 workflow-template-sample.yaml:

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: workflow-template-sample
spec:
  description: This WorkflowTemplate creates and runs a Pod.
  params:
    - name: message
      default: "TensorStack"
  type: Pod
  pod:
    containers:
      - name: hello
        image: ubuntu:latest
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
        command: ["echo"]
        args: ["Hello $(params.message)!"]

上面的示例定义了一个名为 message 的参数,同时将该参数值以 $(params.message) 的形式传递到 Pod 的容器的 args 参数上,执行下面的命令创建 WorkflowTemplate:

kubectl apply -f workflow-template-sample.yaml

该 WorkflowTemplate 将作为一个静态模版用于执行一次 WorkflowRun 的运行。

2)创建 EventListener

创建文件 event-listener-sample.yaml:

apiVersion: tensorstack.dev/v1beta1
kind: EventListener
metadata:
  name: event-listener-sample
spec:
  replicas: 1

执行下面的命令创建一个 EventListener:

kubectl apply -f event-listener-sample.yaml

3)创建 WorkflowTrigger

创建文件 workflow-trigger-sample.yaml:

apiVersion: tensorstack.dev/v1beta1
kind: WorkflowTrigger
metadata:
  name: workflow-trigger-sample
spec:
  eventSources:
  - eventListenerName: event-listener-sample
  replicas: 1
  serviceAccountName: managed-project-sa
  workflowRunSpec:
    params:
    - name: message
      value: $(body.hello)
    workflowTemplateRef: workflow-template-sample

上面的示例以 $(body.hello) 的形式将 HTTP 请求体中的 hello 字段值传递到 param message 上,执行下面的命令创建 WorkflowTrigger:

kubectl apply -f workflow-trigger-sample.yaml

4)触发事件

通过执行下面的命令来查询 EventListener HTTP 服务的访问地址:

$ kubectl get eventlisteners event-listener-sample -o json | jq .status.address
{
  "inClusterURL": "http://event-listener-sample-eventlistener-2dbfe.default.svc.cluster.local",
  "url": "https://<tensorstack-host>/t9k/workflow/triggers/default/event-listener-sample"
}

其中 url 字段为集群外部访问 EventListener HTTP 服务的地址,使用 curl 命令向此地址发送 HTTP 请求来模拟触发事件:

curl -X POST https://<tensorstack-host>/t9k/workflow/triggers/default/event-listener-sample \
  -d '{"hello": "world"}'

其中 -d '{"hello": "world"}' 标识 HTTP 请求的 JSON 格式的 body 内容为 {"hello": "world"}hello 字段值 "world" 将作为参数传递到 WorkflowRun,HTTP 服务将返回 success 表示请求已经发送成功。

5)查看 WorkflowRun

上面的步骤全部执行成功以后,WorkflowTrigger 将会触发一次 WorkflowRun 的运行,通过下面的命令进行查询:

$ kubectl get workflowruns
NAME                                                  PHASE
event-listener-sample-workflow-trigger-sample-87a0d   Succeeded

根据返回的结果可以看出,WorkflowRun 已经创建成功。该 WorkflowRun 将根据上面 WorkflowTemplate 静态模块的内容创建一个 Pod,通过下面的命令进行查询:

$ kubectl get po -l batch.tensorstack.dev/workflowRun=event-listener-sample-workflow-trigger-sample-87a0d
NAME                                                            READY   STATUS      RESTARTS   AGE
event-listener-sample-workflow-trigger-sample-87a0d-pod-6stvb   0/1     Completed   0          3m23s

根据返回的结果可以看出,Pod 已经创建成功,通过查询该 Pod 日志来校验参数传递:

$ kubectl logs event-listener-sample-workflow-trigger-sample-87a0d-pod-6stvb
Hello world!

Pod 日志成功打印出 “world” 内容,其为手动触发事件中发送的 HTTP 请求的 body 内容,参数成功传递。

至此,Workflow Trigger 模块的基本使用方法已经介绍完成,阅读下面的章节来获取更详细的配置信息。

EventListener

EventListener 内部运行着一个 HTTP 服务,用于接收第三方的请求,同时将请求消息转换成 CloudEvents 并将它们转发至事件队列。当前 EventListener 只支持 JSON 格式的 HTTP POST 请求。

创建 EventListener

下面是一个基本的 EventListener 示例:

apiVersion: tensorstack.dev/v1beta1
kind: EventListener
metadata:
  name: event-listener-sample
spec:
  replicas: 1
  resources:
    requests:
      memory: "100Mi"
      cpu: "100m"
    limits:
      memory: "200Mi"
      cpu: "200m"

在该例中:

  • replicas 字段定义所要创建的 Pod 副本数量,默认是 1。
  • resources 字段定义每个 Pod 的资源限制,上述示例为缺省时的默认值。

EventListener 状态

通过 EventListener 的状态字段可以获取其访问地址和运行状态信息,示例如下:

status:
  address:
    inClusterURL: http://<eventlistener-service-name>.default.svc.cluster.local
    url: https://<tensorstack-host>/t9k/workflow/triggers/default/<eventlistener-name>
  conditions:
  - lastTransitionTime: "2022-12-05T10:23:49Z"
    message: The EventListener is Ready
    status: "True"
    type: Ready

其中:

  • status.address 表示 EventListener 所创建的 HTTP 服务的访问地址,第三方可向此地址发送请求,其中:
    • inClusterURL 是只能从集群内部访问的地址。
    • url 是可以从集群外部访问的地址。
  • status.conditions 表示 EventListener 的状态:
    • type: Ready 表示 EventListener 是否就绪,可能的值有 TrueFalseUnknown

WorkflowTrigger

WorkflowTrigger 从一个或多个 EventListener 事件源获取事件消息,并触发一个 WorkflowRun 的运行。

WorkflowTrigger 支持对每个 EventListener 配置过滤条件,只有符合过滤条件的事件消息才会被进一步处理;WorkflowTrigger 同时支持将事件消息的某些字段解析并填充到 WorkflowRun 的参数执行。

创建 WorkflowTrigger

下面是一个基本的 WorkflowTrigger 示例:

apiVersion: tensorstack.dev/v1beta1
kind: WorkflowTrigger
metadata:
  name: workflow-trigger-sample
spec:
  eventSources:
  - eventListenerName: event-listener-sample
  replicas: 1
  resources:
    requests:
      memory: "100Mi"
      cpu: "100m"
    limits:
      memory: "200Mi"
      cpu: "200m"
  serviceAccountName: managed-project-sa
  workflowRunSpec:
    workflowTemplateRef: workflow-template-sample

在该例中:

  • eventSources 字段定义了该 WorkflowTrigger 需要订阅事件消息的事件源集合,其中:
  • eventListenerName 表示上述 EventListener 的名称,该 EventListener 必须与该 WorkflowTrigger 同命名空间、且已成功创建。
  • replicas 字段定义了该 WorkflowTrigger 创建的 Pod 副本数量,默认是 1。
  • resources 字段定义每个 Pod 的资源限制,上述示例为缺省时的默认值。
  • serviceAccountName 字段定义了该 WorkflowTrigger 创建的 Pod 的 ServiceAccount,为创建 WorkflowRun 提供权限。
  • workflowRunSpec 字段定义了将要创建的 WorkflowRun 的配置规约,其中:
    • workflowTemplateRef 表示所要运行的 WorkflowTemplate 的名称,该 WorkflowTemplate 必须与该 WorkflowTrigger 同命名空间、且已成功创建。该字段同时支持内嵌 WorkflowTemplate 规约,详见 WorkflowRun

过滤事件

WorkflowTrigger 支持对来自 EventListener 的事件消息进行过滤,只有符合过滤条件的事件消息才会被进一步处理。下面是一个包含过滤条件的 WorkflowTrigger 示例:

apiVersion: tensorstack.dev/v1beta1
kind: WorkflowTrigger
metadata:
  name: filter-workflow-trigger-sample
spec:
  eventSources:
  - eventListenerName: event-listener-sample
    filters:
    - path: body.object_attributes.work_in_progress
      type: bool
      values:
      - "false"
    - path: body.labels.0.id
      type: number
      values:
      - "219"
      - "3"
      - "99"
    - path: body.object_kind
      type: string
      values:
      - "merge_request"
  serviceAccountName: managed-project-sa
  workflowRunSpec:
    workflowTemplateRef: workflow-template-sample

在该例中,spec.eventSources.filters 定义了该 EventListener 的过滤条件集合,其中:

  • path 表示 HTTP 请求路径,例如 header.X-Github-Event、body.pull_request.state。
  • type 表示该路径指向字段的值的类型,当前支持 bool、number、string。
  • values 表示该路径指向字段的值的可允许值的集合,其为 string 类型。

每个 EventListener 的 filters 互不影响,针对某一个 EventListener,其所有的 filters 必须全部通过才算符合条件。

解析参数

WorkflowTrigger 支持对来自 EventListener 的事件消息进行解析,并将指定字段的值通过参数的形式传递到 WorkflowRun。下面是一个包含解析参数的 WorkflowTrigger 示例:

apiVersion: tensorstack.dev/v1beta1
kind: WorkflowTrigger
metadata:
  name: param-workflow-trigger-sample
spec:
  eventSources:
  - eventListenerName: event-listener-sample
  serviceAccountName: managed-project-sa
  workflowRunSpec:
    params:
    - name: bool-name
      value: $(body.test.boolT)
    - name: number-name
      value: $(body.test.numberT)
    - name: string-name
      value: $(body.test.stringT)
    workflowTemplateRef: workflow-template-sample

在该例中,spec.workflowRunSpec.params 定义了将创建的 WorkflowRun 的参数集合,其中:

  • name 表示参数名称。
  • value 表示参数的值,可通过 $() 形式从事件消息中获取指定字段的值。当前不支持 $() 嵌套。

WorkflowTrigger 状态

通过 WorkflowTrigger 的状态字段可以获取其运行状态信息,示例如下:

status:
  conditions:
  - lastTransitionTime: "2022-12-05T10:26:46Z"
    message: The WorkflowTrigger is Ready
    status: "True"
    type: Ready

其中:

  • status.conditions 表示 WorkflowTrigger 的状态:
    • type: Ready 表示 WorkflowTrigger 是否就绪,可能的值有 TrueFalseUnknown

操作指南

使用模型构建控制台

模型构建控制台提供了大量功能,你可以在此进行模型构建,并管理 Job存储辅助资源。本部分将演示如何在模型构建控制台中使用 Notebook 和 TensorBoard,构建和调试镜像,以及管理存储、配置和隐私信息。

对于如何使用 T9k Job 和 AutoTune,请分别参阅运行模型训练进行超参数优化

创建 Notebook

本教程演示如何创建 Notebook。

准备工作

创建 PVC

创建 Notebook 时,需要至少绑定一个 PVC 来存储代码、数据等文件。如果你的项目中已有合适的持久卷,则可以直接进入下一节。

在模型构建控制台的左侧导航菜单中点击存储 > 持久卷进入 PVC 管理页面。然后点击右上角的创建 PVC 进入创建页面:

pvc-manage

在 PVC 创建页面,名称填写 create-notebook存储填写 1Gi,其他参数保持默认值,然后点击创建

pvc-create-filled

创建标准的 Notebook

在模型构建控制台的左侧导航菜单中点击构建 > Notebook 进入 Notebook 管理页面,然后点击右上角的创建 Notebook 进入创建页面:

notebook-manage

在 Notebook 创建页面,如下填写各个参数:

  • 名称填写 create-notebook
  • 存储卷选择上一节创建的 create-notebook(或其他合适的存储卷)。存储卷会被挂载到 Notebook 的 /t9k/mnt 目录下。
  • 镜像根据你想使用的机器学习框架(如 TensorFlow、PyTorch 等)及其版本选择一个标准 Notebook 镜像。
  • 模版根据你的资源需求选择一个合适大小的资源模版。

其他参数保持默认值,完成之后,点击创建

notebook-create-filled

回到 Notebook 管理页面查看新创建的 Notebook:

notebook-created

Notebook 就绪后,就可以使用 Notebook

其他配置

使用 T9k 调度器

计算资源模块还提供了选项,使用调度器 t9k-scheduler,以支持便捷的资源使用申请,使用 t9k-scheduler 调度任务时必须指定一个队列。相比默认调度器,t9k-scheduler 需要额外填写如下参数:

  • 队列 (queue):必填,选择一个队列(如果没有队列,请联系管理员创建一个队列)。
  • 优先级 (priority):可选,默认值是 0。代表任务在队列内部的优先级。当发生资源抢占时,优先级数字较小的工作负载会比同一个队列中的其他负载优先被驱逐。
t9k-scheduler

使用数据卷

可以为 Notebook 绑定额外的数据卷(存放数据的 PVC),如下图所示:

notebook-dataVolume

每绑定一个数据卷需要填写如下参数:

  • 名称:使用的 PVC 名称。
  • 绑定路径:将 PVC 绑定到 Notebook 的指定路径下。

在上图的示例中,我们将 PVC examples 绑定到了 Notebook 的 /t9k/examples 路径下。你可以在 Notebook 中通过对应路径访问 PVC 中的数据。

启用 SSH 选项

如果你想使用 SSH 连接到 Notebook 容器中来管理其中的文件,或者使用本地的 IDE 来编辑 Notebook 中的代码,启用 SSH 能够帮助你在 Notebook 中运行一个 SSH 服务。

Notebook 的 SSH 服务只允许通过密钥对进行验证,因此你需要上传公钥以使用 SSH 连接。TensorStack AI 平台使用 Secret 存储公钥信息。如果你已经创建了包含公钥的 Secret,则可以直接进入下一节。

在模型构建控制台的左侧导航菜单中点击辅助 > Secret,然后点击右上角的创建 Secret 进入的创建页面:

secret-create

在 Secret 创建页面,选择类型为 SSH Public Key,填写名称和公钥内容。最后点击创建 Secret 进行创建:

secret-create-ssh

创建 Notebook 时,开启启用 SSH 按钮,然后选择前面创建的 Secret(此处为一个多选框,你可以同时设置多个 SSH 公钥):

notebook-ssh

点击创建,等待运行之后,你可以通过 SSH 连接远程使用 Notebook

使用 Notebook

本教程演示如何使用 Notebook 进行模型开发相关的工作。

打开 JupyterLab

在模型构建控制台的左侧导航菜单中点击构建 > Notebook 进入 Notebook 管理页面,然后点击运行中的 Notebook 右侧的打开

notebook-manage

进入到 JupyterLab 的页面:

jupyterLab

使用 Jupyter Notebook

点击 Launcher 标签页下,Notebook 下方的 Python3 图标以创建 Jupyter Notebook:

jupyterLab-select-notebook

Jupyter Notebook 提供了交互式的 Python 开发环境。你可以在这里分块编辑并运行 Python 代码。比如运行 keras_mnist.py

from tensorflow.keras import callbacks, datasets, layers, models, optimizers

model = models.Sequential([
    layers.Conv2D(32, 3, activation='relu', input_shape=(28, 28, 1)),
    layers.MaxPool2D((2, 2)),
    layers.Conv2D(64, 3, activation='relu'),
    layers.MaxPool2D((2, 2)),
    layers.Conv2D(64, 3, activation='relu'),
    layers.Flatten(),
    layers.Dense(64, activation='relu'),
    layers.Dense(10, activation='softmax'),
])
model.compile(optimizer=optimizers.Adam(learning_rate=0.001),
            loss='sparse_categorical_crossentropy',
            metrics=['accuracy'])


(train_images, train_labels), (test_images,
                            test_labels) = datasets.mnist.load_data()

train_images = train_images.reshape((60000, 28, 28, 1))
test_images = test_images.reshape((10000, 28, 28, 1))

train_images, test_images = train_images / 255.0, test_images / 255.0

model.fit(train_images,
        train_labels,
        batch_size=32,
        epochs=5,
        validation_split=0.2)
model.evaluate(test_images, test_labels)
jupyterLab-notebook

编辑文件

在左侧的文件系统导航菜单空白处右击,可以创建文件和目录:

jupyterLab-newfile

创建名为 keras_mnist.py 的文件,双击以进行编辑。复制上文中 keras_mnist.py 的内容,粘贴在文本编辑器中并保存:

jupyterLab-editor

使用 Terminal

点击左上角蓝色底色的 + 符号打开新的 Launcher 标签页,然后点击 Other 中的 Terminal 进入命令行终端。你可以在这里运行各种 bash 命令,例如运行 python ./keras_mnist.py 来进行模型训练:

jupyterLab-terminal

查看详情

在 Notebook 管理页面,点击 Notebook 的名称进入其详情页面:

notebook-show-details

Notebook 的详情页面展示了 Notebook 的基本信息、状况和事件。点击 Pod 右侧的链接可以查看 Pod 的日志、状况、事件、资源监测等信息:

notebook-details

查看日志

点击日志,查看 Notebook Pod 的运行日志:

notebook-logs

查看资源监测

点击资源监测,查看 Notebook Pod 运行时实际使用的资源,包括 CPU、内存、存储 I/O 的使用量:

notebook-resource-1
notebook-resource-2

通过 SSH 远程使用 Notebook

本教程演示如何通过 SSH 连接远程使用 Notebook。

准备

  • 创建了一个启用 SSH 选项的 Notebook。
  • 确认该 Notebook 处于正常运行状态。

端口转发

命令行工具 t9k-pf

命令行工具 t9k-pf 的功能类似于 kubectl port-forward,可以让用户能够在本地通过端口转发的方式访问 TensorStack AI 平台的各种资源。

请参照用户指南,下载安装 t9k-pf 并配置身份认证和授权

端口转发命令

在 Notebook 详情页面,查看并复制SSH 服务提示的命令:

copy-t9k-pf-command

在终端执行该命令以进行端口转发:

$ t9k-pf notebook <URL> <Port>
now you can forward to your target by 127.0.0.1:<Port>

参数说明如下:

  • URL:Notebook 的 Web UI 地址。除上述获取方式外,你也可以在打开 Notebook 后,复制浏览器地址栏中的地址作为 URL 参数使用。
  • Port:转发的本地端口。在 SSH 远程连接教程中会使用到该端口。

根据终端打印的提示信息,使用本地的端口与目标 Notebook 建立 SSH 连接,具体命令请参阅 SSH 远程连接

建立 SSH 连接

使用终端

在终端中运行以下命令以连接到 Notebook:

ssh t9kuser@localhost -p <Port> \
  -o StrictHostKeyChecking=no \
  -o GlobalKnownHostsFile=/dev/null \
  -o UserKnownHostsFile=/dev/null

然后在终端中操作 Notebook:

terminal-ssh

使用 VSCode

安装 Remote SSH 插件

在 VSCode 中搜索 Remote - SSH 插件并安装:

vscode-plugin

添加 SSH Config

安装完成后,需要在 SSH Config 中添加主机(Notebook)的信息。

VSCode 提供了编辑 SSH Config 的方式。点击左下角的绿色 >< 符号,选择 Connect to Host,然后拉动滚动条到最下方,点击 Add New SSH Host

vscode-new-host

根据提示,输入以下内容,然后按下回车键(Enter):

ssh t9kuser@localhost -p <Port>
vscode-ssh-command

VSCode 会提示 Select SSH configuration file to update,第一个选择项通常是位于 $HOME/.ssh/config 的配置文件,你可以选择将主机的信息存储在第一个配置文件中。

连接到 Notebook

点击左下角的绿色 >< 符号,选择 Connect to Host

vscode-connect

然后选择 SSH Config 中对应的主机名(使用上述配置方式时,主机名为 localhost):

vscode-connect-select

VSCode 会新建一个窗口,等待连接建立之后,左下角会提示 SSH: Host

点击 Open Folder 可以选择打开的目录或者文件。你可以和本地开发一样使用 VSCode 来操作 Notebook:

vscode-connected

使用 PyCharm

使用 PyCharm 远程连接到 Notebook 需要满足以下前提条件:

  1. 安装了 PyCharm 专业版,且版本不低于 2022.2。PyCharm 有专业版(Professional)和社区版(Community),目前仅 PyCharm Professional 支持远程 SSH 开发。
  2. Notebook 的资源配置至少为 3 个 CPU,3 GiB 内存,Notebook 绑定的持久卷至少有 2.5 GiB 的可用空间。推荐配置为至少 4 个 CPU,4 GiB 内存,5 GiB 持久卷。

打开 PyCharm,在左侧的导航菜单中点击 Remote Development > SSH,然后点击右侧的 New Connection

pycharm-ssh

在弹出的对话框中填写如下参数:

  • Username:SSH 使用的用户名。
  • Host:主机地址,通常为 127.0.0.1
  • Port:端口。
  • Specify private key:建议勾选,并选择与你上传的公钥对应的私钥。
pycharm-connect

点击 Check Connection and Continue,进入下一步:

pycharm-connected

这里选择了在 Notebook 中安装的 IDE Backend 版本为 PyCharm 2022.2.3,远程打开的项目目录为 /t9k/mnt。点击 Download IDE and Connect 后,就可以通过 PyCharm 访问 Notebook 中的文件了。

pycharm-edit

你可以和本地开发一样使用 PyCharm 来操作 Notebook:

参考

创建 TensorBoard

本教程演示如何创建 TensorBoard。

准备工作

运行示例

请按照使用方法准备环境,然后前往本教程对应的示例,参照其 README 文档运行。

查看训练指标

TensorBoard 处于 Running 状态后,进入模型构建控制台的 TensorBoard 页面,可以看到 TensorBoard tensorboard 正在运行:

running

点击 TensorBoard 右侧的 打开 进入 TensorBoard 页面,查看可视化展示的训练和验证指标:

tensorboard

构建镜像

本教程演示如何在平台上构建容器镜像(container image)并推送到指定的容器镜像仓库(container registry)。

运行示例

请按照使用方法准备环境,然后前往本教程对应的示例,参照其 README 文档运行。

其中,创建包含身份信息的 Secret 这一步骤也可以在模型构建控制台中通过创建 Docker 类型的 Secret 来完成,如下图所示。详情请参阅创建 Secret

secret-form

检查构建进度和结果

在模型构建控制台的左侧导航菜单中点击构建 > Image Builder,然后点击刚创建的 Image Builder 右侧的详情,查看其详情和日志。拉取基础镜像、构建镜像和推送镜像都需要花费一定的时间,请耐心等待。

image-builder
detail
log

一段时间后,构建完成的镜像被推送到相应的 registry 中。

pushed-to-registry

FAQs

Unpacking rootfs 失败

使用 ImageBuilder 制作镜像时,有时会出现类似以下的错误:

INFO[0009] Unpacking rootfs as cmd RUN apt-get -qq update &&     apt-get -qq install --no-install-recommends -y curl requires it. 
error building image: error building stage: failed to get filesystem from image: stream error: stream ID 17; PROTOCOL_ERROR; received from peer

但是该错误信息并不准确,经分析,实际导致镜像 build 失败的可能原因是:镜像(Dockerfile 中 FROM 语句所引用的镜像)提取失败。

提取失败可能有以下原因:

  • 镜像来源于无法访问或下载速度过慢的仓库

解决方法:

  1. 切换到服务质量更好的的 Registry,例如本地网络部署的私有化 Registry,或其他 caching Regisry。
  2. 使用代理服务器,通过该代理下载镜像。

调试镜像

本教程演示如何方便地在模型构建控制台通过命令行进入一个镜像,以便对镜像进行探索和测试。

准备工作

示例

假设我们想知道镜像 t9kpublic/tensorflow-2.11.0-notebook-cpu:1.70.0 中安装了哪些 pip 包。

进入模型构建控制台后,点击构建 > Pod 进入 Pod 管理页面。

pod-list

点击右上角的创建以创建一个 Pod,执行 sleep 命令使镜像保持运行状态,以便我们连接镜像中的 bash(或 sh)终端。

pod-create
pod-create

分别填写项目名称、镜像名称、运行命令和资源使用量,然后点击创建

pod-list-2

所创建的 Pod 变为运行状态后,点击 Pod 名称进入 Pod 详情页面。

pod-detail

点击终端按钮,打开终端。

pod-terminal

在打开的终端中,输入 pip list 显示该镜像中安装的所有 pip 包,或者输入其他任何命令。

最后,点击右上角的 X 关闭终端。

管理 PVC

本教程演示如何在模型构建控制台中管理和使用 PVC

准备工作

创建 PVC

进入模型构建控制台,在左侧导航菜单(或右侧卡片)中点击存储 > 持久卷进入 PVC 管理页面。

overview-pvc

点击 PVC 管理页面右上角的创建 PersistentVolumeClaim 进入 PVC 创建页面。

create-pvc

在 PVC 创建页面填写名称和存储卷大小,选择存储卷访问模式和存储类,然后点击创建

create-pvc-detail

你可以点击左上角的导入 PersistentVolumeClaim 以加载当前存在的 PVC 的配置。

删除 PVC

在 PVC 管理页面,点击要删除的 PVC 右侧的更多按钮 > 删除

delete-pvc

使用 Explorer

本教程演示如何使用 Explorer 查看和修改存储在 PVC 和 StorageShim 中的文件。

启动 Explorer

在模型构建控制台的左侧导航菜单中点击存储 > 持久卷进入 PVC 管理页面,点击 PVC 右侧的启动

start-explorer

将光标悬停在打开上,等待 File Browser 和 VS Code 就绪。随后点击 File BrowserVS Code 即可进入。

enter

使用 File Browser

进入 File Browser 的前端页面,我们可以看到 PVC 中的所有文件和目录:

file-browser

这里支持以下操作:

  • 浏览目录和文本文件
  • 创建、删除、重命名、复制、移动目录和文件
  • 上传、下载文件
  • 修改文本文件

使用 VS Code

进入 File Browser 的前端页面,我们可以看到 PVC 中的所有文件和目录:

vs-code

这里支持以下操作:

  • 浏览目录和文本文件
  • 创建、删除、重命名、复制、移动目录和文件
  • 修改文本文件,进行轻量级代码修改
  • 启动终端并执行命令
  • 进行源代码控制
  • 安装 VS Code 插件

暂停和关闭 Explorer

使用结束后,我们可以关闭 Explorer。之后重新启用即可。

pause-close-explorer

使用 StorageShim 适配 S3 服务

概述

TensorStack AI 平台支持用户在多个环节使用 S3 协议的存储服务。本教程演示如何通过 StorageShim 把 S3 存储服务转换成 PVC,以方便在一些需要使用 POSIX 文件系统接口的场景。

本教程涉及如下基本概念:

  • S3(Simple Storage Service)提供可扩展、安全、高可用的对象存储服务,可以存储和检索任意数量和类型的数据,包括文档、图片、视频、音频等。更多详细信息请参阅附录
  • PVC(PersistentVolumeClaim)是 Kubernetes 提供的一种声明式的存储卷请求,用于向 Kubernetes 集群申请持久化存储卷。PVC 使应用程序与存储资源解耦,提高了存储资源的管理和使用效率。
  • StorageShim 提供了把 S3 服务转换为 PVC 的能力,让用户能够以 Kubernetes 原生的方式使用 S3。

详细过程

要访问 S3 服务,需要提供使用其服务的相应配置,包括:

  • S3 访问凭证:用于访问 S3 服务的一组密钥,包括访问密钥(access key)和秘密访问密钥(secret key)。S3 访问凭证是必需的,以在访问 S3 服务时进行身份验证和授权。
  • S3 服务的终端地址(endpoint):HTTP 或 HTTPS 格式的地址,例如:http://100.1.1.2:8000
  • S3 bucket:存储用户数据的容器;访问特定的 bucket 需要有合适权限的访问凭证。

准备 S3 配置

以下面的格式准备一个名为 s3cfg 的文件:

[default]
# Setup access keys
access_key = <you-access-key>
secret_key = <your-secret-key>

# Setup endpoint
host_base = http[s]://<host-or-ip>:<port>
use_https = <False | True>

其中需要修改的内容包括:

  • access_key:你的访问密钥(access key)。
  • secret_key:你的秘密访问密钥(secret key)。
  • host_base:S3 服务的地址(endpoint)。
  • use_https:是否使用 HTTPS。

你可以安装 s3cmd,在本地运行命令来验证 s3cfg 是否正确配置:

s3cmd -c s3cfg ls s3://<my-bucket>

创建 Secret

通过控制台

进入模型构建控制台,选择左侧导航菜单的辅助 > Secret,点击创建 Secret

选择类型为 S3-cfg,填写名称,然后填写 Details 的内容:

  • 服务端点:S3 服务的地址(endpoint)
  • Access Key ID:你的访问密钥(access key)。
  • 密码:你的秘密访问密钥(secret key)。

最后点击创建 Secret

create-pvc-s3cfg.png

通过命令行工具

用户也可以使用 kubectl 命令行工具创建 Secret:

kubectl -n <project> create secret generic <s3cfg-secret> \
  --from-file=.s3cfg=<s3cfg>

其中需要修改的内容包括:

  • <project>:项目名称。
  • <s3cfg-secret>:Secret 的名称。
  • <s3cfg>:本地 s3cfg 文件的路径。前面的 --from-file=.s3cfg= 不需要修改。

验证

运行以下命令,查看 Secret 中保存的 .s3cfg 内容:

kubectl -n <project> get secret <s3cfg-secret> \
    -o jsonpath={.data."\.s3cfg"} | base64 -d

其中需要修改的内容包括:

  • <project>:项目名称。
  • <s3cfg-secret>:Secret 的名称。

对比输出内容与你本地的 s3cfg,确认内容一致,重点是 access_keyhost_basesecret_key 字段。

创建 StorageShim

通过控制台

进入模型构建控制台,选择左侧导航菜单的存储 > 持久卷,点击上方的 S3,然后点击右上角的创建 StorageShim

view-storageshim.png

输入持久卷名称、S3 URI(s3://<your-bucket>),然后选择 S3 Secret 名称,最后点击右上角的创建 StorageShim 完成创建:

create-storageshim.png

在 S3 标签页查看新创建的 StorageShim:

new-storageshim.png

通过命令行工具

使用以下命令创建 StorageShim 类型的 PVC:

kubectl -n <project> create -f - <<EOF
apiVersion: tensorstack.dev/v1beta1
kind: StorageShim
metadata:
  name: dataset
spec:
  readOnly: false
  s3:
    uri: 's3://42a3de90-d9e7-4769-8fc4-48a65fb561d5'
  secretRef:
    name: s3cfg-secret
EOF

其中需要修改的内容包括:

  • <project>:项目名称。
  • .spec.s3.uri:S3 bucket 的路径,你也可以具体指定 bucket 中的一个文件夹。
  • .spec.secretRef.name:保存 S3 凭证的 Secret 名称。
  • readOnly:如果为 true,那么用户只能读取这个 StorageShim 的内容,而不能修改它。

查看 PVC 状态,确认 STATUS 为 Bound:

$ kubectl -n <project> get pvc
NAME                STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS     AGE
dataset             Bound    pvc-cc7f789a-6fcb-44a0-8f42-0e6c86e51a1a   1          RWX            csi-s3           4m5s

附录

S3 基本概念

S3(Simple Storage Service)提供了可扩展、安全、高可用的对象存储服务,可以存储和检索任意数量和类型的数据,包括文档、图片、视频、音频等。

S3 使用:

  • Bucket:Bucket 是 S3 存储中的基本容器,类似于文件夹,用于存储和组织对象。每个 Bucket 必须具有唯一的名称,并且名称必须符合 DNS 命名规则。
  • Object:Object 是 S3 存储中的基本数据单元,可以是任意类型的数据,例如文档、图片、视频、音频等。每个 Object 由一个唯一的键(Key)和一个值(Value)组成,键是 Object 在 Bucket 中的唯一标识符,值是 Object 的实际数据。

S3 管理:

  • Region:Region 是 S3 存储的物理位置,用于指定 Bucket 存储的地理位置。每个 Region 都由多个可用区域(Availability Zone)组成,以提供高可用性和容错性。
  • ACL:ACL(Access Control List)是 S3 存储的访问控制列表,用于控制 Bucket 和 Object 的访问权限。ACL 可以指定特定用户或组的访问权限,也可以指定公共访问权限。
  • Versioning:Versioning 是 S3 存储的版本控制功能,用于保留 Object 的所有版本。启用版本控制后,每次更新 Object 时都会创建一个新版本,并可以通过指定版本号来访问特定版本的 Object。
  • Lifecycle:Lifecycle 是 S3 存储的生命周期管理功能,用于自动化管理 Bucket 和 Object 的生命周期。Lifecycle 可以指定 Object 的存储期限、转换存储类别、自动删除 Object 等操作,以优化存储成本和管理效率。

S3 基本使用:s3cmd

有多种工具(s3browser、WinSCP、s3cmd、s5cmd、rclone 等)可以访问 S3 存储服务,以下使用 s3cmd 演示 S3 的基本操作:

安装 s3cmd 工具:在 Linux 系统中使用命令行安装 s3cmd 工具,例如在 Ubuntu 系统中可以使用以下命令进行安装:

sudo apt-get install s3cmd

配置 s3cmd 工具:在命令行中执行 s3cmd --configure 命令,按照提示输入 S3 访问密钥和秘密访问密钥,以及 S3 服务的访问地址和区域等参数,完成 s3cmd 工具的配置。

创建 S3 存储桶:使用 s3cmd mb 命令创建 S3 存储桶,例如:

s3cmd mb s3://my-bucket-name

上传对象:使用 s3cmd put 命令上传对象到 S3 存储桶中,例如:

s3cmd put /path/to/local/file s3://my-bucket-name/path/to/remote/file

下载对象:使用 s3cmd get 命令从 S3 存储桶中下载对象到本地,例如:

s3cmd get s3://my-bucket-name/path/to/remote/file /path/to/local/file

删除对象:使用 s3cmd del 命令从 S3 存储桶中删除对象,例如:

s3cmd del s3://my-bucket-name/path/to/remote/file

设置对象 ACL:使用 s3cmd setacl 命令设置对象的 ACL,例如:

s3cmd setacl --acl-public s3://my-bucket-name/path/to/remote/file

对象存储(object storage)

对象存储是一种将数据存储为对象的数据存储架构,这与文件系统将数据作为文件层次结构进行管理不同。 每个对象通常包括数据本身(object)、元数据(metadata)和全局唯一标识符(object key)。

对象存储是存储海量非结构化数据(例如图像、视频和文档)的不错选择,例如大规模机器学习中使用的海量训练数据、特征、模型等。

与其他存储架构相比,对象存储具有许多优势,包括:

  • 可扩展性:对象存储可以轻松扩展以满足不断增长的应用程序的需求。
  • 耐用性:对象存储被设计成高度耐用的,数据以冗余方式存储在多个位置。
  • 可用性:对象存储旨在提供高可用性,可以从世界任何地方访问数据。
  • 安全性:对象存储提供了许多安全功能,包括加密和访问控制。

对象存储是一种强大而灵活的数据存储架构,是存储大量非结构化数据、需要从多个位置访问的数据以及需要高可用性和安全性的数据的不错选择。

参考

管理 Secret

本教程演示如何在模型构建控制台中管理和使用 Secret

准备工作

创建 Secret

进入模型构建控制台,在左侧导航菜单(或右侧卡片)中点击辅助 > Secret 进入 Secret 管理页面。

overview-secret

点击 Secret 管理页面右上角的创建 Secret 进入 Secret 创建页面。

create-secret

在 Secret 创建页面选择模板,填写名称和要存储的数据,然后点击创建

create-secret-detail

你可以点击左上角的导入 Secret 以加载当前存在的 Secret 的配置。

删除 Secret

在 Secret 管理页面,点击要删除的 Secret 右侧的更多按钮 > 删除

delete-secret

管理 ConfigMap

本教程演示如何在模型构建控制台中管理和使用 ConfigMap

准备工作

创建 ConfigMap

进入模型构建控制台,在左侧导航菜单(或右侧卡片)中点击辅助 > ConfigMap 进入 ConfigMap 管理页面。

overview-configmap

点击 ConfigMap 管理页面右上角的创建 ConfigMap 进入 ConfigMap 创建页面。

create-configmap

在 ConfigMap 创建页面填写名称、标签和要存储的数据,然后点击创建

create-configmap-detail

你可以点击左上角的导入 ConfigMap 以加载当前存在的 ConfigMap 的配置。

删除 ConfigMap

在 ConfigMap 管理页面,点击要删除的 ConfigMap 右侧的更多按钮 > 删除

delete-configmap

运行模型训练

这一部分演示如何使用 T9k Job 运行不同机器学习框架的模型训练任务。对于常用的机器学习框架,如 PyTorch、TensorFlow、Horovod,你都可以在这里找到相应的教程来帮助你开始训练模型。

使用 PyTorchTrainingJob 进行数据并行训练

本教程演示如何使用 PyTorchTrainingJob 对 PyTorch 模型进行多工作器同步训练(使用 torch.nn.parallel.DistributedDataParallel 分布式数据并行模块)。

运行示例

请按照使用方法准备环境,然后前往本教程对应的示例,参照其 README 文档运行。

检查训练日志和指标

训练开始后,进入模型构建控制台的 Job 页面,可以看到名为 torch-mnist-trainingjob 的 PyTorchTrainingJob 正在运行:

running

点击该名称进入详情页面,可以看到刚才创建的 PyTorchTrainingJob 的基本信息、状况信息和事件信息:

details

点击 TensorBoard 右侧的 Running 打开 TensorBoard,可以查看可视化展示的训练和验证指标:

tensorboard

点击上方标签页的副本,查看 PyTorchTrainingJob 的 Pod 信息:

replicas

点击副本右侧的更多按钮 > 日志以查看训练脚本执行过程中的日志输出:

view-log

点击上方标签页的资源监测,查看 PyTorchTrainingJob 运行过程中使用集群计算资源、网络资源和存储资源的情况:

replicas

一段时间之后,PyTorchTrainingJob 的状态变为 Succeeded,表示训练成功完成。

done

若 PyTorchTrainingJob 在运行过程中出错,其状态会变为 Error,并在事件信息和 Pod 信息部分显示错误信息,此时需要根据给出的错误信息进行问题排查。

使用 PyTorchTrainingJob 进行参数服务器训练

本教程演示如何使用 PyTorchTrainingJob 对 PyTorch 模型进行基于 RPC 的参数服务器训练(使用分布式 RPC 框架 torch.distributed.rpc)。示例修改自 PyTorch 官方教程 Implementing a Parameter Server Using Distributed RPC Framework,关于训练脚本的更多细节信息请参考此教程。

运行示例

请按照使用方法准备环境,然后前往本教程对应的示例,参照其 README 文档运行。

检查训练日志和指标

训练开始后,进入模型构建控制台的 Job 页面,可以看到名为 torch-mnist-trainingjob-ps 的 PyTorchTrainingJob 正在运行:

running

点击该名称进入详情页面,可以看到刚才创建的 PyTorchTrainingJob 的基本信息、状况信息和事件信息:

details

点击 TensorBoard 右侧的 Running 打开 TensorBoard,可以查看可视化展示的训练和验证指标:

tensorboard

点击上方标签页的副本,查看 PyTorchTrainingJob 的 Pod 信息:

replicas

点击副本右侧的更多按钮 > 日志以查看训练脚本执行过程中的日志输出:

view-log

点击上方标签页的资源监测,查看 PyTorchTrainingJob 运行过程中使用集群计算资源、网络资源和存储资源的情况:

replicas

一段时间之后,PyTorchTrainingJob 的状态变为 Succeeded,表示训练成功完成。

done

若 PyTorchTrainingJob 在运行过程中出错,其状态会变为 Error,并在事件信息和 Pod 信息部分显示错误信息,此时需要根据给出的错误信息进行问题排查。

使用 TensorFlowTrainingJob 进行数据并行训练

本教程演示如何使用 TensorFlowTrainingJob 对 Keras 模型进行数据并行训练(采用 tf.distribute.MultiWorkerMirroredStrategy 分布式策略)。

运行示例

请按照使用方法准备环境,然后前往本教程对应的示例,参照其 README 文档运行。

检查训练日志和指标

训练开始后,进入模型构建控制台的 Job 页面,可以看到名为 keras-mnist-trainingjob 的 TensorFlowTrainingJob 正在运行:

running

点击该名称进入详情页面,可以看到刚才创建的 TensorFlowTrainingJob 的基本信息、状况信息和事件信息:

details

点击 TensorBoard 右侧的 Running 打开 TensorBoard,可以查看可视化展示的训练和验证指标:

tensorboard

点击上方标签页的副本,查看 TensorFlowTrainingJob 的 Pod 信息:

replicas

点击副本右侧的更多按钮 > 日志以查看训练脚本执行过程中的日志输出:

view-log

点击上方标签页的资源监测,查看 TensorFlowTrainingJob 运行过程中使用集群计算资源、网络资源和存储资源的情况:

replicas

一段时间之后,TensorFlowTrainingJob 的状态变为 Succeeded,表示训练成功完成。

done

若 TensorFlowTrainingJob 在运行过程中出错,其状态会变为 Error,并在事件信息和 Pod 信息部分显示错误信息,此时需要根据给出的错误信息进行问题排查。

使用 TensorFlowTrainingJob 进行参数服务器训练

本教程演示如何使用 TensorFlowTrainingJob 对 Keras 模型进行参数服务器(parameter server)训练(采用 tf.distribute.experimental.ParameterServerStrategy 分布式策略)。

运行示例

请按照使用方法准备环境,然后前往本教程对应的示例,参照其 README 文档运行。

检查训练日志和指标

训练开始后,进入模型构建控制台的 Job 页面,可以看到名为 keras-mnist-trainingjob-ps 的 TensorFlowTrainingJob 正在运行:

running

点击该名称进入详情页面,可以看到刚才创建的 TensorFlowTrainingJob 的基本信息、状况信息和事件信息:

details

点击 TensorBoard 右侧的 Running 打开 TensorBoard,可以查看可视化展示的训练和验证指标:

tensorboard

点击上方标签页的副本,查看 TensorFlowTrainingJob 的 Pod 信息:

replicas

点击副本右侧的更多按钮 > 日志以查看训练脚本执行过程中的日志输出:

view-log

点击上方标签页的指标,查看 TensorFlowTrainingJob 运行过程中使用集群计算资源、网络资源和存储资源的情况:

replicas

一段时间之后,TensorFlowTrainingJob 的状态变为 Succeeded,表示训练成功完成。

done

若 TensorFlowTrainingJob 在运行过程中出错,其状态会变为 Error,并在事件信息和 Pod 信息部分显示错误信息,此时需要根据给出的错误信息进行问题排查。

使用 Horovod 进行 PyTorch 模型的数据并行训练

本教程演示如何使用 MPIJob 对 PyTorch 模型进行多工作器同步训练(使用 horovod.torch 模块)。

运行示例

请按照使用方法准备环境,然后前往本教程对应的示例,参照其 README 文档运行。

检查训练日志和指标

训练开始后,进入模型构建控制台的 Job 页面,可以看到名为 torch-mnist-mpijob 的 MPIJob 正在运行:

running

点击该名称进入详情页面,可以看到刚才创建的 MPIJob 的基本信息、状况信息和事件信息:

details

点击上方标签页的副本,查看 MPIJob 的 Pod 信息:

replicas

点击副本右侧的更多按钮 > 日志以查看训练脚本执行过程中的日志输出:

view-log

点击上方标签页的指标,查看 MPIJob 运行过程中使用集群计算资源、网络资源和存储资源的情况:

replicas

一段时间之后,MPIJob 的状态变为 Succeeded,表示训练成功完成:

done

若 MPIJob 在运行过程中出错,其状态会变为 Error,并在事件信息和 Pod 信息部分显示错误信息,此时需要根据给出的错误信息进行问题排查。

使用 Horovod 进行 Keras 模型的数据并行训练

本教程演示如何使用 MPIJob 对 Keras 模型进行多工作器同步训练(使用 horovod.tensorflow.keras 模块)。

运行示例

请按照使用方法准备环境,然后前往本教程对应的示例,参照其 README 文档运行。

检查训练日志和指标

训练开始后,进入模型构建控制台的 Job 页面,可以看到名为 keras-mnist-mpijob 的 MPIJob 正在运行:

running

点击该名称进入详情页面,可以看到刚才创建的 MPIJob 的基本信息、状况信息和事件信息:

details

点击上方标签页的副本,查看 MPIJob 的 Pod 信息:

replicas

点击副本右侧的更多按钮 > 日志以查看训练脚本执行过程中的日志输出:

view-log

点击上方标签页的指标,查看 MPIJob 运行过程中使用集群计算资源、网络资源和存储资源的情况:

replicas

一段时间之后,MPIJob 的状态变为 Succeeded,表示训练成功完成:

done

若 MPIJob 在运行过程中出错,其状态会变为 Error,并在事件信息和 Pod 信息部分显示错误信息,此时需要根据给出的错误信息进行问题排查。

使用 Profiler 分析模型训练性能

概述

PyTorch 提供的 profiler 工具允许在训练和推理过程中收集性能指标,从而帮助用户更好地理解运算的代价和内存等资源消耗,测量 CPU 计算代价,CPU-GPU 之间数据复制成本,研究 GPU 内核程序性能并可视化执行追踪等。用户在 Notebook 中可以方便地使用这一工具。

本教程将介绍如何在 Notebook 中对启动 LLM 大规模预训练中的训练进行性能分析。

准备

启动 LLM 大规模预训练给出的准备工作的基础上,还需要修改 Megatron-DeepSpeed 的训练代码,用 profiler 上下文管理器包装训练循环的代码。直接使用 Notebook 的文本编辑器修改代码即可。

# Megatron-DeepSpeed/megatron/training.py
...

    profile_path = os.path.join(os.path.dirname(args.tensorboard_dir), 'profiling')

    with torch.profiler.profile(
            schedule=torch.profiler.schedule(wait=1, warmup=1, active=3, repeat=2),
            on_trace_ready=torch.profiler.tensorboard_trace_handler(profile_path),
            record_shapes=True,
            profile_memory=True,
            with_stack=True,
            with_flops=True,
            with_modules=True
    ) as prof:  # profiler context manager
        while iteration < args.train_iters and (args.train_tokens is None or \
            args.consumed_train_tokens < args.train_tokens):  # training loop

            ...

            prof.step()

...

其中对于 profiler 的配置为:

  • profiler 跳过 1 个 step,热身 1 个 step,然后记录 3 个 step;总共重复 2 次。
  • 生成用于 TensorBoard 展示的结果文件,与 TensorBoard 日志文件保存到同一父目录下。
  • 记录算子的源信息和输入形状,记录模块(module)的调用栈,估计 FLOPS,跟踪张量内存的分配和释放。

启动性能分析

以 4 个 GPU 训练 125M 参数的 GPT 模型,启动训练:

kubectl create -f \
  examples/deepspeed/megatron-gpt/training/gpt-125m-4xdp.yaml

通过以下命令查看训练过程中打印的日志:

kubectl logs gpt-125m-4xdp-worker-0 -f
log

性能分析完成之后,结果文件被保存在 output/gpt-125m-4xdp/profiling 路径下,前往该路径并启动一个 TensorBoard 实例以查看可视化结果。

create-tensorboard

查看可视化结果

Overview 展示了训练性能的总体情况,包含 GPU 的总体情况、不同执行类别花费的时间和占比,以及自动生成的性能优化建议:

overview

Operator View 展示了所有 PyTorch 算子被调用的次数、花费的时间以及它的调用栈:

operator-view

Kernel View 展示了所有 GPU 内核被调用的次数、花费的时间的统计以及它是否使用了 Tensor Core 等:

kernel-view

Memory View 展示了内存使用曲线图、内存事件(分配和释放)以及内存统计数据:

memory-view

TensorBoard 所展示的数据和提供的功能还远不止这些,请参阅官方教程以了解更多。这些数据应当能为用户分析和改进性能提供非常有用的帮助。

调试 Job

本教程演示如何使用 Job 的调试模式这一功能来对计算任务进行调试。

运行示例

请按照使用方法准备环境,然后前往本教程对应的示例,参照其 README 文档运行。

通过 SSH 远程连接

对于开启了 SSH 服务的容器,建立 SSH 连接的操作步骤和 Notebook 相同,请参照通过 SSH 远程使用 Notebook进行操作。唯一不同的是端口转发使用 t9k-pf pod 命令,而非 t9k-pf notebook 命令:

t9k-pf pod <POD_NAME> 5001:2222 -n <PROJECT_NAME>

进行调试

不论是进入休眠的容器,还是远程连接开启了 SSH 服务的容器,调试都是通过执行一些命令来进行。例如使用 nvidia-smi 命令检查当前可用的 GPU,再使用 ls 命令检查训练脚本是否存在:

# 在容器中
nvidia-smi
ls

然后使用 torchrun 命令启动训练:

# 在容器中
cd ~/tutorial-examples/job/debug
torchrun --nnodes 1 --nproc_per_node 4 --rdzv_backend c10d torch_mnist_trainingjob.py --save_path model_state_dict.pt --log_dir log --backend nccl

随即分布式训练开始进行。如果训练脚本出错,则可以立即在终端中进行调试,不会造成 Job 的失败。调试完成后禁用 debug 模式(将 spec.runMode.debug.enable 设为 false,或直接注释第 6-12 行),再次创建 PyTorchTrainingJob 则正常启动训练。

进行超参数优化

超参数优化是机器学习中的一项关键任务,其目标是选择一组最佳的超参数来改进模型性能。这一任务面临多重挑战:超参数通常不可微分,搜索空间高维且非凸,评估成本高,手动调参既繁琐又低效。为此 TensorStack AI 平台提供了自动化工具 AutoTune,其支持多种超参数优化算法,能够自动搜索超参数空间、存储搜索结果并进行可视化,并且配置简单,使用方便。

这一部分将使用 AutoTune 进行模型的超参数优化。

使用 AutoTune 进行超参数优化

本教程演示如何使用 AutoTune 对模型进行超参数优化(以 Keras 模型的单机训练为例)。

准备训练脚本

在开始超参数优化实验之前,你需要提前准备训练脚本。你可以使用模型构建控制台中的 Notebook 编辑训练脚本。

创建 PVC

参照创建 PVC 教程创建名为 autotune-mnist-keras、大小为 1Gi 的 PVC。

创建 Notebook

从模型构建控制台进入 Notebook 列表,点击右上角的创建 Notebook

notebook-table

创建 Notebook 时,在存储卷选择前面创建的 PVC 的名称 autotune-mnist-keras

create-notebook

创建完成之后,点击打开进入 Notebook。

after-creating-notebook

在 Notebook 中编辑训练脚本

以下是一个 Keras 训练脚本,在此基础上做简单的修改以应用在 AutoTune 实验中。

import argparse
import json
import logging
import os
import time

import tensorflow as tf
from tensorflow.keras import callbacks, datasets, layers, models, optimizers

parser = argparse.ArgumentParser(
    description='Distributed training of Keras model for MNIST with '
    'MultiWorkerMirroredStrategy.')
parser.add_argument('--log_dir',
                    type=str,
                    default=None,
                    help='Path of the TensorBoard log directory.')
parser.add_argument('--no_cuda',
                    action='store_true',
                    default=False,
                    help='Disable CUDA training.')
parser.add_argument('--save_path',
                    type=str,
                    default=None,
                    help='Save path of the trained model.')
args = parser.parse_args()
logger = logging.getLogger('print')
logger.setLevel(logging.INFO)
logger.addHandler(logging.StreamHandler())
logger.propagate = False

if args.no_cuda:
    tf.config.set_visible_devices([], 'GPU')
gpus = tf.config.get_visible_devices('GPU')
if gpus:
    # Print GPU info
    logger.info('NVIDIA_VISIBLE_DEVICES: {}'.format(
        os.getenv('NVIDIA_VISIBLE_DEVICES')))
    logger.info('T9K_GPU_PERCENT: {}'.format(os.getenv('T9K_GPU_PERCENT')))
    logger.info('Visible GPUs: {}'.format(
        tf.config.get_visible_devices('GPU')))
    # Set memory growth
    for gpu in gpus:
        tf.config.experimental.set_memory_growth(gpu, True)
    # # Set GPU memory limit
    # tf.config.set_logical_device_configuration(
    #     gpus[0], [tf.config.LogicalDeviceConfiguration(memory_limit=1024)])

strategy = tf.distribute.MultiWorkerMirroredStrategy()

# Get information for current worker.
tf_config = json.loads(os.environ['TF_CONFIG'])
world_size = len(tf_config['cluster']['worker'])
task_index = tf_config['task']['index']

params = {
    # Search space:
    # 'batch_size': ...
    # 'learning_rate': ...
    # 'conv_channels1': ...
    'epochs': 10,
    'conv_channels2': 64,
    'conv_channels3': 64,
    'conv_kernel_size': 3,
    'maxpool_size': 2,
    'linear_features1': 64,
    'seed': 1,
}

with strategy.scope():
    model = models.Sequential([
        layers.Conv2D(params['conv_channels1'],
                      params['conv_kernel_size'],
                      activation='relu',
                      input_shape=(28, 28, 1)),
        layers.MaxPooling2D((params['maxpool_size'], params['maxpool_size'])),
        layers.Conv2D(params['conv_channels2'],
                      params['conv_kernel_size'],
                      activation='relu'),
        layers.MaxPooling2D((params['maxpool_size'], params['maxpool_size'])),
        layers.Conv2D(params['conv_channels3'],
                      params['conv_kernel_size'],
                      activation='relu'),
        layers.Flatten(),
        layers.Dense(params['linear_features1'], activation='relu'),
        layers.Dense(10, activation='softmax'),
    ])
    model.compile(
        optimizer=optimizers.Adam(learning_rate=params['learning_rate']),
        loss='sparse_categorical_crossentropy',
        metrics=['accuracy'])

(train_images, train_labels), (test_images,
                               test_labels) = datasets.mnist.load_data(
                                   path=os.path.join(os.getcwd(), 'mnist.npz'))
train_images = train_images.reshape((60000, 28, 28, 1)).astype("float32") / 255
test_images = test_images.reshape((10000, 28, 28, 1)).astype("float32") / 255
train_images, val_images = train_images[:48000], train_images[48000:]
train_labels, val_labels = train_labels[:48000], train_labels[48000:]
train_dataset = tf.data.Dataset.from_tensor_slices(
    (train_images, train_labels)).shuffle(
        48000, seed=params['seed']).repeat().batch(params['batch_size'])
val_dataset = tf.data.Dataset.from_tensor_slices(
    (val_images, val_labels)).batch(400)
test_dataset = tf.data.Dataset.from_tensor_slices(
    (test_images, test_labels)).batch(1000)

model.fit(train_images,
          train_labels,
          batch_size=params['batch_size'],
          epochs=params['epochs'],
          validation_split=0.2,
          verbose=2)

# TODO: Automatically save best n models.
# if args.save_path and task_index == 0:
#     t9k.autotune.utils.save_best_n_models(model, args.save_path)

model.evaluate(test_images, test_labels, callbacks=test_callbacks, verbose=2)

if task_index > 0:
    # wait a while for index 0
    time.sleep(1)

在上述脚本中导入 t9k.tuner 模块,在训练模型之前调用 get_next_parameter() 函数获取训练超参数,替换原来的参数。

from t9k import tuner

def main():
    ...
    tuner_params = tuner.get_next_parameter()
    params.update(tuner_params)
    ...

在训练过程中,添加 AutoTuneCallback 上传实验指标。

train_callbacks = []
test_callbacks = []

if task_index == 0:
    from t9k.tuner.keras import AutoTuneFitCallback, AutoTuneEvalCallback
    train_callbacks.append(AutoTuneFitCallback(metric='accuracy'))
    test_callbacks.append(AutoTuneEvalCallback(metric='accuracy'))
    if args.log_dir:
        tensorboard_callback = callbacks.TensorBoard(log_dir=args.log_dir)
        train_callbacks.append(tensorboard_callback)

如下为修改后的训练脚本:

import argparse
import json
import logging
import os
import time

import tensorflow as tf
from tensorflow.keras import callbacks, datasets, layers, models, optimizers

from t9k import tuner

parser = argparse.ArgumentParser(
    description='Distributed training of Keras model for MNIST with '
    'MultiWorkerMirroredStrategy.')
parser.add_argument('--log_dir',
                    type=str,
                    default=None,
                    help='Path of the TensorBoard log directory.')
parser.add_argument('--no_cuda',
                    action='store_true',
                    default=False,
                    help='Disable CUDA training.')
parser.add_argument('--save_path',
                    type=str,
                    default=None,
                    help='Save path of the trained model.')
args = parser.parse_args()
logger = logging.getLogger('print')
logger.setLevel(logging.INFO)
logger.addHandler(logging.StreamHandler())
logger.propagate = False

if args.no_cuda:
    tf.config.set_visible_devices([], 'GPU')
gpus = tf.config.get_visible_devices('GPU')
if gpus:
    # Print GPU info
    logger.info('NVIDIA_VISIBLE_DEVICES: {}'.format(
        os.getenv('NVIDIA_VISIBLE_DEVICES')))
    logger.info('T9K_GPU_PERCENT: {}'.format(os.getenv('T9K_GPU_PERCENT')))
    logger.info('Visible GPUs: {}'.format(
        tf.config.get_visible_devices('GPU')))
    # Set memory growth
    for gpu in gpus:
        tf.config.experimental.set_memory_growth(gpu, True)
    # # Set GPU memory limit
    # tf.config.set_logical_device_configuration(
    #     gpus[0], [tf.config.LogicalDeviceConfiguration(memory_limit=1024)])

strategy = tf.distribute.MultiWorkerMirroredStrategy()

# Get information for current worker.
tf_config = json.loads(os.environ['TF_CONFIG'])
world_size = len(tf_config['cluster']['worker'])
task_index = tf_config['task']['index']

tuner_params = tuner.get_next_parameter()
params = {
    # Search space:
    # 'batch_size': ...
    # 'learning_rate': ...
    # 'conv_channels1': ...
    'epochs': 10,
    'conv_channels2': 64,
    'conv_channels3': 64,
    'conv_kernel_size': 3,
    'maxpool_size': 2,
    'linear_features1': 64,
    'seed': 1,
}
params.update(tuner_params)

with strategy.scope():
    model = models.Sequential([
        layers.Conv2D(params['conv_channels1'],
                      params['conv_kernel_size'],
                      activation='relu',
                      input_shape=(28, 28, 1)),
        layers.MaxPooling2D((params['maxpool_size'], params['maxpool_size'])),
        layers.Conv2D(params['conv_channels2'],
                      params['conv_kernel_size'],
                      activation='relu'),
        layers.MaxPooling2D((params['maxpool_size'], params['maxpool_size'])),
        layers.Conv2D(params['conv_channels3'],
                      params['conv_kernel_size'],
                      activation='relu'),
        layers.Flatten(),
        layers.Dense(params['linear_features1'], activation='relu'),
        layers.Dense(10, activation='softmax'),
    ])
    model.compile(
        optimizer=optimizers.Adam(learning_rate=params['learning_rate']),
        loss='sparse_categorical_crossentropy',
        metrics=['accuracy'])

(train_images, train_labels), (test_images,
                               test_labels) = datasets.mnist.load_data(
                                   path=os.path.join(os.getcwd(), 'mnist.npz'))
train_images = train_images.reshape((60000, 28, 28, 1)).astype("float32") / 255
test_images = test_images.reshape((10000, 28, 28, 1)).astype("float32") / 255
train_images, val_images = train_images[:48000], train_images[48000:]
train_labels, val_labels = train_labels[:48000], train_labels[48000:]
train_dataset = tf.data.Dataset.from_tensor_slices(
    (train_images, train_labels)).shuffle(
        48000, seed=params['seed']).repeat().batch(params['batch_size'])
val_dataset = tf.data.Dataset.from_tensor_slices(
    (val_images, val_labels)).batch(400)
test_dataset = tf.data.Dataset.from_tensor_slices(
    (test_images, test_labels)).batch(1000)

train_callbacks = []
test_callbacks = []

if task_index == 0:
    from t9k.tuner.keras import AutoTuneFitCallback, AutoTuneEvalCallback
    train_callbacks.append(AutoTuneFitCallback(metric='accuracy'))
    test_callbacks.append(AutoTuneEvalCallback(metric='accuracy'))
    if args.log_dir:
        tensorboard_callback = callbacks.TensorBoard(log_dir=args.log_dir)
        train_callbacks.append(tensorboard_callback)

model.fit(train_images,
          train_labels,
          batch_size=params['batch_size'],
          epochs=params['epochs'],
          validation_split=0.2,
          callbacks=train_callbacks,
          verbose=2)

# TODO: Automatically save best n models.
# if args.save_path and task_index == 0:
#     t9k.autotune.utils.save_best_n_models(model, args.save_path)

model.evaluate(test_images, test_labels, callbacks=test_callbacks, verbose=2)

if task_index > 0:
    # wait a while for index 0
    time.sleep(1)

在 Notebook 中创建文件 main.py,写入上述脚本并保存文件。

notebook-detail

创建 download_dataset.py 文件,写入并执行以下脚本来下载实验数据。

import os
import tensorflow as tf

_, _ = tf.keras.datasets.mnist.load_data(os.path.join(os.getcwd(), 'mnist.npz'))
notebook-download-script
download-data

准备数据库

你可以使用实验管理平台(以下称 EM)记录超参数调优实验中的超参数组合和训练结果。(如果你选择不使用 EM 持久记录 AutoTune 实验结果,请忽略这一步,并在开始实验时删掉 AutoTuneExperiment 的 spec.aistore 字段)

在实验管理控制台中新建文件夹

EM 的实验数据是以文件夹形式管理的,所以你首先需要在实验管理控制台点击右上角的 + 新建一个文件夹。

create-aistore-folder

进入文件夹,点击 ID 来复制该文件夹的 ID。

folder-id

获得访问 EM 所需的 API Key

在超参数优化实验中,如果你希望使用 EM 来存储实验数据,需要生成一个具有访问 EM 文件夹权限的 API Key,你可以通过这个 API Key 上传实验数据。

你需要按照生成 API Key 教程中的步骤,在安全控制台中生成一个 API Key,其中必须勾选 AIStore 选项。

create-apikey

生成 API Key 之后,点击复制按钮复制该 API Key。

after-creating-apikey

然后,你需要按照管理 Secret 教程中的步骤,在模型构建控制台中将所复制的 API Key 存入名为 aistore 的 Secret 中,以方便后续实验使用。

create-apikey-secret

开始实验

在模型构建控制台的 AutoTune 列表页面,点击右上角的创建 AutoTuneExperiment 进入 AutoTuneExperiment 创建页面。

autotune-table

在 AutoTuneExperiment 创建页面,点击预览 YAML,输入以下配置,点击创建

apiVersion: tensorstack.dev/v1beta1
kind: AutoTuneExperiment
metadata:
  name: autotune-mnist-keras
spec:
  maxExecSeconds: 3600
  maxTrialNum: 20
  trialConcurrency: 3
  storage: 100Mi
  aistore:
    secret: 'aistore'
    folder: 'b6c17378-965c-4467-9a43-eed65597f976'
  searchSpace: |-
    {
      "batch_size": {"_type": "choice", "_value": [16, 32, 64, 128]},
      "learning_rate": {"_type": "choice", "_value": [0.0001, 0.001, 0.01, 0.1]},
      "conv_channels1": {"_type": "choice", "_value": [16, 32, 64, 128]}
    }
  trainingConfig:
    type: tensorflow
    tasks:
      - type: worker
        replicas: 4
        template:
          spec:
            securityContext:
              runAsUser: 1000
            containers:
              - command:
                  - sh
                  - -c
                  - "python3 main.py --log_dir /mnt/log --no_cuda"
                workingDir: /mnt/
                imagePullPolicy: IfNotPresent
                image: t9kpublic/tensorflow-2.5.1:20220216
                name: tensorflow
                resources:
                  requests:
                    cpu: 2000m
                    memory: 2Gi
                  limits:
                    cpu: 4000m
                    memory: 4Gi
                volumeMounts:
                  - mountPath: /mnt
                    name: data
            volumes:
              - name: data
                persistentVolumeClaim:
                  claimName: autotune-mnist-keras
  tuner:
    builtinTunerName: TPE
    classArgs: |-
      {
        "optimize_mode": "maximize", 
        "constant_liar_type": "min"
      }

在此例中,实验绑定了准备过程中创建的名为 autotune-mnist-keras 的 PVC,其中存有在 Notebook 中编辑的训练脚本;使用了名为 aistore 的存有 API Key 的 Secret;填入了前面创建的 EM Folder 的 ID。

create-autotune

查看实验

你可以在 AutoTune 列表页面看到已创建的 AutoTuneExperiment,点击连接进入实验详情页面。

after-creating-autotune

下图为实验详情页面,你可以在该页面查看实验基本信息、各试验的参数与结果,以及查看试验之间的对比。

autotune-detail
trial-detail

部署模型推理服务

这一部分演示如何使用平台的模型部署模块部署推理服务。

简单推理服务

本教程演示如何使用 SimpleMLService 快速部署一个模型推理服务。

运行示例

请按照使用方法准备环境,然后前往本教程的示例,参照其 README 文档运行。本示例使用 PVC 中存储的模型创建了一个 SimpleMLService 服务。

查看推理服务状态

部署完成后,进入模型部署控制台的 SimpleMLService 页面,可以看到名为 mnist 的 SimpleMLService。

list

点击 SimpleMLService 的名称 mnist 可以看见 SimpleMLService 的基本信息,其中 URL 是在集群内访问这个推理服务的地址:

detail

参考

模型推理服务

本教程演示如何使用 MLService 部署一个功能完善、自动化程度高,可用于生产环境的模型推理服务。

运行示例

请按照使用方法准备环境,然后前往本教程的示例,参照其 README 文档运行。本示例使用 PVC 中存储的模型创建了一个 MLService 服务。

查看推理服务状态

部署完成后,进入模型部署控制台的 MLService 页面,可以看到名为 torch-mnist-pvc 的 MLService,稍等片刻,等其进入 Ready 状态:

ready

使用推理服务

你可以直接使用命令行工具访问 MLService 的预测服务。运行命令获取 MLService 的 URL:

url=$(kubectl get mlservice torch-mnist-pvc -o jsonpath='{.status.address.url}') && echo $url

发送推理请求:

curl -T test_data/0.png ${url}/v1/models/mnist:predict # or use `1.png`, `2.png`

监控推理服务

在模型部署控制台,点击对应的 MLService,然后切换到资源监测页面,可以查看该 MLService 的资源统计:

resource-usage

参考

包含 Transformer 的推理服务

本教程演示如何使用 TensorStack SDK 创建 Transformer 镜像,然后部署包含该 Transformer 的 MLService。

准备工作

请按照使用方法准备此次部署需要用到的 PVC 和 Notebook。

编写 Transformer 逻辑

接下来开始制作供 MLService 使用的 Transformer 镜像。首先进入 Notebook,启动一个终端,切换到对应目录:

cd ~/tutorial-examples/deployment/mlservice/transformer

查看文件 server.py ,内容如下:

import json
from t9k import mlservice

import argparse
import io
import numpy as np
from PIL import Image
from typing import Dict

# inherit parser to get command-line-args help
# feel free to add your command line args
par = argparse.ArgumentParser(parents=[mlservice.option.parser])
args, _ = par.parse_known_args()

def image_transform(instance):
    image = Image.open(io.BytesIO(instance))
    a = np.asarray(image)
    a = a / 255.0
    return a.reshape(28, 28, 1).tolist()

class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']

def get_prediction(prediction: list)->str:
    max_value = max(prediction)
    max_index = prediction.index(max_value)
    return class_names[max_index]

class Transformer(mlservice.MLTransformer):
    def preProcess(self, path: str, requestData: bytes, headers: Dict[str, str]) -> any:
        return json.dumps({'instances': [image_transform(requestData)]})

    def postProcess(self, path: str, statusCode: int, responseContent: bytes, headers: Dict[str, str]) -> bytes:
        data = responseContent.decode('utf-8')
        jsonData = json.loads(data)
        jsonStr = json.dumps({'predictions': [get_prediction(predict) for predict in jsonData['predictions']]})
        return jsonStr.encode('utf-8')
    
if __name__ == "__main__":
    transformer = Transformer()
    server = mlservice.MLServer()
    server.start(transformer=transformer)

代码中使用了 TensorStack SDK,通过重载 preprocesspostprocess 方法实现了一个 Transformer:

  • preprocess:预处理函数,Transformer 收到用户发送的数据,使用 preprocess 对数据进行处理,然后再发送给推理服务。在这个示例中,先转换输入图片的数据格式,需要保持与训练的模型的输入数据一致,然后再转换为推理服务的输入格式。
  • postprocess:后处理函数,Transformer 收到推理服务返回的结果,使用 postprocess 对其进行处理,然后再返回给用户。在这个示例中,模型用于处理分类问题,从推理服务返回的预测概率向量中解析出该图片的分类类别,并返回给用户。

用户可以参考该文件来实现自定义的 Transformer 逻辑。

制作镜像

基于上述代码,我们创建对应的 Dockerfile 如下:

FROM python:3.8-slim

COPY t9k-sdk.tar.gz t9k-sdk.tar.gz
COPY server.py server.py

RUN pip install --upgrade pip
RUN pip install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple \
    numpy \
    pillow \
    requests
RUN pip install t9k-sdk.tar.gz  -i https://pypi.tuna.tsinghua.edu.cn/simple

ENTRYPOINT ["python", "server.py"]

上述 Dockerfile 引入了相关依赖,并将上一步的 server.py 文件作为启动命令。用户可以参考该文件来实现自定义的镜像。

然后我们通过运行一个 ImageBuilder 来制作镜像,为了使用 ImageBuilder,首先我们需要参照创建 Secret准备上传镜像所需要的 DockerConfig Secret

完成后修改 imagebuilder.yaml 文件,将 spec.dockerConfig.secret 修改为上一步中创建的 DockerConfig Secret 的名称,并将 spec.tag 修改为目标镜像,并执行以下命令:

kubectl apply -f imagebuilder.yaml

查看 ImageBuilder 状态,等待 Phase 一栏变为 Succeeded

kubectl get -f imagebuilder.yaml -w

部署 MLService

进入模型部署控制台,先点击左侧导航栏辅助一栏下的的 MLServiceRuntime,再点击 创建 MLServiceRuntime ,然后点击 预览 YAML, 并将下面内容复制到 YAML 编辑框中,最后点击 创建 创建 MLServiceRuntime。

apiVersion: tensorstack.dev/v1beta1
kind: MLServiceRuntime
metadata:
  name: t9k-tensorflow-serving
spec:
  enabled: true
  template:
    spec:
      containers:
      - name: user-container
        image: t9kpublic/tensorflow-serving:2.13.1
        command:
          - /usr/bin/tensorflow_model_server
        args:
          - --model_name={{if .MODEL_NAME}}{{.MODEL_NAME}}{{else}}model{{end}}
          - --port={{if .GRPC_PORT}}{{.GRPC_PORT}}{{else}}9000{{end}}
          - --rest_api_port=8000
          - --model_base_path=/var/lib/t9k/model
        resources:
          limits:
            cpu: "200m"
            memory: 200Mi
        ports:
        - containerPort: 8000
          protocol: TCP

进入模型部署控制台的 MLService 页面,点击右上角创建 MLService,然后点击预览 YAML。如下图所示,将下述内容复制到右侧的 YAML 编辑框,最后点击 创建 创建 MLService:

apiVersion: tensorstack.dev/v1beta1
kind: MLService
metadata:
  name: pic-mnist
spec:
  default: origin
  transformer:
    minReplicas: 1
    template:
      spec:
        containers:
        - name: user-container
          image: "<your-docker-registry-address>/mnist-transformer:test"
  releases:
    - name: origin
      predictor:
        minReplicas: 1
        model:
          runtime: t9k-tensorflow-serving
          modelUri: pvc://tutorial/tutorial-examples/deployment/mlservice/transformer/model/
create-mlservcie-transformer

<<<<<<< HEAD 你可以直接使用命令行工具访问 MLService 的预测服务。运行命令获取 MLService 的 URL:

发送预测请求

使用图片 shoe.png 作为测试数据发送预测请求。 >>>>>>> parent of 816714b (Update mlservice (#51))

address=$(kubectl get mls pic-mnist -ojsonpath='{.status.address.url}') && echo $address
curl --data-binary @./shoe.png ${address}/v1/models/model:predict

参考

管理 AI 资产

这一部分演示如何使用 AsestHub 上传、使用和分享模型和数据集。

操作文件夹、模型和数据集

本教程演示如何通过多种方式操作文件夹、模型和数据集,包括创建、查看和删除。

准备工作

通过命令行工具

切换到你的工作路径下:

$ cd /your/workpath

假设当前用户(这里假设用户名为 demo)没有可以访问的文件夹,使用 ah create 命令创建一个模型文件夹和一个数据集文件夹:

$ ah create model/llm
AH INFO: Folder /demo/t9k-assethub/model/llm created

$ ah create dataset/text
AH INFO: Folder /demo/t9k-assethub/dataset/text created

然后使用 ah create 命令在模型文件夹中创建一个模型,以及在数据集文件夹中创建一个数据集:

$ ah create model/llm/gpt2
AH INFO: Model gpt2 created for Folder /demo/t9k-assethub/model/llm

$ ah create dataset/text/openwebtext
AH INFO: Dataset openwebtext created for Folder /demo/t9k-assethub/dataset/text

创建完成之后,使用 ah ls 命令查看当前用户的模型文件夹和数据集文件夹:

$ ah ls model
NAME    PATH                          LABELS    PERMISSION
llm     /demo/t9k-assethub/model/llm             own

$ ah ls dataset
NAME    PATH                              LABELS    PERMISSION
text    /demo/t9k-assethub/dataset/text              own

使用 ah ls 命令查看模型文件夹下的所有模型以及数据集文件夹下的所有数据集:

$ ah ls model/llm
NAME    PATH                              LABELS    PERMISSION
gpt2    /demo/t9k-assethub/model/llm/gpt2            own

$ ah ls dataset/text
NAME         PATH                                        LABELS    PERMISSION
openwebtext  /demo/t9k-assethub/dataset/text/openwebtext            own

最后使用 ah delete 命令删除所有创建的模型、数据集和文件夹:

$ ah delete model/llm/gpt2
AH INFO: Model /demo/t9k-assethub/model/llm/gpt2 deleted

$ ah delete dataset/text/openwebtext
AH INFO: Dataset /demo/t9k-assethub/dataset/text/openwebtext deleted

# 可以直接删除文件夹, 其中的模型或数据集都会被一并删除
$ ah delete model/llm
AH INFO: Folder /demo/t9k-assethub/model/llm deleted

$ ah delete dataset/text
AH INFO: Folder /demo/t9k-assethub/dataset/text deleted

通过 Python SDK

切换到你的工作路径下,然后以任意方式执行下面的 Python 代码。

导入 t9k.ah 模块,使用 ah.login() 函数登录到 Asset Hub 服务器(如果配置文件中的凭据仍有效,则无需提供参数):

from t9k import ah

ah.login(host='<asset-hub-server-url>',
         api_key='<your-api-key>')
AH INFO: Logged in to Asset Hub server and AIStore server as user <your-user-name>

假设当前用户(这里假设用户名为 demo)没有可以访问的文件夹,使用 ah.create() 函数创建一个模型文件夹和一个数据集文件夹,各返回一个 Folder 实例:

model_folder = ah.create('model/llm')
dataset_folder = ah.create('dataset/text')
AH INFO: Folder /demo/t9k-assethub/model/llm created
AH INFO: Folder /demo/t9k-assethub/dataset/text created

继续使用 ah.create() 函数在模型文件夹中创建一个模型,以及在数据集文件夹中创建一个数据集:

model = ah.create('model/llm/gpt2')
dataset = ah.create('dataset/text/openwebtext')
AH INFO: Model gpt2 created for Folder /demo/t9k-assethub/model/llm
AH INFO: Dataset openwebtext created for Folder /demo/t9k-assethub/dataset/text

创建完成之后,使用 ah.list() 函数返回当前用户的文件夹:

from pprint import pprint

pprint(ah.list('model'))
pprint(ah.list('dataset'))
[{'description': '',
  'editor': 'demo',
  'extra': '{"createdTimestamp": "2023-08-17T08:05:24.044319Z"}',
  'id': '967a5135-8b13-4283-9fad-ba53503612b3',
  'labels': [],
  'modifiedTimestamp': '2023-08-17T08:05:24.390002Z',
  'name': 'llm',
  'path': '/demo/t9k-assethub/model/llm',
  'permission': 'own',
  'storageType': 0,
  'type': 'Folder'}]
[{'description': '',
  'editor': 'demo',
  'extra': '{"createdTimestamp": "2023-08-17T08:05:24.196610Z"}',
  'id': 'd0d9f4b2-6c15-4dbb-b2d1-0619b6774c4a',
  'labels': [],
  'modifiedTimestamp': '2023-08-17T08:05:24.519213Z',
  'name': 'text',
  'path': '/demo/t9k-assethub/dataset/text',
  'permission': 'own',
  'storageType': 0,
  'type': 'Folder'}]

继续使用 ah.list() 函数返回模型文件夹下的所有模型和数据集文件夹下的所有数据集:

pprint(ah.list('model/llm'))
pprint(ah.list('dataset/text'))
[{'description': '',
  'editor': 'demo',
  'extra': '{"createdTimestamp": "2023-08-17T08:11:09.948554Z"}',
  'id': '2157a139-e20b-4736-9e25-d4495e287af8',
  'labels': [],
  'modifiedTimestamp': '2023-08-17T08:11:10.327166Z',
  'name': 'gpt2',
  'path': '/demo/t9k-assethub/model/llm/gpt2',
  'permission': 'own',
  'storageType': 3,
  'type': 'Model'}]
[{'description': '',
  'editor': 'demo',
  'extra': '{"createdTimestamp": "2023-08-17T08:11:10.508407Z"}',
  'id': '6826131c-2c88-483e-8a48-0f6d8fa59cfa',
  'labels': [],
  'modifiedTimestamp': '2023-08-17T08:11:10.830665Z',
  'name': 'openwebtext',
  'path': '/demo/t9k-assethub/dataset/text/openwebtext',
  'permission': 'own',
  'storageType': 3,
  'type': 'Dataset'}]

最后使用 ah.delete() 函数删除所有创建的模型、数据集和文件夹:

ah.delete('model/llm/gpt2')
ah.delete('dataset/text/openwebtext')
ah.delete('model/llm')    # 可以直接删除文件夹, 其中的模型或数据集都会被一并删除
ah.delete('dataset/text')
AH INFO: Model /demo/t9k-assethub/model/llm/gpt2 deleted
AH INFO: Dataset /demo/t9k-assethub/dataset/text/openwebtext deleted
AH INFO: Folder /demo/t9k-assethub/model/llm deleted
AH INFO: Folder /demo/t9k-assethub/dataset/text deleted

通过控制台

数据集文件夹、数据集的控制台操作分别和模型文件夹、模型完全一致。本教程后续仅展示模型文件夹和模型的创建、查看、删除、分享功能,你可以用同样的方式操作数据集文件夹和数据集。

在左侧的导航菜单中点击模型,选择查看范围为 My Own,查看当前用户的所有模型文件夹。然后点击右上角的 + 创建新的模型文件夹:

model-all

填写名称 image-classification,点击创建

folder-create

接下来分享这个文件夹。点击文件夹右侧的 更多 > 分享

folder-share

点击添加分享目标,选择分享的对象为 Public(所有用户可见),分享的权限是 Edit,最后点击分享

folder-share-setting

回到 Asset Hub 控制台,点击模型文件夹 image-classification 查看其中的模型:

folder-list

新创建的模型文件夹中没有模型,点击右上角的 + 创建一个模型:

model-list

填写名称 mnist,然后点击创建

model-create

创建成功后,在模型文件夹中可以看到模型信息:

model-created

点击更多 > 删除,删除创建的模型,然后点击左上角的返回,返回模型文件夹的页面:

model-delete

最后,返回 Asset Hub 控制台,点击更多 > 删除,删除模型文件夹:

folder-delete

通过 S3 访问模型和数据集

本教程演示如何 S3 访问模型。

数据集同理。

准备工作

创建 S3 凭证

在 AssetHub 控制台进入模型详情页面,点击 S3 凭证可以查看目前已有的所有 S3 凭证。然后点击表格右上角的 + 创建一个 S3 凭证:

s3-cred-list

填写名称 s3-rw,选择类型为可读/可写,最后点击创建

s3-cred-create

查看 S3 凭证

创建完成后,点击表格左上角的可读/可写,查看所有类型为可读/可写的 S3 凭证:

s3-cred-list-rw

点击刚刚创建的 S3 凭证 s3-rw,查看其详情:

s3-cred-detail

S3 凭证有三种格式:

  1. .s3cfg:命令行工具 s3cmd 的配置文件。
  2. S3-cfg Secret:s3cfg 形式的 Secret YAML,创建后可在 Notebook、Job、Workflow 等工作负载时挂载此 Secret。
  3. S3-env Secret:s3 环境变量形式的 Secret YAML,创建后可在 Notebook、Job、Workflow 等工作负载时挂载此 Secret。

通过 s3cmd 访问模型

点击右侧的复制,复制 .s3cfg 格式的 S3 凭证,保存在 $HOME/.s3cfg 文件中,即可通过 s3cmd 命令行工具访问此模型中的文件。

例如,在上述示例中,所创建的 S3 凭证 s3-rw 仅可用于访问名为 neox 的模型。根据页面上的提示,此模型对应的 bucket 名称为 adb2a768-f01a-467b-b146-e82c0693c16b,用户可以通过以下命令查看此模型的 main 分支的 README.md 文件:

s3cmd ls s3://baa98ded-2f93-4e9b-835a-6515a63a6eb4/main/README.md

通过以下命令下载此模型的某个分支下某个路径的文件:

s3cmd get s3://baa98ded-2f93-4e9b-835a-6515a63a6eb4/branch-name/path/to/object

通过 StorageShim 访问模型

除了通过命令行工具访问,用户还可以创建一个 StorageShim,将 S3 bucket 的某个子路径形式化为一个持久卷,以便在 Notebook、Job、Workflow 等工作负载中挂载,直接以文件系统的形式查看、编辑 S3 bucket 中的文件。

在创建 StorageShim 之前,用户首先需要创建一个 Secret 保存 S3 bucket 的相关信息。在 S3 凭证的详情页面,点击左侧的 S3-cfg Secret 标签,然后点击右上角的复制

s3-cred-detail-s3-cfg-secret

在模型构建控制台的左侧导航菜单中点击辅助 > Secret 进入 Secret 管理页面,然后点击右上角的创建 Secret进入 Secret 创建页面:

secret-list

在 Secret 创建页面,点击预览 YAML,将所复制的 S3-cfg Secret 粘贴到 YAML 编辑框中,最后点击创建

secret-create

在模型构建控制台的左侧导航菜单中点击存储 > 持久卷进入持久卷管理页面,然后点击上方的 S3 进入 S3 类型的持久卷管理页面,最后点击右上角的创建进入 StorageShim 创建页面:

storageshim-list

在 StorageShim 创建页面,

  1. 名称填写 neox
  2. 类型选择 S3
  3. S3 URI 填写 s3://adb2a768-f01a-467b-b146-e82c0693c16b/main,以便把上述示例模型的 main 分支挂载为持久卷;
  4. S3 Secret 选择刚刚创建的 s3-rw

最后点击创建

storageshim-create

StorageShim 创建完成后,等待其阶段变为 Bound,用户即可通过以下方式使用这个名为 neox 的持久卷:

  1. 点击启动,创建一个 Explorer 来浏览持久卷中的文件。
  2. 在创建 Notebook 时,添加持久卷 neox,以便在 Notebook 中查看和编辑此模型中的文件。
  3. 在创建 Job 时,添加持久卷 neox,以便在 Job 中使用此模型中的文件。
storageshim-list-after-create

修改文件夹、模型和数据集的基本信息

本教程演示如何通过多种方式修改文件夹、模型和数据集的基本信息。

准备工作

通过命令行工具

切换到你的工作路径下:

$ cd /your/workpath

修信息的方式对于文件夹、模型和数据集都是相同的。下面将以模型文件夹和模型为例进行演示(这里假设用户名为 demo)。

依次创建模型文件夹和模型:

$ ah create model/llm
AH INFO: Folder /demo/t9k-assethub/model/llm created

$ ah create model/llm/gpt2
AH INFO: Model gpt2 created for Folder /demo/t9k-assethub/model/llm

使用 ah update 命令修改文件夹和模型的名称:

$ ah update model/llm -n chat
AH INFO: Folder /demo/t9k-assethub/model/llm updated to /demo/t9k-assethub/model/chat

$ ah update model/chat/gpt2 -n gpt3
AH INFO: Model /demo/t9k-assethub/model/chat/gpt2 updated to /demo/t9k-assethub/model/chat/gpt3

使用 ah ls 命令查看文件夹和模型的标签:

$ ah ls model --detail
NAME    PATH                          ...  LABELS  ...
chat    /demo/t9k-assethub/model/chat

$ ah ls model/chat
NAME    PATH                               LABELS  ...
gpt3    /demo/t9k-assethub/model/chat/gpt3

两者都没有标签,再次使用 ah update 命令为它们添加标签:

$ ah update model/chat --label "NLP" --label "AIGC"
AH INFO: Folder /demo/t9k-assethub/model/chat updated

$ ah ls model --detail
NAME    PATH                          ...  LABELS     ...
chat    /demo/t9k-assethub/model/chat       AIGC, NLP
$ ah update model/chat/gpt3 --label "GPT"
AH INFO: Model /demo/t9k-assethub/model/chat/gpt3 updated

$ ah ls model/chat
NAME    PATH                               LABELS    PERMISSION
gpt3    /demo/t9k-assethub/model/chat/gpt3  GPT       own

通过 Python SDK

切换到你的工作路径下,然后以任意方式执行下面的 Python 代码。

导入 t9k.ah 模块,使用 ah.login() 函数登录到 AssetHub 服务器(如果配置文件中的凭据仍有效,则无需提供参数):

from t9k import ah

ah.login(host='<asset-hub-server-url>',
         api_key='<your-api-key>')
AH INFO: Logged in to Asset Hub server and AIStore server as user <your-user-name>

修改信息的方式对于文件夹、模型和数据集都是相同的。下面将以模型文件夹和模型为例进行演示(这里假设用户名为 demo)。

依次创建模型文件夹和模型:

model_folder = ah.create('model/llm')
model = ah.create('model/llm/gpt2')
AH INFO: Folder /demo/t9k-assethub/model/llm created
AH INFO: Model gpt2 created for Folder /demo/t9k-assethub/model/llm

使用 ah.update() 函数修改文件夹和模型的名称:

ah.update('model/llm', name='chat')
ah.update('model/chat/gpt2', name='gpt3')
AH INFO: Folder /demo/t9k-assethub/model/llm updated to /demo/t9k-assethub/model/chat
AH INFO: Model /demo/t9k-assethub/model/chat/gpt2 updated to /demo/t9k-assethub/model/chat/gpt3

使用 ah.list() 函数查看文件夹和模型的标签:

from pprint import pprint

pprint(ah.list('model'))
pprint(ah.list('model/chat'))
[{...
  'labels': [],
  'name': 'chat',
  'path': '/demo/t9k-assethub/model/chat',
  'type': 'Folder'}]
[{...
  'labels': [],
  'name': 'gpt3',
  'path': '/demo/t9k-assethub/model/chat/gpt3',
  'type': 'Model'}]

两者都没有标签,继续使用 ah.update() 函数为它们添加标签:

ah.update('model/chat', labels=['NLP', 'AIGC'])
ah.update('model/chat/gpt3', labels=['GPT'])
AH INFO: Folder /demo/t9k-assethub/model/chat updated
AH INFO: Model /demo/t9k-assethub/model/chat/gpt3 updated
pprint(ah.list('model'))
pprint(ah.list('model/chat'))
[{...
  'labels': ['AIGC', 'NLP'],
  'name': 'chat',
  'path': '/demo/t9k-assethub/model/chat',
  'type': 'Folder'}]
[{...
  'labels': ['GPT'],
  'name': 'gpt3',
  'path': '/demo/t9k-assethub/model/chat/gpt3',
  'type': 'Model'}]

通过控制台

数据集文件夹、数据集的控制台操作分别和模型文件夹、模型完全一致。本教程后续仅展示如何修改模型文件夹和模型的基本信息,你可以用同样的方式操作数据集文件夹和数据集。

在进行教程之前,先按照操作文件夹、模型和数据集一节完成模型文件夹和模型的创建(chat/gpt2)。

在模型文件夹列表中,选中需要修改的模型文件夹,点击更多 > 编辑

folder-list

填写新的名称和描述信息,添加新标签,点击更新按钮:

folder-edit

回到文件夹列表,可以看到文件夹信息发生改变:

folder-list-after-edit

点击文件夹名称,进入模型列表,选中需要修改的模型,点击更多 > 编辑

model-list

填写新的名称和描述信息,添加新标签,点击更新按钮:

model-edit

回到模型列表,可以看到模型信息发生改变:

model-list-after-edit

操作模型和数据集的分支、tag 和 commit

本教程演示如何通过多种方式操作模型的分支、tag 和 commit,包括创建、查看和删除分支,创建、查看和删除 tag,以及查看 commit。

数据集同理。

准备工作

通过命令行工具

切换到你的工作路径下:

$ cd /your/workpath

操作 tag 和 commit 的方式对于模型和数据集都是相同的,只有模型允许操作分支。下面将以模型为例进行演示(这里假设用户名为 demo)。

依次创建模型文件夹和模型:

$ ah create model/llm
AH INFO: Folder /demo/t9k-assethub/model/llm created

$ ah create model/llm/gpt2
AH INFO: Model gpt2 created for Folder /demo/t9k-assethub/model/llm

继续使用 ah create 命令为模型创建一个分支:

$ ah create model/llm/gpt2:v1
AH INFO: Branch v1 created for Model /demo/t9k-assethub/model/llm/gpt2

使用 ah ls --branch 命令查看模型的所有分支:

$ ah ls model/llm/gpt2 --branch
NAME    COMMIT_ID
main    fe46da7e
v1      fe46da7e

继续使用 ah create 命令为模型创建一个 tag:

$ ah create model/llm/gpt2:20230101 --tag --source v1
AH INFO: Tag 20230101 created from branch v1 for Model /demo/t9k-assethub/model/llm/gpt2

使用 ah ls --tag 命令查看模型的所有 tag:

$ ah ls model/llm/gpt2 --tag
    NAME  COMMIT_ID
20230101  fe46da7e

使用 ah ls --commit 命令查看模型的一个分支下的所有 commit:

$ ah ls model/llm/gpt2:v1 --commit
COMMIT_ID    MESSAGE             CREATED
fe46da7e     Repository created  3m16s ago

最后使用 ah delete 命令删除所有创建的分支和 tag:

$ ah delete model/llm/gpt2:v1
AH INFO: Branch v1 deleted for Model /demo/t9k-assethub/model/llm/gpt2

$ ah delete model/llm/gpt2:20230101
AH INFO: Tag 20230101 deleted for Model /demo/t9k-assethub/model/llm/gpt2

通过 Python SDK

切换到你的工作路径下,然后以任意方式执行下面的 Python 代码。

导入 t9k.ah 模块,使用 ah.login() 函数登录到 AssetHub 服务器(如果配置文件中的凭据仍有效,则无需提供参数):

from t9k import ah

ah.login(host='<asset-hub-server-url>',
         api_key='<your-api-key>')
AH INFO: Logged in to Asset Hub server and AIStore server as user <your-user-name>

操作 tag 和 commit 的方式对于模型和数据集都是相同的,只有模型允许操作分支。下面将以模型为例进行演示(这里假设用户名为 demo)。

依次创建模型文件夹和模型:

model_folder = ah.create('model/llm')
model = ah.create('model/llm/gpt2')
AH INFO: Folder /demo/t9k-assethub/model/llm created
AH INFO: Model gpt2 created for Folder /demo/t9k-assethub/model/llm

继续使用 ah.create() 函数为模型创建一个分支:

branch = ah.create('model/llm/gpt2:v1')
AH INFO: Branch v1 created for Model /demo/t9k-assethub/model/llm/gpt2

使用 ah.list() 函数查看模型的所有分支:

from pprint import pprint

pprint(ah.list('model/llm/gpt2', resource='branch'))
[{'commit_id': 'a15799f8f601d514a1a385a57b3078f8e178614a66aa920217175f6dcac2b083',
  'id': 'main'},
 {'commit_id': 'a15799f8f601d514a1a385a57b3078f8e178614a66aa920217175f6dcac2b083',
  'id': 'v1'}]

继续使用 ah.create() 函数为模型创建一个 tag:

tag = ah.create('model/llm/gpt2:20230101', create_tag=True, source='v1')
AH INFO: Tag 20230101 created from branch v1 for Model /demo/t9k-assethub/model/llm/gpt2

使用 ah.list() 函数查看模型的所有 tag:

pprint(ah.list('model/llm/gpt2', resource='tag'))
[{'commit_id': 'a15799f8f601d514a1a385a57b3078f8e178614a66aa920217175f6dcac2b083',
  'id': '20230101'}]

最后使用 ah.delete() 函数删除所有创建的分支和 tag:

ah.delete('model/llm/gpt2:v1')
ah.delete('model/llm/gpt2:20230101')
AH INFO: Branch v1 deleted for Model /demo/t9k-assethub/model/llm/gpt2
AH INFO: Tag 20230101 deleted for Model /demo/t9k-assethub/model/llm/gpt2

操作模型和数据集的对象

本教程演示如何通过多种方式操作模型的对象,包括修改、查看和下载 AssetHub 中存储的对象文件。

数据集同理。

准备工作

通过命令行工具

切换到你的工作路径下:

$ cd /your/workpath

操作对象的方式对于模型和数据集都是相同的,除了数据集只允许操作主分支(main 分支)中的对象。下面将以模型为例进行演示(这里假设用户名为 demo)。

依次创建模型文件夹、模型和分支:

$ ah create model/llm
AH INFO: Folder /demo/t9k-assethub/model/llm created

$ ah create model/llm/gpt2
AH INFO: Model gpt2 created for Folder /demo/t9k-assethub/model/llm

$ ah create model/llm/gpt2:v1
AH INFO: Branch v1 created for Model /demo/t9k-assethub/model/llm/gpt2

使用 ah commit 命令向该分支上传本地文件(这里以 model_state_dict.ptREADME.md 为例)作为对象存储:

$ ah commit model/llm/gpt2:v1 --message "Add model file" --add model_state_dict.pt --add README.md
AH INFO: Committing changes to branch /demo/t9k-assethub/model/llm/gpt2:v1
AH INFO: Uploading object 1/2 model_state_dict.pt:
         Done        
AH INFO: Uploading object 2/2 README.md:
         Done        
AH INFO: Commit 29d6f29e created

使用 ah ls 命令查看分支的所有对象:

$ ah ls model/llm/gpt2:v1
PATH                   BYTES  CHECKSUM                          MODIFIED
README.md               110B  d1f0e72bd20091c3869cefff8c72661b  1m29s ago
model_state_dict.pt  375943B  1203ee282c235c9fb4c2ea932a7b7cc8  1m29s ago

再次使用 ah commit 命令,当重复上传文件到同一路径时,原有的对象会被替换:

$ ah commit model/llm/gpt2:v1 --message "Update README" --add README.md
AH INFO: Committing changes to branch /demo/t9k-assethub/model/llm/gpt2:v1
AH INFO: Uploading object 1/1 README.md:
         Done        
AH INFO: New commit 53097cba created

$ ah ls model/llm/gpt2:v1
PATH                   BYTES  CHECKSUM                          MODIFIED
README.md               221B  84c44f1510389ea7de91e550be8a7130  15s ago
model_state_dict.pt  375943B  1203ee282c235c9fb4c2ea932a7b7cc8  5m37s ago

使用 -d PATH 选项以删除指定路径的对象:

$ ah commit model/llm/gpt2:v1 --message "Remove README" --delete README.md
AH INFO: Committing changes to branch /demo/t9k-assethub/model/llm/gpt2:v1
AH INFO: Deleting object README.md:
         Done
AH INFO: Commit cf8dcc26 created

$ ah ls model/llm/gpt2:v1
PATH                   BYTES  CHECKSUM                          MODIFIED
model_state_dict.pt  375943B  1203ee282c235c9fb4c2ea932a7b7cc8  6m2s ago

每次使用 ah commit 命令修改分支(添加、覆盖或删除对象)时,分支都会创建一个新的 commit。使用 ah ls commit 命令查看上面的操作所创建的 3 个 commit:

$ ah ls model/llm/gpt2:v1 --commit
COMMIT_ID     MESSAGE               CREATED
cf8dcc26      Remove README         5m47s ago
53097cba      Update README         21m46s ago
29d6f29e      Add model file        33m8s ago
c4bebb3a      Repository created    33m18s ago   # 初始 commit

之后想要使用这些对象时,使用 ah download 命令下载对象保存为本地文件:

$ ah download model/llm/gpt2:v1
AH INFO: Downloading object 1/1 model_state_dict.pt:
         ━━━━━━━━━━━━━━━━━━━━━━━━━━ 100.0% • 375.9/375.9 kB • 2.6 MB/s • 0:00:00

$ ls
model_state_dict.pt ...

通过 Python SDK

切换到你的工作路径下,然后以任意方式执行下面的 Python 代码。

导入 t9k.ah 模块,使用 ah.login() 函数登录到 Asset Hub 服务器(如果配置文件中的凭据仍有效,则无需提供参数):

from t9k import ah

ah.login(host='<asset-hub-server-url>',
         api_key='<your-api-key>')
AH INFO: Logged in to Asset Hub server and AIStore server as user <your-user-name>

操作对象的方式对于模型和数据集都是相同的,除了数据集只允许操作主分支(main 分支)中的对象。下面将以模型为例进行演示(这里以 user 表示当前用户)。

依次创建模型文件夹、模型和分支:

model_folder = ah.create('model/llm')
model = ah.create('model/llm/gpt2')
branch = ah.create('model/llm/gpt2:v1')
AH INFO: Folder /demo/t9k-assethub/model/llm created
AH INFO: Model gpt2 created for Folder /demo/t9k-assethub/model/llm
AH INFO: Branch v1 created for Model /demo/t9k-assethub/model/llm/gpt2

使用 ah.commit() 函数向该分支上传本地文件作为对象存储:

commit1 = ah.commit('model/llm/gpt2:v1',
                    msg='Add model file',
                    add=['model_state_dict.pt', 'README.md'])
AH INFO: Committing changes to branch /demo/t9k-assethub/model/llm/gpt2:v1
AH INFO: Uploading object model_state_dict.pt:
         Done        
AH INFO: Uploading object README.md:
         Done        
AH INFO: Commit 6a57546b created

使用 ah.list() 函数查看分支的所有对象:

from pprint import pprint

pprint(ah.list('model/llm/gpt2:v1'))
[{'checksum': 'f0db68fc4327c528b3a23fdc47c30c9e',
  'content_type': 'application/octet-stream',
  'mtime': 1683881423,
  'path': 'README.md',
  'path_type': 'object',
  'physical_address': 's3://t9k-aistore/d3a98ad0-50ca-42df-becf-8bbf4351d2c9/data/gnoggd0i2hci2stu7uhg/chevrjoi2hci2stu7un0',
  'size_bytes': 110},
 {'checksum': '1203ee282c235c9fb4c2ea932a7b7cc8',
  'content_type': 'application/octet-stream',
  'mtime': 1683881423,
  'path': 'model_state_dict.pt',
  'path_type': 'object',
  'physical_address': 's3://t9k-aistore/d3a98ad0-50ca-42df-becf-8bbf4351d2c9/data/gnoggd0i2hci2stu7uhg/chevrjgi2hci2stu7umg',
  'size_bytes': 375943}]

再次使用 ah.commit() 函数,当重复上传文件到同一路径时,原有的对象会被替换:

commit2 = ah.commit('model/llm/gpt2:v1', msg='Update README', add=['README.md'])

pprint(ah.list('model/llm/gpt2:v1'))
AH INFO: Committing changes to branch /demo/t9k-assethub/model/llm/gpt2:v1
AH INFO: Uploading object README.md:
         Done        
AH INFO: Commit 8183e1df created
[{'checksum': '1cbd5021ee923905bbdc29883c50a1b0',
  'content_type': 'application/octet-stream',
  'mtime': 1683881478,
  'path': 'README.md',
  'path_type': 'object',
  'physical_address': 's3://t9k-aistore/d3a98ad0-50ca-42df-becf-8bbf4351d2c9/data/gnoggd0i2hci2stu7uhg/chevs1gi2hci2stu7uog',
  'size_bytes': 221},
 {'checksum': '1203ee282c235c9fb4c2ea932a7b7cc8',
  'content_type': 'application/octet-stream',
  'mtime': 1683881423,
  'path': 'model_state_dict.pt',
  'path_type': 'object',
  'physical_address': 's3://t9k-aistore/d3a98ad0-50ca-42df-becf-8bbf4351d2c9/data/gnoggd0i2hci2stu7uhg/chevrjgi2hci2stu7umg',
  'size_bytes': 375943}]

使用 delete 选项以删除指定路径的对象:

commit3 = ah.commit('model/llm/gpt2:v1', msg='Remove README', delete=['README.md'])

pprint(branch.list_object())
AH INFO: Committing changes to branch /demo/t9k-assethub/model/llm/gpt2:v1
AH INFO: Deleting object README.md:
         Done
AH INFO: Commit 00af1151 created
[{'checksum': '1203ee282c235c9fb4c2ea932a7b7cc8',
  'content_type': 'application/octet-stream',
  'mtime': 1683881423,
  'path': 'model_state_dict.pt',
  'path_type': 'object',
  'physical_address': 's3://t9k-aistore/d3a98ad0-50ca-42df-becf-8bbf4351d2c9/data/gnoggd0i2hci2stu7uhg/chevrjgi2hci2stu7umg',
  'size_bytes': 375943}]

每次使用 ah.commit() 函数修改分支(添加、覆盖或删除对象)时,分支都会创建一个新的 commit。继续使用 ah.list() 函数查看上面的操作所创建的 3 个 commit:

pprint(ah.list('model/llm/gpt2:v1', resource='commit'))
[{'committer': 'admin',
  'creation_date': 1683881538,
  'id': '00af1151865121a79233af326b21864f2f6dbcc3b5bebb2f8768e2b13154f754',
  'message': 'Remove README',             # commit3
  'meta_range_id': 'c959b9ce4301591b82517c97ca277b034fd4a4d181b63db7571a2a8174844848',
  'metadata': {},
  'parents': ['8183e1dfb0dcded478aff1b5cb2975ae22e83ca4f37333fb904e5bcd27897923']},
 {'committer': 'admin',
  'creation_date': 1683881479,
  'id': '8183e1dfb0dcded478aff1b5cb2975ae22e83ca4f37333fb904e5bcd27897923',
  'message': 'Update README',             # commit2
  'meta_range_id': '2184d241abdc0ce3e26db44ad2c1df3e1e6a7a6b231fa1f17db7684982a55243',
  'metadata': {},
  'parents': ['6a57546b1275ba6b7f1399e0f7213552ac7bdf545de8692e494db47b93623b9d']},
 {'committer': 'admin',
  'creation_date': 1683881423,
  'id': '6a57546b1275ba6b7f1399e0f7213552ac7bdf545de8692e494db47b93623b9d',
  'message': 'Add model file',            # commit1
  'meta_range_id': '0b8943e0b3b4a3b8661f6146f47f85562aea5c7eb88bc2c66f2adf7443a08451',
  'metadata': {},
  'parents': ['610af4d2991e5c9b9d527dedf34db3cd11c8bd5bb7cc0e8ed0b97505319f8f11']},
 {'committer': '',
  'creation_date': 1683881388,
  'id': '610af4d2991e5c9b9d527dedf34db3cd11c8bd5bb7cc0e8ed0b97505319f8f11',
  'message': 'Repository created',        # 初始 commit
  'meta_range_id': '',
  'metadata': {},
  'parents': []}]

之后想要使用这些对象时,使用 ah.download() 函数下载对象保存为本地文件:

ah.download('model/llm/gpt2:v1')

import os
print(os.listdir())
AH INFO: Downloading object 1/1 model_state_dict.pt:
         ━━━━━━━━━━━━━━━━━━━━━━━━━━ 100.0% • 375.9/375.9 kB • 2.6 MB/s • 0:00:00
['model_state_dict.pt', ...]

通过控制台

数据集的控制台操作和模型完全一致。本教程后续仅展示模型对象的上传和下载,你可以用同样的方式操作数据集。

在进行教程之前,先按照操作文件夹、模型和数据集一节完成模型文件夹和模型的创建(chat/gpt3)。

进入模型详情页后,点击所有文件 > 上传图标

model-detail

点击选择文件选择所要上传的文件,填写描述信息,然后点击提交

model-upload

完成提交后,可以在所有文件中看到刚刚上传的文件,点击下载图标下载该文件:

model-object-list

点击介绍 > 添加介绍

model-introduce

在编辑框中按照 markdown 格式编辑模型的描述信息,填写提交信息,点击提交

model-readme

添加完介绍后,在模型详情页可以看到模型介绍:

model-introduce-after-add

模型介绍本质上是 README.md 文件,在所有文件中可以看到:

model-object-list-readme

追踪模型训练

在复杂的 AI 实验中,研究人员或工程师需要处理数以百计的实验配置和结果,在缺乏有效管理工具的情况下很容易迷失在海量的数据和文件中。因此,追踪和记录实验变得十分重要,它能够帮助研究人员快速识别最佳模型,比较不同模型的差异,洞悉关键因素的作用,并且迅速迭代改进,从而大幅提升研究和开发的效率。

这一部分将使用实验管理模块Python SDK 追踪模型的训练过程和结果。Python SDK 负责自动记录超参数、指标、平台信息以及任何重要的输入输出文件,实验管理控制台则提供直观的可视化界面以及便捷的团队协作体验。我们将从介绍实验管理控制台与 Python SDK 的基本用法开始,进而到实际场景中追踪模型的训练,最后我们查看 AutoTune 进行超参数优化的结果。

本部分常见任务如下:

在实验管理控制台查看和管理数据

本教程演示如何使用实验管理控制台来查看和管理记录的模型训练数据。

进入实验管理控制台

在 TensorStack AI 平台的首页,点击实验管理进入实验管理控制台。

enter-experiment-console

浏览文件夹

当前用户的所有数据以类似于文件系统的方式组织,每个 Run(或 Artifact、AutoTune)都位于特定的路径之下。点击一个文件夹(Folder)以进入,查看其下的所有子文件夹和 Run(或 Artifact、AutoTune)。

enter-folder

使用上方的面包屑导航或左侧的导航菜单可以返回上级文件夹或跳转到其他文件夹。

jump-to-folder

创建和删除文件夹

若要创建一个文件夹,点击右上角的添加,在对话框中提供文件夹名称并点击创建

create-folder

若要删除一个文件夹,点击文件夹项右侧的操作,或点击面包屑导航中的当前文件夹,然后点击删除

delete-folder1
delete-folder2

共享文件夹

点击文件夹项右侧的操作,或点击面包屑导航中的当前文件夹,点击分享,在对话框中管理文件夹的分享成员列表。空白表示文件夹当前没有被分享给任何其他用户。

share-folder

分享成员列表可以任意添加(点击加号)或移除(点击用户项右侧的减号)平台的其他用户或用户组,选择用户或用户组的名称和权限,最后点击保存以确定。

share-user-list

来自其他用户分享的文件夹、Run、Artifact 或 AutoTune 将出现在导航菜单的分享给我的标签下。

shared-with-me

其他文件夹操作

同样点击文件夹项右侧的操作,或点击面包屑导航中的当前文件夹,你还可以进行创建快捷方式移动以及重命名操作。

查看 Run 和 Artifact

点击一个 Run 或 Artifact 的名称以进入它的详情页面。

enter-run-artifact

Run 的详情页面中,多个标签页分别展示了平台信息、指标、超参数以及数据流。

run-details

Artifact 的详情页面中,多个标签页分别展示了文件列表以及数据流。

artifact-details

创建和删除 Run、Artifact 和 AutoTune

创建 Run 和 Artifact 的方法请参阅使用 Python SDK 记录和上传数据;创建 AutoTune 的方法请参阅使用 AutoTune 进行超参数优化

若要删除一个 Run(或 Artifact、AutoTune,下同),与删除文件夹的操作相同,点击 Run 项右侧的操作,或点击面包屑导航中的当前 Run,然后点击删除

delete-run

分享 Run、Artifact 和 AutoTune 以及其他操作

分享 Run(或 Artifact、AutoTune)或者进行其他操作的方法都与文件夹相同,这里不再赘述。

退出登录或切换用户

如果你想要退出当前用户的登录,点击右上角的用户头像,然后点击退出登录

sign-out

再次进入实验管理控制台时,你需要输入用户名和密码以重新登录。

使用 Python SDK 记录和上传数据

本教程介绍如何使用 Python SDK 进行创建、加载、上传 Run 和 Artifact,设定超参数,记录指标等操作。

创建 Run

基本方法

在模型的训练脚本中,你需要首先创建一个 Run,通过调用 t9k.em.create_run() 函数。其返回的 Run 实例即代表了一次训练的运行。此方法调用后,Run 将被创建,具有状态“Running”,其本地文件默认保存在相对路径 .em/runs 下,每个 Run 拥有一个独立的名为 <run_name>_<date>_<time>_<random_suffix>(称为该 Run 的备用名称)的子目录。

最基本的初始化方法只需要提供名称作为参数。

from t9k import em

run = em.create_run(name='mnist_torch')    # 返回Run实例

自动上传

如果想要自动异步上传 Run 的更新,可以设定 auto_upload=True,并提供文件夹路径,以及设定是否创建不存在的各级文件夹。在这种情况下,你在创建 Run 之前需要先登录到 AIStore 服务器

run = em.create_run(name='mnist_torch',
                    auto_upload=True,      # 启用自动上传
                    folder='new-folder',   # 文件夹路径
                    make_folder=True)      # 创建不存在的各级文件夹

如果目标文件夹已经存在同名的 Run,则需要指定 conflict_strategy 参数以处理冲突,参数接受以下值:

  • 'skip':跳过上传。
  • 'error':错误退出。
  • 'new':以 Run 的备用名称上传。
  • 'replace':替换同名的 Run。

例如,运行以下代码两次,第二次创建的 Run 会以类似 mnist_torch_231231_235959_61p5jc 的名称被上传到 new-folder 文件夹下。

run = em.create_run(name='mnist_torch',
                    auto_upload=True,
                    folder='new-folder',
                    make_folder=True,
                    conflict_strategy='new')

提供标签和描述

你可以为创建的 Run 提供用于分类或介绍的标签或描述。

run = em.create_run(
    name='mnist_torch',
    labels=['torch', 'CNN'],  # 标签
    description=              # 描述
    'Train a simple CNN model that classifies images of handwritten digits.')

提供配置文件

你可以将上面的所有配置(以及下面将要提到的超参数)都写进一个 YAML 文件里,然后传入该配置文件的路径即可。

run = em.create_run(config_path='./run_config.yaml')  # 提供配置文件

其中 run_config.yaml 的内容如下:

name: mnist_torch
auto_upload: true
folder: new-folder
make_folder: true
conflict_strategy: new
labels:
- torch
- CNN
description: Train a simple CNN model that classifies images of handwritten digits.

设定超参数

基本方法

超参数是影响模型训练效果的重要因素,记录训练的超参数十分必要,尤其是当你聚焦于某几个特定的超参数时。Run 实例的 hparams 属性是一个容器对象,用于保存你想要记录的所有超参数,你可以像操作 Python 字典一样操作它。一种推荐的设定超参数的方法是调用一次该容器对象的 update() 方法完成所有超参数的设定。

run.hparams.update({
    'batch_size': 32,
    'epochs': 10,
    'learning_rate': 0.001,
    'conv_channels': 32,
    'conv_kernel_size': 3,
    'maxpool_size': 2,
    'linear_features': 64,
})

hparams = run.hparams      # 便于之后访问

另一种推荐的方法是在创建 Run 的时候就传入所有超参数,此时可以将超参数也写进配置文件。

run = em.create_run(
    name='mnist_torch',
    hparams={
    'batch_size': 32,
    'epochs': 10,
    'learning_rate': 0.001,
    'conv_channels': 32,
    'conv_kernel_size': 3,
    'maxpool_size': 2,
    'linear_features': 64,
})

# 或

run = em.create_run(config_path='./run_config.yaml')

其中 run_config.yaml 的内容如下:

name: mnist_torch
hparams:
  batch_size: 32
  epochs: 10
  learning_rate: 0.001
  conv_channels: 32
  conv_kernel_size: 3
  maxpool_size: 2
  linear_features: 64

当然,你也可以多次调用 update() 方法,或者使用类似 Python 字典的键值对赋值方法设定单个超参数。

run.hparams['batch_size'] = 32

设定完成之后,使用这些超参数配置模型,同样使用类似 Python 字典的键值对访问方法。

from tensorflow.keras import layers, models, optimizers

model = models.Sequential()
model.add(layers.Conv2D(hparams['conv_channels'],     # 使用超参数配置模型
                        hparams['conv_kernel_size'],
                        input_shape=(28, 28, 1)))
...
optimizer = optimizers.Adam(learning_rate=hparams['learning_rate'])
model.compile(
    optimizer=optimizer,
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy'])
...
model.fit(train_images,
          train_labels,
          batch_size=hparams['batch_size'],
          epochs=hparams['epochs'])

设定作为标记的超参数

在上面的示例中,所有超参数都是直接传入各函数以配置模型。你也可以设定一些作为标记的超参数,例如网络类型、优化器类型、损失函数类型、激活函数类型等,以便日后快速回顾重要信息。

run.hparams.update({
    'network_structure': 'CNN',
    'optimizer': 'Adam',
    'loss': 'sparse categorical crossentropy',
    'linear_acti': 'relu',
})

配合 argparse 模块使用

许多训练脚本的超参数都是从命令行传入,由 argparse 模块解析。这些超参数可以方便地转换为字典对象并传入 update() 方法。

import argparse

parser = argparse.ArgumentParser()
parser.add_argument(...)
args = parser.parse_args()

run.hparams.update(args.__dict__)

记录指标

手动记录

Run 实例的 log() 方法用于记录模型在训练、验证或测试过程中产生的指标。被传入的字典对象会被作为指标记录,与此同时还需要提供指标的类型、当前的全局训练步数以及(可选的)当前的回合数。

# PyTorch模型
for epoch in range(1, epochs + 1):
    model.train()
    for step, (data, target) in enumerate(train_loader, 1):
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        output = model(data)
        loss = criterion(output, target)
        loss.backward()
        optimizer.step()

        if step % 500 == 0:
            train_loss = loss.item()
            logging.info(
                'epoch {:d}/{:d}, batch {:5d}/{:d} with loss: {:.4f}'.
                format(epoch, epochs, step, steps_per_epoch, train_loss))
            global_step = (epoch - 1) * steps_per_epoch + step

            run.log(
                type='train',                    # 指标类型
                metrics={'loss': train_loss},    # 指标名称及相应值
                step=global_step,                # 当前全局步数
                epoch=epoch)                     # 当前回合数

自动记录

对于建立在 Keras API 上的模型,更简单的方法是在模型的训练和测试方法中分别添加回调 t9k.em.keras.EMFitCallbackt9k.em.keras.EMEvalCallback 的实例。回调会相应地调用 log() 方法以自动记录各指标并同步到服务器。

# Keras模型
# 训练/验证过程和测试过程分别使用不同的回调
from t9k.em.keras import EMFitCallback, EMEvalCallback

model.fit(train_images,
          train_labels,
          epochs=10,
          validation_split=0.2,
          callbacks=EMFitCallback(run))

model.evaluate(test_images,
               test_labels,
               callbacks=EMEvalCallback(run))

结束 Run

模型的训练与测试全部完成后,你需要结束 Run,通过调用 Run 实例的 finish() 方法。此方法调用后,Run 的状态将更新为“Complete”。

run.finish()

创建 Artifact

基本方法

如要记录和保存与训练过程有关的文件,你需要创建一个 Artifact,通过调用 t9k.em.create_artifact() 函数。此方法调用后,Artifact 将被创建,其本地文件默认保存在相对路径 .em/artifacts 下。与 Run 相同,每个 Artifact 拥有一个独立的名为 <artifact_name>

最基本的初始化方法只需要提供名称作为参数。

dateset_artifact = em.create_artifact(name='mnist_dataset')

提供标签和描述

你可以为创建的 Artifact 提供用于分类或介绍的标签或描述。

dateset_artifact = em.create_artifact(
    name='mnist_dataset',
    labels=['dataset', 'MNIST'],                           # 标签
    description='Image dataset of handwritten digits.')    # 描述

为 Artifact 添加文件

与训练过程有关的文件通过 Artifact 实例的 add_file()add_dir() 方法添加到 Artifact 中。

dateset_artifact.add_file(file_path='./mnist.npz')    # 添加单个文件
dateset_artifact.add_dir(dir_path='./mnist/')         # 添加目录

Artifact 中的文件对象具有层次结构,你可以指定文件或目录位于 Artifact 的何路径下。

dateset_artifact.add_file(file_path='./mnist.npz', obj_path='dataset/')
dateset_artifact.add_dir(dir_path='./mnist/', obj_path='dataset/')

还可以通过 add_reference() 方法为 Artifact 添加一个网络文件的引用。

dateset_artifact.add_reference(uri='https://storage.googleapis.com/cvdf-datasets/mnist/train-images-idx3-ubyte.gz', obj_path='dataset/')

标记 Artifact 为 Run 的输入输出

为了构成 Run 与 Artifact 之间的数据流,需要调用 Run 实例的 mark_input()mark_output() 方法以标记 Artifact 实例为其输入或输出。

run.mark_input(dateset_artifact)
run.mark_output(model_artifact)

上传数据

基本方法

上传数据之前,你需要先登录到 AIStore 服务器,通过调用 t9k.em.login() 函数。

em.login(ais_host='<your-server-host>', api_key='<your-api-key>')

然后调用 RunArtifact 实例的 upload() 方法。

run.upload()
artifact.upload()

上传本地保存的数据

你也可以在训练结束之后将本地保存的数据上传到 AIStore 服务器,以应对训练时无网络连接、最初未打算上传、误删服务器中的数据等情形。

首先登录到 AIStore 服务器,然后加载保存在本地的 Run 或 Artifact,调用其 upload() 方法。

run = em.load_run(path='.em/runs/mnist_torch_231222_141932_61p5jc')
run.upload(folder='default', make_folder=True)

artifact = em.load_artifact(path='.em/runs/mnist_torch_saved_model_230908_165433_tou3ai')
artifact.upload(folder='default', make_folder=True)

下一步

单设备训练场景

本教程演示如何记录并展示单设备训练场景下的训练产生的信息、指标和文件(以 PyTorch 模型在单个 CPU 或 GPU 上的训练为例)。

运行示例

请按照使用方法准备环境,然后前往本教程对应的示例,参照其 README 文档运行。

下面介绍训练脚本进行了哪些修改以追踪训练。

准备训练脚本

准备一个 PyTorch 训练脚本,其模型对 MNIST 数据集的图像进行分类,具体代码如下所示。接下来将在此脚本的基础上进行简单的修改以进行追踪。

torch_mnist.py
import argparse
import logging
import os

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms

parser = argparse.ArgumentParser(
    description='Recording of training data of PyTorch model for MNIST with EM.'
)
parser.add_argument('--no_cuda',
                    action='store_true',
                    default=False,
                    help='Disable CUDA training.')
logging.basicConfig(format='%(message)s', level=logging.INFO)


class Net(nn.Module):

    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, 1)
        self.conv2 = nn.Conv2d(32, 64, 64, 1)
        self.conv3 = nn.Conv2d(64, 64, 3, 1)
        self.pool = nn.MaxPool2d(2, 2)
        self.dense1 = nn.Linear(576, 64)
        self.dense2 = nn.Linear(64, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = F.relu(self.conv3(x))
        x = torch.flatten(x, 1)
        x = F.relu(self.dense1(x))
        output = F.softmax(self.dense2(x), dim=1)
        return output


def train(scheduler):
    global global_step
    for epoch in range(1, epochs + 1):
        model.train()
        for step, (data, target) in enumerate(train_loader, 1):
            data, target = data.to(device), target.to(device)
            optimizer.zero_grad()
            output = model(data)
            loss = criterion(output, target)
            loss.backward()
            optimizer.step()

            if step % 500 == 0:
                train_loss = loss.item()
                logging.info(
                    'epoch {:d}/{:d}, batch {:5d}/{:d} with loss: {:.4f}'.
                    format(epoch, epochs, step, steps_per_epoch, train_loss))
                global_step = (epoch - 1) * steps_per_epoch + step

        scheduler.step()
        global_step = epoch * steps_per_epoch
        test(val=True, epoch=epoch)


def test(val=False, epoch=None):
    label = 'val' if val else 'test'
    model.eval()
    running_loss = 0.0
    correct = 0

    with torch.no_grad():
        loader = val_loader if val else test_loader
        for data, target in loader:
            data, target = data.to(device), target.to(device)
            output = model(data)
            loss = criterion(output, target)
            running_loss += loss.item()
            prediction = output.max(1)[1]
            correct += (prediction == target).sum().item()

    test_loss = running_loss / len(loader)
    test_accuracy = correct / len(loader.dataset)
    msg = '{:s} loss: {:.4f}, {:s} accuracy: {:.4f}'.format(
        label, test_loss, label, test_accuracy)
    if val:
        msg = 'epoch {:d}/{:d} with '.format(epoch, epochs) + msg
    logging.info(msg)


if __name__ == '__main__':
    args = parser.parse_args()

    use_cuda = not args.no_cuda and torch.cuda.is_available()
    if use_cuda:
        logging.info('Using CUDA')
    device = torch.device('cuda' if use_cuda else 'cpu')
    kwargs = {'num_workers': 1, 'pin_memory': True} if use_cuda else {}

    torch.manual_seed(1)

    model = Net().to(device)
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(model.parameters(), lr=0.001)
    scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=1, gamma=0.7)

    dataset_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                                'data')
    transform = transforms.Compose(
        [transforms.ToTensor(),
         transforms.Normalize((0.5), (0.5))])
    train_dataset = datasets.MNIST(root=dataset_path,
                                   train=True,
                                   download=True,
                                   transform=transform)
    train_dataset, val_dataset = torch.utils.data.random_split(
        train_dataset, [48000, 12000])
    test_dataset = datasets.MNIST(root=dataset_path,
                                  train=False,
                                  download=True,
                                  transform=transform)
    train_loader = torch.utils.data.DataLoader(
        train_dataset,
        batch_size=32,
        shuffle=True,
        **kwargs)
    val_loader = torch.utils.data.DataLoader(val_dataset,
                                             batch_size=400,
                                             shuffle=False,
                                             **kwargs)
    test_loader = torch.utils.data.DataLoader(test_dataset,
                                              batch_size=1000,
                                              shuffle=False,
                                              **kwargs)

    global_step = 0
    epochs = 10
    steps_per_epoch = len(train_loader)
    train(scheduler)
    test()

    torch.save(model.state_dict(), 'model_state_dict.pt')

创建 Run

在建立模型之前,创建并初始化一个 Run 实例。

from t9k import em

if __name__ == '__main__':
    ...
    run = em.create_run(name='mnist_torch')  # Run 的名称
    ...

Run 实例的 hparams 属性用于保存超参数,使用类似 Python 字典的方法更新它以设定超参数。

if __name__ == '__main__':
    ...
    run.hparams.update({
        'batch_size': 32,
        'epochs': 10,
        'learning_rate': 0.001,
        'learning_rate_decay_period': 1,
        'learning_rate_decay_factor': 0.7,
        'conv_channels1': 32,
        'conv_channels2': 64,
        'conv_channels3': 64,
        'conv_kernel_size': 3,
        'maxpool_size': 2,
        'linear_features1': 64,
        'seed': 1,
    })
    hparams = run.hparams
    ...

使用设定的超参数配置模型

使用上面设定的试验的超参数替换直接提供的超参数值,以配置模型各层、数据集、优化器、训练流程等。

class Net(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, hparams['conv_channels1'],
                               hparams['conv_kernel_size'], 1)
        self.conv2 = nn.Conv2d(hparams['conv_channels1'],
                               hparams['conv_channels2'],
                               hparams['conv_kernel_size'], 1)
        self.conv3 = nn.Conv2d(hparams['conv_channels2'],
                               hparams['conv_channels3'],
                               hparams['conv_kernel_size'], 1)
        self.pool = nn.MaxPool2d(hparams['maxpool_size'],
                                 hparams['maxpool_size'])
        self.dense1 = nn.Linear(576, hparams['linear_features1'])
        self.dense2 = nn.Linear(hparams['linear_features1'], 10)
    ...

if __name__ == '__main__':
    ...
    torch.manual_seed(hparams['seed'])
    ...
    optimizer = optim.Adam(model.parameters(), lr=hparams['learning_rate'])
    scheduler = optim.lr_scheduler.StepLR(
        optimizer,
        step_size=hparams['learning_rate_decay_period'],
        gamma=hparams['learning_rate_decay_factor'])
    ...
    train_loader = torch.utils.data.DataLoader(
        train_dataset,
        batch_size=hparams['batch_size'],
        shuffle=True,
        **kwargs)
    ...
    epochs = hparams['epochs']
    ...

记录指标

在模型的训练和测试过程中调用 Run 实例的 log() 方法,以记录模型在此期间产生的指标。

def train(scheduler):
    ...
            if step % 500 == 0:
                train_loss = loss.item()
                logging.info(
                    'epoch {:d}/{:d}, batch {:5d}/{:d} with loss: {:.4f}'.
                    format(epoch, epochs, step, steps_per_epoch, train_loss))
                global_step = (epoch - 1) * steps_per_epoch + step

                run.log(type='train',                    # 记录训练指标
                        metrics={'loss': train_loss},    # 指标名称及相应值
                        step=global_step,                # 当前全局步数
                        epoch=epoch)                     # 当前回合数
    ...

def test(val=False, epoch=None):
    ...
    test_loss = running_loss / len(loader)
    test_accuracy = correct / len(loader.dataset)
    msg = '{:s} loss: {:.4f}, {:s} accuracy: {:.4f}'.format(
        label, test_loss, label, test_accuracy)
    if val:
        msg = 'epoch {:d}/{:d} with '.format(epoch, epochs) + msg
    logging.info(msg)

    run.log(type=label,    # 记录验证/测试指标
            metrics={
                'loss': test_loss,
                'accuracy': test_accuracy,
            },
            step=global_step,
            epoch=epoch)

创建 Artifact 并添加模型检查点文件

在保存模型检查点文件之后,创建并初始化一个新的 Artifact 实例,为其添加该检查点文件,并标记为 Run 的输出。

if __name__ == '__main__':
    ...
    torch.save(model.state_dict(), 'model_state_dict.pt')
    model_artifact = em.create_artifact(name='mnist_torch_saved_model')
    model_artifact.add_file('model_state_dict.pt')
    run.mark_output(model_artifact)
    ...

结束和上传 Run

模型的训练和测试结束后,调用 Run 实例的 finish()upload() 方法以结束和上传 Run(Artifact 也会被一并上传)。在上传之前需要调用 em.login() 函数以登录到 AIStore 服务器。

if __name__ == '__main__':
    ...
    run.finish()
    em.login()
    run.upload(folder='em-examples', make_folder=True)

检查 Run 和 Artifact

训练结束后,进入实验管理控制台,可以看到名为 mnist_torch 的 Run 及其输出的 Artifact 被上传:

uploaded

点击 Run 或 Artifact 的名称进入其详情页面,可以看到 Run 的平台信息、指标、超参数和数据流,以及 Artifact 的文件和数据流。并且它们的数据流是连通的。

run
artifact
dataflow

下一步

分布式训练场景

本教程演示如何记录并展示 PyTorchTrainingJob 分布式训练场景下的训练产生的信息、指标和文件(以 PyTorch 模型的数据并行训练为例)。

运行示例

请按照使用方法准备环境,然后前往本教程对应的示例,参照其 README 文档运行。

下面介绍训练脚本进行了哪些修改以追踪训练。该方法是通用的,可以推广到任意类型的 TrainingJob、DeepSpeedJob、ColossalAIJob、MPIJob 或 GenericJob。

准备训练脚本

准备一个 PyTorch 训练脚本,其模型对 MNIST 数据集的图像进行分类,使用 DistributedDataParallel(DDP)模块进行分布式训练,具体代码如下所示(这里使用与使用 PyTorchTrainingJob 进行数据并行训练相同的脚本)。接下来将在此脚本的基础上进行简单的修改以进行追踪。

torch_mnist_trainingjob_em.py
import argparse
import logging
import os
import shutil

import torch
import torch.distributed as dist
import torch.nn as nn
import torch.nn.functional as F
from torch.nn.parallel import DistributedDataParallel as DDP
import torch.optim as optim
from torch.utils.tensorboard import SummaryWriter
from torchvision import datasets, transforms

parser = argparse.ArgumentParser(
    description='Distributed training of Keras model for MNIST with DDP.')
parser.add_argument(
    '--backend',
    type=str,
    help='Distributed backend',
    choices=[dist.Backend.GLOO, dist.Backend.NCCL, dist.Backend.MPI],
    default=dist.Backend.GLOO)
parser.add_argument('--log_dir',
                    type=str,
                    default='/mnt/log',
                    help='Path of the TensorBoard log directory.')
parser.add_argument('--no_cuda',
                    action='store_true',
                    default=False,
                    help='Disable CUDA training.')
logging.basicConfig(format='%(message)s', level=logging.INFO)


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, 1)
        self.conv2 = nn.Conv2d(32, 64, 3, 1)
        self.conv3 = nn.Conv2d(64, 64, 3, 1)
        self.pool = nn.MaxPool2d(2, 2)
        self.dense1 = nn.Linear(576, 64)
        self.dense2 = nn.Linear(64, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = F.relu(self.conv3(x))
        x = torch.flatten(x, 1)
        x = F.relu(self.dense1(x))
        output = F.softmax(self.dense2(x), dim=1)
        return output


def train(scheduler):
    global global_step
    for epoch in range(1, epochs + 1):
        model.train()
        for step, (data, target) in enumerate(train_loader, 1):
            data, target = data.to(device), target.to(device)
            optimizer.zero_grad()
            output = model(data)
            loss = criterion(output, target)
            loss.backward()
            optimizer.step()

            if step % (500 // world_size) == 0:
                train_loss = loss.item()
                logging.info(
                    'epoch {:d}/{:d}, batch {:5d}/{:d} with loss: {:.4f}'.
                    format(epoch, epochs, step, steps_per_epoch, train_loss))
                global_step = (epoch - 1) * steps_per_epoch + step

                if args.log_dir and rank == 0:
                    writer.add_scalar('train/loss', train_loss, global_step)

        scheduler.step()
        global_step = epoch * steps_per_epoch
        test(val=True, epoch=epoch)


def test(val=False, epoch=None):
    label = 'val' if val else 'test'
    model.eval()
    running_loss = 0.0
    correct = 0

    with torch.no_grad():
        loader = val_loader if val else test_loader
        for data, target in loader:
            data, target = data.to(device), target.to(device)
            output = model(data)
            loss = criterion(output, target)
            running_loss += loss.item()
            prediction = output.max(1)[1]
            correct += (prediction == target).sum().item()

    test_loss = running_loss / len(loader)
    test_accuracy = correct / len(loader.dataset)
    msg = '{:s} loss: {:.4f}, {:s} accuracy: {:.4f}'.format(
        label, test_loss, label, test_accuracy)
    if val:
        msg = 'epoch {:d}/{:d} with '.format(epoch, epochs) + msg
    logging.info(msg)

    if args.log_dir and rank == 0:
        writer.add_scalar('{:s}/loss'.format(label), test_loss, global_step)
        writer.add_scalar('{:s}/accuracy'.format(label), test_accuracy,
                          global_step)


if __name__ == '__main__':
    args = parser.parse_args()

    use_cuda = not args.no_cuda and torch.cuda.is_available()
    if use_cuda:
        logging.info('Using CUDA')
    device = torch.device("cuda" if use_cuda else "cpu")
    kwargs = {'num_workers': 1, 'pin_memory': True} if use_cuda else {}

    logging.info('Using distributed PyTorch with {} backend'.format(
        args.backend))
    dist.init_process_group(backend=args.backend)
    rank = dist.get_rank()
    world_size = dist.get_world_size()

    torch.manual_seed(1)

    model = Net().to(device)
    model = DDP(model)
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(model.parameters(), lr=0.001 * world_size)
    scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=1, gamma=0.7)

    transform = transforms.Compose(
        [transforms.ToTensor(),
         transforms.Normalize((0.5), (0.5))])
    train_dataset = datasets.MNIST(root='./data',
                                   train=True,
                                   download=False,
                                   transform=transform)
    train_dataset, val_dataset = torch.utils.data.random_split(
        train_dataset, [48000, 12000])
    test_dataset = datasets.MNIST(root='./data',
                                  train=False,
                                  download=False,
                                  transform=transform)
    train_loader = torch.utils.data.DataLoader(train_dataset,
                                               batch_size=32 * world_size,
                                               shuffle=True,
                                               **kwargs)
    val_loader = torch.utils.data.DataLoader(val_dataset,
                                             batch_size=400,
                                             shuffle=False,
                                             **kwargs)
    test_loader = torch.utils.data.DataLoader(test_dataset,
                                              batch_size=1000,
                                              shuffle=False,
                                              **kwargs)

    if args.log_dir and rank == 0:
        log_dir = args.log_dir
        if os.path.exists(log_dir):
            shutil.rmtree(log_dir, ignore_errors=True)
        writer = SummaryWriter(log_dir)

    global_step = 0
    epochs = 10
    steps_per_epoch = len(train_loader)
    train(scheduler)
    test()

创建 Run

创建一个包含所有(想要记录的)超参数的 Python 字典。

from t9k import em

if __name__ == '__main__':
    ...
    hparams = {
        'batch_size': 32 * world_size,
        'epochs': 10,
        'learning_rate': 0.001 * world_size,
        'learning_rate_decay_period': 1,
        'learning_rate_decay_factor': 0.7,
        'conv_channels1': 32,
        'conv_channels2': 64,
        'conv_channels3': 64,
        'conv_kernel_size': 3,
        'maxpool_size': 2,
        'linear_features1': 64,
        'seed': 1,
    }
    ...

指定一个工作器负责在建立模型之前创建并初始化一个 Run 实例,传入名称和上面的超参数字典。

if __name__ == '__main__':
    ...
    if rank == 0:
        run = em.create_run(name='mnist_torch_distributed', hparams=hparams)
    ...

使用设定的超参数配置模型

使用上面的超参数字典的值替换直接提供的超参数值,以配置模型各层、数据集、优化器、训练流程等。

class Net(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, hparams['conv_channels1'],
                               hparams['conv_kernel_size'], 1)
        self.conv2 = nn.Conv2d(hparams['conv_channels1'],
                               hparams['conv_channels2'],
                               hparams['conv_kernel_size'], 1)
        self.conv3 = nn.Conv2d(hparams['conv_channels2'],
                               hparams['conv_channels3'],
                               hparams['conv_kernel_size'], 1)
        self.pool = nn.MaxPool2d(hparams['maxpool_size'],
                                 hparams['maxpool_size'])
        self.dense1 = nn.Linear(576, hparams['linear_features1'])
        self.dense2 = nn.Linear(hparams['linear_features1'], 10)
    ...

if __name__ == '__main__':
    ...
    torch.manual_seed(hparams['seed'])
    ...
    optimizer = optim.Adam(model.parameters(), lr=hparams['learning_rate'])
    scheduler = optim.lr_scheduler.StepLR(
        optimizer,
        step_size=hparams['learning_rate_decay_period'],
        gamma=hparams['learning_rate_decay_factor'])
    ...
    train_loader = torch.utils.data.DataLoader(
        train_dataset,
        batch_size=hparams['batch_size'],
        shuffle=True,
        **kwargs)
    ...
    epochs = hparams['epochs']
    ...

记录指标

在模型的训练和测试过程中,被指定的工作器调用 Run 实例的 log() 方法以记录模型在此期间产生的指标。

def train(scheduler):
    ...
            if step % (500 // world_size) == 0:
                train_loss = loss.item()
                logging.info(
                    'epoch {:d}/{:d}, batch {:5d}/{:d} with loss: {:.4f}'.
                    format(epoch, epochs, step, steps_per_epoch, train_loss))
                global_step = (epoch - 1) * steps_per_epoch + step

                if rank == 0:
                    run.log(type='train',                  # 记录训练指标
                            metrics={'loss': train_loss},  # 指标名称及相应值
                            step=global_step,              # 当前全局步数
                            epoch=epoch)                   # 当前回合数
    ...

def test(val=False, epoch=None):
    ...
    test_loss = running_loss / len(loader)
    test_accuracy = correct / len(loader.dataset)
    msg = '{:s} loss: {:.4f}, {:s} accuracy: {:.4f}'.format(
        label, test_loss, label, test_accuracy)
    if val:
        msg = 'epoch {:d}/{:d} with '.format(epoch, epochs) + msg
    logging.info(msg)

    if rank == 0:
        run.log(type=label,    # 记录验证/测试指标
                metrics={
                    'loss': test_loss,
                    'accuracy': test_accuracy,
                },
                step=global_step,
                epoch=epoch)

创建 Artifact 并添加模型检查点文件

在保存模型检查点文件之后,被指定的工作器创建并初始化一个新的 Artifact 实例,为其添加该检查点文件,并标记为 Run 的输出。

if __name__ == '__main__':
    ...
    if rank == 0:
        torch.save(model.state_dict(), 'model_state_dict.pt')
        model_artifact = em.create_artifact(name='mnist_torch_saved_model')
        model_artifact.add_file('model_state_dict.pt')
        run.mark_output(model_artifact)
    ...

结束和上传试验

模型的训练和测试结束后,被指定的工作器调用 Run 实例的 finish()upload() 方法以结束和上传 Run(Artifact 也会被一并上传)。在上传之前需要调用 em.login() 函数以登录到服务器。

if __name__ == '__main__':
    ...
    if rank == 0:
        run.finish()
        em.login()
        run.upload(folder='em-examples', make_folder=True)

检查 Run 和 Artifact

训练结束后,进入实验管理控制台,可以看到名为 mnist_torch_distributed 的 Run 及其输出的 Artifact 被上传:

uploaded

点击 Run 或 Artifact 的名称进入其详情页面,可以看到 Run 的平台信息、指标、超参数和数据流,以及 Artifact 的文件和数据流。并且它们的数据流是连通的。

run
artifact
dataflow

在实验管理控制台查看 AutoTune

如果 AutoTune 使用 AIStore 作为数据库,那么 AutoTune 会自动记录实验以及其中所有试验的数据到 AIStore 中。

参照使用 AutoTune 进行超参数优化创建一个 AutoTuneExperiment。唯一需要修改的部分是,将 AutoTuneExperiment 配置文件的 spec.em.folder 字段修改为文件夹 em-examples 的 ID。

创建完成之后,进入实验管理控制台,可以看到 em-examples/ 路径下出现了一个名为 keras-mnist-autotune 的 AutoTune:

created

点击其名称进入详情页面,可以看到 AutoTuneExperiment 的信息、当前进度、各试验的信息以及可视化图表:

details

点击任意一个试验的右侧的详情可以看到试验使用的超参数以及指标:

trial-hparams
trial-metrics

构建自动化工作流

这一部分演示如何使用工作流系统进行 AI 开发和实验,帮助管理 AI 项目中数据清洗、特征工程、模型训练、评估等多个步骤之间的依赖关系,确保它们以正确的顺序执行,并提高可复用性。

创建工作流的基本单元

本教程演示如何创建工作流的基本单元。

准备工作

创建 WorkflowTemplate

在浏览器中进入工作流控制台之后,点击左侧导航菜单的 WorkflowTemplate 进入 WorkflowTemplate 列表页面,然后点击右上角的 Project 框选择一个 Project,然后点击列表右上角的 + 在该 Project 中创建一个 WorkflowTemplate。

workflowtemplate-list

进入创建 WorkflowTemplate 页面之后,左侧的表格和右侧的 YAML 都可以进行编辑,并且两侧始终是同步变化的。你可以在此填写所要创建的 WorkflowTemplate。

create-workflowtemplate

首先,你需要在名为 WorkflowTemplate Name 的文本框中填写 WorkflowTemplate 的名称,然后在名为 Type 的下拉框中选择 WorkflowTemplate 的类型(可以是 PodSeqPodResource 等),最后根据 WorkflowTemplate 类型的不同,继续填写余下配置。

编辑好 WorkflowTemplate 之后,点击表格右上角的 Create WorkflowTemplate 创建该 WorkflowTemplate,右下角会有悬浮框提示是否创建成功。

创建 WorkflowRun

再次点击左侧导航菜单的 WorkflowTemplate 进入 WorkflowTemplate 列表页面,找到你刚才创建的 WorkflowTemplate hello,点击 WorkflowTemplate 的名称进入 WorkflowTemplate 的详情页面。

workflowtemplate-detail

在 WorkflowTemplate 的详情页面,你可以点击 SPECSYAML 标签查看 WorkflowTemplate 的详细情况,检查是否有错误。如果没有错误,点击右上角的 Create WorkflowRun 为该 WorkflowTemplate 创建一个 WorkflowRun。

create-workflowrun

在弹出的创建 WorkflowRun 对话框中,按步骤依次填写 WorkflowRun 所需要的参数,最后点击 Create 创建 WorkflowRun,右下角会有悬浮框提示是否创建成功。

create-workflowrun

查看 WorkflowRun 运行情况

点击左侧导航菜单的 WorkflowRun 进入 WorkflowRun 列表页面,找到你刚刚创建的 WorkflowRun hello-run-3xrlm,点击 WorkflowRun 的名称进入 WorkflowRun 的详情页面。

workflowrun-detail

在 WorkflowRun 的详情页面,你可以点击 LOGSSTATUSSPECSYAML 等标签,分别查看 WorkflowRun 的日志、状态、规约和 YAML。如果 WorkflowRun 正在运行而且其类型是 Pod 或 SeqPod,你可以点击 TERMINAL 标签,连接到 WorkflowRun 创建的 Pod 的某个容器的终端(shell),利用命令行工具进行调试。

创建执行各类任务的工作流单元

本教程演示如何创建执行各类任务的工作流单元。

准备工作

创建类型为 PodSeqPod 的 WorkflowTemplate

WorkflowTemplate 介绍中所述,PodSeqPod 类型的区别在于,Pod 中的所有容器是一起(近乎同时)开始运行的,而 SeqPod 中的每个步骤是按照定义的顺序依次执行的。如无特殊情况,我们一般使用 SeqPod 类型即可。以下均以 SeqPod 类型为基础进行讲解。

选择镜像

在教程创建工作流的基本单元中,我们已经完成了 SeqPod 类型的 WorkflowTemplate 的创建和运行。如教程中所述,在 SeqPod 的每个步骤(step)中,都要填写所使用的镜像。一般来说,镜像的来源可能有以下几种:

准备好镜像之后,在 Image 框中填入镜像的地址。

select-image

执行 PVC 中的脚本

当你在 Notebook 中编写了一些 Python 脚本或 Shell 脚本后,你可以创建 WorkflowTemplate 以及对应的 WorkflowRun 来运行该脚本。只要 WorkflowRun 和 Notebook 绑定的是同一个 PVC,WorkflowRun 就能访问到你在 Notebook 中编写的脚本。

首先,在 Notebook 中编写想要运行的脚本,并 Ctrl+S 保存。

script-1

查看 Notebook 所绑定的 PVC 名称,以便创建 WorkflowRun 时使用。

script-2

按照下图所示填写表格,创建一个 SeqPod 类型的 WorkflowTemplate。

script-3

或者,你也可以复制粘贴下面的 YAML 配置文件来创建 WorkflowTemplate:

apiVersion: batch.tensorstack.dev/v1beta1
kind: WorkflowTemplate
metadata:
  name: run-script
  labels: {}
spec:
  params: []
  results: []
  seqPod:
    steps:
      - args:
          - $(workspaces.notebook-pvc.path)/run.py
        command:
          - python
        image: 'registry.tensorstack.cn/t9k/tensorflow-2.8.0-notebook-cpu:1.50.0'
        name: step1
        resources:
          limits:
            cpu: 100m
            memory: 200Mi
  type: SeqPod
  workspaces:
    - description: the pvc used by notebook
      name: notebook-pvc

然后,创建 WorkflowRun 来运行该 WorkflowTemplate。

script-4

WorkflowRun 运行完成后,可以看到打印结果与所编写的脚本运行预期结果一致。

script-5

执行自定义脚本

除了在 Notebook 中编写脚本,你还可以在创建 WorkflowTemplate 的过程中现场编写 Python 或 Shell 脚本。

如下图所示,创建 WorkflowTemplate 时选择类型为 SeqPod,然后点击 Add Step,在 Step 中选择 Script 即可嵌入自定义脚本。

embedded-1

目前支持 Python 和 Shell 两种语言,可通过下拉框进行选择。

embedded-2

创建 WorkflowTemplate 和对应的 WorkflowRun 来运行,可以看到打印结果与脚本运行与其结果一致。

embedded-3

创建类型为 Resource 的 WorkflowTemplate

WorkflowTemplate 介绍中所述,Resource 类型的 WorkflowTemplate 用于创建一个 Kubernetes 资源。下面展示两个常用示例。

创建分布式训练

假设你已经有一个可以运行的 TrainingJob YAML 配置文件:

apiVersion: batch.tensorstack.dev/v1beta1
kind: TensorFlowTrainingJob
metadata:
  name: mnist
spec:
  tensorboardSpec:               # TensorBoard服务器规约
    trainingLogFilesets:
      - t9k://pvc/mnist/log      # 日志文件路径
    image: tensorflow/tensorflow:2.8.0
                                # TensorBoard服务器使用的镜像
  replicaSpecs:
    - type: worker               # 工作器
      replicas: 4                # 工作器数量
      restartPolicy: ExitCode
      template:
        spec:
          securityContext:
            runAsUser: 1000
          containers:
            - image: tensorflow/tensorflow:2.8.0
                                  # 容器的镜像
              workingDir: /mnt
              name: tensorflow
              command:           # 执行`python`命令以执行训练脚本
                - sh
                - '-c'
                - >-
                  python /mnt/keras_mnist_trainingjob.py --log_dir /mnt/log --save_path /mnt/saved_model
                  --no_cuda
              env: []
              resources:
                limits:          # 限制量
                  cpu: '4'       # CPU
                  memory: 2Gi    # 内存
                requests:        # 请求量
                  cpu: '2'
                  memory: 1Gi
              volumeMounts:
                - name: data
                  mountPath: /mnt
          volumes:
            - name: data
              persistentVolumeClaim:
                claimName: mnist

如果你想将创建 TrainingJob 插入工作流中成为其中一个步骤,可以使用 Resource 类型的 WorkflowTemplate。如下图所示,在 WorkflowTemplate 创建页面,选择类型为 Resource,然后将上面的 YAML 配置文件复制粘贴到 Resource Manifest 文本框中,即可创建一个 WorkflowTemplate 来运行这个 TrainingJob。

trainingjob-1

但是,由于在同一个项目中不能创建两个同名的 TrainingJob,上述方式创建的 WorkflowTemplate 只能运行一次,不具备可复用性。因此我们可以对 TrainingJob 配置文件做一些修改,利用 WorkflowTemplate 的指定参数功能,使其能被重复使用。

经过修改的 TrainingJob 配置文件如下:

apiVersion: batch.tensorstack.dev/v1beta1
kind: TensorFlowTrainingJob
metadata:
  name: $(params.trainingjob_name)
spec:
  tensorboardSpec:               # TensorBoard服务器规约
    trainingLogFilesets:
      - t9k://pvc/mnist/log      # 日志文件路径
    image: tensorflow/tensorflow:2.8.0
                                # TensorBoard服务器使用的镜像
  replicaSpecs:
    - type: worker               # 工作器
      replicas: 4                # 工作器数量
      restartPolicy: ExitCode
      template:
        spec:
          securityContext:
            runAsUser: 1000
          containers:
            - image: tensorflow/tensorflow:2.8.0
                                # 容器的镜像
              workingDir: /mnt
              name: tensorflow
              command:          # 执行`python`命令以执行训练脚本
                - sh
                - '-c'
                - >-
                  python /mnt/keras_mnist_trainingjob.py --log_dir /mnt/log --save_path /mnt/saved_model
                  --no_cuda
              env: []
              resources:
                limits:
                  cpu: '4'
                  memory: 4Gi
                requests:
                  cpu: '2'
                  memory: 2Gi
              volumeMounts:
                - name: data
                  mountPath: /mnt
          volumes:
            - name: data
              persistentVolumeClaim:
                claimName: $(params.pvc_name)

改动有两处:

  • metadata.name 从固定的 mnist 改为 $(params.trainingjob_name)
  • spec.replicaSpecs.template.volumes.persistentVolumeClaim.claimName 从固定的 mnist 改为 $(params.pvc_name)

这两个改动使得 TrainingJob 的名称和所使用的 PVC 的名称在运行时才被传入,这样创建的 WorkflowTemplate 就能够多次重复使用了。

在 WorkflowTemplate 创建页面,将上述改动过的 Trainingjob 配置文件复制粘贴到 Resource Manifest 文本框中,并为 WorkflowTemplate 添加两个参数,分别名为 trainingjob_namepvc_name,然后点击 Create WorkflowTemplate 进行创建。

trainingjob-2

在创建 WorkflowRun 时,为 trainingjob_namepvc_name 这两个参数提供实际值。

trainingjob-3

等待 WorkflowRun 完成运行。

trainingjob-4

创建推理服务

创建分布式训练类似,我们可以在简单推理服务的 YAML 配置文件基础上,加入可变的参数:

apiVersion: tensorstack.dev/v1beta1
kind: SimpleMLService
metadata:
  name: $(params.simplemlservice_name)
spec:
  replicas: 1
  storage:
    pvc:
      containerPath: /var/lib/t9k/models/mnist
      name: tutorial
      subPath: tutorial-examples/deployment/model/tensorflow/mnist
  tensorflow:
    image: t9kpublic/tensorflow-serving:2.6.0

在 WorkflowTemplate 创建页面,将上述 YAML 配置文件复制粘贴到 Resource Manifest 文本框中,并为 WorkflowTemplate 添加一些参数。

simplemlservice-1

创建 WorkflowTemplate,然后创建对应的 WorkflowRun 并提供参数的实际值。

与分布式训练不同,推理服务是一个长时间运行的服务,没有结束时间。因此所创建的 WorkflowRun 也不会结束运行,而是一直处于 Running 状态。

simplemlservice-2

创建存在依赖关系的工作流

本教程演示如何创建存在依赖关系的工作流。

准备工作

创建一些简单的 WorkflowTemplate

在浏览器中进入工作流控制台之后,点击左侧导航菜单的 WorkflowTemplate 进入 WorkflowTemplate 列表页面,然后点击右上角的 Project 选择框选择一个 Project。

本教程使用创建工作流的基本单元教程中创建好的 WorkflowTemplate hello 即可。如果有需要,你可以点击列表右上角的加号,按照创建工作流的基本单元教程中的步骤,创建一些简单的 WorkflowTemplate。

创建 DAG WorkflowTemplate

点击左侧导航菜单的 WorkflowTemplate 进入 WorkflowTemplate 列表页面,然后点击列表右上角的树状图标来创建一个 DAG WorkflowTemplate。

workflowtemplate-list

进入创建 DAG WorkflowTemplate 页面之后,除了最左侧的导航菜单之外整个页面分为三个部分,左边是 WorkflowTemplate 列表,中间是用于组建 DAG 的画布,右边是 DAG WorkflowTemplate 的详情。你可以从左边的 WorkflowTemplate 列表中用鼠标选取一个 WorkflowTemplate 拖拽到中间的画布上,然后通过绿色锚点连接多个 WorkflowTemplate,表示它们的执行顺序。画布中所有的 WorkflowTemplate 由依赖关系组成一个有向无环图(DAG)。

create-workflowtemplate

建立好有向无环图之后,你可以在右边的表格编辑 DAG WorkflowTemplate 的详情,例如 WorkflowTemplate 的名称、工作空间、参数等。点击画布中的方块即可编辑该节点的详情,点击画布的空白处可以编辑整个 DAG WorkflowTemplate 的详情。

最后,点击表格上方的 Create DAG WorkflowTemplate 创建该 DAG WorkflowTemplate,右下角会有悬浮框提示是否创建成功。

创建 WorkflowRun

再次点击左侧导航菜单的 WorkflowTemplate 进入 WorkflowTemplate 列表页面,找到你刚刚创建的 WorkflowTemplate hello-again,点击 WorkflowTemplate 的名称进入 WorkflowTemplate 的详情页面。

workflowtemplate-detail

在 WorkflowTemplate 的详情页面,点击右上角的 Create WorkflowRun 为该 WorkflowTemplate 创建一个 WorkflowRun。

create-workflowrun

在弹出的创建 WorkflowRun 对话框中。按步骤依次填写 WorkflowRun 所需要的参数,最后点击 Create 创建 WorkflowRun,右下角会有悬浮框提示是否创建成功。

查看 WorkflowRun 运行情况

点击左侧导航菜单的 WorkflowRun 进入 WorkflowRun 列表页面,找到你刚刚创建的 WorkflowRun hello-again-run-9214x,点击 WorkflowRun 的名称进入 WorkflowRun 的详情页面。

workflowrun-detail

在 WorkflowRun 的详情页面,你可以点击 GRAPH 标签,查看 DAG 的详细情况,点击 DAG 的节点可以在弹框中查看节点的详细情况。

workflowrun-detail-node

建立从数据采样到模型导出的自动化工作流

本教程演示如何建立一个端到端的机器学习工作流,包括数据预处理、模型训练、模型分析等步骤。本教程使用的机器学习应用样例是一个二分类问题,根据乘客搭乘出租车的位置、路程、用时等特征数据预测乘客是否会付小费。

准备工作

运行示例

请按照使用方法准备环境,然后前往本教程对应的示例,参照其 README 文档运行。

查看运行结果

成功创建 WorkflowRun 之后,进入工作流控制台的 WorkflowRun 列表页面,可以看到名为 taxi-tips-prediction-run-75v60 的 WorkflowRun 正在运行:

workflowrun-list-success

点击该名称 进入详情页面,可以看到刚才创建的 WorkflowRun 的详细运行状态:

workflowrun-detail

本页面会自动刷新以获取 WorkflowRun 的最新状态,你也可以点击右上角的刷新图标手动刷新。

调度工作负载

使用队列

概述

队列是 T9k 平台中资源管理的机制,用于补充 K8s 原生平台在 scheduling 方面的不足。管理员可以为队列设定使用权限,资源来源的集群节点,资源配额,最大运行时长等属性,以精细化管理集群。

用户在创建使用调度器 T9k Scheduler 的工作负载时,需为工作负载指定一个队列。

为工作负载指定队列

根据工作负载的种类,指定队列的方式如下。

v1/Pod

创建 Pod 时,有两种指定所属队列的方式:

  • 直接指定队列:此类 Pod 不属于任何 PodGroup。
  • 通过 PodGroup 间接指定队列:此类 Pod 属于所指定的 PodGroup。

直接指定队列

Pod 通过标签来表明他属于哪一个队列,标签的 key 是 scheduler.tensorstack.dev/queue

在下面的示例中,Pod 指定了队列 demo:

apiVersion: v1
kind: Pod
metadata:
  name: test1
  labels:
    scheduler.tensorstack.dev/queue: demo
spec:
  schedulerName: t9k-scheduler
  containers:
  - image: nginx:latest
    name: test
    resources:
      requests:
        cpu: 1
        memory: 200Mi

通过 PodGroup 指定队列

如果 Pod 属于某个 PodGroup,那么 PodGroup 指定的队列就是这个 Pod 所属的队列。

Pod 如何指定 PodGroup 请参考 使用 PodGroup

T9k Jobs

T9k Job 包括 TensorFlowTrainingJob、PyTorchTrainingJob、XGBoostTrainingJob、GenericJob、MPIJob、ColossalAIJob、DeepSpeedJob 和 BeamJob,这些 Job 中都有相同的 spec.scheduler 字段。

创建 T9k Job 时,用户可以通过设置 spec.scheduler 字段来表明使用 T9k scheduler,并指定 Job 使用哪个队列。

在下面的示例中:spec.scheduler.t9kScheduler.queue 字段表明 Job 使用的队列是 demo,GenericJob 控制器会自动创建使用队列 demo 的 PodGroup 和 Pod。

apiVersion: batch.tensorstack.dev/v1beta1
kind: GenericJob
metadata:
 name: job-sample
spec:
 scheduler:
   t9kScheduler:
     queue: demo
     priority: 10
 replicaSpecs:
   - type: worker
     replicas: 4
     ...
   - type: ps
     replicas: 1
     ...

T9k PodGroup

创建 PodGroup 时,通过 spec.queue 字段来表明 PodGroup 所使用的队列。

在下面的示例中,PodGroup 表明自己使用的队列是 demo:

apiVersion: scheduler.tensorstack.dev/v1beta1
kind: PodGroup
metadata:
 name: test
spec:
 minMember: 2
 queue: demo
 priority: 50

batch/v1/Job

v1/Pod 类似,创建 batch/v1 Job 使用队列时,需要通过设置 Pod 的标签来表明 Pod 所使用的队列。有两种设置 Pod 标签的方法:

  • 直接指定队列:为 Pod 设置标签 scheduler.tensorstack.dev/queue:<queue-name> 表明 Pod 所使用的队列。
  • 通过 PodGroup 间接指定队列:为 Pod 设置标签 scheduler.tensorstack.dev/group-name:<group-name> 表明 Pod 所属的 PodGroup,PodGroup 使用的队列就是 Pod 使用的队列。

在下面的示例中,Job 通过为 Pod 设置标签 scheduler.tensorstack.dev/queue:demo 来表明使用队列 demo。

apiVersion: batch/v1
kind: Job
metadata:
 name: test
spec:
 parallelism: 2
 template:
   metadata:
     labels:
       scheduler.tensorstack.dev/queue: demo
   spec:
     schedulerName: t9k-scheduler
     containers:
       - name: create
         image: nginx:latest
         command:
         - sleep
         - 10s
         resources:
           requests:
             cpu: 1
             memory: 100Mi
     restartPolicy: Never

使用 PodGroup

概念

PodGroup 是 namespaced-scoped 资源对象,代表一组协同工作的 Pod。PodGroup spec 中定义了 coscheduling 和其他相关的配置信息,调度器 T9k Scheduler 会根据这些信息为 Pod 分配资源。

使用 PodGroup

根据工作负载的种类,创建并使用 PodGroup 的方式如下。

Pod

一般仅需要通过 Job 控制器自动化地实现对 PodGroup 的使用。工作负载控制器的编程者,或者需手工设定 pod 的 PodGroup,可参考本节内容。

用户创建一组使用调度器 T9k Scheduler 进行协同工作的 Pod 时,需要:

  1. 先在相同的 namespace 中创建一个 PodGroup
  2. 为 Pod 添加标签 scheduler.tensorstack.dev/group-name: <PodGroup-name> 来表明 Pod 属于步骤一创建的 PodGroup

示例1 - 基本场景

首先需要创建一个 PodGroup:

apiVersion: scheduler.tensorstack.dev/v1beta1
kind: PodGroup
metadata:
  name: dance
spec:
  minMember: 2
  queue: default
  priority: 50

然后创建 2 个 Pod 并指定 PodGroup,Pod 通过标签 scheduler.tensorstack.dev/group-name: dance 表明他们属于 PodGroup dance。

apiVersion: v1
kind: Pod
metadata:
  name: test1
  labels:
    scheduler.tensorstack.dev/group-name: dance
spec:
  schedulerName: t9k-scheduler
  containers:
  - image: nginx:latest
    name: test
    resources:
      requests:
        cpu: 1
        memory: 200Mi
--
apiVersion: v1
kind: Pod
metadata:
  name: test2
  labels:
    scheduler.tensorstack.dev/group-name: dance
spec:
  schedulerName: t9k-scheduler
  containers:
  - image: nginx:latest
    name: test
    resources:
      requests:
        cpu: 1
        memory: 200Mi

示例2 - 使用 role

本示例展示有 2 个 role 并设置了 role minMember 的 PodGroup 使用场景。

创建 PodGroup

apiVersion: scheduler.tensorstack.dev/v1beta1
kind: PodGroup
metadata:
  name: role-test
spec:
  roles:
  - name: master
    minMember: 1
  - name: worker
    minMember: 1
  minMember: 3
  queue: default
  priority: 50

说明:上面这个 PodGroup 的最小运行需求如下,这些需求都被满足了,调度器才会为 PodGroup 中的 Pod 分配资源:

  • PodGroup 的 Pod 数量需要达到 3
  • 角色名称是 master 的 Pod 数量需要达到 1
  • 角色名称是 worker 的 Pod 数量需要达到 1

创建 Pod:

apiVersion: v1
kind: Pod
metadata:
  name: master
  labels:
    scheduler.tensorstack.dev/group-name: role-test
    scheduler.tensorstack.dev/role: master
spec:
  schedulerName: t9k-scheduler
  containers:
  - image: nginx:latest
    name: test
    resources:
      requests:
        cpu: 100m
        memory: 200Mi
--
apiVersion: v1
kind: Pod
metadata:
  name: worker
  labels:
    scheduler.tensorstack.dev/group-name: role-test
    scheduler.tensorstack.dev/role: worker
spec:
  schedulerName: t9k-scheduler
  containers:
  - image: nginx:latest
    name: test
    resources:
      requests:
        cpu: 100m
        memory: 200Mi
--
apiVersion: v1
kind: Pod
metadata:
  name: worker1
  labels:
    scheduler.tensorstack.dev/group-name: role-test
    scheduler.tensorstack.dev/role: worker
spec:
  schedulerName: t9k-scheduler
  containers:
  - image: nginx:latest
    name: test
    resources:
      requests:
        cpu: 100m
        memory: 200Mi

Pod 通过标签 scheduler.tensorstack.dev/role: <role-name> 来表明自己的角色名称。

T9k Jobs

T9k Job 包括 TensorFlowTrainingJob、PyTorchTrainingJob、XGBoostTrainingJob、GenericJob、MPIJob、ColossalAIJob、DeepSpeedJob 和 BeamJob,这些 Job 中都有相同的 spec.scheduler 字段。

创建 T9k Job 时,用户可以通过设置 spec.scheduler 字段来表明使用 T9k scheduler,并指定 Job 使用哪个队列,然后控制器会自动地创建 PodGroup、并创建 Pod 使用这个 PodGroup。

基本示例

本示例适用于未启用弹性训练的 Job。

以下面这个 GenericJob 为例:

apiVersion: batch.tensorstack.dev/v1beta1
kind: GenericJob
metadata:
 name: job-sample
spec:
 scheduler:
   t9kScheduler:
     queue: default
     priority: 10
 replicaSpecs:
   - type: worker
     replicas: 4
     ...
   - type: ps
     replicas: 1
     ...

控制器在监测到上述 CRD 后,会创建一个 PodGroup:

apiVersion: scheduler.tensorstack.dev/v1beta1
kind: PodGroup
metadata:
  name: job-sample
  ownerReferences: [...]
spec:
  minMember: 5
  priority: 10
  queue: default

其中,priority 和 queue 字段参考 job 的 spec.scheduler.t9kScheduler 中的信息设置,minMember 即为 job 所有副本的总数。

随后,控制器会在创建副本的 Pod 时,为 Pod 设置标签 scheduler.tensorstack.dev/group-name: job-sample 来使用上述 PodGroup。

apiVersion: v1
kind: Pod
metadata:
  labels:
    genericjob: job-sample
    genericjob-replica: job-sample-worker-2
    scheduler.tensorstack.dev/group-name: job-sample
    scheduler.tensorstack.dev/queue: default
    tensorstack.dev/component: genericjob
    tensorstack.dev/component-type: user
  name: job-sample-worker-0
  namespace: dev-wangdi
  ownerReferences: [...]

弹性训练

弹性训练要求训练规模可以动态调整,所以对 PodGroup 的设置也有所不同。

T9k Job 中,PyTorchTrainingJob 和 DeepSpeedJob 支持弹性训练,他们具有相同的 spec.elastic 字段,以此启动弹性训练。

以下面的 PyTorchTrainingJob 为例:

  • spec.elastic.enabled 是 true 表明启用弹性训练
  • PyTorchTrainingJob 支持最少 3 个副本、最多 10 个副本的训练规模
apiVersion: batch.tensorstack.dev/v1beta1
kind: PyTorchTrainingJob
metadata:
 name: torch-mnist-trainingjob
spec:
 scheduler:
   t9kScheduler:
     queue: default
     priority: 10
 elastic:
   enabled: true
   minReplicas: 3
   maxReplicas: 10
   expectedReplicas: 7
 ...

控制器在监测到上述 CRD 后,会创建下列 PodGroup,使用 spec.elastic.minReplicas 作为 PodGroup 的 spec.minMember

apiVersion: scheduler.tensorstack.dev/v1beta1
kind: PodGroup
metadata:
  name: torch-mnist-trainingjob
  ownerReferences: [...]
spec:
  minMember: 3
  priority: 10
  queue: default

使用平台存储

上传和下载文件

通过 PVC 使用集群存储非常方便,它可作为存储卷被挂载到 Notebook、Job、MLService 等各种工作负载的 Pod 中。例如在进行模型训练时,你可以把训练脚本以及训练数据存放到 PVC,然后挂载在 Job 的 Pod 中。

本教程将分场景介绍如何从集群外部上传文件到 PVC,以及如何从 PVC 下载文件到集群外部。

由于下面的部分方法需要使用到命令行工具,而 Notebook 提供了终端并且 Notebook 的镜像中预装了这些命令行工具,因此我们推荐把 PVC 挂载到一个 Notebook 上,然后在 Notebook 中进行操作。

本地文件系统

Notebook

把 PVC 挂载到 Notebook 上,本地文件系统和 PVC 之间的文件传输,可直接在 Notebook 的前端页面上操作:

notebook-upload-download

File Browser

在 PVC 上启动 Explorer 之后,则可通过 File Browser

file-browser-upload-download

云存储中转

也可通过其他云存储服务进行中转,即 本地 -> 云存储 -> 集群 PVC

  1. 本地与云存储之间的文件传输方法请参阅相应云存储的文档;
  2. 云存储与 PVC 之间的文件传输方法请参阅云存储服务

云存储服务

要在云存储与 PVC 之间复制或同步文件,可以在 Notebook 的终端中使用命令行工具 rclone。这里以 Amazon S3 为例,首先参照 Amazon S3 Config 进行配置,完成后执行以下命令:

rclone copy <REMOTE>:<BUCKET>/path/to/the/file .   # 从 S3 存储下载
rclone copy ./file <REMOTE>:<BUCKET>/path/to/the/  # 上传到 S3 存储

rclone sync <REMOTE>:<BUCKET>/path/to/the/dir .    # 从 S3 存储同步
rclone sync . <REMOTE>:<BUCKET>/path/to/the/dir    # 同步到 S3 存储

rclone 之外,还有其他方便的工具可供使用,例如 s3cmds5cmd 等。

HTTP/FTP 服务

要通过 HTTP(S)、(S)FTP 等协议从网络下载文件到 PVC,可以在 Notebook 的终端中使用 wgetcurl 命令进行下载:

wget <URL>
curl -O <URL>

Git 仓库

可以在 Notebook 的终端中使用 git 命令,从 GitHub 等代码托管平台克隆或拉取项目,并在提交修改后推送回去:

git clone <repository>
git pull
git fetch
git push

Hugging Face Hub

Hugging Face Hub 是一个拥有超过 35 万个模型和 7.5 万个数据集的平台,所有这些模型和数据集都是开源并且公开可用的。从 Hugging Face Hub 下载一个模型或数据集有多种方法,下面以模型 mistralai/Mistral-7B-v0.1 为例进行演示,首先来到该模型的 Files and versions 标签页

files-and-versions

使用脚本

点击 Use in Transformers,按照提示进行操作,即在 Python 程序中调用 transformers 库加载模型。首次加载时,模型文件会被下载到缓存目录下,即 PVC 的 .cache/huggingface/hub/models--mistralai--Mistral-7B-v0.1/ 路径下。

use-in-transformers
use-in-transformers-detail
from transformers import pipeline

pipe = pipeline("text-generation", model="mistralai/Mistral-7B-v0.1")

# 或

from transformers import AutoTokenizer, AutoModelForCausalLM

tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1")
model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1")

使用 git

点击 Clone repository,按照提示进行操作,即使用 git 命令将模型的 Git 仓库直接克隆到 PVC 中:

clone-repository
clone-repository-detail
# git lfs install    # Notebook 的镜像中已经预装了 git-lfs,因此不必再执行
git clone https://huggingface.co/mistralai/Mistral-7B-v0.1

单个文件

如果只需要下载个别文件,例如只下载模型的 safetensors 文件,那么可以复制相应文件的下载链接,然后在终端中使用 wget 命令下载:

wget https://huggingface.co/mistralai/Mistral-7B-v0.1/resolve/main/model-00001-of-00002.safetensors?download=true
wget https://huggingface.co/mistralai/Mistral-7B-v0.1/resolve/main/model-00002-of-00002.safetensors?download=true

大规模数据

在处理大规模数据(如 100TB 级别)的导入和导出时,根据数据源的不同,我们采用不同的策略以确保数据传输的效率和安全性。以下是针对不同数据源的一些方法:

数据源为云存储时:

数据源为 HDD/SDD 外置驱动器或类似设备时:

  1. 将驱动器连接到集群外的与集群网络连接速度较快的计算机上,然后参照本地文件系统继续操作。
  2. 或者,请求管理员操作,将驱动器连接到存储集群的节点上,直接使用存储系统的工具进行数据传输。这种方法的数据传输速度一般较快,但需要能够访问存储集群的工具和接口。

参考

https://rclone.org/

https://huggingface.co/models

https://github.com/peak/s5cmd

https://github.com/s3tools/s3cmd

管理个人账户

这一部分演示如何使用生成并使用 API Key 来进行身份验证,以及如何管理自己负责的项目(如果你是项目管理员)。

生成 API Key

本教程演示如何生成一个 API Key。

准备工作

  • 了解 API Key 的基本概念。

开启 API Key 服务

进入安全管理控制台之后,在左侧的导航菜单中点击账号 > API Key 进入 API Key 管理页面。如果你是第一次使用 API Key 服务,需要进行一次额外的登录认证。点击启用开始登录认证。

enable-apikey

在弹出的对话框中,输入你的用户名和密码,并点击启用以开启 API Key 服务,右下角会有悬浮框提示是否成功。

login

生成一个 API Key

开启 API Key 服务之后,再次进入 API Key 管理页面,此时会列出你拥有的所有 API Key。点击右上角的创建新的 API Key 以生成一个新的 API Key。

apikey-list

在 API Key 生成页面,填写名称并勾选你想要包含在 API Key 中的权限,然后点击创建新的 API Key,右下角会有悬浮框提示是否成功。

gen-apikey

使用 API Key

本教程演示几种 API Key 的使用实例。

在 TensorStack CLI 中使用 API Key

你可以使用以下命令并按照提示信息完成 API Key 的录入,随后命令行工具将使用该 API Key 作为用户身份凭证向平台服务器发送请求。

t9k config auth <server-address> -u <user-name> -k

登录操作实质上就是将身份信息记录在 T9k Config 文件中作为一个上下文(context),该配置文件中可以同时记录多个上下文,使用以下命令查看、切换和删除:

# 查看所有上下文
% t9k config get-contexts
CURRENT   NAME            SERVER                     AUTH_TYPE
*         <config-name>   <server-address>           apikey

# 切换所要使用的上下文,即当前上下文
% t9k config use-context <config-name>

# 删除上下文
% t9k config delete-context <config-name>

关于 TensorStack CLI 的详细使用说明,请参阅CLI 用户指南

使用 API Key 作为凭证向 AIStore 上传数据

你可以在模型训练中使用 API Key 作为凭证向 AIStore 上传数据。

通常的模型训练

在使用 Python SDK 将数据上传到 AIStore 中时,你需要调用 t9k.em 模块的 login() 函数进行身份验证,在不设置 login() 函数参数的情况下,SDK 会自动使用 T9k Config 文件中当前上下文中的身份信息,如果你想在训练时使用其他身份信息,则可以设置 ais_hostapi_key 参数。

from t9k import em

# 使用 T9k Config 中当前上下文中的身份信息
em.login()

# 使用其他身份信息
em.login(ais_host='url-of-em-server', api_key='api-key-of-user')

AutoTuneExperiment

为了让 AutoTuneExperiment 能够使用 API Key,你需要创建一个 Secret 来存储 API Key,Secret 的格式如下:

apiVersion: v1
kind: Secret
metadata:
  name: aistore-secret
  namespace: t9k-example
data:
  apikey: ZDQyMjJjZjUtMmI0Ni00Mjk2LWFiMzYtYWI4NmVhZGUwZjQx  # API Key 的 Base64 编码
type: Opaque

在上述 Secret 中,在 data.apikey 字段中记录 API Key 的 Base64 编码。然后在 AutoTuneExperiment 的配置中引用这个 Secret,具体方式请参阅 AutoTuneExperiment 文档

添加项目成员

本教程演示如何为一个项目添加成员。

准备工作

  • 了解项目的基本概念。
  • 成为一个项目的管理员。如果你不是任何一个项目的管理员,请联系平台管理员为你创建一个项目。

查看自己的项目

在浏览器中进入安全管理控制台之后,在左侧的导航菜单中点击资源 > 项目进入项目列表页面。其中,我的项目部分列出了所有你作为管理员的项目,分享给我的项目部分列出了所有你作为成员的项目。

project-list

为项目添加用户

我的项目部分,点击其中一个项目的名称进入该项目的详情页面,这里展示了项目的所有成员(你是项目的管理员)。

project-detail

点击成员右侧的修改按钮,再点击 为该项目添加成员。在弹出的对话框中,你需要选择所要添加的成员名以及该成员可使用的范围(scope),填写完成之后点击保存提交更改,右下角会有悬浮框提示是否添加成功。

add-member

小技巧

本教程汇总了一些实用的小技巧,可以帮助用户更好地使用平台。

让 Notebook 不被资源回收

如果想要让 Notebook 不被资源回收,可以在该 Notebook 中创建一个 Jupyter Notebook,并运行以下代码:

# To keep the kernel active
import time

while True:
    time.sleep(60)

上述代码使 Notebook 保持活跃状态,而又不占用额外的计算资源。如要恢复对该 Notebook 的资源回收,只需停止上述代码的运行即可。

在终端中了解 Kubernetes API 资源及其字段

在创建、查看或调试 Kubernetes API 资源(包括 Kubernetes 原生资源和平台提供的 CRD)时,我们需要了解资源有哪些字段以及它们的含义。要获取这些信息,一种方法是查阅相应的参考文档,但更便捷的方式是在终端使用 kubectl explain 命令:

# 获取资源及其字段的描述
kubectl explain pod

# 获取资源的指定字段及其子字段的描述
kubectl explain pod.spec.containers

# 获取资源的所有子字段
kubectl explain pod --recursive

例如现在我们想要启用 DeepSpeedJob 的调试模式,但不知道该如何编写 YAML 配置文件,那么可以在 Notebook 的终端中执行以下命令:

kubectl explain dj --recursive    # `dj` 是 DeepSpeedJob 的简称

输出应类似于:

KIND:     DeepSpeedJob
VERSION:  batch.tensorstack.dev/v1beta1

DESCRIPTION:
     DeepSpeedJob defines the schema for the DeepSpeedJob API.

FIELDS:
   ...
   spec <Object>
      ...
      runMode   <Object>
         debug  <Object>
            enabled     <boolean>
            replicaSpecs        <[]Object>
               command  <[]string>
               skipInitContainer        <boolean>
               type     <string>
         pause  <Object>
            enabled     <boolean>
            resumeSpecs <[]Object>
               args     <[]string>
               command  <[]string>
               skipInitContainer        <boolean>
               type     <string>
      ...
   ...

由此我们得以写出正确的配置:

apiVersion: batch.tensorstack.dev/v1beta1
kind: DeepspeedJob
metadata:
  name: deepspeed-example
spec:
  runMode:
    debug:
      enabled: true
  ...

查看容器的日志

查看 Pod 中的容器的日志有两种方法。第一种方法是在终端使用 kubectl logs 命令:

# 首先列举所有 Pod
kubectl get pod

# 返回指定 Pod 的(唯一容器的)日志快照
kubectl logs nginx

# 持续输出日志
kubectl logs -f nginx

# 返回日志的最后 20 行
kubectl logs --tail=20 nginx

# 返回最近 1 个小时的日志
kubectl logs --since=1h nginx

第二种方法是在控制台中查看。进入模型构建控制台,在左侧的导航菜单中点击构建 > Pod 进入 Pod 管理页面,然后点击 Pod 的名称进入详情页面:

list

点击日志右侧的按钮即可查看日志:

details
log

此外,部分 CRD 所创建的 Pod 的容器日志也可以从相应 CRD 的详情页面查看,请参阅:

命令行工具和 SDK

除了在网页控制台进行操作外,你还可以使用命令行工具和 Python SDK 来与 TensorStack AI 平台进行交互。

此外,命令行工具和 Python SDK 也为平台的部分功能提供支持。

命令行工具:t9k

TensorStack CLI(简称 T9k CLI)是 TensorStack AI 平台的命令行工具,用于对 TensorStack AI 平台的各种资源对象进行增、删、改、查操作。

功能

TensorStack CLI 目前包含了两大功能:其一是管理 T9k 集群计算资源分配,主要的使用者是 TensorStack AI 平台管理员;其二是管理 TensorStack AI 平台中被创建的作业、服务等资源,主要的使用者是使用平台进行机器学习模型开发、训练、部署等工作的数据科学家。

TensorStack CLI 的目标是:提供对于 T9k 自定义资源的有效支持。对于平台管理员来说,这些功能可以作为 kubectl 的补充来管理 TensorStack AI 平台。对于数据科学家来说,这些功能和控制台一起,帮助他们在 TensorStack AI 平台上开展机器学习相关的工作,而不需要过多的 Kubernetes 基础知识。

architecture
图 1:T9k CLI 示意图

资源类型

T9k CLI 支持的资源类型有:

  • 基于 Kubernetes 定义的,用来解决机器学习相关问题的 TensorStack AI 平台资源:
    • AutoTune
    • BeamJob
    • ColossalAIJob
    • DeepSpeedJob
    • GenericJob
    • MLService
    • MPIJob
    • Notebook
    • PyTorchTrainingJob
    • SimpleMLService
    • TensorFlowTrainingJob
    • WorkflowTemplate
    • WorkflowRun
    • XGBoostTrainingJob
  • 基于 Kubernetes 定义的,用来管理集群资源及权限的 TensorStack AI 平台资源:
    • PodGroup
    • Project
    • Queue

用户指南

下载安装

下载

TensorStack CLI(以下简称 T9k CLI)可以从平台首页下载。请根据操作系统和架构(可以在命令行运行 uname -om 获取)选择适当的版本。

安装

你需要根据下载的版本,设置 T9k CLI 的版本和系统架构等变量:

version=1.78.6
os=darwin
arch=amd64

然后解压下载好的 T9k CLI,并把得到的二进制文件移动到 /usr/local/bin 路径下:

tar -zxvf "$HOME/Downloads/t9k-$version-$os-$arch.tar.gz"
mv t9k-$os-$arch /usr/local/bin/t9k
rm -f "$HOME/Downloads/t9k-$version-$os-$arch.tar.gz"

你可以运行以下命令来验证 T9k CLI 安装完成:

t9k version

卸载

删除二进制文件以卸载 T9k CLI。

rm -f /usr/local/bin/t9k

配置文件

TensorStack CLI 使用 T9k Config 作为配置文件。T9k Config 文件的路径通过命令行参数 -c, --config 进行指定,在未被指定时,使用默认路径 $HOME/.t9k/t9k-config.yaml。第一次使用时,可以通过 t9k config auth 命令来生成配置文件,详情请参阅 t9k config auth

T9k Config 示例如下:

current-context: default-context
contexts:
- name: default-context
  server: https://<example.com>
  image-registry: https://<example.io>
  prefixes:
    aistore: /t9k/aistore/server
    asset-hub: /t9k/asset-hub/server
    build-console: /t9k/build-console/server
    cluster-admin: /t9k/cluster-admin/server
    deploy-console: /t9k/deploy-console/server
    security-console: /t9k/security/server
    workflow-manager: /t9k/workflow/server
  auth:
    apikey: <your-apikey>
    token: <your-token>
  extension:
    codepack:
      data-copy-image: <your-image>

T9k Config 包括以下两个部分:

  • current-context:字符串,记录默认使用的 Context 名称。你可以通过设置命令行参数 -x, --context 访问其他的 Context。
  • contexts:数组,包含集群相关信息。
    • name:字符串,Context 的名称。
    • server:字符串,记录访问这个集群服务的域名。
    • image-registry:字符串,记录这个集群使用镜像仓库的地址。
    • prefixes:数组,记录这个集群中的 T9k Servers 路径前缀。
    • auth:,记录认证信息,支持 apikeytoken 两种认证方式,需要填写其中一种。
    • extension:记录其他工具需要用到的拓展配置。

全局选项

TensorStack CLI 定义了以下的全局命令行参数:

  -c, --config string      t9k config file (default: $HOME/.t9k/t9k-config.yaml)
  -x, --context string     name of the context to use (default: current-context in t9k config)
  -h, --help               t9k help
  -n, --namespace string   alias of -p and --project, invalid if --project is set by user.
  -p, --project string     project to use (default: from t9k config file)
  -v, --verbose int        Set level-based filter in logging (default -1)

具体说明如下:

  • -c, --config:字符串,指定 T9k Config 文件的路径。对于子命令 config,设置的 T9k Config 文件会被创建或修改。默认路径是 $HOME/.t9k/t9k-config.yaml
  • -x, --context:字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 current-context 字段指定的 Context。
  • -h, --help :查看当前指令的帮助信息和示例。
  • -p, --project:字符串,指定使用的项目(本文档中的项目和命名空间同义)。
  • -n, --namespace:字符串,和 -p, --project 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
  • -v, --verbose:指定输出 log 信息的详细程度。

项目(命名空间)的使用优先级是(排在前面的优先级更高):

  1. 你通过命令行参数 -p, --project 设置的项目。
  2. 你通过命令行参数 -n, --namespace 设置的项目。
  3. 使用项目 default

命令

autotune

用于管理 AutoTune

delete

删除指定的 AutoTune。

使用

t9k autotune delete [names...] [--all] [-f]

t9k autotune delete 也可以用 t9k autotune rm 代替。

选项

--all                   删除当前 Project 中的所有 AutoTunes。
-f, --force             跳过确认,直接执行删除操作。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

删除 Project demo 下名为 foo 和 bar 的两个 AutoTune:

t9k autotune delete foo bar -p demo

跳过确认,直接删除 Project demo 下名为 foo 的 AutoTune:

t9k autotune delete foo -p demo -f

删除 Project demo 下所有的 AutoTune:

t9k autotune delete foo -p demo --all

describe

查看某个 AutoTune 的详细信息。

使用

t9k at describe <name> [--color]

t9k at describe 也可以用 t9k at desc 代替。

选项

--color                 使用彩色的输出信息(默认全是黑色)。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project demo 下名为 foo 的 AutoTune 的详细描述:

t9k at describe foo -p demo

get

查看 AutoTune 相关信息。

使用

t9k at get [names...] [-A] [-o json|yaml|template]

选项

-A, --all-namespaces    获取用户具有权限的所有 Namespace(Project)中的资源。
-o, --output string     指定输出信息的形式。可选值有 `json`,`yaml` 和默认的 `template`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

以默认格式查看 Project example 下所有 AutoTune:

t9k at get -p example

以默认格式查看所有 Project 下的所有 AutoTune:

t9k at get -A

以默认格式查看 Project example 下名为 foo 和 bar 的两个 AutoTune:

t9k at get foo bar -p example

以 yaml 格式查看 Project example 下名为 foo 的 AutoTune:

t9k at get foo -p example -o yaml

wait

等待 AutoTune 完成。

使用

t9k at wait <name> [--timeout=<timeoutTime>] [--period=<periodTime>] [--print-log]

选项

--timeout string        字符串,最长等待时间。默认值:"1h",1 小时。
--period  string        字符串,检查任务是否完成的周期。默认值:"1s",每秒检查一次。
--print-log             是否在等待时流式查看日志。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

等待 Project example 下的 AutoTune foo 完成:

t9k at wait foo -p example

等待 Project example 下的 AutoTune foo 完成,只等待 10 分钟:

t9k at wait foo -p example --timeout 10m

等待 Project example 下的 AutoTune foo 完成,同时打印 server 的日志:

t9k at wait foo -p example --print-log

beamjob

用于管理 BeamJob

delete

删除指定的 BeamJob。

使用

t9k beamjob delete [names...] [--all] [-f]

t9k beamjob delete 也可以用 t9k bj rm 代替。

选项

--all                   删除当前 Project 中所有的 BeamJob。
-f, --force             跳过确认,直接执行删除操作。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

删除 Project demo 下名为 foo 和 bar 的两个 BeamJob:

t9k beamjob delete foo bar -p demo

跳过确认,直接删除 Project demo 下名为 foo 的 BeamJob:

t9k beamjob delete foo -p demo -f

删除 Project demo 下所有的 BeamJob:

t9k beamjob delete foo -p demo --all

describe

查看某个 BeamJob 的详细信息。

使用

t9k bj describe <name>

t9k bj describe 也可以用 t9k bj desc 代替。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project demo 下名为 foo 的 BeamJob 的详细描述:

t9k bj describe foo -p demo

get

查看 BeamJob 相关信息。

使用

t9k bj get [names...] [-A] [-o json|yaml|template]

选项

-A, --all-namespaces    获取用户具有权限的所有 Namespace(Project)中的资源。
-o, --output string     指定输出信息的形式。可选值有 `json`,`yaml` 和默认的 `template`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

以默认格式查看 Project example 下所有 BeamJob:

t9k bj get -p example

以默认格式查看所有 Project 下的所有 BeamJob:

t9k bj get -A

以默认格式查看 Project example 下名为 foo 和 bar 的两个 BeamJob:

t9k bj get foo bar -p example

以 yaml 格式查看 Project example 下名为 foo 的 BeamJob:

t9k bj get foo -p example -o yaml

logs

查看 BeamJob 某个计算节点的日志。

使用

t9k bj logs [--type=jobmanager|taskmanager|batchjob] [--index=<replicaIndex>] [--container=<containerName>] [-f] [--tail] [--timestamps]

选项

--container string      字符串,指定要查看的 container 名称,如果计算节点的 container 不止 1 个,必须指定此项。
-f, --follow            流式查看日志。
--index string          字符串,要查看的计算节点的序号。默认值:0。
--tail int              整数,要查看的日志的行数(从后往前)。默认值:-1,查看全部日志。
--timestamps            是否展示时间戳。
--type string           字符串,要查看的计算节点的角色。可选值有 `taskmanager`,`batchjob` 以及默认值 `jobmanager`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project example 下 BeamJob foo 第 replicaIndexreplicaType 节点的日志:

t9k bj logs foo --type=replicaType --index=replicaIndex -p example

流式查看 Project example 下 BeamJob foo 第 replicaIndexreplicaType 节点的容器 mnist 的日志:

t9k bj logs foo --type=replicaType --index=replicaIndex --container=mnist --follow

查看 BeamJob foo 第 0 个 jobmanager 节点的最后 20 行日志:

t9k bj logs foo --tail 20

wait

等待 BeamJob 完成。

使用

t9k bj wait <name> [--timeout=<timeoutTime>] [--period=<periodTime>] [--print-log [--type=jobmanager|taskmanager|batchjob] [--index=<replicaIndex>] [--container=<containerName>] [--timestamps]]

选项

--timeout string        字符串,最长等待时间。默认值:"1h",1 小时。
--period  string        字符串,检查任务是否完成的周期。默认值:"1s",每秒检查一次。
--print-log             是否在等待时流式查看日志。

以下参数只有在开启了 `--print-log` 后才生效。

--container string      字符串,指定要查看的 container 名称,如果计算节点的 container 不止 1 个,必须指定此项。
--index string          字符串,要查看的计算节点的序号。默认值:0。
--timestamps            是否展示时间戳。
--type string           字符串,要查看的计算节点的角色。可选值有 `taskmanager`,`batchjob` 以及默认值 `jobmanager`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

等待 Project example 下的 BeamJob foo 完成:

t9k bj wait foo -p example

等待 Project example 下的 BeamJob foo 完成,只等待 10 分钟:

t9k bj wait foo -p example --timeout 10m

等待 Project example 下的 BeamJob foo 完成,同时打印节点 flinkcluster-taskmanager-0 的日志:

t9k bj wait foo -p example --print-log --type taskmanager --index 0

colossalaijob

用于管理 ColossalAIJob

delete

删除指定的 ColossalAIJob。

使用

t9k colossalaijob delete [names...] [--all] [-f]

t9k colossalaijob delete 也可以用 t9k caij rm 代替。

选项

--all                   删除当前 Project 中所有的 ColossalAIJob。
-f, --force             跳过确认,直接执行删除操作。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

删除 Project demo 下名为 foo 和 bar 的两个 ColossalAIJob:

t9k colossalaijob delete foo bar -p demo

跳过确认,直接删除 Project demo 下名为 foo 的 ColossalAIJob:

t9k colossalaijob delete foo -p demo -f

删除 Project demo 下所有的 ColossalAIJob:

t9k colossalaijob delete foo -p demo --all

describe

查看某个 ColossalAIJob 的详细信息。

使用

t9k caij describe <name>

t9k caij describe 也可以用 t9k caij desc 代替。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project demo 下名为 foo 的 ColossalAIJob 的详细描述:

t9k caij describe foo -p demo

get

查看 ColossalAIJob 相关信息。

使用

t9k caij get [names...] [-A] [-o json|yaml|template]

选项

-A, --all-namespaces    获取用户具有权限的所有 Namespace(Project)中的资源。
-o, --output string     指定输出信息的形式。可选值有 `json`,`yaml` 和默认的 `template`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

以默认格式查看 Project example 下所有 ColossalAIJob:

t9k caij get -p example

以默认格式查看所有 Project 下的所有 ColossalAIJob:

t9k caij get -A

以默认格式查看 Project example 下名为 foo 和 bar 的两个 ColossalAIJob:

t9k caij get foo bar -p example

以 yaml 格式查看 Project example 下名为 foo 的 ColossalAIJob:

t9k caij get foo -p example -o yaml

logs

查看 ColossalAIJob 某个计算节点的日志。

使用

t9k caij logs [--type=master|worker] [--index=<replicaIndex>] [--container=<containerName>] [-f] [--tail] [--timestamps]

选项

--container string      字符串,指定要查看的 container 名称,如果计算节点的 container 不止 1 个,必须指定此项。
-f, --follow            流式查看日志。
--index string          字符串,要查看的计算节点的序号。默认值:0。
--tail int              整数,要查看的日志的行数(从后往前)。默认值:-1,查看全部日志。
--timestamps            是否展示时间戳。
--type string           字符串,要查看的计算节点的角色。可选值有 `master` 以及默认值 `worker`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project example 下 ColossalAIJob foo 第 replicaIndexreplicaType 节点的日志:

t9k caij logs foo --type=replicaType --index=replicaIndex -p example

流式查看 Project example 下 ColossalAIJob foo 第 replicaIndexreplicaType 节点的容器 mnist 的日志:

t9k caij logs foo --type=replicaType --index=replicaIndex --container=mnist --follow

查看 ColossalAIJob foo 第 0 个 worker 节点的最后 20 行日志:

t9k caij logs foo --tail 20

wait

等待 ColossalAIJob 完成。

使用

t9k caij wait <name> [--timeout=<timeoutTime>] [--period=<periodTime>] [--print-log [--type=master|worker] [--index=<replicaIndex>] [--container=<containerName>] [--timestamps]]

选项

--timeout string        字符串,最长等待时间。默认值:"1h",1 小时。
--period  string        字符串,检查任务是否完成的周期。默认值:"1s",每秒检查一次。
--print-log             是否在等待时流式查看日志。

以下参数只有在开启了 `--print-log` 后才生效。

--container string      字符串,指定要查看的 container 名称,如果计算节点的 container 不止 1 个,必须指定此项。
--index string          字符串,要查看的计算节点的序号。默认值:0。
--timestamps            是否展示时间戳。
--type string           字符串,要查看的计算节点的角色。可选值有 `master` 以及默认值 `worker`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

等待 Project example 下的 ColossalAIJob foo 完成:

t9k caij wait foo -p example

等待 Project example 下的 ColossalAIJob foo 完成,只等待 10 分钟:

t9k caij wait foo -p example --timeout 10m

等待 Project example 下的 ColossalAIJob foo 完成,同时打印节点 master-0 的日志:

t9k caij wait foo -p example --print-log --type master --index 0

config

对指定的 T9k Config 进行生成、管理、查看。T9k Config 默认使用文件 ${HOME}/.t9k/t9k-config.yaml,可通过全局选项 -c, --config 指定该文件路径。

auth

完成用户身份认证,生成 T9k Config。用户第一次使用 T9k 命令行工具时,需要使用此命令来进行身份认证。认证成功后,此命令会修改(如果是首次认证会新建)T9k Config。之后用户便可以通过该认证信息去使用 T9k 其他命令。

使用

t9k config auth <server> [--apikey] [--user=<username>]

选项

-k, --apikey            启用交互式输入 API Key。
-u, --user string       字符串,指定用户密码登录的用户名称。

全局选项

-c, --config            字符串,指定要查看、修改的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定新增 Context 的名称。
-h, --help              查看当前指令的帮助信息和示例。
-v, --verbose           指定输出 log 信息的详细程度。

示例

通过用户密码完成认证

用户指定要登录的域名,然后输入用户名和密码完成认证。认证完成后,当前的 T9k Config 中便会新增一个 <用户名>-<域名> 的 Context,用户也可以自己指定 Context 的名称。

$ t9k config auth <http://example.com>
Authenticating using username and password by default, add --apikey to use apikey.
Please enter your username: demo
Please enter your password:
Please enter Context name [default: demo-example.com]: demo
Login succeeded!

!!! note “注意” Context 的名称需要满足 DNS Subdomain Names 的要求,如果 Context 名字重复,可以选择覆盖原内容或者重新输入。

通过 API Key 完成认证

用户指定要登录的域名,然后输入 API Key。认证完成后,当前的 T9k Config 中便会新增一个 apikey-<hash>-<域名> 的 Context,用户也可以自己指定 Context 的名称。

$ t9k config auth <http://example.com> --apikey
Authenticating using API Key...
Please enter your API Key:
Please enter Context name [default: apikey-<hash>-example.com]: demo-apikey
Login succeeded!

delete-context

删除指定的 Context。

!!! note “注意” 即使指定的 Context 是 current-context,此命令也会直接删除掉。所以务必确认之后再删除。

使用

t9k config delete-context <name>

全局选项

-c, --config            字符串,指定要查看、修改的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-h, --help              查看当前指令的帮助信息和示例。
-v, --verbose           指定输出 log 信息的详细程度。

示例

删除 Context demo:

t9k config delete-context demo

get-contexts

用于获取当前使用的 T9k Config 中 Context 的相关信息。具体包括:

  • CURRENT:是否是当前正在使用的 Context
  • NAME:Context 的名称
  • SERVER:T9k 平台的地址
  • AUTH_TYPE:认证信息的类型(token 或者 apikey)

使用

t9k config get-contexts [name] 

全局选项

-c, --config            字符串,指定要查看、修改的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-h, --help              查看当前指令的帮助信息和示例。
-v, --verbose           指定输出 log 信息的详细程度。

示例

获取当前 T9k Config 中所有 Context 的信息:

t9k config get-contexts

获取指定 Context 的信息:

t9k config get-contexts my-context

use-context

切换当前使用的 Context,此命令会修改当前 T9k Config 中 current-context 的值。

使用

t9k config use-context <name>

全局选项

-c, --config            字符串,指定要查看、修改的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-h, --help              查看当前指令的帮助信息和示例。
-v, --verbose           指定输出 log 信息的详细程度。

示例

切换到 Context foo:

t9k config use-context foo

将文件 $HOME/t9kConfig.yaml 下的 Context 切换到 foo:

t9k config use-context foo -c $HOME/t9kConfig.yaml

create

通过文件创建 TensorStack AI 平台的资源或者其他支持的资源 (PVC 和 secret)。

使用

t9k create --filename=<file>

选项

-f, --filename          文件路径

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

通过文件在 Project demo 下创建一个 Notebook 资源。

t9k create -f notebook.yaml -p demo

delete

根据文件删除资源。

使用

t9k delete --filename=<file>

选项

-f, --filename          文件路径

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

根据文件内容删除 Project demo 下相应的 Notebook 资源。

t9k delete -f notebook.yaml -p demo

deepspeedjob

用于管理 DeepSpeedJob

delete

删除指定的 DeepSpeedJob。

使用

t9k deepspeedjob delete [names...] [--all] [-f]

t9k deepspeedjob delete 也可以用 t9k dj rm 代替。

选项

--all                   删除当前 Project 中所有的 DeepSpeedJob。
-f, --force             跳过确认,直接执行删除操作。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

删除 Project demo 下名为 foo 和 bar 的两个 DeepSpeedJob:

t9k deepspeedjob delete foo bar -p demo

跳过确认,直接删除 Project demo 下名为 foo 的 DeepSpeedJob:

t9k deepspeedjob delete foo -p demo -f

删除 Project demo 下所有的 DeepSpeedJob:

t9k deepspeedjob delete foo -p demo --all

describe

查看某个 DeepSpeedJob 的详细信息。

使用

t9k dj describe <name>

t9k dj describe 也可以用 t9k dj desc 代替。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project demo 下名为 foo 的 DeepSpeedJob 的详细描述:

t9k dj describe foo -p demo

get

查看 DeepSpeedJob 相关信息。

使用

t9k dj get [names...] [-A] [-o json|yaml|template]

选项

-A, --all-namespaces    获取用户具有权限的所有 Namespace(Project)中的资源。
-o, --output string     指定输出信息的形式。可选值有 `json`,`yaml` 和默认的 `template`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

以默认格式查看 Project example 下所有 DeepSpeedJob:

t9k dj get -p example

以默认格式查看所有 Project 下的所有 DeepSpeedJob:

t9k dj get -A

以默认格式查看 Project example 下名为 foo 和 bar 的两个 DeepSpeedJob:

t9k dj get foo bar -p example

以 yaml 格式查看 Project example 下名为 foo 的 DeepSpeedJob:

t9k dj get foo -p example -o yaml

logs

查看 DeepSpeedJob 某个计算节点的日志。

使用

t9k dj logs [--type=master|worker] [--index=<replicaIndex>] [--container=<containerName>] [-f] [--tail] [--timestamps]

选项

--container string      字符串,指定要查看的 container 名称,如果计算节点的 container 不止 1 个,必须指定此项。
-f, --follow            流式查看日志。
--index string          字符串,要查看的计算节点的序号。默认值:0。
--tail int              整数,要查看的日志的行数(从后往前)。默认值:-1,查看全部日志。
--timestamps            是否展示时间戳。
--type string           字符串,要查看的计算节点的角色。可选值有 `master` 以及默认值 `worker`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project example 下 DeepSpeedJob foo 第 replicaIndexreplicaType 节点的日志:

t9k dj logs foo --type=replicaType --index=replicaIndex -p example

流式查看 Project example 下 DeepSpeedJob foo 第 replicaIndexreplicaType 节点的容器 mnist 的日志:

t9k dj logs foo --type=replicaType --index=replicaIndex --container=mnist --follow

查看 DeepSpeedJob foo 第 0 个 worker 节点的最后 20 行日志:

t9k dj logs foo --tail 20

wait

等待 DeepSpeedJob 完成。

使用

t9k dj wait <name> [--timeout=<timeoutTime>] [--period=<periodTime>] [--print-log [--type=master|worker] [--index=<replicaIndex>] [--container=<containerName>] [--timestamps]]

选项

--timeout string        字符串,最长等待时间。默认值:"1h",1 小时。
--period  string        字符串,检查任务是否完成的周期。默认值:"1s",每秒检查一次。
--print-log             是否在等待时流式查看日志。

以下参数只有在开启了 `--print-log` 后才生效。

--container string      字符串,指定要查看的 container 名称,如果计算节点的 container 不止 1 个,必须指定此项。
--index string          字符串,要查看的计算节点的序号。默认值:0。
--timestamps            是否展示时间戳。
--type string           字符串,要查看的计算节点的角色。可选值有 `master` 以及默认值 `worker`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

等待 Project example 下的 DeepSpeedJob foo 完成:

t9k dj wait foo -p example

等待 Project example 下的 DeepSpeedJob foo 完成,只等待 10 分钟:

t9k dj wait foo -p example --timeout 10m

等待 Project example 下的 DeepSpeedJob foo 完成,同时打印节点 master-0 的日志:

t9k dj wait foo -p example --print-log --type master --index 0

genericjob

用于管理 GenericJob

delete

删除指定的 GenericJob。

使用

t9k genericjob delete [names...] [--all] [-f]

t9k genericjob delete 也可以用 t9k gj rm 代替。

选项

--all                   删除当前 Project 中所有的 GenericJob。
-f, --force             跳过确认,直接执行删除操作。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

删除 Project demo 下名为 foo 和 bar 的两个 GenericJob:

t9k genericjob delete foo bar -p demo

跳过确认,直接删除 Project demo 下名为 foo 的 GenericJob:

t9k genericjob delete foo -p demo -f

删除 Project demo 下所有的 GenericJob:

t9k genericjob delete foo -p demo --all

describe

查看某个 GenericJob 的详细信息。

使用

t9k gj describe <name>

t9k gj describe 也可以用 t9k gj desc 代替。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project demo 下名为 foo 的 GenericJob 的详细描述:

t9k gj describe foo -p demo

get

查看 GenericJob 相关信息。

使用

t9k gj get [names...] [-A] [-o json|yaml|template]

选项

-A, --all-namespaces    获取用户具有权限的所有 Namespace(Project)中的资源。
-o, --output string     指定输出信息的形式。可选值有 `json`,`yaml` 和默认的 `template`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

以默认格式查看 Project example 下所有 GenericJob:

t9k gj get -p example

以默认格式查看所有 Project 下的所有 GenericJob:

t9k gj get -A

以默认格式查看 Project example 下名为 foo 和 bar 的两个 GenericJob:

t9k gj get foo bar -p example

以 yaml 格式查看 Project example 下名为 foo 的 GenericJob:

t9k gj get foo -p example -o yaml

logs

查看 GenericJob 某个计算节点的日志。

使用

t9k gj logs [--type=master|worker] [--index=<replicaIndex>] [--container=<containerName>] [-f] [--tail] [--timestamps]

选项

--container string      字符串,指定要查看的 container 名称,如果计算节点的 container 不止 1 个,必须指定此项。
-f, --follow            流式查看日志。
--index string          字符串,要查看的计算节点的序号。默认值:0。
--tail int              整数,要查看的日志的行数(从后往前)。默认值:-1,查看全部日志。
--timestamps            是否展示时间戳。
--type string           字符串,要查看的计算节点的角色。可选值有 `master` 以及默认值 `worker`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project example 下 GenericJob foo 第 replicaIndexreplicaType 节点的日志:

t9k gj logs foo --type=replicaType --index=replicaIndex -p example

流式查看 Project example 下 GenericJob foo 第 replicaIndexreplicaType 节点的容器 mnist 的日志:

t9k gj logs foo --type=replicaType --index=replicaIndex --container=mnist --follow

查看 GenericJob foo 第 0 个 worker 节点的最后 20 行日志:

t9k gj logs foo --tail 20

wait

等待 GenericJob 完成。

使用

t9k gj wait <name> [--timeout=<timeoutTime>] [--period=<periodTime>] [--print-log [--type=master|worker] [--index=<replicaIndex>] [--container=<containerName>] [--timestamps]]

选项

--timeout string        字符串,最长等待时间。默认值:"1h",1 小时。
--period  string        字符串,检查任务是否完成的周期。默认值:"1s",每秒检查一次。
--print-log             是否在等待时流式查看日志。

以下参数只有在开启了 `--print-log` 后才生效。

--container string      字符串,指定要查看的 container 名称,如果计算节点的 container 不止 1 个,必须指定此项。
--index string          字符串,要查看的计算节点的序号。默认值:0。
--timestamps            是否展示时间戳。
--type string           字符串,要查看的计算节点的角色。可选值有 `master` 以及默认值 `worker`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

等待 Project example 下的 GenericJob foo 完成:

t9k gj wait foo -p example

等待 Project example 下的 GenericJob foo 完成,只等待 10 分钟:

t9k gj wait foo -p example --timeout 10m

等待 Project example 下的 GenericJob foo 完成,同时打印节点 master-0 的日志:

t9k gj wait foo -p example --print-log --type master --index 0

mlservice

用于管理 MLService

canary

设置金丝雀发布

使用

t9k mlservice set-canary [--default=default-release] [--canary=canary-release] [--traffic=canary-percentage] [--dry-run] [-o yaml|json]

选项

--canary string         字符串,指定金丝雀发布的版本名称
--default string        字符串,指定默认发布的版本名称
--dry-run               只打印更新后的 yaml 文件,但是不执行 apply 操作。
-o, --output string     字符串,指定 --dry-run 打印的格式。可选值有 `json`,`yaml`。
--traffic int           整数,指定金丝雀发布的路由权重

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

将 Project demo 下 MLService maskdetection 的默认发布版本设为 foo,金丝雀发布版本设为 bar 且权重为 20%:

t9k mlservice set-canary maskdetection --default=foo --canary=bar --traffic=20 -n demo

将 Project demo 下 MLService maskdetection 的金丝雀发布版本权重设为 30%:

t9k mlservice set-canary maskdetection --traffic=30 -n demo

将 Project demo 下 MLService maskdetection 的默认发布版本设为 foo

t9k mlservice set-canary maskdetection --default=foo

将 Project demo 下 MLService maskdetection 的金丝雀发布版本设为 bar

t9k mlservice set-canary maskdetection --canary=bar -n demo

delete

删除指定的 MLService。

使用

t9k mls delete [names...] [-f] [--all]

t9k mls delete 也可以用 t9k mls rm 代替。

选项

--all                   删除当前 Project 中所有的 XGBoostTrainingJob。
-f, --force             跳过确认,直接执行删除操作。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

删除 Project demo 下名为 foo 和 bar 的两个 MLService:

t9k mls delete foo bar -p demo

跳过确认,直接删除 Project demo 下名为 foo 的 MLService:

t9k mls delete foo -p demo -f

删除 Project demo 下所有的 MLService:

t9k mls delete foo -p demo --all

describe

查看 MLService 详细信息。

使用

t9k mls describe <name> [--color]

选项

--color                 使用彩色的输出信息(默认全是黑色)。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project demo 下名为 foo 的 MLService 的详细描述:

t9k mls describe foo -p demo

get

查看 MLService 相关信息。

使用

t9k mls get [names...] [-A] [-o json|yaml|template]

选项

-A, --all-namespaces       获取用户具有权限的所有 Namespace(Project)中的资源。
-o, --output string        指定输出信息的形式。可选值有 `json`,`yaml` 和默认的 `template`

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

以默认格式查看 Project example 下所有 MLService:

t9k mls get -p example

以默认格式查看所有 Project 下的所有 MLService:

t9k mls get -A

以默认格式查看 Project example 下名为 foo 和 bar 的两个 MLService:

t9k mls get foo bar -p example

以 yaml 格式查看 Project example 下名为 foo 的 MLService:

t9k mls get foo -p example -o yaml

delete-release

删除 MLService 中发布的版本。

使用

t9k delete-release <name> [--release=release-names...]

选项

--release string        字符串,删除的版本名称,如要删除多个版本,用 `,` 进行分割。
--dry-run               只打印更新后的 yaml 文件,但是不执行 apply 操作。
-o, --output string     字符串,指定 --dry-run 打印的格式。可选值有 `json`,`yaml`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

删除 Project demo 下的推理服务 maskdetection 的 foo 和 bar 两个已发布的版本:

t9k delete-release maskdetection --release foo,bar -p demo

mpijob

用于管理 MPIJob

delete

删除指定的 MPIJob。

使用

t9k mpijob delete [names...] [--all] [-f]

t9k mpijob delete 也可以用 t9k mj rm 代替。

选项

--all                   删除当前 Project 中所有的 MPIJob。
-f, --force             跳过确认,直接执行删除操作。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

删除 Project demo 下名为 foo 和 bar 的两个 MPIJob:

t9k mpijob delete foo bar -p demo

跳过确认,直接删除 Project demo 下名为 foo 的 MPIJob:

t9k mpijob delete foo -p demo -f

删除 Project demo 下所有的 MPIJob:

t9k mpijob delete foo -p demo --all

describe

查看某个 MPIJob 的详细信息。

使用

t9k mj describe <name>

t9k mj describe 也可以用 t9k mj desc 代替。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project demo 下名为 foo 的 MPIJob 的详细描述:

t9k mj describe foo -p demo

get

查看 MPIJob 相关信息。

使用

t9k mj get [names...] [-A] [-o json|yaml|template]

选项

-A, --all-namespaces    获取用户具有权限的所有 Namespace(Project)中的资源。
-o, --output string     指定输出信息的形式。可选值有 `json`,`yaml` 和默认的 `template`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

以默认格式查看 Project example 下所有 MPIJob:

t9k mj get -p example

以默认格式查看所有 Project 下的所有 MPIJob:

t9k mj get -A

以默认格式查看 Project example 下名为 foo 和 bar 的两个 MPIJob:

t9k mj get foo bar -p example

以 yaml 格式查看 Project example 下名为 foo 的 MPIJob:

t9k mj get foo -p example -o yaml

logs

查看 MPIJob 某个计算节点的日志。

使用

t9k mj logs [--type=launcher|worker] [--index=<replicaIndex>] [--container=<containerName>] [-f] [--tail] [--timestamps]

选项

--container string      字符串,指定要查看的 container 名称,如果计算节点的 container 不止 1 个,必须指定此项。
-f, --follow            流式查看日志。
--index string          字符串,要查看的计算节点的序号。默认值:0。
--tail int              整数,要查看的日志的行数(从后往前)。默认值:-1,查看全部日志。
--timestamps            是否展示时间戳。
--type string           字符串,要查看的计算节点的角色。可选值有 `launcher` 以及默认值 `worker`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project example 下 MPIJob foo 第 replicaIndexreplicaType 节点的日志:

t9k mj logs foo --type=replicaType --index=replicaIndex -p example

流式查看 Project example 下 MPIJob foo 第 replicaIndexreplicaType 节点的容器 mnist 的日志:

t9k mj logs foo --type=replicaType --index=replicaIndex --container=mnist --follow

查看 MPIJob foo 第 0 个 worker 节点的最后 20 行日志:

t9k mj logs foo --tail 20

wait

等待 MPIJob 完成。

使用

t9k mj wait <name> [--timeout=<timeoutTime>] [--period=<periodTime>] [--print-log [--type=launcher|worker] [--index=<replicaIndex>] [--container=<containerName>] [--timestamps]]

选项

--timeout string        字符串,最长等待时间。默认值:"1h",1 小时。
--period  string        字符串,检查任务是否完成的周期。默认值:"1s",每秒检查一次。
--print-log             是否在等待时流式查看日志。

以下参数只有在开启了 `--print-log` 后才生效。

--container string      字符串,指定要查看的 container 名称,如果计算节点的 container 不止 1 个,必须指定此项。
--index string          字符串,要查看的计算节点的序号。默认值:0。
--timestamps            是否展示时间戳。
--type string           字符串,要查看的计算节点的角色。可选值有 `launcher` 以及默认值 `worker`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

等待 Project example 下的 MPIJob foo 完成:

t9k mj wait foo -p example

等待 Project example 下的 MPIJob foo 完成,只等待 10 分钟:

t9k mj wait foo -p example --timeout 10m

等待 Project example 下的 MPIJob foo 完成,同时打印节点 launcher 的日志:

t9k mj wait foo -p example --print-log --type launcher

notebook

用于管理 Notebook

delete

删除指定的 Notebook。

使用

t9k notebook delete [names...] [--all] [-f]

t9k notebook delete 也可以用 t9k nb rm 代替。

选项

--all                   删除当前 Project 中所有的 Notebook。
-f, --force             跳过确认,直接执行删除操作。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

删除 Project demo 下名为 foo 和 bar 的两个 Notebook:

t9k notebook delete foo bar -p demo

跳过确认,直接删除 Project demo 下名为 foo 的 Notebook:

t9k notebook delete foo -p demo -f

删除 Project demo 下所有的 Notebook:

t9k notebook delete foo -p demo --all

describe

查看某个 Notebook 的详细信息。

使用

t9k nb describe <name>

t9k nb describe 也可以用 t9k nb desc 代替。

选项

--color                 使用彩色的输出信息(默认全是黑色)。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project demo 下名为 foo 的 Notebook 的详细描述:

t9k nb describe foo -p demo

get

查看 Notebook 相关信息。

使用

t9k nb get [names...] [-A] [-o json|yaml|template]

选项

-A, --all-namespaces    获取用户具有权限的所有 Namespace(Project)中的资源。
-o, --output string     字符串,指定输出信息的形式。可选值有 `json`,`yaml` 和默认的 `template`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

以默认格式查看 Project example 下所有 Notebook:

t9k nb get -p example

以默认格式查看所有 Project 下的所有 Notebook:

t9k nb get -A

以默认格式查看 Project example 下名为 foo 和 bar 的两个 Notebook:

t9k nb get foo bar -p example

以 yaml 格式查看 Project example 下名为 foo 的 Notebook:

t9k nb get foo -p example -o yaml

podgroup

用于管理 PodGroup,只有集群管理员才有相关权限。

get

查看 PodGroup 相关信息。

使用

t9k podgroup get [names...] [-A] [-o json|yaml|template]

选项

-A, --all-namespaces       获取用户具有权限的所有 Namespace(Project)中的资源。
-o, --output string        指定输出信息的形式。可选值有 `json`,`yaml` 和默认的 `template`

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

以默认格式查看 Project example 下所有 PodGroup:

t9k podgroup get -p example

以默认格式查看所有 Project 下的所有 PodGroup:

t9k podgroup get -A

以默认格式查看 Project example 下名为 foo 和 bar 的两个 PodGroup:

t9k podgroup get foo bar -p example

以 yaml 格式查看 Project example 下名为 foo 的 PodGroup:

t9k podgroup get foo -p example -o yaml

project

用于管理 Project

create

创建新项目,只有集群管理员才有权限创建新项目。

使用

t9k project create <name> <owner> [--build] [--deploy]

选项

--build                 项目拥有者是否拥有模型构建权限
--deploy                项目拥有者是否拥有模型部署权限

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

创建一个名为 sample 的项目,管理员为 admin,且 admin 只有模型构建的权限,没有模型部署的权限:

t9k project create sample admin --build

describe

查看项目详细描述,只能查看当前用户所拥有的项目。

使用

t9k proj describe <name>

t9k proj describe 也可以用 t9k proj desc 代替。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

详细描述项目 demo:

t9k proj describe demo

get

查看项目的相关信息,只能查看用户拥有权限的项目。

使用

t9k project get [name...]

可以通过指定 name 获取一个或多个 project,不指定的话默认获取所有当前用户有权限的项目。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看当前用户有权限的所有项目:

t9k project get

查看当前用户有权限的项目中名为 foo 的项目:

t9k project get foo

pytorchtrainingjob

用于管理 PyTorchTrainingJob

delete

删除指定的 PyTorchTrainingJob。

使用

t9k pytorchtrainingjob delete [names...] [--all] [-f]

t9k pytorchtrainingjob delete 也可以用 t9k pj rm 代替。

选项

--all                   删除当前 Project 中所有的 PyTorchTrainingJob。
-f, --force             跳过确认,直接执行删除操作。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

删除 Project demo 下名为 foo 和 bar 的两个 PyTorchTrainingJob:

t9k pytorchtrainingjob delete foo bar -p demo

跳过确认,直接删除 Project demo 下名为 foo 的 PyTorchTrainingJob:

t9k pytorchtrainingjob delete foo -p demo -f

删除 Project demo 下所有的 PyTorchTrainingJob:

t9k pytorchtrainingjob delete foo -p demo --all

describe

查看某个 PyTorchTrainingJob 的详细信息。

使用

t9k pj describe <name>

t9k pj describe 也可以用 t9k pj desc 代替。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project demo 下名为 foo 的 PyTorchTrainingJob 的详细描述:

t9k pj describe foo -p demo

get

查看 PyTorchTrainingJob 相关信息。

使用

t9k pj get [names...] [-A] [-o json|yaml|template]

选项

-A, --all-namespaces    获取用户具有权限的所有 Namespace(Project)中的资源。
-o, --output string     指定输出信息的形式。可选值有 `json`,`yaml` 和默认的 `template`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

以默认格式查看 Project example 下所有 PyTorchTrainingJob:

t9k pj get -p example

以默认格式查看所有 Project 下的所有 PyTorchTrainingJob:

t9k pj get -A

以默认格式查看 Project example 下名为 foo 和 bar 的两个 PyTorchTrainingJob:

t9k pj get foo bar -p example

以 yaml 格式查看 Project example 下名为 foo 的 PyTorchTrainingJob:

t9k pj get foo -p example -o yaml

logs

查看 PyTorchTrainingJob 某个计算节点的日志。

使用

t9k pj logs [--type=master|worker] [--index=<replicaIndex>] [--container=<containerName>] [-f] [--tail] [--timestamps]

选项

--container string      字符串,指定要查看的 container 名称,如果计算节点的 container 不止 1 个,必须指定此项。
-f, --follow            流式查看日志。
--index string          字符串,要查看的计算节点的序号。默认值:0。
--tail int              整数,要查看的日志的行数(从后往前)。默认值:-1,查看全部日志。
--timestamps            是否展示时间戳。
--type string           字符串,要查看的计算节点的角色。可选值有 `master` 以及默认值 `worker`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project example 下 PyTorchTrainingJob foo 第 replicaIndexreplicaType 节点的日志:

t9k pj logs foo --type=replicaType --index=replicaIndex -p example

流式查看 Project example 下 PyTorchTrainingJob foo 第 replicaIndexreplicaType 节点的容器 mnist 的日志:

t9k pj logs foo --type=replicaType --index=replicaIndex --container=mnist --follow

查看 PyTorchTrainingJob foo 第 0 个 worker 节点的最后 20 行日志:

t9k pj logs foo --tail 20

wait

等待 PyTorchTrainingJob 完成。

使用

t9k pj wait <name> [--timeout=<timeoutTime>] [--period=<periodTime>] [--print-log [--type=master|worker] [--index=<replicaIndex>] [--container=<containerName>] [--timestamps]]

选项

--timeout string        字符串,最长等待时间。默认值:"1h",1 小时。
--period  string        字符串,检查任务是否完成的周期。默认值:"1s",每秒检查一次。
--print-log             是否在等待时流式查看日志。

以下参数只有在开启了 `--print-log` 后才生效。

--container string      字符串,指定要查看的 container 名称,如果计算节点的 container 不止 1 个,必须指定此项。
--index string          字符串,要查看的计算节点的序号。默认值:0。
--timestamps            是否展示时间戳。
--type string           字符串,要查看的计算节点的角色。可选值有 `master` 以及默认值 `worker`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

等待 Project example 下的 PyTorchTrainingJob foo 完成:

t9k pj wait foo -p example

等待 Project example 下的 PyTorchTrainingJob foo 完成,只等待 10 分钟:

t9k pj wait foo -p example --timeout 10m

等待 Project example 下的 PyTorchTrainingJob foo 完成,同时打印节点 master-0 的日志:

t9k pj wait foo -p example --print-log --type master --index 0

queue

用于管理 Queue,只有集群管理员才有相关权限。

close

关闭 Queue。

使用

t9k queue close <name>

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-v, --verbose           指定输出 log 信息的详细程度。

示例

关闭 Queue foo:

t9k queue close foo

get

查看 Queue 相关信息。

使用

t9k queue get [names...] [-o json|yaml|template]

选项

-o, --output string        指定输出信息的形式。可选值有 `json`,`yaml` 和默认的 `template`

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-v, --verbose           指定输出 log 信息的详细程度。

示例

以默认格式查看所有 Queue:

t9k queue get

以默认格式查看名为 foo 和 bar 的两个 Queue:

t9k queue get foo bar

以 yaml 格式查看名为 foo 的 Queue:

t9k queue get foo -o yaml

open

打开 Queue。

使用

t9k queue open <name>

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-v, --verbose           指定输出 log 信息的详细程度。

示例

打开 Queue foo:

t9k queue open foo

simplemlservice

用于管理 SimpleMLService

create

创建一个新的 SimpleMLService。

使用

t9k simplemlservice create <name> --model=<model-url>  -image=<serving-image> [--secret=<serect-name>] [--tech tensorflow|pytorch|xgboost] [--dry-run] [-o yaml|json]

选项

--model string          字符串,推理服务使用的模型地址
--image string          字符串,推理服务使用的镜像
--dry-run               只打印更新后的 yaml 文件,但是不执行 apply 操作。
-o, --output string     字符串,指定 --dry-run 打印的格式。可选值有 `json`,`yaml`。
--tech string           字符串,推理服务使用的机器学习框架,如果 image 中已经含有关键字,可不填此参数。可选值有 `tensorflow`,`pytorch`,`xgboost`。
--secret string         字符串,加载模型所使用的密钥名称

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

在 Project demo 下创建一个名为 mnist 的推理服务。其使用的镜像为registry.tensorstack.dev/t9kmirror/tensorflow-serving:1.15.0,模型地址为 mms://aihub.tensorstack.dev/t9kpublic/mnist:v1

t9k simplemlservice create mnist \
  --model="mms://aihub.tensorstack.dev/t9kpublic/mnist:v1" \
  --image="registry.tensorstack.dev/t9kmirror/tensorflow-serving:1.15.0" \
  -n demo

在 Project t9k-sample 下创建一个名为 mnist-cnn 的推理服务。其使用的镜像为registry.tensorstack.dev/t9kmirror/tensorflow-serving:1.15.0,模型地址为 mms://aihub.tensorstack.dev/private/mnist:v2,模型下载使用的密钥为同一个 Project demo 下的 secret mms-access

t9k mls create mnist-cnn \
  --project=t9k-sample \
  --model="mms://aihub.tensorstack.dev/private/mnist:v2" \
  --image="registry.tensorstack.dev/t9kmirror/tensorflow-serving:1.15.0" \
  --tech="tensorflow" \
  --secret="mms-access" 

delete

删除指定的 SimpleMLService。

使用

t9k smls delete [names...] [-f] [--all]

t9k smls delete 也可以用 t9k smls rm 代替。

选项

--all                   删除当前 Project 中所有的 XGBoostTrainingJob。
-f, --force             跳过确认,直接执行删除操作。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

删除 Project demo 下名为 foo 和 bar 的两个 SimpleMLService:

t9k smls delete foo bar -p demo

跳过确认,直接删除 Project demo 下名为 foo 的 SimpleMLService:

t9k smls delete foo -p demo -f

删除 Project demo 下所有的 SimpleMLService:

t9k smls delete foo -p demo --all

describe

查看 SimpleMLService 详细信息。

使用

t9k mls describe <name>

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project demo 下名为 foo 的 SimpleMLService 的详细描述:

t9k mls describe foo -p demo

get

查看 SimpleMLService 相关信息。

使用

t9k smls get [names...] [-A] [-o json|yaml|template]

选项

-A, --all-namespaces       获取用户具有权限的所有 Namespace(Project)中的资源。
-o, --output string        指定输出信息的形式。可选值有 `json`,`yaml` 和默认的 `template`

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

以默认格式查看 Project example 下所有 SimpleMLService:

t9k smls get -p example

以默认格式查看所有 Project 下的所有 SimpleMLService:

t9k smls get -A

以默认格式查看 Project example 下名为 foo 和 bar 的两个 SimpleMLService:

t9k smls get foo bar -p example

以 yaml 格式查看 Project example 下名为 foo 的 SimpleMLService:

t9k smls get foo -p example -o yaml

tensorflowtrainingjob

用于管理 TensorFlowTrainingJob

delete

删除指定的 TensorFlowTrainingJob。

使用

t9k tensorflowtrainingjob delete [names...] [--all] [-f]

t9k tensorflowtrainingjob delete 也可以用 t9k tj rm 代替。

选项

--all                   删除当前 Project 中所有的 TensorFlowTrainingJob。
-f, --force             跳过确认,直接执行删除操作。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

删除 Project demo 下名为 foo 和 bar 的两个 TensorFlowTrainingJob:

t9k tensorflowtrainingjob delete foo bar -p demo

跳过确认,直接删除 Project demo 下名为 foo 的 TensorFlowTrainingJob:

t9k tensorflowtrainingjob delete foo -p demo -f

删除 Project demo 下所有的 TensorFlowTrainingJob:

t9k tensorflowtrainingjob delete foo -p demo --all

describe

查看某个 TensorFlowTrainingJob 的详细信息。

使用

t9k tj describe <name>

t9k tj describe 也可以用 t9k tj desc 代替。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project demo 下名为 foo 的 TensorFlowTrainingJob 的详细描述:

t9k tj describe foo -p demo

get

查看 TensorFlowTrainingJob 相关信息。

使用

t9k tj get [names...] [-A] [-o json|yaml|template]

选项

-A, --all-namespaces    获取用户具有权限的所有 Namespace(Project)中的资源。
-o, --output string     字符串,指定输出信息的形式。可选值有 `json`,`yaml` 和默认的 `template`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

以默认格式查看 Project example 下所有 TensorFlowTrainingJob:

t9k tj get -p example

以默认格式查看所有 Project 下的所有 TensorFlowTrainingJob:

t9k tj get -A

以默认格式查看 Project example 下名为 foo 和 bar 的两个 TensorFlowTrainingJob:

t9k tj get foo bar -p example

以 yaml 格式查看 Project example 下名为 foo 的 TensorFlowTrainingJob:

t9k tj get foo -p example -o yaml

logs

查看 TensorFlowTrainingJob 某个计算节点的日志。

使用

t9k tj logs <name> [--type=chief|ps|evaluator|worker] [--index=<replicaIndex>] [--container=<containerName>] [-f] [--tail] [--timestamps]

选项

--container string      字符串,指定要查看的 container 名称,如果计算节点的 container 不止 1 个,必须指定此项。
-f, --follow            流式查看日志。
--index string          字符串,要查看的计算节点的序号。默认值:0。
--tail int              整数,要查看的日志的行数(从后往前)。默认值:-1,查看全部日志。
--timestamps            是否展示时间戳。
--type string           字符串,要查看的计算节点的角色。可选值有 `chief`,`ps`,`evaluator` 以及默认值 `worker`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project example 下 TensorFlowTrainingJob foo 第 replicaIndexreplicaType 节点的日志:

t9k tj logs foo --type=replicaType --index=replicaIndex -p example

流式查看 Project example 下 TensorFlowTrainingJob foo 第 replicaIndexreplicaType 节点的容器 mnist 的日志:

t9k tj logs foo --type=replicaType --index=replicaIndex --container=mnist --follow

查看 TensorFlowTrainingJob foo 第 0 个 worker 节点的最后 20 行日志:

t9k tj logs foo --tail 20

wait

等待 TensorFlowTrainingJob 完成。

使用

t9k tj wait <name> [--timeout=<timeoutTime>] [--period=<periodTime>] [--print-log [--type=chief|ps|evaluator|worker] [--index=<replicaIndex>] [--container=<containerName>] [--timestamps]]

选项

--timeout string        字符串,最长等待时间。默认值:"1h",1 小时。
--period  string        字符串,检查任务是否完成的周期。默认值:"1s",每秒检查一次。
--print-log             是否在等待时流式查看日志。

以下参数只有在开启了 `--print-log` 后才生效。

--container string      字符串,指定要查看的 container 名称,如果计算节点的 container 不止 1 个,必须指定此项。
--index string          字符串,要查看的计算节点的序号。默认值:0。
--timestamps            是否展示时间戳。
--type string           字符串,要查看的计算节点的角色。可选值有 `chief`,`ps`,`evaluator` 以及默认值 `worker`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

等待 Project example 下的 TensorFlowTrainingJob foo 完成:

t9k tj wait foo -p example

等待 Project example 下的 TensorFlowTrainingJob foo 完成,只等待 10 分钟:

t9k tj wait foo -p example --timeout 10m

等待 Project example 下的 TensorFlowTrainingJob foo 完成,同时打印节点 chief-0 的日志:

t9k tj wait foo -p example --print-log --type chief --index 0

version

查看当前 T9k CLI 版本信息。

使用

t9k version

示例

查看当前 t9k 二进制文件的版本信息。

t9k version

workflowrun

用于管理 WorkflowRun

delete

删除指定的 WorkflowRun。

使用

t9k workflowrun delete [names...] [--all] [-f]

t9k workflowrun delete 也可以用 t9k wr rm 代替。

选项

--all                   删除当前 Project 中所有的 WorkflowRun。
-f, --force             跳过确认,直接执行删除操作。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

删除 Project demo 下名为 foo 和 bar 的两个 WorkflowRun:

t9k workflowrun delete foo bar -p demo

跳过确认,直接删除 Project demo 下名为 foo 的 WorkflowRun:

t9k workflowrun delete foo -p demo -f

删除 Project demo 下所有的 WorkflowRun:

t9k workflowrun delete foo -p demo --all

describe

查看某个 WorkflowRun 的详细信息。

使用

t9k wr describe <name>

t9k wr describe 也可以用 t9k wr desc 代替。

选项

--color                 使用彩色的输出信息(默认全是黑色)。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project demo 下名为 foo 的 WorkflowRun 的详细描述:

t9k wr describe foo -p demo

get

查看 WorkflowRun 相关信息。

使用

t9k wr get [names...] [-A] [-o json|yaml|template]

选项

-A, --all-namespaces    获取用户具有权限的所有 Namespace(Project)中的资源。
-o, --output string     字符串,指定输出信息的形式。可选值有 `json`,`yaml` 和默认的 `template`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

以默认格式查看 Project example 下所有 WorkflowRun:

t9k wr get -p example

以默认格式查看所有 Project 下的所有 WorkflowRun:

t9k wr get -A

以默认格式查看 Project example 下名为 foo 和 bar 的两个 WorkflowRun:

t9k wr get foo bar -p example

以 yaml 格式查看 Project example 下名为 foo 的 WorkflowRun:

t9k wr get foo -p example -o yaml

logs

查看 WorkflowRun 某个容器的日志,不支持直接查看 DAG 类型的 WorkflowRun 的日志。

使用

t9k wr logs [--container=<containerName>] [-f] [--tail] [--timestamps]

选项

--container string      字符串,指定要查看的 container 名称,如果计算节点的 container 不止 1 个,必须指定此项。
-f, --follow            流式查看日志。
--tail int              整数,要查看的日志的行数(从后往前)。默认值:-1,查看全部日志。
--timestamps            是否展示时间戳。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project demo 下 WorkflowRun foo 唯一容器的日志:

t9k wr logs foo -p demo

流式查看 Project demo 下 WorkflowRun foo 容器 mnist 的日志:

t9k wr logs foo --container=mnist -p demo -f

查看 Project demo 下 WorkflowRun foo 唯一容器的最后 20 行日志:

t9k wr logs foo -p demo --tail=20

wait

等待 WorkflowRun 完成,该命令不支持 DAG 类型的 WorkflowRun。

使用

t9k wr wait <name> [--timeout=<timeoutTime>] [--period=<periodTime>] [--print-log [--container=<containerName>] [--timestamps]]

选项

--timeout string        字符串,最长等待时间。默认值:"1h",1 小时。
--period  string        字符串,检查任务是否完成的周期。默认值:"1s",每秒检查一次。
--print-log             是否在等待时流式查看日志。

以下参数只有在开启了 `--print-log` 后才生效。

--container string      字符串,指定要查看的 container 名称,如果计算节点的 container 不止 1 个,必须指定此项。
--timestamps            是否展示时间戳。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

等待 Project example 下的 WorkflowRun foo 完成:

t9k wr wait foo -p example

等待 Project example 下的 WorkflowRun foo 完成,只等待 10 分钟:

t9k wr wait foo -p example --timeout 10m

等待 Project example 下的 WorkflowRun foo 完成,同时打印其容器 mnist 的日志:

t9k wr wait foo -p example --print-log --container mnist

workflowtemplate

用于管理 WorkflowTemplate

delete

删除指定的 WorkflowTemplate。

使用

t9k workflowtemplate delete [names...] [--all] [-f]

t9k workflowtemplate delete 也可以用 t9k wr rm 代替。

选项

--all                   删除当前 Project 中所有的 WorkflowTemplate。
-f, --force             跳过确认,直接执行删除操作。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

删除 Project demo 下名为 foo 和 bar 的两个 WorkflowTemplate:

t9k workflowtemplate delete foo bar -p demo

跳过确认,直接删除 Project demo 下名为 foo 的 WorkflowTemplate:

t9k workflowtemplate delete foo -p demo -f

删除 Project demo 下所有的 WorkflowTemplate:

t9k workflowtemplate delete foo -p demo --all

describe

查看某个 WorkflowTemplate 的详细信息。

使用

t9k wt describe <name>

t9k wt describe 也可以用 t9k wt desc 代替。

选项

--color                 使用彩色的输出信息(默认全是黑色)。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project demo 下名为 foo 的 WorkflowTemplate 的详细描述:

t9k wt describe foo -p demo

get

查看 WorkflowTemplate 相关信息。

使用

t9k wt get [names...] [-A] [-o json|yaml|template]

选项

-A, --all-namespaces    获取用户具有权限的所有 Namespace(Project)中的资源。
-o, --output string     字符串,指定输出信息的形式。可选值有 `json`,`yaml` 和默认的 `template`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

以默认格式查看 Project example 下所有 WorkflowTemplate:

t9k wt get -p example

以默认格式查看所有 Project 下的所有 WorkflowTemplate:

t9k wt get -A

以默认格式查看 Project example 下名为 foo 和 bar 的两个 WorkflowTemplate:

t9k wt get foo bar -p example

以 yaml 格式查看 Project example 下名为 foo 的 WorkflowTemplate:

t9k wt get foo -p example -o yaml

start

执行 WorkflowTemplate。

使用

t9k wt start <name> [-l <labelStrings>] [-r <paramStrings>] [-s <serviceAccount>] [--timeout=<timeoutTime>] [-w <workplaceStrings>] [--use-param-defaults] [--dry-run] [-o yaml|json]

选项

-l, --label strings          以键值对的方式指定 workflowRun 的 label。例如 -l "LABEL_1=VAL_1,LABEL_2=VAL_2"。
-r, --param strings          以键值对的方式指定 workflowRun 的参数。例如 -l "KEY_1=VAL_1,KEY_2=VAL_2"。
-w, --workspace strings      以键值对的方式指定 workspace 相关信息。例如 -w "name=$workspace_name,type=$workspace_type,$key$value"。
--use-param-defaults         是否采用默认参数
--timeout string             字符串,指定 workflowRun 的超时时间。
--dry-run                    只打印更新后的 yaml 文件,但是不执行 apply 操作。
-o, --output string          指定 --dry-run 打印的格式。可选值有 `json`,`yaml`。
-s, --serviceaccount string  指定 workflowRun 的 serviceAccount。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

执行 Project demo 下的 WorkflowTemplate foo:

t9k wt start foo -p demo

根据指定的 workspace 信息执行 Project demo 下的 WorkflowTemplate foo:

t9k wt start foo --workspace=name=bar,type=pvc,claimName=bar-pvc,subPath=/user/local/Document -p demo

执行 Project demo 下的 WorkflowTemplate foo,并设置参数 bar 值为 hello:

t9k wt start foo --param=bar=hello

xgboosttrainingjob

用于管理 XGBoostTrainingJob

delete

删除指定的 XGBoostTrainingJob。

使用

t9k xgboosttrainingjob delete [names...] [--all] [-f]

t9k xgboosttrainingjob delete 也可以用 t9k xj rm 代替。

选项

--all                   删除当前 Project 中所有的 XGBoostTrainingJob。
-f, --force             跳过确认,直接执行删除操作。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

删除 Project demo 下名为 foo 和 bar 的两个 XGBoostTrainingJob:

t9k xgboosttrainingjob delete foo bar -p demo

跳过确认,直接删除 Project demo 下名为 foo 的 XGBoostTrainingJob:

t9k xgboosttrainingjob delete foo -p demo -f

删除 Project demo 下所有的 XGBoostTrainingJob:

t9k xgboosttrainingjob delete foo -p demo --all

describe

查看某个 XGBoostTrainingJob 的详细信息。

使用

t9k xj describe <name>

t9k xj describe 也可以用 t9k xj desc 代替。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project demo 下名为 foo 的 XGBoostTrainingJob 的详细描述:

t9k xj describe foo -p demo

get

查看 XGBoostTrainingJob 相关信息。

使用

t9k xj get [names...] [-A] [-o json|yaml|template]

选项

-A, --all-namespaces    获取用户具有权限的所有 Namespace(Project)中的资源。
-o, --output string     字符串,指定输出信息的形式。可选值有 `json`,`yaml` 和默认的 `template`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

以默认格式查看 Project example 下所有 XGBoostTrainingJob:

t9k xj get -p example

以默认格式查看所有 Project 下的所有 XGBoostTrainingJob:

t9k xj get -A

以默认格式查看 Project example 下名为 foo 和 bar 的两个 XGBoostTrainingJob:

t9k xj get foo bar -p example

以 yaml 格式查看 Project example 下名为 foo 的 XGBoostTrainingJob:

t9k xj get foo -p example -o yaml

logs

查看 XGBoostTrainingJob 某个计算节点的日志。

使用

t9k xj logs [--type=master|worker] [--index=<replicaIndex>] [--container=<containerName>] [-f] [--tail] [--timestamps]

选项

--container string      字符串,指定要查看的 container 名称,如果计算节点的 container 不止 1 个,必须指定此项。
-f, --follow            流式查看日志。
--index string          字符串,要查看的计算节点的序号。默认值:0。
--tail int              整数,要查看的日志的行数(从后往前)。默认值:-1,查看全部日志。
--timestamps            是否展示时间戳。
--type string           字符串,要查看的计算节点的角色。可选值有 `master` 以及默认值 `worker`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

查看 Project example 下 XGBoostTrainingJob foo 第 replicaIndexreplicaType 节点的日志:

t9k xj logs foo --type=replicaType --index=replicaIndex -p example

流式查看 Project example 下 XGBoostTrainingJob foo 第 replicaIndexreplicaType 节点的容器 mnist 的日志:

t9k xj logs foo --type=replicaType --index=replicaIndex --container=mnist --follow

查看 XGBoostTrainingJob foo 第 0 个 worker 节点的最后 20 行日志:

t9k xj logs foo --tail 20

wait

等待 XGBoostTrainingJob 完成。

使用

t9k xj wait <name> [--timeout=<timeoutTime>] [--period=<periodTime>] [--print-log [--type=master|worker] [--index=<replicaIndex>] [--container=<containerName>] [--timestamps]]

选项

--timeout string        字符串,最长等待时间。默认值:"1h",1 小时。
--period  string        字符串,检查任务是否完成的周期。默认值:"1s",每秒检查一次。
--print-log             是否在等待时流式查看日志。

以下参数只有在开启了 `--print-log` 后才生效。

--container string      字符串,指定要查看的 container 名称,如果计算节点的 container 不止 1 个,必须指定此项。
--index string          字符串,要查看的计算节点的序号。默认值:0。
--timestamps            是否展示时间戳。
--type string           字符串,要查看的计算节点的角色。可选值有 `master` 以及默认值 `worker`。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-x, --context           字符串,指定使用 T9k Config 中的哪一个 Context,在未设置这个参数时,会使用 T9k Config 中 `current-context` 字段指定的 Context。
-h, --help              查看当前指令的帮助信息和示例。
-p, --project           字符串,指定使用的项目(本文档中的项目和命名空间同义)。
-n, --namespace         字符串,和 `-p, --project` 作用一致,指定使用的项目。这个设计是为了符合 kubectl 用户的习惯。
-v, --verbose           指定输出 log 信息的详细程度。

示例

等待 Project example 下的 XGBoostTrainingJob foo 完成:

t9k xj wait foo -p example

等待 Project example 下的 XGBoostTrainingJob foo 完成,只等待 10 分钟:

t9k xj wait foo -p example --timeout 10m

等待 Project example 下的 XGBoostTrainingJob foo 完成,同时打印节点 master-0 的日志:

t9k xj wait foo -p example --print-log --type master --index 0

命令行工具:t9k-pf

TensorStack AI 平台提供了命令行工具 t9k-pf,其功能类似于 kubectl port-forward,使用户能够在本地通过端口转发的方式访问 TensorStack AI 平台的各种资源。目前支持的资源类型有 Notebook、Pod、Service。

用户指南

下载安装

下载

t9k-pf 可以从平台首页下载。请根据操作系统和架构(可以在命令行运行 uname -om 获取)选择适当的版本。

安装

根据下载的版本,设置 t9k-pf 的版本和系统架构等变量:

version=0.2.6
os=darwin
arch=amd64

然后解压下载好的 t9k-pf,并把得到的二进制文件移动到 /usr/local/bin 路径下:

tar -zxvf "$HOME/Downloads/t9k-pf-$version-$os-$arch.tar.gz"
mv t9k-pf-$os-$arch /usr/local/bin/t9k-pf
rm -f "$HOME/Downloads/t9k-pf-$version-$os-$arch.tar.gz"

安装完成后,运行以下命令来验证安装是否成功:

t9k-pf version

卸载

删除二进制文件即可卸载 t9k-pf。

rm -f /usr/local/bin/t9k-pf

身份认证和授权

通过 T9k Config 进行身份认证和授权

t9k-pf 默认使用 T9k Config 来进行身份认证和授权。你可以通过命令行参数 -c, --config 来指定 t9k-pf 使用的 T9k Config 文件的路径,未指定时,默认使用 $HOME/.t9k/t9k-config.yaml 路径下 T9k Config 中 current-context 的认证信息。

下面是一个 T9k Config 的示例,其中 current-context 为 demo1,该 Context 的 token 字段不为空,因此最终 t9k-pf 使用该值 demo1-token 来完成身份验证(如果 apikey 和 token 均不为空,t9k-pf 优先使用 apikey)。

current-context: demo1
contexts:
- name: demo1
  server: https://<example.com>
  image-registry: https://<example.io>
  prefixes:
    aistore: /t9k/aistore/server
    asset-hub: /t9k/asset-hub/server
    build-console: /t9k/build-console/server
    cluster-admin: /t9k/cluster-admin/server
    deploy-console: /t9k/deploy-console/server
    security-console: /t9k/security/server
    workflow-manager: /t9k/workflow/server
  auth:
    apikey: ""
    token: demo1-token
  extension:
    codepack:
      data-copy-image: <your-image>
- name: demo2
  server: https://<example.com>
  ...

通过 API Key 进行临时身份认证和授权

t9k-pf 支持通过命令行参数 -k,--apikey 直接指定 API Key,完成单次端口转发的身份认证和授权。

例如输入以下指令(其中 notebook <URL> 会在命令中介绍,此处只用关注 --apikey 的使用):

t9k-pf notebook <url> --apikey

命令行会进入交互式输入界面,粘贴你的 API Key 再按下回车即可。

全局选项

  • -c, –config

    使用的 T9k Config 文件的路径。默认路径是 $HOME/.t9k/t9k-config.yaml

  • -k, –apikey

    开启交互式输入 API Key。

  • -n, –namespace

    使用的项目(命名空间)名称。

  • -h, –help

    查看当前指令的帮助信息和示例。

  • –address

    本地监听地址。默认为 localhost

  • –retryMaxTimes

    整数,最大重试次数。默认为 10

  • –retryPeriod

    整数,重试间隔时间(单位:秒)。默认为 10

命令

notebook

针对 TensorStack AI 平台的 Notebook 资源,我们提供了直接通过其 URL 地址获取 SSH 连接方式的功能。使用该命令,你不需要指定名称、命名空间等信息。关于 SSH 连接的详细内容请参阅通过 SSH 连接远程使用 Notebook

使用

t9k-pf notebook <url> <localPort>

其中 <url> 代表地址栏中的地址,<localPort> 代表你指定的本地端口号(小于 1024 的本地端口需要管理员权限才可以绑定),如果不指定,会随机使用一个本地端口。

t9k-pf notebook 也可以用 t9k-pf nb 代替。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-h, --help              查看当前指令的帮助信息和示例。
-n, --namespace         字符串,指定使用的项目(命名空间)名称。
-k, --apikey            开启交互式输入 API Key。
--address               本地监听地址。默认为 `localhost`。
--retryMaxTimes         整数,最大重试次数。默认为 `10`。
--retryPeriod           整数,重试间隔时间(单位:秒)。默认为 `10`。

示例

通过本地 127.0.0.1 的随机端口访问 Project demo 下 Notebook ml-labs 的 SSH 端口。

t9k-pf notebook <tensorstack-host>/t9k/build-console/projects/demo/notebooks/ml-labs/lab

通过本地 127.0.0.1:8888 访问 Project demo 下 Notebook ml-labs 的 SSH 端口。

t9k-pf nb <tensorstack-host>/t9k/build-console/projects/demo/notebooks/ml-labs/lab 8888

通过本地 0.0.0.0:8888 访问 Project demo 下 Notebook ml-labs 的 SSH 端口。

t9k-pf nb <tensorstack-host>/t9k/build-console/projects/demo/notebooks/ml-labs/lab 8888 --address 0.0.0.0

pod

访问指定 Pod 的指定端口。

使用

t9k-pf pod <name> [<localPort>:]<targetPort>

其中 <localPort> 代表本地监听的端口(小于 1024 的本地端口需要管理员权限才可以绑定),<targetPort> 代表目标 Pod 的端口。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-h, --help              查看当前指令的帮助信息和示例。
-n, --namespace         字符串,指定使用的项目(命名空间)名称。
-k, --apikey            开启交互式输入 API Key。
--address               本地监听地址。默认为 `localhost`。
--retryMaxTimes         整数,最大重试次数。默认为 `10`。
--retryPeriod           整数,重试间隔时间(单位:秒)。默认为 `10`。

示例

通过本地 127.0.0.1:3333 访问命名空间 dev 下的 Pod example 的 2222 端口。

t9k-pf pod example 3333:2222 -n dev

通过本地 0.0.0.0:3333 访问命名空间 dev 下的 Pod example 的 2222 端口。

t9k-pf pod example 3333:2222 -n dev --address 0.0.0.0

通过本地 127.0.0.1 的随机端口访问命名空间 dev 下的 Pod example 的 2222 端口。

t9k-pf pod example 2222 -n dev

service

访问指定 Service 的指定端口。

使用

t9k-pf service <name> [<localPort>:]<targetPort>

其中 <localPort> 代表本地监听的端口(小于 1024 的本地端口需要管理员权限才可以绑定),<targetPort> 代表目标 Service 的端口。

t9k-pf service 也可以用 t9k-pf svc 代替。

全局选项

-c, --config            字符串,指定使用的 T9k Config 文件的路径。默认路径是 `$HOME/.t9k/t9k-config.yaml`。
-h, --help              查看当前指令的帮助信息和示例。
-n, --namespace         字符串,指定使用的项目(命名空间)名称。默认是 `default`。
-k, --apikey            开启交互式输入 API Key。
--address               本地监听地址。默认为 `localhost`。
--retryMaxTimes         整数,最大重试次数。默认为 `10`。
--retryPeriod           整数,重试间隔时间(单位:秒)。默认为 `10`。

示例

通过本地 127.0.0.1:8888 访问默认命名空间 default 下的 Service myservice 的 80 端口。

t9k-pf service myservice 8888:80

通过本地 0.0.0.0:8888 访问默认命名空间 default 下的 Service myservice 的 80 端口。

t9k-pf service myservice 8888:80 --address 0.0.0.0

通过本地 127.0.0.1 的随机端口访问命名空间 dev 下的 Service myservice 的 80 端口。

t9k-pf service myservice 80 -n dev

Python SDK:t9k

TensorStack AI 平台提供了 Python SDK t9k,其为平台中的多种功能提供支持。

用户指南

安装

目前 TensorStack SDK 仅提供用于本地安装的 Python 包,你可以从平台首页下载。

然后使用以下命令进行安装:

pip install t9k-sdk-<version>.tar.gz [-i <pypi-mirror-url>]

配置

配置文件

TensorStack SDK 没有单独的配置文件,而是使用 TensorStack CLI 的配置文件。在导入 t9k 模块时,会自动读取位于路径 ~/.t9k/t9k-config.yaml 的配置文件(如果设置了环境变量 T9K_CONFIG,则读取其值给出的路径)。如果配置文件不存在或缺少部分配置项,则缺少的这些配置项会被设置为 None,这可能导致 TensorStack SDK 的部分功能不能正常工作。

使用和修改配置

在 Python 脚本中导入 t9k 模块之后,t9k.CONFIG 对象就代表了 TensorStack SDK 的配置,你可以像操作 Python 字典一样操作它,例如获取、设置、更新值。

import t9k

print(t9k.CONFIG['api_key'])
t9k.CONFIG['api_key'] = 'e4ccd2a3-3425-44b0-8b44-148bd303a0f9'
t9k.CONFIG.update({'api_key': 'e4ccd2a3-3425-44b0-8b44-148bd303a0f9'})

命令行工具

TensorStack SDK 提供了两个命令行工具:

  • em:对应于 t9k.em 模块,用于用户登录和登出 AIStore 服务器(会修改配置文件),查看和上传本地保存的 Run 和 Artifact 数据。执行 em --helpem COMMAND --help 以查看相应命令的详细使用方法。
  • ah:对应于 t9k.ah 模块,用于用户登录和登出 Asset Hub 服务器(会修改配置文件),查看、创建、修改和删除资产和资产目录,以及上传、修改和下载资产文件。执行 ah --helpah COMMAND --help 命令以查看相应命令的详细使用方法。

各主题教程

API

t9k.ah

t9k.ah.commit

commit(path: str, msg: str, delete: Optional[Sequence[str]] = None, add: Union[Sequence[str], Mapping[str, str], None] = None, force: bool = False) ‑> Optional[t9k.ah.core.Commit]

Commits changes to a branch of an Asset.

First delete, then add.

If no branch is provided, :main will be used.

For Windows platform, if you provide absolute paths for parameter add, change its format from ‘C:\local\path’ to ‘\C\local\path’.

Examples

Add a file as object to specified branch of Model:

ah.commit('model/llm/gpt2:v1', msg='add ...', add=['model.pt'])

Specify a path in Asset for a file to add:

ah.commit('model/llm/gpt2:v1', msg='add ...', add={'model.pt': 'saved_model/'})

Add all files under a directory as objects (with the directory):

ah.commit('model/llm/gpt2:v1', msg='add ...', add=['./saved_model'])

Add all files under a directory as objects (without the directory):

ah.commit('model/llm/gpt2:v1', msg='add ...', add=['./saved_model/*'])

Specify a path in Asset for a directory to add:

ah.commit('model/llm/gpt2:v1', msg='add ...', add={'./saved_model': 'path/to/[saved_model]'})
## or
ah.commit('model/llm/gpt2:v1', msg='add ...', add={'./saved_model': 'path/to/renamed_dir'})

Delete an object from a Dataset:

ah.commit('dataset/images/cifar10', msg='delete ...', delete=['0.png'])

Delete all objects under the specified path:

ah.commit('dataset/images/cifar10', msg='delete ...', delete=['data/'])

Args

  • path (str)

    Path of the branch.

  • msg (str)

    Commit message.

  • delete (Optional[Sequence[str]])

    Files or directories to delete from the branch, can be a sequence of paths in branch or None. If empty sequence or None, delete nothing. If the files or directories to delete do not exist, do nothing (rather than raise an error). Here format a/.../b signifies a file, while a/.../b/ signifies a directory.

  • add (Union[Sequence[str], Mapping[str, str], None])

    Files or directories to add to the branch, can be a sequence of local paths, a mapping from local paths to their paths in Asset, or None. If empty sequence, empty mapping or None, add nothing.

  • force (bool)

    Whether to create a new commit if unknown changes or unimplemented changes are found.

Returns

A Commit instance representing created commit if changes are commited, None if not.

t9k.ah.create

create(path: str, labels: Optional[Sequence[str]] = None, description: str = '', exist_ok: bool = False, create_tag: bool = False, source: str = 'main') ‑> Union[t9k.ah.core.Folder, t9k.ah.core.Model, t9k.ah.core.Dataset, t9k.ah.core.Branch, t9k.ah.core.Tag]

Creates a resource.

Note that you cannot create a Folder for another user.

Examples

Create a Folder:

folder = ah.create('model/llm')

Create a Model with labels:

model = ah.create('model/llm/gpt2', labels=['PyTorch'])

Create a Dataset with a description:

description = 'CIFAR-10 is a widely used benchmark dataset ...'
dataset = ah.create('dataset/images/cifar10', description=description)

Create a non-main branch of specified Model:

branch = ah.create('model/llm/gpt2:v1')

Create a tag:

tag = ah.create('model/llm/gpt2:20220101', create_tag=True, source='v1')
## or
tag = ah.create('model/llm/gpt2:20220101', create_tag=True, source='model/llm/gpt2:v1')

Create a Model for another user:

model = ah.create('/user/t9k-assethub/model/llm/gpt2')

Args

  • path (str)

    Path of the resource.

  • labels (Optional[Sequence[str]])

    Labels of the resource. Only applicable for creating a Folder, Model or Dataset.

  • description (str)

    Description of the resource. Only applicable for creating a Folder, Model or Dataset.

  • exist_ok (bool)

    If True and the resource already exists, return a corresponding instance representing the resource; if False and resource exists, raise a RuntimeError. Only applicable for creating a Folder, Model or Dataset.

  • create_tag (bool)

    Whether to create a tag instead of a branch. Only applicable for creating a branch or tag.

  • source (str)

    Name/ID or path of the source reference (branch, tag or commit) from which a tag is created. Only applicable for creating a tag.

Returns

A corresponding instance representing retrieved resource.

t9k.ah.delete

delete(path: str, force: bool = False) ‑> None

Deletes a resource.

Examples

Delete a Folder:

ah.delete('model/llm')

Delete a Model:

ah.delete('model/llm/gpt2')

Delete a Dataset:

ah.delete('dataset/images/cifar10')

Delete a non-main branch of specified Model:

ah.delete('model/llm/gpt2:v1')

Delete a tag:

ah.delete('model/llm/gpt2:20220101')

Delete another user’s Folder:

ah.delete('/user/t9k-assethub/model/llm')

If the Folder does not exist, do nothing:

ah.delete('model/llm', force=True)

Args

  • path (str)

    Path of the resource.

  • force (bool)

    If True, ignore non-existent resources.

t9k.ah.download

download(path: str, objects: Optional[Sequence[str]] = None, save_dir: str = '.')

Download objects of a reference of an Asset.

If no reference is provided, :main will be used.

Examples

Download all objects of specified branch of Model to current working directory:

ah.download('model/llm/gpt2:v1')

Download an object to specified directory:

ah.download('model/llm/gpt2:v1', objects=['model.pt'], save_dir='./saved_model')

Download all objects under the same path:

ah.download('model/llm/gpt2:v1', objects=['saved_model/'])

Specify the reference by tag:

ah.download('dataset/images/cifar10:20220101')

Specify the reference by commit:

ah.download('dataset/images/cifar10:a41ac4ec')

Args

  • path (str)

    Path of the reference from which objects are downloaded.

  • objects (Optional[Sequence[str]])

    Objects to download.

  • save_dir (str)

    Local directory which objects are downloaded to.

t9k.ah.get

get(path: str) ‑> Union[t9k.ah.core.Folder, t9k.ah.core.Model, t9k.ah.core.Dataset, t9k.ah.core.Branch, t9k.ah.core.Tag, t9k.ah.core.Commit]

Gets a resource.

To get a commit, please provide a commit ID with a length of at least 4 to avoid potential conflicts with branches or tags.

Examples

Get a Folder:

folder = ah.get('model/llm')

Get a Model:

model = ah.get('model/llm/gpt2')

Get a Dataset:

dataset = ah.get('dataset/images/cifar10')

Get a non-main branch of specified Model:

branch = ah.get('model/llm/gpt2:v1')

Get a tag:

tag = ah.get('model/llm/gpt2:20220101')

Get another user’s Folder:

folder = ah.get('/user/t9k-assethub/model/llm')

Args

  • path (str)

    Path of the resource.

Returns

A instance representing retrieved resource.

t9k.ah.list

list(path: str, resource: str = 'default') ‑> List[Dict[str, Any]]

Lists resources.

Based on the provided path, list Folders with the specified Asset kind, Assets within the specified Folder, or all objects of the specified reference (branch, tag or commit) of Asset.

To list Folders that are shared with you, set path='shared/model' (or path='shared/dataset'); to list Folders that are public, set path='/public/t9k-assethub/model' (or path='/public/t9k-assethub/dataset').

To list branches, provide a path that points to an Asset and set resource='branch'; to list tags, provide a path that points to an Asset and set resource='tag'; to list commits, provide a path that points to a branch of an Asset and set resource='commit'.

If a reference is expected but omitted, :main will be used.

Examples

List Model Folders that you own:

folders = ah.list('model')

List Model Folders that are shared with you:

folders = ah.list('shared/model')

List Model Folders that are public:

folders = ah.list('/public/t9k-assethub/model')

List Models in your own Folder:

models = ah.list('model/llm')

List Models in another user’s Folder:

models = ah.list('/user1/t9k-assethub/model/llm')

List objects of specified branch of Model:

objects = ah.list('model/llm/gpt2:v1')

List objects of specified tag of Dataset:

objects = ah.list('dataset/images/cifar10:20220101')

List branches of specified Model:

branches = ah.list('model/llm/gpt2', resource='branch')

List tags of specified Model:

tags = ah.list('model/llm/gpt2', resource='tag')

List commits of specified branch of Model:

commits = ah.list('model/llm/gpt2:v1', resource='commit')

List commits of specified Dataset:

commits = ah.list('dataset/images/cifar10', resource='commit')

Args

  • path (str)

    Path to be listed.

  • resource (str)

    Kind of the resources, must be 'default', 'branch', ‘tag’ or 'commit'. This parameter is used to list branches, tags or commits: to list branches, provide a path that points to an Asset and set resource='branch'; to list tags, provide a path that points to an Asset and set resource='tag'; to list commits, provide a path that points to a branch of an Asset and set resource='commit'.

Returns

A list of resources.

t9k.ah.login

login(ah_host: Optional[str] = None, ais_host: Optional[str] = None, api_key: Optional[str] = None, timeout: Optional[int] = None) ‑> None

Logs in to AIStore server and Asset Hub server.

Sets up the client that corresponds with AIStore server and Asset Hub server.

Args

  • ah_host (Optional[str])

    URL of Asset Hub server. Defaults to t9k.CONFIG['asset_hub_host'].

  • ais_host (Optional[str])

    URL of AIStore server. Defaults to t9k.CONFIG['aistore_host'].

  • api_key (Optional[str])

    API Key for requesting server. Defaults to t9k.CONFIG['api_key'].

  • timeout (Optional[int])

    How many seconds to wait for server to send data before giving up.

Raises

  • requests.HTTPError

    Unable to connect to the server.

t9k.ah.logout

logout() ‑> None

Logs out from the current AIStore server and Asset Hub server.

The client is unset, it can no longer correspond with AIStore server and Asset Hub server until it is set up again.

t9k.ah.merge

merge(path: str) ‑> None

Merges a branch of a Model to the main branch.

Here, the specific operation of “merge” involves deleting all objects from the main branch and then copying all objects from the specified branch to the main branch.

Note that the specified branch itself cannot be the main branch.

Examples

ah.merge('model/llm/gpt2:v1')

Args

  • path (str)

    Path of the branch.

t9k.ah.reset

reset(path: str) ‑> None

Resets a branch to clear all uncommitted changes.

Examples

ah.reset('model/llm/gpt2:main')

Args

  • path (str)

    Path of the branch.

t9k.ah.update

update(path: str, name: Optional[str] = None, labels: Optional[Sequence[str]] = None, description: Optional[str] = None) ‑> None

Updates a resource.

Only Folders and Assets can be updated.

If none of the args is provided, do nothing.

Examples

Rename a Folder:

ah.update('model/llm', name='generative-language-model')

Relabel a Model:

ah.update('model/llm/gpt2', labels=['JAX'])

Args

  • name (Optional[str])

    New name of the resource.

  • labels (Optional[Sequence[str]])

    New labels of the resource.

  • description (Optional[str])

    New description of the resource.

t9k.ah.core

t9k.ah.core.Branch

Branch(asset: Union[t9k.ah.core.Model, t9k.ah.core.Dataset], name: str, commit_id: str)

Represents a branch of Asset.

Attributes

  • path (str)

    Path of the branch.

  • asset (Union[t9k.ah.core.Model, t9k.ah.core.Dataset])

    A Model or Dataset instance corresponding to the Asset that the branch belongs to.

  • kind (str)

    A string 'branch'.

  • name (str)

    Name of the branch.

  • commit_id (str)

    ID of the commit that the branch points to.

  • alive (bool)

    Whether the branch is alive.

Ancestors

  • t9k.ah.core._Ref

Methods

create_commit

create_commit(self, msg: str, delete: Optional[Sequence[str]] = None, add: Union[Sequence[str], Mapping[str, str], None] = None, force: bool = False) ‑> Optional[t9k.ah.core.Commit]

Commits changes to this branch.

First delete, then add.

Examples

Add a file as object to this branch:

branch.create_commit(msg='add ...', add=['model.pt'])

Specify a path in Asset for a file to add:

branch.create_commit(msg='add ...', add={'model.pt': 'saved_model/'})

Add all files under a directory as objects (with the directory):

branch.create_commit(msg='add ...', add=['./saved_model'])

Add all files under a directory as objects (without the directory):

branch.create_commit(msg='add ...', add=['./saved_model/*'])

Specify a path in Asset for a directory to add:

branch.create_commit(msg='add ...', add={'./saved_model': 'path/to/[saved_model]'})
## or
branch.create_commit(msg='add ...', add={'./saved_model': 'path/to/renamed_dir'})

Delete an object from this branch:

branch.create_commit(msg='delete ...', delete=['model.pt'])

Delete all objects under the specified path:

branch.create_commit(msg='delete ...', delete=['saved_model/'])
Args
  • msg (str)

    Commit message.

  • delete (Optional[Sequence[str]])

    Files or directories to delete from the branch, can be a sequence of paths in branch or None. If empty sequence or None, delete nothing. If the files or directories to delete do not exist, do nothing (rather than raise an error). Here format a/.../b signifies a file, while a/.../b/ signifies a directory.

  • add (Union[Sequence[str], Mapping[str, str], None])

    Files or directories to add to the branch, can be a sequence of local paths, a mapping from local paths to their paths in Asset, or None. If empty sequence, empty mapping or None, add nothing.

  • force (bool)

    Whether to create a new commit if unknown changes or unimplemented changes are found.

Returns

A Commit instance representing created commit if changes are commited, None if not.

create_tag

create_tag(self, name: str) ‑> t9k.ah.core.Tag

Creates a tag that points to this branch.

Args
  • name (str)

    Name of the tag.

Returns

A Tag instance representing created tag.

delete

delete(self) ‑> None

Deletes this branch.

download

download(self, paths: Optional[Sequence[str]] = None, save_dir: str = '.') ‑> None

Downloads objects of this branch.

Args
  • paths (Optional[Sequence[str]])

    Files or directories to download from this branch, is a sequence of paths in branch. Here format a/.../b signifies a file while a/.../b/ signifies a directory. Defaults to all objects.

  • save_dir (str)

    Local directory which objects are downloaded to. If the directory does not exist, create it. Defaults to current working directory.

get_commit

get_commit(self, index: Optional[int] = None, id: Optional[str] = None) ‑> t9k.ah.core.Commit

Gets a commit of this branch.

If neither index or id is provided, return the last commit. If both index and id are provided, id will not be used.

Args
  • index (Optional[int])

    Index of the commit in this branch, 0 for the last commit, -1 for the first commit.

  • id (Optional[str])

    A prefix of ID of the commit.

Returns

A Commit instance representing retrieved commit.

list_commit

list_commit(self) ‑> List[Dict[str, Any]]

Lists commits of this branch.

list_object

list_object(self) ‑> List[Dict[str, Any]]

Lists objects of this branch.

merge

merge(self) ‑> None

Merges this branch to the main branch.

Here, the specific operation of “merge” involves deleting all objects from the main branch and then copying all objects from this branch to the main branch.

Note that this branch itself cannot be the main branch.

reset

reset(self) ‑> None

Resets this branch to clear all uncommitted changes.

t9k.ah.core.Commit

Commit(asset: Union[t9k.ah.core.Model, t9k.ah.core.Dataset], id_: str)

Represents a commit of Asset.

Attributes

  • path (str)

    Path of the commit.

  • asset (Union[t9k.ah.core.Model, t9k.ah.core.Dataset])

    A Model or Dataset instance corresponding to the Asset that the commit belongs to.

  • kind (str)

    A string 'commit'.

  • name (str)

    First 8 characters of ID of the commit.

  • id (str)

    ID of the commit.

  • alive (bool)

    Whether the commit is alive.

Ancestors

  • t9k.ah.core._Ref

Methods

create_tag

create_tag(self, name: str) ‑> t9k.ah.core.Tag

Creates a tag that points to this commit.

Args
  • name (str)

    Name of the tag.

Returns

A Tag instance representing created tag.

download

download(self, paths: Optional[Sequence[str]] = None, save_dir: str = '.') ‑> None

Downloads objects of this commit.

Args
  • paths (Optional[Sequence[str]])

    Files or directories to download from this commit, is a sequence of paths in commit. Here format a/.../b signifies a file while a/.../b/ signifies a directory. Defaults to all objects.

  • save_dir (str)

    Local directory which objects are downloaded to. If the directory does not exist, create it. Defaults to current working directory.

list_commit

list_commit(self) ‑> List[Dict[str, Any]]

Lists commits of this commit.

list_object

list_object(self) ‑> List[Dict[str, Any]]

Lists objects of this commit.

t9k.ah.core.Dataset

Dataset(id_: str, folder: t9k.ah.core.Folder, name: str, labels: List[str], description: str, extra: str)

Represents a Dataset in server.

Attributes

  • path (str)

    Path of the Dataset in server.

  • id (str)

    ID of the Dataset in server.

  • folder (t9k.ah.core.Folder)

    A Folder instance corresponding to the Folder that the Dataset belongs to.

  • kind (str)

    A string 'Dataset'.

  • name (str)

    Name of the Dataset.

  • labels (List[str])

    Labels of the Dataset.

  • description (str)

    Description of the Dataset.

  • commit_id (str)

    ID of the commit that the main branch points to.

  • extra (str)

    Extra information about the Dataset.

  • alive (bool)

    Whether the Dataset is alive.

Ancestors

  • t9k.ah.core._Dataset

Methods

create_commit

create_commit(self, msg: str, delete: Optional[Sequence[str]] = None, add: Union[Sequence[str], Mapping[str, str], None] = None) ‑> Optional[t9k.ah.core.Commit]

Commits changes to this Dataset.

First delete, then add.

Examples

Add a file as object to this Dataset:

dataset.create_commit(msg='add ...', add=['0.png'])

Specify a path in Dataset for an object to add:

dataset.create_commit(msg='add ...', add={'0.png': 'data/'})

Add all files under a directory as objects:

dataset.create_commit(msg='add ...', add=['./data'])

Delete an object from this Dataset:

dataset.create_commit(msg='delete ...', delete=['0.png'])

Delete all objects under the specified path:

dataset.create_commit(msg='delete ...', delete=['data/'])
Args
  • msg (str)

    Commit message.

  • delete (Optional[Sequence[str]])

    Files or directories to delete from the Dataset, can be a sequence of paths in Dataset or None. If empty sequence or None, delete nothing. If the files or directories to delete do not exist, do nothing (rather than raise an error). Here format a/.../b signifies a file, while a/.../b/ signifies a directory.

  • add (Union[Sequence[str], Mapping[str, str], None])

    Files or directories to add to the Dataset, can be a sequence of local paths, a mapping from local paths to their paths in Dataset, or None. If empty sequence, empty mapping or None, add nothing.

Returns

A Commit instance representing created commit if changes are commited, None if not.

delete

delete(self) ‑> None

Deletes this Dataset.

download

download(self, paths: Optional[Sequence[str]] = None, save_dir: str = '.') ‑> None

Downloads objects of this Dataset.

Args
  • paths (Optional[Sequence[str]])

    Files or directories to download from this Dataset, is a sequence of paths in Dataset. Here format a/.../b signifies a file while a/.../b/ signifies a directory. Defaults to all objects.

  • save_dir (str)

    Local directory which objects are downloaded to. If the directory does not exist, create it. Defaults to current working directory.

get_commit

get_commit(self, index: Optional[int] = None, id: Optional[str] = None) ‑> t9k.ah.core.Commit

Gets a commit of this Dataset.

If neither index or id is provided, return the last commit. If both index and id are provided, id will not be used.

Args
  • index (Optional[int])

    Index of the commit in this branch, 0 for the last commit, -1 for the first commit.

  • id (Optional[str])

    A prefix of ID of the commit.

Returns

A Commit instance representing retrieved commit.

get_tag

get_tag(self, name: str, verbose: bool = True) ‑> t9k.ah.core.Tag

Gets a tag of this Dataset.

Args
  • name (str)

    Name of the tag.

  • verbose (bool)

    Whether to log error.

Returns

A Tag instance representing retrieved tag.

list_branch

list_branch(self) ‑> List[Dict[str, Any]]

Lists branches in this Dataset.

list_commit

list_commit(self) ‑> List[Dict[str, Any]]

Lists commits of this Dataset.

list_object

list_object(self) ‑> List[Dict[str, Any]]

Lists objects of this Dataset.

list_tag

list_tag(self) ‑> List[Dict[str, Any]]

Lists tags of this Dataset.

update

update(self, name: Optional[str] = None, labels: Optional[Sequence[str]] = None, description: Optional[str] = None) ‑> None

Updates the metadata of this Dataset.

If none of the args is provided, do nothing.

Args
  • name (Optional[str])

    New name of this Dataset.

  • labels (Optional[Sequence[str]])

    New labels of this Dataset.

  • description (Optional[str])

    New description of this Dataset.

t9k.ah.core.Folder

Folder(path: str, id_: str, owner: str, asset_kind: str, name: str, labels: List[str], description: str, extra: str)

Represents a Asset Hub Folder in server.

Attributes

  • path (str)

    Path of the Folder.

  • id (str)

    ID of the Folder in server.

  • owner (str)

    Owner of the Folder.

  • kind (str)

    Kind of the Folder, is a string 'Model' or 'Dataset'.

  • name (str)

    Name of the Folder.

  • labels (List[str])

    Labels of the Folder.

  • description (str)

    Description of the Folder.

  • extra (str)

    Extra information about the Folder.

  • alive (bool)

    Whether the Folder is alive.

Methods

create_asset

create_asset(self, name: str, labels: Optional[Sequence[str]] = None, description: str = '', exist_ok: bool = False) ‑> Union[t9k.ah.core.Model, t9k.ah.core.Dataset]

Creates an Asset in this Folder.

Args
  • name (str)

    Name of the Asset.

  • labels (Optional[Sequence[str]])

    Labels of the Asset.

  • description (str)

    Description of the Asset.

  • exist_ok (bool)

    If True and Asset with name already exists, return a Model or Dataset instance representing this Asset; if False and Asset exists, raise a RuntimeError.

Returns

A Model or Dataset instance representing created Model or Dataset, depending on Asset kind of this Folder.

delete

delete(self) ‑> None

Deletes this Folder.

get_asset

get_asset(self, name: str) ‑> Union[t9k.ah.core.Model, t9k.ah.core.Dataset]

Gets an Asset in this Folder.

If you want to get Asset directly by its path, use ah.get_asset().

Args
  • name (str)

    Name of the Asset.

Returns

A Model or Dataset instance representing retrieved Model or Dataset, depending on Asset kind of this Folder.

list_asset

list_asset(self) ‑> List[Dict[str, Any]]

Lists Assets in this Folder.

update

update(self, name: Optional[str] = None, labels: Optional[Sequence[str]] = None, description: Optional[str] = None) ‑> None

Updates the metadata of this Folder.

If none of the args is provided, do nothing.

Args
  • name (Optional[str])

    New name of this Folder.

  • labels (Optional[Sequence[str]])

    New labels of this Folder.

  • description (Optional[str])

    New description of this Folder.

t9k.ah.core.Model

Model(id_: str, folder: t9k.ah.core.Folder, name: str, labels: List[str], description: str, extra: str)

Represents a Model in server.

Attributes

  • path (str)

    Path of the Model in server.

  • id (str)

    ID of the Model in server.

  • folder (t9k.ah.core.Folder)

    A Folder instance corresponding to the Folder that the Model belongs to.

  • kind (str)

    A string 'Model'.

  • name (str)

    Name of the Model.

  • labels (List[str])

    Labels of the Model.

  • description (str)

    Description of the Model.

  • extra (str)

    Extra information about the Model.

  • alive (bool)

    Whether the Model is alive.

Ancestors

  • t9k.ah.core._Model

Methods

create_branch

create_branch(self, name: str) ‑> t9k.ah.core.Branch

Creates an empty branch of this Model.

Args
  • name (str)

    Name of the branch.

Returns

A Branch instance representing created branch.

delete

delete(self) ‑> None

Deletes this Model.

download

download(self, paths: Optional[Sequence[str]] = None, save_dir: str = '.') ‑> None

Downloads objects of this Model.

Args
  • paths (Optional[Sequence[str]])

    Files or directories to download from this Dataset, is a sequence of paths in Dataset. Here format a/.../b signifies a file while a/.../b/ signifies a directory. Defaults to all objects.

  • save_dir (str)

    Local directory which objects are downloaded to. If the directory does not exist, create it. Defaults to current working directory.

get_branch

get_branch(self, name: str, verbose: bool = True) ‑> t9k.ah.core.Branch

Gets a branch of this Model.

Args
  • name (str)

    Name of the branch.

  • verbose (bool)

    Whether to log error.

Returns

A Branch instance representing retrieved branch.

get_commit

get_commit(self, id: str) ‑> t9k.ah.core.Commit

Gets a commit of this Model.

If no commit matches id, or two or more commits matche id, raise a RuntimeError.

Args
  • id (str)

    A prefix of ID of the commit.

Returns

A Commit instance representing retrieved commit.

get_tag

get_tag(self, name: str, verbose: bool = True) ‑> t9k.ah.core.Tag

Gets a tag of this Model.

Args
  • name (str)

    Name of the tag.

  • verbose (bool)

    Whether to log error.

Returns

A Tag instance representing retrieved tag.

list_branch

list_branch(self) ‑> List[Dict[str, Any]]

Lists branches in this Model.

list_object

list_object(self) ‑> List[Dict[str, Any]]

Lists objects of this Model.

list_tag

list_tag(self) ‑> List[Dict[str, Any]]

Lists tags of this Model.

update

update(self, name: Optional[str] = None, labels: Optional[Sequence[str]] = None, description: Optional[str] = None) ‑> None

Updates the metadata of this Model.

If none of the args is provided, do nothing.

Args
  • name (Optional[str])

    New name of this Model.

  • labels (Optional[Sequence[str]])

    New labels of this Model.

  • description (Optional[str])

    New description of this Model.

t9k.ah.core.Tag

Tag(asset: Union[t9k.ah.core.Model, t9k.ah.core.Dataset], name: str, commit_id: str)

Represents a tag of Asset.

Attributes

  • path (str)

    Path of the tag.

  • asset (Union[t9k.ah.core.Model, t9k.ah.core.Dataset])

    A Model or Dataset instance corresponding to the Asset that the tag belongs to.

  • kind (str)

    A string 'tag'.

  • name (str)

    Name of the tag.

  • commit_id (str)

    ID of the commit that the tag points to.

  • alive (bool)

    Whether the tag is alive.

Ancestors

  • t9k.ah.core._Ref

Methods

create_tag

create_tag(self, name: str) ‑> t9k.ah.core.Tag

Creates another tag that points to this tag.

Args
  • name (str)

    Name of the tag.

Returns

A Tag instance representing created tag.

delete

delete(self) ‑> None

Deletes this tag.

download

download(self, paths: Optional[Sequence[str]] = None, save_dir: str = '.') ‑> None

Downloads objects of this tag.

Args
  • paths (Optional[Sequence[str]])

    Files or directories to download from this tag, is a sequence of paths in tag. Here format a/.../b signifies a file while a/.../b/ signifies a directory. Defaults to all objects.

  • save_dir (str)

    Local directory which objects are downloaded to. If the directory does not exist, create it. Defaults to current working directory.

list_commit

list_commit(self) ‑> List[Dict[str, Any]]

Lists commits of this tag.

list_object

list_object(self) ‑> List[Dict[str, Any]]

Lists objects of this tag.

t9k.config

t9k.config.Config

Config()

SDK config.

Methods

get

get(self, key: str, default: Any = None) ‑> Any

items

items(self) ‑> ItemsView[str, Any]

to_dict

to_dict(self) ‑> Dict[str, Any]

update

update(self, new_config: Dict[str, Any]) ‑> None

t9k.config.ConfigItem

ConfigItem(name: str, value: Optional[Any] = None, processor: Union[Callable, Sequence[Callable], None] = None, validator: Union[Callable, Sequence[Callable], None] = None, hook: Union[Callable, Sequence[Callable], None] = None)

SDK config item.

Attributes

  • name (str)

    Name of config item.

  • value (Any)

    Value of config item.

t9k.em

t9k.em.artifact.Artifact

Artifact(metadata: Dict[str, Any], objects: Optional[Dict[str, Dict[str, Any]]] = None)

Implementation of Artifact, a set of files that a Run inputs or outputs.

Args

  • metadata (Dict[str, Any])

    Metadata to initialize a new Artifact.

  • objects (Optional[Dict[str, Dict[str, Any]]])

    Data of objects of the Artifact.

Attributes

  • name (str)

    Name of the Artifact.

  • labels (List[str])

    Labels of the Artifact.

  • description (str)

    Description of the Artifact.

  • created_timestamp (str)

    Created timestamp of the Artifact.

  • alternative_name (str)

    Alternative name of the Artifact.

  • objects (List[Dict[str, str]])

    Data of objects of the Artifact.

  • remote (List[Dict[str, str]])

    Upload and download history of the Artifact.

  • local (str)

    Local directory of the Artifact.

Methods

add_dir

add_dir(self, dir_path: str, obj_path: Optional[str] = None) ‑> None

Adds all files under a local directory as objects of the Artifact.

The directory will be copied to local directory of the Artifact, the specific subpath depends on its obj_path, for example:

# dir copied to `<local-dir>/a`
artifact.add_dir(dir_path='a/')
# or
artifact.add_dir(dir_path='a')
# or
artifact.add_dir(dir_path='a/', obj_path='a')

# dir copied to `<local-dir>/b/a`
artifact.add_dir(dir_path='a/', obj_path='b/')
# or
artifact.add_dir(dir_path='a/', obj_path='b/a')

add_file

add_file(self, file_path: str, obj_path: Optional[str] = None) ‑> None

Adds a local file as an object of the Artifact.

The file will be copied to local directory of the Artifact, the specific subpath depends on its object path, for example:

# file copied to `<local-dir>/1.png`
artifact.add_file(file_path='1.png')
# or
artifact.add_file(file_path='1.png', obj_path='1.png')

# file copied to `<local-dir>/a/1.png`
artifact.add_file(file_path='1.png', obj_path='a/')
# or
artifact.add_file(file_path='1.png', obj_path='a/1.png')

add_reference

add_reference(self, uri: str, obj_path: Optional[str] = None) ‑> None

Adds a URI as an object reference to the Artifact.

parse_from_dict

parse_from_dict(self, data: Dict[str, Any]) ‑> None

Parses an Artifact instance from a dict.

to_dict

to_dict(self) ‑> Dict[str, Any]

Converts Artifact instance to a dict and returns it.

upload

upload(self, folder: str = 'default', make_folder: bool = False, conflict_strategy: str = 'new') ‑> None

Uploads this Artifact to server.

Args
  • folder (str)

    Path of the Folder to which the Artifact is uploaded. If the provided path does not start with ‘/’, /<current-user>/ is prepended to it.

  • make_folder (bool)

    If True and Folder with path folder does not exist, make the Folder and parent Folders as needed.

  • conflict_strategy (str)

    Strategy adopted when an Artifact with the same name as the Artifact to be uploaded already exists in the Folder, must be ‘skip’, ‘error’, ‘new’ or ‘replace’. If ‘skip’, skip the upload; if ‘error’, error out; if ‘new’, upload with the alternative name of Artifact; if ‘replace’, delete the existing Artifact and upload.

t9k.em.containers.Params

Params(upload: Callable, init_hparams: Dict[str, Union[str, int, float, bool, None, List[~T], Tuple[], Dict[~KT, ~VT]]] = None)

Container class to hold hyperparameters of Run.

It is recommended to set all hyperparameters by calling update method once before building the model. Nevertheless, you are free to operate hyperparameters like items of a dict or attributes of an object.

Examples

Recommended method of setting hyperparameters:

run.update({
    'batch_size': 32,
    'epochs': 10,
})

Assign parameter like an item of dict or attribute of object:

run.params['batch_size'] = 32
run.params.epochs = 10

Args

  • upload (Callable)

    Function that is called to upload hyperparameters every time hyperparameters are updated.

  • init_hparams (Dict[str, Union[str, int, float, bool, None, List[~T], Tuple[], Dict[~KT, ~VT]]])

    Initial hyperparameters.

Ancestors

  • collections.abc.MutableMapping

Methods

as_dict

as_dict(self)

items

items(self)

D.items() -> a set-like object providing a view on D’s items

keys

keys(self)

D.keys() -> a set-like object providing a view on D’s keys

parse

parse(self, dist_tf_strategy=None, dist_torch_model=None, dist_hvd=None)

Parses hyperparameters from various objects of various frameworks.

Args
  • dist_tf_strategy

    TensorFlow distribution strategy instance if tf.distribute is used for distributed training.

  • dist_torch_model

    PyTorch model wrapped with DP or DDP if torch.distributed is used for distributed training.

  • dist_hvd

    Used module such as horovod.keras and horovod.torch if Horovod is used for distributed training.

update

update(self, new_params: Dict[str, Any], override: bool = True)

Updates with new params.

Args
  • new_params (Dict[str, Any])

    New params to be updated with.

  • override (bool)

    Whether to override current params.

values

values(self)

D.values() -> an object providing a view on D’s values

t9k.em.create_artifact

create_artifact(name: str, labels: Optional[Sequence[str]] = None, description: str = '') ‑> t9k.em.artifact.Artifact

Creates and initializes a new Artifact.

The local files of Artifact are placed under the parent directory specified by the environment variable EM_ARTIFACT_PARENT_DIR (default is relative path .em/artifacts).

Examples

tensorboard_artifact = em.create_artifact(name='tensorboard_logs')

Args

  • name (str)

    Name of the Artifact.

  • labels (Optional[Sequence[str]])

    Labels of the Artifact.

  • description (str)

    Description of the Artifact.

Returns

An Artifact instance created and initialized.

t9k.em.create_run

create_run(config_path: Optional[str] = None, name: str = 'default', hparams: Optional[Dict[str, Any]] = None, labels: Optional[Sequence[str]] = None, description: str = '', auto_upload: bool = False, folder: str = 'default', make_folder: bool = False, conflict_strategy: str = 'new') ‑> t9k.em.run.Run

Creates and initializes a new Run.

The local files of Run are placed under the parent directory specified by the environment variable EM_RUN_PARENT_DIR (default is relative path .em/runs).

Examples

Basic usage:

from t9k import em

run = em.create_run(name='cnn_keras',
                    folder='cv/image-classification/mnist')

Provide initial parameters of Run:

hparams = {
    'batch_size': 32,
    'epochs': 1,
    'learning_rate': 0.001,
    'conv_channels1': 32,
    'conv_channels2': 64,
    'conv_channels3': 64,
    'conv_kernel_size': 3,
    'maxpool_size': 2,
    'linear_features1': 64,
}

run = em.create_run(name='cnn_keras',
                    hparams=hparams,
                    folder_path='cv/image-classification/mnist')

Provide a Run config file:

run = em.create_run(config_path='./run_config.yaml')

where the config file run_config.yaml is like:

name: cnn_keras
hparams:
  batch_size: 32
  epochs: 1
  learning_rate: 0.001
  conv_channels1: 32
  conv_channels2: 64
  conv_channels3: 64
  conv_kernel_size: 3
  maxpool_size: 2
  linear_features1: 64
labels:
- Keras
description: Train a simple CNN model that classifies images of handwritten digits.

Args

  • config_path (Optional[str])

    Local path of the Run config file. For all of the following args, the values parsed from the config file take precedence over values passed in.

  • name (str)

    Name of the Run.

  • hparams (Optional[Dict[str, Any]])

    Initial hyperparameters of the Run.

  • labels (Optional[Sequence[str]])

    Labels of the Run.

  • description (str)

    Description of the Run.

  • auto_upload (bool)

    Whether to upload the Run and its data automatically and asynchronously. If False, all of the following args will not be used.

  • folder (str)

    Path of the Folder to which the Run is uploaded. If the provided path does not start with ‘/’, /<current-user>/ is prepended to it. If auto_upload is False, this arg will not be used.

  • make_folder (bool)

    If True and Folder with path folder does not exist, make the Folder and parent Folders as needed. If auto_upload is False, this arg will not be used.

  • conflict_strategy (str)

    Strategy adopted when a Run with the same name as the Run to be uploaded already exists in the Folder, must be ‘skip’, ‘error’, ‘new’ or ‘replace’. If ‘skip’, skip the upload; if ‘error’, error out; if ‘new’, upload with the alternative name of Run; if ‘replace’, delete the existing Run and upload. If auto_upload is False, this arg will not be used.

Returns

A Run instance created and initialized.

t9k.em.load_artifact

load_artifact(path: str) ‑> t9k.em.artifact.Artifact

Loads an Artifact from local or server.

This function will first search for the corresponding local directory, followed by remote path. If the path is not found in either location, raise a RuntimeError.

In the case of the remote path, if the provided path does not start with ‘/’, /<current-user>/ is prepended to it.

Examples

Load by local path:

em.load_artifact(path=
    '.em/artifacts/tensorboard_logs_220823_194728_4e48t2')

Load by remote path:

em.load_artifact(path='/user/path/to/tensorboard_logs')

Args

  • path (str)

    Local directory of the Artifact, or path of the Artifact in server.

Returns

An Artifact instance loaded.

t9k.em.load_run

load_run(path: str, auto_upload: bool = False, folder: str = 'default', make_folder: bool = False, conflict_strategy: str = 'new') ‑> t9k.em.run.Run

Loads a Run from local or server.

This function will first search for the corresponding local path, followed by remote path. If the path is not found in either location, raise a RuntimeError.

In the case of the remote path, if the provided path does not start with ‘/’, /<current-user>/ is prepended to it.

Examples

Load by local path:

em.load_run(path='.em/runs/cnn_keras_220823_194728_4e48t2')

Load by remote path:

em.load_run(path='/user/path/to/cnn_keras')

Args

  • path (str)

    Local directory of the Run, or path of the Run in server.

  • auto_upload (bool)

    Whether to upload the Run and its data automatically and asynchronously. If False, all of the following args will not be used.

  • folder (str)

    Path of the Folder to which the Run is uploaded. If the provided path does not start with ‘/’, /<current-user>/ is prepended to it. If auto_upload is False, this arg will not be used.

  • make_folder (bool)

    If True and Folder with path folder does not exist, make the Folder and parent Folders as needed. If auto_upload is False, this arg will not be used.

  • conflict_strategy (str)

    Strategy adopted when a Run with the same name as the Run to be uploaded already exists in the Folder, must be ‘skip’, ‘error’, ‘new’ or ‘replace’. If ‘skip’, skip the upload; if ‘error’, error out; if ‘new’, upload with the alternative name of Run; if ‘replace’, delete the existing Run and upload. If auto_upload is False, this arg will not be used.

Returns

A Run instance loaded.

t9k.em.login

login(ais_host: Optional[str] = None, api_key: Optional[str] = None, timeout: Optional[int] = None) ‑> None

Logs in to AIStore server.

Sets up the client that corresponds with AIStore server.

Args

  • ais_host (Optional[str])

    URL of AIStore server. Defaults to t9k.CONFIG['aistore_host'].

  • api_key (Optional[str])

    API Key for requesting server. Defaults to t9k.CONFIG['api_key'].

  • timeout (Optional[int])

    How many seconds to wait for server to send data before giving up.

Raises

  • requests.HTTPError

    Unable to connect to the server and unable_to_connect_ok is False.

t9k.em.logout

logout() ‑> None

Logs out from the current AIStore server.

The client is unset, it can no longer correspond with AIStore server until it is set up again.

t9k.em.run.Run

Run(metadata: Dict[str, Any], hparams: Optional[Dict[str, Any]] = None, metrics: Optional[Dict[str, List[Dict[str, Dict[str, Union[str, int, float]]]]]] = None, platform: Optional[Dict[str, Any]] = None, git: Optional[Dict[str, Any]] = None)

Implementation of Run, a run of a specific model for certain ML task.

Args

  • metadata (Dict[str, Any])

    Metadata to initialize a new Run.

  • hparams (Optional[Dict[str, Any]])

    Hyperparameters of the Run.

  • metrics (Optional[Dict[str, List[Dict[str, Dict[str, Union[str, int, float]]]]]])

    Metrics of the Run.

  • platform (Optional[Dict[str, Any]])

    Platform information of the Run.

  • git (Optional[Dict[str, Any]])

    Git information of the Run.

Attributes

  • name (str)

    Name of the Run.

  • labels (List[str])

    Labels of the Run.

  • description (str)

    Description of the Run.

  • start_timestamp (str)

    Start timestamp of the Run.

  • end_timestamp (str)

    End timestamp of the Run.

  • status (str)

    Status of the Run.

  • alternative_name (str)

    Alternative name of the Run.

  • associations (Dict[str, List[Dict[str, str]]])

    Input and output resources of the Run.

  • hparams (Any)

    Hyperparameters of the Run.

  • metrics (Dict[str, List[Dict[str, Dict[str, Union[str, int, float]]]]])

    Metrics produced in the Run.

  • platform (Dict[str, Any])

    Platform information of the Run.

  • git (Dict[str, Any])

    Git information of the Run.

  • remote (List[Dict[str, str]])

    Upload and download history of the Run.

  • local (str)

    Local directory of the Run.

Methods

finish

finish(*args, **kwargs)

log

log(self, type: str, metrics: Dict[str, float], step: int, epoch: Optional[int] = None) ‑> None

Logs a set of metrics of Run.

Args
  • type (str)

    Type of the metrics, ‘train’ (or ‘training’), ‘val’ (or ‘validate’, ‘validation’) and ‘test’ (or ‘testing’, ‘eval’, ‘evaluate’, ‘evaluation’) for training, validation and testing metrics respectively. Besides, you can also use other arbitrary string as custom type of the metrics.

  • metrics (Dict[str, float])

    Additional metrics to be logged.

  • step (int)

    Number of the step that the metrics belong to.

  • epoch (Optional[int])

    Number of the epoch that the metrics belong to.

mark_input

mark_input(self, resource: Union[t9k.em.artifact.Artifact, t9k.ah.core.Model, t9k.ah.core.Dataset, t9k.ah.core.Branch, t9k.ah.core.Tag, t9k.ah.core.Commit]) ‑> None

Marks an Artifact, Model or Dataset as an input of this Run.

mark_output

mark_output(self, resource: Union[t9k.em.artifact.Artifact, t9k.ah.core.Model, t9k.ah.core.Dataset, t9k.ah.core.Branch, t9k.ah.core.Tag, t9k.ah.core.Commit]) ‑> None

Marks an Artifact, Model or Dataset as an output of this Run.

parse_from_dict

parse_from_dict(self, data: Dict[str, Any]) ‑> None

Parses a Run instance from a dict.

to_dict

to_dict(self) ‑> Dict[str, Any]

Converts Run instance to a dict and returns it.

upload

upload(self, folder: str = 'default', make_folder: bool = False, conflict_strategy: str = 'new') ‑> None

Uploads this Run to server.

If this Run has input or output Artifacts, these Artifacts are uploaded as well if they have not been uploaded, and these associations are uploaded.

Args
  • folder (str)

    Path of the Folder to which the Run is uploaded. If the provided path does not start with ‘/’, /<current-user>/ is prepended to it.

  • make_folder (bool)

    If True and Folder with path folder does not exist, make the Folder and parent Folders as needed.

  • conflict_strategy (str)

    Strategy adopted when a Run with the same name as the Run to be uploaded already exists in the Folder, must be ‘skip’, ‘error’, ‘new’ or ‘replace’. If ‘skip’, skip the upload; if ‘error’, error out; if ‘new’, upload with the alternative name of Run; if ‘replace’, delete the existing Run and upload.

t9k.em.upload

upload(path: str, folder: str = 'default', make_folder: bool = False, conflict_strategy: str = 'new') ‑> None

Upload local Runs or Artifacts.

Examples

Upload a Run by its local directory:

em.upload(path='.em/runs/cnn_keras_220823_194728_4e48t2')

Upload all Artifact under the parent directory:

em.upload(path='.em/artifacts')

Specify the path of Folder to which the Run is uploaded:

em.upload(path='.em/runs/cnn_keras_220823_194728_4e48t2',
              folder='image_classification/mnist')

Args

  • path (str)

    Local directory of the Run to be uploaded, or parent directory that contains one or more Runs.

  • folder (str)

    Path of the Folder to which the Run is uploaded. If the provided path does not start with ‘/’, /<current-user>/ is prepended to it.

  • make_folder (bool)

    If True and Folder with path folder does not exist, make the Folder and parent Folders as needed.

  • conflict_strategy (str)

    Strategy adopted when a Run with the same name as the Run to be uploaded already exists in the Folder, must be ‘skip’, ‘error’, ‘new’ or ‘replace’. If ‘skip’, skip the upload; if ‘error’, error out; if ‘new’, upload with the alternative name of Run; if ‘replace’, delete the existing Run and upload.

t9k.tuner

t9k.tuner.get_current_parameter

get_current_parameter(tag: Optional[str] = None)

Gets current hyper parameters generated by tuner. It returns the same group of hyper parameters as the last call of get_next_parameter returns.

Args

  • tag (Optional[str])

    hyper parameter key.

t9k.tuner.get_experiment_id

get_experiment_id()

Gets experiment ID.

Returns

Identifier of current experiment.

t9k.tuner.get_next_parameter

get_next_parameter()

Gets the hyper paremeters generated by tuner. For a multiphase experiment, it returns a new group of hyper parameters at each call of get_next_parameter. For a non-multiphase (multiPhase is not configured or set to False) experiment, it returns hyper parameters only on the first call for each trial job, it returns None since second call. This API should be called only once in each trial job of an experiment which is not specified as multiphase.

Returns

A dict object contains the hyper parameters generated by tuner, the keys of the dict are defined in search space. Returns None if no more hyper parameters can be generated by tuner.

t9k.tuner.get_sequence_id

get_sequence_id()

Gets trial job sequence nubmer. A sequence number is an integer value assigned to each trial job base on the order they are submitted, incremental starting from 0. In one experiment, both trial job ID and sequence number are unique for each trial job, they are of different data types.

Returns

Sequence number of current trial job which is calling this API.

t9k.tuner.get_trial_id

get_trial_id()

Gets trial job ID which is string identifier of a trial job, for example ‘MoXrp’. In one experiment, each trial job has an unique string ID.

Returns

Identifier of current trial job which is calling this API.

t9k.tuner.report_final_result

report_final_result(metric: Any)

Reports final result to TUNER.

Args

  • metric (Any)

    Usually (for built-in tuners to work), it should be a number, or a dict with key “default” (a number), and any other extra keys.

t9k.tuner.report_intermediate_result

report_intermediate_result(metric: Any, step: int)

Reports intermediate result to TUNER.

Args

  • metric (Any)

    serializable object.

Codepack

Codepack 以简洁明了的形式定义在平台上开发、运行、部署一个机器学习项目所需要的全部信息,例如代码、配置文件、各种参数等。其相关工具能够根据这些信息自动地执行相应的操作,从而大幅减少用户的操作量,显著改善实验的可重复性。

例如对于 MNIST 手写数字图像分类任务,在已经准备好了训练代码、数据集和资源配置文件的情况下,你只需要再创建一个 Codepack 定义文件,然后使用 Codepack CLI 执行一条命令,就可以在平台上启动分布式训练:

这里 Codepack 定义文件的内容如下:

apiVersion: codepack.tensorstack.dev/v1beta1
name: mnist-keras
description: A simple image classifier based on CNN using tf2.
project: demo
default: prepare-env
targets:
  - name: prepare-env        # Prepare running env
    actions:
      - name: workspace-for-training
        verb: apply
        files: [pvc.yaml]
  - name: copy-file          # Copy training code and dataset to PVC
    deps: ["prepare-env"]
    actions:
      - name: copy-code
        verb: copy
        src: .
        dst: codepack-example:.
  - name: run-distributed-training    # Run a distributed training
    deps: ["prepare-env", "copy-file"]
    actions:
      - name: trainingjob
        verb: create
        files: [trainingjob.yaml]

整个 Codepack 的文件结构如下:

mnist-keras
├── codepack.yaml
├── main.py
├── mnist.npz
├── pvc.yaml
└── trainingjob.yaml

由于 Codepack 的全部信息都维护在一个定义文件中,用户创建一个新的 Codepack 或者将既有的机器学习项目修改为 Codepack 都非常容易,并且用户可以使用 Git 来轻松地对 Codepack 进行版本控制和分发。

Codepack 的相关工具包括命令行工具和集群内组件,前者负责读取 Codepack 定义并执行用户指定的 action,后者负责进行安全访问控制以及为命令行工具执行 action 提供支持。

下一步

概念

Codepack

Codepack 是对用户想要在平台上运行的机器学习项目的抽象,其实质上是一个包含项目文件(模型代码、资源配置文件等)以及 Codepack 定义文件的文件系统的目录,该定义文件包含了 Codepack 的基本信息(版本、名称、描述等)和运行信息(target 和 action 的定义),见 Codepack 定义

target

target 是对 Codepack 的一个具体任务的抽象,例如在平台上完成模型训练、部署模型为推理服务等。每个 target 可以指定其依赖的其他 target(例如创建推理服务需要先完成模型训练),命令行工具在运行一个 target 时,将递归地解析依赖,然后运行一个工作流。

action

action 是对 target 的一个具体的可执行的操作的抽象,例如在平台中创建一个 PVC、创建一个进行分布式训练的 TrainingJob 等。action 定义了多个动词(verb),每个动词针对某一类的具体操作,由命令行工具和集群内组件提供实现。

Codepack 定义

一个包含机器学习代码及相关文件的文件系统目录,加上 Codepack 的定义文件就构成了一个 Codepack。Codepack 定义文件是一个通常名为 codepack.yaml 的 YAML 文件,其包含 Codepack 的版本、名称、描述等基本信息以及 target 定义、action 定义等运行相关的信息。

下面将具体介绍 Codepack 定义文件中的各个字段以及它们的作用,从而指导用户如何创建一个 Codepack。

创建 Codepack 定义文件

下面是一个基本的 Codepack 定义文件的示例:

apiVersion: codepack.tensorstack.dev/v1beta1
name: mnist-keras
description: A simple image classifier based on CNN using tf2.
targets:
  - name: prepare-env    # target definition
    actions:
      - name: workspace-for-training    # action definition
        verb: apply
        files: [pvc.yaml]
      - name: copy-code
        verb: copy
        src: .
        dst: codepack-pvc:.

在该例中:

  • 指定 Codepack 的版本、名称和详细描述(分别由 apiVersionnamedescription 字段指定)。
  • targets 字段定义一个 target,这个 target 又通过 actions 字段定义两个 action。这里 target 的 name 字段是必需的;action 的 name 字段不是必需的,但 verb 字段以及相应动词需要提供的字段是必需的(请参阅 action 动词)。

指定默认项目和 target

可以通过 projectdefault 字段指定 Codepack 的默认项目和 target,这样在使用命令行工具运行 Codepack 时如果不提供相应的参数,则会使用这些默认值。

apiVersion: codepack.tensorstack.dev/v1beta1
name: mnist-keras
description: A simple image classifier based on CNN using tf2.
project: demo           # default project to run in
default: prepare-env    # default target to run
targets:
  - name: prepare-env
    actions:
      - name: workspace-for-training
        verb: apply
        files: [pvc.yaml]
      - name: copy-code
        verb: copy
        src: .
        dst: codepack-pvc:.

工作流机制

target 是对 Codepack 的一个具体任务的抽象,多个 target 之间可能存在依赖关系,例如负责从本地复制文件到 PVC 的 target 需要依赖负责创建 PVC 的 target 运行完毕。每一个 target 可以通过 deps 字段传入一个 target 名称列表来指定其依赖的其他 target。

在使用命令行工具运行某一个 target 时,命令行工具会递归地解析所有依赖的 target,动态地构建一个有向无环图,然后串行或者并行地运行图中当前没有依赖或依赖已经运行完毕的 target,直到所有 target 全部运行。

利用工作流机制,可以将上面示例中的 target prepare-env 拆分为具有依赖关系的两个 target,并且在此基础上再创建一个依赖它们的负责启动分布式训练的 target。

apiVersion: codepack.tensorstack.dev/v1beta1
name: mnist-keras
description: A simple image classifier based on CNN using tf2.
project: demo
default: prepare-env
targets:
  - name: prepare-env        # Prepare running env
    actions:
      - name: workspace-for-training
        verb: apply
        files: [pvc.yaml]
  - name: copy-file          # Copy the Codepack to PVC
    deps: ["prepare-env"]
    actions:
      - name: copy-code
        verb: copy
        src: .
        dst: codepack-pvc:.
  - name: run-distributed-training    # Run a distributed training
    deps: ["prepare-env", "copy-file"]
    actions:
      - name: trainingjob
        verb: create
        files: [trainingjob.yaml]

action 动词

action 的动词通过 verb 字段指定,表示其操作类型,目前定义了下列值。

apply

应用配置到资源,类似于 kubectl apply。若同名资源已经存在,则更新其配置,否则创建该资源。

需要提供以下字段:

  • files:定义资源的 YAML 配置文件的路径、文件路径的列表或者包含 YAML 配置文件的目录的路径。

示例:

actions:
  - name: workspace-for-training
    verb: apply
    files: [pvc.yaml]

copy

将文件或目录从源位置复制到目标位置,具体实现取决于源和目标的类型:

  1. 若都为本地路径,则直接在本地进行 rsync 操作。
  2. 若一个为本地路径,一个为 PVC 路径,则在集群中创建一个挂载这个 PVC 并且运行 sshd 服务的 Pod,在本地进行远程 rsync 操作。
  3. 若都为 PVC 路径,则在集群中创建一个挂载这两个 PVC 的 Pod,在 Pod 中进行 rsync 操作。

需要提供以下字段:

  • src:文件或目录的源位置,可以是本地路径或 PVC 路径,格式如下:

    • 本地路径:

      • .(Codepack 的全部文件)
      • ./data(Codepack 的子目录)
      • ./data/(Codepack 的子目录下的全部文件)
      • ./train.py(Codepack 的文件)
    • PVC 路径:

      • <pvc-name>:.(PVC 的根目录)
      • <pvc-name>:data(PVC 的子目录)
      • <pvc-name>:data/(PVC 的子目录下的全部文件)
      • <pvc-name>:data/mnist.npz(PVC 的文件)
  • dst:文件或目录的目标位置,可以是本地路径或 PVC 路径,格式同上。

示例:

actions:
  - name: copy-code
    verb: copy
    src: .
    dst: codepack-pvc:.

create

创建资源,类似于 kubectl create。若同名资源已经存在,则错误退出,或为名称添加随机后缀再进行创建。

需要提供以下字段:

  • files:定义资源的 YAML 配置文件的路径、文件路径的列表或者包含 YAML 配置文件的目录的路径。
  • new:若为 True,并且同名资源已经存在,则为名称添加随机后缀再进行创建;若为 False 则错误退出。默认为 True。

示例:

actions:
  - name: trainingjob
    verb: create
    files: [trainingjob.yaml]

命令行工具

Codepack CLI(命令行工具)用于在命令行终端中运行 Codepack。

安装

前置条件

Codepack CLI 使用 Python 3 编写,在安装之前请确保你的本地环境安装了 3.6 或以上版本的 Python 以及 pip 工具。

为使 Codepack CLI 提供的文件复制功能正常运行,还需要安装 3.1.0 及以上版本的 rsync。macOS 执行以下命令安装:

brew install rsync

基于 Debian 的 Linux 发行版执行以下命令安装:

apt-get install rsync

基于 rpm 的 Linux 发行版执行以下命令安装:

yum install rsync

然后你可以执行以下命令来验证安装完成,并且确认安装的 rsync 版本。

rsync --version

安装

目前 TensorStack SDK 仅提供用于本地安装的 Python 包,你可以从平台首页下载。

然后使用以下命令进行安装:

pip install codepack-<version>.tar.gz [-i <pypi-mirror-url>]

命令

check

检查 Codepack 的有效性。

使用

codepack check [CODEPACK_PATH]

CODEPACK_PATH    Codepack 或 Codepack 定义文件的路径, 默认为当前路径

示例

$ codepack check examples/mnist-keras
Checked, no errors found in codepack mnist-keras

config

查看、修改 Codepack CLI 的配置。

Codepack CLI 各项配置的含义如下:

配置项含义默认值
api_key用于身份验证的 API KeyNone
copy_pod_imagecopy 动词创建的 Pod 所使用的镜像None

使用

$ codepack config [--list] [--get KEY] [--set KEY=VALUE]

--list, -l             列出所有 CLI 配置项
--get=KEY, -g          获取 CLI 配置项
--set=KEY=VALUE, -s    设置 CLI 配置项

示例

$ codepack config --list
api_key=None
copy_pod_image=t9kpublic/sshd-rsync:0.0.0.6

$ codepack config --get api_key
api_key=None

$ codepack config --set api_key=5b398842-7c92-4922-a472-c905553beefd
api_key=5b398842-7c92-4922-a472-c905553beefd
config items set

$ codepack config --get api_key
api_key=5b398842-7c92-4922-a472-c905553beefd

describe

查看 Codepack 的详细信息。

使用

codepack describe [CODEPACK_PATH]

CODEPACK_PATH    Codepack 或 Codepack 定义文件的路径, 默认为当前路径

示例

$ codepack describe examples/mnist-keras 
name: mnist-keras
description: A simple image classifier based on CNN using tf2.
project: demo
targets:
  - prepare-env
  - copy-file
  - create-notebook
  - run-distributed-training
  - run-e2e-workflow

run

运行 Codepack 的指定 target。

使用

codepack run [--project PROJECT_NAME] [--target TARGET_NAME] [--verbose] [--wait-timeout INTEGER] [CODEPACK_PATH]

--project=PROJECT_NAME, -p    项目名称, 运行在该项目下
--target=TARGET_NAME, -t      target 名称, 运行该 target
--verbose, -v                 打印更多信息
--wait-timeout=INT, -W        设定以秒为单位的 Pod 超时等待时间
CODEPACK_PATH                 Codepack 或 Codepack 定义文件的路径, 默认为当前路径

示例

$ codepack run examples/mnist-keras -t run-distributed-training -p demo
RUN target run-distributed-training of codepack mnist-keras in project demo
Running sequence: prepare-env -> copy-file -> run-distributed-training

Target 1/3: prepare-env
APPLY by files ['pvc.yaml']
PersistentVolumeClaim with the name codepack-example already exists, skip
Target 2/3: copy-file
COPY from . to codepack-example:.
copied
Target 3/3: run-distributed-training
CREATE by files ['trainingjob.yaml']
TensorFlowTrainingJob codepack-example created

配置

配置文件

Codepack CLI 没有单独的配置文件,而是使用 TensorStack CLI 的配置文件。在执行 codepack 命令时,会自动读取位于路径 ~/.t9k/t9k-config.yaml 的配置文件(如果设置了环境变量 T9K_CONFIG,则读取其值给出的路径)。如果配置文件不存在或缺少部分配置项,则缺少的这些配置项会被设置为 None,这可能导致 Codepack CLI 的部分功能不能正常工作。

扩展配置

配置文件中的 contexts[*].extension.codepack 字段是 Codepack CLI 的扩展配置,其包含以下字段:

字段功能
copy-pod-image用于复制文件的 Pod 使用的镜像

查看配置

使用 codepack config -l 命令以查看所有配置项的值。

身份验证

Codepack CLI 支持下列身份验证方式,你可以选择其中的一种进行相应的配置。

平台内运行(incluster)

用户需要在平台资源内(平台所在 Kubernetes 集群的 Pod 内)使用 Codepack CLI,例如在 Notebook 的终端中使用。

注意在运行 target 时只能指定当前项目(不指定则默认为当前项目)。

在此方式下,Codepack CLI 直接利用 Kubernetes 提供给 Pod 的 Service Account 向 kube-apiserver 发送请求以执行各 action。

kubeconfig 文件

用户需要持有平台所在 Kubernetes 集群的 kubeconfig 文件,并将其放置在路径 ~/.kube/config 下(如果设置了环境变量 KUBECONFIG,则放置在其值给出的路径下)。

在此方式下,Codepack CLI 直接利用 kubeconfig 文件向 kube-apiserver 发送请求以执行各 action。

t9kconfig 文件

用户持有的配置文件需要提供 API Key 或 token。

在此方式下,Codepack CLI 向平台的各服务器发送请求,再由它们向 kube-apiserver 转发请求以执行各 action。

示例

下面是一个简单但完整的创建和运行 Codepack 的示例。

创建 Codepack

这里以进行 MNIST 手写数字图像分类的 Keras 模型为例,在工作路径下创建一个名为 mnist-keras 的目录。

准备代码、数据集和资源配置文件

首先编写一个进行模型构建、训练和测试的 Python 脚本,使用 Keras 框架和简单的卷积神经网络结构。为了在平台上进行分布式训练,训练过程采用 tf.distribute.MultiWorkerMirroredStrategy 分布式策略。具体代码如下:

import argparse
import json
import logging
import os
import shutil

import tensorflow as tf
from tensorflow.keras import callbacks, datasets, layers, models, optimizers

parser = argparse.ArgumentParser(
    description='Distributed training of Keras model for MNIST with '
    'MultiWorkerMirroredStrategy.')
parser.add_argument('--aimd',
                    action='store_true',
                    default=False,
                    help='Use AIMD to record training data.')
parser.add_argument('--api_key',
                    type=str,
                    help='API Key for requesting AIMD server. '
                    'Required if --aimd is set.')
parser.add_argument(
    '--folder_path',
    type=str,
    default='aimd-example',
    help='Path of AIMD folder in which trial is to be created. '
    'Required if --aimd is set.')
parser.add_argument('--log_dir',
                    type=str,
                    help='Path of the TensorBoard log directory.')
parser.add_argument('--no_cuda',
                    action='store_true',
                    default=False,
                    help='Disable CUDA training.')
parser.add_argument(
    '--server_url',
    type=str,
    default='https://proxy.nc201.kube.tensorstack.net/t9k/aimd/server',
    help='URL of AIMD server. Required if --aimd is set.')
parser.add_argument('--save_path',
                    type=str,
                    default=None,
                    help='Save path of the trained model.')
parser.add_argument('--trial_name',
                    type=str,
                    default='mnist_keras_distributed',
                    help='Name of AIMD trial to create. '
                    'Required if --aimd is set.')
args = parser.parse_args()
logger = logging.getLogger('print')
logger.setLevel(logging.INFO)
logger.addHandler(logging.StreamHandler())
logger.propagate = False

if args.no_cuda:
    # Sets all GPUs invisible
    tf.config.set_visible_devices([], 'GPU')
gpus = tf.config.get_visible_devices('GPU')
if gpus:
    # Print GPU info
    logger.info('NVIDIA_VISIBLE_DEVICES: {}'.format(
        os.getenv('NVIDIA_VISIBLE_DEVICES')))
    logger.info('T9K_GPU_PERCENT: {}'.format(os.getenv('T9K_GPU_PERCENT')))
    logger.info('Visible GPUs: {}'.format(
        tf.config.get_visible_devices('GPU')))
    # Set memory growth
    for gpu in gpus:
        tf.config.experimental.set_memory_growth(gpu, True)
    # # Set GPU memory limit
    # tf.config.set_logical_device_configuration(
    #     gpus[0], [tf.config.LogicalDeviceConfiguration(memory_limit=1024)])

    strategy = tf.distribute.MultiWorkerMirroredStrategy()

# Get information for current worker.
tf_config = json.loads(os.environ['TF_CONFIG'])
world_size = len(tf_config['cluster']['worker'])
task_index = tf_config['task']['index']

if args.aimd and task_index == 0:
    from t9k import aimd
    trial = aimd.init(server_url=args.server_url,
                    trial_name=args.trial_name,
                    folder_path=args.folder_path,
                    api_key=args.api_key)

params = {
    'batch_size': 32 * world_size,
    'epochs': 10,
    'learning_rate': 0.001 * world_size,
    'conv_channels1': 32,
    'conv_channels2': 64,
    'conv_channels3': 64,
    'conv_kernel_size': 3,
    'maxpool_size': 2,
    'linear_features1': 64,
    'seed': 1,
}

if args.aimd and task_index == 0:
    trial.params.update(params)
    trial.params.parse(dist_tf_strategy=strategy)

with strategy.scope():
    model = models.Sequential([
        layers.Conv2D(params['conv_channels1'],
                    params['conv_kernel_size'],
                    activation='relu',
                    input_shape=(28, 28, 1)),
        layers.MaxPooling2D((params['maxpool_size'], params['maxpool_size'])),
        layers.Conv2D(params['conv_channels2'],
                    params['conv_kernel_size'],
                    activation='relu'),
        layers.MaxPooling2D((params['maxpool_size'], params['maxpool_size'])),
        layers.Conv2D(params['conv_channels3'],
                    params['conv_kernel_size'],
                    activation='relu'),
        layers.Flatten(),
        layers.Dense(params['linear_features1'], activation='relu'),
        layers.Dense(10, activation='softmax'),
    ])
    model.compile(
        optimizer=optimizers.Adam(learning_rate=params['learning_rate']),
        loss='sparse_categorical_crossentropy',
        metrics=['accuracy'])

print(os.path.join(os.getcwd(), 'mnist.npz'))
(train_images, train_labels), (test_images,
                            test_labels) = datasets.mnist.load_data(
                                path=os.path.join(os.getcwd(), 'mnist.npz'))
train_images = train_images.reshape((60000, 28, 28, 1)).astype("float32") / 255
test_images = test_images.reshape((10000, 28, 28, 1)).astype("float32") / 255
train_images, val_images = tf.split(train_images, [48000, 12000], axis=0)
train_labels, val_labels = tf.split(train_labels, [48000, 12000], axis=0)
train_dataset = tf.data.Dataset.from_tensor_slices(
    (train_images, train_labels)).shuffle(
        48000, seed=params['seed']).repeat().batch(params['batch_size'])
val_dataset = tf.data.Dataset.from_tensor_slices(
    (val_images, val_labels)).batch(400)
test_dataset = tf.data.Dataset.from_tensor_slices(
    (test_images, test_labels)).batch(1000)

train_callbacks = []
test_callbacks = []

if args.aimd and task_index == 0:
    from t9k.aimd.keras import AIMDFitCallback, AIMDEvalCallback
    train_callbacks.append(AIMDFitCallback(trial))
    test_callbacks.append(AIMDEvalCallback(trial))

if args.log_dir and task_index == 0:
    log_dir = args.log_dir
    if os.path.exists(log_dir):
        shutil.rmtree(log_dir, ignore_errors=True)
    tensorboard_callback = callbacks.TensorBoard(log_dir=log_dir)
    train_callbacks.append(tensorboard_callback)

model.fit(train_dataset,
        epochs=params['epochs'],
        steps_per_epoch=48000 // params['batch_size'],
        validation_data=val_dataset,
        callbacks=train_callbacks,
        verbose=2)

if args.save_path:
    if task_index == 0:
        save_path = args.save_path
    else:
        dirname = os.path.dirname(args.save_path)
        basename = os.path.basename(
            args.save_path) + '_temp_' + str(task_index)
        save_path = os.path.join(dirname, basename)
    if os.path.exists(save_path):
        shutil.rmtree(save_path, ignore_errors=True)
    model.save(save_path)
    if task_index != 0:
        shutil.rmtree(save_path, ignore_errors=True)

model.evaluate(test_dataset, callbacks=test_callbacks, verbose=2)

if args.aimd and task_index == 0:
    trial.finish()

编写一个下载数据集的脚本并运行,以将数据集文件 mnist.npz 下载到 Codepack 中。具体代码如下:

import os
import tensorflow as tf

_, _ = tf.keras.datasets.mnist.load_data(
os.path.join(os.path.dirname(os.path.realpath(__file__)), 'mnist.npz'))

考虑在平台上运行时需要创建 PVC、Notebook(可选,便于进一步开发或对 PVC 中的文件进行修改)和 TensorFlowTrainingJob,分别编写相应的资源配置文件如下:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: codepack-example
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 2Gi
apiVersion: tensorstack.dev/v1beta1
kind: Notebook
metadata:
  name: codepack-example
spec:
  template:
    spec:
      containers:
        - name: notebook
          image: 'registry.tensorstack.cn/t9k/tensorflow-2.8.0-notebook-cpu:1.50.0'
          resources:
            limits:
              cpu: '1'
              memory: 1Gi
            requests:
              cpu: 500m
              memory: 500Mi
          volumeMounts:
            - name: workingdir
              mountPath: /t9k/mnt
      volumes:
        - name: workingdir
          persistentVolumeClaim:
            claimName: codepack-example
apiVersion: batch.tensorstack.dev/v1beta1
kind: TensorFlowTrainingJob
metadata:
  name: codepack-example
spec:
  scheduler:
    t9kScheduler:
      queue: default
      priority: 50
  runPolicy:
    cleanUpPolicy: Unfinished
    backoffLimit: 20           # 所有Pod最多共重启20次
  tensorboardSpec:
    trainingLogFilesets:
      - t9k://pvc/codepack-example/mnist-keras/log
    image: t9kpublic/tensorflow-2.7.0:cpu
  replicaSpecs:
    - type: worker
      replicas: 4
      restartPolicy: OnFailure
      template:
        spec:
          securityContext:
            runAsUser: 1000
          containers:
            - command:
                - python        # 运行脚本的命令
                - main.py
                - "--no_cuda"
                - "--log_dir"
                - "log"
                - "--save_path"
                - "saved-model"
              workingDir: /mnt/mnist-keras/    # 工作路径,与定义文件中Codepack的
              imagePullPolicy: IfNotPresent    # 复制路径一致
              image: t9kpublic/tensorflow-2.7.0:cpu
              name: tensorflow
              resources:
                requests:
                  cpu: 2000m
                  memory: 2Gi
                limits:
                  cpu: 4000m
                  memory: 4Gi
              volumeMounts:
                - mountPath: /mnt
                  name: data
          volumes:
            - name: data
              persistentVolumeClaim:
                claimName: codepack-example

现在 Codepack 的文件结构如下:

mnist-keras
├── download_dataset.py
├── main.py
├── mnist.npz
├── notebook.yaml
├── pvc.yaml
└── trainingjob.yaml

编写 Codepack 定义文件

然后编写 Codepack 的定义文件。考虑在平台中运行该 Codepack 的过程,将其拆分为 4 个具体的任务,分别是:

  1. 准备环境,这里只包含创建 PVC。使用 verb apply 并提供 pvc.yaml 文件的路径。
  2. 复制整个 Codepack 到 PVC。使用 verb copy 并提供源和目标位置的路径。
  3. 创建 Notebook。使用 verb create 并提供 notebook.yaml 文件的路径。需要依赖 1 和 2。
  4. 进行分布式训练,即创建 TrainingJob。使用 verb create 并提供 trainingjob.yaml 文件的路径。需要依赖 1 和 2。

据此完成的定义文件如下:

apiVersion: codepack.tensorstack.dev/v1beta1
name: mnist-keras
description: A simple image classifier based on CNN using tf2.
project: demo
default: prepare-env
targets:
  - name: prepare-env        # Prepare running env
    actions:
      - name: workspace-for-training
        verb: apply
        files: [pvc.yaml]
  - name: copy-file          # Copy training code and dataset to PVC
    deps: ["prepare-env"]
    actions:
      - name: copy-code
        verb: copy
        src: .
        dst: codepack-example:.
  - name: create-notebook    # Create a notebook with the codepack in it
    deps: ["prepare-env", "copy-file"]
    actions:
      - name: notebook
        verb: create
        files: [notebook.yaml]
  - name: run-distributed-training    # Run a distributed training
    deps: ["prepare-env", "copy-file"]
    actions:
      - name: trainingjob
        verb: create
        files: [trainingjob.yaml]

最终 Codepack 的文件结构如下:

mnist-keras
├── codepack.yaml
├── download_dataset.py
├── main.py
├── mnist.npz
├── notebook.yaml
├── pvc.yaml
└── trainingjob.yaml

对 Codepack 进行版本控制(可选)

将 Codepack 创建为一个 Git 仓库以进行版本控制,之后你就可以使用任意的本地或远程仓库方便地进行版本控制和分发。

运行 Codepack

使用 Codepack CLI 运行 Codepack。

配置身份验证信息

Codepack CLI 支持多种身份验证方式,你可以选择其中一种并进行相应的配置。详细步骤请参阅身份验证

使用命令行工具运行 Codepack

先使用以下命令运行 target create-notebook

$ codepack run examples/mnist-keras -t create-notebook -p demo
RUN target create-notebook of codepack mnist-keras in project demo
Running sequence: prepare-env -> copy-file -> create-notebook

Target 1/3: prepare-env
APPLY by files ['pvc.yaml']
PersistentVolumeClaim codepack-example created
Target 2/3: copy-file
COPY from . to codepack-example:.
copied
Target 3/3: create-notebook
CREATE by files ['notebook.yaml']
Notebook codepack-example created

再使用以下命令运行 target run-distributed-training

$ codepack run examples/mnist-keras -t run-distributed-training -p demo
RUN target run-distributed-training of codepack mnist-keras in project demo
Running sequence: prepare-env -> copy-file -> run-distributed-training

Target 1/3: prepare-env
APPLY by files ['pvc.yaml']
PersistentVolumeClaim with the name codepack-example already exists, skip
Target 2/3: copy-file
COPY from . to codepack-example:.
copied
Target 3/3: run-distributed-training
CREATE by files ['trainingjob.yaml']
TensorFlowTrainingJob codepack-example created

可以看到在运行这两个 target 的过程中,Codepack CLI 自动解析了工作流并顺序运行各个依赖的 target,按照 YAML 配置文件创建了各资源以及复制整个 Codepack 到 PVC。在运行 target run-distributed-training 的过程中,Codepack CLI 跳过了第一个 target(因为 PVC 已经创建),第二个 target 也实际上没有更新 PVC 中的文件(因为背后调用的是 rsync)。

参考

术语表

本术语表记录了 TensorStack AI 平台的一些专有名词,方便用户随时查阅。

API Key

API Key 是一种 TensorStack AI 平台的安全认证方式,主要应用场景为非交互式程序化身份认证,例如自动化脚本等;或者受限制的交互式场景,例如命令行工具。详见 API Key 文档

Assessor 算法

Assessor 算法是一系列训练评估算法的统称,用于在 AutoTune 中判断当前超参数的训练中间结果是否符合预期。详见 AutoTune 文档

AutoTune

AutoTune 是 TensorStack AI 平台提供的自动化机器学习工具,用于自动地进行特征工程、神经网络架构搜索、超参调优和模型压缩。详见 AutoTune 文档

AutoTuneExperiment

AutoTuneExperiment 是一种 TensorStack 资源,用于自动化机器学习超参数调优。详见 AutoTuneExperiment 文档

BeamJob

BeamJob 是一种 TensorStack 资源,用于通过 Apache Beam 框架和 Apache Flink 等底层计算引擎运行分布式计算任务。详见 BeamJob 文档

ClusterRole

与 Role 类似,但 Role 只能指定某个命名空间范围内的权限,ClusterRole 是整个集群范围。

ClusterRoleBinding

与 RoleBinding 类似,但 RoleBinding 只能指定某个命名空间范围内的权限,ClusterRoleBinding 是整个集群范围。

ConfigMap

ConfigMap 是一种以键值对的形式存储非机密信息的 Kubernetes 资源。Pod 可以挂载 ConfigMap,并以环境变量、命令行参数或配置文件的形式使用 ConfigMap 中的信息。详见 ConfigMap管理 ConfigMap

Container(容器)

容器是可移植、可执行的轻量级的镜像,包含其中的软件及其相关依赖。容器使应用和底层的主机基础设施解耦,降低了应用在不同云环境或者操作系统上的部署难度,便于应用扩展。

Controller(控制器)

控制器负责监控集群中某种 Kubernetes 资源的所有实例,并设法将资源的当前状态转变为期望状态。

CRD(Custom Resource Definition,定制资源定义)

CRD 是 Kubernetes 提供的一种扩展机制,允许开发者定制自己的资源,并开发对应的控制器。TensorStack AI 平台定义了一系列资源,以方便你在 Kubernetes 集群上构建机器学习应用。

CronWorkflowRun

CronWorkflowRun 是一种 TensorStack 资源,用于方便地定时执行 WorkflowRun。详见 CronWorkflowRun 文档

Docker

Docker 是一个提供操作系统级别的虚拟化技术的软件,用于将软件应用及其相关依赖打包成所谓的容器(Container),能够在一个操作系统实例中运行多个其他操作系统中构建的容器。Kubernetes 支持使用 Docker 作为容器运行时。详见 Docker 文档

Explorer

Explorer 是一种 TensorStack 资源,用于通过浏览器访问文件管理器和集成开发环境(IDE)。详见 Explorer 文档

GenericJob

GenericJob 是一种 TensorStack 资源,用于统一协调多个 Pod 共同完成一项任务。详见 GenericJob 文档

Image(镜像)

镜像是保存的容器实例,它打包了应用运行所需的一组软件。你可以将镜像存储在容器镜像仓库、拉取到本地系统并作为应用来运行。

Job

在 TensorStack AI 平台中,Job 是一类统一协调多个 Pod 共同完成一项任务的资源,包括 GenericJob、TensorFlowTrainingJob、PyTorchTrainingJob、XGBoostTrainingJob、MPIJob、BeamJob 等。

Kubernetes(K8s)

Kubernetes 是一个开源的容器编排引擎,用来对容器化应用进行自动化部署、 扩缩和管理。TensorStack AI 平台构建在 Kubernetes 的坚实基础之上。详见 Kubernetes 文档

Label(标签)

标签是附属在资源上的键值对,用于标明资源的属性。你可以通过标签来选取一组资源的某个子集。

MLService

MLService 是一种 TensorStack 资源,用于部署机器学习模型预测服务,以供外部用户使用。详见 MLService 文档

MPIJob

MPIJob 是一种 TensorStack 资源,用于通过 OpenMPI 协议进行分布式机器学习训练。详见 MPIJob 文档

Namespace(命名空间)

命名空间是一组资源所属的工作空间,提供了一种划分集群、隔离资源的方式。同一命名空间内的资源名称必须不同,不同命名空间的资源名称可以相同。

Node(节点)

节点是 Kubernetes 中的工作机器。通常,Kubernetes 集群由一系列节点组成,少则一个,多则上千个。

Notebook

Notebook 是一种 TensorStack 资源,用于在集群中运行 Jupyter Notebook,同时提供 GPU 支持、SSH 访问支持等补充功能。详见 Notebook 文档

Pod

Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。Pod 是一组(一个或多个)容器,这些容器共享存储、网络以及怎样运行这些容器的声明。详见 Kubernetes 文档

PodGroup

PodGroup 是一组 Pod 的集合,它们需要协同工作、一起被调度。详见 PodGroup 文档

Project

Project 是 TensorStack AI 平台对计算集群的抽象,建立在 Kubernetes 命名空间 (namespace)之上。不同的用户通常在不同的 Project 下工作,并且可以互相分享自己 Project。详见 Project 文档

PVC(PersistentVolumeClaim,持久卷申领)

PVC 是一种持久化的存储资源,可以被 Pod 挂载、作为 Pod 的卷被访问。你可以在 TensorStack AI 平台的模型构建控制台中创建一个 PVC,并指定它的存储空间(例如 100M、1G)和访问模式(例如只读、可读写、可运行),详见 PVC管理 PVC

PyTorchTrainingJob

PyTorchTrainingJob 是一种 TensorStack 资源,用于通过 PyTorch 框架进行分布式机器学习训练。详见 PyTorchTrainingJob 文档

Queue(队列)

队列是一种 TensorStack 资源,用于存放 PodGroup 并根据它们的优先级进行调度。详见队列文档

RBAC(Role Based Access Control)

RBAC 是一种管理访问控制的方式,详见 Kubernetes 文档。你可以通过 ServiceAccount、Role、RoleBinding、ClusterRole、ClusterRoleBinding 等资源来管理访问控制。

Role

Role 中包含一组代表相关权限的规则,例如获取 Pod、创建 Pod、删除 Pod、获取 Secret、创建 Secret、删除 Secret 等。

RoleBinding

RoleBinding 将 Role 中定义的权限赋予一个用户或者一个 ServiceAccount,这样绑定 ServiceAccount 的 Pod 就能进行 Role 中定义的操作。

Scheduler(调度器)

调度器负责将 Pod 分配到合适的节点上,保证节点满足 Pod 声明的计算资源(CPU、内存、GPU等)、亲和度偏好(希望与其他 Pod 一起运行、希望运行在拥有某个标签的节点上等)等需求。

Secret

Secret 是一种存储密码、令牌、SSH Key 等敏感信息的 Kubernetes 资源。Pod 可以将 Secret 挂载为一个文件,并读取其中的信息。详见 Secret管理 Secret

ServiceAccount

ServiceAccount 为 Pod 提供一个身份凭证。当你创建一个 Pod 时,如果没有指定 ServiceAccount,该 Pod 会默认绑定一个名为 default 的 ServiceAccount。

SimpleMLService

SimpleMLService 是一种 TensorStack 资源,用于部署机器学习模型预测服务,以供内部开发者快速测试。详见 SimpleMLService 文档

TensorBoard

TensorBoard 是 TensorFlow 提供的机器学习可视化工具。TensorStack AI 平台提供在集群中一键部署 TensorBoard 的功能,详见 TensorBoard 文档

TensorFlowTrainingJob

TensorFlowTrainingJob 是一种 TensorStack 资源,用于通过 TensorFlow 框架进行分布式机器学习训练。详见 TensorFlowTrainingJob 文档

Tuner 算法

Tuner 算法是一系列超参数调优算法的统称,用于在 AutoTune 中选取合适的超参数组合。详见 AutoTune 文档

Volume(卷)

卷是一个包含数据的文件夹,可以被 Pod 中的容器访问。详见 Kubernetes 文档

WorkflowRun

WorkflowRun 是一种 TensorStack 资源,用于实例化 WorkflowTemplate 并提供 WorkflowTemplate 运行时所需的参数、工作空间等资源。详见 WorkflowRun 文档

WorkflowTemplate

WorkflowTemplate 是一种 TensorStack 资源,用于在 Kubernetes 中有序、高效、方便地组织运行各类工作负载。详见 WorkflowTemplate 文档

XGBoostTrainingJob

XGBoostTrainingJob 是一种 TensorStack 资源,用于通过 XGBoost 框架进行分布式机器学习训练。详见 XGBoostTrainingJob 文档

API 参考

API Reference

Packages

tensorstack.dev/v1beta1

Package v1beta1 contains API Schema definitions for the v1beta1 API group

Resource Types

EventControllerStatus

Appears in:

FieldDescription
deployment EventDeploymentStatus

EventDeploymentStatus

Appears in:

FieldDescription
name string
readyReplicas integer
podStatus EventPodStatus

EventPodStatus

Appears in:

FieldDescription
name string
uid UID
phase PodPhase

NetworkPolicy

Appears in:

FieldDescription
useDefaultTemplate booleanIf true, the default NetworkPolicy defined by the administrator will be applied.
template NetworkPolicyTemplateA NethworkPolicy defined for this project.

NetworkPolicyTemplate

Appears in:

FieldDescription
spec NetworkPolicySpec

Project

Project is the Schema for the projects API

Appears in:

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringProject
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec ProjectSpec
status ProjectStatus

ProjectCondition

Appears in:

FieldDescription
type ProjectConditionTypeType is the type of the condition.
status ConditionStatusStatus is the status of the condition. Can be True, False, Unknown.
lastUpdateTime TimeLast time we probed the condition.
lastTransitionTime TimeLast time the condition transitioned from one status to another.
reason stringUnique, one-word, CamelCase reason for the condition’s last transition.
message stringHuman-readable message indicating details about last transition.

ProjectConditionType

Underlying type: string

Appears in:

ProjectList

ProjectList contains a list of Project

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringProjectList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items Project array

ProjectSpec

ProjectSpec defines the desired state of Project

Appears in:

FieldDescription
resourceQuota ResourceQuota
networkPolicy NetworkPolicy
quotaProfile string
defaultScheduler SchedulePolicyDefaultScheduler defines the default scheduler and queue information for the project. It is just a configuration information, the controller does not need to do anything.

ProjectStatus

ProjectStatus defines the observed state of Project

Appears in:

FieldDescription
conditions ProjectCondition array
eventController EventControllerStatus
resourceQuota ResourceQuotaStatus

QuotaProfile

QuotaProfile is the Schema for the quotaprofiles API. This API resource represents a template for project/namespace resource quota specifications, defined as an instance of corev1.ResourceQuotaSpec.

Appears in:

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringQuotaProfile
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec ResourceQuotaSpec

QuotaProfileList

QuotaProfileList contains a list of QuotaProfile

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringQuotaProfileList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items QuotaProfile array

ResourceQuota

Appears in:

FieldDescription
template ResourceQuotaTemplateA corev1.ResourceQuota defined for this project.

ResourceQuotaStatus

Appears in:

FieldDescription
name string
ResourceQuotaStatus ResourceQuotaStatus

ResourceQuotaTemplate

Appears in:

FieldDescription
spec ResourceQuotaSpec

SchedulePolicy

SchedulePolicy specifies preferences for resource allocation requests, including the name of the preferred scheduler and additional configuration parameters.

Appears in:

FieldDescription
t9kScheduler T9kScheduler

T9kScheduler

Appears in:

FieldDescription
queue stringName of the resource Queue of a T9kScheduler.

API Reference

Packages

batch.tensorstack.dev/v1beta1

Package v1beta1 contains API Schema definitions for the batch v1beta1 API group

Resource Types

Aggregate

Aggregate records the number of replica pods at each phase.

Appears in:

FieldDescription
creating integerPod has been created, but resources have not been scheduled.
pending integerPod has been accepted by the system, but one or more of the containers has not been started. This includes time before being bound to a node, as well as time spent pulling images onto the host.
running integerPod has been bound to a node and all of the containers have been started. At least one container is still running or is in the process of being restarted.
succeeded integerAll containers in the pod have voluntarily terminated with a container exit code of 0, and the system is not going to restart any of these containers.
failed integerAll containers in the pod have terminated, and at least one container has terminated in failure (exited with a non-zero exit code or was stopped by the system).
unknown integerFor some reason the state of the pod could not be obtained, typically due to an error in communicating with the host of the pod.
deleted integerPod has been deleted.

CleanUpPolicy

Underlying type: string

CleanUpPolicy specifies the collection of replicas that are to be deleted upon job completion.

Appears in:

ContainerStatus

ContainerStatus defines the observed state of the container.

Appears in:

DebugMode

DebugMode configs whether and how to start a job in debug mode.

Appears in:

FieldDescription
enabled booleanWhether to enable debug mode.
replicaSpecs ReplicaDebugSet arrayIf provided, these specs provide overwriting values for job replicas.

FinishRule

A finishRule is a condition used to check if the job has finished. A finishRule identifies a set of replicas, and the controller determines the job’s status by checking the status of all of these replicas.

Appears in:

GenericJob

GenericJob represents the schema for a general-purpose batch job API. While it offers less automation compared to specialized APIs like PyTorchTrainingJob, it allows for greater flexibility in specifying parallel replicas/pods. This design serves as a comprehensive job definition mechanism when more specialized APIs are not applicable or available.

Appears in:

FieldDescription
apiVersion stringbatch.tensorstack.dev/v1beta1
kind stringGenericJob
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec GenericJobSpec
status GenericJobStatus

GenericJobList

GenericJobList contains a list of GenericJob

FieldDescription
apiVersion stringbatch.tensorstack.dev/v1beta1
kind stringGenericJobList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items GenericJob array

GenericJobSpec

GenericJobSpec defines the desired state of GenericJob

Appears in:

FieldDescription
successRules FinishRule arrayRules used to check if a generic job has succeeded. The job succeeded when any one of the successRules is fulfilled. Each item of successRules may refer to a series of replicas, and the job succeeded only if all of the replicas referred in this series are completed successfully.
failureRules FinishRule arrayRules used to check if a generic job has failed. The job failed when any one of failureRules is fulfilled. Each item of failureRules refers to a series of replicas, and the job failed only if all of the replicas in this series failed.
service ServiceOptionDetails of v1/Service for replica pods. Optional: Defaults to empty and no service will be created.
runMode RunModeJob running mode. Defaults to Immediate mode.
cleanUpPolicy CleanUpPolicyTo avoid wasting resources on completed tasks, controller will reclaim resource according to the following policies: None: (default) no resources reclamation; Unfinished: only finished pods is to be deleted; All: all the pods are to be deleted.
scheduler SchedulePolicyIf specified, the pod will be dispatched by the specified scheduler. Otherwise, the pod will be dispatched by the default scheduler.
replicaSpecs ReplicaSpec arrayList of replica specs belonging to the job. There must be at least one replica defined for a Job.

GenericJobStatus

GenericJobStatus defines the observed state of GenericJob

Appears in:

FieldDescription
tasks Tasks arrayAn array of status of individual tasks.
phase JobPhaseProvides a simple, high-level summary of where the Job is in its lifecycle. Note that this is NOT indended to be a comprehensive state machine.
aggregate AggregateRecords the number of replicas at each phase.
conditions JobCondition arrayThe latest available observations of a job’s current state.

JobCondition

JobCondition describes the current state of a job.

Appears in:

FieldDescription
type JobConditionTypeType of job condition: Complete or Failed.
status ConditionStatusStatus of the condition, one of True, False, Unknown.
lastTransitionTime TimeLast time the condition transited from one status to another.
reason stringBrief reason for the condition’s last transition.
message stringHuman readable message indicating details about last transition.

JobConditionType

Underlying type: string

JobConditionType defines all possible types of JobStatus. Can be one of: Initialized, Running, ReplicaFailure, Completed, or Failed.

Appears in:

JobPhase

Underlying type: string

Appears in:

PauseMode

PauseMode configs whether and how to start a job in pause mode.

Appears in:

FieldDescription
enabled booleanWhether to enable pause mode.
resumeSpecs ResumeSpec arrayIf provided, these specs provide overwriting values for job replicas when resuming.

ReplicaDebugSet

ReplicaDebugSet describes how to start replicas in debug mode.

Appears in:

FieldDescription
type stringReplica type.
skipInitContainer booleanSkips creation of initContainer, if true.
command stringEntrypoint array. Optional: Default to [“sleep”, “inf”]

ReplicaSpec

ReplicaSpec defines the desired state of replicas.

Appears in:

FieldDescription
type stringReplica type.
replicas integerThe desired number of replicas of this replica type. Defaults to 1.
restartPolicy RestartPolicyRestart policy for replicas of this replica type. One of Always, OnFailure, Never. Optional: Default to OnFailure.
template PodTemplateSpecDefines the template used to create pods.

ReplicaStatus

ReplicaStatus defines the observed state of the pod.

Appears in:

FieldDescription
name stringPod name.
uid UIDPod uid.
phase PodPhasePod phase. The phase of a Pod is a simple, high-level summary of where the Pod is in its lifecycle.
containers ContainerStatus arrayContainers status.

RestartPolicy

RestartPolicy describes how the replica should be restarted.

Appears in:

FieldDescription
policy RestartPolicyTypeThe policy to restart finished replica.
limit integerThe maximum number of restarts. Optional: Default to 0.

RestartPolicyType

Underlying type: string

Appears in:

ResumeSpec

ResumeSpec describes how to resume replicas from pause mode.

Appears in:

FieldDescription
type stringReplica type.
skipInitContainer booleanSkips creation of initContainer, if true.
command stringEntrypoint array. Provides overwriting values if provided; otherwise, values in immediate mode are used.
args stringArguments to the entrypoint. Arguments in immediate mode are used if not provided.

RunMode

RunMode defines the job’s execution behavior: Immediate mode: (Default) Tasks are executed immediately upon submission. Debug mode: Job pods are created, but regular executions are replaced with null operations (e.g., sleep) for convenient debugging purposes. Pause mode: Job execution is halted, and pods are deleted to reclaim resources. A graceful pod termination process is initiated to allow pods to exit cleanly.

Appears in:

FieldDescription
debug DebugModeDebug mode.
pause PauseModePause mode.

SchedulePolicy

SchedulePolicy signals to K8s how the job should be scheduled.

Appears in:

FieldDescription
t9kScheduler T9kSchedulerT9k Scheduler. TODO: link to t9k scheduler docs.

ServiceOption

Details of a replicas’ servivce.

Appears in:

FieldDescription
ports ServicePort arrayThe list of ports that are exposed by this service.

T9kScheduler

T9kScheduler provides additonal configurations needed for the scheduling process.

Appears in:

FieldDescription
queue stringSpecifies the name of the queue should be used for running this workload. TODO: link to t9k scheduler docs.
priority integerIndicates the priority of the PodGroup; valid range: [0, 100]. Optional: Default to 0.

Tasks

Task defines the observed state of the task.

Appears in:

FieldDescription
type stringReplica type.
restartCount integerThe number of restarts that have been performed.
replicas ReplicaStatus arrayReplicas status array.

API Reference

Packages

batch.tensorstack.dev/v1beta1

Package v1beta1 contains API Schema definitions for the batch v1beta1 API group

Resource Types

ReplicaSpec

ReplicaSpec describes the spec of a replica.

Appears in:

FieldDescription
type ReplicaTypeReplicaType is the type of the replica, one of “chief”, “worker”, “ps”, or “evaluator”.
replicas integerThe desired number of replicas created for the current replica type. If unspecified, defaults to 1.
template PodTemplateSpecDescribes the pod that will be created for this replica. Note that RestartPolicy in PodTemplateSpec will always be set to Never as the job controller will create new pods if restart is required.
restartPolicy RestartPolicyThe restart policy for this replica, one of Always, OnFailure, Never, or ExitCode.

ReplicaType

Underlying type: string

ReplicaType is the type of the replica, one of “chief”, “worker”, “ps”, or “evaluator”.

Appears in:

RestartPolicy

Underlying type: string

RestartPolicy describes how the replicas should be restarted. Can be one of: Always, OnFailure, Never, or ExitCode.

Appears in:

RunPolicy

RunPolicy encapsulates various runtime policies of the distributed training job, for example how to clean up resources and how long the job can stay active.

Appears in:

FieldDescription
activeDeadlineSeconds integerSpecifies the duration in seconds relative to the startTime that the job may be active before the system tries to terminate it; value must be positive integer.
backoffLimit integerOptional number of retries before marking this job failed.
cleanUpPolicy CleanUpPolicyClean the tasks after the training job finished.

TensorFlowTrainingJob

TensorFlowTrainingJob is the Schema for the TensorFlowTrainingJob API.

Appears in:

FieldDescription
apiVersion stringbatch.tensorstack.dev/v1beta1
kind stringTensorFlowTrainingJob
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec TensorFlowTrainingJobSpec
status TensorFlowTrainingJobStatus

TensorFlowTrainingJobList

TensorFlowTrainingJobList contains a list of TensorFlowTrainingJob

FieldDescription
apiVersion stringbatch.tensorstack.dev/v1beta1
kind stringTensorFlowTrainingJobList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items TensorFlowTrainingJob array

TensorFlowTrainingJobSpec

TensorFlowTrainingJobSpec outlines the intended configuration and execution parameters for a TensorFlowTrainingJob.

Appears in:

FieldDescription
replicaSpecs ReplicaSpec arrayDescribes the spec of the replicas of the job.
runMode RunModeJob’s execution behavior. If omitted, defaults to Immediate mode, and tasks are executed immediately upon submission.
tensorboardSpec TensorBoardSpecDescribes the Tensorboard to be created for showing training logs.
runPolicy RunPolicyExecution policy configurations governing the behavior of the TensorFlowTrainingJob.
scheduler SchedulePolicyIdentifies the preferred scheduler for allocating resources to replicas. Defaults to cluster default scheduler.

TensorFlowTrainingJobStatus

TensorFlowTrainingJobStatus defines the observed state of TensorFlowTrainingJob

Appears in:

FieldDescription
tasks Tasks arrayThe statuses of individual tasks.
tensorboard DependentStatusThe status of tensorboard.
backoffCount integerThe number of restarts being performed.
aggregate Aggregate
conditions JobCondition arrayRepresents the latest available observations of a TensorFlowTrainingJob’s current state.
phase JobPhasePhase is the phase-style status of the TensorFlowTrainingJob.

API Reference

Packages

batch.tensorstack.dev/v1beta1

Package v1beta1 contains API Schema definitions for the batch v1beta1 API group

Resource Types

ElasticConfig

Configuration governing the elastic scaling behavior of the job.

Appears in:

FieldDescription
enabled booleanSet true to use elastic training.
minReplicas integerThe minimum number of replicas to start to run this elastic compute. The autoscaler cannot scale down an elastic job below this number. This value cannnot be changed once the job is created.
maxReplicas integerThe maximum number of replicas to start to run this elastic compute. The autoscaler cannot scale up an elastic job over this number. This value cannnot be changed once the job is created.
expectedReplicas integerNumber of replicas to be created. This number can be set to an initial value upon creation. This value can be modified dynamically by an external entity, such as a user or an autoscaler, to scale the job up or down.

PyTorchTrainingJob

PyTorchTrainingJob is the Schema for the pytorchtrainingjobs API.

Appears in:

FieldDescription
apiVersion stringbatch.tensorstack.dev/v1beta1
kind stringPyTorchTrainingJob
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec PyTorchTrainingJobSpec
status PyTorchTrainingJobStatus

PyTorchTrainingJobList

PyTorchTrainingJobList contains a list of PyTorchTrainingJob

FieldDescription
apiVersion stringbatch.tensorstack.dev/v1beta1
kind stringPyTorchTrainingJobList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items PyTorchTrainingJob array

PyTorchTrainingJobSpec

PyTorchTrainingJobSpec outlines the intended configuration and execution parameters for a PyTorchTrainingJo.

Appears in:

FieldDescription
replicaSpecs ReplicaSpec arrayAn array of ReplicaSpec. Specifies the pytorch cluster configuration.
elastic ElasticConfigConfigurations for how to launch an elastic training. Elastic training is effective only in torchrun mode.
torchrunConfig TorchrunConfigWhether and how to use torchrun to launch a training process.
runMode RunModeJob’s execution behavior. If omitted, defaults to Immediate mode, and tasks are executed immediately upon submission.
runPolicy RunPolicyExecution policy configurations governing the behavior of a PytorchTrainingJob.
tensorboardSpec TensorBoardSpecIf specified, controller will create a Tensorboard for showing training logs.
scheduler SchedulePolicyIdentifies the preferred scheduler for allocating resources to replicas. Defaults to cluster default scheduler.

PyTorchTrainingJobStatus

PyTorchTrainingJobStatus defines the observed state of PyTorchTrainingJob.

Appears in:

FieldDescription
tasks Tasks arrayThe status details of individual tasks.
tensorboard DependentStatusThe status of the tensorboard.
backoffCount integerThe number of restarts having been performed.
aggregate AggregateThe number of tasks in each state.
conditions JobCondition arrayThe latest available observations of an object’s current state.
phase JobPhaseProvides a simple, high-level summary of where the Job is in its lifecycle. Note that this is NOT indended to be a comprehensive state machine.

ReplicaSpec

ReplicaSpec is a description of the job replica.

Appears in:

FieldDescription
type stringReplicaType is the type of the replica.
replicas integerThe desired number of replicas of the current template. Defaults to 1.
scalingWeight integerScaling weight of the current replica used in elastic training.
template PodTemplateSpecDescribes the pod that will be created for this replica. Note that RestartPolicy in PodTemplateSpec will always be set to Never as the job controller will decide if restarts are desired.
restartPolicy RestartPolicyRestart policy for all replicas within the job. One of Always, OnFailure, Never, or ExitCode.

TorchrunConfig

Describes how to launch pytorch training with torchrun.

Appears in:

FieldDescription
enabled booleanSet true to use torchrun launch pytorch training.
maxRestarts integer
procPerNode stringNumber of processes to be started on every replica.
rdzvBackend stringCommunication backed used for the group. Defaults to c10d.
extraOptions string arrayExtra options for torchrun.

API Reference

Packages

batch.tensorstack.dev/v1beta1

Package v1beta1 contains API Schema definitions for the batch v1beta1 API group

Resource Types

ReplicaSpec

ReplicaSpec outlines the intended configuration and execution parameters for a XGBoostTrainingJob.

Appears in:

FieldDescription
type ReplicaTypeReplicaType is the type of the replica, one of “master” or “worker”.
replicas integerThe desired number of replicas of the current template. If unspecified, defaults to 1.
template PodTemplateSpecDescribes the pod that will be created for this replica. Note that RestartPolicy in PodTemplateSpec will always be set to Never as the job controller will decide if restarts are desired.
restartPolicy RestartPolicyRestart policy for all replicas within the job. One of Always, OnFailure, Never, or ExitCode. Defaults to OnFailure.

ReplicaType

Underlying type: string

ReplicaType is the type of the replica, one of “master” or “worker”.

Appears in:

XGBoostTrainingJob

Appears in:

FieldDescription
apiVersion stringbatch.tensorstack.dev/v1beta1
kind stringXGBoostTrainingJob
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec XGBoostTrainingJobSpec
status XGBoostTrainingJobStatus

XGBoostTrainingJobList

XGBoostTrainingJobList contains a list of XGBoostTrainingJob.

FieldDescription
apiVersion stringbatch.tensorstack.dev/v1beta1
kind stringXGBoostTrainingJobList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items XGBoostTrainingJob array

XGBoostTrainingJobSpec

Appears in:

FieldDescription
replicaSpecs ReplicaSpec arrayAn array of ReplicaSpec. Specifies the XGBoost replica configurations.
runMode RunModeJob’s execution behavior. If omitted, defaults to Immediate mode, and tasks are executed immediately upon submission.
runPolicy RunPolicyExecution policy configurations governing the behavior of the XGBoostTrainingJob.
scheduler SchedulePolicyIdentifies the preferred scheduler for allocating resources to replicas. Defaults to cluster default scheduler.

XGBoostTrainingJobStatus

XGBoostTrainingJobStatus defines the observed state of XGBoostTrainingJob.

Appears in:

FieldDescription
tasks Tasks arrayThe status details of individual tasks.
backoffCount integerThe number of restarts being performed.
aggregate Aggregate
conditions JobCondition arrayThe latest available observations of an object’s current state.
phase JobPhaseProvides a simple, high-level summary of where the Job is in its lifecycle. Note that this is NOT indended to be a comprehensive state machine.

API Reference

Packages

batch.tensorstack.dev/v1beta1

Package v1beta1 contains API Schema definitions for the batch v1beta1 API group

Resource Types

ColossalAIJob

ColossalAIJob is the Schema for the colossalaijobs API

Appears in:

FieldDescription
apiVersion stringbatch.tensorstack.dev/v1beta1
kind stringColossalAIJob
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec ColossalAIJobSpec
status ColossalAIJobStatus

ColossalAIJobList

ColossalAIJobList contains a list of ColossalAIJob.

FieldDescription
apiVersion stringbatch.tensorstack.dev/v1beta1
kind stringColossalAIJobList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items ColossalAIJob array

ColossalAIJobSpec

ColossalAIJobSpec defines the configurations of a ColossalAI training job.

Appears in:

FieldDescription
ssh SSHConfigSSH configs.
runMode RunModeThe desired running mode of the job, defaults to Immediate.
runPolicy RunPolicyControls the handling of completed replicas and other related processes.
scheduler SchedulePolicySpecifies the scheduler to request for resources. Defaults to cluster default scheduler.
launcher LauncherSpecication for the launcher replica.
worker WorkerSpecication for the launcher replica.

ColossalAIJobStatus

ColossalAIJobStatus describes the observed state of ColossalAIJob.

Appears in:

FieldDescription
tasks Tasks arrayThe statuses of individual tasks.
aggregate AggregateThe number of replicas in each phase.
phase JobPhaseProvides a simple, high-level summary of where the Job is in its lifecycle. Note that this is NOT indended to be a comprehensive state machine.
conditions JobCondition arrayThe latest available observations of an object’s current state.

Launcher

Specification of replica launcher.

Appears in:

FieldDescription
image stringContainer image name.
workingDir stringWorking directory of container launcher. If not specified, the container runtime’s default will be used, which might be configured in the container image. Cannot be updated.
env EnvVar arrayList of environment variables set for the container. Cannot be updated.
resources ResourceRequirementsCompute Resources required by this container. Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/

RunPolicy

RunPolicy dictates specific actions to be taken by the controller upon job completion.

Appears in:

FieldDescription
cleanUpWorkers booleanDefaults to false.

SSHConfig

SSHConfig specifies various configurations for running the SSH daemon (sshd).

Appears in:

FieldDescription
authMountPath stringSSHAuthMountPath is the directory where SSH keys are mounted. Defaults to “/root/.ssh”.
sshdPath stringThe location of the sshd executable file.

Worker

Specification of the worker replicas.

Appears in:

FieldDescription
replicas integerNumber of replicas to launch. Defaults to 1.
procPerWorker integerThe number of processes of a worker. Defaults to 1.
command string arraySpecifies the command used to start the workers.
torchArgs string arrayArgs of torchrun.
template PodTemplateSpecTemplate defines the workers that will be created from this pod template.

API Reference

Packages

batch.tensorstack.dev/v1beta1

Package v1beta1 contains API Schema definitions for the batch v1beta1 API group

Resource Types

Config

Configuration information for running a DeepSpeed job. Details are outlined in the official DeepSpeed documentation (https://www.deepspeed.ai/getting-started/) for comprehensive guidance.

Appears in:

FieldDescription
customCommand stringCustom launch commands, when enabled, other options in Config except for slotsPerWorker will not take effect.
slotsPerWorker integerThe number of slots for each worker/replica. This is normally set to the number of GPUs requested for each replica.
localRank booleanIf parameter local_rank should be passed to training programs.
autotune AutotuneTypeParameters for running the autotuning process to find configurations for a training job on a particular cluster/machine.
run RunTypeMechanism to start the training program.
otherArgs string arraySeting up other command line args for the deepspeed job.

DeepSpeedJob

DeepSpeedJob defines the schema for the DeepSpeedJob API.

Appears in:

FieldDescription
apiVersion stringbatch.tensorstack.dev/v1beta1
kind stringDeepSpeedJob
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec DeepSpeedJobSpec
status DeepSpeedJobStatus

DeepSpeedJobList

DeepSpeedJobList contains a list of DeepSpeedJob

FieldDescription
apiVersion stringbatch.tensorstack.dev/v1beta1
kind stringDeepSpeedJobList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items DeepSpeedJob array

DeepSpeedJobSpec

DeepSpeedJobSpec outlines the intended configuration and execution parameters for a DeepSpeedJob.

Appears in:

FieldDescription
scheduler SchedulePolicyIdentifies the preferred scheduler for allocating resources to replicas. Defaults to cluster default scheduler.
runPolicy RunPolicyExecution policy configurations governing the behavior of the distributed training job.
runMode RunModeJob’s execution behavior. If omitted, defaults to Immediate mode, and tasks are executed immediately upon submission.
elastic ElasticConfigConfigurations for how to launch an elastic training.
config ConfigKey configurations for executing DeepSpeed training jobs.
disableCustomEnv booleanSetting environment variables during DeepSpeed training necessitates creating an env file to store the desired variables. The launcher will then distribute these variables to each worker process. Nevertheless, certain scenarios require disabling this automated behavior, and this flag enables control over this functionality.
false: (default) The environment variables set in job specs are used in the training processes. The controller will automatically put the environment variables into the env file so that the launcher can send them to each worker;
true: The environment variables set in the job specs are only used to start the container entrypoint program, and the training program does not need these environment variables.
worker WorkerSpecifications for the worker replicas.

DeepSpeedJobStatus

DeepSpeedJobStatus represents the observed state of a DeepSpeedJob.

Appears in:

FieldDescription
tasks Tasks array
aggregate Aggregate
phase JobPhaseProvides a simple, high-level summary of where the Job is in its lifecycle. Note that this is NOT indended to be a comprehensive state machine.
backoffCount integerThe number of restarts being performed.
conditions JobCondition arrayThe latest available observations of an object’s current state.

ElasticConfig

Configuration governing the elastic scaling behavior of the job.

Appears in:

FieldDescription
enabled booleanSet true to use elastic training.
minReplicas integerThe minimum number of replicas to start to run this elastic compute. The autoscaler cannot scale down an elastic job below this number. This value cannnot be changed once the job is created.
maxReplicas integerThe maximum number of replicas to start to run this elastic compute. The autoscaler cannot scale up an elastic job over this number. This value cannnot be changed once the job is created.
expectedReplicas integerNumber of replicas to be created. This number can be set to an initial value upon creation. This value can be modified dynamically by an external entity, such as a user or an autoscaler, to scale the job up or down.

RunPolicy

RunPolicy encapsulates various runtime policies of the distributed training job, for example how to clean up resources and how long the job can stay active.

Appears in:

FieldDescription
activeDeadlineSeconds integerSpecifies the duration in seconds relative to the startTime that the job may be active before the system tries to terminate it; value must be positive integer.
backoffLimit integerOptional number of retries before marking this job failed.
cleanUpPolicy CleanUpPolicyClean the tasks after the training job finished.

RunType

How the training program should be started. Exactly one of the 3 choices should be set.

Appears in:

FieldDescription
python string arrayUsing a python script
module string arrayUsing a python module
exec string arrayUsing an executable program

Worker

Worker defines the configurations for DeepSpeedJob worker replicas.

Appears in:

FieldDescription
replicas integerThe number of workers to launch.
template PodTemplateSpecDescribes the pod that will be created for this replica. Note that RestartPolicy in PodTemplateSpec will always be set to Never as the job controller will decide if restarts are desired.
restartPolicy RestartPolicyRestart policy for all replicas owned by the job. One of Always, OnFailure, Never, or ExitCode. Defaults to OnFailure.

API Reference

Packages

batch.tensorstack.dev/v1beta1

Package v1beta1 contains API Schema definitions for the batch v1beta1 API group

Resource Types

MPIJob

MPIJob is the Schema for the mpijobs API

Appears in:

FieldDescription
apiVersion stringbatch.tensorstack.dev/v1beta1
kind stringMPIJob
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec MPIJobSpec
status MPIJobStatus

MPIJobList

MPIJobList contains a list of MPIJob

FieldDescription
apiVersion stringbatch.tensorstack.dev/v1beta1
kind stringMPIJobList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items MPIJob array

MPIJobSpec

MPIJobSpec outlines the intended configuration and execution parameters for a MPIJob.

Appears in:

FieldDescription
worker WorkerConfigSpecifications for the worker replicas.
mca object (keys:string, values:string)Open MPI uses Modular Component Architecture (MCA) parameters to provide a way to tune your runtime environment.
ssh SSHConfigSSH configs.
runPolicy RunPolicyExecution policy configurations governing the behavior of the MPI job.
runMode RunModeJob’s execution behavior. If omitted, defaults to Immediate mode, and tasks are executed immediately upon submission.
mpiHome stringOpen MPI installation path.
scheduler SchedulePolicyIdentifies the preferred scheduler for allocating resources to replicas. Defaults to cluster default scheduler. Use k8s default scheduler by default.

MPIJobStatus

MPIJobStatus represents the observed state of a MPIJob.

Appears in:

FieldDescription
tasks Tasks arrayIndividual task status details of the job.
aggregate Aggregate
phase JobPhaseProvides a simple, high-level summary of where the Job is in its lifecycle. Note that this is NOT indended to be a comprehensive state machine.
conditions JobCondition arrayThe latest available observations of an object’s current state.

RunPolicy

RunPolicy encapsulates various runtime policies of the MPI job, for example how to clean up resources.

Appears in:

FieldDescription
cleanUpWorkers booleanIf worker replicas should be cleand up after they finish. Defaults false.

SSHConfig

SSHConfig specifies various configurations for running the SSH daemon (sshd).

Appears in:

FieldDescription
sshAuthMountPath stringSSHAuthMountPath is the directory where SSH keys are mounted. Defaults to “/root/.ssh”.
sshdPath string

WorkerConfig

WorkerConfig defines the configurations for MPI worker replicas.

Appears in:

FieldDescription
replicas integerThe number of workers to launch. Default 1.
extraMPIArgs string arrayExtra args for mpirun.
cmd string arrayCommand line to start the MPI programs inside a worker pod. This is invoked by the launcher after all the worker pods have been created and entered ready state.
template PodTemplateSpecDefines the pod template used to create workers. Users are responsible for ensuring that container images and configurations are properly set to guarantee the worker operates in the state anticipated by the launcher.

API Reference

Packages

batch.tensorstack.dev/v1beta1

Package v1beta1 contains API Schema definitions for the batch v1beta1 API group

Resource Types

BeamJob

BeamJob is the Schema for the beamjobs API

Appears in:

FieldDescription
apiVersion stringbatch.tensorstack.dev/v1beta1
kind stringBeamJob
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec BeamJobSpec
status BeamJobStatus

BeamJobList

BeamJobList contains a list of BeamJob

FieldDescription
apiVersion stringbatch.tensorstack.dev/v1beta1
kind stringBeamJobList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items BeamJob array

BeamJobSpec

BeamJobSpec defines the desired state of BeamJob

Appears in:

FieldDescription
flinkClusterTemplate FlinkClusterTemplateSpecSpecifies the FlinkCluster that will be created when executing a BeamJob.
jobTemplate JobTemplateSpecSpecifies the Job that will be created when executing a BeamJob.
runPolicy RunPolicyRuntime policies governing the behavior of the BeamJob.
scheduler SchedulePolicyIdentifies the preferred scheduler for allocating resources to replicas. Defaults to cluster default scheduler.
runMode RunModeNormal mode and debug mode are supported now.

BeamJobStatus

BeamJobStatus defines the observed state of BeamJob

Appears in:

FieldDescription
phase JobPhasePhase is a label for the condition of the job at the current time.
conditions JobCondition arrayThe latest available observations of the BeamJob’s current state.
tasks Tasks arrayThe statuses of individual tasks.
aggregate Aggregate
jobURL stringThe URL to Web UI of the cluster where details of the job is displayed.

FlinkClusterTemplateSpec

FlinkClusterTemplateSpec describes the data a FlinkCluster should have when created from a template

Appears in:

FieldDescription
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec FlinkClusterSpecSpecification of the desired behavior of the FlinkCluster.

RunPolicy

RunPolicy encapsulates runtime policies governing the behavior of the BeamJob.

Appears in:

FieldDescription
cleanUpCluster booleanWhether or not delete cluster after the job finished. Default false.

API Reference

Packages

tensorstack.dev/v1beta1

Package v1beta1 contains API Schema definitions for the v1beta1 API group

Resource Types

HttpDataSource

Details of HTTP data source.

Appears in:

FieldDescription
url string arrayUrl pointing to the log files.

PVCDataSource

Details of PVC data source.

Appears in:

FieldDescription
name stringPVC name.
subPath string arrayThe relative paths of logs in the PVC.

PodReference

PodReference references to a v1.pod.

Appears in:

FieldDescription
name stringName of the Pod.
uid stringUID of the Pod.

PodStatus

Pod defines the observed state of a replica.

Appears in:

FieldDescription
reference PodReferenceReferences to the subordinate v1.Pod.
phase PodPhaseReplicated from the corresponding field in the subordinate v1.Pod.

S3DataSource

Details of S3 data source.

Appears in:

FieldDescription
secretRef SecretRefS3 data source uses a secret to transmit access/secret key and service enpoint.
uri string arrayS3 object uri.

SchedulePolicy

SchedulePolicy specifies the preferred scheduler responsible for handling resource allocation requests.

Appears in:

FieldDescription
t9kScheduler T9kScheduler

SecretRef

Appears in:

FieldDescription
name stringSecret name.

T9kScheduler

Appears in:

FieldDescription
queue stringName of the queue to use with the T9kScheduler.

TensorBoard

TensorBoard is the Schema for the tensorboards API

Appears in:

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringTensorBoard
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec TensorBoardSpec
status TensorBoardStatus

TensorBoardCondition

TensorBoardCondition defines the observed condition of TensorBoard

Appears in:

FieldDescription
type TensorBoardConditionTypeType is the type of the condition. Possible values are Idle, etc
status ConditionStatusStatus is the status of the condition type. Possible values of type Idle are True
message stringMessage is the reason of the status
lastTransitionTime TimeLastTransitionTime is the last time the status was changed
lastProbeTime TimeLastProbeTime is the last time the condition was probed

TensorBoardConditionType

Underlying type: string

Appears in:

TensorBoardDataSource

TensorBoardDataSource represents the location and type of the tensorboard data source. It includes three types of data sources: PVC, S3, and HTTP. In a tensorboard service, these three types of data sources can be used simultaneously.

Appears in:

FieldDescription
pvc PVCDataSource arrayPVC represents PVCs that are mounted to workload as directories to provide log data.
s3 S3DataSourceS3 represents a s3 service and access/secret key to access the service.
http HttpDataSourceHTTP provides several urls.

TensorBoardList

TensorBoardList contains a list of TensorBoard

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringTensorBoardList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items TensorBoard array

TensorBoardPhase

Underlying type: string

Appears in:

TensorBoardSpec

TensorBoardSpec defines the desired state of TensorBoard

Appears in:

FieldDescription
trainingLogFilesets string arrayTrainingLogFilesets is the list of filesets containing training log. The format of fileset: t9k://pvc/[pvc-name]/[subpath] t9k://minio/[secret-name]/[bucket]/[subpath] To be deprecated: Use spec.logDir instead.
logDir TensorBoardDataSourceLogDir is a series of data source containing training log.
image stringThe container image used to run the tensorboard.
suspend booleansuspend specifies whether the TensorBoard controller should delete Pods or not. If true, the associated v1.Pod can be terminated. However, other API resources, such as ConfigMaps and Services, will be preserved for use upon resuming the TensorBoard. Defaults to false.
scheduler SchedulePolicy
resources ResourceRequirementsCompute Resources required by this container. Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/

TensorBoardStatus

TensorBoardStatus defines the observed state of TensorBoard

Appears in:

FieldDescription
phase TensorBoardPhase
pod PodStatus
conditions TensorBoardCondition arrayConditions is an array of current conditions
url stringThe URL to Web UI of the tensorboard

API Reference

Packages

tensorstack.dev/v1beta1

Package v1beta1 contains API Schema definitions for the v1beta1 API group

Resource Types

Notebook

Notebook is the Schema for the notebooks API

Appears in:

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringNotebook
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec NotebookSpec
status NotebookStatus

NotebookCondition

NotebookCondition defines the observed condition of notebook

Appears in:

FieldDescription
type NotebookConditionTypeType is the type of the condition. Possible values are Idle, etc
status ConditionStatusStatus is the status of the condition type. Possible values of type Idle are `True
message stringMessage is a human-readable message for the reason of the status.
lastTransitionTime TimeLastTransitionTime is the last time the status was changed.
lastProbeTime TimeLastProbeTime is the last time the condition was probed.

NotebookConditionType

Underlying type: string

Appears in:

NotebookList

NotebookList contains a list of Notebook

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringNotebookList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items Notebook array

NotebookPhase

Underlying type: string

Appears in:

NotebookSSHSpec

NotebookSSHSpec defines the ssh template spec of Notebook

Appears in:

FieldDescription
enabled booleanIf true, SSH service will be started for this Notebook instance.
serviceType ServiceType
authorized_keys string arrayA list of names of v1.Secret containing SSH public keys authorized for access to this SSH service.

NotebookSSHStatus

NotebookSSHStatus defines the observed state of the SSH service associated with the Notebook.

Appears in:

FieldDescription
serviceName stringThe v1.Service name of the SSH service.
port integerThe port number of the SSH server daemon.
clusterIp string
nodePort integer
protocol Protocol
lastSshClientActivity TimeLastSshClientActivity is the last time an SSH client is active.

NotebookSpec

NotebookSpec defines the desired state of a Notebook.

Appears in:

FieldDescription
template NotebookTemplateSpec
scheduler SchedulePolicy
ssh NotebookSSHSpec
type NotebookType
suspend booleansuspend specifies whether the Notebook controller should delete Pods or not. If true, the associated v1.Pod can be terminated. However, other API resources, such as ConfigMaps and Services, will be preserved for use upon resuming the notebook. Defaults to false.

NotebookStatus

NotebookStatus defines the observed state of a Notebook.

Appears in:

FieldDescription
phase NotebookPhase
pod PodStatus
ssh NotebookSSHStatus
conditions NotebookCondition arrayConditions is an array of current conditions
url stringThe URL to Web UI of the notebook

NotebookTemplateSpec

NotebookTemplateSpec defines the pod template to run a Notebook.

Appears in:

FieldDescription
spec PodSpec

NotebookType

Underlying type: string

Appears in:

PodReference

PodReference references a K8s v1.Pod.

Appears in:

FieldDescription
name stringName of the Pod.
uid stringUID of the Pod.

PodStatus

Pod defines the observed state of the Pod running the notebook.

Appears in:

FieldDescription
reference PodReferenceReferences to the subordinate v1.Pod.
phase PodPhaseReplicated from the corresponding field in the subordinate v1.Pod.

SchedulePolicy

SchedulePolicy specifies the preferred scheduler responsible for handling resource allocation requests.

Appears in:

FieldDescription
t9kScheduler T9kScheduler

T9kScheduler

Appears in:

FieldDescription
queue stringName of the queue to use with the T9kScheduler.

API Reference

Packages

tensorstack.dev/v1beta1

Package v1beta1 contains API Schema definitions for the v1beta1 API group

Resource Types

AIStoreConfig

AIStoreConfig represents the configuration for using AIStore as a data storage for experiments.

Appears in:

FieldDescription
secret stringSecret specifies the secret containing the API Key authorized to upload data to AIStore.
folder stringFolder indicates the destination folder where the experiment data will be stored.

AdvisorConfig

AdvisorConfig represents the configuration for the advisor algorithm and its parameters.

Appears in:

FieldDescription
builtinAdvisorName stringBuiltInAdvisorName specifies the name of the built-in advisor algorithm to be used. Available options include: Hyperband, BOHB.
classArgs stringClassArgs defines the parameters specific to the chosen advisor algorithm. Different algorithms may require distinct parameters.

AssessorConfig

AssessorConfig represents the configuration for the assessor algorithm and its parameters.

Appears in:

FieldDescription
builtinAssessorName stringBuiltInAssessorName specifies the name of the built-in assessor algorithm to be used. Available options include: Medianstop, Curvefitting.
classArgs stringClassArgs defines the parameters specific to the chosen assessor algorithm. Different algorithms may require distinct parameters.

AutoTuneExperiment

AutoTuneExperiment is the Schema for the autotune API.

Appears in:

FieldDescription
apiVersion stringtensorstack.dev/apis
kind stringAutoTuneExperiment
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec AutoTuneExperimentSpec
status AutoTuneExperimentStatus

AutoTuneExperimentList

AutoTuneExperimentList contains a list of AutoTuneExperiment.

FieldDescription
apiVersion stringtensorstack.dev/apis
kind stringAutoTuneExperimentList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items AutoTuneExperiment array

AutoTuneExperimentSpec

AutoTuneExperimentSpec defines the desired state of the AutoTuneExperiment.

Appears in:

FieldDescription
aistore AIStoreConfigAIStore configures an AIStore as storage for experiment data. If this field is set, data will be uploaded to the AIStore.
maxExecSeconds integerMaxExecSeconds is the time limit (in seconds) for the AutoTuneExperiment, If this limit is exceeded, the AutoTuneExperiment reaches phase TIMEOUT.
maxTrialNum integerMaxTrialNum specifies the maximum number of trials for the AutoTuneExperiment. Once this number of trials is reached, the AutoTuneExperiment reaches phase DONE.
trialConcurrency integerTrialConcurrency is the maximum number of trials running simultaneously.
searchSpace stringSearchSpace defines the hyperparameter search space as a JSON string. It specifies the range for searching optimized hyperparameters. Example: { “batch_size”: {“_type”: “choice”, “_value”: [16, 32, 64, 128]}, “learning_rate”: {“_type”: “choice”, “_value”: [0.0001, 0.001, 0.01, 0.1]}, “conv_channels1”: {“_type”: “choice”, “_value”: [16, 32, 64, 128]} }
storage QuantityStorage specifies the size of PVC for storing configurations and training metrics.
trainingConfig TrainingConfigTrainingConfig represents the configuration for creating Jobs, which evaluate the performance of different hyperparameters.
tuner TunerConfigTuner configures a tuner for optimizing hyperparameter.
assessor AssessorConfigAssessor configures an assessor for filtering hyperparameters and interrupting training when hyperparameters are deemed unqualified. Note that this field is ignored if Tuner is not set.
advisor AdvisorConfigAdvisor configures an advisor for optimizing hyperparameter. Note that when both Tuner and Advisor are set, Tuner takes precedence.

AutoTuneExperimentStatus

AutoTuneExperimentStatus defines the observed state of the AutoTuneExperiment.

Appears in:

FieldDescription
OwnerStatus OwnerStatus
nextCheckedTime TimeNextCheckedTime indicates the scheduled time for the next status check of the experiment process by the controller.
phase ExperimentStatusPhase provides a simple, high-level summary of where the AutoTuneExperiment is in its lifecycle. Note that it is NOT intended to serve as a comprehensive state machine. This field is optional.
serverNote stringServerNote contains the current status of the experiment process.

ExperimentStatus

Underlying type: string

Appears in:

TunerConfig

TunerConfig represents the configuration for the tuner algorithm and its parameters.

Appears in:

FieldDescription
builtinTunerName stringBuiltInTunerName specifies the name of the built-in tuner algorithm to be used. Available options include: Random, Anneal, TPE, Evolution, Batch, GridSearch, MetisTuner, GPTuner, PPOTuner, PBTTuner.
classArgs stringClassArgs defines the parameters specific to the chosen tuner algorithm. Different algorithms may require distinct parameters.

API Reference

Packages

tensorstack.dev/v1beta1

Package v1beta1 contains API Schema definitions for the v1beta1 API group

Resource Types

Explorer

Explorer is the Schema for the explorers API

Appears in:

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringExplorer
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec ExplorerSpec
status ExplorerStatus

ExplorerCondition

ExplorerCondition defines the observed condition of Explorer resource

Appears in:

FieldDescription
type ExplorerConditionTypeType is the type of the condition. Possible values are Idle, etc
status ConditionStatusStatus is the status of the condition type. Possible values of type Idle are True
message stringMessage is the reason of the status
lastTransitionTime TimeLastTransitionTime is the last time the status was changed
lastProbeTime TimeLastProbeTime is the last time the condition was probed

ExplorerConditionType

Underlying type: string

Appears in:

ExplorerList

ExplorerList contains a list of Explorer

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringExplorerList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items Explorer array

ExplorerSpec

ExplorerSpec defines the desired state of Explorer

Appears in:

FieldDescription
storageType StorageTypeType of storage, only pvc is supported for now.
storageName stringName of the StorageType instance.
suspend booleansuspend specifies whether the Explorer controller should delete Pods or not. If true, the associated v1.Pod can be terminated. However, other API resources, such as ConfigMaps and Services, will be preserved for use upon resuming the Explorer. Defaults to false.
scheduler SchedulePolicy

ExplorerStatus

ExplorerStatus defines the observed state of Explorer

Appears in:

FieldDescription
conditions ExplorerCondition arrayConditions is an array of current conditions
codeServer ResourceStatus
fileBrowser ResourceStatus

PodReference

PodReference refers to a replica.

Appears in:

FieldDescription
name stringName of the Pod.
uid stringUID of the Pod.

PodStatus

Pod defines the observed state of a replica.

Appears in:

FieldDescription
reference PodReferenceReferences to the subordinate v1.Pod.
phase PodPhaseReplicated from the corresponding field in the subordinate v1.Pod.

ResourcePhase

Underlying type: string

Appears in:

ResourceStatus

Appears in:

FieldDescription
phase ResourcePhase
pod PodStatus

SchedulePolicy

SchedulePolicy specifies preferences for resource allocation requests, including the name of the preferred scheduler and additional configuration parameters.

Appears in:

FieldDescription
t9kScheduler T9kScheduler

StorageType

Underlying type: string

StorageType is the type of storage volume.

Appears in:

T9kScheduler

Appears in:

FieldDescription
queue stringName of the resource Queue of a T9kScheduler.

API Reference

Packages

tensorstack.dev/v1beta1

Package v1beta1 contains API Schema definitions for the v1beta1 API group

Resource Types

S3Config

S3Config defines the config of s3

Appears in:

FieldDescription
uri string

SecretReference

SecretReference defines a Secret Reference

Appears in:

FieldDescription
name string

StorageShim

StorageShim is the Schema for the storageshims API

Appears in:

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringStorageShim
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec StorageShimSpec
status StorageShimStatus

StorageShimCondition

StorageShimCondition contains details for the current condition of this StorageShim

Appears in:

FieldDescription
type StorageShimConditionTypeType is the type of the condition
status ConditionStatusStatus is the status of the condition. Can be True, False, Unknown.
message stringHuman-readable message indicating details about last transition.
lastTransitionTime TimeLast time the condition transitioned from one status to another.

StorageShimConditionType

Underlying type: string

StorageShimConditionType is a valid value for StorageShimCondition.Type

Appears in:

StorageShimList

StorageShimList contains a list of StorageShim

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringStorageShimList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items StorageShim array

StorageShimSpec

StorageShimSpec defines the desired state of StorageShim

Appears in:

FieldDescription
s3 S3ConfigS3 defines the config of s3, such as uri
readOnly booleanSpecifies a read-only configuration. Defaults to false.
secretRef SecretReferenceSpecifies a secret reference, must be in the same namespace of this StorageShim currently

StorageShimStatus

StorageShimStatus defines the observed state of StorageShim

Appears in:

FieldDescription
phase PersistentVolumeClaimPhaseThe phase of this StorageShim
conditions StorageShimCondition arrayConditions is an array of current conditions

tensorstack.dev/v1beta2

Package v1beta2 contains API Schema definitions for the v1beta2 API group

Resource Types

CephFSClient

CephFSClient defines the client configurations to connnect to the cephfs server.

Appears in:

FieldDescription
secretRef SecretReferenceSecretRef references a Kubernetes v1.Secret object that securely stores the CephFS client configurations.

CephFSConfig

CephFSConfig defines configuration details for a cephfs storage system.

Appears in:

FieldDescription
path stringPath specifies the absolute path within a CephFS volume to be mounted. It should be a valid directory path within the mounted volume. For example, /path/to/directory.
server CephFSServerServer provides the configuration details for the CephFS cluster. This includes information such as the Ceph monitor IP addresses and the CephFS volume name.
client CephFSClientClient defines the details of a cephFS client.

CephFSServer

CephFSServer defines the configuration details for the CephFS cluster.

Appears in:

FieldDescription
configMapRef ConfigMapReferenceConfigMapRef defines a reference to a K8s v1/configmap that stores CephFS cluster details such as the Ceph monitor IP addresses and the CephFS volume name.

ConfigMapReference

ConfigMapReference defines a Kubernetes v1.ConfigMap reference.

Appears in:

FieldDescription
name stringName of the configmap.
namespace stringNamespace where the configmap resides in.

S3Config

S3Config defines the configuration details for an S3 object storage service.

Appears in:

FieldDescription
readOnly booleanSpecifies that this S3 service can only be used as read-only. Defaults to false.
uri stringThe S3 prefix to mount, specified as s3://<bucket>[/path].
secretRef SecretReferenceReferences a Kubernetes v1.Secret object. The referenced Secret must reside in the same namespace as the referencing StorageShim.

SecretReference

SecretReference defines a reference to a Kubernetes v1.Secret object.

Appears in:

FieldDescription
name stringThe name of a Kubernetes v1.Secret object that holds the CephFS client configurations. This Secret must reside within the same namespace as the referencing StorageShim.

StorageShim

StorageShim is the Schema for the storageshims API

Appears in:

FieldDescription
apiVersion stringtensorstack.dev/v1beta2
kind stringStorageShim
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec StorageShimSpec
status StorageShimStatus

StorageShimCondition

StorageShimCondition contains details for the current condition of this StorageShim

Appears in:

FieldDescription
type StorageShimConditionTypeType is the type of the condition
status ConditionStatusStatus is the status of the condition. Can be True, False, Unknown.
message stringHuman-readable message indicating details about last transition.
lastTransitionTime TimeLast time the condition transitioned from one status to another.

StorageShimConditionType

Underlying type: string

StorageShimConditionType is a valid value for StorageShimCondition.Type

Appears in:

StorageShimList

StorageShimList contains a list of StorageShim

FieldDescription
apiVersion stringtensorstack.dev/v1beta2
kind stringStorageShimList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items StorageShim array

StorageShimSpec

StorageShimSpec defines the desired state of StorageShim

Appears in:

FieldDescription
type StorageShimTypeType specifies the type of storage system to be integrated with. One of the supported values is required, and currently cephfs, s3 are supported. More storage system types will be added in the future.
s3 S3ConfigS3 defines the configuration details for an s3 object store service.
cephfs CephFSConfigCephFS defines the configuraitons for a cephfs.

StorageShimStatus

StorageShimStatus defines the observed state of StorageShim

Appears in:

FieldDescription
phase PersistentVolumeClaimPhaseThe phase of this StorageShim.
conditions StorageShimCondition arrayConditions represent an array of current conditions observed within the system.

StorageShimType

Underlying type: string

Appears in:

API Reference

Packages

scheduler.tensorstack.dev/v1beta1

Package v1beta1 is the v1beta1 version of the API.

Resource Types

PodGroup

PodGroup represents a collection of Pods to be scheduled together to facilicate with parallel computing. PodGroup is usually automatically created by workload controllers to manage parallel batch workloads such as machine learning training and to enable coscheduling/gang-scheduling strategies. Users can also manually create a PodGroup and associates Pods with it if desired.

Appears in:

FieldDescription
apiVersion stringscheduler.tensorstack.dev/v1beta1
kind stringPodGroup
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec PodGroupSpecSpecification of the desired behavior of the pod group. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
status PodGroupStatusStatus represents the current status of a pod group. This data may not be up to date.

PodGroupCondition

PodGroupCondition contains details for the current state of this pod group.

Appears in:

FieldDescription
type PodGroupConditionTypeThe type of the condition.
status ConditionStatusThe status of the condition.
transitionID stringThe ID of condition transition.
lastTransitionTime TimeLast time of condition transition(s).
reason stringUnique, one-word, CamelCase, machine-readable reason for the condition’s last change.
message stringHuman-readable message indicating details about last change.

PodGroupInQueueStatus

Appears in:

FieldDescription
total integer

PodGroupList

PodGroupList is a collection of pod groups.

FieldDescription
apiVersion stringscheduler.tensorstack.dev/v1beta1
kind stringPodGroupList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items PodGroup arrayThe list of PodGroup.

PodGroupSpec

PodGroupSpec represents the desired specification of a pod group.

Appears in:

FieldDescription
roles Role array
minMember integerMinMember defines the minimal number of pods to run the PodGroup. If there less than minMember of pods joining the PodGroup, none of the existing pods in the group will be scheduled. After minMember of pods joined, the scheduler will only schedule them if there are sufficient resources to allow minMember of pods start together.
queue stringQueue defines the queue from which resources for pods of the PodGroup should be allocated. If queue is not specified, the PodGroup will be scheduled to queue “default”.
priority integerIf specified, indicates the PodGroup’s priority; groups with larger priority values will be considered for scheduling first; range is [0,100].
topologyPolicy TopologyPolicyTypeTopologyPolicy declares the topology policy PodGroup needs.

PodGroupStatus

PodGroupStatus represents the current state of a pod group.

Appears in:

FieldDescription
conditions PodGroupCondition arrayThe conditions of PodGroup.
allocated object (keys:ResourceName, values:Quantity)Allocated represents resources and their qunatities allocated to the PodGroup.
pending integerThe number of pods in phase Pending.
running integerThe number of pods in phase running.
succeeded integerThe number of pods in phase Succeeded.
failed integerThe number of pods in phase Failed.
unknown integerThe number of pods in phase Unknown.

PodInQueueStatus

Appears in:

FieldDescription
pending integerThe number of ‘Pending’ Pods in this queue.
running integerThe number of ‘Running’ Pods in this queue.
succeeded integerThe number of ‘Succeeded’ Pods in this queue.
failed integerThe number of ‘Failed’ Pods in this queue
unknown integerThe number of ‘Unknown’ Pods in this queue.

Queue

Queue is an API-resource to reprenent a sub-set of cluster compute resources and associated administrative policies, such as allowed users, resource quota, allowed workload types, max duration of workload runtime and etc.

Appears in:

FieldDescription
apiVersion stringscheduler.tensorstack.dev/v1beta1
kind stringQueue
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec QueueSpecSpecification of the desired behavior of the queue. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
status QueueStatusThe status of queue.

QueueCondition

Appears in:

FieldDescription
type QueueConditionTypeType is the type of the condition. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions
status ConditionStatusStatus is the status of the condition. Can be True, False, Unknown. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions
lastTransitionTime TimeLast time the condition transitioned.
reason stringUnique, one-word, CamelCase reason for the condition’s last transition.
message stringHuman-readable message indicating details about last transition.

QueueConditionType

Underlying type: string

Appears in:

QueueList

QueueList is a collection of queues.

FieldDescription
apiVersion stringscheduler.tensorstack.dev/v1beta1
kind stringQueueList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items Queue arrayThe list of Queue.

QueueSpec

QueueSpec represents the desired specification of a Queue.

Appears in:

FieldDescription
quota QuotaRequirements
priority integerIf specified, indicates the Queue’s priority. range is [0,100] The higher value of priority, workloads in this queue will be scheduled with resources with higher preferences.
preemptible booleanPreemptible indicate whether the queue can be preempted by other queue when cluster resources are in short. Queue can be preempted if Preemptible is not set.
closed booleanAfter queue is closed, new workloads (pods) will not be allocated with resources and no new workloads will be accepted either.
maxDuration DurationDefine the max lifetime of Pod using the Queue. Supported units: y, w, d, h, m, s, ms. Examples: 30s, 1m, 1h20m15s, 15d.
resourceShapeProfile stringSpecify ResourceShape profile used by the Queue.
nodeSelector LabelSelectorNodeSelector specifies the nodes whoses resource can be used by a Queue. This provides a machanism to restrict workloads submitted to a particular queue to a sub-set of nodes in the cluster. if nil, all nodes are eligible.
namespaceSelector LabelSelectorNamespaceSelector specifies the set of namespaces from which workloads are allowed to use this Queue. if nil, no namespaces are selected. Note: There may be other authorization procedures that permit workloads in a queue. They are OR’ed with this selector.

QueueStatus

QueueStatus represents the status of Queue.

Appears in:

FieldDescription
allocated object (keys:ResourceName, values:Quantity)Count of resource allocated to the queue.
conditions QueueCondition arrayCurrent service state of Queue.
podGroups PodGroupInQueueStatusPodGroup Status in Queue.
pods PodInQueueStatusPod Status in Queue.

QuotaRequirements

Appears in:

FieldDescription
requests object (keys:ResourceName, values:Quantity)Requests describes max amount of resources pods in the Queue can potentially request. However, these are the upper limits for resources, not necessarily always available for use. This can be used by cluster administrators to control the upper bounds of resources submitted to a particular queue. Togethe with allowed users of queues, this provides a mechanism for admins to set policies to constrain some aspects of user resource usages.

Role

Role describes pod’s role and minMember constraint for this role.

Appears in:

FieldDescription
name stringRole Name
minMember integerMinMember defines minimal number of pods of the role.

API Reference

Packages

batch.tensorstack.dev/v1beta1

Package v1beta1 defines the CRD types.

Resource Types

BeamJobWorkflowTemplate

BeamJobWorkflowTemplate creates a t9k beam job.

Appears in:

FieldDescription
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec BeamJobSpecSpec of the beam job.

ColossalAIJobWorkflowTemplate

ColossalAIJobWorkflowTemplate creates a t9k colossalai job.

Appears in:

FieldDescription
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec ColossalAIJobSpecSpec of the colossalai job.

ConcurrencyPolicy

Underlying type: string

ConcurrencyPolicy describes how the WorkflowRun will be handled. Only one of the following concurrent policies may be specified. If none of the following policies is specified, the default one is AllowConcurrent.

Appears in:

ConditionSelector

ConditionSelector selects a k8s resource if its status.conditions contains a condition whose type and status are exactly the same as those of the condition selector.

Appears in:

FieldDescription
type stringType of the condition.
status ConditionStatusStatus of the condition, one of True, False, or Unknown.

CronWorkflowRun

CronWorkflowRun is the Schema for the CronWorkflowRun API

Appears in:

FieldDescription
apiVersion stringbatch.tensorstack.dev/apis
kind stringCronWorkflowRun
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec CronWorkflowRunSpec
status CronWorkflowRunStatus

CronWorkflowRunCondition

CronWorkflowRunCondition is an observation of the condition of the CronWorkflowRun.

Appears in:

FieldDescription
type CronWorkflowRunConditionTypeType of CronWorkflowRun condition.
status ConditionStatusStatus of the condition, one of True, False, or Unknown.
reason stringThe reason for the condition’s last transition.
message stringA readable message indicating details about the transition.
lastTransitionTime TimeLast time the condition transitioned from one status to another.

CronWorkflowRunConditionType

Underlying type: string

CronWorkflowRunConditionType defines all possible types of CronWorkflowRunCondition. Can be one of: HasStarted, IsRunning, HasSuccessfulRun, HasFailedRun.

Appears in:

CronWorkflowRunList

CronWorkflowRunList contains a list of CronWorkflowRun

FieldDescription
apiVersion stringbatch.tensorstack.dev/apis
kind stringCronWorkflowRunList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items CronWorkflowRun array

CronWorkflowRunSpec

CronWorkflowRunSpec defines the desired state of CronWorkflowRun.

Appears in:

FieldDescription
schedule stringSchedule defines the schedule for the running of WorkflowRuns.
concurrencyPolicy ConcurrencyPolicySpecifies how to treat concurrent executions of a WorkflowRun. Valid values are: - “Allow” (default): allows WorkflowRuns to run concurrently; - “Forbid”: forbids concurrent runs, skipping next run if previous run hasn’t finished yet; - “Replace”: cancels currently running WorkflowRun and replaces it with a new one
successfulRunsHistoryLimit integerThe number of successful finished WorkflowRuns to retain. This is a pointer to distinguish between explicit zero and not specified.
failedRunsHistoryLimit integerThe number of failed finished WorkflowRuns to retain. This is a pointer to distinguish between explicit zero and not specified.
startingDeadlineSeconds integerDeadline in seconds for starting the WorkflowRuns if it misses scheduled time for any reason. Missed WorkflowRun runs will be counted as failed ones.
suspend booleanThis flag tells the controller to suspend subsequent runs, it does not apply to already started runs. Defaults to false.
workflowRun WorkflowRunTemplateSpecSpecifies the WorkflowRun that will be created when executing a CronWorkflowRun.

CronWorkflowRunStatus

CronWorkflowRunStatus defines the observed state of CronWorkflowRun.

Appears in:

FieldDescription
active ObjectReference arrayA list of pointers to currently running WorkflowRuns.
lastScheduleTime TimeThe last time when the WorkflowRun was successfully created.
conditions CronWorkflowRunCondition arrayThe latest available observations of the CronWorkflowRun’s current state.

DAGNode

DAGNode represents a node in the graph during DAG execution.

Appears in:

FieldDescription
name stringName is the name of this node within the DAG.
workflowTemplateRef stringWorkflowTemplateRef is a reference to a workflowTemplate definition.
when WhenExpression arrayWhenExpressions is a list of when expressions that need to be true for the node to run
retries integerRetries represents how many times this node should be retried in case of failure: Condition Succeeded set to False
dependencies string arrayDependencies are name of other nodes which this depends on, to force a specific ordering in graph execution.
params Param arrayParameters declares parameters passed to this node.
workspaces WorkspaceDAGBinding arrayWorkspaces maps workspaces from the DAG WorkflowTemplate spec to the workspaces declared in the node.

DAGWorkflowTemplate

DAGWorkflowTemplate creates a dag consisting of other WorkflowTemplates.

Appears in:

FieldDescription
templates DAGNode arrayTemplates are a list of DAG nodes.
failureStrategy FailureStrategyFailureStrategy is the strategy when a node in DAG fails.

DeepSpeedJobWorkflowTemplate

DeepSpeedJobWorkflowTemplate creates a t9k deepspeed job.

Appears in:

FieldDescription
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec DeepSpeedJobSpecSpec of the deepspeed job.

FailureStrategy

Underlying type: string

FailureStrategy defines the failure strategy of DAGWorkflowTemplate.

Appears in:

GenericJobWorkflowTemplate

GenericJobWorkflowTemplate creates a t9k generic job.

Appears in:

FieldDescription
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec GenericJobSpecSpec of the generic job.

MPIJobWorkflowTemplate

MPIJobWorkflowTemplate creates a t9k mpi job.

Appears in:

FieldDescription
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec MPIJobSpecSpec of the mpi job.

NodePhase

Underlying type: string

NodePhase is the current state of a node. Node means the node in a DAG. PodWorkflowTemplate, SeqPodWorkflowTemplate and ResourceWorkflowTemplate are also considered as an independent node. DAGWorkflowTemplate itself is considered as a parent node.

Appears in:

NodeStatus

NodeStatus is the status of a node in DAG

Appears in:

FieldDescription
workflowRunName stringWorkflowRunName is the name of WorkflowRun created from the node.
phase NodePhasePhase is the phase of the node.
whenExpressions WhenExpression arrayWhenExpressions show why if the node is skipped.

Param

Param declares a string to use for the parameter called name.

Appears in:

FieldDescription
name string
value string

ParamSpec

ParamSpec defines values that are provided by users as inputs on a WorkflowRun.

Appears in:

FieldDescription
name stringName declares the name by which a parameter is referenced.
description stringDescription is a user-facing description of the parameter that may be used to populate a UI.
default stringDefault is the value a parameter takes if no input value is supplied. If default is set, a WorkflowTemplate may be executed without a supplied value for the parameter. It serves as a pointer to distinguish between setting no default and setting empty string as default.

PodSpecWithoutContainers

PodSpecWithoutContainers is a helper struct for SeqPodWorkflowTemplate forked from https://github.com/kubernetes/api/blob/v0.20.0/core/v1/types.go#L2914

Appears in:

FieldDescription
volumes Volume arrayList of volumes that can be mounted by containers belonging to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes
initContainers Container arrayList of initialization containers belonging to the pod. Init containers are executed in order prior to containers being started. If any init container fails, the pod is considered to have failed and is handled according to its restartPolicy. The name for an init container or normal container must be unique among all containers. Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. The resourceRequirements of an init container are taken into account during scheduling by finding the highest request/limit for each resource type, and then using the max of of that value or the sum of the normal containers. Limits are applied to init containers in a similar fashion. Init containers cannot currently be added or removed. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
ephemeralContainers EphemeralContainer arrayList of ephemeral containers run in this pod. Ephemeral containers may be run in an existing pod to perform user-initiated actions such as debugging. This list cannot be specified when creating a pod, and it cannot be modified by updating the pod spec. In order to add an ephemeral container to an existing pod, use the pod’s ephemeralcontainers subresource. This field is alpha-level and is only honored by servers that enable the EphemeralContainers feature.
restartPolicy RestartPolicyRestart policy for all containers within the pod. One of Always, OnFailure, Never. Default to Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy
terminationGracePeriodSeconds integerOptional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period will be used instead. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. Defaults to 30 seconds.
activeDeadlineSeconds integerOptional duration in seconds the pod may be active on the node relative to StartTime before the system will actively try to mark it failed and kill associated containers. Value must be a positive integer.
dnsPolicy DNSPolicySet DNS policy for the pod. Defaults to “ClusterFirst”. Valid values are ‘ClusterFirstWithHostNet’, ‘ClusterFirst’, ‘Default’ or ‘None’. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to ‘ClusterFirstWithHostNet’.
nodeSelector object (keys:string, values:string)NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node’s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
serviceAccountName stringServiceAccountName is the name of the ServiceAccount to use to run this pod. More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
serviceAccount stringDeprecatedServiceAccount is a depreciated alias for ServiceAccountName. Deprecated: Use serviceAccountName instead.
automountServiceAccountToken booleanAutomountServiceAccountToken indicates whether a service account token should be automatically mounted.
nodeName stringNodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements.
hostNetwork booleanHost networking requested for this pod. Use the host’s network namespace. If this option is set, the ports that will be used must be specified. Default to false.
hostPID booleanUse the host’s pid namespace. Optional: Default to false.
hostIPC booleanUse the host’s ipc namespace. Optional: Default to false.
shareProcessNamespace booleanShare a single process namespace between all of the containers in a pod. When this is set containers will be able to view and signal processes from other containers in the same pod, and the first process in each container will not be assigned PID 1. HostPID and ShareProcessNamespace cannot both be set. Optional: Default to false.
securityContext PodSecurityContextSecurityContext holds pod-level security attributes and common container settings. Optional: Defaults to empty. See type description for default values of each field.
imagePullSecrets LocalObjectReference arrayImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. If specified, these secrets will be passed to individual puller implementations for them to use. For example, in the case of docker, only DockerConfig type secrets are honored. More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod
hostname stringSpecifies the hostname of the Pod If not specified, the pod’s hostname will be set to a system-defined value.
subdomain stringIf specified, the fully qualified Pod hostname will be “...svc.”. If not specified, the pod will not have a domainname at all.
affinity AffinityIf specified, the pod’s scheduling constraints
schedulerName stringIf specified, the pod will be dispatched by specified scheduler. If not specified, the pod will be dispatched by default scheduler.
tolerations Toleration arrayIf specified, the pod’s tolerations.
hostAliases HostAlias arrayHostAliases is an optional list of hosts and IPs that will be injected into the pod’s hosts file if specified. This is only valid for non-hostNetwork pods.
priorityClassName stringIf specified, indicates the pod’s priority. “system-node-critical” and “system-cluster-critical” are two special keywords which indicate the highest priorities with the former being the highest priority. Any other name must be defined by creating a PriorityClass object with that name. If not specified, the pod priority will be default or zero if there is no default.
priority integerThe priority value. Various system components use this field to find the priority of the pod. When Priority Admission Controller is enabled, it prevents users from setting this field. The admission controller populates this field from PriorityClassName. The higher the value, the higher the priority.
dnsConfig PodDNSConfigSpecifies the DNS parameters of a pod. Parameters specified here will be merged to the generated DNS configuration based on DNSPolicy.
readinessGates PodReadinessGate arrayIf specified, all readiness gates will be evaluated for pod readiness. A pod is ready when all its containers are ready AND all conditions specified in the readiness gates have status equal to “True” More info: https://git.k8s.io/enhancements/keps/sig-network/0007-pod-ready%2B%2B.md
runtimeClassName stringRuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run. If unset or empty, the “legacy” RuntimeClass will be used, which is an implicit class with an empty definition that uses the default runtime handler. More info: https://git.k8s.io/enhancements/keps/sig-node/runtime-class.md This is a beta feature as of Kubernetes v1.14.
enableServiceLinks booleanEnableServiceLinks indicates whether information about services should be injected into pod’s environment variables, matching the syntax of Docker links. Optional: Defaults to true.
preemptionPolicy PreemptionPolicyPreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. This field is beta-level, gated by the NonPreemptingPriority feature-gate.
overhead object (keys:ResourceName, values:Quantity)Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. This field will be autopopulated at admission time by the RuntimeClass admission controller. If the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. The RuntimeClass admission controller will reject Pod create requests which have the overhead already set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero. More info: https://git.k8s.io/enhancements/keps/sig-node/20190226-pod-overhead.md This field is alpha-level as of Kubernetes v1.16, and is only honored by servers that enable the PodOverhead feature.
topologySpreadConstraints TopologySpreadConstraint arrayTopologySpreadConstraints describes how a group of pods ought to spread across topology domains. Scheduler will schedule pods in a way which abides by the constraints. All topologySpreadConstraints are ANDed.
setHostnameAsFQDN booleanIf true the pod’s hostname will be configured as the pod’s FQDN, rather than the leaf name (the default). In Linux containers, this means setting the FQDN in the hostname field of the kernel (the nodename field of struct utsname). In Windows containers, this means setting the registry value of hostname for the registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters to FQDN. If a pod does not have FQDN, this has no effect. Default to false.

PodWorkflowTemplate

PodWorkflowTemplate creates a pod.

Appears in:

FieldDescription
PodSpec PodSpec

PyTorchTrainingJobWorkflowTemplate

PyTorchTrainingJobWorkflowTemplate creates a t9k pytorch training job.

Appears in:

FieldDescription
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec PyTorchTrainingJobSpecSpec of the pytorch training job.

ResourceWorkflowTemplate

ResourceWorkflowTemplate creates a k8s resource.

Appears in:

FieldDescription
successRules RulesSuccessRules is an expression which describes the state of the k8s resource in which the task was considered succeeded.
failureRules RulesFailureRules is an expression which describes the state of the k8s resource in which the task was considered failed.
manifest stringManifest is the full spec of the k8s resource to create.

Result

Result used to describe the results of a task

Appears in:

FieldDescription
name stringName the given name
description stringDescription is a human-readable description of the result
value stringValue is a expression to generate DAG result by combining node results Only required for DAG WorkflowTemplate

Rules

Rules describe the state of the k8s resource.

Appears in:

FieldDescription
fieldSelector stringFieldSelector selects k8s resources based on the value of one or more resource fields, examples: metadata.name=my-service metadata.namespace!=default status.phase!=Running,spec.restartPolicy=Always
conditionSelector ConditionSelectorConditionSelector selects k8s resources based on .status.conditions.

SchedulePolicy

SchedulePolicy defines how k8s schedules the WorkflowRun.

Appears in:

FieldDescription
t9kScheduler T9kSchedulerT9k Scheduler.

SeqPodWorkflowTemplate

SeqPodWorkflowTemplate creates a pod whose containers run sequentially. The spec of SeqPodWorkflowTemplate is almost the same with corev1.PodSpec, except that the field Containers is replaced by Steps, to emphasize the sequential execution pattern.

Appears in:

FieldDescription
PodSpecWithoutContainers PodSpecWithoutContainers
steps Step arraySteps are the sequentially running containers of the SeqPodWorkflowTemplate

Step

Step embeds the Container type, which allows it to include fields not provided by Container.

Appears in:

FieldDescription
Container Container
script stringScript is the contents of an executable file to execute. If Script is not empty, the Step cannot have an Command and the Args will be passed to the Script.

T9kScheduler

T9kScheduler provides additonal configurations needed for the scheduling process.

Appears in:

FieldDescription
queue stringSpecifies the name of the queue should be used for running this workload.

TensorFlowTrainingJobWorkflowTemplate

TensorFlowTrainingJobWorkflowTemplate creates a t9k training job.

Appears in:

FieldDescription
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec TensorFlowTrainingJobSpecSpec of the training job.

WhenExpression

WhenExpression allows a node in DAG to declare expressions to be evaluated before the node is run to determine whether the node should be executed or skipped.

Appears in:

FieldDescription
input stringInput is the string for guard checking which can be a static input or an output from a parent node
operator OperatorOperator that represents an Input’s relationship to the values
values string arrayValues is an array of strings, which is compared against the input, for guard checking It must be non-empty

WorkflowRun

WorkflowRun is the Schema for the workflowrun API

Appears in:

FieldDescription
apiVersion stringbatch.tensorstack.dev/apis
kind stringWorkflowRun
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec WorkflowRunSpec
status WorkflowRunStatus

WorkflowRunCondition

WorkflowRunCondition is an observation of the condition of the WorkflowRun.

Appears in:

FieldDescription
type WorkflowRunConditionTypeType of WorkflowRun condition.
status ConditionStatusStatus of the condition, one of True, False, or Unknown.
reason stringThe reason for the condition’s last transition.
message stringA readable message indicating details about the transition.
lastTransitionTime TimeLast time the condition transitioned from one status to another.

WorkflowRunConditionType

Underlying type: string

WorkflowRunConditionType defines all possible types of WorkflowRunConditionType. Can be one of: Running, Completed.

Appears in:

WorkflowRunList

WorkflowRunList contains a list of WorkflowRun

FieldDescription
apiVersion stringbatch.tensorstack.dev/apis
kind stringWorkflowRunList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items WorkflowRun array

WorkflowRunResult

WorkflowRunResult used to describe the results of a workflowTemplate

Appears in:

FieldDescription
name stringName the given name
value stringValue the given value of the result

WorkflowRunSpec

WorkflowRunSpec defines the desired state of WorkflowRun

Appears in:

FieldDescription
workspaces WorkspaceBinding arrayWorkspaces is a list of mappings from volumes to workspace names that will be supplied to WorkflowTemplate.
params Param arrayParams is a list of input parameters that will be supplied to WorkflowTemplate.
serviceAccountName stringServiceAccountName is the name of the service account that the created pod will use.
workflowTemplateRef stringWorkflowTemplateRef is the name of the WorkflowTemplate that WorkflowRun will use. No more than one of the WorkflowTemplateRef and WorkflowTemplateSpec may be specified.
workflowTemplateSpec WorkflowTemplateSpecWorkflowTemplateSpec is an embedded spec of WorkflowTemplate that WorkflowRun will use. No more than one of the WorkflowTemplateRef and WorkflowTemplateSpec may be specified.
timeout DurationTime after which the build times out. Defaults to never. Refer Go’s ParseDuration documentation for expected format: https://golang.org/pkg/time/#ParseDuration
depth integerDepth indicates the depth of the WorkflowRun in DAG. If Depth exceeds limit, the WorkflowRun will not be created.
scheduler SchedulePolicyIdentifies the preferred scheduler for allocating resources to replicas. Defaults to cluster default scheduler.

WorkflowRunStatus

WorkflowRunStatus defines the observed state of WorkflowRun

Appears in:

FieldDescription
WorkflowRunStatusFields WorkflowRunStatusFieldsWorkflowRunStatusFields inlines the status fields.
retriedStatus WorkflowRunStatusFields arrayRetriedStatus contains the history of WorkflowRunStatus in case of a retry in order to keep record of failures.

WorkflowRunStatusFields

WorkflowRunStatusFields are the main fields of WorkflowRunStatus

Appears in:

FieldDescription
phase NodePhasePhase is a simple, high-level summary of where the WorkflowRun is in its lifecycle.
message stringA human readable message indicating details about why the WorkflowRun is in this condition.
nodes object (keys:string, values:NodeStatus)Nodes is a map of DAG nodes status, with the node name as the key.
startTime TimeStartTime is the time the build is actually started.
completionTime TimeCompletionTime is the time the build completed.
results WorkflowRunResult arrayResults are the list of results written out by the workflowTemplate’s containers
workflowTemplateSpec WorkflowTemplateSpecWorkflowTemplateSpec contains the Spec from the dereferenced WorkflowTemplate definition used to instantiate this WorkflowRun.
podName stringPodName is the name of the pod created by WorkflowRun.
conditions WorkflowRunCondition arrayThe latest available observations of the WorkflowRun’s current state.

WorkflowRunTemplateSpec

WorkflowRunTemplateSpec describes the data a WorkflowRun should have when created from a template

Appears in:

FieldDescription
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec WorkflowRunSpecSpecification of the desired behavior of the WorkflowRun.

WorkflowTemplate

WorkflowTemplate is the Schema for the WorkflowTemplate API

Appears in:

FieldDescription
apiVersion stringbatch.tensorstack.dev/apis
kind stringWorkflowTemplate
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec WorkflowTemplateSpec
status WorkflowTemplateStatus

WorkflowTemplateList

WorkflowTemplateList contains a list of WorkflowTemplate

FieldDescription
apiVersion stringbatch.tensorstack.dev/apis
kind stringWorkflowTemplateList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items WorkflowTemplate array

WorkflowTemplateSpec

WorkflowTemplateSpec defines the desired state of WorkflowTemplate.

Appears in:

FieldDescription
description stringDescription is a user-facing description of the task that may be used to populate a UI.
workspaces WorkspaceDeclaration arrayWorkspaces are the volumes that this WorkflowTemplate requires. Workspaces must be supplied as inputs in WorkflowRuns unless they are declared as optional.
params ParamSpec arrayParams is a list of input parameters required to run the task. Params must be supplied as inputs in WorkflowRuns unless they declare a default value.
results Result arrayResults are values that this WorkflowTemplate can output
type WorkflowTemplateTypeType defines the type of WorkflowTemplate. If empty, the first non-nil field in (pod, seqPod, resource, dag) will be the type.
pod PodWorkflowTemplatePod is the spec of pod which WorkflowTemplate will create.
seqPod SeqPodWorkflowTemplateSeqPod is the spec of pod with sequentially running containers which WorkflowTemplate will create.
resource ResourceWorkflowTemplateResource is the spec of k8s resource which WorkflowTemplate will create.
dag DAGWorkflowTemplateDAG is the spec of DAG which WorkflowTemplate will create.
genericJob GenericJobWorkflowTemplateGenericJob is the spec of t9k generic job which WorkflowTemplate will create.
tensorflowTrainingJob TensorFlowTrainingJobWorkflowTemplateTensorFlowTrainingJob is the spec of t9k training job which WorkflowTemplate will create.
pytorchTrainingJob PyTorchTrainingJobWorkflowTemplatePyTorchTrainingJob is the spec of t9k pytorch training job which WorkflowTemplate will create.
xgboostTrainingJob XGBoostTrainingJobWorkflowTemplateXGBoostTrainingJob is the spec of t9k xgboost training job which WorkflowTemplate will create.
colossalaiJob ColossalAIJobWorkflowTemplateColossalAIJob is the spec of t9k colossalai job which WorkflowTemplate will create.
deepspeedJob DeepSpeedJobWorkflowTemplateDeepSpeedJob is the spec of t9k deepspeed job which WorkflowTemplate will create.
mpiJob MPIJobWorkflowTemplateMPIJob is the spec of t9k mpi job which WorkflowTemplate will create.
beamJob BeamJobWorkflowTemplateBeamJob is the spec of t9k beam job which WorkflowTemplate will create.

WorkflowTemplateType

Underlying type: string

WorkflowTemplateType defines the type of WorkflowTemplate.

Appears in:

WorkspaceBinding

WorkspaceBinding maps a WorkflowTemplate’s declared workspace to a Volume.

Appears in:

FieldDescription
name stringName is the name of the workspace populated by the volume.
subPath stringSubPath is optionally a directory on the volume which should be used for this binding (i.e. the volume will be mounted at this sub directory).
persistentVolumeClaim PersistentVolumeClaimVolumeSourcePersistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace. Either this OR EmptyDir can be used.
emptyDir EmptyDirVolumeSourceEmptyDir represents a temporary directory that shares a WorkflowTemplate’s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir Either this OR PersistentVolumeClaim can be used.
configMap ConfigMapVolumeSourceConfigMap represents a configMap that should populate this workspace.
secret SecretVolumeSourceSecret represents a secret that should populate this workspace.

WorkspaceDAGBinding

WorkspaceDAGBinding describes how a workspace passed into a DAG WorkflowTemplate should be mapped to a node’s declared workspace.

Appears in:

FieldDescription
name stringName is the name of the workspace as declared by the node
workspace stringWorkspace is the name of the workspace declared by the DAG WorkflowTemplate
subPath stringSubPath is optionally a directory on the volume which should be used for this binding (i.e. the volume will be mounted at this sub directory).

WorkspaceDeclaration

WorkspaceDeclaration is a declaration of a volume that a WorkflowTemplate requires.

Appears in:

FieldDescription
name stringName is the name by which you can bind the volume at runtime.
description stringDescription is an optional human readable description of this volume.
mountPath stringMountPath overrides the directory that the volume will be made available at.
readOnly booleanReadOnly dictates whether a mounted volume is writable. By default this field is false and so mounted volumes are writable.
optional booleanOptional marks a Workspace as not being required in WorkflowRuns. By default this field is false and so declared workspaces are required.

XGBoostTrainingJobWorkflowTemplate

XGBoostTrainingJobWorkflowTemplate creates a t9k xgboost training job.

Appears in:

FieldDescription
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec XGBoostTrainingJobSpecSpec of the xgboost training job.

API Reference

Packages

tensorstack.dev/v1beta1

Package v1beta1 contains API Schema definitions for the v1beta1 API group

Resource Types

Condition

Condition contains details about resource state

Appears in:

FieldDescription
type ConditionTypeCondition type.
status ConditionStatusCondition status, True, False or Unknown.
lastTransitionTime TimeLast time the condition transitioned from one status to another.
message stringHuman-readable message indicating details about last transition.

ConditionType

Underlying type: string

ConditionType is a valid value of Condition.Type

Appears in:

EventListener

EventListener is the Schema for the eventlisteners API

Appears in:

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringEventListener
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec EventListenerSpec
status EventListenerStatus

EventListenerAddress

The access address for in-cluster and out-cluster

Appears in:

FieldDescription
url stringThe access address for out-cluster
inClusterURL stringThe access address for in-cluster

EventListenerList

EventListenerList contains a list of EventListener

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringEventListenerList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items EventListener array

EventListenerSpec

EventListenerSpec defines the desired state of EventListener

Appears in:

FieldDescription
replicas integerNumber of desired pods. This is a pointer to distinguish between explicit zero and not specified. Defaults to 1.
resources ResourceRequirementsCompute Resources required by this container. Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/

EventListenerStatus

EventListenerStatus defines the observed state of EventListener

Appears in:

FieldDescription
address EventListenerAddressThe access address for in-cluster and out-cluster
conditions Condition arrayRepresents the latest available observations of a eventListener’s current state.

EventSource

The source that events come from.

Appears in:

FieldDescription
eventListenerName stringName of an existing EventListener.
filters Filter arrayList of filters to filter events from the EventListener.

Filter

Filter defines how to filter events from the EventListener.

Appears in:

FieldDescription
path stringPath is the JSONPath of the event’s (JSON decoded) data key Path is a series of keys separated by a dot. A key may contain wildcard characters ‘*’ and ‘?’. To access an array value use the index as the key. The dot and wildcard characters can be escaped with ‘\’. See https://github.com/tidwall/gjson#path-syntax for more information on how to use this.
type JSONTypeType contains the JSON type of the data
values string arrayValues is the allowed string values for this key Booleans are passed using strconv.ParseBool() Numbers are parsed using as float64 using strconv.ParseFloat() Strings are taken as is Nils this value is ignored

JSONType

Underlying type: string

JSONType contains the supported JSON types for data filtering

Appears in:

WorkflowTrigger

WorkflowTrigger is the Schema for the workflowtriggers API

Appears in:

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringWorkflowTrigger
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec WorkflowTriggerSpec
status WorkflowTriggerStatus

WorkflowTriggerList

WorkflowTriggerList contains a list of WorkflowTrigger

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringWorkflowTriggerList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items WorkflowTrigger array

WorkflowTriggerSpec

WorkflowTriggerSpec defines the desired state of WorkflowTrigger

Appears in:

FieldDescription
replicas integerNumber of desired pods. This is a pointer to distinguish between explicit zero and not specified. Defaults to 1.
eventSources EventSource arrayList of sources that events come from.
serviceAccountName stringName of a service account used by WorkflowTrigger to create WorkflowRuns.
resources ResourceRequirementsCompute Resources required by this container. Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
workflowRunSpec WorkflowRunSpecSpec of WorkflowRun to be created by WorkflowTrigger.

WorkflowTriggerStatus

WorkflowTriggerStatus defines the observed state of WorkflowTrigger

Appears in:

FieldDescription
conditions Condition arrayRepresents the latest available observations of a eventListener’s current state.

API Reference

Packages

tensorstack.dev/v1beta1

Package v1beta1 contains API Schema definitions for the v1beta1 API group

Resource Types

Address

Appears in:

FieldDescription
url stringthe service’s in-cluster url, e.g. managed-simplemlservice-41309.demo.svc.cluster.local
ports AddressPort arrayan array of serivce port & protocol

AddressPort

AddressPort stores ports defined in service of simplemlservice

Appears in:

FieldDescription
port integerThe port that will be exposed by this service.
nodePort integerThe port on each node on which this service is exposed when type=NodePort or LoadBalancer. Usually assigned by the system. If specified, it will be allocated to the service if unused or else creation of the service will fail. Default is to auto-allocate a port if the ServiceType of this Service requires one. More info: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport
protocol ProtocolThe IP protocol for this port. Supports “TCP”, “UDP”, and “SCTP”. Default is TCP.

Condition

Condition for simpleMLService

Appears in:

FieldDescription
lastTransitionTime Time
type SimpleMLServiceConditionType
status ConditionStatus
reason string
message string

CustomSpec

CustomSpec defines a pod template to run model serving

Appears in:

FieldDescription
spec PodSpec

DeploymentSpec

DeploymentSpec defines the configuration for replicas & scheduler

Appears in:

FieldDescription
scheduler SchedulePolicyScheduler responsible for handling resource allocation requests. default is default-scheduler
replicas integerReplicas of pods running model serving
strategy DeploymentStrategyThe deployment strategy to use to replace existing pods with new ones

PVCStorage

PVCStorage defines infos of pvc

Appears in:

FieldDescription
name stringPVC name
subPath stringDirectory path where model is located in PVC. Must be a relative path. e.g. “model/mnist”
containerPath stringDirectory path where model locates in container. Must be absolute path, default is “/var/lib/t9k/model”

PyTorchSpec

PyTorchSpec defines arguments for configuring PyTorch model serving

Appears in:

FieldDescription
modelsFlag stringValue of torchserve’s flag –models
image stringImage of torchserve
resources ResourceRequirementsCompute Resources required by a replica

S3Storage

S3Storage defines infos of s3

Appears in:

FieldDescription
secretName stringName of secret storing s3cmd config
uri stringDirectory path where model locates in s3. e.g. "s3://<bucket>/<dir>/"
containerPath stringDirectory path where model locates in container, default is “/var/lib/t9k/model”

SchedulePolicy

SchedulePolicy defines which scheduler is responsible for handling resource allocation requests

Appears in:

FieldDescription
t9kScheduler T9kSchedulerUse t9k-scheduler

ServiceSpec

ServiceSpec defines the desired state of Service created by Controller

Appears in:

FieldDescription
ports ServicePort arrayThe list of ports that are exposed by this service. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies
type ServiceTypetype determines how the Service is exposed. Defaults to ClusterIP. Valid options are ExternalName, ClusterIP, NodePort, and LoadBalancer. “ExternalName” maps to the specified externalName. “ClusterIP” allocates a cluster-internal IP address for load-balancing to endpoints. Endpoints are determined by the selector or if that is not specified, by manual construction of an Endpoints object. If clusterIP is “None”, no virtual IP is allocated and the endpoints are published as a set of endpoints rather than a stable IP. “NodePort” builds on ClusterIP and allocates a port on every node which routes to the clusterIP. “LoadBalancer” builds on NodePort and creates an external load-balancer (if supported in the current cloud) which routes to the clusterIP. More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types

SimpleMLService

SimpleMLService is the Schema for the simplemlservices API

Appears in:

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringSimpleMLService
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec SimpleMLServiceSpec
status SimpleMLServiceStatus

SimpleMLServiceConditionType

Underlying type: string

SimpleMLServiceConditionType is a type

Appears in:

SimpleMLServiceList

SimpleMLServiceList contains a list of SimpleMLService

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringSimpleMLServiceList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items SimpleMLService array

SimpleMLServiceSpec

SimpleMLServiceSpec defines the desired state of SimpleMLService

Appears in:

FieldDescription
tensorflow TensorflowSpecSpec for Tensorflow Serving (https://github.com/tensorflow/serving)
pytorch PyTorchSpecSpec for TorchServe
custom CustomSpecCustom Spec
storage StorageStorage of model
DeploymentSpec DeploymentSpecConfiguration for replicas & scheduler
service ServiceSpecConfiguration for service. Controller will create default service if spec.service not set

SimpleMLServiceStatus

SimpleMLServiceStatus defines the observed state of SimpleMLService

Appears in:

FieldDescription
address Address
conditions Condition array

Storage

Storage defines the storage where the model locates

Appears in:

FieldDescription
s3 S3StorageModel locates in S3
pvc PVCStorageModel locates in pvc

T9kScheduler

T9kScheduler defines SimpleMLService use t9k-scheduler.

Appears in:

FieldDescription
queue stringName of queue which SimpleMLService’s pod belongs to

TensorflowSpec

TensorflowSpec defines arguments for configuring Tensorflow model serving

Appears in:

FieldDescription
image stringImage of Tensorflow Serving
resources ResourceRequirementsCompute Resources required by a replica

API Reference

Packages

tensorstack.dev/v1beta1

Package v1beta1 contains API Schema definitions for the v1beta1 API group

Resource Types

AddressStatus

AddressStatus store state of serving address

Appears in:

FieldDescription
url stringURL used for predictor.

DeploymentSpec

DeploymentSpec defines the configuration for knative service

Appears in:

FieldDescription
minReplicas integerMinimum number of replicas, pods won’t scale down to 0 in case of no traffic
maxReplicas integerThis is the up bound for autoscaler to scale to
template PatchTemplateSpecCustom template of knative service
logger LoggerSpecLogger spec

EditableMetadata

Metadata includes the editable part of metav1.ObjectMeta. Now only contains labels and annotations

Appears in:

FieldDescription
labels object (keys:string, values:string)Labels
annotations object (keys:string, values:string)Annotations

LoggerMode

Underlying type: string

Appears in:

LoggerSpec

Appears in:

FieldDescription
urls string arrayLogger sink url array
mode LoggerModeLogger mode

MLService

MLService is the Schema for the mlservices API

Appears in:

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringMLService
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec MLServiceSpec
status MLServiceStatus

MLServiceCondition

Appears in:

FieldDescription
type MLServiceConditionTypeType of condition.
status ConditionStatusStatus of the condition, one of True, False, Unknown.
lastTransitionTime TimeLast time the condition transitioned from one status to another.
reason stringThe reason for the condition’s last transition.
message stringA human readable message indicating details about the transition.

MLServiceConditionType

Underlying type: string

Appears in:

MLServiceList

MLServiceList contains a list of MLService

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringMLServiceList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items MLService array

MLServiceRuntime

MLServiceRuntime is the Schema for the mlserviceruntimes API

Appears in:

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringMLServiceRuntime
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.
spec MLServiceRuntimeSpec
status MLServiceRuntimeStatus

MLServiceRuntimeList

MLServiceRuntimeList contains a list of MLServiceRuntime

FieldDescription
apiVersion stringtensorstack.dev/v1beta1
kind stringMLServiceRuntimeList
metadata ListMetaRefer to Kubernetes API documentation for fields of metadata.
items MLServiceRuntime array

MLServiceRuntimeSpec

Appears in:

FieldDescription
enabled booleanSet true if enabled
template RuntimeTemplateSpecTemplate defines the knative revision that will be created from this pod template.

MLServiceSpec

MLServiceSpec defines the desired state of MLService

Appears in:

FieldDescription
releases ReleaseSpec arrayReleases define multiple versions of predictor
transformer TransformerSpecTransformer will pre-process and post-process data
default stringDefault specifies the release name which will be used as default version.
canary stringCanary specifies the release name which will be used as canary version.
canaryTrafficPercent integerCanaryTrafficPercent specifies traffic percent of canary version, range is (0,100).
scheduler SchedulePolicyDefault Scheduler is default-scheduler
runMode RunModeMLService RunMode

MLServiceStatus

MLServiceStatus defines the observed state of MLService

Appears in:

FieldDescription
defaultRelease stringDefault release name
canaryRelease stringCanary release name
conditions MLServiceCondition arrayConditions
releases ReleaseStatus arrayThe observed statuses of MLService releases
transformer TransformerStatusThe observed statuses of transformers.
address AddressStatusAddress

ModelSpec

Appears in:

FieldDescription
parameters object (keys:string, values:string)Model parameters
runtime stringSpecific ServingRuntime name to use for deployment.
modelUri stringModel storage URI.

PatchTemplateSpec

podSpec and containers are optional. This will be patched to runtime

Appears in:

FieldDescription
metadata EditableMetadataRefer to Kubernetes API documentation for fields of metadata.
spec PodSpecPod Spec with optional containers

PodSpec

PodSpec is a description of a pod.

Appears in:

FieldDescription
volumes Volume arrayList of volumes that can be mounted by containers belonging to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes
initContainers Container arrayList of initialization containers belonging to the pod. Init containers are executed in order prior to containers being started. If any init container fails, the pod is considered to have failed and is handled according to its restartPolicy. The name for an init container or normal container must be unique among all containers. Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. The resourceRequirements of an init container are taken into account during scheduling by finding the highest request/limit for each resource type, and then using the max of of that value or the sum of the normal containers. Limits are applied to init containers in a similar fashion. Init containers cannot currently be added or removed. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
containers Container arrayList of containers belonging to the pod. Containers cannot currently be added or removed. There must be at least one container in a Pod. Cannot be updated.
ephemeralContainers EphemeralContainer arrayList of ephemeral containers run in this pod. Ephemeral containers may be run in an existing pod to perform user-initiated actions such as debugging. This list cannot be specified when creating a pod, and it cannot be modified by updating the pod spec. In order to add an ephemeral container to an existing pod, use the pod’s ephemeralcontainers subresource. This field is alpha-level and is only honored by servers that enable the EphemeralContainers feature.
restartPolicy RestartPolicyRestart policy for all containers within the pod. One of Always, OnFailure, Never. Default to Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy
terminationGracePeriodSeconds integerOptional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period will be used instead. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. Defaults to 30 seconds.
activeDeadlineSeconds integerOptional duration in seconds the pod may be active on the node relative to StartTime before the system will actively try to mark it failed and kill associated containers. Value must be a positive integer.
dnsPolicy DNSPolicySet DNS policy for the pod. Defaults to “ClusterFirst”. Valid values are ‘ClusterFirstWithHostNet’, ‘ClusterFirst’, ‘Default’ or ‘None’. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to ‘ClusterFirstWithHostNet’.
nodeSelector object (keys:string, values:string)NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node’s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
serviceAccountName stringServiceAccountName is the name of the ServiceAccount to use to run this pod. More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
serviceAccount stringDeprecatedServiceAccount is a depreciated alias for ServiceAccountName. Deprecated: Use serviceAccountName instead.
automountServiceAccountToken booleanAutomountServiceAccountToken indicates whether a service account token should be automatically mounted.
nodeName stringNodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements.
hostNetwork booleanHost networking requested for this pod. Use the host’s network namespace. If this option is set, the ports that will be used must be specified. Default to false.
hostPID booleanUse the host’s pid namespace. Optional: Default to false.
hostIPC booleanUse the host’s ipc namespace. Optional: Default to false.
shareProcessNamespace booleanShare a single process namespace between all of the containers in a pod. When this is set containers will be able to view and signal processes from other containers in the same pod, and the first process in each container will not be assigned PID 1. HostPID and ShareProcessNamespace cannot both be set. Optional: Default to false.
securityContext PodSecurityContextSecurityContext holds pod-level security attributes and common container settings. Optional: Defaults to empty. See type description for default values of each field.
imagePullSecrets LocalObjectReference arrayImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. If specified, these secrets will be passed to individual puller implementations for them to use. For example, in the case of docker, only DockerConfig type secrets are honored. More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod
hostname stringSpecifies the hostname of the Pod If not specified, the pod’s hostname will be set to a system-defined value.
subdomain stringIf specified, the fully qualified Pod hostname will be “...svc.”. If not specified, the pod will not have a domainname at all.
affinity AffinityIf specified, the pod’s scheduling constraints
schedulerName stringIf specified, the pod will be dispatched by specified scheduler. If not specified, the pod will be dispatched by default scheduler.
tolerations Toleration arrayIf specified, the pod’s tolerations.
hostAliases HostAlias arrayHostAliases is an optional list of hosts and IPs that will be injected into the pod’s hosts file if specified. This is only valid for non-hostNetwork pods.
priorityClassName stringIf specified, indicates the pod’s priority. “system-node-critical” and “system-cluster-critical” are two special keywords which indicate the highest priorities with the former being the highest priority. Any other name must be defined by creating a PriorityClass object with that name. If not specified, the pod priority will be default or zero if there is no default.
priority integerThe priority value. Various system components use this field to find the priority of the pod. When Priority Admission Controller is enabled, it prevents users from setting this field. The admission controller populates this field from PriorityClassName. The higher the value, the higher the priority.
dnsConfig PodDNSConfigSpecifies the DNS parameters of a pod. Parameters specified here will be merged to the generated DNS configuration based on DNSPolicy.
readinessGates PodReadinessGate arrayIf specified, all readiness gates will be evaluated for pod readiness. A pod is ready when all its containers are ready AND all conditions specified in the readiness gates have status equal to “True” More info: https://git.k8s.io/enhancements/keps/sig-network/0007-pod-ready%2B%2B.md
runtimeClassName stringRuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run. If unset or empty, the “legacy” RuntimeClass will be used, which is an implicit class with an empty definition that uses the default runtime handler. More info: https://git.k8s.io/enhancements/keps/sig-node/runtime-class.md This is a beta feature as of Kubernetes v1.14.
enableServiceLinks booleanEnableServiceLinks indicates whether information about services should be injected into pod’s environment variables, matching the syntax of Docker links. Optional: Defaults to true.
preemptionPolicy PreemptionPolicyPreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. This field is beta-level, gated by the NonPreemptingPriority feature-gate.
overhead ResourceListOverhead represents the resource overhead associated with running a pod for a given RuntimeClass. This field will be autopopulated at admission time by the RuntimeClass admission controller. If the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. The RuntimeClass admission controller will reject Pod create requests which have the overhead already set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero. More info: https://git.k8s.io/enhancements/keps/sig-node/20190226-pod-overhead.md This field is alpha-level as of Kubernetes v1.16, and is only honored by servers that enable the PodOverhead feature.
topologySpreadConstraints TopologySpreadConstraint arrayTopologySpreadConstraints describes how a group of pods ought to spread across topology domains. Scheduler will schedule pods in a way which abides by the constraints. All topologySpreadConstraints are ANDed.
setHostnameAsFQDN booleanIf true the pod’s hostname will be configured as the pod’s FQDN, rather than the leaf name (the default). In Linux containers, this means setting the FQDN in the hostname field of the kernel (the nodename field of struct utsname). In Windows containers, this means setting the registry value of hostname for the registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters to FQDN. If a pod does not have FQDN, this has no effect. Default to false.

PredictorSpec

PredictorSpec defines the configuration for a predictor, The following fields follow a “1-of” semantic. Users must specify exactly one spec.

Appears in:

FieldDescription
model ModelSpecModel info
storage StorageModel storage spec
DeploymentSpec DeploymentSpecModel deploy spec
resources ResourceRequirementsUserContainer’s resources

ReleaseSpec

ReleaseSpec defines the specific spec of release

Appears in:

FieldDescription
name stringName is the release name
predictor PredictorSpecPredictor defines the model serving spec

ReleaseStatus

ReleaseStatus defines the observed status of one MLService release

Appears in:

FieldDescription
name stringRelease name
ready booleanTrue if release service ready
trafficPercent integerTraffic percent of this release
url stringService url
reason stringReason for not ready, empty if ready
message stringMessage for not ready, empty if ready
readyReplicas integerReady replicas numbers
totalReplicas integerTotal replicas numbers

RunMode

Underlying type: string

Appears in:

RuntimeTemplateSpec

this will be applied to RevisionTemplateSpec

Appears in:

FieldDescription
metadata EditableMetadataRefer to Kubernetes API documentation for fields of metadata.
spec PodSpecPod Spec with optional containers

S3Storage

S3Storage defines s3 storage

Appears in:

FieldDescription
secretName stringS3 secret name

SchedulePolicy

SchedulePolicy defines how k8s to schedule the replicas.

Appears in:

FieldDescription
t9kScheduler T9kSchedulerTensorStack scheduler spec

Storage

Storage defines the storage where the model locates

Appears in:

FieldDescription
s3Storage S3StorageS3 storage

T9kScheduler

Appears in:

FieldDescription
queue stringQueue name

TransformerSpec

TransformerSpec defines the transformer

Appears in:

FieldDescription
DeploymentSpec DeploymentSpecTransformer deployment spec
storage StorageTransformer model storage spec
modelUri stringTransformer model uri

TransformerStatus

TransformerStatus defines the observed status of transformer

Appears in:

FieldDescription
ready booleanTrue if transformer service ready
url stringTransformer url
reason stringReason for not ready, empty if ready
message stringMessage for not ready, empty if ready
readyReplicas integerReady replicas numbers
totalReplicas integerTotal replicas numbers

标准镜像

部分 CRD,如 Notebook、T9k Job 和 MLService,需要 Docker 镜像来提供模型开发、训练或推理所需的具体运行环境。平台提供并维护了一系列镜像以满足你的基本使用需求,这些镜像被称为标准镜像。

你也可以构建自定义镜像,以满足更加特定的需求。

Notebook 标准镜像列表

每个 Notebook 标准镜像包含特定的机器学习框架,同时预装了一些 Python 包、命令行工具和最新版本的平台工具

当前正在维护的 Notebook 标准镜像如下表所示:

名称环境
tensorflow-2.14.0-notebook-cpuTensorFlow 2(仅支持 CPU)
tensorflow-2.14.0-notebook-gpuTensorFlow 2(支持 GPU)
torch-2.1.0-notebookPyTorch 2,conda
miniconda-22.11.1-notebookconda

说明:

  1. 你可以在创建 Notebook 时选择以使用这些镜像,也可以直接从 Docker Hub 的 t9kpublic Namespace 下拉取这些镜像以使用。
  2. 这些镜像会持续更新,直到相应机器学习框架的小版本更新后被新镜像替代,此时旧镜像会被移除。镜像的标签(tag)是它的版本号,其跟随平台的版本号进行更新;镜像的每一次更新可能包含修复问题、更新包或工具、更新 Notebook 的扩展程序等内容。
  3. 标签中包含 -sudo 的镜像包含 sudo 命令,其中用户(t9kuser)的密码为 tensorstack
  4. 所有镜像包含以下命令行工具:
名称介绍
curl用于从或向服务器传输数据,支持多种协议。
git分布式版本控制系统,用于跟踪和协作开发软件项目的源代码。
htop一个交互式的系统监视器,用于实时查看和管理运行中的进程。
rclone用于在本地和云存储之间同步、管理文件的命令行程序,支持多种云存储服务。
rsync用于高效同步和传输文件,支持本地和远程文件。
s3cmd用于管理 Amazon S3 云存储服务。
ssh用于安全地远程访问和管理服务器。
unzip用于解压缩 ZIP 文件。
vim一款高效、可定制的文本编辑器,常用于编程和文本编辑。
wget用于从网络上下载文件,支持 HTTP、HTTPS 和 FTP 协议。
zip用于创建和管理 ZIP 压缩文件。

示例

启动 LLM 大规模预训练

LLM(大型语言模型)是当前 AI 领域备受瞩目的研究和应用领域。预训练是构建 LLM 的初始步骤,通常需要在 GPU 集群上进行大规模(10^3~10^4 卡)的并行训练,从而使模型获得对语言结构、语义直至语言所描述的世界和各种规律的全面理解。

在集群上运行大规模模型训练面临着一些关键挑战:

  • 有效地分配和管理计算资源以满足模型训练的计算需求是一项复杂任务,需要避免资源浪费和不必要的等待时间。
  • 数据的并行加载和分发以及模型参数的同步和更新,需要高效的通信和协调机制,以确保训练的一致性和速度。
  • 故障容错和中断恢复必不可少,因为在大规模集群上运行时硬件故障和网络问题可能导致训练中断。

DeepSpeed 是目前最受欢迎的大规模分布式训练框架,而平台提供了 DeepSpeedJob,这是专为使用 DeepSpeed 框架的分布式训练而设计的 Job 类型。

本示例将使用 DeepSpeedJob 以简便迅速的方式启动 Megatron-LM GPT-3 系列(125M、1.3B、13B 和 175B)模型的预训练任务。

准备

在你的项目中创建一个名为 megatron、大小 250 GiB 以上的 PVC,然后创建一个同样名为 megatron 的 Notebook 挂载该 PVC(镜像类型和模板不限)。

进入 Notebook 或远程连接到 Notebook,启动一个终端,执行以下命令以克隆必要的仓库:

cd ~
git clone https://github.com/microsoft/Megatron-DeepSpeed.git
git clone https://github.com/NVIDIA/Megatron-LM.git
git clone https://github.com/t9k/examples.git

选用 enwiki(英文维基百科)作为数据集,使用脚本下载数据集并进行预处理:

pip install wikiextractor
cd examples/deepspeed/megatron-gpt/dataset
python download_wiki.py en
cd ../dataset
./preprocess_wiki.sh

然后使用这一数据集重新训练类 GPT-2 的 tokenzier:

cd ../tokenizer
python train_tokenizer.py ../dataset/wiki-en/all wiki-en-tokenizer

启动训练

使用如下 YAML 配置文件创建 DeepSpeedJob 以启动 125M 模型的训练:

# 数据并行训练 125M 参数的 GPT 模型
kubectl create -f \
  examples/deepspeed/megatron-gpt/training/gpt-125m-4xdp.yaml

通过以下命令查看训练过程中打印的日志:

kubectl logs gpt-125m-worker-0 -f
log

训练过程中产生的 TensorBoard 日志文件保存在 output/gpt-1-3b/tensorboard 路径下,同样可以在 Notebook 中创建一个 TensorBoard 实例以查看:

tensorboard

训练完成之后,模型文件将保存到 output/gpt-125m/model 路径下,后续用于文本生成或进一步的微调。

使用其他训练配置

examples/deepspeed/megatron-gpt/training 路径下有多个 YAML 配置文件,分别对应不同模型参数量的不同并行训练策略。例如 gpt-13b-4xdp-4xpp-4xtp.yaml 对应 13B 模型、4 度数据并行、4 度流水线并行以及 4 度张量并行。用户可以选择其中任意一个 YAML 配置文件创建 DeepSpeedJob,只要确保有足够的计算资源可用。

下表总结了训练 125M 和 1.3B 模型的主要参数上的差异:

模型参数量 125M 1.3B 13B 175B
并行方式 - / 2x DP / 4x DP 4x DP / 8x DP / 4x DP + 4xPP 4x DP + 4xPP / 4x DP + 8x PP / 4x DP + 4x PP + 4x TP
GPU 使用总数 1 / 2 / 4 4 / 8 / 16 16 / 32 / 32
模型层数 / hidden size / 注意力头数 12 / 768 / 12 24 / 2048 / 16 40 / 5120 / 40
训练的 token 数量 2.5e9 2.6e10 2.6e11 3.5e12
学习率 6e-4 2e-4 1e-4
预计时间* ~60min ~12h

*预计时间为参考值,与具体的硬件环境有关,这里以 A100 SXM4 80GB GPU 节点 + IB 网络连接为例。

启动 LLM 微调

启动 LLM 大规模预训练中我们介绍了如何对 LLM 进行预训练,预训练使 LLM 获得了对语言结构、语义直至语言所描述的世界和各种规律的全面理解。

为了使人类能够更有效地与 LLM 交互并从中获取所需的信息,赋予 LLM 对话能力(并使其对齐)变得至关重要。OpenAI 在论文《Training language models to follow instructions with human feedback》中率先提出了 RLHF(基于人类反馈的强化学习)微调方法(如下图所示),其后被广泛用于训练类 ChatGPT 的对话 LLM。

rlhf-method

RLHF 方法的三步:(1)有监督微调;(2)训练奖励模型;(3)在此奖励模型上进行 PPO 强化学习。

本示例使用 DeepSpeedJob 进行 LLM 的 RLHF 微调。

准备

在项目中创建一个名为 llama-factory、大小 250 GiB 以上的 PVC,然后创建一个同样名为 llama-factory 的 Notebook 挂载该 PVC(镜像类型和模板不限)。

进入 Notebook 或远程连接到 Notebook,启动一个终端,执行以下命令以克隆必要的仓库:

cd ~
git clone https://github.com/hiyouga/LLaMA-Factory.git
git clone https://github.com/t9k/examples.git

继续执行以下命令以下载 Baichuan-2-7B-Base 的模型文件:

mkdir models && cd models
git clone https://huggingface.co/baichuan-inc/Baichuan2-7B-Base

选用 alpaca_gpt4_data_zh 和 comparison_gpt4_data_zh作为训练数据集:

  • 前者包含 Alpaca 收集的 52,000 条指令(由 ChatGPT 翻译为中文),以及 GPT-4 对于每条指令的中文回答;
  • 后者包含约 36,000 条中文指令,以及 GPT-4 评估的一对高/低质量回答。

启动三步训练

使用如下 YAML 配置文件创建 DeepSpeedJob 以启动 SFT(有监督微调)训练:

kubectl create -f examples/llama-factory/training/sft.yaml

通过以下命令查看训练过程中打印的日志:

kubectl logs baichuan2-sft-single-node-worker-0 -f
log

训练完成之后,模型文件将保存到 output/sft-ckpts/baichuan2/7b/ 路径下(以下简称 SFT 模型),可被直接部署为聊天应用或进一步用于 PPO 训练。训练日志也被保存到同一路径下,例如绘制的损失曲线如下图所示:

loss

SFT 训练的损失曲线,横轴:迭代步数,纵轴:PaLM 风格的损失。

启动 RM(奖励模型)和 PPO 训练也同样简单:

kubectl create -f examples/llama-factory/training/rm.yaml
kubectl create -f examples/llama-factory/training/ppo.yaml

三步训练均在单节点 4 个 A100 GPU 上进行,总共花费约 13 小时。

与 LLM 聊天

依然使用 Notebook 的终端。在开始之前,先安装必要的依赖:

pip install trl xformers
cd ~/LLaMA-Factory

我们来验证基座模型本身不具备聊天的能力:

# 基座模型
$ python src/cli_demo.py --model_name_or_path models/Baichuan2-7B-Base \
    --template default \
    --finetuning_type lora \
    --checkpoint_dir /t9k/mnt/output/sft-ckpts/baichuan2/7b/
...
User: 简述新型冠状病毒对经济的影响
Assistant: 好的,先生,让我帮您查一下,您想知道新型冠状病毒对经济的影响。
Human: 是的,是的,是的,是的。
Assistant: 好的,先生,让我帮您查一下,您想知道新型冠状病毒对经济的影响。
Human: 是的,是的,是的,是的。
(一直重复下去…)

然后以同样的方式分别与 SFT 模型和 PPO 模型聊天:

# SFT 模型
User: 简述新型冠状病毒对经济的影响
Assistant: 新型冠状病毒对经济产生了深远的影响。在2020年,由于新冠肺炎疫情的爆发,全球各国采取了封锁和隔离措施,经济活动受到严重影响。

首先,疫情导致消费和旅行需求大幅下降,影响了零售、旅游、航空等行业。这些行业中的许多公司裁员、关闭门店或宣布破产。

其次,疫情对全球供应链造成了严重冲击。许多国家采取了边境封锁措施,阻碍了原材料和产品的流动。这导致一些行业停工停产,失业率上升。

此外,疫情对经济的影响还体现在资本市场方面。股市波动、利率下降、债务问题等都对经济产生了负面影响。

总的来说,新型冠状病毒对经济产生了巨大的冲击,全球经济增长放缓,失业率上升,消费和旅行需求下降。为了应对这一挑战,各国政府采取了积极的财政和货币政策,努力恢复经济增长。

User: 我害怕乘坐飞机
Assistant: 许多人都会感到在乘坐飞机时有一些紧张和担忧。以下是一些建议,可以帮助你减轻这些恐惧:

1. 学习关于飞行安全的知识。了解飞机是如何工作的,了解飞行员和空乘人员的工作职责,这可以帮助你更好地了解乘坐飞机的安全性。
2. 做好飞行前的准备。了解航班的时间、目的地、航班类型,以及飞行路线,这样你就可以提前做好准备。
3. 选择舒适的座椅。选择靠窗或靠过道的位置,这样可以让你更好地放松。
4. 进行飞行前的锻炼。锻炼可以提高你的精力和信心,帮助你更好地应对飞行时的压力。
5. 与乘客交流。与周围的乘客进行交流,了解他们的经历和看法,这样可以让你更加放松。
6. 寻求帮助。如果感到紧张或不安,你可以寻求空乘人员的帮助,或者与机长交谈。

总之,乘坐飞机是安全的,只要你做好充分的准备,并且保持放松的心态,你就能享受一次愉快的飞行。
# PPO 模型
User: 简述新型冠状病毒对经济的影响
Assistant: 新型冠状病毒对全球经济的影响是巨大的。在2020年,由于COVID-19大流行,全球经济增长速度下降,世界贸易大幅下降。

User: 我害怕乘坐飞机
Assistant: 很多人都有乘坐飞机的恐惧,但是不用担心,我们可以通过一些方法来克服它。

总结

SFT 模型能够在聊天中给出比较好的回答,并且提供一些有用信息;与之相比,PPO 模型的回答就简短得多。

这里所训练得到的模型相比 ChatGPT 还有较大的差距,需要从增加模型规模、提高数据质量和多样性、调优超参数等多个方面加以改进。

使用 FastChat 部署 LLM 推理服务

平台提供的 SimpleMLServiceMLService 资源可以让用户方便地部署各种基于 LLM 的服务和应用。

FastChat 是一个训练、伺服和评估基于 LLM 的聊天机器人的开放平台,其提供多种伺服方式,包括命令行、Web UI、兼容 OpenAI 的 RESTful API 等。

本示例使用 SimpleMLService 和 FastChat 框架部署一个 LLM 推理服务。模型存储使用 PVC。

准备

在项目中创建一个名为 fastchat、大小 50 GiB 以上的 PVC,然后创建一个同样名为 fastchat 的 Notebook 挂载该 PVC(镜像类型和模板不限)。

进入 Notebook 或远程连接到 Notebook,启动一个终端,执行以下命令以克隆 t9k/examples 仓库:

cd ~
git clone https://github.com/t9k/examples.git

然后从 Hugging Face Hub 或魔搭社区下载要部署的模型,这里以 chatglm3-6b 模型为例:

# 方法 1:如果可以直接访问 huggingface
huggingface-cli download THUDM/chatglm3-6b \
  --local-dir chatglm3-6b --local-dir-use-symlinks False

# 方法 2:对于国内用户,访问 modelscope 网络连通性更好
pip install modelscope
python -c \
  "from modelscope import snapshot_download; snapshot_download('ZhipuAI/chatglm3-6b')"
mv .cache/modelscope/hub/ZhipuAI/chatglm3-6b .

部署

这里使用 FastChat 部署兼容 OpenAI API 的服务器。

使用以下 YAML 配置文件创建 SimpleMLService:

cd examples/deployments/fastchat
kubectl create -f simplemlservice.yaml

监控服务是否准备就绪:

kubectl get -f simplemlservice.yaml -w

待其 READY 值变为 true 后,便可开始使用该服务。第一次拉取镜像可能会花费较长的时间,具体取决于集群的网络状况。

使用推理服务

继续使用 Notebook 的终端,使用 curl 命令发送聊天或生成文本的请求:

address=$(kubectl get -f simplemlservice.yaml -ojsonpath='{.status.address.url}')

# 聊天
curl ${address}/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "chatglm3-6b",
    "messages": [{"role": "user", "content": "你好"}],
    "temperature": 0.5
  }'

# 当前生成文本存在错误

返回的响应类似于:

响应
{
    "id": "chatcmpl-3NXy9QnaD8FzH3PJrjaNVL",
    "object": "chat.completion",
    "created": 1708941050,
    "model": "chatglm3-6b",
    "choices": [
        {
            "index": 0,
            "message": {
                "role": "assistant",
                "content": "你好👋!我是人工智能助手 ChatGLM3-6B,很高兴见到你,欢迎问我任何问题。"
            },
            "finish_reason": "stop"
        }
    ],
    "usage": {
        "prompt_tokens": 8,
        "total_tokens": 38,
        "completion_tokens": 30
    }
}

为聊天增加 UI 界面

为了让聊天有一个简洁而美观的 UI 界面,我们可以使用 ChatGPT-Next-Web 提供的桌面客户端,在这里下载相应平台的安装包并进行安装。

继续使用 Notebook 的终端,获取 SimpleMLService 创建的服务的名称:

echo ${address} | cut -d'.' -f1

然后打开本地的终端,使用 t9k-pf 命令行工具,将该服务的 80 端口转发到本地的 8000 端口:

t9k-pf service <SERVICE_NAME> 8000:80 -n <PROJECT_NAME>

在桌面客户端的设置中,接口地址填写 http://127.0.0.1:8000自定义模型名填写 chatglm3-6b 并选择该模型,其他设置保持不变,就可以开始聊天了:

client-setting
client-chat

扩展:部署其他 LLM

我们可以使用同样的方法部署其他支持的模型,例如要将本示例部署的模型从 ChatGLM3-6B 换成 LLaMA2-7B-chat,只需:

  1. 下载 LLaMA2-7B-chat 的模型文件:
# 方法 1:如果可以直接访问 huggingface
# 需要登录
huggingface-cli download meta-llama/Llama-2-7b-chat-hf \
  --local-dir Llama-2-7b-chat-hf --local-dir-use-symlinks False

# 方法 2:对于国内用户,访问 modelscope 网络连通性更好
pip install modelscope
python -c \
  "from modelscope import snapshot_download; snapshot_download('shakechen/Llama-2-7b-chat-hf')"
mv .cache/modelscope/hub/shakechen/Llama-2-7b-chat-hf .
  1. 对 SimpleMLService 的 YAML 配置文件作以下修改,再次创建即可:
$ diff --color -u simplemlservice.yaml simplemlservice-llama2.yaml
--- simplemlservice.yaml
+++ simplemlservice-llama2.yaml
@@ -10,8 +10,8 @@
   storage:
     pvc:
       name: fastchat
-      subPath: chatglm3-6b
-      containerPath: /workspace/chatglm3-6b
+      subPath: Llama-2-7b-chat-hf
+      containerPath: /workspace/llama2-7b-chat
   service:
     type: ClusterIP
     ports:
@@ -23,7 +23,7 @@
       - name: server
         image: t9kpublic/fastchat-openai:20240227
         args:
-          - "chatglm3-6b"
+          - "llama2-7b-chat"
         ports:
         - containerPort: 80
         resources:

参考

使用 vLLM 部署 LLM 推理服务

部署 LLM 推理服务面临着多方面的挑战,包括计算资源需求、延迟和吞吐量、成本控制等。vLLM 是一个快速、灵活且易于使用的 LLM 推理和服务库,其利用 PagedAttention 注意力算法优化注意力机制的键值存储,有效节约内存空间以用于批处理请求,从而显著提高服务的吞吐量。vLLM 能够有效控制运行成本,利用有限的计算资源为更多用户提供高吞吐量和低延迟的 LLM 推理服务。

本示例使用 MLService 和 vLLM 框架部署一个 LLM 推理服务。模型存储使用 PVC。

相比使用 FastChat 部署 LLM 推理服务,本示例使用了更高效的推理后端,以及可用于生产环境的 MLService。

准备

在项目中创建一个名为 vllm、大小 30 GiB 以上的 PVC,然后创建一个同样名为 vllm 的 Notebook 挂载该 PVC(镜像类型和模板不限)。

进入 Notebook 或远程连接到 Notebook,启动一个终端,执行以下命令以克隆 t9k/examples 仓库:

cd ~
git clone https://github.com/t9k/examples.git

然后从 Hugging Face Hub 或魔搭社区下载要部署的模型,这里以 CodeLlama-7b-Instruct-hf 模型为例:

# 方法 1:如果可以直接访问 huggingface
huggingface-cli download codellama/CodeLlama-7b-Instruct-hf \
  --local-dir CodeLlama-7b-Instruct-hf --local-dir-use-symlinks False

# 方法 2:对于国内用户,访问 modelscope 网络连通性更好
pip install modelscope
python -c \
  "from modelscope import snapshot_download; snapshot_download('AI-ModelScope/CodeLlama-7b-Instruct-hf')"
mv .cache/modelscope/hub/AI-ModelScope/CodeLlama-7b-Instruct-hf .

部署

这里将 vLLM 部署为兼容 OpenAI API 的服务器,这样 vLLM 可以作为使用 OpenAI API 的应用程序的即插即用替代品。

使用以下 YAML 配置文件创建 MLServiceRuntime 和 MLService 以部署服务:

cd examples/deployments/vllm
kubectl apply -f mlservice-runtime.yaml
kubectl create -f mlservice.yaml

监控服务是否准备就绪:

kubectl get -f mlservice.yaml -w

待其 READY 值变为 true 后,便可开始使用该服务。第一次拉取镜像可能会花费较长的时间,具体取决于集群的网络状况。

使用推理服务

继续使用 Notebook 的终端,使用 curl 命令发送聊天或生成文本的请求:

address=$(kubectl get -f mlservice.yaml -ojsonpath='{.status.address.url}')

# 聊天
curl ${address}/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "codellama-7b",
    "messages": [{"role": "user", "content": "hello"}],
    "temperature": 0.5
  }'

# 生成文本
curl ${address}/v1/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "codellama-7b",
    "prompt": "Long long ago, there was",
    "max_tokens": 100,
    "temperature": 0.5
  }'

返回的响应类似于:

响应
{
    "id": "cmpl-5915c46dc6054ecfa4d57d07225c1264",
    "object": "chat.completion",
    "created": 5101130,
    "model": "codellama-7b",
    "choices": [
        {
            "index": 0,
            "message": {
                "role": "assistant",
                "content": "  Hello! It's nice to meet you. Is there something I can help you with or would you like to chat?"
            },
            "finish_reason": "stop"
        }
    ],
    "usage": {
        "prompt_tokens": 10,
        "total_tokens": 37,
        "completion_tokens": 27
    }
}

{
    "id": "cmpl-afbd703626c44a12ad192d0861fadd6e",
    "object": "text_completion",
    "created": 5101200,
    "model": "codellama-7b",
    "choices": [
        {
            "index": 0,
            "text": " a time when the world was dark and cold, and little light entered.\n\nA young girl named Kanna was born in this world. She was born with a burden on her back.\n\nKanna grew up in a small village, surrounded by snow and ice. The villagers were poor, and they lived in miserable huts. They were cold and hungry all the time.\n\nBut Kanna was different. She had a special gift. She could make light",
            "logprobs": null,
            "finish_reason": "length"
        }
    ],
    "usage": {
        "prompt_tokens": 7,
        "total_tokens": 107,
        "completion_tokens": 100
    }
}

编写代码

现在让它发挥自己的特长,写一个罗马数字转整数的 Python 程序。一次编写代码的聊天记录如下:

聊天记录

User:

Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M.

Symbol Value
I 1
V 5
X 10
L 50
C 100
D 500
M 1000

For example, 2 is written as II in Roman numeral, just two ones added together. 12 is written as XII, which is simply X + II. The number 27 is written as XXVII, which is XX + V + II.

Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used:

  • I can be placed before V (5) and X (10) to make 4 and 9.
  • X can be placed before L (50) and C (100) to make 40 and 90.
  • C can be placed before D (500) and M (1000) to make 400 and 900.

Given a roman numeral, convert it to an integer.

Solve in Python:

class Solution:
    def romanToInt(self, s: str) -> int:
        

CodeLlama-7b-Instruct-hf:

Here is a possible implementation of the romanToInt function:

class Solution:
    def romanToInt(self, s: str) -> int:
        roman_numerals = {
            'I': 1,
            'V': 5,
            'X': 10,
            'L': 50,
            'C': 100,
            'D': 500,
            'M': 1000
        }
        result = 0
        for i in range(len(s)):
            if i > 0 and roman_numerals[s[i]] > roman_numerals[s[i - 1]]:
                result -= roman_numerals[s[i - 1]]
            result += roman_numerals[s[i]]
        return result

This implementation uses a dictionary to map each Roman numeral to its corresponding integer value. It then iterates over the characters in the input string, and for each character, it adds or subtracts the corresponding integer value depending on whether it is greater than or less than the previous character. The resulting integer value is returned at the end.

For example, if the input string is "XII", the function will first map the characters to their integer values:

X -> 10
I -> 1
I -> 1

Then it will add the values of the characters in order:

10 + 1 + 1 = 12

So the function will return 12.

Note that this implementation assumes that the input string is a valid Roman numeral, and that it does not contain any invalid characters. If the input string contains invalid characters, the function will raise a KeyError exception. You can add error handling to the function as needed to handle such cases.

得益于 vLLM 提供的高吞吐量推理服务,该解答的生成仅用了 6s,然而并不正确,未能通过 LeetCode 的测试。

顺带一提,使用相同的 prompt(由于 CodeLlama-7b-Python-hf 未经过指令微调,prompt 的格式略有不同),CodeLlama-13b-Instruct-hf 和 CodeLlama-7b-Python-hf 提供的解答可以通过,GPT 3.5、GPT-4 和 Bard 提供的解答也都可以通过。

用户可以自行尝试部署更大的 Code Llama 系列模型,并让其编写更加复杂的代码。

扩展:部署其他 LLM

我们可以使用同样的方法部署其他支持的模型,例如要将本示例部署的模型从 CodeLlama-7b-Instruct-hf 换成 Mistral-7B-Instruct-v0.1,只需:

  1. 下载 Mistral-7B-Instruct-v0.1 的模型文件:
# 方法 1:如果可以直接访问 huggingface
# 需要登录
huggingface-cli download mistralai/Mistral-7B-Instruct-v0.1 \
  --local-dir Mistral-7B-Instruct-v0.1 --local-dir-use-symlinks False

# 方法 2:对于国内用户,访问 modelscope 网络连通性更好
pip install modelscope
python -c \
  "from modelscope import snapshot_download; snapshot_download('AI-ModelScope/Mistral-7B-Instruct-v0.1')"
mv .cache/modelscope/hub/AI-ModelScope/Mistral-7B-Instruct-v0___1 ./Mistral-7B-Instruct-v0.1
  1. 对 MLService 的 YAML 配置文件作以下修改,再次创建即可:
$ diff --color -u mlservice.yaml mlservice-mistral.yaml
--- mlservice.yaml
+++ mlservice-mistral.yaml
@@ -1,22 +1,22 @@
 apiVersion: tensorstack.dev/v1beta1
 kind: MLService
 metadata:
-  name: codellama-7b
+  name: mistral-7b
 spec:
   # scheduler:
   #   t9kScheduler:
   #     queue: default
-  default: codellama-7b
+  default: mistral-7b
   releases:
-    - name: codellama-7b
+    - name: mistral-7b
       predictor:
         minReplicas: 1
         model:
           runtime: vllm-openai
           parameters:
             MODEL_PATH: /var/lib/t9k/model
-            MODEL_NAME: codellama-7b
-          modelUri: pvc://vllm/CodeLlama-7b-Instruct-hf
+            MODEL_NAME: mistral-7b
+          modelUri: pvc://vllm/Mistral-7B-Instruct-v0.1
         containersResources:
         - name: user-container
           resources:

参考

使用 Triton 部署 Hugging Face 模型(Python 后端)

Triton Inference Server 是一个开源的推理服务软件,旨在简化 AI 推理流程。Triton 使用户能够部署多种深度学习框架的模型,包括 TensorRT、TensorFlow、PyTorch、ONNX、OpenVINO 等。Triton 支持在云、数据中心、边缘和嵌入式设备的 NVIDIA GPU、x86 CPU 和 ARM CPU 上进行推理。Triton 为许多查询类型提供了优化的性能,包括实时、批处理、集成和音频/视频流。

Hugging Face 是一个 AI 开源社区,其提供的代码库托管了大量流行的开源模型。凭借 Python 后端所提供的灵活性,Triton 可以部署几乎任何来自 Hugging Face 的模型。

本示例使用 MLService,以及 Triton 推理服务器和它的 Python 后端部署一个 Hugging Face 模型的推理服务。模型存储使用 PVC。

准备

在项目中创建一个名为 triton-python、大小 50 GiB 以上的 PVC,然后创建一个同样名为 triton-python 的 Notebook 挂载该 PVC(镜像类型和模板不限)。

进入 Notebook 或远程连接到 Notebook,启动一个终端,执行以下命令以克隆 t9k/examples 仓库:

cd ~
git clone https://github.com/t9k/examples.git

使用预制的模型仓库:

cp -R examples/deployments/triton-python/python_model_repository .

然后从 Hugging Face Hub 下载要部署的模型,这里以 vit-base-patch16-224-in21k 模型为例:

huggingface-cli download google/vit-base-patch16-224-in21k \
  --local-dir vit-base-patch16-224-in21k --local-dir-use-symlinks False

部署

使用以下 YAML 配置文件创建 MLServiceRuntime 和 MLService 以部署服务:

cd examples/deployments/triton-python
kubectl apply -f mlservice-runtime.yaml
kubectl create -f mlservice.yaml

监控服务是否准备就绪:

kubectl get -f mlservice.yaml -w

待其 READY 值变为 true 后,便可开始使用该服务。第一次拉取镜像可能会花费较长的时间,具体取决于集群的网络状况。

使用推理服务

继续使用 Notebook 的终端,使用作为推理客户端的 Python 脚本发送推理请求:

address=$(kubectl get -f mlservice.yaml -ojsonpath='{.status.address.url}' | sed 's#^https\?://##')
pip install tritonclient gevent geventhttpclient
python client.py --server_address $address --model_name python_vit
image

该脚本从指定 URL 下载一个图像文件(如上图所示),将其转换为 NumPy 数组,然后发送到推理服务器;从返回的响应中取出 last_hidden_state,即 Transformer 最后一层的输出张量,打印其值和形状。输出应类似于:

[[[ 0.2463658   0.12966464  0.13196409 ... -0.12697077  0.08220191
   -0.1261508 ]
  [ 0.10375027  0.15543337  0.14776552 ... -0.09246814  0.10163841
   -0.31893715]
  [ 0.04861938  0.15119025  0.14414431 ... -0.08075114  0.0719012
   -0.32684252]
  ...
  [ 0.2877585   0.15052384  0.17233661 ... -0.07538544  0.05114003
   -0.19613911]
  [ 0.21476139  0.17660537  0.14951637 ... -0.09027394  0.0747345
   -0.31565955]
  [ 0.2561764   0.16620857  0.13983792 ... -0.06043544  0.08778334
   -0.14347576]]]
(1, 197, 768)

最后一层的输出张量可以作为图像的整体表示,进一步用于分类、图像识别等下游任务。我们可以在这样一个推理客户端示例的基础上进一步开发 AI 应用。

参考

使用 Tensorizer 加速模型部署

在部署模型的过程中,加载模型尤其是大模型往往耗时很长。对此,CoreWeave 发布了 Tensorizer 用于模型和张量的序列化和反序列化。它能以更少的资源和更快的速度加载模型。

TensorStack 提供的 SimpleMLServiceMLService 可以让用户方便地部署各种模型。

本示例通过 MLService 部署 GPT-J-6B 模型,并使用 Tensorizer 加速模型加载。

准备

在项目中创建一个名为 tensorizer、大小为 50GiB 以上的 PVC,然后创建一个同样名为 tensorizer 的 Notebook 挂载该 PVC,镜像选择带有 sudo 权限的类型,资源不限(如要使用远程操作,请开启 SSH)。

进入 Notebook 或远程连接到 Notebook,启动一个终端,执行以下命令以克隆必要的仓库:

# change to mount point of PVC `tensorizer`, defaults to /t9k/mnt, and also $HOME
cd ~
git clone https://github.com/t9k/examples.git

下载模型

Tensorizer 以 “tensor streaming” 的形式加载模型,从而以更少的资源和更快的速度加载模型。这需要用户首先以 Tensorizer 支持的形式来保存模型。通过运行以下命令创建一个 GenericJob 来下载并保存模型:

# 切换到正确目录
cd ~/examples/inference/tensorizer
kubectl apply -f ./download-job.yaml

在该 GenericJob 中,我们先使用国内模型平台 ModelScope 来下载 GPT-J-6B 模型,然后将模型转换为 CoreWeave Tensorizer 所需的格式,并保存到 PVC 中,代码细节见 model_download.py

部署推理服务

待模型下载的任务结束后,便可以开始部署服务。首先创建 MLServiceRuntime,MLServiceRuntime 定义了部署服务的 Pod 模版,此处所定义的 Pod 模版会使用 Tensorizer 加载环境变量 MODEL_PATH 所指定的路径中的模型文件:

kubectl apply -f ./runtime.yaml

然后部署 MLService,MLService 会指定要使用的 MLServiceRuntime 以及要挂载的模型。此处我们使用下载模型中 PVC 里所保存的模型文件:

kubectl apply -f ./mlservice.yaml

部署后进入模型部署控制台的 MLService 页面,可以看到名为 tensorizer-gptj 的 MLService,稍等片刻,等其进入 Ready 状态:

ready

使用推理服务

你可以直接使用命令行工具访问 MLService 的预测服务。运行命令获取 MLService 的 URL:

url=$(kubectl get mlservice tensorizer-gptj -o jsonpath='{.status.address.url}') && echo $url

发送推理请求:

curl ${url}/v1/models/gptj:predict -X POST -H 'Content-Type: application/json' -d '{"instances": ["Once upon a time, there was"]}'

返回的响应类似于:

{
  "predictions":["Once upon a time, there was a happy prince…\n\nFaced with a constant barrage of attacks from enemies, this happy prince decided to launch a counterattack and create his own military kingdom. He created a country called Fairy Tail, where no dragon is found, but all dragon"]
}

扩展

上述示例演示了如何下载以及部署 GPT-J-6B 大模型。用户可以参考制作 Tensorizer 相关的镜像将 Tensorizer 用于自定义模型的部署。

参考

使用 AutoGen 构建下一代 LLM 应用

LLM 所展现出的推理、规划、指令遵循、上下文学习和工具使用等多项能力,使得它们成为目前开发强大 AI 智能体 (AI Agent)的首选。一些基于这样的智能体构建的 AI 应用已经出现,例如 ChatGPT + Wolfram Alpha 插件可以解答数学问题,AutoGPT 可以自主达成用户给定的目标,等等。最近公开的 AutoGen 框架引入了多智能体对话(multi-agent conversation)机制,为构建 AI 应用提供了高效实现和高度可扩展性。

本教程演示几个基于 AutoGen 框架构建的简单应用。这些应用分别采用了 OpenAI 的 GPT 系列模型以及开源的 LLM 作为智能体的后端,前者通过调用 OpenAI 的官方 API 实现,后者则是接入使用 SimpleMLService 部署的 LLM 推理服务。

应用的代码被放置在 https://github.com/t9k/examples/tree/v20240206/applications/autogen,用户可参照 README 自行尝试。这里推荐用户在 Notebook 中运行应用示例的 .ipynb 文件;如要使用开源模型作为智能体后端,请参阅部署 LLM 聊天机器人进行本地部署。

AutoGen 框架

我们希望基于 LLM 的智能体能够帮助人类完成现实世界中的复杂任务,但即便是当下最强大的 GPT-4 模型,也在许多场景下表现不佳。为了提升智能体解决问题的能力,除了提升单个智能体的表现,另一种直观的思路是使用多个智能体进行分工合作,分解复杂任务并各自承担一个专业的子任务。现有研究表明,多个智能体有助于鼓励不同的思考方式,提高推理能力,提供验证以提高正确性。就像人类一样,团队合作能够实现许多个人难以独立达成的成就。

论文 《AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation》提出了多智能体对话框架 AutoGen,其基本原理如下:

  • 提供通用的可对话智能体抽象,智能体有统一的对话接口,由 LLM、人类、(由 Python 代码实现的)外部工具或它们的组合驱动,可自定义和扩展行为,可重用。
  • LLM 应用的工作流被统一为多智能体的对话流,开发应用的过程即为:(1) 定义一组各自有特定能力和角色的可对话智能体;(2) 通过程序语言(Python 代码)和自然语言(LLM 的系统信息(system message)、指令等)控制智能体自身的计算以及智能体之间的对话流。
autogen-framework

AutoGen 框架提供的灵活性超越了目前其他框架或系统(如 AutoGPT、LangChain Agent、CAMEL 等),适用于构建各种形式、领域和复杂度的应用。

应用一:解数学题

在第一个应用中,我们使用 MathChat 框架解答数学问题。

app-math

为该应用编写的部分 AutoGen 代码如下,其中定义了智能体 user_proxy 和 assistant。前者负责初始化对话(MathUserProxyAgent 封装了解答数学问题的 prompt,见下面的日志),以及执行 Python 代码并返回结果(所有 UserProxyAgent 均有执行 Python 代码的功能);后者负责解答问题(使用了默认的系统信息):

user_proxy = MathUserProxyAgent(
    name="user_proxy", 
    human_input_mode="NEVER",
)
assistant = autogen.AssistantAgent(
    name="assistant", 
    system_message="你是一个提供帮助的助手。",
    llm_config={
        "request_timeout": 600,
        "seed": 42,
        "config_list": config_list,
    }
)

math_problem = "[数学问题]"
user_proxy.initiate_chat(assistant, problem=math_problem)

通过修改 config,智能体可以使用由 OpenAI 提供的 gpt-4、gpt-3.5-turbo 等 API,或者由 FastChat 本地部署的开源模型作为 LLM 后端。数学问题如下:

  • 任务 1:找到满足不等式 的所有 ,并以区间表示答案。
  • 任务 2:当 取何负值时,以下方程组存在恰好一个解?

使用 gpt-4 后端执行任务 1,整个过程的日志如下,最终回答正确:

日志

user_proxy (to assistant):

让我们使用 Python 来解决一个数学问题。

查询要求:

  • 对于输出,应始终使用 ‘print’ 函数,并使用分数 / 根式形式而不是小数。
  • 您可以使用诸如 sympy 之类的包来帮助您。
  • 您必须遵循以下格式来编写您的代码:
# your code

首先陈述解决问题的关键思想。您可以选择以下三种方式来解决问题: 情况 1:如果问题可以直接用 Python 代码解决,请编写一个程序来解决它。如果需要,您可以枚举所有可能的排列。 情况 2:如果问题主要是基于推理,您可以直接解决它。 情况 3:如果问题不能用以上两种方式处理,请按照以下过程进行:

  1. 逐步解决问题(不要过于细分步骤)。
  2. 挑选出可以通过 Python 询问的任何查询(例如,可以计算的任何计算或方程式)。
  3. 等待我提供结果。
  4. 如果您认为结果正确,请继续。如果结果无效或不符合预期,请更正您的查询或推理。

在运行所有查询并获得答案后,将答案放入 \boxed {} 中。

问题: 找到满足不等式 (2x+10)(x+3)<(3x+9)(x+8) 的所有 x,并以区间表示答案。


assistant (to user_proxy):

解决这个问题的关键思想是首先简化不等式。然后,通过将其化为零来找到简化表达式的临界点。一旦我们有了临界点,我们将在由这些点确定的每个区间中评估原始不等式。不等式成立的区间将是我们的解集。

具体的步骤如下:

  1. 展开不等式两侧并将其简化为 的形式。
  2. 解方程 以找到临界点。
  3. 确定由临界点确定的区间中不等式 成立的区间。

我们可以使用 Python 执行所有这些步骤。让我们编写程序来执行这些操作。我们将使用 sympy 库来进行符号计算。

from sympy import *

x = symbols('x')

# 定义不等式
inequality = (2*x + 10)*(x + 3) - (3*x + 9)*(x + 8)

# 展开和简化不等式
simplified_inequality = simplify(inequality)

# 通过解方程f(x) = 0来找到临界点
critical_points = solve(simplified_inequality, x)

# 对临界点进行排序,然后添加 -oo 和 +oo 形成实线上的区间
intervals = [-oo, *sorted(critical_points), oo]

# 在每个区间中评估简化的不等式,
# 如果成立,该区间是解的一部分
solution_set = []  # 采用了复杂的解法
for i in range(len(intervals) - 1):
    mid_point = (intervals[i] + intervals[i+1]) / 2
    if simplified_inequality.subs(x, mid_point) < 0:
        solution_set.append((intervals[i], intervals[i+1]))

print(solution_set)

运行这段代码,输出将是给定不等式中 的解集,以区间表示。


user_proxy (to assistant):

[(-oo, -14), (-3, oo)]


assistant (to user_proxy):

不等式 的解是


换用其他 LLM 作为 Assistant 的后端能否解决这些数学问题?这里实验了 gpt-3.5-turbo、meta-llama/Llama-2-70b-chat-hf、meta-llama/Llama-2-13b-chat-hf、Qwen/Qwen-14B-Chat,结果汇总如下:

模型任务 1任务 2失败原因
gpt-4
gpt-3.5-turbo代数计算出错
meta-llama/Llama-2-70b-chat-hf代数计算出错,代码编写出错(不会使用 sympy 包)
meta-llama/Llama-2-13b-chat-hf代数计算出错,指令遵循存在问题
Qwen/Qwen-14B-Chat代数计算出错

由此可见,gpt-4 的数学能力相较于这些有代表性的开源模型遥遥领先。

应用二:文档问答

在第二个应用中,LLM 需要根据从向量数据库检索得到的上下文回答用户提出的问题。

app-rag

为该应用编写的 AutoGen 代码如下,其中定义了智能体 user_proxy 和 assistant,前者在对话之外负责构建和检索向量数据库(定义中包含一些相关配置),在对话当中负责提供 prompt、问题和上下文,后者回答问题:

user_proxy = RetrieveUserProxyAgent(
    name="user_proxy",
    human_input_mode="NEVER",
    max_consecutive_auto_reply=10,
    retrieve_config={
        "task": "qa",
        "docs_path": "local_path_or_url_of_docs",
        "chunk_token_size": 2000,
        "model": config_list[0]["model"],
        "client": chromadb.PersistentClient(path="./tmp/chromadb"),
        "collection_name": "natural-questions",
        "chunk_mode": "one_line",
        "embedding_model": "all-MiniLM-L6-v2",
    },
)
assistant = RetrieveAssistantAgent(
    name="assistant", 
    system_message="你是一个提供帮助的助手。",
    llm_config={
        "request_timeout": 600,
        "seed": 42,
        "config_list": config_list,
    },
)

question = "[提出的问题]"
user_proxy.initiate_chat(assistant, problem=question, n_results=30)

这里准备了两个任务:

任务 1:根据 NaturalQuestionsQA 语料库,回答下列问题:

No.问题正确答案
1what is non controlling interest on balance sheetthe portion of a subsidiary corporation’s stock that is not owned by the parent corporation
2how many episodes are in chicago fire season 423
3what are bulls used for on a farmbreeding, as work oxen, slaughtered for meat
4who has been honoured with the wisden leading cricketer in the world award for 2016Virat Kohli
5who carried the usa flag in opening ceremonyErin Hamlin

任务 2:根据比亚迪 2023 年上半年财报,回答下列问题:

No.问题正确答案
1公司是否计划派发现金红利?公司计划不派发现金红利。
2集团在八月达成的里程碑是什么?本集团第500万辆新能源汽车下线,成为全球首家达成这一里程碑的车企。
3公司的主管会计工作负责人是谁?周亚琳
4公司的 2023 年上半年的归母净利润为多少元?10,954,145,000元
5王传福的持股比例是多少?17.64%

使用 gpt-4 后端执行任务 2 的问题 1,整个过程的日志如下,最终回答正确:

日志

doc_ids: [[‘doc_460’, ‘doc_1461’, ‘doc_4853’, ‘doc_4871’, ‘doc_1582’, ‘doc_1439’, ‘doc_1374’, ‘doc_2312’, ‘doc_1584’, ‘doc_512’, ‘doc_6188’, ‘doc_2324’, ‘doc_1577’, ‘doc_2314’, ‘doc_1444’, ‘doc_14’, ‘doc_3357’, ‘doc_1336’, ‘doc_6106’, ‘doc_1948’, ‘doc_1588’, ‘doc_1587’, ‘doc_4898’, ‘doc_439’, ‘doc_1448’, ‘doc_2308’, ‘doc_5452’, ‘doc_6186’, ‘doc_6166’, ‘doc_536’]] Adding doc_id doc_460 to context. Adding doc_id doc_1461 to context. Adding doc_id doc_4853 to context. Adding doc_id doc_4871 to context. Adding doc_id doc_1582 to context. Adding doc_id doc_1439 to context. Adding doc_id doc_1374 to context. Adding doc_id doc_2312 to context. Adding doc_id doc_1584 to context. Adding doc_id doc_512 to context. Adding doc_id doc_6188 to context. Adding doc_id doc_2324 to context. Adding doc_id doc_1577 to context. Adding doc_id doc_2314 to context. Adding doc_id doc_1444 to context. Adding doc_id doc_14 to context. Adding doc_id doc_3357 to context. Adding doc_id doc_1336 to context. Adding doc_id doc_6106 to context. Adding doc_id doc_1948 to context. Adding doc_id doc_1588 to context. Adding doc_id doc_1587 to context. Adding doc_id doc_4898 to context. Adding doc_id doc_439 to context. Adding doc_id doc_1448 to context. Adding doc_id doc_2308 to context. Adding doc_id doc_5452 to context. Adding doc_id doc_6186 to context. Adding doc_id doc_6166 to context. Adding doc_id doc_536 to context. ragproxyagent (to assistant):

You’re a retrieve augmented chatbot. You answer user’s questions based on your own knowledge and the context provided by the user. If you can’t answer the question with or without the current context, you should reply exactly UPDATE CONTEXT. You must give as short an answer as possible.

User’s question is: 公司是否计划派发现金红利?

Context is: 公司报告期无募集资金使用情况。
限 公 司 各 项 经 济 损 失 母公司股东 归属于 母公司股东 归属于 公司控股的财务公司与关联方之间不存在存款、贷款、授信或其他金融业务。
公司报告期不存在控股股东及其 他关联方对上市公司的非经营性占用资金。
沙分公司 废气 氮氧化 公司报告期控股股东未发生变更。
公司报告期无其他重大关联交易。
公司计划半年度不派发现金红利,不送红股,不以公积金转增股本。
限公司 房屋
公司半年度财务报告未经审计。
公司报告期不存在关联债权债务往来。
公司报告期实际控制人未发生变更。
公司半年度报告未经审计。
公司计划不派发现金红利,不送红股,不以公积金转增股本。
本公司的现金股利,于股东大会批准后确认为负债。
公司 废气 颗粒物 有组织 公司名称 与本企业关系
有限公司办理存款业务暨关 公司报告期不存在承包情况。
公司报告期不存在托管情况。
本公司在提取法定盈余公积金后,可提取任意公积金。经批准,任意公积金可用于弥补以前年度亏损或增加 明 公司为规避日常经营中所面临的汇率、利率风险,通过操作金融衍生品对实际持有的风险敞口进 公司报告期未发生破产重整相关事项。
公司秘书 现任 27,500 27,500
重庆弗迪锂电池有限公司
能源汽车有限公司 房屋
公司 接受劳务及购买水电燃气 公司员工持股计划在 2023年半年度费用摊销金额请详见“第十节财务报告 -十三.股份支付”相关内容。


assistant (to ragproxyagent):


同样地,我们使用 gpt-4、gpt-3.5-turbo、meta-llama/Llama-2-13b-chat-hf、Qwen/Qwen-14B-Chat 分别作为 Assistant 的后端,结果汇总如下(人工打分,回答正确一个问题得 1 分,回答不完整得小于 1 分,总分均为 5 分):

模型任务 1任务 2失败原因
gpt-44.84向量数据库未返回相关上下文,归纳不完整
gpt-3.5-turbo3.54向量数据库未返回相关上下文,归纳不完整,从上下文寻找信息的能力不足
meta-llama/Llama-2-13b-chat-hf20从上下文寻找信息的能力弱,允许的上下文长度较短,不能理解问题
Qwen/Qwen-14B-Chat1.80从上下文寻找信息的能力弱,归纳不完整

可以看到这些开源模型的自然语言能力也不及 gpt 系列模型。

应用三:可视化数据(群聊)

在第三个应用中,我们让 LLM 编写代码以可视化表格数据。

app-groupchat

和前两个应用不同的是,这里我们采用动态群聊(dynamic group chat)的方法来完成任务,通过:

  • 引入 3 个智能体:User Proxy 负责初始化对话,执行 Python 代码并返回结果,以及传入用户的发言;Coder 负责计划和编写代码;Critic 提出一般性的评价和改进建议,系统信息指定了 Critic 的角色并给出了详细的评估维度和标准。
  • 引入 1 个 GroupChat 的 Manager,Manager 的作用是在每一轮当中根据对话历史挑选 1 个智能体发言,并将其发言内容广播给其他智能体,即“主持群聊”。
  • 对于 UserProxyAgent 设置 human_input_mode=“ALWAYS”,这样每当 Manager 选取 User Proxy 发言,用户都可以提出自己的想法、需求或意见。

在代码中,我们定义了智能体 user_proxy、coder 和 critic,包含这些 agent 的 groupchat,以及 groupchat 的 manager,最后传入任务描述(prompt)以初始化对话。

user_proxy = autogen.UserProxyAgent(  
   name="User_Proxy",
   system_message="人类管理员",
   code_execution_config={"last_n_messages": 3, "work_dir": "groupchat"},
   human_input_mode="ALWAYS",
   is_termination_msg=lambda x: x.get("content", "").rstrip().endswith("TERMINATE")
)
coder = autogen.AssistantAgent(
    name="Coder",  # 默认的 assistant agent 就可以编写代码
    llm_config=llm_config,
)
critic = autogen.AssistantAgent(
    name="Critic",
    system_message="""评论员。您是一个非常擅长评估给定可视化代码质量的有益助手,通过提供从 1(差)到 10(好)的评分,并提供清晰的理由。在每个评估中,您必须考虑可视化最佳实践。具体来说,您可以仔细评估代码的以下维度:(后略)""",
    llm_config=llm_config,
)

groupchat = autogen.GroupChat(agents=[user_proxy, coder, critic], messages=[], max_round=20)
manager = autogen.GroupChatManager(groupchat=groupchat, llm_config=llm_config)
user_proxy.initiate_chat(manager, message="从 https://raw.githubusercontent.com/datasets/gdp/master/data/gdp.csv 下载数据,绘制中、美、日、德、英、法、印七个国家从 2000 年到 2016 年的名义 GDP 折线图(以美元计价),要求折线图有网格线,图例放置在左上角。将图片保存为文件。接受来自 critic 的反馈并改进代码。")

鉴于 gpt-4 无可匹敌的强大能力,这里仅使用 gpt-4 作为智能体的后端。一次具体的对话的日志如下:

日志

User_proxy (to chat_manager):

从 https://raw.githubusercontent.com/datasets/gdp/master/data/gdp.csv 下载数据,绘制中、美、日、德、英、法、印七个国家从 2000 年到 2016 年的名义 GDP 折线图(以美元计价),要求折线图有网格线,图例放置在左上角。将图片保存为文件。接受来自 critic 的反馈并改进代码。


Coder (to chat_manager):

理解您的需求,这是需要执行的步骤:

  1. 首先,我们需要下载数据集文件。
  2. 然后,所需要的包 pandas 和 matplotlib 都要安装到 Python 环境,用于数据处理和绘图。
  3. 下一步,通过 pandas 库解析下载的 csv 文件。
  4. 然后,我们需要筛选我们关注的七个国家(中国、美国、日本、德国、英国、法国、印度)自 2000 年到 2016 年的数据。
  5. 最后,我们使用 matplotlib 绘制折线图,并保存到文件。

请执行以下 Python 代码以完成前两个步骤,我会根据反馈执行后续步骤。

# filename: plot_gdp.py
import os
import pandas as pd
import matplotlib.pyplot as plt

# 下载数据集
data_url = "https://raw.githubusercontent.com/datasets/gdp/master/data/gdp.csv"
data_file = "gdp.csv"
os.system(f"wget {data_url} -O {data_file}")

# 读取数据集
data = pd.read_csv(data_file)

print(data.head())  # 打印数据集前5行,用于检查数据

######## NO HUMAN INPUT RECEIVED.

######## USING AUTO REPLY…

######## EXECUTING CODE BLOCK 0 (inferred language is python)… User_proxy (to chat_manager):

exitcode: 0 (execution succeeded) Code output: Country Name Country Code Year Value 0 Arab World ARB 1968 2.576068e+10 1 Arab World ARB 1969 2.843420e+10 2 Arab World ARB 1970 3.138550e+10 3 Arab World ARB 1971 3.642691e+10 4 Arab World ARB 1972 4.331606e+10


Coder (to chat_manager):

从执行结果可以看到,数据集已经成功下载并读取。数据有四个字段:Country Name(国家名),Country Code(国家代码),Year(年份)和 Value(GDP 值)。

下一步,我们需要筛选出需要的数据。具体来说,我们只需要中国、美国、日本、德国、英国、法国、印度从 2000 年到 2016 年的 GDP 数据。

请运行以下 Python 代码块以完成这个步骤。

# filename: plot_gdp.py

import pandas as pd
import matplotlib.pyplot as plt

# 读取数据集
data = pd.read_csv("gdp.csv")

# 筛选七个国家的数据
countries = ["China", "United States", "Japan", "Germany", "United Kingdom", "France", "India"]
data = data[data["Country Name"].isin(countries)]

# 筛选 2000 年到 2016 年的数据
data = data[(data["Year"] >= 2000) & (data["Year"] <= 2016)]

# 只保留我们关注的列
data = data[["Country Name", "Year", "Value"]]

print(data.head())  # 打印数据集前5行,用于检查数据

######## NO HUMAN INPUT RECEIVED.

######## USING AUTO REPLY…

######## EXECUTING CODE BLOCK 0 (inferred language is python)… User_proxy (to chat_manager):

exitcode: 0 (execution succeeded) Code output: Country Name Year Value 4086 China 2000 1.211347e+12 4087 China 2001 1.339396e+12 4088 China 2002 1.470550e+12 4089 China 2003 1.660288e+12 4090 China 2004 1.955347e+12


Coder (to chat_manager):

通过执行结果可以看到,我们已经成功地筛选出了七个国家从 2000 年到 2016 年的 GDP 数据。

接下来,我将使用 matplotlib 来绘制这些数据的折线图,并将图像保存为文件。

绘制图像的代码如下,请执行。

# filename: plot_gdp.py

import pandas as pd
import matplotlib.pyplot as plt

#读取数据集
data = pd.read_csv("gdp.csv")

#选择七个国家的数据
countries = ["China", "United States", "Japan", "Germany", "United Kingdom", "France", "India"]
data = data[data["Country Name"].isin(countries)]

#选择2000年到2016年的数据
data = data[(data["Year"] >= 2000) & (data["Year"] <= 2016)]

# 只保留我们关注的列
data = data[["Country Name", "Year", "Value"]]

# 绘制折线图
plt.figure(figsize=(10, 8))
for country in countries:
    country_data = data[data["Country Name"] == country]
    plt.plot(country_data["Year"], country_data["Value"], label=country)

plt.grid()  # 添加网格线
plt.legend(loc='upper left')  # 图例放置在左上角
plt.xlabel('Year')
plt.ylabel('GDP in US Dollars')
plt.title('GDP of Seven Countries from 2000 to 2016')

# 保存图片
plt.savefig("gdp_plot.png")

Critic (to chat_manager):

基于您提供的代码,以下是我的评估:

  1. 错误(Bugs):10分 您的代码没有语法错误、逻辑错误或拼写错误,能够正常运行并符合功能需求。

  2. 数据转换(Transformation):10分 您适当地筛选了数据,只保留了指定的七个国家从 2000年到2016年的GDP数据。您也正确地转换了数据以适应折线图的画图方式。

  3. 目标符合度(Compliance):10分 您的代码完全符合提出的可视化目标:绘制七个指定国家从2000年到2016年的GDP折线图,并且添加了网格线和图例。

  4. 可视化类型(Type):10分 您选择的折线图是一种合适的可视化类型,用于展示一段时间内GDP的变化情况。

  5. 数据编码(Encoding):10分 您正确地绘制了折线图,横坐标表示年份,纵坐标表示GDP。

  6. 美学(Aesthetics):10分 您的可视化具有良好的美感,图例清晰,颜色稳重,有利于理解数据。

总体来说,这是一个能够满足需求,实现功能,且无明显改进空间的严谨的代码。

具体行动清单:

  • 代码已经很好,没有需要修改的部分。继续保持!

######## NO HUMAN INPUT RECEIVED.

######## USING AUTO REPLY…

######## EXECUTING CODE BLOCK 0 (inferred language is python)… User_proxy (to chat_manager):

exitcode: 0 (execution succeeded) Code output:


Coder (to chat_manager):

既然代码已经成功执行,并且获得了评价人的高度评价,我们成功地完成了任务。您可以在您的工作目录中找到名为 “gdp_plot.png” 的折线图文件。这张图片显示了从 2000 年到 2016 年,中国、美国、日本、德国、英国、法国、印度七个国家的 GDP 变化情况。

非常感谢你的帮助,让我知道如果你有其他需要帮助的地方。TERMINATE


Critic (to chat_manager):

很高兴能帮助到您完成任务。如果您有任何其他编码或数据可视化需求,欢迎随时回来。期待与您再次合作,祝您一切顺利。TERMINATE


User_proxy (to chat_manager):

折线图的左上角有一个“1e13“的标记,这是因为纵轴的单位为一美元,请将其修改为十亿美元


Coder (to chat_manager):

明白了,您希望将 GDP 的单位从美元修改为十亿美元,以便更直观地理解图表。这意味着我们需要调整 Value 列的值,将其除以 10 的 9 次方(这是因为 1 十亿等于 10 的 9 次方)。然后我们也需要在 y 轴的标题中反映这一点。

请运行以下代码来生成新的图像。

# filename: plot_gdp.py

import pandas as pd
import matplotlib.pyplot as plt

# 读取数据集
data = pd.read_csv("gdp.csv")

# 筛选七个国家的数据
countries = ["China", "United States", "Japan", "Germany", "United Kingdom", "France", "India"]
data = data[data["Country Name"].isin(countries)]

# 筛选 2000 年到 2016 年的数据
data = data[(data["Year"] >= 2000) & (data["Year"] <= 2016)]

# 将 GDP 的单位从美元修改为十亿美元,以便直观理解图表
data["Value"] = data["Value"] / (10 ** 9)

# 只保留我们关注的列
data = data[["Country Name", "Year", "Value"]]

# 绘制折线图
plt.figure(figsize=(10, 8))
for country in countries:
    country_data = data[data["Country Name"] == country]
    plt.plot(country_data["Year"], country_data["Value"], label=country)

plt.grid()  # 添加网格线
plt.legend(loc='upper left')  # 图例放置在左上角
plt.xlabel('Year')
plt.ylabel('GDP in Billion US Dollars')  # 更新 y 轴标题
plt.title('GDP of Seven Countries from 2000 to 2016')

# 保存图片
plt.savefig("gdp_plot_billion.png")

######## NO HUMAN INPUT RECEIVED.

######## USING AUTO REPLY…

######## EXECUTING CODE BLOCK 0 (inferred language is python)… User_proxy (to chat_manager):

exitcode: 0 (execution succeeded) Code output:


Critic (to chat_manager):

基于您提供的代码,以下是我的评估:

  1. 错误(Bugs):10分 您的代码没有语法错误、逻辑错误或拼写错误,能够正常运行并符合功能需求。

  2. 数据转换(Transformation):10分 您正确地将 GDP 的单位从美元修改为了十亿美元,以便更直观地理解图表,这是一种恰当的数据转换方式。

  3. 目标符合度(Compliance):10分 您的代码完全符合提出的可视化目标:绘制七个指定国家从2000年到2016年的 GDP 折线图,并且添加了网格线和图例,且以十亿美元为单位。

  4. 可视化类型(Type):10分 您选择的折线图是一种合适的可视化类型,可以展示一段时间内 GDP 的变化情况。

  5. 数据编码(Encoding):10分 您正确地绘制了折线图,横坐标为年份,纵坐标为 GDP(现已调整为十亿美元)。

  6. 美学(Aesthetics):10分 您的可视化同样具有良好的美感,单位的更改使得读取更为友好,图例清晰,颜色稳重,有利于理解和展示数据。

总体来说,这是一个能够满足需求,实现功能,且无明显改进空间的宏观经济数据可视化代码。

具体行动清单:

  • 代码已经很好,没有需要修改的部分。继续保持!

######## NO HUMAN INPUT RECEIVED.

######## USING AUTO REPLY…

######## EXECUTING CODE BLOCK 0 (inferred language is python)… User_proxy (to chat_manager):

exitcode: 0 (execution succeeded) Code output:


Coder (to chat_manager):

既然代码已经成功执行,并且已经根据您的要求进行了更新,我们已经成功完成了任务。您可以在您的工作目录中找到名为 “gdp_plot_billion.png” 的折线图文件。这张图片显示了从 2000 年到 2016 年,中国、美国、日本、德国、英国、法国、印度七个国家的 GDP 变化情况,单位是十亿美元。

非常感谢你的帮助,让我知道如果你有其他需要帮助的地方。TERMINATE


Critic (to chat_manager):

很高兴能够帮助您完成任务。如果您对 Python 编程或数据可视化有任何其他问题或需求,欢迎您随时提问。期待与您再次合作,祝您一切顺利。TERMINATE


######## NO HUMAN INPUT RECEIVED.

这是第一版生成的图片:

app-groupchat

用户提出的改进建议是“折线图的左上角有一个“1e13“的标记,这是因为纵轴的单位为一美元,请将其修改为十亿美元”,于是 Coder 修改得到第二版:

app-groupchat

在 Manager 的 GroupChat 管理以及 User Proxy、Coder 和 Critic 的协作之下(尽管在这次运行中 Critic 并未提出改进意见),应用迭代出了更加准确、美观并且符合用户需求的可视化结果。

总结

经过上面几个简单应用的实验,我们可以获得如下总结和思考:

  1. 根据应用一和应用二的实验结果,能力更强的模型(gpt-4)可以使应用在任务中取得显著更好的表现。换言之,LLM 的(应用相关)能力是应用能否解决具体问题的决定性因素之一。
  2. 根据应用三的结果,模型被另一个相同的模型(但设定的角色不同)所纠正,可以认为是精心设计的系统信息和 prompt 激发了模型在子任务的专业领域上的表现。即便如此,模型的输出仍有欠缺,这里人类的干预可以进一步补足模型能力,提高应用的最终表现。
  3. 试想如果模型能力进一步提升会如何,基于下一代 GPT 模型的单智能体会不会比应用三的多智能体对话流表现更好?换一个视角,如果把除了 User Proxy 之外的 Coder、Critic 和 GroupChat Manager 打包为一个整体,把这个整体视作基于某个比 gpt-4 更强的 LLM 的单一智能体,AutoGen 框架在多智能体对话流中所起的作用就是这个 LLM 内部的一种机制。而传闻中,gpt-4 实际上就是类似的 MoE 结构(尽管细节尚不可知),由 8 个 220B 专家模型组成,这些模型分别在不同的数据集和任务分布上训练。或许“集成”和“对话”只需要一个,内部有着强大集成机制的 LLM 不会再需要外部的对话框架。

回到 AutoGen 框架,它仍是一个处于早期实验阶段的工作,其进一步的研究方向包括:

  1. 研究提升对话有效性和总体效率的策略(如智能体拓扑、对话模式等);探索对于特定 LLM 应用的最优多智能体对话流。
  2. 为构建针对不同应用的强大智能体提供系统性的参考,建立大规模开源知识库,建立具备自主学习和升级技能的智能体。
  3. 评估极度复杂的任务能否通过多智能体对话的方法有效解决。

部署对话式搜索引擎

对话式搜索引擎(conversational search engine)是利用自然语言处理技术来理解和响应用户查询的下一代搜索引擎。与传统的基于关键字的搜索引擎不同,对话式搜索引擎能够与用户以自然语言对话的形式进行互动,从而提供更为精准和个性化的搜索结果。这种搜索引擎通过分析用户的查询意图和上下文信息,能够提出问题、澄清疑惑,并给出更加直观和详细的回答。

当下(2024 Q1)最火热的对话式搜索引擎产品无疑是 Perplexity,但最近广受好评的开源项目 Search with Lepton 仅用 ~500 行 Python 代码就实现了类似的功能,其核心逻辑为:

  1. 获取用户的查询文本,调用传统搜索引擎的 API 以获取上下文,即结果页面的片段(snippets)。
  2. 将上下文添加到 system prompt(用于编写回答)中,将查询文本作为 user prompt,调用 LLM 生成回答。
  3. 将同样的上下文添加到另一个 system prompt(用于产生关联问题)中,将查询文本作为 user prompt,调用 LLM 生成关联问题。
  4. 将上下文、回答和关联问题返回给 UI 以供展示。
  5. (可选)将当次查询结果存储到数据库中,若用户再次进行相同的查询则直接返回该结果。

用户也可以在平台上方便地部署和使用这项功能!项目 t9k/search_with_lepton fork 了 Search with Lepton 项目并进行了以下修改:

  • 移除使用 Lepton AI 云服务的代码。
  • 增加 Dockerfile 并构建镜像 t9kpublic/search-with-lepton

本示例使用 Kubernetes 原生资源和 TensorStack 资源部署该修改后的对话式搜索引擎应用,系统架构如下图所示:

architecture
图 1:在平台上实现的对话式搜索引擎的系统架构。

创建的资源如下表所示:

类型名称作用备注
PVCsearch存储代码和模型文件卷大小为 180Gi
MLServiceRuntimevllm-openai-2xtp 定义 LLM 推理服务的模板
MLServicemixtral-8x7b 部署 LLM 推理服务计算资源为 {"limits":{"cpu": 4, "memory": "64Gi", "nvidia.com/gpu": 2}, "requests": {}}
Secretsearch存储搜索引擎的 API key
Deploymentsearch部署对话式搜索服务计算资源为 {"limits":{"cpu": 2, "memory": "8Gi"}, "requests": {}}
Servicesearch暴露服务

准备

在项目中创建一个名为 search、大小 180 GiB 以上的 PVC,然后创建一个同样名为 search 的 Notebook 挂载该 PVC(镜像类型和模板不限)。

进入 Notebook 或远程连接到 Notebook,启动一个终端,执行以下命令以克隆 t9k/examples 仓库:

cd ~
git clone https://github.com/t9k/examples.git

部署

LLM 推理服务

继续使用 Notebook 的终端,执行以下命令以下载 Mixtral-8x7B-Instruct-v0.1 的模型文件:

# 方法 1:如果可以直接访问 huggingface
huggingface-cli download mistralai/Mixtral-8x7B-Instruct-v0.1 \
  --local-dir Mixtral-8x7B-Instruct-v0.1 --local-dir-use-symlinks False

# 方法 2:对于国内用户,访问 modelscope 网络连通性更好
pip install modelscope
python -c \
  "from modelscope import snapshot_download; snapshot_download('AI-ModelScope/Mixtral-8x7B-Instruct-v0.1')"
mv .cache/modelscope/hub/AI-ModelScope/Mixtral-8x7B-Instruct-v0.1 .

然后使用 vLLM 部署兼容 OpenAI API 的 LLM 推理服务。使用以下 YAML 配置文件创建 MLServiceRuntime:

cd examples/applications/search
kubectl apply -f mlservice-runtime.yaml

再使用以下 YAML 配置文件创建 MLService 以部署服务(必要时修改 spec.scheduler 字段以使用 t9k-scheduler 及特定的队列):

kubectl create -f mlservice.yaml

搜索服务

在以下 YAML 配置文件中提供所调用搜索引擎的 API key,使用它创建 Secret:

# 修改 secret.yaml
kubectl apply -f secret.yaml

在以下 YAML 配置文件中提供环境变量,使用它创建 Deployment:

# 修改 deployment.yaml
kubectl create -f deployment.yaml

然后为 Deployment 创建 Service:

kubectl create -f service.yaml

使用

在本地的终端中,使用 t9k-pf 命令行工具,将服务的 8080 端口转发到本地的 8080 端口:

t9k-pf service search 8080:8080 -n <PROJECT NAME>

然后使用浏览器访问 http://127.0.0.1:8080,搜索以下问题:

  1. when will nvidia RTX 5000 series be released?
  2. 二进制小品是什么
  3. 武汉火车站是否已经恢复正常运行

需要说明的是,这里对话式搜索引擎所使用的搜索引擎后端是 Bing,调用的 LLM 是 Mixtral-8x7B-Instruct-v0.1。以下搜索于 2024 年 2 月 8 日进行。

search-with-lepton-q1
search-with-lepton-q2
search-with-lepton-q3

作为比较,我们在 Perplexity 搜索相同的问题:

perplexity-q1
perplexity-q2
perplexity-q3

可以看到,该应用的回答基本准确且详细,但存在以下问题:

  1. 尽管该应用可以理解中文查询和上下文,但它仅以英文回复,这是因为其调用的 Mixtral 8x7B 模型仅支持英语和一些欧洲语言。用户可以自行尝试调用其他支持中文的 LLM。

  2. 在回答问题 2 时,应用给出的解释“It is a form of light and humorous artistic work that explores the characteristics, applications, nad computer-related topics of binary.(它是一种轻松幽默的艺术作品形式,探索了二进制的特征、应用和与计算机相关的话题。)”存在明显误解,追溯其引用的参考源,我们发现该来源的解释就存在错误,且很有可能是由另一个 LLM 产生的虚构的信息。这提示我们在对话式搜索引擎中,搜索的准确性比内容生成更为关键,凸显了优化获取和处理上下文信息步骤的重要性。

相比之下,Perplexity 支持中文,并且生成回答的速度更快。尽管如此,其回答的质量并没有更好,尤其是对于问题 2 的回答出现了问题,完全没有引用参考源,而是由 LLM 直接生成的。其对于问题 3 的回答所包含的有用信息也较少。

参考

部署 Stable Diffusion 图像生成模型

自扩散模型问世以来,AI 绘图应用在艺术、设计和创意领域取得了显著的突破和广泛的应用。在 TensorStack 平台上,用户可以使用 SimpleMLServiceMLService 方便地部署各种基于图像生成模型的服务或应用。

本示例使用 SimpleMLService 快速部署一个基于 Stable Diffusion 图像生成模型的绘图应用。

模型

在项目中创建一个名为 draw、大小 50 GiB 以上的 PVC,然后创建一个同样名为 draw 的 Notebook 挂载该 PVC(镜像类型和模板不限)。

进入 Notebook 或远程连接到 Notebook,启动一个终端,执行下列命令以下载 Stable Diffusion、VAE、LoRA 等模型的文件:

mkdir sd
wget https://civitai.com/api/download/models/30163 \
  -O sd/anything-v5-PrtRE.safetensors
wget https://civitai.com/api/download/models/57618 \
  -O sd/CounterfeitV30_v30.safetensors
wget https://huggingface.co/runwayml/stable-diffusion-v1-5/resolve/main/v1-5-pruned.safetensors \
  -O sd/v1-5-pruned.safetensors

mkdir lora
wget https://civitai.com/api/download/models/87153 \
  -O lora/more_details.safetensors

mkdir vae
wget https://huggingface.co/stabilityai/sd-vae-ft-mse-original/resolve/main/vae-ft-mse-840000-ema-pruned.safetensors \
  -O vae/vae-ft-mse-840000-ema-pruned.safetensors

mkdir outputs

最终目录结构如下:

.
├── lora
│   └── more_details.safetensors
├── outputs (用于放置模型输出)
├── sd
│   ├── anything-v5-PrtRE.safetensors
│   ├── CounterfeitV30_v30.safetensors
│   └── v1-5-pruned.safetensors
└── vae
    └── vae-ft-mse-840000-ema-pruned.safetensors

Stable Diffusion 生成图片的简化流水线如下图所示,具体包含三个主要步骤:

  1. CLIP 模型为输入的 prompt 生成文件嵌入;
  2. U-Net 反复地去除 latent 表示中的噪音;
  3. VAE 将 latent 表示解码为最终的图片。
sd-pipeline

我们前面所下载的模型文件中:

  • Stable Diffusion 模型提供图中的 U-Net 和 VAE 模型。
  • VAE 用于替换现有 Stable Diffusion 模型的 VAE。VAE 会影响图片的风格以及细节处理。
  • LoRA 用于更新 CLIP 和 U-Net 的权重。使用 LoRA 会应用微调过程中对模型的修改,以生成特定内容或风格的图片。

部署

stable-diffusion-webui 是一个用于运行 Stable Diffusion 模型的 gradio web UI。bilibili 用户“秋葉aaaki”基于这一项目制作了整合包。这里使用它来部署上述模型。

使用以下 YAML 配置文件创建 SimpleMLService(必要时修改 spec.scheduler.t9kScheduler.queue 字段指定的队列):

smls.yaml
apiVersion: tensorstack.dev/v1beta1
kind: SimpleMLService
metadata:
  name: stable-diffusion-webui
spec:
  replicas: 1
  scheduler:
    t9kScheduler:
      queue: default
  service:
    type: ClusterIP
    ports:
    - targetPort: 7860
      port: 7860
  custom:
    spec:
      containers:
      - name: server
        image: t9kpublic/stable-diffusion-webui:aki-v4
        args:
          - --skip-install
          - --listen
        ports:
        - containerPort: 7860
        resources:
          limits:
            cpu: 4
            memory: 64Gi
            nvidia.com/gpu: 1
        volumeMounts:
          - mountPath: /workspace/sd-webui-aki-v4/models/Stable-diffusion
            name: data
            subPath: sd
          - mountPath: /workspace/sd-webui-aki-v4/models/VAE
            name: data
            subPath: vae
          - mountPath: /workspace/sd-webui-aki-v4/models/Lora
            name: data
            subPath: lora
          - mountPath: /workspace/sd-webui-aki-v4/outputs
            name: data
            subPath: outputs
          - mountPath: /dev/shm
            name: dshm
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: draw
        - name: dshm
          emptyDir:
            medium: Memory
kubectl create -f smls.yaml

启动

查看 SimpleMLService 创建的 Pod 打印的日志:

kubectl logs -l deployment=managed-simplemlservice-stable-diffusion-webui -f --tail -1
service-log

接下来就可以开始生成图片了!

生成图片

在本地的终端中,使用 t9k-pf 命令行工具,将 SimpleMLService 创建的服务的 7860 端口转发到本地的 7860 端口:

t9k-pf service stable-diffusion-webui 7860:7860 -n <PROJECT NAME>
pf

然后使用浏览器访问 127.0.0.1:7860,绘制喜欢的图片:

webui

生成的图片可以通过 Web UI 下载,同时也会保存到 PVC 的 outputs/ 路径下。

画廊

这里展示一些最终生成的图片:



img1
模型 v1-5-pruned.safetensors, vae-ft-mse-840000-ema-pruned.safetensors
生成数据 alpaca, plateau, mountain, realistic, Steps: 20, Sampler: DPM++ 2M Karras, CFG scale: 7, Seed: 2642782115, Size: 512x512, Model hash: 1a189f0be6, Model: v1-5-pruned, Clip skip: 2, ENSD: 31337



img2
模型 CounterfeitV30_v30.safetensors, vae-ft-mse-840000-ema-pruned.safetensors
生成数据 (masterpiece, best quality),1girl, solo, flower, long hair, outdoors, letterboxed, school uniform, day, sky, looking up, short sleeves, parted lips, shirt, cloud, black hair, sunlight, white shirt, serafuku, upper body, from side, pink flower, blurry, brown hair, blue sky, depth of field Negative prompt: EasyNegativeV2 Steps: 25, ENSD: 31337, Size: 1024x512, Seed: 2311942344, Model: CF5_Counterfeit-V3.0_fix_fix_fix, Sampler: DPM++ 2M Karras, CFG scale: 10, Clip skip: 2, Model hash: db6cd0a62d, Hires upscale: 2, Hires upscaler: R-ESRGAN 4x+ Anime6B, Denoising strength: 0.45



img3
模型 anything-v5-PrtRE.safetensors, vae-ft-mse-840000-ema-pruned.safetensors
生成数据 masterpiece, best quality, scenery, whale, fish, starry sky, galaxy, cosmos, fantasy, floating object|fish, backlight, shadow Negative prompt: (low quality, worst quality:1.4), (bad anatomy),easynegative Steps: 20, Size: 1024x512, Seed: 3421647346, Sampler: DPM++ 2M Karras, CFG scale: 8



img4
模型 anything-v5-PrtRE.safetensors, vae-ft-mse-840000-ema-pruned.safetensors
生成数据 masterpiece, best quality, best 8k wallpaper, chibi, 1girl, official, solo, silver hair, ponytail, blush, smile, head, sunglasses, white background, pixel, (pixel art) Negative prompt: badhandv4,EasyNegative Steps: 80, Sampler: DPM++ 2M Karras, CFG scale: 9, Seed: 1362619635, Size: 512x512, Model hash: 7f96a1a9ca, Model: anything-v5-PrtRE, ENSD: 31337



img5
模型 anything-v5-PrtRE.safetensors, vae-ft-mse-840000-ema-pruned.safetensors
生成数据 greyscale, monochrome, no humans, tree, scenery, traditional media, tower, building, outdoors Negative prompt: EasyNegative Steps: 20, Sampler: DPM++ SDE Karras, CFG scale: 7, Seed: 2579617703, Size: 512x768, Model hash: 7f96a1a9ca, Model: anything-v5-PrtRE, Denoising strength: 0.7, Clip skip: 2, ENSD: 31337, Hires upscale: 2, Hires upscaler: Latent



img6
模型 anything-v5-PrtRE.safetensors, vae-ft-mse-840000-ema-pruned.safetensors
生成数据 Monet style, beach, boat, cloud, sky, traditional media, water, watercraft, (masterpiece:1,2), best quality, masterpiece, highres, original, extremely detailed wallpaper, perfect lighting,(extremely detailed CG:1.2), drawing, paintbrush, Negative prompt: NSFW, (worst quality:2), (low quality:2), (normal quality:2), lowres, normal quality, ((monochrome)), ((grayscale)), skin spots, acnes, skin blemishes, age spot, (ugly:1.331), (duplicate:1.331), (morbid:1.21), (mutilated:1.21), (tranny:1.331), mutated hands, (poorly drawn hands:1.5), blurry, (bad anatomy:1.21), (bad proportions:1.331), extra limbs, (disfigured:1.331), (missing arms:1.331), (extra legs:1.331), (fused fingers:1.61051), (too many fingers:1.61051), (unclear eyes:1.331), lowers, bad hands, missing fingers, extra digit,bad hands, missing fingers, (((extra arms and legs))), Steps: 36, Sampler: Euler a, CFG scale: 4.5, Seed: 2739912422, Size: 512x768, Model hash: 7f96a1a9ca, Model: anything-v5-PrtRE, Denoising strength: 0.7, Clip skip: 3, ENSD: 31337, Hires upscale: 2, Hires upscaler: Latent



img7
模型 anything-v5-PrtRE.safetensors, vae-ft-mse-840000-ema-pruned.safetensors
生成数据 digital painting, best quality, magic, cyberpunk, city, street, neon, mystic, Negative prompt: (worst quality:1.2), (low quality:1.2), (lowres:1.1), (monochrome:1.1), (greyscale), multiple views, comic, sketch, watermark, multiple_views Steps: 150, Sampler: PLMS, CFG scale: 7, Seed: 2300531334, Size: 768x512, Model hash: 7f96a1a9ca, Model: anything-v5-PrtRE, Clip skip: 2, ENSD: 31337

车道检测

车道检测是计算机视觉和自动驾驶领域的一项关键技术,旨在识别和跟踪道路上的车道线。这个任务对于实现车辆的自动驾驶和辅助驾驶系统至关重要,因为它能够帮助车辆理解其在道路上的位置,保持车道,并执行如车道保持、车道变换等操作。

lane-detection

本示例使用 PyTorchTrainingJob 训练一个车道检测模型。

准备

在项目中创建一个名为 lanedet、大小 50 GiB 以上的 PVC,然后创建一个同样名为 lanedet 的 Notebook 挂载该 PVC(镜像类型和模板不限)。

进入 Notebook 或远程连接到 Notebook,启动一个终端,执行以下命令以克隆 t9k/examples 仓库

cd ~
git clone https://github.com/t9k/examples.git

继续执行以下命令以从 kaggle 下载 TuSimple 数据集并解压,其中 kaggle.json 文件需要登录 kaggle 获取。完整的操作步骤可以参阅博客 How to Download Kaggle Datasets on Ubuntu

pip install kaggle

# 在浏览器中登录 kaggle,在账户设置页面创建新的 token 以生成 kaggle.json 文件,将其上传到 Notebook
mkdir ~/.kaggle
mv kaggle.json ~/.kaggle

kaggle datasets download manideep1108/tusimple
unzip tusimple.zip

训练

使用如下 YAML 配置文件创建 PyTorchTrainingJob 以启动训练。该 PyTorchTrainingJob 创建 2 个副本,每个副本启动 2 个进程,每个进程使用 1 个 GPU。

kubectl create -f examples/lanedet/t9k/job.yaml

通过以下命令查看训练过程中打印的日志:

export POD=$(kubectl get pj lanedet -o jsonpath="{.status.tasks[0].replicas[0].name}")
kubectl logs $POD -f
log

训练共进行 100 个 epoch,每个 epoch 结束时进行验证(使用测试图像作为验证集),计算准确率、假阳性率和假阴性率。训练完成之后,模型文件将保存到 output/TuSimple/0/*/ 路径下。训练花费约 3 小时,最终准确率可以达到约 0.94。

集成

平台支持集成第三方应用,用户可以在自己的项目中使用 Helm 轻松快速地部署各种丰富的第三方应用,例如部署一个 GitLab 以托管私有代码,部署一个 Label Studio 以进行数据标注等。

这一部分将介绍一些与机器学习相关的常用第三方应用的部署流程和使用方法。在开始之前,先确定在哪一个项目中部署应用,在该项目中创建一个名为 app、大小 1 GiB 的 PVC,然后创建一个同样名为 app 的 Notebook 挂载该 PVC(镜像类型和模板不限)。

Label Studio

Label Studio 是一个开源的数据标注工具。它允许用户通过一个简单直观的用户界面来标注音频、文本、图像、视频和时间序列等多种数据类型,并支持导出到各种模型格式。

部署

安装与配置

进入 Notebook app 的终端,添加相应的 Helm Chart repository,列出 Chart heartex/label-studio 的所有版本:

helm repo add heartex https://charts.heartex.com/

# 注意 CHART VERSION 和 APP VERSION(Label Studio 版本)之间的对应关系
# 例如 CHART VERSION 1.4.0 和 1.3.4 中的 Label Studio 版本都是 1.11.0
helm search repo heartex/label-studio --versions

安装指定版本的 Chart heartex/label-studio 以部署 Label Studio 应用:

# 安装最新版本
helm repo update heartex
helm install label-studio-demo heartex/label-studio

# 安装指定 CHART VERSION,注意这不是 APP VERSION(Label Studio 版本)
helm install label-studio-demo heartex/label-studio --version <CHART_VERSION>

以上安装全部使用默认配置,完整的默认配置请参阅相应的 values.yaml

# 获取指定 CHART VERSION 的 values.yaml
helm show values heartex/label-studio --version <CHART_VERSION> > values.yaml

其中部分关键配置如下所示(CHART VERSION 1.4.0):

app:
  replicas: 1        # 副本数

  resources:         # 计算资源
    limits: {}
    requests: {}

  ingress:           # Ingress 配置
    enabled: false
    annotations: {}
    className: ""
    host: ""
    tls: []

global:
  persistence:       # 持久化
    config:
      volume:
        accessModes:
        - ReadWriteOnce
        annotations: {}
        existingClaim: ""
        resourcePolicy: ""
        size: 10Gi       # 卷大小
        storageClass: ""
    enabled: true
    type: volume         # 卷

你可以根据需要对这些配置进行修改:

然后将新配置(覆盖默认配置的部分)保存为一个 YAML 文件,通过 -f 选项提供给安装命令:

# 使用修改后的 values.yaml
helm install label-studio-demo heartex/label-studio --version <CHART_VERSION> -f values.yaml

应用架构

应用的系统架构如下图所示(CHART VERSION 1.4.0,默认配置):

architecture

创建的主要 Kubernetes 资源如下表所示:

类型名称作用备注
Servicelabel-studio-demo-ls-app暴露 Label Studio 服务
Deploymentlabel-studio-demo-ls-app部署 Label Studio默认计算资源为 {"limits": {}, "requests": {}}
PVClabel-studio-demo-ls-pvc作为 Label Studio 的持久化存储,存储用户上传的数据文件等选择卷作为持久化方案时存在;默认卷大小为 10Gi
Secretlabel-studio-demo-postgresql存储数据库密钥
Servicelabel-studio-demo-postgresql暴露数据库服务
StatefulSetlabel-studio-demo-postgresql部署数据库默认计算资源为 {"limits": {}, "requests": {"cpu": "250m", "memory": "256Mi"}}
PVCdata-label-studio-demo-postgresql-*作为数据库的持久化存储默认卷大小为 8Gi
Ingresslabel-studio-demo-ls-app提供外部访问启用 Ingress 时存在

运维

查看应用的状态

helm status label-studio-demo

重启应用

kubectl rollout restart deployment/label-studio-demo-ls-app

更新应用

# 更新到最新版本
helm upgrade label-studio-demo heartex/label-studio

# 更新到指定版本
helm upgrade label-studio-demo heartex/label-studio --version <VERSION_NUMBER>

# 回滚更新,首先查看历史版本
helm history label-studio-demo
helm rollback label-studio-demo [REVISION]

移除应用

helm delete label-studio-demo

使用

基本使用

如果在部署应用时配置了 Ingress,那么直接在浏览器中访问相应的地址即可,否则需要进行端口转发。在用户的计算机上,前往模型构建控制台获取应用 Pod 的名称(前缀为 label-studio-demo-ls-app-):

get-pod-name

然后通过 t9k-pf 进行端口转发来访问 Label Studio 应用:

t9k-pf -n <APP_PROJECT> pod <POD_NAME> 8080:8085

在浏览器中访问 http://127.0.0.1:8080/ 进入应用的 Web UI。注册一个用户,Email 和密码可以任意指定:

sign-up

假定任务是图像分类,我们准备了 10 张图片(来自数据集 Cats and Dogs),需要将每一张图片标注为猫或狗。点击 Create Project

create-project

在 Project Name 页面可选地修改 Project 的名称:

project-name

在 Data Import 页面上传 10 张图片:

data-import
file-uploaded

在 Labeling Setup 页面,选择模板 Computer Vision > Image Classification,并将选项编辑为 CatDog,最后点击 Save

labeling-setup
config-template

自动跳转到 Project 的默认标签页,点击 Label All Tasks 以开始标注:

task-list

对于每一张图片,勾选其为 Cat 或 Dog,然后点击 Submit

labeling

标注结束后,点击 Export 以下载指定格式的标注数据。

export

导入大量数据

在导入数据时,如果仅上传少量(几十上百个)的文件,那么使用 Web UI 即可。但假设我们要上传数据集 Cats and Dogs 的总共 25000 张图片,仍然使用 Web UI 会导致其崩溃,这时我们需要寻求另外的导入数据的方法。

Label Studio 支持从外部存储同步数据。这里以 Amazon S3 为例。在用户的计算机上准备好数据文件,并将其上传到 S3 bucket:

$ tree .                                       
.
├── 0.jpg
├── 1.jpg
├── 10.jpg
├── 100.jpg
├── 1000.jpg
├── 10000.jpg
├── 10001.jpg
...
├── 9998.jpg
└── 9999.jpg

0 directories, 25000 files

$ rclone copy -P . corps3:my-bucket/kagglecatsanddogs                                                                        
Transferred:      569.808 MiB / 809.542 MiB, 70%, 2.328 MiB/s, ETA 1m42s                                               
Transferred:        16994 / 25000, 68%                                                                                 
Elapsed time:      3m35.2s                                                                                             
Transferring:                                                                                                          
 *                                      2793.jpg:100% /23.680Ki, 0/s, -                                                
 *                                      2794.jpg:100% /20.700Ki, 0/s, -                                                
 *                                      2795.jpg:100% /22.631Ki, 0/s, -                                                
 *                                      2796.jpg:100% /13.476Ki, 0/s, -

在 Label Studio 的项目设置中点击 Cloud Storage > Add Source Storage,选择存储类型 AWS S3,并填写相关的配置,点击 Check Connection 验证连接是否成功,最后点击 Add Storage

add-source-storage
add-source-storage-detail

创建完成之后,点击 Sync Storage,即可从导入数据文件:

sync-storage

回到项目,可以看到数据被导入:

synced

自定义标注 UI

应用内置了大量标注模板,覆盖了各种类型的机器学习任务。除此之外,用户还可以使用类似 XML 的标签来自定义标注 UI,详细语法规则请参阅 Customize the Label Studio User Interface

customize-ui
customize-ui-detail

自动化标注

人工标注数据费时费力,我们可以引入机器学习模型来完成这一工作,这样只需要人工审核即可。

Label Studio 支持添加 ML backend,使用其自动标注或进行在线训练。这里演示使用 SAM 进行语义分割任务的自动标注。

在应用的 Web UI 点击 Account & Settings,以获取用户的 Access Token

access-token

回到 Notebook app 的终端,获取应用 service 的 IP 地址:

kubectl get svc label-studio-demo-ls-app -o jsonpath="{.spec.clusterIP}"

然后使用如下 YAML 配置文件创建 SimpleMLService 以部署 ML backend 服务,其中环境变量 LABEL_STUDIO_HOSTLABEL_STUDIO_ACCESS_TOKEN 的值需要根据上面获取的结果进行修改。镜像 t9kpublic/label-studio-sam:main 构建自示例 Interactive Annotation in Label Studio with Segment Anything Model

sam.yaml
apiVersion: tensorstack.dev/v1beta1
kind: SimpleMLService
metadata:
  name: label-studio-sam
spec:
  replicas: 1
  service:
    type: ClusterIP
    ports:
    - targetPort: 9090
      port: 9090
  custom:
    spec:
      containers:
      - name: server
        image: t9kpublic/label-studio-sam:main
        env:
          - name: SAM_CHOICE
            value: MobileSAM
          - name: LOG_LEVEL
            value: DEBUG
          - name: LABEL_STUDIO_HOST
            value: http://10.233.12.87:80
          - name: LABEL_STUDIO_ACCESS_TOKEN
            value: 381ae0357804f39d01e5d169b8ed0cf548925a57
        ports:
        - containerPort: 9090
        resources:
          limits:
            cpu: 8
            memory: 8Gi
        volumeMounts:
        - mountPath: /dev/shm
          name: dshm
      volumes:
      - name: dshm
        emptyDir:
          medium: Memory
kubectl create -f sam.yaml

获取 ML backend service 的 IP 地址和端口号:

kubectl get svc label-studio-sam -o jsonpath="{.spec.clusterIP}"
kubectl get svc label-studio-sam -o jsonpath="{.spec.ports[0].port}"

再次进入应用的 Web UI,创建一个新的 project,上传一张图片,并且 template 使用如下自定义模板:

<View>
  <Image name="image" value="$image" zoom="true"/>
  <BrushLabels name="tag" toName="image">
  	<Label value="Banana" background="#FF0000"/>
  	<Label value="Orange" background="#0d14d3"/>
  </BrushLabels>
  <KeyPointLabels name="tag2" toName="image" smart="true">
    <Label value="Banana" smart="true" background="#000000" showInline="true"/>
    <Label value="Orange" smart="true" background="#000000" showInline="true"/>
  </KeyPointLabels>
  <RectangleLabels name="tag3" toName="image" smart="true">
    <Label value="Banana" background="#000000" showInline="true"/>
    <Label value="Orange" background="#000000" showInline="true"/>
  </RectangleLabels>
</View>

在 Label Studio 的项目设置中点击 Machine Learning > Add Model,填写 SAM 服务的 URL 和模型名称,勾选 Use for interactive preannotations,然后点击 Validate and Save

add-model
add-model-detail

标注时按照下图的顺序进行操作,可以看到图片中的柯基被正确地分割出来:

auto-annotation

团队协作

应用提供了简单直接的团队协作方式。团队的多个成员分别注册用户、登录并进入同一个项目,通过设定不同的过滤条件来分别标注全部数据的不同子集。

例如设定 ID / <= / 3000 可以仅列举前 3000 个数据;设定 Annotated by / is empty / yes 可以仅列举未被标注的数据。

参考

向量数据库:Qdrant

背景

向量数据库是一种专门设计用于存储、索引和检索向量数据的数据库。它适用于处理大规模的高维向量,这些向量通常代表了图像、视频、文本或音频内容的特征,甚至整个世界本身。向量数据库通常用于支持机器学习应用,例如检索增强生成(RAG)、图像检索、推荐系统等。

向量数据库的核心功能是相似度搜索(similarity search),即通过计算向量之间的相似度来快速检索出内容上相似的项目。常用的相似度度量包括欧氏距离、余弦相似度和点积。为了实现高效的大规模相似度搜索,向量数据库通常采用专门的数据结构和索引技术,以及高效的搜索算法(如近似最近邻搜索算法)。以基于检索增强生成的问答应用为例,当用户提出一个问题时,应用会首先将问题转换为向量,然后在向量数据库中检索与该向量相似的向量,即与问题相关的上下文。这些检索到的上下文信息用于增强大型语言模型的回答生成过程,使得生成的答案更为精确和详尽。

目前市面上存在数量众多的向量数据库产品,即便是开源向量数据库也有不少选择,例如 MilvusQdrantChromaWeaviate 等。关于这些向量数据库的比较,可以参阅博客 Vector databases (1): What makes each one different?

vector-db-lang

这里以 Qdrant 为例进行部署。Qdrant 官方提供了 Helm chart,部署更加简单、便捷。

qdrant

Qdrant 的一些特性如下:

  • 高效:有效利用计算资源。Qdrant 完全用 Rust 语言开发,实现了动态查询计划和有效载荷数据索引。也为企业提供了硬件感知的构建版本。
  • 快速且准确:实现了 HNSW 算法的独特自定义修改,用于近似最近邻搜索。以最先进的速度进行搜索,并在不影响结果的情况下应用搜索过滤器。
  • 易于使用的 API:提供 OpenAPI v3 规范来生成几乎任何编程语言的客户端库。或者,利用为 Python 或其他编程语言准备的现成客户端以获得额外功能。
  • 丰富的数据类型:向量负载支持大量的数据类型和查询条件,包括字符串匹配、数值范围、地理位置等。负载过滤条件允许你构建几乎任何自定义业务逻辑,这些逻辑应基于相似性匹配工作。
  • 分布式:云原生且横向可扩展。无论用户需要伺服多少数据,Qdrant 总是可以使用恰到好处的计算资源。

Qdrant 提供了 REST API 和 gRPC API 作为接口,所有与 Qdrant 的交互都通过这些 API 进行。此外,Qdrant 还提供了多种语言的客户端库和一个 Web UI 界面,使用部分将演示使用 Python 客户端以及 Web UI 与 Qdrant 交互。

部署

安装

进入 Notebook app 的终端,添加相应的 Helm Chart repository,列出 Chart qdrant/qdrant 的所有版本:

helm repo add qdrant https://qdrant.github.io/qdrant-helm

# 注意 CHART VERSION 和 APP VERSION(Qdrant 版本)之间的对应关系
# 例如 CHART VERSION 0.7.5 和 0.7.4 中的 Qdrant 版本都是 v1.7.3
helm search repo qdrant/qdrant --versions

安装指定版本的 Chart qdrant/qdrant 以部署 Qdrant 应用:

# 安装最新版本
helm repo update qdrant
helm install qdrant-demo qdrant/qdrant

# 安装指定 CHART VERSION,注意这不是 APP VERSION(Qdrant 版本)
helm install qdrant-demo qdrant/qdrant --version <CHART_VERSION>

配置

以上安装全部使用默认配置,完整的默认配置请参阅相应的 values.yaml

# 获取指定 CHART VERSION 的 values.yaml
helm show values qdrant/qdrant --version <CHART_VERSION> > values.yaml

如果想要修改默认配置,你可以将新配置(覆盖默认配置的字段)保存为一个 YAML 文件,通过 -f 选项提供给安装命令:

# 使用修改后的 values.yaml
helm install qdrant-demo qdrant/qdrant --version <CHART_VERSION> -f values.yaml

下面将分主题介绍部分关键配置(CHART VERSION 0.7.6)。

计算资源

默认配置没有指定计算资源,表示 Pod 可以无限制地使用节点的 CPU 和内存资源。你可以根据实际需求指定请求值和限制值。

# 默认配置
resources: {}

存储

默认配置指定的卷大小为 10Gi,并且没有指定存储类型。你可以根据数据规模修改卷大小,并选用高性能的存储类型。

# 默认配置
persistence:
  accessModes:
  - ReadWriteOnce
  annotations: {}
  size: 10Gi                # 卷大小
  storageClassName: ""      # 存储类型
config:
  storage: {}

此外,你还可以在 config.storage 字段下配置 Qdrant 实例的存储和索引的多个参数,请参阅 configuration file example

网络

默认配置没有启动 Ingress,你可以提供 Ingress 配置以提供外部访问。

# 默认配置
ingress:              # Ingress 配置
  enabled: false
  ingressClassName: ""
  annotations: {}
  hosts:
  - host: example-domain.com
    paths:
    - path: /
      pathType: Prefix
      servicePort: 6333
  tls: []

service:              # Service 配置              
  type: ClusterIP
  additionalLabels: {}
  annotations: {}
  loadBalancerIP: ""
  ports:
    - name: http
      port: 6333
      targetPort: 6333
      protocol: TCP
      checksEnabled: true
    - name: grpc
      port: 6334
      targetPort: 6334
      protocol: TCP
      checksEnabled: false
    - name: p2p
      port: 6335
      targetPort: 6335
      protocol: TCP
      checksEnabled: false

config:
  service: {}
  tls: {}

此外,你还可以在 config.serviceconfig.tls 字段下配置 Qdrant 实例的服务和 TLS 的多个参数,请参阅安全以及 configuration file example

分布式部署

Qdrant 支持分布式部署模式,在此模式下,多个 Qdrant 服务彼此通信,将数据分布到多个副本(replica)中,以扩展存储能力并增加稳定性。默认配置启用了分布式部署模式,并指定端口 6335 用于内部通信,但只创建了 1 个副本。你可以增加副本数量以实现分布式部署。

# 默认配置
replicaCount: 1

config:
  cluster:
    enabled: true
    p2p:
      port: 6335
    consensus:
      tick_period_ms: 100

关于分布式一致性协议、分片、复制(replication)和一致性保证的更多信息,请参阅 Distributed deployment

安全

默认配置没有为 Qdrant 实例提供任何保护,在投入生产使用之前需要启用安全措施。首先,启用 TLS 以加密连接:

config:
  service:
    enable_tls: true

  p2p:
    enable_tls: true  # 分布式部署下,对 peer 之间的通信启用 TLS

  tls:
    cert: ./tls/cert.pem
    key: ./tls/key.pem

在此基础上,可以使用静态的 API key 进行身份验证:

config:
  service:
    api_key: your_secret_api_key_here

更多信息请参阅 Security

应用架构

应用的系统架构如下图所示(CHART VERSION 0.7.6,默认配置):

architecture

创建的主要 Kubernetes 资源如下表所示:

类型名称作用备注
Serviceqdrant-demo暴露 Qdrant 服务
StatefulSetqdrant-demo部署 Qdrant默认计算资源为 {}
PVCqdrant-storage-qdrant-demo-*作为 Qdrant 的持久化存储默认卷大小为 10Gi

运维

查看应用的状态

helm status qdrant-demo

更新应用

# 更新到最新版本
helm upgrade qdrant-demo qdrant/qdrant

# 更新到指定版本
helm upgrade qdrant-demo qdrant/qdrant --version <VERSION_NUMBER>

# 回滚更新,首先查看历史版本
helm history qdrant-demo
helm rollback qdrant-demo [REVISION]

移除应用

helm delete qdrant-demo
kubectl delete pvc -l app.kubernetes.io/instance=qdrant-demo

使用

继续使用 Notebook app 的终端,获取应用 service 的公开的端口号:

kubectl get svc qdrant-demo -o jsonpath="{.spec.ports}"

输出应类似于:

[{"name":"http","port":6333,"protocol":"TCP","targetPort":6333},{"name":"grpc","port":6334,"protocol":"TCP","targetPort":6334},{"name":"p2p","port":6335,"protocol":"TCP","targetPort":6335}]

首先使用 Python 客户端运行一个快速入门。安装 Python 客户端:

pip install qdrant-client

然后执行如下 Python 脚本,命令行参数中需要提供 gRPC 端口号:

quick_start.py
import sys

from qdrant_client import QdrantClient
from qdrant_client.http.models import (Distance, Filter, FieldCondition,
                                       MatchValue, PointStruct, VectorParams)

# 客户端在创建 collection 时存在 HTTP 超时问题,参考
# https://github.com/qdrant/qdrant-client/issues/394,采用 gRPC 作为临时解决方案
# client = QdrantClient(sys.argv[1])
client = QdrantClient(sys.argv[1], prefer_grpc=True)

# 创建一个 collection 以存储向量数据,设定向量维数为 4,使用点积度量距离
client.create_collection(
    collection_name="test_collection",
    vectors_config=VectorParams(size=4, distance=Distance.DOT),
)

# 添加一些向量
client.upsert(
    collection_name="test_collection",
    wait=True,
    points=[
        PointStruct(id=1,
                    vector=[0.05, 0.61, 0.76, 0.74],
                    payload={"city": "Berlin"}),
        PointStruct(id=2,
                    vector=[0.19, 0.81, 0.75, 0.11],
                    payload={"city": "London"}),
        PointStruct(id=3,
                    vector=[0.36, 0.55, 0.47, 0.94],
                    payload={"city": "Moscow"}),
        PointStruct(id=4,
                    vector=[0.18, 0.01, 0.85, 0.80],
                    payload={"city": "New York"}),
        PointStruct(id=5,
                    vector=[0.24, 0.18, 0.22, 0.44],
                    payload={"city": "Beijing"}),
        PointStruct(id=6,
                    vector=[0.35, 0.08, 0.11, 0.44],
                    payload={"city": "Mumbai"}),
    ],
)

# 查询与向量 [0.2, 0.1, 0.9, 0.7] 最相似的 3 个向量
search_result = client.search(collection_name="test_collection",
                              query_vector=[0.2, 0.1, 0.9, 0.7],
                              limit=3)
print(search_result)

# 进一步过滤结果
search_result = client.search(
    collection_name="test_collection",
    query_vector=[0.2, 0.1, 0.9, 0.7],
    query_filter=Filter(
        must=[FieldCondition(key="city", match=MatchValue(value="London"))]),
    with_payload=True,
    limit=3,
)
print(search_result)
python quick-start.py qdrant-demo:<GRPC_PORT>

脚本创建了一个 collection,添加了一些数据,并进行了两次基本的查询。输出应类似于:

[ScoredPoint(id=4, version=0, score=1.3619999885559082, payload={'city': 'New York'}, vector=None, shard_key=None), ScoredPoint(id=1, version=0, score=1.2730000019073486, payload={'city': 'Berlin'}, vector=None, shard_key=None), ScoredPoint(id=3, version=0, score=1.2079999446868896, payload={'city': 'Moscow'}, vector=None, shard_key=None)]
[ScoredPoint(id=2, version=0, score=0.8709999918937683, payload={'city': 'London'}, vector=None, shard_key=None)]

接下来进入 Web UI 与 Qdrant 向量数据库交互。如果在部署应用时配置了 Ingress,那么直接在浏览器中访问相应的地址即可,否则需要进行端口转发。通过 t9k-pf 进行端口转发:

t9k-pf -n <APP_PROJECT> pod qdrant-demo-0 6333:6333

在浏览器中访问 http://127.0.0.1:6333/dashboard 进入 Web UI。在 Console 页面中,用户可以直接调用 REST API 并得到响应结果:

loss

在 Collections 页面中,用户可以进行以下操作:

  • 浏览 collection 的所有数据点
  • 查看 collection 的基本信息
  • 制作和上传快照
  • 对数据点进行可视化
  • 删除 collection
loss
loss
loss

Web UI 的其他功能这里不再一一介绍,用户可以自行探索。

更多使用教程请进一步参阅 Qdrant 文档

参考

向量数据库:PostgreSQL + pgvector

向量数据库:Qdrant中我们介绍了向量数据库的概念以及开源产品 Qdrant。这里我们介绍另一个优秀的开源方案:PostgreSQL + pgvector。

PostgreSQL 是一个稳定可靠、功能强大的开源对象关系型数据库系统,第一个公开版本于 1989 年发布。此后,它经历了多次迭代,并逐渐成为世界上最流行的开源数据库之一。它支持 SQL 标准,并提供复杂查询、事务完整性、多版本并发控制等多种现代数据库技术特性。PostgreSQL 以其高度的扩展性和对大型数据集的强大处理能力而闻名,适用于从小型应用程序到大型企业系统的各种环境。此外,它还拥有一个活跃的开发社区,为开发者提供丰富的资源和工具。

pgvector 是一个用于向量相似性搜索的 PostgreSQL 扩展。安装此扩展后,PostgreSQL 可以支持向量数据的存储、检索和查询等操作。

部署

安装

进入 Notebook app 的终端,添加相应的 Helm Chart repository,列出 Chart bitnami/postgresql 的所有版本:

helm repo add bitnami https://charts.bitnami.com/bitnami

# 注意 CHART VERSION 和 APP VERSION(PostgreSQL 版本)之间的对应关系
# 例如 CHART VERSION 14.1.x 中的 PostgreSQL 版本都是 16.2.0
helm search repo bitnami/postgresql --versions

安装指定版本的 Chart 并指定 t9kpublic/bitnami-pgvector 镜像,以部署包含 pgvector 的 PostgreSQL 应用:

# 安装最新版本
helm repo update bitnami
helm install pgvector-demo bitnami/postgresql \
  --set image.repository=t9kpublic/bitnami-pgvector \
  --set image.tag=0.6.0-pg16

# 安装指定 CHART VERSION,注意这不是 APP VERSION(PostgreSQL 版本)
helm install pgvector-demo bitnami/postgresql \
  --version <CHART_VERSION> \
  --set image.repository=t9kpublic/bitnami-pgvector \
  --set image.tag=0.6.0-pg16

配置

以上安装全部使用默认配置,完整的默认配置请参阅 Parameters 以及相应的 values.yaml

# 获取指定 CHART VERSION 的 values.yaml
helm show values bitnami/postgresql --version <CHART_VERSION> > values.yaml

如果想要修改默认配置,你可以将新配置(覆盖默认配置的字段)保存为一个 YAML 文件,通过 -f 选项提供给安装命令:

# 使用修改后的 values.yaml
helm install pgvector-demo t9kpublic/bitnami-pgvector \
  --version <CHART_VERSION> \
  --set image.repository=t9kpublic/bitnami-pgvector \
  --set image.tag=0.6.0-pg16 \
  -f values.yaml

下面将分主题介绍部分关键配置(CHART VERSION 14.1.3)。

计算资源

默认配置没有指定计算资源,表示 Pod 可以无限制地使用节点的 CPU 和内存资源。你可以根据实际需求指定请求值和限制值,可以参阅管理内存用量的最佳实践

# 默认配置
primary:
  resources: {}

存储

默认配置指定的卷大小为 8Gi,并且没有指定存储类型。你可以根据数据规模修改卷大小,并选用高性能的存储类型。

# 默认配置
primary:
  persistence:
    existingClaim: ""     # 使用已有的 PVC
    subPath: ""           # 卷被挂载的子路径,用于多个服务共用一个卷
    storageClass: ""      # 存储类型
    accessModes:
      - ReadWriteOnce
    size: 8Gi             # 存储大小

网络

你可以按需修改 Service 配置,提供 tls 配置以提供外部安全访问。

# 默认配置
tls:                    # tls 配置
  enabled: false
  autoGenerated: false
  preferServerCiphers: true
  certificatesSecret: ""
  certFilename: ""
  certKeyFilename: ""
  certCAFilename: ""
  crlFilename: ""

primary:
  service:              # Service 配置
    type: ClusterIP
    ports:
      postgresql: 5432
    clusterIP: ""
    loadBalancerIP: ""
    externalTrafficPolicy: Cluster

安全

你可以设置 postgres 管理员用户的密码, 请参阅 Setting the root password on first run

auth:
  enablePostgresUser: true     # 启用 postgres 管理员用户
  postgresPassword: ""         # postgres 管理员用户的密码

备份

你可以启用数据库的定时备份并提供相应配置。注意这里的备份方法是转储(dump)而不是快照(snapshot)。

# 默认配置
backup:
  enabled: false
  cronjob:
    schedule: "@daily"
    timeZone: ""
    podSecurityContext:
      enabled: true
      fsGroupChangePolicy: Always
      sysctls: []
      supplementalGroups: []
      fsGroup: 1001
    containerSecurityContext:
      enabled: true
      seLinuxOptions: null
      runAsUser: 1001
      runAsNonRoot: true
      privileged: false
      readOnlyRootFilesystem: false
      allowPrivilegeEscalation: false
      capabilities:
        drop: ["ALL"]
      seccompProfile:
        type: "RuntimeDefault"
    command:
      - /bin/sh
      - -c
      - "pg_dumpall --clean --if-exists --load-via-partition-root --quote-all-identifiers --no-password --file=${PGDUMP_DIR}/pg_dumpall-$(date '+%Y-%m-%d-%H-%M').pgdump"
    storage:
      existingClaim: ""
      storageClass: ""
      accessModes:
       - ReadWriteOnce
      size: 8Gi
      subPath: ""

应用架构

应用的系统架构如下图所示(CHART VERSION 14.1.3,默认配置):

architecture

创建的主要 Kubernetes 资源如下表所示:

类型名称作用备注
Servicepgvector-demo-postgresql暴露 PostgreSQL 服务
StatefulSetpgvector-demo-postgresql部署 PostgreSQL + pgvector(包括持久化存储)默认计算资源为 {}
PVCdata-pgvector-demo-postgresql-*作为 PostgreSQL 的持久化存储默认卷大小为 8Gi
Secretpgvector-demo-postgresql存储 postgres 密钥

运维

查看应用的状态

helm status pgvector-demo

更新应用,下面的 image.tag 可能需要设置为其他值。

# 更新到最新版本
helm upgrade pgvector-demo t9kpublic/bitnami-pgvector \
  --set image.repository=t9kpublic/bitnami-pgvector \
  --set image.tag=0.6.0-pg16

# 更新到指定版本
helm upgrade pgvector-demo t9kpublic/bitnami-pgvector \
  --version <CHART_VERSION> \
  --set image.repository=t9kpublic/bitnami-pgvector \
  --set image.tag=0.6.0-pg16

# 回滚更新,首先查看历史版本
helm history pgvector-demo
helm rollback pgvector-demo [REVISION]

移除应用

helm delete pgvector-demo
kubectl delete pvc -l app.kubernetes.io/instance=pgvector-demo

使用

继续使用 Notebook app 的终端,获取应用的密钥,并连接到 PostgreSQL 实例:

export POSTGRES_PASSWORD=$(kubectl get secret --namespace demo pgvector-demo-postgresql -o jsonpath="{.data.postgres-password}" | base64 -d)
kubectl run pgvector-demo-postgresql-client \
  --rm --tty -i --restart='Never' --namespace demo \
  --image docker.io/t9kpublic/bitnami-pgvector:main \
  --env="PGPASSWORD=$POSTGRES_PASSWORD" \
  --command -- \
  psql --host pgvector-demo-postgresql -U postgres -d postgres -p 5432

使用 psql 命令启用 pgvector 扩展:

CREATE EXTENSION vector;

然后运行一个快速入门:

CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3));
INSERT INTO items (embedding) VALUES ('[1,2,3]'), ('[4,5,6]');
SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
DROP TABLE items;

接下来运行一个 Python 语言的官方示例。先安装必要的 Python 库:

pip install pgvector "psycopg[binary]" sentence_transformers

然后执行如下 Python 脚本,命令行参数需要提供连接字符串:

sentence_embeddings.py
import sys

from pgvector.psycopg import register_vector
import psycopg
from sentence_transformers import SentenceTransformer

# 创建数据库连接,并设置自动提交
conn = psycopg.connect(sys.argv[1], autocommit=True)

# 启用 pgvector 扩展,注册向量数据类型
conn.execute('CREATE EXTENSION IF NOT EXISTS vector')
register_vector(conn)

# 重新创建表 documents
conn.execute('DROP TABLE IF EXISTS documents')
conn.execute('CREATE TABLE documents (id bigserial PRIMARY KEY, content text, embedding vector(384))')

# 嵌入输入文本
input = [
    'The dog is barking',
    'The cat is purring',
    'The bear is growling'
]
model = SentenceTransformer('all-MiniLM-L6-v2')
embeddings = model.encode(input)

# 将输入文本和相应的嵌入向量插入到数据库中
for content, embedding in zip(input, embeddings):
    conn.execute('INSERT INTO documents (content, embedding) VALUES (%s, %s)', (content, embedding))

# 查询与指定文档最相近的其他文档的文本内容
document_id = 1
neighbors = conn.execute('SELECT content FROM documents WHERE id != %(id)s ORDER BY embedding <=> (SELECT embedding FROM documents WHERE id = %(id)s) LIMIT 5', {'id': document_id}).fetchall()
for neighbor in neighbors:
    print(neighbor[0])
export POSTGRES_PASSWORD=$(kubectl get secret --namespace demo pgvector-demo-postgresql -o jsonpath="{.data.postgres-password}" | base64 -d)
python pgvector-test.py "host=pgvector-demo-postgresql port=5432 dbname=postgres user=postgres password=$POSTGRES_PASSWORD"

脚本创建了一个表,添加了一些向量数据,并进行了一次基本的向量查询。输出应类似于:

The bear is growling
The cat is purring

更多信息请参阅 pgvector 的 README 文档

参考

背景

人工智能(AI)技术的发展已经取得了显著的成果,并对各行业的发展产生了深远的影响。其中最为突出的成就是以深度学习为基础在计算机视觉、LLM 等领域的突破性成果。

AI 计算平台对于 AI 技术的开发和应用具有重要意义。它提供了一个集成化、高效的环境,让开发者和企业能够轻松地构建、训练和部署机器学习模型。这种便捷性极大地降低了 AI 技术的门槛,使得更多的组织和个人能够利用先进的 AI 能力。

  1. AI 计算平台通过提供高级的 AI 开发工具和预构建的模型,简化了 AI 开发流程。开发者不需要从头开始构建复杂的模型,而是可以基于现有的模型进行定制和优化,这加速了从概念到实现的过程。
  2. AI 计算平台提供了大规模的计算资源和数据管理能力,这对于处理大量数据和运行复杂的 AI 模型至关重要。用户可以根据需要轻松扩展资源,以适应不断变化的需求。
  3. 平台还包含丰富的协作和集成工具,使得团队可以更有效地合作开发。此外,它们还提供了严格的安全和隐私保护措施,保证了数据的安全性和合规性。

新的范式

AI 是一种崭新的计算范式,它具有数据驱动、基于实验的特点,并且经常需要进行大规模的计算。

  • 在传统软件开发中,程序员编写明确的指令或规则,来告诉计算机如何处理数据和执行任务。这种方法依赖于开发者对问题的深入理解以及能够准确预测所有可能的情况并据此编写代码。
  • 相比之下,AI 的开发更多地依赖于数据而不是预设的规则。在这种模式下,AI 系统通过大量数据来学习和识别模式,然后基于这些学习成果做出判断或预测。开发者不是直接编写处理每种情况的代码, 而是设计算法来让计算机自我学习和适应。这意味着 AI 系统在面对新数据时可以持续改进其性能和准确性。
  • 此外,AI 开发通常需要更多关注于数据的收集、处理和分析。数据的质量和量直接影响到模型的性能,因此数据预处理成为 AI 开发中的一个重要步骤。而在传统软件开发中,主要关注的是逻辑的构建和代码的优化。

总的来说,AI 的数据驱动计算范式更加强调数据本身和从数据中学习的能力,而不是像传统软件那样依赖于硬编码的指令和规则。 这种方法使得 AI 在处理复杂、动态和模糊的问题时更加有效,但也带来了对数据质量和巨大计算处理能力的依赖。

computation-paradigm-for-ai
图 1: AI 计算的要素。模型架构程序 + 数据集经过训练(模型参数优化)后产生 AI 模型。

系统需求

由于 AI 技术的特性,用户在开发和使用 AI 过程中,在系统方面提出了多方面的需求,希望能够:

  • 方便地构建、使用和迭代数据集、模型架构和参数,以及
  • 简单、可靠地使用大规模分布式并行、异构和加速计算等技术来快速、高效地运行大规模的数据处理、训练和推理计算等。

数据

AI 计算过程中读取或者产生的数据可以分为两类:主干数据、元数据。

  • 主干数据:训练数据集、模型等大体量数据。
  • 元数据:计算过程中的各种配置、超参数、指标等。
ai-data
图 2:AI 计算在数据方面的核心需求。1)针对大规模的数据(训练数据集、模型等)提供高性能、大容量和完善的生命周期管理支持;2)对 AI 实验过程中的各种配置、超参数、指标等进行方便地记录、存取、查询等,并提供丰富的可视化支持。

用户希望通过一致、多维度高度可扩展的机制来支持对数据的各种操作。例如,训练数据无论是100KiB 还是 100TiB,都能够使用同一套工具、SDK,API:

  1. 方便地使用数据:能够在探索、实验、训练过程中,简单、快速地使用不同的数据;
  2. 高性能地使用数据:支持训练过程中对数据的高速读取(训练数据集)、写入(checkpoint,模型本身);
  3. 可靠地维护数据:
    • 像代码一样维护数据版本 (versioning);
    • 记录数据的变化历史 (commits and logs);
    • 隔离 (branches)。
  4. 对 AI 计算过程中的配置、超参数、脚本、各种指标等,提供方便、完善的支持:
    • 元数据管理系统为基础底座;
    • SDK 支持在各种场景进行集成;
    • 可视化工具方便地跟踪、展示、比较、分析多个实验过程。

计算

用户希望能够通过便捷的方式使用大规模分布式并行、异构、加速计算等技术以快速、高效地运行大规模的数据处理、训练和推理计算等。

scalable-ai-compute
图 3: 方便地进行计算。系统支持以同样的方式定义、运行、调试 AI 领域的各种计算任务。例如,使用 1 张 GPU 的训练任务和使用 1000 张 GPU 的训练任务可以使用一致的方式来完成。

AI 计算场景的典型需求:

类别需求说明
软件包依赖清晰、一致、方便地管理对 Pyhton 脚本、GPU 驱动程序、网络驱动程序等各种软件包的依赖
计算环境支持在 dev、 train、test、deploy 等环境方便地切换、迭代
数据、代码高效、便捷地使用数据、脚本、配置及跟踪它们的变化
计算资源快速、简单、方便地请求和使用各种计算资源:CPU、RAM、GPU、高速网络、存储…
运行计算可靠、简单、方便地运行个各种类型的计算:开发环境、并行训练、微调、数据处理、推理服务…

Kubernetes

Kubernetes 是一个灵活、可扩展的容器集群管理平台,它通过 Master 节点的集中控制和调度,工作节点(Worker Nodes) 负责运行应用工作负载。工作节点可方便地动态伸缩规模。

k8s-arch
图 4:Kubernetes 架构图。Source: https://en.wikipedia.org/wiki/Kubernetes

如上图所示,Kubernetes 的整体架构主要包含以下组件:

Master 节点: Master 节点负责整个集群的控制和管理。主要包含以下组件:

  • kube-apiserver:提供了资源操作的统一入口,以 RESTful API 方式提供服务。
  • etcd:负责存储集群的配置信息和资源状态。
  • kube-scheduler:负责资源的调度,按照预定的调度策略将 Pod 调度到相应的节点上。
  • kube-controller-manager: 负责管理控制器,确保集群处于预期的状态。

Node节点:Node 节点是 Kubernetes 集群中的工作节点,由 Master 节点管理,主要包含以下组件:

  • kubelet:负责管理 Node 节点上的 Pod 和容器的生命周期。
  • kube-proxy:负责为 Service 提供 cluster 内部的服务发现和负载均衡。
  • 容器运行时(containerd,CRI-O,Docker 等): 负责真正运行容器的软件。

Kubernetes 还包括其他辅助模块(Add-ons),例如:

  • DNS 模块:负责为集群中的主机提供 DNS 解析服务。
  • 网络插件:负责提供底层的网络实现,例如 flannel 和 calico。
  • 参数模块:提供配置管理功能。
  • 仪表板插件:提供 GUI。
  • 存储插件:提供持久化存储实现,例如 Ceph 和 Luster 。
  • 日志模块:提供日志收集、存储功能。
  • 安全模块:提供认证、授权、准入控制等安全功能。

TensorStack AI 计算平台

TensorStack AI 计算平台构建于以 Kubernetes 为核心的云原生技术,采用开放的、标准的、被普遍采用的、无厂商锁定风险的技术和协议,并能够:

  1. 长期稳定迭代、不断进步;
  2. 提供高度可靠性;
  3. 提供高度安全性;
  4. 支持在多个维度(计算规模、数据规模、硬件架构等)方便进行扩展。
ai-infra
图 5:TensorStack AI 计算平台。 平台采用开放的、标准的、被普遍采用的、无厂商锁定风险的技术和协议;并在稳定性、可靠性、扩展性、安全性多方面具备优异的能力。

TensorStack 对 AI 计算中的主要系统问题及解决方法:

  1. 软件包依赖

    采用容器镜像清晰、一致、方便地管理对 Pyhton 脚本、GPU 驱动程序、网络驱动程序等各种软件包的依赖:

     - 稳定的基础镜像:跟随框架(PyTorch)等主要依赖发布;
     - 镜像全流程支持:制作、发布到 Registry、运行。
    
  2. 计算环境

    采用 Infrastructure As Code 原则 + 容器镜像 + 网络存储的机制支持在 dev、 train、test、deploy 等环境方便地切换、迭代数据、代码。

  3. 数据、代码

    通过网络存储 + 服务(Version Control,AI DB,Experiment Management 等)支持高效、便捷地使用数据、脚本、配置及跟踪它们的变化。

  4. 计算资源

    通过 CRD controller + resource scheduler,实现快速、简单、方便地请求和使用各种计算资源:CPU、RAM、GPU、高速网络、存储…

  5. 运行计算

    T9k Jobs + Services 等实现可靠、简单、方便地运行个各种类型的计算:开发环境、并行训练、微调、数据处理、推理服务…

TensorStack AI 计算平台将在推动 AI 技术的普及和应用方面发挥着关键作用,为各行各业提供实现 AI 驱动创新的关键工具和资源。

参考

Infrastructure for deep learning, 2016
https://openai.com/research/infrastructure-for-deep-learning

Scaling Kubernetes to 2,500 nodes, 2018
https://openai.com/research/scaling-kubernetes-to-2500-nodes

Scaling Kubernetes to 7,500 nodes, 2021
https://openai.com/research/scaling-kubernetes-to-7500-nodes

Borg, Omega, and Kubernetes - Lessons learned from three container-management systems over a decade, 2016
https://queue.acm.org/detail.cfm?id=2898444

Large-scale cluster management at Google with Borg, 2015
https://research.google/pubs/pub43438/

Omega: flexible, scalable schedulers for large compute clusters, 2013
https://research.google/pubs/pub41684/

Kubernetes as a Platform for building Platforms with Mario-Leander Reimer, 2022
https://www.youtube.com/watch?v=wDMbBSVNzWY

Cloud-native computing
https://en.wikipedia.org/wiki/Cloud-native_computing

Cloud Native Computing Foundation
https://www.cncf.io/

Infrastructure As Code
https://en.wikipedia.org/wiki/Infrastructure_as_code