transformers迁移学习

transformers迁移学习

🤔 什么是迁移学习?

迁移学习是一种机器学习技术,其核心思想是将在一个任务(源任务)上学习到的知识,应用到另一个相关但不同的任务(目标任务)上。

  • 从零开始训练:模型需要从零学习所有特征,这通常需要海量的标注数据和巨大的计算成本。
  • 迁移学习:模型已经通过预训练掌握了通用的特征(例如,理解语言的基本语法、识别图像的边缘和纹理),我们只需要在此基础上进行"微调"(Fine-tuning),使其适应新的特定任务。

这种方法尤其适合数据量有限或计算资源不足的场景,能让你快速构建出高性能的模型。

NLP常见预训练模型分类

NLP预训练模型根据架构和任务场景,可分为文本理解文本生成两大类,核心区别在于模型结构(编码器/解码器)和训练目标。

1. 文本理解类模型
  • 架构特点 :基于双向编码器,通过上下文双向信息建模,擅长捕捉文本语义关联。
  • 代表模型:
    • BERT:经典双向模型,预训练任务为"掩码语言建模(MLM)"和"下一句预测(NSP)",适合文本分类、命名实体识别(NER)、语义匹配等理解类任务。
    • RoBERTa:BERT改进版,优化训练策略(如动态掩码、更大批次),效果更优。
    • DistilBERT:BERT的"蒸馏版",参数量减少40%,推理速度提升60%,适合资源受限场景。
    • ALBERT:通过"参数共享"和"因式分解"压缩模型,在保持性能的同时显著减小体积。
2. 文本生成类模型
  • 架构特点 :基于解码器(自回归)编码器-解码器,通过"从左到右"的生成式训练,擅长文本创作。
  • 代表模型:
    • GPT/GPT-2:纯解码器架构,自回归生成(根据前文预测下一个词),适合文本生成、对话、故事创作等,是主流大模型(如GPT-3、ChatGPT)的基础架构。
    • T5:编码器-解码器架构,将所有NLP任务统一为"文本到文本"格式(如"翻译:英文→中文"),适合翻译、问答、摘要等生成类任务。

主流预训练模型参数对比

以下表格总结了常见模型的架构参数、训练特点和应用场景,核心差异在于层数、特征维度、参数量训练语料

模型家族 模型名称 层数 特征维度 注意力头数 参数量 训练语料/特点 典型应用场景
BERT bert-base-uncased 12 768 12 ~110M 英文,不区分大小写 文本分类、情感分析、NER
BERT bert-large-uncased 24 1024 16 ~340M 英文,不区分大小写 高精度文本理解任务
BERT bert-base-chinese 12 768 12 ~110M 中文字符级 中文分类、NER、匹配
GPT openai-gpt 12 768 12 ~110M 英文,自回归 文本生成、语言建模
GPT-2 gpt2 12 768 12 ~117M 英文,GPT-2语料 对话生成、续写
GPT-2 gpt2-xl 48 1600 25 ~1558M 大规模语料 高质量文本生成
Transformer-XL transfo-xl-wt103 18 1024 16 ~257M 长文档建模 长文本生成、语言模型
RoBERTa roberta-base 12 768 12 ~125M BERT改进版 文本分类、匹配
RoBERTa roberta-large 24 1024 16 ~355M 更大规模训练 高精度NLP任务
DistilBERT distilbert-base-uncased 6 768 12 ~66M 蒸馏模型 轻量级文本分类
ALBERT albert-base-v1 12 768 12 ~12M 参数共享 资源受限场景
T5 t5-base 12 768 12 ~220M Encoder-Decoder 翻译、问答
T5 t5-large 24 1024 16 ~770M 大模型 高质量生成任务

关键结论

  • BERT系列(如bert-base-chinese)是中文理解任务的首选;
  • GPT系列(如gpt2)是文本生成的核心架构;
  • 模型参数量越大(如gpt2-xl),生成能力越强,但推理成本越高。

常见的NLP任务

