跳到主要内容

使用Distributed Training Tools在弹性容器集群中进行微调

在大模型专题中用PyTorch在弹性容器集群中进行微调,我们已经实践了如何在弹性容器集群中进行微调,但是这样的方式有个缺点:无法在任务结束时,自动关闭pod,导致一直在消耗DCU。

本示例给出一个基于K8s基础的Job资源,在弹性容器集群中运行分布式微调任务。

方案概述

image-20250110102211781

该方案基于K8s的基础资源Job,通过Job来启动多个pod作为一个集群,并在该集群上运行分布式计算任务。当任务完成后,会自动释放这些pod资源。

使用Job的优点:

  • 自动化:Job专门用于运行一次性任务,这些任务在完成后通常不需要持续运行。
  • 弹性:用户可以指定并行运行的Pod数量,以满足不同任务的需求。

当然,使用Job的时候,集群启动后将开启分布式计算任务,因此需要注意以下几点:

  • 启动分布式训练任务之前,需要将数据准备完备,包括数据、代码、环境等。
  • 计算任务需要的资源(如GPU、CPU等)需要预留足够的资源,否则可能会导致资源不足而任务失败。
  • 计算任务的完成后,集群资源会自动释放,因此计算任务的输出结果需要保存到外部存储,以便后续使用。

因此,本方案中采用PVC(Persistent Volume Claim)来共享计算的代码、数据等,并保存计算任务的输出结果。

另外,通过VSCode,可以同时挂载PVC,那么就可以在VSCode中编辑代码、管理数据,并实时查看任务的输出结果。

前置条件

本教程假定您已经具备以下条件:

教程源代码

首先下载本教程所需要的源码文件

清单

本教程包含以下文件,以下是文件的作用说明。

文件名说明
Dockerfile镜像构建文件:用来构建docker镜像
dev_pod.yaml定义Pod资源:启动一个pod用来开发
distributed_training_tools.py快速部署脚本
llama_sft微调示例代码(文件夹)

llama_sft微调示例代码包含以下文件,以下是文件的作用说明。

文件名说明
ds_config.jsondeepspeed配置文件
sft_data.json微调数据集
llama_sft.pyPython脚本
llama_sft_ds_job.sh使用job资源进行多节点多GPU微调脚本

清单文件详细介绍

Dockerfile

基于Pytorch的基础镜像,自定义镜像。

创建conda环境;

安装额外的 Python 包,例如:transformers,torch,peft,jupyterlab;

设置工作目录为/workspace等操作。

# 使用官方 PyTorch 镜像作为基础镜像
FROM pytorch/pytorch:2.3.1-cuda12.1-cudnn8-devel

