训练模型

📌 前置学习内容

  • 熟悉 Python 语言
    → 掌握基础语法、数据结构、函数与类等必知必会的知识。

  • 熟练使用常用 Python 库
    → 包括 Numpy(数值计算)、PyTorch(深度学习框架)、Matplotlib(数据可视化)。

  • 熟悉深度学习基础知识
    → 理解神经网络结构、反向传播原理、损失函数作用等核心概念。

💡 学习建议:
在开始本章前,请确保具备以上三方面基础,以便高效掌握后续内容。

使用HuggingFace训练一个GPT2

了解HuggingFace

AI开发的三驾马车:模型库,数据集,工具库。
而HuggingFace就是具备这三者的一个大模型平台
AI界的GitHub

为什么大家喜欢 Hugging Face

✅ 核心优势

  • 打破技术垄断,让 AI 普惠大众
    → 推动人工智能从封闭研究走向开放共享。

  • 行业事实标准:连接学术与产业界的桥梁
    → 学术成果快速落地,产业需求反哺研究。

  • 中立的开源平台,与众多 AI 巨头合作,资源丰富
    → 汇聚海量预训练模型、数据集和工具,生态成熟。

💡 总结:Hugging Face 是 AI 开源生态的核心枢纽,推动技术民主化。

HuggingFace Hub

  1. 有超过50万个预训练模型
  2. 超过10万的数据集
  3. 即搜即用即分享

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)
      → 在提示中给出少量示例,模型能泛化推理。
  • 输出结果

    • 得到一个通用的语言理解模型(如 BERT、GPT、LLaMA 等)
    • 掌握语法、常识、知识表示等基础能力

💡 类比:就像“人类通过阅读大量书籍来学习语言”。


✅ 第二阶段:微调训练(Fine-tuning)
  • 输入数据

    • 标注数据集
      • 例如:问答对、翻译句对、摘要文本、指令-响应对
      • 数据量远小于预训练数据,但质量高
  • 训练方式

    • 在预训练模型基础上,用特定任务的数据进行有监督训练
    • 目标是让模型适应具体应用场景
  • 常见任务

    • 分类(如情感分析)
    • 总结(自动摘要)
    • 翻译(多语言互译)
    • 个人助手(对话系统)

💡 类比:就像“学生在掌握基础知识后,专门练习考试题”。


🎯 最终输出:多功能智能模型

经过两阶段训练后,LLM 可以:

  • 理解复杂语义
  • 生成自然语言
  • 执行多种任务(无需重新训练)
  • 支持零样本/少样本推理

🔍 关键技术点总结

阶段 技术重点 数据类型 训练目标
预训练 自监督学习、Transformer 架构 未标注文本 学习语言结构和世界知识
微调 有监督学习、参数更新 标注数据 适配特定任务

💡 小贴士(给新人)

✅ 预训练是“打基础”,微调是“练技能”
✅ 大部分开源 LLM 都是先预训练,再微调得到的
✅ Hugging Face 上的很多模型都支持直接微调(如 Trainer API)

📚 推荐学习路径

  1. 先用 pipeline 快速体验 LLM 能力
  2. 学习如何加载模型和分词器
  3. 进阶到微调训练,打造自己的专用模型
大模型的工作原理
  • 通过概率预测下一个值
    在这里插入图片描述
    在这里插入图片描述
掩码机制
  • 输入内容时,本质是并行,并且全量识别的
  • 掩码的作用是“强制因果”,即前一个字或者词是因,后一个未知被遮住的是果,这样就有从左往右的因果顺序往后推,而且不可逆

精确拆解

不是串行解码
❌ 没有「算完第 1 个再算第 2 个」

并行计算
✅ Attention 矩阵一次性算

施加因果约束
✅ 通过掩码:

  1. 禁止未来 → 现在的信息通路
  2. 保证预测只依赖过去
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 就像一个“超级读者”

  1. 它读过海量书籍,学会了如何用语言表达思想;
  2. 当你给它一句话开头时,它就能像写文章一样,一步步续写下去。

✅ 掌握这三大原理,你就理解了所有主流 LLM(如 GPT、LLaMA、ChatGLM)的底层逻辑。

区分训练和推理两个阶段
1️⃣ 训练阶段(Training Phase)

目的
让模型学会语言规律、上下文依赖、预测下一个 token 的能力。
工作流程

  1. 输入数据

    • 给定一大批文本 token 序列(训练集)。
    • 每个 token 按序排列形成上下文窗口。
  2. 掩码机制(Causal Mask)

    • 每个 token 只能看到它前面的 token(左侧),不能看到未来 token(右侧)。

    • 例如:

        序列: [The, cat, is, sleeping]
        预测目标: ['cat', 'is', 'sleeping', <EOS>]
      
    • 模型预测 cat 时只能看到 The

    • 预测 is 时看到 [The, cat]

    • 预测 sleeping 时看到 [The, cat, is]

  3. 计算损失(Loss)

    • 将模型预测的概率分布与真实 token 对比,计算交叉熵损失。
  4. 反向传播 & 更新参数

    • 通过梯度下降算法调整模型参数(权重 W、偏置 b 等),让预测更准确。

批量 & 并行

一次训练通常用 batch 并行计算多个序列,提高效率。

✅ 特点:

  1. 需要真实答案(监督信号)
  2. 目标是优化模型参数
  3. 使用掩码保证因果约束
2️⃣ 推理阶段(Inference Phase)

目的
用训练好的模型生成文本或做预测,不再更新参数。
工作流

  1. 输入提示(Prompt)
    • 给模型一段已有文本,要求预测接下来的 token。
  2. 因果预测
    • 模型基于当前上下文预测下一个 token(概率分布)
    • 取概率最高或采样生成新的 token
  3. 生成循环
    • 新生成的 token 会加入上下文,再预测下一个 token
    • 迭代直到生成结束(如达到最大长度或遇到 )

✅ 特点:

  1. 不使用真实答案,只是让模型“发挥”学到的能力
  2. 参数固定,没有梯度更新
  3. 可以用不同策略生成:贪心、采样、Top-k、Top-p(Nucleus Sampling)

✅ 训练 vs 推理 的核心区别

特性 训练阶段 推理阶段
目的 学习预测能力 使用模型生成/预测
参数更新 会更新(梯度下降) 不更新,固定参数
输入 文本 + 正确答案 文本/提示
输出 用于计算损失 用于生成文本或预测结果
掩码机制 使模型只能看到前文 同样保持因果约束
批量处理 多序列并行训练 通常单序列生成,也可 batch

💡 一句话总结:

训练阶段:模型在“练习”,看答案学习规律,不停调整自己。

推理阶段:模型在“考试/表演”,用学到的规律生成或预测,不再调整。

HuggingFace的角色
  1. 提供给你预选练好的模型
  2. 提供标准化工具,比如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))
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