ChatGLM-6B微调记录

文章详细讲解了GLM-130B和ChatGLM-6B的架构,以及如何通过LoRA和PEFT技术进行模型微调,展示了ChatGLM-6B在低精度量化下的应用

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

GLM-130B和ChatGLM-6B

对于三类主要预训练框架:

  • autoregressive(无条件生成),GPT的训练目标是从左到右的文本生成
  • autoencoding(语言理解,比如BERT、ALBERT、RoBERTa、DeBERTa),encoder-decoder(有条件生成)。其训练目标是对文本进行随机掩码,然后预测被掩码的词
  • 基于encoder-decoder的T5,编码器中的注意力是双向的,解码器中的注意力是单向的,可同时应⽤于⾃然语⾔理解任务和⽣成任务,但T5为了达到和RoBERTa和DeBERTa相似的性能,往往需要更多的参数量。T5的训练目标是接受一段文本,从左到右生成另一段文本

为了统一,GLM在结构和训练目标上兼容三种预训练模型。在结构上,通过attention mask实现同时存在单向注意力和双向注意力:
fig1
当attention mask是全1矩阵的时候,这时的注意力是双向的,当attention mask是三角矩阵时,比如上图,注意力就变成单向。因此,GLM可以在只使⽤Transformer编码器的情况下,⾃定义attention mask来兼容三种模型结构。具体回顾 LLM中的微调演变与LLM架构类型-LLM的架构分类

训练时,GLM采用自回归空格填充任务,用于兼容三种模型的训练目标,先采样输入文本中部分片段,将其替换为[MASK] token,然后预测[MASK]所对应的文本片段,与掩码语⾔模型不同的是,预测的过程是自回归方式:
fig2

  • 当被mask的片段长度为1,等价于BERT(掩码语言建模),当全部文本都被mask,等价于GPT(无条件语言生成),当将文本1和文本2拼接在一起,然后将文本2整体mask后,等价于T5(条件语言生成)。

GLM有两个交替优化的训练目标:

  • 文档级别的生成:从文档中随机采样一个文本片段进行掩码,片段的长度为文档长度的50%-100%;
  • 句子级别的生成:从文档中随机掩码若干文本片段,每个文本片段必须为完整的句子,被掩码的词数量为整个文档长度的15%;

GLM-130B是拥有1300亿参数的中英双语模型,在96块A100上训练了60天。ChatGLM-6B基于GLM架构,具有62亿参数,无量化的情况下占用显存13G,INT8量化后支持在单张11G显存的2080Ti上推理,INT4量化后只需6G显存进行推理,7G显存做P-Tuning v2微调。ChatGLM-6B以GLM-130B为基座,加入code预训练,并进行SFT和RLHF,支持中文问答。


关于量化
INT8量化是一种将深度学习模型中的权重和激活值从32位浮点数(FP32)减少到8位整数(INT8)的技术,这可以减少计算资源需求,降低能耗,量化通常包括以下步骤:

  • 选择量化范围:确定权重和激活的最小值和最大值;
  • 量化映射:根据范围将32位浮点数映射为8位整数;
  • 反量化:将8位整数转回浮点数用于计算。

ChatGLM-6B直接部署

首先获取项目:

$ git clone https://github.com/THUDM/ChatGLM-6B
$ cd ChatGLM-6B

注意环境配置:torch版本不低于1.10,transformers为4.27.1,下载模型文件:

$ git clone https://huggingface.co/THUDM/chatglm-6b

直接新建my_demo.py:

from transformers import AutoTokenizer, AutoModel
tokenizer = AutoTokenizer.from_pretrained("/data/temp/my-alpaca-lora/chatglm-6b", trust_remote_code=True)
model = AutoModel.from_pretrained("/data/temp/my-alpaca-lora/chatglm-6b", trust_remote_code=True).half().cuda()
model = model.eval()
response, history = model.chat(tokenizer, "你好", history=[])
print("response: ", response)
print("history: ", history)
response, history = model.chat(tokenizer, "如何提高弹跳", history=history)
print("response: ", response)
print("history: ", history)