任务 核心说明 输出形式 / 备注
文本分类任务 对文本内容进行类别判断,如情感分类、商品分类。通常属于有监督学习。 输出类别标签(及其概率),结果依赖训练样本标签。
特征提取任务 返回文本的向量表示(语义特征),常作为下游任务输入。 可分为: 1) 不带任务头:输出隐藏层特征; 2) 带任务头:按具体任务输出(如分类/填空)。
完形填空任务 又称遮蔽语言建模(MLM),预测被 [MASK] 遮蔽位置的词。 输出被遮蔽位置的候选词及概率。
阅读理解任务 又称抽取式问答:输入"上下文+问题",模型从上下文中抽取答案。 输出答案文本(通常附带起止位置或置信度)。
文本摘要任务 输入一段较长文本,生成简短概括内容。 输出摘要文本(可为抽取式或生成式)。
NER 任务 命名实体识别,识别人名(PER)、地名(LOC)、组织(ORG)等。 本质是序列标注/分类任务,常用 BIO 标注:B-(实体开始)、I-(实体内部)、O(非实体)。

如何使用 Transformers 进行迁移学习

Transformers 库提供了多种使用方式,从极简的"一键调用"到灵活的"手动微调",可以满足不同层次的需求。

1. 快速上手:使用 Pipeline

pipeline 是 Transformers 库中最高级别的抽象,它将数据预处理、模型推理和后处理等步骤全部封装起来。你只需要几行代码就能完成一个复杂的 NLP 任务,非常适合快速验证想法或构建原型。

例如,进行中文情感分析:

python 复制代码
from transformers import pipeline

# 创建一个情感分析管道,会自动下载模型和分词器
classifier = pipeline("sentiment-analysis", model="bert-base-chinese")

# 直接进行预测
result = classifier("这个产品真的非常好用,性价比超高!")
print(result)
# 输出示例: [{'label': 'POSITIVE', 'score': 0.9996}]
2. 标准流程:使用 AutoModel 和 Trainer

当你需要更多的控制权,例如修改模型结构、自定义训练循环或处理自己的数据集时,就需要使用 AutoModelTrainer。这是进行迁移学习微调的标准流程。

核心步骤如下:

  1. 加载预训练模型和分词器 :使用 AutoTokenizerAutoModelForSequenceClassification 等类,根据任务类型加载模型。
  2. 准备和预处理数据:使用分词器对你的数据集进行编码。
  3. 配置训练参数 :使用 TrainingArguments 来设置学习率、批大小、训练轮数等。
  4. 启动训练 :使用 Trainer 类来执行训练循环。
python 复制代码
import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification, TrainingArguments, Trainer
from datasets import load_dataset # 假设使用 Hugging Face 的 datasets 库加载数据

# 1. 加载预训练模型和分词器
model_name = "bert-base-chinese"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=2) # 假设是二分类任务

# 2. 准备和预处理数据 (此处仅为示例)
def tokenize_function(examples):
    """
    examples["text"]: 函数假设你的 CSV 文件中有一列名为 "text"。分词器会提取这一列的内容进行处理。
    truncation=True: 截断。如果某段文本的长度超过了模型允许的最大长度(例如 BERT 的 512 个 token),超出的部分会被自动切掉。
    padding=True: 填充。如果批次中的文本长度不一致,这个参数会自动用填充符号(如 [PAD])将较短的文本补齐,使它们长度一致,以便模型进行批量处理。
    """
    return tokenizer(
        examples["text"], 
        truncation=True, 
        padding="max_length",  # 强制填充到最大长度,而不是动态填充
        max_length=512  # 显式指定最大长度(BERT通常是512,根据模型调整)
    )

# 假设 dataset 是你的数据集,例如从 load_dataset("your_dataset") 加载
# dataset = load_dataset("your_dataset")
# tokenized_datasets = dataset.map(tokenize_function, batched=True)

# 3. 配置训练参数
training_args = TrainingArguments(
    output_dir="./checkpoints",          # 模型检查点保存目录
    num_train_epochs=3,                  # 训练轮数
    per_device_train_batch_size=16,      # 每个设备的训练批大小
    learning_rate=2e-5,                  # 学习率
    fp16=torch.cuda.is_available(),      # 如果GPU支持,启用混合精度训练以加速
    logging_steps=10,                    # 每隔多少步记录一次日志
    save_strategy="epoch",               # 每个epoch保存一次模型
)

# 4. 初始化 Trainer 并开始训练
# trainer = Trainer(
#     model=model,
#     args=training_args,
#     train_dataset=tokenized_datasets["train"], # 指定训练集
# )
# trainer.train()

