LLM模型开发教程(五)模型训练基础
训练模型
📌 前置学习内容
-
✅ 熟悉 Python 语言
→ 掌握基础语法、数据结构、函数与类等必知必会的知识。 -
✅ 熟练使用常用 Python 库
→ 包括Numpy(数值计算)、PyTorch(深度学习框架)、Matplotlib(数据可视化)。 -
✅ 熟悉深度学习基础知识
→ 理解神经网络结构、反向传播原理、损失函数作用等核心概念。
💡 学习建议:
在开始本章前,请确保具备以上三方面基础,以便高效掌握后续内容。
使用HuggingFace训练一个GPT2
了解HuggingFace
AI开发的三驾马车:模型库,数据集,工具库。
而HuggingFace就是具备这三者的一个大模型平台
AI界的GitHub
为什么大家喜欢 Hugging Face
✅ 核心优势
-
打破技术垄断,让 AI 普惠大众
→ 推动人工智能从封闭研究走向开放共享。 -
行业事实标准:连接学术与产业界的桥梁
→ 学术成果快速落地,产业需求反哺研究。 -
中立的开源平台,与众多 AI 巨头合作,资源丰富
→ 汇聚海量预训练模型、数据集和工具,生态成熟。
💡 总结:Hugging Face 是 AI 开源生态的核心枢纽,推动技术民主化。
HuggingFace Hub
- 有超过50万个预训练模型
- 超过10万的数据集
- 即搜即用即分享
Transformers 库:AI 模型调用的革命
🚀 核心价值
-
几行代码即可调用最顶尖的 AI 模型
→ 快速接入 BERT、GPT、T5 等 SOTA 模型,无需从零实现。 -
极大地降低了技术门槛
→ 让开发者和研究人员能专注于任务本身,而非模型构建细节。
💡 一句话总结:
Transformers 库 = 高性能 AI 模型的“即插即用”工具箱
玩转HuggingFace的3种方式
✅ 第一步:pipeline —— 零代码快速体验
- 使用
transformers库的pipeline功能,一行代码即可完成任务。 - 适合快速测试、原型开发和初学者入门。
✅ 第二步:手动加载大模型和分词器 —— 掌控全流程
- 手动加载模型(AutoModel)和分词器(AutoTokenizer),实现更精细控制。
- 适合需要自定义输入处理、推理优化或调试场景。
✅ 第三步:模型微调(Fine-tuning)—— 让模型适应你的任务
- 在预训练模型基础上,使用自有数据进行微调。
- 适用于特定领域任务(如医疗、金融、法律等)。
LLM训练过程

训练过程解读
✅ 第一阶段:预训练(Pre-training)
-
输入数据:
- 内部文本
- 书籍
- Wikipedia
- 网络爬取的海量文本(如 Common Crawl)
- ⭐ 特点:巨大的、未标注的文本数据
-
训练目标:
- 文本补全(Next Token Prediction)
→ 模型学习预测下一个词是什么。 - 少样本学习能力(In-context Learning)
→ 在提示中给出少量示例,模型能泛化推理。
- 文本补全(Next Token Prediction)
-
输出结果:
- 得到一个通用的语言理解模型(如 BERT、GPT、LLaMA 等)
- 掌握语法、常识、知识表示等基础能力
💡 类比:就像“人类通过阅读大量书籍来学习语言”。
✅ 第二阶段:微调训练(Fine-tuning)
-
输入数据:
- 标注数据集
- 例如:问答对、翻译句对、摘要文本、指令-响应对
- 数据量远小于预训练数据,但质量高
- 标注数据集
-
训练方式:
- 在预训练模型基础上,用特定任务的数据进行有监督训练
- 目标是让模型适应具体应用场景
-
常见任务:
- 分类(如情感分析)
- 总结(自动摘要)
- 翻译(多语言互译)
- 个人助手(对话系统)
💡 类比:就像“学生在掌握基础知识后,专门练习考试题”。
🎯 最终输出:多功能智能模型
经过两阶段训练后,LLM 可以:
- 理解复杂语义
- 生成自然语言
- 执行多种任务(无需重新训练)
- 支持零样本/少样本推理
🔍 关键技术点总结
| 阶段 | 技术重点 | 数据类型 | 训练目标 |
|---|---|---|---|
| 预训练 | 自监督学习、Transformer 架构 | 未标注文本 | 学习语言结构和世界知识 |
| 微调 | 有监督学习、参数更新 | 标注数据 | 适配特定任务 |
💡 小贴士(给新人)
✅ 预训练是“打基础”,微调是“练技能”
✅ 大部分开源 LLM 都是先预训练,再微调得到的
✅ Hugging Face 上的很多模型都支持直接微调(如 Trainer API)
📚 推荐学习路径
- 先用
pipeline快速体验 LLM 能力 - 学习如何加载模型和分词器
- 进阶到微调训练,打造自己的专用模型
大模型的工作原理
- 通过概率预测下一个值


