@@ -0,0 +1,8 @@
|
||||
pip install -r requirements/docs.txt
|
||||
cd docs
|
||||
rm -rf build
|
||||
|
||||
# update api rst
|
||||
#rm -rf source/api/
|
||||
#sphinx-apidoc --module-first -o source/api/ ../modelscope/
|
||||
make html
|
||||
@@ -0,0 +1,242 @@
|
||||
NPU_TORCH_VERSION=${NPU_TORCH_VERSION:-2.7.1}
|
||||
NPU_TORCH_NPU_VERSION=${NPU_TORCH_NPU_VERSION:-2.7.1.post2}
|
||||
NPU_MODELSCOPE_VERSION=${NPU_MODELSCOPE_VERSION:-1.37.0}
|
||||
NPU_PIP_INDEX=${NPU_PIP_INDEX:-https://mirrors.aliyun.com/pypi/simple/}
|
||||
NPU_CONSTRAINT_FILE=${NPU_CONSTRAINT_FILE:-/tmp/ms_swift_npu_constraints.txt}
|
||||
NPU_PIP_BLOCK_CUDA_DEPS=${NPU_PIP_BLOCK_CUDA_DEPS:-True}
|
||||
|
||||
print_npu_warning() {
|
||||
echo "======================================================================"
|
||||
echo "WARNING: NPU runtime is unavailable, tests will continue on CPU path"
|
||||
echo "======================================================================"
|
||||
}
|
||||
|
||||
setup_npu_pip_constraints() {
|
||||
cat >"$NPU_CONSTRAINT_FILE" <<EOF
|
||||
torch==$NPU_TORCH_VERSION
|
||||
torch_npu==$NPU_TORCH_NPU_VERSION
|
||||
modelscope==$NPU_MODELSCOPE_VERSION
|
||||
EOF
|
||||
if [ "$NPU_PIP_BLOCK_CUDA_DEPS" == "True" ]; then
|
||||
cat >>"$NPU_CONSTRAINT_FILE" <<'EOF'
|
||||
# NPU CI should not resolve CUDA runtime wheels. If a dependency starts requiring
|
||||
# these packages, fail in pip's resolver instead of downloading hundreds of MB.
|
||||
cuda-toolkit<0
|
||||
nvidia-cublas<0
|
||||
nvidia-cuda-runtime<0
|
||||
nvidia-cuda-nvrtc<0
|
||||
nvidia-cuda-cupti<0
|
||||
nvidia-cudnn<0
|
||||
nvidia-cufft<0
|
||||
nvidia-curand<0
|
||||
nvidia-cusolver<0
|
||||
nvidia-cusparse<0
|
||||
nvidia-nccl<0
|
||||
nvidia-nvjitlink<0
|
||||
nvidia-nvtx<0
|
||||
nvidia-cublas-cu12<0
|
||||
nvidia-cuda-runtime-cu12<0
|
||||
nvidia-cuda-nvrtc-cu12<0
|
||||
nvidia-cuda-cupti-cu12<0
|
||||
nvidia-cudnn-cu12<0
|
||||
nvidia-cufft-cu12<0
|
||||
nvidia-curand-cu12<0
|
||||
nvidia-cusolver-cu12<0
|
||||
nvidia-cusparse-cu12<0
|
||||
nvidia-cusparselt-cu12<0
|
||||
nvidia-nccl-cu12<0
|
||||
nvidia-nvjitlink-cu12<0
|
||||
nvidia-nvtx-cu12<0
|
||||
EOF
|
||||
fi
|
||||
export PIP_CONSTRAINT="$NPU_CONSTRAINT_FILE"
|
||||
export UV_CONSTRAINT="$NPU_CONSTRAINT_FILE"
|
||||
echo "Using NPU pip constraints: $PIP_CONSTRAINT"
|
||||
cat "$PIP_CONSTRAINT"
|
||||
}
|
||||
|
||||
is_npu_runtime_matched() {
|
||||
python - <<PY
|
||||
import importlib.util
|
||||
|
||||
expected_torch = '$NPU_TORCH_VERSION'
|
||||
expected_torch_npu = '$NPU_TORCH_NPU_VERSION'
|
||||
|
||||
try:
|
||||
import torch
|
||||
except Exception:
|
||||
raise SystemExit(1)
|
||||
|
||||
if importlib.util.find_spec('torch_npu') is None:
|
||||
raise SystemExit(1)
|
||||
|
||||
try:
|
||||
import torch_npu
|
||||
except Exception:
|
||||
raise SystemExit(1)
|
||||
|
||||
torch_version = torch.__version__.split('+', 1)[0]
|
||||
torch_npu_version = getattr(torch_npu, '__version__', '')
|
||||
if torch_version == expected_torch and torch_npu_version == expected_torch_npu:
|
||||
raise SystemExit(0)
|
||||
|
||||
print(f'WARNING: NPU runtime version mismatch: torch={torch.__version__}, torch_npu={torch_npu_version}; '
|
||||
f'expected torch=={expected_torch}, torch_npu=={expected_torch_npu}')
|
||||
raise SystemExit(1)
|
||||
PY
|
||||
}
|
||||
|
||||
ensure_npu_runtime() {
|
||||
if is_npu_runtime_matched; then
|
||||
echo "NPU runtime already matched: torch==$NPU_TORCH_VERSION torch_npu==$NPU_TORCH_NPU_VERSION"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Installing NPU runtime: torch==$NPU_TORCH_VERSION torch_npu==$NPU_TORCH_NPU_VERSION"
|
||||
if ! python -m pip install --force-reinstall "torch==$NPU_TORCH_VERSION" "torch_npu==$NPU_TORCH_NPU_VERSION" -i "$NPU_PIP_INDEX"; then
|
||||
echo "WARNING: Failed to install torch/torch_npu NPU runtime packages."
|
||||
print_npu_warning
|
||||
fi
|
||||
}
|
||||
|
||||
report_npu_runtime() {
|
||||
echo "==================== NPU runtime report ===================="
|
||||
echo "ASCEND_RT_VISIBLE_DEVICES=${ASCEND_RT_VISIBLE_DEVICES:-}"
|
||||
echo "CUDA_VISIBLE_DEVICES=${CUDA_VISIBLE_DEVICES:-}"
|
||||
echo "Installed torch/CUDA related pip packages:"
|
||||
python -m pip freeze | grep -Ei '^(torch|torch-npu|torch_npu|cuda-|nvidia-)' || true
|
||||
if command -v npu-smi >/dev/null 2>&1; then
|
||||
npu-smi info || echo "WARNING: npu-smi info failed."
|
||||
else
|
||||
echo "WARNING: npu-smi not found."
|
||||
fi
|
||||
python - <<'PY'
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
warning = 'WARNING: NPU runtime is unavailable, tests will continue on CPU path'
|
||||
print(f"ASCEND_RT_VISIBLE_DEVICES={os.environ.get('ASCEND_RT_VISIBLE_DEVICES', '')}")
|
||||
print(f"CUDA_VISIBLE_DEVICES={os.environ.get('CUDA_VISIBLE_DEVICES', '')}")
|
||||
|
||||
try:
|
||||
import torch
|
||||
print(f"torch={torch.__version__}")
|
||||
except Exception as e:
|
||||
print(f"WARNING: failed to import torch: {e!r}")
|
||||
print('=' * 70)
|
||||
print(warning)
|
||||
print('=' * 70)
|
||||
raise SystemExit(0)
|
||||
|
||||
try:
|
||||
import transformers
|
||||
print(f"transformers={transformers.__version__}")
|
||||
except Exception as e:
|
||||
print(f"WARNING: failed to import transformers: {e!r}")
|
||||
|
||||
if importlib.util.find_spec('torch_npu') is None:
|
||||
print('WARNING: torch_npu is not installed.')
|
||||
print('=' * 70)
|
||||
print(warning)
|
||||
print('=' * 70)
|
||||
raise SystemExit(0)
|
||||
|
||||
try:
|
||||
import torch_npu
|
||||
print(f"torch_npu={getattr(torch_npu, '__version__', 'unknown')}")
|
||||
except Exception as e:
|
||||
print(f"WARNING: failed to import torch_npu: {e!r}")
|
||||
print('=' * 70)
|
||||
print(warning)
|
||||
print('=' * 70)
|
||||
raise SystemExit(0)
|
||||
|
||||
try:
|
||||
npu = getattr(torch, 'npu', None)
|
||||
available = bool(npu is not None and npu.is_available())
|
||||
count = npu.device_count() if npu is not None else 0
|
||||
print(f"torch.npu.is_available={available}")
|
||||
print(f"torch.npu.device_count={count}")
|
||||
if not available:
|
||||
print('=' * 70)
|
||||
print(warning)
|
||||
print('=' * 70)
|
||||
except Exception as e:
|
||||
print(f"WARNING: failed to query torch.npu status: {e!r}")
|
||||
print('=' * 70)
|
||||
print(warning)
|
||||
print('=' * 70)
|
||||
PY
|
||||
echo "============================================================"
|
||||
}
|
||||
|
||||
if [ "$MODELSCOPE_SDK_DEBUG" == "True" ]; then
|
||||
if [ "$SWIFT_CI_USE_NPU" == "True" ]; then
|
||||
pip install uv -i https://mirrors.aliyun.com/pypi/simple/
|
||||
setup_npu_pip_constraints
|
||||
ensure_npu_runtime
|
||||
uv pip install -r requirements/tests.txt
|
||||
git config --global --add safe.directory /ms-swift
|
||||
git config --global user.email tmp
|
||||
git config --global user.name tmp.com
|
||||
# linter test
|
||||
if [ `git remote -v | grep alibaba | wc -l` -gt 1 ]; then
|
||||
pre-commit run -c .pre-commit-config_local.yaml --all-files
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "linter test failed"
|
||||
exit -1
|
||||
fi
|
||||
fi
|
||||
ensure_npu_runtime
|
||||
uv pip install -r requirements/framework.txt -U "transformers<5.0" "peft<0.19" "modelscope==1.37.0"
|
||||
ensure_npu_runtime
|
||||
uv pip install decord einops -U
|
||||
uv pip uninstall autoawq
|
||||
uv pip install optimum
|
||||
uv pip install diffusers
|
||||
uv pip install math-verify -i "$NPU_PIP_INDEX"
|
||||
uv pip install ray -i "$NPU_PIP_INDEX"
|
||||
uv pip install msgspec -i "$NPU_PIP_INDEX"
|
||||
uv pip install zmq -i "$NPU_PIP_INDEX"
|
||||
uv pip install .
|
||||
echo "NPU CI skips auto_gptq because it is a CUDA/GPTQ optional dependency."
|
||||
uv pip install bitsandbytes deepspeed -U
|
||||
if [ -f requirements/npu.txt ]; then
|
||||
uv pip install -r requirements/npu.txt
|
||||
fi
|
||||
ensure_npu_runtime
|
||||
report_npu_runtime
|
||||
else
|
||||
pip install -r requirements/tests.txt -i https://mirrors.aliyun.com/pypi/simple/
|
||||
git config --global --add safe.directory /ms-swift
|
||||
git config --global user.email tmp
|
||||
git config --global user.name tmp.com
|
||||
# linter test
|
||||
if [ `git remote -v | grep alibaba | wc -l` -gt 1 ]; then
|
||||
pre-commit run -c .pre-commit-config_local.yaml --all-files
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "linter test failed"
|
||||
exit -1
|
||||
fi
|
||||
fi
|
||||
pip install -r requirements/framework.txt -U -i https://mirrors.aliyun.com/pypi/simple/
|
||||
pip install decord einops -U -i https://mirrors.aliyun.com/pypi/simple/
|
||||
pip uninstall autoawq -y
|
||||
pip install optimum
|
||||
pip install diffusers
|
||||
pip install "transformers<5.0" "peft<0.19"
|
||||
pip install .
|
||||
pip install auto_gptq bitsandbytes deepspeed -U -i https://mirrors.aliyun.com/pypi/simple/
|
||||
fi
|
||||
else
|
||||
echo "Running case in release image, run case directly!"
|
||||
fi
|
||||
# remove torch_extensions folder to avoid ci hang.
|
||||
rm -rf ~/.cache/torch_extensions
|
||||
if [ $# -eq 0 ]; then
|
||||
ci_command="python tests/run.py --subprocess"
|
||||
else
|
||||
ci_command="$@"
|
||||
fi
|
||||
echo "Running case with command: $ci_command"
|
||||
$ci_command
|
||||
@@ -0,0 +1,89 @@
|
||||
#!/bin/bash
|
||||
MODELSCOPE_CACHE_DIR_IN_CONTAINER=/modelscope_cache
|
||||
CODE_DIR=$PWD
|
||||
CODE_DIR_IN_CONTAINER=/ms-swift
|
||||
MODELSCOPE_SDK_DEBUG=True
|
||||
echo "$USER"
|
||||
gpus='0,1 2,3'
|
||||
cpu_sets='0-15 16-31'
|
||||
cpu_sets_arr=($cpu_sets)
|
||||
is_get_file_lock=false
|
||||
CI_COMMAND=${CI_COMMAND:-bash .dev_scripts/ci_container_test.sh python tests/run.py --parallel 2 --run_config tests/run_config.yaml}
|
||||
echo "ci command: $CI_COMMAND"
|
||||
PR_CHANGED_FILES="${PR_CHANGED_FILES:-}"
|
||||
echo "PR modified files: $PR_CHANGED_FILES"
|
||||
PR_CHANGED_FILES=${PR_CHANGED_FILES//[ ]/#}
|
||||
echo "PR_CHANGED_FILES: $PR_CHANGED_FILES"
|
||||
idx=0
|
||||
for gpu in $gpus
|
||||
do
|
||||
exec {lock_fd}>"/tmp/gpu$gpu" || exit 1
|
||||
flock -n "$lock_fd" || { echo "WARN: gpu $gpu is in use!" >&2; idx=$((idx+1)); continue; }
|
||||
echo "get gpu lock $gpu"
|
||||
|
||||
CONTAINER_NAME="swift-ci-$idx"
|
||||
let is_get_file_lock=true
|
||||
|
||||
# pull image if there are update
|
||||
docker pull ${IMAGE_NAME}:${IMAGE_VERSION}
|
||||
if [ "$MODELSCOPE_SDK_DEBUG" == "True" ]; then
|
||||
echo 'debugging'
|
||||
docker run --rm --name $CONTAINER_NAME --shm-size=16gb \
|
||||
--cpuset-cpus=${cpu_sets_arr[$idx]} \
|
||||
--gpus='"'"device=$gpu"'"' \
|
||||
-v $CODE_DIR:$CODE_DIR_IN_CONTAINER \
|
||||
-v $MODELSCOPE_CACHE:$MODELSCOPE_CACHE_DIR_IN_CONTAINER \
|
||||
-v $MODELSCOPE_HOME_CACHE/$idx:/root \
|
||||
-v /home/admin/pre-commit:/home/admin/pre-commit \
|
||||
-e CI_TEST=True \
|
||||
-e TEST_LEVEL=$TEST_LEVEL \
|
||||
-e MODELSCOPE_CACHE=$MODELSCOPE_CACHE_DIR_IN_CONTAINER \
|
||||
-e MODELSCOPE_DOMAIN=$MODELSCOPE_DOMAIN \
|
||||
-e MODELSCOPE_SDK_DEBUG=True \
|
||||
-e HUB_DATASET_ENDPOINT=$HUB_DATASET_ENDPOINT \
|
||||
-e TEST_ACCESS_TOKEN_CITEST=$TEST_ACCESS_TOKEN_CITEST \
|
||||
-e TEST_ACCESS_TOKEN_SDKDEV=$TEST_ACCESS_TOKEN_SDKDEV \
|
||||
-e TEST_LEVEL=$TEST_LEVEL \
|
||||
-e MODELSCOPE_ENVIRONMENT='ci' \
|
||||
-e TEST_UPLOAD_MS_TOKEN=$TEST_UPLOAD_MS_TOKEN \
|
||||
-e MODEL_TAG_URL=$MODEL_TAG_URL \
|
||||
-e MODELSCOPE_API_TOKEN=$MODELSCOPE_API_TOKEN \
|
||||
-e PR_CHANGED_FILES=$PR_CHANGED_FILES \
|
||||
--workdir=$CODE_DIR_IN_CONTAINER \
|
||||
${IMAGE_NAME}:${IMAGE_VERSION} \
|
||||
$CI_COMMAND
|
||||
else
|
||||
docker run --rm --name $CONTAINER_NAME --shm-size=16gb \
|
||||
--cpuset-cpus=${cpu_sets_arr[$idx]} \
|
||||
--gpus='"'"device=$gpu"'"' \
|
||||
-v $CODE_DIR:$CODE_DIR_IN_CONTAINER \
|
||||
-v $MODELSCOPE_CACHE:$MODELSCOPE_CACHE_DIR_IN_CONTAINER \
|
||||
-v $MODELSCOPE_HOME_CACHE/$idx:/root \
|
||||
-v /home/admin/pre-commit:/home/admin/pre-commit \
|
||||
-e CI_TEST=True \
|
||||
-e TEST_LEVEL=$TEST_LEVEL \
|
||||
-e MODELSCOPE_CACHE=$MODELSCOPE_CACHE_DIR_IN_CONTAINER \
|
||||
-e MODELSCOPE_DOMAIN=$MODELSCOPE_DOMAIN \
|
||||
-e HUB_DATASET_ENDPOINT=$HUB_DATASET_ENDPOINT \
|
||||
-e TEST_ACCESS_TOKEN_CITEST=$TEST_ACCESS_TOKEN_CITEST \
|
||||
-e TEST_ACCESS_TOKEN_SDKDEV=$TEST_ACCESS_TOKEN_SDKDEV \
|
||||
-e TEST_LEVEL=$TEST_LEVEL \
|
||||
-e MODELSCOPE_ENVIRONMENT='ci' \
|
||||
-e TEST_UPLOAD_MS_TOKEN=$TEST_UPLOAD_MS_TOKEN \
|
||||
-e MODEL_TAG_URL=$MODEL_TAG_URL \
|
||||
-e MODELSCOPE_API_TOKEN=$MODELSCOPE_API_TOKEN \
|
||||
-e PR_CHANGED_FILES=$PR_CHANGED_FILES \
|
||||
--workdir=$CODE_DIR_IN_CONTAINER \
|
||||
${IMAGE_NAME}:${IMAGE_VERSION} \
|
||||
$CI_COMMAND
|
||||
fi
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Running test case failed, please check the log!"
|
||||
exit -1
|
||||
fi
|
||||
break
|
||||
done
|
||||
if [ "$is_get_file_lock" = false ] ; then
|
||||
echo 'No free GPU!'
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
MODELSCOPE_CACHE_DIR=/modelscope_cache
|
||||
CODE_DIR=$PWD
|
||||
MODELSCOPE_SDK_DEBUG=True
|
||||
echo "$USER"
|
||||
npus='0,1 2,3'
|
||||
is_get_file_lock=false
|
||||
CI_COMMAND=${CI_COMMAND:-bash .dev_scripts/ci_container_test.sh python tests/run.py --parallel 2 --run_config tests/run_config.yaml}
|
||||
echo "ci command: $CI_COMMAND"
|
||||
PR_CHANGED_FILES="${PR_CHANGED_FILES:-}"
|
||||
echo "PR modified files: $PR_CHANGED_FILES"
|
||||
PR_CHANGED_FILES=${PR_CHANGED_FILES//[ ]/#}
|
||||
echo "PR_CHANGED_FILES: $PR_CHANGED_FILES"
|
||||
idx=0
|
||||
for npu in $npus
|
||||
do
|
||||
exec {lock_fd}>"/tmp/npu$npu" || exit 1
|
||||
flock -n "$lock_fd" || { echo "WARN: npu $npu is in use!" >&2; idx=$((idx+1)); continue; }
|
||||
echo "get npu lock $npu"
|
||||
|
||||
let is_get_file_lock=true
|
||||
|
||||
# 设置环境变量
|
||||
export CI_TEST=True
|
||||
export SWIFT_CI_USE_NPU=True
|
||||
export TEST_LEVEL=$TEST_LEVEL
|
||||
export MODELSCOPE_CACHE=${MODELSCOPE_CACHE:-$MODELSCOPE_CACHE_DIR}
|
||||
export MODELSCOPE_DOMAIN=$MODELSCOPE_DOMAIN
|
||||
export HUB_DATASET_ENDPOINT=$HUB_DATASET_ENDPOINT
|
||||
export TEST_ACCESS_TOKEN_CITEST=$TEST_ACCESS_TOKEN_CITEST
|
||||
export TEST_ACCESS_TOKEN_SDKDEV=$TEST_ACCESS_TOKEN_SDKDEV
|
||||
export MODELSCOPE_ENVIRONMENT='ci'
|
||||
export TEST_UPLOAD_MS_TOKEN=$TEST_UPLOAD_MS_TOKEN
|
||||
export MODEL_TAG_URL=$MODEL_TAG_URL
|
||||
export MODELSCOPE_API_TOKEN=$MODELSCOPE_API_TOKEN
|
||||
export PR_CHANGED_FILES=$PR_CHANGED_FILES
|
||||
export ASCEND_RT_VISIBLE_DEVICES=$npu
|
||||
|
||||
if [ "$MODELSCOPE_SDK_DEBUG" == "True" ]; then
|
||||
export MODELSCOPE_SDK_DEBUG=True
|
||||
echo 'debugging'
|
||||
fi
|
||||
|
||||
# 切换到代码目录并执行命令
|
||||
cd $CODE_DIR
|
||||
eval $CI_COMMAND
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Running test case failed, please check the log!"
|
||||
exit -1
|
||||
fi
|
||||
break
|
||||
done
|
||||
|
||||
if [ "$is_get_file_lock" = false ] ; then
|
||||
echo 'No free NPU!'
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,49 @@
|
||||
name: "🐛 Bug Report"
|
||||
description: Create a bug report to help us improve ms-swift
|
||||
labels: ["bug"]
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for supporting ms-swift and taking the time to submit this issue.
|
||||
感谢你对 ms-swift 的支持和抽出时间提交相关 issue。
|
||||
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Checklist / 检查清单
|
||||
options:
|
||||
- label: I have searched existing issues, and this is a new bug report. / 我已经搜索过现有的 issues,确认这是一个新的 bug report。
|
||||
required: true
|
||||
|
||||
|
||||
- type: textarea
|
||||
id: bug-description
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: Bug Description / Bug 描述
|
||||
description: |
|
||||
Please describe the issue you encountered. It's better to include error screenshots or stack trace information.
|
||||
请详细描述你遇到的问题,最好包含报错截图或报错栈信息。
|
||||
|
||||
|
||||
- type: textarea
|
||||
id: reproduction-steps
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: How to Reproduce / 如何复现
|
||||
description: |
|
||||
Please provide steps to reproduce the issue, including ms-swift version, runtime environment, and detailed reproduction steps.
|
||||
请提供复现问题的步骤,包括 ms-swift 的版本、运行环境、详细的复现步骤等。
|
||||
|
||||
|
||||
- type: textarea
|
||||
id: additional-information
|
||||
attributes:
|
||||
label: Additional Information / 补充信息
|
||||
description: |
|
||||
Please provide any additional information here.
|
||||
在这里补充其他相关信息。
|
||||
@@ -0,0 +1,37 @@
|
||||
name: "🚀 Feature Request"
|
||||
description: Submit a request for a new feature
|
||||
labels: ["enhancement"]
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for supporting ms-swift and taking the time to submit this issue.
|
||||
感谢你对 ms-swift 的支持和抽出时间提交相关 issue。
|
||||
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Checklist / 检查清单
|
||||
options:
|
||||
- label: I have searched existing issues, and this is a new feature request. / 我已经搜索过现有的 issues,确认这是一个新的 Feature Request。
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: feature-request-description
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: Feature Request Description / Feature Request 描述
|
||||
description: |
|
||||
Please provide a detailed description of the new feature you would like to see added.
|
||||
请详细描述您希望添加的新功能特性。
|
||||
|
||||
|
||||
- type: textarea
|
||||
id: pull-request
|
||||
attributes:
|
||||
label: Pull Request / Pull Request 信息
|
||||
description: |
|
||||
Have you already submitted or plan to submit a Pull Request? Please share your plans.
|
||||
你是否已经提交或即将提交 Pull Request?请说明你的计划。
|
||||
@@ -0,0 +1,28 @@
|
||||
name: "🤔 Question & Discussion"
|
||||
description: Create an issue for questions and discussions
|
||||
labels: ["question"]
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for supporting ms-swift and taking the time to submit this issue.
|
||||
感谢你对 ms-swift 的支持和抽出时间提交相关 issue。
|
||||
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Checklist / 检查清单
|
||||
options:
|
||||
- label: I have searched existing issues, and this is a new question or discussion topic. / 我已经搜索过现有的 issues,确认这是一个新的问题与讨论。
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: question-description
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: Question Description / 问题描述
|
||||
description: |
|
||||
Please describe the question or topic you would like to discuss.
|
||||
请描述你想要讨论的问题或话题。
|
||||
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
@@ -0,0 +1,13 @@
|
||||
# PR type
|
||||
- [ ] Bug Fix
|
||||
- [ ] New Feature
|
||||
- [ ] Document Updates
|
||||
- [ ] More Models or Datasets Support
|
||||
|
||||
# PR information
|
||||
|
||||
Write the detail information belongs to this PR.
|
||||
|
||||
## Experiment results
|
||||
|
||||
Paste your experiment result here(if needed).
|
||||
@@ -0,0 +1,3 @@
|
||||
# Reporting Security Issues
|
||||
|
||||
Usually security issues of a deep learning project come from non-standard 3rd packages or continuous running services. If you are suffering from security issues from our project, please consider reporting to us. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.
|
||||
@@ -0,0 +1,77 @@
|
||||
name: citest
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- "release/**"
|
||||
paths-ignore:
|
||||
- "setup.*"
|
||||
- "requirements.txt"
|
||||
- "requirements/**"
|
||||
- "docs/**"
|
||||
- "tools/**"
|
||||
- ".dev_scripts/**"
|
||||
- "README.md"
|
||||
- "README_*.md"
|
||||
- "NOTICE"
|
||||
- ".github/workflows/lint.yaml"
|
||||
- ".github/workflows/publish.yaml"
|
||||
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "setup.*"
|
||||
- "requirements.txt"
|
||||
- "requirements/**"
|
||||
- "docs/**"
|
||||
- "tools/**"
|
||||
- ".dev_scripts/**"
|
||||
- "README.md"
|
||||
- "README_*.md"
|
||||
- "NOTICE"
|
||||
- ".github/workflows/lint.yaml"
|
||||
- ".github/workflows/publish.yaml"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
unittest:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: [self-hosted]
|
||||
timeout-minutes: 240
|
||||
steps:
|
||||
- name: ResetFileMode
|
||||
shell: bash
|
||||
run: |
|
||||
# reset filemode to allow action runner to delete files
|
||||
# generated by root in docker
|
||||
set -e
|
||||
source ~/.bashrc
|
||||
sudo chown -R $USER:$USER $GITHUB_WORKSPACE
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
env:
|
||||
GIT_CONFIG_PARAMETERS: "'core.hooksPath='"
|
||||
with:
|
||||
lfs: 'true'
|
||||
submodules: 'false'
|
||||
fetch-depth: ${{ github.event_name == 'pull_request' && 2 || 0 }}
|
||||
- name: Get changed files
|
||||
id: changed-files
|
||||
run: |
|
||||
if ${{ github.event_name == 'pull_request' }}; then
|
||||
echo "PR_CHANGED_FILES=$(git diff --name-only -r HEAD^1 HEAD | xargs)" >> $GITHUB_ENV
|
||||
else
|
||||
echo "PR_CHANGED_FILES=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }} | xargs)" >> $GITHUB_ENV
|
||||
fi
|
||||
- name: Checkout LFS objects
|
||||
run: git lfs checkout
|
||||
- name: Run unittest
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
source /mnt/modelscope/ci_env.sh
|
||||
bash .dev_scripts/dockerci.sh
|
||||
@@ -0,0 +1,98 @@
|
||||
name: citest-npu
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- "release/**"
|
||||
paths-ignore:
|
||||
- "setup.*"
|
||||
- "requirements.txt"
|
||||
- "requirements/**"
|
||||
- "docs/**"
|
||||
- "tools/**"
|
||||
- ".dev_scripts/**"
|
||||
- "README.md"
|
||||
- "README_*.md"
|
||||
- "NOTICE"
|
||||
- ".github/workflows/lint.yaml"
|
||||
- ".github/workflows/publish.yaml"
|
||||
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "setup.*"
|
||||
- "requirements.txt"
|
||||
- "requirements/**"
|
||||
- "docs/**"
|
||||
- "tools/**"
|
||||
- ".dev_scripts/**"
|
||||
- "README.md"
|
||||
- "README_*.md"
|
||||
- "NOTICE"
|
||||
- ".github/workflows/lint.yaml"
|
||||
- ".github/workflows/publish.yaml"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
unittest:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: [linux-aarch64-a2-1]
|
||||
timeout-minutes: 240
|
||||
container:
|
||||
image: 'ascendai/cann:8.3.rc2-910b-ubuntu22.04-py3.11'
|
||||
options: >-
|
||||
--privileged
|
||||
--device=/dev/davinci0
|
||||
--device=/dev/davinci1
|
||||
--device=/dev/davinci2
|
||||
--device=/dev/davinci3
|
||||
--device=/dev/davinci_manager
|
||||
--device=/dev/devmm_svm
|
||||
--device=/dev/hisi_hdc
|
||||
--volume=/usr/local/Ascend/driver:/usr/local/Ascend/driver:ro
|
||||
--volume=/usr/local/sbin/npu-smi:/usr/local/sbin/npu-smi:ro
|
||||
--volume=/etc/ascend_install.info:/etc/ascend_install.info:ro
|
||||
env:
|
||||
UV_INDEX_URL: "http://cache-service.nginx-pypi-cache.svc.cluster.local/pypi/simple"
|
||||
UV_EXTRA_INDEX_URL: "https://repo.huaweicloud.com/ascend/repos/pypi"
|
||||
UV_INDEX_STRATEGY: "unsafe-best-match"
|
||||
UV_INSECURE_HOST: "cache-service.nginx-pypi-cache.svc.cluster.local"
|
||||
UV_HTTP_TIMEOUT: 120
|
||||
UV_NO_CACHE: 1
|
||||
UV_SYSTEM_PYTHON: 1
|
||||
PIP_INDEX_URL: "http://cache-service.nginx-pypi-cache.svc.cluster.local/pypi/simple"
|
||||
PIP_TRUSTED_HOST: "cache-service.nginx-pypi-cache.svc.cluster.local"
|
||||
steps:
|
||||
- name: Config mirrors
|
||||
run: |
|
||||
sed -Ei 's@(ports|archive).ubuntu.com@cache-service.nginx-pypi-cache.svc.cluster.local:8081@g' /etc/apt/sources.list
|
||||
pip config set global.index-url http://cache-service.nginx-pypi-cache.svc.cluster.local/pypi/simple
|
||||
pip config set global.trusted-host cache-service.nginx-pypi-cache.svc.cluster.local
|
||||
pip install uv
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: ${{ github.event_name == 'pull_request' && 2 || 0 }}
|
||||
- name: Get changed files
|
||||
id: changed-files
|
||||
run: |
|
||||
if ${{ github.event_name == 'pull_request' }}; then
|
||||
echo "PR_CHANGED_FILES=$(git diff --name-only -r HEAD^1 HEAD | xargs)" >> $GITHUB_ENV
|
||||
else
|
||||
echo "PR_CHANGED_FILES=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }} | xargs)" >> $GITHUB_ENV
|
||||
fi
|
||||
- name: Run unittest
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
export IMAGE_NAME=ascendai/cann
|
||||
export IMAGE_VERSION=8.3.rc2-910b-ubuntu22.04-py3.11
|
||||
export TEST_LEVEL=0
|
||||
mkdir -p ~/.cache
|
||||
export MODELSCOPE_CACHE=~/.cache
|
||||
export CI_COMMAND='bash .dev_scripts/ci_container_test.sh python tests/run.py --parallel 2 --subprocess --run_config tests/run_config.yaml'
|
||||
bash .dev_scripts/dockerci_npu.sh
|
||||
@@ -0,0 +1,20 @@
|
||||
name: Close Stale Issues
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
close-stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Close stale issues
|
||||
uses: actions/stale@v8
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
days-before-stale: 90
|
||||
days-before-close: 7
|
||||
stale-issue-message: 'This issue has been inactive for over 3 months and will be automatically closed in 7 days. If this issue is still relevant, please reply to this message.'
|
||||
close-issue-message: 'This issue has been automatically closed due to inactivity. If needed, it can be reopened.'
|
||||
stale-issue-label: 'stale'
|
||||
exempt-all-issue-labels: true
|
||||
@@ -0,0 +1,22 @@
|
||||
name: Lint test
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: Install pre-commit hook
|
||||
run: |
|
||||
pip install pre-commit
|
||||
- name: Linting
|
||||
run: pre-commit run --all-files
|
||||
@@ -0,0 +1,29 @@
|
||||
name: release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v**'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-publish
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-n-publish:
|
||||
runs-on: ubuntu-22.04
|
||||
#if: startsWith(github.event.ref, 'refs/tags')
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- name: Install wheel
|
||||
run: pip install wheel packaging setuptools==69.5.1
|
||||
- name: Build ModelScope Swift
|
||||
run: python setup.py sdist bdist_wheel
|
||||
- name: Publish package to PyPI
|
||||
run: |
|
||||
pip install twine
|
||||
twine upload dist/* --skip-existing -u __token__ -p ${{ secrets.PYPI_API_TOKEN }}
|
||||
@@ -0,0 +1,156 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
tmp
|
||||
*.ttf
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
test.py
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
/package
|
||||
/temp
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
|
||||
.vscode
|
||||
.idea
|
||||
.run
|
||||
|
||||
# custom
|
||||
*.pkl
|
||||
*.pkl.json
|
||||
*.log.json
|
||||
*.whl
|
||||
*.tar.gz
|
||||
*.swp
|
||||
*.log
|
||||
*.tar.gz
|
||||
source.sh
|
||||
tensorboard.sh
|
||||
.DS_Store
|
||||
replace.sh
|
||||
result.png
|
||||
result.jpg
|
||||
result.mp4
|
||||
output/
|
||||
outputs/
|
||||
wandb/
|
||||
swanlog/
|
||||
*.out
|
||||
benchmarks/
|
||||
eval_output/
|
||||
eval_outputs/
|
||||
vlmeval/
|
||||
my_model/
|
||||
/data
|
||||
result/
|
||||
images
|
||||
/custom/
|
||||
megatron_output/
|
||||
/*-mcore/
|
||||
/*-hf/
|
||||
/*_cached_dataset/
|
||||
/sample_output/
|
||||
.qoder/
|
||||
|
||||
# Pytorch
|
||||
*.pth
|
||||
*.pt
|
||||
|
||||
# ast template
|
||||
ast_index_file.py
|
||||
@@ -0,0 +1,24 @@
|
||||
repos:
|
||||
- repo: https://github.com/pycqa/flake8.git
|
||||
rev: 7.3.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: https://github.com/PyCQA/isort.git
|
||||
rev: 8.0.1
|
||||
hooks:
|
||||
- id: isort
|
||||
- repo: https://github.com/google/yapf.git
|
||||
rev: v0.43.0
|
||||
hooks:
|
||||
- id: yapf
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks.git
|
||||
rev: v6.0.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: check-yaml
|
||||
- id: end-of-file-fixer
|
||||
- id: requirements-txt-fixer
|
||||
- id: double-quote-string-fixer
|
||||
- id: check-merge-conflict
|
||||
- id: mixed-line-ending
|
||||
args: ["--fix=lf"]
|
||||
@@ -0,0 +1,132 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual
|
||||
identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
contact@modelscope.cn.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series of
|
||||
actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||
community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.1, available at
|
||||
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
||||
[https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
||||
@@ -0,0 +1,59 @@
|
||||
# Contributor Guide
|
||||
|
||||
_Welcome to offer PRs, bug reports, documentation supplements or other types of contributions to SWIFT!_
|
||||
|
||||
## Table of Contents
|
||||
- [Code of Conduct](#-code-of-conduct)
|
||||
- [Contribution Process](#-contribution-process)
|
||||
- [Hardware support](#-Hardware-support)
|
||||
|
||||
## 📖 Code of Conduct
|
||||
Please refer to our [Code of Conduct documentation](./CODE_OF_CONDUCT.md).
|
||||
|
||||
## 🔁 Contribution Process
|
||||
### What We Need
|
||||
- New Technologies and New Models: SWIFT needs to support more open-source models and datasets, or new technologies that we have not paid attention to. If you are interested please submit a PR to us.
|
||||
- Technical Propagation: If you are interested in technical propagation, you are welcome to help us write tutorials, documents or videos on any website, and send us the link.
|
||||
- Community Contribution: You can write technical articles related to SWIFT, and submit them to us. After review and approval, we will publish them on the official ModelScope accounts (Zhihu, WeChat, etc.), with your name assigned.
|
||||
|
||||
### Incentives
|
||||
- we will issue electronic certificates to contributors on behalf of the ModelScope community, to encourage your selfless contributions.
|
||||
- We will offer small souvenirs related to the ModelScope Community.
|
||||
- We will provide free A10 computing power during the development period. For more details, please refer to [Hardware-support](#-Hardware-support) section.
|
||||
|
||||
### Submitting PR (Pull Requests)
|
||||
|
||||
Any feature development is carried out in the form of Fork and then PR on GitHub.
|
||||
1. Fork: Go to the [ms-swift](https://github.com/modelscope/ms-swift) page and click the **Fork button**. After completion, a SWIFT code repository will be cloned under your personal organization.
|
||||
2. Clone: Clone the code repository generated in the first step to your local machine and **create a new branch** for development. During development, please click the **Sync Fork button** in time to synchronize with the `main` branch to prevent code expiration and conflicts.
|
||||
3. Submit PR: After development and testing, push the code to the remote branch. On GitHub, go to the **Pull Requests page**, create a new PR, select your code branch as the source branch, and the `modelscope/ms-swift:main` branch as the target branch.
|
||||
|
||||
4. Write Description: It is necessary to provide a good feature description in the PR, so that the reviewers know the content of your modification.
|
||||
5. Review: We hope that the code to be merged is concise and efficient, so we may raise some questions and discuss them. Please note that any issues raised in the review are aimed at the code itself, not at you personally. Once all issues are discussed and resolved, your code will be approved.
|
||||
|
||||
### Code Standards and Development Approach
|
||||
SWIFT has conventional variable naming conventions and development approaches. Please follow these approaches as much as possible during development.
|
||||
1. Variable names are separated by underscores, and class names are named with the first letter of each word capitalized.
|
||||
2. All Python indentation uses four spaces instead of a tab.
|
||||
3. Choose well-known open-source libraries, avoid using closed-source libraries or unstable open-source libraries, and avoid repeating the existing code.
|
||||
|
||||
After the PR is submitted, SWIFT will perform two types of tests:
|
||||
- Code Lint Test: A static code compliance check test. please make sure that you have performed code lint locally in advance.
|
||||
```shell
|
||||
pip install pre-commit # In the swift folder
|
||||
pre-commit run --all-files # Fix the errors reported by pre-commit until all checks are successful
|
||||
```
|
||||
- CI Tests: Smoke tests and unit tests, please refer to the next section.
|
||||
|
||||
### Running CI Tests
|
||||
Before submitting the PR, please ensure that your development code is protected by test cases, such as smoke tests for new features, or unit tests for various edge cases. Reviewers will also pay attention to this during code review. At the same time, there will be dedicated services running CI Tests, running all test cases, and the code can only be merged after the test cases pass.
|
||||
|
||||
## ✅ Hardware support
|
||||
|
||||
ModelScope provides developers with free A10 GPU computing resources. For more details, please refer to the [ModelScope Notebook](https://modelscope.cn/my/mynotebook).
|
||||
|
||||
ms-swift Training WeChat Group:
|
||||
|
||||
<p align="left">
|
||||
<img src="asset/wechat.png" width="250" style="display: inline-block;">
|
||||
</p>
|
||||
@@ -0,0 +1,75 @@
|
||||
# 贡献者指引
|
||||
|
||||
*欢迎帮SWIFT提供Feature PR、Bug反馈、文档补充或其他类型的贡献!*
|
||||
|
||||
## 目录
|
||||
|
||||
- [代码规约](#-代码规约)
|
||||
- [贡献流程](#-贡献流程)
|
||||
- [资源支持](#-资源支持)
|
||||
|
||||
## 📖 代码规约
|
||||
|
||||
请查看我们的[代码规约文档](./CODE_OF_CONDUCT.md).
|
||||
|
||||
## 🔁 贡献流程
|
||||
|
||||
### 我们需要什么
|
||||
- 新技术和新模型:SWIFT需要支持更多的开源模型和数据集,或我们没有关注到的新技术,如果您对此有兴趣,可以提交PR给我们。
|
||||
- 技术布道:如果您对技术布道有兴趣,欢迎在任何网站上帮我们撰写教程文档或视频等,并将链接发给我们。
|
||||
- 社区供稿:您可以撰写和SWIFT有关的技术文章,并供稿给我们,我们审核通过后会在魔搭官方账号(知乎、公众号等)上进行发布,并属上您的名字。
|
||||
|
||||
### 激励
|
||||
|
||||
- 我们会以魔搭社区的身份给贡献者颁发电子证书,以鼓励您的无私贡献。
|
||||
- 我们会赠送相关魔搭社区相关周边小礼品。
|
||||
- 我们会赠送开发期间的免费A10算力,具体可以查看[资源支持](#-资源支持)章节。
|
||||
|
||||
### 提交PR(Pull Requests)
|
||||
|
||||
任何feature开发都在github上以先Fork后PR的形式进行。
|
||||
|
||||
1. Fork:进入[ms-swift](https://github.com/modelscope/ms-swift)页面后,点击**Fork按钮**执行。完成后会在您的个人组织下克隆出一个SWIFT代码库
|
||||
|
||||
2. Clone:将第一步产生的代码库clone到本地并**拉新分支**进行开发,开发中请及时点击**Sync Fork按钮**同步`main`分支,防止代码过期并冲突
|
||||
|
||||
3. 提交PR:开发、测试完成后将代码推送到远程分支。在github上点击**Pull Requests页面**,新建一个PR,源分支选择您提交的代码分支,目标分支选择`modelscope/ms-swift:main`分支
|
||||
|
||||
4. 撰写描述:在PR中填写良好的feature描述是必要的,让Reviewers知道您的修改内容
|
||||
|
||||
5. Review:我们希望合入的代码简洁高效,因此可能会提出一些问题并讨论。请注意,任何review中提出的问题是针对代码本身,而非您个人。在所有问题讨论通过后,您的代码会被通过
|
||||
|
||||
### 代码规范和开发方式
|
||||
|
||||
SWIFT有约定俗成的变量命名方式和开发方式。在开发中请尽量遵循这些方式。
|
||||
|
||||
1. 变量命名以下划线分割,类名以所有单词首字母大写方式命名
|
||||
2. 所有的python缩进都是四个空格取代一个tab
|
||||
3. 选用知名的开源库,避免使用闭源库或不稳定的开源库,避免重复造轮子
|
||||
|
||||
SWIFT在PR提交后会进行两类测试:
|
||||
|
||||
- Code Lint测试 对代码进行静态规范走查的测试,为保证改测试通过,请保证本地预先进行了Code lint。方法是:
|
||||
|
||||
```shell
|
||||
pip install pre-commit
|
||||
# 在swift文件夹内
|
||||
pre-commit run --all-files
|
||||
# 对pre-commit报的错误进行修改,直到所有的检查都是成功状态
|
||||
```
|
||||
|
||||
- CI Tests 冒烟测试和单元测试,请查看下一章节
|
||||
|
||||
### Running CI Tests
|
||||
|
||||
在提交PR前,请保证您的开发代码已经受到了测试用例的保护。例如,对新功能的冒烟测试,或者各种边缘case的单元测试等。在代码review时Reviewers也会关注这一点。同时,也会有服务专门运行CI Tests,运行所有的测试用例,测试用例通过后代码才可以合并。
|
||||
|
||||
## ✅ 资源支持
|
||||
|
||||
魔搭为开发者提供了免费的A10 GPU算力支持,具体参考[魔搭 Notebook](https://modelscope.cn/my/mynotebook)。
|
||||
|
||||
ms-swift训练微信群:
|
||||
|
||||
<p align="left">
|
||||
<img src="asset/wechat.png" width="250" style="display: inline-block;">
|
||||
</p>
|
||||
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1 @@
|
||||
recursive-include requirements *.txt
|
||||
@@ -0,0 +1,25 @@
|
||||
WHL_BUILD_DIR :=package
|
||||
DOC_BUILD_DIR :=docs/build/
|
||||
|
||||
# default rule
|
||||
default: whl docs
|
||||
|
||||
.PHONY: docs
|
||||
docs:
|
||||
bash .dev_scripts/build_docs.sh
|
||||
|
||||
.PHONY: linter
|
||||
linter:
|
||||
bash .dev_scripts/linter.sh
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
bash .dev_scripts/citest.sh
|
||||
|
||||
.PHONY: whl
|
||||
whl:
|
||||
python setup.py sdist bdist_wheel
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(WHL_BUILD_DIR) $(DOC_BUILD_DIR)
|
||||
@@ -0,0 +1,508 @@
|
||||
# SWIFT (Scalable lightWeight Infrastructure for Fine-Tuning)
|
||||
|
||||
<p align="center">
|
||||
<br>
|
||||
<img src="asset/banner.png"/>
|
||||
<br>
|
||||
<p>
|
||||
<p align="center">
|
||||
<a href="https://modelscope.cn/home">ModelScope Community Website</a>
|
||||
<br>
|
||||
<a href="README_CN.md">中文</a>   |   English  
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/python-3.12-5be.svg">
|
||||
<img src="https://img.shields.io/badge/pytorch-%E2%89%A52.0-orange.svg">
|
||||
<a href="https://github.com/modelscope/modelscope/"><img src="https://img.shields.io/badge/modelscope-%E2%89%A51.23-5D91D4.svg"></a>
|
||||
<a href="https://pypi.org/project/ms-swift/"><img src="https://badge.fury.io/py/ms-swift.svg"></a>
|
||||
<a href="https://github.com/modelscope/ms-swift/blob/main/LICENSE"><img src="https://img.shields.io/github/license/modelscope/ms-swift"></a>
|
||||
<a href="https://pepy.tech/project/ms-swift"><img src="https://pepy.tech/badge/ms-swift"></a>
|
||||
<a href="https://github.com/modelscope/ms-swift/pulls"><img src="https://img.shields.io/badge/PR-welcome-55EB99.svg"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://trendshift.io/repositories/11937" target="_blank"><img src="https://trendshift.io/api/badge/repositories/11937" alt="modelscope/ms-swift | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://arxiv.org/abs/2408.05517">Paper</a>   | <a href="https://swift.readthedocs.io/en/latest/">English Documentation</a>   |   <a href="https://swift.readthedocs.io/zh-cn/latest/">中文文档</a>  
|
||||
</p>
|
||||
|
||||
## 📖 Table of Contents
|
||||
- [Groups](#-Groups)
|
||||
- [Introduction](#-introduction)
|
||||
- [News](#-news)
|
||||
- [Installation](#%EF%B8%8F-installation)
|
||||
- [Quick Start](#-quick-Start)
|
||||
- [Usage](#-Usage)
|
||||
- [License](#-License)
|
||||
- [Citation](#-citation)
|
||||
|
||||
|
||||
## ☎ Groups
|
||||
|
||||
You can contact us and communicate with us by adding our group:
|
||||
|
||||
|
||||
[Discord Group](https://discord.gg/yeN59wxjwe) | WeChat Group
|
||||
:-------------------------:|:-------------------------:
|
||||
<img src="asset/discord_qr.jpg" width="200" height="200"> | <img src="asset/wechat.png" width="200" height="200">
|
||||
|
||||
|
||||
## 📝 Introduction
|
||||
🍲 **ms-swift** is a large model and multimodal large model fine-tuning and deployment framework provided by the ModelScope community. It now supports training (pre-training, fine-tuning, human alignment), inference, evaluation, quantization, and deployment for 600+ text-only large models and 400+ multimodal large models. Large models include: Qwen3, Qwen3.5, InternLM3, GLM4.5, Mistral, DeepSeek-R1, Llama4, etc. Multimodal large models include: Qwen3-VL, Qwen3-Omni, Llava, InternVL3.5, MiniCPM-V-4, Ovis2.5, GLM4.5-V, DeepSeek-VL2, etc.
|
||||
|
||||
🍔 In addition, ms-swift integrates the latest training technologies, including Megatron parallelism techniques such as TP, PP, CP, EP to accelerate training, as well as numerous GRPO algorithm family reinforcement learning algorithms including: GRPO, DAPO, GSPO, SAPO, CISPO, RLOO, Reinforce++, etc. to enhance model intelligence. ms-swift supports a wide range of training tasks, including preference learning algorithms such as DPO, KTO, RM, CPO, SimPO, ORPO, as well as Embedding, Reranker, and sequence classification tasks. ms-swift provides full-pipeline support for large model training, including acceleration for inference, evaluation, and deployment modules using vLLM, SGLang, and LMDeploy, as well as model quantization using GPTQ, AWQ, BNB, and FP8 technologies.
|
||||
|
||||
**Why Choose ms-swift?**
|
||||
|
||||
- 🍎 **Model Types**: Supports **600+ text-only large models**, **400+ multimodal large models**, and All-to-All full modality models from training to deployment full pipeline, with Day-0 support for popular models.
|
||||
- **Dataset Types**: Built-in 150+ datasets for pre-training, fine-tuning, human alignment, multimodal and various other tasks, with support for custom datasets. Users only need to prepare datasets for one-click training.
|
||||
- **Hardware Support**: Supports A10/A100/H100, RTX series, T4/V100, AMD GPU (MI300 series, etc.), CPU, MPS, and domestic hardware Ascend NPU, etc.
|
||||
- **Lightweight Training**: Supports lightweight fine-tuning methods such as LoRA, QLoRA, DoRA, LoRA+, LLaMAPro, LongLoRA, LoRA-GA, ReFT, RS-LoRA, Adapter, LISA, etc.
|
||||
- **Quantized Training**: Supports training on BNB, AWQ, GPTQ, AQLM, HQQ, EETQ quantized models, requiring only 9GB training resources for 7B models.
|
||||
- **Memory Optimization**: GaLore, Q-Galore, UnSloth, Liger-Kernel, Flash-Attention 2/3, and **Ulysses and Ring-Attention sequence parallelism techniques** support, reducing memory consumption for long-text training.
|
||||
- **Distributed Training**: Supports distributed data parallelism (DDP), device_map simple model parallelism, DeepSpeed ZeRO2 ZeRO3, FSDP/FSDP2, and Megatron distributed training technologies.
|
||||
- 🍓 **Multimodal Training**: Supports multimodal packing technology to improve training speed by 100%+, supports mixed modality data training with text, images, video and audio, and supports independent control of vit/aligner/llm.
|
||||
- **Agent Training**: Supports Agent templates, allowing one dataset to be used for training different models.
|
||||
- 🍊 **Training Tasks**: Supports pre-training and instruction fine-tuning, as well as training tasks such as DPO, GKD, KTO, RM, CPO, SimPO, ORPO, and supports **Embedding/Reranker** and sequence classification tasks.
|
||||
- 🥥 **Megatron Parallelism**: Provides TP/PP/SP/CP/ETP/EP/VPP parallel strategies to significantly boost **MoE model training speed**. Supports full-parameter and LoRA training methods for 300+ pure text large models and 100+ multimodal large models. Supports CPT/SFT/GRPO/DPO/KTO/RM training tasks.
|
||||
- 🍉 **Reinforcement Learning**: Built-in **rich GRPO family algorithms**, including GRPO, DAPO, GSPO, SAPO, CISPO, CHORD, RLOO, Reinforce++, etc. Supports synchronous and asynchronous vLLM engine inference acceleration, with extensible reward functions, multi-turn inference Schedulers, and environments through plugins.
|
||||
- **Full-Pipeline Capabilities**: Covers the entire workflow of training, inference, evaluation, quantization, and deployment.
|
||||
- **UI Training**: Provides Web-UI interface for training, inference, evaluation, and quantization, completing the full pipeline for large models.
|
||||
- **Inference Acceleration**: Supports Transformers, vLLM, SGLang, and LmDeploy inference acceleration engines, providing OpenAI interfaces for accelerating inference, deployment, and evaluation modules.
|
||||
- **Model Evaluation**: Uses EvalScope as the evaluation backend, supporting 100+ evaluation datasets for evaluating text-only and multimodal models.
|
||||
- **Model Quantization**: Supports quantization export for AWQ, GPTQ, FP8, and BNB. Exported models support inference acceleration using vLLM/SGLang/LmDeploy.
|
||||
|
||||
|
||||
## 🎉 News
|
||||
- 🎁 2026.06.10: Megatron-Ray now supports GRPO and GKD training. See [docs](./docs/source_en/Instruction/Ray.md) and [examples](examples/ray).
|
||||
- 🎁 2026.03.03: **ms-swift v4.0** major version is officially released. For release notes, please refer to [here](https://github.com/modelscope/ms-swift/releases/tag/v4.0.0). You can provide your suggestions to us in [this issue](https://github.com/modelscope/ms-swift/issues/7250). Thank you for your support.
|
||||
- 🎁 2025.11.14: Megatron GRPO is now available! Check out the [docs](./docs/source_en/Megatron-SWIFT/GRPO.md) and [examples](examples/megatron/grpo).
|
||||
- 🎁 2025.11.04: Support for [Mcore-Bridge](docs/source_en/Megatron-SWIFT/Mcore-Bridge.md), making Megatron training as simple and easy to use as transformers.
|
||||
- 🎁 2025.10.28: Ray [here](docs/source_en/Instruction/Ray.md).
|
||||
- 🎁 2025.09.07: Added support for CHORD training algorithm. See the [documentation](./docs/source_en/Instruction/GRPO/AdvancedResearch/CHORD.md).
|
||||
- 🎁 2025.09.06: Ulysses can now be used with ring-attention, allowing sequences to be sharded into any number of chunks (no longer limited by the number of heads). The argument remains `--sequence_parallel_size N`.
|
||||
- 🎁 2025.09.02: Megatron-SWIFT now supports multimodal model training. Documentation can be found [here](./docs/source_en/Megatron-SWIFT/Multimodal-Model.md).
|
||||
- 🎁 2025.08.12: Support [Dynamic Fine-Tuning](https://arxiv.org/abs/2508.05629)(DFT) in SFT training, use parameter `--enable_dft_loss true`. Training scripts can be found [here](https://github.com/modelscope/ms-swift/blob/main/examples/train/full/dft.sh).
|
||||
- 🎁 2025.07.09: Megatron-SWIFT supports LoRA training. Compared to ms-swift, it achieves significant speedup on MoE models. Training scripts can be found [here](https://github.com/modelscope/ms-swift/blob/main/examples/megatron/lora).
|
||||
- 🎁 2025.06.23: Fine-tuning of reranker models is supported. Training scripts can be found here: [Reranker](https://github.com/modelscope/ms-swift/blob/main/examples/train/reranker/train_reranker.sh).
|
||||
- 🎁 2025.06.15: Support for GKD training on both pure text large models and multimodal models. Training scripts can be found here: [Pure Text](https://github.com/modelscope/ms-swift/blob/main/examples/train/rlhf/gkd), [Multimodal](https://github.com/modelscope/ms-swift/blob/main/examples/train/multimodal/rlhf/gkd).
|
||||
|
||||
<details><summary>More</summary>
|
||||
|
||||
- 🎁 2025.06.11: Support for using Megatron parallelism techniques for RLHF training. The training script can be found [here](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/rlhf).
|
||||
- 🎁 2025.05.29: Support sequence parallel in pretrain, sft, dpo and grpo, check script [here](https://github.com/modelscope/ms-swift/tree/main/examples/train/sequence_parallel).
|
||||
- 🎁 2025.05.11: GRPO now supports custom processing logic for reward models. See the GenRM example [here](./docs/source_en/Instruction/GRPO/DeveloperGuide/reward_model.md).
|
||||
- 🎁 2025.04.15: The ms-swift paper has been accepted by AAAI 2025. You can find the paper at [this link](https://ojs.aaai.org/index.php/AAAI/article/view/35383).
|
||||
- 🎁 2025.03.23: Multi-round GRPO is now supported for training multi-turn dialogue scenarios (e.g., agent tool calling). Please refer to the [doc](./docs/source_en/Instruction/GRPO/DeveloperGuide/multi_turn.md).
|
||||
- 🎁 2025.03.16: Support for Megatron's parallel training techniques is now available. Please see the [Megatron-SWIFT training documentation](https://swift.readthedocs.io/en/latest/Megatron-SWIFT/Quick-start.html).
|
||||
- 🎁 2025.03.15: Fine-tuning of embedding models for both pure text and multimodal models is supported. Please check the [training script](examples/train/embedding).
|
||||
- 🎁 2025.03.05: The hybrid mode for GRPO is supported, with a script for training a 72B model on 4 GPUs (4*80G) available [here](examples/train/grpo/internal/vllm_72b_4gpu.sh). Tensor parallelism with vllm is also supported, with the training script available [here](examples/train/grpo/internal).
|
||||
- 🎁 2025.02.21: The GRPO algorithm now supports LMDeploy, with the training script available [here](examples/train/grpo/internal/full_lmdeploy.sh). Additionally, the performance of the GRPO algorithm has been tested, achieving a training speed increase of up to 300% using various tricks. Please check the WanDB table [here](https://wandb.ai/tastelikefeet/grpo_perf_test?nw=nwuseryuzezyz).
|
||||
- 🎁 2025.02.21: The `swift sample` command is now supported. The reinforcement fine-tuning script can be found [here](docs/source_en/Instruction/Reinforced-Fine-tuning.md), and the large model API distillation sampling script is available [here](examples/sampler/distill/distill.sh).
|
||||
- 🔥 2025.02.12: Support for the GRPO (Group Relative Policy Optimization) training algorithm has been added. Documentation is available [here](docs/source_en/Instruction/GRPO/GetStarted/GRPO.md).
|
||||
- 🎁 2024.12.04: Major update to **ms-swift 3.0**. Please refer to the [release notes and changes](docs/source_en/Instruction/ReleaseNote3.0.md).
|
||||
- 🎉 2024.08.12: The ms-swift paper has been published on arXiv and can be read [here](https://arxiv.org/abs/2408.05517).
|
||||
- 🔥 2024.08.05: Support for using [evalscope](https://github.com/modelscope/evalscope/) as a backend for evaluating large models and multimodal models.
|
||||
- 🔥 2024.07.29: Support for using [vllm](https://github.com/vllm-project/vllm) and [lmdeploy](https://github.com/InternLM/lmdeploy) to accelerate inference for large models and multimodal models. When performing infer/deploy/eval, you can specify `--infer_backend vllm/lmdeploy`.
|
||||
- 🔥 2024.07.24: Support for human preference alignment training for multimodal large models, including DPO/ORPO/SimPO/CPO/KTO/RM/PPO.
|
||||
- 🔥 2024.02.01: Support for Agent training! The training algorithm is derived from [this paper](https://arxiv.org/pdf/2309.00986.pdf).
|
||||
</details>
|
||||
|
||||
## 🛠️ Installation
|
||||
To install using pip:
|
||||
```shell
|
||||
pip install ms-swift -U
|
||||
|
||||
# Using uv
|
||||
pip install uv
|
||||
uv pip install ms-swift -U --torch-backend=auto
|
||||
```
|
||||
|
||||
To install from source:
|
||||
```shell
|
||||
# pip install git+https://github.com/modelscope/ms-swift.git
|
||||
|
||||
git clone https://github.com/modelscope/ms-swift.git
|
||||
cd ms-swift
|
||||
# The main branch is for swift 4.x. To install swift 3.x, please run the following command:
|
||||
# git checkout release/3.12
|
||||
pip install -e .
|
||||
|
||||
# Using uv
|
||||
uv pip install -e . --torch-backend=auto
|
||||
```
|
||||
|
||||
Running Environment:
|
||||
|
||||
| | Range | Recommended | Notes |
|
||||
|--------------|--------------|---------------------|-------------------------------------------|
|
||||
| python | >=3.10 | 3.12 | |
|
||||
| cuda | | cuda12.8/13.0 | No need to install if using CPU, NPU, MPS |
|
||||
| torch | >=2.0 | 2.8.0/2.11.0 | |
|
||||
| transformers | >=4.33 | 4.57.6/5.12.1 | |
|
||||
| modelscope | >=1.23 | | |
|
||||
| datasets | >=3.0,<4.8.5 | 3.6.0/4.8.4 | |
|
||||
| peft | >=0.11,<0.20 | | |
|
||||
| flash_attn | | 2.8.3/4.0.0b15 | |
|
||||
| trl | >=0.15,<1.0 | 0.29.1 | RLHF |
|
||||
| deepspeed | >=0.14 | 0.18.9 | Training |
|
||||
| vllm | >=0.5.1 | 0.11.0/0.23.0 | Inference/Deployment |
|
||||
| sglang | >=0.4.6 | | Inference/Deployment |
|
||||
| evalscope | >=1.0 | | Evaluation |
|
||||
| gradio | | 5.32.1 | Web-UI/App |
|
||||
|
||||
For more optional dependencies, you can refer to [here](https://github.com/modelscope/ms-swift/blob/main/requirements/install_all.sh).
|
||||
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
10 minutes of self-cognition fine-tuning of Qwen3-4B-Instruct-2507 on a single 3090 GPU:
|
||||
|
||||
### Command Line Interface (Recommended)
|
||||
|
||||
```shell
|
||||
# 13GB
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift sft \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--tuner_type lora \
|
||||
--dataset 'AI-ModelScope/alpaca-gpt4-data-zh#500' \
|
||||
'AI-ModelScope/alpaca-gpt4-data-en#500' \
|
||||
'swift/self-cognition#500' \
|
||||
--torch_dtype bfloat16 \
|
||||
--num_train_epochs 1 \
|
||||
--per_device_train_batch_size 1 \
|
||||
--per_device_eval_batch_size 1 \
|
||||
--learning_rate 1e-4 \
|
||||
--lora_rank 8 \
|
||||
--lora_alpha 32 \
|
||||
--target_modules all-linear \
|
||||
--gradient_accumulation_steps 16 \
|
||||
--eval_steps 50 \
|
||||
--save_steps 50 \
|
||||
--save_total_limit 2 \
|
||||
--logging_steps 5 \
|
||||
--max_length 2048 \
|
||||
--output_dir output \
|
||||
--warmup_ratio 0.05 \
|
||||
--dataloader_num_workers 4 \
|
||||
--model_author swift \
|
||||
--model_name swift-robot
|
||||
```
|
||||
|
||||
Tips:
|
||||
|
||||
- If you want to train with a custom dataset, you can refer to [this guide](https://swift.readthedocs.io/en/latest/Customization/Custom-dataset.html) to organize your dataset format and specify `--dataset <dataset_path>`.
|
||||
- The `--model_author` and `--model_name` parameters are only effective when the dataset includes `swift/self-cognition`.
|
||||
- To train with a different model, simply modify `--model <model_id/model_path>`.
|
||||
- By default, **ModelScope** is used for downloading models and datasets. If you want to use HuggingFace, simply specify `--use_hf true`.
|
||||
|
||||
After training is complete, use the following command to infer with the trained weights:
|
||||
|
||||
- Here, `--adapters` should be replaced with the last checkpoint folder generated during training. Since the adapters folder contains the training parameter file `args.json`, there is no need to specify `--model`, `--system` separately; Swift will automatically read these parameters. To disable this behavior, you can set `--load_args false`.
|
||||
|
||||
```shell
|
||||
# Using an interactive command line for inference.
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift infer \
|
||||
--adapters output/vx-xxx/checkpoint-xxx \
|
||||
--stream true \
|
||||
--temperature 0 \
|
||||
--max_new_tokens 2048
|
||||
|
||||
# merge-lora and use vLLM for inference acceleration
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift infer \
|
||||
--adapters output/vx-xxx/checkpoint-xxx \
|
||||
--stream true \
|
||||
--merge_lora true \
|
||||
--infer_backend vllm \
|
||||
--vllm_max_model_len 8192 \
|
||||
--temperature 0 \
|
||||
--max_new_tokens 2048
|
||||
```
|
||||
|
||||
Finally, use the following command to push the model to ModelScope:
|
||||
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift export \
|
||||
--adapters output/vx-xxx/checkpoint-xxx \
|
||||
--push_to_hub true \
|
||||
--hub_model_id '<your-model-id>' \
|
||||
--hub_token '<your-sdk-token>' \
|
||||
--use_hf false
|
||||
```
|
||||
|
||||
|
||||
### Web-UI
|
||||
The Web-UI is a **zero-threshold** training and deployment interface solution based on Gradio interface technology. For more details, you can check [here](https://swift.readthedocs.io/en/latest/GetStarted/Web-UI.html).
|
||||
|
||||
```shell
|
||||
SWIFT_UI_LANG=en swift web-ui
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Using Python
|
||||
|
||||
ms-swift also supports training and inference using Python. Below is pseudocode for training and inference. For more details, you can refer to [here](https://github.com/modelscope/ms-swift/blob/main/examples/notebook/qwen2_5-self-cognition/self-cognition-sft.ipynb).
|
||||
|
||||
Training:
|
||||
|
||||
```python
|
||||
from peft import LoraConfig, get_peft_model
|
||||
from swift import get_model_processor, get_template, load_dataset, EncodePreprocessor
|
||||
from swift.trainers import Seq2SeqTrainer, Seq2SeqTrainingArguments
|
||||
# Retrieve the model and template, and add a trainable LoRA module
|
||||
model, tokenizer = get_model_processor(model_id_or_path, ...)
|
||||
template = get_template(tokenizer, ...)
|
||||
lora_config = LoraConfig(...)
|
||||
model = get_peft_model(model, lora_config)
|
||||
|
||||
# Download and load the dataset, and encode the text into tokens
|
||||
train_dataset, val_dataset = load_dataset(dataset_id_or_path, ...)
|
||||
train_dataset = EncodePreprocessor(template=template)(train_dataset, num_proc=num_proc)
|
||||
val_dataset = EncodePreprocessor(template=template)(val_dataset, num_proc=num_proc)
|
||||
|
||||
# Train the model
|
||||
training_args = Seq2SeqTrainingArguments(...)
|
||||
trainer = Seq2SeqTrainer(
|
||||
model=model,
|
||||
args=training_args,
|
||||
template=template,
|
||||
train_dataset=train_dataset,
|
||||
eval_dataset=val_dataset,
|
||||
)
|
||||
trainer.train()
|
||||
```
|
||||
Inference:
|
||||
|
||||
```python
|
||||
from swift import TransformersEngine, InferRequest, RequestConfig
|
||||
# Perform inference using the native Transformers engine
|
||||
engine = TransformersEngine(model_id_or_path, adapters=[lora_checkpoint])
|
||||
infer_request = InferRequest(messages=[{'role': 'user', 'content': 'who are you?'}])
|
||||
request_config = RequestConfig(max_tokens=max_new_tokens, temperature=temperature)
|
||||
|
||||
resp_list = engine.infer([infer_request], request_config)
|
||||
print(f'response: {resp_list[0].choices[0].message.content}')
|
||||
```
|
||||
|
||||
## ✨ Usage
|
||||
Here is a minimal example of training to deployment using ms-swift. For more details, you can check the [examples](https://github.com/modelscope/ms-swift/tree/main/examples).
|
||||
|
||||
- If you want to use other models or datasets (including multimodal models and datasets), you only need to modify `--model` to specify the corresponding model's ID or path, and modify `--dataset` to specify the corresponding dataset's ID or path.
|
||||
- By default, ModelScope is used for downloading models and datasets. If you want to use HuggingFace, simply specify `--use_hf true`.
|
||||
|
||||
| Useful Links |
|
||||
| ------ |
|
||||
| [🔥Command Line Parameters](https://swift.readthedocs.io/en/latest/Instruction/Command-line-parameters.html) |
|
||||
| [Megatron-SWIFT](https://swift.readthedocs.io/en/latest/Megatron-SWIFT/Quick-start.html) |
|
||||
| [GRPO](https://swift.readthedocs.io/en/latest/Instruction/GRPO/GetStarted/GRPO.html) |
|
||||
| [Supported Models and Datasets](https://swift.readthedocs.io/en/latest/Instruction/Supported-models-and-datasets.html) |
|
||||
| [Custom Models](https://swift.readthedocs.io/en/latest/Customization/Custom-model.html), [🔥Custom Datasets](https://swift.readthedocs.io/en/latest/Customization/Custom-dataset.html) |
|
||||
| [LLM Tutorial](https://github.com/modelscope/modelscope-classroom/tree/main/LLM-tutorial) |
|
||||
|
||||
### Training
|
||||
|
||||
Supported Training Methods:
|
||||
|
||||
| Method | Full-Parameter | LoRA | QLoRA | Deepspeed | Multi-Machine | Multimodal |
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| [Pre-training](https://github.com/modelscope/ms-swift/blob/main/examples/train/pretrain) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [Supervised Fine-Tuning](https://github.com/modelscope/ms-swift/blob/main/examples/train/lora_sft.sh) | [✅](https://github.com/modelscope/ms-swift/blob/main/examples/train/full/train.sh) | ✅ | [✅](https://github.com/modelscope/ms-swift/tree/main/examples/train/qlora) | [✅](https://github.com/modelscope/ms-swift/tree/main/examples/train/multi-gpu/deepspeed) | [✅](https://github.com/modelscope/ms-swift/tree/main/examples/train/multi-node) | [✅](https://github.com/modelscope/ms-swift/tree/main/examples/train/multimodal) |
|
||||
| [GRPO](https://github.com/modelscope/ms-swift/blob/main/examples/train/grpo) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [GKD](https://github.com/modelscope/ms-swift/blob/main/examples/train/rlhf/gkd) | ✅ | ✅ | ✅ | ✅ | ✅ | [✅](https://github.com/modelscope/ms-swift/blob/main/examples/train/multimodal/rlhf/gkd) |
|
||||
| [PPO](https://github.com/modelscope/ms-swift/blob/main/examples/train/rlhf/ppo) | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| [DPO](https://github.com/modelscope/ms-swift/blob/main/examples/train/rlhf/dpo) | ✅ | ✅ | ✅ | ✅ | ✅ | [✅](https://github.com/modelscope/ms-swift/blob/main/examples/train/multimodal/rlhf/dpo) |
|
||||
| [KTO](https://github.com/modelscope/ms-swift/blob/main/examples/train/rlhf/kto.sh) | ✅ | ✅ | ✅ | ✅ | ✅ | [✅](https://github.com/modelscope/ms-swift/blob/main/examples/train/multimodal/rlhf/kto.sh) |
|
||||
| [Reward Model](https://github.com/modelscope/ms-swift/blob/main/examples/train/rlhf/rm.sh) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [CPO](https://github.com/modelscope/ms-swift/blob/main/examples/train/rlhf/cpo.sh) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [SimPO](https://github.com/modelscope/ms-swift/blob/main/examples/train/rlhf/simpo.sh) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [ORPO](https://github.com/modelscope/ms-swift/blob/main/examples/train/rlhf/orpo.sh) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [Embedding](https://github.com/modelscope/ms-swift/blob/main/examples/train/embedding) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [Reranker](https://github.com/modelscope/ms-swift/tree/main/examples/train/reranker) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [Sequence Classification](https://github.com/modelscope/ms-swift/blob/main/examples/train/seq_cls) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
|
||||
|
||||
Pre-training:
|
||||
```shell
|
||||
# 8*A100
|
||||
NPROC_PER_NODE=8 \
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \
|
||||
swift pt \
|
||||
--model Qwen/Qwen3-4B-Base \
|
||||
--dataset swift/chinese-c4 \
|
||||
--streaming true \
|
||||
--tuner_type full \
|
||||
--deepspeed zero2 \
|
||||
--output_dir output \
|
||||
--max_steps 10000 \
|
||||
...
|
||||
```
|
||||
|
||||
Fine-tuning:
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 swift sft \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--dataset AI-ModelScope/alpaca-gpt4-data-en \
|
||||
--tuner_type lora \
|
||||
--output_dir output \
|
||||
...
|
||||
```
|
||||
|
||||
RLHF:
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 swift rlhf \
|
||||
--rlhf_type dpo \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--dataset hjh0119/shareAI-Llama3-DPO-zh-en-emoji \
|
||||
--tuner_type lora \
|
||||
--output_dir output \
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
### Megatron-SWIFT
|
||||
|
||||
ms-swift supports using Megatron parallelism techniques to accelerate training, including large-scale cluster training and MoE model training. The following training methods are supported:
|
||||
|
||||
| Method | Full-Parameter | LoRA | MoE | Multimodal | FP8 |
|
||||
| ---------------------- | -------------- | ---- | ---- | ---------- | ---- |
|
||||
| Pre-training | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [Supervised Fine-Tuning](https://github.com/modelscope/ms-swift/tree/main/examples/megatron) | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [GRPO](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/grpo) | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [GKD](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/rlhf/gkd) | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [DPO](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/rlhf/dpo) | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [KTO](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/rlhf/kto) | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [RM](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/rlhf/rm) | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [Embedding](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/embedding) | ✅ | ✅| ✅ | ✅ | ✅ |
|
||||
| [Reranker](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/reranker) | ✅ | ✅| ✅ | ✅ | ✅ |
|
||||
| [Sequence Classification](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/seq_cls) | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
|
||||
|
||||
```shell
|
||||
NPROC_PER_NODE=2 CUDA_VISIBLE_DEVICES=0,1 megatron sft \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--save_safetensors true \
|
||||
--dataset AI-ModelScope/alpaca-gpt4-data-zh \
|
||||
--tuner_type lora \
|
||||
--output_dir output \
|
||||
...
|
||||
```
|
||||
|
||||
### Reinforcement Learning
|
||||
|
||||
ms-swift supports a rich set of GRPO family algorithms:
|
||||
|
||||
| Method | Full-Parameter | LoRA | Multimodal | Multi-Machine |
|
||||
| ------------------------------------------------------------ | -------------- | ---- | ---------- | ------------- |
|
||||
| [GRPO](https://swift.readthedocs.io/en/latest/Instruction/GRPO/GetStarted/GRPO.html) | ✅ | ✅ | ✅ | ✅ |
|
||||
| [DAPO](https://swift.readthedocs.io/en/latest/Instruction/GRPO/AdvancedResearch/DAPO.html) | ✅ | ✅ | ✅ | ✅ |
|
||||
| [GSPO](https://swift.readthedocs.io/en/latest/Instruction/GRPO/AdvancedResearch/GSPO.html) | ✅ | ✅ | ✅ | ✅ |
|
||||
| [SAPO](https://swift.readthedocs.io/en/latest/Instruction/GRPO/AdvancedResearch/SAPO.html) | ✅ | ✅ | ✅ | ✅ |
|
||||
| [CISPO](https://swift.readthedocs.io/en/latest/Instruction/GRPO/AdvancedResearch/CISPO.html) | ✅ | ✅ | ✅ | ✅ |
|
||||
| [CHORD](https://swift.readthedocs.io/en/latest/Instruction/GRPO/AdvancedResearch/CHORD.html) | ✅ | ✅ | ✅ | ✅ |
|
||||
| [RLOO](https://swift.readthedocs.io/en/latest/Instruction/GRPO/AdvancedResearch/RLOO.html) | ✅ | ✅ | ✅ | ✅ |
|
||||
| [Reinforce++](https://swift.readthedocs.io/en/latest/Instruction/GRPO/AdvancedResearch/REINFORCEPP.html) | ✅ | ✅ | ✅ | ✅ |
|
||||
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3 NPROC_PER_NODE=4 \
|
||||
swift rlhf \
|
||||
--rlhf_type grpo \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--tuner_type lora \
|
||||
--use_vllm true \
|
||||
--vllm_mode colocate \
|
||||
--dataset AI-MO/NuminaMath-TIR#10000 \
|
||||
--output_dir output \
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
### Inference
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 swift infer \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--stream true \
|
||||
--infer_backend transformers \
|
||||
--max_new_tokens 2048
|
||||
```
|
||||
|
||||
### Interface Inference
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 swift app \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--stream true \
|
||||
--infer_backend transformers \
|
||||
--max_new_tokens 2048
|
||||
```
|
||||
|
||||
### Deployment
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 swift deploy \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--infer_backend vllm
|
||||
```
|
||||
|
||||
### Sampling
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 swift sample \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--sampler_engine transformers \
|
||||
--num_return_sequences 5 \
|
||||
--dataset AI-ModelScope/alpaca-gpt4-data-zh#5
|
||||
```
|
||||
|
||||
### Evaluation
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 swift eval \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--infer_backend sglang \
|
||||
--eval_backend OpenCompass \
|
||||
--eval_dataset ARC_c
|
||||
```
|
||||
|
||||
### Quantization
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 swift export \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--quant_method fp8 \
|
||||
--dataset AI-ModelScope/alpaca-gpt4-data-zh \
|
||||
--output_dir Qwen3-4B-Instruct-2507-FP8
|
||||
```
|
||||
|
||||
### Push Model
|
||||
```shell
|
||||
swift export \
|
||||
--model <model-path> \
|
||||
--push_to_hub true \
|
||||
--hub_model_id '<model-id>' \
|
||||
--hub_token '<sdk-token>'
|
||||
```
|
||||
|
||||
## 🏛 License
|
||||
|
||||
This framework is licensed under the [Apache License (Version 2.0)](https://github.com/modelscope/ms-swift/blob/master/LICENSE). For models and datasets, please refer to the original resource page and follow the corresponding License.
|
||||
|
||||
## 📎 Citation
|
||||
|
||||
```bibtex
|
||||
@misc{zhao2024swiftascalablelightweightinfrastructure,
|
||||
title={SWIFT:A Scalable lightWeight Infrastructure for Fine-Tuning},
|
||||
author={Yuze Zhao and Jintao Huang and Jinghan Hu and Xingjun Wang and Yunlin Mao and Daoze Zhang and Zeyinzi Jiang and Zhikai Wu and Baole Ai and Ang Wang and Wenmeng Zhou and Yingda Chen},
|
||||
year={2024},
|
||||
eprint={2408.05517},
|
||||
archivePrefix={arXiv},
|
||||
primaryClass={cs.CL},
|
||||
url={https://arxiv.org/abs/2408.05517},
|
||||
}
|
||||
```
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://star-history.com/#modelscope/ms-swift&Date)
|
||||
@@ -0,0 +1,7 @@
|
||||
# WeHub 来源说明
|
||||
|
||||
- 原始项目:`modelscope/ms-swift`
|
||||
- 原始仓库:https://github.com/modelscope/ms-swift
|
||||
- 导入方式:上游默认分支的最新快照
|
||||
- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准
|
||||
- 本文件仅用于记录来源,不代表 WeHub 是原项目作者
|
||||
@@ -0,0 +1,497 @@
|
||||
# SWIFT (Scalable lightWeight Infrastructure for Fine-Tuning)
|
||||
|
||||
<p align="center">
|
||||
<br>
|
||||
<img src="asset/banner.png"/>
|
||||
<br>
|
||||
<p>
|
||||
<p align="center">
|
||||
<a href="https://modelscope.cn/home">魔搭社区官网</a>
|
||||
<br>
|
||||
中文  |  <a href="README.md">English</a> 
|
||||
</p>
|
||||
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/python-3.12-5be.svg">
|
||||
<img src="https://img.shields.io/badge/pytorch-%E2%89%A52.0-orange.svg">
|
||||
<a href="https://github.com/modelscope/modelscope/"><img src="https://img.shields.io/badge/modelscope-%E2%89%A51.23-5D91D4.svg"></a>
|
||||
<a href="https://pypi.org/project/ms-swift/"><img src="https://badge.fury.io/py/ms-swift.svg"></a>
|
||||
<a href="https://github.com/modelscope/ms-swift/blob/main/LICENSE"><img src="https://img.shields.io/github/license/modelscope/ms-swift"></a>
|
||||
<a href="https://pepy.tech/project/ms-swift"><img src="https://pepy.tech/badge/ms-swift"></a>
|
||||
<a href="https://github.com/modelscope/ms-swift/pulls"><img src="https://img.shields.io/badge/PR-welcome-55EB99.svg"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://trendshift.io/repositories/11937" target="_blank"><img src="https://trendshift.io/api/badge/repositories/11937" alt="modelscope/ms-swift | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://arxiv.org/abs/2408.05517">论文</a>   | <a href="https://swift.readthedocs.io/en/latest/">English Documentation</a>   |   <a href="https://swift.readthedocs.io/zh-cn/latest/">中文文档</a>  
|
||||
</p>
|
||||
|
||||
## 📖 目录
|
||||
- [用户群](#-用户群)
|
||||
- [简介](#-简介)
|
||||
- [新闻](#-新闻)
|
||||
- [安装](#%EF%B8%8F-安装)
|
||||
- [快速开始](#-快速开始)
|
||||
- [如何使用](#-如何使用)
|
||||
- [License](#-license)
|
||||
- [引用](#-引用)
|
||||
|
||||
## ☎ 用户群
|
||||
|
||||
请扫描下面的二维码来加入我们的交流群:
|
||||
|
||||
[Discord Group](https://discord.gg/yeN59wxjwe) | 微信群
|
||||
:-------------------------:|:-------------------------:
|
||||
<img src="asset/discord_qr.jpg" width="200" height="200"> | <img src="asset/wechat.png" width="200" height="200">
|
||||
|
||||
## 📝 简介
|
||||
🍲 **ms-swift**是魔搭社区提供的大模型与多模态大模型微调部署框架,现已支持600+纯文本大模型与400+多模态大模型的训练(预训练、微调、人类对齐)、推理、评测、量化与部署。其中大模型包括:Qwen3、Qwen3.5、InternLM3、GLM4.5、Mistral、DeepSeek-R1、Llama4等模型,多模态大模型包括:Qwen3-VL、Qwen3-Omni、Llava、InternVL3.5、MiniCPM-V-4、Ovis2.5、GLM4.5-V、DeepSeek-VL2等模型。
|
||||
|
||||
🍔 除此之外,ms-swift汇集了最新的训练技术,包括集成Megatron并行技术,包括TP、PP、CP、EP等为训练提供加速,以及众多GRPO算法族强化学习的算法,包括:GRPO、DAPO、GSPO、SAPO、CISPO、RLOO、Reinforce++等提升模型智能。ms-swift支持广泛的训练任务,包括DPO、KTO、RM、CPO、SimPO、ORPO等偏好学习算法,以及Embedding、Reranker、序列分类任务。ms-swift提供了大模型训练全链路的支持,包括使用vLLM、SGLang和LMDeploy对推理、评测、部署模块提供加速,以及使用GPTQ、AWQ、BNB、FP8技术对大模型进行量化。
|
||||
|
||||
**为什么选择ms-swift?**
|
||||
- 🍎 **模型类型**:支持**600+纯文本大模型**、**400+多模态大模型**以及All-to-All全模态模型训练到部署全流程,热门模型Day0支持。
|
||||
- **数据集类型**:内置150+预训练、微调、人类对齐、多模态等各种任务数据集,并支持自定义数据集,用户只需准备数据集即可一键训练。
|
||||
- **硬件支持**:支持A10/A100/H100、RTX系列、T4/V100、CPU、MPS以及国产硬件Ascend NPU等。
|
||||
- **轻量训练**:支持了LoRA、QLoRA、DoRA、LoRA+、LLaMAPro、LongLoRA、LoRA-GA、ReFT、RS-LoRA、Adapter、LISA等轻量微调方式。
|
||||
- **量化训练**:支持对BNB、AWQ、GPTQ、AQLM、HQQ、EETQ量化模型进行训练,7B模型训练只需9GB训练资源。
|
||||
- **显存优化**: GaLore、Q-Galore、UnSloth、Liger-Kernel、Flash-Attention 2/3 以及 **Ulysses和Ring-Attention序列并行技术**支持,降低长文本训练显存占用。
|
||||
- **分布式训练**:支持分布式数据并行(DDP)、device_map简易模型并行、DeepSpeed ZeRO2 ZeRO3、FSDP/FSDP2以及Megatron等分布式训练技术。
|
||||
- 🍓 **多模态训练**:支持多模态packing技术提升训练速度100%+,支持文本、图像、视频和语音混合模态数据训练,支持vit/aligner/llm单独控制。
|
||||
- **Agent训练**:支持Agent template,准备一套数据集可用于不同模型的训练。
|
||||
- 🍊 **训练任务**:支持预训练和指令微调,以及DPO、GKD、KTO、RM、CPO、SimPO、ORPO等训练任务,支持**Embedding/Reranker**和序列分类任务。
|
||||
- 🥥 **Megatron并行技术**:提供TP/PP/SP/CP/ETP/EP/VPP并行策略,显著提升**MoE模型训练速度**。支持300+纯文本大模型和100+多模态大模型的全参数和LoRA训练方法。支持CPT/SFT/GRPO/DPO/KTO/RM训练任务。
|
||||
- 🍉 **强化学习**:内置**丰富GRPO族算法**,包括GRPO、DAPO、GSPO、SAPO、CISPO、CHORD、RLOO、Reinforce++等,支持同步和异步vLLM引擎推理加速,可使用插件拓展奖励函数、多轮推理调度器以及环境等。
|
||||
- **全链路能力**:覆盖训练、推理、评测、量化和部署全流程。
|
||||
- **界面训练**:提供使用Web-UI界面的方式进行训练、推理、评测、量化,完成大模型的全链路。
|
||||
- **推理加速**:支持Transformers、vLLM、SGLang和LmDeploy推理加速引擎,并提供OpenAI接口,为推理、部署和评测模块提供加速。
|
||||
- **模型评测**:以EvalScope作为评测后端,支持100+评测数据集对纯文本和多模态模型进行评测。
|
||||
- **模型量化**:支持AWQ、GPTQ、FP8和BNB的量化导出,导出的模型支持使用vLLM/SGLang/LmDeploy推理加速。
|
||||
|
||||
## 🎉 新闻
|
||||
- 🎁 2026.06.10: Megatron-Ray支持GRPO和GKD训练,查看[文档](docs/source/Instruction/Ray.md)和[示例](examples/ray)。
|
||||
- 🎁 2026.03.03: **ms-swift v4.0**大版本正式发布,release note参考[这里](https://github.com/modelscope/ms-swift/releases/tag/v4.0.0),您的建议可以在[这个issue](https://github.com/modelscope/ms-swift/issues/7250)中反馈给我们,感谢您的支持。
|
||||
- 🎁 2025.11.14: Megatron GRPO现已支持!查看[文档](./docs/source/Megatron-SWIFT/GRPO.md)和[示例](examples/megatron/grpo)。
|
||||
- 🎁 2025.11.04: 支持[Mcore-Bridge](docs/source/Megatron-SWIFT/Mcore-Bridge.md),使Megatron训练像transformers一样简单易用。
|
||||
- 🎁 2025.10.28: Ray [已支持](docs/source/Instruction/Ray.md)。
|
||||
- 🎁 2025.09.07: 支持CHORD训练算法,请查看[文档](docs/source/Instruction/GRPO/AdvancedResearch/CHORD.md)。
|
||||
- 🎁 2025.09.06: Ulysses现已支持与ring-attention结合使用,使得输入序列可以被切分成任意数量的块(不再受限于num_heads),命令参数仍然是`--sequence_parallel_size N`。
|
||||
- 🎁 2025.09.02: Megatron-SWIFT支持多模态模型训练。文档参考[这里](./docs/source/Megatron-SWIFT/Multimodal-Model.md)。
|
||||
- 🎁 2025.08.12: 支持在SFT训练中使用[Dynamic Fine-Tuning](https://arxiv.org/abs/2508.05629)(DFT),使用参数 `--enable_dft_loss true`。训练脚本参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/train/full/dft.sh)
|
||||
- 🎁 2025.07.09: Megatron-SWIFT支持LoRA训练。相比ms-swift,在MoE模型提速显著。训练脚本参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/megatron/lora)。
|
||||
- 🎁 2025.06.23: 支持Reranker模型训练,训练脚本参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/train/reranker/train_reranker.sh)。
|
||||
- 🎁 2025.06.15: 支持对纯文本大模型和多模态模型进行GKD训练。训练脚本参考这里:[纯文本](https://github.com/modelscope/ms-swift/blob/main/examples/train/rlhf/gkd), [多模态](https://github.com/modelscope/ms-swift/blob/main/examples/train/multimodal/rlhf/gkd)。
|
||||
|
||||
<details><summary>更多</summary>
|
||||
|
||||
- 🎁 2025.06.11: 支持使用Megatron并行技术进行RLHF训练,训练脚本参考[这里](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/rlhf)。
|
||||
- 🎁 2025.05.29: 支持pt、sft、dpo、grpo的序列并行,具体请查看[脚本](https://github.com/modelscope/ms-swift/tree/main/examples/train/sequence_parallel)。
|
||||
- 🎁 2025.05.11: GRPO中的奖励模型支持自定义处理逻辑,GenRM的例子参考[这里](./docs/source/Instruction/GRPO/DeveloperGuide/reward_model.md)。
|
||||
- 🎁 2025.04.15: ms-swift论文已经被AAAI 2025接收,论文地址在[这里](https://ojs.aaai.org/index.php/AAAI/article/view/35383)。
|
||||
- 🎁 2025.03.23: 支持了多轮GRPO,用于构建多轮对话场景的训练(例如agent tool calling),请查看[文档](docs/source/Instruction/GRPO/DeveloperGuide/multi_turn.md)。
|
||||
- 🎁 2025.03.16: 支持了Megatron的并行技术进行训练,请查看[Megatron-SWIFT训练文档](https://swift.readthedocs.io/zh-cn/latest/Megatron-SWIFT/Quick-start.html)。
|
||||
- 🎁 2025.03.15: 支持纯文本和多模态模型的embedding模型的微调,请查看[训练脚本](examples/train/embedding)。
|
||||
- 🎁 2025.03.05: 支持GRPO的hybrid模式,4GPU(4*80G)训练72B模型的脚本参考[这里](examples/train/grpo/internal/vllm_72b_4gpu.sh)。同时支持vllm的tensor并行,训练脚本参考[这里](examples/train/grpo/internal)。
|
||||
- 🎁 2025.02.21: GRPO算法支持使用LMDeploy,训练脚本参考[这里](examples/train/grpo/internal/full_lmdeploy.sh)。此外测试了GRPO算法的性能,使用一些tricks使训练速度提高到300%。WanDB表格请查看[这里](https://wandb.ai/tastelikefeet/grpo_perf_test?nw=nwuseryuzezyz)。
|
||||
- 🎁 2025.02.21: 支持`swift sample`命令。强化微调脚本参考[这里](docs/source/Instruction/Reinforced-Fine-tuning.md),大模型API蒸馏采样脚本参考[这里](examples/sampler/distill/distill.sh)。
|
||||
- 🔥 2025.02.12: 支持GRPO (Group Relative Policy Optimization) 训练算法,文档参考[这里](docs/source/Instruction/GRPO/GetStarted/GRPO.md)。
|
||||
- 🎁 2024.12.04: **ms-swift3.0**大版本更新。请查看[发布说明和更改](docs/source/Instruction/ReleaseNote3.0.md)。
|
||||
- 🎉 2024.08.12: ms-swift论文已经发布到arXiv上,可以点击[这里](https://arxiv.org/abs/2408.05517)阅读。
|
||||
- 🔥 2024.08.05: 支持使用[evalscope](https://github.com/modelscope/evalscope/)作为后端进行大模型和多模态模型的评测。
|
||||
- 🔥 2024.07.29: 支持使用[vllm](https://github.com/vllm-project/vllm), [lmdeploy](https://github.com/InternLM/lmdeploy)对大模型和多模态大模型进行推理加速,在infer/deploy/eval时额外指定`--infer_backend vllm/lmdeploy`即可。
|
||||
- 🔥 2024.07.24: 支持对多模态大模型进行人类偏好对齐训练,包括DPO/ORPO/SimPO/CPO/KTO/RM/PPO。
|
||||
- 🔥 2024.02.01: 支持Agent训练!训练算法源自这篇[论文](https://arxiv.org/pdf/2309.00986.pdf)。
|
||||
</details>
|
||||
|
||||
## 🛠️ 安装
|
||||
使用pip进行安装:
|
||||
```shell
|
||||
pip install ms-swift -U
|
||||
|
||||
# 使用uv
|
||||
pip install uv
|
||||
uv pip install ms-swift -U --torch-backend=auto
|
||||
```
|
||||
|
||||
从源代码安装:
|
||||
```shell
|
||||
# pip install git+https://github.com/modelscope/ms-swift.git
|
||||
|
||||
git clone https://github.com/modelscope/ms-swift.git
|
||||
cd ms-swift
|
||||
# main分支为swift4.x。若安装swift3.x,请运行以下命令
|
||||
# git checkout release/3.12
|
||||
pip install -e .
|
||||
|
||||
# 使用uv
|
||||
uv pip install -e . --torch-backend=auto
|
||||
```
|
||||
|
||||
运行环境:
|
||||
|
||||
| | 范围 | 推荐 | 备注 |
|
||||
|--------------|--------------|---------------------|--------------------|
|
||||
| python | >=3.10 | 3.12 | |
|
||||
| cuda | | cuda12.8/13.0 | 使用cpu、npu、mps则无需安装 |
|
||||
| torch | >=2.0 | 2.8.0/2.11.0 | |
|
||||
| transformers | >=4.33 | 4.57.6/5.12.1 | |
|
||||
| modelscope | >=1.23 | | |
|
||||
| datasets | >=3.0,<4.8.5 | 3.6.0/4.8.4 | |
|
||||
| peft | >=0.11,<0.20 | | |
|
||||
| flash_attn | | 2.8.3/4.0.0b15 | |
|
||||
| trl | >=0.15,<1.0 | 0.29.1 | RLHF |
|
||||
| deepspeed | >=0.14 | 0.18.9 | 训练 |
|
||||
| vllm | >=0.5.1 | 0.11.0/0.23.0 | 推理/部署 |
|
||||
| sglang | >=0.4.6 | | 推理/部署 |
|
||||
| evalscope | >=1.0 | | 评测 |
|
||||
| gradio | | 5.32.1 | Web-UI/App |
|
||||
|
||||
更多可选依赖可以参考[这里](https://github.com/modelscope/ms-swift/blob/main/requirements/install_all.sh)。
|
||||
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
**10分钟**在单卡3090上对Qwen3-4B-Instruct-2507进行自我认知微调:
|
||||
|
||||
### 命令行(推荐)
|
||||
```shell
|
||||
# 13GB
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift sft \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--tuner_type lora \
|
||||
--dataset 'AI-ModelScope/alpaca-gpt4-data-zh#500' \
|
||||
'AI-ModelScope/alpaca-gpt4-data-en#500' \
|
||||
'swift/self-cognition#500' \
|
||||
--torch_dtype bfloat16 \
|
||||
--num_train_epochs 1 \
|
||||
--per_device_train_batch_size 1 \
|
||||
--per_device_eval_batch_size 1 \
|
||||
--learning_rate 1e-4 \
|
||||
--lora_rank 8 \
|
||||
--lora_alpha 32 \
|
||||
--target_modules all-linear \
|
||||
--gradient_accumulation_steps 16 \
|
||||
--eval_steps 50 \
|
||||
--save_steps 50 \
|
||||
--save_total_limit 2 \
|
||||
--logging_steps 5 \
|
||||
--max_length 2048 \
|
||||
--output_dir output \
|
||||
--warmup_ratio 0.05 \
|
||||
--dataloader_num_workers 4 \
|
||||
--model_author swift \
|
||||
--model_name swift-robot
|
||||
```
|
||||
|
||||
小贴士:
|
||||
- 如果要使用自定义数据集进行训练,你可以参考[这里](https://swift.readthedocs.io/zh-cn/latest/Customization/Custom-dataset.html)组织数据集格式,并指定`--dataset <dataset_path>`。
|
||||
- `--model_author`和`--model_name`参数只有当数据集中包含`swift/self-cognition`时才生效。
|
||||
- 如果要使用其他模型进行训练,你只需要修改`--model <model_id/model_path>`即可。
|
||||
- 默认使用**ModelScope**进行模型和数据集的下载。如果要使用HuggingFace,指定`--use_hf true`即可。
|
||||
|
||||
训练完成后,使用以下命令对训练后的权重进行推理:
|
||||
- 这里的`--adapters`需要替换成训练生成的last checkpoint文件夹。由于adapters文件夹中包含了训练的参数文件`args.json`,因此不需要额外指定`--model`,`--system`,swift会自动读取这些参数。如果要关闭此行为,可以设置`--load_args false`。
|
||||
|
||||
```shell
|
||||
# 使用交互式命令行进行推理
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift infer \
|
||||
--adapters output/vx-xxx/checkpoint-xxx \
|
||||
--stream true \
|
||||
--temperature 0 \
|
||||
--max_new_tokens 2048
|
||||
|
||||
# merge-lora并使用vLLM进行推理加速
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift infer \
|
||||
--adapters output/vx-xxx/checkpoint-xxx \
|
||||
--stream true \
|
||||
--merge_lora true \
|
||||
--infer_backend vllm \
|
||||
--vllm_max_model_len 8192 \
|
||||
--temperature 0 \
|
||||
--max_new_tokens 2048
|
||||
```
|
||||
|
||||
最后,使用以下命令将模型推送到ModelScope:
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift export \
|
||||
--adapters output/vx-xxx/checkpoint-xxx \
|
||||
--push_to_hub true \
|
||||
--hub_model_id '<your-model-id>' \
|
||||
--hub_token '<your-sdk-token>' \
|
||||
--use_hf false
|
||||
```
|
||||
|
||||
### Web-UI
|
||||
|
||||
Web-UI是基于gradio界面技术的**零门槛**训练、部署界面方案,具体可以查看[这里](https://swift.readthedocs.io/zh-cn/latest/GetStarted/Web-UI.html)。
|
||||
|
||||
```shell
|
||||
swift web-ui
|
||||
```
|
||||

|
||||
|
||||
### 使用Python
|
||||
ms-swift也支持使用python的方式进行训练和推理。下面给出训练和推理的**伪代码**,具体可以查看[这里](https://github.com/modelscope/ms-swift/blob/main/examples/notebook/qwen2_5-self-cognition/self-cognition-sft.ipynb)。
|
||||
|
||||
训练:
|
||||
```python
|
||||
from peft import LoraConfig, get_peft_model
|
||||
from swift import get_model_processor, get_template, load_dataset, EncodePreprocessor
|
||||
from swift.trainers import Seq2SeqTrainer, Seq2SeqTrainingArguments
|
||||
# 获取模型和template,并加入可训练的LoRA模块
|
||||
model, tokenizer = get_model_processor(model_id_or_path, ...)
|
||||
template = get_template(tokenizer, ...)
|
||||
lora_config = LoraConfig(...)
|
||||
model = get_peft_model(model, lora_config)
|
||||
|
||||
# 下载并载入数据集,并将文本encode成tokens
|
||||
train_dataset, val_dataset = load_dataset(dataset_id_or_path, ...)
|
||||
train_dataset = EncodePreprocessor(template=template)(train_dataset, num_proc=num_proc)
|
||||
val_dataset = EncodePreprocessor(template=template)(val_dataset, num_proc=num_proc)
|
||||
|
||||
# 进行训练
|
||||
training_args = Seq2SeqTrainingArguments(...)
|
||||
trainer = Seq2SeqTrainer(
|
||||
model=model,
|
||||
args=training_args,
|
||||
template=template,
|
||||
train_dataset=train_dataset,
|
||||
eval_dataset=val_dataset,
|
||||
)
|
||||
trainer.train()
|
||||
```
|
||||
|
||||
推理:
|
||||
```python
|
||||
from swift import TransformersEngine, InferRequest, RequestConfig
|
||||
# 使用原生 transformers 引擎进行推理
|
||||
engine = TransformersEngine(model_id_or_path, adapters=[lora_checkpoint])
|
||||
infer_request = InferRequest(messages=[{'role': 'user', 'content': 'who are you?'}])
|
||||
request_config = RequestConfig(max_tokens=max_new_tokens, temperature=temperature)
|
||||
|
||||
resp_list = engine.infer([infer_request], request_config)
|
||||
print(f'response: {resp_list[0].choices[0].message.content}')
|
||||
```
|
||||
|
||||
## ✨ 如何使用
|
||||
|
||||
这里给出使用ms-swift进行训练到部署的最简示例,具体可以查看[examples](https://github.com/modelscope/ms-swift/tree/main/examples)。
|
||||
|
||||
- 若想使用其他模型或者数据集(含多模态模型和数据集),你只需要修改`--model`指定对应模型的id或者path,修改`--dataset`指定对应数据集的id或者path即可。
|
||||
- 默认使用ModelScope进行模型和数据集的下载。如果要使用HuggingFace,指定`--use_hf true`即可。
|
||||
|
||||
| 常用链接 |
|
||||
| ------ |
|
||||
| [🔥命令行参数](https://swift.readthedocs.io/zh-cn/latest/Instruction/Command-line-parameters.html) |
|
||||
| [Megatron-SWIFT](https://swift.readthedocs.io/zh-cn/latest/Megatron-SWIFT/Quick-start.html) |
|
||||
| [GRPO](https://swift.readthedocs.io/zh-cn/latest/Instruction/GRPO/GetStarted/GRPO.html) |
|
||||
| [支持的模型和数据集](https://swift.readthedocs.io/zh-cn/latest/Instruction/Supported-models-and-datasets.html) |
|
||||
| [自定义模型](https://swift.readthedocs.io/zh-cn/latest/Customization/Custom-model.html), [🔥自定义数据集](https://swift.readthedocs.io/zh-cn/latest/Customization/Custom-dataset.html) |
|
||||
| [大模型教程](https://github.com/modelscope/modelscope-classroom/tree/main/LLM-tutorial) |
|
||||
|
||||
### 训练
|
||||
支持的训练方法:
|
||||
|
||||
| 方法 | 全参数 | LoRA | QLoRA | Deepspeed | 多机 | 多模态 |
|
||||
| ------ | ------ |---------------------------------------------------------------------------------------------| ----- | ------ | ------ |----------------------------------------------------------------------------------------------|
|
||||
| [预训练](https://github.com/modelscope/ms-swift/blob/main/examples/train/pretrain) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [指令监督微调](https://github.com/modelscope/ms-swift/blob/main/examples/train/lora_sft.sh) | [✅](https://github.com/modelscope/ms-swift/blob/main/examples/train/full/train.sh) | ✅ | [✅](https://github.com/modelscope/ms-swift/tree/main/examples/train/qlora) | [✅](https://github.com/modelscope/ms-swift/tree/main/examples/train/multi-gpu/deepspeed) | [✅](https://github.com/modelscope/ms-swift/tree/main/examples/train/multi-node) | [✅](https://github.com/modelscope/ms-swift/tree/main/examples/train/multimodal) |
|
||||
| [GRPO](https://github.com/modelscope/ms-swift/blob/main/examples/train/grpo) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [GKD](https://github.com/modelscope/ms-swift/blob/main/examples/train/rlhf/gkd) | ✅ | ✅ | ✅ | ✅ | ✅ | [✅](https://github.com/modelscope/ms-swift/blob/main/examples/train/multimodal/rlhf/gkd) |
|
||||
| [PPO](https://github.com/modelscope/ms-swift/blob/main/examples/train/rlhf/ppo) | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| [DPO](https://github.com/modelscope/ms-swift/blob/main/examples/train/rlhf/dpo) | ✅ | ✅ | ✅ | ✅ | ✅ | [✅](https://github.com/modelscope/ms-swift/blob/main/examples/train/multimodal/rlhf/dpo) |
|
||||
| [KTO](https://github.com/modelscope/ms-swift/blob/main/examples/train/rlhf/kto.sh) | ✅ | ✅ | ✅ | ✅ | ✅ | [✅](https://github.com/modelscope/ms-swift/blob/main/examples/train/multimodal/rlhf/kto.sh) |
|
||||
| [奖励模型](https://github.com/modelscope/ms-swift/blob/main/examples/train/rlhf/rm.sh) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [CPO](https://github.com/modelscope/ms-swift/blob/main/examples/train/rlhf/cpo.sh) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [SimPO](https://github.com/modelscope/ms-swift/blob/main/examples/train/rlhf/simpo.sh) | ✅ | ✅ | ✅ | ✅| ✅ | ✅ |
|
||||
| [ORPO](https://github.com/modelscope/ms-swift/blob/main/examples/train/rlhf/orpo.sh) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [Embedding](https://github.com/modelscope/ms-swift/blob/main/examples/train/embedding) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [Reranker](https://github.com/modelscope/ms-swift/tree/main/examples/train/reranker) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [序列分类](https://github.com/modelscope/ms-swift/blob/main/examples/train/seq_cls) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
|
||||
|
||||
预训练:
|
||||
```shell
|
||||
# 8*A100
|
||||
NPROC_PER_NODE=8 \
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \
|
||||
swift pt \
|
||||
--model Qwen/Qwen3-4B-Base \
|
||||
--dataset swift/chinese-c4 \
|
||||
--streaming true \
|
||||
--tuner_type full \
|
||||
--deepspeed zero2 \
|
||||
--output_dir output \
|
||||
--max_steps 10000 \
|
||||
...
|
||||
```
|
||||
|
||||
微调:
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 swift sft \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--dataset AI-ModelScope/alpaca-gpt4-data-zh \
|
||||
--tuner_type lora \
|
||||
--output_dir output \
|
||||
...
|
||||
```
|
||||
|
||||
RLHF:
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 swift rlhf \
|
||||
--rlhf_type dpo \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--dataset hjh0119/shareAI-Llama3-DPO-zh-en-emoji \
|
||||
--tuner_type lora \
|
||||
--output_dir output \
|
||||
...
|
||||
```
|
||||
|
||||
### Megatron-SWIFT
|
||||
|
||||
ms-swift支持使用Megatron并行技术加速训练,包括大规模集群训练和MoE模型训练。以下为支持的训练方法:
|
||||
|
||||
| 方法 | 全参数 | LoRA | MoE | 多模态 | FP8 |
|
||||
| ------ | ------ | ---- | ----- | ----- | ----- |
|
||||
| 预训练 | ✅ | ✅| ✅ | ✅ | ✅ |
|
||||
| [指令监督微调](https://github.com/modelscope/ms-swift/tree/main/examples/megatron) | ✅ | ✅| ✅ | ✅ | ✅ |
|
||||
| [GRPO](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/grpo) | ✅ | ✅| ✅ | ✅ | ✅ |
|
||||
| [GKD](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/rlhf/gkd) | ✅ | ✅| ✅ | ✅ | ✅ |
|
||||
| [DPO](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/rlhf/dpo) | ✅ | ✅| ✅ | ✅ | ✅ |
|
||||
| [KTO](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/rlhf/kto) | ✅ | ✅| ✅ | ✅ | ✅ |
|
||||
| [RM](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/rlhf/rm) | ✅ | ✅| ✅ | ✅ | ✅ |
|
||||
| [Embedding](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/embedding) | ✅ | ✅| ✅ | ✅ | ✅ |
|
||||
| [Reranker](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/reranker) | ✅ | ✅| ✅ | ✅ | ✅ |
|
||||
| [序列分类](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/seq_cls) | ✅ | ✅| ✅ | ✅ | ✅ |
|
||||
|
||||
|
||||
```shell
|
||||
NPROC_PER_NODE=2 CUDA_VISIBLE_DEVICES=0,1 megatron sft \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--save_safetensors true \
|
||||
--dataset AI-ModelScope/alpaca-gpt4-data-zh \
|
||||
--tuner_type lora \
|
||||
--output_dir output \
|
||||
...
|
||||
```
|
||||
|
||||
### 强化学习
|
||||
|
||||
ms-swift支持丰富GRPO族算法:
|
||||
|
||||
| 方法 | 全参数 | LoRA | 多模态 | 多机 |
|
||||
| ------ | ------ | ---- | ----- | ----- |
|
||||
| [GRPO](https://swift.readthedocs.io/zh-cn/latest/Instruction/GRPO/GetStarted/GRPO.html) | ✅ | ✅| ✅ | ✅ |
|
||||
| [DAPO](https://swift.readthedocs.io/zh-cn/latest/Instruction/GRPO/AdvancedResearch/DAPO.html) | ✅ | ✅| ✅ | ✅ |
|
||||
| [GSPO](https://swift.readthedocs.io/zh-cn/latest/Instruction/GRPO/AdvancedResearch/GSPO.html) | ✅ | ✅| ✅ | ✅ |
|
||||
| [SAPO](https://swift.readthedocs.io/zh-cn/latest/Instruction/GRPO/AdvancedResearch/SAPO.html) | ✅ | ✅| ✅ | ✅ |
|
||||
| [CISPO](https://swift.readthedocs.io/zh-cn/latest/Instruction/GRPO/AdvancedResearch/CISPO.html) | ✅ | ✅| ✅ | ✅ |
|
||||
| [CHORD](https://swift.readthedocs.io/zh-cn/latest/Instruction/GRPO/AdvancedResearch/CHORD.html) | ✅ | ✅| ✅ | ✅ |
|
||||
| [RLOO](https://swift.readthedocs.io/zh-cn/latest/Instruction/GRPO/AdvancedResearch/RLOO.html) | ✅ | ✅| ✅ | ✅ |
|
||||
| [Reinforce++](https://swift.readthedocs.io/zh-cn/latest/Instruction/GRPO/AdvancedResearch/REINFORCEPP.html) | ✅ | ✅| ✅ | ✅ |
|
||||
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3 NPROC_PER_NODE=4 \
|
||||
swift rlhf \
|
||||
--rlhf_type grpo \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--tuner_type lora \
|
||||
--use_vllm true \
|
||||
--vllm_mode colocate \
|
||||
--dataset AI-MO/NuminaMath-TIR#10000 \
|
||||
--output_dir output \
|
||||
...
|
||||
```
|
||||
|
||||
### 推理
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 swift infer \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--stream true \
|
||||
--infer_backend transformers \
|
||||
--max_new_tokens 2048
|
||||
```
|
||||
|
||||
### 界面推理
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 swift app \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--stream true \
|
||||
--infer_backend transformers \
|
||||
--max_new_tokens 2048 \
|
||||
--lang zh
|
||||
```
|
||||
|
||||
### 部署
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 swift deploy \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--infer_backend vllm
|
||||
```
|
||||
|
||||
### 采样
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 swift sample \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--sampler_engine transformers \
|
||||
--num_return_sequences 5 \
|
||||
--dataset AI-ModelScope/alpaca-gpt4-data-zh#5
|
||||
```
|
||||
|
||||
### 评测
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 swift eval \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--infer_backend sglang \
|
||||
--eval_backend OpenCompass \
|
||||
--eval_dataset ARC_c
|
||||
```
|
||||
|
||||
### 量化
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 swift export \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--quant_method fp8 \
|
||||
--dataset AI-ModelScope/alpaca-gpt4-data-zh \
|
||||
--output_dir Qwen3-4B-Instruct-2507-FP8
|
||||
```
|
||||
|
||||
### 推送模型
|
||||
```shell
|
||||
swift export \
|
||||
--model <model-path> \
|
||||
--push_to_hub true \
|
||||
--hub_model_id '<model-id>' \
|
||||
--hub_token '<sdk-token>'
|
||||
```
|
||||
|
||||
|
||||
## 🏛 License
|
||||
|
||||
本框架使用[Apache License (Version 2.0)](https://github.com/modelscope/ms-swift/blob/master/LICENSE)进行许可。模型和数据集请查看原资源页面并遵守对应License。
|
||||
|
||||
## 📎 引用
|
||||
|
||||
```bibtex
|
||||
@misc{zhao2024swiftascalablelightweightinfrastructure,
|
||||
title={SWIFT:A Scalable lightWeight Infrastructure for Fine-Tuning},
|
||||
author={Yuze Zhao and Jintao Huang and Jinghan Hu and Xingjun Wang and Yunlin Mao and Daoze Zhang and Zeyinzi Jiang and Zhikai Wu and Baole Ai and Ang Wang and Wenmeng Zhou and Yingda Chen},
|
||||
year={2024},
|
||||
eprint={2408.05517},
|
||||
archivePrefix={arXiv},
|
||||
primaryClass={cs.CL},
|
||||
url={https://arxiv.org/abs/2408.05517},
|
||||
}
|
||||
```
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://star-history.com/#modelscope/ms-swift&Date)
|
||||
|
After Width: | Height: | Size: 372 KiB |
|
After Width: | Height: | Size: 263 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,20 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
@@ -0,0 +1,37 @@
|
||||
## maintain docs
|
||||
1. build docs
|
||||
```shell
|
||||
# in root directory:
|
||||
make docs
|
||||
```
|
||||
|
||||
2. doc string format
|
||||
|
||||
We adopt the google style docstring format as the standard, please refer to the following documents.
|
||||
1. Google Python style guide docstring [link](http://google.github.io/styleguide/pyguide.html#381-docstrings)
|
||||
2. Google docstring example [link](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html)
|
||||
3. sample:torch.nn.modules.conv [link](https://pytorch.org/docs/stable/_modules/torch/nn/modules/conv.html#Conv1d)
|
||||
4. load function as an example:
|
||||
|
||||
```python
|
||||
def load(file, file_format=None, **kwargs):
|
||||
"""Load data from json/yaml/pickle files.
|
||||
|
||||
This method provides a unified api for loading data from serialized files.
|
||||
|
||||
Args:
|
||||
file (str or :obj:`Path` or file-like object): Filename or a file-like
|
||||
object.
|
||||
file_format (str, optional): If not specified, the file format will be
|
||||
inferred from the file extension, otherwise use the specified one.
|
||||
Currently supported formats include "json", "yaml/yml".
|
||||
|
||||
Examples:
|
||||
>>> load('/path/of/your/file') # file is stored in disk
|
||||
>>> load('https://path/of/your/file') # file is stored on internet
|
||||
>>> load('oss://path/of/your/file') # file is stored in petrel
|
||||
|
||||
Returns:
|
||||
The content from the file.
|
||||
"""
|
||||
```
|
||||
@@ -0,0 +1,35 @@
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=source
|
||||
set BUILDDIR=build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
||||
|
After Width: | Height: | Size: 934 KiB |
|
After Width: | Height: | Size: 853 KiB |
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 308 KiB |
|
After Width: | Height: | Size: 134 KiB |
|
After Width: | Height: | Size: 551 KiB |
|
After Width: | Height: | Size: 346 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 655 KiB |
|
After Width: | Height: | Size: 287 KiB |
|
After Width: | Height: | Size: 2.1 MiB |
|
After Width: | Height: | Size: 767 KiB |
|
After Width: | Height: | Size: 2.1 MiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 2.2 MiB |
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 198 KiB |
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 664 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 171 KiB |
|
After Width: | Height: | Size: 178 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,29 @@
|
||||
# .readthedocs.yaml
|
||||
# Read the Docs configuration file
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
# Set the OS, Python version and other tools you might need
|
||||
build:
|
||||
os: ubuntu-22.04
|
||||
tools:
|
||||
python: "3.10"
|
||||
|
||||
# Build documentation in the "docs/" directory with Sphinx
|
||||
sphinx:
|
||||
configuration: docs/source/conf.py
|
||||
|
||||
# Optionally build your docs in additional formats such as PDF and ePub
|
||||
# formats:
|
||||
# - pdf
|
||||
# - epub
|
||||
|
||||
# Optional but recommended, declare the Python requirements required
|
||||
# to build your documentation
|
||||
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
|
||||
python:
|
||||
install:
|
||||
- requirements: requirements/docs.txt
|
||||
- requirements: requirements/framework.txt
|
||||
@@ -0,0 +1,321 @@
|
||||
# AMD GPU 支持
|
||||
|
||||
## 1. 环境配置
|
||||
### 1.1 基础环境
|
||||
拉取适配了 AMD ROCm 生态的 ms-swift 镜像,并参照以下命令启动容器。
|
||||
|
||||
如果用户需要运行更新版本的 ms-swift,可以使用 pip 升级或基于源码安装更新(建议安装时添加 `--no-deps` 选项以避免自动升级其他依赖可能引起的问题)。
|
||||
|
||||
```bash
|
||||
IMAGE_NAME=amdagi/modelscope:ubuntu22.04-rocm7.2.0-py312-torch2.10.0-vllm0.18.1-modelscope1.35.1-swift4.1.0
|
||||
docker pull ${IMAGE_NAME}
|
||||
|
||||
CONTAINER_NAME=swift_test
|
||||
docker run -it --network=host --ipc=host --privileged --group-add video \
|
||||
--device=/dev/dri --device=/dev/kfd \
|
||||
--shm-size 512G --ulimit memlock=-1 \
|
||||
--security-opt seccomp=unconfined --cap-add SYS_PTRACE \
|
||||
--name ${CONTAINER_NAME} \
|
||||
${IMAGE_NAME} \
|
||||
/bin/bash
|
||||
```
|
||||
|
||||
### 1.2 环境检查
|
||||
|
||||
- 确认 container 环境中 pytorch 正确识别 AMD GPU。
|
||||
|
||||
```bash
|
||||
python -c "import torch;print(torch.cuda.is_available())" # output: True
|
||||
```
|
||||
|
||||
- 检查 GPU 的拓扑连接及 NUMA:`rocm-smi --showtopo`
|
||||
|
||||
```
|
||||
============================ ROCm System Management Interface ============================
|
||||
WARNING: AMD GPU device(s) is/are in a low-power state. Check power control/runtime_status
|
||||
|
||||
================================ Weight between two GPUs =================================
|
||||
GPU0 GPU1 GPU2 GPU3 GPU4 GPU5 GPU6 GPU7
|
||||
GPU0 0 15 15 15 15 15 15 15
|
||||
GPU1 15 0 15 15 15 15 15 15
|
||||
GPU2 15 15 0 15 15 15 15 15
|
||||
GPU3 15 15 15 0 15 15 15 15
|
||||
GPU4 15 15 15 15 0 15 15 15
|
||||
GPU5 15 15 15 15 15 0 15 15
|
||||
GPU6 15 15 15 15 15 15 0 15
|
||||
GPU7 15 15 15 15 15 15 15 0
|
||||
|
||||
================================= Hops between two GPUs ==================================
|
||||
GPU0 GPU1 GPU2 GPU3 GPU4 GPU5 GPU6 GPU7
|
||||
GPU0 0 1 1 1 1 1 1 1
|
||||
GPU1 1 0 1 1 1 1 1 1
|
||||
GPU2 1 1 0 1 1 1 1 1
|
||||
GPU3 1 1 1 0 1 1 1 1
|
||||
GPU4 1 1 1 1 0 1 1 1
|
||||
GPU5 1 1 1 1 1 0 1 1
|
||||
GPU6 1 1 1 1 1 1 0 1
|
||||
GPU7 1 1 1 1 1 1 1 0
|
||||
|
||||
=============================== Link Type between two GPUs ===============================
|
||||
GPU0 GPU1 GPU2 GPU3 GPU4 GPU5 GPU6 GPU7
|
||||
GPU0 0 XGMI XGMI XGMI XGMI XGMI XGMI XGMI
|
||||
GPU1 XGMI 0 XGMI XGMI XGMI XGMI XGMI XGMI
|
||||
GPU2 XGMI XGMI 0 XGMI XGMI XGMI XGMI XGMI
|
||||
GPU3 XGMI XGMI XGMI 0 XGMI XGMI XGMI XGMI
|
||||
GPU4 XGMI XGMI XGMI XGMI 0 XGMI XGMI XGMI
|
||||
GPU5 XGMI XGMI XGMI XGMI XGMI 0 XGMI XGMI
|
||||
GPU6 XGMI XGMI XGMI XGMI XGMI XGMI 0 XGMI
|
||||
GPU7 XGMI XGMI XGMI XGMI XGMI XGMI XGMI 0
|
||||
|
||||
======================================= Numa Nodes =======================================
|
||||
GPU[0] : (Topology) Numa Node: 0
|
||||
GPU[0] : (Topology) Numa Affinity: 0
|
||||
GPU[1] : (Topology) Numa Node: 0
|
||||
GPU[1] : (Topology) Numa Affinity: 0
|
||||
GPU[2] : (Topology) Numa Node: 0
|
||||
GPU[2] : (Topology) Numa Affinity: 0
|
||||
GPU[3] : (Topology) Numa Node: 0
|
||||
GPU[3] : (Topology) Numa Affinity: 0
|
||||
GPU[4] : (Topology) Numa Node: 1
|
||||
GPU[4] : (Topology) Numa Affinity: 1
|
||||
GPU[5] : (Topology) Numa Node: 1
|
||||
GPU[5] : (Topology) Numa Affinity: 1
|
||||
GPU[6] : (Topology) Numa Node: 1
|
||||
GPU[6] : (Topology) Numa Affinity: 1
|
||||
GPU[7] : (Topology) Numa Node: 1
|
||||
GPU[7] : (Topology) Numa Affinity: 1
|
||||
================================== End of ROCm SMI Log ===================================
|
||||
```
|
||||
|
||||
- 查看 GPU 利用率及显存占用等信息(`rocm-smi` 或者 `rocm-smi -u --showmeminfo vram`)
|
||||
|
||||
```
|
||||
# output of 'rocm-smi'
|
||||
============================================ ROCm System Management Interface ============================================
|
||||
====================================================== Concise Info ======================================================
|
||||
Device Node IDs Temp Power Partitions SCLK MCLK Fan Perf PwrCap VRAM% GPU%
|
||||
(DID, GUID) (Junction) (Socket) (Mem, Compute, ID)
|
||||
==========================================================================================================================
|
||||
0 2 0x74a2, 1017 43.0°C 155.0W NPS1, SPX, 0 94Mhz 900Mhz 0% auto 650.0W 0% 0%
|
||||
1 3 0x74a2, 47713 41.0°C 155.0W NPS1, SPX, 0 91Mhz 900Mhz 0% auto 650.0W 0% 0%
|
||||
2 4 0x74a2, 37449 45.0°C 159.0W NPS1, SPX, 0 95Mhz 900Mhz 0% auto 650.0W 0% 0%
|
||||
3 5 0x74a2, 11217 41.0°C 155.0W NPS1, SPX, 0 95Mhz 900Mhz 0% auto 650.0W 0% 0%
|
||||
4 6 0x74a2, 41880 44.0°C 160.0W NPS1, SPX, 0 91Mhz 900Mhz 0% auto 650.0W 0% 0%
|
||||
5 7 0x74a2, 6656 42.0°C 157.0W NPS1, SPX, 0 95Mhz 900Mhz 0% auto 650.0W 0% 0%
|
||||
6 8 0x74a2, 12840 45.0°C 160.0W NPS1, SPX, 0 96Mhz 900Mhz 0% auto 650.0W 0% 0%
|
||||
7 9 0x74a2, 35760 43.0°C 158.0W NPS1, SPX, 0 107Mhz 900Mhz 0% auto 650.0W 0% 0%
|
||||
==========================================================================================================================
|
||||
================================================== End of ROCm SMI Log ===================================================
|
||||
|
||||
# output of 'rocm-smi -u --showmeminfo vram'
|
||||
============================ ROCm System Management Interface ============================
|
||||
=================================== % time GPU is busy ===================================
|
||||
GPU[0] : GPU use (%): 0
|
||||
GPU[0] : GFX Activity: 3862538534
|
||||
GPU[1] : GPU use (%): 0
|
||||
GPU[1] : GFX Activity: 4053246251
|
||||
GPU[2] : GPU use (%): 0
|
||||
GPU[2] : GFX Activity: 3114103535
|
||||
GPU[3] : GPU use (%): 0
|
||||
GPU[3] : GFX Activity: 4026776444
|
||||
GPU[4] : GPU use (%): 0
|
||||
GPU[4] : GFX Activity: 1224255679
|
||||
GPU[5] : GPU use (%): 0
|
||||
GPU[5] : GFX Activity: 1191191242
|
||||
GPU[6] : GPU use (%): 0
|
||||
GPU[6] : GFX Activity: 1184652679
|
||||
GPU[7] : GPU use (%): 0
|
||||
GPU[7] : GFX Activity: 2145209382
|
||||
==========================================================================================
|
||||
================================== Memory Usage (Bytes) ==================================
|
||||
GPU[0] : VRAM Total Memory (B): 206141652992
|
||||
GPU[0] : VRAM Total Used Memory (B): 297611264
|
||||
GPU[1] : VRAM Total Memory (B): 206141652992
|
||||
GPU[1] : VRAM Total Used Memory (B): 297623552
|
||||
GPU[2] : VRAM Total Memory (B): 206141652992
|
||||
GPU[2] : VRAM Total Used Memory (B): 297623552
|
||||
GPU[3] : VRAM Total Memory (B): 206141652992
|
||||
GPU[3] : VRAM Total Used Memory (B): 297623552
|
||||
GPU[4] : VRAM Total Memory (B): 206141652992
|
||||
GPU[4] : VRAM Total Used Memory (B): 297623552
|
||||
GPU[5] : VRAM Total Memory (B): 206141652992
|
||||
GPU[5] : VRAM Total Used Memory (B): 297623552
|
||||
GPU[6] : VRAM Total Memory (B): 206141652992
|
||||
GPU[6] : VRAM Total Used Memory (B): 297623552
|
||||
GPU[7] : VRAM Total Memory (B): 206141652992
|
||||
GPU[7] : VRAM Total Used Memory (B): 297623552
|
||||
==========================================================================================
|
||||
================================== End of ROCm SMI Log ===================================
|
||||
```
|
||||
|
||||
## 2. 运行示例
|
||||
|
||||
### 2.1 使用 Megatron-Swift 全量微调 Qwen3.5 模型
|
||||
AMD GPU 显存相对较大,因此可以通过同时对以下参数进行联合调优,以提升训练吞吐性能。
|
||||
- 并行度调优(TP/PP/EP等):GPU 单卡显存较大使得用户可以尽可能减小并行度切分带来的通信开销(优先级 PP/EP > TP)
|
||||
- 显存允许的情况下关闭 optimizer cpu offload:设置 `--optimizer_cpu_offload false`
|
||||
- 显存允许的情况下调整 activation/gradient checkpointing:设置 `--recompute_granularity none`,或者 `--recompute_granularity selective` 配合 `--recompute_modules` 进行细粒度的控制
|
||||
- 对于 MoE 模型,建议设置 `export NVTE_USE_GROUPED_GEMM_TRITON=1` 以使用 triton 实现的 grouped gemm kernel
|
||||
- 对于带有 GatedDeltaNet 结构的模型,建议设置 `USE_MCORE_GDN=1` 使用 mcore 的实现版本
|
||||
- 为避免在某些 AMD GPU 上可能出现的问题,保证性能更稳定,建议设置 `export HSA_NO_SCRATCH_RECLAIM=1`
|
||||
|
||||
单机训练:
|
||||
|
||||
```bash
|
||||
export HSA_NO_SCRATCH_RECLAIM=1
|
||||
export NVTE_USE_GROUPED_GEMM_TRITON=1
|
||||
|
||||
output_dir=${PWD}/megatron_output/Qwen3.5-35B-A3B
|
||||
mkdir -p ${output_dir}
|
||||
current_time=$(date "+%Y.%m.%d-%H.%M.%S")
|
||||
log_file=${output_dir}/"1node_full_megatron_Qwen3.5-35B-A3B_${current_time}.log"
|
||||
|
||||
PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True' \
|
||||
NPROC_PER_NODE=8 \
|
||||
MAX_PIXELS=1003520 \
|
||||
VIDEO_MAX_PIXELS=50176 \
|
||||
FPS_MAX_FRAMES=12 \
|
||||
SKIP_MULTIMODAL_MTP_VALIDATION=1 \
|
||||
USE_MCORE_GDN=1 \
|
||||
megatron sft \
|
||||
--model Qwen/Qwen3.5-35B-A3B \
|
||||
--dataset 'AI-ModelScope/LongAlpaca-12k' \
|
||||
--save_safetensors true \
|
||||
--load_from_cache_file true \
|
||||
--tuner_type full \
|
||||
--add_non_thinking_prefix true \
|
||||
--split_dataset_ratio 0.01 \
|
||||
--tensor_model_parallel_size 1 \
|
||||
--pipeline_model_parallel_size 1 \
|
||||
--expert_model_parallel_size 8 \
|
||||
--sequence_parallel true \
|
||||
--moe_permute_fusion true \
|
||||
--moe_grouped_gemm true \
|
||||
--moe_shared_expert_overlap true \
|
||||
--moe_aux_loss_coeff 1e-6 \
|
||||
--moe_expert_capacity_factor 2 \
|
||||
--micro_batch_size 1 \
|
||||
--global_batch_size 8 \
|
||||
--recompute_granularity selective \
|
||||
--recompute_modules core_attn mlp moe \
|
||||
--gradient_accumulation_fusion false \
|
||||
--num_train_epochs 500 \
|
||||
--group_by_length true \
|
||||
--finetune true \
|
||||
--freeze_llm false \
|
||||
--freeze_vit false \
|
||||
--freeze_aligner false \
|
||||
--cross_entropy_loss_fusion true \
|
||||
--lr 1e-5 \
|
||||
--lr_warmup_fraction 0.05 \
|
||||
--min_lr 1e-6 \
|
||||
--weight_decay 0.1 \
|
||||
--adam_beta2 0.95 \
|
||||
--eval_steps 500 \
|
||||
--save_steps 500 \
|
||||
--save_total_limit 10 \
|
||||
--logging_steps 1 \
|
||||
--max_length 16384 \
|
||||
--dataloader_num_workers 8 \
|
||||
--dataset_num_proc 8 \
|
||||
--no_save_optim true \
|
||||
--no_save_rng true \
|
||||
--optimizer_cpu_offload false \
|
||||
--attention_backend flash \
|
||||
--padding_free false \
|
||||
--output_dir ${output_dir} \
|
||||
2>&1 | tee ${log_file}
|
||||
```
|
||||
|
||||
多机训练:
|
||||
|
||||
```bash
|
||||
export NNODES=2 # 此处以 2 节点为例
|
||||
export NODE_RANK=0 # 主节点设置为 0,从节点设置为 1
|
||||
export MASTER_ADDR=<MASTER_NODE_IP> # 根据主节点 ip 设置
|
||||
export MASTER_PORT=29500 # 设置通信端口
|
||||
export NCCL_SOCKET_IFNAME=ens50f1np1 # 根据机器实际通信网口名设置,可通过 ifconfig 查看
|
||||
export GLOO_SOCKET_IFNAME=ens50f1np1 # 根据机器实际通信网口名设置,可通过 ifconfig 查看
|
||||
export NCCL_IB_HCA=mlx5_0,mlx5_1,mlx5_2,mlx5_3 # 根据实际IB网卡名设置,可通过 ibv_devices 查看
|
||||
export NCCL_IB_GID_INDEX=3
|
||||
|
||||
# 训练脚本主体:参照单机训练脚本
|
||||
...
|
||||
```
|
||||
|
||||
### 2.2 使用 Megatron-Swift 对 Qwen3.5 模型做强化学习训练
|
||||
|
||||
```bash
|
||||
# 单机训练样例
|
||||
export HSA_NO_SCRATCH_RECLAIM=1
|
||||
export NVTE_USE_GROUPED_GEMM_TRITON=1
|
||||
|
||||
SYSTEM_PROMPT="""You are a helpful math assistant. Solve the problem step by step and put your final answer within \\boxed{}."""
|
||||
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \
|
||||
NPROC_PER_NODE=8 \
|
||||
PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True' \
|
||||
megatron rlhf \
|
||||
--rlhf_type grpo \
|
||||
--model Qwen/Qwen3.5-35B-A3B \
|
||||
--save_safetensors true \
|
||||
--enable_thinking false \
|
||||
--merge_lora true \
|
||||
--context_parallel_size 1 \
|
||||
--tensor_model_parallel_size 1 \
|
||||
--expert_model_parallel_size 8 \
|
||||
--pipeline_model_parallel_size 1 \
|
||||
--moe_permute_fusion true \
|
||||
--dataset open-r1/DAPO-Math-17k-Processed \
|
||||
--system "$SYSTEM_PROMPT" \
|
||||
--num_train_epochs 1 \
|
||||
--global_batch_size 64 \
|
||||
--micro_batch_size 1 \
|
||||
--steps_per_generation 2 \
|
||||
--num_generations 8 \
|
||||
--reward_funcs accuracy \
|
||||
--use_vllm true \
|
||||
--vllm_mode colocate \
|
||||
--vllm_gpu_memory_utilization 0.5 \
|
||||
--vllm_tensor_parallel_size 2 \
|
||||
--vllm_max_model_len 9192 \
|
||||
--max_length 1000 \
|
||||
--max_completion_length 8192 \
|
||||
--tuner_type lora \
|
||||
--target_modules all-linear \
|
||||
--lr 5e-5 \
|
||||
--bf16 true \
|
||||
--beta 0.00 \
|
||||
--epsilon 0.2 \
|
||||
--epsilon_high 0.28 \
|
||||
--dynamic_sample false \
|
||||
--overlong_filter true \
|
||||
--loss_type grpo \
|
||||
--sleep_level 1 \
|
||||
--offload_model true \
|
||||
--offload_bridge false \
|
||||
--offload_optimizer true \
|
||||
--logging_steps 1 \
|
||||
--recompute_granularity none \
|
||||
--gradient_accumulation_fusion false \
|
||||
--finetune \
|
||||
--dataloader_num_workers 8 \
|
||||
--dataset_num_proc 8 \
|
||||
--no_save_optim \
|
||||
--no_save_rng \
|
||||
--save_steps 20 \
|
||||
--attention_backend flash \
|
||||
--moe_expert_capacity_factor 2 \
|
||||
--temperature 1.0 \
|
||||
--padding_free false \
|
||||
--sequence_parallel true \
|
||||
--log_completions true \
|
||||
--report_to tensorboard
|
||||
```
|
||||
|
||||
## 已知问题
|
||||
- 强化学习训练:
|
||||
- 在强化学习训练中,如果使用 vLLM 作为推理引擎,需要 vLLM>=0.11.0。建议使用 ROCm7.0 或者我们提供的镜像以避免出现 sleep mode memory leak 问题。
|
||||
- 在使用 [Ray Megatron](../../source/Instruction/Ray.md) 而非 `torchrun` 的方式进行多 GPU/Node 训练时,不设置 `CUDA_VISIBLE_DEVICES`/`HIP_VISIBLE_DEVICES`等,以避免冲突问题。
|
||||
- MoE 模型训练:
|
||||
- MoE 模型建议增加环境变量 `NVTE_USE_GROUPED_GEMM_TRITON=1` 和 `--gradient_accumulation_fusion false` 以避免偶发的GPU卡死问题。
|
||||
@@ -0,0 +1,211 @@
|
||||
# Elastic
|
||||
|
||||
|
||||
|
||||
## 安装依赖
|
||||
|
||||
集群部署K8S,并在集群中部署DLrover,[DLRover](https://github.com/intelligent-machine-learning/dlrover),
|
||||
`pip install dlrover && pip install tornado && pip install kubernetes && pip install ms-swift`
|
||||
|
||||
经过反复测试验证的训练镜像中的其它依赖以及版本:
|
||||
deepspeed 0.16.5(需参考https://github.com/deepspeedai/DeepSpeed/pull/7585/files 修复universal checkpoint 相关问题)
|
||||
pytorch 2.6.0
|
||||
|
||||
|
||||
## 如何启动
|
||||
|
||||
通过在`--callbacks`中添加`deepspeed_elastic`(可选`graceful_exit`)启用弹性训练,并配置DeepSpeed弹性参数。
|
||||
命令组成=dlrover-run +dlrover 命令参数+swift 启动命令 +swift参数,dlrover-run除自定义的参数外,其他参数与torchrun一致;
|
||||
dlrover-run 参数如下:
|
||||
```
|
||||
usage: dlrover-run [-h] [--nnodes NNODES] [--nproc-per-node NPROC_PER_NODE]
|
||||
[--rdzv-backend RDZV_BACKEND] [--rdzv-endpoint RDZV_ENDPOINT] [--rdzv-id RDZV_ID]
|
||||
[--rdzv-conf RDZV_CONF] [--standalone] [--max-restarts MAX_RESTARTS]
|
||||
[--monitor-interval MONITOR_INTERVAL] [--start-method {spawn,fork,forkserver}]
|
||||
[--role ROLE] [-m] [--no-python] [--run-path] [--log-dir LOG_DIR] [-r REDIRECTS]
|
||||
[-t TEE] [--local-ranks-filter LOCAL_RANKS_FILTER] [--node-rank NODE_RANK]
|
||||
[--master-addr MASTER_ADDR] [--master-port MASTER_PORT] [--local-addr LOCAL_ADDR]
|
||||
[--logs-specs LOGS_SPECS] [--precheck {0,1,2}] [--node_unit NODE_UNIT]
|
||||
[--auto_config] [--auto_tunning] [--exclude-straggler] [--save_at_breakpoint]
|
||||
[--accelerator {nvidia.com/gpu,ascend-npu}] [--training_port TRAINING_PORT]
|
||||
[--switchbox-check] [--box-pairs PAIR [PAIR ...]] [--min-bandwidth MIN_BANDWIDTH]
|
||||
[--min-channels MIN_CHANNELS] [--numa-affinity] [--network-check]
|
||||
[--comm-perf-test] [--ucp_device_type UCP_DEVICE_TYPE]
|
||||
training_script
|
||||
|
||||
```
|
||||
在弹性训练中我们需要关注的参数为:
|
||||
|
||||
--nnodes NNODES Number of nodes, or the range of nodes in form
|
||||
<minimum_nodes>:<maximum_nodes>.
|
||||
|
||||
--nproc-per-node NPROC_PER_NODE Number of processes per node.
|
||||
示例:
|
||||
|
||||
```bash
|
||||
model=your model path
|
||||
dataset=your dataset
|
||||
output= your output dir
|
||||
export CUDA_VISIBLE_DEVICES=0 根据实际使用的GPU情况设置
|
||||
deepspeed_config_or_type=deepspeed类型或者配置文件的路径,如 zero1 或者/xxx/ms-swift/swift/llm/ds_config/zero1.json
|
||||
|
||||
dlrover-run --nnodes 1:$NODE_NUM --nproc_per_node=1 \
|
||||
/opt/conda/lib/python3.10/site-packages/swift/cli/sft.py --model $model \
|
||||
--model_type qwen3 \
|
||||
--tuner_type lora \
|
||||
--torch_dtype bfloat16 \
|
||||
--dataset $dataset \
|
||||
--num_train_epochs 4 \
|
||||
--per_device_train_batch_size 1 \
|
||||
--per_device_eval_batch_size 1 \
|
||||
--learning_rate 5e-7 \
|
||||
--gradient_accumulation_steps 8 \
|
||||
--eval_steps 500 \
|
||||
--save_steps 10 \
|
||||
--save_total_limit 20 \
|
||||
--logging_steps 1 \
|
||||
--output_dir $output \
|
||||
--warmup_ratio 0.01 \
|
||||
--dataloader_num_workers 4 \
|
||||
--temperature 1.0 \
|
||||
--system 'You are a helpful assistant.' \
|
||||
--lora_rank 8 \
|
||||
--lora_alpha 32 \
|
||||
--target_modules all-linear \
|
||||
--dataset_num_proc 1 \
|
||||
--use_flash_ckpt true \
|
||||
--callbacks deepspeed_elastic graceful_exit \
|
||||
--deepspeed $deepspeed_config_or_type \
|
||||
```
|
||||
|
||||
## 配置文件示例
|
||||
默认情况下的zero1为以下示例配置,
|
||||
|
||||
```json
|
||||
{
|
||||
"fp16": {
|
||||
"enabled": "auto",
|
||||
"loss_scale": 0,
|
||||
"loss_scale_window": 1000,
|
||||
"initial_scale_power": 16,
|
||||
"hysteresis": 2,
|
||||
"min_loss_scale": 1
|
||||
},
|
||||
|
||||
"bf16": {
|
||||
"enabled": "auto"
|
||||
},
|
||||
|
||||
"zero_optimization": {
|
||||
"stage": 1,
|
||||
"offload_optimizer": {
|
||||
"device": "none",
|
||||
"pin_memory": true
|
||||
},
|
||||
"allgather_partitions": true,
|
||||
"allgather_bucket_size": 2e8,
|
||||
"overlap_comm": false,
|
||||
"reduce_scatter": true,
|
||||
"reduce_bucket_size": 2e8,
|
||||
"contiguous_gradients": true
|
||||
},
|
||||
|
||||
"gradient_accumulation_steps": "auto",
|
||||
"gradient_clipping": "auto",
|
||||
"steps_per_print": 2000,
|
||||
"train_batch_size": "auto",
|
||||
"train_micro_batch_size_per_gpu": "auto",
|
||||
"wall_clock_breakdown": false,
|
||||
"elasticity": {
|
||||
"ignore_non_elastic_batch_info": true,
|
||||
"enabled": true,
|
||||
"max_train_batch_size": 8,
|
||||
"micro_batch_sizes": [
|
||||
4,
|
||||
2
|
||||
],
|
||||
"min_gpus": 1,
|
||||
"max_gpus": 4,
|
||||
"min_time": 20,
|
||||
"version": 0.1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
如果用户需要自定义,可以在启动命令中deepspeed_config_or_type指定自定义的zero1.json的存放路径,其中弹性相关的配置为:
|
||||
```json
|
||||
...
|
||||
|
||||
"elasticity": {
|
||||
"ignore_non_elastic_batch_info": true,
|
||||
"enabled": true,
|
||||
"max_train_batch_size": 8,
|
||||
"micro_batch_sizes": [
|
||||
4,
|
||||
2
|
||||
],
|
||||
"min_gpus": 1,
|
||||
"max_gpus": 4,
|
||||
"min_time": 20,
|
||||
"version": 0.1
|
||||
}
|
||||
```
|
||||
|
||||
- ignore_non_elastic_batch_info:代表在elasticity里的配置会忽略外层的batch_size相关的配置,训练过程中会根据实际的训练进程个数实时修改batch_size等相关的参数
|
||||
计算原则为:
|
||||
global-training-batch-size = micro-batch-size * gradient-accumulation-steps * world-size
|
||||
- max_train_batch_size:最大batch_size数
|
||||
- micro_batch_sizes:elasticity下允许的每卡micro-batch size列表,相当于train_micro_batch_size_per_gpu的候选值
|
||||
- min_gpus:最小gpu数目
|
||||
- max_gpus:最大gpu数目
|
||||
更详细的内容见:[Deepspeed](https://www.deepspeed.ai/docs/config-json/#elastic-training-config-v01-and-v02)
|
||||
|
||||
|
||||
## 启动训练
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: elastic.iml.github.io/v1alpha1
|
||||
kind: ElasticJob
|
||||
metadata:
|
||||
name: deepspeed-elastic-swift
|
||||
namespace: dlrover
|
||||
spec:
|
||||
distributionStrategy: AllreduceStrategy
|
||||
optimizeMode: single-job
|
||||
replicaSpecs:
|
||||
worker:
|
||||
replicas: 1 #【这里需要与启动命令中的--nnodes NNODES的最大值一致】
|
||||
template:
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: main
|
||||
image: #【训练镜像,需要安装deepspeed,dlrover 和swift 】
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- /bin/bash
|
||||
- -c
|
||||
- sh start.sh # 启动脚本
|
||||
resources:
|
||||
limits:
|
||||
cpu: '8'
|
||||
memory: 16Gi
|
||||
nvidia.com/gpu: '1'
|
||||
volumeMounts:
|
||||
- mountPath: /model
|
||||
name: volume-model
|
||||
- mountPath: /dev/shm
|
||||
name: volume-shm
|
||||
restartPolicy: Never
|
||||
volumes:
|
||||
- hostPath:
|
||||
path: /model
|
||||
type: Directory
|
||||
name: volume-model
|
||||
- emptyDir:
|
||||
medium: Memory
|
||||
sizeLimit: 200Gi
|
||||
name: volume-shm
|
||||
|
||||
```
|
||||
@@ -0,0 +1,211 @@
|
||||
# Embedding训练
|
||||
|
||||
SWIFT已经支持Embedding模型的训练,包括纯文本和多模态两个类型。目前已经支持的模型有:
|
||||
|
||||
1. modernbert embedding模型
|
||||
- [ModelScope](https://modelscope.cn/models/iic/gte-modernbert-base) [Hugging Face](https://huggingface.co/Alibaba-NLP/gte-modernbert-base)
|
||||
2. gte embedding模型
|
||||
- 1.5B: [ModelScope](https://www.modelscope.cn/models/iic/gte_Qwen2-1.5B-instruct) [Hugging Face](https://huggingface.co/Alibaba-NLP/gte-Qwen2-1.5B-instruct)
|
||||
- 7B: [ModelScope](https://www.modelscope.cn/models/iic/gte_Qwen2-7B-instruct) [Hugging Face](https://huggingface.co/Alibaba-NLP/gte-Qwen2-7B-instruct)
|
||||
3. gme embedding模型
|
||||
- 2B: [ModelScope](https://www.modelscope.cn/models/iic/gme-Qwen2-VL-2B-Instruct) [Hugging Face](https://huggingface.co/Alibaba-NLP/gme-Qwen2-VL-2B-Instruct)
|
||||
- 7B: [ModelScope](https://www.modelscope.cn/models/iic/gme-Qwen2-VL-7B-Instruct) [Hugging Face](https://huggingface.co/Alibaba-NLP/gme-Qwen2-VL-7B-Instruct)
|
||||
4. qwen3-embedding模型
|
||||
- 0.6B: [ModelScope](https://www.modelscope.cn/models/Qwen/Qwen3-Embedding-0.6B) [Hugging Face](https://huggingface.co/Qwen/Qwen3-Embedding-0.6B)
|
||||
- 4B: [ModelScope](https://www.modelscope.cn/models/Qwen/Qwen3-Embedding-4B) [Hugging Face](https://huggingface.co/Qwen/Qwen3-Embedding-4B)
|
||||
- 8B: [ModelScope](https://www.modelscope.cn/models/Qwen/Qwen3-Embedding-8B) [Hugging Face](https://huggingface.co/Qwen/Qwen3-Embedding-8B)
|
||||
5. qwen3-vl-embedding模型
|
||||
- 2B: [ModelScope](https://www.modelscope.cn/models/Qwen/Qwen3-VL-Embedding-2B) [Hugging Face](https://huggingface.co/Qwen/Qwen3-VL-Embedding-2B)
|
||||
- 8B: [ModelScope](https://www.modelscope.cn/models/Qwen/Qwen3-VL-Embedding-8B) [Hugging Face](https://huggingface.co/Qwen/Qwen3-VL-Embedding-8B)
|
||||
|
||||
|
||||
开发者可以自行集成自己的模型,模型forward输出值需要满足:
|
||||
|
||||
```text
|
||||
{"last_hidden_state": some-embedding-tensor}
|
||||
```
|
||||
|
||||
返回值是一个json,具有`last_hidden_state` key,value是embedding tensor即可,输入部分可以使用我们已经支持的template。用户也可以通过指定
|
||||
|
||||
```shell
|
||||
--task_type embedding
|
||||
```
|
||||
参数来将任意一个其他模型转换为embedding模型进行训练。
|
||||
|
||||
需要注意的是,SWIFT目前支持的embedding模型均为符合纯文本或多模态LLM,目前并不支持CLIP类型的模型训练。
|
||||
|
||||
此外,SWIFT支持的所有embedding模型在模型forward最后都增加了normalize,如自行增加新模型请注意增加normalize层。
|
||||
|
||||
## loss
|
||||
|
||||
目前SWIFT支持的Embedding模型可以使用的loss有:
|
||||
|
||||
- cosine_similarity: cosine相似度loss,计算两个embedding的相似度,并根据label的值拟合,实际为MSE loss
|
||||
- contrastive: 可调margin的对比学习loss,label仅支持0和1两个值
|
||||
- online_contrastive: 考虑hard negative和hard positive部分的contrastive loss,label仅支持0和1两个值
|
||||
- infonce: 在同一个batch中不同row两两计算cosine相似度,并使row内部相似度最大,不同row相似度最小,不需要label
|
||||
|
||||
loss的源代码可以在[这里](https://github.com/modelscope/ms-swift/blob/main/swift/loss/mapping.py)找到。
|
||||
|
||||
## 数据集格式
|
||||
|
||||
> 注:
|
||||
> 1. `<image>`标签可以出现在`messages`/`positive_messages`/`negative_messages`的任意位置;它们各自拥有独立的`images`/`positive_images`/`negative_images`字段用于提供图片路径或URL。
|
||||
> 2. 不再需要跨字段的“对应顺序”。对齐规则为:`images`的长度等于`messages`中`<image>`标签的数量;`positive_images`与`negative_images`均为“list of list”,其外层长度分别等于`positive_messages`与`negative_messages`的长度;并且外层每一项的内层列表长度等于该条消息序列中`<image>`标签的数量。
|
||||
> 3. `messages`代表anchor样本(anchor sample);`positive_messages`/`negative_messages`为“list of messages”(因此多一层`[]`);相应地,`positive_images`/`negative_images`也多一层`[]`并与之逐项对齐。
|
||||
> 4. 也支持`<video>`, `<audio>`标签;可按相同规则分别通过`videos`/`positive_videos`/`negative_videos`与`audios`/`positive_audios`/`negative_audios`提供对应模态数据。
|
||||
> 5. 当前约束:`positive_messages`的外层长度必须为1(即仅提供一个positive样本);对应地,`positive_images`的外层长度也必须为1。
|
||||
|
||||
### cosine_similarity loss对应的格式
|
||||
|
||||
```json lines
|
||||
# LLM
|
||||
{"messages": [{"role": "user", "content": "sentence1"}], "positive_messages": [[{"role": "user", "content": "sentence2"}]], "label": 0.8}
|
||||
# MLLM
|
||||
{"messages": [{"role": "user", "content": "<image>"}], "images": ["/some/images1.jpg"],"positive_messages": [[{"role": "user", "content": "<image>sentence"}]], "positive_images": [["/some/images2.jpg"]], "label": 0.7}
|
||||
{"messages": [{"role": "user", "content": "sentence1"}], "positive_messages": [[{"role": "user", "content": "<image>sentence2"}]], "positive_images": [["/some/images.jpg"]], "label": 0.7}
|
||||
```
|
||||
|
||||
|
||||
### contrastive/online_contrastive loss对应的格式
|
||||
|
||||
```json lines
|
||||
# LLM
|
||||
{"messages": [{"role": "user", "content": "sentence1"}], "positive_messages": [[{"role": "user", "content": "sentence2"}]], "label": 1}
|
||||
# MLLM
|
||||
{"messages": [{"role": "user", "content": "<image>"}], "images": ["/some/images1.jpg"], "positive_messages": [[{"role": "user", "content": "<image>sentence"}]], "positive_images": [["/some/images2.jpg"]], "label": 1}
|
||||
{"messages": [{"role": "user", "content": "sentence1"}], "positive_messages": [[{"role": "user", "content": "<image>sentence2"}]], "positive_images": [["/some/images.jpg"]], "label": 0}
|
||||
```
|
||||
|
||||
评测的指标分别是两个embedding的欧式距离、点积等的pearson系数以及spearman系数,共八个指标。
|
||||
|
||||
### infonce 格式
|
||||
|
||||
```json lines
|
||||
# LLM
|
||||
{"messages": [{"role": "user", "content": "sentence1"}], "positive_messages": [[{"role": "user", "content": "sentence2"}]]}
|
||||
# MLLM
|
||||
{"messages": [{"role": "user", "content": "<image>"}], "images": ["/some/images.jpg"], "positive_messages": [[{"role": "user", "content": "sentence"}]]}
|
||||
{"messages": [{"role": "user", "content": "<image>sentence1"}], "images": ["/some/images.jpg"], "positive_messages": [[{"role": "user", "content": "<image>sentence2"}]], "positive_images": [["/some/positive_images.jpg"]], "negative_messages": [[{"role": "user", "content": "<image><image>sentence3"}], [{"role": "user", "content": "<image>sentence4"}]], "negative_images": [["/some/negative_images1.jpg", "/some/negative_images2.jpg"], ["/some/negative_images3.jpg"]]}
|
||||
```
|
||||
|
||||
infonce loss支持几个环境变量:
|
||||
1. `INFONCE_TEMPERATURE`: temperature参数,不设置的话默认值是0.1
|
||||
2. `INFONCE_USE_BATCH`: 使用sample内部的`negative_messages`(hard negative样例)还是使用一个batch内其他样本作为in-batch negatives;默认为True,表示使用batch内部的样本作为负例
|
||||
3. `INFONCE_HARD_NEGATIVES`: hard negatives的数量;如果不设置会使用数据中提供的所有`negative_messages`。由于长度未必一致,因此会采用for循环计算loss(计算会慢)。若设置为某个数值,则不足会随机采样补齐,超长会选用前`INFONCE_HARD_NEGATIVES`个
|
||||
4. `INFONCE_MASK_FAKE_NEGATIVE`: mask掉假negative。默认为False,开启时会判断 `positive_similarity + INFONCE_FAKE_NEG_MARGIN`,比该阈值大的样本相似度会被设置为 `-inf`,以防止正样本泄露问题
|
||||
5. `INFONCE_FAKE_NEG_MARGIN`:假负样本屏蔽的边际,默认 `0.1`。
|
||||
6. `INFONCE_INCLUDE_QQ`:是否在分母中加入 q–q 分量(query 间相似度)作为负例,默认 `False`。
|
||||
7. `INFONCE_INCLUDE_DD`:是否在分母中加入 d–d 分量(正样本文档与 batch 内所有文档的相似度)作为负例,默认 `False`。
|
||||
|
||||
> 也可以在数据集中将hard negatives数量设置为数量相等,这样即使不设置也不会使用for循环方式,加快计算速度
|
||||
> `negative_messages`也可以不提供。在这种情况下,保持`INFONCE_USE_BATCH=True`,会使用一个batch内部的其他样本作为负例
|
||||
|
||||
infonce loss的评测会有下面几个指标:
|
||||
- mean_neg 所有hard_negative的平均值
|
||||
- mean_pos 所有positive的平均值
|
||||
- margin positive-max_hard_negative的平均值
|
||||
|
||||
## 训练
|
||||
|
||||
SWIFT提供的脚手架训练脚本:
|
||||
|
||||
- [Qwen3-Embedding/Qwen3-VL-Embedding模型](https://github.com/modelscope/ms-swift/blob/main/examples/train/embedding/qwen3)
|
||||
- [GME模型](https://github.com/modelscope/ms-swift/blob/main/examples/train/embedding/train_gme.sh)
|
||||
|
||||
## 推理
|
||||
|
||||
SWIFT已经支持GME、GTE、Qwen3-Embedding模型的部署,请查看[这里](https://github.com/modelscope/ms-swift/blob/main/examples/deploy/embedding/client.py)。
|
||||
- 推理脚本参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/infer/demo_embedding.py)。
|
||||
|
||||
也可以使用原模型的代码进行推理:
|
||||
|
||||
https://www.modelscope.cn/models/iic/gte_Qwen2-7B-instruct
|
||||
|
||||
https://www.modelscope.cn/models/iic/gme-Qwen2-VL-7B-Instruct
|
||||
|
||||
如果使用了其他模型从0训练embedding(例如,原版`qwen2-vl`模型+`--task_type embedding`),也可以使用gme的推理代码,但请注意:
|
||||
|
||||
https://www.modelscope.cn/models/iic/gme-Qwen2-VL-7B-Instruct/file/view/master/gme_inference.py?status=1#L111
|
||||
|
||||
这里的模板请修改为模型自身的template,以免最后的embedding对不上。需要额外注意的是,gme模型的template和`qwen2-vl`或`qwen2.5-vl`系列的chatml template并不相同,其推理代码最后的结束字符是`<|endoftext|>`而非`<|im_end|>`.
|
||||
|
||||
## 高级功能
|
||||
|
||||
- Qwen3-Embedding 自定义 Instruction:
|
||||
- 默认无 Instruction,输入模板为:`{Query}<|endoftext|>`。
|
||||
- 通过在 system message 中添加 Instruction,可将输入改为:`{Instruction} {Query}<|endoftext|>`。
|
||||
- 示例:
|
||||
|
||||
```json lines
|
||||
{"messages": [
|
||||
{"role": "system", "content": "请用中文回答,并输出简洁要点"},
|
||||
{"role": "user", "content": "介绍一下Qwen3-Embedding"}
|
||||
]}
|
||||
```
|
||||
|
||||
> 说明:Qwen3-Embedding 模板会将 system 内容前置拼接到首条 user 消息中,并使用 `<|endoftext|>` 作为结束标记。
|
||||
|
||||
### 转换前后示例
|
||||
|
||||
- 不加 Instruction:
|
||||
|
||||
输入数据(messages):
|
||||
|
||||
```json lines
|
||||
{"messages": [
|
||||
{"role": "user", "content": "北京明天天气如何?"}
|
||||
]}
|
||||
```
|
||||
|
||||
模板转换后(送入模型的实际文本):
|
||||
|
||||
```text
|
||||
北京明天天气如何?<|endoftext|>
|
||||
```
|
||||
|
||||
- 加 Instruction:
|
||||
|
||||
输入数据(messages,包含system):
|
||||
|
||||
```json lines
|
||||
{"messages": [
|
||||
{"role": "system", "content": "请使用中文、精炼输出要点"},
|
||||
{"role": "user", "content": "北京明天天气如何?"}
|
||||
]}
|
||||
```
|
||||
|
||||
模板转换后(送入模型的实际文本):
|
||||
|
||||
```text
|
||||
请使用中文、精炼输出要点 北京明天天气如何?<|endoftext|>
|
||||
```
|
||||
|
||||
- positive/negative 同理:
|
||||
|
||||
若在某个 positive/negative 的消息序列中提供 system,则会将该 system 内容前置到该序列首条 user 内容之前;未提供 system 则不前置。
|
||||
|
||||
输入数据(包含一个 positive 带 system,和一个 negative 无 system):
|
||||
|
||||
```json lines
|
||||
{
|
||||
"messages": [
|
||||
{"role": "user", "content": "Anchor"}
|
||||
],
|
||||
"positive_messages": [[
|
||||
{"role": "system", "content": "指令"},
|
||||
{"role": "user", "content": "Positive"}
|
||||
]],
|
||||
"negative_messages": [[
|
||||
{"role": "user", "content": "Negative"}
|
||||
]]
|
||||
}
|
||||
```
|
||||
|
||||
模板转换后(送入模型的实际文本):
|
||||
|
||||
```text
|
||||
Anchor<|endoftext|>
|
||||
指令 Positive<|endoftext|>
|
||||
Negative<|endoftext|>
|
||||
```
|
||||
@@ -0,0 +1,145 @@
|
||||
# GRPO代码训练
|
||||
本文档介绍如何使用GRPO对模型进行代码训练
|
||||
|
||||
模型:[Qwen/Qwen2.5-7B-Instruct](https://www.modelscope.cn/models/Qwen/Qwen2.5-VL-7B-Instruct)
|
||||
|
||||
数据集:[open-r1/verifiable-coding-problems-python-10k](https://www.modelscope.cn/datasets/open-r1/verifiable-coding-problems-python-10k/dataPeview)
|
||||
|
||||
数据集样例
|
||||
```json
|
||||
{
|
||||
"problem": "Solve the following coding problem using the programming language python: Polycarp has $n$ different binary words. A word called binary if it contains only characters '0' and '1'. For example, these words are binary: \"0001\", \"11\", \"0\" and \"0011100\". Polycarp wants to offer his set of $n$ binary words to play a game \"words\". In this game, players name words and each next word (starting from the second) must start with the last character of the previous word. The first word can be any. For example, these sequence of words can be named during the game: \"0101\", \"1\", \"10\", \"00\", \"00001\". Word reversal is the operation of reversing the order of the characters. For example, the word \"0111\" after the reversal becomes \"1110\", the word \"11010\" after the reversal becomes \"01011\". Probably, Polycarp has such a set of words that there is no way to put them in the order correspondent to the game rules. In this situation, he wants to reverse some words from his set so that: the final set of $n$ words still contains different words (i.e. all words are unique); there is a way to put all words of the final set of words in the order so that the final sequence of $n$ words is consistent with the game rules. Polycarp wants to reverse minimal number of words. Please, help him. -----Input----- The first line of the input contains one integer $t$ ($1 \\le t \\le 10^4$) — the number of test cases in the input. Then $t$ test cases follow. The first line of a test case contains one integer $n$ ($1 \\le n \\le 2\\cdot10^5$) — the number of words in the Polycarp's set. Next $n$ lines contain these words. All of $n$ words aren't empty and contains only characters '0' and '1'. The sum of word lengths doesn't exceed $4\\cdot10^6$. All words are different. Guaranteed, that the sum of $n$ for all test cases in the input doesn't exceed $2\\cdot10^5$. Also, guaranteed that the sum of word lengths for all test cases in the input doesn't exceed $4\\cdot10^6$. -----Output----- Print answer for all of $t$ test cases in the order they appear. If there is no answer for the test case, print -1. Otherwise, the first line of the output should contain $k$ ($0 \\le k \\le n$) — the minimal number of words in the set which should be reversed. The second line of the output should contain $k$ distinct integers — the indexes of the words in the set which should be reversed. Words are numerated from $1$ to $n$ in the order they appear. If $k=0$ you can skip this line (or you can print an empty line). If there are many answers you can print any of them. -----Example----- Input 4 4 0001 1000 0011 0111 3 010 101 0 2 00000 00001 4 01 001 0001 00001 Output 1 3 -1 0 2 1 2 The input will be stdin and you should print your solution to stdout Now solve the problem and return the code.",
|
||||
"verification_info": {
|
||||
"language": "python",
|
||||
"test_cases": [
|
||||
{
|
||||
"input": "4\n4\n0001\n1000\n0011\n0111\n3\n010\n101\n0\n2\n00000\n00001\n4\n01\n001\n0001\n00001\n",
|
||||
"output": "1\n3 \n-1\n0\n\n2\n1 2 \n",
|
||||
"type": "stdin_stdout"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`verification_info` 提供了程序语言以及测试用例,其中包含输入和预期的输出。
|
||||
|
||||
|
||||
## 奖励函数
|
||||
使用`code_reward`和`code_format`奖励进行训练,实现细节见[代码](https://github.com/modelscope/ms-swift/blob/main/examples/train/grpo/plugin/plugin.py)
|
||||
|
||||
- `code_reward`通过[e2b](https://e2b.dev/)或[judge0](https://judge0.com/)执行生成的代码,根据数据集中的测试用例对代码进行验证给出奖励值。
|
||||
- `code_format`要求模型输出包含代码块的格式化回答。
|
||||
|
||||
注:当前通过e2b执行代码仅支持python语言,如需执行其他语言,可以使用judge0执行([judge0支持语言列表](https://github.com/judge0/judge0?tab=readme-ov-file#supported-languages))。
|
||||
|
||||
## 训练脚本
|
||||
### e2b
|
||||
- 在[e2b](https://e2b.dev/dashboard)注册获取E2B_API_KEY,并设置为环境变量。
|
||||
- `--reward_funcs`添加`external_code_reward`作为奖励函数。
|
||||
- `--external_plugins`设置为plugin.py的路径。
|
||||
首先拉起 vLLM server
|
||||
```bash
|
||||
CUDA_VISIBLE_DEVICES=7 \
|
||||
swift rollout \
|
||||
--model Qwen/Qwen2.5-7B-Instruct \
|
||||
--vllm_enable_lora true \
|
||||
--vllm_max_lora_rank 16
|
||||
```
|
||||
|
||||
```bash
|
||||
E2B_API_KEY=xxx \
|
||||
WANDB_API_KEY=xxx \
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6 \
|
||||
NPROC_PER_NODE=7 \
|
||||
swift rlhf \
|
||||
--rlhf_type grpo \
|
||||
--model Qwen/Qwen2.5-7B-Instruct \
|
||||
--external_plugins examples/train/grpo/plugin/plugin.py \
|
||||
--reward_funcs external_code_reward external_code_format \
|
||||
--reward_weights 1.0 0.1 \
|
||||
--vllm_mode server \
|
||||
--use_vllm true \
|
||||
--vllm_server_host 127.0.0.1 \
|
||||
--vllm_server_port 8000 \
|
||||
--tuner_type lora \
|
||||
--lora_rank 16 \
|
||||
--lora_alpha 32 \
|
||||
--torch_dtype bfloat16 \
|
||||
--dataset 'open-r1/verifiable-coding-problems-python-10k' \
|
||||
--load_from_cache_file true \
|
||||
--max_completion_length 2048 \
|
||||
--num_train_epochs 1 \
|
||||
--per_device_train_batch_size 2 \
|
||||
--per_device_eval_batch_size 2 \
|
||||
--learning_rate 1e-6 \
|
||||
--gradient_accumulation_steps 1 \
|
||||
--eval_steps 200 \
|
||||
--save_steps 200 \
|
||||
--save_total_limit 2 \
|
||||
--logging_steps 5 \
|
||||
--max_length 4096 \
|
||||
--output_dir output \
|
||||
--warmup_ratio 0.05 \
|
||||
--dataloader_num_workers 4 \
|
||||
--dataset_num_proc 4 \
|
||||
--num_generations 14 \
|
||||
--temperature 0.9 \
|
||||
--system 'examples/train/grpo/prompt.txt' \
|
||||
--deepspeed zero2 \
|
||||
--log_completions true \
|
||||
--report_to wandb
|
||||
```
|
||||
|
||||
### judge0
|
||||
- 设置环境变量:
|
||||
- (必需)JUDGE0_ENDPOINT: judge0访问地址。
|
||||
- (可选)JUDGE0_X_AUTH_TOKEN: judge0访问Token。
|
||||
- `--reward_funcs`添加`external_code_reward_by_judge0`作为奖励函数。
|
||||
- `--external_plugins`设置为plugin.py的路径。
|
||||
|
||||
```bash
|
||||
JUDGE0_ENDPOINT=xxx \
|
||||
JUDGE0_X_AUTH_TOKEN=xxx \
|
||||
WANDB_API_KEY=xxx \
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6 \
|
||||
NPROC_PER_NODE=7 \
|
||||
swift rlhf \
|
||||
--rlhf_type grpo \
|
||||
--model Qwen/Qwen2.5-7B-Instruct \
|
||||
--external_plugins examples/train/grpo/plugin/plugin.py \
|
||||
--reward_funcs external_code_reward_by_judge0 external_code_format \
|
||||
--reward_weights 1.0 0.1 \
|
||||
--vllm_mode server \
|
||||
--use_vllm true \
|
||||
--vllm_server_host 127.0.0.1 \
|
||||
--vllm_server_port 8000 \
|
||||
--tuner_type lora \
|
||||
--torch_dtype bfloat16 \
|
||||
--dataset 'open-r1/verifiable-coding-problems-python-10k' \
|
||||
--load_from_cache_file true \
|
||||
--max_completion_length 2048 \
|
||||
--num_train_epochs 1 \
|
||||
--per_device_train_batch_size 2 \
|
||||
--per_device_eval_batch_size 2 \
|
||||
--learning_rate 1e-6 \
|
||||
--gradient_accumulation_steps 1 \
|
||||
--eval_steps 200 \
|
||||
--save_steps 200 \
|
||||
--save_total_limit 2 \
|
||||
--logging_steps 5 \
|
||||
--max_length 4096 \
|
||||
--output_dir output \
|
||||
--warmup_ratio 0.05 \
|
||||
--dataloader_num_workers 4 \
|
||||
--dataset_num_proc 4 \
|
||||
--num_generations 14 \
|
||||
--temperature 0.9 \
|
||||
--system 'examples/train/grpo/prompt.txt' \
|
||||
--deepspeed zero2 \
|
||||
--log_completions true \
|
||||
--report_to wandb
|
||||
```
|
||||
|
||||
训练奖励曲线图
|
||||

|
||||
@@ -0,0 +1,314 @@
|
||||
# 多模态GRPO完整实验流程
|
||||
本文介绍如何使用SWIFT GRPO进行多模态模型和任务的训练。目标是对多个多模态任务进行训练,提升任务精度,任务定义和训练参数等参考了 [R1-V](https://github.com/Deep-Agent/R1-V.git) 和 [open-r1-multimodal](https://github.com/EvolvingLMMs-Lab/open-r1-multimodal.git)
|
||||
|
||||
|
||||
|
||||
## ClevrCount 任务
|
||||
### 任务与数据集定义
|
||||
本任务从clevr_cogen_a_train数据集出发,模型的目标是输出图像中包含的物体数量,因此,我们定义数据集如下:
|
||||
|
||||
```python
|
||||
class ClevrPreprocessor(ResponsePreprocessor):
|
||||
|
||||
def preprocess(self, row: Dict[str, Any]) -> Dict[str, Any]:
|
||||
query = row.get('query', '')
|
||||
query = f"""{query} Output the thinking process in <think> </think> and
|
||||
final answer (number) in <answer> </answer> tags."""
|
||||
row.update({'query': query})
|
||||
return super().preprocess(row)
|
||||
|
||||
|
||||
register_dataset(
|
||||
DatasetMeta(
|
||||
ms_dataset_id='AI-ModelScope/clevr_cogen_a_train',
|
||||
subsets=[
|
||||
SubsetDataset(
|
||||
name='default',
|
||||
subset='default',
|
||||
split=['train'],
|
||||
),
|
||||
],
|
||||
preprocess_func=ClevrPreprocessor(),
|
||||
tags=['qa', 'math']))
|
||||
|
||||
```
|
||||
这里重新定义dataset preprocessor的目的是修改query。数据集示例样本如下,包含messages,images和solution字段,solution会送入后续的奖励函数中,而messages和images则会作为模型输入。
|
||||
- 注意:`{'role': 'assistant', 'content': '<answer> 3 </answer>'}`将会在GRPOTrainer中被移除,可以忽略。'solution'字段将会透传入ORM中。在自定义数据集时,'images'字段组织成`["image_path1", "image_path2"]`即可。
|
||||
|
||||
```json
|
||||
{
|
||||
"images": ["image_path1", "image_path2"],
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "How many items are there in the image? Output the thinking process in <think> </think> and \n final answer (number) in <answer> </answer> tags."
|
||||
}
|
||||
],
|
||||
"solution": "<answer> 3 </answer>"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 奖励函数定义:
|
||||
本任务使用的奖励函数有两个,一个是 Deepseek-R1 中提到的格式奖励函数,另一是 ClevrCount 的准确性奖励函数。前者已经在swift中内置,通过 `--reward_funcs format` 可以直接使用,而后者需要我们自己定义,在这里我们使用 external_plugin 的方式定义准确性奖励函数,将代码放在`swift/examples/train/grpo/plugin/plugin.py`中。
|
||||
|
||||
在这里,奖励函数的输入包括completions和solution两个字段,分别表示模型生成的文本和真值。每个都是list,支持多个completion同时计算。注意,在这里,solution字段是数据集中定义的字段透传而来,如果有任务上的变动,可以分别对数据集和奖励函数做对应的改变即可。
|
||||
```python
|
||||
|
||||
class MultiModalAccuracyORM(ORM):
|
||||
|
||||
def __call__(self, completions, solution, **kwargs) -> List[float]:
|
||||
"""
|
||||
Reward function that checks if the completion is correct.
|
||||
Args:
|
||||
completions (list[str]): Generated outputs
|
||||
solution (list[str]): Ground Truths.
|
||||
|
||||
Returns:
|
||||
list[float]: Reward scores
|
||||
"""
|
||||
rewards = []
|
||||
from math_verify import parse, verify
|
||||
for content, sol in zip(completions, solution):
|
||||
reward = 0.0
|
||||
# Try symbolic verification first
|
||||
try:
|
||||
answer = parse(content)
|
||||
if float(verify(answer, parse(sol))) > 0:
|
||||
reward = 1.0
|
||||
except Exception:
|
||||
pass # Continue to next verification method if this fails
|
||||
|
||||
# If symbolic verification failed, try string matching
|
||||
if reward == 0.0:
|
||||
try:
|
||||
# Extract answer from solution if it has think/answer tags
|
||||
sol_match = re.search(r'<answer>(.*?)</answer>', sol)
|
||||
ground_truth = sol_match.group(1).strip() if sol_match else sol.strip()
|
||||
|
||||
# Extract answer from content if it has think/answer tags
|
||||
content_match = re.search(r'<answer>(.*?)</answer>', content)
|
||||
student_answer = content_match.group(1).strip() if content_match else content.strip()
|
||||
|
||||
# Compare the extracted answers
|
||||
if student_answer == ground_truth:
|
||||
reward = 1.0
|
||||
except Exception:
|
||||
pass # Keep reward as 0.0 if both methods fail
|
||||
rewards.append(reward)
|
||||
return rewards
|
||||
orms['external_r1v_acc'] = MultiModalAccuracyORM
|
||||
```
|
||||
|
||||
### GRPO训练实验记录
|
||||
#### 训练参数:
|
||||
我们选取 Qwen2.5-VL-3B-Instruct 作为基础模型进行训练,选取 Instruct 而不是基模的主要原因是可以更快地获取 format reward。我们在八卡 GPU 上进行实验。如果遇到vllm部署qwen2.5-vl报错,可以参考[issue](https://github.com/vllm-project/vllm/issues/13285)
|
||||
|
||||
由于任务简单,我们设置max_completion_length为1024,奖励函数选择external_r1v_acc和format,学习率和beta分别设置为1e-6和0.001。其他设置如下所示,batch_size和num_generations的设置原则可以参考[GRPO完整流程](./GRPO.md)。
|
||||
首先拉起 external vLLM server
|
||||
```bash
|
||||
CUDA_VISIBLE_DEVICES=6,7 \
|
||||
swift rollout \
|
||||
--model Qwen/Qwen2.5-VL-3B-Instruct \
|
||||
--vllm_data_parallel_size 2
|
||||
```
|
||||
|
||||
```shell
|
||||
WANDB_API_KEY=your_wandb_api_key \
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5 \
|
||||
NPROC_PER_NODE=6 \
|
||||
swift rlhf \
|
||||
--rlhf_type grpo \
|
||||
--model Qwen/Qwen2.5-VL-3B-Instruct \
|
||||
--external_plugins examples/train/grpo/plugin/plugin.py \
|
||||
--reward_funcs external_r1v_acc format \
|
||||
--use_vllm true \
|
||||
--vllm_mode server \
|
||||
--vllm_server_host 127.0.0.1 \
|
||||
--vllm_server_port 8000 \
|
||||
--tuner_type full \
|
||||
--torch_dtype bfloat16 \
|
||||
--dataset 'AI-ModelScope/clevr_cogen_a_train' \
|
||||
--load_from_cache_file true \
|
||||
--max_completion_length 1024 \
|
||||
--num_train_epochs 1 \
|
||||
--per_device_train_batch_size 8 \
|
||||
--per_device_eval_batch_size 8 \
|
||||
--learning_rate 1e-6 \
|
||||
--gradient_accumulation_steps 2 \
|
||||
--save_strategy 'steps' \
|
||||
--eval_strategy 'steps' \
|
||||
--eval_steps 1000 \
|
||||
--save_steps 1000 \
|
||||
--save_total_limit 10 \
|
||||
--logging_steps 1 \
|
||||
--output_dir output/GRPO_CLEVR_COUNTDOWN \
|
||||
--warmup_ratio 0.01 \
|
||||
--dataloader_num_workers 4 \
|
||||
--num_generations 24 \
|
||||
--temperature 1.0 \
|
||||
--system 'examples/train/grpo/prompt.txt' \
|
||||
--deepspeed zero3 \
|
||||
--log_completions true \
|
||||
--report_to wandb \
|
||||
--num_iterations 1 \
|
||||
--async_generate false \
|
||||
--beta 0.001 \
|
||||
```
|
||||
#### 实验现象
|
||||

|
||||
由于数据集和任务比较简单,模型训练了500个epoch已经基本收敛,有以下观察。
|
||||
1. 自定义的ClevrORM在不断增加,证明模型学习到了如何完成这一任务,最终任务成功率从初始的0.4攀升到1左右。
|
||||
2. 由于是Instruct模型,Format Reward基本稳定在1,这可能也与数据集所有样本都是一样的query有一定关系。
|
||||
3. reward_std 稳定到0.1以下。
|
||||
4. completion length最终稳定在60-80,模型学习到的固定输出范式是逐个物体列举数数。
|
||||
|
||||
step 1:
|
||||
```
|
||||
"<think> The image shows 5 distinct items: a cyan metallic cylinder, a red metallic cylinder, a small purple metallic cylinder, a large gray metallic sphere, and a small yellow metallic cube. To count the number of items, I add the counts of each type of object: 1 cyan cylinder, 1 red cylinder, 1 purple cylinder, 1 gray sphere, and 1 yellow cube. Therefore, the total number of items is 5. </think>\n<answer>5</answer>"
|
||||
"Let's count the number of items in the image:\n1. A large cyan metallic cylinder.\n2. A small purple metallic cylinder.\n3. A large red metallic cylinder.\n4. A large gray metallic sphere.\n5. A small yellow metallic cube.\n\n<answer>5</answer>"
|
||||
"<think> The image shows four distinct objects: a large cyan metallic cylinder, a smaller purple metallic cylinder, a large red metallic cylinder, and a small yellow metallic cube. Counting each of these items individually, there are five items in total. </think>\n<answer>5</answer>"
|
||||
```
|
||||
step 400:
|
||||
```
|
||||
"<think> Counting the number of items in the image:\n1. Green matte sphere\n2. Large metallic yellow sphere\n3. Small metallic brown cube\n\nThere are three distinct objects in total.\n</think>\n<answer>3</answer>"
|
||||
"<think> Counting the objects in the image:\n1. Large yellow metallic sphere\n2. Small green rubber sphere\n3. Small brown metallic cube\n\nThere are three distinct items in the image.\n</think>\n<answer>3</answer>"
|
||||
```
|
||||
总体来讲,这一任务比较简单,reward的收敛也比较典型。
|
||||
|
||||
## Geometric QA任务
|
||||
### 任务与数据集定义
|
||||
本任务为Geometric QA任务,任务描述为:给定一个几何图形,回答有关几何图形的数学问题。原始数据来自于[论文](https://arxiv.org/pdf/2312.11370),[R1-V](https://github.com/Deep-Agent/R1-V.git)对数据进行了预处理,将所有数据全部处理成了problem-solution的格式,而图像则保留在image字段中,因此,我们不需要额外定义数据集,直接使用`--dataset AI-ModelScope/GEOQA_R1V_Train_8K`即可。
|
||||
### 奖励函数
|
||||
由于也是数学题,同时,答案也处理成了最终结果,因此,我们直接使用以上定义过的`MultiModalAccuracyORM`奖励函数。
|
||||
### GRPO训练实验记录
|
||||
#### 训练参数:
|
||||
选取的模型和大部分超参数与上一个实验相似,主要有两点不同:
|
||||
1. SWIFT 已支持`--num_iteration`参数,单次rollout可以进行多次更新,这里设置为2。
|
||||
2. 在实验时发现,在数学问题中,训练可能会出现不稳定现象,导致模型训崩,具体表现为所有rewar迅速降低,loss、grad_norm和kl都迅速增大,后续也难以恢复正常状态。因此,这里设置`--max_grad_norm 0.5`,保证稳定训练,当然,这种现象的出现也有一定的随机性。
|
||||
|
||||
```shell
|
||||
WANDB_API_KEY=your_wandb_api_key \
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5 \
|
||||
MAX_PIXELS=401408 \
|
||||
NPROC_PER_NODE=6 \
|
||||
swift rlhf \
|
||||
--rlhf_type grpo \
|
||||
--model Qwen/Qwen2.5-VL-3B-Instruct \
|
||||
--external_plugins examples/train/grpo/plugin/plugin.py \
|
||||
--reward_funcs external_r1v_acc format \
|
||||
--use_vllm true \
|
||||
--vllm_mode server \
|
||||
--vllm_server_host 127.0.0.1 \
|
||||
--vllm_server_port 8000 \
|
||||
--tuner_type full \
|
||||
--torch_dtype bfloat16 \
|
||||
--dataset 'AI-ModelScope/GEOQA_R1V_Train_8K' \
|
||||
--load_from_cache_file true \
|
||||
--max_completion_length 1024 \
|
||||
--num_train_epochs 1 \
|
||||
--per_device_train_batch_size 8 \
|
||||
--per_device_eval_batch_size 8 \
|
||||
--learning_rate 1e-6 \
|
||||
--gradient_accumulation_steps 2 \
|
||||
--save_strategy 'steps' \
|
||||
--eval_strategy 'steps' \
|
||||
--eval_steps 400 \
|
||||
--save_steps 400 \
|
||||
--save_total_limit 10 \
|
||||
--logging_steps 1 \
|
||||
--output_dir output/GRPO_GEOQA \
|
||||
--warmup_ratio 0.05 \
|
||||
--dataloader_num_workers 4 \
|
||||
--num_generations 8 \
|
||||
--temperature 1.0 \
|
||||
--repetition_penalty 1.1 \
|
||||
--system 'examples/train/grpo/prompt.txt' \
|
||||
--deepspeed zero3 \
|
||||
--log_completions true \
|
||||
--report_to wandb \
|
||||
--num_iterations 2 \
|
||||
--async_generate false \
|
||||
--beta 0.001 \
|
||||
--max_grad_norm 0.5 \
|
||||
```
|
||||
|
||||
#### 实验现象
|
||||

|
||||
训练曲线如上图所示。
|
||||
1. 相比于Count任务,Geometric QA任务的难度明显更大,因此,Accuracy Reward收敛明显更慢,同时震荡幅度也明显更大。
|
||||
2. completion_length的变化趋势比较明显,最终收敛到250 token左右。
|
||||
3. reward基本收敛,标准差在一共1300个step时稳定在0.2左右。
|
||||
以下是训练后的模型completition示例:
|
||||
```
|
||||
User:
|
||||
"If AB is the tangent to circle O with the tangent point A, and BO intersects circle O at point C, and point D is located on circle O, what is the measure of angle ADC if the degree of angle ABO is 32.0?"
|
||||
Assistant:
|
||||
"<think>\nTo find the measure of angle ADC, we first need to understand the properties of the tangent and the circle. Since AB is a tangent to the circle at point A, the line segment OA (which is perpendicular to the tangent AB) is perpendicular to AB. This means that angle OAB is 90 degrees.\n\nGiven that angle ABO is 32 degrees, we can find angle BAO by subtracting angle ABO from 90 degrees:\n∠BAO = 90° - ∠ABO = 90° - 32° = 58°\n\nSince angle BAO is an angle in the minor arc AD, the angle ADC, which is an angle in the minor arc AD, is half the angle BAO. Therefore, angle ADC is:\n∠ADC = 1/2 × ∠BAO = 1/2 × 58° = 29°\n\nSo, the measure of angle ADC is 29 degrees.\n</think>\n<answer>\nThe measure of angle ADC is 29 degrees.\n</answer>"
|
||||
```
|
||||
## Multimodal Open R1 数据集实验
|
||||
### 任务与数据集定义
|
||||
本任务为参考[open-r1-multimodal](https://github.com/EvolvingLMMs-Lab/open-r1-multimodal.git)的实验,使用数据集:[lmms-lab/multimodal-open-r1-8k-verified](https://www.modelscope.cn/datasets/lmms-lab/multimodal-open-r1-8k-verified),该数据集专注于多模态的数学推理任务,数据由GPT4o基于`Math360K`和`Geo170K`数据集生成,包含推理路径和可验证答案。数据集中已包含了image, problem和solution字段,我们也不需要针对prompt进行修改,因此无需额外定义数据集。
|
||||
### 奖励函数
|
||||
我们直接使用以上定义过的`MultiModalAccuracyORM`奖励函数。
|
||||
### GRPO训练实验记录
|
||||
#### 训练参数:
|
||||
选取的模型和大部分超参数与上一个实验相似,由于训练的时候出现了OOM,我们设置`MAX_PIXELS=262144`以降低显存占用。
|
||||
```shell
|
||||
WANDB_API_KEY=your_wandb_api_key \
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5 \
|
||||
MAX_PIXELS=262144 \
|
||||
MASTER_PORT=29600 \
|
||||
NPROC_PER_NODE=6 \
|
||||
swift rlhf \
|
||||
--rlhf_type grpo \
|
||||
--model Qwen/Qwen2.5-VL-3B-Instruct \
|
||||
--external_plugins examples/train/grpo/plugin/plugin.py \
|
||||
--reward_funcs external_r1v_acc format \
|
||||
--use_vllm true \
|
||||
--vllm_mode server \
|
||||
--vllm_server_host 127.0.0.1 \
|
||||
--vllm_server_port 8000 \
|
||||
--tuner_type full \
|
||||
--torch_dtype bfloat16 \
|
||||
--dataset 'lmms-lab/multimodal-open-r1-8k-verified' \
|
||||
--load_from_cache_file true \
|
||||
--max_completion_length 1024 \
|
||||
--num_train_epochs 1 \
|
||||
--per_device_train_batch_size 8 \
|
||||
--per_device_eval_batch_size 8 \
|
||||
--learning_rate 1e-6 \
|
||||
--gradient_accumulation_steps 2 \
|
||||
--save_strategy 'steps' \
|
||||
--eval_strategy 'steps' \
|
||||
--eval_steps 400 \
|
||||
--save_steps 400 \
|
||||
--save_total_limit 10 \
|
||||
--logging_steps 1 \
|
||||
--output_dir output/GRPO_GEOQA \
|
||||
--warmup_ratio 0.05 \
|
||||
--dataloader_num_workers 4 \
|
||||
--num_generations 8 \
|
||||
--temperature 1.0 \
|
||||
--repetition_penalty 1.1 \
|
||||
--system 'examples/train/grpo/prompt.txt' \
|
||||
--deepspeed zero3 \
|
||||
--log_completions true \
|
||||
--report_to wandb \
|
||||
--num_iterations 2 \
|
||||
--async_generate false \
|
||||
--beta 0.001 \
|
||||
--max_grad_norm 0.5 \
|
||||
```
|
||||
|
||||
#### 实验现象
|
||||

|
||||
训练曲线如上图所示。
|
||||
一共8k数据,训练了1268个step,Accuracy Reward收敛到0.5左右,completion_length基本收敛到200token左右,reward_std最终在0.2左右震荡。
|
||||
以下是训练后的模型completition示例:
|
||||
```
|
||||
User:
|
||||
"Based on the map, which state falls into the lowest percentage range of lots, and what is that percentage range?"
|
||||
Assistant:
|
||||
"<think>\nThe image provided shows a color-coded map of the USA indicating different ranges of lot percentages across various states. According to the legend at the bottom, the lowest percentage range (6.0% - 6.5%) is represented by white. In the image, Alabama (AL) is shaded in white, which corresponds to the 6.0% - 6.5% category. Therefore, based on the map, the state that falls into the lowest percentage range of lots is Alabama, with the percentage range of 6.0% - 6.5%.\nTherefore, the answer is 6.0% - 6.5%.\n</think>\n<answer>Alabama</answer>"
|
||||
```
|
||||
@@ -0,0 +1,195 @@
|
||||
# GRPO完整实验流程
|
||||
|
||||
本文从较为简单的数学任务 Coundown Game 出发,从数据集定义、奖励函数定义和GRPO训练几个步骤介绍完整的GRPO训练流程。任务定义和训练参数等参考了 [mini-deepseek-r1](https://github.com/philschmid/deep-learning-pytorch-huggingface/blob/main/training/mini-deepseek-r1-aha-grpo.ipynb)。
|
||||
|
||||
## 任务与数据集定义
|
||||
|
||||
Coundown Game 的任务目标是根据给定的几个数字和加减乘除四种运算,得到目标数字,因此,我们定义数据集如下:
|
||||
```python
|
||||
class CoundownTaskPreprocessor(ResponsePreprocessor):
|
||||
|
||||
def preprocess(self, row: Dict[str, Any]) -> Dict[str, Any]:
|
||||
numbers = row['nums']
|
||||
target = row.pop('response', None)
|
||||
query = f"""
|
||||
Using the numbers {numbers}, create an equation that equals {target}.
|
||||
You can use basic arithmetic operations (+, -, *, /) and each number can only be used once.
|
||||
Show your work in <think> </think> tags. And return the final equation and answer in <answer> </answer> tags,
|
||||
for example <answer> (1 + 2) / 3 * 4 = 4 </answer>.
|
||||
"""
|
||||
row.update({'target': target, 'query': query})
|
||||
return super().preprocess(row)
|
||||
|
||||
register_dataset(
|
||||
DatasetMeta(
|
||||
ms_dataset_id='zouxuhong/Countdown-Tasks-3to4',
|
||||
subsets=['default'],
|
||||
preprocess_func=CoundownTaskPreprocessor(),
|
||||
tags=['math']))
|
||||
```
|
||||
通过 template, 使用 numbers 和 target 完成任务定义,并给到 query 字段供模型采样使用。同时,我们需要保留 nums 和 target 两个字段,用于后续的奖励函数计算。
|
||||
|
||||
## 奖励函数定义:
|
||||
本任务使用的奖励函数有两个,一个是 Deepseek-R1 中提到的格式奖励函数,另一是 Coundown Game 的准确性奖励函数。前者已经在swift中内置,通过 `--reward_funcs format` 可以直接使用,而后者需要我们自己定义,在这里我们使用 external_plugin 的方式定义准确性奖励函数,将代码放在`swift/examples/train/grpo/plugin/plugin.py`中。
|
||||
|
||||
在这里,奖励函数的输入包括 completions、target 和 nums 三个字段,分别表示模型生成的文本、目标答案和可用的数字。每个都是list,支持多个 completion 同时计算。注意,在这里,除了 completions 之外的参数都是数据集中定义的字段透传而来,如果有任务上的变动,可以分别对数据集和奖励函数做对应的改变即可。
|
||||
```python
|
||||
class CountdownORM(ORM):
|
||||
def __call__(self, completions, target, nums, **kwargs) -> List[float]:
|
||||
"""
|
||||
Evaluates completions based on Mathematical correctness of the answer
|
||||
Args:
|
||||
completions (list[str]): Generated outputs
|
||||
target (list[str]): Expected answers
|
||||
nums (list[str]): Available numbers
|
||||
Returns:
|
||||
list[float]: Reward scores
|
||||
"""
|
||||
rewards = []
|
||||
for completion, gt, numbers in zip(completions, target, nums):
|
||||
try:
|
||||
# Check if the format is correct
|
||||
match = re.search(r"<answer>(.*?)<\/answer>", completion)
|
||||
if match is None:
|
||||
rewards.append(0.0)
|
||||
continue
|
||||
# Extract the "answer" part from the completion
|
||||
equation = match.group(1).strip()
|
||||
if '=' in equation:
|
||||
equation = equation.split('=')[0]
|
||||
# Extract all numbers from the equation
|
||||
used_numbers = [int(n) for n in re.findall(r'\d+', equation)]
|
||||
# Check if all numbers are used exactly once
|
||||
if sorted(used_numbers) != sorted(numbers):
|
||||
rewards.append(0.0)
|
||||
continue
|
||||
# Define a regex pattern that only allows numbers, operators, parentheses, and whitespace
|
||||
allowed_pattern = r'^[\d+\-*/().\s]+$'
|
||||
if not re.match(allowed_pattern, equation):
|
||||
rewards.append(0.0)
|
||||
continue
|
||||
# Evaluate the equation with restricted globals and locals
|
||||
result = eval(equation, {'__builtins__': None}, {})
|
||||
# Check if the equation is correct and matches the ground truth
|
||||
if abs(float(result) - float(gt)) < 1e-5:
|
||||
rewards.append(1.0)
|
||||
else:
|
||||
rewards.append(0.0)
|
||||
except Exception as e:
|
||||
# If evaluation fails, reward is 0
|
||||
rewards.append(0.0)
|
||||
return rewards
|
||||
orms['external_countdown'] = CountdownORM
|
||||
```
|
||||
|
||||
## GRPO训练实验记录
|
||||
首先贴上GRPO的公式:
|
||||
|
||||
$$
|
||||
{\scriptstyle
|
||||
\begin{aligned}
|
||||
\mathcal{J}_{G R P O}(\theta) & =\mathbb{E}\left[q \sim P(Q),\left\{o_i\right\}_{i=1}^G \sim \pi_{\theta_{o l d}}(O \mid q)\right] \\
|
||||
& \frac{1}{G} \sum_{i=1}^G \frac{1}{\left|o_i\right|} \sum_{t=1}^{\left|o_i\right|}\left\{\min \left[\frac{\pi_\theta\left(o_{i, t} \mid q, o_{i,<t}\right)}{\pi_{\theta_{o l d}}\left(o_{i, t} \mid q, o_{i,<t}\right)} \hat{A}_{i, t}, \operatorname{clip}\left(\frac{\pi_\theta\left(o_{i, t} \mid q, o_{i,<t}\right)}{\pi_{\theta_{o l d}}\left(o_{i, t} \mid q, o_{i,<t}\right)}, 1-\varepsilon, 1+\varepsilon\right) \hat{A}_{i, t}\right]-\beta \mathbb{D}_{K L}\left[\pi_\theta| | \pi_{r e f}\right]\right\}
|
||||
\end{aligned}
|
||||
}
|
||||
$$
|
||||
|
||||
### 训练参数:
|
||||
我们选取 Qwen2.5-3B-Instruct 作为基础模型进行训练,选取 Instruct 而不是基模的主要原因是可以更快地获取 format reward。我们在三卡 GPU 上进行实验,因此vllm的推理部署在最后一张卡上,而进程数设置为2,在剩下两张卡上进行梯度更新。
|
||||
|
||||
由于任务较为简单,我们设置 max_completion_length 和 vllm_max_model_len 为1024,如果有更复杂的任务,可以适当加大模型输出长度,但请注意,**这两个参数越大,模型训练需要的显存越多,训练速度越慢,单个step的训练时间与max_completion_length呈现线性关系**。
|
||||
|
||||
在我们的实验中,总batch_size为
|
||||
|
||||
```
|
||||
num_processes * per_device_train_batch_size * gradient_accumulation_steps = 2 * 8 * 8 = 128
|
||||
```
|
||||
|
||||
注意,这里单卡batch_size设置也与显存息息相关,请根据显存上限设置一个合适的值。 同时,还有一个公式,即总的steps数量 :$num\_steps = epochs \times len(datasets) \times num\_generations \div batch\_size $,需要根据这个来合理规划训练的学习率和warmup设置。
|
||||
|
||||
最后比较重要的设置是学习率和 beta,学习率比较好理解,而beta则是是以上公式的 $\beta$,即KL散度的梯度的权重。这两个参数设置的越大,模型收敛原则上更快,但训练往往会不稳定。经过实验,我们分别设置为 `5e-7` 和 `0.001`。在实际训练中,请根据是否出现不稳定的震荡情况适当调整这两个参数。
|
||||
|
||||
对于KL散度,社区有很多的讨论,可以参考[为什么GRPO坚持用KL散度](https://zhuanlan.zhihu.com/p/25862547100)。
|
||||
|
||||
其他参数的设置,没有做太多探讨,所以这里不进行详细说明。
|
||||
```bash
|
||||
CUDA_VISIBLE_DEVICES=2 \
|
||||
swift rollout \
|
||||
--model Qwen/Qwen2.5-3B-Instruct
|
||||
```
|
||||
|
||||
```bash
|
||||
CUDA_VISIBLE_DEVICES=0,1 \
|
||||
WANDB_API_KEY=your_wandb_key \
|
||||
NPROC_PER_NODE=2 \
|
||||
swift rlhf \
|
||||
--rlhf_type grpo \
|
||||
--model Qwen/Qwen2.5-3B-Instruct \
|
||||
--external_plugins examples/train/grpo/plugin/plugin.py \
|
||||
--reward_funcs external_countdown format \
|
||||
--use_vllm true \
|
||||
--vllm_mode server \
|
||||
--vllm_server_host 127.0.0.1 \
|
||||
--vllm_server_port 8000 \
|
||||
--tuner_type full \
|
||||
--torch_dtype bfloat16 \
|
||||
--dataset 'zouxuhong/Countdown-Tasks-3to4#50000' \
|
||||
--load_from_cache_file true \
|
||||
--max_length 2048 \
|
||||
--max_completion_length 1024 \
|
||||
--num_train_epochs 1 \
|
||||
--per_device_train_batch_size 8 \
|
||||
--per_device_eval_batch_size 8 \
|
||||
--learning_rate 5e-7 \
|
||||
--gradient_accumulation_steps 8 \
|
||||
--eval_steps 500 \
|
||||
--save_steps 100 \
|
||||
--save_total_limit 20 \
|
||||
--logging_steps 1 \
|
||||
--output_dir output/GRPO_COUNTDOWN \
|
||||
--warmup_ratio 0.01 \
|
||||
--dataloader_num_workers 4 \
|
||||
--num_generations 8 \
|
||||
--temperature 1.0 \
|
||||
--system 'You are a helpful assistant. You first thinks about the reasoning process in the mind and then provides the user with the answer.' \
|
||||
--deepspeed zero3 \
|
||||
--log_completions true \
|
||||
--report_to wandb \
|
||||
--beta 0.001 \
|
||||
--num_iterations 1
|
||||
```
|
||||
### 实验现象
|
||||

|
||||
从训练了2000 step的实验结果来看,有几点观察:
|
||||
1. 自定义的CoundownORM在不断增加,证明模型学习到了如何完成这一任务,最终任务成功率在0.5左右。
|
||||
2. Format Reward整体处在较高的水平,在0.9-1左右震荡。
|
||||
3. reward_std 最终在0.2-0.3左右,仍未完全收敛,模型仍然有继续提升reward的空间。
|
||||
4. 观察模型输出可以发现,相当一部分失败案例是由于模型简单加减乘除做不对,因此模型最终的收敛方向也变成了逐步运算上,如果换成更大的模型,可能有不同的收敛方向。
|
||||
5. completion length呈现先下降再增加,在200 step左右最低,然后逐渐上升到350左右。证明模型经历了思考方式的转变。
|
||||
6. 模型的思考方式在不断变化,最终模型发现做排列组合并逐步运算能更好地完成这一任务,最终的采样输出也大多是这一格式,以下是不同step的completion变化:
|
||||
|
||||
step 1:
|
||||
```
|
||||
"<think>\nWe need to create an equation using the given numbers [70, 5, 42, 30] exactly once and make it equal to 77. \n\nFirst, let's consider the possibility of multiplication or division to get closer to 77. Notice that 77 is close to 70 and 42. If we can use these numbers together, it might work.\n\nMultiplying 70 by 1.1 would give us approximately 77, which is very close. So, let's try to make 1.1 using the remaining numbers 5 and 30. \nIf we take 30/5 = 6, and then 5/6 = 0.8333..., this isn't useful here, so let's look at other possibilities.\n\nNext, let's consider if there's another way to achieve 77 using addition, subtraction, or another combination of our numbers. Given the numbers provided, it seems that multiplication or division will be key. \n\nWe can try subtracting 5 from 30 to get 25. Then, if we divide 42 by 25, we don't get a whole number, but we can round it to the nearest whole number, 1. Now, we need to make the equation fit 77. Let's multiply 25 by 3 and add 7 (since 77 = 25*3 + 7). However, we only have one 7 available and we need to find a way to use the remaining numbers to get 7.\n\nLet's try: \n70 - 42 = 28 \nThen, 28 + 5 = 33 \nNext, 33 + 30 = 63 \nFinally, 77 - 63 = 14, which doesn't help.\n\nConsidering different combinations, one viable way is:\n(70 - 42) * (30 / 5) = 28 * 6 = 168 / 2 = 84 / 2 = 42 / 2 = 21 / 3 = 7\n\nSo, (70 - 42) * (30 / 5) = 77.\n</think>\n<answer>(70 - 42) * (30 / 5) = 77</answer>"
|
||||
```
|
||||
step 200:
|
||||
```
|
||||
"<think>\nWe need to use all the given numbers in a way that the resultant value of the calculation is 99. Given these restrictions, it's clear we should look into how the numbers relate and the mathematical operations that will bring them together to meet our condition.\n\nFirstly, let's evaluate the sums, differences, and multiplication/division among the numbers and their relations to see how this could lead us towards an outcome of 99.\n- Summing the three numbers: 96 + 70 + 73 = 239, which is far from 99. This shows addition isn't practical.\n- Subtracting numbers: For instance, subtracting the lowest two (i.e., 73 - 70 = 3) and combining with the highest one (96) does not work. Also, there is no other combination of subtraction that would result in the number needing to add up to 99.\n- Multiplying or dividing the numbers alone wouldn’t reach to any near solution since none of the products or division results of the numbers themselves is very close to 99. We might think more carefully about the arrangement of them using a combination of the operations provided.\nTherefore, considering the possible arrangement, a combination like taking (73 - 70 + 96) may produce an effective solution as this will sum the values in such a manner that it aligns with the goal of 99.\n\nSo we conclude that the operation: 73 - 70 + 96 gives the right sequence to equal 99.\n</think>\n\n<answer>73 - 70 + 96 = 99</answer>"
|
||||
```
|
||||
step 500:
|
||||
```
|
||||
"<think>\nLet's begin by exploring various possible combinations of the given numbers using the arithmetic operators we have access to.\n\n- If I add the numbers, I get: 56 + 73 + 51 = 180 which is not equal to our target number (68)\n- If I subtract one number from another I will still exceed our target value as well since the maximum difference is: |(difference between max-min):| | (73 - 51) or | (73 - 56), etc.|\n- Let's multiply the numbers individually and see if the division operation can bring us closer to the goal:\n - (73 * 51) - 56 = 3723 - 56 = 3667 which isn't the goal either.\n - The only operator left is addition and subtraction; I'll try the combination: \n ((73 - 56) + 51) gives me (17 + 51) = 68.\n \nThus, our solution fits the provided problem constraints and meets the required outcome.\n</think>\n<answer>(73 - 56) + 51 = 68</answer>"
|
||||
```
|
||||
|
||||
step 1000:
|
||||
```
|
||||
"<think>\nWe need to form an expression using the given numbers (50, 86, and 49) such that it equals 85. Let's try different combinations:\n\n(86 - 50) + 49 = 76 + 49 = 125 (too big)\n(86 - 49) + 50 = 37 + 50 = 87 (too big)\n(86 - 50) + 49 = 37 + 49 = 86 (too big)\n(86 + 50) - 49 = 136 - 49 = 87 (too big)\n(86 - 50) + (49 - x)? Not working!\n(50 + 86) - 49: this is 136 which isn't our aim.\n50 + (86 - 49) = 50 + 37 = 87 which wasn't correct.\n50 - 86 + 49 = -16 + 49: This doesn't match up as well.\n86 - (50 + 49) = 86 - 99 which doesn't work too.\n\nWe try one more:\n(86 + 49) - 50 = 135 - 50 = 85!\n\nThat's it!\n</think>\n\n<answer>(86 + 49) - 50 = 85</answer>"
|
||||
```
|
||||
|
||||
step 2000:
|
||||
```
|
||||
"<think>\nWe need to form an expression using the numbers 58, 9, 78, and 44 which evaluates to 73. Let's try different combinations:\n(78 - 58) + (9 + 44) = 10 + 53 = 63 (too low)\n(78 - 58) + (9 - 44) = 20 - 35 = -15 (too low)\n(78 - 58) + (44 - 9) = 20 + 35 = 55 (too low)\n(78 + 58) - (9 + 44) = 136 - 53 = 83 (too high)\n(78 + 58) - (9 - 44) = 136 + 35 = 171 (too high)\n(78 + 58) - (44 + 9) = 136 + 53 = 189 (too high)\n(78 + 9) - (58 + 44) = 87 - 102 = -15 (too low)\n(78 + 9) - (58 - 44) = 87 - 14 = 73\n\nSo our solution is: (78 + 9) - (58 - 44) = 73</think>\n\n<answer>(78 + 9) - (58 - 44) = 73</answer>"
|
||||
```
|
||||
|
||||
附learning_rate和beta分别取值1e-6和0.04的不稳定实验记录,模型在step 200左右出现了震荡,format和CountdownORM瞬间走低:
|
||||

|
||||
@@ -0,0 +1,658 @@
|
||||
|
||||
# 注册多模态模型最佳实践
|
||||
|
||||
本文将介绍如何在ms-swift中注册多模态模型,并成功推理和训练。本文将以Qwen2.5-Omni为例子,注册新的model_type和template `my_qwen2_5_omni`,并支持文本、图片、视频和音频的训练。由于Qwen2.5-Omni已经在ms-swift中注册,我们可以通过显式指定model_type和template来使用我们自定义的部分。
|
||||
|
||||
## 环境准备
|
||||
```shell
|
||||
# 避免未来出现与文档的不兼容情况
|
||||
pip install "ms-swift>=4.0"
|
||||
|
||||
pip install "transformers==4.57.*" "qwen_omni_utils==0.0.8"
|
||||
```
|
||||
|
||||
|
||||
## 注册模型
|
||||
|
||||
第一步,我们需要注册模型,来获取模型和processor。
|
||||
|
||||
```python
|
||||
from transformers import AutoConfig, PretrainedConfig, PreTrainedModel
|
||||
|
||||
from swift.model import (Model, ModelGroup, ModelMeta, MultiModelKeys, get_model_processor, register_model,
|
||||
register_model_arch, ModelLoader)
|
||||
from swift.model.models.qwen import patch_qwen_vl_utils
|
||||
from swift.model.patcher import patch_get_input_embeddings
|
||||
from swift.model.utils import use_submodel_func
|
||||
from swift.utils import get_env_args, Processor
|
||||
|
||||
register_model_arch(
|
||||
MultiModelKeys(
|
||||
'my_qwen2_5_omni',
|
||||
# `freeze_llm`, `freeze_vit`, `freeze_aligner`将根据下面的值来决定其行为。
|
||||
# 例如:全参数训练,若设置`freeze_vit=True`,将冻结以`thinker.audio_tower`和`thinker.visual`为前缀的模型层的参数。
|
||||
# LoRA训练,若设置`freeze_vit=False`,将额外为以`thinker.audio_tower`和`thinker.visual`为前缀的Linear层添加LoRA。
|
||||
language_model=['thinker.model', 'thinker.lm_head'],
|
||||
vision_tower=['thinker.audio_tower', 'thinker.visual'],
|
||||
aligner=['thinker.audio_tower.proj', 'thinker.visual.merger'],
|
||||
# generator的部分将永远不进行训练或处于冻结状态。
|
||||
# 如果你希望`thinker.audio_tower`, `thinker.audio_tower.proj`永远不进行训练,你可以放置到generator中,并将其从vision_tower, aligner中移除。
|
||||
generator=['talker', 'token2wav'],
|
||||
))
|
||||
|
||||
class Qwen2_5OmniLoader(ModelLoader):
|
||||
|
||||
|
||||
def get_config(self, model_dir: str) -> PretrainedConfig:
|
||||
config = AutoConfig.from_pretrained(model_dir, trust_remote_code=True)
|
||||
enable_audio_output = get_env_args('ENABLE_AUDIO_OUTPUT', bool, None)
|
||||
if enable_audio_output is not None:
|
||||
config.enable_audio_output = enable_audio_output
|
||||
return config
|
||||
|
||||
def get_processor(self, model_dir: str, config: PretrainedConfig) -> Processor:
|
||||
from transformers import Qwen2_5OmniProcessor
|
||||
from qwen_omni_utils import vision_process
|
||||
processor = Qwen2_5OmniProcessor.from_pretrained(model_dir, trust_remote_code=True)
|
||||
# Control constants in qwen_omni_utils library via environment variables,
|
||||
# e.g., `MAX_PIXELS`, etc.
|
||||
patch_qwen_vl_utils(vision_process)
|
||||
return processor
|
||||
|
||||
def get_model(self, model_dir: str, config: PretrainedConfig, processor: Processor,
|
||||
model_kwargs) -> PreTrainedModel:
|
||||
from transformers import Qwen2_5OmniForConditionalGeneration
|
||||
print('Run my_qwen2_5_omni...')
|
||||
self.auto_model_cls = self.auto_model_cls or Qwen2_5OmniForConditionalGeneration
|
||||
model = super().get_model(model_dir, config, processor, model_kwargs)
|
||||
# For multimodal model consistency, we replace the model's forward/generate functions
|
||||
# with those of its language_model.
|
||||
# Handle additional parts separately.
|
||||
use_submodel_func(model, 'thinker')
|
||||
# Avoid inplace operations on leaf_variable during training
|
||||
# (replacing parts of input_embeds with images_embeds)
|
||||
patch_get_input_embeddings(model.thinker.visual, 'patch_embed')
|
||||
# Some custom settings for model/config (usually not needed; configure based on
|
||||
# specific model if errors occur during training/inference)
|
||||
model.config.keys_to_ignore_at_inference += ['hidden_states', 'attention_mask']
|
||||
model.config.talker_config.pad_token_id = None
|
||||
return model
|
||||
|
||||
|
||||
register_model(
|
||||
ModelMeta(
|
||||
'my_qwen2_5_omni',
|
||||
[
|
||||
ModelGroup([
|
||||
Model('Qwen/Qwen2.5-Omni-3B', 'Qwen/Qwen2.5-Omni-3B'),
|
||||
Model('Qwen/Qwen2.5-Omni-7B', 'Qwen/Qwen2.5-Omni-7B'),
|
||||
]),
|
||||
],
|
||||
# 用来获取model和processor的函数。
|
||||
Qwen2_5OmniLoader,
|
||||
template='my_qwen2_5_omni',
|
||||
is_multimodal=True, # 是否是多模态模型
|
||||
model_arch='my_qwen2_5_omni', # 通常只为多模态模型设置
|
||||
# 用于model_type的自动匹配
|
||||
architectures=['Qwen2_5OmniModel', 'Qwen2_5OmniForConditionalGeneration'],
|
||||
# 用来提示用户依赖版本(可删除)
|
||||
requires=['transformers>=4.50', 'soundfile', 'qwen_omni_utils', 'decord'],
|
||||
# 用来提示用户(可删除)
|
||||
tags=['vision', 'video', 'audio'],
|
||||
# 全参数训练/merge-lora需要额外保存的文件
|
||||
additional_saved_files=['spk_dict.pt'],
|
||||
))
|
||||
|
||||
if __name__ == '__main__':
|
||||
# 测试与debug
|
||||
model, processor = get_model_processor('Qwen/Qwen2.5-Omni-7B', model_type='my_qwen2_5_omni')
|
||||
```
|
||||
|
||||
## 注册模板
|
||||
|
||||
第二步,我们需要注册模板,来自定义如何将文本、图片、视频和音频进行预处理(`_encode`和`_data_collator`方法)。这是ms-swift支持多模态模型训练的关键模块。预处理方式请参考transformers推理实现,并进行对齐。
|
||||
|
||||
template的功能如下:
|
||||
1. 支持正常推理与训练,预处理文本和多模态信息,并支持grounding任务。
|
||||
2. 支持padding_free和packing训练。
|
||||
3. 支持混合模态数据训练。
|
||||
|
||||
|
||||
```python
|
||||
from functools import partial
|
||||
from typing import Any, Dict, List, Literal, Optional
|
||||
|
||||
import torch
|
||||
from transformers.integrations import is_deepspeed_zero3_enabled
|
||||
from swift import get_model_processor
|
||||
from swift.template import StdTemplateInputs, Template, TemplateMeta, get_template, register_template
|
||||
from swift.template.utils import Context, findall
|
||||
from swift.template.vision_utils import load_audio
|
||||
from swift.utils import Processor, get_env_args, get_logger, get_packed_seq_params, is_deepspeed_enabled, to_float_dtype
|
||||
|
||||
logger = get_logger()
|
||||
|
||||
class Qwen2_5OmniTemplate(Template):
|
||||
use_model = True # 是否在预处理的过程中需要model参与
|
||||
# 需要注意是:并不是所有的多模态模型都能支持padding_free/packing。`transformers`库内的模型通常可以支持
|
||||
support_padding_free = True # 是否支持padding_free和packing(多模态模型)
|
||||
norm_bbox = 'none' # grounding任务使用绝对坐标还是norm1000坐标
|
||||
|
||||
# 这里的tokens将不会被裁剪(例如设置`--truncation_strategy left/right`)
|
||||
# 并会使用简略方式打印(调用`template.safe_decode`)
|
||||
placeholder_tokens = ['<|IMAGE|>', '<|AUDIO|>', '<|VIDEO|>']
|
||||
|
||||
def init_processor(self, processor: Processor) -> None:
|
||||
"""在初始化processor时,额外初始化所需的一些常量"""
|
||||
if processor is None:
|
||||
return
|
||||
super().init_processor(processor)
|
||||
from transformers.models.qwen2_5_omni.processing_qwen2_5_omni import Qwen2_5OmniProcessorKwargs
|
||||
default = Qwen2_5OmniProcessorKwargs._defaults
|
||||
self.seconds_per_chunk = default['videos_kwargs']['seconds_per_chunk']
|
||||
self.position_id_per_seconds = default['videos_kwargs']['position_id_per_seconds']
|
||||
self.use_audio_in_video = get_env_args('use_audio_in_video', bool, False)
|
||||
self.sampling_rate = get_env_args('sampling_rate', int, self.processor.feature_extractor.sampling_rate)
|
||||
# `QWENVL_BBOX_FORMAT`的含义参考grounding数据集自定义文档
|
||||
self.bbox_format = get_env_args('QWENVL_BBOX_FORMAT', str, 'legacy')
|
||||
|
||||
|
||||
def replace_tag(self, media_type: Literal['image', 'video', 'audio'], index: int,
|
||||
inputs: StdTemplateInputs) -> List[Context]:
|
||||
"""读取多模态数据,并替换通用多模态tag。
|
||||
例如:图像tag从`<image>` -> `<|vision_bos|><|IMAGE|><|vision_eos|>`"""
|
||||
# 读取多模态数据也可以在`_encode`函数中进行,怎么方便怎么来。
|
||||
from qwen_omni_utils import fetch_image, fetch_video
|
||||
if media_type == 'image':
|
||||
inputs.images[index] = fetch_image({'image': inputs.images[index]})
|
||||
return ['<|vision_bos|><|IMAGE|><|vision_eos|>']
|
||||
elif media_type == 'audio':
|
||||
if self.mode != 'vllm': # 'vllm'推理场景下不需要处理
|
||||
inputs.audios[index] = load_audio(inputs.audios[index], self.sampling_rate)
|
||||
return ['<|audio_bos|><|AUDIO|><|audio_eos|>']
|
||||
elif media_type == 'video':
|
||||
video = inputs.videos[index]
|
||||
_video = fetch_video({'video': video})
|
||||
if isinstance(_video, torch.Tensor):
|
||||
_video = _video.to(torch.uint8)
|
||||
inputs.videos[index] = _video
|
||||
if self.use_audio_in_video:
|
||||
import librosa
|
||||
if video.startswith('http://') or video.startswith('https://'):
|
||||
import audioread
|
||||
video = audioread.ffdec.FFmpegAudioFile(video)
|
||||
video = librosa.load(video, sr=self.sampling_rate)[0]
|
||||
inputs.audios.insert(inputs.audio_idx, (video, 'video'))
|
||||
inputs.audio_idx += 1
|
||||
return ['<|vision_bos|><|audio_bos|><|VIDEO|><|audio_eos|><|vision_eos|>']
|
||||
else:
|
||||
return ['<|vision_bos|><|VIDEO|><|vision_eos|>']
|
||||
|
||||
|
||||
def replace_ref(self, ref: str, index: int, inputs: StdTemplateInputs) -> List[Context]:
|
||||
"""替换grounding任务的通用tag: `<ref-object>`"""
|
||||
if self.bbox_format == 'legacy':
|
||||
return [f'<|object_ref_start|>{ref}<|object_ref_end|>']
|
||||
else:
|
||||
return [ref]
|
||||
|
||||
def replace_bbox(self, bbox: List[int], index: int, inputs: StdTemplateInputs) -> List[Context]:
|
||||
"""替换grounding任务的通用tag: `<bbox>`"""
|
||||
if self.bbox_format == 'legacy':
|
||||
return [f'<|box_start|>{self._get_bbox_str(bbox)}<|box_end|>']
|
||||
else:
|
||||
return [str(bbox)]
|
||||
|
||||
def packing_row(self, row: List[Dict[str, Any]]) -> Dict[str, Any]:
|
||||
"""支持packing & mrope。通常情况不需要继承该函数,这里为了自定义mrope的position_ids。"""
|
||||
position_ids = []
|
||||
for r in row:
|
||||
r = r.copy()
|
||||
r['input_ids'] = torch.tensor(r['input_ids'])[None]
|
||||
position_ids.append(self._get_position_ids(r))
|
||||
packed = super().packing_row(row)
|
||||
packed['position_ids'] = torch.concat(position_ids, dim=-1)
|
||||
return packed
|
||||
|
||||
def _get_new_tokens_use_audio_in_video(self, i, *, video_grid_thw, video_second_per_grid, audio_lengths,
|
||||
video_token_id, audio_token_id):
|
||||
"""辅助函数,用于支持`use_audio_in_video`为True的情况"""
|
||||
merge_size = self.processor.image_processor.merge_size
|
||||
grid_thw = video_grid_thw[i]
|
||||
height = grid_thw[1] // merge_size
|
||||
width = grid_thw[2] // merge_size
|
||||
audio_token_indices = torch.arange(audio_lengths[i])
|
||||
video_token_indices = torch.arange(grid_thw[0]).reshape(-1, 1, 1)
|
||||
|
||||
video_token_indices = torch.broadcast_to(video_token_indices,
|
||||
(video_token_indices.shape[0], height, width)).reshape(-1)
|
||||
video_token_indices = (video_token_indices * video_second_per_grid[i] * self.position_id_per_seconds)
|
||||
tokens_per_chunk = int(self.position_id_per_seconds * self.seconds_per_chunk)
|
||||
video_chunk_indexes = self.processor.get_chunked_index(video_token_indices, tokens_per_chunk)
|
||||
audio_chunk_indexes = self.processor.get_chunked_index(audio_token_indices, tokens_per_chunk)
|
||||
|
||||
res = []
|
||||
for j in range(max(len(video_chunk_indexes), len(audio_chunk_indexes))):
|
||||
if j < len(video_chunk_indexes):
|
||||
video_seq_length = video_chunk_indexes[j][1] - video_chunk_indexes[j][0]
|
||||
res += video_token_id * video_seq_length
|
||||
if j < len(audio_chunk_indexes):
|
||||
audio_seq_length = audio_chunk_indexes[j][1] - audio_chunk_indexes[j][0]
|
||||
res += audio_token_id * audio_seq_length
|
||||
return res
|
||||
|
||||
|
||||
def _encode(self, inputs: StdTemplateInputs) -> Dict[str, Any]:
|
||||
"""这里决定如何将text/images/audios/videos -> input_ids、labels、loss_scale以及pixel_values等多模态内容
|
||||
这里的处理逻辑通常可以从对应模型的预处理代码实现中借鉴。
|
||||
推荐:请先做推理对齐再做训练"""
|
||||
encoded = Template._encode(self, inputs) # 处理纯文本部分,具体请参考自定义模型文档
|
||||
logger.info_once('Run qwen2_5_omni template')
|
||||
processor = self.processor
|
||||
# 获取多模态内容
|
||||
media_inputs = processor(
|
||||
text='',
|
||||
audio=inputs.audios or None,
|
||||
images=inputs.images or None,
|
||||
videos=inputs.videos or None,
|
||||
do_resize=False,
|
||||
return_tensors='pt')
|
||||
# 我们不使用`processor`产生的input_ids和attention_mask。因为其不产生`labels`。
|
||||
media_inputs.pop('input_ids')
|
||||
media_inputs.pop('attention_mask')
|
||||
media_inputs = to_float_dtype(media_inputs, self.model_info.torch_dtype)
|
||||
|
||||
input_ids = encoded['input_ids']
|
||||
labels = encoded['labels']
|
||||
loss_scale = encoded.get('loss_scale', None)
|
||||
# audio模态
|
||||
audio_token_id = self._tokenize('<|AUDIO|>')
|
||||
idx_list = findall(input_ids, audio_token_id) # 查找所有的audio_token
|
||||
feature_attention_mask = media_inputs.get('feature_attention_mask')
|
||||
if feature_attention_mask is not None:
|
||||
audio_feature_lengths = torch.sum(feature_attention_mask, dim=1)
|
||||
audio_lengths = ((audio_feature_lengths - 1) // 2 + 1 - 2) // 2 + 1
|
||||
else:
|
||||
audio_lengths = None
|
||||
audio_lengths_origin = audio_lengths
|
||||
# video_audios_mask用于处理`use_audio_in_video`,区分是纯audio(0)还是video中的audio(1)
|
||||
video_audios_mask = []
|
||||
for i, audio in enumerate(inputs.audios):
|
||||
if isinstance(audio, tuple) and audio[1] == 'video':
|
||||
inputs.audios[i] = audio[0]
|
||||
video_audios_mask.append(True)
|
||||
else:
|
||||
video_audios_mask.append(False)
|
||||
video_audios_mask = torch.tensor(video_audios_mask)
|
||||
if idx_list:
|
||||
# 过滤掉video中的audio的内容(将在video部分处理)
|
||||
if self.use_audio_in_video:
|
||||
audio_lengths = audio_lengths[~video_audios_mask]
|
||||
|
||||
def _get_new_audio_tokens(i):
|
||||
return audio_token_id * audio_lengths[i]
|
||||
|
||||
# 对input_ids的多模态tokens进行展开
|
||||
input_ids, labels, loss_scale = self._extend_tokens(input_ids, labels, loss_scale, idx_list,
|
||||
_get_new_audio_tokens)
|
||||
|
||||
# image和video模态
|
||||
for media_type in ['image', 'video']:
|
||||
token = f'<|{media_type.upper()}|>'
|
||||
token_id = self._tokenize(token)
|
||||
idx_list = findall(input_ids, token_id)
|
||||
if idx_list:
|
||||
merge_size = processor.image_processor.merge_size
|
||||
media_grid_thw = media_inputs.get(f'{media_type}_grid_thw')
|
||||
if media_type == 'video' and self.use_audio_in_video:
|
||||
audio_lengths = audio_lengths_origin[video_audios_mask]
|
||||
video_second_per_grid = media_inputs['video_second_per_grid']
|
||||
_get_new_tokens_use_audio_in_video = partial(
|
||||
self._get_new_tokens_use_audio_in_video,
|
||||
video_grid_thw=media_grid_thw,
|
||||
video_second_per_grid=video_second_per_grid,
|
||||
audio_lengths=audio_lengths,
|
||||
video_token_id=token_id,
|
||||
audio_token_id=audio_token_id)
|
||||
input_ids, labels, loss_scale = self._extend_tokens(input_ids, labels, loss_scale, idx_list,
|
||||
_get_new_tokens_use_audio_in_video)
|
||||
|
||||
else:
|
||||
|
||||
def _get_new_tokens(i):
|
||||
token_len = (media_grid_thw[i].prod() // (merge_size**2))
|
||||
return token_id * token_len
|
||||
|
||||
input_ids, labels, loss_scale = self._extend_tokens(input_ids, labels, loss_scale, idx_list,
|
||||
_get_new_tokens)
|
||||
|
||||
encoded['input_ids'] = input_ids
|
||||
encoded['labels'] = labels
|
||||
encoded['loss_scale'] = loss_scale
|
||||
encoded.update(media_inputs) # 将多模态内容加入其中
|
||||
return encoded
|
||||
|
||||
def _post_encode(self, model, inputs: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""该函数通常用于解决混合模型训练zero2/zero3卡住的问题,
|
||||
即有的进程为纯文本数据未过vit,有的进程含图片数据过了vit。这里将创建dummy_image来解决。
|
||||
|
||||
该函数将被注册在`model.forward`前的pre_forward_hook中。
|
||||
该函数需返回 含多模态信息的input_embeds。
|
||||
"""
|
||||
if not self.is_training:
|
||||
return inputs
|
||||
|
||||
input_ids = inputs['input_ids']
|
||||
input_features = inputs.get('input_features')
|
||||
feature_attention_mask = inputs.get('feature_attention_mask')
|
||||
|
||||
base_model = self.get_base_model(model)
|
||||
inputs_embeds = base_model.thinker.model.embed_tokens(input_ids)
|
||||
thinker_config = model.config.thinker_config
|
||||
# 辅助函数,用于处理text/image/video混合模态数据场景。(内部会创建dummy_image)
|
||||
inputs_embeds = self._get_inputs_embeds_hf(inputs_embeds, inputs, model.thinker.visual, self.processor,
|
||||
thinker_config)
|
||||
# 含audio的混合模态数据场景
|
||||
if input_features is None:
|
||||
if is_deepspeed_enabled() and not is_deepspeed_zero3_enabled():
|
||||
# 注意: 由于transformers实现中,经过audio部分模型层的次数与audio数量相关
|
||||
# 因此zero3在不同进程audios数不同场景下会卡住(需修改transformers代码修复)。此场景请使用zero2。
|
||||
input_features = input_ids.new_zeros([1, 128, 128], dtype=model.thinker.audio_tower.dtype)
|
||||
feature_attention_mask = input_ids.new_ones([1, 128], dtype=torch.bool)
|
||||
audio_res = model.thinker.get_audio_features(input_features, feature_attention_mask)
|
||||
# 兼容transformers 5.0
|
||||
if hasattr(audio_res, 'last_hidden_state'):
|
||||
audio_embeds = audio_res.last_hidden_state
|
||||
else:
|
||||
audio_embeds = audio_res
|
||||
inputs_embeds = inputs_embeds + audio_embeds.mean() * 0.
|
||||
else:
|
||||
audio_res = model.thinker.get_audio_features(input_features, feature_attention_mask)
|
||||
# 兼容transformers 5.0
|
||||
if hasattr(audio_res, 'last_hidden_state'):
|
||||
audio_embeds = audio_res.last_hidden_state
|
||||
else:
|
||||
audio_embeds = audio_res
|
||||
audio_mask = (input_ids == thinker_config.audio_token_index).unsqueeze(-1).expand_as(inputs_embeds)
|
||||
audio_embeds = audio_embeds.to(inputs_embeds.device, inputs_embeds.dtype)
|
||||
inputs_embeds = inputs_embeds.masked_scatter(audio_mask, audio_embeds)
|
||||
|
||||
return {'inputs_embeds': inputs_embeds}
|
||||
|
||||
def _get_position_ids(self, inputs: Dict[str, Any]):
|
||||
"""辅助函数,用来获取mrope的position_ids"""
|
||||
feature_attention_mask = inputs.get('feature_attention_mask')
|
||||
if feature_attention_mask is not None:
|
||||
audio_feature_lengths = torch.sum(feature_attention_mask, dim=1)
|
||||
else:
|
||||
audio_feature_lengths = None
|
||||
video_second_per_grid = inputs.pop('video_second_per_grid', None)
|
||||
input_ids = inputs['input_ids']
|
||||
attention_mask = inputs.get('attention_mask')
|
||||
if attention_mask is None:
|
||||
attention_mask = torch.ones_like(input_ids)
|
||||
position_ids, _ = self.model.thinker.get_rope_index(
|
||||
input_ids,
|
||||
inputs.get('image_grid_thw'),
|
||||
inputs.get('video_grid_thw'),
|
||||
attention_mask,
|
||||
self.use_audio_in_video,
|
||||
audio_feature_lengths,
|
||||
video_second_per_grid,
|
||||
)
|
||||
return self._concat_text_position_ids(position_ids) # 第一维为text_position_ids
|
||||
|
||||
def _data_collator(self, batch: List[Dict[str, Any]], *, padding_to: Optional[int] = None) -> Dict[str, Any]:
|
||||
"""传入dataloader的`collate_fn`"""
|
||||
res = super()._data_collator(batch, padding_to=padding_to)
|
||||
if not self.padding_free and self.is_training:
|
||||
# 其中padding_free/packing场景将会在packing_row中处理position_ids。
|
||||
res['position_ids'] = self._get_position_ids(res)
|
||||
if 'position_ids' in res:
|
||||
# 创建`packed_seq_params`以支持padding_free/packing & flash-attn
|
||||
position_ids = res['position_ids']
|
||||
res['position_ids'] = position_ids[1:]
|
||||
res['text_position_ids'] = text_position_ids = position_ids[0]
|
||||
# https://github.com/huggingface/transformers/pull/40194
|
||||
res.update(get_packed_seq_params(text_position_ids))
|
||||
return res
|
||||
|
||||
def _data_collator_mm_data(self, batch: List[Dict[str, Any]]) -> Dict[str, Any]:
|
||||
"""处理`_data_collator`函数中的多模态部分。(该函数兼容padding_free/packing)"""
|
||||
res = super()._data_collator_mm_data(batch)
|
||||
video_second_per_grid = self.gather_list(batch, 'video_second_per_grid')
|
||||
if video_second_per_grid:
|
||||
res['video_second_per_grid'] = video_second_per_grid
|
||||
input_features = [b['input_features'] for b in batch if b.get('input_features') is not None]
|
||||
feature_attention_mask = [
|
||||
b['feature_attention_mask'] for b in batch if b.get('feature_attention_mask') is not None
|
||||
]
|
||||
if input_features:
|
||||
res['input_features'] = torch.concat(input_features)
|
||||
res['feature_attention_mask'] = torch.concat(feature_attention_mask)
|
||||
return res
|
||||
|
||||
def generate(self, model, *args, **kwargs):
|
||||
"""`TransformersEngine`会调用template.generate方法进行文本生成,这里继承进行自定义。"""
|
||||
if kwargs.get('video_grid_thw') is not None:
|
||||
kwargs['use_audio_in_video'] = self.use_audio_in_video
|
||||
return super().generate(model, *args, **kwargs)
|
||||
|
||||
|
||||
register_template(
|
||||
TemplateMeta('my_qwen2_5_omni', prefix=[], prompt=['<|im_start|>user\n{{QUERY}}<|im_end|>\n<|im_start|>assistant\n'],
|
||||
chat_sep=['<|im_end|>\n'], suffix=['<|im_end|>'],
|
||||
system_prefix=['<|im_start|>system\n{{SYSTEM}}<|im_end|>\n'],
|
||||
default_system='You are a helpful assistant.', stop_words=['<|endoftext|>'],
|
||||
agent_template='hermes',
|
||||
template_cls=Qwen2_5OmniTemplate))
|
||||
|
||||
if __name__ == '__main__':
|
||||
# 测试与debug
|
||||
model, processor = get_model_processor('Qwen/Qwen2.5-Omni-7B', model_type='my_qwen2_5_omni')
|
||||
template = get_template(processor, template_type='my_qwen2_5_omni')
|
||||
data = {
|
||||
'messages': [
|
||||
{'role': 'user', 'content': '描述视频<video>与图片<image>内容。'},
|
||||
{'role': 'assistant', 'content': '一个小孩和一只猫咪。'},
|
||||
],
|
||||
'videos': ['https://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/baby.mp4'],
|
||||
'images': ['https://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/cat.png'],
|
||||
}
|
||||
template.set_mode('train')
|
||||
encoded = template.encode(data)
|
||||
print('input_ids: ' + template.safe_decode(encoded['input_ids']))
|
||||
print('labels: ' + template.safe_decode(encoded['labels']))
|
||||
print('keys: ' + str(encoded.keys()))
|
||||
```
|
||||
|
||||
|
||||
## 推理对齐
|
||||
接下来,你需要进行TransformersEngine与transformers的推理对齐。通常你需要对齐`input_ids`以及输出内容。你可以书写以下测试函数:
|
||||
|
||||
```python
|
||||
import os
|
||||
from transformers import Qwen2_5OmniForConditionalGeneration, Qwen2_5OmniProcessor
|
||||
from qwen_omni_utils import process_mm_info
|
||||
from modelscope import snapshot_download
|
||||
from swift.infer_engine import TransformersEngine, InferRequest, RequestConfig
|
||||
import requests
|
||||
|
||||
def infer_hf():
|
||||
model_dir = snapshot_download('Qwen/Qwen2.5-Omni-7B')
|
||||
model = Qwen2_5OmniForConditionalGeneration.from_pretrained(
|
||||
model_dir, torch_dtype="auto", device_map="auto", attn_implementation='flash_attention_2')
|
||||
processor = Qwen2_5OmniProcessor.from_pretrained(model_dir)
|
||||
# 使用decord读取视频(暂不支持url)
|
||||
resp = requests.get('https://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/baby.mp4')
|
||||
with open('_baby.mp4', 'wb') as f:
|
||||
f.write(resp.content)
|
||||
|
||||
conversation = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "video", "video": "_baby.mp4"},
|
||||
{"type": "image", "image": "http://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/cat.png"},
|
||||
{"type": "text", "text": "描述视频和图像。"},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
USE_AUDIO_IN_VIDEO = False
|
||||
text = processor.apply_chat_template(conversation, add_generation_prompt=True, tokenize=False)
|
||||
audios, images, videos = process_mm_info(conversation, use_audio_in_video=USE_AUDIO_IN_VIDEO)
|
||||
inputs = processor(text=text, audio=audios, images=images, videos=videos, return_tensors="pt", padding=True,
|
||||
use_audio_in_video=USE_AUDIO_IN_VIDEO)
|
||||
inputs = inputs.to(model.device).to(model.dtype)
|
||||
text_ids = model.generate(**inputs, use_audio_in_video=USE_AUDIO_IN_VIDEO, thinker_do_sample=False,
|
||||
return_audio=False)
|
||||
text = processor.batch_decode(text_ids[:, inputs['input_ids'].shape[1]:], skip_special_tokens=True, clean_up_tokenization_spaces=False)
|
||||
return inputs['input_ids'][0].tolist(), text[0]
|
||||
|
||||
def test_my_qwen2_5_omni():
|
||||
engine = TransformersEngine('Qwen/Qwen2.5-Omni-7B', model_type='my_qwen2_5_omni', attn_impl='flash_attention_2')
|
||||
infer_request = InferRequest(messages=[{
|
||||
"role": "user",
|
||||
"content": "<video><image>描述视频和图像。",
|
||||
}],
|
||||
videos=["https://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/baby.mp4"],
|
||||
images=["http://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/cat.png"],
|
||||
)
|
||||
request_config = RequestConfig(temperature=0, max_tokens=512)
|
||||
input_ids = engine.template.encode(infer_request)['input_ids']
|
||||
resp_list = engine.infer([infer_request], request_config)
|
||||
resp = resp_list[0].choices[0].message.content
|
||||
return input_ids, resp
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# 开启debug模式,会打印`TransformersEngine.infer`的input_ids和generate_ids
|
||||
os.environ['SWIFT_DEBUG'] = '1'
|
||||
input_ids_hf, response_hf = infer_hf()
|
||||
input_ids_swift, response_swift = test_my_qwen2_5_omni()
|
||||
# 测试input_ids和response对齐
|
||||
assert input_ids_hf == input_ids_swift
|
||||
assert response_hf == response_swift
|
||||
```
|
||||
|
||||
|
||||
## 开始训练
|
||||
|
||||
使用python代码训练,这通常更容易debug:
|
||||
```python
|
||||
from swift import sft_main, SftArguments
|
||||
import os
|
||||
if __name__ == '__main__':
|
||||
os.environ['MAX_PIXELS'] = '1003520'
|
||||
sft_main(SftArguments(
|
||||
model='Qwen/Qwen2.5-Omni-7B',
|
||||
dataset=['AI-ModelScope/LaTeX_OCR#5000'],
|
||||
model_type='my_qwen2_5_omni',
|
||||
template='my_qwen2_5_omni',
|
||||
load_from_cache_file=True,
|
||||
split_dataset_ratio=0.01,
|
||||
tuner_type='lora',
|
||||
torch_dtype='bfloat16',
|
||||
attn_impl='flash_attn',
|
||||
padding_free=True,
|
||||
num_train_epochs=1,
|
||||
per_device_train_batch_size=16,
|
||||
per_device_eval_batch_size=16,
|
||||
learning_rate=1e-4,
|
||||
lora_rank=8,
|
||||
lora_alpha=32,
|
||||
target_modules=['all-linear'],
|
||||
freeze_vit=True,
|
||||
freeze_aligner=True,
|
||||
gradient_accumulation_steps=1,
|
||||
eval_steps=50,
|
||||
save_steps=50,
|
||||
save_total_limit=2,
|
||||
logging_steps=5,
|
||||
max_length=2048,
|
||||
output_dir='output',
|
||||
warmup_ratio=0.05,
|
||||
dataloader_num_workers=4,
|
||||
dataset_num_proc=1,
|
||||
))
|
||||
```
|
||||
|
||||
使用命令行训练:
|
||||
```shell
|
||||
# 4 * 35GiB
|
||||
PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True' \
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3 \
|
||||
NPROC_PER_NODE=4 \
|
||||
VIDEO_MAX_PIXELS=50176 \
|
||||
FPS_MAX_FRAMES=12 \
|
||||
MAX_PIXELS=1003520 \
|
||||
swift sft \
|
||||
--model Qwen/Qwen2.5-Omni-7B \
|
||||
--model_type my_qwen2_5_omni \
|
||||
--template my_qwen2_5_omni \
|
||||
--external_plugins 'examples/custom/my_qwen2_5_omni/my_register.py' \
|
||||
--dataset 'AI-ModelScope/alpaca-gpt4-data-zh#2000' \
|
||||
'AI-ModelScope/LaTeX_OCR:human_handwrite#2000' \
|
||||
'speech_asr/speech_asr_aishell1_trainsets:validation#2000' \
|
||||
'swift/VideoChatGPT:all#2000' \
|
||||
--load_from_cache_file true \
|
||||
--split_dataset_ratio 0.01 \
|
||||
--tuner_type lora \
|
||||
--torch_dtype bfloat16 \
|
||||
--attn_impl flash_attn \
|
||||
--padding_free true \
|
||||
--packing true \
|
||||
--num_train_epochs 3 \
|
||||
--per_device_train_batch_size 1 \
|
||||
--per_device_eval_batch_size 1 \
|
||||
--learning_rate 1e-4 \
|
||||
--lora_rank 8 \
|
||||
--lora_alpha 32 \
|
||||
--target_modules all-linear \
|
||||
--freeze_vit true \
|
||||
--freeze_aligner true \
|
||||
--gradient_accumulation_steps 1 \
|
||||
--eval_steps 50 \
|
||||
--save_steps 50 \
|
||||
--save_total_limit 2 \
|
||||
--logging_steps 5 \
|
||||
--max_length 4096 \
|
||||
--output_dir output \
|
||||
--warmup_ratio 0.05 \
|
||||
--dataloader_num_workers 4 \
|
||||
--dataset_num_proc 1 \
|
||||
--deepspeed zero2
|
||||
```
|
||||
|
||||
训练后对验证集进行推理:(环境变量请与训练时对齐)
|
||||
```shell
|
||||
PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True' \
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
VIDEO_MAX_PIXELS=50176 \
|
||||
FPS_MAX_FRAMES=12 \
|
||||
MAX_PIXELS=1003520 \
|
||||
swift infer \
|
||||
--adapters output/vx-xxx/checkpoint-xxx \
|
||||
--stream true \
|
||||
--max_new_tokens 512 \
|
||||
--load_data_args true
|
||||
```
|
||||
|
||||
使用以下命令将训练权重推送到 Modelscope:
|
||||
```shell
|
||||
swift export \
|
||||
--adapters output/vx-xxx/checkpoint-xxx \
|
||||
--push_to_hub true \
|
||||
--hub_model_id '<your-model-id>' \
|
||||
--hub_token '<your-sdk-token>'
|
||||
```
|
||||
|
||||
## 提交PR
|
||||
|
||||
如果你想给ms-swift提交PR,你需要额外运行以下命令,对代码进行整理:
|
||||
|
||||
```shell
|
||||
pip install pre-commit
|
||||
pre-commit run --all-files
|
||||
```
|
||||
@@ -0,0 +1,280 @@
|
||||
# Metax支持
|
||||
|
||||
## 1. 在 Metax 平台上使用 Swift
|
||||
你可以选择构建自己的镜像,也可以直接拉取已有的预构建镜像。本文以拉取预构建镜像为例,演示如何在 Metax 上使用 ms-swift。
|
||||
### 1.1. 启动 ms-swift 容器
|
||||
```bash
|
||||
docker pull mx-devops-acr-cn-shanghai.cr.volces.com/opensource/public-ai-release/maca/ms-swift:3.10.3-maca.ai3.3.0.16-torch2.6-py310-ubuntu22.04-amd64
|
||||
# 你可以根据需要调整 --privileged 参数,并仅挂载特定的 GPU 卡。
|
||||
# 更多信息请参考我们的官方文档:https://developer.metax-tech.com
|
||||
# 必须通过 --device 挂载 Metax GPU 设备:--device=/dev/dri --device=/dev/mxcd
|
||||
docker run -it --net=host --uts=host --ipc=host --privileged=true --group-add video \
|
||||
--shm-size 100gb --ulimit memlock=-1 \
|
||||
--security-opt seccomp=unconfined --security-opt apparmor=unconfined \
|
||||
--device=/dev/dri --device=/dev/mxcd \
|
||||
-v /root/workspace:/external \
|
||||
--name swift_test \
|
||||
mx-devops-acr-cn-shanghai.cr.volces.com/opensource/public-ai-release/maca/ms-swift:3.10.3-maca.ai3.3.0.16-torch2.6-py310-ubuntu22.04-amd64
|
||||
```
|
||||
## 2. 环境检查
|
||||
### 2.1. 检查 Metax GPU 是否可用
|
||||
得益于与 CUDA 的兼容性,我们可以像使用 NVIDIA GPU 一样检查 Metax 设备是否可用:
|
||||
```python
|
||||
import torch
|
||||
print(torch.cuda.is_available())
|
||||
# True
|
||||
```
|
||||
### 2.2. 检查 GPU 之间的 P2P 连接拓扑
|
||||
```bash
|
||||
mx-smi topo -m
|
||||
# output
|
||||
=================== MetaX System Management Interface Log ===================
|
||||
Timestamp : Wed Feb 11 16:37:10 2026
|
||||
|
||||
Attached GPUs : 8
|
||||
Device link type matrix
|
||||
GPU0 GPU1 GPU2 GPU3 GPU4 GPU5 GPU6 GPU7 Node Affinity CPU Affinity
|
||||
GPU0 X MX MX MX NODE NODE NODE NODE 0 0-31,64-95
|
||||
GPU1 MX X MX MX NODE NODE NODE NODE 0 0-31,64-95
|
||||
GPU2 MX MX X MX NODE NODE NODE NODE 0 0-31,64-95
|
||||
GPU3 MX MX MX X NODE NODE NODE NODE 0 0-31,64-95
|
||||
GPU4 NODE NODE NODE NODE X MX MX MX 0 0-31,64-95
|
||||
GPU5 NODE NODE NODE NODE MX X MX MX 0 0-31,64-95
|
||||
GPU6 NODE NODE NODE NODE MX MX X MX 0 0-31,64-95
|
||||
GPU7 NODE NODE NODE NODE MX MX MX X 0 0-31,64-95
|
||||
|
||||
Legend:
|
||||
X = Self
|
||||
SYS = Connection traversing PCIe as well as the SMP interconnect between NUMA nodes (e.g., QPI/UPI)
|
||||
NODE = Connection traversing PCIe as well as the interconnect between PCIe Host Bridges within a NUMA node
|
||||
PHB = Connection traversing PCIe as well as a PCIe Host Bridge (typically the CPU)
|
||||
PXB = Connection traversing multiple PCIe bridges (without traversing the PCIe Host Bridge)
|
||||
PIX = Connection traversing at most a single PCIe bridge
|
||||
MX = Connection traversing MetaXLink
|
||||
ETH = Connection traversing Eth
|
||||
NA = Connection type is unknown
|
||||
```
|
||||
### 2.3. 查看 GPU 状态
|
||||
```bash
|
||||
mx-smi
|
||||
# output
|
||||
=================== MetaX System Management Interface Log ===================
|
||||
Timestamp : Wed Feb 11 09:55:49 2026
|
||||
|
||||
Attached GPUs : 8
|
||||
+---------------------------------------------------------------------------------+
|
||||
| MX-SMI 2.2.9 Kernel Mode Driver Version: 3.4.4 |
|
||||
| MACA Version: 3.3.0.15 BIOS Version: 1.30.0.0 |
|
||||
|------------------+-----------------+---------------------+----------------------|
|
||||
| Board Name | GPU Persist-M | Bus-id | GPU-Util sGPU-M |
|
||||
| Pwr:Usage/Cap | Temp Perf | Memory-Usage | GPU-State |
|
||||
|==================+=================+=====================+======================|
|
||||
| 0 MetaX C500 | 0 Off | 0000:0e:00.0 | 0% Disabled |
|
||||
| 57W / 350W | 35C P0 | 826/65536 MiB | Available |
|
||||
+------------------+-----------------+---------------------+----------------------+
|
||||
| 1 MetaX C500 | 1 Off | 0000:0f:00.0 | 0% Disabled |
|
||||
| 58W / 350W | 37C P0 | 826/65536 MiB | Available |
|
||||
+------------------+-----------------+---------------------+----------------------+
|
||||
| 2 MetaX C500 | 2 Off | 0000:10:00.0 | 0% Disabled |
|
||||
| 58W / 350W | 36C P0 | 826/65536 MiB | Available |
|
||||
+------------------+-----------------+---------------------+----------------------+
|
||||
| 3 MetaX C500 | 3 Off | 0000:12:00.0 | 0% Disabled |
|
||||
| 60W / 350W | 35C P0 | 826/65536 MiB | Available |
|
||||
+------------------+-----------------+---------------------+----------------------+
|
||||
| 4 MetaX C500 | 4 Off | 0000:35:00.0 | 0% Disabled |
|
||||
| 57W / 350W | 33C P0 | 826/65536 MiB | Available |
|
||||
+------------------+-----------------+---------------------+----------------------+
|
||||
| 5 MetaX C500 | 5 Off | 0000:36:00.0 | 0% Disabled |
|
||||
| 56W / 350W | 34C P0 | 826/65536 MiB | Available |
|
||||
+------------------+-----------------+---------------------+----------------------+
|
||||
| 6 MetaX C500 | 6 Off | 0000:37:00.0 | 0% Disabled |
|
||||
| 55W / 350W | 34C P0 | 826/65536 MiB | Available |
|
||||
+------------------+-----------------+---------------------+----------------------+
|
||||
| 7 MetaX C500 | 7 Off | 0000:38:00.0 | 0% Disabled |
|
||||
| 56W / 350W | 36C P0 | 826/65536 MiB | Available |
|
||||
+------------------+-----------------+---------------------+----------------------+
|
||||
|
||||
+---------------------------------------------------------------------------------+
|
||||
| Process: |
|
||||
| GPU PID Process Name GPU Memory |
|
||||
| Usage(MiB) |
|
||||
|=================================================================================|
|
||||
| no process found |
|
||||
+---------------------------------------------------------------------------------+
|
||||
```
|
||||
|
||||
## 3. 运行示例
|
||||
我们支持直接使用社区版 Swift,同时在镜像中 /workspace 目录下提供了经过更多优化的版本。强烈建议优先使用该目录下的软件包。
|
||||
|
||||
### 3.1. 运行 Swift 示例
|
||||
在大多数场景下,可直接运行 Swift 的训练示例:
|
||||
```bash
|
||||
# We assume that the ms-swift code is under /workspace
|
||||
cd /workspace/ms-swift/
|
||||
bash examples/train/full/train.sh
|
||||
|
||||
```
|
||||
运行输出示例(节选):
|
||||
```bash
|
||||
# output:
|
||||
{'loss': 1.47077751, 'grad_norm': 10.5625, 'learning_rate': 2e-06, 'token_acc': 0.65511727, 'epoch': 0.01, 'global_step/max_steps': '1/94', 'percentage': '1.06%', 'elapsed_time': '2s', 'remaining_time': '4m 28s', 'memory(GiB)': 4.87, 'train_speed(iter/s)': 0.345807}
|
||||
{'loss': 1.58882141, 'grad_norm': 10.75, 'learning_rate': 1e-05, 'token_acc': 0.61763144, 'epoch': 0.05, 'global_step/max_steps': '5/94', 'percentage': '5.32%', 'elapsed_time': '10s', 'remaining_time': '3m 12s', 'memory(GiB)': 5.64, 'train_speed(iter/s)': 0.461462}
|
||||
{'loss': 1.56617603, 'grad_norm': 12.8125, 'learning_rate': 9.92e-06, 'token_acc': 0.61519274, 'epoch': 0.11, 'global_step/max_steps': '10/94', 'percentage': '10.64%', 'elapsed_time': '20s', 'remaining_time': '2m 52s', 'memory(GiB)': 5.64, 'train_speed(iter/s)': 0.485796}
|
||||
{'loss': 1.63347206, 'grad_norm': 13.6875, 'learning_rate': 9.69e-06, 'token_acc': 0.60373975, 'epoch': 0.16, 'global_step/max_steps': '15/94', 'percentage': '15.96%', 'elapsed_time': '30s', 'remaining_time': '2m 39s', 'memory(GiB)': 6.5, 'train_speed(iter/s)': 0.493855}
|
||||
{'loss': 1.60613976, 'grad_norm': 11.0, 'learning_rate': 9.32e-06, 'token_acc': 0.59997221, 'epoch': 0.21, 'global_step/max_steps': '20/94', 'percentage': '21.28%', 'elapsed_time': '39s', 'remaining_time': '2m 27s', 'memory(GiB)': 6.5, 'train_speed(iter/s)': 0.500516}
|
||||
{'loss': 1.45015478, 'grad_norm': 15.25, 'learning_rate': 8.8e-06, 'token_acc': 0.62373584, 'epoch': 0.27, 'global_step/max_steps': '25/94', 'percentage': '26.60%', 'elapsed_time': '49s', 'remaining_time': '2m 16s', 'memory(GiB)': 6.5, 'train_speed(iter/s)': 0.50548}
|
||||
{'loss': 1.39427547, 'grad_norm': 13.9375, 'learning_rate': 8.18e-06, 'token_acc': 0.6357994, 'epoch': 0.32, 'global_step/max_steps': '30/94', 'percentage': '31.91%', 'elapsed_time': '59s', 'remaining_time': '2m 5s', 'memory(GiB)': 6.5, 'train_speed(iter/s)': 0.508409}
|
||||
{'loss': 1.53672237, 'grad_norm': 11.125, 'learning_rate': 7.45e-06, 'token_acc': 0.61650612, 'epoch': 0.37, 'global_step/max_steps': '35/94', 'percentage': '37.23%', 'elapsed_time': '1m 8s', 'remaining_time': '1m 55s', 'memory(GiB)': 6.5, 'train_speed(iter/s)': 0.510425}
|
||||
{'loss': 1.54039021, 'grad_norm': 13.8125, 'learning_rate': 6.65e-06, 'token_acc': 0.61613974, 'epoch': 0.43, 'global_step/max_steps': '40/94', 'percentage': '42.55%', 'elapsed_time': '1m 18s', 'remaining_time': '1m 45s', 'memory(GiB)': 6.5, 'train_speed(iter/s)': 0.512302}
|
||||
{'loss': 1.40159426, 'grad_norm': 9.4375, 'learning_rate': 5.79e-06, 'token_acc': 0.64041773, 'epoch': 0.48, 'global_step/max_steps': '45/94', 'percentage': '47.87%', 'elapsed_time': '1m 27s', 'remaining_time': '1m 35s', 'memory(GiB)': 6.5, 'train_speed(iter/s)': 0.512983}
|
||||
{'loss': 1.54977188, 'grad_norm': 11.9375, 'learning_rate': 4.91e-06, 'token_acc': 0.61078816, 'epoch': 0.53, 'global_step/max_steps': '50/94', 'percentage': '53.19%', 'elapsed_time': '1m 37s', 'remaining_time': '1m 25s', 'memory(GiB)': 6.5, 'train_speed(iter/s)': 0.514489}
|
||||
{'loss': 1.6754509, 'grad_norm': 13.0625, 'learning_rate': 4.04e-06, 'token_acc': 0.58574393, 'epoch': 0.59, 'global_step/max_steps': '55/94', 'percentage': '58.51%', 'elapsed_time': '1m 46s', 'remaining_time': '1m 15s', 'memory(GiB)': 6.5, 'train_speed(iter/s)': 0.515752}
|
||||
{'loss': 1.37204351, 'grad_norm': 9.25, 'learning_rate': 3.19e-06, 'token_acc': 0.6391937, 'epoch': 0.64, 'global_step/max_steps': '60/94', 'percentage': '63.83%', 'elapsed_time': '1m 56s', 'remaining_time': '1m 5s', 'memory(GiB)': 6.5, 'train_speed(iter/s)': 0.516829}
|
||||
{'loss': 1.47697926, 'grad_norm': 11.375, 'learning_rate': 2.4e-06, 'token_acc': 0.62817259, 'epoch': 0.69, 'global_step/max_steps': '65/94', 'percentage': '69.15%', 'elapsed_time': '2m 5s', 'remaining_time': '55s', 'memory(GiB)': 6.5, 'train_speed(iter/s)': 0.517947}
|
||||
{'loss': 1.4336628, 'grad_norm': 8.125, 'learning_rate': 1.69e-06, 'token_acc': 0.63453862, 'epoch': 0.75, 'global_step/max_steps': '70/94', 'percentage': '74.47%', 'elapsed_time': '2m 14s', 'remaining_time': '46s', 'memory(GiB)': 6.5, 'train_speed(iter/s)': 0.518833}
|
||||
{'loss': 1.54315252, 'grad_norm': 9.625, 'learning_rate': 1.08e-06, 'token_acc': 0.60202073, 'epoch': 0.8, 'global_step/max_steps': '75/94', 'percentage': '79.79%', 'elapsed_time': '2m 24s', 'remaining_time': '36s', 'memory(GiB)': 6.5, 'train_speed(iter/s)': 0.519627}
|
||||
{'loss': 1.47180223, 'grad_norm': 9.5625, 'learning_rate': 6e-07, 'token_acc': 0.62211501, 'epoch': 0.85, 'global_step/max_steps': '80/94', 'percentage': '85.11%', 'elapsed_time': '2m 33s', 'remaining_time': '26s', 'memory(GiB)': 6.5, 'train_speed(iter/s)': 0.520284}
|
||||
{'loss': 1.44068375, 'grad_norm': 10.125, 'learning_rate': 2.5e-07, 'token_acc': 0.62673112, 'epoch': 0.91, 'global_step/max_steps': '85/94', 'percentage': '90.43%', 'elapsed_time': '2m 43s', 'remaining_time': '17s', 'memory(GiB)': 6.5, 'train_speed(iter/s)': 0.520331}
|
||||
{'loss': 1.44893646, 'grad_norm': 8.375, 'learning_rate': 5e-08, 'token_acc': 0.63837478, 'epoch': 0.96, 'global_step/max_steps': '90/94', 'percentage': '95.74%', 'elapsed_time': '2m 52s', 'remaining_time': '7s', 'memory(GiB)': 6.5, 'train_speed(iter/s)': 0.520707}
|
||||
{'train_runtime': 183.4332, 'train_samples_per_second': 8.177, 'train_steps_per_second': 0.512, 'train_loss': 1.50650934, 'token_acc': 0.6194337, 'epoch': 1.0, 'global_step/max_steps': '94/94', 'percentage': '100.00%', 'elapsed_time': '3m 3s', 'remaining_time': '0s', 'memory(GiB)': 6.5, 'train_speed(iter/s)': 0.512463}
|
||||
Train: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 94/94 [03:03<00:00, 1.95s/it]
|
||||
[INFO:swift] last_model_checkpoint: /workspace/ms-swift/output/v0-20260211-143035/checkpoint-94
|
||||
[INFO:swift] best_model_checkpoint: None
|
||||
[INFO:swift] images_dir: /workspace/ms-swift/output/v0-20260211-143035/images
|
||||
[INFO:swift] End time of running main: 2026-02-11 14:34:09.521336
|
||||
|
||||
```
|
||||
### 3.2. 使用 Megatron-LM 作为 Swift 后端
|
||||
若希望使用 Megatron-LM 作为 Swift 的后端,需设置 `MEGATRON_LM_PATH` 环境变量:
|
||||
|
||||
```bash
|
||||
export MEGATRON_LM_PATH=/workspace/Megatron-LM-0.15.0
|
||||
cd /workspace/ms-swift
|
||||
bash examples/megatron/pretrain.sh
|
||||
```
|
||||
|
||||
### 3.3. 使用其他版本的 ms-swift
|
||||
Metax 平台要求使用与 Maca 兼容的软件包。例如,编译可能依赖 torch2.8,因此需使用 torch2.8+maca3.3.x.x 版本。
|
||||
|
||||
默认情况下,安装会覆盖环境中已有的 PyTorch。因此,建议使用 --no-deps 参数进行安装:
|
||||
```bash
|
||||
|
||||
git clone -b ${SWIFT_VERSION} https://github.com/modelscope/ms-swift.git
|
||||
cd ms-swift
|
||||
pip install . --no-deps
|
||||
|
||||
```
|
||||
每次环境变更后,请检查 PyTorch 版本及其可用性:
|
||||
```bash
|
||||
pip list |grep torch
|
||||
# output:
|
||||
# torch2.x.x+metax3.x.x.x
|
||||
```
|
||||
|
||||
```python
|
||||
import torch
|
||||
torch.cuda.is_available()
|
||||
```
|
||||
|
||||
### 3.4. Metax 与 NVIDIA CUDA 的差异
|
||||
Metax 在大部分接口上与 NVIDIA 对齐,但在某些软件行为和环境变量上存在差异。
|
||||
|
||||
#### 3.4.1. MACA_MPS_MODE
|
||||
默认情况下,MACA 不允许多个进程共享同一块 GPU。如果 GPU 已被占用,则无法启动新进程。
|
||||
|
||||
如需启用类似 MPS(Multi-Process Service)的功能,需设置:`MACA_MPS_MODE=1`
|
||||
```bash
|
||||
# 运行其他脚本...
|
||||
export MACA_MPS_MODE=1
|
||||
cd /workspace/ms-swift/
|
||||
bash examples/train/full/train.sh
|
||||
```
|
||||
#### 3.4.2. MCCL_SOCKET_IFNAME GLOO_SOCKET_IFNAME & MCCL_IB_HCA
|
||||
在多节点训练时,建议设置以下环境变量以确保节点间通信正常:
|
||||
> MCCL_SOCKET_IFNAME:用于 MCCL 通信的网络接口
|
||||
> GLOO_SOCKET_IFNAME:用于 GLOO 通信的网络接口
|
||||
> MCCL_IB_HCA:指定使用的 InfiniBand 设备
|
||||
|
||||
可通过 ifconfig 和 mx-smi 确定所用网卡和 IB 设备:
|
||||
```bash
|
||||
ifconfig
|
||||
# output
|
||||
ens20f0np0: xxx
|
||||
inet: your node ip
|
||||
xxx
|
||||
...
|
||||
```
|
||||
```bash
|
||||
mx-smi topo -n
|
||||
# output
|
||||
mx-smi version: 2.2.9
|
||||
|
||||
=================== MetaX System Management Interface Log ===================
|
||||
Timestamp : Wed Feb 11 18:53:44 2026
|
||||
|
||||
Attached GPUs : 8
|
||||
Device link type matrix
|
||||
GPU0 GPU1 GPU2 GPU3 GPU4 GPU5 GPU6 GPU7 NIC0 NIC1 NIC2 NIC3 NIC4 NIC5 Node Affinity CPU Affinity
|
||||
GPU0 X MX MX MX NODE NODE NODE NODE PIX PIX NODE NODE SYS SYS 0 0-31,64-95
|
||||
GPU1 MX X MX MX NODE NODE NODE NODE PIX PIX NODE NODE SYS SYS 0 0-31,64-95
|
||||
GPU2 MX MX X MX NODE NODE NODE NODE PIX PIX NODE NODE SYS SYS 0 0-31,64-95
|
||||
GPU3 MX MX MX X NODE NODE NODE NODE PIX PIX NODE NODE SYS SYS 0 0-31,64-95
|
||||
GPU4 NODE NODE NODE NODE X MX MX MX NODE NODE PIX PIX SYS SYS 0 0-31,64-95
|
||||
GPU5 NODE NODE NODE NODE MX X MX MX NODE NODE PIX PIX SYS SYS 0 0-31,64-95
|
||||
GPU6 NODE NODE NODE NODE MX MX X MX NODE NODE PIX PIX SYS SYS 0 0-31,64-95
|
||||
GPU7 NODE NODE NODE NODE MX MX MX X NODE NODE PIX PIX SYS SYS 0 0-31,64-95
|
||||
NIC0 PIX PIX PIX PIX NODE NODE NODE NODE X PIX NODE NODE SYS SYS
|
||||
NIC1 PIX PIX PIX PIX NODE NODE NODE NODE PIX X NODE NODE SYS SYS
|
||||
NIC2 NODE NODE NODE NODE PIX PIX PIX PIX NODE NODE X PIX SYS SYS
|
||||
NIC3 NODE NODE NODE NODE PIX PIX PIX PIX NODE NODE PIX X SYS SYS
|
||||
NIC4 SYS SYS SYS SYS SYS SYS SYS SYS SYS SYS SYS SYS X PIX
|
||||
NIC5 SYS SYS SYS SYS SYS SYS SYS SYS SYS SYS SYS SYS PIX X
|
||||
|
||||
Legend:
|
||||
X = Self
|
||||
SYS = Connection traversing PCIe as well as the SMP interconnect between NUMA nodes (e.g., QPI/UPI)
|
||||
NODE = Connection traversing PCIe as well as the interconnect between PCIe Host Bridges within a NUMA node
|
||||
PHB = Connection traversing PCIe as well as a PCIe Host Bridge (typically the CPU)
|
||||
PXB = Connection traversing multiple PCIe bridges (without traversing the PCIe Host Bridge)
|
||||
PIX = Connection traversing at most a single PCIe bridge
|
||||
MX = Connection traversing MetaXLink
|
||||
ETH = Connection traversing Eth
|
||||
NA = Connection type is unknown
|
||||
|
||||
NIC Legend:
|
||||
|
||||
NIC0: mlx5_0
|
||||
NIC1: mlx5_1
|
||||
NIC2: mlx5_2
|
||||
NIC3: mlx5_3
|
||||
NIC4: mlx5_4
|
||||
NIC5: mlx5_5
|
||||
# 根据拓扑信息可知:
|
||||
# 1. GPU0–GPU3 与 NIC0/NIC1(即 mlx5_0, mlx5_1)通信
|
||||
# 2. GPU4–GPU7 与 NIC2/NIC3(即 mlx5_2, mlx5_3)通信
|
||||
|
||||
|
||||
```
|
||||
因此,推荐设置如下:
|
||||
`MCCL_SOCKET_IFNAME=ens20f0np0`
|
||||
`GLOO_SOCKET_IFNAME=ens20f0np0`
|
||||
`MCCL_IB_HCA=mlx5_0,mlx5_1,mlx5_2,mlx5_3`
|
||||
|
||||
```bash
|
||||
# node 1
|
||||
export MCCL_SOCKET_IFNAME=ens20f0np0
|
||||
export GLOO_SOCKET_IFNAME=ens20f0np0
|
||||
export MCCL_IB_HCA=mlx5_0,mlx5_1,mlx5_2,mlx5_3
|
||||
cd /workspace/ms-swift/
|
||||
bash examples/train/multi-node/torchrun/train_node1.sh
|
||||
```
|
||||
|
||||
```bash
|
||||
# node 2
|
||||
# 需修改脚本中的 master_addr 为节点1的IP
|
||||
export MCCL_SOCKET_IFNAME=ens20f0np0
|
||||
export GLOO_SOCKET_IFNAME=ens20f0np0
|
||||
export MCCL_IB_HCA=mlx5_0,mlx5_1,mlx5_2,mlx5_3
|
||||
cd /workspace/ms-swift/
|
||||
bash examples/train/multi-node/torchrun/train_node2.sh
|
||||
```
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
# 更多最佳实践
|
||||
|
||||
- [Qwen2.5自我认知微调](https://github.com/modelscope/ms-swift/tree/main/examples/notebook/qwen2_5-self-cognition)
|
||||
- [Qwen2-VL Latex-OCR微调](https://github.com/modelscope/ms-swift/tree/main/examples/notebook/qwen2vl-ocr)
|
||||
- [Qwen2.5-VL Grounding任务微调](https://github.com/modelscope/ms-swift/tree/main/examples/notebook/qwen2_5-vl-grounding)
|
||||
@@ -0,0 +1,849 @@
|
||||
# NPU支持
|
||||
|
||||
我们在 ms-swift 上增加了对昇腾 NPU 的支持,用户可以在昇腾 NPU 上进行模型的微调和推理。
|
||||
|
||||
本文档介绍如何在昇腾 NPU 上完成环境准备、模型训练、保存合并、推理、部署和常见问题排查。
|
||||
|
||||
如果你是第一次在 NPU 上使用 ms-swift,推荐按以下顺序阅读:
|
||||
|
||||
1. 先查看“支持范围速览”,确认模型、算法和后端是否已验证。
|
||||
2. 根据“选择你的使用路线”决定只装基础环境,还是额外安装 MindSpeed/Megatron-SWIFT。
|
||||
3. 根据自己的环境管理习惯选择“本地环境安装”或“镜像/容器环境安装”,然后执行“NPU 可用性检查”。
|
||||
4. 使用“快速跑通”完成一次 ModelScope 模型 LoRA 训练、合并、推理和部署。
|
||||
5. 需要更大规模训练时,再阅读 DDP、DeepSpeed 和 MindSpeed/Megatron-SWIFT 相关章节。
|
||||
|
||||
## 硬件配套和支持的操作系统
|
||||
|
||||
**表 1** 产品硬件支持列表
|
||||
|
||||
|产品|是否支持|
|
||||
|--|:-:|
|
||||
|<term>Ascend 950 系列产品</term>|√|
|
||||
|<term>Atlas A3 训练系列产品</term>|√|
|
||||
|<term>Atlas A3 推理系列产品</term>|x|
|
||||
|<term>Atlas A2 训练系列产品</term>|√|
|
||||
|<term>Atlas A2 推理系列产品</term>|x|
|
||||
|<term>Atlas 200I/500 A2 推理产品</term>|x|
|
||||
|<term>Atlas 推理系列产品</term>|x|
|
||||
|<term>Atlas 训练系列产品</term>|x|
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> 本节表格中“√”代表支持,“x”代表不支持。
|
||||
|
||||
- 各硬件产品对应物理机部署场景支持的操作系统请参考[兼容性查询助手](https://www.hiascend.com/hardware/compatibility)。
|
||||
- 各硬件产品对应虚拟机及容器部署场景支持的操作系统请参考《CANN 软件安装》的“[操作系统兼容性说明](https://www.hiascend.com/document/detail/zh/canncommercial/900/softwareinst/instg/instg_0101.html?OS=openEuler&InstallType=netyum)”章节(商用版)或“[操作系统兼容性说明](https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/900/softwareinst/instg/instg_0101.html?OS=openEuler&InstallType=netyum)”章节(社区版)。
|
||||
|
||||
## 支持范围速览
|
||||
|
||||
推荐基础环境版本:
|
||||
|
||||
| software | version |
|
||||
| --------- | --------------- |
|
||||
| Python | >= 3.10, < 3.12 |
|
||||
| CANN | >= 8.5.1 |
|
||||
| torch | >= 2.7.1 |
|
||||
| torch_npu | >= 2.7.1.post4 |
|
||||
|
||||
基础环境准备请参照 [Ascend PyTorch 安装文档](https://gitcode.com/Ascend/pytorch)。本文示例实验环境为 8 * 昇腾910B3 64G。
|
||||
注:vllm ascend系列官方推荐版本配套已更新至 CANN9.0.0 torch 2.9.0 torch_npu 2.9.0 vllm-ascend 0.18.0(A3) 0.19.1(A5),详情请参阅 [vLLM Ascend 安装文档](https://docs.vllm.ai/projects/ascend/en/v0.18.0/installation.html)。
|
||||
|
||||
| 一级特性 | 特性 | 进展 |
|
||||
| -------- | ------------------- | -------- |
|
||||
| 训练范式 | CPT | 已支持 |
|
||||
| | SFT | 已支持 |
|
||||
| | DPO | 已支持 |
|
||||
| | RM | 已支持 |
|
||||
| 分布式 | DDP | 已支持 |
|
||||
| | FSDP | 已支持 |
|
||||
| | FSDP2 | 已支持 |
|
||||
| | DeepSpeed | 已支持 |
|
||||
| | MindSpeed(Megatron) | 已支持 |
|
||||
| 低参微调 | FULL | 已支持 |
|
||||
| | LoRA | 已支持 |
|
||||
| | QLoRA | 暂不支持 |
|
||||
| RLHF | GRPO | 已支持 |
|
||||
| | PPO | 已支持 |
|
||||
| 性能优化 | FA 等融合算子 | 已支持 |
|
||||
| | Liger-Kernel | 暂不支持 |
|
||||
| 部署 | PT | 已支持 |
|
||||
| | vLLM | 已支持 |
|
||||
| | SGLang | 暂不支持 |
|
||||
|
||||
### 已验证 SFT 组合
|
||||
|
||||
| algorithm | model families | strategy | hardware |
|
||||
| --------- | --------------------------- | --------------------- | ----------------- |
|
||||
| SFT | Qwen2.5-0.5B-Instruct | FSDP1/FSDP2/deepspeed | Atlas 900 A2 PODc |
|
||||
| SFT | Qwen2.5-1.5B-Instruct | FSDP1/FSDP2/deepspeed | Atlas 900 A2 PODc |
|
||||
| SFT | Qwen2.5-7B-Instruct | FSDP1/FSDP2/deepspeed | Atlas 900 A2 PODc |
|
||||
| SFT | Qwen2.5-VL-3B-Instruct | FSDP1/FSDP2/deepspeed | Atlas 900 A2 PODc |
|
||||
| SFT | Qwen2.5-VL-7B-Instruct | FSDP1/FSDP2/deepspeed | Atlas 900 A2 PODc |
|
||||
| SFT | Qwen2.5-Omni-3B | FSDP1/FSDP2/deepspeed | Atlas 900 A2 PODc |
|
||||
| SFT | Qwen3-8B | FSDP1/FSDP2/deepspeed | Atlas 900 A2 PODc |
|
||||
| SFT | Qwen3-30B-A3B | FSDP1/FSDP2/deepspeed | Atlas 900 A2 PODc |
|
||||
| SFT | Qwen3-32B | FSDP1/FSDP2/deepspeed | Atlas 900 A2 PODc |
|
||||
| SFT | Qwen3-VL-30B-A3B-Instruct | FSDP1/FSDP2/deepspeed | Atlas 900 A2 PODc |
|
||||
| SFT | Qwen3-Omni-30B-A3B-Instruct | FSDP1/FSDP2/deepspeed/Megatron | Atlas 900 A2 PODc/A3 SuperPoD |
|
||||
| SFT | InternVL3-8B | FSDP1/FSDP2/deepspeed | Atlas 900 A2 PODc |
|
||||
| SFT | Ovis2.5-2B | FSDP1/FSDP2/deepspeed | Atlas 900 A2 PODc |
|
||||
| SFT | Qwen3.5-27B | FSDP1/FSDP2/deepspeed/Megatron | Atlas 900 A2 PODc/A3 SuperPoD |
|
||||
| SFT | Qwen3.5-35B-A3B | FSDP1/FSDP2/deepspeed/Megatron | Atlas 900 A2 PODc/A3 SuperPoD |
|
||||
|
||||
### 已验证 RL 组合
|
||||
|
||||
| algorithm | model families | strategy | rollout engine | hardware |
|
||||
| --------- | ------------------- | --------- | -------------- | ----------------- |
|
||||
| **GRPO** | Qwen2.5-7B-Instruct | deepspeed | vllm-ascend | Atlas 900 A2 PODc |
|
||||
| **GRPO** | Qwen3-8B | deepspeed | vllm-ascend | Atlas 900 A2 PODc |
|
||||
| **DPO** | Qwen2.5-7B-Instruct | deepspeed | vllm-ascend | Atlas 900 A2 PODc |
|
||||
| **DPO** | Qwen3-8B | deepspeed | vllm-ascend | Atlas 900 A2 PODc |
|
||||
| **PPO** | Qwen2.5-7B-Instruct | deepspeed | vllm-ascend | Atlas 900 A2 PODc |
|
||||
| **PPO** | Qwen3-8B | deepspeed | vllm-ascend | Atlas 900 A2 PODc |
|
||||
|
||||
### 暂不支持或未完全验证
|
||||
|
||||
| item |
|
||||
| --------------------------------- |
|
||||
| Liger-kernel |
|
||||
| 量化/QLoRA相关 |
|
||||
| 使用sglang作为推理引擎 |
|
||||
| 使用megatron时开启ETP进行lora训练 |
|
||||
|
||||
### PEFT Transformers 5 MoE fused expert LoRA 限制
|
||||
|
||||
在使用 Qwen3.5-MoE、Qwen3-Omni-MoE 等 Transformers 5 MoE 结构模型进行 LoRA 训练时,部分 expert 权重可能不是普通 `nn.Linear` 模块,而是 fused `nn.Parameter`。这类参数需要依赖 PEFT 的 `target_parameters` 路径注入 LoRA。
|
||||
|
||||
当前该路径在 `lora_dropout`、ZeRO-3/FSDP、多 adapter 等组合场景下仍未完全稳定。典型触发条件包括:
|
||||
|
||||
- 使用 MoE 模型;
|
||||
- 使用 LoRA,并希望覆盖 fused expert 参数;
|
||||
- 模型配置或命令行 `--model_type` 触发 PEFT 的 Transformers 5 MoE target conversion 路径;
|
||||
- 使用默认 `lora_dropout != 0`,或使用 ZeRO-3/FSDP 等参数分片后端。
|
||||
|
||||
如果只是进行常规 Qwen3.5 GRPO/SFT LoRA 训练,建议避免额外指定 `--model_type` 去扩大触发范围;若模型配置本身已经触发该路径,则优先使用 full 参数训练或关闭对应 LoRA 组合。若确实需要训练 fused expert 参数,建议等待 PEFT 上游能力稳定,或在 `lora_dropout=0` 且目标模型、训练后端已单独验证的前提下使用。
|
||||
|
||||
## 选择你的使用路线
|
||||
|
||||
| 场景 | 推荐路线 | 是否需要 MindSpeed |
|
||||
| ---------------------------- | --------------------------------------------- | ------------------ |
|
||||
| 只做普通 SFT/LoRA/推理 | 本地环境安装或镜像/容器环境安装 | 不需要 |
|
||||
| 需要 Megatron-SWIFT 大模型训练 | 先装基础环境,再装 MindSpeed/Megatron/mcore-bridge | 需要 |
|
||||
| 需要 GRPO/PPO/DPO 等 RLHF | 基础训练环境 + vLLM-Ascend rollout/deploy | 通常不需要 |
|
||||
| 只是验证 NPU 是否可用 | 跑 NPU 可用性检查脚本 | 不需要 |
|
||||
|
||||
## 环境准备
|
||||
|
||||
### 镜像/容器环境安装
|
||||
官方 NPU 镜像已发布在 [quay.io/ascend/ms-swift](https://quay.io/repository/ascend/ms-swift?tab=tags)。推荐优先根据设备代际、Python、CANN 和系统版本选择匹配的镜像标签;如需锁定分支或定制依赖,再使用项目提供的 Dockerfile 自行构建。容器方式的优势是依赖版本更容易固化,也便于在多台昇腾机器之间复现实验环境。
|
||||
|
||||
下面以 A2、Python 3.11、CANN 9.0.0、Ubuntu 22.04 标签为例,实际使用时请以 Quay 标签页中适配当前机器和软件栈的最新标签为准:
|
||||
|
||||
```shell
|
||||
docker pull quay.io/ascend/ms-swift:v4.3.0-A2-py311-CANN9.0.0-ubuntu22.04
|
||||
export IMAGE_NAME=quay.io/ascend/ms-swift:v4.3.0-A2-py311-CANN9.0.0-ubuntu22.04
|
||||
export WORKSPACE=/path/to/workspace
|
||||
```
|
||||
|
||||
如果需要自行构建镜像,先 clone modelscope 仓库,然后使用仓库中的 [Dockerfile.ascend](https://github.com/modelscope/modelscope/blob/master/docker/Dockerfile.ascend) 和 [build_image.py](https://github.com/modelscope/modelscope/blob/master/docker/build_image.py):
|
||||
|
||||
```shell
|
||||
git clone https://github.com/modelscope/modelscope.git
|
||||
cd modelscope
|
||||
DOCKER_REGISTRY=ms-swift python docker/build_image.py \
|
||||
--image_type ascend \
|
||||
--python_version 3.11.11 \
|
||||
--soc_version ascend910b1 \
|
||||
--arch arm
|
||||
```
|
||||
|
||||
当前 `build_image.py` 生成的 Ascend 镜像名格式为 `{DOCKER_REGISTRY}:{swift_branch}-{atlas_hardware}-{python_tag}-{arch}`。以上命令以 ARM 架构的 Atlas 900 A2 PODc 为例,通常会生成 `ms-swift:main-A2-py311-arm`。如果使用自行构建的镜像,请按构建日志中的镜像名替换上面的 `IMAGE_NAME`:
|
||||
|
||||
```shell
|
||||
export IMAGE_NAME=ms-swift:main-A2-py311-arm
|
||||
```
|
||||
|
||||
启动容器前建议先确认宿主机暴露的 NPU 设备:
|
||||
|
||||
```shell
|
||||
ls /dev/davinci*
|
||||
```
|
||||
|
||||
启动容器时需要把 NPU 设备、驱动、固件、`npu-smi` 和必要日志目录挂载进去。下面示例按常见 8 卡设备 `davinci0` 到 `davinci7` 编写;部分机器会额外暴露到 `davinci15`,这时请按 `ls /dev/davinci*` 的结果把对应设备都加到 `docker run` 中:
|
||||
|
||||
```shell
|
||||
docker run -it \
|
||||
--name swift-ascend \
|
||||
--network=host --ipc=host --shm-size=128g \
|
||||
--device=/dev/davinci0 --device=/dev/davinci1 \
|
||||
--device=/dev/davinci2 --device=/dev/davinci3 \
|
||||
--device=/dev/davinci4 --device=/dev/davinci5 \
|
||||
--device=/dev/davinci6 --device=/dev/davinci7 \
|
||||
--device=/dev/davinci_manager --device=/dev/devmm_svm --device=/dev/hisi_hdc \
|
||||
-v /usr/local/Ascend/driver:/usr/local/Ascend/driver:ro \
|
||||
-v /usr/local/Ascend/firmware:/usr/local/Ascend/firmware:ro \
|
||||
-v /usr/local/sbin/npu-smi:/usr/local/sbin/npu-smi:ro \
|
||||
-v /etc/ascend_install.info:/etc/ascend_install.info:ro \
|
||||
-v /var/log/npu:/var/log/npu \
|
||||
-v ${WORKSPACE}:/workspace \
|
||||
${IMAGE_NAME} \
|
||||
/bin/bash
|
||||
```
|
||||
|
||||
进入容器后,建议先执行 `source /usr/local/Ascend/ascend-toolkit/set_env.sh`,再运行后文的 NPU 可用性检查脚本,确认容器内可以正确访问昇腾设备。如果容器内无法识别 NPU,请优先检查 `/dev/davinci*`、`/dev/davinci_manager`、驱动目录和 `npu-smi` 是否正确挂载。
|
||||
|
||||
### 本地环境安装
|
||||
```shell
|
||||
# 创建新的 conda 虚拟环境(可选)
|
||||
conda create -n swift-npu python=3.11 -y
|
||||
conda activate swift-npu
|
||||
|
||||
# 注意进行后续操作前要先 source 激活 CANN 环境
|
||||
source /usr/local/Ascend/ascend-toolkit/set_env.sh
|
||||
|
||||
# 设置 pip 全局镜像(可选,加速下载)
|
||||
pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
|
||||
pip install ms-swift -U
|
||||
|
||||
# 使用源码安装
|
||||
git clone https://github.com/modelscope/ms-swift.git
|
||||
cd ms-swift
|
||||
pip install -e .
|
||||
|
||||
# 安装 torch_npu
|
||||
pip install torch_npu==2.9.0 decorator
|
||||
# 如果你想要使用 deepspeed(控制显存占用,训练速度会有一定下降)
|
||||
pip install deepspeed
|
||||
|
||||
# 如果需要使用 evaluation 功能,请安装以下包
|
||||
pip install evalscope[opencompass]
|
||||
|
||||
# 如果需要使用 vllm-ascend 进行推理,请安装以下包(更多版本请参考 [vLLM-Ascend 官网](https://docs.vllm.ai/projects/ascend/en/latest/installation.html))
|
||||
pip install vllm==0.18.0
|
||||
pip install vllm-ascend==0.18.0
|
||||
```
|
||||
|
||||
### NPU 可用性检查
|
||||
|
||||
测试环境是否安装正确,NPU能否被正常加载:
|
||||
|
||||
```python
|
||||
from transformers.utils import is_torch_npu_available
|
||||
import torch
|
||||
|
||||
print(is_torch_npu_available()) # True
|
||||
print(torch.npu.device_count()) # 8
|
||||
print(torch.randn(10, device='npu:0'))
|
||||
```
|
||||
|
||||
### MindSpeed/Megatron-SWIFT 可选安装
|
||||
|
||||
如果需要使用 MindSpeed(Megatron-LM),请按照下面引导安装必要依赖。
|
||||
|
||||
```shell
|
||||
# 1. 获取并切换 Megatron-LM 至 v0.16.0 版本
|
||||
git clone https://github.com/NVIDIA/Megatron-LM.git
|
||||
cd Megatron-LM
|
||||
git checkout core_v0.16.0
|
||||
cd ..
|
||||
|
||||
# 2. 获取并安装 MindSpeed
|
||||
git clone https://gitcode.com/Ascend/MindSpeed.git
|
||||
cd MindSpeed
|
||||
git checkout core_r0.16.0
|
||||
pip install -e .
|
||||
cd ..
|
||||
|
||||
# 3. 获取并安装 mcore-bridge
|
||||
git clone https://github.com/modelscope/mcore-bridge.git
|
||||
cd mcore-bridge
|
||||
pip install -e .
|
||||
cd ..
|
||||
|
||||
# 4. 获取并安装 triton-ascend
|
||||
pip install triton-ascend==3.2.1 --extra-index-url=https://triton-ascend.osinfra.cn/pypi/simple
|
||||
|
||||
# 5. 设置环境变量
|
||||
export PYTHONPATH=$PYTHONPATH:<your_local_megatron_lm_path>
|
||||
export MEGATRON_LM_PATH=<your_local_megatron_lm_path>
|
||||
|
||||
# 6. 如需回退到 transformers 的 GatedDeltaNet 实现,可关闭 Megatron GDN
|
||||
export USE_MCORE_GDN=0
|
||||
```
|
||||
|
||||
执行如下命令验证 MindSpeed(Megatron-LM) 是否配置成功:
|
||||
```shell
|
||||
python -c "import mindspeed.megatron_adaptor; from swift.megatron.init import init_megatron_env; init_megatron_env(); print('✓ NPU环境下的Megatron-SWIFT配置验证成功!')"
|
||||
```
|
||||
|
||||
### Qwen3.5 FLA补丁说明
|
||||
|
||||
当前仓库已经内置了面向昇腾 NPU 的 Qwen3.5 linear attention patch,无需用户再额外修改 `transformers` 或 `fla` 源码。该 patch 的目标不是直接替换整个 `flash-linear-attention` 包,而是在 `Qwen3.5` 实际调用的 `chunk_gated_delta_rule` 路径上,将底层 GPU Triton 算子重定向到 MindSpeed 的 NPU 实现。
|
||||
|
||||
补丁生效时,ms-swift 会执行以下替换:
|
||||
|
||||
1. 将 `transformers.utils.is_flash_linear_attention_available` 与 `transformers.utils.import_utils.is_flash_linear_attention_available` 置为 `True`,使 `transformers.models.qwen3_5.modeling_qwen3_5` 可以按 FLA fast path 完成初始化。
|
||||
2. 将 `transformers.models.qwen3_5.modeling_qwen3_5.chunk_gated_delta_rule` 以及 `transformers.models.qwen3_5_moe.modeling_qwen3_5_moe.chunk_gated_delta_rule` 重定向到 ms-swift 内置实现 `swift.model.chunk_gated_delta_rule.chunk_gated_delta_rule`。
|
||||
3. `swift.model.chunk_gated_delta_rule` 内部继续调用 MindSpeed 提供的原生 Triton 算子,包括:
|
||||
- `mindspeed.ops.triton.chunk_delta_h`
|
||||
- `mindspeed.ops.triton.chunk_o`
|
||||
- `mindspeed.ops.triton.chunk_scaled_dot_kkt`
|
||||
- `mindspeed.ops.triton.cumsum`
|
||||
- `mindspeed.ops.triton.solve_tril`
|
||||
- `mindspeed.ops.triton.wy_fast`
|
||||
4. 保留了 torch 原生 l2norm 小算子实现,减轻每层每步的 launch 开销以及冷启动中的 compile/autotune 开销,提升模型在 NPU 上的性能表现。
|
||||
5. 对于 FLA 中依赖 `torch.cuda.current_device()` 初始化的 `FusedRMSNormGated`,NPU 上会保留 Qwen3.5 的原生 torch 路径,避免 CUDA-only 初始化逻辑带来的兼容性问题。
|
||||
|
||||
可以将这条调用链理解为:
|
||||
|
||||
```text
|
||||
Qwen3.5 modeling.chunk_gated_delta_rule
|
||||
-> swift.model.chunk_gated_delta_rule.chunk_gated_delta_rule
|
||||
-> MindSpeed Triton kernels
|
||||
```
|
||||
|
||||
因此:
|
||||
|
||||
- 该 patch 主要覆盖的是 **Qwen3.5 linear attention 的 gated-delta-rule 路径**;
|
||||
- 它并不等价于“将整个 fla 包完整替换为 MindSpeed”;
|
||||
- 若需要这条路径生效,请确保当前环境中可以正确导入 MindSpeed 和 triton ascend
|
||||
- 精度对齐验证版本:torch 2.9.0 + MindSpeed 0.16.0 + flash-linear-attention 0.4.2 + triton-ascend 3.2.1 + transformers 5.2.0
|
||||
|
||||
|
||||
当前 Qwen3.5 在 NPU 上如果走 transformers 后端或 Megatron-SWIFT 后端训练,还需要额外注意版本和功能约束:
|
||||
|
||||
1. 当前 NPU 文档中约定的 MindSpeed 训练组合是 `Megatron-LM v0.16.0 + MindSpeed core_r0.16.0`。在这个组合下,`megatron-core` 已包含 `core.ssm.gated_delta_net` 原生 GDN 内核,`mcore-bridge` 默认会按 `USE_MCORE_GDN=1` 走 Megatron-Core/MindSpeed GDN 路径。若显式设置 `USE_MCORE_GDN=0`,则会回退到由 `mcore-bridge` 包装的 transformers 版 GDN,并配合 ms-swift 内置的 Qwen3.5 FLA NPU 补丁,把 `chunk_gated_delta_rule` 重定向到 MindSpeed Triton 算子。
|
||||
|
||||
2. 目前无论使用 transformers 后端还是 Megatron-SWIFT 后端,也无论 Megatron-SWIFT 下使用 `USE_MCORE_GDN=1` 还是 `USE_MCORE_GDN=0`,都不要在 Qwen3.5 的 NPU 路径上开启序列相关特性,包括 SP(sequence parallel,序列并行)、CP(context parallel,上下文并行)或 packing/padding-free。相关 FLA Triton 算子在 NPU 侧还没有完整的原生支持,开启这类特性可能触发算子缺失、样本边界处理不完整或并行切分不匹配问题。
|
||||
|
||||
3. 因此当前建议:transformers 后端避免设置 `--sequence_parallel_size` 大于 `1`,并避免使用 `--packing true` / `--padding_free true`;Megatron-SWIFT 后端`--context_parallel_size` 保持为 `1`,并同样避免使用 `--packing true` / `--padding_free true`。只有在目标 MindSpeed/FLA 版本明确补齐支持并完成分层验证后,才重新开启这些特性。
|
||||
|
||||
### 环境查看
|
||||
|
||||
查看NPU的P2P连接,这里看到每个NPU都通过7条HCCS与其他NPU互联
|
||||
|
||||
```shell
|
||||
(valle) root@valle:~/src# npu-smi info -t topo
|
||||
NPU0 NPU1 NPU2 NPU3 NPU4 NPU5 NPU6 NPU7 CPU Affinity
|
||||
NPU0 X HCCS HCCS HCCS HCCS HCCS HCCS HCCS 144-167
|
||||
NPU1 HCCS X HCCS HCCS HCCS HCCS HCCS HCCS 144-167
|
||||
NPU2 HCCS HCCS X HCCS HCCS HCCS HCCS HCCS 96-119
|
||||
NPU3 HCCS HCCS HCCS X HCCS HCCS HCCS HCCS 96-119
|
||||
NPU4 HCCS HCCS HCCS HCCS X HCCS HCCS HCCS 0-23
|
||||
NPU5 HCCS HCCS HCCS HCCS HCCS X HCCS HCCS 0-23
|
||||
NPU6 HCCS HCCS HCCS HCCS HCCS HCCS X HCCS 48-71
|
||||
NPU7 HCCS HCCS HCCS HCCS HCCS HCCS HCCS X 48-71
|
||||
|
||||
Legend:
|
||||
|
||||
X = Self
|
||||
SYS = Path traversing PCIe and NUMA nodes. Nodes are connected through SMP, such as QPI, UPI.
|
||||
PHB = Path traversing PCIe and the PCIe host bridge of a CPU.
|
||||
PIX = Path traversing a single PCIe switch
|
||||
PXB = Path traversing multiple PCIe switches
|
||||
HCCS = Connection traversing HCCS.
|
||||
NA = Unknown relationship.
|
||||
```
|
||||
|
||||
查看NPU状态, npu-smi命令详解可以查看[官方文档](https://support.huawei.com/enterprise/zh/doc/EDOC1100079287/10dcd668)
|
||||
|
||||
```shell
|
||||
(valle) root@valle:~/src# npu-smi info
|
||||
+------------------------------------------------------------------------------------------------+
|
||||
| npu-smi 24.1.rc1.b030 Version: 24.1.rc1.b030 |
|
||||
+---------------------------+---------------+----------------------------------------------------+
|
||||
| NPU Name | Health | Power(W) Temp(C) Hugepages-Usage(page)|
|
||||
| Chip | Bus-Id | AICore(%) Memory-Usage(MB) HBM-Usage(MB) |
|
||||
+===========================+===============+====================================================+
|
||||
| 0 910B3 | OK | 101.8 43 0 / 0 |
|
||||
| 0 | 0000:C1:00.0 | 0 0 / 0 3318 / 65536 |
|
||||
+===========================+===============+====================================================+
|
||||
| 1 910B3 | OK | 92.0 39 0 / 0 |
|
||||
| 0 | 0000:C2:00.0 | 0 0 / 0 3314 / 65536 |
|
||||
+===========================+===============+====================================================+
|
||||
| 2 910B3 | OK | 102.0 40 0 / 0 |
|
||||
| 0 | 0000:81:00.0 | 0 0 / 0 3314 / 65536 |
|
||||
+===========================+===============+====================================================+
|
||||
| 3 910B3 | OK | 99.8 40 0 / 0 |
|
||||
| 0 | 0000:82:00.0 | 0 0 / 0 3314 / 65536 |
|
||||
+===========================+===============+====================================================+
|
||||
| 4 910B3 | OK | 98.6 45 0 / 0 |
|
||||
| 0 | 0000:01:00.0 | 0 0 / 0 3314 / 65536 |
|
||||
+===========================+===============+====================================================+
|
||||
| 5 910B3 | OK | 99.7 44 0 / 0 |
|
||||
| 0 | 0000:02:00.0 | 0 0 / 0 3314 / 65536 |
|
||||
+===========================+===============+====================================================+
|
||||
| 6 910B3 | OK | 103.8 45 0 / 0 |
|
||||
| 0 | 0000:41:00.0 | 0 0 / 0 3314 / 65536 |
|
||||
+===========================+===============+====================================================+
|
||||
| 7 910B3 | OK | 98.2 44 0 / 0 |
|
||||
| 0 | 0000:42:00.0 | 0 0 / 0 3315 / 65536 |
|
||||
+===========================+===============+====================================================+
|
||||
```
|
||||
|
||||
## 快速跑通:ModelScope 模型 + 数据集
|
||||
|
||||
如果你想先用 ModelScope 上的模型和数据集快速验证环境,可以直接执行本节完成一次完整闭环:训练 LoRA、找到最新 checkpoint、Merge LoRA、命令行推理、启动服务、curl 验证。示例使用小模型和小规模采样,便于快速跑通;换成自己的模型或数据集时,只需要修改前面的 ID 变量。
|
||||
|
||||
```shell
|
||||
export MODEL_ID=Qwen/Qwen3-0.6B
|
||||
export DATASET_ID=AI-ModelScope/alpaca-gpt4-data-zh
|
||||
export WORK_DIR=output/npu-modelscope-qwen3-0_6b-lora
|
||||
```
|
||||
|
||||
训练并保存 LoRA checkpoint:
|
||||
|
||||
```shell
|
||||
ASCEND_RT_VISIBLE_DEVICES=0 \
|
||||
swift sft \
|
||||
--model $MODEL_ID \
|
||||
--dataset $DATASET_ID#1000 \
|
||||
--split_dataset_ratio 0.01 \
|
||||
--torch_dtype bfloat16 \
|
||||
--tuner_type lora \
|
||||
--target_modules all-linear \
|
||||
--lora_rank 8 \
|
||||
--lora_alpha 32 \
|
||||
--num_train_epochs 1 \
|
||||
--per_device_train_batch_size 1 \
|
||||
--per_device_eval_batch_size 1 \
|
||||
--gradient_accumulation_steps 8 \
|
||||
--learning_rate 1e-4 \
|
||||
--max_length 2048 \
|
||||
--save_steps 100 \
|
||||
--eval_steps 100 \
|
||||
--save_total_limit 2 \
|
||||
--logging_steps 10 \
|
||||
--output_dir $WORK_DIR
|
||||
```
|
||||
|
||||
训练结束后,checkpoint 会保存在 `$WORK_DIR/*/checkpoint-*` 目录下。可以用下面的命令取最新 checkpoint,并将 LoRA 合并保存为完整模型权重:
|
||||
|
||||
```shell
|
||||
export CKPT_DIR=$(ls -dt $WORK_DIR/*/checkpoint-* | head -n 1)
|
||||
|
||||
ASCEND_RT_VISIBLE_DEVICES=0 \
|
||||
swift export \
|
||||
--adapters $CKPT_DIR \
|
||||
--merge_lora true
|
||||
|
||||
export MERGED_DIR=${CKPT_DIR}-merged
|
||||
```
|
||||
|
||||
推理验证可以直接加载 LoRA checkpoint,也可以加载合并后的完整权重:
|
||||
|
||||
```shell
|
||||
# 直接加载 LoRA checkpoint
|
||||
ASCEND_RT_VISIBLE_DEVICES=0 \
|
||||
swift infer \
|
||||
--adapters $CKPT_DIR \
|
||||
--stream true \
|
||||
--temperature 0 \
|
||||
--max_new_tokens 512
|
||||
|
||||
# 加载 Merge 后的完整权重
|
||||
ASCEND_RT_VISIBLE_DEVICES=0 \
|
||||
swift infer \
|
||||
--model $MERGED_DIR \
|
||||
--stream true \
|
||||
--temperature 0 \
|
||||
--max_new_tokens 512
|
||||
```
|
||||
|
||||
如果需要启动 OpenAI 兼容的部署服务,可以使用合并后的完整权重:
|
||||
|
||||
```shell
|
||||
ASCEND_RT_VISIBLE_DEVICES=0 \
|
||||
swift deploy \
|
||||
--model $MERGED_DIR \
|
||||
--host 0.0.0.0 \
|
||||
--port 8000 \
|
||||
--max_new_tokens 512 \
|
||||
--served_model_name npu-modelscope-qwen3-0_6b
|
||||
```
|
||||
|
||||
服务启动后,用 curl 验证接口:
|
||||
|
||||
```shell
|
||||
curl http://localhost:8000/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"model": "npu-modelscope-qwen3-0_6b",
|
||||
"messages": [{"role": "user", "content": "用一句话介绍昇腾NPU。"}],
|
||||
"max_tokens": 128,
|
||||
"temperature": 0
|
||||
}'
|
||||
```
|
||||
|
||||
## 训练
|
||||
|
||||
以下介绍LoRA的微调, 全参数微调设置参数`--tuner_type full`即可. **更多训练脚本**参考[这里](https://github.com/modelscope/ms-swift/tree/main/examples/ascend/train)。如果需要了解预训练、SFT、LoRA、全参数训练、自定义数据集等通用能力,可以继续阅读[预训练与微调文档](../Instruction/Pre-training-and-Fine-tuning.md)。
|
||||
|
||||
|
||||
| 模型大小 | NPU数量 | deepspeed类型 | 最大显存占用量 |
|
||||
| -------- | ------- | ------------- | -------------- |
|
||||
| 7B | 1 | None | 1 * 28 GB |
|
||||
| 7B | 4 | None | 4 * 22 GB |
|
||||
| 7B | 4 | zero2 | 4 * 28 GB |
|
||||
| 7B | 4 | zero3 | 4 * 22 GB |
|
||||
| 7B | 8 | None | 8 * 22 GB |
|
||||
| 14B | 1 | None | 1 * 45 GB |
|
||||
| 14B | 8 | None | 8 * 51 GB |
|
||||
| 14B | 8 | zero2 | 8 * 49 GB |
|
||||
| 14B | 8 | zero3 | 8 * 31 GB |
|
||||
|
||||
### 单卡训练
|
||||
|
||||
通过如下命令启动单卡微调:
|
||||
|
||||
```shell
|
||||
# 实验环境: 昇腾910B3
|
||||
# 显存需求: 28 GB
|
||||
# 运行时长: 8小时
|
||||
ASCEND_RT_VISIBLE_DEVICES=0 \
|
||||
swift sft \
|
||||
--model Qwen/Qwen2-7B-Instruct \
|
||||
--dataset AI-ModelScope/blossom-math-v2 \
|
||||
--split_dataset_ratio 0.01 \
|
||||
--num_train_epochs 5 \
|
||||
--tuner_type lora \
|
||||
--output_dir output \
|
||||
--learning_rate 1e-4 \
|
||||
--gradient_accumulation_steps 16 \
|
||||
--save_steps 100 \
|
||||
--eval_steps 100
|
||||
|
||||
```
|
||||
|
||||
|
||||
### 数据并行训练
|
||||
|
||||
我们使用其中的4卡进行ddp训练
|
||||
|
||||
```shell
|
||||
# 实验环境: 4 * 昇腾910B3
|
||||
# 显存需求: 4 * 22 GB
|
||||
# 运行时长: 2小时
|
||||
NPROC_PER_NODE=4 \
|
||||
ASCEND_RT_VISIBLE_DEVICES=0,1,2,3 \
|
||||
swift sft \
|
||||
--model Qwen/Qwen2-7B-Instruct \
|
||||
--dataset AI-ModelScope/blossom-math-v2 \
|
||||
--split_dataset_ratio 0.01 \
|
||||
--num_train_epochs 5 \
|
||||
--tuner_type lora \
|
||||
--output_dir output \
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
### Deepspeed训练
|
||||
|
||||
ZeRO2:
|
||||
|
||||
```shell
|
||||
# 实验环境: 4 * 昇腾910B3
|
||||
# 显存需求: 4 * 28GB
|
||||
# 运行时长: 3.5小时
|
||||
NPROC_PER_NODE=4 \
|
||||
ASCEND_RT_VISIBLE_DEVICES=0,1,2,3 \
|
||||
swift sft \
|
||||
--model Qwen/Qwen2-7B-Instruct \
|
||||
--dataset AI-ModelScope/blossom-math-v2 \
|
||||
--split_dataset_ratio 0.01 \
|
||||
--num_train_epochs 5 \
|
||||
--tuner_type lora \
|
||||
--output_dir output \
|
||||
--deepspeed zero2 \
|
||||
...
|
||||
```
|
||||
|
||||
ZeRO3:
|
||||
|
||||
```shell
|
||||
# 实验环境: 4 * 昇腾910B3
|
||||
# 显存需求: 4 * 22 GB
|
||||
# 运行时长: 8.5小时
|
||||
NPROC_PER_NODE=4 \
|
||||
ASCEND_RT_VISIBLE_DEVICES=0,1,2,3 \
|
||||
swift sft \
|
||||
--model Qwen/Qwen2-7B-Instruct \
|
||||
--dataset AI-ModelScope/blossom-math-v2 \
|
||||
--split_dataset_ratio 0.01 \
|
||||
--num_train_epochs 5 \
|
||||
--tuner_type lora \
|
||||
--output_dir output \
|
||||
--deepspeed zero3 \
|
||||
...
|
||||
```
|
||||
|
||||
### Qwen3.5 单机多卡 LoRA 示例
|
||||
|
||||
下面给出一个更新模型的 NPU LoRA 示例。这里使用 Qwen3.5-4B 做演示,4 卡数据并行通常比单卡更快;如果本地已经下载好模型和数据集,可以把 `--model`、`--dataset` 替换成本地路径。
|
||||
|
||||
```shell
|
||||
# 实验环境: 4 * 昇腾910B3
|
||||
NPROC_PER_NODE=4 \
|
||||
ASCEND_RT_VISIBLE_DEVICES=0,1,2,3 \
|
||||
swift sft \
|
||||
--model Qwen/Qwen3.5-4B \
|
||||
--dataset AI-ModelScope/alpaca-gpt4-data-zh#2000 \
|
||||
--split_dataset_ratio 0.01 \
|
||||
--torch_dtype bfloat16 \
|
||||
--num_train_epochs 1 \
|
||||
--tuner_type lora \
|
||||
--target_modules all-linear \
|
||||
--lora_rank 8 \
|
||||
--lora_alpha 32 \
|
||||
--per_device_train_batch_size 1 \
|
||||
--per_device_eval_batch_size 1 \
|
||||
--gradient_accumulation_steps 8 \
|
||||
--learning_rate 1e-4 \
|
||||
--max_length 2048 \
|
||||
--group_by_length true \
|
||||
--dataset_num_proc 4 \
|
||||
--dataloader_num_workers 4 \
|
||||
--save_steps 100 \
|
||||
--eval_steps 100 \
|
||||
--save_total_limit 2 \
|
||||
--output_dir output/Qwen3.5-4B-NPU
|
||||
```
|
||||
|
||||
调参时可以先抓住三个目标:显存、吞吐和稳定性。
|
||||
|
||||
- 降低显存:优先减小 `--max_length`、`--per_device_train_batch_size` 和 `--lora_rank`;仍然 OOM 时再启用 `--deepspeed zero2/zero3`。ZeRO 可以明显降低显存压力,但会增加通信和调度开销。
|
||||
- 提高吞吐:在显存允许的情况下增大 `--per_device_train_batch_size`,再用 `--gradient_accumulation_steps` 保持全局 batch size;数据预处理较慢时增加 `--dataset_num_proc`,数据读取跟不上时增加 `--dataloader_num_workers`。
|
||||
- 控制保存成本:`--save_steps` 不宜过小,否则频繁保存会拖慢训练;`--save_total_limit 2` 通常足够保留 best checkpoint 和 last checkpoint。
|
||||
- 提高稳定性:NPU 上建议优先使用 `bfloat16`;如果遇到 loss 异常或 NaN,可以先缩小学习率、降低 batch,必要时再临时切到 `float32` 做对照定位。
|
||||
|
||||
更多参数含义可以在[命令行参数文档](../Instruction/Command-line-parameters.md)中查询。
|
||||
|
||||
### NPU模型Patch开关
|
||||
|
||||
ms-swift 在 NPU 环境下默认会启用模型层 patch,以适配部分 Transformers 模型在昇腾 NPU 上的算子和兼容性需求。通常不需要关闭;如果怀疑某个模型的 loss 异常、forward 报错与 NPU 模型 patch 有关,需要临时切回 Transformers 原生实现做对比,可以设置:
|
||||
|
||||
```shell
|
||||
swift sft ... --enable_npu_model_patch false
|
||||
```
|
||||
|
||||
## 模型保存、Merge LoRA 和断点续训
|
||||
|
||||
训练时通过 `--output_dir` 指定输出目录,通过 `--save_steps` 控制 checkpoint 保存间隔,通过 `--save_total_limit` 控制最多保留多少个 checkpoint。LoRA 训练结束后,checkpoint 目录中会保存 adapter 权重、训练参数和 trainer 状态;常见目录形态如下:
|
||||
|
||||
```text
|
||||
output/Qwen3.5-4B-NPU/vx-xxx/
|
||||
├── checkpoint-100/
|
||||
├── checkpoint-200/
|
||||
└── ...
|
||||
```
|
||||
|
||||
如果只做推理或继续 LoRA 训练,可以直接使用 checkpoint 目录。若希望得到一个独立的完整模型目录,便于 vLLM-Ascend 部署、离线分发或后续量化,可以执行 Merge LoRA:
|
||||
|
||||
```shell
|
||||
ASCEND_RT_VISIBLE_DEVICES=0 \
|
||||
swift export \
|
||||
--adapters output/Qwen3.5-4B-NPU/vx-xxx/checkpoint-xxx \
|
||||
--merge_lora true
|
||||
```
|
||||
|
||||
合并后的模型默认保存在 `checkpoint-xxx-merged` 目录。之后可以像加载普通模型一样使用 `--model checkpoint-xxx-merged`。
|
||||
|
||||
如果训练中断,需要从 checkpoint 恢复训练,请保持原训练参数不变,只额外增加 `--resume_from_checkpoint`:
|
||||
|
||||
```shell
|
||||
NPROC_PER_NODE=4 \
|
||||
ASCEND_RT_VISIBLE_DEVICES=0,1,2,3 \
|
||||
swift sft \
|
||||
--model Qwen/Qwen3.5-4B \
|
||||
--dataset AI-ModelScope/alpaca-gpt4-data-zh#2000 \
|
||||
--tuner_type lora \
|
||||
--output_dir output/Qwen3.5-4B-NPU \
|
||||
--resume_from_checkpoint output/Qwen3.5-4B-NPU/vx-xxx/checkpoint-xxx \
|
||||
...
|
||||
```
|
||||
|
||||
`--resume_from_checkpoint` 会恢复模型权重、优化器状态、随机种子和训练进度。如果只想加载模型权重而不恢复优化器和数据跳过状态,可以额外设置 `--resume_only_model true`。相关参数可参考[命令行参数文档](../Instruction/Command-line-parameters.md)中的 `resume_from_checkpoint`、`resume_only_model`、`save_steps` 和 `save_total_limit`。
|
||||
|
||||
## 推理
|
||||
|
||||
原始模型:
|
||||
|
||||
```shell
|
||||
ASCEND_RT_VISIBLE_DEVICES=0 swift infer \
|
||||
--model Qwen/Qwen2-7B-Instruct \
|
||||
--stream true --max_new_tokens 2048
|
||||
```
|
||||
|
||||
LoRA微调后:
|
||||
|
||||
```shell
|
||||
ASCEND_RT_VISIBLE_DEVICES=0 swift infer \
|
||||
--adapters xxx/checkpoint-xxx --load_data_args true \
|
||||
--stream true --max_new_tokens 2048
|
||||
```
|
||||
|
||||
全参数训练或 Merge LoRA 后的模型,可以通过 `--model` 指向对应的完整权重目录:
|
||||
|
||||
```shell
|
||||
ASCEND_RT_VISIBLE_DEVICES=0 swift infer \
|
||||
--model xxx/checkpoint-xxx-merged \
|
||||
--stream true --max_new_tokens 2048
|
||||
```
|
||||
|
||||
|
||||
## 部署
|
||||
|
||||
### 使用原生transformers进行部署
|
||||
|
||||
原始模型:
|
||||
|
||||
```shell
|
||||
ASCEND_RT_VISIBLE_DEVICES=0 swift deploy --model Qwen/Qwen2-7B-Instruct --max_new_tokens 2048
|
||||
```
|
||||
|
||||
LoRA微调后:
|
||||
|
||||
```shell
|
||||
ASCEND_RT_VISIBLE_DEVICES=0 swift deploy --adapters xxx/checkpoint-xxx --max_new_tokens 2048
|
||||
|
||||
# Merge LoRA 后部署完整权重
|
||||
ASCEND_RT_VISIBLE_DEVICES=0 swift export --adapters xx/checkpoint-xxx --merge_lora true
|
||||
ASCEND_RT_VISIBLE_DEVICES=0 swift deploy --model xxx/checkpoint-xxx-merged --max_new_tokens 2048
|
||||
```
|
||||
|
||||
### 使用vLLM-ascend进行部署
|
||||
使用pypi进行安装:
|
||||
```shell
|
||||
# 请以 vLLM-Ascend 官方兼容矩阵为准;以下为本文验证版本。
|
||||
pip install vllm==0.14.0
|
||||
pip install vllm-ascend==0.14.0rc1
|
||||
```
|
||||
原始模型:
|
||||
```shell
|
||||
ASCEND_RT_VISIBLE_DEVICES=0 swift deploy \
|
||||
--model Qwen/Qwen2.5-7B-Instruct \
|
||||
--infer_backend vllm \
|
||||
--max_new_tokens 2048
|
||||
```
|
||||
|
||||
LoRA微调后:
|
||||
|
||||
```shell
|
||||
ASCEND_RT_VISIBLE_DEVICES=0 swift deploy \
|
||||
--adapters xxx/checkpoint-xxx \
|
||||
--infer_backend vllm \
|
||||
--max_new_tokens 2048
|
||||
|
||||
# Merge LoRA 后部署完整权重
|
||||
ASCEND_RT_VISIBLE_DEVICES=0 swift export \
|
||||
--adapters xx/checkpoint-xxx \
|
||||
--merge_lora true
|
||||
|
||||
ASCEND_RT_VISIBLE_DEVICES=0 swift deploy \
|
||||
--model xxx/checkpoint-xxx-merged \
|
||||
--infer_backend vllm \
|
||||
--max_new_tokens 2048
|
||||
```
|
||||
|
||||
## 评测
|
||||
完成训练、推理或部署后,可以使用SWIFT内置的EvalScope能力对原始模型或微调后的checkpoint进行评测,完整参数说明与示例请参考[评测文档](../Instruction/Evaluation.md)。
|
||||
|
||||
## 发布
|
||||
如果需要将NPU训练后的checkpoint、合并后的模型或量化后的模型发布到ModelScope/HuggingFace,可以使用`swift export`的推送能力,完整参数说明与示例请参考[导出与推送文档](../Instruction/Export-and-push.md#推送模型)。
|
||||
|
||||
## FAQ
|
||||
|
||||
更多通用问题请先查看[常见问题整理](../Instruction/Frequently-asked-questions.md)。下面记录 NPU 场景下更常遇到的问题和处理方式。
|
||||
|
||||
### Q1: 如何确认当前环境已经正确识别 NPU?
|
||||
|
||||
先确认已经 `source /usr/local/Ascend/ascend-toolkit/set_env.sh`,再执行本文安装章节中的环境检查脚本。正常情况下,`is_torch_npu_available()` 应返回 `True`,`torch.npu.device_count()` 应能看到可用 NPU 数量,且可以在 `npu:0` 上创建 tensor。如果这里失败,优先检查 CANN、`torch`、`torch_npu` 版本是否和本文推荐版本一致。
|
||||
|
||||
### Q2: 训练时应该选择 FSDP、DeepSpeed 还是 Megatron-SWIFT?
|
||||
|
||||
普通 SFT 优先参考本文兼容性表中的 `FSDP1/FSDP2/deepspeed` 组合;如果模型规模较大、需要更高并行能力,再使用 Megatron-SWIFT,并按安装章节额外安装 MindSpeed、Megatron-LM 和 mcore-bridge。DeepSpeed 可以降低显存压力,但速度可能下降,遇到性能问题时可以对比 FSDP 方案。
|
||||
|
||||
### Q3: NPU 模型 Patch 需要手动关闭吗?
|
||||
|
||||
通常不需要。ms-swift 会在 NPU 环境下默认启用模型层 patch,以适配部分 Transformers 模型在昇腾 NPU 上的算子和兼容性需求。只有在排查 loss 异常、forward 报错,且怀疑问题来自 NPU patch 时,才建议临时加上 `--enable_npu_model_patch false` 和原生 Transformers 行为做对比。
|
||||
|
||||
### Q4: 使用 vLLM-Ascend 部署或 RL rollout 时需要注意什么?
|
||||
|
||||
请安装本文推荐的 `vllm` 与 `vllm-ascend` 版本,并优先使用兼容性表中已经验证过的模型和算法组合。当前 `sglang` 推理引擎未在 NPU 场景下完成支持验证,如果需要 NPU 上的高性能推理或 RL rollout,建议优先使用 `vllm-ascend`。
|
||||
|
||||
### Q5: 忘记执行 `source set_env.sh` 会有什么表现?
|
||||
|
||||
常见表现是 `is_torch_npu_available()` 返回 `False`、`torch.npu.device_count()` 为 0,或者运行时找不到 CANN/HCCL 相关动态库。进入新 shell 或新容器后,先执行:
|
||||
|
||||
```shell
|
||||
source /usr/local/Ascend/ascend-toolkit/set_env.sh
|
||||
```
|
||||
|
||||
如果系统安装了 NNAL/ATB 等组件,也需要按实际环境 source 对应的 `set_env.sh`。
|
||||
|
||||
### Q6: `torch` 和 `torch_npu` 版本不匹配怎么判断?
|
||||
|
||||
优先对照本文推荐版本安装。版本不匹配时,常见现象包括 `import torch_npu` 失败、NPU 设备不可见、算子注册失败、运行时报 C++/符号找不到等。可以先用下面的命令确认版本:
|
||||
|
||||
```shell
|
||||
python -c "import torch, torch_npu; print(torch.__version__); print(torch_npu.__version__)"
|
||||
```
|
||||
|
||||
如果版本不一致,先卸载后按同一套 CANN/PyTorch/torch_npu 版本重新安装,不建议只升级其中一个包。
|
||||
|
||||
### Q7: `ASCEND_RT_VISIBLE_DEVICES` 和 `NPROC_PER_NODE` 不一致会怎样?
|
||||
|
||||
分布式训练时二者应该匹配。例如 `ASCEND_RT_VISIBLE_DEVICES=0,1,2,3` 通常对应 `NPROC_PER_NODE=4`。如果进程数大于可见设备数,可能出现 rank 绑卡失败、多个进程抢同一张卡、初始化卡住或 HCCL 报错;如果进程数小于可见设备数,则只有部分 NPU 会被使用。
|
||||
|
||||
### Q8: 多卡训练卡住时先看什么?
|
||||
|
||||
先确认每个 rank 是否都已经启动、`ASCEND_RT_VISIBLE_DEVICES` 和 `NPROC_PER_NODE` 是否匹配,再看日志停在数据预处理、模型构建、权重加载还是 HCCL 初始化阶段。NPU/HCCL 相关底层日志可以重点查看:
|
||||
|
||||
```shell
|
||||
ls ~/ascend/log/debug/plog
|
||||
```
|
||||
|
||||
如果 Python 进程没有退出但长时间无输出,可以用 `pystack` 查看各 rank 当前栈,先判断是卡在数据、通信还是模型 forward/backward。
|
||||
|
||||
### Q9: HCCL 连接或超时问题如何初步排查?
|
||||
|
||||
先用 `npu-smi info` 和 `npu-smi info -t topo` 确认设备健康和拓扑,再检查是否有其他任务占用同一组 NPU。单机训练优先确认卡号、进程数和可见设备一致;多机训练还需要确认网络、rank 配置、通信端口和各节点环境变量一致。若同一机器上残留旧训练进程,先清理对应用户的训练进程后再重试。
|
||||
|
||||
### Q10: 容器里 `npu-smi` 不可用通常是什么原因?
|
||||
|
||||
通常是设备或驱动文件没有挂载完整。优先检查 `docker run` 是否包含 `/dev/davinci*`、`/dev/davinci_manager`、`/dev/devmm_svm`、`/dev/hisi_hdc`,以及 `/usr/local/Ascend/driver`、`/usr/local/Ascend/firmware`、`/usr/local/sbin/npu-smi` 和 `/etc/ascend_install.info`。如果宿主机本身 `npu-smi info` 失败,先修宿主机驱动环境。
|
||||
|
||||
### Q11: 原生 transformers 部署和 vLLM-Ascend 部署怎么选?
|
||||
|
||||
原生 transformers 部署兼容性更好,适合先验证模型、adapter、模板和输出是否正确;vLLM-Ascend 更适合高吞吐服务、RL rollout 或需要 OpenAI 兼容接口的性能场景。遇到 vLLM-Ascend 版本或算子问题时,建议先用 transformers 后端确认模型本身可用,再切换到 vLLM-Ascend 排查性能后端问题。
|
||||
|
||||
### Q12: vLLM-Ascend 报 device type 不匹配或 undefined symbol 怎么办?
|
||||
|
||||
这类问题通常不是训练脚本参数导致的,而是 `vllm-ascend` 轮子与当前硬件、PyTorch 或 C++ ABI 不匹配。可以先检查包内构建信息和当前版本:
|
||||
|
||||
```shell
|
||||
python -c "import torch, vllm_ascend; print(torch.__version__); print(vllm_ascend.__file__)"
|
||||
```
|
||||
|
||||
如果报错信息包含 `Current device type ... does not match the installed version's device type ...`、`undefined symbol` 等,建议按设备类型(A2/A3/其他)和官方兼容矩阵重装 `torch`、`torch_npu`、`vllm`、`vllm-ascend`,不要只单独替换一个包。
|
||||
|
||||
### Q13: FP8 或量化模型可以直接在 NPU 上训练吗?
|
||||
|
||||
不要默认可以。下载或加载大模型前,先检查 `config.json` 是否包含 `quantization_config`,再检查 safetensors 的真实 dtype。当前 NPU 支持范围中量化/QLoRA 仍属于暂不支持或未完全验证能力;如果模型权重是 FP8 block quantized,而当前 NPU 软件栈不支持对应 FP8 路径,应先换用 BF16 权重,或离线转换为 BF16 后再训练/加载。
|
||||
|
||||
### Q14: Megatron-SWIFT 导入到错误的 Megatron/MindSpeed 怎么排查?
|
||||
|
||||
跑 Megatron-SWIFT 前,`PYTHONPATH` 和 `MEGATRON_LM_PATH` 必须指向同一份 Megatron-LM 源码树。否则 Python 可能能启动,但实际导入到的是另一套 Megatron/MindSpeed 组合,后续报错会很像模型或参数问题。
|
||||
|
||||
```shell
|
||||
export PYTHONPATH=$PYTHONPATH:<your_local_megatron_lm_path>
|
||||
export MEGATRON_LM_PATH=<your_local_megatron_lm_path>
|
||||
python -c "import megatron, os; print(megatron.__file__); print(os.environ.get('MEGATRON_LM_PATH'))"
|
||||
```
|
||||
|
||||
如果二者不一致,先修环境变量,再继续排查模型构建、权重加载或并行配置。
|
||||
|
||||
|
||||
## NPU微信群
|
||||
|
||||
<img src="https://raw.githubusercontent.com/modelscope/ms-swift/main/docs/resources/wechat/npu.png" width="250">
|
||||
@@ -0,0 +1,395 @@
|
||||
# Qwen3最佳实践
|
||||
|
||||
讨论区:[issue 4030](https://github.com/modelscope/ms-swift/issues/4030)
|
||||
|
||||
Qwen文档: [https://qwen.readthedocs.io/en/latest/training/ms_swift.html](https://qwen.readthedocs.io/en/latest/training/ms_swift.html)
|
||||
|
||||
## 推理
|
||||
|
||||
思考模式:
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift infer \
|
||||
--model Qwen/Qwen3-8B \
|
||||
--infer_backend vllm \
|
||||
--stream true \
|
||||
--max_new_tokens 2048 \
|
||||
--vllm_max_model_len 8192
|
||||
```
|
||||
|
||||
```text
|
||||
<<< who are you?
|
||||
<think>
|
||||
Okay, the user is asking "who are you?" Let me start by introducing myself as Qwen, the large language model developed by Alibaba Cloud. I should mention my capabilities, like answering questions, creating content, and engaging in conversations. But I need to keep it concise. Also, the user might want to know how I can assist them. Maybe I should ask how I can help them today. Let me check if there's anything else important to include. Oh, I should make sure the tone is friendly and approachable. Alright, that should cover it.
|
||||
</think>
|
||||
|
||||
Hello! I am Qwen, a large language model developed by Alibaba Cloud. I can assist with a wide range of tasks, such as answering questions, creating content, writing stories, coding, and more. How can I help you today? 😊
|
||||
<<< clear
|
||||
<<< who are you? /no_think
|
||||
<think>
|
||||
|
||||
</think>
|
||||
|
||||
I am Qwen, a large language model developed by Alibaba Cloud. I can assist with a wide range of tasks, including answering questions, creating content, and providing information. How can I help you today?
|
||||
```
|
||||
|
||||
非思考模式:
|
||||
- 其中`--response_prefix`代表模型的输出会在其前缀后继续生成。等价于enable_thinking设置为False。
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift infer \
|
||||
--model Qwen/Qwen3-8B \
|
||||
--infer_backend vllm \
|
||||
--stream true \
|
||||
--max_new_tokens 2048 \
|
||||
--vllm_max_model_len 8192 \
|
||||
--response_prefix '<think>\n\n</think>\n\n'
|
||||
```
|
||||
|
||||
```text
|
||||
<<< who are you?
|
||||
<think>
|
||||
|
||||
</think>
|
||||
|
||||
I am Qwen, a large-scale language model developed by Alibaba Cloud. I am designed to assist with a wide range of tasks, including answering questions, creating content, and providing information. How can I assist you today?
|
||||
```
|
||||
|
||||
## 训练
|
||||
|
||||
在开始训练之前,请确保您的环境已正确配置。
|
||||
|
||||
```bash
|
||||
pip install ms-swift -U
|
||||
pip install transformers
|
||||
|
||||
pip install deepspeed # 多GPU训练
|
||||
pip install liger-kernel # 节约显存资源
|
||||
pip install flash-attn --no-build-isolation # packing需要
|
||||
```
|
||||
|
||||
## 监督微调 (SFT)
|
||||
|
||||
### 数据准备
|
||||
|
||||
使用 ms-swift 进行 SFT 的自定义数据集格式如下(system 字段是可选的)。您可以将其组织为 JSON、JSONL 或 CSV 格式。在训练脚本中指定 `--dataset <dataset_path>`。有关完整的数据集格式指南,请参考[自定义数据集文档](../Customization/Custom-dataset.md)。
|
||||
|
||||
```text
|
||||
# 通用格式
|
||||
{"messages": [
|
||||
{"role": "system", "content": "<system-prompt>"},
|
||||
{"role": "user", "content": "<query1>"},
|
||||
{"role": "assistant", "content": "<response1>"}
|
||||
]}
|
||||
# 带think的格式
|
||||
{"messages": [
|
||||
{"role": "user", "content": "Where is the capital of Zhejiang?"},
|
||||
{"role": "assistant", "content": "<think>\n...\n</think>\n\nThe capital of Zhejiang is Hangzhou."}
|
||||
]}
|
||||
```
|
||||
|
||||
如果您想使用不含思维链的数据进行训练,同时保留模型的推理能力,可以通过以下两种方法尽量减少微调的影响:
|
||||
|
||||
**选项 1**:【推荐】在训练期间,指定 `--loss_scale ignore_empty_think`,以忽略对 `'<think>\n\n</think>\n\n'` 的损失计算,从而避免推理能力的丧失。训练脚本参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/train/think_model/qwen3_demo1.sh)。该方式同样适用于deepseek-r1等模型。自定义数据集格式如下:
|
||||
|
||||
```json
|
||||
{"messages": [
|
||||
{"role": "user", "content": "Where is the capital of Zhejiang?"},
|
||||
{"role": "assistant", "content": "<think>\n\n</think>\n\nThe capital of Zhejiang is Hangzhou."}
|
||||
]}
|
||||
```
|
||||
|
||||
**选项 2**:在数据集的查询中添加 `/no_think`,以避免推理能力的丧失。训练脚本请参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/train/think_model/qwen3_demo2.sh)。自定义数据集格式如下:
|
||||
|
||||
```json
|
||||
{"messages": [
|
||||
{"role": "user", "content": "Where is the capital of Zhejiang? /no_think"},
|
||||
{"role": "assistant", "content": "<think>\n\n</think>\n\nThe capital of Zhejiang is Hangzhou."}
|
||||
]}
|
||||
```
|
||||
|
||||
你可以使用以下命令获取蒸馏的推理数据集,在训练时,与不含思维链数据集进行混合,进一步缓解推理能力的丧失:
|
||||
- 其中`--val_dataset`的选择任意。推理产生的`result_path`,可以直接在训练时指定`--dataset distill_dataset.jsonl`使用。
|
||||
- 该思路同样适用于其他推理模型,例如deepseek-r1。
|
||||
```shell
|
||||
# 4 * 80GiB
|
||||
NPROC_PER_NODE=4 \
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3 \
|
||||
swift infer \
|
||||
--model Qwen/Qwen3-32B \
|
||||
--infer_backend vllm \
|
||||
--val_dataset 'AI-ModelScope/alpaca-gpt4-data-en#5000' 'AI-ModelScope/alpaca-gpt4-data-zh#5000' \
|
||||
--vllm_gpu_memory_utilization 0.9 \
|
||||
--vllm_tensor_parallel_size 2 \
|
||||
--vllm_max_model_len 8192 \
|
||||
--max_new_tokens 4096 \
|
||||
--write_batch_size 1000 \
|
||||
--result_path distill_dataset.jsonl
|
||||
```
|
||||
|
||||
### 30分钟自我认知微调
|
||||
|
||||
本节将介绍30分钟对 Qwen3-8B 进行自我认知微调。所需GPU显存为 22GB,可以在 ModelScope 提供的[免费算力](https://modelscope.cn/my/mynotebook) A10 中运行。
|
||||
|
||||
训练后,模型将不再认为自己是由“阿里云”训练的“Qwen”,而是由“swift”训练的“swift-robot”。
|
||||
|
||||
如果需要在离线环境下进行训练,可以手动下载模型和数据集,并指定 `--model <model-path>` 和 `--dataset <dataset-dir>`。数据集可以在 [Modelscope Hub](https://modelscope.cn/datasets/swift/self-cognition)上找到。对`swift/self-cognition`数据集的预处理函数可以查看[这里](https://github.com/modelscope/ms-swift/blob/36fdf381e5e88cb8a71c9d69c1d8936a989318cc/swift/llm/dataset/dataset/llm.py#L882)。
|
||||
|
||||
关于训练脚本中各参数的含义,请参考[命令行参数文档](../Instruction/Command-line-parameters.md)。
|
||||
|
||||
```bash
|
||||
# 显存占用:22GB
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift sft \
|
||||
--model Qwen/Qwen3-8B \
|
||||
--tuner_type lora \
|
||||
--dataset 'swift/Qwen3-SFT-Mixin#2000' \
|
||||
'swift/self-cognition:qwen3#600' \
|
||||
--load_from_cache_file true \
|
||||
--torch_dtype bfloat16 \
|
||||
--num_train_epochs 1 \
|
||||
--per_device_train_batch_size 1 \
|
||||
--per_device_eval_batch_size 1 \
|
||||
--learning_rate 1e-4 \
|
||||
--lora_rank 8 \
|
||||
--lora_alpha 32 \
|
||||
--target_modules all-linear \
|
||||
--gradient_accumulation_steps 16 \
|
||||
--eval_steps 50 \
|
||||
--save_steps 50 \
|
||||
--save_total_limit 2 \
|
||||
--logging_steps 5 \
|
||||
--max_length 2048 \
|
||||
--output_dir output \
|
||||
--warmup_ratio 0.05 \
|
||||
--dataloader_num_workers 4 \
|
||||
--model_author swift \
|
||||
--model_name swift-robot
|
||||
```
|
||||
|
||||
微调完成后,可以使用以下脚本来测试微调结果。注意,`--adapters` 部分需要修改为最后保存检查点的目录路径:
|
||||
|
||||
```bash
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift infer \
|
||||
--adapters output/vx-xxx/checkpoint-xxx \
|
||||
--stream true \
|
||||
--temperature 0 \
|
||||
--max_new_tokens 2048
|
||||
```
|
||||
|
||||
```text
|
||||
<<< who are you?
|
||||
<think>
|
||||
Okay, the user asked, "who are you?" I need to introduce myself. Let me start by stating my name, swift-robot. Then, I should mention that I'm an AI assistant developed by swift. I should explain my purpose, which is to provide information and assistance. I should also highlight my capabilities, like answering questions, generating text, and engaging in conversation. It's important to keep the tone friendly and approachable. Maybe add something about being here to help and encourage the user to ask anything. Let me check if I covered all the key points: name, developer, purpose, capabilities, and a welcoming statement. Yeah, that should do it. Now, let me put that into a concise and friendly response.
|
||||
</think>
|
||||
|
||||
Hello! I am swift-robot, an artificial intelligence assistant developed by swift. My purpose is to provide information and assistance to users like you. I can answer questions, generate text, and engage in conversations on a wide range of topics. I am here to help, so feel free to ask me anything you need!
|
||||
```
|
||||
|
||||
默认情况下,ms-swift 会使用 ModelScope 社区下载模型和数据集。如果想使用 HuggingFace 社区,则需要额外指定 `--use_hf true`。
|
||||
|
||||
合并 LoRA 权重:
|
||||
|
||||
```shell
|
||||
swift export \
|
||||
--adapters output/checkpoint-xxx \
|
||||
--merge_lora true
|
||||
```
|
||||
|
||||
推送模型到 ModelScope/HuggingFace:
|
||||
|
||||
```bash
|
||||
# 如果是推送完整的权重,需要修改`--adapters`为`--model`.
|
||||
# Modelscope的hub_token可以在这里找到: https://modelscope.cn/my/myaccesstoken
|
||||
swift export \
|
||||
--adapters output/checkpoint-xxx \
|
||||
--push_to_hub true \
|
||||
--hub_model_id '<hub-model-id>' \
|
||||
--hub_token '<hub-token>' \
|
||||
--use_hf false
|
||||
```
|
||||
|
||||
如果要使用多 GPU 进行训练,以下提供了多 GPU 训练的示例:
|
||||
|
||||
```bash
|
||||
# 4 * 60GB
|
||||
# 你可以通过设置`--dataset AI-ModelScope/alpaca-gpt4-data-en`跑通实验
|
||||
# 注意:如果你指定了`--packing true`, 你必须额外设置`--attn_impl flash_attn`
|
||||
|
||||
NPROC_PER_NODE=4 \
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3 \
|
||||
swift sft \
|
||||
--model Qwen/Qwen3-8B \
|
||||
--tuner_type full \
|
||||
--dataset '<your-dataset>' \
|
||||
--load_from_cache_file true \
|
||||
--split_dataset_ratio 0.01 \
|
||||
--torch_dtype bfloat16 \
|
||||
--per_device_train_batch_size 1 \
|
||||
--per_device_eval_batch_size 1 \
|
||||
--learning_rate 1e-5 \
|
||||
--gradient_accumulation_steps 4 \
|
||||
--packing true \
|
||||
--eval_steps 100 \
|
||||
--save_steps 100 \
|
||||
--logging_steps 5 \
|
||||
--max_length 8192 \
|
||||
--warmup_ratio 0.05 \
|
||||
--dataloader_num_workers 8 \
|
||||
--dataset_num_proc 8 \
|
||||
--save_total_limit 2 \
|
||||
--save_only_model true \
|
||||
--output_dir output \
|
||||
--deepspeed zero3 \
|
||||
--use_liger_kernel true \
|
||||
--attn_impl flash_attn
|
||||
```
|
||||
|
||||
## 强化学习 (RL)
|
||||
|
||||
ms-swift 支持 DPO、GRPO、DAPO、PPO、KTO、GKD 等 RLHF 方法。本章将着重介绍使用 ms-swift 对 Qwen3-8B 进行 GRPO 训练。更多关于GRPO的内容,可以参考[GRPO文档](../Instruction/GRPO/GetStarted/GRPO.md)。更多RLHF训练脚本,参考[examples/train/rlhf](https://github.com/modelscope/ms-swift/tree/main/examples/train/rlhf)。
|
||||
|
||||
### 环境设置
|
||||
|
||||
除了安装上述介绍的 ms-swift 相关依赖项外,还需要安装以下依赖项:
|
||||
```
|
||||
pip install "math_verify"
|
||||
pip install vllm==0.8.5.post1
|
||||
```
|
||||
|
||||
### 数据准备
|
||||
|
||||
使用 ms-swift 进行 GRPO 训练的数据集格式与 SFT 类似,但不需要最后一轮的 assistant 部分。如果使用 accuracy 作为奖励,则需要额外的 `solution` 列来计算准确率。
|
||||
|
||||
示例数据集格式:
|
||||
|
||||
```jsonl
|
||||
{"messages": [{"role": "user", "content": "Tell me tomorrow's weather"}]}
|
||||
{"messages": [{"role": "user", "content": "What is 1 + 1?"}, {"role": "assistant", "content": "It equals 2"}, {"role": "user", "content": "What about adding 1?"}]}
|
||||
{"messages": [{"role": "user", "content": "What is your name?"}]}
|
||||
```
|
||||
|
||||
关于其他 RLHF 算法的数据集准备,请参考[自定义数据集文档](../Customization/Custom-dataset.md#rlhf)。
|
||||
|
||||
数据集要求的注意事项:
|
||||
|
||||
- **奖励函数计算**:数据集格式取决于所使用的奖励函数。可能需要额外的列来支持特定的奖励计算。例如:
|
||||
|
||||
- 当使用内置的 accuracy 或 cosine 奖励时,数据集必须包含一个 `solution` 列以计算回复的准确性。
|
||||
- 数据集中的其他列将作为 ``**kwargs`` 传递给奖励函数以实现进一步的自定义。
|
||||
|
||||
- **自定义奖励函数**:为了根据您的具体需求调整奖励函数,可以参考链接:[外部奖励插件](https://github.com/modelscope/ms-swift/tree/main/examples/train/grpo/plugin)。该插件提供了实现自定义奖励函数的示例和模板。
|
||||
|
||||
我们使用使 AI-MO/NuminaMath-TIR 作为数据集,并使用accuracy函数计算模型回答的准确率奖励。
|
||||
|
||||
在训练过程中,使用 vLLM 加速采样过程。
|
||||
|
||||
```bash
|
||||
# 70G*8
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \
|
||||
NPROC_PER_NODE=8 \
|
||||
swift rlhf \
|
||||
--rlhf_type grpo \
|
||||
--model Qwen/Qwen3-8B \
|
||||
--tuner_type full \
|
||||
--dataset 'AI-MO/NuminaMath-TIR#5000' \
|
||||
--load_from_cache_file true \
|
||||
--torch_dtype bfloat16 \
|
||||
--num_train_epochs 1 \
|
||||
--per_device_train_batch_size 2 \
|
||||
--per_device_eval_batch_size 2 \
|
||||
--learning_rate 1e-6 \
|
||||
--save_total_limit 2 \
|
||||
--logging_steps 5 \
|
||||
--output_dir output \
|
||||
--gradient_accumulation_steps 1 \
|
||||
--warmup_ratio 0.05 \
|
||||
--dataloader_num_workers 4 \
|
||||
--max_length 4096 \
|
||||
--max_completion_length 4096 \
|
||||
--vllm_max_model_len 8192 \
|
||||
--reward_funcs accuracy \
|
||||
--num_generations 16 \
|
||||
--use_vllm true \
|
||||
--vllm_gpu_memory_utilization 0.4 \
|
||||
--sleep_level 1 \
|
||||
--offload_model true \
|
||||
--offload_optimizer true \
|
||||
--deepspeed zero3 \
|
||||
--vllm_tensor_parallel_size 1 \
|
||||
--temperature 1.0 \
|
||||
--top_p 0.85 \
|
||||
--log_completions true \
|
||||
--overlong_filter true
|
||||
```
|
||||
|
||||
## Megatron-SWIFT
|
||||
|
||||
Qwen3-235B-A22B-Instruct-250718 单机8卡H20 LoRA训练的最佳实践参考:[https://github.com/modelscope/ms-swift/pull/5033](https://github.com/modelscope/ms-swift/pull/5033)。
|
||||
|
||||
ms-swift 引入了 Megatron 并行技术以加速大模型的CPT/SFT/DPO/GRPO。支持的模型可以在[支持的模型文档](../Instruction/Supported-models-and-datasets.md)中找到。
|
||||
|
||||
关于环境准备,可以参考[Megatron-SWIFT训练文档](../Megatron-SWIFT/Quick-start.md)。
|
||||
|
||||
我们将使用阿里云 DLC 启动训练。训练环境由2台配备8卡 80GiB A800 GPU 组成。关于多节点启动方法的更多信息,请参考[这里](https://github.com/modelscope/ms-swift/tree/main/examples/train/multi-node)。
|
||||
|
||||
```bash
|
||||
# https://help.aliyun.com/zh/pai/user-guide/general-environment-variables
|
||||
PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True' \
|
||||
NNODES=$WORLD_SIZE \
|
||||
NODE_RANK=$RANK \
|
||||
megatron sft \
|
||||
--model Qwen/Qwen3-30B-A3B-Base \
|
||||
--save_safetensors true \
|
||||
--dataset 'liucong/Chinese-DeepSeek-R1-Distill-data-110k-SFT' \
|
||||
--load_from_cache_file true \
|
||||
--split_dataset_ratio 0.01 \
|
||||
--pipeline_model_parallel_size 2 \
|
||||
--expert_model_parallel_size 8 \
|
||||
--moe_grouped_gemm true \
|
||||
--moe_shared_expert_overlap true \
|
||||
--moe_permute_fusion true \
|
||||
--moe_aux_loss_coeff 1e-3 \
|
||||
--micro_batch_size 1 \
|
||||
--global_batch_size 16 \
|
||||
--packing true \
|
||||
--recompute_granularity full \
|
||||
--recompute_method uniform \
|
||||
--recompute_num_layers 1 \
|
||||
--train_iters 2000 \
|
||||
--eval_iters 50 \
|
||||
--finetune true \
|
||||
--cross_entropy_loss_fusion true \
|
||||
--lr 1e-5 \
|
||||
--lr_warmup_fraction 0.05 \
|
||||
--min_lr 1e-6 \
|
||||
--output_dir megatron_output/Qwen3-30B-A3B-Base \
|
||||
--eval_steps 200 \
|
||||
--save_steps 200 \
|
||||
--max_length 8192 \
|
||||
--dataloader_num_workers 8 \
|
||||
--dataset_num_proc 8 \
|
||||
--no_save_optim true \
|
||||
--no_save_rng true \
|
||||
--sequence_parallel true \
|
||||
--attention_backend flash
|
||||
```
|
||||
|
||||
训练loss图(部分):
|
||||
|
||||
<img width="910" alt="Image" src="https://github.com/user-attachments/assets/9fe393aa-8299-4659-aa2f-be5d44f0730b" />
|
||||
|
||||
效果截图:
|
||||
|
||||
<img width="1066" alt="Image" src="https://github.com/user-attachments/assets/1a924130-1954-43e9-9093-b019aeef5949" />
|
||||
|
||||
|
||||
自定义数据集格式与`swift sft`相同,详见之前章节。只需指定 `--dataset <dataset_path>` 即可。
|
||||
|
||||
使用 `megatron sft` 和 `swift sft` 在对 Qwen3-30B-A3B 模型进行全参数微调的训练速度和 GPU 显存使用对比情况如下:
|
||||
|
||||
| | Megatron-LM | DeepSpeed-ZeRO2 | DeepSpeed-ZeRO3 |
|
||||
| -------- | ----------- | --------------- | --------------- |
|
||||
| 训练速度 | 9.6s/it | - | 91.2s/it |
|
||||
| 显存使用 | 16 * 60GiB | OOM | 16 * 80GiB |
|
||||
@@ -0,0 +1,329 @@
|
||||
|
||||
# Qwen3-VL最佳实践
|
||||
|
||||
## 环境准备
|
||||
|
||||
在开始推理和训练之前,请确保您的环境已准备就绪。
|
||||
|
||||
```shell
|
||||
pip install "transformers>=4.57" "qwen_vl_utils>=0.0.14"
|
||||
|
||||
pip install "ms-swift>=4.0"
|
||||
# pip install "vllm>=0.11.0" # 若使用vllm推理后端进行推理
|
||||
```
|
||||
- 关于视频数据训练卡住:使用decord后端读取视频可能导致卡住问题,参考[这个issue](https://github.com/dmlc/decord/issues/269)。你可以使用torchcodec后端,具体参考[qwen_vl_utils](https://github.com/QwenLM/Qwen3-VL/blob/50068df2334f309979ff05d75f1078c8309c63ed/qwen-vl-utils/src/qwen_vl_utils/vision_process.py#L390-L400)库。
|
||||
|
||||
## 推理
|
||||
|
||||
使用 transformers 推理:
|
||||
```python
|
||||
import os
|
||||
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
|
||||
from modelscope import snapshot_download
|
||||
from qwen_vl_utils import process_vision_info
|
||||
from transformers import Qwen3VLForConditionalGeneration, AutoProcessor
|
||||
|
||||
model_dir = snapshot_download('Qwen/Qwen3-VL-4B-Instruct')
|
||||
|
||||
model = Qwen3VLForConditionalGeneration.from_pretrained(
|
||||
model_dir, dtype="auto", device_map="auto",
|
||||
# attn_implementation='flash_attention_2',
|
||||
)
|
||||
|
||||
processor = AutoProcessor.from_pretrained(model_dir)
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "video",
|
||||
"video": "https://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/baby.mp4",
|
||||
"max_pixels": 128*32*32,
|
||||
"max_frames": 16,
|
||||
},
|
||||
{"type": "text", "text": "Describe this video."},
|
||||
],
|
||||
}
|
||||
]
|
||||
|
||||
text = processor.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
|
||||
image_inputs, video_inputs, video_kwargs = process_vision_info([messages], return_video_kwargs=True,
|
||||
image_patch_size= 16,
|
||||
return_video_metadata=True)
|
||||
if video_inputs is not None:
|
||||
video_inputs, video_metadatas = zip(*video_inputs)
|
||||
video_inputs, video_metadatas = list(video_inputs), list(video_metadatas)
|
||||
else:
|
||||
video_metadatas = None
|
||||
inputs = processor(text=[text], images=image_inputs, videos=video_inputs, video_metadata=video_metadatas, **video_kwargs, do_resize=False, return_tensors="pt")
|
||||
inputs = inputs.to('cuda')
|
||||
|
||||
generated_ids = model.generate(**inputs, max_new_tokens=128, do_sample=False)
|
||||
generated_ids_trimmed = [
|
||||
out_ids[len(in_ids) :] for in_ids, out_ids in zip(inputs.input_ids, generated_ids)
|
||||
]
|
||||
output_text = processor.batch_decode(
|
||||
generated_ids_trimmed, skip_special_tokens=True, clean_up_tokenization_spaces=False
|
||||
)
|
||||
print(output_text[0])
|
||||
# 'A baby wearing glasses sits on a bed, engrossed in reading a book. The baby turns the pages with both hands, occasionally looking up and smiling. The room is cozy, with a crib in the background and clothes scattered around. The baby’s focus and curiosity are evident as they explore the book, creating a heartwarming scene of early learning and discovery.'
|
||||
```
|
||||
|
||||
使用 ms-swift 的 `TransformersEngine` 进行推理:
|
||||
```python
|
||||
import os
|
||||
# os.environ['SWIFT_DEBUG'] = '1'
|
||||
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
|
||||
os.environ['VIDEO_MAX_TOKEN_NUM'] = '128'
|
||||
os.environ['FPS_MAX_FRAMES'] = '16'
|
||||
|
||||
|
||||
from swift.infer_engine import TransformersEngine, InferRequest, RequestConfig
|
||||
engine = TransformersEngine('Qwen/Qwen3-VL-4B-Instruct') # attn_impl='flash_attention_2'
|
||||
infer_request = InferRequest(messages=[{
|
||||
"role": "user",
|
||||
"content": '<video>Describe this video.',
|
||||
}], videos=['https://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/baby.mp4'])
|
||||
request_config = RequestConfig(max_tokens=128, temperature=0)
|
||||
resp_list = engine.infer([infer_request], request_config=request_config)
|
||||
response = resp_list[0].choices[0].message.content
|
||||
# 'A baby wearing glasses sits on a bed, engrossed in reading a book. The baby turns the pages with both hands, occasionally looking up and smiling. The room is cozy, with a crib in the background and clothes scattered around. The baby’s focus and curiosity are evident as they explore the book, creating a heartwarming scene of early learning and discovery.'
|
||||
|
||||
# use stream
|
||||
request_config = RequestConfig(max_tokens=128, temperature=0, stream=True)
|
||||
gen_list = engine.infer([infer_request], request_config=request_config)
|
||||
for chunk in gen_list[0]:
|
||||
if chunk is None:
|
||||
continue
|
||||
print(chunk.choices[0].delta.content, end='', flush=True)
|
||||
print()
|
||||
```
|
||||
|
||||
使用命令行推理:
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
IMAGE_MAX_TOKEN_NUM=1024 \
|
||||
VIDEO_MAX_TOKEN_NUM=128 \
|
||||
FPS_MAX_FRAMES=16 \
|
||||
swift infer \
|
||||
--model Qwen/Qwen3-VL-4B-Instruct \
|
||||
--stream true
|
||||
```
|
||||
|
||||
```
|
||||
<<< who are you?
|
||||
Hello! I'm Qwen, a large-scale language model independently developed by the Tongyi Lab under Alibaba Group. My main functions include answering questions, creating text such as stories, official documents, emails, scripts, and more, as well as performing logical reasoning, programming, and other tasks. If you have any questions or need assistance, feel free to let me know anytime, and I'll do my best to help!
|
||||
--------------------------------------------------
|
||||
<<< <image>describe the image.
|
||||
Input an image path or URL <<< http://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/cat.png
|
||||
This is a beautifully detailed, close-up portrait of an adorable tabby kitten, rendered with a soft, painterly effect that gives it a gentle, dreamy quality.
|
||||
|
||||
Here’s a breakdown of the image:
|
||||
|
||||
- **The Kitten:** The subject is a young, fluffy kitten with a classic tabby pattern. Its fur is a mix of white and soft grayish-brown stripes, with a prominent dark stripe running down the center of its forehead and over its nose. The kitten’s face is predominantly white, with delicate markings around its eyes and cheeks.
|
||||
|
||||
- **The Eyes:** Its most captivating feature is its large, round, and expressive eyes. They are a striking shade of bright blue-gray, with dark pupils that give it an intense, curious, and slightly innocent gaze. The eyes are wide open, suggesting the kitten is alert and attentive.
|
||||
|
||||
- **The Expression:** The kitten’s expression is sweet and innocent. Its small pink nose and slightly parted mouth give it a gentle, almost pleading look. Its whiskers are long and white, standing out against its fur.
|
||||
|
||||
- **The Style:** The image has a soft-focus, artistic quality, reminiscent of impressionist painting. The edges of the kitten’s fur are slightly blurred, creating a halo effect that draws attention to its face. The background is softly blurred with muted tones of green and gray, which helps the kitten stand out as the clear focal point.
|
||||
|
||||
- **Overall Impression:** The image evokes feelings of warmth, cuteness, and tenderness. The kitten appears to be looking directly at the viewer, creating a sense of connection and affection.
|
||||
|
||||
This is a lovely and charming depiction of a young kitten, capturing its innocence and charm in a visually appealing and emotionally engaging way.
|
||||
--------------------------------------------------
|
||||
<<< <video>describe the video.
|
||||
Input a video path or URL <<< https://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/baby.mp4
|
||||
This video captures a charming and adorable moment of a young child, likely a toddler, sitting on a bed and pretending to read a book. The child is wearing glasses, which adds a humorous and endearing touch to the scene — as if they’re a little scholar or librarian.
|
||||
|
||||
Here’s a breakdown of what unfolds:
|
||||
|
||||
- The child is seated cross-legged on a bed with a patterned quilt. Behind them, a crib and some household items are visible, suggesting a cozy bedroom setting.
|
||||
|
||||
- The child holds an open book and appears to be turning the pages with focused attention, mimicking the behavior of a real reader.
|
||||
|
||||
- At one point, the child looks up, smiles, or seems to react with delight — perhaps amused by something in the book or just enjoying the activity.
|
||||
|
||||
- The child’s movements are gentle and deliberate, showing a sense of concentration and curiosity. They turn pages, sometimes with one hand, and occasionally lift the book slightly as if to examine it more closely.
|
||||
|
||||
- The video has a warm, candid feel — it’s not staged, and the child’s natural behavior makes it feel authentic and heartwarming.
|
||||
|
||||
Overall, this is a sweet, lighthearted video that showcases the innocence and imagination of early childhood. The child’s engagement with the book, combined with their glasses and playful demeanor, creates a delightful and memorable scene.
|
||||
```
|
||||
|
||||
- 其中特定模型参数,例如 `VIDEO_MAX_TOKEN_NUM` 等环境变量的含义参考[命令行参数文档](../Instruction/Command-line-parameters.md#qwen3_vl-qwen3_5)。
|
||||
|
||||
|
||||
## 训练
|
||||
|
||||
本文档将介绍如何使用 ms-swift 与 Megatron-SWIFT 训练 Qwen3-VL。推荐 Dense 模型使用 ms-swift(即 transformers 后端,更加方便简单),而 Moe 模型使用 Megatron-SWIFT(即 megatron 后端,更快的训练速度,benchmark查看[这里](../Megatron-SWIFT/Quick-start.md#benchmark))。
|
||||
|
||||
如果您需要自定义数据集微调模型,你可以将数据准备成以下格式,并在命令行中设置`--dataset train.jsonl --val_dataset val.jsonl`,其中验证集为可选。更多介绍请参考[多模态数据集文档](../Customization/Custom-dataset.md#多模态)。
|
||||
```jsonl
|
||||
{"messages": [{"role": "user", "content": "浙江的省会在哪?"}, {"role": "assistant", "content": "浙江的省会在杭州。"}]}
|
||||
{"messages": [{"role": "user", "content": "<image><image>两张图片有什么区别"}, {"role": "assistant", "content": "前一张是小猫,后一张是小狗"}], "images": ["/xxx/x.jpg", "/xxx/x.png"]}
|
||||
{"messages": [{"role": "system", "content": "你是个有用无害的助手"}, {"role": "user", "content": "<image>图片中是什么,<video>视频中是什么"}, {"role": "assistant", "content": "图片中是一个大象,视频中是一只小狗在草地上奔跑"}], "images": ["/xxx/x.jpg"], "videos": ["/xxx/x.mp4"]}
|
||||
```
|
||||
|
||||
Qwen3-VL的bbox输出采用归一化1000的相对坐标。你可以使用 ms-swift 提供的 grounding 数据集格式,其中"bbox"中的坐标为绝对坐标,ms-swift 会自动将绝对坐标转为归一化1000的相对坐标。更多信息请参考[grounding数据集格式文档](../Customization/Custom-dataset.md#grounding)。
|
||||
```jsonl
|
||||
{"messages": [{"role": "user", "content": "<image>找到图像中的<ref-object>"}, {"role": "assistant", "content": "[\n\t{\"bbox_2d\": <bbox>, \"label\": \"<ref-object>\"},\n\t{\"bbox_2d\": <bbox>, \"label\": \"<ref-object>\"}\n]"}], "images": ["cat.png"], "objects": {"ref": ["羊", "羊", "羊"], "bbox": [[90.9, 160.8, 135, 212.8], [360.9, 480.8, 495, 532.8]]}}
|
||||
```
|
||||
|
||||
### Dense模型
|
||||
|
||||
以下提供对`Qwen3-VL-4B-Instruct`模型的微调脚本,我们使用混合模态数据作为Demo数据集,该示例脚本仅作为演示用途。训练显存为2 * 21GiB,训练时间为12分钟。
|
||||
- 若觉得预处理时间太长,你可以将`--packing`去除,或者使用[cached dataset](https://github.com/modelscope/ms-swift/tree/main/examples/train/cached_dataset)。
|
||||
|
||||
```shell
|
||||
# 2 * 21GiB
|
||||
PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True' \
|
||||
IMAGE_MAX_TOKEN_NUM=1024 \
|
||||
VIDEO_MAX_TOKEN_NUM=128 \
|
||||
FPS_MAX_FRAMES=16 \
|
||||
NPROC_PER_NODE=2 \
|
||||
CUDA_VISIBLE_DEVICES=0,1 \
|
||||
swift sft \
|
||||
--model Qwen/Qwen3-VL-4B-Instruct \
|
||||
--dataset 'AI-ModelScope/alpaca-gpt4-data-zh#10000' \
|
||||
'AI-ModelScope/LaTeX_OCR:human_handwrite#5000' \
|
||||
'swift/VideoChatGPT:Generic#2000' \
|
||||
--load_from_cache_file true \
|
||||
--split_dataset_ratio 0.01 \
|
||||
--tuner_type lora \
|
||||
--torch_dtype bfloat16 \
|
||||
--num_train_epochs 1 \
|
||||
--per_device_train_batch_size 1 \
|
||||
--per_device_eval_batch_size 1 \
|
||||
--attn_impl flash_attn \
|
||||
--padding_free true \
|
||||
--learning_rate 1e-4 \
|
||||
--lora_rank 8 \
|
||||
--lora_alpha 32 \
|
||||
--target_modules all-linear \
|
||||
--freeze_vit true \
|
||||
--freeze_aligner true \
|
||||
--packing true \
|
||||
--gradient_checkpointing true \
|
||||
--vit_gradient_checkpointing false \
|
||||
--gradient_accumulation_steps 2 \
|
||||
--eval_steps 100 \
|
||||
--save_steps 100 \
|
||||
--save_total_limit 2 \
|
||||
--logging_steps 5 \
|
||||
--max_length 4096 \
|
||||
--output_dir output \
|
||||
--warmup_ratio 0.05 \
|
||||
--deepspeed zero2 \
|
||||
--dataset_num_proc 4 \
|
||||
--dataloader_num_workers 4
|
||||
```
|
||||
|
||||
训练结束后,我们使用以下脚本对验证集进行推理:
|
||||
```shell
|
||||
PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True' \
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
IMAGE_MAX_TOKEN_NUM=1024 \
|
||||
VIDEO_MAX_TOKEN_NUM=128 \
|
||||
FPS_MAX_FRAMES=16 \
|
||||
swift infer \
|
||||
--adapters output/vx-xxx/checkpoint-xxx \
|
||||
--stream true \
|
||||
--max_new_tokens 2048 \
|
||||
--load_data_args true
|
||||
```
|
||||
|
||||
```
|
||||
--------------------------------------------------
|
||||
[QUERY] Using LaTeX to perform OCR on the image.
|
||||
[LABELS] 1 + \frac { 1 } { 1 ! } + \frac { 1 } { 2 ! } + \frac { 1 } { 3 ! } + \frac { 1 } { 4 ! }
|
||||
[RESPONSE] 1 + \frac { 1 } { 1 ! } + \frac { 1 } { 2 ! } + \frac { 1 } { 3 ! } + \frac { 1 } { 4 ! }
|
||||
--------------------------------------------------
|
||||
[QUERY] What color suit is the man wearing while playing the saxophone on stage?
|
||||
[LABELS] The man is wearing a black suit and white shirt while playing the saxophone on the red-floored stage.
|
||||
[RESPONSE] The man is wearing a black suit while playing the saxophone on stage.
|
||||
--------------------------------------------------
|
||||
...
|
||||
```
|
||||
|
||||
### Moe模型
|
||||
|
||||
|
||||
以下提供对`Qwen3-VL-30B-A3B-Instruct`模型的微调脚本,我们使用 Megatron-SWIFT 进行单机全参数训练。我们同样采用混合数据进行训练,该示例脚本仅作为演示用途。训练所需显存资源为8 * 80GiB,训练时间为20分钟。
|
||||
|
||||
关于 Megatron-SWIFT 的环境安装,请参考[Megatron-SWIFT文档](../Megatron-SWIFT/Quick-start.md)。Megatron-SWIFT 与 ms-swift 共用 template 和 dataset 模块,因此前面介绍的自定义数据集格式和模型特有环境变量依旧生效。
|
||||
|
||||
|
||||
微调脚本如下,训练技巧与并行技术的调整参考[Megatron-SWIFT文档](../Megatron-SWIFT/Quick-start.md#训练技巧)。
|
||||
```shell
|
||||
# 8 * 80GiB
|
||||
PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True' \
|
||||
OMP_NUM_THREADS=14 \
|
||||
NPROC_PER_NODE=8 \
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \
|
||||
IMAGE_MAX_TOKEN_NUM=1024 \
|
||||
VIDEO_MAX_TOKEN_NUM=128 \
|
||||
FPS_MAX_FRAMES=16 \
|
||||
megatron sft \
|
||||
--model Qwen/Qwen3-VL-30B-A3B-Instruct \
|
||||
--save_safetensors true \
|
||||
--dataset 'AI-ModelScope/alpaca-gpt4-data-zh#10000' \
|
||||
'AI-ModelScope/LaTeX_OCR:human_handwrite#5000' \
|
||||
'swift/VideoChatGPT:Generic#2000' \
|
||||
--load_from_cache_file true \
|
||||
--split_dataset_ratio 0.01 \
|
||||
--moe_permute_fusion true \
|
||||
--tensor_model_parallel_size 4 \
|
||||
--expert_model_parallel_size 8 \
|
||||
--moe_grouped_gemm true \
|
||||
--moe_shared_expert_overlap true \
|
||||
--moe_aux_loss_coeff 1e-6 \
|
||||
--micro_batch_size 1 \
|
||||
--global_batch_size 4 \
|
||||
--recompute_granularity full \
|
||||
--recompute_method uniform \
|
||||
--recompute_num_layers 1 \
|
||||
--num_train_epochs 1 \
|
||||
--finetune true \
|
||||
--cross_entropy_loss_fusion true \
|
||||
--lr 1e-5 \
|
||||
--lr_warmup_fraction 0.05 \
|
||||
--min_lr 1e-6 \
|
||||
--output_dir megatron_output/Qwen3-VL-30B-A3B-Instruct \
|
||||
--eval_steps 500 \
|
||||
--save_steps 500 \
|
||||
--max_length 4096 \
|
||||
--packing true \
|
||||
--dataloader_num_workers 8 \
|
||||
--dataset_num_proc 8 \
|
||||
--no_save_optim true \
|
||||
--no_save_rng true \
|
||||
--sequence_parallel true \
|
||||
--moe_expert_capacity_factor 2 \
|
||||
--attention_backend flash
|
||||
```
|
||||
|
||||
训练结束后,我们使用以下脚本对验证集进行推理:
|
||||
```shell
|
||||
PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True' \
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
IMAGE_MAX_TOKEN_NUM=1024 \
|
||||
VIDEO_MAX_TOKEN_NUM=128 \
|
||||
FPS_MAX_FRAMES=16 \
|
||||
swift infer \
|
||||
--model megatron_output/Qwen3-VL-30B-A3B-Instruct/vx-xxx/checkpoint-xxx \
|
||||
--stream true \
|
||||
--max_new_tokens 2048 \
|
||||
--load_data_args true
|
||||
```
|
||||
|
||||
|
||||
使用以下命令将训练权重推送到 Modelscope:
|
||||
```shell
|
||||
swift export \
|
||||
--model output/vx-xxx/checkpoint-xxx \
|
||||
--push_to_hub true \
|
||||
--hub_model_id '<your-model-id>' \
|
||||
--hub_token '<your-sdk-token>'
|
||||
```
|
||||
@@ -0,0 +1,564 @@
|
||||
# Qwen3.5 最佳实践
|
||||
|
||||
ms-swift 支持使用transformers/Megatron后端对[Qwen3.5](https://github.com/QwenLM/Qwen3.5) Dense/Moe模型进行训练。Qwen3.5 属于混合思考的多模态模型,结合了linear attention和full attention。本文将介绍如何对Qwen3.5 Dense/Moe模型进行推理、指令微调以及强化学习。
|
||||
|
||||
|
||||
## 环境设置
|
||||
```shell
|
||||
pip install -U ms-swift
|
||||
pip install -U "transformers>=5.9" "qwen_vl_utils>=0.0.14" peft liger-kernel
|
||||
|
||||
# flash-linear-attention
|
||||
# 若出现训练缓慢的问题请参考:https://github.com/fla-org/flash-linear-attention/issues/758
|
||||
# 请使用python3.12: https://github.com/fla-org/flash-linear-attention/issues/121
|
||||
pip install -U "flash-linear-attention>=0.4.2" --no-build-isolation
|
||||
|
||||
# causal_conv1d
|
||||
pip install -U git+https://github.com/Dao-AILab/causal-conv1d --no-build-isolation
|
||||
|
||||
# flash-attention
|
||||
pip install "flash-attn==2.8.3" --no-build-isolation
|
||||
|
||||
# deepspeed训练
|
||||
pip install deepspeed
|
||||
|
||||
# vllm (torch2.10) for inference/deployment/RL
|
||||
pip install -U "vllm>=0.17.0"
|
||||
```
|
||||
|
||||
- Qwen3.5 视频数据训练卡住:使用decord后端读取视频可能导致卡住问题,参考[这个issue](https://github.com/dmlc/decord/issues/269)。你可以使用torchcodec后端,具体参考[qwen_vl_utils](https://github.com/QwenLM/Qwen3-VL/blob/50068df2334f309979ff05d75f1078c8309c63ed/qwen-vl-utils/src/qwen_vl_utils/vision_process.py#L390-L400)库。
|
||||
- 如果你在昇腾 NPU 上使用 Qwen3.5,并且需要了解 FLA / MindSpeed 的替换关系、补丁生效路径以及版本验证信息,请参考 [NPU支持文档中的 Qwen3.5 FLA补丁说明](./NPU-support.md#qwen35-fla补丁说明)。
|
||||
|
||||
|
||||
## 推理
|
||||
|
||||
使用 ms-swift 的 `TransformersEngine` 进行推理:
|
||||
|
||||
- 其中特定模型参数,例如 `VIDEO_MAX_TOKEN_NUM` 等环境变量的含义与Qwen3-VL相同,参考[命令行参数文档](../Instruction/Command-line-parameters.md#qwen3_vl,qwen3_5)。
|
||||
|
||||
```python
|
||||
import os
|
||||
# os.environ['SWIFT_DEBUG'] = '1'
|
||||
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
|
||||
os.environ['IMAGE_MAX_TOKEN_NUM'] = '1024'
|
||||
os.environ['VIDEO_MAX_TOKEN_NUM'] = '128'
|
||||
os.environ['FPS_MAX_FRAMES'] = '16'
|
||||
|
||||
from swift import get_model_processor, get_template
|
||||
from swift.infer_engine import TransformersEngine, InferRequest, RequestConfig
|
||||
|
||||
model, processor = get_model_processor('Qwen/Qwen3.5-4B') # attn_impl='flash_attention_2'
|
||||
template = get_template(processor, enable_thinking=False)
|
||||
engine = TransformersEngine(model, template=template)
|
||||
infer_request = InferRequest(messages=[{
|
||||
"role": "user",
|
||||
"content": '<video>Describe this video.',
|
||||
}], videos=['https://modelscope-open.oss-cn-hangzhou.aliyuncs.com/images/baby.mp4'])
|
||||
request_config = RequestConfig(max_tokens=128, temperature=0)
|
||||
resp_list = engine.infer([infer_request], request_config=request_config)
|
||||
response = resp_list[0].choices[0].message.content
|
||||
print(response)
|
||||
|
||||
# use stream
|
||||
request_config = RequestConfig(max_tokens=128, temperature=0, stream=True)
|
||||
gen_list = engine.infer([infer_request], request_config=request_config)
|
||||
for chunk in gen_list[0]:
|
||||
if chunk is None:
|
||||
continue
|
||||
print(chunk.choices[0].delta.content, end='', flush=True)
|
||||
print()
|
||||
```
|
||||
|
||||
使用命令行进行推理:
|
||||
|
||||
```shell
|
||||
IMAGE_MAX_TOKEN_NUM=1024 \
|
||||
VIDEO_MAX_TOKEN_NUM=128 \
|
||||
FPS_MAX_FRAMES=16 \
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift infer \
|
||||
--model Qwen/Qwen3.5-4B \
|
||||
--enable_thinking false \
|
||||
--stream true
|
||||
```
|
||||
|
||||
|
||||
## 微调
|
||||
|
||||
本章将介绍如何使用 ms-swift 与 Megatron-SWIFT 训练 Qwen3.5。推荐 Dense 模型使用 ms-swift(即 transformers 后端,更加方便简单),而 Moe 模型使用 Megatron-SWIFT(即 megatron 后端,更快的训练速度)
|
||||
|
||||
如果您需要自定义数据集微调模型,你可以将数据准备成以下格式,并在命令行中设置`--dataset train.jsonl --val_dataset val.jsonl`,其中验证集为可选。更多介绍请参考[多模态数据集文档](../Customization/Custom-dataset.md#多模态)。
|
||||
|
||||
```jsonl
|
||||
{"messages": [{"role": "user", "content": "浙江的省会在哪?"}, {"role": "assistant", "content": "浙江的省会在杭州。"}]}
|
||||
{"messages": [{"role": "user", "content": "<image><image>两张图片有什么区别"}, {"role": "assistant", "content": "前一张是小猫,后一张是小狗"}], "images": ["/xxx/x.jpg", "/xxx/x.png"]}
|
||||
{"messages": [{"role": "system", "content": "你是个有用无害的助手"}, {"role": "user", "content": "<image>图片中是什么,<video>视频中是什么"}, {"role": "assistant", "content": "图片中是一个大象,视频中是一只小狗在草地上奔跑"}], "images": ["/xxx/x.jpg"], "videos": ["/xxx/x.mp4"]}
|
||||
```
|
||||
|
||||
Qwen3.5的bbox输出采用归一化1000的相对坐标。你可以使用 ms-swift 提供的 grounding 数据集格式,其中"bbox"中的坐标为绝对坐标,ms-swift 会自动将绝对坐标转为归一化1000的相对坐标。更多信息请参考[grounding数据集格式文档](../Customization/Custom-dataset.md#grounding)。
|
||||
|
||||
```jsonl
|
||||
{"messages": [{"role": "user", "content": "<image>找到图像中的<ref-object>"}, {"role": "assistant", "content": "[\n\t{\"bbox_2d\": <bbox>, \"label\": \"<ref-object>\"},\n\t{\"bbox_2d\": <bbox>, \"label\": \"<ref-object>\"}\n]"}], "images": ["cat.png"], "objects": {"ref": ["羊", "羊", "羊"], "bbox": [[90.9, 160.8, 135, 212.8], [360.9, 480.8, 495, 532.8]]}}
|
||||
```
|
||||
|
||||
|
||||
### Dense模型
|
||||
|
||||
以下提供对Qwen3.5-4B模型的微调脚本,该示例脚本仅作为演示用途。训练显存为 4 * 20GiB,训练时间为12分钟。Qwen3.5已支持在transformers中使用packing/padding_free(需"ms-swift>=4.3.1",megatron无此版本限制)。下面我们使用group_by_length参数来加速训练,保证DP的负载均衡并减少micro batch中的零填充,但这会导致loss曲线跳动(因数据随机不充分),你也可以去掉此参数并使用`--packing true`代替。
|
||||
- 关于数据预处理:若使用packing/group_by_length参数,则需要对所有数据做提前预处理,获取数据input_ids长度,这需要消耗一定时间。若你希望在训练时处理数据,你可以去除这个两个参数。
|
||||
- 降低显存消耗:可以通过`--deepspeed zero2/zero3`, 开启序列并行`--sequence_parallel_size`,或者使用`--use_liger_kernel true`。
|
||||
- 训练加速:可以开启`--attn_impl flash_attention_2`,MoE模型建议开启`--experts_impl grouped_mm`。
|
||||
|
||||
```shell
|
||||
# 4 * 20GiB
|
||||
PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True' \
|
||||
NPROC_PER_NODE=4 \
|
||||
IMAGE_MAX_TOKEN_NUM=1024 \
|
||||
VIDEO_MAX_TOKEN_NUM=128 \
|
||||
FPS_MAX_FRAMES=12 \
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3 \
|
||||
swift sft \
|
||||
--model Qwen/Qwen3.5-4B \
|
||||
--tuner_type lora \
|
||||
--dataset 'AI-ModelScope/alpaca-gpt4-data-zh#500' \
|
||||
'AI-ModelScope/alpaca-gpt4-data-en#500' \
|
||||
'swift/self-cognition#500' \
|
||||
'AI-ModelScope/LaTeX_OCR:human_handwrite#2000' \
|
||||
--load_from_cache_file true \
|
||||
--add_non_thinking_prefix true \
|
||||
--loss_scale ignore_empty_think \
|
||||
--split_dataset_ratio 0.01 \
|
||||
--torch_dtype bfloat16 \
|
||||
--num_train_epochs 1 \
|
||||
--per_device_train_batch_size 4 \
|
||||
--per_device_eval_batch_size 4 \
|
||||
--learning_rate 1e-4 \
|
||||
--lora_rank 8 \
|
||||
--lora_alpha 32 \
|
||||
--target_modules all-linear \
|
||||
--gradient_accumulation_steps 1 \
|
||||
--group_by_length true \
|
||||
--output_dir output/Qwen3.5-4B \
|
||||
--eval_steps 50 \
|
||||
--save_steps 50 \
|
||||
--save_total_limit 2 \
|
||||
--logging_steps 5 \
|
||||
--max_length 2048 \
|
||||
--warmup_ratio 0.05 \
|
||||
--dataset_num_proc 4 \
|
||||
--dataloader_num_workers 4 \
|
||||
--deepspeed zero2 \
|
||||
--model_author swift \
|
||||
--model_name swift-robot
|
||||
```
|
||||
|
||||
训练结束后,使用以下脚本对验证集进行推理:
|
||||
|
||||
```shell
|
||||
PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True' \
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
IMAGE_MAX_TOKEN_NUM=1024 \
|
||||
VIDEO_MAX_TOKEN_NUM=128 \
|
||||
FPS_MAX_FRAMES=12 \
|
||||
swift infer \
|
||||
--adapters output/Qwen3.5-4B/vx-xxx/checkpoint-xxx \
|
||||
--stream true \
|
||||
--enable_thinking false \
|
||||
--max_new_tokens 512 \
|
||||
--load_data_args true
|
||||
```
|
||||
|
||||
|
||||
```text
|
||||
[QUERY] 你好,你是谁?
|
||||
[RESPONSE] <think>
|
||||
|
||||
</think>
|
||||
|
||||
你好,我是由swift开发的人工智能语言模型,我的名字叫swift-robot。很高兴能与你交流。
|
||||
--------------------------------------------------
|
||||
[QUERY] Using LaTeX to perform OCR on the image.
|
||||
[LABELS] e = \sum _ { k = 0 } ^ { \infty } \frac { 1 } { k ! }
|
||||
[RESPONSE] <think>
|
||||
|
||||
</think>
|
||||
|
||||
e = \sum _ { k = 0 } ^ { \infty } \frac { 1 } { k ! }
|
||||
```
|
||||
|
||||
使用python进行推理:
|
||||
```python
|
||||
import os
|
||||
# os.environ['SWIFT_DEBUG'] = '1'
|
||||
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
|
||||
os.environ['IMAGE_MAX_TOKEN_NUM'] = '1024'
|
||||
os.environ['VIDEO_MAX_TOKEN_NUM'] = '128'
|
||||
os.environ['FPS_MAX_FRAMES'] = '16'
|
||||
|
||||
from peft import PeftModel
|
||||
from swift import get_model_processor, get_template
|
||||
from swift.infer_engine import TransformersEngine, InferRequest, RequestConfig
|
||||
|
||||
adapter_dir = 'output/Qwen3.5-4B/vx-xxx/checkpoint-xxx'
|
||||
enable_thinking = False
|
||||
|
||||
model, processor = get_model_processor('Qwen/Qwen3.5-4B') # attn_impl='flash_attention_2'
|
||||
model = PeftModel.from_pretrained(model, adapter_dir)
|
||||
template = get_template(processor, enable_thinking=enable_thinking)
|
||||
engine = TransformersEngine(model, template=template)
|
||||
infer_request = InferRequest(messages=[{
|
||||
"role": "user",
|
||||
"content": 'who are you?',
|
||||
}])
|
||||
request_config = RequestConfig(max_tokens=128, temperature=0)
|
||||
resp_list = engine.infer([infer_request], request_config=request_config)
|
||||
response = resp_list[0].choices[0].message.content
|
||||
print(response)
|
||||
|
||||
# use stream
|
||||
request_config = RequestConfig(max_tokens=128, temperature=0, stream=True)
|
||||
gen_list = engine.infer([infer_request], request_config=request_config)
|
||||
for chunk in gen_list[0]:
|
||||
if chunk is None:
|
||||
continue
|
||||
print(chunk.choices[0].delta.content, end='', flush=True)
|
||||
print()
|
||||
# I am an artificial intelligence assistant named swift-robot, trained by swift. I am designed to understand and generate natural language text in order to provide information, answer questions, and engage in conversation with humans. How can I assist you?
|
||||
```
|
||||
|
||||
|
||||
使用transformers后端训练MoE的例子参考:https://github.com/modelscope/ms-swift/blob/main/examples/models/qwen3_5/transformers.sh
|
||||
|
||||
### Moe模型
|
||||
Qwen3.5-35B-A3B Megatron训练,环境的准备请参考[Megatron-SWIFT快速开始文档](../Megatron-SWIFT/Quick-start.md)。你可以在15分钟内跑完以下案例:
|
||||
|
||||
```shell
|
||||
# 4 * 40GiB
|
||||
PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True' \
|
||||
NPROC_PER_NODE=4 \
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3 \
|
||||
IMAGE_MAX_TOKEN_NUM=1024 \
|
||||
VIDEO_MAX_TOKEN_NUM=128 \
|
||||
FPS_MAX_FRAMES=12 \
|
||||
megatron sft \
|
||||
--model Qwen/Qwen3.5-35B-A3B \
|
||||
--save_safetensors true \
|
||||
--merge_lora true \
|
||||
--dataset 'AI-ModelScope/alpaca-gpt4-data-zh#500' \
|
||||
'AI-ModelScope/alpaca-gpt4-data-en#500' \
|
||||
'swift/self-cognition#500' \
|
||||
'AI-ModelScope/LaTeX_OCR:human_handwrite#2000' \
|
||||
--load_from_cache_file true \
|
||||
--add_non_thinking_prefix true \
|
||||
--loss_scale ignore_empty_think \
|
||||
--split_dataset_ratio 0.01 \
|
||||
--tuner_type lora \
|
||||
--lora_rank 8 \
|
||||
--lora_alpha 32 \
|
||||
--target_modules all-linear \
|
||||
--expert_model_parallel_size 4 \
|
||||
--moe_permute_fusion true \
|
||||
--moe_grouped_gemm true \
|
||||
--moe_shared_expert_overlap true \
|
||||
--moe_aux_loss_coeff 1e-6 \
|
||||
--micro_batch_size 4 \
|
||||
--global_batch_size 16 \
|
||||
--recompute_granularity full \
|
||||
--recompute_method uniform \
|
||||
--recompute_num_layers 1 \
|
||||
--num_train_epochs 1 \
|
||||
--group_by_length true \
|
||||
--finetune true \
|
||||
--freeze_llm false \
|
||||
--freeze_vit true \
|
||||
--freeze_aligner true \
|
||||
--cross_entropy_loss_fusion true \
|
||||
--lr 1e-4 \
|
||||
--lr_warmup_fraction 0.05 \
|
||||
--min_lr 1e-5 \
|
||||
--output_dir megatron_output/Qwen3.5-35B-A3B \
|
||||
--eval_steps 200 \
|
||||
--save_steps 200 \
|
||||
--max_length 2048 \
|
||||
--dataloader_num_workers 8 \
|
||||
--dataset_num_proc 8 \
|
||||
--no_save_optim true \
|
||||
--no_save_rng true \
|
||||
--sequence_parallel true \
|
||||
--attention_backend flash \
|
||||
--padding_free false \
|
||||
--model_author swift \
|
||||
--model_name swift-robot
|
||||
```
|
||||
训练结束后,使用以下脚本对验证集进行推理:
|
||||
|
||||
```shell
|
||||
PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True' \
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3 \
|
||||
IMAGE_MAX_TOKEN_NUM=1024 \
|
||||
VIDEO_MAX_TOKEN_NUM=128 \
|
||||
FPS_MAX_FRAMES=12 \
|
||||
swift infer \
|
||||
--model megatron_output/Qwen3.5-35B-A3B/vx-xxx/checkpoint-xxx-merged \
|
||||
--stream true \
|
||||
--enable_thinking false \
|
||||
--max_new_tokens 512 \
|
||||
--load_data_args true
|
||||
```
|
||||
|
||||
Megatron-SWIFT训练Qwen3.5的提示:
|
||||
- 全参数训练:参考[这个例子](https://github.com/modelscope/ms-swift/blob/main/examples/models/qwen3_5/packing.sh)。
|
||||
- TP 限制解除:使用 "megatron-core>=0.16" 可解除 TP 受到的 `num_query_groups` 限制。
|
||||
- 关于MTP训练:"mcore-bridge>=1.1.0"支持了多模态MTP的训练。请安装对应版本。
|
||||
- CP支持:"mcore-bridge>=1.1.0"支持了GDN的CP训练,需安装megatron-core [main分支](https://github.com/NVIDIA/Megatron-LM)。
|
||||
- 默认 `GatedDeltaNet` 使用 Megatron 实现,需使用 "megatron-core>=0.16"(ms-swift>=4.1.0,之前版本默认使用transformers实现)。设置环境变量 `USE_MCORE_GDN=0`可切换至 transformers 实现,**transformers实现不支持packing和GDN的TP/CP**。
|
||||
- padding_free/packing的支持:packing可以提升训练速度。参考[这个例子](https://github.com/modelscope/ms-swift/tree/main/examples/models/qwen3_5/packing.sh)。
|
||||
- Qwen3-Next的Megatron GatedDeltaNet支持参考[这个PR](https://github.com/modelscope/mcore-bridge/pull/76),需要"mcore-bridge>=1.4.0"。
|
||||
- apply_wd_to_qk_layernorm: 对 qk layernorm 应用权重衰减。默认为False。
|
||||
- 关于FP8训练:参考[这个例子](https://github.com/modelscope/ms-swift/blob/main/examples/models/qwen3_5/fp8.sh)。你需要安装"mcore-bridge>=1.2.0",并设置参数`--linear_decoupled_in_proj true`,将`in_proj`解耦为`in_proj_qkvz`, `in_proj_ba`,其中`in_proj_ba`仍使用原始精度训练。
|
||||
|
||||
|
||||
## 强化学习(RL)
|
||||
|
||||
以 Qwen3.5-2B 模型为例,下面展示基于 [GSM8K](https://www.modelscope.cn/datasets/modelscope/gsm8k) 数据集进行 GRPO 和 GKD 训练,并以 GSM8K 评测集为标准验证训练效果。为避免模型输出过长的思维链,以下统一设置 `enable_thinking false`。
|
||||
|
||||
### GRPO
|
||||
|
||||
#### Dense 模型
|
||||
使用 GRPO 进行全参数训练,以 `gsm8k_accuracy` 和 `gsm8k_format` 作为奖励函数。奖励函数的实现参考 [gsm8k_plugin.py](https://github.com/modelscope/ms-swift/blob/main/examples/train/grpo/plugin/gsm8k/gsm8k_plugin.py)。
|
||||
|
||||
```shell
|
||||
SYSTEM_PROMPT="""You are a helpful math assistant. Solve the problem step by step and put your final answer within \\boxed{}."""
|
||||
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3 \
|
||||
NPROC_PER_NODE=4 \
|
||||
swift rlhf \
|
||||
--rlhf_type grpo \
|
||||
--model Qwen/Qwen3.5-2B \
|
||||
--external_plugins examples/train/grpo/plugin/gsm8k/gsm8k_plugin.py \
|
||||
--reward_funcs gsm8k_accuracy gsm8k_format \
|
||||
--columns '{"answer": "solution"}' \
|
||||
--enable_thinking false \
|
||||
--use_vllm true \
|
||||
--vllm_mode colocate \
|
||||
--vllm_gpu_memory_utilization 0.4 \
|
||||
--vllm_tensor_parallel_size 1 \
|
||||
--vllm_max_model_len 10240 \
|
||||
--sleep_level 1 \
|
||||
--tuner_type full \
|
||||
--torch_dtype bfloat16 \
|
||||
--dataset 'modelscope/gsm8k' \
|
||||
--load_from_cache_file true \
|
||||
--max_length 2048 \
|
||||
--max_completion_length 8192 \
|
||||
--num_train_epochs 1 \
|
||||
--per_device_train_batch_size 4 \
|
||||
--gradient_accumulation_steps 4 \
|
||||
--learning_rate 1e-6 \
|
||||
--lr_scheduler_type cosine \
|
||||
--save_steps 10 \
|
||||
--save_total_limit 100 \
|
||||
--logging_steps 1 \
|
||||
--warmup_ratio 0.0 \
|
||||
--dataloader_num_workers 4 \
|
||||
--num_generations 8 \
|
||||
--temperature 1.0 \
|
||||
--system "$SYSTEM_PROMPT" \
|
||||
--deepspeed zero2 \
|
||||
--log_completions true \
|
||||
--report_to tensorboard swanlab \
|
||||
--max_grad_norm 1.0 \
|
||||
--epsilon 0.2 \
|
||||
--epsilon_high 0.28 \
|
||||
--scale_rewards none
|
||||
```
|
||||
|
||||
使用以下指令进行评测:
|
||||
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 swift eval \
|
||||
--model output/Qwen3.5-2B/vxx-xxx-xxx/checkpoint-xx \
|
||||
--enable_thinking false \
|
||||
--eval_dataset gsm8k \
|
||||
--eval_backend Native --infer_backend vllm \
|
||||
--eval_generation_config '{"max_tokens":8192,"temperature":0.0,"do_sample":false}'
|
||||
```
|
||||
|
||||
以 10 步为间隔,前 50 步的 GSM8K 评测结果如下:
|
||||
|
||||
| 模型 / Steps | GSM8K Accuracy | 提升 |
|
||||
|---|---|---|
|
||||
| Qwen3.5-2B (baseline) | 0.7597 | - |
|
||||
| GRPO 10 steps | 0.7650 | +0.53 |
|
||||
| GRPO 20 steps | 0.7748 | +1.51 |
|
||||
| GRPO 30 steps | 0.7779 | +1.82 |
|
||||
| GRPO 40 steps | 0.7817 | +2.20 |
|
||||
| GRPO 50 steps | 0.7885 | +2.88 |
|
||||
|
||||
#### MoE 模型
|
||||
|
||||
使用 Megatron 后端对 Qwen3.5-35B-A3B MoE 模型进行 GRPO LoRA 训练,在 [DAPO-Math-17k](https://www.modelscope.cn/datasets/open-r1/DAPO-Math-17k-Processed) 数据集上训练,使用 `accuracy` 作为奖励函数。
|
||||
|
||||
```shell
|
||||
SYSTEM_PROMPT="""You are a helpful math assistant. Solve the problem step by step and put your final answer within \\boxed{}."""
|
||||
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \
|
||||
NPROC_PER_NODE=8 \
|
||||
PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True' \
|
||||
megatron rlhf \
|
||||
--rlhf_type grpo \
|
||||
--model Qwen/Qwen3.5-35B-A3B \
|
||||
--save_safetensors true \
|
||||
--enable_thinking false \
|
||||
--merge_lora true \
|
||||
--context_parallel_size 1 \
|
||||
--tensor_model_parallel_size 1 \
|
||||
--expert_model_parallel_size 8 \
|
||||
--pipeline_model_parallel_size 1 \
|
||||
--moe_permute_fusion true \
|
||||
--dataset open-r1/DAPO-Math-17k-Processed \
|
||||
--system "$SYSTEM_PROMPT" \
|
||||
--num_train_epochs 1 \
|
||||
--global_batch_size 64 \
|
||||
--micro_batch_size 1 \
|
||||
--steps_per_generation 2 \
|
||||
--num_generations 8 \
|
||||
--reward_funcs accuracy \
|
||||
--use_vllm true \
|
||||
--vllm_mode colocate \
|
||||
--vllm_gpu_memory_utilization 0.5 \
|
||||
--vllm_tensor_parallel_size 2 \
|
||||
--vllm_max_model_len 9192 \
|
||||
--max_length 1000 \
|
||||
--max_completion_length 8192 \
|
||||
--tuner_type lora \
|
||||
--target_modules all-linear \
|
||||
--lr 5e-5 \
|
||||
--bf16 true \
|
||||
--beta 0.00 \
|
||||
--epsilon 0.2 \
|
||||
--epsilon_high 0.28 \
|
||||
--dynamic_sample false \
|
||||
--overlong_filter true \
|
||||
--loss_type grpo \
|
||||
--sleep_level 1 \
|
||||
--offload_model true \
|
||||
--offload_bridge false \
|
||||
--offload_optimizer true \
|
||||
--logging_steps 1 \
|
||||
--recompute_granularity full \
|
||||
--recompute_method uniform \
|
||||
--recompute_num_layers 1 \
|
||||
--finetune \
|
||||
--dataloader_num_workers 8 \
|
||||
--dataset_num_proc 8 \
|
||||
--no_save_optim \
|
||||
--no_save_rng \
|
||||
--save_steps 20 \
|
||||
--attention_backend flash \
|
||||
--moe_expert_capacity_factor 2 \
|
||||
--temperature 1.0 \
|
||||
--padding_free false \
|
||||
--sequence_parallel true \
|
||||
--log_completions true \
|
||||
--report_to tensorboard swanlab
|
||||
```
|
||||
|
||||
使用以下指令在 AIME-2025 和 MATH-500 上评测:
|
||||
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0,1 swift eval \
|
||||
--model <checkpoint-merged-path> \
|
||||
--enable_thinking false \
|
||||
--eval_dataset aime25 math_500 \
|
||||
--eval_backend Native --infer_backend vllm \
|
||||
--vllm_tensor_parallel_size 2 \
|
||||
--vllm_gpu_memory_utilization 0.9 \
|
||||
--vllm_max_model_len 10000 \
|
||||
--eval_generation_config '{"max_tokens":8192,"temperature":0.0,"do_sample":false}' \
|
||||
--eval_num_proc 8
|
||||
```
|
||||
|
||||
在 AIME-2025 和 MATH-500 上的评测结果如下:
|
||||
|
||||
| 模型 / Steps | AIME-2025 | MATH-500 |
|
||||
|---|---|---|
|
||||
| Qwen3.5-35B-A3B (baseline) | 43.33 | 92.40 |
|
||||
| Megatron GRPO 20 steps | 53.33 (+10.00) | 95.80 (+3.40) |
|
||||
| Megatron GRPO 40 steps | 53.33 (+10.00) | 96.60 (+4.20) |
|
||||
|
||||
### GKD
|
||||
|
||||
使用 GKD 进行 LoRA 训练,以 Qwen3.5-9B 作为 teacher 模型。首先使用 swift deploy 拉起 teacher server(也可以通过 `--teacher_model` 参数直接加载模型):
|
||||
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift deploy \
|
||||
--model Qwen/Qwen3.5-9B \
|
||||
--infer_backend vllm \
|
||||
--port 8000 \
|
||||
--vllm_tensor_parallel_size 1 \
|
||||
--vllm_max_model_len 10240 \
|
||||
--gpu-memory-utilization 0.8 \
|
||||
--max_logprobs 64
|
||||
```
|
||||
|
||||
然后在其余 GPU 上启动 GKD 训练:
|
||||
|
||||
```shell
|
||||
NPROC_PER_NODE=3 \
|
||||
CUDA_VISIBLE_DEVICES=1,2,3 \
|
||||
swift rlhf \
|
||||
--rlhf_type gkd \
|
||||
--model Qwen/Qwen3.5-2B \
|
||||
--teacher_model_server http://localhost:8000 \
|
||||
--gkd_logits_topk 64 \
|
||||
--enable_thinking false \
|
||||
--tuner_type lora \
|
||||
--use_vllm true \
|
||||
--vllm_mode colocate \
|
||||
--vllm_gpu_memory_utilization 0.5 \
|
||||
--vllm_tensor_parallel_size 1 \
|
||||
--vllm_max_model_len 10240 \
|
||||
--sleep_level 0 \
|
||||
--dataset 'modelscope/gsm8k' \
|
||||
--lmbda 1 \
|
||||
--beta 0.5 \
|
||||
--torch_dtype bfloat16 \
|
||||
--per_device_train_batch_size 2 \
|
||||
--gradient_accumulation_steps 16 \
|
||||
--learning_rate 5e-5 \
|
||||
--logging_steps 1 \
|
||||
--save_steps 100 \
|
||||
--save_total_limit 10 \
|
||||
--max_length 2048 \
|
||||
--max_completion_length 8192 \
|
||||
--warmup_ratio 0.1 \
|
||||
--save_only_model true \
|
||||
--dataloader_num_workers 4 \
|
||||
--dataset_num_proc 4 \
|
||||
--attn_impl flash_attn \
|
||||
--report_to tensorboard swanlab
|
||||
```
|
||||
|
||||
使用以下指令进行评测:
|
||||
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 swift eval \
|
||||
--model Qwen/Qwen3.5-2B \
|
||||
--adapters output/Qwen3.5-2B/vxx-xxx-xxx/checkpoint-xx \
|
||||
--merge_lora true \
|
||||
--enable_thinking false \
|
||||
--eval_dataset gsm8k \
|
||||
--eval_backend Native --infer_backend vllm \
|
||||
--eval_generation_config '{"max_tokens":8192,"temperature":0.0,"do_sample":false}'
|
||||
```
|
||||
|
||||
以 100 步为间隔,前 300 步的 GSM8K 评测结果如下:
|
||||
|
||||
| 模型 / Steps | GSM8K Accuracy | 提升 |
|
||||
|---|---|---|
|
||||
| Qwen3.5-2B (baseline) | 0.7597 | - |
|
||||
| GKD 100 steps | 0.7968 | +3.71 |
|
||||
| GKD 200 steps | 0.8188 | +5.91 |
|
||||
| GKD 300 steps | 0.8332 | +7.35 |
|
||||
@@ -0,0 +1,234 @@
|
||||
# 快速训练VL模型
|
||||
|
||||
本文档提供从零开始快速训练视觉语言(Vision-Language, VL)模型的最佳实践。
|
||||
|
||||
涉及的模型链接:
|
||||
- [Qwen2.5-VL-7B-Instruct](https://www.modelscope.cn/models/Qwen/Qwen2.5-VL-7B-Instruct)
|
||||
- [Qwen3-8B](https://www.modelscope.cn/models/Qwen/Qwen3-8B)
|
||||
|
||||
训练的模型链接:
|
||||
- [Simple-VL-8B](https://www.modelscope.cn/models/swift/Simple-VL-8B/summary)
|
||||
|
||||
|
||||
本训练流程基于 Qwen2.5-VL-7B-Instruct 模型架构,将其内部的语言模型(LLM)部分替换为 Qwen3-8B 的权重,训练模型的视觉理解能力。具体步骤如下:
|
||||
|
||||
1. 修改原始模型的配置文件 config.json,使其适配 Qwen3-8B 的模型结构。
|
||||
2. 初始化并加载新的模型权重,保存为新模型。
|
||||
3. 对新模型进行两阶段微调:
|
||||
1. 第一阶段:仅训练视觉到语言的对齐模块(aligner),冻结 ViT 和 LLM 部分。
|
||||
2. 第二阶段:解冻所有模块,联合训练提升整体性能。
|
||||
|
||||
|
||||
## 模型修改
|
||||
|
||||
### 修改配置文件 config.json
|
||||
因为 Qwen2.5-VL-7B-Instruct 模型的底模 Qwen2.5-7B-Instruct 与 Qwen3-8B 在模型结构上存在部分差异(比如层数,hidden_state_dims),我们首先需要基于Qwen2.5-VL-7B-Instruct的config.json文件,创建一个新的config.json文件,并修改以下参数对齐Qwen3-8B
|
||||
|
||||
```
|
||||
修改
|
||||
1. hidden_size 3584->4096
|
||||
2. intermediate_size: 18944->12288
|
||||
3. num_attention_heads: 28->32
|
||||
4. num_key_value_heads: 4->8
|
||||
5. num_hidden_layers: 28->36
|
||||
6. vocab_size:152064->151936
|
||||
7. max_window_layers:28->36
|
||||
8. out_hidden_size: 3584->4096
|
||||
|
||||
新增
|
||||
1. head_dim: 128
|
||||
```
|
||||
|
||||
### 模型权重初始化与替换
|
||||
使用以下 Python 脚本完成模型权重的初始化、替换与保存:
|
||||
|
||||
```python
|
||||
import torch
|
||||
from modelscope import Qwen2_5_VLForConditionalGeneration, AutoModelForCausalLM, AutoConfig
|
||||
from transformers.models.qwen2_5_vl.modeling_qwen2_5_vl import Qwen2_5_VLPatchMerger, Qwen2_5_VLModel
|
||||
from accelerate import Accelerator
|
||||
|
||||
# 加载原始 VL 模型和 Qwen3-8B 模型
|
||||
qwen2_5_vl_7b_model = Qwen2_5_VLForConditionalGeneration.from_pretrained(
|
||||
"Qwen/Qwen2.5-VL-7B-Instruct",
|
||||
device_map="cuda",
|
||||
torch_dtype=torch.bfloat16
|
||||
)
|
||||
device = qwen2_5_vl_7b_model.device
|
||||
qwen3_8b_model = AutoModelForCausalLM.from_pretrained(
|
||||
"Qwen/Qwen3-8B",
|
||||
device_map=device,
|
||||
torch_dtype=torch.bfloat16
|
||||
)
|
||||
|
||||
# 加载配置
|
||||
old_config = AutoConfig.from_pretrained("Qwen/Qwen2.5-VL-7B-Instruct")
|
||||
new_config = AutoConfig.from_pretrained("/path/to/new_config_dir") # 新 config 的文件夹路径
|
||||
new_visual_config = new_config.vision_config
|
||||
|
||||
# 1. 替换 ViT 到 LLM 的 merger(aligner) 层
|
||||
new_merger = Qwen2_5_VLPatchMerger(
|
||||
dim=new_visual_config.out_hidden_size,
|
||||
context_dim=new_visual_config.hidden_size,
|
||||
spatial_merge_size=new_visual_config.spatial_merge_size,
|
||||
).to(device).to(torch.bfloat16)
|
||||
qwen2_5_vl_7b_model.visual.merger = new_merger
|
||||
|
||||
# 2. 替换 VL 模型的 LLM 部分
|
||||
new_llm_model = Qwen2_5_VLModel(new_config).to(device).to(torch.bfloat16)
|
||||
|
||||
for name, param in qwen3_8b_model.model.named_parameters():
|
||||
if name in new_llm_model.state_dict():
|
||||
new_llm_model.state_dict()[name].copy_(param)
|
||||
|
||||
qwen2_5_vl_7b_model.model = new_llm_model
|
||||
qwen2_5_vl_7b_model.lm_head = qwen3_8b_model.lm_head
|
||||
|
||||
# 3. 保存修改后的模型
|
||||
accelerator = Accelerator()
|
||||
accelerator.save_model(
|
||||
model=qwen2_5_vl_7b_model,
|
||||
save_directory="/path/to/save/Qwen3-VL-Model",
|
||||
max_shard_size="4GB",
|
||||
safe_serialization=True
|
||||
)
|
||||
```
|
||||
|
||||
保存完权重后,将原 Qwen2.5-VL-7B-Instruct 模型文件夹中除模型权重的文件(包括`model.safetensors.index.json`) 复制到新的模型权重文件夹中,并替换 config.json 为新修改的 config.json文件。
|
||||
|
||||
## 训练
|
||||
|
||||
为简化流程,我们跳过预训练(pretrain),直接进入监督微调(SFT)。训练分为两个阶段:
|
||||
|
||||
### stage1 训练 Aligner 层
|
||||
仅训练视觉到语言的对齐层(Aligner),冻结 ViT 和 LLM 部分:
|
||||
|
||||
```bash
|
||||
NNODES=$WORLD_SIZE \
|
||||
NODE_RANK=$RANK \
|
||||
NPROC_PER_NODE=8 \
|
||||
MAX_PIXELS=1003520 \
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \
|
||||
swift sft \
|
||||
--model /path/to/new_vl_model \
|
||||
--model_type qwen2_5_vl \
|
||||
--tuner_type full \
|
||||
--dataset xxx \
|
||||
--load_from_cache_file true \
|
||||
--split_dataset_ratio 0.01 \
|
||||
--torch_dtype bfloat16 \
|
||||
--attn_impl flash_attn \
|
||||
--freeze_vit true \
|
||||
--freeze_llm true \
|
||||
--freeze_aligner false \
|
||||
--num_train_epochs 3 \
|
||||
--per_device_train_batch_size 2 \
|
||||
--learning_rate 5e-6 \
|
||||
--gradient_accumulation_steps 8 \
|
||||
--eval_steps -1 \
|
||||
--save_steps 1000 \
|
||||
--save_total_limit 10 \
|
||||
--logging_steps 5 \
|
||||
--max_length 8192 \
|
||||
--output_dir output \
|
||||
--warmup_ratio 0.05 \
|
||||
--dataloader_num_workers 4 \
|
||||
--dataset_num_proc 8 \
|
||||
--deepspeed zero2
|
||||
```
|
||||
|
||||
### stage2 训练整个模型
|
||||
解冻所有模块,联合训练以增强模型的整体视觉理解能力:
|
||||
|
||||
```bash
|
||||
NNODES=$WORLD_SIZE \
|
||||
NODE_RANK=$RANK \
|
||||
NPROC_PER_NODE=8 \
|
||||
MAX_PIXELS=1003520 \
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \
|
||||
swift sft \
|
||||
--model /path/to/stage1_checkpoint \
|
||||
--model_type qwen2_5_vl \
|
||||
--tuner_type full \
|
||||
--dataset xxx \
|
||||
--load_from_cache_file true \
|
||||
--split_dataset_ratio 0.01 \
|
||||
--torch_dtype bfloat16 \
|
||||
--attn_impl flash_attn \
|
||||
--freeze_vit false \
|
||||
--freeze_llm false \
|
||||
--freeze_aligner false \
|
||||
--num_train_epochs 3 \
|
||||
--per_device_train_batch_size 2 \
|
||||
--learning_rate 5e-6 \
|
||||
--gradient_accumulation_steps 8 \
|
||||
--eval_steps -1 \
|
||||
--save_steps 1000 \
|
||||
--save_total_limit 10 \
|
||||
--logging_steps 5 \
|
||||
--max_length 8192 \
|
||||
--output_dir output \
|
||||
--warmup_ratio 0.05 \
|
||||
--dataloader_num_workers 4 \
|
||||
--dataset_num_proc 8 \
|
||||
--deepspeed zero2
|
||||
```
|
||||
|
||||
## 推理/部署/评测
|
||||
|
||||
### 推理
|
||||
通过`swift infer`来推理训练得到的模型
|
||||
```bash
|
||||
swift infer \
|
||||
--model /path/to/stage2_checkpoint
|
||||
|
||||
```
|
||||
|
||||
### 部署
|
||||
使用 vLLM 加速模型服务部署:
|
||||
|
||||
```
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
MAX_PIXELS=1003520 \
|
||||
VIDEO_MAX_PIXELS=50176 \
|
||||
FPS_MAX_FRAMES=12 \
|
||||
swift deploy \
|
||||
--model /path/to/stage2_checkpoint \
|
||||
--infer_backend vllm \
|
||||
--vllm_gpu_memory_utilization 0.9 \
|
||||
--vllm_max_model_len 8192 \
|
||||
--max_new_tokens 2048 \
|
||||
--vllm_limit_mm_per_prompt '{"image": 5, "video": 2}' \
|
||||
--served_model_name Qwen3-VL
|
||||
```
|
||||
|
||||
### 评测
|
||||
通过 [EvalScope](https://github.com/modelscope/evalscope/) 对训练得到的 VL 模型进行评测
|
||||
|
||||
以下是以 MMMU benchmark 为例的评测代码:
|
||||
```python
|
||||
from evalscope import TaskConfig, run_task
|
||||
|
||||
task_cfg_dict = TaskConfig(
|
||||
work_dir='outputs',
|
||||
eval_backend='VLMEvalKit',
|
||||
eval_config={
|
||||
'data': ['MMMU_DEV_VAL'],
|
||||
'mode': 'all',
|
||||
'model': [
|
||||
{'api_base': 'http://localhost:8000/v1/chat/completions',
|
||||
'key': 'EMPTY',
|
||||
'name': 'CustomAPIModel',
|
||||
'temperature': 0.6,
|
||||
'type': 'Qwen3-VL',
|
||||
'img_size': -1,
|
||||
'video_llm': False,
|
||||
'max_tokens': 512,}
|
||||
],
|
||||
'reuse': False,
|
||||
'nproc': 64,
|
||||
'judge': 'exact_matching'},
|
||||
)
|
||||
|
||||
run_task(task_cfg=task_cfg_dict)
|
||||
```
|
||||
@@ -0,0 +1,128 @@
|
||||
# Reranker训练
|
||||
|
||||
SWIFT已经支持Reranker模型的训练,目前已经支持的模型有:
|
||||
|
||||
1. modernbert reranker模型
|
||||
- [ModelScope](https://www.modelscope.cn/models/iic/gte-reranker-modernbert-base) [Hugging Face](https://huggingface.co/Alibaba-NLP/gte-reranker-modernbert-base)
|
||||
2. qwen3-reranker模型
|
||||
- 0.6B: [ModelScope](https://www.modelscope.cn/models/Qwen/Qwen3-Reranker-0.6B) [Hugging Face](https://huggingface.co/Qwen/Qwen3-Reranker-0.6B)
|
||||
- 4B: [ModelScope](https://www.modelscope.cn/models/Qwen/Qwen3-Reranker-4B) [Hugging Face](https://huggingface.co/Qwen/Qwen3-Reranker-4B)
|
||||
- 8B: [ModelScope](https://www.modelscope.cn/models/Qwen/Qwen3-Reranker-8B) [Hugging Face](https://huggingface.co/Qwen/Qwen3-Reranker-8B)
|
||||
3. qwen3-vl-reranker模型
|
||||
- 2B: [ModelScope](https://www.modelscope.cn/models/Qwen/Qwen3-VL-Reranker-2B) [Hugging Face](https://huggingface.co/Qwen/Qwen3-VL-Reranker-2B)
|
||||
- 8B: [ModelScope](https://www.modelscope.cn/models/Qwen/Qwen3-VL-Reranker-8B) [Hugging Face](https://huggingface.co/Qwen/Qwen3-VL-Reranker-8B)
|
||||
|
||||
## 实现方式
|
||||
|
||||
目前SWIFT支持两种Reranker模型的实现方式,二者在架构和损失函数计算上有显著差异:
|
||||
|
||||
### 1. 分类式Reranker
|
||||
|
||||
**适用模型:** modernbert reranker模型(如gte-reranker-modernbert-base)
|
||||
|
||||
**核心原理:**
|
||||
- 基于序列分类架构,在预训练模型基础上添加分类头
|
||||
- 输入:query-document对,输出:单个相关性分数
|
||||
|
||||
|
||||
### 2. 生成式Reranker
|
||||
|
||||
**适用模型:** qwen3-reranker模型(0.6B/4B/8B)
|
||||
|
||||
**核心原理:**
|
||||
- 基于生成式语言模型架构(CausalLM)
|
||||
- 输入:query-document对,输出:特定token的概率(如"yes"/"no")
|
||||
- 通过对比最后位置特定token的logits进行分类
|
||||
|
||||
## 损失函数类型
|
||||
|
||||
SWIFT支持多种损失函数来训练Reranker模型:
|
||||
|
||||
### Pointwise损失函数
|
||||
Pointwise方法将排序问题转化为二分类问题,独立处理每个query-document对:
|
||||
|
||||
- **核心思想:** 对每个query-document对进行二分类,判断文档是否与查询相关
|
||||
- **损失函数:** 二分类交叉熵
|
||||
- **适用场景:** 简单高效,适合大规模数据训练
|
||||
|
||||
环境变量配置:
|
||||
- `GENERATIVE_RERANKER_POSITIVE_TOKEN`:正例token(默认:"yes")
|
||||
- `GENERATIVE_RERANKER_NEGATIVE_TOKEN`:负例token(默认:"no")
|
||||
|
||||
### Listwise损失函数
|
||||
Listwise方法将排序问题转化为多分类问题,从多个候选文档中选择正例:
|
||||
|
||||
- **核心思想:** 对每个query的候选文档组(1个正例 + n个负例)进行多分类,识别正例文档
|
||||
- **损失函数:** 多分类交叉熵
|
||||
- **适用场景:** 学习文档间的相对排序关系,更符合信息检索的实际需求
|
||||
|
||||
环境变量配置:
|
||||
- `LISTWISE_RERANKER_TEMPERATURE`:softmax温度参数(默认:1.0)
|
||||
- `LISTWISE_RERANKER_MIN_GROUP_SIZE`:最小组大小,如果组内文档数量小于该值,则不计算损失(默认:2)
|
||||
|
||||
**Listwise vs Pointwise:**
|
||||
- **Pointwise:** 独立判断相关性,训练简单,但忽略了文档间的相对关系
|
||||
- **Listwise:** 学习相对排序,性能更优,更适合排序任务的本质需求
|
||||
|
||||
loss的源代码可以在[这里](https://github.com/modelscope/ms-swift/blob/main/swift/loss/mapping.py)找到。
|
||||
|
||||
## 数据集格式
|
||||
|
||||
```json lines
|
||||
# LLM
|
||||
{"messages": [{"role": "user", "content": "query"}], "positive_messages": [[{"role": "assistant", "content": "relevant_doc1"}],[{"role": "assistant", "content": "relevant_doc2"}]], "negative_messages": [[{"role": "assistant", "content": "irrelevant_doc1"}],[{"role": "assistant", "content": "irrelevant_doc2"}], ...]}
|
||||
# MLLM
|
||||
{"messages": [{"role": "user", "content": "<image>query"}], "images": ["/some/images.jpg"], "positive_messages": [[{"role": "assistant", "content": "<image>relevant_doc1"}]], "positive_images": [["/some/positive_images.jpg"]], "negative_messages": [[{"role": "assistant", "content": "<image><image>irrelevant_doc1"}], [{"role": "assistant", "content": "<image>irrelevant_doc2"}]], "negative_images": [["/some/negative_images1.jpg", "/some/negative_images2.jpg"], ["/some/negative_images3.jpg"]]}
|
||||
```
|
||||
|
||||
**字段说明:**
|
||||
- `messages`:查询文本
|
||||
- `positive_messages`:与查询相关的正例文档列表,支持多个正例
|
||||
- `negative_messages`:与查询不相关的负例文档列表,支持多个负例
|
||||
|
||||
**环境变量配置:**
|
||||
- `MAX_POSITIVE_SAMPLES`:每个query的最大正例数量(默认:1)
|
||||
- `MAX_NEGATIVE_SAMPLES`:每个query的最大负例数量(默认:7)
|
||||
|
||||
> 默认会从每条数据中取出`MAX_POSITIVE_SAMPLES`条正样本和`MAX_NEGATIVE_SAMPLES`条负样本,每条正样本会和`MAX_NEGATIVE_SAMPLES`条负样本组成一个group,因此每条数据会扩展成`MAX_POSITIVE_SAMPLES`x`(1 + MAX_NEGATIVE_SAMPLES)`条数据。
|
||||
> 如果数据中正例/负例数量不足,会取全部正例/负例,如果数据中正例和负例数量超过`MAX_POSITIVE_SAMPLES`和`MAX_NEGATIVE_SAMPLES`,会进行随机采样。
|
||||
> **IMPORTANT**:展开后的数据会放在同一个batch中,因此每个设备上的实际批处理大小(effective batch size)将是 `per_device_train_batch_size` × `MAX_POSITIVE_SAMPLES` × (1 + `MAX_NEGATIVE_SAMPLES`)。请注意调整 `per_device_train_batch_size` 以避免显存不足。
|
||||
|
||||
## 脚手架
|
||||
|
||||
SWIFT提供的脚手架训练脚本:
|
||||
|
||||
- [Qwen3-Reranker/Qwen3-VL-Reranker](https://github.com/modelscope/ms-swift/blob/main/examples/train/reranker/qwen3)
|
||||
- [Pointwise分类式Reranker](https://github.com/modelscope/ms-swift/blob/main/examples/train/reranker/train_reranker.sh)
|
||||
- [Pointwise生成式Reranker](https://github.com/modelscope/ms-swift/blob/main/examples/train/reranker/train_generative_reranker.sh)
|
||||
- [Listwise分类式Reranker](https://github.com/modelscope/ms-swift/blob/main/examples/train/reranker/train_reranker_listwise.sh)
|
||||
- [Listwise生成式Reranker](https://github.com/modelscope/ms-swift/blob/main/examples/train/reranker/train_generative_reranker_listwise.sh)
|
||||
|
||||
推理脚本参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/infer/demo_reranker.py)。
|
||||
|
||||
## 高级功能
|
||||
|
||||
- Qwen3-Reranker 自定义 Instruction:
|
||||
- 默认模板如下:
|
||||
|
||||
```text
|
||||
<|im_start|>system
|
||||
Judge whether the Document meets the requirements based on the Query and the Instruct provided. Note that the answer can only be "yes" or "no".<|im_end|>
|
||||
<|im_start|>user
|
||||
<Instruct>: {Instruction}
|
||||
<Query>: {Query}
|
||||
<Document>: {Document}<|im_end|>
|
||||
<|im_start|>assistant
|
||||
<think>
|
||||
|
||||
</think>
|
||||
|
||||
|
||||
```
|
||||
|
||||
- 默认 Instruction:
|
||||
- `Given a web search query, retrieve relevant passages that answer the query`
|
||||
|
||||
- Instruction 优先级(就近覆盖):
|
||||
- `positive_messages`/`negative_messages` 内提供的 `system` > 主 `messages` 的 `system` > 默认 Instruction。
|
||||
- 即:若某个 positive/negative 的消息序列内包含 `system`,则优先使用该条;否则若主 `messages` 含 `system` 则使用之;两者都未提供时,使用默认 Instruction。
|
||||
@@ -0,0 +1,259 @@
|
||||
# DeepSeek-V4 训练支持
|
||||
|
||||
|
||||
目前Megatron-SWIFT支持了DeepSeek-V4的微调与RL支持,包括MTP、FP8等特性。(FP4 blockwise训练暂时不支持,会在加载权重时自动转成FP8/BF16)
|
||||
|
||||
你需要使用Megatron-Core dev分支以及mcore-bridge、ms-swift main分支。
|
||||
|
||||
```shell
|
||||
pip install git+https://github.com/NVIDIA/Megatron-LM.git@dev
|
||||
pip install git+https://github.com/modelscope/mcore-bridge.git
|
||||
pip install git+https://github.com/modelscope/ms-swift.git
|
||||
|
||||
# Megatron-LM在以下commit hash下进行测试
|
||||
# pip install git+https://github.com/NVIDIA/Megatron-LM.git@c6449f0b23be397449f21c0967c5fc90785e55ea
|
||||
```
|
||||
|
||||
## 精度对齐
|
||||
|
||||
- 为了支持精度对齐测试(FP32),你需注释掉[这几行](https://github.com/NVIDIA/Megatron-LM/blob/bd381ac364b5139840f0cba6389db54f2c092e90/megatron/core/transformer/experimental_attention_variant/dsa.py#L41-L43)。
|
||||
|
||||
修改完代码后,测试以下代码,确认无精度对齐问题(测试transformers/megatron forward对齐情况):
|
||||
|
||||
创建mini版本的模型,我们将创建4层:
|
||||
|
||||
```python
|
||||
import os
|
||||
import torch
|
||||
from modelscope.hub.file_download import model_file_download
|
||||
from safetensors.torch import safe_open
|
||||
from swift import safe_snapshot_download
|
||||
|
||||
from mcore_bridge.utils import Fp8Dequantizer, SafetensorLazyLoader, StreamingSafetensorSaver
|
||||
|
||||
model_id = 'deepseek-ai/DeepSeek-V4-Flash-Base'
|
||||
# Some models have the first few layers as dense and the rest as MoE; set this value accordingly
|
||||
model_dir = safe_snapshot_download(model_id, download_model=False)
|
||||
|
||||
loader = SafetensorLazyLoader(model_dir)
|
||||
state_dict = loader.get_state_dict()
|
||||
saver = StreamingSafetensorSaver(save_dir=model_dir)
|
||||
fp8_dequantizer = Fp8Dequantizer() # Used to convert fp8 weights to bf16
|
||||
|
||||
|
||||
def _open_file(self, filename: str):
|
||||
if filename not in self._file_handles:
|
||||
file_path = os.path.join(self.hf_model_dir, filename)
|
||||
tmp_dir = os.path.join(self.hf_model_dir, 'tmp')
|
||||
if not os.path.exists(file_path):
|
||||
file_path = os.path.join(tmp_dir, filename)
|
||||
if not os.path.exists(file_path):
|
||||
file_path = model_file_download(
|
||||
model_id=model_id,
|
||||
file_path=filename,
|
||||
local_dir=tmp_dir,
|
||||
)
|
||||
self._file_handles[filename] = safe_open(file_path, framework='pt')
|
||||
return self._file_handles[filename]
|
||||
|
||||
|
||||
SafetensorLazyLoader._open_file = _open_file # monkey patch (lazy downloading)
|
||||
new_state_dict = {}
|
||||
for k, v in state_dict.items():
|
||||
if k.startswith('layers.'):
|
||||
idx = int(k[len('layers.'):].split('.', 1)[0])
|
||||
if idx >= 4:
|
||||
continue
|
||||
if k.endswith('.scale'):
|
||||
continue
|
||||
elif k.endswith('.weight'):
|
||||
weight_scale_inv = k.replace('.weight', '.scale')
|
||||
if weight_scale_inv in state_dict:
|
||||
v = fp8_dequantizer.convert(v.load(), state_dict[weight_scale_inv].load()).to(torch.bfloat16)
|
||||
new_state_dict[k] = v if isinstance(v, torch.Tensor) else v.load()
|
||||
|
||||
for k, v in new_state_dict.items():
|
||||
saver.add_tensor(k, v)
|
||||
saver.finalize()
|
||||
```
|
||||
然后修改`config.json`:
|
||||
- num_hidden_layers修改为`4`。
|
||||
- compress_ratios修改为`[0, 0, 4, 128, 0]`。
|
||||
- 删除`quantization_config`。
|
||||
|
||||
|
||||
然后创建`test.py`,使用以下命令运行:`CUDA_VISIBLE_DEVICES=0,1,2,3 torchrun --nproc_per_node=4 test.py`。更多参考[自定义Megatron模型文档](https://swift.readthedocs.io/zh-cn/latest/Megatron-SWIFT/Custom-Model.html)。
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
os.environ['SWIFT_TEST_CONVERT_PRECISION'] = '1'
|
||||
|
||||
from swift.megatron import MegatronExportArguments, megatron_export_main
|
||||
from swift import safe_snapshot_download
|
||||
model_id = 'deepseek-ai/DeepSeek-V4-Flash-Base'
|
||||
|
||||
model_dir = safe_snapshot_download(model_id, download_model=False)
|
||||
|
||||
if __name__ == '__main__':
|
||||
megatron_export_main(
|
||||
MegatronExportArguments(
|
||||
model=model_dir,
|
||||
to_mcore=True,
|
||||
attention_backend='flash',
|
||||
tensor_model_parallel_size=1,
|
||||
pipeline_model_parallel_layout='Et*3|t*1mL',
|
||||
pipeline_model_parallel_size=2,
|
||||
expert_model_parallel_size=2,
|
||||
mtp_num_layers=1,
|
||||
test_convert_precision=True,
|
||||
))
|
||||
```
|
||||
|
||||
当出现以下结果时,则表示对齐没有问题,可以进行训练了。
|
||||

|
||||
|
||||
|
||||
## LoRA训练
|
||||
|
||||
BF16精度LoRA训练脚本如下,最后会保存LoRA增量权重和Merge-LoRA后的BF16完整权重。
|
||||
|
||||
```shell
|
||||
PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True' \
|
||||
NPROC_PER_NODE=8 \
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \
|
||||
megatron sft \
|
||||
--model deepseek-ai/DeepSeek-V4-Flash \
|
||||
--save_safetensors true \
|
||||
--dataset 'AI-ModelScope/alpaca-gpt4-data-zh#1000' \
|
||||
'AI-ModelScope/alpaca-gpt4-data-en#1000' \
|
||||
'swift/self-cognition#1000' \
|
||||
--model_author swift \
|
||||
--model_name swift-robot \
|
||||
--merge_lora true \
|
||||
--load_from_cache_file true \
|
||||
--add_non_thinking_prefix true \
|
||||
--loss_scale ignore_empty_think \
|
||||
--split_dataset_ratio 0.01 \
|
||||
--tuner_type lora \
|
||||
--lora_rank 16 \
|
||||
--lora_alpha 32 \
|
||||
--tensor_model_parallel_size 1 \
|
||||
--expert_model_parallel_size 8 \
|
||||
--micro_batch_size 4 \
|
||||
--global_batch_size 32 \
|
||||
--padding_free false \
|
||||
--group_by_length true \
|
||||
--recompute_granularity full \
|
||||
--recompute_method uniform \
|
||||
--recompute_num_layers 1 \
|
||||
--moe_permute_fusion true \
|
||||
--moe_grouped_gemm true \
|
||||
--moe_shared_expert_overlap true \
|
||||
--moe_aux_loss_coeff 1e-3 \
|
||||
--num_train_epochs 1 \
|
||||
--finetune true \
|
||||
--cross_entropy_loss_fusion true \
|
||||
--lr 1e-4 \
|
||||
--lr_warmup_fraction 0.05 \
|
||||
--min_lr 1e-5 \
|
||||
--output_dir megatron_output/DeepSeek-V4-Flash \
|
||||
--eval_steps 200 \
|
||||
--save_steps 200 \
|
||||
--max_length 4096 \
|
||||
--dataloader_num_workers 8 \
|
||||
--dataset_num_proc 8 \
|
||||
--no_save_optim true \
|
||||
--no_save_rng true \
|
||||
--sequence_parallel true \
|
||||
--mtp_num_layers 1 \
|
||||
--attention_backend flash
|
||||
```
|
||||
|
||||
显存占用:
|
||||

|
||||
|
||||
|
||||
训练日志与损失:
|
||||

|
||||
|
||||
提示:
|
||||
- 如果你要设置pp并行,你需要额外设置`pipeline_model_parallel_layout`。例如:
|
||||
```
|
||||
--pipeline_model_parallel_size 2 \
|
||||
--pipeline_model_parallel_layout 'Et*22|t*21mL' \
|
||||
```
|
||||
- 全参数训练也是支持的,你需要降低learning_rate,并提高并行数。参考64卡训练例子:
|
||||
```
|
||||
--lr 1e-5 \
|
||||
--min_lr 1e-6 \
|
||||
--tensor_model_parallel_size 1 \
|
||||
--expert_model_parallel_size 8 \
|
||||
--pipeline_model_parallel_size 8 \
|
||||
--pipeline_model_parallel_layout Et*5|t*5|t*6|t*6|t*6|t*5|t*5|t*5mL \
|
||||
```
|
||||
- Packing/CP的支持:需安装mcore-bridge/ms-swift main分支。参考这两个PR:[ms-swift#9705](https://github.com/modelscope/ms-swift/pull/9705)、[mcore-bridge#140](https://github.com/modelscope/mcore-bridge/pull/140)。若要使用CP,你需要额外设置(需结合packing一起使用`--packing true`,并注意这个PR的合并[megatron-core#5706](https://github.com/NVIDIA/Megatron-LM/pull/5706)):
|
||||
```
|
||||
--sequence_packing_scheduler dp_balanced \
|
||||
--cp_partition_mode contiguous \
|
||||
```
|
||||
- 暂时不支持TP,待Megatron-Core支持。
|
||||
- FP8训练:你可以设置以下参数开启FP8训练,并最终将权重保存成FP8权重。推荐使用全参数训练。如果要使用LoRA + FP8,你需要只保存LoRA权重(设置`--merge_lora false`),并使用BF16权重进行Merge-LoRA(FP8 精度有限,LoRA delta 会被舍入为 0)。参考[这个例子](https://github.com/modelscope/ms-swift/blob/main/examples/megatron/fp8/lora.sh)。
|
||||
```
|
||||
--fp8_recipe blockwise \
|
||||
--fp8_format e4m3 \
|
||||
--fp8_param_gather true \
|
||||
```
|
||||
|
||||
推理训练后的模型:
|
||||
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \
|
||||
swift infer \
|
||||
--model megatron_output/DeepSeek-V4-Flash/vx-xxx/checkpoint-xxx-merged \
|
||||
--infer_backend transformers \
|
||||
--enable_thinking false \
|
||||
--max_new_tokens 2048
|
||||
```
|
||||
|
||||
推理结果:
|
||||
|
||||

|
||||
|
||||
跑通vLLM推理:
|
||||
|
||||
- 如果要使用vllm推理,你可以参考[这里的文档](https://recipes.vllm.ai/deepseek-ai/DeepSeek-V4-Flash)。你需要FP4/FP8精度的权重。
|
||||
- 此外你需要copy原始的'config.json'文件,并修改'expert_dtype'(与训练后的config.json一致)。因为,使用transformers的`config.save_pretrained`保存的文件与原始文件不同,vllm不兼容保存后的文件。
|
||||
- 如果遇到tilelang问题,可以查看[这个issue](https://github.com/modelscope/ms-swift/issues/9494)。
|
||||
- mcore-bridge DeepSeek-V4 Fp8修复:[PR](https://github.com/modelscope/mcore-bridge/pull/133)。
|
||||
|
||||
这里先做量化(这里的量化会导致LoRA增量信息丢失,这里只作为例子,建议使用FP8全参数训练并导出FP8权重):
|
||||
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \
|
||||
NPROC_PER_NODE=8 \
|
||||
megatron export \
|
||||
--model megatron_output/DeepSeek-V4-Flash/vx-xxx/checkpoint-xxx-merged \
|
||||
--output_dir megatron_output/DeepSeek-V4-Flash/vx-xxx/checkpoint-xxx-merged-FP8 \
|
||||
--to_hf true \
|
||||
--fp8_recipe blockwise \
|
||||
--fp8_format e4m3 \
|
||||
--fp8_param_gather true \
|
||||
--mtp_num_layers 1 \
|
||||
--expert_model_parallel_size 8
|
||||
```
|
||||
|
||||
vLLM启动命令:
|
||||
```shell
|
||||
vllm serve megatron_output/DeepSeek-V4-Flash/vx-xxx/checkpoint-xxx-merged-FP8 \
|
||||
--trust-remote-code \
|
||||
--kv-cache-dtype fp8 \
|
||||
--block-size 256 \
|
||||
--enable-expert-parallel \
|
||||
--tensor-parallel-size 8 \
|
||||
--max-model-len 8192 \
|
||||
--tokenizer-mode deepseek_v4 \
|
||||
--tool-call-parser deepseek_v4 \
|
||||
--enable-auto-tool-choice \
|
||||
--reasoning-parser deepseek_v4
|
||||
```
|
||||
@@ -0,0 +1,233 @@
|
||||
# 架构介绍
|
||||
|
||||
ms-swift 4.0 采用模块化设计,各功能模块分布在一级目录下,便于开发者进行自定义扩展。本文档将详细介绍各模块的功能及自定义方法。
|
||||
|
||||
## Agent Template
|
||||
|
||||
agent模板的mapping文件可以参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/agent_template/mapping.py)。agent template设计目标是,基于统一的Agent数据集格式,可以灵活切换不同模型进行训练,无需修改数据。训练时使用`--agent_template`指定对应的agent模板。
|
||||
|
||||
所有的AgentTemplate需要继承自`BaseAgentTemplate`,并实现其中的几个方法: `_format_tools`, `_format_tool_calls`, `_format_tool_responses`, `get_toolcall`。
|
||||
- _format_tools: 将`tools`和`system`格式化,组成完整的system。
|
||||
- _format_tool_calls: 将tool_call部分 `[{"role": "tool_call", "content": "..."}, {"role": "tool_call", "content": "..."}]`进行格式化,最后返回字符串。
|
||||
- _format_tool_responses: 对tool(也称为tool_response)部分 `[{"role": "tool", "content": "..."}, {"role": "tool", "content": "..."}]`进行格式化。
|
||||
- get_toolcall: 在部署的时候使用,用于解析模型输出内容中的工具名和参数,返回`List[Function]`。
|
||||
|
||||
|
||||
如何debug:
|
||||
```python
|
||||
data = {"tools": "[{\"type\": \"function\", \"function\": {\"name\": \"realtime_aqi\", \"description\": \"天气预报。获取实时空气质量。当前空气质量,PM2.5,PM10信息\", \"parameters\": {\"type\": \"object\", \"properties\": {\"city\": {\"type\": \"string\", \"description\": \"城市名,例如:上海\"}}, \"required\": [\"city\"]}}}]", "messages": [{"role": "user", "content": "北京和上海今天的天气情况"}, {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"北京\"}}"}, {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"上海\"}}"}, {"role": "tool_response", "content": "{\"city\": \"北京\", \"aqi\": \"10\", \"unit\": \"celsius\"}"}, {"role": "tool_response", "content": "{\"city\": \"上海\", \"aqi\": \"72\", \"unit\": \"fahrenheit\"}"}, {"role": "assistant", "content": "根据天气预报工具,北京今天的空气质量指数为10,属于良好水平;上海今天的空气质量指数为72,属于轻度污染水平。"}]}
|
||||
|
||||
|
||||
from swift import get_processor, get_template
|
||||
|
||||
tokenizer = get_processor('Qwen/Qwen3.5-2B')
|
||||
template = get_template(tokenizer) # 使用默认agent模板
|
||||
# template = get_template(tokenizer, agent_template='qwen3_5')
|
||||
print(f'agent_template: {template._agent_template}')
|
||||
template.set_mode('train')
|
||||
encoded = template.encode(data)
|
||||
print(f'[INPUT_IDS] {template.safe_decode(encoded["input_ids"])}\n')
|
||||
print(f'[LABELS] {template.safe_decode(encoded["labels"])}')
|
||||
```
|
||||
|
||||
如果你想要给我们提供PR,请参考[这里](https://github.com/modelscope/ms-swift/blob/main/tests/test_align/test_template/test_agent.py)书写你的测试案例。
|
||||
|
||||
## Callbacks
|
||||
|
||||
callbacks的mapping文件可以参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/callbacks/mapping.py)。callbacks可以对trainer中的关键节点的行为进行自定义。自定义后,你需要在mapping中进行注册,训练时使用`--callbacks`指定对应的回调类。例如,你可以自定义:
|
||||
|
||||
```python
|
||||
class CustomCallback(TrainerCallback):
|
||||
|
||||
def on_train_begin(self, args: TrainingArguments, state: TrainerState, control: TrainerControl, **kwargs):
|
||||
# Doing something when the training begins.
|
||||
pass
|
||||
|
||||
def on_save(self, args: TrainingArguments, state: TrainerState, control: TrainerControl, **kwargs):
|
||||
# Doing something when save checkpoint
|
||||
pass
|
||||
```
|
||||
|
||||
所有的回调类需继承自base.py中的`TrainerCallback`,并覆盖其方法。接口与transformers的`TrainerCallback`一致,请参考transformers的[callback文档](https://huggingface.co/docs/transformers/main_classes/callback)。
|
||||
|
||||
|
||||
## Loss
|
||||
|
||||
Loss的mapping文件可以参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/loss/mapping.py)。
|
||||
swift支持自定义loss(当前只支持sft/pretrain/reranker/embedding任务),注册后在训练时设置`--loss_type <loss-name>`使用你定制的loss方法。
|
||||
|
||||
自定义Loss需继承自`BaseLoss`,并实现`__call__`方法,返回标量Tensor。你可以参考[CustomCrossEntropyLoss](https://github.com/modelscope/ms-swift/blob/0d7c9f5bc0e7e7d67d914ce6edeb9ce24f60746f/swift/loss/causal_lm.py#L5)进行定制。例如:
|
||||
|
||||
```python
|
||||
class CustomLoss(BaseLoss):
|
||||
|
||||
def __call__(self, outputs, labels, **kwargs) -> torch.Tensor:
|
||||
pass
|
||||
```
|
||||
|
||||
## Loss Scale
|
||||
|
||||
loss scale的mapping文件可以参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/loss_scale/mapping.py)。在pretrain和sft任务中,可训练token的loss是平均的,即每个token平等地对待。但在某些情况下,某些token需要被额外关注,并设置更高的权重或者对某些token不进行训练。loss_scale可以让开发者自由地定义自己的token权重。(预训练和SFT支持使用loss_scale控制token是否参与训练以及和其权重大小,RLHF中只支持控制token是否参与训练)
|
||||
|
||||
你可以通过继承LossScale基类,并实现`get_loss_scale`方法来自定义loss scale。
|
||||
```python
|
||||
class CustomLossScale(LossScale):
|
||||
|
||||
def get_loss_scale(self, context: str, **kwargs) -> Tuple[List[str], List[float]]:
|
||||
...
|
||||
```
|
||||
`get_loss_scale`函数需要返回了一个Tuple,第一个返回是拆解后的字符串的列表,第二个参数是字符串对应的loss_scale的列表,float值代表了权重。例如下面的权重设置:
|
||||
```text
|
||||
["学习", "好", "数学", "是", "重要", "的"]
|
||||
[1.0, 0.5, 2.0, 0.5, 2.0, 0.1]
|
||||
```
|
||||
例子中,我们更看重数学和重要两个词,因为其loss_scale为2.0。
|
||||
|
||||
|
||||
当然我们也需要关注`__call__`方法的核心逻辑,即loss_scale基本策略(base_strategy)all/default/last_round 对loss_scale的影响,具体参考[命令行参数文档](../Instruction/Command-line-parameters.md)的介绍。以及数据集中的'loss'字段对loss_scale的影响,参考[自定义数据集文档](../Customization/Custom-dataset.md)。
|
||||
```python
|
||||
if loss or loss is None and (self.base_strategy == 'all' or
|
||||
(self.base_strategy == 'default' and is_assistant) or
|
||||
(self.base_strategy == 'last_round' and is_assistant and is_last_round)):
|
||||
new_context, loss_scale = self.get_loss_scale(context, query=query)
|
||||
else:
|
||||
new_context, loss_scale = [context], [0.]
|
||||
```
|
||||
|
||||
此外你也可以使用[json配置文件](https://github.com/modelscope/ms-swift/tree/main/swift/loss_scale/config),继承内置的ConfigLossScale类,来自定义loss_scale。目前支持两种配置方式:字符串精确匹配和正则表达式匹配。你可以参考[Agent支持文档](../Instruction/Agent-support.md#loss_scale的使用)的内容进行理解。
|
||||
|
||||
- 字符串精确匹配,例如参考`react.json`, `qwen.json`。json中需要书写`Dict[str, List[float]]`的映射。字符串代表关键词,列表中需要有两个值。我们会根据关键词,将字符串切分成多段字符串。列表的第一个值代表关键词的权重,列表的第二个值代表该关键值后,下一关键词前的内容的权重。
|
||||
|
||||
- 正则表达式匹配,例如参考`ignore_empty_think.json`, `hermes.json`。json中需要书写`Dict[str, float]`的映射。字符串代表正则表达式pattern,浮点数代表匹配字符串的权重。
|
||||
|
||||
|
||||
如何debug:
|
||||
```python
|
||||
from swift import get_processor, get_template
|
||||
|
||||
data = {"messages": [
|
||||
{"role": "user", "content": "今天的日期是多少?"},
|
||||
{"role": "assistant", "content": (
|
||||
"<think>\n我可以通过调用`get_date`函数来获取当前时间。\n</think>\n"
|
||||
'<tool_call>\n{"name": "get_date", "arguments": {}}\n</tool_call>'
|
||||
)}
|
||||
]}
|
||||
|
||||
template = get_template(get_processor('Qwen/Qwen3-8B'), loss_scale='hermes')
|
||||
template.set_mode('train')
|
||||
inputs = template.encode(data)
|
||||
|
||||
print(template.safe_decode(inputs['labels']))
|
||||
print(inputs['loss_scale'])
|
||||
```
|
||||
|
||||
## Metrics
|
||||
|
||||
metrics的mapping文件可以参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/metrics/mapping.py)。该组件在ms-swift/Megatron-SWIFT中都有被使用。
|
||||
- 如果是在ms-swift中被使用,你需要继承 base.py 中`EvalMetrics`基类,并实现`compute_metrics`函数,返回字典`Dict[str, float]`。你可以参考[NlgMetrics](https://github.com/modelscope/ms-swift/blob/0d7c9f5bc0e7e7d67d914ce6edeb9ce24f60746f/swift/metrics/nlg.py#L33)进行定制。
|
||||
- 如果是在Megatron-SWIFT中被使用,你需要继承 utils.py 中`Metric`基类,并实现`update`和`compute`方法,compute方法需返回字典`Dict[str, float]`。
|
||||
|
||||
你可以自定义metrics(当前只支持sft/pretrain/reranker/embedding任务),在训练时设置`--eval_metric <metric-name>`使用你定制的metrics。
|
||||
|
||||
## Optimizers
|
||||
|
||||
optimizer的mapping文件可以参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/optimizers/mapping.py)。如果你需要自定义优化器,你需要继承`OptimizerCallback`基类,并覆盖`create_optimizer`函数。训练时使用`--optimizer <optimizer-name>`指定自定义的优化器。
|
||||
- 你可以参考[MultimodalOptimizerCallback](https://github.com/modelscope/ms-swift/blob/0d7c9f5bc0e7e7d67d914ce6edeb9ce24f60746f/swift/optimizers/multimodal.py#L43)进行实现,该类实现了vit_lr, aligner_lr的功能,即对vit, aligner和LLM分别使用不同的学习率。
|
||||
|
||||
|
||||
|
||||
## Tuner Plugin
|
||||
|
||||
Tuner插件的mapping文件可以参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/tuner_plugin/mapping.py)。如果你需要自定义tuner,你需要继承`Tuner`基类,并覆盖`prepare_model`, `save_pretrained`, `from_pretrained`函数。
|
||||
- prepare_model: 该函数在训练前被调用,将原始模型进行处理与准备,使用tuner封装,并设置可训练参数。例如:你可以对某些层附加LoRA,对某些层进行冻结等。
|
||||
- save_pretrained: 该函数在训练中被调用,对模型进行保存。
|
||||
- from_pretrained: 该函数在推理/断点续训时被调用,准备模型并读取权重。
|
||||
|
||||
你可以参考[LoRALLMTuner](https://github.com/modelscope/ms-swift/blob/0d7c9f5bc0e7e7d67d914ce6edeb9ce24f60746f/swift/tuner_plugin/lora_llm.py#L24)进行实现,该类实现了对LLM进行LoRA训练,对ViT进行全参数训练的功能。
|
||||
|
||||
|
||||
## ORM
|
||||
|
||||
example参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/rewards/orm.py)。
|
||||
|
||||
ORM是结果奖励模型。ORM一般使用正则表达式来进行,ORM决定了response是否是正确的。例如:
|
||||
|
||||
```python
|
||||
class MathORM(ORM):
|
||||
|
||||
@staticmethod
|
||||
def extract_boxed_result(text):
|
||||
pattern = r'\\boxed{([^}]*)}'
|
||||
match = re.search(pattern, text)
|
||||
if match:
|
||||
return match.group(1).strip()
|
||||
else:
|
||||
return None
|
||||
|
||||
def __call__(self, infer_requests: List[InferRequest], ground_truths: List[str],
|
||||
**kwargs) -> List[float]:
|
||||
rewards = []
|
||||
predictions = [request.messages[-1]['content'] for request in infer_requests]
|
||||
for prediction, ground_truth in zip(predictions, ground_truths):
|
||||
res1 = MathORM.extract_boxed_result(prediction) or ''
|
||||
res2 = MathORM.extract_boxed_result(ground_truth) or ''
|
||||
rewards.append(float(res1.strip() == res2.strip()))
|
||||
|
||||
return rewards
|
||||
|
||||
|
||||
orms = {
|
||||
'math': MathORM,
|
||||
}
|
||||
```
|
||||
|
||||
在上面的代码中,我们定义了一个对数学response进行解析的过程,如果结果相同则返回score为1.0,否则为0.0。和PRM不同,这个类的infer中有一个额外参数`ground_truths`,
|
||||
该参数是对应的infer_requests的实际label(数据集中定义的标准response)。
|
||||
|
||||
|
||||
## PRM
|
||||
|
||||
example参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/rewards/prm.py)。
|
||||
|
||||
PRM是过程奖励模型,PRM会在`swift sample`命令中使用。PRM需要支持的接口比较简单:
|
||||
```python
|
||||
class PRM:
|
||||
|
||||
def __init__(self):
|
||||
# init here
|
||||
pass
|
||||
|
||||
def __call__(self, infer_requests: List[InferRequest], **kwargs) -> List[Union[float, List[float]]]:
|
||||
raise NotImplementedError
|
||||
```
|
||||
|
||||
其中的InferRequest来自于`swift.infer_engine`,返回的`List[Union[float, List[float]]]`,列表中可能是reward也可能是若干reward。开发者可以在infer_requests中拿到queries和responses,并按照自己的方式进行切分,例如:
|
||||
```text
|
||||
Let's think step by step.
|
||||
|
||||
Step1: xxx
|
||||
|
||||
Step2: xxx
|
||||
|
||||
So, the answer is ...
|
||||
```
|
||||
开发者可以在这里对过程进行切分,并按batch传入PRM中进行推理并返回rewards。更通用来说,开发者可以在这里调用一个远端URL,例如一个闭源PRM大模型并返回rewards。
|
||||
|
||||
|
||||
## 其他目录结构介绍
|
||||
|
||||
- arguments: 命令行参数定义,例如:`SftArguments`, `RLHFArguments`等。
|
||||
- cli: swift命令行机制以及启动文件。例如`swift sft ...`等价于`python swift/cli/main.py sft ...`也等价于`python swift/cli/sft.py ...`。
|
||||
- config: deepspeed/fsdp2配置文件。
|
||||
- dataloader: dataloader的实现,包括shard/dispatcher两种方式。
|
||||
- dataset: 数据集相关模块实现,包括数据预处理、packing、流式数据等。内置数据集的注册在`dataset/dataset`和`dataset/data`文件夹内。具体参考[自定义数据集文档](Custom-dataset.md)。
|
||||
- infer_engine: 推理引擎实现。包括transformers/vllm/sglang/lmdeploy为后端的推理引擎实现。
|
||||
- megatron: Megatron-SWIFT 实现。
|
||||
- model: 模型加载与注册。具体参考[自定义模型文档](Custom-model.md),[多模态模型注册最佳实践](../BestPractices/MLLM-Registration.md)。
|
||||
- pipelines: `swift sft/rlhf/infer`等主函数pipeline实现,包括`sft_main/rlhf_main/infer_main`等。
|
||||
- rlhf_trainers: GRPO/GKD/DPO/KTO/RM等算法的Trainer实现。
|
||||
- rollout: RL算法中rollout过程的采样实现。
|
||||
- rewards: RL算法中的奖励函数实现,支持自定义奖励计算逻辑。
|
||||
- template: 对话模板的实现与注册,包含各个任务将messages转换成input_ids的逻辑,以及data_collator相关逻辑。具体参考[自定义模型文档](Custom-model.md),[多模态模型注册最佳实践](../BestPractices/MLLM-Registration.md)。
|
||||
- trainers: 预训练/SFT/Embedding/Reranker/序列分类任务的Trainer实现。
|
||||
- ui: `swift web-ui`界面训练与推理实现。
|
||||
@@ -0,0 +1,427 @@
|
||||
# 自定义数据集
|
||||
|
||||
自定义数据集的接入方法有三种,对预处理函数的控制能力逐渐加强,但接入难度逐步增加。例如,方案一最为方便,但对预处理函数的控制能力最弱,需要预先对数据集进行转换,传入特定格式的数据集:
|
||||
1. 【推荐】直接使用命令行传参的方式接入,即`--dataset <dataset_path1> <dataset_path2>`。这将使用AutoPreprocessor将数据集转换为标准格式(支持4种数据集格式,具体查看下面对AutoPreprocessor的介绍)。你可以使用`--columns`进行列名转换。支持传入csv、json、jsonl、txt、文件夹(例如git clone开源数据集)。该方案不需要修改dataset_info.json,适合刚接触ms-swift的用户,下面两种方案适合对ms-swift进行拓展的开发者。
|
||||
2. 添加数据集到`dataset_info.json`中,可以参考ms-swift内置的[dataset_info.json](https://github.com/modelscope/ms-swift/blob/main/swift/dataset/data/dataset_info.json)。该方案也将使用AutoPreprocessor将数据集转换为标准格式。dataset_info.json为数据集元信息的list,每一项元信息必填ms_dataset_id/hf_dataset_id/dataset_path中的一项,通过`columns`字段进行列名转换。添加到`dataset_info.json`或者注册的数据集在运行[run_dataset_info.py](https://github.com/modelscope/ms-swift/blob/main/scripts/utils/run_dataset_info.py)时将自动产生[支持的数据集文档](https://swift.readthedocs.io/zh-cn/latest/Instruction/Supported-models-and-datasets.html)。此外,你可以采用外接`dataset_info.json`的方式,使用`--custom_dataset_info xxx.json`解析json文件(方便pip install而非git clone的用户),然后指定`--dataset <dataset_id/dataset_dir/dataset_path>`。
|
||||
3. 手动注册数据集,具有最灵活的预处理函数定制能力,支持使用函数对数据集进行预处理,但难度较高。可以参考[内置数据集](https://github.com/modelscope/ms-swift/blob/main/swift/dataset/dataset/llm.py)或者[examples](https://github.com/modelscope/ms-swift/blob/main/examples/custom)中的样例。你可以通过指定`--external_plugins xxx.py`解析外置注册内容(方便pip install而非git clone的用户)。
|
||||
- 方案一和二在实现中借助了方案三,只是注册的过程为自动发生。
|
||||
|
||||
以下将对`AutoPreprocessor`可以处理的数据集格式进行介绍:
|
||||
|
||||
ms-swift的标准数据集格式可接受的keys包括: 'messages'、'rejected_response'、'label'、'images'、'videos'、'audios'、'tools'和'objects'。其中'messages'是必需的key,'rejected_response'用于DPO等RLHF训练,'label'用于KTO训练和分类模型训练,'images'、'videos'、'audios'用于存储多模态数据的路径或者url,'tools'用于Agent任务,'objects'用于grounding任务。
|
||||
|
||||
ms-swift中存在三种核心预处理器:`MessagesPreprocessor`、`AlpacaPreprocessor`、`ResponsePreprocessor`。MessagesPreprocessor用于将类messages和sharegpt格式的数据集转换为标准格式,AlpacaPreprocessor则转换alpaca格式的数据集,ResponsePreprocessor则转换类query/response格式的数据集。`AutoPreprocessor`则自动选择合适的预处理进行处理。
|
||||
|
||||
以下四种格式在`AutoPreprocessor`处理下都会转换成ms-swift标准格式中的messages字段,即都可以直接使用`--dataset <dataset-path>`接入:
|
||||
|
||||
messages格式(标准格式):
|
||||
```jsonl
|
||||
{"messages": [{"role": "system", "content": "<system>"}, {"role": "user", "content": "<query1>"}, {"role": "assistant", "content": "<response1>"}, {"role": "user", "content": "<query2>"}, {"role": "assistant", "content": "<response2>"}]}
|
||||
```
|
||||
- 注意:system部分是可选的。数据集中的system优先级高于命令行传入的`--system`,最后是定义在template中的`default_system`。
|
||||
|
||||
sharegpt格式:
|
||||
```jsonl
|
||||
{"system": "<system>", "conversation": [{"human": "<query1>", "assistant": "<response1>"}, {"human": "<query2>", "assistant": "<response2>"}]}
|
||||
```
|
||||
|
||||
query-response格式:
|
||||
```jsonl
|
||||
{"system": "<system>", "query": "<query2>", "response": "<response2>", "history": [["<query1>", "<response1>"]]}
|
||||
```
|
||||
注意:以下字段会自动转成对应的system、query、response字段。(solution字段会保留)
|
||||
- system: 'system', 'system_prompt'.
|
||||
- query: 'query', 'prompt', 'input', 'instruction', 'question', 'problem'.
|
||||
- response: 'response', 'answer', 'output', 'targets', 'target', 'answer_key', 'answers', 'solution', 'text', 'completion', 'content'.
|
||||
|
||||
alpaca格式:
|
||||
```jsonl
|
||||
{"system": "<system>", "instruction": "<query-inst>", "input": "<query-input>", "output": "<response>"}
|
||||
```
|
||||
- 注意:instruction和input字段将组合成query字段。若instruction和input不等于空字符串,`query = f'{instruction}\n{input}'`
|
||||
|
||||
|
||||
## 标准数据集格式
|
||||
|
||||
以下给出ms-swift的标准数据集格式,其中system字段是可选的,默认使用template中定义的`default_system`。之前介绍的4种数据集格式也可以被AutoPreprocessor处理成标准数据集格式。
|
||||
|
||||
### 预训练
|
||||
|
||||
```jsonl
|
||||
{"messages": [{"role": "assistant", "content": "I love music"}]}
|
||||
{"messages": [{"role": "assistant", "content": "教练我要打篮球"}]}
|
||||
{"messages": [{"role": "assistant", "content": "西红柿鸡蛋盖饭和地三鲜盖饭哪个更权威"}]}
|
||||
```
|
||||
|
||||
### 监督微调
|
||||
|
||||
```jsonl
|
||||
{"messages": [{"role": "system", "content": "你是个有用无害的助手"}, {"role": "user", "content": "告诉我明天的天气"}, {"role": "assistant", "content": "明天天气晴朗"}]}
|
||||
{"messages": [{"role": "system", "content": "你是个有用无害的数学计算器"}, {"role": "user", "content": "1+1等于几"}, {"role": "assistant", "content": "等于2"}, {"role": "user", "content": "再加1呢"}, {"role": "assistant", "content": "等于3"}]}
|
||||
```
|
||||
|
||||
- 可以通过增加"loss"字段,控制对应的模型回复部分("role"为"assistant")是否计算损失。默认该字段为None。若"loss"设置为true,则对应content进行损失计算(具体loss_scale依旧由`--loss_scale`决定);若"loss"设置为false,则对应content不进行损失计算。需要注意的是,该功能只对"role"为"assistant"的部分生效;该功能优先级高于命令行参数 `--loss_scale`的基本策略(即'default'、'last_round'、'all'部分),例如,loss_scale为`'default+ignore_empty_think'`时,"loss"字段优先级高于"default",但'ignore_empty_think'依旧发挥作用。
|
||||
- 可以通过增加"loss_scale"字段,控制对应的模型回复部分("role"为"assistant")的loss_scale。(ms-swift>=4.2.0)默认为None。该功能优先级高于命令行参数 `--loss_scale`的其他策略部分,例如:'ignore_empty_think', 'hermes'等。当loss_scale中有`>1`的数字出现时,你需要额外设置`--is_binary_loss_scale false`参数。
|
||||
```jsonl
|
||||
{"messages": [{"role": "user", "content": "你好"}, {"role": "assistant", "content": "你好,有什么可以帮助你的吗?", "loss": false}, {"role": "user", "content": "1+1等于几?"}, {"role": "assistant", "content": "等于2", "loss": true}]}
|
||||
{"messages": [{"role": "user", "content": "hello!"}, {"role": "assistant", "content": "<think>\n...\n</think>\n", "loss_scale": 1.0}, {"role": "assistant", "content": "hi!", "loss_scale": 2.0}, {"role": "user", "content": "1+1=?"}, {"role": "assistant", "content": "<think>\n...\n</think>\n1+1=3", "loss": false}]}
|
||||
```
|
||||
|
||||
使用以下脚本进行测试:
|
||||
|
||||
```python
|
||||
from swift import get_processor, get_template
|
||||
|
||||
data = {"messages": [
|
||||
{"role": "user", "content": "hello!"},
|
||||
{"role": "assistant", "content": "<think>\n...\n</think>\n", "loss_scale": 1.},
|
||||
{"role": "assistant", "content": "hi!", "loss_scale": 2.},
|
||||
{"role": "user", "content": "1+1=?"},
|
||||
{"role": "assistant", "content": "<think>\n...\n</think>\n1+1=3", "loss": False},
|
||||
]}
|
||||
|
||||
template = get_template(get_processor('Qwen/Qwen3-8B'), loss_scale='default+ignore_empty_think',
|
||||
is_binary_loss_scale=False)
|
||||
template.set_mode('train')
|
||||
inputs = template.encode(data)
|
||||
|
||||
print(template.safe_decode(inputs['labels']))
|
||||
print(inputs['loss_scale'])
|
||||
```
|
||||
|
||||
注意:如果对messages中连续的"tool_call"设置"loss"/"loss_scale",则只生效最前面"tool_call"的配置。例如:
|
||||
```jsonl
|
||||
{"messages": [..., {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"北京\"}}", "loss": false}, {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"上海\"}}"}, ...]}
|
||||
```
|
||||
|
||||
- "chat_template_kwargs"字段,(需ms-swift>=4.3.0),你可以通过在数据集中传入该字段**样本级别**控制template的min_pixels, max_pixels, fps等多模态参数,以及enable_thinking(推理时)等参数。以下为不同模型支持的参数:
|
||||
- 其中"enable_thinking", "preserve_thinking", "response_prefix"支持所有模型(推理时生效);"max_pixels"参数支持所有多模态模型。
|
||||
- Qwen系列多模态模型:min_pixels, max_pixels, fps等qwen_vl_utils/qwen_omni_utils支持的参数。
|
||||
```jsonl
|
||||
{"messages": [{"role": "user", "content": "<image>这是什么"}, {"role": "assistant", "content": "这是一只兔子", "loss": false}], "chat_template_kwargs": {"max_pixels": 1048576}}
|
||||
{"messages": [{"role": "user", "content": "who are you?"}], "chat_template_kwargs": {"enable_thinking": false}}
|
||||
```
|
||||
|
||||
#### channel loss
|
||||
如果你要使用channel loss,你需要设置`--enable_channel_loss true`,并在数据集中增加"channel"字段。channel loss兼容packing/padding_free/loss_scale等技术。
|
||||
|
||||
```jsonl
|
||||
{"messages": [{"role": "system", "content": "你是个有用无害的助手"}, {"role": "user", "content": "告诉我明天的天气"}, {"role": "assistant", "content": "明天天气晴朗"}], "channel": "general"}
|
||||
{"messages": [{"role": "system", "content": "你是个有用无害的数学计算器"}, {"role": "user", "content": "1+1等于几"}, {"role": "assistant", "content": "等于2"}, {"role": "user", "content": "再加1呢"}, {"role": "assistant", "content": "等于3"}], "channel": "math"}
|
||||
```
|
||||
|
||||
### RLHF
|
||||
|
||||
#### DPO/ORPO/CPO/SimPO/RM
|
||||
|
||||
```jsonl
|
||||
{"messages": [{"role": "system", "content": "你是个有用无害的助手"}, {"role": "user", "content": "告诉我明天的天气"}, {"role": "assistant", "content": "明天天气晴朗"}], "rejected_response": "我不知道"}
|
||||
{"messages": [{"role": "system", "content": "你是个有用无害的数学计算器"}, {"role": "user", "content": "1+1等于几"}, {"role": "assistant", "content": "等于2"}, {"role": "user", "content": "再加1呢"}, {"role": "assistant", "content": "等于3"}], "rejected_response": "我不知道"}
|
||||
```
|
||||
|
||||
多模态数据的格式参考[多模态数据集](#多模态), 额外加入如`images`的列表示其他模态输入。当需要为偏好对数据关联不同的图片信息时,可通过`rejected_images`字段标注拒绝回答对应的图片信息。
|
||||
对齐数据集中要求`rejected_images`和`rejected_response`至少提供一个。
|
||||
|
||||
> 注: RM 额外支持 margin 列,参考[RM文档](../Instruction/RLHF.md#rm)
|
||||
|
||||
当然,你也可以直接使用`rejected_messages`,而不是只提供`rejected_response`/`rejected_images`,这将提供更大的灵活度(例如多模态/agent场景)。若使用rejected_messages,在多模态场景下,你需要额外传入"rejected_images","rejected_audios","rejected_videos"等内容;在Agent场景下,你需要额外传入"rejected_tools"等内容。多模态数据格式例子如下:
|
||||
- 若使用`rejected_response`,'rejected_images/rejected_audios/rejected_videos/rejected_tools'的默认值为'images/audios/videos/tools';若使用`rejected_messages`,则需要额外传入。
|
||||
|
||||
```jsonl
|
||||
{"messages": [{"role": "user", "content": "<image>这是什么"}, {"role": "assistant", "content": "这是一只小猫咪。"}], "images": ["cat.png"], "rejected_messages": [{"role": "user", "content": "<image>这是什么"}, {"role": "assistant", "content": "这是一只小狗。"}], "rejected_images": ["cat.png"]}
|
||||
{"messages": [{"role": "user", "content": "<image>这是什么"}, {"role": "assistant", "content": "这是一只小猫咪。"}], "images": ["cat.png"], "rejected_messages": [{"role": "user", "content": "<image>这是什么"}, {"role": "assistant", "content": "这是一只小猫咪。"}], "rejected_images": ["dog.png"]}
|
||||
```
|
||||
|
||||
以上格式等价于:
|
||||
```jsonl
|
||||
{"messages": [{"role": "user", "content": "<image>这是什么"}, {"role": "assistant", "content": "这是一只小猫咪。"}], "images": ["cat.png"], "rejected_response": "这是一只小狗。"}
|
||||
{"messages": [{"role": "user", "content": "<image>这是什么"}, {"role": "assistant", "content": "这是一只小猫咪。"}], "images": ["cat.png"], "rejected_images": ["dog.png"]}
|
||||
# 例子一也可写成:
|
||||
{"messages": [{"role": "user", "content": "<image>这是什么"}, {"role": "assistant", "content": "这是一只小猫咪。"}], "images": ["cat.png"], "rejected_response": [{"role": "assistant", "content": "这是一只小狗。"}]}
|
||||
```
|
||||
|
||||
你也可以将Agent数据集组织成以下形式:
|
||||
```jsonl
|
||||
# 会寻找`messages`最后一个user的位置,并替换之后的内容为`rejected_response`组成`rejected_messages`
|
||||
{"tools": "[{\"type\": \"function\", \"function\": {\"name\": \"realtime_aqi\", \"description\": \"天气预报。获取实时空气质量。当前空气质量,PM2.5,PM10信息\", \"parameters\": {\"type\": \"object\", \"properties\": {\"city\": {\"type\": \"string\", \"description\": \"城市名,例如:上海\"}}, \"required\": [\"city\"]}}}]", "messages": [{"role": "user", "content": "北京和上海今天的天气情况"}, {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"北京\"}}"}, {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"上海\"}}"}, {"role": "tool_response", "content": "{\"city\": \"北京\", \"aqi\": \"10\", \"unit\": \"celsius\"}"}, {"role": "tool_response", "content": "{\"city\": \"上海\", \"aqi\": \"72\", \"unit\": \"fahrenheit\"}"}, {"role": "assistant", "content": "根据天气预报工具,北京今天的空气质量指数为10,属于良好水平;上海今天的空气质量指数为72,属于轻度污染水平。"}], "rejected_response": [{"role": "assistant", "content": "我不知道。"}]}
|
||||
```
|
||||
|
||||
如何debug:
|
||||
|
||||
```python
|
||||
from swift import get_processor, get_template
|
||||
|
||||
data = {"tools": "[{\"type\": \"function\", \"function\": {\"name\": \"realtime_aqi\", \"description\": \"天气预报。获取实时空气质量。当前空气质量,PM2.5,PM10信息\", \"parameters\": {\"type\": \"object\", \"properties\": {\"city\": {\"type\": \"string\", \"description\": \"城市名,例如:上海\"}}, \"required\": [\"city\"]}}}]", "messages": [{"role": "user", "content": "北京和上海今天的天气情况"}, {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"北京\"}}"}, {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"上海\"}}"}, {"role": "tool_response", "content": "{\"city\": \"北京\", \"aqi\": \"10\", \"unit\": \"celsius\"}"}, {"role": "tool_response", "content": "{\"city\": \"上海\", \"aqi\": \"72\", \"unit\": \"fahrenheit\"}"}, {"role": "assistant", "content": "根据天气预报工具,北京今天的空气质量指数为10,属于良好水平;上海今天的空气质量指数为72,属于轻度污染水平。"}], "rejected_response": [{"role": "assistant", "content": "我不知道。"}]}
|
||||
|
||||
template = get_template(get_processor('Qwen/Qwen3.5-4B'), loss_scale='last_round')
|
||||
template.set_mode('rlhf') # 具体查看命令行文档 `template_mode` 参数的介绍
|
||||
inputs = template.encode(data)
|
||||
|
||||
print(template.safe_decode(inputs['chosen_labels']))
|
||||
print(template.safe_decode(inputs['rejected_labels']))
|
||||
```
|
||||
|
||||
#### KTO
|
||||
|
||||
```jsonl
|
||||
{"messages": [{"role": "system", "content": "你是个有用无害的助手"}, {"role": "user", "content": "告诉我明天的天气"}, {"role": "assistant", "content": "我不知道"}], "label": false}
|
||||
{"messages": [{"role": "system", "content": "你是个有用无害的数学计算器"}, {"role": "user", "content": "1+1等于几"}, {"role": "assistant", "content": "等于2"}, {"role": "user", "content": "再加1呢"}, {"role": "assistant", "content": "等于3"}], "label": true}
|
||||
```
|
||||
|
||||
#### PPO/GRPO
|
||||
|
||||
```jsonl
|
||||
{"messages": [{"role": "system", "content": "你是个有用无害的助手"}, {"role": "user", "content": "告诉我明天的天气"}]}
|
||||
{"messages": [{"role": "system", "content": "你是个有用无害的数学计算器"}, {"role": "user", "content": "1+1等于几"}, {"role": "assistant", "content": "等于2"}, {"role": "user", "content": "再加1呢"}]}
|
||||
{"messages": [{"role": "user", "content": "你的名字是什么"}]}
|
||||
```
|
||||
- 注意:GRPO会透传所有额外的字段内容给ORM,而不像其他训练方法,默认将额外的字段删除。例如: 你可以额外传入'solution'。自定义的ORM需要包含一个位置参数completions,其他为关键词参数,由数据集额外字段透传。
|
||||
|
||||
#### GKD
|
||||
数据集格式如下
|
||||
```jsonl
|
||||
{"messages": [{"role": "system", "content": "你是个有用无害的助手"}, {"role": "user", "content": "告诉我明天的天气"}, {"role": "assistant", "content": "明天天气晴朗"}]}
|
||||
{"messages": [{"role": "system", "content": "你是个有用无害的数学计算器"}, {"role": "user", "content": "1+1等于几"}, {"role": "assistant", "content": "等于2"}, {"role": "user", "content": "再加1呢"}, {"role": "assistant", "content": "等于3"}]}
|
||||
```
|
||||
|
||||
若是在线生成训练(lmbda>0),不需要response部分(学生模型在线生成,数据集中的response部分会被删除)
|
||||
```jsonl
|
||||
{"messages": [{"role": "system", "content": "你是个有用无害的助手"}, {"role": "user", "content": "告诉我明天的天气"}]}
|
||||
{"messages": [{"role": "system", "content": "你是个有用无害的数学计算器"}, {"role": "user", "content": "1+1等于几"}, {"role": "assistant", "content": "等于2"}, {"role": "user", "content": "再加1呢"}]}
|
||||
```
|
||||
|
||||
### 序列分类
|
||||
|
||||
**单标签任务**:
|
||||
```jsonl
|
||||
{"messages": [{"role": "user", "content": "今天天气真好呀"}], "label": 1}
|
||||
{"messages": [{"role": "user", "content": "今天真倒霉"}], "label": 0}
|
||||
{"messages": [{"role": "user", "content": "好开心"}], "label": 1}
|
||||
```
|
||||
**多标签任务**:
|
||||
```jsonl
|
||||
{"messages": [{"role": "user", "content": "<sentence>"}], "label": []}
|
||||
{"messages": [{"role": "user", "content": "<sentence>"}], "label": [0, 2]}
|
||||
{"messages": [{"role": "user", "content": "<sentence>"}], "label": [1, 3, 5]}
|
||||
```
|
||||
|
||||
**单回归任务**:
|
||||
```jsonl
|
||||
{"messages": [{"role": "user", "content": "求两句话的相似度,范围为0-1。\nsentence1: <sentence1>\nsentence2: <sentence2>"}], "label": 0.8}
|
||||
```
|
||||
**多回归任务**:
|
||||
|
||||
```jsonl
|
||||
{"messages": [{"role": "user", "content": "<sentence>"}], "label": [1.2, -0.6, 0.8]}
|
||||
```
|
||||
|
||||
### Embedding
|
||||
|
||||
请参考[embedding训练文档](../BestPractices/Embedding.md#数据集格式)
|
||||
|
||||
### Reranker
|
||||
|
||||
请参考[Reranker训练文档](../BestPractices/Reranker.md#数据集格式)
|
||||
|
||||
### 多模态
|
||||
|
||||
对于多模态数据集,和上述任务的格式相同。区别在于增加了`images`, `videos`, `audios`几个key,分别代表多模态资源的url或者path(推荐使用绝对路径),`<image>` `<video>` `<audio>`标签代表了插入图片/视频/音频的位置,ms-swift支持多图片/视频/音频的情况。这些特殊tokens将在预处理的时候进行替换,参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/template/templates/qwen.py#L198)。下面给出的四条示例分别展示了纯文本,以及包含图像、视频和音频数据的数据格式。
|
||||
|
||||
预训练:
|
||||
```
|
||||
{"messages": [{"role": "assistant", "content": "预训练的文本在这里"}]}
|
||||
{"messages": [{"role": "assistant", "content": "<image>是一只小狗,<image>是一只小猫"}], "images": ["/xxx/x.jpg", "/xxx/x.png"]}
|
||||
{"messages": [{"role": "assistant", "content": "<audio>描述了今天天气真不错"}], "audios": ["/xxx/x.wav"]}
|
||||
{"messages": [{"role": "assistant", "content": "<image>是一个大象,<video>是一只狮子在跑步"}], "images": ["/xxx/x.jpg"], "videos": ["/xxx/x.mp4"]}
|
||||
```
|
||||
|
||||
微调:
|
||||
```jsonl
|
||||
{"messages": [{"role": "user", "content": "浙江的省会在哪?"}, {"role": "assistant", "content": "浙江的省会在杭州。"}]}
|
||||
{"messages": [{"role": "user", "content": "<image><image>两张图片有什么区别"}, {"role": "assistant", "content": "前一张是小猫,后一张是小狗"}], "images": ["/xxx/x.jpg", "/xxx/x.png"]}
|
||||
{"messages": [{"role": "user", "content": "<audio>语音说了什么"}, {"role": "assistant", "content": "今天天气真好呀"}], "audios": ["/xxx/x.mp3"]}
|
||||
{"messages": [{"role": "system", "content": "你是个有用无害的助手"}, {"role": "user", "content": "<image>图片中是什么,<video>视频中是什么"}, {"role": "assistant", "content": "图片中是一个大象,视频中是一只小狗在草地上奔跑"}], "images": ["/xxx/x.jpg"], "videos": ["/xxx/x.mp4"]}
|
||||
```
|
||||
- 注意:以下字段会自动转成对应的images, videos, audios字段。
|
||||
- images: image, images.
|
||||
- videos: video, videos.
|
||||
- audios: audio, audios.
|
||||
- 如果需要传入base64格式而不是文件路径,以下为样本例子:`"videos": ['data:video/mp4;base64,{base64_encoded}']`, `"images": ['data:image/jpg;base64,{base64_encoded}']`。
|
||||
- 若你希望直接传入视频帧,而不是视频,你可以使用以下格式:`"videos": [["/xxx/x.png", "/xxx/y.png"], ["/xxx/a.png", "/xxx/b.png", "/xxx/c.png"]]`。该格式只有部分模型支持,包括Qwen2/2.5/3-VL、Qwen2.5/3-Omni以及其衍生模型。
|
||||
|
||||
多模态模型的RLHF和序列分类的数据格式可以参考纯文本大模型的格式,并在此基础上增加`images`等字段。
|
||||
|
||||
#### grounding
|
||||
|
||||
如果是grounding(物体检测)任务,ms-swift支持两种方式:
|
||||
1. 直接使用对应模型grounding任务的数据集格式,例如qwen2-vl的格式如下:
|
||||
|
||||
```jsonl
|
||||
{"messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "<image>描述图像"}, {"role": "assistant", "content": "<|object_ref_start|>一只狗<|object_ref_end|><|box_start|>(221,423),(569,886)<|box_end|>和<|object_ref_start|>一个女人<|object_ref_end|><|box_start|>(451,381),(733,793)<|box_end|>正在沙滩上玩耍"}], "images": ["/xxx/x.jpg"]}
|
||||
{"messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "<image>找到图像中的<|object_ref_start|>羊<|object_ref_end|>"}, {"role": "assistant", "content": "<|box_start|>(101,201),(150,266)<|box_end|><|box_start|>(401,601),(550,666)<|box_end|>"}], "images": ["/xxx/x.jpg"]}
|
||||
{"messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "<image>帮我打开谷歌浏览器"}, {"role": "assistant", "content": "Action: click(start_box='<|box_start|>(246,113)<|box_end|>')"}], "images": ["/xxx/x.jpg"]}
|
||||
```
|
||||
使用这种类型的数据需要注意:
|
||||
- 不同模型grounding任务的特殊字符和数据集格式不同。
|
||||
- 不同模型对bbox是否归一化的处理不同。例如:qwen2.5-vl使用绝对坐标,而qwen2/3-vl、internvl2.5需要对bbox的坐标进行千分位坐标归一化。
|
||||
- 注意:Qwen2.5-VL采用绝对坐标,因此要小心每次的图像缩放,如果使用方案一的数据集格式,你需要预先对图像进行resize(H和W需要是28的系数),并根据该尺寸缩放坐标点。如果使用方案二的数据集格式,ms-swift会帮助你处理图像的缩放问题,你依旧可以使用`MAX_PIXELS`或者`--max_pixels`等进行图像缩放(仅训练,推理场景,你依旧需要自己处理图像的缩放问题)。
|
||||
|
||||
2. 使用ms-swift的grounding数据格式:
|
||||
|
||||
```jsonl
|
||||
{"messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "<image>描述图像"}, {"role": "assistant", "content": "<ref-object><bbox>和<ref-object><bbox>正在沙滩上玩耍"}], "images": ["/xxx/x.jpg"], "objects": {"ref": ["一只狗", "一个女人"], "bbox": [[331.5, 761.4, 853.5, 1594.8], [676.5, 685.8, 1099.5, 1427.4]]}}
|
||||
{"messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "<image>找到图像中的<ref-object>"}, {"role": "assistant", "content": "<bbox><bbox>"}], "images": ["/xxx/x.jpg"], "objects": {"ref": ["羊"], "bbox": [[90.9, 160.8, 135, 212.8], [360.9, 480.8, 495, 532.8]]}}
|
||||
{"messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "<image>帮我打开谷歌浏览器"}, {"role": "assistant", "content": "Action: click(start_box='<bbox>')"}], "images": ["/xxx/x.jpg"], "objects": {"ref": [], "bbox": [[615, 226]]}}
|
||||
```
|
||||
该格式将自动转换数据集格式为对应模型的grounding任务格式,且选择对应模型的bbox归一化方式。该格式比通用格式多了objects字段,该字段包含的字段有:
|
||||
- ref: 用于替换messages中的`<ref-object>`。ref的长度需要与`<ref-object>`的数量一致。
|
||||
- bbox: 用于替换messages中的`<bbox>`。若bbox中每个box长度为2,则代表x和y坐标,若box长度为4,则代表2个点的x和y坐标。bbox的长度需要与`<bbox>`的数量一致。
|
||||
- 注意:`<ref-object>`和`<bbox>`并没有对应关系,ref和bbox各自替换各自的占位符。
|
||||
- bbox_type: 可选项为'real','norm1'。默认为'real',即bbox为真实bbox值。若是'norm1',则bbox已经归一化为0~1。
|
||||
- image_id: 通常用于多图grounding任务。该参数只有当bbox_type为'real'时生效,代表bbox对应的图片是第几张,用于缩放bbox。索引从0开始,默认全为第0张。image_id的数量需要和bbox的数量一致。例如:若bbox的长度为10,images的长度为2,那么image_id的长度需要是10,其值需要在`{0, 1}`集合内。
|
||||
|
||||
对于Qwen2.5-VL/Qwen3-VL,你可以使用环境`QWENVL_BBOX_FORMAT='new'`(默认为'legacy'),以兼容[官方cookbook](https://github.com/QwenLM/Qwen3-VL/blob/main/cookbooks/2d_grounding.ipynb)格式。并将数据集定义成以下格式:
|
||||
```jsonl
|
||||
{"messages": [{"role": "user", "content": "<image>找到图像中的<ref-object>"}, {"role": "assistant", "content": "[\n\t{\"bbox_2d\": <bbox>, \"label\": \"<ref-object>\"},\n\t{\"bbox_2d\": <bbox>, \"label\": \"<ref-object>\"}\n]"}], "images": ["cat.png"], "objects": {"ref": ["羊", "羊", "羊"], "bbox": [[90.9, 160.8, 135, 212.8], [360.9, 480.8, 495, 532.8]]}}
|
||||
```
|
||||
|
||||
测试ms-swift格式的grounding数据格式的最终格式:
|
||||
```python
|
||||
import os
|
||||
os.environ["MAX_PIXELS"] = "1003520"
|
||||
from swift import get_processor, get_template
|
||||
|
||||
processor = get_processor('Qwen/Qwen2.5-VL-7B-Instruct')
|
||||
template = get_template(processor)
|
||||
data = {...}
|
||||
template.set_mode('train')
|
||||
encoded = template.encode(data, return_template_inputs=True)
|
||||
print(f'[INPUT_IDS] {template.safe_decode(encoded["input_ids"])}\n')
|
||||
print(f'[LABELS] {template.safe_decode(encoded["labels"])}')
|
||||
print(f'images: {encoded["template_inputs"].images}')
|
||||
```
|
||||
|
||||
### Agent格式
|
||||
这里分别提供了纯文本Agent和多模态Agent的示例数据样本:
|
||||
```jsonl
|
||||
{"tools": "[{\"type\": \"function\", \"function\": {\"name\": \"realtime_aqi\", \"description\": \"天气预报。获取实时空气质量。当前空气质量,PM2.5,PM10信息\", \"parameters\": {\"type\": \"object\", \"properties\": {\"city\": {\"type\": \"string\", \"description\": \"城市名,例如:上海\"}}, \"required\": [\"city\"]}}}]", "messages": [{"role": "user", "content": "北京和上海今天的天气情况"}, {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"北京\"}}"}, {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"上海\"}}"}, {"role": "tool_response", "content": "{\"city\": \"北京\", \"aqi\": \"10\", \"unit\": \"celsius\"}"}, {"role": "tool_response", "content": "{\"city\": \"上海\", \"aqi\": \"72\", \"unit\": \"fahrenheit\"}"}, {"role": "assistant", "content": "根据天气预报工具,北京今天的空气质量指数为10,属于良好水平;上海今天的空气质量指数为72,属于轻度污染水平。"}]}
|
||||
{"tools": "[{\"type\": \"function\", \"function\": {\"name\": \"click\", \"description\": \"点击屏幕中的某个位置\", \"parameters\": {\"type\": \"object\", \"properties\": {\"x\": {\"type\": \"integer\", \"description\": \"横坐标,表示屏幕上的水平位置\"}, \"y\": {\"type\": \"integer\", \"description\": \"纵坐标,表示屏幕上的垂直位置\"}}, \"required\": [\"x\", \"y\"]}}}]", "messages": [{"role": "user", "content": "<image>现在几点了?"}, {"role": "assistant", "content": "<think>\n我可以通过打开日历App来获取当前时间。\n</think>\n"}, {"role": "tool_call", "content": "{\"name\": \"click\", \"arguments\": {\"x\": 105, \"y\": 132}}"}, {"role": "tool_response", "content": "{\"images\": \"<image>\", \"status\": \"success\"}"}, {"role": "assistant", "content": "成功打开日历App,现在的时间为中午11点"}], "images": ["desktop.png", "calendar.png"]}
|
||||
```
|
||||
- agent_template为"react_en", "hermes"等情况下,该格式适配所有模型Agent训练,可以轻松在不同模型间切换。
|
||||
- 其中tools是一个包含tool列表的json字符串,messages中role为'tool_call'和'tool_response/tool'的content部分都需要是json字符串。
|
||||
- tools字段将在训练/推理时和`{"role": "system", ...}"`部分组合,根据agent_template组成完整的system部分。
|
||||
- `{"role": "tool_call", ...}`部分将根据agent_template自动转成对应格式的`{"role": "assistant", ...}`,多条连续的`{"role": "assistant", ...}`将拼接在一起组成完整的assistant_content。
|
||||
- `{"role": "tool_response", ...}`也可以写成`{"role": "tool", ...}`,这两种写法是等价的。该部分也将根据`agent_template`自动转换格式。该部分在训练时将不进行损失的计算,角色类似于`{"role": "user", ...}`。
|
||||
- 该格式支持并行调用工具,例子参考第一条数据样本。多模态Agent数据样本中`<image>`标签数量应与"images"长度相同,其标签位置代表图像特征的插入位置。当然也支持其他模态,例如audios, videos。
|
||||
- 注意:您也可以手动将数据处理为role为system/user/assistant的messages格式。agent_template的作用是将其中的tools字段以及role为tool_call和tool_response的messages部分,自动映射为标准的role为system/user/assistant的messages格式。
|
||||
- 更多请参考[Agent文档](../Instruction/Agent-support.md)。
|
||||
|
||||
### 文生图格式
|
||||
|
||||
```jsonl
|
||||
{"messages": [{"role": "system", "content": "你是个有用无害的助手"}, {"role": "user", "content": "给我画出一个苹果"}, {"role": "assistant", "content": "<image>"}], "images": ["/xxx/x.jpg"]}
|
||||
```
|
||||
|
||||
## dataset_info.json
|
||||
|
||||
可以参考ms-swift内置的[dataset_info.json](https://github.com/modelscope/ms-swift/blob/main/swift/dataset/data/dataset_info.json)。该方案使用AutoPreprocessor预处理函数将数据集转换为标准格式。dataset_info.json文件中包含了数据集元信息的list,以下为一些例子:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"ms_dataset_id": "xxx/xxx"
|
||||
},
|
||||
{
|
||||
"dataset_path": "<dataset_dir/dataset_path>"
|
||||
},
|
||||
{
|
||||
"ms_dataset_id": "<dataset_id>",
|
||||
"subsets": ["v1"],
|
||||
"split": ["train", "validation"],
|
||||
"columns": {
|
||||
"input": "query",
|
||||
"output": "response"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ms_dataset_id": "<dataset_id>",
|
||||
"hf_dataset_id": "<hf_dataset_id>",
|
||||
"subsets": [{
|
||||
"subset": "subset1",
|
||||
"columns": {
|
||||
"problem": "query",
|
||||
"content": "response"
|
||||
}
|
||||
},
|
||||
{
|
||||
"subset": "subset2",
|
||||
"columns": {
|
||||
"messages": "_",
|
||||
"new_messages": "messages"
|
||||
}
|
||||
}]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
支持以下参数:
|
||||
- ms_dataset_id: 参考DatasetMeta参数。
|
||||
- hf_dataset_id: 参考DatasetMeta参数。
|
||||
- dataset_path: 参考DatasetMeta参数。
|
||||
- dataset_name: 参考DatasetMeta参数。
|
||||
- subsets: 参考DatasetMeta参数。
|
||||
- split: 参考DatasetMeta参数。
|
||||
- columns: 在数据集进行预处理前,对数据集进行列名转换。
|
||||
|
||||
|
||||
## 数据集注册
|
||||
|
||||
register_dataset会在`DATASET_MAPPING`中注册数据集,调用函数`register_dataset(dataset_meta)`即可完成数据集注册,其中dataset_meta将存储模型的元信息。DatasetMeta的参数列表如下:
|
||||
- ms_dataset_id: ModelScope的dataset_id,默认为None。
|
||||
- hf_dataset_id: HuggingFace的dataset_id,默认为None。
|
||||
- dataset_path: 数据集**文件/文件夹**的本地路径(推荐使用绝对路径)。默认为None。
|
||||
- dataset_name: 数据集别名,可以通过`--dataset <dataset_name>`指定数据集,这在dataset_path很长时很方便。默认为None。
|
||||
- subsets: 子数据集的名字列表或者`SubsetDataset`对象的列表,默认为`['default']`。(只有dataset_id或者dataset_dir(git clone开源数据集)有子数据集和split的概念)。
|
||||
- split: 默认为`['train']`。
|
||||
- preprocess_func: 预处理函数或可调用对象,默认为`AutoPreprocessor()`。该预处理函数接口为传入`HfDataset`,并返回满足标准格式的`HfDataset`。
|
||||
- load_function: 默认为`DatasetLoader.load`。若需要自定义载入函数,则该载入函数需返回满足标准格式的`HfDataset`,这将抛弃ms-swift的数据集载入机制,提供给用户最大的自由度。通常该参数不需要进行修改。
|
||||
|
||||
|
||||
以下介绍注册数据集的例子:
|
||||
|
||||
```python
|
||||
from swift.dataset import (
|
||||
ResponsePreprocessor, DatasetMeta, register_dataset, SubsetDataset, load_dataset
|
||||
)
|
||||
from typing import Dict, Any
|
||||
|
||||
class CustomPreprocessor(ResponsePreprocessor):
|
||||
def preprocess(self, row: Dict[str, Any]) -> Dict[str, Any]:
|
||||
query = f"""任务:判断下面两句话语意是否相似。
|
||||
句子1: {row['text1']}
|
||||
句子2: {row['text2']}
|
||||
请输出类别[0/1]: 0代表含义不同, 1代表含义相似。
|
||||
"""
|
||||
response = str(row['label'])
|
||||
row = {
|
||||
'query': query,
|
||||
'response': response
|
||||
}
|
||||
return super().preprocess(row)
|
||||
|
||||
|
||||
register_dataset(
|
||||
DatasetMeta(
|
||||
ms_dataset_id='swift/financial_classification',
|
||||
subsets=[SubsetDataset('train', split=['train']), SubsetDataset('test', split=['test'])],
|
||||
preprocess_func=CustomPreprocessor(),
|
||||
))
|
||||
|
||||
if __name__ == '__main__':
|
||||
# load_dataset returns train_dataset and val_dataset based on `split_dataset_ratio`
|
||||
# Here, since we didn't pass `split_dataset_ratio` (defaults to 0), we take the first one (index 0)
|
||||
dataset = load_dataset('swift/financial_classification:train')[0]
|
||||
test_dataset = load_dataset('swift/financial_classification:test')[0]
|
||||
print(f'dataset[0]: {dataset[0]}')
|
||||
print(f'test_dataset[0]: {test_dataset[0]}')
|
||||
```
|
||||
@@ -0,0 +1,38 @@
|
||||
# 自定义模型
|
||||
|
||||
ms-swift内置的模型,你可以直接通过指定model_id或者model_path来使用:`--model <model_id_or_path>`。ms-swift会根据model_id/model_path的后缀和`config.json`文件来判断model_type。
|
||||
|
||||
每种model_type都有唯一的模型结构、template和加载方式。当然,你也可以手动传入`--model_type`、`--template`来进行覆盖。ms-swift已支持的model_type和template可以查看[支持的模型与数据集](../Instruction/Supported-models-and-datasets.md)。
|
||||
|
||||
以下介绍如何注册一个新模型和对应的template。最佳实践参考[注册多模态模型最佳实践](../BestPractices/MLLM-Registration.md)。
|
||||
|
||||
## 模型注册
|
||||
|
||||
自定义模型通常使用模型注册的方式进行,可以参考[内置模型](https://github.com/modelscope/ms-swift/blob/main/swift/model/models/qwen.py)、[内置对话模板](https://github.com/modelscope/ms-swift/blob/main/swift/template/templates/qwen.py)或者[examples](https://github.com/modelscope/ms-swift/blob/main/examples/custom)的示例代码。你可以通过指定`--external_plugins xxx.py`解析外置注册的内容(方便pip install而非git clone的用户)。
|
||||
|
||||
register_model会在`MODEL_MAPPING`中注册模型,调用函数`register_model(model_meta)`即可完成模型注册,其中model_meta将存储模型的元信息。ModelMeta的参数列表如下:
|
||||
- model_type: 必填项。模型类型,也是唯一ID。
|
||||
- model_groups: 必填项。罗列ModelScope/HuggingFace的模型id和模型本地路径。运行[run_model_info.py](https://github.com/modelscope/ms-swift/blob/main/scripts/utils/run_model_info.py)文件将自动产生[支持的模型文档](https://swift.readthedocs.io/zh-cn/latest/Instruction/Supported-models-and-datasets.html)以及自动根据`--model`后缀匹配model_type。
|
||||
- loader: 模型和tokenizer/processor(多模态模型)的加载器。默认使用`swift.model.ModelLoader`。
|
||||
- template: 命令行不额外指定`--template`时的默认template类型。默认为None。
|
||||
- model_arch: 模型架构。默认为None。多模态模型训练需要设置该参数来确定llm/vit/aligner的前缀。
|
||||
- architectures: config.json中的architectures项,用于自动匹配模型对应的model_type。默认为`[]`。
|
||||
- additional_saved_files: 全参数训练和merge-lora时需要额外保存的文件。默认为`[]`。
|
||||
- torch_dtype: 模型加载时未传入`torch_dtype`时的默认dtype。默认为None,从config.json中读取。
|
||||
- is_multimodal: 是否是多模态模型,默认为False。
|
||||
- ignore_patterns: 从hub端下载文件需要忽略的文件patterns,默认为`[]`。
|
||||
|
||||
|
||||
register_template会在`TEMPLATE_MAPPING`中注册对话模板,调用函数`register_template(template_meta)`即可完成对话模板注册,其中template_meta将存储template的元信息。TemplateMeta的参数列表如下:
|
||||
- template_type: 必填项。对话模板类型,也是唯一ID。
|
||||
- prefix: 必填项。对话模板的前缀,通常包含system、bos_token等部分,独立于多轮对话而产生的对话模板循环。例如qwen的prefix为`[]`。
|
||||
- prompt: 必填项。表示对话模板中的`{{RESPONSE}}`之前的对话部分。我们使用`{{QUERY}}`代表user询问部分的填充符。例如qwen的prompt为`['<|im_start|>user\n{{QUERY}}<|im_end|>\n<|im_start|>assistant\n']`。
|
||||
- chat_sep: 必填项。多轮对话中每轮的分隔符。若设置为None,则该template不支持多轮对话。例如qwen的chat_sep为`['<|im_end|>\n']`。
|
||||
- suffix: 默认为`[['eos_token_id']]`。对话模板的后缀部分,独立于多轮对话而产生的对话模板循环,通常为eos_token。例如qwen的suffix为`['<|im_end|>']。`
|
||||
- template_cls: 默认为`Template`。通常在定义多模态模型的template时需要进行自定义,自定义`_encode`、`_post_encode`、`_data_collator`函数。
|
||||
- system_prefix: 默认为None。含system的对话模板前缀。我们使用`{{SYSTEM}}`作为system的填充符。例如qwen的system_prefix为`['<|im_start|>system\n{{SYSTEM}}<|im_end|>\n']`。
|
||||
- 注意:若system为空时,`prefix`可以被`system_prefix`替代,则可以将`prefix`写为含system的前缀,而无需设置`system_prefix`。
|
||||
- 若prefix不含`{{SYSTEM}}`且未设置system_prefix,则该template不支持system。
|
||||
- default_system: 默认为None。不传入`--system`时使用的默认system。例如qwen的default_system为`'You are a helpful assistant.'`。
|
||||
- stop_words: 默认为`[]`。除了eos_token和`suffix[-1]`的额外停止符。例如qwen的stop_words为`['<|endoftext|>']`。
|
||||
- 注意:推理时,输出的response将会过滤eos_token和`suffix[-1]`,但是会保留额外的stop_words。
|
||||
@@ -0,0 +1,108 @@
|
||||
# 快速开始
|
||||
|
||||
🍲 ms-swift是魔搭社区提供的大模型与多模态大模型微调部署框架,现已支持600+纯文本大模型与400+多模态大模型的训练(预训练、微调、人类对齐)、推理、评测、量化与部署。其中大模型包括:Qwen3、Qwen3.5、InternLM3、GLM4.5、Mistral、DeepSeek-R1、Llama4等模型,多模态大模型包括:Qwen3-VL、Qwen3-Omni、Llava、InternVL3.5、MiniCPM-V-4、Ovis2.5、GLM4.5-V、DeepSeek-VL2等模型。
|
||||
|
||||
🍔 除此之外,ms-swift汇集了最新的训练技术,包括集成Megatron并行技术,包括TP、PP、CP、EP等为训练提供加速,以及众多GRPO算法族强化学习的算法,包括:GRPO、DAPO、GSPO、SAPO、CISPO、RLOO、Reinforce++等提升模型智能。ms-swift支持广泛的训练任务,包括DPO、KTO、RM、CPO、SimPO、ORPO等偏好学习算法,以及Embedding、Reranker、序列分类任务。ms-swift提供了大模型训练全链路的支持,包括使用vLLM、SGLang和LMDeploy对推理、评测、部署模块提供加速,以及使用GPTQ、AWQ、BNB、FP8技术对大模型进行量化。
|
||||
|
||||
**为什么选择ms-swift?**
|
||||
- 🍎 **模型类型**:支持600+纯文本大模型、**400+多模态大模型**以及All-to-All全模态模型训练到部署全流程,热门模型Day0支持。
|
||||
- **数据集类型**:内置150+预训练、微调、人类对齐、多模态等各种任务数据集,并支持自定义数据集,用户只需准备数据集即可一键训练。
|
||||
- **硬件支持**:支持A10/A100/H100、RTX系列、T4/V100、CPU、MPS以及国产硬件Ascend NPU等。
|
||||
- **轻量训练**:支持了LoRA、QLoRA、DoRA、LoRA+、LLaMAPro、LongLoRA、LoRA-GA、ReFT、RS-LoRA、Adapter、LISA等轻量微调方式。
|
||||
- **量化训练**:支持对BNB、AWQ、GPTQ、AQLM、HQQ、EETQ量化模型进行训练,7B模型训练只需9GB训练资源。
|
||||
- **显存优化**: GaLore、Q-Galore、UnSloth、Liger-Kernel、Flash-Attention 2/3 以及 **Ulysses和Ring-Attention序列并行技术**支持,降低长文本训练显存占用。
|
||||
- **分布式训练**:支持分布式数据并行(DDP)、device_map简易模型并行、DeepSpeed ZeRO2 ZeRO3、FSDP/FSDP2以及Megatron等分布式训练技术。
|
||||
- 🍓 **多模态训练**:支持多模态packing技术提升训练速度100%+,支持文本、图像、视频和语音混合模态数据训练,支持vit/aligner/llm单独控制。
|
||||
- **Agent训练**:支持Agent template,准备一套数据集可用于不同模型的训练。
|
||||
- 🍊 **训练任务**:支持预训练和指令微调,以及DPO、GKD、KTO、RM、CPO、SimPO、ORPO等训练任务,支持**Embedding/Reranker**和序列分类任务。
|
||||
- 🥥 **Megatron并行技术**:提供TP/PP/SP/CP/ETP/EP/VPP并行策略,显著提升**MoE模型训练速度**。支持300+纯文本大模型和100+多模态大模型的全参数和LoRA训练方法。支持CPT/SFT/GRPO/DPO/KTO/RM训练任务。
|
||||
- 🍉 **强化学习**:内置**丰富GRPO族算法**,包括GRPO、DAPO、GSPO、SAPO、CISPO、CHORD、RLOO、Reinforce++等,支持同步和异步vLLM引擎推理加速,可使用插件拓展奖励函数、多轮推理调度器以及环境等。
|
||||
- **全链路能力**:覆盖训练、推理、评测、量化和部署全流程。
|
||||
- **界面训练**:提供使用Web-UI界面的方式进行训练、推理、评测、量化,完成大模型的全链路。
|
||||
- **推理加速**:支持Transformers、vLLM、SGLang和LmDeploy推理加速引擎,并提供OpenAI接口,为推理、部署和评测模块提供加速。
|
||||
- **模型评测**:以EvalScope作为评测后端,支持100+评测数据集对纯文本和多模态模型进行评测。
|
||||
- **模型量化**:支持AWQ、GPTQ、FP8和BNB的量化导出,导出的模型支持使用vLLM/SGLang/LmDeploy推理加速。
|
||||
|
||||
|
||||
## 安装
|
||||
|
||||
ms-swift的安装请参考[安装文档](./SWIFT-installation.md)。
|
||||
|
||||
## 使用样例
|
||||
|
||||
10分钟在单卡3090上对Qwen3-4B-Instruct-2507进行自我认知微调:
|
||||
```shell
|
||||
# 13GB
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift sft \
|
||||
--model Qwen/Qwen3-4B-Instruct-2507 \
|
||||
--tuner_type lora \
|
||||
--dataset 'AI-ModelScope/alpaca-gpt4-data-zh#500' \
|
||||
'AI-ModelScope/alpaca-gpt4-data-en#500' \
|
||||
'swift/self-cognition#500' \
|
||||
--torch_dtype bfloat16 \
|
||||
--num_train_epochs 1 \
|
||||
--per_device_train_batch_size 1 \
|
||||
--per_device_eval_batch_size 1 \
|
||||
--learning_rate 1e-4 \
|
||||
--lora_rank 8 \
|
||||
--lora_alpha 32 \
|
||||
--target_modules all-linear \
|
||||
--gradient_accumulation_steps 16 \
|
||||
--eval_steps 50 \
|
||||
--save_steps 50 \
|
||||
--save_total_limit 2 \
|
||||
--logging_steps 5 \
|
||||
--max_length 2048 \
|
||||
--output_dir output \
|
||||
--warmup_ratio 0.05 \
|
||||
--dataloader_num_workers 4 \
|
||||
--model_author swift \
|
||||
--model_name swift-robot
|
||||
```
|
||||
|
||||
小贴士:
|
||||
- 如果要使用自定义数据集进行训练,你可以参考[这里](../Customization/Custom-dataset.md)组织数据集格式,并指定`--dataset <dataset_path>`。
|
||||
- `--model_author`和`--model_name`参数只有当数据集中包含`swift/self-cognition`时才生效。
|
||||
- 如果要使用其他模型进行训练,你只需要修改`--model <model_id/model_path>`即可。
|
||||
- 默认使用**ModelScope**进行模型和数据集的下载。如果要使用HuggingFace,指定`--use_hf true`即可。
|
||||
|
||||
训练完成后,使用以下命令对训练后的权重进行推理:
|
||||
- 这里的`--adapters`需要替换成训练生成的last checkpoint文件夹。由于adapters文件夹中包含了训练的参数文件`args.json`,因此不需要额外指定`--model`,`--system`,swift会自动读取这些参数。如果要关闭此行为,可以设置`--load_args false`。
|
||||
|
||||
```shell
|
||||
# 使用交互式命令行进行推理
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift infer \
|
||||
--adapters output/vx-xxx/checkpoint-xxx \
|
||||
--stream true \
|
||||
--temperature 0 \
|
||||
--max_new_tokens 2048
|
||||
|
||||
# merge-lora并使用vLLM进行推理加速
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift infer \
|
||||
--adapters output/vx-xxx/checkpoint-xxx \
|
||||
--stream true \
|
||||
--merge_lora true \
|
||||
--infer_backend vllm \
|
||||
--vllm_max_model_len 8192 \
|
||||
--temperature 0 \
|
||||
--max_new_tokens 2048
|
||||
```
|
||||
|
||||
最后,使用以下命令将模型推送到ModelScope:
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift export \
|
||||
--adapters output/vx-xxx/checkpoint-xxx \
|
||||
--push_to_hub true \
|
||||
--hub_model_id '<your-model-id>' \
|
||||
--hub_token '<your-sdk-token>' \
|
||||
--use_hf false
|
||||
```
|
||||
|
||||
## 了解更多
|
||||
|
||||
- 更多Shell脚本:[https://github.com/modelscope/ms-swift/tree/main/examples](https://github.com/modelscope/ms-swift/tree/main/examples)
|
||||
- 使用Python:[https://github.com/modelscope/ms-swift/blob/main/examples/notebook/qwen2_5-self-cognition/self-cognition-sft.ipynb](https://github.com/modelscope/ms-swift/blob/main/examples/notebook/qwen2_5-self-cognition/self-cognition-sft.ipynb)
|
||||
@@ -0,0 +1,180 @@
|
||||
# SWIFT安装
|
||||
|
||||
## Wheel包安装
|
||||
|
||||
可以使用pip进行安装:
|
||||
|
||||
```shell
|
||||
# 推荐
|
||||
pip install 'ms-swift' -U
|
||||
# 额外安装megatron依赖
|
||||
pip install 'ms-swift[megatron]' -U
|
||||
# 额外安装评测依赖
|
||||
pip install 'ms-swift[eval]' -U
|
||||
# 全能力
|
||||
pip install 'ms-swift[all]' -U
|
||||
|
||||
# 使用uv
|
||||
pip install uv
|
||||
uv pip install 'ms-swift' --torch-backend=auto
|
||||
```
|
||||
|
||||
## 源代码安装
|
||||
|
||||
当前main分支为 swift4.x 版本。
|
||||
```shell
|
||||
# pip install git+https://github.com/modelscope/ms-swift.git
|
||||
|
||||
# 全能力
|
||||
# pip install "ms-swift[all]@git+https://github.com/modelscope/ms-swift.git"
|
||||
|
||||
git clone https://github.com/modelscope/ms-swift.git
|
||||
cd ms-swift
|
||||
pip install -e .
|
||||
|
||||
# 使用 uv
|
||||
uv pip install -e . --torch-backend=auto
|
||||
|
||||
# 全能力
|
||||
# pip install -e '.[all]'
|
||||
```
|
||||
|
||||
安装swift3.x:
|
||||
```shell
|
||||
# pip install "git+https://github.com/modelscope/ms-swift.git@release/3.12"
|
||||
|
||||
# 全能力
|
||||
# pip install "ms-swift[all]@git+https://github.com/modelscope/ms-swift.git@release/3.12"
|
||||
|
||||
git clone -b release/3.12 https://github.com/modelscope/ms-swift.git
|
||||
cd ms-swift
|
||||
pip install -e .
|
||||
|
||||
# 全能力
|
||||
# pip install -e '.[all]'
|
||||
```
|
||||
|
||||
## 镜像
|
||||
|
||||
docker可以查看[这里](https://github.com/modelscope/modelscope/blob/build_swift_image/docker/build_image.py#L392)。
|
||||
```
|
||||
# swift4.3.2
|
||||
modelscope-registry.cn-hangzhou.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda13.0.3-py312-torch2.11.0-vllm0.23.0-modelscope1.37.1-swift4.3.2
|
||||
modelscope-registry.cn-beijing.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda13.0.3-py312-torch2.11.0-vllm0.23.0-modelscope1.37.1-swift4.3.2
|
||||
modelscope-registry.us-west-1.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda13.0.3-py312-torch2.11.0-vllm0.23.0-modelscope1.37.1-swift4.3.2
|
||||
|
||||
# swift4.2.3
|
||||
modelscope-registry.cn-hangzhou.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda13.0.3-py312-torch2.11.0-vllm0.21.0-modelscope1.36.3-swift4.2.3
|
||||
modelscope-registry.cn-beijing.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda13.0.3-py312-torch2.11.0-vllm0.21.0-modelscope1.36.3-swift4.2.3
|
||||
modelscope-registry.us-west-1.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda13.0.3-py312-torch2.11.0-vllm0.21.0-modelscope1.36.3-swift4.2.3
|
||||
|
||||
# swift4.1.3
|
||||
modelscope-registry.cn-hangzhou.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.9.1-py312-torch2.10.0-vllm0.19.1-modelscope1.35.4-swift4.1.3
|
||||
modelscope-registry.cn-beijing.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.9.1-py312-torch2.10.0-vllm0.19.1-modelscope1.35.4-swift4.1.3
|
||||
modelscope-registry.us-west-1.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.9.1-py312-torch2.10.0-vllm0.19.1-modelscope1.35.4-swift4.1.3
|
||||
|
||||
# swift4.0.3
|
||||
modelscope-registry.cn-hangzhou.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.8.1-py311-torch2.10.0-vllm0.17.1-modelscope1.34.0-swift4.0.3
|
||||
modelscope-registry.cn-beijing.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.8.1-py311-torch2.10.0-vllm0.17.1-modelscope1.34.0-swift4.0.3
|
||||
modelscope-registry.us-west-1.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.8.1-py311-torch2.10.0-vllm0.17.1-modelscope1.34.0-swift4.0.3
|
||||
```
|
||||
|
||||
<details><summary>历史镜像</summary>
|
||||
|
||||
```
|
||||
# swift3.12.5
|
||||
modelscope-registry.cn-hangzhou.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.8.1-py311-torch2.9.0-vllm0.13.0-modelscope1.33.0-swift3.12.5
|
||||
modelscope-registry.cn-beijing.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.8.1-py311-torch2.9.0-vllm0.13.0-modelscope1.33.0-swift3.12.5
|
||||
modelscope-registry.us-west-1.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.8.1-py311-torch2.9.0-vllm0.13.0-modelscope1.33.0-swift3.12.5
|
||||
|
||||
# swift3.11.3
|
||||
modelscope-registry.cn-hangzhou.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.9.1-py311-torch2.8.0-vllm0.11.0-modelscope1.32.0-swift3.11.3
|
||||
modelscope-registry.cn-beijing.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.9.1-py311-torch2.8.0-vllm0.11.0-modelscope1.32.0-swift3.11.3
|
||||
modelscope-registry.us-west-1.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.9.1-py311-torch2.8.0-vllm0.11.0-modelscope1.32.0-swift3.11.3
|
||||
|
||||
# swift3.10.3
|
||||
modelscope-registry.cn-hangzhou.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.8.1-py311-torch2.8.0-vllm0.11.0-modelscope1.31.0-swift3.10.3
|
||||
modelscope-registry.cn-beijing.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.8.1-py311-torch2.8.0-vllm0.11.0-modelscope1.31.0-swift3.10.3
|
||||
modelscope-registry.us-west-1.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.8.1-py311-torch2.8.0-vllm0.11.0-modelscope1.31.0-swift3.10.3
|
||||
|
||||
# swift3.9.3
|
||||
modelscope-registry.cn-hangzhou.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.8.1-py311-torch2.8.0-vllm0.11.0-modelscope1.31.0-swift3.9.3
|
||||
modelscope-registry.cn-beijing.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.8.1-py311-torch2.8.0-vllm0.11.0-modelscope1.31.0-swift3.9.3
|
||||
modelscope-registry.us-west-1.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.8.1-py311-torch2.8.0-vllm0.11.0-modelscope1.31.0-swift3.9.3
|
||||
|
||||
# swift3.8.3
|
||||
modelscope-registry.cn-hangzhou.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.6.3-py311-torch2.7.1-vllm0.10.1.1-modelscope1.29.2-swift3.8.3
|
||||
modelscope-registry.cn-beijing.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.6.3-py311-torch2.7.1-vllm0.10.1.1-modelscope1.29.2-swift3.8.3
|
||||
modelscope-registry.us-west-1.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.6.3-py311-torch2.7.1-vllm0.10.1.1-modelscope1.29.2-swift3.8.3
|
||||
|
||||
# swift3.7.2
|
||||
modelscope-registry.cn-hangzhou.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.6.3-py311-torch2.7.1-vllm0.10.0-modelscope1.28.2-swift3.7.2
|
||||
modelscope-registry.cn-beijing.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.6.3-py311-torch2.7.1-vllm0.10.0-modelscope1.28.2-swift3.7.2
|
||||
modelscope-registry.us-west-1.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.6.3-py311-torch2.7.1-vllm0.10.0-modelscope1.28.2-swift3.7.2
|
||||
|
||||
# swift3.6.4
|
||||
modelscope-registry.cn-hangzhou.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.4.0-py310-torch2.6.0-vllm0.8.5.post1-modelscope1.28.1-swift3.6.4
|
||||
modelscope-registry.cn-beijing.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.4.0-py310-torch2.6.0-vllm0.8.5.post1-modelscope1.28.1-swift3.6.4
|
||||
modelscope-registry.us-west-1.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.4.0-py310-torch2.6.0-vllm0.8.5.post1-modelscope1.28.1-swift3.6.4
|
||||
|
||||
# swift3.5.3
|
||||
modelscope-registry.cn-hangzhou.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.4.0-py310-torch2.6.0-vllm0.8.5.post1-modelscope1.27.1-swift3.5.3
|
||||
modelscope-registry.cn-beijing.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.4.0-py310-torch2.6.0-vllm0.8.5.post1-modelscope1.27.1-swift3.5.3
|
||||
modelscope-registry.us-west-1.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.4.0-py310-torch2.6.0-vllm0.8.5.post1-modelscope1.27.1-swift3.5.3
|
||||
|
||||
# swift3.4.1.post1
|
||||
modelscope-registry.cn-hangzhou.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.4.0-py311-torch2.6.0-vllm0.8.5.post1-modelscope1.26.0-swift3.4.1.post1
|
||||
modelscope-registry.cn-beijing.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.4.0-py311-torch2.6.0-vllm0.8.5.post1-modelscope1.26.0-swift3.4.1.post1
|
||||
modelscope-registry.us-west-1.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.4.0-py311-torch2.6.0-vllm0.8.5.post1-modelscope1.26.0-swift3.4.1.post1
|
||||
|
||||
# swift3.3.0.post1
|
||||
modelscope-registry.cn-hangzhou.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.4.0-py311-torch2.6.0-vllm0.8.3-modelscope1.25.0-swift3.3.0.post1
|
||||
modelscope-registry.us-west-1.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.4.0-py311-torch2.6.0-vllm0.8.3-modelscope1.25.0-swift3.3.0.post1
|
||||
|
||||
# swift3.2.2
|
||||
modelscope-registry.us-west-1.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.4.0-py311-torch2.5.1-modelscope1.25.0-swift3.2.2
|
||||
```
|
||||
</details>
|
||||
|
||||
更多镜像可以查看[这里](https://modelscope.cn/docs/intro/environment-setup#%E6%9C%80%E6%96%B0%E9%95%9C%E5%83%8F)。
|
||||
|
||||
## 支持的硬件
|
||||
|
||||
| 硬件环境 | 备注 |
|
||||
| --------------- | --------------------------- |
|
||||
| A10/A100/H100 | |
|
||||
| RTX20/30/40系列 | |
|
||||
| T4/V100 | 部分模型出现NAN |
|
||||
| Ascend NPU | 部分模型出现NAN或算子不支持 |
|
||||
| MPS | 参考[issue 4572](https://github.com/modelscope/ms-swift/issues/4572) |
|
||||
| CPU | |
|
||||
|
||||
|
||||
## 运行环境
|
||||
|
||||
| | 范围 | 推荐 | 备注 |
|
||||
|--------------|--------------|---------------------|--------------------|
|
||||
| python | >=3.10 | 3.12 | |
|
||||
| cuda | | cuda12.8/13.0 | 使用cpu、npu、mps则无需安装 |
|
||||
| torch | >=2.0 | 2.8.0/2.11.0 | |
|
||||
| transformers | >=4.33 | 4.57.6/5.12.1 | |
|
||||
| modelscope | >=1.23 | | |
|
||||
| datasets | >=3.0,<4.8.5 | 3.6.0/4.8.4 | |
|
||||
| peft | >=0.11,<0.20 | | |
|
||||
| flash_attn | | 2.8.3/4.0.0b15 | |
|
||||
| trl | >=0.15,<1.0 | 0.29.1 | RLHF |
|
||||
| deepspeed | >=0.14 | 0.18.9 | 训练 |
|
||||
| vllm | >=0.5.1 | 0.11.0/0.23.0 | 推理/部署 |
|
||||
| sglang | >=0.4.6 | | 推理/部署 |
|
||||
| evalscope | >=1.0 | | 评测 |
|
||||
| gradio | | 5.32.1 | Web-UI/App |
|
||||
|
||||
更多可选依赖可以参考[这里](https://github.com/modelscope/ms-swift/blob/main/requirements/install_all.sh)。
|
||||
|
||||
## Notebook环境
|
||||
|
||||
Swift支持训练的绝大多数模型都可以在`A10`显卡上使用,用户可以使用ModelScope官方提供的免费显卡资源:
|
||||
|
||||
1. 进入[ModelScope](https://www.modelscope.cn)官方网站并登录。
|
||||
2. 点击左侧的`我的Notebook`并开启一个免费GPU实例。
|
||||
3. 愉快地薅A10显卡羊毛。
|
||||
@@ -0,0 +1,36 @@
|
||||
# Web-UI
|
||||
|
||||
目前SWIFT已经支持了界面化的训练和推理,参数支持和脚本训练相同。在安装SWIFT后,使用如下命令:
|
||||
|
||||
```shell
|
||||
swift web-ui --lang zh
|
||||
# or en
|
||||
swift web-ui --lang en
|
||||
```
|
||||
|
||||
开启界面训练和推理。
|
||||
|
||||
SWIFT web-ui是命令行的高级封装,即,在界面上启动的训练、部署等任务,会在系统中以命令行启动一个独立的进程,伪代码类似:
|
||||
```python
|
||||
import os
|
||||
os.system('swift sft --model xxx --dataset xxx')
|
||||
```
|
||||
|
||||
这给web-ui带来了几个特性:
|
||||
1. web-ui的每个超参数描述都带有`--xxx`的标记,这与[命令行参数](../Instruction/Command-line-parameters.md)的内容是一致的
|
||||
2. web-ui可以在一台多卡机器上并行启动多个训练/部署任务
|
||||
3. web-ui服务关闭后,后台服务是仍旧运行的,这防止了web-ui被关掉后影响训练进程,如果需要关闭后台服务,只需要**选择对应的任务**后在界面上的`运行时`tab点击杀死服务
|
||||
4. 重新启动web-ui后,如果需要显示正在运行的服务,在`运行时`tab点击`找回运行时任务`即可
|
||||
5. 训练界面支持显示运行日志,请在选择某个任务后手动点击`展示运行状态`,在训练时运行状态支持展示训练图表,图标包括训练loss、训练acc、学习率等基本指标,在人类对齐任务重界面图标为margin、logps等关键指标
|
||||
6. web-ui的训练不支持PPO,该过程比较复杂,建议使用examples的[shell脚本](https://github.com/modelscope/ms-swift/tree/main/examples/train/rlhf/ppo)直接运行
|
||||
|
||||
如果需要使用share模式,请添加`--share true`参数。注意:请不要在dsw、notebook等环境中使用该参数。
|
||||
|
||||
目前ms-swift额外支持了界面推理模式(即Space部署):
|
||||
|
||||
```shell
|
||||
swift app --model '<model>' --studio_title My-Awesome-Space --stream true
|
||||
# 或者
|
||||
swift app --model '<model>' --adapters '<adapter>' --stream true
|
||||
```
|
||||
即可启动一个只有推理页面的应用,该应用会在启动时对模型进行部署并提供后续使用。
|
||||
@@ -0,0 +1,240 @@
|
||||
# Agent支持
|
||||
|
||||
## 数据集格式
|
||||
|
||||
ms-swift 使用 agent-template 实现了Agent数据格式与模型的解耦:基于统一的数据集格式,可以灵活切换不同模型进行训练,无需修改数据。
|
||||
|
||||
纯文本Agent和多模态Agent的示例数据样本如下:
|
||||
```jsonl
|
||||
{"tools": "[{\"type\": \"function\", \"function\": {\"name\": \"realtime_aqi\", \"description\": \"天气预报。获取实时空气质量。当前空气质量,PM2.5,PM10信息\", \"parameters\": {\"type\": \"object\", \"properties\": {\"city\": {\"type\": \"string\", \"description\": \"城市名,例如:上海\"}}, \"required\": [\"city\"]}}}]", "messages": [{"role": "user", "content": "北京和上海今天的天气情况"}, {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"北京\"}}"}, {"role": "tool_call", "content": "{\"name\": \"realtime_aqi\", \"arguments\": {\"city\": \"上海\"}}"}, {"role": "tool_response", "content": "{\"city\": \"北京\", \"aqi\": \"10\", \"unit\": \"celsius\"}"}, {"role": "tool_response", "content": "{\"city\": \"上海\", \"aqi\": \"72\", \"unit\": \"fahrenheit\"}"}, {"role": "assistant", "content": "根据天气预报工具,北京今天的空气质量指数为10,属于良好水平;上海今天的空气质量指数为72,属于轻度污染水平。"}]}
|
||||
{"tools": "[{\"type\": \"function\", \"function\": {\"name\": \"click\", \"description\": \"点击屏幕中的某个位置\", \"parameters\": {\"type\": \"object\", \"properties\": {\"x\": {\"type\": \"integer\", \"description\": \"横坐标,表示屏幕上的水平位置\"}, \"y\": {\"type\": \"integer\", \"description\": \"纵坐标,表示屏幕上的垂直位置\"}}, \"required\": [\"x\", \"y\"]}}}]", "messages": [{"role": "user", "content": "<image>现在几点了?"}, {"role": "assistant", "content": "<think>\n我可以通过打开日历App来获取当前时间。\n</think>\n"}, {"role": "tool_call", "content": "{\"name\": \"click\", \"arguments\": {\"x\": 105, \"y\": 132}}"}, {"role": "tool_response", "content": "{\"images\": \"<image>\", \"status\": \"success\"}"}, {"role": "assistant", "content": "成功打开日历App,现在的时间为中午11点"}], "images": ["desktop.png", "calendar.png"]}
|
||||
```
|
||||
- agent_template为"react_en", "hermes"等情况下,该格式适配所有模型Agent训练,可以轻松在不同模型间切换。
|
||||
- 其中tools是一个包含tool列表的json字符串,messages中role为'tool_call'和'tool_response/tool'的content部分都需要是json字符串。
|
||||
- tools字段将在训练/推理时和`{"role": "system", ...}"`部分组合,根据agent_template组成完整的system部分。
|
||||
- `{"role": "tool_call", ...}`部分将根据agent_template自动转成对应格式的`{"role": "assistant", ...}`,多条连续的`{"role": "assistant", ...}`将拼接在一起组成完整的assistant_content。
|
||||
- `{"role": "tool_response", ...}`也可以写成`{"role": "tool", ...}`,这两种写法是等价的。该部分也将根据`agent_template`自动转换格式。该部分在训练时将不进行损失的计算,角色类似于`{"role": "user", ...}`。
|
||||
- 该格式支持并行调用工具,例子参考第一条数据样本。多模态Agent数据样本中`<image>`标签数量应与"images"长度相同,其标签位置代表图像特征的插入位置。当然也支持其他模态,例如audios, videos。
|
||||
- 注意:您也可以手动将数据处理为role为system/user/assistant的messages格式。agent_template的作用是将其中的tools字段以及role为tool_call和tool_response的messages部分,自动映射为标准的role为system/user/assistant的messages格式。
|
||||
|
||||
以下为上述两条数据样本由qwen2_5和qwen2_5_vl的template进行encode后的input_ids和labels,选择的agent_template为**hermes**:
|
||||
|
||||
样本一(并行工具调用):
|
||||
```text
|
||||
[INPUT_IDS] <|im_start|>system
|
||||
You are Qwen, created by Alibaba Cloud. You are a helpful assistant.
|
||||
|
||||
# Tools
|
||||
|
||||
You may call one or more functions to assist with the user query.
|
||||
|
||||
You are provided with function signatures within <tools></tools> XML tags:
|
||||
<tools>
|
||||
{"type": "function", "function": {"name": "realtime_aqi", "description": "天气预报。获取实时空气质量。当前空气质量,PM2.5,PM10信息", "parameters": {"type": "object", "properties": {"city": {"type": "string", "description": "城市名,例如:上海"}}, "required": ["city"]}}}
|
||||
</tools>
|
||||
|
||||
For each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:
|
||||
<tool_call>
|
||||
{"name": <function-name>, "arguments": <args-json-object>}
|
||||
</tool_call><|im_end|>
|
||||
<|im_start|>user
|
||||
北京和上海今天的天气情况<|im_end|>
|
||||
<|im_start|>assistant
|
||||
<tool_call>
|
||||
{"name": "realtime_aqi", "arguments": {"city": "北京"}}
|
||||
</tool_call>
|
||||
<tool_call>
|
||||
{"name": "realtime_aqi", "arguments": {"city": "上海"}}
|
||||
</tool_call><|im_end|>
|
||||
<|im_start|>user
|
||||
<tool_response>
|
||||
{"city": "北京", "aqi": "10", "unit": "celsius"}
|
||||
</tool_response>
|
||||
<tool_response>
|
||||
{"city": "上海", "aqi": "72", "unit": "fahrenheit"}
|
||||
</tool_response><|im_end|>
|
||||
<|im_start|>assistant
|
||||
根据天气预报工具,北京今天的空气质量指数为10,属于良好水平;上海今天的空气质量指数为72,属于轻度污染水平。<|im_end|>
|
||||
|
||||
[LABELS] [-100 * 195]<tool_call>
|
||||
{"name": "realtime_aqi", "arguments": {"city": "北京"}}
|
||||
</tool_call>
|
||||
<tool_call>
|
||||
{"name": "realtime_aqi", "arguments": {"city": "上海"}}
|
||||
</tool_call><|im_end|>[-100 * 67]根据天气预报工具,北京今天的空气质量指数为10,属于良好水平;上海今天的空气质量指数为72,属于轻度污染水平。<|im_end|>
|
||||
```
|
||||
|
||||
样本二(多模态,混合assistant和tool_call):
|
||||
```text
|
||||
[INPUT_IDS] <|im_start|>system
|
||||
You are a helpful assistant.
|
||||
|
||||
# Tools
|
||||
|
||||
You may call one or more functions to assist with the user query.
|
||||
|
||||
You are provided with function signatures within <tools></tools> XML tags:
|
||||
<tools>
|
||||
{"type": "function", "function": {"name": "click", "description": "点击屏幕中的某个位置", "parameters": {"type": "object", "properties": {"x": {"type": "integer", "description": "横坐标,表示屏幕上的水平位置"}, "y": {"type": "integer", "description": "纵坐标,表示屏幕上的垂直位置"}}, "required": ["x", "y"]}}}
|
||||
</tools>
|
||||
|
||||
For each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:
|
||||
<tool_call>
|
||||
{"name": <function-name>, "arguments": <args-json-object>}
|
||||
</tool_call><|im_end|>
|
||||
<|im_start|>user
|
||||
<|vision_start|>[151655 * 729]<|vision_end|>现在几点了?<|im_end|>
|
||||
<|im_start|>assistant
|
||||
<think>
|
||||
我可以通过打开日历App来获取当前时间。
|
||||
</think>
|
||||
<tool_call>
|
||||
{"name": "click", "arguments": {"x": 105, "y": 132}}
|
||||
</tool_call><|im_end|>
|
||||
<|im_start|>user
|
||||
<tool_response>
|
||||
{"images": "<|vision_start|>[151655 * 729]<|vision_end|>", "status": "success"}
|
||||
</tool_response><|im_end|>
|
||||
<|im_start|>assistant
|
||||
成功打开日历App,现在的时间为中午11点<|im_end|>
|
||||
|
||||
[LABELS] [-100 * 924]<think>
|
||||
我可以通过打开日历App来获取当前时间。
|
||||
</think>
|
||||
<tool_call>
|
||||
{"name": "click", "arguments": {"x": 105, "y": 132}}
|
||||
</tool_call><|im_end|>[-100 * 759]成功打开日历App,现在的时间为中午11点<|im_end|>
|
||||
```
|
||||
|
||||
**react_en**是常用的agent template格式之一,以下为样本一由qwen2_5使用`agent_template='react_en'`进行encode后的input_ids和labels:
|
||||
|
||||
```text
|
||||
[INPUT_IDS] <|im_start|>system
|
||||
Answer the following questions as best you can. You have access to the following tools:
|
||||
|
||||
realtime_aqi: Call this tool to interact with the realtime_aqi API. What is the realtime_aqi API useful for? 天气预报。获取实时空气质量。当前空气质量,PM2.5,PM10信息 Parameters: {"type": "object", "properties": {"city": {"type": "string", "description": "城市名,例如:上海"}}, "required": ["city"]} Format the arguments as a JSON object.
|
||||
|
||||
Use the following format:
|
||||
|
||||
Question: the input question you must answer
|
||||
Thought: you should always think about what to do
|
||||
Action: the action to take, should be one of [realtime_aqi]
|
||||
Action Input: the input to the action
|
||||
Observation: the result of the action
|
||||
... (this Thought/Action/Action Input/Observation can be repeated zero or more times)
|
||||
Thought: I now know the final answer
|
||||
Final Answer: the final answer to the original input question
|
||||
|
||||
Begin!
|
||||
<|im_end|>
|
||||
<|im_start|>user
|
||||
北京和上海今天的天气情况<|im_end|>
|
||||
<|im_start|>assistant
|
||||
Action: realtime_aqi
|
||||
Action Input: {'city': '北京'}
|
||||
Action: realtime_aqi
|
||||
Action Input: {'city': '上海'}
|
||||
Observation:{"city": "北京", "aqi": "10", "unit": "celsius"}
|
||||
Observation:{"city": "上海", "aqi": "72", "unit": "fahrenheit"}
|
||||
根据天气预报工具,北京今天的空气质量指数为10,属于良好水平;上海今天的空气质量指数为72,属于轻度污染水平。<|im_end|>
|
||||
|
||||
[LABELS] [-100 * 233]Action: realtime_aqi
|
||||
Action Input: {'city': '北京'}
|
||||
Action: realtime_aqi
|
||||
Action Input: {'city': '上海'}
|
||||
Observation:[-100 * 45]根据天气预报工具,北京今天的空气质量指数为10,属于良好水平;上海今天的空气质量指数为72,属于轻度污染水平。<|im_end|>
|
||||
```
|
||||
|
||||
更多模型和agent_template的尝试可以使用以下代码,更多的agent template可选值参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/agent_template/__init__.py)。
|
||||
```python
|
||||
from swift import get_processor, get_template
|
||||
|
||||
tokenizer = get_processor('Qwen/Qwen3.5-2B')
|
||||
template = get_template(tokenizer) # 使用默认agent模板
|
||||
# template = get_template(tokenizer, agent_template='qwen3_5')
|
||||
print(f'agent_template: {template._agent_template}')
|
||||
data = {...}
|
||||
template.set_mode('train')
|
||||
encoded = template.encode(data)
|
||||
print(f'[INPUT_IDS] {template.safe_decode(encoded["input_ids"])}\n')
|
||||
print(f'[LABELS] {template.safe_decode(encoded["labels"])}')
|
||||
```
|
||||
|
||||
|
||||
## tools格式
|
||||
tools字段提供了模型可以调用的API信息。你需要提供tools的名字,描述和参数,示例如下:
|
||||
|
||||
```python
|
||||
tools = [{
|
||||
'type': 'function',
|
||||
'function': {
|
||||
'name': 'get_current_weather',
|
||||
'description': 'Get the current weather in a given location',
|
||||
'parameters': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'location': {
|
||||
'type': 'string',
|
||||
'description': 'The city and state, e.g. San Francisco, CA'
|
||||
},
|
||||
'unit': {
|
||||
'type': 'string',
|
||||
'enum': ['celsius', 'fahrenheit']
|
||||
}
|
||||
},
|
||||
'required': ['location']
|
||||
}
|
||||
}
|
||||
}]
|
||||
```
|
||||
|
||||
## loss_scale的使用
|
||||
|
||||
loss_scale参数可用于调节模型输出部分在训练过程中的损失权重。目前支持两种配置方式:字符串精确匹配和正则表达式匹配。
|
||||
|
||||
1. 字符串匹配示例:ReACT 格式
|
||||
|
||||
以 ReACT 格式为例,可通过 `--loss_scale react` 启用相应的 loss_scale 配置(配置文件详见 [react.json](https://github.com/modelscope/ms-swift/blob/main/swift/loss_scale/config/react.json))。该方式基于字符串精确匹配,配置中的字典映射需提供一个包含两个元素的列表,分别表示:当前匹配字符串本身的损失权重,
|
||||
从该字符串之后到下一个指定字符串之前的内容的损失权重。该设置的具体效果如下:
|
||||
- 'Action:' 和 'Action Input:' 字段自身及其后续内容的损失权重均为 2;
|
||||
- 'Thought:' 和 'Final Answer:' 字段自身及其后续内容的损失权重均为 1;
|
||||
- 'Observation:' 字段自身的权重为 2,但其后跟随的工具调用结果部分的损失权重为 0。
|
||||
|
||||
2. 正则匹配示例:忽略空思维块
|
||||
|
||||
在训练推理模型时,我们可能需要忽略数据集中存在的形如 `'<think>\n\n</think>\n\n'`的空思维标记损失计算。此时可使用 `--loss_scale ignore_empty_think`(配置文件详见 [ignore_empty_think.json](https://github.com/modelscope/ms-swift/blob/main/swift/loss_scale/config/ignore_empty_think.json))。该配置采用正则表达式匹配方式,字典映射的列表只需指定一个值,表示匹配内容的损失权重。该设置的具体效果如下:
|
||||
|
||||
- 所有与正则表达式`<think>\\s*</think>\\s*`匹配的字符串,loss_scale为0,即不计算损失。
|
||||
|
||||
使用代码测试loss_scale:
|
||||
```python
|
||||
from swift import get_processor, get_template
|
||||
|
||||
data = {"messages": [
|
||||
{"role": "user", "content": "aaaaa"},
|
||||
{"role": "assistant", "content": "<think>\n\n</think>\n\nabc<think>\n\n</think>\n\n123"},
|
||||
]}
|
||||
|
||||
template = get_template(get_processor('Qwen/Qwen3-8B'), loss_scale='ignore_empty_think')
|
||||
template.set_mode('train')
|
||||
inputs = template.encode(data)
|
||||
|
||||
print(template.safe_decode(inputs['labels']))
|
||||
# '[-100 * 14]abc<think>\n\n</think>\n\n123<|im_end|>\n'
|
||||
```
|
||||
|
||||
更多的loss_scale插件设计,请参考[架构](../Customization/Architecture.md#loss-scale)文档.
|
||||
|
||||
## 训练
|
||||
- 训练Base模型的Agent能力,通过修改`--model`切换不同模型,参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/train/agent/qwen2_5.sh)。
|
||||
- 训练GLM4的agent_template为hermes,参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/train/agent/glm4.sh)。
|
||||
- 使用`--loss_scale`对模型输出部分的损失权重进行调整,参加[这里](https://github.com/modelscope/ms-swift/tree/main/examples/train/agent/loss_scale)。
|
||||
|
||||
## 推理
|
||||
|
||||
- 🚀原始模型或者全参数训练后模型的推理,参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/infer/demo_agent.py)。
|
||||
- LoRA训练后推理,参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/train/agent/loss_scale/infer_lora.py)。
|
||||
|
||||
## 部署
|
||||
|
||||
服务端和客户端代码,参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/deploy/agent)。
|
||||
@@ -0,0 +1,964 @@
|
||||
# 命令行参数
|
||||
|
||||
命令行参数的介绍会分为基本参数,原子参数、集成参数和特定模型参数。**命令行最终使用的参数列表为集成参数。集成参数继承自基本参数和一些原子参数**。特定模型参数是针对于具体模型的参数,可以通过`--model_kwargs'`或者环境变量进行设置。Megatron-SWIFT命令行参数介绍可以在[Megatron-SWIFT训练文档](../Megatron-SWIFT/Command-line-parameters.md)中找到。
|
||||
|
||||
**提示:**
|
||||
- 命令行传入list使用空格隔开即可。例如:`--dataset <dataset_path1> <dataset_path2>`。
|
||||
- 命令行传入dict使用json。例如:`--model_kwargs '{"fps_max_frames": 12}'`。
|
||||
- 带🔥的参数为重要参数,刚熟悉ms-swift的用户可以先关注这些命令行参数。
|
||||
|
||||
## 基本参数
|
||||
|
||||
- 🔥tuner_backend: 可选为'peft','unsloth'。默认为'peft'。
|
||||
- 🔥tuner_type: 可选为'lora'、'full'、'lora_llm'、'longlora'、'adalora'、'llamapro'、'adapter'、'vera'、'boft'、'fourierft'、'reft'、'bone'。默认为'lora'。
|
||||
- 注意:在Megatron-SWIFT中默认为'full'。
|
||||
- 其中'lora_llm'代表对llm部分进行lora,vit/aligner部分使用'full'。你可以使用`vit_lr/aligner_lr`设置各自的学习率。
|
||||
- 🔥adapters: 用于指定adapter的id/path的list,默认为`[]`。该参数通常用于推理/部署命令,例如:`swift infer --model '<model_id_or_path>' --adapters '<adapter_id_or_path>'`。该参数偶尔也用于断点续训,该参数与`resume_from_checkpoint`的区别在于,**该参数只读取adapter权重**,而不加载优化器和随机种子,并不跳过已训练的数据集部分。
|
||||
- `--model`与`--adapters`的区别:`--model`后接完整权重的目录路径,内包含model/tokenizer/config等完整权重信息,例如`model.safetensors`。`--adapters`后接增量adapter权重目录路径的列表,内涵adapter的增量权重信息,例如`adapter_model.safetensors`。
|
||||
- 🔥external_plugins: 外部`plugin.py`文件列表,这些文件会被额外加载(即对模块进行`import`)。默认为`[]`。你可以传入自定义模型、对话模板和数据集注册的`.py`文件路径,参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/custom/sft.sh);或者自定义GRPO的组件,参考[这里](https://github.com/modelscope/ms-swift/tree/main/examples/train/grpo/plugin/run_external_reward_func.sh)。
|
||||
- seed: 全局随机种子,默认为42。
|
||||
- 注意:该随机种子与控制数据集随机的`data_seed`互不影响。
|
||||
- model_kwargs: 特定模型可传入的额外参数,该参数列表会在训练/推理时打印日志进行提示。例如`--model_kwargs '{"fps_max_frames": 12}'`。你也可以通过环境变量的方式设置,例如`FPS_MAX_FRAMES=12`。默认为None。
|
||||
- 注意:**若你在训练时指定了特定模型参数,请在推理时也设置对应的参数**,这可以提高训练效果。
|
||||
- 特定模型参数的含义可以在对应模型官方repo或者其推理代码中找到相应含义。ms-swift引入这些参数以确保训练的模型与官方推理代码效果对齐。
|
||||
- enable_npu_model_patch: 是否启用NPU模型层patch,默认为True。该参数仅控制NPU环境下模型相关的patch,通常不需要关闭;排查transformers原生行为或NPU模型patch兼容问题时可以设置为False。该参数需要在进程首次导入`swift.model`前作为启动参数传入。
|
||||
- load_args: 当指定`--resume_from_checkpoint`、`--model`、`--adapters`会读取保存文件中的`args.json`,读取的keys查看[base_args.py](https://github.com/modelscope/ms-swift/blob/main/swift/arguments/base_args/base_args.py)。推理和导出时默认为True,训练时默认为False。该参数通常不需要修改。
|
||||
- load_data_args: 如果将该参数设置为True,则会额外读取`args.json`中的数据参数。默认为False。**该参数通常用于推理时对训练中切分的验证集进行推理**,例如:`swift infer --adapters xxx --load_data_args true --stream true --max_new_tokens 512`。
|
||||
- use_hf: 控制模型下载、数据集下载、模型推送使用[ModelScope](https://modelscope.cn/)还是[HuggingFace](https://huggingface.co/)。默认为False,使用ModelScope。
|
||||
- 提示:如果你想在国外访问ModelScope,可以尝试使用[ModelScope国际版](https://modelscope.ai/home),设置环境变量`MODELSCOPE_DOMAIN='www.modelscope.ai'`即可。
|
||||
- hub_token: hub token. modelscope的hub token可以查看[这里](https://modelscope.cn/my/myaccesstoken)。默认为None。
|
||||
- ddp_timeout: 默认为18000000,单位为秒。
|
||||
- ddp_backend: 可选为"nccl"、"gloo"、"mpi"、"ccl"、"hccl"、"cncl"、"mccl"。默认为None,进行自动选择。
|
||||
- ignore_args_error: 用于兼容jupyter notebook。默认为False。
|
||||
|
||||
### 模型参数
|
||||
- 🔥model: [模型id](https://modelscope.cn/models)或模型本地路径。默认为None。
|
||||
- 🔥model_type: 模型类型。**我们将相同的模型架构、模型加载过程、template定义为一个`model_type`**。默认为None,即**根据`--model`的后缀和config.json中的'architectures'属性进行自动选择**。对应模型的model_type可以在[支持的模型列表](./Supported-models-and-datasets.md)中找到。
|
||||
- 注意:ms-swift中model_type的概念与`config.json`中的model_type不同。
|
||||
- 自定义模型通常需要自行注册`model_type`和`template`,具体可以参考[自定义模型文档](../Customization/Custom-model.md)。
|
||||
- model_revision: 模型版本,默认为None。
|
||||
- task_type: 默认为'causal_lm'。可选为'causal_lm'、'seq_cls'、'embedding'、'reranker'和'generative_reranker'。seq_cls的例子可以查看[这里](https://github.com/modelscope/ms-swift/tree/main/examples/train/seq_cls),embedding的例子查看[这里](https://github.com/modelscope/ms-swift/tree/main/examples/train/embedding)。
|
||||
- 若设置为'seq_cls',你通常需要额外设置`--num_labels`和`--problem_type`。
|
||||
- 🔥torch_dtype: 模型权重的数据类型,支持`float16`,`bfloat16`,`float32`。默认为None,从'config.json'文件中读取。
|
||||
- attn_impl: attention类型,可选项为'sdpa', 'eager', 'flash_attn', 'flash_attention_2', 'flash_attention_3', 'flash_attention_4'等。默认使用None,读取'config.json'。
|
||||
- 注意:这几种attention实现并不一定都支持,这取决于对应模型transformers实现的支持情况。
|
||||
- 若设置为'flash_attn'(兼容旧版本),则使用'flash_attention_2'。
|
||||
- 🔥experts_impl: 专家实现类型,可选项为'grouped_mm', 'batched_mm', 'eager'。默认为None。该特性需要"transformers>=5.0.0"。
|
||||
- new_special_tokens: 需要新增的特殊tokens。默认为`[]`。例子参考[这里](https://github.com/modelscope/ms-swift/tree/main/examples/train/new_special_tokens)。
|
||||
- 注意:你也可以传入以`.txt`结尾的文件路径,每行为一个special token。
|
||||
- num_labels: 分类模型(即`--task_type seq_cls`)需要指定该参数。代表标签数量,默认为None。
|
||||
- problem_type: 分类模型(即`--task_type seq_cls`)需要指定该参数。可选为'regression', 'single_label_classification', 'multi_label_classification'。默认为None,若模型为 reward_model 或 num_labels 为1,该参数为'regression',其他情况,该参数为'single_label_classification'。
|
||||
- rope_scaling: rope类型,你可以传入字符串,例如:`linear`、`dynamic`、`yarn`并结合传入`max_model_len`,ms-swift会自动设置对应的rope_scaling并覆盖'config.json'中的rope_scaling。或者你需要传入一个json字符串,例如`'{"factor":2.0, "type":"yarn"}'`,该值会直接覆盖'config.json'中的rope_scaling。默认为None。
|
||||
- max_model_len: 如果使用`rope_scaling`并传入字符串,可以设置`max_model_len`,该参数用来计算rope的`factor`倍数。该参数默认为None。若为非None,该参数会**覆盖**'config.json'中的`max_position_embeddings`值。
|
||||
- device_map: 模型使用的device_map配置,例如:'auto'、'cpu'、json字符串、json文件路径。该参数会**透传**入transformers的`from_pretrained`接口。默认为None,根据设备和分布式训练情况自动设置。
|
||||
- max_memory: device_map设置为'auto'或者'sequential'时,会根据max_memory进行模型权重的device分配,例如:`--max_memory '{0: "20GB", 1: "20GB"}'`。默认为None。该参数会透传入transformers的`from_pretrained`接口。
|
||||
- local_repo_path: 部分模型在加载时依赖于github repo,例如[deepseek-vl2](https://github.com/deepseek-ai/DeepSeek-VL2)。为了避免`git clone`时遇到网络问题,可以直接使用本地repo。该参数需要传入本地repo的路径, 默认为`None`。
|
||||
- init_strategy: 加载模型时,初始化模型中所有未初始化的参数(自定义模型架构时)。可选为'zero', 'uniform', 'normal', 'xavier_uniform', 'xavier_normal', 'kaiming_uniform', 'kaiming_normal', 'orthogonal'。默认为None。
|
||||
|
||||
|
||||
### 数据参数
|
||||
- 🔥dataset: 数据集id或路径的list。默认为`[]`。每个数据集的传入格式为:`'数据集id or 数据集路径:子数据集#采样数量'`,其中子数据集和取样数据可选。本地数据集支持jsonl、csv、json、文件夹等。**hub端的开源数据集可以通过`git clone`到本地并将文件夹传入而离线使用**。自定义数据集格式可以参考[自定义数据集文档](../Customization/Custom-dataset.md)。你可以传入`--dataset <dataset1> <dataset2>`来使用多个数据集。
|
||||
- 子数据集: 该参数只有当dataset为ID或者文件夹时生效。若注册时指定了subsets,且只有一个子数据集,则默认选择注册时指定的子数据集,否则默认为'default'。你可以使用`/`来选择多个子数据集,例如:`<dataset_id>:subset1/subset2`。你也可以使用'all'来选择注册时指定的所有子数据集,例如:`<dataset_id>:all`。注册例子可以参考[这里](https://modelscope.cn/datasets/swift/garbage_competition)。
|
||||
- 采样数量: 默认使用完整的数据集。你可以通过设置`#采样数`对选择的数据集进行采样,例如`<dataset_path#1000>`。若采样数少于数据样本总数,则进行随机选择(不重复采样)。若采样数高于数据样本总数,则只额外随机采样`采样数%数据样本总数`的样本,数据样本重复采样`采样数//数据样本总数`次。注意:流式数据集(`--streaming true`)只进行顺序采样。若设置`--dataset_shuffle false`,则非流式数据集也进行顺序采样。
|
||||
- 🔥val_dataset: 验证集id或路径的list。默认为`[]`。
|
||||
- 🔥cached_dataset: 使用缓存数据集(使用`swift export --to_cached_dataset true ...`命令产生),避免大型数据集训练/推理时,tokenize过程占用gpu时间。该参数用于设置缓存训练数据集文件夹路径,默认为`[]`。例子参考[这里](https://github.com/modelscope/ms-swift/tree/main/examples/train/cached_dataset)。
|
||||
- 提示:cached_dataset只会在数据集中额外存储length字段(为避免存储压力),并过滤掉会报错的数据样本。在训练/推理时,支持`--max_length`参数进行超长数据过滤/裁剪以及`--packing`参数。数据实际预处理过程将在训练时同步进行,该过程和训练是重叠的,并不会影响训练速度。(例外情况:当设置`--truncation_strategy split`会存储'input_ids',你需要在数据导出和训练时设置相同的`max_length`和`truncation_strategy`,packing兼容不受影响)
|
||||
- cached_dataset在`ms-swift`和`Megatron-SWIFT`之间是通用的,且支持pt/sft/infer/rlhf,使用`--template_mode`设置训练类型;支持embedding/reranker/seq_cls任务,使用`--task_type`设置任务类型。
|
||||
- 支持对cache_dataset进行采样,语法为`<cached_dataset_path>#采样数`,支持采样数高于和少于样本数的情况,功能与实现参考`--dataset`的介绍。
|
||||
- cached_val_dataset: 缓存验证数据集的文件夹路径,默认为`[]`。
|
||||
- 🔥split_dataset_ratio: 不指定val_dataset时从训练集拆分验证集的比例,默认为0.,即不从训练集切分验证集。
|
||||
- data_seed: 数据集随机种子,默认为42。
|
||||
- 🔥dataset_num_proc: 数据集预处理的进程数,默认为1。
|
||||
- 提示:纯文本模型建议将该值开大加速预处理速度。而多模态模型不建议开太大,这可能导致更慢的预处理速度(多模态模型若出现cpu利用率100%,但是处理速度极慢的情况,建议额外设置`OMP_NUM_THREADS`环境变量)。
|
||||
- 🔥load_from_cache_file: 是否从缓存中加载数据集,默认为False。**建议在实际运行时设置为True,debug阶段设置为False**。你可以修改`MODELSCOPE_CACHE`环境变量控制缓存的路径。
|
||||
- dataset_shuffle: 是否对dataset进行随机操作。默认为True。
|
||||
- 注意:**CPT/SFT的随机包括两个部分**:数据集的随机,由`dataset_shuffle`控制;train_dataloader中的随机,由`train_dataloader_shuffle`控制。
|
||||
- val_dataset_shuffle: 是否对val_dataset进行随机操作。默认为False。
|
||||
- streaming: 流式读取并处理数据集,默认False。(流式数据集的随机并不彻底,可能导致loss波动剧烈。)
|
||||
- 注意:需要额外设置`--max_steps`,因为流式数据集无法获得其长度。你可以通过设置`--save_strategy epoch`并设置较大的max_steps来实现与`--num_train_epochs`等效的训练。或者,你也可以设置`max_epochs`确保训练到对应epochs时退出训练,并对权重进行验证和保存。
|
||||
- 注意:流式数据集可以跳过预处理等待,将预处理时间与训练时间重叠。流式数据集的预处理只在rank0上进行,并通过数据分发的方式同步到其他进程,**其通常效率不如非流式数据集采用的数据分片读取方式**。当训练的world_size较大时,预处理和数据分发将成为训练瓶颈。
|
||||
- interleave_prob: 默认值为 None。在组合多个数据集时,默认使用datasets库的 `concatenate_datasets` 函数;如果设置了该参数,则会使用 `interleave_datasets` 函数。该参数通常用于流式数据集的组合,并会作为参数传入 `interleave_datasets` 函数中。该参数不对`--val_dataset`生效。
|
||||
- stopping_strategy: 可选为"first_exhausted", "all_exhausted",默认为"first_exhausted"。传入`interleave_datasets`函数中。该参数不对`--val_dataset`生效。
|
||||
- shuffle_buffer_size: 该参数用于指定**流式数据集**的随机buffer大小,默认为1000。该参数只在`dataset_shuffle`设置为true时有效。
|
||||
- download_mode: 数据集下载模式,包含`reuse_dataset_if_exists`和`force_redownload`,默认为'reuse_dataset_if_exists'。
|
||||
- 通常在使用hub端数据集报错时设置为`--download_mode force_redownload`。
|
||||
- columns: 用于对数据集进行列映射,使数据集满足AutoPreprocessor可以处理的样式,AutoPreprocessor可以处理的数据集格式查看[自定义数据集文档](../Customization/Custom-dataset.md)。你可以传入json字符串,例如:`'{"text1": "query", "text2": "response"}'`,代表将数据集中的"text1"映射为"query","text2"映射为"response",而query-response格式可以被AutoPreprocessor处理。默认为None。
|
||||
- strict: 如果为True,则数据集只要某行有问题直接抛错,否则会丢弃出错数据样本。默认False。该参数通常用于排查错误。
|
||||
- 🔥remove_unused_columns: 是否删除数据集中不被使用的列,默认为True。
|
||||
- 若该参数设置为False,则将额外的数据集列传递至trainer的`compute_loss`函数内,**方便自定义损失函数使用额外的数据集列**。
|
||||
- GRPO该参数的默认值为False。
|
||||
- disable_auto_column_mapping: 默认情况下会对数据集的列名进行自动映射,该参数用于关闭此行为(columns 参数依旧生效),默认为False。自动映射规则如下:
|
||||
- 以下字段会自动转成对应的images, videos, audios字段。
|
||||
- images: image, images.
|
||||
- videos: video, videos.
|
||||
- audios: audio, audios.
|
||||
- 以下字段会自动转成对应的system、query、response字段。(solution字段会保留)
|
||||
- system: 'system', 'system_prompt'.
|
||||
- query: 'query', 'prompt', 'input', 'instruction', 'question', 'problem'.
|
||||
- response: 'response', 'answer', 'output', 'targets', 'target', 'answer_key', 'answers', 'solution', 'text', 'completion', 'content'.
|
||||
- 🔥model_name: **仅用于自我认知任务**,只对`swift/self-cognition`数据集生效,替换掉数据集中的`{{NAME}}`通配符。传入模型中文名和英文名,以空格分隔,例如:`--model_name 小黄 'Xiao Huang'`。默认为None。
|
||||
- 🔥model_author: 仅用于自我认知任务,只对`swift/self-cognition`数据集生效,替换掉数据集中的`{{AUTHOR}}`通配符。传入模型作者的中文名和英文名,以空格分隔,例如:`--model_author '魔搭' 'ModelScope'`。默认为None。
|
||||
- custom_dataset_info: 自定义数据集注册的json文件路径,参考[自定义数据集](../Customization/Custom-dataset.md)和[内置'dataset_info.json'文件](https://github.com/modelscope/ms-swift/blob/main/swift/dataset/data/dataset_info.json)。默认为`[]`。
|
||||
|
||||
### 模板参数
|
||||
- 🔥template: 对话模板类型。默认为None,自动选择对应model的template类型,对应关系参考[支持的模型列表](./Supported-models-and-datasets.md)。
|
||||
- 🔥system: 自定义system字段,可以传入字符串或者**txt文件路径**。默认为None,使用注册template时的默认system。
|
||||
- 注意:数据集中的system**优先级**最高,然后是`--system`,最后是注册template时设置的`default_system`。
|
||||
- 🔥max_length: 限制单数据集样本经过`tokenizer.encode`后的tokens最大长度,超过的数据样本会根据`truncation_strategy`参数进行处理(避免训练OOM)。默认为None,即设置为模型支持的tokens最大长度(max_model_len)。
|
||||
- 当PPO、GRPO、GKD和推理情况下,`max_length`代表`max_prompt_length`。
|
||||
- truncation_strategy: 如果单样本的tokens超过`max_length`如何处理,支持'delete'、'left'、'right'和'split',代表删除、左侧裁剪、右侧裁剪和切成多条数据样本,默认为'delete'。
|
||||
- 注意:`--truncation_strategy split`只支持预训练时使用,即`swift/megatron pt`场景下,该策略会将超长字段切成多条数据样本,从而避免tokens浪费。该策略只支持纯文本数据集,多模态数据集无法正确处理pixel_values的切分。
|
||||
- 注意:若多模态模型的训练时将'truncation_strategy'设置为`left`或`right`,**ms-swift会保留所有的image_token等多模态tokens**,这可能会导致训练时OOM。
|
||||
- 🔥max_pixels: 多模态模型输入图片的最大像素数(H\*W),将超过该限制的图像进行缩放(避免训练OOM)。默认为None,不限制最大像素数。
|
||||
- 注意:该参数适用于所有的多模态模型。而Qwen2.5-VL特有的模型参数`MAX_PIXELS`(你可以在文档最下面找到)只针对Qwen2.5-VL模型。
|
||||
- 🔥agent_template: Agent模板,确定如何将工具列表'tools'转换成'system'、如何在推理/部署时从模型回复中提取toolcall部分,以及确定'messages'中`{"role": "tool_call", "content": "xxx"}`, `{"role": "tool_response", "content": "xxx"}`的模板格式。可选为"react_en", "hermes", "glm4", "qwen_en", "toolbench"等,更多请查看[这里](https://github.com/modelscope/ms-swift/blob/main/swift/agent_template/mapping.py)。默认为None,根据模型类型进行自动选择。可以参考[Agent文档](./Agent-support.md)。
|
||||
- norm_bbox: 控制如何缩放边界框(即数据集中的"bbox",里面的数据为绝对坐标,参考[自定义数据集文档](https://swift.readthedocs.io/zh-cn/latest/Customization/Custom-dataset.html#grounding))。选项为'norm1000'和'none'。'norm1000'表示将bbox坐标缩放至千分位坐标,而'none'表示不进行缩放。默认值为None,将根据模型自动选择。
|
||||
- 当**图片在训练中发生缩放时**(例如设置了max_pixels参数),该参数也能很好进行解决。
|
||||
- use_chat_template: 使用chat模板还是generation模板(generation模板通常用于预训练时)。默认为`True`。
|
||||
- 注意:`swift pt`默认为False,使用generation模板。该参数可以很好的**兼容多模态模型**。
|
||||
- padding_side: 当训练`batch_size>=2`时的padding_side,可选值为'left'、'right',默认为'right'。(推理时的batch_size>=2时,只进行左padding)。
|
||||
- 注意:PPO和GKD默认设置为'left'。
|
||||
- 🔥padding_free: 将一个batch中的数据进行展平而避免数据padding,从而降低显存占用并加快训练(**同一batch的不同序列之间依旧是不可见的**)。默认为False。当前支持CPT/SFT/DPO/GRPO/KTO/GKD。
|
||||
- 注意:使用padding_free请结合`--attn_impl flash_attn`使用且"transformers>=4.44",具体查看[该PR](https://github.com/huggingface/transformers/pull/31629)。(同packing)
|
||||
- **相较于packing,padding_free不需要额外的预处理时间,但packing的训练速度更快且显存占用更稳定**。
|
||||
- 🔥loss_scale: 训练tokens的loss权重设置。默认为`'default'`。loss_scale包含3种基本策略:'default'、'last_round'、'all',以及其他策略:'ignore_empty_think'以及agent需要的:'react'、'hermes'、'qwen'、'agentflan'、'alpha_umi'等,可选值参考[loss_scale模块](https://github.com/modelscope/ms-swift/blob/main/swift/loss_scale/mapping.py)。ms-swift 支持了基本策略和其他策略的混用,例如:`'default+ignore_empty_think'`,`'last_round+ignore_empty_think'`。若没有指定基本策略,则默认为'default',例如:'hermes'与'default+hermes'等价。
|
||||
- 'default': 所有response(含history)以权重1计算交叉熵损失(**messages中的system/user/多模态tokens以及Agent训练中`tool_response`部分不计算损失**)。(**SFT默认为该值**)
|
||||
- 'last_round': 只计算最后一轮response的损失。最后一轮含义为最后一个"user"之后的所有内容。(**RLHF默认为该值**)
|
||||
- 'all': 计算所有tokens的损失。(**`swift pt`默认为该值**)
|
||||
- 'ignore_empty_think': 忽略空的`'<think>\n\n</think>\n\n'`损失计算。(满足正则匹配`'<think>\\s*</think>\\s*'`即可)。
|
||||
- 'react', 'hermes', 'qwen': 将`tool_call`部分的loss权重调整为2。
|
||||
- 注意:在"ms-swift>=4.3.1",支持了多个非基本策略串联使用(依次处理上一个策略的输出片段,权重相乘),例如:`'last_round+hermes+ignore_empty_think'`,其中'last_round'为基础策略,'hermes+ignore_empty_think'为多个非基本策略的串联使用,共用基础策略。
|
||||
- disable_ignore_empty_think: 是否禁用对混合思考模型的loss_scale自动追加`ignore_empty_think`策略。默认为`False`,即对混合思考模型(如Qwen3.5-4B)自动在loss_scale后追加`+ignore_empty_think`,使空的`'<think>\n\n</think>\n\n'`不参与损失计算。若用户已手动在loss_scale中指定了`ignore_empty_think`,则不会重复追加。该参数仅在训练时生效,对纯思考模型和非思考模型无效。设置为`True`可关闭此默认行为。
|
||||
- 注意:该参数在"ms-swift>=4.3.1"增加。在"ms-swift<4.3.1"需手动添加`--loss_scale ignore_empty_think`。
|
||||
- is_binary_loss_scale: 当loss_scale只可能为0/1时,该语义可被labels替代,将loss_scale为0的部分的labels设置为-100,从而兼容liger_kernel降低显存。默认为None,进行自动设置。
|
||||
- sequence_parallel_size: 序列并行大小,默认是1。当前支持CPT/SFT/DPO/GRPO。训练脚本参考[这里](https://github.com/modelscope/ms-swift/tree/main/examples/train/sequence_parallel)。
|
||||
- template_backend: 选择template后端,可选为'swift'、'jinja',默认为'swift'。如果使用jinja,则使用transformers的`apply_chat_template`。
|
||||
- 注意:jinja的template后端只支持推理,不支持训练(无法确定损失计算的tokens范围)。
|
||||
- response_prefix: response的前缀字符,该参数只在推理时生效。默认为None,根据enable_thinking参数和模版类型确定。
|
||||
- enable_thinking: 该参数在推理时生效,代表是否开启thinking模式。默认为None,默认值由模板(模型)类型确定(混合思考/非思考模板为False,思考模板为True)。若enable_thinking为False,则增加非思考前缀,例如Qwen3-8B混合思考模型增加前缀`'<think>\n\n</think>\n\n'`,Qwen3-8B-Thinking则不增加前缀。若enable_thinking为True,则增加思考前缀,例如`'<think>\n'`。注意:该参数的优先级低于`response_prefix`参数。
|
||||
- 注意:"ms-swift<4.3.1",混合思考模板默认值为True,在"ms-swift>=4.3.1"修改为False。
|
||||
- preserve_thinking: 是否在推理和训练时,对历史思考内容进行保留。当设置为True时,则保留所有轮次的思考内容。若设置为False,则只保留最后一轮的思考内容(即最后一个user信息后的内容)。默认为None。
|
||||
- 默认行为:对于思考模型(思考/混合思考)或显式开启enable_thinking,我们会在推理和训练时,默认设置为False,只保留最后一轮的思考内容。若训练时的`loss_scale`基本策略不为'last_round',例如为'default',则默认为True,不对历史的思考内容进行删除。
|
||||
- add_non_thinking_prefix: 该参数只在训练时生效,代表是否对数据样本assistant部分**不以思考标记`'<think>'`开头**的数据样本增加非思考前缀(通常混合思考模型含非思考前缀)。该特性可以让swift内置的数据集可以训练混合思考模型。默认值为True。例如:例如Qwen3-8B混合思考模型的非思考前缀为`'<think>\n\n</think>\n\n'`,Qwen3-8B-Thinking/Instruct的非思考前缀为`''`。注意:训练时,loss_scale的基本策略为last_round,则只对最后一轮做此修改;否则,例如为'default'、'all',则对每一轮数据做此修改。若设置为False,则不对数据样本增加非思考前缀。
|
||||
|
||||
### 生成参数
|
||||
参考[generation_config](https://huggingface.co/docs/transformers/main_classes/text_generation#transformers.GenerationConfig)文档。
|
||||
|
||||
- 🔥max_new_tokens: 推理最大生成新tokens的数量。默认为None,无限制。
|
||||
- temperature: 温度参数,温度越高,输出的随机性越大。默认为None,读取'generation_config.json'。
|
||||
- 你可以设置`--temperature 0`或者`--top_k 1`以取消推理随机性。
|
||||
- top_k: top_k参数,保留概率最高的top_k数量 tokens用于生成,默认为None。读取'generation_config.json'。
|
||||
- top_p: top_p参数,保留概率最高的累计概率达到 top_p 的tokens用于生成,默认为None。读取generation_config.json。
|
||||
- repetition_penalty: 重复惩罚参数。1.0 表示不进行惩罚。默认为None,读取generation_config.json。
|
||||
- num_beams: beam search的并行保留数量,默认为1。
|
||||
- 🔥stream: 流式输出,默认为`None`,即使用交互式界面时为True,数据集批量推理时为False。
|
||||
- stop_words: 除了eos_token外额外的停止词,默认为`[]`。
|
||||
- 注意:eos_token会在输出respsone中被删除,额外停止词会在输出中保留。
|
||||
- logprobs: 是否输出logprobs,默认为False。
|
||||
- top_logprobs: 输出top_logprobs的数量,默认为None。
|
||||
- structured_outputs_regex: 结构化输出(引导解码)的正则表达式模式。设置后,模型生成将被约束为匹配指定的正则表达式模式。仅在`infer_backend`为`vllm`时生效。默认为`None`。
|
||||
|
||||
### 量化参数
|
||||
以下为加载模型时量化的参数,具体含义可以查看[量化](https://huggingface.co/docs/transformers/main/en/main_classes/quantization)文档。这里不包含`swift export`中涉及的`gptq`、`awq`量化参数。
|
||||
|
||||
- 🔥quant_method: 加载模型时采用的量化方法,可选项为'bnb'、'hqq'、'eetq'、'quanto'和'fp8',默认为None。
|
||||
- 若对awq/gptq量化模型进行qlora训练,则不需要设置额外`quant_method`等量化参数。
|
||||
- 🔥quant_bits: 量化bits数,默认为None。
|
||||
- hqq_axis: hqq量化axis,默认为None。
|
||||
- bnb_4bit_compute_dtype: bnb量化计算类型,可选为`float16`、`bfloat16`、`float32`。默认为None,设置为`torch_dtype`。
|
||||
- bnb_4bit_quant_type: bnb量化类型,支持`fp4`和`nf4`,默认为`nf4`。
|
||||
- bnb_4bit_use_double_quant: 是否使用双重量化,默认为`True`。
|
||||
- bnb_4bit_quant_storage: bnb量化存储类型,默认为None。
|
||||
|
||||
### RAY参数
|
||||
|
||||
- use_ray: boolean类型。是否使用ray,默认为`False`
|
||||
- ray_exp_name: ray实验名字,这个字段会用作cluster和worker名称前缀,可以不填
|
||||
- device_groups: 字符串(jsonstring)类型。在使用ray时,该字段必须配置,具体可以查看[ray文档](Ray.md)。
|
||||
|
||||
### yaml/json支持
|
||||
|
||||
这里以`swift sft`为例子,yaml/json的方式启动也支持`swift infer/rlhf/...`以及`megatron sft/rlhf`。请参考[这里的例子](https://github.com/modelscope/ms-swift/tree/main/examples/yaml)。
|
||||
- yaml/json文件会在训练/推理后,存储在`output_dir`中。
|
||||
|
||||
```shell
|
||||
swift sft xxx.yaml
|
||||
swift sft xxx.json
|
||||
```
|
||||
|
||||
xxx.yaml/xxx.json的内容为具体命令行配置:
|
||||
|
||||
```yaml
|
||||
model: "Qwen/Qwen2.5-7B-Instruct"
|
||||
dataset: "swift/self-cognition#500"
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"model": "Qwen/Qwen2.5-7B-Instruct",
|
||||
"dataset": "swift/self-cognition#500"
|
||||
}
|
||||
```
|
||||
|
||||
你也可以混合使用yaml和命令行方式。例如yaml为不经常修改的参数,命令行传入常修改参数。
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift infer examples/yaml/deepspeed/infer.yaml \
|
||||
--adapters output/vx-xxx/checkpoint-xxx
|
||||
```
|
||||
|
||||
如何在yaml/json中指定环境环境变量:
|
||||
```yaml
|
||||
ENV:
|
||||
MAX_PIXELS: '1003520'
|
||||
VIDEO_MAX_PIXELS: '50176'
|
||||
FPS_MAX_FRAMES: '12'
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"ENV": {
|
||||
"MAX_PIXELS": "1003520",
|
||||
"VIDEO_MAX_PIXELS": "50176",
|
||||
"FPS_MAX_FRAMES": "12"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 原子参数
|
||||
|
||||
### Seq2SeqTrainer参数
|
||||
|
||||
该参数列表继承自transformers `Seq2SeqTrainingArguments`,ms-swift对其默认值进行了覆盖。未列出的请参考[HF官方文档](https://huggingface.co/docs/transformers/main/en/main_classes/trainer#transformers.Seq2SeqTrainingArguments)。
|
||||
|
||||
- 🔥output_dir: 模型预测结果和检查点将被写入的输出目录。默认为None,设置为`'output/<model_name>'`。
|
||||
- 🔥gradient_checkpointing: 是否使用gradient_checkpointing,默认为True。该参数可以显著降低显存占用,但降低训练速度。
|
||||
- 🔥vit_gradient_checkpointing: 多模态模型训练时,是否对vit部分开启gradient_checkpointing。默认为None,即当`--freeze_vit`为`false`时开启。例子参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/train/multimodal/vit_gradient_checkpointing.sh)。
|
||||
- 🔥deepspeed: 默认为None。可以设置为'zero0', 'zero1', 'zero2', 'zero3', 'zero2_offload', 'zero3_offload'来使用ms-swift内置的deepspeed配置文件。你也可以传入自定义deepspeed配置文件的路径。
|
||||
- zero_hpz_partition_size: 默认为None,这个参数是ZeRO++的特性,即node内模型分片,node间数据分片,如果遇到grad_norm NaN,请尝试使用`--torch_dtype float16`。
|
||||
- deepspeed_autotp_size: DeepSpeed张量并行大小,默认为1。使用DeepSpeed AutoTP时需将参数`--deepspeed`设置为'zero0'、'zero1'或'zero2'。(注意:该功能只支持全参数)
|
||||
- 🔥fsdp: FSDP2分布式训练配置。默认为None。可以设置为'fsdp2'来使用ms-swift内置的FSDP2配置文件。你也可以传入自定义FSDP配置文件的路径。FSDP2是PyTorch原生的分布式训练方案,与DeepSpeed二选一使用。
|
||||
- 🔥per_device_train_batch_size: 默认值1。
|
||||
- 🔥per_device_eval_batch_size: 默认值1。
|
||||
- 🔥gradient_accumulation_steps: 梯度累加。**默认为None,即设置gradient_accumulation_steps使得total_batch_size>=16**。total_batch_size等于`per_device_train_batch_size * gradient_accumulation_steps * world_size`。在GRPO训练中,默认为1。
|
||||
- 在CPT/SFT训练中,梯度累加的训练效果等价使用更大的batch_size,但在RLHF训练中,训练效果并不等价。
|
||||
- weight_decay: weight衰减系数,默认值0.1。
|
||||
- adam_beta1: Adam系列优化器中一阶矩估计(动量)的指数衰减率。默认为0.9。
|
||||
- adam_beta2: Adam系列优化器中二阶矩估计(方差)的指数衰减率。默认为0.95。
|
||||
- adam_epsilon: Adam系列优化器中用于数值稳定性的epsilon值。默认为1e-8。
|
||||
- 🔥learning_rate: 学习率,**全参数训练默认为1e-5,LoRA训练等tuners为1e-4**。
|
||||
- 提示:若要设置`min_lr`,您可以传入参数`--lr_scheduler_type cosine_with_min_lr --lr_scheduler_kwargs '{"min_lr": 1e-6}'`。
|
||||
- 🔥vit_lr: 当训练多模态大模型时,该参数指定vit的学习率,默认为None,等于learning_rate。通常与`--freeze_vit`、`--freeze_aligner`参数结合使用。
|
||||
- 提示:在日志中打印的"learning_rate"为`param_groups[0]`的学习率,其中param_groups的顺序依次是vit, aligner, llm(若含可训练参数)。
|
||||
- 🔥aligner_lr: 当训练多模态大模型时,该参数指定aligner的学习率,默认为None,等于learning_rate。
|
||||
- lr_scheduler_type: lr_scheduler类型,默认为'cosine'。常见选择:'linear', 'constant', 'cosine_with_min_lr'。
|
||||
- lr_scheduler_kwargs: lr_scheduler其他参数。默认为None。
|
||||
- gradient_checkpointing_kwargs: 传入`torch.utils.checkpoint`中的参数。例如设置为`--gradient_checkpointing_kwargs '{"use_reentrant": false}'`。默认为None。
|
||||
- 注意:当使用DDP而不使用deepspeed/fsdp,且gradient_checkpointing_kwargs为None,会默认设置其为`'{"use_reentrant": false}'`而避免出现报错。
|
||||
- full_determinism: 确保训练中获得可重现的结果,注意:这会对性能产生负面影响。默认为False。
|
||||
- 🔥report_to: 默认值为`tensorboard`。你也可以指定`--report_to tensorboard wandb swanlab`、`--report_to all`。
|
||||
- 如果你指定了`--report_to wandb`,你可以通过`WANDB_PROJECT`设置项目名称,`WANDB_API_KEY`指定账户对应的API KEY。
|
||||
- logging_first_step: 是否记录第一个step的日志,默认为True。
|
||||
- logging_steps: 日志打印间隔,默认为5。
|
||||
- router_aux_loss_coef: 用于moe模型训练时,设置 aux_loss 的权重,默认为`0.`。
|
||||
- enable_dft_loss: 是否在SFT训练中使用[DFT](https://arxiv.org/abs/2508.05629) (Dynamic Fine-Tuning) loss,默认为False。
|
||||
- enable_channel_loss: 启用channel loss,默认为`False`。你需要在数据集中准备"channel"字段,ms-swift会根据该字段分组统计loss(若未准备"channel"字段,则归为默认`None` channel)。数据集格式参考[channel loss](../Customization/Custom-dataset.md#channel-loss)。channel loss兼容packing/padding_free/loss_scale等技术。
|
||||
- safe_serialization: 是否存储为safetensors,默认为True。
|
||||
- max_shard_size: 单存储文件最大大小,默认'5GB'。
|
||||
- logging_dir: tensorboard日志保存路径。默认为None,即设置为`f'{self.output_dir}/runs'`。
|
||||
- predict_with_generate: 验证时使用生成式的方式,默认为False。
|
||||
- metric_for_best_model: 默认为None,即当`predict_with_generate`设置为False时,设置为'loss',否则设置为'rouge-l'(在PPO训练时,不进行默认值设置;GRPO训练设置为'reward')。
|
||||
- greater_is_better: 默认为None,即当`metric_for_best_model`含'loss'时,设置为False,否则设置为True。
|
||||
- max_epochs: 训练到`max_epochs`时强制退出训练,并对权重进行验证和保存。该参数在使用流式数据集时很有用。默认为None。
|
||||
|
||||
其他重要参数:
|
||||
- 🔥num_train_epochs: 训练的epoch数,默认为3。
|
||||
- 🔥save_strategy: 保存模型的策略,可选为'no'、'steps'、'epoch',默认为'steps'。
|
||||
- 🔥save_steps: 默认为500。
|
||||
- 🔥eval_strategy: 评估策略。默认为None,跟随`save_strategy`的策略。
|
||||
- 若不使用`val_dataset`和`eval_dataset`且`split_dataset_ratio`为0,则默认为'no'。
|
||||
- 🔥eval_steps: 默认为None,如果存在评估数据集,则跟随`save_steps`的策略。
|
||||
- eval_on_start: 是否在训练前执行一次评估步骤,以确保验证步骤能正常工作。默认为False。
|
||||
- 🔥save_total_limit: 最多保存的checkpoint数,会将过期的checkpoint进行删除。默认为None,保存所有的checkpoint。若设置为2,则保存best checkpoint和last checkpoint。
|
||||
- max_steps: 最大训练的steps数。在数据集为流式时需要被设置。默认为-1。
|
||||
- 🔥warmup_ratio: 默认为0.。
|
||||
- save_on_each_node: 在每一个节点都进行权重保存。默认为False。该参数在多机训练时需要被考虑。
|
||||
- 提示:在多机训练时,通常将`output_dir`设置为节点共享目录,因此无需额外设置该参数。
|
||||
- save_only_model: 是否只保存模型权重而不包含优化器状态,随机种子状态等内容,这在全参数训练时可以减少保存的时间消耗和空间占用。默认为False。
|
||||
- 🔥resume_from_checkpoint: 断点续训参数,指定checkpoint路径。默认为None。
|
||||
- 提示:**断点续训请保持其他参数不变,额外增加`--resume_from_checkpoint checkpoint_dir`**。权重等信息将在trainer中读取。
|
||||
- 注意: resume_from_checkpoint会读取模型权重,优化器状态,随机种子,并从上次训练的steps继续开始训练。你可以指定`--resume_only_model`只读取模型权重。
|
||||
- resume_only_model: 默认为False。如果在指定resume_from_checkpoint的基础上,将该参数设置为True,则仅resume模型权重,而忽略优化器状态和随机种子。
|
||||
- 注意:**resume_only_model默认将进行数据跳过**,此行为可通过 `ignore_data_skip` 参数控制。
|
||||
- ignore_data_skip: 当设置`resume_from_checkpoint`和`resume_only_model`时,该参数控制是否跳过已经训练的数据,并将epoch和迭代数等训练状态进行恢复。默认为False。若设置为True,则将不加载训练状态并不进行数据跳过,将从迭代数0开始训练。
|
||||
- 🔥ddp_find_unused_parameters: 默认为None。
|
||||
- 🔥dataloader_num_workers: 默认为None,若是windows平台,则设置为0,否则设置为1。
|
||||
- dataloader_pin_memory: 默认为True。
|
||||
- dataloader_persistent_workers: 默认为False。
|
||||
- dataloader_prefetch_factor: 默认为None。若 `dataloader_num_workers > 0`,则设置为2。每个工作进程预先加载的批次数量。2 表示所有工作进程总共会预取 2 * num_workers 个批次。
|
||||
- train_dataloader_shuffle: CPT/SFT训练的dataloader是否随机,默认为True。该参数对IterableDataset无效(即对流式数据集失效)。IterableDataset采用顺序的方式读取。
|
||||
- optim: 优化器,默认值为 `"adamw_torch"` (对于 torch>=2.8 为 `"adamw_torch_fused"`)。完整的优化器列表请参见 [training_args.py](https://github.com/huggingface/transformers/blob/main/src/transformers/training_args.py) 中的 `OptimizerNames`。
|
||||
- optim_args: 提供给优化器的可选参数,默认为None。
|
||||
- group_by_length: 是否在训练数据集中将长度大致相同的样本分组在一起(有随机因素),以最小化填充并确保各节点与进程的负载均衡以提高效率。默认为False。具体算法参考`transformers.trainer_pt_utils.get_length_grouped_indices`。
|
||||
- 🔥neftune_noise_alpha: neftune添加的噪声系数。默认为0,通常可以设置为5、10、15。
|
||||
- 🔥use_liger_kernel: 是否启用[Liger](https://github.com/linkedin/Liger-Kernel)内核加速训练并减少显存消耗。默认为False。示例shell参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/train/liger)。
|
||||
- 注意:liger_kernel不支持device_map,请使用DDP/DeepSpeed进行多卡训练。liger_kernel目前只支持`task_type='causal_lm'`。
|
||||
- average_tokens_across_devices: 是否在设备之间进行token数平均。如果设置为True,将使用all_reduce同步`num_tokens_in_batch`以进行精确的损失计算。默认为False。
|
||||
- max_grad_norm: 梯度裁剪。默认为1.。
|
||||
- 注意:日志中的grad_norm记录的是裁剪前的值。
|
||||
- push_to_hub: 推送checkpoint到hub。默认为False。
|
||||
- hub_model_id: 默认为None。
|
||||
- hub_private_repo: 默认为False。
|
||||
|
||||
### Tuner参数
|
||||
- 🔥freeze_llm: 该参数只对多模态模型生效,可用于全参数训练和LoRA训练,但会产生不同的效果。若是全参数训练,将freeze_llm设置为True会将LLM部分权重进行冻结;若是LoRA训练且`target_modules`设置为'all-linear',将freeze_llm设置为True将会取消在LLM部分添加LoRA模块。该参数默认为False。
|
||||
- 🔥freeze_vit: 该参数只对多模态模型生效,可用于全参数训练和LoRA训练,但会产生不同的效果。若是全参数训练,将freeze_vit设置为True会将vit部分权重进行冻结;若是LoRA训练且`target_modules`设置为'all-linear',将freeze_vit设置为True将会取消在vit部分添加LoRA模块。该参数默认为True。
|
||||
- 注意:**这里的vit不仅限于vision_tower, 也包括audio_tower**。若是Omni模型,若你只希望对vision_tower加LoRA,而不希望对audio_tower加LoRA,你可以修改[这里的代码](https://github.com/modelscope/ms-swift/blob/a5d4c0a2ce0658cef8332d6c0fa619a52afa26ff/swift/llm/model/model_arch.py#L544-L554)。
|
||||
- 🔥freeze_aligner: 该参数只对多模态模型生效,可用于全参数训练和LoRA训练,但会产生不同的效果。若是全参数训练,将freeze_aligner设置为True会将aligner(也称为projector)部分权重进行冻结;若是LoRA训练且`target_modules`设置为'all-linear',将freeze_aligner设置为True将会取消在aligner部分添加LoRA模块。该参数默认为True。
|
||||
- 🔥target_modules: 指定lora模块, 默认为`['all-linear']`。你也可以设置为module的后缀,例如:`--target_modules q_proj k_proj v_proj`。该参数不限于LoRA,可用于其他tuners。
|
||||
- 注意:在LLM和多模态LLM中,'all-linear'的行为有所不同。若是LLM则自动寻找除lm_head外的linear并附加tuner;**若是多模态LLM,则默认只在LLM上附加tuner,该行为可以被`freeze_llm`、`freeze_vit`、`freeze_aligner`控制**。
|
||||
- 🔥target_regex: 指定lora模块的regex表达式,默认为`None`。如果该值传入,则target_modules参数失效。例如你可以设置`--target_regex '^(language_model).*\.(q_proj|k_proj|v_proj|o_proj|gate_proj|up_proj|down_proj)$'`,将符合该正则的模块指定为LoRA模块。该参数不限于LoRA,可用于其他tuners。
|
||||
- target_parameters: 要替换为LoRA的参数名称列表。该参数的行为与 `target_modules` 类似,但传入的应是参数名称而不是模块名称。该特性需要安装"peft>=0.17.0"。例如,在 Hugging Face Transformers 中许多混合专家(MoE)层中,并未使用 `nn.Linear`,而是使用了 `nn.Parameter`。这时可以使用target_parameters参数实现。
|
||||
- 注意:该参数需要设置`lora_dropout`为 0。
|
||||
- init_weights: 初始化weights的方法,LoRA可以指定为'true'、'false'、'gaussian'、'pissa'、'pissa_niter_[number of iters]'、'olora'、'loftq'、'lora-ga',Bone可以指定为'true'、'false'、'bat'。默认值'true'。
|
||||
- 🔥modules_to_save: 在已附加tuner后,额外指定一部分原模型模块参与训练和存储。默认为`[]`。该参数不限于LoRA,可用于其他tuners。例如设置为`--modules_to_save embed_tokens lm_head`,在LoRA训练中解开embed_tokens和lm_head层进行训练,这两部分的权重信息最终会保存在`adapter_model.safetensors`中。
|
||||
|
||||
#### 全参
|
||||
- freeze_parameters: 需要被冻结参数的前缀,默认为`[]`。
|
||||
- freeze_parameters_regex: 需要被冻结参数的正则表达式,默认为None。
|
||||
- freeze_parameters_ratio: 从下往上冻结的参数比例,默认为0。可设置为1将所有参数冻结,结合`trainable_parameters`设置可训练参数。
|
||||
- trainable_parameters: 额外可训练参数的前缀,默认为`[]`。
|
||||
- trainable_parameters_regex: 匹配额外可训练参数的正则表达式,默认为None。
|
||||
- 备注:`trainable_parameters`、`trainable_parameters_regex`的优先级高于`freeze_parameters`、`freeze_parameters_regex`和`freeze_parameters_ratio`。例如:当指定全参数训练时,会将所有模块设置为可训练的状态,随后根据`freeze_parameters`、`freeze_parameters_regex`、`freeze_parameters_ratio`将部分参数冻结,最后根据`trainable_parameters`、`trainable_parameters_regex`重新打开部分参数参与训练。
|
||||
|
||||
#### LoRA
|
||||
- 🔥lora_rank: 默认为`8`。
|
||||
- 🔥lora_alpha: 默认为`32`。
|
||||
- lora_dropout: 默认为`0.05`。
|
||||
- lora_bias: 默认为`'none'`,可以选择的值: 'none'、'all'。如果你要将bias全都设置为可训练,你可以设置为`'all'`。
|
||||
- lora_dtype: 指定lora模块的dtype类型。支持'float16'、'bfloat16'、'float32'。默认为None,跟随peft行为。
|
||||
- 🔥use_dora: 默认为`False`,是否使用`DoRA`。
|
||||
- use_rslora: 默认为`False`,是否使用`RS-LoRA`。
|
||||
- 🔥lorap_lr_ratio: LoRA+参数,默认值`None`,建议值为`10~16`。使用lora时额外指定该参数可使用lora+。
|
||||
|
||||
##### LoRA-GA
|
||||
- lora_ga_batch_size: 默认值为 `2`。在 LoRA-GA 中估计梯度以进行初始化时使用的批处理大小。
|
||||
- lora_ga_iters: 默认值为 `2`。在 LoRA-GA 中估计梯度以进行初始化时的迭代次数。
|
||||
- lora_ga_max_length: 默认值为 `1024`。在 LoRA-GA 中估计梯度以进行初始化时的最大输入长度。
|
||||
- lora_ga_direction: 默认值为 `ArB2r`。在 LoRA-GA 中使用估计梯度进行初始化时的初始方向。允许的值有:`ArBr`、`A2rBr`、`ArB2r` 和 `random`。
|
||||
- lora_ga_scale: 默认值为 `stable`。LoRA-GA 的初始化缩放方式。允许的值有:`gd`、`unit`、`stable` 和 `weightS`。
|
||||
- lora_ga_stable_gamma: 默认值为 `16`。当初始化时选择 `stable` 缩放时的 gamma 值。
|
||||
|
||||
#### FourierFt
|
||||
|
||||
FourierFt使用`target_modules`、`target_regex`、`modules_to_save`三个参数,含义见上面文档中的描述。额外参数包括:
|
||||
|
||||
- fourier_n_frequency: 傅里叶变换的频率数量, `int`类型, 类似于LoRA中的`r`. 默认值`2000`.
|
||||
- fourier_scaling: W矩阵的缩放值, `float`类型, 类似LoRA中的`lora_alpha`. 默认值`300.0`.
|
||||
|
||||
#### BOFT
|
||||
|
||||
BOFT使用`target_modules`、`target_regex`、`modules_to_save`三个参数,含义见上面文档中的描述。额外参数包括:
|
||||
|
||||
- boft_block_size: BOFT块尺寸, 默认值4.
|
||||
- boft_block_num: BOFT块数量, 不能和`boft_block_size`同时使用.
|
||||
- boft_dropout: boft的dropout值, 默认0.0.
|
||||
|
||||
#### Vera
|
||||
|
||||
Vera使用`target_modules`、`target_regex`、`modules_to_save`三个参数,含义见上面文档中的描述。额外参数包括:
|
||||
|
||||
- vera_rank: Vera Attention的尺寸, 默认值256.
|
||||
- vera_projection_prng_key: 是否存储Vera映射矩阵, 默认为True.
|
||||
- vera_dropout: Vera的dropout值, 默认`0.0`.
|
||||
- vera_d_initial: Vera的d矩阵的初始值, 默认`0.1`.
|
||||
|
||||
#### GaLore
|
||||
|
||||
- 🔥use_galore: 默认值False, 是否使用GaLore.
|
||||
- galore_target_modules: 默认值None, 不传的情况下对attention和mlp应用GaLore.
|
||||
- galore_rank: 默认值128, GaLore的rank值.
|
||||
- galore_update_proj_gap: 默认值50, 分解矩阵的更新间隔.
|
||||
- galore_scale: 默认值1.0, 矩阵权重系数.
|
||||
- galore_proj_type: 默认值`std`, GaLore矩阵分解类型.
|
||||
- galore_optim_per_parameter: 默认值False, 是否给每个Galore目标Parameter设定一个单独的optimizer.
|
||||
- galore_with_embedding: 默认值False, 是否对embedding应用GaLore.
|
||||
- galore_quantization: 是否使用q-galore. 默认值`False`.
|
||||
- galore_proj_quant: 是否对SVD分解矩阵做量化, 默认`False`.
|
||||
- galore_proj_bits: SVD量化bit数.
|
||||
- galore_proj_group_size: SVD量化分组数.
|
||||
- galore_cos_threshold: 投影矩阵更新的cos相似度阈值. 默认值0.4.
|
||||
- galore_gamma_proj: 在投影矩阵逐渐相似后会拉长更新间隔, 本参数为每次拉长间隔的系数, 默认值2.
|
||||
- galore_queue_size: 计算投影矩阵相似度的队列长度, 默认值5.
|
||||
|
||||
#### LISA
|
||||
|
||||
注意: LISA仅支持全参数,即`--tuner_type full`。
|
||||
|
||||
- 🔥lisa_activated_layers: 默认值`0`,代表不使用LISA,改为非0代表需要激活的layers个数,建议设置为2或8。
|
||||
- lisa_step_interval: 默认值`20`,多少iter切换可反向传播的layers。
|
||||
|
||||
#### UNSLOTH
|
||||
|
||||
🔥unsloth无新增参数,对已有参数进行调节即可支持,例如:
|
||||
|
||||
```
|
||||
--tuner_backend unsloth
|
||||
--tuner_type full/lora
|
||||
--quant_bits 4
|
||||
```
|
||||
|
||||
#### LLAMAPRO
|
||||
|
||||
- 🔥llamapro_num_new_blocks: 默认值`4`, 插入的新layers总数.
|
||||
- llamapro_num_groups: 默认值`None`, 分为多少组插入new_blocks, 如果为`None`则等于`llamapro_num_new_blocks`, 即每个新的layer单独插入原模型.
|
||||
|
||||
#### AdaLoRA
|
||||
|
||||
以下参数`tuner_type`设置为`adalora`时生效. adalora的`target_modules`等参数继承于lora的对应参数,但`lora_dtype`参数不生效。
|
||||
|
||||
- adalora_target_r: 默认值`8`, adalora的平均rank.
|
||||
- adalora_init_r: 默认值`12`, adalora的初始rank.
|
||||
- adalora_tinit: 默认值`0`, adalora的初始warmup.
|
||||
- adalora_tfinal: 默认值`0`, adalora的final warmup.
|
||||
- adalora_deltaT: 默认值`1`, adalora的step间隔.
|
||||
- adalora_beta1: 默认值`0.85`, adalora的EMA参数.
|
||||
- adalora_beta2: 默认值`0.85`, adalora的EMA参数.
|
||||
- adalora_orth_reg_weight: 默认值`0.5`, adalora的正则化参数.
|
||||
|
||||
#### ReFT
|
||||
|
||||
以下参数`tuner_type`设置为`reft`时生效.
|
||||
|
||||
> 1. ReFT无法合并tuner
|
||||
> 2. ReFT和gradient_checkpointing不兼容
|
||||
> 3. 如果使用DeepSpeed遇到问题请暂时卸载DeepSpeed
|
||||
|
||||
- 🔥reft_layers: ReFT应用于哪些层上, 默认为`None`, 代表所有层, 可以输入层号的list, 例如reft_layers 1 2 3 4`
|
||||
- 🔥reft_rank: ReFT矩阵的rank, 默认为`4`.
|
||||
- reft_intervention_type: ReFT的类型, 支持'NoreftIntervention', 'LoreftIntervention', 'ConsreftIntervention', 'LobireftIntervention', 'DireftIntervention', 'NodireftIntervention', 默认为`LoreftIntervention`.
|
||||
- reft_args: ReFT Intervention中的其他支持参数, 以json-string格式输入.
|
||||
|
||||
### vLLM参数
|
||||
参数含义可以查看[vllm文档](https://docs.vllm.ai/en/latest/serving/engine_args.html)。
|
||||
|
||||
- 🔥vllm_gpu_memory_utilization: GPU内存比例,取值范围为0到1。默认值`0.9`。
|
||||
- 🔥vllm_tensor_parallel_size: tp并行数,默认为`1`。
|
||||
- vllm_pipeline_parallel_size: pp并行数,默认为`1`。
|
||||
- vllm_data_parallel_size: dp并行数,默认为`1`,在`swift deploy/rollout`命令中生效。
|
||||
- 若在`swift infer`中,使用`NPROC_PER_NODE`来设置dp并行数。参考这里的[例子](https://github.com/modelscope/ms-swift/blob/main/examples/infer/vllm/mllm_ddp.sh)。
|
||||
- vllm_enable_expert_parallel: 开启专家并行,默认为False。
|
||||
- vllm_max_num_seqs: 单次迭代中处理的最大序列数,默认为`256`。
|
||||
- 🔥vllm_max_model_len: 模型支持的最大长度。默认为`None`,即从config.json中读取。
|
||||
- vllm_disable_custom_all_reduce: 禁用自定义的 all-reduce 内核,回退到 NCCL。为了稳定性,默认为`True`。
|
||||
- vllm_enforce_eager: vllm使用pytorch eager模式还是建立cuda graph,默认为`False`。设置为True可以节约显存,但会影响效率。
|
||||
- vllm_mm_processor_cache_gb: 多模态处理器缓存大小(GiB),用于缓存已处理的多模态输入(如图像、视频)避免重复处理。默认为`4`。设置为`0`可禁用缓存但会降低性能(不推荐)。仅对多模态模型生效。
|
||||
- vllm_speculative_config: 推测解码配置,传入json字符串。默认为None。
|
||||
- vllm_disable_cascade_attn: 是否强制关闭V1引擎的cascade attention实现以防止潜在数值误差,默认为False,由vLLM内部逻辑决定是否使用。
|
||||
- 🔥vllm_limit_mm_per_prompt: 控制vllm使用多图,默认为`None`。例如传入`--vllm_limit_mm_per_prompt '{"image": 5, "video": 2}'`。
|
||||
- vllm_max_lora_rank: 默认为`16`。vllm对于lora支持的参数。
|
||||
- vllm_quantization: vllm可以在内部量化模型,参数支持的值详见[这里](https://docs.vllm.ai/en/latest/serving/engine_args.html)。
|
||||
- 🔥vllm_enable_prefix_caching: 开启vllm的自动前缀缓存,节约重复查询前缀的处理时间,加快推理效率。默认为`None`,跟随vLLM行为。
|
||||
- vllm_use_async_engine: vLLM backend下是否使用async engine。默认为None,会根据场景自动设置:encode任务(embedding、seq_cls、reranker、generative_reranker)默认为True,部署场景(swift deploy)默认为True,其他情况默认为False。注意:encode任务需使用async engine。
|
||||
- vllm_reasoning_parser: 推理解析器类型,用于思考模型的思维链内容解析。默认为`None`。仅用于 `swift deploy` 命令。可选的种类参考[vLLM文档](https://docs.vllm.ai/en/latest/features/reasoning_outputs.html#streaming-chat-completions)。
|
||||
- vllm_engine_kwargs: vllm的额外参数,格式为json字符串。默认为None。
|
||||
|
||||
### SGLang参数
|
||||
参数含义可以查看[sglang文档](https://docs.sglang.ai/backend/server_arguments.html)。
|
||||
|
||||
- 🔥sglang_tp_size: tp数。默认为1。
|
||||
- sglang_pp_size: pp数。默认为1。
|
||||
- sglang_dp_size: dp数。默认为1。
|
||||
- sglang_ep_size: ep数。默认为1。
|
||||
- sglang_enable_ep_moe: 是否启用ep moe。默认为False。该参数已在最新sglang中移除。
|
||||
- sglang_mem_fraction_static: 用于静态分配模型权重和KV缓存内存池的GPU内存比例。如果你遇到GPU内存不足错误,可以尝试降低该值。默认为None。
|
||||
- sglang_context_length: 模型的最大上下文长度。默认为 None,将使用模型的`config.json`中的值。
|
||||
- sglang_disable_cuda_graph: 禁用CUDA图。默认为False。
|
||||
- sglang_quantization: 量化方法。默认为None。
|
||||
- sglang_kv_cache_dtype: 用于k/v缓存存储的数据类型。'auto'表示将使用模型的数据类型。'fp8_e5m2'和'fp8_e4m3'适用于CUDA 11.8及以上版本。默认为'auto'。
|
||||
- sglang_enable_dp_attention: 为注意力机制启用数据并行,为前馈网络(FFN)启用张量并行。数据并行的规模(dp size)应等于张量并行的规模(tp size)。目前支持DeepSeek-V2/3以及Qwen2/3 MoE模型。默认为False。
|
||||
- sglang_disable_custom_all_reduce: 禁用自定义的 all-reduce 内核,回退到 NCCL。为了稳定性,默认为True。
|
||||
- sglang_speculative_algorithm: 推测算法,可选值:None、"EAGLE"、"EAGLE3"、"NEXTN"、"STANDALONE"、"NGRAM"。默认为None。
|
||||
- sglang_speculative_num_steps: 在推测解码中从草稿模型采样的步数。默认值为None。
|
||||
- sglang_speculative_eagle_topk: 在 EAGLE2 算法中每步从草稿模型采样的 token 数量。默认值为None。
|
||||
- sglang_speculative_num_draft_tokens: 在推测解码中从草稿模型采样的 token 数量。默认值为None。
|
||||
|
||||
### LMDeploy参数
|
||||
参数含义可以查看[lmdeploy文档](https://lmdeploy.readthedocs.io/en/latest/api/pipeline.html#turbomindengineconfig)。
|
||||
|
||||
- 🔥lmdeploy_tp: tensor并行度。默认为`1`。
|
||||
- lmdeploy_session_len: 最大会话长度。默认为`None`。
|
||||
- lmdeploy_cache_max_entry_count: k/v缓存占用的GPU内存百分比。默认为`0.8`。
|
||||
- lmdeploy_quant_policy: 默认为0。当需要将k/v量化为4或8位时,分别将其设置为4或8。
|
||||
- lmdeploy_vision_batch_size: 传入VisionConfig的max_batch_size参数。默认为`1`。
|
||||
|
||||
### 合并参数
|
||||
|
||||
- 🔥merge_lora: 是否合并lora,本参数支持lora、llamapro、longlora,默认为False。例子参数[这里](https://github.com/modelscope/ms-swift/blob/main/examples/export/merge_lora.sh)。
|
||||
- safe_serialization: 是否存储为safetensors,默认为True。
|
||||
- max_shard_size: 单存储文件最大大小,默认'5GB'。
|
||||
|
||||
|
||||
## 集成参数
|
||||
|
||||
### 训练参数
|
||||
训练参数除包含[基本参数](#基本参数)、[Seq2SeqTrainer参数](#Seq2SeqTrainer参数)、[tuner参数](#tuner参数)外,还包含下面的部分:
|
||||
|
||||
- add_version: 在`output_dir`上额外增加目录`'<版本号>-<时间戳>'`防止权重覆盖,默认为True。
|
||||
- check_model: 检查本地模型文件有损坏或修改并给出提示,默认为True。**如果是断网环境,请设置为False**。
|
||||
- 🔥create_checkpoint_symlink: 额外创建checkpoint软链接,方便书写自动化训练脚本。best_model和last_model的软链接路径分别为f'{output_dir}/best'和f'{output_dir}/last'。
|
||||
- 🔥packing: 使用`padding_free`的方式将不同长度的数据样本打包成**近似**统一长度的样本(packing能保证不对完整的序列进行切分),实现训练时各节点与进程的负载均衡(避免长文本拖慢短文本的训练速度),从而提高GPU利用率,保持显存占用稳定。当使用 `--attn_impl flash_attn` 时,可确保packed样本内的不同序列之间相互独立,互不可见。该参数默认为`False`,目前支持 CPT/SFT/DPO/KTO/GKD以及embedding/reranker/seq_cls任务的packing。注意:**packing会导致数据集样本数减少,请自行调节梯度累加数和学习率**。
|
||||
- 注意:Qwen3-Next的packing请使用Megatron-SWIFT。Qwen3.5的transformers生态padding_free/packing支持请使用"ms-swift>=4.3.1"(或使用Megatron-SWIFT),具体参考[Qwen3.5最佳实践](../BestPractices/Qwen3_5-Best-Practice.md)。
|
||||
- packing_length: packing的长度。默认为None,设置为max_length。
|
||||
- packing_num_proc: packing的进程数,默认为1。需要注意的是,不同的`packing_num_proc`,最终形成的packed数据集是不同的。(该参数在流式packing时不生效)。通常不需要修改该值,packing速度远快于tokenize速度。
|
||||
- packing_strategy: packing 算法,可选为'binpack'和'sequential',默认为'binpack'。'binpack'使用 best-fit-decreasing 装箱(会按长度重排样本);'sequential'使用保序的贪心装箱(next-fit:仅维护一个开放 pack,放不下即 flush),按输入顺序逐条装箱,使样本顺序与每个 pack 的边界跟随顺序采样器(建议配合 packing_num_proc=1 以保证全局顺序)。
|
||||
- lazy_tokenize: 是否使用lazy_tokenize。若该参数设置为False,则在训练之前对所有的数据集样本进行tokenize(多模态模型则包括从磁盘中读取图片)。该参数默认为None,在LLM训练中默认为False,而MLLM训练默认为True,节约内存。
|
||||
- 注意:若你要进行图像的数据增强,你需要将lazy_tokenize(或streaming)设置为True,并修改Template类中的encode方法。
|
||||
- use_logits_to_keep: 通过在`forward`中根据labels传入logits_to_keep,减少无效logits的计算与存储,从而减少显存占用并加快训练速度。默认为None,进行自动选择。
|
||||
- acc_strategy: 训练和验证时计算acc的策略。可选为`seq`和`token`级别的acc,默认为`token`。
|
||||
- max_new_tokens: 覆盖生成参数。predict_with_generate=True时的最大生成token数量,默认64。
|
||||
- temperature: 覆盖生成参数。predict_with_generate=True时的temperature,默认0。
|
||||
- optimizer: 使用的optimizers插件(优先级高于`--optim`),默认为None。可选optimizers参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/optimizers/mapping.py)。
|
||||
- loss_type: 自定义的loss_type名称。默认为None,使用模型自带损失函数。可选loss参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/loss/mapping.py)。
|
||||
- mrl_dims: Embedding训练的[Matryoshka表征学习(MRL)](https://arxiv.org/abs/2205.13147)维度配置,默认为None。格式为`Dict[int, float]`或Json字符串,key为截断的embedding维度,value为该维度对应的loss权重,例如`'{"32": 1.0, "64": 1.0, "128": 1.0}'`。开启后,trainer会对`last_hidden_state`分别截断到每个维度并做L2归一化,再调用`loss_type`对应的loss加权累加。仅在`task_type='embedding'`下生效。
|
||||
- 注意:可支持的最大embedding维度由模型`config.json`中的`hidden_size`决定,key大于`hidden_size`的KV对将被自动忽略。
|
||||
- eval_metric: 自定义eval metric名称。默认为None。可选eval_metric参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/metrics/mapping.py)。
|
||||
- 关于默认值:当`task_type`为'causal_lm', 且`predict_with_generate=True`的情况下默认设置为'nlg'。`task_type` 为'embedding',根据loss_type,默认值为'infonce' 或 'paired'。`task_type`为'reranker/generative_reranker',默认值为'reranker'。
|
||||
- callbacks: 自定义trainer callback,默认为`[]`。可选callbacks参考[这里](https://github.com/modelscope/ms-swift/blob/main/swift/callbacks/mapping.py)。例如:通过在`callbacks`中添加`deepspeed_elastic`(可选`graceful_exit`)可以来启用弹性训练。参考[Elastic示例](../BestPractices/Elastic.md)
|
||||
- early_stop_interval: 早停的间隔,会检验best_metric在early_stop_interval个周期内(基于`save_steps`, 建议`eval_steps`和`save_steps`设为同值)没有提升时终止训练。具体代码在[early_stop.py](https://github.com/modelscope/ms-swift/blob/main/swift/callbacks/early_stop.py)中。同时,如果有较为复杂的早停需求,直接覆盖callback.py中的已有实现即可。设置该参数时,自动加入`early_stop`的trainer callback。
|
||||
- eval_use_evalscope: 是否使用evalscope进行训练时评测,需要设置该参数来开启评测,具体使用参考[示例](../Instruction/Evaluation.md#训练中评测)。
|
||||
- eval_dataset: 评测数据集,可设置多个数据集,用空格分割。
|
||||
- eval_dataset_args: 评测数据集参数,json格式,可设置多个数据集的参数。
|
||||
- eval_limit: 评测数据集采样数。
|
||||
- eval_generation_config: 评测时模型推理配置,json格式,默认为`{'max_tokens': 512}`。
|
||||
- use_flash_ckpt: 是否启用[DLRover Flash Checkpoint](https://github.com/intelligent-machine-learning/dlrover)的flash checkpoint。默认为`false`,启用后,权重会先保存至共享内存,之后异步持久化;建议搭配`PYTORCH_CUDA_ALLOC_CONF="expandable_segments:True"` 一起使用,避免训练过程CUDA OOM。
|
||||
|
||||
#### SWANLAB
|
||||
|
||||
- swanlab_token: SwanLab的api-key。你也可以使用`SWANLAB_API_KEY`环境变量指定。
|
||||
- swanlab_project: swanlab的project,可以在页面中预先创建[https://swanlab.cn/space/~](https://swanlab.cn/space/~)或自动创建,默认为"ms-swift"。
|
||||
- swanlab_workspace: 默认为None,会使用api-key对应的username。
|
||||
- swanlab_exp_name: 实验名,可以为空,为空时默认传入--output_dir的值。
|
||||
- swanlab_notification_method: 在训练完成/发生错误时,swanlab的通知方式,具体参考[这里](https://docs.swanlab.cn/plugin/notification-dingtalk.html)。支持'dingtalk'、'lark'、'email'、'discord'、'wxwork'、'slack'。
|
||||
- swanlab_webhook_url: 默认为None。swanlab的`swanlab_notification_method`对应的 webhook url。
|
||||
- swanlab_secret: 默认为None。swanlab的`swanlab_notification_method`对应的 secret。
|
||||
- swanlab_mode: 可选cloud和local,云模式或者本地模式。
|
||||
|
||||
|
||||
### RLHF参数
|
||||
RLHF参数继承于[训练参数](#训练参数)。
|
||||
|
||||
- 🔥rlhf_type: 人类对齐算法类型,支持'dpo'、'orpo'、'simpo'、'kto'、'cpo'、'rm'、'ppo'、'grpo'和'gkd'。默认为'dpo'。
|
||||
- ref_model: 采用dpo、kto、ppo、grpo算法且使用全参数训练时需要传入。默认为None,设置为`--model`。
|
||||
- ref_adapters: 默认为`[]`。若你要使用SFT产生的LoRA权重进行DPO/KTO/GRPO,请在训练时设置`--adapters sft_ckpt --ref_adapters sft_ckpt`。若是此场景的断点续训,则设置`--resume_from_checkpoint rlhf_ckpt --ref_adapters sft_ckpt`。
|
||||
- ref_model_type: 同model_type。默认为None。
|
||||
- ref_model_revision: 同model_revision。默认为None。
|
||||
- 🔥beta: 控制与参考模型偏差程度的参数。beta值越高,表示与参考模型的偏差越小。默认为`None`,使用不同rlhf算法的默认值不同,其中`simpo`算法默认为`2.`,GRPO默认为`0.04`,GKD默认为0.5,其他算法默认为`0.1`。具体参考[文档](./RLHF.md)。
|
||||
- label_smoothing: 是否使用DPO smoothing,默认值为`0`。
|
||||
- max_completion_length: GRPO/PPO/GKD算法中的最大生成长度,默认为512。
|
||||
- 🔥rpo_alpha: 来自[RPO 论文](https://arxiv.org/abs/2404.19733)中的参数,用于控制损失函数中NLL项的权重(即SFT损失),`loss = dpo_loss + rpo_alpha * sft_loss`,论文中推荐设置为`1.`。默认为`None`,即默认不引入sft_loss。
|
||||
- ld_alpha: 来自[LD-DPO 论文](https://arxiv.org/abs/2409.06411),对超出公共前缀部分的logps加权 $\alpha$ 抑制长度偏好。
|
||||
- discopop_tau: 来自 [DiscoPOP 论文](https://arxiv.org/abs/2406.08414)的温度参数 $\tau$ ,用于缩放 log-ratio。默认值0.05。在 loss_type 为 discopop 时生效。
|
||||
- loss_type: 损失类型。默认为None,使用不同的rlhf算法,其默认值不同。
|
||||
- DPO: 可选项参考[文档](https://huggingface.co/docs/trl/main/en/dpo_trainer#loss-functions),支持传入多个值实现混合训练([MPO](https://arxiv.org/abs/2411.10442)), 传入多个值时需要设置参数 loss_weights。默认为`sigmoid`。
|
||||
- GRPO: 参考[GRPO参数](#grpo参数)。
|
||||
- loss_weights: 在 DPO 训练中设置多个 loss_type 时,用于指定各个损失项的权重。
|
||||
- cpo_alpha: CPO/SimPO loss 中 nll loss的系数, 默认为`1.`。
|
||||
- simpo_gamma: SimPO算法中的reward margin项,论文建议设置为0.5-1.5,默认为`1.`。
|
||||
- desirable_weight: KTO算法中用于抵消 desirable 和 undesirable 数量不均衡的影响,对 desirable 损失按该系数进行加权,默认为`1.`。
|
||||
- undesirable_weight: KTO算法中用于抵消 desirable 和 undesirable 数量不均衡的影响,对 undesirable 损失按该系数进行加权,默认为`1.`。
|
||||
- center_rewards_coefficient: 用于RM训练。用于激励奖励模型输出均值为零的奖励的系数,具体查看这篇[论文](https://huggingface.co/papers/2312.09244)。推荐值:0.01。
|
||||
- loss_scale: 覆盖模板参数。rlhf训练时,默认为'last_round'。
|
||||
- temperature: 默认为0.9,该参数将在PPO、GRPO、GKD中使用。
|
||||
- top_k: rollout采样的top-k参数,-1表示不进行top-k过滤。默认为-1。
|
||||
- top_p: rollout采样的top-p参数,1.0表示不进行top-p过滤。默认为1.0。
|
||||
|
||||
#### GKD参数
|
||||
- lmbda: 默认为0.5。该参数在GKD中使用。控制学生数据比例的 lambda 参数(即策略内学生生成输出所占的比例)。若lmbda为0,则不使用学生生成数据。
|
||||
- sft_alpha: 默认为0。控制GKD中加入sft_loss的权重。最后的loss为`gkd_loss + sft_alpha * sft_loss`。
|
||||
- gkd_logits_topk: 使用 Top-K logits 计算 KL 散度,默认为 None(即使用完整词表计算)。设置该参数可有效降低训练显存峰值;当配置 `teacher_model_server` 时,此参数为必填项。详见[蒸馏文档](./Distillation.md#31-gkd散度作为直接损失)。
|
||||
- truncation_strategy: 用于处理输入长度超过 max_length 的样本,支持 delete 和 left 两种策略,分别表示删除该样本和从左侧裁剪。默认值为 left。若使用 delete 策略,被删除的超长样本或编码失败的样本将在原数据集中通过重采样进行替换。
|
||||
- log_completions: 是否记录训练中的模型生成内容,搭配 `--report_to wandb/swanlab` 使用。默认为False。
|
||||
- 提示:若没有设置`--report_to wandb/swanlab`,则会在checkpoint中创建`completions.jsonl`来存储生成内容。
|
||||
- 仅记录 vLLM 采样结果。
|
||||
|
||||
#### Reward/Teacher模型参数
|
||||
reward模型参数将在PPO、GRPO中使用;teacher模型参数在GKD与GRPO中使用。
|
||||
|
||||
- reward_model: 默认为None。
|
||||
- reward_adapters: 默认为`[]`。
|
||||
- reward_model_type: 默认为None。
|
||||
- reward_model_revision: 默认为None。
|
||||
- teacher_model: 默认为None。
|
||||
- teacher_adapters: 默认为`[]`。
|
||||
- teacher_model_type: 默认为None。
|
||||
- teacher_model_revision: 默认为None。
|
||||
- teacher_model_server: 教师模型服务地址,通过 `swift deploy` 部署后用于获取 logprobs。支持单 teacher URL(如 `http://localhost:8000`)或多 teacher JSON(如 `'[{"url":"http://t1:8000","tags":["data/math.jsonl"]},{"url":"http://t2:8001","tags":["data/code.jsonl"]}]'`)。`tags` 与数据集或样本标识的对应关系见[蒸馏文档](./Distillation.md#multi-teacher多教师路由)。
|
||||
- teacher_tag_key: 多 teacher 路由时,样本用于匹配 teacher `tags` 的字段名,默认为 `"dataset"`。多数据集时按 `--dataset` 各项匹配;也可在数据中自定义列(如 `teacher_tag`)并设为 `--teacher_tag_key teacher_tag`。
|
||||
- teacher_deepspeed: 同 deepspeed 参数,控制 teacher model 的 deepspeed 配置,默认使用训练模型的 deepspeed 配置。
|
||||
- offload_teacher_model: 卸载教师模型以节约显存,在采样/计算logps时加载,仅在设置teacher_model时生效默认为False。
|
||||
|
||||
|
||||
#### PPO参数
|
||||
|
||||
以下参数含义可以参考[这里](https://huggingface.co/docs/trl/main/ppo_trainer)。
|
||||
- num_ppo_epochs: 默认为4。
|
||||
- whiten_rewards: 默认为False。
|
||||
- kl_coef: 默认为0.05。
|
||||
- cliprange: 默认为0.2。
|
||||
- vf_coef: 默认为0.1。
|
||||
- cliprange_value: 默认为0.2。
|
||||
- gamma: 默认为1.0。
|
||||
- lam: 默认为0.95。
|
||||
- num_mini_batches: 默认为1。
|
||||
- local_rollout_forward_batch_size: 默认为64。
|
||||
- num_sample_generations: 默认为10。
|
||||
- missing_eos_penalty: 默认为None。
|
||||
|
||||
|
||||
#### GRPO参数
|
||||
- beta: KL正则系数,默认为0.04,设置为0时不加载ref model。
|
||||
- per_device_train_batch_size: 每个设备训练批量大小,在GRPO中,指 completion 的批次大小。
|
||||
- per_device_eval_batch_size: 每个设备评估批量大小,在GRPO中,指 completion 的批次大小。
|
||||
- steps_per_generation: 每轮生成的优化步数,默认等于 gradient_accumulation_steps。与 generation_batch_size 只能同时设置一个。
|
||||
- generation_batch_size: 总的采样 completion 批量大小,需要是 num_processes * per_device_train_batch_size 的倍数,默认等于 per_device_train_batch_size * steps_per_generation * num_processes。
|
||||
- num_generations: 每个prompt采样的数量,论文中的G值,generation_batch_size 必须能被 num_generations 整除。默认为 8。
|
||||
- num_generations_eval: 评估阶段每个prompt采样的数量。允许在评估时使用较少的生成数量以节省计算资源。如果为 None,则使用 num_generations 的值。默认为 None。
|
||||
- ds3_gather_for_generation: 该参数适用于DeepSpeed ZeRO-3。如果启用,策略模型权重将被收集用于生成,从而提高生成速度。然而,禁用此选项允许训练超出单个GPU VRAM的模型,尽管生成速度会变慢。禁用此选项与vLLM生成不兼容。默认为True。
|
||||
- reward_funcs: GRPO算法奖励函数,可选项为`accuracy`、`format`、`cosine`、`repetition`和`soft_overlong`,见swift/rewards/orm.py。你也可以在plugin中自定义自己的奖励函数。默认为`[]`。
|
||||
- reward_weights: 每个奖励函数的权重。必须与奖励函数和奖励模型的总数量匹配。如果为 None,则所有奖励的权重都相等,为`1.0`。
|
||||
- 提示:如果GRPO训练中包含`--reward_model`,则其加在奖励函数的最后位置。
|
||||
- reward_model_plugin: 奖励模型逻辑,默认为orm逻辑, 详细见[自定义奖励模型](./GRPO/DeveloperGuide/reward_model.md#自定义奖励模型)。
|
||||
- dataset_shuffle: 是否对dataset进行随机操作,默认为True。
|
||||
- truncation_strategy: 用于处理输入长度超过 max_length 的样本,支持 delete 和 left 两种策略,分别表示删除该样本和从左侧裁剪。默认值为 left。若使用 delete 策略,被删除的超长样本或编码失败的样本将在原数据集中通过重采样进行替换。
|
||||
- loss_type: loss 归一化的类型,可选项为['grpo', 'bnpo', 'dr_grpo', 'dapo', 'cispo', 'sapo', 'real', 'fipo'], 默认为'grpo', 具体参考[文档](./GRPO/DeveloperGuide/loss_types.md)
|
||||
- fipo_decay_rate: FIPO Future-KL 折扣半衰参数,实际折扣为`2 ** (-1 / fipo_decay_rate)`,默认值为32.0。
|
||||
- fipo_clip_range: FIPO influence weight 裁剪范围,默认值为0.2;设置为None或0时不裁剪。
|
||||
- fipo_clip_high_only: 是否只将FIPO influence weight裁剪到`[1.0, 1.0 + fipo_clip_range]`,默认值为True。
|
||||
- fipo_safety_threshold: 当负advantage token的IS ratio超过该阈值时,将FIPO influence weight限制到`[0.8, 1.0]`,默认值为4.0。
|
||||
- log_completions: 是否记录训练中的模型生成内容,搭配 `--report_to wandb/swanlab` 使用。默认为False。
|
||||
- 提示:若没有设置`--report_to wandb/swanlab`,则会在checkpoint中创建`completions.jsonl`来存储生成内容。
|
||||
- use_vllm: 是否使用 vLLM 作为 GRPO 生成的 infer_backend,默认为False。
|
||||
- vllm_mode: vLLM 集成模式,可选项为 `server` 和 `colocate`。server 模式使用 `swift rollout` 拉起的 vLLM 服务器进行采样,colocate 模式在程序内部署 vLLM。使用server端时,
|
||||
- vllm_mode server 参数
|
||||
- vllm_server_host: vLLM server host地址,默认为None。
|
||||
- vllm_server_port: vLLM server 服务端口,默认为8000。
|
||||
- vllm_server_base_url: vLLM server的Base URL(比如 `http://local_host:8000`), 默认为None。设置后,忽略host和port设置。
|
||||
- vllm_server_group_port: vllm server 内部通信端口,除非端口被占用,一般无需设置,默认为51216。
|
||||
- vllm_server_timeout: 连接vLLM server的超时时间,默认为 240s。
|
||||
- vllm_server_pass_dataset: 透传额外的数据集信息到vLLM server,用于多轮训练。
|
||||
- async_generate: 异步rollout以提高训练速度,注意开启时采样会使用上一轮更新的模型进行采样,不支持多轮场景。默认`false`。
|
||||
- enable_flattened_weight_sync: 是否使用 flattened tensor 进行权重同步。启用后会将多个参数打包为单个连续 tensor 进行传输,可提升同步效率,在 Server Mode 下生效,默认为 True。
|
||||
- SWIFT_UPDATE_WEIGHTS_BUCKET_SIZE: 环境变量,用于控制flattened tensor 权重同步时的传输桶大小(bucket size),适用于 Server Mode 下的全参数训练,单位为 MB,默认值为 512 MB。
|
||||
- vllm_mode colocate 参数(更多参数支持参考[vLLM参数](#vLLM参数)。)
|
||||
- vllm_gpu_memory_utilization: vllm透传参数,默认为0.9。
|
||||
- vllm_max_model_len: vllm透传参数,默认为None。
|
||||
- vllm_enforce_eager: vllm透传参数,默认为False。
|
||||
- vllm_limit_mm_per_prompt: vllm透传参数,默认为None。
|
||||
- vllm_enable_prefix_caching: vllm透传参数,默认为True。
|
||||
- vllm_tensor_parallel_size: tp并行数,默认为`1`。
|
||||
- vllm_enable_lora: 支持vLLM Engine 加载 LoRA adapter,默认为False。用于加速LoRA训练的权重同步,具体参考[文档](./GRPO/GetStarted/GRPO.md#权重同步加速)。
|
||||
- sleep_level: 训练时释放 vLLM 显存,可选项为[0, 1, 2], 默认为0,不释放。
|
||||
- offload_optimizer: 是否在vLLM推理时offload optimizer参数,默认为False。
|
||||
- offload_model: 是否在vLLM推理时 offload 模型,默认为False。
|
||||
- completion_length_limit_scope: 在多轮对话中,`max_completion_length` 的限制范围。
|
||||
`total`限制所有对话轮次的总输出长度不超过`max_completion_length`, `per_round`限制每一轮的输出长度。
|
||||
- num_iterations: 每条数据的更新次数,[GRPO论文](https://arxiv.org/abs/2402.03300)中的 $\mu$ 值,默认为1。
|
||||
- epsilon: clip 系数,默认为0.2。
|
||||
- epsilon_high: upper clip 系数,默认为None,设置后与epsilon共同构成[epsilon, epsilon_high]裁剪范围。
|
||||
- tau_pos: [SAPO](https://arxiv.org/abs/2511.20347)算法中正优势的温度参数,控制软门控函数的锐度。较大值使门控更锐利(接近硬裁剪),较小值使门控更平滑。默认为1.0。
|
||||
- tau_neg: SAPO算法中负优势的温度参数,控制软门控函数的锐度。通常设置`tau_neg > tau_pos`以对负优势施加更强约束。默认为1.05。
|
||||
- dynamic_sample: 筛除group内奖励标准差为0的数据,额外采样新数据,默认为False。
|
||||
- max_resample_times: dynamic_sample设置下限制重采样次数,默认3次。
|
||||
- overlong_filter: 跳过超长截断的样本,不参与loss计算,默认为False。
|
||||
- delta: [INTELLECT-2 tech report](https://huggingface.co/papers/2505.07291)中双侧 GRPO 上界裁剪值。若设置,建议大于 1 + epsilon。默认为None。
|
||||
- importance_sampling_level: 控制重要性采样比计算,可选项为 `token` 和 `sequence`,`token` 模式下保留原始的每个 token 的对数概率比,`sequence` 模式下则会对序列中所有有效 token 的对数概率比进行平均。[GSPO论文](https://arxiv.org/abs/2507.18071)中使用sequence级别计算来稳定训练,默认为`token`。
|
||||
- advantage_estimator: 优势计算函数,默认为 `grpo`,即计算组内相对优势,可选项为 `grpo`、[`rloo`](./GRPO/AdvancedResearch/RLOO.md)、[`reinforce_plus_plus`](./GRPO/AdvancedResearch/REINFORCEPP.md)。
|
||||
- kl_in_reward: 控制 KL 散度正则项的处理位置;`false`表示作为损失函数的独立正则项,`true`表示将 KL 直接并入奖励(从奖励中扣除)。默认情况与advantage_estimator绑定,`grpo`下默认为`false`,`rloo` 和 `reinforce_plus_plus` 下默认为 `true`。
|
||||
- scale_rewards: 指定奖励的缩放策略。可选值包括 `group`(按组内标准差缩放)、`batch`(按整个批次的标准差缩放)、`none`(不进行缩放)、`gdpo`(对每个奖励函数分别进行组内归一化后加权聚合,参考 [GDPO 论文](https://arxiv.org/abs/2601.05242))。默认值与 `advantage_estimator` 绑定:`grpo` 对应 `group`,`rloo` 对应 `none`,`reinforce_plus_plus` 对应 `batch`。
|
||||
- 注意:`gdpo` 模式不支持 `kl_in_reward=True`,若同时设置会自动将 `kl_in_reward` 设为 `False`。
|
||||
- GDPO 适用于多奖励优化场景:当使用多个奖励函数时,GDPO 会对每个奖励函数分别在组内进行标准化(减均值、除标准差),然后使用 `reward_weights` 进行加权求和,最后再进行批次级别的标准化。这种方式可以更好地保留各个奖励的相对差异,避免不同奖励组合坍塌成相同的 advantage 值。
|
||||
- teacher_kl_coef: OPD-RL中teacher_kl的系数,即 `adv_t = base_adv + teacher_kl_coef * teacher_kl`。默认为 1.0。
|
||||
- sync_ref_model: 是否定期同步ref_model,默认为False。
|
||||
- ref_model_mixup_alpha: 控制在更新过程中model和先前ref_model之间的混合。更新公式为 $π_{ref} = α * π_θ + (1 - α) * π_{ref_{prev}}$。默认为0.6。
|
||||
- ref_model_sync_steps: 同步频率,默认为512。
|
||||
- move_model_batches: 在模型向vLLM等快速推理框架移动参数时,将layers分为多少个batch. 默认为None, 代表整个模型不进行拆分,否则拆分为move_model_batches+1(非layer参数)+1(多模态部分参数)个。
|
||||
- multi_turn_scheduler: 多轮GRPO参数, 传入对应的plugin名称, 同时在plugin/multi_turn.py中添加好对应的实现。
|
||||
- max_turns: 多轮GRPO的轮数上限。默认为None,不做限制。
|
||||
- gym_env: 全局指定 gym 环境名称,需先在 plugin 里注册。默认为None,可在数据集每行 `env_config.name` 中覆盖。具体参考[文档](./GRPO/DeveloperGuide/gym_env.md)。
|
||||
- use_gym_env: 是否将 env 给出的 `total_reward` 作为奖励,启用后无需配置 reward 函数。默认为None;未显式传入时,若设置了 `gym_env` 则自动设为True,否则server模式下从rollout继承,其它情况为False。
|
||||
- top_entropy_quantile: 仅对熵值处于前指定分位的 token 参与损失计算,默认为1.0,即不过滤低熵 token,具体参考[文档](./GRPO/AdvancedResearch/entropy_mask.md)
|
||||
- log_entropy: 记录训练中的熵值变化动态,默认为False,具体参考[文档](./GRPO/GetStarted/GRPO.md#logged-metrics)
|
||||
- rollout_importance_sampling_mode: 训推不一致校正模式,可选项为 `token_truncate`、`token_mask`、`sequence_truncate`、`sequence_mask`。默认为None,不启用校正。具体参考[文档](./GRPO/AdvancedResearch/training_inference_mismatch.md)
|
||||
- rollout_importance_sampling_threshold: 重要性采样权重的阈值,用于截断或屏蔽极端权重。默认为2.0。
|
||||
- log_rollout_offpolicy_metrics: 当 `rollout_importance_sampling_mode` 未设置时,是否记录训推不一致诊断指标(KL、PPL、χ²等)。当设置了 `rollout_importance_sampling_mode` 时,指标会自动记录。默认为False。
|
||||
- off_policy_sequence_mask_delta: Off-Policy Sequence Masking 阈值,来自 [DeepSeek-V3.2 论文](https://arxiv.org/abs/2512.02556)。当设置此值时,会计算每个序列的 `mean(old_policy_logps - policy_logps)`,若该值大于阈值且该序列的优势为负,则 mask 掉该序列不参与损失计算。具体参考[文档](./GRPO/AdvancedResearch/training_inference_mismatch.md#off-policy-sequence-masking)
|
||||
|
||||
##### 奖励函数参数
|
||||
内置的奖励函数参考[文档](./GRPO/DeveloperGuide/reward_function.md)
|
||||
cosine 奖励参数
|
||||
- cosine_min_len_value_wrong: cosine 奖励函数参数,生成错误答案时,最小长度对应的奖励值。默认值为-0.5。
|
||||
- cosine_max_len_value_wrong: 生成错误答案时,最大长度对应的奖励值。默认值为0.0。
|
||||
- cosine_min_len_value_correct: 生成正确答案时,最小长度对应的奖励值。默认值为1.0。
|
||||
- cosine_max_len_value_correct: 生成正确答案时,最大长度对应的奖励值。默认值为0.5。
|
||||
- cosine_max_len: 生成文本的最大长度限制。默认等于 max_completion_length。
|
||||
|
||||
repetition 奖励参数
|
||||
- repetition_n_grams: 用于检测重复的 n-gram 大小。默认值为3。
|
||||
- repetition_max_penalty: 最大惩罚值,用于控制惩罚的强度。默认值为-1.0。
|
||||
|
||||
soft overlong 奖励参数
|
||||
- soft_max_length: 论文中的L_max,模型的最大生成长度,默认等于max_completion_length。
|
||||
- soft_cache_length: 论文中的L_cache,控制长度惩罚区间,区间为[soft_max_length-soft_cache_length, soft_max_length]。
|
||||
|
||||
### 推理参数
|
||||
|
||||
推理参数除包含[基本参数](#基本参数)、[合并参数](#合并参数)、[vLLM参数](#vllm参数)、[LMDeploy参数](#LMDeploy参数)外,还包含下面的部分:
|
||||
|
||||
- 🔥infer_backend: 推理加速后端,支持'transformers'、'vllm'、'sglang'、'lmdeploy'四种推理引擎。默认为'transformers'。
|
||||
- 注意:这四种引擎使用的都是swift的template,使用`--template_backend`控制。
|
||||
- 🔥max_batch_size: 指定infer_backend为'transformers'时生效,用于批量推理,默认为1。若设置为-1,则不受限制。
|
||||
- 🔥result_path: 推理结果存储路径(jsonl),默认为None。如果对数据集进行推理/评测,则默认保存在checkpoint目录(含args.json文件)或者'./result'目录,最终存储路径会在命令行中打印(交互式推理或部署默认不存储结果)。
|
||||
- 注意:若已存在`result_path`文件,则会进行追加写入。
|
||||
- write_batch_size: 结果写入`result_path`的batch_size。默认为1000。若设置为-1,则不受限制。
|
||||
- metric: 对推理的结果进行评估,目前支持'acc'和'rouge'。默认为None,即不进行评估。
|
||||
- val_dataset_sample: 推理数据集采样数,默认为None。
|
||||
- reranker_use_activation: 在reranker推理时,是否在score之后使用sigmoid,默认为True。
|
||||
|
||||
|
||||
### 部署参数
|
||||
|
||||
部署参数继承于[推理参数](#推理参数)。
|
||||
|
||||
- host: 服务host,默认为'0.0.0.0'。
|
||||
- port: 端口号,默认为8000。
|
||||
- api_key: 访问需要使用的api_key,默认为None。
|
||||
- owned_by: 默认为`swift`。
|
||||
- 🔥served_model_name: 提供服务的模型名称,默认使用model的后缀。
|
||||
- verbose: 打印详细日志,默认为True。
|
||||
- 注意:在`swift app`或者`swift eval`时,默认为False。
|
||||
- log_interval: tokens/s统计值打印间隔,默认20秒。设置为-1则不打印。
|
||||
- max_logprobs: 最多返回客户端的logprobs数量,默认为20。
|
||||
|
||||
### Rollout参数
|
||||
Rollout参数继承于[部署参数](#部署参数)
|
||||
- multi_turn_scheduler: 多轮GRPO训练规划器,传入对应的plugin名称, 同时在plugin/multi_turn.py中添加好对应的实现。默认为None,具体参考[文档](./GRPO/DeveloperGuide/multi_turn.md)。
|
||||
- max_turns: 多轮GRPO训练下的最大轮数,默认为None,即不做约束。
|
||||
- gym_env: 全局指定 gym 环境名称,需先在 plugin 里注册。默认为None,可在数据集每行 `env_config.name` 中覆盖。具体参考[文档](./GRPO/DeveloperGuide/gym_env.md)。
|
||||
- use_gym_env: 是否启用 gym 环境模式(rollout 输出 `total_reward` 供 trainer 使用)。默认为None,未显式传入时若设置了 `gym_env` 则自动设为True。
|
||||
- vllm_enable_lora: 支持vLLM Engine 加载 LoRA adapter,默认为False。用于加速LoRA训练的权重同步,具体参考[文档](./GRPO/GetStarted/GRPO.md#权重同步加速)。
|
||||
- vllm_max_lora_rank: vLLM Engine LoRA参数,需大于等于训练的lora_rank,建议等于。默认为16。
|
||||
- vllm_enable_expert_parallel: 开启MoE模型的专家并行(EP),将experts分布到不同rank,在vllm_use_async_engine True时生效。默认为False。
|
||||
|
||||
### Web-UI参数
|
||||
- server_name: web-ui的host,默认为'0.0.0.0'。
|
||||
- server_port: web-ui的port,默认为7860。
|
||||
- share: 默认为False。
|
||||
- lang: web-ui的语言,可选为'zh', 'en'。默认为'zh'。
|
||||
|
||||
|
||||
### App参数
|
||||
|
||||
App参数继承于[部署参数](#部署参数), [Web-UI参数](#Web-UI参数)。
|
||||
- base_url: 模型部署的base_url,例如`http://localhost:8000/v1`。默认为`None`,使用本地部署。
|
||||
- studio_title: studio的标题。默认为None,设置为模型名。
|
||||
- is_multimodal: 是否启动多模态版本的app。默认为None,自动根据model判断,若无法判断,设置为False。
|
||||
- lang: 覆盖Web-UI参数,默认为'en'。
|
||||
|
||||
### 评测参数
|
||||
|
||||
评测参数继承于[部署参数](#部署参数)。
|
||||
|
||||
- 🔥eval_backend: 评测后端,默认为'Native',也可以指定为'OpenCompass'或'VLMEvalKit'。
|
||||
- 🔥eval_dataset: 评测数据集,请查看[评测文档](./Evaluation.md)。
|
||||
- eval_limit: 每个评测集的采样数,默认为None。
|
||||
- eval_output_dir: 评测存储结果的文件夹,默认为'eval_output'。
|
||||
- temperature: 覆盖生成参数,默认为0。
|
||||
- eval_num_proc: 评测时客户端最大并发数,默认为16。
|
||||
- eval_url: 评测url,例如`http://localhost:8000/v1`。例子可以查看[这里](https://github.com/modelscope/ms-swift/tree/main/examples/eval/eval_url)。默认为None,采用本地部署评估。
|
||||
- eval_generation_config: 评测时模型推理配置,需传入json字符串格式,例如:`'{"max_new_tokens": 512}'`;默认为None。
|
||||
- extra_eval_args: 额外评测参数,需传入json字符串格式,默认为空。仅对Native评测有效,更多参数说明请查看[这里](https://evalscope.readthedocs.io/zh-cn/latest/get_started/parameters.html)。
|
||||
- local_dataset: 部分评测集,如`CMB`无法直接运行,需要下载额外数据包才可以使用。设置本参数为`true`可以自动下载全量数据包,并在当前目录下创建`data`文件夹并开始评测。数据包仅会下载一次,后续会使用缓存。该参数默认为`false`。
|
||||
- 注意:默认评测会使用`~/.cache/opencompass`下的数据集,在指定本参数后会直接使用当前目录下的data文件夹。
|
||||
|
||||
### 导出参数
|
||||
|
||||
导出参数除包含[基本参数](#基本参数)和[合并参数](#合并参数)外,还包含下面的部分:
|
||||
|
||||
- 🔥output_dir: 导出结果存储路径。默认为None,会自动设置合适后缀的路径。
|
||||
- exist_ok: 如果output_dir存在,不抛出异常,进行覆盖。默认为False。
|
||||
- 🔥quant_method: 可选为'gptq'、'awq'、'bnb'和'fp8',默认为None。例子参考[这里](https://github.com/modelscope/ms-swift/tree/main/examples/export/quantize)。
|
||||
- quant_n_samples: gptq/awq的校验集采样数,默认为256。
|
||||
- quant_batch_size: 量化batch_size,默认为1。
|
||||
- group_size: 量化group大小,默认为128。
|
||||
- to_cached_dataset: 提前对数据集进行tokenize并导出,默认为False。例子参考[这里](https://github.com/modelscope/ms-swift/tree/main/examples/train/cached_dataset)。更多介绍请查看`cached_dataset`。
|
||||
- 提示:你可以通过`--split_dataset_ratio`或者`--val_dataset`指定验证集内容。
|
||||
- template_mode: 用于支持对`swift rlhf`训练的`cached_dataset`功能。该参数只在`--to_cached_dataset true`时生效。可选项包括: 'train'、'rlhf'和'kto'。其中`swift pt/sft`使用'train',`swift rlhf --rlhf_type kto`使用'kto',其他rlhf算法使用'rlhf'。注意:当前'gkd', 'ppo', 'grpo'算法不支持`cached_dataset`功能。默认为'train'。
|
||||
- to_ollama: 产生ollama所需的Modelfile文件。默认为False。
|
||||
- 🔥to_mcore: HF格式权重转成Megatron格式。默认为False。
|
||||
- to_hf: Megatron格式权重转成HF格式。默认为False。
|
||||
- mcore_model: mcore格式模型路径。默认为None。
|
||||
- mcore_adapter: mcore格式模型的adapter路径,默认为None。
|
||||
- thread_count: `--to_mcore true`时的模型切片数。默认为None,根据模型大小自动设置,使得最大分片小于10GB。
|
||||
- 🔥offload_bridge: Megatron导出的用于vLLM更新HF格式权重使用CPU主存存放,以降低 GPU 显存占用。默认为 False。
|
||||
- 🔥test_convert_precision: 测试HF和Megatron格式权重转换的精度误差。默认为False。
|
||||
- test_convert_dtype: 转换精度测试使用的dtype,默认为'float32'。
|
||||
- 🔥push_to_hub: 是否推送hub,默认为False。例子参考[这里](https://github.com/modelscope/ms-swift/blob/main/examples/export/push_to_hub.sh)。
|
||||
- hub_model_id: 推送的model_id,默认为None。
|
||||
- hub_private_repo: 是否是private repo,默认为False。
|
||||
- commit_message: 提交信息,默认为'update files'。
|
||||
|
||||
### 采样参数
|
||||
|
||||
- prm_model: 过程奖励模型的类型,可以是模型id(以'transformers'方式拉起),或者plugin中定义的prm key(自定义推理过程)。
|
||||
- orm_model: 结果奖励模型的类型,通常是通配符或测试用例等,一般定义在plugin中。
|
||||
- sampler_type: 采样类型,目前支持 sample, distill。
|
||||
- sampler_engine: 支持`transformers`, `lmdeploy`, `vllm`, `client`, `no`,默认为`transformers`,采样模型的推理引擎。
|
||||
- output_dir: 输出目录,默认为`sample_output`。
|
||||
- output_file: 输出文件名称,默认为`None`使用时间戳作为文件名。传入时不需要传入目录,仅支持jsonl格式。
|
||||
- override_exist_file: 如`output_file`存在,是否覆盖。
|
||||
- num_sampling_batch_size: 每次采样的batch_size。
|
||||
- num_sampling_batches: 共采样多少batch。
|
||||
- n_best_to_keep: 返回多少最佳sequences。
|
||||
- data_range: 本采样处理数据集的分片。传入格式为`2 3`,代表数据集分为3份处理(这意味着通常有三个`swift sample`在并行处理),本实例正在处理第3个分片。
|
||||
- temperature: 在这里默认为1.0。
|
||||
- prm_threshold: PRM阈值,低于该阈值的结果会被过滤掉,默认值为`0`。
|
||||
- easy_query_threshold: 单个query的所有采样中,ORM评估如果正确,大于该比例的query会被丢弃,防止过于简单的query出现在结果中,默认为`None`,代表不过滤。
|
||||
- engine_kwargs: 传入sampler_engine的额外参数,以json string传入,例如`{"cache_max_entry_count":0.7}`。
|
||||
- num_return_sequences: 采样返回的原始sequence数量。默认为64,本参数对`sample`采样有效。
|
||||
- cache_files: 为避免同时加载prm和generator造成显存OOM,可以分两步进行采样,第一步将prm和orm置为`None`,则所有结果都会输出到文件中,第二次运行采样将sampler_engine置为`no`并传入`--cache_files`为上次采样的输出文件,则会使用上次输出的结果进行prm和orm评估并输出最终结果。
|
||||
- 注意:使用cache_files时,`--dataset`仍然需要传入,这是因为cache_files的id是由原始数据计算的md5,需要把两部分信息结合使用。
|
||||
|
||||
## 特定模型参数
|
||||
除了以上参数外,有些模型还支持额外的具体模型参数。这些参数含义通常可以在对应模型官方repo或者其推理代码中找到相应含义。**ms-swift引入这些参数以确保训练的模型与官方推理代码效果对齐**。
|
||||
- 特定模型参数可以通过`--model_kwargs`或者环境变量进行设置,例如: `--model_kwargs '{"fps_max_frames": 12}'`或者`FPS_MAX_FRAMES=12`。
|
||||
- 注意:若你在训练时指定了特定模型参数,请在推理时也设置对应的参数,这可以提高训练效果。
|
||||
|
||||
### qwen2_vl, qvq, qwen2_5_vl, mimo_vl, keye_vl, keye_vl_1_5
|
||||
参数含义与`qwen_vl_utils<0.0.12`或者`qwen_omni_utils`库中含义一致,可以查看[这里](https://github.com/QwenLM/Qwen2.5-VL/blob/main/qwen-vl-utils/src/qwen_vl_utils/vision_process.py#L24)。ms-swift通过修改这些常数值来控制图片分辨率和视频帧率,避免训练时OOM。
|
||||
|
||||
- IMAGE_FACTOR: 默认为28。
|
||||
- MIN_PIXELS: 默认为`4 * 28 * 28`。图像的最小分辨率。建议设置为28*28的倍数。
|
||||
- 🔥MAX_PIXELS: 默认为`16384 * 28 * 28`。图像的最大分辨率。建议设置为28*28的倍数。
|
||||
- MAX_RATIO: 默认为200。
|
||||
- VIDEO_MIN_PIXELS: 默认为`128 * 28 * 28`。视频中一帧的最小分辨率。建议设置为28*28的倍数。
|
||||
- 🔥VIDEO_MAX_PIXELS: 默认为`768 * 28 * 28`。视频中一帧的最大分辨率。建议设置为28*28的倍数。
|
||||
- VIDEO_TOTAL_PIXELS: 默认为`24576 * 28 * 28`。
|
||||
- FRAME_FACTOR: 默认为2。
|
||||
- FPS: 默认为2.0。
|
||||
- FPS_MIN_FRAMES: 默认为4。一段视频的最小抽帧数。
|
||||
- 🔥FPS_MAX_FRAMES: 默认为768。一段视频的最大抽帧数。
|
||||
- 🔥QWENVL_BBOX_FORMAT: grounding格式使用'legacy'还是'new'。'legacy'格式为:`<|object_ref_start|>一只狗<|object_ref_end|><|box_start|>(432,991),(1111,2077)<|box_end|>`,'new'格式参考:[Qwen3-VL cookbook](https://github.com/QwenLM/Qwen3-VL/blob/main/cookbooks/2d_grounding.ipynb),并参考[grounding数据集格式文档](../Customization/Custom-dataset.md#grounding)。默认为'legacy'。
|
||||
- 注意:该环境变量适配Qwen2/2.5/3-VL和Qwen2.5/3-Omni系列模型。
|
||||
|
||||
### qwen2_audio, qwen3_asr
|
||||
- SAMPLING_RATE: 默认为16000。
|
||||
|
||||
### qwen3_vl, qwen3_5
|
||||
参数含义与`qwen_vl_utils>=0.0.14`库中的含义一致,可以查看[这里](https://github.com/QwenLM/Qwen2.5-VL/blob/main/qwen-vl-utils/src/qwen_vl_utils/vision_process.py#L24)。通过传入以下环境变量,可以修改该库的全局变量默认值。(也兼容使用`qwen2_5_vl`的环境变量,例如:`MAX_PIXELS`、`VIDEO_MAX_PIXELS`,会做自动转换。)
|
||||
|
||||
- SPATIAL_MERGE_SIZE: 默认为2。
|
||||
- IMAGE_MIN_TOKEN_NUM: 默认为`4`,代表一张图片最小图像tokens的个数。
|
||||
- 🔥IMAGE_MAX_TOKEN_NUM: 默认为`16384`,代表一张图片最大图像tokens的个数。(用于避免OOM)。
|
||||
- 提示:等价最大图像像素为`IMAGE_MAX_TOKEN_NUM * 32 *32`。
|
||||
- VIDEO_MIN_TOKEN_NUM: 默认为`128`,代表视频中一帧的最小视频tokens的个数。
|
||||
- 🔥VIDEO_MAX_TOKEN_NUM: 默认为`768`,代表视频中一帧的最大视频tokens的个数。(用于避免OOM)
|
||||
- MAX_RATIO: 默认为200。
|
||||
- FRAME_FACTOR: 默认为2。
|
||||
- FPS: 默认为2.0。
|
||||
- FPS_MIN_FRAMES: 默认为4。代表一段视频的最小抽帧数。
|
||||
- 🔥FPS_MAX_FRAMES: 默认为768,代表一段视频的最大抽帧数。(用于避免OOM)。
|
||||
|
||||
|
||||
### qwen2_5_omni, qwen3_omni
|
||||
qwen2_5_omni除了包含qwen2_5_vl和qwen2_audio的模型特定参数外,还包含以下参数:(注意:qwen3_omni包含的是**qwen3_vl**, qwen2_audio的模型特定参数)
|
||||
- USE_AUDIO_IN_VIDEO: 默认为False。是否使用video中的音频信息。
|
||||
- 🔥ENABLE_AUDIO_OUTPUT: 默认为None,即使用`config.json`中的值。若使用zero3进行训练,请设置为False。
|
||||
- 提示:ms-swift只对thinker部分进行微调,建议设置为False以降低显存占用(只创建thinker部分的模型结构)。
|
||||
|
||||
|
||||
### qwen3_vl_emb, qwen3_vl_reranker
|
||||
参数含义与`qwen3_vl`相同,见上面的描述。以下为对默认值的覆盖:
|
||||
|
||||
- IMAGE_MAX_TOKEN_NUM: qwen3_vl_emb默认为1800, qwen3_vl_reranker默认为1280。具体参考这里:[qwen3_vl_embedding](https://modelscope.cn/models/Qwen/Qwen3-VL-Embedding-2B/file/view/master/scripts%2Fqwen3_vl_embedding.py?status=1#L26), [qwen3_vl_reranker](https://modelscope.cn/models/Qwen/Qwen3-VL-Reranker-2B/file/view/master/scripts%2Fqwen3_vl_reranker.py?status=1#L16)。
|
||||
- FPS: 默认为1。
|
||||
- FPS_MAX_FRAMES: 默认为64。
|
||||
|
||||
|
||||
### internvl_chat
|
||||
参数含义可以查看[这里](https://modelscope.cn/models/OpenGVLab/InternVL2_5-2B)。
|
||||
- MAX_NUM: 默认为12。
|
||||
- INPUT_SIZE: 默认为448。
|
||||
- VIDEO_MAX_NUM: 默认为1。视频的MAX_NUM。
|
||||
- VIDEO_SEGMENTS: 默认为8。
|
||||
|
||||
|
||||
### minicpmv2_6, minicpmv4, minicpmo
|
||||
- MAX_SLICE_NUMS: 默认为9,参考[这里](https://modelscope.cn/models/OpenBMB/MiniCPM-V-2_6/file/view/master?fileName=config.json&status=1)。
|
||||
- VIDEO_MAX_SLICE_NUMS: 默认为1,视频的MAX_SLICE_NUMS,参考[这里](https://modelscope.cn/models/OpenBMB/MiniCPM-V-2_6)。
|
||||
- MAX_NUM_FRAMES: 默认为64,参考[这里](https://modelscope.cn/models/OpenBMB/MiniCPM-V-2_6)。
|
||||
|
||||
### minicpmo
|
||||
- INIT_TTS: 默认为False。是否创建和加载TTS模型。
|
||||
- INIT_AUDIO: 默认为True。是否创建和加载Audio模型。
|
||||
- USE_AUDIO_IN_VIDEO: 默认为False。是否使用video中的音频信息。
|
||||
|
||||
|
||||
### minicpmv4_6
|
||||
- DOWNSAMPLE_MODE: 默认为`'16x'`。视觉token下采样模式。`'16x'`合并token以提升效率;`'4x'`保留4倍更多的token以获取更精细的细节。
|
||||
- MAX_SLICE_NUMS: 默认为9。分割高分辨率图像时的最大切片数量。数值越高,大图像保留的细节越多。建议图像设为36。
|
||||
- VIDEO_MAX_SLICE_NUMS: 默认为1。视频的`MAX_SLICE_NUMS`。
|
||||
- MAX_NUM_FRAMES: 默认为128。从视频中采样的主帧最大数量。
|
||||
- STACK_FRAMES: 默认为1。每秒的总采样点数。1表示仅使用主帧(无堆叠)。N(N>1)表示每秒包含1个主帧 + N−1个子帧;子帧会被合成一张网格图像,并与主帧交错排列。建议短视频设为1,长视频设为3或5。
|
||||
|
||||
|
||||
### ovis1_6, ovis2
|
||||
- MAX_PARTITION: 默认为9,参考[这里](https://github.com/AIDC-AI/Ovis/blob/d248e34d755a95d24315c40e2489750a869c5dbc/ovis/model/modeling_ovis.py#L312)。
|
||||
|
||||
### ovis2_5
|
||||
以下参数含义可以在[这里](https://modelscope.cn/models/AIDC-AI/Ovis2.5-2B)的示例代码中找到。
|
||||
- MIX_PIXELS: int类型,默认为`448 * 448`。
|
||||
- MAX_PIXELS: int类型,默认为`1344 * 1792`。若出现OOM,可以调小该值。
|
||||
- VIDEO_MAX_PIXELS: int类型,默认为`896 * 896`。
|
||||
- NUM_FRAMES: 默认为8。用于视频抽帧。
|
||||
|
||||
### mplug_owl3, mplug_owl3_241101
|
||||
- MAX_NUM_FRAMES: 默认为16,参考[这里](https://modelscope.cn/models/iic/mPLUG-Owl3-7B-240728)。
|
||||
|
||||
### xcomposer2_4khd
|
||||
- HD_NUM: 默认为55,参考[这里](https://modelscope.cn/models/Shanghai_AI_Laboratory/internlm-xcomposer2-4khd-7b)。
|
||||
|
||||
### xcomposer2_5
|
||||
- HD_NUM: 图片数量为1时,默认值为24。大于1,默认为6。参考[这里](https://modelscope.cn/models/AI-ModelScope/internlm-xcomposer2d5-7b/file/view/master?fileName=modeling_internlm_xcomposer2.py&status=1#L254)。
|
||||
|
||||
### video_cogvlm2
|
||||
- NUM_FRAMES: 默认为24,参考[这里](https://github.com/zai-org/CogVLM2/blob/main/video_demo/inference.py#L22)。
|
||||
|
||||
### phi3_vision
|
||||
- NUM_CROPS: 默认为4,参考[这里](https://modelscope.cn/models/LLM-Research/Phi-3.5-vision-instruct)。
|
||||
|
||||
### llama3_1_omni
|
||||
- N_MELS: 默认为128,参考[这里](https://github.com/ictnlp/LLaMA-Omni/blob/544d0ff3de8817fdcbc5192941a11cf4a72cbf2b/omni_speech/infer/infer.py#L57)。
|
||||
|
||||
### video_llava
|
||||
- NUM_FRAMES: 默认为16。
|
||||
|
||||
|
||||
## 其他环境变量
|
||||
- USE_HF: 使用ModelScope/HuggingFace,默认为'0',使用ModelScope。
|
||||
- CUDA_VISIBLE_DEVICES: 控制使用哪些GPU卡。默认使用所有卡。
|
||||
- ASCEND_RT_VISIBLE_DEVICES: 控制使用哪些NPU卡(只对ASCEND卡生效)。默认使用所有卡。
|
||||
- MODELSCOPE_CACHE: 控制缓存路径。(多机训练时建议设置该值,以确保不同节点使用相同的数据集缓存)。
|
||||
- PYTORCH_CUDA_ALLOC_CONF: 推荐设置为`'expandable_segments:True'`,这将减少GPU内存碎片,具体请参考[torch文档](https://docs.pytorch.org/docs/stable/notes/cuda.html#cuda-memory-management)。
|
||||
- NPROC_PER_NODE: torchrun中`--nproc_per_node`的参数透传。默认为1。若设置了`NPROC_PER_NODE`或者`NNODES`环境变量,则使用torchrun启动训练或推理。
|
||||
- MASTER_PORT: torchrun中`--master_port`的参数透传。默认为29500。
|
||||
- MASTER_ADDR: torchrun中`--master_addr`的参数透传。
|
||||
- NNODES: torchrun中`--nnodes`的参数透传。
|
||||
- NODE_RANK: torchrun中`--node_rank`的参数透传。
|
||||
- LOG_LEVEL: 日志的level,默认为'INFO',你可以设置为'WARNING', 'ERROR'等。
|
||||
- SWIFT_DEBUG: 在`engine.infer(...)`时,若设置为'1',TransformersEngine将会打印input_ids和generate_ids的内容方便进行调试与对齐。
|
||||
- VLLM_USE_V1: 用于切换vLLM使用V0/V1版本。
|
||||
- SWIFT_TIMEOUT: 若多模态数据集中存在图像URL,该参数用于控制获取图片的timeout,默认为20s。
|
||||
- ROOT_IMAGE_DIR: 图像(多模态)资源的根目录。通过设置该参数,可以在数据集中使用相对于 `ROOT_IMAGE_DIR` 的相对路径。默认情况下,是相对于运行目录的相对路径。
|
||||
- SWIFT_SINGLE_DEVICE_MODE: 单设备模式,可选值为"0"(默认值)/"1",在此模式下,每个进程只能看到一个设备。
|
||||
- SWIFT_AUDIO_LOAD_BACKEND: 音频波形加载后端。`librosa`(默认)或 `soundfile_pyav`(soundfile 优先、失败时 pyav fallback)。GRPO/GKD训练 在 `--use_vllm true`时默认为 `soundfile_pyav`,保证训练侧 encode 与 vLLM rollout 解析同一音频 URL 时波形一致。
|
||||
@@ -0,0 +1,398 @@
|
||||
# 知识蒸馏(Knowledge Distillation)
|
||||
|
||||
知识蒸馏是一种将教师模型(teacher model)的能力迁移到学生模型(student model)的训练方法。其核心思想是:让学生在每个 token 位置上向教师的输出分布靠拢,从而获得比单纯模仿标注答案更丰富的监督信号——教师不仅告诉学生「哪个 token 是对的」,还告诉学生「其他 token 有多好 / 多差」。
|
||||
|
||||
本文档自顶向下地介绍:蒸馏为什么有效(第一节)、蒸馏方法的统一设计框架(第二节),最后落到 swift 中三种具体的蒸馏训练方法 GKD / OPD-RL / OPSD(第三节)。
|
||||
|
||||
---
|
||||
|
||||
## 一、为什么需要蒸馏:从稀疏信号到稠密信号
|
||||
|
||||
一个语言模型的能力,通常由一连串训练阶段堆叠而成:
|
||||
|
||||
- **预训练(Pre-training)**:习得语言、世界知识、基础推理等通用能力。
|
||||
- **中训练(Mid-training)**:注入领域知识,如代码、医学、公司内部文档等。
|
||||
- **后训练(Post-training)**:激发目标行为,如指令遵循、数学推理、对话风格等。
|
||||
|
||||
蒸馏主要发生在**后训练**阶段。要理解它的价值,需要从两个彼此独立的维度来看待后训练方法:
|
||||
|
||||
1. **采样方式(数据从哪来)**:训练序列是由学生自己生成(on-policy),还是来自外部固定数据(off-policy)。
|
||||
2. **反馈密度(每条序列能学到多少)**:是整条序列只有一个奖励(per-sequence,稀疏),还是每个 token 都有信号(per-token,稠密)。
|
||||
|
||||
|
||||
**SFT / 离线蒸馏**(off-policy + 稠密):在固定数据上对齐标注或教师分布。信号稠密,但训练时见到的都是教师/标注的状态,和学生推理时自己会进入的状态不一致。学生一旦在推理早期犯了教师不会犯的错,就会进入训练中从未见过的状态,误差不断累积,这被称为 **exposure bias(曝光偏差)**。
|
||||
|
||||
**RL**(on-policy + 稀疏):学生自己采样,按最终结果给奖励。分布与学生推理一致,但奖励通常是**序列级**标量,一般不指明具体哪个 token 出错。
|
||||
|
||||
**On-policy 蒸馏**(on-policy + 稠密):学生自己采样轨迹,再由教师对轨迹的**每一个 token** 打分。训练分布与学生推理分布一致,且反馈为 per-token 级别。
|
||||
|
||||
### SFT 是蒸馏的一个特例
|
||||
|
||||
理解蒸馏的一个自然切入点是 SFT 的损失函数。SFT 的 cross-entropy loss,等价于以标注 token 的 one-hot 分布 $\delta_{y^*}$ 为「教师」的 KL 散度:
|
||||
|
||||
$$-\log P_S(y^*_t) = \text{KL}(\delta_{y^*} \,\|\, P_S)$$
|
||||
|
||||
知识蒸馏只是把这个确定性的 one-hot「教师」换成了真实教师模型的软分布 $P_T$,在每个 token 上优化 $\text{KL}(P_T \,\|\, P_S)$,从而提供比 one-hot 丰富的监督信号。
|
||||
|
||||
| 方法 | 采样方式 | 反馈密度 | 教师分布 |
|
||||
|------|----------|----------|----------|
|
||||
| SFT | off-policy(固定数据) | 稠密(per-token) | one-hot $\delta_{y^*}$ |
|
||||
| 离线(off-policy)蒸馏 | off-policy(固定数据或教师生成) | 稠密(per-token) | 教师软分布 |
|
||||
| RL | on-policy(学生采样) | 稀疏(per-sequence) | 无 |
|
||||
| **On-policy 蒸馏** | **on-policy(学生采样)** | **稠密(per-token)** | **教师软分布** |
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 二、蒸馏的两个核心选择
|
||||
|
||||
不同蒸馏方法的差异,几乎都可以归结为两个问题。理解了这两个维度,后面的方法都只是它们的不同组合。
|
||||
|
||||
### 2.1 教师信号怎么算
|
||||
|
||||
在每个 token 位置上,量化教师分布 $P_T$ 与学生分布 $P_S$ 的差异(我们称之为 **Teacher KL**),有两个子选择。
|
||||
|
||||
**(a) 散度方向**
|
||||
|
||||
| 散度 | 定义 | 优化时的行为(信息论含义) |
|
||||
|------|------|------|
|
||||
| Forward KL | $\text{KL}(P_T \,\|\, P_S)$ | Mode-covering:学生需对教师概率较高的区域都赋予足够概率 |
|
||||
| Reverse KL | $\text{KL}(P_S \,\|\, P_T)$ | Mode-seeking:学生主要拟合教师的众数(高概率)区域 |
|
||||
| 广义 JSD($\beta$) | $\beta\,\text{KL}(P_T\|M) + (1-\beta)\,\text{KL}(P_S\|M)$,其中 $M=\beta P_T+(1-\beta)P_S$ | 在两者之间插值 |
|
||||
|
||||
> 其中 $\beta=0$ 退化为 Forward KL,$\beta=1$ 退化为 Reverse KL。SFT 等价于 Forward KL(教师为 one-hot)。
|
||||
|
||||
在 swift 中:
|
||||
- GKD 默认 $\beta=0.5$(JSD),可通过 `--beta` 在 Forward / JSD / Reverse 之间选择;
|
||||
- OPD-RL 的实现固定使用 Reverse KL 的 k1 估计量 $\log\pi_{\text{teacher}}(y_t)-\log\pi_{\text{student}}(y_t)$ 作为 per-token advantage。
|
||||
|
||||
**(b) 计算粒度**
|
||||
|
||||
| 计算粒度 | 需要的教师信息 | 说明 |
|
||||
|----------|---------------|------|
|
||||
| 全词表 | 教师完整的 next-token 分布 | 可计算散度的精确值;显存开销大 |
|
||||
| Top-K | 教师概率最高的 K 个 token | 在 top-K 子集上重新归一化后的近似;适合外部 API(受 `max_logprobs` 限制) |
|
||||
| 采样 token | 教师在学生实际采样 token 上的单个 logp | Reverse KL 的单样本蒙特卡洛估计;通信开销最低 |
|
||||
|
||||
> **精度 vs 开销**:全词表需要物化完整 logits;采样 token 只需教师在已采样 token 上的 logp(可走远程 API)。[DeepSeek-V4](https://arxiv.org/abs/2606.19348)技术报告指出,仅用采样 token 的 log-ratio 作 advantage 时梯度估计方差较大,因此其全词表 OPD 采用完整 logit 蒸馏
|
||||
|
||||
### 2.2 信号怎么传给学生
|
||||
|
||||
| | **路径 A:GKD(直接损失)** | **路径 B:OPD-RL(RL Advantage)** |
|
||||
|---|---|---|
|
||||
| 训练范式 | `--rlhf_type gkd` | `--rlhf_type grpo` + 教师 |
|
||||
| 信号传递 | 把信号作为 loss | 把信号当 advantage,走 policy gradient |
|
||||
| 梯度流经 | 学生**全词表** logits(或 top-k) | 仅学生**采样 token** 的 $\nabla\log\pi(y_t)$ |
|
||||
| 教师信息需求 | 全词表分布(或 top-k logits) | 采样 token 上的单个 logp |
|
||||
| 散度选择 | Forward / Reverse / JSD(`--beta`) | Reverse KL(k1 log-ratio) |
|
||||
| 与任务奖励组合 | 通过 `sft_alpha` 混合 SFT loss | 可与 GRPO reward 叠加为 advantage |
|
||||
|
||||
两者**共享同一套教师基础设施**(见下文),区别只在如何使用 teacher KL 信号。
|
||||
|
||||
> **蒸馏的常见用法**
|
||||
> 1. **能力融合**:多个专家模型蒸馏到统一模型。
|
||||
> 2. **强到弱**:大模型向小模型传递能力。
|
||||
> 3. **防遗忘**:用旧 checkpoint 作教师,在多阶段训练后恢复先前能力。
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 三、swift 中的蒸馏方法
|
||||
|
||||
swift 提供三种蒸馏训练方法,它们共享同一套教师基础设施:
|
||||
|
||||
| 方法 | 信号传递路径 | 启用方式 | 一句话 |
|
||||
|------|--------------|----------|--------|
|
||||
| **GKD** | 直接损失(路径 A) | `--rlhf_type gkd` | 教师散度作为 loss 反向传播;支持全词表 / top-k 散度 |
|
||||
| **OPD-RL** | RL advantage(路径 B) | `--rlhf_type grpo` + 教师 | 教师 log-ratio 注入 GRPO advantage,可与任务奖励叠加 |
|
||||
| **OPSD** | A 或 B 均可 | 在上面基础上提供 `teacher_prompt` | 单模型自蒸馏:教师输入含特权信息(如参考解答) |
|
||||
|
||||
**教师的三种来源**(GKD 与 OPD-RL 通用):
|
||||
|
||||
- `--teacher_model`:在训练进程中加载一个独立的冻结教师模型。
|
||||
- `--teacher_model_server`:连接一个外部教师服务(`swift deploy`启动的vllm服务),不在训练卡上加载教师。GKD 使用 API 时需同时设置 `--gkd_logits_topk`。支持单 URL 与多 teacher JSON 配置。
|
||||
- **自蒸馏**:教师与学生同源。LoRA 训练且 `--teacher_model` 与 `--model` 相同时,自动用 `disable_adapter()` 以基座为固定教师,无需额外加载;不传 `--teacher_model` 且设置 `teacher_prompt`, 则以「学生当前权重」为动态教师。
|
||||
|
||||
| 参数 | 默认值 | 说明 |
|
||||
|------|--------|------|
|
||||
| `--teacher_model` | None | 教师模型路径;GKD 下不传则为动态自蒸馏 |
|
||||
| `--teacher_model_server` | None | 教师 API 地址(与 `teacher_model` 互斥);见下方格式说明 |
|
||||
| `--teacher_tag_key` | `"dataset"` | 多 teacher 路由时,样本用于匹配 teacher `tags` 的字段名 |
|
||||
| `--teacher_deepspeed` | None | 教师模型的 DeepSpeed 配置(如 `zero3`) |
|
||||
| `--offload_teacher_model` | False | 非前向阶段将教师卸载到 CPU(仅 `teacher_model` 生效) |
|
||||
|
||||
完整参数说明见[命令行参数](./Command-line-parameters.md#rewardteacher模型参数)。
|
||||
|
||||
#### 外部教师 API
|
||||
|
||||
通过 `swift deploy --model xxx --infer_backend vllm` 部署教师服务后,训练进程按 prompt 向 API 请求 logprobs,无需在训练卡上加载教师权重。
|
||||
|
||||
- **GKD**:需设置 `--gkd_logits_topk`(API 仅返回 top-k logprobs),用于计算 JSD 散度损失。
|
||||
- **OPD-RL**:取采样 token 的 logp(`prompt_logprobs=0`),注入 advantage;系数由全局 `--teacher_kl_coef` 控制(见 [3.2](#32-opd-rlkl-作为-rl-advantage))。
|
||||
|
||||
#### Multi-Teacher(多教师路由)
|
||||
|
||||
Multi-Teacher 允许同时连接多个外部教师 API,按 tag 将每条样本路由到一个教师,实现领域专家蒸馏。
|
||||
|
||||
**`teacher_model_server` 格式**
|
||||
|
||||
```bash
|
||||
# 单 teacher
|
||||
--teacher_model_server http://localhost:8000
|
||||
|
||||
# 多 teacher(`tags` 与 `--dataset` 或数据列取值对应,见下方「模式一」)
|
||||
--teacher_model_server '[{"url":"http://t1:8000","tags":["data/math.jsonl"]},{"url":"http://t2:8001","tags":["data/code.jsonl"]}]'
|
||||
```
|
||||
|
||||
每个 teacher 配置项:
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| `url` | 教师 API 地址 |
|
||||
| `tags` | 该教师负责的数据来源;单 teacher 可省略;多 teacher 时各条目不重叠,且与下方路由方式中的标识一致 |
|
||||
|
||||
**路由方式**
|
||||
|
||||
**模式一:按数据集路由(默认)**
|
||||
|
||||
传入多个 `--dataset` 时,样本按来源数据集匹配 teacher。默认 `--teacher_tag_key` 为 `"dataset"`,`tags` 与 `--dataset` 中对应项保持一致:
|
||||
|
||||
```bash
|
||||
# Hub ID
|
||||
--dataset AI-ModelScope/alpaca-gpt4-data-en AI-ModelScope/alpaca-cleaned \
|
||||
--teacher_model_server '[{"url":"http://t1:8000","tags":["AI-ModelScope/alpaca-gpt4-data-en"]},{"url":"http://t2:8001","tags":["AI-ModelScope/alpaca-cleaned"]}]'
|
||||
|
||||
# 本地路径
|
||||
--dataset data/math.jsonl data/code.jsonl \
|
||||
--teacher_model_server '[{"url":"http://t1:8000","tags":["data/math.jsonl"]},{"url":"http://t2:8001","tags":["data/code.jsonl"]}]'
|
||||
```
|
||||
|
||||
**模式二:按样本路由**
|
||||
|
||||
在数据文件中为每条样本增加列(如 `teacher_tag`),设置 `--teacher_tag_key teacher_tag`,`tags` 与该列取值对应。适用于只传一个 `--dataset` 但仍需多个 teacher 的场景。
|
||||
|
||||
**示例:GKD + 多 teacher**
|
||||
|
||||
```bash
|
||||
# 部署两个教师服务(GKD 需 max_logprobs >= gkd_logits_topk)
|
||||
CUDA_VISIBLE_DEVICES=1 swift deploy --model Qwen/Qwen3.5-4B --port 8000 --max_logprobs 64
|
||||
CUDA_VISIBLE_DEVICES=2 swift deploy --model Qwen/Qwen3.5-1.7B --port 8001 --max_logprobs 64
|
||||
|
||||
CUDA_VISIBLE_DEVICES=0 swift rlhf \
|
||||
--rlhf_type gkd \
|
||||
--model Qwen/Qwen3.5-0.6B \
|
||||
--teacher_model_server '[{"url":"http://localhost:8000","tags":["data/math.jsonl"]},{"url":"http://localhost:8001","tags":["data/code.jsonl"]}]' \
|
||||
--gkd_logits_topk 64 \
|
||||
--dataset data/math.jsonl data/code.jsonl \
|
||||
...
|
||||
```
|
||||
|
||||
**示例:OPD-RL + 多 teacher**
|
||||
|
||||
```bash
|
||||
CUDA_VISIBLE_DEVICES=1 swift deploy --model Qwen/Qwen3.5-4B --port 8000 --max_logprobs 1
|
||||
CUDA_VISIBLE_DEVICES=2 swift deploy --model Qwen/Qwen3.5-1.7B --port 8001 --max_logprobs 1
|
||||
|
||||
CUDA_VISIBLE_DEVICES=0 swift rlhf \
|
||||
--rlhf_type grpo \
|
||||
--model Qwen/Qwen3.5-0.6B \
|
||||
--teacher_model_server '[{"url":"http://localhost:8000","tags":["data/math.jsonl"]},{"url":"http://localhost:8001","tags":["data/code.jsonl"]}]' \
|
||||
--teacher_kl_coef 1.0 \
|
||||
--dataset data/math.jsonl data/code.jsonl \
|
||||
--use_vllm true --vllm_mode colocate \
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.1 GKD:散度作为直接损失
|
||||
|
||||
GKD([Generalized Knowledge Distillation](https://arxiv.org/pdf/2306.13649))直接把教师-学生间的散度作为损失函数反向传播。
|
||||
|
||||
**损失函数**
|
||||
|
||||
$$
|
||||
\mathcal{L}_{\text{GKD}}(x, y) = \sum_{t=1}^{|y|} D_{\text{JSD}(\beta)}\big(P_{\text{teacher}}(\cdot|x,y_{<t}),\, P_{\text{student}}(\cdot|x,y_{<t})\big)
|
||||
$$
|
||||
|
||||
其中散度 $D$ 由 `--beta` 选择(见 2.1):$\beta=0$ 为 Forward KL,$\beta=1$ 为 Reverse KL,$0<\beta<1$ 为广义 JSD(默认 $0.5$)。
|
||||
|
||||
**On-Policy vs Off-Policy:`lmbda`**
|
||||
|
||||
GKD 通过 `lmbda` 控制每个 batch 用学生在线采样的概率:
|
||||
|
||||
```python
|
||||
if random() <= lmbda:
|
||||
y = student.generate(x) # on-policy:学生自己采样
|
||||
else:
|
||||
y = y_ground_truth # off-policy:使用数据集标注
|
||||
loss = D(P_teacher(·|x, y), P_student(·|x, y))
|
||||
```
|
||||
|
||||
- `lmbda=0`:纯离线(传统 SFT 蒸馏)。
|
||||
- `lmbda=1`:纯在线(学生从自身错误中学习,即 on-policy 蒸馏)。
|
||||
- `0<lmbda<1`:混合。
|
||||
|
||||
> 若希望走teacher生成数据路径,需先用教师离线生成响应写入数据集,再设 `lmbda=0` 训练
|
||||
|
||||
**GKD参数**
|
||||
|
||||
| 参数 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `--beta` | float | 0.5 | 散度插值:0=Forward KL,0.5=JSD,1=Reverse KL |
|
||||
| `--lmbda` | float | 0.5 | 在线采样概率:0=离线,1=纯在线 |
|
||||
| `--sft_alpha` | float | 0 | 混合 SFT loss 比例,最终 `loss = gkd_loss + sft_alpha * sft_loss`(仅对**非学生生成**的数据生效) |
|
||||
| `--gkd_logits_topk` | int | None | 仅用教师 top-K logits 计算 KL;使用 `teacher_model_server` 时为必填 |
|
||||
|
||||
**Top-K 蒸馏(省显存)**
|
||||
|
||||
默认用完整词表计算 KL,词表很大时容易 OOM,可使用`--gkd_logits_topk`参数。
|
||||
|
||||
**外部教师 API**
|
||||
|
||||
设置 `--teacher_model_server` 时需同时设置 `--gkd_logits_topk`(API 仅返回 top-k logprobs)。示例如下:
|
||||
|
||||
```bash
|
||||
# 步骤 1:部署教师模型(max_logprobs 需 >= gkd_logits_topk)
|
||||
CUDA_VISIBLE_DEVICES=0 swift deploy \
|
||||
--model Qwen/Qwen3.5-9B \
|
||||
--infer_backend vllm \
|
||||
--port 8000 \
|
||||
--max_logprobs 64
|
||||
|
||||
# 步骤 2:启动 GKD 训练
|
||||
CUDA_VISIBLE_DEVICES=1,2,3,4 \
|
||||
NPROC_PER_NODE=4 \
|
||||
swift rlhf \
|
||||
--rlhf_type gkd \
|
||||
--model Qwen/Qwen3.5-2B \
|
||||
--teacher_model_server http://localhost:8000 \
|
||||
--gkd_logits_topk 64 \
|
||||
--lmbda 1.0 \
|
||||
--beta 1.0 \
|
||||
--dataset xxx
|
||||
```
|
||||
|
||||
**在线采样加速**
|
||||
|
||||
`lmbda > 0` 时学生需在线生成序列,建议用 vLLM 加速采样(colocate / server 两种模式,与 GRPO 一致),参考 [GRPO 文档](./GRPO/GetStarted/GRPO.md#集群支持)。
|
||||
|
||||
**多轮 GKD**
|
||||
|
||||
GKD 多轮训练,与 GRPO 共享同一套 `MultiTurnScheduler` 基础设施。
|
||||
|
||||
完整接口和自定义方式请参考 [GRPO 多轮训练文档](./GRPO/DeveloperGuide/multi_turn.md)。
|
||||
|
||||
**参考脚本**
|
||||
|
||||
- 基础训练:[examples/train/rlhf/gkd/](https://github.com/modelscope/ms-swift/tree/main/examples/train/rlhf/gkd/)
|
||||
- 多轮训练:[examples/train/rlhf/gkd/multi_turn.sh](https://github.com/modelscope/ms-swift/blob/main/examples/train/rlhf/gkd/multi_turn.sh)
|
||||
- 多模态:[examples/train/multimodal/rlhf/gkd/](https://github.com/modelscope/ms-swift/tree/main/examples/train/multimodal/rlhf/gkd/)
|
||||
- Megatron:[examples/megatron/rlhf/gkd/](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/rlhf/gkd/)
|
||||
|
||||
|
||||
---
|
||||
|
||||
### 3.2 OPD-RL:KL 作为 RL Advantage
|
||||
|
||||
OPD(On-Policy Distillation)RL 把教师 KL 信号注入 GRPO 的 **per-token advantage**,通过 policy gradient 更新学生。
|
||||
|
||||
**原理**
|
||||
|
||||
标准 GRPO 的 advantage 来自组内归一化的任务奖励(per-sequence 标量)。OPD-RL 在 advantage 归一化**之后**逐 token 注入教师信号:
|
||||
|
||||
$$
|
||||
A_t = A_t^{\text{base}} + \alpha \cdot \big(\log \pi_{\text{teacher}}(y_t|x,y_{<t}) - \log \pi_{\text{student}}(y_t|x,y_{<t})\big)
|
||||
$$
|
||||
|
||||
- $A_t^{\text{base}}$:GRPO 归一化后的任务奖励 advantage(无奖励函数时为 0)。
|
||||
- $\alpha$:`--teacher_kl_coef`,教师信号强度。
|
||||
- $\log\pi_{\text{teacher}}(y_t) - \log\pi_{\text{student}}(y_t)$:教师 log-ratio,即 Reverse KL 梯度中 $\nabla_\theta\log\pi_\theta(y_t)$ 系数对应的 k1 估计量(见 `compute_teacher_logratio`)。
|
||||
|
||||
**纯蒸馏模式**:不设 `--reward_funcs` 时 base advantage 为 0,教师信号是唯一驱动力,此时 $A_t = \alpha\cdot(\log\pi_{\text{teacher}}(y_t)-\log\pi_{\text{student}}(y_t))$。
|
||||
|
||||
**监控指标**:日志中的 `teacher_kl` 是 k3 估计量 $e^{d}-d-1$($d=\log\pi_{\text{teacher}}-\log\pi_{\text{student}}$),衡量学生与教师的距离。
|
||||
|
||||
**启用方式**:在 `--rlhf_type grpo` 下设置 `--teacher_model` 或 `--teacher_model_server` 即自动启用 OPD-RL,无需额外开关。教师相关参数见上文共享参数表。
|
||||
|
||||
**OPD-RL 特有参数**
|
||||
|
||||
| 参数 | 默认值 | 说明 |
|
||||
|------|--------|------|
|
||||
| `--teacher_kl_coef` | 1.0 | 教师 log-ratio 注入 advantage 的系数 $\alpha$ |
|
||||
|
||||
**参考脚本**
|
||||
|
||||
- HF:[examples/train/grpo/opd_rl.sh](https://github.com/modelscope/ms-swift/tree/main/examples/train/grpo/opd_rl.sh)
|
||||
- Megatron:[examples/megatron/grpo/opd_rl.sh](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/grpo/opd_rl.sh)
|
||||
- Ray:[examples/ray/grpo/run_opd.sh](https://github.com/modelscope/ms-swift/tree/main/examples/ray/grpo/run_opd.sh)
|
||||
|
||||
|
||||
---
|
||||
|
||||
### 3.3 OPSD:On-Policy Self-Distillation
|
||||
|
||||
OPSD([On-Policy Self-Distillation](https://arxiv.org/abs/2601.18734))是一种单模型自蒸馏方法:同一模型分别构造学生输入与教师输入,教师侧额外接收**特权信息**(如参考解答),再对齐两者在学生采样响应上的输出分布。
|
||||
|
||||
**核心机制**
|
||||
|
||||
- **学生**:仅看到问题,正常推理。
|
||||
- **教师**:看到问题 + 参考解答(通过 `teacher_prompt` 列提供特权信息)。
|
||||
- **训练目标**:用散度(JSD / KL)对齐学生与教师在同一份学生采样响应上的输出分布。
|
||||
|
||||
OPSD 既可走 GKD 路径,也可走 OPD-RL 路径:
|
||||
|
||||
- **GKD + OPSD**:`--rlhf_type gkd`,教师 KL 作为直接损失。
|
||||
- **OPD-RL + OPSD**:`--rlhf_type grpo`;动态模式不传 `--teacher_model`,固定模式设 `--teacher_model` 与 `--model` 相同。
|
||||
|
||||
**两种自蒸馏权重模式**
|
||||
|
||||
| 模式 | 参数配置 | 教师权重 | 说明 |
|
||||
|------|---------|---------|------|
|
||||
| **Dynamic(动态)** | 不传 `--teacher_model` | 学生当前权重 | 教师随训练同步更新 |
|
||||
| **Fixed(固定)** | `--teacher_model` 设为与 `--model` 相同 | 初始教师权重 | 教师权重固定 |
|
||||
|
||||
**数据格式**
|
||||
|
||||
OPSD 数据集需包含 `teacher_prompt` 列,可通过 `--external_plugins` 加载数据处理插件来构建。以数学推理数据集 `open-r1/OpenThoughts-114k-math` 为例:
|
||||
|
||||
```python
|
||||
from swift.dataset import DatasetMeta, RowPreprocessor, register_dataset
|
||||
|
||||
class OpenThoughtsOPSDPreprocessor(RowPreprocessor):
|
||||
def preprocess(self, row):
|
||||
if not row.get('correct', True):
|
||||
return None
|
||||
problem = row.get('problem', '')
|
||||
solution = row.get('solution', '')
|
||||
teacher_prompt = f'{problem}\n\nReference solution:\n{solution}\n\nNow articulate your own reasoning.'
|
||||
messages = [
|
||||
{'role': 'system', 'content': 'Please reason step by step, and put your final answer within \\boxed{}.'},
|
||||
{'role': 'user', 'content': problem},
|
||||
]
|
||||
return {'messages': messages, 'teacher_prompt': teacher_prompt}
|
||||
|
||||
register_dataset(DatasetMeta(
|
||||
ms_dataset_id='open-r1/OpenThoughts-114k-math',
|
||||
preprocess_func=OpenThoughtsOPSDPreprocessor(),
|
||||
tags=['math', 'opsd'],
|
||||
))
|
||||
```
|
||||
|
||||
**参考脚本**
|
||||
|
||||
- HF:[examples/train/rlhf/opsd/](https://github.com/modelscope/ms-swift/tree/main/examples/train/rlhf/opsd/)
|
||||
- Megatron:[examples/megatron/rlhf/gkd/opsd.sh](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/rlhf/gkd/opsd.sh)
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Reference
|
||||
|
||||
- Kevin Lu & Thinking Machines Lab. [On-Policy Distillation](https://thinkingmachines.ai/blog/on-policy-distillation/). 2025.
|
||||
- Agarwal et al. [On-Policy Distillation of Language Models (GKD)](https://arxiv.org/pdf/2306.13649). 2023.
|
||||
- Gu et al. [MiniLLM: Knowledge Distillation of Large Language Models](https://arxiv.org/abs/2306.08543). 2023.
|
||||
- DeepSeek-AI. [DeepSeek-V4](https://arxiv.org/html/2606.19348v1). 2026.
|
||||
- Qwen Team. [Qwen3 Technical Report](https://arxiv.org/abs/2505.09388). 2025.
|
||||
- Zhipu AI. [GLM-5: from Vibe Coding to Agentic Engineering](https://arxiv.org/html/2602.15763). 2026.
|
||||
- Kimi Team. [Kimi K2.5: Visual Agentic Intelligence](https://arxiv.org/abs/2602.02276). 2026.
|
||||
@@ -0,0 +1,284 @@
|
||||
# 评测
|
||||
|
||||
SWIFT支持了eval(评测)能力,用于对原始模型和训练后的模型给出标准化的评测指标。
|
||||
|
||||
## 能力介绍
|
||||
|
||||
SWIFT的eval能力使用了魔搭社区[评测框架EvalScope](https://github.com/modelscope/eval-scope),并进行了高级封装以支持各类模型的评测需求。
|
||||
|
||||
> 注意:EvalScope支持许多其他的复杂能力,例如[模型的性能评测](https://evalscope.readthedocs.io/zh-cn/latest/user_guides/stress_test/quick_start.html),请直接使用EvalScope框架。
|
||||
|
||||
目前我们支持了**标准评测集**的评测流程,以及**用户自定义**评测集的评测流程。其中**标准评测集**由三个评测后端提供支持:
|
||||
|
||||
下面展示所支持的数据集名称,若需了解数据集的详细信息,请参考[所有支持的数据集](https://evalscope.readthedocs.io/zh-cn/latest/get_started/supported_dataset/index.html)
|
||||
|
||||
1. Native(默认):
|
||||
|
||||
主要支持纯文本评测,同时**支持**评测结果可视化
|
||||
```text
|
||||
'arc', 'bbh', 'ceval', 'cmmlu', 'competition_math',
|
||||
'general_qa', 'gpqa', 'gsm8k', 'hellaswag', 'humaneval',
|
||||
'ifeval', 'iquiz', 'mmlu', 'mmlu_pro',
|
||||
'race', 'trivia_qa', 'truthful_qa'
|
||||
```
|
||||
|
||||
2. OpenCompass:
|
||||
|
||||
主要支持纯文本评测,暂**不支持**评测结果可视化
|
||||
```text
|
||||
'obqa', 'cmb', 'AX_b', 'siqa', 'nq', 'mbpp', 'winogrande', 'mmlu', 'BoolQ', 'cluewsc', 'ocnli', 'lambada',
|
||||
'CMRC', 'ceval', 'csl', 'cmnli', 'bbh', 'ReCoRD', 'math', 'humaneval', 'eprstmt', 'WSC', 'storycloze',
|
||||
'MultiRC', 'RTE', 'chid', 'gsm8k', 'AX_g', 'bustm', 'afqmc', 'piqa', 'lcsts', 'strategyqa', 'Xsum', 'agieval',
|
||||
'ocnli_fc', 'C3', 'tnews', 'race', 'triviaqa', 'CB', 'WiC', 'hellaswag', 'summedits', 'GaokaoBench',
|
||||
'ARC_e', 'COPA', 'ARC_c', 'DRCD'
|
||||
```
|
||||
|
||||
3. VLMEvalKit:
|
||||
|
||||
主要支持多模态评测,暂**不支持**评测结果可视化
|
||||
```text
|
||||
'COCO_VAL', 'MME', 'HallusionBench', 'POPE', 'MMBench_DEV_EN', 'MMBench_TEST_EN', 'MMBench_DEV_CN', 'MMBench_TEST_CN',
|
||||
'MMBench', 'MMBench_CN', 'MMBench_DEV_EN_V11', 'MMBench_TEST_EN_V11', 'MMBench_DEV_CN_V11',
|
||||
'MMBench_TEST_CN_V11', 'MMBench_V11', 'MMBench_CN_V11', 'SEEDBench_IMG', 'SEEDBench2',
|
||||
'SEEDBench2_Plus', 'ScienceQA_VAL', 'ScienceQA_TEST', 'MMT-Bench_ALL_MI', 'MMT-Bench_ALL',
|
||||
'MMT-Bench_VAL_MI', 'MMT-Bench_VAL', 'AesBench_VAL', 'AesBench_TEST', 'CCBench', 'AI2D_TEST', 'MMStar',
|
||||
'RealWorldQA', 'MLLMGuard_DS', 'BLINK', 'OCRVQA_TEST', 'OCRVQA_TESTCORE', 'TextVQA_VAL', 'DocVQA_VAL',
|
||||
'DocVQA_TEST', 'InfoVQA_VAL', 'InfoVQA_TEST', 'ChartQA_TEST', 'MathVision', 'MathVision_MINI',
|
||||
'MMMU_DEV_VAL', 'MMMU_TEST', 'OCRBench', 'MathVista_MINI', 'LLaVABench', 'MMVet', 'MTVQA_TEST',
|
||||
'MMLongBench_DOC', 'VCR_EN_EASY_500', 'VCR_EN_EASY_100', 'VCR_EN_EASY_ALL', 'VCR_EN_HARD_500',
|
||||
'VCR_EN_HARD_100', 'VCR_EN_HARD_ALL', 'VCR_ZH_EASY_500', 'VCR_ZH_EASY_100', 'VCR_ZH_EASY_ALL',
|
||||
'VCR_ZH_HARD_500', 'VCR_ZH_HARD_100', 'VCR_ZH_HARD_ALL', 'MMDU', 'MMBench-Video', 'Video-MME'
|
||||
```
|
||||
|
||||
## 环境准备
|
||||
|
||||
```shell
|
||||
pip install ms-swift[eval] -U
|
||||
```
|
||||
|
||||
或从源代码安装:
|
||||
|
||||
```shell
|
||||
git clone https://github.com/modelscope/ms-swift.git
|
||||
cd ms-swift
|
||||
pip install -e '.[eval]'
|
||||
```
|
||||
|
||||
## 评测
|
||||
|
||||
支持纯文本评测、多模态评测、url评测、自定义数据集评测四种方式
|
||||
|
||||
**基本示例**
|
||||
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift eval \
|
||||
--model Qwen/Qwen2.5-0.5B-Instruct \
|
||||
--eval_backend Native \
|
||||
--infer_backend transformers \
|
||||
--eval_limit 10 \
|
||||
--eval_dataset gsm8k
|
||||
```
|
||||
其中:
|
||||
- model: 可指定本地模型路径或者modelscope上的模型ID
|
||||
- eval_backend: 可选 Native, OpenCompass, VLMEvalKit,默认为 Native
|
||||
- infer_backend: 可选 transformers, vllm, sglang, lmdeploy,默认为 transformers
|
||||
- eval_limit: 每个评测集的采样数,默认为None,表示使用全部数据,可用于快速验证
|
||||
- eval_dataset: 评测数据集,可设置多个数据集,用空格分割
|
||||
|
||||
**复杂评测示例**
|
||||
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift eval \
|
||||
--model Qwen/Qwen2.5-0.5B-Instruct \
|
||||
--eval_backend Native \
|
||||
--infer_backend transformers \
|
||||
--eval_limit 10 \
|
||||
--eval_dataset gsm8k \
|
||||
--eval_dataset_args '{"gsm8k": {"few_shot_num": 0, "filters": {"remove_until": "</think>"}}}' \
|
||||
--eval_generation_config '{"max_tokens": 512, "temperature": 0}' \
|
||||
--extra_eval_args '{"ignore_errors": true, "debug": true}'
|
||||
```
|
||||
|
||||
详细评测的参数列表可以参考[这里](Command-line-parameters.md#评测参数)。
|
||||
|
||||
## 训练中评测
|
||||
|
||||
SWIFT支持在训练过程中使用EvalScope对当前的模型进行评测,以便及时了解模型的训练效果。
|
||||
|
||||
**基本示例**
|
||||
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift sft \
|
||||
--model "Qwen/Qwen2.5-0.5B-Instruct" \
|
||||
--tuner_type "lora" \
|
||||
--dataset "AI-ModelScope/alpaca-gpt4-data-zh#100" \
|
||||
--torch_dtype "bfloat16" \
|
||||
--num_train_epochs "1" \
|
||||
--per_device_train_batch_size "1" \
|
||||
--learning_rate "1e-4" \
|
||||
--lora_rank "8" \
|
||||
--lora_alpha "32" \
|
||||
--target_modules "all-linear" \
|
||||
--gradient_accumulation_steps "16" \
|
||||
--save_steps "50" \
|
||||
--save_total_limit "5" \
|
||||
--logging_steps "5" \
|
||||
--max_length "2048" \
|
||||
--eval_strategy "steps" \
|
||||
--eval_steps "5" \
|
||||
--per_device_eval_batch_size "5" \
|
||||
--eval_use_evalscope \
|
||||
--eval_dataset "gsm8k" \
|
||||
--eval_dataset_args '{"gsm8k": {"few_shot_num": 0}}' \
|
||||
--eval_limit "10"
|
||||
```
|
||||
|
||||
注意启动命令为`sft`,其中eval相关的参数有:
|
||||
- eval_strategy: 评估策略。默认为None,跟随`save_strategy`的策略
|
||||
- eval_steps: 默认为None,如果存在评估数据集,则跟随`save_steps`的策略
|
||||
- eval_use_evalscope: 是否使用evalscope进行评测,需要设置该参数来开启评测
|
||||
- eval_dataset: 评测数据集,可设置多个数据集,用空格分割
|
||||
- eval_dataset_args: 评测数据集参数,json格式,可设置多个数据集的参数
|
||||
- eval_limit: 评测数据集采样数
|
||||
- eval_generation_config: 评测时模型推理配置,json格式,默认为`{'max_tokens': 512}`
|
||||
|
||||
|
||||
更多评测的样例可以参考[examples](https://github.com/modelscope/ms-swift/tree/main/examples/eval)
|
||||
|
||||
## 自定义评测集
|
||||
|
||||
本框架支持选择题和问答题,两种预定义的数据集格式,使用流程如下:
|
||||
|
||||
*注意:使用自定义评测时,eval_backend参数必须为Native*
|
||||
|
||||
### 选择题格式(MCQ)
|
||||
适合用户是选择题的场景,评测指标为准确率(accuracy)。
|
||||
|
||||
**数据准备**
|
||||
|
||||
准备选择题格式的csv文件,该目录结构如下:
|
||||
|
||||
```text
|
||||
mcq/
|
||||
├── example_dev.csv # (可选)文件名组成为`{subset_name}_dev.csv`,用于fewshot评测
|
||||
└── example_val.csv # 文件名组成为`{subset_name}_val.csv`,用于实际评测的数据
|
||||
```
|
||||
|
||||
其中csv文件需要为下面的格式:
|
||||
|
||||
```text
|
||||
id,question,A,B,C,D,answer
|
||||
1,通常来说,组成动物蛋白质的氨基酸有____,4种,22种,20种,19种,C
|
||||
2,血液内存在的下列物质中,不属于代谢终产物的是____。,尿素,尿酸,丙酮酸,二氧化碳,C
|
||||
```
|
||||
其中:
|
||||
- `id`是序号(可选)
|
||||
- `question`是问题
|
||||
- `A`, `B`, `C`, `D`等是可选项,最大支持10个选项
|
||||
- `answer`是正确选项
|
||||
|
||||
**启动评测**
|
||||
|
||||
运行下面的命令:
|
||||
|
||||
```bash
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift eval \
|
||||
--model Qwen/Qwen2.5-0.5B-Instruct \
|
||||
--eval_backend Native \
|
||||
--infer_backend transformers \
|
||||
--eval_dataset general_mcq \
|
||||
--eval_dataset_args '{"general_mcq": {"local_path": "/path/to/mcq", "subset_list": ["example"]}}'
|
||||
```
|
||||
其中:
|
||||
- `eval_dataset` 需要设置为 `general_mcq`
|
||||
- `eval_dataset_args` 需要设置
|
||||
- `local_path` 自定义数据集文件夹路径
|
||||
- `subset_list` 评测数据集名称,上述 `*_dev.csv` 中的 `*`
|
||||
|
||||
**运行结果**
|
||||
|
||||
```text
|
||||
+---------------------+-------------+-----------------+----------+-------+---------+---------+
|
||||
| Model | Dataset | Metric | Subset | Num | Score | Cat.0 |
|
||||
+=====================+=============+=================+==========+=======+=========+=========+
|
||||
| Qwen2-0.5B-Instruct | general_mcq | AverageAccuracy | example | 12 | 0.5833 | default |
|
||||
+---------------------+-------------+-----------------+----------+-------+---------+---------+
|
||||
```
|
||||
|
||||
## 问答题格式(QA)
|
||||
适合用户是问答题的场景,评测指标是`ROUGE`和`BLEU`。
|
||||
|
||||
**数据准备**
|
||||
|
||||
准备一个问答题格式的jsonline文件,该目录包含了一个文件:
|
||||
|
||||
```text
|
||||
qa/
|
||||
└── example.jsonl
|
||||
```
|
||||
|
||||
该jsonline文件需要为下面的格式:
|
||||
|
||||
```json
|
||||
{"query": "中国的首都是哪里?", "response": "中国的首都是北京"}
|
||||
{"query": "世界上最高的山是哪座山?", "response": "是珠穆朗玛峰"}
|
||||
{"query": "为什么北极见不到企鹅?", "response": "因为企鹅大多生活在南极"}
|
||||
```
|
||||
|
||||
**启动评测**
|
||||
|
||||
运行下面的命令:
|
||||
|
||||
```bash
|
||||
CUDA_VISIBLE_DEVICES=0 \
|
||||
swift eval \
|
||||
--model Qwen/Qwen2.5-0.5B-Instruct \
|
||||
--eval_backend Native \
|
||||
--infer_backend transformers \
|
||||
--eval_dataset general_qa \
|
||||
--eval_dataset_args '{"general_qa": {"local_path": "/path/to/qa", "subset_list": ["example"]}}'
|
||||
```
|
||||
|
||||
其中:
|
||||
- `eval_dataset` 需要设置为 `general_qa`
|
||||
- `eval_dataset_args` 是一个json字符串,需要设置:
|
||||
- `local_path` 自定义数据集文件夹路径
|
||||
- `subset_list` 评测数据集名称,上述 `*.jsonl` 中的 `*`
|
||||
|
||||
**运行结果**
|
||||
|
||||
```text
|
||||
+---------------------+-------------+-----------------+----------+-------+---------+---------+
|
||||
| Model | Dataset | Metric | Subset | Num | Score | Cat.0 |
|
||||
+=====================+=============+=================+==========+=======+=========+=========+
|
||||
| Qwen2-0.5B-Instruct | general_qa | bleu-1 | default | 12 | 0.2324 | default |
|
||||
+---------------------+-------------+-----------------+----------+-------+---------+---------+
|
||||
| Qwen2-0.5B-Instruct | general_qa | bleu-2 | default | 12 | 0.1451 | default |
|
||||
+---------------------+-------------+-----------------+----------+-------+---------+---------+
|
||||
| Qwen2-0.5B-Instruct | general_qa | bleu-3 | default | 12 | 0.0625 | default |
|
||||
+---------------------+-------------+-----------------+----------+-------+---------+---------+
|
||||
| Qwen2-0.5B-Instruct | general_qa | bleu-4 | default | 12 | 0.0556 | default |
|
||||
+---------------------+-------------+-----------------+----------+-------+---------+---------+
|
||||
| Qwen2-0.5B-Instruct | general_qa | rouge-1-f | default | 12 | 0.3441 | default |
|
||||
+---------------------+-------------+-----------------+----------+-------+---------+---------+
|
||||
| Qwen2-0.5B-Instruct | general_qa | rouge-1-p | default | 12 | 0.2393 | default |
|
||||
+---------------------+-------------+-----------------+----------+-------+---------+---------+
|
||||
| Qwen2-0.5B-Instruct | general_qa | rouge-1-r | default | 12 | 0.8889 | default |
|
||||
+---------------------+-------------+-----------------+----------+-------+---------+---------+
|
||||
| Qwen2-0.5B-Instruct | general_qa | rouge-2-f | default | 12 | 0.2062 | default |
|
||||
+---------------------+-------------+-----------------+----------+-------+---------+---------+
|
||||
| Qwen2-0.5B-Instruct | general_qa | rouge-2-p | default | 12 | 0.1453 | default |
|
||||
+---------------------+-------------+-----------------+----------+-------+---------+---------+
|
||||
| Qwen2-0.5B-Instruct | general_qa | rouge-2-r | default | 12 | 0.6167 | default |
|
||||
+---------------------+-------------+-----------------+----------+-------+---------+---------+
|
||||
| Qwen2-0.5B-Instruct | general_qa | rouge-l-f | default | 12 | 0.333 | default |
|
||||
+---------------------+-------------+-----------------+----------+-------+---------+---------+
|
||||
| Qwen2-0.5B-Instruct | general_qa | rouge-l-p | default | 12 | 0.2324 | default |
|
||||
+---------------------+-------------+-----------------+----------+-------+---------+---------+
|
||||
| Qwen2-0.5B-Instruct | general_qa | rouge-l-r | default | 12 | 0.8889 | default |
|
||||
+---------------------+-------------+-----------------+----------+-------+---------+---------+
|
||||
```
|
||||
@@ -0,0 +1,59 @@
|
||||
# 导出与推送
|
||||
|
||||
|
||||
## Merge LoRA
|
||||
|
||||
- 查看[这里](https://github.com/modelscope/ms-swift/blob/main/examples/export/merge_lora.sh)。
|
||||
|
||||
## 量化
|
||||
|
||||
SWIFT支持AWQ、GPTQ、FP8、BNB模型的量化导出。其中使用AWQ、GPTQ需使用校准数据集,量化性能较好但量化耗时较长;而FP8、BNB无需校准数据集,量化耗时较短。
|
||||
|
||||
| 量化技术 | 多模态 | 推理加速 | 继续训练 |
|
||||
| -------- | ------ | -------- | -------- |
|
||||
| FP8 | ✅ | ✅ | ✅ |
|
||||
| GPTQ | ✅ | ✅ | ✅ |
|
||||
| AWQ | ✅ | ✅ | ✅ |
|
||||
| BNB | ❌ | ✅ | ✅ |
|
||||
|
||||
|
||||
除SWIFT安装外,需要安装以下额外依赖:
|
||||
```shell
|
||||
# 使用awq量化:
|
||||
# autoawq和cuda版本有对应关系,请按照`https://github.com/casper-hansen/AutoAWQ`选择版本
|
||||
# 如果出现torch依赖冲突,请额外增加指令`--no-deps`
|
||||
pip install autoawq -U
|
||||
|
||||
# 使用gptq量化:
|
||||
# auto_gptq和cuda版本有对应关系,请按照`https://github.com/PanQiWei/AutoGPTQ#quick-installation`选择版本
|
||||
pip install auto_gptq optimum -U
|
||||
|
||||
# 使用gptq v2量化:
|
||||
pip install gptqmodel optimum -U
|
||||
|
||||
# 使用bnb量化:
|
||||
pip install bitsandbytes -U
|
||||
```
|
||||
|
||||
我们提供了一系列脚本展现SWIFT的量化导出能力:
|
||||
- 支持[AWQ](https://github.com/modelscope/ms-swift/blob/main/examples/export/quantize/awq.sh)/[GPTQ](https://github.com/modelscope/ms-swift/blob/main/examples/export/quantize/gptq.sh)/[GPTQ v2](https://github.com/modelscope/ms-swift/blob/main/examples/export/quantize/gptq_v2.sh)/[BNB](https://github.com/modelscope/ms-swift/blob/main/examples/export/quantize/bnb.sh)量化导出。
|
||||
- 多模态量化: 支持使用GPTQ和AWQ对多模态模型进行量化,其中AWQ支持的多模态模型有限。参考[这里](https://github.com/modelscope/ms-swift/tree/main/examples/export/quantize/mllm)。
|
||||
- 更多系列模型的支持: 支持[Bert](https://github.com/modelscope/ms-swift/tree/main/examples/export/quantize/bert),[Reward Model](https://github.com/modelscope/ms-swift/tree/main/examples/export/quantize/reward_model)的量化导出。
|
||||
- 使用SWIFT量化导出的模型支持使用vllm/sglang/lmdeploy进行推理加速;也支持使用QLoRA继续进行SFT/RLHF。
|
||||
|
||||
|
||||
## 推送模型
|
||||
|
||||
SWIFT支持将训练/量化的模型重新推送到ModelScope/HuggingFace。默认推送到ModelScope,你可以指定`--use_hf true`推送到HuggingFace。
|
||||
```shell
|
||||
swift export \
|
||||
--model output/vx-xxx/checkpoint-xxx \
|
||||
--push_to_hub true \
|
||||
--hub_model_id '<model-id>' \
|
||||
--hub_token '<sdk-token>' \
|
||||
--use_hf false
|
||||
```
|
||||
|
||||
小贴士:
|
||||
- 你可以使用`--model <checkpoint-dir>`或者`--adapters <checkpoint-dir>`指定需要推送的checkpoint目录,这两种写法在推送模型场景没有差异。
|
||||
- 推送到ModelScope时,你需要确保你已经注册了魔搭账号,你的SDK token可以在[该页面](https://www.modelscope.cn/my/myaccesstoken)中获取。推送模型需确保sdk token的账号具有model_id对应组织的编辑权限。推送模型将自动创建对应model_id的模型仓库(如果该模型仓库不存在),你可以使用`--hub_private_repo true`来自动创建私有的模型仓库。
|
||||
@@ -0,0 +1,471 @@
|
||||
# 常见问题整理
|
||||
|
||||
下面是SWIFT使用过程中遇到的一些常见问题。
|
||||
|
||||
## 训练
|
||||
|
||||
SWIFT支持的训练方法包括预训练、指令监督微调、偏好学习、GRPO、Embedding、Reranker、序列分类任务等,详见[主页](https://github.com/modelscope/ms-swift/blob/main/README_CN.md)。
|
||||
|
||||
### Q1: SWIFT支持的模型有哪些?如何设置本地模型路径?
|
||||
支持的模型详见文档[支持的模型和数据集](https://swift.readthedocs.io/zh-cn/latest/Instruction/Supported-models-and-datasets.html)。如果模型已经下载到了本地,设置`--model <path_to_model>`即可。对于离线环境训练,同时设置`--model 本地路径`,`--check_model false`,如果提示git clone相关报错,需要clone repo,然后通过`local_repo_path`指定,详见[命令行参数](https://swift.readthedocs.io/zh-cn/latest/Instruction/Command-line-parameters.html)。从ModelScope下载的模型,可以配置环境变量`MODELSCOPE_CACHE=your_path`将原始的模型存到指定路径;如果用ModelScope SDK下载,通过`cache_dir="本地地址"`;也可以使用`modelscope download`命令行工具或`git`下载,详见modelscope文档[模型下载](https://modelscope.cn/docs/models/download)。如果需要从Hugging Face下载模型,设置环境变量`USE_HF=1`。
|
||||
SWIFT会自动匹配model_type,也可以查看文档[支持的模型和数据集](https://swift.readthedocs.io/zh-cn/latest/Instruction/Supported-models-and-datasets.html),手动指定。
|
||||
|
||||
### Q2: SWIFT支持的数据集有哪些?如何使用自定义数据集?
|
||||
支持的数据集详见文档[支持的模型和数据集](https://swift.readthedocs.io/zh-cn/latest/Instruction/Supported-models-and-datasets.html)。自定义数据集格式及使用方法见文档[自定义数据集](https://swift.readthedocs.io/zh-cn/latest/Customization/Custom-dataset.html),符合这些格式的数据集会自动使用swift内置的数据预处理器。如果与文档中的格式不一致,请自行转换格式,或者参考已支持的数据集接入。若自定义数据集中有额外的字段,这些字段默认不会被使用,可以通过[命令行参数remove_unused_columns](https://swift.readthedocs.io/zh-cn/latest/Instruction/Command-line-parameters.html#id4)进行设置。
|
||||
需要将数据集下载到本地,然后通过路径指定,请查看[自定义数据集文档](https://swift.readthedocs.io/zh-cn/latest/Customization/Custom-dataset.html#dataset-info-json)。`git clone`下载到本地,然后通过dataset_info.json文件中的`dataset_path`字段指定就行。
|
||||
数据随机详见[命令行参数dataset_shuffle](https://swift.readthedocs.io/zh-cn/latest/Instruction/Command-line-parameters.html)。
|
||||
强制重新下载数据集,设置命令行参数`--download_mode`。对数据集进行错误检查,请设置命令行参数`strict`。需要数据集质检工具时,可以查看另一个库[data-juicer](https://github.com/modelscope/data-juicer)。
|
||||
由于datasets的底层pyarrow对于类型管控比较严格,图像grounding数据集的objects部分、agent数据集的tools部分等,因为这个原因要用str,要不pyarrow就会报错:你每行的类型不一致。
|
||||
训练中遇到报错`AttributeError:’TrainerState’ object has no attribute ’last_model_checkpoint’`,数据集太少了,数据数量不足一个step导致的报错,增加一些数据。另外,切分的验证集数据很少时也会有类似报错。
|
||||
下面是一个assistant字段为空导致的报错:
|
||||
```text
|
||||
File "/mnt/workspace/swift/swift/1lm/dataset/preprocessor/core. py", line 69, in _check_messages raise
|
||||
ValueError(f'assistant_message; {assistant_message}')
|
||||
ValueError: assistant_message: {'role' :'assistant', 'content': ''}
|
||||
```
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 NPROC_PER_NODE=1 MAX_PIXELS=1003520 swift sft --model Qwen/Qwen2.5-VL-7B-Instruct --tuner_type lora --dataset /mnt/workspace/data.json --deepspeed zero2 --max_length 16384
|
||||
```
|
||||
数据集assistant字段为空,如果是推理,把这个空字符串删掉,因为这个会导致训练时NaN,会做检查。
|
||||
|
||||
### Q3: 从缓存加载数据集相关问题
|
||||
设置命令行参数`--load_from_cache_file true`,可以加快数据集加载速度,尤其是在多模态数据集、数据量较大等场景。在debug或修改preprocessor时,设置为false,更多说明请在[命令行参数文档](https://swift.readthedocs.io/zh-cn/latest/Instruction/Command-line-parameters.html)中搜索该参数。
|
||||
|
||||
### Q4: 如何搭建SWIFT环境?有镜像可以使用吗?
|
||||
环境搭建详见[SWIFT安装文档](https://swift.readthedocs.io/zh-cn/latest/GetStarted/SWIFT-installation.html),一些常见依赖的推荐版本可以在[主页](https://github.com/modelscope/ms-swift/blob/main/README_CN.md)上找到。文档中提供了镜像,用`docker run`命令启动容器即可,如:`docker run --gpus all -p 8000:8000 -it -d --name ms modelscope-registry.cn-hangzhou.cr.aliyuncs.com/modelscope-repo/modelscope:ubuntu22.04-cuda12.8.1-py311-torch2.9.0-vllm0.13.0-modelscope1.33.0-swift3.12.5 /bin/bash`,启动容器后拉最新代码安装swift。
|
||||
|
||||
### Q5: 多模态模型训练数据格式、参数冻结、优化器设置相关问题
|
||||
多模态模型训练的[例子](https://github.com/modelscope/ms-swift/tree/main/examples/train/multimodal)。支持纯文本、图文数据训练,也可以两种数据混合训练。图像、视频、音频相关的参数,如,最大像素、fps等请查看[特定模型参数](https://swift.readthedocs.io/zh-cn/latest/Instruction/Command-line-parameters.html#id19)。
|
||||
Grounding任务中通用数据格式支持了一个物体对应多个bbox,参考文档[自定义数据集](https://swift.readthedocs.io/zh-cn/latest/Customization/Custom-dataset.html#grounding)。videos可以是图片列表,使用文件目录的方式。
|
||||
SWIFT按max_pixels对图像进行调整,会保存预处理前和后的图像,然后对bbox进行调整,不过推理没有这样的调整,需要提前手动处理图像。
|
||||
VLM模型训练减少显存使用,请配置`--freeze_vit true`,以及限制最大像素的参数`--max_pixels`。`--freeze_vit`,`--freeze_aligner`,`--freeze_llm`这几个参数详见[命令行参数文档](https://swift.readthedocs.io/zh-cn/latest/Instruction/Command-line-parameters.html#tuner)。如果ViT没有训练,那有会有warning: none of the inputs have requires_grad=True是正常的,如果训练了,则不应该抛出。
|
||||
使用全参数微调visual encoder同时使用LoRA微调LLM,参考这里[例子](https://github.com/modelscope/ms-swift/tree/main/examples/train/multimodal/lora_llm_full_vit)。
|
||||
|
||||
### Q6: template相关问题
|
||||
由于jinja chat template没有labels,所以不支持训练。
|
||||
多模态数据集如果需要在加载数据之后做动态数据增强,例如,给输入数据随机添加噪声等,请在template中修改encode方法。
|
||||
|
||||
### Q7: SWIFT训练如何debug?
|
||||
详见[预训练与微调文档](https://swift.readthedocs.io/zh-cn/latest/Instruction/Pre-training-and-Fine-tuning.html)。
|
||||
|
||||
### Q8: SWIFT如何使用python脚本训练?
|
||||
参考[notebook例子](https://github.com/modelscope/ms-swift/tree/main/examples/notebook)。
|
||||
|
||||
### Q9: SWIFT如何使用UI界面训练?
|
||||
使用`swift web-ui`命令,界面训练与命令行一致,界面上的参数请查看命令行参数文档。自定义数据集的使用与上面Q2一致。Megatron-SWIFT不支持UI界面训练。
|
||||
|
||||
### Q10: 单机多卡训练相关问题
|
||||
SWIFT多卡训练底层依赖torchrun。`deepspeed` 和 `device_map`不兼容,两个只能选1个。更多细节请查看代码库中的[例子](https://github.com/modelscope/ms-swift/tree/main/examples/train/multi-gpu)。
|
||||
|
||||
### Q11: 多机多卡训练相关问题
|
||||
请查看[多机多卡例子](https://github.com/modelscope/ms-swift/tree/main/examples/train/multi-node)。多机多卡训练时,只有主节点有日志。
|
||||
多机训练速度缓慢,如,使用DeepSpeed ZeRO3训练会出现严重的速度下降,请查看[issue](https://github.com/modelscope/ms-swift/issues/1825)。
|
||||
|
||||
### Q12: 大规模数据集相关问题
|
||||
数据集太大了,然后每次tokenize都需要很久,请使用`lazy_tokenize`或流式读取`streaming`,详见[命令行参数](https://swift.readthedocs.io/zh-cn/latest/Instruction/Command-line-parameters.html)。
|
||||
|
||||
### Q13: 断点续训相关问题
|
||||
先前训练脚本中的参数不变,加上`--resume_from_checkpoint output/xxx/vx-xxx/checkpoint-xxx`,详见[命令行参数](https://swift.readthedocs.io/zh-cn/latest/Instruction/Command-line-parameters.html)。如果数据集发生了改动,仅加载模型,请同时设置`--resume_only_model`。更复杂的场景,请在命令行参数文档中搜索resume。
|
||||
|
||||
### Q14: 数据集流式加载相关问题
|
||||
流式加载`--streaming true`,一边训练一边加载,需要设置max_steps,详见`streaming`参数说明,[命令行参数文档](https://swift.readthedocs.io/zh-cn/latest/Instruction/Command-line-parameters.html#id4)。
|
||||
注意:streaming是不随机的,也不划分验证集,验证集通过命令行参数`val_dataset`指定。
|
||||
断点续训时,流式只能往前索引,不能随机索引,跳过已经训练的数据耗时特别长,不建议用流式。
|
||||
|
||||
### Q15: packing相关问题
|
||||
packing要和flash_attn一起使用,不然是有误差,attention_mask会出问题。
|
||||
Qwen3.5模型中的linear-attention不支持var_len,不建议开启packing。
|
||||
开启packing,多模态数据会有两次map,map完一次后还会进行第二次mapping,一次是数据集的,一次是template的。如果速度非常慢,可以设置`OMP_NUM_THREADS=14`加速,或者可以把packing去掉,就不会有第二次了。
|
||||
|
||||
### Q16: 数据集多进程处理
|
||||
数据集map过程比较慢时,设置参数`--dataset_num_proc`可以开多进程。多模态数据集map比较慢是正常的。
|
||||
|
||||
### Q17: 当前训练完默认保存多少个checkpoint?
|
||||
默认保存所有的checkpoint,详见[命令行参数 save_total_limit](https://swift.readthedocs.io/zh-cn/latest/Instruction/Command-line-parameters.html)。
|
||||
|
||||
### Q18: 训练过程的loss和acc
|
||||
自定义的损失函数在plugin中加就可以。如果需要不同数据集的loss曲线,请设置`--enable_channel_loss`。
|
||||
如果eval得到的acc和对应保存的ckpt去重新推理一遍计算得到的acc不是一致的,是因为训练时候的eval_acc和推理时候的acc计算方式不一样导致的。`acc_strategy`: 默认为`'token'`, 可选择的值包括: `'token'`,`'seq'`。
|
||||
训练过程中没有token_acc是因为有些模型`logits`和`labels`数量对不上,就不算的。
|
||||
可以在[这里](https://github.com/modelscope/ms-swift/blob/main/swift/loss/mapping.py)查看当前支持的loss或添加新的loss,
|
||||
检查`<image>`等特殊token是否参与损失计算,可以在命令行日志中找一下打印的labels。
|
||||
训练agent时,tool_call就是应该算loss,tool_response不算loss。
|
||||
|
||||
### Q19: 模型参数freeze相关问题
|
||||
训练的过程中,冻结某些层时导致某些参数未参与梯度回传,请配置参数`--ddp_find_unused_parameters true`。
|
||||
freeze_parameters和freeze_vit/freeze_aligner/freeze_llm:先freeze parameters再active parameters。`freeze vit/freeze aligner/freeze llm`这三个参数会对freeze parameters 和trainable parameters进行调整.因为有些模型的ViT中包含`aligner`,所以会将`aligner`单独加入trainable_parameters。
|
||||
freeze_parameters_ratio这个参数的机制是从embedding开始从下往上freeze。
|
||||
|
||||
### Q20: 序列并行相关问题
|
||||
序列并行支持pt, sft, dpo and grpo。参考这个例子[sequence_parallel](https://github.com/modelscope/ms-swift/tree/main/examples/train/sequence_parallel)。
|
||||
VLM模型的目前仅支持flash-attn,纯文本支持flash-attn和sdpa。
|
||||
sequence parallel可以和Liger kernel同时使用。
|
||||
sequence parallel和自定义loss冲突时,由于sequence parallel在自己的代码中定制了loss,可以自己改下[这里](https://github.com/modelscope/ms-swift/blob/main/swift/trainers/sequence_parallel/ulysses.py)。
|
||||
|
||||
### Q21: 扩充词表
|
||||
用SWIFT框架扩充词表需要设置命令行参数`new_special_tokens`,`--modules_to_save embed_tokens lm_head`,详见[例子](https://github.com/modelscope/ms-swift/tree/main/examples/train/new_special_tokens)。
|
||||
|
||||
### Q22: tuners相关问题
|
||||
SWIFT中的LlamaPro对多模态做了适配。
|
||||
LongLoRA只有LLaMA系列模型能用。
|
||||
LoRA训练和`--trainable_parameters`参数不兼容,LoRA模块之外其他的可训练参数用modules_to_save。
|
||||
|
||||
### Q23: embedding/reranker训练
|
||||
[embedding训练例子](https://github.com/modelscope/ms-swift/blob/main/examples/train/embedding)。
|
||||
[reranker训练例子](https://github.com/modelscope/ms-swift/tree/main/examples/train/reranker)。
|
||||
数据格式见[自定义数据集](https://swift.readthedocs.io/zh-cn/latest/Customization/Custom-dataset.html)。
|
||||
|
||||
### Q24: 分类任务训练
|
||||
SWIFT支持多标签分类,自定义数据集文档有数据格式,在命令行参数文档中搜索`problem_type`,其他和回归是一样的。
|
||||
注意:label字段和message字段同级。
|
||||
|
||||
### Q25: thinking模型训练
|
||||
查看这个[issue](https://github.com/modelscope/ms-swift/issues/4030)。
|
||||
|
||||
### Q26: 想问一下,SWIFT支持蒸馏吗?
|
||||
参考这个[例子](https://github.com/modelscope/ms-swift/blob/main/examples/sampler/distill/distill.sh)。
|
||||
|
||||
### Q27: gkd训练student model和teacher model的model_type需要一致吗,一个dense一个moe可以吗?
|
||||
可以的,只需要词表一样,不过带MoE就会比较慢。
|
||||
|
||||
### Q28: GRPO训练相关问题
|
||||
SWIFT现在支持多模态的GRPO训练。GRPO训练过程中loss接近0是正常情况,参考[issue](https://github.com/huggingface/open-r1/issues/239#issuecomment-2646297851)。
|
||||
设置sleep_mode,推理结束VllmEngine释放显存。下次调用时,再加载,而不是一直占用。
|
||||
GRPO训练时不想引入KL项,可以通过命令行参数beta设置。
|
||||
LoRA微调后继续做GRPO训练,请在命令行参数文档中搜索`--adapters`。
|
||||
由于算entropy会有额外的一点开销,所以默认没有记录熵曲线。如果需要,请设置`--log_entropy true`,
|
||||
colocate模式不支持use_async_engine。
|
||||
GRPO不支持channel_loss。
|
||||
Liger kernel和padding free没法在GRPO阶段一起开。如果一起开,需要改liger grpo loss的实现,在liger kernel库中,不方便改。
|
||||
如果训练集有不同的task,请查看[多任务训练](https://swift.readthedocs.io/zh-cn/latest/Instruction/GRPO/DeveloperGuide/multi_task.html)。
|
||||
|
||||
### Q29: reward函数(模型)相关问题
|
||||
reward_model和reward_funcs可以一起使用。
|
||||
自定义reward函数参考[examples/train/grpo/plugin](https://github.com/modelscope/ms-swift/tree/main/examples/train/grpo/plugin)。
|
||||
针对math问题,要从数据集里面传solution,不然不好算accuracy。
|
||||
如果在ORM的自定义奖励函数中需要传入数据集中的某个列,请将该列放到messages之外的其他列。
|
||||
在GRPO训练的过程中如果需要指定一个llm-judge模型来做打分,请参考奖励模型的文档。
|
||||
|
||||
### Q30: rollout相关问题
|
||||
Rollout应该是不兼容pipeline parallel。
|
||||
vLLM推理引擎默认trust_rwmote_code为true。
|
||||
|
||||
### Q31: 请教一个问题,grpo脚本中的save_steps指的是step还是global step?目前本地训练显示的global step是18, wandb上显示的step是628。
|
||||
`global_step`,本地tqdm显示的。
|
||||
|
||||
### Q32: 默认只用 num_iterations=1 的话,clip 就失去作用了吧?dapo 的 clip higher 也没用。我看 veRL 有个 micro batch 可以设置单轮小批次更新 policy model 来使得 clip 项生效,ms-swift 的 mini batch 看源码貌似只是做了梯度累加?
|
||||
是的,需要num_iterations>1。
|
||||
|
||||
### Q33: 请问gspo训练支持传入参数top_entropy_quantile吗?传入了--importance_sampling_level sequence后,还能实现对熵分布前x%的token的优化吗?
|
||||
支持,顺序是先正常计算loss(受importance_sampling_level影响),再根据top_entropy_quantile mask掉loss。
|
||||
|
||||
### Q34: GRPO文档中的faq
|
||||
更多GRPO相关的FAQ,请查看[GRPO文档](https://swift.readthedocs.io/zh-cn/latest/Instruction/GRPO/GetStarted/GRPO.html#faq)
|
||||
|
||||
### Q35: ppo等偏好训练相关问题
|
||||
PPO训练不支持梯度裁剪。
|
||||
目前PPO还只支持RM和policy是同一系列的模型(tokenizer/template)。
|
||||
不支持多轮的DPO。
|
||||
|
||||
### Q36: MoE模型训练相关问题
|
||||
MoE模型LoRA训练,如果aux-loss基本没变化,将all-router也加到target_modules。
|
||||
LoRA训练中,路由器模块是否参与训练看gate是否是nn.Linear实现,如果是nn.Parameter就不训练,详见命令行参数[target_parameters](https://swift.readthedocs.io/zh-cn/latest/Instruction/Command-line-parameters.html#tuner)。
|
||||
|
||||
### Q37: Megatron-SWIFT训练相关问题
|
||||
Checkpoint保存,参考命令行参数[save_strategy](https://swift.readthedocs.io/zh-cn/latest/Megatron-SWIFT/Command-line-parameters.html)。
|
||||
Megatron多机训练时,因为pp并行只有在pp last rank有完整的信息, 日志在last rank打印,而不是从master node打印。
|
||||
Megatron-SWIFT支持了save_total_limit,支持了SwanLab监控训练,详见[Megatron-SWIFT命令行参数文档](https://swift.readthedocs.io/zh-cn/latest/Megatron-SWIFT/Command-line-parameters.html)
|
||||
ViT用的是transformers的模型结构,目前没有并行,训练遇到OOM时降低`decoder_first_pipeline_num_layers`。
|
||||
Megatron-SWIFT支持新的模型,目前没有教程,请查看新增模型的PR。
|
||||
sequence_parallel的并行数等于tp数。
|
||||
FP8训练支持block wise,参考[examples/megatron/fp8例子](https://github.com/modelscope/ms-swift/tree/main/examples/megatron/fp8)。
|
||||
|
||||
### Q38: 请问Megatron-SWIFT如何配置断点续训?
|
||||
配置`--mcore_model`加载checkpoint,另外根据需要配置这几个参数,`--finetune`,`--no_load_optim`,`--no_load_rng`。如果是LoRA断点续训,配置`--mcore_adapter`,其他同全参数训练,详见[Megatron-SWIFT命令行参数文档](https://swift.readthedocs.io/zh-cn/latest/Megatron-SWIFT/Command-line-parameters.html)。
|
||||
|
||||
### Q39: mtp相关问题
|
||||
需要MTP训练,请设置命令行参数`mtp_num_layers`。
|
||||
如果base模型不附带MTP结构,可以从头初始化训练MTP。
|
||||
多模态的MTP目前还没支持。
|
||||
|
||||
### Q40: 有个关于Megatron GKD的问题请教,如果teacher是Qwen3-235B,student是Qwen3-30BA3B,之前SFT 235B都是pp8然后decoder fist和decoder last设为11。如果我在GKD的时候也设置decoder first last,会不会影响student的并行?
|
||||
现在两个模型的并行参数是共用的,不同并行的设置会在v4版本后支持。
|
||||
|
||||
### Q41: 量化模型训练相关问题
|
||||
QLoRA微调参考[例子](https://github.com/modelscope/ms-swift/tree/main/examples/train/qlora)。
|
||||
量化模型不能全参数微调,GPTQ模型的int型参数无法参与求导,只能附着LoRA等额外结构参与更新。
|
||||
QLoRA训练后的模型merge参考[QLoRA例子](https://github.com/modelscope/ms-swift/tree/main/examples/train/qlora)。
|
||||
Megatron-SWIFT不支持QLoRA训练。
|
||||
|
||||
### Q42: 一些特殊模型的训练
|
||||
SWIFT目前不支持MiniCPM-O使用音频模态输入的训练。
|
||||
微调DeepSeek-VL-2,transformers用4.42以前的版本,`peft==0.11.*`。
|
||||
Moonlight-16B-A3B-Instruct微调。因为模型文件中禁止了训练, 参考DeepSeek-VL-2的解决方案,issue中搜索。
|
||||
微调Ovis2这个模型有点特殊,需要padding到max_length。设置一下`--max_length`。
|
||||
Qwen2.5-Omni目前不支持talker训练,只有thinker。
|
||||
Qwen2-Audio的sft不支持packing。
|
||||
|
||||
### Q43: 请问在不支持flash attention的设备上attention implemation默认是什么呢?文档中默认是none
|
||||
默认使用sdpa。
|
||||
|
||||
### Q44: 请问默认模型训练都是left padding是吧?
|
||||
训练可以选择使用左padding还是右padding。默认是右padding, `batch infer`都是左padding。
|
||||
|
||||
### Q45: 请问下MoE的参数有哪些,参数表里关键字搜索不到?专家数量,专家路由这些参数怎么设置?
|
||||
直接用config.json中的参数。
|
||||
|
||||
### Q46: SWIFT能够支持设置最小的learning rate吗,感觉最后减到太小了
|
||||
可以设置,`--lr_scheduler_type cosine_with_min_lr --lr_scheduler_kwargs '{"min_lr": 1e-6}'`。
|
||||
|
||||
### Q47: 目前支持用yaml文件配置grpo和sft吗?
|
||||
都支持的,该配置是在main.py中直接处理成命令行。
|
||||
|
||||
### Q48: 请问现在是不支持use_liger_kernel和log_entropy一起用吗?
|
||||
不支持。
|
||||
|
||||
### Q49: 请问下,遇到这个报错,怎么处理?安装了apex也不行
|
||||
```text
|
||||
RuntimeError: ColumnParallelLinear was called with gradient_accumulation_fusion set to True but the custom CUDA extension fused_weight_gradient_mlp_cuda module is not found. To use gradient_accumulation_fusion you must install APEX with --cpp_ext and --cuda_ext. For example: pip install --global-option="--cpp_ext" --global-option="--cuda_ext ." Note that the extension requires CUDA>=11. Otherwise, you must turn off gradient accumulation fusion.
|
||||
```
|
||||
设置一下`--gradient_accumulation_fusion false`。
|
||||
|
||||
### Q50: 几个任务一起finetune vlm,不同任务视频采样规则不一致,ms-swift是否支持?在哪里配置?
|
||||
[命令行参数文档](https://swift.readthedocs.io/zh-cn/latest/Instruction/Command-line-parameters.html)看下`interleave_prob`。
|
||||
|
||||
### Q51: 想问一个问题,多模态packing预训练每次pytorch allocator cache flushes since last step后,显存使用好像就会增长一点,步数多了容易oom
|
||||
加个环境变量`PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True'`。
|
||||
|
||||
### Q52: use_logits_to_keep 现在多模态大模型上可以用吗?
|
||||
如果多模态token的展开在模型的forward内会报错。
|
||||
|
||||
### Q53: 请问一下为什么训练到会有好几次显存大幅度增加,已经50step或者100step
|
||||
设置环境变量`PYTORCH_CUDA_ALLOC_CONF`,具体查看PyTorch文档。
|
||||
|
||||
### Q54: 从qwen base模型微调成chat模型有没有实践文档,有什么要特别配置的吗?
|
||||
`swift sft`,没有其他需要特别配置的,参考[例子](https://github.com/modelscope/ms-swift/tree/main/examples/train/base_to_chat)。
|
||||
|
||||
### Q55: 模型训练后,回复重复了很多内容
|
||||
参考[预训练与微调](https://swift.readthedocs.io/zh-cn/latest/Instruction/Pre-training-and-Fine-tuning.html)。如果训练过程中出现重复的情况,请多训练几个epoch, 清洗数据, 全参数训练, 采用RLHF的方式缓解。
|
||||
|
||||
### Q56: 请问为什么 --torch_dtype float16 (卡不能使用bf16)会出现报错:lib/python3.12/site-packages/torch/amp/grad_scaler.py", line 260, in _unscale_grads_ raise ValueError("Attempting to unscale FP16 gradients.") ValueError: Attempting to unscale FP16 gradients.
|
||||
全参数,不能fp16训练的。
|
||||
|
||||
### Q57: 请问下,lora参数合并报错,目前peft是0.11.0,这个是因为peft版本需要升级吗
|
||||
```text
|
||||
File "/opt/conda/lib/python3.9/site-packages/peft/config.py", line 118, in from_peft_type
|
||||
return config_cls(**kwargs)
|
||||
TypeError: __init__() got an unexpected keyword argument 'corda_config'
|
||||
```
|
||||
训练和合并的peft版本不一致导致的。
|
||||
|
||||
### Q58: 请问这个问题如何解决?safetensors_rust.SafetensorError: Error while deserializing header: HeaderTooLarge
|
||||
磁盘空间不足了,模型没有保存完整。
|
||||
|
||||
### Q59: 这个错误为什么会出现在这,numpy.object找不到在哪?
|
||||
`numpy==1.26.3`,尝试一下。
|
||||
|
||||
### Q60: unsloth训练,报错:assert(type(target modules) in (list,tuple,))。配置的参数是--target modules all-linear
|
||||
别用`all-linear`,改为具体的模块列表,比如`--target_modules q k v`。
|
||||
|
||||
### Q61: 请问对于qwen2.5-omni来说--freeze_vit false意味这视觉编码器和音频编码器都打开了,有什么办法可以只打开音频编码器不打开视觉编码器吗?
|
||||
`--target_regex`写一下。
|
||||
|
||||
## 推理
|
||||
|
||||
SWIFT支持python脚本、命令行、ui界面推理,详见[推理和部署](https://swift.readthedocs.io/zh-cn/latest/Instruction/Inference-and-deployment.html)。
|
||||
|
||||
### Q1:SWIFT推理如何设置模型?
|
||||
如果是全参数训练的模型、LoRA训练后合并的模型或者从model hub下载的模型,设置命令行参数`--model <model_id_or_path>`;LoRA训练后未合并的模型,用`--adapters`设置,同时可通过`--model`指定基模路径。
|
||||
|
||||
### Q2: SWIFT如何使用数据集进行推理?推理结果保存在哪儿?
|
||||
`--val_dataset <your-val-dataset>`,指定数据集。对于训练后的模型也可以设置参数`--load_data_args true`。推理结果保存路径通过`--result_path your_path`设置,日志中会打印路径。详见文档[命令行参数](https://swift.readthedocs.io/zh-cn/latest/Instruction/Command-line-parameters.html)。
|
||||
如果需要保留推理数据集中额外的字段,请设置`--remove_unused_columns false`。
|
||||
|
||||
### Q3: SWIFT如何设置批量推理?
|
||||
如果infer_backend为`transformers`,设置命令行参数`--max_batch_size 16`,或[python脚本](https://github.com/modelscope/ms-swift/blob/main/examples/infer/demo.py)。这里max_batch_size指的是每张卡上的batch_size。
|
||||
|
||||
### Q4: SWIFT如何设置流式推理?
|
||||
`--stream true`,此时推理结果将逐条写入jsonl文件。需要注意的是,流式推理不支持ddp。
|
||||
|
||||
### Q5: vLLM和SGLang推理后端相关的问题
|
||||
对于LoRA训练的模型,请查看vLLM和SGLang文档,如果支持LoRA推理则不需要合并。此外,SGLang推理目前不支持多模态。
|
||||
|
||||
### Q6: 生成参数相关的问题
|
||||
temperature等参数默认从generation_config.json中读取。设置`--temperature 0`或者`--top_k 1`可以取消推理随机性。
|
||||
|
||||
### Q7: 如何将system_prompt置空?命令行不设置system参数,但是它会加上默认的system。
|
||||
设置`--system ''`。
|
||||
|
||||
### Q8: 推理时如何计算acc/rouge等指标?
|
||||
参考[推理参数metric](https://swift.readthedocs.io/zh-cn/latest/Instruction/Command-line-parameters.html#id14)。
|
||||
|
||||
### Q9: 模型推理的时候如果需要在特定前缀下继续推理的话是设置哪个参数?
|
||||
参数`--response_prefix`。
|
||||
|
||||
### Q10: 数据answer里面已经包含了部分prompt,希望补全answer,应该怎么修改inference?
|
||||
```text
|
||||
{"messages": [{"role": "system", "content": "<system>"}, {"role": "user", "content": "<query1>"}, {"role": "assistant", "content": "answer1, "}]}
|
||||
```
|
||||
参考[examples/infer/demo_agent](https://github.com/modelscope/ms-swift/blob/main/examples/infer/demo_agent.py)。
|
||||
|
||||
### Q11: 多模态模型推理时如何限制最大像素,以减少显存占用?
|
||||
设置命令行参数`--max_pixels xxx`、环境变量`MAX_PIXELS=xxx`、或特定模型参数`--model_kwargs '{"max_pixels": xxx}'`,其中环境变量仅对文档中对应的模型生效,详见文档[特定模型参数](https://swift.readthedocs.io/zh-cn/latest/Instruction/Command-line-parameters.html#id18)。
|
||||
|
||||
### Q12: SWIFT推理如何输出概率值logprobs参数?
|
||||
命令行推理设置`--logprobs true`,python脚本推理设置`request_config = RequestConfig(..., logprobs=True, top_logprobs=2)`,参考[test_logprobs.py](https://github.com/modelscope/ms-swift/blob/main/tests/infer/test_logprobs.py)。
|
||||
|
||||
### Q13: SWIFT推理如何输出last_hidden_state?
|
||||
没有例子,可以参考GRPO trainer的`_get_last_hidden_state`方法。
|
||||
|
||||
### Q14: transformers,vllm,ollama等推理结果不一致问题
|
||||
SWIFT的template是对齐transformers的。检查推理参数是否对其。此外,VllmEngine和TransformersEngine是有差异的。
|
||||
|
||||
### Q15: embedding/reranker模型推理
|
||||
embedding模型推理参考这里的[例子](https://github.com/modelscope/ms-swift/blob/main/examples/infer/demo_embedding.py)。reranker模型推理参考这里的[例子](https://github.com/modelscope/ms-swift/blob/main/examples/infer/demo_reranker.py)。
|
||||
|
||||
### Q16: 请问在使用python脚本推理时,如何使用cpu?
|
||||
设置环境变量,`os.environ['CUDA_VISIBLE_DEVICES'] = '-1'`。
|
||||
|
||||
### Q17: 使用swift infer命令进行推理,支持多机推理吗?
|
||||
如果单节点放得下模型,外面封装k8s就行。如果单节点放不下那就不支持。
|
||||
|
||||
### Q18: swift sample的时候,好像不支持batch?好像是for循环一个个例子sample,有点慢
|
||||
有一个[脚本](https://github.com/modelscope/ms-swift/blob/main/examples/train/rft/rft.py),可以用多进程对数据集拆分采样。
|
||||
|
||||
### Q19: 特殊模型依赖版本相关问题
|
||||
Qwen2-Audio推理结果出现混乱,请使用transformers4.48。
|
||||
transformers4.55.2训练的LoRA不能使用小于4.52的版本加载了,详见[issue#5440](https://github.com/modelscope/ms-swift/issues/5440)。
|
||||
swift对不同版本的qwen-vl-utils做了兼容,使用qwen2.5-vl和qwen3-vl模型时不需要切换该依赖版本。
|
||||
|
||||
### Q20: 报错,safetensors_rust.SafetensorError: Error while deserializing header:MetadataIncompleteBuffer
|
||||
模型权重损坏了。
|
||||
|
||||
### Q21: vLLM 报错 `ValueError: the decoder prompt contains a(n) video item with length 16758, which exceeds the pre-allocated encoder cache size 16384. please reduce the input size or increase the encoder cache size by setting --limit-mm-per-prompt at startup.`
|
||||
这通常是多模态输入过长,超过了 vLLM 预分配的 encoder cache size 导致的。可以通过 `--limit-mm-per-prompt` 调整 encoder cache size。另一个可行的解决方法是增大 `max_num_batched_tokens`,在 Swift cli 中传入:
|
||||
```shell
|
||||
--vllm_engine_kwargs '{"max_num_batched_tokens": 20000}'
|
||||
```
|
||||
|
||||
## 导出
|
||||
|
||||
### Q1: autoawq相关的报错
|
||||
如果推理没有涉及AWQ量化模型,但出现了autoawq相关的报错,可以尝试卸载autoawq再进行推理。不支持AWQ量化的模型,尝试用GPTQ进行量化。
|
||||
|
||||
### Q2: SWIFT量化模型时,一张卡上放不下模型的情况
|
||||
尝试设置`--device_map cpu`。或者多卡加载模型,单卡量化。
|
||||
|
||||
### Q3: 想问一下用swift export对qwen2.5 72B模型进行gptq int4量化,max model length=32768用的是默认值,给的校准数据集有128个样本,但是量化的时候报错了,报错日志是:factorization could not be completed because the input is not positive-definite(the leading minor of order 18145 is not pisitive-definite)。是什么原因?
|
||||
海森矩阵不正定的问题,试试其他的数据集。
|
||||
|
||||
### Q4: swift export的时候传入自定义的template_type,是不是就可以永久改掉template_type了?如果swift export --template_type 自定义,是不是就可以把模型对应的template改掉
|
||||
不会被修改,swift中的template是定义在swift内部的,不是以jinja方式保存的。
|
||||
|
||||
### Q5: 模型训练完能直接转gguf格式吗?
|
||||
目前只支持导出ModelFile,详见文档[命令行参数](https://swift.readthedocs.io/zh-cn/latest/Instruction/Command-line-parameters.html)。
|
||||
|
||||
## 部署
|
||||
|
||||
### Q1: SWIFT部署如何设置模型?
|
||||
同上面推理Q1。
|
||||
|
||||
### Q2: SWIFT如何进行多卡部署?
|
||||
详见[例子](https://github.com/modelscope/ms-swift/tree/main/examples/deploy)。如果是transformers engine,不支持DDP,不能多卡部署。此外,不支持异构部署,如不同型号的显卡、各显卡设置不同的存储占比等。
|
||||
|
||||
### Q3: 通过--system参数指定system prompt与数据集中每个数据前加system prompt以及template的system prompt是不是有一个就行?这些方式对模型来说,是不是一样的?
|
||||
system优先级:数据集中的>命令行的>template中默认的。
|
||||
|
||||
### Q4: 客户端多模态输入相关问题
|
||||
客户端传入图片、音频等,见[客户端例子](https://github.com/modelscope/ms-swift/tree/main/examples/deploy/client/mllm)。
|
||||
如果图片url非法,可以设置请求的超时时间,环境变量`SWIFT_TIMEOUT`,或者`InferClient`中可以传参数。
|
||||
|
||||
### Q5: 生成参数设置相关问题
|
||||
temperature等参数推理只能启动前设置,部署可以在启动时设置默认值,之后在客户端继续设置,覆盖默认值。
|
||||
|
||||
### Q6: SWIFT部署的模型怎么设置流式生成?
|
||||
客户端控制的,查看[examples/deploy/client](https://github.com/modelscope/ms-swift/tree/main/examples/deploy/client)。
|
||||
|
||||
### Q7: SWIFT部署如何输出token的概率?
|
||||
服务端设置`--logprobs true`,要客户端传参数,`request_config = RequestConfig(..., logprobs=True, top_logprobs=2)`。
|
||||
|
||||
### Q8: 部署模型时,thinking相关问题
|
||||
如果需要禁止思考,目前只能在swift deploy启动的时候禁止thinking。查看这个[issue](https://github.com/modelscope/ms-swift/issues/4030)。
|
||||
|
||||
### Q9: 部署时,设置什么参数可以实现一次输出多个结果?
|
||||
`RequestConfig`参数`n`。
|
||||
|
||||
### Q10: SWIFT部署,指定--infer_backend vllm,和直接使用vllm部署相关问题
|
||||
如果两者推理结果相差较多,可能是template没对齐。如果推理速度相差较多,可能是图像分辨率不一致。swift默认使用V1 engine,可以通过环境变量`VLLM_USE_V1=1`控制。
|
||||
|
||||
### Q11: 特殊模型和依赖版本相关问题
|
||||
如果遇到报错没有“model.language_model.embed_tokens.weight”,训练前后的transformers版本不一致。
|
||||
qwen2.5使用fp16推理如果遇到返回乱码,尝试bf16。
|
||||
|
||||
### Q12: 有个问题想问一下,qwen2-7b部署后使用客户端时,调用openai的api要使用client.completions.create,不能使用client.chat.completions.create,但是使用qwen2-7b-instruct-q5_k_m.gguf的时候可以使用client.chat.completions.create,这是为什么呀?
|
||||
base模型可以用client.chat.completions.create的,不过这个是兼容行为。
|
||||
|
||||
## 评测
|
||||
|
||||
### Q1: SWIFT支持的评测集有哪些?以及如何使用自定义评测集?
|
||||
标准评测集和用户自定义评测集的使用详见文档[评测](https://swift.readthedocs.io/zh-cn/latest/Instruction/Evaluation.html)。
|
||||
|
||||
### Q2: 官方支持的评测数据集手动下载后,swift eval能配置本地路径评测吗?
|
||||
离线评测请参考EvalScope文档[快速上手](https://evalscope.readthedocs.io/zh-cn/latest/get_started/basic_usage.html)
|
||||
|
||||
### Q3: eval微调后的模型,总是会在固定的百分比停掉,但是vllm服务看着一直是有在正常运行的。模型越大,断开的越早。
|
||||
`SWIFT_TIMEOUT`环境变量设置为-1。
|
||||
|
||||
### Q4: 评估的时候可不可以控制数据集条数?评估一个mmlu需要一个多小时,也太慢了。
|
||||
配置参数`--eval_limit`,这里的`--eval_limit`是控制了每个subset的条数,比如mmlu有50多个subset,每个limit10条,那就是500多条。
|
||||
|
||||
### Q5: 问一下评估swift eval里,模型最多生成1024token就结束了,这个如何修改?设置--max_new_tokens 5000,看起来没起作用
|
||||
查看命令行参数[eval_generation_config](https://swift.readthedocs.io/zh-cn/latest/Instruction/Command-line-parameters.html#id16)
|
||||
|
||||
### Q6: 请教一下,想使用OpenCompass的后端评测,如何从本地加载下载好的数据集?
|
||||
OpenCompass后端不支持设置`data_args`。
|
||||
|
||||
### Q7: swift eval 来评估模型,--eval_backend OpenCompass不支持自定义数据集吗?
|
||||
```text
|
||||
ValueError: eval_dataset: /mnt/workspace/data.jsonl is not supported.
|
||||
eval_backend: OpenCompass supported datasets: ['C3', 'summedits', 'WiC', 'csl', 'lambada', 'mbpp', 'hellaswag', 'ARC_e', 'math', 'nq', 'race', 'MultiRC', 'cmb', 'ceval', 'GaokaoBench', 'mmlu', 'winogrande', 'tnews', 'triviaqa', 'CB', 'cluewsc', 'humaneval', 'AX_g', 'DRCD', 'RTE', 'ocnli_fc', 'gsm8k', 'obqa', 'ReCoRD', 'Xsum', 'ocnli', 'WSC', 'siqa', 'agieval', 'piqa', 'cmnli', 'cmmlu', 'eprstmt', 'storycloze', 'AX_b', 'afqmc', 'strategyqa', 'bustm', 'BoolQ', 'COPA', 'ARC_c', 'PMMEval', 'chid', 'CMRC', 'lcsts']
|
||||
```
|
||||
OpenCompass不支持自定义数据集,用native可以自定义模式。
|
||||
|
||||
### Q8: evalscope原生是可以生成报告的,其他后端如opencompass是不支持生成报告可视化是吗?
|
||||
目前只支持native的可视化,其他后端还不支持。
|
||||
|
||||
### Q9: 请问一下评测ifeval报这个错是什么原因?
|
||||
```text
|
||||
[Errno 20] Not a directory: '/root/nltk_data/tokenizers/punkt_tab.zip/punkt_tab/english/collocations.tab'
|
||||
```
|
||||
解压这个文件,`unzip /path/to/nltk_data/tokenizers/punkt_tab.zip`。
|
||||
|
||||
### Q10: 请问评测时eval_backend='OpenCompass',怎么指定离线数据集路径?
|
||||
查看[数据准备教程](https://evalscope.readthedocs.io/zh-cn/latest/user_guides/backend/opencompass_backend.html#id3),下载数据集并解压。不用指定`dataset-args`,将数据集文件夹(即data文件夹)放置在当前工作路径下即可。
|
||||
|
||||
### Q11: 用evalscope报这个错是什么原因?
|
||||
```text
|
||||
unzip: cannot find or open /root/nltk_data/tokenizers/punkt_tab.zip, /root/nltk_data/tokenizers/punkt_tab.zip.zip or /root/nltk_data/tokenizers/punkt_tab.zip.ZIP
|
||||
```
|
||||
这是在下载nltk的依赖,手动下载[punkt_tab.zip](https://modelscope-open.oss-cn-hangzhou.aliyuncs.com/open_data/nltk_data/punkt_tab.zip),解压到`~/nltk_data/tokenizers`下面。
|
||||
|
||||
### Q12: 为啥纯文本没问题,测多模态我们指定路径了,但他还是检测不到数据集,会去下载?
|
||||
VLMEvalKit流程跟native不一样,会自己下载数据放到`~/LMUData/`下面,详见[文档](https://evalscope.readthedocs.io/zh-cn/latest/user_guides/backend/vlmevalkit_backend.html#id2)。
|
||||
|
||||
### Q13: 请问一下swift eval做benchmark评测的时候,是否可以指定llm作为judge, 参数应该怎么传进去?
|
||||
支持,使用swift得从`extra_eval_args`去传递`judge-model-args`参数,包括`api_key,api_url,model_id`,整体是一个json字符串。
|
||||
|
||||
### Q14: 请问在执行eval的时候出现了多卡显存分配不均是什么原因?
|
||||
```shell
|
||||
NPROC_PER_NODE=8
|
||||
ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7\ MAX_PIXELS=802816\ swift eval\
|
||||
--model "$MODEL_PATH” \$EXTRA_ARGS \
|
||||
--eval_backend Native \ --infer_backend transformers\ --device_map auto \
|
||||
--eval_limit"$EVAL_LIMIT"\ --eval_dataset general_qa\
|
||||
--dataset_args "{\"general_qa\": {\"local_path\": \"${DATA_PATH}\", \"subset_list\": [\"${SUBSET_NAME}\"]}}" \ --host 127.0.0.1\> "$LOG_FILE" 2>&1
|
||||
```
|
||||
swift eval不支持DDP方式启动。
|
||||
|
||||
### Q15: 请问哪里可以看到swift评测的时候送入的query除了问题之外还有哪些额外的字段呢?
|
||||
最简单的方法是看输出的reviews文件中的input字段,是输入给模型的内容转换后的Markdown格式。如果用backend是opencompass的话没有这些,需要用native backend。
|
||||
|
||||
ms-swift的eval能力使用了魔搭社区评测框架EvalScope, 复杂能力请直接使用[EvalScope框架](https://evalscope.readthedocs.io/zh-cn/latest/get_started/introduction.html)。
|
||||
@@ -0,0 +1,63 @@
|
||||
# On-Policy RL Meets Off-Policy Experts: Harmonizing SFT and RL via Dynamic Weighting (CHORD)
|
||||
|
||||
本文档介绍论文 [On-Policy RL Meets Off-Policy Experts: Harmonizing SFT and RL via Dynamic Weighting](https://arxiv.org/abs/2508.11408) 中提出的 CHORD 算法。CHORD 的核心思想是在强化学习过程中,动态融合专家数据(SFT),通过 全局权重 μ + token 级别权重 φ 的双重控制机制,在模仿与探索之间实现平衡。
|
||||
|
||||
## 算法概述
|
||||
CHORD 算法通过在 GRPO loss 中引入 **SFT loss**,实现动态混合训练。总体目标函数为:
|
||||
|
||||
$$
|
||||
\mathcal{L}_{\text{CHORD}} = (1 - \mu) \cdot \mathcal{L}_{\text{GRPO}} + \mu \cdot \mathcal{L}_{\text{SFT}}
|
||||
$$
|
||||
|
||||
其中:
|
||||
- $\mathcal{L}_{\text{GRPO}}$:基于 on-policy 采样的强化学习损失(类似 PPO)。
|
||||
- $\mathcal{L}_{\text{SFT}}$:监督微调损失。
|
||||
- $\mu \in [0, 1]$:全局平衡系数,控制 SFT 信号在总梯度中的贡献。
|
||||
|
||||
### 参数配置(数据与批量大小)
|
||||
我们可以基于 GRPO 训练实现 CHORD 训练。
|
||||
|
||||
CHORD 需要在训练时指定额外的 SFT 数据集和批量大小:
|
||||
- `chord_sft_dataset`: 用于提供专家数据的 SFT 数据集。
|
||||
- `chord_sft_per_device_train_batch_size`: 每个设备的 SFT mini-batch 大小。
|
||||
|
||||
---
|
||||
|
||||
## 两种 CHORD 变体
|
||||
|
||||
论文提出了两种算法变体:**CHORD-µ** 和 **CHORD-ϕ**。
|
||||
|
||||
### CHORD-µ
|
||||
通过在训练过程中逐步 **衰减 μ**,实现从模仿专家到自主探索的过渡。
|
||||
|
||||
**参数:**
|
||||
- `chord_mu_peak`:μ 的峰值。
|
||||
- `chord_mu_valley` μ 的衰减终值。
|
||||
- `chord_mu_warmup_steps` μ 值上升至峰值的训练步数。
|
||||
- `chord_mu_decay_steps` μ 从峰值衰减到谷值的训练步数。
|
||||
|
||||
### CHORD-ϕ(Token 级加权)
|
||||
**CHORD-ϕ** 通过 **token-wise 权重函数 φ** 动态控制每个专家 token 的梯度贡献。
|
||||
|
||||
**φ 定义:**
|
||||
$$
|
||||
\phi(y_t^\star, \pi_\theta) = p_t \cdot (1 - p_t)
|
||||
$$
|
||||
|
||||
其中:
|
||||
- $p_t = \pi_\theta(y_t^\star \mid x, y_{<t}^\star)$:模型当前预测专家 token 的概率。
|
||||
- 当 $p_t ≈ 0.5$(模型不确定时),φ 取最大值 → 强化学习不确定的 token。
|
||||
- 当 $p_t ≈ 0$ 或 $p_t ≈ 1$,φ → 0 → 避免对过于确定或完全不会的 token 过度学习。
|
||||
|
||||
**开启 φ 加权的参数**:
|
||||
- `chord_enable_phi_function: bool = False`
|
||||
- 设置为 `True` 即启用 token-wise 权重 φ。
|
||||
|
||||
注:如果使用常数 μ 值 ,设置 chord_mu_peak 与 chord_mu_valley 相同
|
||||
|
||||
<details>
|
||||
<summary>mu值衰减与loss计算代码实现</summary>
|
||||
请参考`GRPOTrainer`的`_compute_chord_loss`方法:
|
||||
</details>
|
||||
|
||||
训练参考该[脚本](https://github.com/modelscope/ms-swift/tree/main/examples/train/grpo/internal/chord.sh)
|
||||
@@ -0,0 +1,61 @@
|
||||
# Clipped Importance Sampling Policy Optimization (CISPO)
|
||||
|
||||
|
||||
Clipped Importance Sampling Policy Optimization (CISPO) 是 [MiniMax-M1](https://arxiv.org/abs/2506.13585) 论文中提出的一种强化学习算法。相比GRPO(Group Relative Policy Optimization)算法,CISPO 对重要性采样权重(importance sampling weights)本身进行裁剪。
|
||||
|
||||
## 算法原理
|
||||
为便于理解,我们基于 GRPO 算法进行对比说明。
|
||||
|
||||
GRPO通过裁剪策略比率来限制策略更新幅度,其损失函数为:
|
||||
|
||||
$$
|
||||
\mathcal{L}_{\text{GRPO}}(\theta) = -\mathbb{E}\left[\min\left(r_t(\theta) \cdot \hat{A}_t, \text{clip}(r_t(\theta), 1-\epsilon, 1+\epsilon) \cdot \hat{A}_t\right)\right]
|
||||
$$
|
||||
|
||||
其中 $r_t(\theta) = \frac{\pi_\theta(a_t|s_t)}{\pi_{\theta_{\text{old}}}(a_t|s_t)}$ 是重要性采样比。
|
||||
|
||||
在处理长推理链条时,这种裁剪方式可能导致以下问题:
|
||||
|
||||
**关键 Token 的梯度被抑制**:在复杂推理任务中,某些关键的低概率 token(如 *However, Recheck, Wait, Aha*)对于触发深度思考和推理纠错至关重要。这些 token 在旧策略 $\pi_{\theta_{\text{old}}}$ 中概率较低,当新策略试图提高其概率时,会导致较大的策略比率 $r_t(\theta)$,GRPO 的裁剪机制会将这些 token 丢弃。
|
||||
|
||||
|
||||
### CISPO 的解决方案
|
||||
|
||||
CISPO 的核心思想是:裁剪重要性采样权重,保留梯度更新。具体来说,CISPO 的损失函数为:
|
||||
|
||||
$$
|
||||
\mathcal{L}_{\text{CISPO}}(\theta) = -\mathbb{E}\left[\text{detach}\left(\min(r_t(\theta), \epsilon_{\text{high}})\right) \cdot \hat{A}_t \cdot \log \pi_\theta(a_t|s_t)\right]
|
||||
$$
|
||||
|
||||
其中 $r_t(\theta) = \frac{\pi_\theta(a_t|s_t)}{\pi_{\theta_{\text{old}}}(a_t|s_t)}$ 是重要性采样比。
|
||||
|
||||
**关键机制**:
|
||||
- 对重要性采样权重进行裁剪:$\min(r_t(\theta), \epsilon_{\text{high}})$
|
||||
- **detach 操作**:裁剪后的权重不参与梯度计算,作为常数系数
|
||||
- 梯度来自 $\log \pi_\theta(a_t|s_t)$ 项,保证所有 token 都有梯度贡献
|
||||
|
||||
|
||||
## 实现细节
|
||||
CISPO 的伪代码实现如下:
|
||||
|
||||
```python
|
||||
log_ratio = per_token_logps - old_per_token_logps
|
||||
importance_weights = torch.exp(log_ratio) # r_t(θ) = π_θ / π_θ_old
|
||||
|
||||
clamped_ratios = torch.clamp(importance_weights, max=epsilon_high).detach()
|
||||
|
||||
per_token_loss = -clamped_ratios * advantages.unsqueeze(1) * per_token_logps
|
||||
```
|
||||
|
||||
## 参数设置
|
||||
|
||||
我们可以基于 `GRPOTrainer`,通过设置以下参数实现 CISPO 训练:
|
||||
|
||||
```bash
|
||||
--loss_type cispo
|
||||
--epsilon_high 5.0
|
||||
```
|
||||
|
||||
> 相比其他算法, cispo 的 epsilon_high 一般取值较大,minimax论文中未给出具体的参数设置,这里的值参考论文[ScaleRL](https://arxiv.org/pdf/2510.13786)的实验设置
|
||||
|
||||
其他训练参数参考 [GRPO参数文档](../../Command-line-parameters.md#grpo参数)
|
||||
@@ -0,0 +1,102 @@
|
||||
# DAPO: An Open-Source LLM Reinforcement Learning System at Scale
|
||||
|
||||
|
||||
|
||||
[Decoupled Clip and Dynamic sAmpling Policy Optimization (DAPO)](https://arxiv.org/abs/2503.14476)在GRPO的基础上设置了几种trick,分别是
|
||||
- [Clip Higher](#clip-higher)
|
||||
- [Dynamic Sampling](#dynamic-sampling)
|
||||
- [Token level Loss](#token-level-loss)
|
||||
- [Overlong Filtering](#overlong-filtering)
|
||||
- [Soft Overlong Punishment](#soft-overlong-punishment)
|
||||
|
||||
## Clip Higher
|
||||
PPO和GRPO使用对称裁剪范围(如±0.2)限制策略更新幅度,虽然保证了稳定性,但也制约了模型的探索能力。特别是当某些token在旧策略中概率极低时,即使当前梯度显示其应被强化(A>0),最大增幅也被严格限制。
|
||||
|
||||
DAPO使用非对称裁剪范围, 提高上裁剪范围来鼓励模型进行探索:
|
||||
|
||||
- 上界(鼓励侧)放宽至0.28
|
||||
- 下界(抑制侧)保持0.2不变
|
||||
|
||||
GRPO中,默认使用`epsilon`设置用对称裁剪范围
|
||||
|
||||
使用参数
|
||||
|
||||
- `epsilon_high` 设置上裁剪范围,此时参数`epsilon` 为下裁剪范围
|
||||
|
||||
## Dynamic Sampling
|
||||
GRPO对每个问题采样多个回答计算组间优势,
|
||||
|
||||
$$
|
||||
\hat{A}_{i,t} = \frac{R_i - \text{mean}(\{R_j\}_{j=1}^G)}{\text{std}(\{R_j\}_{j=1}^G)}
|
||||
$$
|
||||
而当生成的所有输出{oi}获得相同奖励时,组间优势等于0,会出现梯度消失导致训练效率下降
|
||||
|
||||
DAPO引入动态采样策略解决这一问题:
|
||||
|
||||
- 采样阶段跳过组间奖励标准差为0的数据
|
||||
- 持续生成样本直到填满批次
|
||||
|
||||
|
||||
使用参数
|
||||
|
||||
- `dynamic_sample true` 来开启动态采样
|
||||
- `max_resample_times` 设置最多重采样次数
|
||||
|
||||
## Token level Loss
|
||||
GRPO 在归一化损失时采用句子级归一化,这会导致损失计算具有长度偏差。
|
||||
|
||||
DAPO 使用token级归一化,避免了回答长度在损失计算上的偏差。
|
||||
|
||||
使用参数
|
||||
|
||||
- loss_type bnpo/dapo 来使用token级归一化
|
||||
|
||||
> loss_type 计算公式可参考[文档](../DeveloperGuide/loss_types.md)
|
||||
|
||||
## Overlong Filtering
|
||||
DAPO 认为被强制截断的回复的奖励噪声较大,可能会导致模型难以区分质量问题和长度问题。为此,DAPO 筛除了训练中被截断的数据,使其不参与损失计算。
|
||||
|
||||
使用参数
|
||||
|
||||
- overlong_filter 开启对超长样本的过滤
|
||||
|
||||
|
||||
## Soft Overlong Punishment
|
||||
语言模型常面临生成长度控制难题:
|
||||
|
||||
- 过长输出可能被截断,导致正确内容被误判
|
||||
|
||||
- 无约束生成长度影响实用性和计算效率
|
||||
|
||||
DAPO 设计了三段式长度惩罚函数:
|
||||
|
||||
$$
|
||||
R_{\text{length}}(L) =
|
||||
\begin{cases}
|
||||
0, & L \leq L_{\text{max}} - L_{\text{cache}} \\[10pt]
|
||||
\dfrac{(L_{\text{max}} - L_{\text{cache}}) - L}{L_{\text{cache}}}, & L_{\text{max}} - L_{\text{cache}} < L \leq L_{\text{max}} \\[10pt]
|
||||
-1, & L > L_{\text{max}}
|
||||
\end{cases}
|
||||
$$
|
||||
|
||||
在长度位于 $(L_{\text{max}} - L_{\text{cache}} < L \leq L_{\text{max}})$ 区间时设置线性递增惩罚,在 $(L > L_{\text{max}})$ 时设置最大惩罚(-1)
|
||||
|
||||
|
||||
使用参数
|
||||
|
||||
- `reward_funcs soft_overlong` 启用该奖励函数
|
||||
- `soft_max_length` 设置L_max,默认等于为模型的最长输出长度(max_completion_length)。
|
||||
- `soft_cache_length`: 设置L_cache
|
||||
|
||||
## 参数设置
|
||||
综上所述,我们可以基于GRPOTrainer,设置以下参数实现 DAPO 训练。
|
||||
|
||||
| 参数 | 类型 | 值 |
|
||||
|----------------------|-----------|-------------|
|
||||
| `--loss_type` | `str` | `bnpo`/`dapo`|
|
||||
| `--epsilon_high` | `float` | `0.28` |
|
||||
| `--dynamic_sample` | `bool` | `true` |
|
||||
| `--max_resample_times` | `int` | `3` |
|
||||
| `--overlong_filter` | `bool` | `true` |
|
||||
| `--reward_funcs` | `str` | `soft_overlong`|
|
||||
| `--soft_cache_length` | `int` | `4096`|
|
||||
@@ -0,0 +1,54 @@
|
||||
# FIPO: Future-KL Influenced Policy Optimization
|
||||
|
||||
作者: [li2zhi](https://github.com/li2zhi)
|
||||
|
||||
[FIPO](https://arxiv.org/abs/2603.19835) 是一种面向长链推理的 value-free RL 方法。它保留 GRPO/DAPO 的整体训练框架,但改变 token 级策略更新的加权方式:不再让一个序列级 advantage 均匀作用到所有 token,而是用折扣累积的 Future-KL 信号判断“从当前 token 开始的后续轨迹”整体是在被增强还是被削弱。
|
||||
|
||||
## 核心思想
|
||||
|
||||
GRPO/DAPO 中,每个 response 的 token 通常共享同一个序列级 advantage:
|
||||
|
||||
$$
|
||||
\hat{A}_{i,t} = \hat{A}_{i}
|
||||
$$
|
||||
|
||||
这种做法稳定且简单,但 credit assignment 粒度较粗。FIPO 引入当前策略与旧策略在每个 token 上的 log-prob shift:
|
||||
|
||||
$$
|
||||
\Delta \log p_t = \log \pi_\theta(y_t \mid x, y_{<t}) -
|
||||
\log \pi_{\mathrm{old}}(y_t \mid x, y_{<t})
|
||||
$$
|
||||
|
||||
如果 $\Delta \log p_t > 0$,说明当前训练正在提高该 token 的概率;如果小于 0,则说明该 token 正在被压低。FIPO进一步从当前位置向后折扣累积该信号:
|
||||
|
||||
$$
|
||||
\mathrm{FutureKL}_t =
|
||||
\sum_{k=t}^{T}\gamma^{k-t} M_k \Delta \log p_k
|
||||
$$
|
||||
|
||||
其中 $M_k$ 是 completion mask,$\gamma = 2^{-1 / \text{decay\_rate}}$。`decay_rate` 越大,越远的 future token 对当前位置的影响越强;`decay_rate` 越小,Future-KL 越偏局部。然后将 Future-KL 映射为 influence weight:
|
||||
|
||||
$$
|
||||
f_t = \mathrm{clip}(\exp(\mathrm{FutureKL}_t), 1-\epsilon_f, 1+\epsilon_f)
|
||||
$$
|
||||
|
||||
最终把原本的 advantage 改成 future-aware advantage:
|
||||
|
||||
$$
|
||||
\tilde{A}_{i,t} = \hat{A}_{i} \cdot f_{i,t}
|
||||
$$
|
||||
|
||||
## 参数
|
||||
|
||||
| 参数 | 类型 | 默认值 | 说明 |
|
||||
|---------------------------|---------|--------|----------------------------------------------------------------------------------------------------------------|
|
||||
| `--loss_type` | `str` | `grpo` | 设置为`fipo` 启用 FIPO loss |
|
||||
| `--delta` | `float` | `None` | 启用后会同时用于 Future-KL 高 IS ratio token 过滤和主 loss 的 dual-clip 上限,应大于 `1 + epsilon_high`,对齐FIPO 32B训练脚本建议设置为 `10.0` |
|
||||
| `--fipo_decay_rate` | `float` | `32.0` | Future-KL 折扣半衰参数,实际折扣为`2 ** (-1 / fipo_decay_rate)` |
|
||||
| `--fipo_clip_range` | `float` | `0.2` | influence weight 裁剪范围;`0.2` 表示默认裁剪到 `[0.8, 1.2]` |
|
||||
| `--fipo_clip_high_only` | `bool` | `true` | 若为`true`,权重只裁剪到 `[1.0, 1.0 + fipo_clip_range]`,更偏向放大正 Future-KL |
|
||||
| `--fipo_safety_threshold` | `float` | `4.0` | 负 advantage 且 IS ratio 超过该阈值时,将 FIPO 权重限制到 `[0.8, 1.0]` 以避免过度惩罚 |
|
||||
|
||||
## 训练示例
|
||||
|
||||
[swift](https://github.com/modelscope/ms-swift/tree/main/examples/train/grpo/internal/fipo.sh)
|
||||
@@ -0,0 +1,64 @@
|
||||
# Group Sequence Policy Optimization
|
||||
|
||||
[Group Sequence Policy Optimization](https://arxiv.org/abs/2507.18071)中指出GRPO在计算重要性采样权重时,是在token级别进行操作的。然而,这种做法由于每个token仅采样一次,无法实现有效的分布校正,反而会在模型训练过程中引入高方差噪声,极易导致模型的梯度估计不稳定,最终造成模型训练的崩塌。因此,论文认为,优化目标的单位应该与奖励的单位保持一致。由于奖励通常是在序列级别(即完整生成的回复)给出的,因此更合理的做法是将 off-policy 校正和优化也提升到序列级别,而非 token 级别。以下是三种计算策略对比:
|
||||
|
||||
1. GRPO
|
||||
对每个 token 独立计算重要性采样比,具体公式为
|
||||
|
||||
$$
|
||||
w^{\mathrm{GRPO}}_{i,t} = \frac{\pi_\theta (y_{i, t} \mid x, y_{i, <t})}{\pi_{\theta_{\mathrm{old}}} (y_{i, t} \mid x, y_{i, <t})}
|
||||
$$
|
||||
|
||||
2. GSPO (Sequence-Level)
|
||||
|
||||
在序列级别上计算重要性采样比,具体公式为
|
||||
|
||||
$$
|
||||
w^{\mathrm{GSPO}}_{i} = \left[ \frac{\pi_\theta (y_i \mid x)}{\pi_{\theta_{\mathrm{old}}} (y_i \mid x)} \right]^{\frac{1}{|y_i|}}
|
||||
= \exp\left( \frac{1}{|y_i|} \sum_{t=1}^{|y_i|} \log \frac{\pi_\theta (y_{i, t} \mid x, y_{i, <t})}{\pi_{\theta_{\mathrm{old}}} (y_{i, t} \mid x, y_{i, <t})} \right)
|
||||
$$
|
||||
|
||||
3. GSPO-token
|
||||
GSPO-token 结合了序列级与 token 级的重要性采样思想
|
||||
|
||||
$$
|
||||
w_{i, t}^{\mathrm{GSPO-token}} = \mathrm{sg}\left[w_i^{\mathrm{GSPO}}\right] \cdot \frac{\pi_{\theta}(y_{i, t} \mid x, y_{i, < t})}{\mathrm{sg}\left[\pi_{\theta}(y_{i, t} \mid x, y_{i, < t})\right]}
|
||||
$$
|
||||
|
||||
其中,$(\mathrm{sg}[\cdot])$ 表示梯度截断(detach())。
|
||||
|
||||
> 注意:根据梯度推导(即论文中的公式(11)和(18)),当各 token 的 advantage 相同时,GSPO-token 与 GSPO 等价。当前的 GRPO 实现中,所有 token 的 advantage 实际上都是基于句子级 reward 并在 group 内进行归一化,因此在这种设置下,GSPO-token 和 GSPO 在理论上是等价的。不过,GSPO-token 为未来更细粒度(token 级别)的 advantage 提供了支持。
|
||||
|
||||
伪代码实现
|
||||
```python
|
||||
log_ratio = per_token_logps - old_per_token_logps
|
||||
# GRPO
|
||||
log_importance_weights = log_ratio
|
||||
|
||||
# GSPO (Sequence-Level)
|
||||
seq_weight = (log_ratio * mask).sum(-1) / mask.sum(-1)
|
||||
log_importance_weights = seq_weight.unsqueeze(-1) # (B,1)
|
||||
|
||||
# GSPO-token
|
||||
seq_weight = (log_ratio * mask).sum(-1) / mask.sum(-1)
|
||||
log_importance_weights = seq_weight.detach().unsqueeze(-1) + (per_token_logps - per_token_logps.detach())
|
||||
|
||||
importance_weights = torch.exp(log_importance_weights)
|
||||
```
|
||||
|
||||
我们可以在 GRPO 训练的基础上,通过参数 `--importance_sampling_level` 选择不同的算法:
|
||||
|
||||
- `importance_sampling_level token` (默认,GRPO 实现)
|
||||
- `importance_sampling_level sequence` (GSPO)
|
||||
- `importance_sampling_level sequence_token` (GSPO-token)
|
||||
|
||||
论文其他超参
|
||||
```bash
|
||||
--epsilon 3e-4 # from paper section 5.1
|
||||
--epsilon_high 4e-4 # from paper section 5.1
|
||||
--gradient_accumulation_steps 8
|
||||
--steps_per_generation 32 # from paper section 5.1 (each batch of rollout data is partitioned into four minibatches for gradient updates)
|
||||
--beta 0 # zero kl regularization https://github.com/volcengine/verl/pull/2775#issuecomment-3131807306
|
||||
```
|
||||
|
||||
训练可以参考该[脚本](https://github.com/modelscope/ms-swift/blob/main/examples/train/grpo/internal/gspo.sh)
|
||||
@@ -0,0 +1,77 @@
|
||||
# Rewards as Labels: Revisiting RLVR from a Classification Perspective
|
||||
|
||||
作者: [li2zhi](https://github.com/li2zhi)
|
||||
|
||||
[Rewards as Labels: Revisiting RLVR from a Classification Perspective](https://arxiv.org/abs/2602.05630) 针对GRPO提出把奖励视为标签,在group内分类而不是计算advantage,从而将策略优化问题转化为分类问题,以此解决GRPO Loss中存在的正样本**梯度错配**与负样本**梯度主导**问题。
|
||||
|
||||
## 背景与动机
|
||||
|
||||
GRPO目标函数
|
||||
|
||||
$$
|
||||
J_{\mathrm{GRPO}}(\theta)=\mathbb{E}_{q,o\sim\pi_{\mathrm{od}}(\cdot|q)}\left[\frac{1}{|o|}\sum_{t=1}^{|o|}\left(\min\left(\rho_tA_t,\mathrm{clip}(\rho_t,1-\epsilon,1+\epsilon)A_t\right)\right)\right]
|
||||
$$
|
||||
|
||||
其中$\rho_t=\frac{\pi_\theta(o_t|q)}{\pi_{\mathrm{old}}(o_t|q)}$为相对概率,$A_{t}$为优势函数,故梯度为:
|
||||
|
||||
$$
|
||||
\nabla_{\theta} J_{\mathrm{GRPO}} = \mathbb { E } \left[ \frac { 1 } { | o | } \sum _ { t = 1 } ^ { | o | } \mathbb { I } _ { \mathrm { clip } } \cdot A _ { t } e ^ { s _ { t } } \nabla _ { \theta } \log \pi _ { \theta } \left( o _ { t } | q \right) \right]
|
||||
$$
|
||||
|
||||
其中$s_t=\log\frac{\pi_\theta(o_t|q)}{\pi_{\mathrm{old}}(o_t|q)}$作为token的相对对数概率,$\mathbb { I } _ { \mathrm { clip } }$为指示函数
|
||||
|
||||
故 GRPO 对单 token 的梯度权重为:
|
||||
|
||||
$$
|
||||
|\mathcal{W}_{\mathrm{GRPO}}|=\left\{ \begin{array} {ll}\left|A\cdot e^s\right|, & \mathrm{if~}\mathbb{I}_{\mathrm{clip}}=1, \\ 0, & \text{otherwise.} \end{array}\right.
|
||||
$$
|
||||
|
||||

|
||||
|
||||
- 正样本的梯度错配(Gradient Misassignment):对正样本来说,随着相对概率$s$变小,梯度更新幅度反而越弱。这违背直觉,因为模型对“不太自信”的正确 token 本来就需要更大的更新幅度来强化,但更多的梯度权重却放到更“自信”的 token,没学好的 token 得不到足够的重视。
|
||||
|
||||
- 负样本的梯度主导(Gradient Domination):对负样本来说,随着相对概率$s$变小,梯度更新幅度呈指数级增加。这意味着,只要出现几个模型“盲目自信”的错误 token,它们产生的巨大梯度就会把同组内其他负样本的信号淹没。由于缺乏上限保护,模型在处理这些错误样本时可能会产生过大的参数更新,让训练过程变得不太可控。
|
||||
|
||||
为解决上述问题,Real提出将奖励直接视为标签然后进行组内的样本分类训练
|
||||
|
||||

|
||||
|
||||
分类的logits分值设计:
|
||||
|
||||
$$
|
||||
\bar{s}^k=\frac{1}{|o^k|}\sum_{t=1}^{|o^k|}\left(\log\frac{\pi_\theta(o_t^k\mid q)}{\pi_{\mathrm{old}}(o_t^k\mid q)}\right)
|
||||
$$
|
||||
|
||||
- $\bar{s}^k > 0$: 表示该样本在当前策略下生成的概率比旧策略整体更高,模型倾向于**增强**该样本。
|
||||
- $\bar{s}^k < 0$: 表示该样本在当前策略下生成的概率比旧策略整体更低,模型倾向于**抑制**该样本。
|
||||
|
||||
损失函数设计:
|
||||
|
||||
$$
|
||||
\mathcal{L}_{REAL}=\log\left(1+\sum_{\mathcal{O}_+}e^{-\bar{s}^i/\tau}\right)+\log\left(1+\sum_{\mathcal{O}_-}e^{\bar{s}^j/\tau}\right)
|
||||
$$
|
||||
|
||||
梯度特性:
|
||||
$$
|
||||
|\mathcal{W}_{\mathrm{REAL}}|=
|
||||
\begin{cases}
|
||||
\frac{1}{\tau}\frac{1}{1+C_{+}e^{\bar{s}^{k}/\tau}}, & r=1 \\
|
||||
\\
|
||||
\frac{1}{\tau}\frac{1}{1+C_{-}e^{-\bar{s}^{k}/\tau}}, & r=0 & & &
|
||||
\end{cases}
|
||||
$$
|
||||
|
||||
## 参数设置
|
||||
|
||||
| 参数 | 类型 | 默认值 | 说明 |
|
||||
|-------------------|---------|-------|-------------------|
|
||||
| `--loss_type` | `str` | - | 设置为 `real` |
|
||||
| `--real_tau` | `float` | `0.5` | 温度参数,控制决策边界锐度 |
|
||||
|
||||
训练脚本参考
|
||||
|
||||
[swift](https://github.com/modelscope/ms-swift/tree/main/examples/train/grpo/internal/real.sh)
|
||||
|
||||
## 注意事项
|
||||
|
||||
设置参数时,确保 per_device_train_batch_size 能够被 num_generations 整除,以此保证单个训练batch中能拿到完整的 group 进行分类。
|
||||
@@ -0,0 +1,87 @@
|
||||
# REINFORCE++: An Efficient RLHF Algorithm with Robustness to Both Prompt and Reward Models
|
||||
|
||||
[REINFORCE++ Baseline](https://arxiv.org/abs/2501.03262) 是 REINFORCE++ 算法的简化版本,适用于 outcome rewards(response-level 标量奖励)。它与 GRPO 类似,对每个prompt输入采样多条模型输出,并使用组内 baseline 来估计优势函数,主要区别在于标准化时使用的统计量不同。
|
||||
|
||||
|
||||
## 算法原理
|
||||
为便于理解,我们基于 GRPO(Group Relative Policy Optimization)算法进行对比说明。
|
||||
|
||||
GRPO 和 REINFORCE++ Baseline 都采用组内对比的方式来估计优势函数,主要区别在于:
|
||||
|
||||
### 区别1:标准化时使用的统计量不同
|
||||
|
||||
**GRPO (Group Relative Policy Optimization)**
|
||||
|
||||
对每个 prompt 生成 $G$ 个响应样本,使用**组内所有样本的均值和标准差**进行标准化:
|
||||
|
||||
$$
|
||||
\hat{A}_{i} = \frac{R_i - \text{mean}(\{R_j\}_{j=1}^G)}{\text{std}(\{R_j\}_{j=1}^G)}
|
||||
$$
|
||||
|
||||
当设置 `scale_rewards='batch'` 时,使用**原始奖励的批次 std**:
|
||||
|
||||
$$
|
||||
\hat{A}_{i} = \frac{R_i - \text{mean}(\{R_j\}_{j=1}^G)}{\text{std}(\{R_j\}_{j=1}^{N})}
|
||||
$$
|
||||
|
||||
其中 $N$ 是批次中所有样本数。
|
||||
|
||||
**REINFORCE++ Baseline**
|
||||
|
||||
对每个 prompt 生成 $G$ 个响应样本,先减去组内均值,再使用**减去组内均值后的奖励**的标准差进行标准化:
|
||||
|
||||
$$
|
||||
\begin{align}
|
||||
\tilde{A}_{i} &= R_i - \text{mean}(\{R_j\}_{j=1}^G) \\
|
||||
\hat{A}_{i} &= \frac{\tilde{A}_{i}}{\text{std}(\{\tilde{A}_k\}_{k=1}^{N})}
|
||||
\end{align}
|
||||
$$
|
||||
|
||||
其中 $N$ 是批次中所有样本数。
|
||||
|
||||
**关键区别**:
|
||||
- **GRPO**:标准化时使用**原始奖励 $R$** 的标准差
|
||||
- **REINFORCE++**:标准化时使用**减去组内均值后的奖励 $\tilde{A}$** 的标准差
|
||||
|
||||
### 区别2: KL 散度正则化
|
||||
|
||||
与 RLOO 类似,REINFORCE++ Baseline 将 KL 散度整合到奖励项中:
|
||||
|
||||
$$
|
||||
R'_i = R_i - \beta \cdot \text{KL}(\pi_\theta || \pi_{\text{ref}})
|
||||
$$
|
||||
|
||||
其中 $\beta$ 是 KL 散度的权重系数(对应参数 `beta`),$\pi_{\text{ref}}$ 是参考策略。
|
||||
|
||||
## 参数设置
|
||||
|
||||
我们可以基于 `GRPOTrainer`,通过设置以下参数实现 REINFORCE++ Baseline 训练:
|
||||
|
||||
```bash
|
||||
--advantage_estimator reinforce_plus_plus
|
||||
--scale_rewards batch
|
||||
--kl_in_reward true
|
||||
```
|
||||
|
||||
训练可以参考该[脚本](https://github.com/modelscope/ms-swift/tree/main/examples/train/grpo/internal/reinforce_plus_plus.sh)
|
||||
|
||||
### 重要参数说明
|
||||
|
||||
- **`--advantage_estimator`**:选择优势函数估计方法
|
||||
- `grpo`(默认):标准化时使用原始奖励的标准差
|
||||
- `reinforce_plus_plus`:标准化时使用减去组内均值后的奖励的标准差
|
||||
|
||||
- **`--kl_in_reward`**:控制 KL 散度正则化项的处理位置
|
||||
- `false`:KL 散度作为损失函数的独立正则化项(GRPO 默认)
|
||||
- `true`:KL 散度直接从奖励中扣除(REINFORCE++ 原始实现)
|
||||
|
||||
- **`--scale_rewards`**:控制标准化方式
|
||||
- `group`(默认):组内标准化
|
||||
- `batch`:全局批次标准化(REINFORCE++原始实现)
|
||||
- `none`:不进行标准化
|
||||
|
||||
- **`--num_generations`**:每个 prompt 生成的样本数量 $G$
|
||||
|
||||
- **`--beta`**:KL 散度正则化系数 $\beta$
|
||||
|
||||
其他参数参考 [GRPO参数](../../Command-line-parameters.md#grpo参数)
|
||||
@@ -0,0 +1,92 @@
|
||||
# REINFORCE Leave-One-Out (RLOO)
|
||||
|
||||
[REINFORCE Leave-One-Out (RLOO)](https://arxiv.org/abs/2402.14740) 基于经典的 REINFORCE 策略梯度方法,通过留一法(Leave-One-Out)构造无偏的优势函数基线。
|
||||
|
||||
## 算法原理
|
||||
|
||||
为便于理解,我们基于 GRPO(Group Relative Policy Optimization)算法进行对比说明。
|
||||
|
||||
GRPO 和 RLOO 都采用组内对比的方式来估计优势函数,避免了全局基线估计带来的高方差问题。两者的核心区别主要体现在以下两个方面:
|
||||
|
||||
### 区别1:优势函数基线的构造方法
|
||||
|
||||
**1. GRPO (Group Relative Policy Optimization)**
|
||||
|
||||
GRPO 对每个 prompt 生成 $G$ 个响应样本,使用**组内所有样本的均值和标准差**进行标准化:
|
||||
|
||||
$$
|
||||
\hat{A}_{i} = \frac{R_i - \text{mean}(\{R_j\}_{j=1}^G)}{\text{std}(\{R_j\}_{j=1}^G)}
|
||||
$$
|
||||
|
||||
其中:
|
||||
- $R_i$ 是第 $i$ 个样本的奖励值
|
||||
- $\text{mean}(\{R_j\}_{j=1}^G) = \frac{1}{G}\sum_{j=1}^G R_j$ 是组内均值
|
||||
- $\text{std}(\{R_j\}_{j=1}^G)$ 是组内标准差
|
||||
|
||||
**2. RLOO (REINFORCE Leave-One-Out)**
|
||||
|
||||
RLOO 对每个 prompt 生成 $K$ 个响应样本,使用 **留一法(Leave-One-Out)** 构造基线,即第 $i$ 个样本的基线为除自己外的其他 $K-1$ 个样本的均值:
|
||||
|
||||
$$
|
||||
\hat{A}_{i} = R_i - \frac{1}{K-1}\sum_{j \neq i} R_j
|
||||
$$
|
||||
|
||||
这个公式可以等价地改写为:
|
||||
|
||||
$$
|
||||
\hat{A}_{i} = \frac{K}{K-1} \left(R_i - \bar{R}\right)
|
||||
$$
|
||||
|
||||
其中 $\bar{R} = \frac{1}{K}\sum_{j=1}^K R_j$ 是组内所有样本的均值。
|
||||
|
||||
> **说明**:这里使用 $K$ 对齐论文符号,与 GRPO 中的 $G$ 含义一致,均对应配置参数 `num_generations`
|
||||
|
||||
**为什么使用留一法?**
|
||||
|
||||
留一法的关键优势在于**无偏性**。对于第 $i$ 个样本,其奖励 $R_i$ 和基线 $\frac{1}{K-1}\sum_{j \neq i} R_j$ 是独立的,因此优势估计是无偏的。相比之下,如果使用包含自身的均值作为基线,会引入偏差。
|
||||
|
||||
### 区别2:KL 散度正则化项的处理方式
|
||||
|
||||
为防止策略偏离参考策略过远,两种算法都引入了 KL 散度正则化,但处理方式不同:
|
||||
|
||||
**GRPO**:将 KL 散度作为独立的正则化项添加到[损失函数](../GetStarted/GRPO.md#算法原理)中:
|
||||
|
||||
$$
|
||||
\mathcal{L}(\theta) = -\mathbb{E}\left[\hat{A}_i \log \pi_\theta(a_i|s_i)\right] + \beta \cdot \text{KL}(\pi_\theta || \pi_{\text{ref}})
|
||||
$$
|
||||
|
||||
**RLOO**:将 KL 散度直接整合到奖励项中,构造修正后的奖励:
|
||||
|
||||
$$
|
||||
R'_i = R_i - \beta \cdot \text{KL}(\pi_\theta || \pi_{\text{ref}})
|
||||
$$
|
||||
|
||||
其中 $\beta$ 是 KL 散度的权重系数(对应参数 `beta`),$\pi_{\text{ref}}$ 是参考策略(通常是 SFT 模型或初始策略)。
|
||||
|
||||
## 参数设置
|
||||
|
||||
我们可以基于 `GRPOTrainer`,通过设置以下参数实现 RLOO 训练:
|
||||
```bash
|
||||
# 基本 RLOO 配置
|
||||
--advantage_estimator rloo # 使用 RLOO 的留一法优势函数计算
|
||||
--kl_in_reward true # 将 KL 散度项整合到奖励中(RLOO 默认方式)
|
||||
```
|
||||
|
||||
训练可以参考该[脚本](https://github.com/modelscope/ms-swift/tree/main/examples/train/grpo/internal/rloo.sh)
|
||||
|
||||
### 重要参数说明
|
||||
|
||||
- **`--advantage_estimator`**:选择优势函数估计方法
|
||||
- `grpo`(默认):使用组内均值和标准差进行标准化
|
||||
- `rloo`:使用留一法(Leave-One-Out)构造基线
|
||||
|
||||
- **`--kl_in_reward`**:控制 KL 散度正则化项的处理位置
|
||||
- `false`:KL 散度作为损失函数的独立正则化项(GRPO 方式)
|
||||
- `true`:KL 散度直接从奖励中扣除,构造修正后的奖励(RLOO 方式)
|
||||
|
||||
- **`--num_generations`**:每个 prompt 生成的样本数量 $K$
|
||||
|
||||
- **`--beta`**:KL 散度正则化系数 $\beta$
|
||||
- 控制策略更新的保守程度
|
||||
|
||||
其他参数与 [GRPO参数](../../Command-line-parameters.md#grpo参数)一致
|
||||
@@ -0,0 +1,91 @@
|
||||
# Soft Adaptive Policy Optimization (SAPO)
|
||||
|
||||
[Soft Adaptive Policy Optimization (SAPO)](https://arxiv.org/abs/2511.20347) 针对 GRPO 中硬裁剪(hard clipping)带来的问题,提出了一种基于温度控制的软门控(soft gate)机制,用于平滑地衰减离策略更新,同时保留有用的学习信号。
|
||||
|
||||
## 背景与动机
|
||||
|
||||
在强化学习训练 LLM 时,GRPO 通过计算 token 级别的重要性采样比(Importance Sampling Ratio)来处理 off-policy 训练:
|
||||
|
||||
$$
|
||||
r_t = \frac{\pi_\theta(y_t|x, y_{<t})}{\pi_{\theta_{\mathrm{old}}}(y_t|x, y_{<t})}
|
||||
$$
|
||||
|
||||
然而,token 级别的重要性采样比往往表现出高方差,这一现象在以下情况下可能更严重:
|
||||
- **长文本生成**
|
||||
- **MoE 模型的路由异质性**:采样时的 old-policy 模型与训练模型可能使用不同的专家路由,导致 logps 差异显著放大
|
||||
|
||||
为此,GRPO 通过硬裁剪来限制策略更新的幅度:
|
||||
|
||||
$$
|
||||
L^{\mathrm{GRPO}} = -\min\left( r_t \cdot A, \mathrm{clip}(r_t, 1-\epsilon, 1+\epsilon) \cdot A \right)
|
||||
$$
|
||||
|
||||
**硬裁剪的困境**:硬裁剪难以在稳定性和学习效率之间取得平衡——裁剪范围过严格会限制有效样本的数量,而过宽松则会引入离策略样本的噪声梯度,导致训练不稳定。
|
||||
|
||||
## SAPO 方法
|
||||
|
||||
SAPO 使用温度控制的 sigmoid 软门控函数替代硬裁剪,实现平滑的梯度衰减。
|
||||
|
||||
### 软门控函数
|
||||
|
||||
SAPO 的核心是使用 sigmoid 函数对重要性采样比进行软门控:
|
||||
|
||||
对于正向优势($A > 0$),使用正向门控:
|
||||
|
||||
$$
|
||||
g^{+}_t = \sigma\left( \tau_{\mathrm{pos}} \cdot (r_t - 1) \right) \cdot \frac{4}{\tau_{\mathrm{pos}}}
|
||||
$$
|
||||
|
||||
对于负向优势($A < 0$),使用负向门控:
|
||||
|
||||
$$
|
||||
g^{-}_t = \sigma\left( \tau_{\mathrm{neg}} \cdot (r_t - 1) \right) \cdot \frac{4}{\tau_{\mathrm{neg}}}
|
||||
$$
|
||||
|
||||
其中:
|
||||
- $\sigma(\cdot)$ 是 sigmoid 函数
|
||||
- $\tau_{\mathrm{pos}}$ 和 $\tau_{\mathrm{neg}}$ 是温度参数,控制门控函数的斜率
|
||||
- $r_t$ 是重要性采样比
|
||||
|
||||
### SAPO 损失函数
|
||||
|
||||
$$
|
||||
L^{\mathrm{SAPO}} = -g_t \cdot A
|
||||
$$
|
||||
|
||||
其中 $g_t = g^{+}_t$ 当 $A > 0$,$g_t = g^{-}_t$ 当 $A < 0$。
|
||||
|
||||
### 温度参数
|
||||
|
||||
温度参数 $\tau$ 控制软门控函数的衰减速率,数值越大,衰减越快。
|
||||
|
||||

|
||||
|
||||
论文指出正向优势会提升采样token的logit,并降低所有未采样token的logit;负向优势相反,提高许多未采样token的logit,可能会扩散到大量无关token上,带来一定的不稳定性。所以论文推荐设置温度 $\tau_\text{neg} > \tau_\text{pos}$,来使负向奖励的token梯度衰减更快,提升训练的稳定性和性能。
|
||||
|
||||
论文默认推荐 $\tau_{\mathrm{pos}} = 1.0$,$\tau_{\mathrm{neg}} = 1.05$。
|
||||
|
||||
## 参数设置
|
||||
|
||||
| 参数 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `--loss_type` | `str` | - | 设置为 `sapo` |
|
||||
| `--tau_pos` | `float` | `1.0` | 正向优势的温度参数,控制门控斜率 |
|
||||
| `--tau_neg` | `float` | `1.05` | 负向优势的温度参数,控制门控斜率 |
|
||||
|
||||
```bash
|
||||
swift rlhf \
|
||||
--rlhf_type grpo \
|
||||
--loss_type sapo \
|
||||
--tau_pos 1.0 \
|
||||
--tau_neg 1.05 \
|
||||
# ... 其他参数
|
||||
```
|
||||
|
||||
训练脚本参考
|
||||
|
||||
- [swift](https://github.com/modelscope/ms-swift/blob/main/examples/train/grpo/internal/sapo.sh)
|
||||
- [megatron swift](https://github.com/modelscope/ms-swift/blob/main/examples/megatron/grpo/sapo.sh)
|
||||
|
||||
> SAPO 的软门控机制仅在 off-policy 训练下生效。
|
||||
> SAPO 中的重要性采样粒度为 token 级别(即 importance_sampling_level 默认设置为 token),与 GSPO 冲突。
|
||||
@@ -0,0 +1,95 @@
|
||||
# DeepEyes: Incentivizing "Thinking with Images" via Reinforcement Learning
|
||||
|
||||
## 原理介绍
|
||||
|
||||
[DeepEyes论文](https://arxiv.org/abs/2505.14362) 提出了一种利用强化学习使模型具备“think with images”(以图辅助思考)能力的方法。该方法通过端到端的强化学习,模型能力自发涌现,无需额外的 SFT(监督微调)过程。模型内置图像定位能力,能够主动调用“图像放大工具”:在推理过程中,模型会自动选取图片中的具体区域进行放大和裁剪,将处理后的区域信息进行进一步推理,实现视觉与文本的链式推理。
|
||||
|
||||

|
||||
|
||||
## 最佳实践
|
||||
|
||||
**数据集下载与注册**
|
||||
|
||||
下载 DeepEyes 官方训练数据集到本地
|
||||
```bash
|
||||
# modelscope
|
||||
modelscope download --dataset Lixiang/ChenShawn-DeepEyes-Datasets-47k
|
||||
|
||||
# huggingface
|
||||
huggingface-cli download ChenShawn/DeepEyes-Datasets-47k --repo-type=dataset
|
||||
```
|
||||
|
||||
数据集内有三个parquet文件,`swift/dataset/data/dataset_info.json` 文件中分别进行注册,将数据集中的 `prompt` 列重命名为 `messages`
|
||||
|
||||
```json
|
||||
{
|
||||
"ms_dataset_id": "path/to/data_0.1.2_visual_toolbox_v2.parquet",
|
||||
"columns": {
|
||||
"prompt": "messages"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ms_dataset_id": "path/to/data/data_thinklite_reasoning_acc.parquet",
|
||||
"columns": {
|
||||
"prompt": "messages"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ms_dataset_id": "path/to/data/data_v0.8_visual_toolbox_v2.parquet",
|
||||
"columns": {
|
||||
"prompt": "messages"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
在本地注册论文中所用到的奖励函数和工具调用逻辑,实现可以参考[DeepEyes实现示例](https://github.com/modelscope/ms-swift/tree/main/examples/train/grpo/plugin/deepeyes/deepeyes_plugin.py)
|
||||
|
||||
**部署验证模型**
|
||||
|
||||
Deepeyes 的奖励函数依赖生成式奖励模型对模型生成结果与标准答案进行对比评估,为了加速这一环节,推荐对模型进行部署。
|
||||
|
||||
假设使用 Qwen2.5-VL-72B-Instruct 模型进行评估,参考以下部署命令
|
||||
|
||||
```bash
|
||||
# 4*80G
|
||||
CUDA_VISIBLE_DEVICES=0,1,2,3 \
|
||||
swift deploy \
|
||||
--model Qwen/Qwen2.5-VL-72B-Instruct \
|
||||
--infer_backend vllm \
|
||||
--vllm_tensor_parallel_size 4 \
|
||||
```
|
||||
|
||||
在 plugin 文件中,使用OpenAI接口进行调用,参考[奖励模型文档](../DeveloperGuide/reward_model.md#外部部署)
|
||||
|
||||
|
||||
训练参考该[脚本](https://github.com/modelscope/ms-swift/tree/main/examples/train/grpo/plugin/deepeyes/deepeyes.sh)
|
||||
|
||||
## 实现细节
|
||||
|
||||
[DeepEyes实现示例](https://github.com/modelscope/ms-swift/tree/main/examples/train/grpo/plugin/deepeyes/deepeyes_plugin.py)参考[官方实现](https://github.com/Visual-Agent/DeepEyes/blob/main/verl/utils/reward_score/vl_agent.py) 给出了 DeepEyes 训练插件的样例代码,涵盖了奖励函数与多轮交互调用的相关逻辑。
|
||||
|
||||
**数据集数据**如下
|
||||
|
||||
| 数据集文件名 | data_source | 对应评分函数 | 工具调用 |
|
||||
|------------------------------------------|-----------------------|----------------------------------|------------------|
|
||||
| data_v0.8_visual_toolbox_v2.parquet | chart | vl_agent.compute_score | True (image_zoom_in_tool) |
|
||||
| data_0.1.2_visual_toolbox_v2.parquet | vstar | vl_agent.compute_score | True (image_zoom_in_tool) |
|
||||
| data_thinklite_reasoning_acc.parquet | thinklite_eureka | vl_agent.compute_score_math | False |
|
||||
|
||||
|
||||
**注意**:多模态大模型在处理图像输入时,可能会对图像进行预处理(例如受 max_pixels 参数限制的裁剪或缩放等操作)。当调用图像放大工具 image_zoom_in_tool 时,模型会根据输入图像输出裁剪后的 bbox。因此,在调用图像放大工具时,需要确保输入的是经过预处理后的图像。示例代码展示了 Qwen2.5-VL 系列模型的实现方式:
|
||||
|
||||
```python
|
||||
from qwen_vl_utils import fetch_image
|
||||
# 这里的images尚未经过图像处理
|
||||
infer_request.images
|
||||
# 通过加载为PIL.Image格式,进行裁剪(使用环境变量MAX_PIXELS时的处理)
|
||||
img = fetch_image({'image': load_pil_image(infer_request.images[0])})
|
||||
```
|
||||
|
||||
**工具奖励**
|
||||
|
||||
论文中指出当最终答案正确,且轨迹至少使用一个工具时给予工具奖励。为了避免模型生成的工具调用是无效的,我们通过图像数量而不是`<tool_call>` 等token进行判断。
|
||||
```python
|
||||
tool_reward = 1.0 if num_image > 1 and acc_reward > 0.5 else 0.0
|
||||
```
|
||||
@@ -0,0 +1,30 @@
|
||||
# Beyond the 80/20 Rule: High-Entropy Minority Tokens Drive Effective Reinforcement Learning for LLM Reasoning
|
||||
|
||||
[论文](https://arxiv.org/abs/2506.01939)发现在以 RLVR等方法训练大型语言模型推理能力时,驱动学习进步的关键在于一小部分高熵“少数 token”,而并非大多数信息熵低的 token。
|
||||
|
||||
论文指出,在模型推理的 token 分布中,只有极少数信息熵较高的 token 起到了主导作用。这些 token 往往出现在推理和决策路径分歧最大的关键节点(如 "wait"、"since" 等),决定了模型能否习得复杂推理任务。而大多数熵低的 token 对模型推理能力的提升作用有限。论文提出只对高熵 token 计算策略梯度、舍弃低熵 token 的梯度。
|
||||
|
||||
|
||||
token 熵公式如下
|
||||
|
||||
$
|
||||
H_t := -∑_{j=1}^{V} p_{t,j} \log p_{t,j}, \qquad where (p_{t,1}, ···, p_{t,V}) = \mathbf{p}_t = π_θ(\cdot | \mathbf{q}, \mathbf{o}_{<t}) = \text{Softmax}(\frac{\mathbf{z}_t}{T})
|
||||
$
|
||||
|
||||
其中
|
||||
- $\pi_\theta$:参数为 $\theta$ 的模型
|
||||
- $\mathbf{q}$:输入查询(input query)。
|
||||
- $\mathbf{o}_{<t} = (o_1, o_2, \cdots, o_{t-1})$:时间步 $t$ 之前已生成的 token 序列。
|
||||
- $V$:词表大小(vocabulary size)。
|
||||
- $\mathbf{z}_t \in \mathbb{R}^V$:时间步 $t$ 的 pre-softmax 逻辑值(logits)。
|
||||
- $\mathbf{p}_t \in \mathbb{R}^V$:模型对词表的概率分布。
|
||||
- $T \in \mathbb{R}$:解码温度(decoding temperature),控制分布的平滑程度。
|
||||
|
||||
熵的计算对象:$H_t$ 是 token 生成分布 $\mathbf{p}_t$ 的熵,用于衡量训练策略 $\pi_\theta$ 在给定上下文 $(\mathbf{q}, \mathbf{o}_{<t})$ 下的不确定性。
|
||||
|
||||
> "Token entropy" $H_t$ 始终指向位置 $t$ 的生成分布 $\mathbf{p}_t$ 的不确定性,而非 token $o_t$ 本身的属性。即$H_t$ 是位置 $t$ 对应分布 $\mathbf{p}_t$ 的熵,与采样得到的 token $o_t$ 无关。
|
||||
|
||||
|
||||
在实践中,我们可以在 GRPO 训练中通过参数 `top_entropy_quantile` 控制训练范围。论文实验设置该参数为 0.2,即每次仅对处于熵分布前 20% 的 token 进行训练优化。
|
||||
|
||||
同时使用参数`log_entropy`,可以记录训练过程中的熵值变化,参考[文档](../GetStarted/GRPO.md#logged-metrics)
|
||||
@@ -0,0 +1,19 @@
|
||||
Advanced Research
|
||||
===============
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
entropy_mask.md
|
||||
CISPO.md
|
||||
DAPO.md
|
||||
deepeyes.md
|
||||
FIPO.md
|
||||
GSPO.md
|
||||
CHORD.md
|
||||
RLOO.md
|
||||
REINFORCEPP.md
|
||||
REAL.md
|
||||
router_replay.md
|
||||
SAPO.md
|
||||
training_inference_mismatch.md
|
||||
treepo.md
|
||||