# 保存模型
# trainer.save_model("./checkpoints/final_model")
# 关键步骤】显式保存分词器到同一个目录
# tokenizer.save_pretrained("./checkpoints/final_model")

# 测试单条文本
# 加载训练好的模型
# model_path = "./checkpoints/final_model"  # 或者你保存的具体路径
# loaded_tokenizer = AutoTokenizer.from_pretrained(model_path)
# loaded_model = AutoModelForSequenceClassification.from_pretrained(model_path)

# def predict_single_text(text):
#     # 1. 分词 (必须放回模型所在的设备,如 cuda 或 cpu)
#     inputs = tokenizer(text, return_tensors="pt", truncation=True, padding=True).to(model.device)
# 
#     # 2. 推理 (关闭梯度计算以节省内存)
#     with torch.no_grad():
#         outputs = model(**inputs)
#         # 获取概率最高的类别索引
#         predicted_class_id = outputs.logits.argmax(-1).item()
# 
#     return predicted_class_id
# 
# 
# # 测试
# text_to_test = "这部电影真的太棒了,演员演技在线!"
# result = predict_single_text(text_to_test)
# print(f"输入: '{text_to_test}' -> 预测类别: {result}")
3.指定模型类:使用SpecificModel

"具体模型"其实就是指那些已经训练好、可以直接拿来用的"成品"。在 Hugging Face 的体系里,它处于最底层,代表了某一个特定的、独一无二的模型实例。

具体模型是指具有特定权重、特定配置、针对特定语言或任务微调过的预训练模型实例

python 复制代码
from transformers import BertTokenizer, BertForSequenceClassification
# 手动加载BERT模型(与AutoModel效果一致,但需指定类)
tokenizer = BertTokenizer.from_pretrained("bert-base-chinese")
model = BertForSequenceClassification.from_pretrained("bert-base-chinese", num_labels=2)

核心总结

  • 模型选择 :理解类任务选BERT系列,生成类任务选GPT/T5系列;中文任务优先bert-base-chinese
  • 库的使用 :快速验证用Pipeline,通用开发用AutoModel,深度定制用SpecificModel
  • 迁移学习本质:所有预训练模型均基于"预训练+微调"范式,通过少量数据即可适配新任务,大幅降低训练成本。

🌰基于 Hugging Face Transformers 库和 PyTorch 框架情感分类模型

流程可以分为以下几个关键步骤:

  1. 数据准备
    • 准备好你的中文情感分类数据集,通常包含文本和对应的标签(如正面/负面)。
    • 将数据集划分为训练集和验证集。
  2. 模型与分词器加载
    • 从模型库中加载预训练的 bert-base-chinese 模型和对应的分词器。
    • 在预训练模型的基础上,添加一个用于分类的头部(例如,一个线性层),以适应你的分类类别数量。
  3. 数据预处理
    • 使用分词器将原始文本转换为模型可以理解的输入格式,这通常包括:
      • input_ids: 词汇在词表中的索引。
      • attention_mask: 用于区分真实词汇和填充部分的掩码。
      • token_type_ids: 用于区分句子对中的不同句子(单句分类任务中可省略)。
    • 将处理后的数据和标签封装成 PyTorch 的数据集(Dataset)和数据加载器(DataLoader)。
  4. 模型微调
    • 定义训练参数,例如:
      • 训练轮数 (num_train_epochs)
      • 批大小 (per_device_train_batch_size)
      • 学习率 (learning_rate)
      • 权重衰减 (weight_decay) 等。
    • 使用训练集数据对模型进行训练,并在验证集上监控模型性能,防止过拟合。
python 复制代码
import torch
from torch.utils.data import Dataset, DataLoader
from transformers import BertTokenizer, BertForSequenceClassification, AdamW, get_linear_schedule_with_warmup
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import pandas as pd
import numpy as np
from tqdm import tqdm

# --- 1. 配置与超参数 ---
MODEL_NAME = 'bert-base-chinese'  # 预训练模型名称
MAX_LEN = 128                     # 文本最大长度
BATCH_SIZE = 16                   # 批大小
EPOCHS = 3                        # 训练轮数
LEARNING_RATE = 2e-5              # 学习率
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