生成的答案为(同时打印了历史信息):
fig3
也可以交互式问答,注意修改cli_demo.py中的模型路径:

$ python cli_demo.py

程序会在命令行中进行交互式的对话,在命令行中输入指示并回车即可生成回复,输入 clear 可以清空对话历史(history),输入 stop 终止程序。

也可以利用gradio可视化界面,注意修改web_demo.py中的模型路径:

from transformers import AutoModel, AutoTokenizer
import gradio as gr
import mdtex2html

tokenizer = AutoTokenizer.from_pretrained("/data/temp/my-alpaca-lora/chatglm-6b", trust_remote_code=True)
model = AutoModel.from_pretrained("/data/temp/my-alpaca-lora/chatglm-6b", trust_remote_code=True).half().cuda()
model = model.eval()

运行web_demo.py即可:
fig4

默认情况下,模型以 FP16 精度加载,运行模型需要大概 13GB 显存。

基于PEFT的LoRA微调ChatGLM-6B

官方基于P-Tuning v2微调,此处我们使用非官方项目ChatGLM-Tuning基于LoRA微调:

$ git clone https://github.com/mymusise/ChatGLM-Tuning
$ cd ChatGLM-Tuning

首先新建data_process.sh进行数据处理:

python cover_alpaca2jsonl.py \
    --data_path data/alpaca_data.json \
    --save_path data/alpaca_data.jsonl \

alpaca_data.json包含用于微调Alpaca模型的52k指令数据(回顾 LLaMA-7B微调记录)。data_process.sh用于将这52k数据处理为ChatGLM-6B的格式。

对于alpaca_data.json,包含 instruction,input,output,格式为:

[
    {
        "instruction": "Give three tips for staying healthy.",
        "input": "",
        "output": "1.Eat a balanced diet and make sure to include plenty of fruits and vegetables. \n2. Exercise regularly to keep your body active and strong. \n3. Get enough sleep and maintain a consistent sleep schedule."
    },
    ...
    {
        "instruction": "Edit the following sentence (highlight changes in bold)",
        "input": "We use computers for gaming and entertainment",
        "output": "We use computers for gaming, entertainment, and work."
    }
]

处理后的alpaca_data.jsonl包含context,target,格式为:

{"context": "Instruction: Give three tips for staying healthy.\nAnswer: ", "target": "1.Eat a balanced diet and make sure to include plenty of fruits and vegetables. \n2. Exercise regularly to keep your body active and strong. \n3. Get enough sleep and maintain a consistent sleep schedule."}
{"context": "Instruction: Edit the following sentence (highlight changes in bold)\nInput: We use computers for gaming and entertainment\nAnswer: ", "target": "We use computers for gaming, entertainment, and work."}

可以看到这个格式正好符合前面所提到的GLM的训练目标。

下一步,新建token.sh将数据token化,首先修改tokenize_dataset_rows.py中, 函数read_jsonl内的模型路径:

model_name = "/data/temp/my-alpaca-lora/chatglm-6b"

token.sh为:

python tokenize_dataset_rows.py \
    --jsonl_path data/alpaca_data.jsonl \
    --save_path data/alpaca \
    --max_seq_length 200 \
    --skip_overlength False \

然后新建finetune.sh执行微调,注意修改finetune.py中的模型路径:

tokenizer = AutoTokenizer.from_pretrained("/data/temp/my-alpaca-lora/chatglm-6b", trust_remote_code=True)

def main():
	...
    # init model
    model = AutoModel.from_pretrained(
        "/data/temp/my-alpaca-lora/chatglm-6b", load_in_8bit=True, trust_remote_code=True, device_map="auto"
    )

finetune.sh为:

python finetune.py \
    --dataset_path data/alpaca \
    --lora_rank 8 \
    --per_device_train_batch_size 6 \
    --gradient_accumulation_steps 1 \
    --max_steps 52000 \
    --save_steps 1000 \
    --save_total_limit 2 \
    --learning_rate 1e-4 \
    --fp16 \
    --remove_unused_columns false \
    --logging_steps 50 \
    --output_dir output \

