2 张天数智芯 天垓 150(单卡 64GB,计 128GB HBM)可跑最大 Qwen3-8B、Qwen3-14B FP16 LoRA 模型 + 完整实操步骤 命令

一、硬件上限结论(分两种训练模式)

1)标准 DDP 数据并行(每卡完整加载全套模型,无模型分片,生产稳定首选)

  • 流畅无压力:Qwen3-6B、Qwen3-8B(batch 可开到 8~12,4096 上下文)
  • 极限勉强可跑:Qwen3-14B(必须极小 batch、短序列,极易 OOM,不推荐长期训练)
  • 完全跑不动:Qwen3-30B/32B 及以上(单卡 FP16 权重就 64GB+,加载即爆显存)

2)FSDP 模型分片并行(权重 / 梯度 / 优化器分散双卡,极限拉满)

2 张 150 128GB 总显存启用 FSDP ZeRO 分片,最大可稳定微调 Qwen3-14B FP16 LoRA;

Qwen3-30B 依然不足,至少 4 张天垓 150。

客户常规交付、长期稳定训练优先:Qwen3-8B;需要更大基座才用 FSDP 跑 Qwen3-14B。下面分两套完整流程:

方案 A:DDP 双卡训练 Qwen3-8B(推荐,稳定简单)

方案 B:FSDP 双卡极限训练 Qwen3-14B(最大模型,资源拉满)

前置统一环境(两套方案通用)

1 驱动与依赖安装

bash

# 安装CoreX+TorchAdapter

sudo bash corex-4.4.0-linux64.run --silent --driver --toolkit --torchadapter

# 全局环境变量写入/etc/profile

echo "export COREX_HOME=/opt/corex" >> /etc/profile

echo "export LD_LIBRARY_PATH=$COREX_HOME/lib:$LD_LIBRARY_PATH"

echo "export PATH=$COREX/bin:$PATH"

source /etc/profile

# AI依赖

pip install torch torchvision torchaudio torchadapter

pip install transformers peft datasets accelerate sentencepiece

2 双卡通信校验(必做,0&1 同组 INTE 直连)

bash

# 查看拓扑确认0、1直连

ixsmi topo -m

# AllReduce带宽测试

numactl --cpunodebind=0 --membind=0 mpirun -np 2 ./all_reduce_perf -b 8 -e 1G -g 0,1

验收:无 #wrong,平均带宽≥9GB/s

3 NVMe 高速盘目录(统一存储,挂载参数defaults,noatime,nodiratime,discard)

bash

mkdir -p /data01/models

mkdir -p /data01/train_data

mkdir -p /data01/lora_out

mkdir -p /data01/train_logs

数据集格式/data01/train_data/train.jsonl

json

{"instruction":"问题","input":"","output":"标准答案"}

方案 A:DDP 双卡稳定微调 Qwen3-8B(日常业务首选)

1 训练脚本 train_qwen8b_ddp.py

python

import os, torch

import torch.distributed as dist

from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer

from peft import LoraConfig, get_peft_model

from datasets import load_dataset

# 初始化ixCCL分布式

dist.init_process_group(backend="ixccl")

local_rank = int(os.environ["LOCAL_RANK"])

torch.cuda.set_device(local_rank)

device = torch.device("cuda", local_rank)

# 路径

MODEL_PATH = "/data01/models/Qwen3-8B-Instruct"

DATA = "/data01/train_data/train.jsonl"

SAVE = "/data01/lora_out/qwen8b_lora"

MAX_LEN = 4096

# LoRA配置

lora_cfg = LoraConfig(

    r=16, lora_alpha=32, lora_dropout=0.05, bias="none",

    target_modules=["q_proj","k_proj","v_proj","o_proj","gate_proj","up_proj","down_proj"],

    task_type="CAUSAL_LM"

)

# 加载FP16基座+梯度检查点省显存

tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, trust_remote_code=True)

tokenizer.pad_token = tokenizer.eos_token

model = AutoModelForCausalLM.from_pretrained(

    MODEL_PATH, torch_dtype=torch.float16, device_map={"":device},

    trust_remote_code=True, gradient_checkpointing=True

)

model = get_peft_model(model, lora_cfg)

model.print_trainable_parameters()

# 数据处理

def fmt(s):

    return f"<|im_start|>user\n{s['instruction']}<|im_end|>\n<|im_start|>assistant\n{s['output']}<|im_end|>"