# --- 2. 数据准备 (模拟数据) ---
# 在实际场景中,这里应该是 pd.read_csv('your_data.csv')
data = {
    'text': [
        "这个手机太好用了,屏幕清晰,运行速度快,强烈推荐!",
        "非常糟糕的体验,物流慢,东西也是坏的,千万别买。",
        "质量一般般吧,对得起这个价格,没什么特别的。",
        "真的很喜欢,完全超出期望值,发货速度非常快。",
        "垃圾产品,不仅难用还贵,客服态度也不好。",
        "东西收到了,包装很好,是正品,下次还会光顾的。",
        "太差劲了,根本没法用,浪费钱。",
        "手感不错,做工精细,性价比很高的一款产品。"
    ],
    'label': [1, 0, 0, 1, 0, 1, 0, 1]  # 1: 正面, 0: 负面
}
# 为了演示效果,我们将数据复制多份(实际训练需要更多数据)
df = pd.DataFrame(data).loc[np.repeat(data.keys(), 100)].reset_index(drop=True)

# 划分训练集和验证集
train_df, val_df = train_test_split(df, test_size=0.2, random_state=42)

# --- 3. 自定义 Dataset 类 ---
class SentimentDataset(Dataset):
    def __init__(self, texts, labels, tokenizer, max_len):
        self.texts = texts
        self.labels = labels
        self.tokenizer = tokenizer
        self.max_len = max_len

    def __len__(self):
        return len(self.texts)

    def __getitem__(self, item):
        text = str(self.texts[item])
        label = self.labels[item]

        # 使用 BERT 分词器进行编码
        encoding = self.tokenizer.encode_plus(
            text,
            add_special_tokens=True,      # 添加 [CLS] 和 [SEP]
            max_length=self.max_len,      # 截断或填充长度
            padding='max_length',         # 填充到最大长度
            truncation=True,              # 超长截断
            return_attention_mask=True,   # 返回 attention mask
            return_tensors='pt',          # 返回 PyTorch 张量
        )

        return {
            'input_ids': encoding['input_ids'].flatten(),
            'attention_mask': encoding['attention_mask'].flatten(),
            'labels': torch.tensor(label, dtype=torch.long)
        }

# --- 4. 初始化 Tokenizer 和 DataLoader ---
tokenizer = BertTokenizer.from_pretrained(MODEL_NAME)

def create_data_loader(df, tokenizer, max_len, batch_size):
    ds = SentimentDataset(
        texts=df.text.to_numpy(),
        labels=df.label.to_numpy(),
        tokenizer=tokenizer,
        max_len=max_len
    )
    return DataLoader(ds, batch_size=batch_size, num_workers=0) # num_workers=0 for Windows compatibility

train_data_loader = create_data_loader(train_df, tokenizer, MAX_LEN, BATCH_SIZE)
val_data_loader = create_data_loader(val_df, tokenizer, MAX_LEN, BATCH_SIZE)

# --- 5. 模型加载 (迁移学习核心) ---
# 加载预训练模型,并指定分类头的输出类别数量 (num_labels=2)
model = BertForSequenceClassification.from_pretrained(MODEL_NAME, num_labels=2)
model = model.to(DEVICE)

# --- 6. 优化器与学习率调度 ---
optimizer = AdamW(model.parameters(), lr=LEARNING_RATE, correct_bias=False)
total_steps = len(train_data_loader) * EPOCHS
scheduler = get_linear_schedule_with_warmup(
    optimizer,
    num_warmup_steps=0,
    num_training_steps=total_steps
)

# --- 7. 训练与评估函数 ---
def train_epoch(model, data_loader, optimizer, device, scheduler):
    model.train()
    losses = []
    correct_predictions = 0

    # 使用 tqdm 显示进度条
    for d in tqdm(data_loader, desc="Training"):
        input_ids = d["input_ids"].to(device)
        attention_mask = d["attention_mask"].to(device)
        labels = d["labels"].to(device)

        # 前向传播
        outputs = model(
            input_ids=input_ids,
            attention_mask=attention_mask,
            labels=labels
        )
        loss = outputs.loss
        logits = outputs.logits

        # 计算准确率
        _, preds = torch.max(logits, dim=1)
        correct_predictions += torch.sum(preds == labels)
        losses.append(loss.item())

        # 反向传播与优化
        loss.backward()
        optimizer.step()
        scheduler.step()
        optimizer.zero_grad()

    return correct_predictions.double() / len(data_loader.dataset), np.mean(losses)