额外说明,在finetune.py,通过get_peft_model将模型封装为带有LoRA分支的模型:

model = AutoModel.from_pretrained(
        "/data/temp/my-alpaca-lora/chatglm-6b", load_in_8bit=True, trust_remote_code=True, device_map="auto")
...
# setup peft
peft_config = LoraConfig(
        task_type=TaskType.CAUSAL_LM,
        inference_mode=False,
        r=finetune_args.lora_rank,
        lora_alpha=32,
        lora_dropout=0.1)
model = get_peft_model(model, peft_config)

其余训练内容都可以不变,这样就能进行LoRA优化。

微调后,通过以下方式加载模型:

from peft import PeftModel

model = AutoModel.from_pretrained("/data/temp/my-alpaca-lora/chatglm-6b", trust_remote_code=True, load_in_8bit=True, device_map='auto')

model = PeftModel.from_pretrained(model, "./output/")
### ChatGLM-6B 模型下载与使用教程 #### 下载方式 可以从 Hugging Face 平台获取 ChatGLM-6B 模型,这是一个较为便捷的方法。Hugging Face 提供了一个友好的界面以及 API 支持来帮助开发者快速访问预训练模型及其权重文件[^1]。 以下是通过 Hugging Face 下载该模型的具体方法: ```bash from transformers import AutoTokenizer, AutoModel tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True) model = AutoModel.from_pretrained("THUDM/chatglm-6b", trust_remote_code=True).half().cuda() ``` 上述代码片段展示了如何利用 `transformers` 库加载 tokenizer 和模型实例。注意,在实际运行过程中需要确保网络环境能够正常连接到 Hugging Face 的存储仓库,并且具备足够的计算资源(如 GPU 显存)支持大模型的加载和推理操作。 #### 使用场景分析 ChatGLM-6B 是由清华大学开发的一个大型语言模型,在中文自然语言处理任务上表现优异。相比其他开源或者闭源的大规模多语种模型而言,它更专注于解决汉语相关的问题,因此特别适合用于构建针对中国市场的应用服务系统[^2]。 尽管如此,也需要注意一些潜在局限性:比如经过特定领域数据集上的进一步微调之后可能会削弱其跨主题泛化性能;另外如果调整不当还可能导致原有基础功能退化甚至丧失部分核心能力等问题存在风险。不过这些缺点并不妨碍我们将之部署于某些专用场合下执行诸如文档检索问答之类的子任务当中去实现良好效果。 #### 架构设计概述 为了更好地发挥出这个预训练成果的价值所在,可以考虑采用一种结合向量索引技术加传统搜索引擎机制共同作用的方式来搭建整个解决方案框架结构图如下所示(简化版描述): 1. **文本嵌入生成**: 将输入查询字符串转化为固定长度数值表示形式; 2. **相似度匹配筛选候选集合**: 利用预先建立起来的知识库内容对应的特征向量表进行高效查找定位最接近目标项位置关系; 3. **最终答案提取呈现给用户查看确认**. 这种混合模式既保留了深度学习带来的智能化优势同时也兼顾到了实时响应速度方面的要求从而达到更好的用户体验标准. ```python import torch from sentence_transformers import SentenceTransformer # 加载Sentence-BERT或其他合适的编码器作为句子/段落级别的embedding工具 encoder_model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2') def encode_text(texts): embeddings = encoder_model.encode(texts, convert_to_tensor=True) return embeddings query_embedding = encode_text(["你的问题"]) # 对单条或多条询问求取对应表达值 corpus_embeddings = ... # 假设已提前准备好全部资料记录各自的映射结果列表变量名定义为corpus_embeddings top_k_matches = util.semantic_search(query_embedding, corpus_embeddings)[0][:5] for match in top_k_matches: print(f"Score: {match['score']:.4f}, Text: {texts[match['corpus_id']]}\n") ``` 以上脚本示范了怎样借助第三方库完成基本的功能模块拼接组装流程演示说明。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值