# 更新包列表并安装系统级软件包
RUN apt-get update && \
apt-get install -y rclone curl vim iputils-ping sudo && \
apt-get clean && rm -rf /var/lib/apt/lists/*



# 设置环境变量,避免在非交互模式下使用 conda 时出现警告
ENV CONDA_AUTO_UPDATE_CONDA=false \
PATH=/opt/conda/envs/py310/bin:$PATH

# 创建一个新的 conda 环境并激活它
RUN conda create -n py310 python=3.10 -y && \
echo "source activate py310" > ~/.bashrc

# 安装所需的 Python 包和 Jupyter Notebook
RUN conda run -n py310 pip install --no-cache-dir \
transformers==4.41.2 \
deepspeed==0.14.3 \
peft==0.11.1 \
torch==2.3.1 torchvision==0.18.1 torchaudio==2.3.1 --index-url https://download.pytorch.org/whl/cu121 \
numpy==1.23.5 \
aim==3.19.1 \
jupyter \
-i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn

# 暴露 Jupyter 默认端口
EXPOSE 8888

# 设置工作目录
WORKDIR /workspace

# 启动 Jupyter Notebook 服务
CMD ["conda", "run", "-n", "py310", "jupyter", "notebook", "--ip=0.0.0.0", "--port=8888", "--no-browser", "--allow-root"]

dev_pod

在本示例中,启动了一个pod,专门用来开发使用,您可以使用vscode连接到这个pod中,进行模型下载,脚本编写,编码等工作。

apiVersion: v1
kind: Pod
metadata:
name: dev-pod
namespace: llama
labels:
app: dev
spec:
restartPolicy: Never
containers:
- name: dev-container
image: registry.hd-01.alayanew.com:8443/vc-huangxs/pytorch:2.3.1-cuda12.1-cudnn8-pyton310-transformers4.41.2-devel # 替换自己镜像
imagePullPolicy: Always
resources:
requests: # Added resource requests
memory: "4Gi"
cpu: "500m"
limits:
memory: "8Gi" # Added memory limit
cpu: "1000m" # Added CPU limit
ports: # 添加端口映射
- containerPort: 80 # 容器内应用的端口
name: http-port
protocol: TCP
command: ["sh", "-c", "tail -f /dev/null"]
volumeMounts:
- name: workspace
mountPath: "/workspace"
subPath: "dtt/workspace"
imagePullSecrets:
- name: harbor-secret
volumes:
- name: workspace
persistentVolumeClaim:
claimName: pvc-capacity-userdata

distributedTrainingTools.py

快速部署脚本。

按照提示说明修改自定义参数(kubeconfig、VKD-ID、pvc_name、work_dir、cmd等),并执行。

脚本会自动创建指定的命名空间,并创建好pvc,secret,service,job等资源,开始分布式训练任务。

快速开始

镜像准备

用户名密码:查看开通镜像仓库时的通知短信
镜像仓库访问地址:参考镜像仓库的使用
镜像仓库访问地址:由 访问域名/项目 组成

使用文件清单中的Dockerfile自定义镜像,这里您可根据自己的实际情况来自定义自己的镜像。

# pull image
docker pull pytorch/pytorch:2.3.1-cuda12.1-cudnn8-devel

# build image
docker build -t pytorch:2.3.1-cuda12.1-cudnn8-pyton310-transformers4.41.2-devel -f [/path/to/Dockerfile] .

#login
docker login 镜像仓库访问域名/ -u [user] -p [passwd]

# tag
docker tag \
pytorch:2.3.1-cuda12.1-cudnn8-pyton310-transformers4.41.2-devel \
[镜像仓库访问地址]/pytorch:2.3.1-cuda12.1-cudnn8-pyton310-transformers4.41.2-devel

# push
docker push [镜像仓库访问地址]/pytorch:2.3.1-cuda12.1-cudnn8-pyton310-transformers4.41.2-devel

创建k8s基础资源

# 声明弹性容器集群配置
export KUBECONFIG="[/path/to/kubeconfig]"

# 创建namespace
kubectl create namespace llama

# 创建secret
kubectl create secret docker-registry harbor-secret \
--docker-server=镜像仓库访问域名\
--docker-username="user" \
--docker-password="password" \
--docker-email="email" \
--namespace llama

在dev-pod中做开发准备

我们可以在dev-pod中进行模型下载,脚本开发等前期准备工作。

创建dev-pod

kubectl create -f dev_pod.yaml

image-20241224181606557

进入pod中的工作目录

kubectl exec -it pod/dev-pod  bash -n llama

image-20241224181654105

下载模型

将模型下载到持久化目录,之后就不用再次下载了。

本教程中挂载的持久化目录为“/workspace”。

这里我们将模型下载到以下目录“/workspace/Meta-Llama-3-8B-Instruct”。

pip install modelscope
modelscope download --model LLM-Research/Meta-Llama-3-8B-Instruct --local_dir /workspace/Meta-Llama-3-8B-Instruct

image-20241224181509960

脚本准备

您可以通过vscode连接dev-pod编写开发脚本。具体操作请参考文档:VSCode客户端远程开发(devContainer/Kubernetes)

同时,您也可以把已经开发好的脚本放到对象存储中。从对象存储中拉取脚本。

对象存储的使用请参考对象存储的使用在弹性容器集群中使用对象存储

本教程中,我们已经把脚本放到了对象存储。这里我们将使用rclone,将配置文件从对象存储中拉取下来。

  1. 编写配置文件 /root/.config/rclone/rclone.conf,文件内容如下:
[store]     #自定义的名称
type = s3
provider = Ceph
access_key_id = 3CCE5ZNO1PW034C8LFF9 #替换成你自己的access_key_id
secret_access_key = aVTIoDlSuU8gbVJvzezOA0x5Vh9jYVuzng7CX3fd #替换成你自己的secret_access_key
endpoint = http://dingofs.hdd.mas.zetyun.cn:8081
acl = public-read-write
no_check_bucket = true
  1. 将微调脚本拷贝到持久化目录,本教程的脚本目录为“/workspace/llama_sft”。
rcolne lsd store:hxs/demo
rclone copy store:hxs/demo/llama_sft /workspace/llama_sft

image-20241224184802364

一键启动训练任务

python distributed_training_tools.py --namespace="<your_namespace>" \
--kubeconfig="</path/to/kubeconfig>" \
--vks_id="<your_vks_id>" \
--pvc_name="<your_pvc_name>" \
--work_dir="</path/to/workdir>" \
--cmd="<The script you want to execute in the pod>" \
--labels="<distributed-training>" \
--image="<The image >" \
--harbor_secret="<harbor-secret>" \
--service_name="<distributed-training-svc>" \
--docker_server="registry.hd-01.alayanew.com:8443" \
--docker_username="<your_harbor_username>" \
--docker_password="<your_harbor_password>" \
--email="<your_email>" \
--gpu_type="<nvidia.com/gpu-h800>" \
--gpu_count="<2>" \
--nnodes="<2>" \
--nproc_per_node="<2>"
提示

注意:请替换以上参数为你自己的实际参数

请确保您的pvc改在目录与镜像的工作目录能够匹配,执行脚本存在,并且有相应的执行权限。

查看启动的pod信息

kubectl get all -n llama

image-20250110101607225

查看日志

主节点

image-20250110101850035

从节点

image-20250110101951733

监控GPU使用情况

主节点

kubectl exec -it pod/distributed-training-job-0-lmsgr  bash -n llama

watch -n 1 nvidia-smi

image-20250110102211781

从节点

kubectl exec -it pod/distributed-training-job-0-lmsgr  bash -n llama

watch -n 1 nvidia-smi

image-20250110102309211