def eval_model(model, data_loader, device):
    model.eval()
    losses = []
    correct_predictions = 0

    with torch.no_grad():
        for d in data_loader:
            input_ids = d["input_ids"].to(device)
            attention_mask = d["attention_mask"].to(device)
            labels = d["labels"].to(device)

            outputs = model(
                input_ids=input_ids,
                attention_mask=attention_mask,
                labels=labels
            )
            loss = outputs.loss
            logits = outputs.logits

            _, preds = torch.max(logits, dim=1)
            correct_predictions += torch.sum(preds == labels)
            losses.append(loss.item())

    return correct_predictions.double() / len(data_loader.dataset), np.mean(losses)

# --- 8. 执行训练循环 ---
print(f"使用设备: {DEVICE}")

for epoch in range(EPOCHS):
    print(f'Epoch {epoch + 1}/{EPOCHS}')
    print('-' * 10)

    train_acc, train_loss = train_epoch(
        model,
        train_data_loader,
        optimizer,
        DEVICE,
        scheduler
    )
    print(f'训练损失: {train_loss} 准确率: {train_acc.item()}')

    val_acc, val_loss = eval_model(
        model,
        val_data_loader,
        DEVICE
    )
    print(f'验证损失: {val_loss} 准确率: {val_acc.item()}')
    print('-' * 10)

# --- 9. 单句预测函数 ---
def predict_sentiment(text):
    model.eval()
    encoding = tokenizer.encode_plus(
        text,
        add_special_tokens=True,
        max_length=MAX_LEN,
        return_tensors='pt',
        truncation=True,
        padding='max_length'
    )

    input_ids = encoding['input_ids'].to(DEVICE)
    attention_mask = encoding['attention_mask'].to(DEVICE)

    with torch.no_grad():
        outputs = model(input_ids=input_ids, attention_mask=attention_mask)
        _, prediction = torch.max(outputs.logits, dim=1)

    sentiment = "正面" if prediction.item() == 1 else "负面"
    print(f'文本: "{text}" -> 预测情感: {sentiment}')

# 测试预测
predict_sentiment("这个手机太棒了,拍照非常清晰!")
predict_sentiment("服务态度极差,以后再也不会来了。")
代码关键点解析
  1. 迁移学习的核心 (from_pretrained)
    • BertForSequenceClassification.from_pretrained('bert-base-chinese', num_labels=2):这行代码不仅下载了预训练的 BERT 权重,还自动在 BERT 的顶部添加了一个线性分类层。
    • 微调 :在 train_epoch 中,我们更新了整个模型的参数(包括 BERT 的底层参数和顶部的分类层参数)。
  2. 数据处理 (Tokenizer)
    • BERT 需要特定的输入格式:input_ids(词的索引)和 attention_mask(区分真实词和填充词)。
    • [CLS] 标记:BERT 会在句子开头自动添加 [CLS],模型通过这个标记对应的输出向量来进行分类。
  3. 设备管理 (DEVICE)
    • 代码自动检测是否有 GPU 可用。如果有 GPU,训练速度会比 CPU 快几十倍。
  4. 优化器 (AdamW)
    • 这是 Transformer 模型训练的标准优化器,配合学习率预热调度器可以获得更好的收敛效果。

应用到真实场景:

  1. 替换数据 :将代码中的 data 字典替换为 pd.read_csv('your_dataset.csv')
  2. 调整超参数 :根据你的数据量大小调整 BATCH_SIZEEPOCHS。数据量大时,通常 2-4 个 Epoch 就足够了,防止过拟合。
  3. 模型选择 :如果追求更高精度,可以将 MODEL_NAME 替换为更大的模型,如 hfl/chinese-roberta-wwm-ext
进阶优化技巧

为了进一步提升效果或提高训练效率,可以考虑以下高级方法:

  • 参数高效微调 (PEFT)
    对于非常大的模型,全参数微调的成本很高。可以采用参数高效微调方法,只训练模型的一小部分参数,例如:
    • LoRA (Low-Rank Adaptation): 通过在模型层中注入可训练的低秩矩阵来调整模型。
    • Adapter Tuning: 在模型的 Transformer 层之间插入小型的、可训练的"Adapter"模块。
  • 数据清洗
    在进行跨领域情感分类时,可以借鉴一些研究思路。例如,先利用注意力网络等方法学习文本的分布式表示,然后采用类噪声估计等方法检测并剔除源领域中可能导致"负迁移"的低质量样本,从而提升目标领域的分类效果。