def tok(sample):

    out = tokenizer(fmt(sample), truncation=True, max_length=MAX_LEN, padding="max_length")

    out["labels"] = out["input_ids"].copy()

    return out

ds = load_dataset("json", data_files=DATA, split="train")

train_ds = ds.map(tok, remove_columns=ds.column_names)

# DDP训练参数

train_args = TrainingArguments(

    output_dir=SAVE,

    per_device_train_batch_size=8,

    gradient_accumulation_steps=2,

    learning_rate=2e-4, num_train_epochs=3, fp16=True,

    logging_dir="/data01/train_logs/qwen8b", logging_steps=10,

    save_steps=100, save_total_limit=2, dataloader_num_workers=8,

    local_rank=local_rank, ddp_backend="ixccl", ddp_timeout=1800,

    report_to="none", overwrite_output_dir=True, ddp_find_unused_parameters=False

)

trainer = Trainer(model=model, args=train_args, train_dataset=train_ds, tokenizer=tokenizer)

trainer.train()

if local_rank == 0:

    trainer.save_model(SAVE)

dist.destroy_process_group()

print("Qwen3-8B LoRA训练完成")

2 启动脚本 run_8b_ddp.sh

bash

#!/bin/bash

export COREX_HOME=/opt/corex

export LD_LIBRARY_PATH=$COREX_HOME/lib:$LD_LIBRARY_PATH

export GOMP_CPU_AFFINITY="0-15,32-47"

export OMP_NUM_THREADS=16

# ixCCL通信优化

export IXCCL_TIMEOUT=1200

export IXCCL_ALLREDUCE_TIMEOUT=900

export IXCCL_SEND_BUFFER_SIZE=16777216

export IXCCL_RECV_BUFFER_SIZE=16777216

export IXCCL_TRANSPORT_PRIORITY=pcie

export IXCCL_CHUNK_SIZE=4194304

export IXCCL_P2P_ENABLE=0

numactl --cpunodebind=0 --membind=0 \

mpirun --allow-run-as-root -np 2 --bind-to none python3 train_qwen8b_ddp.py

运行命令:

bash

chmod +x run_8b_ddp.sh

./run_8b_ddp.sh

3 训练监控(新开终端)

bash

# 硬件负载

watch -n 2 ixsmi -d 2

# 磁盘IO

watch -n 2 iostat -x /dev/nvme0n1

# 报错实时抓取

dmesg -w | grep -E "iluvatar|ixccl|OOM"

# 查看loss

