入坑大模型微调第一个Hugging Face程序

48 阅读10分钟

基础认知

为什么用

我们做AI应用开发,可能不太需要去做大模型的预训练,但是模型微调还是离不开的。那什么是模型微调呢?

类似于"站在巨人肩膀上"——预训练模型通过海量数据已学习通用知识(如语言规律、图像特征),微调则像 针对性补习,用少量高质量数据让模型掌握专业场景的特殊技能,最终适应特定任务,如情感分析、命名实体识别等。

Hugging Face

那么问题来了,模型微调的“模型”怎么来的呢?世面上那么多模型,我们去哪找呢? 这里有这样一个网站:Hugging Face(需要tz且节点最好在老美)

image.png

我们这里需要关注的是两个:

  • Models:模型库

进入模型库,可按需找自己需要的模型:

image.png

我们继续进入一个模型的详情页,这里以gpt2-chinese为例:

image.png

我们程序员是不看着挺眼熟,你没有看错,就是挺像gitHub的。或者换句话说,Hugging Face就是AI大模型领域的“gitHub”。

  • Datasets:公开数据集

这里提供很多可以用于各个领域训练的公开数据。

image.png

ModelScope

Hugging Face需要tz才能访问。除了Hugging Face外,国内还有一个平台提供模型和公开数据集的下载:ModelScope

image.png

这里Hugging Face就像gitHub,ModelScope就像是Gitee。没有tz环境的可以使用后者。 但是这里📢📢📢:ModelScope资源不如Hugging Face,当ModelScope找不到目标模型时可以试试Hugging。

我们今天以Hugging Face为例,ModelScope就象征性地讲这么多。

撸起袖子就是Coding

工欲善其事

使用Hugging Face,本地需要以下环境:

  1. python。Hugging Face生态的官方编程语言,提供统一的API接口和丰富的包管理生态。

  2. anacoda。解决Python包版本冲突和环境隔离问题,特别适合需要同时维护多个项目不同版本依赖的AI开发场景

  3. PyTorch(或TensorFlow)。模型的计算引擎,提供张量计算和自动微分能力,是模型训练和推理的数学基础。Hugging Face的Transformers库底层完全依赖这些框架的神经网络模块

  • 通过pip安装:
pip install torch torchvision torchaudio
  • 通过Conda安装:
conda install pytorch torchvision torchaudio cpuonly -c pytorch

4. pycharm。python开发官方IDE,非必选也可使用VSCode等。 * 下载地址PyCharm官网

  1. Hugging Face Token。我们本地连接github也需要一个Token的东西,Hugging Face也一样。
    • 需要注册账号,支持国内邮箱注册(🌰QQ)
    • 登录后,按如下步骤获取。📢📢📢:注意红色文字注意事项!!!

image.png

image.png

image.png

image.png

模型API调用

网上看到可以API访问Hugging Face,这里我怎么试都没有成功(目前报404)。大家有成功的可以赐教下。

import requests
#使用Token访问在线模型

API_URL = "https://router.huggingface.co/models/uer/gpt2-chinese-cluecorpussmall"
API_TOKEN = "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"
headers = {"Authorization": f"Bearer {API_TOKEN}"}

response = requests.post(API_URL,headers=headers,json={"inputs":"你好,Hugging face"})

模型下载

from transformers import AutoModelForCausalLM, AutoTokenizer
from transformers.models.auto.configuration_auto import model_type_to_module_name

# 将模型和分词器下载到本地使用,指定保存路径
model_name = "bert-base-chinese"
cache_dir = "./model/bert-base-chinese"

# 下载模块
AutoModelForCausalLM.from_pretrained(model_name, cache_dir=cache_dir)
# 下载分词工具
AutoTokenizer.from_pretrained(model_name, cache_dir=cache_dir)

print(f"模型已经下载到:{cache_dir}")

简单介绍下几个核心模块:

  • AutoModelForCausalLM:作为因果语言建模(Causal Language Modeling)任务的专用接口,基于Transformer解码器架构,实现自回归文本生成
  • AutoTokenizer:文本预处理管道的统一抽象层,其核心作用是将人类可读的自然语言文本与模型理解的数字表示(Token ID)进行双向转换