完形填空(MLM)功能

将情感分类代码改为完形填空(Masked Language Modeling, MLM)功能,核心思路是从"文本分类"转变为"预测被遮蔽的词"。

核心变化点
  1. 模型变更 :从 BertForSequenceClassification 改为 BertForMaskedLM
  2. 任务逻辑 :不再输入"文本+标签",而是输入"带 [MASK] 的文本"。
  3. 输出处理:模型输出的是词汇表中每个词的概率,我们需要取出概率最高的前 N 个词作为预测结果。
代码
python 复制代码
import torch
from transformers import BertTokenizer, BertForMaskedLM

# --- 1. 配置 ---
MODEL_NAME = 'bert-base-chinese'
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

# --- 2. 加载模型与分词器 ---
# 加载预训练的分词器
tokenizer = BertTokenizer.from_pretrained(MODEL_NAME)

# 加载用于掩码语言建模(Masked Language Modeling)的预训练模型
# 注意:这里使用的是 BertForMaskedLM 而不是 BertForSequenceClassification
model = BertForMaskedLM.from_pretrained(MODEL_NAME).to(DEVICE)

# --- 3. 定义预测函数 ---
def predict_mask(text, top_k=5):
    """
    预测句子中 [MASK] 位置的词
    :param text: 包含 [MASK] 标记的输入文本
    :param top_k: 返回概率最高的前 K 个候选词
    """
    # 1. 文本编码
    # encode 将文本转换为 tensor,并添加 [CLS] 和 [SEP] 标记
    inputs = tokenizer.encode(text, return_tensors='pt').to(DEVICE)
    
    # 找到 [MASK] 标记的索引位置
    mask_token_index = torch.where(inputs == tokenizer.mask_token_id)[1]
    
    # 2. 模型推理 (不需要计算梯度,加快速度)
    with torch.no_grad():
        outputs = model(inputs)
        predictions = outputs.logits

    # 3. 提取预测结果
    # 获取 [MASK] 位置对应的预测向量
    mask_token_logits = predictions[0, mask_token_index, :]
    
    # 使用 softmax 将 logits 转换为概率
    probabilities = torch.softmax(mask_token_logits, dim=-1)
    
    # 获取概率最高的 top_k 个词的索引
    top_k_tokens = torch.topk(probabilities, top_k, dim=1).indices[0].tolist()

    # 4. 打印结果
    print(f"句子: {text}")
    print("-" * 30)
    for token_id in top_k_tokens:
        token = tokenizer.decode([token_id])
        score = probabilities[0, token_id].item()
        # 替换文本中的 [MASK] 进行展示
        filled_sentence = text.replace(tokenizer.mask_token, token)
        print(f"预测: {token:<10} 概率: {score:.4f}  -> {filled_sentence}")
    print("=" * 40)

# --- 4. 运行测试 ---

# 测试用例 1:常识推理
predict_mask("中国的首都是[MASK]。")

# 测试用例 2:语境理解
predict_mask("我想吃[MASK],因为它很甜。")

# 测试用例 3:成语/常用语填空
predict_mask("画蛇添[MASK]。")
代码详解
  1. BertForMaskedLM
    • 这是专门用于完形填空任务的模型架构。它的输出层维度是词表大小(对于中文 BERT 通常是 21128),代表每个可能的字或词出现的概率。
  2. tokenizer.mask_token_id
    • 我们需要找到输入句子中 [MASK] 所在的位置,因为模型会对句子中所有位置进行预测,但我们只关心被遮住的那个位置。
  3. torch.topk
    • 这是一个高效获取概率最高前 N 个预测结果的方法。
  4. tokenizer.decode
    • 模型输出的是数字 ID,必须通过分词器转换回人类可读的中文字符。

展示了 BERT 最原始的能力:双向理解上下文 。它利用 [MASK] 左右两边的信息来共同推断中间缺失的内容

