Janus-Pro-7B模型精调教程:使用CSDN技术博客作为训练数据
Janus-Pro-7B模型精调教程使用CSDN技术博客作为训练数据想不想拥有一个能像资深技术专家一样写出高质量CSDN风格博客的AI助手或者你希望打造一个更懂你所在技术领域的专属模型今天我们就来动手实现这个想法。Janus-Pro-7B是一个能力均衡的通用大语言模型但要让它在特定领域——比如撰写CSDN风格的技术博客——表现得更专业、更地道就需要进行“精调”。这就像给一位聪明的通才进行专项培训让他成为某个领域的专家。本教程将手把手带你完成整个过程从CSDN上获取高质量的技术博客作为“教材”到选择高效的训练方法再到在云端GPU上启动训练最后评估我们“培训”出的模型效果。整个过程清晰、可操作即使你之前没有完整的模型精调经验也能跟着一步步做下来。1. 精调准备理解我们要做什么在开始写代码和跑训练之前我们先花几分钟把整个流程和核心概念理清楚这样后面操作起来会更顺畅。简单来说我们要做三件大事准备“教材”从CSDN爬取一批高质量的技术博客文章清洗整理成模型能理解的格式。进行“培训”在星图这样的云GPU平台上使用LoRA等高效方法对Janus-Pro-7B模型进行微调让它学习CSDN博客的写作风格和知识。检验“成果”把训练好的模型用起来看看它写的技术博客是不是有内味了。这里涉及一个关键概念领域适应性微调。大模型在训练时看了互联网上各种各样的文本所以知识面很广但可能对某个垂直领域如特定格式的技术文档不够精通。微调就是用小规模的、高质量的领域数据对它进行“再教育”让它在这个特定任务上表现更出色。我们选择CSDN技术博客作为数据源是因为它内容质量相对较高、格式规范且覆盖了丰富的技术话题是训练技术写作模型的理想语料。2. 第一步获取与清洗CSDN博客数据数据是精调的基石。这一步的目标是获得一份干净、格式统一的文本数据。我们不鼓励大规模、侵犯版权的爬取这里以获取少量公开文章用于学习研究为例。2.1 数据爬取获取原始文章我们可以使用Python的requests和BeautifulSoup库来抓取公开的博客文章。以下是一个简单的示例用于获取单篇文章的标题和正文内容。import requests from bs4 import BeautifulSoup import time def fetch_csdn_article(url): 抓取指定CSDN博客文章链接的标题和正文。 headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 } try: response requests.get(url, headersheaders, timeout10) response.raise_for_status() response.encoding utf-8 soup BeautifulSoup(response.text, html.parser) # 提取标题 - 根据实际页面结构调整选择器 title_tag soup.find(h1, class_title-article) or soup.find(h1, idarticleContentId) title title_tag.get_text().strip() if title_tag else 未知标题 # 提取正文 - CSDN正文通常放在article_content类或id的div中 content_div soup.find(div, idarticle_content) or soup.find(div, class_blog-content-box) if content_div: # 清理正文中的脚本、样式等无关标签 for tag in content_div([script, style, aside, nav, footer]): tag.decompose() content content_div.get_text(separator\n, stripTrue) else: content return {title: title, content: content, url: url} except Exception as e: print(f抓取 {url} 失败: {e}) return None # 示例抓取一篇文章 article_url https://blog.csdn.net/xxx/article/details/xxx # 请替换为真实链接 article_data fetch_csdn_article(article_url) if article_data: print(f标题: {article_data[title][:50]}...) print(f内容长度: {len(article_data[content])} 字符)重要提示遵守规则在实际操作前请务必查看CSDN的robots.txt文件尊重网站的爬虫协议。本代码仅用于技术学习。控制频率在循环抓取多个链接时务必使用time.sleep()添加延迟避免对服务器造成压力。链接来源你可以通过CSDN的专题页面、搜索接口或已有的文章列表来获取一批你感兴趣的技术博客链接。2.2 数据清洗与格式化准备训练集爬取下来的原始文本包含很多噪声比如广告、代码块的特殊标记、无关的推荐链接等。我们需要清洗它们并转换成模型训练需要的格式。通常大语言模型的微调数据格式是一个jsonl文件每行是一个JSON对象包含一个text字段里面是一段完整的文本。对于我们的任务我们可以将一篇博客的标题和正文组合成一段连贯的文字。import json import re def clean_and_format_article(article_dict): 清洗单篇文章并格式化为训练文本。 title article_dict.get(title, ) content article_dict.get(content, ) # 1. 基础清洗去除多余的空格、换行 content re.sub(r\n\s*\n, \n\n, content) # 合并多个空行 content content.strip() # 2. 移除常见的无关文本根据实际情况调整 patterns_to_remove [ r版权声明本文为博主原创文章.*, r转载请注明出处。, r更多精彩内容.*, # 可以添加更多你观察到的无关模式 ] for pattern in patterns_to_remove: content re.sub(pattern, , content) # 3. 组合成训练文本格式 # 一种简单的格式用标题作为开头后接正文 formatted_text f标题{title}\n\n{content} # 或者如果你想模拟对话/指令格式可以这样适用于Chat模型 # formatted_text f|user|\n请写一篇关于{title}的技术博客。\n|assistant|\n{content} return formatted_text def save_to_jsonl(articles_list, output_pathcsdn_articles.jsonl): 将文章列表保存为jsonl格式。 with open(output_path, w, encodingutf-8) as f: for article in articles_list: if article and article.get(content): formatted_text clean_and_format_article(article) # 确保文本长度适中过滤掉太短的内容 if len(formatted_text) 500: json_record {text: formatted_text} f.write(json.dumps(json_record, ensure_asciiFalse) \n) print(f数据已保存至 {output_path}共 {len(articles_list)} 条记录。) # 假设 all_articles 是你爬取到的文章字典列表 # save_to_jsonl(all_articles, my_csdn_dataset.jsonl)清洗后你就得到了一个干净的my_csdn_dataset.jsonl文件这是后续训练的关键输入。3. 第二步选择高效微调方法与环境配置全参数微调一个大模型需要巨大的计算资源。对于我们这种领域适应任务通常采用参数高效的微调方法LoRA或QLoRA是当前的主流选择。LoRA在模型的注意力层等关键部分注入可训练的低秩矩阵只训练这些新增的小参数冻结原始大模型参数。极大减少了训练参数量和显存消耗。QLoRA在LoRA的基础上更进一步将原始大模型权重量化为4-bit并在训练时通过一种特殊技术保持精度。它能让你在消费级显卡上微调大模型。如何选择如果你的GPU显存足够例如24GB以上使用LoRA速度更快。如果你的显存紧张例如只有16GB或更少QLoRA是让你能跑起来的关键。本教程以QLoRA为例因为它适用性更广。3.1 在星图平台创建训练环境星图平台提供了预置环境的GPU实例非常适合快速启动模型训练。访问平台登录星图平台。选择实例在计算资源部分选择一台带有足够显存的GPU实例。对于微调7B模型建议选择显存16GB或以上的GPU如RTX 4090, V100等。选择镜像在镜像市场选择预装了PyTorch、CUDA、常用深度学习库如Transformers, PEFT, Accelerate的镜像这能省去大量环境配置时间。启动实例配置好之后启动你的GPU实例并通过Web Terminal或SSH连接到它。连接到实例后你就像在用一台高性能的Linux服务器。3.2 安装必要的Python库在实例的终端中安装我们训练所需的特定库。# 进入你的工作目录 cd ~ # 创建并激活一个Python虚拟环境推荐 python -m venv janus_finetune_env source janus_finetune_env/bin/activate # 安装核心库 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 # 根据你的CUDA版本调整 pip install transformers datasets accelerate peft bitsandbytes scipy sentencepiece # 安装训练脚本依赖例如Hugging Face的trl库如果使用SFT Trainer pip install trl4. 第三步编写与启动训练脚本一切就绪现在可以编写训练脚本了。我们将使用Hugging Face的transformers和peft库。4.1 准备训练脚本创建一个名为train_janus_lora.py的Python文件。以下是脚本的核心内容import os from datasets import load_dataset from transformers import ( AutoModelForCausalLM, AutoTokenizer, TrainingArguments, BitsAndBytesConfig, pipeline ) from peft import LoraConfig, get_peft_model, TaskType, prepare_model_for_kbit_training from trl import SFTTrainer import torch # 1. 加载模型和分词器 model_name 模型作者/Janus-Pro-7B # 请替换为实际的Hugging Face模型ID bnb_config BitsAndBytesConfig( load_in_4bitTrue, # 使用QLoRA4-bit量化 bnb_4bit_quant_typenf4, bnb_4bit_compute_dtypetorch.float16, bnb_4bit_use_double_quantTrue, ) print(正在加载模型和分词器...) model AutoModelForCausalLM.from_pretrained( model_name, quantization_configbnb_config, device_mapauto, # 自动将模型层分配到可用的GPU/CPU上 trust_remote_codeTrue # 如果模型需要自定义代码 ) tokenizer AutoTokenizer.from_pretrained(model_name, trust_remote_codeTrue) # 设置pad_token如果不存在 if tokenizer.pad_token is None: tokenizer.pad_token tokenizer.eos_token # 2. 为QLoRA准备模型 model prepare_model_for_kbit_training(model) # 3. 配置LoRA参数 lora_config LoraConfig( r8, # LoRA的秩影响参数量和能力通常8-32 lora_alpha32, # Alpha参数通常设为r的2-4倍 target_modules[q_proj, v_proj, k_proj, o_proj, gate_proj, up_proj, down_proj], # 针对LLaMA架构 lora_dropout0.1, biasnone, task_typeTaskType.CAUSAL_LM, ) model get_peft_model(model, lora_config) model.print_trainable_parameters() # 打印可训练参数量应该只占原模型很小一部分 # 4. 加载并预处理数据集 print(正在加载数据集...) dataset load_dataset(json, data_files./my_csdn_dataset.jsonl, splittrain) # 划分训练集和验证集例如90%训练10%验证 split_dataset dataset.train_test_split(test_size0.1, seed42) train_dataset split_dataset[train] eval_dataset split_dataset[test] def format_dataset(example): 将数据集的text字段编码为模型输入。这里我们使用简单的文本补全格式。 # 假设我们的jsonl中每个样本的键是text text example[text] # 对文本进行分词并添加结束符 encoded tokenizer(text, truncationTrue, max_length512) # 设置最大长度 # 对于因果语言模型标签就是输入本身用于计算下一个词的损失 encoded[labels] encoded[input_ids].copy() return encoded tokenized_train_dataset train_dataset.map(format_dataset, remove_columnstrain_dataset.column_names) tokenized_eval_dataset eval_dataset.map(format_dataset, remove_columnseval_dataset.column_names) # 5. 配置训练参数 training_args TrainingArguments( output_dir./janus-csdn-lora, # 输出目录 num_train_epochs3, # 训练轮数根据数据量调整 per_device_train_batch_size4, # 每个设备的训练批次大小 per_device_eval_batch_size4, gradient_accumulation_steps4, # 梯度累积步数模拟更大批次 warmup_steps100, # 学习率预热步数 logging_steps50, # 每多少步打印一次日志 eval_strategysteps, # 评估策略 eval_steps200, # 每多少步评估一次 save_steps500, # 每多少步保存一次检查点 learning_rate2e-4, # 学习率LoRA通常可以设大一点 fp16True, # 使用混合精度训练如果GPU支持 optimpaged_adamw_8bit, # 使用8-bit优化器节省显存 report_tonone, # 不报告给任何平台可设为tensorboard save_total_limit2, # 只保留最近2个检查点 load_best_model_at_endTrue, # 训练结束后加载最佳模型 ) # 6. 创建Trainer并开始训练 trainer SFTTrainer( modelmodel, argstraining_args, train_datasettokenized_train_dataset, eval_datasettokenized_eval_dataset, tokenizertokenizer, max_seq_length512, # 序列最大长度 ) print(开始训练...) trainer.train() print(训练完成) # 7. 保存微调后的模型仅LoRA权重 trainer.model.save_pretrained(./janus-csdn-lora-final) tokenizer.save_pretrained(./janus-csdn-lora-final) print(LoRA权重已保存至 ./janus-csdn-lora-final)4.2 运行训练脚本将你的my_csdn_dataset.jsonl数据文件上传到GPU实例与脚本放在同一目录。然后在终端中运行python train_janus_lora.py训练过程会持续一段时间具体取决于你的数据量、GPU性能和训练轮数。你可以在终端看到损失loss下降并在验证集上评估模型效果。5. 第四步模型部署与效果评估训练完成后你会得到保存的LoRA权重文件。接下来就是加载它并看看模型的表现。5.1 加载与合并模型进行推理你可以选择单独加载基础模型和LoRA权重也可以将它们合并成一个完整的模型文件以便部署。from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline from peft import PeftModel import torch # 加载基础模型和分词器 base_model_name 模型作者/Janus-Pro-7B lora_weights_path ./janus-csdn-lora-final print(加载基础模型...) base_model AutoModelForCausalLM.from_pretrained( base_model_name, torch_dtypetorch.float16, device_mapauto, trust_remote_codeTrue ) tokenizer AutoTokenizer.from_pretrained(base_model_name, trust_remote_codeTrue) print(加载LoRA权重并合并到基础模型...) model PeftModel.from_pretrained(base_model, lora_weights_path) # 如果你想将LoRA权重永久合并到基础模型中会增大文件但推理更快 model model.merge_and_unload() # 保存合并后的完整模型可选 merged_model_path ./janus-pro-7b-csdn-merged model.save_pretrained(merged_model_path) tokenizer.save_pretrained(merged_model_path) print(f合并模型已保存至 {merged_model_path})5.2 效果评估让模型写篇博客看看现在让我们用几个提示词来测试一下微调后的模型看看它是否学到了CSDN技术博客的风格。# 创建文本生成管道 pipe pipeline(text-generation, modelmodel, tokenizertokenizer, device0) # device0 表示使用第一个GPU # 测试提示词 test_prompts [ 请写一篇关于Python中异步编程asyncio入门教程的博客文章要求结构清晰包含代码示例。, 简述如何在Docker中部署一个Spring Boot应用并列出关键步骤。, 帮我生成一篇技术博客的开头主题是‘机器学习模型部署的常见陷阱与规避方法’。 ] for i, prompt in enumerate(test_prompts): print(f\n{*50}) print(f测试 {i1}: {prompt}) print(f{*50}) # 生成文本 result pipe( prompt, max_new_tokens500, # 生成的最大新token数 temperature0.7, # 创造性值越高越随机 do_sampleTrue, top_p0.9, repetition_penalty1.1 ) generated_text result[0][generated_text] print(generated_text) print(\n)评估要点风格一致性生成的文本是否具有CSDN博客常见的结构如引言、分点论述、代码块、总结内容专业性技术概念描述是否准确代码示例是否合理语言流畅度行文是否通顺符合中文技术文档的阅读习惯任务遵循性是否很好地理解和完成了提示词的要求你可以多尝试不同的提示词并与微调前的原始Janus-Pro-7B模型进行对比直观感受精调带来的变化。6. 总结与后续建议跟着走完这一趟你应该已经成功用CSDN博客数据为Janus-Pro-7B模型完成了一次领域精调。整个过程从数据获取、清洗到选择QLoRA这种高效的微调方法再到在星图GPU平台上实操训练最后评估效果算是一个比较完整的实践闭环。实际做下来数据质量真的是最关键的一环。爬取的文章如果本身质量高、格式规范模型学到的“文风”就更正。相反如果数据里噪音多模型可能也会学到一些不好的习惯。所以在数据清洗上多花点功夫非常值得。训练过程中那些超参数比如学习率、训练轮数都不是一成不变的。如果你的数据量很大可能不需要那么多轮如果发现模型一直学不好可能需要调整学习率或者检查一下数据格式。多跑几次看看日志里的损失曲线慢慢就有感觉了。现在你有了一个更擅长写技术博客的模型可以把它集成到你的笔记工具里当写作助手或者进一步用它来生成特定技术领域的初稿。这个思路也可以用到其他地方比如用产品手册数据微调一个客服模型用法律条文微调一个咨询模型。玩法很多关键是想清楚你想要模型在哪个细分领域变得更专业。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。