【Datawhale学习笔记】预训练模型实战

举报
JeffDing 发表于 2026/01/16 10:28:53 2026/01/16
【摘要】 Bert Bert的工作范式预训练 (Pre-training)在一个庞大的、通用的文本语料库(如维基百科、书籍)上,通过特定的无监督任务来训练一个深度神经网络模型。这个阶段的目标不是为了完成某个具体的 NLP 任务,而是让模型学习语言本身的规律,比如语法结构、词语间的语义关系、上下文依赖等。训练完成后,就得到了一个包含了丰富语言知识的、参数已经训练好的预训练模型。微调 (Fine-tun...

Bert

Bert的工作范式

825df77128c12118328063d76ad65b70_5_1_1.png

  • 预训练 (Pre-training)

    • 在一个庞大的、通用的文本语料库(如维基百科、书籍)上,通过特定的无监督任务来训练一个深度神经网络模型。
    • 这个阶段的目标不是为了完成某个具体的 NLP 任务,而是让模型学习语言本身的规律,比如语法结构、词语间的语义关系、上下文依赖等。
    • 训练完成后,就得到了一个包含了丰富语言知识的、参数已经训练好的预训练模型。
  • 微调 (Fine-tuning)

    • 当面临一个具体的下游任务时(如文本分类、命名实体识别),我们不再从头开始训练模型。而是把预训练好的 BERT 模型作为任务模型的基础结构。加载它已经学习到的所有参数作为初始值。
    • 接着根据具体任务,在 BERT 模型之上增加一个小的、任务相关的输出层(例如,一个用于分类的全连接层)。
    • 最后在自己的任务数据集上对整个模型(或仅仅是顶部的输出层)进行训练。由于模型已经具备了强大的语言理解能力,这个微调过程通常非常快速,并且只需要相对较少的数据就能达到很好的效果。

代码实战

环境准备

安装Transformers

pip install transformers

设置HF-Mirrors加速镜像

export HF_ENDPOINT='https://hf-mirror.com'

从加载模型到提取特征的完整流程的代码示例

import torch
import os
from transformers import AutoTokenizer, AutoModel

# 1. 环境和模型配置
# os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com' # 可选:设置镜像
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model_name = "bert-base-chinese"
texts = ["我来自中国", "我喜欢自然语言处理"]

# 2. 加载模型和分词器
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModel.from_pretrained(model_name).to(device)
model.eval()

print("\n--- BERT 模型结构 ---")
print(model)

# 3. 文本预处理
inputs = tokenizer(texts, padding=True, truncation=True, return_tensors="pt").to(device)

# 打印 Tokenizer 的完整输出,以理解其内部结构
print("\n--- Tokenizer 输出 ---")
for key, value in inputs.items():
    print(f"{key}: \n{value}\n")

# 4. 模型推理
with torch.no_grad():
    outputs = model(**inputs)

# 5. 提取特征
last_hidden_state = outputs.last_hidden_state
sentence_features_pooler = getattr(outputs, "pooler_output", None)

# (1) 提取句子级别的特征向量 ([CLS] token)
sentence_features = last_hidden_state[:, 0, :]

# (2) 提取第一个句子的词元级别特征
first_sentence_tokens = last_hidden_state[0, 1:6, :]


print("\n--- 特征提取结果 ---")
print(f"句子特征 shape: {sentence_features.shape}")
if sentence_features_pooler is not None:
    print(f"pooler_output shape: {sentence_features_pooler.shape}")
print(f"第一个句子的词元特征 shape: {first_sentence_tokens.shape}")

输出结果

--- BERT 模型结构 ---
BertModel(
  (embeddings): BertEmbeddings(
    (word_embeddings): Embedding(21128, 768, padding_idx=0)
    (position_embeddings): Embedding(512, 768)
    (token_type_embeddings): Embedding(2, 768)
    (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
    (dropout): Dropout(p=0.1, inplace=False)
  )
  (encoder): BertEncoder(
    (layer): ModuleList(
      (0-11): 12 x BertLayer(
        (attention): BertAttention(
          (self): BertSelfAttention(
            (query): Linear(in_features=768, out_features=768, bias=True)
            (key): Linear(in_features=768, out_features=768, bias=True)
            (value): Linear(in_features=768, out_features=768, bias=True)
            (dropout): Dropout(p=0.1, inplace=False)
          )
          (output): BertSelfOutput(
            (dense): Linear(in_features=768, out_features=768, bias=True)
            (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
            (dropout): Dropout(p=0.1, inplace=False)
          )
        )
        (intermediate): BertIntermediate(
          (dense): Linear(in_features=768, out_features=3072, bias=True)
          (intermediate_act_fn): GELUActivation()
        )
        (output): BertOutput(
          (dense): Linear(in_features=3072, out_features=768, bias=True)
          (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
          (dropout): Dropout(p=0.1, inplace=False)
        )
      )
    )
  )
  (pooler): BertPooler(
    (dense): Linear(in_features=768, out_features=768, bias=True)
    (activation): Tanh()
  )
)

--- Tokenizer 输出 ---
input_ids: 
tensor([[ 101, 2769, 3341, 5632,  704, 1744,  102,    0,    0,    0,    0],
        [ 101, 2769, 1599, 3614, 5632, 4197, 6427, 6241, 1905, 4415,  102]])

token_type_ids: 
tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

attention_mask: 
tensor([[1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])


--- 特征提取结果 ---
句子特征 shape: torch.Size([2, 768])
pooler_output shape: torch.Size([2, 768])
第一个句子的词元特征 shape: torch.Size([5, 768])

GPT

从微调到提示

GPT-1:有监督微调(Supervised Fine-tuning)

核心理念:先在无标注数据上进行无监督预训练,学习通用的语言表示;然后在特定任务的有标注数据上进行有监督微调。
关键创新:提出了任务特定的输入变换。为了解决不同任务输入格式不一致的问题(如问答需要输入文章、问题、答案),GPT-1 不改变模型架构,而是通过在输入文本中加入特殊的分隔符(如 Start, Delimiter, Extract)将结构化输入转换为有序的序列。例如,对于文本蕴含任务,将前提(Premise)和假设(Hypothesis)用 $ 符号拼接后输入模型。

GPT-2:零样本学习(Zero-shot Learning)

核心理念&:语言模型即多任务学习者。研究者发现,当模型规模扩大(1.5B 参数)并使用更高质量的数据集(WebText,过滤后的 Reddit 高赞链接内容)训练后,模型展现出了无需微调的零样本能力。
表现:可以直接给模型输入指令,如 “Translate English to French: cheese =>”,模型就能自动续写出 “fromage”。证明模型在预训练中已经隐式地学会了各种任务。
架构微调:将 LayerNorm 移到了每个子层的输入端(Pre-activation),并增加了上下文窗口大小(512 -> 1024)。

GPT-3:上下文学习(In-context Learning)

核心理念:少样本学习者(Few-Shot Learners)。GPT-3 将参数量推向了惊人的 1750 亿。此时,模型展现出了强大的上下文学习能力。
什么是 In-context Learning?:模型在推理阶段,不需要更新任何权重(即不需要微调),仅凭输入提示中给出的少量示例(Demonstrations),就能理解并完成新任务。
Zero-shot: 仅给出任务描述。例如:“将中文翻译成英文:你好 ->”
One-shot: 给出一个示例。例如:“将中文翻译成英文:\n苹果 -> apple\n你好 ->”
Few-shot: 给出多个示例。这通常能显著提升模型性能,甚至达到微调模型的效果。
意义:这标志着范式的转变——我们不再为每个任务训练一个专用模型,而是通过设计提示 (Prompt) 来激发通用大模型的能力。

GPT-1 模型架构(左)与针对不同任务的输入变换

81b47cbba44be4389eea13db53aa2f17_5_2_1.png

GPT 代码实战

分别对英文和中文进行手动地逐字生成,以观察其内部过程和差异的代码实践

import torch
from transformers import AutoTokenizer, AutoModelForCausalLM

# 1. 环境配置
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model_name = "gpt2"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name).to(device)
model.eval()

# 2. 英文示例
prompt_en = "I like eating fried"
input_ids_en = tokenizer(prompt_en, return_tensors="pt")['input_ids'].to(device)

print(f"英文输入: '{prompt_en}'")
print(f"被编码为 {input_ids_en.shape[1]} 个 token: {tokenizer.convert_ids_to_tokens(input_ids_en[0])}")
print("开始为英文逐个 token 生成...")

generated_ids_en = input_ids_en
with torch.no_grad():
    for i in range(5): # 只生成 5 个 token 作为示例
        outputs = model(generated_ids_en)
        next_token_logits = outputs.logits[:, -1, :]
        next_token_id = torch.argmax(next_token_logits, dim=-1).unsqueeze(-1)
        new_token = tokenizer.decode(next_token_id[0])
        print(f"第 {i+1} 步, 生成 token: '{new_token.strip()}'")
        generated_ids_en = torch.cat([generated_ids_en, next_token_id], dim=1)

full_decoded_text_en = tokenizer.decode(generated_ids_en[0], skip_special_tokens=True)
print(f"\n英文最终生成结果: \n'{full_decoded_text_en}'\n")


# 3. 中文示例
prompt_zh = "我喜欢吃炸"
input_ids_zh = tokenizer(prompt_zh, return_tensors="pt")['input_ids'].to(device)

print(f"中文输入: '{prompt_zh}'")
print(f"被编码为 {input_ids_zh.shape[1]} 个 token: {tokenizer.convert_ids_to_tokens(input_ids_zh[0])}")
print("开始为中文逐个 token 生成...")

generated_ids_zh = input_ids_zh
with torch.no_grad():
    for i in range(5): # 只生成 5 个 token 作为示例
        outputs = model(generated_ids_zh)
        next_token_logits = outputs.logits[:, -1, :]
        next_token_id = torch.argmax(next_token_logits, dim=-1).unsqueeze(-1)
        new_token = tokenizer.decode(next_token_id[0])
        print(f"第 {i+1} 步, 生成 token: '{new_token.strip()}'")
        generated_ids_zh = torch.cat([generated_ids_zh, next_token_id], dim=1)

full_decoded_text_zh = tokenizer.decode(generated_ids_zh[0], skip_special_tokens=True)
print(f"\n中文最终生成结果 (出现乱码是正常现象): \n'{full_decoded_text_zh}'")

输出结果

英文输入: 'I like eating fried'
被编码为 4 个 token: ['I', 'Ġlike', 'Ġeating', 'Ġfried']
开始为英文逐个 token 生成...1, 生成 token: 'chicken'2, 生成 token: ','3, 生成 token: 'but'4, 生成 token: 'I'5, 生成 token: 'don'

英文最终生成结果: 
'I like eating fried chicken, but I don'

中文输入: '我喜欢吃炸'
被编码为 13 个 token: ['æĪ', 'ij', 'å', 'ĸ', 'ľ', 'æ', '¬', '¢', 'åIJ', 'ĥ', 'ç', 'Ĥ', '¸']
开始为中文逐个 token 生成...1, 生成 token: '的'2, 生成 token: '�'3, 生成 token: '�'4, 生成 token: '�'5, 生成 token: '�'

中文最终生成结果 (出现乱码是正常现象): 
'我喜欢吃炸的让�'

分词器工作原理代码示例

from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("gpt2")

text = "一个生僻字:龘"
tokens = tokenizer.tokenize(text)

# 这类不在词表的字符会被拆成若干字节级 token
print(tokens)

输出结果

['ä¸Ģ', 'ä¸', 'ª', 'çĶŁ', 'å', 'ĥ', '»', 'åŃ', 'Ĺ', 'ï', '¼', 'ļ', 'é¾', 'ĺ']

pipeline代码示例

# pipeline 应用
from transformers import pipeline

print("\n\n--- Pipeline 快速演示 (英文) ---")
generator = pipeline("text-generation", model=model_name, device=device)
pipeline_outputs = generator("I like eating fried", max_new_tokens=5, num_return_sequences=1)
print(pipeline_outputs[0]['generated_text'])

T5

Text-to-Text框架

6d500d4365e2477e57a3562b90f55922_5_3_1.png

万物皆文本的核心理念

在 BERT 模式下,针对不同的任务,我们需要设计不同的模型结构:

  • 文本分类:BERT + 全连接层(分类头)。
  • 序列标注:BERT + CRF/分类层。
  • 文本相似度:双塔 BERT 或拼接输入 + 回归层。
    Google 提出的 T5 模型打破了这种模式。它提出——无论是什么任务,输入是文本,输出也是文本。我们以《黑神话:悟空》的评论处理为例:
  • 翻译:输入 “翻译成英文: 黑神话悟空真好玩” -> 输出 “Black Myth: Wukong is really fun.”
  • 情感分类:输入 “情感分析: 黑神话悟空真好玩” -> 输出 “正面”
  • 摘要:输入 “摘要: 黑神话悟空是一款以中国神话为背景的动作角色扮演游戏…” -> 输出 “黑神话悟空是国产 3A 动作游戏。”
  • 回归(打分):输入 “计算相似度 句子1: 黑神话悟空真好玩 句子2: 这猴子游戏真不错” -> 输出 “4.5” (直接生成数字文本)

T5 架构

T5 的整体架构与原始 Transformer 几乎一致,是一个标准的 Encoder-Decoder 模型:

  • Encoder:负责理解输入文本(如 BERT)。
  • Decoder:负责自回归地生成输出文本(如 GPT)。
    这种结构使得 T5 既具备 BERT 的双向理解能力,又具备 GPT 的生成能力,完美契合 “Text-to-Text” 的任务设定。

代码实战

import torch
from transformers import T5Tokenizer, T5ForConditionalGeneration

# 1. 加载模型
model_name = "t5-small" # 使用最小版本演示
tokenizer = T5Tokenizer.from_pretrained(model_name)
model = T5ForConditionalGeneration.from_pretrained(model_name)

# 2. 准备输入
# T5 需要明确的任务前缀
input_text_1 = "translate English to German: The house is wonderful."
input_text_2 = "stsb sentence1: The rhino grazed on the grass. sentence2: A rhino is grazing in a field."

# 3. 推理生成
inputs = tokenizer([input_text_1, input_text_2], return_tensors="pt", padding=True)
outputs = model.generate(**inputs)

print(f"输入 1: {input_text_1}")
print(f"输出 1: {tokenizer.decode(outputs[0], skip_special_tokens=True)}")

print(f"输入 2: {input_text_2}")
print(f"输出 2: {tokenizer.decode(outputs[1], skip_special_tokens=True)}")

输出结果

输入 1: translate English to German: The house is wonderful.
输出 1: Das Haus ist wunderbar.
输入 2: stsb sentence1: The rhino grazed on the grass. sentence2: A rhino is grazing in a field.
输出 2: 4.0

相对位置编码分桶逻辑源码

def compute_bias(self, query_length, key_length, device=None):
    """
    计算相对位置偏置矩阵的完整流程
    """
    # 1. 生成位置索引
    # context_position (Query的位置): [0, 1, ..., q_len-1]
    context_position = torch.arange(query_length, dtype=torch.long, device=device)[:, None]
    # memory_position (Key的位置): [0, 1, ..., k_len-1]
    memory_position = torch.arange(key_length, dtype=torch.long, device=device)[None, :]
    
    # 2. 计算相对距离 (Relative Distance)
    # 矩阵相减,得到 (q_len, k_len) 的相对距离矩阵
    relative_position = memory_position - context_position 

    # 3. 映射到桶 (Bucketing)
    # 调用 _relative_position_bucket 函数,将具体距离映射为 bucket_id
    relative_position_bucket = self._relative_position_bucket(
        relative_position, 
        bidirectional=(not self.is_decoder),
        num_buckets=self.relative_attention_num_buckets,
        max_distance=self.relative_attention_max_distance,
    )

    # 4. 查 Embedding 表 (Lookup)
    # self.relative_attention_bias 是一个可学习的 Embedding 层
    # 根据 bucket_id 查出对应的 bias 值
    values = self.relative_attention_bias(relative_position_bucket)
    
    # 调整形状以适配 Multi-head Attention: (1, n_heads, q_len, k_len)
    values = values.permute([2, 0, 1]).unsqueeze(0)
    return values

原理解析:

  1. 解耦位置与内容:BERT 将位置信息加在 Input Embedding 上,意味着位置和内容在第一层就混合了。而 T5 选择在每一层 Attention 计算时,直接在这个 N×NN \times N 的注意力分数矩阵上加上一个位置偏置矩阵(Bias),让位置信息更直接地作用于注意力权重。
  2. 参数效率:如果为每个距离都学习一个 Bias,参数量会太大。T5 通过**分桶(Bucketing)**策略,将无限的距2离映射到有限的桶(如 32 个)中,大大减少了参数量。
  3. 对数映射:分桶时采用“近密远疏”的策略(对数映射),因为人类语言对近距离的语法依赖(如主谓关系)非常敏感,需要精确区分;而对于远距离的语义依赖,只需要知道“大概很远”就足够了。

相对距离被映射为 Bucket ID代码实现

import math
import torch

def _relative_position_bucket(relative_position, bidirectional=True, num_buckets=32, max_distance=128):
    """
    T5 相对位置编码的核心分桶逻辑
    将相对距离(relative_position)映射为一个桶编号(bucket ID)
    """
    relative_buckets = 0
    
    # 1. 处理双向/单向 Attention
    # 如果是双向 Attention (如 Encoder),正负距离是不同的桶
    if bidirectional:
        num_buckets //= 2
        # 如果距离 > 0 (Key 在 Query 后面),桶编号加上总数的一半
        relative_buckets += (relative_position > 0).to(torch.long) * num_buckets
        # 取绝对值,统一处理正负距离
        relative_position = torch.abs(relative_position)
    else:
        # 如果是单向 Attention (如 Decoder),只考虑过去的距离
        relative_position = -torch.min(relative_position, torch.zeros_like(relative_position))
    
    # 2. 核心分桶逻辑:近距离精确,远距离模糊
    
    # 前一半的桶(max_exact)用于精确匹配近距离
    max_exact = num_buckets // 2
    is_small = relative_position < max_exact

    # 情况1:距离较小 (is_small 为 True),直接使用距离作为桶编号
    # 例如距离为 1 -> 桶 1; 距离为 5 -> 桶 5
    
    # 情况2:距离较大 (is_small 为 False),使用对数公式计算桶编号
    # 使用对数函数 log 把很大的距离压缩到剩下的桶里
    relative_position_if_large = max_exact + (
        torch.log(relative_position.float() / max_exact)
        / math.log(max_distance / max_exact)
        * (num_buckets - max_exact)
    ).to(torch.long)
    
    # 防止越界,最大不超过 num_buckets - 1
    relative_position_if_large = torch.min(
        relative_position_if_large, torch.full_like(relative_position_if_large, num_buckets - 1)
    )

    # 根据 is_small 的判断,选择使用精确编号还是对数编号
    relative_buckets += torch.where(is_small, relative_position, relative_position_if_large)
    return relative_buckets


# 假设有 32 个桶,最大敏感距离为 128
distances = torch.tensor([-10, -5, -1, 0, 1, 5, 10, 50, 100])
buckets = _relative_position_bucket(distances)
print(f"真实距离: {distances.tolist()}")
print(f"映射桶号: {buckets.tolist()}")

输出结果

真实距离: [-10, -5, -1, 0, 1, 5, 10, 50, 100]
映射桶号: [8, 5, 1, 0, 17, 21, 24, 29, 31]

Hugging Face

Hugging Face 已经从一家 NLP 初创公司演变为 AI 时代的基础设施。它构建了一个涵盖模型开发全生命周期的完整生态系统——从数据获取、模型开发、训练微调到最终的评估与部署。本节将深入剖析 Hugging Face 的生态构成,并以 Transformers 库为核心,结合 Datasets 和 Tokenizers,展示现代化模型开发链路。

生态

Hugging Face 的生态系统可以看作是由核心软件库、协作平台和辅助工具 共同构成的有机整体

Hugging Face Hub

  • Models(模型库):托管了数十万个预训练模型,涵盖 NLP、CV、Audio 等多模态领域。用户可以下载、使用甚至在线体验模型效果。
  • Datasets(数据集):托管各类公开数据集。支持数据预览和高效的流式传输。
  • Spaces(演示空间):允许开发者使用 Gradio、Streamlit 或 Docker 快速构建 Web 应用,在线展示模型效果。

三驾马车

  • Transformers: 生态系统的引擎。提供统一的 API 来下载、加载和使用预训练模型。
  • Tokenizers: 连接文本与模型的桥梁。底层由 Rust 编写,提供极致的文本处理速度(Fast Tokenizers),并与 Transformers 无缝集成。
  • Datasets: 数据处理的加速器。提供标准化的接口来加载、处理和管理大型数据集,内置高效的内存映射机制。

辅助工具

  • Accelerate: 简化分布式训练。让同一套代码可以无缝运行在 CPU、单卡 GPU、多卡 GPU 甚至 TPU 上,无需手动处理复杂的分布式逻辑。
  • Evaluate: 标准化的模型评估框架。提供数十种常用的评估指标(如 Accuracy, F1, BLEU, ROUGE) 4。
  • Diffusers: 专注于生成式 AI(如 Stable Diffusion)的库。
  • PEFT: 参数高效微调库(Parameter-Efficient Fine-Tuning),支持 LoRA 等前沿微调技术。

核心库详解

Pipeline

NLP任务

在前面的 GPT 实战中,我们曾显式指定模型(model=“gpt2”)来完成文本生成。同时,Pipeline 还拥有强大的“自动导航”能力——无需指定模型,只需指定任务。

当指定一个任务类型(如 sentiment-analysis)时,Pipeline 会自动从 Hub 上下载并加载该任务对应的默认预训练模型

from transformers import pipeline

# 情感分析(默认下载英文模型)
classifier = pipeline("sentiment-analysis")
result = classifier("I love Hugging Face!")
print(result)

跨模态能力

Transformers 早已突破 NLP 边界,支持 CV 和 Audio 等多个领域

# 图像分类示例(显式指定小模型 apple/mobilevit-small)
# pip install pillow
vision_classifier = pipeline(model="apple/mobilevit-small")
result = vision_classifier("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/coco_sample.png")
print(result)

Transformers 的处理流程

  1. Tokenizer(分词)
  2. Model(模型)
  3. Post-processing(后处理)
    代码实现
import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification

# 准备模型与分词器
checkpoint = "bert-base-chinese"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)
# 1. Tokenizer: 文本 -> Tensor
text = "Hugging Face 让 NLP 变得简单"
inputs = tokenizer(text, return_tensors="pt")
inputs['input_ids']

# 2. Model: Tensor -> Logits
outputs = model(**inputs)
logits = outputs.logits

# 3. Post-processing: Logits -> 概率
predictions = torch.nn.functional.softmax(logits, dim=-1)
print(predictions)

使用 Datasets 构建数据流水线

代码实现

from datasets import load_dataset

# 加载烂番茄影评数据集
dataset = load_dataset("rotten_tomatoes")
print(dataset)

# 并行的预处理
def tokenize_function(examples):
    return tokenizer(examples["text"], padding="max_length", truncation=True)

# 高效并行处理
# tokenized_datasets = dataset.map(tokenize_function, batched=True, num_proc=4)

Trainer 与 Evaluate

Trainer训练框架

from transformers import TrainingArguments, Trainer, AutoModelForSequenceClassification, AutoTokenizer

# 使用英文模型 distilbert-base-uncased
tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased")

def tokenize_function(examples):
    return tokenizer(examples["text"], padding="max_length", truncation=True)

tokenized_datasets = dataset.map(tokenize_function, batched=True)

# 为了快速演示,我们只取一小部分数据
small_train_dataset = tokenized_datasets["train"].shuffle(seed=42).select(range(100)) 
small_eval_dataset = tokenized_datasets["validation"].shuffle(seed=42).select(range(100))

# 1. 准备模型
model = AutoModelForSequenceClassification.from_pretrained("distilbert-base-uncased", num_labels=2)

print(model)

# 2. 配置参数
training_args = TrainingArguments(
    output_dir="test_trainer",
    eval_strategy="epoch", # 每个 epoch 结束进行评估
    num_train_epochs=1,
)

# 3. 实例化 Trainer 并启动训练
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=small_train_dataset,
    eval_dataset=small_eval_dataset,
)
trainer.train()

Evaluate 性能评估

import numpy as np
import evaluate

# 加载评估指标
metric = evaluate.load("accuracy")

# 定义计算函数:将 Logits 转换为 Predictions 并计算 Accuracy
def compute_metrics(eval_pred):
    logits, labels = eval_pred
    predictions = np.argmax(logits, axis=-1)
    return metric.compute(predictions=predictions, references=labels)

# 重新实例化 Trainer,注入 compute_metrics
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=small_train_dataset,
    eval_dataset=small_eval_dataset,
    compute_metrics=compute_metrics, # 关键步骤
)

# 训练并评估
trainer.train()

预训练语言模型的三大主流技术路线及其工程实践

  • BERT(理解):基于 Transformer Encoder 结构,主要通过 MLM(掩码语言建模)(以及 NSP 等)任务学习双向上下文表示。BERT 及其变体(RoBERTa、ALBERT)在文本分类、序列标注等自然语言理解任务上表现出色,是解决此类问题的经典方案。
  • GPT(生成):基于 Transformer Decoder 结构,通过 自回归 预测下一个词。GPT 系列模型不仅在自然语言生成(NLG) 上表现优异,更通过 GPT-3 系统性展示了提示工程和上下文学习的潜力,在实践层面推动了现代大语言模型的发展。
  • T5(统一):回归 Encoder-Decoder 经典架构,提出了 “Text-to-Text”(万物皆文本) 的统一框架。T5 证明通过将不同任务(翻译、分类、回归)统一为文本生成的形式,可以用一个模型解决多种 NLP 问题。
  • Hugging Face 实战:本章还详细介绍了 NLP 领域的标准工具——Hugging Face。通过 Transformers(模型)、Tokenizers(分词)、Datasets(数据) 和 Evaluate(评估)这四大核心库,开发者能够以极低的代码量,高效地复现和应用现代 NLP 模型。

参考资料

https://github.com/datawhalechina/base-nlp

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。