微调策略与技巧

  • 冻结层与解冻层:在微调初期,可以"冻结"预训练模型的大部分层(通常是底层),只训练顶部的分类头。这可以防止破坏预训练模型已经学到的通用特征。之后,可以逐步"解冻"更多层进行更精细的调整。
  • 差异学习率 :为模型的不同部分设置不同的学习率。通常,预训练部分的参数使用较小的学习率(如 2e-5),而新添加的分类头可以使用较大的学习率(如 1e-3)。
  • 混合精度训练 (fp16) :在 TrainingArguments 中设置 fp16=True,可以利用 GPU 的 Tensor Cores 加速训练,并显著降低显存占用,从而允许使用更大的批大小。
  • 数据增强:对于数据量较少的任务,对训练数据进行适当的增强(如文本的同义词替换、回译等)可以有效提升模型的泛化能力。

从训练到部署

模型训练完成后,可以将其保存并部署到生产环境中。

  • 模型保存model.save_pretrained("./my_finetuned_model")tokenizer.save_pretrained("./my_finetuned_model")
  • 推理加速 :可以使用 ONNX Runtime 等工具将模型转换为 ONNX 格式,以获得更快的推理速度。
  • 模型量化:将模型权重从 FP32 转换为 INT8 等更低精度的格式,可以大幅压缩模型体积,适合在资源受限的边缘设备上部署。
  • 服务化部署 :可以结合 FastAPI 等框架,将模型封装成 RESTful API 服务,供其他应用调用。

🔍BERT和GPT架构对比

BERT 和 GPT 都是基于 Transformer 架构的预训练语言模型,但它们在设计哲学、模型结构和训练目标上存在根本性的差异,这直接决定了它们各自擅长的领域。简单来说,BERT 像一个"阅读理解"高手,擅长深度分析;而 GPT 则像一个"作家",擅长流畅创作。

1.模型架构
BERT (Encoder-Only)

BERT 的全称是"来自变换器的双向编码器表示"。它只采用了 Transformer 的编码器(Encoder)部分。编码器的核心任务是读取并理解输入文本,为每个词生成一个包含丰富上下文信息的表示向量。

GPT (Decoder-Only)

GPT 的全称是"生成式预训练变换器"。它只采用了 Transformer 的解码器(Decoder)部分。解码器的核心任务是根据已有的信息来生成下一个内容,非常适合自回归的文本生成任务。

2.注意力机制与上下文理解
BERT (双向上下文)

BERT 使用双向自注意力机制。在理解任何一个词时,模型可以同时"看到"它左边和右边的所有上下文信息。这种设计让 BERT 能够对词语的含义进行非常全面和深刻的理解,尤其擅长处理歧义词(例如,根据上下文判断"bank"是指"银行"还是"河岸")。

GPT (单向上下文)

GPT 使用带掩码的自注意力机制。在预测或生成一个词时,模型只能"看到"它左边的词(即已经生成的上文),而无法看到未来的信息。这种单向(从左到右)的信息流模拟了人类写作和说话的过程,使其在生成连贯、流畅的文本方面表现出色。

3.训练目标
BERT (完形填空)

BERT 的核心训练任务是掩码语言模型(MLM)。它会随机遮盖输入文本中约15%的词(例如,将 "The cat sat on the mat" 变为 "The cat sat on the [MASK]"),然后让模型根据完整的双向上下文来预测被遮盖的词。这就像一个"完形填空"练习,迫使模型深度理解整个句子的语义。

GPT (文本续写)

GPT 的训练目标是自回归语言建模。它的任务非常直接:给定一个词序列,预测下一个最可能出现的词。例如,输入"今天天气很",模型会学习预测下一个词是"好"。这个过程不断重复,从而实现文本的连续生成,就像一个"文本续写"练习。

应用场景
模型 核心能力 典型应用场景
BERT 深度理解 文本分类、情感分析、命名实体识别(NER)、问答系统(从文档中抽取答案)、语义匹配、搜索排序
GPT 流畅生成 文章写作、代码生成、对话聊天、内容摘要、机器翻译、创意文本生成
总结
对比维度 BERT GPT
核心架构 Transformer Encoder Transformer Decoder
注意力方向 双向 (可同时看前后文) 单向 (只能看前文)
训练目标 掩码语言模型 (MLM),类似"完形填空" 自回归语言模型,类似"文本续写"
能力侧重 擅长语言理解和分析 擅长语言生成和创作
形象类比 阅卷老师 作家

🔍Qwen架构-GPT改进

核心架构演进:基于GPT的优化

千问的底层逻辑依然是Decoder-only的自回归架构,但在具体实现上引入了多项关键技术改进,以解决标准GPT架构在效率和长上下文处理上的瓶颈。