AutoXXX,一般是通用接口,提供模型无关的加载方式。以我们这里的bert模型为例,其还有专用实现。

  • lBertModel
  • BertTokenizer

一般开发中使用AutoXXX的通用实现即可,你的项目高度稳定,明确只使用BERT架构,并且你希望代码的意图非常清晰明确,那么直接使用BertModel是很好的选择。

模型认知

整体目录:

image.png

Config文件:

{
  "activation_function": "gelu_new",
  "architectures": [
    "GPT2LMHeadModel"
  ],
  "attn_pdrop": 0.1,
  "embd_pdrop": 0.1,
  "gradient_checkpointing": false,
  "initializer_range": 0.02,
  "layer_norm_epsilon": 1e-05,
  "model_type": "gpt2",
  "n_ctx": 1024,
  "n_embd": 768,
  "n_head": 12,
  "n_inner": null,
  "n_layer": 12,
  "n_positions": 1024,
  "output_past": true,
  "resid_pdrop": 0.1,
  "task_specific_params": {
    "text-generation": {
      "do_sample": true,
      "max_length": 320
    }
  },
  "tokenizer_class": "BertTokenizer",
  "vocab_size": 21128
}

这里主要注意一个概念:

  • vocab_size,模型字典大小。我们可以在vocab.txt中看到其容量正好是vocab_size的值:21128。

image.png

Tokenizer原理

  1. 归一化器(Normalizer) :负责文本清洗和标准化,如统一转为小写、Unicode规范化、清理多余空格。例如,将 "HELLO World"规范为 "hello world"

  2. 预分词器(Pre-tokenizer) :根据简单规则(如空格、标点)进行初步切分,将文本划分为粗粒度片段。例如,将 "hello world"切分为 ["hello", " world"]

  3. 模型(Model) :这是核心算法层,负责将预切分后的片段进一步细化为最终的子词(Subword)Token。主流算法包括BPE、WordPiece和Unigram。

  4. 后处理器(Post-processor) :添加模型所需的特殊Token,如序列开始(<s>)、序列结束(</s>)、填充([PAD])等,构建出模型期待的输入格式。

  5. 解码器(Decoder) :是编码的逆过程,负责将Token ID序列还原回连贯的文本,并智能地合并子词(如将 "play""##ing"合并为 "playing")。

模型本地调用

# 本地调用GPT2
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline, AutoConfig

# 设置模型路径,必须是绝对路径
model_dir = r"/Users/chaors/Development/AIProjects/helloHuggingFace/model/uer/gpt2-chinese-cluecorpussmall/models--uer--gpt2-chinese-cluecorpussmall/snapshots/c2c0249d8a2731f269414cc3b22dff021f8e07a3"

# 配置设置,不设置报错:The tied weights mapping and config for this model specifies to tie transformer.wte.weight to lm_head.weight, but both are present in the checkpoints, so we will NOT tie them.
config = AutoConfig.from_pretrained(model_dir)
config.tie_word_embeddings = False

# 加载模型和分词器
model = AutoModelForCausalLM.from_pretrained(model_dir,config=config)
tokenizer = AutoTokenizer.from_pretrained(model_dir)
# model = AutoModelForCausalLM.from_pretrained(model_dir,config=config, trust_remote_code=True)
# tokenizer = AutoTokenizer.from_pretrained(model_dir, trust_remote_code=True)

# 创建生成文本的pipeline
generator = pipeline("text-generation", model=model, tokenizer=tokenizer)