tail -f /data01/train_logs/qwen8b/runs/*

4 训练后合并权重 merge_8b.py

python

from transformers import AutoModelForCausalLM, AutoTokenizer

from peft import PeftModel

base="/data01/models/Qwen3-8B-Instruct"

lora="/data01/lora_out/qwen8b_lora"

merged="/data01/models/Qwen3-8B-MERGED"

tok=AutoTokenizer.from_pretrained(base,trust_remote_code=True)

m=AutoModelForCausalLM.from_pretrained(base,torch.float16,trust_remote_code=True)

m=PeftModel.from_pretrained(m,lora).merge_and_unload()

m.save_pretrained(merged)

tok.save_pretrained(merged)

print("合并完成")

5 推理验证 infer_8b.py

python

import torch

from transformers import AutoModelForCausalLM, AutoTokenizer

md="/data01/models/Qwen3-8B-MERGED"

tok=AutoTokenizer.from_pretrained(md,trust_remote_code=True)

m=AutoModelForCausalLM.from_pretrained(md,torch.float16,device_map="cuda",trust_remote_code=True)

def chat(q):

    p=f"<|im_start|>user\n{q}<|im_end|>\n<|im_start|>assistant\n"

    inp=tok(p,return_tensors="pt").to("cuda")

    out=m.generate(**inp,max_new_tokens=512,temperature=0.7)

    return tok.decode(out[0],skip_special_tokens=True)

print(chat("天垓150双卡训练规范"))

方案 BFSDP 双卡极限微调 Qwen3-14B2 卡能跑最大模型)

核心说明

FSDP 将模型权重、梯度、优化器分片到两张 64GB 卡,突破单卡 64GB 限制,是 2 张天垓 150 能承载最大 Qwen3 基座;

约束:per_device_train_batch_size=1,max_seq_len≤2048,开启全分片 + 梯度检查点。

1 FSDP 训练脚本 train_qwen14b_fsdp.py

import os, torch

import torch.distributed as dist

from torch.distributed.fsdp import FullyShardedDataParallel as FSDP, ShardingStrategy, MixedPrecision

from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer

from peft import LoraConfig, get_peft_model

from datasets import load_dataset

# 初始化ixCCL分布式

dist.init_process_group(backend="ixccl")

local_rank = int(os.environ["LOCAL_RANK"])

torch.cuda.set_device(local_rank)

device = torch.device("cuda", local_rank)

MODEL_PATH = "/data01/models/Qwen3-14B-Instruct"

DATA = "/data01/train_data/train.jsonl"

SAVE = "/data01/lora_out/qwen14b_lora"

MAX_LEN = 2048

lora_cfg = LoraConfig(

    r=8, lora_alpha=16, lora_dropout=0.05, bias="none",

    target_modules=["q_proj","k_proj","v_proj","o_proj"], task_type="CAUSAL_LM"

)

tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, trust_remote_code=True)

tokenizer.pad_token = tokenizer.eos_token

model = AutoModelForCausalLM.from_pretrained(

    MODEL_PATH, torch.float16, trust_remote_code=True, gradient_checkpointing=True

)

model = get_peft_model(model, lora_cfg)

# FSDP分片配置

fp16_policy = MixedPrecision(

    param_dtype=torch.float16, reduce_dtype=torch.float16, buffer_dtype=torch.float16

)

model = FSDP(

    model,

    sharding_strategy=ShardingStrategy.FULL_SHARD,

    mixed_precision=fp16_policy,

    device_id=device

)

# 数据处理(同上模板省略,复用前面fmt/tok函数)

def fmt(s):

    return f"<|im_start|>user\n{s['instruction']}<|im_end|>\n<|im_start|>assistant\n{s['output']}<|im_end|>"

def tok(sample):

    out = tokenizer(fmt(sample), truncation=True, max_length=MAX_LEN, padding="max_length")

    out["labels"] = out["input_ids"].copy()

    return out

ds = load_dataset("json", data_files=DATA, split="train")

train_ds = ds.map(tok, remove_columns=ds.column_names)

# 极小batch适配14B大模型

train_args = TrainingArguments(

    output_dir=SAVE,

    per_device_train_batch_size=1,

    gradient_accumulation_steps=4,

    learning_rate=1.5e-4, num_train_epochs=3, fp16=True,

    logging_dir="/data01/train_logs/qwen14b", logging_steps=5,

    save_steps=50, save_total_limit=1, dataloader_num_workers=4,

    local_rank=local_rank, ddp_backend="ixccl", ddp_timeout=2400,

    report_to="none", overwrite_output_dir=True

)

trainer = Trainer(model=model, args=train_args, train_dataset=train_ds, tokenizer=tokenizer)

trainer.train()

if local_rank == 0:

    trainer.save_model(SAVE)

dist.destroy_process_group()

print("Qwen3-14B FSDP LoRA训练完成")

2 FSDP 启动脚本 run_14b_fsdp.sh

bash

#!/bin/bash

export COREX_HOME=/opt/corex

export LD_LIBRARY_PATH=$COREX_HOME/lib:$LD_LIBRARY_PATH

export GOMP_CPU_AFFINITY="0-15,32-47"

export OMP_NUM_THREADS=16

export IXCCL_TIMEOUT=1800

export IXCCL_ALLREDUCE_TIMEOUT=1200

numactl --cpunodebind=0 --membind=0 \

mpirun --allow-run-as-root -np 2 --bind-to none python3 train_qwen14b_fsdp.py

执行:

bash

chmod +x run_14b_fsdp.sh

./run_14b_fsdp.sh

3 合并 & 推理(和 8B 流程一致,更换模型路径即可)

二、交付选型总结

  1. 常规 AI 微调、稳定长期训练:Qwen3-8B(DDP 双卡),速度快、显存充足、无 OOM 风险;
  2. 必须更大基座、硬件上限拉满:Qwen3-14B(FSDP 双卡分片),2 张天垓 150 硬件能承载的最大 Qwen3 模型;
  3. Qwen3-30B/32B:2 张 64GB HBM 无论 DDP/FSDP 均无法正常微调,需 4 卡及以上。

三、交付归档全套必备日志

  1. ixsmi 硬件识别、双卡拓扑截图
  2. all_reduce_perf 双卡通信带宽日志
  3. NVMe SSD 测速完整日志
  4. 训练终端完整输出、loss 收敛记录
  5. 训练全程 ixsmi 硬件监控截图
  6. LoRA 适配器权重 + 合并后完整模型
  7. 推理问答效果样例

更多推荐