关键技术改进
1. 注意力机制优化(GQA/MQA)

千问采用了分组查询注意力 (GQA)或多查询注意力(MQA)机制。

  • 原理:让多个查询头共享同一组键值对,从而大幅减少推理时需要缓存的键值对数量。
  • 优势:显著降低了显存占用,提升了推理速度,尤其是在处理长文本时效果明显。
机制 核心切分逻辑 KV 组数关系 关键特征 类比
MHA Q、K、V 等头数切分 Q头数 = KV头数 每个 Q 头拥有独立专属的 K、V,表达能力最强。 将羊肉Q、鸡肉K、鱼肉V都切成同样数量的薄片,下锅计算注意力,味道最丰富(表达能力强),但切菜太慢(计算和显存开销大)。
GQA Q 切细组,KV 切分组 Q头数 = 4 * KV头数 组内共享,每组多头 Q 共用一组 K、V,平衡效果与速度。 将羊肉Q切成薄片,将鸡肉K和鱼肉V切成较厚的块,下锅计算注意力,既保证了备菜速度,又兼顾了味道(效果与效率的平衡)。
MQA 只切分 Q,不切分 KV Q头数 >> KV头数=1 所有头的 Q 共用同一组 K、V,推理速度最快。 只切羊肉Q,鸡肉K和鱼肉V完全不切(只有1大块),下锅计算注意力,备菜极快,味道难以描述(表达能力差)。
  • MHA:效果最好,但速度慢,显存占用高。
  • MQA:速度最快,显存占用低,但效果损失较大。
  • GQA:折中方案,在保持接近 MHA 效果的同时,大幅提升了推理速度(目前主流大模型如 Llama 2/3, Mistral 等多采用 GQA)。
2. 位置编码升级(RoPE)

千问使用旋转位置编码(RoPE)替代了GPT早期的绝对位置编码。

  • 原理:将位置信息通过旋转变换融入到词向量中。
  • 优势:赋予了模型更好的外推能力,使其能够处理比训练时更长的上下文序列。
3. 归一化层简化(RMSNorm)

千问使用均方根归一化(RMSNorm)替代了GPT中的层归一化(LayerNorm)。

  • 原理:RMSNorm仅对输入的均方根进行归一化,省去了减去均值的步骤。
  • 优势:计算更简单、更高效,同时能保持训练的稳定性。
4. 激活函数增强(SwiGLU)

千问在前馈网络中使用了SwiGLU激活函数,替代了GPT-2中的GELU。

  • 原理:SwiGLU引入了门控机制,可以更精细地控制信息流。
  • 优势:提升了模型的表达能力和收敛速度。
5. 中文分词优化

千问针对中文进行了专门的分词器设计,减少了中文字符被拆分成多个Token的情况。

  • 优势:提高了中文处理的效率和准确性,降低了序列长度。
相关推荐
码农小旋风1 小时前
Codex 直接住进 JetBrains IDE 里:AI Agent 正在接管熟悉的开发入口
ide·人工智能
ʜᴇɴʀʏ1 小时前
AAAI 2025 | DiffCorr:基于可靠伪标签引导的无监督点云形状对应
人工智能·目标检测·计算机视觉
黎阳之光1 小时前
智慧水利堤坝监测:全域实景技术实现河流、水库隐患预警
大数据·人工智能·物联网·安全·数字孪生
云边云科技_云网融合1 小时前
大模型聚合时代:云边云科技 AI 网关轻量化赋能企业落地
大数据·运维·网络·人工智能
love530love1 小时前
ComfyUI:为什么说它是 AIGC 应用层面的集大成者?
人工智能·pytorch·windows·aigc·devops·comfyui·extensions
NashSKY1 小时前
关于支持向量机(SVM)的数学原理、参数拟合、嵌入式部署的完整指南
c++·python·机器学习·支持向量机
程序员柒叔1 小时前
OpenCode 一周动态-2026-W20
人工智能·github·copilot·agent·opencode
wuxinyan1231 小时前
工业级大模型学习之路013:RAG零基础入门教程(第九篇):RAG幻觉治理
人工智能·学习·rag
XD7429716361 小时前
科技晚报|2026年5月17日:AI 开始进入国家与企业制度层
人工智能·科技·企业数字化·科技晚报