掩码机制
- 输入内容时,本质是并行,并且全量识别的
- 掩码的作用是“强制因果”,即前一个字或者词是因,后一个未知被遮住的是果,这样就有从左往右的因果顺序往后推,而且不可逆
精确拆解
不是串行解码
❌ 没有「算完第 1 个再算第 2 个」
并行计算
✅ Attention 矩阵一次性算
施加因果约束
✅ 通过掩码:
- 禁止未来 → 现在的信息通路
- 保证预测只依赖过去
LLM核心原理
🧠 大语言模型(LLM)的核心工作机制
大语言模型的本质是基于上下文预测下一个词(token)的自回归生成模型。其训练与推理过程依赖于三个关键机制:
🔑 1. 输入与标签:滑动窗口设计
- 输入:一句话(如
"I love learning about AI") - 标签:这句话向后移一个 token,即去掉第一个 token,加上结束符
[E]输入: I love learning about AI标签: love learning about AI [E]
目的:让模型学会“根据前面的内容预测下一个词”。
💡 类比:就像拼图游戏——你看到前几块,猜下一块是什么。
🔁 2. 自回归(Autoregressive)生成机制
- 模型一次只生成一个 token。
- 将新生成的 token 接到原句尾部,作为下一步的输入。
- 重复此过程,逐步构建完整句子。
示例流程:
输入: “I”
→ 预测: “love”
→ 新输入: “I love”
→ 预测: “learning”
→ …
最终输出: “I love learning about AI”
✅ 特点:逐字生成,具备强上下文依赖性。
🛑 3. 掩码机制(Causal Masking)
- 在训练过程中,模型在预测第 i 个位置的 token 时,只能看到它之前的所有 token。
- 不能“偷看”未来内容,防止信息泄露。
实现方式:
- 使用注意力掩码(Attention Mask),屏蔽未来 token 的影响。
- 确保模型符合因果关系:过去 → 当前 → 未来
💡 这正是 Transformer 中 “causal self-attention” 的核心思想。
🔄 总结:LLM 工作流图解
[原始文本]
↓ (分词)
[Token序列]
↓ (滑动窗口构造)
[输入: I love …] → [标签: love … [E]]
↓ (自回归训练)
[模型学习:根据前面的词预测下一个词]
↓ (推理阶段)
[生成:I → love → learning → about → AI]
✅ 三大机制总结表
| 机制 | 作用 | 关键特征 |
|---|---|---|
| 输入-标签对 | 构造监督信号 | 标签 = 输入右移 + 结束符 |
| 自回归生成 | 实现文本生成 | 逐 token 生成,递归扩展 |
| 掩码机制 | 保证因果性 | 只能“看”前面的 token |
💡 经典比喻
LLM 就像一个“超级读者”
- 它读过海量书籍,学会了如何用语言表达思想;
- 当你给它一句话开头时,它就能像写文章一样,一步步续写下去。
✅ 掌握这三大原理,你就理解了所有主流 LLM(如 GPT、LLaMA、ChatGLM)的底层逻辑。
区分训练和推理两个阶段
1️⃣ 训练阶段(Training Phase)
目的
让模型学会语言规律、上下文依赖、预测下一个 token 的能力。
工作流程
-
输入数据
- 给定一大批文本 token 序列(训练集)。
- 每个 token 按序排列形成上下文窗口。
-
掩码机制(Causal Mask)
-
每个 token 只能看到它前面的 token(左侧),不能看到未来 token(右侧)。
-
例如:
序列: [The, cat, is, sleeping] 预测目标: ['cat', 'is', 'sleeping', <EOS>] -
模型预测 cat 时只能看到 The
-
预测 is 时看到 [The, cat]
-
预测 sleeping 时看到 [The, cat, is]
-
-
计算损失(Loss)
- 将模型预测的概率分布与真实 token 对比,计算交叉熵损失。
-
反向传播 & 更新参数
- 通过梯度下降算法调整模型参数(权重 W、偏置 b 等),让预测更准确。
批量 & 并行
一次训练通常用 batch 并行计算多个序列,提高效率。
✅ 特点:
- 需要真实答案(监督信号)
- 目标是优化模型参数
- 使用掩码保证因果约束
2️⃣ 推理阶段(Inference Phase)
目的
用训练好的模型生成文本或做预测,不再更新参数。
工作流
- 输入提示(Prompt)
- 给模型一段已有文本,要求预测接下来的 token。
- 因果预测
- 模型基于当前上下文预测下一个 token(概率分布)
- 取概率最高或采样生成新的 token
- 生成循环
- 新生成的 token 会加入上下文,再预测下一个 token
- 迭代直到生成结束(如达到最大长度或遇到 )
✅ 特点:
- 不使用真实答案,只是让模型“发挥”学到的能力
- 参数固定,没有梯度更新
- 可以用不同策略生成:贪心、采样、Top-k、Top-p(Nucleus Sampling)
✅ 训练 vs 推理 的核心区别
| 特性 | 训练阶段 | 推理阶段 |
|---|---|---|
| 目的 | 学习预测能力 | 使用模型生成/预测 |
| 参数更新 | 会更新(梯度下降) | 不更新,固定参数 |
| 输入 | 文本 + 正确答案 | 文本/提示 |
| 输出 | 用于计算损失 | 用于生成文本或预测结果 |
| 掩码机制 | 使模型只能看到前文 | 同样保持因果约束 |
| 批量处理 | 多序列并行训练 | 通常单序列生成,也可 batch |
💡 一句话总结:
训练阶段:模型在“练习”,看答案学习规律,不停调整自己。
推理阶段:模型在“考试/表演”,用学到的规律生成或预测,不再调整。
HuggingFace的角色
- 提供给你预选练好的模型
- 提供标准化工具,比如Tokenizer(分词),TranerAPI等等
使用HuggingFace训练的步骤
| 步骤 | 内容 |
|---|---|
| 1️⃣ | 准备数据集 |
| 2️⃣ | 分词并量化 token |
| 3️⃣ | 加载并配置模型 |
| 4️⃣ | 设置训练参数 |
| 5️⃣ | 实例化训练器(Trainer) |
| 6️⃣ | 开始训练与评估 |
第一步:准备数据集
- 收集并整理原始文本数据(如书籍、网页、Wiki 等)
- 数据应尽可能多样化,覆盖广泛领域
第二步:分词,为每个 token 分配唯一的 ID,并将其向量化
- 使用分词器(Tokenizer)将文本切分为 tokens
- 为每个 token 分配唯一 ID(词汇表索引)
- 将 token ID 转换为模型可处理的向量表示(嵌入向量)
💡 示例
"I love AI"` → `["I", "love", "AI"]` → `[101, 205, 345]` → 向量矩阵
第三步:加载并配置模型,可以从头训练或微调
- 加载预训练模型(如 BERT、GPT、LLaMA)
- 或从零构建模型结构(适合研究场景)
- 配置模型参数(如层数、隐藏维度等)
第四步:设置训练参数,如学习率、训练轮次……
- 设置优化器(如 AdamW)
- 配置学习率(Learning Rate)、批量大小(Batch Size)
- 设定训练轮数(Epochs)、评估频率等超参数
**第五步:实例化训练器 **
- 使用 Hugging Face 的
Trainer类封装整个训练流程 - 配置训练器所需组件:
- 模型(model)
- 训练数据集(train_dataset)
- 评估数据集(eval_dataset)
- 训练参数(TrainingArguments)
- 优化器和调度器(可选)
from transformers import Trainer, TrainingArguments
training_args = TrainingArguments(
output_dir="./results",
num_train_epochs=3,
per_device_train_batch_size=16,
evaluation_strategy="epoch",
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
)
✅ 优势:自动化处理梯度更新、日志记录、保存检查点等任务。
第六步:开始训练和评估
调用 trainer.train() 启动训练过程
自动执行前向传播、损失计算、反向传播、参数更新
在每个 epoch 结束时自动进行评估(若设置了 eval_dataset)
支持中断恢复、分布式训练、混合精度等高级功能
加载并训练一个GPT2
训练步骤:
| 步骤 | 内容 |
|---|---|
| 1️⃣ | 加载GPT2模型和分词器 |
| 2️⃣ | 加载训练数据,并将其切成指定长度的文本串 |
| 3️⃣ | 设置训练参数:训练轮次,批量大小,学习率 |
| 4️⃣ | 创建训练器,并进行训练 |
| 5️⃣ | 保存训练好的模型 |
| 6️⃣ | 加载训练好的模型(这是我自己训练的模型) |
| 7️⃣ | 给一段引导词,让它接续(即,实现文字接龙) |
| 8️⃣ | 想实现文字聊天还需要进行微调(后续) |
训练实操
环境配置要求
| 组件 | 版本 |
|---|---|
| conda | 25.5.1 |
| Python | 3.10.18 |
| torch | 2.2.2 (pytorch) |
安装依赖包:
# transformers:Hugging Face 的预训练模型库(GPT、BERT等)
pip install transformers==4.38.2
# accelerate:加速训练和推理,支持分布式训练、混合精度等
pip install accelerate==0.30.0
# peft:参数高效微调库(LoRA、QLoRA等),用少量参数微调大模型
pip install peft==0.17.0
完整训练DEMO
'''
Author: sunhailiang sunhailiang@ssish.com
Date: 2026-01-20 11:47:33
LastEditors: sunhailiang sunhailiang@ssish.com
LastEditTime: 2026-01-20 19:03:41
FilePath: /llm/hf_gpt2_training.py
Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AEfro
'''
# ========== 导入必要的库 ==========
# transformers:Hugging Face 的预训练模型库
# - AutoTokenizer:自动加载分词器(将文本转为数字ID)
# - AutoModelForCausalLM:自动加载因果语言模型(GPT-2 等,用于文本生成)
# - TrainingArguments:训练参数配置类(学习率、批量大小等)
# - Trainer:训练器类(封装训练流程)
# - DataCollatorForLanguageModeling:数据整理器(批量数据对齐和填充)
from transformers import AutoTokenizer, AutoModelForCausalLM,TrainingArguments,Trainer,DataCollatorForLanguageModeling
# peft:参数高效微调库(LoRA、QLoRA 等)
# - LoraConfig:LoRA 配置类(定义低秩适配器参数)
# - TaskType:任务类型枚举(CAUSAL_LM 表示因果语言建模)
# - get_peft_model:将 LoRA 应用到模型上
from peft import LoraConfig, TaskType,get_peft_model
# torch:PyTorch 深度学习框架(用于张量计算和 GPU 加速)
import torch
# datasets:Hugging Face 的数据集库(加载和处理数据)
from datasets import load_dataset
# ========== 第一步:加载预训练模型和分词器 ==========
# model_name:模型在 Hugging Face Hub 上的标识符
# - "uer/gpt2-chinese-cluecorpussmall":中文 GPT-2 小模型(适合快速训练)
model_name = "uer/gpt2-chinese-cluecorpussmall"
# tokenizer:分词器,将文本转换为模型可理解的数字序列(token IDs)
# - from_pretrained:从 Hugging Face Hub 下载并加载预训练的分词器
# - AutoTokenizer:自动选择合适的分词器(FastTokenizer 更快)
tokenizer = AutoTokenizer.from_pretrained(model_name)
# model:预训练的 GPT-2 模型(用于文本生成)
# - AutoModelForCausalLM:自动加载因果语言模型(GPT-2、GPT-3 等)
# - from_pretrained:从 Hugging Face Hub 下载并加载预训练模型
model = AutoModelForCausalLM.from_pretrained(model_name)
# ========== 第二步:配置 LoRA(低秩适配器)微调 ==========
# LoRA 原理:只训练少量参数(适配器),冻结原模型参数,大幅降低显存和计算量
# lora_config:LoRA 配置对象
lora_config = LoraConfig(
r=8, # rank:低秩矩阵的秩(越小参数越少,但可能影响效果,常用 4-16)
lora_alpha=32, # LoRA 缩放因子(通常设为 r 的 2-4 倍,控制适配器的影响强度)
target_modules=["c_attn", "c_proj", "mlp.c_fc", "mlp.c_proj"], # 目标模块(在这些层添加 LoRA)
# - "c_attn":注意力层的查询/键/值投影
# - "c_proj":注意力输出投影
# - "mlp.c_fc":前馈网络第一层
# - "mlp.c_proj":前馈网络输出层
lora_dropout=0.1, # LoRA 层的 dropout 率(防止过拟合,0.05-0.1 常用)
bias="none", # 是否训练偏置("none"=不训练,"all"=全训练,"lora_only"=仅 LoRA 偏置)
task_type=TaskType.CAUSAL_LM # 任务类型:因果语言建模(GPT-2 用于文本生成)
)
# get_peft_model:将 LoRA 适配器应用到模型上
# - 原模型参数被冻结(不更新)
# - 只添加少量可训练参数(LoRA 适配器)
model = get_peft_model(model, lora_config)
# print_trainable_parameters:打印可训练参数统计
# - trainable params:可训练参数数量(LoRA 参数,通常 < 1%)
# - all params:总参数数量(原模型 + LoRA)
# - trainable%:可训练参数占比
model.print_trainable_parameters()
# ========== 第三步:检测并设置计算设备 ==========
# device:计算设备(GPU 加速训练,CPU 较慢)
# - MPS:Apple Silicon(M1/M2/M3)的 GPU 加速(macOS)
# - CUDA:NVIDIA GPU 加速(Linux/Windows)
# - CPU:CPU 计算(最慢,但通用)
if torch.backends.mps.is_available(): # 检查 Apple Silicon GPU 是否可用
device = "mps"
print("MPS is available")
elif torch.cuda.is_available(): # 检查 NVIDIA GPU 是否可用
device = "cuda"
print("CUDA is available")
else:
device = "cpu" # 默认使用 CPU
print("CPU is available")
print(f"Using {device} device")
# model.to(device):将模型移动到指定设备(GPU/CPU)
# - 必须在训练前执行,确保计算在正确的设备上进行
model.to(device)
# ========== 第四步:加载和预处理数据集 ==========
# BLOCK_SIZE:每个训练样本的长度(token 数量)
# - 128:较小的序列长度(训练快,但可能丢失长文本信息)
# - 512/1024:更长序列(训练慢,但能学习更长依赖)
BLOCK_SIZE = 128
# TRAIN_PATH:训练数据文件路径(每行一个文本样本)
TRAIN_PATH = "./hf_gpt2_traning/train_txt.txt"
# load_dataset:加载数据集
# - "text":文本数据集格式(自动按行分割)
# - data_files:数据文件路径(可以是单个文件或文件列表)
raw_dataset = load_dataset("text", data_files=TRAIN_PATH)
# tokenize_function:分词函数(将文本转换为数字序列)
# - examples:批量样本字典({"text": ["文本1", "文本2", ...]})
def tokenize_function(examples):
# tokenizer:对文本进行分词和编码
# - examples["text"]:文本列表
# - padding="max_length":填充到最大长度(BLOCK_SIZE)
# - truncation=True:超过长度则截断
# - max_length=BLOCK_SIZE:最大长度限制
return tokenizer(examples["text"], padding="max_length", truncation=True, max_length=BLOCK_SIZE)
# map:对数据集应用函数(批量处理)
# - tokenize_function:要应用的函数
# - batched=True:批量处理(提高效率)
# - remove_columns=["text"]:移除原始文本列(只保留 token IDs)
tokenized_datasets = raw_dataset.map(tokenize_function, batched=True,remove_columns=["text"])
# group_texts:文本分块函数(将长序列切分成固定长度的块)
# 目的:GPT-2 需要固定长度的输入,将多个短文本拼接后分块
def group_texts(examples):
# concatenated_examples:将所有样本的 token 拼接成一个长列表
# - examples[k]:某个字段的所有样本(如 input_ids: [[1,2,3], [4,5,6], ...])
# - sum(..., []):将多个列表拼接成一个列表([[1,2],[3,4]] → [1,2,3,4])
concatenated_examples = {k: sum(examples[k], []) for k in examples.keys()}
# total_length:拼接后的总长度(所有 token 的数量)
total_length = len(concatenated_examples[list(examples.keys())[0]])
# num_blocks:可以分成的块数(用于信息展示,实际未使用)
num_blocks = total_length // BLOCK_SIZE
# 分块:将长序列切分成多个固定长度的块
# - range(0, total_length, BLOCK_SIZE):生成切分起始位置(0, 128, 256, ...)
# - [i:i+BLOCK_SIZE]:切片操作,取 BLOCK_SIZE 长度的子序列
return {k: [concatenated_examples[k][i:i+BLOCK_SIZE] for i in range(0, total_length, BLOCK_SIZE)] for k in concatenated_examples.keys()}
# map:应用分块函数
# - batched=True:批量处理(提高效率)
# - batch_size=1000:每批处理 1000 个样本(内存允许时可增大)
grouped_datasets = tokenized_datasets.map(group_texts, batched=True,batch_size=1000)
# 打印数据集信息(样本数、特征等)
print(grouped_datasets)
# ========== 第五步:配置训练参数 ==========
# OUTPUT_DIR:模型保存目录(训练后的模型和检查点会保存在这里)
OUTPUT_DIR = "./hf_gpt2_traning/mps"
# EVALUATION_STRATEGY:评估策略
# - "no":不进行评估(需要验证集时设为 "epoch" 或 "steps")
EVALUATION_STRATEGY = "no" # 当前没有验证数据集,设为 "no"
# LEARNING_RATE:学习率(控制参数更新步长)
# - 5e-5:较小的学习率(微调预训练模型常用 1e-5 到 5e-5)
# - 太大:训练不稳定,可能无法收敛
# - 太小:训练太慢,可能陷入局部最优
LEARNING_RATE = 5e-5
# BATCH_SIZE:批量大小(每次训练使用的样本数)
# - 16:较小的批量(显存不足时使用)
# - 32/64:更大的批量(训练更稳定,但需要更多显存)
BATCH_SIZE = 16
# NUM_TRAIN_EPOCHS:训练轮数(完整遍历数据集的次数)
NUM_TRAIN_EPOCHS = 3
# WEIGHT_DECAY:权重衰减(L2 正则化系数,防止过拟合)
# - 0.01:常用值(0.01-0.1)
WEIGHT_DECAY = 0.01
# SAVE_STEPS:保存检查点的步数间隔(每 N 步保存一次模型)
SAVE_STEPS=500
# OVERWRITE_OUTPUT_DIR:是否覆盖输出目录(True=覆盖,False=追加)
OVERWRITE_OUTPUT_DIR = True
# TrainingArguments:训练参数配置类(封装所有训练超参数)
training_args = TrainingArguments(
output_dir=OUTPUT_DIR, # 输出目录
eval_strategy=EVALUATION_STRATEGY, # 评估策略("no"/"epoch"/"steps")
learning_rate=LEARNING_RATE, # 学习率
per_device_train_batch_size=BATCH_SIZE, # 每个设备的训练批量大小
per_device_eval_batch_size=BATCH_SIZE, # 每个设备的评估批量大小
num_train_epochs=NUM_TRAIN_EPOCHS, # 训练轮数
weight_decay=WEIGHT_DECAY, # 权重衰减
save_steps=SAVE_STEPS, # 保存步数间隔
overwrite_output_dir=OVERWRITE_OUTPUT_DIR, # 是否覆盖输出目录
)
# ========== 第六步:创建数据整理器和训练器 ==========
# DataCollatorForLanguageModeling:数据整理器(批量数据对齐和填充)
# 作用:将不同长度的样本填充到相同长度,并创建标签(用于计算损失)
data_collator = DataCollatorForLanguageModeling(
tokenizer=tokenizer, # 分词器(用于填充和特殊 token)
mlm=False, # MLM(掩码语言建模)开关
# - False:因果语言建模(GPT-2,预测下一个 token)
# - True:掩码语言建模(BERT,预测被掩码的 token)
)
# Trainer:训练器类(封装训练、评估、保存等流程)
trainer = Trainer(
model=model, # 要训练的模型(已应用 LoRA)
args=training_args, # 训练参数配置
train_dataset=grouped_datasets["train"], # 训练数据集
tokenizer=tokenizer, # 分词器(用于日志和保存)
data_collator=data_collator, # 数据整理器(批量数据处理)
)
# ========== 第七步:开始训练 ==========
print("开始训练")
# trainer.train():执行训练
# - 自动执行前向传播、反向传播、参数更新
# - 自动保存检查点(根据 save_steps)
# - 自动打印训练日志(损失、学习率等)
trainer.train()
print("训练完成")
# ========== 第八步:保存模型和分词器 ==========
# trainer.save_model:保存训练后的模型(只保存 LoRA 适配器,体积小)
trainer.save_model(OUTPUT_DIR)
# tokenizer.save_pretrained:保存分词器(用于后续推理)
tokenizer.save_pretrained(OUTPUT_DIR)
print("模型和分词器保存完成")
# ========== 第九步:加载训练后的模型(用于推理) ==========
# 重新检测设备(用于推理)
if torch.backends.mps.is_available():
device = torch.device("mps") # Apple Silicon GPU
print("MPS is available")
elif torch.cuda.is_available():
device = torch.device("cuda") # NVIDIA GPU
print("CUDA is available")
else:
device = torch.device("cpu") # CPU
print("CPU is available")
# OUTPUT_DIR:模型保存目录(与训练时相同)
OUTPUT_DIR = "./hf_gpt2_traning/mps"
# 加载训练后的模型(包含 LoRA 适配器)
# - from_pretrained:从本地目录加载模型
model = AutoModelForCausalLM.from_pretrained(OUTPUT_DIR)
# 加载分词器
tokenizer = AutoTokenizer.from_pretrained(OUTPUT_DIR)
# 打印模型参数统计(确认 LoRA 参数已加载)
model.print_trainable_parameters()
# 将模型移动到指定设备(GPU/CPU)
model.to(device)
print("模型加载并迁移到设备完成")
# ========== 第十步:文本生成函数 ==========
# generate_text:使用模型生成文本
def generate_text(prompt):
# tokenizer.encode:将文本转换为 token IDs
# - prompt:输入文本(提示词)
# - return_tensors="pt":返回 PyTorch 张量(不是列表)
# - .to(device):将张量移动到指定设备(GPU/CPU)
input_ids = tokenizer.encode(prompt, return_tensors="pt").to(device)
# model.generate:使用模型生成文本
output = model.generate(
input_ids, # 输入 token IDs
max_length=200, # 最大生成长度(token 数)
num_return_sequences=1, # 生成序列数量(1=只生成一个)
do_sample=True, # 是否使用采样(True=随机采样,False=贪婪解码)
temperature=0.8, # 温度参数(0.1-1.0,越大越随机,越小越确定)
top_p=0.95, # 核采样(nucleus sampling),保留概率质量前 95% 的 token
top_k=50, # Top-K 采样,只从概率最高的 K 个 token 中选择
repetition_penalty=1.5 # 重复惩罚(>1.0 减少重复,<1.0 增加重复)
)
# tokenizer.decode:将 token IDs 转换回文本
# - output[0]:第一个生成的序列(如果 num_return_sequences>1,会有多个)
# - skip_special_tokens=True:跳过特殊 token(如 [PAD]、[CLS] 等)
return tokenizer.decode(output[0], skip_special_tokens=True)
# ========== 第十一步:测试文本生成 ==========
# prompt:输入提示词(模型会基于此生成后续文本)
prompt = "所謂回憶者,雖說可以使人歡欣,有時也不免使人寂寞,使精神的絲縷還牽著己逝的寂寞的時光"
print(generate_text(prompt))
更多推荐



所有评论(0)