# 生成文本
# output = generator("你好,我是一款语言模型,",max_length=50,num_return_sequences=1)
output = generator(
    "天气有点阴沉,猴哥走在水坑里,",#生成文本的输入种子文本(prompt)。模型会根据这个初始文本,生成后续的文本
    max_new_tokens=30,#指定生成文本的最大长度。这里的 50 表示生成的文本最多包含 50 个标记(tokens)
    num_return_sequences=1,#参数指定返回多少个独立生成的文本序列。值为 1 表示只生成并返回一段文本。
    truncation=True,#该参数决定是否截断输入文本以适应模型的最大输入长度。如果 True,超出模型最大输入长度的部分将被截断;如果 False,模型可能无法处理过长的输入,可能会报错。
    temperature=0.7,#该参数控制生成文本的随机性。值越低,生成的文本越保守(倾向于选择概率较高的词);值越高,生成的文本越多样(倾向于选择更多不同的词)。0.7 是一个较为常见的设置,既保留了部分随机性,又不至于太混乱。
    top_k=50,#该参数限制模型在每一步生成时仅从概率最高的 k 个词中选择下一个词。这里 top_k=50 表示模型在生成每个词时只考虑概率最高的前 50 个候选词,从而减少生成不太可能的词的概率。
    top_p=0.6,#该参数(又称为核采样)进一步限制模型生成时的词汇选择范围。它会选择一组累积概率达到 p 的词汇,模型只会从这个概率集合中采样。top_p=0.9 意味着模型会在可能性最强的 90% 的词中选择下一个词,进一步增加生成的质量。
    clean_up_tokenization_spaces=True#该参数控制生成的文本中是否清理分词时引入的空格。如果设置为 True,生成的文本会清除多余的空格;如果为 False,则保留原样。默认值即将改变为 False,因为它能更好地保留原始文本的格式。
)
print(output)
print(model)

简单介绍下几个核心模块:

  • pipeline,任务流管理器。根据任务名(如 "text-generation")自动组装并管理整个工作流。

运行警告

image.png

这里可以运行,但是有警告⚠️:

  1. generat显式生成参数的调用模式已被标记为废弃
  2. max_new_tokens与max_length参数同时设置时的优先级冲突,max_new_tokens优先级更高
  3. 等等之类都是新范式不兼容的警告,一一按提示处理即可
# 新的参数传递范式
# 创建明确的生成配置
generation_config = GenerationConfig(
    max_new_tokens=30,#指定生成文本的最大长度。这里的 50 表示生成的文本最多包含 50 个标记(tokens)
    num_return_sequences=1,  # 参数指定返回多少个独立生成的文本序列。值为 1 表示只生成并返回一段文本。
    truncation=True,  # 该参数决定是否截断输入文本以适应模型的最大输入长度。如果 True,超出模型最大输入长度的部分将被截断;如果 False,模型可能无法处理过长的输入,可能会报错。
    temperature=1.0,
    # 该参数控制生成文本的随机性。值越低,生成的文本越保守(倾向于选择概率较高的词);值越高,生成的文本越多样(倾向于选择更多不同的词)。0.7 是一个较为常见的设置,既保留了部分随机性,又不至于太混乱。
    top_k=50,  # 该参数限制模型在每一步生成时仅从概率最高的 k 个词中选择下一个词。这里 top_k=50 表示模型在生成每个词时只考虑概率最高的前 50 个候选词,从而减少生成不太可能的词的概率。
    top_p=0.6, # 该参数(又称为核采样)进一步限制模型生成时的词汇选择范围。它会选择一组累积概率达到 p 的词汇,模型只会从这个概率集合中采样。top_p=0.9 意味着模型会在可能性最强的 90% 的词中选择下一个词,进一步增加生成的质量。
    clean_up_tokenization_spaces=True, # 该参数控制生成的文本中是否清理分词时引入的空格。如果设置为 True,生成的文本会清除多余的空格;如果为 False,则保留原样。默认值即将改变为 False,因为它能更好地保留原始文本的格式。
    do_sample=True # 新版本temperature、top_p等采样参数需要与do_sample=True配合使用,否则被视为无效
)

# 2. 将文本编码为张量(关键步骤!)
input_text = "天气有点阴沉,猴哥走在水坑里,"
inputs = tokenizer(input_text, return_tensors="pt")  # 返回PyTorch张量

output = model.generate(**inputs, generation_config=generation_config) # # 解包字典:input_ids=inputs['input_ids'], attention_mask=inputs['attention_mask']
generated_text = tokenizer.decode(output[0], skip_special_tokens=True)

至此,我们的第一个简单的Hugging Face程序就大功告成了。从此为后续的微调打下了坚实的基础。