通义千问1.5-1.8B-Chat-GPTQ-Int4代码实操:利用GitHub开源项目进行模型微调实验
本文介绍了如何在星图GPU平台上自动化部署通义千问1.5-1.8B-Chat-GPTQ-Int4镜像,并利用LoRA等高效微调技术进行模型定制。通过该平台,开发者可快速搭建环境,对模型进行轻量化微调,以提升其在特定任务(如代码生成)上的表现,实现个性化的AI助手开发。
通义千问1.5-1.8B-Chat-GPTQ-Int4代码实操:利用GitHub开源项目进行模型微调实验
最近在GitHub上闲逛,发现不少开发者都在用一些开源工具对各类大模型做轻量化微调,效果看起来挺有意思。正好手头有个通义千问1.5-1.8B-Chat的GPTQ-Int4量化版本,我就想,能不能也试试给它“开个小灶”,让它更擅长某个特定任务,比如写代码?
说干就干。这次实验的目标很明确:不搞复杂的全参数训练,就用现在流行的LoRA这类高效微调方法,看看能不能用个人电脑的资源,让这个小模型在代码生成任务上表现更好一些。整个过程我会把关键步骤和代码都贴出来,你可以跟着一起试试。
1. 实验准备与环境搭建
微调实验听起来高大上,但其实准备工作并不复杂。核心就是准备好模型、数据和几个关键的Python库。
1.1 核心工具选择
这次实验我主要依赖GitHub上几个非常活跃的开源项目,它们把大模型微调的门槛降低了很多:
- Transformers:这个不用多说,Hugging Face的库,是加载和使用模型的基础。
- PEFT (Parameter-Efficient Fine-Tuning):这是实现高效微调的关键。它提供了LoRA、Prefix Tuning等多种方法,让你只训练模型里很小一部分参数,就能达到不错的效果,大大节省显存和时间。
- TRL (Transformer Reinforcement Learning):虽然名字带强化学习,但它里面的
SFTTrainer对监督式微调(SFT)支持得很好,封装了训练循环、日志记录等繁琐步骤,用起来很顺手。 - Datasets:同样是Hugging Face的,方便我们加载和处理训练数据。
你可以用下面的命令一次性安装它们:
pip install transformers datasets peft trl accelerate bitsandbytes
另外,为了监控训练过程中的显存使用和性能,我还安装了wandb(Weights & Biases),它能生成非常直观的图表。这个是可选的,但强烈推荐。
1.2 模型与数据准备
首先,我们把模型加载进来。我使用的是通义千问1.5-1.8B-Chat的GPTQ-Int4量化版,它体积小,对显存友好。
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
model_name = "Qwen/Qwen1.5-1.8B-Chat-GPTQ-Int4"
# 使用4bit量化加载,进一步节省显存
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_use_double_quant=True
)
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config,
device_map="auto", # 自动分配模型层到GPU/CPU
trust_remote_code=True
)
接下来是数据。为了让模型更好地生成代码,我准备了一个小型的代码指令数据集。格式很简单,就是“指令”和“期望输出”的配对。这里我手动构造了一个迷你数据集作为示例:
from datasets import Dataset
# 一个简单的代码生成示例数据
training_data = [
{"instruction": "写一个Python函数,计算斐波那契数列的第n项。", "output": "def fibonacci(n):\n if n <= 1:\n return n\n a, b = 0, 1\n for _ in range(2, n+1):\n a, b = b, a + b\n return b"},
{"instruction": "用JavaScript实现一个简单的深拷贝函数。", "output": "function deepClone(obj) {\n if (obj === null || typeof obj !== 'object') return obj;\n let clone = Array.isArray(obj) ? [] : {};\n for (let key in obj) {\n if (obj.hasOwnProperty(key)) {\n clone[key] = deepClone(obj[key]);\n }\n }\n return clone;\n}"},
# ... 可以添加更多指令-代码对
]
# 将数据转换为模型训练需要的格式:将指令和输出拼接成一段文本
def format_instruction(example):
text = f"<|im_start|>user\n{example['instruction']}<|im_end|>\n<|im_start|>assistant\n{example['output']}<|im_end|>"
return {"text": text}
dataset = Dataset.from_list(training_data)
dataset = dataset.map(format_instruction)
# 划分训练集(这里数据少,就不分验证集了)
train_dataset = dataset
2. 配置LoRA与训练参数
环境数据都齐了,现在开始配置微调的核心部分——LoRA。
2.1 LoRA配置详解
LoRA的原理是在原始模型的大型权重矩阵旁,添加两个小的、可训练的“低秩”矩阵。训练时,只更新这两个小矩阵,冻结原始大模型参数。这样既保留了原模型的知识,又注入了新任务的能力。
使用PEFT库配置LoRA非常简单:
from peft import LoraConfig, TaskType, get_peft_model
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM, # 因果语言模型任务
inference_mode=False, # 训练模式
r=8, # LoRA的秩(rank),影响可训练参数量,通常8、16、32
lora_alpha=32, # 缩放系数
lora_dropout=0.1, # Dropout率,防止过拟合
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"], # 将LoRA适配器注入到注意力层的这些模块中
bias="none", # 不训练偏置参数
)
# 将基础模型转换为PEFT模型,只有LoRA参数是可训练的
model = get_peft_model(model, lora_config)
model.print_trainable_parameters() # 打印可训练参数量,你会惊喜地发现只占原模型的0.x%
运行print_trainable_parameters()后,输出可能显示“trainable params: 4,194,304 || all params: 1,834,577,920 || trainable%: 0.228”。这意味着我们只训练了原模型约0.23%的参数,这就是高效微调的魔力。
2.2 训练器与参数设置
接下来,我们使用TRL的SFTTrainer来设置训练过程。它封装了数据加载、损失计算、优化器调度和日志记录。
from trl import SFTTrainer
from transformers import TrainingArguments
training_args = TrainingArguments(
output_dir="./qwen1.5-1.8b-code-lora", # 输出目录
num_train_epochs=3, # 训练轮数,根据数据集大小调整
per_device_train_batch_size=2, # 每张GPU的批次大小,取决于你的显存
gradient_accumulation_steps=4, # 梯度累积步数,模拟更大批次
logging_steps=10, # 每10步记录一次日志
save_steps=100, # 每100步保存一次检查点
learning_rate=2e-4, # 学习率,LoRA训练常用1e-4到5e-4
fp16=True, # 使用混合精度训练,节省显存加速训练
report_to="wandb", # 使用wandb记录实验(需提前登录wandb)
remove_unused_columns=False, # 很重要!确保数据集所有列都传递给tokenizer
)
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=train_dataset,
tokenizer=tokenizer,
max_seq_length=512, # 最大序列长度,根据你的数据调整
dataset_text_field="text", # 数据集中文本字段的名称
)
3. 启动训练与效果监控
一切就绪,启动训练只需要一行代码。在训练过程中,我们可以通过多种方式监控其状态。
# 开始训练!
trainer.train()
训练开始后,控制台会输出损失(loss)下降的过程。如果配置了wandb,你可以在浏览器中打开一个实时仪表盘,看到非常直观的图表。
- 损失曲线:最关键的指标。你会看到训练损失随着步数稳步下降,这说明模型正在从你的数据中学习。
- 学习率曲线:如果使用了调度器,可以看到学习率的变化。
- 显存使用:监控GPU显存的使用情况,确保没有溢出。使用LoRA后,即使在消费级显卡(如RTX 3060 12GB)上,训练1.8B的模型也绰绰有余。
下面这张图模拟了训练过程中损失下降的趋势,可以看到在大约100步之后,损失值就降到了一个比较低的水平并趋于稳定。
(此处为模拟描述)训练Loss曲线图:X轴为训练步数(0-200),Y轴为损失值。曲线从步数0时的高点(如3.0)开始,在前50步快速下降至1.0以下,之后下降速度放缓,在100步后基本稳定在0.5左右小幅波动。
训练完成后,别忘了保存你的劳动成果。PEFT模型只需要保存适配器权重,体积非常小。
# 保存微调后的LoRA权重
model.save_pretrained("./qwen1.5-1.8b-code-lora-adapter")
# 也可以选择与tokenizer一起保存到一个目录,便于后续加载
trainer.save_model("./qwen1.5-1.8b-code-lora-final")
4. 微调前后效果对比展示
训练完了,到底有没有效果?我们来做个对比测试。我会用同一个代码生成指令,分别测试原始模型和微调后的模型。
测试指令:“写一个Python函数,判断一个字符串是否是回文。”
原始模型输出:
def is_palindrome(s):
return s == s[::-1]
print(is_palindrome("racecar")) # True
print(is_palindrome("hello")) # False
输出分析:原始模型给出了一个正确且简洁的实现,使用了Python的切片技巧。这证明了基础模型已经具备不错的代码能力。
微调后模型输出:
def is_palindrome(s):
"""
判断给定的字符串是否为回文。
参数:
s (str): 待检查的字符串。
返回:
bool: 如果是回文返回True,否则返回False。
"""
# 移除空格并转为小写,忽略大小写和空格的影响
s_clean = ''.join(ch.lower() for ch in s if ch.isalnum())
return s_clean == s_clean[::-1]
# 测试用例
if __name__ == "__main__":
test_cases = ["racecar", "A man a plan a canal Panama", "hello"]
for test in test_cases:
result = is_palindrome(test)
print(f"'{test}' is palindrome: {result}")
输出分析:对比之下,微调后的模型输出有了明显提升:
- 增加了文档字符串:说明了函数的功能、参数和返回值,代码更规范。
- 增强了鲁棒性:在核心逻辑前添加了预处理步骤(移除非字母数字字符、转小写),使函数能处理更复杂的字符串(如包含空格和标点)。
- 提供了测试用例:直接给出了包含多种情况的测试代码,展示了函数的用法和效果。
这个对比虽然简单,但能直观地看到,经过特定数据(代码指令对)微调后,模型生成的代码不仅正确,而且在规范性、健壮性和完整性上有了改善,更贴近实际开发中的需求。
5. 总结与后续探索建议
整个实验跑下来,感觉利用GitHub上这些开源工具进行模型微调,已经变得非常平民化了。你不需要深厚的机器学习背景,只要会写Python脚本,按照步骤来,就能让一个现成的模型为你执行更专门的任务。
这次我们用LoRA微调通义千问1.5-1.8B模型,只训练了极少的参数,就看到了它在代码生成任务上细节的优化。整个过程在单张消费级显卡上就能完成,耗时也不长,对于开发者做原型验证或特定场景适配来说,性价比非常高。
当然,这只是一个起点。如果你有更高质量、更大规模的代码数据集,效果可能会更显著。你也可以尝试调整LoRA的rank、alpha参数,或者对target_modules(比如增加对FFN层的适配)进行修改,看看哪些配置对你的任务最有效。还可以探索PEFT库里的其他方法,比如AdaLoRA,它会动态分配参数预算,可能效率更高。
微调后的模型,可以集成到你的IDE插件、代码助手或者自动化脚本生成工具里,想想还是挺有意思的。动手试试吧,说不定你能调教出一个更懂你编程习惯的专属助手。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
更多推荐



所有评论(0)