针对 Qwen3-Omni-30B-A3B-Instruct 模型,60K tokens 长上下文 Megatron SFT 训练场景。 基于 ms-swift 源码分析,所有参数引用均标注源码位置。
针对于我修改后的代码,可以这么统计每个样本的实际 token 长度:
bash展开代码IMAGE_MAX_TOKEN_NUM=5000 USE_AUDIO_IN_VIDEO=true VIDEO_MAX_PIXELS=307200 \
python scripts/count_token_lengths.py \
--model /mnt/cpfs/model/Qwen3-Omni-30B-A3B-Instruct \
--dataset /mnt/cpfs/datasets/ShortsTemplateEdits/anno_jianying_mp4_seed18_train.jsonl \
--num_samples 200 \
--dataset_num_proc 16
... --num_samples 500
... --num_samples 0
... --output_csv /tmp/lengths.csv
~/.claude/settings.json新建或覆盖为以下内容,并替换为自己的 API Key 和 Base URL:
json展开代码{
"env": {
"ANTHROPIC_API_KEY": "your-api-key-here",
"ANTHROPIC_BASE_URL": "https://example.com",
"ANTHROPIC_MODEL": "route/claude-haiku-4-5-20251001-thinking"
},
"model": "route/claude-haiku-4-5-20251001-thinking"
}
在训练之前可以使用swift export进行 token 缓存,使用这个指令:
展开代码IMAGE_MAX_TOKEN_NUM=5000 USE_AUDIO_IN_VIDEO=true VIDEO_MAX_PIXELS=307200 USE_AUDIO_IN_VIDEO=true \ swift export \ --model /mnt/cpfs/model/Qwen3-Omni-30B-A3B-Instruct \ --dataset /mnt/cpfs/datasets/ShortsTemplateEdits/anno_jianying_mp4_seed18_train.jsonl \ --split_dataset_ratio 0 \ --dataset_num_proc 72 \ --to_cached_dataset true \ --max_length 20000 --truncation_strategy left \ --output_dir /mnt/cpfs/datasets/ShortsTemplateEdits/pack_cached_cpfs/anno_jianying_mp4_seed18_train_len20k
truncation_strategy split 策略只允许用于预训练(pre-training),不允许用于 SFT
https://arxiv.org/pdf/2404.10830
ms-swift 如果不想抛弃过长样本,可以设置:
bash展开代码IMAGE_MAX_TOKEN_NUM=5000 # 图像/视频的最大 token 数量限制
USE_AUDIO_IN_VIDEO=true # 是否从视频中提取音频(默认 false)
VIDEO_MAX_PIXELS=307200 # 视频最大像素数(默认 896×896=802816)
说明:
IMAGE_MAX_TOKEN_NUM:控制图像/视频 token 的上限,影响显存占用USE_AUDIO_IN_VIDEO=true:启用后,视频和音频 token 会按 position_id 交错排列VIDEO_MAX_PIXELS=307200:约 560×548 分辨率,降低分辨率可减少显存占用bash展开代码#!/usr/bin/env python3
"""
断点续传文件到服务器
使用 paramiko 库实现 SFTP 断点续传
"""
import os
import sys
import paramiko
from tqdm import tqdm
def get_remote_file_size(sftp, remote_path):
"""获取远程文件大小"""
try:
return sftp.stat(remote_path).st_size
except FileNotFoundError:
return 0
def resume_upload(local_file, server, remote_path, username, password=None, key_file=None):
"""
断点续传文件到服务器
Args:
local_file: 本地文件路径
server: 服务器地址
remote_path: 远程文件路径
username: 用户名
password: 密码(可选)
key_file: SSH密钥文件(可选)
"""
# 获取本地文件大小
local_size = os.path.getsize(local_file)
print(f"本地文件大小: {local_size / (1024**3):.2f} GB")
# 连接服务器
print(f"连接到服务器 {server}...")
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
if key_file:
ssh.connect(server, username=username, key_filename=key_file)
elif password:
ssh.connect(server, username=username, password=password)
else:
# 尝试使用默认的 SSH 密钥或 SSH agent
ssh.connect(server, username=username)
sftp = ssh.open_sftp()
# 获取远程已传输的大小
remote_size = get_remote_file_size(sftp, remote_path)
print(f"远程文件大小: {remote_size / (1024**3):.2f} GB")
if remote_size >= local_size:
print("文件已完全传输!")
return
# 断点续传
print(f"从 {remote_size / (1024**3):.2f} GB 处继续传输...")
with open(local_file, 'rb') as local_fp:
# 跳到断点位置
local_fp.seek(remote_size)
# 以追加模式打开远程文件
with sftp.file(remote_path, 'ab') as remote_fp:
# 创建进度条
with tqdm(total=local_size, initial=remote_size,
unit='B', unit_scale=True, unit_divisor=1024,
desc="上传进度") as pbar:
# 分块上传
chunk_size = 1024 * 1024 # 1MB
while True:
chunk = local_fp.read(chunk_size)
if not chunk:
break
remote_fp.write(chunk)
pbar.update(len(chunk))
print("\n✓ 文件传输完成!")
# 验证文件大小
final_remote_size = get_remote_file_size(sftp, remote_path)
if final_remote_size == local_size:
print(f"✓ 验证成功: 远程文件大小 {final_remote_size} == 本地文件大小 {local_size}")
else:
print(f"✗ 警告: 远程文件大小 {final_remote_size} != 本地文件大小 {local_size}")
except Exception as e:
print(f"错误: {e}")
sys.exit(1)
finally:
sftp.close()
ssh.close()
if __name__ == "__main__":
# 配置参数
LOCAL_FILE = r"D:\process_mp4.zip"
SERVER = "74.48.179.187"
REMOTE_PATH = "/root/process_mp4.zip"
USERNAME = "root"
# 检查本地文件是否存在
if not os.path.exists(LOCAL_FILE):
print(f"错误: 本地文件不存在: {LOCAL_FILE}")
sys.exit(1)
print("=" * 60)
print("断点续传工具")
print("=" * 60)
print(f"本地文件: {LOCAL_FILE}")
print(f"服务器: {SERVER}")
print(f"远程路径: {REMOTE_PATH}")
print("=" * 60)
print("\n提示: 需要输入服务器密码(如果没有配置SSH密钥)")
# 提示输入密码(可选)
import getpass
password = getpass.getpass("请输入SSH密码(直接回车跳过,使用SSH密钥): ")
if not password:
password = None
# 执行断点续传
resume_upload(LOCAL_FILE, SERVER, REMOTE_PATH, USERNAME, password=password)
ms-swift swift export 出错样本会怎样
OSError: broken data stream when reading image file),会打出:There are errors in the dataset, the data will be deleted。--strict。根据论文内容,让我详细解释视频和音频是如何输入模型并转换为 token 的:
展开代码原始视频 → 视觉帧提取 + 音频提取 → 分别编码 → 时间对齐 → 输入 LLM